extend formats functionality a bit
[nihav.git] / src / register.rs
1 use std::fmt;
2
3 #[derive(Debug,Clone,Copy)]
4 #[allow(dead_code)]
5 pub enum CodecType {
6 Video,
7 Audio,
8 Subtitles,
9 Data,
10 None,
11 }
12
13 impl fmt::Display for CodecType {
14 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15 match *self {
16 CodecType::Video => write!(f, "Video"),
17 CodecType::Audio => write!(f, "Audio"),
18 CodecType::Subtitles => write!(f, "Subtitles"),
19 CodecType::Data => write!(f, "Data"),
20 CodecType::None => write!(f, "-"),
21 }
22 }
23 }
24
25 const CODEC_CAP_INTRAONLY:u32 = 0x000001;
26 const CODEC_CAP_LOSSLESS:u32 = 0x000002;
27 const CODEC_CAP_REORDER:u32 = 0x000004;
28 const CODEC_CAP_HYBRID:u32 = 0x000008;
29 const CODEC_CAP_SCALABLE:u32 = 0x000010;
30
31 pub struct CodecDescription {
32 name: &'static str,
33 fname: &'static str,
34 ctype: CodecType,
35 caps: u32,
36 }
37
38 impl CodecDescription {
39 pub fn get_name(&self) -> &'static str { self.name }
40 pub fn get_full_name(&self) -> &'static str { self.fname }
41 pub fn get_codec_type(&self) -> CodecType { self.ctype }
42 pub fn is_intraonly(&self) -> bool { (self.caps & CODEC_CAP_INTRAONLY) != 0 }
43 pub fn is_lossless(&self) -> bool { (self.caps & CODEC_CAP_LOSSLESS) != 0 }
44 pub fn has_reorder(&self) -> bool { (self.caps & CODEC_CAP_REORDER) != 0 }
45 pub fn is_hybrid(&self) -> bool { (self.caps & CODEC_CAP_HYBRID) != 0 }
46 pub fn is_scalable(&self) -> bool { (self.caps & CODEC_CAP_SCALABLE) != 0 }
47 }
48
49 impl fmt::Display for CodecDescription {
50 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51 let mut out = format!("{}", self.fname);
52 if self.caps != 0 {
53 let mut capfmt = "".to_string();
54 if (self.caps & CODEC_CAP_INTRAONLY) != 0 {
55 capfmt = format!("{} Intra-only", capfmt);
56 }
57 if (self.caps & CODEC_CAP_LOSSLESS) != 0 {
58 capfmt = format!("{} Lossless", capfmt);
59 }
60 if (self.caps & CODEC_CAP_REORDER) != 0 {
61 capfmt = format!("{} Frame reorder", capfmt);
62 }
63 if (self.caps & CODEC_CAP_HYBRID) != 0 {
64 capfmt = format!("{} Can be lossy and lossless", capfmt);
65 }
66 if (self.caps & CODEC_CAP_SCALABLE) != 0 {
67 capfmt = format!("{} Scalable", capfmt);
68 }
69 out = format!("{} ({})", out, capfmt);
70 }
71 write!(f, "{}", out)
72 }
73 }
74
75 macro_rules! desc {
76 (video; $n:expr, $fn:expr) => ({
77 CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Video,
78 caps: 0 }
79 });
80 (video; $n:expr, $fn:expr, $c:expr) => ({
81 CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Video,
82 caps: $c }
83 });
84 (video-ll; $n:expr, $fn:expr) => ({
85 CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Video,
86 caps: CODEC_CAP_LOSSLESS | CODEC_CAP_INTRAONLY }
87 });
88 (video-llp; $n:expr, $fn:expr) => ({
89 CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Video,
90 caps: CODEC_CAP_LOSSLESS }
91 });
92 (video-im; $n:expr, $fn:expr) => ({
93 CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Video,
94 caps: CODEC_CAP_INTRAONLY }
95 });
96 (video-modern; $n:expr, $fn:expr) => ({
97 CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Video,
98 caps: CODEC_CAP_REORDER | CODEC_CAP_HYBRID }
99 });
100 (audio; $n:expr, $fn:expr) => ({
101 CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Audio,
102 caps: 0 }
103 });
104 (audio-ll; $n:expr, $fn:expr) => ({
105 CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Audio,
106 caps: CODEC_CAP_LOSSLESS | CODEC_CAP_INTRAONLY }
107 });
108 }
109
110 pub fn get_codec_description(name: &str) -> Option<&'static CodecDescription> {
111 for i in 0..CODEC_REGISTER.len() {
112 if CODEC_REGISTER[i].name == name {
113 return Some(&CODEC_REGISTER[i]);
114 }
115 }
116 None
117 }
118
119 static CODEC_REGISTER: &'static [CodecDescription] = &[
120 desc!(video-im; "video-indeo1", "Intel Raw IF09"),
121 desc!(video-im; "video-indeo2", "Intel Indeo 2"),
122 desc!(video; "video-indeo3", "Intel Indeo 3"),
123 desc!(video; "video-indeo4", "Intel Indeo 4", CODEC_CAP_REORDER | CODEC_CAP_SCALABLE),
124 desc!(video; "video-indeo5", "Intel Indeo 5", CODEC_CAP_REORDER | CODEC_CAP_SCALABLE),
125 desc!(audio; "audio-iac", "Intel Indeo audio"),
126 desc!(audio; "audio-imc", "Intel Music Coder"),
127 ];
128
129 static AVI_VIDEO_CODEC_REGISTER: &'static [(&[u8;4], &str)] = &[
130 (b"IF09", "video-indeo1"),
131 (b"RT21", "video-indeo2"),
132 (b"IV31", "video-indeo3"),
133 (b"IV32", "video-indeo3"),
134 (b"IV41", "video-indeo4"),
135 (b"IV50", "video-indeo5"),
136 ];
137
138 static WAV_CODEC_REGISTER: &'static [(u16, &str)] = &[
139 (0x0000, "audio-pcm"),
140 (0x0001, "audio-pcm"),
141 (0x0003, "audio-pcm"),
142 (0x0401, "audio-imc"),
143 (0x0402, "audio-iac"),
144 ];
145
146 pub fn find_codec_from_avi_fourcc(fcc: &[u8;4]) -> Option<&'static str> {
147 for i in 0..AVI_VIDEO_CODEC_REGISTER.len() {
148 let (fourcc, name) = AVI_VIDEO_CODEC_REGISTER[i];
149 if fourcc == fcc { return Some(name); }
150 }
151 None
152 }
153
154 pub fn find_codec_from_wav_twocc(tcc: u16) -> Option<&'static str> {
155 for i in 0..WAV_CODEC_REGISTER.len() {
156 let (twocc, name) = WAV_CODEC_REGISTER[i];
157 if twocc == tcc { return Some(name); }
158 }
159 None
160 }
161
162 #[cfg(test)]
163 mod test {
164 use super::*;
165
166 #[test]
167 fn test_register() {
168 let c1 = find_codec_from_avi_fourcc(b"IV41").unwrap();
169 let c2 = find_codec_from_wav_twocc(0x401).unwrap();
170 println!("found {} and {}", c1, c2);
171 let cd1 = get_codec_description(c1).unwrap();
172 let cd2 = get_codec_description(c2).unwrap();
173 println!("got {} and {}", cd1, cd2);
174 }
175 }