Skip to main content

dash_mpd/
vtt.rs

1//! Support for the VTT subtitle format
2//
3// This module provides support for VTT subtitles that are distributed in fragmented MP4 segments.
4// These subtitles are provided as a separate media stream of fMP4 segments, that the media player
5// retrieves incrementally.
6//
7// This module implements:
8//
9//  - extracting the VTT fragments from an MP4 fragment
10//
11//  - appending them to the VttDocument object
12//
13//  - serializing to a single merged VTT subtitle file
14//
15
16use tracing::{trace, warn};
17use bytes::Bytes;
18use crate::DashMpdError;
19
20
21#[derive(Clone, Debug)]
22pub struct VttDocument {
23    contents: Vec<String>,
24    warned_binary_contents: bool,
25}
26
27impl Default for VttDocument {
28    fn default() -> Self {
29        Self::new()
30    }
31}
32
33impl VttDocument {
34    #[must_use]
35    pub fn new() -> VttDocument {
36        VttDocument {
37            contents: Vec::new(),
38            warned_binary_contents: false,
39        }
40    }
41
42    // Extract VTT content from the binary data in bytes.
43    pub fn add_bytes(&mut self, bytes: &Bytes) -> Result<(), DashMpdError> {
44        if let Ok(s) = str::from_utf8(bytes) {
45            self.add_content(s)?;
46        } else {
47            if !self.warned_binary_contents {
48                warn!("Ignoring invalid UTF-8 in VTT subs: {}", String::from_utf8_lossy(bytes));
49                self.warned_binary_contents = true;
50            }
51        }
52        Ok(())
53    }
54
55    pub fn add_content(&mut self, content: &str) -> Result<(), DashMpdError> {
56        trace!("adding VTT content {content}");
57        self.contents.push(content.to_string());
58        Ok(())
59    }
60
61    // Generate a complete VTT document corresponding to the merge of all the fragments seen so
62    // far. Note that we can't implement this using the fmt::Display trait for VttDocument, because
63    // we need a mutable reference to self, which is not available for Display.
64    #[allow(clippy::inherent_to_string)]
65    pub fn to_string(&mut self) -> String {
66        self.contents.concat()
67    }
68}
69