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