Ignore fragmentation header when packetizing H264
instead reparse nalu boundaries from the bitstream. H264 is the last use of the RTPFragmentationHeader and this would allow to avoid passing and precalculating this legacy structure. Bug: webrtc:6471 Change-Id: Ia6e8bf0836fd5c022423d836894cde81f136d1f1 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/178911 Reviewed-by: Philip Eliasson <philipel@webrtc.org> Reviewed-by: Niels Moller <nisse@webrtc.org> Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/master@{#31746}
This commit is contained in:
committed by
Commit Bot
parent
3d2210876e
commit
820021d246
@ -31,7 +31,7 @@ std::unique_ptr<RtpPacketizer> RtpPacketizer::Create(
|
|||||||
PayloadSizeLimits limits,
|
PayloadSizeLimits limits,
|
||||||
// Codec-specific details.
|
// Codec-specific details.
|
||||||
const RTPVideoHeader& rtp_video_header,
|
const RTPVideoHeader& rtp_video_header,
|
||||||
const RTPFragmentationHeader* fragmentation) {
|
const RTPFragmentationHeader* /*fragmentation*/) {
|
||||||
if (!type) {
|
if (!type) {
|
||||||
// Use raw packetizer.
|
// Use raw packetizer.
|
||||||
return std::make_unique<RtpPacketizerGeneric>(payload, limits);
|
return std::make_unique<RtpPacketizerGeneric>(payload, limits);
|
||||||
@ -39,11 +39,10 @@ std::unique_ptr<RtpPacketizer> RtpPacketizer::Create(
|
|||||||
|
|
||||||
switch (*type) {
|
switch (*type) {
|
||||||
case kVideoCodecH264: {
|
case kVideoCodecH264: {
|
||||||
RTC_CHECK(fragmentation);
|
|
||||||
const auto& h264 =
|
const auto& h264 =
|
||||||
absl::get<RTPVideoHeaderH264>(rtp_video_header.video_type_header);
|
absl::get<RTPVideoHeaderH264>(rtp_video_header.video_type_header);
|
||||||
return std::make_unique<RtpPacketizerH264>(
|
return std::make_unique<RtpPacketizerH264>(payload, limits,
|
||||||
payload, limits, h264.packetization_mode, *fragmentation);
|
h264.packetization_mode);
|
||||||
}
|
}
|
||||||
case kVideoCodecVP8: {
|
case kVideoCodecVP8: {
|
||||||
const auto& vp8 =
|
const auto& vp8 =
|
||||||
|
|||||||
@ -25,7 +25,6 @@
|
|||||||
#include "common_video/h264/pps_parser.h"
|
#include "common_video/h264/pps_parser.h"
|
||||||
#include "common_video/h264/sps_parser.h"
|
#include "common_video/h264/sps_parser.h"
|
||||||
#include "common_video/h264/sps_vui_rewriter.h"
|
#include "common_video/h264/sps_vui_rewriter.h"
|
||||||
#include "modules/include/module_common_types.h"
|
|
||||||
#include "modules/rtp_rtcp/source/byte_io.h"
|
#include "modules/rtp_rtcp/source/byte_io.h"
|
||||||
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
|
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
@ -46,19 +45,18 @@ enum FuDefs : uint8_t { kSBit = 0x80, kEBit = 0x40, kRBit = 0x20 };
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
RtpPacketizerH264::RtpPacketizerH264(
|
RtpPacketizerH264::RtpPacketizerH264(rtc::ArrayView<const uint8_t> payload,
|
||||||
rtc::ArrayView<const uint8_t> payload,
|
PayloadSizeLimits limits,
|
||||||
PayloadSizeLimits limits,
|
H264PacketizationMode packetization_mode)
|
||||||
H264PacketizationMode packetization_mode,
|
|
||||||
const RTPFragmentationHeader& fragmentation)
|
|
||||||
: limits_(limits), num_packets_left_(0) {
|
: limits_(limits), num_packets_left_(0) {
|
||||||
// Guard against uninitialized memory in packetization_mode.
|
// Guard against uninitialized memory in packetization_mode.
|
||||||
RTC_CHECK(packetization_mode == H264PacketizationMode::NonInterleaved ||
|
RTC_CHECK(packetization_mode == H264PacketizationMode::NonInterleaved ||
|
||||||
packetization_mode == H264PacketizationMode::SingleNalUnit);
|
packetization_mode == H264PacketizationMode::SingleNalUnit);
|
||||||
|
|
||||||
for (size_t i = 0; i < fragmentation.fragmentationVectorSize; ++i) {
|
for (const auto& nalu :
|
||||||
|
H264::FindNaluIndices(payload.data(), payload.size())) {
|
||||||
input_fragments_.push_back(
|
input_fragments_.push_back(
|
||||||
payload.subview(fragmentation.Offset(i), fragmentation.Length(i)));
|
payload.subview(nalu.payload_start_offset, nalu.payload_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GeneratePackets(packetization_mode)) {
|
if (!GeneratePackets(packetization_mode)) {
|
||||||
|
|||||||
@ -19,7 +19,6 @@
|
|||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include "api/array_view.h"
|
#include "api/array_view.h"
|
||||||
#include "modules/include/module_common_types.h"
|
|
||||||
#include "modules/rtp_rtcp/source/rtp_format.h"
|
#include "modules/rtp_rtcp/source/rtp_format.h"
|
||||||
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
|
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
|
||||||
#include "modules/video_coding/codecs/h264/include/h264_globals.h"
|
#include "modules/video_coding/codecs/h264/include/h264_globals.h"
|
||||||
@ -34,8 +33,7 @@ class RtpPacketizerH264 : public RtpPacketizer {
|
|||||||
// The payload_data must be exactly one encoded H264 frame.
|
// The payload_data must be exactly one encoded H264 frame.
|
||||||
RtpPacketizerH264(rtc::ArrayView<const uint8_t> payload,
|
RtpPacketizerH264(rtc::ArrayView<const uint8_t> payload,
|
||||||
PayloadSizeLimits limits,
|
PayloadSizeLimits limits,
|
||||||
H264PacketizationMode packetization_mode,
|
H264PacketizationMode packetization_mode);
|
||||||
const RTPFragmentationHeader& fragmentation);
|
|
||||||
|
|
||||||
~RtpPacketizerH264() override;
|
~RtpPacketizerH264() override;
|
||||||
|
|
||||||
|
|||||||
@ -13,9 +13,9 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/algorithm/container.h"
|
||||||
#include "api/array_view.h"
|
#include "api/array_view.h"
|
||||||
#include "common_video/h264/h264_common.h"
|
#include "common_video/h264/h264_common.h"
|
||||||
#include "modules/include/module_common_types.h"
|
|
||||||
#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
|
#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
|
||||||
#include "modules/rtp_rtcp/source/byte_io.h"
|
#include "modules/rtp_rtcp/source/byte_io.h"
|
||||||
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
|
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
|
||||||
@ -56,45 +56,61 @@ enum NalDefs { kFBit = 0x80, kNriMask = 0x60, kTypeMask = 0x1F };
|
|||||||
// Bit masks for FU (A and B) headers.
|
// Bit masks for FU (A and B) headers.
|
||||||
enum FuDefs { kSBit = 0x80, kEBit = 0x40, kRBit = 0x20 };
|
enum FuDefs { kSBit = 0x80, kEBit = 0x40, kRBit = 0x20 };
|
||||||
|
|
||||||
RTPFragmentationHeader CreateFragmentation(rtc::ArrayView<const size_t> sizes) {
|
// Creates Buffer that looks like nal unit of given size.
|
||||||
RTPFragmentationHeader fragmentation;
|
rtc::Buffer GenerateNalUnit(size_t size) {
|
||||||
fragmentation.VerifyAndAllocateFragmentationHeader(sizes.size());
|
RTC_CHECK_GT(size, 0);
|
||||||
size_t offset = 0;
|
rtc::Buffer buffer(size);
|
||||||
for (size_t i = 0; i < sizes.size(); ++i) {
|
|
||||||
fragmentation.fragmentationOffset[i] = offset;
|
|
||||||
fragmentation.fragmentationLength[i] = sizes[i];
|
|
||||||
offset += sizes[i];
|
|
||||||
}
|
|
||||||
return fragmentation;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create fragmentation with single fragment of same size as |frame|
|
|
||||||
RTPFragmentationHeader NoFragmentation(rtc::ArrayView<const uint8_t> frame) {
|
|
||||||
size_t frame_size[] = {frame.size()};
|
|
||||||
return CreateFragmentation(frame_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create frame of given size.
|
|
||||||
rtc::Buffer CreateFrame(size_t frame_size) {
|
|
||||||
rtc::Buffer frame(frame_size);
|
|
||||||
// Set some valid header.
|
// Set some valid header.
|
||||||
frame[0] = 0x01;
|
buffer[0] = kSlice;
|
||||||
// Generate payload to detect when shifted payload was put into a packet.
|
for (size_t i = 1; i < size; ++i) {
|
||||||
for (size_t i = 1; i < frame_size; ++i)
|
buffer[i] = static_cast<uint8_t>(i);
|
||||||
frame[i] = static_cast<uint8_t>(i);
|
}
|
||||||
|
// Last byte shouldn't be 0, or it may be counted as part of next 4-byte start
|
||||||
|
// sequence.
|
||||||
|
buffer[size - 1] |= 0x10;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create frame consisting of nalus of given size.
|
||||||
|
rtc::Buffer CreateFrame(std::initializer_list<size_t> nalu_sizes) {
|
||||||
|
static constexpr int kStartCodeSize = 3;
|
||||||
|
rtc::Buffer frame(absl::c_accumulate(nalu_sizes, 0) +
|
||||||
|
kStartCodeSize * nalu_sizes.size());
|
||||||
|
size_t offset = 0;
|
||||||
|
for (size_t nalu_size : nalu_sizes) {
|
||||||
|
EXPECT_GE(nalu_size, 1u);
|
||||||
|
// Insert nalu start code
|
||||||
|
frame[offset] = 0;
|
||||||
|
frame[offset + 1] = 0;
|
||||||
|
frame[offset + 2] = 1;
|
||||||
|
// Set some valid header.
|
||||||
|
frame[offset + 3] = 1;
|
||||||
|
// Fill payload avoiding accidental start codes
|
||||||
|
if (nalu_size > 1) {
|
||||||
|
memset(frame.data() + offset + 4, 0x3f, nalu_size - 1);
|
||||||
|
}
|
||||||
|
offset += (kStartCodeSize + nalu_size);
|
||||||
|
}
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create frame with size deduced from fragmentation.
|
// Create frame consisting of given nalus.
|
||||||
rtc::Buffer CreateFrame(const RTPFragmentationHeader& fragmentation) {
|
rtc::Buffer CreateFrame(rtc::ArrayView<const rtc::Buffer> nalus) {
|
||||||
size_t last_frame_index = fragmentation.fragmentationVectorSize - 1;
|
static constexpr int kStartCodeSize = 3;
|
||||||
size_t frame_size = fragmentation.fragmentationOffset[last_frame_index] +
|
int frame_size = 0;
|
||||||
fragmentation.fragmentationLength[last_frame_index];
|
for (const rtc::Buffer& nalu : nalus) {
|
||||||
rtc::Buffer frame = CreateFrame(frame_size);
|
frame_size += (kStartCodeSize + nalu.size());
|
||||||
// Set some headers.
|
}
|
||||||
// Tests can expect those are valid but shouln't rely on actual values.
|
rtc::Buffer frame(frame_size);
|
||||||
for (size_t i = 0; i <= last_frame_index; ++i) {
|
size_t offset = 0;
|
||||||
frame[fragmentation.fragmentationOffset[i]] = i + 1;
|
for (const rtc::Buffer& nalu : nalus) {
|
||||||
|
// Insert nalu start code
|
||||||
|
frame[offset] = 0;
|
||||||
|
frame[offset + 1] = 0;
|
||||||
|
frame[offset + 2] = 1;
|
||||||
|
// Copy the nalu unit.
|
||||||
|
memcpy(frame.data() + offset + 3, nalu.data(), nalu.size());
|
||||||
|
offset += (kStartCodeSize + nalu.size());
|
||||||
}
|
}
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
@ -117,31 +133,28 @@ class RtpPacketizerH264ModeTest
|
|||||||
: public ::testing::TestWithParam<H264PacketizationMode> {};
|
: public ::testing::TestWithParam<H264PacketizationMode> {};
|
||||||
|
|
||||||
TEST_P(RtpPacketizerH264ModeTest, SingleNalu) {
|
TEST_P(RtpPacketizerH264ModeTest, SingleNalu) {
|
||||||
const uint8_t frame[2] = {kIdr, 0xFF};
|
const uint8_t frame[] = {0, 0, 1, kIdr, 0xFF};
|
||||||
|
|
||||||
RtpPacketizerH264 packetizer(frame, kNoLimits, GetParam(),
|
RtpPacketizerH264 packetizer(frame, kNoLimits, GetParam());
|
||||||
NoFragmentation(frame));
|
|
||||||
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
||||||
|
|
||||||
ASSERT_THAT(packets, SizeIs(1));
|
ASSERT_THAT(packets, SizeIs(1));
|
||||||
EXPECT_THAT(packets[0].payload(), ElementsAreArray(frame));
|
EXPECT_THAT(packets[0].payload(), ElementsAre(kIdr, 0xFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(RtpPacketizerH264ModeTest, SingleNaluTwoPackets) {
|
TEST_P(RtpPacketizerH264ModeTest, SingleNaluTwoPackets) {
|
||||||
RtpPacketizer::PayloadSizeLimits limits;
|
RtpPacketizer::PayloadSizeLimits limits;
|
||||||
limits.max_payload_len = kMaxPayloadSize;
|
limits.max_payload_len = kMaxPayloadSize;
|
||||||
const size_t fragment_sizes[] = {kMaxPayloadSize, 100};
|
rtc::Buffer nalus[] = {GenerateNalUnit(kMaxPayloadSize),
|
||||||
RTPFragmentationHeader fragmentation = CreateFragmentation(fragment_sizes);
|
GenerateNalUnit(100)};
|
||||||
rtc::Buffer frame = CreateFrame(fragmentation);
|
rtc::Buffer frame = CreateFrame(nalus);
|
||||||
|
|
||||||
RtpPacketizerH264 packetizer(frame, limits, GetParam(), fragmentation);
|
RtpPacketizerH264 packetizer(frame, limits, GetParam());
|
||||||
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
||||||
|
|
||||||
ASSERT_THAT(packets, SizeIs(2));
|
ASSERT_THAT(packets, SizeIs(2));
|
||||||
EXPECT_THAT(packets[0].payload(),
|
EXPECT_THAT(packets[0].payload(), ElementsAreArray(nalus[0]));
|
||||||
ElementsAreArray(frame.data(), kMaxPayloadSize));
|
EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[1]));
|
||||||
EXPECT_THAT(packets[1].payload(),
|
|
||||||
ElementsAreArray(frame.data() + kMaxPayloadSize, 100));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(RtpPacketizerH264ModeTest,
|
TEST_P(RtpPacketizerH264ModeTest,
|
||||||
@ -149,21 +162,18 @@ TEST_P(RtpPacketizerH264ModeTest,
|
|||||||
RtpPacketizer::PayloadSizeLimits limits;
|
RtpPacketizer::PayloadSizeLimits limits;
|
||||||
limits.max_payload_len = 200;
|
limits.max_payload_len = 200;
|
||||||
limits.first_packet_reduction_len = 5;
|
limits.first_packet_reduction_len = 5;
|
||||||
const size_t fragments[] = {195, 200, 200};
|
rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/195),
|
||||||
|
GenerateNalUnit(/*size=*/200),
|
||||||
|
GenerateNalUnit(/*size=*/200)};
|
||||||
|
rtc::Buffer frame = CreateFrame(nalus);
|
||||||
|
|
||||||
RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
|
RtpPacketizerH264 packetizer(frame, limits, GetParam());
|
||||||
rtc::Buffer frame = CreateFrame(fragmentation);
|
|
||||||
|
|
||||||
RtpPacketizerH264 packetizer(frame, limits, GetParam(), fragmentation);
|
|
||||||
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
||||||
|
|
||||||
ASSERT_THAT(packets, SizeIs(3));
|
ASSERT_THAT(packets, SizeIs(3));
|
||||||
const uint8_t* next_fragment = frame.data();
|
EXPECT_THAT(packets[0].payload(), ElementsAreArray(nalus[0]));
|
||||||
EXPECT_THAT(packets[0].payload(), ElementsAreArray(next_fragment, 195));
|
EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[1]));
|
||||||
next_fragment += 195;
|
EXPECT_THAT(packets[2].payload(), ElementsAreArray(nalus[2]));
|
||||||
EXPECT_THAT(packets[1].payload(), ElementsAreArray(next_fragment, 200));
|
|
||||||
next_fragment += 200;
|
|
||||||
EXPECT_THAT(packets[2].payload(), ElementsAreArray(next_fragment, 200));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(RtpPacketizerH264ModeTest,
|
TEST_P(RtpPacketizerH264ModeTest,
|
||||||
@ -171,21 +181,18 @@ TEST_P(RtpPacketizerH264ModeTest,
|
|||||||
RtpPacketizer::PayloadSizeLimits limits;
|
RtpPacketizer::PayloadSizeLimits limits;
|
||||||
limits.max_payload_len = 200;
|
limits.max_payload_len = 200;
|
||||||
limits.last_packet_reduction_len = 5;
|
limits.last_packet_reduction_len = 5;
|
||||||
const size_t fragments[] = {200, 200, 195};
|
rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/200),
|
||||||
|
GenerateNalUnit(/*size=*/200),
|
||||||
|
GenerateNalUnit(/*size=*/195)};
|
||||||
|
rtc::Buffer frame = CreateFrame(nalus);
|
||||||
|
|
||||||
RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
|
RtpPacketizerH264 packetizer(frame, limits, GetParam());
|
||||||
rtc::Buffer frame = CreateFrame(fragmentation);
|
|
||||||
|
|
||||||
RtpPacketizerH264 packetizer(frame, limits, GetParam(), fragmentation);
|
|
||||||
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
||||||
|
|
||||||
ASSERT_THAT(packets, SizeIs(3));
|
ASSERT_THAT(packets, SizeIs(3));
|
||||||
const uint8_t* next_fragment = frame.data();
|
EXPECT_THAT(packets[0].payload(), ElementsAreArray(nalus[0]));
|
||||||
EXPECT_THAT(packets[0].payload(), ElementsAreArray(next_fragment, 200));
|
EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[1]));
|
||||||
next_fragment += 200;
|
EXPECT_THAT(packets[2].payload(), ElementsAreArray(nalus[2]));
|
||||||
EXPECT_THAT(packets[1].payload(), ElementsAreArray(next_fragment, 200));
|
|
||||||
next_fragment += 200;
|
|
||||||
EXPECT_THAT(packets[2].payload(), ElementsAreArray(next_fragment, 195));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(RtpPacketizerH264ModeTest,
|
TEST_P(RtpPacketizerH264ModeTest,
|
||||||
@ -194,10 +201,9 @@ TEST_P(RtpPacketizerH264ModeTest,
|
|||||||
limits.max_payload_len = 200;
|
limits.max_payload_len = 200;
|
||||||
limits.first_packet_reduction_len = 20;
|
limits.first_packet_reduction_len = 20;
|
||||||
limits.last_packet_reduction_len = 30;
|
limits.last_packet_reduction_len = 30;
|
||||||
rtc::Buffer frame = CreateFrame(150);
|
rtc::Buffer frame = CreateFrame({150});
|
||||||
|
|
||||||
RtpPacketizerH264 packetizer(frame, limits, GetParam(),
|
RtpPacketizerH264 packetizer(frame, limits, GetParam());
|
||||||
NoFragmentation(frame));
|
|
||||||
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
||||||
|
|
||||||
EXPECT_THAT(packets, SizeIs(1));
|
EXPECT_THAT(packets, SizeIs(1));
|
||||||
@ -211,19 +217,19 @@ INSTANTIATE_TEST_SUITE_P(
|
|||||||
|
|
||||||
// Aggregation tests.
|
// Aggregation tests.
|
||||||
TEST(RtpPacketizerH264Test, StapA) {
|
TEST(RtpPacketizerH264Test, StapA) {
|
||||||
size_t fragments[] = {2, 2, 0x123};
|
rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/2),
|
||||||
|
GenerateNalUnit(/*size=*/2),
|
||||||
|
GenerateNalUnit(/*size=*/0x123)};
|
||||||
|
rtc::Buffer frame = CreateFrame(nalus);
|
||||||
|
|
||||||
RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
|
RtpPacketizerH264 packetizer(frame, kNoLimits,
|
||||||
rtc::Buffer frame = CreateFrame(fragmentation);
|
H264PacketizationMode::NonInterleaved);
|
||||||
|
|
||||||
RtpPacketizerH264 packetizer(
|
|
||||||
frame, kNoLimits, H264PacketizationMode::NonInterleaved, fragmentation);
|
|
||||||
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
||||||
|
|
||||||
ASSERT_THAT(packets, SizeIs(1));
|
ASSERT_THAT(packets, SizeIs(1));
|
||||||
auto payload = packets[0].payload();
|
auto payload = packets[0].payload();
|
||||||
EXPECT_EQ(payload.size(),
|
EXPECT_EQ(payload.size(),
|
||||||
kNalHeaderSize + 3 * kLengthFieldLength + frame.size());
|
kNalHeaderSize + 3 * kLengthFieldLength + 2 + 2 + 0x123);
|
||||||
|
|
||||||
EXPECT_EQ(payload[0], kStapA);
|
EXPECT_EQ(payload[0], kStapA);
|
||||||
payload = payload.subview(kNalHeaderSize);
|
payload = payload.subview(kNalHeaderSize);
|
||||||
@ -231,29 +237,26 @@ TEST(RtpPacketizerH264Test, StapA) {
|
|||||||
EXPECT_THAT(payload.subview(0, kLengthFieldLength),
|
EXPECT_THAT(payload.subview(0, kLengthFieldLength),
|
||||||
ElementsAre(0, 2)); // Size.
|
ElementsAre(0, 2)); // Size.
|
||||||
EXPECT_THAT(payload.subview(kLengthFieldLength, 2),
|
EXPECT_THAT(payload.subview(kLengthFieldLength, 2),
|
||||||
ElementsAreArray(frame.data(), 2));
|
ElementsAreArray(nalus[0]));
|
||||||
payload = payload.subview(kLengthFieldLength + 2);
|
payload = payload.subview(kLengthFieldLength + 2);
|
||||||
// 2nd fragment.
|
// 2nd fragment.
|
||||||
EXPECT_THAT(payload.subview(0, kLengthFieldLength),
|
EXPECT_THAT(payload.subview(0, kLengthFieldLength),
|
||||||
ElementsAre(0, 2)); // Size.
|
ElementsAre(0, 2)); // Size.
|
||||||
EXPECT_THAT(payload.subview(kLengthFieldLength, 2),
|
EXPECT_THAT(payload.subview(kLengthFieldLength, 2),
|
||||||
ElementsAreArray(frame.data() + 2, 2));
|
ElementsAreArray(nalus[1]));
|
||||||
payload = payload.subview(kLengthFieldLength + 2);
|
payload = payload.subview(kLengthFieldLength + 2);
|
||||||
// 3rd fragment.
|
// 3rd fragment.
|
||||||
EXPECT_THAT(payload.subview(0, kLengthFieldLength),
|
EXPECT_THAT(payload.subview(0, kLengthFieldLength),
|
||||||
ElementsAre(0x1, 0x23)); // Size.
|
ElementsAre(0x1, 0x23)); // Size.
|
||||||
EXPECT_THAT(payload.subview(kLengthFieldLength),
|
EXPECT_THAT(payload.subview(kLengthFieldLength), ElementsAreArray(nalus[2]));
|
||||||
ElementsAreArray(frame.data() + 4, 0x123));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(RtpPacketizerH264Test, SingleNalUnitModeHasNoStapA) {
|
TEST(RtpPacketizerH264Test, SingleNalUnitModeHasNoStapA) {
|
||||||
// This is the same setup as for the StapA test.
|
// This is the same setup as for the StapA test.
|
||||||
size_t fragments[] = {2, 2, 0x123};
|
rtc::Buffer frame = CreateFrame({2, 2, 0x123});
|
||||||
RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
|
|
||||||
rtc::Buffer frame = CreateFrame(fragmentation);
|
|
||||||
|
|
||||||
RtpPacketizerH264 packetizer(
|
RtpPacketizerH264 packetizer(frame, kNoLimits,
|
||||||
frame, kNoLimits, H264PacketizationMode::SingleNalUnit, fragmentation);
|
H264PacketizationMode::SingleNalUnit);
|
||||||
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
||||||
|
|
||||||
// The three fragments should be returned as three packets.
|
// The three fragments should be returned as three packets.
|
||||||
@ -269,23 +272,23 @@ TEST(RtpPacketizerH264Test, StapARespectsFirstPacketReduction) {
|
|||||||
limits.first_packet_reduction_len = 100;
|
limits.first_packet_reduction_len = 100;
|
||||||
const size_t kFirstFragmentSize =
|
const size_t kFirstFragmentSize =
|
||||||
limits.max_payload_len - limits.first_packet_reduction_len;
|
limits.max_payload_len - limits.first_packet_reduction_len;
|
||||||
size_t fragments[] = {kFirstFragmentSize, 2, 2};
|
rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/kFirstFragmentSize),
|
||||||
RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
|
GenerateNalUnit(/*size=*/2),
|
||||||
rtc::Buffer frame = CreateFrame(fragmentation);
|
GenerateNalUnit(/*size=*/2)};
|
||||||
|
rtc::Buffer frame = CreateFrame(nalus);
|
||||||
|
|
||||||
RtpPacketizerH264 packetizer(
|
RtpPacketizerH264 packetizer(frame, limits,
|
||||||
frame, limits, H264PacketizationMode::NonInterleaved, fragmentation);
|
H264PacketizationMode::NonInterleaved);
|
||||||
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
||||||
|
|
||||||
ASSERT_THAT(packets, SizeIs(2));
|
ASSERT_THAT(packets, SizeIs(2));
|
||||||
// Expect 1st packet is single nalu.
|
// Expect 1st packet is single nalu.
|
||||||
EXPECT_THAT(packets[0].payload(),
|
EXPECT_THAT(packets[0].payload(), ElementsAreArray(nalus[0]));
|
||||||
ElementsAreArray(frame.data(), kFirstFragmentSize));
|
|
||||||
// Expect 2nd packet is aggregate of last two fragments.
|
// Expect 2nd packet is aggregate of last two fragments.
|
||||||
const uint8_t* tail = frame.data() + kFirstFragmentSize;
|
EXPECT_THAT(packets[1].payload(),
|
||||||
EXPECT_THAT(packets[1].payload(), ElementsAre(kStapA, //
|
ElementsAre(kStapA, //
|
||||||
0, 2, tail[0], tail[1], //
|
0, 2, nalus[1][0], nalus[1][1], //
|
||||||
0, 2, tail[2], tail[3]));
|
0, 2, nalus[2][0], nalus[2][1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(RtpPacketizerH264Test, StapARespectsLastPacketReduction) {
|
TEST(RtpPacketizerH264Test, StapARespectsLastPacketReduction) {
|
||||||
@ -294,22 +297,23 @@ TEST(RtpPacketizerH264Test, StapARespectsLastPacketReduction) {
|
|||||||
limits.last_packet_reduction_len = 100;
|
limits.last_packet_reduction_len = 100;
|
||||||
const size_t kLastFragmentSize =
|
const size_t kLastFragmentSize =
|
||||||
limits.max_payload_len - limits.last_packet_reduction_len;
|
limits.max_payload_len - limits.last_packet_reduction_len;
|
||||||
size_t fragments[] = {2, 2, kLastFragmentSize};
|
rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/2),
|
||||||
RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
|
GenerateNalUnit(/*size=*/2),
|
||||||
rtc::Buffer frame = CreateFrame(fragmentation);
|
GenerateNalUnit(/*size=*/kLastFragmentSize)};
|
||||||
|
rtc::Buffer frame = CreateFrame(nalus);
|
||||||
|
|
||||||
RtpPacketizerH264 packetizer(
|
RtpPacketizerH264 packetizer(frame, limits,
|
||||||
frame, limits, H264PacketizationMode::NonInterleaved, fragmentation);
|
H264PacketizationMode::NonInterleaved);
|
||||||
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
||||||
|
|
||||||
ASSERT_THAT(packets, SizeIs(2));
|
ASSERT_THAT(packets, SizeIs(2));
|
||||||
// Expect 1st packet is aggregate of 1st two fragments.
|
// Expect 1st packet is aggregate of 1st two fragments.
|
||||||
EXPECT_THAT(packets[0].payload(), ElementsAre(kStapA, //
|
EXPECT_THAT(packets[0].payload(),
|
||||||
0, 2, frame[0], frame[1], //
|
ElementsAre(kStapA, //
|
||||||
0, 2, frame[2], frame[3]));
|
0, 2, nalus[0][0], nalus[0][1], //
|
||||||
|
0, 2, nalus[1][0], nalus[1][1]));
|
||||||
// Expect 2nd packet is single nalu.
|
// Expect 2nd packet is single nalu.
|
||||||
EXPECT_THAT(packets[1].payload(),
|
EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[2]));
|
||||||
ElementsAreArray(frame.data() + 4, kLastFragmentSize));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(RtpPacketizerH264Test, TooSmallForStapAHeaders) {
|
TEST(RtpPacketizerH264Test, TooSmallForStapAHeaders) {
|
||||||
@ -317,22 +321,23 @@ TEST(RtpPacketizerH264Test, TooSmallForStapAHeaders) {
|
|||||||
limits.max_payload_len = 1000;
|
limits.max_payload_len = 1000;
|
||||||
const size_t kLastFragmentSize =
|
const size_t kLastFragmentSize =
|
||||||
limits.max_payload_len - 3 * kLengthFieldLength - 4;
|
limits.max_payload_len - 3 * kLengthFieldLength - 4;
|
||||||
size_t fragments[] = {2, 2, kLastFragmentSize};
|
rtc::Buffer nalus[] = {GenerateNalUnit(/*size=*/2),
|
||||||
RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
|
GenerateNalUnit(/*size=*/2),
|
||||||
rtc::Buffer frame = CreateFrame(fragmentation);
|
GenerateNalUnit(/*size=*/kLastFragmentSize)};
|
||||||
|
rtc::Buffer frame = CreateFrame(nalus);
|
||||||
|
|
||||||
RtpPacketizerH264 packetizer(
|
RtpPacketizerH264 packetizer(frame, limits,
|
||||||
frame, limits, H264PacketizationMode::NonInterleaved, fragmentation);
|
H264PacketizationMode::NonInterleaved);
|
||||||
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
||||||
|
|
||||||
ASSERT_THAT(packets, SizeIs(2));
|
ASSERT_THAT(packets, SizeIs(2));
|
||||||
// Expect 1st packet is aggregate of 1st two fragments.
|
// Expect 1st packet is aggregate of 1st two fragments.
|
||||||
EXPECT_THAT(packets[0].payload(), ElementsAre(kStapA, //
|
EXPECT_THAT(packets[0].payload(),
|
||||||
0, 2, frame[0], frame[1], //
|
ElementsAre(kStapA, //
|
||||||
0, 2, frame[2], frame[3]));
|
0, 2, nalus[0][0], nalus[0][1], //
|
||||||
|
0, 2, nalus[1][0], nalus[1][1]));
|
||||||
// Expect 2nd packet is single nalu.
|
// Expect 2nd packet is single nalu.
|
||||||
EXPECT_THAT(packets[1].payload(),
|
EXPECT_THAT(packets[1].payload(), ElementsAreArray(nalus[2]));
|
||||||
ElementsAreArray(frame.data() + 4, kLastFragmentSize));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fragmentation + aggregation.
|
// Fragmentation + aggregation.
|
||||||
@ -342,28 +347,29 @@ TEST(RtpPacketizerH264Test, MixedStapAFUA) {
|
|||||||
const size_t kFuaPayloadSize = 70;
|
const size_t kFuaPayloadSize = 70;
|
||||||
const size_t kFuaNaluSize = kNalHeaderSize + 2 * kFuaPayloadSize;
|
const size_t kFuaNaluSize = kNalHeaderSize + 2 * kFuaPayloadSize;
|
||||||
const size_t kStapANaluSize = 20;
|
const size_t kStapANaluSize = 20;
|
||||||
size_t fragments[] = {kFuaNaluSize, kStapANaluSize, kStapANaluSize};
|
rtc::Buffer nalus[] = {GenerateNalUnit(kFuaNaluSize),
|
||||||
RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
|
GenerateNalUnit(kStapANaluSize),
|
||||||
rtc::Buffer frame = CreateFrame(fragmentation);
|
GenerateNalUnit(kStapANaluSize)};
|
||||||
|
rtc::Buffer frame = CreateFrame(nalus);
|
||||||
|
|
||||||
RtpPacketizerH264 packetizer(
|
RtpPacketizerH264 packetizer(frame, limits,
|
||||||
frame, limits, H264PacketizationMode::NonInterleaved, fragmentation);
|
H264PacketizationMode::NonInterleaved);
|
||||||
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
||||||
|
|
||||||
ASSERT_THAT(packets, SizeIs(3));
|
ASSERT_THAT(packets, SizeIs(3));
|
||||||
const uint8_t* next_fragment = frame.data() + kNalHeaderSize;
|
|
||||||
// First expect two FU-A packets.
|
// First expect two FU-A packets.
|
||||||
EXPECT_THAT(packets[0].payload().subview(0, kFuAHeaderSize),
|
EXPECT_THAT(packets[0].payload().subview(0, kFuAHeaderSize),
|
||||||
ElementsAre(kFuA, FuDefs::kSBit | frame[0]));
|
ElementsAre(kFuA, FuDefs::kSBit | nalus[0][0]));
|
||||||
EXPECT_THAT(packets[0].payload().subview(kFuAHeaderSize),
|
EXPECT_THAT(
|
||||||
ElementsAreArray(next_fragment, kFuaPayloadSize));
|
packets[0].payload().subview(kFuAHeaderSize),
|
||||||
next_fragment += kFuaPayloadSize;
|
ElementsAreArray(nalus[0].data() + kNalHeaderSize, kFuaPayloadSize));
|
||||||
|
|
||||||
EXPECT_THAT(packets[1].payload().subview(0, kFuAHeaderSize),
|
EXPECT_THAT(packets[1].payload().subview(0, kFuAHeaderSize),
|
||||||
ElementsAre(kFuA, FuDefs::kEBit | frame[0]));
|
ElementsAre(kFuA, FuDefs::kEBit | nalus[0][0]));
|
||||||
EXPECT_THAT(packets[1].payload().subview(kFuAHeaderSize),
|
EXPECT_THAT(
|
||||||
ElementsAreArray(next_fragment, kFuaPayloadSize));
|
packets[1].payload().subview(kFuAHeaderSize),
|
||||||
next_fragment += kFuaPayloadSize;
|
ElementsAreArray(nalus[0].data() + kNalHeaderSize + kFuaPayloadSize,
|
||||||
|
kFuaPayloadSize));
|
||||||
|
|
||||||
// Then expect one STAP-A packet with two nal units.
|
// Then expect one STAP-A packet with two nal units.
|
||||||
EXPECT_THAT(packets[2].payload()[0], kStapA);
|
EXPECT_THAT(packets[2].payload()[0], kStapA);
|
||||||
@ -371,13 +377,11 @@ TEST(RtpPacketizerH264Test, MixedStapAFUA) {
|
|||||||
EXPECT_THAT(payload.subview(0, kLengthFieldLength),
|
EXPECT_THAT(payload.subview(0, kLengthFieldLength),
|
||||||
ElementsAre(0, kStapANaluSize));
|
ElementsAre(0, kStapANaluSize));
|
||||||
EXPECT_THAT(payload.subview(kLengthFieldLength, kStapANaluSize),
|
EXPECT_THAT(payload.subview(kLengthFieldLength, kStapANaluSize),
|
||||||
ElementsAreArray(next_fragment, kStapANaluSize));
|
ElementsAreArray(nalus[1]));
|
||||||
payload = payload.subview(kLengthFieldLength + kStapANaluSize);
|
payload = payload.subview(kLengthFieldLength + kStapANaluSize);
|
||||||
next_fragment += kStapANaluSize;
|
|
||||||
EXPECT_THAT(payload.subview(0, kLengthFieldLength),
|
EXPECT_THAT(payload.subview(0, kLengthFieldLength),
|
||||||
ElementsAre(0, kStapANaluSize));
|
ElementsAre(0, kStapANaluSize));
|
||||||
EXPECT_THAT(payload.subview(kLengthFieldLength),
|
EXPECT_THAT(payload.subview(kLengthFieldLength), ElementsAreArray(nalus[2]));
|
||||||
ElementsAreArray(next_fragment, kStapANaluSize));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(RtpPacketizerH264Test, LastFragmentFitsInSingleButNotLastPacket) {
|
TEST(RtpPacketizerH264Test, LastFragmentFitsInSingleButNotLastPacket) {
|
||||||
@ -387,12 +391,10 @@ TEST(RtpPacketizerH264Test, LastFragmentFitsInSingleButNotLastPacket) {
|
|||||||
limits.last_packet_reduction_len = 20;
|
limits.last_packet_reduction_len = 20;
|
||||||
limits.single_packet_reduction_len = 20;
|
limits.single_packet_reduction_len = 20;
|
||||||
// Actual sizes, which triggered this bug.
|
// Actual sizes, which triggered this bug.
|
||||||
size_t fragments[] = {20, 8, 18, 1161};
|
rtc::Buffer frame = CreateFrame({20, 8, 18, 1161});
|
||||||
RTPFragmentationHeader fragmentation = CreateFragmentation(fragments);
|
|
||||||
rtc::Buffer frame = CreateFrame(fragmentation);
|
|
||||||
|
|
||||||
RtpPacketizerH264 packetizer(
|
RtpPacketizerH264 packetizer(frame, limits,
|
||||||
frame, limits, H264PacketizationMode::NonInterleaved, fragmentation);
|
H264PacketizationMode::NonInterleaved);
|
||||||
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
||||||
|
|
||||||
// Last packet has to be of correct size.
|
// Last packet has to be of correct size.
|
||||||
@ -406,11 +408,11 @@ TEST(RtpPacketizerH264Test, LastFragmentFitsInSingleButNotLastPacket) {
|
|||||||
// Returns sizes of the payloads excluding fua headers.
|
// Returns sizes of the payloads excluding fua headers.
|
||||||
std::vector<int> TestFua(size_t frame_payload_size,
|
std::vector<int> TestFua(size_t frame_payload_size,
|
||||||
const RtpPacketizer::PayloadSizeLimits& limits) {
|
const RtpPacketizer::PayloadSizeLimits& limits) {
|
||||||
rtc::Buffer frame = CreateFrame(kNalHeaderSize + frame_payload_size);
|
rtc::Buffer nalu[] = {GenerateNalUnit(kNalHeaderSize + frame_payload_size)};
|
||||||
|
rtc::Buffer frame = CreateFrame(nalu);
|
||||||
|
|
||||||
RtpPacketizerH264 packetizer(frame, limits,
|
RtpPacketizerH264 packetizer(frame, limits,
|
||||||
H264PacketizationMode::NonInterleaved,
|
H264PacketizationMode::NonInterleaved);
|
||||||
NoFragmentation(frame));
|
|
||||||
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
||||||
|
|
||||||
EXPECT_GE(packets.size(), 2u); // Single packet indicates it is not FuA.
|
EXPECT_GE(packets.size(), 2u); // Single packet indicates it is not FuA.
|
||||||
@ -429,7 +431,7 @@ std::vector<int> TestFua(size_t frame_payload_size,
|
|||||||
// Clear S and E bits before testing all are duplicating same original header.
|
// Clear S and E bits before testing all are duplicating same original header.
|
||||||
fua_header.front() &= ~FuDefs::kSBit;
|
fua_header.front() &= ~FuDefs::kSBit;
|
||||||
fua_header.back() &= ~FuDefs::kEBit;
|
fua_header.back() &= ~FuDefs::kEBit;
|
||||||
EXPECT_THAT(fua_header, Each(Eq((kFuA << 8) | frame[0])));
|
EXPECT_THAT(fua_header, Each(Eq((kFuA << 8) | nalu[0][0])));
|
||||||
|
|
||||||
return payload_sizes;
|
return payload_sizes;
|
||||||
}
|
}
|
||||||
@ -488,11 +490,10 @@ TEST(RtpPacketizerH264Test, FUABig) {
|
|||||||
|
|
||||||
TEST(RtpPacketizerH264Test, RejectsOverlongDataInPacketizationMode0) {
|
TEST(RtpPacketizerH264Test, RejectsOverlongDataInPacketizationMode0) {
|
||||||
RtpPacketizer::PayloadSizeLimits limits;
|
RtpPacketizer::PayloadSizeLimits limits;
|
||||||
rtc::Buffer frame = CreateFrame(kMaxPayloadSize + 1);
|
rtc::Buffer frame = CreateFrame({kMaxPayloadSize + 1});
|
||||||
RTPFragmentationHeader fragmentation = NoFragmentation(frame);
|
|
||||||
|
|
||||||
RtpPacketizerH264 packetizer(
|
RtpPacketizerH264 packetizer(frame, limits,
|
||||||
frame, limits, H264PacketizationMode::SingleNalUnit, fragmentation);
|
H264PacketizationMode::SingleNalUnit);
|
||||||
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
std::vector<RtpPacketToSend> packets = FetchAllPackets(&packetizer);
|
||||||
|
|
||||||
EXPECT_THAT(packets, IsEmpty());
|
EXPECT_THAT(packets, IsEmpty());
|
||||||
|
|||||||
@ -290,6 +290,7 @@ FakeH264Encoder::FakeH264Encoder(Clock* clock)
|
|||||||
std::unique_ptr<RTPFragmentationHeader> FakeH264Encoder::EncodeHook(
|
std::unique_ptr<RTPFragmentationHeader> FakeH264Encoder::EncodeHook(
|
||||||
EncodedImage* encoded_image,
|
EncodedImage* encoded_image,
|
||||||
CodecSpecificInfo* codec_specific) {
|
CodecSpecificInfo* codec_specific) {
|
||||||
|
static constexpr std::array<uint8_t, 3> kStartCode = {0, 0, 1};
|
||||||
const size_t kSpsSize = 8;
|
const size_t kSpsSize = 8;
|
||||||
const size_t kPpsSize = 11;
|
const size_t kPpsSize = 11;
|
||||||
const int kIdrFrequency = 10;
|
const int kIdrFrequency = 10;
|
||||||
@ -299,46 +300,46 @@ std::unique_ptr<RTPFragmentationHeader> FakeH264Encoder::EncodeHook(
|
|||||||
current_idr_counter = idr_counter_;
|
current_idr_counter = idr_counter_;
|
||||||
++idr_counter_;
|
++idr_counter_;
|
||||||
}
|
}
|
||||||
|
for (size_t i = 0; i < encoded_image->size(); ++i) {
|
||||||
|
encoded_image->data()[i] = static_cast<uint8_t>(i);
|
||||||
|
}
|
||||||
|
|
||||||
auto fragmentation = std::make_unique<RTPFragmentationHeader>();
|
auto fragmentation = std::make_unique<RTPFragmentationHeader>();
|
||||||
|
|
||||||
if (current_idr_counter % kIdrFrequency == 0 &&
|
if (current_idr_counter % kIdrFrequency == 0 &&
|
||||||
encoded_image->size() > kSpsSize + kPpsSize + 1) {
|
encoded_image->size() > kSpsSize + kPpsSize + 1 + 3 * kStartCode.size()) {
|
||||||
const size_t kNumSlices = 3;
|
const size_t kNumSlices = 3;
|
||||||
fragmentation->VerifyAndAllocateFragmentationHeader(kNumSlices);
|
fragmentation->VerifyAndAllocateFragmentationHeader(kNumSlices);
|
||||||
fragmentation->fragmentationOffset[0] = 0;
|
fragmentation->fragmentationOffset[0] = kStartCode.size();
|
||||||
fragmentation->fragmentationLength[0] = kSpsSize;
|
fragmentation->fragmentationLength[0] = kSpsSize;
|
||||||
fragmentation->fragmentationOffset[1] = kSpsSize;
|
fragmentation->fragmentationOffset[1] = 2 * kStartCode.size() + kSpsSize;
|
||||||
fragmentation->fragmentationLength[1] = kPpsSize;
|
fragmentation->fragmentationLength[1] = kPpsSize;
|
||||||
fragmentation->fragmentationOffset[2] = kSpsSize + kPpsSize;
|
fragmentation->fragmentationOffset[2] =
|
||||||
|
3 * kStartCode.size() + kSpsSize + kPpsSize;
|
||||||
fragmentation->fragmentationLength[2] =
|
fragmentation->fragmentationLength[2] =
|
||||||
encoded_image->size() - (kSpsSize + kPpsSize);
|
encoded_image->size() - (3 * kStartCode.size() + kSpsSize + kPpsSize);
|
||||||
const size_t kSpsNalHeader = 0x67;
|
const size_t kSpsNalHeader = 0x67;
|
||||||
const size_t kPpsNalHeader = 0x68;
|
const size_t kPpsNalHeader = 0x68;
|
||||||
const size_t kIdrNalHeader = 0x65;
|
const size_t kIdrNalHeader = 0x65;
|
||||||
encoded_image->data()[fragmentation->fragmentationOffset[0]] =
|
memcpy(encoded_image->data(), kStartCode.data(), kStartCode.size());
|
||||||
kSpsNalHeader;
|
encoded_image->data()[fragmentation->Offset(0)] = kSpsNalHeader;
|
||||||
encoded_image->data()[fragmentation->fragmentationOffset[1]] =
|
memcpy(encoded_image->data() + fragmentation->Offset(1) - kStartCode.size(),
|
||||||
kPpsNalHeader;
|
kStartCode.data(), kStartCode.size());
|
||||||
encoded_image->data()[fragmentation->fragmentationOffset[2]] =
|
encoded_image->data()[fragmentation->Offset(1)] = kPpsNalHeader;
|
||||||
kIdrNalHeader;
|
memcpy(encoded_image->data() + fragmentation->Offset(2) - kStartCode.size(),
|
||||||
|
kStartCode.data(), kStartCode.size());
|
||||||
|
encoded_image->data()[fragmentation->Offset(2)] = kIdrNalHeader;
|
||||||
} else {
|
} else {
|
||||||
const size_t kNumSlices = 1;
|
const size_t kNumSlices = 1;
|
||||||
fragmentation->VerifyAndAllocateFragmentationHeader(kNumSlices);
|
fragmentation->VerifyAndAllocateFragmentationHeader(kNumSlices);
|
||||||
fragmentation->fragmentationOffset[0] = 0;
|
fragmentation->fragmentationOffset[0] = kStartCode.size();
|
||||||
fragmentation->fragmentationLength[0] = encoded_image->size();
|
fragmentation->fragmentationLength[0] =
|
||||||
|
encoded_image->size() - kStartCode.size();
|
||||||
|
memcpy(encoded_image->data(), kStartCode.data(), kStartCode.size());
|
||||||
const size_t kNalHeader = 0x41;
|
const size_t kNalHeader = 0x41;
|
||||||
encoded_image->data()[fragmentation->fragmentationOffset[0]] = kNalHeader;
|
encoded_image->data()[fragmentation->fragmentationOffset[0]] = kNalHeader;
|
||||||
}
|
}
|
||||||
uint8_t value = 0;
|
|
||||||
int fragment_counter = 0;
|
|
||||||
for (size_t i = 0; i < encoded_image->size(); ++i) {
|
|
||||||
if (fragment_counter == fragmentation->fragmentationVectorSize ||
|
|
||||||
i != fragmentation->fragmentationOffset[fragment_counter]) {
|
|
||||||
encoded_image->data()[i] = value++;
|
|
||||||
} else {
|
|
||||||
++fragment_counter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
codec_specific->codecType = kVideoCodecH264;
|
codec_specific->codecType = kVideoCodecH264;
|
||||||
codec_specific->codecSpecific.H264.packetization_mode =
|
codec_specific->codecSpecific.H264.packetization_mode =
|
||||||
H264PacketizationMode::NonInterleaved;
|
H264PacketizationMode::NonInterleaved;
|
||||||
|
|||||||
Reference in New Issue
Block a user