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群提.
- 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 len H264数据字节数
* @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);
@ -97,7 +97,7 @@ API_EXPORT void API_CALL mk_media_input_h264(mk_media ctx, void *data, int len,
* @param data H265数据
* @param len H265数据字节数
* @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);

View File

@ -191,8 +191,6 @@ keepAliveSecond=15
port=554
#rtsps服务器监听地址
sslport=322
#在接收rtsp推流时是否重新生成时间戳(很多推流器的时间戳着实很烂)
modifyStamp=0
[shell]
#调试telnet服务器接受最大bufffer大小

View File

@ -438,7 +438,7 @@ void installWebHook(){
//如果没有url参数客户端又不支持cookie那么会根据ip和端口追踪用户
//追踪用户的目的是为了缓存上次鉴权结果,减少鉴权次数,提高性能
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个小时
invoker("","",60 * 60);
return;

View File

@ -104,7 +104,14 @@ void DevChannel::inputH264(const char* pcData, int iDataLen, uint32_t dts,uint32
} else {
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) {
@ -122,7 +129,14 @@ void DevChannel::inputH265(const char* pcData, int iDataLen, uint32_t dts,uint32
} else {
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) {

View File

@ -26,7 +26,11 @@
#include "MediaSink.h"
//最多等待未初始化的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{
@ -34,23 +38,16 @@ void MediaSink::addTrack(const Track::Ptr &track_in) {
lock_guard<recursive_mutex> lck(_mtx);
//克隆Track只拷贝其数据不拷贝其数据转发关系
auto track = track_in->clone();
auto codec_id = track->getCodecId();
_track_map[codec_id] = track;
auto lam = [this,track](){
_allTrackReady = false;
_trackReadyCallback[codec_id] = [this, track]() {
onTrackReady(track);
};
if(track->ready()){
lam();
}else{
_anyTrackUnReady = true;
_allTrackReady = false;
_trackReadyCallback[codec_id] = lam;
_ticker.resetTime();
}
track->addDelegate(std::make_shared<FrameWriterInterfaceHelper>([this](const Frame::Ptr &frame){
if(!_anyTrackUnReady){
track->addDelegate(std::make_shared<FrameWriterInterfaceHelper>([this](const Frame::Ptr &frame) {
if (_allTrackReady) {
onTrackFrame(frame);
}
}));
@ -58,7 +55,6 @@ void MediaSink::addTrack(const Track::Ptr &track_in) {
void MediaSink::resetTracks() {
lock_guard<recursive_mutex> lck(_mtx);
_anyTrackUnReady = false;
_allTrackReady = false;
_track_map.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;
_anyTrackUnReady = false;
if(!_trackReadyCallback.empty()){
//这是超时强制忽略未准备好的Track
_trackReadyCallback.clear();
@ -103,7 +124,6 @@ void MediaSink::inputFrame(const Frame::Ptr &frame) {
//最少有一个有效的Track
onAllTrackReady();
}
}
}
vector<Track::Ptr> MediaSink::getTracks(bool trackReady) const{

View File

@ -109,12 +109,13 @@ protected:
* @param frame
*/
virtual void onTrackFrame(const Frame::Ptr &frame) {};
private:
void emitAllTrackReady();
private:
mutable recursive_mutex _mtx;
map<int,Track::Ptr> _track_map;
map<int,function<void()> > _trackReadyCallback;
bool _allTrackReady = false;
bool _anyTrackUnReady = false;
Ticker _ticker;
};

View File

@ -26,14 +26,18 @@
#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 {
int64_t DeltaStamp::deltaStamp(int64_t stamp) {
if(!_last_stamp){
//第一次计算时间戳增量,时间戳增量为0
if(stamp){
_last_stamp = stamp;
}
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;
//////////////以下是播放时间戳的计算//////////////////
if(pts_dts_diff > MAX_DELTA_STAMP || pts_dts_diff < -MAX_DELTA_STAMP){
if(ABS(pts_dts_diff) > MAX_CTS){
//如果差值太大,则认为由于回环导致时间戳错乱了
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

View File

@ -27,8 +27,9 @@
#ifndef ZLMEDIAKIT_STAMP_H
#define ZLMEDIAKIT_STAMP_H
#include "Util/TimeTicker.h"
#include <set>
#include <cstdint>
#include "Util/TimeTicker.h"
using namespace toolkit;
namespace mediakit {
@ -88,6 +89,27 @@ private:
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
#endif //ZLMEDIAKIT_STAMP_H

View File

@ -158,7 +158,6 @@ const string kAuthBasic = RTSP_FIELD"authBasic";
const string kHandshakeSecond = RTSP_FIELD"handshakeSecond";
const string kKeepAliveSecond = RTSP_FIELD"keepAliveSecond";
const string kDirectProxy = RTSP_FIELD"directProxy";
const string kModifyStamp = RTSP_FIELD"modifyStamp";
onceToken token([](){
//默认Md5方式认证
@ -166,7 +165,6 @@ onceToken token([](){
mINI::Instance()[kHandshakeSecond] = 15;
mINI::Instance()[kKeepAliveSecond] = 15;
mINI::Instance()[kDirectProxy] = 1;
mINI::Instance()[kModifyStamp] = false;
},nullptr);
} //namespace Rtsp

View File

@ -232,8 +232,6 @@ extern const string kKeepAliveSecond;
//假定您的拉流源地址不是264或265或AAC那么你可以使用直接代理的方式来支持rtsp代理
//默认开启rtsp直接代理rtmp由于没有这些问题是强制开启直接代理的
extern const string kDirectProxy;
//rtsp推流是否修改时间戳
extern const string kModifyStamp;
} //namespace Rtsp
////////////RTMP服务器配置///////////

View File

@ -104,7 +104,6 @@ public:
//表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据)
unsigned int no_raw_data_blocks_in_frame; //2 uimsfb
unsigned char buffer[2 * 1024 + 7];
uint16_t sequence;
uint32_t timeStamp;
uint32_t iPrefixSize = 7;
} ;

View File

@ -102,7 +102,7 @@ void AACRtmpEncoder::inputFrame(const Frame::Ptr &frame) {
rtmpPkt->bodySize = rtmpPkt->strBuf.size();
rtmpPkt->chunkId = CHUNK_AUDIO;
rtmpPkt->streamId = STREAM_MEDIA;
rtmpPkt->timeStamp = frame->stamp();
rtmpPkt->timeStamp = frame->dts();
rtmpPkt->typeId = MSG_AUDIO;
RtmpCodec::inputRtmp(rtmpPkt, false);
}

View File

@ -41,7 +41,7 @@ AACRtpEncoder::AACRtpEncoder(uint32_t ui32Ssrc,
void AACRtpEncoder::inputFrame(const Frame::Ptr &frame) {
GET_CONFIG(uint32_t, cycleMS, Rtp::kCycleMS);
auto uiStamp = frame->stamp();
auto uiStamp = frame->dts();
auto pcData = frame->data() + 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);
_adts->aac_frame_length += (cur_aac_payload_len);
if (rtppack->mark == true) {
_adts->sequence = rtppack->sequence;
_adts->timeStamp = rtppack->timeStamp;
writeAdtsHeader(*_adts, _adts->buffer);
onGetAAC(_adts);

View File

@ -81,13 +81,6 @@ class Frame : public Buffer, public CodecInfo {
public:
typedef std::shared_ptr<Frame> Ptr;
virtual ~Frame(){}
/**
* ,使dts() pts()
*/
inline uint32_t stamp() const {
return dts();
};
/**
*

View File

@ -49,24 +49,25 @@ public:
NAL_SPS = 7,
NAL_PPS = 8,
NAL_IDR = 5,
NAL_SEI = 6,
} NalType;
char *data() const override{
return (char *)buffer.data();
return (char *)_buffer.data();
}
uint32_t size() const override {
return buffer.size();
return _buffer.size();
}
uint32_t dts() const override {
return timeStamp;
return _dts;
}
uint32_t pts() const override {
return ptsStamp ? ptsStamp : timeStamp;
return _pts ? _pts : _dts;
}
uint32_t prefixSize() const override{
return iPrefixSize;
return _prefix_size;
}
TrackType getTrackType() const override{
@ -78,11 +79,11 @@ public:
}
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{
switch(H264_TYPE(buffer[iPrefixSize]) ){
switch(H264_TYPE(_buffer[_prefix_size]) ){
case H264Frame::NAL_SPS:
case H264Frame::NAL_PPS:
return true;
@ -91,10 +92,10 @@ public:
}
}
public:
uint32_t timeStamp;
uint32_t ptsStamp = 0;
string buffer;
uint32_t iPrefixSize = 4;
uint32_t _dts = 0;
uint32_t _pts = 0;
uint32_t _prefix_size = 4;
string _buffer;
};
@ -339,19 +340,19 @@ private:
if(!_sps.empty()){
auto spsFrame = std::make_shared<H264Frame>();
spsFrame->iPrefixSize = 4;
spsFrame->buffer.assign("\x0\x0\x0\x1",4);
spsFrame->buffer.append(_sps);
spsFrame->timeStamp = frame->stamp();
spsFrame->_prefix_size = 4;
spsFrame->_buffer.assign("\x0\x0\x0\x1",4);
spsFrame->_buffer.append(_sps);
spsFrame->_dts = frame->dts();
VideoTrack::inputFrame(spsFrame);
}
if(!_pps.empty()){
auto ppsFrame = std::make_shared<H264Frame>();
ppsFrame->iPrefixSize = 4;
ppsFrame->buffer.assign("\x0\x0\x0\x1",4);
ppsFrame->buffer.append(_pps);
ppsFrame->timeStamp = frame->stamp();
ppsFrame->_prefix_size = 4;
ppsFrame->_buffer.assign("\x0\x0\x0\x1",4);
ppsFrame->_buffer.append(_pps);
ppsFrame->_dts = frame->dts();
VideoTrack::inputFrame(ppsFrame);
}
}

View File

@ -35,8 +35,8 @@ H264RtmpDecoder::H264RtmpDecoder() {
H264Frame::Ptr H264RtmpDecoder::obtainFrame() {
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
auto frame = obtainObj();
frame->buffer.clear();
frame->iPrefixSize = 4;
frame->_buffer.clear();
frame->_prefix_size = 4;
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) {
#if 1
_h264frame->timeStamp = dts;
_h264frame->ptsStamp = pts;
_h264frame->buffer.assign("\x0\x0\x0\x1", 4); //添加264头
_h264frame->buffer.append(pcData, iLen);
_h264frame->_dts = dts;
_h264frame->_pts = pts;
_h264frame->_buffer.assign("\x0\x0\x0\x1", 4); //添加264头
_h264frame->_buffer.append(pcData, iLen);
//写入环形缓存
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());
_lastPacket = nullptr;
}
@ -149,7 +153,7 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
//I or P or B frame
int8_t flags = 7; //h.264
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->strBuf.clear();
@ -161,7 +165,7 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
_lastPacket->chunkId = CHUNK_VIDEO;
_lastPacket->streamId = STREAM_MEDIA;
_lastPacket->timeStamp = frame->stamp();
_lastPacket->timeStamp = frame->dts();
_lastPacket->typeId = MSG_VIDEO;
}

View File

@ -70,8 +70,8 @@ H264RtpDecoder::H264RtpDecoder() {
H264Frame::Ptr H264RtpDecoder::obtainFrame() {
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
auto frame = ResourcePoolHelper<H264Frame>::obtainObj();
frame->buffer.clear();
frame->iPrefixSize = 4;
frame->_buffer.clear();
frame->_prefix_size = 4;
return frame;
}
@ -113,9 +113,9 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
if (nal.type >= 0 && nal.type < 24) {
//a full frame
_h264frame->buffer.assign("\x0\x0\x0\x1", 4);
_h264frame->buffer.append((char *)frame, length);
_h264frame->timeStamp = rtppack->timeStamp;
_h264frame->_buffer.assign("\x0\x0\x0\x1", 4);
_h264frame->_buffer.append((char *)frame, length);
_h264frame->_pts = rtppack->timeStamp;
auto key = _h264frame->keyFrame();
onGetH264(_h264frame);
return (key); //i frame
@ -142,9 +142,9 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
//过小的帧丢弃
NALU nal;
MakeNalu(ptr[0], nal);
_h264frame->buffer.assign("\x0\x0\x0\x1", 4);
_h264frame->buffer.append((char *)ptr, len);
_h264frame->timeStamp = rtppack->timeStamp;
_h264frame->_buffer.assign("\x0\x0\x0\x1", 4);
_h264frame->_buffer.append((char *)ptr, len);
_h264frame->_pts = rtppack->timeStamp;
if(nal.type == H264Frame::NAL_IDR){
haveIDR = true;
}
@ -162,10 +162,10 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
if (fu.S) {
//该帧的第一个rtp包 FU-A start
char tmp = (nal.forbidden_zero_bit << 7 | nal.nal_ref_idc << 5 | fu.type);
_h264frame->buffer.assign("\x0\x0\x0\x1", 4);
_h264frame->buffer.push_back(tmp);
_h264frame->buffer.append((char *)frame + 2, length - 2);
_h264frame->timeStamp = rtppack->timeStamp;
_h264frame->_buffer.assign("\x0\x0\x0\x1", 4);
_h264frame->_buffer.push_back(tmp);
_h264frame->_buffer.append((char *)frame + 2, length - 2);
_h264frame->_pts = rtppack->timeStamp;
//该函数return时保存下当前sequence,以便下次对比seq是否连续
_lastSeq = rtppack->sequence;
return _h264frame->keyFrame();
@ -173,22 +173,22 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
if (rtppack->sequence != _lastSeq + 1 && rtppack->sequence != 0) {
//中间的或末尾的rtp包其seq必须连续(如果回环了则判定为连续)否则说明rtp丢包那么该帧不完整必须得丢弃
_h264frame->buffer.clear();
_h264frame->_buffer.clear();
WarnL << "rtp sequence不连续: " << rtppack->sequence << " != " << _lastSeq << " + 1,该帧被废弃";
return false;
}
if (!fu.E) {
//该帧的中间rtp包 FU-A mid
_h264frame->buffer.append((char *)frame + 2, length - 2);
_h264frame->_buffer.append((char *)frame + 2, length - 2);
//该函数return时保存下当前sequence,以便下次对比seq是否连续
_lastSeq = rtppack->sequence;
return false;
}
//该帧最后一个rtp包 FU-A end
_h264frame->buffer.append((char *)frame + 2, length - 2);
_h264frame->timeStamp = rtppack->timeStamp;
_h264frame->_buffer.append((char *)frame + 2, length - 2);
_h264frame->_pts = rtppack->timeStamp;
auto key = _h264frame->keyFrame();
onGetH264(_h264frame);
return key;
@ -209,8 +209,12 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
}
void H264RtpDecoder::onGetH264(const H264Frame::Ptr &frame) {
//根据pts计算dts
auto flag = _dts_generator.getDts(frame->_pts,frame->_dts);
if(flag){
//写入环形缓存
RtpCodec::inputFrame(frame);
}
_h264frame = obtainFrame();
}
@ -232,7 +236,7 @@ H264RtpEncoder::H264RtpEncoder(uint32_t ui32Ssrc,
void H264RtpEncoder::inputFrame(const Frame::Ptr &frame) {
GET_CONFIG(uint32_t,cycleMS,Rtp::kCycleMS);
auto pcData = frame->data() + frame->prefixSize();
auto uiStamp = frame->stamp();
auto uiStamp = frame->pts();
auto iLen = frame->size() - frame->prefixSize();
//获取NALU的5bit 帧类型
unsigned char naluType = H264_TYPE(pcData[0]);

View File

@ -30,6 +30,7 @@
#include "Rtsp/RtpCodec.h"
#include "Util/ResourcePool.h"
#include "Extension/H264.h"
#include "Common/Stamp.h"
using namespace toolkit;
namespace mediakit{
@ -66,6 +67,7 @@ private:
H264Frame::Ptr obtainFrame();
private:
H264Frame::Ptr _h264frame;
DtsGenerator _dts_generator;
int _lastSeq = 0;
};

View File

@ -74,23 +74,23 @@ public:
} NaleType;
char *data() const override {
return (char *) buffer.data();
return (char *) _buffer.data();
}
uint32_t size() const override {
return buffer.size();
return _buffer.size();
}
uint32_t dts() const override {
return timeStamp;
return _dts;
}
uint32_t pts() const override {
return ptsStamp ? ptsStamp : timeStamp;
return _pts ? _pts : _dts;
}
uint32_t prefixSize() const override {
return iPrefixSize;
return _prefix_size;
}
TrackType getTrackType() const override {
@ -102,11 +102,11 @@ public:
}
bool keyFrame() const override {
return isKeyFrame(H265_TYPE(buffer[iPrefixSize]));
return isKeyFrame(H265_TYPE(_buffer[_prefix_size]));
}
bool configFrame() const override{
switch(H265_TYPE(buffer[iPrefixSize])){
switch(H265_TYPE(_buffer[_prefix_size])){
case H265Frame::NAL_VPS:
case H265Frame::NAL_SPS:
case H265Frame::NAL_PPS:
@ -131,10 +131,10 @@ public:
}
public:
uint32_t timeStamp;
uint32_t ptsStamp = 0;
string buffer;
uint32_t iPrefixSize = 4;
uint32_t _dts = 0;
uint32_t _pts = 0;
uint32_t _prefix_size = 4;
string _buffer;
};
@ -356,27 +356,27 @@ private:
}
if(!_vps.empty()){
auto vpsFrame = std::make_shared<H265Frame>();
vpsFrame->iPrefixSize = 4;
vpsFrame->buffer.assign("\x0\x0\x0\x1", 4);
vpsFrame->buffer.append(_vps);
vpsFrame->timeStamp = frame->stamp();
vpsFrame->_prefix_size = 4;
vpsFrame->_buffer.assign("\x0\x0\x0\x1", 4);
vpsFrame->_buffer.append(_vps);
vpsFrame->_dts = frame->dts();
VideoTrack::inputFrame(vpsFrame);
}
if (!_sps.empty()) {
auto spsFrame = std::make_shared<H265Frame>();
spsFrame->iPrefixSize = 4;
spsFrame->buffer.assign("\x0\x0\x0\x1", 4);
spsFrame->buffer.append(_sps);
spsFrame->timeStamp = frame->stamp();
spsFrame->_prefix_size = 4;
spsFrame->_buffer.assign("\x0\x0\x0\x1", 4);
spsFrame->_buffer.append(_sps);
spsFrame->_dts = frame->dts();
VideoTrack::inputFrame(spsFrame);
}
if (!_pps.empty()) {
auto ppsFrame = std::make_shared<H265Frame>();
ppsFrame->iPrefixSize = 4;
ppsFrame->buffer.assign("\x0\x0\x0\x1", 4);
ppsFrame->buffer.append(_pps);
ppsFrame->timeStamp = frame->stamp();
ppsFrame->_prefix_size = 4;
ppsFrame->_buffer.assign("\x0\x0\x0\x1", 4);
ppsFrame->_buffer.append(_pps);
ppsFrame->_dts = frame->dts();
VideoTrack::inputFrame(ppsFrame);
}
}

View File

@ -70,8 +70,8 @@ H265RtpDecoder::H265RtpDecoder() {
H265Frame::Ptr H265RtpDecoder::obtainFrame() {
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
auto frame = ResourcePoolHelper<H265Frame>::obtainObj();
frame->buffer.clear();
frame->iPrefixSize = 4;
frame->_buffer.clear();
frame->_prefix_size = 4;
return frame;
}
@ -99,11 +99,11 @@ bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
MakeFU(frame[2], fu);
if (fu.S) {
//该帧的第一个rtp包
_h265frame->buffer.assign("\x0\x0\x0\x1", 4);
_h265frame->buffer.push_back(fu.type << 1);
_h265frame->buffer.push_back(0x01);
_h265frame->buffer.append((char *) frame + 3, length - 3);
_h265frame->timeStamp = rtppack->timeStamp;
_h265frame->_buffer.assign("\x0\x0\x0\x1", 4);
_h265frame->_buffer.push_back(fu.type << 1);
_h265frame->_buffer.push_back(0x01);
_h265frame->_buffer.append((char *) frame + 3, length - 3);
_h265frame->_pts = rtppack->timeStamp;
//该函数return时保存下当前sequence,以便下次对比seq是否连续
_lastSeq = rtppack->sequence;
return (_h265frame->keyFrame()); //i frame
@ -111,22 +111,22 @@ bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
if (rtppack->sequence != _lastSeq + 1 && rtppack->sequence != 0) {
//中间的或末尾的rtp包其seq必须连续(如果回环了则判定为连续)否则说明rtp丢包那么该帧不完整必须得丢弃
_h265frame->buffer.clear();
_h265frame->_buffer.clear();
WarnL << "rtp sequence不连续: " << rtppack->sequence << " != " << _lastSeq << " + 1,该帧被废弃";
return false;
}
if (!fu.E) {
//该帧的中间rtp包
_h265frame->buffer.append((char *) frame + 3, length - 3);
_h265frame->_buffer.append((char *) frame + 3, length - 3);
//该函数return时保存下当前sequence,以便下次对比seq是否连续
_lastSeq = rtppack->sequence;
return false;
}
//该帧最后一个rtp包
_h265frame->buffer.append((char *) frame + 3, length - 3);
_h265frame->timeStamp = rtppack->timeStamp;
_h265frame->_buffer.append((char *) frame + 3, length - 3);
_h265frame->_pts = rtppack->timeStamp;
auto key = _h265frame->keyFrame();
onGetH265(_h265frame);
return key;
@ -134,9 +134,9 @@ bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
default: // 4.4.1. Single NAL Unit Packets (p24)
//a full frame
_h265frame->buffer.assign("\x0\x0\x0\x1", 4);
_h265frame->buffer.append((char *)frame, length);
_h265frame->timeStamp = rtppack->timeStamp;
_h265frame->_buffer.assign("\x0\x0\x0\x1", 4);
_h265frame->_buffer.append((char *)frame, length);
_h265frame->_pts = rtppack->timeStamp;
auto key = _h265frame->keyFrame();
onGetH265(_h265frame);
return key;
@ -144,8 +144,12 @@ bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
}
void H265RtpDecoder::onGetH265(const H265Frame::Ptr &frame) {
//计算dts
auto flag = _dts_generator.getDts(frame->_pts,frame->_dts);
if(flag){
//写入环形缓存
RtpCodec::inputFrame(frame);
}
_h265frame = obtainFrame();
}
@ -167,7 +171,7 @@ H265RtpEncoder::H265RtpEncoder(uint32_t ui32Ssrc,
void H265RtpEncoder::inputFrame(const Frame::Ptr &frame) {
GET_CONFIG(uint32_t,cycleMS,Rtp::kCycleMS);
uint8_t *pcData = (uint8_t*)frame->data() + frame->prefixSize();
auto uiStamp = frame->stamp();
auto uiStamp = frame->pts();
auto iLen = frame->size() - frame->prefixSize();
unsigned char naluType = H265_TYPE(pcData[0]); //获取NALU的5bit 帧类型
uiStamp %= cycleMS;

View File

@ -30,6 +30,7 @@
#include "Rtsp/RtpCodec.h"
#include "Util/ResourcePool.h"
#include "Extension/H265.h"
#include "Common/Stamp.h"
using namespace toolkit;
@ -67,6 +68,7 @@ private:
H265Frame::Ptr obtainFrame();
private:
H265Frame::Ptr _h265frame;
DtsGenerator _dts_generator;
int _lastSeq = 0;
};

View File

@ -303,7 +303,7 @@ private:
//拦截websocket数据接收
_onRecv = [this](const Buffer::Ptr &pBuf){
//解析websocket数据包
WebSocketSplitter::decode((uint8_t*)pBuf->data(),pBuf->size());
this->WebSocketSplitter::decode((uint8_t*)pBuf->data(),pBuf->size());
};
return;
}

View File

@ -219,16 +219,26 @@ public:
virtual ~MuteAudioMaker(){}
void inputFrame(const Frame::Ptr &frame) override {
if(frame->getTrackType() == TrackVideo){
auto iAudioIndex = frame->stamp() / MUTE_ADTS_DATA_MS;
auto iAudioIndex = frame->dts() / MUTE_ADTS_DATA_MS;
if(_iAudioIndex != iAudioIndex){
_iAudioIndex = iAudioIndex;
auto aacFrame = std::make_shared<AACFrameNoCacheAble>((char *)MUTE_ADTS_DATA,
MUTE_ADTS_DATA_LEN,
_iAudioIndex * MUTE_ADTS_DATA_MS);
auto aacFrame = std::make_shared<AACFrameCacheAble>((char *)MUTE_ADTS_DATA, MUTE_ADTS_DATA_LEN, _iAudioIndex * MUTE_ADTS_DATA_MS);
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:
int _iAudioIndex = 0;
};

View File

@ -226,6 +226,8 @@ inline bool MP4Reader::readVideoSample(int iTimeInc,bool justSeekSyncFrame) {
MP4Duration pRenderingOffset;
if(MP4ReadSample(_hMP4File, _video_trId, iIdx + 1, &pBytes, &numBytes,NULL,NULL,&pRenderingOffset,&_bSyncSample)){
if (!justSeekSyncFrame) {
uint32_t dts = (double) _video_ms * iIdx / _video_num_samples;
uint32_t pts = dts + pRenderingOffset / 90;
uint32_t iOffset = 0;
while (iOffset < numBytes) {
uint32_t iFrameLen;
@ -235,8 +237,7 @@ inline bool MP4Reader::readVideoSample(int iTimeInc,bool justSeekSyncFrame) {
break;
}
memcpy(pBytes + iOffset, "\x0\x0\x0\x1", 4);
uint32_t dts = (double) _video_ms * iIdx / _video_num_samples;
writeH264(pBytes + iOffset, iFrameLen + 4, dts, dts + pRenderingOffset / 90);
writeH264(pBytes + iOffset, iFrameLen + 4, dts, pts);
iOffset += (iFrameLen + 4);
}
}else if(_bSyncSample){
@ -260,9 +261,10 @@ inline bool MP4Reader::readAudioSample(int iTimeInc,bool justSeekSyncFrame) {
uint8_t *pBytes = _adts.buffer + 7;
if(MP4ReadSample(_hMP4File, _audio_trId, i + 1, &pBytes, &numBytes)){
if (!justSeekSyncFrame) {
uint32_t dts = (double) _audio_ms * i / _audio_num_samples;
_adts.aac_frame_length = 7 + numBytes;
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{
ErrorL << "读取音频失败:" << i+ 1;

View File

@ -72,7 +72,6 @@ public:
const string &stream_id,
int ring_size = 0) :
MediaSource(RTMP_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) {
_metadata = TitleMeta().getMetadata();
}
virtual ~RtmpMediaSource() {}
@ -117,6 +116,9 @@ public:
virtual void setMetaData(const AMFValue &metadata) {
lock_guard<recursive_mutex> lock(_mtx);
_metadata = metadata;
if(_ring){
regist();
}
}
/**
@ -143,11 +145,10 @@ public:
_ring = std::make_shared<RingType>(_ring_size, std::move(lam));
onReaderChanged(0);
//如果输入了非config帧
//那么说明不再可能获取config帧以及metadata,
//所以我们强制其为已注册
if(_metadata){
regist();
}
}
_track_stamps_map[pkt->typeId] = pkt->timeStamp;
_ring->write(pkt, pkt->isVideoKeyFrame());
checkNoneReader();

View File

@ -66,6 +66,7 @@ private:
_pRtmpMediaSrc = dynamic_pointer_cast<RtmpMediaSource>(_pMediaSrc);
if(_pRtmpMediaSrc){
_pRtmpMediaSrc->setMetaData(val);
_set_meta_data = true;
}
_delegate.reset(new RtmpDemuxer);
_delegate->loadMetaData(val);
@ -73,6 +74,10 @@ private:
}
void onMediaData(const RtmpPacket::Ptr &chunkData) override {
if(_pRtmpMediaSrc){
if(!_set_meta_data && !chunkData->isCfgFrame()){
_set_meta_data = true;
_pRtmpMediaSrc->setMetaData(TitleMeta().getMetadata());
}
_pRtmpMediaSrc->onWrite(chunkData);
}
if(!_delegate){
@ -83,6 +88,7 @@ private:
}
private:
RtmpMediaSource::Ptr _pRtmpMediaSrc;
bool _set_meta_data = false;
};

View File

@ -332,7 +332,7 @@ void RtmpProtocol::handle_C0C1() {
//complex handsharke
handle_C1_complex();
#else
WarnL << "未打开ENABLE_OPENSSL宏复杂握手采用简单方式处理";
WarnL << "未打开ENABLE_OPENSSL宏复杂握手采用简单方式处理flash播放器可能无法播放";
handle_C1_simple();
#endif//ENABLE_OPENSSL
}
@ -372,10 +372,10 @@ void RtmpProtocol::handle_C1_complex(){
check_C1_Digest(digest,c1_joined);
send_complex_S0S1S2(0,digest);
InfoL << "schema0";
// InfoL << "schema0";
}catch(std::exception &ex){
//貌似flash从来都不用schema1
WarnL << "try rtmp complex schema0 failed:" << ex.what();
// WarnL << "try rtmp complex schema0 failed:" << ex.what();
try{
/* c1s1 schema1
time: 4bytes
@ -389,9 +389,9 @@ void RtmpProtocol::handle_C1_complex(){
check_C1_Digest(digest,c1_joined);
send_complex_S0S1S2(1,digest);
InfoL << "schema1";
// InfoL << "schema1";
}catch(std::exception &ex){
WarnL << "try rtmp complex schema1 failed:" << ex.what();
// WarnL << "try rtmp complex schema1 failed:" << ex.what();
handle_C1_simple();
}
}

View File

@ -434,6 +434,7 @@ void RtmpSession::setMetaData(AMFDecoder &dec) {
auto metadata = dec.load<AMFValue>();
// dumpMetadata(metadata);
_pPublisherSrc->setMetaData(metadata);
_set_meta_data = true;
}
void RtmpSession::onProcessCmd(AMFDecoder &dec) {
@ -452,7 +453,7 @@ void RtmpSession::onProcessCmd(AMFDecoder &dec) {
std::string method = dec.load<std::string>();
auto it = s_cmd_functions.find(method);
if (it == s_cmd_functions.end()) {
TraceP(this) << "can not support cmd:" << method;
// TraceP(this) << "can not support cmd:" << method;
return;
}
_dNowReqID = dec.load<double>();
@ -473,9 +474,10 @@ void RtmpSession::onRtmpChunk(RtmpPacket &chunkData) {
case MSG_DATA3: {
AMFDecoder dec(chunkData.strBuf, chunkData.typeId == MSG_CMD3 ? 1 : 0);
std::string type = dec.load<std::string>();
TraceP(this) << "notify:" << type;
if (type == "@setDataFrame") {
setMetaData(dec);
}else{
TraceP(this) << "unknown notify:" << type;
}
}
break;
@ -490,6 +492,11 @@ void RtmpSession::onRtmpChunk(RtmpPacket &chunkData) {
_stamp[chunkData.typeId % 2].revise(chunkData.timeStamp, chunkData.timeStamp, dts_out, dts_out, true);
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)));
}
break;

View File

@ -95,6 +95,7 @@ private:
std::string _strTcUrl;
MediaInfo _mediaInfo;
double _dNowReqID = 0;
bool _set_meta_data = false;
Ticker _ticker;//数据接收时间
RingBuffer<RtmpPacket::Ptr>::RingReader::Ptr _pRingReader;
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) {
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);
}
inline void RtspSession::onRcvPeerUdpData(int intervaled, const Buffer::Ptr &pBuf, const struct sockaddr& addr) {