Merge commit '23aae62c2cb4504a09ceb8cd0cabc1c8b260f521'
authorMichael Niedermayer <michaelni@gmx.at>
Tue, 18 Sep 2012 12:30:31 +0000 (14:30 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Tue, 18 Sep 2012 12:45:44 +0000 (14:45 +0200)
* commit '23aae62c2cb4504a09ceb8cd0cabc1c8b260f521':
  alsdec: Check k used for rice decoder.
  avfiltergraph: silence an uninitialized variable warning
  xsubenc: reindent
  lavc: replace AVCodecContext.encode with subtitle-specific callback
  lavc: add const to private codec class initialization.
  avconv: don't pass a bogus parameter to avfilter_graph_create_filter().
  id3v2: strdup the genre name explicitly.
  lavf/id3v2: do not export empty fields.
  buffersrc: add const to the AVFrame* argument of av_buffersrc_write_frame()
  lavfi: replace empty input/output lists with null pointers

Conflicts:
ffmpeg_filter.c
libavcodec/alsdec.c
libavcodec/dvdsubenc.c
libavcodec/utils.c
libavcodec/v210dec.h
libavfilter/af_channelsplit.c
libavfilter/avfiltergraph.c
libavfilter/buffersrc.c
libavfilter/src_movie.c
libavfilter/vf_ass.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
26 files changed:
1  2 
ffmpeg_filter.c
libavcodec/allcodecs.c
libavcodec/alsdec.c
libavcodec/assenc.c
libavcodec/avcodec.h
libavcodec/dvbsub.c
libavcodec/dvdsubenc.c
libavcodec/movtextenc.c
libavcodec/srtenc.c
libavcodec/utils.c
libavcodec/xsubenc.c
libavfilter/af_amix.c
libavfilter/af_channelsplit.c
libavfilter/af_join.c
libavfilter/asink_anullsink.c
libavfilter/asrc_anullsrc.c
libavfilter/avfilter.c
libavfilter/avfiltergraph.c
libavfilter/buffersink.c
libavfilter/buffersrc.c
libavfilter/buffersrc.h
libavfilter/split.c
libavfilter/src_movie.c
libavfilter/vf_frei0r.c
libavfilter/vsink_nullsink.c
libavfilter/vsrc_testsrc.c

diff --cc ffmpeg_filter.c
index 1887ffe,0000000..8478edf
mode 100644,000000..100644
--- /dev/null
@@@ -1,774 -1,0 +1,774 @@@
-                                        name, NULL, NULL/*buffersink_params*/, fg->graph);
 +/*
 + * ffmpeg filter configuration
 + *
 + * This file is part of FFmpeg.
 + *
 + * FFmpeg is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + *
 + * FFmpeg is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with FFmpeg; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 + */
 +
 +#include "ffmpeg.h"
 +
 +#include "libavfilter/avfilter.h"
 +#include "libavfilter/avfiltergraph.h"
 +#include "libavfilter/buffersink.h"
 +
 +#include "libavutil/audioconvert.h"
 +#include "libavutil/avassert.h"
 +#include "libavutil/avstring.h"
 +#include "libavutil/bprint.h"
 +#include "libavutil/pixdesc.h"
 +#include "libavutil/pixfmt.h"
 +#include "libavutil/imgutils.h"
 +#include "libavutil/samplefmt.h"
 +
 +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 == AV_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 == AV_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_fmt_of_2(best, *p, target, has_alpha, NULL);
 +            if (*p == target)
 +                break;
 +        }
 +        if (*p == PIX_FMT_NONE) {
 +            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);
 +            return best;
 +        }
 +    }
 +    return target;
 +}
 +
 +void choose_sample_fmt(AVStream *st, AVCodec *codec)
 +{
 +    if (codec && codec->sample_fmts) {
 +        const enum AVSampleFormat *p = codec->sample_fmts;
 +        for (; *p != -1; p++) {
 +            if (*p == st->codec->sample_fmt)
 +                break;
 +        }
 +        if (*p == -1) {
 +            if((codec->capabilities & CODEC_CAP_LOSSLESS) && av_get_sample_fmt_name(st->codec->sample_fmt) > av_get_sample_fmt_name(codec->sample_fmts[0]))
 +                av_log(NULL, AV_LOG_ERROR, "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 char *choose_pix_fmts(OutputStream *ost)
 +{
 +     if (ost->keep_pix_fmt) {
 +        if (ost->filter)
 +            avfilter_graph_set_auto_convert(ost->filter->graph->graph,
 +                                            AVFILTER_AUTO_CONVERT_NONE);
 +        if (ost->st->codec->pix_fmt == PIX_FMT_NONE)
 +            return NULL;
 +        return av_strdup(av_get_pix_fmt_name(ost->st->codec->pix_fmt));
 +    }
 +    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 && 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 == AV_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 == AV_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++) {
 +            const char *name = av_get_pix_fmt_name(*p);
 +            avio_printf(s, "%s:", name);
 +        }
 +        len = avio_close_dyn_buf(s, &ret);
 +        ret[len - 1] = 0;
 +        return ret;
 +    } else
 +        return NULL;
 +}
 +
 +/**
 + * Define a function for building a string containing a list of
 + * allowed formats,
 + */
 +#define DEF_CHOOSE_FORMAT(type, var, supported_list, none, get_name, separator)\
 +static char *choose_ ## var ## s(OutputStream *ost)                            \
 +{                                                                              \
 +    if (ost->st->codec->var != none) {                                         \
 +        get_name(ost->st->codec->var);                                         \
 +        return av_strdup(name);                                                \
 +    } else if (ost->enc->supported_list) {                                     \
 +        const type *p;                                                         \
 +        AVIOContext *s = NULL;                                                 \
 +        uint8_t *ret;                                                          \
 +        int len;                                                               \
 +                                                                               \
 +        if (avio_open_dyn_buf(&s) < 0)                                         \
 +            exit_program(1);                                                   \
 +                                                                               \
 +        for (p = ost->enc->supported_list; *p != none; p++) {                  \
 +            get_name(*p);                                                      \
 +            avio_printf(s, "%s" separator, name);                              \
 +        }                                                                      \
 +        len = avio_close_dyn_buf(s, &ret);                                     \
 +        ret[len - 1] = 0;                                                      \
 +        return ret;                                                            \
 +    } else                                                                     \
 +        return NULL;                                                           \
 +}
 +
 +// DEF_CHOOSE_FORMAT(enum PixelFormat, pix_fmt, pix_fmts, PIX_FMT_NONE,
 +//                   GET_PIX_FMT_NAME, ":")
 +
 +DEF_CHOOSE_FORMAT(enum AVSampleFormat, sample_fmt, sample_fmts,
 +                  AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME, ",")
 +
 +DEF_CHOOSE_FORMAT(int, sample_rate, supported_samplerates, 0,
 +                  GET_SAMPLE_RATE_NAME, ",")
 +
 +DEF_CHOOSE_FORMAT(uint64_t, channel_layout, channel_layouts, 0,
 +                  GET_CH_LAYOUT_NAME, ",")
 +
 +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;
 +
 +    ost->filter = fg->outputs[0];
 +
 +    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 = NULL;
 +    enum AVMediaType type = avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx);
 +    int i;
 +
 +    // TODO: support other filter types
 +    if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) {
 +        av_log(NULL, AV_LOG_FATAL, "Only video and audio 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++) {
 +            enum AVMediaType stream_type = s->streams[i]->codec->codec_type;
 +            if (stream_type != type &&
 +                !(stream_type == AVMEDIA_TYPE_SUBTITLE &&
 +                  type == AVMEDIA_TYPE_VIDEO /* sub2video hack */))
 +                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\n", in->pad_idx,
 +                   in->filter_ctx->name);
 +            exit_program(1);
 +        }
 +    }
 +    av_assert0(ist);
 +
 +    ist->discard         = 0;
 +    ist->decoding_needed++;
 +    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_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
 +{
 +    char *pix_fmts;
 +    OutputStream *ost = ofilter->ost;
 +    AVCodecContext *codec = ost->st->codec;
 +    AVFilterContext *last_filter = out->filter_ctx;
 +    int pad_idx = out->pad_idx;
 +    int ret;
 +    char name[255];
 +    AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc();
 +
 +    snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index);
 +    ret = avfilter_graph_create_filter(&ofilter->filter,
 +                                       avfilter_get_by_name("ffbuffersink"),
++                                       name, NULL, NULL, fg->graph);
 +    av_freep(&buffersink_params);
 +
 +    if (ret < 0)
 +        return ret;
 +
 +    if (codec->width || codec->height) {
 +        char args[255];
 +        AVFilterContext *filter;
 +
 +        snprintf(args, sizeof(args), "%d:%d:flags=0x%X",
 +                 codec->width,
 +                 codec->height,
 +                 (unsigned)ost->sws_flags);
 +        snprintf(name, sizeof(name), "scaler for output stream %d:%d",
 +                 ost->file_index, ost->index);
 +        if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"),
 +                                                name, args, 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;
 +    }
 +
 +    if ((pix_fmts = choose_pix_fmts(ost))) {
 +        AVFilterContext *filter;
 +        snprintf(name, sizeof(name), "pixel format for output stream %d:%d",
 +                 ost->file_index, ost->index);
 +        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 (ost->frame_rate.num && 0) {
 +        AVFilterContext *fps;
 +        char args[255];
 +
 +        snprintf(args, sizeof(args), "fps=%d/%d", ost->frame_rate.num,
 +                 ost->frame_rate.den);
 +        snprintf(name, sizeof(name), "fps for output stream %d:%d",
 +                 ost->file_index, ost->index);
 +        ret = avfilter_graph_create_filter(&fps, avfilter_get_by_name("fps"),
 +                                           name, args, NULL, fg->graph);
 +        if (ret < 0)
 +            return ret;
 +
 +        ret = avfilter_link(last_filter, pad_idx, fps, 0);
 +        if (ret < 0)
 +            return ret;
 +        last_filter = fps;
 +        pad_idx = 0;
 +    }
 +
 +    if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
 +        return ret;
 +
 +    return 0;
 +}
 +
 +static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
 +{
 +    OutputStream *ost = ofilter->ost;
 +    AVCodecContext *codec  = ost->st->codec;
 +    AVFilterContext *last_filter = out->filter_ctx;
 +    int pad_idx = out->pad_idx;
 +    char *sample_fmts, *sample_rates, *channel_layouts;
 +    char name[255];
 +    int ret;
 +
 +
 +    snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index);
 +    ret = avfilter_graph_create_filter(&ofilter->filter,
 +                                       avfilter_get_by_name("ffabuffersink"),
 +                                       name, NULL, NULL, fg->graph);
 +    if (ret < 0)
 +        return ret;
 +
 +#define AUTO_INSERT_FILTER(opt_name, filter_name, arg) do {                 \
 +    AVFilterContext *filt_ctx;                                              \
 +                                                                            \
 +    av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi "            \
 +           "similarly to -af " filter_name "=%s.\n", arg);                  \
 +                                                                            \
 +    ret = avfilter_graph_create_filter(&filt_ctx,                           \
 +                                       avfilter_get_by_name(filter_name),   \
 +                                       filter_name, arg, NULL, fg->graph);  \
 +    if (ret < 0)                                                            \
 +        return ret;                                                         \
 +                                                                            \
 +    ret = avfilter_link(last_filter, pad_idx, filt_ctx, 0);                 \
 +    if (ret < 0)                                                            \
 +        return ret;                                                         \
 +                                                                            \
 +    last_filter = filt_ctx;                                                 \
 +    pad_idx = 0;                                                            \
 +} while (0)
 +    if (ost->audio_channels_mapped) {
 +        int i;
 +        AVBPrint pan_buf;
 +        av_bprint_init(&pan_buf, 256, 8192);
 +        av_bprintf(&pan_buf, "0x%"PRIx64,
 +                   av_get_default_channel_layout(ost->audio_channels_mapped));
 +        for (i = 0; i < ost->audio_channels_mapped; i++)
 +            if (ost->audio_channels_map[i] != -1)
 +                av_bprintf(&pan_buf, ":c%d=c%d", i, ost->audio_channels_map[i]);
 +
 +        AUTO_INSERT_FILTER("-map_channel", "pan", pan_buf.str);
 +        av_bprint_finalize(&pan_buf, NULL);
 +    }
 +
 +    if (codec->channels && !codec->channel_layout)
 +        codec->channel_layout = av_get_default_channel_layout(codec->channels);
 +
 +    sample_fmts     = choose_sample_fmts(ost);
 +    sample_rates    = choose_sample_rates(ost);
 +    channel_layouts = choose_channel_layouts(ost);
 +    if (sample_fmts || sample_rates || channel_layouts) {
 +        AVFilterContext *format;
 +        char args[256];
 +        args[0] = 0;
 +
 +        if (sample_fmts)
 +            av_strlcatf(args, sizeof(args), "sample_fmts=%s:",
 +                            sample_fmts);
 +        if (sample_rates)
 +            av_strlcatf(args, sizeof(args), "sample_rates=%s:",
 +                            sample_rates);
 +        if (channel_layouts)
 +            av_strlcatf(args, sizeof(args), "channel_layouts=%s:",
 +                            channel_layouts);
 +
 +        av_freep(&sample_fmts);
 +        av_freep(&sample_rates);
 +        av_freep(&channel_layouts);
 +
 +        snprintf(name, sizeof(name), "audio format for output stream %d:%d",
 +                 ost->file_index, ost->index);
 +        ret = avfilter_graph_create_filter(&format,
 +                                           avfilter_get_by_name("aformat"),
 +                                           name, args, NULL, fg->graph);
 +        if (ret < 0)
 +            return ret;
 +
 +        ret = avfilter_link(last_filter, pad_idx, format, 0);
 +        if (ret < 0)
 +            return ret;
 +
 +        last_filter = format;
 +        pad_idx = 0;
 +    }
 +
 +    if (audio_volume != 256 && 0) {
 +        char args[256];
 +
 +        snprintf(args, sizeof(args), "%f", audio_volume / 256.);
 +        AUTO_INSERT_FILTER("-vol", "volume", args);
 +    }
 +
 +    if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
 +        return ret;
 +
 +    return 0;
 +}
 +
 +#define DESCRIBE_FILTER_LINK(f, inout, in)                         \
 +{                                                                  \
 +    AVFilterContext *ctx = inout->filter_ctx;                      \
 +    AVFilterPad *pads = in ? ctx->input_pads  : ctx->output_pads;  \
 +    int       nb_pads = in ? ctx->input_count : ctx->output_count; \
 +    AVIOContext *pb;                                               \
 +                                                                   \
 +    if (avio_open_dyn_buf(&pb) < 0)                                \
 +        exit_program(1);                                           \
 +                                                                   \
 +    avio_printf(pb, "%s", ctx->filter->name);                      \
 +    if (nb_pads > 1)                                               \
 +        avio_printf(pb, ":%s", avfilter_pad_get_name(pads, inout->pad_idx));\
 +    avio_w8(pb, 0);                                                \
 +    avio_close_dyn_buf(pb, &f->name);                              \
 +}
 +
 +int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
 +{
 +    av_freep(&ofilter->name);
 +    DESCRIBE_FILTER_LINK(ofilter, out, 0);
 +
 +    switch (avfilter_pad_get_type(out->filter_ctx->output_pads, out->pad_idx)) {
 +    case AVMEDIA_TYPE_VIDEO: return configure_output_video_filter(fg, ofilter, out);
 +    case AVMEDIA_TYPE_AUDIO: return configure_output_audio_filter(fg, ofilter, out);
 +    default: av_assert0(0);
 +    }
 +}
 +
 +static int sub2video_prepare(InputStream *ist)
 +{
 +    AVFormatContext *avf = input_files[ist->file_index]->ctx;
 +    int i, ret, w, h;
 +    uint8_t *image[4];
 +    int linesize[4];
 +
 +    /* Compute the size of the canvas for the subtitles stream.
 +       If the subtitles codec has set a size, use it. Otherwise use the
 +       maximum dimensions of the video streams in the same file. */
 +    w = ist->st->codec->width;
 +    h = ist->st->codec->height;
 +    if (!(w && h)) {
 +        for (i = 0; i < avf->nb_streams; i++) {
 +            if (avf->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
 +                w = FFMAX(w, avf->streams[i]->codec->width);
 +                h = FFMAX(h, avf->streams[i]->codec->height);
 +            }
 +        }
 +        if (!(w && h)) {
 +            w = FFMAX(w, 720);
 +            h = FFMAX(h, 576);
 +        }
 +        av_log(avf, AV_LOG_INFO, "sub2video: using %dx%d canvas\n", w, h);
 +    }
 +    ist->sub2video.w = ist->st->codec->width  = w;
 +    ist->sub2video.h = ist->st->codec->height = h;
 +
 +    /* rectangles are PIX_FMT_PAL8, but we have no guarantee that the
 +       palettes for all rectangles are identical or compatible */
 +    ist->st->codec->pix_fmt = PIX_FMT_RGB32;
 +
 +    ret = av_image_alloc(image, linesize, w, h, PIX_FMT_RGB32, 32);
 +    if (ret < 0)
 +        return ret;
 +    memset(image[0], 0, h * linesize[0]);
 +    ist->sub2video.ref = avfilter_get_video_buffer_ref_from_arrays(
 +            image, linesize, AV_PERM_READ | AV_PERM_PRESERVE,
 +            w, h, PIX_FMT_RGB32);
 +    if (!ist->sub2video.ref) {
 +        av_free(image[0]);
 +        return AVERROR(ENOMEM);
 +    }
 +    return 0;
 +}
 +
 +static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
 +                                        AVFilterInOut *in)
 +{
 +    AVFilterContext *first_filter = in->filter_ctx;
 +    AVFilter *filter = avfilter_get_by_name("buffer");
 +    InputStream *ist = ifilter->ist;
 +    AVRational tb = ist->framerate.num ? av_inv_q(ist->framerate) :
 +                                         ist->st->time_base;
 +    AVRational fr = ist->framerate.num ? ist->framerate :
 +                                         ist->st->r_frame_rate;
 +    AVRational sar;
 +    AVBPrint args;
 +    char name[255];
 +    int pad_idx = in->pad_idx;
 +    int ret;
 +
 +    if (ist->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
 +        ret = sub2video_prepare(ist);
 +        if (ret < 0)
 +            return ret;
 +    }
 +
 +    sar = ist->st->sample_aspect_ratio.num ?
 +          ist->st->sample_aspect_ratio :
 +          ist->st->codec->sample_aspect_ratio;
 +    if(!sar.den)
 +        sar = (AVRational){0,1};
 +    av_bprint_init(&args, 0, 1);
 +    av_bprintf(&args,
 +             "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:"
 +             "pixel_aspect=%d/%d:sws_param=flags=%d", ist->st->codec->width,
 +             ist->st->codec->height, ist->st->codec->pix_fmt,
 +             tb.num, tb.den, sar.num, sar.den,
 +             SWS_BILINEAR + ((ist->st->codec->flags&CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0));
 +    if (fr.num && fr.den)
 +        av_bprintf(&args, ":frame_rate=%d/%d", fr.num, fr.den);
 +    snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
 +             ist->file_index, ist->st->index);
 +
 +    if ((ret = avfilter_graph_create_filter(&ifilter->filter, filter, name,
 +                                            args.str, NULL, fg->graph)) < 0)
 +        return ret;
 +
 +    if (ist->framerate.num) {
 +        AVFilterContext *setpts;
 +
 +        snprintf(name, sizeof(name), "force CFR for input from stream %d:%d",
 +                 ist->file_index, ist->st->index);
 +        if ((ret = avfilter_graph_create_filter(&setpts,
 +                                                avfilter_get_by_name("setpts"),
 +                                                name, "N", NULL,
 +                                                fg->graph)) < 0)
 +            return ret;
 +
 +        if ((ret = avfilter_link(setpts, 0, first_filter, pad_idx)) < 0)
 +            return ret;
 +
 +        first_filter = setpts;
 +        pad_idx = 0;
 +    }
 +
 +    if ((ret = avfilter_link(ifilter->filter, 0, first_filter, pad_idx)) < 0)
 +        return ret;
 +    return 0;
 +}
 +
 +static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
 +                                        AVFilterInOut *in)
 +{
 +    AVFilterContext *first_filter = in->filter_ctx;
 +    AVFilter *filter = avfilter_get_by_name("abuffer");
 +    InputStream *ist = ifilter->ist;
 +    int pad_idx = in->pad_idx;
 +    char args[255], name[255];
 +    int ret;
 +
 +    snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s"
 +             ":channel_layout=0x%"PRIx64,
 +             1, ist->st->codec->sample_rate,
 +             ist->st->codec->sample_rate,
 +             av_get_sample_fmt_name(ist->st->codec->sample_fmt),
 +             ist->st->codec->channel_layout);
 +    snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
 +             ist->file_index, ist->st->index);
 +
 +    if ((ret = avfilter_graph_create_filter(&ifilter->filter, filter,
 +                                            name, args, NULL,
 +                                            fg->graph)) < 0)
 +        return ret;
 +
 +#define AUTO_INSERT_FILTER_INPUT(opt_name, filter_name, arg) do {                 \
 +    AVFilterContext *filt_ctx;                                              \
 +                                                                            \
 +    av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi "            \
 +           "similarly to -af " filter_name "=%s.\n", arg);                  \
 +                                                                            \
 +    snprintf(name, sizeof(name), "graph %d %s for input stream %d:%d",      \
 +                fg->index, filter_name, ist->file_index, ist->st->index);   \
 +    ret = avfilter_graph_create_filter(&filt_ctx,                           \
 +                                       avfilter_get_by_name(filter_name),   \
 +                                       name, arg, NULL, fg->graph);         \
 +    if (ret < 0)                                                            \
 +        return ret;                                                         \
 +                                                                            \
 +    ret = avfilter_link(filt_ctx, 0, first_filter, pad_idx);                \
 +    if (ret < 0)                                                            \
 +        return ret;                                                         \
 +                                                                            \
 +    first_filter = filt_ctx;                                                  \
 +} while (0)
 +
 +    if (audio_sync_method > 0) {
 +        char args[256] = {0};
 +
 +        av_strlcatf(args, sizeof(args), "min_comp=0.001:min_hard_comp=%f", audio_drift_threshold);
 +        if (audio_sync_method > 1)
 +            av_strlcatf(args, sizeof(args), ":max_soft_comp=%f", audio_sync_method/(double)ist->st->codec->sample_rate);
 +        AUTO_INSERT_FILTER_INPUT("-async", "aresample", args);
 +    }
 +
 +//     if (ost->audio_channels_mapped) {
 +//         int i;
 +//         AVBPrint pan_buf;
 +//         av_bprint_init(&pan_buf, 256, 8192);
 +//         av_bprintf(&pan_buf, "0x%"PRIx64,
 +//                    av_get_default_channel_layout(ost->audio_channels_mapped));
 +//         for (i = 0; i < ost->audio_channels_mapped; i++)
 +//             if (ost->audio_channels_map[i] != -1)
 +//                 av_bprintf(&pan_buf, ":c%d=c%d", i, ost->audio_channels_map[i]);
 +//         AUTO_INSERT_FILTER_INPUT("-map_channel", "pan", pan_buf.str);
 +//         av_bprint_finalize(&pan_buf, NULL);
 +//     }
 +
 +    if (audio_volume != 256) {
 +        char args[256];
 +
 +        snprintf(args, sizeof(args), "%f", audio_volume / 256.);
 +        AUTO_INSERT_FILTER_INPUT("-vol", "volume", args);
 +    }
 +    if ((ret = avfilter_link(ifilter->filter, 0, first_filter, pad_idx)) < 0)
 +        return ret;
 +
 +    return 0;
 +}
 +
 +static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter,
 +                                  AVFilterInOut *in)
 +{
 +    av_freep(&ifilter->name);
 +    DESCRIBE_FILTER_LINK(ifilter, in, 1);
 +
 +    switch (avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx)) {
 +    case AVMEDIA_TYPE_VIDEO: return configure_input_video_filter(fg, ifilter, in);
 +    case AVMEDIA_TYPE_AUDIO: return configure_input_audio_filter(fg, ifilter, in);
 +    default: av_assert0(0);
 +    }
 +}
 +
 +int configure_filtergraph(FilterGraph *fg)
 +{
 +    AVFilterInOut *inputs, *outputs, *cur;
 +    int ret, i, init = !fg->graph, simple = !fg->graph_desc;
 +    const char *graph_desc = simple ? fg->outputs[0]->ost->avfilter :
 +                                      fg->graph_desc;
 +
 +    avfilter_graph_free(&fg->graph);
 +    if (!(fg->graph = avfilter_graph_alloc()))
 +        return AVERROR(ENOMEM);
 +
 +    if (simple) {
 +        OutputStream *ost = fg->outputs[0]->ost;
 +        char args[255];
 +        snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags);
 +        fg->graph->scale_sws_opts = av_strdup(args);
 +    }
 +
 +    if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0)
 +        return ret;
 +
 +    if (simple && (!inputs || inputs->next || !outputs || outputs->next)) {
 +        av_log(NULL, AV_LOG_ERROR, "Simple filtergraph '%s' does not have "
 +               "exactly one input and output.\n", graph_desc);
 +        return AVERROR(EINVAL);
 +    }
 +
 +    for (cur = inputs; !simple && init && cur; cur = cur->next)
 +        init_input_filter(fg, cur);
 +
 +    for (cur = inputs, i = 0; cur; cur = cur->next, i++)
 +        if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0)
 +            return ret;
 +    avfilter_inout_free(&inputs);
 +
 +    if (!init || simple) {
 +        /* 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;
 +}
 +
 +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;
 +}
 +
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -193,62 -194,8 +193,62 @@@ static void dvb_encode_rle4(uint8_t **p
      *pq = q;
  }
  
 +static void dvb_encode_rle8(uint8_t **pq,
 +                            const uint8_t *bitmap, int linesize,
 +                            int w, int h)
 +{
 +    uint8_t *q;
 +    int x, y, len, x1, color;
 +
 +    q = *pq;
 +
 +    for (y = 0; y < h; y++) {
 +        *q++ = 0x12;
 +
 +        x = 0;
 +        while (x < w) {
 +            x1 = x;
 +            color = bitmap[x1++];
 +            while (x1 < w && bitmap[x1] == color)
 +                x1++;
 +            len = x1 - x;
 +            if (len == 1 && color) {
 +                // 00000001 to 11111111           1 pixel in colour x
 +                *q++ = color;
 +            } else {
 +                if (color == 0x00) {
 +                    // 00000000 0LLLLLLL          L pixels (1-127) in colour 0 (L > 0)
 +                    len = FFMIN(len, 127);
 +                    *q++ = 0x00;
 +                    *q++ = len;
 +                } else if (len > 2) {
 +                    // 00000000 1LLLLLLL CCCCCCCC L pixels (3-127) in colour C (L > 2)
 +                    len = FFMIN(len, 127);
 +                    *q++ = 0x00;
 +                    *q++ = 0x80+len;
 +                    *q++ = color;
 +                }
 +                else if (len == 2) {
 +                    *q++ = color;
 +                    *q++ = color;
 +                } else {
 +                    *q++ = color;
 +                    len = 1;
 +                }
 +            }
 +            x += len;
 +        }
 +        /* end of line */
 +        // 00000000 00000000 end of 8-bit/pixel_code_string
 +        *q++ = 0x00;
 +        *q++ = 0x00;
 +        bitmap += linesize;
 +    }
 +    *pq = q;
 +}
 +
  static int encode_dvb_subtitles(DVBSubtitleContext *s,
-                                 uint8_t *outbuf, AVSubtitle *h)
+                                 uint8_t *outbuf, const AVSubtitle *h)
  {
      uint8_t *q, *pseg_len;
      int page_id, region_id, clut_id, object_id, i, bpp_index, page_state;
@@@ -416,13 -205,13 +416,13 @@@ static int dvdsub_init(AVCodecContext *
  }
  
  static int dvdsub_encode(AVCodecContext *avctx,
-                          unsigned char *buf, int buf_size, void *data)
+                          unsigned char *buf, int buf_size,
+                          const AVSubtitle *sub)
  {
      //DVDSubtitleContext *s = avctx->priv_data;
-     AVSubtitle *sub = data;
      int ret;
  
 -    ret = encode_dvd_subtitles(buf, buf_size, sub);
 +    ret = encode_dvd_subtitles(avctx, buf, buf_size, sub);
      return ret;
  }
  
