NDK--Android Studio中直播推流框架的搭建

上次我們搭建了nginx流媒體服務器,接下來就是研究安卓端是如何直播推流到nginx服務器,之前我們了解到視頻流和音頻流,那么直播也必然繞不開這兩個流,手機端的直播可想而知,視頻流使用攝像頭獲取,音頻流使用麥克風獲取。然而攝像頭和麥克風直接獲取的裸數(shù)據(jù)的體積實在是太大了,如果要想進行網(wǎng)絡傳輸,必須進行壓縮,即編碼

一、視頻編碼:使用h264

h264是目前使用最廣泛的視頻編碼,由于高壓縮比、高圖像質量等優(yōu)勢,使得其在具有高壓縮比的同時還擁有高質量流暢的圖像,在網(wǎng)絡傳輸過程中所需要的帶寬更少,也更加經濟
編碼規(guī)則--h264擁有一套獨特的編碼
1.I幀 幀內編碼幀

可以理解為這一幀畫面的完整保留(實際是進行了切片和壓縮);解碼時只需要本幀數(shù)據(jù)就可以完成(因為包含完整畫面)

I幀特點:
JPEG壓縮編碼
它是一個全幀壓縮編碼幀。它將全幀圖像信息進行JPEG壓縮編碼及傳輸;  
解碼時僅用I幀的數(shù)據(jù)就可重構完整圖像; 
I幀描述了圖像背景和運動主體的詳情;
I幀是P幀和B幀的參考幀(其質量直接影響到同組中以后各幀的質量);
I幀是幀組GOP的基礎幀(第一幀),在一組中只有一個I幀
I幀不需要考慮運動矢量;
I幀所占數(shù)據(jù)的信息量比較大。
2.P幀 前向預測編碼幀

以I幀為參考幀,在I幀中找出P幀“某點”的預測值和運動矢量, 取預測差值和運動矢量一起傳送。在接收端根據(jù)運動矢量從I幀中找出P幀“某點”的預測值并與差值相加以得到P幀“某點”樣值,從而可得到完整的P幀。

P幀特點:
P幀是I幀后面相隔1~2幀的編碼幀;
P幀采用運動補償?shù)姆椒▊魉退c前面的I或P幀的差值及運動矢量(預測誤差);
解碼時必須將I幀中的預測值與預測誤差求和后才能重構完整的P幀圖像;
P幀屬于前向預測的幀間編碼。它只參考前面最靠近它的I幀或P幀;
由于P幀是參考幀,它可能造成解碼錯誤的擴散;
由于是差值傳送,P幀的壓縮比較高
3.B幀 雙向預測內插編碼幀

B幀記錄的是本幀(I幀或P幀)與前后幀(P幀)的差別(具體比較復雜,有4種情況,要解碼B幀,不僅要取得之前的緩存畫面(I幀或P幀),還要解碼之后的畫面(P幀),通過前后畫面的與本幀數(shù)據(jù)的疊加取得最終的畫面。B幀壓縮率高,但是解碼時CPU會比較累。

B幀特點
B幀是由前面的I或P幀和后面的P幀來進行預測的;
B幀傳送的是它與前面的I或P幀和后面的P幀之間的預測誤差及運動矢量;
B幀是雙向預測編碼幀;
B幀壓縮比最高,因為它只反映丙參考幀間運動主體的變化情況,預測比較準確;
B幀不是參考幀,不會造成解碼錯誤的擴散
I、B、P各幀是根據(jù)壓縮算法的需要,是人為定義的,它們都是實實在在的物理幀。一般來說,I幀的壓縮率是7(跟JPG差不多),P幀是20,B幀可以達到50??梢娛褂肂幀能節(jié)省大量空間,節(jié)省出來的空間可以用來保存多一些I幀,這樣在相同碼率下,可以提供更好的畫質。
4.宏塊(對一幀畫面進行切片后,片中包含的數(shù)據(jù))是視頻信息的主要承載者,因為它包含著每一個像素的亮度和色度信息。視頻解碼最主要的工作則是提供高效的方式從碼流中獲得宏塊中的像素陣列。組成部分:一個宏塊由一個16×16亮度像素和附加的一個8×8 Cb和一個 8×8 Cr 彩色像素塊組成 。每個圖象中,若干宏塊被排列成片的形式。
I幀、P幀、B幀的概念比較抽象,可以用下面的列子作為理解
一個蘋果在屏幕中間做自由落體運動,在中間時的畫面如下:
這個畫面是運動的起始點,可以把它當作I幀。另一個畫面是蘋果落到屏幕下邊緣時,如下圖:
這是蘋果運動過程中,我們某個時間點記錄的畫面,可以把它當作P幀,而I幀和P幀中間過程的畫面,我們把它們成為B幀,由于B幀不存在真正的畫面,只有以前一畫面(I幀或P幀,P幀也有畫面信息)和后一畫面(P幀)模擬,進行畫面的預測,所以B幀所含的數(shù)據(jù)量很小,但是B幀越多,預測也就越多,會導致運動的不準確性,可以理解為B幀會使得這運動變?yōu)閯蛩龠\動,很顯然上面兩張圖中間的速度并不是勻速的,所以P幀特點中有一項為:P幀是I幀后面相隔1~2幀的編碼幀,即B幀在兩個畫面幀之間(I幀和P幀之間,P幀和P幀之間)只有1 ~ 2幀或沒有。

