From 620d75f5befe1387bc457bc3ec5ad0158c4e6697 Mon Sep 17 00:00:00 2001 From: philipel Date: Wed, 15 Mar 2017 02:51:11 -0700 Subject: [PATCH] Save width/height of SPS nalus and restore them on the first packet of an IDR. It appears that for some H264 streams that the width/height is not set for the first packet of the IDR but in the packet containing the SPS/PPS. BUG=chromium:698088, webrtc:7139 Review-Url: https://codereview.webrtc.org/2750633003 Cr-Commit-Position: refs/heads/master@{#17239} --- .../video_coding/h264_sps_pps_tracker.cc | 10 +++++- .../video_coding/h264_sps_pps_tracker.h | 2 ++ .../h264_sps_pps_tracker_unittest.cc | 32 +++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/webrtc/modules/video_coding/h264_sps_pps_tracker.cc b/webrtc/modules/video_coding/h264_sps_pps_tracker.cc index 5dfdb49146..e4450a351f 100644 --- a/webrtc/modules/video_coding/h264_sps_pps_tracker.cc +++ b/webrtc/modules/video_coding/h264_sps_pps_tracker.cc @@ -45,6 +45,7 @@ H264SpsPpsTracker::PacketAction H264SpsPpsTracker::CopyAndFixBitstream( bool insert_packet = codec_header.nalus_length == 0 ? true : false; int pps_id = -1; + int sps_id = -1; size_t required_size = 0; for (size_t i = 0; i < codec_header.nalus_length; ++i) { const NaluInfo& nalu = codec_header.nalus[i]; @@ -55,6 +56,8 @@ H264SpsPpsTracker::PacketAction H264SpsPpsTracker::CopyAndFixBitstream( sps_data_[nalu.sps_id].data.reset(new uint8_t[nalu.size]); memcpy(sps_data_[nalu.sps_id].data.get(), data + nalu.offset, nalu.size); + sps_data_[nalu.sps_id].width = packet->width; + sps_data_[nalu.sps_id].height = packet->height; break; } case H264::NaluType::kPps: { @@ -83,7 +86,8 @@ H264SpsPpsTracker::PacketAction H264SpsPpsTracker::CopyAndFixBitstream( return kRequestKeyframe; } - auto sps = sps_data_.find(pps->second.sps_id); + sps_id = pps->second.sps_id; + auto sps = sps_data_.find(sps_id); if (sps == sps_data_.end()) { LOG(LS_WARNING) << "No SPS with id << " << pps_data_[nalu.pps_id].sps_id << " received"; @@ -177,6 +181,8 @@ H264SpsPpsTracker::PacketAction H264SpsPpsTracker::CopyAndFixBitstream( memcpy(insert_at, data, data_size); } + packet->width = sps_data_[sps_id].width; + packet->height = sps_data_[sps_id].height; packet->dataPtr = buffer; packet->sizeBytes = required_size; return kInsert; @@ -222,6 +228,8 @@ void H264SpsPpsTracker::InsertSpsPpsNalus(const std::vector& sps, SpsInfo sps_info; sps_info.size = sps.size(); + sps_info.width = parsed_sps->width; + sps_info.height = parsed_sps->height; uint8_t* sps_data = new uint8_t[sps_info.size]; memcpy(sps_data, sps.data(), sps_info.size); sps_info.data.reset(sps_data); diff --git a/webrtc/modules/video_coding/h264_sps_pps_tracker.h b/webrtc/modules/video_coding/h264_sps_pps_tracker.h index e769268779..7f8bc04416 100644 --- a/webrtc/modules/video_coding/h264_sps_pps_tracker.h +++ b/webrtc/modules/video_coding/h264_sps_pps_tracker.h @@ -42,6 +42,8 @@ class H264SpsPpsTracker { struct SpsInfo { size_t size = 0; + int width = -1; + int height = -1; std::unique_ptr data; }; diff --git a/webrtc/modules/video_coding/h264_sps_pps_tracker_unittest.cc b/webrtc/modules/video_coding/h264_sps_pps_tracker_unittest.cc index 9d4d64f97e..a7cec21e61 100644 --- a/webrtc/modules/video_coding/h264_sps_pps_tracker_unittest.cc +++ b/webrtc/modules/video_coding/h264_sps_pps_tracker_unittest.cc @@ -265,6 +265,7 @@ TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBand) { constexpr uint8_t kData[] = {1, 2, 3}; // Generated by "ffmpeg -r 30 -f avfoundation -i "default" out.h264" on macos. + // width: 320, height: 240 const std::vector sps( {0x67, 0x7a, 0x00, 0x0d, 0xbc, 0xd9, 0x41, 0x41, 0xfa, 0x10, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x03, 0x03, 0xc0, 0xf1, 0x42, 0x99, 0x60}); @@ -279,6 +280,8 @@ TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBand) { idr_packet.sizeBytes = sizeof(kData); EXPECT_EQ(H264SpsPpsTracker::kInsert, tracker_.CopyAndFixBitstream(&idr_packet)); + EXPECT_EQ(320, idr_packet.width); + EXPECT_EQ(240, idr_packet.height); if (idr_packet.dataPtr != kData) { // In case CopyAndFixBitStream() prepends SPS/PPS nalus to the packet, it // uses new uint8_t[] to allocate memory. Caller of CopyAndFixBitStream() @@ -327,5 +330,34 @@ TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBandIncompleteNalu) { tracker_.CopyAndFixBitstream(&idr_packet)); } +TEST_F(TestH264SpsPpsTracker, SaveRestoreWidthHeight) { + std::vector data; + + // Insert an SPS/PPS packet with width/height and make sure + // that information is set on the first IDR packet. + VCMPacket sps_pps_packet1 = GetDefaultPacket(); + AddSps(&sps_pps_packet1, 0, &data); + AddPps(&sps_pps_packet1, 0, 1, &data); + sps_pps_packet1.dataPtr = data.data(); + sps_pps_packet1.sizeBytes = data.size(); + sps_pps_packet1.width = 320; + sps_pps_packet1.height = 240; + EXPECT_EQ(H264SpsPpsTracker::kDrop, + tracker_.CopyAndFixBitstream(&sps_pps_packet1)); + + VCMPacket idr_packet1 = GetDefaultPacket(); + idr_packet1.video_header.is_first_packet_in_frame = true; + AddIdr(&idr_packet1, 1); + data.insert(data.end(), {1, 2, 3}); + idr_packet1.dataPtr = data.data(); + idr_packet1.sizeBytes = data.size(); + EXPECT_EQ(H264SpsPpsTracker::kInsert, + tracker_.CopyAndFixBitstream(&idr_packet1)); + + EXPECT_EQ(320, idr_packet1.width); + EXPECT_EQ(240, idr_packet1.height); + delete[] idr_packet1.dataPtr; +} + } // namespace video_coding } // namespace webrtc