Example #1
0
File: f_lavfi.c Project: Akemi/mpv
// Attempt to initialize all pads. Return true if all are initialized, or
// false if more data is needed (or on error).
static bool init_pads(struct lavfi *c)
{
    if (!c->graph)
        goto error;

    for (int n = 0; n < c->num_out_pads; n++) {
        struct lavfi_pad *pad = c->out_pads[n];
        if (pad->buffer)
            continue;

        const AVFilter *dst_filter = NULL;
        if (pad->type == MP_FRAME_AUDIO) {
            dst_filter = avfilter_get_by_name("abuffersink");
        } else if (pad->type == MP_FRAME_VIDEO) {
            dst_filter = avfilter_get_by_name("buffersink");
        } else {
            assert(0);
        }

        if (!dst_filter)
            goto error;

        char name[256];
        snprintf(name, sizeof(name), "mpv_sink_%s", pad->name);

        if (avfilter_graph_create_filter(&pad->buffer, dst_filter,
                                         name, NULL, NULL, c->graph) < 0)
            goto error;

        if (avfilter_link(pad->filter, pad->filter_pad, pad->buffer, 0) < 0)
            goto error;
    }

    for (int n = 0; n < c->num_in_pads; n++) {
        struct lavfi_pad *pad = c->in_pads[n];
        if (pad->buffer)
            continue;

        mp_frame_unref(&pad->in_fmt);

        read_pad_input(c, pad);
        // no input data, format unknown, can't init, wait longer.
        if (!pad->pending.type)
            return false;

        if (mp_frame_is_data(pad->pending)) {
            assert(pad->pending.type == pad->type);

            pad->in_fmt = mp_frame_ref(pad->pending);
            if (!pad->in_fmt.type)
                goto error;

            if (pad->in_fmt.type == MP_FRAME_VIDEO)
                mp_image_unref_data(pad->in_fmt.data);
            if (pad->in_fmt.type == MP_FRAME_AUDIO)
                mp_aframe_unref_data(pad->in_fmt.data);
        }

        if (pad->pending.type == MP_FRAME_EOF && !pad->in_fmt.type) {
            // libavfilter makes this painful. Init it with a dummy config,
            // just so we can tell it the stream is EOF.
            if (pad->type == MP_FRAME_AUDIO) {
                struct mp_aframe *fmt = mp_aframe_create();
                mp_aframe_set_format(fmt, AF_FORMAT_FLOAT);
                mp_aframe_set_chmap(fmt, &(struct mp_chmap)MP_CHMAP_INIT_STEREO);
                mp_aframe_set_rate(fmt, 48000);
                pad->in_fmt = (struct mp_frame){MP_FRAME_AUDIO, fmt};
            }
            if (pad->type == MP_FRAME_VIDEO) {
                struct mp_image *fmt = talloc_zero(NULL, struct mp_image);
                mp_image_setfmt(fmt, IMGFMT_420P);
                mp_image_set_size(fmt, 64, 64);
                pad->in_fmt = (struct mp_frame){MP_FRAME_VIDEO, fmt};
            }
        }

        if (pad->in_fmt.type != pad->type)
            goto error;

        AVBufferSrcParameters *params = av_buffersrc_parameters_alloc();
        if (!params)
            goto error;

        pad->timebase = AV_TIME_BASE_Q;

        char *filter_name = NULL;
        if (pad->type == MP_FRAME_AUDIO) {
            struct mp_aframe *fmt = pad->in_fmt.data;
            params->format = af_to_avformat(mp_aframe_get_format(fmt));
            params->sample_rate = mp_aframe_get_rate(fmt);
            struct mp_chmap chmap = {0};
            mp_aframe_get_chmap(fmt, &chmap);
            params->channel_layout = mp_chmap_to_lavc(&chmap);
            pad->timebase = (AVRational){1, mp_aframe_get_rate(fmt)};
            filter_name = "abuffer";
        } else if (pad->type == MP_FRAME_VIDEO) {
            struct mp_image *fmt = pad->in_fmt.data;
            params->format = imgfmt2pixfmt(fmt->imgfmt);
            params->width = fmt->w;
            params->height = fmt->h;
            params->sample_aspect_ratio.num = fmt->params.p_w;
            params->sample_aspect_ratio.den = fmt->params.p_h;
            params->hw_frames_ctx = fmt->hwctx;
            params->frame_rate = av_d2q(fmt->nominal_fps, 1000000);
            filter_name = "buffer";
        } else {
            assert(0);
        }

        params->time_base = pad->timebase;

        const AVFilter *filter = avfilter_get_by_name(filter_name);
        if (filter) {
            char name[256];
            snprintf(name, sizeof(name), "mpv_src_%s", pad->name);

            pad->buffer = avfilter_graph_alloc_filter(c->graph, filter, name);
        }
        if (!pad->buffer) {
            av_free(params);
            goto error;
        }

        int ret = av_buffersrc_parameters_set(pad->buffer, params);
        av_free(params);
        if (ret < 0)
            goto error;

        if (avfilter_init_str(pad->buffer, NULL) < 0)
            goto error;

        if (avfilter_link(pad->buffer, 0, pad->filter, pad->filter_pad) < 0)
            goto error;
    }

    return true;
error:
    MP_FATAL(c, "could not initialize filter pads\n");
    c->failed = true;
    mp_filter_internal_mark_failed(c->f);
    return false;
}
Example #2
0
static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
                                        AVFilterInOut *in)
{
    AVFilterContext *last_filter;
    const AVFilter *buffer_filt = avfilter_get_by_name("buffer");
    InputStream *ist = ifilter->ist;
    InputFile     *f = input_files[ist->file_index];
    AVRational tb = ist->framerate.num ? av_inv_q(ist->framerate) :
                    ist->st->time_base;
    AVRational fr = ist->framerate;
    AVRational sar;
    AVBPrint args;
    char name[255];
    int ret, pad_idx = 0;
    int64_t tsoffset = 0;
    AVBufferSrcParameters *par = av_buffersrc_parameters_alloc();
    
    if(!par)
    {
        return AVERROR(ENOMEM);
    }
    memset(par, 0, sizeof(*par));
    par->format = AV_PIX_FMT_NONE;
    
    if(ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO)
    {
        av_log(NULL, AV_LOG_ERROR, "Cannot connect video filter to audio input\n");
        ret = AVERROR(EINVAL);
        goto fail;
    }
    
    if(!fr.num)
    {
        fr = av_guess_frame_rate(input_files[ist->file_index]->ctx, ist->st, NULL);
    }
    
    if(ist->dec_ctx->codec_type == AVMEDIA_TYPE_SUBTITLE)
    {
        ret = sub2video_prepare(ist);
        if(ret < 0)
        {
            goto fail;
        }
    }
    
    sar = ist->st->sample_aspect_ratio.num ?
          ist->st->sample_aspect_ratio :
          ist->dec_ctx->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->resample_width,
               ist->resample_height,
               ist->hwaccel_retrieve_data ? ist->hwaccel_retrieved_pix_fmt : ist->resample_pix_fmt,
               tb.num, tb.den, sar.num, sar.den,
               SWS_BILINEAR + ((ist->dec_ctx->flags & AV_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, buffer_filt, name,
                                           args.str, NULL, fg->graph)) < 0)
    {
        goto fail;
    }
    par->hw_frames_ctx = ist->hw_frames_ctx;
    ret = av_buffersrc_parameters_set(ifilter->filter, par);
    if(ret < 0)
    {
        goto fail;
    }
    av_freep(&par);
    last_filter = ifilter->filter;
    
    if(ist->autorotate)
    {
        double theta = get_rotation(ist->st);
        
        if(fabs(theta - 90) < 1.0)
        {
            ret = insert_filter(&last_filter, &pad_idx, "transpose", "clock");
        }
        else if(fabs(theta - 180) < 1.0)
        {
            ret = insert_filter(&last_filter, &pad_idx, "hflip", NULL);
            if(ret < 0)
            {
                return ret;
            }
            ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL);
        }
        else if(fabs(theta - 270) < 1.0)
        {
            ret = insert_filter(&last_filter, &pad_idx, "transpose", "cclock");
        }
        else if(fabs(theta) > 1.0)
        {
            char rotate_buf[64];
            snprintf(rotate_buf, sizeof(rotate_buf), "%f*PI/180", theta);
            ret = insert_filter(&last_filter, &pad_idx, "rotate", rotate_buf);
        }
        if(ret < 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(last_filter, 0, setpts, 0)) < 0)
        {
            return ret;
        }
        
        last_filter = setpts;
    }
    
    if(do_deinterlace)
    {
        AVFilterContext *yadif;
        
        snprintf(name, sizeof(name), "deinterlace input from stream %d:%d",
                 ist->file_index, ist->st->index);
        if((ret = avfilter_graph_create_filter(&yadif,
                                               avfilter_get_by_name("yadif"),
                                               name, "", NULL,
                                               fg->graph)) < 0)
        {
            return ret;
        }
        
        if((ret = avfilter_link(last_filter, 0, yadif, 0)) < 0)
        {
            return ret;
        }
        
        last_filter = yadif;
    }
    
    snprintf(name, sizeof(name), "trim for input stream %d:%d",
             ist->file_index, ist->st->index);
    if(copy_ts)
    {
        tsoffset = f->start_time == AV_NOPTS_VALUE ? 0 : f->start_time;
        if(!start_at_zero && f->ctx->start_time != AV_NOPTS_VALUE)
        {
            tsoffset += f->ctx->start_time;
        }
    }
    ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?
                      AV_NOPTS_VALUE : tsoffset, f->recording_time,
                      &last_filter, &pad_idx, name);
    if(ret < 0)
    {
        return ret;
    }
    
    if((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)
    {
        return ret;
    }
    return 0;
fail:
    av_freep(&par);
    
    return ret;
}