Skip to content
Snippets Groups Projects
ffmpeg.c 220 KiB
Newer Older
Fabrice Bellard's avatar
Fabrice Bellard committed
/*
Fabrice Bellard's avatar
Fabrice Bellard committed
 * Copyright (c) 2000-2003 Fabrice Bellard
Fabrice Bellard's avatar
Fabrice Bellard 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
 * version 2.1 of the License, or (at your option) any later version.
Fabrice Bellard's avatar
Fabrice Bellard committed
 *
 * FFmpeg is distributed in the hope that it will be useful,
Fabrice Bellard's avatar
Fabrice Bellard committed
 * 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.
Fabrice Bellard's avatar
Fabrice Bellard committed
 *
 * 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
Fabrice Bellard's avatar
Fabrice Bellard 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>
#include <signal.h>
#include <limits.h>
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavutil/opt.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/avstring.h"
#include "libavutil/libm.h"
#include "libavutil/imgutils.h"
#include "libavutil/timestamp.h"
#include "libavformat/os_support.h"
Michael Niedermayer's avatar
Michael Niedermayer committed
#include "libswresample/swresample.h"
#include "libavformat/ffm.h" // not public API

# include "libavfilter/avcodec.h"
# include "libavfilter/avfilter.h"
# include "libavfilter/avfiltergraph.h"
# include "libavfilter/buffersrc.h"
#if HAVE_SYS_RESOURCE_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>
Fabrice Bellard's avatar
Fabrice Bellard committed
#endif
#include <time.h>
Fabrice Bellard's avatar
Fabrice Bellard committed

Fabrice Bellard's avatar
Fabrice Bellard committed
#include "cmdutils.h"

#include "libavutil/avassert.h"
#define VSYNC_AUTO       -1
#define VSYNC_PASSTHROUGH 0
#define VSYNC_CFR         1
#define VSYNC_VFR         2
Reimar Döffinger's avatar
Reimar Döffinger committed
#define VSYNC_DROP        0xff
const char program_name[] = "ffmpeg";
const int program_birth_year = 2000;
Fabrice Bellard's avatar
Fabrice Bellard committed
/* select an input stream for an output stream */
typedef struct StreamMap {
    int disabled;           /** 1 is this mapping is disabled by a negative map */
Fabrice Bellard's avatar
Fabrice Bellard committed
    int file_index;
    int stream_index;
    int sync_file_index;
    int sync_stream_index;
    char *linklabel;       /** name of an output link, for mapping lavfi outputs */
Fabrice Bellard's avatar
Fabrice Bellard committed

typedef struct {
    int  file_idx,  stream_idx,  channel_idx; // input
    int ofile_idx, ostream_idx;               // output
} AudioChannelMap;

Fabrice Bellard's avatar
Fabrice Bellard committed

#define MAX_STREAMS 1024    /* arbitrary sanity check value */
static int frame_bits_per_raw_sample = 0;
static int video_discard = 0;
static int same_quant = 0;
static int do_deinterlace = 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
static int intra_dc_precision = 8;
static int qp_hist = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
static int intra_only = 0;
static const char *video_codec_name    = NULL;
static const char *audio_codec_name    = NULL;
static const char *subtitle_codec_name = NULL;
Fabrice Bellard's avatar
Fabrice Bellard committed

static int file_overwrite = 0;
static int no_file_overwrite = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
static int do_benchmark = 0;
static int do_benchmark_all = 0;
static int do_hex_dump = 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 int opt_shortest = 0;
static char *vstats_filename;
static FILE *vstats_file;
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 float dts_delta_threshold = 10;
static float dts_error_threshold = 3600*30;
static int print_stats = 1;
static int debug_ts = 0;
static int current_time;
static unsigned int allocated_audio_buf_size;
static uint8_t *async_buf;
static unsigned int allocated_async_buf_size;
Stefano Sabatini's avatar
Stefano Sabatini committed
#define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass"
Fabrice Bellard's avatar
Fabrice Bellard committed

typedef struct InputFilter {
    AVFilterContext    *filter;
    struct InputStream *ist;
    struct FilterGraph *graph;
} InputFilter;

typedef struct OutputFilter {
    AVFilterContext     *filter;
    struct OutputStream *ost;
    struct FilterGraph  *graph;

    /* temporary storage until stream maps are processed */
    AVFilterInOut       *out_tmp;
} OutputFilter;

typedef struct FilterGraph {
    int            index;
    const char    *graph_desc;

    AVFilterGraph *graph;

    InputFilter   **inputs;
    int          nb_inputs;
    OutputFilter **outputs;
    int         nb_outputs;
} FilterGraph;

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;

    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;
    int resample_height;
    int resample_width;
    int resample_pix_fmt;

    /* a pool of free buffers for decoded data */
    FrameBuffer *buffer_pool;

    /* decoded data from this stream goes into all those filters
     * currently video only */
    InputFilter **filters;
    int        nb_filters;
} 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() */
} InputFile;
typedef struct OutputStream {
Fabrice Bellard's avatar
Fabrice Bellard committed
    int file_index;          /* file index */
    int index;               /* stream index in the output file */
    int source_index;        /* InputStream index */
Fabrice Bellard's avatar
Fabrice Bellard committed
    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 */
    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;
    int64_t max_frames;
    AVFrame *output_frame;
Fabrice Bellard's avatar
Fabrice Bellard committed
    /* video only */
    int force_fps;
    int top_field_first;
    float frame_aspect_ratio;
    float last_quality;
    /* forced key frames */
    int64_t *forced_kf_pts;
    int forced_kf_count;
    int forced_kf_index;

Fabrice Bellard's avatar
Fabrice Bellard committed
    /* audio only */
    int audio_resample;
    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;
    uint64_t resample_channel_layout;
    AVFifoBuffer *fifo;     /* for compression: one audio fifo per codec */
    SwrContext *swr;
    OutputFilter *filter;
    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;

    enum PixelFormat pix_fmts[2];
} OutputStream;
Fabrice Bellard's avatar
Fabrice Bellard committed


#if HAVE_TERMIOS_H

