Android RTMP直播(续二)

/

软硬件环境

  • ubuntu 16.04
  • Android Studio 2.1.3
  • OTT BOx with android 5.1.1
  • nginx 1.11.3
  • nginx-rtmp-module
  • VLC

前言

Android RTMP直播(续)介绍了HLS协议相关的基础内容,本文将继续深入学习HLS的其它高级特性.

服务端多码率支持

nginx.conf
  1. #user nobody;
  2. worker_processes auto;
  3. rtmp_auto_push on;
  4. error_log logs/error.log;
  5. error_log logs/error.log notice;
  6. error_log logs/error.log info;
  7. #pid logs/nginx.pid;
  8. events {
  9. worker_connections 1024;
  10. }
  11. rtmp {
  12. server {
  13. listen 1935;
  14. chunk_size 4000;
  15. # TV mode: one publisher, many subscribers
  16. #application mytv {
  17. # enable live streaming
  18. #live on;
  19. # record first 1K of stream
  20. #record all;
  21. #record_path /tmp/av;
  22. #record_max_size 1K;
  23. # append current timestamp to each flv
  24. #record_unique on;
  25. # publish only from localhost
  26. #allow publish 127.0.0.1;
  27. #deny publish all;
  28. #allow play all;
  29. #}
  30. # Transcoding (ffmpeg needed)
  31. #application big {
  32. # live on;
  33. # On every pusblished stream run this command (ffmpeg)
  34. # with substitutions: $app/${app}, $name/${name} for application & stream name.
  35. #
  36. # This ffmpeg call receives stream from this application &
  37. # reduces the resolution down to 32x32. The stream is the published to
  38. # 'small' application (see below) under the same name.
  39. #
  40. # ffmpeg can do anything with the stream like video/audio
  41. # transcoding, resizing, altering container/codec params etc
  42. #
  43. # Multiple exec lines can be specified.
  44. # exec ffmpeg -re -i rtmp://localhost:1935/$app/$name -vcodec flv -acodec copy -s 32x32
  45. #-f flv rtmp://localhost:1935/small/${name};
  46. #}
  47. #application small {
  48. # live on;
  49. # # Video with reduced resolution comes here from ffmpeg
  50. #}
  51. #application webcam {
  52. # live on;
  53. # Stream from local webcam
  54. # exec_static ffmpeg -f video4linux2 -i /dev/video0 -c:v libx264 -an
  55. #-f flv rtmp://localhost:1935/webcam/mystream;
  56. #}
  57. # application mypush {
  58. # live on;
  59. # Every stream published here
  60. # is automatically pushed to
  61. # these two machines
  62. #push rtmp1.example.com;
  63. #push rtmp2.example.com:1934;
  64. # }
  65. # application mypull {
  66. # live on;
  67. # Pull all streams from remote machine
  68. # and play locally
  69. #pull rtmp://rtmp3.example.com pageUrl=www.example.com/index.html;
  70. # }
  71. # application mystaticpull {
  72. # live on;
  73. # Static pull is started at nginx start
  74. #pull rtmp://rtmp4.example.com pageUrl=www.example.com/index.html name=mystream static;
  75. # }
  76. # video on demand
  77. # application vod {
  78. # play /opt/www/vod;
  79. # }
  80. # application vod2 {
  81. # play /var/mp4s;
  82. # }
  83. # Many publishers, many subscribers
  84. # no checks, no recording
  85. #application videochat {
  86. # live on;
  87. # The following notifications receive all
  88. # the session variables as well as
  89. # particular call arguments in HTTP POST
  90. # request
  91. # Make HTTP request & use HTTP retcode
  92. # to decide whether to allow publishing
  93. # from this connection or not
  94. # on_publish http://localhost:8080/publish;
  95. # Same with playing
  96. # on_play http://localhost:8080/play;
  97. # Publish/play end (repeats on disconnect)
  98. # on_done http://localhost:8080/done;
  99. # All above mentioned notifications receive
  100. # standard connect() arguments as well as
  101. # play/publish ones. If any arguments are sent
  102. # with GET-style syntax to play & publish
  103. # these are also included.
  104. # Example URL:
  105. # rtmp://localhost/myapp/mystream?a=b&c=d
  106. # record 10 video keyframes (no audio) every 2 minutes
  107. # record keyframes;
  108. # record_path /tmp/vc;
  109. # record_max_frames 10;
  110. # record_interval 2m;
  111. # Async notify about an flv recorded
  112. # on_record_done http://localhost:8080/record_done;
  113. #}
  114. # HLS
  115. # For HLS to work please create a directory in tmpfs (/tmp/hls here)
  116. # for the fragments. The directory contents is served via HTTP (see
  117. # http{} section in config)
  118. #
  119. # Incoming stream must be in H264/AAC. For iPhones use baseline H264
  120. # profile (see ffmpeg example).
  121. # This example creates RTMP stream from movie ready for HLS:
  122. #
  123. # ffmpeg -loglevel verbose -re -i movie.avi -vcodec libx264
  124. # -vprofile baseline -acodec libmp3lame -ar 44100 -ac 1
  125. # -f flv rtmp://localhost:1935/hls/movie
  126. #
  127. # If you need to transcode live stream use 'exec' feature.
  128. #
  129. application hls {
  130. live on;
  131. hls on;
  132. hls_path /opt/www/live;
  133. hls_nested on;
  134. hls_variant _low BANDWIDTH=800000;
  135. hls_variant _mid BANDWIDTH=1200000;
  136. hls_variant _hi BANDWIDTH=2000000;
  137. }
  138. # MPEG-DASH is similar to HLS
  139. #application dash {
  140. # live on;
  141. # dash on;
  142. # dash_path /tmp/dash;
  143. #}
  144. }
  145. }
  146. # HTTP can be used for accessing RTMP stats
  147. http {
  148. server {
  149. listen 8081;
  150. location / {
  151. root /opt/www/;
  152. }
  153. # This URL provides RTMP statistics in XML
  154. location /stat {
  155. rtmp_stat all;
  156. # Use this stylesheet to view XML as web page
  157. # in browser
  158. rtmp_stat_stylesheet stat.xsl;
  159. }
  160. location /stat.xsl {
  161. # XML stylesheet to view RTMP stats.
  162. # Copy stat.xsl wherever you want
  163. # and put the full directory path here
  164. root /home/djstava/Workshop/Web/nginx-rtmp-module/;
  165. }
  166. location /hls {
  167. # Serve HLS fragments
  168. types {
  169. application/vnd.apple.mpegurl m3u8;
  170. video/mp2t ts;
  171. }
  172. root /opt/www/;
  173. add_header Cache-Control no-cache;
  174. }
  175. #location /dash {
  176. # Serve DASH fragments
  177. # root /tmp;
  178. # add_header Cache-Control no-cache;
  179. #}
  180. }
  181. }

