Newer
Older
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "framehook.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
Roumen Petrov
committed
#include <signal.h>
#ifdef CONFIG_OS2
#include <sys/types.h>
#include <sys/select.h>
#include <stdlib.h>
#endif
#include <time.h>
#include <ctype.h>
#if !defined(INFINITY) && defined(HUGE_VAL)
#define INFINITY HUGE_VAL
#endif
#define MAXINT64 int64_t_C(0x7fffffffffffffff)
typedef struct {
const char *name;
int flags;
#define HAS_ARG 0x0001
#define OPT_BOOL 0x0002
#define OPT_EXPERT 0x0004
#define OPT_STRING 0x0008
union {
int *int_arg;
char **str_arg;
} u;
const char *help;
const char *argname;
} OptionDef;
/* select an input stream for an output stream */
typedef struct AVStreamMap {
int file_index;
int stream_index;
} AVStreamMap;
extern const OptionDef options[];
void show_help(void);
#define MAX_FILES 20
static AVFormatContext *input_files[MAX_FILES];
static int nb_input_files = 0;
static AVFormatContext *output_files[MAX_FILES];
static int nb_output_files = 0;
static AVStreamMap stream_maps[MAX_FILES];
static int nb_stream_maps;
static AVInputFormat *file_iformat;
static AVOutputFormat *file_oformat;
Fabrice Bellard
committed
static AVImageFormat *image_format;
static float frame_aspect_ratio = 0;
static enum PixelFormat frame_pix_fmt = PIX_FMT_YUV420P;
Michael Niedermayer
committed
static int frame_topBand = 0;
static int frame_bottomBand = 0;
static int frame_leftBand = 0;
static int frame_rightBand = 0;
Michael Niedermayer
committed
static int frame_rate = 25;
static int frame_rate_base = 1;
static int video_bit_rate = 200*1000;
static int video_bit_rate_tolerance = 4000*1000;
static int video_qmin = 2;
static int video_qmax = 31;
static int video_mb_qmin = 2;
static int video_mb_qmax = 31;
static int video_qdiff = 3;
static float video_qblur = 0.5;
static float video_qcomp = 0.5;
#if 0 //experimental, (can be removed)
static float video_rc_qsquish=1.0;
static float video_rc_qmod_amp=0;
static int video_rc_qmod_freq=0;
static char *video_rc_override_string=NULL;
static char *video_rc_eq="tex^qComp";
static int video_rc_buffer_size=0;
static float video_rc_buffer_aggressivity=1.0;
static int video_rc_max_rate=0;
static int video_rc_min_rate=0;
static float video_rc_initial_cplx=0;
static float video_b_qfactor = 1.25;
static float video_b_qoffset = 1.25;
Michael Niedermayer
committed
static float video_i_qfactor = -0.8;
Michael Niedermayer
committed
static int me_method = ME_EPZS;
static int video_disable = 0;
static int video_codec_id = CODEC_ID_NONE;
static int same_quality = 0;
static int use_hq = 0;
Michael Niedermayer
committed
/* Fx */
static int use_aic = 0;
static int use_umv = 0;
/* /Fx */
static int use_h263p_extra = 0;
static int do_deinterlace = 0;
static int workaround_bugs = FF_BUG_AUTODETECT;
static int error_resilience = 2;
static int error_concealment = 3;
static int dct_algo = 0;
static int idct_algo = 0;
static int use_part = 0;
static int packet_size = 0;
static int gop_size = 12;
static int intra_only = 0;
static int audio_sample_rate = 44100;
static int audio_bit_rate = 64000;
static int audio_disable = 0;
static int audio_channels = 1;
static int audio_codec_id = CODEC_ID_NONE;
static int file_overwrite = 0;
static char *str_title = NULL;
static char *str_author = NULL;
static char *str_copyright = NULL;
static char *str_comment = NULL;
static int do_hex_dump = 0;
static int do_play = 0;
static int do_psnr = 0;
static int do_vstats = 0;
static int do_pass = 0;
static int bitexact = 0;
static char *pass_logfilename = NULL;
static int audio_stream_copy = 0;
static int video_stream_copy = 0;
Max Krasnyansky
committed
static int rate_emu = 0;
static char *video_grab_format = "video4linux";
Fabrice Bellard
committed
static char *video_device = NULL;
Fabrice Bellard
committed
static int video_channel = 0;
Fabrice Bellard
committed
static char *audio_grab_format = "audio_device";
Fabrice Bellard
committed
static char *audio_device = NULL;
#define DEFAULT_PASS_LOGFILENAME "ffmpeg2pass"
typedef struct AVOutputStream {
int file_index; /* file index */
int index; /* stream index in the output file */
int source_index; /* AVInputStream index */
AVStream *st; /* stream in the output file */
Fabrice Bellard
committed
int encoding_needed; /* true if encoding needed for this stream */
int frame_number;
/* input pts and corresponding output pts
for A/V sync */
double sync_ipts;
double sync_ipts_offset;
int video_resample; /* video_resample and video_crop are mutually exclusive */
AVPicture pict_tmp; /* temporary image for resampling */
ImgReSampleContext *img_resample_ctx; /* for image resampling */
int video_crop; /* video_resample and video_crop are mutually exclusive */
int topBand; /* cropping area sizes */
int leftBand;
/* audio only */
int audio_resample;
ReSampleContext *resample; /* for audio resampling */
FifoBuffer fifo; /* for compression: one audio fifo per codec */
} AVOutputStream;
typedef struct AVInputStream {
int file_index;
int index;
AVStream *st;
int discard; /* true if stream data should be discarded */
int decoding_needed; /* true if the packets must be decoded in 'raw_fifo' */
int64_t sample_index; /* current sample */
Fabrice Bellard
committed
int frame_decoded; /* true if a video or audio frame has been decoded */
Max Krasnyansky
committed
int64_t start; /* time when read started */
unsigned long frame; /* current frame */
} AVInputStream;
typedef struct AVInputFile {
int eof_reached; /* true if eof reached */
int ist_index; /* index of first stream in ist_table */
int buffer_size; /* current total buffer size */
int buffer_size_max; /* buffer size at which we consider we can stop
buffering */
int nb_streams; /* nb streams we are aware of */
/* init terminal so that we can grab keys */
static struct termios oldtty;
static void term_exit(void)
{
tcsetattr (0, TCSANOW, &oldtty);
}
Roumen Petrov
committed
static volatile sig_atomic_t received_sigterm = 0;
static void
sigterm_handler(int sig)
{
received_sigterm = sig;
term_exit();
}
static void term_init(void)
{
struct termios tty;
tcgetattr (0, &tty);
oldtty = tty;
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
|INLCR|IGNCR|ICRNL|IXON);
tty.c_oflag |= OPOST;
tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
tty.c_cflag &= ~(CSIZE|PARENB);
tty.c_cflag |= CS8;
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 0;
tcsetattr (0, TCSANOW, &tty);
Roumen Petrov
committed
signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */
signal(SIGQUIT, sigterm_handler); /* Quit (POSIX). */
signal(SIGTERM, sigterm_handler); /* Termination (ANSI). */
/*
register a function to be called at normal program termination
*/
#ifdef CONFIG_BEOS_NETSERVER
fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);
#endif
}
/* read a key without blocking */
static int read_key(void)
{
int n = 1;
#ifndef CONFIG_BEOS_NETSERVER
struct timeval tv;
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(0, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
n = select(1, &rfds, NULL, NULL, &tv);
#endif
n = read(0, &ch, 1);
if (n == 1)
return n;
#else
/* no interactive support */
static void term_exit(void)
}
static void term_init(void)
{
}
static int read_key(void)
{
return 0;
#endif
static int read_ffserver_streams(AVFormatContext *s, const char *filename)
int i, err;
err = av_open_input_file(&ic, filename, NULL, FFM_PACKET_SIZE, NULL);
if (err < 0)
return err;
/* copy stream format */
s->nb_streams = ic->nb_streams;
for(i=0;i<ic->nb_streams;i++) {
AVStream *st;
st = av_mallocz(sizeof(AVFormatContext));
memcpy(st, ic->streams[i], sizeof(AVStream));
s->streams[i] = st;
}
av_close_input_file(ic);
return 0;
}
Fabrice Bellard
committed
#define MAX_AUDIO_PACKET_SIZE (128 * 1024)
static void do_audio_out(AVFormatContext *s,
AVOutputStream *ost,
AVInputStream *ist,
unsigned char *buf, int size)
{
Sylvain Corré
committed
static uint8_t *audio_buf = NULL;
static uint8_t *audio_out = NULL;
Sylvain Corré
committed
Sylvain Corré
committed
/* SC: dynamic allocation of buffers */
if (!audio_buf)
audio_buf = av_malloc(2*MAX_AUDIO_PACKET_SIZE);
if (!audio_out)
Sylvain Corré
committed
if (!audio_buf || !audio_out)
return; /* Should signal an error ! */
enc = &ost->st->codec;
if (ost->audio_resample) {
buftmp = audio_buf;
size_out = audio_resample(ost->resample,
(short *)buftmp, (short *)buf,
size / (ist->st->codec.channels * 2));
size_out = size_out * enc->channels * 2;
} else {
buftmp = buf;
size_out = size;
}
/* now encode as many frames as possible */
if (enc->frame_size > 1) {
/* output resampled raw samples */
fifo_write(&ost->fifo, buftmp, size_out,
&ost->fifo.wptr);
frame_bytes = enc->frame_size * 2 * enc->channels;
while (fifo_read(&ost->fifo, audio_buf, frame_bytes,
&ost->fifo.rptr) == 0) {
(short *)audio_buf);
Fabrice Bellard
committed
av_write_frame(s, ost->index, audio_out, ret);
/* output a pcm frame */
/* XXX: change encoding codec API to avoid this ? */
switch(enc->codec->id) {
case CODEC_ID_PCM_S16LE:
case CODEC_ID_PCM_S16BE:
case CODEC_ID_PCM_U16LE:
case CODEC_ID_PCM_U16BE:
break;
default:
size_out = size_out >> 1;
break;
}
ret = avcodec_encode_audio(enc, audio_out, size_out,
(short *)buftmp);
Fabrice Bellard
committed
av_write_frame(s, ost->index, audio_out, ret);
static void pre_process_video_frame(AVInputStream *ist, AVPicture *picture, void **bufp)
{
AVCodecContext *dec;
AVPicture *picture2;
AVPicture picture_tmp;
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
dec = &ist->st->codec;
/* deinterlace : must be done before any resize */
if (do_deinterlace) {
int size;
/* create temporary picture */
size = avpicture_get_size(dec->pix_fmt, dec->width, dec->height);
buf = av_malloc(size);
if (!buf)
return;
picture2 = &picture_tmp;
avpicture_fill(picture2, buf, dec->pix_fmt, dec->width, dec->height);
if (avpicture_deinterlace(picture2, picture,
dec->pix_fmt, dec->width, dec->height) < 0) {
/* if error, do not deinterlace */
av_free(buf);
buf = NULL;
picture2 = picture;
}
} else {
picture2 = picture;
}
frame_hook_process(picture2, dec->pix_fmt, dec->width, dec->height);
if (picture != picture2)
*picture = *picture2;
*bufp = buf;
}
Fabrice Bellard
committed
/* we begin to correct av delay at this threshold */
#define AV_DELAY_MAX 0.100
static void do_video_out(AVFormatContext *s,
AVOutputStream *ost,
AVInputStream *ist,
AVPicture *in_picture,
Fabrice Bellard
committed
int *frame_size, AVOutputStream *audio_sync)
Fabrice Bellard
committed
int nb_frames, i, ret;
AVPicture *final_picture, *formatted_picture;
AVPicture picture_format_temp, picture_crop_temp;
static uint8_t *video_buffer;
uint8_t *buf = NULL, *buf1 = NULL;
AVCodecContext *enc, *dec;
dec = &ist->st->codec;
Fabrice Bellard
committed
/* by default, we output a single frame */
nb_frames = 1;
Philip Gladstone
committed
*frame_size = 0;
Fabrice Bellard
committed
/* NOTE: the A/V sync is always done by considering the audio is
the master clock. It is suffisant for transcoding or playing,
but not for the general case */
if (audio_sync) {
/* compute the A-V delay and duplicate/remove frames if needed */
double adelta, vdelta, apts, vpts, av_delay;
if (audio_sync->sync_ipts != AV_NOPTS_VALUE &&
ost->sync_ipts != AV_NOPTS_VALUE) {
adelta = (double)(ost->st->pts.val - audio_sync->sync_opts) *
s->pts_num / s->pts_den;
apts = audio_sync->sync_ipts + adelta;
vdelta = (double)(ost->st->pts.val - ost->sync_opts) *
s->pts_num / s->pts_den;
vpts = ost->sync_ipts + vdelta;
av_delay = apts - vpts;
// printf("delay=%f\n", av_delay);
if (av_delay < -AV_DELAY_MAX)
nb_frames = 2;
else if (av_delay > AV_DELAY_MAX)
nb_frames = 0;
}
} else {
double vdelta;
if (ost->sync_ipts != AV_NOPTS_VALUE) {
vdelta = (double)(ost->st->pts.val) * s->pts_num / s->pts_den - (ost->sync_ipts - ost->sync_ipts_offset);
Philip Gladstone
committed
if (vdelta < 100 && vdelta > -100 && ost->sync_ipts_offset) {
if (vdelta < -AV_DELAY_MAX)
nb_frames = 2;
else if (vdelta > AV_DELAY_MAX)
nb_frames = 0;
} else {
ost->sync_ipts_offset -= vdelta;
Philip Gladstone
committed
if (!ost->sync_ipts_offset)
ost->sync_ipts_offset = 0.000001; /* one microsecond */
}
Philip Gladstone
committed
#if defined(PJSG)
{
static char *action[] = { "drop frame", "copy frame", "dup frame" };
printf("Input PTS %12.6f, output PTS %12.6f: %s\n",
(double) ost->sync_ipts, (double) ost->st->pts.val * s->pts_num / s->pts_den,
action[nb_frames]);
}
#endif
}
Fabrice Bellard
committed
}
if (nb_frames <= 0)
if (!video_buffer)
Fabrice Bellard
committed
video_buffer = av_malloc(VIDEO_BUFFER_SIZE);
if (!video_buffer)
return;
/* convert pixel format if needed */
if (enc->pix_fmt != dec->pix_fmt) {
int size;
/* create temporary picture */
size = avpicture_get_size(enc->pix_fmt, dec->width, dec->height);
if (!buf)
return;
formatted_picture = &picture_format_temp;
avpicture_fill(formatted_picture, buf, enc->pix_fmt, dec->width, dec->height);
if (img_convert(formatted_picture, enc->pix_fmt,
in_picture, dec->pix_fmt,
dec->width, dec->height) < 0) {
fprintf(stderr, "pixel format conversion not handled\n");
goto the_end;
}
} else {
formatted_picture = in_picture;
}
/* XXX: resampling could be done before raw format convertion in
some cases to go faster */
/* XXX: only works for YUV420P */
final_picture = &ost->pict_tmp;
img_resample(ost->img_resample_ctx, final_picture, formatted_picture);
} else if (ost->video_crop) {
picture_crop_temp.data[0] = formatted_picture->data[0] +
(ost->topBand * formatted_picture->linesize[0]) + ost->leftBand;
picture_crop_temp.data[1] = formatted_picture->data[1] +
((ost->topBand >> 1) * formatted_picture->linesize[1]) +
(ost->leftBand >> 1);
picture_crop_temp.data[2] = formatted_picture->data[2] +
((ost->topBand >> 1) * formatted_picture->linesize[2]) +
(ost->leftBand >> 1);
picture_crop_temp.linesize[0] = formatted_picture->linesize[0];
picture_crop_temp.linesize[1] = formatted_picture->linesize[1];
picture_crop_temp.linesize[2] = formatted_picture->linesize[2];
final_picture = &picture_crop_temp;
final_picture = formatted_picture;
}
/* duplicates frame if needed */
/* XXX: pb because no interleaving */
Fabrice Bellard
committed
for(i=0;i<nb_frames;i++) {
if (s->oformat->flags & AVFMT_RAWPICTURE) {
/* raw pictures are written as AVPicture structure to
avoid any copies. We support temorarily the older
method. */
av_write_frame(s, ost->index,
(uint8_t *)final_picture, sizeof(AVPicture));
} else {
*(AVPicture*)&big_picture= *final_picture;
/* handles sameq here. This is not correct because it may
not be a global option */
if (same_quality) {
big_picture.quality = ist->st->quality;
}else
big_picture.quality = ost->st->quality;
ret = avcodec_encode_video(enc,
//enc->frame_number = enc->real_pict_num;
Fabrice Bellard
committed
av_write_frame(s, ost->index, video_buffer, ret);
*frame_size = ret;
//fprintf(stderr,"\nFrame: %3d %3d size: %5d type: %d",
// enc->frame_number-1, enc->real_pict_num, ret,
/* if two pass, output log */
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
}
Fabrice Bellard
committed
ost->frame_number++;
Fabrice Bellard
committed
the_end:
static double psnr(double d){
if(d==0) return INFINITY;
Fabrice Bellard
committed
static void do_video_stats(AVFormatContext *os, AVOutputStream *ost,
int frame_size)
{
static FILE *fvstats=NULL;
char filename[40];
time_t today2;
struct tm *today;
AVCodecContext *enc;
int frame_number;
double ti1, bitrate, avg_bitrate;
if (!fvstats) {
today2 = time(NULL);
today = localtime(&today2);
sprintf(filename, "vstats_%02d%02d%02d.log", today->tm_hour,
today->tm_min,
today->tm_sec);
fvstats = fopen(filename,"w");
if (!fvstats) {
perror("fopen");
exit(1);
}
}
ti = MAXINT64;
enc = &ost->st->codec;
total_size += frame_size;
if (enc->codec_type == CODEC_TYPE_VIDEO) {
Fabrice Bellard
committed
frame_number = ost->frame_number;
fprintf(fvstats, "frame= %5d q= %2.1f ", frame_number, enc->coded_frame->quality);
if (enc->flags&CODEC_FLAG_PSNR)
fprintf(fvstats, "PSNR= %6.2f ", psnr(enc->coded_frame->error[0]/(enc->width*enc->height*255.0*255.0)));
fprintf(fvstats,"f_size= %6d ", frame_size);
Fabrice Bellard
committed
/* compute pts value */
ti1 = (double)ost->st->pts.val * os->pts_num / os->pts_den;
if (ti1 < 0.01)
ti1 = 0.01;
Michael Niedermayer
committed
bitrate = (double)(frame_size * 8) * enc->frame_rate / enc->frame_rate_base / 1000.0;
avg_bitrate = (double)(total_size * 8) / ti1 / 1000.0;
fprintf(fvstats, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ",
(double)total_size / 1024, ti1, bitrate, avg_bitrate);
fprintf(fvstats,"type= %s\n", av_get_pict_type_char(enc->coded_frame->pict_type));
Fabrice Bellard
committed
}
static void print_report(AVFormatContext **output_files,
AVOutputStream **ost_table, int nb_ostreams,
int is_last_report)
Fabrice Bellard
committed
{
char buf[1024];
AVOutputStream *ost;
AVFormatContext *oc, *os;
Fabrice Bellard
committed
AVCodecContext *enc;
int frame_number, vid, i;
double bitrate, ti1, pts;
Fabrice Bellard
committed
if (!is_last_report) {
Fabrice Bellard
committed
/* display the report every 0.5 seconds */
cur_time = av_gettime();
if (last_time == -1) {
last_time = cur_time;
return;
}
if ((cur_time - last_time) < 500000)
return;
last_time = cur_time;
}
Fabrice Bellard
committed
oc = output_files[0];
total_size = url_ftell(&oc->pb);
buf[0] = '\0';
ti1 = 1e10;
vid = 0;
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
os = output_files[ost->file_index];
enc = &ost->st->codec;
if (vid && enc->codec_type == CODEC_TYPE_VIDEO) {
}
Fabrice Bellard
committed
if (!vid && enc->codec_type == CODEC_TYPE_VIDEO) {
frame_number = ost->frame_number;
frame_number, enc->coded_frame ? enc->coded_frame->quality : 0);
if (enc->flags&CODEC_FLAG_PSNR)
sprintf(buf + strlen(buf), "PSNR= %6.2f ", psnr(enc->coded_frame->error[0]/(enc->width*enc->height*255.0*255.0)));
Fabrice Bellard
committed
vid = 1;
}
/* compute min output value */
pts = (double)ost->st->pts.val * os->pts_num / os->pts_den;
Kareila
committed
if ((pts < ti1) && (pts > 0))
Fabrice Bellard
committed
ti1 = pts;
}
if (ti1 < 0.01)
ti1 = 0.01;
bitrate = (double)(total_size * 8) / ti1 / 1000.0;
sprintf(buf + strlen(buf),
"size=%8.0fkB time=%0.1f bitrate=%6.1fkbits/s",
(double)total_size / 1024, ti1, bitrate);
Fabrice Bellard
committed
fprintf(stderr, "%s ", buf);
Fabrice Bellard
committed
if (is_last_report) {
fprintf(stderr, "\n");
} else {
fprintf(stderr, "\r");
fflush(stderr);
}
/*
* The following code is the main loop of the file converter
*/
static int av_encode(AVFormatContext **output_files,
int nb_output_files,
AVFormatContext **input_files,
int nb_input_files,
AVStreamMap *stream_maps, int nb_stream_maps)
{
Fabrice Bellard
committed
int ret, i, j, k, n, nb_istreams = 0, nb_ostreams = 0, pts_set;
AVFormatContext *is, *os;
AVCodecContext *codec, *icodec;
AVOutputStream *ost, **ost_table = NULL;
AVInputStream *ist, **ist_table = NULL;
AVFormatContext *stream_no_data;
int key;
file_table= (AVInputFile*) av_mallocz(nb_input_files * sizeof(AVInputFile));
/* input stream init */
j = 0;
for(i=0;i<nb_input_files;i++) {
is = input_files[i];
file_table[i].ist_index = j;
file_table[i].nb_streams = is->nb_streams;
j += is->nb_streams;
}
nb_istreams = j;
ist_table = av_mallocz(nb_istreams * sizeof(AVInputStream *));
if (!ist_table)
for(i=0;i<nb_istreams;i++) {
ist = av_mallocz(sizeof(AVInputStream));
if (!ist)
goto fail;
ist_table[i] = ist;
}
j = 0;
for(i=0;i<nb_input_files;i++) {
is = input_files[i];
for(k=0;k<is->nb_streams;k++) {
ist = ist_table[j++];
ist->st = is->streams[k];
ist->file_index = i;
ist->index = k;
ist->discard = 1; /* the stream is discarded by default
(changed later) */
Max Krasnyansky
committed
if (ist->st->codec.rate_emu) {
ist->start = av_gettime();
ist->frame = 0;
}
}
}
/* output stream init */
nb_ostreams = 0;
for(i=0;i<nb_output_files;i++) {
os = output_files[i];
nb_ostreams += os->nb_streams;
}
if (nb_stream_maps > 0 && nb_stream_maps != nb_ostreams) {
fprintf(stderr, "Number of stream maps must match number of output streams\n");
exit(1);
}
Brian Foley
committed
/* Sanity check the mapping args -- do the input files & streams exist? */
for(i=0;i<nb_stream_maps;i++) {
int fi = stream_maps[i].file_index;
int si = stream_maps[i].stream_index;
if (fi < 0 || fi > nb_input_files - 1 ||
si < 0 || si > file_table[fi].nb_streams - 1) {
fprintf(stderr,"Could not find input stream #%d.%d\n", fi, si);
exit(1);
}
}
ost_table = av_mallocz(sizeof(AVOutputStream *) * nb_ostreams);
if (!ost_table)
goto fail;
for(i=0;i<nb_ostreams;i++) {
ost = av_mallocz(sizeof(AVOutputStream));
if (!ost)
goto fail;
ost_table[i] = ost;
}
n = 0;
for(k=0;k<nb_output_files;k++) {
os = output_files[k];
for(i=0;i<os->nb_streams;i++) {
int found;
ost = ost_table[n++];
ost->file_index = k;
ost->index = i;
ost->st = os->streams[i];
if (nb_stream_maps > 0) {
ost->source_index = file_table[stream_maps[n-1].file_index].ist_index +
stream_maps[n-1].stream_index;
Brian Foley
committed
/* Sanity check that the stream types match */
if (ist_table[ost->source_index]->st->codec.codec_type != ost->st->codec.codec_type) {
fprintf(stderr, "Codec type mismatch for mapping #%d.%d -> #%d.%d\n",
stream_maps[n-1].file_index, stream_maps[n-1].stream_index,
ost->file_index, ost->index);
exit(1);
}
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
} else {
/* get corresponding input stream index : we select the first one with the right type */
found = 0;
for(j=0;j<nb_istreams;j++) {
ist = ist_table[j];
if (ist->discard &&
ist->st->codec.codec_type == ost->st->codec.codec_type) {
ost->source_index = j;
found = 1;
}
}
if (!found) {
/* try again and reuse existing stream */
for(j=0;j<nb_istreams;j++) {
ist = ist_table[j];
if (ist->st->codec.codec_type == ost->st->codec.codec_type) {
ost->source_index = j;
found = 1;
}
}
if (!found) {
fprintf(stderr, "Could not find input stream matching output stream #%d.%d\n",
ost->file_index, ost->index);
exit(1);
}
}
}
ist = ist_table[ost->source_index];
ist->discard = 0;
}
}
/* for each output stream, we compute the right encoding parameters */
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
ist = ist_table[ost->source_index];
codec = &ost->st->codec;
icodec = &ist->st->codec;
if (ost->st->stream_copy) {
/* if stream_copy is selected, no need to decode or encode */
codec->codec_id = icodec->codec_id;
codec->codec_type = icodec->codec_type;
codec->codec_tag = icodec->codec_tag;
codec->bit_rate = icodec->bit_rate;
switch(codec->codec_type) {
case CODEC_TYPE_AUDIO:
codec->sample_rate = icodec->sample_rate;
codec->channels = icodec->channels;
break;
case CODEC_TYPE_VIDEO:
codec->frame_rate = icodec->frame_rate;
Michael Niedermayer
committed
codec->frame_rate_base = icodec->frame_rate_base;
codec->width = icodec->width;
codec->height = icodec->height;
break;
default:
av_abort();
}
} else {
switch(codec->codec_type) {
case CODEC_TYPE_AUDIO:
if (fifo_init(&ost->fifo, 2 * MAX_AUDIO_PACKET_SIZE))
goto fail;
if (codec->channels == icodec->channels &&
codec->sample_rate == icodec->sample_rate) {
ost->audio_resample = 0;
} else {
if (codec->channels != icodec->channels &&
icodec->codec_id == CODEC_ID_AC3) {
/* Special case for 5:1 AC3 input */
/* and mono or stereo output */
/* Request specific number of channels */
icodec->channels = codec->channels;
if (codec->sample_rate == icodec->sample_rate)
ost->audio_resample = 0;
else {
ost->audio_resample = 1;
ost->resample = audio_resample_init(codec->channels, icodec->channels,
codec->sample_rate,
icodec->sample_rate);
}
/* Request specific number of channels */
icodec->channels = codec->channels;
} else {
ost->audio_resample = 1;
ost->resample = audio_resample_init(codec->channels, icodec->channels,
}
break;
case CODEC_TYPE_VIDEO:
codec->height == icodec->height &&
frame_topBand == 0 &&
frame_bottomBand == 0 &&
frame_leftBand == 0 &&
frame_rightBand == 0)
{
ost->video_resample = 0;
ost->video_crop = 0;
} else if ((codec->width == icodec->width -
(frame_leftBand + frame_rightBand)) &&
(codec->height == icodec->height -
(frame_topBand + frame_bottomBand)))
{
ost->video_crop = 1;
ost->topBand = frame_topBand;
ost->leftBand = frame_leftBand;
ost->video_crop = 0; // cropping is handled as part of resample
buf = av_malloc((codec->width * codec->height * 3) / 2);
if (!buf)
goto fail;
ost->pict_tmp.data[0] = buf;
ost->pict_tmp.data[1] = ost->pict_tmp.data[0] + (codec->width * codec->height);
ost->pict_tmp.data[2] = ost->pict_tmp.data[1] + (codec->width * codec->height) / 4;
ost->pict_tmp.linesize[0] = codec->width;