MPEG: 整合复用ts/ps生成代码

This commit is contained in:
ziyue 2021-12-28 21:04:53 +08:00
parent dce6b27f4f
commit 89870190e9
12 changed files with 425 additions and 481 deletions

View File

@ -187,10 +187,7 @@ endif ()
set(VS_FALGS "/wd4819") set(VS_FALGS "/wd4819")
#mpegts #mpegts
if (ENABLE_HLS) if (ENABLE_RTPPROXY OR ENABLE_HLS)
message(STATUS "ENABLE_HLS defined")
add_definitions(-DENABLE_HLS)
include_directories(${MediaServer_Root}/libmpeg/include) include_directories(${MediaServer_Root}/libmpeg/include)
aux_source_directory(${MediaServer_Root}/libmpeg/include src_mpeg) aux_source_directory(${MediaServer_Root}/libmpeg/include src_mpeg)
aux_source_directory(${MediaServer_Root}/libmpeg/source src_mpeg) aux_source_directory(${MediaServer_Root}/libmpeg/source src_mpeg)
@ -228,12 +225,16 @@ if (ENABLE_MP4)
endif () endif ()
endif () endif ()
#rtprtpps/ts if (ENABLE_RTPPROXY)
if (ENABLE_RTPPROXY AND ENABLE_HLS)
message(STATUS "ENABLE_RTPPROXY defined") message(STATUS "ENABLE_RTPPROXY defined")
add_definitions(-DENABLE_RTPPROXY) add_definitions(-DENABLE_RTPPROXY)
endif () 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) file(GLOB ToolKit_src_list ${ToolKit_Root}/*/*.cpp ${ToolKit_Root}/*/*.h ${ToolKit_Root}/*/*.c)
if (IOS) if (IOS)

View File

@ -16,6 +16,7 @@
#include "Util/onceToken.h" #include "Util/onceToken.h"
#include "Util/CMD.h" #include "Util/CMD.h"
#include "Network/TcpServer.h" #include "Network/TcpServer.h"
#include "Network/UdpServer.h"
#include "Poller/EventPoller.h" #include "Poller/EventPoller.h"
#include "Common/config.h" #include "Common/config.h"
#include "Rtsp/RtspSession.h" #include "Rtsp/RtspSession.h"

View File

@ -92,7 +92,7 @@ Frame::Ptr Frame::getCacheAbleFrame(const Frame::Ptr &frame){
TrackType getTrackType(CodecId codecId) { TrackType getTrackType(CodecId codecId) {
switch (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) CODEC_MAP(XX)
#undef XX #undef XX
default : return TrackInvalid; default : return TrackInvalid;
@ -101,14 +101,14 @@ TrackType getTrackType(CodecId codecId) {
const char *getCodecName(CodecId codec) { const char *getCodecName(CodecId codec) {
switch (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) CODEC_MAP(XX)
#undef XX #undef XX
default : return "invalid"; default : return "invalid";
} }
} }
#define XX(name, type, value, str) {str, name}, #define XX(name, type, value, str, mpeg_id) {str, name},
static map<string, CodecId, StrCaseCompare> codec_map = {CODEC_MAP(XX)}; static map<string, CodecId, StrCaseCompare> codec_map = {CODEC_MAP(XX)};
#undef XX #undef XX

View File

@ -31,20 +31,20 @@ typedef enum {
} TrackType; } TrackType;
#define CODEC_MAP(XX) \ #define CODEC_MAP(XX) \
XX(CodecH264, TrackVideo, 0, "H264") \ XX(CodecH264, TrackVideo, 0, "H264", PSI_STREAM_H264) \
XX(CodecH265, TrackVideo, 1, "H265") \ XX(CodecH265, TrackVideo, 1, "H265", PSI_STREAM_H265) \
XX(CodecAAC, TrackAudio, 2, "mpeg4-generic") \ XX(CodecAAC, TrackAudio, 2, "mpeg4-generic", PSI_STREAM_AAC) \
XX(CodecG711A, TrackAudio, 3, "PCMA") \ XX(CodecG711A, TrackAudio, 3, "PCMA", PSI_STREAM_AUDIO_G711A) \
XX(CodecG711U, TrackAudio, 4, "PCMU") \ XX(CodecG711U, TrackAudio, 4, "PCMU", PSI_STREAM_AUDIO_G711U) \
XX(CodecOpus, TrackAudio, 5, "opus") \ XX(CodecOpus, TrackAudio, 5, "opus", PSI_STREAM_AUDIO_OPUS) \
XX(CodecL16, TrackAudio, 6, "L16") \ XX(CodecL16, TrackAudio, 6, "L16", PSI_STREAM_RESERVED) \
XX(CodecVP8, TrackVideo, 7, "VP8") \ XX(CodecVP8, TrackVideo, 7, "VP8", PSI_STREAM_VP8) \
XX(CodecVP9, TrackVideo, 8, "VP9") \ XX(CodecVP9, TrackVideo, 8, "VP9", PSI_STREAM_VP9) \
XX(CodecAV1, TrackVideo, 9, "AV1X") XX(CodecAV1, TrackVideo, 9, "AV1X", PSI_STREAM_AV1)
typedef enum { typedef enum {
CodecInvalid = -1, CodecInvalid = -1,
#define XX(name, type, value, str) name = value, #define XX(name, type, value, str, mpeg_id) name = value,
CODEC_MAP(XX) CODEC_MAP(XX)
#undef XX #undef XX
CodecMax CodecMax

View File

@ -12,13 +12,15 @@
#define HLSRECORDER_H #define HLSRECORDER_H
#include "HlsMakerImp.h" #include "HlsMakerImp.h"
#include "TsMuxer.h" #include "MPEG.h"
namespace mediakit { namespace mediakit {
class HlsRecorder : public MediaSourceEventInterceptor, public TsMuxer, public std::enable_shared_from_this<HlsRecorder> { class HlsRecorder : public MediaSourceEventInterceptor, public MpegMuxer, public std::enable_shared_from_this<HlsRecorder> {
public: public:
typedef std::shared_ptr<HlsRecorder> Ptr; using Ptr = std::shared_ptr<HlsRecorder>;
HlsRecorder(const string &m3u8_file, const string &params){
HlsRecorder(const string &m3u8_file, const string &params) : MpegMuxer(false) {
GET_CONFIG(uint32_t, hlsNum, Hls::kSegmentNum); GET_CONFIG(uint32_t, hlsNum, Hls::kSegmentNum);
GET_CONFIG(uint32_t, hlsBufSize, Hls::kFileBufSize); GET_CONFIG(uint32_t, hlsBufSize, Hls::kFileBufSize);
GET_CONFIG(float, hlsDuration, Hls::kSegmentDuration); GET_CONFIG(float, hlsDuration, Hls::kSegmentDuration);
@ -27,7 +29,7 @@ public:
_hls->clearCache(); _hls->clearCache();
} }
~HlsRecorder(){} ~HlsRecorder() = default;
void setMediaSource(const string &vhost, const string &app, const string &stream_id) { void setMediaSource(const string &vhost, const string &app, const string &stream_id) {
_hls->setMediaSource(vhost, app, stream_id); _hls->setMediaSource(vhost, app, stream_id);
@ -68,17 +70,17 @@ public:
_hls->clearCache(); _hls->clearCache();
} }
if (_enabled || !hls_demand) { if (_enabled || !hls_demand) {
return TsMuxer::inputFrame(frame); return MpegMuxer::inputFrame(frame);
} }
return false; return false;
} }
private: private:
void onTs(std::shared_ptr<Buffer> buffer, uint32_t timestamp, bool is_idr_fast_packet) override { void onWrite(std::shared_ptr<Buffer> buffer, uint32_t timestamp, bool key_pos) override {
if (!buffer) { if (!buffer) {
_hls->inputData(nullptr, 0, timestamp, is_idr_fast_packet); _hls->inputData(nullptr, 0, timestamp, key_pos);
} else { } else {
_hls->inputData(buffer->data(), buffer->size(), timestamp, is_idr_fast_packet); _hls->inputData(buffer->data(), buffer->size(), timestamp, key_pos);
} }
} }

256
src/Record/MPEG.cpp Normal file
View File

@ -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 <cstdlib>
#include <assert.h>
#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<BufferLikeString>();
}
_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

114
src/Record/MPEG.h Normal file
View File

@ -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 <cstdio>
#include <cstdint>
#include <unordered_map>
#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> 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<int, int/*track_id*/> _codec_to_trackid;
FrameMerger _frame_merger{FrameMerger::h264_prefix};
std::shared_ptr<BufferLikeString> _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> buffer, uint32_t timestamp, bool key_pos) = 0;
};
}//namespace mediakit
#endif
#endif //ZLMEDIAKIT_MPEG_H

