记录FFmpeg遇见的坑

利用av_frame_clone可以将一个frame clone后,其实也只是v_frame_alloc()+av_frame_ref()。但是有时候在音频帧的clone后不知道为什么会导致了返回了NULL。这个时候就懵逼了。这个debug进去后发现了一个问题,就是channel_layout没有设置导致的。这个因为是我手动设置解码器,所以忘记弄了,这个一般直接读取的话没有那个错误。


假如你用ffmpeg解码后再进行编码,不知为什么如果源过快时候会发现画面卡顿,音频声音差,只要你将输入源sleep,情况明显改善。这时,其实是内存污染作怪。在ffmpeg里面,解码后的avframe内存还是归ffmpeg管理,当你每次读包解码时候,过快这样就会导致那种情况了。你要做的是用av_frame_clone,那样的话那个就可以了。


假如你将一个音频文件转码成aac文件结尾的文件,这个时候你会发现有个问题是,不知道为什么文件的播放时间总是会比我们实际的时间会长,而且这种长度会随着本来的音频时间长度成线性关系增加。这时,你可能会怀疑自己的编码是不是哪里出了问题。但事实上不是,那是因为aac文件播放本来就有adts,而在ffmpeg里面计算aac文件播放的duration时间,跟踪源码发现ffmpeg里面计算文件是长度是对比视频跟音频的长度,取其最大的。代码如下



static void estimate_timings_from_bit_rate(AVFormatContext *ic)
{
    int64_t filesize, duration;
    int i, show_warning = 0;
    AVStream *st;

    /* if bit_rate is already set, we believe it */
    if (ic->bit_rate <= 0) {
        int64_t bit_rate = 0;
        for (i = 0; i < ic->nb_streams; i++) {
            st = ic->streams[i];
            if (st->codecpar->bit_rate <= 0 && st->internal->avctx->bit_rate > 0)
                st->codecpar->bit_rate = st->internal->avctx->bit_rate;
            if (st->codecpar->bit_rate > 0) {
                if (INT64_MAX - st->codecpar->bit_rate < bit_rate) {
                    bit_rate = 0;
                    break;
                }
                bit_rate += st->codecpar->bit_rate;
            } else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && st->codec_info_nb_frames > 1) {
                // If we have a videostream with packets but without a bitrate
                // then consider the sum not known
                bit_rate = 0;
                break;
            }
        }
        ic->bit_rate = bit_rate;
    }

    /* if duration is already set, we believe it */
    if (ic->duration == AV_NOPTS_VALUE &&
        ic->bit_rate != 0) {
        filesize = ic->pb ? avio_size(ic->pb) : 0;
        if (filesize > ic->internal->data_offset) {
            filesize -= ic->internal->data_offset;
            for (i = 0; i < ic->nb_streams; i++) {
                st      = ic->streams[i];
                if (   st->time_base.num <= INT64_MAX / ic->bit_rate
                    && st->duration == AV_NOPTS_VALUE) {
                    duration = av_rescale(8 * filesize, st->time_base.den,
                                          ic->bit_rate *
                                          (int64_t) st->time_base.num);
                    st->duration = duration;
                    show_warning = 1;
                }
            }
        }
    }
    if (show_warning)
        av_log(ic, AV_LOG_WARNING,
               "Estimating duration from bitrate, this may be inaccurate\n");
}

在这里你看到duration是将filesize来依据,而aac文件这里就出了个问题了,它会将一些别的信息添加进去,这个具体是什么信息,还没有深入研究,估计是一些设置信息,然后就会出现上述的bug。

在ffmpeg里面,假如你试过用avformat_open_input去读取rtmp流,而rtmp流不正确,这时不得不等待2分钟,通过网上的搜索,我们看到很多设置timeout,但我不知道是不是只有我这里会这样,我设置timeout后,连正确的流也拉取不了,最后一直查找资料跟debug发现我设置的参数是错误的,应该是rw_timeout,设置后,终于能正常时间内连接。

Queue input is backward in time,在ffmpeg里面,假如你用音频编码aac的时候,可能遇到这个警告。源代码如下:

if(afq->frame_count && new[-1].pts >= new->pts)
            av_log(afq->avctx, AV_LOG_WARNING, "Queue input is backward in time\n");


1.编码的nbsample不对

2.pts不对



linux编译Android,利用sdk编译./ndk-build NDK_PROJECT_PATH=/home/zoring/sour/libyuv APP_BUILD_SCRIPT=/home/zoring/sour/libyuv/Android.mk

上面NDK_PROJECT_PATH是指文件的文件

APP_BUILD_SCRIPT是Android.mk的位置。

基本用这个可以编译好MP3lame的

另外附上x264编译的


