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}