Skip to main content

symphonia_core/codecs/
subtitle.rs

1// Symphonia
2// Copyright (c) 2019-2026 The Project Symphonia Developers.
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
8//! Subtitle decoder specific support.
9
10use std::fmt;
11
12#[cfg(feature = "exp-subtitle-codecs")]
13use crate::codecs::CodecInfo;
14use crate::common::FourCc;
15#[cfg(feature = "exp-subtitle-codecs")]
16use crate::errors::Result;
17#[cfg(feature = "exp-subtitle-codecs")]
18use crate::packet::{Packet, PacketRef};
19#[cfg(feature = "exp-subtitle-codecs")]
20use crate::subtitle::GenericSubtitleBufferRef;
21
22/// An `SubtitleCodecId` is a unique identifier used to identify a specific video codec.
23///
24/// # Creating a Codec ID
25///
26/// Using a [well-known](well_known) codec ID is *highly* recommended to maximize compatibility
27/// between components, libraries, and applications. However, if a codec requires custom codec ID,
28/// or there is no well-known ID, then the [`FourCc`] for the codec may be converted into a codec
29/// ID.
30#[repr(transparent)]
31#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
32pub struct SubtitleCodecId(u32);
33
34/// Null subtitle codec ID
35pub const CODEC_ID_NULL_SUBTITLE: SubtitleCodecId = SubtitleCodecId(0x0);
36
37impl SubtitleCodecId {
38    /// Create a new subtitle codec ID from a FourCC.
39    pub const fn new(cc: FourCc) -> SubtitleCodecId {
40        // A FourCc always only contains ASCII characters. Therefore, the upper bits are always 0.
41        Self(0x8000_0000 | u32::from_be_bytes(cc.get()))
42    }
43}
44
45impl Default for SubtitleCodecId {
46    fn default() -> Self {
47        CODEC_ID_NULL_SUBTITLE
48    }
49}
50
51impl From<FourCc> for SubtitleCodecId {
52    fn from(value: FourCc) -> Self {
53        SubtitleCodecId::new(value)
54    }
55}
56
57impl fmt::Display for SubtitleCodecId {
58    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
59        write!(f, "{:#x}", self.0)
60    }
61}
62
63/// Codec parameters for subtitle codecs.
64#[derive(Clone, Debug, Default)]
65pub struct SubtitleCodecParameters {
66    /// The codec ID.
67    pub codec: SubtitleCodecId,
68    /// Extra data (defined by the codec).
69    pub extra_data: Option<Box<[u8]>>,
70}
71
72impl SubtitleCodecParameters {
73    pub fn new() -> SubtitleCodecParameters {
74        SubtitleCodecParameters { codec: CODEC_ID_NULL_SUBTITLE, extra_data: None }
75    }
76
77    /// Provide the `VideoCodecId`.
78    pub fn for_codec(&mut self, codec: SubtitleCodecId) -> &mut Self {
79        self.codec = codec;
80        self
81    }
82
83    /// Provide codec extra data.
84    pub fn with_extra_data(&mut self, data: Box<[u8]>) -> &mut Self {
85        self.extra_data = Some(data);
86        self
87    }
88}
89
90/// `SubtitleDecoderOptions` is a common set of options that all subtitle decoders use.
91#[cfg(feature = "exp-subtitle-codecs")]
92#[non_exhaustive]
93#[derive(Copy, Clone, Debug, Default)]
94pub struct SubtitleDecoderOptions {
95    // None yet.
96}
97
98/// A `SubtitleDecoder` implements a subtitle codec's decode algorithm. It consumes `Packet`s and
99/// produces plain text or rendered subtitles.
100#[cfg(feature = "exp-subtitle-codecs")]
101pub trait SubtitleDecoder: Send + Sync {
102    /// Reset the decoder.
103    ///
104    /// A decoder must be reset when the next packet is discontinuous with respect to the last
105    /// decoded packet. Most notably, this occurs after a seek.
106    ///
107    /// # For Implementations
108    ///
109    /// For codecs that do a lot of pre-computation, reset should only reset the absolute minimum
110    /// amount of state.
111    fn reset(&mut self);
112
113    /// Get basic information about the codec.
114    fn codec_info(&self) -> &CodecInfo;
115
116    /// Gets a reference to an updated set of `SubtitleCodecParameters` based on the codec
117    /// parameters the decoder was instantiated with.
118    fn codec_params(&self) -> &SubtitleCodecParameters;
119
120    /// Decodes a `Packet` of subtitle data and returns a generic (plaintext or rendered) subtitle.
121    ///
122    /// If a `DecodeError` or `IoError` is returned, the packet is undecodeable and should be
123    /// discarded. Decoding may be continued with the next packet.
124    ///
125    /// Implementors of decoders *must* `clear` the last decoded subtitle if an error occurs.
126    fn decode(&mut self, packet: &Packet) -> Result<GenericSubtitleBufferRef<'_>> {
127        self.decode_ref(&packet.as_packet_ref())
128    }
129
130    /// Decodes a `PacketRef` of subtitle data and returns a generic (untyped) subtitle buffer reference
131    /// containing the decoded subtitles.
132    ///
133    /// This method is identical to `decode` but takes a `PacketRef` for zero-copy packet passing.
134    fn decode_ref(&mut self, packet: &PacketRef<'_>) -> Result<GenericSubtitleBufferRef<'_>>;
135
136    /// Allows read access to the internal audio buffer.
137    ///
138    /// After a successful call to `decode`, this will contain the audio content of the last decoded
139    /// `Packet`. If the last call to `decode` resulted in an error, then implementors *must* ensure
140    /// the returned audio buffer has zero length.
141    fn last_decoded(&self) -> GenericSubtitleBufferRef<'_>;
142}
143
144/// IDs for well-known subtitle codecs.
145pub mod well_known {
146    use super::SubtitleCodecId;
147
148    // Text-based subtitle codecs
149    //---------------------------
150
151    // Plain text subtitles
152
153    /// UTF8 encoded plain text
154    pub const CODEC_ID_TEXT_UTF8: SubtitleCodecId = SubtitleCodecId(0x100);
155
156    // Styled/formatted/rich text/markup-based subtitles
157
158    /// SubStation Alpha
159    pub const CODEC_ID_SSA: SubtitleCodecId = SubtitleCodecId(0x200);
160    /// Advanced SubStation Alpha
161    pub const CODEC_ID_ASS: SubtitleCodecId = SubtitleCodecId(0x201);
162    /// Synchronized Accessible Media Interchange
163    pub const CODEC_ID_SAMI: SubtitleCodecId = SubtitleCodecId(0x202);
164    /// SubRip
165    pub const CODEC_ID_SRT: SubtitleCodecId = SubtitleCodecId(0x203);
166    /// WebVTT
167    pub const CODEC_ID_WEBVTT: SubtitleCodecId = SubtitleCodecId(0x204);
168    /// DVB subtitles
169    pub const CODEC_ID_DVBSUB: SubtitleCodecId = SubtitleCodecId(0x205);
170    /// HDMV text subtitles (HDMV TextST)
171    pub const CODEC_ID_HDMV_TEXTST: SubtitleCodecId = SubtitleCodecId(0x206);
172    /// 3GPP Timed Text subtitle (MPEG Timed Text)
173    pub const CODEC_ID_MOV_TEXT: SubtitleCodecId = SubtitleCodecId(0x207);
174
175    // Image-based subtitle codecs
176    //----------------------------
177
178    /// Bitmap Subtitle
179    pub const CODEC_ID_BMP: SubtitleCodecId = SubtitleCodecId(0x300);
180    /// DVD Subtitle
181    pub const CODEC_ID_VOBSUB: SubtitleCodecId = SubtitleCodecId(0x301);
182    /// HDMV presentation graphics subtitles (HDMV PGS)
183    pub const CODEC_ID_HDMV_PGS: SubtitleCodecId = SubtitleCodecId(0x302);
184
185    // Mixed-mode subtitle codecs
186    //---------------------------
187
188    /// OGG Karaoke and Text Encapsulation (OGG KATE)
189    pub const CODEC_ID_KATE: SubtitleCodecId = SubtitleCodecId(0x400);
190}