/*
* codecs.c,
*
* Copyright (C) 2004-06 Karl, Frankfurt
*
* This program 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.
*
* This program 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#ifdef SOLARIS
#include <strings.h>
#else
#include <string.h>
#endif
#include <locale.h>
#include <ctype.h>
#include <libintl.h>
#include "app_data.h"
#include "codecs.h"
#include "xvidcap-intl.h"
#include <ffmpeg/avcodec.h>
#include <ffmpeg/avformat.h>
#define DEBUGFILE "codecs.c"
xvCodec tCodecs[NUMCODECS];
xvFFormat tFFormats[NUMCAPS];
xvAuCodec tAuCodecs[NUMAUCODECS];
const xvCodec none = {
"NONE",
N_("NONE"),
CODEC_NONE,
CODEC_ID_NONE,
0,
0,
NULL,
NULL
};
#ifdef USE_FFMPEG
const xvCodec pgm = {
"PGM",
N_("Portable Graymap"),
CODEC_PGM,
CODEC_ID_PGM,
300000,
24,
"0.1-100",
NULL
};
const xvCodec ppm = {
"PPM",
N_("Portable Pixmap"),
CODEC_PPM,
CODEC_ID_PPM,
300000,
24,
"0.1-100",
NULL
};
const xvCodec png = {
"PNG",
N_("Portable Network Graphics"),
CODEC_PNG,
CODEC_ID_PNG,
300000,
24,
"0.1-100",
NULL
};
const xvCodec jpeg = {
"JPEG",
N_("Joint Picture Expert Group"),
CODEC_JPEG,
CODEC_ID_JPEGLS,
300000,
24,
"0.1-100",
NULL
};
const xvCodec mpeg1 = {
"MPEG1",
N_("MPEG 1"),
CODEC_MPEG1,
CODEC_ID_MPEG1VIDEO,
300000,
24,
NULL,
"24|25|30|50|60"
// FIXME: adapt to ffmpeg's new fractional fps handling
// "23.976|24|25|29.97|30|50|59.94|60"
};
const xvCodec mjpeg = {
"MJPEG",
N_("MJPEG"),
CODEC_MJPEG,
CODEC_ID_MJPEG,
300000,
24,
"7.5-30", // this is actually MPEG4 ... no idea if
// this is the same here
NULL
};
const xvCodec mpeg4 = {
"MPEG4",
N_("MPEG 4 (DIVX)"),
CODEC_MPEG4,
CODEC_ID_MPEG4,
300000,
24,
"7.5-30",
NULL
};
const xvCodec ms_div2 = {
"MS_DIV2",
N_("Microsoft DIVX 2"),
CODEC_MSDIV2,
CODEC_ID_MSMPEG4V2,
300000,
24,
"7.5-30", // this is actually MPEG4 ... no idea if
// this is the same here
NULL
};
const xvCodec ms_div3 = {
"MS_DIV3",
N_("Microsoft DIVX 3"),
CODEC_MSDIV3,
CODEC_ID_MSMPEG4V3,
300000,
24,
"7.5-30", // this is actually MPEG4 ... no idea if
// this is the same here
NULL
};
const xvCodec flv1 = {
"FLASH_VIDEO",
N_("Flash Video"),
CODEC_FLV,
CODEC_ID_FLV1,
300000,
24,
"7.5-30", // this is actually MPEG4 ... no idea if
// this is the same here
NULL
};
const xvCodec dv = {
"DV",
N_("DV Video"),
CODEC_DV,
CODEC_ID_DVVIDEO,
300000,
25,
NULL,
"25"
// FIXME: adapt to ffmpeg's new fractional fps handling
// "25|29.97"
};
const xvCodec mpeg2 = {
"MPEG2",
N_("MPEG2 Video"),
CODEC_MPEG2,
CODEC_ID_MPEG2VIDEO,
300000,
24,
NULL,
"24|25|30|50|60"
// FIXME: adapt to ffmpeg's new fractional fps handling
// "23.976|24|25|29.97|30|50|59.94|60"
};
const xvCodec svq1 = {
"SVQ1",
N_("Soerensen VQ 1"),
CODEC_SVQ1,
CODEC_ID_SVQ1,
300000,
24,
"7.5-30", // this is actually MPEG4 ... no idea if
// this is the same here
NULL
};
#endif // USE_FFMPEG
// audio codecs
const xvAuCodec none_aucodec = {
"NONE",
N_("NONE"),
AU_CODEC_NONE,
CODEC_ID_NONE
};
#ifdef USE_FFMPEG
#ifdef HAVE_FFMPEG_AUDIO
const xvAuCodec mp2 = {
"MP2",
N_("MPEG2"),
AU_CODEC_MP2,
CODEC_ID_MP2
};
#ifdef HAVE_LIBMP3LAME
const xvAuCodec mp3 = {
"MP3",
N_("MPEG2 Layer 3"),
AU_CODEC_MP3,
CODEC_ID_MP3
};
#endif // HAVE_LIBMP3LAME
const xvAuCodec pcm16 = {
"PCM16",
N_("PCM"),
AU_CODEC_PCM16,
CODEC_ID_PCM_S16LE
};
#endif // HAVE_FFMPEG_AUDIO
#endif // USE_FFMPEG
// file formats
const xvFFormat none_format = {
"NONE",
N_("NONE"),
"NONE",
NULL,
CODEC_NONE,
NULL,
AU_CODEC_NONE,
NULL
};
const xvFFormat xwd = {
"xwd",
N_("X11 Window Dump"),
NULL,
"xwd",
CODEC_NONE,
NULL,
AU_CODEC_NONE,
NULL
};
#ifdef USE_FFMPEG
const xvFFormat pgm_format = {
"pgm",
N_("Portable Graymap File"),
NULL,
"pgm",
CODEC_PGM,
"PGM",
AU_CODEC_NONE,
NULL
};
const xvFFormat ppm_format = {
"ppm",
N_("Portable Anymap File"),
NULL,
"ppm",
CODEC_PPM,
"PPM",
AU_CODEC_NONE,
NULL
};
const xvFFormat png_format = {
"png",
N_("Portable Network Graphics File"),
NULL,
"png",
CODEC_PNG,
"PNG",
AU_CODEC_NONE,
NULL
};
const xvFFormat jpeg_format = {
"jpg",
N_("Joint Picture Expert Group"),
NULL,
"jpg|jpeg",
CODEC_JPEG,
"JPEG",
AU_CODEC_NONE,
NULL
};
const xvFFormat avi = {
"avi",
N_("Microsoft Audio Video Interleaved File"),
"avi",
"avi",
CODEC_MSDIV2,
"MPEG1|MJPEG|MPEG4|MS_DIV2|MPEG2|DV",
#ifdef HAVE_FFMPEG_AUDIO
AU_CODEC_MP2,
#ifdef HAVE_LIBMP3LAME
"MP2|MP3|PCM16"
#else
"MP2|PCM16"
#endif // HAVE_LIBMP3LAME
#else
AU_CODEC_NONE,
NULL
#endif // HAVE_FFMPEG_AUDIO
};
const xvFFormat divx = {
"divx",
N_("General AVI file (DIVX default)"),
"avi",
"mpeg|mpg",
CODEC_MPEG4,
"MPEG1|MJPEG|MPEG4|MS_DIV2|MPEG2|DV",
#ifdef HAVE_FFMPEG_AUDIO
AU_CODEC_MP2,
#ifdef HAVE_LIBMP3LAME
"MP2|MP3|PCM16"
#else
"MP2|PCM16"
#endif // HAVE_LIBMP3LAME
#else
AU_CODEC_NONE,
NULL
#endif // HAVE_FFMPEG_AUDIO
};
const xvFFormat asf = {
"asf",
N_("Microsoft Advanced Streaming Format"),
"asf",
"asf",
CODEC_MSDIV3,
"MS_DIV3",
#ifdef HAVE_FFMPEG_AUDIO
AU_CODEC_NONE,
#ifdef HAVE_LIBMP3LAME
"MP2|MP3"
#else
"MP2"
#endif // HAVE_LIBMP3LAME
#else
AU_CODEC_NONE,
NULL
#endif // HAVE_FFMPEG_AUDIO
};
const xvFFormat ff_flv1 = {
"flv1",
N_("Macromedia Flash Video Stream"),
"flv",
"flv|flv1",
CODEC_FLV,
"FLASH_VIDEO",
#ifdef HAVE_FFMPEG_AUDIO
#ifdef HAVE_LIBMP3LAME
AU_CODEC_MP3,
"MP3"
#else
AU_CODEC_NONE,
NULL
#endif // HAVE_LIBMP3LAME
#else
AU_CODEC_NONE,
NULL
#endif // HAVE_FFMPEG_AUDIO
};
const xvFFormat swf = {
"swf",
N_("Macromedia Shockwave Flash File"),
"swf",
"swf",
CODEC_FLV,
"FLASH_VIDEO|MJPEG",
/*
#ifdef HAVE_FFMPEG_AUDIO
#ifdef HAVE_LIBMP3LAME
AU_CODEC_MP3,
"MP2|MP3"
#else
AU_CODEC_MP2,
"MP2"
#endif // HAVE_LIBMP3LAME
#else
*/
AU_CODEC_NONE,
NULL
// #endif // HAVE_FFMPEG_AUDIO
};
const xvFFormat dv_format = {
"dv",
N_("DV Video Format"),
"dv",
"dv",
CODEC_DV,
"DV",
#ifdef HAVE_FFMPEG_AUDIO
AU_CODEC_MP2,
"PCM16"
#else
AU_CODEC_NONE,
NULL
#endif // HAVE_FFMPEG_AUDIO
};
const xvFFormat mpeg = {
"mpeg",
N_("MPEG1 System Format"),
"mpeg",
"m1v|vcd",
CODEC_MPEG1,
"MPEG1",
#ifdef HAVE_FFMPEG_AUDIO
AU_CODEC_MP2,
"MP2"
#else
AU_CODEC_NONE,
NULL
#endif // HAVE_FFMPEG_AUDIO
};
const xvFFormat svcd = {
"mpeg2",
N_("MPEG2 PS Format"),
"svcd",
"m2v|svcd",
CODEC_MPEG2,
"MPEG2",
#ifdef HAVE_FFMPEG_AUDIO
AU_CODEC_MP2,
"MP2"
#else
AU_CODEC_NONE,
NULL
#endif // HAVE_FFMPEG_AUDIO
};
const xvFFormat mov = {
"mov",
N_("Quicktime Format"),
"mov",
"mov|qt",
CODEC_MPEG4,
"MPEG4|SVQ1|DV",
#ifdef HAVE_FFMPEG_AUDIO
#ifdef HAVE_LIBMP3LAME
AU_CODEC_MP3,
"MP2|MP3|PCM16"
#else
AU_CODEC_PCM16,
"MP2|PCM16"
#endif // HAVE_LIBMP3LAME
#else
AU_CODEC_NONE,
NULL
#endif // HAVE_FFMPEG_AUDIO
};
#endif // USE_FFMPEG
/*
* must be called by main() to initialize data structures
*/
void xvc_codecs_init()
{
int i = 0;
// these are absolutely required to be in the same order as the
// enumeration of CAP_* types in codecs.h
tCodecs[i++] = none;
#ifdef USE_FFMPEG
tCodecs[i++] = pgm;
tCodecs[i++] = ppm;
tCodecs[i++] = png;
tCodecs[i++] = jpeg;
tCodecs[i++] = mpeg1;
tCodecs[i++] = mjpeg;
tCodecs[i++] = mpeg4;
tCodecs[i++] = ms_div2;
tCodecs[i++] = ms_div3;
tCodecs[i++] = flv1;
tCodecs[i++] = dv;
tCodecs[i++] = mpeg2;
tCodecs[i++] = svq1;
#endif // USE_FFMPEG
// dto.
// the target item of the array will be found by CAP_XXX - CAP_FFM
i = 0;
tFFormats[i++] = none_format;
tFFormats[i++] = xwd;
#ifdef USE_FFMPEG
tFFormats[i++] = pgm_format;
tFFormats[i++] = ppm_format;
tFFormats[i++] = png_format;
tFFormats[i++] = jpeg_format;
tFFormats[i++] = avi;
tFFormats[i++] = divx;
tFFormats[i++] = asf;
tFFormats[i++] = ff_flv1;
tFFormats[i++] = swf;
tFFormats[i++] = dv_format;
tFFormats[i++] = mpeg;
tFFormats[i++] = svcd;
tFFormats[i++] = mov;
#endif // USE_FFMPEG
// audio codecs
i = 0;
tAuCodecs[i++] = none_aucodec;
#ifdef USE_FFMPEG
#ifdef HAVE_FFMPEG_AUDIO
tAuCodecs[i++] = mp2;
#ifdef HAVE_LIBMP3LAME
tAuCodecs[i++] = mp3;
#endif // HAVE_LIBMP3LAME
tAuCodecs[i++] = pcm16;
#endif // HAVE_FFMPEG_AUDIO
#endif // USE_FFMPEG
}
/*
* find ffmpeg codec id from xvidcap's
* 0 is a valid id ... therefore we return -1 on failure
*/
int xvc_trans_codec(int xv_codec)
{
int i, ret = -1;
for (i = 0; i < NUMCODECS; i++) {
if (tCodecs[i].id == xv_codec)
ret = tCodecs[i].ffmpeg_id;
}
return ret;
}
/*
* check if string is element in list (e.g. allowed_vid_codecs)
*/
int xvc_is_element(char *xvList, char *xvElement)
{
char llist[512];
char lelement[512];
char *found = NULL;
int ret, y;
sprintf(llist, "|%s|", xvList);
for (y = 0; y < strlen(llist); y++) {
llist[y] = toupper(llist[y]);
}
sprintf(lelement, "|%s|", xvElement);
for (y = 0; y < strlen(lelement); y++) {
lelement[y] = toupper(lelement[y]);
}
found = strstr(llist, lelement);
if (found != NULL)
ret = 1;
else
ret = 0;
return ret;
}
/*
* enumerate list (e.g. allowed_vid_codecs)
*/
char *xvc_next_element(char *list)
{
static char *p_list;
static char llist[512];
char *ret;
if (list != NULL) {
sprintf(llist, "|%s|", list);
ret = strtok_r(llist, "|", &p_list);
} else {
ret = strtok_r(NULL, "|", &p_list);
}
return ret;
}
/*
* find target based on filename
* returns CAP_* or 0 if none found
*/
int xvc_codec_get_target_from_filename(char *file)
{
char *ext = NULL, *element = NULL;
int ret = 0, n;
ext = rindex(file, '.');
if (ext == NULL) {
return ret;
}
ext++;
for (n = CAP_NONE; n < NUMCAPS; n++) {
if (tFFormats[n].extensions) {
element = xvc_next_element(tFFormats[n].extensions);
while (element != NULL) {
if (strcasecmp(ext, element) == 0) {
// then we have found the right extension in target n
ret = n;
return ret;
}
element = xvc_next_element(NULL);
}
}
}
return ret;
}
/*
* check if fps rate is valid for given codec
* returns 0 for false or 1 for true
*/
int xvc_codec_is_valid_fps(int fps, int codec)
{
#define DEBUGFUNCTION "xvc_codec_is_valid_fps()"
char *element = NULL;
if (tCodecs[codec].allowed_fps) {
element = xvc_next_element(tCodecs[codec].allowed_fps);
while (element) {
int f = xvc_get_int_from_float_string(element);
if (f < 0)
fprintf(stderr,
"%s %s: Non-fatal error in the definition of valid fps for codec %s\n",
DEBUGFILE, DEBUGFUNCTION, tCodecs[codec].name);
else if (f == fps)
return 1;
element = xvc_next_element(NULL);
}
}
if (tCodecs[codec].allowed_fps_ranges) {
element = xvc_next_element(tCodecs[codec].allowed_fps_ranges);
while (element) {
int start = 0, end = 0;
char *start_str = strdup(element);
char *ptr = index(start_str, '-');
*ptr = '\0';
ptr++;
start = xvc_get_int_from_float_string(start_str);
end = xvc_get_int_from_float_string(ptr);
if (start < 0 || end < 0) {
fprintf(stderr,
"%s %s: Non-fatal error in the definition of valid fps ranges for codec %s\n",
DEBUGFILE, DEBUGFUNCTION, tCodecs[codec].name);
} else if (start <= fps && fps <= end)
return 1;
element = xvc_next_element(NULL);
}
}
// FIXME: what kind of error do I want to report with the return code?
return 0;
#undef DEBUGFUNCTION
}
/*
* count elements in a list (e.g. allowed_vid_codecs)
*/
int xvc_num_elements(char *list)
{
static char *p_list;
static char llist[512];
char *elem;
int elem_count = 0;
if (list != NULL) {
sprintf(llist, "|%s|", list);
elem = strtok_r(llist, "|", &p_list);
do {
elem_count++;
elem = strtok_r(NULL, "|", &p_list);
}
while (elem != NULL);
}
return elem_count;
}
syntax highlighted by Code2HTML, v. 0.9.1