View File

@ -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<BufferLikeString>();
}
_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)

View File

@ -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 <unordered_map>
#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> 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<int, int/*track_id*/> _codec_to_trackid;
FrameMerger _frame_merger{FrameMerger::h264_prefix};
std::shared_ptr<BufferLikeString> _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> buffer, uint32_t timestamp,bool is_idr_fast_packet) = 0;
};
}//namespace mediakit
#endif// defined(ENABLE_HLS)
#endif //TSMUXER_H

View File

@ -9,148 +9,14 @@
*/ */
#if defined(ENABLE_RTPPROXY) #if defined(ENABLE_RTPPROXY)
#include "PSEncoder.h" #include "PSEncoder.h"
#include "Extension/H264.h" #include "Extension/H264.h"
#include "Rtsp/RtspMuxer.h" #include "Rtsp/RtspMuxer.h"
namespace mediakit{ namespace mediakit{
PSEncoder::PSEncoder() { PSEncoderImp::PSEncoderImp(uint32_t ssrc, uint8_t payload_type) : MpegMuxer(true) {
_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) {
GET_CONFIG(uint32_t,video_mtu,Rtp::kVideoMtuSize); GET_CONFIG(uint32_t,video_mtu,Rtp::kVideoMtuSize);
_rtp_encoder = std::make_shared<CommonRtpEncoder>(CodecInvalid, ssrc, video_mtu, 90000, payload_type, 0); _rtp_encoder = std::make_shared<CommonRtpEncoder>(CodecInvalid, ssrc, video_mtu, 90000, payload_type, 0);
_rtp_encoder->setRtpRing(std::make_shared<RtpRing::RingType>()); _rtp_encoder->setRtpRing(std::make_shared<RtpRing::RingType>());
@ -164,9 +30,13 @@ PSEncoderImp::~PSEncoderImp() {
InfoL << this << " " << printSSRC(_rtp_encoder->getSsrc()); InfoL << this << " " << printSSRC(_rtp_encoder->getSsrc());
} }
void PSEncoderImp::onPS(uint32_t stamp, void *packet, size_t bytes) { void PSEncoderImp::onWrite(std::shared_ptr<Buffer> buffer, uint32_t stamp, bool key_pos) {
_rtp_encoder->inputFrame(std::make_shared<FrameFromPtr>((char *) packet, bytes, stamp, stamp)); if (!buffer) {
return;
}
_rtp_encoder->inputFrame(std::make_shared<FrameFromPtr>(buffer->data(), buffer->size(), stamp, stamp));
} }
}//namespace mediakit }//namespace mediakit
#endif//defined(ENABLE_RTPPROXY) #endif//defined(ENABLE_RTPPROXY)

View File

@ -10,63 +10,17 @@
#ifndef ZLMEDIAKIT_PSENCODER_H #ifndef ZLMEDIAKIT_PSENCODER_H
#define ZLMEDIAKIT_PSENCODER_H #define ZLMEDIAKIT_PSENCODER_H
#if defined(ENABLE_RTPPROXY) #if defined(ENABLE_RTPPROXY)
#include "mpeg-ps.h"
#include "Record/MPEG.h"
#include "Common/MediaSink.h" #include "Common/MediaSink.h"
#include "Common/Stamp.h" #include "Common/Stamp.h"
#include "Extension/CommonRtp.h" #include "Extension/CommonRtp.h"
namespace mediakit{ namespace mediakit{
//该类实现mpeg-ps容器格式的打包 class PSEncoderImp : public MpegMuxer{
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<struct ps_muxer_t> _muxer;
unordered_map<int, track_info> _codec_to_trackid;
FrameMerger _frame_merger{FrameMerger::h264_prefix};
};
class PSEncoderImp : public PSEncoder{
public: public:
PSEncoderImp(uint32_t ssrc, uint8_t payload_type = 96); PSEncoderImp(uint32_t ssrc, uint8_t payload_type = 96);
~PSEncoderImp() override; ~PSEncoderImp() override;
@ -76,12 +30,13 @@ protected:
virtual void onRTP(Buffer::Ptr rtp) = 0; virtual void onRTP(Buffer::Ptr rtp) = 0;
protected: protected:
void onPS(uint32_t stamp, void *packet, size_t bytes) override; void onWrite(std::shared_ptr<Buffer> buffer, uint32_t stamp, bool key_pos) override;
private: private:
std::shared_ptr<CommonRtpEncoder> _rtp_encoder; std::shared_ptr<CommonRtpEncoder> _rtp_encoder;
}; };
}//namespace mediakit }//namespace mediakit
#endif //ENABLE_RTPPROXY #endif //ENABLE_RTPPROXY
#endif //ZLMEDIAKIT_PSENCODER_H #endif //ZLMEDIAKIT_PSENCODER_H

View File

@ -12,18 +12,18 @@
#define ZLMEDIAKIT_TSMEDIASOURCEMUXER_H #define ZLMEDIAKIT_TSMEDIASOURCEMUXER_H
#include "TSMediaSource.h" #include "TSMediaSource.h"
#include "Record/TsMuxer.h" #include "Record/MPEG.h"
namespace mediakit { namespace mediakit {
class TSMediaSourceMuxer : public TsMuxer, public MediaSourceEventInterceptor, class TSMediaSourceMuxer : 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>;
TSMediaSourceMuxer(const string &vhost, TSMediaSourceMuxer(const string &vhost,
const string &app, const string &app,
const string &stream_id) { const string &stream_id) : MpegMuxer(false) {
_media_src = std::make_shared<TSMediaSource>(vhost, app, stream_id); _media_src = std::make_shared<TSMediaSource>(vhost, app, stream_id);
} }
@ -54,7 +54,7 @@ public:
_media_src->clearCache(); _media_src->clearCache();
} }
if (_enabled || !ts_demand) { if (_enabled || !ts_demand) {
return TsMuxer::inputFrame(frame); return MpegMuxer::inputFrame(frame);
} }
return false; return false;
} }
@ -66,13 +66,13 @@ public:
} }
protected: protected:
void onTs(std::shared_ptr<Buffer> buffer, uint32_t timestamp, bool is_idr_fast_packet) override { void onWrite(std::shared_ptr<Buffer> buffer, uint32_t timestamp, bool key_pos) override {
if (!buffer) { if (!buffer) {
return; return;
} }
auto packet = std::make_shared<TSPacket>(std::move(buffer)); auto packet = std::make_shared<TSPacket>(std::move(buffer));
packet->time_stamp = timestamp; packet->time_stamp = timestamp;
_media_src->onWrite(std::move(packet), is_idr_fast_packet); _media_src->onWrite(std::move(packet), key_pos);
} }
private: private: