1 /*
2  * tccodecs.c -- codecs helper functions.
3  * (C) 2005-2010 - Francesco Romani <fromani -at- gmail -dot- com>
4  *
5  * This file is part of transcode, a video stream processing tool.
6  *
7  * transcode is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * transcode is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 
22 #include "libtc.h"
23 #include "src/transcode.h"
24 #include "tccodecs.h"
25 
26 #include <string.h>
27 
28 /* internal usage only ***************************************************/
29 
30 typedef struct {
31     TCCodecID id;        /* a TC_CODEC_* value */
32     const char *name;    /* usually != fourcc */
33     const char *fourcc;  /* real-world fourcc */
34     const char *comment;
35     int multipass;       /* multipass capable */
36     int flags;
37 } TCCodecInfo;
38 
39 
40 /*
41  * this table is *always* accessed in RO mode, so there is no need
42  * to protect it with threading locks
43  */
44 static const TCCodecInfo tc_codecs_info[] = {
45     /* video codecs */
46     { TC_CODEC_RGB,        "rgb",         "RGB",
47                            "RGB/BGR",                0, TC_VIDEO },
48     { TC_CODEC_YUV420P,    "yuv420p",     "I420",
49                            "YUV420P",                0, TC_VIDEO },
50     { TC_CODEC_YUV422P,    "yuv422p",     "UYVY",
51                            "YUV422P",                0, TC_VIDEO },
52     { TC_CODEC_YUY2,       "yuy2",        "YUY2",
53                            "YUY2",                   0, TC_VIDEO },
54     // XXX: right fcc?
55     { TC_CODEC_MPEG1VIDEO, "mpeg1video",  "mpg1",
56                            "MPEG1 ES",               1, TC_VIDEO },
57     { TC_CODEC_MPEG2VIDEO, "mpeg2video",  "mpg2",
58                            "MPEG2 ES",               1, TC_VIDEO },
59     { TC_CODEC_MPEG4VIDEO, "mpeg4video",  "mp4v",
60                            "MPEG4 ES",               1, TC_VIDEO },
61     /* FIXME; set up `DIVX' fcc for backward compatibility? */
62     { TC_CODEC_XVID,       "xvid",        "XVID",
63                            "XviD",                   1, TC_VIDEO },
64     { TC_CODEC_DIVX3,      "divx3",       "DIV3",
65                            "DivX;-)",                1, TC_VIDEO },
66     { TC_CODEC_DIVX4,      "divx4",       "DIVX",
67                            "DivX 4.x",               1, TC_VIDEO },
68     { TC_CODEC_DIVX5,      "divx5",       "DX50",
69                            "DivX 5.x",               1, TC_VIDEO },
70     { TC_CODEC_MJPEG,      "mjpeg",       "MJPG",
71                            "MJPEG",                  0, TC_VIDEO },
72     { TC_CODEC_LJPEG,      "ljpeg",       "LJPG",
73                            "Lossless (motion) JPEG", 0, TC_VIDEO },
74     { TC_CODEC_DV,         "dvvideo",     "DVSD",
75                            "DigitalVideo",           0, TC_VIDEO },
76     { TC_CODEC_LZO1,       "lzo1",        "LZO1",
77                            "LZO v1",                 0, TC_VIDEO },
78     { TC_CODEC_LZO2,       "lzo2",        "LZO2",
79                            "LZO v2",                 0, TC_VIDEO },
80     { TC_CODEC_MP42,       "msmpeg4v2",   "MP42",
81                            "MS MPEG4 v2",            1, TC_VIDEO },
82     { TC_CODEC_MP43,       "msmpeg4v3",   "MP43",
83                            "MS MPEG4 v3",            1, TC_VIDEO },
84     { TC_CODEC_RV10,       "realvideo10", "RV10",
85                            "RealVideo (old)",        0, TC_VIDEO },
86     { TC_CODEC_WMV1,       "wmv1",        "WMV1",
87                            "WMV v1 (WMP7)",          1, TC_VIDEO },
88     { TC_CODEC_WMV2,       "wmv2",        "WMV2",
89                            "WMV v2 (WMP8)",          1, TC_VIDEO },
90     { TC_CODEC_H264,       "h264",        "H264",
91                            "h.264 (AVC)",            1, TC_VIDEO },
92     { TC_CODEC_H263P,      "h263p",       "H263",
93                            "h.263 plus",             1, TC_VIDEO },
94     // XXX: right fcc?
95     { TC_CODEC_H263I,      "h263",        "H263",
96                            "h.263",                  0, TC_VIDEO },
97 
98     { TC_CODEC_HUFFYUV,    "huffyuv",     "HFYU",
99                            "HuffYUV",                1, TC_VIDEO },
100     // XXX: right fcc?
101     { TC_CODEC_FFV1,       "ffv1",        "FFV1",
102                            "FFV1 (experimental)",    1, TC_VIDEO },
103     { TC_CODEC_ASV1,       "asusvideo1",  "ASV1",
104                            "ASUS codec v1",          0, TC_VIDEO },
105     { TC_CODEC_ASV2,       "asusvideo2",  "ASV2",
106                            "ASUS codec v2",          0, TC_VIDEO },
107     { TC_CODEC_PV3,        "pv3",         "PV3",
108                            "PV3",                    0, TC_VIDEO }, /* XXX */
109     { TC_CODEC_NUV,        "nuv",         "NUV",
110                            "RTjpeg",                 0, TC_VIDEO }, /* XXX */
111 
112     /* FIXME: add more codec informations, on demand */
113 
114     /* audio codecs */
115     { TC_CODEC_PCM,        "pcm",         NULL,
116                            "PCM",                    0, TC_AUDIO },
117     { TC_CODEC_LPCM,       "lpcm",        NULL,
118                            "LPCM",                   0, TC_AUDIO },
119     { TC_CODEC_AC3,        "ac3",         NULL,
120                            "AC3",                    0, TC_AUDIO },
121     { TC_CODEC_MP3,        "mp3",         NULL,
122                            "MPEG ES Layer 3",        0, TC_AUDIO },
123     { TC_CODEC_MP2,        "mp2",         NULL,
124                            "MPEG ES Layer 2",        0, TC_AUDIO },
125     { TC_CODEC_AAC,        "aac",         NULL,
126                            "AAC",                    0, TC_AUDIO },
127     { TC_CODEC_VORBIS,     "vorbis",      NULL,
128                            "ogg/vorbis",             0, TC_AUDIO },
129     { TC_CODEC_VAG,        "vag",         NULL,
130                            "PS-VAG",                 0, TC_AUDIO },
131     /* FIXME: add more codec informations, on demand */
132 
133     /* miscelanous; XXX: drop from here */
134     { TC_CODEC_MPEG,       "MPEG",        NULL,
135                            "MPEG program stream",    0, TC_VIDEO|TC_AUDIO },
136     { TC_CODEC_MPEG1,      "MPEG-1",      NULL,
137                            "MPEG 1 program stream",  0, TC_VIDEO|TC_AUDIO },
138     { TC_CODEC_MPEG2,      "MPEG-2",      NULL,
139                            "MPEG 2 program stream",  0, TC_VIDEO|TC_AUDIO },
140 
141     /* special codecs*/
142     { TC_CODEC_ANY,        "everything",  NULL,
143                            NULL,                     0, 0 },
144     { TC_CODEC_UNKNOWN,    "unknown",     NULL,
145                            NULL,                     0, 0 },
146     { TC_CODEC_ERROR,      "error",       NULL,
147                            NULL,                     0, 0 }, // XXX
148     /* this MUST be the last one */
149 };
150 
151 /* compatibility */
tc_translate_codec_id(TCCodecID codec)152 int tc_translate_codec_id(TCCodecID codec)
153 {
154     switch (codec) {
155       case CODEC_AC3:    return TC_CODEC_AC3;
156       case CODEC_MP3:    return TC_CODEC_MP3;
157       case CODEC_MP2:    return TC_CODEC_MP2;
158       case CODEC_PCM:    return TC_CODEC_PCM;
159       case CODEC_LPCM:   return TC_CODEC_LPCM;
160       case CODEC_VORBIS: return TC_CODEC_VORBIS;
161       case CODEC_VAG:    return TC_CODEC_VAG;
162       default:           return TC_CODEC_ERROR; /* can't happen */
163     }
164     return TC_CODEC_ERROR;
165 }
166 
167 
168 /*
169  * TCCodecMatcher:
170  *      generic codec finder function family.
171  *      tell if a TCCodecInfo descriptor match certains given criterias
172  *      using a function-dependent method.
173  *      See also 'find_tc_codec' function.
174  *
175  * Parameters:
176  *      info: a pointer to a TCCodecInfo descriptor to be examinated
177  *  userdata: a pointer to data with function-dependent meaning
178  * Return Value:
179  *      TC_TRUE if function succeed,
180  *      TC_FALSE otherwise.
181  */
182 typedef int (*TCCodecMatcher)(const TCCodecInfo *info, const void *userdata);
183 
184 /*
185  * id_matcher:
186  *      match a TCCodecInfo descriptor on codec's id.
187  *      'userdata' must be an *address* of an uint32_t containing a TC_CODEC_*
188  *      to match.
189  *
190  * Parameters:
191  *      as for TCCodecMatcher
192  * Return Value:
193  *      as for TCCodecMatcher
194  */
id_matcher(const TCCodecInfo * info,const void * userdata)195 static int id_matcher(const TCCodecInfo *info, const void *userdata)
196 {
197     if (info == NULL || userdata == NULL) {
198         return TC_FALSE;
199     }
200 
201     return (*(int*)userdata == info->id) ?TC_TRUE :TC_FALSE;
202 }
203 
204 /*
205  * name_matcher:
206  *      match a TCCodecInfo descriptor on codec's name (note: note != fourcc).
207  *      'userdata' must be the C-string to match.
208  *      Note: ignore case.
209  *
210  * Parameters:
211  *      as for TCCodecMatcher
212  * Return Value:
213  *      as for TCCodecMatcher
214  */
name_matcher(const TCCodecInfo * info,const void * userdata)215 static int name_matcher(const TCCodecInfo *info, const void *userdata)
216 {
217     if (info == NULL || userdata == NULL) {
218         return TC_FALSE;
219     }
220     if(!info->name || (strcasecmp(info->name, userdata) != 0)) {
221         return TC_FALSE;
222     }
223     return TC_TRUE;
224 }
225 
226 /*
227  * find_tc_codec:
228  *      find a TCCodecInfo descriptor matching certains given criterias.
229  *      It scans the whole TCCodecInfos table applying the given
230  *      matcher with the given data to each element, halting when a match
231  *      is found
232  *
233  * Parameters:
234  *      matcher: a TCCodecMatcher to be applied to find the descriptor.
235  *     userdata: matching data to be passed to matcher together with a table
236  *               entry.
237  *
238  * Return Value:
239  *      >= 0: index of an entry in TCCodecInfo in table if an entry match
240  *            the finding criteria
241  *      TC_NULL_MATCH if no entry matches the given criteria
242  */
find_tc_codec(const TCCodecInfo * infos,TCCodecMatcher matcher,const void * userdata)243 static int find_tc_codec(const TCCodecInfo *infos,
244                          TCCodecMatcher matcher,
245                          const void *userdata)
246 {
247     int found = TC_FALSE, i = 0;
248 
249     if (infos == NULL) {
250         return TC_NULL_MATCH;
251     }
252 
253     for (i = 0; infos[i].id != TC_CODEC_ERROR; i++) {
254         found = matcher(&infos[i], userdata);
255         if (found) {
256             break;
257         }
258     }
259     if (!found) {
260         i = TC_NULL_MATCH;
261     }
262 
263     return i;
264 }
265 
266 /* public API ************************************************************/
267 
tc_codec_to_comment(TCCodecID codec)268 const char* tc_codec_to_comment(TCCodecID codec)
269 {
270     int idx = find_tc_codec(tc_codecs_info, id_matcher, &codec);
271 
272     if (idx == TC_NULL_MATCH) { /* not found */
273         return "unknown";
274     }
275     return tc_codecs_info[idx].comment; /* can be NULL */
276 }
277 
278 
tc_codec_to_string(TCCodecID codec)279 const char* tc_codec_to_string(TCCodecID codec)
280 {
281     int idx = find_tc_codec(tc_codecs_info, id_matcher, &codec);
282 
283     if (idx == TC_NULL_MATCH) { /* not found */
284         return NULL;
285     }
286     return tc_codecs_info[idx].name; /* can be NULL */
287 }
288 
tc_codec_from_string(const char * codec)289 TCCodecID tc_codec_from_string(const char *codec)
290 {
291     int idx = find_tc_codec(tc_codecs_info, name_matcher, codec);
292 
293     if (idx == TC_NULL_MATCH) { /* not found */
294         return TC_CODEC_ERROR;
295     }
296     return tc_codecs_info[idx].id;
297 }
298 
tc_codec_fourcc(TCCodecID codec)299 const char* tc_codec_fourcc(TCCodecID codec)
300 {
301     int idx = find_tc_codec(tc_codecs_info, id_matcher, &codec);
302 
303     if (idx == TC_NULL_MATCH) { /* not found */
304         return NULL;
305     }
306     return tc_codecs_info[idx].fourcc; /* can be NULL */
307 }
308 
tc_codec_description(TCCodecID codec,char * buf,size_t bufsize)309 int tc_codec_description(TCCodecID codec, char *buf, size_t bufsize)
310 {
311     int idx = find_tc_codec(tc_codecs_info, id_matcher, &codec);
312     int ret;
313 
314     if (idx == TC_NULL_MATCH) { /* not found */
315         return -1;
316     }
317 
318     ret = tc_snprintf(buf, bufsize, "%-12s: (fourcc=%s multipass=%-3s) %s",
319                       tc_codecs_info[idx].name,
320                       tc_codecs_info[idx].fourcc,
321                       tc_codecs_info[idx].multipass ?"yes" :"no",
322                       tc_codecs_info[idx].comment);
323     return ret;
324 }
325 
tc_codec_is_multipass(TCCodecID codec)326 int tc_codec_is_multipass(TCCodecID codec)
327 {
328     int idx = find_tc_codec(tc_codecs_info, id_matcher, &codec);
329 
330     if (idx == TC_NULL_MATCH) { /* not found */
331         return TC_FALSE;
332     }
333     return tc_codecs_info[idx].multipass;
334 }
335 
336 /*************************************************************************/
337 
338 /*
339  * Local variables:
340  *   c-file-style: "stroustrup"
341  *   c-file-offsets: ((case-label . *) (statement-case-intro . *))
342  *   indent-tabs-mode: nil
343  * End:
344  *
345  * vim: expandtab shiftwidth=4:
346  */
347