Skip to main content

media_codec/
encoder.rs

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 &params.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}