Skip to main content

vsd_mp4/sub/
stpp.rs

1/*
2    REFERENCES
3    ----------
4
5    1. https://github.com/shaka-project/shaka-player/blob/a4e926772e1b754fe968ee6f97490f08a40fe535/lib/text/mp4_ttml_parser.js
6
7*/
8
9use crate::{
10    Result, bail, data, parser,
11    parser::Mp4Parser,
12    sub::{Subtitles, ttml},
13};
14
15/// A parser for extracting TTML subtitles from MP4 files.
16pub struct StppSubsParser;
17
18impl StppSubsParser {
19    /// Creates a new `Mp4TtmlParser` from the given initialization segment.
20    pub fn from_init(data: &[u8]) -> Result<Self> {
21        let saw_stpp = data!(false);
22        let saw_stpp_c = saw_stpp.clone();
23
24        Mp4Parser::new()
25            .base_box("moov", parser::children)
26            .base_box("trak", parser::children)
27            .base_box("mdia", parser::children)
28            .base_box("minf", parser::children)
29            .base_box("stbl", parser::children)
30            .full_box("stsd", parser::sample_description)
31            .base_box("stpp", move |box_| {
32                *saw_stpp_c.borrow_mut() = true;
33                box_.parser.stop();
34                Ok(())
35            })
36            .parse(data, false, false)?;
37
38        if !saw_stpp.take() {
39            bail!("STPP box not found.");
40        }
41
42        Ok(Self)
43    }
44
45    /// Parses the given media segment data to extract subtitles.
46    pub fn parse(&self, data: &[u8]) -> Result<Subtitles> {
47        let saw_mdat = data!(false);
48        let subtitles = data!(Subtitles::new());
49
50        let saw_mdat_c = saw_mdat.clone();
51        let subtitles_c = subtitles.clone();
52
53        Mp4Parser::new()
54            .base_box(
55                "mdat",
56                parser::alldata(move |data| {
57                    *saw_mdat_c.borrow_mut() = true;
58                    // Join this to any previous payload, in case the mp4 has multiple
59                    // mdats.
60                    let xml = String::from_utf8(data)?;
61                    subtitles_c
62                        .borrow_mut()
63                        .extend_cues(ttml::parse(&xml)?.into_cues());
64                    Ok(())
65                }),
66            )
67            .parse(data, false, false)?;
68
69        if !saw_mdat.take() {
70            bail!("MDAT box not found.");
71        }
72
73        Ok(subtitles.take())
74    }
75}