release 8.0

This commit is contained in:
夏楚
2023-12-09 16:23:51 +08:00
committed by GitHub
parent 44c82752b3
commit bbe8f4a018
346 changed files with 2529 additions and 3435 deletions

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -205,39 +205,31 @@ public:
/**
* 构造函数
* @param aac_cfg aac两个字节的配置描述
* @param payload_type rtp payload type
* @param sample_rate 音频采样率
* @param payload_type rtp payload type 默认98
* @param channels 通道数
* @param bitrate 比特率
*/
AACSdp(const string &aac_cfg,
int sample_rate,
int channels,
int bitrate = 128,
int payload_type = 98) : Sdp(sample_rate,payload_type){
AACSdp(const string &aac_cfg, int payload_type, int sample_rate, int channels, int bitrate)
: Sdp(sample_rate, payload_type) {
_printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n";
if (bitrate) {
_printer << "b=AS:" << bitrate << "\r\n";
}
_printer << "a=rtpmap:" << payload_type << " " << getCodecName() << "/" << sample_rate << "/" << channels << "\r\n";
_printer << "a=rtpmap:" << payload_type << " " << getCodecName(CodecAAC) << "/" << sample_rate << "/" << channels << "\r\n";
string configStr;
char buf[4] = {0};
for(auto &ch : aac_cfg){
char buf[4] = { 0 };
for (auto &ch : aac_cfg) {
snprintf(buf, sizeof(buf), "%02X", (uint8_t)ch);
configStr.append(buf);
}
_printer << "a=fmtp:" << payload_type << " streamtype=5;profile-level-id=1;mode=AAC-hbr;"
<< "sizelength=13;indexlength=3;indexdeltalength=3;config=" << configStr << "\r\n";
_printer << "a=control:trackID=" << (int)TrackAudio << "\r\n";
}
string getSdp() const override {
return _printer;
}
string getSdp() const override { return _printer; }
CodecId getCodecId() const override {
return CodecAAC;
}
private:
_StrPrinter _printer;
};
@@ -249,18 +241,14 @@ AACTrack::AACTrack(const string &aac_cfg) {
throw std::invalid_argument("adts配置必须最少2个字节");
}
_cfg = aac_cfg;
onReady();
}
const string &AACTrack::getConfig() const {
return _cfg;
update();
}
CodecId AACTrack::getCodecId() const {
return CodecAAC;
}
bool AACTrack::ready() {
bool AACTrack::ready() const {
return !_cfg.empty();
}
@@ -276,9 +264,24 @@ int AACTrack::getAudioChannel() const {
return _channel;
}
static Frame::Ptr addADTSHeader(const Frame::Ptr &frame_in, const std::string &aac_config) {
auto frame = FrameImp::create();
frame->_codec_id = CodecAAC;
// 生成adts头
char adts_header[32] = { 0 };
auto size = dumpAacConfig(aac_config, frame_in->size(), (uint8_t *)adts_header, sizeof(adts_header));
CHECK(size > 0, "Invalid adts config");
frame->_prefix_size = size;
frame->_dts = frame_in->dts();
frame->_buffer.assign(adts_header, size);
frame->_buffer.append(frame_in->data(), frame_in->size());
return frame;
}
bool AACTrack::inputFrame(const Frame::Ptr &frame) {
if (!frame->prefixSize()) {
return inputFrame_l(frame);
CHECK(ready());
return inputFrame_l(addADTSHeader(frame, _cfg));
}
bool ret = false;
@@ -289,70 +292,68 @@ bool AACTrack::inputFrame(const Frame::Ptr &frame) {
auto ptr = frame->data();
auto end = frame->data() + frame->size();
while (ptr < end) {
auto frame_len = getAacFrameLength((uint8_t *) ptr, end - ptr);
auto frame_len = getAacFrameLength((uint8_t *)ptr, end - ptr);
if (frame_len < ADTS_HEADER_LEN) {
break;
}
if (frame_len == (int)frame->size()) {
return inputFrame_l(frame);
}
auto sub_frame = std::make_shared<FrameTSInternal<FrameFromPtr> >(frame, (char *) ptr, frame_len, ADTS_HEADER_LEN,dts,pts);
auto sub_frame = std::make_shared<FrameInternalBase<FrameFromPtr>>(frame, (char *)ptr, frame_len, dts, pts, ADTS_HEADER_LEN);
ptr += frame_len;
if (ptr > end) {
WarnL << "invalid aac length in adts header: " << frame_len
<< ", remain data size: " << end - (ptr - frame_len);
break;
}
sub_frame->setCodecId(CodecAAC);
if (inputFrame_l(sub_frame)) {
ret = true;
}
dts += 1024*1000/getAudioSampleRate();
pts += 1024*1000/getAudioSampleRate();
dts += 1024 * 1000 / getAudioSampleRate();
pts += 1024 * 1000 / getAudioSampleRate();
}
return ret;
}
bool AACTrack::inputFrame_l(const Frame::Ptr &frame) {
if (_cfg.empty()) {
//未获取到aac_cfg信息
if (frame->prefixSize()) {
//根据7个字节的adts头生成aac config
_cfg = makeAacConfig((uint8_t *) (frame->data()), frame->prefixSize());
onReady();
} else {
WarnL << "无法获取adts头!";
}
if (_cfg.empty() && frame->prefixSize()) {
// 未获取到aac_cfg信息根据7个字节的adts头生成aac config
_cfg = makeAacConfig((uint8_t *)(frame->data()), frame->prefixSize());
update();
}
if (frame->size() > frame->prefixSize()) {
//除adts头外有实际负载
// 除adts头外有实际负载
return AudioTrack::inputFrame(frame);
}
return false;
}
toolkit::Buffer::Ptr AACTrack::getExtraData() const {
CHECK(ready());
return std::make_shared<BufferString>(_cfg);
}
void AACTrack::setExtraData(const uint8_t *data, size_t size) {
CHECK(size >= 2);
_cfg.assign((char *)data, size);
update();
}
bool AACTrack::update() {
return parseAacConfig(_cfg, _sampleRate, _channel);
}
void AACTrack::onReady() {
if (!parseAacConfig(_cfg, _sampleRate, _channel)) {
_cfg.clear();
}
Track::Ptr AACTrack::clone() const {
return std::make_shared<AACTrack>(*this);
}
Track::Ptr AACTrack::clone() {
return std::make_shared<std::remove_reference<decltype(*this)>::type>(*this);
}
Sdp::Ptr AACTrack::getSdp() {
if(!ready()){
Sdp::Ptr AACTrack::getSdp(uint8_t payload_type) const {
if (!ready()) {
WarnL << getCodecName() << " Track未准备好";
return nullptr;
}
update();
return std::make_shared<AACSdp>(getConfig(), getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024);
return std::make_shared<AACSdp>(getExtraData()->toString(), payload_type, getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024);
}
}//namespace mediakit

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -17,47 +17,33 @@
namespace mediakit{
std::string makeAacConfig(const uint8_t *hex, size_t length);
int getAacFrameLength(const uint8_t *hex, size_t length);
int dumpAacConfig(const std::string &config, size_t length, uint8_t *out, size_t out_size);
bool parseAacConfig(const std::string &config, int &samplerate, int &channels);
/**
* aac音频通道
*/
class AACTrack : public AudioTrack{
class AACTrack : public AudioTrack {
public:
using Ptr = std::shared_ptr<AACTrack>;
/**
* 延后获取adts头信息
* 在随后的inputFrame中获取adts头信息
*/
AACTrack() = default;
/**
* 构造aac类型的媒体
* @param aac_cfg aac配置信息
* 通过aac extra data 构造对象
*/
AACTrack(const std::string &aac_cfg);
/**
* 获取aac 配置信息
*/
const std::string &getConfig() const;
bool ready() override;
bool ready() const override;
CodecId getCodecId() const override;
int getAudioChannel() const override;
int getAudioSampleRate() const override;
int getAudioSampleBit() const override;
bool inputFrame(const Frame::Ptr &frame) override;
toolkit::Buffer::Ptr getExtraData() const override;
void setExtraData(const uint8_t *data, size_t size) override;
bool update() override;
private:
void onReady();
Sdp::Ptr getSdp() override;
Track::Ptr clone() override;
Sdp::Ptr getSdp(uint8_t payload_type) const override;
Track::Ptr clone() const override;
bool inputFrame_l(const Frame::Ptr &frame);
private:

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -16,90 +16,18 @@ using namespace toolkit;
namespace mediakit {
static string getConfig(const RtmpPacket &thiz) {
string ret;
if ((RtmpAudioCodec)thiz.getRtmpCodecId() != RtmpAudioCodec::aac) {
return ret;
}
if (thiz.buffer.size() < 4) {
WarnL << "get aac config failed, rtmp packet is: " << hexdump(thiz.data(), thiz.size());
return ret;
}
ret = thiz.buffer.substr(2);
return ret;
}
void AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) {
CHECK(pkt->size() > 2);
if (pkt->isConfigFrame()) {
_aac_cfg = getConfig(*pkt);
if (!_aac_cfg.empty()) {
onGetAAC(nullptr, 0, 0);
}
getTrack()->setExtraData((uint8_t *)pkt->data() + 2, pkt->size() - 2);
return;
}
if (!_aac_cfg.empty()) {
onGetAAC(pkt->buffer.data() + 2, pkt->buffer.size() - 2, pkt->time_stamp);
}
}
void AACRtmpDecoder::onGetAAC(const char* data, size_t len, uint32_t stamp) {
auto frame = FrameImp::create();
frame->_codec_id = CodecAAC;
//生成adts头
char adts_header[32] = {0};
auto size = dumpAacConfig(_aac_cfg, len, (uint8_t *) adts_header, sizeof(adts_header));
if (size > 0) {
frame->_buffer.assign(adts_header, size);
frame->_prefix_size = size;
} else {
frame->_buffer.clear();
frame->_prefix_size = 0;
}
if(len > 0){
//追加负载数据
frame->_buffer.append(data, len);
frame->_dts = stamp;
}
if(size > 0 || len > 0){
//有adts头或者实际aac负载
RtmpCodec::inputFrame(frame);
}
RtmpCodec::inputFrame(std::make_shared<FrameFromPtr>(CodecAAC, pkt->buffer.data() + 2, pkt->buffer.size() - 2, pkt->time_stamp));
}
/////////////////////////////////////////////////////////////////////////////////////
AACRtmpEncoder::AACRtmpEncoder(const Track::Ptr &track) {
_track = dynamic_pointer_cast<AACTrack>(track);
}
void AACRtmpEncoder::makeConfigPacket() {
if (_track && _track->ready()) {
//从track中和获取aac配置信息
_aac_cfg = _track->getConfig();
}
if (!_aac_cfg.empty()) {
makeAudioConfigPkt();
}
}
bool AACRtmpEncoder::inputFrame(const Frame::Ptr &frame) {
if (_aac_cfg.empty()) {
if (frame->prefixSize()) {
// 包含adts头,从adts头获取aac配置信息
_aac_cfg = makeAacConfig((uint8_t *)(frame->data()), frame->prefixSize());
}
makeConfigPacket();
}
if (_aac_cfg.empty()) {
return false;
}
auto pkt = RtmpPacket::create();
// header
pkt->buffer.push_back(_audio_flv_flags);
@@ -115,14 +43,18 @@ bool AACRtmpEncoder::inputFrame(const Frame::Ptr &frame) {
return true;
}
void AACRtmpEncoder::makeAudioConfigPkt() {
_audio_flv_flags = getAudioRtmpFlags(std::make_shared<AACTrack>(_aac_cfg));
void AACRtmpEncoder::makeConfigPacket() {
_audio_flv_flags = getAudioRtmpFlags(getTrack());
auto pkt = RtmpPacket::create();
// header
pkt->buffer.push_back(_audio_flv_flags);
pkt->buffer.push_back((uint8_t)RtmpAACPacketType::aac_config_header);
// aac config
pkt->buffer.append(_aac_cfg);
auto extra_data = getTrack()->getExtraData();
CHECK(extra_data);
pkt->buffer.append(extra_data->data(), extra_data->size());
pkt->body_size = pkt->buffer.size();
pkt->chunk_id = CHUNK_AUDIO;
pkt->stream_index = STREAM_MEDIA;

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -19,35 +19,23 @@ namespace mediakit{
/**
* aac Rtmp转adts类
*/
class AACRtmpDecoder : public RtmpCodec{
class AACRtmpDecoder : public RtmpCodec {
public:
using Ptr = std::shared_ptr<AACRtmpDecoder>;
AACRtmpDecoder() {}
~AACRtmpDecoder() {}
AACRtmpDecoder(const Track::Ptr &track) : RtmpCodec(track) {}
/**
* 输入Rtmp并解码
* @param rtmp Rtmp数据包
*/
void inputRtmp(const RtmpPacket::Ptr &rtmp) override;
CodecId getCodecId() const override{
return CodecAAC;
}
private:
void onGetAAC(const char *data, size_t len, uint32_t stamp);
private:
std::string _aac_cfg;
};
/**
* aac adts转Rtmp类
*/
class AACRtmpEncoder : public AACRtmpDecoder{
class AACRtmpEncoder : public RtmpCodec {
public:
using Ptr = std::shared_ptr<AACRtmpEncoder>;
@@ -57,8 +45,7 @@ public:
* 那么inputFrame时可以不输入adts头
* @param track
*/
AACRtmpEncoder(const Track::Ptr &track);
~AACRtmpEncoder() {}
AACRtmpEncoder(const Track::Ptr &track) : RtmpCodec(track) {}
/**
* 输入aac 数据可以不带adts头
@@ -72,12 +59,7 @@ public:
void makeConfigPacket() override;
private:
void makeAudioConfigPkt();
private:
uint8_t _audio_flv_flags;
AACTrack::Ptr _track;
std::string _aac_cfg;
uint8_t _audio_flv_flags {0};
};
}//namespace mediakit

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -12,63 +12,36 @@
namespace mediakit{
AACRtpEncoder::AACRtpEncoder(uint32_t ui32Ssrc,
uint32_t ui32MtuSize,
uint32_t ui32SampleRate,
uint8_t ui8PayloadType,
uint8_t ui8Interleaved) :
RtpInfo(ui32Ssrc,
ui32MtuSize,
ui32SampleRate,
ui8PayloadType,
ui8Interleaved){
}
bool AACRtpEncoder::inputFrame(const Frame::Ptr &frame) {
auto stamp = frame->dts();
auto data = frame->data() + frame->prefixSize();
auto len = frame->size() - frame->prefixSize();
auto ptr = (char *) data;
auto remain_size = len;
auto max_size = getMaxSize() - 4;
auto ptr = (char *)frame->data() + frame->prefixSize();
auto size = frame->size() - frame->prefixSize();
auto remain_size = size;
auto max_size = getRtpInfo().getMaxSize() - 4;
while (remain_size > 0) {
if (remain_size <= max_size) {
_section_buf[0] = 0;
_section_buf[1] = 16;
_section_buf[2] = (len >> 5) & 0xFF;
_section_buf[3] = ((len & 0x1F) << 3) & 0xFF;
memcpy(_section_buf + 4, ptr, remain_size);
makeAACRtp(_section_buf, remain_size + 4, true, stamp);
outputRtp(ptr, remain_size, size, true, frame->dts());
break;
}
_section_buf[0] = 0;
_section_buf[1] = 16;
_section_buf[2] = ((len) >> 5) & 0xFF;
_section_buf[3] = ((len & 0x1F) << 3) & 0xFF;
memcpy(_section_buf + 4, ptr, max_size);
makeAACRtp(_section_buf, max_size + 4, false, stamp);
outputRtp(ptr, max_size, size, false, frame->dts());
ptr += max_size;
remain_size -= max_size;
}
return len > 0;
return true;
}
void AACRtpEncoder::makeAACRtp(const void *data, size_t len, bool mark, uint64_t stamp) {
RtpCodec::inputRtp(makeRtp(getTrackType(), data, len, mark, stamp), false);
void AACRtpEncoder::outputRtp(const char *data, size_t len, size_t total_len, bool mark, uint64_t stamp) {
auto rtp = getRtpInfo().makeRtp(TrackAudio, nullptr, len + 4, mark, stamp);
auto payload = rtp->data() + RtpPacket::kRtpTcpHeaderSize + RtpPacket::kRtpHeaderSize;
payload[0] = 0;
payload[1] = 16;
payload[2] = ((total_len) >> 5) & 0xFF;
payload[3] = ((total_len & 0x1F) << 3) & 0xFF;
memcpy(payload + 4, data, len);
RtpCodec::inputRtp(std::move(rtp), false);
}
/////////////////////////////////////////////////////////////////////////////////////
AACRtpDecoder::AACRtpDecoder(const Track::Ptr &track) {
auto aacTrack = std::dynamic_pointer_cast<AACTrack>(track);
if (!aacTrack || !aacTrack->ready()) {
WarnL << "该aac track无效!";
} else {
_aac_cfg = aacTrack->getConfig();
}
obtainFrame();
}
AACRtpDecoder::AACRtpDecoder() {
obtainFrame();
}
@@ -145,17 +118,8 @@ bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) {
void AACRtpDecoder::flushData() {
auto ptr = reinterpret_cast<const uint8_t *>(_frame->data());
if ((ptr[0] == 0xFF && (ptr[1] & 0xF0) == 0xF0) && _frame->size() > ADTS_HEADER_LEN) {
//adts头打入了rtp包不符合规范兼容EasyPusher的bug
// adts头打入了rtp包不符合规范兼容EasyPusher的bug
_frame->_prefix_size = ADTS_HEADER_LEN;
} else {
//没有adts头则插入adts头
char adts_header[128] = {0};
auto size = dumpAacConfig(_aac_cfg, _frame->_buffer.size(), (uint8_t *) adts_header, sizeof(adts_header));
if (size > 0) {
//插入adts头
_frame->_buffer.insert(0, adts_header, size);
_frame->_prefix_size = size;
}
}
RtpCodec::inputFrame(_frame);
obtainFrame();

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -21,8 +21,7 @@ class AACRtpDecoder : public RtpCodec {
public:
using Ptr = std::shared_ptr<AACRtpDecoder>;
AACRtpDecoder(const Track::Ptr &track);
~AACRtpDecoder() {}
AACRtpDecoder();
/**
* 输入rtp并解码
@@ -31,20 +30,12 @@ public:
*/
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = false) override;
CodecId getCodecId() const override {
return CodecAAC;
}
protected:
AACRtpDecoder();
private:
void obtainFrame();
void flushData();
private:
uint64_t _last_dts = 0;
std::string _aac_cfg;
FrameImp::Ptr _frame;
};
@@ -52,24 +43,10 @@ private:
/**
* aac adts转rtp类
*/
class AACRtpEncoder : public AACRtpDecoder , public RtpInfo {
class AACRtpEncoder : public RtpCodec {
public:
using Ptr = std::shared_ptr<AACRtpEncoder>;
/**
* @param ui32Ssrc ssrc
* @param ui32MtuSize mtu 大小
* @param ui32SampleRate 采样率
* @param ui8PayloadType pt类型
* @param ui8Interleaved rtsp interleaved 值
*/
AACRtpEncoder(uint32_t ui32Ssrc,
uint32_t ui32MtuSize,
uint32_t ui32SampleRate,
uint8_t ui8PayloadType = 97,
uint8_t ui8Interleaved = TrackAudio * 2);
~AACRtpEncoder() {}
/**
* 输入aac 数据必须带dats头
* @param frame 带dats头的aac数据
@@ -77,10 +54,8 @@ public:
bool inputFrame(const Frame::Ptr &frame) override;
private:
void makeAACRtp(const void *data, size_t len, bool mark, uint64_t stamp);
void outputRtp(const char *data, size_t len, size_t total_len, bool mark, uint64_t stamp);
private:
unsigned char _section_buf[1600];
};
}//namespace mediakit

View File

@@ -1,55 +1,35 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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 "CommonRtmp.h"
namespace mediakit{
CommonRtmpDecoder::CommonRtmpDecoder(CodecId codec) {
_codec = codec;
obtainFrame();
}
CodecId CommonRtmpDecoder::getCodecId() const {
return _codec;
}
void CommonRtmpDecoder::obtainFrame() {
_frame = FrameImp::create();
_frame->_codec_id = _codec;
}
namespace mediakit {
void CommonRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &rtmp) {
//拷贝负载
_frame->_buffer.assign(rtmp->buffer.data() + 1, rtmp->buffer.size() - 1);
_frame->_dts = rtmp->time_stamp;
//写入环形缓存
RtmpCodec::inputFrame(_frame);
//创建下一帧
obtainFrame();
auto frame = FrameImp::create();
frame->_codec_id = getTrack()->getCodecId();
frame->_buffer.assign(rtmp->buffer.data() + 1, rtmp->buffer.size() - 1);
frame->_dts = rtmp->time_stamp;
RtmpCodec::inputFrame(frame);
}
/////////////////////////////////////////////////////////////////////////////////////
CommonRtmpEncoder::CommonRtmpEncoder(const Track::Ptr &track) : CommonRtmpDecoder(track->getCodecId()) {
_audio_flv_flags = getAudioRtmpFlags(track);
}
bool CommonRtmpEncoder::inputFrame(const Frame::Ptr &frame) {
if (!_audio_flv_flags) {
return false;
_audio_flv_flags = getAudioRtmpFlags(getTrack());
}
auto rtmp = RtmpPacket::create();
//header
// header
rtmp->buffer.push_back(_audio_flv_flags);
//data
// data
rtmp->buffer.append(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize());
rtmp->body_size = rtmp->buffer.size();
rtmp->chunk_id = CHUNK_AUDIO;

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -23,42 +23,26 @@ class CommonRtmpDecoder : public RtmpCodec {
public:
using Ptr = std::shared_ptr<CommonRtmpDecoder>;
~CommonRtmpDecoder() override {}
/**
* 构造函数
* @param codec 编码id
*/
CommonRtmpDecoder(CodecId codec);
/**
* 返回编码类型ID
*/
CodecId getCodecId() const override;
CommonRtmpDecoder(const Track::Ptr &track) : RtmpCodec(track) {}
/**
* 输入Rtmp并解码
* @param rtmp Rtmp数据包
*/
void inputRtmp(const RtmpPacket::Ptr &rtmp) override;
private:
void obtainFrame();
private:
CodecId _codec;
FrameImp::Ptr _frame;
};
/**
* 通用 rtmp编码类
*/
class CommonRtmpEncoder : public CommonRtmpDecoder {
class CommonRtmpEncoder : public RtmpCodec {
public:
using Ptr = std::shared_ptr<CommonRtmpEncoder>;
CommonRtmpEncoder(const Track::Ptr &track);
~CommonRtmpEncoder() override{}
CommonRtmpEncoder(const Track::Ptr &track) : RtmpCodec(track) {}
/**
* 输入帧数据
@@ -66,7 +50,7 @@ public:
bool inputFrame(const Frame::Ptr &frame) override;
private:
uint8_t _audio_flv_flags = 0;
uint8_t _audio_flv_flags { 0 };
};
}//namespace mediakit

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -18,10 +18,6 @@ CommonRtpDecoder::CommonRtpDecoder(CodecId codec, size_t max_frame_size ){
obtainFrame();
}
CodecId CommonRtpDecoder::getCodecId() const {
return _codec;
}
void CommonRtpDecoder::obtainFrame() {
_frame = FrameImp::create();
_frame->_codec_id = _codec;
@@ -66,17 +62,12 @@ bool CommonRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool){
////////////////////////////////////////////////////////////////
CommonRtpEncoder::CommonRtpEncoder(CodecId codec, uint32_t ssrc, uint32_t mtu_size,
uint32_t sample_rate, uint8_t payload_type, uint8_t interleaved)
: CommonRtpDecoder(codec), RtpInfo(ssrc, mtu_size, sample_rate, payload_type, interleaved) {
}
bool CommonRtpEncoder::inputFrame(const Frame::Ptr &frame){
auto stamp = frame->pts();
auto ptr = frame->data() + frame->prefixSize();
auto len = frame->size() - frame->prefixSize();
auto remain_size = len;
auto max_size = getMaxSize();
auto max_size = getRtpInfo().getMaxSize();
bool is_key = frame->keyFrame();
bool mark = false;
while (remain_size > 0) {
@@ -87,7 +78,7 @@ bool CommonRtpEncoder::inputFrame(const Frame::Ptr &frame){
rtp_size = remain_size;
mark = true;
}
RtpCodec::inputRtp(makeRtp(getTrackType(), ptr, rtp_size, mark, stamp), is_key);
RtpCodec::inputRtp(getRtpInfo().makeRtp(frame->getTrackType(), ptr, rtp_size, mark, stamp), is_key);
ptr += rtp_size;
remain_size -= rtp_size;
is_key = false;

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -23,8 +23,6 @@ class CommonRtpDecoder : public RtpCodec {
public:
using Ptr = std::shared_ptr <CommonRtpDecoder>;
~CommonRtpDecoder() override {}
/**
* 构造函数
* @param codec 编码id
@@ -32,11 +30,6 @@ public:
*/
CommonRtpDecoder(CodecId codec, size_t max_frame_size = 2 * 1024);
/**
* 返回编码类型ID
*/
CodecId getCodecId() const override;
/**
* 输入rtp并解码
* @param rtp rtp数据包
@@ -59,23 +52,10 @@ private:
/**
* 通用 rtp编码类
*/
class CommonRtpEncoder : public CommonRtpDecoder, public RtpInfo {
class CommonRtpEncoder : public RtpCodec {
public:
using Ptr = std::shared_ptr <CommonRtpEncoder>;
~CommonRtpEncoder() override {}
/**
* 构造函数
* @param codec 编码类型
* @param ssrc ssrc
* @param mtu_size mtu 大小
* @param sample_rate 采样率
* @param payload_type pt类型
* @param interleaved rtsp interleaved 值
*/
CommonRtpEncoder(CodecId codec, uint32_t ssrc, uint32_t mtu_size, uint32_t sample_rate, uint8_t payload_type, uint8_t interleaved);
/**
* 输入帧数据并编码成rtp
*/

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -29,6 +29,7 @@
#include "Common/config.h"
using namespace std;
using namespace toolkit;
namespace mediakit{
@@ -91,9 +92,7 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) {
return std::make_shared<H265Track>(vps, sps, pps, 0, 0, 0);
}
case CodecJPEG : {
return std::make_shared<JPEGTrack>();
}
case CodecJPEG : return std::make_shared<JPEGTrack>();
default: {
//其他codec不支持
@@ -129,53 +128,30 @@ Track::Ptr Factory::getTrackByAbstractTrack(const Track::Ptr& track) {
}
}
RtpCodec::Ptr Factory::getRtpEncoderByCodecId(CodecId codec_id, uint32_t sample_rate, uint8_t pt, uint32_t ssrc) {
GET_CONFIG(uint32_t, audio_mtu, Rtp::kAudioMtuSize);
GET_CONFIG(uint32_t, video_mtu, Rtp::kVideoMtuSize);
auto type = getTrackType(codec_id);
auto mtu = type == TrackVideo ? video_mtu : audio_mtu;
auto interleaved = type * 2;
RtpCodec::Ptr Factory::getRtpEncoderByCodecId(CodecId codec_id, uint8_t pt) {
switch (codec_id) {
case CodecH264: return std::make_shared<H264RtpEncoder>(ssrc, mtu, sample_rate, pt, interleaved);
case CodecH265: return std::make_shared<H265RtpEncoder>(ssrc, mtu, sample_rate, pt, interleaved);
case CodecAAC: return std::make_shared<AACRtpEncoder>(ssrc, mtu, sample_rate, pt, interleaved);
case CodecH264: return std::make_shared<H264RtpEncoder>();
case CodecH265: return std::make_shared<H265RtpEncoder>();
case CodecAAC: return std::make_shared<AACRtpEncoder>();
case CodecL16:
case CodecOpus: return std::make_shared<CommonRtpEncoder>(codec_id, ssrc, mtu, sample_rate, pt, interleaved);
case CodecOpus: return std::make_shared<CommonRtpEncoder>();
case CodecG711A:
case CodecG711U: {
if (pt == Rtsp::PT_PCMA || pt == Rtsp::PT_PCMU) {
return std::make_shared<G711RtpEncoder>(codec_id, ssrc, mtu, sample_rate, pt, interleaved, 1);
return std::make_shared<G711RtpEncoder>(codec_id, 1);
}
return std::make_shared<CommonRtpEncoder>(codec_id, ssrc, mtu, sample_rate, pt, interleaved);
return std::make_shared<CommonRtpEncoder>();
}
case CodecJPEG: return std::make_shared<JPEGRtpEncoder>(ssrc, mtu, sample_rate, pt, interleaved);
case CodecJPEG: return std::make_shared<JPEGRtpEncoder>();
default: WarnL << "暂不支持该CodecId:" << codec_id; return nullptr;
}
}
RtpCodec::Ptr Factory::getRtpEncoderBySdp(const Sdp::Ptr &sdp) {
// ssrc不冲突即可,可以为任意的32位整形
static atomic<uint32_t> s_ssrc(0);
uint32_t ssrc = s_ssrc++;
if (!ssrc) {
// ssrc不能为0
ssrc = s_ssrc++;
}
if (sdp->getTrackType() == TrackVideo) {
//视频的ssrc是偶数方便调试
ssrc = 2 * ssrc;
} else {
//音频ssrc是奇数
ssrc = 2 * ssrc + 1;
}
return getRtpEncoderByCodecId(sdp->getCodecId(), sdp->getSampleRate(), sdp->getPayloadType(), ssrc);
}
RtpCodec::Ptr Factory::getRtpDecoderByTrack(const Track::Ptr &track) {
switch (track->getCodecId()){
case CodecH264 : return std::make_shared<H264RtpDecoder>();
case CodecH265 : return std::make_shared<H265RtpDecoder>();
case CodecAAC : return std::make_shared<AACRtpDecoder>(track->clone());
case CodecAAC : return std::make_shared<AACRtpDecoder>();
case CodecL16 :
case CodecOpus :
case CodecG711A :
@@ -267,7 +243,19 @@ Track::Ptr Factory::getAudioTrackByAmf(const AMFValue& amf, int sample_rate, int
return getTrackByCodecId(codecId, sample_rate, channels, sample_bit);
}
RtmpCodec::Ptr Factory::getRtmpCodecByTrack(const Track::Ptr &track, bool is_encode) {
RtmpCodec::Ptr Factory::getRtmpDecoderByTrack(const Track::Ptr &track) {
switch (track->getCodecId()){
case CodecH264 : return std::make_shared<H264RtmpDecoder>(track);
case CodecAAC : return std::make_shared<AACRtmpDecoder>(track);
case CodecH265 : return std::make_shared<H265RtmpDecoder>(track);
case CodecOpus :
case CodecG711A :
case CodecG711U : return std::make_shared<CommonRtmpDecoder>(track);
default : WarnL << "暂不支持该CodecId:" << track->getCodecName(); return nullptr;
}
}
RtmpCodec::Ptr Factory::getRtmpEncoderByTrack(const Track::Ptr &track) {
switch (track->getCodecId()){
case CodecH264 : return std::make_shared<H264RtmpEncoder>(track);
case CodecAAC : return std::make_shared<AACRtmpEncoder>(track);
@@ -276,9 +264,7 @@ RtmpCodec::Ptr Factory::getRtmpCodecByTrack(const Track::Ptr &track, bool is_enc
case CodecG711A :
case CodecG711U : {
auto audio_track = dynamic_pointer_cast<AudioTrack>(track);
if (is_encode && (audio_track->getAudioSampleRate() != 8000 ||
audio_track->getAudioChannel() != 1 ||
audio_track->getAudioSampleBit() != 16)) {
if (audio_track->getAudioSampleRate() != 8000 || audio_track->getAudioChannel() != 1 || audio_track->getAudioSampleBit() != 16) {
//rtmp对g711只支持8000/1/16规格但是ZLMediaKit可以解析其他规格的G711
WarnL << "RTMP只支持8000/1/16规格的G711,目前规格是:"
<< audio_track->getAudioSampleRate() << "/"
@@ -294,16 +280,46 @@ RtmpCodec::Ptr Factory::getRtmpCodecByTrack(const Track::Ptr &track, bool is_enc
}
AMFValue Factory::getAmfByCodecId(CodecId codecId) {
GET_CONFIG(bool, enhanced, Rtmp::kEnhanced);
switch (codecId) {
case CodecAAC: return AMFValue((int)RtmpAudioCodec::aac);
case CodecH264: return AMFValue((int)RtmpVideoCodec::h264);
case CodecH265: return AMFValue((int)RtmpVideoCodec::h265);
case CodecH265: return enhanced ? AMFValue((int)RtmpVideoCodec::fourcc_hevc) : AMFValue((int)RtmpVideoCodec::h265);
case CodecG711A: return AMFValue((int)RtmpAudioCodec::g711a);
case CodecG711U: return AMFValue((int)RtmpAudioCodec::g711u);
case CodecOpus: return AMFValue((int)RtmpAudioCodec::opus);
case CodecAV1: return AMFValue((int)RtmpVideoCodec::fourcc_av1);
case CodecVP9: return AMFValue((int)RtmpVideoCodec::fourcc_vp9);
default: return AMFValue(AMF_NULL);
}
}
static size_t aacPrefixSize(const char *data, size_t bytes) {
uint8_t *ptr = (uint8_t *)data;
size_t prefix = 0;
if (!(bytes > ADTS_HEADER_LEN && ptr[0] == 0xFF && (ptr[1] & 0xF0) == 0xF0)) {
return 0;
}
return ADTS_HEADER_LEN;
}
Frame::Ptr Factory::getFrameFromPtr(CodecId codec, const char *data, size_t bytes, uint64_t dts, uint64_t pts) {
switch (codec) {
case CodecH264: return std::make_shared<H264FrameNoCacheAble>((char *)data, bytes, dts, pts, prefixSize(data, bytes));
case CodecH265: return std::make_shared<H265FrameNoCacheAble>((char *)data, bytes, dts, pts, prefixSize(data, bytes));
case CodecJPEG: return std::make_shared<JPEGFrame<FrameFromPtr>>(0, codec, (char *)data, bytes, dts, pts);
case CodecAAC: return std::make_shared<FrameFromPtr>(codec, (char *)data, bytes, dts, pts, aacPrefixSize(data, bytes));
case CodecOpus:
case CodecG711A:
case CodecG711U: return std::make_shared<FrameFromPtr>(codec, (char *)data, bytes, dts, pts);
default: return nullptr;
}
}
Frame::Ptr Factory::getFrameFromBuffer(CodecId codec, Buffer::Ptr data, uint64_t dts, uint64_t pts) {
auto frame = Factory::getFrameFromPtr(codec, data->data(), data->size(), dts, pts);
return std::make_shared<FrameCacheAble>(frame, false, std::move(data));
}
}//namespace mediakit

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -14,6 +14,7 @@
#include <string>
#include "Rtmp/amf.h"
#include "Extension/Track.h"
#include "Extension/Frame.h"
#include "Rtsp/RtpCodec.h"
#include "Rtmp/RtmpCodec.h"
@@ -42,20 +43,12 @@ public:
*/
static Track::Ptr getTrackByAbstractTrack(const Track::Ptr& track);
/**
* 根据sdp生成rtp编码器
* @param sdp sdp对象
*/
static RtpCodec::Ptr getRtpEncoderBySdp(const Sdp::Ptr &sdp);
/**
* 根据codec id生成rtp编码器
* @param codec_id 编码id
* @param sample_rate 采样率视频固定为90000
* @param pt rtp payload type
* @param ssrc rtp ssrc
*/
static RtpCodec::Ptr getRtpEncoderByCodecId(CodecId codec_id, uint32_t sample_rate, uint8_t pt, uint32_t ssrc);
static RtpCodec::Ptr getRtpEncoderByCodecId(CodecId codec_id, uint8_t pt);
/**
* 根据Track生成Rtp解包器
@@ -78,16 +71,24 @@ public:
static Track::Ptr getAudioTrackByAmf(const AMFValue& amf, int sample_rate, int channels, int sample_bit);
/**
* 根据Track获取Rtmp的编码器
* 根据Track获取Rtmp的编码器
* @param track 媒体描述对象
* @param is_encode 是否为编码器还是解码器
*/
static RtmpCodec::Ptr getRtmpCodecByTrack(const Track::Ptr &track, bool is_encode);
static RtmpCodec::Ptr getRtmpEncoderByTrack(const Track::Ptr &track);
/**
* 根据Track获取Rtmp的解码器
* @param track 媒体描述对象
*/
static RtmpCodec::Ptr getRtmpDecoderByTrack(const Track::Ptr &track);
/**
* 根据codecId获取rtmp的codec描述
*/
static AMFValue getAmfByCodecId(CodecId codecId);
static Frame::Ptr getFrameFromPtr(CodecId codec, const char *data, size_t size, uint64_t dts, uint64_t pts);
static Frame::Ptr getFrameFromBuffer(CodecId codec, toolkit::Buffer::Ptr data, uint64_t dts, uint64_t pts);
};
}//namespace mediakit

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -15,6 +15,14 @@
#include "Common/Stamp.h"
#include "Common/MediaSource.h"
#if defined(ENABLE_MP4)
#include "mov-format.h"
#endif
#if defined(ENABLE_HLS) || defined(ENABLE_RTPPROXY)
#include "mpeg-proto.h"
#endif
using namespace std;
using namespace toolkit;
@@ -41,24 +49,73 @@ FrameStamp::FrameStamp(Frame::Ptr frame, Stamp &stamp, int modify_stamp)
TrackType getTrackType(CodecId codecId) {
switch (codecId) {
#define XX(name, type, value, str, mpeg_id) case name : return type;
#define XX(name, type, value, str, mpeg_id, mp4_id) case name : return type;
CODEC_MAP(XX)
#undef XX
default : return TrackInvalid;
}
}
#if defined(ENABLE_MP4)
int getMovIdByCodec(CodecId codecId) {
switch (codecId) {
#define XX(name, type, value, str, mpeg_id, mp4_id) case name : return mp4_id;
CODEC_MAP(XX)
#undef XX
default : return MOV_OBJECT_NONE;
}
}
CodecId getCodecByMovId(int object_id) {
if (object_id == MOV_OBJECT_NONE) {
return CodecInvalid;
}
switch (object_id) {
#define XX(name, type, value, str, mpeg_id, mp4_id) case mp4_id : return name;
CODEC_MAP(XX)
#undef XX
default : WarnL << "Unsupported mov: " << object_id; return CodecInvalid;
}
}
#endif
#if defined(ENABLE_HLS) || defined(ENABLE_RTPPROXY)
int getMpegIdByCodec(CodecId codec) {
switch (codec) {
#define XX(name, type, value, str, mpeg_id, mp4_id) case name : return mpeg_id;
CODEC_MAP(XX)
#undef XX
default : return PSI_STREAM_RESERVED;
}
}
CodecId getCodecByMpegId(int mpeg_id) {
if (mpeg_id == PSI_STREAM_RESERVED) {
return CodecInvalid;
}
switch (mpeg_id) {
#define XX(name, type, value, str, mpeg_id, mp4_id) case mpeg_id : return name;
CODEC_MAP(XX)
#undef XX
// 海康的 PS 流中会有0xBD 的包
case 0xBD: return CodecInvalid;
default : WarnL << "Unsupported mpeg: " << mpeg_id; return CodecInvalid;
}
}
#endif
const char *getCodecName(CodecId codec) {
switch (codec) {
#define XX(name, type, value, str, mpeg_id) case name : return str;
#define XX(name, type, value, str, mpeg_id, mp4_id) case name : return str;
CODEC_MAP(XX)
#undef XX
default : return "invalid";
}
}
#define XX(name, type, value, str, mpeg_id) {str, name},
static map<string, CodecId, StrCaseCompare> codec_map = {CODEC_MAP(XX)};
#define XX(name, type, value, str, mpeg_id, mp4_id) {str, name},
static map<string, CodecId, StrCaseCompare> codec_map = { CODEC_MAP(XX) };
#undef XX
CodecId getCodecId(const string &str){
@@ -94,6 +151,10 @@ TrackType CodecInfo::getTrackType() const {
return mediakit::getTrackType(getCodecId());
}
std::string CodecInfo::getTrackTypeStr() const {
return getTrackString(getTrackType());
}
static size_t constexpr kMaxFrameCacheSize = 100;
bool FrameMerger::willFlush(const Frame::Ptr &frame) const{
@@ -165,7 +226,19 @@ void FrameMerger::doMerge(BufferLikeString &merged, const Frame::Ptr &frame) con
}
}
static bool isNeedMerge(CodecId codec){
switch (codec) {
case CodecH264:
case CodecH265: return true;
default: return false;
}
}
bool FrameMerger::inputFrame(const Frame::Ptr &frame, onOutput cb, BufferLikeString *buffer) {
if (frame && !isNeedMerge(frame->getCodecId())) {
cb(frame->dts(), frame->pts(), frame, true);
return true;
}
if (willFlush(frame)) {
Frame::Ptr back = _frame_cache.back();
Buffer::Ptr merged_frame = back;
@@ -233,8 +306,6 @@ public:
*/
FrameWriterInterfaceHelper(onWriteFrame cb) { _callback = std::move(cb); }
virtual ~FrameWriterInterfaceHelper() = default;
/**
* 写入帧数据
*/

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -20,7 +20,9 @@
#include "Network/Buffer.h"
namespace mediakit {
class Stamp;
typedef enum {
TrackInvalid = -1,
TrackVideo = 0,
@@ -31,21 +33,21 @@ typedef enum {
} TrackType;
#define CODEC_MAP(XX) \
XX(CodecH264, TrackVideo, 0, "H264", PSI_STREAM_H264) \
XX(CodecH265, TrackVideo, 1, "H265", PSI_STREAM_H265) \
XX(CodecAAC, TrackAudio, 2, "mpeg4-generic", PSI_STREAM_AAC) \
XX(CodecG711A, TrackAudio, 3, "PCMA", PSI_STREAM_AUDIO_G711A) \
XX(CodecG711U, TrackAudio, 4, "PCMU", PSI_STREAM_AUDIO_G711U) \
XX(CodecOpus, TrackAudio, 5, "opus", PSI_STREAM_AUDIO_OPUS) \
XX(CodecL16, TrackAudio, 6, "L16", PSI_STREAM_RESERVED) \
XX(CodecVP8, TrackVideo, 7, "VP8", PSI_STREAM_VP8) \
XX(CodecVP9, TrackVideo, 8, "VP9", PSI_STREAM_VP9) \
XX(CodecAV1, TrackVideo, 9, "AV1", PSI_STREAM_AV1) \
XX(CodecJPEG, TrackVideo, 10, "JPEG", PSI_STREAM_RESERVED)
XX(CodecH264, TrackVideo, 0, "H264", PSI_STREAM_H264, MOV_OBJECT_H264) \
XX(CodecH265, TrackVideo, 1, "H265", PSI_STREAM_H265, MOV_OBJECT_HEVC) \
XX(CodecAAC, TrackAudio, 2, "mpeg4-generic", PSI_STREAM_AAC, MOV_OBJECT_AAC) \
XX(CodecG711A, TrackAudio, 3, "PCMA", PSI_STREAM_AUDIO_G711A, MOV_OBJECT_G711a) \
XX(CodecG711U, TrackAudio, 4, "PCMU", PSI_STREAM_AUDIO_G711U, MOV_OBJECT_G711u) \
XX(CodecOpus, TrackAudio, 5, "opus", PSI_STREAM_AUDIO_OPUS, MOV_OBJECT_OPUS) \
XX(CodecL16, TrackAudio, 6, "L16", PSI_STREAM_RESERVED, MOV_OBJECT_NONE) \
XX(CodecVP8, TrackVideo, 7, "VP8", PSI_STREAM_VP8, MOV_OBJECT_VP8) \
XX(CodecVP9, TrackVideo, 8, "VP9", PSI_STREAM_VP9, MOV_OBJECT_VP9) \
XX(CodecAV1, TrackVideo, 9, "AV1", PSI_STREAM_AV1, MOV_OBJECT_AV1) \
XX(CodecJPEG, TrackVideo, 10, "JPEG", PSI_STREAM_JPEG_2000, MOV_OBJECT_JPEG)
typedef enum {
CodecInvalid = -1,
#define XX(name, type, value, str, mpeg_id) name = value,
#define XX(name, type, value, str, mpeg_id, mp4_id) name = value,
CODEC_MAP(XX)
#undef XX
CodecMax
@@ -78,6 +80,26 @@ const char *getCodecName(CodecId codecId);
*/
TrackType getTrackType(CodecId codecId);
/**
* 根据codecid获取mov object id
*/
int getMovIdByCodec(CodecId codecId);
/**
* 根据mov object id获取CodecId
*/
CodecId getCodecByMovId(int object_id);
/**
* 根据codecid获取mpeg id
*/
int getMpegIdByCodec(CodecId codec);
/**
* 根据mpeg id获取CodecId
*/
CodecId getCodecByMpegId(int mpeg_id);
/**
* 编码信息的抽象接口
*/
@@ -85,7 +107,6 @@ class CodecInfo {
public:
using Ptr = std::shared_ptr<CodecInfo>;
CodecInfo() = default;
virtual ~CodecInfo() = default;
/**
@@ -102,6 +123,7 @@ public:
* 获取音视频类型
*/
TrackType getTrackType() const;
std::string getTrackTypeStr() const;
};
/**
@@ -110,7 +132,6 @@ public:
class Frame : public toolkit::Buffer, public CodecInfo {
public:
using Ptr = std::shared_ptr<Frame>;
virtual ~Frame() = default;
/**
* 返回解码时间戳,单位毫秒
@@ -220,24 +241,52 @@ protected:
FrameImp() = default;
};
/**
* 一个Frame类中可以有多个帧他们通过 0x 00 00 01 分隔
* ZLMediaKit会先把这种复合帧split成单个帧然后再处理
* 一个复合帧可以通过无内存拷贝的方式切割成多个子Frame
* 提供该类的目的是切割复合帧时防止内存拷贝,提高性能
*/
template <typename Parent>
class FrameInternal : public Parent {
// 包装一个指针成不可缓存的frame
class FrameFromPtr : public Frame {
public:
using Ptr = std::shared_ptr<FrameInternal>;
FrameInternal(const Frame::Ptr &parent_frame, char *ptr, size_t size, size_t prefix_size)
: Parent(ptr, size, parent_frame->dts(), parent_frame->pts(), prefix_size) {
_parent_frame = parent_frame;
}
bool cacheAble() const override { return _parent_frame->cacheAble(); }
using Ptr = std::shared_ptr<FrameFromPtr>;
private:
Frame::Ptr _parent_frame;
FrameFromPtr(CodecId codec_id, char *ptr, size_t size, uint64_t dts, uint64_t pts = 0, size_t prefix_size = 0, bool is_key = false)
: FrameFromPtr(ptr, size, dts, pts, prefix_size, is_key) {
_codec_id = codec_id;
}
char *data() const override { return _ptr; }
size_t size() const override { return _size; }
uint64_t dts() const override { return _dts; }
uint64_t pts() const override { return _pts ? _pts : dts(); }
size_t prefixSize() const override { return _prefix_size; }
bool cacheAble() const override { return false; }
bool keyFrame() const override { return _is_key; }
bool configFrame() const override { return false; }
CodecId getCodecId() const override {
if (_codec_id == CodecInvalid) {
throw std::invalid_argument("Invalid codec type of FrameFromPtr");
}
return _codec_id;
}
protected:
FrameFromPtr() = default;
FrameFromPtr(char *ptr, size_t size, uint64_t dts, uint64_t pts = 0, size_t prefix_size = 0, bool is_key = false) {
_ptr = ptr;
_size = size;
_dts = dts;
_pts = pts;
_prefix_size = prefix_size;
_is_key = is_key;
}
protected:
bool _is_key;
char *_ptr;
uint64_t _dts;
uint64_t _pts = 0;
size_t _size;
size_t _prefix_size;
CodecId _codec_id = CodecInvalid;
};
/**
@@ -247,27 +296,210 @@ private:
* 提供该类的目的是切割复合帧时防止内存拷贝,提高性能
*/
template <typename Parent>
class FrameTSInternal : public Parent {
class FrameInternalBase : public Parent {
public:
using Ptr = std::shared_ptr<FrameTSInternal>;
FrameTSInternal(
const Frame::Ptr &parent_frame, char *ptr, size_t size, size_t prefix_size, uint64_t dts, uint64_t pts)
: Parent(ptr, size, dts, pts, prefix_size) {
_parent_frame = parent_frame;
using Ptr = std::shared_ptr<FrameInternalBase>;
FrameInternalBase(Frame::Ptr parent_frame, char *ptr, size_t size, uint64_t dts, uint64_t pts = 0, size_t prefix_size = 0)
: Parent(parent_frame->getCodecId(), ptr, size, dts, pts, prefix_size) {
_parent_frame = std::move(parent_frame);
}
bool cacheAble() const override { return _parent_frame->cacheAble(); }
private:
Frame::Ptr _parent_frame;
};
/**
* 一个Frame类中可以有多个帧他们通过 0x 00 00 01 分隔
* ZLMediaKit会先把这种复合帧split成单个帧然后再处理
* 一个复合帧可以通过无内存拷贝的方式切割成多个子Frame
* 提供该类的目的是切割复合帧时防止内存拷贝,提高性能
*/
template <typename Parent>
class FrameInternal : public FrameInternalBase<Parent> {
public:
using Ptr = std::shared_ptr<FrameInternal>;
FrameInternal(const Frame::Ptr &parent_frame, char *ptr, size_t size, size_t prefix_size)
: FrameInternalBase<Parent>(parent_frame, ptr, size, parent_frame->dts(), parent_frame->pts(), prefix_size) {}
};
// 管理一个指针生命周期并生产一个frame
class FrameAutoDelete : public FrameFromPtr {
public:
template <typename... ARGS>
FrameAutoDelete(ARGS &&...args) : FrameFromPtr(std::forward<ARGS>(args)...) {}
~FrameAutoDelete() override { delete[] _ptr; };
bool cacheAble() const override { return true; }
};
// 把一个不可缓存的frame声明为可缓存的
template <typename Parent>
class FrameToCache : public Parent {
public:
template<typename ... ARGS>
FrameToCache(ARGS &&...args) : Parent(std::forward<ARGS>(args)...) {};
bool cacheAble() const override {
return true;
}
};
// 该对象的功能是把一个不可缓存的帧转换成可缓存的帧
class FrameCacheAble : public FrameFromPtr {
public:
using Ptr = std::shared_ptr<FrameCacheAble>;
FrameCacheAble(const Frame::Ptr &frame, bool force_key_frame = false, toolkit::Buffer::Ptr buf = nullptr) {
if (frame->cacheAble()) {
_ptr = frame->data();
_buffer = frame;
} else if (buf) {
_ptr = frame->data();
_buffer = std::move(buf);
} else {
auto buffer = std::make_shared<toolkit::BufferLikeString>();
buffer->assign(frame->data(), frame->size());
_ptr = buffer->data();
_buffer = std::move(buffer);
}
_size = frame->size();
_dts = frame->dts();
_pts = frame->pts();
_prefix_size = frame->prefixSize();
_codec_id = frame->getCodecId();
_key = force_key_frame ? true : frame->keyFrame();
_config = frame->configFrame();
_drop_able = frame->dropAble();
_decode_able = frame->decodeAble();
}
/**
* 可以被缓存
*/
bool cacheAble() const override { return true; }
bool keyFrame() const override { return _key; }
bool configFrame() const override { return _config; }
bool dropAble() const override { return _drop_able; }
bool decodeAble() const override { return _decode_able; }
private:
bool _key;
bool _config;
bool _drop_able;
bool _decode_able;
toolkit::Buffer::Ptr _buffer;
};
//该类实现frame级别的时间戳覆盖
class FrameStamp : public Frame {
public:
using Ptr = std::shared_ptr<FrameStamp>;
FrameStamp(Frame::Ptr frame, Stamp &stamp, int modify_stamp);
~FrameStamp() override {}
uint64_t dts() const override { return (uint64_t)_dts; }
uint64_t pts() const override { return (uint64_t)_pts; }
size_t prefixSize() const override { return _frame->prefixSize(); }
bool keyFrame() const override { return _frame->keyFrame(); }
bool configFrame() const override { return _frame->configFrame(); }
bool cacheAble() const override { return _frame->cacheAble(); }
bool dropAble() const override { return _frame->dropAble(); }
bool decodeAble() const override { return _frame->decodeAble(); }
char *data() const override { return _frame->data(); }
size_t size() const override { return _frame->size(); }
CodecId getCodecId() const override { return _frame->getCodecId(); }
private:
int64_t _dts;
int64_t _pts;
Frame::Ptr _frame;
};
/**
* 该对象可以把Buffer对象转换成可缓存的Frame对象
*/
template <typename Parent>
class FrameFromBuffer : public Parent {
public:
/**
* 构造frame
* @param buf 数据缓存
* @param dts 解码时间戳
* @param pts 显示时间戳
* @param prefix 帧前缀长度
* @param offset buffer有效数据偏移量
*/
FrameFromBuffer(toolkit::Buffer::Ptr buf, uint64_t dts, uint64_t pts, size_t prefix = 0, size_t offset = 0)
: Parent(buf->data() + offset, buf->size() - offset, dts, pts, prefix) {
_buf = std::move(buf);
}
/**
* 构造frame
* @param buf 数据缓存
* @param dts 解码时间戳
* @param pts 显示时间戳
* @param prefix 帧前缀长度
* @param offset buffer有效数据偏移量
* @param codec 帧类型
*/
FrameFromBuffer(CodecId codec, toolkit::Buffer::Ptr buf, uint64_t dts, uint64_t pts, size_t prefix = 0, size_t offset = 0)
: Parent(codec, buf->data() + offset, buf->size() - offset, dts, pts, prefix) {
_buf = std::move(buf);
}
/**
* 该帧可缓存
*/
bool cacheAble() const override { return true; }
private:
toolkit::Buffer::Ptr _buf;
};
/**
* 合并一些时间戳相同的frame
*/
class FrameMerger {
public:
using onOutput = std::function<void(uint64_t dts, uint64_t pts, const toolkit::Buffer::Ptr &buffer, bool have_key_frame)>;
using Ptr = std::shared_ptr<FrameMerger>;
enum {
none = 0,
h264_prefix,
mp4_nal_size,
};
FrameMerger(int type);
/**
* 刷新输出缓冲注意此时会调用FrameMerger::inputFrame传入的onOutput回调
* 请注意回调捕获参数此时是否有效
*/
void flush();
void clear();
bool inputFrame(const Frame::Ptr &frame, onOutput cb, toolkit::BufferLikeString *buffer = nullptr);
private:
bool willFlush(const Frame::Ptr &frame) const;
void doMerge(toolkit::BufferLikeString &buffer, const Frame::Ptr &frame) const;
private:
int _type;
bool _have_decode_able_frame = false;
onOutput _cb;
toolkit::List<Frame::Ptr> _frame_cache;
};
/**
* 写帧接口的抽象接口类
*/
class FrameWriterInterface {
public:
using Ptr = std::shared_ptr<FrameWriterInterface>;
FrameWriterInterface() = default;
virtual ~FrameWriterInterface() = default;
/**
@@ -287,8 +519,6 @@ public:
class FrameDispatcher : public FrameWriterInterface {
public:
using Ptr = std::shared_ptr<FrameDispatcher>;
FrameDispatcher() = default;
~FrameDispatcher() override = default;
/**
* 添加代理
@@ -397,209 +627,5 @@ private:
std::map<void *, FrameWriterInterface::Ptr> _delegates;
};
/**
* 通过Frame接口包装指针方便使用者把自己的数据快速接入ZLMediaKit
*/
class FrameFromPtr : public Frame {
public:
using Ptr = std::shared_ptr<FrameFromPtr>;
FrameFromPtr(
CodecId codec_id, char *ptr, size_t size, uint64_t dts, uint64_t pts = 0, size_t prefix_size = 0,
bool is_key = false)
: FrameFromPtr(ptr, size, dts, pts, prefix_size, is_key) {
_codec_id = codec_id;
}
FrameFromPtr(char *ptr, size_t size, uint64_t dts, uint64_t pts = 0, size_t prefix_size = 0, bool is_key = false) {
_ptr = ptr;
_size = size;
_dts = dts;
_pts = pts;
_prefix_size = prefix_size;
_is_key = is_key;
}
char *data() const override { return _ptr; }
size_t size() const override { return _size; }
uint64_t dts() const override { return _dts; }
uint64_t pts() const override { return _pts ? _pts : dts(); }
size_t prefixSize() const override { return _prefix_size; }
bool cacheAble() const override { return false; }
bool keyFrame() const override { return _is_key; }
bool configFrame() const override { return false; }
void setCodecId(CodecId codec_id) { _codec_id = codec_id; }
CodecId getCodecId() const override {
if (_codec_id == CodecInvalid) {
throw std::invalid_argument("FrameFromPtr对象未设置codec类型");
}
return _codec_id;
}
protected:
FrameFromPtr() = default;
protected:
bool _is_key;
char *_ptr;
uint64_t _dts;
uint64_t _pts = 0;
size_t _size;
size_t _prefix_size;
CodecId _codec_id = CodecInvalid;
};
/**
* 该对象的功能是把一个不可缓存的帧转换成可缓存的帧
*/
class FrameCacheAble : public FrameFromPtr {
public:
using Ptr = std::shared_ptr<FrameCacheAble>;
FrameCacheAble(const Frame::Ptr &frame, bool force_key_frame = false) {
if (frame->cacheAble()) {
_frame = frame;
_ptr = frame->data();
} else {
_buffer = FrameImp::create();
_buffer->_buffer.assign(frame->data(), frame->size());
_ptr = _buffer->data();
}
_size = frame->size();
_dts = frame->dts();
_pts = frame->pts();
_prefix_size = frame->prefixSize();
_codec_id = frame->getCodecId();
_key = force_key_frame ? true : frame->keyFrame();
_config = frame->configFrame();
_drop_able = frame->dropAble();
_decode_able = frame->decodeAble();
}
~FrameCacheAble() override = default;
/**
* 可以被缓存
*/
bool cacheAble() const override { return true; }
bool keyFrame() const override { return _key; }
bool configFrame() const override { return _config; }
bool dropAble() const override { return _drop_able; }
bool decodeAble() const override { return _decode_able; }
private:
bool _key;
bool _config;
bool _drop_able;
bool _decode_able;
Frame::Ptr _frame;
FrameImp::Ptr _buffer;
};
//该类实现frame级别的时间戳覆盖
class FrameStamp : public Frame {
public:
using Ptr = std::shared_ptr<FrameStamp>;
FrameStamp(Frame::Ptr frame, Stamp &stamp, int modify_stamp);
~FrameStamp() override {}
uint64_t dts() const override { return (uint64_t)_dts; }
uint64_t pts() const override { return (uint64_t)_pts; }
size_t prefixSize() const override { return _frame->prefixSize(); }
bool keyFrame() const override { return _frame->keyFrame(); }
bool configFrame() const override { return _frame->configFrame(); }
bool cacheAble() const override { return _frame->cacheAble(); }
bool dropAble() const override { return _frame->dropAble(); }
bool decodeAble() const override { return _frame->decodeAble(); }
char *data() const override { return _frame->data(); }
size_t size() const override { return _frame->size(); }
CodecId getCodecId() const override { return _frame->getCodecId(); }
private:
int64_t _dts;
int64_t _pts;
Frame::Ptr _frame;
};
/**
* 该对象可以把Buffer对象转换成可缓存的Frame对象
*/
template <typename Parent>
class FrameWrapper : public Parent {
public:
~FrameWrapper() = default;
/**
* 构造frame
* @param buf 数据缓存
* @param dts 解码时间戳
* @param pts 显示时间戳
* @param prefix 帧前缀长度
* @param offset buffer有效数据偏移量
*/
FrameWrapper(toolkit::Buffer::Ptr buf, uint64_t dts, uint64_t pts, size_t prefix, size_t offset)
: Parent(buf->data() + offset, buf->size() - offset, dts, pts, prefix) {
_buf = std::move(buf);
}
/**
* 构造frame
* @param buf 数据缓存
* @param dts 解码时间戳
* @param pts 显示时间戳
* @param prefix 帧前缀长度
* @param offset buffer有效数据偏移量
* @param codec 帧类型
*/
FrameWrapper(toolkit::Buffer::Ptr buf, uint64_t dts, uint64_t pts, size_t prefix, size_t offset, CodecId codec)
: Parent(codec, buf->data() + offset, buf->size() - offset, dts, pts, prefix) {
_buf = std::move(buf);
}
/**
* 该帧可缓存
*/
bool cacheAble() const override { return true; }
private:
toolkit::Buffer::Ptr _buf;
};
/**
* 合并一些时间戳相同的frame
*/
class FrameMerger {
public:
using onOutput = std::function<void(uint64_t dts, uint64_t pts, const toolkit::Buffer::Ptr &buffer, bool have_key_frame)>;
using Ptr = std::shared_ptr<FrameMerger>;
enum {
none = 0,
h264_prefix,
mp4_nal_size,
};
FrameMerger(int type);
~FrameMerger() = default;
/**
* 刷新输出缓冲注意此时会调用FrameMerger::inputFrame传入的onOutput回调
* 请注意回调捕获参数此时是否有效
*/
void flush();
void clear();
bool inputFrame(const Frame::Ptr &frame, onOutput cb, toolkit::BufferLikeString *buffer = nullptr);
private:
bool willFlush(const Frame::Ptr &frame) const;
void doMerge(toolkit::BufferLikeString &buffer, const Frame::Ptr &frame) const;
private:
int _type;
bool _have_decode_able_frame = false;
onOutput _cb;
toolkit::List<Frame::Ptr> _frame_cache;
};
} // namespace mediakit
#endif // ZLMEDIAKIT_FRAME_H

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -23,41 +23,34 @@ public:
/**
* G711采样率固定为8000
* @param codecId G711A G711U
* @param payload_type rtp payload type
* @param sample_rate 音频采样率
* @param payload_type rtp payload
* @param channels 通道数
* @param bitrate 比特率
*/
G711Sdp(CodecId codecId,
int sample_rate,
int channels,
int bitrate = 128,
int payload_type = 98) : Sdp(sample_rate,payload_type), _codecId(codecId){
G711Sdp(CodecId codecId, int payload_type, int sample_rate, int channels, int bitrate)
: Sdp(sample_rate, payload_type) {
_printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n";
if (bitrate) {
_printer << "b=AS:" << bitrate << "\r\n";
}
_printer << "a=rtpmap:" << payload_type << " " << getCodecName() << "/" << sample_rate << "/" << channels << "\r\n";
_printer << "a=control:trackID=" << (int)TrackAudio << "\r\n";
_printer << "a=rtpmap:" << payload_type << " " << getCodecName(codecId) << "/" << sample_rate << "/" << channels << "\r\n";
}
string getSdp() const override {
return _printer;
}
CodecId getCodecId() const override {
return _codecId;
}
private:
_StrPrinter _printer;
CodecId _codecId;
};
Track::Ptr G711Track::clone() {
return std::make_shared<std::remove_reference<decltype(*this)>::type>(*this);
Track::Ptr G711Track::clone() const {
return std::make_shared<G711Track>(*this);
}
Sdp::Ptr G711Track::getSdp() {
if(!ready()){
Sdp::Ptr G711Track::getSdp(uint8_t payload_type) const {
if (!ready()) {
WarnL << getCodecName() << " Track未准备好";
return nullptr;
}
@@ -66,13 +59,12 @@ Sdp::Ptr G711Track::getSdp() {
const auto sample_rate = getAudioSampleRate();
const auto audio_channel = getAudioChannel();
const auto bitrate = getBitRate() >> 10;
auto payload_type = 98;
if (sample_rate == 8000 && audio_channel == 1) {
// https://datatracker.ietf.org/doc/html/rfc3551#section-6
payload_type = (codec == CodecG711U) ? Rtsp::PT_PCMU : Rtsp::PT_PCMA;
}
return std::make_shared<G711Sdp>(codec, sample_rate, audio_channel, bitrate, payload_type);
return std::make_shared<G711Sdp>(codec, payload_type, sample_rate, audio_channel, bitrate);
}
}//namespace mediakit

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -25,8 +25,8 @@ public:
G711Track(CodecId codecId, int sample_rate, int channels, int sample_bit) : AudioTrackImp(codecId, 8000, 1, 16) {}
private:
Sdp::Ptr getSdp() override;
Track::Ptr clone() override;
Sdp::Ptr getSdp(uint8_t payload_type) const override;
Track::Ptr clone() const override;
};
}//namespace mediakit

View File

@@ -2,11 +2,7 @@
namespace mediakit {
G711RtpEncoder::G711RtpEncoder(
CodecId codec, uint32_t ssrc, uint32_t mtu_size, uint32_t sample_rate, uint8_t payload_type, uint8_t interleaved,
uint32_t channels)
: CommonRtpDecoder(codec)
, RtpInfo(ssrc, mtu_size, sample_rate, payload_type, interleaved) {
G711RtpEncoder::G711RtpEncoder(CodecId codec, uint32_t channels){
_cache_frame = FrameImp::create();
_cache_frame->_codec_id = codec;
_channels = channels;
@@ -40,7 +36,7 @@ bool G711RtpEncoder::inputFrame(const Frame::Ptr &frame) {
}
n++;
stamp += 20;
RtpCodec::inputRtp(makeRtp(getTrackType(), ptr, rtp_size, mark, stamp), false);
RtpCodec::inputRtp(getRtpInfo().makeRtp(TrackAudio, ptr, rtp_size, mark, stamp), false);
ptr += rtp_size;
remain_size -= rtp_size;
}

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -20,23 +20,16 @@ namespace mediakit {
/**
* G711 rtp编码类
*/
class G711RtpEncoder : public CommonRtpDecoder, public RtpInfo {
class G711RtpEncoder : public RtpCodec {
public:
using Ptr = std::shared_ptr<G711RtpEncoder>;
~G711RtpEncoder() override = default;
/**
* 构造函数
* @param codec 编码类型
* @param ssrc ssrc
* @param mtu_size mtu 大小
* @param sample_rate 采样率
* @param payload_type pt类型
* @param interleaved rtsp interleaved 值
* @param channels 通道数
*/
G711RtpEncoder(CodecId codec, uint32_t ssrc, uint32_t mtu_size, uint32_t sample_rate, uint8_t payload_type,
uint8_t interleaved, uint32_t channels);
G711RtpEncoder(CodecId codec, uint32_t channels);
/**
* 输入帧数据并编码成rtp

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -14,6 +14,10 @@
#include "Util/base64.h"
#include "Common/config.h"
#ifdef ENABLE_MP4
#include "mpeg4-avc.h"
#endif
using namespace std;
using namespace toolkit;
@@ -109,24 +113,7 @@ size_t prefixSize(const char *ptr, size_t len) {
H264Track::H264Track(const string &sps, const string &pps, int sps_prefix_len, int pps_prefix_len) {
_sps = sps.substr(sps_prefix_len);
_pps = pps.substr(pps_prefix_len);
onReady();
}
H264Track::H264Track(const Frame::Ptr &sps, const Frame::Ptr &pps) {
if (sps->getCodecId() != CodecH264 || pps->getCodecId() != CodecH264) {
throw std::invalid_argument("必须输入H264类型的帧");
}
_sps = string(sps->data() + sps->prefixSize(), sps->size() - sps->prefixSize());
_pps = string(pps->data() + pps->prefixSize(), pps->size() - pps->prefixSize());
onReady();
}
const string &H264Track::getSps() const {
return _sps;
}
const string &H264Track::getPps() const {
return _pps;
update();
}
CodecId H264Track::getCodecId() const {
@@ -145,7 +132,7 @@ float H264Track::getVideoFps() const {
return _fps;
}
bool H264Track::ready() {
bool H264Track::ready() const {
return !_sps.empty() && !_pps.empty();
}
@@ -168,19 +155,87 @@ bool H264Track::inputFrame(const Frame::Ptr &frame) {
return ret;
}
toolkit::Buffer::Ptr H264Track::getExtraData() const {
CHECK(ready());
#ifdef ENABLE_MP4
struct mpeg4_avc_t avc;
memset(&avc, 0, sizeof(avc));
string sps_pps = string("\x00\x00\x00\x01", 4) + _sps + string("\x00\x00\x00\x01", 4) + _pps;
h264_annexbtomp4(&avc, sps_pps.data(), (int)sps_pps.size(), NULL, 0, NULL, NULL);
std::string extra_data;
extra_data.resize(1024);
auto extra_data_size = mpeg4_avc_decoder_configuration_record_save(&avc, (uint8_t *)extra_data.data(), extra_data.size());
if (extra_data_size == -1) {
WarnL << "生成H264 extra_data 失败";
return nullptr;
}
extra_data.resize(extra_data_size);
return std::make_shared<BufferString>(std::move(extra_data));
#else
std::string extra_data;
// AVCDecoderConfigurationRecord start
extra_data.push_back(1); // version
extra_data.push_back(_sps[1]); // profile
extra_data.push_back(_sps[2]); // compat
extra_data.push_back(_sps[3]); // level
extra_data.push_back((char)0xff); // 6 bits reserved + 2 bits nal size length - 1 (11)
extra_data.push_back((char)0xe1); // 3 bits reserved + 5 bits number of sps (00001)
// sps
uint16_t size = (uint16_t)_sps.size();
size = htons(size);
extra_data.append((char *)&size, 2);
extra_data.append(_sps);
// pps
extra_data.push_back(1); // version
size = (uint16_t)_pps.size();
size = htons(size);
extra_data.append((char *)&size, 2);
extra_data.append(_pps);
return std::make_shared<BufferString>(std::move(extra_data));
#endif
}
void H264Track::setExtraData(const uint8_t *data, size_t bytes) {
#ifdef ENABLE_MP4
struct mpeg4_avc_t avc;
memset(&avc, 0, sizeof(avc));
if (mpeg4_avc_decoder_configuration_record_load(data, bytes, &avc) > 0) {
std::vector<uint8_t> config(bytes * 2);
int size = mpeg4_avc_to_nalu(&avc, config.data(), bytes * 2);
if (size > 4) {
splitH264((char *)config.data(), size, 4, [&](const char *ptr, size_t len, size_t prefix) {
inputFrame_l(std::make_shared<H264FrameNoCacheAble>((char *)ptr, len, 0, 0, prefix));
});
update();
}
}
#else
CHECK(bytes >= 8); // 6 + 2
size_t offset = 6;
uint16_t sps_size = data[offset] << 8 | data[offset + 1];
auto sps_ptr = data + offset + 2;
offset += (2 + sps_size);
CHECK(bytes >= offset + 2); // + pps_size
_sps.assign((char *)sps_ptr, sps_size);
uint16_t pps_size = data[offset] << 8 | data[offset + 1];
auto pps_ptr = data + offset + 2;
offset += (2 + pps_size);
CHECK(bytes >= offset);
_pps.assign((char *)pps_ptr, pps_size);
update();
#endif
}
bool H264Track::update() {
return getAVCInfo(_sps, _width, _height, _fps);
}
void H264Track::onReady() {
if (!getAVCInfo(_sps, _width, _height, _fps)) {
_sps.clear();
_pps.clear();
}
}
Track::Ptr H264Track::clone() {
return std::make_shared<std::remove_reference<decltype(*this)>::type>(*this);
Track::Ptr H264Track::clone() const {
return std::make_shared<H264Track>(*this);
}
bool H264Track::inputFrame_l(const Frame::Ptr &frame) {
@@ -218,7 +273,7 @@ bool H264Track::inputFrame_l(const Frame::Ptr &frame) {
}
if (_width == 0 && ready()) {
onReady();
update();
}
return ret;
}
@@ -245,14 +300,12 @@ void H264Track::insertConfigFrame(const Frame::Ptr &frame) {
class H264Sdp : public Sdp {
public:
H264Sdp(const string &strSPS, const string &strPPS, int bitrate, int payload_type = 96)
: Sdp(90000, payload_type) {
//视频通道
H264Sdp(const string &strSPS, const string &strPPS, int payload_type, int bitrate) : Sdp(90000, payload_type) {
_printer << "m=video 0 RTP/AVP " << payload_type << "\r\n";
if (bitrate) {
_printer << "b=AS:" << bitrate << "\r\n";
}
_printer << "a=rtpmap:" << payload_type << " " << getCodecName() << "/" << 90000 << "\r\n";
_printer << "a=rtpmap:" << payload_type << " " << getCodecName(CodecH264) << "/" << 90000 << "\r\n";
/**
Single NAI Unit Mode = 0. // Single NAI mode (Only nals from 1-23 are allowed)
@@ -275,23 +328,20 @@ public:
_printer << "; sprop-parameter-sets=";
_printer << encodeBase64(strSPS) << ",";
_printer << encodeBase64(strPPS) << "\r\n";
_printer << "a=control:trackID=" << (int)TrackVideo << "\r\n";
}
string getSdp() const { return _printer; }
CodecId getCodecId() const { return CodecH264; }
private:
_StrPrinter _printer;
};
Sdp::Ptr H264Track::getSdp() {
Sdp::Ptr H264Track::getSdp(uint8_t payload_type) const {
if (!ready()) {
WarnL << getCodecName() << " Track未准备好";
return nullptr;
}
return std::make_shared<H264Sdp>(getSps(), getPps(), getBitRate() / 1024);
return std::make_shared<H264Sdp>(_sps, _pps, payload_type, getBitRate() / 1024);
}
} // namespace mediakit

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -18,7 +18,6 @@
namespace mediakit{
bool getAVCInfo(const std::string &strSps,int &iVideoWidth, int &iVideoHeight, float &iVideoFps);
void splitH264(const char *ptr, size_t len, size_t prefix, const std::function<void(const char *, size_t, size_t)> &cb);
size_t prefixSize(const char *ptr, size_t len);
@@ -43,8 +42,6 @@ public:
this->_codec_id = CodecH264;
}
~H264FrameHelper() override = default;
bool keyFrame() const override {
auto nal_ptr = (uint8_t *) this->data() + this->prefixSize();
return H264_TYPE(*nal_ptr) == NAL_IDR && decodeAble();
@@ -107,33 +104,21 @@ public:
* @param sps_prefix_len 264头长度可以为3个或4个字节一般为0x00 00 00 01
* @param pps_prefix_len 264头长度可以为3个或4个字节一般为0x00 00 00 01
*/
H264Track(const std::string &sps,const std::string &pps,int sps_prefix_len = 4,int pps_prefix_len = 4);
H264Track(const std::string &sps, const std::string &pps, int sps_prefix_len = 4, int pps_prefix_len = 4);
/**
* 构造h264类型的媒体
* @param sps sps帧
* @param pps pps帧
*/
H264Track(const Frame::Ptr &sps,const Frame::Ptr &pps);
/**
* 返回不带0x00 00 00 01头的sps/pps
*/
const std::string &getSps() const;
const std::string &getPps() const;
bool ready() override;
bool ready() const override;
CodecId getCodecId() const override;
int getVideoHeight() const override;
int getVideoWidth() const override;
float getVideoFps() const override;
bool inputFrame(const Frame::Ptr &frame) override;
toolkit::Buffer::Ptr getExtraData() const override;
void setExtraData(const uint8_t *data, size_t size) override;
bool update() override;
private:
void onReady();
Sdp::Ptr getSdp() override;
Track::Ptr clone() override;
Sdp::Ptr getSdp(uint8_t payload_type) const override;
Track::Ptr clone() const override;
bool inputFrame_l(const Frame::Ptr &frame);
void insertConfigFrame(const Frame::Ptr &frame);

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -16,139 +16,50 @@ using namespace toolkit;
namespace mediakit {
H264RtmpDecoder::H264RtmpDecoder() {
_h264frame = obtainFrame();
}
H264Frame::Ptr H264RtmpDecoder::obtainFrame() {
auto frame = FrameImp::create<H264Frame>();
frame->_prefix_size = 4;
return frame;
}
/**
* 返回不带0x00 00 00 01头的sps pps
*/
static bool getH264Config(const RtmpPacket &thiz, string &sps, string &pps) {
if ((RtmpVideoCodec)thiz.getRtmpCodecId() != RtmpVideoCodec::h264) {
return false;
}
if (thiz.buffer.size() < 13) {
return false;
}
uint16_t sps_size;
memcpy(&sps_size, thiz.buffer.data() + 11, 2);
sps_size = ntohs(sps_size);
if ((int) thiz.buffer.size() < 13 + sps_size + 1 + 2) {
return false;
}
uint16_t pps_size;
memcpy(&pps_size, thiz.buffer.data() + 13 + sps_size + 1, 2);
pps_size = ntohs(pps_size);
if ((int) thiz.buffer.size() < 13 + sps_size + 1 + 2 + pps_size) {
return false;
}
sps.assign(thiz.buffer.data() + 13, sps_size);
pps.assign(thiz.buffer.data() + 13 + sps_size + 1 + 2, pps_size);
return true;
}
void H264RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) {
if (pkt->isConfigFrame()) {
//缓存sps pps后续插入到I帧之前
if (!getH264Config(*pkt, _sps, _pps)) {
WarnL << "get h264 sps/pps failed, rtmp packet is: " << hexdump(pkt->data(), pkt->size());
return;
}
onGetH264(_sps.data(), _sps.size(), pkt->time_stamp, pkt->time_stamp);
onGetH264(_pps.data(), _pps.size(), pkt->time_stamp, pkt->time_stamp);
CHECK(pkt->size() > 5);
getTrack()->setExtraData((uint8_t *)pkt->data() + 5, pkt->size() - 5);
return;
}
if (pkt->buffer.size() > 9) {
auto total_len = pkt->buffer.size();
size_t offset = 5;
uint8_t *cts_ptr = (uint8_t *) (pkt->buffer.data() + 2);
int32_t cts = (((cts_ptr[0] << 16) | (cts_ptr[1] << 8) | (cts_ptr[2])) + 0xff800000) ^ 0xff800000;
auto pts = pkt->time_stamp + cts;
while (offset + 4 < total_len) {
uint32_t frame_len;
memcpy(&frame_len, pkt->buffer.data() + offset, 4);
frame_len = ntohl(frame_len);
offset += 4;
if (frame_len + offset > total_len) {
break;
}
onGetH264(pkt->buffer.data() + offset, frame_len, pkt->time_stamp, pts);
offset += frame_len;
CHECK(pkt->size() > 9);
uint8_t *cts_ptr = (uint8_t *)(pkt->buffer.data() + 2);
int32_t cts = (((cts_ptr[0] << 16) | (cts_ptr[1] << 8) | (cts_ptr[2])) + 0xff800000) ^ 0xff800000;
auto pts = pkt->time_stamp + cts;
splitFrame((uint8_t *)pkt->data() + 5, pkt->size() - 5, pkt->time_stamp, pts);
}
void H264RtmpDecoder::splitFrame(const uint8_t *data, size_t size, uint32_t dts, uint32_t pts) {
auto end = data + size;
while (data + 4 < end) {
uint32_t frame_len = load_be32(data);
data += 4;
if (data + frame_len > end) {
break;
}
outputFrame((const char *)data, frame_len, dts, pts);
data += frame_len;
}
}
inline void H264RtmpDecoder::onGetH264(const char* data, size_t len, uint32_t dts, uint32_t pts) {
if (!len) {
return;
}
_h264frame->_dts = dts;
_h264frame->_pts = pts;
_h264frame->_buffer.assign("\x00\x00\x00\x01", 4); //添加264头
_h264frame->_buffer.append(data, len);
//写入环形缓存
RtmpCodec::inputFrame(_h264frame);
_h264frame = obtainFrame();
void H264RtmpDecoder::outputFrame(const char *data, size_t len, uint32_t dts, uint32_t pts) {
auto frame = FrameImp::create<H264Frame>();
frame->_prefix_size = 4;
frame->_dts = dts;
frame->_pts = pts;
frame->_buffer.assign("\x00\x00\x00\x01", 4); // 添加264头
frame->_buffer.append(data, len);
RtmpCodec::inputFrame(frame);
}
////////////////////////////////////////////////////////////////////////
H264RtmpEncoder::H264RtmpEncoder(const Track::Ptr &track) {
_track = dynamic_pointer_cast<H264Track>(track);
}
void H264RtmpEncoder::makeConfigPacket(){
if (_track && _track->ready()) {
//尝试从track中获取sps pps信息
_sps = _track->getSps();
_pps = _track->getPps();
}
if (!_sps.empty() && !_pps.empty()) {
//获取到sps/pps
makeVideoConfigPkt();
_got_config_frame = true;
}
}
void H264RtmpEncoder::flush() {
inputFrame(nullptr);
}
bool H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
if (frame) {
auto data = frame->data() + frame->prefixSize();
auto len = frame->size() - frame->prefixSize();
auto type = H264_TYPE(data[0]);
switch (type) {
case H264Frame::NAL_SPS: {
if (!_got_config_frame) {
_sps = string(data, len);
makeConfigPacket();
}
break;
}
case H264Frame::NAL_PPS: {
if (!_got_config_frame) {
_pps = string(data, len);
makeConfigPacket();
}
break;
}
default: break;
}
}
if (!_rtmp_packet) {
_rtmp_packet = RtmpPacket::create();
//flags/not config/cts预占位
@@ -173,11 +84,7 @@ bool H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
}, &_rtmp_packet->buffer);
}
void H264RtmpEncoder::makeVideoConfigPkt() {
if (_sps.size() < 4) {
WarnL << "sps长度不足4字节";
return;
}
void H264RtmpEncoder::makeConfigPacket() {
auto flags = (uint8_t)RtmpVideoCodec::h264;
flags |= ((uint8_t)RtmpFrameType::key_frame << 4);
auto pkt = RtmpPacket::create();
@@ -187,23 +94,9 @@ void H264RtmpEncoder::makeVideoConfigPkt() {
// cts
pkt->buffer.append("\x0\x0\x0", 3);
// AVCDecoderConfigurationRecord start
pkt->buffer.push_back(1); // version
pkt->buffer.push_back(_sps[1]); // profile
pkt->buffer.push_back(_sps[2]); // compat
pkt->buffer.push_back(_sps[3]); // level
pkt->buffer.push_back((char)0xff); // 6 bits reserved + 2 bits nal size length - 1 (11)
pkt->buffer.push_back((char)0xe1); // 3 bits reserved + 5 bits number of sps (00001)
// sps
uint16_t size = (uint16_t)_sps.size();
size = htons(size);
pkt->buffer.append((char *)&size, 2);
pkt->buffer.append(_sps);
// pps
pkt->buffer.push_back(1); // version
size = (uint16_t)_pps.size();
size = htons(size);
pkt->buffer.append((char *)&size, 2);
pkt->buffer.append(_pps);
auto extra_data = getTrack()->getExtraData();
CHECK(extra_data);
pkt->buffer.append(extra_data->data(), extra_data->size());
pkt->body_size = pkt->buffer.size();
pkt->chunk_id = CHUNK_VIDEO;

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -24,8 +24,7 @@ class H264RtmpDecoder : public RtmpCodec {
public:
using Ptr = std::shared_ptr<H264RtmpDecoder>;
H264RtmpDecoder();
~H264RtmpDecoder() {}
H264RtmpDecoder(const Track::Ptr &track) : RtmpCodec(track) {}
/**
* 输入264 Rtmp包
@@ -33,24 +32,15 @@ public:
*/
void inputRtmp(const RtmpPacket::Ptr &rtmp) override;
CodecId getCodecId() const override{
return CodecH264;
}
protected:
void onGetH264(const char *data, size_t len, uint32_t dts, uint32_t pts);
H264Frame::Ptr obtainFrame();
protected:
H264Frame::Ptr _h264frame;
std::string _sps;
std::string _pps;
private:
void outputFrame(const char *data, size_t len, uint32_t dts, uint32_t pts);
void splitFrame(const uint8_t *data, size_t size, uint32_t dts, uint32_t pts);
};
/**
* 264 Rtmp打包类
*/
class H264RtmpEncoder : public H264RtmpDecoder{
class H264RtmpEncoder : public RtmpCodec {
public:
using Ptr = std::shared_ptr<H264RtmpEncoder>;
@@ -60,8 +50,7 @@ public:
* 那么inputFrame时可以不输入sps pps
* @param track
*/
H264RtmpEncoder(const Track::Ptr &track);
~H264RtmpEncoder() = default;
H264RtmpEncoder(const Track::Ptr &track) : RtmpCodec(track) {}
/**
* 输入264帧可以不带sps pps
@@ -80,13 +69,8 @@ public:
void makeConfigPacket() override;
private:
void makeVideoConfigPkt();
private:
bool _got_config_frame = false;
H264Track::Ptr _track;
RtmpPacket::Ptr _rtmp_packet;
FrameMerger _merger{FrameMerger::mp4_nal_size};
FrameMerger _merger { FrameMerger::mp4_nal_size };
};
}//namespace mediakit

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -192,10 +192,6 @@ void H264RtpDecoder::outputFrame(const RtpPacket::Ptr &rtp, const H264Frame::Ptr
////////////////////////////////////////////////////////////////////////
H264RtpEncoder::H264RtpEncoder(uint32_t ssrc, uint32_t mtu, uint32_t sample_rate, uint8_t pt, uint8_t interleaved)
: RtpInfo(ssrc, mtu, sample_rate, pt, interleaved) {
}
void H264RtpEncoder::insertConfigFrame(uint64_t pts){
if (!_sps || !_pps) {
return;
@@ -206,7 +202,7 @@ void H264RtpEncoder::insertConfigFrame(uint64_t pts){
}
void H264RtpEncoder::packRtp(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
if (len + 3 <= getMaxSize()) {
if (len + 3 <= getRtpInfo().getMaxSize()) {
// 采用STAP-A/Single NAL unit packet per H.264 模式
packRtpSmallFrame(ptr, len, pts, is_mark, gop_pos);
} else {
@@ -216,7 +212,7 @@ void H264RtpEncoder::packRtp(const char *ptr, size_t len, uint64_t pts, bool is_
}
void H264RtpEncoder::packRtpFu(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
auto packet_size = getMaxSize() - 2;
auto packet_size = getRtpInfo().getMaxSize() - 2;
if (len <= packet_size + 1) {
// 小于FU-A打包最小字节长度要求采用STAP-A/Single NAL unit packet per H.264 模式
packRtpSmallFrame(ptr, len, pts, is_mark, gop_pos);
@@ -238,7 +234,7 @@ void H264RtpEncoder::packRtpFu(const char *ptr, size_t len, uint64_t pts, bool i
}
//传入nullptr先不做payload的内存拷贝
auto rtp = makeRtp(getTrackType(), nullptr, packet_size + 2, fu_flags->end_bit && is_mark, pts);
auto rtp = getRtpInfo().makeRtp(TrackVideo, nullptr, packet_size + 2, fu_flags->end_bit && is_mark, pts);
//rtp payload 负载部分
uint8_t *payload = rtp->getPayload();
//FU-A 第1个字节
@@ -266,7 +262,7 @@ void H264RtpEncoder::packRtpSmallFrame(const char *data, size_t len, uint64_t pt
void H264RtpEncoder::packRtpStapA(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
// 如果帧长度不超过mtu,为了兼容性 webrtc采用STAP-A模式打包
auto rtp = makeRtp(getTrackType(), nullptr, len + 3, is_mark, pts);
auto rtp = getRtpInfo().makeRtp(TrackVideo, nullptr, len + 3, is_mark, pts);
uint8_t *payload = rtp->getPayload();
//STAP-A
payload[0] = (ptr[0] & (~0x1F)) | 24;
@@ -279,7 +275,7 @@ void H264RtpEncoder::packRtpStapA(const char *ptr, size_t len, uint64_t pts, boo
void H264RtpEncoder::packRtpSingleNalu(const char *data, size_t len, uint64_t pts, bool is_mark, bool gop_pos) {
// Single NAL unit packet per H.264 模式
RtpCodec::inputRtp(makeRtp(getTrackType(), data, len, is_mark, pts), gop_pos);
RtpCodec::inputRtp(getRtpInfo().makeRtp(TrackVideo, data, len, is_mark, pts), gop_pos);
}
bool H264RtpEncoder::inputFrame(const Frame::Ptr &frame) {

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -28,7 +28,6 @@ public:
using Ptr = std::shared_ptr<H264RtpDecoder>;
H264RtpDecoder();
~H264RtpDecoder() override = default;
/**
* 输入264 rtp包
@@ -37,10 +36,6 @@ public:
*/
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = true) override;
CodecId getCodecId() const override{
return CodecH264;
}
private:
bool singleFrame(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint64_t stamp);
bool unpackStapA(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint64_t stamp);
@@ -62,26 +57,11 @@ private:
/**
* 264 rtp打包类
*/
class H264RtpEncoder : public H264RtpDecoder ,public RtpInfo{
class H264RtpEncoder : public RtpCodec {
public:
using Ptr = std::shared_ptr<H264RtpEncoder>;
/**
* @param ssrc ssrc
* @param mtu mtu大小
* @param sample_rate 采样率强制为90000
* @param pt pt类型
* @param interleaved rtsp interleaved
*/
H264RtpEncoder(uint32_t ssrc,
uint32_t mtu = 1400,
uint32_t sample_rate = 90000,
uint8_t pt = 96,
uint8_t interleaved = TrackVideo * 2);
~H264RtpEncoder() override = default;
/**
* 输入264帧
* @param frame 帧数据,必须
*/

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -12,6 +12,10 @@
#include "SPSParser.h"
#include "Util/base64.h"
#ifdef ENABLE_MP4
#include "mpeg4-hevc.h"
#endif
using namespace std;
using namespace toolkit;
@@ -58,19 +62,7 @@ H265Track::H265Track(const string &vps,const string &sps, const string &pps,int
_vps = vps.substr(vps_prefix_len);
_sps = sps.substr(sps_prefix_len);
_pps = pps.substr(pps_prefix_len);
onReady();
}
const string &H265Track::getVps() const {
return _vps;
}
const string &H265Track::getSps() const {
return _sps;
}
const string &H265Track::getPps() const {
return _pps;
update();
}
CodecId H265Track::getCodecId() const {
@@ -89,7 +81,7 @@ float H265Track::getVideoFps() const {
return _fps;
}
bool H265Track::ready() {
bool H265Track::ready() const {
return !_vps.empty() && !_sps.empty() && !_pps.empty();
}
@@ -139,25 +131,58 @@ bool H265Track::inputFrame_l(const Frame::Ptr &frame) {
}
}
if (_width == 0 && ready()) {
onReady();
update();
}
return ret;
}
toolkit::Buffer::Ptr H265Track::getExtraData() const {
CHECK(ready());
#ifdef ENABLE_MP4
struct mpeg4_hevc_t hevc;
memset(&hevc, 0, sizeof(hevc));
string vps_sps_pps = string("\x00\x00\x00\x01", 4) + _vps + string("\x00\x00\x00\x01", 4) + _sps + string("\x00\x00\x00\x01", 4) + _pps;
h265_annexbtomp4(&hevc, vps_sps_pps.data(), (int) vps_sps_pps.size(), NULL, 0, NULL, NULL);
std::string extra_data;
extra_data.resize(1024);
auto extra_data_size = mpeg4_hevc_decoder_configuration_record_save(&hevc, (uint8_t *)extra_data.data(), extra_data.size());
if (extra_data_size == -1) {
WarnL << "生成H265 extra_data 失败";
return nullptr;
}
return std::make_shared<BufferString>(std::move(extra_data));
#else
WarnL << "请开启MP4相关功能并使能\"ENABLE_MP4\",否则对H265的支持不完善";
return nullptr;
#endif
}
void H265Track::setExtraData(const uint8_t *data, size_t bytes) {
#ifdef ENABLE_MP4
struct mpeg4_hevc_t hevc;
memset(&hevc, 0, sizeof(hevc));
if (mpeg4_hevc_decoder_configuration_record_load(data, bytes, &hevc) > 0) {
std::vector<uint8_t> config(bytes * 2);
int size = mpeg4_hevc_to_nalu(&hevc, config.data(), bytes * 2);
if (size > 4) {
splitH264((char *)config.data(), size, 4, [&](const char *ptr, size_t len, size_t prefix) {
inputFrame_l(std::make_shared<H265FrameNoCacheAble>((char *)ptr, len, 0, 0, prefix));
});
update();
}
}
#else
WarnL << "请开启MP4相关功能并使能\"ENABLE_MP4\",否则对H265的支持不完善";
#endif
}
bool H265Track::update() {
return getHEVCInfo(_vps, _sps, _width, _height, _fps);
}
void H265Track::onReady() {
if (!getHEVCInfo(_vps, _sps, _width, _height, _fps)) {
_vps.clear();
_sps.clear();
_pps.clear();
}
}
Track::Ptr H265Track::clone() {
return std::make_shared<std::remove_reference<decltype(*this)>::type>(*this);
Track::Ptr H265Track::clone() const {
return std::make_shared<H265Track>(*this);
}
void H265Track::insertConfigFrame(const Frame::Ptr &frame) {
@@ -205,17 +230,13 @@ public:
* @param payload_type rtp payload type 默认96
* @param bitrate 比特率
*/
H265Sdp(const string &strVPS,
const string &strSPS,
const string &strPPS,
int bitrate = 4000,
int payload_type = 96) : Sdp(90000,payload_type) {
H265Sdp(const string &strVPS, const string &strSPS, const string &strPPS, int payload_type, int bitrate) : Sdp(90000, payload_type) {
//视频通道
_printer << "m=video 0 RTP/AVP " << payload_type << "\r\n";
if (bitrate) {
_printer << "b=AS:" << bitrate << "\r\n";
}
_printer << "a=rtpmap:" << payload_type << " " << getCodecName() << "/" << 90000 << "\r\n";
_printer << "a=rtpmap:" << payload_type << " " << getCodecName(CodecH265) << "/" << 90000 << "\r\n";
_printer << "a=fmtp:" << payload_type << " ";
_printer << "sprop-vps=";
_printer << encodeBase64(strVPS) << "; ";
@@ -223,26 +244,20 @@ public:
_printer << encodeBase64(strSPS) << "; ";
_printer << "sprop-pps=";
_printer << encodeBase64(strPPS) << "\r\n";
_printer << "a=control:trackID=" << (int)TrackVideo << "\r\n";
}
string getSdp() const override {
return _printer;
}
string getSdp() const override { return _printer; }
CodecId getCodecId() const override {
return CodecH265;
}
private:
_StrPrinter _printer;
};
Sdp::Ptr H265Track::getSdp() {
if(!ready()){
Sdp::Ptr H265Track::getSdp(uint8_t payload_type) const {
if (!ready()) {
WarnL << getCodecName() << " Track未准备好";
return nullptr;
}
return std::make_shared<H265Sdp>(getVps(), getSps(), getPps(), getBitRate() / 1024);
return std::make_shared<H265Sdp>(_vps, _sps, _pps, payload_type, getBitRate() / 1024);
}
}//namespace mediakit

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -19,8 +19,6 @@
namespace mediakit {
bool getHEVCInfo(const std::string &strVps, const std::string &strSps, int &iVideoWidth, int &iVideoHeight, float &iVideoFps);
template<typename Parent>
class H265FrameHelper : public Parent{
public:
@@ -64,8 +62,6 @@ public:
this->_codec_id = CodecH265;
}
~H265FrameHelper() override = default;
bool keyFrame() const override {
auto nal_ptr = (uint8_t *) this->data() + this->prefixSize();
auto type = H265_TYPE(*nal_ptr);
@@ -137,25 +133,19 @@ public:
*/
H265Track(const std::string &vps,const std::string &sps, const std::string &pps,int vps_prefix_len = 4, int sps_prefix_len = 4, int pps_prefix_len = 4);
/**
* 返回不带0x00 00 00 01头的vps/sps/pps
*/
const std::string &getVps() const;
const std::string &getSps() const;
const std::string &getPps() const;
bool ready() override;
bool ready() const override;
CodecId getCodecId() const override;
int getVideoWidth() const override;
int getVideoHeight() const override;
float getVideoFps() const override;
bool inputFrame(const Frame::Ptr &frame) override;
toolkit::Buffer::Ptr getExtraData() const override;
void setExtraData(const uint8_t *data, size_t size) override;
bool update() override;
private:
void onReady();
Sdp::Ptr getSdp() override;
Track::Ptr clone() override;
Sdp::Ptr getSdp(uint8_t payload_type) const override;
Track::Ptr clone() const override;
bool inputFrame_l(const Frame::Ptr &frame);
void insertConfigFrame(const Frame::Ptr &frame);

View File

@@ -1,15 +1,16 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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 "Rtmp/utils.h"
#include "H265Rtmp.h"
#include "Rtmp/utils.h"
#include "Common/config.h"
#ifdef ENABLE_MP4
#include "mpeg4-hevc.h"
#endif // ENABLE_MP4
@@ -19,48 +20,6 @@ using namespace toolkit;
namespace mediakit {
H265RtmpDecoder::H265RtmpDecoder() {
_h265frame = obtainFrame();
}
H265Frame::Ptr H265RtmpDecoder::obtainFrame() {
auto frame = FrameImp::create<H265Frame>();
frame->_prefix_size = 4;
return frame;
}
#ifdef ENABLE_MP4
static bool decode_HEVCDecoderConfigurationRecord(uint8_t *extra, size_t bytes, string &frame) {
struct mpeg4_hevc_t hevc;
memset(&hevc, 0, sizeof(hevc));
if (mpeg4_hevc_decoder_configuration_record_load((uint8_t *)extra, bytes, &hevc) > 0) {
uint8_t *config = new uint8_t[bytes * 2];
int size = mpeg4_hevc_to_nalu(&hevc, config, bytes * 2);
if (size > 4) {
frame.assign((char *)config + 4, size - 4);
}
delete[] config;
return size > 4;
}
return false;
}
/**
* 返回不带0x00 00 00 01头的sps
*/
static bool getH265ConfigFrame(const RtmpPacket &thiz, string &frame) {
if ((RtmpVideoCodec)thiz.getRtmpCodecId() != RtmpVideoCodec::h265) {
return false;
}
if (thiz.buffer.size() < 6) {
WarnL << "bad H265 cfg!";
return false;
}
return decode_HEVCDecoderConfigurationRecord((uint8_t *)thiz.buffer.data() + 5, thiz.buffer.size() - 5, frame);
}
#endif
void H265RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) {
if (_info.codec == CodecInvalid) {
// 先判断是否为增强型rtmp
@@ -73,75 +32,47 @@ void H265RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) {
if (!_info.is_enhanced || _info.codec != CodecH265) {
throw std::invalid_argument("Invalid enhanced-rtmp hevc packet!");
}
auto data = (uint8_t *)pkt->data() + 5;
auto size = pkt->size() - 5;
switch (_info.video.pkt_type) {
case RtmpPacketType::PacketTypeSequenceStart: {
#ifdef ENABLE_MP4
string config;
if (decode_HEVCDecoderConfigurationRecord(data, size, config)) {
onGetH265(config.data(), config.size(), pkt->time_stamp, pkt->time_stamp);
}
#else
WarnL << "请开启MP4相关功能并使能\"ENABLE_MP4\",否则对H265-RTMP支持不完善";
#endif
getTrack()->setExtraData((uint8_t *)pkt->data() + RtmpPacketInfo::kEnhancedRtmpHeaderSize, pkt->size() - RtmpPacketInfo::kEnhancedRtmpHeaderSize);
break;
}
case RtmpPacketType::PacketTypeCodedFramesX:
case RtmpPacketType::PacketTypeCodedFrames: {
auto data = (uint8_t *)pkt->data() + RtmpPacketInfo::kEnhancedRtmpHeaderSize;
auto size = pkt->size() - RtmpPacketInfo::kEnhancedRtmpHeaderSize;
auto pts = pkt->time_stamp;
CHECK(size > 3);
if (RtmpPacketType::PacketTypeCodedFrames == _info.video.pkt_type) {
// SI24 = [CompositionTime Offset]
CHECK(size > 7);
int32_t cts = (((data[0] << 16) | (data[1] << 8) | (data[2])) + 0xff800000) ^ 0xff800000;
pts += cts;
data += 3;
size -= 3;
}
CHECK(size > 4);
splitFrame(data, size, pkt->time_stamp, pts);
break;
}
case RtmpPacketType::PacketTypeMetadata: {
// The body does not contain video data. The body is an AMF encoded metadata.
// The metadata will be represented by a series of [name, value] pairs.
// For now the only defined [name, value] pair is [“colorInfo”, Object]
// See Metadata Frame section for more details of this object.
//
// For a deeper understanding of the encoding please see description
// of SCRIPTDATA and SSCRIPTDATAVALUE in the FLV file spec.
// DATA = [“colorInfo”, Object]
break;
}
case RtmpPacketType::PacketTypeSequenceEnd: {
// signals end of sequence
break;
}
default: break;
default: WarnL << "Unknown pkt_type: " << (int)_info.video.pkt_type; break;
}
return;
}
// 国内扩展(12) H265 rtmp
if (pkt->isConfigFrame()) {
#ifdef ENABLE_MP4
string config;
if (getH265ConfigFrame(*pkt, config)) {
onGetH265(config.data(), config.size(), pkt->time_stamp, pkt->time_stamp);
}
#else
WarnL << "请开启MP4相关功能并使能\"ENABLE_MP4\",否则对H265-RTMP支持不完善";
#endif
CHECK(pkt->size() > 5);
getTrack()->setExtraData((uint8_t *)pkt->data() + 5, pkt->size() - 5);
return;
}
if (pkt->buffer.size() > 9) {
uint8_t *cts_ptr = (uint8_t *)(pkt->buffer.data() + 2);
int32_t cts = (((cts_ptr[0] << 16) | (cts_ptr[1] << 8) | (cts_ptr[2])) + 0xff800000) ^ 0xff800000;
auto pts = pkt->time_stamp + cts;
splitFrame((uint8_t *)pkt->data() + 5, pkt->size() - 5, pkt->time_stamp, pts);
}
CHECK(pkt->size() > 9);
uint8_t *cts_ptr = (uint8_t *)(pkt->buffer.data() + 2);
int32_t cts = (((cts_ptr[0] << 16) | (cts_ptr[1] << 8) | (cts_ptr[2])) + 0xff800000) ^ 0xff800000;
auto pts = pkt->time_stamp + cts;
splitFrame((uint8_t *)pkt->data() + 5, pkt->size() - 5, pkt->time_stamp, pts);
}
void H265RtmpDecoder::splitFrame(const uint8_t *data, size_t size, uint32_t dts, uint32_t pts) {
@@ -152,100 +83,51 @@ void H265RtmpDecoder::splitFrame(const uint8_t *data, size_t size, uint32_t dts,
if (data + frame_len > end) {
break;
}
onGetH265((const char *)data, frame_len, dts, pts);
outputFrame((const char *)data, frame_len, dts, pts);
data += frame_len;
}
}
inline void H265RtmpDecoder::onGetH265(const char *data, size_t size, uint32_t dts, uint32_t pts) {
if (size == 0) {
return;
}
#if 1
_h265frame->_dts = dts;
_h265frame->_pts = pts;
_h265frame->_buffer.assign("\x00\x00\x00\x01", 4); // 添加265头
_h265frame->_buffer.append(data, size);
// 写入环形缓存
RtmpCodec::inputFrame(_h265frame);
_h265frame = obtainFrame();
#else
// 防止内存拷贝这样产生的265帧不会有0x00 00 01头
auto frame = std::make_shared<H265FrameNoCacheAble>((char *)data, size, dts, pts, 0);
inline void H265RtmpDecoder::outputFrame(const char *data, size_t size, uint32_t dts, uint32_t pts) {
auto frame = FrameImp::create<H265Frame>();
frame->_prefix_size = 4;
frame->_dts = dts;
frame->_pts = pts;
frame->_buffer.assign("\x00\x00\x00\x01", 4); // 添加265头
frame->_buffer.append(data, size);
RtmpCodec::inputFrame(frame);
#endif
}
////////////////////////////////////////////////////////////////////////
H265RtmpEncoder::H265RtmpEncoder(const Track::Ptr &track) {
_track = dynamic_pointer_cast<H265Track>(track);
}
void H265RtmpEncoder::makeConfigPacket() {
if (_track && _track->ready()) {
// 尝试从track中获取sps pps信息
_sps = _track->getSps();
_pps = _track->getPps();
_vps = _track->getVps();
}
if (!_sps.empty() && !_pps.empty() && !_vps.empty()) {
// 获取到sps/pps
makeVideoConfigPkt();
_got_config_frame = true;
}
}
void H265RtmpEncoder::flush() {
inputFrame(nullptr);
}
bool H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
if (frame) {
auto data = frame->data() + frame->prefixSize();
auto len = frame->size() - frame->prefixSize();
auto type = H265_TYPE(data[0]);
switch (type) {
case H265Frame::NAL_SPS: {
if (!_got_config_frame) {
_sps = string(data, len);
makeConfigPacket();
}
break;
}
case H265Frame::NAL_PPS: {
if (!_got_config_frame) {
_pps = string(data, len);
makeConfigPacket();
}
break;
}
case H265Frame::NAL_VPS: {
if (!_got_config_frame) {
_vps = string(data, len);
makeConfigPacket();
}
break;
}
default: break;
}
}
if (!_rtmp_packet) {
_rtmp_packet = RtmpPacket::create();
// flags/not_config/cts预占位
_rtmp_packet->buffer.resize(5);
GET_CONFIG(bool, enhanced, Rtmp::kEnhanced);
_rtmp_packet->buffer.resize((enhanced ? RtmpPacketInfo::kEnhancedRtmpHeaderSize : 2) + 3);
}
return _merger.inputFrame(frame, [this](uint64_t dts, uint64_t pts, const Buffer::Ptr &, bool have_key_frame) {
// flags
_rtmp_packet->buffer[0] = (uint8_t)RtmpVideoCodec::h265 | ((uint8_t)(have_key_frame ? RtmpFrameType::key_frame : RtmpFrameType::inter_frame) << 4);
_rtmp_packet->buffer[1] = (uint8_t)RtmpH264PacketType::h264_nalu;
GET_CONFIG(bool, enhanced, Rtmp::kEnhanced);
if (enhanced) {
auto header = (RtmpVideoHeaderEnhanced *)_rtmp_packet->data();
header->enhanced = 1;
header->pkt_type = (int)RtmpPacketType::PacketTypeCodedFrames;
header->frame_type = have_key_frame ? (int)RtmpFrameType::key_frame : (int)RtmpFrameType::inter_frame;
header->fourcc = htonl((uint32_t)RtmpVideoCodec::fourcc_hevc);
} else {
// flags
_rtmp_packet->buffer[0] = (uint8_t)RtmpVideoCodec::h265 | ((uint8_t)(have_key_frame ? RtmpFrameType::key_frame : RtmpFrameType::inter_frame) << 4);
_rtmp_packet->buffer[1] = (uint8_t)RtmpH264PacketType::h264_nalu;
}
int32_t cts = pts - dts;
// cts
set_be24(&_rtmp_packet->buffer[2], cts);
set_be24(&_rtmp_packet->buffer[enhanced ? 5 : 2], cts);
_rtmp_packet->time_stamp = dts;
_rtmp_packet->body_size = _rtmp_packet->buffer.size();
_rtmp_packet->chunk_id = CHUNK_VIDEO;
@@ -257,38 +139,36 @@ bool H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
}, &_rtmp_packet->buffer);
}
void H265RtmpEncoder::makeVideoConfigPkt() {
#ifdef ENABLE_MP4
auto flags = (uint8_t)RtmpVideoCodec::h265;
flags |= ((uint8_t)RtmpFrameType::key_frame << 4);
void H265RtmpEncoder::makeConfigPacket() {
auto pkt = RtmpPacket::create();
// header
pkt->buffer.push_back(flags);
pkt->buffer.push_back((uint8_t)RtmpH264PacketType::h264_config_header);
// cts
pkt->buffer.append("\x0\x0\x0", 3);
struct mpeg4_hevc_t hevc;
memset(&hevc, 0, sizeof(hevc));
string vps_sps_pps = string("\x00\x00\x00\x01", 4) + _vps + string("\x00\x00\x00\x01", 4) + _sps + string("\x00\x00\x00\x01", 4) + _pps;
h265_annexbtomp4(&hevc, vps_sps_pps.data(), (int)vps_sps_pps.size(), NULL, 0, NULL, NULL);
uint8_t extra_data[1024];
int extra_data_size = mpeg4_hevc_decoder_configuration_record_save(&hevc, extra_data, sizeof(extra_data));
if (extra_data_size == -1) {
WarnL << "生成H265 extra_data 失败";
return;
GET_CONFIG(bool, enhanced, Rtmp::kEnhanced);
if (enhanced) {
pkt->buffer.resize(RtmpPacketInfo::kEnhancedRtmpHeaderSize);
auto header = (RtmpVideoHeaderEnhanced *)pkt->data();
header->enhanced = 1;
header->pkt_type = (int)RtmpPacketType::PacketTypeSequenceStart;
header->frame_type = (int)RtmpFrameType::key_frame;
header->fourcc = htonl((uint32_t)RtmpVideoCodec::fourcc_hevc);
} else {
auto flags = (uint8_t)RtmpVideoCodec::h265;
flags |= ((uint8_t)RtmpFrameType::key_frame << 4);
// header
pkt->buffer.push_back(flags);
pkt->buffer.push_back((uint8_t)RtmpH264PacketType::h264_config_header);
// cts
pkt->buffer.append("\x0\x0\x0", 3);
}
// HEVCDecoderConfigurationRecord
pkt->buffer.append((char *)extra_data, extra_data_size);
auto extra_data = getTrack()->getExtraData();
CHECK(extra_data);
pkt->buffer.append(extra_data->data(), extra_data->size());
pkt->body_size = pkt->buffer.size();
pkt->chunk_id = CHUNK_VIDEO;
pkt->stream_index = STREAM_MEDIA;
pkt->time_stamp = 0;
pkt->type_id = MSG_VIDEO;
RtmpCodec::inputRtmp(pkt);
#else
WarnL << "请开启MP4相关功能并使能\"ENABLE_MP4\",否则对H265-RTMP支持不完善";
#endif
}
} // namespace mediakit

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -24,8 +24,7 @@ class H265RtmpDecoder : public RtmpCodec {
public:
using Ptr = std::shared_ptr<H265RtmpDecoder>;
H265RtmpDecoder();
~H265RtmpDecoder() = default;
H265RtmpDecoder(const Track::Ptr &track) : RtmpCodec(track) {}
/**
* 输入265 Rtmp包
@@ -33,23 +32,18 @@ public:
*/
void inputRtmp(const RtmpPacket::Ptr &rtmp) override;
CodecId getCodecId() const override { return CodecH265; }
protected:
H265Frame::Ptr obtainFrame();
void onGetH265(const char *data, size_t size, uint32_t dts, uint32_t pts);
void outputFrame(const char *data, size_t size, uint32_t dts, uint32_t pts);
void splitFrame(const uint8_t *data, size_t size, uint32_t dts, uint32_t pts);
protected:
RtmpPacketInfo _info;
H265Frame::Ptr _h265frame;
};
/**
* 265 Rtmp打包类
*/
class H265RtmpEncoder : public H265RtmpDecoder {
class H265RtmpEncoder : public RtmpCodec {
public:
using Ptr = std::shared_ptr<H265RtmpEncoder>;
@@ -59,8 +53,7 @@ public:
* 那么inputFrame时可以不输入sps pps
* @param track
*/
H265RtmpEncoder(const Track::Ptr &track);
~H265RtmpEncoder() = default;
H265RtmpEncoder(const Track::Ptr &track) : RtmpCodec(track) {}
/**
* 输入265帧可以不带sps pps
@@ -79,14 +72,6 @@ public:
void makeConfigPacket() override;
private:
void makeVideoConfigPkt();
private:
bool _got_config_frame = false;
std::string _vps;
std::string _sps;
std::string _pps;
H265Track::Ptr _track;
RtmpPacket::Ptr _rtmp_packet;
FrameMerger _merger { FrameMerger::mp4_nal_size };
};

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -248,20 +248,8 @@ void H265RtpDecoder::outputFrame(const RtpPacket::Ptr &rtp, const H265Frame::Ptr
////////////////////////////////////////////////////////////////////////
H265RtpEncoder::H265RtpEncoder(uint32_t ui32Ssrc,
uint32_t ui32MtuSize,
uint32_t ui32SampleRate,
uint8_t ui8PayloadType,
uint8_t ui8Interleaved) :
RtpInfo(ui32Ssrc,
ui32MtuSize,
ui32SampleRate,
ui8PayloadType,
ui8Interleaved) {
}
void H265RtpEncoder::packRtpFu(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
auto max_size = getMaxSize() - 3;
auto max_size = getRtpInfo().getMaxSize() - 3;
auto nal_type = H265_TYPE(ptr[0]); //获取NALU的5bit 帧类型
unsigned char s_e_flags;
bool fu_start = true;
@@ -283,7 +271,7 @@ void H265RtpEncoder::packRtpFu(const char *ptr, size_t len, uint64_t pts, bool i
{
// 传入nullptr先不做payload的内存拷贝
auto rtp = makeRtp(getTrackType(), nullptr, max_size + 3, mark_bit, pts);
auto rtp = getRtpInfo().makeRtp(TrackVideo, nullptr, max_size + 3, mark_bit, pts);
// rtp payload 负载部分
uint8_t *payload = rtp->getPayload();
// FU 第1个字节表明为FU
@@ -304,9 +292,9 @@ void H265RtpEncoder::packRtpFu(const char *ptr, size_t len, uint64_t pts, bool i
}
void H265RtpEncoder::packRtp(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
if (len <= getMaxSize()) {
if (len <= getRtpInfo().getMaxSize()) {
//signal-nalu
RtpCodec::inputRtp(makeRtp(getTrackType(), ptr, len, is_mark, pts), gop_pos);
RtpCodec::inputRtp(getRtpInfo().makeRtp(TrackVideo, ptr, len, is_mark, pts), gop_pos);
} else {
//FU-A模式
packRtpFu(ptr, len, pts, is_mark, gop_pos);

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -28,7 +28,6 @@ public:
using Ptr = std::shared_ptr<H265RtpDecoder>;
H265RtpDecoder();
~H265RtpDecoder() {}
/**
* 输入265 rtp包
@@ -37,10 +36,6 @@ public:
*/
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = true) override;
CodecId getCodecId() const override{
return CodecH265;
}
private:
bool unpackAp(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint64_t stamp);
bool mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint64_t stamp, uint16_t seq);
@@ -63,24 +58,10 @@ private:
/**
* 265 rtp打包类
*/
class H265RtpEncoder : public H265RtpDecoder ,public RtpInfo{
class H265RtpEncoder : public RtpCodec {
public:
using Ptr = std::shared_ptr<H265RtpEncoder>;
/**
* @param ui32Ssrc ssrc
* @param ui32MtuSize mtu大小
* @param ui32SampleRate 采样率强制为90000
* @param ui8PayloadType pt类型
* @param ui8Interleaved rtsp interleaved
*/
H265RtpEncoder(uint32_t ui32Ssrc,
uint32_t ui32MtuSize = 1400,
uint32_t ui32SampleRate = 90000,
uint8_t ui8PayloadType = 96,
uint8_t ui8Interleaved = TrackVideo * 2);
~H265RtpEncoder() {}
/**
* 输入265帧
* @param frame 帧数据,必须

View File

@@ -31,23 +31,20 @@ void JPEGTrack::getVideoResolution(const uint8_t *buf, int len) {
class JPEGSdp : public Sdp {
public:
JPEGSdp(int bitrate): Sdp(90000, Rtsp::PT_JPEG) {
JPEGSdp(int bitrate) : Sdp(90000, Rtsp::PT_JPEG) {
_printer << "m=video 0 RTP/AVP " << (int)getPayloadType() << "\r\n";
if (bitrate) {
_printer << "b=AS:" << bitrate << "\r\n";
}
_printer << "a=control:trackID=" << (int)TrackVideo << "\r\n";
}
std::string getSdp() const { return _printer; }
CodecId getCodecId() const { return CodecJPEG; }
private:
_StrPrinter _printer;
};
Sdp::Ptr JPEGTrack::getSdp() {
Sdp::Ptr JPEGTrack::getSdp(uint8_t) const {
return std::make_shared<JPEGSdp>(getBitRate() / 1024);
}
} // namespace mediakit

View File

@@ -14,12 +14,12 @@ public:
int getVideoHeight() const override { return _height; }
int getVideoWidth() const override { return _width; }
float getVideoFps() const override { return _fps; }
bool ready() override { return _fps > 0; }
bool ready() const override { return _fps > 0; }
bool inputFrame(const Frame::Ptr &frame) override;
private:
Sdp::Ptr getSdp() override;
Track::Ptr clone() override { return std::make_shared<std::remove_reference<decltype(*this)>::type>(*this); }
Sdp::Ptr getSdp(uint8_t payload_type) const override;
Track::Ptr clone() const override { return std::make_shared<JPEGTrack>(*this); }
void getVideoResolution(const uint8_t *buf, int len);
private:
@@ -29,39 +29,34 @@ private:
uint64_t _tmp = 0;
};
class JPEGFrame : public Frame {
class JPEGFrameType {
public:
virtual ~JPEGFrameType() = default;
virtual uint8_t pixType() const = 0;
};
template <typename Parent>
class JPEGFrame : public Parent, public JPEGFrameType {
public:
static constexpr auto kJFIFSize = 20u;
/**
* JPEG/MJPEG帧
* @param buffer 帧数据
* @param dts 时间戳,单位毫秒
* @param pix_type pixel format type; AV_PIX_FMT_YUVJ422P || (AVCOL_RANGE_JPEG && AV_PIX_FMT_YUV422P) : 1; AV_PIX_FMT_YUVJ420P || (AVCOL_RANGE_JPEG && AV_PIX_FMT_YUV420P) : 0
* @param prefix_size JFIF头大小
*/
JPEGFrame(toolkit::Buffer::Ptr buffer, uint64_t dts, uint8_t pix_type = 0, size_t prefix_size = 0) {
_buffer = std::move(buffer);
_dts = dts;
template <typename... ARGS>
JPEGFrame(uint8_t pix_type, ARGS &&...args) : Parent(std::forward<ARGS>(args)...) {
_pix_type = pix_type;
_prefix_size = prefix_size;
// JFIF头固定20个字节长度
CHECK(this->size() > kJFIFSize);
}
~JPEGFrame() override = default;
uint64_t dts() const override { return _dts; }
size_t prefixSize() const override { return _prefix_size; }
size_t prefixSize() const override { return 0; }
bool keyFrame() const override { return true; }
bool configFrame() const override { return false; }
CodecId getCodecId() const override { return CodecJPEG; }
char *data() const override { return _buffer->data(); }
size_t size() const override { return _buffer->size(); }
uint8_t pixType() const {return _pix_type; }
uint8_t pixType() const override { return _pix_type; }
private:
uint8_t _pix_type;
size_t _prefix_size;
uint64_t _dts;
toolkit::Buffer::Ptr _buffer;
};
}//namespace mediakit

View File

@@ -745,10 +745,10 @@ void JPEGRtpEncoder::rtpSendJpeg(const uint8_t *buf, int size, uint64_t pts, uin
hdr_size += 4 + 64 * nb_qtables;
/* payload max in one packet */
len = MIN(size, (int)getMaxSize() - hdr_size);
len = MIN(size, (int)getRtpInfo().getMaxSize() - hdr_size);
/* marker bit is last packet in frame */
auto rtp_packet = makeRtp(getTrackType(), nullptr, len + hdr_size, size == len, pts);
auto rtp_packet = getRtpInfo().makeRtp(TrackVideo, nullptr, len + hdr_size, size == len, pts);
p = rtp_packet->getPayload();
/* set main header */
@@ -788,9 +788,7 @@ JPEGRtpDecoder::JPEGRtpDecoder() {
memset(&_ctx.timestamp, 0, sizeof(_ctx) - offsetof(decltype(_ctx), timestamp));
}
CodecId JPEGRtpDecoder::getCodecId() const {
return CodecJPEG;
}
using JPEGFrameImp = JPEGFrame<FrameFromBuffer<FrameFromPtr> >;
bool JPEGRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool) {
auto payload = rtp->getPayload();
@@ -806,8 +804,7 @@ bool JPEGRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool) {
uint8_t type;
if (0 == jpeg_parse_packet(nullptr, &_ctx, &stamp, payload, size, seq, marker ? RTP_FLAG_MARKER : 0, &type)) {
auto buffer = std::make_shared<toolkit::BufferString>(std::move(_ctx.frame));
// JFIF头固定20个字节长度
auto frame = std::make_shared<JPEGFrame>(std::move(buffer), stamp / 90, type, 20);
auto frame = std::make_shared<JPEGFrameImp>(type, std::move(buffer), stamp / 90, 0);
_ctx.frame.clear();
RtpCodec::inputFrame(std::move(frame));
}
@@ -817,17 +814,13 @@ bool JPEGRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool) {
////////////////////////////////////////////////////////////////////////
JPEGRtpEncoder::JPEGRtpEncoder(
uint32_t ssrc, uint32_t mtu, uint32_t sample_rate, uint8_t payload_type, uint8_t interleaved)
: RtpInfo(ssrc, mtu, sample_rate, payload_type, interleaved) {}
bool JPEGRtpEncoder::inputFrame(const Frame::Ptr &frame) {
auto ptr = (uint8_t *)frame->data() + frame->prefixSize();
auto len = frame->size() - frame->prefixSize();
// JFIF头固定20个字节长度
auto ptr = (uint8_t *)frame->data() + frame->prefixSize() + JPEGFrameImp::kJFIFSize;
auto len = frame->size() - frame->prefixSize() - JPEGFrameImp::kJFIFSize;
auto pts = frame->pts();
auto type = 1;
auto jpeg = dynamic_pointer_cast<JPEGFrame>(frame);
auto jpeg = dynamic_pointer_cast<JPEGFrameType>(frame);
if (jpeg) {
type = jpeg->pixType();
}

View File

@@ -25,12 +25,6 @@ public:
typedef std::shared_ptr <JPEGRtpDecoder> Ptr;
JPEGRtpDecoder();
~JPEGRtpDecoder() override = default;
/**
* 返回编码类型ID
*/
CodecId getCodecId() const override;
/**
* 输入rtp并解码
@@ -43,13 +37,10 @@ private:
struct PayloadContext _ctx;
};
class JPEGRtpEncoder : public JPEGRtpDecoder, public RtpInfo {
class JPEGRtpEncoder : public RtpCodec {
public:
using Ptr = std::shared_ptr<JPEGRtpEncoder>;
JPEGRtpEncoder(uint32_t ssrc, uint32_t mtu = 1400, uint32_t sample_rate = 90000, uint8_t payload_type = 96, uint8_t interleaved = TrackVideo * 2);
~JPEGRtpEncoder() = default;
bool inputFrame(const Frame::Ptr &frame) override;
private:

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -22,47 +22,36 @@ class L16Sdp : public Sdp {
public:
/**
* L16采样位数固定为16位
* @param codecId CodecL16
* @param payload_type rtp payload type
* @param channels 通道数
* @param sample_rate 音频采样率
* @param payload_type rtp payload
* @param bitrate 比特率
*/
L16Sdp(CodecId codecId,
int sample_rate,
int channels,
int bitrate = 128,
int payload_type = 98) : Sdp(sample_rate,payload_type), _codecId(codecId){
L16Sdp(int payload_type, int sample_rate, int channels, int bitrate) : Sdp(sample_rate, payload_type) {
_printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n";
if (bitrate) {
_printer << "b=AS:" << bitrate << "\r\n";
}
_printer << "a=rtpmap:" << payload_type << " " << getCodecName() << "/" << sample_rate << "/" << channels << "\r\n";
_printer << "a=control:trackID=" << (int)TrackAudio << "\r\n";
_printer << "a=rtpmap:" << payload_type << " " << getCodecName(CodecL16) << "/" << sample_rate << "/" << channels << "\r\n";
}
string getSdp() const override {
return _printer;
}
string getSdp() const override { return _printer; }
CodecId getCodecId() const override {
return _codecId;
}
private:
_StrPrinter _printer;
CodecId _codecId;
};
Sdp::Ptr L16Track::getSdp() {
Sdp::Ptr L16Track::getSdp(uint8_t payload_type) const {
WarnL << "Enter L16Track::getSdp function";
if(!ready()){
if (!ready()) {
WarnL << getCodecName() << " Track未准备好";
return nullptr;
}
return std::make_shared<L16Sdp>(getCodecId(), getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024);
return std::make_shared<L16Sdp>(payload_type, getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024);
}
Track::Ptr L16Track::clone() {
return std::make_shared<std::remove_reference<decltype(*this)>::type >(*this);
Track::Ptr L16Track::clone() const {
return std::make_shared<L16Track>(*this);
}
}//namespace mediakit

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -25,8 +25,8 @@ public:
L16Track(int sample_rate, int channels) : AudioTrackImp(CodecL16,sample_rate,channels,16){}
private:
Sdp::Ptr getSdp() override;
Track::Ptr clone() override;
Sdp::Ptr getSdp(uint8_t payload_type) const override;
Track::Ptr clone() const override;
};
}//namespace mediakit

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -22,39 +22,33 @@ class OpusSdp : public Sdp {
public:
/**
* 构造opus sdp
* @param payload_type rtp payload type
* @param sample_rate 音频采样率
* @param payload_type rtp payload
* @param channels 通道数
* @param bitrate 比特率
*/
OpusSdp(int sample_rate,
int channels,
int bitrate = 128,
int payload_type = 98) : Sdp(sample_rate,payload_type){
OpusSdp(int payload_type, int sample_rate, int channels, int bitrate) : Sdp(sample_rate, payload_type) {
_printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n";
if (bitrate) {
_printer << "b=AS:" << bitrate << "\r\n";
}
_printer << "a=rtpmap:" << payload_type << " " << getCodecName() << "/" << sample_rate << "/" << channels << "\r\n";
_printer << "a=control:trackID=" << (int)TrackAudio << "\r\n";
_printer << "a=rtpmap:" << payload_type << " " << getCodecName(CodecOpus) << "/" << sample_rate << "/" << channels << "\r\n";
}
string getSdp() const override {
return _printer;
}
CodecId getCodecId() const override {
return CodecOpus;
}
private:
_StrPrinter _printer;
};
Sdp::Ptr OpusTrack::getSdp() {
if(!ready()){
Sdp::Ptr OpusTrack::getSdp(uint8_t payload_type) const {
if (!ready()) {
WarnL << getCodecName() << " Track未准备好";
return nullptr;
}
return std::make_shared<OpusSdp>(getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024);
return std::make_shared<OpusSdp>(payload_type, getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024);
}
}//namespace mediakit

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -26,11 +26,11 @@ public:
private:
//克隆该Track
Track::Ptr clone() override {
return std::make_shared<std::remove_reference<decltype(*this)>::type >(*this);
Track::Ptr clone() const override {
return std::make_shared<OpusTrack>(*this);
}
//生成sdp
Sdp::Ptr getSdp() override ;
Sdp::Ptr getSdp(uint8_t payload_type) const override ;
};
}//namespace mediakit

View File

@@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@@ -21,23 +21,32 @@ namespace mediakit{
/**
* 媒体通道描述类,也支持帧输入输出
*/
class Track : public FrameDispatcher , public CodecInfo{
class Track : public FrameDispatcher, public CodecInfo {
public:
using Ptr = std::shared_ptr<Track>;
/**
* 默认构造
*/
Track() = default;
virtual ~Track() = default;
/**
* 复制拷贝,只能拷贝派生类的信息,
* 环形缓存和代理关系不能拷贝,否则会关系紊乱
*/
Track(const Track &that) { _bit_rate = that._bit_rate; }
/**
* 是否准备好准备好才能获取譬如sps pps等信息
*/
virtual bool ready() = 0;
virtual bool ready() const = 0;
/**
* 克隆接口,用于复制本对象用
* 在调用该接口时只会复制派生类的信息
* 环形缓存和代理关系不能拷贝,否则会关系紊乱
*/
virtual Track::Ptr clone() = 0;
virtual Track::Ptr clone() const = 0;
/**
* 更新track信息比如触发sps/pps解析
@@ -46,9 +55,19 @@ public:
/**
* 生成sdp
* @return sdp对象
* @return sdp对象
*/
virtual Sdp::Ptr getSdp() = 0;
virtual Sdp::Ptr getSdp(uint8_t payload_type) const = 0;
/**
* 获取extra data, 一般用于rtmp/mp4生成
*/
virtual toolkit::Buffer::Ptr getExtraData() const { return nullptr; }
/**
* 设置extra data
*/
virtual void setExtraData(const uint8_t *data, size_t size) {}
/**
* 返回比特率
@@ -62,14 +81,6 @@ public:
*/
virtual void setBitRate(int bit_rate) { _bit_rate = bit_rate; }
/**
* 复制拷贝,只能拷贝派生类的信息,
* 环形缓存和代理关系不能拷贝,否则会关系紊乱
*/
Track(const Track &that){
_bit_rate = that._bit_rate;
}
private:
int _bit_rate = 0;
};
@@ -97,6 +108,40 @@ public:
virtual float getVideoFps() const { return 0; }
};
class VideoTrackImp : public VideoTrack {
public:
using Ptr = std::shared_ptr<VideoTrackImp>;
/**
* 构造函数
* @param codec_id 编码类型
* @param width 宽
* @param height 高
* @param fps 帧率
*/
VideoTrackImp(CodecId codec_id, int width, int height, int fps) {
_codec_id = codec_id;
_width = width;
_height = height;
_fps = fps;
}
int getVideoHeight() const override { return _width; }
int getVideoWidth() const override { return _height; }
float getVideoFps() const override { return _fps; }
bool ready() const override { return true; }
Track::Ptr clone() const override { return std::make_shared<VideoTrackImp>(*this); }
Sdp::Ptr getSdp(uint8_t payload_type) const override { return nullptr; }
CodecId getCodecId() const override { return _codec_id; }
private:
CodecId _codec_id;
int _width = 0;
int _height = 0;
float _fps = 0;
};
/**
* 音频Track派生类支持采样率通道数采用位数信息
*/
@@ -131,7 +176,7 @@ public:
* @param channels 通道数
* @param sample_bit 采样位数一般为16
*/
AudioTrackImp(CodecId codecId,int sample_rate, int channels, int sample_bit){
AudioTrackImp(CodecId codecId, int sample_rate, int channels, int sample_bit){
_codecid = codecId;
_sample_rate = sample_rate;
_channels = channels;
@@ -148,7 +193,7 @@ public:
/**
* 是否已经初始化
*/
bool ready() override {
bool ready() const override {
return true;
}
@@ -172,6 +217,10 @@ public:
int getAudioChannel() const override{
return _channels;
}
Track::Ptr clone() const override { return std::make_shared<AudioTrackImp>(*this); }
Sdp::Ptr getSdp(uint8_t payload_type) const override { return nullptr; }
private:
CodecId _codecid;
int _sample_rate;
@@ -179,9 +228,8 @@ private:
int _sample_bit;
};
class TrackSource{
class TrackSource {
public:
TrackSource() = default;
virtual ~TrackSource() = default;
/**