mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2026-06-22 00:42:22 +08:00
release 8.0
This commit is contained in:
@@ -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
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
* 写入帧数据
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 帧数据,必须
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 };
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 帧数据,必须
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user