Skip to content

Commit

Permalink
hls example start
Browse files Browse the repository at this point in the history
  • Loading branch information
yury committed Dec 12, 2023
1 parent 71ce564 commit e08df02
Show file tree
Hide file tree
Showing 14 changed files with 395 additions and 33 deletions.
7 changes: 0 additions & 7 deletions cidre/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,6 @@ required-features = ["am"]
name = "am-device-mount-dev-image"
required-features = ["am"]

[[example]]
name = "at-audio"

[[example]]
name = "wk-web-view"
required-features = ["wk"]

[lib]
# proc-macro = true
#crate-type = ["staticlib", "rlib"]
Expand Down
126 changes: 126 additions & 0 deletions cidre/examples/av-asset-writer-hls/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use std::time::Duration;

use cidre::{
arc, av, av::AssetWriterDelegate, cm, define_obj_type, dispatch, ns, objc, sc,
sc::StreamOutput, ut,
};

#[repr(C)]
struct Context {
input: arc::R<av::AssetWriterInput>,
writer: arc::R<av::AssetWriter>,
}

define_obj_type!(
OutputDelegate + sc::StreamOutputImpl,
Context,
OUTPUT_DELEGATE_CLS
);

impl sc::StreamOutput for OutputDelegate {}

#[objc::add_methods]
impl sc::StreamOutputImpl for OutputDelegate {
extern "C" fn impl_stream_did_output_sample_buf(
&mut self,
_cmd: Option<&cidre::objc::Sel>,
_stream: &sc::Stream,
sample_buffer: &mut cm::SampleBuf,
_kind: sc::OutputType,
) {
if sample_buffer.image_buf().is_none() {
// skipping sample buffers without image buffers
eprint!("n");
return;
}
let ctx = self.inner_mut();
if ctx.input.is_ready_for_more_media_data() {
let res = unsafe { ctx.input.append_sample_buf_throws(sample_buffer) };
if res {
eprint!(".");
} else {
eprint!("{:?}", ctx.writer.error());
}
} else {
eprint!("x");
}
}
}

define_obj_type!(
WriterDelegate + av::AssetWriterDelegateImpl,
usize,
WRITER_DELEGATE_CLS
);

impl AssetWriterDelegate for WriterDelegate {}

#[objc::add_methods]
impl av::AssetWriterDelegateImpl for WriterDelegate {
extern "C" fn impl_asset_writer_did_output_segment_data_with_report(
&mut self,
_cmd: Option<&objc::Sel>,
_writer: &av::AssetWriter,
_segment_data: &ns::Data,
segment_type: av::AssetSegmentType,
segment_report: Option<&av::AssetSegmentReport>,
) {
eprintln!("{segment_type:?} {segment_report:?}");
if let Some(report) = segment_report {
let report = &report.track_reports()[0];
eprintln!("duration: {:?}", report.duration().seconds());
}
}
}

#[tokio::main]
async fn main() {
const FPS: i32 = 30;

let delegate = WriterDelegate::with(0);
let mut writer = av::AssetWriter::with_content_type(ut::Type::mpeg4movie()).unwrap();

let assist =
av::OutputSettingsAssistant::with_preset(av::OutputSettingsPreset::hevc_1920x1080())
.unwrap();
let mut input = av::AssetWriterInput::with_media_type_and_output_settings(
av::MediaType::video(),
assist.video_settings().as_deref(),
)
.unwrap();
input.set_expects_media_data_in_real_time(true);

writer.add_input(&input).unwrap();
writer.set_delegate(Some(delegate.as_ref()));
writer.set_output_file_type_profile(Some(av::FileTypeProfile::mpeg4_apple_hls()));
writer.set_preferred_output_segment_interval(cm::Time::with_seconds(6.0, 1));
writer.set_initial_segment_start_time(cm::Time::zero());
let queue = dispatch::Queue::serial_with_autoreleasepool();

let content = sc::ShareableContent::current().await.expect("content");
let ref display = content.displays()[0];
let mut cfg = sc::StreamCfg::new();
cfg.set_minimum_frame_interval(cm::Time::new(1, FPS));
cfg.set_width(display.width() as usize * 2);
cfg.set_height(display.height() as usize * 2);
let windows = ns::Array::new();
let filter = sc::ContentFilter::with_display_excluding_windows(display, &windows);
let stream = sc::Stream::new(&filter, &cfg);
let output = OutputDelegate::with(Context {
input,
writer: writer.clone(),
});
stream
.add_stream_output(output.as_ref(), sc::OutputType::Screen, Some(&queue))
.expect("failed to add output");
if writer.start_writing() {
writer.start_session_at_source_time(cm::Time::zero());
stream.start().await.unwrap();
} else {
eprintln!("failed? {:?}", writer.error());
}
eprintln!("started");

tokio::time::sleep(Duration::from_secs(100)).await;
eprintln!("ended");
}
5 changes: 5 additions & 0 deletions cidre/pomace/av/av.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ Class AV_ASSET_READER;
Class AV_ASSET_WRITER_INPUT;
Class AV_ASSET_READER_TRACK_OUTPUT;

Class AV_OUTPUT_SETTINGS_ASSISTANT;

Class AV_AUDIO_TIME;

