新增媒体流flush机制:#1996

This commit is contained in:
ziyue 2022-10-16 19:49:56 +08:00
parent 80eef693c6
commit ac1abb34da
44 changed files with 287 additions and 124 deletions

View File

@ -420,9 +420,7 @@ FFmpegDecoder::FFmpegDecoder(const Track::Ptr &track, int thread_num) {
FFmpegDecoder::~FFmpegDecoder() { FFmpegDecoder::~FFmpegDecoder() {
stopThread(true); stopThread(true);
if (_do_merger) { if (_do_merger) {
_merger.inputFrame(nullptr, [&](uint64_t dts, uint64_t pts, const Buffer::Ptr &buffer, bool have_idr) { _merger.flush();
decodeFrame(buffer->data(), buffer->size(), dts, pts, false);
});
} }
flush(); flush();
} }
@ -452,7 +450,7 @@ const AVCodecContext *FFmpegDecoder::getContext() const {
bool FFmpegDecoder::inputFrame_l(const Frame::Ptr &frame, bool live, bool enable_merge) { bool FFmpegDecoder::inputFrame_l(const Frame::Ptr &frame, bool live, bool enable_merge) {
if (_do_merger && enable_merge) { if (_do_merger && enable_merge) {
return _merger.inputFrame(frame, [&](uint64_t dts, uint64_t pts, const Buffer::Ptr &buffer, bool have_idr) { return _merger.inputFrame(frame, [this, live](uint64_t dts, uint64_t pts, const Buffer::Ptr &buffer, bool have_idr) {
decodeFrame(buffer->data(), buffer->size(), dts, pts, live); decodeFrame(buffer->data(), buffer->size(), dts, pts, live);
}); });
} }

View File

@ -359,9 +359,9 @@ public:
virtual ~PacketCache() = default; virtual ~PacketCache() = default;
void inputPacket(uint64_t stamp, bool is_video, std::shared_ptr<packet> pkt, bool key_pos) { void inputPacket(uint64_t stamp, bool is_video, std::shared_ptr<packet> pkt, bool key_pos) {
bool flush = flushImmediatelyWhenCloseMerge(); bool flag = flushImmediatelyWhenCloseMerge();
if (!flush && _policy.isFlushAble(is_video, key_pos, stamp, _cache->size())) { if (!flag && _policy.isFlushAble(is_video, key_pos, stamp, _cache->size())) {
flushAll(); flush();
} }
//追加数据到最后 //追加数据到最后
@ -370,11 +370,20 @@ public:
_key_pos = key_pos; _key_pos = key_pos;
} }
if (flush) { if (flag) {
flushAll(); flush();
} }
} }
void flush() {
if (_cache->empty()) {
return;
}
onFlush(std::move(_cache), _key_pos);
_cache = std::make_shared<packet_list>();
_key_pos = false;
}
virtual void clearCache() { virtual void clearCache() {
_cache->clear(); _cache->clear();
} }
@ -382,15 +391,6 @@ public:
virtual void onFlush(std::shared_ptr<packet_list>, bool key_pos) = 0; virtual void onFlush(std::shared_ptr<packet_list>, bool key_pos) = 0;
private: private:
void flushAll() {
if (_cache->empty()) {
return;
}
onFlush(std::move(_cache), _key_pos);
_cache = std::make_shared<packet_list>();
_key_pos = false;
}
bool flushImmediatelyWhenCloseMerge() { bool flushImmediatelyWhenCloseMerge() {
//一般的协议关闭合并写时立即刷新缓存这样可以减少一帧的延时但是rtp例外 //一般的协议关闭合并写时立即刷新缓存这样可以减少一帧的延时但是rtp例外
//因为rtp的包很小一个RtpPacket包中也不是完整的一帧图像所以在关闭合并写时 //因为rtp的包很小一个RtpPacket包中也不是完整的一帧图像所以在关闭合并写时

View File

@ -155,7 +155,7 @@ void FrameMerger::doMerge(BufferLikeString &merged, const Frame::Ptr &frame) con
} }
} }
bool FrameMerger::inputFrame(const Frame::Ptr &frame, const onOutput &cb, BufferLikeString *buffer) { bool FrameMerger::inputFrame(const Frame::Ptr &frame, onOutput cb, BufferLikeString *buffer) {
if (willFlush(frame)) { if (willFlush(frame)) {
Frame::Ptr back = _frame_cache.back(); Frame::Ptr back = _frame_cache.back();
Buffer::Ptr merged_frame = back; Buffer::Ptr merged_frame = back;
@ -190,6 +190,7 @@ bool FrameMerger::inputFrame(const Frame::Ptr &frame, const onOutput &cb, Buffer
if (frame->decodeAble()) { if (frame->decodeAble()) {
_have_decode_able_frame = true; _have_decode_able_frame = true;
} }
_cb = std::move(cb);
_frame_cache.emplace_back(Frame::getCacheAbleFrame(frame)); _frame_cache.emplace_back(Frame::getCacheAbleFrame(frame));
return true; return true;
} }
@ -203,4 +204,11 @@ void FrameMerger::clear() {
_have_decode_able_frame = false; _have_decode_able_frame = false;
} }
void FrameMerger::flush() {
if (_cb) {
inputFrame(nullptr, std::move(_cb), nullptr);
}
clear();
}
}//namespace mediakit }//namespace mediakit

View File

@ -271,6 +271,11 @@ public:
* *
*/ */
virtual bool inputFrame(const Frame::Ptr &frame) = 0; virtual bool inputFrame(const Frame::Ptr &frame) = 0;
/**
* frame缓存
*/
virtual void flush() {};
}; };
/** /**
@ -542,8 +547,13 @@ public:
FrameMerger(int type); FrameMerger(int type);
~FrameMerger() = default; ~FrameMerger() = default;
/**
* FrameMerger::inputFrame传入的onOutput回调
*
*/
void flush();
void clear(); void clear();
bool inputFrame(const Frame::Ptr &frame, const onOutput &cb, toolkit::BufferLikeString *buffer = nullptr); bool inputFrame(const Frame::Ptr &frame, onOutput cb, toolkit::BufferLikeString *buffer = nullptr);
private: private:
bool willFlush(const Frame::Ptr &frame) const; bool willFlush(const Frame::Ptr &frame) const;
@ -552,6 +562,7 @@ private:
private: private:
int _type; int _type;
bool _have_decode_able_frame = false; bool _have_decode_able_frame = false;
onOutput _cb;
toolkit::List<Frame::Ptr> _frame_cache; toolkit::List<Frame::Ptr> _frame_cache;
}; };

