blob: c4729df87b7399b55cec615623148660ec992730 [file] [log] [blame]
/*
* ffmpeg main
* Copyright (c) 2000-2003 Fabrice Bellard
*
* 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
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include <ctype.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <limits.h>
#include <unistd.h>
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavutil/opt.h"
#include "libavcodec/audioconvert.h"
#include "libavutil/audioconvert.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/colorspace.h"
#include "libavutil/fifo.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/avstring.h"
#include "libavutil/libm.h"
#include "libavformat/os_support.h"
#include "libavformat/ffm.h" // not public API
#if CONFIG_AVFILTER
# include "libavfilter/avcodec.h"
# include "libavfilter/avfilter.h"
# include "libavfilter/avfiltergraph.h"
# include "libavfilter/vsink_buffer.h"
# include "libavfilter/vsrc_buffer.h"
#endif
#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
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#if HAVE_TERMIOS_H
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
#elif HAVE_KBHIT
#include <conio.h>
#endif
#include <time.h>
#include "cmdutils.h"
#include "libavutil/avassert.h"
const char program_name[] = "ffmpeg";
const int program_birth_year = 2000;
/* select an input stream for an output stream */
typedef struct StreamMap {
int file_index;
int stream_index;
int sync_file_index;
int sync_stream_index;
} StreamMap;
/**
* select an input file for an output file
*/
typedef struct MetadataMap {
int file; //< file index
char type; //< type of metadata to copy -- (g)lobal, (s)tream, (c)hapter or (p)rogram
int index; //< stream/chapter/program number
} MetadataMap;
typedef struct ChapterMap {
int in_file;
int out_file;
} ChapterMap;
static const OptionDef options[];
#define MAX_FILES 100
#define MAX_STREAMS 1024 /* arbitrary sanity check value */
static const char *last_asked_format = NULL;
static double *ts_scale;
static int nb_ts_scale;
static AVFormatContext *output_files[MAX_FILES];
static int nb_output_files = 0;
static StreamMap *stream_maps = NULL;
static int nb_stream_maps;
/* first item specifies output metadata, second is input */
static MetadataMap (*meta_data_maps)[2] = NULL;
static int nb_meta_data_maps;
static int metadata_global_autocopy = 1;
static int metadata_streams_autocopy = 1;
static int metadata_chapters_autocopy = 1;
static ChapterMap *chapter_maps = NULL;
static int nb_chapter_maps;
/* indexed by output file stream index */
static int *streamid_map = NULL;
static int nb_streamid_map = 0;
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 int frame_bits_per_raw_sample = 0;
static enum AVSampleFormat audio_sample_fmt = AV_SAMPLE_FMT_NONE;
static int max_frames[4] = {INT_MAX, INT_MAX, INT_MAX, INT_MAX};
static AVRational frame_rate;
static float video_qscale = 0;
static uint16_t *intra_matrix = NULL;
static uint16_t *inter_matrix = NULL;
static const char *video_rc_override_string=NULL;
static int video_disable = 0;
static int video_discard = 0;
static char *video_codec_name = NULL;
static unsigned int video_codec_tag = 0;
static char *video_language = NULL;
static int same_quality = 0;
static int do_deinterlace = 0;
static int top_field_first = -1;
static int me_threshold = 0;
static int intra_dc_precision = 8;
static int loop_input = 0;
static int loop_output = AVFMT_NOOUTPUTLOOP;
static int qp_hist = 0;
#if CONFIG_AVFILTER
static char *vfilters = NULL;
#endif
static int intra_only = 0;
static int audio_sample_rate = 0;
#define QSCALE_NONE -99999
static float audio_qscale = QSCALE_NONE;
static int audio_disable = 0;
static int audio_channels = 0;
static char *audio_codec_name = NULL;
static unsigned int audio_codec_tag = 0;
static char *audio_language = NULL;
static int subtitle_disable = 0;
static char *subtitle_codec_name = NULL;
static char *subtitle_language = NULL;
static unsigned int subtitle_codec_tag = 0;
static int data_disable = 0;
static char *data_codec_name = NULL;
static unsigned int data_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 input_ts_offset = 0;
static int file_overwrite = 0;
static AVDictionary *metadata;
static int do_benchmark = 0;
static int do_hex_dump = 0;
static int do_pkt_dump = 0;
static int do_psnr = 0;
static int do_pass = 0;
static const char *pass_logfilename_prefix;
static int audio_stream_copy = 0;
static int video_stream_copy = 0;
static int subtitle_stream_copy = 0;
static int data_stream_copy = 0;
static int video_sync_method= -1;
static int audio_sync_method= 0;
static float audio_drift_threshold= 0.1;
static int copy_ts= 0;
static int copy_tb= 0;
static int opt_shortest = 0;
static char *vstats_filename;
static FILE *vstats_file;
static int opt_programid = 0;
static int copy_initial_nonkeyframes = 0;
static int rate_emu = 0;
static int video_channel = 0;
static char *video_standard;
static int audio_volume = 256;
static int exit_on_error = 0;
static int using_stdin = 0;
static int verbose = 1;
static int run_as_daemon = 0;
static int thread_count= 1;
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 char *forced_key_frames = NULL;
static float dts_delta_threshold = 10;
static int64_t timer_start;
static uint8_t *audio_buf;
static uint8_t *audio_out;
static unsigned int allocated_audio_out_size, allocated_audio_buf_size;
static short *samples;
static AVBitStreamFilterContext *video_bitstream_filters=NULL;
static AVBitStreamFilterContext *audio_bitstream_filters=NULL;
static AVBitStreamFilterContext *subtitle_bitstream_filters=NULL;
#define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass"
struct InputStream;
typedef struct OutputStream {
int file_index; /* file index */
int index; /* stream index in the output file */
int source_index; /* InputStream index */
AVStream *st; /* stream in the output file */
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 InputStream *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
AVBitStreamFilterContext *bitstream_filters;
AVCodec *enc;
/* video only */
int video_resample;
AVFrame resample_frame; /* temporary frame for image resampling */
struct SwsContext *img_resample_ctx; /* for image resampling */
int resample_height;
int resample_width;
int resample_pix_fmt;
AVRational frame_rate;
float frame_aspect_ratio;
/* forced key frames */
int64_t *forced_kf_pts;
int forced_kf_count;
int forced_kf_index;
/* audio only */
int audio_resample;
ReSampleContext *resample; /* for audio resampling */
int resample_sample_fmt;
int resample_channels;
int resample_sample_rate;
int reformat_pair;
AVAudioConvert *reformat_ctx;
AVFifoBuffer *fifo; /* for compression: one audio fifo per codec */
FILE *logfile;
#if CONFIG_AVFILTER
AVFilterContext *output_video_filter;
AVFilterContext *input_video_filter;
AVFilterBufferRef *picref;
char *avfilter;
AVFilterGraph *graph;
#endif
int sws_flags;
} OutputStream;
static OutputStream **output_streams_for_file[MAX_FILES] = { NULL };
static int nb_output_streams_for_file[MAX_FILES] = { 0 };
typedef struct InputStream {
int file_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' */
AVCodec *dec;
int64_t start; /* time when read started */
int64_t next_pts; /* synthetic pts for cases where pkt.pts
is not defined */
int64_t pts; /* current pts */
double ts_scale;
int is_start; /* is 1 at the start and after a discontinuity */
int showed_multi_packet_warning;
int is_past_recording_time;
} InputStream;
typedef struct InputFile {
AVFormatContext *ctx;
int eof_reached; /* true if eof reached */
int ist_index; /* index of first stream in ist_table */
int buffer_size; /* current total buffer size */
int64_t ts_offset;
} InputFile;
#if HAVE_TERMIOS_H
/* init terminal so that we can grab keys */
static struct termios oldtty;
#endif
static InputStream *input_streams = NULL;
static int nb_input_streams = 0;
static InputFile *input_files = NULL;
static int nb_input_files = 0;
#if CONFIG_AVFILTER
static int configure_video_filters(InputStream *ist, OutputStream *ost)
{
AVFilterContext *last_filter, *filter;
/** filter graph containing all filters including input & output */
AVCodecContext *codec = ost->st->codec;
AVCodecContext *icodec = ist->st->codec;
enum PixelFormat pix_fmts[] = { codec->pix_fmt, PIX_FMT_NONE };
AVRational sample_aspect_ratio;
char args[255];
int ret;
ost->graph = avfilter_graph_alloc();
if (ist->st->sample_aspect_ratio.num){
sample_aspect_ratio = ist->st->sample_aspect_ratio;
}else
sample_aspect_ratio = ist->st->codec->sample_aspect_ratio;
snprintf(args, 255, "%d:%d:%d:%d:%d:%d:%d", ist->st->codec->width,
ist->st->codec->height, ist->st->codec->pix_fmt, 1, AV_TIME_BASE,
sample_aspect_ratio.num, sample_aspect_ratio.den);
ret = avfilter_graph_create_filter(&ost->input_video_filter, avfilter_get_by_name("buffer"),
"src", args, NULL, ost->graph);
if (ret < 0)
return ret;
ret = avfilter_graph_create_filter(&ost->output_video_filter, avfilter_get_by_name("buffersink"),
"out", NULL, pix_fmts, ost->graph);
if (ret < 0)
return ret;
last_filter = ost->input_video_filter;
if (codec->width != icodec->width || codec->height != icodec->height) {
snprintf(args, 255, "%d:%d:flags=0x%X",
codec->width,
codec->height,
ost->sws_flags);
if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"),
NULL, args, NULL, ost->graph)) < 0)
return ret;
if ((ret = avfilter_link(last_filter, 0, filter, 0)) < 0)
return ret;
last_filter = filter;
}
snprintf(args, sizeof(args), "flags=0x%X", ost->sws_flags);
ost->graph->scale_sws_opts = av_strdup(args);
if (ost->avfilter) {
AVFilterInOut *outputs = avfilter_inout_alloc();
AVFilterInOut *inputs = avfilter_inout_alloc();
outputs->name = av_strdup("in");
outputs->filter_ctx = last_filter;
outputs->pad_idx = 0;
outputs->next = NULL;
inputs->name = av_strdup("out");
inputs->filter_ctx = ost->output_video_filter;
inputs->pad_idx = 0;
inputs->next = NULL;
if ((ret = avfilter_graph_parse(ost->graph, ost->avfilter, &inputs, &outputs, NULL)) < 0)
return ret;
av_freep(&ost->avfilter);
} else {
if ((ret = avfilter_link(last_filter, 0, ost->output_video_filter, 0)) < 0)
return ret;
}
if ((ret = avfilter_graph_config(ost->graph, NULL)) < 0)
return ret;
codec->width = ost->output_video_filter->inputs[0]->w;
codec->height = ost->output_video_filter->inputs[0]->h;
codec->sample_aspect_ratio = ost->st->sample_aspect_ratio =
ost->frame_aspect_ratio ? // overriden by the -aspect cli option
av_d2q(ost->frame_aspect_ratio*codec->height/codec->width, 255) :
ost->output_video_filter->inputs[0]->sample_aspect_ratio;
return 0;
}
#endif /* CONFIG_AVFILTER */
static void term_exit(void)
{
av_log(NULL, AV_LOG_QUIET, "%s", "");
#if HAVE_TERMIOS_H
if(!run_as_daemon)
tcsetattr (0, TCSANOW, &oldtty);
#endif
}
static volatile int received_sigterm = 0;
static void
sigterm_handler(int sig)
{
received_sigterm = sig;
q_pressed++;
term_exit();
}
static void term_init(void)
{
#if HAVE_TERMIOS_H
if(!run_as_daemon){
struct termios tty;
tcgetattr (0, &tty);
oldtty = tty;
atexit(term_exit);
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
|INLCR|IGNCR|ICRNL|IXON);
tty.c_oflag |= OPOST;
tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
tty.c_cflag &= ~(CSIZE|PARENB);
tty.c_cflag |= CS8;
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 0;
tcsetattr (0, TCSANOW, &tty);
signal(SIGQUIT, sigterm_handler); /* Quit (POSIX). */
}
#endif
signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */
signal(SIGTERM, sigterm_handler); /* Termination (ANSI). */
#ifdef SIGXCPU
signal(SIGXCPU, sigterm_handler);
#endif
}
/* read a key without blocking */
static int read_key(void)
{
#if HAVE_TERMIOS_H
int n = 1;
unsigned char ch;
struct timeval tv;
fd_set rfds;
if(run_as_daemon)
return -1;
FD_ZERO(&rfds);
FD_SET(0, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
n = select(1, &rfds, NULL, NULL, &tv);
if (n > 0) {
n = read(0, &ch, 1);
if (n == 1)
return ch;
return n;
}
#elif HAVE_KBHIT
if(kbhit())
return(getch());
#endif
return -1;
}
static int decode_interrupt_cb(void)
{
q_pressed += read_key() == 'q';
return q_pressed > 1;
}
static int ffmpeg_exit(int ret)
{
int i;
/* close files */
for(i=0;i<nb_output_files;i++) {
AVFormatContext *s = output_files[i];
if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)
avio_close(s->pb);
avformat_free_context(s);
av_free(output_streams_for_file[i]);
}
for(i=0;i<nb_input_files;i++) {
av_close_input_file(input_files[i].ctx);
}
av_free(intra_matrix);
av_free(inter_matrix);
if (vstats_file)
fclose(vstats_file);
av_free(vstats_filename);
av_free(streamid_map);
av_free(stream_maps);
av_free(meta_data_maps);
av_freep(&input_streams);
av_freep(&input_files);
av_free(video_codec_name);
av_free(audio_codec_name);
av_free(subtitle_codec_name);
av_free(data_codec_name);
av_free(video_standard);
uninit_opts();
av_free(audio_buf);
av_free(audio_out);
allocated_audio_buf_size= allocated_audio_out_size= 0;
av_free(samples);
#if CONFIG_AVFILTER
avfilter_uninit();
#endif
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;
}
/* similar to ff_dynarray_add() and av_fast_realloc() */
static void *grow_array(void *array, int elem_size, int *size, int new_size)
{
if (new_size >= INT_MAX / elem_size) {
fprintf(stderr, "Array too big.\n");
ffmpeg_exit(1);
}
if (*size < new_size) {
uint8_t *tmp = av_realloc(array, new_size*elem_size);
if (!tmp) {
fprintf(stderr, "Could not alloc buffer.\n");
ffmpeg_exit(1);
}
memset(tmp + *size*elem_size, 0, (new_size-*size) * elem_size);
*size = new_size;
return tmp;
}
return array;
}
static void choose_sample_fmt(AVStream *st, AVCodec *codec)
{
if(codec && codec->sample_fmts){
const enum AVSampleFormat *p= codec->sample_fmts;
for(; *p!=-1; p++){
if(*p == st->codec->sample_fmt)
break;
}
if (*p == -1) {
if((codec->capabilities & CODEC_CAP_LOSSLESS) && av_get_sample_fmt_name(st->codec->sample_fmt) > av_get_sample_fmt_name(codec->sample_fmts[0]))
av_log(NULL, AV_LOG_ERROR, "Convertion will not be lossless'\n");
av_log(NULL, AV_LOG_WARNING,
"Incompatible sample format '%s' for codec '%s', auto-selecting format '%s'\n",
av_get_sample_fmt_name(st->codec->sample_fmt),
codec->name,
av_get_sample_fmt_name(codec->sample_fmts[0]));
st->codec->sample_fmt = codec->sample_fmts[0];
}
}
}
static void choose_sample_rate(AVStream *st, AVCodec *codec)
{
if(codec && codec->supported_samplerates){
const int *p= codec->supported_samplerates;
int best=0;
int best_dist=INT_MAX;
for(; *p; p++){
int dist= abs(st->codec->sample_rate - *p);
if(dist < best_dist){
best_dist= dist;
best= *p;
}
}
if(best_dist){
av_log(st->codec, AV_LOG_WARNING, "Requested sampling rate unsupported using closest supported (%d)\n", best);
}
st->codec->sample_rate= best;
}
}
static void choose_pixel_fmt(AVStream *st, AVCodec *codec)
{
if(codec && codec->pix_fmts){
const enum PixelFormat *p= codec->pix_fmts;
if(st->codec->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL){
if(st->codec->codec_id==CODEC_ID_MJPEG){
p= (const enum PixelFormat[]){PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_NONE};
}else if(st->codec->codec_id==CODEC_ID_LJPEG){
p= (const enum PixelFormat[]){PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ444P, PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_YUV444P, PIX_FMT_BGRA, PIX_FMT_NONE};
}
}
for(; *p!=-1; p++){
if(*p == st->codec->pix_fmt)
break;
}
if (*p == -1) {
if(st->codec->pix_fmt != PIX_FMT_NONE)
av_log(NULL, AV_LOG_WARNING,
"Incompatible pixel format '%s' for codec '%s', auto-selecting format '%s'\n",
av_pix_fmt_descriptors[st->codec->pix_fmt].name,
codec->name,
av_pix_fmt_descriptors[codec->pix_fmts[0]].name);
st->codec->pix_fmt = codec->pix_fmts[0];
}
}
}
static OutputStream *new_output_stream(AVFormatContext *oc, int file_idx, AVCodec *codec)
{
OutputStream *ost;
AVStream *st = av_new_stream(oc, oc->nb_streams < nb_streamid_map ? streamid_map[oc->nb_streams] : 0);
int idx = oc->nb_streams - 1;
if (!st) {
av_log(NULL, AV_LOG_ERROR, "Could not alloc stream.\n");
ffmpeg_exit(1);
}
output_streams_for_file[file_idx] =
grow_array(output_streams_for_file[file_idx],
sizeof(*output_streams_for_file[file_idx]),
&nb_output_streams_for_file[file_idx],
oc->nb_streams);
ost = output_streams_for_file[file_idx][idx] =
av_mallocz(sizeof(OutputStream));
if (!ost) {
fprintf(stderr, "Could not alloc output stream\n");
ffmpeg_exit(1);
}
ost->file_index = file_idx;
ost->index = idx;
ost->st = st;
ost->enc = codec;
avcodec_get_context_defaults3(st->codec, codec);
ost->sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
return ost;
}
static int read_ffserver_streams(AVFormatContext *s, const char *filename)
{
int i, err;
AVFormatContext *ic;
int nopts = 0;
err = av_open_input_file(&ic, filename, NULL, FFM_PACKET_SIZE, NULL);
if (err < 0)
return err;
/* copy stream format */
for(i=0;i<ic->nb_streams;i++) {
AVStream *st;
OutputStream *ost;
AVCodec *codec;
codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id);
ost = new_output_stream(s, nb_output_files, codec);
st = ost->st;
// FIXME: a more elegant solution is needed
memcpy(st, ic->streams[i], sizeof(AVStream));
st->info = av_malloc(sizeof(*st->info));
memcpy(st->info, ic->streams[i]->info, sizeof(*st->info));
avcodec_copy_context(st->codec, ic->streams[i]->codec);
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
if (audio_stream_copy) {
st->stream_copy = 1;
} else
choose_sample_fmt(st, codec);
} else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
if (video_stream_copy) {
st->stream_copy = 1;
} else
choose_pixel_fmt(st, codec);
}
if(st->codec->flags & CODEC_FLAG_BITEXACT)
nopts = 1;
}
av_close_input_file(ic);
return 0;
}
static double
get_sync_ipts(const OutputStream *ost)
{
const InputStream *ist = ost->sync_ist;
return (double)(ist->pts - start_time)/AV_TIME_BASE;
}
static void write_frame(AVFormatContext *s, AVPacket *pkt, AVCodecContext *avctx, AVBitStreamFilterContext *bsfc){
int ret;
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 & AV_PKT_FLAG_KEY);
if(a>0){
av_free_packet(pkt);
new_pkt.destruct= av_destruct_packet;
} else if(a<0){
fprintf(stderr, "%s failed for stream %d, codec %s",
bsfc->filter->name, pkt->stream_index,
avctx->codec ? avctx->codec->name : "copy");
print_error("", a);
if (exit_on_error)
ffmpeg_exit(1);
}
*pkt= new_pkt;
bsfc= bsfc->next;
}
ret= av_interleaved_write_frame(s, pkt);
if(ret < 0){
print_error("av_interleaved_write_frame()", ret);
ffmpeg_exit(1);
}
}
#define MAX_AUDIO_PACKET_SIZE (128 * 1024)
static void do_audio_out(AVFormatContext *s,
OutputStream *ost,
InputStream *ist,
unsigned char *buf, int size)
{
uint8_t *buftmp;
int64_t audio_out_size, audio_buf_size;
int64_t allocated_for_size= size;
int size_out, frame_bytes, ret, resample_changed;
AVCodecContext *enc= ost->st->codec;
AVCodecContext *dec= ist->st->codec;
int osize = av_get_bytes_per_sample(enc->sample_fmt);
int isize = av_get_bytes_per_sample(dec->sample_fmt);
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);
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
audio_buf_size= FFMAX(audio_buf_size, enc->frame_size);
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");
ffmpeg_exit(1);
}
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");
ffmpeg_exit(1);
}
if (enc->channels != dec->channels)
ost->audio_resample = 1;
resample_changed = ost->resample_sample_fmt != dec->sample_fmt ||
ost->resample_channels != dec->channels ||
ost->resample_sample_rate != dec->sample_rate;
if ((ost->audio_resample && !ost->resample) || resample_changed) {
if (resample_changed) {
av_log(NULL, AV_LOG_INFO, "Input stream #%d.%d frame changed from rate:%d fmt:%s ch:%d to rate:%d fmt:%s ch:%d\n",
ist->file_index, ist->st->index,
ost->resample_sample_rate, av_get_sample_fmt_name(ost->resample_sample_fmt), ost->resample_channels,
dec->sample_rate, av_get_sample_fmt_name(dec->sample_fmt), dec->channels);
ost->resample_sample_fmt = dec->sample_fmt;
ost->resample_channels = dec->channels;
ost->resample_sample_rate = dec->sample_rate;
if (ost->resample)
audio_resample_close(ost->resample);
}
/* if audio_sync_method is >1 the resampler is needed for audio drift compensation */
if (audio_sync_method <= 1 &&
ost->resample_sample_fmt == enc->sample_fmt &&
ost->resample_channels == enc->channels &&
ost->resample_sample_rate == enc->sample_rate) {
ost->resample = NULL;
ost->audio_resample = 0;
} else {
if (dec->sample_fmt != AV_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);
ffmpeg_exit(1);
}
}
}
#define MAKE_SFMT_PAIR(a,b) ((a)+AV_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",
av_get_sample_fmt_name(dec->sample_fmt),
av_get_sample_fmt_name(enc->sample_fmt));
ffmpeg_exit(1);
}
ost->reformat_pair=MAKE_SFMT_PAIR(enc->sample_fmt,dec->sample_fmt);
}
if(audio_sync_method){
double delta = get_sync_ipts(ost) * enc->sample_rate - ost->sync_opts
- av_fifo_size(ost->fifo)/(enc->channels * 2);
double idelta= delta*dec->sample_rate / enc->sample_rate;
int byte_delta= ((int)idelta)*2*dec->channels;
//FIXME resample delay
if(fabs(delta) > 50){
if(ist->is_start || fabs(delta) > audio_drift_threshold*enc->sample_rate){
if(byte_delta < 0){
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);
av_assert0(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);
}
}
}else
ost->sync_opts= lrintf(get_sync_ipts(ost) * enc->sample_rate)
- av_fifo_size(ost->fifo)/(enc->channels * 2); //FIXME wrong
if (ost->audio_resample) {
buftmp = audio_buf;
size_out = audio_resample(ost->resample,
(short *)buftmp, (short *)buf,
size / (dec->channels * isize));
size_out = size_out * enc->channels * osize;
} else {
buftmp = buf;
size_out = size;
}
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)
ffmpeg_exit(1);
return;
}
buftmp = audio_buf;
size_out = len*osize;
}
/* now encode as many frames as possible */
if (enc->frame_size > 1) {
/* output resampled raw samples */
if (av_fifo_realloc2(ost->fifo, av_fifo_size(ost->fifo) + size_out) < 0) {
fprintf(stderr, "av_fifo_realloc2() failed\n");
ffmpeg_exit(1);
}
av_fifo_generic_write(ost->fifo, buftmp, size_out, NULL);
frame_bytes = enc->frame_size * osize * enc->channels;
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");
ffmpeg_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);
pkt.flags |= AV_PKT_FLAG_KEY;
write_frame(s, &pkt, enc, ost->bitstream_filters);
ost->sync_opts += enc->frame_size;
}
} else {
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;
if(size_out > audio_out_size){
fprintf(stderr, "Internal error, buffer size too small\n");
ffmpeg_exit(1);
}
//FIXME pass ost->sync_opts as AVFrame.pts in avcodec_encode_audio()
ret = avcodec_encode_audio(enc, audio_out, size_out,
(short *)buftmp);
if (ret < 0) {
fprintf(stderr, "Audio encoding failed\n");
ffmpeg_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);
pkt.flags |= AV_PKT_FLAG_KEY;
write_frame(s, &pkt, enc, ost->bitstream_filters);
}
}
static void pre_process_video_frame(InputStream *ist, AVPicture *picture, void **bufp)
{
AVCodecContext *dec;
AVPicture *picture2;
AVPicture picture_tmp;
uint8_t *buf = 0;
dec = ist->st->codec;
/* deinterlace : must be done before any resize */
if (do_deinterlace) {
int size;
/* create temporary picture */
size = avpicture_get_size(dec->pix_fmt, dec->width, dec->height);
buf = av_malloc(size);
if (!buf)
return;
picture2 = &picture_tmp;
avpicture_fill(picture2, buf, dec->pix_fmt, dec->width, dec->height);
if(avpicture_deinterlace(picture2, picture,
dec->pix_fmt, dec->width, dec->height) < 0) {
/* if error, do not deinterlace */
fprintf(stderr, "Deinterlacing failed\n");
av_free(buf);
buf = NULL;
picture2 = picture;
}
} else {
picture2 = picture;
}
if (picture != picture2)
*picture = *picture2;
*bufp = buf;
}
/* we begin to correct av delay at this threshold */
#define AV_DELAY_MAX 0.100
static void do_subtitle_out(AVFormatContext *s,
OutputStream *ost,
InputStream *ist,
AVSubtitle *sub,
int64_t pts)
{
static uint8_t *subtitle_out = NULL;
int subtitle_out_max_size = 1024 * 1024;
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)
ffmpeg_exit(1);
return;
}
enc = ost->st->codec;
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++) {
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,
subtitle_out_max_size, sub);
if (subtitle_out_size < 0) {
fprintf(stderr, "Subtitle encoding failed\n");
ffmpeg_exit(1);
}
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);
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;
}
write_frame(s, &pkt, ost->st->codec, ost->bitstream_filters);
}
}
static int bit_buffer_size= 1024*256;
static uint8_t *bit_buffer= NULL;
static void do_video_out(AVFormatContext *s,
OutputStream *ost,
InputStream *ist,
AVFrame *in_picture,
int *frame_size, float quality)
{
int nb_frames, i, ret, av_unused resample_changed;
AVFrame *final_picture, *formatted_picture;
AVCodecContext *enc, *dec;
double sync_ipts;
enc = ost->st->codec;
dec = ist->st->codec;
sync_ipts = get_sync_ipts(ost) / av_q2d(enc->time_base);
/* by default, we output a single frame */
nb_frames = 1;
*frame_size = 0;
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)
nb_frames = lrintf(vdelta);
//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");
}else if (nb_frames > 1) {
nb_frames_dup += nb_frames - 1;
if (verbose>2)
fprintf(stderr, "*** %d dup!\n", nb_frames-1);
}
}else
ost->sync_opts= lrintf(sync_ipts);
nb_frames= FFMIN(nb_frames, max_frames[AVMEDIA_TYPE_VIDEO] - ost->frame_number);
if (nb_frames <= 0)
return;
formatted_picture = in_picture;
final_picture = formatted_picture;
#if !CONFIG_AVFILTER
resample_changed = ost->resample_width != dec->width ||
ost->resample_height != dec->height ||
ost->resample_pix_fmt != dec->pix_fmt;
if (resample_changed) {
av_log(NULL, AV_LOG_INFO,
"Input stream #%d.%d frame changed from size:%dx%d fmt:%s to size:%dx%d fmt:%s\n",
ist->file_index, ist->st->index,
ost->resample_width, ost->resample_height, av_get_pix_fmt_name(ost->resample_pix_fmt),
dec->width , dec->height , av_get_pix_fmt_name(dec->pix_fmt));
ost->resample_width = dec->width;
ost->resample_height = dec->height;
ost->resample_pix_fmt = dec->pix_fmt;
}
ost->video_resample = dec->width != enc->width ||
dec->height != enc->height ||
dec->pix_fmt != enc->pix_fmt;
if (ost->video_resample) {
final_picture = &ost->resample_frame;
if (!ost->img_resample_ctx || resample_changed) {
/* initialize the destination picture */
if (!ost->resample_frame.data[0]) {
avcodec_get_frame_defaults(&ost->resample_frame);
if (avpicture_alloc((AVPicture *)&ost->resample_frame, enc->pix_fmt,
enc->width, enc->height)) {
fprintf(stderr, "Cannot allocate temp picture, check pix fmt\n");
ffmpeg_exit(1);
}
}
/* initialize a new scaler context */
sws_freeContext(ost->img_resample_ctx);
ost->img_resample_ctx = sws_getContext(dec->width, dec->height, dec->pix_fmt,
enc->width, enc->height, enc->pix_fmt,
ost->sws_flags, NULL, NULL, NULL);
if (ost->img_resample_ctx == NULL) {
fprintf(stderr, "Cannot get resampling context\n");
ffmpeg_exit(1);
}
}
sws_scale(ost->img_resample_ctx, formatted_picture->data, formatted_picture->linesize,
0, ost->resample_height, final_picture->data, final_picture->linesize);
}
#endif
/* duplicates frame if needed */
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 |= AV_PKT_FLAG_KEY;
write_frame(s, &pkt, ost->st->codec, ost->bitstream_filters);
enc->coded_frame = old_frame;
} else {
AVFrame big_picture;
big_picture= *final_picture;
/* better than nothing: use input picture interlaced
settings */
big_picture.interlaced_frame = in_picture->interlaced_frame;
if (ost->st->codec->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
big_picture.top_field_first = top_field_first;
}
/* handles sameq here. This is not correct because it may
not be a global option */
big_picture.quality = quality;
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);
if (ost->forced_kf_index < ost->forced_kf_count &&
big_picture.pts >= ost->forced_kf_pts[ost->forced_kf_index]) {
big_picture.pict_type = AV_PICTURE_TYPE_I;
ost->forced_kf_index++;
}
ret = avcodec_encode_video(enc,
bit_buffer, bit_buffer_size,
&big_picture);
if (ret < 0) {
fprintf(stderr, "Video encoding failed\n");
ffmpeg_exit(1);
}
if(ret>0){
pkt.data= bit_buffer;
pkt.size= ret;
if(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->key_frame)
pkt.flags |= AV_PKT_FLAG_KEY;
write_frame(s, &pkt, ost->st->codec, ost->bitstream_filters);
*frame_size = ret;
video_size += ret;
//fprintf(stderr,"\nFrame: %3d size: %5d type: %d",
// enc->frame_number-1, ret, enc->pict_type);
/* if two pass, output log */
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
}
}
}
ost->sync_opts++;
ost->frame_number++;
}
}
static double psnr(double d){
return -10.0*log(d)/log(10.0);
}
static void do_video_stats(AVFormatContext *os, OutputStream *ost,
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) {
perror("fopen");
ffmpeg_exit(1);
}
}
enc = ost->st->codec;
if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {
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);
/* 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_picture_type_char(enc->coded_frame->pict_type));
}
}
static void print_report(AVFormatContext **output_files,
OutputStream **ost_table, int nb_ostreams,
int is_last_report)
{
char buf[1024];
OutputStream *ost;
AVFormatContext *oc;
int64_t total_size;
AVCodecContext *enc;
int frame_number, vid, i;
double bitrate;
int64_t pts = INT64_MAX;
static int64_t last_time = -1;
static int qp_histogram[52];
if (!is_last_report) {
int64_t cur_time;
/* display the report every 0.5 seconds */
cur_time = av_gettime();
if (last_time == -1) {
last_time = cur_time;
return;
}
if ((cur_time - last_time) < 500000)
return;
last_time = cur_time;
}
oc = output_files[0];
total_size = avio_size(oc->pb);
if(total_size<0) // FIXME improve avio_size() so it works with non seekable output too
total_size= avio_tell(oc->pb);
buf[0] = '\0';
vid = 0;
for(i=0;i<nb_ostreams;i++) {
float q = -1;
ost = ost_table[i];
enc = ost->st->codec;
if (!ost->st->stream_copy && enc->coded_frame)
q = enc->coded_frame->quality/(float)FF_QP2LAMBDA;
if (vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "q=%2.1f ", q);
}
if (!vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) {
float t = (av_gettime()-timer_start) / 1000000.0;
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, q);
if(is_last_report)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "L");
if(qp_hist){
int j;
int qp = lrintf(q);
if(qp>=0 && qp<FF_ARRAY_ELEMS(qp_histogram))
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)));
}
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=");
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));
}
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "*:%2.2f ", psnr(error_sum/scale_sum));
}
vid = 1;
}
/* compute min output value */
pts = FFMIN(pts, av_rescale_q(ost->st->pts.val,
ost->st->time_base, AV_TIME_BASE_Q));
}
if (verbose > 0 || is_last_report) {
int hours, mins, secs, us;
secs = pts / AV_TIME_BASE;
us = pts % AV_TIME_BASE;
mins = secs / 60;
secs %= 60;
hours = mins / 60;
mins %= 60;
bitrate = pts ? total_size * 8 / (pts / 1000.0) : 0;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
"size=%8.0fkB time=", total_size / 1024.0);
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
"%02d:%02d:%02d.%02d ", hours, mins, secs,
(100 * us) / AV_TIME_BASE);
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
"bitrate=%6.1fkbits/s", bitrate);
if (nb_frames_dup || nb_frames_drop)
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);
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
);
}
}
static void generate_silence(uint8_t* buf, enum AVSampleFormat sample_fmt, size_t size)
{
int fill_char = 0x00;
if (sample_fmt == AV_SAMPLE_FMT_U8)
fill_char = 0x80;
memset(buf, fill_char, size);
}
/* pkt = NULL means EOF (needed to flush decoder buffers) */
static int output_packet(InputStream *ist, int ist_index,
OutputStream **ost_table, int nb_ostreams,
const AVPacket *pkt)
{
AVFormatContext *os;
OutputStream *ost;
int ret, i;
int got_output;
AVFrame picture;
void *buffer_to_free = NULL;
static unsigned int samples_size= 0;
AVSubtitle subtitle, *subtitle_to_free;
int64_t pkt_pts = AV_NOPTS_VALUE;
#if CONFIG_AVFILTER
int frame_available;
#endif
float quality;
AVPacket avpkt;
int bps = av_get_bytes_per_sample(ist->st->codec->sample_fmt);
if(ist->next_pts == AV_NOPTS_VALUE)
ist->next_pts= ist->pts;
if (pkt == NULL) {
/* EOF handling */
av_init_packet(&avpkt);
avpkt.data = NULL;
avpkt.size = 0;
goto handle_eof;
} else {
avpkt = *pkt;
}
if(pkt->dts != AV_NOPTS_VALUE)
ist->next_pts = ist->pts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
if(pkt->pts != AV_NOPTS_VALUE)
pkt_pts = av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q);
//while we have more to decode or while the decoder did output something on EOF
while (avpkt.size > 0 || (!pkt && got_output)) {
uint8_t *data_buf, *decoded_data_buf;
int data_size, decoded_data_size;
handle_eof:
ist->pts= ist->next_pts;
if(avpkt.size && avpkt.size != pkt->size &&
((!ist->showed_multi_packet_warning && verbose>0) || verbose>1)){
fprintf(stderr, "Multiple frames in a packet from stream %d\n", pkt->stream_index);
ist->showed_multi_packet_warning=1;
}
/* decode the packet if needed */
decoded_data_buf = NULL; /* fail safe */
decoded_data_size= 0;
data_buf = avpkt.data;
data_size = avpkt.size;
subtitle_to_free = NULL;
if (ist->decoding_needed) {
switch(ist->st->codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:{
if(pkt && samples_size < FFMAX(pkt->size*sizeof(*samples), AVCODEC_MAX_AUDIO_FRAME_SIZE)) {
samples_size = FFMAX(pkt->size*sizeof(*samples), AVCODEC_MAX_AUDIO_FRAME_SIZE);
av_free(samples);
samples= av_malloc(samples_size);
}
decoded_data_size= samples_size;
/* XXX: could avoid copy if PCM 16 bits with same
endianness as CPU */
ret = avcodec_decode_audio3(ist->st->codec, samples, &decoded_data_size,
&avpkt);
if (ret < 0)
goto fail_decode;
avpkt.data += ret;
avpkt.size -= ret;
data_size = ret;
got_output = decoded_data_size > 0;
/* Some bug in mpeg audio decoder gives */
/* decoded_data_size < 0, it seems they are overflows */
if (!got_output) {
/* no audio frame */
continue;
}
decoded_data_buf = (uint8_t *)samples;
ist->next_pts += ((int64_t)AV_TIME_BASE/bps * decoded_data_size) /
(ist->st->codec->sample_rate * ist->st->codec->channels);
break;}
case AVMEDIA_TYPE_VIDEO:
decoded_data_size = (ist->st->codec->width * ist->st->codec->height * 3) / 2;
/* XXX: allocate picture correctly */
avcodec_get_frame_defaults(&picture);
avpkt.pts = pkt_pts;
avpkt.dts = ist->pts;
pkt_pts = AV_NOPTS_VALUE;
ret = avcodec_decode_video2(ist->st->codec,
&picture, &got_output, &avpkt);
quality = same_quality ? picture.quality : 0;
if (ret < 0)
goto fail_decode;
if (!got_output) {
/* no picture yet */
goto discard_packet;
}
ist->next_pts = ist->pts = picture.best_effort_timestamp;
if (ist->st->codec->time_base.num != 0) {
int ticks= ist->st->parser ? ist->st->parser->repeat_pict+1 : ist->st->codec->ticks_per_frame;
ist->next_pts += ((int64_t)AV_TIME_BASE *
ist->st->codec->time_base.num * ticks) /
ist->st->codec->time_base.den;
}
avpkt.size = 0;
buffer_to_free = NULL;
pre_process_video_frame(ist, (AVPicture *)&picture, &buffer_to_free);
break;
case AVMEDIA_TYPE_SUBTITLE:
ret = avcodec_decode_subtitle2(ist->st->codec,
&subtitle, &got_output, &avpkt);
if (ret < 0)
goto fail_decode;
if (!got_output) {
goto discard_packet;
}
subtitle_to_free = &subtitle;
avpkt.size = 0;
break;
default:
goto fail_decode;
}
} else {
switch(ist->st->codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
ist->next_pts += ((int64_t)AV_TIME_BASE * ist->st->codec->frame_size) /
ist->st->codec->sample_rate;
break;
case AVMEDIA_TYPE_VIDEO:
if (ist->st->codec->time_base.num != 0) {
int ticks= ist->st->parser ? ist->st->parser->repeat_pict+1 : ist->st->codec->ticks_per_frame;
ist->next_pts += ((int64_t)AV_TIME_BASE *
ist->st->codec->time_base.num * ticks) /
ist->st->codec->time_base.den;
}
break;
}
ret = avpkt.size;
avpkt.size = 0;
}
#if CONFIG_AVFILTER
if(ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
if (start_time == 0 || ist->pts >= start_time) {
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
if (ost->input_video_filter && ost->source_index == ist_index) {
if (!picture.sample_aspect_ratio.num)
picture.sample_aspect_ratio = ist->st->sample_aspect_ratio;
picture.pts = ist->pts;
av_vsrc_buffer_add_frame(ost->input_video_filter, &picture, AV_VSRC_BUF_FLAG_OVERWRITE);
}
}
}
#endif
// preprocess audio (volume)
if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
if (audio_volume != 256) {
short *volp;
volp = samples;
for(i=0;i<(decoded_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 (rate_emu) {
int64_t pts = av_rescale(ist->pts, 1000000, AV_TIME_BASE);
int64_t now = av_gettime() - ist->start;
if (pts > now)
usleep(pts - now);
}
/* if output time reached then transcode raw format,
encode packets and output them */
if (start_time == 0 || ist->pts >= start_time)
for(i=0;i<nb_ostreams;i++) {
int frame_size;
ost = ost_table[i];
if (ost->source_index == ist_index) {
#if CONFIG_AVFILTER
frame_available = ist->st->codec->codec_type != AVMEDIA_TYPE_VIDEO ||
!ost->output_video_filter || avfilter_poll_frame(ost->output_video_filter->inputs[0]);
while (frame_available) {
if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO && ost->output_video_filter) {
AVRational ist_pts_tb = ost->output_video_filter->inputs[0]->time_base;
if (av_vsink_buffer_get_video_buffer_ref(ost->output_video_filter, &ost->picref, 0) < 0)
goto cont;
if (ost->picref) {
avfilter_fill_frame_from_video_buffer_ref(&picture, ost->picref);
ist->pts = av_rescale_q(ost->picref->pts, ist_pts_tb, AV_TIME_BASE_Q);
}
}
#endif
os = output_files[ost->file_index];
/* set the input output pts pairs */
//ost->sync_ipts = (double)(ist->pts + input_files[ist->file_index].ts_offset - start_time)/ AV_TIME_BASE;
if (ost->encoding_needed) {
av_assert0(ist->decoding_needed);
switch(ost->st->codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
do_audio_out(os, ost, ist, decoded_data_buf, decoded_data_size);
break;
case AVMEDIA_TYPE_VIDEO:
#if CONFIG_AVFILTER
if (ost->picref->video && !ost->frame_aspect_ratio)
ost->st->codec->sample_aspect_ratio = ost->picref->video->sample_aspect_ratio;
#endif
do_video_out(os, ost, ist, &picture, &frame_size,
same_quality ? quality : ost->st->codec->global_quality);
if (vstats_filename && frame_size)
do_video_stats(os, ost, frame_size);
break;
case AVMEDIA_TYPE_SUBTITLE:
do_subtitle_out(os, ost, ist, &subtitle,
pkt->pts);
break;
default:
abort();
}
} else {
AVFrame avframe; //FIXME/XXX remove this
AVPicture pict;
AVPacket opkt;
int64_t ost_tb_start_time= av_rescale_q(start_time, AV_TIME_BASE_Q, ost->st->time_base);
av_init_packet(&opkt);
if ((!ost->frame_number && !(pkt->flags & AV_PKT_FLAG_KEY)) && !copy_initial_nonkeyframes)
#if !CONFIG_AVFILTER
continue;
#else
goto cont;
#endif
/* 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 & AV_PKT_FLAG_KEY;
if(ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
audio_size += data_size;
else if (ost->st->codec->codec_type == AVMEDIA_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(pkt->pts, ist->st->time_base, ost->st->time_base) - ost_tb_start_time;
else
opkt.pts= AV_NOPTS_VALUE;
if (pkt->dts == AV_NOPTS_VALUE)
opkt.dts = av_rescale_q(ist->pts, AV_TIME_BASE_Q, ost->st->time_base);
else
opkt.dts = av_rescale_q(pkt->dts, ist->st->time_base, ost->st->time_base);
opkt.dts -= ost_tb_start_time;
opkt.duration = av_rescale_q(pkt->duration, ist->st->time_base, ost->st->time_base);
opkt.flags= pkt->flags;
//FIXME remove the following 2 lines they shall be replaced by the bitstream filters
if( ost->st->codec->codec_id != CODEC_ID_H264
&& ost->st->codec->codec_id != CODEC_ID_MPEG1VIDEO
&& ost->st->codec->codec_id != CODEC_ID_MPEG2VIDEO
) {
if(av_parser_change(ist->st->parser, ost->st->codec, &opkt.data, &opkt.size, data_buf, data_size, pkt->flags & AV_PKT_FLAG_KEY))
opkt.destruct= av_destruct_packet;
} else {
opkt.data = data_buf;
opkt.size = data_size;
}
if (os->oformat->flags & AVFMT_RAWPICTURE) {
/* store AVPicture in AVPacket, as expected by the output format */
avpicture_fill(&pict, opkt.data, ost->st->codec->pix_fmt, ost->st->codec->width, ost->st->codec->height);
opkt.data = (uint8_t *)&pict;
opkt.size = sizeof(AVPicture);
opkt.flags |= AV_PKT_FLAG_KEY;
}
write_frame(os, &opkt, ost->st->codec, ost->bitstream_filters);
ost->st->codec->frame_number++;
ost->frame_number++;
av_free_packet(&opkt);
}
#if CONFIG_AVFILTER
cont:
frame_available = (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) &&
ost->output_video_filter && avfilter_poll_frame(ost->output_video_filter->inputs[0]);
avfilter_unref_buffer(ost->picref);
}
#endif
}
}
av_free(buffer_to_free);
/* XXX: allocate the subtitles in the codec ? */
if (subtitle_to_free) {
avsubtitle_free(subtitle_to_free);
subtitle_to_free = NULL;
}
}
discard_packet:
if (pkt == NULL) {
/* EOF handling */
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
if (ost->source_index == ist_index) {
AVCodecContext *enc= ost->st->codec;
os = output_files[ost->file_index];
if(ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <=1)
continue;
if(ost->st->codec->codec_type == AVMEDIA_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;
switch(ost->st->codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
fifo_bytes = av_fifo_size(ost->fifo);
ret = 0;
/* encode any samples remaining in fifo */
if (fifo_bytes > 0) {
int osize = av_get_bytes_per_sample(enc->sample_fmt);
int fs_tmp = enc->frame_size;
av_fifo_generic_read(ost->fifo, audio_buf, fifo_bytes, NULL);
if (enc->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME) {
enc->frame_size = fifo_bytes / (osize * enc->channels);
} else { /* pad */
int frame_bytes = enc->frame_size*osize*enc->channels;
if (allocated_audio_buf_size < frame_bytes)
ffmpeg_exit(1);
generate_silence(audio_buf+fifo_bytes, enc->sample_fmt, frame_bytes - fifo_bytes);
}
ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, (short *)audio_buf);
pkt.duration = av_rescale((int64_t)enc->frame_size*ost->st->time_base.den,
ost->st->time_base.num, enc->sample_rate);
enc->frame_size = fs_tmp;
}
if(ret <= 0) {
ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, NULL);
}
if (ret < 0) {
fprintf(stderr, "Audio encoding failed\n");
ffmpeg_exit(1);
}
audio_size += ret;
pkt.flags |= AV_PKT_FLAG_KEY;
break;
case AVMEDIA_TYPE_VIDEO:
ret = avcodec_encode_video(enc, bit_buffer, bit_buffer_size, NULL);
if (ret < 0) {
fprintf(stderr, "Video encoding failed\n");
ffmpeg_exit(1);
}
video_size += ret;
if(enc->coded_frame && enc->coded_frame->key_frame)
pkt.flags |= AV_PKT_FLAG_KEY;
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
}
break;
default:
ret=-1;
}
if(ret<=0)
break;
pkt.data= bit_buffer;
pkt.size= ret;
if(enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)
pkt.pts= av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
write_frame(os, &pkt, ost->st->codec, ost->bitstream_filters);
}
}
}
}
}
return 0;
fail_decode:
return -1;
}
static void print_sdp(AVFormatContext **avc, int n)
{
char sdp[2048];
av_sdp_create(avc, n, sdp, sizeof(sdp));
printf("SDP:\n%s\n", sdp);
fflush(stdout);
}
static int copy_chapters(int infile, int outfile)
{
AVFormatContext *is = input_files[infile].ctx;
AVFormatContext *os = output_files[outfile];
int i;
for (i = 0; i < is->nb_chapters; i++) {
AVChapter *in_ch = is->chapters[i], *out_ch;
int64_t ts_off = av_rescale_q(start_time - input_files[infile].ts_offset,
AV_TIME_BASE_Q, in_ch->time_base);
int64_t rt = (recording_time == INT64_MAX) ? INT64_MAX :
av_rescale_q(recording_time, AV_TIME_BASE_Q, in_ch->time_base);
if (in_ch->end < ts_off)
continue;
if (rt != INT64_MAX && in_ch->start > rt + ts_off)
break;
out_ch = av_mallocz(sizeof(AVChapter));
if (!out_ch)
return AVERROR(ENOMEM);
out_ch->id = in_ch->id;
out_ch->time_base = in_ch->time_base;
out_ch->start = FFMAX(0, in_ch->start - ts_off);
out_ch->end = FFMIN(rt, in_ch->end - ts_off);
if (metadata_chapters_autocopy)
av_dict_copy(&out_ch->metadata, in_ch->metadata, 0);
os->nb_chapters++;
os->chapters = av_realloc(os->chapters, sizeof(AVChapter)*os->nb_chapters);
if (!os->chapters)
return AVERROR(ENOMEM);
os->chapters[os->nb_chapters - 1] = out_ch;
}
return 0;
}
static void parse_forced_key_frames(char *kf, OutputStream *ost,
AVCodecContext *avctx)
{
char *p;
int n = 1, i;
int64_t t;
for (p = kf; *p; p++)
if (*p == ',')
n++;
ost->forced_kf_count = n;
ost->forced_kf_pts = av_malloc(sizeof(*ost->forced_kf_pts) * n);
if (!ost->forced_kf_pts) {
av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n");
ffmpeg_exit(1);
}
for (i = 0; i < n; i++) {
p = i ? strchr(p, ',') + 1 : kf;
t = parse_time_or_die("force_key_frames", p, 1);
ost->forced_kf_pts[i] = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base);
}
}
/*
* The following code is the main loop of the file converter
*/
static int transcode(AVFormatContext **output_files,
int nb_output_files,
InputFile *input_files,
int nb_input_files,
StreamMap *stream_maps, int nb_stream_maps)
{
int ret = 0, i, j, k, n, nb_ostreams = 0, step;
AVFormatContext *is, *os;
AVCodecContext *codec, *icodec;
OutputStream *ost, **ost_table = NULL;
InputStream *ist;
char error[1024];
int key;
int want_sdp = 1;
uint8_t no_packet[MAX_FILES]={0};
int no_packet_count=0;
int nb_frame_threshold[AVMEDIA_TYPE_NB]={0};
int nb_streams[AVMEDIA_TYPE_NB]={0};
if (rate_emu)
for (i = 0; i < nb_input_streams; i++)
input_streams[i].start = av_gettime();
/* output stream init */
nb_ostreams = 0;
for(i=0;i<nb_output_files;i++) {
os = output_files[i];
if (!os->nb_streams && !(os->oformat->flags & AVFMT_NOSTREAMS)) {
av_dump_format(output_files[i], i, output_files[i]->filename, 1);
fprintf(stderr, "Output file #%d does not contain any stream\n", i);
ret = AVERROR(EINVAL);
goto fail;
}
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");
ret = AVERROR(EINVAL);
goto fail;
}
/* Sanity check the mapping args -- do the input files & streams exist? */
for(i=0;i<nb_stream_maps;i++) {
int fi = stream_maps[i].file_index;
int si = stream_maps[i].stream_index;
if (fi < 0 || fi > nb_input_files - 1 ||
si < 0 || si > input_files[fi].ctx->nb_streams - 1) {
fprintf(stderr,"Could not find input stream #%d.%d\n", fi, si);
ret = AVERROR(EINVAL);
goto fail;
}
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 > input_files[fi].ctx->nb_streams - 1) {
fprintf(stderr,"Could not find sync stream #%d.%d\n", fi, si);
ret = AVERROR(EINVAL);
goto fail;
}
}
ost_table = av_mallocz(sizeof(OutputStream *) * nb_ostreams);
if (!ost_table)
goto fail;
for(k=0;k<nb_output_files;k++) {
os = output_files[k];
for(i=0;i<os->nb_streams;i++,n++) {
nb_streams[os->streams[i]->codec->codec_type]++;
}
}
for(step=1<<30; step; step>>=1){
int found_streams[AVMEDIA_TYPE_NB]={0};
for(j=0; j<AVMEDIA_TYPE_NB; j++)
nb_frame_threshold[j] += step;
for(j=0; j<nb_input_streams; j++) {
int skip=0;
ist = &input_streams[j];
if(opt_programid){
int pi,si;
AVFormatContext *f= input_files[ ist->file_index ].ctx;
skip=1;
for(pi=0; pi<f->nb_programs; pi++){
AVProgram *p= f->programs[pi];
if(p->id == opt_programid)
for(si=0; si<p->nb_stream_indexes; si++){
if(f->streams[ p->stream_index[si] ] == ist->st)
skip=0;
}
}
}
if (ist->discard && ist->st->discard != AVDISCARD_ALL && !skip
&& nb_frame_threshold[ist->st->codec->codec_type] <= ist->st->codec_info_nb_frames){
found_streams[ist->st->codec->codec_type]++;
}
}
for(j=0; j<AVMEDIA_TYPE_NB; j++)
if(found_streams[j] < nb_streams[j])
nb_frame_threshold[j] -= step;
}
n = 0;
for(k=0;k<nb_output_files;k++) {
os = output_files[k];
for(i=0;i<os->nb_streams;i++,n++) {
int found;
ost = ost_table[n] = output_streams_for_file[k][i];
if (nb_stream_maps > 0) {
ost->source_index = input_files[stream_maps[n].file_index].ist_index +
stream_maps[n].stream_index;
/* Sanity check that the stream types match */
if (input_streams[ost->source_index].st->codec->codec_type != ost->st->codec->codec_type) {
int i= ost->file_index;
av_dump_format(output_files[i], i, output_files[i]->filename, 1);
fprintf(stderr, "Codec type mismatch for mapping #%d.%d -> #%d.%d\n",
stream_maps[n].file_index, stream_maps[n].stream_index,
ost->file_index, ost->index);
ffmpeg_exit(1);
}
} else {
/* get corresponding input stream index : we select the first one with the right type */
found = 0;
for (j = 0; j < nb_input_streams; j++) {
int skip=0;
ist = &input_streams[j];
if(opt_programid){
int pi,si;
AVFormatContext *f = input_files[ist->file_index].ctx;
skip=1;
for(pi=0; pi<f->nb_programs; pi++){
AVProgram *p= f->programs[pi];
if(p->id == opt_programid)
for(si=0; si<p->nb_stream_indexes; si++){
if(f->streams[ p->stream_index[si] ] == ist->st)
skip=0;
}
}
}
if (ist->discard && ist->st->discard != AVDISCARD_ALL && !skip &&
ist->st->codec->codec_type == ost->st->codec->codec_type &&
nb_frame_threshold[ist->st->codec->codec_type] <= ist->st->codec_info_nb_frames) {
ost->source_index = j;
found = 1;
break;
}
}
if (!found) {
if(! opt_programid) {
/* try again and reuse existing stream */
for (j = 0; j < nb_input_streams; j++) {
ist = &input_streams[j];
if ( ist->st->codec->codec_type == ost->st->codec->codec_type
&& ist->st->discard != AVDISCARD_ALL) {
ost->source_index = j;
found = 1;
}
}
}
if (!found) {
int i= ost->file_index;
av_dump_format(output_files[i], i, output_files[i]->filename, 1);
fprintf(stderr, "Could not find input stream matching output stream #%d.%d\n",
ost->file_index, ost->index);
ffmpeg_exit(1);
}
}
}
ist = &input_streams[ost->source_index];
ist->discard = 0;
ost->sync_ist = (nb_stream_maps > 0) ?
&input_streams[input_files[stream_maps[n].sync_file_index].ist_index +
stream_maps[n].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];
os = output_files[ost->file_index];
ist = &input_streams[ost->source_index];
codec = ost->st->codec;
icodec = ist->st->codec;
if (metadata_streams_autocopy)
av_dict_copy(&ost->st->metadata, ist->st->metadata,
AV_DICT_DONT_OVERWRITE);
ost->st->disposition = ist->st->disposition;
codec->bits_per_raw_sample= icodec->bits_per_raw_sample;
codec->chroma_sample_location = icodec->chroma_sample_location;
if (ost->st->stream_copy) {
uint64_t extra_size = (uint64_t)icodec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE;
if (extra_size > INT_MAX)
goto fail;
/* 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){
if( !os->oformat->codec_tag
|| av_codec_get_id (os->oformat->codec_tag, icodec->codec_tag) == codec->codec_id
|| av_codec_get_tag(os->oformat->codec_tag, icodec->codec_id) <= 0)
codec->codec_tag = icodec->codec_tag;
}
codec->bit_rate = icodec->bit_rate;
codec->rc_max_rate = icodec->rc_max_rate;
codec->rc_buffer_size = icodec->rc_buffer_size;
codec->extradata= av_mallocz(extra_size);
if (!codec->extradata)
goto fail;
memcpy(codec->extradata, icodec->extradata, icodec->extradata_size);
codec->extradata_size= icodec->extradata_size;
if(!copy_tb && av_q2d(icodec->time_base)*icodec->ticks_per_frame > av_q2d(ist->st->time_base) && av_q2d(ist->st->time_base) < 1.0/500){
codec->time_base = icodec->time_base;
codec->time_base.num *= icodec->ticks_per_frame;
av_reduce(&codec->time_base.num, &codec->time_base.den,
codec->time_base.num, codec->time_base.den, INT_MAX);
}else
codec->time_base = ist->st->time_base;
switch(codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
if(audio_volume != 256) {
fprintf(stderr,"-acodec copy and -vol are incompatible (frames are not decoded)\n");
ffmpeg_exit(1);
}
codec->channel_layout = icodec->channel_layout;
codec->sample_rate = icodec->sample_rate;
codec->channels = icodec->channels;
codec->frame_size = icodec->frame_size;
codec->audio_service_type = icodec->audio_service_type;
codec->block_align= icodec->block_align;
if(codec->block_align == 1 && codec->codec_id == CODEC_ID_MP3)
codec->block_align= 0;
if(codec->codec_id == CODEC_ID_AC3)
codec->block_align= 0;
break;
case AVMEDIA_TYPE_VIDEO:
codec->pix_fmt = icodec->pix_fmt;
codec->width = icodec->width;
codec->height = icodec->height;
codec->has_b_frames = icodec->has_b_frames;
if (!codec->sample_aspect_ratio.num) {
codec->sample_aspect_ratio =
ost->st->sample_aspect_ratio =
ist->st->sample_aspect_ratio.num ? ist->st->sample_aspect_ratio :
ist->st->codec->sample_aspect_ratio.num ?
ist->st->codec->sample_aspect_ratio : (AVRational){0, 1};
}
break;
case AVMEDIA_TYPE_SUBTITLE:
codec->width = icodec->width;
codec->height = icodec->height;
break;
case AVMEDIA_TYPE_DATA:
break;
default:
abort();
}
} else {
if (!ost->enc)
ost->enc = avcodec_find_encoder(ost->st->codec->codec_id);
switch(codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
ost->fifo= av_fifo_alloc(1024);
if(!ost->fifo)
goto fail;
ost->reformat_pair = MAKE_SFMT_PAIR(AV_SAMPLE_FMT_NONE,AV_SAMPLE_FMT_NONE);
if (!codec->sample_rate) {
codec->sample_rate = icodec->sample_rate;
if (icodec->lowres)
codec->sample_rate >>= icodec->lowres;
}
choose_sample_rate(ost->st, ost->enc);
codec->time_base = (AVRational){1, codec->sample_rate};
if (codec->sample_fmt == AV_SAMPLE_FMT_NONE)
codec->sample_fmt = icodec->sample_fmt;
choose_sample_fmt(ost->st, ost->enc);
if (!codec->channels) {
codec->channels = icodec->channels;
codec->channel_layout = icodec->channel_layout;
}
if (av_get_channel_layout_nb_channels(codec->channel_layout) != codec->channels)
codec->channel_layout = 0;
ost->audio_resample = codec->sample_rate != icodec->sample_rate || audio_sync_method > 1;
icodec->request_channels = codec->channels;
ist->decoding_needed = 1;
ost->encoding_needed = 1;
ost->resample_sample_fmt = icodec->sample_fmt;
ost->resample_sample_rate = icodec->sample_rate;
ost->resample_channels = icodec->channels;
break;
case AVMEDIA_TYPE_VIDEO:
if (codec->pix_fmt == PIX_FMT_NONE)
codec->pix_fmt = icodec->pix_fmt;
choose_pixel_fmt(ost->st, ost->enc);
if (ost->st->codec->pix_fmt == PIX_FMT_NONE) {
fprintf(stderr, "Video pixel format is unknown, stream cannot be encoded\n");
ffmpeg_exit(1);
}
ost->video_resample = codec->width != icodec->width ||
codec->height != icodec->height ||
codec->pix_fmt != icodec->pix_fmt;
if (ost->video_resample) {
codec->bits_per_raw_sample= frame_bits_per_raw_sample;
}
if (!codec->width || !codec->height) {
codec->width = icodec->width;
codec->height = icodec->height;
}
ost->resample_height = icodec->height;
ost->resample_width = icodec->width;
ost->resample_pix_fmt= icodec->pix_fmt;
ost->encoding_needed = 1;
ist->decoding_needed = 1;
if (!ost->frame_rate.num)
ost->frame_rate = ist->st->r_frame_rate.num ? ist->st->r_frame_rate : (AVRational){25,1};
if (ost->enc && ost->enc->supported_framerates && !force_fps) {
int idx = av_find_nearest_q_idx(ost->frame_rate, ost->enc->supported_framerates);
ost->frame_rate = ost->enc->supported_framerates[idx];
}
codec->time_base = (AVRational){ost->frame_rate.den, ost->frame_rate.num};
if( av_q2d(codec->time_base) < 0.001 && video_sync_method
&& (video_sync_method==1 || (video_sync_method<0 && !(os->oformat->flags & AVFMT_VARIABLE_FPS)))){
av_log(os, AV_LOG_WARNING, "Frame rate very high for a muxer not effciciently supporting it.\n"
"Please consider specifiying a lower framerate, a different muxer or -vsync 2\n");
}
#if CONFIG_AVFILTER
if (configure_video_filters(ist, ost)) {
fprintf(stderr, "Error opening filters!\n");
exit(1);
}
#endif
break;
case AVMEDIA_TYPE_SUBTITLE:
ost->encoding_needed = 1;
ist->decoding_needed = 1;
break;
default:
abort();
break;
}
/* two pass mode */
if (ost->encoding_needed && codec->codec_id != CODEC_ID_H264 &&
(codec->flags & (CODEC_FLAG_PASS1 | CODEC_FLAG_PASS2))) {
char logfilename[1024];
FILE *f;
snprintf(logfilename, sizeof(logfilename), "%s-%d.log",
pass_logfilename_prefix ? pass_logfilename_prefix : DEFAULT_PASS_LOGFILENAME_PREFIX,
i);
if (codec->flags & CODEC_FLAG_PASS1) {
f = fopen(logfilename, "wb");
if (!f) {
fprintf(stderr, "Cannot write log file '%s' for pass-1 encoding: %s\n", logfilename, strerror(errno));
ffmpeg_exit(1);
}
ost->logfile = f;
} else {
char *logbuffer;
size_t logbuffer_size;
if (read_file(logfilename, &logbuffer, &logbuffer_size) < 0) {
fprintf(stderr, "Error reading log file '%s' for pass-2 encoding\n", logfilename);
ffmpeg_exit(1);
}
codec->stats_in = logbuffer;
}
}
}
if(codec->codec_type == AVMEDIA_TYPE_VIDEO){
/* maximum video buffer size is 6-bytes per pixel, plus DPX header size */
int size= codec->width * codec->height;
bit_buffer_size= FFMAX(bit_buffer_size, 6*size + 1664);
}
}
if (!bit_buffer)
bit_buffer = av_malloc(bit_buffer_size);
if (!bit_buffer) {
fprintf(stderr, "Cannot allocate %d bytes output buffer\n",
bit_buffer_size);
ret = AVERROR(ENOMEM);
goto fail;
}
/* open each encoder */
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
if (ost->encoding_needed) {
AVCodec *codec = ost->enc;
AVCodecContext *dec = input_streams[ost->source_index].st->codec;
if (!codec) {
snprintf(error, sizeof(error), "Encoder (codec id %d) not found for output stream #%d.%d",
ost->st->codec->codec_id, ost->file_index, ost->index);
ret = AVERROR(EINVAL);
goto dump_format;
}
if (dec->subtitle_header) {
ost->st->codec->subtitle_header = av_malloc(dec->subtitle_header_size);
if (!ost->st->codec->subtitle_header) {
ret = AVERROR(ENOMEM);
goto dump_format;
}
memcpy(ost->st->codec->subtitle_header, dec->subtitle_header, dec->subtitle_header_size);
ost->st->codec->subtitle_header_size = dec->subtitle_header_size;
}
if (avcodec_open(ost->st->codec, codec) < 0) {
snprintf(error, sizeof(error), "Error while opening encoder for output stream #%d.%d - maybe incorrect parameters such as bit_rate, rate, width or height",
ost->file_index, ost->index);
ret = AVERROR(EINVAL);
goto dump_format;
}
extra_size += ost->st->codec->extradata_size;
}
}
/* open each decoder */
for (i = 0; i < nb_input_streams; i++) {
ist = &input_streams[i];
if