mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2026-06-12 19:24:22 +08:00
Fix RTMP proxy audio forwarding (#4745)
## Summary This fixes RTMP playback audio corruption and VLC playback compatibility when proxying some upstream RTMP streams through `addStreamProxy`. In the reproduced case, HTTP-FLV playback was normal, while RTMP playback had missing audio or occasional sharp noise in VLC. ## Root cause - RTMP aggregate message parsing copied the 4-byte `PreviousTagSize` field into the sub-message payload. This shifts the payload boundary and can corrupt subsequent audio packets. - `RtmpSession::onSendMedia` forwarded proxied audio/video packets with the packet's original chunk stream id. This can make audio packets use an unsuitable chunk id for RTMP playback. - The RTMP play response emitted non-essential `MSG_DATA` notifications (`|RtmpSampleAccess` and `NetStream.Data.Start`). FFmpeg tolerates these, but VLC may expose them as an extra `Data: none` stream and handle RTMP playback poorly. ## Changes - Exclude `PreviousTagSize` from aggregate sub-message payloads while still skipping it when advancing the parser cursor. - Send audio packets on `CHUNK_AUDIO` and video packets on `CHUNK_VIDEO` from `STREAM_MEDIA`; keep the original values for other packet types. - Avoid sending the non-essential RTMP play data notifications before metadata/config/media packets. ## Validation - Built `MediaServer` locally in Debug mode. - Proxied four live RTMP test streams via `addStreamProxy`. - Verified local RTMP and HTTP-FLV playback expose AAC audio tracks. - Decoded RTMP audio with `ffmpeg -xerror`; all tested streams completed without AAC decode errors. - Verified the VLC compatibility change removes the extra `Data: none` stream from RTMP output while preserving Video + Audio streams. - Built and deployed a Docker image locally with docker compose and re-tested RTMP/FLV audio playback.
This commit is contained in:
@@ -910,10 +910,7 @@ void RtmpProtocol::handle_chunk(RtmpPacket::Ptr packet) {
|
||||
ts |= (*ptr << 24);
|
||||
ptr += 1;
|
||||
ptr += 3;
|
||||
// 参考FFmpeg多拷贝了4个字节 [AUTO-TRANSLATED:d8aae4ae]
|
||||
// Reference FFmpeg copied 4 more bytes
|
||||
size += 4;
|
||||
if (ptr + size > ptr_tail) {
|
||||
if (ptr + size + 4 > ptr_tail) {
|
||||
break;
|
||||
}
|
||||
if (!first_message) {
|
||||
@@ -930,7 +927,7 @@ void RtmpProtocol::handle_chunk(RtmpPacket::Ptr packet) {
|
||||
sub_packet.stream_index = chunk_data.stream_index;
|
||||
sub_packet.chunk_id = chunk_data.chunk_id;
|
||||
handle_chunk(std::move(sub_packet_ptr));
|
||||
ptr += size;
|
||||
ptr += size + 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -273,17 +273,7 @@ void RtmpSession::sendPlayResponse(const string &err, const RtmpMediaSource::Ptr
|
||||
"details", _media_info.stream,
|
||||
"clientid", "0"});
|
||||
|
||||
// |RtmpSampleAccess(true, true)
|
||||
AMFEncoder invoke;
|
||||
invoke << "|RtmpSampleAccess" << true << true;
|
||||
sendResponse(MSG_DATA, invoke.data());
|
||||
|
||||
//onStatus(NetStream.Data.Start)
|
||||
invoke.clear();
|
||||
AMFValue obj(AMF_OBJECT);
|
||||
obj.set("code", "NetStream.Data.Start");
|
||||
invoke << "onStatus" << obj;
|
||||
sendResponse(MSG_DATA, invoke.data());
|
||||
|
||||
//onStatus(NetStream.Play.PublishNotify)
|
||||
sendStatus({ "level", "status",
|
||||
@@ -587,7 +577,17 @@ void RtmpSession::onCmd_seek(AMFDecoder &dec) {
|
||||
}
|
||||
|
||||
void RtmpSession::onSendMedia(const RtmpPacket::Ptr &pkt) {
|
||||
sendRtmp(pkt->type_id, pkt->stream_index, pkt, pkt->time_stamp, pkt->chunk_id);
|
||||
switch (pkt->type_id) {
|
||||
case MSG_AUDIO:
|
||||
sendRtmp(pkt->type_id, STREAM_MEDIA, pkt, pkt->time_stamp, CHUNK_AUDIO);
|
||||
break;
|
||||
case MSG_VIDEO:
|
||||
sendRtmp(pkt->type_id, STREAM_MEDIA, pkt, pkt->time_stamp, CHUNK_VIDEO);
|
||||
break;
|
||||
default:
|
||||
sendRtmp(pkt->type_id, pkt->stream_index, pkt, pkt->time_stamp, pkt->chunk_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool RtmpSession::close(MediaSource &sender) {
|
||||
|
||||
Reference in New Issue
Block a user