Detach H264 sps pps tracker from VCMPacket

Bug: webrtc:10979
Change-Id: I6ec5db570c3957dd068109accad88d2f62304163
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158523
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29639}
This commit is contained in:
Danil Chapovalov
2019-10-28 13:27:05 +01:00
committed by Commit Bot
parent 05c47926ff
commit fbec2ec292
5 changed files with 192 additions and 202 deletions

View File

@ -80,6 +80,7 @@ rtc_library("video_coding") {
visibility = [ "*" ]
deps = [
"..:module_fec_api",
"../../api:array_view",
"../../api:scoped_refptr",
"../../api/video:encoded_image",
"../../api/video:video_bitrate_allocation",

View File

@ -10,15 +10,15 @@
#include "modules/video_coding/h264_sps_pps_tracker.h"
#include <memory>
#include <string>
#include <utility>
#include "absl/types/variant.h"
#include "common_video/h264/h264_common.h"
#include "common_video/h264/pps_parser.h"
#include "common_video/h264/sps_parser.h"
#include "modules/video_coding/codecs/h264/include/h264_globals.h"
#include "modules/video_coding/frame_object.h"
#include "modules/video_coding/packet_buffer.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
@ -44,15 +44,14 @@ H264SpsPpsTracker::SpsInfo& H264SpsPpsTracker::SpsInfo::operator=(
SpsInfo&& rhs) = default;
H264SpsPpsTracker::SpsInfo::~SpsInfo() = default;
H264SpsPpsTracker::PacketAction H264SpsPpsTracker::CopyAndFixBitstream(
VCMPacket* packet) {
RTC_DCHECK(packet->codec() == kVideoCodecH264);
H264SpsPpsTracker::FixedBitstream H264SpsPpsTracker::CopyAndFixBitstream(
rtc::ArrayView<const uint8_t> bitstream,
RTPVideoHeader* video_header) {
RTC_DCHECK(video_header);
RTC_DCHECK(video_header->codec == kVideoCodecH264);
const uint8_t* data = packet->dataPtr;
const size_t data_size = packet->sizeBytes;
const RTPVideoHeader& video_header = packet->video_header;
auto& h264_header =
absl::get<RTPVideoHeaderH264>(packet->video_header.video_type_header);
absl::get<RTPVideoHeaderH264>(video_header->video_type_header);
bool append_sps_pps = false;
auto sps = sps_data_.end();
@ -62,8 +61,9 @@ H264SpsPpsTracker::PacketAction H264SpsPpsTracker::CopyAndFixBitstream(
const NaluInfo& nalu = h264_header.nalus[i];
switch (nalu.type) {
case H264::NaluType::kSps: {
sps_data_[nalu.sps_id].width = packet->width();
sps_data_[nalu.sps_id].height = packet->height();
SpsInfo& sps_info = sps_data_[nalu.sps_id];
sps_info.width = video_header->width;
sps_info.height = video_header->height;
break;
}
case H264::NaluType::kPps: {
@ -74,31 +74,31 @@ H264SpsPpsTracker::PacketAction H264SpsPpsTracker::CopyAndFixBitstream(
// If this is the first packet of an IDR, make sure we have the required
// SPS/PPS and also calculate how much extra space we need in the buffer
// to prepend the SPS/PPS to the bitstream with start codes.
if (video_header.is_first_packet_in_frame) {
if (video_header->is_first_packet_in_frame) {
if (nalu.pps_id == -1) {
RTC_LOG(LS_WARNING) << "No PPS id in IDR nalu.";
return kRequestKeyframe;
return {kRequestKeyframe};
}
pps = pps_data_.find(nalu.pps_id);
if (pps == pps_data_.end()) {
RTC_LOG(LS_WARNING)
<< "No PPS with id << " << nalu.pps_id << " received";
return kRequestKeyframe;
return {kRequestKeyframe};
}
sps = sps_data_.find(pps->second.sps_id);
if (sps == sps_data_.end()) {
RTC_LOG(LS_WARNING)
<< "No SPS with id << " << pps->second.sps_id << " received";
return kRequestKeyframe;
return {kRequestKeyframe};
}
// Since the first packet of every keyframe should have its width and
// height set we set it here in the case of it being supplied out of
// band.
packet->video_header.width = sps->second.width;
packet->video_header.height = sps->second.height;
video_header->width = sps->second.width;
video_header->height = sps->second.height;
// If the SPS/PPS was supplied out of band then we will have saved
// the actual bitstream in |data|.
@ -127,9 +127,9 @@ H264SpsPpsTracker::PacketAction H264SpsPpsTracker::CopyAndFixBitstream(
}
if (h264_header.packetization_type == kH264StapA) {
const uint8_t* nalu_ptr = data + 1;
while (nalu_ptr < data + data_size) {
RTC_DCHECK(video_header.is_first_packet_in_frame);
const uint8_t* nalu_ptr = bitstream.data() + 1;
while (nalu_ptr < bitstream.data() + bitstream.size()) {
RTC_DCHECK(video_header->is_first_packet_in_frame);
required_size += sizeof(start_code_h264);
// The first two bytes describe the length of a segment.
@ -143,12 +143,14 @@ H264SpsPpsTracker::PacketAction H264SpsPpsTracker::CopyAndFixBitstream(
if (h264_header.nalus_length > 0) {
required_size += sizeof(start_code_h264);
}
required_size += data_size;
required_size += bitstream.size();
}
// Then we copy to the new buffer.
uint8_t* buffer = new uint8_t[required_size];
uint8_t* insert_at = buffer;
H264SpsPpsTracker::FixedBitstream fixed;
fixed.data = std::make_unique<uint8_t[]>(required_size);
fixed.size = required_size;
uint8_t* insert_at = fixed.data.get();
if (append_sps_pps) {
// Insert SPS.
@ -183,8 +185,8 @@ H264SpsPpsTracker::PacketAction H264SpsPpsTracker::CopyAndFixBitstream(
// Copy the rest of the bitstream and insert start codes.
if (h264_header.packetization_type == kH264StapA) {
const uint8_t* nalu_ptr = data + 1;
while (nalu_ptr < data + data_size) {
const uint8_t* nalu_ptr = bitstream.data() + 1;
while (nalu_ptr < bitstream.data() + bitstream.size()) {
memcpy(insert_at, start_code_h264, sizeof(start_code_h264));
insert_at += sizeof(start_code_h264);
@ -192,10 +194,9 @@ H264SpsPpsTracker::PacketAction H264SpsPpsTracker::CopyAndFixBitstream(
uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1];
nalu_ptr += 2;
size_t copy_end = nalu_ptr - data + segment_length;
if (copy_end > data_size) {
delete[] buffer;
return kDrop;
size_t copy_end = nalu_ptr - bitstream.data() + segment_length;
if (copy_end > bitstream.size()) {
return {kDrop};
}
memcpy(insert_at, nalu_ptr, segment_length);
@ -207,12 +208,11 @@ H264SpsPpsTracker::PacketAction H264SpsPpsTracker::CopyAndFixBitstream(
memcpy(insert_at, start_code_h264, sizeof(start_code_h264));
insert_at += sizeof(start_code_h264);
}
memcpy(insert_at, data, data_size);
memcpy(insert_at, bitstream.data(), bitstream.size());
}
packet->dataPtr = buffer;
packet->sizeBytes = required_size;
return kInsert;
fixed.action = kInsert;
return fixed;
}
void H264SpsPpsTracker::InsertSpsPpsNalus(const std::vector<uint8_t>& sps,

View File

@ -11,25 +11,33 @@
#ifndef MODULES_VIDEO_CODING_H264_SPS_PPS_TRACKER_H_
#define MODULES_VIDEO_CODING_H264_SPS_PPS_TRACKER_H_
#include <cstddef>
#include <cstdint>
#include <map>
#include <memory>
#include <vector>
#include "api/array_view.h"
#include "modules/rtp_rtcp/source/rtp_video_header.h"
namespace webrtc {
class VCMPacket;
namespace video_coding {
class H264SpsPpsTracker {
public:
enum PacketAction { kInsert, kDrop, kRequestKeyframe };
struct FixedBitstream {
PacketAction action;
std::unique_ptr<uint8_t[]> data;
size_t size;
};
H264SpsPpsTracker();
~H264SpsPpsTracker();
PacketAction CopyAndFixBitstream(VCMPacket* packet);
// Returns fixed bitstream and modifies |video_header|.
FixedBitstream CopyAndFixBitstream(rtc::ArrayView<const uint8_t> bitstream,
RTPVideoHeader* video_header);
void InsertSpsPpsNalus(const std::vector<uint8_t>& sps,
const std::vector<uint8_t>& pps);

View File

@ -19,14 +19,22 @@
#include "modules/rtp_rtcp/source/rtp_video_header.h"
#include "modules/video_coding/codecs/h264/include/h264_globals.h"
#include "modules/video_coding/packet.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace video_coding {
namespace {
using ::testing::ElementsAreArray;
const uint8_t start_code[] = {0, 0, 0, 1};
rtc::ArrayView<const uint8_t> Bitstream(
const H264SpsPpsTracker::FixedBitstream& fixed) {
return rtc::MakeArrayView(fixed.data.get(), fixed.size);
}
void ExpectSpsPpsIdr(const RTPVideoHeaderH264& codec_header,
uint8_t sps_id,
uint8_t pps_id) {
@ -51,19 +59,18 @@ void ExpectSpsPpsIdr(const RTPVideoHeaderH264& codec_header,
EXPECT_TRUE(contains_idr);
}
class H264VcmPacket : public VCMPacket {
class H264VideoHeader : public RTPVideoHeader {
public:
H264VcmPacket() {
video_header.codec = kVideoCodecH264;
video_header.is_first_packet_in_frame = false;
auto& type_header =
video_header.video_type_header.emplace<RTPVideoHeaderH264>();
type_header.nalus_length = 0;
type_header.packetization_type = kH264SingleNalu;
H264VideoHeader() {
codec = kVideoCodecH264;
is_first_packet_in_frame = false;
auto& h264_header = video_type_header.emplace<RTPVideoHeaderH264>();
h264_header.nalus_length = 0;
h264_header.packetization_type = kH264SingleNalu;
}
RTPVideoHeaderH264& h264() {
return absl::get<RTPVideoHeaderH264>(video_header.video_type_header);
return absl::get<RTPVideoHeaderH264>(video_type_header);
}
};
@ -71,7 +78,7 @@ class H264VcmPacket : public VCMPacket {
class TestH264SpsPpsTracker : public ::testing::Test {
public:
void AddSps(H264VcmPacket* packet,
void AddSps(H264VideoHeader* header,
uint8_t sps_id,
std::vector<uint8_t>* data) {
NaluInfo info;
@ -81,10 +88,10 @@ class TestH264SpsPpsTracker : public ::testing::Test {
data->push_back(H264::NaluType::kSps);
data->push_back(sps_id); // The sps data, just a single byte.
packet->h264().nalus[packet->h264().nalus_length++] = info;
header->h264().nalus[header->h264().nalus_length++] = info;
}
void AddPps(H264VcmPacket* packet,
void AddPps(H264VideoHeader* header,
uint8_t sps_id,
uint8_t pps_id,
std::vector<uint8_t>* data) {
@ -95,16 +102,16 @@ class TestH264SpsPpsTracker : public ::testing::Test {
data->push_back(H264::NaluType::kPps);
data->push_back(pps_id); // The pps data, just a single byte.
packet->h264().nalus[packet->h264().nalus_length++] = info;
header->h264().nalus[header->h264().nalus_length++] = info;
}
void AddIdr(H264VcmPacket* packet, int pps_id) {
void AddIdr(H264VideoHeader* header, int pps_id) {
NaluInfo info;
info.type = H264::NaluType::kIdr;
info.sps_id = -1;
info.pps_id = pps_id;
packet->h264().nalus[packet->h264().nalus_length++] = info;
header->h264().nalus[header->h264().nalus_length++] = info;
}
protected:
@ -113,165 +120,149 @@ class TestH264SpsPpsTracker : public ::testing::Test {
TEST_F(TestH264SpsPpsTracker, NoNalus) {
uint8_t data[] = {1, 2, 3};
H264VcmPacket packet;
packet.h264().packetization_type = kH264FuA;
packet.dataPtr = data;
packet.sizeBytes = sizeof(data);
H264VideoHeader header;
header.h264().packetization_type = kH264FuA;
EXPECT_EQ(H264SpsPpsTracker::kInsert, tracker_.CopyAndFixBitstream(&packet));
EXPECT_EQ(memcmp(packet.dataPtr, data, sizeof(data)), 0);
delete[] packet.dataPtr;
H264SpsPpsTracker::FixedBitstream fixed =
tracker_.CopyAndFixBitstream(data, &header);
EXPECT_EQ(fixed.action, H264SpsPpsTracker::kInsert);
EXPECT_THAT(Bitstream(fixed), ElementsAreArray(data));
}
TEST_F(TestH264SpsPpsTracker, FuAFirstPacket) {
uint8_t data[] = {1, 2, 3};
H264VcmPacket packet;
packet.h264().packetization_type = kH264FuA;
packet.h264().nalus_length = 1;
packet.video_header.is_first_packet_in_frame = true;
packet.dataPtr = data;
packet.sizeBytes = sizeof(data);
H264VideoHeader header;
header.h264().packetization_type = kH264FuA;
header.h264().nalus_length = 1;
header.is_first_packet_in_frame = true;
EXPECT_EQ(H264SpsPpsTracker::kInsert, tracker_.CopyAndFixBitstream(&packet));
H264SpsPpsTracker::FixedBitstream fixed =
tracker_.CopyAndFixBitstream(data, &header);
EXPECT_EQ(fixed.action, H264SpsPpsTracker::kInsert);
std::vector<uint8_t> expected;
expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
expected.insert(expected.end(), {1, 2, 3});
EXPECT_EQ(memcmp(packet.dataPtr, expected.data(), expected.size()), 0);
delete[] packet.dataPtr;
EXPECT_THAT(Bitstream(fixed), ElementsAreArray(expected));
}
TEST_F(TestH264SpsPpsTracker, StapAIncorrectSegmentLength) {
uint8_t data[] = {0, 0, 2, 0};
H264VcmPacket packet;
packet.h264().packetization_type = kH264StapA;
packet.video_header.is_first_packet_in_frame = true;
packet.dataPtr = data;
packet.sizeBytes = sizeof(data);
H264VideoHeader header;
header.h264().packetization_type = kH264StapA;
header.is_first_packet_in_frame = true;
EXPECT_EQ(H264SpsPpsTracker::kDrop, tracker_.CopyAndFixBitstream(&packet));
EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &header).action,
H264SpsPpsTracker::kDrop);
}
TEST_F(TestH264SpsPpsTracker, SingleNaluInsertStartCode) {
uint8_t data[] = {1, 2, 3};
H264VcmPacket packet;
packet.h264().nalus_length = 1;
packet.dataPtr = data;
packet.sizeBytes = sizeof(data);
H264VideoHeader header;
header.h264().nalus_length = 1;
EXPECT_EQ(H264SpsPpsTracker::kInsert, tracker_.CopyAndFixBitstream(&packet));
H264SpsPpsTracker::FixedBitstream fixed =
tracker_.CopyAndFixBitstream(data, &header);
EXPECT_EQ(fixed.action, H264SpsPpsTracker::kInsert);
std::vector<uint8_t> expected;
expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
expected.insert(expected.end(), {1, 2, 3});
EXPECT_EQ(memcmp(packet.dataPtr, expected.data(), expected.size()), 0);
delete[] packet.dataPtr;
EXPECT_THAT(Bitstream(fixed), ElementsAreArray(expected));
}
TEST_F(TestH264SpsPpsTracker, NoStartCodeInsertedForSubsequentFuAPacket) {
std::vector<uint8_t> data = {1, 2, 3};
H264VcmPacket packet;
packet.h264().packetization_type = kH264FuA;
H264VideoHeader header;
header.h264().packetization_type = kH264FuA;
// Since no NALU begin in this packet the nalus_length is zero.
packet.h264().nalus_length = 0;
header.h264().nalus_length = 0;
packet.dataPtr = data.data();
packet.sizeBytes = data.size();
H264SpsPpsTracker::FixedBitstream fixed =
tracker_.CopyAndFixBitstream(data, &header);
EXPECT_EQ(H264SpsPpsTracker::kInsert, tracker_.CopyAndFixBitstream(&packet));
EXPECT_EQ(memcmp(packet.dataPtr, data.data(), data.size()), 0);
delete[] packet.dataPtr;
EXPECT_EQ(fixed.action, H264SpsPpsTracker::kInsert);
EXPECT_THAT(Bitstream(fixed), ElementsAreArray(data));
}
TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoSpsPpsInserted) {
std::vector<uint8_t> data = {1, 2, 3};
H264VcmPacket packet;
packet.video_header.is_first_packet_in_frame = true;
H264VideoHeader header;
header.is_first_packet_in_frame = true;
AddIdr(&header, 0);
AddIdr(&packet, 0);
packet.dataPtr = data.data();
packet.sizeBytes = data.size();
EXPECT_EQ(H264SpsPpsTracker::kRequestKeyframe,
tracker_.CopyAndFixBitstream(&packet));
EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &header).action,
H264SpsPpsTracker::kRequestKeyframe);
}
TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoPpsInserted) {
std::vector<uint8_t> data = {1, 2, 3};
H264VcmPacket packet;
packet.video_header.is_first_packet_in_frame = true;
H264VideoHeader header;
header.is_first_packet_in_frame = true;
AddSps(&header, 0, &data);
AddIdr(&header, 0);
AddSps(&packet, 0, &data);
AddIdr(&packet, 0);
packet.dataPtr = data.data();
packet.sizeBytes = data.size();
EXPECT_EQ(H264SpsPpsTracker::kRequestKeyframe,
tracker_.CopyAndFixBitstream(&packet));
EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &header).action,
H264SpsPpsTracker::kRequestKeyframe);
}
TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoSpsInserted) {
std::vector<uint8_t> data = {1, 2, 3};
H264VcmPacket packet;
packet.video_header.is_first_packet_in_frame = true;
H264VideoHeader header;
header.is_first_packet_in_frame = true;
AddPps(&header, 0, 0, &data);
AddIdr(&header, 0);
AddPps(&packet, 0, 0, &data);
AddIdr(&packet, 0);
packet.dataPtr = data.data();
packet.sizeBytes = data.size();
EXPECT_EQ(H264SpsPpsTracker::kRequestKeyframe,
tracker_.CopyAndFixBitstream(&packet));
EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &header).action,
H264SpsPpsTracker::kRequestKeyframe);
}
TEST_F(TestH264SpsPpsTracker, SpsPpsPacketThenIdrFirstPacket) {
std::vector<uint8_t> data;
H264VcmPacket sps_pps_packet;
H264VideoHeader sps_pps_header;
// Insert SPS/PPS
AddSps(&sps_pps_packet, 0, &data);
AddPps(&sps_pps_packet, 0, 1, &data);
sps_pps_packet.dataPtr = data.data();
sps_pps_packet.sizeBytes = data.size();
EXPECT_EQ(H264SpsPpsTracker::kInsert,
tracker_.CopyAndFixBitstream(&sps_pps_packet));
delete[] sps_pps_packet.dataPtr;
data.clear();
AddSps(&sps_pps_header, 0, &data);
AddPps(&sps_pps_header, 0, 1, &data);
EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &sps_pps_header).action,
H264SpsPpsTracker::kInsert);
// Insert first packet of the IDR
H264VcmPacket idr_packet;
idr_packet.video_header.is_first_packet_in_frame = true;
AddIdr(&idr_packet, 1);
data.insert(data.end(), {1, 2, 3});
idr_packet.dataPtr = data.data();
idr_packet.sizeBytes = data.size();
EXPECT_EQ(H264SpsPpsTracker::kInsert,
tracker_.CopyAndFixBitstream(&idr_packet));
H264VideoHeader idr_header;
idr_header.is_first_packet_in_frame = true;
AddIdr(&idr_header, 1);
data = {1, 2, 3};
H264SpsPpsTracker::FixedBitstream fixed =
tracker_.CopyAndFixBitstream(data, &idr_header);
EXPECT_EQ(fixed.action, H264SpsPpsTracker::kInsert);
std::vector<uint8_t> expected;
expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
expected.insert(expected.end(), {1, 2, 3});
EXPECT_EQ(memcmp(idr_packet.dataPtr, expected.data(), expected.size()), 0);
delete[] idr_packet.dataPtr;
EXPECT_THAT(Bitstream(fixed), ElementsAreArray(expected));
}
TEST_F(TestH264SpsPpsTracker, SpsPpsIdrInStapA) {
std::vector<uint8_t> data;
H264VcmPacket packet;
packet.h264().packetization_type = kH264StapA;
packet.video_header.is_first_packet_in_frame = true; // Always true for StapA
H264VideoHeader header;
header.h264().packetization_type = kH264StapA;
header.is_first_packet_in_frame = true; // Always true for StapA
data.insert(data.end(), {0}); // First byte is ignored
data.insert(data.end(), {0, 2}); // Length of segment
AddSps(&packet, 13, &data);
AddSps(&header, 13, &data);
data.insert(data.end(), {0, 2}); // Length of segment
AddPps(&packet, 13, 27, &data);
AddPps(&header, 13, 27, &data);
data.insert(data.end(), {0, 5}); // Length of segment
AddIdr(&packet, 27);
AddIdr(&header, 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));
H264SpsPpsTracker::FixedBitstream fixed =
tracker_.CopyAndFixBitstream(data, &header);
EXPECT_THAT(fixed.action, H264SpsPpsTracker::kInsert);
std::vector<uint8_t> expected;
expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
@ -280,9 +271,7 @@ TEST_F(TestH264SpsPpsTracker, SpsPpsIdrInStapA) {
expected.insert(expected.end(), {H264::NaluType::kPps, 27});
expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
expected.insert(expected.end(), {1, 2, 3, 2, 1});
EXPECT_EQ(memcmp(packet.dataPtr, expected.data(), expected.size()), 0);
delete[] packet.dataPtr;
EXPECT_THAT(Bitstream(fixed), ElementsAreArray(expected));
}
TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBand) {
@ -297,25 +286,18 @@ TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBand) {
tracker_.InsertSpsPpsNalus(sps, pps);
// Insert first packet of the IDR.
H264VcmPacket idr_packet;
idr_packet.video_header.is_first_packet_in_frame = true;
AddIdr(&idr_packet, 0);
idr_packet.dataPtr = kData;
idr_packet.sizeBytes = sizeof(kData);
EXPECT_EQ(1u, idr_packet.h264().nalus_length);
EXPECT_EQ(H264SpsPpsTracker::kInsert,
tracker_.CopyAndFixBitstream(&idr_packet));
EXPECT_EQ(3u, idr_packet.h264().nalus_length);
EXPECT_EQ(320, idr_packet.width());
EXPECT_EQ(240, idr_packet.height());
ExpectSpsPpsIdr(idr_packet.h264(), 0, 0);
H264VideoHeader idr_header;
idr_header.is_first_packet_in_frame = true;
AddIdr(&idr_header, 0);
EXPECT_EQ(idr_header.h264().nalus_length, 1u);
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()
// needs to take care of freeing the memory.
delete[] idr_packet.dataPtr;
}
H264SpsPpsTracker::FixedBitstream fixed =
tracker_.CopyAndFixBitstream(kData, &idr_header);
EXPECT_EQ(idr_header.h264().nalus_length, 3u);
EXPECT_EQ(idr_header.width, 320u);
EXPECT_EQ(idr_header.height, 240u);
ExpectSpsPpsIdr(idr_header.h264(), 0, 0);
}
TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBandWrongNaluHeader) {
@ -330,13 +312,12 @@ TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBandWrongNaluHeader) {
tracker_.InsertSpsPpsNalus(sps, pps);
// Insert first packet of the IDR.
H264VcmPacket idr_packet;
idr_packet.video_header.is_first_packet_in_frame = true;
AddIdr(&idr_packet, 0);
idr_packet.dataPtr = kData;
idr_packet.sizeBytes = sizeof(kData);
EXPECT_EQ(H264SpsPpsTracker::kRequestKeyframe,
tracker_.CopyAndFixBitstream(&idr_packet));
H264VideoHeader idr_header;
idr_header.is_first_packet_in_frame = true;
AddIdr(&idr_header, 0);
EXPECT_EQ(tracker_.CopyAndFixBitstream(kData, &idr_header).action,
H264SpsPpsTracker::kRequestKeyframe);
}
TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBandIncompleteNalu) {
@ -349,13 +330,12 @@ TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBandIncompleteNalu) {
tracker_.InsertSpsPpsNalus(sps, pps);
// Insert first packet of the IDR.
H264VcmPacket idr_packet;
idr_packet.video_header.is_first_packet_in_frame = true;
AddIdr(&idr_packet, 0);
idr_packet.dataPtr = kData;
idr_packet.sizeBytes = sizeof(kData);
EXPECT_EQ(H264SpsPpsTracker::kRequestKeyframe,
tracker_.CopyAndFixBitstream(&idr_packet));
H264VideoHeader idr_header;
idr_header.is_first_packet_in_frame = true;
AddIdr(&idr_header, 0);
EXPECT_EQ(tracker_.CopyAndFixBitstream(kData, &idr_header).action,
H264SpsPpsTracker::kRequestKeyframe);
}
TEST_F(TestH264SpsPpsTracker, SaveRestoreWidthHeight) {
@ -363,29 +343,25 @@ TEST_F(TestH264SpsPpsTracker, SaveRestoreWidthHeight) {
// Insert an SPS/PPS packet with width/height and make sure
// that information is set on the first IDR packet.
H264VcmPacket sps_pps_packet;
AddSps(&sps_pps_packet, 0, &data);
AddPps(&sps_pps_packet, 0, 1, &data);
sps_pps_packet.dataPtr = data.data();
sps_pps_packet.sizeBytes = data.size();
sps_pps_packet.video_header.width = 320;
sps_pps_packet.video_header.height = 240;
EXPECT_EQ(H264SpsPpsTracker::kInsert,
tracker_.CopyAndFixBitstream(&sps_pps_packet));
delete[] sps_pps_packet.dataPtr;
H264VideoHeader sps_pps_header;
AddSps(&sps_pps_header, 0, &data);
AddPps(&sps_pps_header, 0, 1, &data);
sps_pps_header.width = 320;
sps_pps_header.height = 240;
H264VcmPacket idr_packet;
idr_packet.video_header.is_first_packet_in_frame = true;
AddIdr(&idr_packet, 1);
EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &sps_pps_header).action,
H264SpsPpsTracker::kInsert);
H264VideoHeader idr_header;
idr_header.is_first_packet_in_frame = true;
AddIdr(&idr_header, 1);
data.insert(data.end(), {1, 2, 3});
idr_packet.dataPtr = data.data();
idr_packet.sizeBytes = data.size();
EXPECT_EQ(H264SpsPpsTracker::kInsert,
tracker_.CopyAndFixBitstream(&idr_packet));
EXPECT_EQ(320, idr_packet.width());
EXPECT_EQ(240, idr_packet.height());
delete[] idr_packet.dataPtr;
EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &idr_header).action,
H264SpsPpsTracker::kInsert);
EXPECT_EQ(idr_header.width, 320);
EXPECT_EQ(idr_header.height, 240);
}
} // namespace video_coding