Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
Z
ZLMediaKit
概览
Overview
Details
Activity
Cycle Analytics
版本库
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
问题
0
Issues
0
列表
Board
标记
里程碑
合并请求
0
Merge Requests
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
Snippets
成员
Collapse sidebar
Close sidebar
活动
图像
聊天
创建新问题
作业
提交
Issue Boards
Open sidebar
张翔宇
ZLMediaKit
Commits
7805558d
Unverified
Commit
7805558d
authored
Apr 20, 2020
by
baiyfcu
Committed by
GitHub
Apr 20, 2020
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #13 from xiongziliang/master
update
parents
40afa204
003cd583
显示空白字符变更
内嵌
并排
正在显示
54 个修改的文件
包含
894 行增加
和
990 行删除
+894
-990
3rdpart/ZLToolKit
+1
-1
3rdpart/media-server
+1
-1
README.md
+35
-155
README_en.md
+2
-2
api/include/mk_media.h
+11
-36
api/include/mk_player.h
+4
-2
api/source/mk_media.cpp
+12
-43
api/source/mk_player.cpp
+2
-6
conf/config.ini
+3
-0
server/WebApi.cpp
+19
-15
src/Common/Device.cpp
+67
-85
src/Common/Device.h
+36
-51
src/Common/MediaSink.cpp
+8
-15
src/Common/MediaSource.cpp
+47
-0
src/Common/MediaSource.h
+111
-0
src/Common/config.cpp
+4
-0
src/Common/config.h
+5
-0
src/Extension/AAC.cpp
+1
-2
src/Extension/AACRtmp.cpp
+8
-33
src/Extension/AACRtmp.h
+1
-1
src/Extension/Factory.cpp
+63
-99
src/Extension/Factory.h
+1
-32
src/Extension/G711.cpp
+1
-2
src/Extension/G711.h
+36
-82
src/Extension/G711Rtmp.cpp
+22
-28
src/Extension/G711Rtmp.h
+10
-26
src/Extension/G711Rtp.cpp
+49
-49
src/Extension/G711Rtp.h
+9
-8
src/Extension/H264.cpp
+1
-1
src/Extension/H265.cpp
+1
-1
src/Http/HttpSession.cpp
+13
-4
src/Http/HttpSession.h
+1
-1
src/Record/MP4Demuxer.cpp
+9
-3
src/Record/MP4Demuxer.h
+1
-1
src/Record/MP4Reader.cpp
+8
-7
src/Rtmp/FlvMuxer.cpp
+20
-15
src/Rtmp/FlvMuxer.h
+5
-5
src/Rtmp/Rtmp.cpp
+59
-1
src/Rtmp/Rtmp.h
+16
-17
src/Rtmp/RtmpDemuxer.cpp
+48
-5
src/Rtmp/RtmpDemuxer.h
+1
-1
src/Rtmp/RtmpMediaSource.h
+35
-6
src/Rtmp/RtmpPlayer.cpp
+7
-0
src/Rtmp/RtmpPlayer.h
+2
-0
src/Rtmp/RtmpPusher.cpp
+11
-2
src/Rtmp/RtmpSession.cpp
+16
-21
src/Rtmp/RtmpSession.h
+2
-1
src/Rtp/RtpProcess.cpp
+3
-1
src/Rtsp/Rtsp.cpp
+22
-7
src/Rtsp/Rtsp.h
+27
-25
src/Rtsp/RtspMediaSource.h
+7
-91
src/Rtsp/RtspPlayer.cpp
+7
-0
src/Rtsp/RtspPlayer.h
+2
-0
tests/test_benchmark.cpp
+1
-0
没有找到文件。
ZLToolKit
@
987683f1
Subproject commit
681be205ef164db08effd83f925bb750eb1fe149
Subproject commit
987683f1045613098e2bcd534bc90a13d16df8a4
media-server
@
24519a59
Subproject commit
97cf5e47a5af1ff3d4d187f3ebffd9254595df7
5
Subproject commit
24519a594c2c634b21fbe09fad28d54c4eba088
5
README.md
查看文件 @
7805558d
...
@@ -3,29 +3,33 @@
...
@@ -3,29 +3,33 @@
[
english readme
](
https://github.com/xiongziliang/ZLMediaKit/blob/master/README_en.md
)
[
english readme
](
https://github.com/xiongziliang/ZLMediaKit/blob/master/README_en.md
)
# 一个基于C++11的高性能运营级流媒体服务框架
# 一个基于C++11的高性能运营级流媒体服务框架
[

](https://travis-ci.org/xiongziliang/ZLMediaKit)
[

](https://travis-ci.org/xiongziliang/ZLMediaKit)
## 项目特点
## 项目特点
-
基于C++11开发,避免使用裸指针,代码稳定可靠;同时跨平台移植简单方便,代码清晰简洁。
-
打包多种流媒体协议(RTSP/RTMP/HLS/HTTP-FLV/Websocket-FLV),支持协议间的互相转换,提供一站式的服务。
-
基于C++11开发,避免使用裸指针,代码稳定可靠,性能优越。
-
使用epoll+线程池+异步网络IO模式开发,并发性能优越。
-
支持多种协议(RTSP/RTMP/HLS/HTTP-FLV/Websocket-FLV/GB28181/MP4),支持协议互转。
-
已实现主流的的H264/H265+AAC流媒体方案,代码精简,脉络清晰,适合学习。
-
使用多路复用/多线程/异步网络IO模式开发,并发性能优越,支持海量客户端连接。
-
编码格式与框架代码解耦,方便自由简洁的添加支持其他编码格式。
-
代码经过长期大量的稳定性、性能测试,已经在线上商用验证已久。
-
代码经过大量的稳定性、性能测试,可满足商用服务器项目。
-
支持linux、macos、ios、android、windows全平台。
-
支持linux、macos、ios、android、windows平台。
-
支持画面秒开、极低延时(
[
500毫秒内,最低可达100毫秒
](
https://github.com/zlmediakit/ZLMediaKit/wiki/%E5%BB%B6%E6%97%B6%E6%B5%8B%E8%AF%95
)
)。
-
支持画面秒开(GOP缓存)、极低延时(
[
500毫秒内,最低可达100毫秒
](
https://github.com/zlmediakit/ZLMediaKit/wiki/%E5%BB%B6%E6%97%B6%E6%B5%8B%E8%AF%95
)
)。
-
[
ZLMediaKit高并发实现原理
](
https://github.com/xiongziliang/ZLMediaKit/wiki/ZLMediaKit%E9%AB%98%E5%B9%B6%E5%8F%91%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86
)
。
-
提供完善的标准
[
C API
](
https://github.com/xiongziliang/ZLMediaKit/tree/master/api/include
)
,可以作SDK用,或供其他语言调用。
-
提供完善的标准
[
C API
](
https://github.com/xiongziliang/ZLMediaKit/tree/master/api/include
)
,可以作SDK用,或供其他语言调用。
-
提供完整的
[
MediaServer
](
https://github.com/xiongziliang/ZLMediaKit/tree/master/server
)
服务器,可以免开发直接部署为商用服务器。
-
提供完整的
[
MediaServer
](
https://github.com/xiongziliang/ZLMediaKit/tree/master/server
)
服务器,可以免开发直接部署为商用服务器。
-
提供完善的
[
restful api
](
https://github.com/xiongziliang/ZLMediaKit/wiki/MediaServer%E6%94%AF%E6%8C%81%E7%9A%84HTTP-API
)
以及
[
web hook
](
https://github.com/xiongziliang/ZLMediaKit/wiki/MediaServer%E6%94%AF%E6%8C%81%E7%9A%84HTTP-HOOK-API
)
,支持丰富的业务逻辑。
-
打通了视频监控协议栈与直播协议栈,对RTSP/RTMP支持都很完善。
-
全面支持H265。
## 项目定位
## 项目定位
-
移动嵌入式跨平台流媒体解决方案。
-
移动嵌入式跨平台流媒体解决方案。
-
商用级流媒体服务器。
-
商用级流媒体服务器。
-
网络编程二次开发SDK。
-
网络编程二次开发SDK。
## 功能清单
## 功能清单
-
RTSP
-
RTSP
-
RTSP 服务器,支持RTMP/MP4转RTSP
-
RTSP 服务器,支持RTMP/MP4转RTSP
-
RTSPS 服务器,支持亚马逊echo show这样的设备
-
RTSPS 服务器,支持亚马逊echo show这样的设备
...
@@ -35,7 +39,7 @@
...
@@ -35,7 +39,7 @@
-
服务器/客户端完整支持Basic/Digest方式的登录鉴权,全异步可配置化的鉴权接口
-
服务器/客户端完整支持Basic/Digest方式的登录鉴权,全异步可配置化的鉴权接口
-
支持H265编码
-
支持H265编码
-
服务器支持RTSP推流(包括
`rtp over udp`
`rtp over tcp`
方式)
-
服务器支持RTSP推流(包括
`rtp over udp`
`rtp over tcp`
方式)
-
支持任意编码格式的rtsp推流,只是除H264/H265
+AAC
外无法转协议
-
支持任意编码格式的rtsp推流,只是除H264/H265
/AAC/G711
外无法转协议
-
RTMP
-
RTMP
-
RTMP 播放服务器,支持RTSP/MP4转RTMP
-
RTMP 播放服务器,支持RTSP/MP4转RTMP
...
@@ -44,7 +48,7 @@
...
@@ -44,7 +48,7 @@
-
RTMP 推流客户端
-
RTMP 推流客户端
-
支持http
[
s
]
-flv直播
-
支持http
[
s
]
-flv直播
-
支持websocket-flv直播
-
支持websocket-flv直播
-
支持任意编码格式的rtmp推流,只是除H264/H265
+AAC
外无法转协议
-
支持任意编码格式的rtmp推流,只是除H264/H265
/AAC/G711
外无法转协议
-
支持
[
RTMP-H265
](
https://github.com/ksvc/FFmpeg/wiki
)
-
支持
[
RTMP-H265
](
https://github.com/ksvc/FFmpeg/wiki
)
-
HLS
-
HLS
...
@@ -79,167 +83,40 @@
...
@@ -79,167 +83,40 @@
-
提供c api sdk
-
提供c api sdk
## 编译以及测试
## 细节列表
请参考wiki:
[
快速开始
](
https://github.com/xiongziliang/ZLMediaKit/wiki/%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B
)
-
转协议:
| 功能/编码格式 | H264 | H265 | AAC | other |
| :------------------------------: | :--: | :--: | :--: | :---: |
| RTSP[S] --> RTMP/HTTP[S]-FLV/FLV | Y | Y | Y | N |
| RTMP --> RTSP[S] | Y | Y | Y | N |
| RTSP[S] --> HLS | Y | Y | Y | N |
| RTMP --> HLS | Y | Y | Y | N |
| RTSP[S] --> MP4 | Y | Y | Y | N |
| RTMP --> MP4 | Y | Y | Y | N |
| MP4 --> RTSP[S] | Y | Y | Y | N |
| MP4 --> RTMP | Y | Y | Y | N |
-
流生成:
| 功能/编码格式 | H264 | H265 | AAC | other |
| :------------------------------: | :--: | :--: | :--: | :---: |
| RTSP
[
S
]
推流 | Y | Y | Y | Y |
| RTSP拉流代理 | Y | Y | Y | Y |
| RTMP推流 | Y | Y | Y | Y |
| RTMP拉流代理 | Y | Y | Y | Y |
-
RTP传输方式:
| 功能/RTP传输方式 | tcp | udp | http | udp_multicast |
| :-----------------: | :--: | :--: | :--: | :-----------: |
| RTSP
[
S
]
Play Server | Y | Y | Y | Y |
| RTSP
[
S
]
Push Server | Y | Y | N | N |
| RTSP Player | Y | Y | N | Y |
| RTSP Pusher | Y | Y | N | N |
-
支持的服务器类型列表
| 服务类型 | Y/N |
## 怎么使用
| :-----------------: | :--: |
| RTSP
[
S
]
Play Server | Y |
| RTSP
[
S
]
Push Server | Y |
| RTMP | Y |
| HTTP
[
S
]
/WebSocket
[
S
]
| Y |
-
支持的客户端类型
你有三种方法使用ZLMediaKit,分别是:
| 客户端类型 | Y/N |
-
1、使用c api,作为sdk使用,请参考
[
这里
](
https://github.com/xiongziliang/ZLMediaKit/tree/master/api/include
)
.
| :---------: | :--: |
-
2、作为独立的流媒体服务器使用,不想做c/c++开发的,可以参考
[
restful api
](
https://github.com/xiongziliang/ZLMediaKit/wiki/MediaServer%E6%94%AF%E6%8C%81%E7%9A%84HTTP-API
)
和
[
web hook
](
https://github.com/xiongziliang/ZLMediaKit/wiki/MediaServer%E6%94%AF%E6%8C%81%E7%9A%84HTTP-HOOK-API
)
.
| RTSP Player | Y |
-
3、如果想做c/c++开发,添加业务逻辑增加功能,可以参考这里的
[
测试程序
](
https://github.com/xiongziliang/ZLMediaKit/tree/master/tests
)
.
| RTSP Pusher | Y |
| RTMP Player | Y |
| RTMP Pusher | Y |
| HTTP
[
S
]
| Y |
| WebSocket
[
S
]
| Y |
## 编译以及测试
请参考wiki:
[
快速开始
](
https://github.com/xiongziliang/ZLMediaKit/wiki/%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B
)
## Docker 镜像
## Docker 镜像
你可以从Docker Hub下载已经编译好的镜像并启动它:
你可以从Docker Hub下载已经编译好的镜像并启动它:
```
bash
```
bash
docker run
-id
-p
1935:1935
-p
8080:80 gemfield/zlmediakit:20.04-runtime-ubuntu18.04
docker run
-id
-p
1935:1935
-p
8080:80 gemfield/zlmediakit:20.04-runtime-ubuntu18.04
```
```
你也可以根据Dockerfile编译镜像:
你也可以根据Dockerfile编译镜像:
```
bash
```
bash
bash build_docker_images.sh
bash build_docker_images.sh
```
```
## 使用方法
-
作为服务器:
```cpp
TcpServer::Ptr rtspSrv(new TcpServer());
TcpServer::Ptr rtmpSrv(new TcpServer());
TcpServer::Ptr httpSrv(new TcpServer());
TcpServer::Ptr httpsSrv(new TcpServer());
rtspSrv->start<RtspSession>(mINI::Instance()[Config::Rtsp::kPort]);
rtmpSrv->start<RtmpSession>(mINI::Instance()[Config::Rtmp::kPort]);
httpSrv->start<HttpSession>(mINI::Instance()[Config::Http::kPort]);
httpsSrv->start<HttpsSession>(mINI::Instance()[Config::Http::kSSLPort]);
```
-
作为播放器:
```cpp
MediaPlayer::Ptr player(new MediaPlayer());
weak_ptr<MediaPlayer> weakPlayer = player;
player->setOnPlayResult([weakPlayer](const SockException &ex) {
InfoL << "OnPlayResult:" << ex.what();
auto strongPlayer = weakPlayer.lock();
if (ex || !strongPlayer) {
return;
}
auto viedoTrack = strongPlayer->getTrack(TrackVideo);
if (!viedoTrack) {
WarnL << "没有视频Track!";
return;
}
viedoTrack->addDelegate(std::make_shared<FrameWriterInterfaceHelper>([](const Frame::Ptr &frame) {
//此处解码并播放
}));
});
player->setOnShutdown([](const SockException &ex) {
ErrorL << "OnShutdown:" << ex.what();
});
//支持rtmp、rtsp
(*player)[Client::kRtpType] = Rtsp::RTP_TCP;
player->play("rtsp://admin:jzan123456@192.168.0.122/");
```
-
作为代理服务器:
```cpp
//support rtmp and rtsp url
//just support H264+AAC
auto urlList = {"rtmp://live.hkstv.hk.lxdns.com/live/hks",
"rtsp://184.72.239.149/vod/mp4://BigBuckBunny_175k.mov"};
map<string , PlayerProxy::Ptr> proxyMap;
int i=0;
for(auto url : urlList){
//PlayerProxy构造函数前两个参数分别为应用名(app),流id(streamId)
//比如说应用为live,流id为0,那么直播地址为:
//http://127.0.0.1/live/0/hls.m3u8
//rtsp://127.0.0.1/live/0
//rtmp://127.0.0.1/live/0
//录像地址为:
//http://127.0.0.1/record/live/0/2017-04-11/11-09-38.mp4
//rtsp://127.0.0.1/record/live/0/2017-04-11/11-09-38.mp4
//rtmp://127.0.0.1/record/live/0/2017-04-11/11-09-38.mp4
PlayerProxy::Ptr player(new PlayerProxy("live",to_string(i++).data()));
player->play(url);
proxyMap.emplace(string(url),player);
}
```
-
作为推流客户端器:
```cpp
PlayerProxy::Ptr player(new PlayerProxy("app","stream"));
//拉一个流,生成一个RtmpMediaSource,源的名称是"app/stream"
//你也可以以其他方式生成RtmpMediaSource,比如说MP4文件(请研读MediaReader代码)
player->play("rtmp://live.hkstv.hk.lxdns.com/live/hks");
RtmpPusher::Ptr pusher;
//监听RtmpMediaSource注册事件,在PlayerProxy播放成功后触发。
NoticeCenter::Instance().addListener(nullptr,Config::Broadcast::kBroadcastRtmpSrcRegisted,
[&pusher](BroadcastRtmpSrcRegistedArgs){
//媒体源"app/stream"已经注册,这时方可新建一个RtmpPusher对象并绑定该媒体源
const_cast<RtmpPusher::Ptr &>(pusher).reset(new RtmpPusher(app,stream));
//推流地址,请改成你自己的服务器。
//这个范例地址(也是基于mediakit)是可用的,但是带宽只有1mb,访问可能很卡顿。
pusher->publish("rtmp://jizan.iok.la/live/test");
});
```
## 参考案例
## 参考案例
-
[
IOS摄像头实时录制,生成rtsp/rtmp/hls/http-flv
](
https://gitee.com/xiahcu/IOSMedia
)
-
[
IOS摄像头实时录制,生成rtsp/rtmp/hls/http-flv
](
https://gitee.com/xiahcu/IOSMedia
)
-
[
IOS rtmp/rtsp播放器,视频推流器
](
https://gitee.com/xiahcu/IOSPlayer
)
-
[
IOS rtmp/rtsp播放器,视频推流器
](
https://gitee.com/xiahcu/IOSPlayer
)
-
[
支持linux、windows、mac的rtmp/rtsp播放器
](
https://github.com/xiongziliang/ZLMediaPlayer
)
-
[
支持linux、windows、mac的rtmp/rtsp播放器
](
https://github.com/xiongziliang/ZLMediaPlayer
)
-
[
配套的管理WEB网站
](
https://github.com/chenxiaolei/ZLMediaKit_NVR_UI
)
-
[
配套的管理WEB网站
](
https://github.com/chenxiaolei/ZLMediaKit_NVR_UI
)
-
[
DotNetCore的RESTful客户端
](
https://github.com/MingZhuLiu/ZLMediaKit.DotNetCore.Sdk
)
-
[
支持GB28181信令服务器、onvif的NVS系统
](
https://gitee.com/qinqi/JNVS
)
## 授权协议
## 授权协议
...
@@ -248,17 +125,21 @@ bash build_docker_images.sh
...
@@ -248,17 +125,21 @@ bash build_docker_images.sh
由于使用本项目而产生的商业纠纷或侵权行为一概与本项项目及开发者无关,请自行承担法律风险。
由于使用本项目而产生的商业纠纷或侵权行为一概与本项项目及开发者无关,请自行承担法律风险。
## 联系方式
## 联系方式
-
邮箱:
<771730766@qq.com>
(本项目相关或流媒体相关问题请走issue流程,否则恕不邮件答复)
-
邮箱:
<771730766@qq.com>
(本项目相关或流媒体相关问题请走issue流程,否则恕不邮件答复)
-
QQ群:542509000
-
QQ群:542509000
## 怎么提问?
## 怎么提问?
如果要对项目有相关疑问,建议您这么做:
如果要对项目有相关疑问,建议您这么做:
-
1、仔细看下readme、wiki,如果有必要可以查看下issue.
-
1、仔细看下readme、wiki,如果有必要可以查看下issue.
-
2、如果您的问题还没解决,可以提issue.
-
2、如果您的问题还没解决,可以提issue.
-
3、有些问题,如果不具备参考性的,无需在issue提的,可以在qq群提.
-
3、有些问题,如果不具备参考性的,无需在issue提的,可以在qq群提.
-
4、QQ私聊一般不接受无偿技术咨询和支持(
[
为什么不提倡QQ私聊
](
https://github.com/xiongziliang/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/xiongziliang/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
)
).
## 致谢
## 致谢
感谢以下各位对本项目包括但不限于代码贡献、问题反馈、资金捐赠等各种方式的支持!以下排名不分先后:
感谢以下各位对本项目包括但不限于代码贡献、问题反馈、资金捐赠等各种方式的支持!以下排名不分先后:
[
老陈
](
https://github.com/ireader
)
[
老陈
](
https://github.com/ireader
)
...
@@ -276,13 +157,12 @@ bash build_docker_images.sh
...
@@ -276,13 +157,12 @@ bash build_docker_images.sh
[
linkingvision
](
https://www.linkingvision.com/
)
[
linkingvision
](
https://www.linkingvision.com/
)
[
茄子
](
https://github.com/taotaobujue2008
)
[
茄子
](
https://github.com/taotaobujue2008
)
[
好心情
](
<
409257224@qq.com
>
)
[
好心情
](
<
409257224@qq.com
>
)
[
浮沉
](
https://github.com/MingZhuLiu
)
## 捐赠
## 捐赠
欢迎捐赠以便更好的推动项目的发展,谢谢您的支持!
欢迎捐赠以便更好的推动项目的发展,谢谢您的支持!
[
支付宝
](
https://raw.githubusercontent.com/xiongziliang/other/master/IMG_3919.JPG
)
[
支付宝
](
https://raw.githubusercontent.com/xiongziliang/other/master/IMG_3919.JPG
)
[
微信
](
https://raw.githubusercontent.com/xiongziliang/other/master/IMG_3920.JPG
)
[
微信
](
https://raw.githubusercontent.com/xiongziliang/other/master/IMG_3920.JPG
)
README_en.md
查看文件 @
7805558d
...
@@ -20,7 +20,7 @@
...
@@ -20,7 +20,7 @@
-
RTSP player and pusher.
-
RTSP player and pusher.
-
RTP Transport :
`rtp over udp`
`rtp over tcp`
`rtp over http`
`rtp udp multicast`
.
-
RTP Transport :
`rtp over udp`
`rtp over tcp`
`rtp over http`
`rtp udp multicast`
.
-
Basic/Digest/Url Authentication.
-
Basic/Digest/Url Authentication.
-
H26
5/H264/AAC
codec.
-
H26
4/H265/AAC/G711
codec.
-
Recorded as mp4.
-
Recorded as mp4.
-
Vod of mp4.
-
Vod of mp4.
...
@@ -28,7 +28,7 @@
...
@@ -28,7 +28,7 @@
-
RTMP server,support player and pusher.
-
RTMP server,support player and pusher.
-
RTMP player and pusher.
-
RTMP player and pusher.
-
Support HTTP-FLV player.
-
Support HTTP-FLV player.
-
H264/
AAC
codec.
-
H264/
H265/AAC/G711
codec.
-
Recorded as flv or mp4.
-
Recorded as flv or mp4.
-
Vod of mp4.
-
Vod of mp4.
-
support
[
RTMP-H265
](
https://github.com/ksvc/FFmpeg/wiki
)
-
support
[
RTMP-H265
](
https://github.com/ksvc/FFmpeg/wiki
)
...
...
api/include/mk_media.h
查看文件 @
7805558d
...
@@ -25,11 +25,14 @@ typedef void *mk_media;
...
@@ -25,11 +25,14 @@ typedef void *mk_media;
* @param app 应用名,推荐为live
* @param app 应用名,推荐为live
* @param stream 流id,例如camera
* @param stream 流id,例如camera
* @param duration 时长(单位秒),直播则为0
* @param duration 时长(单位秒),直播则为0
* @param rtsp_enabled 是否启用rtsp协议
* @param rtmp_enabled 是否启用rtmp协议
* @param hls_enabled 是否生成hls
* @param hls_enabled 是否生成hls
* @param mp4_enabled 是否生成mp4
* @param mp4_enabled 是否生成mp4
* @return 对象指针
* @return 对象指针
*/
*/
API_EXPORT
mk_media
API_CALL
mk_media_create
(
const
char
*
vhost
,
const
char
*
app
,
const
char
*
stream
,
float
duration
,
int
hls_enabled
,
int
mp4_enabled
);
API_EXPORT
mk_media
API_CALL
mk_media_create
(
const
char
*
vhost
,
const
char
*
app
,
const
char
*
stream
,
float
duration
,
int
rtsp_enabled
,
int
rtmp_enabled
,
int
hls_enabled
,
int
mp4_enabled
);
/**
/**
* 销毁媒体源
* 销毁媒体源
...
@@ -38,42 +41,24 @@ API_EXPORT mk_media API_CALL mk_media_create(const char *vhost, const char *app,
...
@@ -38,42 +41,24 @@ API_EXPORT mk_media API_CALL mk_media_create(const char *vhost, const char *app,
API_EXPORT
void
API_CALL
mk_media_release
(
mk_media
ctx
);
API_EXPORT
void
API_CALL
mk_media_release
(
mk_media
ctx
);
/**
/**
* 添加
h264
视频轨道
* 添加视频轨道
* @param ctx 对象指针
* @param ctx 对象指针
* @param track_id 0:CodecH264/1:CodecH265
* @param width 视频宽度
* @param width 视频宽度
* @param height 视频高度
* @param height 视频高度
* @param fps 视频fps
* @param fps 视频fps
*/
*/
API_EXPORT
void
API_CALL
mk_media_init_
h264
(
mk_media
ctx
,
int
width
,
int
height
,
int
fps
);
API_EXPORT
void
API_CALL
mk_media_init_
video
(
mk_media
ctx
,
int
track_id
,
int
width
,
int
height
,
int
fps
);
/**
/**
* 添加
h265视
频轨道
* 添加
音
频轨道
* @param ctx 对象指针
* @param ctx 对象指针
* @param width 视频宽度
* @param track_id 2:CodecAAC/3:CodecG711A/4:CodecG711U
* @param height 视频高度
* @param fps 视频fps
*/
API_EXPORT
void
API_CALL
mk_media_init_h265
(
mk_media
ctx
,
int
width
,
int
height
,
int
fps
);
/**
* 添加aac音频轨道
* @param ctx 对象指针
* @param channel 通道数
* @param sample_bit 采样位数,只支持16
* @param sample_rate 采样率
* @param profile aac编码profile,在不输入adts头时用于生产adts头
*/
API_EXPORT
void
API_CALL
mk_media_init_aac
(
mk_media
ctx
,
int
channel
,
int
sample_bit
,
int
sample_rate
,
int
profile
);
/**
* 添加g711音频轨道
* @param ctx 对象指针
* @param au 1.G711A 2.G711U
* @param channel 通道数
* @param channel 通道数
* @param sample_bit 采样位数,只支持16
* @param sample_bit 采样位数,只支持16
* @param sample_rate 采样率
* @param sample_rate 采样率
*/
*/
API_EXPORT
void
API_CALL
mk_media_init_
g711
(
mk_media
ctx
,
int
au
,
int
sample_bit
,
int
sample_rate
);
API_EXPORT
void
API_CALL
mk_media_init_
audio
(
mk_media
ctx
,
int
track_id
,
int
sample_rate
,
int
channels
,
int
sample_bit
);
/**
/**
* 初始化h264/h265/aac完毕后调用此函数,
* 初始化h264/h265/aac完毕后调用此函数,
...
@@ -104,16 +89,6 @@ API_EXPORT void API_CALL mk_media_input_h264(mk_media ctx, void *data, int len,
...
@@ -104,16 +89,6 @@ API_EXPORT void API_CALL mk_media_input_h264(mk_media ctx, void *data, int len,
API_EXPORT
void
API_CALL
mk_media_input_h265
(
mk_media
ctx
,
void
*
data
,
int
len
,
uint32_t
dts
,
uint32_t
pts
);
API_EXPORT
void
API_CALL
mk_media_input_h265
(
mk_media
ctx
,
void
*
data
,
int
len
,
uint32_t
dts
,
uint32_t
pts
);
/**
/**
* 输入单帧AAC音频
* @param ctx 对象指针
* @param data 单帧AAC数据
* @param len 单帧AAC数据字节数
* @param dts 时间戳,毫秒
* @param with_adts_header data中是否包含7个字节的adts头
*/
API_EXPORT
void
API_CALL
mk_media_input_aac
(
mk_media
ctx
,
void
*
data
,
int
len
,
uint32_t
dts
,
int
with_adts_header
);
/**
* 输入单帧AAC音频(单独指定adts头)
* 输入单帧AAC音频(单独指定adts头)
* @param ctx 对象指针
* @param ctx 对象指针
* @param data 不包含adts头的单帧AAC数据
* @param data 不包含adts头的单帧AAC数据
...
@@ -121,7 +96,7 @@ API_EXPORT void API_CALL mk_media_input_aac(mk_media ctx, void *data, int len, u
...
@@ -121,7 +96,7 @@ API_EXPORT void API_CALL mk_media_input_aac(mk_media ctx, void *data, int len, u
* @param dts 时间戳,毫秒
* @param dts 时间戳,毫秒
* @param adts adts头
* @param adts adts头
*/
*/
API_EXPORT
void
API_CALL
mk_media_input_aac
1
(
mk_media
ctx
,
void
*
data
,
int
len
,
uint32_t
dts
,
void
*
adts
);
API_EXPORT
void
API_CALL
mk_media_input_aac
(
mk_media
ctx
,
void
*
data
,
int
len
,
uint32_t
dts
,
void
*
adts
);
/**
/**
* 输入单帧G711音频
* 输入单帧G711音频
...
...
api/include/mk_player.h
查看文件 @
7805558d
...
@@ -31,7 +31,7 @@ typedef void(API_CALL *on_mk_play_event)(void *user_data,int err_code,const char
...
@@ -31,7 +31,7 @@ typedef void(API_CALL *on_mk_play_event)(void *user_data,int err_code,const char
* 收到音视频数据回调
* 收到音视频数据回调
* @param user_data 用户数据指针
* @param user_data 用户数据指针
* @param track_type 0:视频,1:音频
* @param track_type 0:视频,1:音频
* @param codec_id 0:H264,1:H265,2:AAC
* @param codec_id 0:H264,1:H265,2:AAC
3.G711A 4.G711U
* @param data 数据指针
* @param data 数据指针
* @param len 数据长度
* @param len 数据长度
* @param dts 解码时间戳,单位毫秒
* @param dts 解码时间戳,单位毫秒
...
@@ -98,13 +98,15 @@ API_EXPORT void API_CALL mk_player_set_on_shutdown(mk_player ctx, on_mk_play_eve
...
@@ -98,13 +98,15 @@ API_EXPORT void API_CALL mk_player_set_on_shutdown(mk_player ctx, on_mk_play_eve
/**
/**
* 设置音视频数据回调函数
* 设置音视频数据回调函数
* 该接口
只能在播放成功事件触发后才能调用
* 该接口
在播放成功事件触发后才有效
* @param ctx 播放器指针
* @param ctx 播放器指针
* @param cb 回调函数指针,不得为null
* @param cb 回调函数指针,不得为null
* @param user_data 用户数据指针
* @param user_data 用户数据指针
*/
*/
API_EXPORT
void
API_CALL
mk_player_set_on_data
(
mk_player
ctx
,
on_mk_play_data
cb
,
void
*
user_data
);
API_EXPORT
void
API_CALL
mk_player_set_on_data
(
mk_player
ctx
,
on_mk_play_data
cb
,
void
*
user_data
);
///////////////////////////获取音视频相关信息接口在播放成功回调触发后才有效///////////////////////////////
/**
/**
* 获取视频codec_id -1:不存在 0:H264,1:H265,2:AAC 3.G711A 4.G711U
* 获取视频codec_id -1:不存在 0:H264,1:H265,2:AAC 3.G711A 4.G711U
* @param ctx 播放器指针
* @param ctx 播放器指针
...
...
api/source/mk_media.cpp
查看文件 @
7805558d
...
@@ -96,9 +96,11 @@ API_EXPORT int API_CALL mk_media_total_reader_count(mk_media ctx){
...
@@ -96,9 +96,11 @@ API_EXPORT int API_CALL mk_media_total_reader_count(mk_media ctx){
return
(
*
obj
)
->
getChannel
()
->
totalReaderCount
();
return
(
*
obj
)
->
getChannel
()
->
totalReaderCount
();
}
}
API_EXPORT
mk_media
API_CALL
mk_media_create
(
const
char
*
vhost
,
const
char
*
app
,
const
char
*
stream
,
float
duration
,
int
hls_enabled
,
int
mp4_enabled
)
{
API_EXPORT
mk_media
API_CALL
mk_media_create
(
const
char
*
vhost
,
const
char
*
app
,
const
char
*
stream
,
float
duration
,
int
rtsp_enabled
,
int
rtmp_enabled
,
int
hls_enabled
,
int
mp4_enabled
)
{
assert
(
vhost
&&
app
&&
stream
);
assert
(
vhost
&&
app
&&
stream
);
MediaHelper
::
Ptr
*
obj
(
new
MediaHelper
::
Ptr
(
new
MediaHelper
(
vhost
,
app
,
stream
,
duration
,
true
,
true
,
hls_enabled
,
mp4_enabled
)));
MediaHelper
::
Ptr
*
obj
(
new
MediaHelper
::
Ptr
(
new
MediaHelper
(
vhost
,
app
,
stream
,
duration
,
rtsp_enabled
,
rtmp_enabled
,
hls_enabled
,
mp4_enabled
)));
(
*
obj
)
->
attachEvent
();
(
*
obj
)
->
attachEvent
();
return
(
mk_media
)
obj
;
return
(
mk_media
)
obj
;
}
}
...
@@ -109,48 +111,25 @@ API_EXPORT void API_CALL mk_media_release(mk_media ctx) {
...
@@ -109,48 +111,25 @@ API_EXPORT void API_CALL mk_media_release(mk_media ctx) {
delete
obj
;
delete
obj
;
}
}
API_EXPORT
void
API_CALL
mk_media_init_
h264
(
mk_media
ctx
,
int
width
,
int
height
,
int
frameRate
)
{
API_EXPORT
void
API_CALL
mk_media_init_
video
(
mk_media
ctx
,
int
track_id
,
int
width
,
int
height
,
int
fps
)
{
assert
(
ctx
);
assert
(
ctx
);
MediaHelper
::
Ptr
*
obj
=
(
MediaHelper
::
Ptr
*
)
ctx
;
MediaHelper
::
Ptr
*
obj
=
(
MediaHelper
::
Ptr
*
)
ctx
;
VideoInfo
info
;
VideoInfo
info
;
info
.
iFrameRate
=
frameRate
;
info
.
codecId
=
(
CodecId
)
track_id
;
info
.
iFrameRate
=
fps
;
info
.
iWidth
=
width
;
info
.
iWidth
=
width
;
info
.
iHeight
=
height
;
info
.
iHeight
=
height
;
(
*
obj
)
->
getChannel
()
->
initVideo
(
info
);
(
*
obj
)
->
getChannel
()
->
initVideo
(
info
);
}
}
API_EXPORT
void
API_CALL
mk_media_init_h265
(
mk_media
ctx
,
int
width
,
int
height
,
int
frameRate
)
{
API_EXPORT
void
API_CALL
mk_media_init_audio
(
mk_media
ctx
,
int
track_id
,
int
sample_rate
,
int
channels
,
int
sample_bit
){
assert
(
ctx
);
MediaHelper
::
Ptr
*
obj
=
(
MediaHelper
::
Ptr
*
)
ctx
;
VideoInfo
info
;
info
.
iFrameRate
=
frameRate
;
info
.
iWidth
=
width
;
info
.
iHeight
=
height
;
(
*
obj
)
->
getChannel
()
->
initH265Video
(
info
);
}
API_EXPORT
void
API_CALL
mk_media_init_aac
(
mk_media
ctx
,
int
channel
,
int
sample_bit
,
int
sample_rate
,
int
profile
)
{
assert
(
ctx
);
assert
(
ctx
);
MediaHelper
::
Ptr
*
obj
=
(
MediaHelper
::
Ptr
*
)
ctx
;
MediaHelper
::
Ptr
*
obj
=
(
MediaHelper
::
Ptr
*
)
ctx
;
AudioInfo
info
;
AudioInfo
info
;
info
.
codecId
=
(
CodecId
)
track_id
;
info
.
iSampleRate
=
sample_rate
;
info
.
iSampleRate
=
sample_rate
;
info
.
iChannel
=
channel
;
info
.
iChannel
=
channel
s
;
info
.
iSampleBit
=
sample_bit
;
info
.
iSampleBit
=
sample_bit
;
info
.
iProfile
=
profile
;
(
*
obj
)
->
getChannel
()
->
initAudio
(
info
);
}
API_EXPORT
void
API_CALL
mk_media_init_g711
(
mk_media
ctx
,
int
au
,
int
sample_bit
,
int
sample_rate
)
{
assert
(
ctx
);
MediaHelper
::
Ptr
*
obj
=
(
MediaHelper
::
Ptr
*
)
ctx
;
AudioInfo
info
;
info
.
iSampleRate
=
sample_rate
;
info
.
iChannel
=
1
;
info
.
iSampleBit
=
sample_bit
;
info
.
iProfile
=
0
;
info
.
codecId
=
(
CodecId
)
au
;
(
*
obj
)
->
getChannel
()
->
initAudio
(
info
);
(
*
obj
)
->
getChannel
()
->
initAudio
(
info
);
}
}
...
@@ -172,24 +151,14 @@ API_EXPORT void API_CALL mk_media_input_h265(mk_media ctx, void *data, int len,
...
@@ -172,24 +151,14 @@ API_EXPORT void API_CALL mk_media_input_h265(mk_media ctx, void *data, int len,
(
*
obj
)
->
getChannel
()
->
inputH265
((
char
*
)
data
,
len
,
dts
,
pts
);
(
*
obj
)
->
getChannel
()
->
inputH265
((
char
*
)
data
,
len
,
dts
,
pts
);
}
}
API_EXPORT
void
API_CALL
mk_media_input_aac
(
mk_media
ctx
,
void
*
data
,
int
len
,
uint32_t
dts
,
int
with_adts_header
)
{
API_EXPORT
void
API_CALL
mk_media_input_aac
(
mk_media
ctx
,
void
*
data
,
int
len
,
uint32_t
dts
,
void
*
adts
)
{
assert
(
ctx
&&
data
&&
len
>
0
);
MediaHelper
::
Ptr
*
obj
=
(
MediaHelper
::
Ptr
*
)
ctx
;
(
*
obj
)
->
getChannel
()
->
inputAAC
((
char
*
)
data
,
len
,
dts
,
with_adts_header
);
}
API_EXPORT
void
API_CALL
mk_media_input_aac1
(
mk_media
ctx
,
void
*
data
,
int
len
,
uint32_t
dts
,
void
*
adts
)
{
assert
(
ctx
&&
data
&&
len
>
0
&&
adts
);
assert
(
ctx
&&
data
&&
len
>
0
&&
adts
);
MediaHelper
::
Ptr
*
obj
=
(
MediaHelper
::
Ptr
*
)
ctx
;
MediaHelper
::
Ptr
*
obj
=
(
MediaHelper
::
Ptr
*
)
ctx
;
(
*
obj
)
->
getChannel
()
->
inputAAC
((
char
*
)
data
,
len
,
dts
,
(
char
*
)
adts
);
(
*
obj
)
->
getChannel
()
->
inputAAC
((
char
*
)
data
,
len
,
dts
,
(
char
*
)
adts
);
}
}
API_EXPORT
void
API_CALL
mk_media_input_g711
(
mk_media
ctx
,
void
*
data
,
int
len
,
uint32_t
dts
)
API_EXPORT
void
API_CALL
mk_media_input_g711
(
mk_media
ctx
,
void
*
data
,
int
len
,
uint32_t
dts
){
{
assert
(
ctx
&&
data
&&
len
>
0
);
assert
(
ctx
&&
data
&&
len
>
0
);
MediaHelper
::
Ptr
*
obj
=
(
MediaHelper
::
Ptr
*
)
ctx
;
MediaHelper
::
Ptr
*
obj
=
(
MediaHelper
::
Ptr
*
)
ctx
;
(
*
obj
)
->
getChannel
()
->
inputG711
((
char
*
)
data
,
len
,
dts
);
(
*
obj
)
->
getChannel
()
->
inputG711
((
char
*
)
data
,
len
,
dts
);
}
}
api/source/mk_player.cpp
查看文件 @
7805558d
...
@@ -101,9 +101,7 @@ API_EXPORT void API_CALL mk_player_set_on_data(mk_player ctx, on_mk_play_data cb
...
@@ -101,9 +101,7 @@ API_EXPORT void API_CALL mk_player_set_on_data(mk_player ctx, on_mk_play_data cb
});
});
}
}
API_EXPORT
int
API_CALL
mk_player_video_codecId
(
mk_player
ctx
){
API_EXPORT
int
API_CALL
mk_player_video_codecId
(
mk_player
ctx
)
{
assert
(
ctx
);
assert
(
ctx
);
MediaPlayer
::
Ptr
&
player
=
*
((
MediaPlayer
::
Ptr
*
)
ctx
);
MediaPlayer
::
Ptr
&
player
=
*
((
MediaPlayer
::
Ptr
*
)
ctx
);
auto
track
=
dynamic_pointer_cast
<
VideoTrack
>
(
player
->
getTrack
(
TrackVideo
));
auto
track
=
dynamic_pointer_cast
<
VideoTrack
>
(
player
->
getTrack
(
TrackVideo
));
...
@@ -131,9 +129,7 @@ API_EXPORT int API_CALL mk_player_video_fps(mk_player ctx) {
...
@@ -131,9 +129,7 @@ API_EXPORT int API_CALL mk_player_video_fps(mk_player ctx) {
return
track
?
track
->
getVideoFps
()
:
0
;
return
track
?
track
->
getVideoFps
()
:
0
;
}
}
API_EXPORT
int
API_CALL
mk_player_audio_codecId
(
mk_player
ctx
){
API_EXPORT
int
API_CALL
mk_player_audio_codecId
(
mk_player
ctx
)
{
assert
(
ctx
);
assert
(
ctx
);
MediaPlayer
::
Ptr
&
player
=
*
((
MediaPlayer
::
Ptr
*
)
ctx
);
MediaPlayer
::
Ptr
&
player
=
*
((
MediaPlayer
::
Ptr
*
)
ctx
);
auto
track
=
dynamic_pointer_cast
<
AudioTrack
>
(
player
->
getTrack
(
TrackAudio
));
auto
track
=
dynamic_pointer_cast
<
AudioTrack
>
(
player
->
getTrack
(
TrackAudio
));
...
...
conf/config.ini
查看文件 @
7805558d
...
@@ -42,6 +42,9 @@ publishToRtxp=1
...
@@ -42,6 +42,9 @@ publishToRtxp=1
publishToHls
=
1
publishToHls
=
1
#是否默认推流时mp4录像,hook接口(on_publish)中可以覆盖该设置
#是否默认推流时mp4录像,hook接口(on_publish)中可以覆盖该设置
publishToMP4
=
0
publishToMP4
=
0
#合并写缓存大小(单位毫秒),合并写指服务器缓存一定的数据后才会一次性写入socket,这样能提高性能,但是会提高延时
#在开启低延时模式后,该参数不起作用
mergeWriteMS
=
300
[hls]
[hls]
#hls写文件的buf大小,调整参数可以提高文件io性能
#hls写文件的buf大小,调整参数可以提高文件io性能
...
...
server/WebApi.cpp
查看文件 @
7805558d
...
@@ -38,11 +38,12 @@ using namespace mediakit;
...
@@ -38,11 +38,12 @@ using namespace mediakit;
namespace
API
{
namespace
API
{
typedef
enum
{
typedef
enum
{
InvalidArgs
=
-
300
,
Exception
=
-
400
,
//代码抛异常
SqlFailed
=
-
200
,
InvalidArgs
=
-
300
,
//参数不合法
AuthFailed
=
-
100
,
SqlFailed
=
-
200
,
//sql执行失败
OtherFailed
=
-
1
,
AuthFailed
=
-
100
,
//鉴权失败
Success
=
0
OtherFailed
=
-
1
,
//业务代码执行失败,
Success
=
0
//执行成功
}
ApiErr
;
}
ApiErr
;
#define API_FIELD "api."
#define API_FIELD "api."
...
@@ -154,7 +155,8 @@ static inline void addHttpListener(){
...
@@ -154,7 +155,8 @@ static inline void addHttpListener(){
HttpSession
::
KeyValue
headerOut
;
HttpSession
::
KeyValue
headerOut
;
auto
allArgs
=
getAllArgs
(
parser
);
auto
allArgs
=
getAllArgs
(
parser
);
HttpSession
::
KeyValue
&
headerIn
=
parser
.
getValues
();
HttpSession
::
KeyValue
&
headerIn
=
parser
.
getValues
();
headerOut
[
"Content-Type"
]
=
"application/json; charset=utf-8"
;
GET_CONFIG
(
string
,
charSet
,
Http
::
kCharSet
);
headerOut
[
"Content-Type"
]
=
StrPrinter
<<
"application/json; charset="
<<
charSet
;
if
(
api_debug
){
if
(
api_debug
){
auto
newInvoker
=
[
invoker
,
parser
,
allArgs
](
const
string
&
codeOut
,
auto
newInvoker
=
[
invoker
,
parser
,
allArgs
](
const
string
&
codeOut
,
const
HttpSession
::
KeyValue
&
headerOut
,
const
HttpSession
::
KeyValue
&
headerOut
,
...
@@ -207,7 +209,7 @@ static inline void addHttpListener(){
...
@@ -207,7 +209,7 @@ static inline void addHttpListener(){
}
}
#endif// ENABLE_MYSQL
#endif// ENABLE_MYSQL
catch
(
std
::
exception
&
ex
)
{
catch
(
std
::
exception
&
ex
)
{
val
[
"code"
]
=
API
::
OtherFailed
;
val
[
"code"
]
=
API
::
Exception
;
val
[
"msg"
]
=
ex
.
what
();
val
[
"msg"
]
=
ex
.
what
();
invoker
(
"200 OK"
,
headerOut
,
val
.
toStyledString
());
invoker
(
"200 OK"
,
headerOut
,
val
.
toStyledString
());
}
}
...
@@ -447,9 +449,11 @@ void installWebApi() {
...
@@ -447,9 +449,11 @@ void installWebApi() {
bool
flag
=
src
->
close
(
allArgs
[
"force"
].
as
<
bool
>
());
bool
flag
=
src
->
close
(
allArgs
[
"force"
].
as
<
bool
>
());
val
[
"result"
]
=
flag
?
0
:
-
1
;
val
[
"result"
]
=
flag
?
0
:
-
1
;
val
[
"msg"
]
=
flag
?
"success"
:
"close failed"
;
val
[
"msg"
]
=
flag
?
"success"
:
"close failed"
;
val
[
"code"
]
=
API
::
OtherFailed
;
}
else
{
}
else
{
val
[
"result"
]
=
-
2
;
val
[
"result"
]
=
-
2
;
val
[
"msg"
]
=
"can not find the stream"
;
val
[
"msg"
]
=
"can not find the stream"
;
val
[
"code"
]
=
API
::
OtherFailed
;
}
}
});
});
...
@@ -725,21 +729,27 @@ void installWebApi() {
...
@@ -725,21 +729,27 @@ void installWebApi() {
api_regist1
(
"/index/api/startRecord"
,[](
API_ARGS1
){
api_regist1
(
"/index/api/startRecord"
,[](
API_ARGS1
){
CHECK_SECRET
();
CHECK_SECRET
();
CHECK_ARGS
(
"type"
,
"vhost"
,
"app"
,
"stream"
);
CHECK_ARGS
(
"type"
,
"vhost"
,
"app"
,
"stream"
);
val
[
"result"
]
=
Recorder
::
startRecord
((
Recorder
::
type
)
allArgs
[
"type"
].
as
<
int
>
(),
auto
result
=
Recorder
::
startRecord
((
Recorder
::
type
)
allArgs
[
"type"
].
as
<
int
>
(),
allArgs
[
"vhost"
],
allArgs
[
"vhost"
],
allArgs
[
"app"
],
allArgs
[
"app"
],
allArgs
[
"stream"
],
allArgs
[
"stream"
],
allArgs
[
"customized_path"
]);
allArgs
[
"customized_path"
]);
val
[
"result"
]
=
result
;
val
[
"code"
]
=
result
?
API
::
Success
:
API
::
OtherFailed
;
val
[
"msg"
]
=
result
?
"success"
:
"start record failed"
;
});
});
// 停止录制hls或MP4
// 停止录制hls或MP4
api_regist1
(
"/index/api/stopRecord"
,[](
API_ARGS1
){
api_regist1
(
"/index/api/stopRecord"
,[](
API_ARGS1
){
CHECK_SECRET
();
CHECK_SECRET
();
CHECK_ARGS
(
"type"
,
"vhost"
,
"app"
,
"stream"
);
CHECK_ARGS
(
"type"
,
"vhost"
,
"app"
,
"stream"
);
val
[
"result"
]
=
Recorder
::
stopRecord
((
Recorder
::
type
)
allArgs
[
"type"
].
as
<
int
>
(),
auto
result
=
Recorder
::
stopRecord
((
Recorder
::
type
)
allArgs
[
"type"
].
as
<
int
>
(),
allArgs
[
"vhost"
],
allArgs
[
"vhost"
],
allArgs
[
"app"
],
allArgs
[
"app"
],
allArgs
[
"stream"
]);
allArgs
[
"stream"
]);
val
[
"result"
]
=
result
;
val
[
"code"
]
=
result
?
API
::
Success
:
API
::
OtherFailed
;
val
[
"msg"
]
=
result
?
"success"
:
"stop record failed"
;
});
});
// 获取hls或MP4录制状态
// 获取hls或MP4录制状态
...
@@ -802,12 +812,10 @@ void installWebApi() {
...
@@ -802,12 +812,10 @@ void installWebApi() {
api_regist1
(
"/index/hook/on_play"
,[](
API_ARGS1
){
api_regist1
(
"/index/hook/on_play"
,[](
API_ARGS1
){
//开始播放事件
//开始播放事件
throw
SuccessException
();
});
});
api_regist1
(
"/index/hook/on_flow_report"
,[](
API_ARGS1
){
api_regist1
(
"/index/hook/on_flow_report"
,[](
API_ARGS1
){
//流量统计hook api
//流量统计hook api
throw
SuccessException
();
});
});
api_regist1
(
"/index/hook/on_rtsp_realm"
,[](
API_ARGS1
){
api_regist1
(
"/index/hook/on_rtsp_realm"
,[](
API_ARGS1
){
...
@@ -827,7 +835,6 @@ void installWebApi() {
...
@@ -827,7 +835,6 @@ void installWebApi() {
api_regist1
(
"/index/hook/on_stream_changed"
,[](
API_ARGS1
){
api_regist1
(
"/index/hook/on_stream_changed"
,[](
API_ARGS1
){
//媒体注册或反注册事件
//媒体注册或反注册事件
throw
SuccessException
();
});
});
...
@@ -890,12 +897,10 @@ void installWebApi() {
...
@@ -890,12 +897,10 @@ void installWebApi() {
api_regist1
(
"/index/hook/on_record_mp4"
,[](
API_ARGS1
){
api_regist1
(
"/index/hook/on_record_mp4"
,[](
API_ARGS1
){
//录制mp4分片完毕事件
//录制mp4分片完毕事件
throw
SuccessException
();
});
});
api_regist1
(
"/index/hook/on_shell_login"
,[](
API_ARGS1
){
api_regist1
(
"/index/hook/on_shell_login"
,[](
API_ARGS1
){
//shell登录调试事件
//shell登录调试事件
throw
SuccessException
();
});
});
api_regist1
(
"/index/hook/on_stream_none_reader"
,[](
API_ARGS1
){
api_regist1
(
"/index/hook/on_stream_none_reader"
,[](
API_ARGS1
){
...
@@ -931,7 +936,6 @@ void installWebApi() {
...
@@ -931,7 +936,6 @@ void installWebApi() {
api_regist1
(
"/index/hook/on_server_started"
,[](
API_ARGS1
){
api_regist1
(
"/index/hook/on_server_started"
,[](
API_ARGS1
){
//服务器重启报告
//服务器重启报告
throw
SuccessException
();
});
});
...
...
src/Common/Device.cpp
查看文件 @
7805558d
...
@@ -8,13 +8,9 @@
...
@@ -8,13 +8,9 @@
* 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 <stdio.h>
#include <stdio.h>
#include "Device.h"
#include "Device.h"
#include "Util/logger.h"
#include "Util/logger.h"
#include "Util/util.h"
#include "Util/base64.h"
#include "Util/base64.h"
#include "Util/TimeTicker.h"
#include "Extension/AAC.h"
#include "Extension/AAC.h"
#include "Extension/G711.h"
#include "Extension/G711.h"
#include "Extension/H264.h"
#include "Extension/H264.h"
...
@@ -24,15 +20,15 @@ using namespace toolkit;
...
@@ -24,15 +20,15 @@ using namespace toolkit;
namespace
mediakit
{
namespace
mediakit
{
DevChannel
::
DevChannel
(
const
string
&
strV
host
,
DevChannel
::
DevChannel
(
const
string
&
v
host
,
const
string
&
strA
pp
,
const
string
&
a
pp
,
const
string
&
str
I
d
,
const
string
&
str
eam_i
d
,
float
fD
uration
,
float
d
uration
,
bool
bEanbleR
tsp
,
bool
enable_r
tsp
,
bool
bEanbleR
tmp
,
bool
enable_r
tmp
,
bool
bEanbleH
ls
,
bool
enable_h
ls
,
bool
bEnableM
p4
)
:
bool
enable_m
p4
)
:
MultiMediaSourceMuxer
(
strVhost
,
strApp
,
strId
,
fDuration
,
bEanbleRtsp
,
bEanbleRtmp
,
bEanbleHls
,
bEnableM
p4
)
{}
MultiMediaSourceMuxer
(
vhost
,
app
,
stream_id
,
duration
,
enable_rtsp
,
enable_rtmp
,
enable_hls
,
enable_m
p4
)
{}
DevChannel
::~
DevChannel
()
{}
DevChannel
::~
DevChannel
()
{}
...
@@ -68,14 +64,14 @@ void DevChannel::inputPCM(char* pcData, int iDataLen, uint32_t uiStamp) {
...
@@ -68,14 +64,14 @@ void DevChannel::inputPCM(char* pcData, int iDataLen, uint32_t uiStamp) {
if
(
_pAacEnc
)
{
if
(
_pAacEnc
)
{
unsigned
char
*
pucOut
;
unsigned
char
*
pucOut
;
int
iRet
=
_pAacEnc
->
inputData
(
pcData
,
iDataLen
,
&
pucOut
);
int
iRet
=
_pAacEnc
->
inputData
(
pcData
,
iDataLen
,
&
pucOut
);
if
(
iRet
>
0
)
{
if
(
iRet
>
7
)
{
inputAAC
((
char
*
)
pucOut
,
iRet
,
uiStamp
);
inputAAC
((
char
*
)
pucOut
+
7
,
iRet
-
7
,
uiStamp
,
(
char
*
)
pucOut
);
}
}
}
}
}
}
#endif //ENABLE_FAAC
#endif //ENABLE_FAAC
void
DevChannel
::
inputH264
(
const
char
*
pcData
,
int
iDataLen
,
uint32_t
dts
,
uint32_t
pts
)
{
void
DevChannel
::
inputH264
(
const
char
*
data
,
int
len
,
uint32_t
dts
,
uint32_t
pts
)
{
if
(
dts
==
0
){
if
(
dts
==
0
){
dts
=
(
uint32_t
)
_aTicker
[
0
].
elapsedTime
();
dts
=
(
uint32_t
)
_aTicker
[
0
].
elapsedTime
();
}
}
...
@@ -83,24 +79,27 @@ void DevChannel::inputH264(const char* pcData, int iDataLen, uint32_t dts,uint32
...
@@ -83,24 +79,27 @@ void DevChannel::inputH264(const char* pcData, int iDataLen, uint32_t dts,uint32
pts
=
dts
;
pts
=
dts
;
}
}
int
prefixeSize
;
int
prefixeSize
;
if
(
memcmp
(
"
\x00\x00\x00\x01
"
,
pcD
ata
,
4
)
==
0
)
{
if
(
memcmp
(
"
\x00\x00\x00\x01
"
,
d
ata
,
4
)
==
0
)
{
prefixeSize
=
4
;
prefixeSize
=
4
;
}
else
if
(
memcmp
(
"
\x00\x00\x01
"
,
pcD
ata
,
3
)
==
0
)
{
}
else
if
(
memcmp
(
"
\x00\x00\x01
"
,
d
ata
,
3
)
==
0
)
{
prefixeSize
=
3
;
prefixeSize
=
3
;
}
else
{
}
else
{
prefixeSize
=
0
;
prefixeSize
=
0
;
}
}
//由于rtmp/hls/mp4需要缓存时间戳相同的帧,
//所以使用FrameNoCacheAble类型的帧反而会在转换成FrameCacheAble时多次内存拷贝
//在此处只拷贝一次,性能开销更低
H264Frame
::
Ptr
frame
=
std
::
make_shared
<
H264Frame
>
();
H264Frame
::
Ptr
frame
=
std
::
make_shared
<
H264Frame
>
();
frame
->
_dts
=
dts
;
frame
->
_dts
=
dts
;
frame
->
_pts
=
pts
;
frame
->
_pts
=
pts
;
frame
->
_buffer
.
assign
(
"
\x00\x00\x00\x01
"
,
4
);
frame
->
_buffer
.
assign
(
"
\x00\x00\x00\x01
"
,
4
);
frame
->
_buffer
.
append
(
pcData
+
prefixeSize
,
iDataL
en
-
prefixeSize
);
frame
->
_buffer
.
append
(
data
+
prefixeSize
,
l
en
-
prefixeSize
);
frame
->
_prefix_size
=
4
;
frame
->
_prefix_size
=
4
;
inputFrame
(
frame
);
inputFrame
(
frame
);
}
}
void
DevChannel
::
inputH265
(
const
char
*
pcData
,
int
iDataLen
,
uint32_t
dts
,
uint32_t
pts
)
{
void
DevChannel
::
inputH265
(
const
char
*
data
,
int
len
,
uint32_t
dts
,
uint32_t
pts
)
{
if
(
dts
==
0
){
if
(
dts
==
0
){
dts
=
(
uint32_t
)
_aTicker
[
0
].
elapsedTime
();
dts
=
(
uint32_t
)
_aTicker
[
0
].
elapsedTime
();
}
}
...
@@ -108,98 +107,81 @@ void DevChannel::inputH265(const char* pcData, int iDataLen, uint32_t dts,uint32
...
@@ -108,98 +107,81 @@ void DevChannel::inputH265(const char* pcData, int iDataLen, uint32_t dts,uint32
pts
=
dts
;
pts
=
dts
;
}
}
int
prefixeSize
;
int
prefixeSize
;
if
(
memcmp
(
"
\x00\x00\x00\x01
"
,
pcD
ata
,
4
)
==
0
)
{
if
(
memcmp
(
"
\x00\x00\x00\x01
"
,
d
ata
,
4
)
==
0
)
{
prefixeSize
=
4
;
prefixeSize
=
4
;
}
else
if
(
memcmp
(
"
\x00\x00\x01
"
,
pcD
ata
,
3
)
==
0
)
{
}
else
if
(
memcmp
(
"
\x00\x00\x01
"
,
d
ata
,
3
)
==
0
)
{
prefixeSize
=
3
;
prefixeSize
=
3
;
}
else
{
}
else
{
prefixeSize
=
0
;
prefixeSize
=
0
;
}
}
//由于rtmp/hls/mp4需要缓存时间戳相同的帧,
//所以使用FrameNoCacheAble类型的帧反而会在转换成FrameCacheAble时多次内存拷贝
//在此处只拷贝一次,性能开销更低
H265Frame
::
Ptr
frame
=
std
::
make_shared
<
H265Frame
>
();
H265Frame
::
Ptr
frame
=
std
::
make_shared
<
H265Frame
>
();
frame
->
_dts
=
dts
;
frame
->
_dts
=
dts
;
frame
->
_pts
=
pts
;
frame
->
_pts
=
pts
;
frame
->
_buffer
.
assign
(
"
\x00\x00\x00\x01
"
,
4
);
frame
->
_buffer
.
assign
(
"
\x00\x00\x00\x01
"
,
4
);
frame
->
_buffer
.
append
(
pcData
+
prefixeSize
,
iDataL
en
-
prefixeSize
);
frame
->
_buffer
.
append
(
data
+
prefixeSize
,
l
en
-
prefixeSize
);
frame
->
_prefix_size
=
4
;
frame
->
_prefix_size
=
4
;
inputFrame
(
frame
);
inputFrame
(
frame
);
}
}
void
DevChannel
::
inputAAC
(
const
char
*
pcData
,
int
iDataLen
,
uint32_t
uiStamp
,
bool
withAdtsHeader
)
{
class
AACFrameCacheAble
:
public
AACFrameNoCacheAble
{
if
(
withAdtsHeader
){
public
:
inputAAC
(
pcData
+
7
,
iDataLen
-
7
,
uiStamp
,
pcData
);
template
<
typename
...
ARGS
>
}
else
if
(
_audio
)
{
AACFrameCacheAble
(
ARGS
&&
...
args
)
:
AACFrameNoCacheAble
(
std
::
forward
<
ARGS
>
(
args
)...){};
inputAAC
(
pcData
,
iDataLen
,
uiStamp
,(
char
*
)
_adtsHeader
);
virtual
~
AACFrameCacheAble
()
{
}
delete
[]
_ptr
;
}
};
void
DevChannel
::
inputAAC
(
const
char
*
pcDataWithoutAdts
,
int
iDataLen
,
uint32_t
uiStamp
,
const
char
*
pcAdtsHeader
){
bool
cacheAble
()
const
override
{
if
(
uiStamp
==
0
){
return
true
;
uiStamp
=
(
uint32_t
)
_aTicker
[
1
].
elapsedTime
();
}
}
if
(
pcAdtsHeader
+
7
==
pcDataWithoutAdts
){
};
inputFrame
(
std
::
make_shared
<
AACFrameNoCacheAble
>
((
char
*
)
pcDataWithoutAdts
-
7
,
iDataLen
+
7
,
uiStamp
,
0
,
7
));
}
else
{
char
*
dataWithAdts
=
new
char
[
iDataLen
+
7
];
memcpy
(
dataWithAdts
,
pcAdtsHeader
,
7
);
memcpy
(
dataWithAdts
+
7
,
pcDataWithoutAdts
,
iDataLen
);
inputFrame
(
std
::
make_shared
<
AACFrameNoCacheAble
>
(
dataWithAdts
,
iDataLen
+
7
,
uiStamp
,
0
,
7
));
delete
[]
dataWithAdts
;
}
}
void
DevChannel
::
inputAAC
(
const
char
*
data_without_adts
,
int
len
,
uint32_t
dts
,
const
char
*
adts_header
){
if
(
dts
==
0
){
dts
=
(
uint32_t
)
_aTicker
[
1
].
elapsedTime
();
}
void
DevChannel
::
inputG711
(
const
char
*
pcData
,
int
iDataLen
,
uint32_t
uiStamp
)
if
(
adts_header
){
{
if
(
adts_header
+
7
==
data_without_adts
){
if
(
uiStamp
==
0
)
{
//adts头和帧在一起
uiStamp
=
(
uint32_t
)
_aTicker
[
1
].
elapsedTime
();
inputFrame
(
std
::
make_shared
<
AACFrameNoCacheAble
>
((
char
*
)
data_without_adts
-
7
,
len
+
7
,
dts
,
0
,
7
));
}
else
{
//adts头和帧不在一起
char
*
dataWithAdts
=
new
char
[
len
+
7
];
memcpy
(
dataWithAdts
,
adts_header
,
7
);
memcpy
(
dataWithAdts
+
7
,
data_without_adts
,
len
);
inputFrame
(
std
::
make_shared
<
AACFrameCacheAble
>
(
dataWithAdts
,
len
+
7
,
dts
,
0
,
7
));
}
}
}
inputFrame
(
std
::
make_shared
<
G711FrameNoCacheAble
>
(
_audio
->
codecId
,
(
char
*
)
pcData
,
iDataLen
,
uiStamp
,
0
));
}
}
void
DevChannel
::
initVideo
(
const
VideoInfo
&
info
)
{
void
DevChannel
::
inputG711
(
const
char
*
data
,
int
len
,
uint32_t
dts
){
_video
=
std
::
make_shared
<
VideoInfo
>
(
info
);
if
(
dts
==
0
)
{
addTrack
(
std
::
make_shared
<
H264Track
>
());
dts
=
(
uint32_t
)
_aTicker
[
1
].
elapsedTime
();
}
inputFrame
(
std
::
make_shared
<
G711FrameNoCacheAble
>
(
_audio
->
codecId
,
(
char
*
)
data
,
len
,
dts
,
0
));
}
}
void
DevChannel
::
init
H265Video
(
const
VideoInfo
&
info
)
{
void
DevChannel
::
init
Video
(
const
VideoInfo
&
info
)
{
_video
=
std
::
make_shared
<
VideoInfo
>
(
info
);
_video
=
std
::
make_shared
<
VideoInfo
>
(
info
);
addTrack
(
std
::
make_shared
<
H265Track
>
());
switch
(
info
.
codecId
){
case
CodecH265
:
addTrack
(
std
::
make_shared
<
H265Track
>
());
break
;
case
CodecH264
:
addTrack
(
std
::
make_shared
<
H264Track
>
());
break
;
default
:
WarnL
<<
"不支持该类型的视频编码类型:"
<<
info
.
codecId
;
break
;
}
}
}
void
DevChannel
::
initAudio
(
const
AudioInfo
&
info
)
{
void
DevChannel
::
initAudio
(
const
AudioInfo
&
info
)
{
_audio
=
std
::
make_shared
<
AudioInfo
>
(
info
);
_audio
=
std
::
make_shared
<
AudioInfo
>
(
info
);
if
(
info
.
codecId
==
CodecAAC
)
switch
(
info
.
codecId
)
{
{
case
CodecAAC
:
addTrack
(
std
::
make_shared
<
AACTrack
>
());
break
;
addTrack
(
std
::
make_shared
<
AACTrack
>
());
case
CodecG711A
:
case
CodecG711U
:
addTrack
(
std
::
make_shared
<
G711Track
>
(
info
.
codecId
,
info
.
iSampleRate
,
info
.
iChannel
,
info
.
iSampleBit
));
break
;
AACFrame
adtsHeader
;
default
:
WarnL
<<
"不支持该类型的音频编码类型:"
<<
info
.
codecId
;
break
;
adtsHeader
.
syncword
=
0x0FFF
;
adtsHeader
.
id
=
0
;
adtsHeader
.
layer
=
0
;
adtsHeader
.
protection_absent
=
1
;
adtsHeader
.
profile
=
info
.
iProfile
;
//audioObjectType - 1;
int
i
=
0
;
for
(
auto
rate
:
samplingFrequencyTable
)
{
if
(
rate
==
info
.
iSampleRate
)
{
adtsHeader
.
sf_index
=
i
;
};
++
i
;
}
adtsHeader
.
private_bit
=
0
;
adtsHeader
.
channel_configuration
=
info
.
iChannel
;
adtsHeader
.
original
=
0
;
adtsHeader
.
home
=
0
;
adtsHeader
.
copyright_identification_bit
=
0
;
adtsHeader
.
copyright_identification_start
=
0
;
adtsHeader
.
aac_frame_length
=
7
;
adtsHeader
.
adts_buffer_fullness
=
2047
;
adtsHeader
.
no_raw_data_blocks_in_frame
=
0
;
writeAdtsHeader
(
adtsHeader
,
_adtsHeader
);
}
else
if
(
info
.
codecId
==
CodecG711A
||
info
.
codecId
==
CodecG711U
)
{
addTrack
(
std
::
make_shared
<
G711Track
>
(
info
.
codecId
,
info
.
iSampleBit
,
info
.
iSampleRate
));
}
}
}
}
...
...
src/Common/Device.h
查看文件 @
7805558d
...
@@ -30,105 +30,91 @@ using namespace toolkit;
...
@@ -30,105 +30,91 @@ using namespace toolkit;
#include "Codec/H264Encoder.h"
#include "Codec/H264Encoder.h"
#endif //ENABLE_X264
#endif //ENABLE_X264
namespace
mediakit
{
namespace
mediakit
{
class
VideoInfo
{
class
VideoInfo
{
public
:
public
:
CodecId
codecId
=
CodecH264
;
int
iWidth
;
int
iWidth
;
int
iHeight
;
int
iHeight
;
float
iFrameRate
;
float
iFrameRate
;
};
};
class
AudioInfo
{
class
AudioInfo
{
public
:
public
:
CodecId
codecId
;
CodecId
codecId
=
CodecAAC
;
int
iChannel
;
int
iChannel
;
int
iSampleBit
;
int
iSampleBit
;
int
iSampleRate
;
int
iSampleRate
;
int
iProfile
;
};
};
/**
/**
*
该类已经废弃,保留只为兼容旧代码,请直接使用MultiMediaSourceMuxer类!
*
MultiMediaSourceMuxer类的包装,方便初学者使用
*/
*/
class
DevChannel
:
public
MultiMediaSourceMuxer
{
class
DevChannel
:
public
MultiMediaSourceMuxer
{
public
:
public
:
typedef
std
::
shared_ptr
<
DevChannel
>
Ptr
;
typedef
std
::
shared_ptr
<
DevChannel
>
Ptr
;
//fDuration<=0为直播,否则为点播
//fDuration<=0为直播,否则为点播
DevChannel
(
const
string
&
strV
host
,
DevChannel
(
const
string
&
v
host
,
const
string
&
strA
pp
,
const
string
&
a
pp
,
const
string
&
str
I
d
,
const
string
&
str
eam_i
d
,
float
fD
uration
=
0
,
float
d
uration
=
0
,
bool
bEanbleR
tsp
=
true
,
bool
enable_r
tsp
=
true
,
bool
bEanbleR
tmp
=
true
,
bool
enable_r
tmp
=
true
,
bool
bEanbleH
ls
=
true
,
bool
enable_h
ls
=
true
,
bool
bEnableM
p4
=
false
);
bool
enable_m
p4
=
false
);
virtual
~
DevChannel
();
virtual
~
DevChannel
();
/**
/**
* 初始化
h264
视频Track
* 初始化视频Track
* 相当于MultiMediaSourceMuxer::addTrack(
H264
Track::Ptr );
* 相当于MultiMediaSourceMuxer::addTrack(
Video
Track::Ptr );
* @param info
* @param info
视频相关信息
*/
*/
void
initVideo
(
const
VideoInfo
&
info
);
void
initVideo
(
const
VideoInfo
&
info
);
/**
/**
* 初始化h265视频Track
* 初始化音频Track
* @param info
* 相当于MultiMediaSourceMuxer::addTrack(AudioTrack::Ptr );
*/
* @param info 音频相关信息
void
initH265Video
(
const
VideoInfo
&
info
);
/**
* 初始化aac音频Track
* 相当于MultiMediaSourceMuxer::addTrack(AACTrack::Ptr );
* @param info
*/
*/
void
initAudio
(
const
AudioInfo
&
info
);
void
initAudio
(
const
AudioInfo
&
info
);
/**
/**
* 输入264帧
* 输入264帧
* @param
pcD
ata 264单帧数据指针
* @param
d
ata 264单帧数据指针
* @param
iDataL
en 数据指针长度
* @param
l
en 数据指针长度
* @param dts 解码时间戳,单位毫秒;等于0时内部会自动生成时间戳
* @param dts 解码时间戳,单位毫秒;等于0时内部会自动生成时间戳
* @param pts 播放时间戳,单位毫秒;等于0时内部会赋值为dts
* @param pts 播放时间戳,单位毫秒;等于0时内部会赋值为dts
*/
*/
void
inputH264
(
const
char
*
pcData
,
int
iDataLen
,
uint32_t
dts
,
uint32_t
pts
=
0
);
void
inputH264
(
const
char
*
data
,
int
len
,
uint32_t
dts
,
uint32_t
pts
=
0
);
/**
/**
* 输入265帧
* 输入265帧
* @param
pcD
ata 265单帧数据指针
* @param
d
ata 265单帧数据指针
* @param
iDataL
en 数据指针长度
* @param
l
en 数据指针长度
* @param dts 解码时间戳,单位毫秒;等于0时内部会自动生成时间戳
* @param dts 解码时间戳,单位毫秒;等于0时内部会自动生成时间戳
* @param pts 播放时间戳,单位毫秒;等于0时内部会赋值为dts
* @param pts 播放时间戳,单位毫秒;等于0时内部会赋值为dts
*/
*/
void
inputH265
(
const
char
*
pcData
,
int
iDataLen
,
uint32_t
dts
,
uint32_t
pts
=
0
);
void
inputH265
(
const
char
*
data
,
int
len
,
uint32_t
dts
,
uint32_t
pts
=
0
);
/**
/**
* 输入
可能带adts头的
aac帧
* 输入aac帧
* @param
pcDataWithAdts 可能
带adts头的aac帧
* @param
data_without_adts 不
带adts头的aac帧
* @param
iDataL
en 帧数据长度
* @param
l
en 帧数据长度
* @param
uiStamp 时间戳,单位毫秒,等于0时内部会自动生成时间戳
* @param
dts 时间戳,单位毫秒
* @param
withAdtsHeader 是否带
adts头
* @param
adts_header
adts头
*/
*/
void
inputAAC
(
const
char
*
pcDataWithAdts
,
int
iDataLen
,
uint32_t
uiStamp
,
bool
withAdtsHeader
=
true
);
void
inputAAC
(
const
char
*
data_without_adts
,
int
len
,
uint32_t
dts
,
const
char
*
adts_header
);
/**
* 输入不带adts头的aac帧
* @param pcDataWithoutAdts 不带adts头的aac帧
* @param iDataLen 帧数据长度
* @param uiStamp 时间戳,单位毫秒
* @param pcAdtsHeader adts头
*/
void
inputAAC
(
const
char
*
pcDataWithoutAdts
,
int
iDataLen
,
uint32_t
uiStamp
,
const
char
*
pcAdtsHeader
);
/**
/**
* G711音频帧
* G711音频帧
* @param
pcD
ata 音频帧
* @param
d
ata 音频帧
* @param
iDataL
en 帧数据长度
* @param
l
en 帧数据长度
* @param
uiStamp
时间戳,单位毫秒
* @param
dts
时间戳,单位毫秒
*/
*/
void
inputG711
(
const
char
*
pcData
,
int
iDataLen
,
uint32_t
uiStamp
);
void
inputG711
(
const
char
*
data
,
int
len
,
uint32_t
dts
);
#ifdef ENABLE_X264
#ifdef ENABLE_X264
/**
/**
* 输入yuv420p视频帧,内部会完成编码并调用inputH264方法
* 输入yuv420p视频帧,内部会完成编码并调用inputH264方法
...
@@ -151,6 +137,7 @@ public:
...
@@ -151,6 +137,7 @@ public:
#endif //ENABLE_FAAC
#endif //ENABLE_FAAC
private
:
private
:
#ifdef ENABLE_X264
#ifdef ENABLE_X264
std
::
shared_ptr
<
H264Encoder
>
_pH264Enc
;
std
::
shared_ptr
<
H264Encoder
>
_pH264Enc
;
#endif //ENABLE_X264
#endif //ENABLE_X264
...
@@ -160,9 +147,7 @@ private:
...
@@ -160,9 +147,7 @@ private:
#endif //ENABLE_FAAC
#endif //ENABLE_FAAC
std
::
shared_ptr
<
VideoInfo
>
_video
;
std
::
shared_ptr
<
VideoInfo
>
_video
;
std
::
shared_ptr
<
AudioInfo
>
_audio
;
std
::
shared_ptr
<
AudioInfo
>
_audio
;
SmoothTicker
_aTicker
[
2
];
SmoothTicker
_aTicker
[
2
];
uint8_t
_adtsHeader
[
7
];
};
};
}
/* namespace mediakit */
}
/* namespace mediakit */
...
...
src/Common/MediaSink.cpp
查看文件 @
7805558d
...
@@ -34,23 +34,16 @@ void MediaSink::addTrack(const Track::Ptr &track_in) {
...
@@ -34,23 +34,16 @@ void MediaSink::addTrack(const Track::Ptr &track_in) {
track
->
addDelegate
(
std
::
make_shared
<
FrameWriterInterfaceHelper
>
([
this
](
const
Frame
::
Ptr
&
frame
)
{
track
->
addDelegate
(
std
::
make_shared
<
FrameWriterInterfaceHelper
>
([
this
](
const
Frame
::
Ptr
&
frame
)
{
if
(
_allTrackReady
)
{
if
(
_allTrackReady
)
{
onTrackFrame
(
frame
);
onTrackFrame
(
frame
);
return
;
}
}
else
{
if
(
frame
->
getTrackType
()
==
TrackVideo
)
{
checkTrackIfReady
(
nullptr
);
//还有track未准备好,如果是视频的话,如果直接丢帧可能导致丢失I帧
checkTrackIfReady
(
nullptr
);
if
(
_allTrackReady
)
{
if
(
_allTrackReady
)
{
//运行至这里说明Track状态由未就绪切换为已就绪状态,那么这帧就不应该丢弃
onTrackFrame
(
frame
);
onTrackFrame
(
frame
);
}
}
else
if
(
frame
->
keyFrame
()){
else
WarnL
<<
"some track is unready,drop key frame of: "
<<
frame
->
getCodecName
();
{
ErrorL
<<
" 还有track未准备好,丢帧 codecName: "
<<
frame
->
getCodecName
();
}
}
else
ErrorL
<<
" 还有track未准备好,丢帧 codecName: "
<<
frame
->
getCodecName
();
}
}
}));
}));
}
}
...
@@ -70,8 +63,8 @@ void MediaSink::inputFrame(const Frame::Ptr &frame) {
...
@@ -70,8 +63,8 @@ void MediaSink::inputFrame(const Frame::Ptr &frame) {
if
(
it
==
_track_map
.
end
())
{
if
(
it
==
_track_map
.
end
())
{
return
;
return
;
}
}
it
->
second
->
inputFrame
(
frame
);
checkTrackIfReady
(
it
->
second
);
checkTrackIfReady
(
it
->
second
);
it
->
second
->
inputFrame
(
frame
);
}
}
void
MediaSink
::
checkTrackIfReady_l
(
const
Track
::
Ptr
&
track
){
void
MediaSink
::
checkTrackIfReady_l
(
const
Track
::
Ptr
&
track
){
...
@@ -140,7 +133,7 @@ void MediaSink::emitAllTrackReady() {
...
@@ -140,7 +133,7 @@ void MediaSink::emitAllTrackReady() {
//移除未准备好的Track
//移除未准备好的Track
for
(
auto
it
=
_track_map
.
begin
();
it
!=
_track_map
.
end
();)
{
for
(
auto
it
=
_track_map
.
begin
();
it
!=
_track_map
.
end
();)
{
if
(
!
it
->
second
->
ready
())
{
if
(
!
it
->
second
->
ready
())
{
WarnL
<<
"
该track长时间未被初始化,已忽略:
"
<<
it
->
second
->
getCodecName
();
WarnL
<<
"
track not ready for a long time, ignored:
"
<<
it
->
second
->
getCodecName
();
it
=
_track_map
.
erase
(
it
);
it
=
_track_map
.
erase
(
it
);
continue
;
continue
;
}
}
...
...
src/Common/MediaSource.cpp
查看文件 @
7805558d
...
@@ -450,4 +450,50 @@ MediaSource::Ptr MediaSource::createFromMP4(const string &schema, const string &
...
@@ -450,4 +450,50 @@ MediaSource::Ptr MediaSource::createFromMP4(const string &schema, const string &
#endif //ENABLE_MP4
#endif //ENABLE_MP4
}
}
static
bool
isFlushAble_default
(
bool
is_audio
,
uint32_t
last_stamp
,
uint32_t
new_stamp
,
int
cache_size
)
{
if
(
new_stamp
<
last_stamp
)
{
//时间戳回退(可能seek中)
return
true
;
}
if
(
!
is_audio
)
{
//这是视频,时间戳发送变化或者缓存超过1024个
return
last_stamp
!=
new_stamp
||
cache_size
>=
1024
;
}
//这是音频,缓存超过100ms或者缓存个数超过10个
return
new_stamp
>
last_stamp
+
100
||
cache_size
>
10
;
}
static
bool
isFlushAble_merge
(
bool
is_audio
,
uint32_t
last_stamp
,
uint32_t
new_stamp
,
int
cache_size
,
int
merge_ms
)
{
if
(
new_stamp
<
last_stamp
)
{
//时间戳回退(可能seek中)
return
true
;
}
if
(
new_stamp
>
last_stamp
+
merge_ms
){
//时间戳增量超过合并写阈值
return
true
;
}
if
(
!
is_audio
)
{
//这是视频,缓存数超过1024个,这个逻辑用于避免时间戳异常的流导致的内存暴增问题
//而且sendmsg接口一般最多只能发送1024个数据包
return
cache_size
>=
1024
;
}
//这是音频,音频缓存超过20个
return
cache_size
>
20
;
}
bool
FlushPolicy
::
isFlushAble
(
uint32_t
last_stamp
,
uint32_t
new_stamp
,
int
cache_size
)
{
GET_CONFIG
(
bool
,
ultraLowDelay
,
General
::
kUltraLowDelay
);
GET_CONFIG
(
int
,
mergeWriteMS
,
General
::
kMergeWriteMS
);
if
(
ultraLowDelay
||
mergeWriteMS
<=
0
){
//关闭了合并写或者合并写阈值小于等于0
return
isFlushAble_default
(
_is_audio
,
last_stamp
,
new_stamp
,
cache_size
);
}
return
isFlushAble_merge
(
_is_audio
,
last_stamp
,
new_stamp
,
cache_size
,
mergeWriteMS
);
}
}
/* namespace mediakit */
}
/* namespace mediakit */
\ No newline at end of file
src/Common/MediaSource.h
查看文件 @
7805558d
...
@@ -21,6 +21,9 @@
...
@@ -21,6 +21,9 @@
#include "Util/logger.h"
#include "Util/logger.h"
#include "Util/TimeTicker.h"
#include "Util/TimeTicker.h"
#include "Util/NoticeCenter.h"
#include "Util/NoticeCenter.h"
#include "Util/List.h"
#include "Rtsp/Rtsp.h"
#include "Rtmp/Rtmp.h"
#include "Extension/Track.h"
#include "Extension/Track.h"
#include "Record/Recorder.h"
#include "Record/Recorder.h"
...
@@ -153,6 +156,114 @@ private:
...
@@ -153,6 +156,114 @@ private:
static
recursive_mutex
g_mtxMediaSrc
;
static
recursive_mutex
g_mtxMediaSrc
;
};
};
///缓存刷新策略类
class
FlushPolicy
{
public
:
FlushPolicy
(
bool
is_audio
)
{
_is_audio
=
is_audio
;
};
~
FlushPolicy
()
=
default
;
uint32_t
getStamp
(
const
RtpPacket
::
Ptr
&
packet
)
{
return
packet
->
timeStamp
;
}
uint32_t
getStamp
(
const
RtmpPacket
::
Ptr
&
packet
)
{
return
packet
->
timeStamp
;
}
bool
isFlushAble
(
uint32_t
last_stamp
,
uint32_t
new_stamp
,
int
cache_size
);
private
:
bool
_is_audio
;
};
/// 视频合并写缓存模板
/// \tparam packet 包类型
/// \tparam policy 刷新缓存策略
/// \tparam packet_list 包缓存类型
template
<
typename
packet
,
typename
policy
=
FlushPolicy
,
typename
packet_list
=
List
<
std
::
shared_ptr
<
packet
>
>
>
class
VideoPacketCache
{
public
:
VideoPacketCache
()
:
_policy
(
true
)
{
_cache
=
std
::
make_shared
<
packet_list
>
();
}
virtual
~
VideoPacketCache
()
=
default
;
void
inputVideo
(
const
std
::
shared_ptr
<
packet
>
&
rtp
,
bool
key_pos
)
{
auto
new_stamp
=
_policy
.
getStamp
(
rtp
);
if
(
_policy
.
isFlushAble
(
_last_stamp
,
new_stamp
,
_cache
->
size
()))
{
flushAll
();
}
//追加数据到最后
_cache
->
emplace_back
(
rtp
);
_last_stamp
=
new_stamp
;
if
(
key_pos
)
{
_key_pos
=
key_pos
;
}
}
virtual
void
onFlushVideo
(
std
::
shared_ptr
<
packet_list
>
&
,
bool
key_pos
)
=
0
;
private
:
void
flushAll
()
{
if
(
_cache
->
empty
())
{
return
;
}
onFlushVideo
(
_cache
,
_key_pos
);
_cache
=
std
::
make_shared
<
packet_list
>
();
_key_pos
=
false
;
}
private
:
policy
_policy
;
std
::
shared_ptr
<
packet_list
>
_cache
;
uint32_t
_last_stamp
=
0
;
bool
_key_pos
=
false
;
};
/// 音频频合并写缓存模板
/// \tparam packet 包类型
/// \tparam policy 刷新缓存策略
/// \tparam packet_list 包缓存类型
template
<
typename
packet
,
typename
policy
=
FlushPolicy
,
typename
packet_list
=
List
<
std
::
shared_ptr
<
packet
>
>
>
class
AudioPacketCache
{
public
:
AudioPacketCache
()
:
_policy
(
false
)
{
_cache
=
std
::
make_shared
<
packet_list
>
();
}
virtual
~
AudioPacketCache
()
=
default
;
void
inputAudio
(
const
std
::
shared_ptr
<
packet
>
&
rtp
)
{
auto
new_stamp
=
_policy
.
getStamp
(
rtp
);
if
(
_policy
.
isFlushAble
(
_last_stamp
,
new_stamp
,
_cache
->
size
()))
{
flushAll
();
}
//追加数据到最后
_cache
->
emplace_back
(
rtp
);
_last_stamp
=
new_stamp
;
}
virtual
void
onFlushAudio
(
std
::
shared_ptr
<
packet_list
>
&
)
=
0
;
private
:
void
flushAll
()
{
if
(
_cache
->
empty
())
{
return
;
}
onFlushAudio
(
_cache
);
_cache
=
std
::
make_shared
<
packet_list
>
();
}
private
:
policy
_policy
;
std
::
shared_ptr
<
packet_list
>
_cache
;
uint32_t
_last_stamp
=
0
;
};
}
/* namespace mediakit */
}
/* namespace mediakit */
...
...
src/Common/config.cpp
查看文件 @
7805558d
...
@@ -67,6 +67,7 @@ const string kResetWhenRePlay = GENERAL_FIELD"resetWhenRePlay";
...
@@ -67,6 +67,7 @@ const string kResetWhenRePlay = GENERAL_FIELD"resetWhenRePlay";
const
string
kPublishToRtxp
=
GENERAL_FIELD
"publishToRtxp"
;
const
string
kPublishToRtxp
=
GENERAL_FIELD
"publishToRtxp"
;
const
string
kPublishToHls
=
GENERAL_FIELD
"publishToHls"
;
const
string
kPublishToHls
=
GENERAL_FIELD
"publishToHls"
;
const
string
kPublishToMP4
=
GENERAL_FIELD
"publishToMP4"
;
const
string
kPublishToMP4
=
GENERAL_FIELD
"publishToMP4"
;
const
string
kMergeWriteMS
=
GENERAL_FIELD
"mergeWriteMS"
;
onceToken
token
([](){
onceToken
token
([](){
mINI
::
Instance
()[
kFlowThreshold
]
=
1024
;
mINI
::
Instance
()[
kFlowThreshold
]
=
1024
;
...
@@ -79,6 +80,7 @@ onceToken token([](){
...
@@ -79,6 +80,7 @@ onceToken token([](){
mINI
::
Instance
()[
kPublishToRtxp
]
=
1
;
mINI
::
Instance
()[
kPublishToRtxp
]
=
1
;
mINI
::
Instance
()[
kPublishToHls
]
=
1
;
mINI
::
Instance
()[
kPublishToHls
]
=
1
;
mINI
::
Instance
()[
kPublishToMP4
]
=
0
;
mINI
::
Instance
()[
kPublishToMP4
]
=
0
;
mINI
::
Instance
()[
kMergeWriteMS
]
=
300
;
},
nullptr
);
},
nullptr
);
}
//namespace General
}
//namespace General
...
@@ -286,6 +288,8 @@ const string kTimeoutMS = "protocol_timeout_ms";
...
@@ -286,6 +288,8 @@ const string kTimeoutMS = "protocol_timeout_ms";
const
string
kMediaTimeoutMS
=
"media_timeout_ms"
;
const
string
kMediaTimeoutMS
=
"media_timeout_ms"
;
const
string
kBeatIntervalMS
=
"beat_interval_ms"
;
const
string
kBeatIntervalMS
=
"beat_interval_ms"
;
const
string
kMaxAnalysisMS
=
"max_analysis_ms"
;
const
string
kMaxAnalysisMS
=
"max_analysis_ms"
;
const
string
kBenchmarkMode
=
"benchmark_mode"
;
}
}
}
// namespace mediakit
}
// namespace mediakit
...
...
src/Common/config.h
查看文件 @
7805558d
...
@@ -173,6 +173,9 @@ extern const string kPublishToRtxp ;
...
@@ -173,6 +173,9 @@ extern const string kPublishToRtxp ;
extern
const
string
kPublishToHls
;
extern
const
string
kPublishToHls
;
//是否默认推流时mp4录像,hook接口(on_publish)中可以覆盖该设置
//是否默认推流时mp4录像,hook接口(on_publish)中可以覆盖该设置
extern
const
string
kPublishToMP4
;
extern
const
string
kPublishToMP4
;
//合并写缓存大小(单位毫秒),合并写指服务器缓存一定的数据后才会一次性写入socket,这样能提高性能,但是会提高延时
//在开启低延时模式后,该参数不起作用
extern
const
string
kMergeWriteMS
;
}
//namespace General
}
//namespace General
...
@@ -315,6 +318,8 @@ extern const string kMediaTimeoutMS;
...
@@ -315,6 +318,8 @@ extern const string kMediaTimeoutMS;
extern
const
string
kBeatIntervalMS
;
extern
const
string
kBeatIntervalMS
;
//Track编码格式探测最大时间,单位毫秒,默认2000
//Track编码格式探测最大时间,单位毫秒,默认2000
extern
const
string
kMaxAnalysisMS
;
extern
const
string
kMaxAnalysisMS
;
//是否为性能测试模式,性能测试模式开启后不会解析rtp或rtmp包
extern
const
string
kBenchmarkMode
;
}
}
}
// namespace mediakit
}
// namespace mediakit
...
...
src/Extension/AAC.cpp
查看文件 @
7805558d
...
@@ -98,10 +98,9 @@ void getAACInfo(const AACFrame &adts,int &iSampleRate,int &iChannel){
...
@@ -98,10 +98,9 @@ void getAACInfo(const AACFrame &adts,int &iSampleRate,int &iChannel){
iChannel
=
adts
.
channel_configuration
;
iChannel
=
adts
.
channel_configuration
;
}
}
Sdp
::
Ptr
AACTrack
::
getSdp
()
{
Sdp
::
Ptr
AACTrack
::
getSdp
()
{
if
(
!
ready
()){
if
(
!
ready
()){
WarnL
<<
"AAC
Track未准备好"
;
WarnL
<<
getCodecName
()
<<
"
Track未准备好"
;
return
nullptr
;
return
nullptr
;
}
}
return
std
::
make_shared
<
AACSdp
>
(
getAacCfg
(),
getAudioSampleRate
());
return
std
::
make_shared
<
AACSdp
>
(
getAacCfg
(),
getAudioSampleRate
());
...
...
src/Extension/AACRtmp.cpp
查看文件 @
7805558d
...
@@ -102,10 +102,12 @@ void AACRtmpEncoder::inputFrame(const Frame::Ptr &frame) {
...
@@ -102,10 +102,12 @@ void AACRtmpEncoder::inputFrame(const Frame::Ptr &frame) {
RtmpPacket
::
Ptr
rtmpPkt
=
ResourcePoolHelper
<
RtmpPacket
>::
obtainObj
();
RtmpPacket
::
Ptr
rtmpPkt
=
ResourcePoolHelper
<
RtmpPacket
>::
obtainObj
();
rtmpPkt
->
strBuf
.
clear
();
rtmpPkt
->
strBuf
.
clear
();
//
////////
header
//header
uint8_t
is_config
=
false
;
uint8_t
is_config
=
false
;
rtmpPkt
->
strBuf
.
push_back
(
_
ui8AudioF
lags
);
rtmpPkt
->
strBuf
.
push_back
(
_
audio_flv_f
lags
);
rtmpPkt
->
strBuf
.
push_back
(
!
is_config
);
rtmpPkt
->
strBuf
.
push_back
(
!
is_config
);
//aac data
rtmpPkt
->
strBuf
.
append
(
frame
->
data
()
+
frame
->
prefixSize
(),
frame
->
size
()
-
frame
->
prefixSize
());
rtmpPkt
->
strBuf
.
append
(
frame
->
data
()
+
frame
->
prefixSize
(),
frame
->
size
()
-
frame
->
prefixSize
());
rtmpPkt
->
bodySize
=
rtmpPkt
->
strBuf
.
size
();
rtmpPkt
->
bodySize
=
rtmpPkt
->
strBuf
.
size
();
...
@@ -115,45 +117,18 @@ void AACRtmpEncoder::inputFrame(const Frame::Ptr &frame) {
...
@@ -115,45 +117,18 @@ void AACRtmpEncoder::inputFrame(const Frame::Ptr &frame) {
rtmpPkt
->
typeId
=
MSG_AUDIO
;
rtmpPkt
->
typeId
=
MSG_AUDIO
;
RtmpCodec
::
inputRtmp
(
rtmpPkt
,
false
);
RtmpCodec
::
inputRtmp
(
rtmpPkt
,
false
);
}
}
}
}
void
AACRtmpEncoder
::
makeAudioConfigPkt
()
{
void
AACRtmpEncoder
::
makeAudioConfigPkt
()
{
makeAdtsHeader
(
_aac_cfg
,
*
_adts
);
_audio_flv_flags
=
getAudioRtmpFlags
(
std
::
make_shared
<
AACTrack
>
(
_aac_cfg
));
int
iSampleRate
,
iChannel
,
iSampleBit
=
16
;
getAACInfo
(
*
_adts
,
iSampleRate
,
iChannel
);
uint8_t
flvStereoOrMono
=
(
iChannel
>
1
);
uint8_t
flvSampleRate
;
switch
(
iSampleRate
)
{
case
48000
:
case
44100
:
flvSampleRate
=
3
;
break
;
case
24000
:
case
22050
:
flvSampleRate
=
2
;
break
;
case
12000
:
case
11025
:
flvSampleRate
=
1
;
break
;
default
:
flvSampleRate
=
0
;
break
;
}
uint8_t
flvSampleBit
=
iSampleBit
==
16
;
uint8_t
flvAudioType
=
FLV_CODEC_AAC
;
_ui8AudioFlags
=
(
flvAudioType
<<
4
)
|
(
flvSampleRate
<<
2
)
|
(
flvSampleBit
<<
1
)
|
flvStereoOrMono
;
RtmpPacket
::
Ptr
rtmpPkt
=
ResourcePoolHelper
<
RtmpPacket
>::
obtainObj
();
RtmpPacket
::
Ptr
rtmpPkt
=
ResourcePoolHelper
<
RtmpPacket
>::
obtainObj
();
rtmpPkt
->
strBuf
.
clear
();
rtmpPkt
->
strBuf
.
clear
();
//
////////
header
//header
uint8_t
is_config
=
true
;
uint8_t
is_config
=
true
;
rtmpPkt
->
strBuf
.
push_back
(
_
ui8AudioF
lags
);
rtmpPkt
->
strBuf
.
push_back
(
_
audio_flv_f
lags
);
rtmpPkt
->
strBuf
.
push_back
(
!
is_config
);
rtmpPkt
->
strBuf
.
push_back
(
!
is_config
);
//aac config
rtmpPkt
->
strBuf
.
append
(
_aac_cfg
);
rtmpPkt
->
strBuf
.
append
(
_aac_cfg
);
rtmpPkt
->
bodySize
=
rtmpPkt
->
strBuf
.
size
();
rtmpPkt
->
bodySize
=
rtmpPkt
->
strBuf
.
size
();
...
...
src/Extension/AACRtmp.h
查看文件 @
7805558d
...
@@ -79,7 +79,7 @@ public:
...
@@ -79,7 +79,7 @@ public:
private
:
private
:
void
makeAudioConfigPkt
();
void
makeAudioConfigPkt
();
private
:
private
:
uint8_t
_
ui8AudioF
lags
;
uint8_t
_
audio_flv_f
lags
;
AACTrack
::
Ptr
_track
;
AACTrack
::
Ptr
_track
;
};
};
...
...
src/Extension/Factory.cpp
查看文件 @
7805558d
...
@@ -48,11 +48,11 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) {
...
@@ -48,11 +48,11 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) {
}
}
if
(
strcasecmp
(
track
->
_codec
.
data
(),
"PCMA"
)
==
0
)
{
if
(
strcasecmp
(
track
->
_codec
.
data
(),
"PCMA"
)
==
0
)
{
return
std
::
make_shared
<
G711Track
>
(
CodecG711A
);
return
std
::
make_shared
<
G711Track
>
(
CodecG711A
,
track
->
_samplerate
,
track
->
_channel
,
16
);
}
}
if
(
strcasecmp
(
track
->
_codec
.
data
(),
"PCMU"
)
==
0
)
{
if
(
strcasecmp
(
track
->
_codec
.
data
(),
"PCMU"
)
==
0
)
{
return
std
::
make_shared
<
G711Track
>
(
CodecG711U
);
return
std
::
make_shared
<
G711Track
>
(
CodecG711U
,
track
->
_samplerate
,
track
->
_channel
,
16
);
}
}
if
(
strcasecmp
(
track
->
_codec
.
data
(),
"h264"
)
==
0
)
{
if
(
strcasecmp
(
track
->
_codec
.
data
(),
"h264"
)
==
0
)
{
...
@@ -84,34 +84,18 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) {
...
@@ -84,34 +84,18 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) {
return
std
::
make_shared
<
H265Track
>
(
vps
,
sps
,
pps
,
0
,
0
,
0
);
return
std
::
make_shared
<
H265Track
>
(
vps
,
sps
,
pps
,
0
,
0
,
0
);
}
}
//可以根据传统的payload type 获取编码类型以及采样率等信息
CodecId
codec_id
=
RtpPayload
::
getCodecId
(
track
->
_pt
);
switch
(
codec_id
){
case
CodecG711A
:
case
CodecG711U
:
return
std
::
make_shared
<
G711Track
>
(
codec_id
,
track
->
_samplerate
,
track
->
_channel
,
16
);
default
:
break
;
}
WarnL
<<
"暂不支持该sdp:"
<<
track
->
getName
();
WarnL
<<
"暂不支持该sdp:"
<<
track
->
getName
();
return
nullptr
;
return
nullptr
;
}
}
Track
::
Ptr
Factory
::
getTrackByCodecId
(
CodecId
codecId
)
{
switch
(
codecId
){
case
CodecH264
:{
return
std
::
make_shared
<
H264Track
>
();
}
case
CodecH265
:{
return
std
::
make_shared
<
H265Track
>
();
}
case
CodecAAC
:{
return
std
::
make_shared
<
AACTrack
>
();
}
case
CodecG711A
:
{
return
std
::
make_shared
<
G711Track
>
(
CodecG711A
);
}
case
CodecG711U
:
{
return
std
::
make_shared
<
G711Track
>
(
CodecG711U
);
}
default
:
WarnL
<<
"暂不支持该CodecId:"
<<
codecId
;
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
);
...
@@ -135,59 +119,29 @@ RtpCodec::Ptr Factory::getRtpEncoderBySdp(const Sdp::Ptr &sdp) {
...
@@ -135,59 +119,29 @@ RtpCodec::Ptr Factory::getRtpEncoderBySdp(const Sdp::Ptr &sdp) {
auto
interleaved
=
sdp
->
getTrackType
()
*
2
;
auto
interleaved
=
sdp
->
getTrackType
()
*
2
;
auto
codec_id
=
sdp
->
getCodecId
();
auto
codec_id
=
sdp
->
getCodecId
();
switch
(
codec_id
){
switch
(
codec_id
){
case
CodecH264
:
case
CodecH264
:
return
std
::
make_shared
<
H264RtpEncoder
>
(
ssrc
,
mtu
,
sample_rate
,
pt
,
interleaved
);
return
std
::
make_shared
<
H264RtpEncoder
>
(
ssrc
,
mtu
,
sample_rate
,
pt
,
interleaved
);
case
CodecH265
:
return
std
::
make_shared
<
H265RtpEncoder
>
(
ssrc
,
mtu
,
sample_rate
,
pt
,
interleaved
);
case
CodecH265
:
case
CodecAAC
:
return
std
::
make_shared
<
AACRtpEncoder
>
(
ssrc
,
mtu
,
sample_rate
,
pt
,
interleaved
);
return
std
::
make_shared
<
H265RtpEncoder
>
(
ssrc
,
mtu
,
sample_rate
,
pt
,
interleaved
);
case
CodecG711A
:
case
CodecAAC
:
case
CodecG711U
:
return
std
::
make_shared
<
G711RtpEncoder
>
(
ssrc
,
mtu
,
sample_rate
,
pt
,
interleaved
);
return
std
::
make_shared
<
AACRtpEncoder
>
(
ssrc
,
mtu
,
sample_rate
,
pt
,
interleaved
);
default
:
WarnL
<<
"暂不支持该CodecId:"
<<
codec_id
;
return
nullptr
;
case
CodecG711A
:
case
CodecG711U
:
return
std
::
make_shared
<
G711RtpEncoder
>
(
ssrc
,
mtu
,
sample_rate
,
pt
,
interleaved
);
default
:
WarnL
<<
"暂不支持该CodecId:"
<<
codec_id
;
return
nullptr
;
}
}
}
}
RtpCodec
::
Ptr
Factory
::
getRtpDecoderByTrack
(
const
Track
::
Ptr
&
track
)
{
RtpCodec
::
Ptr
Factory
::
getRtpDecoderByTrack
(
const
Track
::
Ptr
&
track
)
{
switch
(
track
->
getCodecId
()){
switch
(
track
->
getCodecId
()){
case
CodecH264
:
case
CodecH264
:
return
std
::
make_shared
<
H264RtpDecoder
>
();
return
std
::
make_shared
<
H264RtpDecoder
>
();
case
CodecH265
:
return
std
::
make_shared
<
H265RtpDecoder
>
();
case
CodecH265
:
case
CodecAAC
:
return
std
::
make_shared
<
AACRtpDecoder
>
(
track
->
clone
());
return
std
::
make_shared
<
H265RtpDecoder
>
();
case
CodecG711A
:
case
CodecAAC
:
case
CodecG711U
:
return
std
::
make_shared
<
G711RtpDecoder
>
(
track
->
clone
());
return
std
::
make_shared
<
AACRtpDecoder
>
(
track
->
clone
());
default
:
WarnL
<<
"暂不支持该CodecId:"
<<
track
->
getCodecName
();
return
nullptr
;
case
CodecG711A
:
case
CodecG711U
:
return
std
::
make_shared
<
G711RtpDecoder
>
(
track
->
clone
());
default
:
WarnL
<<
"暂不支持该CodecId:"
<<
track
->
getCodecName
();
return
nullptr
;
}
}
}
}
/////////////////////////////rtmp相关///////////////////////////////////////////
/////////////////////////////rtmp相关///////////////////////////////////////////
Track
::
Ptr
Factory
::
getVideoTrackByAmf
(
const
AMFValue
&
amf
)
{
static
CodecId
getVideoCodecIdByAmf
(
const
AMFValue
&
val
){
CodecId
codecId
=
getCodecIdByAmf
(
amf
);
if
(
codecId
==
CodecInvalid
){
return
nullptr
;
}
return
getTrackByCodecId
(
codecId
);
}
mediakit
::
Track
::
Ptr
Factory
::
getAudioTrackByAmf
(
const
AMFValue
&
amf
)
{
CodecId
codecId
=
getAudioCodecIdByAmf
(
amf
);
if
(
codecId
==
CodecInvalid
)
{
return
nullptr
;
}
return
getTrackByCodecId
(
codecId
);
}
CodecId
Factory
::
getCodecIdByAmf
(
const
AMFValue
&
val
){
if
(
val
.
type
()
==
AMF_STRING
){
if
(
val
.
type
()
==
AMF_STRING
){
auto
str
=
val
.
as_string
();
auto
str
=
val
.
as_string
();
if
(
str
==
"avc1"
){
if
(
str
==
"avc1"
){
...
@@ -209,20 +163,34 @@ CodecId Factory::getCodecIdByAmf(const AMFValue &val){
...
@@ -209,20 +163,34 @@ CodecId Factory::getCodecIdByAmf(const AMFValue &val){
case
FLV_CODEC_H264
:
return
CodecH264
;
case
FLV_CODEC_H264
:
return
CodecH264
;
case
FLV_CODEC_AAC
:
return
CodecAAC
;
case
FLV_CODEC_AAC
:
return
CodecAAC
;
case
FLV_CODEC_H265
:
return
CodecH265
;
case
FLV_CODEC_H265
:
return
CodecH265
;
default
:
default
:
WarnL
<<
"暂不支持该Amf:"
<<
type_id
;
return
CodecInvalid
;
WarnL
<<
"暂不支持该Amf:"
<<
type_id
;
return
CodecInvalid
;
}
}
}
else
{
WarnL
<<
"Metadata不存在相应的Track"
;
}
}
return
CodecInvalid
;
return
CodecInvalid
;
}
}
CodecId
Factory
::
getAudioCodecIdByAmf
(
const
AMFValue
&
val
)
Track
::
Ptr
getTrackByCodecId
(
CodecId
codecId
,
int
sample_rate
=
0
,
int
channels
=
0
,
int
sample_bit
=
0
)
{
{
switch
(
codecId
){
case
CodecH264
:
return
std
::
make_shared
<
H264Track
>
();
case
CodecH265
:
return
std
::
make_shared
<
H265Track
>
();
case
CodecAAC
:
return
std
::
make_shared
<
AACTrack
>
();
case
CodecG711A
:
case
CodecG711U
:
return
(
sample_rate
&&
channels
&&
sample_bit
)
?
std
::
make_shared
<
G711Track
>
(
codecId
,
sample_rate
,
channels
,
sample_bit
)
:
nullptr
;
default
:
WarnL
<<
"暂不支持该CodecId:"
<<
codecId
;
return
nullptr
;
}
}
Track
::
Ptr
Factory
::
getVideoTrackByAmf
(
const
AMFValue
&
amf
)
{
CodecId
codecId
=
getVideoCodecIdByAmf
(
amf
);
if
(
codecId
==
CodecInvalid
){
return
nullptr
;
}
return
getTrackByCodecId
(
codecId
);
}
static
CodecId
getAudioCodecIdByAmf
(
const
AMFValue
&
val
)
{
if
(
val
.
type
()
==
AMF_STRING
)
{
if
(
val
.
type
()
==
AMF_STRING
)
{
auto
str
=
val
.
as_string
();
auto
str
=
val
.
as_string
();
if
(
str
==
"mp4a"
)
{
if
(
str
==
"mp4a"
)
{
...
@@ -235,41 +203,38 @@ CodecId Factory::getAudioCodecIdByAmf(const AMFValue& val)
...
@@ -235,41 +203,38 @@ CodecId Factory::getAudioCodecIdByAmf(const AMFValue& val)
if
(
val
.
type
()
!=
AMF_NULL
)
{
if
(
val
.
type
()
!=
AMF_NULL
)
{
auto
type_id
=
val
.
as_integer
();
auto
type_id
=
val
.
as_integer
();
switch
(
type_id
)
{
switch
(
type_id
)
{
case
FLV_CODEC_AAC
:
return
CodecAAC
;
case
FLV_CODEC_AAC
:
return
CodecAAC
;
case
FLV_CODEC_G711A
:
return
CodecG711A
;
case
FLV_CODEC_G711A
:
return
CodecG711A
;
case
FLV_CODEC_G711U
:
return
CodecG711U
;
case
FLV_CODEC_G711U
:
return
CodecG711U
;
default
:
WarnL
<<
"暂不支持该Amf:"
<<
type_id
;
return
CodecInvalid
;
default
:
WarnL
<<
"暂不支持该Amf:"
<<
type_id
;
return
CodecInvalid
;
}
}
}
else
{
WarnL
<<
"Metadata不存在相应的Track"
;
}
}
return
CodecInvalid
;
return
CodecInvalid
;
}
}
Track
::
Ptr
Factory
::
getAudioTrackByAmf
(
const
AMFValue
&
amf
,
int
sample_rate
,
int
channels
,
int
sample_bit
){
CodecId
codecId
=
getAudioCodecIdByAmf
(
amf
);
if
(
codecId
==
CodecInvalid
)
{
return
nullptr
;
}
return
getTrackByCodecId
(
codecId
,
sample_rate
,
channels
,
sample_bit
);
}
RtmpCodec
::
Ptr
Factory
::
getRtmpCodecByTrack
(
const
Track
::
Ptr
&
track
)
{
RtmpCodec
::
Ptr
Factory
::
getRtmpCodecByTrack
(
const
Track
::
Ptr
&
track
)
{
switch
(
track
->
getCodecId
()){
switch
(
track
->
getCodecId
()){
case
CodecH264
:
case
CodecH264
:
return
std
::
make_shared
<
H264RtmpEncoder
>
(
track
);
return
std
::
make_shared
<
H264RtmpEncoder
>
(
track
);
case
CodecAAC
:
return
std
::
make_shared
<
AACRtmpEncoder
>
(
track
);
case
CodecAAC
:
case
CodecH265
:
return
std
::
make_shared
<
H265RtmpEncoder
>
(
track
);
return
std
::
make_shared
<
AACRtmpEncoder
>
(
track
);
case
CodecG711A
:
case
CodecH265
:
case
CodecG711U
:
return
std
::
make_shared
<
G711RtmpEncoder
>
(
track
);
return
std
::
make_shared
<
H265RtmpEncoder
>
(
track
);
default
:
WarnL
<<
"暂不支持该CodecId:"
<<
track
->
getCodecName
();
return
nullptr
;
case
CodecG711A
:
case
CodecG711U
:
return
std
::
make_shared
<
G711RtmpEncoder
>
(
track
);
default
:
WarnL
<<
"暂不支持该CodecId:"
<<
track
->
getCodecName
();
return
nullptr
;
}
}
}
}
AMFValue
Factory
::
getAmfByCodecId
(
CodecId
codecId
)
{
AMFValue
Factory
::
getAmfByCodecId
(
CodecId
codecId
)
{
switch
(
codecId
){
switch
(
codecId
){
//此处用string标明rtmp编码类型目的是为了兼容某些android系统
case
CodecAAC
:
return
AMFValue
(
"mp4a"
);
case
CodecAAC
:
return
AMFValue
(
"mp4a"
);
case
CodecH264
:
return
AMFValue
(
"avc1"
);
case
CodecH264
:
return
AMFValue
(
"avc1"
);
case
CodecH265
:
return
AMFValue
(
FLV_CODEC_H265
);
case
CodecH265
:
return
AMFValue
(
FLV_CODEC_H265
);
...
@@ -279,6 +244,5 @@ AMFValue Factory::getAmfByCodecId(CodecId codecId) {
...
@@ -279,6 +244,5 @@ AMFValue Factory::getAmfByCodecId(CodecId codecId) {
}
}
}
}
}
//namespace mediakit
}
//namespace mediakit
src/Extension/Factory.h
查看文件 @
7805558d
...
@@ -24,14 +24,6 @@ namespace mediakit{
...
@@ -24,14 +24,6 @@ namespace mediakit{
class
Factory
{
class
Factory
{
public
:
public
:
/**
* 根据CodecId获取Track,该Track的ready()状态一般都为false
* @param codecId 编解码器id
* @return
*/
static
Track
::
Ptr
getTrackByCodecId
(
CodecId
codecId
);
////////////////////////////////rtsp相关//////////////////////////////////
////////////////////////////////rtsp相关//////////////////////////////////
/**
/**
* 根据sdp生成Track对象
* 根据sdp生成Track对象
...
@@ -41,14 +33,11 @@ public:
...
@@ -41,14 +33,11 @@ public:
/**
/**
* 根据sdp生成rtp编码器
* 根据sdp生成rtp编码器
* @param sdp sdp对象
* @param sdp sdp对象
* @return
*/
*/
static
RtpCodec
::
Ptr
getRtpEncoderBySdp
(
const
Sdp
::
Ptr
&
sdp
);
static
RtpCodec
::
Ptr
getRtpEncoderBySdp
(
const
Sdp
::
Ptr
&
sdp
);
/**
/**
* 根据Track生成Rtp解包器
* 根据Track生成Rtp解包器
* @param track
* @return
*/
*/
static
RtpCodec
::
Ptr
getRtpDecoderByTrack
(
const
Track
::
Ptr
&
track
);
static
RtpCodec
::
Ptr
getRtpDecoderByTrack
(
const
Track
::
Ptr
&
track
);
...
@@ -58,43 +47,23 @@ public:
...
@@ -58,43 +47,23 @@ public:
/**
/**
* 根据amf对象获取视频相应的Track
* 根据amf对象获取视频相应的Track
* @param amf rtmp metadata中的videocodecid的值
* @param amf rtmp metadata中的videocodecid的值
* @return
*/
*/
static
Track
::
Ptr
getVideoTrackByAmf
(
const
AMFValue
&
amf
);
static
Track
::
Ptr
getVideoTrackByAmf
(
const
AMFValue
&
amf
);
/**
/**
* 根据amf对象获取音频相应的Track
* 根据amf对象获取音频相应的Track
* @param amf rtmp metadata中的audiocodecid的值
* @param amf rtmp metadata中的audiocodecid的值
* @return
*/
*/
static
Track
::
Ptr
getAudioTrackByAmf
(
const
AMFValue
&
amf
);
static
Track
::
Ptr
getAudioTrackByAmf
(
const
AMFValue
&
amf
,
int
sample_rate
,
int
channels
,
int
sample_bit
);
/**
* 根据amf对象获取相应的CodecId
* @param val rtmp metadata中的videocodecid或audiocodecid的值
* @return
*/
static
CodecId
getCodecIdByAmf
(
const
AMFValue
&
val
);
/**
* 根据amf对象获取音频相应的CodecId
* @param val rtmp metadata中的audiocodecid的值
* @return
*/
static
CodecId
getAudioCodecIdByAmf
(
const
AMFValue
&
val
);
/**
/**
* 根据Track获取Rtmp的编解码器
* 根据Track获取Rtmp的编解码器
* @param track 媒体描述对象
* @param track 媒体描述对象
* @return
*/
*/
static
RtmpCodec
::
Ptr
getRtmpCodecByTrack
(
const
Track
::
Ptr
&
track
);
static
RtmpCodec
::
Ptr
getRtmpCodecByTrack
(
const
Track
::
Ptr
&
track
);
/**
/**
* 根据codecId获取rtmp的codec描述
* 根据codecId获取rtmp的codec描述
* @param codecId
* @return
*/
*/
static
AMFValue
getAmfByCodecId
(
CodecId
codecId
);
static
AMFValue
getAmfByCodecId
(
CodecId
codecId
);
};
};
...
...
src/Extension/G711.cpp
查看文件 @
7805558d
...
@@ -12,13 +12,12 @@
...
@@ -12,13 +12,12 @@
namespace
mediakit
{
namespace
mediakit
{
Sdp
::
Ptr
G711Track
::
getSdp
()
{
Sdp
::
Ptr
G711Track
::
getSdp
()
{
if
(
!
ready
()){
if
(
!
ready
()){
WarnL
<<
getCodecName
()
<<
" Track未准备好"
;
WarnL
<<
getCodecName
()
<<
" Track未准备好"
;
return
nullptr
;
return
nullptr
;
}
}
return
std
::
make_shared
<
G711Sdp
>
(
getCodecId
(),
getAudioSampleRate
(),
get
CodecId
()
==
CodecG711A
?
8
:
0
,
getAudioSampleBit
());
return
std
::
make_shared
<
G711Sdp
>
(
getCodecId
(),
getAudioSampleRate
(),
get
AudioChannel
());
}
}
}
//namespace mediakit
}
//namespace mediakit
...
...
src/Extension/G711.h
查看文件 @
7805558d
...
@@ -16,40 +16,27 @@
...
@@ -16,40 +16,27 @@
namespace
mediakit
{
namespace
mediakit
{
class
G711Frame
;
unsigned
const
samplingFrequencyTableG711
[
16
]
=
{
96000
,
88200
,
64000
,
48000
,
44100
,
32000
,
24000
,
22050
,
16000
,
12000
,
11025
,
8000
,
7350
,
0
,
0
,
0
};
void
makeAdtsHeader
(
const
string
&
strAudioCfg
,
G711Frame
&
adts
);
void
writeAdtsHeader
(
const
G711Frame
&
adts
,
uint8_t
*
pcAdts
)
;
string
makeG711AdtsConfig
(
const
uint8_t
*
pcAdts
);
void
getAACInfo
(
const
G711Frame
&
adts
,
int
&
iSampleRate
,
int
&
iChannel
);
/**
/**
*
aac帧,包含adts头
*
G711帧
*/
*/
class
G711Frame
:
public
Frame
{
class
G711Frame
:
public
Frame
{
public
:
public
:
typedef
std
::
shared_ptr
<
G711Frame
>
Ptr
;
typedef
std
::
shared_ptr
<
G711Frame
>
Ptr
;
char
*
data
()
const
override
{
char
*
data
()
const
override
{
return
(
char
*
)
buffer
;
return
(
char
*
)
buffer
.
data
()
;
}
}
uint32_t
size
()
const
override
{
uint32_t
size
()
const
override
{
return
frameLength
;
return
buffer
.
size
()
;
}
}
uint32_t
dts
()
const
override
{
uint32_t
dts
()
const
override
{
return
timeStamp
;
return
timeStamp
;
}
}
uint32_t
prefixSize
()
const
override
{
uint32_t
prefixSize
()
const
override
{
return
iPrefixSize
;
return
0
;
}
}
TrackType
getTrackType
()
const
override
{
TrackType
getTrackType
()
const
override
{
...
@@ -69,17 +56,15 @@ public:
...
@@ -69,17 +56,15 @@ public:
}
}
public
:
public
:
CodecId
_codecId
=
CodecG711A
;
CodecId
_codecId
=
CodecG711A
;
unsigned
int
frameLength
;
// 一个帧的长度包括 raw data block
string
buffer
;
unsigned
char
buffer
[
2
*
1024
+
7
];
uint32_t
timeStamp
;
uint32_t
timeStamp
;
uint32_t
iPrefixSize
=
0
;
}
;
}
;
class
G711FrameNoCacheAble
:
public
FrameNoCacheAble
{
class
G711FrameNoCacheAble
:
public
FrameNoCacheAble
{
public
:
public
:
typedef
std
::
shared_ptr
<
G711FrameNoCacheAble
>
Ptr
;
typedef
std
::
shared_ptr
<
G711FrameNoCacheAble
>
Ptr
;
G711FrameNoCacheAble
(
CodecId
codecId
,
char
*
ptr
,
uint32_t
size
,
uint32_t
dts
,
int
prefixeSize
=
7
){
G711FrameNoCacheAble
(
CodecId
codecId
,
char
*
ptr
,
uint32_t
size
,
uint32_t
dts
,
int
prefixeSize
=
0
){
_codecId
=
codecId
;
_codecId
=
codecId
;
_ptr
=
ptr
;
_ptr
=
ptr
;
_size
=
size
;
_size
=
size
;
...
@@ -105,91 +90,61 @@ public:
...
@@ -105,91 +90,61 @@ public:
private
:
private
:
CodecId
_codecId
;
CodecId
_codecId
;
}
;
};
/**
/**
*
g
711音频通道
*
G
711音频通道
*/
*/
class
G711Track
:
public
AudioTrack
{
class
G711Track
:
public
AudioTrack
{
public
:
public
:
typedef
std
::
shared_ptr
<
G711Track
>
Ptr
;
typedef
std
::
shared_ptr
<
G711Track
>
Ptr
;
/**
/**
* 延后获取adts头信息
* 在随后的inputFrame中获取adts头信息
*/
G711Track
(){}
/**
* G711A G711U
* G711A G711U
*/
*/
G711Track
(
CodecId
codecId
,
int
sampleBit
=
16
,
int
sampleRate
=
8000
){
G711Track
(
CodecId
codecId
,
int
sample_rate
,
int
channels
,
int
sample_bit
){
_codecid
=
codecId
;
_codecid
=
codecId
;
_sample
Bit
=
sampleBit
;
_sample
_rate
=
sample_rate
;
_
sampleRate
=
sampleRate
;
_
channels
=
channels
;
onReady
()
;
_sample_bit
=
sample_bit
;
}
}
/**
/**
* 返回编码类型
* 返回编码类型
* @return
*/
*/
CodecId
getCodecId
()
const
override
{
CodecId
getCodecId
()
const
override
{
return
_codecid
;
return
_codecid
;
}
}
/**
/**
* 在获取aac_cfg前是无效的Track
* 是否已经初始化
* @return
*/
*/
bool
ready
()
override
{
bool
ready
()
override
{
return
true
;
return
true
;
}
}
/**
/**
* 返回音频采样率
* 返回音频采样率
* @return
*/
*/
int
getAudioSampleRate
()
const
override
{
int
getAudioSampleRate
()
const
override
{
return
_sample
R
ate
;
return
_sample
_r
ate
;
}
}
/**
/**
* 返回音频采样位数,一般为16或8
* 返回音频采样位数,一般为16或8
* @return
*/
*/
int
getAudioSampleBit
()
const
override
{
int
getAudioSampleBit
()
const
override
{
return
_sample
B
it
;
return
_sample
_b
it
;
}
}
/**
/**
* 返回音频通道数
* 返回音频通道数
* @return
*/
*/
int
getAudioChannel
()
const
override
{
int
getAudioChannel
()
const
override
{
return
_channel
;
return
_channel
s
;
}
}
/**
* 输入数据帧,并获取aac_cfg
* @param frame 数据帧
*/
void
inputFrame
(
const
Frame
::
Ptr
&
frame
)
override
{
AudioTrack
::
inputFrame
(
frame
);
}
private
:
private
:
/**
*
*/
void
onReady
(){
/*
if(_cfg.size() < 2){
return;
}
G711Frame aacFrame;
makeAdtsHeader(_cfg,aacFrame);
getAACInfo(aacFrame,_sampleRate,_channel);*/
}
Track
::
Ptr
clone
()
override
{
Track
::
Ptr
clone
()
override
{
return
std
::
make_shared
<
std
::
remove_reference
<
decltype
(
*
this
)
>::
type
>
(
*
this
);
return
std
::
make_shared
<
std
::
remove_reference
<
decltype
(
*
this
)
>::
type
>
(
*
this
);
}
}
...
@@ -197,34 +152,31 @@ private:
...
@@ -197,34 +152,31 @@ private:
//生成sdp
//生成sdp
Sdp
::
Ptr
getSdp
()
override
;
Sdp
::
Ptr
getSdp
()
override
;
private
:
private
:
string
_cfg
;
CodecId
_codecid
;
CodecId
_codecid
=
CodecG711A
;
int
_sample_rate
;
int
_sampleRate
=
8000
;
int
_channels
;
int
_sampleBit
=
16
;
int
_sample_bit
;
int
_channel
=
1
;
};
};
/**
/**
* aac
类型SDP
* G711
类型SDP
*/
*/
class
G711Sdp
:
public
Sdp
{
class
G711Sdp
:
public
Sdp
{
public
:
public
:
/**
/**
*
*
G711采样率固定为8000
* @param
aac_
codecId G711A G711U
* @param codecId G711A G711U
* @param sample_rate 音频采样率
* @param sample_rate 音频采样率
* @param playload_type rtp playload
type 默认0为G711U, 8为G711A
* @param playload_type rtp playload
* @param bitrate 比特率
* @param bitrate 比特率
*/
*/
G711Sdp
(
CodecId
codecId
,
G711Sdp
(
CodecId
codecId
,
int
sample_rate
,
int
sample_rate
,
int
playload_type
=
0
,
int
channels
,
int
playload_type
=
98
,
int
bitrate
=
128
)
:
Sdp
(
sample_rate
,
playload_type
),
_codecId
(
codecId
){
int
bitrate
=
128
)
:
Sdp
(
sample_rate
,
playload_type
),
_codecId
(
codecId
){
_printer
<<
"m=audio 0 RTP/AVP "
<<
playload_type
<<
"
\r\n
"
;
_printer
<<
"m=audio 0 RTP/AVP "
<<
playload_type
<<
"
\r\n
"
;
//_printer << "b=AS:" << bitrate << "\r\n";
_printer
<<
"a=rtpmap:"
<<
playload_type
<<
(
codecId
==
CodecG711A
?
" PCMA/"
:
" PCMU/"
)
<<
sample_rate
<<
"/"
<<
channels
<<
"
\r\n
"
;
_printer
<<
"a=rtpmap:"
<<
playload_type
<<
(
codecId
==
CodecG711A
?
" PCMA/"
:
" PCMU/"
)
<<
sample_rate
<<
"
\r\n
"
;
_printer
<<
"a=control:trackID="
<<
getTrackType
()
<<
"
\r\n
"
;
_printer
<<
"a=control:trackID="
<<
getTrackType
()
<<
"
\r\n
"
;
}
}
...
@@ -235,12 +187,14 @@ public:
...
@@ -235,12 +187,14 @@ public:
TrackType
getTrackType
()
const
override
{
TrackType
getTrackType
()
const
override
{
return
TrackAudio
;
return
TrackAudio
;
}
}
CodecId
getCodecId
()
const
override
{
CodecId
getCodecId
()
const
override
{
return
_codecId
;
return
_codecId
;
}
}
private
:
private
:
_StrPrinter
_printer
;
_StrPrinter
_printer
;
CodecId
_codecId
=
CodecG711A
;
CodecId
_codecId
;
};
};
}
//namespace mediakit
}
//namespace mediakit
...
...
src/Extension/G711Rtmp.cpp
查看文件 @
7805558d
...
@@ -12,57 +12,52 @@
...
@@ -12,57 +12,52 @@
namespace
mediakit
{
namespace
mediakit
{
G711RtmpDecoder
::
G711RtmpDecoder
()
{
G711RtmpDecoder
::
G711RtmpDecoder
(
CodecId
codecId
)
{
_adts
=
obtainFrame
();
_frame
=
obtainFrame
();
_codecId
=
codecId
;
}
}
G711Frame
::
Ptr
G711RtmpDecoder
::
obtainFrame
()
{
G711Frame
::
Ptr
G711RtmpDecoder
::
obtainFrame
()
{
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
auto
frame
=
ResourcePoolHelper
<
G711Frame
>::
obtainObj
();
auto
frame
=
ResourcePoolHelper
<
G711Frame
>::
obtainObj
();
frame
->
frameLength
=
0
;
frame
->
buffer
.
clear
()
;
frame
->
iPrefixSize
=
0
;
frame
->
_codecId
=
_codecId
;
return
frame
;
return
frame
;
}
}
bool
G711RtmpDecoder
::
inputRtmp
(
const
RtmpPacket
::
Ptr
&
pkt
,
bool
key_pos
)
{
bool
G711RtmpDecoder
::
inputRtmp
(
const
RtmpPacket
::
Ptr
&
pkt
,
bool
)
{
onGetG711
(
pkt
->
strBuf
.
data
()
+
2
,
pkt
->
strBuf
.
size
()
-
2
,
pkt
->
timeStamp
);
//拷贝G711负载
_frame
->
buffer
.
assign
(
pkt
->
strBuf
.
data
()
+
1
,
pkt
->
strBuf
.
size
()
-
1
);
_frame
->
timeStamp
=
pkt
->
timeStamp
;
//写入环形缓存
RtmpCodec
::
inputFrame
(
_frame
);
_frame
=
obtainFrame
();
return
false
;
return
false
;
}
}
void
G711RtmpDecoder
::
onGetG711
(
const
char
*
pcData
,
int
iLen
,
uint32_t
ui32TimeStamp
)
{
if
(
iLen
+
7
>
sizeof
(
_adts
->
buffer
)){
WarnL
<<
"Illegal adts data, exceeding the length limit."
;
return
;
}
//拷贝aac负载
memcpy
(
_adts
->
buffer
,
pcData
,
iLen
);
_adts
->
frameLength
=
iLen
;
_adts
->
timeStamp
=
ui32TimeStamp
;
//写入环形缓存
RtmpCodec
::
inputFrame
(
_adts
);
_adts
=
obtainFrame
();
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
G711RtmpEncoder
::
G711RtmpEncoder
(
const
Track
::
Ptr
&
track
)
{
G711RtmpEncoder
::
G711RtmpEncoder
(
const
Track
::
Ptr
&
track
)
:
G711RtmpDecoder
(
track
->
getCodecId
())
{
_
track
=
dynamic_pointer_cast
<
G711Track
>
(
track
);
_
audio_flv_flags
=
getAudioRtmpFlags
(
track
);
}
}
void
G711RtmpEncoder
::
inputFrame
(
const
Frame
::
Ptr
&
frame
)
{
void
G711RtmpEncoder
::
inputFrame
(
const
Frame
::
Ptr
&
frame
)
{
if
(
!
_audio_flv_flags
){
return
;
}
RtmpPacket
::
Ptr
rtmpPkt
=
ResourcePoolHelper
<
RtmpPacket
>::
obtainObj
();
RtmpPacket
::
Ptr
rtmpPkt
=
ResourcePoolHelper
<
RtmpPacket
>::
obtainObj
();
rtmpPkt
->
strBuf
.
clear
();
rtmpPkt
->
strBuf
.
clear
();
rtmpPkt
->
strBuf
.
append
(
frame
->
data
()
+
frame
->
prefixSize
(),
frame
->
size
()
-
frame
->
prefixSize
());
//header
rtmpPkt
->
strBuf
.
push_back
(
_audio_flv_flags
);
//g711 data
rtmpPkt
->
strBuf
.
append
(
frame
->
data
()
+
frame
->
prefixSize
(),
frame
->
size
()
-
frame
->
prefixSize
());
rtmpPkt
->
bodySize
=
rtmpPkt
->
strBuf
.
size
();
rtmpPkt
->
bodySize
=
rtmpPkt
->
strBuf
.
size
();
rtmpPkt
->
chunkId
=
CHUNK_AUDIO
;
rtmpPkt
->
chunkId
=
CHUNK_AUDIO
;
rtmpPkt
->
streamId
=
STREAM_MEDIA
;
rtmpPkt
->
streamId
=
STREAM_MEDIA
;
rtmpPkt
->
timeStamp
=
frame
->
dts
();
rtmpPkt
->
timeStamp
=
frame
->
dts
();
rtmpPkt
->
typeId
=
MSG_AUDIO
;
rtmpPkt
->
typeId
=
MSG_AUDIO
;
RtmpCodec
::
inputRtmp
(
rtmpPkt
,
false
);
RtmpCodec
::
inputRtmp
(
rtmpPkt
,
false
);
}
}
}
//
namespace
mediakit
}
//
namespace
mediakit
\ No newline at end of file
src/Extension/G711Rtmp.h
查看文件 @
7805558d
...
@@ -17,13 +17,13 @@
...
@@ -17,13 +17,13 @@
namespace
mediakit
{
namespace
mediakit
{
/**
/**
* G711 Rtmp转
adts
类
* G711 Rtmp转
G711 Frame
类
*/
*/
class
G711RtmpDecoder
:
public
RtmpCodec
,
public
ResourcePoolHelper
<
G711Frame
>
{
class
G711RtmpDecoder
:
public
RtmpCodec
,
public
ResourcePoolHelper
<
G711Frame
>
{
public
:
public
:
typedef
std
::
shared_ptr
<
G711RtmpDecoder
>
Ptr
;
typedef
std
::
shared_ptr
<
G711RtmpDecoder
>
Ptr
;
G711RtmpDecoder
();
G711RtmpDecoder
(
CodecId
codecId
);
~
G711RtmpDecoder
()
{}
~
G711RtmpDecoder
()
{}
/**
/**
...
@@ -37,48 +37,32 @@ public:
...
@@ -37,48 +37,32 @@ public:
return
TrackAudio
;
return
TrackAudio
;
}
}
void
setCodecId
(
CodecId
codecId
)
{
_codecid
=
codecId
;
}
CodecId
getCodecId
()
const
override
{
CodecId
getCodecId
()
const
override
{
return
_codec
i
d
;
return
_codec
I
d
;
}
}
private
:
protected
:
void
onGetG711
(
const
char
*
pcData
,
int
iLen
,
uint32_t
ui32TimeStamp
);
G711Frame
::
Ptr
obtainFrame
();
G711Frame
::
Ptr
obtainFrame
();
protected
:
private
:
G711Frame
::
Ptr
_adts
;
G711Frame
::
Ptr
_frame
;
CodecId
_codecid
=
CodecInvalid
;
CodecId
_codecId
;
};
};
/**
/**
*
aac adts转Rtmp
类
*
G711 RTMP打包
类
*/
*/
class
G711RtmpEncoder
:
public
G711RtmpDecoder
,
public
ResourcePoolHelper
<
RtmpPacket
>
{
class
G711RtmpEncoder
:
public
G711RtmpDecoder
,
public
ResourcePoolHelper
<
RtmpPacket
>
{
public
:
public
:
typedef
std
::
shared_ptr
<
G711RtmpEncoder
>
Ptr
;
typedef
std
::
shared_ptr
<
G711RtmpEncoder
>
Ptr
;
/**
* 构造函数,track可以为空,此时则在inputFrame时输入adts头
* 如果track不为空且包含adts头相关信息,
* 那么inputFrame时可以不输入adts头
* @param track
*/
G711RtmpEncoder
(
const
Track
::
Ptr
&
track
);
G711RtmpEncoder
(
const
Track
::
Ptr
&
track
);
~
G711RtmpEncoder
()
{}
~
G711RtmpEncoder
()
{}
/**
/**
* 输入aac 数据,可以不带adts头
* 输入G711 数据
* @param frame aac数据
*/
*/
void
inputFrame
(
const
Frame
::
Ptr
&
frame
)
override
;
void
inputFrame
(
const
Frame
::
Ptr
&
frame
)
override
;
private
:
private
:
G711Track
::
Ptr
_track
;
uint8_t
_audio_flv_flags
=
0
;
};
};
}
//namespace mediakit
}
//namespace mediakit
...
...
src/Extension/G711Rtp.cpp
查看文件 @
7805558d
...
@@ -12,6 +12,53 @@
...
@@ -12,6 +12,53 @@
namespace
mediakit
{
namespace
mediakit
{
G711RtpDecoder
::
G711RtpDecoder
(
const
Track
::
Ptr
&
track
){
_codecid
=
track
->
getCodecId
();
_frame
=
obtainFrame
();
}
G711Frame
::
Ptr
G711RtpDecoder
::
obtainFrame
()
{
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
auto
frame
=
ResourcePoolHelper
<
G711Frame
>::
obtainObj
();
frame
->
buffer
.
clear
();
frame
->
_codecId
=
_codecid
;
frame
->
timeStamp
=
0
;
return
frame
;
}
bool
G711RtpDecoder
::
inputRtp
(
const
RtpPacket
::
Ptr
&
rtppack
,
bool
)
{
// 获取rtp数据长度
int
length
=
rtppack
->
size
()
-
rtppack
->
offset
;
// 获取rtp数据
const
char
*
rtp_packet_buf
=
rtppack
->
data
()
+
rtppack
->
offset
;
if
(
rtppack
->
timeStamp
!=
_frame
->
timeStamp
)
{
//时间戳变更,清空上一帧
onGetG711
(
_frame
);
}
//追加数据
_frame
->
buffer
.
append
(
rtp_packet_buf
,
length
);
//赋值时间戳
_frame
->
timeStamp
=
rtppack
->
timeStamp
;
if
(
rtppack
->
mark
||
_frame
->
buffer
.
size
()
>
10
*
1024
)
{
//标记为mark时,或者内存快溢出时,我们认为这是该帧最后一个包
onGetG711
(
_frame
);
}
return
false
;
}
void
G711RtpDecoder
::
onGetG711
(
const
G711Frame
::
Ptr
&
frame
)
{
if
(
!
frame
->
buffer
.
empty
()){
//写入环形缓存
RtpCodec
::
inputFrame
(
frame
);
_frame
=
obtainFrame
();
}
}
/////////////////////////////////////////////////////////////////////////////////////
G711RtpEncoder
::
G711RtpEncoder
(
uint32_t
ui32Ssrc
,
G711RtpEncoder
::
G711RtpEncoder
(
uint32_t
ui32Ssrc
,
uint32_t
ui32MtuSize
,
uint32_t
ui32MtuSize
,
uint32_t
ui32SampleRate
,
uint32_t
ui32SampleRate
,
...
@@ -21,7 +68,7 @@ G711RtpEncoder::G711RtpEncoder(uint32_t ui32Ssrc,
...
@@ -21,7 +68,7 @@ G711RtpEncoder::G711RtpEncoder(uint32_t ui32Ssrc,
ui32MtuSize
,
ui32MtuSize
,
ui32SampleRate
,
ui32SampleRate
,
ui8PlayloadType
,
ui8PlayloadType
,
ui8Interleaved
){
ui8Interleaved
)
{
}
}
void
G711RtpEncoder
::
inputFrame
(
const
Frame
::
Ptr
&
frame
)
{
void
G711RtpEncoder
::
inputFrame
(
const
Frame
::
Ptr
&
frame
)
{
...
@@ -45,56 +92,9 @@ void G711RtpEncoder::inputFrame(const Frame::Ptr &frame) {
...
@@ -45,56 +92,9 @@ void G711RtpEncoder::inputFrame(const Frame::Ptr &frame) {
}
}
void
G711RtpEncoder
::
makeG711Rtp
(
const
void
*
data
,
unsigned
int
len
,
bool
mark
,
uint32_t
uiStamp
)
{
void
G711RtpEncoder
::
makeG711Rtp
(
const
void
*
data
,
unsigned
int
len
,
bool
mark
,
uint32_t
uiStamp
)
{
RtpCodec
::
inputRtp
(
makeRtp
(
getTrackType
(),
data
,
len
,
mark
,
uiStamp
),
false
);
RtpCodec
::
inputRtp
(
makeRtp
(
getTrackType
(),
data
,
len
,
mark
,
uiStamp
),
false
);
}
}
/////////////////////////////////////////////////////////////////////////////////////
G711RtpDecoder
::
G711RtpDecoder
(
const
Track
::
Ptr
&
track
){
auto
g711Track
=
dynamic_pointer_cast
<
G711Track
>
(
track
);
_codecid
=
g711Track
->
getCodecId
();
if
(
!
g711Track
||
!
g711Track
->
ready
()){
WarnL
<<
"该g711 track无效!"
;
}
else
{
}
_adts
=
obtainFrame
();
}
G711RtpDecoder
::
G711RtpDecoder
()
{
_adts
=
obtainFrame
();
}
G711Frame
::
Ptr
G711RtpDecoder
::
obtainFrame
()
{
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
auto
frame
=
ResourcePoolHelper
<
G711Frame
>::
obtainObj
();
frame
->
frameLength
=
0
;
frame
->
iPrefixSize
=
0
;
return
frame
;
}
bool
G711RtpDecoder
::
inputRtp
(
const
RtpPacket
::
Ptr
&
rtppack
,
bool
key_pos
)
{
// 获取rtp数据长度
int
length
=
rtppack
->
size
()
-
rtppack
->
offset
;
// 获取rtp数据
const
uint8_t
*
rtp_packet_buf
=
(
uint8_t
*
)
rtppack
->
data
()
+
rtppack
->
offset
;
_adts
->
frameLength
=
length
;
memcpy
(
_adts
->
buffer
,
rtp_packet_buf
,
length
);
_adts
->
_codecId
=
_codecid
;
if
(
rtppack
->
mark
==
true
)
{
_adts
->
timeStamp
=
rtppack
->
timeStamp
;
onGetG711
(
_adts
);
}
return
false
;
}
void
G711RtpDecoder
::
onGetG711
(
const
G711Frame
::
Ptr
&
frame
)
{
//写入环形缓存
RtpCodec
::
inputFrame
(
frame
);
_adts
=
obtainFrame
();
}
}
//namespace mediakit
}
//namespace mediakit
...
...
src/Extension/G711Rtp.h
查看文件 @
7805558d
...
@@ -10,12 +10,12 @@
...
@@ -10,12 +10,12 @@
#ifndef ZLMEDIAKIT_G711RTPCODEC_H
#ifndef ZLMEDIAKIT_G711RTPCODEC_H
#define ZLMEDIAKIT_G711RTPCODEC_H
#define ZLMEDIAKIT_G711RTPCODEC_H
#include "Rtsp/RtpCodec.h"
#include "Rtsp/RtpCodec.h"
#include "Extension/G711.h"
#include "Extension/G711.h"
namespace
mediakit
{
namespace
mediakit
{
/**
/**
*
G711 rtp转adts
类
*
rtp转G711
类
*/
*/
class
G711RtpDecoder
:
public
RtpCodec
,
public
ResourcePoolHelper
<
G711Frame
>
{
class
G711RtpDecoder
:
public
RtpCodec
,
public
ResourcePoolHelper
<
G711Frame
>
{
public
:
public
:
...
@@ -34,20 +34,23 @@ public:
...
@@ -34,20 +34,23 @@ public:
TrackType
getTrackType
()
const
override
{
TrackType
getTrackType
()
const
override
{
return
TrackAudio
;
return
TrackAudio
;
}
}
CodecId
getCodecId
()
const
override
{
CodecId
getCodecId
()
const
override
{
return
_codecid
;
return
_codecid
;
}
}
protected
:
protected
:
G711RtpDecoder
();
G711RtpDecoder
()
{}
private
:
private
:
void
onGetG711
(
const
G711Frame
::
Ptr
&
frame
);
void
onGetG711
(
const
G711Frame
::
Ptr
&
frame
);
G711Frame
::
Ptr
obtainFrame
();
G711Frame
::
Ptr
obtainFrame
();
private
:
private
:
G711Frame
::
Ptr
_
adts
;
G711Frame
::
Ptr
_
frame
;
CodecId
_codecid
=
CodecInvalid
;
CodecId
_codecid
;
};
};
/**
/**
* g711 转rtp类
* g711 转rtp类
*/
*/
...
@@ -75,8 +78,6 @@ public:
...
@@ -75,8 +78,6 @@ public:
void
inputFrame
(
const
Frame
::
Ptr
&
frame
)
override
;
void
inputFrame
(
const
Frame
::
Ptr
&
frame
)
override
;
private
:
private
:
void
makeG711Rtp
(
const
void
*
pData
,
unsigned
int
uiLen
,
bool
bMark
,
uint32_t
uiStamp
);
void
makeG711Rtp
(
const
void
*
pData
,
unsigned
int
uiLen
,
bool
bMark
,
uint32_t
uiStamp
);
private
:
unsigned
char
_aucSectionBuf
[
1600
];
};
};
}
//namespace mediakit
}
//namespace mediakit
...
...
src/Extension/H264.cpp
查看文件 @
7805558d
...
@@ -62,7 +62,7 @@ void splitH264(const char *ptr, int len, const std::function<void(const char *,
...
@@ -62,7 +62,7 @@ void splitH264(const char *ptr, int len, const std::function<void(const char *,
Sdp
::
Ptr
H264Track
::
getSdp
()
{
Sdp
::
Ptr
H264Track
::
getSdp
()
{
if
(
!
ready
()){
if
(
!
ready
()){
WarnL
<<
"H264
Track未准备好"
;
WarnL
<<
getCodecName
()
<<
"
Track未准备好"
;
return
nullptr
;
return
nullptr
;
}
}
return
std
::
make_shared
<
H264Sdp
>
(
getSps
(),
getPps
());
return
std
::
make_shared
<
H264Sdp
>
(
getSps
(),
getPps
());
...
...
src/Extension/H265.cpp
查看文件 @
7805558d
...
@@ -52,7 +52,7 @@ bool getHEVCInfo(const string &strVps, const string &strSps, int &iVideoWidth, i
...
@@ -52,7 +52,7 @@ bool getHEVCInfo(const string &strVps, const string &strSps, int &iVideoWidth, i
Sdp
::
Ptr
H265Track
::
getSdp
()
{
Sdp
::
Ptr
H265Track
::
getSdp
()
{
if
(
!
ready
()){
if
(
!
ready
()){
WarnL
<<
"H265
Track未准备好"
;
WarnL
<<
getCodecName
()
<<
"
Track未准备好"
;
return
nullptr
;
return
nullptr
;
}
}
return
std
::
make_shared
<
H265Sdp
>
(
getVps
(),
getSps
(),
getPps
());
return
std
::
make_shared
<
H265Sdp
>
(
getVps
(),
getSps
(),
getPps
());
...
...
src/Http/HttpSession.cpp
查看文件 @
7805558d
...
@@ -615,20 +615,29 @@ void HttpSession::setSocketFlags(){
...
@@ -615,20 +615,29 @@ void HttpSession::setSocketFlags(){
}
}
}
}
void
HttpSession
::
onWrite
(
const
Buffer
::
Ptr
&
buffer
)
{
void
HttpSession
::
onWrite
(
const
Buffer
::
Ptr
&
buffer
,
bool
flush
)
{
if
(
flush
){
//需要flush那么一次刷新缓存
HttpSession
::
setSendFlushFlag
(
true
);
}
_ticker
.
resetTime
();
_ticker
.
resetTime
();
if
(
!
_flv_over_websocket
){
if
(
!
_flv_over_websocket
){
_ui64TotalBytes
+=
buffer
->
size
();
_ui64TotalBytes
+=
buffer
->
size
();
send
(
buffer
);
send
(
buffer
);
return
;
}
else
{
}
WebSocketHeader
header
;
WebSocketHeader
header
;
header
.
_fin
=
true
;
header
.
_fin
=
true
;
header
.
_reserved
=
0
;
header
.
_reserved
=
0
;
header
.
_opcode
=
WebSocketHeader
::
BINARY
;
header
.
_opcode
=
WebSocketHeader
::
BINARY
;
header
.
_mask_flag
=
false
;
header
.
_mask_flag
=
false
;
WebSocketSplitter
::
encode
(
header
,
buffer
);
WebSocketSplitter
::
encode
(
header
,
buffer
);
}
if
(
flush
){
//本次刷新缓存后,下次不用刷新缓存
HttpSession
::
setSendFlushFlag
(
false
);
}
}
}
void
HttpSession
::
onWebSocketEncodeData
(
const
Buffer
::
Ptr
&
buffer
){
void
HttpSession
::
onWebSocketEncodeData
(
const
Buffer
::
Ptr
&
buffer
){
...
...
src/Http/HttpSession.h
查看文件 @
7805558d
...
@@ -49,7 +49,7 @@ public:
...
@@ -49,7 +49,7 @@ public:
static
string
urlDecode
(
const
string
&
str
);
static
string
urlDecode
(
const
string
&
str
);
protected
:
protected
:
//FlvMuxer override
//FlvMuxer override
void
onWrite
(
const
Buffer
::
Ptr
&
data
)
override
;
void
onWrite
(
const
Buffer
::
Ptr
&
data
,
bool
flush
)
override
;
void
onDetach
()
override
;
void
onDetach
()
override
;
std
::
shared_ptr
<
FlvMuxer
>
getSharedPtr
()
override
;
std
::
shared_ptr
<
FlvMuxer
>
getSharedPtr
()
override
;
...
...
src/Record/MP4Demuxer.cpp
查看文件 @
7805558d
...
@@ -142,7 +142,9 @@ struct Context{
...
@@ -142,7 +142,9 @@ struct Context{
BufferRaw
::
Ptr
buffer
;
BufferRaw
::
Ptr
buffer
;
};
};
Frame
::
Ptr
MP4Demuxer
::
readFrame
(
bool
&
keyFrame
)
{
Frame
::
Ptr
MP4Demuxer
::
readFrame
(
bool
&
keyFrame
,
bool
&
eof
)
{
keyFrame
=
false
;
eof
=
false
;
static
mov_reader_onread
mov_reader_onread
=
[](
void
*
param
,
uint32_t
track_id
,
const
void
*
buffer
,
size_t
bytes
,
int64_t
pts
,
int64_t
dts
,
int
flags
)
{
static
mov_reader_onread
mov_reader_onread
=
[](
void
*
param
,
uint32_t
track_id
,
const
void
*
buffer
,
size_t
bytes
,
int64_t
pts
,
int64_t
dts
,
int
flags
)
{
Context
*
ctx
=
(
Context
*
)
param
;
Context
*
ctx
=
(
Context
*
)
param
;
ctx
->
pts
=
pts
;
ctx
->
pts
=
pts
;
...
@@ -162,18 +164,22 @@ Frame::Ptr MP4Demuxer::readFrame(bool &keyFrame) {
...
@@ -162,18 +164,22 @@ Frame::Ptr MP4Demuxer::readFrame(bool &keyFrame) {
Context
ctx
=
{
this
,
0
};
Context
ctx
=
{
this
,
0
};
auto
ret
=
mov_reader_read2
(
_mov_reader
.
get
(),
mov_onalloc
,
mov_reader_onread
,
&
ctx
);
auto
ret
=
mov_reader_read2
(
_mov_reader
.
get
(),
mov_onalloc
,
mov_reader_onread
,
&
ctx
);
switch
(
ret
)
{
switch
(
ret
)
{
case
0
:
case
0
:
{
eof
=
true
;
return
nullptr
;
return
nullptr
;
}
case
1
:
{
case
1
:
{
keyFrame
=
ctx
.
flags
&
MOV_AV_FLAG_KEYFREAME
;
keyFrame
=
ctx
.
flags
&
MOV_AV_FLAG_KEYFREAME
;
return
makeFrame
(
ctx
.
track_id
,
ctx
.
buffer
,
ctx
.
pts
,
ctx
.
dts
);
return
makeFrame
(
ctx
.
track_id
,
ctx
.
buffer
,
ctx
.
pts
,
ctx
.
dts
);
}
}
default
:
default
:
{
eof
=
true
;
WarnL
<<
"读取mp4文件数据失败:"
<<
ret
;
WarnL
<<
"读取mp4文件数据失败:"
<<
ret
;
return
nullptr
;
return
nullptr
;
}
}
}
}
}
template
<
typename
Parent
>
template
<
typename
Parent
>
...
...
src/Record/MP4Demuxer.h
查看文件 @
7805558d
...
@@ -22,7 +22,7 @@ public:
...
@@ -22,7 +22,7 @@ public:
MP4Demuxer
(
const
char
*
file
);
MP4Demuxer
(
const
char
*
file
);
~
MP4Demuxer
()
override
;
~
MP4Demuxer
()
override
;
int64_t
seekTo
(
int64_t
stamp_ms
);
int64_t
seekTo
(
int64_t
stamp_ms
);
Frame
::
Ptr
readFrame
(
bool
&
keyFrame
);
Frame
::
Ptr
readFrame
(
bool
&
keyFrame
,
bool
&
eof
);
vector
<
Track
::
Ptr
>
getTracks
(
bool
trackReady
)
const
override
;
vector
<
Track
::
Ptr
>
getTracks
(
bool
trackReady
)
const
override
;
uint64_t
getDurationMS
()
const
;
uint64_t
getDurationMS
()
const
;
private
:
private
:
...
...
src/Record/MP4Reader.cpp
查看文件 @
7805558d
...
@@ -48,11 +48,10 @@ MP4Reader::MP4Reader(const string &strVhost,const string &strApp, const string &
...
@@ -48,11 +48,10 @@ MP4Reader::MP4Reader(const string &strVhost,const string &strApp, const string &
bool
MP4Reader
::
readSample
()
{
bool
MP4Reader
::
readSample
()
{
bool
keyFrame
=
false
;
bool
keyFrame
=
false
;
bool
eof
=
false
;
bool
eof
=
false
;
while
(
true
)
{
while
(
!
eof
)
{
auto
frame
=
_demuxer
->
readFrame
(
keyFrame
);
auto
frame
=
_demuxer
->
readFrame
(
keyFrame
,
eof
);
if
(
!
frame
)
{
if
(
!
frame
)
{
eof
=
true
;
continue
;
break
;
}
}
_mediaMuxer
->
inputFrame
(
frame
);
_mediaMuxer
->
inputFrame
(
frame
);
if
(
frame
->
dts
()
>
getCurrentStamp
())
{
if
(
frame
->
dts
()
>
getCurrentStamp
())
{
...
@@ -122,11 +121,12 @@ bool MP4Reader::seekTo(uint32_t ui32Stamp){
...
@@ -122,11 +121,12 @@ bool MP4Reader::seekTo(uint32_t ui32Stamp){
}
}
//搜索到下一帧关键帧
//搜索到下一帧关键帧
bool
keyFrame
=
false
;
bool
keyFrame
=
false
;
while
(
true
)
{
bool
eof
=
false
;
auto
frame
=
_demuxer
->
readFrame
(
keyFrame
);
while
(
!
eof
)
{
auto
frame
=
_demuxer
->
readFrame
(
keyFrame
,
eof
);
if
(
!
frame
){
if
(
!
frame
){
//文件读完了都未找到下一帧关键帧
//文件读完了都未找到下一帧关键帧
return
fals
e
;
continu
e
;
}
}
if
(
keyFrame
||
frame
->
keyFrame
()
||
frame
->
configFrame
()){
if
(
keyFrame
||
frame
->
keyFrame
()
||
frame
->
configFrame
()){
//定位到key帧
//定位到key帧
...
@@ -136,6 +136,7 @@ bool MP4Reader::seekTo(uint32_t ui32Stamp){
...
@@ -136,6 +136,7 @@ bool MP4Reader::seekTo(uint32_t ui32Stamp){
return
true
;
return
true
;
}
}
}
}
return
false
;
}
}
bool
MP4Reader
::
close
(
MediaSource
&
sender
,
bool
force
){
bool
MP4Reader
::
close
(
MediaSource
&
sender
,
bool
force
){
...
...
src/Rtmp/FlvMuxer.cpp
查看文件 @
7805558d
...
@@ -50,12 +50,17 @@ void FlvMuxer::start(const EventPoller::Ptr &poller,const RtmpMediaSource::Ptr &
...
@@ -50,12 +50,17 @@ void FlvMuxer::start(const EventPoller::Ptr &poller,const RtmpMediaSource::Ptr &
}
}
strongSelf
->
onDetach
();
strongSelf
->
onDetach
();
});
});
_ring_reader
->
setReadCB
([
weakSelf
](
const
Rtmp
Packet
::
Ptr
&
pkt
){
_ring_reader
->
setReadCB
([
weakSelf
](
const
Rtmp
MediaSource
::
RingDataType
&
pkt
){
auto
strongSelf
=
weakSelf
.
lock
();
auto
strongSelf
=
weakSelf
.
lock
();
if
(
!
strongSelf
){
if
(
!
strongSelf
){
return
;
return
;
}
}
strongSelf
->
onWriteRtmp
(
pkt
);
int
i
=
0
;
int
size
=
pkt
->
size
();
pkt
->
for_each
([
&
](
const
RtmpPacket
::
Ptr
&
rtmp
){
strongSelf
->
onWriteRtmp
(
rtmp
,
++
i
==
size
);
});
});
});
}
}
...
@@ -84,11 +89,11 @@ void FlvMuxer::onWriteFlvHeader(const RtmpMediaSource::Ptr &mediaSrc) {
...
@@ -84,11 +89,11 @@ void FlvMuxer::onWriteFlvHeader(const RtmpMediaSource::Ptr &mediaSrc) {
}
}
//flv header
//flv header
onWrite
(
std
::
make_shared
<
BufferRaw
>
(
flv_file_header
,
sizeof
(
flv_file_header
)
-
1
));
onWrite
(
std
::
make_shared
<
BufferRaw
>
(
flv_file_header
,
sizeof
(
flv_file_header
)
-
1
)
,
false
);
auto
size
=
htonl
(
0
);
auto
size
=
htonl
(
0
);
//PreviousTagSize0 Always 0
//PreviousTagSize0 Always 0
onWrite
(
std
::
make_shared
<
BufferRaw
>
((
char
*
)
&
size
,
4
));
onWrite
(
std
::
make_shared
<
BufferRaw
>
((
char
*
)
&
size
,
4
)
,
false
);
auto
&
metadata
=
mediaSrc
->
getMetaData
();
auto
&
metadata
=
mediaSrc
->
getMetaData
();
...
@@ -97,12 +102,12 @@ void FlvMuxer::onWriteFlvHeader(const RtmpMediaSource::Ptr &mediaSrc) {
...
@@ -97,12 +102,12 @@ void FlvMuxer::onWriteFlvHeader(const RtmpMediaSource::Ptr &mediaSrc) {
//其实metadata没什么用,有些推流器不产生metadata
//其实metadata没什么用,有些推流器不产生metadata
AMFEncoder
invoke
;
AMFEncoder
invoke
;
invoke
<<
"onMetaData"
<<
metadata
;
invoke
<<
"onMetaData"
<<
metadata
;
onWriteFlvTag
(
MSG_DATA
,
std
::
make_shared
<
BufferString
>
(
invoke
.
data
()),
0
);
onWriteFlvTag
(
MSG_DATA
,
std
::
make_shared
<
BufferString
>
(
invoke
.
data
()),
0
,
false
);
}
}
//config frame
//config frame
mediaSrc
->
getConfigFrame
([
&
](
const
RtmpPacket
::
Ptr
&
pkt
){
mediaSrc
->
getConfigFrame
([
&
](
const
RtmpPacket
::
Ptr
&
pkt
){
onWriteRtmp
(
pkt
);
onWriteRtmp
(
pkt
,
true
);
});
});
}
}
...
@@ -125,29 +130,29 @@ public:
...
@@ -125,29 +130,29 @@ public:
#pragma pack(pop)
#pragma pack(pop)
#endif // defined(_WIN32)
#endif // defined(_WIN32)
void
FlvMuxer
::
onWriteFlvTag
(
const
RtmpPacket
::
Ptr
&
pkt
,
uint32_t
ui32TimeStamp
)
{
void
FlvMuxer
::
onWriteFlvTag
(
const
RtmpPacket
::
Ptr
&
pkt
,
uint32_t
ui32TimeStamp
,
bool
flush
)
{
onWriteFlvTag
(
pkt
->
typeId
,
pkt
,
ui32TimeStamp
);
onWriteFlvTag
(
pkt
->
typeId
,
pkt
,
ui32TimeStamp
,
flush
);
}
}
void
FlvMuxer
::
onWriteFlvTag
(
uint8_t
ui8Type
,
const
Buffer
::
Ptr
&
buffer
,
uint32_t
ui32TimeStamp
)
{
void
FlvMuxer
::
onWriteFlvTag
(
uint8_t
ui8Type
,
const
Buffer
::
Ptr
&
buffer
,
uint32_t
ui32TimeStamp
,
bool
flush
)
{
RtmpTagHeader
header
;
RtmpTagHeader
header
;
header
.
type
=
ui8Type
;
header
.
type
=
ui8Type
;
set_be24
(
header
.
data_size
,
buffer
->
size
());
set_be24
(
header
.
data_size
,
buffer
->
size
());
header
.
timestamp_ex
=
(
uint8_t
)
((
ui32TimeStamp
>>
24
)
&
0xff
);
header
.
timestamp_ex
=
(
uint8_t
)
((
ui32TimeStamp
>>
24
)
&
0xff
);
set_be24
(
header
.
timestamp
,
ui32TimeStamp
&
0xFFFFFF
);
set_be24
(
header
.
timestamp
,
ui32TimeStamp
&
0xFFFFFF
);
//tag header
//tag header
onWrite
(
std
::
make_shared
<
BufferRaw
>
((
char
*
)
&
header
,
sizeof
(
header
)));
onWrite
(
std
::
make_shared
<
BufferRaw
>
((
char
*
)
&
header
,
sizeof
(
header
))
,
false
);
//tag data
//tag data
onWrite
(
buffer
);
onWrite
(
buffer
,
false
);
auto
size
=
htonl
((
buffer
->
size
()
+
sizeof
(
header
)));
auto
size
=
htonl
((
buffer
->
size
()
+
sizeof
(
header
)));
//PreviousTagSize
//PreviousTagSize
onWrite
(
std
::
make_shared
<
BufferRaw
>
((
char
*
)
&
size
,
4
));
onWrite
(
std
::
make_shared
<
BufferRaw
>
((
char
*
)
&
size
,
4
)
,
flush
);
}
}
void
FlvMuxer
::
onWriteRtmp
(
const
RtmpPacket
::
Ptr
&
pkt
)
{
void
FlvMuxer
::
onWriteRtmp
(
const
RtmpPacket
::
Ptr
&
pkt
,
bool
flush
)
{
int64_t
dts_out
;
int64_t
dts_out
;
_stamp
[
pkt
->
typeId
%
2
].
revise
(
pkt
->
timeStamp
,
0
,
dts_out
,
dts_out
);
_stamp
[
pkt
->
typeId
%
2
].
revise
(
pkt
->
timeStamp
,
0
,
dts_out
,
dts_out
);
onWriteFlvTag
(
pkt
,
dts_out
);
onWriteFlvTag
(
pkt
,
dts_out
,
flush
);
}
}
void
FlvMuxer
::
stop
()
{
void
FlvMuxer
::
stop
()
{
...
@@ -187,7 +192,7 @@ void FlvRecorder::startRecord(const EventPoller::Ptr &poller,const RtmpMediaSour
...
@@ -187,7 +192,7 @@ void FlvRecorder::startRecord(const EventPoller::Ptr &poller,const RtmpMediaSour
start
(
poller
,
media
);
start
(
poller
,
media
);
}
}
void
FlvRecorder
::
onWrite
(
const
Buffer
::
Ptr
&
data
)
{
void
FlvRecorder
::
onWrite
(
const
Buffer
::
Ptr
&
data
,
bool
flush
)
{
lock_guard
<
recursive_mutex
>
lck
(
_file_mtx
);
lock_guard
<
recursive_mutex
>
lck
(
_file_mtx
);
if
(
_file
){
if
(
_file
){
fwrite
(
data
->
data
(),
data
->
size
(),
1
,
_file
.
get
());
fwrite
(
data
->
data
(),
data
->
size
(),
1
,
_file
.
get
());
...
...
src/Rtmp/FlvMuxer.h
查看文件 @
7805558d
...
@@ -27,14 +27,14 @@ public:
...
@@ -27,14 +27,14 @@ public:
void
stop
();
void
stop
();
protected
:
protected
:
void
start
(
const
EventPoller
::
Ptr
&
poller
,
const
RtmpMediaSource
::
Ptr
&
media
);
void
start
(
const
EventPoller
::
Ptr
&
poller
,
const
RtmpMediaSource
::
Ptr
&
media
);
virtual
void
onWrite
(
const
Buffer
::
Ptr
&
data
)
=
0
;
virtual
void
onWrite
(
const
Buffer
::
Ptr
&
data
,
bool
flush
)
=
0
;
virtual
void
onDetach
()
=
0
;
virtual
void
onDetach
()
=
0
;
virtual
std
::
shared_ptr
<
FlvMuxer
>
getSharedPtr
()
=
0
;
virtual
std
::
shared_ptr
<
FlvMuxer
>
getSharedPtr
()
=
0
;
private
:
private
:
void
onWriteFlvHeader
(
const
RtmpMediaSource
::
Ptr
&
media
);
void
onWriteFlvHeader
(
const
RtmpMediaSource
::
Ptr
&
media
);
void
onWriteRtmp
(
const
RtmpPacket
::
Ptr
&
pkt
);
void
onWriteRtmp
(
const
RtmpPacket
::
Ptr
&
pkt
,
bool
flush
);
void
onWriteFlvTag
(
const
RtmpPacket
::
Ptr
&
pkt
,
uint32_t
ui32TimeStamp
);
void
onWriteFlvTag
(
const
RtmpPacket
::
Ptr
&
pkt
,
uint32_t
ui32TimeStamp
,
bool
flush
);
void
onWriteFlvTag
(
uint8_t
ui8Type
,
const
Buffer
::
Ptr
&
buffer
,
uint32_t
ui32TimeStamp
);
void
onWriteFlvTag
(
uint8_t
ui8Type
,
const
Buffer
::
Ptr
&
buffer
,
uint32_t
ui32TimeStamp
,
bool
flush
);
private
:
private
:
RtmpMediaSource
::
RingType
::
RingReader
::
Ptr
_ring_reader
;
RtmpMediaSource
::
RingType
::
RingReader
::
Ptr
_ring_reader
;
//时间戳修整器
//时间戳修整器
...
@@ -50,7 +50,7 @@ public:
...
@@ -50,7 +50,7 @@ public:
void
startRecord
(
const
EventPoller
::
Ptr
&
poller
,
const
string
&
vhost
,
const
string
&
app
,
const
string
&
stream
,
const
string
&
file_path
);
void
startRecord
(
const
EventPoller
::
Ptr
&
poller
,
const
string
&
vhost
,
const
string
&
app
,
const
string
&
stream
,
const
string
&
file_path
);
void
startRecord
(
const
EventPoller
::
Ptr
&
poller
,
const
RtmpMediaSource
::
Ptr
&
media
,
const
string
&
file_path
);
void
startRecord
(
const
EventPoller
::
Ptr
&
poller
,
const
RtmpMediaSource
::
Ptr
&
media
,
const
string
&
file_path
);
private
:
private
:
virtual
void
onWrite
(
const
Buffer
::
Ptr
&
data
)
override
;
virtual
void
onWrite
(
const
Buffer
::
Ptr
&
data
,
bool
flush
)
override
;
virtual
void
onDetach
()
override
;
virtual
void
onDetach
()
override
;
virtual
std
::
shared_ptr
<
FlvMuxer
>
getSharedPtr
()
override
;
virtual
std
::
shared_ptr
<
FlvMuxer
>
getSharedPtr
()
override
;
private
:
private
:
...
...
src/Rtmp/Rtmp.cpp
查看文件 @
7805558d
...
@@ -36,11 +36,68 @@ AudioMeta::AudioMeta(const AudioTrack::Ptr &audio,int datarate){
...
@@ -36,11 +36,68 @@ AudioMeta::AudioMeta(const AudioTrack::Ptr &audio,int datarate){
_metadata
.
set
(
"audiosamplesize"
,
audio
->
getAudioSampleBit
());
_metadata
.
set
(
"audiosamplesize"
,
audio
->
getAudioSampleBit
());
}
}
if
(
audio
->
getAudioChannel
()
>
0
){
if
(
audio
->
getAudioChannel
()
>
0
){
_metadata
.
set
(
"audiochannels"
,
audio
->
getAudioChannel
());
_metadata
.
set
(
"stereo"
,
audio
->
getAudioChannel
()
>
1
);
_metadata
.
set
(
"stereo"
,
audio
->
getAudioChannel
()
>
1
);
}
}
_codecId
=
audio
->
getCodecId
();
_codecId
=
audio
->
getCodecId
();
_metadata
.
set
(
"audiocodecid"
,
Factory
::
getAmfByCodecId
(
_codecId
));
_metadata
.
set
(
"audiocodecid"
,
Factory
::
getAmfByCodecId
(
_codecId
));
}
}
uint8_t
getAudioRtmpFlags
(
const
Track
::
Ptr
&
track
){
switch
(
track
->
getTrackType
()){
case
TrackAudio
:
{
auto
audioTrack
=
dynamic_pointer_cast
<
AudioTrack
>
(
track
);
if
(
!
audioTrack
)
{
WarnL
<<
"获取AudioTrack失败"
;
return
0
;
}
auto
iSampleRate
=
audioTrack
->
getAudioSampleRate
();
auto
iChannel
=
audioTrack
->
getAudioChannel
();
auto
iSampleBit
=
audioTrack
->
getAudioSampleBit
();
uint8_t
flvAudioType
;
switch
(
track
->
getCodecId
()){
case
CodecG711A
:
flvAudioType
=
FLV_CODEC_G711A
;
break
;
case
CodecG711U
:
flvAudioType
=
FLV_CODEC_G711U
;
break
;
case
CodecAAC
:
{
flvAudioType
=
FLV_CODEC_AAC
;
//aac不通过flags获取音频相关信息
iSampleRate
=
44100
;
iSampleBit
=
16
;
iChannel
=
2
;
break
;
}
default
:
WarnL
<<
"该编码格式不支持转换为RTMP: "
<<
track
->
getCodecName
();
return
0
;
}
uint8_t
flvSampleRate
;
switch
(
iSampleRate
)
{
case
44100
:
flvSampleRate
=
3
;
break
;
case
22050
:
flvSampleRate
=
2
;
break
;
case
11025
:
flvSampleRate
=
1
;
break
;
case
16000
:
// nellymoser only
case
8000
:
// nellymoser only
case
5512
:
// not MP3
flvSampleRate
=
0
;
break
;
default
:
WarnL
<<
"FLV does not support sample rate "
<<
iSampleRate
<<
" ,choose from (44100, 22050, 11025)"
;
return
0
;
}
uint8_t
flvStereoOrMono
=
(
iChannel
>
1
);
uint8_t
flvSampleBit
=
iSampleBit
==
16
;
return
(
flvAudioType
<<
4
)
|
(
flvSampleRate
<<
2
)
|
(
flvSampleBit
<<
1
)
|
flvStereoOrMono
;
}
default
:
return
0
;
}
}
}
//
namespace
mediakit
}
//
namespace
mediakit
\ No newline at end of file
src/Rtmp/Rtmp.h
查看文件 @
7805558d
...
@@ -161,27 +161,26 @@ public:
...
@@ -161,27 +161,26 @@ public:
strBuf
=
std
::
move
(
that
.
strBuf
);
strBuf
=
std
::
move
(
that
.
strBuf
);
}
}
bool
isVideoKeyFrame
()
const
{
bool
isVideoKeyFrame
()
const
{
return
typeId
==
MSG_VIDEO
&&
(
uint8_t
)
strBuf
[
0
]
>>
4
==
FLV_KEY_FRAME
return
typeId
==
MSG_VIDEO
&&
(
uint8_t
)
strBuf
[
0
]
>>
4
==
FLV_KEY_FRAME
&&
(
uint8_t
)
strBuf
[
1
]
==
1
;
&&
(
uint8_t
)
strBuf
[
1
]
==
1
;
}
}
bool
isCfgFrame
()
const
{
bool
isCfgFrame
()
const
{
return
(
typeId
==
MSG_VIDEO
||
typeId
==
MSG_AUDIO
)
switch
(
typeId
){
&&
(
uint8_t
)
strBuf
[
1
]
==
0
;
case
MSG_VIDEO
:
return
strBuf
[
1
]
==
0
;
case
MSG_AUDIO
:
{
switch
(
getMediaType
()){
case
FLV_CODEC_AAC
:
return
strBuf
[
1
]
==
0
;
default
:
return
false
;
}
}
int
getMediaType
()
const
{
switch
(
typeId
)
{
case
MSG_VIDEO
:
{
return
(
uint8_t
)
strBuf
[
0
]
&
0x0F
;
}
}
break
;
default
:
return
false
;
case
MSG_AUDIO
:
{
return
(
uint8_t
)
strBuf
[
0
]
>>
4
;
}
}
break
;
default
:
break
;
}
}
return
0
;
int
getMediaType
()
const
{
switch
(
typeId
)
{
case
MSG_VIDEO
:
return
(
uint8_t
)
strBuf
[
0
]
&
0x0F
;
case
MSG_AUDIO
:
return
(
uint8_t
)
strBuf
[
0
]
>>
4
;
default
:
return
0
;
}
}
}
int
getAudioSampleRate
()
const
{
int
getAudioSampleRate
()
const
{
if
(
typeId
!=
MSG_AUDIO
)
{
if
(
typeId
!=
MSG_AUDIO
)
{
...
@@ -209,8 +208,6 @@ public:
...
@@ -209,8 +208,6 @@ public:
}
}
};
};
/**
/**
* rtmp metadata基类,用于描述rtmp格式信息
* rtmp metadata基类,用于描述rtmp格式信息
*/
*/
...
@@ -316,6 +313,8 @@ private:
...
@@ -316,6 +313,8 @@ private:
CodecId
_codecId
;
CodecId
_codecId
;
};
};
//根据音频track获取flags
uint8_t
getAudioRtmpFlags
(
const
Track
::
Ptr
&
track
);
}
//namespace mediakit
}
//namespace mediakit
...
...
src/Rtmp/RtmpDemuxer.cpp
查看文件 @
7805558d
...
@@ -15,14 +15,55 @@ namespace mediakit {
...
@@ -15,14 +15,55 @@ namespace mediakit {
void
RtmpDemuxer
::
loadMetaData
(
const
AMFValue
&
val
){
void
RtmpDemuxer
::
loadMetaData
(
const
AMFValue
&
val
){
try
{
try
{
makeVideoTrack
(
val
[
"videocodecid"
]);
int
audiosamplerate
=
0
;
makeAudioTrack
(
val
[
"audiocodecid"
]);
int
audiochannels
=
0
;
int
audiosamplesize
=
0
;
const
AMFValue
*
audiocodecid
=
nullptr
;
const
AMFValue
*
videocodecid
=
nullptr
;
val
.
object_for_each
([
&
](
const
string
&
key
,
const
AMFValue
&
val
)
{
val
.
object_for_each
([
&
](
const
string
&
key
,
const
AMFValue
&
val
)
{
if
(
key
==
"duration"
)
{
if
(
key
==
"duration"
)
{
_fDuration
=
val
.
as_number
();
_fDuration
=
val
.
as_number
();
return
;
return
;
}
}
if
(
key
==
"audiosamplerate"
){
audiosamplerate
=
val
.
as_integer
();
return
;
}
if
(
key
==
"audiosamplesize"
){
audiosamplesize
=
val
.
as_integer
();
return
;
}
if
(
key
==
"stereo"
){
audiochannels
=
val
.
as_boolean
()
?
2
:
1
;
return
;
}
if
(
key
==
"videocodecid"
){
//找到视频
videocodecid
=
&
val
;
return
;
}
if
(
key
==
"audiocodecid"
){
//找到音频
audiocodecid
=
&
val
;
return
;
}
});
});
if
(
videocodecid
){
//有视频
makeVideoTrack
(
*
videocodecid
);
}
if
(
audiocodecid
){
//有音频
makeAudioTrack
(
*
audiocodecid
,
audiosamplerate
,
audiochannels
,
audiosamplesize
);
}
}
catch
(
std
::
exception
&
ex
){
}
catch
(
std
::
exception
&
ex
){
WarnL
<<
ex
.
what
();
WarnL
<<
ex
.
what
();
}
}
...
@@ -46,7 +87,7 @@ bool RtmpDemuxer::inputRtmp(const RtmpPacket::Ptr &pkt) {
...
@@ -46,7 +87,7 @@ bool RtmpDemuxer::inputRtmp(const RtmpPacket::Ptr &pkt) {
if
(
!
_tryedGetAudioTrack
)
{
if
(
!
_tryedGetAudioTrack
)
{
_tryedGetAudioTrack
=
true
;
_tryedGetAudioTrack
=
true
;
auto
codec
=
AMFValue
(
pkt
->
getMediaType
());
auto
codec
=
AMFValue
(
pkt
->
getMediaType
());
makeAudioTrack
(
codec
);
makeAudioTrack
(
codec
,
pkt
->
getAudioSampleRate
(),
pkt
->
getAudioChannel
(),
pkt
->
getAudioSampleBit
()
);
}
}
if
(
_audioRtmpDecoder
){
if
(
_audioRtmpDecoder
){
_audioRtmpDecoder
->
inputRtmp
(
pkt
,
false
);
_audioRtmpDecoder
->
inputRtmp
(
pkt
,
false
);
...
@@ -69,6 +110,7 @@ void RtmpDemuxer::makeVideoTrack(const AMFValue &videoCodec) {
...
@@ -69,6 +110,7 @@ void RtmpDemuxer::makeVideoTrack(const AMFValue &videoCodec) {
//设置rtmp解码器代理,生成的frame写入该Track
//设置rtmp解码器代理,生成的frame写入该Track
_videoRtmpDecoder
->
addDelegate
(
_videoTrack
);
_videoRtmpDecoder
->
addDelegate
(
_videoTrack
);
onAddTrack
(
_videoTrack
);
onAddTrack
(
_videoTrack
);
_tryedGetVideoTrack
=
true
;
}
else
{
}
else
{
//找不到相应的rtmp解码器,该track无效
//找不到相应的rtmp解码器,该track无效
_videoTrack
.
reset
();
_videoTrack
.
reset
();
...
@@ -76,9 +118,9 @@ void RtmpDemuxer::makeVideoTrack(const AMFValue &videoCodec) {
...
@@ -76,9 +118,9 @@ void RtmpDemuxer::makeVideoTrack(const AMFValue &videoCodec) {
}
}
}
}
void
RtmpDemuxer
::
makeAudioTrack
(
const
AMFValue
&
audioCodec
)
{
void
RtmpDemuxer
::
makeAudioTrack
(
const
AMFValue
&
audioCodec
,
int
sample_rate
,
int
channels
,
int
sample_bit
)
{
//生成Track对象
//生成Track对象
_audioTrack
=
dynamic_pointer_cast
<
AudioTrack
>
(
Factory
::
getAudioTrackByAmf
(
audioCodec
));
_audioTrack
=
dynamic_pointer_cast
<
AudioTrack
>
(
Factory
::
getAudioTrackByAmf
(
audioCodec
,
sample_rate
,
channels
,
sample_bit
));
if
(
_audioTrack
)
{
if
(
_audioTrack
)
{
//生成rtmpCodec对象以便解码rtmp
//生成rtmpCodec对象以便解码rtmp
_audioRtmpDecoder
=
Factory
::
getRtmpCodecByTrack
(
_audioTrack
);
_audioRtmpDecoder
=
Factory
::
getRtmpCodecByTrack
(
_audioTrack
);
...
@@ -86,6 +128,7 @@ void RtmpDemuxer::makeAudioTrack(const AMFValue &audioCodec) {
...
@@ -86,6 +128,7 @@ void RtmpDemuxer::makeAudioTrack(const AMFValue &audioCodec) {
//设置rtmp解码器代理,生成的frame写入该Track
//设置rtmp解码器代理,生成的frame写入该Track
_audioRtmpDecoder
->
addDelegate
(
_audioTrack
);
_audioRtmpDecoder
->
addDelegate
(
_audioTrack
);
onAddTrack
(
_audioTrack
);
onAddTrack
(
_audioTrack
);
_tryedGetAudioTrack
=
true
;
}
else
{
}
else
{
//找不到相应的rtmp解码器,该track无效
//找不到相应的rtmp解码器,该track无效
_audioTrack
.
reset
();
_audioTrack
.
reset
();
...
...
src/Rtmp/RtmpDemuxer.h
查看文件 @
7805558d
...
@@ -40,7 +40,7 @@ public:
...
@@ -40,7 +40,7 @@ public:
bool
inputRtmp
(
const
RtmpPacket
::
Ptr
&
pkt
);
bool
inputRtmp
(
const
RtmpPacket
::
Ptr
&
pkt
);
private
:
private
:
void
makeVideoTrack
(
const
AMFValue
&
val
);
void
makeVideoTrack
(
const
AMFValue
&
val
);
void
makeAudioTrack
(
const
AMFValue
&
val
);
void
makeAudioTrack
(
const
AMFValue
&
val
,
int
sample_rate
,
int
channels
,
int
sample_bit
);
private
:
private
:
bool
_tryedGetVideoTrack
=
false
;
bool
_tryedGetVideoTrack
=
false
;
bool
_tryedGetAudioTrack
=
false
;
bool
_tryedGetAudioTrack
=
false
;
...
...
src/Rtmp/RtmpMediaSource.h
查看文件 @
7805558d
...
@@ -33,6 +33,9 @@ using namespace toolkit;
...
@@ -33,6 +33,9 @@ using namespace toolkit;
#define RTMP_GOP_SIZE 512
#define RTMP_GOP_SIZE 512
namespace
mediakit
{
namespace
mediakit
{
typedef
VideoPacketCache
<
RtmpPacket
>
RtmpVideoCache
;
typedef
AudioPacketCache
<
RtmpPacket
>
RtmpAudioCache
;
/**
/**
* rtmp媒体源的数据抽象
* rtmp媒体源的数据抽象
* rtmp有关键的三要素,分别是metadata、config帧,普通帧
* rtmp有关键的三要素,分别是metadata、config帧,普通帧
...
@@ -40,10 +43,11 @@ namespace mediakit {
...
@@ -40,10 +43,11 @@ namespace mediakit {
* 只要生成了这三要素,那么要实现rtmp推流、rtmp服务器就很简单了
* 只要生成了这三要素,那么要实现rtmp推流、rtmp服务器就很简单了
* rtmp推拉流协议中,先传递metadata,然后传递config帧,然后一直传递普通帧
* rtmp推拉流协议中,先传递metadata,然后传递config帧,然后一直传递普通帧
*/
*/
class
RtmpMediaSource
:
public
MediaSource
,
public
RingDelegate
<
RtmpPacket
::
Ptr
>
{
class
RtmpMediaSource
:
public
MediaSource
,
public
RingDelegate
<
RtmpPacket
::
Ptr
>
,
public
RtmpVideoCache
,
public
RtmpAudioCache
{
public
:
public
:
typedef
std
::
shared_ptr
<
RtmpMediaSource
>
Ptr
;
typedef
std
::
shared_ptr
<
RtmpMediaSource
>
Ptr
;
typedef
RingBuffer
<
RtmpPacket
::
Ptr
>
RingType
;
typedef
std
::
shared_ptr
<
List
<
RtmpPacket
::
Ptr
>
>
RingDataType
;
typedef
RingBuffer
<
RingDataType
>
RingType
;
/**
/**
* 构造函数
* 构造函数
...
@@ -122,6 +126,9 @@ public:
...
@@ -122,6 +126,9 @@ public:
return
;
return
;
}
}
//保存当前时间戳
_track_stamps_map
[
pkt
->
typeId
]
=
pkt
->
timeStamp
;
if
(
!
_ring
)
{
if
(
!
_ring
)
{
weak_ptr
<
RtmpMediaSource
>
weakSelf
=
dynamic_pointer_cast
<
RtmpMediaSource
>
(
shared_from_this
());
weak_ptr
<
RtmpMediaSource
>
weakSelf
=
dynamic_pointer_cast
<
RtmpMediaSource
>
(
shared_from_this
());
auto
lam
=
[
weakSelf
](
const
EventPoller
::
Ptr
&
,
int
size
,
bool
)
{
auto
lam
=
[
weakSelf
](
const
EventPoller
::
Ptr
&
,
int
size
,
bool
)
{
...
@@ -142,9 +149,12 @@ public:
...
@@ -142,9 +149,12 @@ public:
regist
();
regist
();
}
}
}
}
_track_stamps_map
[
pkt
->
typeId
]
=
pkt
->
timeStamp
;
//不存在视频,为了减少缓存延时,那么关闭GOP缓存
if
(
pkt
->
typeId
==
MSG_VIDEO
){
_ring
->
write
(
pkt
,
_have_video
?
pkt
->
isVideoKeyFrame
()
:
true
);
RtmpVideoCache
::
inputVideo
(
pkt
,
key
);
}
else
{
RtmpAudioCache
::
inputAudio
(
pkt
);
}
}
}
/**
/**
...
@@ -163,6 +173,25 @@ public:
...
@@ -163,6 +173,25 @@ public:
}
}
private
:
private
:
/**
* 批量flush时间戳相同的视频rtmp包时触发该函数
* @param rtmp_list 时间戳相同的rtmp包列表
* @param key_pos 是否包含关键帧
*/
void
onFlushVideo
(
std
::
shared_ptr
<
List
<
RtmpPacket
::
Ptr
>
>
&
rtmp_list
,
bool
key_pos
)
override
{
_ring
->
write
(
rtmp_list
,
key_pos
);
}
/**
* 批量flush一定数量的音频rtmp包时触发该函数
* @param rtmp_list rtmp包列表
*/
void
onFlushAudio
(
std
::
shared_ptr
<
List
<
RtmpPacket
::
Ptr
>
>
&
rtmp_list
)
override
{
//只有音频的话,就不存在gop缓存的意义
_ring
->
write
(
rtmp_list
,
!
_have_video
);
}
/**
/**
* 每次增减消费者都会触发该函数
* 每次增减消费者都会触发该函数
*/
*/
...
@@ -177,7 +206,7 @@ private:
...
@@ -177,7 +206,7 @@ private:
bool
_have_video
=
false
;
bool
_have_video
=
false
;
mutable
recursive_mutex
_mtx
;
mutable
recursive_mutex
_mtx
;
AMFValue
_metadata
;
AMFValue
_metadata
;
Ring
Buffer
<
RtmpPacket
::
Ptr
>
::
Ptr
_ring
;
Ring
Type
::
Ptr
_ring
;
unordered_map
<
int
,
uint32_t
>
_track_stamps_map
;
unordered_map
<
int
,
uint32_t
>
_track_stamps_map
;
unordered_map
<
int
,
RtmpPacket
::
Ptr
>
_config_frame_map
;
unordered_map
<
int
,
RtmpPacket
::
Ptr
>
_config_frame_map
;
};
};
...
...
src/Rtmp/RtmpPlayer.cpp
查看文件 @
7805558d
...
@@ -118,6 +118,8 @@ void RtmpPlayer::onPlayResult_l(const SockException &ex , bool handshakeComplete
...
@@ -118,6 +118,8 @@ void RtmpPlayer::onPlayResult_l(const SockException &ex , bool handshakeComplete
//开始播放阶段
//开始播放阶段
_pPlayTimer
.
reset
();
_pPlayTimer
.
reset
();
onPlayResult
(
ex
);
onPlayResult
(
ex
);
//是否为性能测试模式
_benchmark_mode
=
(
*
this
)[
Client
::
kBenchmarkMode
].
as
<
int
>
();
}
else
if
(
ex
)
{
}
else
if
(
ex
)
{
//播放成功后异常断开回调
//播放成功后异常断开回调
onShutdown
(
ex
);
onShutdown
(
ex
);
...
@@ -146,6 +148,11 @@ void RtmpPlayer::onConnect(const SockException &err){
...
@@ -146,6 +148,11 @@ void RtmpPlayer::onConnect(const SockException &err){
}
}
void
RtmpPlayer
::
onRecv
(
const
Buffer
::
Ptr
&
pBuf
){
void
RtmpPlayer
::
onRecv
(
const
Buffer
::
Ptr
&
pBuf
){
try
{
try
{
if
(
_benchmark_mode
&&
!
_pPlayTimer
){
//在性能测试模式下,如果rtmp握手完毕后,不再解析rtmp包
_mediaTicker
.
resetTime
();
return
;
}
onParseRtmp
(
pBuf
->
data
(),
pBuf
->
size
());
onParseRtmp
(
pBuf
->
data
(),
pBuf
->
size
());
}
catch
(
exception
&
e
)
{
}
catch
(
exception
&
e
)
{
SockException
ex
(
Err_other
,
e
.
what
());
SockException
ex
(
Err_other
,
e
.
what
());
...
...
src/Rtmp/RtmpPlayer.h
查看文件 @
7805558d
...
@@ -102,6 +102,8 @@ private:
...
@@ -102,6 +102,8 @@ private:
uint32_t
_aiNowStamp
[
2
]
=
{
0
,
0
};
uint32_t
_aiNowStamp
[
2
]
=
{
0
,
0
};
Ticker
_aNowStampTicker
[
2
];
Ticker
_aNowStampTicker
[
2
];
bool
_metadata_got
=
false
;
bool
_metadata_got
=
false
;
//是否为性能测试模式
bool
_benchmark_mode
=
false
;
};
};
}
/* namespace mediakit */
}
/* namespace mediakit */
...
...
src/Rtmp/RtmpPusher.cpp
查看文件 @
7805558d
...
@@ -200,12 +200,21 @@ inline void RtmpPusher::send_metaData(){
...
@@ -200,12 +200,21 @@ inline void RtmpPusher::send_metaData(){
_pRtmpReader
=
src
->
getRing
()
->
attach
(
getPoller
());
_pRtmpReader
=
src
->
getRing
()
->
attach
(
getPoller
());
weak_ptr
<
RtmpPusher
>
weakSelf
=
dynamic_pointer_cast
<
RtmpPusher
>
(
shared_from_this
());
weak_ptr
<
RtmpPusher
>
weakSelf
=
dynamic_pointer_cast
<
RtmpPusher
>
(
shared_from_this
());
_pRtmpReader
->
setReadCB
([
weakSelf
](
const
Rtmp
Packet
::
Ptr
&
pkt
){
_pRtmpReader
->
setReadCB
([
weakSelf
](
const
Rtmp
MediaSource
::
RingDataType
&
pkt
){
auto
strongSelf
=
weakSelf
.
lock
();
auto
strongSelf
=
weakSelf
.
lock
();
if
(
!
strongSelf
)
{
if
(
!
strongSelf
)
{
return
;
return
;
}
}
strongSelf
->
sendRtmp
(
pkt
->
typeId
,
strongSelf
->
_ui32StreamId
,
pkt
,
pkt
->
timeStamp
,
pkt
->
chunkId
);
int
i
=
0
;
int
size
=
pkt
->
size
();
strongSelf
->
setSendFlushFlag
(
false
);
pkt
->
for_each
([
&
](
const
RtmpPacket
::
Ptr
&
rtmp
){
if
(
++
i
==
size
){
strongSelf
->
setSendFlushFlag
(
true
);
}
strongSelf
->
sendRtmp
(
rtmp
->
typeId
,
strongSelf
->
_ui32StreamId
,
rtmp
,
rtmp
->
timeStamp
,
rtmp
->
chunkId
);
});
});
});
_pRtmpReader
->
setDetachCB
([
weakSelf
](){
_pRtmpReader
->
setDetachCB
([
weakSelf
](){
auto
strongSelf
=
weakSelf
.
lock
();
auto
strongSelf
=
weakSelf
.
lock
();
...
...
src/Rtmp/RtmpSession.cpp
查看文件 @
7805558d
...
@@ -193,7 +193,6 @@ void RtmpSession::onCmd_deleteStream(AMFDecoder &dec) {
...
@@ -193,7 +193,6 @@ void RtmpSession::onCmd_deleteStream(AMFDecoder &dec) {
throw
std
::
runtime_error
(
StrPrinter
<<
"Stop publishing"
<<
endl
);
throw
std
::
runtime_error
(
StrPrinter
<<
"Stop publishing"
<<
endl
);
}
}
void
RtmpSession
::
sendPlayResponse
(
const
string
&
err
,
const
RtmpMediaSource
::
Ptr
&
src
){
void
RtmpSession
::
sendPlayResponse
(
const
string
&
err
,
const
RtmpMediaSource
::
Ptr
&
src
){
bool
authSuccess
=
err
.
empty
();
bool
authSuccess
=
err
.
empty
();
bool
ok
=
(
src
.
operator
bool
()
&&
authSuccess
);
bool
ok
=
(
src
.
operator
bool
()
&&
authSuccess
);
...
@@ -272,12 +271,23 @@ void RtmpSession::sendPlayResponse(const string &err,const RtmpMediaSource::Ptr
...
@@ -272,12 +271,23 @@ void RtmpSession::sendPlayResponse(const string &err,const RtmpMediaSource::Ptr
_pRingReader
=
src
->
getRing
()
->
attach
(
getPoller
());
_pRingReader
=
src
->
getRing
()
->
attach
(
getPoller
());
weak_ptr
<
RtmpSession
>
weakSelf
=
dynamic_pointer_cast
<
RtmpSession
>
(
shared_from_this
());
weak_ptr
<
RtmpSession
>
weakSelf
=
dynamic_pointer_cast
<
RtmpSession
>
(
shared_from_this
());
_pRingReader
->
setReadCB
([
weakSelf
](
const
Rtmp
Packet
::
Ptr
&
pkt
)
{
_pRingReader
->
setReadCB
([
weakSelf
](
const
Rtmp
MediaSource
::
RingDataType
&
pkt
)
{
auto
strongSelf
=
weakSelf
.
lock
();
auto
strongSelf
=
weakSelf
.
lock
();
if
(
!
strongSelf
)
{
if
(
!
strongSelf
)
{
return
;
return
;
}
}
strongSelf
->
onSendMedia
(
pkt
);
if
(
strongSelf
->
_paused
){
return
;
}
int
i
=
0
;
int
size
=
pkt
->
size
();
strongSelf
->
setSendFlushFlag
(
false
);
pkt
->
for_each
([
&
](
const
RtmpPacket
::
Ptr
&
rtmp
){
if
(
++
i
==
size
){
strongSelf
->
setSendFlushFlag
(
true
);
}
strongSelf
->
onSendMedia
(
rtmp
);
});
});
});
_pRingReader
->
setDetachCB
([
weakSelf
]()
{
_pRingReader
->
setDetachCB
([
weakSelf
]()
{
auto
strongSelf
=
weakSelf
.
lock
();
auto
strongSelf
=
weakSelf
.
lock
();
...
@@ -393,24 +403,9 @@ void RtmpSession::onCmd_pause(AMFDecoder &dec) {
...
@@ -393,24 +403,9 @@ void RtmpSession::onCmd_pause(AMFDecoder &dec) {
status
.
set
(
"code"
,
paused
?
"NetStream.Pause.Notify"
:
"NetStream.Unpause.Notify"
);
status
.
set
(
"code"
,
paused
?
"NetStream.Pause.Notify"
:
"NetStream.Unpause.Notify"
);
status
.
set
(
"description"
,
paused
?
"Paused stream."
:
"Unpaused stream."
);
status
.
set
(
"description"
,
paused
?
"Paused stream."
:
"Unpaused stream."
);
sendReply
(
"onStatus"
,
nullptr
,
status
);
sendReply
(
"onStatus"
,
nullptr
,
status
);
//streamBegin
//streamBegin
sendUserControl
(
paused
?
CONTROL_STREAM_EOF
:
CONTROL_STREAM_BEGIN
,
sendUserControl
(
paused
?
CONTROL_STREAM_EOF
:
CONTROL_STREAM_BEGIN
,
STREAM_MEDIA
);
STREAM_MEDIA
);
_paused
=
paused
;
if
(
!
_pRingReader
)
{
throw
std
::
runtime_error
(
"Rtmp not started yet!"
);
}
if
(
paused
)
{
_pRingReader
->
setReadCB
(
nullptr
);
}
else
{
weak_ptr
<
RtmpSession
>
weakSelf
=
dynamic_pointer_cast
<
RtmpSession
>
(
shared_from_this
());
_pRingReader
->
setReadCB
([
weakSelf
](
const
RtmpPacket
::
Ptr
&
pkt
)
{
auto
strongSelf
=
weakSelf
.
lock
();
if
(
!
strongSelf
)
{
return
;
}
strongSelf
->
onSendMedia
(
pkt
);
});
}
}
}
void
RtmpSession
::
setMetaData
(
AMFDecoder
&
dec
)
{
void
RtmpSession
::
setMetaData
(
AMFDecoder
&
dec
)
{
...
...
src/Rtmp/RtmpSession.h
查看文件 @
7805558d
...
@@ -80,13 +80,14 @@ private:
...
@@ -80,13 +80,14 @@ private:
double
_dNowReqID
=
0
;
double
_dNowReqID
=
0
;
bool
_set_meta_data
=
false
;
bool
_set_meta_data
=
false
;
Ticker
_ticker
;
//数据接收时间
Ticker
_ticker
;
//数据接收时间
R
ingBuffer
<
RtmpPacket
::
Ptr
>
::
RingReader
::
Ptr
_pRingReader
;
R
tmpMediaSource
::
RingType
::
RingReader
::
Ptr
_pRingReader
;
std
::
shared_ptr
<
RtmpMediaSourceImp
>
_pPublisherSrc
;
std
::
shared_ptr
<
RtmpMediaSourceImp
>
_pPublisherSrc
;
std
::
weak_ptr
<
RtmpMediaSource
>
_pPlayerSrc
;
std
::
weak_ptr
<
RtmpMediaSource
>
_pPlayerSrc
;
//时间戳修整器
//时间戳修整器
Stamp
_stamp
[
2
];
Stamp
_stamp
[
2
];
//消耗的总流量
//消耗的总流量
uint64_t
_ui64TotalBytes
=
0
;
uint64_t
_ui64TotalBytes
=
0
;
bool
_paused
=
false
;
};
};
...
...
src/Rtp/RtpProcess.cpp
查看文件 @
7805558d
...
@@ -204,10 +204,10 @@ void RtpProcess::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t d
...
@@ -204,10 +204,10 @@ void RtpProcess::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t d
pts
/=
90
;
pts
/=
90
;
dts
/=
90
;
dts
/=
90
;
_stamps
[
codecid
].
revise
(
dts
,
pts
,
dts
,
pts
,
false
);
_stamps
[
codecid
].
revise
(
dts
,
pts
,
dts
,
pts
,
false
);
_dts
=
dts
;
switch
(
codecid
)
{
switch
(
codecid
)
{
case
STREAM_VIDEO_H264
:
{
case
STREAM_VIDEO_H264
:
{
_dts
=
dts
;
if
(
!
_codecid_video
)
{
if
(
!
_codecid_video
)
{
//获取到视频
//获取到视频
_codecid_video
=
codecid
;
_codecid_video
=
codecid
;
...
@@ -232,6 +232,7 @@ void RtpProcess::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t d
...
@@ -232,6 +232,7 @@ void RtpProcess::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t d
}
}
case
STREAM_VIDEO_H265
:
{
case
STREAM_VIDEO_H265
:
{
_dts
=
dts
;
if
(
!
_codecid_video
)
{
if
(
!
_codecid_video
)
{
//获取到视频
//获取到视频
_codecid_video
=
codecid
;
_codecid_video
=
codecid
;
...
@@ -254,6 +255,7 @@ void RtpProcess::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t d
...
@@ -254,6 +255,7 @@ void RtpProcess::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t d
}
}
case
STREAM_AUDIO_AAC
:
{
case
STREAM_AUDIO_AAC
:
{
_dts
=
dts
;
if
(
!
_codecid_audio
)
{
if
(
!
_codecid_audio
)
{
//获取到音频
//获取到音频
_codecid_audio
=
codecid
;
_codecid_audio
=
codecid
;
...
...
src/Rtsp/Rtsp.cpp
查看文件 @
7805558d
...
@@ -16,7 +16,7 @@ namespace mediakit{
...
@@ -16,7 +16,7 @@ namespace mediakit{
int
RtpPayload
::
getClockRate
(
int
pt
){
int
RtpPayload
::
getClockRate
(
int
pt
){
switch
(
pt
){
switch
(
pt
){
#define SWITCH_CASE(name, type, value, clock_rate, channel) case value : return clock_rate;
#define SWITCH_CASE(name, type, value, clock_rate, channel
, codec_id
) case value : return clock_rate;
RTP_PT_MAP
(
SWITCH_CASE
)
RTP_PT_MAP
(
SWITCH_CASE
)
#undef SWITCH_CASE
#undef SWITCH_CASE
default
:
return
90000
;
default
:
return
90000
;
...
@@ -25,7 +25,7 @@ int RtpPayload::getClockRate(int pt){
...
@@ -25,7 +25,7 @@ int RtpPayload::getClockRate(int pt){
TrackType
RtpPayload
::
getTrackType
(
int
pt
){
TrackType
RtpPayload
::
getTrackType
(
int
pt
){
switch
(
pt
){
switch
(
pt
){
#define SWITCH_CASE(name, type, value, clock_rate, channel) case value : return type;
#define SWITCH_CASE(name, type, value, clock_rate, channel
, codec_id
) case value : return type;
RTP_PT_MAP
(
SWITCH_CASE
)
RTP_PT_MAP
(
SWITCH_CASE
)
#undef SWITCH_CASE
#undef SWITCH_CASE
default
:
return
TrackInvalid
;
default
:
return
TrackInvalid
;
...
@@ -34,7 +34,7 @@ TrackType RtpPayload::getTrackType(int pt){
...
@@ -34,7 +34,7 @@ TrackType RtpPayload::getTrackType(int pt){
int
RtpPayload
::
getAudioChannel
(
int
pt
){
int
RtpPayload
::
getAudioChannel
(
int
pt
){
switch
(
pt
){
switch
(
pt
){
#define SWITCH_CASE(name, type, value, clock_rate, channel) case value : return channel;
#define SWITCH_CASE(name, type, value, clock_rate, channel
, codec_id
) case value : return channel;
RTP_PT_MAP
(
SWITCH_CASE
)
RTP_PT_MAP
(
SWITCH_CASE
)
#undef SWITCH_CASE
#undef SWITCH_CASE
default
:
return
1
;
default
:
return
1
;
...
@@ -43,13 +43,22 @@ int RtpPayload::getAudioChannel(int pt){
...
@@ -43,13 +43,22 @@ int RtpPayload::getAudioChannel(int pt){
const
char
*
RtpPayload
::
getName
(
int
pt
){
const
char
*
RtpPayload
::
getName
(
int
pt
){
switch
(
pt
){
switch
(
pt
){
#define SWITCH_CASE(name, type, value, clock_rate, channel) case value : return #name;
#define SWITCH_CASE(name, type, value, clock_rate, channel
, codec_id
) case value : return #name;
RTP_PT_MAP
(
SWITCH_CASE
)
RTP_PT_MAP
(
SWITCH_CASE
)
#undef SWITCH_CASE
#undef SWITCH_CASE
default
:
return
"unknown payload type"
;
default
:
return
"unknown payload type"
;
}
}
}
}
CodecId
RtpPayload
::
getCodecId
(
int
pt
)
{
switch
(
pt
)
{
#define SWITCH_CASE(name, type, value, clock_rate, channel, codec_id) case value : return codec_id;
RTP_PT_MAP
(
SWITCH_CASE
)
#undef SWITCH_CASE
default
:
return
CodecInvalid
;
}
}
static
void
getAttrSdp
(
const
map
<
string
,
string
>
&
attr
,
_StrPrinter
&
printer
){
static
void
getAttrSdp
(
const
map
<
string
,
string
>
&
attr
,
_StrPrinter
&
printer
){
const
map
<
string
,
string
>::
value_type
*
ptr
=
nullptr
;
const
map
<
string
,
string
>::
value_type
*
ptr
=
nullptr
;
for
(
auto
&
pr
:
attr
){
for
(
auto
&
pr
:
attr
){
...
@@ -70,7 +79,7 @@ static void getAttrSdp(const map<string, string> &attr, _StrPrinter &printer){
...
@@ -70,7 +79,7 @@ static void getAttrSdp(const map<string, string> &attr, _StrPrinter &printer){
string
SdpTrack
::
getName
()
const
{
string
SdpTrack
::
getName
()
const
{
switch
(
_pt
){
switch
(
_pt
){
#define SWITCH_CASE(name, type, value, clock_rate, channel) case value : return #name;
#define SWITCH_CASE(name, type, value, clock_rate, channel
, codec_id
) case value : return #name;
RTP_PT_MAP
(
SWITCH_CASE
)
RTP_PT_MAP
(
SWITCH_CASE
)
#undef SWITCH_CASE
#undef SWITCH_CASE
default
:
return
_codec
;
default
:
return
_codec
;
...
@@ -172,6 +181,7 @@ void SdpParser::load(const string &sdp) {
...
@@ -172,6 +181,7 @@ void SdpParser::load(const string &sdp) {
if
(
4
==
sscanf
(
opt_val
.
data
(),
" %15[^ ] %d %15[^ ] %d"
,
type
,
&
port
,
rtp
,
&
pt
))
{
if
(
4
==
sscanf
(
opt_val
.
data
(),
" %15[^ ] %d %15[^ ] %d"
,
type
,
&
port
,
rtp
,
&
pt
))
{
track
->
_pt
=
pt
;
track
->
_pt
=
pt
;
track
->
_samplerate
=
RtpPayload
::
getClockRate
(
pt
)
;
track
->
_samplerate
=
RtpPayload
::
getClockRate
(
pt
)
;
track
->
_channel
=
RtpPayload
::
getAudioChannel
(
pt
);
track
->
_type
=
toTrackType
(
type
);
track
->
_type
=
toTrackType
(
type
);
track
->
_m
=
opt_val
;
track
->
_m
=
opt_val
;
track
->
_port
=
port
;
track
->
_port
=
port
;
...
@@ -214,9 +224,14 @@ void SdpParser::load(const string &sdp) {
...
@@ -214,9 +224,14 @@ void SdpParser::load(const string &sdp) {
it
=
track
.
_attr
.
find
(
"rtpmap"
);
it
=
track
.
_attr
.
find
(
"rtpmap"
);
if
(
it
!=
track
.
_attr
.
end
()){
if
(
it
!=
track
.
_attr
.
end
()){
auto
rtpmap
=
it
->
second
;
auto
rtpmap
=
it
->
second
;
int
pt
,
samplerate
;
int
pt
,
samplerate
,
channel
;
char
codec
[
16
]
=
{
0
};
char
codec
[
16
]
=
{
0
};
if
(
3
==
sscanf
(
rtpmap
.
data
(),
"%d %15[^/]/%d"
,
&
pt
,
codec
,
&
samplerate
))
{
if
(
4
==
sscanf
(
rtpmap
.
data
(),
"%d %15[^/]/%d/%d"
,
&
pt
,
codec
,
&
samplerate
,
&
channel
))
{
track
.
_pt
=
pt
;
track
.
_codec
=
codec
;
track
.
_samplerate
=
samplerate
;
track
.
_channel
=
channel
;
}
else
if
(
3
==
sscanf
(
rtpmap
.
data
(),
"%d %15[^/]/%d"
,
&
pt
,
codec
,
&
samplerate
))
{
track
.
_pt
=
pt
;
track
.
_pt
=
pt
;
track
.
_codec
=
codec
;
track
.
_codec
=
codec
;
track
.
_samplerate
=
samplerate
;
track
.
_samplerate
=
samplerate
;
...
...
src/Rtsp/Rtsp.h
查看文件 @
7805558d
...
@@ -34,33 +34,33 @@ typedef enum {
...
@@ -34,33 +34,33 @@ typedef enum {
}
eRtpType
;
}
eRtpType
;
#define RTP_PT_MAP(XX) \
#define RTP_PT_MAP(XX) \
XX(PCMU, TrackAudio, 0, 8000, 1) \
XX(PCMU, TrackAudio, 0, 8000, 1
, CodecG711U
) \
XX(GSM, TrackAudio , 3, 8000, 1) \
XX(GSM, TrackAudio , 3, 8000, 1
, CodecInvalid
) \
XX(G723, TrackAudio, 4, 8000, 1) \
XX(G723, TrackAudio, 4, 8000, 1
, CodecInvalid
) \
XX(DVI4_8000, TrackAudio, 5, 8000, 1) \
XX(DVI4_8000, TrackAudio, 5, 8000, 1
, CodecInvalid
) \
XX(DVI4_16000, TrackAudio, 6, 16000, 1) \
XX(DVI4_16000, TrackAudio, 6, 16000, 1
, CodecInvalid
) \
XX(LPC, TrackAudio, 7, 8000, 1) \
XX(LPC, TrackAudio, 7, 8000, 1
, CodecInvalid
) \
XX(PCMA, TrackAudio, 8, 8000, 1) \
XX(PCMA, TrackAudio, 8, 8000, 1
, CodecG711A
) \
XX(G722, TrackAudio, 9, 8000, 1) \
XX(G722, TrackAudio, 9, 8000, 1
, CodecInvalid
) \
XX(L16_Stereo, TrackAudio, 10, 44100, 2) \
XX(L16_Stereo, TrackAudio, 10, 44100, 2
, CodecInvalid
) \
XX(L16_Mono, TrackAudio, 11, 44100, 1) \
XX(L16_Mono, TrackAudio, 11, 44100, 1
, CodecInvalid
) \
XX(QCELP, TrackAudio, 12, 8000, 1) \
XX(QCELP, TrackAudio, 12, 8000, 1
, CodecInvalid
) \
XX(CN, TrackAudio, 13, 8000, 1) \
XX(CN, TrackAudio, 13, 8000, 1
, CodecInvalid
) \
XX(MPA, TrackAudio, 14, 90000, 1) \
XX(MPA, TrackAudio, 14, 90000, 1
, CodecInvalid
) \
XX(G728, TrackAudio, 15, 8000, 1) \
XX(G728, TrackAudio, 15, 8000, 1
, CodecInvalid
) \
XX(DVI4_11025, TrackAudio, 16, 11025, 1) \
XX(DVI4_11025, TrackAudio, 16, 11025, 1
, CodecInvalid
) \
XX(DVI4_22050, TrackAudio, 17, 22050, 1) \
XX(DVI4_22050, TrackAudio, 17, 22050, 1
, CodecInvalid
) \
XX(G729, TrackAudio, 18, 8000, 1) \
XX(G729, TrackAudio, 18, 8000, 1
, CodecInvalid
) \
XX(CelB, TrackVideo, 25, 90000, 1) \
XX(CelB, TrackVideo, 25, 90000, 1
, CodecInvalid
) \
XX(JPEG, TrackVideo, 26, 90000, 1) \
XX(JPEG, TrackVideo, 26, 90000, 1
, CodecInvalid
) \
XX(nv, TrackVideo, 28, 90000, 1) \
XX(nv, TrackVideo, 28, 90000, 1
, CodecInvalid
) \
XX(H261, TrackVideo, 31, 90000, 1) \
XX(H261, TrackVideo, 31, 90000, 1
, CodecInvalid
) \
XX(MPV, TrackVideo, 32, 90000, 1) \
XX(MPV, TrackVideo, 32, 90000, 1
, CodecInvalid
) \
XX(MP2T, TrackVideo, 33, 90000, 1) \
XX(MP2T, TrackVideo, 33, 90000, 1
, CodecInvalid
) \
XX(H263, TrackVideo, 34, 90000, 1) \
XX(H263, TrackVideo, 34, 90000, 1
, CodecInvalid
) \
typedef
enum
{
typedef
enum
{
#define ENUM_DEF(name, type, value, clock_rate, channel) PT_ ## name = value,
#define ENUM_DEF(name, type, value, clock_rate, channel
, codec_id
) PT_ ## name = value,
RTP_PT_MAP
(
ENUM_DEF
)
RTP_PT_MAP
(
ENUM_DEF
)
#undef ENUM_DEF
#undef ENUM_DEF
PT_MAX
=
128
PT_MAX
=
128
...
@@ -88,6 +88,7 @@ public:
...
@@ -88,6 +88,7 @@ public:
static
TrackType
getTrackType
(
int
pt
);
static
TrackType
getTrackType
(
int
pt
);
static
int
getAudioChannel
(
int
pt
);
static
int
getAudioChannel
(
int
pt
);
static
const
char
*
getName
(
int
pt
);
static
const
char
*
getName
(
int
pt
);
static
CodecId
getCodecId
(
int
pt
);
private
:
private
:
RtpPayload
()
=
delete
;
RtpPayload
()
=
delete
;
~
RtpPayload
()
=
delete
;
~
RtpPayload
()
=
delete
;
...
@@ -128,6 +129,7 @@ public:
...
@@ -128,6 +129,7 @@ public:
int
_pt
;
int
_pt
;
string
_codec
;
string
_codec
;
int
_samplerate
;
int
_samplerate
;
int
_channel
;
string
_fmtp
;
string
_fmtp
;
string
_control
;
string
_control
;
string
_control_surffix
;
string
_control_surffix
;
...
...
src/Rtsp/RtspMediaSource.h
查看文件 @
7805558d
...
@@ -30,94 +30,10 @@ using namespace toolkit;
...
@@ -30,94 +30,10 @@ using namespace toolkit;
#define RTP_GOP_SIZE 512
#define RTP_GOP_SIZE 512
namespace
mediakit
{
namespace
mediakit
{
class
RtpVideoCache
{
typedef
VideoPacketCache
<
RtpPacket
>
RtpVideoCache
;
public
:
typedef
AudioPacketCache
<
RtpPacket
>
RtpAudioCache
;
RtpVideoCache
()
{
_cache
=
std
::
make_shared
<
List
<
RtpPacket
::
Ptr
>
>
();
}
virtual
~
RtpVideoCache
()
=
default
;
void
inputVideoRtp
(
const
RtpPacket
::
Ptr
&
rtp
,
bool
key_pos
)
{
if
(
_last_rtp_stamp
!=
rtp
->
timeStamp
)
{
//时间戳发生变化了
flushAll
();
}
else
if
(
_cache
->
size
()
>
RTP_GOP_SIZE
)
{
//这个逻辑用于避免时间戳异常的流导致的内存暴增问题
flushAll
();
}
//追加数据到最后
/**
_cache
->
emplace_back
(
rtp
);
_last_rtp_stamp
=
rtp
->
timeStamp
;
if
(
key_pos
)
{
_key_pos
=
key_pos
;
}
}
virtual
void
onFlushVideoRtp
(
std
::
shared_ptr
<
List
<
RtpPacket
::
Ptr
>
>
&
,
bool
key_pos
)
=
0
;
private
:
void
flushAll
()
{
if
(
_cache
->
empty
())
{
return
;
}
onFlushVideoRtp
(
_cache
,
_key_pos
);
_cache
=
std
::
make_shared
<
List
<
RtpPacket
::
Ptr
>
>
();
_key_pos
=
false
;
}
private
:
std
::
shared_ptr
<
List
<
RtpPacket
::
Ptr
>
>
_cache
;
uint32_t
_last_rtp_stamp
=
0
;
bool
_key_pos
=
false
;
};
class
RtpAudioCache
{
public
:
RtpAudioCache
()
{
_cache
=
std
::
make_shared
<
List
<
RtpPacket
::
Ptr
>
>
();
}
virtual
~
RtpAudioCache
()
=
default
;
void
inputAudioRtp
(
const
RtpPacket
::
Ptr
&
rtp
)
{
if
(
rtp
->
timeStamp
>
_last_rtp_stamp
+
100
)
{
//累积了100ms的音频数据
flushAll
();
}
else
if
(
_cache
->
size
()
>
10
)
{
//或者audio rtp缓存超过10个
flushAll
();
}
//追加数据到最后
_cache
->
emplace_back
(
rtp
);
_last_rtp_stamp
=
rtp
->
timeStamp
;
}
virtual
void
onFlushAudioRtp
(
std
::
shared_ptr
<
List
<
RtpPacket
::
Ptr
>
>
&
)
=
0
;
private
:
void
flushAll
()
{
if
(
_cache
->
empty
())
{
return
;
}
onFlushAudioRtp
(
_cache
);
_cache
=
std
::
make_shared
<
List
<
RtpPacket
::
Ptr
>
>
();
}
private
:
std
::
shared_ptr
<
List
<
RtpPacket
::
Ptr
>
>
_cache
;
uint32_t
_last_rtp_stamp
=
0
;
};
/**
* rtsp媒体源的数据抽象
* rtsp媒体源的数据抽象
* rtsp有关键的两要素,分别是sdp、rtp包
* rtsp有关键的两要素,分别是sdp、rtp包
* 只要生成了这两要素,那么要实现rtsp推流、rtsp服务器就很简单了
* 只要生成了这两要素,那么要实现rtsp推流、rtsp服务器就很简单了
...
@@ -261,9 +177,9 @@ public:
...
@@ -261,9 +177,9 @@ public:
}
}
if
(
rtp
->
type
==
TrackVideo
){
if
(
rtp
->
type
==
TrackVideo
){
RtpVideoCache
::
inputVideo
Rtp
(
rtp
,
keyPos
);
RtpVideoCache
::
inputVideo
(
rtp
,
keyPos
);
}
else
{
}
else
{
RtpAudioCache
::
inputAudio
Rtp
(
rtp
);
RtpAudioCache
::
inputAudio
(
rtp
);
}
}
}
}
...
@@ -274,7 +190,7 @@ private:
...
@@ -274,7 +190,7 @@ private:
* @param rtp_list 时间戳相同的rtp包列表
* @param rtp_list 时间戳相同的rtp包列表
* @param key_pos 是否包含关键帧
* @param key_pos 是否包含关键帧
*/
*/
void
onFlushVideo
Rtp
(
std
::
shared_ptr
<
List
<
RtpPacket
::
Ptr
>
>
&
rtp_list
,
bool
key_pos
)
override
{
void
onFlushVideo
(
std
::
shared_ptr
<
List
<
RtpPacket
::
Ptr
>
>
&
rtp_list
,
bool
key_pos
)
override
{
_ring
->
write
(
rtp_list
,
key_pos
);
_ring
->
write
(
rtp_list
,
key_pos
);
}
}
...
@@ -282,7 +198,7 @@ private:
...
@@ -282,7 +198,7 @@ private:
* 批量flush一定数量的音频rtp包时触发该函数
* 批量flush一定数量的音频rtp包时触发该函数
* @param rtp_list rtp包列表
* @param rtp_list rtp包列表
*/
*/
void
onFlushAudio
Rtp
(
std
::
shared_ptr
<
List
<
RtpPacket
::
Ptr
>
>
&
rtp_list
)
override
{
void
onFlushAudio
(
std
::
shared_ptr
<
List
<
RtpPacket
::
Ptr
>
>
&
rtp_list
)
override
{
//只有音频的话,就不存在gop缓存的意义
//只有音频的话,就不存在gop缓存的意义
_ring
->
write
(
rtp_list
,
!
_have_video
);
_ring
->
write
(
rtp_list
,
!
_have_video
);
}
}
...
...
src/Rtsp/RtspPlayer.cpp
查看文件 @
7805558d
...
@@ -112,6 +112,11 @@ void RtspPlayer::onConnect(const SockException &err){
...
@@ -112,6 +112,11 @@ void RtspPlayer::onConnect(const SockException &err){
}
}
void
RtspPlayer
::
onRecv
(
const
Buffer
::
Ptr
&
pBuf
)
{
void
RtspPlayer
::
onRecv
(
const
Buffer
::
Ptr
&
pBuf
)
{
if
(
_benchmark_mode
&&
!
_pPlayTimer
){
//在性能测试模式下,如果rtsp握手完毕后,不再解析rtp包
_rtpTicker
.
resetTime
();
return
;
}
input
(
pBuf
->
data
(),
pBuf
->
size
());
input
(
pBuf
->
data
(),
pBuf
->
size
());
}
}
void
RtspPlayer
::
onErr
(
const
SockException
&
ex
)
{
void
RtspPlayer
::
onErr
(
const
SockException
&
ex
)
{
...
@@ -750,6 +755,8 @@ void RtspPlayer::onPlayResult_l(const SockException &ex , bool handshakeComplete
...
@@ -750,6 +755,8 @@ void RtspPlayer::onPlayResult_l(const SockException &ex , bool handshakeComplete
//开始播放阶段
//开始播放阶段
_pPlayTimer
.
reset
();
_pPlayTimer
.
reset
();
onPlayResult
(
ex
);
onPlayResult
(
ex
);
//是否为性能测试模式
_benchmark_mode
=
(
*
this
)[
Client
::
kBenchmarkMode
].
as
<
int
>
();
}
else
if
(
ex
)
{
}
else
if
(
ex
)
{
//播放成功后异常断开回调
//播放成功后异常断开回调
onShutdown
(
ex
);
onShutdown
(
ex
);
...
...
src/Rtsp/RtspPlayer.h
查看文件 @
7805558d
...
@@ -139,6 +139,8 @@ private:
...
@@ -139,6 +139,8 @@ private:
//是否为rtsp点播
//是否为rtsp点播
bool
_is_play_back
;
bool
_is_play_back
;
//是否为性能测试模式
bool
_benchmark_mode
=
false
;
};
};
}
/* namespace mediakit */
}
/* namespace mediakit */
...
...
tests/test_benchmark.cpp
查看文件 @
7805558d
...
@@ -55,6 +55,7 @@ int main(int argc, char *argv[]) {
...
@@ -55,6 +55,7 @@ int main(int argc, char *argv[]) {
player
->
setOnShutdown
([
&
](
const
SockException
&
ex
)
{
player
->
setOnShutdown
([
&
](
const
SockException
&
ex
)
{
--
alivePlayerCnt
;
--
alivePlayerCnt
;
});
});
(
*
player
)[
kBenchmarkMode
]
=
true
;
(
*
player
)[
kRtpType
]
=
atoi
(
argv
[
4
]);
(
*
player
)[
kRtpType
]
=
atoi
(
argv
[
4
]);
player
->
play
(
argv
[
3
]);
player
->
play
(
argv
[
3
]);
playerList
.
push_back
(
player
);
playerList
.
push_back
(
player
);
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论