mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-22 10:40:05 +08:00
MPEG: 整合复用ts/ps生成代码
This commit is contained in:
parent
dce6b27f4f
commit
89870190e9
@ -187,10 +187,7 @@ endif ()
|
|||||||
set(VS_FALGS "/wd4819")
|
set(VS_FALGS "/wd4819")
|
||||||
|
|
||||||
#添加mpeg用于支持ts生成
|
#添加mpeg用于支持ts生成
|
||||||
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 ()
|
||||||
|
|
||||||
#添加rtp库用于rtp转ps/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)
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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 ¶ms){
|
|
||||||
|
HlsRecorder(const string &m3u8_file, const string ¶ms) : 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
256
src/Record/MPEG.cpp
Normal 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
114
src/Record/MPEG.h
Normal 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
|
@ -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)
|
|
@ -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
|
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user