Windows下 ffmpeg 的 “Protocol not found“ 的解决

1. 问题描述

调用ffmpeg库中,如果使用 avformat_open_input 打开返回 -1330794744,使用 av_strerror

	 char buf[1024]={
    
    0};

 	int result = avformat_open_input(&pAVFormatContext, _url.toStdString().c_str(), nullptr, nullptr);
    if(result < 0)
    {
    
    
         av_strerror(result,buf,sizeof(buf));
        qDebug() << "open video "<< _url <<"failure" <<QString(buf);
        return false;
    }

网上通用解决办法,需要两步:

  • 在代码初始化时,把所有协议注册了
	av_register_all();
  • 编译ffmpeg 动态库,需要增加–enable-protocols 选项

但是我的问题比较奇怪,在windwos下用Qt 5.12.6同样一个套代码,在简单的测试项目工作正常,集成到正式的大型项目中就出错了。而且在测试项目中更换编译器,无论用MinGW 64还是用VS2017 64bit 均是正常运行,排除编译器的原因。

2. 排查方法记录

2.1 检查代码中编码器是否安装

在成功代码中把成功打开的编码器打印出来是 h264.我首先在出错的代码,可以用如下遍历把所有编码器打印出来,里面包含了h264.也就是说av_register_all()代码生效了。

void QFFmpeg::showAll()
{
    
    
    //输出所有支持的解码器名称
    QStringList listCodeName;
    AVCodec *code = av_codec_next(NULL);
    while (code != NULL) {
    
    
        listCodeName << code->name;
        //if(::strcmp("h264",code->name)==0)
          qDebug() << "ffmpeg Codec "<< code->name <<", type "<<code->type;
        code = code->next;

    }

  //  qDebug() << __func__ << listCodeName;
}

2.2 确定ffmpeg版本号

我尝试编译ffmpeg ,首先要确定我使用ffmpeg版本,虽然动态库写着的56,但准确的版本需要代码打印出来的,而ffmpeg没有整体版本号,一般用libavutil的版本确定,可以用如下代码打印

 //获取avutil数字版本号
    unsigned int version = avutil_version();
    //获取avutil三个子版本号
    int a = version / (int) pow(2, 16);
    int b = (int) (version - a * pow(2, 16)) / (int) pow(2, 8);
    int c = version % (int) pow(2, 8);
    //拼接avutil完整版本号

    qDebug()  << "MeidaPlayer ffmpeg/avutil version:("<<version<<")="<<a<<"."<<b<<"."<<c ;

运行这段代码,打印出三个数字 56 . 51 . 100

要根据官网下载网页,可以确定是 FFmpeg 4.3.5

在这里插入图片描述

把源码下来发编码工程量巨大,本想改写的qt.pri导入项目进行调试,但是发现需要configure编译参数,要进行一系列配置,网上有人给出来模板,但是每个dll要手动改写,非常痛苦,放弃。

2.3 打印编译参数

但是在源码当中还有有用的发现,我发现如下函数,这个函数明显是用来打印编译时configure的参数的

const char *avformat_configuration(void)
{
    
    
    return FFMPEG_CONFIGURATION;
}

于是我在成功和失败项目中分别打印编译参数

失败项目,清晰显示有 --disable-protocols

–prefix=‘c:/projects/repos/cerbero.git/1.18/build/dist/msvc_x86_64’ --libdir=‘c:/projects/repos/cerbero.git/1.18/build/dist/msvc_x86_64/lib’ --ar=x86_64-w64-mingw32-ar --as=x86_64-w64-mingw32-gcc --cc=x86_64-w64-mingw32-gcc --ld=x86_64-w64-mingw32-gcc --nm=x86_64-w64-mingw32-nm --ranlib=x86_64-w64-mingw32-ranlib --strip=x86_64-w64-mingw32-strip --windres=x86_64-w64-mingw32-windres --enable-static --enable-pic --enable-shared --disable-avdevice --disable-postproc --disable-swscale --disable-programs --disable-ffplay --disable-ffprobe --disable-ffmpeg --disable-encoder=flac --disable-protocols --disable-devices --disable-network --disable-hwaccels --disable-dxva2 --disable-vdpau --disable-filters --enable-filter=yadif --disable-doc --disable-d3d11va --disable-audiotoolbox --disable-videoprtoolbox --disable-vaapi --disable-crystalhd --disable-mediacodec --disable-mediafoundation --disable-nvenc --disable-mmal --disable-omx --disable-omx-rpi --disable-cuda --disable-cuvid --disable-libmfx --disable-libnpp --disable-iconv --disable-jni --disable-v4l2_m2m --disable-vulkan --disable-large-tests --disable-stripping --enable-optimizations --disable-nonfree --disable-version3 --enable-cross-compile --target-os=mingw32 --arch=x86_64 --cross-prefix=x86_64-w64-mingw32-

成功的项目,两者明显不同

configure --disable-static --enable-shared --enable-gpl --enable-version3 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-aacenc --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-lzma --enable-decklink --enable-zlib

也就是说两个应用很可能调用不同版本的dll

2.4 查看运行中调用dll

官方任务管理

失败的应用使用的 avutil-56.dll ,这个版本在编译时关掉所有协议支持,所以运行就会提示Protocol not found
请添加图片描述
成功的应用中调用 avutils-54.dll的版本,这个版本打开所有协议支持,所以不会报错。
请添加图片描述

进一步发现

因为我的项目中用同时用GStreamer和自己ffmpeg ,而GStreamer内部自己带了更高版本但无法正常支工作的版本与我带入的ffmpeg有冲突

请添加图片描述

最终解决方法把GStreamer 1.0内的 关于ffmpeg的头文件和库和动态库换成低版本的动态库,我直接使用内部的库

把正确版本的ffmpeg动态为放入目录当中,并移走错的动态库,即可

猜你喜欢

转载自blog.csdn.net/qq_16504163/article/details/130500369