diff --git a/modules/video_coding/h264_sps_pps_tracker.cc b/modules/video_coding/h264_sps_pps_tracker.cc index 9c0e52178e..aa2361793d 100644 --- a/modules/video_coding/h264_sps_pps_tracker.cc +++ b/modules/video_coding/h264_sps_pps_tracker.cc @@ -27,6 +27,22 @@ namespace video_coding { namespace { const uint8_t start_code_h264[] = {0, 0, 0, 1}; + +bool HasVclData(const VCMPacket& packet) { + const auto* h264_header = + absl::get_if(&packet.video_header.video_type_header); + if (h264_header->nalus_length == 0) { + return h264_header->nalu_type == H264::NaluType::kIdr || + h264_header->nalu_type == H264::NaluType::kSlice; + } + for (size_t i = 0; i < h264_header->nalus_length; ++i) { + if (h264_header->nalus[i].type == H264::NaluType::kIdr || + h264_header->nalus[i].type == H264::NaluType::kSlice) { + return true; + } + } + return false; +} } // namespace H264SpsPpsTracker::H264SpsPpsTracker() = default; @@ -212,6 +228,13 @@ H264SpsPpsTracker::PacketAction H264SpsPpsTracker::CopyAndFixBitstream( packet->dataPtr = buffer; packet->sizeBytes = required_size; + + // If this packet does not contain any VCL NAL units then reset end-of-frame + // flag to prevent it from being interpreted as a frame by the packet buffer. + if (packet->is_last_packet_in_frame() && !HasVclData(*packet)) { + packet->video_header.is_last_packet_in_frame = false; + } + return kInsert; } diff --git a/modules/video_coding/h264_sps_pps_tracker_unittest.cc b/modules/video_coding/h264_sps_pps_tracker_unittest.cc index 7857aa7efc..305b94b8ca 100644 --- a/modules/video_coding/h264_sps_pps_tracker_unittest.cc +++ b/modules/video_coding/h264_sps_pps_tracker_unittest.cc @@ -388,5 +388,49 @@ TEST_F(TestH264SpsPpsTracker, SaveRestoreWidthHeight) { delete[] idr_packet.dataPtr; } +TEST_F(TestH264SpsPpsTracker, ResetEndOfFrameFlagInNonVclPacket) { + // Insert SPS/PPS packet with end-of-frame flag set to true. The tracker + // should reset the flag since this packet doesn't contain VCL NALUs. + std::vector data; + H264VcmPacket packet; + packet.video_header.is_last_packet_in_frame = true; + + AddSps(&packet, 0, &data); + AddPps(&packet, 0, 1, &data); + packet.dataPtr = data.data(); + packet.sizeBytes = data.size(); + + EXPECT_EQ(H264SpsPpsTracker::kInsert, tracker_.CopyAndFixBitstream(&packet)); + EXPECT_FALSE(packet.is_last_packet_in_frame()); + delete[] packet.dataPtr; + data.clear(); +} + +TEST_F(TestH264SpsPpsTracker, KeepEndOfFrameFlagInVclPacket) { + // Insert SPS/PPS/IDR packet with end-of-frame flag set to true. The tracker + // should keep the flag since this packet contains VCL NALUs. + std::vector data; + H264VcmPacket packet; + packet.h264().packetization_type = kH264StapA; + packet.video_header.is_first_packet_in_frame = + true; // Always true for STAP-A. + packet.video_header.is_last_packet_in_frame = true; + + data.insert(data.end(), {0}); // First byte is ignored + data.insert(data.end(), {0, 2}); // Length of segment + AddSps(&packet, 13, &data); + data.insert(data.end(), {0, 2}); // Length of segment + AddPps(&packet, 13, 27, &data); + data.insert(data.end(), {0, 5}); // Length of segment + AddIdr(&packet, 27); + data.insert(data.end(), {1, 2, 3, 2, 1}); + packet.dataPtr = data.data(); + packet.sizeBytes = data.size(); + + EXPECT_EQ(H264SpsPpsTracker::kInsert, tracker_.CopyAndFixBitstream(&packet)); + EXPECT_TRUE(packet.is_last_packet_in_frame()); + delete[] packet.dataPtr; +} + } // namespace video_coding } // namespace webrtc