diff --git a/api/source/mk_frame.cpp b/api/source/mk_frame.cpp index 7a7cdb85..9658134a 100644 --- a/api/source/mk_frame.cpp +++ b/api/source/mk_frame.cpp @@ -19,7 +19,7 @@ using namespace mediakit; extern "C" { -#define XX(name, type, value, str, mpeg_id) API_EXPORT const int MK##name = value; +#define XX(name, type, value, str, mpeg_id, mp4_id) API_EXPORT const int MK##name = value; CODEC_MAP(XX) #undef XX } diff --git a/api/source/mk_player.cpp b/api/source/mk_player.cpp index 87cbcd3c..8eab7ec5 100755 --- a/api/source/mk_player.cpp +++ b/api/source/mk_player.cpp @@ -11,7 +11,6 @@ #include "mk_player.h" #include "Util/logger.h" #include "Player/MediaPlayer.h" -#include "Extension/H264.h" using namespace std; using namespace toolkit; diff --git a/src/Common/Device.cpp b/src/Common/Device.cpp index 2b1edfab..53bd615c 100644 --- a/src/Common/Device.cpp +++ b/src/Common/Device.cpp @@ -115,20 +115,6 @@ bool DevChannel::inputH265(const char *data, int len, uint64_t dts, uint64_t pts return inputFrame(frame); } -class FrameAutoDelete : public FrameFromPtr{ -public: - template - FrameAutoDelete(ARGS && ...args) : FrameFromPtr(std::forward(args)...){} - - ~FrameAutoDelete() override { - delete [] _ptr; - }; - - bool cacheAble() const override { - return true; - } -}; - bool DevChannel::inputAAC(const char *data_without_adts, int len, uint64_t dts, const char *adts_header){ if (dts == 0) { dts = _aTicker[1].elapsedTime(); diff --git a/src/Common/MediaSink.cpp b/src/Common/MediaSink.cpp index 25c53327..4297e50e 100644 --- a/src/Common/MediaSink.cpp +++ b/src/Common/MediaSink.cpp @@ -201,16 +201,6 @@ vector MediaSink::getTracks(bool ready) const{ return ret; } -class FrameFromStaticPtr : public FrameFromPtr { -public: - template - FrameFromStaticPtr(ARGS &&...args) : FrameFromPtr(std::forward(args)...) {}; - - bool cacheAble() const override { - return true; - } -}; - static uint8_t s_mute_adts[] = {0xff, 0xf1, 0x6c, 0x40, 0x2d, 0x3f, 0xfc, 0x00, 0xe0, 0x34, 0x20, 0xad, 0xf2, 0x3f, 0xb5, 0xdd, 0x73, 0xac, 0xbd, 0xca, 0xd7, 0x7d, 0x4a, 0x13, 0x2d, 0x2e, 0xa2, 0x62, 0x02, 0x70, 0x3c, 0x1c, 0xc5, 0x63, 0x55, 0x69, 0x94, 0xb5, 0x8d, 0x70, 0xd7, 0x24, 0x6a, 0x9e, 0x2e, 0x86, 0x24, 0xea, @@ -244,7 +234,7 @@ bool MuteAudioMaker::inputFrame(const Frame::Ptr &frame) { auto audio_idx = frame->dts() / MUTE_ADTS_DATA_MS; if (_audio_idx != audio_idx) { _audio_idx = audio_idx; - auto aacFrame = std::make_shared(CodecAAC, (char *) MUTE_ADTS_DATA, MUTE_ADTS_DATA_LEN, + auto aacFrame = std::make_shared>(CodecAAC, (char *) MUTE_ADTS_DATA, MUTE_ADTS_DATA_LEN, _audio_idx * MUTE_ADTS_DATA_MS, 0, ADTS_HEADER_LEN); return FrameDispatcher::inputFrame(aacFrame); } diff --git a/src/Extension/AAC.cpp b/src/Extension/AAC.cpp index 8aa14448..7df73916 100644 --- a/src/Extension/AAC.cpp +++ b/src/Extension/AAC.cpp @@ -300,7 +300,7 @@ bool AACTrack::inputFrame(const Frame::Ptr &frame) { if (frame_len == (int)frame->size()) { return inputFrame_l(frame); } - auto sub_frame = std::make_shared>(frame, (char *)ptr, frame_len, ADTS_HEADER_LEN, dts, pts); + auto sub_frame = std::make_shared>(frame, (char *)ptr, frame_len, ADTS_HEADER_LEN, dts, pts); ptr += frame_len; if (ptr > end) { WarnL << "invalid aac length in adts header: " << frame_len diff --git a/src/Extension/Frame.cpp b/src/Extension/Frame.cpp index c14337b8..e1d11110 100644 --- a/src/Extension/Frame.cpp +++ b/src/Extension/Frame.cpp @@ -15,6 +15,14 @@ #include "Common/Stamp.h" #include "Common/MediaSource.h" +#if defined(ENABLE_MP4) +#include "mov-format.h" +#endif + +#if defined(ENABLE_HLS) || defined(ENABLE_RTPPROXY) +#include "mpeg-proto.h" +#endif + using namespace std; using namespace toolkit; @@ -41,24 +49,71 @@ FrameStamp::FrameStamp(Frame::Ptr frame, Stamp &stamp, int modify_stamp) TrackType getTrackType(CodecId codecId) { switch (codecId) { -#define XX(name, type, value, str, mpeg_id) case name : return type; +#define XX(name, type, value, str, mpeg_id, mp4_id) case name : return type; CODEC_MAP(XX) #undef XX default : return TrackInvalid; } } +#if defined(ENABLE_MP4) +int getMovIdByCodec(CodecId codecId) { + switch (codecId) { +#define XX(name, type, value, str, mpeg_id, mp4_id) case name : return mp4_id; + CODEC_MAP(XX) +#undef XX + default : return MOV_OBJECT_NONE; + } +} + +CodecId getCodecByMovId(int object_id) { + if (object_id == MOV_OBJECT_NONE) { + return CodecInvalid; + } + switch (object_id) { +#define XX(name, type, value, str, mpeg_id, mp4_id) case mp4_id : return name; + CODEC_MAP(XX) +#undef XX + default : WarnL << "Unsupported mov: " << object_id; return CodecInvalid; + } +} +#endif + +#if defined(ENABLE_HLS) || defined(ENABLE_RTPPROXY) +int getMpegIdByCodec(CodecId codec) { + switch (codec) { +#define XX(name, type, value, str, mpeg_id, mp4_id) case name : return mpeg_id; + CODEC_MAP(XX) +#undef XX + default : return PSI_STREAM_RESERVED; + } +} + +CodecId getCodecByMpegId(int mpeg_id) { + if (mpeg_id == PSI_STREAM_RESERVED) { + return CodecInvalid; + } + switch (mpeg_id) { +#define XX(name, type, value, str, mpeg_id, mp4_id) case mpeg_id : return name; + CODEC_MAP(XX) +#undef XX + default : WarnL << "Unsupported mpeg: " << mpeg_id; return CodecInvalid; + } +} + +#endif + const char *getCodecName(CodecId codec) { switch (codec) { -#define XX(name, type, value, str, mpeg_id) case name : return str; +#define XX(name, type, value, str, mpeg_id, mp4_id) case name : return str; CODEC_MAP(XX) #undef XX default : return "invalid"; } } -#define XX(name, type, value, str, mpeg_id) {str, name}, -static map codec_map = {CODEC_MAP(XX)}; +#define XX(name, type, value, str, mpeg_id, mp4_id) {str, name}, +static map codec_map = { CODEC_MAP(XX) }; #undef XX CodecId getCodecId(const string &str){ diff --git a/src/Extension/Frame.h b/src/Extension/Frame.h index 34338869..590221b6 100644 --- a/src/Extension/Frame.h +++ b/src/Extension/Frame.h @@ -20,7 +20,9 @@ #include "Network/Buffer.h" namespace mediakit { + class Stamp; + typedef enum { TrackInvalid = -1, TrackVideo = 0, @@ -31,21 +33,21 @@ typedef enum { } TrackType; #define CODEC_MAP(XX) \ - XX(CodecH264, TrackVideo, 0, "H264", PSI_STREAM_H264) \ - XX(CodecH265, TrackVideo, 1, "H265", PSI_STREAM_H265) \ - XX(CodecAAC, TrackAudio, 2, "mpeg4-generic", PSI_STREAM_AAC) \ - XX(CodecG711A, TrackAudio, 3, "PCMA", PSI_STREAM_AUDIO_G711A) \ - XX(CodecG711U, TrackAudio, 4, "PCMU", PSI_STREAM_AUDIO_G711U) \ - XX(CodecOpus, TrackAudio, 5, "opus", PSI_STREAM_AUDIO_OPUS) \ - XX(CodecL16, TrackAudio, 6, "L16", PSI_STREAM_RESERVED) \ - XX(CodecVP8, TrackVideo, 7, "VP8", PSI_STREAM_VP8) \ - XX(CodecVP9, TrackVideo, 8, "VP9", PSI_STREAM_VP9) \ - XX(CodecAV1, TrackVideo, 9, "AV1", PSI_STREAM_AV1) \ - XX(CodecJPEG, TrackVideo, 10, "JPEG", PSI_STREAM_RESERVED) + XX(CodecH264, TrackVideo, 0, "H264", PSI_STREAM_H264, MOV_OBJECT_H264) \ + XX(CodecH265, TrackVideo, 1, "H265", PSI_STREAM_H265, MOV_OBJECT_HEVC) \ + XX(CodecAAC, TrackAudio, 2, "mpeg4-generic", PSI_STREAM_AAC, MOV_OBJECT_AAC) \ + XX(CodecG711A, TrackAudio, 3, "PCMA", PSI_STREAM_AUDIO_G711A, MOV_OBJECT_G711a) \ + XX(CodecG711U, TrackAudio, 4, "PCMU", PSI_STREAM_AUDIO_G711U, MOV_OBJECT_G711u) \ + XX(CodecOpus, TrackAudio, 5, "opus", PSI_STREAM_AUDIO_OPUS, MOV_OBJECT_OPUS) \ + XX(CodecL16, TrackAudio, 6, "L16", PSI_STREAM_RESERVED, MOV_OBJECT_NONE) \ + XX(CodecVP8, TrackVideo, 7, "VP8", PSI_STREAM_VP8, MOV_OBJECT_VP8) \ + XX(CodecVP9, TrackVideo, 8, "VP9", PSI_STREAM_VP9, MOV_OBJECT_VP9) \ + XX(CodecAV1, TrackVideo, 9, "AV1", PSI_STREAM_AV1, MOV_OBJECT_AV1) \ + XX(CodecJPEG, TrackVideo, 10, "JPEG", PSI_STREAM_JPEG_2000, MOV_OBJECT_JPEG) typedef enum { CodecInvalid = -1, -#define XX(name, type, value, str, mpeg_id) name = value, +#define XX(name, type, value, str, mpeg_id, mp4_id) name = value, CODEC_MAP(XX) #undef XX CodecMax @@ -78,6 +80,26 @@ const char *getCodecName(CodecId codecId); */ TrackType getTrackType(CodecId codecId); +/** + * 根据codecid获取mov object id + */ +int getMovIdByCodec(CodecId codecId); + +/** + * 根据mov object id获取CodecId + */ +CodecId getCodecByMovId(int object_id); + +/** + * 根据codecid获取mpeg id + */ +int getMpegIdByCodec(CodecId codec); + +/** + * 根据mpeg id获取CodecId + */ +CodecId getCodecByMpegId(int mpeg_id); + /** * 编码信息的抽象接口 */ @@ -220,17 +242,17 @@ protected: }; /** - * 一个Frame类中可以有多个帧,他们通过 0x 00 00 01 分隔 + * 一个Frame类中可以有多个帧(AAC),时间戳会变化 * ZLMediaKit会先把这种复合帧split成单个帧然后再处理 * 一个复合帧可以通过无内存拷贝的方式切割成多个子Frame * 提供该类的目的是切割复合帧时防止内存拷贝,提高性能 */ template -class FrameInternal : public Parent { +class FrameInternalBase : public Parent { public: - using Ptr = std::shared_ptr; - FrameInternal(const Frame::Ptr &parent_frame, char *ptr, size_t size, size_t prefix_size) - : Parent(ptr, size, parent_frame->dts(), parent_frame->pts(), prefix_size) { + using Ptr = std::shared_ptr; + FrameInternalBase(const Frame::Ptr &parent_frame, char *ptr, size_t size, size_t prefix_size, uint64_t dts, uint64_t pts) + : Parent(ptr, size, dts, pts, prefix_size) { _parent_frame = parent_frame; } bool cacheAble() const override { return _parent_frame->cacheAble(); } @@ -240,24 +262,233 @@ private: }; /** - * 一个Frame类中可以有多个帧(AAC),时间戳会变化 + * 一个Frame类中可以有多个帧,他们通过 0x 00 00 01 分隔 * ZLMediaKit会先把这种复合帧split成单个帧然后再处理 * 一个复合帧可以通过无内存拷贝的方式切割成多个子Frame * 提供该类的目的是切割复合帧时防止内存拷贝,提高性能 */ template -class FrameTSInternal : public Parent { +class FrameInternal : public FrameInternalBase { public: - using Ptr = std::shared_ptr; - FrameTSInternal( - const Frame::Ptr &parent_frame, char *ptr, size_t size, size_t prefix_size, uint64_t dts, uint64_t pts) - : Parent(ptr, size, dts, pts, prefix_size) { - _parent_frame = parent_frame; + using Ptr = std::shared_ptr; + FrameInternal(const Frame::Ptr &parent_frame, char *ptr, size_t size, size_t prefix_size) + : FrameInternalBase(parent_frame, ptr, size, prefix_size, parent_frame->dts(), parent_frame->pts()) {} +}; + +// 包装一个指针成不可缓存的frame +class FrameFromPtr : public Frame { +public: + using Ptr = std::shared_ptr; + + FrameFromPtr(CodecId codec_id, char *ptr, size_t size, uint64_t dts, uint64_t pts = 0, size_t prefix_size = 0, bool is_key = false) + : FrameFromPtr(ptr, size, dts, pts, prefix_size, is_key) { + _codec_id = codec_id; } - bool cacheAble() const override { return _parent_frame->cacheAble(); } + + FrameFromPtr(char *ptr, size_t size, uint64_t dts, uint64_t pts = 0, size_t prefix_size = 0, bool is_key = false) { + _ptr = ptr; + _size = size; + _dts = dts; + _pts = pts; + _prefix_size = prefix_size; + _is_key = is_key; + } + + char *data() const override { return _ptr; } + size_t size() const override { return _size; } + uint64_t dts() const override { return _dts; } + uint64_t pts() const override { return _pts ? _pts : dts(); } + size_t prefixSize() const override { return _prefix_size; } + bool cacheAble() const override { return false; } + bool keyFrame() const override { return _is_key; } + bool configFrame() const override { return false; } + void setCodecId(CodecId codec_id) { _codec_id = codec_id; } + + CodecId getCodecId() const override { + if (_codec_id == CodecInvalid) { + throw std::invalid_argument("Invalid codec type of FrameFromPtr"); + } + return _codec_id; + } + +protected: + FrameFromPtr() = default; + +protected: + bool _is_key; + char *_ptr; + uint64_t _dts; + uint64_t _pts = 0; + size_t _size; + size_t _prefix_size; + CodecId _codec_id = CodecInvalid; +}; + +// 管理一个指针生命周期并生产一个frame +class FrameAutoDelete : public FrameFromPtr { +public: + template + FrameAutoDelete(ARGS &&...args) : FrameFromPtr(std::forward(args)...) {} + + ~FrameAutoDelete() override { delete[] _ptr; }; + + bool cacheAble() const override { return true; } +}; + +// 把一个不可缓存的frame声明为可缓存的 +template +class FrameToCache : public Parent { +public: + template + FrameToCache(ARGS &&...args) : Parent(std::forward(args)...) {}; + + bool cacheAble() const override { + return true; + } +}; + +// 该对象的功能是把一个不可缓存的帧转换成可缓存的帧 +class FrameCacheAble : public FrameFromPtr { +public: + using Ptr = std::shared_ptr; + + FrameCacheAble(const Frame::Ptr &frame, bool force_key_frame = false) { + if (frame->cacheAble()) { + _frame = frame; + _ptr = frame->data(); + } else { + _buffer = FrameImp::create(); + _buffer->_buffer.assign(frame->data(), frame->size()); + _ptr = _buffer->data(); + } + _size = frame->size(); + _dts = frame->dts(); + _pts = frame->pts(); + _prefix_size = frame->prefixSize(); + _codec_id = frame->getCodecId(); + _key = force_key_frame ? true : frame->keyFrame(); + _config = frame->configFrame(); + _drop_able = frame->dropAble(); + _decode_able = frame->decodeAble(); + } + + /** + * 可以被缓存 + */ + bool cacheAble() const override { return true; } + bool keyFrame() const override { return _key; } + bool configFrame() const override { return _config; } + bool dropAble() const override { return _drop_able; } + bool decodeAble() const override { return _decode_able; } private: - Frame::Ptr _parent_frame; + bool _key; + bool _config; + bool _drop_able; + bool _decode_able; + Frame::Ptr _frame; + FrameImp::Ptr _buffer; +}; + +//该类实现frame级别的时间戳覆盖 +class FrameStamp : public Frame { +public: + using Ptr = std::shared_ptr; + FrameStamp(Frame::Ptr frame, Stamp &stamp, int modify_stamp); + ~FrameStamp() override {} + + uint64_t dts() const override { return (uint64_t)_dts; } + uint64_t pts() const override { return (uint64_t)_pts; } + size_t prefixSize() const override { return _frame->prefixSize(); } + bool keyFrame() const override { return _frame->keyFrame(); } + bool configFrame() const override { return _frame->configFrame(); } + bool cacheAble() const override { return _frame->cacheAble(); } + bool dropAble() const override { return _frame->dropAble(); } + bool decodeAble() const override { return _frame->decodeAble(); } + char *data() const override { return _frame->data(); } + size_t size() const override { return _frame->size(); } + CodecId getCodecId() const override { return _frame->getCodecId(); } + +private: + int64_t _dts; + int64_t _pts; + Frame::Ptr _frame; +}; + +/** + * 该对象可以把Buffer对象转换成可缓存的Frame对象 + */ +template +class FrameFromBuffer : public Parent { +public: + /** + * 构造frame + * @param buf 数据缓存 + * @param dts 解码时间戳 + * @param pts 显示时间戳 + * @param prefix 帧前缀长度 + * @param offset buffer有效数据偏移量 + */ + FrameFromBuffer(toolkit::Buffer::Ptr buf, uint64_t dts, uint64_t pts, size_t prefix, size_t offset) + : Parent(buf->data() + offset, buf->size() - offset, dts, pts, prefix) { + _buf = std::move(buf); + } + + /** + * 构造frame + * @param buf 数据缓存 + * @param dts 解码时间戳 + * @param pts 显示时间戳 + * @param prefix 帧前缀长度 + * @param offset buffer有效数据偏移量 + * @param codec 帧类型 + */ + FrameFromBuffer(toolkit::Buffer::Ptr buf, uint64_t dts, uint64_t pts, size_t prefix, size_t offset, CodecId codec) + : Parent(codec, buf->data() + offset, buf->size() - offset, dts, pts, prefix) { + _buf = std::move(buf); + } + + /** + * 该帧可缓存 + */ + bool cacheAble() const override { return true; } + +private: + toolkit::Buffer::Ptr _buf; +}; + +/** + * 合并一些时间戳相同的frame + */ +class FrameMerger { +public: + using onOutput = std::function; + using Ptr = std::shared_ptr; + enum { + none = 0, + h264_prefix, + mp4_nal_size, + }; + + FrameMerger(int type); + + /** + * 刷新输出缓冲,注意此时会调用FrameMerger::inputFrame传入的onOutput回调 + * 请注意回调捕获参数此时是否有效 + */ + void flush(); + void clear(); + bool inputFrame(const Frame::Ptr &frame, onOutput cb, toolkit::BufferLikeString *buffer = nullptr); + +private: + bool willFlush(const Frame::Ptr &frame) const; + void doMerge(toolkit::BufferLikeString &buffer, const Frame::Ptr &frame) const; + +private: + int _type; + bool _have_decode_able_frame = false; + onOutput _cb; + toolkit::List _frame_cache; }; /** @@ -393,202 +624,5 @@ private: std::map _delegates; }; -/** - * 通过Frame接口包装指针,方便使用者把自己的数据快速接入ZLMediaKit - */ -class FrameFromPtr : public Frame { -public: - using Ptr = std::shared_ptr; - - FrameFromPtr(CodecId codec_id, char *ptr, size_t size, uint64_t dts, uint64_t pts = 0, size_t prefix_size = 0, bool is_key = false) - : FrameFromPtr(ptr, size, dts, pts, prefix_size,is_key) { - _codec_id = codec_id; - } - - FrameFromPtr(char *ptr, size_t size, uint64_t dts, uint64_t pts = 0, size_t prefix_size = 0, bool is_key = false) { - _ptr = ptr; - _size = size; - _dts = dts; - _pts = pts; - _prefix_size = prefix_size; - _is_key = is_key; - } - - char *data() const override { return _ptr; } - size_t size() const override { return _size; } - uint64_t dts() const override { return _dts; } - uint64_t pts() const override { return _pts ? _pts : dts(); } - size_t prefixSize() const override { return _prefix_size; } - bool cacheAble() const override { return false; } - bool keyFrame() const override { return _is_key; } - bool configFrame() const override { return false; } - void setCodecId(CodecId codec_id) { _codec_id = codec_id; } - - CodecId getCodecId() const override { - if (_codec_id == CodecInvalid) { - throw std::invalid_argument("FrameFromPtr对象未设置codec类型"); - } - return _codec_id; - } - -protected: - FrameFromPtr() = default; - -protected: - bool _is_key; - char *_ptr; - uint64_t _dts; - uint64_t _pts = 0; - size_t _size; - size_t _prefix_size; - CodecId _codec_id = CodecInvalid; -}; - -/** - * 该对象的功能是把一个不可缓存的帧转换成可缓存的帧 - */ -class FrameCacheAble : public FrameFromPtr { -public: - using Ptr = std::shared_ptr; - - FrameCacheAble(const Frame::Ptr &frame, bool force_key_frame = false) { - if (frame->cacheAble()) { - _frame = frame; - _ptr = frame->data(); - } else { - _buffer = FrameImp::create(); - _buffer->_buffer.assign(frame->data(), frame->size()); - _ptr = _buffer->data(); - } - _size = frame->size(); - _dts = frame->dts(); - _pts = frame->pts(); - _prefix_size = frame->prefixSize(); - _codec_id = frame->getCodecId(); - _key = force_key_frame ? true : frame->keyFrame(); - _config = frame->configFrame(); - _drop_able = frame->dropAble(); - _decode_able = frame->decodeAble(); - } - - /** - * 可以被缓存 - */ - bool cacheAble() const override { return true; } - bool keyFrame() const override { return _key; } - bool configFrame() const override { return _config; } - bool dropAble() const override { return _drop_able; } - bool decodeAble() const override { return _decode_able; } - -private: - bool _key; - bool _config; - bool _drop_able; - bool _decode_able; - Frame::Ptr _frame; - FrameImp::Ptr _buffer; -}; - -//该类实现frame级别的时间戳覆盖 -class FrameStamp : public Frame { -public: - using Ptr = std::shared_ptr; - FrameStamp(Frame::Ptr frame, Stamp &stamp, int modify_stamp); - ~FrameStamp() override {} - - uint64_t dts() const override { return (uint64_t)_dts; } - uint64_t pts() const override { return (uint64_t)_pts; } - size_t prefixSize() const override { return _frame->prefixSize(); } - bool keyFrame() const override { return _frame->keyFrame(); } - bool configFrame() const override { return _frame->configFrame(); } - bool cacheAble() const override { return _frame->cacheAble(); } - bool dropAble() const override { return _frame->dropAble(); } - bool decodeAble() const override { return _frame->decodeAble(); } - char *data() const override { return _frame->data(); } - size_t size() const override { return _frame->size(); } - CodecId getCodecId() const override { return _frame->getCodecId(); } - -private: - int64_t _dts; - int64_t _pts; - Frame::Ptr _frame; -}; - -/** - * 该对象可以把Buffer对象转换成可缓存的Frame对象 - */ -template -class FrameWrapper : public Parent { -public: - /** - * 构造frame - * @param buf 数据缓存 - * @param dts 解码时间戳 - * @param pts 显示时间戳 - * @param prefix 帧前缀长度 - * @param offset buffer有效数据偏移量 - */ - FrameWrapper(toolkit::Buffer::Ptr buf, uint64_t dts, uint64_t pts, size_t prefix, size_t offset) - : Parent(buf->data() + offset, buf->size() - offset, dts, pts, prefix) { - _buf = std::move(buf); - } - - /** - * 构造frame - * @param buf 数据缓存 - * @param dts 解码时间戳 - * @param pts 显示时间戳 - * @param prefix 帧前缀长度 - * @param offset buffer有效数据偏移量 - * @param codec 帧类型 - */ - FrameWrapper(toolkit::Buffer::Ptr buf, uint64_t dts, uint64_t pts, size_t prefix, size_t offset, CodecId codec) - : Parent(codec, buf->data() + offset, buf->size() - offset, dts, pts, prefix) { - _buf = std::move(buf); - } - - /** - * 该帧可缓存 - */ - bool cacheAble() const override { return true; } - -private: - toolkit::Buffer::Ptr _buf; -}; - -/** - * 合并一些时间戳相同的frame - */ -class FrameMerger { -public: - using onOutput = std::function; - using Ptr = std::shared_ptr; - enum { - none = 0, - h264_prefix, - mp4_nal_size, - }; - - FrameMerger(int type); - - /** - * 刷新输出缓冲,注意此时会调用FrameMerger::inputFrame传入的onOutput回调 - * 请注意回调捕获参数此时是否有效 - */ - void flush(); - void clear(); - bool inputFrame(const Frame::Ptr &frame, onOutput cb, toolkit::BufferLikeString *buffer = nullptr); - -private: - bool willFlush(const Frame::Ptr &frame) const; - void doMerge(toolkit::BufferLikeString &buffer, const Frame::Ptr &frame) const; - -private: - int _type; - bool _have_decode_able_frame = false; - onOutput _cb; - toolkit::List _frame_cache; -}; - } // namespace mediakit #endif // ZLMEDIAKIT_FRAME_H \ No newline at end of file diff --git a/src/Record/MP4Demuxer.cpp b/src/Record/MP4Demuxer.cpp index 98ca373a..022a6c3d 100644 --- a/src/Record/MP4Demuxer.cpp +++ b/src/Record/MP4Demuxer.cpp @@ -13,10 +13,8 @@ #include "Util/logger.h" #include "Extension/H265.h" #include "Extension/H264.h" -#include "Extension/AAC.h" -#include "Extension/G711.h" -#include "Extension/Opus.h" #include "Extension/JPEG.h" +#include "Extension/Factory.h" using namespace std; using namespace toolkit; @@ -61,85 +59,21 @@ int MP4Demuxer::getAllTracks() { return mov_reader_getinfo(_mov_reader.get(),&s_on_track,this); } -#define SWITCH_CASE(obj_id) case obj_id : return #obj_id -static const char *getObjectName(int obj_id) { - switch (obj_id) { - SWITCH_CASE(MOV_OBJECT_TEXT); - SWITCH_CASE(MOV_OBJECT_MP4V); - SWITCH_CASE(MOV_OBJECT_H264); - SWITCH_CASE(MOV_OBJECT_HEVC); - SWITCH_CASE(MOV_OBJECT_AAC); - SWITCH_CASE(MOV_OBJECT_MP2V); - SWITCH_CASE(MOV_OBJECT_AAC_MAIN); - SWITCH_CASE(MOV_OBJECT_AAC_LOW); - SWITCH_CASE(MOV_OBJECT_AAC_SSR); - SWITCH_CASE(MOV_OBJECT_MP3); - SWITCH_CASE(MOV_OBJECT_MP1V); - SWITCH_CASE(MOV_OBJECT_MP1A); - SWITCH_CASE(MOV_OBJECT_JPEG); - SWITCH_CASE(MOV_OBJECT_PNG); - SWITCH_CASE(MOV_OBJECT_JPEG2000); - SWITCH_CASE(MOV_OBJECT_G719); - SWITCH_CASE(MOV_OBJECT_OPUS); - SWITCH_CASE(MOV_OBJECT_G711a); - SWITCH_CASE(MOV_OBJECT_G711u); - SWITCH_CASE(MOV_OBJECT_AV1); - default: return "unknown mp4 object"; - } -} - - void MP4Demuxer::onVideoTrack(uint32_t track, uint8_t object, int width, int height, const void *extra, size_t bytes) { - Track::Ptr video; - switch (object) { - case MOV_OBJECT_H264: { - video = std::make_shared(); - _track_to_codec.emplace(track, video); - break; - } - - case MOV_OBJECT_HEVC: { - video = std::make_shared(); - _track_to_codec.emplace(track, video); - break; - } - - case MOV_OBJECT_JPEG: { - video = std::make_shared(); - _track_to_codec.emplace(track, video); - break; - } - - default: WarnL << "不支持该编码类型的MP4,已忽略:" << getObjectName(object); break; + auto video = Factory::getTrackByCodecId(getCodecByMovId(object)); + if (!video) { + return; } + _track_to_codec.emplace(track, video); if (extra && bytes) { video->setExtraData((uint8_t *)extra, bytes); } } void MP4Demuxer::onAudioTrack(uint32_t track_id, uint8_t object, int channel_count, int bit_per_sample, int sample_rate, const void *extra, size_t bytes) { - Track::Ptr audio; - switch(object){ - case MOV_OBJECT_AAC:{ - audio = std::make_shared(); - _track_to_codec.emplace(track_id, audio); - break; - } - - case MOV_OBJECT_G711a: - case MOV_OBJECT_G711u:{ - audio = std::make_shared(object == MOV_OBJECT_G711a ? CodecG711A : CodecG711U, sample_rate, channel_count, bit_per_sample / channel_count ); - _track_to_codec.emplace(track_id, audio); - break; - } - - case MOV_OBJECT_OPUS: { - audio = std::make_shared(); - _track_to_codec.emplace(track_id, audio); - break; - } - - default: WarnL << "不支持该编码类型的MP4,已忽略:" << getObjectName(object); break; + auto audio = Factory::getTrackByCodecId(getCodecByMovId(object), sample_rate, channel_count, bit_per_sample / channel_count); + if (!audio) { + return; } if (extra && bytes) { audio->setExtraData((uint8_t *)extra, bytes); @@ -225,10 +159,10 @@ Frame::Ptr MP4Demuxer::makeFrame(uint32_t track_id, const Buffer::Ptr &buf, int6 offset += (frame_len + 4); } if (codec == CodecH264) { - ret = std::make_shared >(buf, (uint64_t)dts, (uint64_t)pts, 4, 0); + ret = std::make_shared >(buf, (uint64_t)dts, (uint64_t)pts, 4, 0); break; } - ret = std::make_shared >(buf, (uint64_t)dts, (uint64_t)pts, 4, 0); + ret = std::make_shared >(buf, (uint64_t)dts, (uint64_t)pts, 4, 0); break; } @@ -238,7 +172,7 @@ Frame::Ptr MP4Demuxer::makeFrame(uint32_t track_id, const Buffer::Ptr &buf, int6 } default: { - ret = std::make_shared>(buf, (uint64_t)dts, (uint64_t)pts, 0, 0, codec); + ret = std::make_shared>(buf, (uint64_t)dts, (uint64_t)pts, 0, 0, codec); break; } } diff --git a/src/Record/MP4Muxer.cpp b/src/Record/MP4Muxer.cpp index 19e317f9..c688d77a 100644 --- a/src/Record/MP4Muxer.cpp +++ b/src/Record/MP4Muxer.cpp @@ -133,21 +133,6 @@ bool MP4MuxerInterface::inputFrame(const Frame::Ptr &frame) { return true; } -static uint8_t getObject(CodecId codecId) { - switch (codecId){ - case CodecG711A : return MOV_OBJECT_G711a; - case CodecG711U : return MOV_OBJECT_G711u; - case CodecOpus : return MOV_OBJECT_OPUS; - case CodecAAC : return MOV_OBJECT_AAC; - case CodecH264 : return MOV_OBJECT_H264; - case CodecH265 : return MOV_OBJECT_HEVC; - case CodecJPEG : return MOV_OBJECT_JPEG; - case CodecVP9: return MOV_OBJECT_VP9; - case CodecAV1: return MOV_OBJECT_AV1; - default : return 0; - } -} - void MP4MuxerInterface::stampSync() { if (_codec_to_trackid.size() < 2) { return; @@ -172,14 +157,14 @@ bool MP4MuxerInterface::addTrack(const Track::Ptr &track) { if (!_mov_writter) { _mov_writter = createWriter(); } - auto mp4_object = getObject(track->getCodecId()); - if (!mp4_object) { - WarnL << "MP4录制不支持该编码格式:" << track->getCodecName(); + auto mp4_object = getMovIdByCodec(track->getCodecId()); + if (mp4_object == MOV_OBJECT_NONE) { + WarnL << "Unsupported codec: " << track->getCodecName(); return false; } if (!track->ready()) { - WarnL << "Track[" << track->getCodecName() << "]未就绪"; + WarnL << "Track[" << track->getCodecName() << "] unready"; return false; } diff --git a/src/Record/MPEG.cpp b/src/Record/MPEG.cpp index 153fd796..d1089fdb 100644 --- a/src/Record/MPEG.cpp +++ b/src/Record/MPEG.cpp @@ -30,26 +30,22 @@ MpegMuxer::~MpegMuxer() { releaseContext(); } -#define XX(name, type, value, str, mpeg_id) \ - case name: { \ - if (mpeg_id == PSI_STREAM_RESERVED) { \ - break; \ - } \ - if (track->getTrackType() == TrackVideo) { \ - _have_video = true; \ - } \ - _codec_to_trackid[track->getCodecId()] = mpeg_muxer_add_stream((::mpeg_muxer_t *)_context, mpeg_id, nullptr, 0); \ - return true; \ - } bool MpegMuxer::addTrack(const Track::Ptr &track) { - switch (track->getCodecId()) { - CODEC_MAP(XX) - default: break; + auto mpeg_id = getMpegIdByCodec(track->getCodecId()); + if (mpeg_id == PSI_STREAM_RESERVED) { + WarnL << "Unsupported codec: " << track->getCodecName(); + return false; } - WarnL << "不支持该编码格式,已忽略:" << track->getCodecName(); - return false; + + if (track->getTrackType() == TrackVideo) { + _have_video = true; + } + auto extra_data = track->getExtraData(); + _codec_to_trackid[track->getCodecId()] = mpeg_muxer_add_stream((::mpeg_muxer_t *)_context, mpeg_id, + extra_data ? extra_data->data() : nullptr, + extra_data ? extra_data->size(): 0); + return true; } -#undef XX bool MpegMuxer::inputFrame(const Frame::Ptr &frame) { auto it = _codec_to_trackid.find(frame->getCodecId()); diff --git a/src/Rtp/Decoder.cpp b/src/Rtp/Decoder.cpp index 37a347ac..4bd52f86 100644 --- a/src/Rtp/Decoder.cpp +++ b/src/Rtp/Decoder.cpp @@ -16,6 +16,7 @@ #include "Extension/AAC.h" #include "Extension/G711.h" #include "Extension/Opus.h" +#include "Extension/Factory.h" #if defined(ENABLE_RTPPROXY) || defined(ENABLE_HLS) #include "mpeg-ts.h" @@ -85,78 +86,18 @@ DecoderImp::DecoderImp(const Decoder::Ptr &decoder, MediaSinkInterface *sink){ } #if defined(ENABLE_RTPPROXY) || defined(ENABLE_HLS) -#define SWITCH_CASE(codec_id) case codec_id : return #codec_id -static const char *getCodecName(int codec_id) { - switch (codec_id) { - SWITCH_CASE(PSI_STREAM_MPEG1); - SWITCH_CASE(PSI_STREAM_MPEG2); - SWITCH_CASE(PSI_STREAM_AUDIO_MPEG1); - SWITCH_CASE(PSI_STREAM_MP3); - SWITCH_CASE(PSI_STREAM_AAC); - SWITCH_CASE(PSI_STREAM_MPEG4); - SWITCH_CASE(PSI_STREAM_MPEG4_AAC_LATM); - SWITCH_CASE(PSI_STREAM_H264); - SWITCH_CASE(PSI_STREAM_MPEG4_AAC); - SWITCH_CASE(PSI_STREAM_H265); - SWITCH_CASE(PSI_STREAM_AUDIO_AC3); - SWITCH_CASE(PSI_STREAM_AUDIO_EAC3); - SWITCH_CASE(PSI_STREAM_AUDIO_DTS); - SWITCH_CASE(PSI_STREAM_VIDEO_DIRAC); - SWITCH_CASE(PSI_STREAM_VIDEO_VC1); - SWITCH_CASE(PSI_STREAM_VIDEO_SVAC); - SWITCH_CASE(PSI_STREAM_AUDIO_SVAC); - SWITCH_CASE(PSI_STREAM_AUDIO_G711A); - SWITCH_CASE(PSI_STREAM_AUDIO_G711U); - SWITCH_CASE(PSI_STREAM_AUDIO_G722); - SWITCH_CASE(PSI_STREAM_AUDIO_G723); - SWITCH_CASE(PSI_STREAM_AUDIO_G729); - SWITCH_CASE(PSI_STREAM_AUDIO_OPUS); - default : return "unknown codec"; + +void DecoderImp::onStream(int stream, int codecid, const void *extra, size_t bytes, int finish) { + // G711传统只支持 8000/1/16的规格,FFmpeg貌似做了扩展,但是这里不管它了 + auto track = Factory::getTrackByCodecId(getCodecByMpegId(codecid), 8000, 1, 16); + if (!track) { + return; } -} - -void DecoderImp::onStream(int stream, int codecid, const void *extra, size_t bytes, int finish){ - switch (codecid) { - case PSI_STREAM_H264: { - onTrack(std::make_shared()); - break; - } - - case PSI_STREAM_H265: { - onTrack(std::make_shared()); - break; - } - - case PSI_STREAM_MPEG4_AAC : - case PSI_STREAM_AAC: { - onTrack(std::make_shared()); - break; - } - - case PSI_STREAM_AUDIO_G711A: - case PSI_STREAM_AUDIO_G711U: { - auto codec = codecid == PSI_STREAM_AUDIO_G711A ? CodecG711A : CodecG711U; - //G711传统只支持 8000/1/16的规格,FFmpeg貌似做了扩展,但是这里不管它了 - onTrack(std::make_shared(codec, 8000, 1, 16)); - break; - } - - case PSI_STREAM_AUDIO_OPUS: { - onTrack(std::make_shared()); - break; - } - - default: - if(codecid != 0){ - WarnL<< "unsupported codec type:" << getCodecName(codecid) << " " << (int)codecid; - } - break; - } - - //防止未获取视频track提前complete导致忽略后续视频的问题,用于兼容一些不太规范的ps流 - if (finish && _tracks[TrackVideo] ) { + onTrack(std::move(track)); + // 防止未获取视频track提前complete导致忽略后续视频的问题,用于兼容一些不太规范的ps流 + if (finish && _tracks[TrackVideo]) { _sink->addTrackCompleted(); - InfoL << "add track finished"; + InfoL << "Add track finished"; } } @@ -171,7 +112,7 @@ void DecoderImp::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t d } auto frame = std::make_shared((char *) data, bytes, (uint64_t)dts, (uint64_t)pts, prefixSize((char *) data, bytes)); _merger.inputFrame(frame,[this](uint64_t dts, uint64_t pts, const Buffer::Ptr &buffer, bool) { - onFrame(std::make_shared >(buffer, dts, pts, prefixSize(buffer->data(), buffer->size()), 0)); + onFrame(std::make_shared >(buffer, dts, pts, prefixSize(buffer->data(), buffer->size()), 0)); }); break; } @@ -182,7 +123,7 @@ void DecoderImp::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t d } auto frame = std::make_shared((char *) data, bytes, (uint64_t)dts, (uint64_t)pts, prefixSize((char *) data, bytes)); _merger.inputFrame(frame,[this](uint64_t dts, uint64_t pts, const Buffer::Ptr &buffer, bool) { - onFrame(std::make_shared >(buffer, dts, pts, prefixSize(buffer->data(), buffer->size()), 0)); + onFrame(std::make_shared >(buffer, dts, pts, prefixSize(buffer->data(), buffer->size()), 0)); }); break; } @@ -223,7 +164,7 @@ void DecoderImp::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t d default: // 海康的 PS 流中会有 codecid 为 0xBD 的包 if (codecid != 0 && codecid != 0xBD) { - WarnL << "unsupported codec type:" << getCodecName(codecid) << " " << (int) codecid; + WarnL << "Unsupported codec type:" << codecid; } break; } diff --git a/src/Rtp/GB28181Process.cpp b/src/Rtp/GB28181Process.cpp index 089aa902..bc48906f 100644 --- a/src/Rtp/GB28181Process.cpp +++ b/src/Rtp/GB28181Process.cpp @@ -12,11 +12,6 @@ #include "GB28181Process.h" #include "Extension/CommonRtp.h" #include "Extension/Factory.h" -#include "Extension/G711.h" -#include "Extension/H264.h" -#include "Extension/H265.h" -#include "Extension/Opus.h" -#include "Extension/JPEG.h" #include "Http/HttpTSPlayer.h" #include "Util/File.h" #include "Common/config.h" @@ -90,7 +85,8 @@ bool GB28181Process::inputRtp(bool, const char *data, size_t data_len) { case Rtsp::PT_PCMU: { // CodecG711U or CodecG711A ref = std::make_shared(8000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); }); - auto track = std::make_shared(pt == Rtsp::PT_PCMU ? CodecG711U : CodecG711A, 8000, 1, 16); + auto track = Factory::getTrackByCodecId(pt == Rtsp::PT_PCMU ? CodecG711U : CodecG711A, 8000, 1, 16); + CHECK(track); _interface->addTrack(track); _rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track); break; @@ -98,7 +94,8 @@ bool GB28181Process::inputRtp(bool, const char *data, size_t data_len) { case Rtsp::PT_JPEG: { // mjpeg ref = std::make_shared(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); }); - auto track = std::make_shared(); + auto track = Factory::getTrackByCodecId(CodecJPEG); + CHECK(track); _interface->addTrack(track); _rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track); break; @@ -107,19 +104,20 @@ bool GB28181Process::inputRtp(bool, const char *data, size_t data_len) { if (pt == opus_pt) { // opus负载 ref = std::make_shared(48000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); }); - auto track = std::make_shared(); + auto track = Factory::getTrackByCodecId(CodecOpus); + CHECK(track); _interface->addTrack(track); _rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track); } else if (pt == h265_pt) { // H265负载 ref = std::make_shared(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); }); - auto track = std::make_shared(); + auto track = Factory::getTrackByCodecId(CodecH265); _interface->addTrack(track); _rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track); } else if (pt == h264_pt) { // H264负载 ref = std::make_shared(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); }); - auto track = std::make_shared(); + auto track = Factory::getTrackByCodecId(CodecH264); _interface->addTrack(track); _rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track); } else { diff --git a/src/Rtp/PSEncoder.cpp b/src/Rtp/PSEncoder.cpp index ff9cd9e6..d5a3bfaa 100644 --- a/src/Rtp/PSEncoder.cpp +++ b/src/Rtp/PSEncoder.cpp @@ -12,7 +12,6 @@ #include "PSEncoder.h" #include "Common/config.h" -#include "Extension/H264.h" #include "Extension/CommonRtp.h" #include "Rtsp/RtspMuxer.h"