主要看看application hls的内容

  1. application hls {
  2. live on;
  3. hls on;
  4. hls_path /opt/www/live;
  5. hls_nested on;
  6. hls_variant _low BANDWIDTH=800000;
  7. hls_variant _mid BANDWIDTH=1200000;
  8. hls_variant _hi BANDWIDTH=2000000;
  9. }

这里设定当带宽分别为800k 1200k 2000k的时候,终端都播放相对应的m3u8索引文件

ffmpeg推流

这里需要利用ffmpeg推送3路不同的流,对应上面提到的低 中 高

  1. ffmpeg -re -i ~/Videos/xjcy.mp4 -vcodec copy -acodec copy -b:v 800k -b:a 32k -f flv rtmp://10.10.10.59/hls/livestream_low
  1. ffmpeg -re -i ~/Videos/xjcy.mp4 -vcodec copy -acodec copy -b:v 1200k -b:a 64k -f flv rtmp://10.10.10.59/hls/livestream_mid
  1. ffmpeg -re -i ~/Videos/xjcy.mp4 -vcodec copy -acodec copy -b:v 2000k -b:a 128k -f flv rtmp://10.10.10.59/hls/livestream_hi

推送开始后,hls的root目录下就会生成相应的文件内容,如下图所示

nginx_ffmpeg_variant

此时livestream.m3u8文件内容为

  1. #EXTM3U
  2. #EXT-X-VERSION:3
  3. #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=800000
  4. livestream_low/index.m3u8
  5. #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1200000
  6. livestream_mid/index.m3u8
  7. #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2000000
  8. livestream_hi/index.m3u8

相应的,播放链接为 http://10.10.10.59:8081/live/livestream.m3u8,播放器需要做的就是根据自身的网络状况,切换到其它的索引文件.

