Example #1
0
static int print_link_prop(AVBPrint *buf, AVFilterLink *link)
{
    char *format;
    char layout[64];

    if (!buf)
        buf = &(AVBPrint){ 0 }; /* dummy buffer */
    switch (link->type) {
        case AVMEDIA_TYPE_VIDEO:
            format = av_x_if_null(av_get_pix_fmt_name(link->format), "?");
            av_bprintf(buf, "[%dx%d %d:%d %s]", link->w, link->h,
                    link->sample_aspect_ratio.num,
                    link->sample_aspect_ratio.den,
                    format);
            break;

        case AVMEDIA_TYPE_AUDIO:
            av_get_channel_layout_string(layout, sizeof(layout),
                                         -1, link->channel_layout);
            format = av_x_if_null(av_get_sample_fmt_name(link->format), "?");
            av_bprintf(buf, "[%dHz %s:%s:%s]",
                    (int)link->sample_rate, format, layout,
                    link->planar ? "planar" : "packed");
            break;

        default:
            av_bprintf(buf, "?");
            break;
    }
    return buf->len;
}
Example #2
0
int avfilter_link(AVFilterContext *src, unsigned srcpad,
                  AVFilterContext *dst, unsigned dstpad)
{
    AVFilterLink *link;

    if (src->nb_outputs <= srcpad || dst->nb_inputs <= dstpad ||
        src->outputs[srcpad]      || dst->inputs[dstpad])
        return AVERROR(EINVAL);

    if (src->output_pads[srcpad].type != dst->input_pads[dstpad].type) {
        av_log(src, AV_LOG_ERROR,
               "Media type mismatch between the '%s' filter output pad %d (%s) and the '%s' filter input pad %d (%s)\n",
               src->name, srcpad, (char *)av_x_if_null(av_get_media_type_string(src->output_pads[srcpad].type), "?"),
               dst->name, dstpad, (char *)av_x_if_null(av_get_media_type_string(dst-> input_pads[dstpad].type), "?"));
        return AVERROR(EINVAL);
    }

    link = av_mallocz(sizeof(*link));
    if (!link)
        return AVERROR(ENOMEM);

    src->outputs[srcpad] = dst->inputs[dstpad] = link;

    link->src     = src;
    link->dst     = dst;
    link->srcpad  = &src->output_pads[srcpad];
    link->dstpad  = &dst->input_pads[dstpad];
    link->type    = src->output_pads[srcpad].type;
    av_assert0(AV_PIX_FMT_NONE == -1 && AV_SAMPLE_FMT_NONE == -1);
    link->format  = -1;

    return 0;
}
Example #3
0
static int end_frame(AVFilterLink *inlink)
{
    AVFilterContext *ctx = inlink->dst;
    BufferSinkContext *buf = inlink->dst->priv;

    av_assert1(inlink->cur_buf);
    if (av_fifo_space(buf->fifo) < sizeof(AVFilterBufferRef *)) {
        /* realloc fifo size */
        if (av_fifo_realloc2(buf->fifo, av_fifo_size(buf->fifo) * 2) < 0) {
            av_log(ctx, AV_LOG_ERROR,
                   "Cannot buffer more frames. Consume some available frames "
                   "before adding new ones.\n");
            return AVERROR(ENOMEM);
        }
    }

    /* cache frame */
    av_fifo_generic_write(buf->fifo,
                          &inlink->cur_buf, sizeof(AVFilterBufferRef *), NULL);
    inlink->cur_buf = NULL;
    if (buf->warning_limit &&
        av_fifo_size(buf->fifo) / sizeof(AVFilterBufferRef *) >= buf->warning_limit) {
        av_log(ctx, AV_LOG_WARNING,
               "%d buffers queued in %s, something may be wrong.\n",
               buf->warning_limit,
               (char *)av_x_if_null(ctx->name, ctx->filter->name));
        buf->warning_limit *= 10;
    }
    return 0;
}
Example #4
0
static av_cold int data_open(URLContext *h, const char *uri, int flags)
{
    DataContext *dc = h->priv_data;
    const char *data, *opt, *next;
    char *ddata;
    int ret, base64 = 0;
    size_t in_size;

    /* data:content/type[;base64],payload */

    av_strstart(uri, "data:", &uri);
    data = strchr(uri, ',');
    if (!data) {
        av_log(h, AV_LOG_ERROR, "No ',' delimiter in URI\n");
        return AVERROR(EINVAL);
    }
    opt = uri;
    while (opt < data) {
        next = av_x_if_null(memchr(opt, ';', data - opt), data);
        if (opt == uri) {
            if (!memchr(opt, '/', next - opt)) { /* basic validity check */
                av_log(h, AV_LOG_ERROR, "Invalid content-type '%.*s'\n",
                       (int)(next - opt), opt);
                return AVERROR(EINVAL);
            }
            av_log(h, AV_LOG_VERBOSE, "Content-type: %.*s\n",
                   (int)(next - opt), opt);
        } else {
            if (!av_strncasecmp(opt, "base64", next - opt)) {
                base64 = 1;
            } else {
                av_log(h, AV_LOG_VERBOSE, "Ignoring option '%.*s'\n",
                       (int)(next - opt), opt);
            }
        }
        opt = next + 1;
    }

    data++;
    in_size = strlen(data);
    if (base64) {
        size_t out_size = 3 * (in_size / 4) + 1;

        if (out_size > INT_MAX || !(ddata = av_malloc(out_size)))
            return AVERROR(ENOMEM);
        if ((ret = av_base64_decode(ddata, data, out_size)) < 0) {
            av_free(ddata);
            av_log(h, AV_LOG_ERROR, "Invalid base64 in URI\n");
            return ret;
        }
        dc->data = dc->tofree = ddata;
        dc->size = ret;
    } else {
        dc->data = data;
        dc->size = in_size;
    }
    return 0;
}
Example #5
0
static int filter_frame(AVFilterLink *link, AVFrame *frame)
{
    AVFilterContext *ctx = link->dst;
    BufferSinkContext *buf = link->dst->priv;
    int ret;

    if ((ret = add_buffer_ref(ctx, frame)) < 0)
        return ret;
    if (buf->warning_limit &&
        av_fifo_size(buf->fifo) / sizeof(AVFilterBufferRef *) >= buf->warning_limit) {
        av_log(ctx, AV_LOG_WARNING,
               "%d buffers queued in %s, something may be wrong.\n",
               buf->warning_limit,
               (char *)av_x_if_null(ctx->name, ctx->filter->name));
        buf->warning_limit *= 10;
    }
    return 0;
}
Example #6
0
static av_cold int init_video(AVFilterContext *ctx)
{
    BufferSourceContext *c = ctx->priv;

    if (c->pix_fmt == AV_PIX_FMT_NONE || !c->w || !c->h || av_q2d(c->time_base) <= 0) {
        av_log(ctx, AV_LOG_ERROR, "Invalid parameters provided.\n");
        return AVERROR(EINVAL);
    }

    if (!(c->fifo = av_fifo_alloc(sizeof(AVFrame*))))
        return AVERROR(ENOMEM);

    av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d pixfmt:%s tb:%d/%d fr:%d/%d sar:%d/%d sws_param:%s\n",
           c->w, c->h, av_get_pix_fmt_name(c->pix_fmt),
           c->time_base.num, c->time_base.den, c->frame_rate.num, c->frame_rate.den,
           c->pixel_aspect.num, c->pixel_aspect.den, (char *)av_x_if_null(c->sws_param, ""));
    c->warning_limit = 100;
    return 0;
}
Example #7
0
static int avi_write_header(AVFormatContext *s)
{
    AVIContext *avi = s->priv_data;
    AVIOContext *pb = s->pb;
    int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale;
    AVCodecContext *stream, *video_enc;
    int64_t list1, list2, strh, strf;
    AVDictionaryEntry *t = NULL;

    if (s->nb_streams > AVI_MAX_STREAM_COUNT) {
        av_log(s, AV_LOG_ERROR, "AVI does not support >%d streams\n",
               AVI_MAX_STREAM_COUNT);
        return AVERROR(EINVAL);
    }

    for(n=0;n<s->nb_streams;n++) {
        s->streams[n]->priv_data= av_mallocz(sizeof(AVIStream));
        if(!s->streams[n]->priv_data)
            return AVERROR(ENOMEM);
    }

    /* header list */
    avi->riff_id = 0;
    list1 = avi_start_new_riff(s, pb, "AVI ", "hdrl");

    /* avi header */
    ffio_wfourcc(pb, "avih");
    avio_wl32(pb, 14 * 4);
    bitrate = 0;

    video_enc = NULL;
    for(n=0;n<s->nb_streams;n++) {
        stream = s->streams[n]->codec;
        bitrate += stream->bit_rate;
        if (stream->codec_type == AVMEDIA_TYPE_VIDEO)
            video_enc = stream;
    }

    nb_frames = 0;

    if(video_enc){
        avio_wl32(pb, (uint32_t)(INT64_C(1000000) * video_enc->time_base.num / video_enc->time_base.den));
    } else {
        avio_wl32(pb, 0);
    }
    avio_wl32(pb, bitrate / 8); /* XXX: not quite exact */
    avio_wl32(pb, 0); /* padding */
    if (!pb->seekable)
        avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_ISINTERLEAVED); /* flags */
    else
        avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */
    avi->frames_hdr_all = avio_tell(pb); /* remember this offset to fill later */
    avio_wl32(pb, nb_frames); /* nb frames, filled later */
    avio_wl32(pb, 0); /* initial frame */
    avio_wl32(pb, s->nb_streams); /* nb streams */
    avio_wl32(pb, 1024 * 1024); /* suggested buffer size */
    if(video_enc){
        avio_wl32(pb, video_enc->width);
        avio_wl32(pb, video_enc->height);
    } else {
        avio_wl32(pb, 0);
        avio_wl32(pb, 0);
    }
    avio_wl32(pb, 0); /* reserved */
    avio_wl32(pb, 0); /* reserved */
    avio_wl32(pb, 0); /* reserved */
    avio_wl32(pb, 0); /* reserved */

    /* stream list */
    for(i=0;i<n;i++) {
        AVIStream *avist= s->streams[i]->priv_data;
        list2 = ff_start_tag(pb, "LIST");
        ffio_wfourcc(pb, "strl");

        stream = s->streams[i]->codec;

        /* stream generic header */
        strh = ff_start_tag(pb, "strh");
        switch(stream->codec_type) {
        case AVMEDIA_TYPE_SUBTITLE:
            // XSUB subtitles behave like video tracks, other subtitles
            // are not (yet) supported.
            if (stream->codec_id != AV_CODEC_ID_XSUB) {
                av_log(s, AV_LOG_ERROR, "Subtitle streams other than DivX XSUB are not supported by the AVI muxer.\n");
                return AVERROR_PATCHWELCOME;
            }
        case AVMEDIA_TYPE_VIDEO: ffio_wfourcc(pb, "vids"); break;
        case AVMEDIA_TYPE_AUDIO: ffio_wfourcc(pb, "auds"); break;
//      case AVMEDIA_TYPE_TEXT : ffio_wfourcc(pb, "txts"); break;
        case AVMEDIA_TYPE_DATA : ffio_wfourcc(pb, "dats"); break;
        }
        if(stream->codec_type == AVMEDIA_TYPE_VIDEO ||
           stream->codec_id == AV_CODEC_ID_XSUB)
            avio_wl32(pb, stream->codec_tag);
        else
            avio_wl32(pb, 1);
        avio_wl32(pb, 0); /* flags */
        avio_wl16(pb, 0); /* priority */
        avio_wl16(pb, 0); /* language */
        avio_wl32(pb, 0); /* initial frame */

        ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale);

        if (   stream->codec_type == AVMEDIA_TYPE_VIDEO
            && stream->codec_id != AV_CODEC_ID_XSUB
            && au_byterate > 1000LL*au_scale) {
            au_byterate = 600;
            au_scale    = 1;
        }
        avpriv_set_pts_info(s->streams[i], 64, au_scale, au_byterate);
        if(stream->codec_id == AV_CODEC_ID_XSUB)
            au_scale = au_byterate = 0;

        avio_wl32(pb, au_scale); /* scale */
        avio_wl32(pb, au_byterate); /* rate */

        avio_wl32(pb, 0); /* start */
        avist->frames_hdr_strm = avio_tell(pb); /* remember this offset to fill later */
        if (!pb->seekable)
            avio_wl32(pb, AVI_MAX_RIFF_SIZE); /* FIXME: this may be broken, but who cares */
        else
            avio_wl32(pb, 0); /* length, XXX: filled later */

        /* suggested buffer size */ //FIXME set at the end to largest chunk
        if(stream->codec_type == AVMEDIA_TYPE_VIDEO)
            avio_wl32(pb, 1024 * 1024);
        else if(stream->codec_type == AVMEDIA_TYPE_AUDIO)
            avio_wl32(pb, 12 * 1024);
        else
            avio_wl32(pb, 0);
        avio_wl32(pb, -1); /* quality */
        avio_wl32(pb, au_ssize); /* sample size */
        avio_wl32(pb, 0);
        avio_wl16(pb, stream->width);
        avio_wl16(pb, stream->height);
        ff_end_tag(pb, strh);

      if(stream->codec_type != AVMEDIA_TYPE_DATA){
          int ret;

        strf = ff_start_tag(pb, "strf");
        switch(stream->codec_type) {
        case AVMEDIA_TYPE_SUBTITLE:
            // XSUB subtitles behave like video tracks, other subtitles
            // are not (yet) supported.
            if (stream->codec_id != AV_CODEC_ID_XSUB) break;
        case AVMEDIA_TYPE_VIDEO:
            ff_put_bmp_header(pb, stream, ff_codec_bmp_tags, 0, 0);
            break;
        case AVMEDIA_TYPE_AUDIO:
            if ((ret = ff_put_wav_header(pb, stream)) < 0) {
                return ret;
            }
            break;
        default:
            av_log(s, AV_LOG_ERROR,
                   "Invalid or not supported codec type '%s' found in the input\n",
                   (char *)av_x_if_null(av_get_media_type_string(stream->codec_type), "?"));
            return AVERROR(EINVAL);
        }
        ff_end_tag(pb, strf);
        if ((t = av_dict_get(s->streams[i]->metadata, "title", NULL, 0))) {
            ff_riff_write_info_tag(s->pb, "strn", t->value);
            t = NULL;
        }
        if(stream->codec_id == AV_CODEC_ID_XSUB
           && (t = av_dict_get(s->streams[i]->metadata, "language", NULL, 0))) {
            const char* langstr = av_convert_lang_to(t->value, AV_LANG_ISO639_1);
            t = NULL;
            if (langstr) {
                char* str = av_asprintf("Subtitle - %s-xx;02", langstr);
                ff_riff_write_info_tag(s->pb, "strn", str);
                av_free(str);
            }
        }
      }

        if (pb->seekable) {
            unsigned char tag[5];
            int j;

            /* Starting to lay out AVI OpenDML master index.
             * We want to make it JUNK entry for now, since we'd
             * like to get away without making AVI an OpenDML one
             * for compatibility reasons.
             */
            avist->indexes.entry = avist->indexes.ents_allocated = 0;
            avist->indexes.indx_start = ff_start_tag(pb, "JUNK");
            avio_wl16(pb, 4);        /* wLongsPerEntry */
            avio_w8(pb, 0);          /* bIndexSubType (0 == frame index) */
            avio_w8(pb, 0);          /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */
            avio_wl32(pb, 0);        /* nEntriesInUse (will fill out later on) */
            ffio_wfourcc(pb, avi_stream2fourcc(tag, i, stream->codec_type));
                                    /* dwChunkId */
            avio_wl64(pb, 0);        /* dwReserved[3]
            avio_wl32(pb, 0);           Must be 0.    */
            for (j=0; j < AVI_MASTER_INDEX_SIZE * 2; j++)
                 avio_wl64(pb, 0);
            ff_end_tag(pb, avist->indexes.indx_start);
        }

        if(   stream->codec_type == AVMEDIA_TYPE_VIDEO
           && s->streams[i]->sample_aspect_ratio.num>0
           && s->streams[i]->sample_aspect_ratio.den>0){
            int vprp= ff_start_tag(pb, "vprp");
            AVRational dar = av_mul_q(s->streams[i]->sample_aspect_ratio,
                                      (AVRational){stream->width, stream->height});
            int num, den;
            av_reduce(&num, &den, dar.num, dar.den, 0xFFFF);

            avio_wl32(pb, 0); //video format  = unknown
            avio_wl32(pb, 0); //video standard= unknown
            avio_wl32(pb, lrintf(1.0/av_q2d(stream->time_base)));
            avio_wl32(pb, stream->width );
            avio_wl32(pb, stream->height);
            avio_wl16(pb, den);
            avio_wl16(pb, num);
            avio_wl32(pb, stream->width );
            avio_wl32(pb, stream->height);
            avio_wl32(pb, 1); //progressive FIXME

            avio_wl32(pb, stream->height);
            avio_wl32(pb, stream->width );
            avio_wl32(pb, stream->height);
            avio_wl32(pb, stream->width );
            avio_wl32(pb, 0);
            avio_wl32(pb, 0);

            avio_wl32(pb, 0);
            avio_wl32(pb, 0);
            ff_end_tag(pb, vprp);
        }

        ff_end_tag(pb, list2);
    }

    if (pb->seekable) {
        /* AVI could become an OpenDML one, if it grows beyond 2Gb range */
        avi->odml_list = ff_start_tag(pb, "JUNK");
        ffio_wfourcc(pb, "odml");
        ffio_wfourcc(pb, "dmlh");
        avio_wl32(pb, 248);
        for (i = 0; i < 248; i+= 4)
             avio_wl32(pb, 0);
        ff_end_tag(pb, avi->odml_list);
    }

    ff_end_tag(pb, list1);

    ff_riff_write_info(s);

    /* some padding for easier tag editing */
    list2 = ff_start_tag(pb, "JUNK");
    for (i = 0; i < 1016; i += 4)
        avio_wl32(pb, 0);
    ff_end_tag(pb, list2);

    avi->movi_list = ff_start_tag(pb, "LIST");
    ffio_wfourcc(pb, "movi");

    avio_flush(pb);

    return 0;
}
Example #8
0
int VideoDecoder::video_thread(void *arg)
{
    VideoState *is = (VideoState *) arg;
    AVStreamsParser* ps = is->getAVStreamsParser();
    AVFrame *frame = av_frame_alloc();
    double pts;
    double duration;
    int ret;
    AVRational tb = ps->video_st->time_base;
    AVRational frame_rate = av_guess_frame_rate(ps->ic, ps->video_st, NULL);

#if CONFIG_AVFILTER
    AVFilterGraph *graph = avfilter_graph_alloc();
    AVFilterContext *filt_out = NULL, *filt_in = NULL;
    int last_w = 0;
    int last_h = 0;
    enum AVPixelFormat last_format = (AVPixelFormat) (-2);
    int last_serial = -1;
    int last_vfilter_idx = 0;
    if (!graph) {
        av_frame_free(&frame);
        return AVERROR(ENOMEM);
    }

#endif

    if (!frame) {
#if CONFIG_AVFILTER
        avfilter_graph_free(&graph);
#endif
        return AVERROR(ENOMEM);
    }

    for (;;) {
        ret = is->viddec().get_video_frame(is, frame);
        if (ret < 0)
            goto the_end;
        if (!ret)
            continue;

#if CONFIG_AVFILTER
        if (   last_w != frame->width
            || last_h != frame->height
            || last_format != frame->format
            || last_serial != is->viddec().pkt_serial
            || last_vfilter_idx != is->vfilter_idx) {
            av_log(NULL, AV_LOG_DEBUG,
                   "Video frame changed from size:%dx%d format:%s serial:%d to size:%dx%d format:%s serial:%d\n",
                   last_w, last_h,
                   (const char *)av_x_if_null(av_get_pix_fmt_name(last_format), "none"), last_serial,
                   frame->width, frame->height,
                   (const char *)av_x_if_null(av_get_pix_fmt_name((AVPixelFormat)frame->format), "none"), is->viddec().pkt_serial);
            avfilter_graph_free(&graph);
            graph = avfilter_graph_alloc();
            if ((ret = configure_video_filters(graph, is,gOptions.vfilters_list ? gOptions.vfilters_list[is->vfilter_idx] : NULL, frame)) < 0) {
                SDL_Event event;
                event.type = FF_QUIT_EVENT;
                event.user.data1 = is;
                SDL_PushEvent(&event);
                goto the_end;
            }
            filt_in  = is->in_video_filter;
            filt_out = is->out_video_filter;
            last_w = frame->width;
            last_h = frame->height;
            last_format = (AVPixelFormat) frame->format;
            last_serial = is->viddec().pkt_serial;
            last_vfilter_idx = is->vfilter_idx;
            frame_rate = filt_out->inputs[0]->frame_rate;
        }

        ret = av_buffersrc_add_frame(filt_in, frame);
        if (ret < 0)
            goto the_end;

        while (ret >= 0) {
            is->frame_last_returned_time = av_gettime_relative() / 1000000.0;

            ret = av_buffersink_get_frame_flags(filt_out, frame, 0);
            if (ret < 0) {
                if (ret == AVERROR_EOF)
                    is->viddec().finished = is->viddec().pkt_serial;
                ret = 0;
                break;
            }

            is->frame_last_filter_delay = av_gettime_relative() / 1000000.0 - is->frame_last_returned_time;
            if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)
                is->frame_last_filter_delay = 0;
            tb = filt_out->inputs[0]->time_base;
#endif
            duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0);
            pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);
            ret = queue_picture(is, frame, pts, duration, av_frame_get_pkt_pos(frame), is->viddec().pkt_serial);
            av_frame_unref(frame);
