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

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

一、視頻編碼:使用h264

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

可以理解為這一幀畫面的完整保留(實(shí)際是進(jìn)行了切片和壓縮);解碼時只需要本幀數(shù)據(jù)就可以完成(因?yàn)榘暾嬅妫?/p>

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

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

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

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

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

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

1.首先下載x264

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

直接下載下來的文件是bz2文件,需要使用bzip2,執(zhí)行以下命令安裝bzip2
yum -y install bzip2.x86_64
執(zhí)行解壓命令
tar xvfj x264-master.tar.bz2 
解壓完畢后的文件內(nèi)容如下
在該目錄下,編寫以下shell腳本,需要使用ndk下的編譯器編譯,ndk的安裝可以參考我以前的文章:http://www.lxweimin.com/p/5850b1f0e024
#!/bin/bash
#改為自己對應(yīng)的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í)行權(quán)限后,執(zhí)行該腳本
等待編譯結(jié)束
將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í)行權(quán)限后執(zhí)行,將生成的include和lib拷貝出來,以備待會放入as工程中

三、推流:使用rtmpdump

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

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

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

1.創(chuàng)建ndk工程,在manifest中賦予權(quán)限
    <uses-permission android:name="android.permission.INTERNET"/>
    <!--錄音權(quán)限-->
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <!--攝像頭權(quán)限-->
    <uses-permission android:name="android.permission.CAMERA"/>
2.將faac和x264中的頭文件和靜態(tài)庫復(fù)制進(jìn)工程中:
在CMakeLists中導(dǎo)入它們
cmake_minimum_required(VERSION 3.4.1)
#將libs的路徑設(shè)置到變量中
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中的相應(yīng)編譯器編譯
        ndk {
            abiFilters "armeabi"
        }
3.復(fù)制rtmpdump到工程下:
在librtmp中創(chuàng)建新的CMakeLists.txt,內(nèi)容如下:
#編譯時關(guān)閉openssl
#編譯時關(guān)閉openssl
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_CRYPTO")
file(GLOB rtmp_source *.c)

add_library(
        rtmp
        STATIC
        ${rtmp_source})

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

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

...

target_link_libraries(
        native-lib
        x264
        faac
        rtmp
        ${log-lib})
build順利通過,至此,集成第三方庫的準(zhǔn)備工作就結(jié)束了,下一篇文章就開始編寫代碼
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內(nèi)容

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