Kurento KMS 流媒体服务器 webRTC转rtmp http flv

摘要:
rtmpsinksync=错误位置=rtmp://192.168.16.133/live/550004通道https://localhost:8443/,网页启动启动webrtc。5.打开网站播放:https://ossrs.net/players/srs_player.html输入srs播放器的url:http://192.168.16.133:8000/live/55000.flv或rmtp地址rtmp://192.168.16.133/live/55000kurentoc源代码修改后生效:1.重新执行/bin/kms构建运行。sh2.页面https://localhost:8443/#,执行stop,然后开始3。查看播放地址,数字+2。例如:http://192.168.16.133:8000/live/55004.flv具体方法见以下介绍:流媒体服务介绍https://blog.csdn.net/qq_28880087/article/details/106604113KMSKurento是构建WebRTC应用程序的底层平台。

webRTC ==(通过nodejs指定的sdp,这个sdp写的要与webrtc源一致)==》 RTP ==》RTMP

各种推流方法:https://www.cnblogs.com/bigben0123/p/14188475.html

整个启动流程:

1,启动kurento服务:

~/kms/kms-omni-build$ ./bin/kms-build-run.sh
若以前启动了,先停止
sudo service kurento-media-server  stop

2,启动虚拟摄像头。用抓取桌面录屏,输出到虚拟摄像头

sudo depmod -a
sudo modprobe v4l2loopback
ffmpeg -f x11grab -r 15 -s 1280x720 -i :0.0+0,0 -vcodec rawvideo -pix_fmt yuv420p -threads 0 -f v4l2 /dev/video0

无限循环推流:-stream_loop -1  无限次; 0是不循环;

ffmpeg -re  -stream_loop -1  -i ./doc/source.200kbps.768x320.flv  -f v4l2 /dev/video0

3,启动nodejs 服务,http 端口在8000

~/dev/kurento-rtmp$ npm start

3.1 如果nodejs不推流,自己推:

gst-launch-1.5 -em 
  rtpbin name=rtpbin latency=5 
  udpsrc port=5003 caps="application/x-rtp,media=(string)audio,clock-rate=(int)48000,encoding-name=(string)OPUS" ! rtpbin.recv_rtp_sink_0 
    rtpbin.  ! rtpopusdepay ! opusdec !  audioconvert ! audioresample ! voaacenc ! aacparse ! mux. 
  udpsrc port=5004 caps="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H264" ! rtpbin.recv_rtp_sink_1 
    rtpbin.  ! rtph264depay ! h264parse ! mux. 
  flvmux name=mux streamable=true ! rtmpsink sync=false location=rtmp://192.168.16.133/live/55000

4,访问 https://localhost:8443/ ,网页start启动webrtc。

5,打开网址播放:https://ossrs.net/players/srs_player.html

在srs播放器中url中输入:

http://192.168.16.133:8000/live/55000.flv 

或者是rmtp地址 

rtmp://192.168.16.133/live/55000

Kurento KMS 流媒体服务器 webRTC转rtmp http flv第1张

 kurento c源码修改后,生效:

1,重新执行 

       ./bin/kms-build-run.sh

2,页面https://localhost:8443/#,执行stop,然后再start

3,看播放地址,数字+2. 比如:http://192.168.16.133:8000/live/55004.flv

具体方法见如下介绍: 


流媒体服务介绍https://blog.csdn.net/qq_28880087/article/details/106604113 

