Fix H26xPacketBuffer Behavior Changes for Padding Packets
This commit fixes the issue of H26xPacketBuffer not supporting the RTP padding packet. Bug: webrtc:383841353 Change-Id: Ibd87cd9c18577d990fa56a2fdfed1552d33b58a2 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/371840 Reviewed-by: Sergey Silkin <ssilkin@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Sergey Silkin <ssilkin@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43586}
This commit is contained in:
parent
6ef206aa1a
commit
6f866347ff
@ -103,6 +103,24 @@ H26xPacketBuffer::H26xPacketBuffer(bool h264_idr_only_keyframes_allowed)
|
|||||||
last_continuous_in_sequence_.fill(std::numeric_limits<int64_t>::min());
|
last_continuous_in_sequence_.fill(std::numeric_limits<int64_t>::min());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
H26xPacketBuffer::InsertResult H26xPacketBuffer::InsertPadding(
|
||||||
|
uint16_t unwrapped_seq_num) {
|
||||||
|
int64_t* last_continuous_unwrapped_seq_num =
|
||||||
|
GetContinuousSequence(last_continuous_in_sequence_, unwrapped_seq_num);
|
||||||
|
if (last_continuous_unwrapped_seq_num == nullptr) {
|
||||||
|
last_continuous_in_sequence_[last_continuous_in_sequence_index_] =
|
||||||
|
unwrapped_seq_num;
|
||||||
|
last_continuous_unwrapped_seq_num =
|
||||||
|
&last_continuous_in_sequence_[last_continuous_in_sequence_index_];
|
||||||
|
last_continuous_in_sequence_index_ =
|
||||||
|
(last_continuous_in_sequence_index_ + 1) %
|
||||||
|
last_continuous_in_sequence_.size();
|
||||||
|
} else {
|
||||||
|
*last_continuous_unwrapped_seq_num = unwrapped_seq_num;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
H26xPacketBuffer::InsertResult H26xPacketBuffer::InsertPacket(
|
H26xPacketBuffer::InsertResult H26xPacketBuffer::InsertPacket(
|
||||||
std::unique_ptr<Packet> packet) {
|
std::unique_ptr<Packet> packet) {
|
||||||
RTC_DCHECK(packet->video_header.codec == kVideoCodecH264 ||
|
RTC_DCHECK(packet->video_header.codec == kVideoCodecH264 ||
|
||||||
|
|||||||
@ -37,6 +37,7 @@ class H26xPacketBuffer {
|
|||||||
|
|
||||||
ABSL_MUST_USE_RESULT InsertResult
|
ABSL_MUST_USE_RESULT InsertResult
|
||||||
InsertPacket(std::unique_ptr<Packet> packet);
|
InsertPacket(std::unique_ptr<Packet> packet);
|
||||||
|
ABSL_MUST_USE_RESULT InsertResult InsertPadding(uint16_t unwrapped_seq_num);
|
||||||
|
|
||||||
// Out of band supplied codec parameters for H.264.
|
// Out of band supplied codec parameters for H.264.
|
||||||
void SetSpropParameterSets(const std::string& sprop_parameter_sets);
|
void SetSpropParameterSets(const std::string& sprop_parameter_sets);
|
||||||
|
|||||||
@ -363,6 +363,7 @@ void RtpVideoStreamReceiver2::AddReceiveCodec(
|
|||||||
payload_type, raw_payload ? std::make_unique<VideoRtpDepacketizerRaw>()
|
payload_type, raw_payload ? std::make_unique<VideoRtpDepacketizerRaw>()
|
||||||
: CreateVideoRtpDepacketizer(video_codec));
|
: CreateVideoRtpDepacketizer(video_codec));
|
||||||
pt_codec_params_.emplace(payload_type, codec_params);
|
pt_codec_params_.emplace(payload_type, codec_params);
|
||||||
|
pt_codec_.emplace(payload_type, video_codec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtpVideoStreamReceiver2::RemoveReceiveCodecs() {
|
void RtpVideoStreamReceiver2::RemoveReceiveCodecs() {
|
||||||
@ -372,6 +373,7 @@ void RtpVideoStreamReceiver2::RemoveReceiveCodecs() {
|
|||||||
payload_type_map_.clear();
|
payload_type_map_.clear();
|
||||||
packet_buffer_.ResetSpsPpsIdrIsH264Keyframe();
|
packet_buffer_.ResetSpsPpsIdrIsH264Keyframe();
|
||||||
h26x_packet_buffer_.reset();
|
h26x_packet_buffer_.reset();
|
||||||
|
pt_codec_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Syncable::Info> RtpVideoStreamReceiver2::GetSyncInfo() const {
|
std::optional<Syncable::Info> RtpVideoStreamReceiver2::GetSyncInfo() const {
|
||||||
@ -692,7 +694,8 @@ bool RtpVideoStreamReceiver2::OnReceivedPayloadData(
|
|||||||
packet->times_nacked = times_nacked;
|
packet->times_nacked = times_nacked;
|
||||||
|
|
||||||
if (codec_payload.size() == 0) {
|
if (codec_payload.size() == 0) {
|
||||||
NotifyReceiverOfEmptyPacket(packet->seq_num());
|
NotifyReceiverOfEmptyPacket(packet->seq_num(),
|
||||||
|
IsH26xPayloadType(packet->payload_type));
|
||||||
rtcp_feedback_buffer_.SendBufferedRtcpFeedback();
|
rtcp_feedback_buffer_.SendBufferedRtcpFeedback();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1108,6 +1111,15 @@ RtpVideoStreamReceiver2::GetSenderReportStats() const {
|
|||||||
return rtp_rtcp_->GetSenderReportStats();
|
return rtp_rtcp_->GetSenderReportStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RtpVideoStreamReceiver2::IsH26xPayloadType(uint8_t payload_type) const {
|
||||||
|
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
||||||
|
auto it = pt_codec_.find(payload_type);
|
||||||
|
if (it == pt_codec_.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return it->second == kVideoCodecH264 || it->second == kVideoCodecH265;
|
||||||
|
}
|
||||||
|
|
||||||
void RtpVideoStreamReceiver2::ManageFrame(
|
void RtpVideoStreamReceiver2::ManageFrame(
|
||||||
std::unique_ptr<RtpFrameObject> frame) {
|
std::unique_ptr<RtpFrameObject> frame) {
|
||||||
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
||||||
@ -1121,7 +1133,8 @@ void RtpVideoStreamReceiver2::ReceivePacket(const RtpPacketReceived& packet) {
|
|||||||
// Padding or keep-alive packet.
|
// Padding or keep-alive packet.
|
||||||
// TODO(nisse): Could drop empty packets earlier, but need to figure out how
|
// TODO(nisse): Could drop empty packets earlier, but need to figure out how
|
||||||
// they should be counted in stats.
|
// they should be counted in stats.
|
||||||
NotifyReceiverOfEmptyPacket(packet.SequenceNumber());
|
NotifyReceiverOfEmptyPacket(packet.SequenceNumber(),
|
||||||
|
IsH26xPayloadType(packet.PayloadType()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (packet.PayloadType() == red_payload_type_) {
|
if (packet.PayloadType() == red_payload_type_) {
|
||||||
@ -1191,7 +1204,8 @@ void RtpVideoStreamReceiver2::ParseAndHandleEncapsulatingHeader(
|
|||||||
if (packet.payload()[0] == ulpfec_receiver_->ulpfec_payload_type()) {
|
if (packet.payload()[0] == ulpfec_receiver_->ulpfec_payload_type()) {
|
||||||
// Notify video_receiver about received FEC packets to avoid NACKing these
|
// Notify video_receiver about received FEC packets to avoid NACKing these
|
||||||
// packets.
|
// packets.
|
||||||
NotifyReceiverOfEmptyPacket(packet.SequenceNumber());
|
NotifyReceiverOfEmptyPacket(packet.SequenceNumber(),
|
||||||
|
IsH26xPayloadType(packet.PayloadType()));
|
||||||
}
|
}
|
||||||
if (ulpfec_receiver_->AddReceivedRedPacket(packet)) {
|
if (ulpfec_receiver_->AddReceivedRedPacket(packet)) {
|
||||||
ulpfec_receiver_->ProcessReceivedFec();
|
ulpfec_receiver_->ProcessReceivedFec();
|
||||||
@ -1201,13 +1215,18 @@ void RtpVideoStreamReceiver2::ParseAndHandleEncapsulatingHeader(
|
|||||||
// In the case of a video stream without picture ids and no rtx the
|
// In the case of a video stream without picture ids and no rtx the
|
||||||
// RtpFrameReferenceFinder will need to know about padding to
|
// RtpFrameReferenceFinder will need to know about padding to
|
||||||
// correctly calculate frame references.
|
// correctly calculate frame references.
|
||||||
void RtpVideoStreamReceiver2::NotifyReceiverOfEmptyPacket(uint16_t seq_num) {
|
void RtpVideoStreamReceiver2::NotifyReceiverOfEmptyPacket(uint16_t seq_num,
|
||||||
|
bool is_h26x) {
|
||||||
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
||||||
RTC_DCHECK_RUN_ON(&worker_task_checker_);
|
RTC_DCHECK_RUN_ON(&worker_task_checker_);
|
||||||
|
|
||||||
OnCompleteFrames(reference_finder_->PaddingReceived(seq_num));
|
OnCompleteFrames(reference_finder_->PaddingReceived(seq_num));
|
||||||
|
|
||||||
OnInsertedPacket(packet_buffer_.InsertPadding(seq_num));
|
if (is_h26x && h26x_packet_buffer_) {
|
||||||
|
OnInsertedPacket(h26x_packet_buffer_->InsertPadding(seq_num));
|
||||||
|
} else {
|
||||||
|
OnInsertedPacket(packet_buffer_.InsertPadding(seq_num));
|
||||||
|
}
|
||||||
if (nack_module_) {
|
if (nack_module_) {
|
||||||
nack_module_->OnReceivedPacket(seq_num, /*is_recovered=*/false);
|
nack_module_->OnReceivedPacket(seq_num, /*is_recovered=*/false);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -300,7 +300,7 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender,
|
|||||||
// This function assumes that it's being called from only one thread.
|
// This function assumes that it's being called from only one thread.
|
||||||
void ParseAndHandleEncapsulatingHeader(const RtpPacketReceived& packet)
|
void ParseAndHandleEncapsulatingHeader(const RtpPacketReceived& packet)
|
||||||
RTC_RUN_ON(packet_sequence_checker_);
|
RTC_RUN_ON(packet_sequence_checker_);
|
||||||
void NotifyReceiverOfEmptyPacket(uint16_t seq_num)
|
void NotifyReceiverOfEmptyPacket(uint16_t seq_num, bool is_h26x)
|
||||||
RTC_RUN_ON(packet_sequence_checker_);
|
RTC_RUN_ON(packet_sequence_checker_);
|
||||||
bool IsRedEnabled() const;
|
bool IsRedEnabled() const;
|
||||||
void InsertSpsPpsIntoTracker(uint8_t payload_type)
|
void InsertSpsPpsIntoTracker(uint8_t payload_type)
|
||||||
@ -320,6 +320,9 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender,
|
|||||||
FrameInstrumentationData>& frame_instrumentation_data,
|
FrameInstrumentationData>& frame_instrumentation_data,
|
||||||
int spatial_idx);
|
int spatial_idx);
|
||||||
|
|
||||||
|
bool IsH26xPayloadType(uint8_t payload_type) const
|
||||||
|
RTC_RUN_ON(packet_sequence_checker_);
|
||||||
|
|
||||||
const Environment env_;
|
const Environment env_;
|
||||||
TaskQueueBase* const worker_queue_;
|
TaskQueueBase* const worker_queue_;
|
||||||
|
|
||||||
@ -410,6 +413,11 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender,
|
|||||||
// Maps a payload type to a map of out-of-band supplied codec parameters.
|
// Maps a payload type to a map of out-of-band supplied codec parameters.
|
||||||
std::map<uint8_t, webrtc::CodecParameterMap> pt_codec_params_
|
std::map<uint8_t, webrtc::CodecParameterMap> pt_codec_params_
|
||||||
RTC_GUARDED_BY(packet_sequence_checker_);
|
RTC_GUARDED_BY(packet_sequence_checker_);
|
||||||
|
|
||||||
|
// Maps payload type to the VideoCodecType.
|
||||||
|
std::map<uint8_t, webrtc::VideoCodecType> pt_codec_
|
||||||
|
RTC_GUARDED_BY(packet_sequence_checker_);
|
||||||
|
|
||||||
int16_t last_payload_type_ RTC_GUARDED_BY(packet_sequence_checker_) = -1;
|
int16_t last_payload_type_ RTC_GUARDED_BY(packet_sequence_checker_) = -1;
|
||||||
|
|
||||||
bool has_received_frame_ RTC_GUARDED_BY(packet_sequence_checker_);
|
bool has_received_frame_ RTC_GUARDED_BY(packet_sequence_checker_);
|
||||||
|
|||||||
@ -956,7 +956,19 @@ TEST_P(RtpVideoStreamReceiver2TestH264, ForceSpsPpsIdrIsKeyframe) {
|
|||||||
idr_video_header, 0);
|
idr_video_header, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RtpVideoStreamReceiver2Test, PaddingInMediaStream) {
|
class RtpVideoStreamReceiver2TestPadding
|
||||||
|
: public RtpVideoStreamReceiver2Test,
|
||||||
|
public ::testing::WithParamInterface<std::string> {
|
||||||
|
protected:
|
||||||
|
RtpVideoStreamReceiver2TestPadding()
|
||||||
|
: RtpVideoStreamReceiver2Test(GetParam()) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(PaddingInMediaStreamAndH26xPacketBuffer,
|
||||||
|
RtpVideoStreamReceiver2TestPadding,
|
||||||
|
Values("", "WebRTC-Video-H26xPacketBuffer/Enabled/"));
|
||||||
|
|
||||||
|
TEST_P(RtpVideoStreamReceiver2TestPadding, PaddingInMediaStream) {
|
||||||
RtpPacketReceived rtp_packet;
|
RtpPacketReceived rtp_packet;
|
||||||
RTPVideoHeader video_header = GetDefaultH264VideoHeader();
|
RTPVideoHeader video_header = GetDefaultH264VideoHeader();
|
||||||
rtc::CopyOnWriteBuffer data({'1', '2', '3'});
|
rtc::CopyOnWriteBuffer data({'1', '2', '3'});
|
||||||
@ -993,6 +1005,64 @@ TEST_F(RtpVideoStreamReceiver2Test, PaddingInMediaStream) {
|
|||||||
video_header, 0);
|
video_header, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(RtpVideoStreamReceiver2TestPadding, EmptyPaddingInMediaStream) {
|
||||||
|
constexpr int kH264PayloadType = 98;
|
||||||
|
RtpPacketReceived rtp_packet_idr, rtp_packet_padding, rtp_packet_slice;
|
||||||
|
// Example Stap-A packet with SPS, PPS, and IDR.
|
||||||
|
std::vector<uint8_t> raw_rtp_with_sps_pps_idr{
|
||||||
|
0x80, 0xe2, 0x13, 0xba, 0x87, 0xa0, 0x0a, 0x8a, 0x00, 0x00, 0x6f,
|
||||||
|
0x00, 0x78, 0x00, 0x19, 0x67, 0x42, 0x40, 0x29, 0x95, 0xb8, 0x78,
|
||||||
|
0x2f, 0xf9, 0x70, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00,
|
||||||
|
0x03, 0x00, 0x78, 0x8d, 0xa1, 0xc3, 0x2e, 0x00, 0x04, 0x68, 0xce,
|
||||||
|
0x3c, 0x80, 0x00, 0x07, 0x05, 0x88, 0x80, 0x03, 0x53, 0xff, 0xff};
|
||||||
|
// Example Empty padding packet next Idr.
|
||||||
|
std::vector<uint8_t> raw_rtp_empty_padding{
|
||||||
|
0x80, 0x62, 0x13, 0xbb, 0x87, 0xa0, 0x21, 0x0a, 0x00, 0x00, 0x6f, 0x00};
|
||||||
|
// Example Single NALU packet with slice.
|
||||||
|
std::vector<uint8_t> raw_rtp_slice(
|
||||||
|
{0x80, 0xE2, 0x13, 0xbc, 0x87, 0xa0, 0x21, 0x0a, 0x00, 0x00, 0x6f,
|
||||||
|
0x00, 0x01, 0x9a, 0x02, 0x3f, 0xc1, 0x48, 0x9a, 0xeb, 0xea, 0xff});
|
||||||
|
|
||||||
|
// Example EncodedFrame with SPS, PPS, and IDR.
|
||||||
|
std::vector<uint8_t> expect_frame_with_sps_pps_idr{
|
||||||
|
0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x40, 0x29, 0x95, 0xb8, 0x78, 0x2f,
|
||||||
|
0xf9, 0x70, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
|
||||||
|
0x78, 0x8d, 0xa1, 0xc3, 0x2e, 0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x3c,
|
||||||
|
0x80, 0x00, 0x00, 0x00, 0x01, 0x05, 0x88, 0x80, 0x03, 0x53, 0xff, 0xff};
|
||||||
|
// Example EncodedFrame with slice.
|
||||||
|
std::vector<uint8_t> expect_frame_with_slice{0x00, 0x00, 0x00, 0x01, 0x01,
|
||||||
|
0x9a, 0x02, 0x3f, 0xc1, 0x48,
|
||||||
|
0x9a, 0xeb, 0xea, 0xff};
|
||||||
|
rtp_packet_idr.Parse(raw_rtp_with_sps_pps_idr.data(),
|
||||||
|
raw_rtp_with_sps_pps_idr.size());
|
||||||
|
rtp_packet_padding.Parse(raw_rtp_empty_padding.data(),
|
||||||
|
raw_rtp_empty_padding.size());
|
||||||
|
rtp_packet_slice.Parse(raw_rtp_slice.data(), raw_rtp_slice.size());
|
||||||
|
|
||||||
|
// Prepare the receiver for H264.
|
||||||
|
webrtc::CodecParameterMap codec_params;
|
||||||
|
rtp_video_stream_receiver_->AddReceiveCodec(kH264PayloadType, kVideoCodecH264,
|
||||||
|
codec_params, false);
|
||||||
|
rtp_video_stream_receiver_->StartReceive();
|
||||||
|
|
||||||
|
// Expect IDR frame.
|
||||||
|
mock_on_complete_frame_callback_.AppendExpectedBitstream(
|
||||||
|
expect_frame_with_sps_pps_idr.data(),
|
||||||
|
expect_frame_with_sps_pps_idr.size());
|
||||||
|
EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame(_));
|
||||||
|
|
||||||
|
rtp_video_stream_receiver_->OnRtpPacket(rtp_packet_idr);
|
||||||
|
|
||||||
|
rtp_video_stream_receiver_->OnRtpPacket(rtp_packet_padding);
|
||||||
|
|
||||||
|
// Expect single NALU frame.
|
||||||
|
mock_on_complete_frame_callback_.ClearExpectedBitstream();
|
||||||
|
mock_on_complete_frame_callback_.AppendExpectedBitstream(
|
||||||
|
expect_frame_with_slice.data(), expect_frame_with_slice.size());
|
||||||
|
EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame(_));
|
||||||
|
rtp_video_stream_receiver_->OnRtpPacket(rtp_packet_slice);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(RtpVideoStreamReceiver2Test, RequestKeyframeIfFirstFrameIsDelta) {
|
TEST_F(RtpVideoStreamReceiver2Test, RequestKeyframeIfFirstFrameIsDelta) {
|
||||||
RtpPacketReceived rtp_packet;
|
RtpPacketReceived rtp_packet;
|
||||||
rtp_packet.SetPayloadType(kPayloadType);
|
rtp_packet.SetPayloadType(kPayloadType);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user