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:
committed by
Commit Bot
parent
05c47926ff
commit
fbec2ec292
@ -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",
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user