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 AudioEncoderConfiguration {
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")]
78impl CodecConfiguration for AudioEncoderConfiguration {
79    type Parameters = AudioEncoderParameters;
80
81    fn from_parameters(parameters: &Self::Parameters) -> Result<Self> {
82        Ok(Self {
83            audio: parameters.audio.clone(),
84            encoder: parameters.encoder.clone(),
85            frame_size: None,
86            delay: None,
87        })
88    }
89
90    fn configure(&mut self, parameters: &Self::Parameters) -> Result<()> {
91        self.audio.update(&parameters.audio);
92        self.encoder.update(&parameters.encoder);
93        Ok(())
94    }
95
96    fn configure_with_option(&mut self, key: &str, value: &Variant) -> Result<()> {
97        self.audio.update_with_option(key, value);
98        self.encoder.update_with_option(key, value);
99
100        match key {
101            "frame_size" => self.frame_size = value.get_uint32(),
102            "delay" => self.delay = value.get_uint32(),
103            _ => {}
104        }
105
106        Ok(())
107    }
108}
109
110#[cfg(feature = "video")]
111#[derive(Clone, Debug, Default)]
112pub struct VideoEncoderParameters {
113    pub video: VideoParameters,
114    pub encoder: EncoderParameters,
115}
116
117#[cfg(feature = "video")]
118impl CodecParameters for VideoEncoderParameters {
119    fn media_type() -> MediaType {
120        MediaType::Video
121    }
122
123    fn codec_type() -> CodecType {
124        CodecType::Encoder
125    }
126}
127
128#[cfg(feature = "video")]
129#[derive(Clone, Debug)]
130pub struct VideoEncoderConfiguration {
131    pub video: VideoParameters,
132    pub encoder: EncoderParameters,
133}
134
135#[cfg(feature = "video")]
136impl CodecConfiguration for VideoEncoderConfiguration {
137    type Parameters = VideoEncoderParameters;
138
139    fn from_parameters(parameters: &Self::Parameters) -> Result<Self> {
140        Ok(Self {
141            video: parameters.video.clone(),
142            encoder: parameters.encoder.clone(),
143        })
144    }
145
146    fn configure(&mut self, parameters: &Self::Parameters) -> Result<()> {
147        self.video.update(&parameters.video);
148        self.encoder.update(&parameters.encoder);
149        Ok(())
150    }
151
152    fn configure_with_option(&mut self, key: &str, value: &Variant) -> Result<()> {
153        self.video.update_with_option(key, value);
154        self.encoder.update_with_option(key, value);
155        Ok(())
156    }
157}
158
159pub trait Encoder<T: CodecConfiguration>: Codec<T> + Send + Sync {
160    fn send_frame(&mut self, config: &T, frame: &Frame) -> Result<()>;
161    fn receive_packet(&mut self, config: &T) -> Result<Packet<'static>> {
162        self.receive_packet_borrowed(config).map(|packet| packet.into_owned())
163    }
164    fn receive_packet_borrowed(&mut self, config: &T) -> Result<Packet<'_>>;
165    fn flush(&mut self, config: &T) -> Result<()>;
166}
167
168pub trait EncoderBuilder<T: CodecConfiguration>: CodecBuilder<T> {
169    fn new_encoder(&self, id: CodecID, parameters: &T::Parameters, options: Option<&Variant>) -> Result<Box<dyn Encoder<T>>>;
170}
171
172pub struct EncoderContext<T: CodecConfiguration> {
173    pub configurations: T,
174    encoder: Box<dyn Encoder<T>>,
175}
176
177#[cfg(feature = "audio")]
178static AUDIO_ENCODER_LIST: LazyCodecList<AudioEncoderConfiguration> = LazyLock::new(|| {
179    RwLock::new(CodecList::<AudioEncoderConfiguration> {
180        codecs: HashMap::new(),
181    })
182});
183
184#[cfg(feature = "video")]
185static VIDEO_ENCODER_LIST: LazyCodecList<VideoEncoderConfiguration> = LazyLock::new(|| {
186    RwLock::new(CodecList::<VideoEncoderConfiguration> {
187        codecs: HashMap::new(),
188    })
189});
190
191pub fn register_encoder<T: CodecConfiguration>(builder: Arc<dyn EncoderBuilder<T>>, default: bool) -> Result<()> {
192    match TypeId::of::<T>() {
193        #[cfg(feature = "audio")]
194        id if id == TypeId::of::<AudioEncoderConfiguration>() => {
195            let builder = unsafe { mem::transmute::<Arc<dyn EncoderBuilder<T>>, Arc<dyn CodecBuilder<AudioEncoderConfiguration>>>(builder) };
196            register_codec(&AUDIO_ENCODER_LIST, builder, default)
197        }
198        #[cfg(feature = "video")]
199        id if id == TypeId::of::<VideoEncoderConfiguration>() => {
200            let builder = unsafe { mem::transmute::<Arc<dyn EncoderBuilder<T>>, Arc<dyn CodecBuilder<VideoEncoderConfiguration>>>(builder) };
201            register_codec(&VIDEO_ENCODER_LIST, builder, default)
202        }
203        _ => Err(Error::Unsupported("codec parameters type".to_string())),
204    }
205}
206
207pub(crate) fn find_encoder<T: CodecConfiguration>(id: CodecID) -> Result<Arc<dyn EncoderBuilder<T>>> {
208    match TypeId::of::<T>() {
209        #[cfg(feature = "audio")]
210        type_id if type_id == TypeId::of::<AudioEncoderConfiguration>() => {
211            let builder = find_codec(&AUDIO_ENCODER_LIST, id)?;
212            unsafe { Ok(mem::transmute::<Arc<dyn CodecBuilder<AudioEncoderConfiguration>>, Arc<dyn EncoderBuilder<T>>>(builder)) }
213        }
214        #[cfg(feature = "video")]
215        type_id if type_id == TypeId::of::<VideoEncoderConfiguration>() => {
216            let builder = find_codec(&VIDEO_ENCODER_LIST, id)?;
217            unsafe { Ok(mem::transmute::<Arc<dyn CodecBuilder<VideoEncoderConfiguration>>, Arc<dyn EncoderBuilder<T>>>(builder)) }
218        }
219        _ => Err(Error::Unsupported("codec parameters type".to_string())),
220    }
221}
222
223pub(crate) fn find_encoder_by_name<T: CodecConfiguration>(name: &str) -> Result<Arc<dyn EncoderBuilder<T>>> {
224    match TypeId::of::<T>() {
225        #[cfg(feature = "audio")]
226        id if id == TypeId::of::<AudioEncoderConfiguration>() => {
227            let builder = find_codec_by_name(&AUDIO_ENCODER_LIST, name)?;
228            unsafe { Ok(mem::transmute::<Arc<dyn CodecBuilder<AudioEncoderConfiguration>>, Arc<dyn EncoderBuilder<T>>>(builder)) }
229        }
230        #[cfg(feature = "video")]
231        id if id == TypeId::of::<VideoEncoderConfiguration>() => {
232            let builder = find_codec_by_name(&VIDEO_ENCODER_LIST, name)?;
233            unsafe { Ok(mem::transmute::<Arc<dyn CodecBuilder<VideoEncoderConfiguration>>, Arc<dyn EncoderBuilder<T>>>(builder)) }
234        }
235        _ => Err(Error::Unsupported("codec parameters type".to_string())),
236    }
237}
238
239impl<T: CodecConfiguration> EncoderContext<T> {
240    pub fn from_codec_id(id: CodecID, parameters: &T::Parameters, options: Option<&Variant>) -> Result<Self> {
241        let builder = find_encoder(id)?;
242        let encoder = builder.new_encoder(id, parameters, options)?;
243        let config = T::from_parameters(parameters)?;
244
245        Ok(Self {
246            configurations: config,
247            encoder,
248        })
249    }
250
251    pub fn from_codec_name(name: &str, parameters: &T::Parameters, options: Option<&Variant>) -> Result<Self> {
252        let builder = find_encoder_by_name(name)?;
253        let encoder = builder.new_encoder(builder.id(), parameters, options)?;
254        let config = T::from_parameters(parameters)?;
255
256        Ok(Self {
257            configurations: config,
258            encoder,
259        })
260    }
261
262    pub fn configure(&mut self, parameters: Option<&T::Parameters>, options: Option<&Variant>) -> Result<()> {
263        if let Some(params) = parameters {
264            self.configurations.configure(params)?;
265        }
266        self.encoder.configure(parameters, options)
267    }
268
269    pub fn set_option(&mut self, key: &str, value: &Variant) -> Result<()> {
270        self.encoder.set_option(key, value)
271    }
272
273    pub fn send_frame(&mut self, frame: &Frame) -> Result<()> {
274        self.encoder.send_frame(&self.configurations, frame)
275    }
276
277    pub fn receive_packet(&mut self) -> Result<Packet<'static>> {
278        self.encoder.receive_packet(&self.configurations)
279    }
280
281    pub fn receive_packet_borrowed(&mut self) -> Result<Packet<'_>> {
282        self.encoder.receive_packet_borrowed(&self.configurations)
283    }
284}