KMS 流媒体服务器源码安装(https://doc-kurento.readthedocs.io/en/latest/dev/dev_guide.html)

 Kurento是一个底层平台取搭建WebRTC应用。需要自己管理 STUN/TURN servers, networking, scalability, etc. 新手建议用OpenVidu 是基于Kurento的开源应用.

官方示例:https://doc-kurento.readthedocs.io/en/latest/user/tutorials.html

支持java,browser js,nodejs。

1,官方只支持 Long-Term Support (LTS)Ubuntu: Ubuntu 16.04 (Xenial) and Ubuntu 18.04 (Bionic) (64-bits only).

18.04的源:https://blog.csdn.net/qq_40584960/article/details/82950511

题外话:

ubuntu的更新注意选择自己的版本,比如19.10的话得是eoan

ubuntu源站:https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/ 

Kurento KMS 流媒体服务器 webRTC转rtmp http flv第2张Kurento KMS 流媒体服务器 webRTC转rtmp http flv第3张
#163源
deb http://mirrors.163.com/ubuntu/ eoan main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ eoan-security main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ eoan-updates main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ eoan-proposed main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ eoan-backports main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ eoan main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ eoan-security main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ eoan-updates main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ eoan-proposed main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ eoan-backports main restricted universe multiverse
View Code

Install required tools

This command will install the basic set of tools that are needed for the next steps:

sudo apt-get update && sudo apt-get install --no-install-recommends --yes 
    build-essential 
    ca-certificates 
    cmake 
    git 
    gnupg

Add Kurento repository

Run these commands to add the Kurento repository to your system configuration:

# Import the Kurento repository signing key
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 5AFA7A83

# Get Ubuntu version definitions
source /etc/upstream-release/lsb-release 2>/dev/null || source /etc/lsb-release

# Add the repository to Apt
sudo tee "/etc/apt/sources.list.d/kurento.list" >/dev/null <<EOF
# Kurento Media Server - Nightly packages
deb [arch=amd64] http://ubuntu.openvidu.io/dev $DISTRIB_CODENAME kms6
EOF

sudo apt-get update

Install build dependencies

Run:更新编译依赖包,包括jdk等

sudo apt-get update && sudo apt-get install --no-install-recommends --yes 
    kurento-media-server-dev

Download KMS source code

Run:

git clone https://github.com/Kurento/kms-omni-build.git
cd kms-omni-build
git submodule update --init --recursive
git submodule update --remote

Note

--recursive and --remote are not used together, because each individual submodule may have their own submodules that might be expected to check out some specific commit, and we don’t want to update those.

OPTIONAL: Change to the master branch of each submodule, if you will be working with the latest version of the code:

REF=master
git checkout "$REF" || true
git submodule foreach "git checkout $REF || true"

You can also set REF to any other branch or tag, such as REF=6.12.0. This will bring the code to the state it had in that version release.

Install build dependencies 这个步骤原文档在下载源码前面执行。需要在这里再次运行一次!编译就没问题。

Run:更新编译依赖包,包括jdk等

sudo apt-get update && sudo apt-get install --no-install-recommends --yes 
    kurento-media-server-dev

Build and run KMS 编译并运行

Make sure your current directory is already kms-omni-build, then run this command:

export MAKEFLAGS="-j$(nproc)"
./bin/kms-build-run.sh

By default, the script kms-build-run.sh will set up the environment and settings to make a Debug build of KMS. You can inspect that script to learn about all the other options it offers, including builds for AddressSanitizer, selection between GCC and Clang compilers, and other modes.

You can set the logging level of specific categories by exporting the environment variable GST_DEBUG before running this script (see Debug Logging).

手动启动/停止

sudo service kurento-media-server start

sudo service kurento-media-server stop

1
缺软件:
sudo apt install pkg-config

2.
gedit ./bin/kms-build-run.sh 450行

# System limits: Set maximum open file descriptors
# Maximum limit value allowed by Ubuntu: 2^20 = 1048576
ulimit -n 1048576

报错ulimit没有权限。

3.

启动时无法开启端口:端口占用了,查看sudo netstat -atunp | more

0:00:00.163066989 2905 0x558b6ba5df50 ERROR KurentoWebSocketTransport WebSocketTransport.cpp:156:initWebSocket: WebSocket error: cannot listen on IPv6 port 8888 (Underlying Transport Error), will try IPv4
0:00:00.163147556 2905 0x558b6ba5df50 ERROR KurentoWebSocketTransport WebSocketTransport.cpp:166:initWebSocket: WebSocket error: cannot listen on IPv4 port 8888 (Underlying Transport Error)


搭建编译环境:

docker安装:https://blog.csdn.net/a346492443/article/details/106355273/

docker权限问题:

Kurento KMS 流媒体服务器 webRTC转rtmp http flv第4张Kurento KMS 流媒体服务器 webRTC转rtmp http flv第5张
sudo groupadd docker     #添加docker用户组
sudo gpasswd -a $USER docker     #将登陆用户加入到docker用户组中
newgrp docker     #更新用户组
docker ps    #测试docker命令是否可以使用sudo正常使用
View Code

kms拉取docker和启动

Kurento KMS 流媒体服务器 webRTC转rtmp http flv第6张Kurento KMS 流媒体服务器 webRTC转rtmp http flv第7张
docker pull kurento/kurento-media-server:latest

docker run -d --name kms --network host 
    kurento/kurento-media-server:latest

获取log:
docker logs --follow kms >"kms-$(date '+%Y%m%dT%H%M%S').log" 2>&1
View Code

构建包:

--install-kurento将自动安装依赖包
git clone https://github.com/Kurento/adm-scripts.git
git clone https://github.com/Kurento/kms-core.git
cd kms-core/
../adm-scripts/kurento-buildpackage.sh 
    --install-kurento 6.12.0 
    --apt-add-repo

通过docker的image构建 kms模块:kurento-buildpackage Docker image

可以创建不同包对不同Ubuntu版本。

使用kurento-buildpackage Docker image,出了隐射源码目录到 /hostdir其他操作和本地编译一样。

比如构建kms-core development branch against Kurento 6.12.0, for Ubuntu 16.04 (Xenial) systems. 

git clone https://github.com/Kurento/kms-core.git
cd kms-core/
docker run --rm 
    --mount type=bind,src="$PWD",dst=/hostdir 
    kurento/kurento-buildpackage:xenial 
        --install-kurento 6.12.0 
        --apt-add-repo

https://www.oschina.net/project/tag/111/streaming

Delivery HTTP FLV Stream

利用peerjs轻松玩转webrtc

webrtc笔记(4): kurento 部署

webrtc笔记(3): 多人视频通讯常用架构Mesh/MCU/SFU

webrtc笔记(1): 基于coturn项目的stun/turn服务器搭建

webrtc笔记(2): 1对1实时视频/语音通讯原理概述

webrtc笔记(5): 基于kurento media server的多人视频聊天示例

flyhelloword的博客_CSDN博客-Linux,Kurento,笔记领域博主

Kurento- Kurento Java Tutorial - kurento-magic-mirror Could not Run Successfully, Why?_flyhelloword的博客-CSDN博客 编译执行

webrtc的开源实现,搭建本地的流媒体服务器,进行rtsp视频流转发,如果可以再叠加一些机器视觉的内容。本篇内容主要解决如何在本地虚拟服务器unbuntu搭建kurento-media-server。

kurentu-media-server是什么?这是一个基于webrtc协议的开源实现。类似其他的开源项目可以参考https://yq.aliyun.com/articles/611978。每个项目都有各自的特点。通过kurentu-media-server逐步切入webrtc,搭建自己的流媒体服务器,关于kurentu与rtsp请戳这里https://www.kurento.org/tags/rtsp

网上教程很多,推荐一个个人感觉很好的https://blog.csdn.net/hyl999/article/details/100176218

官网环境提供了可供测试的java demo。https://github.com/Kurento/kurento-tutorial-java。如何搭建测试环境,可以参考这里https://blog.csdn.net/llhswwha/article/details/102896066

另外一种测试方法在这里https://github.com/lulop-k/kurento-rtsp2webrtc。这个是基于js的前端项目。与人通过这个项目,接入了海康摄像头,感兴趣可以戳这里https://blog.csdn.net/Beihangxiaobao/article/details/89450250。关于与摄像头的详细交互逻辑,原理可以参考这里https://blog.csdn.net/biaobro/article/details/66968518https://blog.csdn.net/qq_32523587/article/details/89041326。这里还有一个关于公网打洞穿透的案例,没试过https://blog.csdn.net/zsj777/article/details/81784256

关于延迟,这里有一篇完美解决了延迟的问题。https://www.cnblogs.com/lanqie/p/8510634.html


  •  HTTP-FLV部分
/http-flv http-flv/README_CN.md at master · mugennsou/http-flv (github.com)

nginx-http-flv-module/README.CN.md at master · winshining/nginx-http-flv-module (github.com)

下载docker镜像:
docker pull mugennsou/nginx-http-flv

运行流媒体服务器:
docker run --rm -it -p 80:80 -p 1935:1935 mugennsou/nginx-http-flv

往指定的服务器推流
ffmpeg -re -i ~/Videos/b.mp4  -c copy -f flv  rtmp://127.0.0.1/demo/stream-1

访问
 http://127.0.0.1

Ubuntu安装ffmpeg: sudo apt-get install ffmpeg

srs推流:

RTMP使用Frame,即帧级别对象。
RTC使用RTP,即包级别对象,Video Frame可能会包含多个RTP packet。
RTMP转RTC,使用Bridger,这样使RTMP和RTC的逻辑相对独立。
RTC下行NACK和PLI都支持,上行NACK还未支持,能跑通了。

详细改动可以参考:c768a8c...3cb797d

https://blog.csdn.net/lixiang987654321/article/details/108714690

webRTC推流 视频教学:https://www.bilibili.com/video/av800024876/

SRS文档:

https://github.com/ossrs/srs/tree/4.0release
https://github.com/ossrs/srs/wiki/v4_CN_Home

源码编译:

国内:
1,
源码克隆
git clone https://gitee.com/winlinvip/srs.oschina.git srs &&
cd srs/trunk && git remote set-url origin https://github.com/ossrs/srs.git && git pull
2,
转到最新4.0开发版,因要使用webRTC
git checkout 4.0release

3,–rtc=on 默认
./configure --with-hls --with-ssl --with-http-server --with-http-callback --with-http-api --with-ingest --with-stream-caster && make 

 

成功后显示:

Kurento KMS 流媒体服务器 webRTC转rtmp http flv第8张Kurento KMS 流媒体服务器 webRTC转rtmp http flv第9张
Generate Makefile
Configure ok! 

Configure summary:
     --x86-x64 --with-hls --with-ssl --with-http-server --with-http-callback --with-http-api --with-ingest --with-stream-caster
     --prefix=/usr/local/srs --hls=on --hds=off --dvr=on --ssl=on --https=on --ssl-1-0=off --sys-ssl=off --transcode=on --ingest=on --stat=on --http-callback=on --http-server=on --stream-caster=on --http-api=on --utest=off --srt=off --rtc=on --simulator=off --gb28181=off --cxx11=off --cxx14=off --ffmpeg-fit=on --nasm=off --srtp-nasm=off --sendmmsg=off --clean=on --gperf=off --gmc=off --gmd=off --gmp=off --gcp=off --gprof=off --log-trace --cc=gcc --cxx=g++ --ar=ar --ld=ld --randlib=randlib
HLS is enabled.
Experiment: StreamCaster is enabled.
Warning: HDS is disabled.
Warning: SRT is disabled.
Experiment: RTC is enabled. https://github.com/ossrs/srs/issues/307
Experiment: HTTPS is enabled. https://github.com/ossrs/srs/issues/1657
DVR is enabled.
RTMP complex handshake is enabled
The transcoding is enabled
The ingesting is enabled.
The http-callback is enabled
Embeded HTTP server for HTTP-FLV/HLS is enabled.
The HTTP API is enabled
Note: The utests are disabled.
Note: The gperf(tcmalloc) is disabled.
Note: The gmc(gperf memory check) is disabled.
Note: The gmd(gperf memory defense) is disabled.
Note: The gmp(gperf memory profile) is disabled.
Note: The gcp(gperf cpu profile) is disabled.
Note: The gprof(GNU profile tool) is disabled.
Note: The valgrind is disabled.
Enable module: modules/hls-ingester
Enable module: modules/mp4-parser
Do full cleanup, you can disable it by: --clean=off
You can clean each some components, see make help

You can run 3rdparty applications:
" python ./research/api-server/server.py 8085  " to start the api-server

You can build SRS:
" make " to build the srs(simple rtmp server).
" make help " to get the usage of make
View Code
Kurento KMS 流媒体服务器 webRTC转rtmp http flv第10张Kurento KMS 流媒体服务器 webRTC转rtmp http flv第11张
make _default
make[1]: Entering directory '/home/zhibin/dev/srs/trunk'
Build the srs(simple rtmp server) over ST(state-threads)
make -f objs/Makefile srs
make[2]: Entering directory '/home/zhibin/dev/srs/trunk'
make[2]: Nothing to be done for 'srs'.
make[2]: Leaving directory '/home/zhibin/dev/srs/trunk'
Ignore utest for it's disabled.
Build the srs_hls_ingester over SRS
make -f objs/Makefile srs_hls_ingester
make[2]: Entering directory '/home/zhibin/dev/srs/trunk'
make[2]: Nothing to be done for 'srs_hls_ingester'.
make[2]: Leaving directory '/home/zhibin/dev/srs/trunk'
Build the srs_mp4_parser over SRS
make -f objs/Makefile srs_mp4_parser
make[2]: Entering directory '/home/zhibin/dev/srs/trunk'
make[2]: Nothing to be done for 'srs_mp4_parser'.
make[2]: Leaving directory '/home/zhibin/dev/srs/trunk'
The build summary:
     +------------------------------------------------------------------------------------
     For SRS benchmark, gperf, gprof and valgrind, please read:
          http://blog.csdn.net/win_lin/article/details/53503869
     +------------------------------------------------------------------------------------
     |The main server usage: ./objs/srs -c conf/srs.conf, start the srs server
     |     About HLS, please read https://github.com/ossrs/srs/wiki/v2_CN_DeliveryHLS
     |     About DVR, please read https://github.com/ossrs/srs/wiki/v3_CN_DVR
     |     About SSL, please read https://github.com/ossrs/srs/wiki/v1_CN_RTMPHandshake
     |     About transcoding, please read https://github.com/ossrs/srs/wiki/v3_CN_FFMPEG
     |     About ingester, please read https://github.com/ossrs/srs/wiki/v1_CN_Ingest
     |     About http-callback, please read https://github.com/ossrs/srs/wiki/v3_CN_HTTPCallback
     |     Aoubt http-server, please read https://github.com/ossrs/srs/wiki/v2_CN_HTTPServer
     |     About http-api, please read https://github.com/ossrs/srs/wiki/v3_CN_HTTPApi
     |     About stream-caster, please read https://github.com/ossrs/srs/wiki/v2_CN_Streamer
     |     (Disabled) About VALGRIND, please read https://github.com/ossrs/state-threads/issues/2
     +------------------------------------------------------------------------------------
binaries, please read https://github.com/ossrs/srs/wiki/v2_CN_Build
You can:
      ./objs/srs -c conf/srs.conf
                  to start the srs server, with config conf/srs.conf.
make[1]: Leaving directory '/home/zhibin/dev/srs/trunk'
View Code

运行 输出webRTC(参考:https://github.com/ossrs/srs/issues/307):

 ./objs/srs -c conf/rtc.conf 
[2020-12-14 16:57:41.108][Trace][38868][34doo9ww] XCORE-SRS/4.0.56(Leo)
[2020-12-14 16:57:41.108][Trace][38868][34doo9ww] config parse complete
[2020-12-14 16:57:41.108][Trace][38868][34doo9ww] you can check log by: tail -f ./objs/srs.log (@see https://github.com/ossrs/srs/wiki/v1_CN_SrsLog)
[2020-12-14 16:57:41.108][Trace][38868][34doo9ww] please check SRS by: ./etc/init.d/srs status

用FFMPEG或OBS推送RTMP流到服务器:

  用rtmp来传输flv流:

ffmpeg -re -i doc/source.200kbps.768x320.flv -c copy 
    -f flv -y rtmp://192.168.1.3/live/livestream

obs的界面设置,后面的串流密钥a.flv是要接到url就可以观看了。
Kurento  KMS 流媒体服务器 webRTC转rtmp http flv第12张

播放器中url写: http://localhost:8000/live/a.flv

 flv播放器h5源码:

Kurento KMS 流媒体服务器 webRTC转rtmp http flv第13张Kurento KMS 流媒体服务器 webRTC转rtmp http flv第14张
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>    
        <script src="https://cdn.bootcss.com/flv.js/1.4.0/flv.min.js"></script>
        <video id="videoElement" style=" 80%;" controls="controls"></video>
        <script>
            if (flvjs.isSupported()) {
                var videoElement = document.getElementById('videoElement');
                var flvPlayer = flvjs.createPlayer({
                    type: 'flv',
                    url:'http://localhost:8000/live/a.flv' 
                });
                flvPlayer.attachMediaElement(videoElement);
                flvPlayer.load();
                flvPlayer.play();
            }
        </script>
    </body>
</html>
View Code
成功时显示:
Kurento KMS 流媒体服务器 webRTC转rtmp http flv第15张Kurento KMS 流媒体服务器 webRTC转rtmp http flv第16张
推摄像头通过rtmp推流
ffmpeg -f dshow -i video="HD Camera":audio="麦克风阵列 (Realtek(R) Audio)" -vcodec libx264 -x264opts "bframes=0"  -r 25 -g 25 -preset:v ultrafast -tune:v zerolatency -codec:a aac -ac 2 -ar 44100 -f flv rtmp://192.168.50.150:1935/live/1 
View Code

webRTC推流:https://ossrs.net/players/srs_player.html 这个页面都有包括播放,推流。 

推流拉流工具ffmpeg,obs界面 方法:https://cloud.tencent.com/developer/article/1505068

sudo add-apt-repository ppa:obsproject/obs-studio
sudo apt update
sudo apt install obs-studio

可播放的流地址:

播放验证,用网页的播放器直接播放:https://ossrs.net/players/srs_player.html 输入网址即可播放 webrtc rtmp等


 ubuntu 虚拟机下使用摄像头

:把usb2.0改成3.0;或者相反。等了半天,突然好了。https://blog.csdn.net/xiaozi0221/article/details/79135930?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control

 没有摄像头用虚拟摄像头:ubuntu 虚拟摄像头 模拟摄像头 virtualCam - Bigben - 博客园 (cnblogs.com) 在vlc,cheese都打不开虚拟摄像头:no device found。

后来运行kurento的helloworld示例,先推流到虚拟摄像头:

 ffmpeg -re -i ./doc/source.200kbps.768x320.flv  -f v4l2 /dev/video0

在firefox里面可以获取到虚拟摄像头了

Kurento KMS 流媒体服务器 webRTC转rtmp http flv第19张


 开源项目 webRTC 转成 RTMP输出

这个项目基于kurento tutorial的hello world构建。

项目地址:https://github.com/godka/kurento-rtmp  

sdp是个文本文件,vlc拿到后可以直接直播。 

原理是摄像头采集webRTC的,发送到kurento服务器。nodejs server充当kurento的客户端,接收sdp offer,根据offer生成自定义得sdp,ffmpeg将sdp和rtp://xxx内容用rtmp推到流媒体服务器node_media_server.

(

sdp是描述RTP包的信息包文件,需要手动加入时间戳等信息,并且在打包rtp时填写。代码实现是,你调用ffmpeg库的函数接口,打包sdp头信息,并将视频数据打包称rtp,然后发送到http://xxxxxx

udp:
推送:ffmpeg -re -i test.264 -vcodec copy -f h264 udp://10.0.192.82:6970

拉取:ffplay -f h264 udp://10.0.192.82:6970

rtp:
ffmpeg -re -i test.264 -vcodec copy -f rtp rtp://10.0.192.82:6970>test.sdp  
ffplay test.sdp

  )

从页面采集摄像头数据用webRTC,通过ws发送到服务端。在 webRtcEndpoint.processOffer处理客户端发来得sdp offer。我们自己生成 rtp的sdpRtpOfferString,将它传递给rtp的

rtpEndpoint.processOffer(sdpRtpOfferString处理。成功后启动ffmpeg,对这个sdpRtpOfferString作为 -i的参数做发送到rtmp服务,即nodejs的Node-Media-Server。这样就可以用http flv播放了。 
  1. 构建:

1.install node && npm  需要nodejs npm安装:https://www.cnblogs.com/schips/p/12402412.html
2.git clone https://github.com/godka/kurento-rtmp
3.cd kurento-rtmp
4.npm install
5.node server.js
6.Open https://yourhost:8443 on Chrome or Firefox
7.Click Start button and have fun!

也可以参考kurento tutorial的hello world安装:

Be sure to install Bower and Node.js version 8.x in your system. In an Ubuntu machine, you can install both as follows:

curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
sudo apt-get install -y nodejs
sudo npm install -g bower

Also, Node.js should already include NPM, the Node.js package manager.

To launch the application, you need to clone the GitHub project where this demo is hosted, install it and run it:

git clone https://github.com/Kurento/kurento-tutorial-node.git
cd kurento-tutorial-node/kurento-hello-world
git checkout master
npm install
cd static
bower install --allow-root
cd ..
npm start

If you have problems installing any of the dependencies, please remove them and clean the npm cache, and try to install them again:

rm -r node_modules
npm cache clean

Access the application connecting to the URL https://localhost:8443/ in a WebRTC capable browser (Chrome, Firefox).

Note

These instructions work only if Kurento Media Server is up and running in the same machine as the tutorial. However, it is possible to connect to a remote KMS in other machine, simply adding the argument ws_uri to the npm execution command, as follows:

npm start -- --ws_uri=ws://{KMS_HOST}:8888/kurento

In this case you need to use npm version 2. To update it you can use this command:

sudo npm install npm -g

观看rmtp地址:

启动后,推webrtc地址:https://localhost:8443/.

如果不能回显,去https://ossrs.net/players/srs_player.html,在srs播放器里面地址输入:rtmp://192.168.16.133/live/127.0.0.1_55002,可以播放。地址是从下面log中找到的:

Kurento KMS 流媒体服务器 webRTC转rtmp http flv第20张

修改server.js,推流地址变成rtmp://192.168.16.133/live/55002,去掉127.0.0.1_

不用搭建srs,直接用播放器访问http flv地址,即可播放:http://192.168.16.133:8000/live/55002.flv 

server.js是服务器. 这个开源用了Node-Media-Server。它是支持rtmp,http flv等的流媒体服务器。

ffmpeg推流用的命令  用sdp生成rtp命令

/*ffmpeg 
-protocol_whitelist "file,udp,rtp" 
-i test.sdp 
-vcodec copy 
-f flv 
rtmp://localhost/live/stream
*/
/*
SDP:
v=0
o=- 0 0 IN IP4 127.0.0.1
s=No Name
c=IN IP4 127.0.0.1
t=0 0
a=tool:libavformat 57.71.100
m=video 55000 RTP/AVP 96
b=AS:200
a=rtpmap:96 H264/90000
*/

 实现回显:webrtc连接成功后,rtp再去回连webrtc。这样就回显。

function connectMediaElements(webRtcEndpoint, rtpEndpoint, callback) {
    webRtcEndpoint.connect(rtpEndpoint, function (error) {
        if (error) {
            return callback(error);
        }
        rtpEndpoint.connect(webRtcEndpoint, function (error) {//rtpEndPoint又连接回去webRTC
            if (error) {
                return callback(error);
            }
            return callback(null);
        });
    });
}

配置sdpStream类型, H264,这里时为了生成 rtp

function generateSdpStreamConfig(nodeStreamIp, port, callback) {
... ...
    var sdpRtpOfferString = 'v=0
';
    sdpRtpOfferString += 'o=- 0 0 IN IP4 ' + nodeStreamIp + '
';
    sdpRtpOfferString += 's=KMS
';
    sdpRtpOfferString += 'c=IN IP4 ' + nodeStreamIp + '
';
    sdpRtpOfferString += 't=0 0
';
    sdpRtpOfferString += 'm=video ' + port + ' RTP/AVP 96
';
    sdpRtpOfferString += 'a=rtpmap:96 H264/90000
';
    sdpRtpOfferString += 'a=fmtp:96 packetization-mode=1
';
    return callback(null, sdpRtpOfferString);

增加音频处理部分

    sdpRtpOfferString += 'm=audio 49170 RTP/AVP 97
' ;
              sdpRtpOfferString += 'a=recvonly
' ;
              sdpRtpOfferString += 'a=rtpmap:97 PCMU/8000
' ;
              sdpRtpOfferString += 'a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=1508
' ;

在rtpEndpoint.processOffer去使用:

webrtc连接成功 => rtc.processOffer => 成功后按照sdp config 调用 rtp.processOffer =>callback(sdpanswer):

                     
webRtcEndpoint.processOffer(sdpOffer, function (error, sdpAnswer) { if (error) { pipeline.release(); return callback(error); } sessions[sessionId] = { 'pipeline': pipeline, 'webRtcEndpoint': webRtcEndpoint } var streamPort = 55000;
//每个新session会调用这里一次
var streamIp = '127.0.0.1';//Test ip generateSdpStreamConfig(streamIp, streamPort, function (err, sdpRtpOfferString) { if (err) { return callback(error); } rtpEndpoint.processOffer(sdpRtpOfferString, function (error) { if (error) { return callback(error); } console.log('start process on: rtp://' + streamIp + ':' + streamPort); console.log('recv sdp answer:', sdpAnswer);
bindFFmpeg(streamIp, streamPort, sdpRtpOfferString, ws)
return callback(null, sdpAnswer); }); }); })

加入session 和 ffmpeg:

全局
var session_index = 0;

用户连接端口生成:

                        //对于RTP,偶数端口被用来传输数据,奇数端口用来传输RTCP包
                        var streamPort = 55000 + (session_index * 2);
                        var audioPort = 49170 + (session_index * 2);
                        session_index++;    //change to next port

webRtcEndpoint.setMaxVideoRecvBandwidth(200)

node-media-server加入rtmp,flv

const NodeMediaServer = require('node-media-server').NodeMediaServer
const rtmp_server_config = {
    rtmp: {
        port: 1935,
        chunk_size: 60000,
        gop_cache: true,
        ping: 60,
        ping_timeout: 30
    },
    http: {
        port: 8000,
        allow_origin: '*'
    }
};

var nms = new NodeMediaServer(rtmp_server_config);
nms.run();

 整体流程图:

Kurento KMS 流媒体服务器 webRTC转rtmp http flv第21张

 浏览器console log

Kurento KMS 流媒体服务器 webRTC转rtmp http flv第22张Kurento KMS 流媒体服务器 webRTC转rtmp http flv第23张
    Page loaded ...
    Starting video call ...
    Creating WebRtcPeer and generating local sdp offer ...
    Invoking SDP offer callback function localhost:8443
    Senging message: {"id":"start","sdpOffer":"v=0
o=mozilla...THIS_IS_SDPARTA-84.0 5506570539139251894 0 IN IP4 0.0.0.0
s=-
t=0 0
a=sendrecv
a=fingerprint:sha-256 29:61:0D:7A:36:FF:4B:99:D1:E3:A9:D2:56:41:94:71:E5:D0:B3:2C:DB:AE:AE:9D:16:0C:72:98:7E:20:4E:F2
a=group:BUNDLE 0 1
a=ice-options:trickle
a=msid-semantic:WMS *
m=audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8 101
c=IN IP4 0.0.0.0
a=sendrecv
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2/recvonly urn:ietf:params:rtp-hdrext:csrc-audio-level
a=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid
a=fmtp:109 maxplaybackrate=48000;stereo=1;useinbandfec=1
a=fmtp:101 0-15
a=ice-pwd:239b6871bcbb276ba438d4dd7ed5313c
a=ice-ufrag:a63a1363
a=mid:0
a=msid:{57bf1af5-7e10-4d79-a5b5-f5156b287579} {82c931b1-6d49-4fbd-9d2a-e0067b1a360d}
a=rtcp-mux
a=rtpmap:109 opus/48000/2
a=rtpmap:9 G722/8000/1
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=setup:actpass
a=ssrc:3699747540 cname:{ac21087a-d493-46e3-a657-d4ee4e1bc9cb}
m=video 9 UDP/TLS/RTP/SAVPF 120 124 121 125 126 127 97 98
c=IN IP4 0.0.0.0
a=sendrecv
a=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:4 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:5 urn:ietf:params:rtp-hdrext:toffset
a=extmap:6/recvonly http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=extmap:7 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=fmtp:126 profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1
a=fmtp:97 profile-level-id=42e01f;level-asymmetry-allowed=1
a=fmtp:120 max-fs=12288;max-fr=60
a=fmtp:124 apt=120
a=fmtp:121 max-fs=12288;max-fr=60
a=fmtp:125 apt=121
a=fmtp:127 apt=126
a=fmtp:98 apt=97
a=ice-pwd:239b6871bcbb276ba438d4dd7ed5313c
a=ice-ufrag:a63a1363
a=mid:1
a=msid:{57bf1af5-7e10-4d79-a5b5-f5156b287579} {c938a455-1129-42bf-8442-f28deb1226ad}
a=rtcp-fb:120 nack
a=rtcp-fb:120 nack pli
a=rtcp-fb:120 ccm fir
a=rtcp-fb:120 goog-remb
a=rtcp-fb:120 transport-cc
a=rtcp-fb:121 nack
a=rtcp-fb:121 nack pli
a=rtcp-fb:121 ccm fir
a=rtcp-fb:121 goog-remb
a=rtcp-fb:121 transport-cc
a=rtcp-fb:126 nack
a=rtcp-fb:126 nack pli
a=rtcp-fb:126 ccm fir
a=rtcp-fb:126 goog-remb
a=rtcp-fb:126 transport-cc
a=rtcp-fb:97 nack
a=rtcp-fb:97 nack pli
a=rtcp-fb:97 ccm fir
a=rtcp-fb:97 goog-remb
a=rtcp-fb:97 transport-cc
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:120 VP8/90000
a=rtpmap:124 rtx/90000
a=rtpmap:121 VP9/90000
a=rtpmap:125 rtx/90000
a=rtpmap:126 H264/90000
a=rtpmap:127 rtx/90000
a=rtpmap:97 H264/90000
a=rtpmap:98 rtx/90000
a=setup:actpass
a=ssrc:1800212177 cname:{ac21087a-d493-46e3-a657-d4ee4e1bc9cb}
a=ssrc:4032663199 cname:{ac21087a-d493-46e3-a657-d4ee4e1bc9cb}
a=ssrc-group:FID 1800212177 4032663199
"}
    Local candidate{"candidate":"candidate:0 1 UDP 2122252543 192.168.16.133 36689 typ host","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:0 1 UDP 2122252543 192.168.16.133 36689 typ host","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:3 1 UDP 2122187007 172.17.0.1 48337 typ host","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:3 1 UDP 2122187007 172.17.0.1 48337 typ host","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:6 1 TCP 2105524479 192.168.16.133 9 typ host tcptype active","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:6 1 TCP 2105524479 192.168.16.133 9 typ host tcptype active","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:7 1 TCP 2105458943 172.17.0.1 9 typ host tcptype active","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:7 1 TCP 2105458943 172.17.0.1 9 typ host tcptype active","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:0 2 UDP 2122252542 192.168.16.133 45262 typ host","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:0 2 UDP 2122252542 192.168.16.133 45262 typ host","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:3 2 UDP 2122187006 172.17.0.1 34010 typ host","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:3 2 UDP 2122187006 172.17.0.1 34010 typ host","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:6 2 TCP 2105524478 192.168.16.133 9 typ host tcptype active","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:6 2 TCP 2105524478 192.168.16.133 9 typ host tcptype active","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:7 2 TCP 2105458942 172.17.0.1 9 typ host tcptype active","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:7 2 TCP 2105458942 172.17.0.1 9 typ host tcptype active","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:0 1 UDP 2122252543 192.168.16.133 33211 typ host","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:0 1 UDP 2122252543 192.168.16.133 33211 typ host","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:3 1 UDP 2122187007 172.17.0.1 36771 typ host","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:3 1 UDP 2122187007 172.17.0.1 36771 typ host","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:6 1 TCP 2105524479 192.168.16.133 9 typ host tcptype active","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:6 1 TCP 2105524479 192.168.16.133 9 typ host tcptype active","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:7 1 TCP 2105458943 172.17.0.1 9 typ host tcptype active","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:7 1 TCP 2105458943 172.17.0.1 9 typ host tcptype active","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:0 2 UDP 2122252542 192.168.16.133 50483 typ host","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:0 2 UDP 2122252542 192.168.16.133 50483 typ host","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:3 2 UDP 2122187006 172.17.0.1 57105 typ host","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:3 2 UDP 2122187006 172.17.0.1 57105 typ host","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:6 2 TCP 2105524478 192.168.16.133 9 typ host tcptype active","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:6 2 TCP 2105524478 192.168.16.133 9 typ host tcptype active","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:7 2 TCP 2105458942 172.17.0.1 9 typ host tcptype active","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:7 2 TCP 2105458942 172.17.0.1 9 typ host tcptype active","sdpMid":"1","sdpMLineIndex":1,"usernameFragment":"a63a1363"}}
    Recv rtmp request: '/live/55000'
    rtmp play url: 'rtmp://localhost/live/55000'
    {
    src: 'rtmp://localhost/live/55000'
    ,
    autoPlay: 'true'
    ,
    controlBarAutoHide: 'true'
    ,
    poster: 'img/adobe.jpg'
    ,
    javascriptCallbackFunction: 'jsbridge'
    }
    SDP answer received from server. Processing ...
    Local candidate{"candidate":"candidate:1 1 UDP 1686052863 103.85.173.226 64573 typ srflx raddr 192.168.16.133 rport 36689","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:1 1 UDP 1686052863 103.85.173.226 64573 typ srflx raddr 192.168.16.133 rport 36689","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:4 1 UDP 1685987327 103.85.173.226 64574 typ srflx raddr 172.17.0.1 rport 48337","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:4 1 UDP 1685987327 103.85.173.226 64574 typ srflx raddr 172.17.0.1 rport 48337","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:1 2 UDP 1686052862 103.85.173.226 64575 typ srflx raddr 192.168.16.133 rport 45262","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:1 2 UDP 1686052862 103.85.173.226 64575 typ srflx raddr 192.168.16.133 rport 45262","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"candidate:4 2 UDP 1685987326 103.85.173.226 64576 typ srflx raddr 172.17.0.1 rport 34010","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"candidate:4 2 UDP 1685987326 103.85.173.226 64576 typ srflx raddr 172.17.0.1 rport 34010","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}}
    Local candidate{"candidate":"","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}
    Senging message: {"id":"onIceCandidate","candidate":{"candidate":"","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"a63a1363"}}
View Code

nodejs server.js日志输出

Kurento KMS 流媒体服务器 webRTC转rtmp http flv第24张Kurento KMS 流媒体服务器 webRTC转rtmp http flv第25张
 node server.js 
2020-12-18 17:53:10 46724 [INFO] Node Media Server v1.5.1
Kurento Tutorial started
Open https://localhost:8443/ with a WebRTC capable browser
2020-12-18 17:53:10 46724 [INFO] Node Media Rtmp Server started on port: 1935
2020-12-18 17:53:10 46724 [INFO] Node Media Http Server started on port: 8000
2020-12-18 17:53:10 46724 [INFO] Node Media WebSocket Server started on port: 8000
2020-12-18 17:53:12 46724 [INFO] There is a new version 2.2.4 that can be updated
Connection received with sessionId mccsJ5SnNdTomRmCe19l4F1ZfW0E7162
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'start',
  sdpOffer: 'v=0
o=mozilla...THIS_IS_SDPARTA-84.0 5506570539139251894 0 IN IP4 0.0.0.0
s=-
t=0 0
a=sendrecv
a=fingerprint:sha-256 29:61:0D:7A:36:FF:4B:99:D1:E3:A9:D2:56:41:94:71:E5:D0:B3:2C:DB:AE:AE:9D:16:0C:72:98:7E:20:4E:F2
a=group:BUNDLE 0 1
a=ice-options:trickle
a=msid-semantic:WMS *
m=audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8 101
c=IN IP4 0.0.0.0
a=sendrecv
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2/recvonly urn:ietf:params:rtp-hdrext:csrc-audio-level
a=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid
a=fmtp:109 maxplaybackrate=48000;stereo=1;useinbandfec=1
a=fmtp:101 0-15
a=ice-pwd:239b6871bcbb276ba438d4dd7ed5313c
a=ice-ufrag:a63a1363
a=mid:0
a=msid:{57bf1af5-7e10-4d79-a5b5-f5156b287579} {82c931b1-6d49-4fbd-9d2a-e0067b1a360d}
a=rtcp-mux
a=rtpmap:109 opus/48000/2
a=rtpmap:9 G722/8000/1
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=setup:actpass
a=ssrc:3699747540 cname:{ac21087a-d493-46e3-a657-d4ee4e1bc9cb}
m=video 9 UDP/TLS/RTP/SAVPF 120 124 121 125 126 127 97 98
c=IN IP4 0.0.0.0
a=sendrecv
a=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:4 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:5 urn:ietf:params:rtp-hdrext:toffset
a=extmap:6/recvonly http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=extmap:7 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=fmtp:126 profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1
a=fmtp:97 profile-level-id=42e01f;level-asymmetry-allowed=1
a=fmtp:120 max-fs=12288;max-fr=60
a=fmtp:124 apt=120
a=fmtp:121 max-fs=12288;max-fr=60
a=fmtp:125 apt=121
a=fmtp:127 apt=126
a=fmtp:98 apt=97
a=ice-pwd:239b6871bcbb276ba438d4dd7ed5313c
a=ice-ufrag:a63a1363
a=mid:1
a=msid:{57bf1af5-7e10-4d79-a5b5-f5156b287579} {c938a455-1129-42bf-8442-f28deb1226ad}
a=rtcp-fb:120 nack
a=rtcp-fb:120 nack pli
a=rtcp-fb:120 ccm fir
a=rtcp-fb:120 goog-remb
a=rtcp-fb:120 transport-cc
a=rtcp-fb:121 nack
a=rtcp-fb:121 nack pli
a=rtcp-fb:121 ccm fir
a=rtcp-fb:121 goog-remb
a=rtcp-fb:121 transport-cc
a=rtcp-fb:126 nack
a=rtcp-fb:126 nack pli
a=rtcp-fb:126 ccm fir
a=rtcp-fb:126 goog-remb
a=rtcp-fb:126 transport-cc
a=rtcp-fb:97 nack
a=rtcp-fb:97 nack pli
a=rtcp-fb:97 ccm fir
a=rtcp-fb:97 goog-remb
a=rtcp-fb:97 transport-cc
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:120 VP8/90000
a=rtpmap:124 rtx/90000
a=rtpmap:121 VP9/90000
a=rtpmap:125 rtx/90000
a=rtpmap:126 H264/90000
a=rtpmap:127 rtx/90000
a=rtpmap:97 H264/90000
a=rtpmap:98 rtx/90000
a=setup:actpass
a=ssrc:1800212177 cname:{ac21087a-d493-46e3-a657-d4ee4e1bc9cb}
a=ssrc:4032663199 cname:{ac21087a-d493-46e3-a657-d4ee4e1bc9cb}
a=ssrc-group:FID 1800212177 4032663199
' }
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:0 1 UDP 2122252543 192.168.16.133 36689 typ host',
     sdpMid: '0',
     sdpMLineIndex: 0,
     usernameFragment: 'a63a1363' } }
Queueing candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:3 1 UDP 2122187007 172.17.0.1 48337 typ host',
     sdpMid: '0',
     sdpMLineIndex: 0,
     usernameFragment: 'a63a1363' } }
Queueing candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:6 1 TCP 2105524479 192.168.16.133 9 typ host tcptype active',
     sdpMid: '0',
     sdpMLineIndex: 0,
     usernameFragment: 'a63a1363' } }
