registry: mark Sorenson Video 3 as having B-frames
[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 desc!(audio; "alaw", "A-law PCM"),
150 desc!(audio; "ulaw", "mu-law PCM"),
151
152 desc!(video-im; "indeo1", "Intel Raw IF09"),
153 desc!(video-im; "indeo2", "Intel Indeo 2"),
154 desc!(video; "indeo3", "Intel Indeo 3"),
155 desc!(video; "indeo4", "Intel Indeo 4", CODEC_CAP_REORDER | CODEC_CAP_SCALABLE),
156 desc!(video; "indeo5", "Intel Indeo 5", CODEC_CAP_REORDER | CODEC_CAP_SCALABLE),
157 desc!(video; "intel263", "Intel I263", CODEC_CAP_REORDER),
158 desc!(audio; "iac", "Intel Indeo audio"),
159 desc!(audio; "imc", "Intel Music Coder"),
160
161 desc!(video; "realvideo1", "Real Video 1"),
162 desc!(video; "realvideo2", "Real Video 2", CODEC_CAP_REORDER),
163 desc!(video; "realvideo3", "Real Video 3", CODEC_CAP_REORDER),
164 desc!(video; "realvideo4", "Real Video 4", CODEC_CAP_REORDER),
165 desc!(video; "realvideo6", "Real Video 6", CODEC_CAP_REORDER),
166 desc!(video; "clearvideo", "ClearVideo"),
167 desc!(video; "clearvideo_rm", "ClearVideo"),
168 desc!(audio; "ra14.4", "RealAudio 14.4"),
169 desc!(audio; "ra28.8", "RealAudio 28.8"),
170 desc!(audio; "cook", "RealAudio Cooker"),
171 desc!(audio; "ralf", "RealAudio Lossless"),
172 desc!(audio; "aac", "AAC"),
173 desc!(audio; "ac3", "ETSI TS 102 366"),
174 desc!(audio; "atrac3", "Sony Atrac3"),
175 desc!(audio; "sipro", "Sipro Labs ADPCM"),
176
177 desc!(video; "cinepak", "Cinepak"),
178
179 desc!(video; "msvideo1", "MS Video 1"),
180 desc!(video; "msrle", "MS RLE"),
181 desc!(audio; "ms-adpcm", "MS ADPCM"),
182 desc!(audio; "ima-adpcm-ms", "IMA ADPCM (MS variant)"),
183
184 desc!(video; "qt-smc", "Apple Graphics"),
185 desc!(video; "qt-rle", "Apple Animation"),
186 desc!(video; "apple-video", "Apple video"),
187 desc!(video; "sorenson-video", "Sorenson Video"),
188 desc!(video; "sorenson-video3", "Sorenson Video 3", CODEC_CAP_REORDER),
189 desc!(audio; "mace-3", "MACE 3:1"),
190 desc!(audio; "mace-6", "MACE 6:1"),
191 desc!(audio; "ima-adpcm-qt", "IMA ADPCM (Apple variant)"),
192 desc!(audio; "qdesign-music", "QDesign Music"),
193 desc!(audio; "qdesign-music2", "QDesign Music v2"),
194 desc!(audio; "qualcomm-purevoice", "Qualcomm PureVoice"),
195
196 desc!(video; "truemotion1", "TrueMotion 1"),
197 desc!(video-im; "truemotionrt", "TrueMotion RT"),
198 desc!(video; "truemotion2", "TrueMotion 2"),
199 desc!(video; "truemotion2x", "TrueMotion 2X"),
200 desc!(video; "vp3", "VP3"),
201 desc!(video; "vp4", "VP4"),
202 desc!(video; "vp5", "VP5"),
203 desc!(video; "vp6", "VP6"),
204 desc!(video; "vp6a", "VP6"),
205 desc!(video; "vp7", "VP7"),
206 desc!(video; "vp8", "VP8"),
207 desc!(video; "vp9", "VP9"),
208 desc!(audio; "adpcm-dk3", "Duck DK3 ADPCM"),
209 desc!(audio; "adpcm-dk4", "Duck DK4 ADPCM"),
210 desc!(audio; "on2avc-500", "On2 AVC"),
211 desc!(audio; "on2avc-501", "On2 AVC"),
212
213 desc!(video; "gdv-video", "Gremlin Digital Video - video"),
214 desc!(audio; "gdv-audio", "Gremlin Digital Video - audio"),
215 desc!(video; "bmv-video", "BMV video"),
216 desc!(audio; "bmv-audio", "BMV audio"),
217 desc!(video; "bmv3-video", "DW Noir BMV video"),
218 desc!(audio; "bmv3-audio", "DW Noir BMV audio"),
219 desc!(video; "midivid", "MidiVid"),
220 desc!(video; "midivid3", "MidiVid 3"),
221 desc!(video-ll; "midivid-ll", "MidiVid Lossless"),
222 desc!(video; "vmd-video", "VMD video"),
223 desc!(audio; "vmd-audio", "VMD audio"),
224
225 desc!(video; "smacker-video", "Smacker video"),
226 desc!(audio; "smacker-audio", "Smacker audio"),
227 desc!(video; "bink-video", "Bink video"),
228 desc!(video; "bink2-video", "Bink2 video"),
229 desc!(audio; "bink-audio-dct", "Bink audio (DCT)"),
230 desc!(audio; "bink-audio-rdft", "Bink audio (RDFT)"),
231
232 desc!(audio; "lhst15f8", "L&H StreamTalk 15kbps at 8 kHz"),
233 desc!(audio; "lhst250f11", "L&H StreamTalk 25kbps at 11 kHz"),
234 desc!(audio; "lhst500f22", "L&H StreamTalk 50kpbs at 22 kHz"),
235 desc!(audio; "lhst48", "L&H StreamTalk CELP Codec 4.8kbps at 8 kHz"),
236
237 desc!(video; "vivo1", "VivoActive Video 1.0"),
238 desc!(video; "vivo2", "VivoActive Video 2.0", CODEC_CAP_REORDER),
239 desc!(audio; "g723.1", "ITU G.723.1"),
240 desc!(audio; "siren", "Polycom Siren"),
241 ];
242
243 static AVI_VIDEO_CODEC_REGISTER: &'static [(&[u8;4], &str)] = &[
244 (&[1, 0, 0, 0], "msrle"),
245 (&[2, 0, 0, 0], "msrle"),
246
247 (b"CRAM", "msvideo1"),
248 (b"MSVC", "msvideo1"),
249 (b"WHAM", "msvideo1"),
250
251 (b"IF09", "indeo1"),
252 (b"RT21", "indeo2"),
253 (b"IV31", "indeo3"),
254 (b"IV32", "indeo3"),
255 (b"IV41", "indeo4"),
256 (b"IV50", "indeo5"),
257 (b"I263", "intel263"),
258
259 (b"UCOD", "clearvideo"),
260 (b"cvid", "cinepak"),
261
262 (b"MVDV", "midivid"),
263 (b"MV30", "midivid3"),
264 (b"MVLZ", "midivid-ll"),
265
266 (b"DUCK", "truemotion1"),
267 (b"TR20", "truemotionrt"),
268 (b"TM20", "truemotion2"),
269 (b"TM2A", "truemotion2x"),
270 (b"TM2X", "truemotion2x"),
271 (b"VP30", "vp3"),
272 (b"VP31", "vp3"),
273 (b"VP40", "vp4"),
274 (b"VP50", "vp5"),
275 (b"VP60", "vp6"),
276 (b"VP61", "vp6"),
277 (b"VP62", "vp6"),
278 (b"VP6A", "vp6a"),
279 (b"VP70", "vp7"),
280 ];
281
282 static WAV_CODEC_REGISTER: &'static [(u16, &str)] = &[
283 (0x0000, "unknown"),
284 (0x0001, "pcm"),
285 (0x0002, "ms-adpcm"),
286 (0x0003, "pcm"),
287 (0x0011, "ima-adpcm-ms"),
288 (0x0061, "adpcm-dk4"),
289 (0x0062, "adpcm-dk3"),
290 (0x0401, "imc"),
291 (0x0402, "iac"),
292 (0x0500, "on2avc-500"),
293 (0x0501, "on2avc-501"),
294 ];
295
296 static MOV_VIDEO_CODEC_REGISTER: &'static [(&[u8;4], &str)] = &[
297 (b"cvid", "cinepak"),
298 (b"jpeg", "jpeg"),
299 //(b"raw ", "raw"),
300 //(b"Yuv2", "raw"),
301 (b"smc ", "qt-smc"),
302 (b"rle ", "qt-rle"),
303 (b"rpza", "apple-video"),
304 (b"kpcd", "kodak-photocd"),
305 //(b"mpeg", "mpeg-video"),
306 (b"mjpa", "mjpeg-a"),
307 (b"mjpb", "mjpeg-b"),
308 (b"svqi", "sorenson-video"),
309 (b"SVQ1", "sorenson-video"),
310 (b"svq3", "sorenson-video3"),
311 (b"SVQ3", "sorenson-video3"),
312
313 (b"IV31", "indeo3"),
314 (b"IV32", "indeo3"),
315
316 (b"UCOD", "clearvideo"),
317
318 (b"VP30", "vp3"),
319 (b"VP31", "vp3"),
320 ];
321
322 static MOV_AUDIO_CODEC_REGISTER: &'static [(&[u8;4], &str)] = &[
323 (b"NONE", "pcm"),
324 (b"raw ", "pcm"),
325 (b"twos", "pcm"),
326 (b"sowt", "pcm"),
327 (b"fl32", "pcm"),
328 (b"fl64", "pcm"),
329 (b"in24", "pcm"),
330 (b"in32", "pcm"),
331 (b"MAC3", "mace-3"),
332 (b"MAC6", "mace-6"),
333 (b"ima4", "ima-adpcm-qt"),
334 (b"ulaw", "ulaw"),
335 (b"alaw", "alaw"),
336 (b"dvca", "dv-audio"),
337 (b"QDMC", "qdesign-music"),
338 (b"QDM2", "qdesign-music2"),
339 (b"Qclp", "qualcomm-purevoice"),
340 //(b".mp3", "mpeg-layer3"),
341 ];
342
343 /// Returns video codec short name for provided FOURCC (used in AVI format).
344 pub fn find_codec_from_avi_fourcc(fcc: &[u8;4]) -> Option<&'static str> {
345 for (fourcc, name) in AVI_VIDEO_CODEC_REGISTER.iter() {
346 if *fourcc == fcc { return Some(name); }
347 }
348 None
349 }
350
351 /// Returns FOURCC (used in AVI format) for provided codec name.
352 pub fn find_avi_fourcc(codecname: &str) -> Option<[u8; 4]> {
353 for (fourcc, name) in AVI_VIDEO_CODEC_REGISTER.iter() {
354 if *name == codecname { return Some(**fourcc); }
355 }
356 None
357 }
358
359 /// Returns known audio codec short name for provided TWOCC (used in WAV and AVI format).
360 pub fn find_codec_from_wav_twocc(tcc: u16) -> Option<&'static str> {
361 for (twocc, name) in WAV_CODEC_REGISTER.iter() {
362 if *twocc == tcc { return Some(name); }
363 }
364 None
365 }
366
367 /// Returns TWOCC (used in WAV and AVI format for provided codec name.
368 pub fn find_wav_twocc(codecname: &str) -> Option<u16> {
369 for (twocc, name) in WAV_CODEC_REGISTER.iter() {
370 if *name == codecname { return Some(*twocc); }
371 }
372 None
373 }
374
375 /// Returns video codec short name for provided FOURCC (used in MOV format).
376 pub fn find_codec_from_mov_video_fourcc(fcc: &[u8;4]) -> Option<&'static str> {
377 for (fourcc, name) in MOV_VIDEO_CODEC_REGISTER.iter() {
378 if *fourcc == fcc { return Some(name); }
379 }
380 None
381 }
382
383 /// Returns known audio codec short name for provided FOURCC (used in MOV format).
384 pub fn find_codec_from_mov_audio_fourcc(fcc: &[u8;4]) -> Option<&'static str> {
385 for (fourcc, name) in MOV_AUDIO_CODEC_REGISTER.iter() {
386 if *fourcc == fcc { return Some(name); }
387 }
388 None
389 }
390
391 #[cfg(test)]
392 mod test {
393 use super::*;
394
395 #[test]
396 fn test_register() {
397 let c1 = find_codec_from_avi_fourcc(b"IV41").unwrap();
398 let c2 = find_codec_from_wav_twocc(0x401).unwrap();
399 println!("found {} and {}", c1, c2);
400 let cd1 = get_codec_description(c1).unwrap();
401 let cd2 = get_codec_description(c2).unwrap();
402 println!("got {} and {}", cd1, cd2);
403 }
404 }