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}
This commit is contained in:
philipel
2017-03-15 02:51:11 -07:00
committed by Commit bot
parent 9f8a566316
commit 620d75f5be
3 changed files with 43 additions and 1 deletions

View File

@ -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<uint8_t>& 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);

View File

@ -42,6 +42,8 @@ class H264SpsPpsTracker {
struct SpsInfo {
size_t size = 0;
int width = -1;
int height = -1;
std::unique_ptr<uint8_t[]> data;
};

View File

@ -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<uint8_t> 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<uint8_t> 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