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
Aurelien Jacobs
committed
/* needed for usleep() */
Aurelien Jacobs
committed
#include "config.h"
#include <ctype.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <errno.h>
Aurelien Jacobs
committed
#include <unistd.h>
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavcodec/opt.h"
#include "libavcodec/audioconvert.h"
#include "libavcodec/colorspace.h"
#include "libavutil/fifo.h"
#include "libavutil/pixdesc.h"
#include "libavutil/avstring.h"
#include "libavformat/os_support.h"
#if HAVE_SYS_RESOURCE_H
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#elif HAVE_GETPROCESSTIMES
#include <windows.h>
#endif
#if HAVE_GETPROCESSMEMORYINFO
#include <windows.h>
#include <psapi.h>
#endif
#include <sys/select.h>
#endif
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
#undef NDEBUG
#include <assert.h>
Michael Niedermayer
committed
const char program_name[] = "FFmpeg";
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 100
static const char *last_asked_format = NULL;
static int64_t input_files_ts_offset[MAX_FILES];
static double input_files_ts_scale[MAX_FILES][MAX_STREAMS];
static AVCodec *input_codecs[MAX_FILES*MAX_STREAMS];
static AVCodec *output_codecs[MAX_FILES*MAX_STREAMS];
static AVStreamMap stream_maps[MAX_FILES*MAX_STREAMS];
Patrice Bensoussan
committed
static AVMetaDataMap meta_data_maps[MAX_FILES];
static int nb_meta_data_maps;
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;
static enum SampleFormat audio_sample_fmt = SAMPLE_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};
Michael Niedermayer
committed
static float video_qscale = 0;
Vidar Madsen
committed
static uint16_t *intra_matrix = NULL;
static uint16_t *inter_matrix = NULL;
static const char *video_rc_override_string=NULL;
static int video_discard = 0;
static char *video_codec_name = NULL;
static char *video_language = 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;
static int64_t channel_layout = 0;
#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 int subtitle_codec_tag = 0;
static float mux_preload= 0.5;
static float mux_max_delay= 0.7;
static int64_t recording_time = INT64_MAX;
static int64_t start_time = 0;
static int64_t rec_timestamp = 0;
static int metadata_count;
static AVMetadataTag *metadata;
static int do_hex_dump = 0;
static int do_pkt_dump = 0;
static int do_psnr = 0;
static int do_pass = 0;
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;
Michael Niedermayer
committed
static int video_global_header = 0;
static FILE *vstats_file;
Nico Sabbi
committed
static int opt_programid = 0;
Wolfram Gloger
committed
static int copy_initial_nonkeyframes = 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 exit_on_error = 0;
static int using_stdin = 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 force_fps = 0;
static int pgmyuv_compatibility_hack=0;
static float dts_delta_threshold = 10;
static unsigned int sws_flags = SWS_BICUBIC;
static uint8_t *audio_buf;
static uint8_t *audio_out;
Michael Niedermayer
committed
unsigned int allocated_audio_out_size, allocated_audio_buf_size;
static short *samples;
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_PREFIX "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;
Jason Garrett-Glaser
committed
int resample_pix_fmt;
/* full frame size of first frame */
int original_height;
int original_width;
/* cropping area sizes */
int video_crop;
int topBand;
int bottomBand;
int leftBand;
int rightBand;
/* cropping area of first frame */
int original_topBand;
int original_bottomBand;
int original_leftBand;
int original_rightBand;
int video_pad;
Todd Kirby
committed
int padbottom;
int padleft;
int padright;
/* audio only */
int audio_resample;
ReSampleContext *resample; /* for audio resampling */
int reformat_pair;
AVAudioConvert *reformat_ctx;
Michael Niedermayer
committed
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 */
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 */
Michael Niedermayer
committed
int showed_multi_packet_warning;
int is_past_recording_time;
} 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 */
/* init terminal so that we can grab keys */
static struct termios oldtty;
static volatile int received_sigterm = 0;
Roumen Petrov
committed
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). */
#ifdef SIGXCPU
signal(SIGXCPU, sigterm_handler);
#endif
#if 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;
#if !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 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)
url_fclose(s->pb);
for(j=0;j<s->nb_streams;j++) {
av_metadata_free(&s->streams[j]->metadata);
av_free(s->streams[j]->codec);
av_free(s->streams[j]);
}
for(j=0;j<s->nb_programs;j++) {
av_metadata_free(&s->programs[j]->metadata);
}
for(j=0;j<s->nb_chapters;j++) {
av_metadata_free(&s->chapters[j]->metadata);
}
av_metadata_free(&s->metadata);
av_free(s);
}
for(i=0;i<nb_input_files;i++)
av_close_input_file(input_files[i]);
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);
#if CONFIG_POWERPC_PERF
void powerpc_display_perf_report(void);
powerpc_display_perf_report();
#endif /* CONFIG_POWERPC_PERF */
for (i=0;i<CODEC_TYPE_NB;i++)
av_free(avcodec_opts[i]);
av_free(avformat_opts);
av_free(sws_opts);
av_free(audio_buf);
av_free(audio_out);
Michael Niedermayer
committed
allocated_audio_buf_size= allocated_audio_out_size= 0;
av_free(samples);
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;
Ronald S. Bultje
committed
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
static void choose_sample_fmt(AVStream *st, AVCodec *codec)
{
if(codec && codec->sample_fmts){
const enum SampleFormat *p= codec->sample_fmts;
for(; *p!=-1; p++){
if(*p == st->codec->sample_fmt)
break;
}
if(*p == -1)
st->codec->sample_fmt = codec->sample_fmts[0];
}
}
static void choose_pixel_fmt(AVStream *st, AVCodec *codec)
{
if(codec && codec->pix_fmts){
const enum PixelFormat *p= codec->pix_fmts;
for(; *p!=-1; p++){
if(*p == st->codec->pix_fmt)
break;
}
if(*p == -1
&& !( st->codec->codec_id==CODEC_ID_MJPEG
&& st->codec->strict_std_compliance <= FF_COMPLIANCE_INOFFICIAL
&& ( st->codec->pix_fmt == PIX_FMT_YUV420P
|| st->codec->pix_fmt == PIX_FMT_YUV422P)))
st->codec->pix_fmt = codec->pix_fmts[0];
}
}
static int read_ffserver_streams(AVFormatContext *s, const char *filename)
int i, err;
int nopts = 0;
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();
if (!st->codec) {
print_error(filename, AVERROR(ENOMEM));
av_exit(1);
}
Alex Beregszaszi
committed
memcpy(st->codec, ic->streams[i]->codec, sizeof(AVCodecContext));
if (st->codec->codec_type == CODEC_TYPE_AUDIO && audio_stream_copy)
st->stream_copy = 1;
else if (st->codec->codec_type == CODEC_TYPE_VIDEO && video_stream_copy)
st->stream_copy = 1;
if(!st->codec->thread_count)
st->codec->thread_count = 1;
if(st->codec->thread_count>1)
avcodec_thread_init(st->codec, st->codec->thread_count);
if(st->codec->flags & CODEC_FLAG_BITEXACT)
nopts = 1;
if (!nopts)
s->timestamp = av_gettime();
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");
if (exit_on_error)
av_exit(1);
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,
Michael Niedermayer
committed
int64_t audio_out_size, audio_buf_size;
Sylvain Corré
committed
Michael Niedermayer
committed
AVCodecContext *enc= ost->st->codec;
AVCodecContext *dec= ist->st->codec;
int osize= av_get_bits_per_sample_format(enc->sample_fmt)/8;
int isize= av_get_bits_per_sample_format(dec->sample_fmt)/8;
Michael Niedermayer
committed
const int coded_bps = av_get_bits_per_sample(enc->codec->id);
need_realloc:
audio_buf_size= (allocated_for_size + isize*dec->channels - 1) / (isize*dec->channels);
Michael Niedermayer
committed
audio_buf_size= (audio_buf_size*enc->sample_rate + dec->sample_rate) / dec->sample_rate;
audio_buf_size= audio_buf_size*2 + 10000; //safety factors for the deprecated resampling API
Michael Niedermayer
committed
audio_buf_size*= osize*enc->channels;
audio_out_size= FFMAX(audio_buf_size, enc->frame_size * osize * enc->channels);
if(coded_bps > 8*osize)
audio_out_size= audio_out_size * coded_bps / (8*osize);
audio_out_size += FF_MIN_BUFFER_SIZE;
if(audio_out_size > INT_MAX || audio_buf_size > INT_MAX){
fprintf(stderr, "Buffer sizes too large\n");
av_exit(1);
}
Michael Niedermayer
committed
av_fast_malloc(&audio_buf, &allocated_audio_buf_size, audio_buf_size);
av_fast_malloc(&audio_out, &allocated_audio_out_size, audio_out_size);
if (!audio_buf || !audio_out){
fprintf(stderr, "Out of memory in do_audio_out\n");
av_exit(1);
}
Sylvain Corré
committed
if (enc->channels != dec->channels)
ost->audio_resample = 1;
if (ost->audio_resample && !ost->resample) {
if (dec->sample_fmt != SAMPLE_FMT_S16)
fprintf(stderr, "Warning, using s16 intermediate sample format for resampling\n");
ost->resample = av_audio_resample_init(enc->channels, dec->channels,
enc->sample_rate, dec->sample_rate,
enc->sample_fmt, dec->sample_fmt,
16, 10, 0, 0.8);
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);
}
}
#define MAKE_SFMT_PAIR(a,b) ((a)+SAMPLE_FMT_NB*(b))
if (!ost->audio_resample && dec->sample_fmt!=enc->sample_fmt &&
MAKE_SFMT_PAIR(enc->sample_fmt,dec->sample_fmt)!=ost->reformat_pair) {
if (ost->reformat_ctx)
av_audio_convert_free(ost->reformat_ctx);
ost->reformat_ctx = av_audio_convert_alloc(enc->sample_fmt, 1,
dec->sample_fmt, 1, NULL, 0);
if (!ost->reformat_ctx) {
fprintf(stderr, "Cannot convert %s sample format to %s sample format\n",
avcodec_get_sample_fmt_name(dec->sample_fmt),
avcodec_get_sample_fmt_name(enc->sample_fmt));
av_exit(1);
}
ost->reformat_pair=MAKE_SFMT_PAIR(enc->sample_fmt,dec->sample_fmt);
}
double delta = get_sync_ipts(ost) * enc->sample_rate - ost->sync_opts
Michael Niedermayer
committed
- 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 > allocated_for_size - size){
allocated_for_size= byte_delta + (int64_t)size;
goto need_realloc;
}
ist->is_start=0;
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);
Michael Niedermayer
committed
// 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)
Michael Niedermayer
committed
- av_fifo_size(ost->fifo)/(ost->st->codec->channels * 2); //FIXME wrong
size_out = audio_resample(ost->resample,
size / (ist->st->codec->channels * isize));
size_out = size_out * enc->channels * osize;
if (!ost->audio_resample && dec->sample_fmt!=enc->sample_fmt) {
const void *ibuf[6]= {buftmp};
void *obuf[6]= {audio_buf};
int istride[6]= {isize};
int ostride[6]= {osize};
int len= size_out/istride[0];
if (av_audio_convert(ost->reformat_ctx, obuf, ostride, ibuf, istride, len)<0) {
printf("av_audio_convert() failed\n");
if (exit_on_error)
av_exit(1);
return;
}
size_out = len*osize;
if (enc->frame_size > 1) {
Michael Niedermayer
committed
if (av_fifo_realloc2(ost->fifo, av_fifo_size(ost->fifo) + size_out) < 0) {
fprintf(stderr, "av_fifo_realloc2() failed\n");
av_exit(1);
}
Michael Niedermayer
committed
av_fifo_generic_write(ost->fifo, buftmp, size_out, NULL);
frame_bytes = enc->frame_size * osize * enc->channels;
Michael Niedermayer
committed
while (av_fifo_size(ost->fifo) >= frame_bytes) {
AVPacket pkt;
av_init_packet(&pkt);
av_fifo_generic_read(ost->fifo, audio_buf, frame_bytes, NULL);
//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);
if (ret < 0) {
fprintf(stderr, "Audio encoding failed\n");
av_exit(1);
}
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);
ost->sync_opts += size_out / (osize * enc->channels);
/* output a pcm frame */
/* determine the size of the coded buffer */
size_out /= osize;
if (coded_bps)
size_out = size_out*coded_bps/8;
Michael Niedermayer
committed
if(size_out > audio_out_size){
fprintf(stderr, "Internal error, buffer size too small\n");
av_exit(1);
}
//FIXME pass ost->sync_opts as AVFrame.pts in avcodec_encode_audio()
ret = avcodec_encode_audio(enc, audio_out, size_out,
if (ret < 0) {
fprintf(stderr, "Audio encoding failed\n");
av_exit(1);
}
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 */
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 */
fprintf(stderr, "Deinterlacing failed\n");
av_free(buf);
buf = NULL;
picture2 = picture;
}
} else {
picture2 = picture;
}
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 = 1024 * 1024;
Fabrice Bellard
committed
int subtitle_out_size, nb, i;
AVCodecContext *enc;
AVPacket pkt;
if (pts == AV_NOPTS_VALUE) {
fprintf(stderr, "Subtitle packets must have a pts\n");
if (exit_on_error)
av_exit(1);
Fabrice Bellard
committed
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++) {
Reimar Döffinger
committed
sub->pts = av_rescale_q(pts, ist->st->time_base, AV_TIME_BASE_Q);
// start_display_time is required to be 0
sub->pts += av_rescale_q(sub->start_display_time, (AVRational){1, 1000}, AV_TIME_BASE_Q);
sub->end_display_time -= sub->start_display_time;
sub->start_display_time = 0;
subtitle_out_size = avcodec_encode_subtitle(enc, subtitle_out,
Fabrice Bellard
committed
subtitle_out_max_size, sub);
Reimar Döffinger
committed
if (subtitle_out_size < 0) {
fprintf(stderr, "Subtitle encoding failed\n");
av_exit(1);
}
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(sub->pts, AV_TIME_BASE_Q, 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;
int64_t topBand, bottomBand, leftBand, rightBand;
AVFrame *final_picture, *formatted_picture, *resampling_dst, *padding_src;
AVFrame picture_crop_temp, picture_pad_temp;
AVCodecContext *enc, *dec;
double sync_ipts;
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;
sync_ipts = get_sync_ipts(ost) / av_q2d(enc->time_base);
Fabrice Bellard
committed
/* by default, we output a single frame */
nb_frames = 1;
Philip Gladstone
committed
*frame_size = 0;
Michael Niedermayer
committed
if(video_sync_method){
double vdelta = sync_ipts - 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 || (video_sync_method<0 && (s->oformat->flags & AVFMT_VARIABLE_FPS))){
if(vdelta<=-0.6){
nb_frames=0;
}else if(vdelta>0.6)
ost->sync_opts= lrintf(sync_ipts);
}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, get_sync_ipts(ost), nb_frames);
if (nb_frames == 0){
++nb_frames_drop;
if (verbose>2)
fprintf(stderr, "*** drop!\n");
nb_frames_dup += nb_frames - 1;
fprintf(stderr, "*** %d dup!\n", nb_frames-1);
ost->sync_opts= lrintf(sync_ipts);
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) {
fprintf(stderr, "error cropping picture\n");
if (exit_on_error)
av_exit(1);
}
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) {
fprintf(stderr, "error padding picture\n");
if (exit_on_error)
av_exit(1);
}
resampling_dst = &picture_pad_temp;
}
}