####前言

先来了解一下视频直播的基本架构:

我们需要有一个主播客户端进行音视频采集,压缩,然后通过RTMP协议进行推流,推到流媒体服务器,然后其他客户端统一从流媒体服务器引流,播放。关于这里的过程的一些细节我将会在后续文章中慢慢道来。

####Linux(Ubuntu系统或者虚拟机)搭建流媒体服务器

先来了解一下俄罗斯人开发的Nginx服务器,Nginx ("engine x") 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器。Nginx是由Igor Sysoev为俄罗斯访问量第二的Rambler.ru站点开发的,第一个公开版本0.1.0发布于2004年10月4日。其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。

因为Nginx服务器支持RTMP协议,因此这里我们作为流媒体服务器。

######Tips:实际开发可能是多台服务器,需要高并发架构支持。反向代理:外网的请求先转发到内网,然后返回的时候再转到外网。

Nginx是一种模块化的服务器,开源,我们可以自由添加删除我们自己的模块,不同的模块使用不同的端口号,互不冲突,如下图所示:

一、先下载安装 nginx 和 nginx-rtmp 编译依赖工具。

sudo apt-get install build-essential libpcre3 libpcre3-dev libssl-dev
复制代码

二、创建一个工作目录,并切换到工作目录。

因为后续可能还需要进行编译等操作,最好先给目录递归赋予权限:

mkdir Live
chmod +x -R Live/
复制代码

三、下载 nginx 和 nginx-rtmp源码(wget是一个从网络上自动下载文件的自由工具)

wget http://nginx.org/download/nginx-1.8.1.tar.gz
wget https://github.com/arut/nginx-rtmp-module/archive/master.zip
复制代码

四、解压

如果你用的是Ubuntu系统,直接通过界面操作解压即可。

安装unzip工具,解压下载的安装包 sudo apt-get install unzip

5.解压 nginx 和 nginx-rtmp安装包

tar -zxvf nginx-1.8.1.tar.gz
unzip master.zip
复制代码

其中:

-zxvf分别是四个参数
x : 从 tar 包中把文件提取出来
z : 表示 tar 包是被 gzip 压缩过的,所以解压时需要用 gunzip 解压
v : 显示详细信息
f : xxx.tar.gz :  指定被处理的文件是 xxx.tar.gz
复制代码

五、添加 nginx-rtmp 模板编译到 nginx

切换到 nginx-目录

cd nginx-1.8.1
./configure --with-http_ssl_module --add-module=../nginx-rtmp-module-master
复制代码

六、编译、安装nginx

编译nginx源码
make
安装需要超级权限
sudo make install
复制代码

######Tips:make、安装编译默认就是调用configure脚本进行编译安装,因此安装路径可以在configure找到。编译过程就是先生成目标文件.o,然后进行链接得到可执行程序。安装的过程就是把一些文件复制到系统目录里面去。

七、安装nginx init 脚本

下载init脚本到/etc/init.d/nginx目录中,其中/etc/init.d目录放是Linux进程启动的时候会执行的一些脚本
sudo wget https://raw.github.com/JasonGiedymin/nginx-init-ubuntu/master/nginx -O /etc/init.d/nginx
给目录添加执行权限
sudo chmod +x /etc/init.d/nginx
刷新一下
sudo update-rc.d nginx defaults
复制代码

八、启动和停止nginx 服务,生成配置文件

sudo service nginx start
复制代码

这时候在浏览器输入http://127.0.0.1/,就可以看到页面,证明服务器已经成功安装好了。然后我们停止服务器,进行后续操作。

sudo service nginx stop
复制代码

九、安装 FFmpeg

这里FFmpeg是用于做音视频的编解码的。同时我们测试直播功能的时候,也可以通过ffplay进行测试,ffplay支持RTMP协议。

cd ffmpeg-2.6.9编译FFmpeg
./configure --disable-yasm
安装FFmpeg(这个过程比较久,耐心等待)
sudo make install
复制代码

输入下面的命令测试是否安装好:

输出安装信息
ffmpeg -v
复制代码

######Tips:服务器内存不足需要配置虚拟内存。

十、配置 nginx-rtmp 服务器

Nginx安装在/usr/local/nginx中,其中:

  1. conf是配置目录
  2. html是网页的目录

