1use crate::{arc, av::MediaType, cv, define_cls, define_obj_type, ns, objc};
2
3#[cfg(feature = "cm")]
4use crate::cm;
5
6#[cfg(all(feature = "blocks", feature = "dispatch"))]
7use crate::{blocks, dispatch};
8
9define_obj_type!(pub WriterInput(ns::Id));
10
11impl arc::A<WriterInput> {
12 #[objc::msg_send(initWithMediaType:outputSettings:)]
13 pub unsafe fn init_media_type_output_settings_throws(
14 self,
15 media_type: &MediaType,
16 output_settings: Option<&ns::Dictionary<ns::String, ns::Id>>,
17 ) -> arc::R<WriterInput>;
18
19 #[cfg(feature = "cm")]
20 #[objc::msg_send(initWithMediaType:outputSettings:sourceFormatHint:)]
21 pub unsafe fn with_media_type_output_settings_source_format_hint_throws(
22 self,
23 media_type: &MediaType,
24 output_settings: Option<&ns::Dictionary<ns::String, ns::Id>>,
25 source_format_hint: Option<&cm::FormatDesc>,
26 ) -> arc::R<WriterInput>;
27}
28
29impl WriterInput {
30 define_cls!(AV_ASSET_WRITER_INPUT);
31
32 pub unsafe fn with_media_type_output_settings_throws(
33 media_type: &MediaType,
34 output_settings: Option<&ns::Dictionary<ns::String, ns::Id>>,
35 ) -> arc::R<WriterInput> {
36 unsafe { Self::alloc().init_media_type_output_settings_throws(media_type, output_settings) }
37 }
38
39 pub fn with_media_type_and_output_settings<'ear>(
40 media_type: &MediaType,
41 output_settings: Option<&ns::Dictionary<ns::String, ns::Id>>,
42 ) -> ns::ExResult<'ear, arc::R<WriterInput>> {
43 ns::try_catch(|| unsafe {
44 Self::alloc().init_media_type_output_settings_throws(media_type, output_settings)
45 })
46 }
47
48 #[cfg(feature = "cm")]
49 pub unsafe fn with_media_type_output_settings_source_format_hint_throws(
50 media_type: &MediaType,
51 output_settings: Option<&ns::Dictionary<ns::String, ns::Id>>,
52 source_format_hint: Option<&cm::FormatDesc>,
53 ) -> arc::R<WriterInput> {
54 unsafe {
55 Self::alloc().with_media_type_output_settings_source_format_hint_throws(
56 media_type,
57 output_settings,
58 source_format_hint,
59 )
60 }
61 }
62
63 #[cfg(feature = "cm")]
64 pub fn with_media_type_output_settings_source_format_hint<'ear>(
65 media_type: &MediaType,
66 output_settings: Option<&ns::Dictionary<ns::String, ns::Id>>,
67 source_format_hint: Option<&cm::FormatDesc>,
68 ) -> ns::ExResult<'ear, arc::R<WriterInput>> {
69 ns::try_catch(|| unsafe {
70 Self::with_media_type_output_settings_source_format_hint_throws(
71 media_type,
72 output_settings,
73 source_format_hint,
74 )
75 })
76 }
77
78 #[cfg(feature = "cm")]
79 pub unsafe fn with_media_type_format_hint_throws(
80 media_type: &MediaType,
81 source_format_hint: &cm::FormatDesc,
82 ) -> arc::R<WriterInput> {
83 unsafe {
84 Self::alloc().with_media_type_output_settings_source_format_hint_throws(
85 media_type,
86 None,
87 Some(source_format_hint),
88 )
89 }
90 }
91
92 pub unsafe fn with_media_type_throws(media_type: &MediaType) -> arc::R<WriterInput> {
93 unsafe { Self::with_media_type_output_settings_throws(media_type, None) }
94 }
95
96 pub fn with_media_type<'ear>(
97 media_type: &MediaType,
98 ) -> ns::ExResult<'ear, arc::R<WriterInput>> {
99 ns::try_catch(|| unsafe { Self::with_media_type_throws(media_type) })
100 }
101
102 #[objc::msg_send(mediaType)]
103 pub fn media_type(&self) -> arc::R<MediaType>;
104
105 #[objc::msg_send(outputSettings)]
106 pub fn output_settings(&self) -> Option<arc::R<ns::Dictionary<ns::String, ns::Id>>>;
107
108 #[objc::msg_send(isReadyForMoreMediaData)]
109 pub fn is_ready_for_more_media_data(&self) -> bool;
110
111 #[objc::msg_send(expectsMediaDataInRealTime)]
112 pub fn expects_media_data_in_real_time(&self) -> bool;
113
114 #[objc::msg_send(setExpectsMediaDataInRealTime:)]
115 pub fn set_expects_media_data_in_real_time(&mut self, value: bool);
116
117 #[objc::msg_send(markAsFinished)]
118 pub fn mark_as_finished(&mut self);
119
120 #[cfg(feature = "cm")]
135 #[objc::msg_send(appendSampleBuffer:)]
136 pub unsafe fn append_sample_buf_throws(&mut self, buffer: &cm::SampleBuf) -> bool;
137
138 #[cfg(feature = "cm")]
139 pub fn append_sample_buf<'ear>(&mut self, buffer: &cm::SampleBuf) -> ns::ExResult<'ear, bool> {
140 ns::try_catch(|| unsafe { self.append_sample_buf_throws(buffer) })
141 }
142
143 #[cfg(all(feature = "blocks", feature = "dispatch"))]
144 #[objc::msg_send(requestMediaDataWhenReadyOnQueue:usingBlock:)]
145 pub unsafe fn request_media_data_when_ready_on_queue_throws(
146 &self,
147 queue: &dispatch::Queue,
148 block: &mut blocks::CompletionBlock,
149 );
150
151 #[cfg(all(feature = "blocks", feature = "dispatch"))]
152 pub fn request_media_data_when_ready_on_queue<'ear>(
153 &self,
154 queue: &dispatch::Queue,
155 block: &mut blocks::CompletionBlock,
156 ) -> ns::ExResult<'ear> {
157 ns::try_catch(|| unsafe {
158 self.request_media_data_when_ready_on_queue_throws(queue, block)
159 })
160 }
161}
162
163define_obj_type!(
164 #[doc(alias = "AVAssetWriterInputPixelBufferAdaptor")]
165 pub WriterInputPixelBufAdaptor(ns::Id)
166);
167
168impl arc::A<WriterInputPixelBufAdaptor> {
169 #[objc::msg_send(initWithAssetWriterInput:sourcePixelBufferAttributes:)]
170 pub unsafe fn init_with_asset_writer_input_throws(
171 self,
172 input: &WriterInput,
173 src_pixel_buf_attrs: Option<ns::Dictionary<ns::String, ns::Id>>,
174 ) -> arc::R<WriterInputPixelBufAdaptor>;
175}
176
177impl WriterInputPixelBufAdaptor {
178 define_cls!(AV_ASSET_WRITER_INPUT_PIXEL_BUFFER_ADAPTOR);
179
180 pub fn with_input_writer<'ear>(
181 input: &WriterInput,
182 src_pixel_buf_attrs: Option<ns::Dictionary<ns::String, ns::Id>>,
183 ) -> ns::ExResult<'ear, arc::R<Self>> {
184 ns::try_catch(|| unsafe {
185 Self::alloc().init_with_asset_writer_input_throws(input, src_pixel_buf_attrs)
186 })
187 }
188
189 #[objc::msg_send(assetWriterInput)]
191 pub fn asset_writer_input(&self) -> arc::R<WriterInput>;
192
193 #[objc::msg_send(sourcePixelBufferAttributes)]
195 pub fn src_pixel_buf_attrs(&self) -> Option<arc::R<ns::Dictionary<ns::String, ns::Id>>>;
196
197 #[objc::msg_send(pixelBufferPool)]
199 pub fn pixel_buf_pool(&self) -> Option<&cv::PixelBufPool>;
200
201 #[cfg(feature = "cm")]
203 #[objc::msg_send(appendPixelBuffer:withPresentationTime:)]
204 pub unsafe fn append_pixel_buf_with_pts_throws(
205 &mut self,
206 buf: &cv::PixelBuf,
207 pts: cm::Time,
208 ) -> bool;
209
210 #[cfg(feature = "cm")]
211 pub fn append_pixel_buf_with_pts<'ear>(
212 &mut self,
213 buf: &cv::PixelBuf,
214 pts: cm::Time,
215 ) -> ns::ExResult<'ear, bool> {
216 ns::try_catch(|| unsafe { self.append_pixel_buf_with_pts_throws(buf, pts) })
217 }
218}
219
220unsafe extern "C" {
221 static AV_ASSET_WRITER_INPUT: &'static objc::Class<WriterInput>;
222 static AV_ASSET_WRITER_INPUT_PIXEL_BUFFER_ADAPTOR:
223 &'static objc::Class<WriterInputPixelBufAdaptor>;
224}
225
226#[cfg(test)]
227mod tests {
228 use crate::{av, objc};
229
230 #[test]
231 fn basics() {
232 let input = av::asset::WriterInput::with_media_type(av::MediaType::video())
233 .expect("failed to create writer");
234 assert_eq!(input.media_type().as_ref(), av::MediaType::video());
235 av::asset::WriterInput::with_media_type(av::MediaType::muxed()).unwrap();
236 av::asset::WriterInput::with_media_type(av::MediaType::audio()).unwrap();
237 av::asset::WriterInput::with_media_type(av::MediaType::text()).unwrap();
238 av::asset::WriterInput::with_media_type(av::MediaType::closed_caption()).unwrap();
239 av::asset::WriterInput::with_media_type(av::MediaType::subtitle()).unwrap();
240 av::asset::WriterInput::with_media_type(av::MediaType::depth_data()).unwrap();
241 let input = av::asset::WriterInput::with_media_type(av::MediaType::timecode()).unwrap();
242 println!("{:?}", input);
243 }
244
245 #[test]
246 fn pixel_buf_adapter() {
247 let input = av::asset::WriterInput::with_media_type(av::MediaType::video())
248 .expect("failed to create writer");
249 let adapter = av::asset::WriterInputPixelBufAdaptor::with_input_writer(&input, None)
250 .expect("failed to create pixel buf adapter");
251
252 assert!(adapter.pixel_buf_pool().is_none());
253
254 objc::ar_pool(|| {
255 let _ = av::asset::WriterInputPixelBufAdaptor::with_input_writer(&input, None)
256 .expect_err("should throw exception");
257 })
258 }
259}