Files
ZLMediaKit/ext-codec/VpxRtmp.cpp
mtdxc f35771a83e 完善ertmp相关代码 (#4505)
增加多种Codec支持,并修复一些bug:
- opus 非标准实现,不输出config frame,与旧的实现保持一致
- 添加RTMP_CODEC_MAP宏,精简代码
2025-10-19 11:56:35 +08:00

154 lines
5.7 KiB
C++

/*
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* 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 "VpxRtmp.h"
#include "Rtmp/utils.h"
#include "Common/config.h"
#include "Extension/Factory.h"
using namespace std;
using namespace toolkit;
namespace mediakit {
void VpxRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) {
if (_info.codec == CodecInvalid) {
// First, determine if it is an enhanced rtmp
parseVideoRtmpPacket((uint8_t *)pkt->data(), pkt->size(), &_info);
}
if (_info.is_enhanced) {
// Enhanced rtmp
parseVideoRtmpPacket((uint8_t *)pkt->data(), pkt->size(), &_info);
if (!_info.is_enhanced || _info.codec != getTrack()->getCodecId()) {
throw std::invalid_argument("Invalid enhanced-rtmp packet!");
}
auto data = (uint8_t *)pkt->data() + RtmpPacketInfo::kEnhancedRtmpHeaderSize;
auto size = pkt->size() - RtmpPacketInfo::kEnhancedRtmpHeaderSize;
switch (_info.video.pkt_type) {
case RtmpPacketType::PacketTypeSequenceStart: {
getTrack()->setExtraData(data, size);
break;
}
case RtmpPacketType::PacketTypeCodedFramesX:
case RtmpPacketType::PacketTypeCodedFrames: {
auto pts = pkt->time_stamp;
if (RtmpPacketType::PacketTypeCodedFrames == _info.video.pkt_type) {
CHECK_RET(size > 3);
// SI24 = [CompositionTime Offset]
int32_t cts = (load_be24(data) + 0xff800000) ^ 0xff800000;
pts += cts;
data += 3;
size -= 3;
}
outputFrame((char*)data, size, pkt->time_stamp, pts);
break;
}
default:
WarnL << "Unknown pkt_type: " << (int)_info.video.pkt_type;
break;
}
} else {
CHECK_RET(pkt->size() > 5);
uint8_t *cts_ptr = (uint8_t *)(pkt->buffer.data() + 2);
int32_t cts = (load_be24(cts_ptr) + 0xff800000) ^ 0xff800000;
// 国内扩展(12) Vpx rtmp
if (pkt->isConfigFrame()) {
getTrack()->setExtraData((uint8_t *)pkt->data() + 5, pkt->size() - 5);
} else {
outputFrame(pkt->data() + 5, pkt->size() - 5, pkt->time_stamp, pkt->time_stamp + cts);
}
}
}
void VpxRtmpDecoder::outputFrame(const char *data, size_t size, uint32_t dts, uint32_t pts) {
RtmpCodec::inputFrame(Factory::getFrameFromPtr(getTrack()->getCodecId(), data, size, dts, pts));
}
////////////////////////////////////////////////////////////////////////
VpxRtmpEncoder::VpxRtmpEncoder(const Track::Ptr &track) : RtmpCodec(track) {
_enhanced = mINI::Instance()[Rtmp::kEnhanced];
}
bool VpxRtmpEncoder::inputFrame(const Frame::Ptr &frame) {
auto packet = RtmpPacket::create();
packet->buffer.resize(8 + frame->size());
char *buff = packet->data();
int32_t cts = frame->pts() - frame->dts();
if (_enhanced) {
auto header = (RtmpVideoHeaderEnhanced *)buff;
header->enhanced = 1;
header->frame_type = frame->keyFrame() ? (int)RtmpFrameType::key_frame : (int)RtmpFrameType::inter_frame;
header->fourcc = htonl(getCodecFourCC(frame->getCodecId()));
buff += RtmpPacketInfo::kEnhancedRtmpHeaderSize;
if (cts) {
header->pkt_type = (uint8_t)RtmpPacketType::PacketTypeCodedFrames;
set_be24(buff, cts);
buff += 3;
} else {
header->pkt_type = (uint8_t)RtmpPacketType::PacketTypeCodedFramesX;
}
} else {
// flags
uint8_t flags = getCodecFlags(frame->getCodecId());
flags |= (uint8_t)(frame->keyFrame() ? RtmpFrameType::key_frame : RtmpFrameType::inter_frame) << 4;
buff[0] = flags;
buff[1] = (uint8_t)RtmpH264PacketType::h264_nalu;
// cts
set_be24(&buff[2], cts);
buff += 5;
}
packet->time_stamp = frame->dts();
memcpy(buff, frame->data(), frame->size());
buff += frame->size();
packet->body_size = buff - packet->data();
packet->chunk_id = CHUNK_VIDEO;
packet->stream_index = STREAM_MEDIA;
packet->type_id = MSG_VIDEO;
// Output rtmp packet
RtmpCodec::inputRtmp(packet);
return true;
}
void VpxRtmpEncoder::makeConfigPacket() {
auto extra_data = getTrack()->getExtraData();
if (!extra_data || !extra_data->size())
return;
auto pkt = RtmpPacket::create();
pkt->body_size = 5 + extra_data->size();
pkt->buffer.resize(pkt->body_size);
auto buff = pkt->buffer.data();
if (_enhanced) {
auto header = (RtmpVideoHeaderEnhanced *)buff;
header->enhanced = 1;
header->pkt_type = (int)RtmpPacketType::PacketTypeSequenceStart;
header->frame_type = (int)RtmpFrameType::key_frame;
header->fourcc = htonl(getCodecFourCC(getTrack()->getCodecId()));
} else {
uint8_t flags = getCodecFlags(getTrack()->getCodecId());
flags |= ((uint8_t)RtmpFrameType::key_frame << 4);
buff[0] = flags;
buff[1] = (uint8_t)RtmpH264PacketType::h264_config_header;
// cts
memset(buff + 2, 0, 3);
}
memcpy(buff+5, extra_data->data(), extra_data->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