media_codec/
encoder.rs

1use std::{
2    any::TypeId,
3    collections::HashMap,
4    mem,
5    sync::{Arc, LazyLock, RwLock},
6};
7
8#[cfg(feature = "audio")]
9use media_core::audio::AudioFrameDescriptor;
10#[cfg(feature = "video")]
11use media_core::video::VideoFrameDescriptor;
12use media_core::{
13    buffer::BufferPool,
14    error::Error,
15    frame::{Frame, SharedFrame},
16    invalid_param_error,
17    variant::Variant,
18    MediaType, Result,
19};
20
21#[cfg(feature = "audio")]
22use crate::AudioParameters;
23#[cfg(feature = "video")]
24use crate::VideoParameters;
25use crate::{
26    find_codec, find_codec_by_name, packet::Packet, register_codec, Codec, CodecBuilder, CodecID, CodecList, CodecParameters, CodecParametersType,
27    CodecSpec, CodecType, LazyCodecList, MediaParametersType,
28};
29
30#[derive(Clone, Debug, Default)]
31pub struct EncoderParameters {
32    pub bit_rate: Option<u64>,
33    pub profile: Option<i32>,
34    pub level: Option<i32>,
35    pub use_pool: Option<bool>,
36}
37
38impl EncoderParameters {
39    fn update(&mut self, other: &EncoderParameters) {
40        if other.bit_rate.is_some() {
41            self.bit_rate = other.bit_rate;
42        }
43        if other.profile.is_some() {
44            self.profile = other.profile;
45        }
46        if other.level.is_some() {
47            self.level = other.level;
48        }
49    }
50
51    fn update_with_option(&mut self, key: &str, value: &Variant) {
52        match key {
53            "bit_rate" => self.bit_rate = value.get_uint64(),
54            "profile" => self.profile = value.get_int32(),
55            "level" => self.level = value.get_int32(),
56            _ => {}
57        }
58    }
59}
60
61impl TryFrom<&CodecParametersType> for EncoderParameters {
62    type Error = Error;
63
64    fn try_from(params: &CodecParametersType) -> Result<Self> {
65        match params {
66            CodecParametersType::Encoder(params) => Ok(params.clone()),
67            _ => Err(invalid_param_error!(params)),
68        }
69    }
70}
71
72#[cfg(feature = "audio")]
73#[derive(Clone, Debug, Default)]
74pub struct AudioEncoderParameters {
75    pub audio: AudioParameters,
76    pub encoder: EncoderParameters,
77}
78
79#[cfg(feature = "audio")]
80#[allow(unreachable_patterns)]
81impl TryFrom<&CodecParameters> for AudioEncoderParameters {
82    type Error = Error;
83
84    fn try_from(params: &CodecParameters) -> Result<Self> {
85        Ok(Self {
86            audio: match &params.media {
87                MediaParametersType::Audio(params) => params.clone(),
88                _ => return Err(invalid_param_error!(params)),
89            },
90            encoder: match &params.codec {
91                CodecParametersType::Encoder(params) => params.clone(),
92                _ => return Err(invalid_param_error!(params)),
93            },
94        })
95    }
96}
97
98#[cfg(feature = "audio")]
99#[derive(Clone, Debug)]
100pub struct AudioEncoder {
101    pub audio: AudioParameters,
102    pub encoder: EncoderParameters,
103    // audio encoder specific configuration
104    pub frame_size: Option<u32>,
105    pub delay: Option<u32>,
106}
107
108#[cfg(feature = "audio")]
109impl CodecSpec for AudioEncoder {
110    type FrameDescriptor = AudioFrameDescriptor;
111
112    fn media_type() -> MediaType {
113        MediaType::Audio
114    }
115
116    fn codec_type() -> CodecType {
117        CodecType::Encoder
118    }
119
120    fn from_parameters(params: &CodecParameters) -> Result<Self> {
121        Ok(Self {
122            audio: (&params.media).try_into()?,
123            encoder: (&params.codec).try_into()?,
124            frame_size: None,
125            delay: None,
126        })
127    }
128
129    fn configure(&mut self, params: &CodecParameters) -> Result<()> {
130        let audio_params = (&params.media).try_into()?;
131        let encoder_params = (&params.codec).try_into()?;
132        self.audio.update(&audio_params);
133        self.encoder.update(&encoder_params);
134        Ok(())
135    }
136
137    fn configure_with_option(&mut self, key: &str, value: &Variant) -> Result<()> {
138        self.audio.update_with_option(key, value);
139        self.encoder.update_with_option(key, value);
140
141        match key {
142            "frame_size" => self.frame_size = value.get_uint32(),
143            "delay" => self.delay = value.get_uint32(),
144            _ => {}
145        }
146
147        Ok(())
148    }
149}
150
151#[cfg(feature = "video")]
152#[derive(Clone, Debug, Default)]
153pub struct VideoEncoderParameters {
154    pub video: VideoParameters,
155    pub encoder: EncoderParameters,
156}
157
158#[cfg(feature = "video")]
159#[allow(unreachable_patterns)]
160impl TryFrom<&CodecParameters> for VideoEncoderParameters {
161    type Error = Error;
162
163    #[allow(unreachable_patterns)]
164    fn try_from(params: &CodecParameters) -> Result<Self> {
165        Ok(Self {
166            video: match &params.media {
167                MediaParametersType::Video(params) => params.clone(),
168                _ => return Err(invalid_param_error!(params)),
169            },
170            encoder: match &params.codec {
171                CodecParametersType::Encoder(params) => params.clone(),
172                _ => return Err(invalid_param_error!(params)),
173            },
174        })
175    }
176}
177
178#[cfg(feature = "video")]
179#[derive(Clone, Debug)]
180pub struct VideoEncoder {
181    pub video: VideoParameters,
182    pub encoder: EncoderParameters,
183}
184
185#[cfg(feature = "video")]
186impl CodecSpec for VideoEncoder {
187    type FrameDescriptor = VideoFrameDescriptor;
188
189    fn media_type() -> MediaType {
190        MediaType::Video
191    }
192
193    fn codec_type() -> CodecType {
194        CodecType::Encoder
195    }
196
197    #[allow(unreachable_patterns)]
198    fn from_parameters(params: &CodecParameters) -> Result<Self> {
199        Ok(Self {
200            video: match &params.media {
201                MediaParametersType::Video(params) => params.clone(),
202                _ => return Err(invalid_param_error!(params)),
203            },
204            encoder: match &params.codec {
205                CodecParametersType::Encoder(params) => params.clone(),
206                _ => return Err(invalid_param_error!(params)),
207            },
208        })
209    }
210
211    #[allow(unreachable_patterns)]
212    fn configure(&mut self, params: &CodecParameters) -> Result<()> {
213        let video_params = (&params.media).try_into()?;
214        let encoder_params = (&params.codec).try_into()?;
215        self.video.update(&video_params);
216        self.encoder.update(&encoder_params);
217        Ok(())
218    }
219
220    fn configure_with_option(&mut self, key: &str, value: &Variant) -> Result<()> {
221        self.video.update_with_option(key, value);
222        self.encoder.update_with_option(key, value);
223        Ok(())
224    }
225}
226
227pub trait Encoder<T: CodecSpec>: Codec<T> + Send + Sync {
228    fn init(&mut self, _config: &T) -> Result<()> {
229        Ok(())
230    }
231    fn send_frame(&mut self, config: &T, pool: Option<&Arc<BufferPool>>, frame: SharedFrame<Frame<'static, T::FrameDescriptor>>) -> Result<()>;
232    fn receive_packet(&mut self, config: &T, pool: Option<&Arc<BufferPool>>) -> Result<Packet<'static>>;
233    fn flush(&mut self, config: &T) -> Result<()>;
234}
235
236pub trait EncoderBuilder<T: CodecSpec>: CodecBuilder<T> {
237    fn new_encoder(&self, id: CodecID, params: &CodecParameters, options: Option<&Variant>) -> Result<Box<dyn Encoder<T>>>;
238}
239
240pub struct EncoderContext<T: CodecSpec> {
241    pub config: T,
242    encoder: Box<dyn Encoder<T>>,
243    pool: Option<Arc<BufferPool>>,
244}
245
246#[cfg(feature = "audio")]
247static AUDIO_ENCODER_LIST: LazyCodecList<AudioEncoder> = LazyLock::new(|| {
248    RwLock::new(CodecList::<AudioEncoder> {
249        codecs: HashMap::new(),
250    })
251});
252
253#[cfg(feature = "video")]
254static VIDEO_ENCODER_LIST: LazyCodecList<VideoEncoder> = LazyLock::new(|| {
255    RwLock::new(CodecList::<VideoEncoder> {
256        codecs: HashMap::new(),
257    })
258});
259
260pub fn register_encoder<T: CodecSpec>(builder: Arc<dyn EncoderBuilder<T>>, default: bool) -> Result<()> {
261    match TypeId::of::<T>() {
262        #[cfg(feature = "audio")]
263        id if id == TypeId::of::<AudioEncoder>() => {
264            let builder = unsafe { mem::transmute::<Arc<dyn EncoderBuilder<T>>, Arc<dyn CodecBuilder<AudioEncoder>>>(builder) };
265            register_codec(&AUDIO_ENCODER_LIST, builder, default)
266        }
267        #[cfg(feature = "video")]
268        id if id == TypeId::of::<VideoEncoder>() => {
269            let builder = unsafe { mem::transmute::<Arc<dyn EncoderBuilder<T>>, Arc<dyn CodecBuilder<VideoEncoder>>>(builder) };
270            register_codec(&VIDEO_ENCODER_LIST, builder, default)
271        }
272        _ => Err(Error::Unsupported("codec parameters type".to_string())),
273    }
274}
275
276pub(crate) fn find_encoder<T: CodecSpec>(id: CodecID) -> Result<Arc<dyn EncoderBuilder<T>>> {
277    match TypeId::of::<T>() {
278        #[cfg(feature = "audio")]
279        type_id if type_id == TypeId::of::<AudioEncoder>() => {
280            let builder = find_codec(&AUDIO_ENCODER_LIST, id)?;
281            unsafe { Ok(mem::transmute::<Arc<dyn CodecBuilder<AudioEncoder>>, Arc<dyn EncoderBuilder<T>>>(builder)) }
282        }
283        #[cfg(feature = "video")]
284        type_id if type_id == TypeId::of::<VideoEncoder>() => {
285            let builder = find_codec(&VIDEO_ENCODER_LIST, id)?;
286            unsafe { Ok(mem::transmute::<Arc<dyn CodecBuilder<VideoEncoder>>, Arc<dyn EncoderBuilder<T>>>(builder)) }
287        }
288        _ => Err(Error::Unsupported("codec parameters type".to_string())),
289    }
290}
291
292pub(crate) fn find_encoder_by_name<T: CodecSpec>(name: &str) -> Result<Arc<dyn EncoderBuilder<T>>> {
293    match TypeId::of::<T>() {
294        #[cfg(feature = "audio")]
295        id if id == TypeId::of::<AudioEncoder>() => {
296            let builder = find_codec_by_name(&AUDIO_ENCODER_LIST, name)?;
297            unsafe { Ok(mem::transmute::<Arc<dyn CodecBuilder<AudioEncoder>>, Arc<dyn EncoderBuilder<T>>>(builder)) }
298        }
299        #[cfg(feature = "video")]
300        id if id == TypeId::of::<VideoEncoder>() => {
301            let builder = find_codec_by_name(&VIDEO_ENCODER_LIST, name)?;
302            unsafe { Ok(mem::transmute::<Arc<dyn CodecBuilder<VideoEncoder>>, Arc<dyn EncoderBuilder<T>>>(builder)) }
303        }
304        _ => Err(Error::Unsupported("codec parameters type".to_string())),
305    }
306}
307
308impl<T: CodecSpec> EncoderContext<T> {
309    pub fn from_codec_id(id: CodecID, params: &CodecParameters, options: Option<&Variant>) -> Result<Self> {
310        let builder = find_encoder(id)?;
311        let encoder = builder.new_encoder(id, params, options)?;
312        let config = T::from_parameters(params)?;
313
314        let buffer_pool = match &params.codec {
315            CodecParametersType::Encoder(encoder_params) => {
316                if encoder_params.use_pool.unwrap_or(false) {
317                    Some(BufferPool::new(0))
318                } else {
319                    None
320                }
321            }
322            _ => return Err(invalid_param_error!(params)),
323        };
324
325        Ok(Self {
326            config,
327            encoder,
328            pool: buffer_pool,
329        })
330    }
331
332    pub fn from_codec_name(name: &str, params: &CodecParameters, options: Option<&Variant>) -> Result<Self> {
333        let builder = find_encoder_by_name(name)?;
334        let encoder = builder.new_encoder(builder.id(), params, options)?;
335        let config = T::from_parameters(params)?;
336
337        Ok(Self {
338            config,
339            encoder,
340            pool: None,
341        })
342    }
343
344    pub fn configure(&mut self, params: Option<&CodecParameters>, options: Option<&Variant>) -> Result<()> {
345        if let Some(params) = params {
346            self.config.configure(params)?;
347        }
348        self.encoder.configure(params, options)
349    }
350
351    pub fn set_option(&mut self, key: &str, value: &Variant) -> Result<()> {
352        self.encoder.set_option(key, value)
353    }
354
355    pub fn send_frame(&mut self, frame: SharedFrame<Frame<'static, T::FrameDescriptor>>) -> Result<()> {
356        self.encoder.send_frame(&self.config, self.pool.as_ref(), frame)
357    }
358
359    pub fn receive_packet(&mut self) -> Result<Packet<'static>> {
360        self.encoder.receive_packet(&self.config, self.pool.as_ref())
361    }
362}