You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

347 lines
12 KiB
C

/*
* tccodecs.c -- codecs helper functions.
* (C) 2005-2010 - Francesco Romani <fromani -at- gmail -dot- com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "libtc.h"
#include "src/transcode.h"
#include "tccodecs.h"
#include <string.h>
/* 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:
*/