diff --git a/CMakeLists.txt b/CMakeLists.txt index 6350cb57..166a46ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,10 +187,7 @@ endif () set(VS_FALGS "/wd4819") #添加mpeg用于支持ts生成 -if (ENABLE_HLS) - message(STATUS "ENABLE_HLS defined") - add_definitions(-DENABLE_HLS) - +if (ENABLE_RTPPROXY OR ENABLE_HLS) include_directories(${MediaServer_Root}/libmpeg/include) aux_source_directory(${MediaServer_Root}/libmpeg/include src_mpeg) aux_source_directory(${MediaServer_Root}/libmpeg/source src_mpeg) @@ -228,12 +225,16 @@ if (ENABLE_MP4) endif () endif () -#添加rtp库用于rtp转ps/ts -if (ENABLE_RTPPROXY AND ENABLE_HLS) +if (ENABLE_RTPPROXY) message(STATUS "ENABLE_RTPPROXY defined") add_definitions(-DENABLE_RTPPROXY) endif () +if (ENABLE_HLS) + message(STATUS "ENABLE_HLS defined") + add_definitions(-DENABLE_HLS) +endif () + #收集源代码 file(GLOB ToolKit_src_list ${ToolKit_Root}/*/*.cpp ${ToolKit_Root}/*/*.h ${ToolKit_Root}/*/*.c) if (IOS) diff --git a/server/main.cpp b/server/main.cpp index 0842f321..1b8d1c5e 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -16,6 +16,7 @@ #include "Util/onceToken.h" #include "Util/CMD.h" #include "Network/TcpServer.h" +#include "Network/UdpServer.h" #include "Poller/EventPoller.h" #include "Common/config.h" #include "Rtsp/RtspSession.h" diff --git a/src/Extension/Frame.cpp b/src/Extension/Frame.cpp index b5213a73..a32e389e 100644 --- a/src/Extension/Frame.cpp +++ b/src/Extension/Frame.cpp @@ -92,7 +92,7 @@ Frame::Ptr Frame::getCacheAbleFrame(const Frame::Ptr &frame){ TrackType getTrackType(CodecId codecId) { switch (codecId) { -#define XX(name, type, value, str) case name : return type; +#define XX(name, type, value, str, mpeg_id) case name : return type; CODEC_MAP(XX) #undef XX default : return TrackInvalid; @@ -101,14 +101,14 @@ TrackType getTrackType(CodecId codecId) { const char *getCodecName(CodecId codec) { switch (codec) { -#define XX(name, type, value, str) case name : return str; +#define XX(name, type, value, str, mpeg_id) case name : return str; CODEC_MAP(XX) #undef XX default : return "invalid"; } } -#define XX(name, type, value, str) {str, name}, +#define XX(name, type, value, str, mpeg_id) {str, name}, static map codec_map = {CODEC_MAP(XX)}; #undef XX diff --git a/src/Extension/Frame.h b/src/Extension/Frame.h index f3773e44..6d42928b 100644 --- a/src/Extension/Frame.h +++ b/src/Extension/Frame.h @@ -31,20 +31,20 @@ typedef enum { } TrackType; #define CODEC_MAP(XX) \ - XX(CodecH264, TrackVideo, 0, "H264") \ - XX(CodecH265, TrackVideo, 1, "H265") \ - XX(CodecAAC, TrackAudio, 2, "mpeg4-generic") \ - XX(CodecG711A, TrackAudio, 3, "PCMA") \ - XX(CodecG711U, TrackAudio, 4, "PCMU") \ - XX(CodecOpus, TrackAudio, 5, "opus") \ - XX(CodecL16, TrackAudio, 6, "L16") \ - XX(CodecVP8, TrackVideo, 7, "VP8") \ - XX(CodecVP9, TrackVideo, 8, "VP9") \ - XX(CodecAV1, TrackVideo, 9, "AV1X") + 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, "AV1X", PSI_STREAM_AV1) typedef enum { CodecInvalid = -1, -#define XX(name, type, value, str) name = value, +#define XX(name, type, value, str, mpeg_id) name = value, CODEC_MAP(XX) #undef XX CodecMax diff --git a/src/Record/HlsRecorder.h b/src/Record/HlsRecorder.h index 115b9c65..4be987a4 100644 --- a/src/Record/HlsRecorder.h +++ b/src/Record/HlsRecorder.h @@ -12,13 +12,15 @@ #define HLSRECORDER_H #include "HlsMakerImp.h" -#include "TsMuxer.h" +#include "MPEG.h" + namespace mediakit { -class HlsRecorder : public MediaSourceEventInterceptor, public TsMuxer, public std::enable_shared_from_this { +class HlsRecorder : public MediaSourceEventInterceptor, public MpegMuxer, public std::enable_shared_from_this { public: - typedef std::shared_ptr Ptr; - HlsRecorder(const string &m3u8_file, const string ¶ms){ + using Ptr = std::shared_ptr; + + HlsRecorder(const string &m3u8_file, const string ¶ms) : MpegMuxer(false) { GET_CONFIG(uint32_t, hlsNum, Hls::kSegmentNum); GET_CONFIG(uint32_t, hlsBufSize, Hls::kFileBufSize); GET_CONFIG(float, hlsDuration, Hls::kSegmentDuration); @@ -27,7 +29,7 @@ public: _hls->clearCache(); } - ~HlsRecorder(){} + ~HlsRecorder() = default; void setMediaSource(const string &vhost, const string &app, const string &stream_id) { _hls->setMediaSource(vhost, app, stream_id); @@ -68,17 +70,17 @@ public: _hls->clearCache(); } if (_enabled || !hls_demand) { - return TsMuxer::inputFrame(frame); + return MpegMuxer::inputFrame(frame); } return false; } private: - void onTs(std::shared_ptr buffer, uint32_t timestamp, bool is_idr_fast_packet) override { + void onWrite(std::shared_ptr buffer, uint32_t timestamp, bool key_pos) override { if (!buffer) { - _hls->inputData(nullptr, 0, timestamp, is_idr_fast_packet); + _hls->inputData(nullptr, 0, timestamp, key_pos); } else { - _hls->inputData(buffer->data(), buffer->size(), timestamp, is_idr_fast_packet); + _hls->inputData(buffer->data(), buffer->size(), timestamp, key_pos); } } diff --git a/src/Record/MPEG.cpp b/src/Record/MPEG.cpp new file mode 100644 index 00000000..bb5e9e6b --- /dev/null +++ b/src/Record/MPEG.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include +#include "MPEG.h" + +#if defined(ENABLE_HLS) || defined(ENABLE_RTPPROXY) + +#include "mpeg-ps.h" +#include "mpeg-ts.h" +#include "mpeg-ts-proto.h" + +namespace mediakit{ + +struct mpeg_muxer_t { + int is_ps; + union { + struct { + void *ctx; + void *param; + mpeg_muxer_func_t func; + } ts; + ps_muxer_t *ps; + } u; +}; + +static void *on_mpeg_ts_alloc(void *param, size_t bytes) { + mpeg_muxer_t *mpeg = (mpeg_muxer_t *) param; + return mpeg->u.ts.func.alloc(mpeg->u.ts.param, bytes); +} + +static void on_mpeg_ts_free(void *param, void *packet) { + mpeg_muxer_t *mpeg = (mpeg_muxer_t *) param; + mpeg->u.ts.func.free(mpeg->u.ts.param, packet); +} + +static int on_mpeg_ts_write(void *param, const void *packet, size_t bytes) { + mpeg_muxer_t *mpeg = (mpeg_muxer_t *) param; + return mpeg->u.ts.func.write(mpeg->u.ts.param, 0, (void *) packet, bytes); +} + +mpeg_muxer_t *mpeg_muxer_create(int is_ps, const mpeg_muxer_func_t *func, void *param) { + mpeg_muxer_t *mpeg = (mpeg_muxer_t *) malloc(sizeof(mpeg_muxer_t)); + assert(mpeg); + mpeg->is_ps = is_ps; + if (is_ps) { + mpeg->u.ps = ps_muxer_create(func, param); + } else { + struct mpeg_ts_func_t ts_func{on_mpeg_ts_alloc, on_mpeg_ts_free, on_mpeg_ts_write}; + mpeg->u.ts.func = *func; + mpeg->u.ts.param = param; + mpeg->u.ts.ctx = mpeg_ts_create(&ts_func, mpeg); + } + return mpeg; +} + +int mpeg_muxer_destroy(mpeg_muxer_t *muxer) { + assert(muxer); + int ret = -1; + if (muxer->is_ps) { + ret = ps_muxer_destroy(muxer->u.ps); + } else { + ret = mpeg_ts_destroy(muxer->u.ts.ctx); + } + free(muxer); + return ret; +} + +int mpeg_muxer_add_stream(mpeg_muxer_t *muxer, int codecid, const void *extradata, size_t extradata_size) { + assert(muxer); + if (muxer->is_ps) { + return ps_muxer_add_stream(muxer->u.ps, codecid, extradata, extradata_size); + } + return mpeg_ts_add_stream(muxer->u.ts.ctx, codecid, extradata, extradata_size); +} + +int mpeg_muxer_input(mpeg_muxer_t *muxer, int stream, int flags, int64_t pts, int64_t dts, const void *data, size_t bytes) { + assert(muxer); + if (muxer->is_ps) { + return ps_muxer_input(muxer->u.ps, stream, flags, pts, dts, data, bytes); + } + return mpeg_ts_write(muxer->u.ts.ctx, stream, flags, pts, dts, data, bytes); +} + +int mpeg_muxer_reset(mpeg_muxer_t *muxer) { + assert(muxer); + if (muxer->is_ps) { + return -1; + } + return mpeg_ts_reset(muxer->u.ts.ctx); +} + +int mpeg_muxer_add_program(mpeg_muxer_t *muxer, uint16_t pn, const void *info, int bytes) { + assert(muxer); + if (muxer->is_ps) { + return -1; + } + return mpeg_ts_add_program(muxer->u.ts.ctx, pn, info, bytes); +} + +int mpeg_muxer_remove_program(mpeg_muxer_t *muxer, uint16_t pn) { + assert(muxer); + if (muxer->is_ps) { + return -1; + } + return mpeg_ts_remove_program(muxer->u.ts.ctx, pn); +} + +int peg_muxer_add_program_stream(mpeg_muxer_t *muxer, uint16_t pn, int codecid, const void *extra_data, size_t extra_data_size) { + assert(muxer); + if (muxer->is_ps) { + return -1; + } + return mpeg_ts_add_program_stream(muxer->u.ts.ctx, pn, codecid, extra_data, extra_data_size); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +MpegMuxer::MpegMuxer(bool is_ps) { + _is_ps = is_ps; + _buffer = BufferRaw::create(); + createContext(); +} + +MpegMuxer::~MpegMuxer() { + releaseContext(); +} + +#define XX(name, type, value, str, mpeg_id) \ + case name : { \ + if (mpeg_id == PSI_STREAM_RESERVED) { \ + break; \ + } \ + _codec_to_trackid[track->getCodecId()] = mpeg_muxer_add_stream(_context, mpeg_id, nullptr, 0); \ + return true; \ + } + +bool MpegMuxer::addTrack(const Track::Ptr &track) { + if (track->getTrackType() == TrackVideo) { + _have_video = true; + } + switch (track->getCodecId()) { + CODEC_MAP(XX) + default: break; + } + WarnL << "不支持该编码格式,已忽略:" << track->getCodecName(); + return false; +} +#undef XX + +bool MpegMuxer::inputFrame(const Frame::Ptr &frame) { + auto it = _codec_to_trackid.find(frame->getCodecId()); + if (it == _codec_to_trackid.end()) { + return false; + } + auto track_id = it->second; + _key_pos = !_have_video; + switch (frame->getCodecId()) { + case CodecH264: + case CodecH265: { + //这里的代码逻辑是让SPS、PPS、IDR这些时间戳相同的帧打包到一起当做一个帧处理, + return _frame_merger.inputFrame(frame,[&](uint32_t dts, uint32_t pts, const Buffer::Ptr &buffer, bool have_idr) { + _key_pos = have_idr; + //取视频时间戳为TS的时间戳 + _timestamp = (uint32_t) dts; + mpeg_muxer_input(_context, track_id, have_idr ? 0x0001 : 0, pts * 90LL,dts * 90LL, buffer->data(), buffer->size()); + flushCache(); + }); + } + + case CodecAAC: { + if (frame->prefixSize() == 0) { + WarnL << "必须提供adts头才能mpeg-ts打包"; + return false; + } + } + + default: { + if (!_have_video) { + //没有视频时,才以音频时间戳为TS的时间戳 + _timestamp = (uint32_t) frame->dts(); + } + mpeg_muxer_input(_context, track_id, frame->keyFrame() ? 0x0001 : 0, frame->pts() * 90LL, frame->dts() * 90LL, frame->data(), frame->size()); + flushCache(); + return true; + } + } +} + +void MpegMuxer::resetTracks() { + _have_video = false; + //通知片段中断 + onWrite(nullptr, _timestamp, false); + releaseContext(); + createContext(); +} + +void MpegMuxer::createContext() { + static mpeg_muxer_func_t func = { + /*alloc*/ + [](void *param, size_t bytes) { + MpegMuxer *thiz = (MpegMuxer *) param; + thiz->_buffer->setCapacity(bytes + 1); + return (void *) thiz->_buffer->data(); + }, + /*free*/ + [](void *param, void *packet) { + //什么也不做 + }, + /*wtite*/ + [](void *param, int stream, void *packet, size_t bytes) { + MpegMuxer *thiz = (MpegMuxer *) param; + thiz->onWrite_l(packet, bytes); + return 0; + } + }; + if (_context == nullptr) { + _context = mpeg_muxer_create(_is_ps, &func, this); + } +} + +void MpegMuxer::onWrite_l(const void *packet, size_t bytes) { + if (!_cache) { + _cache = std::make_shared(); + } + _cache->append((char *) packet, bytes); +} + +void MpegMuxer::flushCache() { + if (!_cache || _cache->empty()) { + return; + } + onWrite(std::move(_cache), _timestamp, _key_pos); + _key_pos = false; +} + +void MpegMuxer::releaseContext() { + if (_context) { + mpeg_muxer_destroy(_context); + _context = nullptr; + } + _codec_to_trackid.clear(); + _frame_merger.clear(); +} + +}//mediakit + +#endif \ No newline at end of file diff --git a/src/Record/MPEG.h b/src/Record/MPEG.h new file mode 100644 index 00000000..ab271c01 --- /dev/null +++ b/src/Record/MPEG.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef ZLMEDIAKIT_MPEG_H +#define ZLMEDIAKIT_MPEG_H + +#if defined(ENABLE_HLS) || defined(ENABLE_RTPPROXY) + +#include +#include +#include +#include "mpeg-ps.h" +#include "Extension/Frame.h" +#include "Extension/Track.h" +#include "Util/File.h" +#include "Common/MediaSink.h" +#include "Common/Stamp.h" + +namespace mediakit { + +typedef struct mpeg_muxer_t mpeg_muxer_t; +typedef struct ps_muxer_func_t mpeg_muxer_func_t; + +mpeg_muxer_t *mpeg_muxer_create(int is_ps, const mpeg_muxer_func_t *func, void *param); +int mpeg_muxer_destroy(mpeg_muxer_t *muxer); +int mpeg_muxer_add_stream(mpeg_muxer_t *muxer, int codecid, const void *extradata, size_t extradata_size); +int mpeg_muxer_input(mpeg_muxer_t *muxer, int stream, int flags, int64_t pts, int64_t dts, const void *data, size_t bytes); +int mpeg_muxer_reset(mpeg_muxer_t *muxer); +int mpeg_muxer_add_program(mpeg_muxer_t *muxer, uint16_t pn, const void *info, int bytes); +int mpeg_muxer_remove_program(mpeg_muxer_t *muxer, uint16_t pn); +int peg_muxer_add_program_stream(mpeg_muxer_t *muxer, uint16_t pn, int codecid, const void *extra_data, size_t extra_data_size); + +/////////////////////////////////////////////////////////////// + +//该类用于产生MPEG-TS/MPEG-PS +class MpegMuxer : public MediaSinkInterface { +public: + MpegMuxer(bool is_ps); + ~MpegMuxer() override; + + /** + * 添加音视频轨道 + */ + bool addTrack(const Track::Ptr &track) override; + + /** + * 重置音视频轨道 + */ + void resetTracks() override; + + /** + * 输入帧数据 + */ + bool inputFrame(const Frame::Ptr &frame) override; + +protected: + /** + * 输出ts/ps数据回调 + * @param buffer ts/ps数据包 + * @param timestamp 时间戳,单位毫秒 + * @param key_pos 是否为关键帧的第一个ts/ps包,用于确保ts切片第一帧为关键帧 + */ + virtual void onWrite(std::shared_ptr buffer, uint32_t timestamp, bool key_pos) = 0; + +private: + void createContext(); + void releaseContext(); + void flushCache(); + void onWrite_l(const void *packet, size_t bytes); + +private: + bool _is_ps = false; + bool _have_video = false; + bool _key_pos = false; + uint32_t _timestamp = 0; + mpeg_muxer_t *_context = nullptr; + BufferRaw::Ptr _buffer; + unordered_map _codec_to_trackid; + FrameMerger _frame_merger{FrameMerger::h264_prefix}; + std::shared_ptr _cache; +}; + +}//mediakit + +#else + +#include "Common/MediaSink.h" + +namespace mediakit { + +class MpegMuxer : public MediaSinkInterface { +public: + MpegMuxer(bool is_ps) {}; + ~MpegMuxer() override = default; + bool addTrack(const Track::Ptr &track) override { return false; } + void resetTracks() override {} + bool inputFrame(const Frame::Ptr &frame) override { return false; } + +protected: + virtual void onWrite(std::shared_ptr buffer, uint32_t timestamp, bool key_pos) = 0; +}; + +}//namespace mediakit + +#endif + +#endif //ZLMEDIAKIT_MPEG_H diff --git a/src/Record/TsMuxer.cpp b/src/Record/TsMuxer.cpp deleted file mode 100644 index ab63b5b5..00000000 --- a/src/Record/TsMuxer.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. - * - * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit). - * - * Use of this source code is governed by MIT license that can be found in the - * LICENSE file in the root of the source tree. All contributing project authors - * may be found in the AUTHORS file in the root of the source tree. - */ - -#if defined(ENABLE_HLS) - -#include "TsMuxer.h" -#include "mpeg-ts-proto.h" -#include "mpeg-ts.h" -#include "Extension/H264.h" - -namespace mediakit { - -TsMuxer::TsMuxer() { - init(); -} - -TsMuxer::~TsMuxer() { - uninit(); -} - -bool TsMuxer::addTrack(const Track::Ptr &track) { - switch (track->getCodecId()) { - case CodecH264: { - _have_video = true; - _codec_to_trackid[track->getCodecId()] = mpeg_ts_add_stream(_context, PSI_STREAM_H264, nullptr, 0); - break; - } - - case CodecH265: { - _have_video = true; - _codec_to_trackid[track->getCodecId()] = mpeg_ts_add_stream(_context, PSI_STREAM_H265, nullptr, 0); - break; - } - - case CodecAAC: { - _codec_to_trackid[track->getCodecId()] = mpeg_ts_add_stream(_context, PSI_STREAM_AAC, nullptr, 0); - break; - } - - case CodecG711A: { - _codec_to_trackid[track->getCodecId()] = mpeg_ts_add_stream(_context, PSI_STREAM_AUDIO_G711A,nullptr, 0); - break; - } - - case CodecG711U: { - _codec_to_trackid[track->getCodecId()] = mpeg_ts_add_stream(_context, PSI_STREAM_AUDIO_G711U,nullptr, 0); - break; - } - - case CodecOpus: { - _codec_to_trackid[track->getCodecId()] = mpeg_ts_add_stream(_context, PSI_STREAM_AUDIO_OPUS,nullptr, 0); - break; - } - - default: WarnL << "mpeg-ts 不支持该编码格式,已忽略:" << track->getCodecName(); return false; - } - - return true; -} - -bool TsMuxer::inputFrame(const Frame::Ptr &frame) { - auto it = _codec_to_trackid.find(frame->getCodecId()); - if (it == _codec_to_trackid.end()) { - return false; - } - auto track_id = it->second; - _is_idr_fast_packet = !_have_video; - switch (frame->getCodecId()) { - case CodecH264: - case CodecH265: { - //这里的代码逻辑是让SPS、PPS、IDR这些时间戳相同的帧打包到一起当做一个帧处理, - return _frame_merger.inputFrame(frame,[&](uint32_t dts, uint32_t pts, const Buffer::Ptr &buffer, bool have_idr) { - //取视频时间戳为TS的时间戳 - _timestamp = (uint32_t) dts; - _is_idr_fast_packet = have_idr; - mpeg_ts_write(_context, track_id, have_idr ? 0x0001 : 0, pts * 90LL,dts * 90LL, buffer->data(), buffer->size()); - flushCache(); - }); - } - - case CodecAAC: { - if (frame->prefixSize() == 0) { - WarnL << "必须提供adts头才能mpeg-ts打包"; - return false; - } - } - - default: { - if (!_have_video) { - //没有视频时,才以音频时间戳为TS的时间戳 - _timestamp = (uint32_t) frame->dts(); - } - mpeg_ts_write(_context, track_id, frame->keyFrame() ? 0x0001 : 0, frame->pts() * 90LL, frame->dts() * 90LL, frame->data(), frame->size()); - flushCache(); - return true; - } - } -} - -void TsMuxer::resetTracks() { - _have_video = false; - //通知片段中断 - onTs(nullptr, _timestamp, 0); - uninit(); - init(); -} - -void TsMuxer::init() { - static mpeg_ts_func_t s_func = { - [](void *param, size_t bytes) { - TsMuxer *muxer = (TsMuxer *) param; - assert(sizeof(muxer->_tsbuf) >= bytes); - return (void *) muxer->_tsbuf; - }, - [](void *param, void *packet) { - //do nothing - }, - [](void *param, const void *packet, size_t bytes) { - TsMuxer *muxer = (TsMuxer *) param; - muxer->onTs_l(packet, bytes); - return 0; - } - }; - if (_context == nullptr) { - _context = mpeg_ts_create(&s_func, this); - } -} - -void TsMuxer::onTs_l(const void *packet, size_t bytes) { - if (!_cache) { - _cache = std::make_shared(); - } - _cache->append((char *) packet, bytes); -} - -void TsMuxer::flushCache() { - onTs(std::move(_cache), _timestamp, _is_idr_fast_packet); - _is_idr_fast_packet = false; -} - -void TsMuxer::uninit() { - if (_context) { - mpeg_ts_destroy(_context); - _context = nullptr; - } - _codec_to_trackid.clear(); - _frame_merger.clear(); -} - -}//namespace mediakit - -#endif// defined(ENABLE_HLS) \ No newline at end of file diff --git a/src/Record/TsMuxer.h b/src/Record/TsMuxer.h deleted file mode 100644 index 0be8b3b3..00000000 --- a/src/Record/TsMuxer.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. - * - * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit). - * - * Use of this source code is governed by MIT license that can be found in the - * LICENSE file in the root of the source tree. All contributing project authors - * may be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef TSMUXER_H -#define TSMUXER_H - -#if defined(ENABLE_HLS) - -#include -#include "Extension/Frame.h" -#include "Extension/Track.h" -#include "Util/File.h" -#include "Common/MediaSink.h" -#include "Common/Stamp.h" - -using namespace toolkit; - -namespace mediakit { - -//该类用于产生MPEG-TS -class TsMuxer : public MediaSinkInterface { -public: - TsMuxer(); - virtual ~TsMuxer(); - - /** - * 添加音视频轨道 - */ - bool addTrack(const Track::Ptr &track) override; - - /** - * 重置音视频轨道 - */ - void resetTracks() override; - - /** - * 输入帧数据 - */ - bool inputFrame(const Frame::Ptr &frame) override; - -protected: - /** - * 输出mpegts数据回调 - * @param buffer mpegts数据包 - * @param timestamp 时间戳,单位毫秒 - * @param is_idr_fast_packet 是否为关键帧的第一个TS包,用于确保ts切片第一帧为关键帧 - */ - virtual void onTs(std::shared_ptr buffer, uint32_t timestamp, bool is_idr_fast_packet) = 0; - -private: - void init(); - void uninit(); - void flushCache(); - void onTs_l(const void *packet, size_t bytes); - -private: - bool _have_video = false; - bool _is_idr_fast_packet = false; - void *_context = nullptr; - char _tsbuf[188]; - uint32_t _timestamp = 0; - unordered_map _codec_to_trackid; - FrameMerger _frame_merger{FrameMerger::h264_prefix}; - std::shared_ptr _cache; -}; - -}//namespace mediakit - -#else - -#include "Common/MediaSink.h" - -namespace mediakit { -class TsMuxer : public MediaSinkInterface { -public: - TsMuxer() {} - ~TsMuxer() override {} - bool addTrack(const Track::Ptr &track) override { return false; } - void resetTracks() override {} - bool inputFrame(const Frame::Ptr &frame) override { return false; } - -protected: - virtual void onTs(std::shared_ptr buffer, uint32_t timestamp,bool is_idr_fast_packet) = 0; -}; -}//namespace mediakit - -#endif// defined(ENABLE_HLS) - -#endif //TSMUXER_H \ No newline at end of file diff --git a/src/Rtp/PSEncoder.cpp b/src/Rtp/PSEncoder.cpp index bc49d63a..36995279 100644 --- a/src/Rtp/PSEncoder.cpp +++ b/src/Rtp/PSEncoder.cpp @@ -9,148 +9,14 @@ */ #if defined(ENABLE_RTPPROXY) + #include "PSEncoder.h" #include "Extension/H264.h" #include "Rtsp/RtspMuxer.h" + namespace mediakit{ -PSEncoder::PSEncoder() { - _buffer = BufferRaw::create(); - init(); -} - -PSEncoder::~PSEncoder() { - -} - -void PSEncoder::init() { - static struct ps_muxer_func_t func = { - /*alloc*/ - [](void *param, size_t bytes) { - PSEncoder *thiz = (PSEncoder *) param; - thiz->_buffer->setCapacity(bytes + 1); - return (void *) thiz->_buffer->data(); - }, - /*free*/ - [](void *param, void *packet) { - //什么也不做 - }, - /*wtite*/ - [](void *param, int stream, void *packet, size_t bytes) { - PSEncoder *thiz = (PSEncoder *) param; - thiz->onPS(thiz->_timestamp, packet, bytes); - return 0; - } - }; - - _muxer.reset(ps_muxer_create(&func, this), [](struct ps_muxer_t *ptr) { - ps_muxer_destroy(ptr); - }); -} - -bool PSEncoder::addTrack(const Track::Ptr &track) { - switch (track->getCodecId()) { - case CodecH264: { - _codec_to_trackid[track->getCodecId()].track_id = ps_muxer_add_stream(_muxer.get(), STREAM_VIDEO_H264, nullptr, 0); - break; - } - - case CodecH265: { - _codec_to_trackid[track->getCodecId()].track_id = ps_muxer_add_stream(_muxer.get(), STREAM_VIDEO_H265, nullptr, 0); - break; - } - - case CodecAAC: { - _codec_to_trackid[track->getCodecId()].track_id = ps_muxer_add_stream(_muxer.get(), STREAM_AUDIO_AAC, nullptr, 0); - break; - } - - case CodecG711A: { - _codec_to_trackid[track->getCodecId()].track_id = ps_muxer_add_stream(_muxer.get(), STREAM_AUDIO_G711A, nullptr, 0); - break; - } - - case CodecG711U: { - _codec_to_trackid[track->getCodecId()].track_id = ps_muxer_add_stream(_muxer.get(), STREAM_AUDIO_G711U, nullptr, 0); - break; - } - - case CodecOpus: { - _codec_to_trackid[track->getCodecId()].track_id = ps_muxer_add_stream(_muxer.get(), STREAM_AUDIO_OPUS, nullptr, 0); - break; - } - - default: WarnL << "mpeg-ps 不支持该编码格式,已忽略:" << track->getCodecName(); return false; - } - //尝试音视频同步 - stampSync(); - return true; -} - -void PSEncoder::stampSync(){ - if(_codec_to_trackid.size() < 2){ - return; - } - - Stamp *audio = nullptr, *video = nullptr; - for(auto &pr : _codec_to_trackid){ - switch (getTrackType((CodecId) pr.first)){ - case TrackAudio : audio = &pr.second.stamp; break; - case TrackVideo : video = &pr.second.stamp; break; - default : break; - } - } - - if(audio && video){ - //音频时间戳同步于视频,因为音频时间戳被修改后不影响播放 - audio->syncTo(*video); - } -} - -void PSEncoder::resetTracks() { - init(); -} - -bool PSEncoder::inputFrame(const Frame::Ptr &frame) { - auto it = _codec_to_trackid.find(frame->getCodecId()); - if (it == _codec_to_trackid.end()) { - return false; - } - auto &track_info = it->second; - int64_t dts_out, pts_out; - switch (frame->getCodecId()) { - case CodecH264: - case CodecH265: { - //这里的代码逻辑是让SPS、PPS、IDR这些时间戳相同的帧打包到一起当做一个帧处理, - return _frame_merger.inputFrame(frame, [&](uint32_t dts, uint32_t pts, const Buffer::Ptr &buffer, bool have_idr) { - track_info.stamp.revise(dts, pts, dts_out, pts_out); - //取视频时间戳为TS的时间戳 - _timestamp = (uint32_t) pts_out; - ps_muxer_input(_muxer.get(), track_info.track_id, have_idr ? 0x0001 : 0, - pts_out * 90LL, dts_out * 90LL, buffer->data(), buffer->size()); - }); - } - - case CodecAAC: { - if (frame->prefixSize() == 0) { - WarnL << "必须提供adts头才能mpeg-ps打包"; - return false; - } - } - - default: { - track_info.stamp.revise(frame->dts(), frame->pts(), dts_out, pts_out); - _timestamp = (uint32_t) dts_out; - ps_muxer_input(_muxer.get(), track_info.track_id, frame->keyFrame() ? 0x0001 : 0, pts_out * 90LL, - dts_out * 90LL, frame->data(), frame->size()); - return true; - } - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -PSEncoderImp::PSEncoderImp(uint32_t ssrc, uint8_t payload_type) { +PSEncoderImp::PSEncoderImp(uint32_t ssrc, uint8_t payload_type) : MpegMuxer(true) { GET_CONFIG(uint32_t,video_mtu,Rtp::kVideoMtuSize); _rtp_encoder = std::make_shared(CodecInvalid, ssrc, video_mtu, 90000, payload_type, 0); _rtp_encoder->setRtpRing(std::make_shared()); @@ -164,9 +30,13 @@ PSEncoderImp::~PSEncoderImp() { InfoL << this << " " << printSSRC(_rtp_encoder->getSsrc()); } -void PSEncoderImp::onPS(uint32_t stamp, void *packet, size_t bytes) { - _rtp_encoder->inputFrame(std::make_shared((char *) packet, bytes, stamp, stamp)); +void PSEncoderImp::onWrite(std::shared_ptr buffer, uint32_t stamp, bool key_pos) { + if (!buffer) { + return; + } + _rtp_encoder->inputFrame(std::make_shared(buffer->data(), buffer->size(), stamp, stamp)); } }//namespace mediakit + #endif//defined(ENABLE_RTPPROXY) diff --git a/src/Rtp/PSEncoder.h b/src/Rtp/PSEncoder.h index deb29a85..8e09e028 100644 --- a/src/Rtp/PSEncoder.h +++ b/src/Rtp/PSEncoder.h @@ -10,63 +10,17 @@ #ifndef ZLMEDIAKIT_PSENCODER_H #define ZLMEDIAKIT_PSENCODER_H + #if defined(ENABLE_RTPPROXY) -#include "mpeg-ps.h" + +#include "Record/MPEG.h" #include "Common/MediaSink.h" #include "Common/Stamp.h" #include "Extension/CommonRtp.h" + namespace mediakit{ -//该类实现mpeg-ps容器格式的打包 -class PSEncoder : public MediaSinkInterface { -public: - PSEncoder(); - ~PSEncoder() override; - - /** - * 添加音视频轨道 - */ - bool addTrack(const Track::Ptr &track) override; - - /** - * 重置音视频轨道 - */ - void resetTracks() override; - - /** - * 输入帧数据 - */ - bool inputFrame(const Frame::Ptr &frame) override; - -protected: - /** - * 输出mpeg-ps的回调函数 - * @param stamp 时间戳,毫秒 - * @param packet 数据指针 - * @param bytes 数据长度 - */ - virtual void onPS(uint32_t stamp, void *packet, size_t bytes) = 0; - -private: - void init(); - //音视频时间戳同步用 - void stampSync(); - -private: - struct track_info { - int track_id = -1; - Stamp stamp; - }; - -private: - uint32_t _timestamp = 0; - BufferRaw::Ptr _buffer; - std::shared_ptr _muxer; - unordered_map _codec_to_trackid; - FrameMerger _frame_merger{FrameMerger::h264_prefix}; -}; - -class PSEncoderImp : public PSEncoder{ +class PSEncoderImp : public MpegMuxer{ public: PSEncoderImp(uint32_t ssrc, uint8_t payload_type = 96); ~PSEncoderImp() override; @@ -76,12 +30,13 @@ protected: virtual void onRTP(Buffer::Ptr rtp) = 0; protected: - void onPS(uint32_t stamp, void *packet, size_t bytes) override; + void onWrite(std::shared_ptr buffer, uint32_t stamp, bool key_pos) override; private: std::shared_ptr _rtp_encoder; }; }//namespace mediakit + #endif //ENABLE_RTPPROXY #endif //ZLMEDIAKIT_PSENCODER_H diff --git a/src/TS/TSMediaSourceMuxer.h b/src/TS/TSMediaSourceMuxer.h index 56aa9b42..edff41d6 100644 --- a/src/TS/TSMediaSourceMuxer.h +++ b/src/TS/TSMediaSourceMuxer.h @@ -12,18 +12,18 @@ #define ZLMEDIAKIT_TSMEDIASOURCEMUXER_H #include "TSMediaSource.h" -#include "Record/TsMuxer.h" +#include "Record/MPEG.h" namespace mediakit { -class TSMediaSourceMuxer : public TsMuxer, public MediaSourceEventInterceptor, +class TSMediaSourceMuxer : public MpegMuxer, public MediaSourceEventInterceptor, public std::enable_shared_from_this { public: using Ptr = std::shared_ptr; TSMediaSourceMuxer(const string &vhost, const string &app, - const string &stream_id) { + const string &stream_id) : MpegMuxer(false) { _media_src = std::make_shared(vhost, app, stream_id); } @@ -54,7 +54,7 @@ public: _media_src->clearCache(); } if (_enabled || !ts_demand) { - return TsMuxer::inputFrame(frame); + return MpegMuxer::inputFrame(frame); } return false; } @@ -66,13 +66,13 @@ public: } protected: - void onTs(std::shared_ptr buffer, uint32_t timestamp, bool is_idr_fast_packet) override { + void onWrite(std::shared_ptr buffer, uint32_t timestamp, bool key_pos) override { if (!buffer) { return; } auto packet = std::make_shared(std::move(buffer)); packet->time_stamp = timestamp; - _media_src->onWrite(std::move(packet), is_idr_fast_packet); + _media_src->onWrite(std::move(packet), key_pos); } private: