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"
Michael Niedermayer
committed
#include "dsputil.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
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
#undef NDEBUG
#include <assert.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;
Patrice Bensoussan
committed
/** select an input file for an output file */
typedef struct AVMetaDataMap {
int out_file;
int in_file;
} AVMetaDataMap;
static void show_help(void);
static void show_license(void);
#define MAX_FILES 20
static AVFormatContext *input_files[MAX_FILES];
static int64_t input_files_ts_offset[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;
Patrice Bensoussan
committed
static AVMetaDataMap meta_data_maps[MAX_FILES];
static int nb_meta_data_maps;
static AVInputFormat *file_iformat;
static AVOutputFormat *file_oformat;
Fabrice Bellard
committed
static AVImageFormat *image_format;
static int frame_width = 0;
static int frame_height = 0;
static float frame_aspect_ratio = 0;
static enum PixelFormat frame_pix_fmt = PIX_FMT_YUV420P;
Todd Kirby
committed
static int frame_padtop = 0;
static int frame_padbottom = 0;
static int frame_padleft = 0;
static int frame_padright = 0;
static int padcolor[3] = {16,128,128}; /* default to black */
Michael Niedermayer
committed
static int frame_topBand = 0;
static int frame_bottomBand = 0;
static int frame_leftBand = 0;
static int frame_rightBand = 0;
static int max_frames[3] = {INT_MAX, INT_MAX, INT_MAX};
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;
Michael Niedermayer
committed
static float video_qscale = 0;
static int video_qmin = 2;
static int video_qmax = 31;
static int video_lmin = 2*FF_QP2LAMBDA;
static int video_lmax = 31*FF_QP2LAMBDA;
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;
Vidar Madsen
committed
static uint16_t *intra_matrix = NULL;
static uint16_t *inter_matrix = NULL;
#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;
static int video_intra_quant_bias= FF_DEFAULT_QUANT_BIAS;
static int video_inter_quant_bias= FF_DEFAULT_QUANT_BIAS;
Michael Niedermayer
committed
static int me_method = ME_EPZS;
static int video_disable = 0;
static int video_codec_id = CODEC_ID_NONE;
static int mb_decision = FF_MB_DECISION_SIMPLE;
static int ildct_cmp = FF_CMP_VSAD;
static int mb_cmp = FF_CMP_SAD;
static int sub_cmp = FF_CMP_SAD;
static int cmp = FF_CMP_SAD;
static int pre_cmp = FF_CMP_SAD;
static int pre_me = 0;
static float lumi_mask = 0;
static float dark_mask = 0;
static float scplx_mask = 0;
static float tcplx_mask = 0;
static float p_mask = 0;
Michael Niedermayer
committed
static int use_aic = 0;
Michael Niedermayer
committed
static int use_umv = 0;
static int use_ss = 0;
static int closed_gop = 0;
static int do_deinterlace = 0;
static int do_interlace_dct = 0;
static int do_interlace_me = 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 top_field_first = -1;
static int noise_reduction = 0;
static int sc_threshold = 0;
Wolfgang Hesseler
committed
static int debug_mv = 0;
Michael Niedermayer
committed
static int me_threshold = 0;
Michael Niedermayer
committed
static int mb_threshold = 0;
static int coder = 0;
static int context = 0;
static int predictor = 0;
static int video_profile = FF_PROFILE_UNKNOWN;
static int video_level = FF_LEVEL_UNKNOWN;
static int subpel_quality= 8;
static int lowres= 0;
static int frame_skip_threshold= 0;
static int frame_skip_factor= 0;
static int frame_skip_exp= 0;
static int frame_skip_cmp= FF_CMP_DCTMAX;
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 mux_rate= 0;
static int mux_packet_size= 0;
static float mux_preload= 0.5;
static float mux_max_delay= 0.7;
static int64_t start_time = 0;
static int64_t rec_timestamp = 0;
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_pkt_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;
static int video_sync_method= 1;
static int audio_sync_method= 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;
static int using_stdin = 0;
static int using_vhook = 0;
static int verbose = 1;
Leon van Stuivenberg
committed
static int q_pressed = 0;
Timofei V. Bondarenko
committed
static int me_range = 0;
static int64_t video_size = 0;
static int64_t audio_size = 0;
static int64_t extra_size = 0;
static int nb_frames_dup = 0;
static int nb_frames_drop = 0;
static int input_sync;
static int pgmyuv_compatibility_hack=0;
#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; /* dts from the AVPacket of the demuxer in second units */
int64_t sync_opts; /* output frame counter, could be changed to some true timestamp */ //FIXME look at frame_number
int video_resample; /* video_resample and video_crop are mutually exclusive */
Michael Niedermayer
committed
AVFrame 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;
Todd Kirby
committed
int video_pad; /* video_resample and video_pad are mutually exclusive */
int padtop; /* padding area sizes */
int padbottom;
int padleft;
int padright;
/* 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 */
Max Krasnyansky
committed
int64_t start; /* time when read started */
unsigned long frame; /* current frame */
int64_t next_pts; /* synthetic pts for cases where pkt.pts
is not defined */
int is_start; /* is 1 at the start and after a discontinuity */
} 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;
Leon van Stuivenberg
committed
static int decode_interrupt_cb(void)
{
return q_pressed || (q_pressed = read_key() == 'q');
}
#else
static volatile int received_sigterm = 0;
/* 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
AVCodecContext *enc= &ost->st->codec;
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 ! */
if(audio_sync_method){
double delta = ost->sync_ipts * enc->sample_rate - ost->sync_opts
- fifo_size(&ost->fifo, ost->fifo.rptr)/(ost->st->codec.channels * 2);
double idelta= delta*ist->st->codec.sample_rate / enc->sample_rate;
int byte_delta= ((int)idelta)*2*ist->st->codec.channels;
//FIXME resample delay
if(fabs(delta) > 50){
if(ist->is_start){
if(byte_delta < 0){
Michael Niedermayer
committed
byte_delta= FFMAX(byte_delta, -size);
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
size += byte_delta;
buf -= byte_delta;
if(verbose > 2)
fprintf(stderr, "discarding %d audio samples\n", (int)-delta);
if(!size)
return;
ist->is_start=0;
}else{
static uint8_t *input_tmp= NULL;
input_tmp= av_realloc(input_tmp, byte_delta + size);
if(byte_delta + size <= MAX_AUDIO_PACKET_SIZE)
ist->is_start=0;
else
byte_delta= MAX_AUDIO_PACKET_SIZE - size;
memset(input_tmp, 0, byte_delta);
memcpy(input_tmp + byte_delta, buf, size);
buf= input_tmp;
size += byte_delta;
if(verbose > 2)
fprintf(stderr, "adding %d audio samples of silence\n", (int)delta);
}
}else if(audio_sync_method>1){
int comp= clip(delta, -audio_sync_method, audio_sync_method);
assert(ost->audio_resample);
if(verbose > 2)
fprintf(stderr, "compensating audio timestamp drift:%f compensation:%d in:%d\n", delta, comp, enc->sample_rate);
// fprintf(stderr, "drift:%f len:%d opts:%lld ipts:%lld fifo:%d\n", delta, -1, ost->sync_opts, (int64_t)(ost->sync_ipts * enc->sample_rate), fifo_size(&ost->fifo, ost->fifo.rptr)/(ost->st->codec.channels * 2));
av_resample_compensate(*(struct AVResampleContext**)ost->resample, comp, enc->sample_rate);
}
}
}else
ost->sync_opts= lrintf(ost->sync_ipts * enc->sample_rate)
- fifo_size(&ost->fifo, ost->fifo.rptr)/(ost->st->codec.channels * 2); //FIXME wrong
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) {
AVPacket pkt;
av_init_packet(&pkt);
(short *)audio_buf);
audio_size += ret;
pkt.stream_index= ost->index;
pkt.data= audio_out;
pkt.size= ret;
if(enc->coded_frame)
pkt.pts= enc->coded_frame->pts;
pkt.flags |= PKT_FLAG_KEY;
av_interleaved_write_frame(s, &pkt);
ost->sync_opts += enc->frame_size;
AVPacket pkt;
av_init_packet(&pkt);
Michael Niedermayer
committed
ost->sync_opts += size_out / (2 * enc->channels);
/* 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);
audio_size += ret;
pkt.stream_index= ost->index;
pkt.data= audio_out;
pkt.size= ret;
if(enc->coded_frame)
pkt.pts= enc->coded_frame->pts;
pkt.flags |= PKT_FLAG_KEY;
av_interleaved_write_frame(s, &pkt);
static void pre_process_video_frame(AVInputStream *ist, AVPicture *picture, void **bufp)
{
AVCodecContext *dec;
AVPicture *picture2;
AVPicture picture_tmp;
dec = &ist->st->codec;
/* deinterlace : must be done before any resize */
if (do_deinterlace || using_vhook) {
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 (do_deinterlace){
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 {
if (img_convert(picture2, dec->pix_fmt, picture,
dec->pix_fmt, dec->width, dec->height) < 0) {
/* if error, do not copy */
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
Todd Kirby
committed
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
/* Expects img to be yuv420 */
static void fill_pad_region(AVPicture* img, int height, int width,
int padtop, int padbottom, int padleft, int padright, int *color) {
int i, y, shift;
uint8_t *optr;
for (i = 0; i < 3; i++) {
shift = (i == 0) ? 0 : 1;
if (padtop || padleft) {
memset(img->data[i], color[i], (((img->linesize[i] * padtop) +
padleft) >> shift));
}
if (padleft || padright) {
optr = img->data[i] + (img->linesize[i] * (padtop >> shift)) +
(img->linesize[i] - (padright >> shift));
for (y = 0; y < ((height - (padtop + padbottom)) >> shift); y++) {
memset(optr, color[i], (padleft + padright) >> shift);
optr += img->linesize[i];
}
}
if (padbottom) {
optr = img->data[i] + (img->linesize[i] * ((height - padbottom) >> shift));
memset(optr, color[i], ((img->linesize[i] * padbottom) >> shift));
}
}
}
static int bit_buffer_size= 1024*256;
static uint8_t *bit_buffer= NULL;
Todd Kirby
committed
static void do_video_out(AVFormatContext *s,
AVOutputStream *ost,
AVInputStream *ist,
Fabrice Bellard
committed
int nb_frames, i, ret;
Michael Niedermayer
committed
AVFrame *final_picture, *formatted_picture;
AVFrame picture_format_temp, picture_crop_temp;
AVCodecContext *enc, *dec;
enum PixelFormat target_pixfmt;
Michael Niedermayer
committed
avcodec_get_frame_defaults(&picture_format_temp);
avcodec_get_frame_defaults(&picture_crop_temp);
dec = &ist->st->codec;
Fabrice Bellard
committed
/* by default, we output a single frame */
nb_frames = 1;
Philip Gladstone
committed
*frame_size = 0;
double vdelta;
vdelta = ost->sync_ipts * enc->frame_rate / enc->frame_rate_base - ost->sync_opts;
//FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
if (vdelta < -1.1)
nb_frames = 0;
else if (vdelta > 1.1)
//fprintf(stderr, "vdelta:%f, ost->sync_opts:%lld, ost->sync_ipts:%f nb_frames:%d\n", vdelta, ost->sync_opts, ost->sync_ipts, nb_frames);
if (nb_frames == 0){
++nb_frames_drop;
if (verbose>2)
fprintf(stderr, "*** drop!\n");
}else if (nb_frames > 1) {
nb_frames_dup += nb_frames;
fprintf(stderr, "*** %d dup!\n", nb_frames-1);
}
}else
ost->sync_opts= lrintf(ost->sync_ipts * enc->frame_rate / enc->frame_rate_base);
nb_frames= FFMIN(nb_frames, max_frames[CODEC_TYPE_VIDEO] - ost->frame_number);
Fabrice Bellard
committed
if (nb_frames <= 0)
/* convert pixel format if needed */
Todd Kirby
committed
target_pixfmt = ost->video_resample || ost->video_pad
? PIX_FMT_YUV420P : enc->pix_fmt;
if (dec->pix_fmt != target_pixfmt) {
int size;
/* create temporary picture */
size = avpicture_get_size(target_pixfmt, dec->width, dec->height);
if (!buf)
return;
formatted_picture = &picture_format_temp;
Michael Niedermayer
committed
avpicture_fill((AVPicture*)formatted_picture, buf, target_pixfmt, dec->width, dec->height);
Michael Niedermayer
committed
if (img_convert((AVPicture*)formatted_picture, target_pixfmt,
(AVPicture *)in_picture, dec->pix_fmt,
dec->width, dec->height) < 0) {
if (verbose >= 0)
fprintf(stderr, "pixel format conversion not handled\n");
goto the_end;
}
} else {
Michael Niedermayer
committed
formatted_picture = in_picture;
Todd Kirby
committed
/* XXX: resampling could be done before raw format conversion in
some cases to go faster */
/* XXX: only works for YUV420P */
final_picture = &ost->pict_tmp;
Michael Niedermayer
committed
img_resample(ost->img_resample_ctx, (AVPicture*)final_picture, (AVPicture*)formatted_picture);
Todd Kirby
committed
if (ost->padtop || ost->padbottom || ost->padleft || ost->padright) {
Michael Niedermayer
committed
fill_pad_region((AVPicture*)final_picture, enc->height, enc->width,
Todd Kirby
committed
ost->padtop, ost->padbottom, ost->padleft, ost->padright,
padcolor);
}
if (enc->pix_fmt != PIX_FMT_YUV420P) {
int size;
av_free(buf);
/* create temporary picture */
size = avpicture_get_size(enc->pix_fmt, enc->width, enc->height);
buf = av_malloc(size);
if (!buf)
return;
final_picture = &picture_format_temp;
Michael Niedermayer
committed
avpicture_fill((AVPicture*)final_picture, buf, enc->pix_fmt, enc->width, enc->height);
Michael Niedermayer
committed
if (img_convert((AVPicture*)final_picture, enc->pix_fmt,
(AVPicture*)&ost->pict_tmp, PIX_FMT_YUV420P,
enc->width, enc->height) < 0) {
if (verbose >= 0)
fprintf(stderr, "pixel format conversion not handled\n");
goto the_end;
}
}
} 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;
Todd Kirby
committed
} else if (ost->video_pad) {
final_picture = &ost->pict_tmp;
for (i = 0; i < 3; i++) {
uint8_t *optr, *iptr;
int shift = (i == 0) ? 0 : 1;
int y, yheight;
/* set offset to start writing image into */
optr = final_picture->data[i] + (((final_picture->linesize[i] *
ost->padtop) + ost->padleft) >> shift);
iptr = formatted_picture->data[i];
yheight = (enc->height - ost->padtop - ost->padbottom) >> shift;
for (y = 0; y < yheight; y++) {
/* copy unpadded image row into padded image row */
memcpy(optr, iptr, formatted_picture->linesize[i]);
optr += final_picture->linesize[i];
iptr += formatted_picture->linesize[i];
}
}
Michael Niedermayer
committed
fill_pad_region((AVPicture*)final_picture, enc->height, enc->width,
Todd Kirby
committed
ost->padtop, ost->padbottom, ost->padleft, ost->padright,
padcolor);
if (enc->pix_fmt != PIX_FMT_YUV420P) {
int size;
av_free(buf);
/* create temporary picture */
size = avpicture_get_size(enc->pix_fmt, enc->width, enc->height);
buf = av_malloc(size);
if (!buf)
return;
final_picture = &picture_format_temp;
Michael Niedermayer
committed
avpicture_fill((AVPicture*)final_picture, buf, enc->pix_fmt, enc->width, enc->height);
Todd Kirby
committed
Michael Niedermayer
committed
if (img_convert((AVPicture*)final_picture, enc->pix_fmt,
(AVPicture*)&ost->pict_tmp, PIX_FMT_YUV420P,
Todd Kirby
committed
enc->width, enc->height) < 0) {
if (verbose >= 0)
fprintf(stderr, "pixel format conversion not handled\n");
Todd Kirby
committed
goto the_end;
}
}
final_picture = formatted_picture;
Fabrice Bellard
committed
for(i=0;i<nb_frames;i++) {
AVPacket pkt;
av_init_packet(&pkt);
pkt.stream_index= ost->index;
if (s->oformat->flags & AVFMT_RAWPICTURE) {
/* raw pictures are written as AVPicture structure to
avoid any copies. We support temorarily the older
method. */
AVFrame* old_frame = enc->coded_frame;
enc->coded_frame = dec->coded_frame; //FIXME/XXX remove this hack
pkt.data= (uint8_t *)final_picture;
pkt.size= sizeof(AVPicture);
if(dec->coded_frame)
pkt.pts= dec->coded_frame->pts;
if(dec->coded_frame && dec->coded_frame->key_frame)
pkt.flags |= PKT_FLAG_KEY;
av_interleaved_write_frame(s, &pkt);
enc->coded_frame = old_frame;
} else {
Michael Niedermayer
committed
big_picture= *final_picture;
/* better than nothing: use input picture interlaced
settings */
big_picture.interlaced_frame = in_picture->interlaced_frame;
if(do_interlace_me || do_interlace_dct){
if(top_field_first == -1)
big_picture.top_field_first = in_picture->top_field_first;
else
/* 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;
Michael Niedermayer
committed
if(!me_threshold)
big_picture.pict_type = 0;
// big_picture.pts = AV_NOPTS_VALUE;
big_picture.pts= av_rescale(ost->sync_opts, AV_TIME_BASE*(int64_t)enc->frame_rate_base, enc->frame_rate);
//av_log(NULL, AV_LOG_DEBUG, "%lld -> encoder\n", ost->sync_opts);
ret = avcodec_encode_video(enc,
bit_buffer, bit_buffer_size,
//enc->frame_number = enc->real_pict_num;
pkt.data= bit_buffer;
pkt.size= ret;
if(enc->coded_frame)
pkt.pts= enc->coded_frame->pts;
/*av_log(NULL, AV_LOG_DEBUG, "encoder -> %lld/%lld\n",
pkt.pts != AV_NOPTS_VALUE ? av_rescale(pkt.pts, enc->frame_rate, AV_TIME_BASE*(int64_t)enc->frame_rate_base) : -1,
pkt.dts != AV_NOPTS_VALUE ? av_rescale(pkt.dts, enc->frame_rate, AV_TIME_BASE*(int64_t)enc->frame_rate_base) : -1);*/
if(enc->coded_frame && enc->coded_frame->key_frame)
pkt.flags |= PKT_FLAG_KEY;
av_interleaved_write_frame(s, &pkt);
*frame_size = ret;
//fprintf(stderr,"\nFrame: %3d %3d size: %5d type: %d",
// enc->frame_number-1, enc->real_pict_num, ret,
// enc->pict_type);
/* 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);
snprintf(filename, sizeof(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;
if (enc->codec_type == CODEC_TYPE_VIDEO) {
Fabrice Bellard
committed
frame_number = ost->frame_number;
Michael Niedermayer
committed
fprintf(fvstats, "frame= %5d q= %2.1f ", frame_number, enc->coded_frame->quality/(float)FF_QP2LAMBDA);
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->sync_opts *enc->frame_rate_base / enc->frame_rate;
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)(video_size * 8) / ti1 / 1000.0;
fprintf(fvstats, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ",
(double)video_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) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "q=%2.1f ",
Michael Niedermayer
committed
enc->coded_frame->quality/(float)FF_QP2LAMBDA);
}
Fabrice Bellard
committed
if (!vid && enc->codec_type == CODEC_TYPE_VIDEO) {
frame_number = ost->frame_number;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "frame=%5d q=%2.1f ",
Michael Niedermayer
committed
frame_number, enc->coded_frame ? enc->coded_frame->quality/(float)FF_QP2LAMBDA : 0);
Michael Niedermayer
committed
if(is_last_report)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "L");
Michael Niedermayer
committed
if (enc->flags&CODEC_FLAG_PSNR){
int j;
double error, error_sum=0;
double scale, scale_sum=0;
char type[3]= {'Y','U','V'};
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "PSNR=");
Michael Niedermayer
committed
for(j=0; j<3; j++){
if(is_last_report){
error= enc->error[j];
scale= enc->width*enc->height*255.0*255.0*frame_number;
}else{
error= enc->coded_frame->error[j];
scale= enc->width*enc->height*255.0*255.0;
}
if(j) scale/=4;
error_sum += error;
scale_sum += scale;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%c:%2.2f ", type[j], psnr(error/scale));
Michael Niedermayer
committed
}
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "*:%2.2f ", psnr(error_sum/scale_sum));
Michael Niedermayer
committed
}
Fabrice Bellard
committed
vid = 1;
}
/* compute min output value */
pts = (double)ost->st->pts.val * ost->st->time_base.num / ost->st->time_base.den;
Kareila
committed
if ((pts < ti1) && (pts > 0))
Fabrice Bellard
committed
ti1 = pts;
}
if (ti1 < 0.01)
ti1 = 0.01;
if (verbose || is_last_report) {
bitrate = (double)(total_size * 8) / ti1 / 1000.0;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
Fabrice Bellard
committed
"size=%8.0fkB time=%0.1f bitrate=%6.1fkbits/s",
(double)total_size / 1024, ti1, bitrate);
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " dup=%d drop=%d",
if (verbose >= 0)
fprintf(stderr, "%s \r", buf);
Fabrice Bellard
committed
fflush(stderr);
}
if (is_last_report && verbose >= 0){
int64_t raw= audio_size + video_size + extra_size;
fprintf(stderr, "\n");
fprintf(stderr, "video:%1.0fkB audio:%1.0fkB global headers:%1.0fkB muxing overhead %f%%\n",
video_size/1024.0,
audio_size/1024.0,
extra_size/1024.0,
100.0*(total_size - raw)/raw
);
}
Fabrice Bellard
committed
/* pkt = NULL means EOF (needed to flush decoder buffers) */
static int output_packet(AVInputStream *ist, int ist_index,
AVOutputStream **ost_table, int nb_ostreams,
Wolfram Gloger
committed
const AVPacket *pkt)
Fabrice Bellard
committed
{
AVFormatContext *os;
AVOutputStream *ost;
uint8_t *ptr;
int len, ret, i;
uint8_t *data_buf;
int data_size, got_picture;
AVFrame picture;
void *buffer_to_free;
static int samples_size= 0;
static short *samples= NULL;
if(!pkt){
ist->pts= ist->next_pts; // needed for last packet if vsync=0
} else if (pkt->dts != AV_NOPTS_VALUE) { //FIXME seems redundant, as libavformat does this too
ist->next_pts = ist->pts = pkt->dts;
Fabrice Bellard
committed
} else {
assert(ist->pts == ist->next_pts);
Fabrice Bellard
committed
}
Fabrice Bellard
committed
if (pkt == NULL) {
/* EOF handling */
ptr = NULL;
len = 0;
goto handle_eof;
}
len = pkt->size;
ptr = pkt->data;
while (len > 0) {
handle_eof:
/* decode the packet if needed */
data_buf = NULL; /* fail safe */
data_size = 0;
if (ist->decoding_needed) {
switch(ist->st->codec.codec_type) {
if(pkt)
samples= av_fast_realloc(samples, &samples_size, FFMAX(pkt->size, AVCODEC_MAX_AUDIO_FRAME_SIZE));
Fabrice Bellard
committed
/* 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;
ptr += ret;
len -= ret;
/* Some bug in mpeg audio decoder gives */
/* data_size < 0, it seems they are overflows */
if (data_size <= 0) {
/* no audio frame */
continue;
}
data_buf = (uint8_t *)samples;
Wolfram Gloger
committed
ist->next_pts += ((int64_t)AV_TIME_BASE/2 * data_size) /
(ist->st->codec.sample_rate * ist->st->codec.channels);
Fabrice Bellard
committed
case CODEC_TYPE_VIDEO:
data_size = (ist->st->codec.width * ist->st->codec.height * 3) / 2;
/* XXX: allocate picture correctly */
avcodec_get_frame_defaults(&picture);
Fabrice Bellard
committed
ret = avcodec_decode_video(&ist->st->codec,
&picture, &got_picture, ptr, len);
ist->st->quality= picture.quality;
if (ret < 0)
goto fail_decode;
if (!got_picture) {
/* no picture yet */
goto discard_packet;
}
if (ist->st->codec.frame_rate_base != 0) {
ist->next_pts += ((int64_t)AV_TIME_BASE *
ist->st->codec.frame_rate_base) /
ist->st->codec.frame_rate;
}
len = 0;
break;
default:
goto fail_decode;
}
} else {
switch(ist->st->codec.codec_type) {
case CODEC_TYPE_AUDIO:
ist->next_pts += ((int64_t)AV_TIME_BASE * ist->st->codec.frame_size) /
(ist->st->codec.sample_rate * ist->st->codec.channels);
break;
case CODEC_TYPE_VIDEO:
if (ist->st->codec.frame_rate_base != 0) {
ist->next_pts += ((int64_t)AV_TIME_BASE *
ist->st->codec.frame_rate_base) /
ist->st->codec.frame_rate;
}
break;
}
Fabrice Bellard
committed
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
data_buf = ptr;
data_size = len;
ret = len;
len = 0;
}
buffer_to_free = NULL;
if (ist->st->codec.codec_type == CODEC_TYPE_VIDEO) {
pre_process_video_frame(ist, (AVPicture *)&picture,
&buffer_to_free);
}
/* frame rate emulation */
if (ist->st->codec.rate_emu) {
int64_t pts = av_rescale((int64_t) ist->frame * ist->st->codec.frame_rate_base, 1000000, ist->st->codec.frame_rate);
int64_t now = av_gettime() - ist->start;
if (pts > now)
usleep(pts - now);
ist->frame++;
}
#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) {
int64_t tmp;
tmp = ist->last_ip_pts;
ist->last_ip_pts = ist->frac_pts.val;
ist->frac_pts.val = tmp;
}
}
#endif
/* if output time reached then transcode raw format,
encode packets and output them */
if (start_time == 0 || ist->pts >= start_time)
for(i=0;i<nb_ostreams;i++) {
int frame_size;
ost = ost_table[i];
if (ost->source_index == ist_index) {
os = output_files[ost->file_index];
#if 0
printf("%d: got pts=%0.3f %0.3f\n", i,
(double)pkt->pts / AV_TIME_BASE,
((double)ist->pts / AV_TIME_BASE) -
((double)ost->st->pts.val * ost->st->time_base.num / ost->st->time_base.den));
Fabrice Bellard
committed
#endif
/* set the input output pts pairs */
ost->sync_ipts = (double)(ist->pts + input_files_ts_offset[ist->file_index])/ AV_TIME_BASE;
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:
do_video_out(os, ost, ist, &picture, &frame_size);
video_size += frame_size;
Fabrice Bellard
committed
if (do_vstats && frame_size)
do_video_stats(os, ost, frame_size);
break;
default:
av_abort();
}
} else {
AVFrame avframe; //FIXME/XXX remove this
AVPacket opkt;
av_init_packet(&opkt);
Fabrice Bellard
committed
/* no reencoding needed : output the packet directly */
/* force the input stream PTS */
avcodec_get_frame_defaults(&avframe);
Fabrice Bellard
committed
ost->st->codec.coded_frame= &avframe;
avframe.key_frame = pkt->flags & PKT_FLAG_KEY;
if(ost->st->codec.codec_type == CODEC_TYPE_AUDIO)
audio_size += data_size;
Wolfram Gloger
committed
else if (ost->st->codec.codec_type == CODEC_TYPE_VIDEO) {
video_size += data_size;
Wolfram Gloger
committed
ost->sync_opts++;
}
opkt.stream_index= ost->index;
opkt.data= data_buf;
opkt.size= data_size;
if(pkt->pts != AV_NOPTS_VALUE)
opkt.pts= pkt->pts + input_files_ts_offset[ist->file_index];
else
opkt.pts= AV_NOPTS_VALUE;
opkt.dts= pkt->dts + input_files_ts_offset[ist->file_index];
av_interleaved_write_frame(os, &opkt);
Fabrice Bellard
committed
ost->st->codec.frame_number++;
ost->frame_number++;
}
}
}
av_free(buffer_to_free);
}
discard_packet:
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
if (pkt == NULL) {
/* EOF handling */
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
if (ost->source_index == ist_index) {
AVCodecContext *enc= &ost->st->codec;
os = output_files[ost->file_index];
if(ost->st->codec.codec_type == CODEC_TYPE_AUDIO && enc->frame_size <=1)
continue;
if(ost->st->codec.codec_type == CODEC_TYPE_VIDEO && (os->oformat->flags & AVFMT_RAWPICTURE))
continue;
if (ost->encoding_needed) {
for(;;) {
AVPacket pkt;
av_init_packet(&pkt);
pkt.stream_index= ost->index;
switch(ost->st->codec.codec_type) {
case CODEC_TYPE_AUDIO:
ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, NULL);
audio_size += ret;
pkt.flags |= PKT_FLAG_KEY;
break;
case CODEC_TYPE_VIDEO:
ret = avcodec_encode_video(enc, bit_buffer, bit_buffer_size, NULL);
video_size += ret;
if(enc->coded_frame && enc->coded_frame->key_frame)
pkt.flags |= PKT_FLAG_KEY;
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
}
break;
default:
ret=-1;
}
if(ret<=0)
break;
pkt.data= bit_buffer;
pkt.size= ret;
if(enc->coded_frame)
pkt.pts= enc->coded_frame->pts;
av_interleaved_write_frame(os, &pkt);
}
}
}
}
}
Fabrice Bellard
committed
return 0;
fail_decode:
return -1;
}
/*
* 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);
}
}
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
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);
}
} 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;
Nathan Kurz
committed
break;
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
}
}
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;
if(!codec->codec_tag) 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;
codec->frame_size = icodec->frame_size;
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 ||
icodec->codec_id == CODEC_ID_DTS)) {
/* Special case for 5:1 AC3 and DTS 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;
}
} else {
ost->audio_resample = 1;
ost->audio_resample = 1;
if(ost->audio_resample){
ost->resample = audio_resample_init(codec->channels, icodec->channels,
codec->sample_rate, icodec->sample_rate);
if(!ost->resample){
printf("Can't resample. Aborting.\n");
av_abort();
}
}
ist->decoding_needed = 1;
ost->encoding_needed = 1;
break;
case CODEC_TYPE_VIDEO:
codec->height == icodec->height &&
frame_topBand == 0 &&
frame_bottomBand == 0 &&
frame_leftBand == 0 &&
Todd Kirby
committed
frame_rightBand == 0 &&
frame_padtop == 0 &&
frame_padbottom == 0 &&
frame_padleft == 0 &&
frame_padright == 0)
{
ost->video_resample = 0;
ost->video_crop = 0;
Todd Kirby
committed
ost->video_pad = 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;
Todd Kirby
committed
} else if ((codec->width == icodec->width +
(frame_padleft + frame_padright)) &&
(codec->height == icodec->height +
(frame_padtop + frame_padbottom))) {
ost->video_resample = 0;
ost->video_crop = 0;
ost->video_pad = 1;
ost->padtop = frame_padtop;
ost->padleft = frame_padleft;
ost->padbottom = frame_padbottom;
ost->padright = frame_padright;
Michael Niedermayer
committed
if( avpicture_alloc( (AVPicture*)&ost->pict_tmp, PIX_FMT_YUV420P,
Todd Kirby
committed
codec->width, codec->height ) )
goto fail;
ost->video_crop = 0; // cropping is handled as part of resample
Michael Niedermayer
committed
if( avpicture_alloc( (AVPicture*)&ost->pict_tmp, PIX_FMT_YUV420P,
codec->width, codec->height ) )
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,
Todd Kirby
committed
frame_leftBand, frame_rightBand,
frame_padtop, frame_padbottom,
frame_padleft, frame_padright);
ost->padtop = frame_padtop;
ost->padleft = frame_padleft;
ost->padbottom = frame_padbottom;
ost->padright = frame_padright;
}
ost->encoding_needed = 1;
ist->decoding_needed = 1;
break;
default:
av_abort();
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
/* 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);
}
Gael Chardon
committed
size = fread(logbuffer, 1, size, f);
fclose(f);
logbuffer[size] = '\0';
codec->stats_in = logbuffer;
if(codec->codec_type == CODEC_TYPE_VIDEO){
int size= codec->width * codec->height;
bit_buffer_size= FFMAX(bit_buffer_size, 4*size);
}
if (!bit_buffer)
bit_buffer = av_malloc(bit_buffer_size);
if (!bit_buffer)
goto fail;
/* 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 */
if (verbose >= 0) {
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);
}
}
/* 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);
}
extra_size += ost->st->codec.extradata_size;
}
}
/* 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;
}
}
/* init pts */
for(i=0;i<nb_istreams;i++) {
ist = ist_table[i];
ist->next_pts = ist->st->start_time;
if(ist->next_pts == AV_NOPTS_VALUE)
ist->next_pts=0;
/* compute buffer size max (should use a complete heuristic) */
for(i=0;i<nb_input_files;i++) {
file_table[i].buffer_size_max = 2048;
}
Patrice Bensoussan
committed
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
/* set meta data information from input file if required */
for (i=0;i<nb_meta_data_maps;i++) {
AVFormatContext *out_file;
AVFormatContext *in_file;
int out_file_index = meta_data_maps[i].out_file;
int in_file_index = meta_data_maps[i].in_file;
if ( out_file_index < 0 || out_file_index >= nb_output_files ) {
fprintf(stderr, "Invalid output file index %d map_meta_data(%d,%d)\n", out_file_index, out_file_index, in_file_index);
ret = -EINVAL;
goto fail;
}
if ( in_file_index < 0 || in_file_index >= nb_input_files ) {
fprintf(stderr, "Invalid input file index %d map_meta_data(%d,%d)\n", in_file_index, out_file_index, in_file_index);
ret = -EINVAL;
goto fail;
}
out_file = output_files[out_file_index];
in_file = input_files[in_file_index];
strcpy(out_file->title, in_file->title);
strcpy(out_file->author, in_file->author);
strcpy(out_file->copyright, in_file->copyright);
strcpy(out_file->comment, in_file->comment);
strcpy(out_file->album, in_file->album);
out_file->year = in_file->year;
out_file->track = in_file->track;
strcpy(out_file->genre, in_file->genre);
}
/* 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 parameters ?)\n", i);
ret = -EINVAL;
goto fail;
}
#ifndef CONFIG_WIN32
if ( !using_stdin && verbose >= 0) {
fprintf(stderr, "Press [q] to stop encoding\n");
Leon van Stuivenberg
committed
url_set_interrupt_cb(decode_interrupt_cb);
}
#endif
term_init();
stream_no_data = 0;
key = -1;
for(; received_sigterm == 0;) {
Patrice Bensoussan
committed
double ipts_min;
double opts_min;
Patrice Bensoussan
committed
ipts_min= 1e100;
opts_min= 1e100;
/* if 'q' pressed, exits */
if (!using_stdin) {
Leon van Stuivenberg
committed
if (q_pressed)
break;
/* 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
for(i=0;i<nb_ostreams;i++) {
Fabrice Bellard
committed
ost = ost_table[i];
os = output_files[ost->file_index];
ist = ist_table[ost->source_index];
if(ost->st->codec.codec_type == CODEC_TYPE_VIDEO)
opts = (double)ost->sync_opts * ost->st->codec.frame_rate_base / ost->st->codec.frame_rate;
else
opts = (double)ost->st->pts.val * ost->st->time_base.num / ost->st->time_base.den;
ipts = (double)ist->pts;
if (!file_table[ist->file_index].eof_reached){
if(ipts < ipts_min) {
ipts_min = ipts;
if(input_sync ) file_index = ist->file_index;
}
if(opts < opts_min) {
opts_min = opts;
if(!input_sync) file_index = ist->file_index;
}
if(ost->frame_number >= max_frames[ost->st->codec.codec_type]){
file_index= -1;
break;
}
if (file_index < 0) {
Fabrice Bellard
committed
}
if (recording_time > 0 && opts_min >= (recording_time / 1000000.0))
Fabrice Bellard
committed
/* read a frame from it and output it in the fifo */
if (av_read_frame(is, &pkt) < 0) {
if (!pkt.size) {
stream_no_data = is;
} else {
stream_no_data = 0;
}
if (do_pkt_dump) {
av_pkt_dump(stdout, &pkt, do_hex_dump);
Fabrice Bellard
committed
}
/* 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;
// fprintf(stderr, "next:%lld dts:%lld off:%lld %d\n", ist->next_pts, pkt.dts, input_files_ts_offset[ist->file_index], ist->st->codec.codec_type);
if (pkt.dts != AV_NOPTS_VALUE) {
int64_t delta= pkt.dts - ist->next_pts;
if(ABS(delta) > 10LL*AV_TIME_BASE && !copy_ts){
input_files_ts_offset[ist->file_index]-= delta;
if (verbose > 2)
fprintf(stderr, "timestamp discontinuity %lld, new offset= %lld\n", delta, input_files_ts_offset[ist->file_index]);
for(i=0; i<file_table[file_index].nb_streams; i++){
int index= file_table[file_index].ist_index + i;
ist_table[index]->next_pts += delta;
//fprintf(stderr,"read #%d.%d size=%d\n", ist->file_index, ist->index, pkt.size);
Fabrice Bellard
committed
if (output_packet(ist, ist_index, ost_table, nb_ostreams, &pkt) < 0) {
if (verbose >= 0)
fprintf(stderr, "Error while decoding stream #%d.%d\n",
ist->file_index, ist->index);
Fabrice Bellard
committed
av_free_packet(&pkt);
goto redo;
Fabrice Bellard
committed
Fabrice Bellard
committed
/* dump report by using the output first video and audio streams */
print_report(output_files, ost_table, nb_ostreams, 0);
Fabrice Bellard
committed
/* at the end of stream, we must flush the decoder buffers */
for(i=0;i<nb_istreams;i++) {
ist = ist_table[i];
if (ist->decoding_needed) {
output_packet(ist, i, ost_table, nb_ostreams, NULL);
}
}
term_exit();
Michael Niedermayer
committed
/* write the trailer if needed and close file */
for(i=0;i<nb_output_files;i++) {
os = output_files[i];
av_write_trailer(os);
}
/* dump report by using the first video and audio streams */
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);
}
}
/* finished ! */
ret = 0;
fail1:
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);
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
}
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")) {
pgmyuv_compatibility_hack=1;
Michael Niedermayer
committed
// opt_image_format(arg);
Fabrice Bellard
committed
}
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) * 8*1024;
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);
}
Michael Niedermayer
committed
static void opt_me_threshold(const char *arg)
{
me_threshold = atoi(arg);
}
Michael Niedermayer
committed
static void opt_mb_threshold(const char *arg)
{
mb_threshold = 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)
Wolfgang Hesseler
committed
static void opt_vismv(const char *arg)
{
debug_mv = atoi(arg);
}
static void opt_verbose(const char *arg)
{
verbose = atoi(arg);
av_log_set_level(atoi(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) {
Loading
Loading full blame...