1use std::{
2 collections::HashMap,
3 marker::PhantomData,
4 sync::{Arc, LazyLock, RwLock},
5};
6
7pub use media_codec_types::encoder::*;
8use media_codec_types::{packet::Packet, CodecID, CodecParameters, CodecParametersType, CodecSpec};
9use media_core::{
10 buffer::BufferPool,
11 frame::{Frame, SharedFrame},
12 invalid_param_error,
13 rational::Rational64,
14 variant::Variant,
15 Result,
16};
17
18use crate::codec::{find_codec, find_codec_by_name, register_codec, CodecList, LazyCodecList};
19
20pub trait EncoderSpec: CodecSpec {
21 fn register(builder: Arc<dyn EncoderBuilder<Self>>, default: bool) -> Result<()>;
22 fn find(id: CodecID) -> Result<Arc<dyn EncoderBuilder<Self>>>;
23 fn find_by_name(name: &str) -> Result<Arc<dyn EncoderBuilder<Self>>>;
24}
25
26pub struct EncoderContext<T: EncoderSpec> {
27 pub config: T,
28 pub time_base: Option<Rational64>,
29 encoder: Box<dyn Encoder<T>>,
30 pool: Option<Arc<BufferPool>>,
31}
32
33#[cfg(feature = "audio")]
34static AUDIO_ENCODER_LIST: LazyCodecList<AudioEncoder, dyn EncoderBuilder<AudioEncoder>> = LazyLock::new(|| {
35 RwLock::new(CodecList::<AudioEncoder, dyn EncoderBuilder<AudioEncoder>> {
36 codecs: HashMap::new(),
37 _marker: PhantomData,
38 })
39});
40
41#[cfg(feature = "audio")]
42impl EncoderSpec for AudioEncoder {
43 fn register(builder: Arc<dyn EncoderBuilder<Self>>, default: bool) -> Result<()> {
44 register_codec(&AUDIO_ENCODER_LIST, builder, default)
45 }
46
47 fn find(id: CodecID) -> Result<Arc<dyn EncoderBuilder<Self>>> {
48 find_codec(&AUDIO_ENCODER_LIST, id)
49 }
50
51 fn find_by_name(name: &str) -> Result<Arc<dyn EncoderBuilder<Self>>> {
52 find_codec_by_name(&AUDIO_ENCODER_LIST, name)
53 }
54}
55
56#[cfg(feature = "video")]
57static VIDEO_ENCODER_LIST: LazyCodecList<VideoEncoder, dyn EncoderBuilder<VideoEncoder>> = LazyLock::new(|| {
58 RwLock::new(CodecList::<VideoEncoder, dyn EncoderBuilder<VideoEncoder>> {
59 codecs: HashMap::new(),
60 _marker: PhantomData,
61 })
62});
63
64#[cfg(feature = "video")]
65impl EncoderSpec for VideoEncoder {
66 fn register(builder: Arc<dyn EncoderBuilder<Self>>, default: bool) -> Result<()> {
67 register_codec(&VIDEO_ENCODER_LIST, builder, default)
68 }
69
70 fn find(id: CodecID) -> Result<Arc<dyn EncoderBuilder<Self>>> {
71 find_codec(&VIDEO_ENCODER_LIST, id)
72 }
73
74 fn find_by_name(name: &str) -> Result<Arc<dyn EncoderBuilder<Self>>> {
75 find_codec_by_name(&VIDEO_ENCODER_LIST, name)
76 }
77}
78
79pub fn register_encoder<T: EncoderSpec>(builder: Arc<dyn EncoderBuilder<T>>, default: bool) -> Result<()> {
80 T::register(builder, default)
81}
82
83pub(crate) fn find_encoder<T: EncoderSpec>(id: CodecID) -> Result<Arc<dyn EncoderBuilder<T>>> {
84 T::find(id)
85}
86
87pub(crate) fn find_encoder_by_name<T: EncoderSpec>(name: &str) -> Result<Arc<dyn EncoderBuilder<T>>> {
88 T::find_by_name(name)
89}
90
91impl<T: EncoderSpec> EncoderContext<T> {
92 pub fn new(codec_id: CodecID, codec_name: Option<&str>, params: &CodecParameters, options: Option<&Variant>) -> Result<Self> {
93 let builder = if let Some(codec_name) = codec_name {
94 find_encoder_by_name(codec_name)?
95 } else {
96 find_encoder(codec_id)?
97 };
98
99 let encoder = builder.new_encoder(codec_id, params, options)?;
100
101 Self::new_with_encoder(encoder, params)
102 }
103
104 pub fn new_with_encoder(encoder: Box<dyn Encoder<T>>, params: &CodecParameters) -> Result<Self> {
105 let config = T::from_parameters(params)?;
106
107 #[allow(unreachable_patterns)]
108 let buffer_pool = match ¶ms.codec {
109 CodecParametersType::Encoder(encoder_params) => {
110 if encoder_params.use_pool.unwrap_or(false) {
111 Some(BufferPool::new(0))
112 } else {
113 None
114 }
115 }
116 _ => return Err(invalid_param_error!(params)),
117 };
118
119 Ok(Self {
120 config,
121 time_base: None,
122 encoder,
123 pool: buffer_pool,
124 })
125 }
126
127 pub fn codec_id(&self) -> CodecID {
128 self.encoder.id()
129 }
130
131 pub fn codec_name(&self) -> &'static str {
132 self.encoder.name()
133 }
134
135 pub fn configure(&mut self, params: Option<&CodecParameters>, options: Option<&Variant>) -> Result<()> {
136 if let Some(params) = params {
137 self.config.configure(params)?;
138 }
139 self.encoder.configure(params, options)
140 }
141
142 pub fn set_option(&mut self, key: &str, value: &Variant) -> Result<()> {
143 self.encoder.set_option(key, value)
144 }
145
146 pub fn send_frame(&mut self, frame: SharedFrame<Frame<'static, T::FrameDescriptor>>) -> Result<()> {
147 self.encoder.send_frame(&self.config, self.pool.as_ref(), frame)
148 }
149
150 pub fn receive_packet(&mut self) -> Result<Packet<'static>> {
151 let mut packet = self.encoder.receive_packet(&self.config, self.pool.as_ref())?;
152
153 packet.time_base = packet.time_base.or(self.time_base);
154
155 Ok(packet)
156 }
157
158 pub fn flush(&mut self) -> Result<()> {
159 self.encoder.flush(&self.config)
160 }
161}