android平台,FFMPEG转码加速(一)-X264

2 篇文章 0 订阅
2 篇文章 0 订阅

一:打开NEON汇编

在ARMV7以上的芯片中,加入NEON汇编的功能,所以编译X264的时候,可以打开NEON

./configure --prefix=/home/arm_lib \
        --disable-gpac \
        --enable-static \
--enable-pic \
--cross-prefix=$ARM_ROOT/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/${ARM_PRE}- --host=arm-linux \
        --extra-cflags=" -I$ARM_INC -fPIC -DANDROID -fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -Wno-psabi -mcpu=cortex-a8-mfpu=neon -mfloat-abi=softfp -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -DANDROID  -Wa,--noexecstack -MMD -MP -I/E/code/thread/pthreads-w32-2-9-1-release" \........................................................


二:打开编码多线程

在X86平台上,x264编译是能自动打开SLICE级别和帧级别的多线程的,它会根据获取的CPU的个数来分配编码线程,一般分配原则为CPU个数*1.5个线程,但开始在小米1S双核的机子上,CPU使用始终只有50%,后来发现原来只有一个线程在编码,在说明怎么打开多线程之前,先介绍下X264的线程并行编码。

x264编码的多线程编码可以两种方式,一种是一帧分多个条带来并行编码,一帧的线程之间没有交互,所以在多核机子上能某种程度达到真正的并行,但一般使用这种编码的情况少,压缩比没有一帧一个条带高(条带阻断了一帧内部的相关性,条带头也会多出一部分数据),除非在那种实时性要求很强的场景下才使用,如视频会议,云游戏等。另外一种是帧级别的并行,一个线程编码一个条带,这种编码方式不能达到真正的并行,因为帧间参考的限制,比如编码当前帧某个宏块的时候,需要前面的被参考帧的宏块附近区域已经重构完成,同时多线程编码编出来的码流也和单线程编码出来的码流不一样,因为多线程参考区域比单线程的参考区域会相对小点,PSNR也相对低点。

回到主题,X264在CONFIGURE的时候,发现平台无法加入PTHREAD的支持,修改方式如下,在CONFIGURE文件中

libpthread=""
if [ "$thread" = "auto" ]; then
    thread="no"
    case $SYS in
        BEOS)
            thread="beos"
            define HAVE_BEOSTHREAD
            ;;
        WINDOWS)
            if cc_check pthread.h -lpthread "pthread_create(0,0,0,0);" ; then
                thread="posix"
                libpthread="-lpthread"
            elif cc_check pthread.h -lpthreadGC2 "pthread_create(0,0,0,0);" ; then
                thread="posix"
                libpthread="-lpthreadGC2"
            elif cc_check pthread.h "-lpthreadGC2 -lwsock32 -DPTW32_STATIC_LIB" "pthread_create(0,0,0,0);" ; then
                thread="posix"
                libpthread="-lpthreadGC2 -lwsock32"
                define PTW32_STATIC_LIB
            elif cc_check pthread.h "-lpthreadGC2 -lws2_32 -DPTW32_STATIC_LIB" "pthread_create(0,0,0,0);" ; then
                thread="posix"
                libpthread="-lpthreadGC2 -lws2_32"
                define PTW32_STATIC_LIB
            else
                # default to native threading if pthread-win32 is unavailable
                thread="win32"
            fi
            ;;
        *)
            #cc_check pthread.h -lpthread && 
   thread="posix" && libpthread="/E/code/thread/pthreads-w32-2-9-1-release/libpthreadGC2.a"
            ;;
    esac
fi


if [ "$thread" = "posix" ]; then
    LDFLAGS="$LDFLAGS $libpthread"
    define HAVE_POSIXTHREAD
    if [ "$SYS" = "LINUX" ] && cc_check sched.h "-D_GNU_SOURCE -Werror" "cpu_set_t p_aff; return CPU_COUNT(&p_aff);" ; then
        define HAVE_CPU_COUNT
    fi
fi


红色的为修改的部分,修改之后,MAKE的时候会报错,在CPU.C中会报cpu_set_t未定义,做如下修改即可

#elif SYS_LINUX
typedef unsigned long int __cpu_mask;
    # define __CPU_SETSIZE  1024
    # define __NCPUBITS     (8 * sizeof (__cpu_mask))


typedef struct
{
  __cpu_mask __bits[__CPU_SETSIZE / __NCPUBITS];
} cpu_set_t;


    cpu_set_t p_aff;
    memset( &p_aff, 0, sizeof(p_aff) );
    //if (sched_getaffinity( 0, sizeof(p_aff), &p_aff ) )
    //   return 1;

编译完后,就可以使用多线程了,-threads xx


3:ffmpeg的264解码多线程

同理,FFMPEG自己解码的多线程虽然可以链接到PTHREAD库,但由于没有针对ARM平台的CPU个数检测函数,所以默认情况下是不能打开多线程的,临时的处理方法:

在FFMPEG的LIBCODEC库中Pthread.c文件

static int get_logical_cpus(AVCodecContext *avctx)
{
    int ret, nb_cpus = 1;
return 4;//直接返回4个CPU个数

然后再在转码命令参数中设置解码线程数,如:ffmpeg -i xx.mp4 -threads 2 -vcodec libx264 ..................


因为现在只追求速度上的优化,不考虑质量,质量通过加大码率来弥补,所以编码参数用-ULTRAFAST来编码。

用PPA(一种程序性能分析工具)跟踪X264的运行状态,线程函数执行的时间



线程间等待的情况


可以看出线程间的并行度还不是很完全,所以如何针对特定的硬件环境,设计算法调节线程之间编码的相关性也是一门很深的学问(以后有机会再讨论)。

以上就是软转码加速的大概情况。


本文版权归作者所有,欢迎转载,但需在文章页面明显位置给出原文连接。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,针对您的问题,我来简单回答一下。 首先,要明确的是,FFmpeg 是一个开源的跨平台音视频处理库,支持包括解码、编码、封装、解封装等功能。而解封装(Demuxing)是指将音视频封装格式中的音视频流解析出来,以便后续对音视频流进行解码、编码等操作。 在 Android 基于 FFmpeg 开发简易播放器中,我们可以使用 FFmpeg 提供的 API 来进行解封装。具体步骤如下: 1. 打开输入文件 使用 FFmpeg 的 avformat_open_input() 函数打开要解封装的音视频文件,该函数返回一个 AVFormatContext 结构体指针,该指针包含了输入文件的相关信息。 2. 寻找音视频流 使用 FFmpeg 的 avformat_find_stream_info() 函数读取输入文件的文件头信息,并寻找其中包含的音视频流。该函数会将每个音视频流的信息保存在 AVStream 结构体中。 3. 选择音视频流 根据需要播放的音视频流类型,在所有寻找到的音视频流中选择对应的流。可以通过判断 AVStream 结构体中的 codecpar->codec_type 来确定该流是音频流还是视频流。 4. 获取解码器 使用 FFmpeg 的 avcodec_find_decoder() 函数获取对应的解码器,并使用 avcodec_open2() 函数打开解码器。 5. 循环读取数据包 使用 FFmpeg 的 av_read_frame() 函数循环读取音视频数据包(AVPacket 结构体),并将数据包送到解码器进行解码。 6. 关闭解码器和输入文件 在播放完成后,需要使用 avcodec_free_context() 函数释放解码器占用的资源,并使用 avformat_close_input() 函数关闭输入文件。 以上就是基于 FFmpeg 进行解封装的大致步骤。当然,在实际开发中还有很多细节需要注意,比如错误处理、内存管理等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值