Newer
Older
Diego Biurrun
committed
* This file is part of FFmpeg.
*
* FFmpeg 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
Diego Biurrun
committed
* version 2.1 of the License, or (at your option) any later version.
Diego Biurrun
committed
* FFmpeg 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
Diego Biurrun
committed
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Diego Biurrun
committed
#include "framehook.h"
#include "fifo.h"
#include "avstring.h"
#ifdef __MINGW32__
#include <conio.h>
#else
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.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;
int sync_file_index;
int sync_stream_index;
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);
static int opt_default(const char *opt, const char *arg);
#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;
static int frame_width = 0;
static int frame_height = 0;
static float frame_aspect_ratio = 0;
static enum PixelFormat frame_pix_fmt = PIX_FMT_NONE;
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;
Fabrice Bellard
committed
static int max_frames[4] = {INT_MAX, INT_MAX, INT_MAX, INT_MAX};
static AVRational frame_rate = (AVRational) {25,1};
Michael Niedermayer
committed
static float video_qscale = 0;
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";
Michael Niedermayer
committed
static int me_method = ME_EPZS;
static int video_discard = 0;
static int do_deinterlace = 0;
Michael Niedermayer
committed
static int me_threshold = 0;
static int loop_input = 0;
static int loop_output = AVFMT_NOOUTPUTLOOP;
static int intra_only = 0;
static int audio_sample_rate = 44100;
#define QSCALE_NONE -99999
static float audio_qscale = QSCALE_NONE;
static int audio_disable = 0;
static int audio_channels = 1;
static int audio_codec_id = CODEC_ID_NONE;
Fabrice Bellard
committed
static char *audio_language = NULL;
static int subtitle_codec_id = CODEC_ID_NONE;
static char *subtitle_language = NULL;
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 char *str_album = NULL;
static int do_hex_dump = 0;
static int do_pkt_dump = 0;
static int do_psnr = 0;
static int do_pass = 0;
static char *pass_logfilename = NULL;
static int audio_stream_copy = 0;
static int video_stream_copy = 0;
Fabrice Bellard
committed
static int subtitle_stream_copy = 0;
static int video_sync_method= 1;
static int audio_sync_method= 0;
Calcium
committed
static int opt_shortest = 0; //
Michael Niedermayer
committed
static int video_global_header = 0;
static char *vstats_filename;
static FILE *fvstats;
Max Krasnyansky
committed
static int rate_emu = 0;
Fabrice Bellard
committed
static int video_channel = 0;
static char *video_standard;
Fabrice Bellard
committed
Michael Niedermayer
committed
static int audio_volume = 256;
static int using_stdin = 0;
static int using_vhook = 0;
static int verbose = 1;
Leon van Stuivenberg
committed
static int q_pressed = 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 uint64_t limit_filesize = 0; //
static int pgmyuv_compatibility_hack=0;
static int dts_delta_threshold = 10;
static int sws_flags = SWS_BICUBIC;
static const char **opt_names;
static int opt_name_count;
static AVCodecContext *avctx_opts[CODEC_TYPE_NB];
static AVFormatContext *avformat_opts;
static struct SwsContext *sws_opts;
static int64_t timer_start;
Michael Niedermayer
committed
static AVBitStreamFilterContext *video_bitstream_filters=NULL;
static AVBitStreamFilterContext *audio_bitstream_filters=NULL;
static AVBitStreamFilterContext *bitstream_filters[MAX_FILES][MAX_STREAMS];
#define DEFAULT_PASS_LOGFILENAME "ffmpeg2pass"
struct AVInputStream;
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 */
struct AVInputStream *sync_ist; /* input stream to sync against */
int64_t sync_opts; /* output frame counter, could be changed to some true timestamp */ //FIXME look at frame_number
int video_resample;
Michael Niedermayer
committed
AVFrame pict_tmp; /* temporary image for resampling */
struct SwsContext *img_resample_ctx; /* for image resampling */
int resample_height;
int video_crop;
int topBand; /* cropping area sizes */
int leftBand;
int video_pad;
Todd Kirby
committed
int padtop; /* padding area sizes */
int padbottom;
int padleft;
int padright;
/* audio only */
int audio_resample;
ReSampleContext *resample; /* for audio resampling */
AVFifoBuffer 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 nb_streams; /* nb streams we are aware of */
#ifndef __MINGW32__
/* init terminal so that we can grab keys */
static struct termios oldtty;
Roumen Petrov
committed
static volatile sig_atomic_t received_sigterm = 0;
static void
sigterm_handler(int sig)
{
received_sigterm = sig;
term_exit();
}
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;
signal(SIGQUIT, sigterm_handler); /* Quit (POSIX). */
#endif
Roumen Petrov
committed
signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */
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)
{
#ifdef __MINGW32__
if(kbhit())
return(getch());
#else
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');
}
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;
Alex Beregszaszi
committed
// FIXME: a more elegant solution is needed
st = av_mallocz(sizeof(AVStream));
Alex Beregszaszi
committed
st->codec = avcodec_alloc_context();
memcpy(st->codec, ic->streams[i]->codec, sizeof(AVCodecContext));
s->streams[i] = st;
}
av_close_input_file(ic);
return 0;
}
static double
get_sync_ipts(const AVOutputStream *ost)
{
const AVInputStream *ist = ost->sync_ist;
return (double)(ist->pts + input_files_ts_offset[ist->file_index] - start_time)/AV_TIME_BASE;
}
Michael Niedermayer
committed
static void write_frame(AVFormatContext *s, AVPacket *pkt, AVCodecContext *avctx, AVBitStreamFilterContext *bsfc){
while(bsfc){
AVPacket new_pkt= *pkt;
int a= av_bitstream_filter_filter(bsfc, avctx, NULL,
&new_pkt.data, &new_pkt.size,
pkt->data, pkt->size,
pkt->flags & PKT_FLAG_KEY);
if(a){
av_free_packet(pkt);
new_pkt.destruct= av_destruct_packet;
}
*pkt= new_pkt;
bsfc= bsfc->next;
}
av_interleaved_write_frame(s, pkt);
}
Fabrice Bellard
committed
#define MAX_AUDIO_PACKET_SIZE (128 * 1024)
static void do_audio_out(AVFormatContext *s,
AVOutputStream *ost,
Sylvain Corré
committed
static uint8_t *audio_buf = NULL;
static uint8_t *audio_out = NULL;
Sylvain Corré
committed
Michael Niedermayer
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 ! */
double delta = get_sync_ipts(ost) * enc->sample_rate - ost->sync_opts
- av_fifo_size(&ost->fifo)/(ost->st->codec->channels * 2);
Michael Niedermayer
committed
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);
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= av_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:%"PRId64" ipts:%"PRId64" fifo:%d\n", delta, -1, ost->sync_opts, (int64_t)(get_sync_ipts(ost) * enc->sample_rate), av_fifo_size(&ost->fifo)/(ost->st->codec->channels * 2));
av_resample_compensate(*(struct AVResampleContext**)ost->resample, comp, enc->sample_rate);
}
ost->sync_opts= lrintf(get_sync_ipts(ost) * enc->sample_rate)
- av_fifo_size(&ost->fifo)/(ost->st->codec->channels * 2); //FIXME wrong
size_out = audio_resample(ost->resample,
Michael Niedermayer
committed
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) {
av_fifo_write(&ost->fifo, buftmp, size_out);
while (av_fifo_read(&ost->fifo, audio_buf, frame_bytes) == 0) {
AVPacket pkt;
av_init_packet(&pkt);
ret = avcodec_encode_audio(enc, audio_out, audio_out_size,
(short *)audio_buf);
audio_size += ret;
pkt.stream_index= ost->index;
pkt.data= audio_out;
pkt.size= ret;
if(enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)
pkt.pts= av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
Michael Niedermayer
committed
write_frame(s, &pkt, ost->st->codec, bitstream_filters[ost->file_index][pkt.stream_index]);
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_S32LE:
case CODEC_ID_PCM_S32BE:
case CODEC_ID_PCM_U32LE:
case CODEC_ID_PCM_U32BE:
size_out = size_out << 1;
break;
case CODEC_ID_PCM_S24LE:
case CODEC_ID_PCM_S24BE:
case CODEC_ID_PCM_U24LE:
case CODEC_ID_PCM_U24BE:
case CODEC_ID_PCM_S24DAUD:
size_out = size_out / 2 * 3;
break;
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,
audio_size += ret;
pkt.stream_index= ost->index;
pkt.data= audio_out;
pkt.size= ret;
if(enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)
pkt.pts= av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
Michael Niedermayer
committed
write_frame(s, &pkt, ost->st->codec, bitstream_filters[ost->file_index][pkt.stream_index]);
static void pre_process_video_frame(AVInputStream *ist, AVPicture *picture, void **bufp)
{
AVCodecContext *dec;
AVPicture *picture2;
AVPicture picture_tmp;
Michael Niedermayer
committed
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(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 {
Panagiotis Issaris
committed
av_picture_copy(picture2, picture, dec->pix_fmt, dec->width, dec->height);
} else {
picture2 = picture;
}
frame_hook_process(picture2, dec->pix_fmt, dec->width, dec->height,
1000000 * ist->pts / AV_TIME_BASE);
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_subtitle_out(AVFormatContext *s,
AVOutputStream *ost,
Fabrice Bellard
committed
AVInputStream *ist,
AVSubtitle *sub,
int64_t pts)
{
static uint8_t *subtitle_out = NULL;
int subtitle_out_max_size = 65536;
int subtitle_out_size, nb, i;
AVCodecContext *enc;
AVPacket pkt;
if (pts == AV_NOPTS_VALUE) {
fprintf(stderr, "Subtitle packets must have a pts\n");
return;
}
Michael Niedermayer
committed
enc = ost->st->codec;
Fabrice Bellard
committed
if (!subtitle_out) {
subtitle_out = av_malloc(subtitle_out_max_size);
}
/* Note: DVB subtitle need one packet to draw them and one other
packet to clear them */
/* XXX: signal it in the codec context ? */
if (enc->codec_id == CODEC_ID_DVB_SUBTITLE)
nb = 2;
else
nb = 1;
for(i = 0; i < nb; i++) {
subtitle_out_size = avcodec_encode_subtitle(enc, subtitle_out,
Fabrice Bellard
committed
subtitle_out_max_size, sub);
Fabrice Bellard
committed
av_init_packet(&pkt);
pkt.stream_index = ost->index;
pkt.data = subtitle_out;
pkt.size = subtitle_out_size;
pkt.pts = av_rescale_q(av_rescale_q(pts, ist->st->time_base, AV_TIME_BASE_Q) + input_files_ts_offset[ist->file_index], AV_TIME_BASE_Q, ost->st->time_base);
if (enc->codec_id == CODEC_ID_DVB_SUBTITLE) {
/* XXX: the pts correction is handled here. Maybe handling
it in the codec would be better */
if (i == 0)
pkt.pts += 90 * sub->start_display_time;
else
pkt.pts += 90 * sub->end_display_time;
}
Michael Niedermayer
committed
write_frame(s, &pkt, ost->st->codec, bitstream_filters[ost->file_index][pkt.stream_index]);
Fabrice Bellard
committed
}
}
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,
Fabrice Bellard
committed
int nb_frames, i, ret;
AVFrame *final_picture, *formatted_picture, *resampling_dst, *padding_src;
AVFrame picture_crop_temp, picture_pad_temp;
AVCodecContext *enc, *dec;
Michael Niedermayer
committed
avcodec_get_frame_defaults(&picture_crop_temp);
avcodec_get_frame_defaults(&picture_pad_temp);
Michael Niedermayer
committed
Michael Niedermayer
committed
enc = ost->st->codec;
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 = get_sync_ipts(ost) / av_q2d(enc->time_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:%"PRId64", 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);
ost->sync_opts= lrintf(get_sync_ipts(ost) / av_q2d(enc->time_base));
nb_frames= FFMIN(nb_frames, max_frames[CODEC_TYPE_VIDEO] - ost->frame_number);
if (ost->video_crop) {
Panagiotis Issaris
committed
if (av_picture_crop((AVPicture *)&picture_crop_temp, (AVPicture *)in_picture, dec->pix_fmt, ost->topBand, ost->leftBand) < 0) {
av_log(NULL, AV_LOG_ERROR, "error cropping picture\n");
}
formatted_picture = &picture_crop_temp;
} else {
formatted_picture = in_picture;
}
final_picture = formatted_picture;
padding_src = formatted_picture;
resampling_dst = &ost->pict_tmp;
if (ost->video_pad) {
final_picture = &ost->pict_tmp;
if (ost->video_resample) {
Panagiotis Issaris
committed
if (av_picture_crop((AVPicture *)&picture_pad_temp, (AVPicture *)final_picture, enc->pix_fmt, ost->padtop, ost->padleft) < 0) {
av_log(NULL, AV_LOG_ERROR, "error padding picture\n");
}
resampling_dst = &picture_pad_temp;
}
}
padding_src = NULL;
final_picture = &ost->pict_tmp;
sws_scale(ost->img_resample_ctx, formatted_picture->data, formatted_picture->linesize,
0, ost->resample_height, resampling_dst->data, resampling_dst->linesize);
if (ost->video_pad) {
Panagiotis Issaris
committed
av_picture_pad((AVPicture*)final_picture, (AVPicture *)padding_src,
enc->height, enc->width, enc->pix_fmt,
ost->padtop, ost->padbottom, ost->padleft, ost->padright, padcolor);
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 && enc->coded_frame->pts != AV_NOPTS_VALUE)
pkt.pts= av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
if(dec->coded_frame && dec->coded_frame->key_frame)
pkt.flags |= PKT_FLAG_KEY;
Michael Niedermayer
committed
write_frame(s, &pkt, ost->st->codec, bitstream_filters[ost->file_index][pkt.stream_index]);
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(avctx_opts[CODEC_TYPE_VIDEO]->flags & (CODEC_FLAG_INTERLACED_DCT|CODEC_FLAG_INTERLACED_ME)){
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= ost->sync_opts;
// big_picture.pts= av_rescale(ost->sync_opts, AV_TIME_BASE*(int64_t)enc->time_base.num, enc->time_base.den);
//av_log(NULL, AV_LOG_DEBUG, "%"PRId64" -> encoder\n", ost->sync_opts);
ret = avcodec_encode_video(enc,
bit_buffer, bit_buffer_size,
if (ret == -1) {
fprintf(stderr, "Video encoding failed\n");
exit(1);
}
//enc->frame_number = enc->real_pict_num;
pkt.data= bit_buffer;
if(enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)
pkt.pts= av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
/*av_log(NULL, AV_LOG_DEBUG, "encoder -> %"PRId64"/%"PRId64"\n",
pkt.pts != AV_NOPTS_VALUE ? av_rescale(pkt.pts, enc->time_base.den, AV_TIME_BASE*(int64_t)enc->time_base.num) : -1,
pkt.dts != AV_NOPTS_VALUE ? av_rescale(pkt.dts, enc->time_base.den, AV_TIME_BASE*(int64_t)enc->time_base.num) : -1);*/
if(enc->coded_frame && enc->coded_frame->key_frame)
pkt.flags |= PKT_FLAG_KEY;
Michael Niedermayer
committed
write_frame(s, &pkt, ost->st->codec, bitstream_filters[ost->file_index][pkt.stream_index]);
*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++;
static double psnr(double d){
if(d==0) return INFINITY;
static void do_video_stats(AVFormatContext *os, AVOutputStream *ost,
Fabrice Bellard
committed
int frame_size)
{
AVCodecContext *enc;
int frame_number;
double ti1, bitrate, avg_bitrate;
/* this is executed just the first time do_video_stats is called */
Benoit Fouet
committed
if (!fvstats) {
fvstats = fopen(vstats_filename, "w");
Benoit Fouet
committed
if (!fvstats) {
perror("fopen");
exit(1);
}
}
Michael Niedermayer
committed
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 = ost->sync_opts * av_q2d(enc->time_base);
if (ti1 < 0.01)
ti1 = 0.01;
bitrate = (frame_size * 8) / av_q2d(enc->time_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;
static int qp_histogram[52];
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;
Fabrice Bellard
committed
if ((cur_time - last_time) < 500000)
return;
last_time = cur_time;
}
Fabrice Bellard
committed
oc = output_files[0];
total_size = url_fsize(&oc->pb);
if(total_size<0) // FIXME improve url_fsize() so it works with non seekable output too
total_size= url_ftell(&oc->pb);
Fabrice Bellard
committed
buf[0] = '\0';
ti1 = 1e10;
vid = 0;
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
os = output_files[ost->file_index];
Michael Niedermayer
committed
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) {
float t = (av_gettime()-timer_start) / 1000000.0;
Fabrice Bellard
committed
frame_number = ost->frame_number;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "frame=%5d fps=%3d q=%3.1f ",
frame_number, (t>1)?(int)(frame_number/t+0.5) : 0,
enc->coded_frame ? enc->coded_frame->quality/(float)FF_QP2LAMBDA : -1);
Michael Niedermayer
committed
if(is_last_report)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "L");
if(qp_hist && enc->coded_frame){
int j;
int qp= lrintf(enc->coded_frame->quality/(float)FF_QP2LAMBDA);
if(qp>=0 && qp<sizeof(qp_histogram)/sizeof(int))
qp_histogram[qp]++;
for(j=0; j<32; j++)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%X", (int)lrintf(log(qp_histogram[j]+1)/log(2)));
}
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);
if (verbose > 1)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " dup=%d drop=%d",
nb_frames_dup, nb_frames_drop);
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 unsigned int samples_size= 0;
static short *samples= NULL;
Fabrice Bellard
committed
AVSubtitle subtitle, *subtitle_to_free;
int got_subtitle;
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 = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
Fabrice Bellard
committed
} else {
Michael Niedermayer
committed
// 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;
Fabrice Bellard
committed
subtitle_to_free = NULL;
Fabrice Bellard
committed
if (ist->decoding_needed) {
Michael Niedermayer
committed
switch(ist->st->codec->codec_type) {
Baptiste Coudurier
committed
samples= av_fast_realloc(samples, &samples_size, FFMAX(pkt->size*sizeof(*samples), AVCODEC_MAX_AUDIO_FRAME_SIZE));
Fabrice Bellard
committed
/* XXX: could avoid copy if PCM 16 bits with same
endianness as CPU */
ret = avcodec_decode_audio2(ist->st->codec, samples, &data_size,
Fabrice Bellard
committed
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;
ist->next_pts += ((int64_t)AV_TIME_BASE/2 * data_size) /
Michael Niedermayer
committed
(ist->st->codec->sample_rate * ist->st->codec->channels);
Fabrice Bellard
committed
case CODEC_TYPE_VIDEO:
Michael Niedermayer
committed
data_size = (ist->st->codec->width * ist->st->codec->height * 3) / 2;
Fabrice Bellard
committed
/* XXX: allocate picture correctly */
avcodec_get_frame_defaults(&picture);
ret = avcodec_decode_video(ist->st->codec,
Fabrice Bellard
committed
&picture, &got_picture, ptr, len);
ist->st->quality= picture.quality;
Fabrice Bellard
committed
goto fail_decode;
if (!got_picture) {
/* no picture yet */
goto discard_packet;
}
Michael Niedermayer
committed
if (ist->st->codec->time_base.num != 0) {
ist->next_pts += ((int64_t)AV_TIME_BASE *
Michael Niedermayer
committed
ist->st->codec->time_base.num) /
ist->st->codec->time_base.den;
Fabrice Bellard
committed
}
len = 0;
break;
Fabrice Bellard
committed
case CODEC_TYPE_SUBTITLE:
ret = avcodec_decode_subtitle(ist->st->codec,
Fabrice Bellard
committed
&subtitle, &got_subtitle, ptr, len);
if (ret < 0)
Fabrice Bellard
committed
goto fail_decode;
Fabrice Bellard
committed
if (!got_subtitle) {
goto discard_packet;
Fabrice Bellard
committed
}
Fabrice Bellard
committed
subtitle_to_free = &subtitle;
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->time_base.num != 0) {
ist->next_pts += ((int64_t)AV_TIME_BASE *
ist->st->codec->time_base.num) /
ist->st->codec->time_base.den;
}
break;
Fabrice Bellard
committed
}
data_buf = ptr;
data_size = len;
ret = len;
len = 0;
}
Fabrice Bellard
committed
buffer_to_free = NULL;
if (ist->st->codec->codec_type == CODEC_TYPE_VIDEO) {
pre_process_video_frame(ist, (AVPicture *)&picture,
&buffer_to_free);
}
Fabrice Bellard
committed
// preprocess audio (volume)
if (ist->st->codec->codec_type == CODEC_TYPE_AUDIO) {
if (audio_volume != 256) {
short *volp;
volp = samples;
for(i=0;i<(data_size / sizeof(short));i++) {
int v = ((*volp) * audio_volume + 128) >> 8;
if (v < -32768) v = -32768;
if (v > 32767) v = 32767;
*volp++ = v;
}
/* frame rate emulation */
if (ist->st->codec->rate_emu) {
int64_t pts = av_rescale((int64_t) ist->frame * ist->st->codec->time_base.num, 1000000, ist->st->codec->time_base.den);
int64_t now = av_gettime() - ist->start;
if (pts > now)
usleep(pts - now);
Fabrice Bellard
committed
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) {
int64_t tmp;
tmp = ist->last_ip_pts;
ist->last_ip_pts = ist->frac_pts.val;
ist->frac_pts.val = tmp;
Fabrice Bellard
committed
}
}
Fabrice Bellard
committed
#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;
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=%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] - start_time)/ AV_TIME_BASE;
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;
if (vstats_filename && frame_size)
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
do_video_stats(os, ost, frame_size);
break;
case CODEC_TYPE_SUBTITLE:
do_subtitle_out(os, ost, ist, &subtitle,
pkt->pts);
break;
default:
av_abort();
}
} else {
AVFrame avframe; //FIXME/XXX remove this
AVPacket opkt;
av_init_packet(&opkt);
/* no reencoding needed : output the packet directly */
/* force the input stream PTS */
avcodec_get_frame_defaults(&avframe);
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;
else if (ost->st->codec->codec_type == CODEC_TYPE_VIDEO) {
video_size += data_size;
ost->sync_opts++;
}
opkt.stream_index= ost->index;
if(pkt->pts != AV_NOPTS_VALUE)
opkt.pts= av_rescale_q(av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q) + input_files_ts_offset[ist->file_index], AV_TIME_BASE_Q, ost->st->time_base);
else
opkt.pts= AV_NOPTS_VALUE;
{
int64_t dts;
if (pkt->dts == AV_NOPTS_VALUE)
dts = ist->next_pts;
dts= av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
opkt.dts= av_rescale_q(dts + input_files_ts_offset[ist->file_index], AV_TIME_BASE_Q, ost->st->time_base);
Fabrice Bellard
committed
}
opkt.flags= pkt->flags;
//FIXME remove the following 2 lines they shall be replaced by the bitstream filters
if(av_parser_change(ist->st->parser, ost->st->codec, &opkt.data, &opkt.size, data_buf, data_size, pkt->flags & PKT_FLAG_KEY))
opkt.destruct= av_destruct_packet;
write_frame(os, &opkt, ost->st->codec, bitstream_filters[ost->file_index][pkt->stream_index]);
ost->st->codec->frame_number++;
ost->frame_number++;
av_free_packet(&opkt);
Fabrice Bellard
committed
}
}
}
av_free(buffer_to_free);
/* XXX: allocate the subtitles in the codec ? */
if (subtitle_to_free) {
if (subtitle_to_free->rects != NULL) {
for (i = 0; i < subtitle_to_free->num_rects; i++) {
av_free(subtitle_to_free->rects[i].bitmap);
av_free(subtitle_to_free->rects[i].rgba_palette);
av_freep(&subtitle_to_free->rects);
Fabrice Bellard
committed
}
subtitle_to_free->num_rects = 0;
subtitle_to_free = NULL;
Fabrice Bellard
committed
}
}
Fabrice Bellard
committed
discard_packet:
if (pkt == NULL) {
/* EOF handling */
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
if (ost->source_index == ist_index) {
Michael Niedermayer
committed
AVCodecContext *enc= ost->st->codec;
os = output_files[ost->file_index];
Michael Niedermayer
committed
if(ost->st->codec->codec_type == CODEC_TYPE_AUDIO && enc->frame_size <=1)
Michael Niedermayer
committed
if(ost->st->codec->codec_type == CODEC_TYPE_VIDEO && (os->oformat->flags & AVFMT_RAWPICTURE))
continue;
if (ost->encoding_needed) {
for(;;) {
AVPacket pkt;
int fifo_bytes;
av_init_packet(&pkt);
pkt.stream_index= ost->index;
Michael Niedermayer
committed
switch(ost->st->codec->codec_type) {
fifo_bytes = av_fifo_size(&ost->fifo);
ret = 0;
/* encode any samples remaining in fifo */
if(fifo_bytes > 0 && enc->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME) {
int fs_tmp = enc->frame_size;
enc->frame_size = fifo_bytes / (2 * enc->channels);
if(av_fifo_read(&ost->fifo, (uint8_t *)samples, fifo_bytes) == 0) {
ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, samples);
}
enc->frame_size = fs_tmp;
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;
}
pkt.data= bit_buffer;
if(enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)
pkt.pts= av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
Michael Niedermayer
committed
write_frame(os, &pkt, ost->st->codec, bitstream_filters[ost->file_index][pkt.stream_index]);
}
}
}
}
}
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;
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
Michael Niedermayer
committed
if (ist->st->codec->rate_emu) {
Max Krasnyansky
committed
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];
if (!os->nb_streams) {
fprintf(stderr, "Output file does not contain any stream\n");
exit(1);
}
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;
Brian Foley
committed
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);
}
fi = stream_maps[i].sync_file_index;
si = stream_maps[i].sync_stream_index;
if (fi < 0 || fi > nb_input_files - 1 ||
si < 0 || si > file_table[fi].nb_streams - 1) {
fprintf(stderr,"Could not find sync stream #%d.%d\n", fi, si);
exit(1);
}
Brian Foley
committed
}
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 +
Brian Foley
committed
/* Sanity check that the stream types match */
Michael Niedermayer
committed
if (ist_table[ost->source_index]->st->codec->codec_type != ost->st->codec->codec_type) {
Brian Foley
committed
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];
Michael Niedermayer
committed
ist->st->codec->codec_type == ost->st->codec->codec_type) {
Nathan Kurz
committed
break;
if (!found) {
/* try again and reuse existing stream */
for(j=0;j<nb_istreams;j++) {
ist = ist_table[j];
Michael Niedermayer
committed
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;
ost->sync_ist = (nb_stream_maps > 0) ?
ist_table[file_table[stream_maps[n-1].sync_file_index].ist_index +
stream_maps[n-1].sync_stream_index] : ist;
}
}
/* 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];
Michael Niedermayer
committed
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;
codec->extradata= icodec->extradata;
codec->extradata_size= icodec->extradata_size;
Michael Niedermayer
committed
if(av_q2d(icodec->time_base) > av_q2d(ist->st->time_base) && av_q2d(ist->st->time_base) < 1.0/1000)
codec->time_base = icodec->time_base;
else
codec->time_base = ist->st->time_base;
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:
Matthijs Douze
committed
if(using_vhook) {
fprintf(stderr,"-vcodec copy and -vhook are incompatible (frames are not decoded)\n");
exit(1);
}
codec->pix_fmt = icodec->pix_fmt;
codec->width = icodec->width;
codec->height = icodec->height;
codec->has_b_frames = icodec->has_b_frames;
break;
Fabrice Bellard
committed
case CODEC_TYPE_SUBTITLE:
break;
default:
av_abort();
}
} else {
switch(codec->codec_type) {
case CODEC_TYPE_AUDIO:
if (av_fifo_init(&ost->fifo, 2 * MAX_AUDIO_PACKET_SIZE))
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;
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:
ost->video_crop = ((frame_leftBand + frame_rightBand + frame_topBand + frame_bottomBand) != 0);
ost->video_pad = ((frame_padleft + frame_padright + frame_padtop + frame_padbottom) != 0);
ost->video_resample = ((codec->width != icodec->width -
(frame_leftBand + frame_rightBand) +
(frame_padleft + frame_padright)) ||
(codec->height != icodec->height -
(frame_topBand + frame_bottomBand) +
(frame_padtop + frame_padbottom)) ||
(codec->pix_fmt != icodec->pix_fmt));
if (ost->video_crop) {
ost->topBand = frame_topBand;
ost->leftBand = frame_leftBand;
}
if (ost->video_pad) {
Todd Kirby
committed
ost->padtop = frame_padtop;
ost->padleft = frame_padleft;
ost->padbottom = frame_padbottom;
ost->padright = frame_padright;
if (!ost->video_resample) {
avcodec_get_frame_defaults(&ost->pict_tmp);
if( avpicture_alloc( (AVPicture*)&ost->pict_tmp, codec->pix_fmt,
codec->width, codec->height ) )
goto fail;
}
}
if (ost->video_resample) {
if( avpicture_alloc( (AVPicture*)&ost->pict_tmp, codec->pix_fmt,
codec->width, codec->height ) ) {
fprintf(stderr, "Cannot allocate temp picture, check pix fmt\n");
exit(1);
if (ENABLE_SWSCALER)
sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
ost->img_resample_ctx = sws_getContext(
icodec->width - (frame_leftBand + frame_rightBand),
icodec->height - (frame_topBand + frame_bottomBand),
icodec->pix_fmt,
codec->width - (frame_padleft + frame_padright),
codec->height - (frame_padtop + frame_padbottom),
codec->pix_fmt,
sws_flags, NULL, NULL, NULL);
if (ost->img_resample_ctx == NULL) {
fprintf(stderr, "Cannot get resampling context\n");
exit(1);
}
ost->resample_height = icodec->height - (frame_topBand + frame_bottomBand);
}
ost->encoding_needed = 1;
ist->decoding_needed = 1;
break;
Fabrice Bellard
committed
case CODEC_TYPE_SUBTITLE:
ost->encoding_needed = 1;
ist->decoding_needed = 1;
break;
default:
av_abort();
Fabrice Bellard
committed
break;
/* two pass mode */
(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 ?
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
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",
ist_table[ost->source_index]->file_index,
ist_table[ost->source_index]->index,
if (ost->sync_ist != ist_table[ost->source_index])
fprintf(stderr, " [sync #%d.%d]",
ost->sync_ist->file_index,
ost->sync_ist->index);
fprintf(stderr, "\n");
}
/* open each encoder */
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
if (ost->encoding_needed) {
AVCodec *codec;
Michael Niedermayer
committed
codec = avcodec_find_encoder(ost->st->codec->codec_id);
fprintf(stderr, "Unsupported codec for output stream #%d.%d\n",
Michael Niedermayer
committed
if (avcodec_open(ost->st->codec, codec) < 0) {
fprintf(stderr, "Error while opening codec for output stream #%d.%d - maybe incorrect parameters such as bit_rate, rate, width or height\n",
Michael Niedermayer
committed
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;
Michael Niedermayer
committed
codec = avcodec_find_decoder(ist->st->codec->codec_id);
fprintf(stderr, "Unsupported codec (id=%d) for input stream #%d.%d\n",
Michael Niedermayer
committed
ist->st->codec->codec_id, ist->file_index, ist->index);
Michael Niedermayer
committed
if (avcodec_open(ist->st->codec, codec) < 0) {
fprintf(stderr, "Error while opening codec for input stream #%d.%d\n",
Michael Niedermayer
committed
//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];
is = input_files[ist->file_index];
ist->next_pts = av_rescale_q(ist->st->start_time, ist->st->time_base, AV_TIME_BASE_Q);
if(ist->st->start_time == AV_NOPTS_VALUE)
if(input_files_ts_offset[ist->file_index])
ist->next_pts= AV_NOPTS_VALUE;
Patrice Bensoussan
committed
/* 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 = AVERROR(EINVAL);
Patrice Bensoussan
committed
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 = AVERROR(EINVAL);
Patrice Bensoussan
committed
goto fail;
Patrice Bensoussan
committed
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 = AVERROR(EINVAL);
goto fail;
}
if ( !using_stdin && verbose >= 0) {
fprintf(stderr, "Press [q] to stop encoding\n");
Leon van Stuivenberg
committed
url_set_interrupt_cb(decode_interrupt_cb);
}
term_init();
key = -1;
timer_start = av_gettime();
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];
Michael Niedermayer
committed
if(ost->st->codec->codec_type == CODEC_TYPE_VIDEO)
opts = ost->sync_opts * av_q2d(ost->st->codec->time_base);
opts = ost->st->pts.val * av_q2d(ost->st->time_base);
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;
}
Michael Niedermayer
committed
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
/* finish if limit size exhausted */
if (limit_filesize != 0 && limit_filesize < url_ftell(&output_files[0]->pb))
/* read a frame from it and output it in the fifo */
if (av_read_frame(is, &pkt) < 0) {
Calcium
committed
if (opt_shortest) break; else continue; //
if (do_pkt_dump) {
Panagiotis Issaris
committed
av_pkt_dump_log(NULL, AV_LOG_DEBUG, &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:%"PRId64" dts:%"PRId64" off:%"PRId64" %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 && ist->next_pts != AV_NOPTS_VALUE) {
int64_t delta= av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q) - ist->next_pts;
if(FFABS(delta) > 1LL*dts_delta_threshold*AV_TIME_BASE && !copy_ts){
input_files_ts_offset[ist->file_index]-= delta;
if (verbose > 2)
fprintf(stderr, "timestamp discontinuity %"PRId64", new offset= %"PRId64"\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) {
Michael Niedermayer
committed
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) {
Michael Niedermayer
committed
avcodec_close(ist->st->codec);
Loading
Loading full blame...