View File

@ -124,7 +124,12 @@ void H264RtmpEncoder::makeConfigPacket(){
} }
} }
void H264RtmpEncoder::flush() {
inputFrame(nullptr);
}
bool H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { bool H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
if (frame) {
auto data = frame->data() + frame->prefixSize(); auto data = frame->data() + frame->prefixSize();
auto len = frame->size() - frame->prefixSize(); auto len = frame->size() - frame->prefixSize();
auto type = H264_TYPE(data[0]); auto type = H264_TYPE(data[0]);
@ -145,6 +150,7 @@ bool H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
} }
default: break; default: break;
} }
}
if (!_rtmp_packet) { if (!_rtmp_packet) {
_rtmp_packet = RtmpPacket::create(); _rtmp_packet = RtmpPacket::create();

View File

@ -62,7 +62,7 @@ public:
* @param track * @param track
*/ */
H264RtmpEncoder(const Track::Ptr &track); H264RtmpEncoder(const Track::Ptr &track);
~H264RtmpEncoder() {} ~H264RtmpEncoder() = default;
/** /**
* 264sps pps * 264sps pps
@ -70,6 +70,11 @@ public:
*/ */
bool inputFrame(const Frame::Ptr &frame) override; bool inputFrame(const Frame::Ptr &frame) override;
/**
* frame缓存
*/
void flush() override;
/** /**
* config包 * config包
*/ */

View File

@ -291,6 +291,14 @@ bool H264RtpEncoder::inputFrame(const Frame::Ptr &frame) {
return true; return true;
} }
void H264RtpEncoder::flush() {
if (_last_frame) {
// 如果时间戳发生了变化那么markbit才置true
inputFrame_l(_last_frame, true);
_last_frame = nullptr;
}
}
bool H264RtpEncoder::inputFrame_l(const Frame::Ptr &frame, bool is_mark){ bool H264RtpEncoder::inputFrame_l(const Frame::Ptr &frame, bool is_mark){
if (frame->keyFrame()) { if (frame->keyFrame()) {
//保证每一个关键帧前都有SPS与PPS //保证每一个关键帧前都有SPS与PPS

View File

@ -85,6 +85,11 @@ public:
*/ */
bool inputFrame(const Frame::Ptr &frame) override; bool inputFrame(const Frame::Ptr &frame) override;
/**
* frame缓存
*/
void flush() override;
private: private:
void insertConfigFrame(uint64_t pts); void insertConfigFrame(uint64_t pts);
bool inputFrame_l(const Frame::Ptr &frame, bool is_mark); bool inputFrame_l(const Frame::Ptr &frame, bool is_mark);

View File

@ -138,7 +138,12 @@ void H265RtmpEncoder::makeConfigPacket(){
} }
} }
void H265RtmpEncoder::flush() {
inputFrame(nullptr);
}
bool H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) { bool H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
if (frame) {
auto data = frame->data() + frame->prefixSize(); auto data = frame->data() + frame->prefixSize();
auto len = frame->size() - frame->prefixSize(); auto len = frame->size() - frame->prefixSize();
auto type = H265_TYPE(data[0]); auto type = H265_TYPE(data[0]);
@ -166,6 +171,7 @@ bool H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
} }
default: break; default: break;
} }
}
if (!_rtmp_packet) { if (!_rtmp_packet) {
_rtmp_packet = RtmpPacket::create(); _rtmp_packet = RtmpPacket::create();

View File

@ -60,7 +60,7 @@ public:
* @param track * @param track
*/ */
H265RtmpEncoder(const Track::Ptr &track); H265RtmpEncoder(const Track::Ptr &track);
~H265RtmpEncoder() {} ~H265RtmpEncoder() = default;
/** /**
* 265sps pps * 265sps pps
@ -68,6 +68,11 @@ public:
*/ */
bool inputFrame(const Frame::Ptr &frame) override; bool inputFrame(const Frame::Ptr &frame) override;
/**
* frame缓存
*/
void flush() override;
/** /**
* config包 * config包
*/ */

View File

@ -31,7 +31,7 @@ public:
}; };
//FMP4直播源 //FMP4直播源
class FMP4MediaSource : public MediaSource, public toolkit::RingDelegate<FMP4Packet::Ptr>, private PacketCache<FMP4Packet>{ class FMP4MediaSource final : public MediaSource, public toolkit::RingDelegate<FMP4Packet::Ptr>, private PacketCache<FMP4Packet>{
public: public:
using Ptr = std::shared_ptr<FMP4MediaSource>; using Ptr = std::shared_ptr<FMP4MediaSource>;
using RingDataType = std::shared_ptr<toolkit::List<FMP4Packet::Ptr> >; using RingDataType = std::shared_ptr<toolkit::List<FMP4Packet::Ptr> >;
@ -42,7 +42,7 @@ public:
const std::string &stream_id, const std::string &stream_id,
int ring_size = FMP4_GOP_SIZE) : MediaSource(FMP4_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) {} int ring_size = FMP4_GOP_SIZE) : MediaSource(FMP4_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) {}
~FMP4MediaSource() override = default; ~FMP4MediaSource() override { flush(); }
/** /**
* *

View File

@ -18,7 +18,7 @@
namespace mediakit { namespace mediakit {
class FMP4MediaSourceMuxer : public MP4MuxerMemory, public MediaSourceEventInterceptor, class FMP4MediaSourceMuxer final : public MP4MuxerMemory, public MediaSourceEventInterceptor,
public std::enable_shared_from_this<FMP4MediaSourceMuxer> { public std::enable_shared_from_this<FMP4MediaSourceMuxer> {
public: public:
using Ptr = std::shared_ptr<FMP4MediaSourceMuxer>; using Ptr = std::shared_ptr<FMP4MediaSourceMuxer>;
@ -29,7 +29,7 @@ public:
_media_src = std::make_shared<FMP4MediaSource>(vhost, app, stream_id); _media_src = std::make_shared<FMP4MediaSource>(vhost, app, stream_id);
} }
~FMP4MediaSourceMuxer() override = default; ~FMP4MediaSourceMuxer() override { MP4MuxerMemory::flush(); };
void setListener(const std::weak_ptr<MediaSourceEvent> &listener){ void setListener(const std::weak_ptr<MediaSourceEvent> &listener){
setDelegate(listener); setDelegate(listener);

View File

@ -393,6 +393,9 @@ void HlsPlayerImp::onShutdown(const SockException &ex) {
break; break;
} }
} }
if (_decoder) {
_decoder->flush();
}
PlayerImp<HlsPlayer, PlayerBase>::onShutdown(ex); PlayerImp<HlsPlayer, PlayerBase>::onShutdown(ex);
} }

View File

@ -60,6 +60,9 @@ void TsPlayerImp::onShutdown(const SockException &ex) {
break; break;
} }
} }
if (_decoder) {
_decoder->flush();
}
PlayerImp<TsPlayer, PlayerBase>::onShutdown(ex); PlayerImp<TsPlayer, PlayerBase>::onShutdown(ex);
} }

View File

@ -16,7 +16,7 @@
namespace mediakit { namespace mediakit {
class HlsRecorder : public MediaSourceEventInterceptor, public MpegMuxer, public std::enable_shared_from_this<HlsRecorder> { class HlsRecorder final : public MediaSourceEventInterceptor, public MpegMuxer, public std::enable_shared_from_this<HlsRecorder> {
public: public:
using Ptr = std::shared_ptr<HlsRecorder>; using Ptr = std::shared_ptr<HlsRecorder>;
@ -30,7 +30,7 @@ public:
_hls->clearCache(); _hls->clearCache();
} }
~HlsRecorder() = default; ~HlsRecorder() { MpegMuxer::flush(); };
void setMediaSource(const std::string &vhost, const std::string &app, const std::string &stream_id) { void setMediaSource(const std::string &vhost, const std::string &app, const std::string &stream_id) {
_hls->setMediaSource(vhost, app, stream_id); _hls->setMediaSource(vhost, app, stream_id);

View File

@ -79,6 +79,10 @@ void MP4MuxerInterface::resetTracks() {
_codec_to_trackid.clear(); _codec_to_trackid.clear();
} }
void MP4MuxerInterface::flush() {
_frame_merger.flush();
}
bool MP4MuxerInterface::inputFrame(const Frame::Ptr &frame) { bool MP4MuxerInterface::inputFrame(const Frame::Ptr &frame) {
auto it = _codec_to_trackid.find(frame->getCodecId()); auto it = _codec_to_trackid.find(frame->getCodecId());
if (it == _codec_to_trackid.end()) { if (it == _codec_to_trackid.end()) {
@ -98,12 +102,12 @@ bool MP4MuxerInterface::inputFrame(const Frame::Ptr &frame) {
//mp4文件时间戳需要从0开始 //mp4文件时间戳需要从0开始
auto &track_info = it->second; auto &track_info = it->second;
int64_t dts_out, pts_out;
switch (frame->getCodecId()) { switch (frame->getCodecId()) {
case CodecH264: case CodecH264:
case CodecH265: { case CodecH265: {
//这里的代码逻辑是让SPS、PPS、IDR这些时间戳相同的帧打包到一起当做一个帧处理 //这里的代码逻辑是让SPS、PPS、IDR这些时间戳相同的帧打包到一起当做一个帧处理
_frame_merger.inputFrame(frame, [&](uint64_t dts, uint64_t pts, const Buffer::Ptr &buffer, bool have_idr) { _frame_merger.inputFrame(frame, [this, &track_info](uint64_t dts, uint64_t pts, const Buffer::Ptr &buffer, bool have_idr) {
int64_t dts_out, pts_out;
track_info.stamp.revise(dts, pts, dts_out, pts_out); track_info.stamp.revise(dts, pts, dts_out, pts_out);
mp4_writer_write(_mov_writter.get(), mp4_writer_write(_mov_writter.get(),
track_info.track_id, track_info.track_id,
@ -117,6 +121,7 @@ bool MP4MuxerInterface::inputFrame(const Frame::Ptr &frame) {
} }
default: { default: {
int64_t dts_out, pts_out;
track_info.stamp.revise(frame->dts(), frame->pts(), dts_out, pts_out); track_info.stamp.revise(frame->dts(), frame->pts(), dts_out, pts_out);
mp4_writer_write(_mov_writter.get(), mp4_writer_write(_mov_writter.get(),
track_info.track_id, track_info.track_id,

View File

@ -43,6 +43,11 @@ public:
*/ */
void resetTracks() override; void resetTracks() override;
/**
* frame缓存
*/
void flush() override;
/** /**
* *
*/ */

