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