Newer
Older
* 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
/* select an input stream for an output stream */
typedef struct AVStreamMap {
int file_index;
int stream_index;
} AVStreamMap;
extern const OptionDef options[];
static void show_help(void);
static void show_license(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 mb_decision = FF_MB_DECISION_SIMPLE;
Michael Niedermayer
committed
/* Fx */
static int use_aic = 0;
static int use_umv = 0;
/* /Fx */
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_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;
static char *video_standard = "ntsc";
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 */
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 */
AVFrac next_pts; /* synthetic pts for cases where pkt.pts == 0 */
int64_t pts; /* current pts */
} 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(AVStream));
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;
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
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, av_delay;
adelta = audio_sync->sync_ipts - ((double)audio_sync->sync_opts *
s->pts_num / s->pts_den);
vdelta = ost->sync_ipts - ((double)ost->sync_opts *
s->pts_num / s->pts_den);
av_delay = adelta - vdelta;
// 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;
vdelta = (double)(ost->st->pts.val) * s->pts_num / s->pts_den - (ost->sync_ipts - ost->sync_ipts_offset);
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;
if (!ost->sync_ipts_offset)
ost->sync_ipts_offset = 0.000001; /* one microsecond */
}
Fabrice Bellard
committed
}
#if defined(AVSYNC_DEBUG)
static char *action[] = { "drop frame", "copy frame", "dup frame" };
if (audio_sync)
fprintf(stderr, "Input APTS %12.6f, output APTS %12.6f, ",
(double) audio_sync->sync_ipts,
(double) audio_sync->st->pts.val * s->pts_num / s->pts_den);
fprintf(stderr, "Input VPTS %12.6f, output VPTS %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= %c\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)
{
int ret, i, j, k, n, nb_istreams = 0, nb_ostreams = 0;
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);
}
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
} 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);
Michael Niedermayer
committed
if(!ost->resample)
{
printf("Can't resample. Aborting.\n");
av_abort();
}
/* Request specific number of channels */
icodec->channels = codec->channels;
} else {
ost->audio_resample = 1;
ost->resample = audio_resample_init(codec->channels, icodec->channels,
Michael Niedermayer
committed
if(!ost->resample)
{
printf("Can't resample. Aborting.\n");
av_abort();
}
}
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;
ost->pict_tmp.linesize[1] = codec->width / 2;
ost->pict_tmp.linesize[2] = codec->width / 2;
Michael Niedermayer
committed
ost->img_resample_ctx = img_resample_full_init(
Michael Niedermayer
committed
ist->st->codec.width, ist->st->codec.height,
frame_topBand, frame_bottomBand,
frame_leftBand, frame_rightBand);
}
ost->encoding_needed = 1;
ist->decoding_needed = 1;
break;
default:
av_abort();
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
/* two pass mode */
if (ost->encoding_needed &&
(codec->flags & (CODEC_FLAG_PASS1 | CODEC_FLAG_PASS2))) {
char logfilename[1024];
FILE *f;
int size;
char *logbuffer;
snprintf(logfilename, sizeof(logfilename), "%s-%d.log",
pass_logfilename ?
pass_logfilename : DEFAULT_PASS_LOGFILENAME, i);
if (codec->flags & CODEC_FLAG_PASS1) {
f = fopen(logfilename, "w");
if (!f) {
perror(logfilename);
exit(1);
}
ost->logfile = f;
} else {
/* read the log file */
f = fopen(logfilename, "r");
if (!f) {
perror(logfilename);
exit(1);
}
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
logbuffer = av_malloc(size + 1);
if (!logbuffer) {
fprintf(stderr, "Could not allocate log buffer\n");
exit(1);
}
fread(logbuffer, 1, size, f);
fclose(f);
logbuffer[size] = '\0';
codec->stats_in = logbuffer;
/* dump the file output parameters - cannot be done before in case
of stream copy */
for(i=0;i<nb_output_files;i++) {
dump_format(output_files[i], i, output_files[i]->filename, 1);
}
/* dump the stream mapping */
fprintf(stderr, "Stream mapping:\n");
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
fprintf(stderr, " Stream #%d.%d -> #%d.%d\n",
ist_table[ost->source_index]->file_index,
ist_table[ost->source_index]->index,
ost->file_index,
ost->index);
}
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
/* open each encoder */
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
if (ost->encoding_needed) {
AVCodec *codec;
codec = avcodec_find_encoder(ost->st->codec.codec_id);
if (!codec) {
fprintf(stderr, "Unsupported codec for output stream #%d.%d\n",
ost->file_index, ost->index);
exit(1);
}
if (avcodec_open(&ost->st->codec, codec) < 0) {
fprintf(stderr, "Error while opening codec for stream #%d.%d - maybe incorrect parameters such as bit_rate, rate, width or height\n",
ost->file_index, ost->index);
exit(1);
}
}
}
/* open each decoder */
for(i=0;i<nb_istreams;i++) {
ist = ist_table[i];
if (ist->decoding_needed) {
AVCodec *codec;
codec = avcodec_find_decoder(ist->st->codec.codec_id);
if (!codec) {
fprintf(stderr, "Unsupported codec (id=%d) for input stream #%d.%d\n",
ist->st->codec.codec_id, ist->file_index, ist->index);
exit(1);
}
if (avcodec_open(&ist->st->codec, codec) < 0) {
fprintf(stderr, "Error while opening codec for input stream #%d.%d\n",
ist->file_index, ist->index);
exit(1);
}
//if (ist->st->codec.codec_type == CODEC_TYPE_VIDEO)
// ist->st->codec.flags |= CODEC_FLAG_REPEAT_FIELD;
Fabrice Bellard
committed
ist->frame_decoded = 1;
}
}
/* init pts */
for(i=0;i<nb_istreams;i++) {
ist = ist_table[i];
switch (ist->st->codec.codec_type) {
case CODEC_TYPE_AUDIO:
0, 0, is->pts_num * ist->st->codec.sample_rate);
break;
case CODEC_TYPE_VIDEO:
0, 0, is->pts_num * ist->st->codec.frame_rate);
break;
default:
break;
}
}
/* compute buffer size max (should use a complete heuristic) */
for(i=0;i<nb_input_files;i++) {
file_table[i].buffer_size_max = 2048;
}
/* open files and write file headers */
for(i=0;i<nb_output_files;i++) {
os = output_files[i];
if (av_write_header(os) < 0) {
fprintf(stderr, "Could not write header for output file #%d (incorrect codec paramters ?)\n", i);
ret = -EINVAL;
goto fail;
}
#ifndef CONFIG_WIN32
fprintf(stderr, "Press [q] to stop encoding\n");
#endif
term_init();
stream_no_data = 0;
key = -1;
int data_size, got_picture;
AVPicture picture;
short samples[AVCODEC_MAX_AUDIO_FRAME_SIZE / 2];
void *buffer_to_free;
Fabrice Bellard
committed
double pts_min;
/* if 'q' pressed, exits */
if (key) {
/* read_key() returns 0 on EOF */
key = read_key();
if (key == 'q')
break;
}
Fabrice Bellard
committed
/* select the stream that we must read now by looking at the
smallest output pts */
Fabrice Bellard
committed
pts_min = 1e10;
for(i=0;i<nb_ostreams;i++) {
double pts;
ost = ost_table[i];
os = output_files[ost->file_index];
ist = ist_table[ost->source_index];
pts = (double)ost->st->pts.val * os->pts_num / os->pts_den;
if (!file_table[ist->file_index].eof_reached &&
pts < pts_min) {
pts_min = pts;
file_index = ist->file_index;
}
}
/* if none, if is finished */
if (file_index < 0) {
Fabrice Bellard
committed
}
Fabrice Bellard
committed
if (recording_time > 0 && pts_min >= (recording_time / 1000000.0))
Fabrice Bellard
committed
/* read a packet from it and output it in the fifo */
is = input_files[file_index];
if (av_read_packet(is, &pkt) < 0) {
file_table[file_index].eof_reached = 1;
continue;
}
if (!pkt.size) {
stream_no_data = is;
} else {
stream_no_data = 0;
}
Fabrice Bellard
committed
if (do_hex_dump) {
printf("stream #%d, size=%d:\n", pkt.stream_index, pkt.size);
av_hex_dump(pkt.data, pkt.size);
}
/* the following test is needed in case new streams appear
dynamically in stream : we ignore them */
if (pkt.stream_index >= file_table[file_index].nb_streams)
ist_index = file_table[file_index].ist_index + pkt.stream_index;
ist = ist_table[ist_index];
if (ist->discard)
goto discard_packet;
// printf("read #%d.%d size=%d\n", ist->file_index, ist->index, pkt.size);
len = pkt.size;
ptr = pkt.data;
while (len > 0) {
/* decode the packet if needed */
data_buf = NULL; /* fail safe */
data_size = 0;
if (ist->decoding_needed) {
Fabrice Bellard
committed
/* NOTE1: we only take into account the PTS if a new
frame has begun (MPEG semantics) */
/* NOTE2: even if the fraction is not initialized,
av_frac_set can be used to set the integer part */
/* If pts is unavailable -- we have to use synthetic one */
if( pkt.pts != AV_NOPTS_VALUE )
{
ist->pts = ist->next_pts.val = pkt.pts;
}
else
{
ist->pts = ist->next_pts.val;
}
Fabrice Bellard
committed
ist->frame_decoded = 0;
}
switch(ist->st->codec.codec_type) {
case CODEC_TYPE_AUDIO:
/* XXX: could avoid copy if PCM 16 bits with same
endianness as CPU */
ret = avcodec_decode_audio(&ist->st->codec, samples, &data_size,
ptr, len);
if (ret < 0)
goto fail_decode;
/* Some bug in mpeg audio decoder gives */
/* data_size < 0, it seems they are overflows */
if (data_size <= 0) {
/* no audio frame */
ptr += ret;
len -= ret;
continue;
is->pts_den * data_size / (2 * ist->st->codec.channels));
data_size = (ist->st->codec.width * ist->st->codec.height * 3) / 2;
ret = avcodec_decode_video(&ist->st->codec,
&big_picture, &got_picture, ptr, len);
picture= *(AVPicture*)&big_picture;
ist->st->quality= big_picture.quality;
if (ret < 0) {
fail_decode:
fprintf(stderr, "Error while decoding stream #%d.%d\n",
ist->file_index, ist->index);
av_free_packet(&pkt);
goto redo;
}
if (!got_picture) {
/* no picture yet */
ptr += ret;
len -= ret;
continue;
}
is->pts_den * ist->st->codec.frame_rate_base);
}
break;
default:
goto fail_decode;
}
} else {
data_buf = ptr;
data_size = len;
ret = len;
}
ptr += ret;
len -= ret;
buffer_to_free = 0;
if (ist->st->codec.codec_type == CODEC_TYPE_VIDEO) {
pre_process_video_frame(ist, &picture, &buffer_to_free);
}
Fabrice Bellard
committed
ist->frame_decoded = 1;
Max Krasnyansky
committed
/* frame rate emulation */
if (ist->st->codec.rate_emu) {
Michael Niedermayer
committed
int64_t pts = av_rescale((int64_t) ist->frame * ist->st->codec.frame_rate_base, 1000000, ist->st->codec.frame_rate);
Max Krasnyansky
committed
int64_t now = av_gettime() - ist->start;
if (pts > now)
usleep(pts - now);
ist->frame++;
}
Fabrice Bellard
committed
#if 0
/* mpeg PTS deordering : if it is a P or I frame, the PTS
is the one of the next displayed one */
/* XXX: add mpeg4 too ? */
if (ist->st->codec.codec_id == CODEC_ID_MPEG1VIDEO) {
if (ist->st->codec.pict_type != B_TYPE) {
Fabrice Bellard
committed
tmp = ist->last_ip_pts;
ist->last_ip_pts = ist->frac_pts.val;
ist->frac_pts.val = tmp;
}
}
#endif
Fabrice Bellard
committed
Fabrice Bellard
committed
ost = ost_table[i];
if (ost->source_index == ist_index) {
os = output_files[ost->file_index];
Fabrice Bellard
committed
#if 0
printf("%d: got pts=%f %f\n", i, pkt.pts / 90000.0,
(ist->pts - ost->st->pts.val) / 90000.0);
Fabrice Bellard
committed
#endif
/* set the input output pts pairs */
ost->sync_ipts = (double)ist->pts * is->pts_num /
is->pts_den;
/* XXX: take into account the various fifos,
in particular for audio */
ost->sync_opts = ost->st->pts.val;
//printf("ipts=%lld sync_ipts=%f sync_opts=%lld pts.val=%lld pkt.pts=%lld\n", ist->pts, ost->sync_ipts, ost->sync_opts, ost->st->pts.val, pkt.pts);
Fabrice Bellard
committed
if (ost->encoding_needed) {
switch(ost->st->codec.codec_type) {
case CODEC_TYPE_AUDIO:
do_audio_out(os, ost, ist, data_buf, data_size);
break;
case CODEC_TYPE_VIDEO:
Fabrice Bellard
committed
/* find an audio stream for synchro */
{
int i;
AVOutputStream *audio_sync, *ost1;
audio_sync = NULL;
for(i=0;i<nb_ostreams;i++) {
ost1 = ost_table[i];
if (ost1->file_index == ost->file_index &&
ost1->st->codec.codec_type == CODEC_TYPE_AUDIO) {
audio_sync = ost1;
break;
}
}
do_video_out(os, ost, ist, &picture, &frame_size, audio_sync);
Philip Gladstone
committed
if (do_vstats && frame_size)
Fabrice Bellard
committed
do_video_stats(os, ost, frame_size);
}
default:
av_abort();
/* force the input stream PTS */
memset(&avframe, 0, sizeof(AVFrame));
ost->st->codec.coded_frame= &avframe;
avframe.key_frame = pkt.flags & PKT_FLAG_KEY;
Fabrice Bellard
committed
av_write_frame(os, ost->index, data_buf, data_size);
Måns Rullgård
committed
ost->st->codec.frame_number++;
Måns Rullgård
committed
ost->frame_number++;
av_free(buffer_to_free);
Fabrice Bellard
committed
/* dump report by using the output first video and audio streams */
print_report(output_files, ost_table, nb_ostreams, 0);
term_exit();
/* dump report by using the first video and audio streams */
Fabrice Bellard
committed
print_report(output_files, ost_table, nb_ostreams, 1);
/* close each encoder */
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
if (ost->encoding_needed) {
av_freep(&ost->st->codec.stats_in);
avcodec_close(&ost->st->codec);
}
}
/* close each decoder */
for(i=0;i<nb_istreams;i++) {
ist = ist_table[i];
if (ist->decoding_needed) {
avcodec_close(&ist->st->codec);
}
}
/* write the trailer if needed and close file */
for(i=0;i<nb_output_files;i++) {
os = output_files[i];
av_write_trailer(os);
if (ist_table) {
for(i=0;i<nb_istreams;i++) {
ist = ist_table[i];
}
if (ost_table) {
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
if (ost) {
if (ost->logfile) {
fclose(ost->logfile);
ost->logfile = NULL;
}
fifo_free(&ost->fifo); /* works even if fifo is not
initialized but set to zero */
if (ost->video_resample)
img_resample_close(ost->img_resample_ctx);
if (ost->audio_resample)
audio_resample_close(ost->resample);
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
}
return ret;
fail:
ret = -ENOMEM;
goto fail1;
}
#if 0
int file_read(const char *filename)
{
URLContext *h;
unsigned char buffer[1024];
int len, i;
if (url_open(&h, filename, O_RDONLY) < 0) {
printf("could not open '%s'\n", filename);
return -1;
}
for(;;) {
len = url_read(h, buffer, sizeof(buffer));
if (len <= 0)
break;
for(i=0;i<len;i++) putchar(buffer[i]);
}
url_close(h);
return 0;
}
#endif
static void opt_image_format(const char *arg)
Fabrice Bellard
committed
{
AVImageFormat *f;
for(f = first_image_format; f != NULL; f = f->next) {
if (!strcmp(arg, f->name))
break;
}
if (!f) {
fprintf(stderr, "Unknown image format: '%s'\n", arg);
exit(1);
}
image_format = f;
}
static void opt_format(const char *arg)
Fabrice Bellard
committed
/* compatibility stuff for pgmyuv */
if (!strcmp(arg, "pgmyuv")) {
opt_image_format(arg);
arg = "image";
}
file_iformat = av_find_input_format(arg);
file_oformat = guess_format(arg, NULL, NULL);
if (!file_iformat && !file_oformat) {
fprintf(stderr, "Unknown input or output format: %s\n", arg);
static void opt_video_bitrate(const char *arg)
static void opt_video_bitrate_tolerance(const char *arg)
{
video_bit_rate_tolerance = atoi(arg) * 1000;
}
static void opt_video_bitrate_max(const char *arg)
{
video_rc_max_rate = atoi(arg) * 1000;
}
static void opt_video_bitrate_min(const char *arg)
{
video_rc_min_rate = atoi(arg) * 1000;
}
static void opt_video_buffer_size(const char *arg)
{
video_rc_buffer_size = atoi(arg) * 1000;
}
static void opt_video_rc_eq(char *arg)
static void opt_video_rc_override_string(char *arg)
{
video_rc_override_string = arg;
}
static void opt_workaround_bugs(const char *arg)
Michael Niedermayer
committed
{
workaround_bugs = atoi(arg);
}
static void opt_dct_algo(const char *arg)
{
dct_algo = atoi(arg);
}
static void opt_idct_algo(const char *arg)
{
idct_algo = atoi(arg);
}
static void opt_error_resilience(const char *arg)
{
error_resilience = atoi(arg);
}
static void opt_error_concealment(const char *arg)
{
error_concealment = atoi(arg);
}
static void opt_debug(const char *arg)
static void opt_frame_rate(const char *arg)
if (parse_frame_rate(&frame_rate, &frame_rate_base, arg) < 0) {
fprintf(stderr, "Incorrect frame rate\n");
exit(1);
}
static void opt_frame_crop_top(const char *arg)
Michael Niedermayer
committed
{
frame_topBand = atoi(arg);
if (frame_topBand < 0) {
fprintf(stderr, "Incorrect top crop size\n");
exit(1);
}
if ((frame_topBand % 2) != 0) {
fprintf(stderr, "Top crop size must be a multiple of 2\n");
exit(1);
}
if ((frame_topBand) >= frame_height){
fprintf(stderr, "Vertical crop dimensions are outside the range of the original image.\nRemember to crop first and scale second.\n");
exit(1);
}
frame_height -= frame_topBand;
}
static void opt_frame_crop_bottom(const char *arg)
Michael Niedermayer
committed
{
frame_bottomBand = atoi(arg);
if (frame_bottomBand < 0) {
fprintf(stderr, "Incorrect bottom crop size\n");
exit(1);
}
if ((frame_bottomBand % 2) != 0) {
fprintf(stderr, "Bottom crop size must be a multiple of 2\n");
exit(1);
}
if ((frame_bottomBand) >= frame_height){
fprintf(stderr, "Vertical crop dimensions are outside the range of the original image.\nRemember to crop first and scale second.\n");
exit(1);
}
frame_height -= frame_bottomBand;
}
static void opt_frame_crop_left(const char *arg)
Michael Niedermayer
committed
{
frame_leftBand = atoi(arg);
if (frame_leftBand < 0) {
fprintf(stderr, "Incorrect left crop size\n");
exit(1);
}
if ((frame_leftBand % 2) != 0) {
fprintf(stderr, "Left crop size must be a multiple of 2\n");
exit(1);
}
if ((frame_leftBand) >= frame_width){
fprintf(stderr, "Horizontal crop dimensions are outside the range of the original image.\nRemember to crop first and scale second.\n");
exit(1);
}
frame_width -= frame_leftBand;
}
static void opt_frame_crop_right(const char *arg)
Michael Niedermayer
committed
{
frame_rightBand = atoi(arg);
if (frame_rightBand < 0) {
fprintf(stderr, "Incorrect right crop size\n");
exit(1);
}
if ((frame_rightBand % 2) != 0) {
fprintf(stderr, "Right crop size must be a multiple of 2\n");
exit(1);
}
if ((frame_rightBand) >= frame_width){
fprintf(stderr, "Horizontal crop dimensions are outside the range of the original image.\nRemember to crop first and scale second.\n");
exit(1);
}
frame_width -= frame_rightBand;
}
static void opt_frame_size(const char *arg)
if (parse_image_size(&frame_width, &frame_height, arg) < 0) {
fprintf(stderr, "Incorrect frame size\n");
exit(1);
}
if ((frame_width % 2) != 0 || (frame_height % 2) != 0) {
fprintf(stderr, "Frame size must be a multiple of 2\n");
exit(1);
}
}
static void opt_frame_pix_fmt(const char *arg)
{
frame_pix_fmt = avcodec_get_pix_fmt(arg);
}
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
static void opt_frame_aspect_ratio(const char *arg)
{
int x = 0, y = 0;
double ar = 0;
const char *p;
p = strchr(arg, ':');
if (p) {
x = strtol(arg, (char **)&arg, 10);
if (arg == p)
y = strtol(arg+1, (char **)&arg, 10);
if (x > 0 && y > 0)
ar = (double)x / (double)y;
} else
ar = strtod(arg, (char **)&arg);
if (!ar) {
fprintf(stderr, "Incorrect aspect ratio specification.\n");
exit(1);
}
frame_aspect_ratio = ar;
}
static void opt_gop_size(const char *arg)
static void opt_b_frames(const char *arg)
{
b_frames = atoi(arg);
if (b_frames > FF_MAX_B_FRAMES) {
fprintf(stderr, "\nCannot have more than %d B frames, increase FF_MAX_B_FRAMES.\n", FF_MAX_B_FRAMES);
exit(1);
} else if (b_frames < 1) {
fprintf(stderr, "\nNumber of B frames must be higher than 0\n");
exit(1);
}
}
static void opt_mb_decision(const char *arg)
{
mb_decision = atoi(arg);
}
static void opt_qscale(const char *arg)
{
video_qscale = atoi(arg);
if (video_qscale < 0 ||
video_qscale > 31) {
fprintf(stderr, "qscale must be >= 1 and <= 31\n");
exit(1);
}
}
static void opt_qmin(const char *arg)
{
video_qmin = atoi(arg);
if (video_qmin < 0 ||
video_qmin > 31) {
fprintf(stderr, "qmin must be >= 1 and <= 31\n");
exit(1);
}
}
static void opt_qmax(const char *arg)
{
video_qmax = atoi(arg);
if (video_qmax < 0 ||
video_qmax > 31) {
fprintf(stderr, "qmax must be >= 1 and <= 31\n");
exit(1);
}
}
static void opt_mb_qmin(const char *arg)
{
video_mb_qmin = atoi(arg);
if (video_mb_qmin < 0 ||
video_mb_qmin > 31) {
fprintf(stderr, "qmin must be >= 1 and <= 31\n");
exit(1);
}
}
static void opt_mb_qmax(const char *arg)
{
video_mb_qmax = atoi(arg);
if (video_mb_qmax < 0 ||
video_mb_qmax > 31) {
fprintf(stderr, "qmax must be >= 1 and <= 31\n");
exit(1);
}
}
static void opt_qdiff(const char *arg)
{
video_qdiff = atoi(arg);
if (video_qdiff < 0 ||
video_qdiff > 31) {
fprintf(stderr, "qdiff must be >= 1 and <= 31\n");
exit(1);
}
}
static void opt_qblur(const char *arg)
{
video_qblur = atof(arg);
}
static void opt_qcomp(const char *arg)
{
video_qcomp = atof(arg);
}
static void opt_rc_initial_cplx(const char *arg)
{
video_rc_initial_cplx = atof(arg);
}
static void opt_b_qfactor(const char *arg)
{
video_b_qfactor = atof(arg);
}
static void opt_i_qfactor(const char *arg)
{
video_i_qfactor = atof(arg);
}
static void opt_b_qoffset(const char *arg)
{
video_b_qoffset = atof(arg);
}
static void opt_i_qoffset(const char *arg)
{
video_i_qoffset = atof(arg);
}
static void opt_packet_size(const char *arg)
{
packet_size= atoi(arg);
}
static void opt_strict(const char *arg)
static void opt_audio_bitrate(const char *arg)
static void opt_audio_rate(const char *arg)
static void opt_audio_channels(const char *arg)
static void opt_video_device(const char *arg)
static void opt_video_channel(const char *arg)
Fabrice Bellard
committed
{
video_channel = strtol(arg, NULL, 0);
}
static void opt_video_standard(const char *arg)
{
video_standard = av_strdup(arg);
}
static void opt_audio_device(const char *arg)
static void opt_dv1394(const char *arg)
{
video_grab_format = "dv1394";
audio_grab_format = NULL;
static void opt_audio_codec(const char *arg)
if (!strcmp(arg, "copy")) {
audio_stream_copy = 1;
p = first_avcodec;
while (p) {
if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
break;
p = p->next;
}
if (p == NULL) {
fprintf(stderr, "Unknown audio codec '%s'\n", arg);
exit(1);
} else {
audio_codec_id = p->id;
}
static void add_frame_hooker(const char *arg)
{
int argc = 0;
char *argv[64];
int i;
argv[0] = strtok(args, " ");
while (argc < 62 && (argv[++argc] = strtok(NULL, " "))) {
}
i = frame_hook_add(argc, argv);
if (i != 0) {
fprintf(stderr, "Failed to add video hook function: %s\n", arg);
exit(1);
}
}
const char *motion_str[] = {
"zero",
"full",
"log",
"phods",
static void opt_motion_estimation(const char *arg)
{
const char **p;
p = motion_str;
for(;;) {
if (!*p) {
fprintf(stderr, "Unknown motion estimation method '%s'\n", arg);
exit(1);
}
if (!strcmp(*p, arg))
break;
p++;
}
static void opt_video_codec(const char *arg)
if (!strcmp(arg, "copy")) {
video_stream_copy = 1;
p = first_avcodec;
while (p) {
if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
break;
p = p->next;
}
if (p == NULL) {
fprintf(stderr, "Unknown video codec '%s'\n", arg);
exit(1);
} else {
video_codec_id = p->id;
}
static void opt_map(const char *arg)
{
AVStreamMap *m;
const char *p;
p = arg;
m = &stream_maps[nb_stream_maps++];
m->file_index = strtol(arg, (char **)&p, 0);
if (*p)
p++;
m->stream_index = strtol(p, (char **)&p, 0);
static void opt_recording_time(const char *arg)
static void opt_input_file(const char *filename)
{
AVFormatContext *ic;
AVFormatParameters params, *ap = ¶ms;
Michael Niedermayer
committed
int err, i, ret, rfps, rfps_base;
if (!strcmp(filename, "-"))
filename = "pipe:";
memset(ap, 0, sizeof(*ap));
ap->sample_rate = audio_sample_rate;
ap->channels = audio_channels;
ap->frame_rate = frame_rate;
Michael Niedermayer
committed
ap->frame_rate_base = frame_rate_base;
ap->width = frame_width;
ap->height = frame_height;
Fabrice Bellard
committed
ap->image_format = image_format;
ap->pix_fmt = frame_pix_fmt;
/* open the input file with generic libav function */
err = av_open_input_file(&ic, filename, file_iformat, 0, ap);
print_error(filename, err);
/* If not enough info to get the stream parameters, we decode the
first frames to get it. (used in mpeg case for example) */
ret = av_find_stream_info(ic);
if (ret < 0) {
fprintf(stderr, "%s: could not find codec parameters\n", filename);
exit(1);
}
/* update the current parameters so that they match the one of the input stream */
for(i=0;i<ic->nb_streams;i++) {
AVCodecContext *enc = &ic->streams[i]->codec;
switch(enc->codec_type) {
case CODEC_TYPE_AUDIO:
//fprintf(stderr, "\nInput Audio channels: %d", enc->channels);
audio_channels = enc->channels;
audio_sample_rate = enc->sample_rate;
break;
case CODEC_TYPE_VIDEO:
frame_height = enc->height;
frame_width = enc->width;
frame_aspect_ratio = enc->aspect_ratio;
frame_pix_fmt = enc->pix_fmt;
Michael Niedermayer
committed
rfps = ic->streams[i]->r_frame_rate;
rfps_base = ic->streams[i]->r_frame_rate_base;
Michael Niedermayer
committed
enc->workaround_bugs = workaround_bugs;
enc->error_resilience = error_resilience;
enc->error_concealment = error_concealment;
enc->idct_algo= idct_algo;
/* if(enc->codec->capabilities & CODEC_CAP_TRUNCATED)
enc->flags|= CODEC_FLAG_TRUNCATED; */
if(/*enc->codec_id==CODEC_ID_MPEG4 || */enc->codec_id==CODEC_ID_MPEG1VIDEO || enc->codec_id==CODEC_ID_H264)
enc->flags|= CODEC_FLAG_TRUNCATED;
if(bitexact)
enc->flags|= CODEC_FLAG_BITEXACT;
Michael Niedermayer
committed
assert(enc->frame_rate_base == rfps_base); // should be true for now
if (enc->frame_rate != rfps) {
fprintf(stderr,"\nSeems that stream %d comes from film source: %2.2f->%2.2f\n",
Michael Niedermayer
committed
i, (float)enc->frame_rate / enc->frame_rate_base,
(float)rfps / rfps_base);
/* update the current frame rate to match the stream frame rate */
Michael Niedermayer
committed
frame_rate = rfps;
frame_rate_base = rfps_base;
Max Krasnyansky
committed
enc->rate_emu = rate_emu;
default:
av_abort();
}
}
input_files[nb_input_files] = ic;
/* dump the file content */
dump_format(ic, nb_input_files, filename, 0);
nb_input_files++;
file_iformat = NULL;
file_oformat = NULL;
Fabrice Bellard
committed
image_format = NULL;
Max Krasnyansky
committed
rate_emu = 0;
static void check_audio_video_inputs(int *has_video_ptr, int *has_audio_ptr)
Fabrice Bellard
committed
{
int has_video, has_audio, i, j;
AVFormatContext *ic;
has_video = 0;
has_audio = 0;
for(j=0;j<nb_input_files;j++) {
ic = input_files[j];
for(i=0;i<ic->nb_streams;i++) {
AVCodecContext *enc = &ic->streams[i]->codec;
switch(enc->codec_type) {
case CODEC_TYPE_AUDIO:
has_audio = 1;
break;
case CODEC_TYPE_VIDEO:
has_video = 1;
break;
default:
av_abort();
Fabrice Bellard
committed
}
}
}
*has_video_ptr = has_video;
*has_audio_ptr = has_audio;
}
static void opt_output_file(const char *filename)
Fabrice Bellard
committed
int use_video, use_audio, nb_streams, input_has_video, input_has_audio;
Fabrice Bellard
committed
AVFormatParameters params, *ap = ¶ms;
if (!strcmp(filename, "-"))
filename = "pipe:";
oc = av_mallocz(sizeof(AVFormatContext));
if (!file_oformat) {
file_oformat = guess_format(NULL, filename, NULL);
if (!file_oformat) {
fprintf(stderr, "Unable for find a suitable output format for '%s'\n",
filename);
exit(1);
}
oc->oformat = file_oformat;
if (!strcmp(file_oformat->name, "ffm") &&
strstart(filename, "http:", NULL)) {
/* special case for files sent to ffserver: we get the stream
parameters from ffserver */
if (read_ffserver_streams(oc, filename) < 0) {
fprintf(stderr, "Could not read stream parameters from '%s'\n", filename);
exit(1);
}
} else {
use_video = file_oformat->video_codec != CODEC_ID_NONE;
use_audio = file_oformat->audio_codec != CODEC_ID_NONE;
Fabrice Bellard
committed
/* disable if no corresponding type found and at least one
input file */
if (nb_input_files > 0) {
check_audio_video_inputs(&input_has_video, &input_has_audio);
if (!input_has_video)
use_video = 0;
if (!input_has_audio)
use_audio = 0;
}
Fabrice Bellard
committed
/* manual disable */
if (audio_disable) {
use_audio = 0;
}
if (video_disable) {
use_video = 0;
}
nb_streams = 0;
if (use_video) {
AVCodecContext *video_enc;
st = av_mallocz(sizeof(AVStream));
if (!st) {
fprintf(stderr, "Could not alloc stream\n");
exit(1);
}
video_enc = &st->codec;
if (video_stream_copy) {
st->stream_copy = 1;
video_enc->codec_type = CODEC_TYPE_VIDEO;
} else {
char *p;
int i;
codec_id = file_oformat->video_codec;
if (video_codec_id != CODEC_ID_NONE)
codec_id = video_codec_id;
video_enc->codec_id = codec_id;
video_enc->bit_rate = video_bit_rate;
video_enc->bit_rate_tolerance = video_bit_rate_tolerance;
video_enc->frame_rate = frame_rate;
Michael Niedermayer
committed
video_enc->frame_rate_base = frame_rate_base;
video_enc->width = frame_width;
video_enc->height = frame_height;
video_enc->aspect_ratio = frame_aspect_ratio;
video_enc->pix_fmt = frame_pix_fmt;
if (!intra_only)
video_enc->gop_size = gop_size;
else
video_enc->gop_size = 0;
if (video_qscale || same_quality) {
video_enc->flags |= CODEC_FLAG_QSCALE;
Loading
Loading full blame...