我們對裸數(shù)據(jù)進行h264編碼需要用到一個工具x264,接下來介紹如何編譯它

1.首先下載x264

網(wǎng)址:https://www.videolan.org/developers/x264.html
可以用git,也可以直接下載后上傳到服務器

直接下載下來的文件是bz2文件,需要使用bzip2,執(zhí)行以下命令安裝bzip2
yum -y install bzip2.x86_64
執(zhí)行解壓命令
tar xvfj x264-master.tar.bz2 
解壓完畢后的文件內容如下
在該目錄下,編寫以下shell腳本,需要使用ndk下的編譯器編譯,ndk的安裝可以參考我以前的文章:http://www.itdecent.cn/p/5850b1f0e024
#!/bin/bash
#改為自己對應的ndk目錄
NDK_ROOT=/lib/ndk/android-ndk-r14b
SYSROOT=$NDK_ROOT/platforms/android-9/arch-arm/
TOOLCHAIN=$NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
function build_one
{
 ./configure \
        --prefix=$PREFIX \
        --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
        --sysroot=$SYSROOT \
        --host=arm-linux \
        --enable-pic \
        --enable-static \
        --disable-asm \
        --disable-shared \
        --disable-cli
        make clean
        make
        make install
}
CPU=arm
PREFIX=$(pwd)/android/$CPU
build_one
給shell腳本執(zhí)行權限后,執(zhí)行該腳本
等待編譯結束
將include和lib拷貝出來,以備待會放入as工程中

二、音頻編碼:使用aac

使用FAAC編碼工具,同樣的要編譯它

官網(wǎng):http://faac.sourceforge.net/

下載后在Linux中解壓
在該目錄下,編寫以下shell腳本,同樣需要使用ndk中的編譯器
#!/bin/sh

CPU=$1
NDK_ROOT=/lib/ndk/android-ndk-r14b
export PLATFORM=$NDK_ROOT/platforms/android-9/arch-arm
export PREBUILT=$NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin
export PREFIX="$(pwd)/android/arm"
export CROSS_COMPILE=$PREBUILT/arm-linux-androideabi-

export CFLAGS="-DANDROID -fPIC -ffunction-sections -funwind-tables -fstack-protector -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -fomit-frame-pointer -fstrict-aliasing -funswitch-loops -finline-limit=300"

export CPPFLAGS="$CFLAGS"
export CFLAGS="$CFLAGS"
export CXXFLAGS="$CFLAGS"
export CXX="${CROSS_COMPILE}g++ --sysroot=${PLATFORM}"
export LDFLAGS="$LDFLAGS"
export CC="${CROSS_COMPILE}gcc --sysroot=${PLATFORM}"
export NM="${CROSS_COMPILE}nm"
export STRIP="${CROSS_COMPILE}strip"
export RANLIB="${CROSS_COMPILE}ranlib"
export AR="${CROSS_COMPILE}ar"

mkdir -p ./android/arm/include
mkdir -p ./android/arm/lib