@@@ -430,8 -219,6 +430,8 @@@ AVCodec ff_dvdsub_encoder = 
      .name           = "dvdsub",
      .type           = AVMEDIA_TYPE_SUBTITLE,
      .id             = AV_CODEC_ID_DVD_SUBTITLE,
-     .encode         = dvdsub_encode,
 +    .init           = dvdsub_init,
+     .encode_sub     = dvdsub_encode,
      .long_name      = NULL_IF_CONFIG_SMALL("DVD subtitles"),
 +    .priv_data_size = sizeof(DVDSubtitleContext),
  };
index 3f73f8b,0000000..7f1b5b8
mode 100644,000000..100644
--- /dev/null
@@@ -1,162 -1,0 +1,161 @@@
-                                  int bufsize, void *data)
 +/*
 + * 3GPP TS 26.245 Timed Text encoder
 + * Copyright (c) 2012  Philip Langdale <philipl@overt.org>
 + *
 + * This file is part of FFmpeg.
 + *
 + * FFmpeg is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + *
 + * FFmpeg is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with FFmpeg; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 + */
 +
 +#include <stdarg.h>
 +#include "avcodec.h"
 +#include "libavutil/avstring.h"
 +#include "libavutil/intreadwrite.h"
 +#include "ass_split.h"
 +#include "ass.h"
 +
 +typedef struct {
 +    ASSSplitContext *ass_ctx;
 +    char buffer[2048];
 +    char *ptr;
 +    char *end;
 +} MovTextContext;
 +
 +
 +static av_cold int mov_text_encode_init(AVCodecContext *avctx)
 +{
 +    /*
 +     * For now, we'll use a fixed default style. When we add styling
 +     * support, this will be generated from the ASS style.
 +     */
 +    static uint8_t text_sample_entry[] = {
 +        0x00, 0x00, 0x00, 0x00, // uint32_t displayFlags
 +        0x01,                   // int8_t horizontal-justification
 +        0xFF,                   // int8_t vertical-justification
 +        0x00, 0x00, 0x00, 0x00, // uint8_t background-color-rgba[4]
 +        // BoxRecord {
 +        0x00, 0x00,             // int16_t top
 +        0x00, 0x00,             // int16_t left
 +        0x00, 0x00,             // int16_t bottom
 +        0x00, 0x00,             // int16_t right
 +        // };
 +        // StyleRecord {
 +        0x00, 0x00,             // uint16_t startChar
 +        0x00, 0x00,             // uint16_t endChar
 +        0x00, 0x01,             // uint16_t font-ID
 +        0x00,                   // uint8_t face-style-flags
 +        0x12,                   // uint8_t font-size
 +        0xFF, 0xFF, 0xFF, 0xFF, // uint8_t text-color-rgba[4]
 +        // };
 +        // FontTableBox {
 +        0x00, 0x00, 0x00, 0x12, // uint32_t size
 +        'f', 't', 'a', 'b',     // uint8_t name[4]
 +        0x00, 0x01,             // uint16_t entry-count
 +        // FontRecord {
 +        0x00, 0x01,             // uint16_t font-ID
 +        0x05,                   // uint8_t font-name-length
 +        'S', 'e', 'r', 'i', 'f',// uint8_t font[font-name-length]
 +        // };
 +        // };
 +    };
 +
 +    MovTextContext *s = avctx->priv_data;
 +
 +    avctx->extradata_size = sizeof text_sample_entry;
 +    avctx->extradata = av_mallocz(avctx->extradata_size);
 +    if (!avctx->extradata)
 +        return AVERROR(ENOMEM);
 +
 +    memcpy(avctx->extradata, text_sample_entry, avctx->extradata_size);
 +
 +    s->ass_ctx = ff_ass_split(avctx->subtitle_header);
 +    return s->ass_ctx ? 0 : AVERROR_INVALIDDATA;
 +}
 +
 +static void mov_text_text_cb(void *priv, const char *text, int len)
 +{
 +    MovTextContext *s = priv;
 +    av_strlcpy(s->ptr, text, FFMIN(s->end - s->ptr, len + 1));
 +    s->ptr += len;
 +}
 +
 +static void mov_text_new_line_cb(void *priv, int forced)
 +{
 +    MovTextContext *s = priv;
 +    av_strlcpy(s->ptr, "\n", FFMIN(s->end - s->ptr, 2));
 +    s->ptr++;
 +}
 +
 +static const ASSCodesCallbacks mov_text_callbacks = {
 +    .text     = mov_text_text_cb,
 +    .new_line = mov_text_new_line_cb,
 +};
 +
 +static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf,
