ffplay-如何获取AVDictionary编解码器

时间:2018-12-04 12:45:08

标签: c++ ffmpeg

当我使用自定义ffmpeg播放器应用程序(ffmpeg stream decoding - artefacts when not using ffplay)解码伪像时,而ffplay显示了没有伪像的完美图像,因此,我需要以与ffplay相同的方式实现我的播放器。

ffplay.c使用

AVDictionary *codec_opts;

已在cmdutils.c中初始化(纠正了我)。我需要这个字典来进行类似于ffplay的编解码器初始化(第2615f行),但是我不明白它是如何创建的。有没有办法

a)以与ffplay相同的方式包含cmdutils-最终链接到cmdutils.o最终使我得到

:-1: error: /.../cmdutils.o: undefined reference to symbol 'swresample_version@@LIBSWRESAMPLE_3'

尽管我使用(QT)包含了libswresample:

LIBS +=-L/usr/local/lib -lavformat -lswscale -lswresample -lavutil -lavcodec 

b)是否可以通过其他任何方式访问AVDictionary codec_opts?

2 个答案:

答案 0 :(得分:1)

是的,您可以为自己的实现创建和设置AVDictionary *codec_opts
检查以下示例:

1)https://github.com/sparrowli/laimpeg/blob/0a68db7d88c0b42c3df584e66366b4e81d3b31ee/libavutil/tests/dict.c
2)https://github.com/ithinkso117/DotNetPusher/blob/cf24e7e10a0b2fa843b435d3d3b759a7aa049d1d/DotNetPusher.Native/Encoder.cpp

对于包含cmdutils.c,这将永远无法进行。您只能通过API并与共享库链接使用FFmpeg的库。

希望这些帮助。

答案 1 :(得分:0)

在我自己的自定义ffmpeg播放器应用程序中,我尝试复制ffplay的AVDictionary编解码器初始化代码,但我不知道它的作用。就是这样,但是看起来比起用于选择选项并启用它们的代码,它更像是对命令行提供的选项的过滤器。

int LIBAV_Video::check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)
{
    int ret = avformat_match_stream_specifier(s, st, spec);
    if (ret < 0)
        av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec);
    return ret;
}

//////////////////////////////////////////////////////////////////////////////////////
AVDictionary* LIBAV_Video::filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
                                                                                                AVFormatContext *s, AVStream *st, AVCodec *codec)
{
    AVDictionary    *ret = NULL;
    AVDictionaryEntry *t = NULL;
    int            flags = s->oformat ? AV_OPT_FLAG_ENCODING_PARAM
                                                                        : 
    AV_OPT_FLAG_DECODING_PARAM;
    char          prefix = 0;
    const AVClass    *cc = avcodec_get_class();

    if (!codec)
        codec              = s->oformat ? avcodec_find_encoder(codec_id)
                                                                      : 
    avcodec_find_decoder(codec_id);

    switch (st->codecpar->codec_type) 
    {
    case AVMEDIA_TYPE_VIDEO:
        prefix  = 'v';
        flags  |= AV_OPT_FLAG_VIDEO_PARAM;
        break;
    case AVMEDIA_TYPE_AUDIO:
        prefix  = 'a';
        flags  |= AV_OPT_FLAG_AUDIO_PARAM;
        break;
    case AVMEDIA_TYPE_SUBTITLE:
        prefix  = 's';
        flags  |= AV_OPT_FLAG_SUBTITLE_PARAM;
        break;
    }

    while (t = av_dict_get(opts, "", t, AV_DICT_IGNORE_SUFFIX)) 
    {
        char *p = strchr(t->key, ':');

        /* check stream specification in opt name */
        if (p)
            switch (check_stream_specifier(s, st, p + 1)) 
            {
            case  1: *p = 0; break;
            case  0:         continue;
            default:         exit(1);   
            }

        if (av_opt_find(&cc, t->key, NULL, flags, AV_OPT_SEARCH_FAKE_OBJ) ||
                !codec ||
                (codec->priv_class &&
                av_opt_find(&codec->priv_class, t->key, NULL, flags,
                AV_OPT_SEARCH_FAKE_OBJ)))
        {
            av_dict_set(&ret, t->key, t->value, 0);
        }
        else if (t->key[0] == prefix &&
                         av_opt_find(&cc, t->key + 1, NULL, flags,
                         AV_OPT_SEARCH_FAKE_OBJ))
        {
            av_dict_set(&ret, t->key + 1, t->value, 0);
        }
        if (p)
            *p = ':';
    }

    return ret;
}

