优化与完善rtmp协议相关代码

rtmp相关常量由宏改为枚举
明确rtmp包一些字段赋值含义
This commit is contained in:
xia-chu 2023-07-22 18:54:59 +08:00
parent 47add54465
commit a86398b6db
7 changed files with 232 additions and 233 deletions

View File

@ -18,7 +18,7 @@ namespace mediakit {
static string getAacCfg(const RtmpPacket &thiz) { static string getAacCfg(const RtmpPacket &thiz) {
string ret; string ret;
if (thiz.getMediaType() != FLV_CODEC_AAC) { if ((RtmpAudioCodec)thiz.getRtmpCodecId() != RtmpAudioCodec::aac) {
return ret; return ret;
} }
if (!thiz.isCfgFrame()) { if (!thiz.isCfgFrame()) {
@ -93,51 +93,45 @@ void AACRtmpEncoder::makeConfigPacket() {
bool AACRtmpEncoder::inputFrame(const Frame::Ptr &frame) { bool AACRtmpEncoder::inputFrame(const Frame::Ptr &frame) {
if (_aac_cfg.empty()) { if (_aac_cfg.empty()) {
if (frame->prefixSize()) { if (frame->prefixSize()) {
//包含adts头,从adts头获取aac配置信息 // 包含adts头,从adts头获取aac配置信息
_aac_cfg = makeAacConfig((uint8_t *) (frame->data()), frame->prefixSize()); _aac_cfg = makeAacConfig((uint8_t *)(frame->data()), frame->prefixSize());
} }
makeConfigPacket(); makeConfigPacket();
} }
if(_aac_cfg.empty()){ if (_aac_cfg.empty()) {
return false; return false;
} }
auto rtmpPkt = RtmpPacket::create(); auto pkt = RtmpPacket::create();
//header // header
uint8_t is_config = false; pkt->buffer.push_back(_audio_flv_flags);
rtmpPkt->buffer.push_back(_audio_flv_flags); pkt->buffer.push_back((uint8_t)RtmpAACPacketType::aac_raw);
rtmpPkt->buffer.push_back(!is_config); // aac data
pkt->buffer.append(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize());
//aac data pkt->body_size = pkt->buffer.size();
rtmpPkt->buffer.append(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize()); pkt->chunk_id = CHUNK_AUDIO;
pkt->stream_index = STREAM_MEDIA;
rtmpPkt->body_size = rtmpPkt->buffer.size(); pkt->time_stamp = frame->dts();
rtmpPkt->chunk_id = CHUNK_AUDIO; pkt->type_id = MSG_AUDIO;
rtmpPkt->stream_index = STREAM_MEDIA; RtmpCodec::inputRtmp(pkt);
rtmpPkt->time_stamp = frame->dts();
rtmpPkt->type_id = MSG_AUDIO;
RtmpCodec::inputRtmp(rtmpPkt);
return true; return true;
} }
void AACRtmpEncoder::makeAudioConfigPkt() { void AACRtmpEncoder::makeAudioConfigPkt() {
_audio_flv_flags = getAudioRtmpFlags(std::make_shared<AACTrack>(_aac_cfg)); _audio_flv_flags = getAudioRtmpFlags(std::make_shared<AACTrack>(_aac_cfg));
auto rtmpPkt = RtmpPacket::create(); auto pkt = RtmpPacket::create();
// header
//header pkt->buffer.push_back(_audio_flv_flags);
uint8_t is_config = true; pkt->buffer.push_back((uint8_t)RtmpAACPacketType::aac_config_header);
rtmpPkt->buffer.push_back(_audio_flv_flags); // aac config
rtmpPkt->buffer.push_back(!is_config); pkt->buffer.append(_aac_cfg);
//aac config pkt->body_size = pkt->buffer.size();
rtmpPkt->buffer.append(_aac_cfg); pkt->chunk_id = CHUNK_AUDIO;
pkt->stream_index = STREAM_MEDIA;
rtmpPkt->body_size = rtmpPkt->buffer.size(); pkt->time_stamp = 0;
rtmpPkt->chunk_id = CHUNK_AUDIO; pkt->type_id = MSG_AUDIO;
rtmpPkt->stream_index = STREAM_MEDIA; RtmpCodec::inputRtmp(pkt);
rtmpPkt->time_stamp = 0;
rtmpPkt->type_id = MSG_AUDIO;
RtmpCodec::inputRtmp(rtmpPkt);
} }
}//namespace mediakit }//namespace mediakit

View File

@ -201,11 +201,11 @@ static CodecId getVideoCodecIdByAmf(const AMFValue &val){
} }
if (val.type() != AMF_NULL) { if (val.type() != AMF_NULL) {
auto type_id = val.as_integer(); auto type_id = (RtmpVideoCodec)val.as_integer();
switch (type_id) { switch (type_id) {
case FLV_CODEC_H264 : return CodecH264; case RtmpVideoCodec::h264: return CodecH264;
case FLV_CODEC_H265 : return CodecH265; case RtmpVideoCodec::h265: return CodecH265;
default : WarnL << "暂不支持该视频Amf:" << type_id; return CodecInvalid; default: WarnL << "暂不支持该视频Amf:" << (int)type_id; return CodecInvalid;
} }
} }
return CodecInvalid; return CodecInvalid;
@ -243,13 +243,13 @@ static CodecId getAudioCodecIdByAmf(const AMFValue &val) {
} }
if (val.type() != AMF_NULL) { if (val.type() != AMF_NULL) {
auto type_id = val.as_integer(); auto type_id = (RtmpAudioCodec)val.as_integer();
switch (type_id) { switch (type_id) {
case FLV_CODEC_AAC : return CodecAAC; case RtmpAudioCodec::aac : return CodecAAC;
case FLV_CODEC_G711A : return CodecG711A; case RtmpAudioCodec::g711a : return CodecG711A;
case FLV_CODEC_G711U : return CodecG711U; case RtmpAudioCodec::g711u : return CodecG711U;
case FLV_CODEC_OPUS : return CodecOpus; case RtmpAudioCodec::opus : return CodecOpus;
default : WarnL << "暂不支持该音频Amf:" << type_id; return CodecInvalid; default : WarnL << "暂不支持该音频Amf:" << (int)type_id; return CodecInvalid;
} }
} }
@ -291,13 +291,13 @@ RtmpCodec::Ptr Factory::getRtmpCodecByTrack(const Track::Ptr &track, bool is_enc
} }
AMFValue Factory::getAmfByCodecId(CodecId codecId) { AMFValue Factory::getAmfByCodecId(CodecId codecId) {
switch (codecId){ switch (codecId) {
case CodecAAC: return AMFValue(FLV_CODEC_AAC); case CodecAAC: return AMFValue((int)RtmpAudioCodec::aac);
case CodecH264: return AMFValue(FLV_CODEC_H264); case CodecH264: return AMFValue((int)RtmpVideoCodec::h264);
case CodecH265: return AMFValue(FLV_CODEC_H265); case CodecH265: return AMFValue((int)RtmpVideoCodec::h265);
case CodecG711A: return AMFValue(FLV_CODEC_G711A); case CodecG711A: return AMFValue((int)RtmpAudioCodec::g711a);
case CodecG711U: return AMFValue(FLV_CODEC_G711U); case CodecG711U: return AMFValue((int)RtmpAudioCodec::g711u);
case CodecOpus: return AMFValue(FLV_CODEC_OPUS); case CodecOpus: return AMFValue((int)RtmpAudioCodec::opus);
default: return AMFValue(AMF_NULL); default: return AMFValue(AMF_NULL);
} }
} }

View File

@ -30,7 +30,7 @@ H264Frame::Ptr H264RtmpDecoder::obtainFrame() {
* 0x00 00 00 01sps pps * 0x00 00 00 01sps pps
*/ */
static bool getH264Config(const RtmpPacket &thiz, string &sps, string &pps) { static bool getH264Config(const RtmpPacket &thiz, string &sps, string &pps) {
if (thiz.getMediaType() != FLV_CODEC_H264) { if ((RtmpVideoCodec)thiz.getRtmpCodecId() != RtmpVideoCodec::h264) {
return false; return false;
} }
if (!thiz.isCfgFrame()) { if (!thiz.isCfgFrame()) {
@ -159,19 +159,18 @@ bool H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
} }
return _merger.inputFrame(frame, [this](uint64_t dts, uint64_t pts, const Buffer::Ptr &, bool have_key_frame) { return _merger.inputFrame(frame, [this](uint64_t dts, uint64_t pts, const Buffer::Ptr &, bool have_key_frame) {
//flags // flags
_rtmp_packet->buffer[0] = FLV_CODEC_H264 | ((have_key_frame ? FLV_KEY_FRAME : FLV_INTER_FRAME) << 4); _rtmp_packet->buffer[0] = (uint8_t)RtmpVideoCodec::h264 | ((uint8_t)(have_key_frame ? RtmpFrameType::key_frame : RtmpFrameType::inter_frame) << 4);
//not config _rtmp_packet->buffer[1] = (uint8_t)RtmpH264PacketType::h264_nalu;
_rtmp_packet->buffer[1] = true;
int32_t cts = pts - dts; int32_t cts = pts - dts;
//cts // cts
set_be24(&_rtmp_packet->buffer[2], cts); set_be24(&_rtmp_packet->buffer[2], cts);
_rtmp_packet->time_stamp = dts; _rtmp_packet->time_stamp = dts;
_rtmp_packet->body_size = _rtmp_packet->buffer.size(); _rtmp_packet->body_size = _rtmp_packet->buffer.size();
_rtmp_packet->chunk_id = CHUNK_VIDEO; _rtmp_packet->chunk_id = CHUNK_VIDEO;
_rtmp_packet->stream_index = STREAM_MEDIA; _rtmp_packet->stream_index = STREAM_MEDIA;
_rtmp_packet->type_id = MSG_VIDEO; _rtmp_packet->type_id = MSG_VIDEO;
//输出rtmp packet // 输出rtmp packet
RtmpCodec::inputRtmp(_rtmp_packet); RtmpCodec::inputRtmp(_rtmp_packet);
_rtmp_packet = nullptr; _rtmp_packet = nullptr;
}, &_rtmp_packet->buffer); }, &_rtmp_packet->buffer);
@ -182,42 +181,39 @@ void H264RtmpEncoder::makeVideoConfigPkt() {
WarnL << "sps长度不足4字节"; WarnL << "sps长度不足4字节";
return; return;
} }
int8_t flags = FLV_CODEC_H264; auto flags = (uint8_t)RtmpVideoCodec::h264;
flags |= (FLV_KEY_FRAME << 4); flags |= ((uint8_t)RtmpFrameType::key_frame << 4);
bool is_config = true; auto pkt = RtmpPacket::create();
// header
auto rtmpPkt = RtmpPacket::create(); pkt->buffer.push_back(flags);
//header pkt->buffer.push_back((uint8_t)RtmpH264PacketType::h264_config_header);
rtmpPkt->buffer.push_back(flags); // cts
rtmpPkt->buffer.push_back(!is_config); pkt->buffer.append("\x0\x0\x0", 3);
//cts // AVCDecoderConfigurationRecord start
rtmpPkt->buffer.append("\x0\x0\x0", 3); pkt->buffer.push_back(1); // version
pkt->buffer.push_back(_sps[1]); // profile
//AVCDecoderConfigurationRecord start pkt->buffer.push_back(_sps[2]); // compat
rtmpPkt->buffer.push_back(1); // version pkt->buffer.push_back(_sps[3]); // level
rtmpPkt->buffer.push_back(_sps[1]); // profile pkt->buffer.push_back((char)0xff); // 6 bits reserved + 2 bits nal size length - 1 (11)
rtmpPkt->buffer.push_back(_sps[2]); // compat pkt->buffer.push_back((char)0xe1); // 3 bits reserved + 5 bits number of sps (00001)
rtmpPkt->buffer.push_back(_sps[3]); // level // sps
rtmpPkt->buffer.push_back((char)0xff); // 6 bits reserved + 2 bits nal size length - 1 (11)
rtmpPkt->buffer.push_back((char)0xe1); // 3 bits reserved + 5 bits number of sps (00001)
//sps
uint16_t size = (uint16_t)_sps.size(); uint16_t size = (uint16_t)_sps.size();
size = htons(size); size = htons(size);
rtmpPkt->buffer.append((char *) &size, 2); pkt->buffer.append((char *)&size, 2);
rtmpPkt->buffer.append(_sps); pkt->buffer.append(_sps);
//pps // pps
rtmpPkt->buffer.push_back(1); // version pkt->buffer.push_back(1); // version
size = (uint16_t)_pps.size(); size = (uint16_t)_pps.size();
size = htons(size); size = htons(size);
rtmpPkt->buffer.append((char *) &size, 2); pkt->buffer.append((char *)&size, 2);
rtmpPkt->buffer.append(_pps); pkt->buffer.append(_pps);
rtmpPkt->body_size = rtmpPkt->buffer.size(); pkt->body_size = pkt->buffer.size();
rtmpPkt->chunk_id = CHUNK_VIDEO; pkt->chunk_id = CHUNK_VIDEO;
rtmpPkt->stream_index = STREAM_MEDIA; pkt->stream_index = STREAM_MEDIA;
rtmpPkt->time_stamp = 0; pkt->time_stamp = 0;
rtmpPkt->type_id = MSG_VIDEO; pkt->type_id = MSG_VIDEO;
RtmpCodec::inputRtmp(rtmpPkt); RtmpCodec::inputRtmp(pkt);
} }
}//namespace mediakit }//namespace mediakit

View File

@ -50,7 +50,7 @@ static bool decode_HEVCDecoderConfigurationRecord(uint8_t *extra, size_t bytes,
* 0x00 00 00 01sps * 0x00 00 00 01sps
*/ */
static bool getH265ConfigFrame(const RtmpPacket &thiz, string &frame) { static bool getH265ConfigFrame(const RtmpPacket &thiz, string &frame) {
if (thiz.getMediaType() != FLV_CODEC_H265) { if ((RtmpVideoCodec)thiz.getRtmpCodecId() != RtmpVideoCodec::h265) {
return false; return false;
} }
if (!thiz.isCfgFrame()) { if (!thiz.isCfgFrame()) {
@ -244,13 +244,11 @@ bool H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
return _merger.inputFrame(frame, [this](uint64_t dts, uint64_t pts, const Buffer::Ptr &, bool have_key_frame) { return _merger.inputFrame(frame, [this](uint64_t dts, uint64_t pts, const Buffer::Ptr &, bool have_key_frame) {
// flags // flags
_rtmp_packet->buffer[0] = FLV_CODEC_H265 | ((have_key_frame ? FLV_KEY_FRAME : FLV_INTER_FRAME) << 4); _rtmp_packet->buffer[0] = (uint8_t)RtmpVideoCodec::h265 | ((uint8_t)(have_key_frame ? RtmpFrameType::key_frame : RtmpFrameType::inter_frame) << 4);
// not config _rtmp_packet->buffer[1] = (uint8_t)RtmpH264PacketType::h264_nalu;
_rtmp_packet->buffer[1] = true;
int32_t cts = pts - dts; int32_t cts = pts - dts;
// cts // cts
set_be24(&_rtmp_packet->buffer[2], cts); set_be24(&_rtmp_packet->buffer[2], cts);
_rtmp_packet->time_stamp = dts; _rtmp_packet->time_stamp = dts;
_rtmp_packet->body_size = _rtmp_packet->buffer.size(); _rtmp_packet->body_size = _rtmp_packet->buffer.size();
_rtmp_packet->chunk_id = CHUNK_VIDEO; _rtmp_packet->chunk_id = CHUNK_VIDEO;
@ -264,13 +262,12 @@ bool H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
void H265RtmpEncoder::makeVideoConfigPkt() { void H265RtmpEncoder::makeVideoConfigPkt() {
#ifdef ENABLE_MP4 #ifdef ENABLE_MP4
int8_t flags = FLV_CODEC_H265; auto flags = (uint8_t)RtmpVideoCodec::h265;
flags |= (FLV_KEY_FRAME << 4); flags |= ((uint8_t)RtmpFrameType::key_frame << 4);
bool is_config = true;
auto pkt = RtmpPacket::create(); auto pkt = RtmpPacket::create();
// header // header
pkt->buffer.push_back(flags); pkt->buffer.push_back(flags);
pkt->buffer.push_back(!is_config); pkt->buffer.push_back((uint8_t)RtmpH264PacketType::h264_config_header);
// cts // cts
pkt->buffer.append("\x0\x0\x0", 3); pkt->buffer.append("\x0\x0\x0", 3);

View File

@ -10,10 +10,10 @@
#include "Rtmp.h" #include "Rtmp.h"
#include "Extension/Factory.h" #include "Extension/Factory.h"
namespace mediakit{
TitleMeta::TitleMeta(float dur_sec, size_t fileSize, const std::map<std::string, std::string> &header) namespace mediakit {
{
TitleMeta::TitleMeta(float dur_sec, size_t fileSize, const std::map<std::string, std::string> &header) {
_metadata.set("duration", dur_sec); _metadata.set("duration", dur_sec);
_metadata.set("fileSize", (int)fileSize); _metadata.set("fileSize", (int)fileSize);
_metadata.set("title", std::string("Streamed by ") + kServerName); _metadata.set("title", std::string("Streamed by ") + kServerName);
@ -22,14 +22,14 @@ TitleMeta::TitleMeta(float dur_sec, size_t fileSize, const std::map<std::string,
} }
} }
VideoMeta::VideoMeta(const VideoTrack::Ptr &video){ VideoMeta::VideoMeta(const VideoTrack::Ptr &video) {
if(video->getVideoWidth() > 0 ){ if (video->getVideoWidth() > 0) {
_metadata.set("width", video->getVideoWidth()); _metadata.set("width", video->getVideoWidth());
} }
if(video->getVideoHeight() > 0 ){ if (video->getVideoHeight() > 0) {
_metadata.set("height", video->getVideoHeight()); _metadata.set("height", video->getVideoHeight());
} }
if(video->getVideoFps() > 0 ){ if (video->getVideoFps() > 0) {
_metadata.set("framerate", video->getVideoFps()); _metadata.set("framerate", video->getVideoFps());
} }
if (video->getBitRate()) { if (video->getBitRate()) {
@ -39,26 +39,26 @@ VideoMeta::VideoMeta(const VideoTrack::Ptr &video){
_metadata.set("videocodecid", Factory::getAmfByCodecId(_codecId)); _metadata.set("videocodecid", Factory::getAmfByCodecId(_codecId));
} }
AudioMeta::AudioMeta(const AudioTrack::Ptr &audio){ AudioMeta::AudioMeta(const AudioTrack::Ptr &audio) {
if (audio->getBitRate()) { if (audio->getBitRate()) {
_metadata.set("audiodatarate", audio->getBitRate() / 1024); _metadata.set("audiodatarate", audio->getBitRate() / 1024);
} }
if(audio->getAudioSampleRate() > 0){ if (audio->getAudioSampleRate() > 0) {
_metadata.set("audiosamplerate", audio->getAudioSampleRate()); _metadata.set("audiosamplerate", audio->getAudioSampleRate());
} }
if(audio->getAudioSampleBit() > 0){ if (audio->getAudioSampleBit() > 0) {
_metadata.set("audiosamplesize", audio->getAudioSampleBit()); _metadata.set("audiosamplesize", audio->getAudioSampleBit());
} }
if(audio->getAudioChannel() > 0){ if (audio->getAudioChannel() > 0) {
_metadata.set("stereo", audio->getAudioChannel() > 1); _metadata.set("stereo", audio->getAudioChannel() > 1);
} }
_codecId = audio->getCodecId(); _codecId = audio->getCodecId();
_metadata.set("audiocodecid", Factory::getAmfByCodecId(_codecId)); _metadata.set("audiocodecid", Factory::getAmfByCodecId(_codecId));
} }
uint8_t getAudioRtmpFlags(const Track::Ptr &track){ uint8_t getAudioRtmpFlags(const Track::Ptr &track) {
switch (track->getTrackType()){ switch (track->getTrackType()) {
case TrackAudio : { case TrackAudio: {
auto audioTrack = std::dynamic_pointer_cast<AudioTrack>(track); auto audioTrack = std::dynamic_pointer_cast<AudioTrack>(track);
if (!audioTrack) { if (!audioTrack) {
WarnL << "获取AudioTrack失败"; WarnL << "获取AudioTrack失败";
@ -68,21 +68,21 @@ uint8_t getAudioRtmpFlags(const Track::Ptr &track){
auto iChannel = audioTrack->getAudioChannel(); auto iChannel = audioTrack->getAudioChannel();
auto iSampleBit = audioTrack->getAudioSampleBit(); auto iSampleBit = audioTrack->getAudioSampleBit();
uint8_t flvAudioType ; uint8_t flvAudioType;
switch (track->getCodecId()){ switch (track->getCodecId()) {
case CodecG711A : flvAudioType = FLV_CODEC_G711A; break; case CodecG711A: flvAudioType = (uint8_t)RtmpAudioCodec::g711a; break;
case CodecG711U : flvAudioType = FLV_CODEC_G711U; break; case CodecG711U: flvAudioType = (uint8_t)RtmpAudioCodec::g711u; break;
case CodecOpus : { case CodecOpus: {
flvAudioType = FLV_CODEC_OPUS; flvAudioType = (uint8_t)RtmpAudioCodec::opus;
//opus不通过flags获取音频相关信息 // opus不通过flags获取音频相关信息
iSampleRate = 44100; iSampleRate = 44100;
iSampleBit = 16; iSampleBit = 16;
iChannel = 2; iChannel = 2;
break; break;
} }
case CodecAAC : { case CodecAAC: {
flvAudioType = FLV_CODEC_AAC; flvAudioType = (uint8_t)RtmpAudioCodec::aac;
//aac不通过flags获取音频相关信息 // aac不通过flags获取音频相关信息
iSampleRate = 44100; iSampleRate = 44100;
iSampleBit = 16; iSampleBit = 16;
iChannel = 2; iChannel = 2;
@ -93,23 +93,15 @@ uint8_t getAudioRtmpFlags(const Track::Ptr &track){
uint8_t flvSampleRate; uint8_t flvSampleRate;
switch (iSampleRate) { switch (iSampleRate) {
case 44100: case 44100: flvSampleRate = 3; break;
flvSampleRate = 3; case 22050: flvSampleRate = 2; break;
break; case 11025: flvSampleRate = 1; break;
case 22050:
flvSampleRate = 2;
break;
case 11025:
flvSampleRate = 1;
break;
case 16000: // nellymoser only case 16000: // nellymoser only
case 8000: // nellymoser only case 8000: // nellymoser only
case 5512: // not MP3 case 5512: // not MP3
flvSampleRate = 0; flvSampleRate = 0;
break; break;
default: default: WarnL << "FLV does not support sample rate " << iSampleRate << " ,choose from (44100, 22050, 11025)"; return 0;
WarnL << "FLV does not support sample rate " << iSampleRate << " ,choose from (44100, 22050, 11025)";
return 0;
} }
uint8_t flvStereoOrMono = (iChannel > 1); uint8_t flvStereoOrMono = (iChannel > 1);
@ -117,32 +109,28 @@ uint8_t getAudioRtmpFlags(const Track::Ptr &track){
return (flvAudioType << 4) | (flvSampleRate << 2) | (flvSampleBit << 1) | flvStereoOrMono; return (flvAudioType << 4) | (flvSampleRate << 2) | (flvSampleBit << 1) | flvStereoOrMono;
} }
default : return 0; default: return 0;
} }
} }
void Metadata::addTrack(AMFValue &metadata, const Track::Ptr &track) { void Metadata::addTrack(AMFValue &metadata, const Track::Ptr &track) {
Metadata::Ptr new_metadata; Metadata::Ptr new_metadata;
switch (track->getTrackType()) { switch (track->getTrackType()) {
case TrackVideo: { case TrackVideo: {
new_metadata = std::make_shared<VideoMeta>(std::dynamic_pointer_cast<VideoTrack>(track)); new_metadata = std::make_shared<VideoMeta>(std::dynamic_pointer_cast<VideoTrack>(track));
}
break; break;
}
case TrackAudio: { case TrackAudio: {
new_metadata = std::make_shared<AudioMeta>(std::dynamic_pointer_cast<AudioTrack>(track)); new_metadata = std::make_shared<AudioMeta>(std::dynamic_pointer_cast<AudioTrack>(track));
}
break; break;
default: }
return; default: return;
} }
new_metadata->getMetadata().object_for_each([&](const std::string &key, const AMFValue &value) { new_metadata->getMetadata().object_for_each([&](const std::string &key, const AMFValue &value) { metadata.set(key, value); });
metadata.set(key, value);
});
} }
RtmpPacket::Ptr RtmpPacket::create(){ RtmpPacket::Ptr RtmpPacket::create() {
#if 0 #if 0
static ResourcePool<RtmpPacket> packet_pool; static ResourcePool<RtmpPacket> packet_pool;
static onceToken token([]() { static onceToken token([]() {
@ -156,8 +144,7 @@ RtmpPacket::Ptr RtmpPacket::create(){
#endif #endif
} }
void RtmpPacket::clear() void RtmpPacket::clear() {
{
is_abs_stamp = false; is_abs_stamp = false;
time_stamp = 0; time_stamp = 0;
ts_field = 0; ts_field = 0;
@ -165,18 +152,26 @@ void RtmpPacket::clear()
buffer.clear(); buffer.clear();
} }
bool RtmpPacket::isVideoKeyFrame() const bool RtmpPacket::isVideoKeyFrame() const {
{ if (type_id != MSG_VIDEO) {
return type_id == MSG_VIDEO && (uint8_t)buffer[0] >> 4 == FLV_KEY_FRAME && (uint8_t)buffer[1] == 1; return false;
}
RtmpPacketInfo info;
if (CodecInvalid == parseVideoRtmpPacket((uint8_t *)data(), size(), &info)) {
return false;
}
if (info.is_enhanced) {
return info.video.frame_type == RtmpFrameType::key_frame && info.video.pkt_type == RtmpPacketType::PacketTypeCodedFramesX;
}
return info.video.frame_type == RtmpFrameType::key_frame && info.video.h264_pkt_type == RtmpH264PacketType::h264_nalu;
} }
bool RtmpPacket::isCfgFrame() const bool RtmpPacket::isCfgFrame() const {
{
switch (type_id) { switch (type_id) {
case MSG_VIDEO: return buffer[1] == 0; case MSG_VIDEO: return (RtmpH264PacketType)buffer[1] == RtmpH264PacketType::h264_config_header;
case MSG_AUDIO: { case MSG_AUDIO: {
switch (getMediaType()) { switch ((RtmpAudioCodec)getRtmpCodecId()) {
case FLV_CODEC_AAC: return buffer[1] == 0; case RtmpAudioCodec::aac: return (RtmpAACPacketType)buffer[1] == RtmpAACPacketType::aac_config_header;
default: return false; default: return false;
} }
} }
@ -184,8 +179,7 @@ bool RtmpPacket::isCfgFrame() const
} }
} }
int RtmpPacket::getMediaType() const int RtmpPacket::getRtmpCodecId() const {
{
switch (type_id) { switch (type_id) {
case MSG_VIDEO: return (uint8_t)buffer[0] & 0x0F; case MSG_VIDEO: return (uint8_t)buffer[0] & 0x0F;
case MSG_AUDIO: return (uint8_t)buffer[0] >> 4; case MSG_AUDIO: return (uint8_t)buffer[0] >> 4;
@ -193,8 +187,7 @@ int RtmpPacket::getMediaType() const
} }
} }
int RtmpPacket::getAudioSampleRate() const int RtmpPacket::getAudioSampleRate() const {
{
if (type_id != MSG_AUDIO) { if (type_id != MSG_AUDIO) {
return 0; return 0;
} }
@ -203,8 +196,7 @@ int RtmpPacket::getAudioSampleRate() const
return sampleRate[flvSampleRate]; return sampleRate[flvSampleRate];
} }
int RtmpPacket::getAudioSampleBit() const int RtmpPacket::getAudioSampleBit() const {
{
if (type_id != MSG_AUDIO) { if (type_id != MSG_AUDIO) {
return 0; return 0;
} }
@ -213,8 +205,7 @@ int RtmpPacket::getAudioSampleBit() const
return sampleBit[flvSampleBit]; return sampleBit[flvSampleBit];
} }
int RtmpPacket::getAudioChannel() const int RtmpPacket::getAudioChannel() const {
{
if (type_id != MSG_AUDIO) { if (type_id != MSG_AUDIO) {
return 0; return 0;
} }
@ -223,8 +214,7 @@ int RtmpPacket::getAudioChannel() const
return channel[flvStereoOrMono]; return channel[flvStereoOrMono];
} }
RtmpPacket & RtmpPacket::operator=(const RtmpPacket &that) RtmpPacket &RtmpPacket::operator=(const RtmpPacket &that) {
{
is_abs_stamp = that.is_abs_stamp; is_abs_stamp = that.is_abs_stamp;
stream_index = that.stream_index; stream_index = that.stream_index;
body_size = that.body_size; body_size = that.body_size;
@ -234,25 +224,20 @@ RtmpPacket & RtmpPacket::operator=(const RtmpPacket &that)
return *this; return *this;
} }
RtmpHandshake::RtmpHandshake(uint32_t _time, uint8_t *_random /*= nullptr*/) RtmpHandshake::RtmpHandshake(uint32_t _time, uint8_t *_random /*= nullptr*/) {
{
_time = htonl(_time); _time = htonl(_time);
memcpy(time_stamp, &_time, 4); memcpy(time_stamp, &_time, 4);
if (!_random) { if (!_random) {
random_generate((char *)random, sizeof(random)); random_generate((char *)random, sizeof(random));
} } else {
else {
memcpy(random, _random, sizeof(random)); memcpy(random, _random, sizeof(random));
} }
} }
void RtmpHandshake::random_generate(char *bytes, int size) void RtmpHandshake::random_generate(char *bytes, int size) {
{ static char cdata[] = { 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x2d, 0x72, 0x74, 0x6d, 0x70, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2d, 0x77, 0x69, 0x6e,
static char cdata[] = { 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x2d, 0x72, 0x6c, 0x69, 0x6e, 0x2d, 0x77, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x40, 0x31, 0x32, 0x36, 0x2e, 0x63,
0x74, 0x6d, 0x70, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x6f, 0x6d };
0x2d, 0x77, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x2d, 0x77, 0x69,
0x6e, 0x74, 0x65, 0x72, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x40, 0x31, 0x32, 0x36, 0x2e, 0x63, 0x6f, 0x6d };
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
bytes[i] = cdata[rand() % (sizeof(cdata) - 1)]; bytes[i] = cdata[rand() % (sizeof(cdata) - 1)];
} }
@ -286,9 +271,9 @@ CodecId parseVideoRtmpPacket(const uint8_t *data, size_t size, RtmpPacketInfo *i
// IsExHeader == 0 // IsExHeader == 0
info->is_enhanced = false; info->is_enhanced = false;
info->video.frame_type = (RtmpFrameType)(data[0] >> 4); info->video.frame_type = (RtmpFrameType)(data[0] >> 4);
info->video.rtmp_codec = (RtmpVideoCodec)(data[0] & 0x0f); auto rtmp_codec = (RtmpVideoCodec)(data[0] & 0x0f);
switch (info->video.rtmp_codec) { switch (rtmp_codec) {
case RtmpVideoCodec::h264: { case RtmpVideoCodec::h264: {
CHECK(size >= 1, "Invalid rtmp buffer size: ", size); CHECK(size >= 1, "Invalid rtmp buffer size: ", size);
info->codec = CodecH264; info->codec = CodecH264;
@ -301,14 +286,14 @@ CodecId parseVideoRtmpPacket(const uint8_t *data, size_t size, RtmpPacketInfo *i
info->video.h264_pkt_type = (RtmpH264PacketType)data[1]; info->video.h264_pkt_type = (RtmpH264PacketType)data[1];
break; break;
} }
default: WarnL << "Rtmp video codec not supported: " << (int)info->video.rtmp_codec; break; default: WarnL << "Rtmp video codec not supported: " << (int)rtmp_codec; break;
} }
} }
return info->codec; return info->codec;
} }
}//namespace mediakit } // namespace mediakit
namespace toolkit { namespace toolkit {
StatisticImp(mediakit::RtmpPacket); StatisticImp(mediakit::RtmpPacket);
} }

View File

@ -63,18 +63,6 @@
#define CHUNK_AUDIO 6 /*音频chunkID*/ #define CHUNK_AUDIO 6 /*音频chunkID*/
#define CHUNK_VIDEO 7 /*视频chunkID*/ #define CHUNK_VIDEO 7 /*视频chunkID*/
#define FLV_KEY_FRAME 1
#define FLV_INTER_FRAME 2
#define FLV_CODEC_AAC 10
#define FLV_CODEC_H264 7
//金山扩展: https://github.com/ksvc/FFmpeg/wiki
#define FLV_CODEC_H265 12
#define FLV_CODEC_G711A 7
#define FLV_CODEC_G711U 8
//参考学而思网校: https://github.com/notedit/rtmp/commit/6e314ac5b29611431f8fb5468596b05815743c10
#define FLV_CODEC_OPUS 13
namespace mediakit { namespace mediakit {
#if defined(_WIN32) #if defined(_WIN32)
@ -181,12 +169,9 @@ public:
} }
void clear(); void clear();
bool isVideoKeyFrame() const; bool isVideoKeyFrame() const;
bool isCfgFrame() const; bool isCfgFrame() const;
int getRtmpCodecId() const;
int getMediaType() const;
int getAudioSampleRate() const; int getAudioSampleRate() const;
int getAudioSampleBit() const; int getAudioSampleBit() const;
int getAudioChannel() const; int getAudioChannel() const;
@ -269,6 +254,10 @@ private:
//根据音频track获取flags //根据音频track获取flags
uint8_t getAudioRtmpFlags(const Track::Ptr &track); uint8_t getAudioRtmpFlags(const Track::Ptr &track);
////////////////// rtmp video //////////////////////////
//https://rtmp.veriskope.com/pdf/video_file_format_spec_v10_1.pdf
// UB [4]; Type of video frame.
enum class RtmpFrameType : uint8_t { enum class RtmpFrameType : uint8_t {
reserved = 0, reserved = 0,
key_frame = 1, // key frame (for AVC, a seekable frame) key_frame = 1, // key frame (for AVC, a seekable frame)
@ -278,6 +267,7 @@ enum class RtmpFrameType : uint8_t {
video_info_frame = 5, // video info/command frame video_info_frame = 5, // video info/command frame
}; };
// UB [4]; Codec Identifier.
enum class RtmpVideoCodec : uint8_t { enum class RtmpVideoCodec : uint8_t {
h263 = 2, // Sorenson H.263 h263 = 2, // Sorenson H.263
screen_video = 3, // Screen video screen_video = 3, // Screen video
@ -288,12 +278,15 @@ enum class RtmpVideoCodec : uint8_t {
h265 = 12, // 国内扩展 h265 = 12, // 国内扩展
}; };
// UI8;
enum class RtmpH264PacketType : uint8_t { enum class RtmpH264PacketType : uint8_t {
h264_config_header = 0, // AVC sequence header(sps/pps) h264_config_header = 0, // AVC or HEVC sequence header(sps/pps)
h264_nalu = 1, // AVC NALU h264_nalu = 1, // AVC or HEVC NALU
h264_end_seq = 2, // AVC end of sequence (lower level NALU sequence ender is not REQUIRED or supported) h264_end_seq = 2, // AVC or HEVC end of sequence (lower level NALU sequence ender is not REQUIRED or supported)
}; };
// https://github.com/veovera/enhanced-rtmp/blob/main/enhanced-rtmp.pdf
// UB[4]
enum class RtmpPacketType : uint8_t { enum class RtmpPacketType : uint8_t {
PacketTypeSequenceStart = 0, PacketTypeSequenceStart = 0,
PacketTypeCodedFrames = 1, PacketTypeCodedFrames = 1,
@ -321,15 +314,49 @@ enum class RtmpPacketType : uint8_t {
PacketTypeMPEG2TSSequenceStart = 5, PacketTypeMPEG2TSSequenceStart = 5,
}; };
////////////////// rtmp audio //////////////////////////
//https://rtmp.veriskope.com/pdf/video_file_format_spec_v10_1.pdf
// UB [4]; Format of SoundData
enum class RtmpAudioCodec : uint8_t {
/**
0 = Linear PCM, platform endian
1 = ADPCM
2 = MP3
3 = Linear PCM, little endian
4 = Nellymoser 16 kHz mono
5 = Nellymoser 8 kHz mono
6 = Nellymoser
7 = G.711 A-law logarithmic PCM
8 = G.711 mu-law logarithmic PCM
9 = reserved
10 = AAC
11 = Speex
14 = MP3 8 kHz
15 = Device-specific sound
*/
g711a = 7,
g711u = 8,
aac = 10,
opus = 13 // 国内扩展
};
// UI8;
enum class RtmpAACPacketType : uint8_t {
aac_config_header = 0, // AAC sequence header
aac_raw = 1, // AAC raw
};
////////////////////////////////////////////
struct RtmpPacketInfo { struct RtmpPacketInfo {
CodecId codec = CodecInvalid; CodecId codec = CodecInvalid;
bool is_enhanced; bool is_enhanced;
union { union {
struct { struct {
RtmpFrameType frame_type; RtmpFrameType frame_type;
RtmpVideoCodec rtmp_codec; RtmpPacketType pkt_type; // enhanced = true
RtmpPacketType pkt_type; RtmpH264PacketType h264_pkt_type; // enhanced = false
RtmpH264PacketType h264_pkt_type;
} video; } video;
}; };
}; };

View File

@ -132,7 +132,7 @@ void RtmpDemuxer::inputRtmp(const RtmpPacket::Ptr &pkt) {
case MSG_AUDIO: { case MSG_AUDIO: {
if (!_try_get_audio_track) { if (!_try_get_audio_track) {
_try_get_audio_track = true; _try_get_audio_track = true;
auto codec = AMFValue(pkt->getMediaType()); auto codec = AMFValue(pkt->getRtmpCodecId());
makeAudioTrack(codec, pkt->getAudioSampleRate(), pkt->getAudioChannel(), pkt->getAudioSampleBit(), 0); makeAudioTrack(codec, pkt->getAudioSampleRate(), pkt->getAudioChannel(), pkt->getAudioSampleBit(), 0);
} }
if (_audio_rtmp_decoder) { if (_audio_rtmp_decoder) {