Queueing candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:7 1 TCP 2105458943 172.17.0.1 9 typ host tcptype active',
     sdpMid: '0',
     sdpMLineIndex: 0,
     usernameFragment: 'a63a1363' } }
Queueing candidate
my session id: mccsJ5SnNdTomRmCe19l4F1ZfW0E7162
start process on: rtp://127.0.0.1:55000
recv sdp answer: v=0
o=- 3817274007 3817274007 IN IP4 0.0.0.0
s=Kurento Media Server
c=IN IP4 0.0.0.0
t=0 0
a=sendrecv:
a=fingerprint:sha-256 29:61:0D:7A:36:FF:4B:99:D1:E3:A9:D2:56:41:94:71:E5:D0:B3:2C:DB:AE:AE:9D:16:0C:72:98:7E:20:4E:F2
a=ice-options:trickle
a=msid-semantic:WMS *
a=group:BUNDLE 0 1
m=audio 1 UDP/TLS/RTP/SAVPF 109 0
a=sendrecv
a=mid:0
a=rtcp:9 IN IP4 0.0.0.0
a=rtpmap:109 opus/48000/2
a=rtpmap:0 PCMU/8000
a=fmtp:109 maxplaybackrate=48000;stereo=1;useinbandfec=1
a=rtcp-mux
a=setup:active
a=ssrc:818740729 cname:user2508105371@host-7539541f
a=ice-ufrag:uRIN
a=ice-pwd:7JeRHk82PE3EdUPbERp8zg
a=fingerprint:sha-256 EE:47:30:B0:A1:B3:2D:B1:10:BD:DC:D1:78:5D:EB:47:F7:A3:D0:6F:C7:A1:D9:74:5F:49:2E:F1:EE:8B:D2:43
m=video 1 UDP/TLS/RTP/SAVPF 120 126 97
a=extmap:4 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=sendrecv
a=mid:1
a=rtcp:9 IN IP4 0.0.0.0
a=rtpmap:120 VP8/90000
a=rtpmap:126 H264/90000
a=rtpmap:97 H264/90000
a=rtcp-fb:120 nack
a=rtcp-fb:120 nack pli
a=rtcp-fb:120 ccm fir
a=rtcp-fb:120 goog-remb
a=rtcp-fb:126 nack
a=rtcp-fb:126 nack pli
a=rtcp-fb:126 ccm fir
a=rtcp-fb:126 goog-remb
a=rtcp-fb:97 nack
a=rtcp-fb:97 nack pli
a=rtcp-fb:97 ccm fir
a=rtcp-fb:97 goog-remb
a=fmtp:126 profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1
a=fmtp:97 profile-level-id=42e01f;level-asymmetry-allowed=1
a=fmtp:120 max-fs=12288;max-fr=60
a=rtcp-mux
a=setup:active
a=ssrc:370512789 cname:user2508105371@host-7539541f
a=ice-ufrag:uRIN
a=ice-pwd:7JeRHk82PE3EdUPbERp8zg
a=fingerprint:sha-256 EE:47:30:B0:A1:B3:2D:B1:10:BD:DC:D1:78:5D:EB:47:F7:A3:D0:6F:C7:A1:D9:74:5F:49:2E:F1:EE:8B:D2:43

Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:0 2 UDP 2122252542 192.168.16.133 45262 typ host',
     sdpMid: '0',
     sdpMLineIndex: 0,
     usernameFragment: 'a63a1363' } }
