av_format/
muxer.rs

1use crate::common::*;
2use crate::data::packet::Packet;
3use crate::data::value::*;
4use std::any::Any;
5use std::io::{Cursor, Seek, SeekFrom, Write};
6use std::sync::Arc;
7
8use crate::error::*;
9
10/// Runtime wrapper around a [`Write`] trait object
11/// which optionally supports [`Seek`] functionality.
12pub struct Writer<W = Cursor<Vec<u8>>> {
13    writer: W,
14    bytes_written: usize,
15}
16
17impl<W: Write> Writer<W> {
18    /// Creates a [`Writer`] from an object that implements the [`Write`] trait.
19    pub fn new(inner: W) -> Self {
20        Self {
21            writer: inner,
22            bytes_written: 0,
23        }
24    }
25}
26
27impl<W: Write> Writer<W> {
28    /// Returns stream position.
29    pub fn position(&mut self) -> usize {
30        self.bytes_written
31    }
32
33    /// Returns a reference to the underlying writer and bytes written.
34    pub fn as_ref(&self) -> (&W, usize) {
35        (&self.writer, self.bytes_written)
36    }
37}
38
39impl<W: Write> Write for Writer<W> {
40    fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
41        let result = self.writer.write(bytes);
42
43        if let Ok(written) = result {
44            self.bytes_written += written;
45        }
46
47        result
48    }
49
50    fn flush(&mut self) -> std::io::Result<()> {
51        self.writer.flush()
52    }
53}
54
55impl<W: Write> Seek for Writer<W>
56where
57    W: Seek,
58{
59    fn seek(&mut self, seek: SeekFrom) -> std::io::Result<u64> {
60        let res = self.writer.seek(seek)?;
61        self.bytes_written = res as usize;
62        Ok(res)
63    }
64}
65
66/// Used to implement muxing operations.
67pub trait Muxer: Send {
68    /// Configures a muxer.
69    fn configure(&mut self) -> Result<()>;
70    /// Writes a stream header into a data structure implementing
71    /// the `Write` trait.
72    fn write_header<W: Write>(&mut self, out: &mut Writer<W>) -> Result<()>;
73    /// Writes a stream packet into a data structure implementing
74    /// the `Write` trait.
75    fn write_packet<W: Write>(&mut self, out: &mut Writer<W>, pkt: Arc<Packet>) -> Result<()>;
76    /// Writes a stream trailer into a data structure implementing
77    /// the `Write` trait.
78    fn write_trailer<W: Write>(&mut self, out: &mut Writer<W>) -> Result<()>;
79
80    /// Sets global media file information for a muxer.
81    fn set_global_info(&mut self, info: GlobalInfo) -> Result<()>;
82    /// Sets a muxer option.
83    ///
84    /// This method should be called as many times as the number of options
85    /// present in a muxer.
86    fn set_option(&mut self, key: &str, val: Value) -> Result<()>;
87}
88
89/// Auxiliary structure to encapsulate a muxer object and
90/// its additional data.
91pub struct Context<M: Muxer + Send, W: Write> {
92    muxer: M,
93    writer: Writer<W>,
94    /// User private data.
95    ///
96    /// This data cannot be cloned.
97    pub user_private: Option<Box<dyn Any + Send + Sync>>,
98}
99
100impl<M: Muxer, W: Write> Context<M, W> {
101    /// Creates a new `Context` instance.
102    pub fn new(muxer: M, writer: Writer<W>) -> Self {
103        Context {
104            muxer,
105            writer,
106            user_private: None,
107        }
108    }
109
110    /// Configures a muxer.
111    pub fn configure(&mut self) -> Result<()> {
112        self.muxer.configure()
113    }
114
115    /// Writes a stream header to an internal buffer and returns how many
116    /// bytes were written or an error.
117    pub fn write_header(&mut self) -> Result<()> {
118        self.muxer.write_header(&mut self.writer)
119    }
120
121    /// Writes a stream packet to an internal buffer and returns how many
122    /// bytes were written or an error.
123    pub fn write_packet(&mut self, pkt: Arc<Packet>) -> Result<()> {
124        self.muxer.write_packet(&mut self.writer, pkt)
125    }
126
127    /// Writes a stream trailer to an internal buffer and returns how many
128    /// bytes were written or an error.
129    pub fn write_trailer(&mut self) -> Result<()> {
130        self.muxer.write_trailer(&mut self.writer)?;
131        self.writer.flush()?;
132
133        Ok(())
134    }
135
136    /// Sets global media file information for a muxer.
137    pub fn set_global_info(&mut self, info: GlobalInfo) -> Result<()> {
138        self.muxer.set_global_info(info)
139    }
140
141    /// Sets a muxer option.
142    ///
143    /// This method should be called as many times as the number of options
144    /// present in a muxer.
145    pub fn set_option<'a, V>(&mut self, key: &str, val: V) -> Result<()>
146    where
147        V: Into<Value<'a>>,
148    {
149        self.muxer.set_option(key, val.into())
150    }
151
152    /// Returns the underlying writer.
153    pub fn writer(&self) -> &Writer<W> {
154        &self.writer
155    }
156
157    /// Consumes this muxer and returns the underlying writer.
158    pub fn into_writer(self) -> Writer<W> {
159        self.writer
160    }
161}
162
163/// Format descriptor.
164///
165/// Contains information on a format and its own muxer.
166#[derive(Clone, Debug, PartialEq, Eq)]
167pub struct Descr {
168    /// Format name.
169    pub name: &'static str,
170    /// Muxer name.
171    pub demuxer: &'static str,
172    /// Format description.
173    pub description: &'static str,
174    /// Format media file extensions.
175    pub extensions: &'static [&'static str],
176    /// Format MIME.
177    pub mime: &'static [&'static str],
178}
179
180/// Used to get a format descriptor and create a new muxer.
181pub trait Descriptor {
182    /// The specific type of the muxer.
183    type OutputMuxer: Muxer + Send;
184
185    /// Creates a new muxer for the requested format.
186    fn create(&self) -> Self::OutputMuxer;
187    /// Returns the descriptor of a format.
188    fn describe(&self) -> &Descr;
189}
190
191/// Used to look for a specific format.
192pub trait Lookup<T: Descriptor + ?Sized> {
193    /// Retrieves a specific format by name.
194    fn by_name(&self, name: &str) -> Option<&'static T>;
195}
196
197impl<T: Descriptor + ?Sized> Lookup<T> for [&'static T] {
198    fn by_name(&self, name: &str) -> Option<&'static T> {
199        self.iter().find(|&&d| d.describe().name == name).copied()
200    }
201}
202
203#[cfg(test)]
204mod test {
205    use super::*;
206
207    const DUMMY_HEADER_LENGTH: usize = 12;
208    const DUMMY_PACKET_LENGTH: usize = 2;
209    const DUMMY_PACKETS_NUMBER: usize = 2;
210    const DUMMY_TRAILER_LENGTH: usize = 13;
211
212    struct DummyDes {
213        d: Descr,
214    }
215
216    struct DummyMuxer {}
217
218    impl DummyMuxer {
219        pub fn new() -> Self {
220            Self {}
221        }
222    }
223
224    impl Muxer for DummyMuxer {
225        fn configure(&mut self) -> Result<()> {
226            Ok(())
227        }
228
229        fn write_header<W: Write>(&mut self, out: &mut Writer<W>) -> Result<()> {
230            let buf = b"Dummy header";
231            out.write_all(buf.as_slice()).unwrap();
232            Ok(())
233        }
234
235        fn write_packet<W: Write>(&mut self, out: &mut Writer<W>, pkt: Arc<Packet>) -> Result<()> {
236            out.write_all(&pkt.data).unwrap();
237            Ok(())
238        }
239
240        fn write_trailer<W: Write>(&mut self, out: &mut Writer<W>) -> Result<()> {
241            let buf = b"Dummy trailer";
242            out.write_all(buf.as_slice()).unwrap();
243            Ok(())
244        }
245
246        fn set_global_info(&mut self, _info: GlobalInfo) -> Result<()> {
247            Ok(())
248        }
249
250        fn set_option(&mut self, _key: &str, _val: Value) -> Result<()> {
251            Ok(())
252        }
253    }
254
255    impl Descriptor for DummyDes {
256        type OutputMuxer = DummyMuxer;
257
258        fn create(&self) -> Self::OutputMuxer {
259            DummyMuxer {}
260        }
261        fn describe(&self) -> &Descr {
262            &self.d
263        }
264    }
265
266    const DUMMY_DES: &dyn Descriptor<OutputMuxer = DummyMuxer> = &DummyDes {
267        d: Descr {
268            name: "dummy",
269            demuxer: "dummy",
270            description: "Dummy mux",
271            extensions: &["mx", "mux"],
272            mime: &["application/dummy"],
273        },
274    };
275
276    #[test]
277    fn lookup() {
278        let muxers: &[&dyn Descriptor<OutputMuxer = DummyMuxer>] = &[DUMMY_DES];
279
280        muxers.by_name("dummy").unwrap();
281    }
282
283    fn run_muxer<W: Write>(writer: Writer<W>) -> Context<DummyMuxer, W> {
284        let mux = DummyMuxer::new();
285
286        let mut muxer = Context::new(mux, writer);
287
288        muxer.configure().unwrap();
289        muxer.write_header().unwrap();
290
291        // Write zeroed packets of a certain size
292        for _ in 0..DUMMY_PACKETS_NUMBER {
293            let packet = Packet::zeroed(DUMMY_PACKET_LENGTH);
294            muxer.write_packet(Arc::new(packet)).unwrap();
295        }
296
297        muxer.write_trailer().unwrap();
298        muxer
299    }
300
301    fn check_underlying_buffer(buffer: &[u8]) {
302        assert_eq!(
303            buffer.get(..DUMMY_HEADER_LENGTH).unwrap(),
304            b"Dummy header".as_slice()
305        );
306
307        assert_eq!(
308            buffer
309                // Get only packets, without header and trailer data
310                .get(
311                    DUMMY_HEADER_LENGTH
312                        ..DUMMY_HEADER_LENGTH + (DUMMY_PACKETS_NUMBER * DUMMY_PACKET_LENGTH)
313                )
314                .unwrap(),
315            &[0, 0, 0, 0]
316        );
317
318        assert_eq!(
319            buffer
320                // Skip header and packets
321                .get(DUMMY_HEADER_LENGTH + (DUMMY_PACKETS_NUMBER * DUMMY_PACKET_LENGTH)..)
322                .unwrap(),
323            b"Dummy trailer".as_slice()
324        );
325    }
326
327    #[test]
328    fn vec_muxer() {
329        let muxer = run_muxer(Writer::new(Vec::new()));
330        let (buffer, index) = muxer.writer().as_ref();
331        check_underlying_buffer(buffer);
332        assert_eq!(
333            index,
334            DUMMY_HEADER_LENGTH
335                + (DUMMY_PACKETS_NUMBER * DUMMY_PACKET_LENGTH)
336                + DUMMY_TRAILER_LENGTH
337        );
338    }
339
340    #[test]
341    fn stdout_muxer() {
342        use std::io::stdout;
343
344        let muxer = run_muxer(Writer::new(stdout()));
345        let (_buffer, index) = muxer.writer().as_ref();
346        assert_eq!(
347            index,
348            DUMMY_HEADER_LENGTH
349                + (DUMMY_PACKETS_NUMBER * DUMMY_PACKET_LENGTH)
350                + DUMMY_TRAILER_LENGTH
351        );
352    }
353
354    #[cfg(not(target_arch = "wasm32"))] // Files depend on host, so this test
355    // cannot be run for WebAssembly
356    #[test]
357    fn file_muxer() {
358        let file = tempfile::tempfile().unwrap();
359        let muxer = run_muxer(Writer::new(file));
360        let mut writer = muxer.into_writer();
361        writer.seek(SeekFrom::Start(3)).unwrap();
362        assert!(writer.bytes_written == 3);
363        assert!(writer.as_ref().0.metadata().unwrap().len() != 0);
364    }
365}