打开 /usr/local/nginx/conf/nginx.conf

在末尾添加如下配置:

rtmp {server {listen 1935;chunk_size 4096;application live {live on;record off;exec ffmpeg -i rtmp://localhost/live/$name -threads 1 -c:v libx264 -profile:v baseline -b:v 350K -s 640x360 -f flv -c:a aac -ac 1 -strict -2 -b:a 56k rtmp://localhost/live360p/$name;}application live360p {live on;record off;}}
}
复制代码

主要是配置RTMP协议,Nginx是一种模块化的服务器,可以自由添加功能。这里主要是配置RTMP模块的一些参数,包括端口号,视频的编解码参数、格式等等。

保存上面配置文件,然后重新启动nginx服务:

sudo service nginx restart
复制代码

######Tips:Nginx的安装目录可以通过在configure查找“install”关键字找到。 ######这里也可以看到http的配置,默认是80端口,如果有冲突的话,可以修改其他端口。不同功能使用不同端口,互不冲突。 ######如果你使用了防火墙,请允许端口 tcp 1935。

####Windows平台下流媒体服务器搭建

由于Windows平台编译Nginx源码比较麻烦,因此我们用其他人编译好的版本即可,下载地址如下:

https://github.com/illuspas/nginx-rtmp-win32
复制代码

同理,我们需要配置nginx-rtmp-win32\conf\nginx.conf文件,然后点击根目录下面的nginx.exe即可打开服务器。

####流媒体服务器测试

引流有两个方法测试(将来也可以通过手机客户端进行测试):

一、服务器配置测试播放器:将Flash播放器的所有文件复制到目录:/usr/local/nginx/html(Windows是www目录)/,然后修改播放地址

播放器下载地址:

链接:http://pan.baidu.com/s/1bo9ePRp 密码:627r
复制代码

######方法一需要把index.html的推流IP地址改为你自己的

二、用ffplay播放RTMP直播流:

在终端输入一下命令即可:

ffplay rtmp://172.17.120.44/live/test
复制代码

######方法二需要把命令中的推流IP地址改为你自己的,并且最好把FFmpeg添加到环境变量

推流的测试:

目前来说也是有两种方法(将来会添加Android端引流测试):

一、使用之前创建的FFmpeg Visual项目,博客地址:

http://www.jianshu.com/p/5b7c18285667
复制代码

二、使用之前创建的FFmpeg Android Studio项目,相关博客地址:

http://www.jianshu.com/p/91e07b7dc8ca
http://www.jianshu.com/p/da140cffadba
复制代码

其中,核心代码如下:

JNIEXPORT void JNICALL
Java_com_nan_ffmpeg_utils_FFmpegUtils_push(JNIEnv *env, jclass type, jstring input_,jstring output_) {const char *input = (*env)->GetStringUTFChars(env, input_, NULL);const char *output = (*env)->GetStringUTFChars(env, output_, NULL);LOGI("%s\n", input);LOGI("%s\n", output);//变量初始化AVFormatContext *inFmtCtx = NULL, *outFmtCtx = NULL;int ret;//注册组件av_register_all();//初始化网络avformat_network_init();//打开输入文件if ((ret = avformat_open_input(&inFmtCtx, input, 0, 0)) < 0) {LOGE("无法打开文件");goto end;}//获取文件信息if ((ret = avformat_find_stream_info(inFmtCtx, 0)) < 0) {LOGE("无法获取文件信息");goto end;}//输出的封装格式上下文,使用RTMP协议推送flv封装格式的流avformat_alloc_output_context2(&outFmtCtx, NULL, "flv", output); //RTMP//avformat_alloc_output_context2(&ofmt_ctx, NULL, "mpegts", output_str);//UDPint i = 0;for (; i < inFmtCtx->nb_streams; i++) {//根据输入封装格式中的AVStream流,来创建输出封装格式的AVStream流//解码器,解码器上下文都要一致AVStream *in_stream = inFmtCtx->streams[i];AVStream *out_stream = avformat_new_stream(outFmtCtx, in_stream->codec->codec);//复制解码器上下文ret = avcodec_copy_context(out_stream->codec, in_stream->codec);//全局头out_stream->codec->codec_tag = 0;if (outFmtCtx->oformat->flags == AVFMT_GLOBALHEADER) {out_stream->codec->flags = CODEC_FLAG_GLOBAL_HEADER;}}//打开输出的AVIOContext IO流上下文AVOutputFormat *ofmt = outFmtCtx->oformat;if (!(ofmt->flags & AVFMT_NOFILE)) {ret = avio_open(&outFmtCtx->pb, output, AVIO_FLAG_WRITE);}//先写一个头ret = avformat_write_header(outFmtCtx, NULL);if (ret < 0) {LOGE("推流发生错误\n");goto end;}//获取视频流的索引位置int videoindex = -1;for (i = 0; i < inFmtCtx->nb_streams; i++) {if (inFmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {videoindex = i;break;}}int frame_index = 0;int64_t start_time = av_gettime();AVPacket pkt;while (1) {AVStream *in_stream, *out_stream;//读取AVPacketret = av_read_frame(inFmtCtx, &pkt);if (ret < 0)break;//没有封装格式的裸流(例如H.264裸流)是不包含PTS、DTS这些参数的。在发送这种数据的时候,需要自己计算并写入AVPacket的PTS,DTS,duration等参数//PTS:Presentation Time Stamp。PTS主要用于度量解码后的视频帧什么时候被显示出来//DTS:Decode Time Stamp。DTS主要是标识读入内存中的流在什么时候开始送入解码器中进行解码if (pkt.pts == AV_NOPTS_VALUE) {//Write PTSAVRational time_base1 = inFmtCtx->streams[videoindex]->time_base;//Duration between 2 frames (us)int64_t calc_duration =(double) AV_TIME_BASE / av_q2d(inFmtCtx->streams[videoindex]->r_frame_rate);//Parameterspkt.pts = (double) (frame_index * calc_duration) /(double) (av_q2d(time_base1) * AV_TIME_BASE);pkt.dts = pkt.pts;pkt.duration = (double) calc_duration / (double) (av_q2d(time_base1) * AV_TIME_BASE);}if (pkt.stream_index == videoindex) {//FFmpeg处理数据速度很快,瞬间就能把所有的数据发送出去,流媒体服务器是接受不了//这里采用av_usleep()函数休眠的方式来延迟发送,延时时间根据帧率与时间基准计算得到AVRational time_base = inFmtCtx->streams[videoindex]->time_base;AVRational time_base_q = {1, AV_TIME_BASE};int64_t pts_time = av_rescale_q(pkt.dts, time_base, time_base_q);int64_t now_time = av_gettime() - start_time;if (pts_time > now_time) {av_usleep(pts_time - now_time);}}in_stream = inFmtCtx->streams[pkt.stream_index];out_stream = outFmtCtx->streams[pkt.stream_index];/* copy packet *///Convert PTS/DTSpkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base,AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base,AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);pkt.pos = -1;//输出进度if (pkt.stream_index == videoindex) {LOGI("第%d帧", frame_index);frame_index++;}//推送ret = av_interleaved_write_frame(outFmtCtx, &pkt);if (ret < 0) {LOGE("Error muxing packet");break;}av_free_packet(&pkt);}//输出结尾av_write_trailer(outFmtCtx);end://释放资源avformat_free_context(inFmtCtx);avio_close(outFmtCtx->pb);avformat_free_context(outFmtCtx);(*env)->ReleaseStringUTFChars(env, input_, input);(*env)->ReleaseStringUTFChars(env, output_, output);
}
复制代码

注意:

  1. 如果是Android Studio项目进行测试的话,记得添加网络、SDCard访问权限。
  2. 如果是Visual Studio项目测试,只需要把上面的JNI方法修改成main函数即可。
  3. 代码先不作解释。

如果觉得我的文字对你有所帮助的话,欢迎关注我的公众号:

我的群欢迎大家进来探讨各种技术与非技术的话题,有兴趣的朋友们加我私人微信huannan88,我拉你进群交(♂)流(♀)

Android NDK开发之旅34 NDK 手把手带你入门直播技术相关推荐

  1. Android NDK开发之旅1 NDK介绍

    ###一.NDK产生的背景 Android平台从诞生起,就已经支持C.C++开发.众所周知,Android的SDK基于Java实现,这意味着基于Android SDK进行开发的第三方应用都必须使用Ja ...

  2. Android NDK开发之旅25 NDK 模仿QQ变声特效

    ###前言 我们这次用到的是fmod这个库,fmod是音效引擎游戏开发革命引擎,著名的游戏开发引擎CosCos2D.U3D都封装了这个库. 学习NDK的目的就是为了让我们的APP能够使用C/C++开源 ...

  3. Android NDK开发之旅31 FFmpeg音频解码

    ###前言 #####基于Android NDK开发之旅30--FFmpeg视频播放这篇文章,我们已经学会视频解码基本过程.这篇文章就对音频解码进行分析. #####音频解码和视频解码的套路基本是一样 ...

  4. Android NDK开发之旅29 云服务器Ubuntu下搭建NDK环境,并编译FFmpeg

    ###前言 因为在Linux环境下编译FFmpeg生成库和头文件下比较方便,所以接下来主要操作在Linux环境下进行.但是对于Android NDK 开发新手来说,自己电脑配置Ubuntu Linux ...

  5. java 与jni转码,Android NDK开发之旅37--FFmpeg转码压缩

    前言 Windows下命令行转码压缩形式 ffmpeg -i input.mov -b:v 640k output.mp4 Android也是利用FFmpeg命令行的形式(混编),进行视频转码压缩. ...

  6. Android NDK开发之旅14 JNI 缓存策略

    ###缓存策略 有两种: ####一.使用局部的static变量: JNIEXPORT void JNICALL Java_com_test_JniTest_cache (JNIEnv * env, ...

  7. 视频直播系统开发技术真的很难吗?手把手带你实现直播技术

    先来聊聊视频直播系统开发常见的三大协议 国内常见的直播协议有几个:RTMP.HLS.HTTP-FLV,下面我们来一一介绍. RTMP,全称 Real Time Messaging Protocol,即 ...

  8. Android NDK开发之 NEON基础介绍

    原文:http://blog.csdn.net/app_12062011/article/details/50434259 Android NDK开发之 NEON基础介绍 这是官方介绍: http:/ ...

  9. Android开发之旅:组件生命周期(二)

    引言 应用程序组件有一个生命周期--一开始Android实例化他们响应意图,直到结束实例被销毁.在这期间,他们有时候处于激活状态,有时候处于非激活状态:对于活动,对用户有时候可见,有时候不可见.组件生 ...

最新文章

  1. Twitter新计划:审视自家算法里的“无心之失”
  2. C#操作Excel文件(转)
  3. CRC校验原理及STM32 IAP在线升级程序
  4. Metal之探究理解视频渲染RGB与YUV颜色编码
  5. Rustup 管理工具
  6. Win下执行Swing程序的BAT文件 和 Linux下执行Swing程序的SH文件
  7. eclipse clean_Clean Sheet – Windows 10的人体工程学Eclipse主题
  8. c语言逆序输出6A8F,【C语言】将二进制数逆序输出。比如6为000...0110,逆序后为0110....
  9. 计算机里有个不能进入的磁盘分区,新电脑只有一个分区怎么办? 教你们如何不进pe给硬盘创建新分区!...
  10. Elasticsearch7.15.2 基础概念和基础语法
  11. 【数据库题型大总结】名词解释总结
  12. 深入浅出MVC框架模式
  13. arcpy_intersectmerge
  14. GB35114 A级过检
  15. 宁夏诗词学会红寺堡采风专辑
  16. 减号android string,在Android应用软键盘上减号加号登录
  17. flv.js简单使用示例
  18. 【linux内核分析与应用-陈莉君】内核同步措施
  19. 剑指offe JZ18 删除链表的节点
  20. Python制作CSDN数据中心——CSDN机器人访客

热门文章

  1. AngularJs Cookie 的使用
  2. Java Thread类的使用
  3. c++ 对象指针参数和对象引用参数02
  4. 一个超酷的横向多列响应式布局效果
  5. 设计模式- 命令模式
  6. Windows Phone中使用Local DataBase与ISolateStorage—在MVVM模式下(—)
  7. Oracle EM 相关命令
  8. IBM---Java 多线程与并发编程专题
  9. 计算时间差的Oracle函数
  10. 【数字信号处理】傅里叶变换性质 ( 频域函数的共轭对称分解 | 序列的傅里叶变换 | 傅里叶变换的共轭对称 | 傅里叶变换的共轭反对称 )