commit
d40d9a5b5b
|
|
@ -1 +1 @@
|
|||
Subproject commit 2970df35c5c8c48013f91c818845c5c90914ea57
|
||||
Subproject commit 665f53b6a4385e2312d3bf09aa305d7e3bf079e6
|
||||
|
|
@ -167,6 +167,8 @@ keepAliveSecond=15
|
|||
port=554
|
||||
#rtsps服务器监听地址
|
||||
sslport=322
|
||||
#在接收rtsp推流时,是否重新生成时间戳(很多推流器的时间戳着实很烂)
|
||||
modifyStamp=1
|
||||
|
||||
[shell]
|
||||
#调试telnet服务器接受最大bufffer大小
|
||||
|
|
|
|||
|
|
@ -35,16 +35,6 @@ void MediaSink::addTrack(const Track::Ptr &track_in) {
|
|||
//克隆Track,只拷贝其数据,不拷贝其数据转发关系
|
||||
auto track = track_in->clone();
|
||||
|
||||
weak_ptr<MediaSink> weakSelf = shared_from_this();
|
||||
track->addDelegate(std::make_shared<FrameWriterInterfaceHelper>([weakSelf](const Frame::Ptr &frame){
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if(!strongSelf){
|
||||
return;
|
||||
}
|
||||
if(!strongSelf->_anyTrackUnReady){
|
||||
strongSelf->onTrackFrame(frame);
|
||||
}
|
||||
}));
|
||||
auto codec_id = track->getCodecId();
|
||||
_track_map[codec_id] = track;
|
||||
auto lam = [this,track](){
|
||||
|
|
@ -58,10 +48,22 @@ void MediaSink::addTrack(const Track::Ptr &track_in) {
|
|||
_trackReadyCallback[codec_id] = lam;
|
||||
_ticker.resetTime();
|
||||
}
|
||||
|
||||
weak_ptr<MediaSink> weakSelf = shared_from_this();
|
||||
track->addDelegate(std::make_shared<FrameWriterInterfaceHelper>([weakSelf](const Frame::Ptr &frame){
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if(!strongSelf){
|
||||
return;
|
||||
}
|
||||
if(!strongSelf->_anyTrackUnReady){
|
||||
strongSelf->onTrackFrame(frame);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
void MediaSink::resetTracks() {
|
||||
_anyTrackUnReady = true;
|
||||
lock_guard<recursive_mutex> lck(_mtx);
|
||||
_anyTrackUnReady = false;
|
||||
_allTrackReady = false;
|
||||
_track_map.clear();
|
||||
_trackReadyCallback.clear();
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ onceToken token([](){
|
|||
mINI::Instance()[kHandshakeSecond] = 15;
|
||||
mINI::Instance()[kKeepAliveSecond] = 15;
|
||||
mINI::Instance()[kDirectProxy] = 1;
|
||||
mINI::Instance()[kModifyStamp] = true;
|
||||
mINI::Instance()[kModifyStamp] = false;
|
||||
},nullptr);
|
||||
|
||||
} //namespace Rtsp
|
||||
|
|
|
|||
|
|
@ -43,11 +43,6 @@ void HlsMaker::makeIndexFile(bool eof) {
|
|||
char file_content[1024];
|
||||
int maxSegmentDuration = 0;
|
||||
|
||||
//停止写之后将最后的片段也写进m3u8文件中
|
||||
if (eof && _stampInc > 0) {
|
||||
_seg_dur_list.push_back(std::make_tuple(_stampInc, _last_file_name));
|
||||
}
|
||||
|
||||
for (auto &tp : _seg_dur_list) {
|
||||
int dur = std::get<0>(tp);
|
||||
if (dur > maxSegmentDuration) {
|
||||
|
|
@ -83,19 +78,16 @@ void HlsMaker::makeIndexFile(bool eof) {
|
|||
void HlsMaker::inputData(void *data, uint32_t len, uint32_t timestamp) {
|
||||
//分片数据中断结束
|
||||
if (data && len) {
|
||||
addNewFile(timestamp);
|
||||
onWriteFile((char *) data, len);
|
||||
}
|
||||
else {
|
||||
_noData = true;
|
||||
_stampInc = _ticker.elapsedTime();
|
||||
_seg_dur_list.push_back(std::make_tuple(_stampInc, _last_file_name));
|
||||
delOldFile();
|
||||
makeIndexFile();
|
||||
addNewSegment(timestamp);
|
||||
onWriteSegment((char *) data, len);
|
||||
//记录上次写入数据时间
|
||||
_ticker_last_data.resetTime();
|
||||
} else {
|
||||
flushLastSegment(true);
|
||||
}
|
||||
}
|
||||
|
||||
void HlsMaker::delOldFile() {
|
||||
void HlsMaker::delOldSegment() {
|
||||
if(_seg_number == 0){
|
||||
//如果设置为保留0个切片,则认为是保存为点播
|
||||
return;
|
||||
|
|
@ -107,28 +99,38 @@ void HlsMaker::delOldFile() {
|
|||
|
||||
//但是实际保存的切片个数比m3u8所述多两个,这样做的目的是防止播放器在切片删除前能下载完毕
|
||||
if (_file_index >= _seg_number + 4) {
|
||||
onDelFile(_file_index - _seg_number - 4);
|
||||
onDelSegment(_file_index - _seg_number - 4);
|
||||
}
|
||||
}
|
||||
|
||||
void HlsMaker::addNewFile(uint32_t) {
|
||||
//上次分片数据中断结束,重置时间避免中途的等待
|
||||
if (_noData) {
|
||||
void HlsMaker::addNewSegment(uint32_t) {
|
||||
if(!_last_file_name.empty() && _ticker.elapsedTime() < _seg_duration * 1000){
|
||||
//存在上个切片,并且未到分片时间
|
||||
return;
|
||||
}
|
||||
|
||||
//关闭并保存上一个切片
|
||||
flushLastSegment();
|
||||
//新增切片
|
||||
_last_file_name = onOpenSegment(_file_index++);
|
||||
//重置切片计时器
|
||||
_ticker.resetTime();
|
||||
_last_file_name = onOpenFile(_file_index++);
|
||||
_noData = false;
|
||||
}
|
||||
|
||||
void HlsMaker::flushLastSegment(bool eof){
|
||||
if(_last_file_name.empty()){
|
||||
//不存在上个切片
|
||||
return;
|
||||
}
|
||||
_stampInc = _ticker.elapsedTime();
|
||||
if (_file_index == 0 || _stampInc >= _seg_duration * 1000) {
|
||||
_ticker.resetTime();
|
||||
auto file_name = onOpenFile(_file_index);
|
||||
if (_file_index++ > 0) {
|
||||
_seg_dur_list.push_back(std::make_tuple(_stampInc, _last_file_name));
|
||||
delOldFile();
|
||||
makeIndexFile();
|
||||
}
|
||||
_last_file_name = file_name;
|
||||
//文件创建到最后一次数据写入的时间即为切片长度
|
||||
auto seg_dur = _ticker.elapsedTime() - _ticker_last_data.elapsedTime();
|
||||
if(seg_dur <= 0){
|
||||
seg_dur = 100;
|
||||
}
|
||||
_seg_dur_list.push_back(std::make_tuple(seg_dur, _last_file_name));
|
||||
delOldSegment();
|
||||
makeIndexFile(eof);
|
||||
_last_file_name.clear();
|
||||
}
|
||||
|
||||
}//namespace mediakit
|
||||
|
|
@ -60,20 +60,20 @@ protected:
|
|||
* @param index
|
||||
* @return
|
||||
*/
|
||||
virtual string onOpenFile(int index) = 0;
|
||||
virtual string onOpenSegment(int index) = 0;
|
||||
|
||||
/**
|
||||
* 删除ts切片文件回调
|
||||
* @param index
|
||||
*/
|
||||
virtual void onDelFile(int index) = 0;
|
||||
virtual void onDelSegment(int index) = 0;
|
||||
|
||||
/**
|
||||
* 写ts切片文件回调
|
||||
* @param data
|
||||
* @param len
|
||||
*/
|
||||
virtual void onWriteFile(const char *data, int len) = 0;
|
||||
virtual void onWriteSegment(const char *data, int len) = 0;
|
||||
|
||||
/**
|
||||
* 写m3u8文件回调
|
||||
|
|
@ -82,21 +82,34 @@ protected:
|
|||
*/
|
||||
virtual void onWriteHls(const char *data, int len) = 0;
|
||||
|
||||
/**
|
||||
* 关闭上个ts切片并且写入m3u8索引
|
||||
* @param eof
|
||||
*/
|
||||
void flushLastSegment(bool eof = false);
|
||||
private:
|
||||
/**
|
||||
* 生成m3u8文件
|
||||
* @param eof true代表点播
|
||||
*/
|
||||
void makeIndexFile(bool eof = false);
|
||||
void delOldFile();
|
||||
void addNewFile(uint32_t timestamp);
|
||||
protected:
|
||||
uint32_t _seg_number = 0;
|
||||
|
||||
/**
|
||||
* 删除旧的ts切片
|
||||
*/
|
||||
void delOldSegment();
|
||||
|
||||
/**
|
||||
* 添加新的ts切片
|
||||
* @param timestamp
|
||||
*/
|
||||
void addNewSegment(uint32_t timestamp);
|
||||
private:
|
||||
bool _noData = false;
|
||||
int _stampInc = 0;
|
||||
uint32_t _seg_number = 0;
|
||||
float _seg_duration = 0;
|
||||
uint64_t _file_index = 0;
|
||||
Ticker _ticker;
|
||||
Ticker _ticker_last_data;
|
||||
string _last_file_name;
|
||||
std::deque<tuple<int,string> > _seg_dur_list;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ HlsMakerImp::HlsMakerImp(const string &m3u8_file,
|
|||
_path_hls = m3u8_file;
|
||||
_params = params;
|
||||
_buf_size = bufSize;
|
||||
_is_vod = seg_number == 0;
|
||||
_file_buf.reset(new char[bufSize],[](char *ptr){
|
||||
delete[] ptr;
|
||||
});
|
||||
|
|
@ -47,14 +48,14 @@ HlsMakerImp::HlsMakerImp(const string &m3u8_file,
|
|||
|
||||
HlsMakerImp::~HlsMakerImp() {
|
||||
//录制完了
|
||||
makeIndexFile(true);
|
||||
if(_seg_number){
|
||||
flushLastSegment(true);
|
||||
if(!_is_vod){
|
||||
//hls直播才删除文件
|
||||
File::delete_file(_path_prefix.data());
|
||||
}
|
||||
}
|
||||
|
||||
string HlsMakerImp::onOpenFile(int index) {
|
||||
string HlsMakerImp::onOpenSegment(int index) {
|
||||
auto full_path = fullPath(index);
|
||||
_file = makeFile(full_path, true);
|
||||
if(!_file){
|
||||
|
|
@ -67,12 +68,12 @@ string HlsMakerImp::onOpenFile(int index) {
|
|||
return StrPrinter << index << ".ts" << "?" << _params;
|
||||
}
|
||||
|
||||
void HlsMakerImp::onDelFile(int index) {
|
||||
void HlsMakerImp::onDelSegment(int index) {
|
||||
//WarnL << index;
|
||||
File::delete_file(fullPath(index).data());
|
||||
}
|
||||
|
||||
void HlsMakerImp::onWriteFile(const char *data, int len) {
|
||||
void HlsMakerImp::onWriteSegment(const char *data, int len) {
|
||||
if (_file) {
|
||||
fwrite(data, len, 1, _file.get());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,9 +44,9 @@ public:
|
|||
uint32_t seg_number = 3);
|
||||
virtual ~HlsMakerImp();
|
||||
protected:
|
||||
string onOpenFile(int index) override ;
|
||||
void onDelFile(int index) override;
|
||||
void onWriteFile(const char *data, int len) override;
|
||||
string onOpenSegment(int index) override ;
|
||||
void onDelSegment(int index) override;
|
||||
void onWriteSegment(const char *data, int len) override;
|
||||
void onWriteHls(const char *data, int len) override;
|
||||
private:
|
||||
string fullPath(int index);
|
||||
|
|
@ -58,6 +58,8 @@ private:
|
|||
string _path_hls;
|
||||
string _params;
|
||||
int _buf_size;
|
||||
//是否为点播
|
||||
bool _is_vod;
|
||||
};
|
||||
|
||||
}//namespace mediakit
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public:
|
|||
* 只会克隆sps pps这些信息 ,而不会克隆Delegate相关关系
|
||||
* @param track
|
||||
*/
|
||||
void addTrack(const Track::Ptr & track) override;
|
||||
void addTrack(const Track::Ptr &track) override;
|
||||
|
||||
/**
|
||||
* 重置track
|
||||
|
|
|
|||
|
|
@ -51,12 +51,9 @@ void DeltaStamp::setPlayBack(bool playback) {
|
|||
_playback = playback;
|
||||
}
|
||||
|
||||
void Stamp::revise(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out) {
|
||||
if(!dts && !pts){
|
||||
//没有时间戳,我们生成时间戳
|
||||
pts = dts = _ticker.elapsedTime();
|
||||
}else if(!pts){
|
||||
//只是没有播放时间戳,使其赋值为解码时间戳
|
||||
void Stamp::revise(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out,bool modifyStamp) {
|
||||
if(!pts){
|
||||
//没有播放时间戳,使其赋值为解码时间戳
|
||||
pts = dts;
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +61,7 @@ void Stamp::revise(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out)
|
|||
int pts_dts_diff = pts - dts;
|
||||
|
||||
//相对时间戳
|
||||
_relativeStamp += deltaStamp(dts);
|
||||
_relativeStamp += deltaStamp(modifyStamp ? _ticker.elapsedTime() : dts);
|
||||
dts_out = _relativeStamp;
|
||||
|
||||
//////////////以下是播放时间戳的计算//////////////////
|
||||
|
|
|
|||
|
|
@ -67,8 +67,9 @@ public:
|
|||
* @param pts 输入pts,如果为0则等于dts
|
||||
* @param dts_out 输出dts
|
||||
* @param pts_out 输出pts
|
||||
* @param modifyStamp 是否用系统时间戳覆盖
|
||||
*/
|
||||
void revise(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out);
|
||||
void revise(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out,bool modifyStamp = false);
|
||||
|
||||
/**
|
||||
* 再设置相对时间戳,用于seek用
|
||||
|
|
|
|||
|
|
@ -486,7 +486,7 @@ void RtmpSession::onRtmpChunk(RtmpPacket &chunkData) {
|
|||
GET_CONFIG(bool,rtmp_modify_stamp,Rtmp::kModifyStamp);
|
||||
if(rtmp_modify_stamp){
|
||||
int64_t dts_out;
|
||||
_stamp[chunkData.typeId % 2].revise(0, 0, dts_out, dts_out);
|
||||
_stamp[chunkData.typeId % 2].revise(0, 0, dts_out, dts_out, true);
|
||||
chunkData.timeStamp = dts_out;
|
||||
}
|
||||
if(!_metadata_got && !chunkData.isCfgFrame()){
|
||||
|
|
|
|||
|
|
@ -76,24 +76,35 @@ void RtspPlayer::teardown(){
|
|||
}
|
||||
|
||||
void RtspPlayer::play(const string &strUrl){
|
||||
auto userAndPwd = FindField(strUrl.data(),"://","@");
|
||||
Rtsp::eRtpType eType = (Rtsp::eRtpType)(int)(*this)[kRtpType];
|
||||
if(userAndPwd.empty()){
|
||||
play(strUrl,"","",eType);
|
||||
auto schema = FindField(strUrl.data(), nullptr,"://");
|
||||
bool isSSL = strcasecmp(schema.data(),"rtsps") == 0;
|
||||
//查找"://"与"/"之间的字符串,用于提取用户名密码
|
||||
auto middle_url = FindField(strUrl.data(),"://","/");
|
||||
if(middle_url.empty()){
|
||||
middle_url = FindField(strUrl.data(),"://", nullptr);
|
||||
}
|
||||
auto pos = middle_url.rfind('@');
|
||||
if(pos == string::npos){
|
||||
//并没有用户名密码
|
||||
play(isSSL,strUrl,"","",eType);
|
||||
return;
|
||||
}
|
||||
auto suffix = FindField(strUrl.data(),"@",nullptr);
|
||||
|
||||
//包含用户名密码
|
||||
auto user_pwd = middle_url.substr(0,pos);
|
||||
auto suffix = strUrl.substr(schema.size() + 3 + pos + 1);
|
||||
auto url = StrPrinter << "rtsp://" << suffix << endl;
|
||||
if(userAndPwd.find(":") == string::npos){
|
||||
play(url,userAndPwd,"",eType);
|
||||
if(user_pwd.find(":") == string::npos){
|
||||
play(isSSL,url,user_pwd,"",eType);
|
||||
return;
|
||||
}
|
||||
auto user = FindField(userAndPwd.data(),nullptr,":");
|
||||
auto pwd = FindField(userAndPwd.data(),":",nullptr);
|
||||
play(url,user,pwd,eType);
|
||||
auto user = FindField(user_pwd.data(),nullptr,":");
|
||||
auto pwd = FindField(user_pwd.data(),":",nullptr);
|
||||
play(isSSL,url,user,pwd,eType);
|
||||
}
|
||||
//播放,指定是否走rtp over tcp
|
||||
void RtspPlayer::play(const string &strUrl, const string &strUser, const string &strPwd, Rtsp::eRtpType eType ) {
|
||||
|
||||
void RtspPlayer::play(bool isSSL,const string &strUrl, const string &strUser, const string &strPwd, Rtsp::eRtpType eType ) {
|
||||
DebugL << strUrl << " "
|
||||
<< (strUser.size() ? strUser : "null") << " "
|
||||
<< (strPwd.size() ? strPwd:"null") << " "
|
||||
|
|
@ -112,12 +123,12 @@ void RtspPlayer::play(const string &strUrl, const string &strUser, const string
|
|||
|
||||
auto ip = FindField(strUrl.data(), "://", "/");
|
||||
if (!ip.size()) {
|
||||
ip = FindField(strUrl.data(), "://", NULL);
|
||||
ip = split(FindField(strUrl.data(), "://", NULL),"?")[0];
|
||||
}
|
||||
auto port = atoi(FindField(ip.data(), ":", NULL).data());
|
||||
if (port <= 0) {
|
||||
//rtsp 默认端口554
|
||||
port = 554;
|
||||
port = isSSL ? 322 : 554;
|
||||
} else {
|
||||
//服务器域名
|
||||
ip = FindField(ip.data(), NULL, ":");
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ private:
|
|||
int getTrackIndexByInterleaved(int interleaved) const;
|
||||
int getTrackIndexByTrackType(TrackType trackType) const;
|
||||
|
||||
void play(const string &strUrl, const string &strUser, const string &strPwd, Rtsp::eRtpType eType);
|
||||
void play(bool isSSL,const string &strUrl, const string &strUser, const string &strPwd, Rtsp::eRtpType eType);
|
||||
void handleResSETUP(const Parser &parser, unsigned int uiTrackIndex);
|
||||
void handleResDESCRIBE(const Parser &parser);
|
||||
bool handleAuthenticationFailure(const string &wwwAuthenticateParamsStr);
|
||||
|
|
|
|||
|
|
@ -932,7 +932,7 @@ 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(0, 0, dts_out, dts_out);
|
||||
_stamp[trackidx].revise(0, 0, dts_out, dts_out, true);
|
||||
rtppt->timeStamp = dts_out;
|
||||
}
|
||||
_pushSrc->onWrite(rtppt, false);
|
||||
|
|
|
|||
Loading…
Reference in New Issue