1use std::{
2 collections::HashMap,
3 marker::PhantomData,
4 sync::{Arc, LazyLock, RwLock},
5};
6
7use media_codec_types::{CodecBuilder, CodecID, CodecSpec};
8use media_core::{invalid_error, not_found_error, Result};
9
10pub(crate) struct CodecList<S: CodecSpec, B: ?Sized + CodecBuilder<S> = dyn CodecBuilder<S>> {
11 pub(crate) codecs: HashMap<CodecID, Vec<Arc<B>>>,
12 pub(crate) _marker: PhantomData<S>,
13}
14
15pub(crate) type LazyCodecList<S, B = dyn CodecBuilder<S>> = LazyLock<RwLock<CodecList<S, B>>>;
16
17pub(crate) fn register_codec<S, B>(codec_list: &LazyCodecList<S, B>, builder: Arc<B>, default: bool) -> Result<()>
18where
19 S: CodecSpec,
20 B: ?Sized + CodecBuilder<S>,
21{
22 let mut codec_list = codec_list.write().map_err(|err| invalid_error!(err.to_string()))?;
23 for &id in builder.ids() {
24 let list = codec_list.codecs.entry(id).or_default();
25
26 if default {
27 list.insert(0, builder.clone());
28 } else {
29 list.push(builder.clone());
30 }
31 }
32
33 Ok(())
34}
35
36pub(crate) fn find_codec<S, B>(codec_list: &LazyCodecList<S, B>, id: CodecID) -> Result<Arc<B>>
37where
38 S: CodecSpec,
39 B: ?Sized + CodecBuilder<S>,
40{
41 let codec_list = codec_list.read().map_err(|err| invalid_error!(err.to_string()))?;
42
43 if let Some(builders) = codec_list.codecs.get(&id) {
44 if let Some(builder) = builders.first() {
45 return Ok(builder.clone());
46 }
47 }
48
49 Err(not_found_error!(format!("codec: {:?}", id)))
50}
51
52pub(crate) fn find_codec_by_name<S, B>(codec_list: &LazyCodecList<S, B>, name: &str) -> Result<Arc<B>>
53where
54 S: CodecSpec,
55 B: ?Sized + CodecBuilder<S>,
56{
57 let codec_list = codec_list.read().map_err(|err| invalid_error!(err.to_string()))?;
58
59 for builders in codec_list.codecs.values() {
60 for builder in builders {
61 if builder.name() == name {
62 return Ok(builder.clone());
63 }
64 }
65 }
66
67 Err(not_found_error!(format!("codec: {}", name)))
68}