/* init terminal so that we can grab keys */
static struct termios oldtty;
static int restore_tty;
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 */
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;
static OutputFile   **output_files   = NULL;
static int         nb_output_files   = 0;
static FilterGraph **filtergraphs;
int               nb_filtergraphs;
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;

    /* 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++;
    }

    for (i = 0; i < o->nb_stream_maps; i++)
        av_freep(&o->stream_maps[i].linklabel);
    av_freep(&o->stream_maps);
    av_freep(&o->audio_channel_maps);
    av_freep(&o->streamid_map);
    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;
static int alloc_buffer(InputStream *ist, AVCodecContext *s, FrameBuffer **pbuf)
{
    FrameBuffer  *buf = av_mallocz(sizeof(*buf));
    int i, ret;
    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;
    }

    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] || !buf->base[i])
            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 > 0);
    buf->refcount--;
    if (!buf->refcount) {
        FrameBuffer *tmp;
        for(tmp= ist->buffer_pool; tmp; tmp= tmp->next)
            av_assert1(tmp != buf);
        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)
    av_assert0(!buf->refcount);
    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 enum PixelFormat choose_pixel_fmt(AVStream *st, AVCodec *codec, enum PixelFormat target)
    if (codec && codec->pix_fmts) {
        const enum PixelFormat *p = codec->pix_fmts;
        int has_alpha= av_pix_fmt_descriptors[target].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, target, has_alpha, NULL);
            if (*p == target)
            if (target != 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[target].name,
                       codec->name,
                       av_pix_fmt_descriptors[best].name);
static char *choose_pixel_fmts(OutputStream *ost)
{
    if (ost->st->codec->pix_fmt != PIX_FMT_NONE) {
        return av_strdup(av_get_pix_fmt_name(choose_pixel_fmt(ost->st, ost->enc, ost->st->codec->pix_fmt)));
    } else if (ost->enc->pix_fmts) {
        const enum PixelFormat *p;
        AVIOContext *s = NULL;
        uint8_t *ret;
        int len;

        if (avio_open_dyn_buf(&s) < 0)
            exit_program(1);

        p = ost->enc->pix_fmts;
        if (ost->st->codec->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
            if (ost->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 (ost->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++)
            avio_printf(s, "%s:", av_get_pix_fmt_name(*p));
        len = avio_close_dyn_buf(s, &ret);
        ret[len - 1] = 0;
        return ret;
static int configure_video_filters(FilterGraph *fg)
    InputStream  *ist = fg->inputs[0]->ist;
    OutputStream *ost = fg->outputs[0]->ost;
    AVFilterContext *in_filter, *out_filter, *filter;
    AVCodecContext *codec = ost->st->codec;
    AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc();
    AVRational sample_aspect_ratio;
    char args[255];
    avfilter_graph_free(&fg->graph);
    fg->graph = avfilter_graph_alloc();
    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 + ((ist->st->codec->flags&CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0));
    ret = avfilter_graph_create_filter(&fg->inputs[0]->filter,
                                       avfilter_get_by_name("buffer"),
                                       "src", args, NULL, fg->graph);
    if (ret < 0)
#if FF_API_OLD_VSINK_API
    ret = avfilter_graph_create_filter(&fg->outputs[0]->filter,
                                       avfilter_get_by_name("buffersink"),
                                       "out", NULL, NULL, fg->graph);
    ret = avfilter_graph_create_filter(&fg->outputs[0]->filter,
                                       avfilter_get_by_name("buffersink"),
                                       "out", NULL, buffersink_params, fg->graph);
#endif
    av_freep(&buffersink_params);
    if (ret < 0)
    in_filter  = fg->inputs[0]->filter;
    out_filter = fg->outputs[0]->filter;
    if (codec->width || codec->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, fg->graph)) < 0)
        if ((ret = avfilter_link(in_filter, 0, filter, 0)) < 0)
        in_filter = filter;
    }

    if ((pix_fmts = choose_pixel_fmts(ost))) {
        if ((ret = avfilter_graph_create_filter(&filter,
                                                avfilter_get_by_name("format"),
                                                "format", pix_fmts, NULL,
                                                fg->graph)) < 0)
            return ret;
        if ((ret = avfilter_link(filter, 0, out_filter, 0)) < 0)
            return ret;

        out_filter = filter;
        av_freep(&pix_fmts);
    snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags);
    fg->graph->scale_sws_opts = av_strdup(args);
        AVFilterInOut *outputs = avfilter_inout_alloc();
        AVFilterInOut *inputs  = avfilter_inout_alloc();

        outputs->name    = av_strdup("in");
        outputs->filter_ctx = in_filter;
        outputs->pad_idx = 0;
        outputs->next    = NULL;

        inputs->name    = av_strdup("out");
        inputs->filter_ctx = out_filter;
        inputs->pad_idx = 0;
        inputs->next    = NULL;

        if ((ret = avfilter_graph_parse(fg->graph, ost->avfilter, &inputs, &outputs, NULL)) < 0)
        av_freep(&ost->avfilter);
        if ((ret = avfilter_link(in_filter, 0, out_filter, 0)) < 0)
    if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0)
    ost->filter = fg->outputs[0];
static FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost)
{
    FilterGraph *fg = av_mallocz(sizeof(*fg));

    if (!fg)
        exit_program(1);
    fg->index = nb_filtergraphs;

    fg->outputs = grow_array(fg->outputs, sizeof(*fg->outputs), &fg->nb_outputs,
                             fg->nb_outputs + 1);
    if (!(fg->outputs[0] = av_mallocz(sizeof(*fg->outputs[0]))))
        exit_program(1);
    fg->outputs[0]->ost   = ost;
    fg->outputs[0]->graph = fg;

    fg->inputs = grow_array(fg->inputs, sizeof(*fg->inputs), &fg->nb_inputs,
                            fg->nb_inputs + 1);
    if (!(fg->inputs[0] = av_mallocz(sizeof(*fg->inputs[0]))))
        exit_program(1);
    fg->inputs[0]->ist   = ist;
    fg->inputs[0]->graph = fg;

    ist->filters = grow_array(ist->filters, sizeof(*ist->filters),
                              &ist->nb_filters, ist->nb_filters + 1);
    ist->filters[ist->nb_filters - 1] = fg->inputs[0];

    filtergraphs = grow_array(filtergraphs, sizeof(*filtergraphs),
                              &nb_filtergraphs, nb_filtergraphs + 1);
    filtergraphs[nb_filtergraphs - 1] = fg;

    return fg;
}

static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
{
    InputStream *ist;
    enum AVMediaType type = in->filter_ctx->input_pads[in->pad_idx].type;
    int i;

    // TODO: support other filter types
    if (type != AVMEDIA_TYPE_VIDEO) {
        av_log(NULL, AV_LOG_FATAL, "Only video filters supported currently.\n");
        exit_program(1);
    }

    if (in->name) {
        AVFormatContext *s;
        AVStream       *st = NULL;
        char *p;
        int file_idx = strtol(in->name, &p, 0);

        if (file_idx < 0 || file_idx >= nb_input_files) {
            av_log(NULL, AV_LOG_FATAL, "Invalid file index %d in filtergraph description %s.\n",
                   file_idx, fg->graph_desc);
            exit_program(1);
        }
        s = input_files[file_idx]->ctx;

        for (i = 0; i < s->nb_streams; i++) {
            if (s->streams[i]->codec->codec_type != type)
                continue;
            if (check_stream_specifier(s, s->streams[i], *p == ':' ? p + 1 : p) == 1) {
                st = s->streams[i];
                break;
            }
        }
        if (!st) {
            av_log(NULL, AV_LOG_FATAL, "Stream specifier '%s' in filtergraph description %s "
                   "matches no streams.\n", p, fg->graph_desc);
            exit_program(1);
        }
        ist = input_streams[input_files[file_idx]->ist_index + st->index];
    } else {
        /* find the first unused stream of corresponding type */
        for (i = 0; i < nb_input_streams; i++) {
            ist = input_streams[i];
            if (ist->st->codec->codec_type == type && ist->discard)
                break;
        }
        if (i == nb_input_streams) {
            av_log(NULL, AV_LOG_FATAL, "Cannot find a matching stream for "
                   "unlabeled input pad %d on filter %s", in->pad_idx,
                   in->filter_ctx->name);
            exit_program(1);
        }
    }
    ist->discard         = 0;
    ist->decoding_needed = 1;
    ist->st->discard = AVDISCARD_NONE;

    fg->inputs = grow_array(fg->inputs, sizeof(*fg->inputs),
                            &fg->nb_inputs, fg->nb_inputs + 1);
    if (!(fg->inputs[fg->nb_inputs - 1] = av_mallocz(sizeof(*fg->inputs[0]))))
        exit_program(1);
    fg->inputs[fg->nb_inputs - 1]->ist   = ist;
    fg->inputs[fg->nb_inputs - 1]->graph = fg;

    ist->filters = grow_array(ist->filters, sizeof(*ist->filters),
                              &ist->nb_filters, ist->nb_filters + 1);
    ist->filters[ist->nb_filters - 1] = fg->inputs[fg->nb_inputs - 1];
}

