add a crate for common MS formats
[nihav.git] / nihav-registry / src / register.rs
1 //! Global registry of codec information.
2 //!
3 //! This module contains codec information from technical level that allows user to retrieve information about codec type and features without creating and invoking a decoder for such codec.
4 use std::fmt;
5
6 /// Codec types.
7 #[derive(Debug,Clone,Copy,PartialEq)]
8 #[allow(dead_code)]
9 pub enum CodecType {
10 /// Video codec.
11 Video,
12 /// Audio codec.
13 Audio,
14 /// Subtitle codec.
15 Subtitles,
16 /// Some special codec (e.g. some event stream or separate timecodes stream).
17 Data,
18 /// Dummy codec.
19 None,
20 }
21
22 impl fmt::Display for CodecType {
23 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24 match *self {
25 CodecType::Video => write!(f, "Video"),
26 CodecType::Audio => write!(f, "Audio"),
27 CodecType::Subtitles => write!(f, "Subtitles"),
28 CodecType::Data => write!(f, "Data"),
29 CodecType::None => write!(f, "-"),
30 }
31 }
32 }
33
34 const CODEC_CAP_INTRAONLY:u32 = 0x0001;
35 const CODEC_CAP_LOSSLESS:u32 = 0x0002;
36 const CODEC_CAP_REORDER:u32 = 0x0004;
37 const CODEC_CAP_HYBRID:u32 = 0x0008;
38 const CODEC_CAP_SCALABLE:u32 = 0x0010;
39
40 /// Codec description structure.
41 #[derive(Clone)]
42 pub struct CodecDescription {
43 /// Short codec name.
44 ///
45 /// Short codec name is used inside NihAV as the unique identifier.
46 pub name: &'static str,
47 /// Full codec name.
48 pub fname: &'static str,
49 /// Codec type.
50 pub ctype: CodecType,
51 /// Codec capabilities.
52 pub caps: u32,
53 }
54
55 impl CodecDescription {
56 /// Returns short codec name.
57 pub fn get_name(&self) -> &'static str { self.name }
58 /// Returns full codec name.
59 pub fn get_full_name(&self) -> &'static str { self.fname }
60 /// Returns codec type.
61 pub fn get_codec_type(&self) -> CodecType { self.ctype }
62 /// Reports whether the codec has only intra frames or not.
63 pub fn is_intraonly(&self) -> bool { (self.caps & CODEC_CAP_INTRAONLY) != 0 }
64 /// Reports whether the codec is lossless.
65 pub fn is_lossless(&self) -> bool { (self.caps & CODEC_CAP_LOSSLESS) != 0 }
66 /// Reports whether the codec requires frame reordering.
67 pub fn has_reorder(&self) -> bool { (self.caps & CODEC_CAP_REORDER) != 0 }
68 /// Reports whether the codec can be either lossless or lossy.
69 pub fn is_hybrid(&self) -> bool { (self.caps & CODEC_CAP_HYBRID) != 0 }
70 /// Reports whether codec supports scalability.
71 ///
72 /// Scalability means that codec can be decoded in reduced resolution by design.
73 pub fn is_scalable(&self) -> bool { (self.caps & CODEC_CAP_SCALABLE) != 0 }
74 }
75
76 impl fmt::Display for CodecDescription {
77 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78 let mut out = self.fname.to_string();
79 if self.caps != 0 {
80 let mut capfmt = "".to_string();
81 if (self.caps & CODEC_CAP_INTRAONLY) != 0 {
82 capfmt = format!("{} Intra-only", capfmt);
83 }
84 if (self.caps & CODEC_CAP_LOSSLESS) != 0 {
85 capfmt = format!("{} Lossless", capfmt);
86 }
87 if (self.caps & CODEC_CAP_REORDER) != 0 {
88 capfmt = format!("{} Frame reorder", capfmt);
89 }
90 if (self.caps & CODEC_CAP_HYBRID) != 0 {
91 capfmt = format!("{} Can be lossy and lossless", capfmt);
92 }
93 if (self.caps & CODEC_CAP_SCALABLE) != 0 {
94 capfmt = format!("{} Scalable", capfmt);
95 }
96 out = format!("{} ({})", out, capfmt);
97 }
98 write!(f, "{}", out)
99 }
100 }
101
102 macro_rules! desc {
103 (video; $n:expr, $fn:expr) => ({
104 CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Video,
105 caps: 0 }
106 });
107 (video; $n:expr, $fn:expr, $c:expr) => ({
108 CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Video,
109 caps: $c }
110 });
111 (video-ll; $n:expr, $fn:expr) => ({
112 CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Video,
113 caps: CODEC_CAP_LOSSLESS | CODEC_CAP_INTRAONLY }
114 });
115 (video-llp; $n:expr, $fn:expr) => ({
116 CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Video,
117 caps: CODEC_CAP_LOSSLESS }
118 });
119 (video-im; $n:expr, $fn:expr) => ({
120 CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Video,
121 caps: CODEC_CAP_INTRAONLY }
122 });
123 (video-modern; $n:expr, $fn:expr) => ({
124 CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Video,
125 caps: CODEC_CAP_REORDER | CODEC_CAP_HYBRID }
126 });
127 (audio; $n:expr, $fn:expr) => ({
128 CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Audio,
129 caps: 0 }
130 });
131 (audio-ll; $n:expr, $fn:expr) => ({
132 CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Audio,
133 caps: CODEC_CAP_LOSSLESS | CODEC_CAP_INTRAONLY }
134 });
135 }
136
137 /// Returns codec description for the provided codec short name if it is found.
138 pub fn get_codec_description(name: &str) -> Option<&'static CodecDescription> {
139 for reg in CODEC_REGISTER {
140 if reg.name == name {
141 return Some(reg);
142 }
143 }
144 None
145 }
146
147 static CODEC_REGISTER: &'static [CodecDescription] = &[
148 desc!(audio-ll; "pcm", "PCM"),
149
150 desc!(video-im; "indeo1", "Intel Raw IF09"),
151 desc!(video-im; "indeo2", "Intel Indeo 2"),
152 desc!(video; "indeo3", "Intel Indeo 3"),
153 desc!(video; "indeo4", "Intel Indeo 4", CODEC_CAP_REORDER | CODEC_CAP_SCALABLE),
154 desc!(video; "indeo5", "Intel Indeo 5", CODEC_CAP_REORDER | CODEC_CAP_SCALABLE),
155 desc!(video; "intel263", "Intel I263", CODEC_CAP_REORDER),
156 desc!(audio; "iac", "Intel Indeo audio"),
157 desc!(audio; "imc", "Intel Music Coder"),
158
159 desc!(video; "realvideo1", "Real Video 1"),
160 desc!(video; "realvideo2", "Real Video 2", CODEC_CAP_REORDER),
161 desc!(video; "realvideo3", "Real Video 3", CODEC_CAP_REORDER),
162 desc!(video; "realvideo4", "Real Video 4", CODEC_CAP_REORDER),
163 desc!(video; "realvideo6", "Real Video 6", CODEC_CAP_REORDER),
164 desc!(video; "clearvideo", "ClearVideo"),
165 desc!(video; "clearvideo_rm", "ClearVideo"),
166 desc!(audio; "ra14.4", "RealAudio 14.4"),
167 desc!(audio; "ra28.8", "RealAudio 28.8"),
168 desc!(audio; "cook", "RealAudio Cooker"),
169 desc!(audio; "ralf", "RealAudio Lossless"),
170 desc!(audio; "aac", "AAC"),
171 desc!(audio; "ac3", "ETSI TS 102 366"),
172 desc!(audio; "atrac3", "Sony Atrac3"),
173 desc!(audio; "sipro", "Sipro Labs ADPCM"),
174
175 desc!(video; "cinepak", "Cinepak"),
176
177 desc!(video; "msvideo1", "MS Video 1"),
178 desc!(audio; "ms-adpcm", "MS ADPCM"),
179 desc!(audio; "ima-adpcm-ms", "IMA ADPCM (MS variant)"),
180
181 desc!(video; "truemotion1", "TrueMotion 1"),
182 desc!(video-im; "truemotionrt", "TrueMotion RT"),
183 desc!(video; "truemotion2", "TrueMotion 2"),
184 desc!(video; "truemotion2x", "TrueMotion 2X"),
185 desc!(video; "vp3", "VP3"),
186 desc!(video; "vp4", "VP4"),
187 desc!(video; "vp5", "VP5"),
188 desc!(video; "vp6", "VP6"),
189 desc!(video; "vp6a", "VP6"),
190 desc!(video; "vp7", "VP7"),
191 desc!(video; "vp8", "VP8"),
192 desc!(video; "vp9", "VP9"),
193 desc!(audio; "adpcm-dk3", "Duck DK3 ADPCM"),
194 desc!(audio; "adpcm-dk4", "Duck DK4 ADPCM"),
195 desc!(audio; "on2avc-500", "On2 AVC"),
196 desc!(audio; "on2avc-501", "On2 AVC"),
197
198 desc!(video; "gdv-video", "Gremlin Digital Video - video"),
199 desc!(audio; "gdv-audio", "Gremlin Digital Video - audio"),
200 desc!(video; "bmv-video", "BMV video"),
201 desc!(audio; "bmv-audio", "BMV audio"),
202 desc!(video; "bmv3-video", "DW Noir BMV video"),
203 desc!(audio; "bmv3-audio", "DW Noir BMV audio"),
204 desc!(video; "midivid", "MidiVid"),
205 desc!(video; "midivid3", "MidiVid 3"),
206 desc!(video-ll; "midivid-ll", "MidiVid Lossless"),
207 desc!(video; "vmd-video", "VMD video"),
208 desc!(audio; "vmd-audio", "VMD audio"),
209
210 desc!(video; "smacker-video", "Smacker video"),
211 desc!(audio; "smacker-audio", "Smacker audio"),
212 desc!(video; "bink-video", "Bink video"),
213 desc!(video; "bink2-video", "Bink2 video"),
214 desc!(audio; "bink-audio-dct", "Bink audio (DCT)"),
215 desc!(audio; "bink-audio-rdft", "Bink audio (RDFT)"),
216
217 desc!(audio; "lhst15f8", "L&H StreamTalk 15kbps at 8 kHz"),
218 desc!(audio; "lhst250f11", "L&H StreamTalk 25kbps at 11 kHz"),
219 desc!(audio; "lhst500f22", "L&H StreamTalk 50kpbs at 22 kHz"),
220 desc!(audio; "lhst48", "L&H StreamTalk CELP Codec 4.8kbps at 8 kHz"),
221
222 desc!(video; "vivo1", "VivoActive Video 1.0"),
223 desc!(video; "vivo2", "VivoActive Video 2.0", CODEC_CAP_REORDER),
224 desc!(audio; "g723.1", "ITU G.723.1"),
225 desc!(audio; "siren", "Polycom Siren"),
226 ];
227
228 static AVI_VIDEO_CODEC_REGISTER: &'static [(&[u8;4], &str)] = &[
229 (b"CRAM", "msvideo1"),
230 (b"MSVC", "msvideo1"),
231 (b"WHAM", "msvideo1"),
232
233 (b"IF09", "indeo1"),
234 (b"RT21", "indeo2"),
235 (b"IV31", "indeo3"),
236 (b"IV32", "indeo3"),
237 (b"IV41", "indeo4"),
238 (b"IV50", "indeo5"),
239 (b"I263", "intel263"),
240
241 (b"UCOD", "clearvideo"),
242 (b"cvid", "cinepak"),
243
244 (b"MVDV", "midivid"),
245 (b"MV30", "midivid3"),
246 (b"MVLZ", "midivid-ll"),
247
248 (b"DUCK", "truemotion1"),
249 (b"TR20", "truemotionrt"),
250 (b"TM20", "truemotion2"),
251 (b"TM2A", "truemotion2x"),
252 (b"TM2X", "truemotion2x"),
253 (b"VP30", "vp3"),
254 (b"VP31", "vp3"),
255 (b"VP40", "vp4"),
256 (b"VP50", "vp5"),
257 (b"VP60", "vp6"),
258 (b"VP61", "vp6"),
259 (b"VP62", "vp6"),
260 (b"VP6A", "vp6a"),
261 (b"VP70", "vp7"),
262 ];
263
264 static WAV_CODEC_REGISTER: &'static [(u16, &str)] = &[
265 (0x0000, "pcm"),
266 (0x0001, "pcm"),
267 (0x0002, "ms-adpcm"),
268 (0x0003, "pcm"),
269 (0x0011, "ima-adpcm-ms"),
270 (0x0061, "adpcm-dk4"),
271 (0x0062, "adpcm-dk3"),
272 (0x0401, "imc"),
273 (0x0402, "iac"),
274 (0x0500, "on2avc-500"),
275 (0x0501, "on2avc-501"),
276 ];
277
278 static MOV_VIDEO_CODEC_REGISTER: &'static [(&[u8;4], &str)] = &[
279 (b"cvid", "cinepak"),
280 (b"jpeg", "jpeg"),
281 //(b"raw ", "raw"),
282 //(b"Yuv2", "raw"),
283 (b"smc ", "qt-smc"),
284 (b"rle ", "qt-rle"),
285 (b"rpza", "apple-video"),
286 (b"kpcd", "kodak-photocd"),
287 //(b"mpeg", "mpeg-video"),
288 (b"mjpa", "mjpeg-a"),
289 (b"mjpb", "mjpeg-b"),
290 (b"svqi", "sorenson-video"),
291
292 (b"IV31", "indeo3"),
293 (b"IV32", "indeo3"),
294
295 (b"UCOD", "clearvideo"),
296
297 (b"VP30", "vp3"),
298 (b"VP31", "vp3"),
299 ];
300
301 static MOV_AUDIO_CODEC_REGISTER: &'static [(&[u8;4], &str)] = &[
302 (b"NONE", "pcm"),
303 (b"raw ", "pcm"),
304 (b"twos", "pcm"),
305 (b"sowt", "pcm"),
306 (b"fl32", "pcm"),
307 (b"fl64", "pcm"),
308 (b"in24", "pcm"),
309 (b"in32", "pcm"),
310 (b"MAC3", "mace-3"),
311 (b"MAC6", "mace-6"),
312 (b"ima4", "ima-adpcm-qt"),
313 (b"ulaw", "ulaw"),
314 (b"alaw", "alaw"),
315 (b"dvca", "dv-audio"),
316 (b"QDMC", "qdesign-music"),
317 (b"QDM2", "qdesign-music2"),
318 (b"Qclp", "qualcomm-purevoice"),
319 //(b".mp3", "mpeg-layer3"),
320 ];
321
322 /// Returns video codec short name for provided FOURCC (used in AVI format).
323 pub fn find_codec_from_avi_fourcc(fcc: &[u8;4]) -> Option<&'static str> {
324 for (fourcc, name) in AVI_VIDEO_CODEC_REGISTER.iter() {
325 if *fourcc == fcc { return Some(name); }
326 }
327 None
328 }
329
330 /// Returns FOURCC (used in AVI format) for provided codec name.
331 pub fn find_avi_fourcc(codecname: &str) -> Option<[u8; 4]> {
332 for (fourcc, name) in AVI_VIDEO_CODEC_REGISTER.iter() {
333 if *name == codecname { return Some(**fourcc); }
334 }
335 None
336 }
337
338 /// Returns known audio codec short name for provided TWOCC (used in WAV and AVI format).
339 pub fn find_codec_from_wav_twocc(tcc: u16) -> Option<&'static str> {
340 for (twocc, name) in WAV_CODEC_REGISTER.iter() {
341 if *twocc == tcc { return Some(name); }
342 }
343 None
344 }
345
346 /// Returns TWOCC (used in WAV and AVI format for provided codec name.
347 pub fn find_wav_twocc(codecname: &str) -> Option<u16> {
348 for (twocc, name) in WAV_CODEC_REGISTER.iter() {
349 if *name == codecname { return Some(*twocc); }
350 }
351 None
352 }
353
354 /// Returns video codec short name for provided FOURCC (used in MOV format).
355 pub fn find_codec_from_mov_video_fourcc(fcc: &[u8;4]) -> Option<&'static str> {
356 for (fourcc, name) in MOV_VIDEO_CODEC_REGISTER.iter() {
357 if *fourcc == fcc { return Some(name); }
358 }
359 None
360 }
361
362 /// Returns known audio codec short name for provided FOURCC (used in MOV format).
363 pub fn find_codec_from_mov_audio_fourcc(fcc: &[u8;4]) -> Option<&'static str> {
364 for (fourcc, name) in MOV_AUDIO_CODEC_REGISTER.iter() {
365 if *fourcc == fcc { return Some(name); }
366 }
367 None
368 }
369
370 #[cfg(test)]
371 mod test {
372 use super::*;
373
374 #[test]
375 fn test_register() {
376 let c1 = find_codec_from_avi_fourcc(b"IV41").unwrap();
377 let c2 = find_codec_from_wav_twocc(0x401).unwrap();
378 println!("found {} and {}", c1, c2);
379 let cd1 = get_codec_description(c1).unwrap();
380 let cd2 = get_codec_description(c2).unwrap();
381 println!("got {} and {}", cd1, cd2);
382 }
383 }