mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-26 12:37:09 +08:00
Merge branch 'master' into cus_pr
同步代码
This commit is contained in:
commit
a0de7577fe
@ -71,6 +71,7 @@ SpaceBeforeInheritanceColon: true
|
|||||||
SpaceBeforeParens: ControlStatements
|
SpaceBeforeParens: ControlStatements
|
||||||
# 空 {} 中不加空格
|
# 空 {} 中不加空格
|
||||||
SpaceInEmptyBlock: false
|
SpaceInEmptyBlock: false
|
||||||
|
Standard: C++11
|
||||||
# Tab 占 4 位
|
# Tab 占 4 位
|
||||||
TabWidth: 4
|
TabWidth: 4
|
||||||
# 不使用 TAB
|
# 不使用 TAB
|
||||||
|
2
.github/workflows/android.yml
vendored
2
.github/workflows/android.yml
vendored
@ -1,4 +1,4 @@
|
|||||||
name: Android CI
|
name: Android
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
name: linux C/C++ CI
|
name: Linux
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
2
.github/workflows/macos.yml
vendored
2
.github/workflows/macos.yml
vendored
@ -1,4 +1,4 @@
|
|||||||
name: macos C/C++ CI
|
name: macOS
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
27
.github/workflows/style.yml
vendored
Normal file
27
.github/workflows/style.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
name: style check
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
# with all history
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Validate BOM
|
||||||
|
run: |
|
||||||
|
ret=0
|
||||||
|
for i in $(git diff --name-only origin/${GITHUB_BASE_REF}...${GITHUB_SHA}); do
|
||||||
|
if [ -f ${i} ]; then
|
||||||
|
case ${i} in
|
||||||
|
*.c|*.cc|*.cpp|*.h)
|
||||||
|
if file ${i} | grep -qv BOM; then
|
||||||
|
echo "Missing BOM in ${i}" && ret=1;
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
exit ${ret}
|
@ -1,4 +1,4 @@
|
|||||||
name: MSVC C/C++ CI
|
name: Windows
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
@ -1 +1 @@
|
|||||||
Subproject commit 136b6b2f28193da218f577423db217aeb0f7aa6a
|
Subproject commit 61f2c6c8d4288c2c60299a84473d9cfec113891c
|
@ -22,6 +22,10 @@ endif()
|
|||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
#加载自定义模块
|
#加载自定义模块
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||||
|
set(DEP_ROOT_DIR ${CMAKE_SOURCE_DIR}/3rdpart/external-${CMAKE_SYSTEM_NAME})
|
||||||
|
if(NOT EXISTS ${DEP_ROOT_DIR})
|
||||||
|
file(MAKE_DIRECTORY ${DEP_ROOT_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
find_program(CCACHE_FOUND ccache)
|
find_program(CCACHE_FOUND ccache)
|
||||||
if(CCACHE_FOUND)
|
if(CCACHE_FOUND)
|
||||||
@ -108,6 +112,7 @@ option(ENABLE_MSVC_MT "Enable MSVC Mt/Mtd lib" true)
|
|||||||
option(ENABLE_API_STATIC_LIB "Enable mk_api static lib" false)
|
option(ENABLE_API_STATIC_LIB "Enable mk_api static lib" false)
|
||||||
option(USE_SOLUTION_FOLDERS "Enable solution dir supported" ON)
|
option(USE_SOLUTION_FOLDERS "Enable solution dir supported" ON)
|
||||||
option(ENABLE_SRT "Enable SRT" true)
|
option(ENABLE_SRT "Enable SRT" true)
|
||||||
|
option(ENABLE_JEMALLOC_STATIC "Enable static linking to the jemalloc library" false)
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# Solution folders:
|
# Solution folders:
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
@ -299,6 +304,13 @@ if (ENABLE_FFMPEG)
|
|||||||
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
if(ENABLE_JEMALLOC_STATIC)
|
||||||
|
include(cmake/Jemalloc.cmake)
|
||||||
|
include_directories(${DEP_ROOT_DIR}/${JEMALLOC_NAME}/include/jemalloc)
|
||||||
|
link_directories(${DEP_ROOT_DIR}/${JEMALLOC_NAME}/lib)
|
||||||
|
set(JEMALLOC_ROOT_DIR "${DEP_ROOT_DIR}/${JEMALLOC_NAME}")
|
||||||
|
endif ()
|
||||||
|
|
||||||
#默认链接jemalloc库避免内存碎片
|
#默认链接jemalloc库避免内存碎片
|
||||||
find_package(JEMALLOC QUIET)
|
find_package(JEMALLOC QUIET)
|
||||||
if (JEMALLOC_FOUND)
|
if (JEMALLOC_FOUND)
|
||||||
|
43
README.md
43
README.md
@ -1,13 +1,19 @@
|
|||||||
![logo](https://raw.githubusercontent.com/xia-chu/ZLMediaKit/master/www/logo.png)
|
![logo](https://raw.githubusercontent.com/ZLMediaKit/ZLMediaKit/master/www/logo.png)
|
||||||
|
|
||||||
# 一个基于C++11的高性能运营级流媒体服务框架
|
# 一个基于C++11的高性能运营级流媒体服务框架
|
||||||
|
|
||||||
[![license](http://img.shields.io/badge/license-MIT-green.svg)](https://github.com/xia-chu/ZLMediaKit/blob/master/LICENSE)
|
[![](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/ZLMediaKit/ZLMediaKit/blob/master/LICENSE)
|
||||||
[![C++](https://img.shields.io/badge/language-c++-red.svg)](https://en.cppreference.com/)
|
[![](https://img.shields.io/badge/language-c++-red.svg)](https://en.cppreference.com/)
|
||||||
[![platform](https://img.shields.io/badge/platform-linux%20|%20macos%20|%20windows-blue.svg)](https://github.com/xia-chu/ZLMediaKit)
|
[![](https://img.shields.io/badge/platform-linux%20|%20macos%20|%20windows-blue.svg)](https://github.com/ZLMediaKit/ZLMediaKit)
|
||||||
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-yellow.svg)](https://github.com/xia-chu/ZLMediaKit/pulls)
|
[![](https://img.shields.io/badge/PRs-welcome-yellow.svg)](https://github.com/ZLMediaKit/ZLMediaKit/pulls)
|
||||||
[![Build Status](https://travis-ci.org/xia-chu/ZLMediaKit.svg?branch=master)](https://travis-ci.org/xia-chu/ZLMediaKit)
|
|
||||||
[![Docker](https://img.shields.io/docker/pulls/zlmediakit/zlmediakit)](https://hub.docker.com/r/zlmediakit/zlmediakit/tags)
|
[![](https://github.com/ZLMediaKit/ZLMediaKit/actions/workflows/android.yml/badge.svg)](https://github.com/ZLMediaKit/ZLMediaKit)
|
||||||
|
[![](https://github.com/ZLMediaKit/ZLMediaKit/actions/workflows/linux.yml/badge.svg)](https://github.com/ZLMediaKit/ZLMediaKit)
|
||||||
|
[![](https://github.com/ZLMediaKit/ZLMediaKit/actions/workflows/macos.yml/badge.svg)](https://github.com/ZLMediaKit/ZLMediaKit)
|
||||||
|
[![](https://github.com/ZLMediaKit/ZLMediaKit/actions/workflows/windows.yml/badge.svg)](https://github.com/ZLMediaKit/ZLMediaKit)
|
||||||
|
|
||||||
|
[![](https://github.com/ZLMediaKit/ZLMediaKit/actions/workflows/docker.yml/badge.svg)](https://hub.docker.com/r/zlmediakit/zlmediakit/tags)
|
||||||
|
[![](https://img.shields.io/docker/pulls/zlmediakit/zlmediakit)](https://hub.docker.com/r/zlmediakit/zlmediakit/tags)
|
||||||
|
|
||||||
## 项目特点
|
## 项目特点
|
||||||
|
|
||||||
@ -16,10 +22,10 @@
|
|||||||
- 使用多路复用/多线程/异步网络IO模式开发,并发性能优越,支持海量客户端连接。
|
- 使用多路复用/多线程/异步网络IO模式开发,并发性能优越,支持海量客户端连接。
|
||||||
- 代码经过长期大量的稳定性、性能测试,已经在线上商用验证已久。
|
- 代码经过长期大量的稳定性、性能测试,已经在线上商用验证已久。
|
||||||
- 支持linux、macos、ios、android、windows全平台。
|
- 支持linux、macos、ios、android、windows全平台。
|
||||||
- 支持画面秒开、极低延时([500毫秒内,最低可达100毫秒](https://github.com/xia-chu/ZLMediaKit/wiki/%E5%BB%B6%E6%97%B6%E6%B5%8B%E8%AF%95))。
|
- 支持画面秒开、极低延时([500毫秒内,最低可达100毫秒](https://github.com/ZLMediaKit/ZLMediaKit/wiki/%E5%BB%B6%E6%97%B6%E6%B5%8B%E8%AF%95))。
|
||||||
- 提供完善的标准[C API](https://github.com/xia-chu/ZLMediaKit/tree/master/api/include),可以作SDK用,或供其他语言调用。
|
- 提供完善的标准[C API](https://github.com/ZLMediaKit/ZLMediaKit/tree/master/api/include),可以作SDK用,或供其他语言调用。
|
||||||
- 提供完整的[MediaServer](https://github.com/xia-chu/ZLMediaKit/tree/master/server)服务器,可以免开发直接部署为商用服务器。
|
- 提供完整的[MediaServer](https://github.com/ZLMediaKit/ZLMediaKit/tree/master/server)服务器,可以免开发直接部署为商用服务器。
|
||||||
- 提供完善的[restful api](https://github.com/xia-chu/ZLMediaKit/wiki/MediaServer%E6%94%AF%E6%8C%81%E7%9A%84HTTP-API)以及[web hook](https://github.com/xia-chu/ZLMediaKit/wiki/MediaServer%E6%94%AF%E6%8C%81%E7%9A%84HTTP-HOOK-API),支持丰富的业务逻辑。
|
- 提供完善的[restful api](https://github.com/ZLMediaKit/ZLMediaKit/wiki/MediaServer%E6%94%AF%E6%8C%81%E7%9A%84HTTP-API)以及[web hook](https://github.com/ZLMediaKit/ZLMediaKit/wiki/MediaServer%E6%94%AF%E6%8C%81%E7%9A%84HTTP-HOOK-API),支持丰富的业务逻辑。
|
||||||
- 打通了视频监控协议栈与直播协议栈,对RTSP/RTMP支持都很完善。
|
- 打通了视频监控协议栈与直播协议栈,对RTSP/RTMP支持都很完善。
|
||||||
- 全面支持H265/H264/AAC/G711/OPUS。
|
- 全面支持H265/H264/AAC/G711/OPUS。
|
||||||
- 功能完善,支持集群、按需转协议、按需推拉流、先播后推、断连续推等功能。
|
- 功能完善,支持集群、按需转协议、按需推拉流、先播后推、断连续推等功能。
|
||||||
@ -58,7 +64,7 @@
|
|||||||
- 支持websocket-flv直播
|
- 支持websocket-flv直播
|
||||||
- 支持H264/H265/AAC/G711/OPUS编码,其他编码能转发但不能转协议
|
- 支持H264/H265/AAC/G711/OPUS编码,其他编码能转发但不能转协议
|
||||||
- 支持[RTMP-H265](https://github.com/ksvc/FFmpeg/wiki)
|
- 支持[RTMP-H265](https://github.com/ksvc/FFmpeg/wiki)
|
||||||
- 支持[RTMP-OPUS](https://github.com/xia-chu/ZLMediaKit/wiki/RTMP%E5%AF%B9H265%E5%92%8COPUS%E7%9A%84%E6%94%AF%E6%8C%81)
|
- 支持[RTMP-OPUS](https://github.com/ZLMediaKit/ZLMediaKit/wiki/RTMP%E5%AF%B9H265%E5%92%8COPUS%E7%9A%84%E6%94%AF%E6%8C%81)
|
||||||
|
|
||||||
- HLS
|
- HLS
|
||||||
- 支持HLS文件生成,自带HTTP文件服务器
|
- 支持HLS文件生成,自带HTTP文件服务器
|
||||||
@ -126,15 +132,15 @@
|
|||||||
|
|
||||||
|
|
||||||
## 编译以及测试
|
## 编译以及测试
|
||||||
**编译前务必仔细参考wiki:[快速开始](https://github.com/xia-chu/ZLMediaKit/wiki/%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B)操作!!!**
|
**编译前务必仔细参考wiki:[快速开始](https://github.com/ZLMediaKit/ZLMediaKit/wiki/%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B)操作!!!**
|
||||||
|
|
||||||
## 怎么使用
|
## 怎么使用
|
||||||
|
|
||||||
你有三种方法使用ZLMediaKit,分别是:
|
你有三种方法使用ZLMediaKit,分别是:
|
||||||
|
|
||||||
- 1、使用c api,作为sdk使用,请参考[这里](https://github.com/xia-chu/ZLMediaKit/tree/master/api/include).
|
- 1、使用c api,作为sdk使用,请参考[这里](https://github.com/ZLMediaKit/ZLMediaKit/tree/master/api/include).
|
||||||
- 2、作为独立的流媒体服务器使用,不想做c/c++开发的,可以参考 [restful api](https://github.com/xia-chu/ZLMediaKit/wiki/MediaServer支持的HTTP-API) 和 [web hook](https://github.com/xia-chu/ZLMediaKit/wiki/MediaServer支持的HTTP-HOOK-API ).
|
- 2、作为独立的流媒体服务器使用,不想做c/c++开发的,可以参考 [restful api](https://github.com/ZLMediaKit/ZLMediaKit/wiki/MediaServer支持的HTTP-API) 和 [web hook](https://github.com/ZLMediaKit/ZLMediaKit/wiki/MediaServer支持的HTTP-HOOK-API ).
|
||||||
- 3、如果想做c/c++开发,添加业务逻辑增加功能,可以参考这里的[测试程序](https://github.com/xia-chu/ZLMediaKit/tree/master/tests).
|
- 3、如果想做c/c++开发,添加业务逻辑增加功能,可以参考这里的[测试程序](https://github.com/ZLMediaKit/ZLMediaKit/tree/master/tests).
|
||||||
|
|
||||||
## Docker 镜像
|
## Docker 镜像
|
||||||
|
|
||||||
@ -167,6 +173,7 @@ bash build_docker_images.sh
|
|||||||
- [Go实现的海康ehome服务器](https://github.com/tsingeye/FreeEhome)
|
- [Go实现的海康ehome服务器](https://github.com/tsingeye/FreeEhome)
|
||||||
|
|
||||||
- 客户端
|
- 客户端
|
||||||
|
- [c sdk完整c#包装库](https://github.com/malegend/ZLMediaKit.Autogen)
|
||||||
- [基于C SDK实现的推流客户端](https://github.com/hctym1995/ZLM_ApiDemo)
|
- [基于C SDK实现的推流客户端](https://github.com/hctym1995/ZLM_ApiDemo)
|
||||||
- [C#版本的Http API与Hook](https://github.com/chengxiaosheng/ZLMediaKit.HttpApi)
|
- [C#版本的Http API与Hook](https://github.com/chengxiaosheng/ZLMediaKit.HttpApi)
|
||||||
- [DotNetCore的RESTful客户端](https://github.com/MingZhuLiu/ZLMediaKit.DotNetCore.Sdk)
|
- [DotNetCore的RESTful客户端](https://github.com/MingZhuLiu/ZLMediaKit.DotNetCore.Sdk)
|
||||||
@ -195,7 +202,7 @@ bash build_docker_images.sh
|
|||||||
- 1、仔细看下readme、wiki,如果有必要可以查看下issue.
|
- 1、仔细看下readme、wiki,如果有必要可以查看下issue.
|
||||||
- 2、如果您的问题还没解决,可以提issue.
|
- 2、如果您的问题还没解决,可以提issue.
|
||||||
- 3、有些问题,如果不具备参考性的,无需在issue提的,可以在qq群提.
|
- 3、有些问题,如果不具备参考性的,无需在issue提的,可以在qq群提.
|
||||||
- 4、QQ私聊一般不接受无偿技术咨询和支持([为什么不提倡QQ私聊](https://github.com/xia-chu/ZLMediaKit/wiki/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E5%BB%BA%E8%AE%AEQQ%E7%A7%81%E8%81%8A%E5%92%A8%E8%AF%A2%E9%97%AE%E9%A2%98%EF%BC%9F)).
|
- 4、QQ私聊一般不接受无偿技术咨询和支持([为什么不提倡QQ私聊](https://github.com/ZLMediaKit/ZLMediaKit/wiki/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E5%BB%BA%E8%AE%AEQQ%E7%A7%81%E8%81%8A%E5%92%A8%E8%AF%A2%E9%97%AE%E9%A2%98%EF%BC%9F)).
|
||||||
|
|
||||||
## 特别感谢
|
## 特别感谢
|
||||||
|
|
||||||
@ -278,4 +285,4 @@ bash build_docker_images.sh
|
|||||||
|
|
||||||
本项目已经得到不少公司和个人开发者的认可,据作者不完全统计,
|
本项目已经得到不少公司和个人开发者的认可,据作者不完全统计,
|
||||||
使用本项目的公司包括知名的互联网巨头、国内排名前列的云服务公司、多家知名的AI独角兽公司,
|
使用本项目的公司包括知名的互联网巨头、国内排名前列的云服务公司、多家知名的AI独角兽公司,
|
||||||
以及一系列中小型公司。使用者可以通过在 [issue](https://github.com/xia-chu/ZLMediaKit/issues/511) 上粘贴公司的大名和相关项目介绍为本项目背书,感谢支持!
|
以及一系列中小型公司。使用者可以通过在 [issue](https://github.com/ZLMediaKit/ZLMediaKit/issues/511) 上粘贴公司的大名和相关项目介绍为本项目背书,感谢支持!
|
||||||
|
@ -187,7 +187,6 @@ API_EXPORT int API_CALL mk_media_init_video(mk_media ctx, int codec_id, int widt
|
|||||||
info.iWidth = width;
|
info.iWidth = width;
|
||||||
info.iHeight = height;
|
info.iHeight = height;
|
||||||
info.iBitRate = bit_rate;
|
info.iBitRate = bit_rate;
|
||||||
(*obj)->getChannel()->initVideo(info);
|
|
||||||
return (*obj)->getChannel()->initVideo(info);
|
return (*obj)->getChannel()->initVideo(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,12 +10,13 @@
|
|||||||
|
|
||||||
#include "mk_track.h"
|
#include "mk_track.h"
|
||||||
#include "Extension/Track.h"
|
#include "Extension/Track.h"
|
||||||
|
#include "Extension/Factory.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace toolkit;
|
using namespace toolkit;
|
||||||
using namespace mediakit;
|
using namespace mediakit;
|
||||||
|
|
||||||
class VideoTrackForC : public VideoTrack {
|
class VideoTrackForC : public VideoTrack, public std::enable_shared_from_this<VideoTrackForC> {
|
||||||
public:
|
public:
|
||||||
VideoTrackForC(int codec_id, codec_args *args) {
|
VideoTrackForC(int codec_id, codec_args *args) {
|
||||||
_codec_id = (CodecId) codec_id;
|
_codec_id = (CodecId) codec_id;
|
||||||
@ -49,7 +50,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Track::Ptr clone() override {
|
Track::Ptr clone() override {
|
||||||
return std::make_shared<std::remove_reference<decltype(*this)>::type>(*this);
|
auto track_in = std::shared_ptr<Track>(shared_from_this());
|
||||||
|
return Factory::getTrackByAbstractTrack(track_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sdp::Ptr getSdp() override {
|
Sdp::Ptr getSdp() override {
|
||||||
@ -61,7 +63,7 @@ private:
|
|||||||
codec_args _args;
|
codec_args _args;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AudioTrackForC : public AudioTrackImp {
|
class AudioTrackForC : public AudioTrackImp, public std::enable_shared_from_this<AudioTrackForC> {
|
||||||
public:
|
public:
|
||||||
~AudioTrackForC() override = default;
|
~AudioTrackForC() override = default;
|
||||||
|
|
||||||
@ -69,7 +71,8 @@ public:
|
|||||||
AudioTrackImp((CodecId) codec_id, args->audio.sample_rate, args->audio.channels, 16) {}
|
AudioTrackImp((CodecId) codec_id, args->audio.sample_rate, args->audio.channels, 16) {}
|
||||||
|
|
||||||
Track::Ptr clone() override {
|
Track::Ptr clone() override {
|
||||||
return std::make_shared<std::remove_reference<decltype(*this)>::type>(*this);
|
auto track_in = std::shared_ptr<Track>(shared_from_this());
|
||||||
|
return Factory::getTrackByAbstractTrack(track_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sdp::Ptr getSdp() override {
|
Sdp::Ptr getSdp() override {
|
||||||
|
@ -64,8 +64,12 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
mk_media media = mk_media_create("__defaultVhost__", "live", "test", 0, 0, 0);
|
mk_media media = mk_media_create("__defaultVhost__", "live", "test", 0, 0, 0);
|
||||||
//h264的codec
|
//h264的codec
|
||||||
mk_media_init_video(media, 0, 0, 0, 0, 2 * 104 * 1024);
|
//mk_media_init_video(media, 0, 0, 0, 0, 2 * 104 * 1024);
|
||||||
|
codec_args v_args={0};
|
||||||
|
mk_track v_track = mk_track_create(MKCodecH264,&v_args);
|
||||||
|
mk_media_init_track(media,v_track);
|
||||||
mk_media_init_complete(media);
|
mk_media_init_complete(media);
|
||||||
|
mk_track_unref(v_track);
|
||||||
|
|
||||||
//创建h264分帧器
|
//创建h264分帧器
|
||||||
mk_h264_splitter splitter = mk_h264_splitter_create(on_h264_frame, media);
|
mk_h264_splitter splitter = mk_h264_splitter_create(on_h264_frame, media);
|
||||||
|
@ -1,16 +1,49 @@
|
|||||||
|
|
||||||
|
|
||||||
find_path(JEMALLOC_INCLUDE_DIR
|
# Tries to find Jemalloc headers and libraries.
|
||||||
|
#
|
||||||
|
# Usage of this module as follows:
|
||||||
|
#
|
||||||
|
# find_package(jemalloc)
|
||||||
|
#
|
||||||
|
# Variables used by this module, they can change the default behaviour and need
|
||||||
|
# to be set before calling find_package:
|
||||||
|
#
|
||||||
|
# JEMALLOC_ROOT_DIR Set this variable to the root installation of
|
||||||
|
# Jemalloc if the module has problems finding
|
||||||
|
# the proper installation path.
|
||||||
|
#
|
||||||
|
# Variables defined by this module:
|
||||||
|
#
|
||||||
|
# JEMALLOC_FOUND System has Jemalloc libs/headers
|
||||||
|
# JEMALLOC_LIBRARIES The Jemalloc libraries
|
||||||
|
# JEMALLOC_INCLUDE_DIR The location of Jemalloc headers
|
||||||
|
if (ENABLE_JEMALLOC_STATIC)
|
||||||
|
find_path(JEMALLOC_INCLUDE_DIR
|
||||||
|
NAMES jemalloc.h
|
||||||
|
HINTS ${JEMALLOC_ROOT_DIR}/include/jemalloc
|
||||||
|
NO_DEFAULT_PATH)
|
||||||
|
|
||||||
|
find_library(JEMALLOC_LIBRARIES
|
||||||
|
NAMES jemalloc
|
||||||
|
HINTS ${JEMALLOC_ROOT_DIR}/lib
|
||||||
|
NO_DEFAULT_PATH)
|
||||||
|
else ()
|
||||||
|
find_path(JEMALLOC_INCLUDE_DIR
|
||||||
NAMES jemalloc/jemalloc.h
|
NAMES jemalloc/jemalloc.h
|
||||||
)
|
)
|
||||||
|
|
||||||
find_library(JEMALLOC_LIBRARY
|
find_library(JEMALLOC_LIBRARIES
|
||||||
NAMES jemalloc
|
NAMES jemalloc
|
||||||
)
|
)
|
||||||
|
|
||||||
set(JEMALLOC_INCLUDE_DIRS ${JEMALLOC_INCLUDE_DIR})
|
endif ()
|
||||||
set(JEMALLOC_LIBRARIES ${JEMALLOC_LIBRARY})
|
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(JEMALLOC DEFAULT_MSG
|
||||||
|
JEMALLOC_LIBRARIES
|
||||||
|
JEMALLOC_INCLUDE_DIR)
|
||||||
|
|
||||||
find_package_handle_standard_args(JEMALLOC DEFAULT_MSG JEMALLOC_LIBRARY JEMALLOC_INCLUDE_DIR)
|
mark_as_advanced(
|
||||||
|
JEMALLOC_ROOT_DIR
|
||||||
|
JEMALLOC_LIBRARIES
|
||||||
|
JEMALLOC_INCLUDE_DIR)
|
||||||
|
50
cmake/Jemalloc.cmake
Normal file
50
cmake/Jemalloc.cmake
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# Download and build Jemalloc
|
||||||
|
|
||||||
|
set(JEMALLOC_VERSION 5.2.1)
|
||||||
|
set(JEMALLOC_NAME jemalloc-${JEMALLOC_VERSION})
|
||||||
|
set(JEMALLOC_TAR_PATH ${DEP_ROOT_DIR}/${JEMALLOC_NAME}.tar.bz2)
|
||||||
|
|
||||||
|
list(APPEND jemalloc_CONFIG_ARGS --disable-initial-exec-tls)
|
||||||
|
list(APPEND jemalloc_CONFIG_ARGS --without-export)
|
||||||
|
list(APPEND jemalloc_CONFIG_ARGS --disable-stats)
|
||||||
|
list(APPEND jemalloc_CONFIG_ARGS --disable-libdl)
|
||||||
|
#list(APPEND jemalloc_CONFIG_ARGS --disable-cxx)
|
||||||
|
#list(APPEND jemalloc_CONFIG_ARGS --with-jemalloc-prefix=je_)
|
||||||
|
#list(APPEND jemalloc_CONFIG_ARGS --enable-debug)
|
||||||
|
|
||||||
|
if(NOT EXISTS ${JEMALLOC_TAR_PATH})
|
||||||
|
message(STATUS "Downloading ${JEMALLOC_NAME}...")
|
||||||
|
file(DOWNLOAD https://github.com/jemalloc/jemalloc/releases/download/${JEMALLOC_VERSION}/${JEMALLOC_NAME}.tar.bz2
|
||||||
|
${JEMALLOC_TAR_PATH})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
SET( DIR_CONTAINING_JEMALLOC ${DEP_ROOT_DIR}/${JEMALLOC_NAME} )
|
||||||
|
|
||||||
|
if(NOT EXISTS ${DIR_CONTAINING_JEMALLOC})
|
||||||
|
message(STATUS "Extracting jemalloc...")
|
||||||
|
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ${JEMALLOC_TAR_PATH} WORKING_DIRECTORY ${DEP_ROOT_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
if(NOT EXISTS ${DIR_CONTAINING_JEMALLOC}/Makefile)
|
||||||
|
message("Configuring jemalloc locally...")
|
||||||
|
# Builds with "--with-jemalloc-prefix=je_" on OSX
|
||||||
|
# SET( BASH_COMMAND_TO_RUN bash -l -c "cd ${DIR_CONTAINING_JEMALLOC} && ./configure ${jemalloc_CONFIG_ARGS}" )
|
||||||
|
#
|
||||||
|
# EXECUTE_PROCESS( COMMAND ${BASH_COMMAND_TO_RUN}
|
||||||
|
# WORKING_DIRECTORY ${DIR_CONTAINING_JEMALLOC} RESULT_VARIABLE JEMALLOC_CONFIGURE )
|
||||||
|
|
||||||
|
execute_process(COMMAND ./configure ${jemalloc_CONFIG_ARGS} WORKING_DIRECTORY ${DIR_CONTAINING_JEMALLOC} RESULT_VARIABLE JEMALLOC_CONFIGURE)
|
||||||
|
if(NOT JEMALLOC_CONFIGURE EQUAL 0)
|
||||||
|
message(FATAL_ERROR "${JEMALLOC_NAME} configure failed!")
|
||||||
|
message("${JEMALLOC_CONFIGURE}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EXISTS ${DIR_CONTAINING_JEMALLOC}/lib/libjemalloc.a)
|
||||||
|
message("Building jemalloc locally...")
|
||||||
|
execute_process(COMMAND make "build_lib_static" WORKING_DIRECTORY ${DIR_CONTAINING_JEMALLOC})
|
||||||
|
if(NOT EXISTS ${DIR_CONTAINING_JEMALLOC}/lib/libjemalloc.a)
|
||||||
|
message(FATAL_ERROR "${JEMALLOC_NAME} build failed!")
|
||||||
|
endif()
|
||||||
|
endif()
|
@ -298,6 +298,7 @@ g711a_pt=8
|
|||||||
#rtc播放推流、播放超时时间
|
#rtc播放推流、播放超时时间
|
||||||
timeoutSec=15
|
timeoutSec=15
|
||||||
#本机对rtc客户端的可见ip,作为服务器时一般为公网ip,可有多个,用','分开,当置空时,会自动获取网卡ip
|
#本机对rtc客户端的可见ip,作为服务器时一般为公网ip,可有多个,用','分开,当置空时,会自动获取网卡ip
|
||||||
|
#同时支持环境变量,以$开头,如"$EXTERN_IP"; 请参考:https://github.com/ZLMediaKit/ZLMediaKit/pull/1786
|
||||||
externIP=
|
externIP=
|
||||||
#rtc udp服务器监听端口号,所有rtc客户端将通过该端口传输stun/dtls/srtp/srtcp数据,
|
#rtc udp服务器监听端口号,所有rtc客户端将通过该端口传输stun/dtls/srtp/srtcp数据,
|
||||||
#该端口是多线程的,同时支持客户端网络切换导致的连接迁移
|
#该端口是多线程的,同时支持客户端网络切换导致的连接迁移
|
||||||
|
@ -47,13 +47,13 @@ static void on_ffmpeg_log(void *ctx, int level, const char *fmt, va_list args) {
|
|||||||
}
|
}
|
||||||
LogLevel lev;
|
LogLevel lev;
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case AV_LOG_FATAL: lev = LError; break;
|
case AV_LOG_FATAL:
|
||||||
case AV_LOG_ERROR: lev = LError; break;
|
case AV_LOG_ERROR: lev = LError; break;
|
||||||
case AV_LOG_WARNING: lev = LWarn; break;
|
case AV_LOG_WARNING: lev = LWarn; break;
|
||||||
case AV_LOG_INFO: lev = LInfo; break;
|
case AV_LOG_INFO: lev = LInfo; break;
|
||||||
case AV_LOG_VERBOSE: lev = LDebug; break;
|
case AV_LOG_VERBOSE:
|
||||||
case AV_LOG_DEBUG: lev = LDebug; break;
|
case AV_LOG_DEBUG: lev = LDebug; break;
|
||||||
case AV_LOG_TRACE: lev = LTrace; break;
|
case AV_LOG_TRACE:
|
||||||
default: lev = LTrace; break;
|
default: lev = LTrace; break;
|
||||||
}
|
}
|
||||||
LoggerWrapper::printLogV(::toolkit::getLogger(), lev, __FILE__, ctx ? av_default_item_name(ctx) : "NULL", level, fmt, args);
|
LoggerWrapper::printLogV(::toolkit::getLogger(), lev, __FILE__, ctx ? av_default_item_name(ctx) : "NULL", level, fmt, args);
|
||||||
@ -63,7 +63,9 @@ static bool setupFFmpeg_l() {
|
|||||||
av_log_set_level(AV_LOG_TRACE);
|
av_log_set_level(AV_LOG_TRACE);
|
||||||
av_log_set_flags(AV_LOG_PRINT_LEVEL);
|
av_log_set_flags(AV_LOG_PRINT_LEVEL);
|
||||||
av_log_set_callback(on_ffmpeg_log);
|
av_log_set_callback(on_ffmpeg_log);
|
||||||
|
#if (LIBAVCODEC_VERSION_MAJOR < 58)
|
||||||
avcodec_register_all();
|
avcodec_register_all();
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,14 +245,14 @@ AVFrame *FFmpegFrame::get() const {
|
|||||||
|
|
||||||
void FFmpegFrame::fillPicture(AVPixelFormat target_format, int target_width, int target_height) {
|
void FFmpegFrame::fillPicture(AVPixelFormat target_format, int target_width, int target_height) {
|
||||||
assert(_data == nullptr);
|
assert(_data == nullptr);
|
||||||
_data = new char[avpicture_get_size(target_format, target_width, target_height)];
|
_data = new char[av_image_get_buffer_size(target_format, target_width, target_height, 1)];
|
||||||
avpicture_fill((AVPicture *) _frame.get(), (uint8_t *) _data, target_format, target_width, target_height);
|
av_image_fill_arrays(_frame->data, _frame->linesize, (uint8_t *) _data, target_format, target_width, target_height,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
template<bool decoder = true>
|
template<bool decoder = true>
|
||||||
static inline AVCodec *getCodec_l(const char *name) {
|
static inline const AVCodec *getCodec_l(const char *name) {
|
||||||
auto codec = decoder ? avcodec_find_decoder_by_name(name) : avcodec_find_encoder_by_name(name);
|
auto codec = decoder ? avcodec_find_decoder_by_name(name) : avcodec_find_encoder_by_name(name);
|
||||||
if (codec) {
|
if (codec) {
|
||||||
InfoL << (decoder ? "got decoder:" : "got encoder:") << name;
|
InfoL << (decoder ? "got decoder:" : "got encoder:") << name;
|
||||||
@ -261,7 +263,7 @@ static inline AVCodec *getCodec_l(const char *name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<bool decoder = true>
|
template<bool decoder = true>
|
||||||
static inline AVCodec *getCodec_l(enum AVCodecID id) {
|
static inline const AVCodec *getCodec_l(enum AVCodecID id) {
|
||||||
auto codec = decoder ? avcodec_find_decoder(id) : avcodec_find_encoder(id);
|
auto codec = decoder ? avcodec_find_decoder(id) : avcodec_find_encoder(id);
|
||||||
if (codec) {
|
if (codec) {
|
||||||
InfoL << (decoder ? "got decoder:" : "got encoder:") << avcodec_get_name(id);
|
InfoL << (decoder ? "got decoder:" : "got encoder:") << avcodec_get_name(id);
|
||||||
@ -277,7 +279,7 @@ public:
|
|||||||
CodecName(enum AVCodecID id) : _id(id) {}
|
CodecName(enum AVCodecID id) : _id(id) {}
|
||||||
|
|
||||||
template <bool decoder>
|
template <bool decoder>
|
||||||
AVCodec *getCodec() const {
|
const AVCodec *getCodec() const {
|
||||||
if (!_codec_name.empty()) {
|
if (!_codec_name.empty()) {
|
||||||
return getCodec_l<decoder>(_codec_name.data());
|
return getCodec_l<decoder>(_codec_name.data());
|
||||||
}
|
}
|
||||||
@ -290,8 +292,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <bool decoder = true>
|
template <bool decoder = true>
|
||||||
static inline AVCodec *getCodec(const std::initializer_list<CodecName> &codec_list) {
|
static inline const AVCodec *getCodec(const std::initializer_list<CodecName> &codec_list) {
|
||||||
AVCodec *ret = nullptr;
|
const AVCodec *ret = nullptr;
|
||||||
for (int i = codec_list.size(); i >= 1; --i) {
|
for (int i = codec_list.size(); i >= 1; --i) {
|
||||||
ret = codec_list.begin()[i - 1].getCodec<decoder>();
|
ret = codec_list.begin()[i - 1].getCodec<decoder>();
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@ -303,8 +305,8 @@ static inline AVCodec *getCodec(const std::initializer_list<CodecName> &codec_li
|
|||||||
|
|
||||||
FFmpegDecoder::FFmpegDecoder(const Track::Ptr &track, int thread_num) {
|
FFmpegDecoder::FFmpegDecoder(const Track::Ptr &track, int thread_num) {
|
||||||
setupFFmpeg();
|
setupFFmpeg();
|
||||||
AVCodec *codec = nullptr;
|
const AVCodec *codec = nullptr;
|
||||||
AVCodec *codec_default = nullptr;
|
const AVCodec *codec_default = nullptr;
|
||||||
switch (track->getCodecId()) {
|
switch (track->getCodecId()) {
|
||||||
case CodecH264:
|
case CodecH264:
|
||||||
codec_default = getCodec({AV_CODEC_ID_H264});
|
codec_default = getCodec({AV_CODEC_ID_H264});
|
||||||
@ -358,7 +360,9 @@ FFmpegDecoder::FFmpegDecoder(const Track::Ptr &track, int thread_num) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//保存AVFrame的引用
|
//保存AVFrame的引用
|
||||||
|
#ifdef FF_API_OLD_ENCDEC
|
||||||
_context->refcounted_frames = 1;
|
_context->refcounted_frames = 1;
|
||||||
|
#endif
|
||||||
_context->flags |= AV_CODEC_FLAG_LOW_DELAY;
|
_context->flags |= AV_CODEC_FLAG_LOW_DELAY;
|
||||||
_context->flags2 |= AV_CODEC_FLAG2_FAST;
|
_context->flags2 |= AV_CODEC_FLAG2_FAST;
|
||||||
if (track->getTrackType() == TrackVideo) {
|
if (track->getTrackType() == TrackVideo) {
|
||||||
@ -539,7 +543,7 @@ FFmpegSwr::~FFmpegSwr() {
|
|||||||
FFmpegFrame::Ptr FFmpegSwr::inputFrame(const FFmpegFrame::Ptr &frame) {
|
FFmpegFrame::Ptr FFmpegSwr::inputFrame(const FFmpegFrame::Ptr &frame) {
|
||||||
if (frame->get()->format == _target_format &&
|
if (frame->get()->format == _target_format &&
|
||||||
frame->get()->channels == _target_channels &&
|
frame->get()->channels == _target_channels &&
|
||||||
frame->get()->channel_layout == _target_channel_layout &&
|
frame->get()->channel_layout == (uint64_t)_target_channel_layout &&
|
||||||
frame->get()->sample_rate == _target_samplerate) {
|
frame->get()->sample_rate == _target_samplerate) {
|
||||||
//不转格式
|
//不转格式
|
||||||
return frame;
|
return frame;
|
||||||
@ -596,7 +600,8 @@ int FFmpegSws::inputFrame(const FFmpegFrame::Ptr &frame, uint8_t *data) {
|
|||||||
}
|
}
|
||||||
AVFrame dst;
|
AVFrame dst;
|
||||||
memset(&dst, 0, sizeof(dst));
|
memset(&dst, 0, sizeof(dst));
|
||||||
avpicture_fill((AVPicture *) &dst, data, _target_format, _target_width, _target_height);
|
av_image_fill_arrays(dst.data, dst.linesize, data, _target_format, _target_width, _target_height,1);
|
||||||
|
|
||||||
if (!_ctx) {
|
if (!_ctx) {
|
||||||
_ctx = sws_getContext(frame->get()->width, frame->get()->height, (enum AVPixelFormat) frame->get()->format,
|
_ctx = sws_getContext(frame->get()->width, frame->get()->height, (enum AVPixelFormat) frame->get()->format,
|
||||||
_target_width, _target_height, _target_format, SWS_FAST_BILINEAR, NULL, NULL, NULL);
|
_target_width, _target_height, _target_format, SWS_FAST_BILINEAR, NULL, NULL, NULL);
|
||||||
|
@ -25,6 +25,7 @@ extern "C" {
|
|||||||
#include "libavcodec/avcodec.h"
|
#include "libavcodec/avcodec.h"
|
||||||
#include "libswresample/swresample.h"
|
#include "libswresample/swresample.h"
|
||||||
#include "libavutil/audio_fifo.h"
|
#include "libavutil/audio_fifo.h"
|
||||||
|
#include "libavutil/imgutils.h"
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -354,64 +354,12 @@ void MultiMediaSourceMuxer::resetTracks() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//该类实现frame级别的时间戳覆盖
|
|
||||||
class FrameModifyStamp : public Frame{
|
|
||||||
public:
|
|
||||||
typedef std::shared_ptr<FrameModifyStamp> Ptr;
|
|
||||||
FrameModifyStamp(const Frame::Ptr &frame, Stamp &stamp){
|
|
||||||
_frame = frame;
|
|
||||||
//覆盖时间戳
|
|
||||||
stamp.revise(frame->dts(), frame->pts(), _dts, _pts, true);
|
|
||||||
}
|
|
||||||
~FrameModifyStamp() override {}
|
|
||||||
|
|
||||||
uint32_t dts() const override{
|
|
||||||
return (uint32_t)_dts;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t pts() const override{
|
|
||||||
return (uint32_t)_pts;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t prefixSize() const override {
|
|
||||||
return _frame->prefixSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool keyFrame() const override {
|
|
||||||
return _frame->keyFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool configFrame() const override {
|
|
||||||
return _frame->configFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cacheAble() const override {
|
|
||||||
return _frame->cacheAble();
|
|
||||||
}
|
|
||||||
|
|
||||||
char *data() const override {
|
|
||||||
return _frame->data();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size() const override {
|
|
||||||
return _frame->size();
|
|
||||||
}
|
|
||||||
|
|
||||||
CodecId getCodecId() const override {
|
|
||||||
return _frame->getCodecId();
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
int64_t _dts;
|
|
||||||
int64_t _pts;
|
|
||||||
Frame::Ptr _frame;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool MultiMediaSourceMuxer::onTrackFrame(const Frame::Ptr &frame_in) {
|
bool MultiMediaSourceMuxer::onTrackFrame(const Frame::Ptr &frame_in) {
|
||||||
GET_CONFIG(bool, modify_stamp, General::kModifyStamp);
|
GET_CONFIG(bool, modify_stamp, General::kModifyStamp);
|
||||||
auto frame = frame_in;
|
auto frame = frame_in;
|
||||||
if (modify_stamp) {
|
if (modify_stamp) {
|
||||||
//开启了时间戳覆盖
|
//开启了时间戳覆盖
|
||||||
frame = std::make_shared<FrameModifyStamp>(frame, _stamp[frame->getTrackType()]);
|
frame = std::make_shared<FrameStamp>(frame, _stamp[frame->getTrackType()],true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
@ -274,6 +274,9 @@ bool AACTrack::inputFrame(const Frame::Ptr &frame) {
|
|||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
//有adts头,尝试分帧
|
//有adts头,尝试分帧
|
||||||
|
int64_t dts = frame->dts();
|
||||||
|
int64_t pts = frame->pts();
|
||||||
|
|
||||||
auto ptr = frame->data();
|
auto ptr = frame->data();
|
||||||
auto end = frame->data() + frame->size();
|
auto end = frame->data() + frame->size();
|
||||||
while (ptr < end) {
|
while (ptr < end) {
|
||||||
@ -284,7 +287,7 @@ bool AACTrack::inputFrame(const Frame::Ptr &frame) {
|
|||||||
if (frame_len == frame->size()) {
|
if (frame_len == frame->size()) {
|
||||||
return inputFrame_l(frame);
|
return inputFrame_l(frame);
|
||||||
}
|
}
|
||||||
auto sub_frame = std::make_shared<FrameInternal<FrameFromPtr> >(frame, (char *) ptr, frame_len, ADTS_HEADER_LEN);
|
auto sub_frame = std::make_shared<FrameTSInternal<FrameFromPtr> >(frame, (char *) ptr, frame_len, ADTS_HEADER_LEN,dts,pts);
|
||||||
ptr += frame_len;
|
ptr += frame_len;
|
||||||
if (ptr > end) {
|
if (ptr > end) {
|
||||||
WarnL << "invalid aac length in adts header: " << frame_len
|
WarnL << "invalid aac length in adts header: " << frame_len
|
||||||
@ -295,6 +298,8 @@ bool AACTrack::inputFrame(const Frame::Ptr &frame) {
|
|||||||
if (inputFrame_l(sub_frame)) {
|
if (inputFrame_l(sub_frame)) {
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
dts += 1024*1000/getAudioSampleRate();
|
||||||
|
pts += 1024*1000/getAudioSampleRate();
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ bool CommonRtpEncoder::inputFrame(const Frame::Ptr &frame){
|
|||||||
auto len = frame->size() - frame->prefixSize();
|
auto len = frame->size() - frame->prefixSize();
|
||||||
auto remain_size = len;
|
auto remain_size = len;
|
||||||
auto max_size = getMaxSize();
|
auto max_size = getMaxSize();
|
||||||
|
bool is_key = frame->keyFrame();
|
||||||
bool mark = false;
|
bool mark = false;
|
||||||
while (remain_size > 0) {
|
while (remain_size > 0) {
|
||||||
size_t rtp_size;
|
size_t rtp_size;
|
||||||
@ -86,9 +86,10 @@ bool CommonRtpEncoder::inputFrame(const Frame::Ptr &frame){
|
|||||||
rtp_size = remain_size;
|
rtp_size = remain_size;
|
||||||
mark = true;
|
mark = true;
|
||||||
}
|
}
|
||||||
RtpCodec::inputRtp(makeRtp(getTrackType(), ptr, rtp_size, mark, stamp), false);
|
RtpCodec::inputRtp(makeRtp(getTrackType(), ptr, rtp_size, mark, stamp), is_key);
|
||||||
ptr += rtp_size;
|
ptr += rtp_size;
|
||||||
remain_size -= rtp_size;
|
remain_size -= rtp_size;
|
||||||
|
is_key = false;
|
||||||
}
|
}
|
||||||
return len > 0;
|
return len > 0;
|
||||||
}
|
}
|
@ -95,6 +95,32 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Track::Ptr Factory::getTrackByAbstractTrack(const Track::Ptr& track) {
|
||||||
|
auto codec = track->getCodecId();
|
||||||
|
switch (codec) {
|
||||||
|
case CodecG711A:
|
||||||
|
case CodecG711U: {
|
||||||
|
auto audio_track = dynamic_pointer_cast<AudioTrackImp>(track);
|
||||||
|
return std::make_shared<G711Track>(codec, audio_track->getAudioSampleRate(), audio_track->getAudioChannel(), 16);
|
||||||
|
}
|
||||||
|
case CodecL16: {
|
||||||
|
auto audio_track = dynamic_pointer_cast<AudioTrackImp>(track);
|
||||||
|
return std::make_shared<L16Track>(audio_track->getAudioSampleRate(), audio_track->getAudioChannel());
|
||||||
|
}
|
||||||
|
case CodecAAC : return std::make_shared<AACTrack>();
|
||||||
|
case CodecOpus : return std::make_shared<OpusTrack>();
|
||||||
|
case CodecH265 : return std::make_shared<H265Track>();
|
||||||
|
case CodecH264 : return std::make_shared<H264Track>();
|
||||||
|
|
||||||
|
default: {
|
||||||
|
//其他codec不支持
|
||||||
|
WarnL << "暂不支持该该编码类型创建Track:" << track->getCodecName();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RtpCodec::Ptr Factory::getRtpEncoderBySdp(const Sdp::Ptr &sdp) {
|
RtpCodec::Ptr Factory::getRtpEncoderBySdp(const Sdp::Ptr &sdp) {
|
||||||
GET_CONFIG(uint32_t,audio_mtu,Rtp::kAudioMtuSize);
|
GET_CONFIG(uint32_t,audio_mtu,Rtp::kAudioMtuSize);
|
||||||
GET_CONFIG(uint32_t,video_mtu,Rtp::kVideoMtuSize);
|
GET_CONFIG(uint32_t,video_mtu,Rtp::kVideoMtuSize);
|
||||||
|
@ -27,6 +27,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
static Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track);
|
static Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据c api 抽象的Track生成具体Track对象
|
||||||
|
*/
|
||||||
|
static Track::Ptr getTrackByAbstractTrack(const Track::Ptr& track);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据sdp生成rtp编码器
|
* 根据sdp生成rtp编码器
|
||||||
* @param sdp sdp对象
|
* @param sdp sdp对象
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include "Util/RingBuffer.h"
|
#include "Util/RingBuffer.h"
|
||||||
#include "Network/Socket.h"
|
#include "Network/Socket.h"
|
||||||
|
#include "Common/Stamp.h"
|
||||||
|
|
||||||
namespace mediakit{
|
namespace mediakit{
|
||||||
|
|
||||||
@ -262,6 +263,27 @@ private:
|
|||||||
Frame::Ptr _parent_frame;
|
Frame::Ptr _parent_frame;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一个Frame类中可以有多个帧(AAC),时间戳会变化
|
||||||
|
* ZLMediaKit会先把这种复合帧split成单个帧然后再处理
|
||||||
|
* 一个复合帧可以通过无内存拷贝的方式切割成多个子Frame
|
||||||
|
* 提供该类的目的是切割复合帧时防止内存拷贝,提高性能
|
||||||
|
*/
|
||||||
|
template<typename Parent>
|
||||||
|
class FrameTSInternal : public Parent{
|
||||||
|
public:
|
||||||
|
typedef std::shared_ptr<FrameTSInternal> Ptr;
|
||||||
|
FrameTSInternal(const Frame::Ptr &parent_frame, char *ptr, size_t size, size_t prefix_size,uint32_t dts,uint32_t pts)
|
||||||
|
: Parent(ptr, size, dts, pts, prefix_size) {
|
||||||
|
_parent_frame = parent_frame;
|
||||||
|
}
|
||||||
|
bool cacheAble() const override {
|
||||||
|
return _parent_frame->cacheAble();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Frame::Ptr _parent_frame;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 写帧接口的抽象接口类
|
* 写帧接口的抽象接口类
|
||||||
*/
|
*/
|
||||||
@ -369,17 +391,18 @@ class FrameFromPtr : public Frame{
|
|||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<FrameFromPtr> Ptr;
|
typedef std::shared_ptr<FrameFromPtr> Ptr;
|
||||||
|
|
||||||
FrameFromPtr(CodecId codec_id, char *ptr, size_t size, uint32_t dts, uint32_t pts = 0, size_t prefix_size = 0)
|
FrameFromPtr(CodecId codec_id, char *ptr, size_t size, uint32_t dts, uint32_t pts = 0, size_t prefix_size = 0,bool is_key = false )
|
||||||
: FrameFromPtr(ptr, size, dts, pts, prefix_size) {
|
: FrameFromPtr(ptr, size, dts, pts, prefix_size,is_key) {
|
||||||
_codec_id = codec_id;
|
_codec_id = codec_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameFromPtr(char *ptr, size_t size, uint32_t dts, uint32_t pts = 0, size_t prefix_size = 0){
|
FrameFromPtr(char *ptr, size_t size, uint32_t dts, uint32_t pts = 0, size_t prefix_size = 0,bool is_key = false){
|
||||||
_ptr = ptr;
|
_ptr = ptr;
|
||||||
_size = size;
|
_size = size;
|
||||||
_dts = dts;
|
_dts = dts;
|
||||||
_pts = pts;
|
_pts = pts;
|
||||||
_prefix_size = prefix_size;
|
_prefix_size = prefix_size;
|
||||||
|
_is_key = is_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *data() const override{
|
char *data() const override{
|
||||||
@ -418,7 +441,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool keyFrame() const override {
|
bool keyFrame() const override {
|
||||||
return false;
|
return _is_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool configFrame() const override{
|
bool configFrame() const override{
|
||||||
@ -435,6 +458,7 @@ protected:
|
|||||||
size_t _size;
|
size_t _size;
|
||||||
size_t _prefix_size;
|
size_t _prefix_size;
|
||||||
CodecId _codec_id = CodecInvalid;
|
CodecId _codec_id = CodecInvalid;
|
||||||
|
bool _is_key;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -498,6 +522,58 @@ private:
|
|||||||
FrameImp::Ptr _buffer;
|
FrameImp::Ptr _buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//该类实现frame级别的时间戳覆盖
|
||||||
|
class FrameStamp : public Frame{
|
||||||
|
public:
|
||||||
|
typedef std::shared_ptr<FrameStamp> Ptr;
|
||||||
|
FrameStamp(const Frame::Ptr &frame, Stamp &stamp,bool modify_stamp){
|
||||||
|
_frame = frame;
|
||||||
|
//覆盖时间戳
|
||||||
|
stamp.revise(frame->dts(), frame->pts(), _dts, _pts, modify_stamp);
|
||||||
|
}
|
||||||
|
~FrameStamp() override {}
|
||||||
|
|
||||||
|
uint32_t dts() const override{
|
||||||
|
return (uint32_t)_dts;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pts() const override{
|
||||||
|
return (uint32_t)_pts;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t prefixSize() const override {
|
||||||
|
return _frame->prefixSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool keyFrame() const override {
|
||||||
|
return _frame->keyFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool configFrame() const override {
|
||||||
|
return _frame->configFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cacheAble() const override {
|
||||||
|
return _frame->cacheAble();
|
||||||
|
}
|
||||||
|
|
||||||
|
char *data() const override {
|
||||||
|
return _frame->data();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const override {
|
||||||
|
return _frame->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
CodecId getCodecId() const override {
|
||||||
|
return _frame->getCodecId();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
int64_t _dts;
|
||||||
|
int64_t _pts;
|
||||||
|
Frame::Ptr _frame;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 该对象可以把Buffer对象转换成可缓存的Frame对象
|
* 该对象可以把Buffer对象转换成可缓存的Frame对象
|
||||||
*/
|
*/
|
||||||
|
@ -8,55 +8,67 @@
|
|||||||
* may be found in the AUTHORS file in the root of the source tree.
|
* may be found in the AUTHORS file in the root of the source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include "Rtcp.h"
|
#include "Rtcp.h"
|
||||||
#include "Util/logger.h"
|
|
||||||
#include "RtcpFCI.h"
|
#include "RtcpFCI.h"
|
||||||
|
#include "Util/logger.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace toolkit;
|
using namespace toolkit;
|
||||||
|
|
||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
|
|
||||||
const char *rtcpTypeToStr(RtcpType type){
|
const char *rtcpTypeToStr(RtcpType type) {
|
||||||
switch (type){
|
switch (type) {
|
||||||
#define SWITCH_CASE(key, value) case RtcpType::key : return #value "(" #key ")";
|
#define SWITCH_CASE(key, value) \
|
||||||
|
case RtcpType::key: \
|
||||||
|
return #value "(" #key ")";
|
||||||
RTCP_PT_MAP(SWITCH_CASE)
|
RTCP_PT_MAP(SWITCH_CASE)
|
||||||
#undef SWITCH_CASE
|
#undef SWITCH_CASE
|
||||||
default: return "unknown rtcp pt";
|
default:
|
||||||
|
return "unknown rtcp pt";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *sdesTypeToStr(SdesType type){
|
const char *sdesTypeToStr(SdesType type) {
|
||||||
switch (type){
|
switch (type) {
|
||||||
#define SWITCH_CASE(key, value) case SdesType::key : return #value "(" #key ")";
|
#define SWITCH_CASE(key, value) \
|
||||||
|
case SdesType::key: \
|
||||||
|
return #value "(" #key ")";
|
||||||
SDES_TYPE_MAP(SWITCH_CASE)
|
SDES_TYPE_MAP(SWITCH_CASE)
|
||||||
#undef SWITCH_CASE
|
#undef SWITCH_CASE
|
||||||
default: return "unknown source description type";
|
default:
|
||||||
|
return "unknown source description type";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *psfbTypeToStr(PSFBType type) {
|
const char *psfbTypeToStr(PSFBType type) {
|
||||||
switch (type){
|
switch (type) {
|
||||||
#define SWITCH_CASE(key, value) case PSFBType::key : return #value "(" #key ")";
|
#define SWITCH_CASE(key, value) \
|
||||||
|
case PSFBType::key: \
|
||||||
|
return #value "(" #key ")";
|
||||||
PSFB_TYPE_MAP(SWITCH_CASE)
|
PSFB_TYPE_MAP(SWITCH_CASE)
|
||||||
#undef SWITCH_CASE
|
#undef SWITCH_CASE
|
||||||
default: return "unknown payload-specific fb message fmt type";
|
default:
|
||||||
|
return "unknown payload-specific fb message fmt type";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *rtpfbTypeToStr(RTPFBType type) {
|
const char *rtpfbTypeToStr(RTPFBType type) {
|
||||||
switch (type){
|
switch (type) {
|
||||||
#define SWITCH_CASE(key, value) case RTPFBType::key : return #value "(" #key ")";
|
#define SWITCH_CASE(key, value) \
|
||||||
|
case RTPFBType::key: \
|
||||||
|
return #value "(" #key ")";
|
||||||
RTPFB_TYPE_MAP(SWITCH_CASE)
|
RTPFB_TYPE_MAP(SWITCH_CASE)
|
||||||
#undef SWITCH_CASE
|
#undef SWITCH_CASE
|
||||||
default: return "unknown transport layer feedback messages fmt type";
|
default:
|
||||||
|
return "unknown transport layer feedback messages fmt type";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t alignSize(size_t bytes) {
|
static size_t alignSize(size_t bytes) {
|
||||||
return (size_t) ((bytes + 3) >> 2) << 2;
|
return (size_t)((bytes + 3) >> 2) << 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setupHeader(RtcpHeader *rtcp, RtcpType type, size_t report_count, size_t total_bytes) {
|
static void setupHeader(RtcpHeader *rtcp, RtcpType type, size_t report_count, size_t total_bytes) {
|
||||||
@ -65,16 +77,16 @@ static void setupHeader(RtcpHeader *rtcp, RtcpType type, size_t report_count, si
|
|||||||
if (report_count > 0x1F) {
|
if (report_count > 0x1F) {
|
||||||
throw std::invalid_argument(StrPrinter << "rtcp report_count最大赋值为31,当前为:" << report_count);
|
throw std::invalid_argument(StrPrinter << "rtcp report_count最大赋值为31,当前为:" << report_count);
|
||||||
}
|
}
|
||||||
//items总个数
|
// items总个数
|
||||||
rtcp->report_count = report_count;
|
rtcp->report_count = report_count;
|
||||||
rtcp->pt = (uint8_t) type;
|
rtcp->pt = (uint8_t)type;
|
||||||
rtcp->setSize(total_bytes);
|
rtcp->setSize(total_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setupPadding(RtcpHeader *rtcp, size_t padding_size) {
|
static void setupPadding(RtcpHeader *rtcp, size_t padding_size) {
|
||||||
if (padding_size) {
|
if (padding_size) {
|
||||||
rtcp->padding = 1;
|
rtcp->padding = 1;
|
||||||
((uint8_t *) rtcp)[rtcp->getSize() - 1] = padding_size & 0xFF;
|
((uint8_t *)rtcp)[rtcp->getSize() - 1] = padding_size & 0xFF;
|
||||||
} else {
|
} else {
|
||||||
rtcp->padding = 0;
|
rtcp->padding = 0;
|
||||||
}
|
}
|
||||||
@ -91,110 +103,125 @@ string RtcpHeader::dumpHeader() const {
|
|||||||
printer << "padding:" << padding << "\r\n";
|
printer << "padding:" << padding << "\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ((RtcpType) pt) {
|
switch ((RtcpType)pt) {
|
||||||
case RtcpType::RTCP_RTPFB : {
|
case RtcpType::RTCP_RTPFB: {
|
||||||
printer << "report_count:" << rtpfbTypeToStr((RTPFBType) report_count) << "\r\n";
|
printer << "report_count:" << rtpfbTypeToStr((RTPFBType)report_count) << "\r\n";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RtcpType::RTCP_PSFB : {
|
case RtcpType::RTCP_PSFB: {
|
||||||
printer << "report_count:" << psfbTypeToStr((PSFBType) report_count) << "\r\n";
|
printer << "report_count:" << psfbTypeToStr((PSFBType)report_count) << "\r\n";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default : {
|
default: {
|
||||||
printer << "report_count:" << report_count << "\r\n";
|
printer << "report_count:" << report_count << "\r\n";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printer << "pt:" << rtcpTypeToStr((RtcpType) pt) << "\r\n";
|
printer << "pt:" << rtcpTypeToStr((RtcpType)pt) << "\r\n";
|
||||||
printer << "size:" << getSize() << "\r\n";
|
printer << "size:" << getSize() << "\r\n";
|
||||||
printer << "--------\r\n";
|
printer << "--------\r\n";
|
||||||
return std::move(printer);
|
return std::move(printer);
|
||||||
}
|
}
|
||||||
|
|
||||||
string RtcpHeader::dumpString() const {
|
string RtcpHeader::dumpString() const {
|
||||||
switch ((RtcpType) pt) {
|
switch ((RtcpType)pt) {
|
||||||
case RtcpType::RTCP_SR: {
|
case RtcpType::RTCP_SR: {
|
||||||
RtcpSR *rtcp = (RtcpSR *) this;
|
RtcpSR *rtcp = (RtcpSR *)this;
|
||||||
return rtcp->dumpString();
|
return rtcp->dumpString();
|
||||||
}
|
}
|
||||||
|
|
||||||
case RtcpType::RTCP_RR: {
|
case RtcpType::RTCP_RR: {
|
||||||
RtcpRR *rtcp = (RtcpRR *) this;
|
RtcpRR *rtcp = (RtcpRR *)this;
|
||||||
return rtcp->dumpString();
|
return rtcp->dumpString();
|
||||||
}
|
}
|
||||||
|
|
||||||
case RtcpType::RTCP_SDES: {
|
case RtcpType::RTCP_SDES: {
|
||||||
RtcpSdes *rtcp = (RtcpSdes *) this;
|
RtcpSdes *rtcp = (RtcpSdes *)this;
|
||||||
return rtcp->dumpString();
|
return rtcp->dumpString();
|
||||||
}
|
}
|
||||||
|
|
||||||
case RtcpType::RTCP_RTPFB:
|
case RtcpType::RTCP_RTPFB:
|
||||||
case RtcpType::RTCP_PSFB: {
|
case RtcpType::RTCP_PSFB: {
|
||||||
RtcpFB *rtcp = (RtcpFB *) this;
|
RtcpFB *rtcp = (RtcpFB *)this;
|
||||||
return rtcp->dumpString();
|
return rtcp->dumpString();
|
||||||
}
|
}
|
||||||
|
|
||||||
case RtcpType::RTCP_BYE: {
|
case RtcpType::RTCP_BYE: {
|
||||||
RtcpBye *rtcp = (RtcpBye *) this;
|
RtcpBye *rtcp = (RtcpBye *)this;
|
||||||
return rtcp->dumpString();
|
return rtcp->dumpString();
|
||||||
}
|
}
|
||||||
|
|
||||||
default: return StrPrinter << dumpHeader() << hexdump((char *)this + sizeof(*this), getSize() - sizeof(*this));
|
default:
|
||||||
|
return StrPrinter << dumpHeader() << hexdump((char *)this + sizeof(*this), getSize() - sizeof(*this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RtcpHeader::getSize() const {
|
size_t RtcpHeader::getSize() const {
|
||||||
//加上rtcp头长度
|
// 加上rtcp头长度
|
||||||
return (1 + ntohs(length)) << 2;
|
return (1 + ntohs(length)) << 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RtcpHeader::getPaddingSize() const{
|
size_t RtcpHeader::getPaddingSize() const {
|
||||||
if (!padding) {
|
if (!padding) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return ((uint8_t *) this)[getSize() - 1];
|
return ((uint8_t *)this)[getSize() - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtcpHeader::setSize(size_t size) {
|
void RtcpHeader::setSize(size_t size) {
|
||||||
//不包含rtcp头的长度
|
// 不包含rtcp头的长度
|
||||||
length = htons((uint16_t) ((size >> 2) - 1));
|
length = htons((uint16_t)((size >> 2) - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtcpHeader::net2Host(size_t len) {
|
void RtcpHeader::net2Host(size_t len) {
|
||||||
switch ((RtcpType) pt) {
|
switch ((RtcpType)pt) {
|
||||||
case RtcpType::RTCP_SR: {
|
case RtcpType::RTCP_SR: {
|
||||||
RtcpSR *sr = (RtcpSR *) this;
|
RtcpSR *sr = (RtcpSR *)this;
|
||||||
sr->net2Host(len);
|
sr->net2Host(len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RtcpType::RTCP_RR: {
|
case RtcpType::RTCP_RR: {
|
||||||
RtcpRR *rr = (RtcpRR *) this;
|
RtcpRR *rr = (RtcpRR *)this;
|
||||||
rr->net2Host(len);
|
rr->net2Host(len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RtcpType::RTCP_SDES: {
|
case RtcpType::RTCP_SDES: {
|
||||||
RtcpSdes *sdes = (RtcpSdes *) this;
|
RtcpSdes *sdes = (RtcpSdes *)this;
|
||||||
sdes->net2Host(len);
|
sdes->net2Host(len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RtcpType::RTCP_RTPFB:
|
case RtcpType::RTCP_RTPFB:
|
||||||
case RtcpType::RTCP_PSFB: {
|
case RtcpType::RTCP_PSFB: {
|
||||||
RtcpFB *fb = (RtcpFB *) this;
|
RtcpFB *fb = (RtcpFB *)this;
|
||||||
fb->net2Host(len);
|
fb->net2Host(len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RtcpType::RTCP_BYE: {
|
case RtcpType::RTCP_BYE: {
|
||||||
RtcpBye *bye = (RtcpBye *) this;
|
RtcpBye *bye = (RtcpBye *)this;
|
||||||
bye->net2Host(len);
|
bye->net2Host(len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case RtcpType::RTCP_XR: {
|
||||||
default: throw std::runtime_error(StrPrinter << "未处理的rtcp包:" << rtcpTypeToStr((RtcpType) this->pt));
|
RtcpXRRRTR *xr = (RtcpXRRRTR *)this;
|
||||||
|
if (xr->bt == 4) {
|
||||||
|
xr->net2Host(len);
|
||||||
|
// TraceL<<xr->dumpString();
|
||||||
|
} else if (xr->bt == 5) {
|
||||||
|
RtcpXRDLRR *dlrr = (RtcpXRDLRR *)this;
|
||||||
|
dlrr->net2Host(len);
|
||||||
|
TraceL << dlrr->dumpString();
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error(StrPrinter << "rtcp xr bt " << xr->bt << " not support");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::runtime_error(StrPrinter << "未处理的rtcp包:" << rtcpTypeToStr((RtcpType)this->pt));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,10 +229,10 @@ vector<RtcpHeader *> RtcpHeader::loadFromBytes(char *data, size_t len) {
|
|||||||
vector<RtcpHeader *> ret;
|
vector<RtcpHeader *> ret;
|
||||||
ssize_t remain = len;
|
ssize_t remain = len;
|
||||||
char *ptr = data;
|
char *ptr = data;
|
||||||
while (remain > (ssize_t) sizeof(RtcpHeader)) {
|
while (remain > (ssize_t)sizeof(RtcpHeader)) {
|
||||||
RtcpHeader *rtcp = (RtcpHeader *) ptr;
|
RtcpHeader *rtcp = (RtcpHeader *)ptr;
|
||||||
auto rtcp_len = rtcp->getSize();
|
auto rtcp_len = rtcp->getSize();
|
||||||
if (remain < (ssize_t) rtcp_len) {
|
if (remain < (ssize_t)rtcp_len) {
|
||||||
WarnL << "非法的rtcp包,声明的长度超过实际数据长度";
|
WarnL << "非法的rtcp包,声明的长度超过实际数据长度";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -213,7 +240,7 @@ vector<RtcpHeader *> RtcpHeader::loadFromBytes(char *data, size_t len) {
|
|||||||
rtcp->net2Host(rtcp_len);
|
rtcp->net2Host(rtcp_len);
|
||||||
ret.emplace_back(rtcp);
|
ret.emplace_back(rtcp);
|
||||||
} catch (std::exception &ex) {
|
} catch (std::exception &ex) {
|
||||||
//不能处理的rtcp包,或者无法解析的rtcp包,忽略掉
|
// 不能处理的rtcp包,或者无法解析的rtcp包,忽略掉
|
||||||
WarnL << ex.what() << ",长度为:" << rtcp_len;
|
WarnL << ex.what() << ",长度为:" << rtcp_len;
|
||||||
}
|
}
|
||||||
ptr += rtcp_len;
|
ptr += rtcp_len;
|
||||||
@ -224,19 +251,13 @@ vector<RtcpHeader *> RtcpHeader::loadFromBytes(char *data, size_t len) {
|
|||||||
|
|
||||||
class BufferRtcp : public Buffer {
|
class BufferRtcp : public Buffer {
|
||||||
public:
|
public:
|
||||||
BufferRtcp(std::shared_ptr<RtcpHeader> rtcp) {
|
BufferRtcp(std::shared_ptr<RtcpHeader> rtcp) { _rtcp = std::move(rtcp); }
|
||||||
_rtcp = std::move(rtcp);
|
|
||||||
}
|
|
||||||
|
|
||||||
~BufferRtcp() override {}
|
~BufferRtcp() override {}
|
||||||
|
|
||||||
char *data() const override {
|
char *data() const override { return (char *)_rtcp.get(); }
|
||||||
return (char *) _rtcp.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size() const override {
|
size_t size() const override { return _rtcp->getSize(); }
|
||||||
return _rtcp->getSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<RtcpHeader> _rtcp;
|
std::shared_ptr<RtcpHeader> _rtcp;
|
||||||
@ -251,36 +272,34 @@ Buffer::Ptr RtcpHeader::toBuffer(std::shared_ptr<RtcpHeader> rtcp) {
|
|||||||
std::shared_ptr<RtcpSR> RtcpSR::create(size_t item_count) {
|
std::shared_ptr<RtcpSR> RtcpSR::create(size_t item_count) {
|
||||||
auto real_size = sizeof(RtcpSR) - sizeof(ReportItem) + item_count * sizeof(ReportItem);
|
auto real_size = sizeof(RtcpSR) - sizeof(ReportItem) + item_count * sizeof(ReportItem);
|
||||||
auto bytes = alignSize(real_size);
|
auto bytes = alignSize(real_size);
|
||||||
auto ptr = (RtcpSR *) new char[bytes];
|
auto ptr = (RtcpSR *)new char[bytes];
|
||||||
setupHeader(ptr, RtcpType::RTCP_SR, item_count, bytes);
|
setupHeader(ptr, RtcpType::RTCP_SR, item_count, bytes);
|
||||||
setupPadding(ptr, bytes - real_size);
|
setupPadding(ptr, bytes - real_size);
|
||||||
return std::shared_ptr<RtcpSR>(ptr, [](RtcpSR *ptr) {
|
return std::shared_ptr<RtcpSR>(ptr, [](RtcpSR *ptr) { delete[] (char *)ptr; });
|
||||||
delete[] (char *) ptr;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string RtcpSR::getNtpStamp() const {
|
string RtcpSR::getNtpStamp() const {
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
tv.tv_sec = ntpmsw - 0x83AA7E80;
|
tv.tv_sec = ntpmsw - 0x83AA7E80;
|
||||||
tv.tv_usec = (decltype(tv.tv_usec)) (ntplsw / ((double) (((uint64_t) 1) << 32) * 1.0e-6));
|
tv.tv_usec = (decltype(tv.tv_usec))(ntplsw / ((double)(((uint64_t)1) << 32) * 1.0e-6));
|
||||||
return LogChannel::printTime(tv);
|
return LogChannel::printTime(tv);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t RtcpSR::getNtpUnixStampMS() const {
|
uint64_t RtcpSR::getNtpUnixStampMS() const {
|
||||||
if (ntpmsw < 0x83AA7E80) {
|
if (ntpmsw < 0x83AA7E80) {
|
||||||
//ntp时间戳起始时间为1900年,但是utc时间戳起始时间为1970年,两者相差0x83AA7E80秒
|
// ntp时间戳起始时间为1900年,但是utc时间戳起始时间为1970年,两者相差0x83AA7E80秒
|
||||||
//ntp时间戳不得早于1970年,否则无法转换为utc时间戳
|
// ntp时间戳不得早于1970年,否则无法转换为utc时间戳
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
tv.tv_sec = ntpmsw - 0x83AA7E80;
|
tv.tv_sec = ntpmsw - 0x83AA7E80;
|
||||||
tv.tv_usec = (decltype(tv.tv_usec)) (ntplsw / ((double) (((uint64_t) 1) << 32) * 1.0e-6));
|
tv.tv_usec = (decltype(tv.tv_usec))(ntplsw / ((double)(((uint64_t)1) << 32) * 1.0e-6));
|
||||||
return 1000 * tv.tv_sec + tv.tv_usec / 1000;
|
return 1000 * tv.tv_sec + tv.tv_usec / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtcpSR::setNtpStamp(struct timeval tv) {
|
void RtcpSR::setNtpStamp(struct timeval tv) {
|
||||||
ntpmsw = htonl(tv.tv_sec + 0x83AA7E80); /* 0x83AA7E80 is the number of seconds from 1900 to 1970 */
|
ntpmsw = htonl(tv.tv_sec + 0x83AA7E80); /* 0x83AA7E80 is the number of seconds from 1900 to 1970 */
|
||||||
ntplsw = htonl((uint32_t) ((double) tv.tv_usec * (double) (((uint64_t) 1) << 32) * 1.0e-6));
|
ntplsw = htonl((uint32_t)((double)tv.tv_usec * (double)(((uint64_t)1) << 32) * 1.0e-6));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtcpSR::setNtpStamp(uint64_t unix_stamp_ms) {
|
void RtcpSR::setNtpStamp(uint64_t unix_stamp_ms) {
|
||||||
@ -300,7 +319,7 @@ string RtcpSR::dumpString() const {
|
|||||||
printer << "rtpts:" << rtpts << "\r\n";
|
printer << "rtpts:" << rtpts << "\r\n";
|
||||||
printer << "packet_count:" << packet_count << "\r\n";
|
printer << "packet_count:" << packet_count << "\r\n";
|
||||||
printer << "octet_count:" << octet_count << "\r\n";
|
printer << "octet_count:" << octet_count << "\r\n";
|
||||||
auto items = ((RtcpSR *) this)->getItemList();
|
auto items = ((RtcpSR *)this)->getItemList();
|
||||||
auto i = 0;
|
auto i = 0;
|
||||||
for (auto &item : items) {
|
for (auto &item : items) {
|
||||||
printer << "---- item:" << i++ << " ----\r\n";
|
printer << "---- item:" << i++ << " ----\r\n";
|
||||||
@ -310,16 +329,18 @@ string RtcpSR::dumpString() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_MIN_SIZE(size, kMinSize) \
|
#define CHECK_MIN_SIZE(size, kMinSize) \
|
||||||
if (size < kMinSize) { \
|
if (size < kMinSize) { \
|
||||||
throw std::out_of_range(StrPrinter << rtcpTypeToStr((RtcpType)pt) << " 长度不足:" << size << " < " << kMinSize); \
|
throw std::out_of_range( \
|
||||||
}
|
StrPrinter << rtcpTypeToStr((RtcpType)pt) << " 长度不足:" << size << " < " << kMinSize); \
|
||||||
|
}
|
||||||
|
|
||||||
#define CHECK_REPORT_COUNT(item_count) \
|
#define CHECK_REPORT_COUNT(item_count) \
|
||||||
/*修正个数,防止getItemList时内存越界*/ \
|
/*修正个数,防止getItemList时内存越界*/ \
|
||||||
if (report_count != item_count) { \
|
if (report_count != item_count) { \
|
||||||
WarnL << rtcpTypeToStr((RtcpType)pt) << " report_count 字段不正确,已修正为:" << (int)report_count << " -> " << item_count; \
|
WarnL << rtcpTypeToStr((RtcpType)pt) << " report_count 字段不正确,已修正为:" << (int)report_count << " -> " \
|
||||||
|
<< item_count; \
|
||||||
report_count = item_count; \
|
report_count = item_count; \
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtcpSR::net2Host(size_t size) {
|
void RtcpSR::net2Host(size_t size) {
|
||||||
static const size_t kMinSize = sizeof(RtcpSR) - sizeof(items);
|
static const size_t kMinSize = sizeof(RtcpSR) - sizeof(items);
|
||||||
@ -334,7 +355,7 @@ void RtcpSR::net2Host(size_t size) {
|
|||||||
|
|
||||||
ReportItem *ptr = &items;
|
ReportItem *ptr = &items;
|
||||||
int item_count = 0;
|
int item_count = 0;
|
||||||
for (int i = 0; i < (int) report_count && (char *) (ptr) + sizeof(ReportItem) <= (char *) (this) + size; ++i) {
|
for (int i = 0; i < (int)report_count && (char *)(ptr) + sizeof(ReportItem) <= (char *)(this) + size; ++i) {
|
||||||
ptr->net2Host();
|
ptr->net2Host();
|
||||||
++ptr;
|
++ptr;
|
||||||
++item_count;
|
++item_count;
|
||||||
@ -345,7 +366,7 @@ void RtcpSR::net2Host(size_t size) {
|
|||||||
vector<ReportItem *> RtcpSR::getItemList() {
|
vector<ReportItem *> RtcpSR::getItemList() {
|
||||||
vector<ReportItem *> ret;
|
vector<ReportItem *> ret;
|
||||||
ReportItem *ptr = &items;
|
ReportItem *ptr = &items;
|
||||||
for (int i = 0; i < (int) report_count; ++i) {
|
for (int i = 0; i < (int)report_count; ++i) {
|
||||||
ret.emplace_back(ptr);
|
ret.emplace_back(ptr);
|
||||||
++ptr;
|
++ptr;
|
||||||
}
|
}
|
||||||
@ -382,19 +403,17 @@ void ReportItem::net2Host() {
|
|||||||
std::shared_ptr<RtcpRR> RtcpRR::create(size_t item_count) {
|
std::shared_ptr<RtcpRR> RtcpRR::create(size_t item_count) {
|
||||||
auto real_size = sizeof(RtcpRR) - sizeof(ReportItem) + item_count * sizeof(ReportItem);
|
auto real_size = sizeof(RtcpRR) - sizeof(ReportItem) + item_count * sizeof(ReportItem);
|
||||||
auto bytes = alignSize(real_size);
|
auto bytes = alignSize(real_size);
|
||||||
auto ptr = (RtcpRR *) new char[bytes];
|
auto ptr = (RtcpRR *)new char[bytes];
|
||||||
setupHeader(ptr, RtcpType::RTCP_RR, item_count, bytes);
|
setupHeader(ptr, RtcpType::RTCP_RR, item_count, bytes);
|
||||||
setupPadding(ptr, bytes - real_size);
|
setupPadding(ptr, bytes - real_size);
|
||||||
return std::shared_ptr<RtcpRR>(ptr, [](RtcpRR *ptr) {
|
return std::shared_ptr<RtcpRR>(ptr, [](RtcpRR *ptr) { delete[] (char *)ptr; });
|
||||||
delete[] (char *) ptr;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string RtcpRR::dumpString() const {
|
string RtcpRR::dumpString() const {
|
||||||
_StrPrinter printer;
|
_StrPrinter printer;
|
||||||
printer << RtcpHeader::dumpHeader();
|
printer << RtcpHeader::dumpHeader();
|
||||||
printer << "ssrc:" << ssrc << "\r\n";
|
printer << "ssrc:" << ssrc << "\r\n";
|
||||||
auto items = ((RtcpRR *) this)->getItemList();
|
auto items = ((RtcpRR *)this)->getItemList();
|
||||||
auto i = 0;
|
auto i = 0;
|
||||||
for (auto &item : items) {
|
for (auto &item : items) {
|
||||||
printer << "---- item:" << i++ << " ----\r\n";
|
printer << "---- item:" << i++ << " ----\r\n";
|
||||||
@ -410,7 +429,7 @@ void RtcpRR::net2Host(size_t size) {
|
|||||||
|
|
||||||
ReportItem *ptr = &items;
|
ReportItem *ptr = &items;
|
||||||
int item_count = 0;
|
int item_count = 0;
|
||||||
for (int i = 0; i < (int) report_count && (char *) (ptr) + sizeof(ReportItem) <= (char *) (this) + size; ++i) {
|
for (int i = 0; i < (int)report_count && (char *)(ptr) + sizeof(ReportItem) <= (char *)(this) + size; ++i) {
|
||||||
ptr->net2Host();
|
ptr->net2Host();
|
||||||
++ptr;
|
++ptr;
|
||||||
++item_count;
|
++item_count;
|
||||||
@ -421,7 +440,7 @@ void RtcpRR::net2Host(size_t size) {
|
|||||||
vector<ReportItem *> RtcpRR::getItemList() {
|
vector<ReportItem *> RtcpRR::getItemList() {
|
||||||
vector<ReportItem *> ret;
|
vector<ReportItem *> ret;
|
||||||
ReportItem *ptr = &items;
|
ReportItem *ptr = &items;
|
||||||
for (int i = 0; i < (int) report_count; ++i) {
|
for (int i = 0; i < (int)report_count; ++i) {
|
||||||
ret.emplace_back(ptr);
|
ret.emplace_back(ptr);
|
||||||
++ptr;
|
++ptr;
|
||||||
}
|
}
|
||||||
@ -445,8 +464,8 @@ size_t SdesChunk::minSize() {
|
|||||||
string SdesChunk::dumpString() const {
|
string SdesChunk::dumpString() const {
|
||||||
_StrPrinter printer;
|
_StrPrinter printer;
|
||||||
printer << "ssrc:" << ssrc << "\r\n";
|
printer << "ssrc:" << ssrc << "\r\n";
|
||||||
printer << "type:" << sdesTypeToStr((SdesType) type) << "\r\n";
|
printer << "type:" << sdesTypeToStr((SdesType)type) << "\r\n";
|
||||||
printer << "txt_len:" << (int) txt_len << "\r\n";
|
printer << "txt_len:" << (int)txt_len << "\r\n";
|
||||||
printer << "text:" << (txt_len ? string(text, txt_len) : "") << "\r\n";
|
printer << "text:" << (txt_len ? string(text, txt_len) : "") << "\r\n";
|
||||||
return std::move(printer);
|
return std::move(printer);
|
||||||
}
|
}
|
||||||
@ -456,32 +475,30 @@ string SdesChunk::dumpString() const {
|
|||||||
std::shared_ptr<RtcpSdes> RtcpSdes::create(const std::vector<string> &item_text) {
|
std::shared_ptr<RtcpSdes> RtcpSdes::create(const std::vector<string> &item_text) {
|
||||||
size_t item_total_size = 0;
|
size_t item_total_size = 0;
|
||||||
for (auto &text : item_text) {
|
for (auto &text : item_text) {
|
||||||
//统计所有SdesChunk对象占用的空间
|
// 统计所有SdesChunk对象占用的空间
|
||||||
item_total_size += alignSize(SdesChunk::minSize() + (0xFF & text.size()));
|
item_total_size += alignSize(SdesChunk::minSize() + (0xFF & text.size()));
|
||||||
}
|
}
|
||||||
auto real_size = sizeof(RtcpSdes) - sizeof(SdesChunk) + item_total_size;
|
auto real_size = sizeof(RtcpSdes) - sizeof(SdesChunk) + item_total_size;
|
||||||
auto bytes = alignSize(real_size);
|
auto bytes = alignSize(real_size);
|
||||||
auto ptr = (RtcpSdes *) new char[bytes];
|
auto ptr = (RtcpSdes *)new char[bytes];
|
||||||
memset(ptr, 0x00, bytes);
|
memset(ptr, 0x00, bytes);
|
||||||
auto item_ptr = &ptr->chunks;
|
auto item_ptr = &ptr->chunks;
|
||||||
for (auto &text : item_text) {
|
for (auto &text : item_text) {
|
||||||
item_ptr->txt_len = (0xFF & text.size());
|
item_ptr->txt_len = (0xFF & text.size());
|
||||||
//确保赋值\0为RTCP_SDES_END
|
// 确保赋值\0为RTCP_SDES_END
|
||||||
memcpy(item_ptr->text, text.data(), item_ptr->txt_len + 1);
|
memcpy(item_ptr->text, text.data(), item_ptr->txt_len + 1);
|
||||||
item_ptr = (SdesChunk *) ((char *) item_ptr + item_ptr->totalBytes());
|
item_ptr = (SdesChunk *)((char *)item_ptr + item_ptr->totalBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
setupHeader(ptr, RtcpType::RTCP_SDES, item_text.size(), bytes);
|
setupHeader(ptr, RtcpType::RTCP_SDES, item_text.size(), bytes);
|
||||||
setupPadding(ptr, bytes - real_size);
|
setupPadding(ptr, bytes - real_size);
|
||||||
return std::shared_ptr<RtcpSdes>(ptr, [](RtcpSdes *ptr) {
|
return std::shared_ptr<RtcpSdes>(ptr, [](RtcpSdes *ptr) { delete[] (char *)ptr; });
|
||||||
delete[] (char *) ptr;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string RtcpSdes::dumpString() const {
|
string RtcpSdes::dumpString() const {
|
||||||
_StrPrinter printer;
|
_StrPrinter printer;
|
||||||
printer << RtcpHeader::dumpHeader();
|
printer << RtcpHeader::dumpHeader();
|
||||||
auto items = ((RtcpSdes *) this)->getChunkList();
|
auto items = ((RtcpSdes *)this)->getChunkList();
|
||||||
auto i = 0;
|
auto i = 0;
|
||||||
for (auto &item : items) {
|
for (auto &item : items) {
|
||||||
printer << "---- item:" << i++ << " ----\r\n";
|
printer << "---- item:" << i++ << " ----\r\n";
|
||||||
@ -495,9 +512,9 @@ void RtcpSdes::net2Host(size_t size) {
|
|||||||
CHECK_MIN_SIZE(size, kMinSize);
|
CHECK_MIN_SIZE(size, kMinSize);
|
||||||
SdesChunk *ptr = &chunks;
|
SdesChunk *ptr = &chunks;
|
||||||
int item_count = 0;
|
int item_count = 0;
|
||||||
for (int i = 0; i < (int) report_count && (char *) (ptr) + SdesChunk::minSize() <= (char *) (this) + size; ++i) {
|
for (int i = 0; i < (int)report_count && (char *)(ptr) + SdesChunk::minSize() <= (char *)(this) + size; ++i) {
|
||||||
ptr->net2Host();
|
ptr->net2Host();
|
||||||
ptr = (SdesChunk *) ((char *) ptr + ptr->totalBytes());
|
ptr = (SdesChunk *)((char *)ptr + ptr->totalBytes());
|
||||||
++item_count;
|
++item_count;
|
||||||
}
|
}
|
||||||
CHECK_REPORT_COUNT(item_count);
|
CHECK_REPORT_COUNT(item_count);
|
||||||
@ -506,9 +523,9 @@ void RtcpSdes::net2Host(size_t size) {
|
|||||||
vector<SdesChunk *> RtcpSdes::getChunkList() {
|
vector<SdesChunk *> RtcpSdes::getChunkList() {
|
||||||
vector<SdesChunk *> ret;
|
vector<SdesChunk *> ret;
|
||||||
SdesChunk *ptr = &chunks;
|
SdesChunk *ptr = &chunks;
|
||||||
for (int i = 0; i < (int) report_count; ++i) {
|
for (int i = 0; i < (int)report_count; ++i) {
|
||||||
ret.emplace_back(ptr);
|
ret.emplace_back(ptr);
|
||||||
ptr = (SdesChunk *) ((char *) ptr + ptr->totalBytes());
|
ptr = (SdesChunk *)((char *)ptr + ptr->totalBytes());
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -521,31 +538,29 @@ std::shared_ptr<RtcpFB> RtcpFB::create_l(RtcpType type, int fmt, const void *fci
|
|||||||
}
|
}
|
||||||
auto real_size = sizeof(RtcpFB) + fci_len;
|
auto real_size = sizeof(RtcpFB) + fci_len;
|
||||||
auto bytes = alignSize(real_size);
|
auto bytes = alignSize(real_size);
|
||||||
auto ptr = (RtcpFB *) new char[bytes];
|
auto ptr = (RtcpFB *)new char[bytes];
|
||||||
if (fci && fci_len) {
|
if (fci && fci_len) {
|
||||||
memcpy((char *) ptr + sizeof(RtcpFB), fci, fci_len);
|
memcpy((char *)ptr + sizeof(RtcpFB), fci, fci_len);
|
||||||
}
|
}
|
||||||
setupHeader(ptr, type, fmt, bytes);
|
setupHeader(ptr, type, fmt, bytes);
|
||||||
setupPadding(ptr, bytes - real_size);
|
setupPadding(ptr, bytes - real_size);
|
||||||
return std::shared_ptr<RtcpFB>((RtcpFB *) ptr, [](RtcpFB *ptr) {
|
return std::shared_ptr<RtcpFB>((RtcpFB *)ptr, [](RtcpFB *ptr) { delete[] (char *)ptr; });
|
||||||
delete[] (char *) ptr;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<RtcpFB> RtcpFB::create(PSFBType fmt, const void *fci, size_t fci_len) {
|
std::shared_ptr<RtcpFB> RtcpFB::create(PSFBType fmt, const void *fci, size_t fci_len) {
|
||||||
return RtcpFB::create_l(RtcpType::RTCP_PSFB, (int) fmt, fci, fci_len);
|
return RtcpFB::create_l(RtcpType::RTCP_PSFB, (int)fmt, fci, fci_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<RtcpFB> RtcpFB::create(RTPFBType fmt, const void *fci, size_t fci_len) {
|
std::shared_ptr<RtcpFB> RtcpFB::create(RTPFBType fmt, const void *fci, size_t fci_len) {
|
||||||
return RtcpFB::create_l(RtcpType::RTCP_RTPFB, (int) fmt, fci, fci_len);
|
return RtcpFB::create_l(RtcpType::RTCP_RTPFB, (int)fmt, fci, fci_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *RtcpFB::getFciPtr() const {
|
const void *RtcpFB::getFciPtr() const {
|
||||||
return (uint8_t *) &ssrc_media + sizeof(ssrc_media);
|
return (uint8_t *)&ssrc_media + sizeof(ssrc_media);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RtcpFB::getFciSize() const {
|
size_t RtcpFB::getFciSize() const {
|
||||||
auto fci_len = (ssize_t) getSize() - getPaddingSize() - sizeof(RtcpFB);
|
auto fci_len = (ssize_t)getSize() - getPaddingSize() - sizeof(RtcpFB);
|
||||||
CHECK(fci_len >= 0);
|
CHECK(fci_len >= 0);
|
||||||
return fci_len;
|
return fci_len;
|
||||||
}
|
}
|
||||||
@ -555,58 +570,60 @@ string RtcpFB::dumpString() const {
|
|||||||
printer << RtcpHeader::dumpHeader();
|
printer << RtcpHeader::dumpHeader();
|
||||||
printer << "ssrc:" << ssrc << "\r\n";
|
printer << "ssrc:" << ssrc << "\r\n";
|
||||||
printer << "ssrc_media:" << ssrc_media << "\r\n";
|
printer << "ssrc_media:" << ssrc_media << "\r\n";
|
||||||
switch ((RtcpType) pt) {
|
switch ((RtcpType)pt) {
|
||||||
case RtcpType::RTCP_PSFB : {
|
case RtcpType::RTCP_PSFB: {
|
||||||
switch ((PSFBType) report_count) {
|
switch ((PSFBType)report_count) {
|
||||||
case PSFBType::RTCP_PSFB_SLI : {
|
case PSFBType::RTCP_PSFB_SLI: {
|
||||||
auto &fci = getFci<FCI_SLI>();
|
auto &fci = getFci<FCI_SLI>();
|
||||||
printer << "fci:" << psfbTypeToStr((PSFBType) report_count) << " " << fci.dumpString();
|
printer << "fci:" << psfbTypeToStr((PSFBType)report_count) << " " << fci.dumpString();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PSFBType::RTCP_PSFB_PLI : {
|
case PSFBType::RTCP_PSFB_PLI: {
|
||||||
getFciSize();
|
getFciSize();
|
||||||
printer << "fci:" << psfbTypeToStr((PSFBType) report_count);
|
printer << "fci:" << psfbTypeToStr((PSFBType)report_count);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PSFBType::RTCP_PSFB_FIR : {
|
case PSFBType::RTCP_PSFB_FIR: {
|
||||||
auto &fci = getFci<FCI_FIR>();
|
auto &fci = getFci<FCI_FIR>();
|
||||||
printer << "fci:" << psfbTypeToStr((PSFBType) report_count) << " " << fci.dumpString();
|
printer << "fci:" << psfbTypeToStr((PSFBType)report_count) << " " << fci.dumpString();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PSFBType::RTCP_PSFB_REMB : {
|
case PSFBType::RTCP_PSFB_REMB: {
|
||||||
auto &fci = getFci<FCI_REMB>();
|
auto &fci = getFci<FCI_REMB>();
|
||||||
printer << "fci:" << psfbTypeToStr((PSFBType) report_count) << " " << fci.dumpString();
|
printer << "fci:" << psfbTypeToStr((PSFBType)report_count) << " " << fci.dumpString();
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:{
|
|
||||||
printer << "fci:" << psfbTypeToStr((PSFBType) report_count) << " " << hexdump(getFciPtr(), getFciSize());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case RtcpType::RTCP_RTPFB : {
|
|
||||||
switch ((RTPFBType) report_count) {
|
|
||||||
case RTPFBType::RTCP_RTPFB_NACK : {
|
|
||||||
auto &fci = getFci<FCI_NACK>();
|
|
||||||
printer << "fci:" << rtpfbTypeToStr((RTPFBType) report_count) << " " << fci.dumpString();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case RTPFBType::RTCP_RTPFB_TWCC : {
|
|
||||||
auto &fci = getFci<FCI_TWCC>();
|
|
||||||
printer << "fci:" << rtpfbTypeToStr((RTPFBType) report_count) << " " << fci.dumpString(getFciSize());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
printer << "fci:" << rtpfbTypeToStr((RTPFBType) report_count) << " " << hexdump(getFciPtr(), getFciSize());
|
printer << "fci:" << psfbTypeToStr((PSFBType)report_count) << " " << hexdump(getFciPtr(), getFciSize());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: /*不可达*/ assert(0); break;
|
case RtcpType::RTCP_RTPFB: {
|
||||||
|
switch ((RTPFBType)report_count) {
|
||||||
|
case RTPFBType::RTCP_RTPFB_NACK: {
|
||||||
|
auto &fci = getFci<FCI_NACK>();
|
||||||
|
printer << "fci:" << rtpfbTypeToStr((RTPFBType)report_count) << " " << fci.dumpString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RTPFBType::RTCP_RTPFB_TWCC: {
|
||||||
|
auto &fci = getFci<FCI_TWCC>();
|
||||||
|
printer << "fci:" << rtpfbTypeToStr((RTPFBType)report_count) << " " << fci.dumpString(getFciSize());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
printer << "fci:" << rtpfbTypeToStr((RTPFBType)report_count) << " " << hexdump(getFciPtr(), getFciSize());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: /*不可达*/
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return std::move(printer);
|
return std::move(printer);
|
||||||
}
|
}
|
||||||
@ -624,24 +641,22 @@ std::shared_ptr<RtcpBye> RtcpBye::create(const std::vector<uint32_t> &ssrcs, con
|
|||||||
assert(reason.size() <= 0xFF);
|
assert(reason.size() <= 0xFF);
|
||||||
auto real_size = sizeof(RtcpHeader) + sizeof(uint32_t) * ssrcs.size() + 1 + reason.size();
|
auto real_size = sizeof(RtcpHeader) + sizeof(uint32_t) * ssrcs.size() + 1 + reason.size();
|
||||||
auto bytes = alignSize(real_size);
|
auto bytes = alignSize(real_size);
|
||||||
auto ptr = (RtcpBye *) new char[bytes];
|
auto ptr = (RtcpBye *)new char[bytes];
|
||||||
setupHeader(ptr, RtcpType::RTCP_BYE, ssrcs.size(), bytes);
|
setupHeader(ptr, RtcpType::RTCP_BYE, ssrcs.size(), bytes);
|
||||||
setupPadding(ptr, bytes - real_size);
|
setupPadding(ptr, bytes - real_size);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (auto ssrc : ssrcs) {
|
for (auto ssrc : ssrcs) {
|
||||||
((RtcpBye *) ptr)->ssrc[i++] = htonl(ssrc);
|
((RtcpBye *)ptr)->ssrc[i++] = htonl(ssrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reason.empty()) {
|
if (!reason.empty()) {
|
||||||
uint8_t *reason_len_ptr = (uint8_t *) ptr + sizeof(RtcpHeader) + sizeof(uint32_t) * ssrcs.size();
|
uint8_t *reason_len_ptr = (uint8_t *)ptr + sizeof(RtcpHeader) + sizeof(uint32_t) * ssrcs.size();
|
||||||
*reason_len_ptr = reason.size() & 0xFF;
|
*reason_len_ptr = reason.size() & 0xFF;
|
||||||
memcpy(reason_len_ptr + 1, reason.data(), *reason_len_ptr);
|
memcpy(reason_len_ptr + 1, reason.data(), *reason_len_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::shared_ptr<RtcpBye>(ptr, [](RtcpBye *ptr) {
|
return std::shared_ptr<RtcpBye>(ptr, [](RtcpBye *ptr) { delete[] (char *)ptr; });
|
||||||
delete[] (char *) ptr;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<uint32_t *> RtcpBye::getSSRC() {
|
vector<uint32_t *> RtcpBye::getSSRC() {
|
||||||
@ -654,16 +669,16 @@ vector<uint32_t *> RtcpBye::getSSRC() {
|
|||||||
|
|
||||||
string RtcpBye::getReason() const {
|
string RtcpBye::getReason() const {
|
||||||
auto *reason_len_ptr = &reason_len + sizeof(ssrc) * (report_count - 1);
|
auto *reason_len_ptr = &reason_len + sizeof(ssrc) * (report_count - 1);
|
||||||
if (reason_len_ptr + 1 >= (uint8_t *) this + getSize()) {
|
if (reason_len_ptr + 1 >= (uint8_t *)this + getSize()) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return string((char *) reason_len_ptr + 1, *reason_len_ptr);
|
return string((char *)reason_len_ptr + 1, *reason_len_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
string RtcpBye::dumpString() const {
|
string RtcpBye::dumpString() const {
|
||||||
_StrPrinter printer;
|
_StrPrinter printer;
|
||||||
printer << RtcpHeader::dumpHeader();
|
printer << RtcpHeader::dumpHeader();
|
||||||
for (auto ssrc : ((RtcpBye *) this)->getSSRC()) {
|
for (auto ssrc : ((RtcpBye *)this)->getSSRC()) {
|
||||||
printer << "ssrc:" << *ssrc << "\r\n";
|
printer << "ssrc:" << *ssrc << "\r\n";
|
||||||
}
|
}
|
||||||
printer << "reason:" << getReason();
|
printer << "reason:" << getReason();
|
||||||
@ -679,18 +694,108 @@ void RtcpBye::net2Host(size_t size) {
|
|||||||
ssrc[i] = ntohl(ssrc[i]);
|
ssrc[i] = ntohl(ssrc[i]);
|
||||||
offset += sizeof(ssrc);
|
offset += sizeof(ssrc);
|
||||||
}
|
}
|
||||||
//修正ssrc个数
|
// 修正ssrc个数
|
||||||
CHECK_REPORT_COUNT(i);
|
CHECK_REPORT_COUNT(i);
|
||||||
|
|
||||||
if (offset < size) {
|
if (offset < size) {
|
||||||
uint8_t *reason_len_ptr = &reason_len + sizeof(ssrc) * (report_count - 1);
|
uint8_t *reason_len_ptr = &reason_len + sizeof(ssrc) * (report_count - 1);
|
||||||
if (reason_len_ptr + 1 + *reason_len_ptr > (uint8_t *) this + size) {
|
if (reason_len_ptr + 1 + *reason_len_ptr > (uint8_t *)this + size) {
|
||||||
WarnL << "invalid rtcp bye reason length";
|
WarnL << "invalid rtcp bye reason length";
|
||||||
//修正reason_len长度
|
// 修正reason_len长度
|
||||||
*reason_len_ptr = ((uint8_t *) this + size - reason_len_ptr - 1) & 0xFF;
|
*reason_len_ptr = ((uint8_t *)this + size - reason_len_ptr - 1) & 0xFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
////////////////////////////////////////////
|
||||||
|
string RtcpXRRRTR::dumpString() const {
|
||||||
|
_StrPrinter printer;
|
||||||
|
printer << RtcpHeader::dumpHeader();
|
||||||
|
printer << "ssrc :" << ssrc << "\r\n";
|
||||||
|
printer << "bt :" << (int)bt << "\r\n";
|
||||||
|
printer << "block_length : " << block_length << "\r\n";
|
||||||
|
printer << "ntp msw : " << ntpmsw << "\r\n";
|
||||||
|
printer << "ntp lsw : " << ntplsw << "\r\n";
|
||||||
|
return std::move(printer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcpXRRRTR::net2Host(size_t size) {
|
||||||
|
static const size_t kMinSize = sizeof(RtcpHeader);
|
||||||
|
CHECK_MIN_SIZE(size, kMinSize);
|
||||||
|
if (size != sizeof(RtcpXRRRTR)) {
|
||||||
|
throw std::invalid_argument(
|
||||||
|
StrPrinter << "rtcp xr Receiver Reference Time Report Block must is " << sizeof(RtcpXRRRTR)
|
||||||
|
<< " actual size " << size);
|
||||||
|
}
|
||||||
|
ssrc = ntohl(ssrc);
|
||||||
|
block_length = ntohs(block_length);
|
||||||
|
ntpmsw = ntohl(ntpmsw);
|
||||||
|
ntplsw = ntohl(ntplsw);
|
||||||
|
}
|
||||||
|
|
||||||
|
string RtcpXRDLRRReportItem::dumpString() const {
|
||||||
|
_StrPrinter printer;
|
||||||
|
|
||||||
|
printer << "ssrc :" << ssrc << "\r\n";
|
||||||
|
printer << "last RR (lrr) :" << lrr << "\r\n";
|
||||||
|
printer << "delay since last RR (dlrr): " << dlrr << "\r\n";
|
||||||
|
|
||||||
|
return std::move(printer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcpXRDLRRReportItem::net2Host() {
|
||||||
|
ssrc = ntohl(ssrc);
|
||||||
|
lrr = ntohl(lrr);
|
||||||
|
dlrr = ntohl(dlrr);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<RtcpXRDLRRReportItem *> RtcpXRDLRR::getItemList() {
|
||||||
|
auto count = block_length / 3;
|
||||||
|
RtcpXRDLRRReportItem *ptr = &items;
|
||||||
|
vector<RtcpXRDLRRReportItem *> ret;
|
||||||
|
for (int i = 0; i < (int)count; ++i) {
|
||||||
|
ret.emplace_back(ptr);
|
||||||
|
++ptr;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
string RtcpXRDLRR::dumpString() const {
|
||||||
|
_StrPrinter printer;
|
||||||
|
printer << RtcpHeader::dumpHeader();
|
||||||
|
printer << "ssrc :" << ssrc << "\r\n";
|
||||||
|
printer << "bt :" << (int)bt << "\r\n";
|
||||||
|
printer << "block_length : " << block_length << "\r\n";
|
||||||
|
auto items_list = ((RtcpXRDLRR *)this)->getItemList();
|
||||||
|
auto i = 0;
|
||||||
|
for (auto &item : items_list) {
|
||||||
|
printer << "---- item:" << i++ << " ----\r\n";
|
||||||
|
printer << item->dumpString();
|
||||||
|
}
|
||||||
|
return std::move(printer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcpXRDLRR::net2Host(size_t size) {
|
||||||
|
static const size_t kMinSize = sizeof(RtcpHeader);
|
||||||
|
CHECK_MIN_SIZE(size, kMinSize);
|
||||||
|
|
||||||
|
ssrc = ntohl(ssrc);
|
||||||
|
block_length = ntohs(block_length);
|
||||||
|
|
||||||
|
auto count = block_length / 3;
|
||||||
|
for (int i = 0; i < (int)count; ++i) {
|
||||||
|
RtcpXRDLRRReportItem *ptr = &items;
|
||||||
|
ptr->net2Host();
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<RtcpXRDLRR> RtcpXRDLRR::create(size_t item_count) {
|
||||||
|
auto real_size = sizeof(RtcpXRDLRR) - sizeof(RtcpXRDLRRReportItem) + item_count * sizeof(RtcpXRDLRRReportItem);
|
||||||
|
auto bytes = alignSize(real_size);
|
||||||
|
auto ptr = (RtcpXRDLRR *)new char[bytes];
|
||||||
|
setupHeader(ptr, RtcpType::RTCP_XR, 0, bytes);
|
||||||
|
setupPadding(ptr, bytes - real_size);
|
||||||
|
return std::shared_ptr<RtcpXRDLRR>(ptr, [](RtcpXRDLRR *ptr) { delete[] (char *)ptr; });
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
#include "Util/onceToken.h"
|
#include "Util/onceToken.h"
|
||||||
@ -706,4 +811,4 @@ static toolkit::onceToken token([](){
|
|||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}//namespace mediakit
|
} // namespace mediakit
|
255
src/Rtcp/Rtcp.h
255
src/Rtcp/Rtcp.h
@ -11,11 +11,11 @@
|
|||||||
#ifndef ZLMEDIAKIT_RTCP_H
|
#ifndef ZLMEDIAKIT_RTCP_H
|
||||||
#define ZLMEDIAKIT_RTCP_H
|
#define ZLMEDIAKIT_RTCP_H
|
||||||
|
|
||||||
|
#include "Common/macros.h"
|
||||||
|
#include "Network/Buffer.h"
|
||||||
|
#include "Util/util.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "Util/util.h"
|
|
||||||
#include "Network/Buffer.h"
|
|
||||||
#include "Common/macros.h"
|
|
||||||
|
|
||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ namespace mediakit {
|
|||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
#endif // defined(_WIN32)
|
#endif // defined(_WIN32)
|
||||||
|
|
||||||
//http://www.networksorcery.com/enp/protocol/rtcp.htm
|
// http://www.networksorcery.com/enp/protocol/rtcp.htm
|
||||||
#define RTCP_PT_MAP(XX) \
|
#define RTCP_PT_MAP(XX) \
|
||||||
XX(RTCP_FIR, 192) \
|
XX(RTCP_FIR, 192) \
|
||||||
XX(RTCP_NACK, 193) \
|
XX(RTCP_NACK, 193) \
|
||||||
@ -41,7 +41,7 @@ namespace mediakit {
|
|||||||
XX(RTCP_RSI, 209) \
|
XX(RTCP_RSI, 209) \
|
||||||
XX(RTCP_TOKEN, 210)
|
XX(RTCP_TOKEN, 210)
|
||||||
|
|
||||||
//https://tools.ietf.org/html/rfc3550#section-6.5
|
// https://tools.ietf.org/html/rfc3550#section-6.5
|
||||||
#define SDES_TYPE_MAP(XX) \
|
#define SDES_TYPE_MAP(XX) \
|
||||||
XX(RTCP_SDES_END, 0) \
|
XX(RTCP_SDES_END, 0) \
|
||||||
XX(RTCP_SDES_CNAME, 1) \
|
XX(RTCP_SDES_CNAME, 1) \
|
||||||
@ -53,8 +53,8 @@ namespace mediakit {
|
|||||||
XX(RTCP_SDES_NOTE, 7) \
|
XX(RTCP_SDES_NOTE, 7) \
|
||||||
XX(RTCP_SDES_PRIVATE, 8)
|
XX(RTCP_SDES_PRIVATE, 8)
|
||||||
|
|
||||||
//https://datatracker.ietf.org/doc/rfc4585/?include_text=1
|
// https://datatracker.ietf.org/doc/rfc4585/?include_text=1
|
||||||
//6.3. Payload-Specific Feedback Messages
|
// 6.3. Payload-Specific Feedback Messages
|
||||||
//
|
//
|
||||||
// Payload-Specific FB messages are identified by the value PT=PSFB as
|
// Payload-Specific FB messages are identified by the value PT=PSFB as
|
||||||
// RTCP message type.
|
// RTCP message type.
|
||||||
@ -80,13 +80,13 @@ namespace mediakit {
|
|||||||
XX(RTCP_PSFB_SLI, 2) \
|
XX(RTCP_PSFB_SLI, 2) \
|
||||||
XX(RTCP_PSFB_RPSI, 3) \
|
XX(RTCP_PSFB_RPSI, 3) \
|
||||||
XX(RTCP_PSFB_FIR, 4) \
|
XX(RTCP_PSFB_FIR, 4) \
|
||||||
XX(RTCP_PSFB_TSTR, 5)\
|
XX(RTCP_PSFB_TSTR, 5) \
|
||||||
XX(RTCP_PSFB_TSTN, 6)\
|
XX(RTCP_PSFB_TSTN, 6) \
|
||||||
XX(RTCP_PSFB_VBCM, 7) \
|
XX(RTCP_PSFB_VBCM, 7) \
|
||||||
XX(RTCP_PSFB_REMB, 15)
|
XX(RTCP_PSFB_REMB, 15)
|
||||||
|
|
||||||
//https://tools.ietf.org/html/rfc4585#section-6.2
|
// https://tools.ietf.org/html/rfc4585#section-6.2
|
||||||
//6.2. Transport Layer Feedback Messages
|
// 6.2. Transport Layer Feedback Messages
|
||||||
//
|
//
|
||||||
// Transport layer FB messages are identified by the value RTPFB as RTCP
|
// Transport layer FB messages are identified by the value RTPFB as RTCP
|
||||||
// message type.
|
// message type.
|
||||||
@ -110,28 +110,28 @@ namespace mediakit {
|
|||||||
XX(RTCP_RTPFB_TMMBN, 4) \
|
XX(RTCP_RTPFB_TMMBN, 4) \
|
||||||
XX(RTCP_RTPFB_TWCC, 15)
|
XX(RTCP_RTPFB_TWCC, 15)
|
||||||
|
|
||||||
//rtcp类型枚举
|
// rtcp类型枚举
|
||||||
enum class RtcpType : uint8_t {
|
enum class RtcpType : uint8_t {
|
||||||
#define XX(key, value) key = value,
|
#define XX(key, value) key = value,
|
||||||
RTCP_PT_MAP(XX)
|
RTCP_PT_MAP(XX)
|
||||||
#undef XX
|
#undef XX
|
||||||
};
|
};
|
||||||
|
|
||||||
//sdes类型枚举
|
// sdes类型枚举
|
||||||
enum class SdesType : uint8_t {
|
enum class SdesType : uint8_t {
|
||||||
#define XX(key, value) key = value,
|
#define XX(key, value) key = value,
|
||||||
SDES_TYPE_MAP(XX)
|
SDES_TYPE_MAP(XX)
|
||||||
#undef XX
|
#undef XX
|
||||||
};
|
};
|
||||||
|
|
||||||
//psfb类型枚举
|
// psfb类型枚举
|
||||||
enum class PSFBType : uint8_t {
|
enum class PSFBType : uint8_t {
|
||||||
#define XX(key, value) key = value,
|
#define XX(key, value) key = value,
|
||||||
PSFB_TYPE_MAP(XX)
|
PSFB_TYPE_MAP(XX)
|
||||||
#undef XX
|
#undef XX
|
||||||
};
|
};
|
||||||
|
|
||||||
//rtpfb类型枚举
|
// rtpfb类型枚举
|
||||||
enum class RTPFBType : uint8_t {
|
enum class RTPFBType : uint8_t {
|
||||||
#define XX(key, value) key = value,
|
#define XX(key, value) key = value,
|
||||||
RTPFB_TYPE_MAP(XX)
|
RTPFB_TYPE_MAP(XX)
|
||||||
@ -161,26 +161,26 @@ const char *rtpfbTypeToStr(RTPFBType type);
|
|||||||
class RtcpHeader {
|
class RtcpHeader {
|
||||||
public:
|
public:
|
||||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||||
//版本号,固定为2
|
// 版本号,固定为2
|
||||||
uint32_t version: 2;
|
uint32_t version : 2;
|
||||||
//padding,固定为0
|
// padding,固定为0
|
||||||
uint32_t padding: 1;
|
uint32_t padding : 1;
|
||||||
//reception report count
|
// reception report count
|
||||||
uint32_t report_count: 5;
|
uint32_t report_count : 5;
|
||||||
#else
|
#else
|
||||||
//reception report count
|
// reception report count
|
||||||
uint32_t report_count: 5;
|
uint32_t report_count : 5;
|
||||||
//padding,末尾是否有追加填充
|
// padding,末尾是否有追加填充
|
||||||
uint32_t padding: 1;
|
uint32_t padding : 1;
|
||||||
//版本号,固定为2
|
// 版本号,固定为2
|
||||||
uint32_t version: 2;
|
uint32_t version : 2;
|
||||||
#endif
|
#endif
|
||||||
//rtcp类型,RtcpType
|
// rtcp类型,RtcpType
|
||||||
uint32_t pt: 8;
|
uint32_t pt : 8;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//长度
|
// 长度
|
||||||
uint32_t length: 16;
|
uint32_t length : 16;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@ -222,7 +222,6 @@ public:
|
|||||||
void setSize(size_t size);
|
void setSize(size_t size);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打印字段详情
|
* 打印字段详情
|
||||||
* 使用net2Host转换成主机字节序后才可使用此函数
|
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||||
@ -240,26 +239,26 @@ private:
|
|||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
//ReportBlock
|
// ReportBlock
|
||||||
class ReportItem {
|
class ReportItem {
|
||||||
public:
|
public:
|
||||||
friend class RtcpSR;
|
friend class RtcpSR;
|
||||||
friend class RtcpRR;
|
friend class RtcpRR;
|
||||||
|
|
||||||
uint32_t ssrc;
|
uint32_t ssrc;
|
||||||
//Fraction lost
|
// Fraction lost
|
||||||
uint32_t fraction: 8;
|
uint32_t fraction : 8;
|
||||||
//Cumulative number of packets lost
|
// Cumulative number of packets lost
|
||||||
uint32_t cumulative: 24;
|
uint32_t cumulative : 24;
|
||||||
//Sequence number cycles count
|
// Sequence number cycles count
|
||||||
uint16_t seq_cycles;
|
uint16_t seq_cycles;
|
||||||
//Highest sequence number received
|
// Highest sequence number received
|
||||||
uint16_t seq_max;
|
uint16_t seq_max;
|
||||||
//Interarrival jitter
|
// Interarrival jitter
|
||||||
uint32_t jitter;
|
uint32_t jitter;
|
||||||
//Last SR timestamp, NTP timestamp,(ntpmsw & 0xFFFF) << 16 | (ntplsw >> 16) & 0xFFFF)
|
// Last SR timestamp, NTP timestamp,(ntpmsw & 0xFFFF) << 16 | (ntplsw >> 16) & 0xFFFF)
|
||||||
uint32_t last_sr_stamp;
|
uint32_t last_sr_stamp;
|
||||||
//Delay since last SR timestamp,expressed in units of 1/65536 seconds
|
// Delay since last SR timestamp,expressed in units of 1/65536 seconds
|
||||||
uint32_t delay_since_last_sr;
|
uint32_t delay_since_last_sr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -273,7 +272,7 @@ private:
|
|||||||
* 网络字节序转换为主机字节序
|
* 网络字节序转换为主机字节序
|
||||||
*/
|
*/
|
||||||
void net2Host();
|
void net2Host();
|
||||||
}PACKED;
|
} PACKED;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 6.4.1 SR: Sender Report RTCP Packet
|
* 6.4.1 SR: Sender Report RTCP Packet
|
||||||
@ -329,7 +328,7 @@ public:
|
|||||||
uint32_t packet_count;
|
uint32_t packet_count;
|
||||||
// sender octet count
|
// sender octet count
|
||||||
uint32_t octet_count;
|
uint32_t octet_count;
|
||||||
//可能有很多个
|
// 可能有很多个
|
||||||
ReportItem items;
|
ReportItem items;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -358,7 +357,7 @@ public:
|
|||||||
* 获取ReportItem对象指针列表
|
* 获取ReportItem对象指针列表
|
||||||
* 使用net2Host转换成主机字节序后才可使用此函数
|
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||||
*/
|
*/
|
||||||
std::vector<ReportItem*> getItemList();
|
std::vector<ReportItem *> getItemList();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
@ -406,13 +405,13 @@ block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//Receiver Report
|
// Receiver Report
|
||||||
class RtcpRR : public RtcpHeader {
|
class RtcpRR : public RtcpHeader {
|
||||||
public:
|
public:
|
||||||
friend class RtcpHeader;
|
friend class RtcpHeader;
|
||||||
|
|
||||||
uint32_t ssrc;
|
uint32_t ssrc;
|
||||||
//可能有很多个
|
// 可能有很多个
|
||||||
ReportItem items;
|
ReportItem items;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -427,7 +426,7 @@ public:
|
|||||||
* 获取ReportItem对象指针列表
|
* 获取ReportItem对象指针列表
|
||||||
* 使用net2Host转换成主机字节序后才可使用此函数
|
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||||
*/
|
*/
|
||||||
std::vector<ReportItem*> getItemList();
|
std::vector<ReportItem *> getItemList();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
@ -475,20 +474,20 @@ SDES items 定义
|
|||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//Source description Chunk
|
// Source description Chunk
|
||||||
class SdesChunk {
|
class SdesChunk {
|
||||||
public:
|
public:
|
||||||
friend class RtcpSdes;
|
friend class RtcpSdes;
|
||||||
|
|
||||||
uint32_t ssrc;
|
uint32_t ssrc;
|
||||||
//SdesType
|
// SdesType
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
//text长度股,可以为0
|
// text长度股,可以为0
|
||||||
uint8_t txt_len;
|
uint8_t txt_len;
|
||||||
//不定长
|
// 不定长
|
||||||
char text[1];
|
char text[1];
|
||||||
//最后以RTCP_SDES_END结尾
|
// 最后以RTCP_SDES_END结尾
|
||||||
//只字段为占位字段,不代表真实位置
|
// 只字段为占位字段,不代表真实位置
|
||||||
uint8_t end;
|
uint8_t end;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -515,12 +514,12 @@ private:
|
|||||||
void net2Host();
|
void net2Host();
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
//Source description
|
// Source description
|
||||||
class RtcpSdes : public RtcpHeader {
|
class RtcpSdes : public RtcpHeader {
|
||||||
public:
|
public:
|
||||||
friend class RtcpHeader;
|
friend class RtcpHeader;
|
||||||
|
|
||||||
//可能有很多个
|
// 可能有很多个
|
||||||
SdesChunk chunks;
|
SdesChunk chunks;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -535,7 +534,7 @@ public:
|
|||||||
* 获取SdesChunk对象指针列表
|
* 获取SdesChunk对象指针列表
|
||||||
* 使用net2Host转换成主机字节序后才可使用此函数
|
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||||
*/
|
*/
|
||||||
std::vector<SdesChunk*> getChunkList();
|
std::vector<SdesChunk *> getChunkList();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
@ -591,11 +590,11 @@ public:
|
|||||||
* @tparam Type 对象类型
|
* @tparam Type 对象类型
|
||||||
* @return 对象指针
|
* @return 对象指针
|
||||||
*/
|
*/
|
||||||
template<typename Type>
|
template <typename Type>
|
||||||
const Type& getFci() const{
|
const Type &getFci() const {
|
||||||
auto fci_data = getFciPtr();
|
auto fci_data = getFciPtr();
|
||||||
auto fci_len = getFciSize();
|
auto fci_len = getFciSize();
|
||||||
Type *fci = (Type *) fci_data;
|
Type *fci = (Type *)fci_data;
|
||||||
fci->check(fci_len);
|
fci->check(fci_len);
|
||||||
return *fci;
|
return *fci;
|
||||||
}
|
}
|
||||||
@ -627,7 +626,7 @@ private:
|
|||||||
static std::shared_ptr<RtcpFB> create_l(RtcpType type, int fmt, const void *fci, size_t fci_len);
|
static std::shared_ptr<RtcpFB> create_l(RtcpType type, int fmt, const void *fci, size_t fci_len);
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
//BYE
|
// BYE
|
||||||
/*
|
/*
|
||||||
0 1 2 3
|
0 1 2 3
|
||||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
@ -687,9 +686,139 @@ private:
|
|||||||
void net2Host(size_t size);
|
void net2Host(size_t size);
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
|
/*
|
||||||
|
0 1 2 3
|
||||||
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|V=2|P|reserved | PT=XR=207 | length |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| SSRC |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
: report blocks :
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
|
||||||
|
0 1 2 3
|
||||||
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| BT=4 | reserved | block length = 2 |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| NTP timestamp, most significant word |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| NTP timestamp, least significant word |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
*/
|
||||||
|
class RtcpXRRRTR : public RtcpHeader {
|
||||||
|
public:
|
||||||
|
friend class RtcpHeader;
|
||||||
|
uint32_t ssrc;
|
||||||
|
// 4
|
||||||
|
uint8_t bt;
|
||||||
|
uint8_t reserved;
|
||||||
|
// 2
|
||||||
|
uint16_t block_length;
|
||||||
|
// ntp timestamp MSW(in second)
|
||||||
|
uint32_t ntpmsw;
|
||||||
|
// ntp timestamp LSW(in picosecond)
|
||||||
|
uint32_t ntplsw;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* 打印字段详情
|
||||||
|
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||||
|
*/
|
||||||
|
std::string dumpString() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网络字节序转换为主机字节序
|
||||||
|
* @param size 字节长度,防止内存越界
|
||||||
|
*/
|
||||||
|
void net2Host(size_t size);
|
||||||
|
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
0 1 2 3
|
||||||
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| BT=5 | reserved | block length |
|
||||||
|
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
| SSRC_1 (SSRC of first receiver) | sub-
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
|
||||||
|
| last RR (LRR) | 1
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| delay since last RR (DLRR) |
|
||||||
|
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
| SSRC_2 (SSRC of second receiver) | sub-
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
|
||||||
|
: ... : 2
|
||||||
|
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
*/
|
||||||
|
class RtcpXRDLRRReportItem {
|
||||||
|
public:
|
||||||
|
friend class RtcpXRDLRR;
|
||||||
|
uint32_t ssrc;
|
||||||
|
uint32_t lrr;
|
||||||
|
uint32_t dlrr;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* 打印字段详情
|
||||||
|
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||||
|
*/
|
||||||
|
std::string dumpString() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网络字节序转换为主机字节序
|
||||||
|
* @param size 字节长度,防止内存越界
|
||||||
|
*/
|
||||||
|
void net2Host();
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
|
class RtcpXRDLRR : public RtcpHeader {
|
||||||
|
public:
|
||||||
|
friend class RtcpHeader;
|
||||||
|
uint32_t ssrc;
|
||||||
|
uint8_t bt;
|
||||||
|
uint8_t reserved;
|
||||||
|
uint16_t block_length;
|
||||||
|
RtcpXRDLRRReportItem items;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建RtcpXRDLRR包,只赋值了RtcpHeader部分(网络字节序)
|
||||||
|
* @param item_count RtcpXRDLRRReportItem对象个数
|
||||||
|
* @return RtcpXRDLRR包
|
||||||
|
*/
|
||||||
|
static std::shared_ptr<RtcpXRDLRR> create(size_t item_count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取RtcpXRDLRRReportItem对象指针列表
|
||||||
|
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||||
|
*/
|
||||||
|
std::vector<RtcpXRDLRRReportItem *> getItemList();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* 打印字段详情
|
||||||
|
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||||
|
*/
|
||||||
|
std::string dumpString() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网络字节序转换为主机字节序
|
||||||
|
* @param size 字节长度,防止内存越界
|
||||||
|
*/
|
||||||
|
void net2Host(size_t size);
|
||||||
|
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
#endif // defined(_WIN32)
|
#endif // defined(_WIN32)
|
||||||
|
|
||||||
} //namespace mediakit
|
} // namespace mediakit
|
||||||
#endif //ZLMEDIAKIT_RTCP_H
|
#endif // ZLMEDIAKIT_RTCP_H
|
||||||
|
@ -14,7 +14,8 @@ using namespace toolkit;
|
|||||||
|
|
||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
|
|
||||||
void RtcpContext::onRtp(uint16_t /*seq*/, uint32_t stamp, uint64_t ntp_stamp_ms, uint32_t /*sample_rate*/, size_t bytes) {
|
void RtcpContext::onRtp(
|
||||||
|
uint16_t /*seq*/, uint32_t stamp, uint64_t ntp_stamp_ms, uint32_t /*sample_rate*/, size_t bytes) {
|
||||||
++_packets;
|
++_packets;
|
||||||
_bytes += bytes;
|
_bytes += bytes;
|
||||||
_last_rtp_stamp = stamp;
|
_last_rtp_stamp = stamp;
|
||||||
@ -45,12 +46,16 @@ Buffer::Ptr RtcpContext::createRtcpRR(uint32_t rtcp_ssrc, uint32_t rtp_ssrc) {
|
|||||||
throw std::runtime_error("没有实现, rtp发送者尝试发送rr包");
|
throw std::runtime_error("没有实现, rtp发送者尝试发送rr包");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Buffer::Ptr RtcpContext::createRtcpXRDLRR(uint32_t rtcp_ssrc, uint32_t rtp_ssrc) {
|
||||||
|
throw std::runtime_error("没有实现, rtp发送者尝试发送xr dlrr包");
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void RtcpContextForSend::onRtcp(RtcpHeader *rtcp) {
|
void RtcpContextForSend::onRtcp(RtcpHeader *rtcp) {
|
||||||
switch ((RtcpType) rtcp->pt) {
|
switch ((RtcpType)rtcp->pt) {
|
||||||
case RtcpType::RTCP_RR: {
|
case RtcpType::RTCP_RR: {
|
||||||
auto rtcp_rr = (RtcpRR *) rtcp;
|
auto rtcp_rr = (RtcpRR *)rtcp;
|
||||||
for (auto item : rtcp_rr->getItemList()) {
|
for (auto item : rtcp_rr->getItemList()) {
|
||||||
if (!item->last_sr_stamp) {
|
if (!item->last_sr_stamp) {
|
||||||
continue;
|
continue;
|
||||||
@ -59,20 +64,34 @@ void RtcpContextForSend::onRtcp(RtcpHeader *rtcp) {
|
|||||||
if (it == _sender_report_ntp.end()) {
|
if (it == _sender_report_ntp.end()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//发送sr到收到rr之间的时间戳增量
|
// 发送sr到收到rr之间的时间戳增量
|
||||||
auto ms_inc = getCurrentMillisecond() - it->second;
|
auto ms_inc = getCurrentMillisecond() - it->second;
|
||||||
//rtp接收端收到sr包后,回复rr包的延时,已转换为毫秒
|
// rtp接收端收到sr包后,回复rr包的延时,已转换为毫秒
|
||||||
auto delay_ms = (uint64_t) item->delay_since_last_sr * 1000 / 65536;
|
auto delay_ms = (uint64_t)item->delay_since_last_sr * 1000 / 65536;
|
||||||
auto rtt = (int) (ms_inc - delay_ms);
|
auto rtt = (int)(ms_inc - delay_ms);
|
||||||
if (rtt >= 0) {
|
if (rtt >= 0) {
|
||||||
//rtt不可能小于0
|
// rtt不可能小于0
|
||||||
_rtt[item->ssrc] = rtt;
|
_rtt[item->ssrc] = rtt;
|
||||||
//InfoL << "ssrc:" << item->ssrc << ",rtt:" << rtt;
|
// InfoL << "ssrc:" << item->ssrc << ",rtt:" << rtt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: break;
|
case RtcpType::RTCP_XR: {
|
||||||
|
auto rtcp_xr = (RtcpXRRRTR *)rtcp;
|
||||||
|
if (rtcp_xr->bt == 4) {
|
||||||
|
_xr_xrrtr_recv_last_rr[rtcp_xr->ssrc]
|
||||||
|
= ((rtcp_xr->ntpmsw & 0xFFFF) << 16) | ((rtcp_xr->ntplsw >> 16) & 0xFFFF);
|
||||||
|
_xr_rrtr_recv_sys_stamp[rtcp_xr->ssrc] = getCurrentMillisecond();
|
||||||
|
} else if (rtcp_xr->bt == 5) {
|
||||||
|
TraceL << "for sender not recive dlrr";
|
||||||
|
} else {
|
||||||
|
TraceL << "not support xr bt " << rtcp_xr->bt;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,55 +108,85 @@ Buffer::Ptr RtcpContextForSend::createRtcpSR(uint32_t rtcp_ssrc) {
|
|||||||
rtcp->setNtpStamp(_last_ntp_stamp_ms);
|
rtcp->setNtpStamp(_last_ntp_stamp_ms);
|
||||||
rtcp->rtpts = htonl(_last_rtp_stamp);
|
rtcp->rtpts = htonl(_last_rtp_stamp);
|
||||||
rtcp->ssrc = htonl(rtcp_ssrc);
|
rtcp->ssrc = htonl(rtcp_ssrc);
|
||||||
rtcp->packet_count = htonl((uint32_t) _packets);
|
rtcp->packet_count = htonl((uint32_t)_packets);
|
||||||
rtcp->octet_count = htonl((uint32_t) _bytes);
|
rtcp->octet_count = htonl((uint32_t)_bytes);
|
||||||
|
|
||||||
//记录上次发送的sender report信息,用于后续统计rtt
|
// 记录上次发送的sender report信息,用于后续统计rtt
|
||||||
auto last_sr_lsr = ((ntohl(rtcp->ntpmsw) & 0xFFFF) << 16) | ((ntohl(rtcp->ntplsw) >> 16) & 0xFFFF);
|
auto last_sr_lsr = ((ntohl(rtcp->ntpmsw) & 0xFFFF) << 16) | ((ntohl(rtcp->ntplsw) >> 16) & 0xFFFF);
|
||||||
_sender_report_ntp[last_sr_lsr] = getCurrentMillisecond();
|
_sender_report_ntp[last_sr_lsr] = getCurrentMillisecond();
|
||||||
if (_sender_report_ntp.size() >= 5) {
|
if (_sender_report_ntp.size() >= 5) {
|
||||||
//删除最早的sr rtcp
|
// 删除最早的sr rtcp
|
||||||
_sender_report_ntp.erase(_sender_report_ntp.begin());
|
_sender_report_ntp.erase(_sender_report_ntp.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
return RtcpHeader::toBuffer(std::move(rtcp));
|
return RtcpHeader::toBuffer(std::move(rtcp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toolkit::Buffer::Ptr RtcpContextForSend::createRtcpXRDLRR(uint32_t rtcp_ssrc, uint32_t rtp_ssrc) {
|
||||||
|
auto rtcp = RtcpXRDLRR::create(1);
|
||||||
|
rtcp->bt = 5;
|
||||||
|
rtcp->reserved = 0;
|
||||||
|
rtcp->block_length = htons(3);
|
||||||
|
rtcp->ssrc = htonl(rtcp_ssrc);
|
||||||
|
rtcp->items.ssrc = htonl(rtp_ssrc);
|
||||||
|
|
||||||
|
if (_xr_xrrtr_recv_last_rr.find(rtp_ssrc) == _xr_xrrtr_recv_last_rr.end()) {
|
||||||
|
rtcp->items.lrr = 0;
|
||||||
|
WarnL;
|
||||||
|
} else {
|
||||||
|
rtcp->items.lrr = htonl(_xr_xrrtr_recv_last_rr[rtp_ssrc]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_xr_rrtr_recv_sys_stamp.find(rtp_ssrc) == _xr_rrtr_recv_sys_stamp.end()) {
|
||||||
|
rtcp->items.dlrr = 0;
|
||||||
|
WarnL;
|
||||||
|
} else {
|
||||||
|
// now - Last SR time,单位毫秒
|
||||||
|
auto delay = getCurrentMillisecond() - _xr_rrtr_recv_sys_stamp[rtp_ssrc];
|
||||||
|
// in units of 1/65536 seconds
|
||||||
|
auto dlsr = (uint32_t)(delay / 1000.0f * 65536);
|
||||||
|
rtcp->items.dlrr = htonl(dlsr);
|
||||||
|
}
|
||||||
|
return RtcpHeader::toBuffer(std::move(rtcp));
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void RtcpContextForRecv::onRtp(uint16_t seq, uint32_t stamp, uint64_t ntp_stamp_ms, uint32_t sample_rate, size_t bytes) {
|
void RtcpContextForRecv::onRtp(
|
||||||
|
uint16_t seq, uint32_t stamp, uint64_t ntp_stamp_ms, uint32_t sample_rate, size_t bytes) {
|
||||||
{
|
{
|
||||||
//接收者才做复杂的统计运算
|
// 接收者才做复杂的统计运算
|
||||||
auto sys_stamp = getCurrentMillisecond();
|
auto sys_stamp = getCurrentMillisecond();
|
||||||
if (_last_rtp_sys_stamp) {
|
if (_last_rtp_sys_stamp) {
|
||||||
//计算时间戳抖动值
|
// 计算时间戳抖动值
|
||||||
double diff = double((int64_t(sys_stamp) - int64_t(_last_rtp_sys_stamp)) * (sample_rate / double(1000.0))
|
double diff = double(
|
||||||
|
(int64_t(sys_stamp) - int64_t(_last_rtp_sys_stamp)) * (sample_rate / double(1000.0))
|
||||||
- (int64_t(stamp) - int64_t(_last_rtp_stamp)));
|
- (int64_t(stamp) - int64_t(_last_rtp_stamp)));
|
||||||
if (diff < 0) {
|
if (diff < 0) {
|
||||||
diff = -diff;
|
diff = -diff;
|
||||||
}
|
}
|
||||||
//抖动单位为采样次数
|
// 抖动单位为采样次数
|
||||||
_jitter += (diff - _jitter) / 16.0;
|
_jitter += (diff - _jitter) / 16.0;
|
||||||
} else {
|
} else {
|
||||||
_jitter = 0;
|
_jitter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_last_rtp_seq > 0xFF00 && seq < 0xFF && (!_seq_cycles || _packets - _last_cycle_packets > 0x1FFF)) {
|
if (_last_rtp_seq > 0xFF00 && seq < 0xFF && (!_seq_cycles || _packets - _last_cycle_packets > 0x1FFF)) {
|
||||||
//上次seq大于0xFF00且本次seq小于0xFF,
|
// 上次seq大于0xFF00且本次seq小于0xFF,
|
||||||
//且未发生回环或者距离上次回环间隔超过0x1FFF个包,则认为回环
|
// 且未发生回环或者距离上次回环间隔超过0x1FFF个包,则认为回环
|
||||||
++_seq_cycles;
|
++_seq_cycles;
|
||||||
_last_cycle_packets = _packets;
|
_last_cycle_packets = _packets;
|
||||||
_seq_max = seq;
|
_seq_max = seq;
|
||||||
} else if (seq > _seq_max) {
|
} else if (seq > _seq_max) {
|
||||||
//本次回环前最大seq
|
// 本次回环前最大seq
|
||||||
_seq_max = seq;
|
_seq_max = seq;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_seq_base) {
|
if (!_seq_base) {
|
||||||
//记录第一个rtp的seq
|
// 记录第一个rtp的seq
|
||||||
_seq_base = seq;
|
_seq_base = seq;
|
||||||
} else if (!_seq_cycles && seq < _seq_base) {
|
} else if (!_seq_cycles && seq < _seq_base) {
|
||||||
//未发生回环,那么取最新的seq为基准seq
|
// 未发生回环,那么取最新的seq为基准seq
|
||||||
_seq_base = seq;
|
_seq_base = seq;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,9 +197,9 @@ void RtcpContextForRecv::onRtp(uint16_t seq, uint32_t stamp, uint64_t ntp_stamp_
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RtcpContextForRecv::onRtcp(RtcpHeader *rtcp) {
|
void RtcpContextForRecv::onRtcp(RtcpHeader *rtcp) {
|
||||||
switch ((RtcpType) rtcp->pt) {
|
switch ((RtcpType)rtcp->pt) {
|
||||||
case RtcpType::RTCP_SR: {
|
case RtcpType::RTCP_SR: {
|
||||||
auto rtcp_sr = (RtcpSR *) rtcp;
|
auto rtcp_sr = (RtcpSR *)rtcp;
|
||||||
/**
|
/**
|
||||||
last SR timestamp (LSR): 32 bits
|
last SR timestamp (LSR): 32 bits
|
||||||
The middle 32 bits out of 64 in the NTP timestamp (as explained in
|
The middle 32 bits out of 64 in the NTP timestamp (as explained in
|
||||||
@ -162,7 +211,8 @@ void RtcpContextForRecv::onRtcp(RtcpHeader *rtcp) {
|
|||||||
_last_sr_ntp_sys = getCurrentMillisecond();
|
_last_sr_ntp_sys = getCurrentMillisecond();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +242,7 @@ Buffer::Ptr RtcpContextForRecv::createRtcpRR(uint32_t rtcp_ssrc, uint32_t rtp_ss
|
|||||||
auto rtcp = RtcpRR::create(1);
|
auto rtcp = RtcpRR::create(1);
|
||||||
rtcp->ssrc = htonl(rtcp_ssrc);
|
rtcp->ssrc = htonl(rtcp_ssrc);
|
||||||
|
|
||||||
ReportItem *item = (ReportItem *) &rtcp->items;
|
ReportItem *item = (ReportItem *)&rtcp->items;
|
||||||
item->ssrc = htonl(rtp_ssrc);
|
item->ssrc = htonl(rtp_ssrc);
|
||||||
|
|
||||||
uint8_t fraction = 0;
|
uint8_t fraction = 0;
|
||||||
@ -211,9 +261,9 @@ Buffer::Ptr RtcpContextForRecv::createRtcpRR(uint32_t rtcp_ssrc, uint32_t rtp_ss
|
|||||||
// now - Last SR time,单位毫秒
|
// now - Last SR time,单位毫秒
|
||||||
auto delay = getCurrentMillisecond() - _last_sr_ntp_sys;
|
auto delay = getCurrentMillisecond() - _last_sr_ntp_sys;
|
||||||
// in units of 1/65536 seconds
|
// in units of 1/65536 seconds
|
||||||
auto dlsr = (uint32_t) (delay / 1000.0f * 65536);
|
auto dlsr = (uint32_t)(delay / 1000.0f * 65536);
|
||||||
item->delay_since_last_sr = htonl(_last_sr_lsr ? dlsr : 0);
|
item->delay_since_last_sr = htonl(_last_sr_lsr ? dlsr : 0);
|
||||||
return RtcpHeader::toBuffer(rtcp);
|
return RtcpHeader::toBuffer(rtcp);
|
||||||
}
|
}
|
||||||
|
|
||||||
}//namespace mediakit
|
} // namespace mediakit
|
@ -11,9 +11,9 @@
|
|||||||
#ifndef ZLMEDIAKIT_RTCPCONTEXT_H
|
#ifndef ZLMEDIAKIT_RTCPCONTEXT_H
|
||||||
#define ZLMEDIAKIT_RTCPCONTEXT_H
|
#define ZLMEDIAKIT_RTCPCONTEXT_H
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include "Rtcp.h"
|
#include "Rtcp.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
|
|
||||||
@ -55,6 +55,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual toolkit::Buffer::Ptr createRtcpSR(uint32_t rtcp_ssrc);
|
virtual toolkit::Buffer::Ptr createRtcpSR(uint32_t rtcp_ssrc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 创建xr的dlrr包,用于接收者估算rtt
|
||||||
|
*
|
||||||
|
* @return toolkit::Buffer::Ptr
|
||||||
|
*/
|
||||||
|
virtual toolkit::Buffer::Ptr createRtcpXRDLRR(uint32_t rtcp_ssrc, uint32_t rtp_ssrc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建RR rtcp包
|
* 创建RR rtcp包
|
||||||
* @param rtcp_ssrc rtcp的ssrc
|
* @param rtcp_ssrc rtcp的ssrc
|
||||||
@ -74,11 +81,11 @@ public:
|
|||||||
virtual size_t geLostInterval();
|
virtual size_t geLostInterval();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//收到或发送的rtp的字节数
|
// 收到或发送的rtp的字节数
|
||||||
size_t _bytes = 0;
|
size_t _bytes = 0;
|
||||||
//收到或发送的rtp的个数
|
// 收到或发送的rtp的个数
|
||||||
size_t _packets = 0;
|
size_t _packets = 0;
|
||||||
//上次的rtp时间戳,毫秒
|
// 上次的rtp时间戳,毫秒
|
||||||
uint32_t _last_rtp_stamp = 0;
|
uint32_t _last_rtp_stamp = 0;
|
||||||
uint64_t _last_ntp_stamp_ms = 0;
|
uint64_t _last_ntp_stamp_ms = 0;
|
||||||
};
|
};
|
||||||
@ -86,8 +93,11 @@ protected:
|
|||||||
class RtcpContextForSend : public RtcpContext {
|
class RtcpContextForSend : public RtcpContext {
|
||||||
public:
|
public:
|
||||||
toolkit::Buffer::Ptr createRtcpSR(uint32_t rtcp_ssrc) override;
|
toolkit::Buffer::Ptr createRtcpSR(uint32_t rtcp_ssrc) override;
|
||||||
|
|
||||||
void onRtcp(RtcpHeader *rtcp) override;
|
void onRtcp(RtcpHeader *rtcp) override;
|
||||||
|
|
||||||
|
toolkit::Buffer::Ptr createRtcpXRDLRR(uint32_t rtcp_ssrc, uint32_t rtp_ssrc) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取rtt
|
* 获取rtt
|
||||||
* @param ssrc rtp ssrc
|
* @param ssrc rtp ssrc
|
||||||
@ -96,8 +106,11 @@ public:
|
|||||||
uint32_t getRtt(uint32_t ssrc) const;
|
uint32_t getRtt(uint32_t ssrc) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<uint32_t/*ssrc*/, uint32_t/*rtt*/> _rtt;
|
std::map<uint32_t /*ssrc*/, uint32_t /*rtt*/> _rtt;
|
||||||
std::map<uint32_t/*last_sr_lsr*/, uint64_t/*ntp stamp*/> _sender_report_ntp;
|
std::map<uint32_t /*last_sr_lsr*/, uint64_t /*ntp stamp*/> _sender_report_ntp;
|
||||||
|
|
||||||
|
std::map<uint32_t /*ssrc*/, uint64_t /*xr rrtr sys stamp*/> _xr_rrtr_recv_sys_stamp;
|
||||||
|
std::map<uint32_t /*ssrc*/, uint32_t /*last rr */> _xr_xrrtr_recv_last_rr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RtcpContextForRecv : public RtcpContext {
|
class RtcpContextForRecv : public RtcpContext {
|
||||||
@ -111,29 +124,29 @@ public:
|
|||||||
void onRtcp(RtcpHeader *rtcp) override;
|
void onRtcp(RtcpHeader *rtcp) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//时间戳抖动值
|
// 时间戳抖动值
|
||||||
double _jitter = 0;
|
double _jitter = 0;
|
||||||
//第一个seq的值
|
// 第一个seq的值
|
||||||
uint16_t _seq_base = 0;
|
uint16_t _seq_base = 0;
|
||||||
//rtp最大seq
|
// rtp最大seq
|
||||||
uint16_t _seq_max = 0;
|
uint16_t _seq_max = 0;
|
||||||
//rtp回环次数
|
// rtp回环次数
|
||||||
uint16_t _seq_cycles = 0;
|
uint16_t _seq_cycles = 0;
|
||||||
//上次回环发生时,记录的rtp包数
|
// 上次回环发生时,记录的rtp包数
|
||||||
size_t _last_cycle_packets = 0;
|
size_t _last_cycle_packets = 0;
|
||||||
//上次的seq
|
// 上次的seq
|
||||||
uint16_t _last_rtp_seq = 0;
|
uint16_t _last_rtp_seq = 0;
|
||||||
//上次的rtp的系统时间戳(毫秒)用于统计抖动
|
// 上次的rtp的系统时间戳(毫秒)用于统计抖动
|
||||||
uint64_t _last_rtp_sys_stamp = 0;
|
uint64_t _last_rtp_sys_stamp = 0;
|
||||||
//上次统计的丢包总数
|
// 上次统计的丢包总数
|
||||||
size_t _last_lost = 0;
|
size_t _last_lost = 0;
|
||||||
//上次统计应收rtp包总数
|
// 上次统计应收rtp包总数
|
||||||
size_t _last_expected = 0;
|
size_t _last_expected = 0;
|
||||||
//上次收到sr包时计算出的Last SR timestamp
|
// 上次收到sr包时计算出的Last SR timestamp
|
||||||
uint32_t _last_sr_lsr = 0;
|
uint32_t _last_sr_lsr = 0;
|
||||||
//上次收到sr时的系统时间戳,单位毫秒
|
// 上次收到sr时的系统时间戳,单位毫秒
|
||||||
uint64_t _last_sr_ntp_sys = 0;
|
uint64_t _last_sr_ntp_sys = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}//namespace mediakit
|
} // namespace mediakit
|
||||||
#endif //ZLMEDIAKIT_RTCPCONTEXT_H
|
#endif // ZLMEDIAKIT_RTCPCONTEXT_H
|
||||||
|
@ -16,16 +16,16 @@ using namespace toolkit;
|
|||||||
|
|
||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
|
|
||||||
void FCI_SLI::check(size_t size){
|
void FCI_SLI::check(size_t size) {
|
||||||
CHECK(size >= kSize);
|
CHECK(size >= kSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
FCI_SLI::FCI_SLI(uint16_t first, uint16_t number, uint8_t pic_id) {
|
FCI_SLI::FCI_SLI(uint16_t first, uint16_t number, uint8_t pic_id) {
|
||||||
//13 bits
|
// 13 bits
|
||||||
first &= 0x1FFF;
|
first &= 0x1FFF;
|
||||||
//13 bits
|
// 13 bits
|
||||||
number &= 0x1FFF;
|
number &= 0x1FFF;
|
||||||
//6 bits
|
// 6 bits
|
||||||
pic_id &= 0x3F;
|
pic_id &= 0x3F;
|
||||||
data = (first << 19) | (number << 6) | pic_id;
|
data = (first << 19) | (number << 6) | pic_id;
|
||||||
data = htonl(data);
|
data = htonl(data);
|
||||||
@ -49,19 +49,19 @@ string FCI_SLI::dumpString() const {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void FCI_FIR::check(size_t size){
|
void FCI_FIR::check(size_t size) {
|
||||||
CHECK(size >= kSize);
|
CHECK(size >= kSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t FCI_FIR::getSSRC() const{
|
uint32_t FCI_FIR::getSSRC() const {
|
||||||
return ntohl(ssrc);
|
return ntohl(ssrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t FCI_FIR::getSeq() const{
|
uint8_t FCI_FIR::getSeq() const {
|
||||||
return seq_number;
|
return seq_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t FCI_FIR::getReserved() const{
|
uint32_t FCI_FIR::getReserved() const {
|
||||||
return (reserved[0] << 16) | (reserved[1] << 8) | reserved[2];
|
return (reserved[0] << 16) | (reserved[1] << 8) | reserved[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ FCI_FIR::FCI_FIR(uint32_t ssrc, uint8_t seq_number, uint32_t reserved) {
|
|||||||
|
|
||||||
static const char kRembMagic[] = "REMB";
|
static const char kRembMagic[] = "REMB";
|
||||||
|
|
||||||
void FCI_REMB::check(size_t size){
|
void FCI_REMB::check(size_t size) {
|
||||||
CHECK(size >= kSize);
|
CHECK(size >= kSize);
|
||||||
CHECK(memcmp(magic, kRembMagic, sizeof(magic)) == 0);
|
CHECK(memcmp(magic, kRembMagic, sizeof(magic)) == 0);
|
||||||
auto num_ssrc = bitrate[0];
|
auto num_ssrc = bitrate[0];
|
||||||
@ -93,7 +93,7 @@ string FCI_REMB::create(const vector<uint32_t> &ssrcs, uint32_t bitrate) {
|
|||||||
CHECK(ssrcs.size() > 0 && ssrcs.size() <= 0xFF);
|
CHECK(ssrcs.size() > 0 && ssrcs.size() <= 0xFF);
|
||||||
string ret;
|
string ret;
|
||||||
ret.resize(kSize + ssrcs.size() * 4);
|
ret.resize(kSize + ssrcs.size() * 4);
|
||||||
FCI_REMB *thiz = (FCI_REMB *) ret.data();
|
FCI_REMB *thiz = (FCI_REMB *)ret.data();
|
||||||
memcpy(thiz->magic, kRembMagic, sizeof(magic));
|
memcpy(thiz->magic, kRembMagic, sizeof(magic));
|
||||||
|
|
||||||
/* bitrate --> BR Exp/BR Mantissa */
|
/* bitrate --> BR Exp/BR Mantissa */
|
||||||
@ -101,7 +101,7 @@ string FCI_REMB::create(const vector<uint32_t> &ssrcs, uint32_t bitrate) {
|
|||||||
uint8_t exp = 0;
|
uint8_t exp = 0;
|
||||||
uint32_t mantissa = 0;
|
uint32_t mantissa = 0;
|
||||||
for (b = 0; b < 32; b++) {
|
for (b = 0; b < 32; b++) {
|
||||||
if (bitrate <= ((uint32_t) 0x3FFFF << b)) {
|
if (bitrate <= ((uint32_t)0x3FFFF << b)) {
|
||||||
exp = b;
|
exp = b;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -110,16 +110,16 @@ string FCI_REMB::create(const vector<uint32_t> &ssrcs, uint32_t bitrate) {
|
|||||||
b = 31;
|
b = 31;
|
||||||
}
|
}
|
||||||
mantissa = bitrate >> b;
|
mantissa = bitrate >> b;
|
||||||
//Num SSRC (8 bits)
|
// Num SSRC (8 bits)
|
||||||
thiz->bitrate[0] = ssrcs.size() & 0xFF;
|
thiz->bitrate[0] = ssrcs.size() & 0xFF;
|
||||||
//BR Exp (6 bits)/BR Mantissa (18 bits)
|
// BR Exp (6 bits)/BR Mantissa (18 bits)
|
||||||
thiz->bitrate[1] = (uint8_t) ((exp << 2) + ((mantissa >> 16) & 0x03));
|
thiz->bitrate[1] = (uint8_t)((exp << 2) + ((mantissa >> 16) & 0x03));
|
||||||
//BR Mantissa (18 bits)
|
// BR Mantissa (18 bits)
|
||||||
thiz->bitrate[2] = (uint8_t) (mantissa >> 8);
|
thiz->bitrate[2] = (uint8_t)(mantissa >> 8);
|
||||||
//BR Mantissa (18 bits)
|
// BR Mantissa (18 bits)
|
||||||
thiz->bitrate[3] = (uint8_t) (mantissa);
|
thiz->bitrate[3] = (uint8_t)(mantissa);
|
||||||
|
|
||||||
//设置ssrc列表
|
// 设置ssrc列表
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (auto ssrc : ssrcs) {
|
for (auto ssrc : ssrcs) {
|
||||||
thiz->ssrc_feedback[i++] = htonl(ssrc);
|
thiz->ssrc_feedback[i++] = htonl(ssrc);
|
||||||
@ -149,7 +149,7 @@ vector<uint32_t> FCI_REMB::getSSRC() {
|
|||||||
string FCI_REMB::dumpString() const {
|
string FCI_REMB::dumpString() const {
|
||||||
_StrPrinter printer;
|
_StrPrinter printer;
|
||||||
printer << "bitrate:" << getBitRate() << ", ssrc:";
|
printer << "bitrate:" << getBitRate() << ", ssrc:";
|
||||||
for (auto &ssrc : ((FCI_REMB *) this)->getSSRC()) {
|
for (auto &ssrc : ((FCI_REMB *)this)->getSSRC()) {
|
||||||
printer << ssrc << " ";
|
printer << ssrc << " ";
|
||||||
}
|
}
|
||||||
return std::move(printer);
|
return std::move(printer);
|
||||||
@ -171,7 +171,7 @@ FCI_NACK::FCI_NACK(uint16_t pid_h, const vector<bool> &type) {
|
|||||||
pid = htons(pid_h);
|
pid = htons(pid_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCI_NACK::check(size_t size){
|
void FCI_NACK::check(size_t size) {
|
||||||
CHECK(size >= kSize);
|
CHECK(size >= kSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +186,7 @@ uint16_t FCI_NACK::getBlp() const {
|
|||||||
vector<bool> FCI_NACK::getBitArray() const {
|
vector<bool> FCI_NACK::getBitArray() const {
|
||||||
vector<bool> ret;
|
vector<bool> ret;
|
||||||
ret.resize(kBitSize + 1);
|
ret.resize(kBitSize + 1);
|
||||||
//nack第一个包丢包
|
// nack第一个包丢包
|
||||||
ret[0] = true;
|
ret[0] = true;
|
||||||
|
|
||||||
auto blp_h = getBlp();
|
auto blp_h = getBlp();
|
||||||
@ -220,25 +220,25 @@ public:
|
|||||||
// |T| S | Run Length |
|
// |T| S | Run Length |
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||||
uint16_t type: 1;
|
uint16_t type : 1;
|
||||||
uint16_t symbol: 2;
|
uint16_t symbol : 2;
|
||||||
uint16_t run_length_high: 5;
|
uint16_t run_length_high : 5;
|
||||||
#else
|
#else
|
||||||
// Run Length 高5位
|
// Run Length 高5位
|
||||||
uint16_t run_length_high: 5;
|
uint16_t run_length_high : 5;
|
||||||
//参考SymbolStatus定义
|
// 参考SymbolStatus定义
|
||||||
uint16_t symbol: 2;
|
uint16_t symbol : 2;
|
||||||
//固定为0
|
// 固定为0
|
||||||
uint16_t type: 1;
|
uint16_t type : 1;
|
||||||
#endif
|
#endif
|
||||||
// Run Length 低8位
|
// Run Length 低8位
|
||||||
uint16_t run_length_low: 8;
|
uint16_t run_length_low : 8;
|
||||||
|
|
||||||
//获取Run Length
|
// 获取Run Length
|
||||||
uint16_t getRunLength() const;
|
uint16_t getRunLength() const;
|
||||||
//构造函数
|
// 构造函数
|
||||||
RunLengthChunk(SymbolStatus status, uint16_t run_length);
|
RunLengthChunk(SymbolStatus status, uint16_t run_length);
|
||||||
//打印本对象
|
// 打印本对象
|
||||||
string dumpString() const;
|
string dumpString() const;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
@ -254,7 +254,7 @@ uint16_t RunLengthChunk::getRunLength() const {
|
|||||||
return run_length_high << 8 | run_length_low;
|
return run_length_high << 8 | run_length_low;
|
||||||
}
|
}
|
||||||
|
|
||||||
string RunLengthChunk::dumpString() const{
|
string RunLengthChunk::dumpString() const {
|
||||||
_StrPrinter printer;
|
_StrPrinter printer;
|
||||||
printer << "run length chunk, symbol:" << (int)symbol << ", run length:" << getRunLength();
|
printer << "run length chunk, symbol:" << (int)symbol << ", run length:" << getRunLength();
|
||||||
return std::move(printer);
|
return std::move(printer);
|
||||||
@ -271,30 +271,30 @@ public:
|
|||||||
// |T|S| symbol list |
|
// |T|S| symbol list |
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||||
uint16_t type: 1;
|
uint16_t type : 1;
|
||||||
uint16_t symbol: 1;
|
uint16_t symbol : 1;
|
||||||
uint16_t symbol_list_high: 6;
|
uint16_t symbol_list_high : 6;
|
||||||
#else
|
#else
|
||||||
// symbol_list 高6位
|
// symbol_list 高6位
|
||||||
uint16_t symbol_list_high: 6;
|
uint16_t symbol_list_high : 6;
|
||||||
//symbol_list中元素是1个还是2个bit
|
// symbol_list中元素是1个还是2个bit
|
||||||
uint16_t symbol: 1;
|
uint16_t symbol : 1;
|
||||||
//固定为1
|
// 固定为1
|
||||||
uint16_t type: 1;
|
uint16_t type : 1;
|
||||||
#endif
|
#endif
|
||||||
// symbol_list 低8位
|
// symbol_list 低8位
|
||||||
uint16_t symbol_list_low: 8;
|
uint16_t symbol_list_low : 8;
|
||||||
|
|
||||||
//获取symbollist
|
// 获取symbollist
|
||||||
vector<SymbolStatus> getSymbolList() const;
|
vector<SymbolStatus> getSymbolList() const;
|
||||||
//构造函数
|
// 构造函数
|
||||||
StatusVecChunk(bool symbol_bit, const vector<SymbolStatus> &status);
|
StatusVecChunk(bool symbol_bit, const vector<SymbolStatus> &status);
|
||||||
//打印本对象
|
// 打印本对象
|
||||||
string dumpString() const;
|
string dumpString() const;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
StatusVecChunk::StatusVecChunk(bool symbol_bit, const vector<SymbolStatus> &status) {
|
StatusVecChunk::StatusVecChunk(bool symbol_bit, const vector<SymbolStatus> &status) {
|
||||||
CHECK( status.size() << symbol_bit <= 14);
|
CHECK(status.size() << symbol_bit <= 14);
|
||||||
uint16_t value = 0;
|
uint16_t value = 0;
|
||||||
type = 1;
|
type = 1;
|
||||||
symbol = symbol_bit;
|
symbol = symbol_bit;
|
||||||
@ -303,31 +303,31 @@ StatusVecChunk::StatusVecChunk(bool symbol_bit, const vector<SymbolStatus> &stat
|
|||||||
CHECK(item <= SymbolStatus::reserved);
|
CHECK(item <= SymbolStatus::reserved);
|
||||||
if (!symbol) {
|
if (!symbol) {
|
||||||
CHECK(item <= SymbolStatus::small_delta);
|
CHECK(item <= SymbolStatus::small_delta);
|
||||||
value |= (int) item << i;
|
value |= (int)item << i;
|
||||||
--i;
|
--i;
|
||||||
} else {
|
} else {
|
||||||
value |= (int) item << (i - 1);
|
value |= (int)item << (i - 1);
|
||||||
i -= 2;
|
i -= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
symbol_list_low = value & 0xFF;
|
symbol_list_low = value & 0xFF;
|
||||||
symbol_list_high = (value >> 8 ) & 0x3F;
|
symbol_list_high = (value >> 8) & 0x3F;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<SymbolStatus> StatusVecChunk::getSymbolList() const {
|
vector<SymbolStatus> StatusVecChunk::getSymbolList() const {
|
||||||
CHECK(type == 1);
|
CHECK(type == 1);
|
||||||
vector<SymbolStatus> ret;
|
vector<SymbolStatus> ret;
|
||||||
auto thiz = ntohs(*((uint16_t *) this));
|
auto thiz = ntohs(*((uint16_t *)this));
|
||||||
if (symbol == 0) {
|
if (symbol == 0) {
|
||||||
//s = 0 时,表示symbollist的每一个bit能表示一个数据包的到达状态
|
// s = 0 时,表示symbollist的每一个bit能表示一个数据包的到达状态
|
||||||
for (int i = 13; i >= 0; --i) {
|
for (int i = 13; i >= 0; --i) {
|
||||||
SymbolStatus status = (SymbolStatus) ((bool) (thiz & (1 << i)));
|
SymbolStatus status = (SymbolStatus)((bool)(thiz & (1 << i)));
|
||||||
ret.emplace_back(status);
|
ret.emplace_back(status);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//s = 1 时,表示symbollist每两个bit表示一个数据包的状态
|
// s = 1 时,表示symbollist每两个bit表示一个数据包的状态
|
||||||
for (int i = 12; i >= 0; i -= 2) {
|
for (int i = 12; i >= 0; i -= 2) {
|
||||||
SymbolStatus status = (SymbolStatus) ((thiz & (3 << i)) >> i);
|
SymbolStatus status = (SymbolStatus)((thiz & (3 << i)) >> i);
|
||||||
ret.emplace_back(status);
|
ret.emplace_back(status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -336,17 +336,17 @@ vector<SymbolStatus> StatusVecChunk::getSymbolList() const {
|
|||||||
|
|
||||||
string StatusVecChunk::dumpString() const {
|
string StatusVecChunk::dumpString() const {
|
||||||
_StrPrinter printer;
|
_StrPrinter printer;
|
||||||
printer << "status vector chunk, symbol:" << (int) symbol << ", symbol list:";
|
printer << "status vector chunk, symbol:" << (int)symbol << ", symbol list:";
|
||||||
auto vec = getSymbolList();
|
auto vec = getSymbolList();
|
||||||
for (auto &item : vec) {
|
for (auto &item : vec) {
|
||||||
printer << (int) item << " ";
|
printer << (int)item << " ";
|
||||||
}
|
}
|
||||||
return std::move(printer);
|
return std::move(printer);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////
|
||||||
|
|
||||||
void FCI_TWCC::check(size_t size){
|
void FCI_TWCC::check(size_t size) {
|
||||||
CHECK(size >= kSize);
|
CHECK(size >= kSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,7 +365,7 @@ uint32_t FCI_TWCC::getReferenceTime() const {
|
|||||||
ret |= ref_time[2];
|
ret |= ref_time[2];
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
//3.1.5. Receive Delta
|
// 3.1.5. Receive Delta
|
||||||
//
|
//
|
||||||
// Deltas are represented as multiples of 250us:
|
// Deltas are represented as multiples of 250us:
|
||||||
//
|
//
|
||||||
@ -392,33 +392,33 @@ uint32_t FCI_TWCC::getReferenceTime() const {
|
|||||||
// be represented. With a 1200 bytes/packet payload, that amounts to
|
// be represented. With a 1200 bytes/packet payload, that amounts to
|
||||||
// 38.4 Mbit/s payload bandwidth.
|
// 38.4 Mbit/s payload bandwidth.
|
||||||
|
|
||||||
static int16_t getRecvDelta(SymbolStatus status, uint8_t *&ptr, const uint8_t *end){
|
static int16_t getRecvDelta(SymbolStatus status, uint8_t *&ptr, const uint8_t *end) {
|
||||||
int16_t delta = 0;
|
int16_t delta = 0;
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case SymbolStatus::not_received : {
|
case SymbolStatus::not_received: {
|
||||||
//丢包, recv delta为0个字节
|
// 丢包, recv delta为0个字节
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolStatus::small_delta : {
|
case SymbolStatus::small_delta: {
|
||||||
CHECK(ptr + 1 <= end);
|
CHECK(ptr + 1 <= end);
|
||||||
//时间戳增量小于256, recv delta为1个字节
|
// 时间戳增量小于256, recv delta为1个字节
|
||||||
delta = *ptr;
|
delta = *ptr;
|
||||||
ptr += 1;
|
ptr += 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolStatus::large_delta : {
|
case SymbolStatus::large_delta: {
|
||||||
CHECK(ptr + 2 <= end);
|
CHECK(ptr + 2 <= end);
|
||||||
//时间戳增量256~65535间,recv delta为2个字节
|
// 时间戳增量256~65535间,recv delta为2个字节
|
||||||
delta = *ptr << 8 | *(ptr + 1);
|
delta = *ptr << 8 | *(ptr + 1);
|
||||||
ptr += 2;
|
ptr += 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolStatus::reserved : {
|
case SymbolStatus::reserved: {
|
||||||
//没有时间戳
|
// 没有时间戳
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
//这个逻辑分支不可达到
|
// 这个逻辑分支不可达到
|
||||||
CHECK(0);
|
CHECK(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -427,25 +427,25 @@ static int16_t getRecvDelta(SymbolStatus status, uint8_t *&ptr, const uint8_t *e
|
|||||||
|
|
||||||
FCI_TWCC::TwccPacketStatus FCI_TWCC::getPacketChunkList(size_t total_size) const {
|
FCI_TWCC::TwccPacketStatus FCI_TWCC::getPacketChunkList(size_t total_size) const {
|
||||||
TwccPacketStatus ret;
|
TwccPacketStatus ret;
|
||||||
auto ptr = (uint8_t *) this + kSize;
|
auto ptr = (uint8_t *)this + kSize;
|
||||||
auto end = (uint8_t *) this + total_size;
|
auto end = (uint8_t *)this + total_size;
|
||||||
CHECK(ptr < end);
|
CHECK(ptr < end);
|
||||||
auto seq = getBaseSeq();
|
auto seq = getBaseSeq();
|
||||||
auto rtp_count = getPacketCount();
|
auto rtp_count = getPacketCount();
|
||||||
for (uint8_t i = 0; i < rtp_count;) {
|
for (uint8_t i = 0; i < rtp_count;) {
|
||||||
CHECK(ptr + RunLengthChunk::kSize <= end);
|
CHECK(ptr + RunLengthChunk::kSize <= end);
|
||||||
RunLengthChunk *chunk = (RunLengthChunk *) ptr;
|
RunLengthChunk *chunk = (RunLengthChunk *)ptr;
|
||||||
if (!chunk->type) {
|
if (!chunk->type) {
|
||||||
//RunLengthChunk
|
// RunLengthChunk
|
||||||
for (auto j = 0; j < chunk->getRunLength(); ++j) {
|
for (auto j = 0; j < chunk->getRunLength(); ++j) {
|
||||||
ret.emplace(seq++, std::make_pair((SymbolStatus) chunk->symbol, 0));
|
ret.emplace(seq++, std::make_pair((SymbolStatus)chunk->symbol, 0));
|
||||||
if (++i >= rtp_count) {
|
if (++i >= rtp_count) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//StatusVecChunk
|
// StatusVecChunk
|
||||||
StatusVecChunk *chunk = (StatusVecChunk *) ptr;
|
StatusVecChunk *chunk = (StatusVecChunk *)ptr;
|
||||||
for (auto &symbol : chunk->getSymbolList()) {
|
for (auto &symbol : chunk->getSymbolList()) {
|
||||||
ret.emplace(seq++, std::make_pair(symbol, 0));
|
ret.emplace(seq++, std::make_pair(symbol, 0));
|
||||||
if (++i >= rtp_count) {
|
if (++i >= rtp_count) {
|
||||||
@ -465,23 +465,29 @@ FCI_TWCC::TwccPacketStatus FCI_TWCC::getPacketChunkList(size_t total_size) const
|
|||||||
string FCI_TWCC::dumpString(size_t total_size) const {
|
string FCI_TWCC::dumpString(size_t total_size) const {
|
||||||
_StrPrinter printer;
|
_StrPrinter printer;
|
||||||
auto map = getPacketChunkList(total_size);
|
auto map = getPacketChunkList(total_size);
|
||||||
printer << "twcc fci, base_seq:" << getBaseSeq() << ", pkt_status_count:" << getPacketCount() << ", ref time:" << getReferenceTime() << ", fb count:" << (int)fb_pkt_count << "\n";
|
printer << "twcc fci, base_seq:" << getBaseSeq() << ", pkt_status_count:" << getPacketCount()
|
||||||
|
<< ", ref time:" << getReferenceTime() << ", fb count:" << (int)fb_pkt_count << "\n";
|
||||||
for (auto &pr : map) {
|
for (auto &pr : map) {
|
||||||
printer << "rtp seq:" << pr.first <<", packet status:" << (int)(pr.second.first) << ", delta:" << pr.second.second << "\n";
|
printer << "rtp seq:" << pr.first << ", packet status:" << (int)(pr.second.first)
|
||||||
|
<< ", delta:" << pr.second.second << "\n";
|
||||||
}
|
}
|
||||||
return std::move(printer);
|
return std::move(printer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void appendDeltaString(string &delta_str, FCI_TWCC::TwccPacketStatus &status, int count){
|
static void appendDeltaString(string &delta_str, FCI_TWCC::TwccPacketStatus &status, int count) {
|
||||||
for (auto it = status.begin(); it != status.end() && count--;) {
|
for (auto it = status.begin(); it != status.end() && count--;) {
|
||||||
switch (it->second.first) {
|
switch (it->second.first) {
|
||||||
//large delta模式先写高字节,再写低字节
|
// large delta模式先写高字节,再写低字节
|
||||||
case SymbolStatus::large_delta: delta_str.push_back((it->second.second >> 8) & 0xFF);
|
case SymbolStatus::large_delta:
|
||||||
//small delta模式只写低字节
|
delta_str.push_back((it->second.second >> 8) & 0xFF);
|
||||||
case SymbolStatus::small_delta: delta_str.push_back(it->second.second & 0xFF); break;
|
// small delta模式只写低字节
|
||||||
default: break;
|
case SymbolStatus::small_delta:
|
||||||
|
delta_str.push_back(it->second.second & 0xFF);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
//移除已经处理过的数据
|
// 移除已经处理过的数据
|
||||||
it = status.erase(it);
|
it = status.erase(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -489,7 +495,7 @@ static void appendDeltaString(string &delta_str, FCI_TWCC::TwccPacketStatus &sta
|
|||||||
string FCI_TWCC::create(uint32_t ref_time, uint8_t fb_pkt_count, TwccPacketStatus &status) {
|
string FCI_TWCC::create(uint32_t ref_time, uint8_t fb_pkt_count, TwccPacketStatus &status) {
|
||||||
string fci;
|
string fci;
|
||||||
fci.resize(FCI_TWCC::kSize);
|
fci.resize(FCI_TWCC::kSize);
|
||||||
FCI_TWCC *ptr = (FCI_TWCC *) (fci.data());
|
FCI_TWCC *ptr = (FCI_TWCC *)(fci.data());
|
||||||
ptr->base_seq = htons(status.begin()->first);
|
ptr->base_seq = htons(status.begin()->first);
|
||||||
ptr->pkt_status_count = htons(status.size());
|
ptr->pkt_status_count = htons(status.size());
|
||||||
ptr->fb_pkt_count = fb_pkt_count;
|
ptr->fb_pkt_count = fb_pkt_count;
|
||||||
@ -500,21 +506,21 @@ string FCI_TWCC::create(uint32_t ref_time, uint8_t fb_pkt_count, TwccPacketStatu
|
|||||||
string delta_str;
|
string delta_str;
|
||||||
while (!status.empty()) {
|
while (!status.empty()) {
|
||||||
{
|
{
|
||||||
//第一个rtp的状态
|
// 第一个rtp的状态
|
||||||
auto symbol = status.begin()->second.first;
|
auto symbol = status.begin()->second.first;
|
||||||
int16_t count = 0;
|
int16_t count = 0;
|
||||||
for (auto &pr : status) {
|
for (auto &pr : status) {
|
||||||
if (pr.second.first != symbol) {
|
if (pr.second.first != symbol) {
|
||||||
//状态发送变更了,本chunk结束
|
// 状态发送变更了,本chunk结束
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (++count >= (0xFFFF >> 3)) {
|
if (++count >= (0xFFFF >> 3)) {
|
||||||
//RunLengthChunk 13个bit表明rtp个数,最多可以表述0xFFFF >> 3个rtp状态
|
// RunLengthChunk 13个bit表明rtp个数,最多可以表述0xFFFF >> 3个rtp状态
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (count >= 7) {
|
if (count >= 7) {
|
||||||
//连续状态相同个数大于6个时,使用RunLengthChunk模式比较节省带宽
|
// 连续状态相同个数大于6个时,使用RunLengthChunk模式比较节省带宽
|
||||||
RunLengthChunk chunk(symbol, count);
|
RunLengthChunk chunk(symbol, count);
|
||||||
fci.append((char *)&chunk, RunLengthChunk::kSize);
|
fci.append((char *)&chunk, RunLengthChunk::kSize);
|
||||||
appendDeltaString(delta_str, status, count);
|
appendDeltaString(delta_str, status, count);
|
||||||
@ -523,20 +529,20 @@ string FCI_TWCC::create(uint32_t ref_time, uint8_t fb_pkt_count, TwccPacketStatu
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
//StatusVecChunk模式
|
// StatusVecChunk模式
|
||||||
//symbol_list中元素是1个bit
|
// symbol_list中元素是1个bit
|
||||||
auto symbol = 0;
|
auto symbol = 0;
|
||||||
vector<SymbolStatus> vec;
|
vector<SymbolStatus> vec;
|
||||||
for (auto &pr : status) {
|
for (auto &pr : status) {
|
||||||
vec.push_back(pr.second.first);
|
vec.push_back(pr.second.first);
|
||||||
if (pr.second.first >= SymbolStatus::large_delta) {
|
if (pr.second.first >= SymbolStatus::large_delta) {
|
||||||
//symbol_list中元素是2个bit
|
// symbol_list中元素是2个bit
|
||||||
symbol = 1;
|
symbol = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vec.size() << symbol >= 14) {
|
if (vec.size() << symbol >= 14) {
|
||||||
//symbol为0时,最多存放14个rtp的状态
|
// symbol为0时,最多存放14个rtp的状态
|
||||||
//symbol为1时,最多存放7个rtp的状态
|
// symbol为1时,最多存放7个rtp的状态
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -547,9 +553,9 @@ string FCI_TWCC::create(uint32_t ref_time, uint8_t fb_pkt_count, TwccPacketStatu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//recv delta部分
|
// recv delta部分
|
||||||
fci.append(delta_str);
|
fci.append(delta_str);
|
||||||
return fci;
|
return fci;
|
||||||
}
|
}
|
||||||
|
|
||||||
}//namespace mediakit
|
} // namespace mediakit
|
@ -11,21 +11,21 @@
|
|||||||
#ifndef ZLMEDIAKIT_RTCPFCI_H
|
#ifndef ZLMEDIAKIT_RTCPFCI_H
|
||||||
#define ZLMEDIAKIT_RTCPFCI_H
|
#define ZLMEDIAKIT_RTCPFCI_H
|
||||||
|
|
||||||
#include "Rtcp.h"
|
|
||||||
#include "Common/config.h"
|
#include "Common/config.h"
|
||||||
|
#include "Rtcp.h"
|
||||||
|
|
||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
|
|
||||||
/////////////////////////////////////////// PSFB ////////////////////////////////////////////////////
|
/////////////////////////////////////////// PSFB ////////////////////////////////////////////////////
|
||||||
|
|
||||||
//PSFB fmt = 2
|
// PSFB fmt = 2
|
||||||
//https://tools.ietf.org/html/rfc4585#section-6.3.2.2
|
// https://tools.ietf.org/html/rfc4585#section-6.3.2.2
|
||||||
// 0 1 2 3
|
// 0 1 2 3
|
||||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
// | First | Number | PictureID |
|
// | First | Number | PictureID |
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
//First: 13 bits
|
// First: 13 bits
|
||||||
// The macroblock (MB) address of the first lost macroblock. The MB
|
// The macroblock (MB) address of the first lost macroblock. The MB
|
||||||
// numbering is done such that the macroblock in the upper left
|
// numbering is done such that the macroblock in the upper left
|
||||||
// corner of the picture is considered macroblock number 1 and the
|
// corner of the picture is considered macroblock number 1 and the
|
||||||
@ -101,8 +101,8 @@ public:
|
|||||||
} PACKED;
|
} PACKED;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//PSFB fmt = 4
|
// PSFB fmt = 4
|
||||||
//https://tools.ietf.org/html/rfc5104#section-4.3.1.1
|
// https://tools.ietf.org/html/rfc5104#section-4.3.1.1
|
||||||
// 0 1 2 3
|
// 0 1 2 3
|
||||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
@ -188,8 +188,8 @@ private:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//PSFB fmt = 15
|
// PSFB fmt = 15
|
||||||
//https://tools.ietf.org/html/draft-alvestrand-rmcat-remb-03
|
// https://tools.ietf.org/html/draft-alvestrand-rmcat-remb-03
|
||||||
// 0 1 2 3
|
// 0 1 2 3
|
||||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
@ -227,9 +227,9 @@ public:
|
|||||||
std::vector<uint32_t> getSSRC();
|
std::vector<uint32_t> getSSRC();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//Unique identifier 'R' 'E' 'M' 'B'
|
// Unique identifier 'R' 'E' 'M' 'B'
|
||||||
char magic[4];
|
char magic[4];
|
||||||
//Num SSRC (8 bits)/BR Exp (6 bits)/ BR Mantissa (18 bits)
|
// Num SSRC (8 bits)/BR Exp (6 bits)/ BR Mantissa (18 bits)
|
||||||
uint8_t bitrate[4];
|
uint8_t bitrate[4];
|
||||||
// SSRC feedback (32 bits) Consists of one or more SSRC entries which
|
// SSRC feedback (32 bits) Consists of one or more SSRC entries which
|
||||||
// this feedback message applies to.
|
// this feedback message applies to.
|
||||||
@ -238,8 +238,8 @@ private:
|
|||||||
|
|
||||||
/////////////////////////////////////////// RTPFB ////////////////////////////////////////////////////
|
/////////////////////////////////////////// RTPFB ////////////////////////////////////////////////////
|
||||||
|
|
||||||
//RTPFB fmt = 1
|
// RTPFB fmt = 1
|
||||||
//https://tools.ietf.org/html/rfc4585#section-6.2.1
|
// https://tools.ietf.org/html/rfc4585#section-6.2.1
|
||||||
// 0 1 2 3
|
// 0 1 2 3
|
||||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
@ -255,7 +255,7 @@ public:
|
|||||||
void check(size_t size);
|
void check(size_t size);
|
||||||
uint16_t getPid() const;
|
uint16_t getPid() const;
|
||||||
uint16_t getBlp() const;
|
uint16_t getBlp() const;
|
||||||
//返回丢包列表,总长度17,第一个包必丢
|
// 返回丢包列表,总长度17,第一个包必丢
|
||||||
// TODO: replace std::bitset
|
// TODO: replace std::bitset
|
||||||
std::vector<bool> getBitArray() const;
|
std::vector<bool> getBitArray() const;
|
||||||
std::string dumpString() const;
|
std::string dumpString() const;
|
||||||
@ -318,20 +318,20 @@ public:
|
|||||||
} PACKED;
|
} PACKED;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum class SymbolStatus : uint8_t{
|
enum class SymbolStatus : uint8_t {
|
||||||
//Packet not received
|
// Packet not received
|
||||||
not_received = 0,
|
not_received = 0,
|
||||||
//Packet received, small delta (所谓small detal是指能用一个字节表示的数值)
|
// Packet received, small delta (所谓small detal是指能用一个字节表示的数值)
|
||||||
small_delta = 1,
|
small_delta = 1,
|
||||||
// Packet received, large ornegative delta (large即是能用两个字节表示的数值)
|
// Packet received, large ornegative delta (large即是能用两个字节表示的数值)
|
||||||
large_delta = 2,
|
large_delta = 2,
|
||||||
//Reserved
|
// Reserved
|
||||||
reserved = 3
|
reserved = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
//RTPFB fmt = 15
|
// RTPFB fmt = 15
|
||||||
//https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1
|
// https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1
|
||||||
//https://zhuanlan.zhihu.com/p/206656654
|
// https://zhuanlan.zhihu.com/p/206656654
|
||||||
// 0 1 2 3
|
// 0 1 2 3
|
||||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
@ -351,14 +351,15 @@ enum class SymbolStatus : uint8_t{
|
|||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
// | recv delta | recv delta | zero padding |
|
// | recv delta | recv delta | zero padding |
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
class FCI_TWCC{
|
class FCI_TWCC {
|
||||||
public:
|
public:
|
||||||
static size_t constexpr kSize = 8;
|
static size_t constexpr kSize = 8;
|
||||||
using TwccPacketStatus = std::map<uint16_t/*rtp ext seq*/, std::pair<SymbolStatus, int16_t/*recv delta,单位为250us*/> >;
|
using TwccPacketStatus
|
||||||
|
= std::map<uint16_t /*rtp ext seq*/, std::pair<SymbolStatus, int16_t /*recv delta,单位为250us*/>>;
|
||||||
void check(size_t size);
|
void check(size_t size);
|
||||||
std::string dumpString(size_t total_size) const;
|
std::string dumpString(size_t total_size) const;
|
||||||
uint16_t getBaseSeq() const;
|
uint16_t getBaseSeq() const;
|
||||||
//单位64ms
|
// 单位64ms
|
||||||
uint32_t getReferenceTime() const;
|
uint32_t getReferenceTime() const;
|
||||||
uint16_t getPacketCount() const;
|
uint16_t getPacketCount() const;
|
||||||
TwccPacketStatus getPacketChunkList(size_t total_size) const;
|
TwccPacketStatus getPacketChunkList(size_t total_size) const;
|
||||||
@ -366,15 +367,15 @@ public:
|
|||||||
static std::string create(uint32_t ref_time, uint8_t fb_pkt_count, TwccPacketStatus &status);
|
static std::string create(uint32_t ref_time, uint8_t fb_pkt_count, TwccPacketStatus &status);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//base sequence number,基础序号,本次反馈的第一个包的序号;也就是RTP扩展头的序列号
|
// base sequence number,基础序号,本次反馈的第一个包的序号;也就是RTP扩展头的序列号
|
||||||
uint16_t base_seq;
|
uint16_t base_seq;
|
||||||
//packet status count, 包个数,本次反馈包含多少个包的状态;从基础序号开始算
|
// packet status count, 包个数,本次反馈包含多少个包的状态;从基础序号开始算
|
||||||
uint16_t pkt_status_count;
|
uint16_t pkt_status_count;
|
||||||
//reference time,基准时间,绝对时间;计算该包中每个媒体包的到达时间都要基于这个基准时间计算
|
// reference time,基准时间,绝对时间;计算该包中每个媒体包的到达时间都要基于这个基准时间计算
|
||||||
uint8_t ref_time[3];
|
uint8_t ref_time[3];
|
||||||
//feedback packet count,反馈包号,本包是第几个transport-cc包,每次加1 |
|
// feedback packet count,反馈包号,本包是第几个transport-cc包,每次加1 |
|
||||||
uint8_t fb_pkt_count;
|
uint8_t fb_pkt_count;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
} //namespace mediakit
|
} // namespace mediakit
|
||||||
#endif //ZLMEDIAKIT_RTCPFCI_H
|
#endif // ZLMEDIAKIT_RTCPFCI_H
|
||||||
|
@ -99,7 +99,11 @@ private:
|
|||||||
if (_rtmp_src) {
|
if (_rtmp_src) {
|
||||||
_rtmp_src->setMetaData(val);
|
_rtmp_src->setMetaData(val);
|
||||||
}
|
}
|
||||||
|
if(_demuxer){
|
||||||
|
return;
|
||||||
|
}
|
||||||
_demuxer = std::make_shared<RtmpDemuxer>();
|
_demuxer = std::make_shared<RtmpDemuxer>();
|
||||||
|
//TraceL<<" _wait_track_ready "<<_wait_track_ready;
|
||||||
_demuxer->setTrackListener(this, _wait_track_ready);
|
_demuxer->setTrackListener(this, _wait_track_ready);
|
||||||
_demuxer->loadMetaData(val);
|
_demuxer->loadMetaData(val);
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ RtmpSession::~RtmpSession() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RtmpSession::onError(const SockException& err) {
|
void RtmpSession::onError(const SockException& err) {
|
||||||
bool is_player = !_push_src;
|
bool is_player = !_push_src_ownership;
|
||||||
uint64_t duration = _ticker.createdTime() / 1000;
|
uint64_t duration = _ticker.createdTime() / 1000;
|
||||||
WarnP(this) << (is_player ? "RTMP播放器(" : "RTMP推流器(")
|
WarnP(this) << (is_player ? "RTMP播放器(" : "RTMP推流器(")
|
||||||
<< _media_info._vhost << "/"
|
<< _media_info._vhost << "/"
|
||||||
@ -219,10 +219,11 @@ void RtmpSession::onCmd_publish(AMFDecoder &dec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RtmpSession::onCmd_deleteStream(AMFDecoder &dec) {
|
void RtmpSession::onCmd_deleteStream(AMFDecoder &dec) {
|
||||||
|
_push_src = nullptr;
|
||||||
|
//此时回复可能触发broken pipe事件,从而直接触发onError回调;所以需要先把_push_src置空,防止触发断流续推功能
|
||||||
sendStatus({ "level", "status",
|
sendStatus({ "level", "status",
|
||||||
"code", "NetStream.Unpublish.Success",
|
"code", "NetStream.Unpublish.Success",
|
||||||
"description", "Stop publishing." });
|
"description", "Stop publishing." });
|
||||||
//_push_src = nullptr;
|
|
||||||
throw std::runtime_error(StrPrinter << "Stop publishing" << endl);
|
throw std::runtime_error(StrPrinter << "Stop publishing" << endl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,15 @@
|
|||||||
using namespace toolkit;
|
using namespace toolkit;
|
||||||
|
|
||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
|
|
||||||
|
void Decoder::setOnDecode(Decoder::onDecode cb) {
|
||||||
|
_on_decode = std::move(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Decoder::setOnStream(Decoder::onStream cb) {
|
||||||
|
_on_stream = std::move(cb);
|
||||||
|
}
|
||||||
|
|
||||||
static Decoder::Ptr createDecoder_l(DecoderImp::Type type) {
|
static Decoder::Ptr createDecoder_l(DecoderImp::Type type) {
|
||||||
switch (type){
|
switch (type){
|
||||||
case DecoderImp::decoder_ps:
|
case DecoderImp::decoder_ps:
|
||||||
|
@ -25,12 +25,16 @@ public:
|
|||||||
typedef std::function<void(int stream, int codecid, const void *extra, size_t bytes, int finish)> onStream;
|
typedef std::function<void(int stream, int codecid, const void *extra, size_t bytes, int finish)> onStream;
|
||||||
|
|
||||||
virtual ssize_t input(const uint8_t *data, size_t bytes) = 0;
|
virtual ssize_t input(const uint8_t *data, size_t bytes) = 0;
|
||||||
virtual void setOnDecode(onDecode cb) = 0;
|
void setOnDecode(onDecode cb);
|
||||||
virtual void setOnStream(onStream cb) = 0;
|
void setOnStream(onStream cb);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Decoder() = default;
|
Decoder() = default;
|
||||||
virtual ~Decoder() = default;
|
virtual ~Decoder() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
onDecode _on_decode;
|
||||||
|
onStream _on_stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DecoderImp{
|
class DecoderImp{
|
||||||
|
@ -53,14 +53,6 @@ ssize_t PSDecoder::input(const uint8_t *data, size_t bytes) {
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PSDecoder::setOnDecode(Decoder::onDecode cb) {
|
|
||||||
_on_decode = std::move(cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PSDecoder::setOnStream(Decoder::onStream cb) {
|
|
||||||
_on_stream = std::move(cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *PSDecoder::onSearchPacketTail(const char *data, size_t len) {
|
const char *PSDecoder::onSearchPacketTail(const char *data, size_t len) {
|
||||||
try {
|
try {
|
||||||
auto ret = ps_demuxer_input(static_cast<struct ps_demuxer_t *>(_ps_demuxer), reinterpret_cast<const uint8_t *>(data), len);
|
auto ret = ps_demuxer_input(static_cast<struct ps_demuxer_t *>(_ps_demuxer), reinterpret_cast<const uint8_t *>(data), len);
|
||||||
|
@ -25,8 +25,6 @@ public:
|
|||||||
~PSDecoder();
|
~PSDecoder();
|
||||||
|
|
||||||
ssize_t input(const uint8_t* data, size_t bytes) override;
|
ssize_t input(const uint8_t* data, size_t bytes) override;
|
||||||
void setOnDecode(onDecode cb) override;
|
|
||||||
void setOnStream(onStream cb) override;
|
|
||||||
|
|
||||||
// HttpRequestSplitter interface
|
// HttpRequestSplitter interface
|
||||||
private:
|
private:
|
||||||
@ -36,8 +34,6 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void *_ps_demuxer = nullptr;
|
void *_ps_demuxer = nullptr;
|
||||||
onDecode _on_decode;
|
|
||||||
onStream _on_stream;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}//namespace mediakit
|
}//namespace mediakit
|
||||||
|
@ -23,7 +23,7 @@ PSEncoderImp::PSEncoderImp(uint32_t ssrc, uint8_t payload_type) : MpegMuxer(true
|
|||||||
_rtp_encoder = std::make_shared<CommonRtpEncoder>(CodecInvalid, ssrc, video_mtu, 90000, payload_type, 0);
|
_rtp_encoder = std::make_shared<CommonRtpEncoder>(CodecInvalid, ssrc, video_mtu, 90000, payload_type, 0);
|
||||||
_rtp_encoder->setRtpRing(std::make_shared<RtpRing::RingType>());
|
_rtp_encoder->setRtpRing(std::make_shared<RtpRing::RingType>());
|
||||||
_rtp_encoder->getRtpRing()->setDelegate(std::make_shared<RingDelegateHelper>([this](RtpPacket::Ptr rtp, bool is_key){
|
_rtp_encoder->getRtpRing()->setDelegate(std::make_shared<RingDelegateHelper>([this](RtpPacket::Ptr rtp, bool is_key){
|
||||||
onRTP(std::move(rtp));
|
onRTP(std::move(rtp),is_key);
|
||||||
}));
|
}));
|
||||||
InfoL << this << " " << printSSRC(_rtp_encoder->getSsrc());
|
InfoL << this << " " << printSSRC(_rtp_encoder->getSsrc());
|
||||||
}
|
}
|
||||||
@ -36,7 +36,7 @@ void PSEncoderImp::onWrite(std::shared_ptr<Buffer> buffer, uint32_t stamp, bool
|
|||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_rtp_encoder->inputFrame(std::make_shared<FrameFromPtr>(buffer->data(), buffer->size(), stamp, stamp));
|
_rtp_encoder->inputFrame(std::make_shared<FrameFromPtr>(buffer->data(), buffer->size(), stamp, stamp,0,key_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
}//namespace mediakit
|
}//namespace mediakit
|
||||||
|
@ -27,7 +27,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
//rtp打包后回调
|
//rtp打包后回调
|
||||||
virtual void onRTP(toolkit::Buffer::Ptr rtp) = 0;
|
virtual void onRTP(toolkit::Buffer::Ptr rtp,bool is_key = false) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void onWrite(std::shared_ptr<toolkit::Buffer> buffer, uint32_t stamp, bool key_pos) override;
|
void onWrite(std::shared_ptr<toolkit::Buffer> buffer, uint32_t stamp, bool key_pos) override;
|
||||||
|
@ -35,7 +35,7 @@ bool RawEncoderImp::addTrack(const Track::Ptr &track){
|
|||||||
_rtp_encoder = createRtpEncoder(track);
|
_rtp_encoder = createRtpEncoder(track);
|
||||||
_rtp_encoder->setRtpRing(std::make_shared<RtpRing::RingType>());
|
_rtp_encoder->setRtpRing(std::make_shared<RtpRing::RingType>());
|
||||||
_rtp_encoder->getRtpRing()->setDelegate(std::make_shared<RingDelegateHelper>([this](RtpPacket::Ptr rtp, bool is_key){
|
_rtp_encoder->getRtpRing()->setDelegate(std::make_shared<RingDelegateHelper>([this](RtpPacket::Ptr rtp, bool is_key){
|
||||||
onRTP(std::move(rtp));
|
onRTP(std::move(rtp),true);
|
||||||
}));
|
}));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -44,7 +44,7 @@ bool RawEncoderImp::addTrack(const Track::Ptr &track){
|
|||||||
_rtp_encoder = createRtpEncoder(track);
|
_rtp_encoder = createRtpEncoder(track);
|
||||||
_rtp_encoder->setRtpRing(std::make_shared<RtpRing::RingType>());
|
_rtp_encoder->setRtpRing(std::make_shared<RtpRing::RingType>());
|
||||||
_rtp_encoder->getRtpRing()->setDelegate(std::make_shared<RingDelegateHelper>([this](RtpPacket::Ptr rtp, bool is_key){
|
_rtp_encoder->getRtpRing()->setDelegate(std::make_shared<RingDelegateHelper>([this](RtpPacket::Ptr rtp, bool is_key){
|
||||||
onRTP(std::move(rtp));
|
onRTP(std::move(rtp),is_key);
|
||||||
}));
|
}));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -43,10 +43,9 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
//rtp打包后回调
|
//rtp打包后回调
|
||||||
virtual void onRTP(toolkit::Buffer::Ptr rtp) = 0;
|
virtual void onRTP(toolkit::Buffer::Ptr rtp, bool is_key = false) = 0;
|
||||||
private:
|
private:
|
||||||
RtpCodec::Ptr createRtpEncoder(const Track::Ptr &track);
|
RtpCodec::Ptr createRtpEncoder(const Track::Ptr &track);
|
||||||
|
|
||||||
uint32_t _ssrc;
|
uint32_t _ssrc;
|
||||||
uint8_t _payload_type;
|
uint8_t _payload_type;
|
||||||
bool _sendAudio;
|
bool _sendAudio;
|
||||||
|
@ -19,25 +19,37 @@ namespace mediakit{
|
|||||||
RtpCache::RtpCache(onFlushed cb) {
|
RtpCache::RtpCache(onFlushed cb) {
|
||||||
_cb = std::move(cb);
|
_cb = std::move(cb);
|
||||||
}
|
}
|
||||||
|
bool RtpCache::firstKeyReady(bool in) {
|
||||||
|
if(_first_key){
|
||||||
|
return _first_key;
|
||||||
|
}
|
||||||
|
_first_key = in;
|
||||||
|
return _first_key;
|
||||||
|
}
|
||||||
void RtpCache::onFlush(std::shared_ptr<List<Buffer::Ptr> > rtp_list, bool) {
|
void RtpCache::onFlush(std::shared_ptr<List<Buffer::Ptr> > rtp_list, bool) {
|
||||||
_cb(std::move(rtp_list));
|
_cb(std::move(rtp_list));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtpCache::input(uint64_t stamp, Buffer::Ptr buffer) {
|
void RtpCache::input(uint64_t stamp, Buffer::Ptr buffer,bool is_key ) {
|
||||||
inputPacket(stamp, true, std::move(buffer), false);
|
inputPacket(stamp, true, std::move(buffer), is_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtpCachePS::onRTP(Buffer::Ptr buffer) {
|
void RtpCachePS::onRTP(Buffer::Ptr buffer,bool is_key) {
|
||||||
|
if(!firstKeyReady(is_key)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto rtp = std::static_pointer_cast<RtpPacket>(buffer);
|
auto rtp = std::static_pointer_cast<RtpPacket>(buffer);
|
||||||
auto stamp = rtp->getStampMS();
|
auto stamp = rtp->getStampMS();
|
||||||
input(stamp, std::move(buffer));
|
input(stamp, std::move(buffer),is_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtpCacheRaw::onRTP(Buffer::Ptr buffer) {
|
void RtpCacheRaw::onRTP(Buffer::Ptr buffer,bool is_key) {
|
||||||
|
if(!firstKeyReady(is_key)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto rtp = std::static_pointer_cast<RtpPacket>(buffer);
|
auto rtp = std::static_pointer_cast<RtpPacket>(buffer);
|
||||||
auto stamp = rtp->getStampMS();
|
auto stamp = rtp->getStampMS();
|
||||||
input(stamp, std::move(buffer));
|
input(stamp, std::move(buffer),is_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
}//namespace mediakit
|
}//namespace mediakit
|
||||||
|
@ -30,13 +30,15 @@ protected:
|
|||||||
* 输入rtp(目的是为了合并写)
|
* 输入rtp(目的是为了合并写)
|
||||||
* @param buffer rtp数据
|
* @param buffer rtp数据
|
||||||
*/
|
*/
|
||||||
void input(uint64_t stamp, toolkit::Buffer::Ptr buffer);
|
void input(uint64_t stamp, toolkit::Buffer::Ptr buffer,bool is_key = false);
|
||||||
|
|
||||||
|
bool firstKeyReady(bool in);
|
||||||
protected:
|
protected:
|
||||||
void onFlush(std::shared_ptr<toolkit::List<toolkit::Buffer::Ptr> > rtp_list, bool) override;
|
void onFlush(std::shared_ptr<toolkit::List<toolkit::Buffer::Ptr> > rtp_list, bool) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
onFlushed _cb;
|
onFlushed _cb;
|
||||||
|
bool _first_key = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RtpCachePS : public RtpCache, public PSEncoderImp{
|
class RtpCachePS : public RtpCache, public PSEncoderImp{
|
||||||
@ -45,7 +47,7 @@ public:
|
|||||||
~RtpCachePS() override = default;
|
~RtpCachePS() override = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void onRTP(toolkit::Buffer::Ptr rtp) override;
|
void onRTP(toolkit::Buffer::Ptr rtp,bool is_key = false) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -55,7 +57,7 @@ public:
|
|||||||
~RtpCacheRaw() override = default;
|
~RtpCacheRaw() override = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void onRTP(toolkit::Buffer::Ptr rtp) override;
|
void onRTP(toolkit::Buffer::Ptr rtp,bool is_key = false) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}//namespace mediakit
|
}//namespace mediakit
|
||||||
|
@ -101,14 +101,6 @@ ssize_t TSDecoder::input(const uint8_t *data, size_t bytes) {
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TSDecoder::setOnDecode(Decoder::onDecode cb) {
|
|
||||||
_on_decode = std::move(cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TSDecoder::setOnStream(Decoder::onStream cb) {
|
|
||||||
_on_stream = std::move(cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif//defined(ENABLE_HLS)
|
#endif//defined(ENABLE_HLS)
|
||||||
|
|
||||||
}//namespace mediakit
|
}//namespace mediakit
|
||||||
|
@ -45,14 +45,10 @@ public:
|
|||||||
TSDecoder();
|
TSDecoder();
|
||||||
~TSDecoder();
|
~TSDecoder();
|
||||||
ssize_t input(const uint8_t* data, size_t bytes) override ;
|
ssize_t input(const uint8_t* data, size_t bytes) override ;
|
||||||
void setOnDecode(onDecode cb) override;
|
|
||||||
void setOnStream(onStream cb) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TSSegment _ts_segment;
|
TSSegment _ts_segment;
|
||||||
struct ts_demuxer_t* _demuxer_ctx = nullptr;
|
struct ts_demuxer_t* _demuxer_ctx = nullptr;
|
||||||
onDecode _on_decode;
|
|
||||||
onStream _on_stream;
|
|
||||||
};
|
};
|
||||||
#endif//defined(ENABLE_HLS)
|
#endif//defined(ENABLE_HLS)
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ RtspSession::~RtspSession() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RtspSession::onError(const SockException &err) {
|
void RtspSession::onError(const SockException &err) {
|
||||||
bool is_player = !_push_src;
|
bool is_player = !_push_src_ownership;
|
||||||
uint64_t duration = _alive_ticker.createdTime() / 1000;
|
uint64_t duration = _alive_ticker.createdTime() / 1000;
|
||||||
WarnP(this) << (is_player ? "RTSP播放器(" : "RTSP推流器(")
|
WarnP(this) << (is_player ? "RTSP播放器(" : "RTSP推流器(")
|
||||||
<< _media_info._vhost << "/"
|
<< _media_info._vhost << "/"
|
||||||
@ -867,8 +867,9 @@ void RtspSession::handleReq_Pause(const Parser &parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RtspSession::handleReq_Teardown(const Parser &parser) {
|
void RtspSession::handleReq_Teardown(const Parser &parser) {
|
||||||
sendRtspResponse("200 OK");
|
|
||||||
_push_src = nullptr;
|
_push_src = nullptr;
|
||||||
|
//此时回复可能触发broken pipe事件,从而直接触发onError回调;所以需要先把_push_src置空,防止触发断流续推功能
|
||||||
|
sendRtspResponse("200 OK");
|
||||||
throw SockException(Err_shutdown,"recv teardown request");
|
throw SockException(Err_shutdown,"recv teardown request");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "Util/MD5.h"
|
#include <atomic>
|
||||||
|
#include "Util/MD5.h"
|
||||||
#include "Util/logger.h"
|
#include "Util/logger.h"
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
#include "Packet.hpp"
|
#include "Packet.hpp"
|
||||||
|
|
||||||
@ -225,7 +225,35 @@ size_t ControlPacket::size() const {
|
|||||||
uint32_t ControlPacket::getSocketID(uint8_t *buf, size_t len) {
|
uint32_t ControlPacket::getSocketID(uint8_t *buf, size_t len) {
|
||||||
return loadUint32(buf + 12);
|
return loadUint32(buf + 12);
|
||||||
}
|
}
|
||||||
|
std::string HandshakePacket::dump(){
|
||||||
|
_StrPrinter printer;
|
||||||
|
printer <<"flag:"<< (int)f<<"\r\n";
|
||||||
|
printer <<"control_type:"<< (int)control_type<<"\r\n";
|
||||||
|
printer <<"sub_type:"<< (int)sub_type<<"\r\n";
|
||||||
|
printer <<"type_specific_info:"<< (int)type_specific_info[0]<<":"<<(int)type_specific_info[1]<<":"<<(int)type_specific_info[2]<<":"<<(int)type_specific_info[3]<<"\r\n";
|
||||||
|
printer <<"timestamp:"<< timestamp<<"\r\n";
|
||||||
|
printer <<"dst_socket_id:"<< dst_socket_id<<"\r\n";
|
||||||
|
|
||||||
|
printer <<"version:"<< version<<"\r\n";
|
||||||
|
printer <<"encryption_field:"<< encryption_field<<"\r\n";
|
||||||
|
printer <<"extension_field:"<< extension_field<<"\r\n";
|
||||||
|
printer <<"initial_packet_sequence_number:"<< initial_packet_sequence_number<<"\r\n";
|
||||||
|
printer <<"mtu:"<< mtu<<"\r\n";
|
||||||
|
printer <<"max_flow_window_size:"<< max_flow_window_size<<"\r\n";
|
||||||
|
printer <<"handshake_type:"<< handshake_type<<"\r\n";
|
||||||
|
printer <<"srt_socket_id:"<< srt_socket_id<<"\r\n";
|
||||||
|
printer <<"syn_cookie:"<< syn_cookie<<"\r\n";
|
||||||
|
printer <<"peer_ip_addr:";
|
||||||
|
for(size_t i=0;i<sizeof(peer_ip_addr);++i){
|
||||||
|
printer<<(int)peer_ip_addr[i]<<":";
|
||||||
|
}
|
||||||
|
printer<<"\r\n";
|
||||||
|
|
||||||
|
for(size_t i=0;i<ext_list.size();++i){
|
||||||
|
printer<<ext_list[i]->dump()<<"\r\n";
|
||||||
|
}
|
||||||
|
return std::move(printer);
|
||||||
|
}
|
||||||
bool HandshakePacket::loadFromData(uint8_t *buf, size_t len) {
|
bool HandshakePacket::loadFromData(uint8_t *buf, size_t len) {
|
||||||
if (HEADER_SIZE + HS_CONTENT_MIN_SIZE > len) {
|
if (HEADER_SIZE + HS_CONTENT_MIN_SIZE > len) {
|
||||||
ErrorL << "size too smalle " << encryption_field;
|
ErrorL << "size too smalle " << encryption_field;
|
||||||
@ -435,15 +463,11 @@ uint32_t HandshakePacket::generateSynCookie(
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// SYN cookie
|
// SYN cookie
|
||||||
char clienthost[NI_MAXHOST];
|
|
||||||
char clientport[NI_MAXSERV];
|
|
||||||
getnameinfo(
|
|
||||||
(struct sockaddr *)addr, sizeof(struct sockaddr_storage), clienthost, sizeof(clienthost), clientport,
|
|
||||||
sizeof(clientport), NI_NUMERICHOST | NI_NUMERICSERV);
|
|
||||||
int64_t timestamp = (DurationCountMicroseconds(SteadyClock::now() - ts) / 60000000) + distractor.load()
|
int64_t timestamp = (DurationCountMicroseconds(SteadyClock::now() - ts) / 60000000) + distractor.load()
|
||||||
+ correction; // secret changes every one minute
|
+ correction; // secret changes every one minute
|
||||||
std::stringstream cookiestr;
|
std::stringstream cookiestr;
|
||||||
cookiestr << clienthost << ":" << clientport << ":" << timestamp;
|
cookiestr << SockUtil::inet_ntoa((struct sockaddr *)addr) << ":" << SockUtil::inet_port((struct sockaddr *)addr)
|
||||||
|
<< ":" << timestamp;
|
||||||
union {
|
union {
|
||||||
unsigned char cookie[16];
|
unsigned char cookie[16];
|
||||||
uint32_t cookie_val;
|
uint32_t cookie_val;
|
||||||
|
@ -118,9 +118,9 @@ public:
|
|||||||
USERDEFINEDTYPE = 0x7FFF
|
USERDEFINEDTYPE = 0x7FFF
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t sub_type : 16;
|
uint16_t sub_type;
|
||||||
uint32_t control_type : 15;
|
uint16_t control_type;
|
||||||
uint32_t f : 1;
|
uint8_t f;
|
||||||
uint8_t type_specific_info[4];
|
uint8_t type_specific_info[4];
|
||||||
uint32_t timestamp;
|
uint32_t timestamp;
|
||||||
uint32_t dst_socket_id;
|
uint32_t dst_socket_id;
|
||||||
@ -189,7 +189,7 @@ public:
|
|||||||
static uint32_t getSynCookie(uint8_t *buf, size_t len);
|
static uint32_t getSynCookie(uint8_t *buf, size_t len);
|
||||||
static uint32_t
|
static uint32_t
|
||||||
generateSynCookie(struct sockaddr_storage *addr, TimePoint ts, uint32_t current_cookie = 0, int correction = 0);
|
generateSynCookie(struct sockaddr_storage *addr, TimePoint ts, uint32_t current_cookie = 0, int correction = 0);
|
||||||
|
std::string dump();
|
||||||
void assignPeerIP(struct sockaddr_storage *addr);
|
void assignPeerIP(struct sockaddr_storage *addr);
|
||||||
///////ControlPacket override///////
|
///////ControlPacket override///////
|
||||||
bool loadFromData(uint8_t *buf, size_t len) override;
|
bool loadFromData(uint8_t *buf, size_t len) override;
|
||||||
|
@ -86,6 +86,7 @@ void SrtTransport::inputSockData(uint8_t *buf, int len, struct sockaddr_storage
|
|||||||
|
|
||||||
handleDataPacket(buf, len, addr);
|
handleDataPacket(buf, len, addr);
|
||||||
} else {
|
} else {
|
||||||
|
WarnL<<"DataPacket switch to other transport: "<<socketId;
|
||||||
switchToOtherTransport(buf, len, socketId, addr);
|
switchToOtherTransport(buf, len, socketId, addr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -94,6 +95,7 @@ void SrtTransport::inputSockData(uint8_t *buf, int len, struct sockaddr_storage
|
|||||||
uint16_t type = ControlPacket::getControlType(buf, len);
|
uint16_t type = ControlPacket::getControlType(buf, len);
|
||||||
if (type != ControlPacket::HANDSHAKE && socketId != _socket_id && _socket_id != 0) {
|
if (type != ControlPacket::HANDSHAKE && socketId != _socket_id && _socket_id != 0) {
|
||||||
// socket id not same
|
// socket id not same
|
||||||
|
WarnL<<"ControlPacket: "<< (int)type <<" switch to other transport: "<<socketId;
|
||||||
switchToOtherTransport(buf, len, socketId, addr);
|
switchToOtherTransport(buf, len, socketId, addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -168,7 +170,7 @@ void SrtTransport::handleHandshakeConclusion(HandshakePacket &pkt, struct sockad
|
|||||||
if (delay <= 120) {
|
if (delay <= 120) {
|
||||||
delay = 120;
|
delay = 120;
|
||||||
}
|
}
|
||||||
for (auto ext : pkt.ext_list) {
|
for (auto& ext : pkt.ext_list) {
|
||||||
// TraceL << getIdentifier() << " ext " << ext->dump();
|
// TraceL << getIdentifier() << " ext " << ext->dump();
|
||||||
if (!req) {
|
if (!req) {
|
||||||
req = std::dynamic_pointer_cast<HSExtMessage>(ext);
|
req = std::dynamic_pointer_cast<HSExtMessage>(ext);
|
||||||
@ -228,7 +230,10 @@ void SrtTransport::handleHandshakeConclusion(HandshakePacket &pkt, struct sockad
|
|||||||
|
|
||||||
void SrtTransport::handleHandshake(uint8_t *buf, int len, struct sockaddr_storage *addr) {
|
void SrtTransport::handleHandshake(uint8_t *buf, int len, struct sockaddr_storage *addr) {
|
||||||
HandshakePacket pkt;
|
HandshakePacket pkt;
|
||||||
assert(pkt.loadFromData(buf, len));
|
if(!pkt.loadFromData(buf, len)){
|
||||||
|
WarnL<<"is not vaild HandshakePacket";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (pkt.handshake_type == HandshakePacket::HS_TYPE_INDUCTION) {
|
if (pkt.handshake_type == HandshakePacket::HS_TYPE_INDUCTION) {
|
||||||
handleHandshakeInduction(pkt, addr);
|
handleHandshakeInduction(pkt, addr);
|
||||||
@ -236,6 +241,7 @@ void SrtTransport::handleHandshake(uint8_t *buf, int len, struct sockaddr_storag
|
|||||||
handleHandshakeConclusion(pkt, addr);
|
handleHandshakeConclusion(pkt, addr);
|
||||||
} else {
|
} else {
|
||||||
WarnL << " not support handshake type = " << pkt.handshake_type;
|
WarnL << " not support handshake type = " << pkt.handshake_type;
|
||||||
|
WarnL <<pkt.dump();
|
||||||
}
|
}
|
||||||
_ack_ticker.resetTime(_now);
|
_ack_ticker.resetTime(_now);
|
||||||
_nak_ticker.resetTime(_now);
|
_nak_ticker.resetTime(_now);
|
||||||
@ -288,13 +294,13 @@ void SrtTransport::handleNAK(uint8_t *buf, int len, struct sockaddr_storage *add
|
|||||||
bool empty = false;
|
bool empty = false;
|
||||||
bool flush = false;
|
bool flush = false;
|
||||||
|
|
||||||
for (auto it : pkt.lost_list) {
|
for (auto& it : pkt.lost_list) {
|
||||||
if (pkt.lost_list.back() == it) {
|
if (pkt.lost_list.back() == it) {
|
||||||
flush = true;
|
flush = true;
|
||||||
}
|
}
|
||||||
empty = true;
|
empty = true;
|
||||||
auto re_list = _send_buf->findPacketBySeq(it.first, it.second - 1);
|
auto re_list = _send_buf->findPacketBySeq(it.first, it.second - 1);
|
||||||
for (auto pkt : re_list) {
|
for (auto& pkt : re_list) {
|
||||||
pkt->R = 1;
|
pkt->R = 1;
|
||||||
pkt->storeToHeader();
|
pkt->storeToHeader();
|
||||||
sendPacket(pkt, flush);
|
sendPacket(pkt, flush);
|
||||||
@ -325,7 +331,7 @@ void SrtTransport::handleDropReq(uint8_t *buf, int len, struct sockaddr_storage
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint32_t max_seq = 0;
|
uint32_t max_seq = 0;
|
||||||
for (auto data : list) {
|
for (auto& data : list) {
|
||||||
max_seq = data->packet_seq_number;
|
max_seq = data->packet_seq_number;
|
||||||
if (_last_pkt_seq + 1 != data->packet_seq_number) {
|
if (_last_pkt_seq + 1 != data->packet_seq_number) {
|
||||||
TraceL << "pkt lost " << _last_pkt_seq + 1 << "->" << data->packet_seq_number;
|
TraceL << "pkt lost " << _last_pkt_seq + 1 << "->" << data->packet_seq_number;
|
||||||
@ -495,7 +501,7 @@ void SrtTransport::handleDataPacket(uint8_t *buf, int len, struct sockaddr_stora
|
|||||||
// when no data ok send nack to sender immediately
|
// when no data ok send nack to sender immediately
|
||||||
} else {
|
} else {
|
||||||
uint32_t last_seq;
|
uint32_t last_seq;
|
||||||
for (auto data : list) {
|
for (auto& data : list) {
|
||||||
last_seq = data->packet_seq_number;
|
last_seq = data->packet_seq_number;
|
||||||
if (_last_pkt_seq + 1 != data->packet_seq_number) {
|
if (_last_pkt_seq + 1 != data->packet_seq_number) {
|
||||||
TraceL << "pkt lost " << _last_pkt_seq + 1 << "->" << data->packet_seq_number;
|
TraceL << "pkt lost " << _last_pkt_seq + 1 << "->" << data->packet_seq_number;
|
||||||
|
@ -17,7 +17,7 @@ SrtTransportImp::~SrtTransportImp() {
|
|||||||
GET_CONFIG(uint32_t, iFlowThreshold, General::kFlowThreshold);
|
GET_CONFIG(uint32_t, iFlowThreshold, General::kFlowThreshold);
|
||||||
if (_total_bytes >= iFlowThreshold * 1024) {
|
if (_total_bytes >= iFlowThreshold * 1024) {
|
||||||
NoticeCenter::Instance().emitEvent(
|
NoticeCenter::Instance().emitEvent(
|
||||||
Broadcast::kBroadcastFlowReport, _media_info, _total_bytes, duration, false,
|
Broadcast::kBroadcastFlowReport, _media_info, _total_bytes, duration, !_is_pusher,
|
||||||
static_cast<SockInfo &>(*this));
|
static_cast<SockInfo &>(*this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,6 +149,11 @@ std::shared_ptr<SockInfo> SrtTransportImp::getOriginSock(mediakit::MediaSource &
|
|||||||
return static_pointer_cast<SockInfo>(getSession());
|
return static_pointer_cast<SockInfo>(getSession());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toolkit::EventPoller::Ptr SrtTransportImp::getOwnerPoller(MediaSource &sender){
|
||||||
|
auto session = getSession();
|
||||||
|
return session ? session->getPoller() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void SrtTransportImp::emitOnPublish() {
|
void SrtTransportImp::emitOnPublish() {
|
||||||
std::weak_ptr<SrtTransportImp> weak_self = static_pointer_cast<SrtTransportImp>(shared_from_this());
|
std::weak_ptr<SrtTransportImp> weak_self = static_pointer_cast<SrtTransportImp>(shared_from_this());
|
||||||
Broadcast::PublishAuthInvoker invoker = [weak_self](const std::string &err, const ProtocolOption &option) {
|
Broadcast::PublishAuthInvoker invoker = [weak_self](const std::string &err, const ProtocolOption &option) {
|
||||||
@ -282,7 +287,10 @@ std::string SrtTransportImp::getIdentifier() const {
|
|||||||
|
|
||||||
bool SrtTransportImp::inputFrame(const Frame::Ptr &frame) {
|
bool SrtTransportImp::inputFrame(const Frame::Ptr &frame) {
|
||||||
if (_muxer) {
|
if (_muxer) {
|
||||||
return _muxer->inputFrame(frame);
|
//TraceL<<"before type "<<frame->getCodecName()<<" dts "<<frame->dts()<<" pts "<<frame->pts();
|
||||||
|
auto frame_tmp = std::make_shared<FrameStamp>(frame, _type_to_stamp[frame->getTrackType()],false);
|
||||||
|
//TraceL<<"after type "<<frame_tmp->getCodecName()<<" dts "<<frame_tmp->dts()<<" pts "<<frame_tmp->pts();
|
||||||
|
return _muxer->inputFrame(frame_tmp);
|
||||||
}
|
}
|
||||||
if (_cached_func.size() > 200) {
|
if (_cached_func.size() > 200) {
|
||||||
WarnL << "cached frame of track(" << frame->getCodecName() << ") is too much, now dropped";
|
WarnL << "cached frame of track(" << frame->getCodecName() << ") is too much, now dropped";
|
||||||
@ -290,11 +298,17 @@ bool SrtTransportImp::inputFrame(const Frame::Ptr &frame) {
|
|||||||
}
|
}
|
||||||
auto frame_cached = Frame::getCacheAbleFrame(frame);
|
auto frame_cached = Frame::getCacheAbleFrame(frame);
|
||||||
lock_guard<recursive_mutex> lck(_func_mtx);
|
lock_guard<recursive_mutex> lck(_func_mtx);
|
||||||
_cached_func.emplace_back([this, frame_cached]() { _muxer->inputFrame(frame_cached); });
|
_cached_func.emplace_back([this, frame_cached]() {
|
||||||
|
//TraceL<<"before type "<<frame_cached->getCodecName()<<" dts "<<frame_cached->dts()<<" pts "<<frame_cached->pts();
|
||||||
|
auto frame_tmp = std::make_shared<FrameStamp>(frame_cached, _type_to_stamp[frame_cached->getTrackType()],false);
|
||||||
|
//TraceL<<"after type "<<frame_tmp->getCodecName()<<" dts "<<frame_tmp->dts()<<" pts "<<frame_tmp->pts();
|
||||||
|
_muxer->inputFrame(frame_tmp);
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SrtTransportImp::addTrack(const Track::Ptr &track) {
|
bool SrtTransportImp::addTrack(const Track::Ptr &track) {
|
||||||
|
_type_to_stamp.emplace(track->getTrackType(),Stamp());
|
||||||
if (_muxer) {
|
if (_muxer) {
|
||||||
return _muxer->addTrack(track);
|
return _muxer->addTrack(track);
|
||||||
}
|
}
|
||||||
@ -311,6 +325,9 @@ void SrtTransportImp::addTrackCompleted() {
|
|||||||
lock_guard<recursive_mutex> lck(_func_mtx);
|
lock_guard<recursive_mutex> lck(_func_mtx);
|
||||||
_cached_func.emplace_back([this]() { _muxer->addTrackCompleted(); });
|
_cached_func.emplace_back([this]() { _muxer->addTrackCompleted(); });
|
||||||
}
|
}
|
||||||
|
if(_type_to_stamp.size() >1){
|
||||||
|
_type_to_stamp[TrackType::TrackAudio].syncTo(_type_to_stamp[TrackType::TrackVideo]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrtTransportImp::doCachedFunc() {
|
void SrtTransportImp::doCachedFunc() {
|
||||||
|
@ -59,6 +59,8 @@ protected:
|
|||||||
std::string getOriginUrl(mediakit::MediaSource &sender) const override;
|
std::string getOriginUrl(mediakit::MediaSource &sender) const override;
|
||||||
// 获取媒体源客户端相关信息
|
// 获取媒体源客户端相关信息
|
||||||
std::shared_ptr<SockInfo> getOriginSock(mediakit::MediaSource &sender) const override;
|
std::shared_ptr<SockInfo> getOriginSock(mediakit::MediaSource &sender) const override;
|
||||||
|
// get poller
|
||||||
|
toolkit::EventPoller::Ptr getOwnerPoller(MediaSource &sender) override;
|
||||||
|
|
||||||
///////MediaSinkInterface override///////
|
///////MediaSinkInterface override///////
|
||||||
void resetTracks() override {};
|
void resetTracks() override {};
|
||||||
@ -87,6 +89,8 @@ private:
|
|||||||
DecoderImp::Ptr _decoder;
|
DecoderImp::Ptr _decoder;
|
||||||
std::recursive_mutex _func_mtx;
|
std::recursive_mutex _func_mtx;
|
||||||
std::deque<std::function<void()>> _cached_func;
|
std::deque<std::function<void()>> _cached_func;
|
||||||
|
|
||||||
|
std::unordered_map<int, Stamp> _type_to_stamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace SRT
|
} // namespace SRT
|
||||||
|
@ -771,7 +771,6 @@ void RtcSession::loadFrom(const string &str) {
|
|||||||
session_name = sdp.getSessionName();
|
session_name = sdp.getSessionName();
|
||||||
session_info = sdp.getSessionInfo();
|
session_info = sdp.getSessionInfo();
|
||||||
connection = sdp.getConnection();
|
connection = sdp.getConnection();
|
||||||
bandwidth = sdp.getBandwidth();
|
|
||||||
time = sdp.getSessionTime();
|
time = sdp.getSessionTime();
|
||||||
msid_semantic = sdp.getItemClass<SdpAttrMsidSemantic>('a', "msid-semantic");
|
msid_semantic = sdp.getItemClass<SdpAttrMsidSemantic>('a', "msid-semantic");
|
||||||
for (auto &media : sdp.medias) {
|
for (auto &media : sdp.medias) {
|
||||||
@ -783,6 +782,7 @@ void RtcSession::loadFrom(const string &str) {
|
|||||||
rtc_media.type = mline.type;
|
rtc_media.type = mline.type;
|
||||||
rtc_media.port = mline.port;
|
rtc_media.port = mline.port;
|
||||||
rtc_media.addr = media.getItemClass<SdpConnection>('c');
|
rtc_media.addr = media.getItemClass<SdpConnection>('c');
|
||||||
|
rtc_media.bandwidth = media.getItemClass<SdpBandwidth>('b');
|
||||||
rtc_media.ice_ufrag = media.getStringItem('a', "ice-ufrag");
|
rtc_media.ice_ufrag = media.getStringItem('a', "ice-ufrag");
|
||||||
rtc_media.ice_pwd = media.getStringItem('a', "ice-pwd");
|
rtc_media.ice_pwd = media.getStringItem('a', "ice-pwd");
|
||||||
rtc_media.role = media.getItemClass<SdpAttrSetup>('a', "setup").role;
|
rtc_media.role = media.getItemClass<SdpAttrSetup>('a', "setup").role;
|
||||||
@ -1060,9 +1060,6 @@ RtcSessionSdp::Ptr RtcSession::toRtcSessionSdp() const{
|
|||||||
if(connection.empty()){
|
if(connection.empty()){
|
||||||
sdp.addItem(std::make_shared<SdpConnection>(connection));
|
sdp.addItem(std::make_shared<SdpConnection>(connection));
|
||||||
}
|
}
|
||||||
if (!bandwidth.empty()) {
|
|
||||||
sdp.addItem(std::make_shared<SdpBandwidth>(bandwidth));
|
|
||||||
}
|
|
||||||
sdp.addAttr(std::make_shared<SdpAttrGroup>(group));
|
sdp.addAttr(std::make_shared<SdpAttrGroup>(group));
|
||||||
sdp.addAttr(std::make_shared<SdpAttrMsidSemantic>(msid_semantic));
|
sdp.addAttr(std::make_shared<SdpAttrMsidSemantic>(msid_semantic));
|
||||||
for (auto &m : media) {
|
for (auto &m : media) {
|
||||||
@ -1080,6 +1077,9 @@ RtcSessionSdp::Ptr RtcSession::toRtcSessionSdp() const{
|
|||||||
}
|
}
|
||||||
sdp_media.addItem(std::move(mline));
|
sdp_media.addItem(std::move(mline));
|
||||||
sdp_media.addItem(std::make_shared<SdpConnection>(m.addr));
|
sdp_media.addItem(std::make_shared<SdpConnection>(m.addr));
|
||||||
|
if (!m.bandwidth.empty() && m.type != TrackAudio) {
|
||||||
|
sdp_media.addItem(std::make_shared<SdpBandwidth>(m.bandwidth));
|
||||||
|
}
|
||||||
if (!m.rtcp_addr.empty()) {
|
if (!m.rtcp_addr.empty()) {
|
||||||
sdp_media.addAttr(std::make_shared<SdpAttrRtcp>(m.rtcp_addr));
|
sdp_media.addAttr(std::make_shared<SdpAttrRtcp>(m.rtcp_addr));
|
||||||
}
|
}
|
||||||
@ -1631,6 +1631,7 @@ RETRY:
|
|||||||
answer_media.proto = offer_media.proto;
|
answer_media.proto = offer_media.proto;
|
||||||
answer_media.port = offer_media.port;
|
answer_media.port = offer_media.port;
|
||||||
answer_media.addr = offer_media.addr;
|
answer_media.addr = offer_media.addr;
|
||||||
|
answer_media.bandwidth = offer_media.bandwidth;
|
||||||
answer_media.rtcp_addr = offer_media.rtcp_addr;
|
answer_media.rtcp_addr = offer_media.rtcp_addr;
|
||||||
answer_media.rtcp_mux = offer_media.rtcp_mux && configure.rtcp_mux;
|
answer_media.rtcp_mux = offer_media.rtcp_mux && configure.rtcp_mux;
|
||||||
answer_media.rtcp_rsize = offer_media.rtcp_rsize && configure.rtcp_rsize;
|
answer_media.rtcp_rsize = offer_media.rtcp_rsize && configure.rtcp_rsize;
|
||||||
|
@ -612,6 +612,7 @@ public:
|
|||||||
std::string mid;
|
std::string mid;
|
||||||
uint16_t port{0};
|
uint16_t port{0};
|
||||||
SdpConnection addr;
|
SdpConnection addr;
|
||||||
|
SdpBandwidth bandwidth;
|
||||||
std::string proto;
|
std::string proto;
|
||||||
RtpDirection direction{RtpDirection::invalid};
|
RtpDirection direction{RtpDirection::invalid};
|
||||||
std::vector<RtcCodecPlan> plan;
|
std::vector<RtcCodecPlan> plan;
|
||||||
@ -666,7 +667,6 @@ public:
|
|||||||
std::string session_info;
|
std::string session_info;
|
||||||
SdpTime time;
|
SdpTime time;
|
||||||
SdpConnection connection;
|
SdpConnection connection;
|
||||||
SdpBandwidth bandwidth;
|
|
||||||
SdpAttrMsidSemantic msid_semantic;
|
SdpAttrMsidSemantic msid_semantic;
|
||||||
std::vector<RtcMedia> media;
|
std::vector<RtcMedia> media;
|
||||||
SdpAttrGroup group;
|
SdpAttrGroup group;
|
||||||
|
File diff suppressed because it is too large
Load Diff
1008
www/ZLMRTCClient.js
1008
www/ZLMRTCClient.js
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user