From f35771a83e3bc5c3b66a9b88da58a6efc6e2581c Mon Sep 17 00:00:00 2001 From: mtdxc Date: Sun, 19 Oct 2025 11:56:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84ertmp=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=20(#4505)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加多种Codec支持,并修复一些bug: - opus 非标准实现,不输出config frame,与旧的实现保持一致 - 添加RTMP_CODEC_MAP宏,精简代码 --- ext-codec/OpusRtmp.cpp | 43 +++++++++++++++++++++++++++++------------- ext-codec/VpxRtmp.cpp | 30 ++++------------------------- src/Rtmp/Rtmp.cpp | 35 +++++++++++++++++++++++++++++++++- src/Rtmp/Rtmp.h | 20 +++++++++++++++++++- 4 files changed, 87 insertions(+), 41 deletions(-) diff --git a/ext-codec/OpusRtmp.cpp b/ext-codec/OpusRtmp.cpp index 19e29be1..b7325363 100644 --- a/ext-codec/OpusRtmp.cpp +++ b/ext-codec/OpusRtmp.cpp @@ -35,6 +35,14 @@ void OpusRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) { outputFrame(data, size, pkt->time_stamp, pkt->time_stamp); } } else { + if (codec == RtmpAudioCodec::aac) { + uint8_t pkt_type = *data; + data++; size--; + if (pkt_type == (uint8_t)RtmpAACPacketType::aac_config_header) { + getTrack()->setExtraData((uint8_t *)data, size); + return; + } + } outputFrame(data, size, pkt->time_stamp, pkt->time_stamp); } } @@ -53,11 +61,14 @@ bool OpusRtmpEncoder::inputFrame(const Frame::Ptr &frame) { if (_enhanced) { uint8_t flags = ((uint8_t)RtmpAudioCodec::ex_header << 4) | (uint8_t)RtmpPacketType::PacketTypeCodedFrames; packet->buffer.push_back(flags); - uint32_t fourcc = static_cast(RtmpAudioCodec::fourcc_opus); + uint32_t fourcc = htonl(getCodecFourCC(getTrack()->getCodecId())); packet->buffer.append(reinterpret_cast(&fourcc), 4); } else { uint8_t flags = getAudioRtmpFlags(getTrack()); packet->buffer.push_back(flags); + if (getTrack()->getCodecId() == CodecAAC) { + packet->buffer.push_back((uint8_t)RtmpAACPacketType::aac_raw); + } } packet->buffer.append(frame->data(), frame->size()); packet->body_size = packet->buffer.size(); @@ -74,23 +85,29 @@ void OpusRtmpEncoder::makeConfigPacket() { auto extra_data = getTrack()->getExtraData(); if (!extra_data || !extra_data->size()) return; - auto pkt = RtmpPacket::create(); + auto packet = RtmpPacket::create(); if (_enhanced) { uint8_t flags = ((uint8_t)RtmpAudioCodec::ex_header << 4) | (uint8_t)RtmpPacketType::PacketTypeSequenceStart; - pkt->buffer.push_back(flags); - uint32_t fourcc = static_cast(RtmpAudioCodec::fourcc_opus); - pkt->buffer.append(reinterpret_cast(&fourcc), 4); + packet->buffer.push_back(flags); + uint32_t fourcc = htonl(getCodecFourCC(getTrack()->getCodecId())); + packet->buffer.append(reinterpret_cast(&fourcc), 4); } else { uint8_t flags = getAudioRtmpFlags(getTrack()); - pkt->buffer.push_back(flags); + packet->buffer.push_back(flags); + if (getTrack()->getCodecId() == CodecAAC) { + packet->buffer.push_back((uint8_t)RtmpAACPacketType::aac_config_header); + } + else{ + return ; + } } - 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; - pkt->time_stamp = 0; - pkt->type_id = MSG_AUDIO; - RtmpCodec::inputRtmp(pkt); + packet->buffer.append(extra_data->data(), extra_data->size()); + packet->body_size = packet->buffer.size(); + packet->chunk_id = CHUNK_AUDIO; + packet->stream_index = STREAM_MEDIA; + packet->time_stamp = 0; + packet->type_id = MSG_AUDIO; + RtmpCodec::inputRtmp(packet); } } // namespace mediakit diff --git a/ext-codec/VpxRtmp.cpp b/ext-codec/VpxRtmp.cpp index da96ad74..34aedca6 100644 --- a/ext-codec/VpxRtmp.cpp +++ b/ext-codec/VpxRtmp.cpp @@ -87,12 +87,7 @@ bool VpxRtmpEncoder::inputFrame(const Frame::Ptr &frame) { auto header = (RtmpVideoHeaderEnhanced *)buff; header->enhanced = 1; header->frame_type = frame->keyFrame() ? (int)RtmpFrameType::key_frame : (int)RtmpFrameType::inter_frame; - switch (frame->getCodecId()) { - case CodecVP8: header->fourcc = htonl((uint32_t)RtmpVideoCodec::fourcc_vp8); break; - case CodecVP9: header->fourcc = htonl((uint32_t)RtmpVideoCodec::fourcc_vp9); break; - case CodecAV1: header->fourcc = htonl((uint32_t)RtmpVideoCodec::fourcc_av1); break; - default: break; - } + header->fourcc = htonl(getCodecFourCC(frame->getCodecId())); buff += RtmpPacketInfo::kEnhancedRtmpHeaderSize; if (cts) { header->pkt_type = (uint8_t)RtmpPacketType::PacketTypeCodedFrames; @@ -103,13 +98,7 @@ bool VpxRtmpEncoder::inputFrame(const Frame::Ptr &frame) { } } else { // flags - uint8_t flags = 0; - switch (getTrack()->getCodecId()) { - case CodecVP8: flags = (uint8_t)RtmpVideoCodec::vp8; break; - case CodecVP9: flags = (uint8_t)RtmpVideoCodec::vp9; break; - case CodecAV1: flags = (uint8_t)RtmpVideoCodec::av1; break; - default: break; - } + uint8_t flags = getCodecFlags(frame->getCodecId()); flags |= (uint8_t)(frame->keyFrame() ? RtmpFrameType::key_frame : RtmpFrameType::inter_frame) << 4; buff[0] = flags; @@ -144,20 +133,9 @@ void VpxRtmpEncoder::makeConfigPacket() { header->enhanced = 1; header->pkt_type = (int)RtmpPacketType::PacketTypeSequenceStart; header->frame_type = (int)RtmpFrameType::key_frame; - switch (getTrack()->getCodecId()) { - case CodecVP8: header->fourcc = htonl((uint32_t)RtmpVideoCodec::fourcc_vp8); break; - case CodecVP9: header->fourcc = htonl((uint32_t)RtmpVideoCodec::fourcc_vp9); break; - case CodecAV1: header->fourcc = htonl((uint32_t)RtmpVideoCodec::fourcc_av1); break; - default: break; - } + header->fourcc = htonl(getCodecFourCC(getTrack()->getCodecId())); } else { - uint8_t flags = 0; - switch (getTrack()->getCodecId()) { - case CodecVP8: flags = (uint8_t)RtmpVideoCodec::vp8; break; - case CodecVP9: flags = (uint8_t)RtmpVideoCodec::vp9; break; - case CodecAV1: flags = (uint8_t)RtmpVideoCodec::av1; break; - default: break; - } + uint8_t flags = getCodecFlags(getTrack()->getCodecId()); flags |= ((uint8_t)RtmpFrameType::key_frame << 4); buff[0] = flags; buff[1] = (uint8_t)RtmpH264PacketType::h264_config_header; diff --git a/src/Rtmp/Rtmp.cpp b/src/Rtmp/Rtmp.cpp index 07ddfc0d..ff565f18 100644 --- a/src/Rtmp/Rtmp.cpp +++ b/src/Rtmp/Rtmp.cpp @@ -55,6 +55,33 @@ AudioMeta::AudioMeta(const AudioTrack::Ptr &audio) { _metadata.set("audiocodecid", Factory::getAmfByCodecId(audio->getCodecId())); } +uint8_t getCodecFlags(CodecId cid) { + switch(cid) { +#define XX(a, b, c) case a: return static_cast(b); + RTMP_CODEC_MAP(XX) +#undef XX + } + return 0; +} + +uint32_t getCodecFourCC(CodecId cid) { + switch(cid) { +#define XX(a, b, c) case a: return static_cast(c); + RTMP_CODEC_MAP(XX) +#undef XX + } + return 0; +} + +CodecId getFourccCodec(uint32_t id) { + switch(id) { +#define XX(a, b, c) case (uint32_t)c: return a; + RTMP_CODEC_MAP(XX) +#undef XX + } + return CodecInvalid; +} + uint8_t getAudioRtmpFlags(const Track::Ptr &track) { track->update(); switch (track->getTrackType()) { @@ -167,7 +194,13 @@ bool RtmpPacket::isVideoKeyFrame() const { bool RtmpPacket::isConfigFrame() const { switch (type_id) { case MSG_AUDIO: { - return (RtmpAudioCodec)getRtmpCodecId() == RtmpAudioCodec::aac && (RtmpAACPacketType)buffer[1] == RtmpAACPacketType::aac_config_header; + switch ((RtmpAudioCodec)getRtmpCodecId()) { + case RtmpAudioCodec::aac: + return (RtmpAACPacketType)buffer[1] == RtmpAACPacketType::aac_config_header; + case RtmpAudioCodec::ex_header: + return (RtmpPacketType)(buffer[0] & 0x0f) == RtmpPacketType::PacketTypeSequenceStart; + } + return false; } case MSG_VIDEO: { if (!isVideoKeyFrame()) { diff --git a/src/Rtmp/Rtmp.h b/src/Rtmp/Rtmp.h index 13b39e85..aa301bb4 100644 --- a/src/Rtmp/Rtmp.h +++ b/src/Rtmp/Rtmp.h @@ -382,9 +382,27 @@ enum class RtmpAudioCodec : uint32_t { ex_header = 9, // Enhanced audio; new, used to signal FOURCC mode aac = 10, opus = 13, // 国内扩展 - fourcc_opus = MKBETAG('O', 'p', 'u', 's') + fourcc_opus = MKBETAG('O', 'p', 'u', 's'), + fourcc_mp3 = MKBETAG('.', 'm', 'p', '3'), + fourcc_aac = MKBETAG('m', 'p', '4', 'a'), + fourcc_ac3 = MKBETAG('a', 'c', '-', '3'), + fourcc_flac = MKBETAG('f', 'L', 'a', 'C'), + }; +#define RTMP_CODEC_MAP(XX) \ + XX(CodecH264, RtmpVideoCodec::h264, RtmpVideoCodec::fourcc_avc1) \ + XX(CodecH265, RtmpVideoCodec::h265, RtmpVideoCodec::fourcc_hevc) \ + XX(CodecVP8, RtmpVideoCodec::vp8, RtmpVideoCodec::fourcc_vp8) \ + XX(CodecVP9, RtmpVideoCodec::vp9, RtmpVideoCodec::fourcc_vp9) \ + XX(CodecAV1, RtmpVideoCodec::av1, RtmpVideoCodec::fourcc_av1) \ + XX(CodecAAC, RtmpAudioCodec::aac, RtmpAudioCodec::fourcc_aac) \ + XX(CodecMP3, RtmpAudioCodec::mp3, RtmpAudioCodec::fourcc_mp3) \ + XX(CodecOpus, RtmpAudioCodec::opus, RtmpAudioCodec::fourcc_opus) +uint32_t getCodecFourCC(CodecId cid); +CodecId getFourccCodec(uint32_t id); +uint8_t getCodecFlags(CodecId cid); + // UI8; enum class RtmpAACPacketType : uint8_t { aac_config_header = 0, // AAC sequence header