Class AV_AUDIO_UNIT_EQ;
Expand Down Expand Up @@ -77,6 +79,9 @@ static void av_initializer(void)
AV_CAPTURE_MULTI_CAM_SESSION = [AVCaptureMultiCamSession class];
AV_CAPTURE_METADATA_INPUT = [AVCaptureMetadataInput class];
#endif

AV_OUTPUT_SETTINGS_ASSISTANT = [AVOutputSettingsAssistant class];

AV_AUDIO_PLAYER_NODE = [AVAudioPlayerNode class];

AV_AUDIO_ENGINE = [AVAudioEngine class];
Expand Down
6 changes: 6 additions & 0 deletions cidre/src/av.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ pub mod asset;
pub use asset::Asset;
pub use asset::AssetCache;
pub use asset::AssetWriter;
pub use asset::AssetWriterDelegate;
pub use asset::AssetWriterDelegateImpl;
pub use asset::FragmentedAsset;
pub use asset::FragmentedAssetMinder;
pub use asset::FragmentedTrack as FragmentedAssetTrack;
Expand Down Expand Up @@ -135,4 +137,8 @@ pub use sample_buffer::QueuedSampleBufRendering;
pub use sample_buffer::QueuedSampleBufRenderingStatus;
pub use sample_buffer::VideoRenderer as SampleBufVideoRenderer;

pub mod output_settings_assistant;
pub use output_settings_assistant::OutputSettingsAssistant;
pub use output_settings_assistant::OutputSettingsPreset;

mod time;
3 changes: 2 additions & 1 deletion cidre/src/av/asset/segment_report.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{av, cm, define_obj_type, ns, objc};

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[doc(alias = "AVAssetSegmentType")]
#[repr(isize)]
pub enum SegmentType {
Expand All @@ -24,7 +25,7 @@ impl SegmentReport {
pub fn segment_type(&self) -> SegmentType;

#[objc::msg_send(trackReports)]
pub fn track_reports(&self) -> ns::Array<TrackReport>;
pub fn track_reports(&self) -> &ns::Array<TrackReport>;
}

define_obj_type!(
Expand Down
24 changes: 22 additions & 2 deletions cidre/src/av/asset/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ impl arc::A<Writer> {
) -> Option<arc::R<Writer>>;

#[objc::msg_send(initWithContentType:)]
pub fn init_with_content_type(self, output_content_type: &ut::Type) -> arc::R<Writer>;
pub unsafe fn init_with_content_type_throws(
self,
output_content_type: &ut::Type,
) -> arc::R<Writer>;
}

impl Writer {
Expand Down Expand Up @@ -69,6 +72,9 @@ impl Writer {
#[objc::msg_send(cancelWriting)]
pub fn cancel_writing(&mut self);

#[objc::msg_send(status)]
pub fn status(&self) -> Status;

#[objc::msg_send(error)]
pub fn error(&self) -> Option<&ns::Error>;

Expand All @@ -85,7 +91,7 @@ impl Writer {
pub fn with_url_and_file_type<'ar>(
url: &ns::Url,
file_type: &av::FileType,
) -> Result<arc::R<Writer>, &'ar ns::Error> {
) -> Result<arc::R<Self>, &'ar ns::Error> {
let mut error = None;
unsafe {
let res = Self::alloc().init_with_url_file_type_err(url, file_type, &mut error);
Expand All @@ -95,6 +101,14 @@ impl Writer {
}
}
}

pub fn with_content_type<'ar>(
output_content_type: &ut::Type,
) -> Result<arc::R<Self>, &'ar ns::Exception> {
ns::try_catch(|| unsafe {
Self::alloc().init_with_content_type_throws(output_content_type)
})
}
}

/// AVAssetWriterSegmentation
Expand Down Expand Up @@ -173,12 +187,18 @@ extern "C" {

#[cfg(test)]
mod tests {
use crate::ut;

#[test]
fn basics() {
use crate::{av, ns};
let url = ns::Url::with_str("file://tmp/bla.mp4").unwrap();

let writer = av::AssetWriter::with_url_and_file_type(&url, av::FileType::mp4()).unwrap();
assert_eq!(writer.inputs().len(), 0);

av::AssetWriter::with_content_type(&ut::Type::pdf())
.expect_err("Can't create writer for pdf");
av::AssetWriter::with_content_type(&ut::Type::mpeg4movie()).expect("Can't create viedeo");
}
}
6 changes: 3 additions & 3 deletions cidre/src/av/asset/writer_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,13 @@ impl WriterInput {
///
/// This method throws an exception if the sample buffer's media type does not match the asset writer input's media type.
#[objc::msg_send(appendSampleBuffer:)]
pub fn append_sample_buffer_throws(&mut self, buffer: &cm::SampleBuf) -> bool;
pub unsafe fn append_sample_buf_throws(&mut self, buffer: &cm::SampleBuf) -> bool;

pub fn append_sample_buffer<'ar>(
pub fn append_sample_buf<'ar>(
&mut self,
buffer: &cm::SampleBuf,
) -> Result<bool, &'ar ns::Exception> {
try_catch(|| self.append_sample_buffer_throws(buffer))
try_catch(|| unsafe { self.append_sample_buf_throws(buffer) })
}

#[objc::msg_send(requestMediaDataWhenReadyOnQueue:usingBlock:)]
Expand Down
Loading

0 comments on commit e08df02

Please # to comment.