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}