一:編碼介紹
軟編碼:使用cpu進(jìn)行編碼。
硬編碼:使用顯卡GPU專用的DSP\FPGA\ASIC芯片等硬件進(jìn)行編碼。
軟編碼的特點(diǎn)是升級(jí)方便,實(shí)現(xiàn)簡單,但是cpu負(fù)載中,性能低。硬編碼性能高。
在H.265之前,H.264一直是新一代的編碼標(biāo)準(zhǔn)。H265主要是用來滿足4
k,8k視頻的需求,H.264以高壓縮高質(zhì)量和支持多種網(wǎng)絡(luò)流媒體傳輸而聞名。經(jīng)過h264標(biāo)準(zhǔn)對視頻進(jìn)行壓縮編碼,能夠有效減小視頻的文件大小,這主要是受益于他的低碼率。與MPEG-2和MPEG-4 ASP等壓縮技術(shù)相比,H.264壓縮技術(shù)節(jié)省來用戶的下載時(shí)間和流量。
H.264只是一個(gè)標(biāo)準(zhǔn),具體實(shí)現(xiàn)包括JM,T264,x264。而由于種種原因,JM,T264等實(shí)現(xiàn)工具,并不能很好地繼續(xù)完成我們的需求,因此x264便成了互聯(lián)網(wǎng)世界中主流的實(shí)現(xiàn)H.264標(biāo)準(zhǔn)的編碼工具。
FFMPEG默認(rèn)只支持對H.264的解碼,并不支持對H.264的編碼,因此就需要我們手動(dòng)配置FFMPEG來實(shí)現(xiàn)對H.264的編碼。首先我們需要下載x264
二:編譯x264
下載完成之后,我們需要首先編譯x264為靜態(tài)庫,這是因?yàn)镕FMPEG默認(rèn)是通過靜態(tài)鏈接方式來鏈接其他功能庫。我們在編譯ffmpeg時(shí),修改了configure文件,這樣方便生成可以讓android識(shí)別的*.so文件,但是我們編譯x264是生成的靜態(tài)庫,因此不需要修改x264的configure文件。下面我們直接放一個(gè)網(wǎng)上的編譯腳本,build_x264_arm.sh:
#!/bin/bash
NDK=/Users/xiaguangcheng/android/android-sdk-macosx/ndk-bundle
SYSROOT=$NDK/platforms/android-18/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
CPU=arm
PREFIX=/Users/xiaguangcheng/x264/arm
ADDI_CFLAGS=""
ADDI_LDFLAGS=""
function build_x264
{
./configure \
--prefix=$PREFIX \
--disable-shared \
--disable-asm \
--enable-static \
--enable-pic \
--enable-strip \
--host=arm-linux-androideabi \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--sysroot=$SYSROOT
--extra-cflags="-Os -fpic $ADDI_CFLAGS $OPTIMIZE_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make -j4
make install
}
build_x264
下面的幾行需要根據(jù)你的電腦來完成配置。同時(shí)在x264文件夾下新建一個(gè)arm的文件夾用來存放編譯之后的文件。
NDK=/Users/xiaguangcheng/android/android-sdk-macosx/ndk-bundle
SYSROOT=$NDK/platforms/android-18/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
CPU=arm
PREFIX=/Users/xiaguangcheng/x264/arm
接著我們通過命令cd x264進(jìn)入到x264文件夾內(nèi),查看新建的build_x264_arm.sh文件的權(quán)限
ls -l build_x264_arm.sh
-rwxrwxrwx 1 xiaguangcheng staff 733 6 26 20:46 build_x264_arm.sh
如果你的該文件不具備可執(zhí)行權(quán)限,那么就需要手動(dòng)添加可執(zhí)行權(quán)限,添加完權(quán)限之后,記得再查看一下是否成功。
chmod 777 build_x264_arm.sh
ls -l build_x264_arm.sh
如果還沒有安裝yasm那么可以通過homebrew安裝
brew install yasm
否則可能會(huì)報(bào)一個(gè)錯(cuò)誤
if you really want to compile without asm, configure with --disable-asm. make: *** [config.mak] Error 1 Makefile:3: config.mak: No such file or directory
接下來我們在命令行中就可以運(yùn)行該文件進(jìn)行編譯
./build_x264_arm.sh
待編譯結(jié)束后,我們在剛剛創(chuàng)建的arm文件夾中的就可以找到一個(gè).a靜態(tài)庫。
三:編譯含有x264靜態(tài)庫的ffmpeg動(dòng)態(tài)庫
在第一篇中我們講解來如何編譯一個(gè)ffmpeg動(dòng)態(tài)庫,但是那個(gè)動(dòng)態(tài)庫并沒有包含x264,這里我們將x264包含進(jìn)來。因此在編譯ffmpeg動(dòng)態(tài)庫的編譯文件基礎(chǔ)之上進(jìn)行略微的修改即可,buildffmpeg.sh文件內(nèi)容更新如下:
#!/bin/bash
export TMPDIR=/Users/xiaguangcheng/ffmpeg/ffmpeg/ffmpegtemp
NDK=/Users/xiaguangcheng/android/android-sdk-macosx/ndk-bundle
SYSROOT=$NDK/platforms/android-18/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
CPU=arm
PREFIX=/Users/xiaguangcheng/ffmpeg/ffmpeg/android
ADDI_CFLAGS="-marm"
function build_one
{
./configure \
--prefix=$PREFIX \
--enable-shared \
--enable-gpl \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-doc \
--disable-symver \
--enable-small \
--enable-gpl \
--enable-libx264 \
--enable-yasm \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--target-os=linux \
--arch=arm \
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="-I/Users/xiaguangcheng/x264/arm/include" \
--extra-ldflags="-L/Users/xiaguangcheng/x264/arm/lib" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
}
build_one
主要修改包括以下幾點(diǎn)
--enable-gpl \
--enable-libx264 \
--enable-yasm \
--extra-cflags="-I/Users/xiaguangcheng/x264/arm/include" \
--extra-ldflags="-L/Users/xiaguangcheng/x264/arm/lib" \
- -I:編譯階段生效的參數(shù),用于指定頭文件的搜索路徑。
- -L:鏈接階段生效的參數(shù),用于指定鏈接庫的搜索路徑,-l用于指定鏈接庫的名稱,一般兩者一起使用的話,就可以指定動(dòng)態(tài)鏈接庫。
查看該文件是否有執(zhí)行權(quán)限,如果有執(zhí)行權(quán)限
./buildffmpeg.sh
運(yùn)行該命令后即可得到最終的包含x264的ffmpeg的so動(dòng)態(tài)庫。我們也可以通過在編譯過程中打印的日志來查看
四:使用包含x264的ffmpeg動(dòng)態(tài)庫在android中壓縮視頻
在android中使用ffmpeg執(zhí)行命令,并通過命令來編碼壓縮視頻,利用FFmpeg玩轉(zhuǎn)Android視頻錄制與壓縮(一),這篇博客已經(jīng)說的差不多了,但是根據(jù)我們項(xiàng)目中上傳視頻的需求,我們還需要獲取在編碼壓縮過程中的進(jìn)度,具體思路是通過process來執(zhí)行命令,而不是通過jni調(diào)用ffmpeg來執(zhí)行命令。而上面提到的這篇博客就是通過jni調(diào)用ffmpeg來執(zhí)行命令的。通過android.jar中的Process來執(zhí)行命令,可以獲取到執(zhí)行命令的結(jié)果,由于在執(zhí)行ffmpeg的過程中,會(huì)出現(xiàn)諸如下面這樣的結(jié)果輸出
frame= 125 fps=0.0 q=38.0 size= 176kB time=00:00:08.54 bitrate= 168.7kbits/frame= 298 fps=297 q=35.0 size= 471kB time=00:00:20.03 bitrate= 192.6kbits/frame= 454 fps=302 q=35.0 size= 727kB time=00:00:30.46 bitrate= 195.4kbits/frame= 662 fps=331 q=33.0 size= 1067kB time=00:00:44.37 bitrate= 197.0kbits/frame= 853 fps=341 q=36.0 size= 1386kB time=00:00:57.05 bitrate= 199.0kbits/frame= 1041 fps=347 q=37.0 size= 1719kB time=00:01:09.56 bitrate= 202.4kbits/frame= 1241 fps=354 q=37.0 size= 2063kB time=00:01:22.91 bitrate= 203.8kbits/frame= 1478 fps=369 q=37.0 size= 2475kB time=00:01:38.73 bitrate= 205.3kbits/frame= 1677 fps=372 q=38.0 size= 2815kB time=00:01:51.96 bitrate= 206.0kbits/frame= 1889 fps=378 q=38.0 size= 3181kB time=00:02:06.13 bitrate= 206.6kbits/frame= 2101 fps=382 q=36.0 size= 3535kB time=00:02:20.29 bitrate= 206.4kbits/frame= 2341 fps=390 q=32.0 size= 3931kB time=00:02:36.22 bitrate= 206.1kbits/frame= 2602 fps=400 q=36.0 size= 4393kB time=00:02:53.63 bitrate= 207.3kbits/frame= 2809 fps=401 q=27.0 size= 4728kB time=00:03:07.47 bitrate= 206.6kbits/frame= 3016 fps=406 q=-1.0 Lsize= 5098kB time=00:03:21.01 bitrate= 207.7kbits/s speed= 27x
那么我們就可以通過先獲取本地視頻的時(shí)長,然后再拿到輸出結(jié)果中的轉(zhuǎn)換時(shí)長來查看編碼進(jìn)度。上面輸出中的size并不是原視頻的size,而是編碼之后的新視頻已經(jīng)生成的size,因此不可以參考。但是我們編碼只是壓縮了大小,并沒有改變時(shí)長,因此時(shí)間可以用來參考
1:獲取本地視頻時(shí)長
Cursor mCursor = mContentResolver.query(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
null, null, null,
MediaStore.MediaColumns.DATE_ADDED + " DESC");
int columnIndex1 = mCursor.getColumnIndex(MediaStore.Video.Media.DURATION);
long millSeconds = mCursor.getLong(columnIndex1);
2:獲取ffmpeg命令輸出結(jié)果
String [] cmd =new String []{"ffmpeg","-i","xiaugangcheng.mp4","xia.mp4"};
Process process = new ProcessBuilder()
.command(cmd)
.redirectErrorStream(true)
.start();
try {
InputStream in = process.getInputStream();
OutputStream out = process.getOutputStream();
readStream(in);
} finally {
process.destroy();
}
3:根據(jù)輸出結(jié)果獲取已轉(zhuǎn)換的視頻時(shí)長
String s=""frame=125 fps=0.0 q=38.0 size=176kB time=01:11:08.54 bitrate= 168.7kbits"";
int index = s.indexOf("time=");
if(index==-1){
return;
}
if(index+5>s.length()||index+13>s.length()){
return;
}
String cmd = s.substring(index+5, index+13);
System.out.println(cmd);
String[] my =cmd.split(":");
int hour =Integer.parseInt(my[0]);
int min =Integer.parseInt(my[1]);
int sec =Integer.parseInt(my[2]);
int totalSec =hour*3600+min*60+sec;
int percent =String totalSec *100/ 202;
progressDialog.setMessage("Processing\n"+percent+"%");
拿到輸入輸出流,就可以轉(zhuǎn)化為string來提取時(shí)間了
文章參考
初識(shí)FFmpeg編譯那些事
Mac下為Android編譯FFMPEG和x264
在Android上使用FFmpeg壓縮視頻
編譯Android下可執(zhí)行命令的FFmpeg