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 "config.h"
#include <ctype.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <errno.h>
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavformat/framehook.h"
#include "libavcodec/opt.h"
#include "libavutil/fifo.h"
#include "libavutil/avstring.h"
#include "libavformat/os_support.h"
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/types.h>
#include <sys/resource.h>
#elif defined(HAVE_GETPROCESSTIMES)
#include <windows.h>
#endif
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
#elif defined(HAVE_CONIO_H)
#include <conio.h>
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
#undef NDEBUG
#include <assert.h>
static const char program_name[] = "FFmpeg";
static const int program_birth_year = 2000;
/* 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;
Diego Pettenò
committed
static const OptionDef options[];
#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) {0,0};
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 const char *video_rc_override_string=NULL;
static int video_discard = 0;
static char *video_codec_name = NULL;
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 char *audio_codec_name = NULL;
Fabrice Bellard
committed
static char *audio_language = NULL;
static int subtitle_disable = 0;
static char *subtitle_codec_name = NULL;
Fabrice Bellard
committed
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 FILE *vstats_file;
Nico Sabbi
committed
static int opt_programid = 0;
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 float dts_delta_threshold = 10;
static unsigned 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 *subtitle_bitstream_filters=NULL;
Michael Niedermayer
committed
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 */
#ifdef HAVE_TERMIOS_H
/* init terminal so that we can grab keys */
static struct termios oldtty;
#ifdef HAVE_TERMIOS_H
Roumen Petrov
committed
static volatile sig_atomic_t received_sigterm = 0;
static void
sigterm_handler(int sig)
{
received_sigterm = sig;
term_exit();
}
#ifdef HAVE_TERMIOS_H
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)
{
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;
#elif defined(HAVE_CONIO_H)
if(kbhit())
return(getch());
Leon van Stuivenberg
committed
static int decode_interrupt_cb(void)
{
return q_pressed || (q_pressed = read_key() == 'q');
}
static int av_exit(int ret)
{
int i;
/* close files */
for(i=0;i<nb_output_files;i++) {
/* maybe av_close_output_file ??? */
AVFormatContext *s = output_files[i];
int j;
if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
url_fclose(s->pb);
for(j=0;j<s->nb_streams;j++) {
av_free(s->streams[j]->codec);
av_free(s->streams[j]);
}
av_free(s);
}
for(i=0;i<nb_input_files;i++)
av_close_input_file(input_files[i]);
av_free_static();
av_free(intra_matrix);
av_free(inter_matrix);
if (vstats_file)
fclose(vstats_file);
av_free(vstats_filename);
av_free(opt_names);
av_free(video_codec_name);
av_free(audio_codec_name);
av_free(subtitle_codec_name);
av_free(video_standard);
#ifdef CONFIG_POWERPC_PERF
extern void powerpc_display_perf_report(void);
powerpc_display_perf_report();
#endif /* CONFIG_POWERPC_PERF */
if (received_sigterm) {
fprintf(stderr,
"Received signal %d: terminating.\n",
(int) received_sigterm);
exit (255);
}
exit(ret); /* not all OS-es handle main() return value */
return ret;
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;
Michael Niedermayer
committed
return (double)(ist->pts - start_time)/AV_TIME_BASE;
}
Michael Niedermayer
committed
static void write_frame(AVFormatContext *s, AVPacket *pkt, AVCodecContext *avctx, AVBitStreamFilterContext *bsfc){
Michael Niedermayer
committed
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);
Michael Niedermayer
committed
av_free_packet(pkt);
new_pkt.destruct= av_destruct_packet;
fprintf(stderr, "%s failed for stream %d, codec %s",
bsfc->filter->name, pkt->stream_index,
avctx->codec ? avctx->codec->name : "copy");
Michael Niedermayer
committed
}
*pkt= new_pkt;
bsfc= bsfc->next;
}
ret= av_interleaved_write_frame(s, pkt);
if(ret < 0){
print_error("av_interleaved_write_frame()", ret);
Michael Niedermayer
committed
}
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;
AVCodecContext *dec= ist->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 (enc->channels != dec->channels)
ost->audio_resample = 1;
if (ost->audio_resample && !ost->resample) {
ost->resample = audio_resample_init(enc->channels, dec->channels,
enc->sample_rate, dec->sample_rate);
if (!ost->resample) {
fprintf(stderr, "Can not resample %d channels @ %d Hz to %d channels @ %d Hz\n",
dec->channels, dec->sample_rate,
enc->channels, enc->sample_rate);
}
}
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 || fabs(delta) > audio_drift_threshold*enc->sample_rate){
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_realloc(&ost->fifo, av_fifo_size(&ost->fifo) + size_out + 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);
//FIXME pass ost->sync_opts as AVFrame.pts in avcodec_encode_audio()
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;
}
//FIXME pass ost->sync_opts as AVFrame.pts in avcodec_encode_audio()
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;
}
if (ENABLE_VHOOK)
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;
Michael Niedermayer
committed
pkt.pts = av_rescale_q(pts, ist->st->time_base, ost->st->time_base);
Fabrice Bellard
committed
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 (video_sync_method == 2)
ost->sync_opts= lrintf(get_sync_ipts(ost) / av_q2d(enc->time_base));
//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);
pkt.pts= av_rescale_q(ost->sync_opts, enc->time_base, ost->st->time_base);
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");
//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){
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 */
if (!vstats_file) {
vstats_file = fopen(vstats_filename, "w");
if (!vstats_file) {
Benoit Fouet
committed
perror("fopen");
Benoit Fouet
committed
}
}
Michael Niedermayer
committed
enc = ost->st->codec;
if (enc->codec_type == CODEC_TYPE_VIDEO) {
Fabrice Bellard
committed
frame_number = ost->frame_number;
fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number, enc->coded_frame->quality/(float)FF_QP2LAMBDA);
if (enc->flags&CODEC_FLAG_PSNR)
fprintf(vstats_file, "PSNR= %6.2f ", psnr(enc->coded_frame->error[0]/(enc->width*enc->height*255.0*255.0)));
fprintf(vstats_file,"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(vstats_file, "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(vstats_file,"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);