Sending candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:3 2 UDP 2122187006 172.17.0.1 34010 typ host',
     sdpMid: '0',
     sdpMLineIndex: 0,
     usernameFragment: 'a63a1363' } }
Sending candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:6 2 TCP 2105524478 192.168.16.133 9 typ host tcptype active',
     sdpMid: '0',
     sdpMLineIndex: 0,
     usernameFragment: 'a63a1363' } }
Sending candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:7 2 TCP 2105458942 172.17.0.1 9 typ host tcptype active',
     sdpMid: '0',
     sdpMLineIndex: 0,
     usernameFragment: 'a63a1363' } }
Sending candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:0 1 UDP 2122252543 192.168.16.133 33211 typ host',
     sdpMid: '1',
     sdpMLineIndex: 1,
     usernameFragment: 'a63a1363' } }
Sending candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:3 1 UDP 2122187007 172.17.0.1 36771 typ host',
     sdpMid: '1',
     sdpMLineIndex: 1,
     usernameFragment: 'a63a1363' } }
Sending candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:6 1 TCP 2105524479 192.168.16.133 9 typ host tcptype active',
     sdpMid: '1',
     sdpMLineIndex: 1,
     usernameFragment: 'a63a1363' } }
Sending candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:7 1 TCP 2105458943 172.17.0.1 9 typ host tcptype active',
     sdpMid: '1',
     sdpMLineIndex: 1,
     usernameFragment: 'a63a1363' } }