-     AVSubtitle *sub = data;
++                                 int bufsize, const AVSubtitle *sub)
 +{
 +    MovTextContext *s = avctx->priv_data;
-     .encode         = mov_text_encode_frame,
 +    ASSDialog *dialog;
 +    int i, len, num;
 +
 +    s->ptr = s->buffer;
 +    s->end = s->ptr + sizeof(s->buffer);
 +
 +    for (i = 0; i < sub->num_rects; i++) {
 +
 +        if (sub->rects[i]->type != SUBTITLE_ASS) {
 +            av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
 +            return AVERROR(ENOSYS);
 +        }
 +
 +        dialog = ff_ass_split_dialog(s->ass_ctx, sub->rects[i]->ass, 0, &num);
 +        for (; dialog && num--; dialog++) {
 +            ff_ass_split_override_codes(&mov_text_callbacks, s, dialog->text);
 +        }
 +    }
 +
 +    if (s->ptr == s->buffer)
 +        return 0;
 +
 +    AV_WB16(buf, strlen(s->buffer));
 +    buf += 2;
 +
 +    len = av_strlcpy(buf, s->buffer, bufsize - 2);
 +
 +    if (len > bufsize-3) {
 +        av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
 +        return AVERROR(EINVAL);
 +    }
 +
 +    return len + 2;
 +}
 +
 +static int mov_text_encode_close(AVCodecContext *avctx)
 +{
 +    MovTextContext *s = avctx->priv_data;
 +    ff_ass_split_free(s->ass_ctx);
 +    return 0;
 +}
 +
 +AVCodec ff_movtext_encoder = {
 +    .name           = "mov_text",
 +    .long_name      = NULL_IF_CONFIG_SMALL("3GPP Timed Text subtitle"),
 +    .type           = AVMEDIA_TYPE_SUBTITLE,
 +    .id             = AV_CODEC_ID_MOV_TEXT,
 +    .priv_data_size = sizeof(MovTextContext),
 +    .init           = mov_text_encode_init,
++    .encode_sub     = mov_text_encode_frame,
 +    .close          = mov_text_encode_close,
 +};
