media_codec/
encoder.rs

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