当我使用自定义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?
答案 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;
}