index fa85ef5,0000000..473c88f
mode 100644,000000..100644
--- /dev/null
@@@ -1,318 -1,0 +1,317 @@@
-                             unsigned char *buf, int bufsize, void *data)
 +/*
 + * SubRip subtitle encoder
 + * Copyright (c) 2010  Aurelien Jacobs <aurel@gnuage.org>
 + *
 + * This file is part of FFmpeg.
 + *
 + * FFmpeg is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + *
 + * FFmpeg is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with FFmpeg; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 + */
 +
 +#include <stdarg.h>
 +#include "avcodec.h"
 +#include "libavutil/avstring.h"
 +#include "ass_split.h"
 +#include "ass.h"
 +
 +
 +#define SRT_STACK_SIZE 64
 +
 +typedef struct {
 +    AVCodecContext *avctx;
 +    ASSSplitContext *ass_ctx;
 +    char buffer[2048];
 +    char *ptr;
 +    char *end;
 +    char *dialog_start;
 +    int count;
 +    char stack[SRT_STACK_SIZE];
 +    int stack_ptr;
 +    int alignment_applied;
 +} SRTContext;
 +
 +
 +#ifdef __GNUC__
 +__attribute__ ((__format__ (__printf__, 2, 3)))
 +#endif
 +static void srt_print(SRTContext *s, const char *str, ...)
 +{
 +    va_list vargs;
 +    va_start(vargs, str);
 +    s->ptr += vsnprintf(s->ptr, s->end - s->ptr, str, vargs);
 +    va_end(vargs);
 +}
 +
 +static int srt_stack_push(SRTContext *s, const char c)
 +{
 +    if (s->stack_ptr >= SRT_STACK_SIZE)
 +        return -1;
 +    s->stack[s->stack_ptr++] = c;
 +    return 0;
 +}
 +
 +static char srt_stack_pop(SRTContext *s)
 +{
 +    if (s->stack_ptr <= 0)
 +        return 0;
 +    return s->stack[--s->stack_ptr];
 +}
 +
 +static int srt_stack_find(SRTContext *s, const char c)
 +{
 +    int i;
 +    for (i = s->stack_ptr-1; i >= 0; i--)
 +        if (s->stack[i] == c)
 +            break;
 +    return i;
 +}
 +
 +static void srt_close_tag(SRTContext *s, char tag)
 +{
 +    srt_print(s, "</%c%s>", tag, tag == 'f' ? "ont" : "");
 +}
 +
 +static void srt_stack_push_pop(SRTContext *s, const char c, int close)
 +{
 +    if (close) {
 +        int i = c ? srt_stack_find(s, c) : 0;
 +        if (i < 0)
 +            return;
 +        while (s->stack_ptr != i)
 +            srt_close_tag(s, srt_stack_pop(s));
 +    } else if (srt_stack_push(s, c) < 0)
 +        av_log(s->avctx, AV_LOG_ERROR, "tag stack overflow\n");
 +}
 +
 +static void srt_style_apply(SRTContext *s, const char *style)
 +{
 +    ASSStyle *st = ff_ass_style_get(s->ass_ctx, style);
 +    if (st) {
 +        int c = st->primary_color & 0xFFFFFF;
 +        if (st->font_name && strcmp(st->font_name, ASS_DEFAULT_FONT) ||
 +            st->font_size != ASS_DEFAULT_FONT_SIZE ||
 +            c != ASS_DEFAULT_COLOR) {
 +            srt_print(s, "<font");
 +            if (st->font_name && strcmp(st->font_name, ASS_DEFAULT_FONT))
 +                srt_print(s, " face=\"%s\"", st->font_name);
 +            if (st->font_size != ASS_DEFAULT_FONT_SIZE)
 +                srt_print(s, " size=\"%d\"", st->font_size);
 +            if (c != ASS_DEFAULT_COLOR)
 +                srt_print(s, " color=\"#%06x\"",
 +                          (c & 0xFF0000) >> 16 | c & 0xFF00 | (c & 0xFF) << 16);
 +            srt_print(s, ">");
 +            srt_stack_push(s, 'f');
 +        }
 +        if (st->bold != ASS_DEFAULT_BOLD) {
 +            srt_print(s, "<b>");
 +            srt_stack_push(s, 'b');
 +        }
 +        if (st->italic != ASS_DEFAULT_ITALIC) {
 +            srt_print(s, "<i>");
 +            srt_stack_push(s, 'i');
 +        }
 +        if (st->underline != ASS_DEFAULT_UNDERLINE) {
 +            srt_print(s, "<u>");
 +            srt_stack_push(s, 'u');
 +        }
 +        if (st->alignment != ASS_DEFAULT_ALIGNMENT) {
 +            srt_print(s, "{\\an%d}", st->alignment);
 +            s->alignment_applied = 1;
 +        }
 +    }
 +}
 +
 +
 +static av_cold int srt_encode_init(AVCodecContext *avctx)
 +{
 +    SRTContext *s = avctx->priv_data;
 +    s->avctx = avctx;
 +    s->ass_ctx = ff_ass_split(avctx->subtitle_header);
 +    return s->ass_ctx ? 0 : AVERROR_INVALIDDATA;
 +}
 +
 +static void srt_text_cb(void *priv, const char *text, int len)
 +{
 +    SRTContext *s = priv;
 +    av_strlcpy(s->ptr, text, FFMIN(s->end-s->ptr, len+1));
 +    s->ptr += len;
 +}
 +
 +static void srt_new_line_cb(void *priv, int forced)
 +{
 +    srt_print(priv, "\r\n");
 +}
 +
 +static void srt_style_cb(void *priv, char style, int close)
 +{
 +    srt_stack_push_pop(priv, style, close);
 +    if (!close)
 +        srt_print(priv, "<%c>", style);
 +}
 +
 +static void srt_color_cb(void *priv, unsigned int color, unsigned int color_id)
 +{
 +    if (color_id > 1)
 +        return;
 +    srt_stack_push_pop(priv, 'f', color == 0xFFFFFFFF);
 +    if (color != 0xFFFFFFFF)
 +        srt_print(priv, "<font color=\"#%06x\">",
 +              (color & 0xFF0000) >> 16 | color & 0xFF00 | (color & 0xFF) << 16);
 +}
 +
 +static void srt_font_name_cb(void *priv, const char *name)
 +{
 +    srt_stack_push_pop(priv, 'f', !name);
 +    if (name)
 +        srt_print(priv, "<font face=\"%s\">", name);
 +}
 +
 +static void srt_font_size_cb(void *priv, int size)
 +{
 +    srt_stack_push_pop(priv, 'f', size < 0);
 +    if (size >= 0)
 +        srt_print(priv, "<font size=\"%d\">", size);
 +}
 +
 +static void srt_alignment_cb(void *priv, int alignment)
 +{
 +    SRTContext *s = priv;
 +    if (!s->alignment_applied && alignment >= 0) {
 +        srt_print(s, "{\\an%d}", alignment);
 +        s->alignment_applied = 1;
 +    }
 +}
 +
 +static void srt_cancel_overrides_cb(void *priv, const char *style)
 +{
 +    srt_stack_push_pop(priv, 0, 1);
 +    srt_style_apply(priv, style);
 +}
 +
 +static void srt_move_cb(void *priv, int x1, int y1, int x2, int y2,
 +                        int t1, int t2)
 +{
 +    SRTContext *s = priv;
 +    char buffer[32];
 +    int len = snprintf(buffer, sizeof(buffer),
 +                       "  X1:%03u X2:%03u Y1:%03u Y2:%03u", x1, x2, y1, y2);
 +    if (s->end - s->ptr > len) {
 +        memmove(s->dialog_start+len, s->dialog_start, s->ptr-s->dialog_start+1);
 +        memcpy(s->dialog_start, buffer, len);
 +        s->ptr += len;
 +    }
 +}
 +
 +static void srt_end_cb(void *priv)
 +{
 +    srt_stack_push_pop(priv, 0, 1);
 +    srt_print(priv, "\r\n\r\n");
 +}
 +
 +static const ASSCodesCallbacks srt_callbacks = {
 +    .text             = srt_text_cb,
 +    .new_line         = srt_new_line_cb,
 +    .style            = srt_style_cb,
 +    .color            = srt_color_cb,
 +    .font_name        = srt_font_name_cb,
 +    .font_size        = srt_font_size_cb,
 +    .alignment        = srt_alignment_cb,
 +    .cancel_overrides = srt_cancel_overrides_cb,
 +    .move             = srt_move_cb,
 +    .end              = srt_end_cb,
 +};
 +
 +static int srt_encode_frame(AVCodecContext *avctx,
-     AVSubtitle *sub = data;
++                            unsigned char *buf, int bufsize, const AVSubtitle *sub)
 +{
 +    SRTContext *s = avctx->priv_data;
-     .encode         = srt_encode_frame,
 +    ASSDialog *dialog;
 +    int i, len, num;
 +
 +    s->ptr = s->buffer;
 +    s->end = s->ptr + sizeof(s->buffer);
 +
 +    for (i=0; i<sub->num_rects; i++) {
 +
 +        if (sub->rects[i]->type != SUBTITLE_ASS) {
 +            av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
 +            return AVERROR(ENOSYS);
 +        }
 +
 +        dialog = ff_ass_split_dialog(s->ass_ctx, sub->rects[i]->ass, 0, &num);
 +        for (; dialog && num--; dialog++) {
 +            if (avctx->codec->id == CODEC_ID_SRT) {
 +                int sh, sm, ss, sc = 10 * dialog->start;
 +                int eh, em, es, ec = 10 * dialog->end;
 +                sh = sc/3600000;  sc -= 3600000*sh;
 +                sm = sc/  60000;  sc -=   60000*sm;
 +                ss = sc/   1000;  sc -=    1000*ss;
 +                eh = ec/3600000;  ec -= 3600000*eh;
 +                em = ec/  60000;  ec -=   60000*em;
 +                es = ec/   1000;  ec -=    1000*es;
 +                srt_print(s,"%d\r\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\r\n",
 +                          ++s->count, sh, sm, ss, sc, eh, em, es, ec);
 +            }
 +            s->alignment_applied = 0;
 +            s->dialog_start = s->ptr - 2;
 +            srt_style_apply(s, dialog->style);
 +            ff_ass_split_override_codes(&srt_callbacks, s, dialog->text);
 +        }
 +    }
 +
 +    if (s->ptr == s->buffer)
 +        return 0;
 +
 +    len = av_strlcpy(buf, s->buffer, bufsize);
 +
 +    if (len > bufsize-1) {
 +        av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
 +        return -1;
 +    }
 +
 +    return len;
 +}
 +
 +static int srt_encode_close(AVCodecContext *avctx)
 +{
 +    SRTContext *s = avctx->priv_data;
 +    ff_ass_split_free(s->ass_ctx);
 +    return 0;
 +}
 +
 +#if CONFIG_SRT_ENCODER
 +AVCodec ff_srt_encoder = {
 +    .name           = "srt",
 +    .long_name      = NULL_IF_CONFIG_SMALL("SubRip subtitle with embedded timing"),
 +    .type           = AVMEDIA_TYPE_SUBTITLE,
 +    .id             = AV_CODEC_ID_SRT,
 +    .priv_data_size = sizeof(SRTContext),
 +    .init           = srt_encode_init,
-     .encode         = srt_encode_frame,
++    .encode_sub     = srt_encode_frame,
 +    .close          = srt_encode_close,
 +};
 +#endif
 +
 +#if CONFIG_SUBRIP_ENCODER
 +AVCodec ff_subrip_encoder = {
 +    .name           = "subrip",
 +    .long_name      = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
 +    .type           = AVMEDIA_TYPE_SUBTITLE,
 +    .id             = AV_CODEC_ID_SUBRIP,
 +    .priv_data_size = sizeof(SRTContext),
 +    .init           = srt_encode_init,
++    .encode_sub     = srt_encode_frame,
 +    .close          = srt_encode_close,
 +};
 +#endif
