android平臺,FFMPEG轉碼加速(一)-X264
一:開啟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
二:開啟編碼多執行緒
在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的執行狀態,執行緒函式執行的時間
執行緒間等待的情況
可以看出執行緒間的並行度還不是很完全,所以如何針對特定的硬體環境,設計演算法調節執行緒之間編碼的相關性也是一門很深的學問(以後有機會再討論)。
以上就是軟轉碼加速的大概情況。
本文版權歸作者所有,歡迎轉載,但需在文章頁面明顯位置給出原文連線。