Skip to main content

media_codec/
decoder.rs

1use std::{
2    collections::HashMap,
3    marker::PhantomData,
4    sync::{Arc, LazyLock, RwLock},
5};
6
7pub use media_codec_types::decoder::*;
8use media_codec_types::{
9    packet::{Packet, PacketProperties},
10    CodecID, CodecParameters, CodecParametersType, CodecSpec,
11};
12use media_core::{
13    frame::{Frame, SharedFrame},
14    frame_pool::{FrameCreator, FramePool},
15    invalid_param_error,
16    rational::Rational64,
17    variant::Variant,
18    Result,
19};
20
21use crate::codec::{find_codec, find_codec_by_name, register_codec, CodecList, LazyCodecList};
22
23pub trait DecoderSpec: CodecSpec {
24    fn register(builder: Arc<dyn DecoderBuilder<Self>>, default: bool) -> Result<()>;
25    fn find(id: CodecID) -> Result<Arc<dyn DecoderBuilder<Self>>>;
26    fn find_by_name(name: &str) -> Result<Arc<dyn DecoderBuilder<Self>>>;
27}
28
29pub struct DecoderContext<T: DecoderSpec> {
30    pub config: T,
31    pub time_base: Option<Rational64>,
32    decoder: Box<dyn Decoder<T>>,
33    pool: Option<Arc<FramePool<Frame<'static, T::FrameDescriptor>>>>,
34    last_pkt_props: Option<PacketProperties>,
35}
36
37#[cfg(feature = "audio")]
38static AUDIO_DECODER_LIST: LazyCodecList<AudioDecoder, dyn DecoderBuilder<AudioDecoder>> = LazyLock::new(|| {
39    RwLock::new(CodecList::<AudioDecoder, dyn DecoderBuilder<AudioDecoder>> {
40        codecs: HashMap::new(),
41        _marker: PhantomData,
42    })
43});
44
45#[cfg(feature = "audio")]
46impl DecoderSpec for AudioDecoder {
47    fn register(builder: Arc<dyn DecoderBuilder<Self>>, default: bool) -> Result<()> {
48        register_codec(&AUDIO_DECODER_LIST, builder, default)
49    }
50
51    fn find(id: CodecID) -> Result<Arc<dyn DecoderBuilder<Self>>> {
52        find_codec(&AUDIO_DECODER_LIST, id)
53    }
54
55    fn find_by_name(name: &str) -> Result<Arc<dyn DecoderBuilder<Self>>> {
56        find_codec_by_name(&AUDIO_DECODER_LIST, name)
57    }
58}
59
60#[cfg(feature = "video")]
61static VIDEO_DECODER_LIST: LazyCodecList<VideoDecoder, dyn DecoderBuilder<VideoDecoder>> = LazyLock::new(|| {
62    RwLock::new(CodecList::<VideoDecoder, dyn DecoderBuilder<VideoDecoder>> {
63        codecs: HashMap::new(),
64        _marker: PhantomData,
65    })
66});
67
68#[cfg(feature = "video")]
69impl DecoderSpec for VideoDecoder {
70    fn register(builder: Arc<dyn DecoderBuilder<Self>>, default: bool) -> Result<()> {
71        register_codec(&VIDEO_DECODER_LIST, builder, default)
72    }
73
74    fn find(id: CodecID) -> Result<Arc<dyn DecoderBuilder<Self>>> {
75        find_codec(&VIDEO_DECODER_LIST, id)
76    }
77
78    fn find_by_name(name: &str) -> Result<Arc<dyn DecoderBuilder<Self>>> {
79        find_codec_by_name(&VIDEO_DECODER_LIST, name)
80    }
81}
82
83pub fn register_decoder<T: DecoderSpec>(builder: Arc<dyn DecoderBuilder<T>>, default: bool) -> Result<()> {
84    T::register(builder, default)
85}
86
87pub(crate) fn find_decoder<T: DecoderSpec>(id: CodecID) -> Result<Arc<dyn DecoderBuilder<T>>> {
88    T::find(id)
89}
90
91pub(crate) fn find_decoder_by_name<T: DecoderSpec>(name: &str) -> Result<Arc<dyn DecoderBuilder<T>>> {
92    T::find_by_name(name)
93}
94
95impl<T: DecoderSpec> DecoderContext<T> {
96    pub fn new(codec_id: CodecID, codec_name: Option<&str>, params: &CodecParameters, options: Option<&Variant>) -> Result<Self> {
97        let builder = if let Some(codec_name) = codec_name {
98            find_decoder_by_name(codec_name)?
99        } else {
100            find_decoder(codec_id)?
101        };
102
103        let decoder = builder.new_decoder(codec_id, params, options)?;
104
105        Self::new_with_decoder(decoder, params)
106    }
107
108    pub fn new_with_decoder(decoder: Box<dyn Decoder<T>>, params: &CodecParameters) -> Result<Self> {
109        let config = T::from_parameters(params)?;
110
111        #[allow(unreachable_patterns)]
112        let frame_pool = match &params.codec {
113            CodecParametersType::Decoder(decoder_params) => {
114                if decoder_params.use_pool.unwrap_or(false) {
115                    Some(FramePool::<Frame<'static, T::FrameDescriptor>>::new())
116                } else {
117                    None
118                }
119            }
120            _ => return Err(invalid_param_error!(params)),
121        };
122
123        Ok(Self {
124            config,
125            decoder,
126            pool: frame_pool,
127            time_base: None,
128            last_pkt_props: None,
129        })
130    }
131
132    pub fn with_frame_creator(mut self, creator: Box<dyn FrameCreator<T::FrameDescriptor>>) -> Self {
133        if let Some(pool) = self.pool.as_mut().and_then(Arc::get_mut) {
134            pool.configure(None, Some(creator));
135        }
136
137        self
138    }
139
140    pub fn codec_id(&self) -> CodecID {
141        self.decoder.id()
142    }
143
144    pub fn codec_name(&self) -> &'static str {
145        self.decoder.name()
146    }
147
148    pub fn configure(&mut self, params: Option<&CodecParameters>, options: Option<&Variant>) -> Result<()> {
149        if let Some(params) = params {
150            self.config.configure(params)?;
151        }
152        self.decoder.configure(params, options)
153    }
154
155    pub fn set_option(&mut self, key: &str, value: &Variant) -> Result<()> {
156        self.decoder.set_option(key, value)
157    }
158
159    pub fn send_packet(&mut self, packet: &Packet) -> Result<()> {
160        self.decoder.send_packet(&self.config, self.pool.as_ref(), packet)?;
161        self.last_pkt_props = Some(PacketProperties::from_packet(packet));
162
163        Ok(())
164    }
165
166    pub fn receive_frame(&mut self) -> Result<SharedFrame<Frame<'static, T::FrameDescriptor>>> {
167        let mut shared_frame = self.decoder.receive_frame(&self.config, self.pool.as_ref())?;
168
169        let frame = shared_frame.write();
170        if let Some(frame) = frame {
171            if let Some(pkt_props) = &self.last_pkt_props {
172                frame.pts = frame.pts.or(pkt_props.pts);
173                frame.dts = frame.dts.or(pkt_props.dts);
174                frame.duration = frame.duration.or(pkt_props.duration);
175            }
176
177            frame.time_base = frame.time_base.or(self.time_base);
178        }
179
180        Ok(shared_frame)
181    }
182
183    pub fn flush(&mut self) -> Result<()> {
184        self.decoder.flush(&self.config)
185    }
186}