整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          手把手配置HLS流媒體服務器

          讀本文前,務必先閱讀前面這篇文章,手把手搭建流媒體服務器詳細步驟。因為本篇文章是在這篇文章的基礎上搭建。

          1.HLS簡述

          HLS是Apple 提出的?種基于 HTTP 的協議,HLS(HTTP Live Streaming)?于解決實時?視頻流的傳輸。尤其是在ios移動端,由于 iOS /H5 不?持 flash,使得 HLS 成了ios移動端實時視頻流傳輸的?選。HLS經常?在直播領域,?些國內的直播云通常? HLS 拉流(將視頻流從服務器拉到客戶端)。HLS最大的缺點就是延遲嚴重,延遲通常在10-30s 之間。

          英文本協議地址如下,可以詳細閱讀。

          HLS英文版協議:https://tools.ietf.org/html/draft-pantos-http-live-streaming-06

          協議有如下部分:

          蘋果開發者官網:https://developer.apple.com/streaming/


          2.HLS數據流整體框架

          HLS數據流向的整體框架如下圖所示。其主要分為以下幾步:

          (1)推流端把采集,編碼,封裝的數據數據發送到服務端。

          (2)Stream segmenter是指把碼流分片。對直播或點播流進行分片,分片的數量是固定,每個分片的時長也是固定,如5個分片,每個分片為5s,分片時間沒有辦法精確到毫秒,因為分片一般默認都是從I幀開始,保證一個完整的GOP。如果分配數量為5,那么就是最多緩存5個分片,只會保存最新分片,過時的分片就會刪除。如有當前有1個分片。當第6個分片加進來,則第一個分片就會被刪除。

          (3)index file就是存儲目前的分片信息,如把分片1,分片2寫入index file。如下圖:

          (4)推送給web server,然后存儲ts文件。

          (5)通過HTTP協議讀取服務器文件,先讀取index file,然后解析index file,最后讀取相應的ts文件。服務器就把ts文件送出去,然后 播放。

          (6)因為index file是保存分片信息,分片是實時更新,所以index file也是持續更新。只要有新的ts文件生成那就會更新。每次index file的ts文件讀取完畢,就會再次讀取index file文件,獲取新的index file,繼續讀取最新的ts文件,如此往復。


          3.搭建HLS流媒體服務器

          先參考前面這篇文章:手把手搭建流媒體服務器詳細步驟

          下面前面2步,在這篇文章手把手搭建流媒體服務器詳細步驟有詳細說明。

          (1)srs官?:https://github.com/ossrs/srs

          碼云的源速度快:https://gitee.com/winlinvip/srs.oschina.git

          github的源速度慢:https://github.com/ossrs/srs.git

          選擇當前最新的release版本3.0

          第?步,獲取SRS。詳細參考GIT獲取代碼:https://github.com/ossrs/srs/wiki/v1_CN_Git

          git clone https://gitee.com/winlinvip/srs.oschina.git
          
          cd srs.oschina
          
          cd trunk

          第?步,編譯SRS。詳細參考Build:https://github.com/ossrs/srs/wiki/v3_CN_Build

          ./configure && make

          (3)編寫SRS配置?件。詳細參考RTMP分發:https://github.com/ossrs/srs/wiki/v1_CN_DeliveryRTMP,Delivery HLS:https://github.com/ossrs/srs/wiki/v3_CN_SampleHLS,Delivery HTTP FLV:https://github.com/ossrs/srs/wiki/v3_CN_SampleHttpFlv,編輯 conf/srs.conf (尤其是hls和http_remux部分),服務器啟動時指定該配置?件(srs的conf?件夾有該?件)。

          listen              1935;
          max_connections     1000;
          srs_log_tank        file;
          srs_log_file        ./objs/srs.log;
          http_api {
              enabled         on;
              listen          1985;
          }
          http_server {
              enabled         on;
              listen          8080;#改為8081應該也可以
              dir             ./objs/nginx/html;
          }
          stats {
              network         0;
              disk            sda sdb xvda xvdb;
          }
          vhost __defaultVhost__ {
                  #hls antonio
                  hls{
                  enabled on;
                  hls_path ./objs/nginx/html;#生成ts文件路經
                  hls_fragment 5; # 分?時? 秒
                  hls_window 25; # 最?緩存的時?秒,也決定了最大延遲時間
          }
                  #http-flv for antonio
                  http_remux
                  {
                  enabled on;
                  mount [vhost]/[app]/[stream].flv;
                  hstrs on;
                  }
          }
          

          (4)啟動SRS。

          -c表示是讀取配置文件。

          在這個路經執行:


          ./objs/srs -c conf/srs.conf

          出現如下,就代表通過后臺跑起來了。


          也可以再輸入如下命令,讓其在前臺顯示,并查看log信息:

          在如下目錄:

          前臺查看log命令如下:

          tail -f objs/srs.log

          出現如下,代表可以成功查看信息:

          使用ffmpeg推流一定要搭建好ffmpeg環境以及到帶有xxx.flv文件的指定目錄去執行命令。

          ffmpeg推流:ffmpeg -re -i source.200kbps.768x320.flv -vcodec copy -acodec copy -f flv -y

          拉流:ffplay rtmp://172.16.204.132/live/livestream

          注意:上述命令中的flv完整路徑,以及srs server ip,?家根據情況??替換為實際值。 另外:默認情況下srs的rtmp采?1935端?,如果該端?被占?或修改了srs.conf中的端?,注意根據情況調整;防?墻如果開了,也要檢測下1935是否允許訪問。

          出現如下界面,就代表搭建成功。


          十分注意:很多朋友都沒注意一個概念,就是以為hls有推流端,實時是hls只有拉流的說法。


          (5)拉流RTMP/HLS/HTTP-FLV流

          RTMP拉流地址:ffplay rtmp://172.16.204.132/live/livestream

          HTTP FLV拉流地址:ffplay http://172.16.204.132:8080/live/livestream.flv

          HLS拉流地址:ffplay http://172.16.204.132:8080/live/livestream.m3u8


          同時拉流端也可以使用可以使?ffplay或者vlc以及 http://ossrs.net/srs.release/trunk/research/players/srs_player.html(經過測試這個播放器也是能拉取到各類流)或其它拉流工具進?測試。


          對比延時時間:

          對比拉取RTMP流和http的livestream.m3u8流。其中左圖是RTMP流,右圖是livestream.m3u8流,可以看出HLS相較RTMP,延時多了接近16s左右,hls這個延時就是最大確點。

          另外,經過測試,拉流FLV這個也是ffplay http://172.16.204.132:8080/live/livestream.flv,也是能夠拉取到。

          本篇文章就分析到這里,歡迎大家關注歡迎關注,點贊,轉發,收藏,分享,評論區討論。

          后面關于項目知識,后期會更新。歡迎關注微信公眾號"記錄世界 from antonio"。

          RS環境搭建

          srs官網:SRS官網

          碼云的源速度快:碼云的源速度快

          github的源速度慢:github的源速度慢

          選擇當前最新的release版本3.0

          第一步,獲取SRS。詳細參考GIT獲取代碼

          git clone https://gitee.com/winlinvip/srs.oschina.git srs.3.0-20200720

          cd srs.3.0-20200720

          #使?當前最新的3.0版本

          git checkout 3.0release

          cd trunk

          第二步,編譯SRS。詳細參考Build

          ./configure && make

          第三步,編寫SRS配置文件。詳細參考RTMP分發,Delivery HLS,Delivery HTTP FLV

          編輯 conf/srs.conf ,服務器啟動時指定該配置文件(srs的conf文件夾有該文件)。

          1 listen 1935;
          2 max_connections 1000;
          3 srs_log_tank file;
          4 srs_log_file ./objs/srs.log;
          5 http_api {
          6 enabled on;
          7 listen 1985;
          8 }
          9 http_server {
          10 enabled on;
          11 listen 8081; # http監聽端?,注意??配置的端?
          12 dir ./objs/nginx/html;
          13 }
          14 stats {
          15 network 0;
          16 disk sda sdb xvda xvdb;
          17 }
          18 vhost __defaultVhost__ {
          19 # hls darren
          20 hls {
          21 enabled on;
          22 hls_path ./objs/nginx/html;
          23 hls_fragment 10;
          24 hls_window 60;
          25 }
          26 # http-flv darren
          27 http_remux {
          28 enabled on;
          29 mount [vhost]/[app]/[stream].flv;
          30 hstrs on;
          31 }
          32 }


          SRS全網獨一份的視頻文檔資料私信1,進群免費領取,更有【免費】FFmpeg/WebRTC/RTMP/NDK/Android音視頻流媒體高級開發-學習視頻教程-騰訊課堂

          第四步,啟動SRS。

          ./objs/srs -c conf/srs.conf

          1 ubuntu@VM-0-13-ubuntu:~/0voice/media/srs.3.0-20200720/trunk$ ./objs/s
          2rs -c conf/srs.conf
          2 后臺運?結果
          3 [2020-07-20 17:34:48.061][Trace][30433][0] XCORE-SRS/3.0.141(OuXuli)
          4 [2020-07-20 17:34:48.061][Trace][30433][0] config parse complete
          5 [2020-07-20 17:34:48.061][Trace][30433][0] write log to file ./objs/s
          rs.log
          6 [2020-07-20 17:34:48.061][Trace][30433][0] you can: tailf ./objs/srs.
          log
          7 [2020-07-20 17:34:48.061][Trace][30433][0] @see: https://github.com/o
          ssrs/srs/wiki/v1_CN_SrsLog

          確認是否已經正常啟動

          1 ubuntu@VM-0-13-ubuntu:~/0voice/media/srs.3.0-20200720/trunk$ sudo ps
          -ef | grep srs
          2 ubuntu 30435 1 0 17:34 pts/0 00:00:00 ./objs/srs -c conf/sr
          s.conf

          顯示到ubuntu 30435 1 0 17:34 pts/0 00:00:00 ./objs/srs -c conf/srs.conf

          安全退出正在運行的srs

          sudo kill -SIGQUIT srs_pid

          默認是后臺啟動的方式,如果是要方便GDB調試則需要修改配置文件為前臺啟動。

          1 listen 1935;
          2 max_connections 1000;
          3 #srs_log_tank file;
          4 #srs_log_file ./objs/srs.log;
          5 # 前臺運?
          6 daemon off;
          7 # 打印到終端控制臺
          8 srs_log_tank console;
          9 http_api {
          10 enabled on;
          11 listen 1985;
          12 }
          313 http_server {
          14 enabled on;
          15 listen 8081; # http監聽端?
          16 dir ./objs/nginx/html;
          17 }
          18 stats {
          19 network 0;
          20 disk sda sdb xvda xvdb;
          21 }
          22 vhost __defaultVhost__ {
          23 # hls darren
          24 hls {
          25 enabled on;
          26 hls_path ./objs/nginx/html;
          27 hls_fragment 10;
          28 hls_window 60;
          29 }
          30 # http-flv darren
          31 http_remux {
          32 enabled on;
          33 mount [vhost]/[app]/[stream].flv;
          34 hstrs on;
          35 }
          36 }

          執行方法:./objs/srs -c conf/srs.conf

          在終端運行,log也在終端顯示

          1 [2020-07-20 17:46:33.586][Trace][1533][0] system default latency(ms)
          : mw(0-350) + mr(0-350) + play-queue(0-30000)
          2 [2020-07-20 17:46:33.586][Warn][1533][0][0] SRS/3.0.141 is beta
          3 [2020-07-20 17:46:33.586][Trace][1533][0] http flv live stream, vhos
          t=__defaultVhost__, mount=[vhost]/[app]/[stream].flv
          4 [2020-07-20 17:46:33.586][Trace][1533][0] http: root mount to ./objs
          /nginx/html
          5 [2020-07-20 17:46:33.586][Trace][1533][0] st_init success, use epoll
          6 [2020-07-20 17:46:33.586][Trace][1533][380] server main cid=380, pid
          45
          =1533, ppid=2337, asprocess=0
          7 [2020-07-20 17:46:33.586][Trace][1533][380] write pid=1533 to ./objs
          /srs.pid success!
          8 [2020-07-20 17:46:33.586][Trace][1533][380] RTMP listen at tcp://0.0
          .0.0:1935, fd=7
          9 [2020-07-20 17:46:33.586][Trace][1533][380] HTTP-API listen at tcp:/
          /0.0.0.0:1985, fd=8
          10 [2020-07-20 17:46:33.586][Trace][1533][380] HTTP-Server listen at tc
          p://0.0.0.0:8081, fd=9
          11 [2020-07-20 17:46:33.586][Trace][1533][380] signal installed, reload
          =1, reopen=10, fast_quit=15, grace_quit=3
          12 [2020-07-20 17:46:33.586][Trace][1533][380] http: api mount /console
          to ./objs/nginx/html/console

          SRS源碼目錄

          trunk目錄

          3rdparty auto conf configure doc etc ide modules research scripts src usr

          src下的源碼

          app core kernel libs main protocol service utest

          app應用

          ├── app

          │ ├── srs_app_async_call.cpp

          │ ├── srs_app_async_call.hpp 可以用來執行異步任務,通過execute()函數 push任務,然后

          在cycle()執行

          │ ├── srs_app_bandwidth.cpp

          │ ├── srs_app_bandwidth.hpp 提供帶寬測試接口

          │ ├── srs_app_caster_flv.cpp

          │ ├── srs_app_caster_flv.hpp 支持POST一個flv流到服務器,類似相當于RTMP的publish

          │ ├── srs_app_config.cpp

          │ ├── srs_app_config.hpp 讀取配置文件

          │ ├── srs_app_conn.cpp

          │ ├── srs_app_conn.hpp srs的基本連接,每個連接對應一個協程,所有的連接都被管理

          │ ├── srs_app_coworkers.cpp

          │ ├── srs_app_coworkers.hpp SrsCoWorkers For origin cluster

          │ ├── srs_app_dash.cpp

          │ ├── srs_app_dash.hpp SrsDash 流媒體DASH業務 The MPEG-DASH encoder,

          transmux RTMP to DASH.

          │ ├── srs_app_dvr.cpp

          │ ├── srs_app_dvr.hpp SrsDvr 錄制RTMP流程flv或者mp4文件

          │ ├── srs_app_edge.cpp

          │ ├── srs_app_edge.hpp SrsEdgeRtmpUpstream 邊緣節點業務,比如從源站拉流到邊緣,邊

          緣回溯到源站

          │ ├── srs_app_empty.cpp

          │ ├── srs_app_empty.hpp 沒有內容

          │ ├── srs_app_encoder.cpp

          │ ├── srs_app_encoder.hpp SrsEncoder 可以使用多個ffmpeg來轉換指定的流,最終調用

          SrsFFMPEG來轉流

          │ ├── srs_app_ffmpeg.cpp

          │ ├── srs_app_ffmpeg.hpp SrsFFMPEG 使用ffmpeg來轉換流

          │ ├── srs_app_forward.cpp

          │ ├── srs_app_forward.hpp SrsForwarder 將流轉發到其他服務器

          │ ├── srs_app_fragment.cpp

          │ ├── srs_app_fragment.hpp SrsFragment 表示一個分片,如HLS分片、DVR分片或DASH分

          片。它是一個媒體文件,例如FLV或MP4,有持續時間。

          │ ├── srs_app_hds.cpp

          │ ├── srs_app_hds.hpp SrsHds 將RTMP轉成Adobe HDS流

          │ ├── srs_app_heartbeat.cpp

          │ ├── srs_app_heartbeat.hpp SrsHttpHeartbeat HHTP心跳

          │ ├── srs_app_hls.cpp

          │ ├── srs_app_hls.hpp SrsHls HLS業務,Transmux RTMP stream to HLS(m3u8 and

          ts).

          │├── srs_app_hourglass.cpp

          │ ├── srs_app_hourglass.hpp SrsHourGlass 滴答tick的處理程序

          │ ├── srs_app_http_api.cpp

          │ ├── srs_app_http_api.hpp SrsHttpApi HTTP業務API7

          │ ├── srs_app_http_client.cpp

          │ ├── srs_app_http_client.hpp 沒有內容

          │ ├── srs_app_http_conn.cpp

          │ ├── srs_app_http_conn.hpp SrsHttpConn,HTTP連接,繼承于SrsConnection

          │ ├── srs_app_http_hooks.cpp

          │ ├── srs_app_http_hooks.hpp SrsHttpHooks HTTP勾子,HTTP回調API

          │ ├── srs_app_http_static.cpp

          │ ├── srs_app_http_static.hpp SrsHttpStaticServer HTTP靜態服務器實例,為HTTP靜態文

          件和FLV/MP4視頻點播服務

          │ ├── srs_app_http_stream.cpp

          │ ├── srs_app_http_stream.hpp SrsHttpStreamServer HTTP直播流服務,支持

          FLV/TS/MP3/AAC流

          │ ├── srs_app_ingest.cpp

          │ ├── srs_app_ingest.hpp SrsIngester攝取文件/流/設備,用FFMPEG編碼(可選), 通過

          RTMP推送到SRS(或其他RTMP服務器)

          │ ├── srs_app_listener.cpp

          │ ├── srs_app_listener.hpp SrsTcpListener SrsUdpListener TCP/UDP監聽器

          │ ├── srs_app_log.cpp

          │ ├── srs_app_log.hpp SrsFastLog 日志

          │ ├── srs_app_mpegts_udp.cpp

          │ ├── srs_app_mpegts_udp.hpp SrsMpegtsOverUdpThe mpegts over udp stream caster

          │ ├── srs_app_ng_exec.cpp

          │ ├── srs_app_ng_exec.hpp SrsNgExec

          │ ├── srs_app_pithy_print.cpp

          │ ├── srs_app_pithy_print.hpp SrsPithyPrint 收集信息,然后打印

          │ ├── srs_app_process.cpp

          │ ├── srs_app_process.hpp SrsProcess啟動和停止進程,當被終止時調用cycle重新啟動進

          │ ├── srs_app_recv_thread.cpp

          │ ├── srs_app_recv_thread.hpp SrsHttpRecvThread HTTP數據讀取,

          SrsPublishRecvThread推流數據讀取,SrsQueueRecvThread從隊列讀取;SrsRecvThread封裝的協程

          │ ├── srs_app_refer.cpp

          │ ├── srs_app_refer.hpp SrsRefer

          │ ├── srs_app_reload.cpp

          │ ├── srs_app_reload.hpp ISrsReloadHandler 重新讀取配置文件的處理

          │ ├── srs_app_rtmp_conn.cpp

          │ ├── srs_app_rtmp_conn.hpp SrsRtmpConn RTMP連接

          │ ├── srs_app_rtsp.cpp

          │ ├── srs_app_rtsp.hpp SrsRtpConn RTSP連接,SrsRtspCaster RTSP業務

          │ ├── srs_app_security.cpp8

          │ ├── srs_app_security.hpp SrsSecurity 安全限制,主要是限制url

          │ ├── srs_app_server.cpp

          │ ├── srs_app_server.hpp SrsServer SRS服務,對應的rtmp、rtsp、http-flv等等業務在這里啟動

          │ ├── srs_app_source.cpp

          │ ├── srs_app_source.hpp SrsSource 對應一個源,支持多個SrsConsumer來拉流,

          SrsSourceManager管理源, SrsMetaCache?于源緩存Meta數據,SrsConsumer源的消費者,

          SrsGopCache GOP緩存

          │ ├── srs_app_statistic.cpp

          │ ├── srs_app_statistic.hpp SrsStatistic流統計

          │ ├── srs_app_st.cpp

          │ ├── srs_app_st.hpp SrsSTCoroutine協程相關

          │ ├── srs_app_thread.cpp

          │ ├── srs_app_thread.hpp SrsCoroutineManager協程管理

          │ ├── srs_app_utility.cpp

          │ └── srs_app_utility.hpp 工具類:SrsPlatformInfo、SrsNetworkDevices、SrsMemInfo、

          SrsDiskStat等等

          ├── core

          │ ├── srs_core_autofree.cpp

          │ ├── srs_core_autofree.hpp 通過棧上的方式構建自動釋放堆申請的對象,這個設計還是非常值

          得我們學習

          │ ├── srs_core.cpp

          │ ├── srs_core.hpp 版本相關的?些信息

          │ ├── srs_core_mem_watch.cpp

          │ ├── srs_core_mem_watch.hpp 內存監測接口

          │ ├── srs_core_performance.cpp

          │ ├── srs_core_performance.hpp 性能測試相關

          │ ├── srs_core_time.cpp

          │ ├── srs_core_time.hpp 時間單位相關

          │ ├── srs_core_version3.cpp

          │ └── srs_core_version3.hpp 版本信息

          ├── kernel // 音視頻格式相關的

          │ ├── srs_kernel_aac.cpp

          │ ├── srs_kernel_aac.hpp SrsAacTransmuxer 合成AAC音頻流,帶ADTS header

          │ ├── srs_kernel_balance.cpp

          │ ├── srs_kernel_balance.hpp SrsLbRoundRobin負載均衡,用于邊緣節點拉流和其他多個服

          務器的功能

          │ ├── srs_kernel_buffer.cpp

          │ ├── srs_kernel_buffer.hpp SrsBuffer讀取字節的實用類

          │ ├── srs_kernel_codec.cpp9

          │ ├── srs_kernel_codec.hpp 編碼器相關,包括視頻和音頻,非常核心的文件;SrsFlvVideo用來檢測FLV的video tag對應內容;SrsFlvAudio用來檢測FLV的audio tag對應內容;SrsMaxNbSamples

          256表示video最大的NALUS個數,audio最大的packet數量;SrsFrame存儲幀,SrsAudioFrame 存儲

          AAC幀,SrsVideoFrame存儲視頻幀;SrsFormat編碼器格式,包含了一個或者多個流,比如為RTMP

          format時,包含一個視頻和一個音頻幀。先猜測推流時的數據實例是保存在SrsFormat?

          │ ├── srs_kernel_consts.cpp

          │ ├── srs_kernel_consts.hpp SRS的常量定義,比如播放的標記#define

          SRS_CONSTS_LOG_PLAY "PLA";發布的標記#define SRS_CONSTS_LOG_CLIENT_PUBLISH

          "CPB";SRS_CONSTS_HTTP_XXX等HTTP響應碼;SRS_CONSTS_RTSP_XXX響應碼等等。

          │ ├── srs_kernel_error.cpp

          │ ├── srs_kernel_error.hpp 返回值常量定義,ERROR_XXX;SrsCplxError 異常類

          │ ├── srs_kernel_file.cpp

          │ ├── srs_kernel_file.hpp 文件的讀寫,SrsFileWriter文件寫入器,SrsFileReader文件讀取器

          │ ├── srs_kernel_flv.cpp

          │ ├── srs_kernel_flv.hpp FLV SrsFlvDecoder解析,SrsFlvTransmuxer將RTMP轉成FLV流;

          SrsSharedPtrMessage對應RTMP的消息

          │ ├── srs_kernel_io.cpp

          │ ├── srs_kernel_io.hpp IO讀寫接口類

          │ ├── srs_kernel_log.cpp

          │ ├── srs_kernel_log.hpp 日志相關

          │ ├── srs_kernel_mp3.cpp

          │ ├── srs_kernel_mp3.hpp SrsMp3Transmuxer將RTMP轉成MP3流

          │ ├── srs_kernel_mp4.cpp

          │ ├── srs_kernel_mp4.hpp SrsMp4Encoder MP4復用器;

          │ ├── srs_kernel_stream.cpp

          │ ├── srs_kernel_stream.hpp SrsSimpleStream用vector實現的簡單的字節append類,主要在

          hls和http中使用,將來需要進行改進。

          │ ├── srs_kernel_ts.cpp

          │ ├── srs_kernel_ts.hpp SrsTsTransmuxer將RTMP流轉成http-ts流,該文件實現了ts格式相

          關的接口

          │ ├── srs_kernel_utility.cpp

          │ └── srs_kernel_utility.hpp 工具函數,比如bool srs_string_ends_with(std::string str,

          std::string flag)

          ├── libs

          │ ├── srs_lib_bandwidth.cpp

          │ ├── srs_lib_bandwidth.hpp SrsBandwidthClient srs-librtmp 客戶端帶寬統計

          │ ├── srs_librtmp.cpp

          │ ├── srs_librtmp.hpp srs提供的客戶端rtmp庫

          │ ├── srs_lib_simple_socket.cpp

          │ └── srs_lib_simple_socket.hpp SimpleSocketStream rtmp客戶端的socket封裝10

          ├── main

          │ ├── srs_main_ingest_hls.cpp 拉取hls發布到rtmp流媒體服務器

          │ ├── srs_main_mp4_parser.cpp MP4 box解析

          │ └── srs_main_server.cpp srs流媒體服務器主入口

          ├── protocol 流媒體協議相關的協議都在這里

          │ ├── srs_http_stack.cpp

          │ ├── srs_http_stack.hpp HTTP協議

          │ ├── srs_protocol_amf0.cpp

          │ ├── srs_protocol_amf0.hpp Amf0解析

          │ ├── srs_protocol_format.cpp

          │ ├── srs_protocol_format.hpp SrsRtmpFormat繼承了SrsFormat, 代表RTMP格式

          │ ├── srs_protocol_io.cpp

          │ ├── srs_protocol_io.hpp 協議數據讀取的IO封裝接口,比如ISrsProtocolReadWriter

          │ ├── srs_protocol_json.cpp

          │ ├── srs_protocol_json.hpp json類

          │ ├── srs_protocol_kbps.cpp

          │ ├── srs_protocol_kbps.hpp 比特率統計相關

          │ ├── srs_protocol_stream.cpp

          │ ├── srs_protocol_stream.hpp 流讀取,從ISrsReader讀取數據到buffer里面

          │ ├── srs_protocol_utility.cpp

          │ ├── srs_protocol_utility.hpp 協議工具函數

          │ ├── srs_raw_avc.cpp

          │ ├── srs_raw_avc.hpp SrsRawH264Stream H264裸流解析,SrsRawAacStream AAC

          裸流解析

          │ ├── srs_rtmp_handshake.cpp

          │ ├── srs_rtmp_handshake.hpp RTMP握手,包括SrsSimpleHandshake和

          SrsComplexHandshake

          │ ├── srs_rtmp_msg_array.cpp

          │ ├── srs_rtmp_msg_array.hpp SrsMessageArray消息數組

          │ ├── srs_rtmp_stack.cpp

          │ ├── srs_rtmp_stack.hpp RTMP協議棧

          │ ├── srs_rtsp_stack.cpp

          │ └── srs_rtsp_stack.hpp RTSP協議棧

          ├── service

          │ ├── srs_service_conn.cpp

          │ ├── srs_service_conn.hpp ISrsConnection HTTP/RTMP/RTSP等對象的連接接口;

          IConnectionManager管理連接接口

          │ ├── srs_service_http_client.cpp

          │ ├── srs_service_http_client.hpp SrsHttpClient HTTP客戶端

          │ ├── srs_service_http_conn.cpp11

          │ ├── srs_service_http_conn.hpp HTTP連接 SrsHttpParser,SrsHttpMessage,

          SrsHttpResponseWriter,SrsHttpResponseReader

          │ ├── srs_service_log.cpp

          │ ├── srs_service_log.hpp SrsConsoleLog日志相關

          │ ├── srs_service_rtmp_conn.cpp

          │ ├── srs_service_rtmp_conn.hpp SrsBasicRtmpClient RTMP客戶端類

          │ ├── srs_service_st.cpp

          │ ├── srs_service_st.hpp 對st-thread協程的封裝

          │ ├── srs_service_utility.cpp

          │ └── srs_service_utility.hpp service組件的工具類

          └── utest

          ├── srs_utest_amf0.cpp

          ├── srs_utest_amf0.hpp

          ├── srs_utest_app.cpp

          ├── srs_utest_app.hpp

          ├── srs_utest_avc.cpp

          ├── srs_utest_avc.hpp

          ├── srs_utest_config.cpp

          ├── srs_utest_config.hpp

          ........... 還有其他utest文件,這里忽略

          8 directories, 203 files

          ava 監控直播流rtsp協議轉rtmp、hls、httpflv協議返回瀏覽器

          目錄

          • 一:了解音視頻流協議:
          • 二:方案一 rtsp 轉rtmp1、下載nginx + nginx-rtmp-module3、cmd 到nginx根目錄啟動nginx8、查攝像頭的rtsp協議格式10、測試rtmp是否轉換成功12、為什么放棄了用rtmp
          • 四:方案三rtsp 轉httpflv(采用)1、安裝nginx-flv-module4.1 采用java代碼去執行ffmepg命令6、前端使用flv.js播放:

          需求背景:

          在做之前的項目的時候有一個對接攝像頭實時播放的需求,由于我們攝像頭的購買量不是很多,海康威視不給我們提供流媒體云服務器,所以需要我們自己去 一個去滿足我們能在瀏覽器看到監控畫面。項目源代碼在以前公司沒有拷貝就不能復習,最近又在準備面試,所以寫了這個博客來復盤和擴展一下,由于我現在沒有Liunx,我就用Windows來演示,生產環境還是要使用Liunx,下面這些操作在Liunx也是一樣的流程,大家自行百度。

          一:了解音視頻流協議:

          媒體流協議對比

          協議

          HttpFlv

          RTMP

          HLS

          Dash

          全稱

          FLASH VIDEO over HTTP

          Real Time Message Protocol

          HTTP Living Streaming


          傳輸方式

          HTTP長連接

          TCP長連接

          HTTP短連接

          HTTP短連接

          視頻封裝格式

          FLV

          FLV TAG

          TS文件

          Mp4

          3gp

          webm

          原理

          同 RTMP ,使用HTTP協議(80端口)

          每個時刻的數據收到后立刻轉發

          集合一段時間的數據,生成TS切片文件(三片),并更新m3u8索引


          延時

          1~3秒

          1~3秒

          5~20秒(依切片情況)

          數據分段

          連續流

          連續流

          切片文件

          切片文件

          Html5播放

          可通過HTML5解封包播放

          (flv.js)

          不支持

          可通過HTML5解封包播放

          (hls.js)

          如果dash文件列表是MP4,

          webm文件,可直接播放

          其它

          需要Flash技術支持,不支持多音頻流、多視頻流,不便于seek(即拖進度條)

          跨平臺支持較差,需要Flash技術支持

          播放時需要多次請求,對于網絡質量要求高


          二:方案一 rtsp 轉rtmp

          1、下載nginx + nginx-rtmp-module

          nginx:下載地址: http://nginx-win.ecsds.eu/download/

          nginx-rtmp-module:nginx 的擴展,安裝后支持rtmp協議,下載地址: https://github.com/arut/nginx-rtmp-module

          解壓nginx-rtmp-module到nginx根目錄下,并修改其文件夾名為nginx-rtmp-module(原名為nginx-rtmp-module-master)

          2、nginx配置文件

          到nginx根目錄下的conf目錄下復制一份nginx-win.conf 重命名 nginx-win-rtmp.conf

          nginx-win-rtmp.conf:

          #user  nobody;
          # multiple workers works !
          worker_processes  2;
          
          #error_log  logs/error.log;
          #error_log  logs/error.log  notice;
          #error_log  logs/error.log  info;
          
          #pid        logs/nginx.pid;
          
          events {
              worker_connections  8192;
              # max value 32768, nginx recycling connections+registry optimization = 
              #   this.value * 20 = max concurrent connections currently tested with one worker
              #   C1000K should be possible depending there is enough ram/cpu power
              # multi_accept on;
          }
          
          rtmp {
              server {
                  listen 1935;
                  chunk_size 4000;
          		
                  application live {
                       live on;
                       # 播放時進行回調,如果HttpRespone statusCode不等于200會斷開
          			 # on_play http://localhost:8081/auth;
                  }
          		
          		application hls {
          		     live on; 
          		     # 開啟hls切片
                       hls on;
                       # m3u8地址
          			 hls_path html/hls;
          			 # 一個切片多少秒
          			 hls_fragment 8s;
          			 # on_play http://localhost:8081/auth;
          			 # on_publish http://localhost:8081/auth;
          			 # on_done http://localhost:8081/auth;
                  }
              }
          }
          
          http {
              #include      /nginx/conf/naxsi_core.rules;
              include       mime.types;
              default_type  application/octet-stream;
          
              #log_format  main  '$remote_addr:$remote_port - $remote_user [$time_local] "$request" '
              #                  '$status $body_bytes_sent "$http_referer" '
              #                  '"$http_user_agent" "$http_x_forwarded_for"';
          
              #access_log  logs/access.log  main;
          
          #     # loadbalancing PHP
          #     upstream myLoadBalancer {
          #         server 127.0.0.1:9001 weight=1 fail_timeout=5;
          #         server 127.0.0.1:9002 weight=1 fail_timeout=5;
          #         server 127.0.0.1:9003 weight=1 fail_timeout=5;
          #         server 127.0.0.1:9004 weight=1 fail_timeout=5;
          #         server 127.0.0.1:9005 weight=1 fail_timeout=5;
          #         server 127.0.0.1:9006 weight=1 fail_timeout=5;
          #         server 127.0.0.1:9007 weight=1 fail_timeout=5;
          #         server 127.0.0.1:9008 weight=1 fail_timeout=5;
          #         server 127.0.0.1:9009 weight=1 fail_timeout=5;
          #         server 127.0.0.1:9010 weight=1 fail_timeout=5;
          #         least_conn;
          #     }
          
              sendfile        off;
              #tcp_nopush     on;
          
              server_names_hash_bucket_size 128;
          
          ## Start: Timeouts ##
              client_body_timeout   10;
              client_header_timeout 10;
              keepalive_timeout     30;
              send_timeout          10;
              keepalive_requests    10;
          ## End: Timeouts ##
          
              #gzip  on;
          
              server {
                  listen       5080;
                  server_name  localhost;
          
          
                  location /stat {
                      rtmp_stat all;
                      rtmp_stat_stylesheet stat.xsl;
                  }
                  location /stat.xsl {
                      root nginx-rtmp-module/;
                  }
                  location /control {
                      rtmp_control all;
                  }
          		
          		location /hls {
                      # Serve HLS fragments
                      types {
                          application/vnd.apple.mpegurl m3u8;
                          video/mp2t ts;
                      }
                      expires -1;
                      add_header Access-Control-Allow-Origin *;
                  }
          
                  #charset koi8-r;
                  #access_log  logs/host.access.log  main;
          
                  ## Caching Static Files, put before first location
                  #location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
                  #    expires 14d;
                  #    add_header Vary Accept-Encoding;
                  #}
          
          # For Naxsi remove the single # line for learn mode, or the ## lines for full WAF mode
                  location / {
                      #include    /nginx/conf/mysite.rules; # see also http block naxsi include line
                      ##SecRulesEnabled;
                   ##DeniedUrl "/RequestDenied";
                   ##CheckRule "$SQL >= 8" BLOCK;
                   ##CheckRule "$RFI >= 8" BLOCK;
                   ##CheckRule "$TRAVERSAL >= 4" BLOCK;
                   ##CheckRule "$XSS >= 8" BLOCK;
                      root   html;
                      index  index.html index.htm;
                  }
          
          # For Naxsi remove the ## lines for full WAF mode, redirect location block used by naxsi
                  ##location /RequestDenied {
                  ##    return 412;
                  ##}
          
          ## Lua examples !
          #         location /robots.txt {
          #           rewrite_by_lua '
          #             if ngx.var.http_host ~= "localhost" then
          #               return ngx.exec("/robots_disallow.txt");
          #             end
          #           ';
          #         }
          
                  #error_page  404              /404.html;
          
                  # redirect server error pages to the static page /50x.html
                  #
                  error_page   500 502 503 504  /50x.html;
                  location = /50x.html {
                      root   html;
                  }
          
                  # proxy the PHP scripts to Apache listening on 127.0.0.1:80
                  #
                  #location ~ \.php$ {
                  #    proxy_pass   http://127.0.0.1;
                  #}
          
                  # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
                  #
                  #location ~ \.php$ {
                  #    root           html;
                  #    fastcgi_pass   127.0.0.1:9000; # single backend process
                  #    fastcgi_pass   myLoadBalancer; # or multiple, see example above
                  #    fastcgi_index  index.php;
                  #    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                  #    include        fastcgi_params;
                  #}
          
                  # deny access to .htaccess files, if Apache's document root
                  # concurs with nginx's one
                  #
                  #location ~ /\.ht {
                  #    deny  all;
                  #}
              }
          
              # another virtual host using mix of IP-, name-, and port-based configuration
              #
              #server {
              #    listen       8000;
              #    listen       somename:8080;
              #    server_name  somename  alias  another.alias;
          
              #    location / {
              #        root   html;
              #        index  index.html index.htm;
              #    }
              #}
          
              # HTTPS server
              #
              #server {
              #    listen       443 ssl spdy;
              #    server_name  localhost;
          
              #    ssl                  on;
              #    ssl_certificate      cert.pem;
              #    ssl_certificate_key  cert.key;
              #    ssl_session_timeout  5m;
              #    ssl_prefer_server_ciphers On;
              #    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
              #    ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:ECDH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!eNULL:!MD5:!DSS:!EXP:!ADH:!LOW:!MEDIUM;
          
              #    location / {
              #        root   html;
              #        index  index.html index.htm;
              #    }
              #}
          
          }

          3、cmd 到nginx根目錄啟動nginx

          nginx.exe -c conf\nginx-win-rtmp.conf

          測試:瀏覽器輸入 http://localhost:5080/stat,看到

          代表安裝成功

          4、下載ffmpeg安裝

          ffmpeg:一個處理音視頻強大的庫,我們需要用它來轉協議,下載地址: https://www.gyan.dev/ffmpeg/builds/ ,這里可以下載essential和full版本,essential就是簡版,只包含ffmpeg.exe、ffplay.exe、

          ffprobe.exe, 而full版本就包含了動態庫和相關頭文件,方便我們在開發中調用。

          5、配置ffmpeg環境變量

          將ffmpeg解壓后里面的bin路徑復制到Path里面去

          6、測試ffmpeg

          cmd ffmpeg -version 命令看到代表成功

          7、下載VLC播放器

          下載地址: https://www.videolan.org/vlc/

          8、查攝像頭的rtsp協議格式

          我這里截圖是海康威視的

          現在沒有測試的流,我找了個點播的rtsp

          rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4,用這個代替是一樣的

          9、執行ffmpeg命令

          ffmpeg強大,命令也是復雜,我們cmd 執行

          ffmpeg -re -rtsp_transport tcp -stimeout 20000000 -i "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4" -buffer_size 1024000 -max_delay 500000 -codec:v libx264 -r 25 -rtbufsize 10M -s 1280x720 -map:v 0 -an -f flv rtmp://127.0.0.1:1935/live/test

          rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4,是輸入源頭

          rtmp://127.0.0.1:1935/live/test 是輸出地址

          如果沒有報錯的話,到現在rtsp就已經轉換好了

          ffmpeg命令學習: https://www.jianshu.com/p/df3216a52e59 、 https://blog.csdn.net/fuhanghang/article/details/123565920

          10、測試rtmp是否轉換成功

          我們打開VLC,媒體->打開網絡串流->輸入 rtmp://127.0.0.1:1935/live/test -> 播放

          11、測試是否成功

          等待幾秒鐘看到有視頻播放就是成功了

          12、為什么放棄了用rtmp

          rtmp的優點是延遲低,效率高,但是在瀏覽器需要安裝flash才能放,也就老版本的瀏覽器在用,rtmp可能會在別的地方支持,所以還是把他方式方法貼出來了。

          三:方案二 rtsp轉hls

          1、nginx配置:

          在前面已經貼出來了,其中這幾個是針對hls的

          2、執行ffmepg命令

          ffmpeg -i "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4" -vcodec libx264 -acodec aac -f flv rtmp://127.0.0.1:1935/hls/test

          3、查看nginx根目錄 -> hls -> test.m3u8 是否生成

          生成了代表一切正常

          4、m3u8在網頁上播放

          <!DOCTYPE html>
          <html lang="zh-CN">
          <head>
              <meta charset="UTF-8">
              <title>前端播放m3u8格式視頻</title>
              <!--https://www.bootcdn.cn/video.js/-->
              <link href="https://cdn.bootcss.com/video.js/7.6.5/alt/video-js-cdn.min.css" rel="stylesheet">
              <script src="https://cdn.bootcss.com/video.js/6.6.2/video.js"></script>
              <!--https://www.bootcdn.cn/videojs-contrib-hls/-->
              <script src="https://cdn.bootcss.com/videojs-contrib-hls/5.15.0/videojs-contrib-hls.min.js"></script>
          </head>
          <body>
              <video id="myVideo" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="auto" width="1080" height="708" data-setup='{}'>    
                  <source id="source" src="http://127.0.0.1:5080/hls/test.m3u8"  type="application/x-mpegURL">
              </video>
          </body>
          <script>    
              // videojs 簡單使用  
              var myVideo = videojs('myVideo',{
                  bigPlayButton : true, 
                  textTrackDisplay : false, 
                  posterImage: false,
                  errorDisplay : false,
              })
              myVideo.play() // 視頻播放
              myVideo.pause() // 視頻暫停
          </script>
          </html>

          source標簽的src屬性: http://你的nginx ip:nginx http端口/hls/test.m3u8

          rtsp轉HLS成功!

          5、認識一下m3u8格式

          m3u8文件里面存儲了一個索引,以文本格式打開是這樣的

          #EXTM3U
          #EXT-X-VERSION:3
          #EXT-X-MEDIA-SEQUENCE:56
          #EXT-X-TARGETDURATION:13
          #EXTINF:10.381,
          test-56.ts
          #EXTINF:10.422,
          test-57.ts
          #EXTINF:13.453,
          test-58.ts

          m3u8文件它不是視頻源,源頭是ts后綴文件

          6、為什么放棄了用HLS

          轉HLS協議及網頁加載過程:

          ffmepg收到rtsp的流時候,會等一個切片的時間,一個切片時間到了,切片ts會放到服務器中,同時m3u8文件中加一個索引,對應著新進入的切片。網頁在加載m3u8的時候,就是讀取m3u8中的的索引去加載ts文件,所以在不斷的請求ts,對ts進行解析,不斷的和TCP握手,這就是為什么HLS延遲高和對網速的要求高的原因,我們監控肯定是要延遲低的,HLS兼容性好,適合點播。

          四:方案三rtsp 轉httpflv(采用)

          1、安裝nginx-flv-module

          這個插件需要編譯,教程: https://blog.csdn.net/KayChanGEEK/article/details/105095844

          我這里已經編譯好了,直接下載啟動:

          https://gitee.com/isyuesen/nginx-flv-file

          2、nginx配置

          看我git里面的https://gitee.com/isyuesen/nginx-flv-file/blob/master/conf/nginx.conf,和默認的config差別主要是添加了這幾個

          rtmp {  
              server {  
                  listen 1935;
                  # 流復用的最大塊大小
                  chunk_size 4000;  
                  application liveapp { 
                      live on;
                      # 推流開始
          			on_publish http://localhost:8081/auth;
          			# 推流關閉
          			on_publish_done http://localhost:8081/auth;
          			# 客戶端開始播放
          			on_play http://localhost:8081/auth;
          			# 客戶端結束播放
          			on_play_done http://localhost:8081/auth;
                  }  
              }  
          }
          location /live {
              flv_live on;
              chunked_transfer_encoding on;
              add_header 'Access-Control-Allow-Credentials' 'true'; #add additional HTTP header
              add_header 'Access-Control-Allow-Origin' '*'; #add additional HTTP header
              add_header Access-Control-Allow-Headers X-Requested-With;
              add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
              add_header 'Cache-Control' 'no-cache';
          }

          3、做java權限認證

          nginx rtmp配置中有配置on_publish鉤子接口 http://localhost:8081/auth,這個回調HttpResponse stausCode如果不等于200會拒絕I/O,更多回調鉤子看: https://github.com/arut/nginx-rtmp-module/wiki/Directives#on_connect

          @PostMapping("/auth")
              public void getVideo(String token, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
                  if (token.equals("tokenValue")) {
                      httpServletResponse.setStatus(200);
                  } else {
                      // 拒絕服務
                      httpServletResponse.setStatus(500);
                  }
              }

          4、執行ffmepg命令:

          ffmpeg -re  -rtsp_transport tcp -i "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4" -f flv -vcodec h264 -vprofile baseline -acodec aac -ar 44100 -strict -2 -ac 1 -f flv -s 640*360 -q 10 "rtmp://127.0.0.1:1935/liveapp/test"

          4.1 采用java代碼去執行ffmepg命令

          依賴 javaCV

          <dependency>
              <groupId>org.bytedeco</groupId>
              <artifactId>javacv-platform</artifactId>
              <version>1.5.2</version>
          </dependency>
          public class App {
              public static void main( String[] args ) throws IOException, InterruptedException {
                  String name = "test";
                  // rtsp地址
                  String rtspDir = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4";
                  // rtmp地址
                  String rtmpDir = "rtmp://192.168.0.140:1935/liveapp/" + name + "?token=tokenValue";
          
                  String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);
                  ProcessBuilder pb = new ProcessBuilder(ffmpeg,
                          "-re",
                          "-rtsp_transport",
                          "tcp",
                          "-i",
                          rtspDir,
                          "-f",
                          "flv",
                          "-vcodec",
                          "h264",
                          "-vprofile",
                          "baseline",
                          "-acodec",
                          "aac",
                          "-ar",
                          "44100",
                          "-strict",
                          "-2",
                          "-ac",
                          "1",
                          "-f",
                          "flv",
                          "-s",
                          "640*360",
                          "-q",
                          "10",
                          rtmpDir
                  );
                  pb.inheritIO().start().waitFor();
              }
          }

          5、測試http-flv鏈接

          如果你跟著我做的,那鏈接就是 http://127.0.0.1:18080/live?port=1935&app=liveapp&stream=test&token=tokenValue,在VLC播放器中點擊媒體 -> 打開網絡串流 -> 輸入http://127.0.0.1:18080/live?port=1935&app=liveapp&stream=test&token=tokenValue -> 播放

          有視頻證明你離成功就差最后一步

          6、前端使用flv.js播放:

          <!doctype html>
          <html lang="en">
          <head>
            <meta charset="UTF-8">
            <meta name="viewport"
                  content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
            <meta http-equiv="X-UA-Compatible" content="ie=edge">
            <title>播放http-flv</title>
          </head>
          <body>
          <video id="videoElement"></video>
          <script src="https://cdn.bootcdn.net/ajax/libs/flv.js/1.6.2/flv.min.js"></script>
          <script>
            if (flvjs.isSupported()) {
                const videoElement = document.getElementById('videoElement');
                const flvPlayer = flvjs.createPlayer({
                  type: 'flv',
                  url: 'http://127.0.0.1:18080/live?port=1935&app=liveapp&stream=test&token=tokenValue'
                });
                flvPlayer.attachMediaElement(videoElement);
                flvPlayer.load();
                flvPlayer.play();
          	}
          </script>
          </body>
          </html>

          7、大功告成


          主站蜘蛛池模板: 色噜噜狠狠一区二区三区| 国产精品毛片a∨一区二区三区| 精品无码人妻一区二区三区18| 精品国产日韩亚洲一区91| 国产午夜精品一区二区三区嫩草| 激情亚洲一区国产精品| 久久久精品日本一区二区三区| 日韩高清一区二区| 国产乱码一区二区三区四| 国产一区二区三区不卡观| 一区二区视频免费观看| 亚洲码欧美码一区二区三区| 99久久精品国产一区二区成人 | 久久综合精品国产一区二区三区| 国产一区二区草草影院| 精品国产一区二区三区久久久狼| 高清一区二区三区日本久| 国产成人无码AV一区二区| 国产成人精品一区二区三区| 无码日韩人妻AV一区免费l| 国产MD视频一区二区三区| 狠狠做深爱婷婷久久综合一区 | 一区二区三区免费电影| 国产一区高清视频| 无码日韩人妻AV一区免费l| 一区二区不卡视频在线观看| 福利一区二区在线| 亚洲男人的天堂一区二区| 动漫精品专区一区二区三区不卡| 免费国产在线精品一区| 亚洲午夜日韩高清一区| 精品人妻少妇一区二区三区| av无码精品一区二区三区四区| 国产精品无码不卡一区二区三区| 国产精久久一区二区三区| 日本一区二区三区高清| 亚洲AV无码一区二区三区DV| 亚洲天堂一区在线| 在线电影一区二区三区| 合区精品久久久中文字幕一区 | 精品午夜福利无人区乱码一区|