ffmpeg

记录Mac系统下构建FFmpeg(-Wl,rpath不支持)及依赖库libxml2遇到的两个问题

最近在Mac系统下尝试编译FFmpeg源码,虽然由于都是nix系的系统,比Win下编译方便很多,但还是遇到一些由于系统差异导致的问题。首先是依赖库libxml2编译时,提示:

-bash: libtoolize: command not found

这个问题,简单调查后发现是由于Mac系统已经存在libtool这个工具,但是功能不同,而相同功能的工具程序换了个名字,叫glibtool,可以通过brew安装,参考这个地址:https://stackoverflow.com/questions/15448582/installed-libtool-but-libtoolize-not-found

glibtool可用后,增加个符号链接,或者改下libxml2的构建脚本,就可以build成功了。

第二个要记录的问题是FFmpeg在编译时,由于使用的是Xcode命令行工具安装的clang,无法识别gcc的“-Wl,rpath=”链接命令,用于指定rpath。

这个问题参考这个github上的issue描述:https://github.com/klee/klee/issues/591,将指定rpath链接参数的写法换成“-Wl,-rpath xxx”即可,多个rpath路径时可以参考下Xcode项目设置里增加rpath后生成的编译链接命令写法。

关于x265编码使用CBR流控码率不达标问题的处理

之前在使用x264编码时所谓的CBR流控其实是通过abr流控+vbv码率、缓冲参数设置的(vbv-maxrate,vbv-bufsize,也可以是ffmpeg的minrate,maxrate,如“ffmpeg -re -stream_loop -1 -i test.mp4 -c:v libx264 -x264-params “nal-hrd=cbr:force-cfr=1” -b:v 4M -minrate 4M -maxrate 4M -bufsize 1M -f flv rtmp://127.0.0.1/live/test,即控制了波动范围的vbr,而到了x265编码时,发现如法炮制的参数并不好使了,码率还是会有较大范围的波动,最后搜索研究了很久后发现,原来x265有这么个参数:

–[no-]strict-cbr Enable stricter conditions and tolerance for bitrate deviations in CBR mode. Default %s\n”, OPT(param->rc.bStrictCbr));

实测加上这个参数后,编码输出码率几乎就是目标码率很小范围内波动了,ffmpeg命令如下:

ffmpeg -re -stream_loop -1 -i <input> -c:v libx265 -b:v 25M -muxrate 30M -x265-params strict-cbr=1:vbv-bufsize=25000:vbv-maxrate=25000 -c:a aac -ac 2 -b:a 128k -f mpegts udp://239.3.3.3:5000

[续]Win10 + WSL编译FFmpeg开启openssl依赖时的坑

之前写过一篇基于WSL编译windows版FFmpeg的博文:使用Win10 + WSL编译FFmpeg时的依赖库处理 – https://blog.k-res.net/archives/2771.html,记录了一些基本构建操作和一些问题,但是当时的configure并没有开启很多其他依赖项来激活相关功能,这次要记录的是通过开启openssl的方式,增加如https,rtmps等协议的支持,虽然有WSL的加持,大大简化了windows下编译FFmpeg的复杂度,但到了某些依赖,如这次要说的openssl时,还是有些需要注意的地方的,毕竟WSL的方式实际的本质是在一个同时有linux命令但又能执行windows执行程序的特殊环境下执行构建操作,带来方便的同时也带来了一些特有的麻烦:

Continue reading…

一种FFmpeg提示“dts < pcr, TS is invalid“的解决方法

此问题出现在使用FFmpeg(动态库)输出UDP+TS流且开启muxrate输出CBR时,音频为aac编码,视频为264编码(libx264),视频部分使用vbv-bufsize及vbv-maxrate和nal-hrd=cbr编码CBR码流,可以看到程序刚跑起来FFmpeg的log回调就会疯狂报标题里提到的dts < pcr警告,这个警告的源码位置只有一个,就在libavformat\mpegtsenc.c的mpegts_write_pes这个函数里,但是读了下代码,也没看出来为什么会报这个警告,后来找到了这两篇参考:

FFMPEG转码音视频不同步情况总结 https://blog.csdn.net/liuchen1206/article/details/79461434

ffmpeg 奇葩问题2 https://blog.csdn.net/WaitForDone/article/details/78030095

