mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-25 20:27:34 +08:00
Merge branch 'master' into research
This commit is contained in:
commit
dad0175094
19
README.md
19
README.md
@ -376,6 +376,25 @@ git submodule update --init
|
||||
- 2、如果您的问题还没解决,可以提issue.
|
||||
- 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>)
|
||||
|
||||
## 捐赠
|
||||
欢迎捐赠以便更好的推动项目的发展,谢谢您的支持!
|
||||
|
@ -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);
|
||||
|
||||
|
@ -191,8 +191,6 @@ keepAliveSecond=15
|
||||
port=554
|
||||
#rtsps服务器监听地址
|
||||
sslport=322
|
||||
#在接收rtsp推流时,是否重新生成时间戳(很多推流器的时间戳着实很烂)
|
||||
modifyStamp=0
|
||||
|
||||
[shell]
|
||||
#调试telnet服务器接受最大bufffer大小
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
}
|
||||
_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,26 +79,50 @@ void MediaSink::inputFrame(const Frame::Ptr &frame) {
|
||||
}
|
||||
}
|
||||
|
||||
if(!_allTrackReady && (_trackReadyCallback.empty() || _ticker.elapsedTime() > MAX_WAIT_MS)){
|
||||
_allTrackReady = true;
|
||||
_anyTrackUnReady = false;
|
||||
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(!_allTrackReady){
|
||||
if(_ticker.elapsedTime() > MAX_WAIT_MS_READY){
|
||||
//如果超过规定时间,那么不再等待并忽略未准备好的Track
|
||||
emitAllTrackReady();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!_track_map.empty()){
|
||||
//最少有一个有效的Track
|
||||
onAllTrackReady();
|
||||
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;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
_last_stamp = stamp;
|
||||
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
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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服务器配置///////////
|
||||
|
@ -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;
|
||||
} ;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 返回解码时间戳,单位毫秒
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
//写入环形缓存
|
||||
RtpCodec::inputFrame(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]);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
//写入环形缓存
|
||||
RtpCodec::inputFrame(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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -225,8 +225,10 @@ inline bool MP4Reader::readVideoSample(int iTimeInc,bool justSeekSyncFrame) {
|
||||
uint32_t numBytes = _video_sample_max_size;
|
||||
MP4Duration pRenderingOffset;
|
||||
if(MP4ReadSample(_hMP4File, _video_trId, iIdx + 1, &pBytes, &numBytes,NULL,NULL,&pRenderingOffset,&_bSyncSample)){
|
||||
if (!justSeekSyncFrame) {
|
||||
uint32_t iOffset = 0;
|
||||
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;
|
||||
memcpy(&iFrameLen,pBytes + iOffset,4);
|
||||
@ -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;
|
||||
|
@ -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,10 +145,9 @@ public:
|
||||
_ring = std::make_shared<RingType>(_ring_size, std::move(lam));
|
||||
onReaderChanged(0);
|
||||
|
||||
//如果输入了非config帧,
|
||||
//那么说明不再可能获取config帧以及metadata,
|
||||
//所以我们强制其为已注册
|
||||
regist();
|
||||
if(_metadata){
|
||||
regist();
|
||||
}
|
||||
}
|
||||
_track_stamps_map[pkt->typeId] = pkt->timeStamp;
|
||||
_ring->write(pkt, pkt->isVideoKeyFrame());
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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,10 +474,11 @@ 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;
|
||||
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);
|
||||
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;
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user