#if CONFIG_AVFILTER
        }
#endif

        if (ret < 0)
            goto the_end;
    }
 the_end:
#if CONFIG_AVFILTER
    avfilter_graph_free(&graph);
#endif
    av_frame_free(&frame);
    return 0;
}
Example #9
0
static av_cold int init(AVFilterContext *ctx)
{
    LADSPAContext *s = ctx->priv;
    LADSPA_Descriptor_Function descriptor_fn;
    const LADSPA_Descriptor *desc;
    LADSPA_PortDescriptor pd;
    AVFilterPad pad = { NULL };
    char *p, *arg, *saveptr = NULL;
    unsigned long nb_ports;
    int i;

    if (!s->dl_name) {
        av_log(ctx, AV_LOG_ERROR, "No plugin name provided\n");
        return AVERROR(EINVAL);
    }

    if (s->dl_name[0] == '/' || s->dl_name[0] == '.') {
        // argument is a path
        s->dl_handle = dlopen(s->dl_name, RTLD_LOCAL|RTLD_NOW);
    } else {
        // argument is a shared object name
        char *paths = av_strdup(getenv("LADSPA_PATH"));
        const char *separator = ":";

        if (paths) {
            p = paths;
            while ((arg = av_strtok(p, separator, &saveptr)) && !s->dl_handle) {
                s->dl_handle = try_load(arg, s->dl_name);
                p = NULL;
            }
        }

        av_free(paths);
        if (!s->dl_handle && (paths = av_asprintf("%s/.ladspa/lib", getenv("HOME")))) {
            s->dl_handle = try_load(paths, s->dl_name);
            av_free(paths);
        }

        if (!s->dl_handle)
            s->dl_handle = try_load("/usr/local/lib/ladspa", s->dl_name);

        if (!s->dl_handle)
            s->dl_handle = try_load("/usr/lib/ladspa", s->dl_name);
    }
    if (!s->dl_handle) {
        av_log(ctx, AV_LOG_ERROR, "Failed to load '%s'\n", s->dl_name);
        return AVERROR(EINVAL);
    }

    descriptor_fn = dlsym(s->dl_handle, "ladspa_descriptor");
    if (!descriptor_fn) {
        av_log(ctx, AV_LOG_ERROR, "Could not find ladspa_descriptor: %s\n", dlerror());
        return AVERROR(EINVAL);
    }

    // Find the requested plugin, or list plugins
    if (!s->plugin) {
        av_log(ctx, AV_LOG_INFO, "The '%s' library contains the following plugins:\n", s->dl_name);
        av_log(ctx, AV_LOG_INFO, "I = Input Channels\n");
        av_log(ctx, AV_LOG_INFO, "O = Output Channels\n");
        av_log(ctx, AV_LOG_INFO, "I:O %-25s %s\n", "Plugin", "Description");
        av_log(ctx, AV_LOG_INFO, "\n");
        for (i = 0; desc = descriptor_fn(i); i++) {
            unsigned long inputs = 0, outputs = 0;

            count_ports(desc, &inputs, &outputs);
            av_log(ctx, AV_LOG_INFO, "%lu:%lu %-25s %s\n", inputs, outputs, desc->Label,
                                     av_x_if_null(desc->Name, "?"));
            av_log(ctx, AV_LOG_VERBOSE, "Maker: %s\n", av_x_if_null(desc->Maker, "?"));
            av_log(ctx, AV_LOG_VERBOSE, "Copyright: %s\n", av_x_if_null(desc->Copyright, "?"));
        }
        return AVERROR_EXIT;
    } else {
        for (i = 0;; i++) {
            desc = descriptor_fn(i);
            if (!desc) {
                av_log(ctx, AV_LOG_ERROR, "Could not find plugin: %s\n", s->plugin);
                return AVERROR(EINVAL);
            }

            if (desc->Label && !strcmp(desc->Label, s->plugin))
                break;
        }
    }

    s->desc  = desc;
    nb_ports = desc->PortCount;

    s->ipmap = av_calloc(nb_ports, sizeof(*s->ipmap));
    s->opmap = av_calloc(nb_ports, sizeof(*s->opmap));
    s->icmap = av_calloc(nb_ports, sizeof(*s->icmap));
    s->ocmap = av_calloc(nb_ports, sizeof(*s->ocmap));
    s->ictlv = av_calloc(nb_ports, sizeof(*s->ictlv));
    s->octlv = av_calloc(nb_ports, sizeof(*s->octlv));
    s->ctl_needs_value = av_calloc(nb_ports, sizeof(*s->ctl_needs_value));
    if (!s->ipmap || !s->opmap || !s->icmap ||
        !s->ocmap || !s->ictlv || !s->octlv || !s->ctl_needs_value)
        return AVERROR(ENOMEM);

    for (i = 0; i < nb_ports; i++) {
        pd = desc->PortDescriptors[i];

        if (LADSPA_IS_PORT_AUDIO(pd)) {
            if (LADSPA_IS_PORT_INPUT(pd)) {
                s->ipmap[s->nb_inputs] = i;
                s->nb_inputs++;
            } else if (LADSPA_IS_PORT_OUTPUT(pd)) {
                s->opmap[s->nb_outputs] = i;
                s->nb_outputs++;
            }
        } else if (LADSPA_IS_PORT_CONTROL(pd)) {
            if (LADSPA_IS_PORT_INPUT(pd)) {
                s->icmap[s->nb_inputcontrols] = i;

                if (LADSPA_IS_HINT_HAS_DEFAULT(desc->PortRangeHints[i].HintDescriptor))
                    set_default_ctl_value(s, s->nb_inputcontrols, s->icmap, s->ictlv);
                else
                    s->ctl_needs_value[s->nb_inputcontrols] = 1;

                s->nb_inputcontrols++;
            } else if (LADSPA_IS_PORT_OUTPUT(pd)) {
                s->ocmap[s->nb_outputcontrols] = i;
                s->nb_outputcontrols++;
            }
        }
    }

    // List Control Ports if "help" is specified
    if (s->options && !strcmp(s->options, "help")) {
        if (!s->nb_inputcontrols) {
            av_log(ctx, AV_LOG_INFO,
                   "The '%s' plugin does not have any input controls.\n",
                   desc->Label);
        } else {
            av_log(ctx, AV_LOG_INFO,
                   "The '%s' plugin has the following input controls:\n",
                   desc->Label);
            for (i = 0; i < s->nb_inputcontrols; i++)
                print_ctl_info(ctx, AV_LOG_INFO, s, i, s->icmap, s->ictlv, 0);
        }
        return AVERROR_EXIT;
    }

    // Parse control parameters
    p = s->options;
    while (s->options) {
        LADSPA_Data val;
        int ret;

        if (!(arg = av_strtok(p, "|", &saveptr)))
            break;
        p = NULL;

        if (sscanf(arg, "c%d=%f", &i, &val) != 2) {
            av_log(ctx, AV_LOG_ERROR, "Invalid syntax.\n");
            return AVERROR(EINVAL);
        }

        if ((ret = set_control(ctx, i, val)) < 0)
            return ret;
        s->ctl_needs_value[i] = 0;
    }

    // Check if any controls are not set
    for (i = 0; i < s->nb_inputcontrols; i++) {
        if (s->ctl_needs_value[i]) {
            av_log(ctx, AV_LOG_ERROR, "Control c%d must be set.\n", i);
            print_ctl_info(ctx, AV_LOG_ERROR, s, i, s->icmap, s->ictlv, 0);
            return AVERROR(EINVAL);
        }
    }

    pad.type = AVMEDIA_TYPE_AUDIO;

    if (s->nb_inputs) {
        pad.name = av_asprintf("in0:%s%lu", desc->Label, s->nb_inputs);
        if (!pad.name)
            return AVERROR(ENOMEM);

        pad.filter_frame = filter_frame;
        pad.config_props = config_input;
        if (ff_insert_inpad(ctx, ctx->nb_inputs, &pad) < 0) {
            av_freep(&pad.name);
            return AVERROR(ENOMEM);
        }
    }

    av_log(ctx, AV_LOG_DEBUG, "ports: %lu\n", nb_ports);
    av_log(ctx, AV_LOG_DEBUG, "inputs: %lu outputs: %lu\n",
                              s->nb_inputs, s->nb_outputs);
    av_log(ctx, AV_LOG_DEBUG, "input controls: %lu output controls: %lu\n",
                              s->nb_inputcontrols, s->nb_outputcontrols);

    return 0;
}
Example #10
0
static int init_filters(const char *filters_descr)
{
    char args[512];
    int ret = 0;
    AVFilter *abuffersrc  = avfilter_get_by_name("abuffer");
    AVFilter *abuffersink = avfilter_get_by_name("abuffersink");
    AVFilterInOut *outputs = avfilter_inout_alloc();
    AVFilterInOut *inputs  = avfilter_inout_alloc();
    static const enum AVSampleFormat out_sample_fmts[] = { AV_SAMPLE_FMT_S16, -1 };
    static const int64_t out_channel_layouts[] = { AV_CH_LAYOUT_MONO, -1 };
    static const int out_sample_rates[] = { 8000, -1 };
    const AVFilterLink *outlink;
    AVRational time_base = fmt_ctx->streams[audio_stream_index]->time_base;

    filter_graph = avfilter_graph_alloc();
    if (!outputs || !inputs || !filter_graph) {
        ret = AVERROR(ENOMEM);
        goto end;
    }

    /* buffer audio source: the decoded frames from the decoder will be inserted here. */
    if (!dec_ctx->channel_layout)
        dec_ctx->channel_layout = av_get_default_channel_layout(dec_ctx->channels);
    snprintf(args, sizeof(args),
            "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64,
             time_base.num, time_base.den, dec_ctx->sample_rate,
             av_get_sample_fmt_name(dec_ctx->sample_fmt), dec_ctx->channel_layout);
    ret = avfilter_graph_create_filter(&buffersrc_ctx, abuffersrc, "in",
                                       args, NULL, filter_graph);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer source\n");
        goto end;
    }

    /* buffer audio sink: to terminate the filter chain. */
    ret = avfilter_graph_create_filter(&buffersink_ctx, abuffersink, "out",
                                       NULL, NULL, filter_graph);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n");
        goto end;
    }

    ret = av_opt_set_int_list(buffersink_ctx, "sample_fmts", out_sample_fmts, -1,
                              AV_OPT_SEARCH_CHILDREN);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n");
        goto end;
    }

    ret = av_opt_set_int_list(buffersink_ctx, "channel_layouts", out_channel_layouts, -1,
                              AV_OPT_SEARCH_CHILDREN);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n");
        goto end;
    }

    ret = av_opt_set_int_list(buffersink_ctx, "sample_rates", out_sample_rates, -1,
                              AV_OPT_SEARCH_CHILDREN);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n");
        goto end;
    }

    /* Endpoints for the filter graph. */
    outputs->name       = av_strdup("in");
    outputs->filter_ctx = buffersrc_ctx;
    outputs->pad_idx    = 0;
    outputs->next       = NULL;

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

    if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr,
                                        &inputs, &outputs, NULL)) < 0)
        goto end;

    if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
        goto end;

    /* Print summary of the sink buffer
     * Note: args buffer is reused to store channel layout string */
    outlink = buffersink_ctx->inputs[0];
    av_get_channel_layout_string(args, sizeof(args), -1, outlink->channel_layout);
    av_log(NULL, AV_LOG_INFO, "Output: srate:%dHz fmt:%s chlayout:%s\n",
           (int)outlink->sample_rate,
           (char *)av_x_if_null(av_get_sample_fmt_name(outlink->format), "?"),
           args);