#!/bin/bash
NDK=$HOME/sour/android-ndk-r10d
SYSROOT=$NDK/platforms/android-9/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64
export PLATFORM=$NDK/platforms/android-8/arch-arm
function build_one
{
./configure --prefix=$PREFIX \
--enable-static \
--enable-shared \
--enable-pic \
--disable-asm \
--disable-cli \
--host=arm-linux \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--sysroot=$PLATFORM  
make clean
make -j8
make install
sudo ldconfig
}
CPU=arm
PREFIX=$HOME/sour/FFmpeg-release-3.2/android/$CPU
ADDI_CFLAGS="-marm"
build_one 

最后是ffmpeg的编译shell

#!/bin/bash
NDK=$HOME/sour/android-ndk-r10d
SYSROOT=$NDK/platforms/android-9/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64
function build_one
{
./configure \
    --prefix=$PREFIX \
    --enable-shared \
    --disable-static \
    --disable-doc \
    --disable-ffmpeg \
    --disable-ffplay \
    --disable-ffprobe \
    --disable-ffserver \
    --disable-avdevice \
    --disable-doc \
    --enable-gpl \
    --enable-nonfree \
    --enable-pthreads \
    --enable-libx264 \
    --enable-libmp3lame \
    --disable-symver \
--enable-yasm --enable-asm --enable-neon --enable-mmx --enable-mmxext --enable-sse --enable-sse2 --enable-sse3 --enable-ssse3 --enable-sse4 --enable-sse42 --enable-avx --enable-avx2 --enable-inline-asm --enable-fma3 --enable-fma4 --enable-jni --enable-mediacodec \
--cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc \
    --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
    --target-os=linux \
    --arch=arm \
    --enable-cross-compile \
    --sysroot=$SYSROOT \
    --extra-cflags="-Os -fpic $ADDI_CFLAGS" \
    --extra-ldflags="$ADDI_LDFLAGS" \
    --extra-cflags="-I $HOME/sour/FFmpeg-release-3.2/android/$CPU/include/" \
    --extra-ldflags="-L $HOME/sour/FFmpeg-release-3.2/android/$CPU/lib/" \
--enable-neon
    $ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
}
CPU=arm
PREFIX=$(pwd)/android/$CPU
ADDI_CFLAGS="-marm"
build_one

 后面是ios的shell

#!/bin/sh

# directories
SOURCE="ffmpeg-3.3"
FAT="FFmpeg-iOS"

SCRATCH="scratch"
# must be an absolute path
THIN=`pwd`/"thin"


X264=/Users/administrator/Desktop/FFmpeg-iOS-build-script/x264
LAME=/Users/administrator/Desktop/FFmpeg-iOS-build-script/lame

#X264=`pwd`/"x264"
#FDK_AAC=`pwd`/"fdk-aac"
#LAME=`pwd`/"lame"

echo "hello x264 $X264"
echo "hello lame $LAME"

CONFIGURE_FLAGS="--enable-cross-compile --disable-debug --disable-programs --enable-yasm --enable-asm --eanble-neon --enable-mmx --enable-mmxext --enable-sse --enable-sse2 --enable-sse3 --enable-ssse3 --enable-sse4 --enable-sse42 --enable-avx --enable-avx2 --enable-inline-asm \
                 --disable-doc --enable-pic --enable-videotoolbox  --disable-ffmpeg --disable-ffplay --disable-ffserver --enable-pthreads --disable-debug --enable-fma3 --enable-fma4"


#---新加MP3---
if [ "$LAME" ]
echo "走lame1"
then
echo "走lame2"
CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-gpl --enable-libmp3lame"
echo "走lame3"
fi
#---新加MP3---


if [ "$X264" ]
then
	CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-gpl --enable-libx264"
fi

if [ "$FDK_AAC" ]
then
	CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-gpl --enable-nonfree --enable-libfdk-aac"
fi

# avresample
#CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-avresample"

ARCHS="arm64 armv7 x86_64 i386"
COMPILE="y"
LIPO="y"

DEPLOYMENT_TARGET="6.0"