直播节目的录制

直播进行的同时一般都会有本地录制的需求,nginx-rtmp-module提供了这个功能,接下来实践一下.还是看nginx.conf配置文件

  1. application hls {
  2. live on;
  3. hls on;
  4. hls_path /opt/www/live;
  5. hls_nested on;
  6. hls_variant _low BANDWIDTH=800000;
  7. hls_variant _mid BANDWIDTH=1200000;
  8. hls_variant _hi BANDWIDTH=2000000;
  9. recorder all {
  10. record all;
  11. record_suffix -%Y-%m-%d-%H_%M_%S.flv;
  12. record_max_size 200000K;
  13. record_path /opt/www/record;
  14. }
  15. }

record all录制所有内容,也可以只录音频或者视频.

推流后/opt/www/record路径下就会自动生成带对应时间戳的flv文件,用vlc测试播放OK.

nginx_ffmpeg_record

时移电视

要想实现时移电视(这里指的是服务器端)的话,首先需要在服务器上保留足够的切片文件,比如说你提供1小时的时移,就意味着要有1小时的切片文件,而且索引文件中包含前1小时的切片序列.

  1. application hls {
  2. live on;
  3. hls on;
  4. hls_path /opt/www/live;
  5. hls_continuous on;
  6. hls_sync 100ms;
  7. hls_nested on;
  8. hls_playlist_length 5m;
  9. hls_fragment 10s;
  10. hls_variant _low BANDWIDTH=800000;
  11. hls_variant _mid BANDWIDTH=1200000;
  12. hls_variant _hi BANDWIDTH=2000000;
  13. #exec /home/djstava/Workshop/Web/nginx-1.11.3/build/test.sh;
  14. #exec_kill_signal term;
  15. #recorder all {
  16. # record all;
  17. # record_suffix -%Y-%m-%d-%H_%M_%S.flv;
  18. # record_max_size 6200000K;
  19. # record_path /opt/www/record;
  20. #}
  21. }

hls_fragment指的是切片文件的长度,这里是10秒,hls_playlist_length指的是索引文件的长度,我这里设的是5分钟.推流开始后,你到切片生成的目录,会发现*.m3u8文件包含了30个ts序列.所以,在上面这种情况下,就只能进行5分钟的时移,当播放进度到达当前直播点时则继续回到直播状态.

执行外部shell脚本

比如有个脚本test.sh,内容如下

  1. #!/bin/bash
  2. on_die ()
  3. {
  4. # kill all children
  5. pkill -KILL -P $$
  6. }
  7. trap 'on_die' TERM
  8. ffmpeg -re -i /home/djstava/Videos/ygdx.mp4 -vcodec copy -acodec copy -f flv rtmp://10.10.10.48/hls/ygdx &
  9. wait

我这里把它放在hls application中执行,则nginx.conf应如下

  1. application hls {
  2. live on;
  3. hls on;
  4. hls_path /opt/www/live;
  5. hls_continuous on;
  6. hls_sync 100ms;
  7. hls_nested on;
  8. hls_playlist_length 5m;
  9. hls_fragment 10s;
  10. hls_variant _low BANDWIDTH=800000;
  11. hls_variant _mid BANDWIDTH=1200000;
  12. hls_variant _hi BANDWIDTH=2000000;
  13. exec /home/djstava/Workshop/Web/nginx-1.11.3/build/test.sh;
  14. exec_kill_signal term;
  15. #recorder all {
  16. # record all;
  17. # record_suffix -%Y-%m-%d-%H_%M_%S.flv;
  18. # record_max_size 6200000K;
  19. # record_path /opt/www/record;
  20. #}
  21. }

当hls服务正常启动时(如上面写过的ffmpeg推流动作),外部脚本test.sh也被执行了.脚本中捕捉了退出的中断信号,也就说,如果ffmpeg推流动作中断了,那么test.sh脚本也就不再执行了.

制作RAMDISK

为了提高HLS的读写效率,可以把切片和索引文件操作放在内存中进行.

  1. mount -t tmpfs -o size=512m tmpfs /opt/www/live

参考文献

1 https://github.com/arut/nginx-rtmp-module/wiki/Directives

转载请注明作者和出处,并添加本页链接。
原文链接:http://xugaoxiang.com/post/96

给我留言