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

上次我们搭建了nginx流媒体服务器,接下来就是研究安卓端是如何直播推流到nginx服务器,之前我们了解到视频流和音频流,那么直播也必然绕不开这两个流,手机端的直播可想而知,视频流使用摄像头获取,音频流使用麦克风获取。然而摄像头和麦克风直接获取的裸数据的体积实在是太大了,如果要想进行网络传输,必须进行压缩,即编码

一、视频编码:使用h264

h264是目前使用最广泛的视频编码,由于高压缩比、高图像质量等优势,使得其在具有高压缩比的同时还拥有高质量流畅的图像,在网络传输过程中所需要的带宽更少,也更加经济
编码规则--h264拥有一套独特的编码
1.I帧 帧内编码帧

可以理解为这一帧画面的完整保留(实际是进行了切片和压缩);解码时只需要本帧数据就可以完成(因为包含完整画面)

I帧特点:
JPEG压缩编码
它是一个全帧压缩编码帧。它将全帧图像信息进行JPEG压缩编码及传输;  
解码时仅用I帧的数据就可重构完整图像; 
I帧描述了图像背景和运动主体的详情;
I帧是P帧和B帧的参考帧(其质量直接影响到同组中以后各帧的质量);
I帧是帧组GOP的基础帧(第一帧),在一组中只有一个I帧
I帧不需要考虑运动矢量;
I帧所占数据的信息量比较大。
2.P帧 前向预测编码帧

以I帧为参考帧,在I帧中找出P帧“某点”的预测值和运动矢量, 取预测差值和运动矢量一起传送。在接收端根据运动矢量从I帧中找出P帧“某点”的预测值并与差值相加以得到P帧“某点”样值,从而可得到完整的P帧。

P帧特点:
P帧是I帧后面相隔1~2帧的编码帧;
P帧采用运动补偿的方法传送它与前面的I或P帧的差值及运动矢量(预测误差);
解码时必须将I帧中的预测值与预测误差求和后才能重构完整的P帧图像;
P帧属于前向预测的帧间编码。它只参考前面最靠近它的I帧或P帧;
由于P帧是参考帧,它可能造成解码错误的扩散;
由于是差值传送,P帧的压缩比较高
3.B帧 双向预测内插编码帧

B帧记录的是本帧(I帧或P帧)与前后帧(P帧)的差别(具体比较复杂,有4种情况,要解码B帧,不仅要取得之前的缓存画面(I帧或P帧),还要解码之后的画面(P帧),通过前后画面的与本帧数据的叠加取得最终的画面。B帧压缩率高,但是解码时CPU会比较累。

B帧特点
B帧是由前面的I或P帧和后面的P帧来进行预测的;
B帧传送的是它与前面的I或P帧和后面的P帧之间的预测误差及运动矢量;
B帧是双向预测编码帧;
B帧压缩比最高,因为它只反映丙参考帧间运动主体的变化情况,预测比较准确;
B帧不是参考帧,不会造成解码错误的扩散
I、B、P各帧是根据压缩算法的需要,是人为定义的,它们都是实实在在的物理帧。一般来说,I帧的压缩率是7(跟JPG差不多),P帧是20,B帧可以达到50。可见使用B帧能节省大量空间,节省出来的空间可以用来保存多一些I帧,这样在相同码率下,可以提供更好的画质。
4.宏块(对一帧画面进行切片后,片中包含的数据)是视频信息的主要承载者,因为它包含着每一个像素的亮度和色度信息。视频解码最主要的工作则是提供高效的方式从码流中获得宏块中的像素阵列。组成部分:一个宏块由一个16×16亮度像素和附加的一个8×8 Cb和一个 8×8 Cr 彩色像素块组成 。每个图象中,若干宏块被排列成片的形式。
I帧、P帧、B帧的概念比较抽象,可以用下面的列子作为理解
一个苹果在屏幕中间做自由落体运动,在中间时的画面如下:
这个画面是运动的起始点,可以把它当作I帧。另一个画面是苹果落到屏幕下边缘时,如下图:
这是苹果运动过程中,我们某个时间点记录的画面,可以把它当作P帧,而I帧和P帧中间过程的画面,我们把它们成为B帧,由于B帧不存在真正的画面,只有以前一画面(I帧或P帧,P帧也有画面信息)和后一画面(P帧)模拟,进行画面的预测,所以B帧所含的数据量很小,但是B帧越多,预测也就越多,会导致运动的不准确性,可以理解为B帧会使得这运动变为匀速运动,很显然上面两张图中间的速度并不是匀速的,所以P帧特点中有一项为:P帧是I帧后面相隔1~2帧的编码帧,即B帧在两个画面帧之间(I帧和P帧之间,P帧和P帧之间)只有1 ~ 2帧或没有。

我们对裸数据进行h264编码需要用到一个工具x264,接下来介绍如何编译它

1.首先下载x264

网址:https://www.videolan.org/developers/x264.html
可以用git,也可以直接下载后上传到服务器

直接下载下来的文件是bz2文件,需要使用bzip2,执行以下命令安装bzip2
yum -y install bzip2.x86_64
执行解压命令
tar xvfj x264-master.tar.bz2 
解压完毕后的文件内容如下
在该目录下,编写以下shell脚本,需要使用ndk下的编译器编译,ndk的安装可以参考我以前的文章://www.greatytc.com/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脚本执行权限后,执行该脚本
等待编译结束
将include和lib拷贝出来,以备待会放入as工程中

二、音频编码:使用aac

使用FAAC编码工具,同样的要编译它

官网: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脚本执行权限后执行,将生成的include和lib拷贝出来,以备待会放入as工程中

三、推流:使用rtmpdump

官网地址:http://rtmpdump.mplayerhq.hu/

从官网下载下来后解压(不要下windows和android的,android中只有so文件,如果要使用,需要将头文件导入as工程)
一会我们将该目录下的librtmp文件夹复制到as工程中,使用cmake编译它

四、创建AS工程:集成各个工具

1.创建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中的头文件和静态库复制进工程中:
在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中创建新的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生成的静态库
...

#引入rtmp的静态库
add_subdirectory(${CMAKE_SOURCE_DIR}/librtmp)

...

target_link_libraries(
        native-lib
        x264
        faac
        rtmp
        ${log-lib})
build顺利通过,至此,集成第三方库的准备工作就结束了,下一篇文章就开始编写代码
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容

  • 基本原理 通过手机的摄像头(Camera)进行视频采集,音频采集(AudioRecord)后通过x264进行视频编...
    czins阅读 2,944评论 0 2
  • 1 前言 1.1 总览 短文将记录一个基本的摄像头直播APP开发的全部流程和技术点。项目使用x264进行视频数据处...
    zhx喜籽阅读 1,331评论 0 1
  • 该工程目录是Android客户端推流环境搭建的工程基础下创建的(音频相关的类AudioChannel先不做): 视...
    CoderYuZ阅读 9,588评论 3 21
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,521评论 16 22
  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    迷月闪星情阅读 10,562评论 0 11