Merge branch 'master' into research

This commit is contained in:
Luke 2020-01-14 11:39:43 +08:00
commit dad0175094
31 changed files with 331 additions and 174 deletions

View File

@ -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>)
## 捐赠 ## 捐赠
欢迎捐赠以便更好的推动项目的发展,谢谢您的支持! 欢迎捐赠以便更好的推动项目的发展,谢谢您的支持!

View File

@ -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);

View File

@ -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大小

View File

@ -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;

View File

@ -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) {

View File

@ -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()){ _ticker.resetTime();
lam();
}else{
_anyTrackUnReady = true;
_allTrackReady = false;
_trackReadyCallback[codec_id] = lam;
_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,26 +79,50 @@ void MediaSink::inputFrame(const Frame::Ptr &frame) {
} }
} }
if(!_allTrackReady && (_trackReadyCallback.empty() || _ticker.elapsedTime() > MAX_WAIT_MS)){ if(!_allTrackReady){
_allTrackReady = true; if(_ticker.elapsedTime() > MAX_WAIT_MS_READY){
_anyTrackUnReady = false; //如果超过规定时间那么不再等待并忽略未准备好的Track
if(!_trackReadyCallback.empty()){ emitAllTrackReady();
//这是超时强制忽略未准备好的Track return;
_trackReadyCallback.clear();
//移除未准备好的Track
for(auto it = _track_map.begin() ; it != _track_map.end() ; ){
if(!it->second->ready()){
it = _track_map.erase(it);
continue;
}
++it;
}
} }
if(!_track_map.empty()){ if(!_trackReadyCallback.empty()){
//最少有一个有效的Track //在超时时间内如果存在未准备好的Track那么继续等待
onAllTrackReady(); 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;
if(!_trackReadyCallback.empty()){
//这是超时强制忽略未准备好的Track
_trackReadyCallback.clear();
//移除未准备好的Track
for(auto it = _track_map.begin() ; it != _track_map.end() ; ){
if(!it->second->ready()){
it = _track_map.erase(it);
continue;
}
++it;
}
}
if(!_track_map.empty()){
//最少有一个有效的Track
onAllTrackReady();
} }
} }

View File

@ -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;
}; };

View File

@ -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
_last_stamp = stamp; if(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

View File

@ -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

View File

@ -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

View File

@ -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服务器配置///////////

View File

@ -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;
} ; } ;

View File

@ -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);
} }

View File

@ -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);

View File

@ -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();
};
/** /**
* *

View File

@ -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);
} }
} }

View File

@ -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;
} }

View File

@ -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
RtpCodec::inputFrame(frame); auto flag = _dts_generator.getDts(frame->_pts,frame->_dts);
if(flag){
//写入环形缓存
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]);

View File

@ -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;
}; };

View File

@ -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);
} }
} }

View File

@ -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
RtpCodec::inputFrame(frame); auto flag = _dts_generator.getDts(frame->_pts,frame->_dts);
if(flag){
//写入环形缓存
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;

View File

@ -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;
}; };

View File

@ -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;
} }

View File

@ -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;
}; };

View File

@ -225,8 +225,10 @@ inline bool MP4Reader::readVideoSample(int iTimeInc,bool justSeekSyncFrame) {
uint32_t numBytes = _video_sample_max_size; uint32_t numBytes = _video_sample_max_size;
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 iOffset = 0; uint32_t dts = (double) _video_ms * iIdx / _video_num_samples;
uint32_t pts = dts + pRenderingOffset / 90;
uint32_t iOffset = 0;
while (iOffset < numBytes) { while (iOffset < numBytes) {
uint32_t iFrameLen; uint32_t iFrameLen;
memcpy(&iFrameLen,pBytes + iOffset,4); memcpy(&iFrameLen,pBytes + iOffset,4);
@ -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;

View File

@ -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,10 +145,9 @@ 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());

View File

@ -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;
}; };

View File

@ -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();
} }
} }

View File

@ -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,10 +474,11 @@ 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;
case MSG_AUDIO: case MSG_AUDIO:
@ -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;

View File

@ -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;

View File

@ -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) {