media_codec/
encoder.rs

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