Sending candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:0 2 UDP 2122252542 192.168.16.133 50483 typ host',
     sdpMid: '1',
     sdpMLineIndex: 1,
     usernameFragment: 'a63a1363' } }
Sending candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:3 2 UDP 2122187006 172.17.0.1 57105 typ host',
     sdpMid: '1',
     sdpMLineIndex: 1,
     usernameFragment: 'a63a1363' } }
Sending candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:6 2 TCP 2105524478 192.168.16.133 9 typ host tcptype active',
     sdpMid: '1',
     sdpMLineIndex: 1,
     usernameFragment: 'a63a1363' } }
Sending candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:7 2 TCP 2105458942 172.17.0.1 9 typ host tcptype active',
     sdpMid: '1',
     sdpMLineIndex: 1,
     usernameFragment: 'a63a1363' } }
Sending candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:1 1 UDP 1686052863 103.85.173.226 64573 typ srflx raddr 192.168.16.133 rport 36689',
     sdpMid: '0',
     sdpMLineIndex: 0,
     usernameFragment: 'a63a1363' } }
Sending candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:4 1 UDP 1685987327 103.85.173.226 64574 typ srflx raddr 172.17.0.1 rport 48337',
     sdpMid: '0',
     sdpMLineIndex: 0,
     usernameFragment: 'a63a1363' } }
