文章目录
- 1. 问题描述
- 2. 排查方法记录
- 2.1 检查代码中编码器是否安装
- 2.2 确定ffmpeg版本号
- 2.3 打印编译参数
- 2.4 查看运行中调用dll
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动态为放入目录当中,并移走错的动态库,即可