mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-12-02 00:12:33 +08:00
Merge branch 'master' into research
This commit is contained in:
commit
dad0175094
19
README.md
19
README.md
@ -377,6 +377,25 @@ git submodule update --init
|
|||||||
- 3、有些问题,如果不具备参考性的,无需在issue提的,可以在qq群提.
|
- 3、有些问题,如果不具备参考性的,无需在issue提的,可以在qq群提.
|
||||||
- 4、QQ私聊一般不接受无偿技术咨询和支持(谈谈人生理想还是可以的😂),毕竟精力有限,谢谢理解.
|
- 4、QQ私聊一般不接受无偿技术咨询和支持(谈谈人生理想还是可以的😂),毕竟精力有限,谢谢理解.
|
||||||
|
|
||||||
|
## 致谢
|
||||||
|
感谢以下各位对本项目包括但不限于代码贡献、问题反馈、资金捐赠等各种方式的支持!以下排名不分先后:
|
||||||
|
|
||||||
|
[老陈](https://github.com/ireader)
|
||||||
|
[Gemfield](https://github.com/gemfield)
|
||||||
|
[南冠彤](https://github.com/nanguantong2)
|
||||||
|
[凹凸慢](https://github.com/tsingeye)
|
||||||
|
[chenxiaolei](https://github.com/chenxiaolei)
|
||||||
|
[史前小虫](https://github.com/zqsong)
|
||||||
|
[清涩绿茶](https://github.com/baiyfcu)
|
||||||
|
[3503207480](https://github.com/3503207480)
|
||||||
|
[DroidChow](https://github.com/DroidChow)
|
||||||
|
[阿塞](https://github.com/HuoQiShuai)
|
||||||
|
[火宣](https://github.com/ChinaCCF)
|
||||||
|
[γ瑞γミ](https://github.com/JerryLinGd)
|
||||||
|
[linkingvision](https://www.linkingvision.com/)
|
||||||
|
[茄子](https://github.com/taotaobujue2008)
|
||||||
|
[好心情](<409257224@qq.com>)
|
||||||
|
|
||||||
## 捐赠
|
## 捐赠
|
||||||
欢迎捐赠以便更好的推动项目的发展,谢谢您的支持!
|
欢迎捐赠以便更好的推动项目的发展,谢谢您的支持!
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ API_EXPORT void API_CALL mk_media_init_aac(mk_media ctx, int channel, int sample
|
|||||||
* @param data 单帧H264数据
|
* @param data 单帧H264数据
|
||||||
* @param len 单帧H264数据字节数
|
* @param len 单帧H264数据字节数
|
||||||
* @param dts 解码时间戳,单位毫秒
|
* @param dts 解码时间戳,单位毫秒
|
||||||
* @param dts 播放时间戳,单位毫秒
|
* @param pts 播放时间戳,单位毫秒
|
||||||
*/
|
*/
|
||||||
API_EXPORT void API_CALL mk_media_input_h264(mk_media ctx, void *data, int len, uint32_t dts, uint32_t pts);
|
API_EXPORT void API_CALL mk_media_input_h264(mk_media ctx, void *data, int len, uint32_t dts, uint32_t pts);
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ API_EXPORT void API_CALL mk_media_input_h264(mk_media ctx, void *data, int len,
|
|||||||
* @param data 单帧H265数据
|
* @param data 单帧H265数据
|
||||||
* @param len 单帧H265数据字节数
|
* @param len 单帧H265数据字节数
|
||||||
* @param dts 解码时间戳,单位毫秒
|
* @param dts 解码时间戳,单位毫秒
|
||||||
* @param dts 播放时间戳,单位毫秒
|
* @param pts 播放时间戳,单位毫秒
|
||||||
*/
|
*/
|
||||||
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);
|
||||||
|
|
||||||
|
@ -191,8 +191,6 @@ keepAliveSecond=15
|
|||||||
port=554
|
port=554
|
||||||
#rtsps服务器监听地址
|
#rtsps服务器监听地址
|
||||||
sslport=322
|
sslport=322
|
||||||
#在接收rtsp推流时,是否重新生成时间戳(很多推流器的时间戳着实很烂)
|
|
||||||
modifyStamp=0
|
|
||||||
|
|
||||||
[shell]
|
[shell]
|
||||||
#调试telnet服务器接受最大bufffer大小
|
#调试telnet服务器接受最大bufffer大小
|
||||||
|
@ -438,7 +438,7 @@ void installWebHook(){
|
|||||||
//如果没有url参数,客户端又不支持cookie,那么会根据ip和端口追踪用户
|
//如果没有url参数,客户端又不支持cookie,那么会根据ip和端口追踪用户
|
||||||
//追踪用户的目的是为了缓存上次鉴权结果,减少鉴权次数,提高性能
|
//追踪用户的目的是为了缓存上次鉴权结果,减少鉴权次数,提高性能
|
||||||
NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastHttpAccess,[](BroadcastHttpAccessArgs){
|
NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastHttpAccess,[](BroadcastHttpAccessArgs){
|
||||||
if(sender.get_peer_ip() == "127.0.0.1" && parser.Params() == hook_adminparams){
|
if(sender.get_peer_ip() == "127.0.0.1" || parser.Params() == hook_adminparams){
|
||||||
//如果是本机或超级管理员访问,那么不做访问鉴权;权限有效期1个小时
|
//如果是本机或超级管理员访问,那么不做访问鉴权;权限有效期1个小时
|
||||||
invoker("","",60 * 60);
|
invoker("","",60 * 60);
|
||||||
return;
|
return;
|
||||||
|
@ -104,7 +104,14 @@ void DevChannel::inputH264(const char* pcData, int iDataLen, uint32_t dts,uint32
|
|||||||
} else {
|
} else {
|
||||||
prefixeSize = 0;
|
prefixeSize = 0;
|
||||||
}
|
}
|
||||||
inputFrame(std::make_shared<H264FrameNoCacheAble>((char *)pcData,iDataLen,dts,pts,prefixeSize));
|
|
||||||
|
H264Frame::Ptr frame = std::make_shared<H264Frame>();
|
||||||
|
frame->_dts = dts;
|
||||||
|
frame->_pts = pts;
|
||||||
|
frame->_buffer.assign("\x00\x00\x00\x01",4);
|
||||||
|
frame->_buffer.append(pcData + prefixeSize, iDataLen - prefixeSize);
|
||||||
|
frame->_prefix_size = 4;
|
||||||
|
inputFrame(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevChannel::inputH265(const char* pcData, int iDataLen, uint32_t dts,uint32_t pts) {
|
void DevChannel::inputH265(const char* pcData, int iDataLen, uint32_t dts,uint32_t pts) {
|
||||||
@ -122,7 +129,14 @@ void DevChannel::inputH265(const char* pcData, int iDataLen, uint32_t dts,uint32
|
|||||||
} else {
|
} else {
|
||||||
prefixeSize = 0;
|
prefixeSize = 0;
|
||||||
}
|
}
|
||||||
inputFrame(std::make_shared<H265FrameNoCacheAble>((char *)pcData,iDataLen,dts,pts,prefixeSize));
|
|
||||||
|
H265Frame::Ptr frame = std::make_shared<H265Frame>();
|
||||||
|
frame->_dts = dts;
|
||||||
|
frame->_pts = pts;
|
||||||
|
frame->_buffer.assign("\x00\x00\x00\x01",4);
|
||||||
|
frame->_buffer.append(pcData + prefixeSize, iDataLen - prefixeSize);
|
||||||
|
frame->_prefix_size = 4;
|
||||||
|
inputFrame(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevChannel::inputAAC(const char* pcData, int iDataLen, uint32_t uiStamp,bool withAdtsHeader) {
|
void DevChannel::inputAAC(const char* pcData, int iDataLen, uint32_t uiStamp,bool withAdtsHeader) {
|
||||||
|
@ -26,7 +26,11 @@
|
|||||||
#include "MediaSink.h"
|
#include "MediaSink.h"
|
||||||
|
|
||||||
//最多等待未初始化的Track 10秒,超时之后会忽略未初始化的Track
|
//最多等待未初始化的Track 10秒,超时之后会忽略未初始化的Track
|
||||||
#define MAX_WAIT_MS 10000
|
#define MAX_WAIT_MS_READY 10000
|
||||||
|
|
||||||
|
//如果添加Track,最多等待3秒
|
||||||
|
#define MAX_WAIT_MS_ADD_TRACK 3000
|
||||||
|
|
||||||
|
|
||||||
namespace mediakit{
|
namespace mediakit{
|
||||||
|
|
||||||
@ -34,23 +38,16 @@ void MediaSink::addTrack(const Track::Ptr &track_in) {
|
|||||||
lock_guard<recursive_mutex> lck(_mtx);
|
lock_guard<recursive_mutex> lck(_mtx);
|
||||||
//克隆Track,只拷贝其数据,不拷贝其数据转发关系
|
//克隆Track,只拷贝其数据,不拷贝其数据转发关系
|
||||||
auto track = track_in->clone();
|
auto track = track_in->clone();
|
||||||
|
|
||||||
auto codec_id = track->getCodecId();
|
auto codec_id = track->getCodecId();
|
||||||
_track_map[codec_id] = track;
|
_track_map[codec_id] = track;
|
||||||
auto lam = [this,track](){
|
_allTrackReady = false;
|
||||||
|
_trackReadyCallback[codec_id] = [this, track]() {
|
||||||
onTrackReady(track);
|
onTrackReady(track);
|
||||||
};
|
};
|
||||||
if(track->ready()){
|
|
||||||
lam();
|
|
||||||
}else{
|
|
||||||
_anyTrackUnReady = true;
|
|
||||||
_allTrackReady = false;
|
|
||||||
_trackReadyCallback[codec_id] = lam;
|
|
||||||
_ticker.resetTime();
|
_ticker.resetTime();
|
||||||
}
|
|
||||||
|
|
||||||
track->addDelegate(std::make_shared<FrameWriterInterfaceHelper>([this](const Frame::Ptr &frame) {
|
track->addDelegate(std::make_shared<FrameWriterInterfaceHelper>([this](const Frame::Ptr &frame) {
|
||||||
if(!_anyTrackUnReady){
|
if (_allTrackReady) {
|
||||||
onTrackFrame(frame);
|
onTrackFrame(frame);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@ -58,7 +55,6 @@ void MediaSink::addTrack(const Track::Ptr &track_in) {
|
|||||||
|
|
||||||
void MediaSink::resetTracks() {
|
void MediaSink::resetTracks() {
|
||||||
lock_guard<recursive_mutex> lck(_mtx);
|
lock_guard<recursive_mutex> lck(_mtx);
|
||||||
_anyTrackUnReady = false;
|
|
||||||
_allTrackReady = false;
|
_allTrackReady = false;
|
||||||
_track_map.clear();
|
_track_map.clear();
|
||||||
_trackReadyCallback.clear();
|
_trackReadyCallback.clear();
|
||||||
@ -83,9 +79,34 @@ void MediaSink::inputFrame(const Frame::Ptr &frame) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!_allTrackReady && (_trackReadyCallback.empty() || _ticker.elapsedTime() > MAX_WAIT_MS)){
|
if(!_allTrackReady){
|
||||||
|
if(_ticker.elapsedTime() > MAX_WAIT_MS_READY){
|
||||||
|
//如果超过规定时间,那么不再等待并忽略未准备好的Track
|
||||||
|
emitAllTrackReady();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!_trackReadyCallback.empty()){
|
||||||
|
//在超时时间内,如果存在未准备好的Track,那么继续等待
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_track_map.size() == 2){
|
||||||
|
//如果已经添加了音视频Track,并且不存在未准备好的Track,那么说明所有Track都准备好了
|
||||||
|
emitAllTrackReady();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_track_map.size() == 1 && _ticker.elapsedTime() > MAX_WAIT_MS_ADD_TRACK){
|
||||||
|
//如果只有一个Track,那么在该Track添加后,我们最多还等待若干时间(可能后面还会添加Track)
|
||||||
|
emitAllTrackReady();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaSink::emitAllTrackReady() {
|
||||||
_allTrackReady = true;
|
_allTrackReady = true;
|
||||||
_anyTrackUnReady = false;
|
|
||||||
if(!_trackReadyCallback.empty()){
|
if(!_trackReadyCallback.empty()){
|
||||||
//这是超时强制忽略未准备好的Track
|
//这是超时强制忽略未准备好的Track
|
||||||
_trackReadyCallback.clear();
|
_trackReadyCallback.clear();
|
||||||
@ -104,7 +125,6 @@ void MediaSink::inputFrame(const Frame::Ptr &frame) {
|
|||||||
onAllTrackReady();
|
onAllTrackReady();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
vector<Track::Ptr> MediaSink::getTracks(bool trackReady) const{
|
vector<Track::Ptr> MediaSink::getTracks(bool trackReady) const{
|
||||||
vector<Track::Ptr> ret;
|
vector<Track::Ptr> ret;
|
||||||
|
@ -109,12 +109,13 @@ protected:
|
|||||||
* @param frame
|
* @param frame
|
||||||
*/
|
*/
|
||||||
virtual void onTrackFrame(const Frame::Ptr &frame) {};
|
virtual void onTrackFrame(const Frame::Ptr &frame) {};
|
||||||
|
private:
|
||||||
|
void emitAllTrackReady();
|
||||||
private:
|
private:
|
||||||
mutable recursive_mutex _mtx;
|
mutable recursive_mutex _mtx;
|
||||||
map<int,Track::Ptr> _track_map;
|
map<int,Track::Ptr> _track_map;
|
||||||
map<int,function<void()> > _trackReadyCallback;
|
map<int,function<void()> > _trackReadyCallback;
|
||||||
bool _allTrackReady = false;
|
bool _allTrackReady = false;
|
||||||
bool _anyTrackUnReady = false;
|
|
||||||
Ticker _ticker;
|
Ticker _ticker;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,14 +26,18 @@
|
|||||||
|
|
||||||
#include "Stamp.h"
|
#include "Stamp.h"
|
||||||
|
|
||||||
#define MAX_DELTA_STAMP 300
|
#define MAX_DELTA_STAMP 1000
|
||||||
|
#define MAX_CTS 500
|
||||||
|
#define ABS(x) ((x) > 0 ? (x) : (-x))
|
||||||
|
|
||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
|
|
||||||
int64_t DeltaStamp::deltaStamp(int64_t stamp) {
|
int64_t DeltaStamp::deltaStamp(int64_t stamp) {
|
||||||
if(!_last_stamp){
|
if(!_last_stamp){
|
||||||
//第一次计算时间戳增量,时间戳增量为0
|
//第一次计算时间戳增量,时间戳增量为0
|
||||||
|
if(stamp){
|
||||||
_last_stamp = stamp;
|
_last_stamp = stamp;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +79,7 @@ void Stamp::revise(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out,
|
|||||||
dts_out = _relativeStamp;
|
dts_out = _relativeStamp;
|
||||||
|
|
||||||
//////////////以下是播放时间戳的计算//////////////////
|
//////////////以下是播放时间戳的计算//////////////////
|
||||||
if(pts_dts_diff > MAX_DELTA_STAMP || pts_dts_diff < -MAX_DELTA_STAMP){
|
if(ABS(pts_dts_diff) > MAX_CTS){
|
||||||
//如果差值太大,则认为由于回环导致时间戳错乱了
|
//如果差值太大,则认为由于回环导致时间戳错乱了
|
||||||
pts_dts_diff = 0;
|
pts_dts_diff = 0;
|
||||||
}
|
}
|
||||||
@ -96,4 +100,58 @@ int64_t Stamp::getRelativeStamp() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DtsGenerator::getDts(uint32_t pts, uint32_t &dts){
|
||||||
|
bool ret = false;
|
||||||
|
if(pts == _last_pts){
|
||||||
|
//pts未变,返回上次结果
|
||||||
|
if(_last_dts){
|
||||||
|
dts = _last_dts;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = getDts_l(pts,dts);
|
||||||
|
if(ret){
|
||||||
|
//保存本次结果
|
||||||
|
_last_dts = dts;
|
||||||
|
}
|
||||||
|
//记录上次pts
|
||||||
|
_last_pts = pts;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DtsGenerator::getDts_l(uint32_t pts, uint32_t &dts){
|
||||||
|
if(_sorter_max_size == 1){
|
||||||
|
//没有B帧
|
||||||
|
dts = pts;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!_sorter_max_size){
|
||||||
|
if(pts > _last_max_pts){
|
||||||
|
if(_frames_since_last_max_pts && _count_sorter_max_size++ > 0){
|
||||||
|
_sorter_max_size = _frames_since_last_max_pts;
|
||||||
|
_dts_pts_offset = (pts - _last_max_pts) / 2;
|
||||||
|
}
|
||||||
|
_frames_since_last_max_pts = 0;
|
||||||
|
_last_max_pts = pts;
|
||||||
|
}
|
||||||
|
++_frames_since_last_max_pts;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pts_sorter.emplace(pts);
|
||||||
|
if(_sorter_max_size && _pts_sorter.size() > _sorter_max_size){
|
||||||
|
auto it = _pts_sorter.begin();
|
||||||
|
dts = *it + _dts_pts_offset;
|
||||||
|
if(dts > pts){
|
||||||
|
//dts不能大于pts(基本不可能到达这个逻辑)
|
||||||
|
dts = pts;
|
||||||
|
}
|
||||||
|
_pts_sorter.erase(it);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}//namespace mediakit
|
}//namespace mediakit
|
@ -27,8 +27,9 @@
|
|||||||
#ifndef ZLMEDIAKIT_STAMP_H
|
#ifndef ZLMEDIAKIT_STAMP_H
|
||||||
#define ZLMEDIAKIT_STAMP_H
|
#define ZLMEDIAKIT_STAMP_H
|
||||||
|
|
||||||
#include "Util/TimeTicker.h"
|
#include <set>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include "Util/TimeTicker.h"
|
||||||
using namespace toolkit;
|
using namespace toolkit;
|
||||||
|
|
||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
@ -88,6 +89,27 @@ private:
|
|||||||
SmoothTicker _ticker;
|
SmoothTicker _ticker;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DtsGenerator{
|
||||||
|
public:
|
||||||
|
DtsGenerator() = default;
|
||||||
|
~DtsGenerator() = default;
|
||||||
|
bool getDts(uint32_t pts, uint32_t &dts);
|
||||||
|
private:
|
||||||
|
bool getDts_l(uint32_t pts, uint32_t &dts);
|
||||||
|
private:
|
||||||
|
uint32_t _dts_pts_offset = 0;
|
||||||
|
uint32_t _last_dts = 0;
|
||||||
|
uint32_t _last_pts = 0;
|
||||||
|
uint32_t _last_max_pts = 0;
|
||||||
|
int _frames_since_last_max_pts = 0;
|
||||||
|
int _sorter_max_size = 0;
|
||||||
|
int _count_sorter_max_size = 0;
|
||||||
|
set<uint32_t> _pts_sorter;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
}//namespace mediakit
|
}//namespace mediakit
|
||||||
|
|
||||||
#endif //ZLMEDIAKIT_STAMP_H
|
#endif //ZLMEDIAKIT_STAMP_H
|
||||||
|
@ -158,7 +158,6 @@ const string kAuthBasic = RTSP_FIELD"authBasic";
|
|||||||
const string kHandshakeSecond = RTSP_FIELD"handshakeSecond";
|
const string kHandshakeSecond = RTSP_FIELD"handshakeSecond";
|
||||||
const string kKeepAliveSecond = RTSP_FIELD"keepAliveSecond";
|
const string kKeepAliveSecond = RTSP_FIELD"keepAliveSecond";
|
||||||
const string kDirectProxy = RTSP_FIELD"directProxy";
|
const string kDirectProxy = RTSP_FIELD"directProxy";
|
||||||
const string kModifyStamp = RTSP_FIELD"modifyStamp";
|
|
||||||
|
|
||||||
onceToken token([](){
|
onceToken token([](){
|
||||||
//默认Md5方式认证
|
//默认Md5方式认证
|
||||||
@ -166,7 +165,6 @@ onceToken token([](){
|
|||||||
mINI::Instance()[kHandshakeSecond] = 15;
|
mINI::Instance()[kHandshakeSecond] = 15;
|
||||||
mINI::Instance()[kKeepAliveSecond] = 15;
|
mINI::Instance()[kKeepAliveSecond] = 15;
|
||||||
mINI::Instance()[kDirectProxy] = 1;
|
mINI::Instance()[kDirectProxy] = 1;
|
||||||
mINI::Instance()[kModifyStamp] = false;
|
|
||||||
},nullptr);
|
},nullptr);
|
||||||
} //namespace Rtsp
|
} //namespace Rtsp
|
||||||
|
|
||||||
|
@ -232,8 +232,6 @@ extern const string kKeepAliveSecond;
|
|||||||
//假定您的拉流源地址不是264或265或AAC,那么你可以使用直接代理的方式来支持rtsp代理
|
//假定您的拉流源地址不是264或265或AAC,那么你可以使用直接代理的方式来支持rtsp代理
|
||||||
//默认开启rtsp直接代理,rtmp由于没有这些问题,是强制开启直接代理的
|
//默认开启rtsp直接代理,rtmp由于没有这些问题,是强制开启直接代理的
|
||||||
extern const string kDirectProxy;
|
extern const string kDirectProxy;
|
||||||
//rtsp推流是否修改时间戳
|
|
||||||
extern const string kModifyStamp;
|
|
||||||
} //namespace Rtsp
|
} //namespace Rtsp
|
||||||
|
|
||||||
////////////RTMP服务器配置///////////
|
////////////RTMP服务器配置///////////
|
||||||
|
@ -104,7 +104,6 @@ public:
|
|||||||
//表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据)
|
//表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据)
|
||||||
unsigned int no_raw_data_blocks_in_frame; //2 uimsfb
|
unsigned int no_raw_data_blocks_in_frame; //2 uimsfb
|
||||||
unsigned char buffer[2 * 1024 + 7];
|
unsigned char buffer[2 * 1024 + 7];
|
||||||
uint16_t sequence;
|
|
||||||
uint32_t timeStamp;
|
uint32_t timeStamp;
|
||||||
uint32_t iPrefixSize = 7;
|
uint32_t iPrefixSize = 7;
|
||||||
} ;
|
} ;
|
||||||
|
@ -102,7 +102,7 @@ void AACRtmpEncoder::inputFrame(const Frame::Ptr &frame) {
|
|||||||
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->stamp();
|
rtmpPkt->timeStamp = frame->dts();
|
||||||
rtmpPkt->typeId = MSG_AUDIO;
|
rtmpPkt->typeId = MSG_AUDIO;
|
||||||
RtmpCodec::inputRtmp(rtmpPkt, false);
|
RtmpCodec::inputRtmp(rtmpPkt, false);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ AACRtpEncoder::AACRtpEncoder(uint32_t ui32Ssrc,
|
|||||||
|
|
||||||
void AACRtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
void AACRtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||||
GET_CONFIG(uint32_t, cycleMS, Rtp::kCycleMS);
|
GET_CONFIG(uint32_t, cycleMS, Rtp::kCycleMS);
|
||||||
auto uiStamp = frame->stamp();
|
auto uiStamp = frame->dts();
|
||||||
auto pcData = frame->data() + frame->prefixSize();
|
auto pcData = frame->data() + frame->prefixSize();
|
||||||
auto iLen = frame->size() - frame->prefixSize();
|
auto iLen = frame->size() - frame->prefixSize();
|
||||||
|
|
||||||
@ -149,7 +149,6 @@ bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtppack, bool key_pos) {
|
|||||||
memcpy(_adts->buffer + _adts->aac_frame_length, rtp_packet_payload + next_aac_payload_offset, cur_aac_payload_len);
|
memcpy(_adts->buffer + _adts->aac_frame_length, rtp_packet_payload + next_aac_payload_offset, cur_aac_payload_len);
|
||||||
_adts->aac_frame_length += (cur_aac_payload_len);
|
_adts->aac_frame_length += (cur_aac_payload_len);
|
||||||
if (rtppack->mark == true) {
|
if (rtppack->mark == true) {
|
||||||
_adts->sequence = rtppack->sequence;
|
|
||||||
_adts->timeStamp = rtppack->timeStamp;
|
_adts->timeStamp = rtppack->timeStamp;
|
||||||
writeAdtsHeader(*_adts, _adts->buffer);
|
writeAdtsHeader(*_adts, _adts->buffer);
|
||||||
onGetAAC(_adts);
|
onGetAAC(_adts);
|
||||||
|
@ -81,13 +81,6 @@ class Frame : public Buffer, public CodecInfo {
|
|||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<Frame> Ptr;
|
typedef std::shared_ptr<Frame> Ptr;
|
||||||
virtual ~Frame(){}
|
virtual ~Frame(){}
|
||||||
/**
|
|
||||||
* 时间戳,已经废弃,请使用dts() 、pts()接口
|
|
||||||
*/
|
|
||||||
inline uint32_t stamp() const {
|
|
||||||
return dts();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回解码时间戳,单位毫秒
|
* 返回解码时间戳,单位毫秒
|
||||||
|
@ -49,24 +49,25 @@ public:
|
|||||||
NAL_SPS = 7,
|
NAL_SPS = 7,
|
||||||
NAL_PPS = 8,
|
NAL_PPS = 8,
|
||||||
NAL_IDR = 5,
|
NAL_IDR = 5,
|
||||||
|
NAL_SEI = 6,
|
||||||
} NalType;
|
} NalType;
|
||||||
|
|
||||||
char *data() const override{
|
char *data() const override{
|
||||||
return (char *)buffer.data();
|
return (char *)_buffer.data();
|
||||||
}
|
}
|
||||||
uint32_t size() const override {
|
uint32_t size() const override {
|
||||||
return buffer.size();
|
return _buffer.size();
|
||||||
}
|
}
|
||||||
uint32_t dts() const override {
|
uint32_t dts() const override {
|
||||||
return timeStamp;
|
return _dts;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t pts() const override {
|
uint32_t pts() const override {
|
||||||
return ptsStamp ? ptsStamp : timeStamp;
|
return _pts ? _pts : _dts;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t prefixSize() const override{
|
uint32_t prefixSize() const override{
|
||||||
return iPrefixSize;
|
return _prefix_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackType getTrackType() const override{
|
TrackType getTrackType() const override{
|
||||||
@ -78,11 +79,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool keyFrame() const override {
|
bool keyFrame() const override {
|
||||||
return H264_TYPE(buffer[iPrefixSize]) == H264Frame::NAL_IDR;
|
return H264_TYPE(_buffer[_prefix_size]) == H264Frame::NAL_IDR;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool configFrame() const override{
|
bool configFrame() const override{
|
||||||
switch(H264_TYPE(buffer[iPrefixSize]) ){
|
switch(H264_TYPE(_buffer[_prefix_size]) ){
|
||||||
case H264Frame::NAL_SPS:
|
case H264Frame::NAL_SPS:
|
||||||
case H264Frame::NAL_PPS:
|
case H264Frame::NAL_PPS:
|
||||||
return true;
|
return true;
|
||||||
@ -91,10 +92,10 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
uint32_t timeStamp;
|
uint32_t _dts = 0;
|
||||||
uint32_t ptsStamp = 0;
|
uint32_t _pts = 0;
|
||||||
string buffer;
|
uint32_t _prefix_size = 4;
|
||||||
uint32_t iPrefixSize = 4;
|
string _buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -339,19 +340,19 @@ private:
|
|||||||
|
|
||||||
if(!_sps.empty()){
|
if(!_sps.empty()){
|
||||||
auto spsFrame = std::make_shared<H264Frame>();
|
auto spsFrame = std::make_shared<H264Frame>();
|
||||||
spsFrame->iPrefixSize = 4;
|
spsFrame->_prefix_size = 4;
|
||||||
spsFrame->buffer.assign("\x0\x0\x0\x1",4);
|
spsFrame->_buffer.assign("\x0\x0\x0\x1",4);
|
||||||
spsFrame->buffer.append(_sps);
|
spsFrame->_buffer.append(_sps);
|
||||||
spsFrame->timeStamp = frame->stamp();
|
spsFrame->_dts = frame->dts();
|
||||||
VideoTrack::inputFrame(spsFrame);
|
VideoTrack::inputFrame(spsFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!_pps.empty()){
|
if(!_pps.empty()){
|
||||||
auto ppsFrame = std::make_shared<H264Frame>();
|
auto ppsFrame = std::make_shared<H264Frame>();
|
||||||
ppsFrame->iPrefixSize = 4;
|
ppsFrame->_prefix_size = 4;
|
||||||
ppsFrame->buffer.assign("\x0\x0\x0\x1",4);
|
ppsFrame->_buffer.assign("\x0\x0\x0\x1",4);
|
||||||
ppsFrame->buffer.append(_pps);
|
ppsFrame->_buffer.append(_pps);
|
||||||
ppsFrame->timeStamp = frame->stamp();
|
ppsFrame->_dts = frame->dts();
|
||||||
VideoTrack::inputFrame(ppsFrame);
|
VideoTrack::inputFrame(ppsFrame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,8 @@ H264RtmpDecoder::H264RtmpDecoder() {
|
|||||||
H264Frame::Ptr H264RtmpDecoder::obtainFrame() {
|
H264Frame::Ptr H264RtmpDecoder::obtainFrame() {
|
||||||
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
|
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
|
||||||
auto frame = obtainObj();
|
auto frame = obtainObj();
|
||||||
frame->buffer.clear();
|
frame->_buffer.clear();
|
||||||
frame->iPrefixSize = 4;
|
frame->_prefix_size = 4;
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,10 +78,10 @@ bool H264RtmpDecoder::decodeRtmp(const RtmpPacket::Ptr &pkt) {
|
|||||||
|
|
||||||
inline void H264RtmpDecoder::onGetH264(const char* pcData, int iLen, uint32_t dts,uint32_t pts) {
|
inline void H264RtmpDecoder::onGetH264(const char* pcData, int iLen, uint32_t dts,uint32_t pts) {
|
||||||
#if 1
|
#if 1
|
||||||
_h264frame->timeStamp = dts;
|
_h264frame->_dts = dts;
|
||||||
_h264frame->ptsStamp = pts;
|
_h264frame->_pts = pts;
|
||||||
_h264frame->buffer.assign("\x0\x0\x0\x1", 4); //添加264头
|
_h264frame->_buffer.assign("\x0\x0\x0\x1", 4); //添加264头
|
||||||
_h264frame->buffer.append(pcData, iLen);
|
_h264frame->_buffer.append(pcData, iLen);
|
||||||
|
|
||||||
//写入环形缓存
|
//写入环形缓存
|
||||||
RtmpCodec::inputFrame(_h264frame);
|
RtmpCodec::inputFrame(_h264frame);
|
||||||
@ -140,7 +140,11 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_lastPacket && _lastPacket->timeStamp != frame->stamp()) {
|
if(type == H264Frame::NAL_SEI){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_lastPacket && _lastPacket->timeStamp != frame->dts()) {
|
||||||
RtmpCodec::inputRtmp(_lastPacket, _lastPacket->isVideoKeyFrame());
|
RtmpCodec::inputRtmp(_lastPacket, _lastPacket->isVideoKeyFrame());
|
||||||
_lastPacket = nullptr;
|
_lastPacket = nullptr;
|
||||||
}
|
}
|
||||||
@ -149,7 +153,7 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
|
|||||||
//I or P or B frame
|
//I or P or B frame
|
||||||
int8_t flags = 7; //h.264
|
int8_t flags = 7; //h.264
|
||||||
bool is_config = false;
|
bool is_config = false;
|
||||||
flags |= ((frame->keyFrame() ? FLV_KEY_FRAME : FLV_INTER_FRAME) << 4);
|
flags |= (((frame->configFrame() || frame->keyFrame()) ? FLV_KEY_FRAME : FLV_INTER_FRAME) << 4);
|
||||||
|
|
||||||
_lastPacket = ResourcePoolHelper<RtmpPacket>::obtainObj();
|
_lastPacket = ResourcePoolHelper<RtmpPacket>::obtainObj();
|
||||||
_lastPacket->strBuf.clear();
|
_lastPacket->strBuf.clear();
|
||||||
@ -161,7 +165,7 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
|
|||||||
|
|
||||||
_lastPacket->chunkId = CHUNK_VIDEO;
|
_lastPacket->chunkId = CHUNK_VIDEO;
|
||||||
_lastPacket->streamId = STREAM_MEDIA;
|
_lastPacket->streamId = STREAM_MEDIA;
|
||||||
_lastPacket->timeStamp = frame->stamp();
|
_lastPacket->timeStamp = frame->dts();
|
||||||
_lastPacket->typeId = MSG_VIDEO;
|
_lastPacket->typeId = MSG_VIDEO;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -70,8 +70,8 @@ H264RtpDecoder::H264RtpDecoder() {
|
|||||||
H264Frame::Ptr H264RtpDecoder::obtainFrame() {
|
H264Frame::Ptr H264RtpDecoder::obtainFrame() {
|
||||||
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
|
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
|
||||||
auto frame = ResourcePoolHelper<H264Frame>::obtainObj();
|
auto frame = ResourcePoolHelper<H264Frame>::obtainObj();
|
||||||
frame->buffer.clear();
|
frame->_buffer.clear();
|
||||||
frame->iPrefixSize = 4;
|
frame->_prefix_size = 4;
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,9 +113,9 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
|
|||||||
|
|
||||||
if (nal.type >= 0 && nal.type < 24) {
|
if (nal.type >= 0 && nal.type < 24) {
|
||||||
//a full frame
|
//a full frame
|
||||||
_h264frame->buffer.assign("\x0\x0\x0\x1", 4);
|
_h264frame->_buffer.assign("\x0\x0\x0\x1", 4);
|
||||||
_h264frame->buffer.append((char *)frame, length);
|
_h264frame->_buffer.append((char *)frame, length);
|
||||||
_h264frame->timeStamp = rtppack->timeStamp;
|
_h264frame->_pts = rtppack->timeStamp;
|
||||||
auto key = _h264frame->keyFrame();
|
auto key = _h264frame->keyFrame();
|
||||||
onGetH264(_h264frame);
|
onGetH264(_h264frame);
|
||||||
return (key); //i frame
|
return (key); //i frame
|
||||||
@ -142,9 +142,9 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
|
|||||||
//过小的帧丢弃
|
//过小的帧丢弃
|
||||||
NALU nal;
|
NALU nal;
|
||||||
MakeNalu(ptr[0], nal);
|
MakeNalu(ptr[0], nal);
|
||||||
_h264frame->buffer.assign("\x0\x0\x0\x1", 4);
|
_h264frame->_buffer.assign("\x0\x0\x0\x1", 4);
|
||||||
_h264frame->buffer.append((char *)ptr, len);
|
_h264frame->_buffer.append((char *)ptr, len);
|
||||||
_h264frame->timeStamp = rtppack->timeStamp;
|
_h264frame->_pts = rtppack->timeStamp;
|
||||||
if(nal.type == H264Frame::NAL_IDR){
|
if(nal.type == H264Frame::NAL_IDR){
|
||||||
haveIDR = true;
|
haveIDR = true;
|
||||||
}
|
}
|
||||||
@ -162,10 +162,10 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
|
|||||||
if (fu.S) {
|
if (fu.S) {
|
||||||
//该帧的第一个rtp包 FU-A start
|
//该帧的第一个rtp包 FU-A start
|
||||||
char tmp = (nal.forbidden_zero_bit << 7 | nal.nal_ref_idc << 5 | fu.type);
|
char tmp = (nal.forbidden_zero_bit << 7 | nal.nal_ref_idc << 5 | fu.type);
|
||||||
_h264frame->buffer.assign("\x0\x0\x0\x1", 4);
|
_h264frame->_buffer.assign("\x0\x0\x0\x1", 4);
|
||||||
_h264frame->buffer.push_back(tmp);
|
_h264frame->_buffer.push_back(tmp);
|
||||||
_h264frame->buffer.append((char *)frame + 2, length - 2);
|
_h264frame->_buffer.append((char *)frame + 2, length - 2);
|
||||||
_h264frame->timeStamp = rtppack->timeStamp;
|
_h264frame->_pts = rtppack->timeStamp;
|
||||||
//该函数return时,保存下当前sequence,以便下次对比seq是否连续
|
//该函数return时,保存下当前sequence,以便下次对比seq是否连续
|
||||||
_lastSeq = rtppack->sequence;
|
_lastSeq = rtppack->sequence;
|
||||||
return _h264frame->keyFrame();
|
return _h264frame->keyFrame();
|
||||||
@ -173,22 +173,22 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
|
|||||||
|
|
||||||
if (rtppack->sequence != _lastSeq + 1 && rtppack->sequence != 0) {
|
if (rtppack->sequence != _lastSeq + 1 && rtppack->sequence != 0) {
|
||||||
//中间的或末尾的rtp包,其seq必须连续(如果回环了则判定为连续),否则说明rtp丢包,那么该帧不完整,必须得丢弃
|
//中间的或末尾的rtp包,其seq必须连续(如果回环了则判定为连续),否则说明rtp丢包,那么该帧不完整,必须得丢弃
|
||||||
_h264frame->buffer.clear();
|
_h264frame->_buffer.clear();
|
||||||
WarnL << "rtp sequence不连续: " << rtppack->sequence << " != " << _lastSeq << " + 1,该帧被废弃";
|
WarnL << "rtp sequence不连续: " << rtppack->sequence << " != " << _lastSeq << " + 1,该帧被废弃";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fu.E) {
|
if (!fu.E) {
|
||||||
//该帧的中间rtp包 FU-A mid
|
//该帧的中间rtp包 FU-A mid
|
||||||
_h264frame->buffer.append((char *)frame + 2, length - 2);
|
_h264frame->_buffer.append((char *)frame + 2, length - 2);
|
||||||
//该函数return时,保存下当前sequence,以便下次对比seq是否连续
|
//该函数return时,保存下当前sequence,以便下次对比seq是否连续
|
||||||
_lastSeq = rtppack->sequence;
|
_lastSeq = rtppack->sequence;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//该帧最后一个rtp包 FU-A end
|
//该帧最后一个rtp包 FU-A end
|
||||||
_h264frame->buffer.append((char *)frame + 2, length - 2);
|
_h264frame->_buffer.append((char *)frame + 2, length - 2);
|
||||||
_h264frame->timeStamp = rtppack->timeStamp;
|
_h264frame->_pts = rtppack->timeStamp;
|
||||||
auto key = _h264frame->keyFrame();
|
auto key = _h264frame->keyFrame();
|
||||||
onGetH264(_h264frame);
|
onGetH264(_h264frame);
|
||||||
return key;
|
return key;
|
||||||
@ -209,8 +209,12 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void H264RtpDecoder::onGetH264(const H264Frame::Ptr &frame) {
|
void H264RtpDecoder::onGetH264(const H264Frame::Ptr &frame) {
|
||||||
|
//根据pts计算dts
|
||||||
|
auto flag = _dts_generator.getDts(frame->_pts,frame->_dts);
|
||||||
|
if(flag){
|
||||||
//写入环形缓存
|
//写入环形缓存
|
||||||
RtpCodec::inputFrame(frame);
|
RtpCodec::inputFrame(frame);
|
||||||
|
}
|
||||||
_h264frame = obtainFrame();
|
_h264frame = obtainFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,7 +236,7 @@ H264RtpEncoder::H264RtpEncoder(uint32_t ui32Ssrc,
|
|||||||
void H264RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
void H264RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||||
GET_CONFIG(uint32_t,cycleMS,Rtp::kCycleMS);
|
GET_CONFIG(uint32_t,cycleMS,Rtp::kCycleMS);
|
||||||
auto pcData = frame->data() + frame->prefixSize();
|
auto pcData = frame->data() + frame->prefixSize();
|
||||||
auto uiStamp = frame->stamp();
|
auto uiStamp = frame->pts();
|
||||||
auto iLen = frame->size() - frame->prefixSize();
|
auto iLen = frame->size() - frame->prefixSize();
|
||||||
//获取NALU的5bit 帧类型
|
//获取NALU的5bit 帧类型
|
||||||
unsigned char naluType = H264_TYPE(pcData[0]);
|
unsigned char naluType = H264_TYPE(pcData[0]);
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "Rtsp/RtpCodec.h"
|
#include "Rtsp/RtpCodec.h"
|
||||||
#include "Util/ResourcePool.h"
|
#include "Util/ResourcePool.h"
|
||||||
#include "Extension/H264.h"
|
#include "Extension/H264.h"
|
||||||
|
#include "Common/Stamp.h"
|
||||||
using namespace toolkit;
|
using namespace toolkit;
|
||||||
|
|
||||||
namespace mediakit{
|
namespace mediakit{
|
||||||
@ -66,6 +67,7 @@ private:
|
|||||||
H264Frame::Ptr obtainFrame();
|
H264Frame::Ptr obtainFrame();
|
||||||
private:
|
private:
|
||||||
H264Frame::Ptr _h264frame;
|
H264Frame::Ptr _h264frame;
|
||||||
|
DtsGenerator _dts_generator;
|
||||||
int _lastSeq = 0;
|
int _lastSeq = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,23 +74,23 @@ public:
|
|||||||
} NaleType;
|
} NaleType;
|
||||||
|
|
||||||
char *data() const override {
|
char *data() const override {
|
||||||
return (char *) buffer.data();
|
return (char *) _buffer.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t size() const override {
|
uint32_t size() const override {
|
||||||
return buffer.size();
|
return _buffer.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t dts() const override {
|
uint32_t dts() const override {
|
||||||
return timeStamp;
|
return _dts;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t pts() const override {
|
uint32_t pts() const override {
|
||||||
return ptsStamp ? ptsStamp : timeStamp;
|
return _pts ? _pts : _dts;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t prefixSize() const override {
|
uint32_t prefixSize() const override {
|
||||||
return iPrefixSize;
|
return _prefix_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackType getTrackType() const override {
|
TrackType getTrackType() const override {
|
||||||
@ -102,11 +102,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool keyFrame() const override {
|
bool keyFrame() const override {
|
||||||
return isKeyFrame(H265_TYPE(buffer[iPrefixSize]));
|
return isKeyFrame(H265_TYPE(_buffer[_prefix_size]));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool configFrame() const override{
|
bool configFrame() const override{
|
||||||
switch(H265_TYPE(buffer[iPrefixSize])){
|
switch(H265_TYPE(_buffer[_prefix_size])){
|
||||||
case H265Frame::NAL_VPS:
|
case H265Frame::NAL_VPS:
|
||||||
case H265Frame::NAL_SPS:
|
case H265Frame::NAL_SPS:
|
||||||
case H265Frame::NAL_PPS:
|
case H265Frame::NAL_PPS:
|
||||||
@ -131,10 +131,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
uint32_t timeStamp;
|
uint32_t _dts = 0;
|
||||||
uint32_t ptsStamp = 0;
|
uint32_t _pts = 0;
|
||||||
string buffer;
|
uint32_t _prefix_size = 4;
|
||||||
uint32_t iPrefixSize = 4;
|
string _buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -356,27 +356,27 @@ private:
|
|||||||
}
|
}
|
||||||
if(!_vps.empty()){
|
if(!_vps.empty()){
|
||||||
auto vpsFrame = std::make_shared<H265Frame>();
|
auto vpsFrame = std::make_shared<H265Frame>();
|
||||||
vpsFrame->iPrefixSize = 4;
|
vpsFrame->_prefix_size = 4;
|
||||||
vpsFrame->buffer.assign("\x0\x0\x0\x1", 4);
|
vpsFrame->_buffer.assign("\x0\x0\x0\x1", 4);
|
||||||
vpsFrame->buffer.append(_vps);
|
vpsFrame->_buffer.append(_vps);
|
||||||
vpsFrame->timeStamp = frame->stamp();
|
vpsFrame->_dts = frame->dts();
|
||||||
VideoTrack::inputFrame(vpsFrame);
|
VideoTrack::inputFrame(vpsFrame);
|
||||||
}
|
}
|
||||||
if (!_sps.empty()) {
|
if (!_sps.empty()) {
|
||||||
auto spsFrame = std::make_shared<H265Frame>();
|
auto spsFrame = std::make_shared<H265Frame>();
|
||||||
spsFrame->iPrefixSize = 4;
|
spsFrame->_prefix_size = 4;
|
||||||
spsFrame->buffer.assign("\x0\x0\x0\x1", 4);
|
spsFrame->_buffer.assign("\x0\x0\x0\x1", 4);
|
||||||
spsFrame->buffer.append(_sps);
|
spsFrame->_buffer.append(_sps);
|
||||||
spsFrame->timeStamp = frame->stamp();
|
spsFrame->_dts = frame->dts();
|
||||||
VideoTrack::inputFrame(spsFrame);
|
VideoTrack::inputFrame(spsFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_pps.empty()) {
|
if (!_pps.empty()) {
|
||||||
auto ppsFrame = std::make_shared<H265Frame>();
|
auto ppsFrame = std::make_shared<H265Frame>();
|
||||||
ppsFrame->iPrefixSize = 4;
|
ppsFrame->_prefix_size = 4;
|
||||||
ppsFrame->buffer.assign("\x0\x0\x0\x1", 4);
|
ppsFrame->_buffer.assign("\x0\x0\x0\x1", 4);
|
||||||
ppsFrame->buffer.append(_pps);
|
ppsFrame->_buffer.append(_pps);
|
||||||
ppsFrame->timeStamp = frame->stamp();
|
ppsFrame->_dts = frame->dts();
|
||||||
VideoTrack::inputFrame(ppsFrame);
|
VideoTrack::inputFrame(ppsFrame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,8 +70,8 @@ H265RtpDecoder::H265RtpDecoder() {
|
|||||||
H265Frame::Ptr H265RtpDecoder::obtainFrame() {
|
H265Frame::Ptr H265RtpDecoder::obtainFrame() {
|
||||||
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
|
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
|
||||||
auto frame = ResourcePoolHelper<H265Frame>::obtainObj();
|
auto frame = ResourcePoolHelper<H265Frame>::obtainObj();
|
||||||
frame->buffer.clear();
|
frame->_buffer.clear();
|
||||||
frame->iPrefixSize = 4;
|
frame->_prefix_size = 4;
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,11 +99,11 @@ bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
|
|||||||
MakeFU(frame[2], fu);
|
MakeFU(frame[2], fu);
|
||||||
if (fu.S) {
|
if (fu.S) {
|
||||||
//该帧的第一个rtp包
|
//该帧的第一个rtp包
|
||||||
_h265frame->buffer.assign("\x0\x0\x0\x1", 4);
|
_h265frame->_buffer.assign("\x0\x0\x0\x1", 4);
|
||||||
_h265frame->buffer.push_back(fu.type << 1);
|
_h265frame->_buffer.push_back(fu.type << 1);
|
||||||
_h265frame->buffer.push_back(0x01);
|
_h265frame->_buffer.push_back(0x01);
|
||||||
_h265frame->buffer.append((char *) frame + 3, length - 3);
|
_h265frame->_buffer.append((char *) frame + 3, length - 3);
|
||||||
_h265frame->timeStamp = rtppack->timeStamp;
|
_h265frame->_pts = rtppack->timeStamp;
|
||||||
//该函数return时,保存下当前sequence,以便下次对比seq是否连续
|
//该函数return时,保存下当前sequence,以便下次对比seq是否连续
|
||||||
_lastSeq = rtppack->sequence;
|
_lastSeq = rtppack->sequence;
|
||||||
return (_h265frame->keyFrame()); //i frame
|
return (_h265frame->keyFrame()); //i frame
|
||||||
@ -111,22 +111,22 @@ bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
|
|||||||
|
|
||||||
if (rtppack->sequence != _lastSeq + 1 && rtppack->sequence != 0) {
|
if (rtppack->sequence != _lastSeq + 1 && rtppack->sequence != 0) {
|
||||||
//中间的或末尾的rtp包,其seq必须连续(如果回环了则判定为连续),否则说明rtp丢包,那么该帧不完整,必须得丢弃
|
//中间的或末尾的rtp包,其seq必须连续(如果回环了则判定为连续),否则说明rtp丢包,那么该帧不完整,必须得丢弃
|
||||||
_h265frame->buffer.clear();
|
_h265frame->_buffer.clear();
|
||||||
WarnL << "rtp sequence不连续: " << rtppack->sequence << " != " << _lastSeq << " + 1,该帧被废弃";
|
WarnL << "rtp sequence不连续: " << rtppack->sequence << " != " << _lastSeq << " + 1,该帧被废弃";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fu.E) {
|
if (!fu.E) {
|
||||||
//该帧的中间rtp包
|
//该帧的中间rtp包
|
||||||
_h265frame->buffer.append((char *) frame + 3, length - 3);
|
_h265frame->_buffer.append((char *) frame + 3, length - 3);
|
||||||
//该函数return时,保存下当前sequence,以便下次对比seq是否连续
|
//该函数return时,保存下当前sequence,以便下次对比seq是否连续
|
||||||
_lastSeq = rtppack->sequence;
|
_lastSeq = rtppack->sequence;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//该帧最后一个rtp包
|
//该帧最后一个rtp包
|
||||||
_h265frame->buffer.append((char *) frame + 3, length - 3);
|
_h265frame->_buffer.append((char *) frame + 3, length - 3);
|
||||||
_h265frame->timeStamp = rtppack->timeStamp;
|
_h265frame->_pts = rtppack->timeStamp;
|
||||||
auto key = _h265frame->keyFrame();
|
auto key = _h265frame->keyFrame();
|
||||||
onGetH265(_h265frame);
|
onGetH265(_h265frame);
|
||||||
return key;
|
return key;
|
||||||
@ -134,9 +134,9 @@ bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
|
|||||||
|
|
||||||
default: // 4.4.1. Single NAL Unit Packets (p24)
|
default: // 4.4.1. Single NAL Unit Packets (p24)
|
||||||
//a full frame
|
//a full frame
|
||||||
_h265frame->buffer.assign("\x0\x0\x0\x1", 4);
|
_h265frame->_buffer.assign("\x0\x0\x0\x1", 4);
|
||||||
_h265frame->buffer.append((char *)frame, length);
|
_h265frame->_buffer.append((char *)frame, length);
|
||||||
_h265frame->timeStamp = rtppack->timeStamp;
|
_h265frame->_pts = rtppack->timeStamp;
|
||||||
auto key = _h265frame->keyFrame();
|
auto key = _h265frame->keyFrame();
|
||||||
onGetH265(_h265frame);
|
onGetH265(_h265frame);
|
||||||
return key;
|
return key;
|
||||||
@ -144,8 +144,12 @@ bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void H265RtpDecoder::onGetH265(const H265Frame::Ptr &frame) {
|
void H265RtpDecoder::onGetH265(const H265Frame::Ptr &frame) {
|
||||||
|
//计算dts
|
||||||
|
auto flag = _dts_generator.getDts(frame->_pts,frame->_dts);
|
||||||
|
if(flag){
|
||||||
//写入环形缓存
|
//写入环形缓存
|
||||||
RtpCodec::inputFrame(frame);
|
RtpCodec::inputFrame(frame);
|
||||||
|
}
|
||||||
_h265frame = obtainFrame();
|
_h265frame = obtainFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +171,7 @@ H265RtpEncoder::H265RtpEncoder(uint32_t ui32Ssrc,
|
|||||||
void H265RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
void H265RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||||
GET_CONFIG(uint32_t,cycleMS,Rtp::kCycleMS);
|
GET_CONFIG(uint32_t,cycleMS,Rtp::kCycleMS);
|
||||||
uint8_t *pcData = (uint8_t*)frame->data() + frame->prefixSize();
|
uint8_t *pcData = (uint8_t*)frame->data() + frame->prefixSize();
|
||||||
auto uiStamp = frame->stamp();
|
auto uiStamp = frame->pts();
|
||||||
auto iLen = frame->size() - frame->prefixSize();
|
auto iLen = frame->size() - frame->prefixSize();
|
||||||
unsigned char naluType = H265_TYPE(pcData[0]); //获取NALU的5bit 帧类型
|
unsigned char naluType = H265_TYPE(pcData[0]); //获取NALU的5bit 帧类型
|
||||||
uiStamp %= cycleMS;
|
uiStamp %= cycleMS;
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "Rtsp/RtpCodec.h"
|
#include "Rtsp/RtpCodec.h"
|
||||||
#include "Util/ResourcePool.h"
|
#include "Util/ResourcePool.h"
|
||||||
#include "Extension/H265.h"
|
#include "Extension/H265.h"
|
||||||
|
#include "Common/Stamp.h"
|
||||||
|
|
||||||
using namespace toolkit;
|
using namespace toolkit;
|
||||||
|
|
||||||
@ -67,6 +68,7 @@ private:
|
|||||||
H265Frame::Ptr obtainFrame();
|
H265Frame::Ptr obtainFrame();
|
||||||
private:
|
private:
|
||||||
H265Frame::Ptr _h265frame;
|
H265Frame::Ptr _h265frame;
|
||||||
|
DtsGenerator _dts_generator;
|
||||||
int _lastSeq = 0;
|
int _lastSeq = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -303,7 +303,7 @@ private:
|
|||||||
//拦截websocket数据接收
|
//拦截websocket数据接收
|
||||||
_onRecv = [this](const Buffer::Ptr &pBuf){
|
_onRecv = [this](const Buffer::Ptr &pBuf){
|
||||||
//解析websocket数据包
|
//解析websocket数据包
|
||||||
WebSocketSplitter::decode((uint8_t*)pBuf->data(),pBuf->size());
|
this->WebSocketSplitter::decode((uint8_t*)pBuf->data(),pBuf->size());
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -219,16 +219,26 @@ public:
|
|||||||
virtual ~MuteAudioMaker(){}
|
virtual ~MuteAudioMaker(){}
|
||||||
void inputFrame(const Frame::Ptr &frame) override {
|
void inputFrame(const Frame::Ptr &frame) override {
|
||||||
if(frame->getTrackType() == TrackVideo){
|
if(frame->getTrackType() == TrackVideo){
|
||||||
auto iAudioIndex = frame->stamp() / MUTE_ADTS_DATA_MS;
|
auto iAudioIndex = frame->dts() / MUTE_ADTS_DATA_MS;
|
||||||
if(_iAudioIndex != iAudioIndex){
|
if(_iAudioIndex != iAudioIndex){
|
||||||
_iAudioIndex = iAudioIndex;
|
_iAudioIndex = iAudioIndex;
|
||||||
auto aacFrame = std::make_shared<AACFrameNoCacheAble>((char *)MUTE_ADTS_DATA,
|
auto aacFrame = std::make_shared<AACFrameCacheAble>((char *)MUTE_ADTS_DATA, MUTE_ADTS_DATA_LEN, _iAudioIndex * MUTE_ADTS_DATA_MS);
|
||||||
MUTE_ADTS_DATA_LEN,
|
|
||||||
_iAudioIndex * MUTE_ADTS_DATA_MS);
|
|
||||||
FrameDispatcher::inputFrame(aacFrame);
|
FrameDispatcher::inputFrame(aacFrame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
class AACFrameCacheAble : public AACFrameNoCacheAble{
|
||||||
|
public:
|
||||||
|
template <typename ... ARGS>
|
||||||
|
AACFrameCacheAble(ARGS && ...args) : AACFrameNoCacheAble(std::forward<ARGS>(args)...){};
|
||||||
|
virtual ~AACFrameCacheAble() = default;
|
||||||
|
|
||||||
|
bool cacheAble() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
private:
|
private:
|
||||||
int _iAudioIndex = 0;
|
int _iAudioIndex = 0;
|
||||||
};
|
};
|
||||||
|
@ -226,6 +226,8 @@ inline bool MP4Reader::readVideoSample(int iTimeInc,bool justSeekSyncFrame) {
|
|||||||
MP4Duration pRenderingOffset;
|
MP4Duration pRenderingOffset;
|
||||||
if(MP4ReadSample(_hMP4File, _video_trId, iIdx + 1, &pBytes, &numBytes,NULL,NULL,&pRenderingOffset,&_bSyncSample)){
|
if(MP4ReadSample(_hMP4File, _video_trId, iIdx + 1, &pBytes, &numBytes,NULL,NULL,&pRenderingOffset,&_bSyncSample)){
|
||||||
if (!justSeekSyncFrame) {
|
if (!justSeekSyncFrame) {
|
||||||
|
uint32_t dts = (double) _video_ms * iIdx / _video_num_samples;
|
||||||
|
uint32_t pts = dts + pRenderingOffset / 90;
|
||||||
uint32_t iOffset = 0;
|
uint32_t iOffset = 0;
|
||||||
while (iOffset < numBytes) {
|
while (iOffset < numBytes) {
|
||||||
uint32_t iFrameLen;
|
uint32_t iFrameLen;
|
||||||
@ -235,8 +237,7 @@ inline bool MP4Reader::readVideoSample(int iTimeInc,bool justSeekSyncFrame) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
memcpy(pBytes + iOffset, "\x0\x0\x0\x1", 4);
|
memcpy(pBytes + iOffset, "\x0\x0\x0\x1", 4);
|
||||||
uint32_t dts = (double) _video_ms * iIdx / _video_num_samples;
|
writeH264(pBytes + iOffset, iFrameLen + 4, dts, pts);
|
||||||
writeH264(pBytes + iOffset, iFrameLen + 4, dts, dts + pRenderingOffset / 90);
|
|
||||||
iOffset += (iFrameLen + 4);
|
iOffset += (iFrameLen + 4);
|
||||||
}
|
}
|
||||||
}else if(_bSyncSample){
|
}else if(_bSyncSample){
|
||||||
@ -260,9 +261,10 @@ inline bool MP4Reader::readAudioSample(int iTimeInc,bool justSeekSyncFrame) {
|
|||||||
uint8_t *pBytes = _adts.buffer + 7;
|
uint8_t *pBytes = _adts.buffer + 7;
|
||||||
if(MP4ReadSample(_hMP4File, _audio_trId, i + 1, &pBytes, &numBytes)){
|
if(MP4ReadSample(_hMP4File, _audio_trId, i + 1, &pBytes, &numBytes)){
|
||||||
if (!justSeekSyncFrame) {
|
if (!justSeekSyncFrame) {
|
||||||
|
uint32_t dts = (double) _audio_ms * i / _audio_num_samples;
|
||||||
_adts.aac_frame_length = 7 + numBytes;
|
_adts.aac_frame_length = 7 + numBytes;
|
||||||
writeAdtsHeader(_adts, _adts.buffer);
|
writeAdtsHeader(_adts, _adts.buffer);
|
||||||
writeAAC(_adts.buffer, _adts.aac_frame_length, (double) _audio_ms * i / _audio_num_samples);
|
writeAAC(_adts.buffer, _adts.aac_frame_length, dts);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
ErrorL << "读取音频失败:" << i+ 1;
|
ErrorL << "读取音频失败:" << i+ 1;
|
||||||
|
@ -72,7 +72,6 @@ public:
|
|||||||
const string &stream_id,
|
const string &stream_id,
|
||||||
int ring_size = 0) :
|
int ring_size = 0) :
|
||||||
MediaSource(RTMP_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) {
|
MediaSource(RTMP_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) {
|
||||||
_metadata = TitleMeta().getMetadata();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~RtmpMediaSource() {}
|
virtual ~RtmpMediaSource() {}
|
||||||
@ -117,6 +116,9 @@ public:
|
|||||||
virtual void setMetaData(const AMFValue &metadata) {
|
virtual void setMetaData(const AMFValue &metadata) {
|
||||||
lock_guard<recursive_mutex> lock(_mtx);
|
lock_guard<recursive_mutex> lock(_mtx);
|
||||||
_metadata = metadata;
|
_metadata = metadata;
|
||||||
|
if(_ring){
|
||||||
|
regist();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -143,11 +145,10 @@ public:
|
|||||||
_ring = std::make_shared<RingType>(_ring_size, std::move(lam));
|
_ring = std::make_shared<RingType>(_ring_size, std::move(lam));
|
||||||
onReaderChanged(0);
|
onReaderChanged(0);
|
||||||
|
|
||||||
//如果输入了非config帧,
|
if(_metadata){
|
||||||
//那么说明不再可能获取config帧以及metadata,
|
|
||||||
//所以我们强制其为已注册
|
|
||||||
regist();
|
regist();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_track_stamps_map[pkt->typeId] = pkt->timeStamp;
|
_track_stamps_map[pkt->typeId] = pkt->timeStamp;
|
||||||
_ring->write(pkt, pkt->isVideoKeyFrame());
|
_ring->write(pkt, pkt->isVideoKeyFrame());
|
||||||
checkNoneReader();
|
checkNoneReader();
|
||||||
|
@ -66,6 +66,7 @@ private:
|
|||||||
_pRtmpMediaSrc = dynamic_pointer_cast<RtmpMediaSource>(_pMediaSrc);
|
_pRtmpMediaSrc = dynamic_pointer_cast<RtmpMediaSource>(_pMediaSrc);
|
||||||
if(_pRtmpMediaSrc){
|
if(_pRtmpMediaSrc){
|
||||||
_pRtmpMediaSrc->setMetaData(val);
|
_pRtmpMediaSrc->setMetaData(val);
|
||||||
|
_set_meta_data = true;
|
||||||
}
|
}
|
||||||
_delegate.reset(new RtmpDemuxer);
|
_delegate.reset(new RtmpDemuxer);
|
||||||
_delegate->loadMetaData(val);
|
_delegate->loadMetaData(val);
|
||||||
@ -73,6 +74,10 @@ private:
|
|||||||
}
|
}
|
||||||
void onMediaData(const RtmpPacket::Ptr &chunkData) override {
|
void onMediaData(const RtmpPacket::Ptr &chunkData) override {
|
||||||
if(_pRtmpMediaSrc){
|
if(_pRtmpMediaSrc){
|
||||||
|
if(!_set_meta_data && !chunkData->isCfgFrame()){
|
||||||
|
_set_meta_data = true;
|
||||||
|
_pRtmpMediaSrc->setMetaData(TitleMeta().getMetadata());
|
||||||
|
}
|
||||||
_pRtmpMediaSrc->onWrite(chunkData);
|
_pRtmpMediaSrc->onWrite(chunkData);
|
||||||
}
|
}
|
||||||
if(!_delegate){
|
if(!_delegate){
|
||||||
@ -83,6 +88,7 @@ private:
|
|||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
RtmpMediaSource::Ptr _pRtmpMediaSrc;
|
RtmpMediaSource::Ptr _pRtmpMediaSrc;
|
||||||
|
bool _set_meta_data = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -332,7 +332,7 @@ void RtmpProtocol::handle_C0C1() {
|
|||||||
//complex handsharke
|
//complex handsharke
|
||||||
handle_C1_complex();
|
handle_C1_complex();
|
||||||
#else
|
#else
|
||||||
WarnL << "未打开ENABLE_OPENSSL宏,复杂握手采用简单方式处理!";
|
WarnL << "未打开ENABLE_OPENSSL宏,复杂握手采用简单方式处理,flash播放器可能无法播放!";
|
||||||
handle_C1_simple();
|
handle_C1_simple();
|
||||||
#endif//ENABLE_OPENSSL
|
#endif//ENABLE_OPENSSL
|
||||||
}
|
}
|
||||||
@ -372,10 +372,10 @@ void RtmpProtocol::handle_C1_complex(){
|
|||||||
check_C1_Digest(digest,c1_joined);
|
check_C1_Digest(digest,c1_joined);
|
||||||
|
|
||||||
send_complex_S0S1S2(0,digest);
|
send_complex_S0S1S2(0,digest);
|
||||||
InfoL << "schema0";
|
// InfoL << "schema0";
|
||||||
}catch(std::exception &ex){
|
}catch(std::exception &ex){
|
||||||
//貌似flash从来都不用schema1
|
//貌似flash从来都不用schema1
|
||||||
WarnL << "try rtmp complex schema0 failed:" << ex.what();
|
// WarnL << "try rtmp complex schema0 failed:" << ex.what();
|
||||||
try{
|
try{
|
||||||
/* c1s1 schema1
|
/* c1s1 schema1
|
||||||
time: 4bytes
|
time: 4bytes
|
||||||
@ -389,9 +389,9 @@ void RtmpProtocol::handle_C1_complex(){
|
|||||||
check_C1_Digest(digest,c1_joined);
|
check_C1_Digest(digest,c1_joined);
|
||||||
|
|
||||||
send_complex_S0S1S2(1,digest);
|
send_complex_S0S1S2(1,digest);
|
||||||
InfoL << "schema1";
|
// InfoL << "schema1";
|
||||||
}catch(std::exception &ex){
|
}catch(std::exception &ex){
|
||||||
WarnL << "try rtmp complex schema1 failed:" << ex.what();
|
// WarnL << "try rtmp complex schema1 failed:" << ex.what();
|
||||||
handle_C1_simple();
|
handle_C1_simple();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -434,6 +434,7 @@ void RtmpSession::setMetaData(AMFDecoder &dec) {
|
|||||||
auto metadata = dec.load<AMFValue>();
|
auto metadata = dec.load<AMFValue>();
|
||||||
// dumpMetadata(metadata);
|
// dumpMetadata(metadata);
|
||||||
_pPublisherSrc->setMetaData(metadata);
|
_pPublisherSrc->setMetaData(metadata);
|
||||||
|
_set_meta_data = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtmpSession::onProcessCmd(AMFDecoder &dec) {
|
void RtmpSession::onProcessCmd(AMFDecoder &dec) {
|
||||||
@ -452,7 +453,7 @@ void RtmpSession::onProcessCmd(AMFDecoder &dec) {
|
|||||||
std::string method = dec.load<std::string>();
|
std::string method = dec.load<std::string>();
|
||||||
auto it = s_cmd_functions.find(method);
|
auto it = s_cmd_functions.find(method);
|
||||||
if (it == s_cmd_functions.end()) {
|
if (it == s_cmd_functions.end()) {
|
||||||
TraceP(this) << "can not support cmd:" << method;
|
// TraceP(this) << "can not support cmd:" << method;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_dNowReqID = dec.load<double>();
|
_dNowReqID = dec.load<double>();
|
||||||
@ -473,9 +474,10 @@ void RtmpSession::onRtmpChunk(RtmpPacket &chunkData) {
|
|||||||
case MSG_DATA3: {
|
case MSG_DATA3: {
|
||||||
AMFDecoder dec(chunkData.strBuf, chunkData.typeId == MSG_CMD3 ? 1 : 0);
|
AMFDecoder dec(chunkData.strBuf, chunkData.typeId == MSG_CMD3 ? 1 : 0);
|
||||||
std::string type = dec.load<std::string>();
|
std::string type = dec.load<std::string>();
|
||||||
TraceP(this) << "notify:" << type;
|
|
||||||
if (type == "@setDataFrame") {
|
if (type == "@setDataFrame") {
|
||||||
setMetaData(dec);
|
setMetaData(dec);
|
||||||
|
}else{
|
||||||
|
TraceP(this) << "unknown notify:" << type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -490,6 +492,11 @@ void RtmpSession::onRtmpChunk(RtmpPacket &chunkData) {
|
|||||||
_stamp[chunkData.typeId % 2].revise(chunkData.timeStamp, chunkData.timeStamp, dts_out, dts_out, true);
|
_stamp[chunkData.typeId % 2].revise(chunkData.timeStamp, chunkData.timeStamp, dts_out, dts_out, true);
|
||||||
chunkData.timeStamp = dts_out;
|
chunkData.timeStamp = dts_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!_set_meta_data && !chunkData.isCfgFrame()){
|
||||||
|
_set_meta_data = true;
|
||||||
|
_pPublisherSrc->setMetaData(TitleMeta().getMetadata());
|
||||||
|
}
|
||||||
_pPublisherSrc->onWrite(std::make_shared<RtmpPacket>(std::move(chunkData)));
|
_pPublisherSrc->onWrite(std::make_shared<RtmpPacket>(std::move(chunkData)));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -95,6 +95,7 @@ private:
|
|||||||
std::string _strTcUrl;
|
std::string _strTcUrl;
|
||||||
MediaInfo _mediaInfo;
|
MediaInfo _mediaInfo;
|
||||||
double _dNowReqID = 0;
|
double _dNowReqID = 0;
|
||||||
|
bool _set_meta_data = false;
|
||||||
Ticker _ticker;//数据接收时间
|
Ticker _ticker;//数据接收时间
|
||||||
RingBuffer<RtmpPacket::Ptr>::RingReader::Ptr _pRingReader;
|
RingBuffer<RtmpPacket::Ptr>::RingReader::Ptr _pRingReader;
|
||||||
std::shared_ptr<RtmpMediaSourceImp> _pPublisherSrc;
|
std::shared_ptr<RtmpMediaSourceImp> _pPublisherSrc;
|
||||||
|
@ -932,12 +932,6 @@ inline void RtspSession::send_NotAcceptable() {
|
|||||||
|
|
||||||
|
|
||||||
void RtspSession::onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx) {
|
void RtspSession::onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx) {
|
||||||
GET_CONFIG(bool,modify_stamp,Rtsp::kModifyStamp);
|
|
||||||
if(modify_stamp){
|
|
||||||
int64_t dts_out;
|
|
||||||
_stamp[trackidx].revise(rtppt->timeStamp, rtppt->timeStamp, dts_out, dts_out, true);
|
|
||||||
rtppt->timeStamp = dts_out;
|
|
||||||
}
|
|
||||||
_pushSrc->onWrite(rtppt, false);
|
_pushSrc->onWrite(rtppt, false);
|
||||||
}
|
}
|
||||||
inline void RtspSession::onRcvPeerUdpData(int intervaled, const Buffer::Ptr &pBuf, const struct sockaddr& addr) {
|
inline void RtspSession::onRcvPeerUdpData(int intervaled, const Buffer::Ptr &pBuf, const struct sockaddr& addr) {
|
||||||
|
Loading…
Reference in New Issue
Block a user