繁体   English   中英

ffmpeg 库从 h263 转码到 h264 视频不同步

[英]ffmpeg library transcode from h263 to h264 video out of sync

目前,我设法实现了一个 function,它将给定的 h263 视频(3gp)转码为 h264 视频(mp4)。 除了视频编解码器之外,输入/输出文件中的所有其他内容都是相同的(例如音频编解码器、比特率、帧速率、分辨率……等)。

但是转码文件的视频 stream 与音频 stream 不同步,视频比音频慢约 1.5 倍。

为了确保转码时帧率和时基保持不变,我检查了我的编解码器和过滤器设置(如下面的示例代码所示),但我无法在我的代码中发现任何问题,这对解决问题没有帮助,我不明白这是怎么发生的,我在设置中遗漏了什么吗?

代码片段

对于编码器设置,它只是从输入容器的解码器中复制参数。

static void _app_config_dst_encoder(
        AVCodecContext *enc_ctx, AVCodecContext *dec_ctx)
{
    const AVCodec *encoder = enc_ctx->codec;
    if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
        enc_ctx->height = dec_ctx->height ;
        enc_ctx->width  = dec_ctx->width  ;
        enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio;
        if (encoder->pix_fmts)
            enc_ctx->pix_fmt = encoder->pix_fmts[0];
        else
            enc_ctx->pix_fmt = dec_ctx->pix_fmt;
        enc_ctx->time_base = dec_ctx->time_base;
        enc_ctx->framerate = dec_ctx->framerate;
        enc_ctx->bit_rate  = dec_ctx->bit_rate;
    } else { // AVMEDIA_TYPE_AUDIO
        enc_ctx->sample_rate = dec_ctx->sample_rate;
        enc_ctx->bit_rate    = dec_ctx->bit_rate;
        enc_ctx->channel_layout = dec_ctx->channel_layout;
        enc_ctx->channels = av_get_channel_layout_nb_channels(enc_ctx->channel_layout);
        enc_ctx->sample_fmt = encoder->sample_fmts[0];
        enc_ctx->time_base = (AVRational){1, enc_ctx->sample_rate};
    }
} // end of _app_config_dst_encoder

对于视频滤镜,为了简单起见,我没有使用额外的滤镜(例如scalesetptsfps ...等),这里的代码主要来自ffmpeg 转码示例

typedef struct {
    AVCodecContext *dec_ctx;
    AVCodecContext *enc_ctx;
    AVFilterContext *filt_sink_ctx;
    AVFilterContext *filt_src_ctx;
    AVFilterGraph   *filter_graph;
    size_t last_recovered_pkt_idx;
} StreamContext;


static int init_filter_video(
        StreamContext *sctx,  AVFilterGraph *filt_graph,
        AVFilterContext **filt_ctx_src, AVFilterContext **filt_ctx_sink)
{
    int ret = 0;
    char args[512] = {0};
    const AVFilter *buffersrc  = avfilter_get_by_name("buffer");
    const AVFilter *buffersink = avfilter_get_by_name("buffersink");
    AVCodecContext *dec_ctx = sctx->dec_ctx;
    AVCodecContext *enc_ctx = sctx->enc_ctx;
    snprintf(args, sizeof(args),
            "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
            dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
            dec_ctx->time_base.num, dec_ctx->time_base.den,
            dec_ctx->sample_aspect_ratio.num,
            dec_ctx->sample_aspect_ratio.den );
    avfilter_graph_create_filter(filt_ctx_src, buffersrc, "in", args, NULL, filt_graph);
    avfilter_graph_create_filter(filt_ctx_sink, buffersink, "out",  NULL, NULL, filt_graph);
    av_opt_set_bin(*filt_ctx_sink, "pix_fmts", (uint8_t*)&enc_ctx->pix_fmt,
            sizeof(enc_ctx->pix_fmt), AV_OPT_SEARCH_CHILDREN);
    return ret;
} // end of init_filter_video


int init_filters(AVFormatContext *fmt_i_ctx)
{
    int ret = 0;
    int idx = 0;
    int (*init_filter_fns[2])(StreamContext *, AVFilterGraph *, AVFilterContext **,
            AVFilterContext **) = {init_filter_video, init_filter_audio};
    // skip init_filter_audio() because it works without problem;
    for (idx = 0; (!ret) && (idx < fmt_i_ctx->nb_streams); idx++)
    {
        StreamContext *sctx = &bd->stream_ctx[idx];
        sctx->filt_sink_ctx = NULL;
        sctx->filt_src_ctx = NULL;
        sctx->filter_graph = NULL;
        char filter_spec[128] = {0};
        enum AVMediaType codectype = fmt_i_ctx->streams[idx]->codecpar->codec_type;
        switch (codectype) {
            case AVMEDIA_TYPE_VIDEO: // passthrough filter specification for video
                snprintf(filter_spec, sizeof(filter_spec), "null");
                break;
            case AVMEDIA_TYPE_AUDIO: // passthrough filter specification for audio
                snprintf(filter_spec, sizeof(filter_spec), "anull");
                break;
            default:
                continue;
        }
        AVFilterContext *buffersrc_ctx = NULL;
        AVFilterContext *buffersink_ctx = NULL;
        AVFilterInOut *outputs = avfilter_inout_alloc();
        AVFilterInOut *inputs  = avfilter_inout_alloc();
        AVFilterGraph *filter_graph = avfilter_graph_alloc();

        ret = init_filter_fns[codectype](sctx, filter_graph, &buffersrc_ctx, &buffersink_ctx);
        if(ret) { goto end; }
        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;

        ret = avfilter_graph_parse_ptr(filter_graph, &filter_spec[0], &inputs, &outputs, NULL);
        ret = avfilter_graph_config(filter_graph, NULL);
        sctx->filt_src_ctx  = buffersrc_ctx;
        sctx->filt_sink_ctx = buffersink_ctx;
        sctx->filter_graph  = filter_graph;

        avfilter_inout_free(&inputs);
        avfilter_inout_free(&outputs);
    } // end of loop
    return ret;
} // end of init_filters

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM