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 ¶ms.media {
83 MediaParametersType::Audio(params) => params.clone(),
84 _ => return Err(invalid_param_error!(params)),
85 },
86 encoder: match ¶ms.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 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: (¶ms.media).try_into()?,
121 encoder: (¶ms.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 = (¶ms.media).try_into()?;
129 let encoder_params = (¶ms.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 ¶ms.media {
165 MediaParametersType::Video(params) => params.clone(),
166 _ => return Err(invalid_param_error!(params)),
167 },
168 encoder: match ¶ms.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 ¶ms.media {
201 MediaParametersType::Video(params) => params.clone(),
202 _ => return Err(invalid_param_error!(params)),
203 },
204 encoder: match ¶ms.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 = (¶ms.media).try_into()?;
214 let encoder_params = (¶ms.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 ¶ms.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}