aboutsummaryrefslogtreecommitdiff
path: root/remuxer/src/segment_extractor.rs
blob: acbec535c532ff87e9a15cf36869ea0c022c051d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use anyhow::{anyhow, Result};
use jellymatroska::{
    block::Block,
    unflatten::{Unflat, Unflatten},
    MatroskaTag,
};
use log::{debug, trace, warn};
use std::collections::VecDeque;

pub struct AbsoluteBlock {
    pub pts_base: u64,
    pub inner: Block,
}

pub struct SegmentExtractIter<'a> {
    segment: Unflatten<'a>,
    extract: u64,
    emission_queue: VecDeque<AbsoluteBlock>,
}

impl AbsoluteBlock {
    pub fn pts(&self) -> u64 {
        self.inner.timestamp_off as u64 + self.pts_base
    }
}

impl<'a> SegmentExtractIter<'a> {
    pub fn new(segment: Unflatten<'a>, extract: u64) -> Self {
        Self {
            segment,
            extract,
            emission_queue: Default::default(),
        }
    }

    pub fn next(&mut self) -> Result<AbsoluteBlock> {
        loop {
            if let Some(b) = self.emission_queue.pop_front() {
                break Ok(b);
            }
            self.read()?;
        }
    }

    pub fn read(&mut self) -> Result<()> {
        let Unflat { children, item } = self.segment.n().ok_or(anyhow!("eof"))??;
        let mut pts_base = 0;
        match item {
            MatroskaTag::SeekHead(_) => {}
            MatroskaTag::Info(_) => {}
            MatroskaTag::Cluster(_) => {
                let mut children = children.unwrap();
                while let Some(Ok(Unflat { children, item })) = children.n() {
                    match item {
                        MatroskaTag::Crc32(_) => (),
                        MatroskaTag::Timestamp(ts) => {
                            trace!("read pts={ts}");
                            pts_base = ts;
                        }
                        MatroskaTag::BlockGroup(_) => {
                            trace!("group");
                            let mut children = children.unwrap();

                            // let mut duration = None;
                            let mut block = None;

                            while let Some(Ok(Unflat { children: _, item })) = children.n() {
                                match item {
                                    MatroskaTag::Block(buf) => block = Some(buf),
                                    // MatroskaTag::BlockDuration(v) => duration = Some(v),
                                    _ => debug!("ignored {item:?}"),
                                }
                            }
                            // TODO duration
                            let block = Block::parse(&block.unwrap())?;
                            if block.track == self.extract {
                                trace!("block: track={} tso={}", block.track, block.timestamp_off);
                                self.emission_queue.push_back(AbsoluteBlock {
                                    pts_base,
                                    inner: block,
                                });
                            }
                        }
                        MatroskaTag::SimpleBlock(buf) => {
                            let block = Block::parse(&buf)?;
                            if block.track == self.extract {
                                trace!("block: track={} tso={}", block.track, block.timestamp_off);
                                self.emission_queue.push_back(AbsoluteBlock {
                                    pts_base,
                                    inner: block,
                                });
                            }
                        }
                        _ => warn!("(rsc) tag ignored: {item:?}"),
                    }
                }
            }
            MatroskaTag::Tags(_) => {}
            MatroskaTag::Cues(_) => {}
            MatroskaTag::Chapters(_) => {}
            MatroskaTag::Tracks(_) => {}
            MatroskaTag::Void(_) => {}
            _ => debug!("(rs) tag ignored: {item:?}"),
        }
        Ok(())
    }
}