Sending candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:1 2 UDP 1686052862 103.85.173.226 64575 typ srflx raddr 192.168.16.133 rport 45262',
     sdpMid: '0',
     sdpMLineIndex: 0,
     usernameFragment: 'a63a1363' } }
Sending candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: 'candidate:4 2 UDP 1685987326 103.85.173.226 64576 typ srflx raddr 172.17.0.1 rport 34010',
     sdpMid: '0',
     sdpMLineIndex: 0,
     usernameFragment: 'a63a1363' } }
Sending candidate
Connection mccsJ5SnNdTomRmCe19l4F1ZfW0E7162 received message  { id: 'onIceCandidate',
  candidate: 
   { candidate: '',
     sdpMid: '0',
     sdpMLineIndex: 0,
     usernameFragment: 'a63a1363' } }
Sending candidate
2020-12-18 17:53:36 46724 [INFO] [rtmp connect] id=A8D9BIZ8 ip=::ffff:127.0.0.1 app=live args={"app":"live","type":"nonprivate","flashVer":"FMLE/3.0 (compatible; Lavf57.83.100)","tcUrl":"rtmp://localhost:1935/live"}
2020-12-18 17:53:36 46724 [INFO] [rtmp publish] New stream. id=A8D9BIZ8 streamPath=/live/55000 streamId=1
2020-12-18 17:53:36 46724 [INFO] [rtmp publish] Handle video. id=A8D9BIZ8 streamPath=/live/55000 frame_type=1 codec_id=7 codec_name=H264 620x320
2020-12-18 17:53:46 46724 [INFO] [http-flv connect] id=Z4FG5CMW ip=::ffff:192.168.16.1 args={}
2020-12-18 17:53:46 46724 [INFO] [http-flv play] Join stream. id=Z4FG5CMW streamPath=/live/55000 
2020-12-18 17:54:29 46724 [INFO] [http-flv play] Close stream. id=Z4FG5CMW streamPath=/live/55000
2020-12-18 17:54:29 46724 [INFO] [http-flv disconnect] id=Z4FG5CMW
2020-12-18 17:54:41 46724 [INFO] [http-flv connect] id=RA4Y3K26 ip=::ffff:192.168.16.1 args={}
2020-12-18 17:54:41 46724 [INFO] [http-flv play] Join stream. id=RA4Y3K26 streamPath=/live/55000 
2020-12-18 17:55:02 46724 [INFO] [rtmp connect] id=Z3ESECAW ip=::ffff:192.168.16.1 app=live args={"app":"live","flashVer":"WIN 32,0,0,465","swfUrl":"https://ossrs.net/players/srs_player/release/srs_player.swf?_version=1.33","tcUrl":"rtmp://192.168.16.133/live","fpad":false,"capabilities":239,"audioCodecs":3575,"videoCodecs":252,"videoFunction":1,"pageUrl":"https://ossrs.net/players/srs_player.html?app=live&stream=127.0.0.1_55000&server=192.168.16.133&port=1935&autostart=true&vhost=192.168.16.133#","objectEncoding":3}
2020-12-18 17:55:04 46724 [INFO] [rtmp play] Join stream. id=Z3ESECAW streamPath=/live/55000  streamId=1 
2020-12-18 17:56:08 46724 [INFO] [rtmp play] Close stream. id=Z3ESECAW streamPath=/live/55000 streamId=1
2020-12-18 17:56:08 46724 [INFO] [rtmp disconnect] id=Z3ESECAW
2020-12-18 17:56:12 46724 [INFO] [rtmp connect] id=G5B3ZVGO ip=::ffff:192.168.16.1 app=live args={"app":"live","flashVer":"WIN 32,0,0,465","swfUrl":"https://ossrs.net/players/srs_player/release/srs_player.swf?_version=1.33","tcUrl":"rtmp://192.168.16.133/live","fpad":false,"capabilities":239,"audioCodecs":3575,"videoCodecs":252,"videoFunction":1,"pageUrl":"https://ossrs.net/players/srs_player.html?app=live&stream=127.0.0.1_55000&server=192.168.16.133&port=1935&autostart=true&vhost=192.168.16.133#","objectEncoding":3}
2020-12-18 17:56:14 46724 [INFO] [rtmp play] Join stream. id=G5B3ZVGO streamPath=/live/55000  streamId=1 
View Code

