Skip to main content

na_mpeg2_decoder/
pipeline.rs

1use std::sync::Arc;
2
3use crate::demux::{Demuxer, StreamType};
4use crate::video::{Decoder, Frame};
5
6use crate::video::Result;
7
8/// High-level convenience wrapper: demux container bytes and decode MPEG-1/2 video frames.
9///
10/// This type is designed for low-overhead integration:
11/// - You can reuse a single pipeline instance across the whole stream.
12/// - Use `push_with()`/`flush_with()` to avoid collecting frames into intermediate vectors.
13#[derive(Debug, Default)]
14pub struct MpegVideoPipeline {
15    demux: Demuxer,
16    dec: Decoder,
17    pkts: Vec<crate::demux::Packet>,
18}
19
20impl MpegVideoPipeline {
21    #[inline]
22    pub fn new() -> Self {
23        Self {
24            demux: Demuxer::new_auto(),
25            dec: Decoder::new(),
26            pkts: Vec::new(),
27        }
28    }
29
30    #[inline]
31    pub fn decoder_mut(&mut self) -> &mut Decoder {
32        &mut self.dec
33    }
34
35    #[inline]
36    pub fn demuxer_mut(&mut self) -> &mut Demuxer {
37        &mut self.demux
38    }
39
40    /// Feed container bytes and invoke `on_frame` for each decoded frame.
41    ///
42    /// `pts_90k` is optional chunk-level PTS in 90 kHz timebase. When demuxing TS/PS,
43    /// packet-level PTS from PES headers takes precedence.
44    pub fn push_with<F>(&mut self, data: &[u8], pts_90k: Option<i64>, mut on_frame: F) -> Result<()>
45    where
46        F: FnMut(Arc<Frame>),
47    {
48        self.pkts.clear();
49        self.demux.push_into(data, pts_90k, &mut self.pkts);
50        for pkt in self.pkts.drain(..) {
51            if pkt.stream_type != StreamType::MpegVideo {
52                continue;
53            }
54            for f in self.dec.decode_shared(&pkt.data, pkt.pts_90k)? {
55                on_frame(f);
56            }
57        }
58        Ok(())
59    }
60
61    /// Flush delayed frames and invoke `on_frame` for each of them.
62    pub fn flush_with<F>(&mut self, mut on_frame: F) -> Result<()>
63    where
64        F: FnMut(Arc<Frame>),
65    {
66        for f in self.dec.flush_shared()? {
67            on_frame(f);
68        }
69        Ok(())
70    }
71}