end:
    avfilter_inout_free(&inputs);
    avfilter_inout_free(&outputs);

    return ret;
}
Example #11
0
static int avi_write_header(AVFormatContext *s)
{
    AVIContext *avi = s->priv_data;
    AVIOContext *pb = s->pb;
    int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale;
    AVCodecContext *video_enc;
    AVStream *video_st = NULL;
    int64_t list1, list2, strh, strf;
    AVDictionaryEntry *t = NULL;
    int padding;

    if (s->nb_streams > AVI_MAX_STREAM_COUNT) {
        av_log(s, AV_LOG_ERROR, "AVI does not support >%d streams\n",
               AVI_MAX_STREAM_COUNT);
        return AVERROR(EINVAL);
    }

    for (n = 0; n < s->nb_streams; n++) {
        s->streams[n]->priv_data = av_mallocz(sizeof(AVIStream));
        if (!s->streams[n]->priv_data)
            return AVERROR(ENOMEM);
    }

    /* header list */
    avi->riff_id = 0;
    list1 = avi_start_new_riff(s, pb, "AVI ", "hdrl");

    /* avi header */
    ffio_wfourcc(pb, "avih");
    avio_wl32(pb, 14 * 4);
    bitrate = 0;

    video_enc = NULL;
    for (n = 0; n < s->nb_streams; n++) {
        AVCodecContext *codec = s->streams[n]->codec;
        bitrate += codec->bit_rate;
        if (codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            video_enc = codec;
            video_st = s->streams[n];
        }
    }

    nb_frames = 0;

    // TODO: should be avg_frame_rate
    if (video_st)
        avio_wl32(pb, (uint32_t) (INT64_C(1000000) * video_st->time_base.num /
                                  video_st->time_base.den));
    else
        avio_wl32(pb, 0);
    avio_wl32(pb, bitrate / 8); /* XXX: not quite exact */
    avio_wl32(pb, 0); /* padding */
    if (!pb->seekable)
        avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_ISINTERLEAVED);  /* flags */
    else
        avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED);  /* flags */
    avi->frames_hdr_all = avio_tell(pb); /* remember this offset to fill later */
    avio_wl32(pb, nb_frames); /* nb frames, filled later */
    avio_wl32(pb, 0); /* initial frame */
    avio_wl32(pb, s->nb_streams); /* nb streams */
    avio_wl32(pb, 1024 * 1024); /* suggested buffer size */
    if (video_enc) {
        avio_wl32(pb, video_enc->width);
        avio_wl32(pb, video_enc->height);
    } else {
        avio_wl32(pb, 0);
        avio_wl32(pb, 0);
    }
    avio_wl32(pb, 0); /* reserved */
    avio_wl32(pb, 0); /* reserved */
    avio_wl32(pb, 0); /* reserved */
    avio_wl32(pb, 0); /* reserved */

    /* stream list */
    for (i = 0; i < n; i++) {
        AVStream *st = s->streams[i];
        AVCodecContext *enc = st->codec;
        AVIStream *avist = st->priv_data;
        list2 = ff_start_tag(pb, "LIST");
        ffio_wfourcc(pb, "strl");

        /* stream generic header */
        strh = ff_start_tag(pb, "strh");
        switch (enc->codec_type) {
        case AVMEDIA_TYPE_SUBTITLE:
            // XSUB subtitles behave like video tracks, other subtitles
            // are not (yet) supported.
            if (enc->codec_id != AV_CODEC_ID_XSUB) {
                av_log(s, AV_LOG_ERROR,
                       "Subtitle streams other than DivX XSUB are not supported by the AVI muxer.\n");
                return AVERROR_PATCHWELCOME;
            }
        case AVMEDIA_TYPE_VIDEO:
            ffio_wfourcc(pb, "vids");
            break;
        case AVMEDIA_TYPE_AUDIO:
            ffio_wfourcc(pb, "auds");
            break;
//      case AVMEDIA_TYPE_TEXT:
//          ffio_wfourcc(pb, "txts");
//          break;
        case AVMEDIA_TYPE_DATA:
            ffio_wfourcc(pb, "dats");
            break;
        }
        if (enc->codec_type == AVMEDIA_TYPE_VIDEO ||
            enc->codec_id == AV_CODEC_ID_XSUB)
            avio_wl32(pb, enc->codec_tag);
        else
            avio_wl32(pb, 1);
        avio_wl32(pb, 0); /* flags */
        avio_wl16(pb, 0); /* priority */
        avio_wl16(pb, 0); /* language */
        avio_wl32(pb, 0); /* initial frame */

        ff_parse_specific_params(st, &au_byterate, &au_ssize, &au_scale);

        if (   enc->codec_type == AVMEDIA_TYPE_VIDEO
            && enc->codec_id != AV_CODEC_ID_XSUB
            && au_byterate > 1000LL*au_scale) {
            au_byterate = 600;
            au_scale    = 1;
        }
        avpriv_set_pts_info(st, 64, au_scale, au_byterate);
        if (enc->codec_id == AV_CODEC_ID_XSUB)
            au_scale = au_byterate = 0;

        avio_wl32(pb, au_scale); /* scale */
        avio_wl32(pb, au_byterate); /* rate */

        avio_wl32(pb, 0); /* start */
        /* remember this offset to fill later */
        avist->frames_hdr_strm = avio_tell(pb);
        if (!pb->seekable)
            /* FIXME: this may be broken, but who cares */
            avio_wl32(pb, AVI_MAX_RIFF_SIZE);
        else
            avio_wl32(pb, 0);  /* length, XXX: filled later */

        /* suggested buffer size, is set to largest chunk size in avi_write_trailer */
        if (enc->codec_type == AVMEDIA_TYPE_VIDEO)
            avio_wl32(pb, 1024 * 1024);
        else if (enc->codec_type == AVMEDIA_TYPE_AUDIO)
            avio_wl32(pb, 12 * 1024);
        else
            avio_wl32(pb, 0);
        avio_wl32(pb, -1); /* quality */
        avio_wl32(pb, au_ssize); /* sample size */
        avio_wl32(pb, 0);
        avio_wl16(pb, enc->width);
        avio_wl16(pb, enc->height);
        ff_end_tag(pb, strh);

        if (enc->codec_type != AVMEDIA_TYPE_DATA) {
            int ret;
            enum AVPixelFormat pix_fmt;

            strf = ff_start_tag(pb, "strf");
            switch (enc->codec_type) {
            case AVMEDIA_TYPE_SUBTITLE:
                /* XSUB subtitles behave like video tracks, other subtitles
                 * are not (yet) supported. */
                if (enc->codec_id != AV_CODEC_ID_XSUB)
                    break;
            case AVMEDIA_TYPE_VIDEO:
                /* WMP expects RGB 5:5:5 rawvideo in avi to have bpp set to 16. */
                if (  !enc->codec_tag
                    && enc->codec_id == AV_CODEC_ID_RAWVIDEO
                    && enc->pix_fmt == AV_PIX_FMT_RGB555LE
                    && enc->bits_per_coded_sample == 15)
                    enc->bits_per_coded_sample = 16;
                ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 0, 0);
                pix_fmt = avpriv_find_pix_fmt(avpriv_pix_fmt_bps_avi,
                                              enc->bits_per_coded_sample);
                if (   !enc->codec_tag
                    && enc->codec_id == AV_CODEC_ID_RAWVIDEO
                    && enc->pix_fmt != pix_fmt
                    && enc->pix_fmt != AV_PIX_FMT_NONE)
                    av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to avi, output file will be unreadable\n",
                          av_get_pix_fmt_name(enc->pix_fmt));
                break;
            case AVMEDIA_TYPE_AUDIO:
                if ((ret = ff_put_wav_header(pb, enc, 0)) < 0)
                    return ret;
                break;
            default:
                av_log(s, AV_LOG_ERROR,
                    "Invalid or not supported codec type '%s' found in the input\n",
                    (char *)av_x_if_null(av_get_media_type_string(enc->codec_type), "?"));
                return AVERROR(EINVAL);
            }
            ff_end_tag(pb, strf);
            if ((t = av_dict_get(st->metadata, "title", NULL, 0))) {
                ff_riff_write_info_tag(s->pb, "strn", t->value);
                t = NULL;
            }
            if (enc->codec_id == AV_CODEC_ID_XSUB
            && (t = av_dict_get(s->streams[i]->metadata, "language", NULL, 0))) {
                const char* langstr = av_convert_lang_to(t->value, AV_LANG_ISO639_1);
                t = NULL;
                if (langstr) {
                    char* str = av_asprintf("Subtitle - %s-xx;02", langstr);
                    if (!str)
                        return AVERROR(ENOMEM);
                    ff_riff_write_info_tag(s->pb, "strn", str);
                    av_free(str);
                }
            }
        }

        if (pb->seekable) {
            write_odml_master(s, i);
        }

        if (enc->codec_type == AVMEDIA_TYPE_VIDEO   &&
            st->sample_aspect_ratio.num > 0 &&
            st->sample_aspect_ratio.den > 0) {
            int vprp       = ff_start_tag(pb, "vprp");
            AVRational dar = av_mul_q(st->sample_aspect_ratio,
                                      (AVRational) { enc->width,
                                                     enc->height });
            int num, den;
            av_reduce(&num, &den, dar.num, dar.den, 0xFFFF);

            avio_wl32(pb, 0); // video format   = unknown
            avio_wl32(pb, 0); // video standard = unknown
            // TODO: should be avg_frame_rate
            avio_wl32(pb, (2LL*st->time_base.den + st->time_base.num - 1) / (2LL * st->time_base.num));
            avio_wl32(pb, enc->width);
            avio_wl32(pb, enc->height);
            avio_wl16(pb, den);
            avio_wl16(pb, num);
            avio_wl32(pb, enc->width);
            avio_wl32(pb, enc->height);
            avio_wl32(pb, 1); // progressive FIXME

            avio_wl32(pb, enc->height);
            avio_wl32(pb, enc->width);
            avio_wl32(pb, enc->height);
            avio_wl32(pb, enc->width);
            avio_wl32(pb, 0);
            avio_wl32(pb, 0);

            avio_wl32(pb, 0);
            avio_wl32(pb, 0);
            ff_end_tag(pb, vprp);
        }

        ff_end_tag(pb, list2);
    }

    if (pb->seekable) {
        /* AVI could become an OpenDML one, if it grows beyond 2Gb range */
        avi->odml_list = ff_start_tag(pb, "JUNK");
        ffio_wfourcc(pb, "odml");
        ffio_wfourcc(pb, "dmlh");
        avio_wl32(pb, 248);
        for (i = 0; i < 248; i += 4)
            avio_wl32(pb, 0);
        ff_end_tag(pb, avi->odml_list);
    }

    ff_end_tag(pb, list1);

    ff_riff_write_info(s);


    padding = s->metadata_header_padding;
    if (padding < 0)
        padding = 1016;

    /* some padding for easier tag editing */
    if (padding) {
        list2 = ff_start_tag(pb, "JUNK");
        for (i = padding; i > 0; i -= 4)
            avio_wl32(pb, 0);
        ff_end_tag(pb, list2);
    }

    avi->movi_list = ff_start_tag(pb, "LIST");
    ffio_wfourcc(pb, "movi");

    avio_flush(pb);

    return 0;
}
Example #12
0
static int init_filters(const char *filters_descr)
{
    char args[512];
    int ret;
    AVFilter *abuffersrc  = avfilter_get_by_name("abuffer");
    AVFilter *abuffersink = avfilter_get_by_name("abuffersink");
    AVFilterInOut *outputs = avfilter_inout_alloc();
    AVFilterInOut *inputs  = avfilter_inout_alloc();
    const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, -1 };
    AVABufferSinkParams *abuffersink_params;
    const AVFilterLink *outlink;
    AVRational time_base = fmt_ctx->streams[audio_stream_index]->time_base;

    filter_graph = avfilter_graph_alloc();

    /* buffer audio source: the decoded frames from the decoder will be inserted here. */
    if (!dec_ctx->channel_layout)
        dec_ctx->channel_layout = av_get_default_channel_layout(dec_ctx->channels);
    snprintf(args, sizeof(args),
            "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64,
             time_base.num, time_base.den, dec_ctx->sample_rate,
             av_get_sample_fmt_name(dec_ctx->sample_fmt), dec_ctx->channel_layout);
    ret = avfilter_graph_create_filter(&buffersrc_ctx, abuffersrc, "in",
                                       args, NULL, filter_graph);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer source\n");
        return ret;
    }

    /* buffer audio sink: to terminate the filter chain. */
    abuffersink_params = av_abuffersink_params_alloc();
    abuffersink_params->sample_fmts     = sample_fmts;
    ret = avfilter_graph_create_filter(&buffersink_ctx, abuffersink, "out",
                                       NULL, abuffersink_params, filter_graph);
    av_free(abuffersink_params);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n");
        return ret;
    }

    /* Endpoints for the filter graph. */
    outputs->name       = av_strdup("in");
    outputs->filter_ctx = buffersrc_ctx;
    outputs->pad_idx    = 0;
    outputs->next       = NULL;

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

    if ((ret = avfilter_graph_parse(filter_graph, filters_descr,
                                    &inputs, &outputs, NULL)) < 0)
        return ret;

    if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
        return ret;

    /* Print summary of the sink buffer
     * Note: args buffer is reused to store channel layout string */
    outlink = buffersink_ctx->inputs[0];
    av_get_channel_layout_string(args, sizeof(args), -1, outlink->channel_layout);
    av_log(NULL, AV_LOG_INFO, "Output: srate:%dHz fmt:%s chlayout:%s\n",
           (int)outlink->sample_rate,
           (char *)av_x_if_null(av_get_sample_fmt_name(outlink->format), "?"),
           args);

    return 0;
}
Example #13
0
static int init_filters(AVStream *audio_stream, int audio_stream_index)
{
	AVCodecContext *dec_ctx = audio_stream->codec;

    char args[512];
    int ret = 0;
    AVFilter *abuffersrc  = avfilter_get_by_name("abuffer");
    AVFilter *abuffersink = avfilter_get_by_name("abuffersink");
    AVFilterInOut *outputs = avfilter_inout_alloc();
    AVFilterInOut *inputs  = avfilter_inout_alloc();
    static const enum AVSampleFormat out_sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE };
	static const int64_t out_channel_layouts[] = { AV_CH_LAYOUT_STEREO, -1 };
    static const int out_sample_rates[] = { dec_ctx->sample_rate, -1 };
    const AVFilterLink *outlink;
    AVRational time_base = fmt_ctx->streams[audio_stream_index]->time_base;

    filter_graph = avfilter_graph_alloc();
    if (!outputs || !inputs || !filter_graph) {
        ret = AVERROR(ENOMEM);
        goto end;
    }

    /* buffer audio source: the decoded frames from the decoder will be inserted here. */
    if (!dec_ctx->channel_layout)
        dec_ctx->channel_layout = av_get_default_channel_layout(dec_ctx->channels);
    _snprintf_s(args, sizeof(args),
            "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64d",
             time_base.num, time_base.den, dec_ctx->sample_rate,
             av_get_sample_fmt_name(dec_ctx->sample_fmt), dec_ctx->channel_layout);
    ret = avfilter_graph_create_filter(&buffersrc_ctx, abuffersrc, "in",
                                       args, NULL, filter_graph);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer source\n");
        goto end;
    }

    /* buffer audio sink: to terminate the filter chain. */
    ret = avfilter_graph_create_filter(&buffersink_ctx, abuffersink, "out",
                                       NULL, NULL, filter_graph);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n");
        goto end;
    }

    ret = av_opt_set_int_list(buffersink_ctx, "sample_fmts", out_sample_fmts, -1,
                              AV_OPT_SEARCH_CHILDREN);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n");
        goto end;
    }

    ret = av_opt_set_int_list(buffersink_ctx, "channel_layouts", out_channel_layouts, -1,
                              AV_OPT_SEARCH_CHILDREN);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n");
        goto end;
    }

    ret = av_opt_set_int_list(buffersink_ctx, "sample_rates", out_sample_rates, -1,
                              AV_OPT_SEARCH_CHILDREN);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n");
        goto end;
    }

	last_flt_ctx = buffersink_ctx;
	int index = 1;
	while(filter_descr[index]) {
		const char* name = NULL;
		const char* arg = NULL;

		char tmp[64] = {0};
		char* pos = NULL;
		strncpy_s(tmp, 64, filter_descr[index], 64);
		pos = strchr(tmp, '=');
		if (pos != NULL) {
			*pos = '\0';
			name = tmp;
			arg = pos + 1;
		}
		else {
			name = filter_descr[index];
			arg = NULL;
		}
		insert_filter(name, arg, &last_flt_ctx);
		index++;
	}

    /* Endpoints for the filter graph. */
    outputs->name       = av_strdup("in");
    outputs->filter_ctx = buffersrc_ctx;
    outputs->pad_idx    = 0;
    outputs->next       = NULL;

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

    if ((ret = avfilter_graph_parse_ptr(filter_graph, filter_descr[0],
                                        &inputs, &outputs, NULL)) < 0)
        goto end;

    if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
        goto end;

    /* Print summary of the sink buffer
     * Note: args buffer is reused to store channel layout string */
    outlink = buffersink_ctx->inputs[0];
    av_get_channel_layout_string(args, sizeof(args), -1, outlink->channel_layout);
    av_log(NULL, AV_LOG_INFO, "Output: srate:%dHz fmt:%s chlayout:%s\n",
           (int)outlink->sample_rate,
		   (char *)av_x_if_null(av_get_sample_fmt_name((AVSampleFormat)outlink->format), "?"),
           args);

end:
    avfilter_inout_free(&inputs);
    avfilter_inout_free(&outputs);

    return ret;
}