if [ "$*" ]
then
	if [ "$*" = "lipo" ]
	then
		# skip compile
		COMPILE=
	else
		ARCHS="$*"
		if [ $# -eq 1 ]
		then
			# skip lipo
			LIPO=
		fi
	fi
fi

if [ "$COMPILE" ]
then
	if [ ! `which yasm` ]
	then
		echo 'Yasm not found'
		if [ ! `which brew` ]
		then
			echo 'Homebrew not found. Trying to install...'
                        ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" \
				|| exit 1
		fi
		echo 'Trying to install Yasm...'
		brew install yasm || exit 1
	fi
	if [ ! `which gas-preprocessor.pl` ]
	then
		echo 'gas-preprocessor.pl not found. Trying to install...'
		(curl -L https://github.com/libav/gas-preprocessor/raw/master/gas-preprocessor.pl \
			-o /usr/local/bin/gas-preprocessor.pl \
			&& chmod +x /usr/local/bin/gas-preprocessor.pl) \
			|| exit 1
	fi

	if [ ! -r $SOURCE ]
	then
		echo 'FFmpeg source not found. Trying to download...'
		curl http://www.ffmpeg.org/releases/$SOURCE.tar.bz2 | tar xj \
			|| exit 1
	fi

	CWD=`pwd`
	for ARCH in $ARCHS
	do
		echo "building $ARCH..."
		mkdir -p "$SCRATCH/$ARCH"
		cd "$SCRATCH/$ARCH"

		CFLAGS="-arch $ARCH"
		if [ "$ARCH" = "i386" -o "$ARCH" = "x86_64" ]
		then
		    PLATFORM="iPhoneSimulator"
		    CFLAGS="$CFLAGS -mios-simulator-version-min=$DEPLOYMENT_TARGET"
		else
		    PLATFORM="iPhoneOS"
		    CFLAGS="$CFLAGS -mios-version-min=$DEPLOYMENT_TARGET -fembed-bitcode"
		    if [ "$ARCH" = "arm64" ]
		    then
		        EXPORT="GASPP_FIX_XCODE5=1"
		    fi
		fi

		XCRUN_SDK=`echo $PLATFORM | tr '[:upper:]' '[:lower:]'`
		CC="xcrun -sdk $XCRUN_SDK clang"

		# force "configure" to use "gas-preprocessor.pl" (FFmpeg 3.3)
		if [ "$ARCH" = "arm64" ]
		then
		    AS="gas-preprocessor.pl -arch aarch64 -- $CC"
		else
		    AS="$CC"
		fi

		CXXFLAGS="$CFLAGS"
		LDFLAGS="$CFLAGS"

#---新加MP3---
if [ "$LAME" ]
then
CFLAGS="$CFLAGS -I$LAME/include"
LDFLAGS="$LDFLAGS -L$LAME/lib"
fi
#---新加MP3---

		if [ "$X264" ]
		then
			CFLAGS="$CFLAGS -I$X264/include"

			LDFLAGS="$LDFLAGS -L$X264/lib"
		fi
		if [ "$FDK_AAC" ]
		then
			CFLAGS="$CFLAGS -I$FDK_AAC/include"
			LDFLAGS="$LDFLAGS -L$FDK_AAC/lib"
		fi
echo "hello root CFLAGS:$CFLAGS"
echo "hello root CONFIGURE_FLAGS:$CONFIGURE_FLAGS"
echo "hello root LDFLAGS:$LDFLAGS"
		TMPDIR=${TMPDIR/%\/} $CWD/$SOURCE/configure \
		    --target-os=darwin \
		    --arch=$ARCH \
		    --cc="$CC" \
		    --as="$AS" \
		    $CONFIGURE_FLAGS \
		    --extra-cflags="$CFLAGS" \
		    --extra-ldflags="$LDFLAGS" \
		    --prefix="$THIN/$ARCH" \
		|| exit 1

		make -j3 install $EXPORT || exit 1
		cd $CWD
	done
fi

if [ "$LIPO" ]
then	
	echo "building fat binaries..."
	mkdir -p $FAT/lib
	set - $ARCHS
	CWD=`pwd`
	cd $THIN/$1/lib
	for LIB in *.a
	do
		cd $CWD
		echo lipo -create `find $THIN -name $LIB` -output $FAT/lib/$LIB 1>&2
		lipo -create `find $THIN -name $LIB` -output $FAT/lib/$LIB || exit 1
	done

	cd $CWD
	cp -rf $THIN/$1/include $FAT
fi

echo Done




linux编译Android,利用sdk编译./ndk-build NDK_PROJECT_PATH=/home/zoring/sour/libyuv APP_BUILD_SCRIPT=/home/zoring/sour/libyuv/Android.mk

上面NDK_PROJECT_PATH是指文件的文件

APP_BUILD_SCRIPT是Android.mk的位置。

基本用这个可以编译好MP3lame的

另外附上x264编译的


在一个项目重构里面,发现声音急促,以及声音断续,一开始以为pts不对,但发现不对。pts是正确的,那么剩下的代码都是根据之前的项目的用的,那么出现逻辑上的错误也很少可能,只能是内存污染。但我是用new的,应该不存在的。最后发现用av_frame_clone解决了问题,这个问题我猜测是ffmpeg内部有个内存管理的,类似于c++的自动内存管理,所以才会导致内存的污染问题出现。


网上的一些cbr说法里面,你会发现不管用,在官网那里提供那里的命令时候输出为ts时也是不管用,很多误人子弟的说这样。

ffmpeg -i /home/zoring/45.ts -b 4000k -minrate 4000k -maxrate 4000k -bufsize 1835k     -vcodec libx264 -f mpegts -muxrate 4000K -y trailer.ts

亲测可用。


有时你会看到那个null(libx264)而不是那个详细信息,这个是因为av_dump_format在avformat_write_header之后。

你可能感兴趣的:(FFmpeg)