@@@ -1406,8 -1172,9 +1406,8 @@@ int avcodec_encode_subtitle(AVCodecCont
          av_log(avctx, AV_LOG_ERROR, "start_display_time must be 0.\n");
          return -1;
      }
 -    if(sub->num_rects == 0 || !sub->rects)
 -        return -1;
 +
-     ret = avctx->codec->encode(avctx, buf, buf_size, (void *)(intptr_t)sub);
+     ret = avctx->codec->encode_sub(avctx, buf, buf_size, sub);
      avctx->frame_number++;
      return ret;
  }
Simple merge
Simple merge
@@@ -142,6 -148,5 +142,6 @@@ AVFilter avfilter_af_channelsplit = 
                                         .type           = AVMEDIA_TYPE_AUDIO,
                                         .filter_samples = filter_samples, },
                                       { NULL }},
-     .outputs = (const AVFilterPad[]){{ NULL }},
+     .outputs = NULL,
 +    .priv_class = &channelsplit_class,
  };
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -75,34 -70,65 +75,34 @@@ typedef struct 
          return AVERROR(EINVAL);\
      }
  
 -int av_buffersrc_write_frame(AVFilterContext *buffer_filter, const AVFrame *frame)
 +int av_buffersrc_add_frame(AVFilterContext *buffer_src,
 +                           const AVFrame *frame, int flags)
  {
 -    BufferSourceContext *c = buffer_filter->priv;
 -    AVFilterBufferRef *buf;
 +    AVFilterBufferRef *picref;
      int ret;
  
 -    if (!frame) {
 -        c->eof = 1;
 -        return 0;
 -    } else if (c->eof)
 -        return AVERROR(EINVAL);
 -
 -    if (!av_fifo_space(c->fifo) &&
 -        (ret = av_fifo_realloc2(c->fifo, av_fifo_size(c->fifo) +
 -                                         sizeof(buf))) < 0)
 -        return ret;
 -
 -    switch (buffer_filter->outputs[0]->type) {
 -    case AVMEDIA_TYPE_VIDEO:
 -        CHECK_VIDEO_PARAM_CHANGE(buffer_filter, c, frame->width, frame->height,
 -                                 frame->format);
 -        buf = ff_get_video_buffer(buffer_filter->outputs[0], AV_PERM_WRITE,
 -                                  c->w, c->h);
 -        if (!buf)
 -            return AVERROR(ENOMEM);
 -
 -        av_image_copy(buf->data, buf->linesize, frame->data, frame->linesize,
 -                      c->pix_fmt, c->w, c->h);
 -        break;
 -    case AVMEDIA_TYPE_AUDIO:
 -        CHECK_AUDIO_PARAM_CHANGE(buffer_filter, c, frame->sample_rate, frame->channel_layout,
 -                                 frame->format);
 -        buf = ff_get_audio_buffer(buffer_filter->outputs[0], AV_PERM_WRITE,
 -                                  frame->nb_samples);
 -        if (!buf)
 -            return AVERROR(ENOMEM);
 -
 -        av_samples_copy(buf->extended_data, frame->extended_data,
 -                        0, 0, frame->nb_samples,
 -                        av_get_channel_layout_nb_channels(frame->channel_layout),
 -                        frame->format);
 -        break;
 -    default:
 -        return AVERROR(EINVAL);
 -    }
 -
 -    avfilter_copy_frame_props(buf, frame);
 +    if (!frame) /* NULL for EOF */
 +        return av_buffersrc_add_ref(buffer_src, NULL, flags);
  
 -    if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) {
 -        avfilter_unref_buffer(buf);
 -        return ret;
 -    }
 +    picref = avfilter_get_buffer_ref_from_frame(buffer_src->outputs[0]->type,
 +                                                frame, AV_PERM_WRITE);
 +    if (!picref)
 +        return AVERROR(ENOMEM);
 +    ret = av_buffersrc_add_ref(buffer_src, picref, flags);
 +    picref->buf->data[0] = NULL;
 +    avfilter_unref_buffer(picref);
 +    return ret;
 +}
  
