mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-26 12:37:09 +08:00
添加断流重连是否接着前一次继续写;修复断流重连成功后hls时间戳错误问题
This commit is contained in:
parent
7d76a3eb9b
commit
d6e60e0919
@ -32,6 +32,9 @@ streamNoneReaderDelayMS=5000
|
|||||||
ultraLowDelay=1
|
ultraLowDelay=1
|
||||||
#拉流代理是否添加静音音频(直接拉流模式本协议无效)
|
#拉流代理是否添加静音音频(直接拉流模式本协议无效)
|
||||||
addMuteAudio=1
|
addMuteAudio=1
|
||||||
|
#拉流代理时如果断流再重连成功是否删除前一次的媒体流数据,如果删除将重新开始,
|
||||||
|
#如果不删除将会接着上一次的数据继续写(录制hls/mp4时会继续在前一个文件后面写)
|
||||||
|
resetWhenRePlay=1
|
||||||
|
|
||||||
[hls]
|
[hls]
|
||||||
#hls写文件的buf大小,调整参数可以提高文件io性能
|
#hls写文件的buf大小,调整参数可以提高文件io性能
|
||||||
|
@ -32,7 +32,7 @@ namespace mediakit{
|
|||||||
|
|
||||||
void MediaSink::addTrack(const Track::Ptr &track_in) {
|
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();
|
||||||
|
|
||||||
weak_ptr<MediaSink> weakSelf = shared_from_this();
|
weak_ptr<MediaSink> weakSelf = shared_from_this();
|
||||||
@ -60,6 +60,14 @@ void MediaSink::addTrack(const Track::Ptr &track_in) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MediaSink::resetTracks() {
|
||||||
|
_anyTrackUnReady = true;
|
||||||
|
_allTrackReady = false;
|
||||||
|
_track_map.clear();
|
||||||
|
_trackReadyCallback.clear();
|
||||||
|
_ticker.resetTime();
|
||||||
|
}
|
||||||
|
|
||||||
void MediaSink::inputFrame(const Frame::Ptr &frame) {
|
void MediaSink::inputFrame(const Frame::Ptr &frame) {
|
||||||
lock_guard<recursive_mutex> lck(_mtx);
|
lock_guard<recursive_mutex> lck(_mtx);
|
||||||
auto codec_id = frame->getCodecId();
|
auto codec_id = frame->getCodecId();
|
||||||
|
@ -52,7 +52,7 @@ public:
|
|||||||
* 输入frame
|
* 输入frame
|
||||||
* @param frame
|
* @param frame
|
||||||
*/
|
*/
|
||||||
void inputFrame(const Frame::Ptr &frame) override ;
|
void inputFrame(const Frame::Ptr &frame) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加track,内部会调用Track的clone方法
|
* 添加track,内部会调用Track的clone方法
|
||||||
@ -61,13 +61,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void addTrack(const Track::Ptr & track);
|
virtual void addTrack(const Track::Ptr & track);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置track
|
||||||
|
*/
|
||||||
|
virtual void resetTracks();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 全部Track是否都准备好了
|
* 全部Track是否都准备好了
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
bool isAllTrackReady() const ;
|
bool isAllTrackReady() const;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取特定类型的Track
|
* 获取特定类型的Track
|
||||||
@ -75,7 +78,7 @@ public:
|
|||||||
* @param trackReady 是否获取已经准备好的Track
|
* @param trackReady 是否获取已经准备好的Track
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
Track::Ptr getTrack(TrackType type,bool trackReady = true) const ;
|
Track::Ptr getTrack(TrackType type,bool trackReady = true) const;
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* 某track已经准备好,其ready()状态返回true,
|
* 某track已经准备好,其ready()状态返回true,
|
||||||
|
@ -69,6 +69,19 @@ public:
|
|||||||
_record->addTrack(track);
|
_record->addTrack(track);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置音视频媒体
|
||||||
|
*/
|
||||||
|
void resetTracks() {
|
||||||
|
if(_rtmp){
|
||||||
|
_rtmp->resetTracks();
|
||||||
|
}
|
||||||
|
if(_rtsp){
|
||||||
|
_rtsp->resetTracks();
|
||||||
|
}
|
||||||
|
_record->resetTracks();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 写入帧数据然后打包rtmp
|
* 写入帧数据然后打包rtmp
|
||||||
* @param frame 帧数据
|
* @param frame 帧数据
|
||||||
|
@ -78,6 +78,7 @@ const string kMaxStreamWaitTimeMS = GENERAL_FIELD"maxStreamWaitMS";
|
|||||||
const string kEnableVhost = GENERAL_FIELD"enableVhost";
|
const string kEnableVhost = GENERAL_FIELD"enableVhost";
|
||||||
const string kUltraLowDelay = GENERAL_FIELD"ultraLowDelay";
|
const string kUltraLowDelay = GENERAL_FIELD"ultraLowDelay";
|
||||||
const string kAddMuteAudio = GENERAL_FIELD"addMuteAudio";
|
const string kAddMuteAudio = GENERAL_FIELD"addMuteAudio";
|
||||||
|
const string kResetWhenRePlay = GENERAL_FIELD"resetWhenRePlay";
|
||||||
|
|
||||||
onceToken token([](){
|
onceToken token([](){
|
||||||
mINI::Instance()[kFlowThreshold] = 1024;
|
mINI::Instance()[kFlowThreshold] = 1024;
|
||||||
@ -86,6 +87,7 @@ onceToken token([](){
|
|||||||
mINI::Instance()[kEnableVhost] = 1;
|
mINI::Instance()[kEnableVhost] = 1;
|
||||||
mINI::Instance()[kUltraLowDelay] = 1;
|
mINI::Instance()[kUltraLowDelay] = 1;
|
||||||
mINI::Instance()[kAddMuteAudio] = 1;
|
mINI::Instance()[kAddMuteAudio] = 1;
|
||||||
|
mINI::Instance()[kResetWhenRePlay] = 1;
|
||||||
},nullptr);
|
},nullptr);
|
||||||
|
|
||||||
}//namespace General
|
}//namespace General
|
||||||
|
@ -179,6 +179,9 @@ extern const string kEnableVhost;
|
|||||||
extern const string kUltraLowDelay;
|
extern const string kUltraLowDelay;
|
||||||
//拉流代理时是否添加静音音频
|
//拉流代理时是否添加静音音频
|
||||||
extern const string kAddMuteAudio;
|
extern const string kAddMuteAudio;
|
||||||
|
//拉流代理时如果断流再重连成功是否删除前一次的媒体流数据,如果删除将重新开始,
|
||||||
|
//如果不删除将会接着上一次的数据继续写(录制hls/mp4时会继续在前一个文件后面写)
|
||||||
|
extern const string kResetWhenRePlay;
|
||||||
}//namespace General
|
}//namespace General
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,8 +81,18 @@ void HlsMaker::makeIndexFile(bool eof) {
|
|||||||
|
|
||||||
|
|
||||||
void HlsMaker::inputData(void *data, uint32_t len, uint32_t timestamp) {
|
void HlsMaker::inputData(void *data, uint32_t len, uint32_t timestamp) {
|
||||||
|
//分片数据中断结束
|
||||||
|
if (data && len) {
|
||||||
addNewFile(timestamp);
|
addNewFile(timestamp);
|
||||||
onWriteFile((char *) data, len);
|
onWriteFile((char *) data, len);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_noData = true;
|
||||||
|
_stampInc = _ticker.elapsedTime();
|
||||||
|
_seg_dur_list.push_back(std::make_tuple(_stampInc, _last_file_name));
|
||||||
|
delOldFile();
|
||||||
|
makeIndexFile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HlsMaker::delOldFile() {
|
void HlsMaker::delOldFile() {
|
||||||
@ -102,6 +112,12 @@ void HlsMaker::delOldFile() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HlsMaker::addNewFile(uint32_t) {
|
void HlsMaker::addNewFile(uint32_t) {
|
||||||
|
//上次分片数据中断结束,重置时间避免中途的等待
|
||||||
|
if (_noData) {
|
||||||
|
_ticker.resetTime();
|
||||||
|
_last_file_name = onOpenFile(_file_index++);
|
||||||
|
_noData = false;
|
||||||
|
}
|
||||||
_stampInc = _ticker.elapsedTime();
|
_stampInc = _ticker.elapsedTime();
|
||||||
if (_file_index == 0 || _stampInc >= _seg_duration * 1000) {
|
if (_file_index == 0 || _stampInc >= _seg_duration * 1000) {
|
||||||
_ticker.resetTime();
|
_ticker.resetTime();
|
||||||
|
@ -92,6 +92,7 @@ protected:
|
|||||||
protected:
|
protected:
|
||||||
uint32_t _seg_number = 0;
|
uint32_t _seg_number = 0;
|
||||||
private:
|
private:
|
||||||
|
bool _noData = false;
|
||||||
int _stampInc = 0;
|
int _stampInc = 0;
|
||||||
float _seg_duration = 0;
|
float _seg_duration = 0;
|
||||||
uint64_t _file_index = 0;
|
uint64_t _file_index = 0;
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
|
|
||||||
class HlsRecorder : public HlsMakerImp , public TsMuxer {
|
class HlsRecorder : public HlsMakerImp, public TsMuxer {
|
||||||
public:
|
public:
|
||||||
template<typename ...ArgsType>
|
template<typename ...ArgsType>
|
||||||
HlsRecorder(ArgsType &&...args):HlsMakerImp(std::forward<ArgsType>(args)...){}
|
HlsRecorder(ArgsType &&...args):HlsMakerImp(std::forward<ArgsType>(args)...){}
|
||||||
|
@ -113,4 +113,18 @@ void MediaRecorder::addTrack(const Track::Ptr &track) {
|
|||||||
#endif //defined(ENABLE_MP4RECORD)
|
#endif //defined(ENABLE_MP4RECORD)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MediaRecorder::resetTracks() {
|
||||||
|
#if defined(ENABLE_HLS)
|
||||||
|
if (_hlsRecorder) {
|
||||||
|
_hlsRecorder->resetTracks();
|
||||||
|
}
|
||||||
|
#endif //defined(ENABLE_HLS)
|
||||||
|
|
||||||
|
#if defined(ENABLE_MP4RECORD)
|
||||||
|
if (_mp4Recorder) {
|
||||||
|
_mp4Recorder->resetTracks();
|
||||||
|
}
|
||||||
|
#endif //defined(ENABLE_MP4RECORD)
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace mediakit */
|
} /* namespace mediakit */
|
||||||
|
@ -51,7 +51,7 @@ public:
|
|||||||
* 输入frame
|
* 输入frame
|
||||||
* @param frame
|
* @param frame
|
||||||
*/
|
*/
|
||||||
void inputFrame(const Frame::Ptr &frame) override ;
|
void inputFrame(const Frame::Ptr &frame) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加track,内部会调用Track的clone方法
|
* 添加track,内部会调用Track的clone方法
|
||||||
@ -59,6 +59,11 @@ public:
|
|||||||
* @param track
|
* @param track
|
||||||
*/
|
*/
|
||||||
void addTrack(const Track::Ptr & track) override;
|
void addTrack(const Track::Ptr & track) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置track
|
||||||
|
*/
|
||||||
|
void resetTracks() override;
|
||||||
private:
|
private:
|
||||||
#if defined(ENABLE_HLS)
|
#if defined(ENABLE_HLS)
|
||||||
std::shared_ptr<HlsRecorder> _hlsRecorder;
|
std::shared_ptr<HlsRecorder> _hlsRecorder;
|
||||||
|
@ -101,6 +101,8 @@ void TsMuxer::inputFrame(const Frame::Ptr &frame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TsMuxer::resetTracks() {
|
void TsMuxer::resetTracks() {
|
||||||
|
//通知片段中断
|
||||||
|
onTs(nullptr, 0, 0, 0);
|
||||||
uninit();
|
uninit();
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
@ -43,10 +43,10 @@ public:
|
|||||||
TsMuxer();
|
TsMuxer();
|
||||||
virtual ~TsMuxer();
|
virtual ~TsMuxer();
|
||||||
void addTrack(const Track::Ptr &track) override;
|
void addTrack(const Track::Ptr &track) override;
|
||||||
|
void resetTracks() override;
|
||||||
void inputFrame(const Frame::Ptr &frame) override;
|
void inputFrame(const Frame::Ptr &frame) override;
|
||||||
protected:
|
protected:
|
||||||
virtual void onTs(const void *packet, int bytes,uint32_t timestamp,int flags) = 0;
|
virtual void onTs(const void *packet, int bytes,uint32_t timestamp,int flags) = 0;
|
||||||
void resetTracks();
|
|
||||||
private:
|
private:
|
||||||
void init();
|
void init();
|
||||||
void uninit();
|
void uninit();
|
||||||
|
@ -122,7 +122,13 @@ void PlayerProxy::play(const string &strUrlTmp) {
|
|||||||
for (auto & track : tracks){
|
for (auto & track : tracks){
|
||||||
track->delDelegate(strongSelf->_mediaMuxer.get());
|
track->delDelegate(strongSelf->_mediaMuxer.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GET_CONFIG(bool,resetWhenRePlay,General::kResetWhenRePlay);
|
||||||
|
if (resetWhenRePlay) {
|
||||||
strongSelf->_mediaMuxer.reset();
|
strongSelf->_mediaMuxer.reset();
|
||||||
|
} else {
|
||||||
|
strongSelf->_mediaMuxer->resetTracks();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//播放异常中断,延时重试播放
|
//播放异常中断,延时重试播放
|
||||||
if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) {
|
if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) {
|
||||||
@ -138,7 +144,7 @@ void PlayerProxy::play(const string &strUrlTmp) {
|
|||||||
if(directProxy && _bEnableRtsp){
|
if(directProxy && _bEnableRtsp){
|
||||||
mediaSource = std::make_shared<RtspMediaSource>(_strVhost,_strApp,_strSrc);
|
mediaSource = std::make_shared<RtspMediaSource>(_strVhost,_strApp,_strSrc);
|
||||||
}
|
}
|
||||||
}else if(dynamic_pointer_cast<RtmpPlayer>(_parser)){
|
} else if(dynamic_pointer_cast<RtmpPlayer>(_parser)){
|
||||||
//rtmp拉流
|
//rtmp拉流
|
||||||
if(_bEnableRtmp){
|
if(_bEnableRtmp){
|
||||||
mediaSource = std::make_shared<RtmpMediaSource>(_strVhost,_strApp,_strSrc);
|
mediaSource = std::make_shared<RtmpMediaSource>(_strVhost,_strApp,_strSrc);
|
||||||
@ -154,7 +160,7 @@ PlayerProxy::~PlayerProxy() {
|
|||||||
_timer.reset();
|
_timer.reset();
|
||||||
}
|
}
|
||||||
void PlayerProxy::rePlay(const string &strUrl,int iFailedCnt){
|
void PlayerProxy::rePlay(const string &strUrl,int iFailedCnt){
|
||||||
auto iDelay = MAX(2 * 1000, MIN(iFailedCnt * 3000,60*1000));
|
auto iDelay = MAX(2 * 1000, MIN(iFailedCnt * 3000, 60*1000));
|
||||||
weak_ptr<PlayerProxy> weakSelf = shared_from_this();
|
weak_ptr<PlayerProxy> weakSelf = shared_from_this();
|
||||||
_timer = std::make_shared<Timer>(iDelay / 1000.0f,[weakSelf,strUrl,iFailedCnt]() {
|
_timer = std::make_shared<Timer>(iDelay / 1000.0f,[weakSelf,strUrl,iFailedCnt]() {
|
||||||
//播放失败次数越多,则延时越长
|
//播放失败次数越多,则延时越长
|
||||||
@ -224,16 +230,23 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
void PlayerProxy::onPlaySuccess() {
|
void PlayerProxy::onPlaySuccess() {
|
||||||
|
GET_CONFIG(bool,resetWhenRePlay,General::kResetWhenRePlay);
|
||||||
if (dynamic_pointer_cast<RtspMediaSource>(_pMediaSrc)) {
|
if (dynamic_pointer_cast<RtspMediaSource>(_pMediaSrc)) {
|
||||||
//rtsp拉流代理
|
//rtsp拉流代理
|
||||||
|
if (resetWhenRePlay || !_mediaMuxer) {
|
||||||
_mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), false, _bEnableRtmp, _bEnableHls, _bEnableMp4));
|
_mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), false, _bEnableRtmp, _bEnableHls, _bEnableMp4));
|
||||||
|
}
|
||||||
} else if (dynamic_pointer_cast<RtmpMediaSource>(_pMediaSrc)) {
|
} else if (dynamic_pointer_cast<RtmpMediaSource>(_pMediaSrc)) {
|
||||||
//rtmp拉流代理
|
//rtmp拉流代理
|
||||||
|
if (resetWhenRePlay || !_mediaMuxer) {
|
||||||
_mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, false, _bEnableHls, _bEnableMp4));
|
_mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, false, _bEnableHls, _bEnableMp4));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
//其他拉流代理
|
//其他拉流代理
|
||||||
|
if (resetWhenRePlay || !_mediaMuxer) {
|
||||||
_mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, _bEnableRtmp, _bEnableHls, _bEnableMp4));
|
_mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, _bEnableRtmp, _bEnableHls, _bEnableMp4));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_mediaMuxer->setListener(shared_from_this());
|
_mediaMuxer->setListener(shared_from_this());
|
||||||
|
|
||||||
auto videoTrack = getTrack(TrackVideo,false);
|
auto videoTrack = getTrack(TrackVideo,false);
|
||||||
|
Loading…
Reference in New Issue
Block a user