playa_ffmpeg/codec/decoder/decoder.rs
1use std::{
2 ops::{Deref, DerefMut},
3 ptr,
4};
5
6use super::{Audio, Check, Conceal, Opened, Subtitle, Video};
7use crate::{
8 Dictionary, Discard, Error, Rational,
9 codec::{Context, traits},
10 ffi::*,
11};
12
13/// A decoder for compressed media streams.
14///
15/// `Decoder` wraps an FFmpeg codec context configured for decoding. It provides methods
16/// to open the decoder with various configurations and convert it to type-specific decoders
17/// (video, audio, or subtitle).
18///
19/// # Lifecycle
20///
21/// 1. Create a `Decoder` from a codec context (typically from a stream)
22/// 2. Open it with [`open()`](Decoder::open), [`open_as()`](Decoder::open_as), or type-specific methods
23/// 3. Use the resulting [`Opened`] decoder to decode packets into frames
24///
25/// # Example
26///
27/// ```ignore
28/// // Get decoder from stream codec parameters
29/// let decoder = stream.codec().decoder();
30///
31/// // Open as video decoder
32/// let mut video = decoder.video()?;
33///
34/// // Decode packets
35/// video.send_packet(&packet)?;
36/// let frame = video.receive_frame()?;
37/// ```
38pub struct Decoder(pub Context);
39
40impl Decoder {
41 /// Opens the decoder with default codec options.
42 ///
43 /// Uses the codec already associated with this decoder context (if any).
44 ///
45 /// # Errors
46 ///
47 /// Returns an error if the decoder cannot be opened (e.g., missing codec,
48 /// invalid parameters, or resource allocation failure).
49 pub fn open(mut self) -> Result<Opened, Error> {
50 unsafe {
51 // Call FFmpeg's avcodec_open2 with null codec (use context's codec) and null options
52 match avcodec_open2(self.as_mut_ptr(), ptr::null(), ptr::null_mut()) {
53 0 => Ok(Opened(self)),
54 e => Err(Error::from(e)),
55 }
56 }
57 }
58
59 /// Opens the decoder with a specific codec.
60 ///
61 /// # Parameters
62 ///
63 /// * `codec` - The codec to use for decoding (must support decoding)
64 ///
65 /// # Errors
66 ///
67 /// Returns `Error::DecoderNotFound` if the codec doesn't support decoding,
68 /// or other errors if the decoder cannot be opened.
69 pub fn open_as<D: traits::Decoder>(mut self, codec: D) -> Result<Opened, Error> {
70 unsafe {
71 if let Some(codec) = codec.decoder() {
72 match avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), ptr::null_mut()) {
73 0 => Ok(Opened(self)),
74 e => Err(Error::from(e)),
75 }
76 } else {
77 Err(Error::DecoderNotFound)
78 }
79 }
80 }
81
82 /// Opens the decoder with a specific codec and options dictionary.
83 ///
84 /// # Parameters
85 ///
86 /// * `codec` - The codec to use for decoding
87 /// * `options` - Dictionary of codec-specific options (e.g., threading, quality settings)
88 ///
89 /// # Errors
90 ///
91 /// Returns `Error::DecoderNotFound` if the codec doesn't support decoding,
92 /// or other errors if the decoder cannot be opened.
93 ///
94 /// # Note
95 ///
96 /// The options dictionary is consumed and reclaimed after the call.
97 pub fn open_as_with<D: traits::Decoder>(mut self, codec: D, options: Dictionary) -> Result<Opened, Error> {
98 unsafe {
99 if let Some(codec) = codec.decoder() {
100 // Disown the dictionary for FFmpeg to consume
101 let mut opts = options.disown();
102 let res = avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), &mut opts);
103
104 // Reclaim ownership to properly free the dictionary
105 Dictionary::own(opts);
106
107 match res {
108 0 => Ok(Opened(self)),
109 e => Err(Error::from(e)),
110 }
111 } else {
112 Err(Error::DecoderNotFound)
113 }
114 }
115 }
116
117 /// Opens this decoder as a video decoder.
118 ///
119 /// Convenience method that finds an appropriate video codec, opens the decoder,
120 /// and returns a type-specific video decoder.
121 ///
122 /// # Errors
123 ///
124 /// Returns `Error::DecoderNotFound` if no suitable video decoder is found for
125 /// this context's codec ID.
126 pub fn video(self) -> Result<Video, Error> {
127 // Try to use codec already in context, otherwise find by ID
128 if let Some(codec) = self.codec() {
129 self.open_as(codec).and_then(|o| o.video())
130 } else if let Some(codec) = super::find(self.id()) {
131 self.open_as(codec).and_then(|o| o.video())
132 } else {
133 Err(Error::DecoderNotFound)
134 }
135 }
136
137 /// Opens this decoder as an audio decoder.
138 ///
139 /// Convenience method that finds an appropriate audio codec, opens the decoder,
140 /// and returns a type-specific audio decoder.
141 ///
142 /// # Errors
143 ///
144 /// Returns `Error::DecoderNotFound` if no suitable audio decoder is found for
145 /// this context's codec ID.
146 pub fn audio(self) -> Result<Audio, Error> {
147 // Try to use codec already in context, otherwise find by ID
148 if let Some(codec) = self.codec() {
149 self.open_as(codec).and_then(|o| o.audio())
150 } else if let Some(codec) = super::find(self.id()) {
151 self.open_as(codec).and_then(|o| o.audio())
152 } else {
153 Err(Error::DecoderNotFound)
154 }
155 }
156
157 /// Opens this decoder as a subtitle decoder.
158 ///
159 /// Convenience method that finds an appropriate subtitle codec, opens the decoder,
160 /// and returns a type-specific subtitle decoder.
161 ///
162 /// # Errors
163 ///
164 /// Returns `Error::DecoderNotFound` if no suitable subtitle decoder is found for
165 /// this context's codec ID.
166 pub fn subtitle(self) -> Result<Subtitle, Error> {
167 if let Some(codec) = super::find(self.id()) { self.open_as(codec).and_then(|o| o.subtitle()) } else { Err(Error::DecoderNotFound) }
168 }
169
170 /// Sets error concealment strategy.
171 ///
172 /// Configures how the decoder should handle corrupted data (e.g., missing macroblocks,
173 /// broken slices). Higher concealment may produce visible artifacts but avoid decode failures.
174 pub fn conceal(&mut self, value: Conceal) {
175 unsafe {
176 (*self.as_mut_ptr()).error_concealment = value.bits();
177 }
178 }
179
180 /// Sets error detection/recognition level.
181 ///
182 /// Controls how strictly the decoder validates input data. Stricter checking catches
183 /// more errors but may reject valid but non-compliant streams.
184 pub fn check(&mut self, value: Check) {
185 unsafe {
186 (*self.as_mut_ptr()).err_recognition = value.bits();
187 }
188 }
189
190 /// Sets which frames to skip during loop filtering (deblocking).
191 ///
192 /// Skipping loop filtering improves decode performance but reduces visual quality.
193 /// Useful for low-power devices or when decoding for analysis rather than display.
194 pub fn skip_loop_filter(&mut self, value: Discard) {
195 unsafe {
196 (*self.as_mut_ptr()).skip_loop_filter = value.into();
197 }
198 }
199
200 /// Sets which frames to skip during IDCT (inverse DCT) processing.
201 ///
202 /// Skipping IDCT can significantly speed up decoding but produces lower quality output.
203 /// Primarily useful for fast seeking or thumbnail extraction.
204 pub fn skip_idct(&mut self, value: Discard) {
205 unsafe {
206 (*self.as_mut_ptr()).skip_idct = value.into();
207 }
208 }
209
210 /// Sets which frames to skip entirely during decoding.
211 ///
212 /// Allows selective frame dropping (e.g., skip all B-frames, skip non-reference frames).
213 /// Useful for fast playback or when only key frames are needed.
214 pub fn skip_frame(&mut self, value: Discard) {
215 unsafe {
216 (*self.as_mut_ptr()).skip_frame = value.into();
217 }
218 }
219
220 /// Gets the time base used for packet timestamps.
221 ///
222 /// This is the time unit for interpreting PTS/DTS values in input packets.
223 /// Typically matches the stream's time base.
224 pub fn packet_time_base(&self) -> Rational {
225 unsafe { Rational::from((*self.as_ptr()).pkt_timebase) }
226 }
227
228 /// Sets the time base for packet timestamps.
229 ///
230 /// Must match the time base of packets being sent to this decoder.
231 pub fn set_packet_time_base<R: Into<Rational>>(&mut self, value: R) {
232 unsafe {
233 (*self.as_mut_ptr()).pkt_timebase = value.into().into();
234 }
235 }
236}
237
238impl Deref for Decoder {
239 type Target = Context;
240
241 fn deref(&self) -> &<Self as Deref>::Target {
242 &self.0
243 }
244}
245
246impl DerefMut for Decoder {
247 fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
248 &mut self.0
249 }
250}
251
252impl AsRef<Context> for Decoder {
253 fn as_ref(&self) -> &Context {
254 self
255 }
256}
257
258impl AsMut<Context> for Decoder {
259 fn as_mut(&mut self) -> &mut Context {
260 &mut self.0
261 }
262}