static int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
{
    AVCodecContext *codec = ofilter->ost->st->codec;
    AVFilterContext *last_filter = out->filter_ctx;
    int pad_idx = out->pad_idx;
    int ret;
    AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc();
    ret = avfilter_graph_create_filter(&ofilter->filter,
                                       avfilter_get_by_name("buffersink"),
                                       "out", NULL, NULL, fg->graph);
    ret = avfilter_graph_create_filter(&ofilter->filter,
                                       avfilter_get_by_name("buffersink"),
                                       "out", NULL, buffersink_params, fg->graph);
#endif
    av_freep(&buffersink_params);

    if (ret < 0)
        return ret;

    if (codec->width || codec->height) {
        char args[255];
        snprintf(args, sizeof(args), "%d:%d:flags=0x%X",
                 codec->width,
                 codec->height,
                 (unsigned)ofilter->ost->sws_flags);
        if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"),
                                                NULL, args, NULL, fg->graph)) < 0)
            return ret;
        if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0)
    if ((pix_fmts = choose_pixel_fmts(ofilter->ost))) {
        AVFilterContext *filter;
        if ((ret = avfilter_graph_create_filter(&filter,
                                                avfilter_get_by_name("format"),
                                                "format", pix_fmts, NULL,
                                                fg->graph)) < 0)
            return ret;
        if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0)
            return ret;

        last_filter = filter;
        pad_idx     = 0;
        av_freep(&pix_fmts);
    }

    if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
        return ret;

    return 0;
}

static int configure_complex_filter(FilterGraph *fg)
{
    AVFilterInOut *inputs, *outputs, *cur;
    int ret, i, init = !fg->graph;

    avfilter_graph_free(&fg->graph);
    if (!(fg->graph = avfilter_graph_alloc()))
        return AVERROR(ENOMEM);

    if ((ret = avfilter_graph_parse2(fg->graph, fg->graph_desc, &inputs, &outputs)) < 0)
        return ret;

    for (cur = inputs; init && cur; cur = cur->next)
        init_input_filter(fg, cur);

    for (cur = inputs, i = 0; cur; cur = cur->next, i++) {
        InputFilter *ifilter = fg->inputs[i];
        InputStream     *ist = ifilter->ist;
        AVRational       sar;
        char            args[255];

        sar = ist->st->sample_aspect_ratio.num ? ist->st->sample_aspect_ratio :
                                                 ist->st->codec->sample_aspect_ratio;
        snprintf(args, sizeof(args), "%d:%d:%d:%d:%d:%d:%d", ist->st->codec->width,
                 ist->st->codec->height, ist->st->codec->pix_fmt, 1, AV_TIME_BASE,
                 sar.num, sar.den);

        if ((ret = avfilter_graph_create_filter(&ifilter->filter,
                                                avfilter_get_by_name("buffer"), cur->name,
                                                args, NULL, fg->graph)) < 0)
            return ret;
        if ((ret = avfilter_link(ifilter->filter, 0,
                                 cur->filter_ctx, cur->pad_idx)) < 0)
            return ret;
    }
    avfilter_inout_free(&inputs);

    if (!init) {
        /* we already know the mappings between lavfi outputs and output streams,
         * so we can finish the setup */
        for (cur = outputs, i = 0; cur; cur = cur->next, i++)
            configure_output_filter(fg, fg->outputs[i], cur);
        avfilter_inout_free(&outputs);

        if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0)
            return ret;
    } else {
        /* wait until output mappings are processed */
        for (cur = outputs; cur;) {
            fg->outputs = grow_array(fg->outputs, sizeof(*fg->outputs),
                                     &fg->nb_outputs, fg->nb_outputs + 1);
            if (!(fg->outputs[fg->nb_outputs - 1] = av_mallocz(sizeof(*fg->outputs[0]))))
                exit_program(1);
            fg->outputs[fg->nb_outputs - 1]->graph   = fg;
            fg->outputs[fg->nb_outputs - 1]->out_tmp = cur;
            cur = cur->next;
            fg->outputs[fg->nb_outputs - 1]->out_tmp->next = NULL;
        }
    }

    return 0;
}