./configure --program-prefix=$PREFIX --without-mp4v2 --host=arm-linux

make
cp ./libfaac/.libs/*.a $PREFIX/lib
cp ./libfaac/.libs/*.so $PREFIX/lib
cp ./include/*.h $PREFIX/include
賦予shell腳本執(zhí)行權限后執(zhí)行,將生成的include和lib拷貝出來,以備待會放入as工程中

三、推流:使用rtmpdump

官網(wǎng)地址:http://rtmpdump.mplayerhq.hu/

從官網(wǎng)下載下來后解壓(不要下windows和android的,android中只有so文件,如果要使用,需要將頭文件導入as工程)
一會我們將該目錄下的librtmp文件夾復制到as工程中,使用cmake編譯它

四、創(chuàng)建AS工程:集成各個工具

1.創(chuàng)建ndk工程,在manifest中賦予權限
    <uses-permission android:name="android.permission.INTERNET"/>
    <!--錄音權限-->
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <!--攝像頭權限-->
    <uses-permission android:name="android.permission.CAMERA"/>
2.將faac和x264中的頭文件和靜態(tài)庫復制進工程中:
在CMakeLists中導入它們
cmake_minimum_required(VERSION 3.4.1)
#將libs的路徑設置到變量中
set(lib_dir ${CMAKE_SOURCE_DIR}/../../../libs)

#include頭文件
include_directories(${CMAKE_SOURCE_DIR}/../../../libs/include)

#x264
add_library(
        x264
        STATIC
        IMPORTED)

SET_TARGET_PROPERTIES(
        x264
        PROPERTIES IMPORTED_LOCATION
        ${lib_dir}/lib/libx264.a)

#faac
add_library(
        faac
        STATIC
        IMPORTED)

SET_TARGET_PROPERTIES(
        faac
        PROPERTIES IMPORTED_LOCATION
        ${lib_dir}/lib/libfaac.a)

add_library(
        native-lib

        SHARED

        native-lib.cpp)

find_library(
        log-lib

        log)


target_link_libraries(
        native-lib
        x264
        faac
        ${log-lib})
在gradle的defaultConfig中配置只編譯armeabi平臺,其他平臺需要重新使用ndk中的相應編譯器編譯
        ndk {
            abiFilters "armeabi"
        }
3.復制rtmpdump到工程下:
在librtmp中創(chuàng)建新的CMakeLists.txt,內容如下:
#編譯時關閉openssl
#編譯時關閉openssl
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_CRYPTO")
file(GLOB rtmp_source *.c)

add_library(
        rtmp
        STATIC
        ${rtmp_source})

在主CMakeLists.txt中導入上面cmake生成的靜態(tài)庫
...

#引入rtmp的靜態(tài)庫
add_subdirectory(${CMAKE_SOURCE_DIR}/librtmp)

...

target_link_libraries(
        native-lib
        x264
        faac
        rtmp
        ${log-lib})
build順利通過,至此,集成第三方庫的準備工作就結束了,下一篇文章就開始編寫代碼
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 基本原理 通過手機的攝像頭(Camera)進行視頻采集,音頻采集(AudioRecord)后通過x264進行視頻編...
    czins閱讀 3,103評論 0 2
  • 1 前言 1.1 總覽 短文將記錄一個基本的攝像頭直播APP開發(fā)的全部流程和技術點。項目使用x264進行視頻數(shù)據(jù)處...
    zhx喜籽閱讀 1,500評論 0 1
  • 該工程目錄是Android客戶端推流環(huán)境搭建的工程基礎下創(chuàng)建的(音頻相關的類AudioChannel先不做): 視...
    CoderYuZ閱讀 9,882評論 3 21
  • 久違的晴天,家長會。 家長大會開好到教室時,離放學已經沒多少時間了。班主任說已經安排了三個家長分享經驗。 放學鈴聲...
    飄雪兒5閱讀 7,788評論 16 22
  • 今天感恩節(jié)哎,感謝一直在我身邊的親朋好友。感恩相遇!感恩不離不棄。 中午開了第一次的黨會,身份的轉變要...
    余生動聽閱讀 10,798評論 0 11

友情鏈接更多精彩內容