View File

@ -33,6 +33,7 @@ MP4Recorder::MP4Recorder(const string &path, const string &vhost, const string &
} }
MP4Recorder::~MP4Recorder() { MP4Recorder::~MP4Recorder() {
flush();
closeFile(); closeFile();
} }
@ -96,6 +97,12 @@ void MP4Recorder::closeFile() {
} }
} }
void MP4Recorder::flush() {
if (_muxer) {
_muxer->flush();
}
}
bool MP4Recorder::inputFrame(const Frame::Ptr &frame) { bool MP4Recorder::inputFrame(const Frame::Ptr &frame) {
if (!(_have_video && frame->getTrackType() == TrackAudio)) { if (!(_have_video && frame->getTrackType() == TrackAudio)) {
//如果有视频且输入的是音频,那么应该忽略切片逻辑 //如果有视频且输入的是音频,那么应该忽略切片逻辑

View File

@ -24,7 +24,7 @@
namespace mediakit { namespace mediakit {
#ifdef ENABLE_MP4 #ifdef ENABLE_MP4
class MP4Recorder : public MediaSinkInterface { class MP4Recorder final : public MediaSinkInterface {
public: public:
using Ptr = std::shared_ptr<MP4Recorder>; using Ptr = std::shared_ptr<MP4Recorder>;
@ -41,6 +41,11 @@ public:
*/ */
bool inputFrame(const Frame::Ptr &frame) override; bool inputFrame(const Frame::Ptr &frame) override;
/**
* frame缓存
*/
void flush() override;
/** /**
* ready状态的track * ready状态的track
*/ */

View File

@ -63,7 +63,7 @@ bool MpegMuxer::inputFrame(const Frame::Ptr &frame) {
case CodecH264: case CodecH264:
case CodecH265: { case CodecH265: {
//这里的代码逻辑是让SPS、PPS、IDR这些时间戳相同的帧打包到一起当做一个帧处理 //这里的代码逻辑是让SPS、PPS、IDR这些时间戳相同的帧打包到一起当做一个帧处理
return _frame_merger.inputFrame(frame,[&](uint64_t dts, uint64_t pts, const Buffer::Ptr &buffer, bool have_idr) { return _frame_merger.inputFrame(frame,[this, track_id](uint64_t dts, uint64_t pts, const Buffer::Ptr &buffer, bool have_idr) {
_key_pos = have_idr; _key_pos = have_idr;
//取视频时间戳为TS的时间戳 //取视频时间戳为TS的时间戳
_timestamp = dts; _timestamp = dts;
@ -153,6 +153,10 @@ void MpegMuxer::releaseContext() {
_frame_merger.clear(); _frame_merger.clear();
} }
void MpegMuxer::flush() {
_frame_merger.flush();
}
}//mediakit }//mediakit
#endif #endif

View File

@ -45,6 +45,11 @@ public:
*/ */
bool inputFrame(const Frame::Ptr &frame) override; bool inputFrame(const Frame::Ptr &frame) override;
/**
* frame缓存
*/
void flush() override;
protected: protected:
/** /**
* ts/ps数据回调 * ts/ps数据回调

View File

@ -60,7 +60,7 @@ public:
MediaSource(RTMP_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) { MediaSource(RTMP_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) {
} }
~RtmpMediaSource() override{} ~RtmpMediaSource() override { flush(); }
/** /**
* *

View File

@ -26,9 +26,9 @@
namespace mediakit { namespace mediakit {
class RtmpMediaSourceImp: public RtmpMediaSource, private TrackListener, public MultiMediaSourceMuxer::Listener { class RtmpMediaSourceImp final : public RtmpMediaSource, private TrackListener, public MultiMediaSourceMuxer::Listener {
public: public:
typedef std::shared_ptr<RtmpMediaSourceImp> Ptr; using Ptr = std::shared_ptr<RtmpMediaSourceImp>;
/** /**
* *
@ -42,7 +42,7 @@ public:
_demuxer->setTrackListener(this); _demuxer->setTrackListener(this);
} }
~RtmpMediaSourceImp() = default; ~RtmpMediaSourceImp() override = default;
/** /**
* metadata * metadata

View File

@ -16,7 +16,7 @@
namespace mediakit { namespace mediakit {
class RtmpMediaSourceMuxer : public RtmpMuxer, public MediaSourceEventInterceptor, class RtmpMediaSourceMuxer final : public RtmpMuxer, public MediaSourceEventInterceptor,
public std::enable_shared_from_this<RtmpMediaSourceMuxer> { public std::enable_shared_from_this<RtmpMediaSourceMuxer> {
public: public:
typedef std::shared_ptr<RtmpMediaSourceMuxer> Ptr; typedef std::shared_ptr<RtmpMediaSourceMuxer> Ptr;
@ -29,7 +29,7 @@ public:
getRtmpRing()->setDelegate(_media_src); getRtmpRing()->setDelegate(_media_src);
} }
~RtmpMediaSourceMuxer() override{} ~RtmpMediaSourceMuxer() override { RtmpMuxer::flush(); }
void setListener(const std::weak_ptr<MediaSourceEvent> &listener){ void setListener(const std::weak_ptr<MediaSourceEvent> &listener){
setDelegate(listener); setDelegate(listener);

View File

@ -43,6 +43,14 @@ bool RtmpMuxer::inputFrame(const Frame::Ptr &frame) {
return encoder ? encoder->inputFrame(frame) : false; return encoder ? encoder->inputFrame(frame) : false;
} }
void RtmpMuxer::flush() {
for (auto &encoder : _encoder) {
if (encoder) {
encoder->flush();
}
}
}
void RtmpMuxer::makeConfigPacket(){ void RtmpMuxer::makeConfigPacket(){
for(auto &encoder : _encoder){ for(auto &encoder : _encoder){
if(encoder){ if(encoder){

View File

@ -51,6 +51,11 @@ public:
*/ */
bool inputFrame(const Frame::Ptr &frame) override; bool inputFrame(const Frame::Ptr &frame) override;
/**
* frame缓存
*/
void flush() override;
/** /**
* track * track
*/ */

View File

@ -65,6 +65,10 @@ DecoderImp::Ptr DecoderImp::createDecoder(Type type, MediaSinkInterface *sink){
return DecoderImp::Ptr(new DecoderImp(decoder, sink)); return DecoderImp::Ptr(new DecoderImp(decoder, sink));
} }
void DecoderImp::flush() {
_merger.flush();
}
ssize_t DecoderImp::input(const uint8_t *data, size_t bytes){ ssize_t DecoderImp::input(const uint8_t *data, size_t bytes){
return _decoder->input(data, bytes); return _decoder->input(data, bytes);
} }
@ -219,11 +223,8 @@ void DecoderImp::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t d
default: default:
// 海康的 PS 流中会有 codecid 为 0xBD 的包 // 海康的 PS 流中会有 codecid 为 0xBD 的包
if (codecid != 0 && codecid != 0xBD) { if (codecid != 0 && codecid != 0xBD) {
if (_last_unsported_print.elapsedTime() / 1000 > 5) {
_last_unsported_print.resetTime();
WarnL << "unsupported codec type:" << getCodecName(codecid) << " " << (int) codecid; WarnL << "unsupported codec type:" << getCodecName(codecid) << " " << (int) codecid;
} }
}
break; break;
} }
} }

View File

@ -39,16 +39,14 @@ protected:
class DecoderImp{ class DecoderImp{
public: public:
typedef enum { typedef enum { decoder_ts = 0, decoder_ps } Type;
decoder_ts = 0,
decoder_ps
}Type;
typedef std::shared_ptr<DecoderImp> Ptr; typedef std::shared_ptr<DecoderImp> Ptr;
~DecoderImp() = default; ~DecoderImp() = default;
static Ptr createDecoder(Type type, MediaSinkInterface *sink); static Ptr createDecoder(Type type, MediaSinkInterface *sink);
ssize_t input(const uint8_t *data, size_t bytes); ssize_t input(const uint8_t *data, size_t bytes);
void flush();
protected: protected:
void onTrack(const Track::Ptr &track); void onTrack(const Track::Ptr &track);
@ -63,7 +61,6 @@ private:
Decoder::Ptr _decoder; Decoder::Ptr _decoder;
MediaSinkInterface *_sink; MediaSinkInterface *_sink;
FrameMerger _merger{FrameMerger::none}; FrameMerger _merger{FrameMerger::none};
toolkit::Ticker _last_unsported_print;
Track::Ptr _tracks[TrackMax]; Track::Ptr _tracks[TrackMax];
}; };

View File

@ -59,12 +59,16 @@ GB28181Process::GB28181Process(const MediaInfo &media_info, MediaSinkInterface *
_interface = sink; _interface = sink;
} }
GB28181Process::~GB28181Process() {}
void GB28181Process::onRtpSorted(RtpPacket::Ptr rtp) { void GB28181Process::onRtpSorted(RtpPacket::Ptr rtp) {
_rtp_decoder[rtp->getHeader()->pt]->inputRtp(rtp, false); _rtp_decoder[rtp->getHeader()->pt]->inputRtp(rtp, false);
} }
void GB28181Process::flush() {
if (_decoder) {
_decoder->flush();
}
}
bool GB28181Process::inputRtp(bool, const char *data, size_t data_len) { bool GB28181Process::inputRtp(bool, const char *data, size_t data_len) {
GET_CONFIG(uint32_t, h264_pt, RtpProxy::kH264PT); GET_CONFIG(uint32_t, h264_pt, RtpProxy::kH264PT);
GET_CONFIG(uint32_t, h265_pt, RtpProxy::kH265PT); GET_CONFIG(uint32_t, h265_pt, RtpProxy::kH265PT);

View File

@ -26,7 +26,7 @@ class GB28181Process : public ProcessInterface {
public: public:
typedef std::shared_ptr<GB28181Process> Ptr; typedef std::shared_ptr<GB28181Process> Ptr;
GB28181Process(const MediaInfo &media_info, MediaSinkInterface *sink); GB28181Process(const MediaInfo &media_info, MediaSinkInterface *sink);
~GB28181Process() override; ~GB28181Process() override = default;
/** /**
* rtp * rtp
@ -36,6 +36,11 @@ public:
*/ */
bool inputRtp(bool, const char *data, size_t data_len) override; bool inputRtp(bool, const char *data, size_t data_len) override;
/**
*
*/
void flush() override;
protected: protected:
void onRtpSorted(RtpPacket::Ptr rtp); void onRtpSorted(RtpPacket::Ptr rtp);

View File

@ -31,6 +31,11 @@ public:
* @return * @return
*/ */
virtual bool inputRtp(bool is_udp, const char *data, size_t data_len) = 0; virtual bool inputRtp(bool is_udp, const char *data, size_t data_len) = 0;
/**
*
*/
virtual void flush() {}
}; };
}//namespace mediakit }//namespace mediakit

View File

@ -19,6 +19,7 @@ namespace mediakit{
RtpCache::RtpCache(onFlushed cb) { RtpCache::RtpCache(onFlushed cb) {
_cb = std::move(cb); _cb = std::move(cb);
} }
bool RtpCache::firstKeyReady(bool in) { bool RtpCache::firstKeyReady(bool in) {
if (_first_key) { if (_first_key) {
return _first_key; return _first_key;
@ -26,6 +27,7 @@ bool RtpCache::firstKeyReady(bool in) {
_first_key = in; _first_key = in;
return _first_key; return _first_key;
} }
void RtpCache::onFlush(std::shared_ptr<List<Buffer::Ptr>> rtp_list, bool) { void RtpCache::onFlush(std::shared_ptr<List<Buffer::Ptr>> rtp_list, bool) {
_cb(std::move(rtp_list)); _cb(std::move(rtp_list));
} }
@ -34,6 +36,11 @@ void RtpCache::input(uint64_t stamp, Buffer::Ptr buffer,bool is_key ) {
inputPacket(stamp, true, std::move(buffer), is_key); inputPacket(stamp, true, std::move(buffer), is_key);
} }
void RtpCachePS::flush() {
PSEncoderImp::flush();
RtpCache::flush();
}
void RtpCachePS::onRTP(Buffer::Ptr buffer, bool is_key) { void RtpCachePS::onRTP(Buffer::Ptr buffer, bool is_key) {
if (!firstKeyReady(is_key)) { if (!firstKeyReady(is_key)) {
return; return;
@ -43,6 +50,11 @@ void RtpCachePS::onRTP(Buffer::Ptr buffer,bool is_key) {
input(stamp, std::move(buffer), is_key); input(stamp, std::move(buffer), is_key);
} }
void RtpCacheRaw::flush() {
RawEncoderImp::flush();
RtpCache::flush();
}
void RtpCacheRaw::onRTP(Buffer::Ptr buffer, bool is_key) { void RtpCacheRaw::onRTP(Buffer::Ptr buffer, bool is_key) {
if (!firstKeyReady(is_key)) { if (!firstKeyReady(is_key)) {
return; return;

View File

@ -19,7 +19,7 @@
namespace mediakit{ namespace mediakit{
class RtpCache : private PacketCache<toolkit::Buffer> { class RtpCache : protected PacketCache<toolkit::Buffer> {
public: public:
using onFlushed = std::function<void(std::shared_ptr<toolkit::List<toolkit::Buffer::Ptr> >)>; using onFlushed = std::function<void(std::shared_ptr<toolkit::List<toolkit::Buffer::Ptr> >)>;
RtpCache(onFlushed cb); RtpCache(onFlushed cb);
@ -33,18 +33,20 @@ protected:
void input(uint64_t stamp, toolkit::Buffer::Ptr buffer,bool is_key = false); void input(uint64_t stamp, toolkit::Buffer::Ptr buffer,bool is_key = false);
bool firstKeyReady(bool in); bool firstKeyReady(bool in);
protected: protected:
void onFlush(std::shared_ptr<toolkit::List<toolkit::Buffer::Ptr> > rtp_list, bool) override; void onFlush(std::shared_ptr<toolkit::List<toolkit::Buffer::Ptr> > rtp_list, bool) override;
private: private:
onFlushed _cb;
bool _first_key = false; bool _first_key = false;
onFlushed _cb;
}; };
class RtpCachePS : public RtpCache, public PSEncoderImp { class RtpCachePS : public RtpCache, public PSEncoderImp {
public: public:
RtpCachePS(onFlushed cb, uint32_t ssrc, uint8_t payload_type = 96) : RtpCache(std::move(cb)), PSEncoderImp(ssrc, payload_type) {}; RtpCachePS(onFlushed cb, uint32_t ssrc, uint8_t payload_type = 96) : RtpCache(std::move(cb)), PSEncoderImp(ssrc, payload_type) {};
~RtpCachePS() override = default; ~RtpCachePS() override = default;
void flush() override;
protected: protected:
void onRTP(toolkit::Buffer::Ptr rtp, bool is_key = false) override; void onRTP(toolkit::Buffer::Ptr rtp, bool is_key = false) override;
@ -52,8 +54,9 @@ protected:
class RtpCacheRaw : public RtpCache, public RawEncoderImp { class RtpCacheRaw : public RtpCache, public RawEncoderImp {
public: public:
RtpCacheRaw(onFlushed cb, uint32_t ssrc, uint8_t payload_type = 96, bool sendAudio = true) : RtpCache(std::move(cb)), RawEncoderImp(ssrc, payload_type,sendAudio) {}; RtpCacheRaw(onFlushed cb, uint32_t ssrc, uint8_t payload_type = 96, bool send_audio = true) : RtpCache(std::move(cb)), RawEncoderImp(ssrc, payload_type, send_audio) {};
~RtpCacheRaw() override = default; ~RtpCacheRaw() override = default;
void flush() override;
protected: protected:
void onRTP(toolkit::Buffer::Ptr rtp, bool is_key = false) override; void onRTP(toolkit::Buffer::Ptr rtp, bool is_key = false) override;

View File

@ -50,6 +50,9 @@ RtpProcess::RtpProcess(const string &stream_id) {
} }
RtpProcess::~RtpProcess() { RtpProcess::~RtpProcess() {
if (_process) {
_process->flush();
}
uint64_t duration = (_last_frame_time.createdTime() - _last_frame_time.elapsedTime()) / 1000; uint64_t duration = (_last_frame_time.createdTime() - _last_frame_time.elapsedTime()) / 1000;
WarnP(this) << "RTP推流器(" WarnP(this) << "RTP推流器("
<< _media_info.shortUrl() << _media_info.shortUrl()

View File

@ -25,6 +25,10 @@ RtpSender::RtpSender(EventPoller::Ptr poller) {
_socket_rtp = Socket::createSocket(_poller, false); _socket_rtp = Socket::createSocket(_poller, false);
} }
RtpSender::~RtpSender() {
flush();
}
void RtpSender::startSend(const MediaSourceEvent::SendRtpArgs &args, const function<void(uint16_t local_port, const SockException &ex)> &cb){ void RtpSender::startSend(const MediaSourceEvent::SendRtpArgs &args, const function<void(uint16_t local_port, const SockException &ex)> &cb){
_args = args; _args = args;
if (!_interface) { if (!_interface) {
@ -231,6 +235,12 @@ void RtpSender::resetTracks(){
_interface->resetTracks(); _interface->resetTracks();
} }
void RtpSender::flush() {
if (_interface) {
_interface->flush();
}
}
//此函数在其他线程执行 //此函数在其他线程执行
bool RtpSender::inputFrame(const Frame::Ptr &frame) { bool RtpSender::inputFrame(const Frame::Ptr &frame) {
//连接成功后才做实质操作(节省cpu资源) //连接成功后才做实质操作(节省cpu资源)

View File

@ -18,12 +18,12 @@
namespace mediakit{ namespace mediakit{
//rtp发送客户端支持发送GB28181协议 //rtp发送客户端支持发送GB28181协议
class RtpSender : public MediaSinkInterface, public std::enable_shared_from_this<RtpSender>{ class RtpSender final : public MediaSinkInterface, public std::enable_shared_from_this<RtpSender>{
public: public:
typedef std::shared_ptr<RtpSender> Ptr; typedef std::shared_ptr<RtpSender> Ptr;
RtpSender(toolkit::EventPoller::Ptr poller = nullptr); RtpSender(toolkit::EventPoller::Ptr poller = nullptr);
~RtpSender() override = default; ~RtpSender() override;
/** /**
* ps-rtp包 * ps-rtp包
@ -37,6 +37,11 @@ public:
*/ */
bool inputFrame(const Frame::Ptr &frame) override; bool inputFrame(const Frame::Ptr &frame) override;
/**
* frame缓存
*/
void flush() override;
/** /**
* trackTrack的clone方法 * trackTrack的clone方法
* sps pps这些信息 Delegate相关关系 * sps pps这些信息 Delegate相关关系

View File

@ -56,7 +56,7 @@ public:
int ring_size = RTP_GOP_SIZE) : int ring_size = RTP_GOP_SIZE) :
MediaSource(RTSP_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) {} MediaSource(RTSP_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) {}
~RtspMediaSource() override{} ~RtspMediaSource() override { flush(); }
/** /**
* *

View File

@ -17,9 +17,9 @@
#include "Common/MultiMediaSourceMuxer.h" #include "Common/MultiMediaSourceMuxer.h"
namespace mediakit { namespace mediakit {
class RtspMediaSourceImp : public RtspMediaSource, private TrackListener, public MultiMediaSourceMuxer::Listener { class RtspMediaSourceImp final : public RtspMediaSource, private TrackListener, public MultiMediaSourceMuxer::Listener {
public: public:
typedef std::shared_ptr<RtspMediaSourceImp> Ptr; using Ptr = std::shared_ptr<RtspMediaSourceImp>;
/** /**
* *
@ -33,7 +33,7 @@ public:
_demuxer->setTrackListener(this); _demuxer->setTrackListener(this);
} }
~RtspMediaSourceImp() = default; ~RtspMediaSourceImp() override = default;
/** /**
* sdp * sdp

View File

@ -16,7 +16,7 @@
namespace mediakit { namespace mediakit {
class RtspMediaSourceMuxer : public RtspMuxer, public MediaSourceEventInterceptor, class RtspMediaSourceMuxer final : public RtspMuxer, public MediaSourceEventInterceptor,
public std::enable_shared_from_this<RtspMediaSourceMuxer> { public std::enable_shared_from_this<RtspMediaSourceMuxer> {
public: public:
typedef std::shared_ptr<RtspMediaSourceMuxer> Ptr; typedef std::shared_ptr<RtspMediaSourceMuxer> Ptr;
@ -29,7 +29,7 @@ public:
getRtpRing()->setDelegate(_media_src); getRtpRing()->setDelegate(_media_src);
} }
~RtspMediaSourceMuxer() override{} ~RtspMediaSourceMuxer() override { RtspMuxer::flush(); }
void setListener(const std::weak_ptr<MediaSourceEvent> &listener){ void setListener(const std::weak_ptr<MediaSourceEvent> &listener){
setDelegate(listener); setDelegate(listener);

View File

@ -86,6 +86,14 @@ bool RtspMuxer::inputFrame(const Frame::Ptr &frame) {
return encoder ? encoder->inputFrame(frame) : false; return encoder ? encoder->inputFrame(frame) : false;
} }
void RtspMuxer::flush() {
for (auto &encoder : _encoder) {
if (encoder) {
encoder->flush();
}
}
}
string RtspMuxer::getSdp() { string RtspMuxer::getSdp() {
return _sdp; return _sdp;
} }

View File

@ -73,6 +73,11 @@ public:
*/ */
bool inputFrame(const Frame::Ptr &frame) override; bool inputFrame(const Frame::Ptr &frame) override;
/**
* frame缓存
*/
void flush() override;
/** /**
* track * track
*/ */

View File

@ -31,7 +31,7 @@ public:
}; };
//TS直播源 //TS直播源
class TSMediaSource : public MediaSource, public toolkit::RingDelegate<TSPacket::Ptr>, private PacketCache<TSPacket>{ class TSMediaSource final : public MediaSource, public toolkit::RingDelegate<TSPacket::Ptr>, private PacketCache<TSPacket>{
public: public:
using Ptr = std::shared_ptr<TSMediaSource>; using Ptr = std::shared_ptr<TSMediaSource>;
using RingDataType = std::shared_ptr<toolkit::List<TSPacket::Ptr> >; using RingDataType = std::shared_ptr<toolkit::List<TSPacket::Ptr> >;
@ -42,7 +42,7 @@ public:
const std::string &stream_id, const std::string &stream_id,
int ring_size = TS_GOP_SIZE) : MediaSource(TS_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) {} int ring_size = TS_GOP_SIZE) : MediaSource(TS_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) {}
~TSMediaSource() override = default; ~TSMediaSource() override { flush(); }
/** /**
* *

View File

@ -16,7 +16,7 @@
namespace mediakit { namespace mediakit {
class TSMediaSourceMuxer : public MpegMuxer, public MediaSourceEventInterceptor, class TSMediaSourceMuxer final : public MpegMuxer, public MediaSourceEventInterceptor,
public std::enable_shared_from_this<TSMediaSourceMuxer> { public std::enable_shared_from_this<TSMediaSourceMuxer> {
public: public:
using Ptr = std::shared_ptr<TSMediaSourceMuxer>; using Ptr = std::shared_ptr<TSMediaSourceMuxer>;
@ -27,7 +27,7 @@ public:
_media_src = std::make_shared<TSMediaSource>(vhost, app, stream_id); _media_src = std::make_shared<TSMediaSource>(vhost, app, stream_id);
} }
~TSMediaSourceMuxer() override = default; ~TSMediaSourceMuxer() override { MpegMuxer::flush(); };
void setListener(const std::weak_ptr<MediaSourceEvent> &listener){ void setListener(const std::weak_ptr<MediaSourceEvent> &listener){
setDelegate(listener); setDelegate(listener);

View File

@ -108,6 +108,9 @@ void SrtTransportImp::onSRTData(DataPacket::Ptr pkt) {
} }
void SrtTransportImp::onShutdown(const SockException &ex) { void SrtTransportImp::onShutdown(const SockException &ex) {
if (_decoder) {
_decoder->flush();
}
SrtTransport::onShutdown(ex); SrtTransport::onShutdown(ex);
} }