//////////////////////////////////////////////////////////////////////////////////////
AVDictionary** LIBAV_Video::setup_find_stream_info_opts(AVFormatContext *s, AVDictionary *codec_opts)
{
    unsigned int i;
    AVDictionary **opts;

    if (!s->nb_streams)
        return NULL;

    opts = (AVDictionary **)av_mallocz_array(s->nb_streams, sizeof(*opts));
    if (!opts) 
    {
        av_log(NULL, AV_LOG_ERROR, "Could not alloc memory for stream options.\n");
        return NULL;
    }

    for (i = 0; i < s->nb_streams; i++)
        opts[i] = filter_codec_opts(codec_opts, s->streams[i]->codecpar->codec_id, s, s->streams[i], NULL);

    return opts;
}

如果有人知道任何 programmatic 程序参考或文档,这些文档或文档确定了用于常见用例的选项,例如最小的播放延迟,那么将不胜感激。

我发现了需要解决的两个问题,才能在自定义代码中获得高质量的ffmpeg libav播放:1)一系列的AVDictionary设置似乎随每个库版本而有所不同,以及2)ffplay需要的AVFilter图形实现要复制。我怀疑需要AVFilter Graph,因为它是在关键帧和非关键帧之间进行插值的逻辑,并且似乎对损坏的帧进行了某种校正。

以下是AVDictionary设置,该设置似乎适用于ffmpeg 4.2.3,但似乎每个发行版都有所不同,我不知道为什么:

  av_dict_set(&mp_opts, "threads", "auto", 0);  // if multi-threading is needed, do it
  av_dict_set( &mp_opts, "refcounted_frames", "1", 0 ); // ffplay sets this
  av_dict_set( &mp_opts, "sync", "video", 0 );  
  av_dict_set( &mp_opts, "fflags", "discardcorrupt", 0 );// sets flag in mp_format_context

    switch (mp_av_player->m_stream_type)
    {
    case 0: // media file
        av_dict_set( &mp_opts, "framerate", "24", 0 );
        av_dict_set( &mp_opts, "scan_all_pmts", "1", 0 );   // ffplay uses this flag
        break;
    case 1: // usb cam
        // av_dict_set(&mp_opts,"show_video_device_dialog","true",0);
        if (usb_format)
        {
            // av_dict_set( &mp_opts, "max_delay", "500000", 0 );   // half second
            // av_dict_set( &mp_opts, "rtbufsize", "106M", 0 );     // a half second of 1280x720x4 
            av_dict_set( &mp_opts, "fflags", "nobuffer", 0 );

            char bsjnk[1024];
            sprintf( bsjnk, "%dx%d", usb_format->m_max_width, usb_format->m_max_height );
            av_dict_set( &mp_opts, "video_size", bsjnk, 0 );
            //
            sprintf( bsjnk, "%1.2f", usb_format->m_max_fps );
            av_dict_set( &mp_opts, "framerate", bsjnk, 0 );
            //
            if (usb_format->m_pixelFormat.size() > 0)
            {
                av_dict_set( &mp_opts, "pixel_format", usb_format->m_pixelFormat.c_str(), 0 );
            }
            else if (usb_format->m_pixelFormat.size() > 0)
            {
                av_dict_set( &mp_opts, "vcodec", usb_format->m_vcodec.c_str(), 0 );
            }
        } 
        else 
        {
            av_dict_set( &mp_opts, "video_size", "640x480", 0 );
            av_dict_set( &mp_opts, "framerate", "30", 0 );
        }
        break;
    case 2: // ip cam
        // av_dict_set( &mp_opts, "flags2", "fast", 0 ); does this cause bad frames?
        av_dict_set( &mp_opts, "max_delay", "100000", 0 );
        av_dict_set( &mp_opts, "flags", "low_delay", 0 );
        // av_dict_set( &mp_opts, "fflags", "flush_packets", 0 );
        // av_dict_set( &mp_opts, "fflags", "nobuffer", 0 ); testing removing this
        av_dict_set( &mp_opts, "rtsp_transport", "tcp", 0 );
        av_dict_set( &mp_opts, "framerate", "29.97", 0 );
        av_dict_set( &mp_opts, "allowed_media_types", "video", 0 );
        break;
    }