完善ertmp相关代码 (#4505)

增加多种Codec支持,并修复一些bug:
- opus 非标准实现,不输出config frame,与旧的实现保持一致
- 添加RTMP_CODEC_MAP宏,精简代码
This commit is contained in:
mtdxc
2025-10-19 11:56:35 +08:00
committed by GitHub
parent 5c58f39046
commit f35771a83e
4 changed files with 87 additions and 41 deletions

View File

@@ -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<uint32_t>(RtmpAudioCodec::fourcc_opus);
uint32_t fourcc = htonl(getCodecFourCC(getTrack()->getCodecId()));
packet->buffer.append(reinterpret_cast<char *>(&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<uint32_t>(RtmpAudioCodec::fourcc_opus);
pkt->buffer.append(reinterpret_cast<char *>(&fourcc), 4);
packet->buffer.push_back(flags);
uint32_t fourcc = htonl(getCodecFourCC(getTrack()->getCodecId()));
packet->buffer.append(reinterpret_cast<char *>(&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

View File

@@ -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;

View File

@@ -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<uint8_t>(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<uint32_t>(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()) {

View File

@@ -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