- int av_buffersrc_write_frame(AVFilterContext *buffer_filter, AVFrame *frame)
 -    return 0;
++int av_buffersrc_write_frame(AVFilterContext *buffer_filter, const AVFrame *frame)
 +{
 +    return av_buffersrc_add_frame(buffer_filter, frame, 0);
  }
  
 -int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf)
 +int av_buffersrc_add_ref(AVFilterContext *s, AVFilterBufferRef *buf, int flags)
  {
      BufferSourceContext *c = s->priv;
 +    AVFilterBufferRef *to_free = NULL;
      int ret;
  
      if (!buf) {
Simple merge
Simple merge
index f221286,0000000..41500f3
mode 100644,000000..100644
--- /dev/null
@@@ -1,644 -1,0 +1,644 @@@
-     .inputs    = (const AVFilterPad[]) {{ .name = NULL }},
 +/*
 + * Copyright (c) 2010 Stefano Sabatini
 + * Copyright (c) 2008 Victor Paesa
 + *
 + * This file is part of FFmpeg.
 + *
 + * FFmpeg is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + *
 + * FFmpeg is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with FFmpeg; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 + */
 +
 +/**
 + * @file
 + * movie video source
 + *
 + * @todo use direct rendering (no allocation of a new frame)
 + * @todo support a PTS correction mechanism
 + */
 +
 +/* #define DEBUG */
 +
 +#include <float.h>
 +#include "libavutil/avstring.h"
 +#include "libavutil/avassert.h"
 +#include "libavutil/opt.h"
 +#include "libavutil/imgutils.h"
 +#include "libavutil/timestamp.h"
 +#include "libavformat/avformat.h"
 +#include "audio.h"
 +#include "avcodec.h"
 +#include "avfilter.h"
 +#include "formats.h"
 +#include "internal.h"
 +#include "video.h"
 +
 +typedef struct {
 +    AVStream *st;
 +    int done;
 +} MovieStream;
 +
 +typedef struct {
 +    /* common A/V fields */
 +    const AVClass *class;
 +    int64_t seek_point;   ///< seekpoint in microseconds
 +    double seek_point_d;
 +    char *format_name;
 +    char *file_name;
 +    char *stream_specs; /**< user-provided list of streams, separated by + */
 +    int stream_index; /**< for compatibility */
 +    int loop_count;
 +
 +    AVFormatContext *format_ctx;
 +    int eof;
 +    AVPacket pkt, pkt0;
 +    AVFrame *frame;   ///< video frame to store the decoded images in
 +
 +    int max_stream_index; /**< max stream # actually used for output */
 +    MovieStream *st; /**< array of all streams, one per output */
 +    int *out_index; /**< stream number -> output number map, or -1 */
 +} MovieContext;
 +
 +#define OFFSET(x) offsetof(MovieContext, x)
 +#define F AV_OPT_FLAG_FILTERING_PARAM
 +
 +static const AVOption movie_options[]= {
 +{"format_name",  "set format name",         OFFSET(format_name),  AV_OPT_TYPE_STRING, {.str =  0},  CHAR_MIN, CHAR_MAX, F },
 +{"f",            "set format name",         OFFSET(format_name),  AV_OPT_TYPE_STRING, {.str =  0},  CHAR_MIN, CHAR_MAX, F },
 +{"streams",      "set streams",             OFFSET(stream_specs), AV_OPT_TYPE_STRING, {.str =  0},  CHAR_MAX, CHAR_MAX, F },
 +{"s",            "set streams",             OFFSET(stream_specs), AV_OPT_TYPE_STRING, {.str =  0},  CHAR_MAX, CHAR_MAX, F },
 +{"si",           "set stream index",        OFFSET(stream_index), AV_OPT_TYPE_INT,    {.i64 = -1},  -1,       INT_MAX, F },
 +{"stream_index", "set stream index",        OFFSET(stream_index), AV_OPT_TYPE_INT,    {.i64 = -1},  -1,       INT_MAX, F },
 +{"seek_point",   "set seekpoint (seconds)", OFFSET(seek_point_d), AV_OPT_TYPE_DOUBLE, {.dbl =  0},  0,        (INT64_MAX-1) / 1000000, F },
 +{"sp",           "set seekpoint (seconds)", OFFSET(seek_point_d), AV_OPT_TYPE_DOUBLE, {.dbl =  0},  0,        (INT64_MAX-1) / 1000000, F },
 +{"loop",         "set loop count",          OFFSET(loop_count),   AV_OPT_TYPE_INT,    {.i64 =  1},  0,        INT_MAX, F },
 +{NULL},
 +};
 +
 +static int movie_config_output_props(AVFilterLink *outlink);
 +static int movie_request_frame(AVFilterLink *outlink);
 +
 +static AVStream *find_stream(void *log, AVFormatContext *avf, const char *spec)
 +{
 +    int i, ret, already = 0, stream_id = -1;
 +    char type_char, dummy;
 +    AVStream *found = NULL;
 +    enum AVMediaType type;
 +
 +    ret = sscanf(spec, "d%[av]%d%c", &type_char, &stream_id, &dummy);
 +    if (ret >= 1 && ret <= 2) {
 +        type = type_char == 'v' ? AVMEDIA_TYPE_VIDEO : AVMEDIA_TYPE_AUDIO;
 +        ret = av_find_best_stream(avf, type, stream_id, -1, NULL, 0);
 +        if (ret < 0) {
 +            av_log(log, AV_LOG_ERROR, "No %s stream with index '%d' found\n",
 +                   av_get_media_type_string(type), stream_id);
 +            return NULL;
 +        }
 +        return avf->streams[ret];
 +    }
 +    for (i = 0; i < avf->nb_streams; i++) {
 +        ret = avformat_match_stream_specifier(avf, avf->streams[i], spec);
 +        if (ret < 0) {
 +            av_log(log, AV_LOG_ERROR,
 +                   "Invalid stream specifier \"%s\"\n", spec);
 +            return NULL;
 +        }
 +        if (!ret)
 +            continue;
 +        if (avf->streams[i]->discard != AVDISCARD_ALL) {
 +            already++;
 +            continue;
 +        }
 +        if (found) {
 +            av_log(log, AV_LOG_WARNING,
 +                   "Ambiguous stream specifier \"%s\", using #%d\n", spec, i);
 +            break;
 +        }
 +        found = avf->streams[i];
 +    }
 +    if (!found) {
 +        av_log(log, AV_LOG_WARNING, "Stream specifier \"%s\" %s\n", spec,
 +               already ? "matched only already used streams" :
 +                         "did not match any stream");
 +        return NULL;
 +    }
 +    if (found->codec->codec_type != AVMEDIA_TYPE_VIDEO &&
 +        found->codec->codec_type != AVMEDIA_TYPE_AUDIO) {
 +        av_log(log, AV_LOG_ERROR, "Stream specifier \"%s\" matched a %s stream,"
 +               "currently unsupported by libavfilter\n", spec,
 +               av_get_media_type_string(found->codec->codec_type));
 +        return NULL;
 +    }
 +    return found;
 +}
 +
 +static int open_stream(void *log, MovieStream *st)
 +{
 +    AVCodec *codec;
 +    int ret;
 +
 +    codec = avcodec_find_decoder(st->st->codec->codec_id);
 +    if (!codec) {
 +        av_log(log, AV_LOG_ERROR, "Failed to find any codec\n");
 +        return AVERROR(EINVAL);
 +    }
 +
 +    if ((ret = avcodec_open2(st->st->codec, codec, NULL)) < 0) {
 +        av_log(log, AV_LOG_ERROR, "Failed to open codec\n");
 +        return ret;
 +    }
 +
 +    return 0;
 +}
 +
 +static int guess_channel_layout(MovieStream *st, int st_index, void *log_ctx)
 +{
 +    AVCodecContext *dec_ctx = st->st->codec;
 +    char buf[256];
 +    int64_t chl = av_get_default_channel_layout(dec_ctx->channels);
 +
 +    if (!chl) {
 +        av_log(log_ctx, AV_LOG_ERROR,
 +               "Channel layout is not set in stream %d, and could not "
 +               "be guessed from the number of channels (%d)\n",
 +               st_index, dec_ctx->channels);
 +        return AVERROR(EINVAL);
 +    }
 +
 +    av_get_channel_layout_string(buf, sizeof(buf), dec_ctx->channels, chl);
 +    av_log(log_ctx, AV_LOG_WARNING,
 +           "Channel layout is not set in output stream %d, "
 +           "guessed channel layout is '%s'\n",
 +           st_index, buf);
 +    dec_ctx->channel_layout = chl;
 +    return 0;
 +}
 +
 +static av_cold int movie_common_init(AVFilterContext *ctx, const char *args, const AVClass *class)
 +{
 +    MovieContext *movie = ctx->priv;
 +    AVInputFormat *iformat = NULL;
 +    int64_t timestamp;
 +    int nb_streams, ret, i;
 +    char default_streams[16], *stream_specs, *spec, *cursor;
 +    char name[16];
 +    AVStream *st;
 +
 +    movie->class = class;
 +    av_opt_set_defaults(movie);
 +
 +    if (args)
 +        movie->file_name = av_get_token(&args, ":");
 +    if (!movie->file_name || !*movie->file_name) {
 +        av_log(ctx, AV_LOG_ERROR, "No filename provided!\n");
 +        return AVERROR(EINVAL);
 +    }
 +
 +    if (*args++ == ':' && (ret = av_set_options_string(movie, args, "=", ":")) < 0)
 +        return ret;
 +
 +    movie->seek_point = movie->seek_point_d * 1000000 + 0.5;
 +
 +    stream_specs = movie->stream_specs;
 +    if (!stream_specs) {
 +        snprintf(default_streams, sizeof(default_streams), "d%c%d",
 +                 !strcmp(ctx->filter->name, "amovie") ? 'a' : 'v',
 +                 movie->stream_index);
 +        stream_specs = default_streams;
 +    }
 +    for (cursor = stream_specs, nb_streams = 1; *cursor; cursor++)
 +        if (*cursor == '+')
 +            nb_streams++;
 +
 +    if (movie->loop_count != 1 && nb_streams != 1) {
 +        av_log(ctx, AV_LOG_ERROR,
 +               "Loop with several streams is currently unsupported\n");
 +        return AVERROR_PATCHWELCOME;
 +    }
 +
 +    av_register_all();
 +
 +    // Try to find the movie format (container)
 +    iformat = movie->format_name ? av_find_input_format(movie->format_name) : NULL;
 +
 +    movie->format_ctx = NULL;
 +    if ((ret = avformat_open_input(&movie->format_ctx, movie->file_name, iformat, NULL)) < 0) {
 +        av_log(ctx, AV_LOG_ERROR,
 +               "Failed to avformat_open_input '%s'\n", movie->file_name);
 +        return ret;
 +    }
 +    if ((ret = avformat_find_stream_info(movie->format_ctx, NULL)) < 0)
 +        av_log(ctx, AV_LOG_WARNING, "Failed to find stream info\n");
 +
 +    // if seeking requested, we execute it
 +    if (movie->seek_point > 0) {
 +        timestamp = movie->seek_point;
 +        // add the stream start time, should it exist
 +        if (movie->format_ctx->start_time != AV_NOPTS_VALUE) {
 +            if (timestamp > INT64_MAX - movie->format_ctx->start_time) {
 +                av_log(ctx, AV_LOG_ERROR,
 +                       "%s: seek value overflow with start_time:%"PRId64" seek_point:%"PRId64"\n",
 +                       movie->file_name, movie->format_ctx->start_time, movie->seek_point);
 +                return AVERROR(EINVAL);
 +            }
 +            timestamp += movie->format_ctx->start_time;
 +        }
 +        if ((ret = av_seek_frame(movie->format_ctx, -1, timestamp, AVSEEK_FLAG_BACKWARD)) < 0) {
 +            av_log(ctx, AV_LOG_ERROR, "%s: could not seek to position %"PRId64"\n",
 +                   movie->file_name, timestamp);
 +            return ret;
 +        }
 +    }
 +
 +    for (i = 0; i < movie->format_ctx->nb_streams; i++)
 +        movie->format_ctx->streams[i]->discard = AVDISCARD_ALL;
 +
 +    movie->st = av_calloc(nb_streams, sizeof(*movie->st));
 +    if (!movie->st)
 +        return AVERROR(ENOMEM);
 +
 +    for (i = 0; i < nb_streams; i++) {
 +        spec = av_strtok(stream_specs, "+", &cursor);
 +        if (!spec)
 +            return AVERROR_BUG;
 +        stream_specs = NULL; /* for next strtok */
 +        st = find_stream(ctx, movie->format_ctx, spec);
 +        if (!st)
 +            return AVERROR(EINVAL);
 +        st->discard = AVDISCARD_DEFAULT;
 +        movie->st[i].st = st;
 +        movie->max_stream_index = FFMAX(movie->max_stream_index, st->index);
 +    }
 +    if (av_strtok(NULL, "+", &cursor))
 +        return AVERROR_BUG;
 +
 +    movie->out_index = av_calloc(movie->max_stream_index + 1,
 +                                 sizeof(*movie->out_index));
 +    if (!movie->out_index)
 +        return AVERROR(ENOMEM);
 +    for (i = 0; i <= movie->max_stream_index; i++)
 +        movie->out_index[i] = -1;
 +    for (i = 0; i < nb_streams; i++)
 +        movie->out_index[movie->st[i].st->index] = i;
 +
 +    for (i = 0; i < nb_streams; i++) {
 +        AVFilterPad pad = { 0 };
 +        snprintf(name, sizeof(name), "out%d", i);
 +        pad.type          = movie->st[i].st->codec->codec_type;
 +        pad.name          = av_strdup(name);
 +        pad.config_props  = movie_config_output_props;
 +        pad.request_frame = movie_request_frame;
 +        ff_insert_outpad(ctx, i, &pad);
 +        ret = open_stream(ctx, &movie->st[i]);
 +        if (ret < 0)
 +            return ret;
 +        if ( movie->st[i].st->codec->codec->type == AVMEDIA_TYPE_AUDIO &&
 +            !movie->st[i].st->codec->channel_layout) {
 +            ret = guess_channel_layout(&movie->st[i], i, ctx);
 +            if (ret < 0)
 +                return ret;
 +        }
 +    }
 +
 +    if (!(movie->frame = avcodec_alloc_frame()) ) {
 +        av_log(log, AV_LOG_ERROR, "Failed to alloc frame\n");
 +        return AVERROR(ENOMEM);
 +    }
 +
 +    av_log(ctx, AV_LOG_VERBOSE, "seek_point:%"PRIi64" format_name:%s file_name:%s stream_index:%d\n",
 +           movie->seek_point, movie->format_name, movie->file_name,
 +           movie->stream_index);
 +
 +    return 0;
 +}
 +
 +static av_cold void movie_uninit(AVFilterContext *ctx)
 +{
 +    MovieContext *movie = ctx->priv;
 +    int i;
 +
 +    for (i = 0; i < ctx->nb_outputs; i++) {
 +        av_freep(&ctx->output_pads[i].name);
 +        if (movie->st[i].st)
 +            avcodec_close(movie->st[i].st->codec);
 +    }
 +    av_opt_free(movie);
 +    av_freep(&movie->file_name);
 +    av_freep(&movie->st);
 +    av_freep(&movie->out_index);
 +    av_freep(&movie->frame);
 +    if (movie->format_ctx)
 +        avformat_close_input(&movie->format_ctx);
 +}
 +
 +static int movie_query_formats(AVFilterContext *ctx)
 +{
 +    MovieContext *movie = ctx->priv;
 +    int list[] = { 0, -1 };
 +    int64_t list64[] = { 0, -1 };
 +    int i;
 +
 +    for (i = 0; i < ctx->nb_outputs; i++) {
 +        MovieStream *st = &movie->st[i];
 +        AVCodecContext *c = st->st->codec;
 +        AVFilterLink *outlink = ctx->outputs[i];
 +
 +        switch (c->codec_type) {
 +        case AVMEDIA_TYPE_VIDEO:
 +            list[0] = c->pix_fmt;
 +            ff_formats_ref(ff_make_format_list(list), &outlink->in_formats);
 +            break;
 +        case AVMEDIA_TYPE_AUDIO:
 +            list[0] = c->sample_fmt;
 +            ff_formats_ref(ff_make_format_list(list), &outlink->in_formats);
 +            list[0] = c->sample_rate;
 +            ff_formats_ref(ff_make_format_list(list), &outlink->in_samplerates);
 +            list64[0] = c->channel_layout;
 +            ff_channel_layouts_ref(avfilter_make_format64_list(list64),
 +                                   &outlink->in_channel_layouts);
 +            break;
 +        }
 +    }
 +
 +    return 0;
 +}
 +
 +static int movie_config_output_props(AVFilterLink *outlink)
 +{
 +    AVFilterContext *ctx = outlink->src;
 +    MovieContext *movie  = ctx->priv;
 +    unsigned out_id = FF_OUTLINK_IDX(outlink);
 +    MovieStream *st = &movie->st[out_id];
 +    AVCodecContext *c = st->st->codec;
 +
 +    outlink->time_base = st->st->time_base;
 +
 +    switch (c->codec_type) {
 +    case AVMEDIA_TYPE_VIDEO:
 +        outlink->w          = c->width;
 +        outlink->h          = c->height;
 +        outlink->frame_rate = st->st->r_frame_rate;
 +        break;
 +    case AVMEDIA_TYPE_AUDIO:
 +        break;
 +    }
 +
 +    return 0;
 +}
 +
 +static AVFilterBufferRef *frame_to_buf(enum AVMediaType type, AVFrame *frame,
 +                                       AVFilterLink *outlink)
 +{
 +    AVFilterBufferRef *buf, *copy;
 +
 +    buf = avfilter_get_buffer_ref_from_frame(type, frame,
 +                                             AV_PERM_WRITE |
 +                                             AV_PERM_PRESERVE |
 +                                             AV_PERM_REUSE2);
 +    if (!buf)
 +        return NULL;
 +    buf->pts = av_frame_get_best_effort_timestamp(frame);
 +    copy = ff_copy_buffer_ref(outlink, buf);
 +    if (!copy)
 +        return NULL;
 +    buf->buf->data[0] = NULL; /* it belongs to the frame */
 +    avfilter_unref_buffer(buf);
 +    return copy;
 +}
 +
 +static char *describe_bufref_to_str(char *dst, size_t dst_size,
 +                                    AVFilterBufferRef *buf,
 +                                    AVFilterLink *link)
 +{
 +    switch (buf->type) {
 +    case AVMEDIA_TYPE_VIDEO:
 +        snprintf(dst, dst_size,
 +                 "video pts:%s time:%s pos:%"PRId64" size:%dx%d aspect:%d/%d",
 +                 av_ts2str(buf->pts), av_ts2timestr(buf->pts, &link->time_base),
 +                 buf->pos, buf->video->w, buf->video->h,
 +                 buf->video->sample_aspect_ratio.num,
 +                 buf->video->sample_aspect_ratio.den);
 +                 break;
 +    case AVMEDIA_TYPE_AUDIO:
 +        snprintf(dst, dst_size,
 +                 "audio pts:%s time:%s pos:%"PRId64" samples:%d",
 +                 av_ts2str(buf->pts), av_ts2timestr(buf->pts, &link->time_base),
 +                 buf->pos, buf->audio->nb_samples);
 +                 break;
 +    default:
 +        snprintf(dst, dst_size, "%s BUG", av_get_media_type_string(buf->type));
 +        break;
 +    }
 +    return dst;
 +}
 +
 +#define describe_bufref(buf, link) \
 +    describe_bufref_to_str((char[1024]){0}, 1024, buf, link)
 +
 +static int rewind_file(AVFilterContext *ctx)
 +{
 +    MovieContext *movie = ctx->priv;
 +    int64_t timestamp = movie->seek_point;
 +    int ret, i;
 +
 +    if (movie->format_ctx->start_time != AV_NOPTS_VALUE)
 +        timestamp += movie->format_ctx->start_time;
 +    ret = av_seek_frame(movie->format_ctx, -1, timestamp, AVSEEK_FLAG_BACKWARD);
 +    if (ret < 0) {
 +        av_log(ctx, AV_LOG_ERROR, "Unable to loop: %s\n", av_err2str(ret));
 +        movie->loop_count = 1; /* do not try again */
 +        return ret;
 +    }
 +
 +    for (i = 0; i < ctx->nb_outputs; i++) {
 +        avcodec_flush_buffers(movie->st[i].st->codec);
 +        movie->st[i].done = 0;
 +    }
 +    movie->eof = 0;
 +    return 0;
 +}
 +
 +/**
 + * Try to push a frame to the requested output.
 + *
 + * @param ctx     filter context
 + * @param out_id  number of output where a frame is wanted;
 + *                if the frame is read from file, used to set the return value;
 + *                if the codec is being flushed, flush the corresponding stream
 + * @return  1 if a frame was pushed on the requested output,
 + *          0 if another attempt is possible,
 + *          <0 AVERROR code
 + */
 +static int movie_push_frame(AVFilterContext *ctx, unsigned out_id)
 +{
 +    MovieContext *movie = ctx->priv;
 +    AVPacket *pkt = &movie->pkt;
 +    MovieStream *st;
 +    int ret, got_frame = 0, pkt_out_id;
 +    AVFilterLink *outlink;
 +    AVFilterBufferRef *buf;
 +
 +    if (!pkt->size) {
 +        if (movie->eof) {
 +            if (movie->st[out_id].done) {
 +                if (movie->loop_count != 1) {
 +                    ret = rewind_file(ctx);
 +                    if (ret < 0)
 +                        return ret;
 +                    movie->loop_count -= movie->loop_count > 1;
 +                    av_log(ctx, AV_LOG_VERBOSE, "Stream finished, looping.\n");
 +                    return 0; /* retry */
 +                }
 +                return AVERROR_EOF;
 +            }
 +            pkt->stream_index = movie->st[out_id].st->index;
 +            /* packet is already ready for flushing */
 +        } else {
 +            ret = av_read_frame(movie->format_ctx, &movie->pkt0);
 +            if (ret < 0) {
 +                av_init_packet(&movie->pkt0); /* ready for flushing */
 +                *pkt = movie->pkt0;
 +                if (ret == AVERROR_EOF) {
 +                    movie->eof = 1;
 +                    return 0; /* start flushing */
 +                }
 +                return ret;
 +            }
 +            *pkt = movie->pkt0;
 +        }
 +    }
 +
 +    pkt_out_id = pkt->stream_index > movie->max_stream_index ? -1 :
 +                 movie->out_index[pkt->stream_index];
 +    if (pkt_out_id < 0) {
 +        av_free_packet(&movie->pkt0);
 +        pkt->size = 0; /* ready for next run */
 +        pkt->data = NULL;
 +        return 0;
 +    }
 +    st = &movie->st[pkt_out_id];
 +    outlink = ctx->outputs[pkt_out_id];
 +
 +    switch (st->st->codec->codec_type) {
 +    case AVMEDIA_TYPE_VIDEO:
 +        ret = avcodec_decode_video2(st->st->codec, movie->frame, &got_frame, pkt);
 +        break;
 +    case AVMEDIA_TYPE_AUDIO:
 +        ret = avcodec_decode_audio4(st->st->codec, movie->frame, &got_frame, pkt);
 +        break;
 +    default:
 +        ret = AVERROR(ENOSYS);
 +        break;
 +    }
 +    if (ret < 0) {
 +        av_log(ctx, AV_LOG_WARNING, "Decode error: %s\n", av_err2str(ret));
 +        return 0;
 +    }
 +    if (!ret)
 +        ret = pkt->size;
 +
 +    pkt->data += ret;
 +    pkt->size -= ret;
 +    if (pkt->size <= 0) {
 +        av_free_packet(&movie->pkt0);
 +        pkt->size = 0; /* ready for next run */
 +        pkt->data = NULL;
 +    }
 +    if (!got_frame) {
 +        if (!ret)
 +            st->done = 1;
 +        return 0;
 +    }
 +
 +    buf = frame_to_buf(st->st->codec->codec_type, movie->frame, outlink);
 +    if (!buf)
 +        return AVERROR(ENOMEM);
 +    av_dlog(ctx, "movie_push_frame(): file:'%s' %s\n", movie->file_name,
 +            describe_bufref(buf, outlink));
 +    switch (st->st->codec->codec_type) {
 +    case AVMEDIA_TYPE_VIDEO:
 +        if (!movie->frame->sample_aspect_ratio.num)
 +            buf->video->sample_aspect_ratio = st->st->sample_aspect_ratio;
 +        ff_start_frame(outlink, buf);
 +        ff_draw_slice(outlink, 0, outlink->h, 1);
 +        ff_end_frame(outlink);
 +        break;
 +    case AVMEDIA_TYPE_AUDIO:
 +        ff_filter_samples(outlink, buf);
 +        break;
 +    }
 +
 +    return pkt_out_id == out_id;
 +}
 +
 +static int movie_request_frame(AVFilterLink *outlink)
 +{
 +    AVFilterContext *ctx = outlink->src;
 +    unsigned out_id = FF_OUTLINK_IDX(outlink);
 +    int ret;
 +
 +    while (1) {
 +        ret = movie_push_frame(ctx, out_id);
 +        if (ret)
 +            return FFMIN(ret, 0);
 +    }
 +}
 +
 +#if CONFIG_MOVIE_FILTER
 +
 +AVFILTER_DEFINE_CLASS(movie);
 +
 +static av_cold int movie_init(AVFilterContext *ctx, const char *args)
 +{
 +    return movie_common_init(ctx, args, &movie_class);
 +}
 +
 +AVFilter avfilter_avsrc_movie = {
 +    .name          = "movie",
 +    .description   = NULL_IF_CONFIG_SMALL("Read from a movie source."),
 +    .priv_size     = sizeof(MovieContext),
 +    .init          = movie_init,
 +    .uninit        = movie_uninit,
 +    .query_formats = movie_query_formats,
 +
++    .inputs    = NULL,
 +    .outputs   = (const AVFilterPad[]) {{ .name = NULL }},
 +    .priv_class = &movie_class,
 +};
 +
 +#endif  /* CONFIG_MOVIE_FILTER */
 +
 +#if CONFIG_AMOVIE_FILTER
 +
 +#define amovie_options movie_options
 +AVFILTER_DEFINE_CLASS(amovie);
 +
 +static av_cold int amovie_init(AVFilterContext *ctx, const char *args)
 +{
 +    return movie_common_init(ctx, args, &amovie_class);
 +}
 +
 +AVFilter avfilter_avsrc_amovie = {
 +    .name          = "amovie",
 +    .description   = NULL_IF_CONFIG_SMALL("Read audio from a movie source."),
 +    .priv_size     = sizeof(MovieContext),
 +    .init          = amovie_init,
 +    .uninit        = movie_uninit,
 +    .query_formats = movie_query_formats,
 +
 +    .inputs    = (const AVFilterPad[]) {{ .name = NULL }},
 +    .outputs   = (const AVFilterPad[]) {{ .name = NULL }},
 +    .priv_class = &amovie_class,
 +};
 +
 +#endif /* CONFIG_AMOVIE_FILTER */
Simple merge
Simple merge
@@@ -525,15 -360,14 +525,15 @@@ static int test_query_formats(AVFilterC
  }
  
  AVFilter avfilter_vsrc_testsrc = {
 -    .name          = "testsrc",
 -    .description   = NULL_IF_CONFIG_SMALL("Generate test pattern."),
 -    .priv_size     = sizeof(TestSourceContext),
 -    .init          = test_init,
 +    .name      = "testsrc",
 +    .description = NULL_IF_CONFIG_SMALL("Generate test pattern."),
 +    .priv_size = sizeof(TestSourceContext),
 +    .init      = test_init,
 +    .uninit    = uninit,
  
 -    .query_formats = test_query_formats,
 +    .query_formats   = test_query_formats,
  
-     .inputs    = (const AVFilterPad[]) {{ .name = NULL}},
+     .inputs    = NULL,
  
      .outputs   = (const AVFilterPad[]) {{ .name = "default",
                                            .type = AVMEDIA_TYPE_VIDEO,
@@@ -639,15 -487,14 +639,15 @@@ static int rgbtest_config_props(AVFilte
  }
  
  AVFilter avfilter_vsrc_rgbtestsrc = {
 -    .name          = "rgbtestsrc",
 -    .description   = NULL_IF_CONFIG_SMALL("Generate RGB test pattern."),
 -    .priv_size     = sizeof(TestSourceContext),
 -    .init          = rgbtest_init,
 +    .name      = "rgbtestsrc",
 +    .description = NULL_IF_CONFIG_SMALL("Generate RGB test pattern."),
 +    .priv_size = sizeof(TestSourceContext),
 +    .init      = rgbtest_init,
 +    .uninit    = uninit,
  
 -    .query_formats = rgbtest_query_formats,
 +    .query_formats   = rgbtest_query_formats,
  
-     .inputs    = (const AVFilterPad[]) {{ .name = NULL}},
+     .inputs    = NULL,
  
      .outputs   = (const AVFilterPad[]) {{ .name = "default",
                                            .type = AVMEDIA_TYPE_VIDEO,