static int configure_complex_filters(void)
{
    int i, ret = 0;

    for (i = 0; i < nb_filtergraphs; i++)
        if (!filtergraphs[i]->graph &&
            (ret = configure_complex_filter(filtergraphs[i])) < 0)
            return ret;
    return 0;
}

static int configure_filtergraph(FilterGraph *fg)
{
    return fg->graph_desc ? configure_complex_filter(fg) : configure_video_filters(fg);
}

static int ist_in_filtergraph(FilterGraph *fg, InputStream *ist)
{
    int i;
    for (i = 0; i < fg->nb_inputs; i++)
        if (fg->inputs[i]->ist == ist)
            return 1;
    return 0;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
static void term_exit(void)
{
    av_log(NULL, AV_LOG_QUIET, "%s", "");
    if(restore_tty)
        tcsetattr (0, TCSANOW, &oldtty);
Fabrice Bellard's avatar
Fabrice Bellard committed

static volatile int received_sigterm = 0;
static void sigterm_handler(int sig)
    if(received_nb_signals > 3)
        exit(123);
Fabrice Bellard's avatar
Fabrice Bellard committed
static void term_init(void)
{
        struct termios tty;

        if (tcgetattr (0, &tty) == 0) {
            oldtty = tty;
            restore_tty = 1;
            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).    */
    signal(SIGTERM, sigterm_handler); /* Termination (ANSI).  */
Måns Rullgård's avatar
Måns Rullgård committed
#ifdef SIGXCPU
    signal(SIGXCPU, sigterm_handler);
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
}

/* 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
#    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
    if(kbhit())
        return(getch());
Fabrice Bellard's avatar
Fabrice Bellard committed
    return -1;
}

static int decode_interrupt_cb(void *ctx)
    return received_nb_signals > 1;
static const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL };

void av_noreturn exit_program(int ret)
    int i, j;

    for (i = 0; i < nb_filtergraphs; i++) {
        avfilter_graph_free(&filtergraphs[i]->graph);
        for (j = 0; j < filtergraphs[i]->nb_inputs; j++)
            av_freep(&filtergraphs[i]->inputs[j]);
        av_freep(&filtergraphs[i]->inputs);
        for (j = 0; j < filtergraphs[i]->nb_outputs; j++)
            av_freep(&filtergraphs[i]->outputs[j]);
        av_freep(&filtergraphs[i]->outputs);
        av_freep(&filtergraphs[i]);
    }
    av_freep(&filtergraphs);
    for (i = 0; i < nb_output_files; i++) {
        AVFormatContext *s = output_files[i]->ctx;
        if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)
        avformat_free_context(s);
        av_dict_free(&output_files[i]->opts);
        av_freep(&output_files[i]);
    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);
        }
        av_freep(&output_streams[i]->filtered_frame);
    for (i = 0; i < nb_input_files; i++) {
        avformat_close_input(&input_files[i]->ctx);
        av_freep(&input_files[i]);
    for (i = 0; i < nb_input_streams; i++) {
        av_freep(&input_streams[i]->decoded_frame);
        av_dict_free(&input_streams[i]->opts);
        free_buffer_pool(input_streams[i]);
        av_freep(&input_streams[i]->filters);

    if (vstats_file)
        fclose(vstats_file);
    av_free(vstats_filename);

    av_freep(&input_streams);
    av_freep(&input_files);
    av_freep(&audio_buf);
    allocated_audio_buf_size = 0;
    av_freep(&async_buf);
    avfilter_uninit();
    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);
        exit_program(1);
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);
        exit_program(1);
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)
            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]));
            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;
            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;
static double
get_sync_ipts(const OutputStream *ost, int64_t pts)
    OutputFile *of = output_files[ost->file_index];
    return (double)(pts - of->start_time) / AV_TIME_BASE;
static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
    AVBitStreamFilterContext *bsfc = ost->bitstream_filters;
    AVCodecContext          *avctx = ost->st->codec;
    if ((avctx->codec_type == AVMEDIA_TYPE_VIDEO && video_sync_method == VSYNC_DROP) ||
        (avctx->codec_type == AVMEDIA_TYPE_AUDIO && audio_sync_method < 0))
        pkt->pts = pkt->dts = AV_NOPTS_VALUE;

    /*
     * Audio encoders may split the packets --  #frames in != #packets out.
     * But there is no reordering, so we can limit the number of output packets
     * by simply dropping them here.
     * Counting encoded video frames needs to be done separately because of
     * reordering, see do_video_out()
     */
    if (!(avctx->codec_type == AVMEDIA_TYPE_VIDEO && avctx->codec)) {
        if (ost->frame_number >= ost->max_frames) {
            av_free_packet(pkt);
    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) {
            new_pkt.destruct = av_destruct_packet;
        } else if (a < 0) {
            av_log(NULL, AV_LOG_ERROR, "Failed to open bitstream filter %s for stream %d with codec %s",
                   bsfc->filter->name, pkt->stream_index,
                   avctx->codec ? avctx->codec->name : "copy");
            print_error("", a);
                exit_program(1);
    pkt->stream_index = ost->index;
    ret = av_interleaved_write_frame(s, pkt);
    if (ret < 0) {
        print_error("av_interleaved_write_frame()", ret);
        exit_program(1);
static void get_default_channel_layouts(OutputStream *ost, InputStream *ist)
{
    char layout_name[256];
    AVCodecContext *enc = ost->st->codec;
    AVCodecContext *dec = ist->st->codec;

    if (dec->channel_layout &&
        av_get_channel_layout_nb_channels(dec->channel_layout) != dec->channels) {
        av_get_channel_layout_string(layout_name, sizeof(layout_name),
                                     dec->channels, dec->channel_layout);
        av_log(NULL, AV_LOG_ERROR, "New channel layout (%s) is invalid\n",
               layout_name);
        dec->channel_layout = 0;
    }
    if (!dec->channel_layout) {
        if (enc->channel_layout && dec->channels == enc->channels) {
            dec->channel_layout = enc->channel_layout;
        } else {
            dec->channel_layout = av_get_default_channel_layout(dec->channels);

            if (!dec->channel_layout) {
                av_log(NULL, AV_LOG_FATAL, "Unable to find default channel "
                       "layout for Input Stream #%d.%d\n", ist->file_index,
                       ist->st->index);
                exit_program(1);
            }
        }
        av_get_channel_layout_string(layout_name, sizeof(layout_name),
                                     dec->channels, dec->channel_layout);
        av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for  Input Stream "
               "#%d.%d : %s\n", ist->file_index, ist->st->index, layout_name);
    }
    if (!enc->channel_layout) {
        if (dec->channels == enc->channels) {
            enc->channel_layout = dec->channel_layout;
            return;
        } else {
            enc->channel_layout = av_get_default_channel_layout(enc->channels);
        }
        if (!enc->channel_layout) {
            av_log(NULL, AV_LOG_FATAL, "Unable to find default channel layout "
                   "for Output Stream #%d.%d\n", ost->file_index,
                   ost->st->index);
            exit_program(1);
        }
        av_get_channel_layout_string(layout_name, sizeof(layout_name),
                                     enc->channels, enc->channel_layout);
        av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for Output Stream "
               "#%d.%d : %s\n", ost->file_index, ost->st->index, layout_name);
    }
}

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);
}
Fabrice Bellard's avatar
Fabrice Bellard committed

static int encode_audio_frame(AVFormatContext *s, OutputStream *ost,
                              const uint8_t *buf, int buf_size)
{
    AVCodecContext *enc = ost->st->codec;
    AVFrame *frame = NULL;
    AVPacket pkt;
    int ret, got_packet;
    av_init_packet(&pkt);
    pkt.data = NULL;
    pkt.size = 0;

    if (buf && buf_size) {
        if (!ost->output_frame) {
            ost->output_frame = avcodec_alloc_frame();
            if (!ost->output_frame) {
                av_log(NULL, AV_LOG_FATAL, "out-of-memory in encode_audio_frame()\n");
            }
        }
        frame = ost->output_frame;
        if (frame->extended_data != frame->data)
            av_freep(&frame->extended_data);
        avcodec_get_frame_defaults(frame);

        frame->nb_samples  = buf_size /
                             (enc->channels * av_get_bytes_per_sample(enc->sample_fmt));
        if ((ret = avcodec_fill_audio_frame(frame, enc->channels, enc->sample_fmt,
                                            buf, buf_size, 1)) < 0) {
            av_log(NULL, AV_LOG_FATAL, "Audio encoding failed (avcodec_fill_audio_frame)\n");
        frame->pts = ost->sync_opts;
        ost->sync_opts += frame->nb_samples;
    update_benchmark(NULL);
    if (avcodec_encode_audio2(enc, &pkt, frame, &got_packet) < 0) {
        av_log(NULL, AV_LOG_FATAL, "Audio encoding failed (avcodec_encode_audio2)\n");
    update_benchmark("encode_audio %d.%d", ost->file_index, ost->index);
    if (got_packet) {
        if (pkt.pts != AV_NOPTS_VALUE)
            pkt.pts      = av_rescale_q(pkt.pts,      enc->time_base, ost->st->time_base);
        if (pkt.dts != AV_NOPTS_VALUE) {
            int64_t max = ost->st->cur_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT);
            pkt.dts      = av_rescale_q(pkt.dts,      enc->time_base, ost->st->time_base);
            if (ost->st->cur_dts && ost->st->cur_dts != AV_NOPTS_VALUE &&  max > pkt.dts) {
                av_log(s, max - pkt.dts > 2 ? AV_LOG_WARNING : AV_LOG_DEBUG, "Audio timestamp %"PRId64" < %"PRId64" invalid, cliping\n", pkt.dts, max);
                pkt.pts = pkt.dts = max;
            }
        }
        if (pkt.duration > 0)
            pkt.duration = av_rescale_q(pkt.duration, enc->time_base, ost->st->time_base);

        write_frame(s, &pkt, ost);
Fabrice Bellard's avatar
Fabrice Bellard committed

        audio_size += pkt.size;
    if (debug_ts) {
        av_log(NULL, AV_LOG_INFO, "encoder -> type:audio "
               "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n",
               av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base),
               av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base));
    }

static int alloc_audio_output_buf(AVCodecContext *dec, AVCodecContext *enc,
                                  int nb_samples, int *buf_linesize)
{
    int64_t audio_buf_samples;
    int audio_buf_size;

    /* calculate required number of samples to allocate */
    audio_buf_samples = ((int64_t)nb_samples * enc->sample_rate + dec->sample_rate) /
                        dec->sample_rate;
    audio_buf_samples = 4 * audio_buf_samples + 10000; // safety factors for resampling
    audio_buf_samples = FFMAX(audio_buf_samples, enc->frame_size);
    if (audio_buf_samples > INT_MAX)
        return AVERROR(EINVAL);

    audio_buf_size = av_samples_get_buffer_size(buf_linesize, enc->channels,
                                                enc->sample_fmt, 0);
    if (audio_buf_size < 0)
        return audio_buf_size;

    av_fast_malloc(&audio_buf, &allocated_audio_buf_size, audio_buf_size);
    if (!audio_buf)
        return AVERROR(ENOMEM);

    return 0;
}

static void do_audio_out(AVFormatContext *s, OutputStream *ost,
                         InputStream *ist, AVFrame *decoded_frame)
Fabrice Bellard's avatar
Fabrice Bellard committed
{
    uint8_t *buftmp;
    int frame_bytes, resample_changed, ret;
    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);
    uint8_t *buf[AV_NUM_DATA_POINTERS];
    int size     = decoded_frame->nb_samples * dec->channels * isize;
    int planes   = av_sample_fmt_is_planar(dec->sample_fmt) ? dec->channels : 1;
    int i;
    int out_linesize = 0;
    int buf_linesize = decoded_frame->linesize[0];

    av_assert0(planes <= AV_NUM_DATA_POINTERS);

    for(i=0; i<planes; i++)
        buf[i]= decoded_frame->data[i];
    get_default_channel_layouts(ost, ist);

    if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples, &out_linesize) < 0) {
        av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n");
        exit_program(1);
    if (audio_sync_method > 1                      ||
        enc->channels       != dec->channels       ||
        enc->channel_layout != dec->channel_layout ||
        enc->sample_rate    != dec->sample_rate    ||
        dec->sample_fmt     != enc->sample_fmt)
    resample_changed = ost->resample_sample_fmt  != dec->sample_fmt ||
                       ost->resample_channels    != dec->channels   ||
                       ost->resample_channel_layout != dec->channel_layout ||
                       ost->resample_sample_rate != dec->sample_rate;

    if ((ost->audio_resample && !ost->swr) || resample_changed || ost->audio_channels_mapped) {
            av_log(NULL, AV_LOG_INFO, "Input stream #%d:%d frame changed from rate:%d fmt:%s ch:%d chl:0x%"PRIx64" to rate:%d fmt:%s ch:%d chl:0x%"PRIx64"\n",
                   ist->file_index, ist->st->index,
                   ost->resample_sample_rate, av_get_sample_fmt_name(ost->resample_sample_fmt),
                   ost->resample_channels, ost->resample_channel_layout,
                   dec->sample_rate, av_get_sample_fmt_name(dec->sample_fmt),
                   dec->channels, dec->channel_layout);
            ost->resample_sample_fmt  = dec->sample_fmt;
            ost->resample_channels    = dec->channels;
            ost->resample_channel_layout = dec->channel_layout;
            ost->resample_sample_rate = dec->sample_rate;
Michael Niedermayer's avatar
Michael Niedermayer committed
            swr_free(&ost->swr);
        /* if audio_sync_method is >1 the resampler is needed for audio drift compensation */
        if (audio_sync_method <= 1 && !ost->audio_channels_mapped &&
            ost->resample_sample_fmt  == enc->sample_fmt &&
            ost->resample_channels    == enc->channels   &&
            ost->resample_channel_layout == enc->channel_layout &&
            ost->resample_sample_rate == enc->sample_rate) {
Michael Niedermayer's avatar
Michael Niedermayer committed
            //ost->swr = NULL;
            ost->swr = swr_alloc_set_opts(ost->swr,
                                          enc->channel_layout, enc->sample_fmt, enc->sample_rate,
                                          dec->channel_layout, dec->sample_fmt, dec->sample_rate,
                                          0, NULL);
            av_opt_set_int(ost->swr, "dither_method", ost->swr_dither_method,0);
            av_opt_set_double(ost->swr, "dither_scale", ost->swr_dither_scale,0);
            if (ost->audio_channels_mapped)
                swr_set_channel_mapping(ost->swr, ost->audio_channels_map);
            av_opt_set_double(ost->swr, "rmvol", ost->rematrix_volume, 0);
            if (ost->audio_channels_mapped) {
                av_opt_set_int(ost->swr, "icl", av_get_default_channel_layout(ost->audio_channels_mapped), 0);
                av_opt_set_int(ost->swr, "uch", ost->audio_channels_mapped, 0);
            if (av_opt_set_int(ost->swr, "ich", dec->channels, 0) < 0) {
                av_log(NULL, AV_LOG_FATAL, "Unsupported number of input channels\n");
                exit_program(1);
            }
            if (av_opt_set_int(ost->swr, "och", enc->channels, 0) < 0) {
                av_log(NULL, AV_LOG_FATAL, "Unsupported number of output channels\n");
                exit_program(1);
            }
            if(audio_sync_method>1) av_opt_set_int(ost->swr, "flags", SWR_FLAG_RESAMPLE, 0);
Michael Niedermayer's avatar
Michael Niedermayer committed
            if(ost->swr && swr_init(ost->swr) < 0){
                av_log(NULL, AV_LOG_FATAL, "swr_init() failed\n");
Michael Niedermayer's avatar
Michael Niedermayer committed
                swr_free(&ost->swr);
            }

            if (!ost->swr) {
                av_log(NULL, AV_LOG_FATAL, "Can not resample %d channels @ %d Hz to %d channels @ %d Hz\n",
Stefano Sabatini's avatar
Stefano Sabatini committed
                        dec->channels, dec->sample_rate,
                        enc->channels, enc->sample_rate);
                exit_program(1);
Stefano Sabatini's avatar
Stefano Sabatini committed
            }
Michael Niedermayer's avatar
Michael Niedermayer committed
    av_assert0(ost->audio_resample || dec->sample_fmt==enc->sample_fmt);
    if (audio_sync_method > 0) {
        double delta = get_sync_ipts(ost, ist->pts) * enc->sample_rate - ost->sync_opts -
                       av_fifo_size(ost->fifo) / (enc->channels * osize);
        int idelta = delta * dec->sample_rate / enc->sample_rate;
        int byte_delta = idelta * isize * 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;
                    for (i=0; i<planes; i++)
                        buf[i]  -= byte_delta/planes;
                    av_log(NULL, AV_LOG_VERBOSE, "discarding %d audio samples\n",
                           -byte_delta / (isize * dec->channels));
                    ist->is_start = 0;
                } else {
                    av_fast_malloc(&async_buf, &allocated_async_buf_size,
                                   byte_delta + size);
                    if (!async_buf) {
                        av_log(NULL, AV_LOG_FATAL, "Out of memory in do_audio_out\n");
                        exit_program(1);
                    }
                    if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples + idelta, &out_linesize) < 0) {
                        av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n");
                        exit_program(1);
                    for (i=0; i<planes; i++) {
                        uint8_t *t = async_buf + i*((byte_delta + size)/planes);
                        generate_silence(t, dec->sample_fmt, byte_delta/planes);
                        memcpy(t + byte_delta/planes, buf[i], size/planes);
                        buf[i] = t;
                    }
                    size += byte_delta;
                    buf_linesize = allocated_async_buf_size;
                    av_log(NULL, AV_LOG_VERBOSE, "adding %d audio samples of silence\n", idelta);
            } else if (audio_sync_method > 1) {
                int comp = av_clip(delta, -audio_sync_method, audio_sync_method);
                av_log(NULL, AV_LOG_VERBOSE, "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));
                swr_set_compensation(ost->swr, comp, enc->sample_rate);
        ost->sync_opts = lrintf(get_sync_ipts(ost, ist->pts) * enc->sample_rate) -
                                av_fifo_size(ost->fifo) / (enc->channels * osize); // FIXME wrong
Fabrice Bellard's avatar
Fabrice Bellard committed

    if (ost->audio_resample || ost->audio_channels_mapped) {
Fabrice Bellard's avatar
Fabrice Bellard committed
        buftmp = audio_buf;
        size_out = swr_convert(ost->swr, (      uint8_t*[]){buftmp},
                                      allocated_audio_buf_size / (enc->channels * osize),
                                      buf,
                                      size / (dec->channels * isize));
        if (size_out < 0) {
            av_log(NULL, AV_LOG_FATAL, "swr_convert failed\n");
            exit_program(1);
        }
        size_out = size_out * enc->channels * osize;
Fabrice Bellard's avatar
Fabrice Bellard committed
    } else {
        buftmp = buf[0];
Fabrice Bellard's avatar
Fabrice Bellard committed
        size_out = size;
    }

Michael Niedermayer's avatar
Michael Niedermayer committed
    av_assert0(ost->audio_resample || dec->sample_fmt==enc->sample_fmt);
Fabrice Bellard's avatar
Fabrice Bellard committed
    /* now encode as many frames as possible */
    if (!(enc->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) {
Fabrice Bellard's avatar
Fabrice Bellard committed
        /* output resampled raw samples */
        if (av_fifo_realloc2(ost->fifo, av_fifo_size(ost->fifo) + size_out) < 0) {
            av_log(NULL, AV_LOG_FATAL, "av_fifo_realloc2() failed\n");
            exit_program(1);
        av_fifo_generic_write(ost->fifo, buftmp, size_out, NULL);
Fabrice Bellard's avatar
Fabrice Bellard committed

        frame_bytes = enc->frame_size * osize * enc->channels;
        while (av_fifo_size(ost->fifo) >= frame_bytes) {
            av_fifo_generic_read(ost->fifo, audio_buf, frame_bytes, NULL);
            encode_audio_frame(s, ost, audio_buf, frame_bytes);
Fabrice Bellard's avatar
Fabrice Bellard committed
        }
    } else {
        encode_audio_frame(s, ost, buftmp, size_out);
Fabrice Bellard's avatar
Fabrice Bellard committed
    }
}

static void pre_process_video_frame(InputStream *ist, AVPicture *picture, void **bufp)
{
    AVCodecContext *dec;
    AVPicture *picture2;
    AVPicture picture_tmp;
    uint8_t *buf = 0;

    /* 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);
        picture2 = &picture_tmp;
        avpicture_fill(picture2, buf, dec->pix_fmt, dec->width, dec->height);

        if (avpicture_deinterlace(picture2, picture,
Ramiro Polla's avatar
Ramiro Polla committed
                                 dec->pix_fmt, dec->width, dec->height) < 0) {
            /* if error, do not deinterlace */
            av_log(NULL, AV_LOG_WARNING, "Deinterlacing failed\n");
Ramiro Polla's avatar
Ramiro Polla committed
            av_free(buf);
            buf = NULL;
            picture2 = picture;
        }
    } else {
        picture2 = picture;
    }

    if (picture != picture2)
        *picture = *picture2;
    *bufp = buf;
}

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) {
        av_log(NULL, AV_LOG_ERROR, "Subtitle packets must have a pts\n");
            exit_program(1);

    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++) {
        ost->sync_opts = av_rescale_q(pts, ist->st->time_base, enc->time_base);

        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;
        subtitle_out_size = avcodec_encode_subtitle(enc, subtitle_out,
            av_log(NULL, AV_LOG_FATAL, "Subtitle encoding failed\n");
            exit_program(1);
        av_init_packet(&pkt);
        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);
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");
            exit_program(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 do_video_out(AVFormatContext *s, OutputStream *ost,
                         AVFrame *in_picture, float quality)
Fabrice Bellard's avatar
Fabrice Bellard committed
{
    int nb_frames, i, ret, format_video_sync;
    double sync_ipts, delta;
    InputStream *ist = NULL;

    if (ost->source_index >= 0)
        ist = input_streams[ost->source_index];
Fabrice Bellard's avatar
Fabrice Bellard committed

    if(ist && ist->st->start_time != AV_NOPTS_VALUE && ist->st->first_dts != AV_NOPTS_VALUE && ost->frame_rate.num)
        duration = 1/(av_q2d(ost->frame_rate) * av_q2d(enc->time_base));
    sync_ipts = get_sync_ipts(ost, in_picture->pts) / av_q2d(enc->time_base);
    delta = sync_ipts - ost->sync_opts + duration;
    /* by default, we output a single frame */
    nb_frames = 1;

    format_video_sync = video_sync_method;
    if (format_video_sync == VSYNC_AUTO)
        format_video_sync = (s->oformat->flags & AVFMT_VARIABLE_FPS) ? ((s->oformat->flags & AVFMT_NOTIMESTAMPS) ? VSYNC_PASSTHROUGH : VSYNC_VFR) : 1;
    switch (format_video_sync) {
    case VSYNC_CFR:
        // FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
        if (delta < -1.1)
        else if (delta > 1.1)
            nb_frames = lrintf(delta);
        break;
    case VSYNC_VFR:
        if (delta <= -0.6)
            nb_frames = 0;
        else if (delta > 0.6)
            ost->sync_opts = lrintf(sync_ipts);
        break;
    case VSYNC_PASSTHROUGH:
        ost->sync_opts = lrintf(sync_ipts);
        break;
    default:
        av_assert0(0);
    }
    nb_frames = FFMIN(nb_frames, ost->max_frames - ost->frame_number);
    if (nb_frames == 0) {
        nb_frames_drop++;
        av_log(NULL, AV_LOG_VERBOSE, "*** drop!\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
        return;
    } else if (nb_frames > 1) {
        nb_frames_dup += nb_frames - 1;
        av_log(NULL, AV_LOG_VERBOSE, "*** %d dup!\n", nb_frames - 1);
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
    /* duplicates frame if needed */
    for (i = 0; i < nb_frames; i++) {
        AVPacket pkt;
        av_init_packet(&pkt);
        pkt.data = NULL;
        pkt.size = 0;
        if (s->oformat->flags & AVFMT_RAWPICTURE &&
            enc->codec->id == CODEC_ID_RAWVIDEO) {
            /* raw pictures are written as AVPicture structure to
               avoid any copies. We support temporarily the older
            enc->coded_frame->interlaced_frame = in_picture->interlaced_frame;
            enc->coded_frame->top_field_first  = in_picture->top_field_first;
            pkt.data   = (uint8_t *)in_picture;
            pkt.size   =  sizeof(AVPicture);
            pkt.pts    = av_rescale_q(ost->sync_opts, enc->time_base, ost->st->time_base);
            write_frame(s, &pkt, ost);
            int got_packet;
            AVFrame big_picture;
            big_picture = *in_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 (ost->top_field_first == -1)
                    big_picture.top_field_first = in_picture->top_field_first;
                else
                    big_picture.top_field_first = !!ost->top_field_first;
            /* handles same_quant here. This is not correct because it may
Fabrice Bellard's avatar
Fabrice Bellard committed
               not be a global option */
            big_picture.quality = quality;
            if (!enc->me_threshold)
            big_picture.pts = 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++;
            }
            update_benchmark(NULL);
            ret = avcodec_encode_video2(enc, &pkt, &big_picture, &got_packet);
            update_benchmark("encode_video %d.%d", ost->file_index, ost->index);
                av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
                exit_program(1);
            if (got_packet) {
                if (pkt.pts == AV_NOPTS_VALUE && !(enc->codec->capabilities & CODEC_CAP_DELAY))
                    pkt.pts = ost->sync_opts;

                if (pkt.pts != AV_NOPTS_VALUE)
                    pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base);
                if (pkt.dts != AV_NOPTS_VALUE)
                    pkt.dts = av_rescale_q(pkt.dts, enc->time_base, ost->st->time_base);
                if (debug_ts) {
                    av_log(NULL, AV_LOG_INFO, "encoder -> type:video "
                           "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n",
                           av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base),
                           av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base));
                }

                write_frame(s, &pkt, ost);
                frame_size = pkt.size;
                video_size += pkt.size;
                av_free_packet(&pkt);
                /* if two pass, output log */
                if (ost->logfile && enc->stats_out) {
                    fprintf(ost->logfile, "%s", enc->stats_out);
                }
Fabrice Bellard's avatar
Fabrice Bellard committed
        }
        ost->sync_opts++;
        /*
         * For video, number of frames in == number of packets out.
         * But there may be reordering, so we can't throw away frames on encoder
         * flush, we need to limit them here, before they go into encoder.
         */
Fabrice Bellard's avatar
Fabrice Bellard committed
    }
    if (vstats_filename && frame_size)
        do_video_stats(output_files[ost->file_index]->ctx, ost, frame_size);
Fabrice Bellard's avatar
Fabrice Bellard committed
}

/* check for new output on any of the filtergraphs */
static int poll_filters(void)
{
    AVFilterBufferRef *picref;
    AVFrame *filtered_frame = NULL;
    int i, ret, ret_all;
    unsigned nb_success, nb_eof;
    while (1) {
        /* Reap all buffers present in the buffer sinks */
Clément Bœsch's avatar
Clément Bœsch committed
        for (i = 0; i < nb_output_streams; i++) {
            OutputStream *ost = output_streams[i];
            OutputFile    *of = output_files[ost->file_index];

            if (!ost->filter || ost->is_past_recording_time)
                continue;

            if (!ost->filtered_frame && !(ost->filtered_frame = avcodec_alloc_frame())) {
                return AVERROR(ENOMEM);
            } else
                avcodec_get_frame_defaults(ost->filtered_frame);
            filtered_frame = ost->filtered_frame;

            while (1) {
                AVRational ist_pts_tb = ost->filter->filter->inputs[0]->time_base;
                ret = av_buffersink_get_buffer_ref(ost->filter->filter, &picref,
                                                   AV_BUFFERSINK_FLAG_NO_REQUEST);
                if (ret < 0) {
                    if (ret != AVERROR(EAGAIN)) {
                        char buf[256];
                        av_strerror(ret, buf, sizeof(buf));
                        av_log(NULL, AV_LOG_WARNING,
                               "Error in av_buffersink_get_buffer_ref(): %s\n", buf);
                    }
                    break;
                }
                filtered_frame->pts = av_rescale_q(picref->pts, ist_pts_tb, AV_TIME_BASE_Q);
                //if (ost->source_index >= 0)
                //    *filtered_frame= *input_streams[ost->source_index]->decoded_frame; //for me_threshold

                if (of->start_time && filtered_frame->pts < of->start_time)
                    return 0;

                switch (ost->filter->filter->inputs[0]->type) {
                case AVMEDIA_TYPE_VIDEO:
                    avfilter_fill_frame_from_video_buffer_ref(filtered_frame, picref);
                    if (!ost->frame_aspect_ratio)
                        ost->st->codec->sample_aspect_ratio = picref->video->sample_aspect_ratio;

                    do_video_out(of->ctx, ost, filtered_frame,
                                 same_quant ? ost->last_quality :
                                              ost->st->codec->global_quality);
                    break;
                default:
                    // TODO support audio/subtitle filters
                    av_assert0(0);
Clément Bœsch's avatar
Clément Bœsch committed
                avfilter_unref_buffer(picref);
            }
        /* Request frames through all the graphs */
        ret_all = nb_success = nb_eof = 0;
        for (i = 0; i < nb_filtergraphs; i++) {
            ret = avfilter_graph_request_oldest(filtergraphs[i]->graph);
            if (!ret) {
                nb_success++;
            } else if (ret == AVERROR_EOF) {
                nb_eof++;
            } else if (ret != AVERROR(EAGAIN)) {
                char buf[256];
                av_strerror(ret, buf, sizeof(buf));
                av_log(NULL, AV_LOG_WARNING,
                       "Error in request_frame(): %s\n", buf);
                ret_all = ret;
            }
        }
        if (!nb_success)
            break;
        /* Try again if anything succeeded */
    }
    return nb_eof == nb_filtergraphs ? AVERROR_EOF : ret_all;
static void print_report(int is_last_report, int64_t timer_start, int64_t cur_time)
    OutputStream *ost;
    int64_t total_size;
    static int64_t last_time = -1;
    static int qp_histogram[52];
    int hours, mins, secs, us;
    if (!print_stats && !is_last_report)
        return;
Loading
Loading full blame...