From a86398b6db20f3b4bd75001f95881fd815b3ec21 Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Sat, 22 Jul 2023 18:54:59 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=8E=E5=AE=8C=E5=96=84rt?= =?UTF-8?q?mp=E5=8D=8F=E8=AE=AE=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rtmp相关常量由宏改为枚举 明确rtmp包一些字段赋值含义 --- src/Extension/AACRtmp.cpp | 62 +++++++------- src/Extension/Factory.cpp | 34 ++++---- src/Extension/H264Rtmp.cpp | 92 ++++++++++----------- src/Extension/H265Rtmp.cpp | 41 +++++----- src/Rtmp/Rtmp.cpp | 163 +++++++++++++++++-------------------- src/Rtmp/Rtmp.h | 71 +++++++++++----- src/Rtmp/RtmpDemuxer.cpp | 2 +- 7 files changed, 232 insertions(+), 233 deletions(-) diff --git a/src/Extension/AACRtmp.cpp b/src/Extension/AACRtmp.cpp index 1454a727..d18d9d25 100644 --- a/src/Extension/AACRtmp.cpp +++ b/src/Extension/AACRtmp.cpp @@ -18,7 +18,7 @@ namespace mediakit { static string getAacCfg(const RtmpPacket &thiz) { string ret; - if (thiz.getMediaType() != FLV_CODEC_AAC) { + if ((RtmpAudioCodec)thiz.getRtmpCodecId() != RtmpAudioCodec::aac) { return ret; } if (!thiz.isCfgFrame()) { @@ -93,51 +93,45 @@ void AACRtmpEncoder::makeConfigPacket() { 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()); + // 包含adts头,从adts头获取aac配置信息 + _aac_cfg = makeAacConfig((uint8_t *)(frame->data()), frame->prefixSize()); } makeConfigPacket(); } - if(_aac_cfg.empty()){ + if (_aac_cfg.empty()) { return false; } - auto rtmpPkt = RtmpPacket::create(); - //header - uint8_t is_config = false; - rtmpPkt->buffer.push_back(_audio_flv_flags); - rtmpPkt->buffer.push_back(!is_config); - - //aac data - rtmpPkt->buffer.append(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize()); - - rtmpPkt->body_size = rtmpPkt->buffer.size(); - rtmpPkt->chunk_id = CHUNK_AUDIO; - rtmpPkt->stream_index = STREAM_MEDIA; - rtmpPkt->time_stamp = frame->dts(); - rtmpPkt->type_id = MSG_AUDIO; - RtmpCodec::inputRtmp(rtmpPkt); + auto pkt = RtmpPacket::create(); + // header + pkt->buffer.push_back(_audio_flv_flags); + pkt->buffer.push_back((uint8_t)RtmpAACPacketType::aac_raw); + // aac data + pkt->buffer.append(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize()); + pkt->body_size = pkt->buffer.size(); + pkt->chunk_id = CHUNK_AUDIO; + pkt->stream_index = STREAM_MEDIA; + pkt->time_stamp = frame->dts(); + pkt->type_id = MSG_AUDIO; + RtmpCodec::inputRtmp(pkt); return true; } void AACRtmpEncoder::makeAudioConfigPkt() { _audio_flv_flags = getAudioRtmpFlags(std::make_shared(_aac_cfg)); - auto rtmpPkt = RtmpPacket::create(); - - //header - uint8_t is_config = true; - rtmpPkt->buffer.push_back(_audio_flv_flags); - rtmpPkt->buffer.push_back(!is_config); - //aac config - rtmpPkt->buffer.append(_aac_cfg); - - rtmpPkt->body_size = rtmpPkt->buffer.size(); - rtmpPkt->chunk_id = CHUNK_AUDIO; - rtmpPkt->stream_index = STREAM_MEDIA; - rtmpPkt->time_stamp = 0; - rtmpPkt->type_id = MSG_AUDIO; - RtmpCodec::inputRtmp(rtmpPkt); + 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); + pkt->body_size = pkt->buffer.size(); + pkt->chunk_id = CHUNK_AUDIO; + pkt->stream_index = STREAM_MEDIA; + pkt->time_stamp = 0; + pkt->type_id = MSG_AUDIO; + RtmpCodec::inputRtmp(pkt); } }//namespace mediakit \ No newline at end of file diff --git a/src/Extension/Factory.cpp b/src/Extension/Factory.cpp index 1bb292bd..a19d0f66 100644 --- a/src/Extension/Factory.cpp +++ b/src/Extension/Factory.cpp @@ -201,11 +201,11 @@ static CodecId getVideoCodecIdByAmf(const AMFValue &val){ } if (val.type() != AMF_NULL) { - auto type_id = val.as_integer(); + auto type_id = (RtmpVideoCodec)val.as_integer(); switch (type_id) { - case FLV_CODEC_H264 : return CodecH264; - case FLV_CODEC_H265 : return CodecH265; - default : WarnL << "暂不支持该视频Amf:" << type_id; return CodecInvalid; + case RtmpVideoCodec::h264: return CodecH264; + case RtmpVideoCodec::h265: return CodecH265; + default: WarnL << "暂不支持该视频Amf:" << (int)type_id; return CodecInvalid; } } return CodecInvalid; @@ -243,13 +243,13 @@ static CodecId getAudioCodecIdByAmf(const AMFValue &val) { } if (val.type() != AMF_NULL) { - auto type_id = val.as_integer(); + auto type_id = (RtmpAudioCodec)val.as_integer(); switch (type_id) { - case FLV_CODEC_AAC : return CodecAAC; - case FLV_CODEC_G711A : return CodecG711A; - case FLV_CODEC_G711U : return CodecG711U; - case FLV_CODEC_OPUS : return CodecOpus; - default : WarnL << "暂不支持该音频Amf:" << type_id; return CodecInvalid; + case RtmpAudioCodec::aac : return CodecAAC; + case RtmpAudioCodec::g711a : return CodecG711A; + case RtmpAudioCodec::g711u : return CodecG711U; + case RtmpAudioCodec::opus : return CodecOpus; + 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) { - switch (codecId){ - case CodecAAC: return AMFValue(FLV_CODEC_AAC); - case CodecH264: return AMFValue(FLV_CODEC_H264); - case CodecH265: return AMFValue(FLV_CODEC_H265); - case CodecG711A: return AMFValue(FLV_CODEC_G711A); - case CodecG711U: return AMFValue(FLV_CODEC_G711U); - case CodecOpus: return AMFValue(FLV_CODEC_OPUS); + switch (codecId) { + case CodecAAC: return AMFValue((int)RtmpAudioCodec::aac); + case CodecH264: return AMFValue((int)RtmpVideoCodec::h264); + case CodecH265: return 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); default: return AMFValue(AMF_NULL); } } diff --git a/src/Extension/H264Rtmp.cpp b/src/Extension/H264Rtmp.cpp index 2c338da8..f93c5a00 100644 --- a/src/Extension/H264Rtmp.cpp +++ b/src/Extension/H264Rtmp.cpp @@ -30,7 +30,7 @@ H264Frame::Ptr H264RtmpDecoder::obtainFrame() { * 返回不带0x00 00 00 01头的sps 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; } if (!thiz.isCfgFrame()) { @@ -159,22 +159,21 @@ 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) { - //flags - _rtmp_packet->buffer[0] = FLV_CODEC_H264 | ((have_key_frame ? FLV_KEY_FRAME : FLV_INTER_FRAME) << 4); - //not config - _rtmp_packet->buffer[1] = true; - int32_t cts = pts - dts; - //cts - set_be24(&_rtmp_packet->buffer[2], cts); - _rtmp_packet->time_stamp = dts; - _rtmp_packet->body_size = _rtmp_packet->buffer.size(); - _rtmp_packet->chunk_id = CHUNK_VIDEO; - _rtmp_packet->stream_index = STREAM_MEDIA; - _rtmp_packet->type_id = MSG_VIDEO; - //输出rtmp packet - RtmpCodec::inputRtmp(_rtmp_packet); - _rtmp_packet = nullptr; - }, &_rtmp_packet->buffer); + // flags + _rtmp_packet->buffer[0] = (uint8_t)RtmpVideoCodec::h264 | ((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); + _rtmp_packet->time_stamp = dts; + _rtmp_packet->body_size = _rtmp_packet->buffer.size(); + _rtmp_packet->chunk_id = CHUNK_VIDEO; + _rtmp_packet->stream_index = STREAM_MEDIA; + _rtmp_packet->type_id = MSG_VIDEO; + // 输出rtmp packet + RtmpCodec::inputRtmp(_rtmp_packet); + _rtmp_packet = nullptr; + }, &_rtmp_packet->buffer); } void H264RtmpEncoder::makeVideoConfigPkt() { @@ -182,42 +181,39 @@ void H264RtmpEncoder::makeVideoConfigPkt() { WarnL << "sps长度不足4字节"; return; } - int8_t flags = FLV_CODEC_H264; - flags |= (FLV_KEY_FRAME << 4); - bool is_config = true; - - auto rtmpPkt = RtmpPacket::create(); - //header - rtmpPkt->buffer.push_back(flags); - rtmpPkt->buffer.push_back(!is_config); - //cts - rtmpPkt->buffer.append("\x0\x0\x0", 3); - - //AVCDecoderConfigurationRecord start - rtmpPkt->buffer.push_back(1); // version - rtmpPkt->buffer.push_back(_sps[1]); // profile - rtmpPkt->buffer.push_back(_sps[2]); // compat - rtmpPkt->buffer.push_back(_sps[3]); // level - 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 + auto flags = (uint8_t)RtmpVideoCodec::h264; + flags |= ((uint8_t)RtmpFrameType::key_frame << 4); + 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); + // 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); - rtmpPkt->buffer.append((char *) &size, 2); - rtmpPkt->buffer.append(_sps); - //pps - rtmpPkt->buffer.push_back(1); // version + 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); - rtmpPkt->buffer.append((char *) &size, 2); - rtmpPkt->buffer.append(_pps); + pkt->buffer.append((char *)&size, 2); + pkt->buffer.append(_pps); - rtmpPkt->body_size = rtmpPkt->buffer.size(); - rtmpPkt->chunk_id = CHUNK_VIDEO; - rtmpPkt->stream_index = STREAM_MEDIA; - rtmpPkt->time_stamp = 0; - rtmpPkt->type_id = MSG_VIDEO; - RtmpCodec::inputRtmp(rtmpPkt); + 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); } }//namespace mediakit diff --git a/src/Extension/H265Rtmp.cpp b/src/Extension/H265Rtmp.cpp index b3001ea0..451310b1 100644 --- a/src/Extension/H265Rtmp.cpp +++ b/src/Extension/H265Rtmp.cpp @@ -50,7 +50,7 @@ static bool decode_HEVCDecoderConfigurationRecord(uint8_t *extra, size_t bytes, * 返回不带0x00 00 00 01头的sps */ static bool getH265ConfigFrame(const RtmpPacket &thiz, string &frame) { - if (thiz.getMediaType() != FLV_CODEC_H265) { + if ((RtmpVideoCodec)thiz.getRtmpCodecId() != RtmpVideoCodec::h265) { return false; } if (!thiz.isCfgFrame()) { @@ -243,34 +243,31 @@ 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) { - // flags - _rtmp_packet->buffer[0] = FLV_CODEC_H265 | ((have_key_frame ? FLV_KEY_FRAME : FLV_INTER_FRAME) << 4); - // not config - _rtmp_packet->buffer[1] = true; - int32_t cts = pts - dts; - // cts - set_be24(&_rtmp_packet->buffer[2], cts); - - _rtmp_packet->time_stamp = dts; - _rtmp_packet->body_size = _rtmp_packet->buffer.size(); - _rtmp_packet->chunk_id = CHUNK_VIDEO; - _rtmp_packet->stream_index = STREAM_MEDIA; - _rtmp_packet->type_id = MSG_VIDEO; - // 输出rtmp packet - RtmpCodec::inputRtmp(_rtmp_packet); - _rtmp_packet = nullptr; - }, &_rtmp_packet->buffer); + // 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); + _rtmp_packet->time_stamp = dts; + _rtmp_packet->body_size = _rtmp_packet->buffer.size(); + _rtmp_packet->chunk_id = CHUNK_VIDEO; + _rtmp_packet->stream_index = STREAM_MEDIA; + _rtmp_packet->type_id = MSG_VIDEO; + // 输出rtmp packet + RtmpCodec::inputRtmp(_rtmp_packet); + _rtmp_packet = nullptr; + }, &_rtmp_packet->buffer); } void H265RtmpEncoder::makeVideoConfigPkt() { #ifdef ENABLE_MP4 - int8_t flags = FLV_CODEC_H265; - flags |= (FLV_KEY_FRAME << 4); - bool is_config = true; + auto flags = (uint8_t)RtmpVideoCodec::h265; + flags |= ((uint8_t)RtmpFrameType::key_frame << 4); auto pkt = RtmpPacket::create(); // header pkt->buffer.push_back(flags); - pkt->buffer.push_back(!is_config); + pkt->buffer.push_back((uint8_t)RtmpH264PacketType::h264_config_header); // cts pkt->buffer.append("\x0\x0\x0", 3); diff --git a/src/Rtmp/Rtmp.cpp b/src/Rtmp/Rtmp.cpp index a5e34773..84eb5dbc 100644 --- a/src/Rtmp/Rtmp.cpp +++ b/src/Rtmp/Rtmp.cpp @@ -10,10 +10,10 @@ #include "Rtmp.h" #include "Extension/Factory.h" -namespace mediakit{ -TitleMeta::TitleMeta(float dur_sec, size_t fileSize, const std::map &header) -{ +namespace mediakit { + +TitleMeta::TitleMeta(float dur_sec, size_t fileSize, const std::map &header) { _metadata.set("duration", dur_sec); _metadata.set("fileSize", (int)fileSize); _metadata.set("title", std::string("Streamed by ") + kServerName); @@ -22,14 +22,14 @@ TitleMeta::TitleMeta(float dur_sec, size_t fileSize, const std::mapgetVideoWidth() > 0 ){ +VideoMeta::VideoMeta(const VideoTrack::Ptr &video) { + if (video->getVideoWidth() > 0) { _metadata.set("width", video->getVideoWidth()); } - if(video->getVideoHeight() > 0 ){ + if (video->getVideoHeight() > 0) { _metadata.set("height", video->getVideoHeight()); } - if(video->getVideoFps() > 0 ){ + if (video->getVideoFps() > 0) { _metadata.set("framerate", video->getVideoFps()); } if (video->getBitRate()) { @@ -39,26 +39,26 @@ VideoMeta::VideoMeta(const VideoTrack::Ptr &video){ _metadata.set("videocodecid", Factory::getAmfByCodecId(_codecId)); } -AudioMeta::AudioMeta(const AudioTrack::Ptr &audio){ +AudioMeta::AudioMeta(const AudioTrack::Ptr &audio) { if (audio->getBitRate()) { _metadata.set("audiodatarate", audio->getBitRate() / 1024); } - if(audio->getAudioSampleRate() > 0){ + if (audio->getAudioSampleRate() > 0) { _metadata.set("audiosamplerate", audio->getAudioSampleRate()); } - if(audio->getAudioSampleBit() > 0){ + if (audio->getAudioSampleBit() > 0) { _metadata.set("audiosamplesize", audio->getAudioSampleBit()); } - if(audio->getAudioChannel() > 0){ + if (audio->getAudioChannel() > 0) { _metadata.set("stereo", audio->getAudioChannel() > 1); } _codecId = audio->getCodecId(); _metadata.set("audiocodecid", Factory::getAmfByCodecId(_codecId)); } -uint8_t getAudioRtmpFlags(const Track::Ptr &track){ - switch (track->getTrackType()){ - case TrackAudio : { +uint8_t getAudioRtmpFlags(const Track::Ptr &track) { + switch (track->getTrackType()) { + case TrackAudio: { auto audioTrack = std::dynamic_pointer_cast(track); if (!audioTrack) { WarnL << "获取AudioTrack失败"; @@ -68,21 +68,21 @@ uint8_t getAudioRtmpFlags(const Track::Ptr &track){ auto iChannel = audioTrack->getAudioChannel(); auto iSampleBit = audioTrack->getAudioSampleBit(); - uint8_t flvAudioType ; - switch (track->getCodecId()){ - case CodecG711A : flvAudioType = FLV_CODEC_G711A; break; - case CodecG711U : flvAudioType = FLV_CODEC_G711U; break; - case CodecOpus : { - flvAudioType = FLV_CODEC_OPUS; - //opus不通过flags获取音频相关信息 + uint8_t flvAudioType; + switch (track->getCodecId()) { + case CodecG711A: flvAudioType = (uint8_t)RtmpAudioCodec::g711a; break; + case CodecG711U: flvAudioType = (uint8_t)RtmpAudioCodec::g711u; break; + case CodecOpus: { + flvAudioType = (uint8_t)RtmpAudioCodec::opus; + // opus不通过flags获取音频相关信息 iSampleRate = 44100; iSampleBit = 16; iChannel = 2; break; } - case CodecAAC : { - flvAudioType = FLV_CODEC_AAC; - //aac不通过flags获取音频相关信息 + case CodecAAC: { + flvAudioType = (uint8_t)RtmpAudioCodec::aac; + // aac不通过flags获取音频相关信息 iSampleRate = 44100; iSampleBit = 16; iChannel = 2; @@ -93,23 +93,15 @@ uint8_t getAudioRtmpFlags(const Track::Ptr &track){ uint8_t flvSampleRate; switch (iSampleRate) { - case 44100: - flvSampleRate = 3; - break; - case 22050: - flvSampleRate = 2; - break; - case 11025: - flvSampleRate = 1; - break; + case 44100: flvSampleRate = 3; break; + case 22050: flvSampleRate = 2; break; + case 11025: flvSampleRate = 1; break; case 16000: // nellymoser only case 8000: // nellymoser only case 5512: // not MP3 flvSampleRate = 0; break; - default: - WarnL << "FLV does not support sample rate " << iSampleRate << " ,choose from (44100, 22050, 11025)"; - return 0; + default: WarnL << "FLV does not support sample rate " << iSampleRate << " ,choose from (44100, 22050, 11025)"; return 0; } uint8_t flvStereoOrMono = (iChannel > 1); @@ -117,32 +109,28 @@ uint8_t getAudioRtmpFlags(const Track::Ptr &track){ return (flvAudioType << 4) | (flvSampleRate << 2) | (flvSampleBit << 1) | flvStereoOrMono; } - default : return 0; + default: return 0; } } - void Metadata::addTrack(AMFValue &metadata, const Track::Ptr &track) { Metadata::Ptr new_metadata; switch (track->getTrackType()) { case TrackVideo: { new_metadata = std::make_shared(std::dynamic_pointer_cast(track)); - } break; + } case TrackAudio: { new_metadata = std::make_shared(std::dynamic_pointer_cast(track)); - } break; - default: - return; + } + default: return; } - new_metadata->getMetadata().object_for_each([&](const std::string &key, const AMFValue &value) { - metadata.set(key, value); - }); + new_metadata->getMetadata().object_for_each([&](const std::string &key, const AMFValue &value) { metadata.set(key, value); }); } -RtmpPacket::Ptr RtmpPacket::create(){ +RtmpPacket::Ptr RtmpPacket::create() { #if 0 static ResourcePool packet_pool; static onceToken token([]() { @@ -156,8 +144,7 @@ RtmpPacket::Ptr RtmpPacket::create(){ #endif } -void RtmpPacket::clear() -{ +void RtmpPacket::clear() { is_abs_stamp = false; time_stamp = 0; ts_field = 0; @@ -165,36 +152,42 @@ void RtmpPacket::clear() buffer.clear(); } -bool RtmpPacket::isVideoKeyFrame() const -{ - return type_id == MSG_VIDEO && (uint8_t)buffer[0] >> 4 == FLV_KEY_FRAME && (uint8_t)buffer[1] == 1; +bool RtmpPacket::isVideoKeyFrame() const { + if (type_id != MSG_VIDEO) { + 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) { - case MSG_VIDEO: return buffer[1] == 0; - case MSG_AUDIO: { - switch (getMediaType()) { - case FLV_CODEC_AAC: return buffer[1] == 0; - default: return false; + case MSG_VIDEO: return (RtmpH264PacketType)buffer[1] == RtmpH264PacketType::h264_config_header; + case MSG_AUDIO: { + switch ((RtmpAudioCodec)getRtmpCodecId()) { + case RtmpAudioCodec::aac: return (RtmpAACPacketType)buffer[1] == RtmpAACPacketType::aac_config_header; + default: return false; + } } - } - default: return false; + default: return false; } } -int RtmpPacket::getMediaType() const -{ +int RtmpPacket::getRtmpCodecId() const { switch (type_id) { - case MSG_VIDEO: return (uint8_t)buffer[0] & 0x0F; - case MSG_AUDIO: return (uint8_t)buffer[0] >> 4; - default: return 0; + case MSG_VIDEO: return (uint8_t)buffer[0] & 0x0F; + case MSG_AUDIO: return (uint8_t)buffer[0] >> 4; + default: return 0; } } -int RtmpPacket::getAudioSampleRate() const -{ +int RtmpPacket::getAudioSampleRate() const { if (type_id != MSG_AUDIO) { return 0; } @@ -203,8 +196,7 @@ int RtmpPacket::getAudioSampleRate() const return sampleRate[flvSampleRate]; } -int RtmpPacket::getAudioSampleBit() const -{ +int RtmpPacket::getAudioSampleBit() const { if (type_id != MSG_AUDIO) { return 0; } @@ -213,8 +205,7 @@ int RtmpPacket::getAudioSampleBit() const return sampleBit[flvSampleBit]; } -int RtmpPacket::getAudioChannel() const -{ +int RtmpPacket::getAudioChannel() const { if (type_id != MSG_AUDIO) { return 0; } @@ -223,8 +214,7 @@ int RtmpPacket::getAudioChannel() const return channel[flvStereoOrMono]; } -RtmpPacket & RtmpPacket::operator=(const RtmpPacket &that) -{ +RtmpPacket &RtmpPacket::operator=(const RtmpPacket &that) { is_abs_stamp = that.is_abs_stamp; stream_index = that.stream_index; body_size = that.body_size; @@ -234,25 +224,20 @@ RtmpPacket & RtmpPacket::operator=(const RtmpPacket &that) return *this; } -RtmpHandshake::RtmpHandshake(uint32_t _time, uint8_t *_random /*= nullptr*/) -{ +RtmpHandshake::RtmpHandshake(uint32_t _time, uint8_t *_random /*= nullptr*/) { _time = htonl(_time); memcpy(time_stamp, &_time, 4); if (!_random) { random_generate((char *)random, sizeof(random)); - } - else { + } else { memcpy(random, _random, sizeof(random)); } } -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, 0x6c, 0x69, 0x6e, 0x2d, 0x77, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x40, 0x31, 0x32, 0x36, 0x2e, 0x63, 0x6f, 0x6d }; +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, + 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++) { bytes[i] = cdata[rand() % (sizeof(cdata) - 1)]; } @@ -286,9 +271,9 @@ CodecId parseVideoRtmpPacket(const uint8_t *data, size_t size, RtmpPacketInfo *i // IsExHeader == 0 info->is_enhanced = false; 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: { CHECK(size >= 1, "Invalid rtmp buffer size: ", size); 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]; 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; } -}//namespace mediakit +} // namespace mediakit namespace toolkit { - StatisticImp(mediakit::RtmpPacket); +StatisticImp(mediakit::RtmpPacket); } \ No newline at end of file diff --git a/src/Rtmp/Rtmp.h b/src/Rtmp/Rtmp.h index d33d9d72..01fc2fbf 100644 --- a/src/Rtmp/Rtmp.h +++ b/src/Rtmp/Rtmp.h @@ -63,18 +63,6 @@ #define CHUNK_AUDIO 6 /*音频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 { #if defined(_WIN32) @@ -181,12 +169,9 @@ public: } void clear(); - bool isVideoKeyFrame() const; bool isCfgFrame() const; - - int getMediaType() const; - + int getRtmpCodecId() const; int getAudioSampleRate() const; int getAudioSampleBit() const; int getAudioChannel() const; @@ -269,6 +254,10 @@ private: //根据音频track获取flags 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 { reserved = 0, 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 }; +// UB [4]; Codec Identifier. enum class RtmpVideoCodec : uint8_t { h263 = 2, // Sorenson H.263 screen_video = 3, // Screen video @@ -288,12 +278,15 @@ enum class RtmpVideoCodec : uint8_t { h265 = 12, // 国内扩展 }; +// UI8; enum class RtmpH264PacketType : uint8_t { - h264_config_header = 0, // AVC sequence header(sps/pps) - h264_nalu = 1, // AVC NALU - h264_end_seq = 2, // AVC end of sequence (lower level NALU sequence ender is not REQUIRED or supported) + h264_config_header = 0, // AVC or HEVC sequence header(sps/pps) + h264_nalu = 1, // AVC or HEVC NALU + 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 { PacketTypeSequenceStart = 0, PacketTypeCodedFrames = 1, @@ -321,15 +314,49 @@ enum class RtmpPacketType : uint8_t { 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 { CodecId codec = CodecInvalid; bool is_enhanced; union { struct { RtmpFrameType frame_type; - RtmpVideoCodec rtmp_codec; - RtmpPacketType pkt_type; - RtmpH264PacketType h264_pkt_type; + RtmpPacketType pkt_type; // enhanced = true + RtmpH264PacketType h264_pkt_type; // enhanced = false } video; }; }; diff --git a/src/Rtmp/RtmpDemuxer.cpp b/src/Rtmp/RtmpDemuxer.cpp index 625cb652..e591acbf 100644 --- a/src/Rtmp/RtmpDemuxer.cpp +++ b/src/Rtmp/RtmpDemuxer.cpp @@ -132,7 +132,7 @@ void RtmpDemuxer::inputRtmp(const RtmpPacket::Ptr &pkt) { case MSG_AUDIO: { if (!_try_get_audio_track) { _try_get_audio_track = true; - auto codec = AMFValue(pkt->getMediaType()); + auto codec = AMFValue(pkt->getRtmpCodecId()); makeAudioTrack(codec, pkt->getAudioSampleRate(), pkt->getAudioChannel(), pkt->getAudioSampleBit(), 0); } if (_audio_rtmp_decoder) {