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
/**
* @file
* multimedia converter based on the FFmpeg libraries
*/
#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/audioconvert.h"
#include "libavutil/audioconvert.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/colorspace.h"
#include "libavutil/fifo.h"
#include "libavutil/dict.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/avstring.h"
#include "libavutil/imgutils.h"
#include "libavformat/os_support.h"
#include "libavformat/ffm.h" // not public API
# include "libavfilter/avcodec.h"
# include "libavfilter/avfilter.h"
# include "libavfilter/avfiltergraph.h"
Stefano Sabatini
committed
# include "libavfilter/buffersink.h"
# include "libavfilter/buffersrc.h"
# include "libavfilter/vsrc_buffer.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
#if HAVE_TERMIOS_H
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
#elif HAVE_KBHIT
#define VSYNC_AUTO -1
#define VSYNC_PASSTHROUGH 0
#define VSYNC_CFR 1
#define VSYNC_VFR 2
const int program_birth_year = 2000;
int disabled; /** 1 is this mapping is disabled by a negative map */
int sync_file_index;
int sync_stream_index;
typedef struct {
int file_idx, stream_idx, channel_idx; // input
int ofile_idx, ostream_idx; // output
} AudioChannelMap;
Diego Pettenò
committed
static const OptionDef options[];
#define MAX_STREAMS 1024 /* arbitrary sanity check value */
static int frame_bits_per_raw_sample = 0;
static int video_discard = 0;
static int do_deinterlace = 0;
static const char *video_codec_name = NULL;
static const char *audio_codec_name = NULL;
static const char *subtitle_codec_name = NULL;
static int no_file_overwrite = 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 video_sync_method = VSYNC_AUTO;
static int audio_sync_method = 0;
static float audio_drift_threshold = 0.1;
static int copy_ts = 0;
static int copy_tb = -1;
static FILE *vstats_file;
Michael Niedermayer
committed
static int audio_volume = 256;
static int exit_on_error = 0;
static int using_stdin = 0;
static int run_as_daemon = 0;
static volatile int received_nb_signals = 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 float dts_delta_threshold = 10;
static float dts_error_threshold = 3600*30;
static int print_stats = 1;
static uint8_t *audio_buf;
static unsigned int allocated_audio_buf_size;
static uint8_t *async_buf;
static unsigned int allocated_async_buf_size;
#define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass"
typedef struct FrameBuffer {
uint8_t *base[4];
uint8_t *data[4];
int linesize[4];
int h, w;
enum PixelFormat pix_fmt;
int refcount;
struct InputStream *ist;
struct FrameBuffer *next;
} FrameBuffer;
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;
AVFrame *decoded_frame;
AVFrame *filtered_frame;
int64_t start; /* time when read started */
/* predicted dts of the next packet read for this stream or (when there are
* several frames in a packet) of the next frame in current packet */
int64_t next_dts;
/* dts of the last packet read for this stream */
int64_t dts;
int64_t next_pts; ///< synthetic pts for the next decode frame
int64_t pts; ///< current pts of the decoded frame
double ts_scale;
int is_start; /* is 1 at the start and after a discontinuity */
int showed_multi_packet_warning;
AVDictionary *opts;
/* a pool of free buffers for decoded data */
FrameBuffer *buffer_pool;
Michael Niedermayer
committed
int dr1;
} InputStream;
typedef struct InputFile {
AVFormatContext *ctx;
int eof_reached; /* true if eof reached */
int ist_index; /* index of first stream in input_streams */
int buffer_size; /* current total buffer size */
int64_t ts_offset;
int nb_streams; /* number of stream that ffmpeg is aware of; may be different
from ctx.nb_streams if new streams appear during av_read_frame() */
typedef struct OutputStream {
int file_index; /* file index */
int index; /* stream index in the output file */
int source_index; /* InputStream index */
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 */
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;
AVFrame *output_frame;
int video_resample;
Jason Garrett-Glaser
committed
int resample_pix_fmt;
AVRational frame_rate;
int force_fps;
int top_field_first;
/* forced key frames */
int64_t *forced_kf_pts;
int forced_kf_count;
int forced_kf_index;
int audio_channels_map[SWR_CH_MAX]; ///< list of the channels id to pick from the source stream
int audio_channels_mapped; ///< number of channels in audio_channels_map
int resample_sample_fmt;
int resample_channels;
int resample_sample_rate;
float rematrix_volume;
Michael Niedermayer
committed
AVFifoBuffer *fifo; /* for compression: one audio fifo per codec */
AVFilterContext *output_video_filter;
AVFilterContext *input_video_filter;
char *avfilter;
AVFilterGraph *graph;
int64_t swr_dither_method;
double swr_dither_scale;
AVDictionary *opts;
int is_past_recording_time;
int stream_copy;
const char *attachment_filename;
int copy_initial_nonkeyframes;
#if HAVE_TERMIOS_H
/* init terminal so that we can grab keys */
static struct termios oldtty;
#endif
Anton Khirnov
committed
typedef struct OutputFile {
AVFormatContext *ctx;
AVDictionary *opts;
int ost_index; /* index of the first stream in output_streams */
int64_t recording_time; /* desired length of the resulting file in microseconds */
int64_t start_time; /* start time in microseconds */
uint64_t limit_filesize; /* filesize limit expressed in bytes */
Anton Khirnov
committed
} OutputFile;
static InputStream *input_streams = NULL;
static int nb_input_streams = 0;
static InputFile *input_files = NULL;
static int nb_input_files = 0;
static OutputStream *output_streams = NULL;
static int nb_output_streams = 0;
Anton Khirnov
committed
static OutputFile *output_files = NULL;
static int nb_output_files = 0;
typedef struct OptionsContext {
/* input/output options */
int64_t start_time;
const char *format;
SpecifierOpt *codec_names;
int nb_codec_names;
SpecifierOpt *audio_channels;
int nb_audio_channels;
SpecifierOpt *audio_sample_rate;
int nb_audio_sample_rate;
SpecifierOpt *rematrix_volume;
int nb_rematrix_volume;
SpecifierOpt *frame_rates;
int nb_frame_rates;
SpecifierOpt *frame_sizes;
int nb_frame_sizes;
SpecifierOpt *frame_pix_fmts;
int nb_frame_pix_fmts;
/* input options */
int64_t input_ts_offset;
int rate_emu;
SpecifierOpt *ts_scale;
int nb_ts_scale;
SpecifierOpt *dump_attachment;
int nb_dump_attachment;
/* output options */
StreamMap *stream_maps;
int nb_stream_maps;
AudioChannelMap *audio_channel_maps; ///< one info entry per -map_channel
int nb_audio_channel_maps; ///< number of (valid) -map_channel settings
int metadata_global_manual;
int metadata_streams_manual;
int metadata_chapters_manual;
const char **attachments;
int nb_attachments;
int chapters_input_file;
int64_t recording_time;
uint64_t limit_filesize;
float mux_preload;
float mux_max_delay;
int video_disable;
int audio_disable;
int subtitle_disable;
int data_disable;
/* indexed by output file stream index */
int *streamid_map;
int nb_streamid_map;
SpecifierOpt *metadata;
int nb_metadata;
SpecifierOpt *max_frames;
int nb_max_frames;
SpecifierOpt *bitstream_filters;
int nb_bitstream_filters;
SpecifierOpt *codec_tags;
int nb_codec_tags;
SpecifierOpt *sample_fmts;
int nb_sample_fmts;
SpecifierOpt *qscale;
int nb_qscale;
SpecifierOpt *forced_key_frames;
int nb_forced_key_frames;
SpecifierOpt *force_fps;
int nb_force_fps;
SpecifierOpt *frame_aspect_ratios;
int nb_frame_aspect_ratios;
SpecifierOpt *rc_overrides;
int nb_rc_overrides;
SpecifierOpt *intra_matrices;
int nb_intra_matrices;
SpecifierOpt *inter_matrices;
int nb_inter_matrices;
SpecifierOpt *top_field_first;
int nb_top_field_first;
SpecifierOpt *metadata_map;
int nb_metadata_map;
SpecifierOpt *presets;
int nb_presets;
SpecifierOpt *copy_initial_nonkeyframes;
int nb_copy_initial_nonkeyframes;
SpecifierOpt *filters;
int nb_filters;
#define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\
{\
int i, ret;\
for (i = 0; i < o->nb_ ## name; i++) {\
char *spec = o->name[i].specifier;\
if ((ret = check_stream_specifier(fmtctx, st, spec)) > 0)\
outvar = o->name[i].u.type;\
else if (ret < 0)\
exit_program(1);\
}\
}
static int64_t getutime(void)
{
#if HAVE_GETRUSAGE
struct rusage rusage;
getrusage(RUSAGE_SELF, &rusage);
return (rusage.ru_utime.tv_sec * 1000000LL) + rusage.ru_utime.tv_usec;
#elif HAVE_GETPROCESSTIMES
HANDLE proc;
FILETIME c, e, k, u;
proc = GetCurrentProcess();
GetProcessTimes(proc, &c, &e, &k, &u);
return ((int64_t) u.dwHighDateTime << 32 | u.dwLowDateTime) / 10;
#else
return av_gettime();
#endif
}
static void update_benchmark(const char *fmt, ...)
{
if (do_benchmark_all) {
int64_t t = getutime();
va_list va;
char buf[1024];
if (fmt) {
va_start(va, fmt);
vsnprintf(buf, sizeof(buf), fmt, va);
va_end(va);
printf("bench: %8"PRIu64" %s \n", t - current_time, buf);
}
current_time = t;
}
}
static void reset_options(OptionsContext *o, int is_input)
{
const OptionDef *po = options;
OptionsContext bak= *o;
/* all OPT_SPEC and OPT_STRING can be freed in generic way */
while (po->name) {
void *dst = (uint8_t*)o + po->u.off;
if (po->flags & OPT_SPEC) {
SpecifierOpt **so = dst;
int i, *count = (int*)(so + 1);
for (i = 0; i < *count; i++) {
av_freep(&(*so)[i].specifier);
if (po->flags & OPT_STRING)
av_freep(&(*so)[i].u.str);
}
av_freep(so);
*count = 0;
} else if (po->flags & OPT_OFFSET && po->flags & OPT_STRING)
av_freep(dst);
po++;
}
av_freep(&o->stream_maps);
av_freep(&o->streamid_map);
memset(o, 0, sizeof(*o));
if(is_input) o->recording_time = bak.recording_time;
else o->recording_time = INT64_MAX;
o->mux_max_delay = 0.7;
o->limit_filesize = UINT64_MAX;
o->chapters_input_file = INT_MAX;
uninit_opts();
init_opts();
}
static int alloc_buffer(InputStream *ist, AVCodecContext *s, FrameBuffer **pbuf)
{
FrameBuffer *buf = av_mallocz(sizeof(*buf));
const int pixel_size = av_pix_fmt_descriptors[s->pix_fmt].comp[0].step_minus1+1;
int h_chroma_shift, v_chroma_shift;
int edge = 32; // XXX should be avcodec_get_edge_width(), but that fails on svq1
int w = s->width, h = s->height;
if (!buf)
return AVERROR(ENOMEM);
if (!(s->flags & CODEC_FLAG_EMU_EDGE)) {
w += 2*edge;
h += 2*edge;
}
avcodec_align_dimensions(s, &w, &h);
if ((ret = av_image_alloc(buf->base, buf->linesize, w, h,
s->pix_fmt, 32)) < 0) {
av_freep(&buf);
return ret;
}
/* XXX this shouldn't be needed, but some tests break without this line
* those decoders are buggy and need to be fixed.
* the following tests fail:
* cdgraphics, ansi, aasc, fraps-v1, qtrle-1bit
*/
memset(buf->base[0], 128, ret);
avcodec_get_chroma_sub_sample(s->pix_fmt, &h_chroma_shift, &v_chroma_shift);
for (i = 0; i < FF_ARRAY_ELEMS(buf->data); i++) {
const int h_shift = i==0 ? 0 : h_chroma_shift;
const int v_shift = i==0 ? 0 : v_chroma_shift;
if ((s->flags & CODEC_FLAG_EMU_EDGE) || !buf->linesize[1])
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
buf->data[i] = buf->base[i];
else
buf->data[i] = buf->base[i] +
FFALIGN((buf->linesize[i]*edge >> v_shift) +
(pixel_size*edge >> h_shift), 32);
}
buf->w = s->width;
buf->h = s->height;
buf->pix_fmt = s->pix_fmt;
buf->ist = ist;
*pbuf = buf;
return 0;
}
static void free_buffer_pool(InputStream *ist)
{
FrameBuffer *buf = ist->buffer_pool;
while (buf) {
ist->buffer_pool = buf->next;
av_freep(&buf->base[0]);
av_free(buf);
buf = ist->buffer_pool;
}
}
static void unref_buffer(InputStream *ist, FrameBuffer *buf)
{
av_assert0(buf->refcount);
buf->refcount--;
if (!buf->refcount) {
buf->next = ist->buffer_pool;
ist->buffer_pool = buf;
}
}
static int codec_get_buffer(AVCodecContext *s, AVFrame *frame)
{
InputStream *ist = s->opaque;
FrameBuffer *buf;
int ret, i;
if(av_image_check_size(s->width, s->height, 0, s) || s->pix_fmt<0)
if (!ist->buffer_pool && (ret = alloc_buffer(ist, s, &ist->buffer_pool)) < 0)
return ret;
buf = ist->buffer_pool;
ist->buffer_pool = buf->next;
buf->next = NULL;
if (buf->w != s->width || buf->h != s->height || buf->pix_fmt != s->pix_fmt) {
av_freep(&buf->base[0]);
av_free(buf);
if ((ret = alloc_buffer(ist, s, &buf)) < 0)
return ret;
}
buf->refcount++;
frame->opaque = buf;
frame->type = FF_BUFFER_TYPE_USER;
frame->extended_data = frame->data;
frame->pkt_pts = s->pkt ? s->pkt->pts : AV_NOPTS_VALUE;
frame->width = buf->w;
frame->height = buf->h;
frame->format = buf->pix_fmt;
frame->sample_aspect_ratio = s->sample_aspect_ratio;
for (i = 0; i < FF_ARRAY_ELEMS(buf->data); i++) {
frame->base[i] = buf->base[i]; // XXX h264.c uses base though it shouldn't
frame->data[i] = buf->data[i];
frame->linesize[i] = buf->linesize[i];
}
return 0;
}
static void codec_release_buffer(AVCodecContext *s, AVFrame *frame)
{
InputStream *ist = s->opaque;
FrameBuffer *buf = frame->opaque;
int i;
if(frame->type!=FF_BUFFER_TYPE_USER)
return avcodec_default_release_buffer(s, frame);
for (i = 0; i < FF_ARRAY_ELEMS(frame->data); i++)
frame->data[i] = NULL;
unref_buffer(ist, buf);
}
static void filter_release_buffer(AVFilterBuffer *fb)
{
FrameBuffer *buf = fb->priv;
av_free(fb);
unref_buffer(buf->ist, buf);
}
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 };
AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc();
AVRational sample_aspect_ratio;
int ret;
ost->graph = avfilter_graph_alloc();
if (!ost->graph)
return AVERROR(ENOMEM);
if (ist->st->sample_aspect_ratio.num) {
sample_aspect_ratio = ist->st->sample_aspect_ratio;
sample_aspect_ratio = ist->st->codec->sample_aspect_ratio;
snprintf(args, 255, "%d:%d:%d:%d:%d:%d:%d:flags=%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, SWS_BILINEAR + ((icodec->flags&CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0));
ret = avfilter_graph_create_filter(&ost->input_video_filter, avfilter_get_by_name("buffer"),
"src", args, NULL, ost->graph);
return ret;
#if FF_API_OLD_VSINK_API
ret = avfilter_graph_create_filter(&ost->output_video_filter, avfilter_get_by_name("buffersink"),
"out", NULL, pix_fmts, ost->graph);
#else
buffersink_params->pixel_fmts = pix_fmts;
ret = avfilter_graph_create_filter(&ost->output_video_filter, avfilter_get_by_name("buffersink"),
"out", NULL, buffersink_params, ost->graph);
#endif
av_freep(&buffersink_params);
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,
(unsigned)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", (unsigned)ost->sws_flags);
ost->graph->scale_sws_opts = av_strdup(args);
if (ost->avfilter) {
AVFilterInOut *outputs = avfilter_inout_alloc();
AVFilterInOut *inputs = avfilter_inout_alloc();
Stefano Sabatini
committed
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);
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 ? // overridden 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;
av_log(NULL, AV_LOG_QUIET, "%s", "");
#if HAVE_TERMIOS_H
tcsetattr (0, TCSANOW, &oldtty);
static volatile int received_sigterm = 0;
Roumen Petrov
committed
static void sigterm_handler(int sig)
Roumen Petrov
committed
{
received_sigterm = sig;
received_nb_signals++;
Roumen Petrov
committed
term_exit();
if(received_nb_signals > 3)
exit(123);
Roumen Petrov
committed
}
#if HAVE_TERMIOS_H
if(!run_as_daemon){
struct termios 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). */
avformat_network_deinit();
signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */
Roumen Petrov
committed
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;
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);
if (n > 0) {
n = read(0, &ch, 1);
if (n == 1)
return ch;
return n;
}
#elif HAVE_KBHIT
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
# if HAVE_PEEKNAMEDPIPE
static int is_pipe;
static HANDLE input_handle;
DWORD dw, nchars;
if(!input_handle){
input_handle = GetStdHandle(STD_INPUT_HANDLE);
is_pipe = !GetConsoleMode(input_handle, &dw);
}
if (stdin->_cnt > 0) {
read(0, &ch, 1);
return ch;
}
if (is_pipe) {
/* When running under a GUI, you will end here. */
if (!PeekNamedPipe(input_handle, NULL, 0, NULL, &nchars, NULL))
return -1;
//Read it
if(nchars != 0) {
read(0, &ch, 1);
return ch;
}else{
return -1;
}
}
# endif
static int decode_interrupt_cb(void *ctx)
Leon van Stuivenberg
committed
{
return received_nb_signals > 1;
Leon van Stuivenberg
committed
}
static const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL };
{
int i;
/* close files */
for (i = 0; i < nb_output_files; i++) {
Anton Khirnov
committed
AVFormatContext *s = output_files[i].ctx;
if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)
avformat_free_context(s);
Anton Khirnov
committed
av_dict_free(&output_files[i].opts);
for (i = 0; i < nb_output_streams; i++) {
AVBitStreamFilterContext *bsfc = output_streams[i].bitstream_filters;
while (bsfc) {
AVBitStreamFilterContext *next = bsfc->next;
av_bitstream_filter_close(bsfc);
bsfc = next;
}
output_streams[i].bitstream_filters = NULL;
if (output_streams[i].output_frame) {
AVFrame *frame = output_streams[i].output_frame;
if (frame->extended_data != frame->data)
av_freep(&frame->extended_data);
av_freep(&frame);
}
for (i = 0; i < nb_input_files; i++) {
avformat_close_input(&input_files[i].ctx);
for (i = 0; i < nb_input_streams; i++) {
av_freep(&input_streams[i].decoded_frame);
av_freep(&input_streams[i].filtered_frame);
av_dict_free(&input_streams[i].opts);
free_buffer_pool(&input_streams[i]);
if (vstats_file)
fclose(vstats_file);
av_free(vstats_filename);
av_freep(&input_streams);
av_freep(&input_files);
av_freep(&output_streams);
Anton Khirnov
committed
av_freep(&output_files);
uninit_opts();
allocated_audio_buf_size = 0;
allocated_async_buf_size = 0;
avformat_network_deinit();
if (received_sigterm) {
av_log(NULL, AV_LOG_INFO, "Received signal %d: terminating.\n",
(int) received_sigterm);
exit(ret); /* not all OS-es handle main() return value */
static void assert_avoptions(AVDictionary *m)
{
AVDictionaryEntry *t;
if ((t = av_dict_get(m, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
av_log(NULL, AV_LOG_FATAL, "Option %s not found.\n", t->key);
static void assert_codec_experimental(AVCodecContext *c, int encoder)
{
const char *codec_string = encoder ? "encoder" : "decoder";
AVCodec *codec;
if (c->codec->capabilities & CODEC_CAP_EXPERIMENTAL &&
c->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
av_log(NULL, AV_LOG_FATAL, "%s '%s' is experimental and might produce bad "
"results.\nAdd '-strict experimental' if you want to use it.\n",
codec_string, c->codec->name);
codec = encoder ? avcodec_find_encoder(c->codec->id) : avcodec_find_decoder(c->codec->id);
if (!(codec->capabilities & CODEC_CAP_EXPERIMENTAL))
av_log(NULL, AV_LOG_FATAL, "Or use the non experimental %s '%s'.\n",
codec_string, codec->name);
Ronald S. Bultje
committed
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)
Ronald S. Bultje
committed
break;
}
if (*p == -1) {
Michael Niedermayer
committed
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, "Conversion will not be lossless.\n");
if(av_get_sample_fmt_name(st->codec->sample_fmt))
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]));
Ronald S. Bultje
committed
st->codec->sample_fmt = codec->sample_fmts[0];
}
Ronald S. Bultje
committed
}
}
Michael Niedermayer
committed
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;
Michael Niedermayer
committed
}
}
int i;
const int *sample_rates = codec->supported_samplerates;
av_log(st->codec, AV_LOG_WARNING,
"Requested sampling rate (%dHz) unsupported, using %dHz instead\n"
"Available sampling rates for %s:",
st->codec->sample_rate, best, codec->name);
for (i = 0; sample_rates[i]; i++) {
if (!sample_rates[i + 1]) av_log(st->codec, AV_LOG_WARNING, " and");
else if (i) av_log(st->codec, AV_LOG_WARNING, ",");
av_log(st->codec, AV_LOG_WARNING, " %d", sample_rates[i]);
}
av_log(st->codec, AV_LOG_WARNING, ".\n");
st->codec->sample_rate = best;
Michael Niedermayer
committed
}
}
Ronald S. Bultje
committed
static void choose_pixel_fmt(AVStream *st, AVCodec *codec)
{
if (codec && codec->pix_fmts) {
const enum PixelFormat *p = codec->pix_fmts;
int has_alpha= av_pix_fmt_descriptors[st->codec->pix_fmt].nb_components % 2 == 0;
enum PixelFormat best= PIX_FMT_NONE;
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 != PIX_FMT_NONE; p++) {
best= avcodec_find_best_pix_fmt2(best, *p, st->codec->pix_fmt, has_alpha, NULL);
if (*p == st->codec->pix_fmt)