/* * tccodecs.c -- codecs helper functions. * (C) 2005-2010 - Francesco Romani * * This file is part of transcode, a video stream processing tool. * * transcode is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * transcode is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "libtc.h" #include "src/transcode.h" #include "tccodecs.h" #include /* internal usage only ***************************************************/ typedef struct { TCCodecID id; /* a TC_CODEC_* value */ const char *name; /* usually != fourcc */ const char *fourcc; /* real-world fourcc */ const char *comment; int multipass; /* multipass capable */ int flags; } TCCodecInfo; /* * this table is *always* accessed in RO mode, so there is no need * to protect it with threading locks */ static const TCCodecInfo tc_codecs_info[] = { /* video codecs */ { TC_CODEC_RGB, "rgb", "RGB", "RGB/BGR", 0, TC_VIDEO }, { TC_CODEC_YUV420P, "yuv420p", "I420", "YUV420P", 0, TC_VIDEO }, { TC_CODEC_YUV422P, "yuv422p", "UYVY", "YUV422P", 0, TC_VIDEO }, { TC_CODEC_YUY2, "yuy2", "YUY2", "YUY2", 0, TC_VIDEO }, // XXX: right fcc? { TC_CODEC_MPEG1VIDEO, "mpeg1video", "mpg1", "MPEG1 ES", 1, TC_VIDEO }, { TC_CODEC_MPEG2VIDEO, "mpeg2video", "mpg2", "MPEG2 ES", 1, TC_VIDEO }, { TC_CODEC_MPEG4VIDEO, "mpeg4video", "mp4v", "MPEG4 ES", 1, TC_VIDEO }, /* FIXME; set up `DIVX' fcc for backward compatibility? */ { TC_CODEC_XVID, "xvid", "XVID", "XviD", 1, TC_VIDEO }, { TC_CODEC_DIVX3, "divx3", "DIV3", "DivX;-)", 1, TC_VIDEO }, { TC_CODEC_DIVX4, "divx4", "DIVX", "DivX 4.x", 1, TC_VIDEO }, { TC_CODEC_DIVX5, "divx5", "DX50", "DivX 5.x", 1, TC_VIDEO }, { TC_CODEC_MJPEG, "mjpeg", "MJPG", "MJPEG", 0, TC_VIDEO }, { TC_CODEC_LJPEG, "ljpeg", "LJPG", "Lossless (motion) JPEG", 0, TC_VIDEO }, { TC_CODEC_DV, "dvvideo", "DVSD", "DigitalVideo", 0, TC_VIDEO }, { TC_CODEC_LZO1, "lzo1", "LZO1", "LZO v1", 0, TC_VIDEO }, { TC_CODEC_LZO2, "lzo2", "LZO2", "LZO v2", 0, TC_VIDEO }, { TC_CODEC_MP42, "msmpeg4v2", "MP42", "MS MPEG4 v2", 1, TC_VIDEO }, { TC_CODEC_MP43, "msmpeg4v3", "MP43", "MS MPEG4 v3", 1, TC_VIDEO }, { TC_CODEC_RV10, "realvideo10", "RV10", "RealVideo (old)", 0, TC_VIDEO }, { TC_CODEC_WMV1, "wmv1", "WMV1", "WMV v1 (WMP7)", 1, TC_VIDEO }, { TC_CODEC_WMV2, "wmv2", "WMV2", "WMV v2 (WMP8)", 1, TC_VIDEO }, { TC_CODEC_H264, "h264", "H264", "h.264 (AVC)", 1, TC_VIDEO }, { TC_CODEC_H263P, "h263p", "H263", "h.263 plus", 1, TC_VIDEO }, // XXX: right fcc? { TC_CODEC_H263I, "h263", "H263", "h.263", 0, TC_VIDEO }, { TC_CODEC_HUFFYUV, "huffyuv", "HFYU", "HuffYUV", 1, TC_VIDEO }, // XXX: right fcc? { TC_CODEC_FFV1, "ffv1", "FFV1", "FFV1 (experimental)", 1, TC_VIDEO }, { TC_CODEC_ASV1, "asusvideo1", "ASV1", "ASUS codec v1", 0, TC_VIDEO }, { TC_CODEC_ASV2, "asusvideo2", "ASV2", "ASUS codec v2", 0, TC_VIDEO }, { TC_CODEC_PV3, "pv3", "PV3", "PV3", 0, TC_VIDEO }, /* XXX */ { TC_CODEC_NUV, "nuv", "NUV", "RTjpeg", 0, TC_VIDEO }, /* XXX */ /* FIXME: add more codec informations, on demand */ /* audio codecs */ { TC_CODEC_PCM, "pcm", NULL, "PCM", 0, TC_AUDIO }, { TC_CODEC_LPCM, "lpcm", NULL, "LPCM", 0, TC_AUDIO }, { TC_CODEC_AC3, "ac3", NULL, "AC3", 0, TC_AUDIO }, { TC_CODEC_MP3, "mp3", NULL, "MPEG ES Layer 3", 0, TC_AUDIO }, { TC_CODEC_MP2, "mp2", NULL, "MPEG ES Layer 2", 0, TC_AUDIO }, { TC_CODEC_AAC, "aac", NULL, "AAC", 0, TC_AUDIO }, { TC_CODEC_VORBIS, "vorbis", NULL, "ogg/vorbis", 0, TC_AUDIO }, { TC_CODEC_VAG, "vag", NULL, "PS-VAG", 0, TC_AUDIO }, /* FIXME: add more codec informations, on demand */ /* miscelanous; XXX: drop from here */ { TC_CODEC_MPEG, "MPEG", NULL, "MPEG program stream", 0, TC_VIDEO|TC_AUDIO }, { TC_CODEC_MPEG1, "MPEG-1", NULL, "MPEG 1 program stream", 0, TC_VIDEO|TC_AUDIO }, { TC_CODEC_MPEG2, "MPEG-2", NULL, "MPEG 2 program stream", 0, TC_VIDEO|TC_AUDIO }, /* special codecs*/ { TC_CODEC_ANY, "everything", NULL, NULL, 0, 0 }, { TC_CODEC_UNKNOWN, "unknown", NULL, NULL, 0, 0 }, { TC_CODEC_ERROR, "error", NULL, NULL, 0, 0 }, // XXX /* this MUST be the last one */ }; /* compatibility */ int tc_translate_codec_id(TCCodecID codec) { switch (codec) { case CODEC_AC3: return TC_CODEC_AC3; case CODEC_MP3: return TC_CODEC_MP3; case CODEC_MP2: return TC_CODEC_MP2; case CODEC_PCM: return TC_CODEC_PCM; case CODEC_LPCM: return TC_CODEC_LPCM; case CODEC_VORBIS: return TC_CODEC_VORBIS; case CODEC_VAG: return TC_CODEC_VAG; default: return TC_CODEC_ERROR; /* can't happen */ } return TC_CODEC_ERROR; } /* * TCCodecMatcher: * generic codec finder function family. * tell if a TCCodecInfo descriptor match certains given criterias * using a function-dependent method. * See also 'find_tc_codec' function. * * Parameters: * info: a pointer to a TCCodecInfo descriptor to be examinated * userdata: a pointer to data with function-dependent meaning * Return Value: * TC_TRUE if function succeed, * TC_FALSE otherwise. */ typedef int (*TCCodecMatcher)(const TCCodecInfo *info, const void *userdata); /* * id_matcher: * match a TCCodecInfo descriptor on codec's id. * 'userdata' must be an *address* of an uint32_t containing a TC_CODEC_* * to match. * * Parameters: * as for TCCodecMatcher * Return Value: * as for TCCodecMatcher */ static int id_matcher(const TCCodecInfo *info, const void *userdata) { if (info == NULL || userdata == NULL) { return TC_FALSE; } return (*(int*)userdata == info->id) ?TC_TRUE :TC_FALSE; } /* * name_matcher: * match a TCCodecInfo descriptor on codec's name (note: note != fourcc). * 'userdata' must be the C-string to match. * Note: ignore case. * * Parameters: * as for TCCodecMatcher * Return Value: * as for TCCodecMatcher */ static int name_matcher(const TCCodecInfo *info, const void *userdata) { if (info == NULL || userdata == NULL) { return TC_FALSE; } if(!info->name || (strcasecmp(info->name, userdata) != 0)) { return TC_FALSE; } return TC_TRUE; } /* * find_tc_codec: * find a TCCodecInfo descriptor matching certains given criterias. * It scans the whole TCCodecInfos table applying the given * matcher with the given data to each element, halting when a match * is found * * Parameters: * matcher: a TCCodecMatcher to be applied to find the descriptor. * userdata: matching data to be passed to matcher together with a table * entry. * * Return Value: * >= 0: index of an entry in TCCodecInfo in table if an entry match * the finding criteria * TC_NULL_MATCH if no entry matches the given criteria */ static int find_tc_codec(const TCCodecInfo *infos, TCCodecMatcher matcher, const void *userdata) { int found = TC_FALSE, i = 0; if (infos == NULL) { return TC_NULL_MATCH; } for (i = 0; infos[i].id != TC_CODEC_ERROR; i++) { found = matcher(&infos[i], userdata); if (found) { break; } } if (!found) { i = TC_NULL_MATCH; } return i; } /* public API ************************************************************/ const char* tc_codec_to_comment(TCCodecID codec) { int idx = find_tc_codec(tc_codecs_info, id_matcher, &codec); if (idx == TC_NULL_MATCH) { /* not found */ return "unknown"; } return tc_codecs_info[idx].comment; /* can be NULL */ } const char* tc_codec_to_string(TCCodecID codec) { int idx = find_tc_codec(tc_codecs_info, id_matcher, &codec); if (idx == TC_NULL_MATCH) { /* not found */ return NULL; } return tc_codecs_info[idx].name; /* can be NULL */ } TCCodecID tc_codec_from_string(const char *codec) { int idx = find_tc_codec(tc_codecs_info, name_matcher, codec); if (idx == TC_NULL_MATCH) { /* not found */ return TC_CODEC_ERROR; } return tc_codecs_info[idx].id; } const char* tc_codec_fourcc(TCCodecID codec) { int idx = find_tc_codec(tc_codecs_info, id_matcher, &codec); if (idx == TC_NULL_MATCH) { /* not found */ return NULL; } return tc_codecs_info[idx].fourcc; /* can be NULL */ } int tc_codec_description(TCCodecID codec, char *buf, size_t bufsize) { int idx = find_tc_codec(tc_codecs_info, id_matcher, &codec); int ret; if (idx == TC_NULL_MATCH) { /* not found */ return -1; } ret = tc_snprintf(buf, bufsize, "%-12s: (fourcc=%s multipass=%-3s) %s", tc_codecs_info[idx].name, tc_codecs_info[idx].fourcc, tc_codecs_info[idx].multipass ?"yes" :"no", tc_codecs_info[idx].comment); return ret; } int tc_codec_is_multipass(TCCodecID codec) { int idx = find_tc_codec(tc_codecs_info, id_matcher, &codec); if (idx == TC_NULL_MATCH) { /* not found */ return TC_FALSE; } return tc_codecs_info[idx].multipass; } /*************************************************************************/ /* * Local variables: * c-file-style: "stroustrup" * c-file-offsets: ((case-label . *) (statement-case-intro . *)) * indent-tabs-mode: nil * End: * * vim: expandtab shiftwidth=4: */