go实现的webrtc。

首先我们知道,Rtmp是一种客户端到服务端的技术,Peer to Server。WebRTC是一种客户端到客户端的技术,Peer to Peer。

Rtmp通过一个TCP连接,向服务端发送或接收连接信息,媒体数据。

WebRTC先使用ICE技术连接STUN/TURN,得到自己的连接信息。再绑定音视频设备获取媒体信息,拼装为SDP信令。两个客户端通过任意方式交换信令,建立客户端直接的连接,再使用RTP发送和接收媒体数据。

如果一个服务端实现了WebRTC客户端的能力,那么它也可以被认为是一个Peer,与用户浏览器的WebRTC客户端创建连接,获得客户端推送过来的媒体数据,就完成了Peer to Server的转换。

需要定义信令交换的方式,web编程当然最简单的就是WebSocket了,定义了一个URL格式
wss://serverip:port/live/stream.rtc 
这种格式和RTMP,HTTP-FLV等相互通用。必须是wss,因为现在的浏览器对webrtc访问摄像头,测试用localhost可以不用ssl。信令交换后,客户端创建了和服务端的udp连接,并源源不断的发送H.264+Opus的rtp包。目前客户端能使用的视频编码是vp8,vp9,h264,音频有PCMA,Opus,不会有AAC,因此我们还需要定义flv封装Opus。Opus和AAC类似,我们定义id为13。这样实现rtmp播放客户端的时候,加入opus解码能力和flv负载opus的能力,就可以播放啦。服务端将Opus直接转码为AAC todo。

WebRTC 研究系列 二、打通webrtc与rtmp

pion/webrtc  go语言的。

https://github.com/pion/example-webrtc-applications/tree/master/twitch 一个利用ffmpeg转发到rtmp的示例


WebRTC video stream broadcast
with conversion to RTMP

WebRTC broadcast with republishing as RTMP

WebRTC as RTMP republishing

商用的:

1,

http://bashell.nodemedia.cn/archives/webrtc-research-series-2-get-through-webrtc-and-rtmp.html

WebRTC推流--ShowDoc (nodemedia.cn) 

2,https://flashphoner.com/webrtc-as-rtmp-re-publishing/


RTP/RTCP协议简介 


实时传输协议RTP(RealtimeTransport Protocol):是针对Internet上多媒体数据流的一个传输协议, 由IETF(Internet工程任务组)作为RFC1889发布。RTP被定义为在一对一或一对多的传输情况下工作,其目的是提供时间信息和实现流同步。RTP的典型应用建立在UDP上,但也可以在TCP或ATM等其他协议之上工作。RTP本身只保证实时数据的传输,并不能为按顺序传送数据包提供可靠的传送机制,也不提供流量控制或拥塞控制,它依靠RTCP提供这些服务。 

实时传输控制协议RTCP(RealtimeTransportControl Protocol):负责管理传输质量在当前应用进程之间交换控制信息。在RTP会话期间,各参与者周期性地传送RTCP包,包中含有已发送的数据包的数量、丢失的数据包的数量等统计资料,因此,服务器可以利用这些信息动态地改变传输速率,甚至改变有效载荷类型。RTP和RTCP配合使用,能以有效的反馈和最小的开销使传输效率最佳化,故特别适合传送网上的实时数据。 

RTCP主要有4个功能: 

(1)用反馈信息的方法来提供分配数据的传送质量,这种反馈可以用来进行流量的拥塞控制,也可以用来监视网络和用来诊断网络中的问题; 

(2)为RTP源提供一个永久性的CNAME(规范性名字)的传送层标志,因为在发现冲突或者程序更新重启时SSRC(同步源标识)会变,需要一个运作痕迹,在一组相关的会话中接收方也要用CNAME来从一个指定的与会者得到相联系的数据流(如音频和视频); 