其中第一篇参考文章里提到了编码速度问题,提到去掉B帧这个操作,而我的应用直接设置了zerolatency的tune相当于也是不带B帧的编码,第二篇文章提到了几个点,一开始直接放到了结果上,疯狂尝试各种qmin、qmax设置,结果都没有见效,而且实际发现我的视频码流并没有文章作者提到的编码出来的视频帧偏大的问题,其实用的就是默认的量化值,每帧大小也基本符合整体目标码率,最后百思不得其解时,试了下直接用ffmpeg命令行进行同样参数的编码操作,发现并没有报这个“dts < pcr”的警告,而且是跑了很长时间后也一次警告都没有,又结合了下第二篇参考文章中提到的delay设置,于是开始比较ffmpeg命令行程序的各种format、codec初始化操作参数,最后终于找到了问题:

Continue reading…

使用Win10 + WSL编译FFmpeg时的依赖库处理

Windows 10的Linux子系统WSL安装过程就不做赘述了,网上资料很多。

之前一直认为WSL只是以类似虚拟机或容器化的方式使得能在Windows上运行原生Linux程序,当然,也在WSL上做过如使用ndk交叉编译Android原生程序、动态库的操作,用起来还是挺方便的。直到最近研究FFmpeg的Windows版编译时才发现(参考自:https://www.bilibili.com/read/cv7058269/),原来WSL还有一个“大杀招”:直接运行Windows执行程序exe,如下图所示:

可以看到,在WSL内直接执行VS 2019的编译器程序cl,也是完全没有问题的,基于这种方法,FFmpeg官网上所说的用cygwin,mingw,msys之类的桥接环境构建Win版FFmpeg的麻烦就不复存在了,而且新版FFmpeg源码(博主用的4.3)的configure也做好了对这种编译方式的支持,参考上面的链接,制定上toolchain=msvc等相关参数,剩下的事和nix系统上构建一样就可以顺利完成了,简单方便!

不过,今天要记录的并不是WSL下编译Win版FFmpeg的问题,而是编译时如何引入其它依赖,如openssl,xml2等以获取更多功能支持,尤其是在Win环境下,这些其它依赖库的位置很有可能是一个很随意的位置,而在WSL环境下处理这种依赖的头文件、库文件搜索路径时是有坑的…

Continue reading…

FFmpeg 4.3.1 hls http(s)配新版Nginx WebDAV 无法删除切片bug

在使用FFmpeg进行hls推流输出时,发现配合新版Nginx (1.21) + WebDav组件的http服务器时,即使指定了m3u8切片数量以及删除无用切片的参数:

hls_list_size 5 -hls_flags delete_segments -hls

也没有在服务端正确删除无用切片,查看Nginx日志,发现每次FFmpeg发起的DELETE文件请求,都会跟随一个这样的报错:

DELETE with body is unsupported!

导致虽然FFmpeg删除文件的http请求到了Nginx,但实际并没有删除掉磁盘上的ts切片文件,时间一长,磁盘空间耗尽,然后就尴尬了…

Continue reading…

关于x265的high-tier启用问题

最近研究x265编码时如何启用high profile(后来才了解到对x265来说应该是high tier),之前接触x264的时候了解到的是直接在编码指定profile时就会有main和high的profile之分,如main、high、high10、high422等,但到了x265时却发现可指定的profile只有这么几个:

static const char * const x265_profile_names[] = {
    /* HEVC v1 */
    "main", "main10", "mainstillpicture", /* alias */ "msp",

    /* HEVC v2 (Range Extensions) */
    "main-intra", "main10-intra",
    "main444-8",  "main444-intra", "main444-stillpicture",

    "main422-10", "main422-10-intra",
    "main444-10", "main444-10-intra",

    "main12",     "main12-intra",
    "main422-12", "main422-12-intra",
    "main444-12", "main444-12-intra",

    "main444-16-intra", "main444-16-stillpicture", /* Not Supported! */
    0
};

并没有像x264的各种high,后经研究发现x265的high profile是通过另一个参数:“high-tier”来控制的,于是用ffmpeg命令行作了如下测试:

Continue reading…

解决Android NDK编译FFmpeg 4.2.2的x86 cpu版时的问题

老规矩,编译环境:Win10 1903,WSL ubuntu,ndk r20b,FFmpeg 4.2.2,首先分享下编译脚本:

#!/bin/bash
make clean

export NDK=/home/kres/android-ndk-r20b
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64/
API=21

function build_android
{
	echo "Compiling FFmpeg for $CPU"
	./configure \
		--prefix=$PREFIX \
		--enable-neon \
		--enable-hwaccels \
		--enable-gpl \
		--enable-postproc \
		--enable-shared \
		--enable-jni \
		--enable-mediacodec \
		--disable-decoders \
		    --enable-decoder=h264_mediacodec \
		    --enable-decoder=vp9 \
		    --enable-decoder=h264 \
		    --enable-decoder=mpeg4 \
		    --enable-decoder=aac \
		    --enable-decoder=aac_latm \
		    --enable-decoder=mjpeg \
		    --enable-decoder=png \
		    --enable-decoder=mpeg4_mediacodec \
		--disable-encoders \
		    --enable-encoder=vp9_vaapi --enable-encoder=h264_nvenc --enable-encoder=h264_v4l2m2m --enable-encoder=hevc_nvenc \
		--disable-demuxers \
		    --enable-demuxer=rtsp --enable-demuxer=rtp --enable-demuxer=flv --enable-demuxer=h264 \
		--disable-muxers \
		    --enable-muxer=rtsp --enable-muxer=rtp --enable-muxer=flv --enable-muxer=h264 \
		--disable-parsers \
		    --enable-parser=mpeg4video --enable-parser=aac --enable-parser=h264 --enable-parser=vp9 \
		--disable-protocols \
		    --enable-protocol=rtmp --enable-protocol=rtp --enable-protocol=tcp --enable-protocol=udp \
		--disable-bsfs \
		--disable-indevs --enable-indev=v4l2 \
		--disable-outdevs \
		--disable-filters \
		--disable-postproc \
		--disable-static \
		--disable-doc \
		--disable-ffmpeg \
		--disable-ffplay \
		--disable-ffprobe \
		--enable-avdevice \
		--disable-doc \
		--disable-symver \
		--cross-prefix=$CROSS_PREFIX \
		--target-os=android \
		--arch=$ARCH \
		--cpu=$CPU \
		--cc=$CC \
		--cxx=$CXX \
		--enable-cross-compile \
		--sysroot=$SYSROOT \
		--extra-cflags="-Os -fpic $OPTIMIZE_CFLAGS" \
		--extra-ldflags="$ADDI_LDFLAGS" \
		$ADDITIONAL_CONFIGURE_FLAG

		make clean
		make -j6
		make install
		echo "The Compilation of FFmpeg for $CPU is completed"

}
	#armv8-a
	ARCH=arm64
	CPU=armv8-a
	CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
	CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
	SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
	CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
	PREFIX=$(pwd)/android/$CPU
	OPTIMIZE_CFLAGS="-march=$CPU"
	build_android

	#armv7-a
	ARCH=arm
	CPU=armv7-a
	CC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang
	CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++
	SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
	CROSS_PREFIX=$TOOLCHAIN/bin/arm-linux-androideabi-
	PREFIX=$(pwd)/android/$CPU
	OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU "
	build_android

	#x86
	ARCH=x86
	CPU=x86
	CC=$TOOLCHAIN/bin/i686-linux-android$API-clang
	CXX=$TOOLCHAIN/bin/i686-linux-android$API-clang++
	SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
	CROSS_PREFIX=$TOOLCHAIN/bin/i686-linux-android-
	PREFIX=$(pwd)/android/$CPU
	OPTIMIZE_CFLAGS="-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32"
	build_android

	#x86_64
	ARCH=x86_64
	CPU=x86-64
	CC=$TOOLCHAIN/bin/x86_64-linux-android$API-clang
	CXX=$TOOLCHAIN/bin/x86_64-linux-android$API-clang++
	SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
	CROSS_PREFIX=$TOOLCHAIN/bin/x86_64-linux-android-
	PREFIX=$(pwd)/android/$CPU
	OPTIMIZE_CFLAGS="-march=$CPU -msse4.2 -mpopcnt -m64 -mtune=intel"
	build_android

Continue reading…