(3)根据与会者的数量来调整RTCP包的发送率; 

(4)传送会话控制信息,如可在用户接口显示与会者的标识,这是可选功能。 

RTP/RTCP工作过程

工作时,RTP协议从上层接收流媒体信息码流(如H.263),装配成RTP数据包发送给下层,下层协议提供RTP和RTCP的分流。如在UDP中,RTP使用一个偶数号端口,则相应的RTCP使用其后的奇数号端口。RTP数据包没有长度限制,它的最大包长只受下层协议的限制。

RTP会话和流的两级分用 

一个RTP会话(Session)包括传给某个指定目的地对(Destination Pair)的所有通信量,发送方可能包括多个。而从同一个同步源发出的RTP分组序列称为流(Stream),一个RTP会话可能包含多个RTP流。一个RTP分组在服务器端发送出去的时候总是要指定属于哪个会话和流,在接收时也需要进行两级分用,即会话分用和流分用。只有当RTP使用同步源标识(SSRC)和分组类型(PTYPE)把同一个流中的分组组合起来,才能够使用序列号(SequenceNumber)和时间戳(Timestamp)对分组进行排序和正确回放。

由于实时数据的独有性,不同实时客户可以共用一个RTP实时服务线程和一个RTCP实时服务线程,这样可以大大减小服务器的负担,而每个文件客户由于请求的文件不同,相应地对速度和开始时间的要求都可能不同,所以需要有自己独有的RTP文件服务线程和RTCP文件服务线程。

RTP服务线程负责把实时数据流发送给客户,RTCP服务线程根据RTP线程的统计数据,产生发送方报告给客户。RTP线程和RTCP线程之间通过一段共享内存交互统计数据,对共享内存必须设置互斥体进行保护,防止出现错误读写。在这种方式下,服务器可以根据每个用户的不同请求和具体情况方便地提供不同的服务。

RTP 时间戳的处理

时间戳字段是RTP首部中说明数据包时间的同步信息,是数据能以正确的时间顺序恢复的关键。时间戳的值给出了分组中数据的第一个字节的采样时间(Sampling Instant),要求发送方时间戳的时钟是连续、单调增长的,即使在没有数据输入或发送数据时也是如此。在静默时,发送方不必发送数据,保持时间戳的增长,在接收端,由于接收到的数据分组的序号没有丢失,就知道没有发生数据丢失,而且只要比较前后分组的时间戳的差异,就可以确定输出的时间间隔。

RTP规定一次会话的初始时间戳必须随机选择,但协议没有规定时间戳的单位,也没有规定该值的精确解释,而是由负载类型来确定时钟的颗粒,这样各种应用类型可以根据需要选择合适的输出计时精度。

在RTP传输音频数据时,一般选定逻辑时间戳速率与采样速率相同,但是在传输视频数据时,必须使时间戳速率大于每帧的一个滴答。如果数据是在同一时刻采样的,协议标准还允许多个分组具有相同的时间戳值。

RTP协议没有规定RTP分组的长度和发送数据的速度,因而需要根据具体情况调整服务器端发送媒体数据的速度。对来自设备的实时数据可以采取等时间间隔访问设备缓冲区,在有新数据输入时发送数据的方式,时间戳的设置相对容易。对已经录制好的本地硬盘上的媒体文件,以H.263格式的文件为例,由于文件本身不包含帧率信息,所以需要知道录制时的帧率或者设置一个初始值,在发送数据的时候找出发送数据中的帧数目,根据帧率和预置值来计算时延,以适当的速度发送数据并设置时间戳信息。

RTCP的一个关键作用就是能让接收方同步多个RTP流,例如:当音频与视频一起传输的时候,由于编码的不同,RTP使用两个流分别进行传输,这样两个流的时间戳以不同的速率运行,接收方必须同步两个流,以保证声音与影像的一致。为能进行流同步,RTCP要求发送方给每个传送一个唯一的标识数据源的规范名(Canonical Name),尽管由一个数据源发出的不同的流具有不同的同步源标识(SSRC),但具有相同的规范名,这样接收方就知道哪些流是有关联的。而发送方报告报文所包含的信息可被接收方用于协调两个流中的时间戳值。发送方报告中含有一个以网络时间协议NTP(Network Time Protocol)格式表示的绝对时间值,接着RTCP报告中给出一个RTP时间戳值,产生该值的时钟就是产生RTP分组中的TimeStamp字段的那个时钟。由于发送方发出的所有流和发送方报告都使用同一个绝对时钟,接收方就可以比较来自同一数据源的两个流的绝对时间,从而确定如何将一个流中的时间戳值映射为另一个流中的时间戳值。

 

·  RTP:实时传输协议(Real-time Transport Protocol)

·        RTP/RTCP是实际传输数据的协议 

·        RTP传输音频/视频数据,如果是PLAY,Server发送到Client端,如果是RECORD,可以由Client发送到Server 

·        整个RTP协议由两个密切相关的部分组成:RTP数据协议和RTP控制协议(即RTCP)

·  RTSP:实时流协议(Real Time Streaming Protocol,RTSP)

·        RTSP的请求主要有DESCRIBE,SETUP,PLAY,PAUSE,TEARDOWN,OPTIONS等,顾名思义可以知道起对话和控制作用 

·        RTSP的对话过程中SETUP可以确定RTP/RTCP使用的端口,PLAY/PAUSE/TEARDOWN可以开始或者停止RTP的发送,等等

·  RTCP:

·        RTP/RTCP是实际传输数据的协议 

·        RTCP包括SenderReport和Receiver Report,用来进行音频/视频的同步以及其他用途,是一种控制协议 


参考:

sdp文件详细总结流媒体分析之sipdroid的videocamera类,流程分析及RTP/RTCP介绍RTP协议详解RTP (I): Intro to RTP and SDP  RTP (II): Streaming with FF带你吃透RTMPSRS 代码分析 https://blog.csdn.net/ManagerUser/article/details/73840130/ webrtc 资源

WebRTC for the Curious

免责声明:文章转载自《Kurento KMS 流媒体服务器 webRTC转rtmp http flv》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Verdi 查看二维数组波形ORACLE触发器详解下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

树莓派搭建bt下载机、即是安装transmission

Transmission是一种BitTorrent客户端, 安装:sudo apt-get install transmission-daemon 给用户授权:sudo usermod -a -G pi debian-transmission 设置Transmission的配置文件:sudo vim /etc/transmission-daemon/s...

Liunx-常用命令杂烩(5)

快捷键 ctrl+alt 显示鼠标 ctrl+alt+tab+F1~F6 :进入字符终端界面tty1~tty6,例如 ctrl+alt+tab+F7 :退出字符终端界面 简单命令相关 whoami      打印当前有效用户名 (who am i) date "+ %Y/%m/%d %H:%M:%S 打印年月日...

su安装

SU 的安装(Ubuntu下)   SU是科罗拉多州矿业学院开发的一个免费地震处理软件。国内外很多科研人员及学生都借助于他来进行创作,和其他天价的处理软件相比,SU对学生就显得尤为珍贵了,更何况他开放源代码,可以方便地在其基础上进行再创作。 但是对于不是很熟悉LINUX的人来说,能把它安装上也需要花不少功夫,下面就把我的体会写出来,以供大家参考。 注:我把...

rabbitmq消费端加入精确控频。

控制频率之前用的是线程池的数量来控制,很难控制。因为做一键事情,做一万次,并不是每次消耗的时间都相同,所以很难推测出到底多少线程并发才刚好不超过指定的频率。 现在在框架中加入控频功能,即使开200线程,也能保证1秒钟只运行10次任务。 里面的rabbitpy后来加的,然来是使用pika的,就框架本身得实现写法上违反了开闭原则,没设计太好。好在不影响调用方式...

tcpdump移植和使用

转载于:http://blog.chinaunix.net/uid-30497107-id-5757540.html?utm_source=tuicool&utm_medium=referral 用简单的话来定义tcpdump,就是:dump the traffic on a network,根据使用者的定义对网络上的数据包进行截获的包分析工具。t...

Ubuntu 搭建ELK

一、简介 官网地址:https://www.elastic.co/cn/ 官网权威指南:https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html 安装指南:https://www.elastic.co/guide/en/elasticsearch/reference/5.x...