RtpPacketizer::NextPacket fills RtpPacket instead of just payload.

This push decision if Marker bit should be set into packetizers fixing
issue where returned last_packet flag was ambiguous for some VP9 packets.

Added test for VP9 where last_packet != marker_bit

BUG=webrtc:6723

Review-Url: https://codereview.webrtc.org/2522553002
Cr-Commit-Position: refs/heads/master@{#15415}
This commit is contained in:
danilchap 2016-12-05 02:26:44 -08:00 committed by Commit bot
parent f00082da37
commit e545e5d062
15 changed files with 317 additions and 295 deletions

View File

@ -18,6 +18,7 @@
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
namespace webrtc {
class RtpPacketToSend;
class RtpPacketizer {
public:
@ -33,15 +34,11 @@ class RtpPacketizer {
const RTPFragmentationHeader* fragmentation) = 0;
// Get the next payload with payload header.
// buffer is a pointer to where the output will be written.
// bytes_to_send is an output variable that will contain number of bytes
// written to buffer. The parameter last_packet is true for the last packet of
// the frame, false otherwise (i.e., call the function again to get the
// next packet).
// Returns true on success or false if there was no payload to packetize.
virtual bool NextPacket(uint8_t* buffer,
size_t* bytes_to_send,
bool* last_packet) = 0;
// Write payload and set marker bit of the |packet|.
// The parameter |last_packet| is true for the last packet of the frame, false
// otherwise (i.e., call the function again to get the next packet).
// Returns true on success, false otherwise.
virtual bool NextPacket(RtpPacketToSend* packet, bool* last_packet) = 0;
virtual ProtectionType GetProtectionType() = 0;

View File

@ -19,6 +19,7 @@
#include "webrtc/base/logging.h"
#include "webrtc/modules/include/module_common_types.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "webrtc/common_video/h264/sps_vui_rewriter.h"
#include "webrtc/common_video/h264/h264_common.h"
#include "webrtc/common_video/h264/pps_parser.h"
@ -229,54 +230,50 @@ size_t RtpPacketizerH264::PacketizeStapA(size_t fragment_index) {
return fragment_index;
}
bool RtpPacketizerH264::NextPacket(uint8_t* buffer,
size_t* bytes_to_send,
bool RtpPacketizerH264::NextPacket(RtpPacketToSend* rtp_packet,
bool* last_packet) {
*bytes_to_send = 0;
RTC_DCHECK(rtp_packet);
RTC_DCHECK(last_packet);
if (packets_.empty()) {
*bytes_to_send = 0;
*last_packet = true;
return false;
}
PacketUnit packet = packets_.front();
if (packet.first_fragment && packet.last_fragment) {
// Single NAL unit packet.
*bytes_to_send = packet.source_fragment.length;
memcpy(buffer, packet.source_fragment.buffer, *bytes_to_send);
size_t bytes_to_send = packet.source_fragment.length;
uint8_t* buffer = rtp_packet->AllocatePayload(bytes_to_send);
memcpy(buffer, packet.source_fragment.buffer, bytes_to_send);
packets_.pop();
input_fragments_.pop_front();
RTC_CHECK_LE(*bytes_to_send, max_payload_len_);
} else if (packet.aggregated) {
NextAggregatePacket(buffer, bytes_to_send);
RTC_CHECK_LE(*bytes_to_send, max_payload_len_);
NextAggregatePacket(rtp_packet);
} else {
NextFragmentPacket(buffer, bytes_to_send);
RTC_CHECK_LE(*bytes_to_send, max_payload_len_);
NextFragmentPacket(rtp_packet);
}
RTC_DCHECK_LE(rtp_packet->payload_size(), max_payload_len_);
*last_packet = packets_.empty();
rtp_packet->SetMarker(*last_packet);
return true;
}
void RtpPacketizerH264::NextAggregatePacket(uint8_t* buffer,
size_t* bytes_to_send) {
void RtpPacketizerH264::NextAggregatePacket(RtpPacketToSend* rtp_packet) {
uint8_t* buffer = rtp_packet->AllocatePayload(max_payload_len_);
RTC_DCHECK(buffer);
PacketUnit* packet = &packets_.front();
RTC_CHECK(packet->first_fragment);
// STAP-A NALU header.
buffer[0] = (packet->header & (kFBit | kNriMask)) | H264::NaluType::kStapA;
int index = kNalHeaderSize;
*bytes_to_send += kNalHeaderSize;
size_t index = kNalHeaderSize;
while (packet->aggregated) {
const Fragment& fragment = packet->source_fragment;
// Add NAL unit length field.
ByteWriter<uint16_t>::WriteBigEndian(&buffer[index], fragment.length);
index += kLengthFieldSize;
*bytes_to_send += kLengthFieldSize;
// Add NAL unit.
memcpy(&buffer[index], fragment.buffer, fragment.length);
index += fragment.length;
*bytes_to_send += fragment.length;
packets_.pop();
input_fragments_.pop_front();
if (packet->last_fragment)
@ -284,10 +281,10 @@ void RtpPacketizerH264::NextAggregatePacket(uint8_t* buffer,
packet = &packets_.front();
}
RTC_CHECK(packet->last_fragment);
rtp_packet->SetPayloadSize(index);
}
void RtpPacketizerH264::NextFragmentPacket(uint8_t* buffer,
size_t* bytes_to_send) {
void RtpPacketizerH264::NextFragmentPacket(RtpPacketToSend* rtp_packet) {
PacketUnit* packet = &packets_.front();
// NAL unit fragmented over multiple packets (FU-A).
// We do not send original NALU header, so it will be replaced by the
@ -301,11 +298,11 @@ void RtpPacketizerH264::NextFragmentPacket(uint8_t* buffer,
fu_header |= (packet->last_fragment ? kEBit : 0);
uint8_t type = packet->header & kTypeMask;
fu_header |= type;
const Fragment& fragment = packet->source_fragment;
uint8_t* buffer =
rtp_packet->AllocatePayload(kFuAHeaderSize + fragment.length);
buffer[0] = fu_indicator;
buffer[1] = fu_header;
const Fragment& fragment = packet->source_fragment;
*bytes_to_send = fragment.length + kFuAHeaderSize;
memcpy(buffer + kFuAHeaderSize, fragment.buffer, fragment.length);
if (packet->last_fragment)
input_fragments_.pop_front();

View File

@ -12,6 +12,7 @@
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H264_H_
#include <deque>
#include <memory>
#include <queue>
#include <string>
@ -34,15 +35,11 @@ class RtpPacketizerH264 : public RtpPacketizer {
const RTPFragmentationHeader* fragmentation) override;
// Get the next payload with H264 payload header.
// buffer is a pointer to where the output will be written.
// bytes_to_send is an output variable that will contain number of bytes
// written to buffer. The parameter last_packet is true for the last packet of
// the frame, false otherwise (i.e., call the function again to get the
// next packet).
// Returns true on success or false if there was no payload to packetize.
bool NextPacket(uint8_t* buffer,
size_t* bytes_to_send,
bool* last_packet) override;
// Write payload and set marker bit of the |packet|.
// The parameter |last_packet| is true for the last packet of the frame, false
// otherwise (i.e., call the function again to get the next packet).
// Returns true on success, false otherwise.
bool NextPacket(RtpPacketToSend* rtp_packet, bool* last_packet) override;
ProtectionType GetProtectionType() override;
@ -89,8 +86,8 @@ class RtpPacketizerH264 : public RtpPacketizer {
void GeneratePackets();
void PacketizeFuA(size_t fragment_index);
size_t PacketizeStapA(size_t fragment_index);
void NextAggregatePacket(uint8_t* buffer, size_t* bytes_to_send);
void NextFragmentPacket(uint8_t* buffer, size_t* bytes_to_send);
void NextAggregatePacket(RtpPacketToSend* rtp_packet);
void NextFragmentPacket(RtpPacketToSend* rtp_packet);
const size_t max_payload_len_;
std::deque<Fragment> input_fragments_;

View File

@ -11,16 +11,22 @@
#include <memory>
#include <vector>
#include "webrtc/base/array_view.h"
#include "webrtc/common_video/h264/h264_common.h"
#include "webrtc/modules/include/module_common_types.h"
#include "webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_format.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "webrtc/test/gmock.h"
#include "webrtc/test/gtest.h"
namespace webrtc {
namespace {
using ::testing::ElementsAreArray;
constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr;
const size_t kMaxPayloadSize = 1200;
const size_t kLengthFieldLength = 2;
@ -46,10 +52,9 @@ enum FuDefs { kSBit = 0x80, kEBit = 0x40, kRBit = 0x20 };
void VerifyFua(size_t fua_index,
const uint8_t* expected_payload,
int offset,
const uint8_t* packet,
size_t length,
rtc::ArrayView<const uint8_t> packet,
const std::vector<size_t>& expected_sizes) {
ASSERT_EQ(expected_sizes[fua_index] + kFuAHeaderSize, length)
ASSERT_EQ(expected_sizes[fua_index] + kFuAHeaderSize, packet.size())
<< "FUA index: " << fua_index;
const uint8_t kFuIndicator = 0x1C; // F=0, NRI=0, Type=28.
EXPECT_EQ(kFuIndicator, packet[0]) << "FUA index: " << fua_index;
@ -65,9 +70,8 @@ void VerifyFua(size_t fua_index,
std::vector<uint8_t> expected_packet_payload(
&expected_payload[offset],
&expected_payload[offset + expected_sizes[fua_index]]);
EXPECT_THAT(
expected_packet_payload,
::testing::ElementsAreArray(&packet[2], expected_sizes[fua_index]))
EXPECT_THAT(expected_packet_payload,
ElementsAreArray(&packet[2], expected_sizes[fua_index]))
<< "FUA index: " << fua_index;
}
@ -88,18 +92,18 @@ void TestFua(size_t frame_size,
kRtpVideoH264, max_payload_size, NULL, kEmptyFrame));
packetizer->SetPayloadData(frame.get(), frame_size, &fragmentation);
std::unique_ptr<uint8_t[]> packet(new uint8_t[max_payload_size]);
size_t length = 0;
RtpPacketToSend packet(kNoExtensions);
ASSERT_LE(max_payload_size, packet.FreeCapacity());
bool last = false;
size_t offset = kNalHeaderSize;
for (size_t i = 0; i < expected_sizes.size(); ++i) {
ASSERT_TRUE(packetizer->NextPacket(packet.get(), &length, &last));
VerifyFua(i, frame.get(), offset, packet.get(), length, expected_sizes);
ASSERT_TRUE(packetizer->NextPacket(&packet, &last));
VerifyFua(i, frame.get(), offset, packet.payload(), expected_sizes);
EXPECT_EQ(i == expected_sizes.size() - 1, last) << "FUA index: " << i;
offset += expected_sizes[i];
}
EXPECT_FALSE(packetizer->NextPacket(packet.get(), &length, &last));
EXPECT_FALSE(packetizer->NextPacket(&packet, &last));
}
size_t GetExpectedNaluOffset(const RTPFragmentationHeader& fragmentation,
@ -117,10 +121,8 @@ size_t GetExpectedNaluOffset(const RTPFragmentationHeader& fragmentation,
void VerifyStapAPayload(const RTPFragmentationHeader& fragmentation,
size_t first_stapa_index,
size_t nalu_index,
const uint8_t* frame,
size_t frame_length,
const uint8_t* packet,
size_t packet_length) {
rtc::ArrayView<const uint8_t> frame,
rtc::ArrayView<const uint8_t> packet) {
size_t expected_payload_offset =
GetExpectedNaluOffset(fragmentation, first_stapa_index, nalu_index) +
kLengthFieldLength;
@ -128,27 +130,22 @@ void VerifyStapAPayload(const RTPFragmentationHeader& fragmentation,
const uint8_t* expected_payload = &frame[offset];
size_t expected_payload_length =
fragmentation.fragmentationLength[nalu_index];
ASSERT_LE(offset + expected_payload_length, frame_length);
ASSERT_LE(expected_payload_offset + expected_payload_length, packet_length);
ASSERT_LE(offset + expected_payload_length, frame.size());
ASSERT_LE(expected_payload_offset + expected_payload_length, packet.size());
std::vector<uint8_t> expected_payload_vector(
expected_payload, &expected_payload[expected_payload_length]);
EXPECT_THAT(expected_payload_vector,
::testing::ElementsAreArray(&packet[expected_payload_offset],
expected_payload_length));
ElementsAreArray(&packet[expected_payload_offset],
expected_payload_length));
}
void VerifySingleNaluPayload(const RTPFragmentationHeader& fragmentation,
size_t nalu_index,
const uint8_t* frame,
size_t frame_length,
const uint8_t* packet,
size_t packet_length) {
std::vector<uint8_t> expected_payload_vector(
&frame[fragmentation.fragmentationOffset[nalu_index]],
&frame[fragmentation.fragmentationOffset[nalu_index] +
fragmentation.fragmentationLength[nalu_index]]);
EXPECT_THAT(expected_payload_vector,
::testing::ElementsAreArray(packet, packet_length));
rtc::ArrayView<const uint8_t> frame,
rtc::ArrayView<const uint8_t> packet) {
auto fragment = frame.subview(fragmentation.fragmentationOffset[nalu_index],
fragmentation.fragmentationLength[nalu_index]);
EXPECT_THAT(packet, ElementsAreArray(fragment.begin(), fragment.end()));
}
} // namespace
@ -161,15 +158,14 @@ TEST(RtpPacketizerH264Test, TestSingleNalu) {
std::unique_ptr<RtpPacketizer> packetizer(
RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kEmptyFrame));
packetizer->SetPayloadData(frame, sizeof(frame), &fragmentation);
uint8_t packet[kMaxPayloadSize] = {0};
size_t length = 0;
RtpPacketToSend packet(kNoExtensions);
ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity());
bool last = false;
ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last));
EXPECT_EQ(2u, length);
ASSERT_TRUE(packetizer->NextPacket(&packet, &last));
EXPECT_EQ(2u, packet.payload_size());
EXPECT_TRUE(last);
VerifySingleNaluPayload(
fragmentation, 0, frame, sizeof(frame), packet, length);
EXPECT_FALSE(packetizer->NextPacket(packet, &length, &last));
VerifySingleNaluPayload(fragmentation, 0, frame, packet.payload());
EXPECT_FALSE(packetizer->NextPacket(&packet, &last));
}
TEST(RtpPacketizerH264Test, TestSingleNaluTwoPackets) {
@ -191,19 +187,18 @@ TEST(RtpPacketizerH264Test, TestSingleNaluTwoPackets) {
RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kEmptyFrame));
packetizer->SetPayloadData(frame, kFrameSize, &fragmentation);
uint8_t packet[kMaxPayloadSize] = {0};
size_t length = 0;
RtpPacketToSend packet(kNoExtensions);
bool last = false;
ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last));
ASSERT_EQ(fragmentation.fragmentationOffset[1], length);
VerifySingleNaluPayload(fragmentation, 0, frame, kFrameSize, packet, length);
ASSERT_TRUE(packetizer->NextPacket(&packet, &last));
ASSERT_EQ(fragmentation.fragmentationOffset[1], packet.payload_size());
VerifySingleNaluPayload(fragmentation, 0, frame, packet.payload());
ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last));
ASSERT_EQ(fragmentation.fragmentationLength[1], length);
VerifySingleNaluPayload(fragmentation, 1, frame, kFrameSize, packet, length);
ASSERT_TRUE(packetizer->NextPacket(&packet, &last));
ASSERT_EQ(fragmentation.fragmentationLength[1], packet.payload_size());
VerifySingleNaluPayload(fragmentation, 1, frame, packet.payload());
EXPECT_TRUE(last);
EXPECT_FALSE(packetizer->NextPacket(packet, &length, &last));
EXPECT_FALSE(packetizer->NextPacket(&packet, &last));
}
TEST(RtpPacketizerH264Test, TestStapA) {
@ -228,18 +223,18 @@ TEST(RtpPacketizerH264Test, TestStapA) {
RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kEmptyFrame));
packetizer->SetPayloadData(frame, kFrameSize, &fragmentation);
uint8_t packet[kMaxPayloadSize] = {0};
size_t length = 0;
RtpPacketToSend packet(kNoExtensions);
ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity());
bool last = false;
ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last));
ASSERT_TRUE(packetizer->NextPacket(&packet, &last));
size_t expected_packet_size =
kNalHeaderSize + 3 * kLengthFieldLength + kFrameSize;
ASSERT_EQ(expected_packet_size, length);
ASSERT_EQ(expected_packet_size, packet.payload_size());
EXPECT_TRUE(last);
for (size_t i = 0; i < fragmentation.fragmentationVectorSize; ++i)
VerifyStapAPayload(fragmentation, 0, i, frame, kFrameSize, packet, length);
VerifyStapAPayload(fragmentation, 0, i, frame, packet.payload());
EXPECT_FALSE(packetizer->NextPacket(packet, &length, &last));
EXPECT_FALSE(packetizer->NextPacket(&packet, &last));
}
TEST(RtpPacketizerH264Test, TestTooSmallForStapAHeaders) {
@ -263,27 +258,27 @@ TEST(RtpPacketizerH264Test, TestTooSmallForStapAHeaders) {
RtpPacketizer::Create(kRtpVideoH264, kMaxPayloadSize, NULL, kEmptyFrame));
packetizer->SetPayloadData(frame, kFrameSize, &fragmentation);
uint8_t packet[kMaxPayloadSize] = {0};
size_t length = 0;
RtpPacketToSend packet(kNoExtensions);
ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity());
bool last = false;
ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last));
ASSERT_TRUE(packetizer->NextPacket(&packet, &last));
size_t expected_packet_size = kNalHeaderSize;
for (size_t i = 0; i < 2; ++i) {
expected_packet_size +=
kLengthFieldLength + fragmentation.fragmentationLength[i];
}
ASSERT_EQ(expected_packet_size, length);
ASSERT_EQ(expected_packet_size, packet.payload_size());
EXPECT_FALSE(last);
for (size_t i = 0; i < 2; ++i)
VerifyStapAPayload(fragmentation, 0, i, frame, kFrameSize, packet, length);
VerifyStapAPayload(fragmentation, 0, i, frame, packet.payload());
ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last));
ASSERT_TRUE(packetizer->NextPacket(&packet, &last));
expected_packet_size = fragmentation.fragmentationLength[2];
ASSERT_EQ(expected_packet_size, length);
ASSERT_EQ(expected_packet_size, packet.payload_size());
EXPECT_TRUE(last);
VerifySingleNaluPayload(fragmentation, 2, frame, kFrameSize, packet, length);
VerifySingleNaluPayload(fragmentation, 2, frame, packet.payload());
EXPECT_FALSE(packetizer->NextPacket(packet, &length, &last));
EXPECT_FALSE(packetizer->NextPacket(&packet, &last));
}
TEST(RtpPacketizerH264Test, TestMixedStapA_FUA) {
@ -315,26 +310,26 @@ TEST(RtpPacketizerH264Test, TestMixedStapA_FUA) {
std::vector<size_t> fua_sizes;
fua_sizes.push_back(1100);
fua_sizes.push_back(1099);
uint8_t packet[kMaxPayloadSize] = {0};
size_t length = 0;
RtpPacketToSend packet(kNoExtensions);
ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity());
bool last = false;
int fua_offset = kNalHeaderSize;
for (size_t i = 0; i < 2; ++i) {
ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last));
VerifyFua(i, frame, fua_offset, packet, length, fua_sizes);
ASSERT_TRUE(packetizer->NextPacket(&packet, &last));
VerifyFua(i, frame, fua_offset, packet.payload(), fua_sizes);
EXPECT_FALSE(last);
fua_offset += fua_sizes[i];
}
// Then expecting one STAP-A packet with two nal units.
ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last));
ASSERT_TRUE(packetizer->NextPacket(&packet, &last));
size_t expected_packet_size =
kNalHeaderSize + 2 * kLengthFieldLength + 2 * kStapANaluSize;
ASSERT_EQ(expected_packet_size, length);
ASSERT_EQ(expected_packet_size, packet.payload_size());
EXPECT_TRUE(last);
for (size_t i = 1; i < fragmentation.fragmentationVectorSize; ++i)
VerifyStapAPayload(fragmentation, 1, i, frame, kFrameSize, packet, length);
VerifyStapAPayload(fragmentation, 1, i, frame, packet.payload());
EXPECT_FALSE(packetizer->NextPacket(packet, &length, &last));
EXPECT_FALSE(packetizer->NextPacket(&packet, &last));
}
TEST(RtpPacketizerH264Test, TestFUAOddSize) {
@ -429,24 +424,20 @@ TEST_F(RtpPacketizerH264TestSpsRewriting, FuASps) {
&fragmentation_header_);
bool last_packet = true;
uint8_t buffer[sizeof(kOriginalSps) + kHeaderOverhead] = {};
size_t num_bytes = 0;
RtpPacketToSend packet(kNoExtensions);
ASSERT_LE(sizeof(kOriginalSps) + kHeaderOverhead, packet.FreeCapacity());
EXPECT_TRUE(packetizer_->NextPacket(buffer, &num_bytes, &last_packet));
EXPECT_TRUE(packetizer_->NextPacket(&packet, &last_packet));
size_t offset = H264::kNaluTypeSize;
size_t length = num_bytes - kFuAHeaderSize;
std::vector<uint8_t> expected_payload(&kRewrittenSps[offset],
&kRewrittenSps[offset + length]);
EXPECT_THAT(expected_payload,
::testing::ElementsAreArray(&buffer[kFuAHeaderSize], length));
size_t length = packet.payload_size() - kFuAHeaderSize;
EXPECT_THAT(packet.payload().subview(kFuAHeaderSize),
ElementsAreArray(&kRewrittenSps[offset], length));
offset += length;
EXPECT_TRUE(packetizer_->NextPacket(buffer, &num_bytes, &last_packet));
length = num_bytes - kFuAHeaderSize;
expected_payload = std::vector<uint8_t>(&kRewrittenSps[offset],
&kRewrittenSps[offset + length]);
EXPECT_THAT(expected_payload,
::testing::ElementsAreArray(&buffer[kFuAHeaderSize], length));
EXPECT_TRUE(packetizer_->NextPacket(&packet, &last_packet));
length = packet.payload_size() - kFuAHeaderSize;
EXPECT_THAT(packet.payload().subview(kFuAHeaderSize),
ElementsAreArray(&kRewrittenSps[offset], length));
offset += length;
EXPECT_EQ(offset, sizeof(kRewrittenSps));
@ -467,18 +458,14 @@ TEST_F(RtpPacketizerH264TestSpsRewriting, StapASps) {
&fragmentation_header_);
bool last_packet = true;
uint8_t buffer[kExpectedTotalSize + kHeaderOverhead] = {};
size_t num_bytes = 0;
RtpPacketToSend packet(kNoExtensions);
ASSERT_LE(kExpectedTotalSize + kHeaderOverhead, packet.FreeCapacity());
EXPECT_TRUE(packetizer_->NextPacket(buffer, &num_bytes, &last_packet));
EXPECT_EQ(kExpectedTotalSize, num_bytes);
std::vector<uint8_t> expected_payload(kRewrittenSps,
&kRewrittenSps[sizeof(kRewrittenSps)]);
EXPECT_THAT(expected_payload,
::testing::ElementsAreArray(
&buffer[H264::kNaluTypeSize + kLengthFieldLength],
sizeof(kRewrittenSps)));
EXPECT_TRUE(packetizer_->NextPacket(&packet, &last_packet));
EXPECT_EQ(kExpectedTotalSize, packet.payload_size());
EXPECT_THAT(packet.payload().subview(H264::kNaluTypeSize + kLengthFieldLength,
sizeof(kRewrittenSps)),
ElementsAreArray(kRewrittenSps));
}
class RtpDepacketizerH264Test : public ::testing::Test {

View File

@ -13,6 +13,7 @@
#include "webrtc/base/logging.h"
#include "webrtc/modules/include/module_common_types.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
namespace webrtc {
@ -45,32 +46,33 @@ void RtpPacketizerGeneric::SetPayloadData(
generic_header_ = RtpFormatVideoGeneric::kFirstPacketBit;
}
bool RtpPacketizerGeneric::NextPacket(uint8_t* buffer,
size_t* bytes_to_send,
bool RtpPacketizerGeneric::NextPacket(RtpPacketToSend* packet,
bool* last_packet) {
RTC_DCHECK(packet);
RTC_DCHECK(last_packet);
if (payload_size_ < payload_length_) {
payload_length_ = payload_size_;
}
payload_size_ -= payload_length_;
*bytes_to_send = payload_length_ + kGenericHeaderLength;
assert(payload_length_ <= max_payload_len_);
RTC_DCHECK_LE(payload_length_, max_payload_len_);
uint8_t* out_ptr = buffer;
uint8_t* out_ptr =
packet->AllocatePayload(kGenericHeaderLength + payload_length_);
// Put generic header in packet
if (frame_type_ == kVideoFrameKey) {
generic_header_ |= RtpFormatVideoGeneric::kKeyFrameBit;
}
*out_ptr++ = generic_header_;
out_ptr[0] = generic_header_;
// Remove first-packet bit, following packets are intermediate
generic_header_ &= ~RtpFormatVideoGeneric::kFirstPacketBit;
// Put payload in packet
memcpy(out_ptr, payload_data_, payload_length_);
memcpy(out_ptr + kGenericHeaderLength, payload_data_, payload_length_);
payload_data_ += payload_length_;
*last_packet = payload_size_ <= 0;
packet->SetMarker(*last_packet);
return true;
}

View File

@ -36,15 +36,11 @@ class RtpPacketizerGeneric : public RtpPacketizer {
const RTPFragmentationHeader* fragmentation) override;
// Get the next payload with generic payload header.
// buffer is a pointer to where the output will be written.
// bytes_to_send is an output variable that will contain number of bytes
// written to buffer. The parameter last_packet is true for the last packet of
// the frame, false otherwise (i.e., call the function again to get the
// next packet).
// Returns true on success or false if there was no payload to packetize.
bool NextPacket(uint8_t* buffer,
size_t* bytes_to_send,
bool* last_packet) override;
// Write payload and set marker bit of the |packet|.
// The parameter |last_packet| is true for the last packet of the frame, false
// otherwise (i.e., call the function again to get the next packet).
// Returns true on success, false otherwise.
bool NextPacket(RtpPacketToSend* packet, bool* last_packet) override;
ProtectionType GetProtectionType() override;

View File

@ -17,6 +17,7 @@
#include "webrtc/base/logging.h"
#include "webrtc/modules/rtp_rtcp/source/vp8_partition_aggregator.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
namespace webrtc {
namespace {
@ -197,9 +198,9 @@ void RtpPacketizerVp8::SetPayloadData(
}
}
bool RtpPacketizerVp8::NextPacket(uint8_t* buffer,
size_t* bytes_to_send,
bool* last_packet) {
bool RtpPacketizerVp8::NextPacket(RtpPacketToSend* packet, bool* last_packet) {
RTC_DCHECK(packet);
RTC_DCHECK(last_packet);
if (!packets_calculated_) {
int ret = 0;
if (aggr_mode_ == kAggrPartitions && balance_) {
@ -217,13 +218,14 @@ bool RtpPacketizerVp8::NextPacket(uint8_t* buffer,
InfoStruct packet_info = packets_.front();
packets_.pop();
uint8_t* buffer = packet->AllocatePayload(max_payload_len_);
int bytes = WriteHeaderAndPayload(packet_info, buffer, max_payload_len_);
if (bytes < 0) {
return false;
}
*bytes_to_send = static_cast<size_t>(bytes);
packet->SetPayloadSize(bytes);
*last_packet = packets_.empty();
packet->SetMarker(*last_packet);
return true;
}

View File

@ -65,19 +65,11 @@ class RtpPacketizerVp8 : public RtpPacketizer {
const RTPFragmentationHeader* fragmentation) override;
// Get the next payload with VP8 payload header.
// max_payload_len limits the sum length of payload and VP8 payload header.
// buffer is a pointer to where the output will be written.
// bytes_to_send is an output variable that will contain number of bytes
// written to buffer. Parameter last_packet is true for the last packet of
// the frame, false otherwise (i.e., call the function again to get the
// next packet).
// For the kStrict and kAggregate mode: returns the partition index from which
// the first payload byte in the packet is taken, with the first partition
// having index 0; returns negative on error.
// For the kEqualSize mode: returns 0 on success, return negative on error.
bool NextPacket(uint8_t* buffer,
size_t* bytes_to_send,
bool* last_packet) override;
// Write payload and set marker bit of the |packet|.
// The parameter |last_packet| is true for the last packet of the frame, false
// otherwise (i.e., call the function again to get the next packet).
// Returns true on success, false otherwise.
bool NextPacket(RtpPacketToSend* packet, bool* last_packet) override;
ProtectionType GetProtectionType() override;

View File

@ -17,22 +17,22 @@ namespace webrtc {
namespace test {
constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr;
RtpFormatVp8TestHelper::RtpFormatVp8TestHelper(const RTPVideoHeaderVP8* hdr)
: payload_data_(NULL),
buffer_(NULL),
: packet_(kNoExtensions),
payload_data_(NULL),
data_ptr_(NULL),
fragmentation_(NULL),
hdr_info_(hdr),
payload_start_(0),
payload_size_(0),
buffer_size_(0),
sloppy_partitioning_(false),
inited_(false) {}
RtpFormatVp8TestHelper::~RtpFormatVp8TestHelper() {
delete fragmentation_;
delete [] payload_data_;
delete [] buffer_;
}
bool RtpFormatVp8TestHelper::Init(const size_t* partition_sizes,
@ -45,9 +45,7 @@ bool RtpFormatVp8TestHelper::Init(const size_t* partition_sizes,
for (size_t p = 0; p < num_partitions; ++p) {
payload_size_ += partition_sizes[p];
}
buffer_size_ = payload_size_ + 6; // Add space for payload descriptor.
payload_data_ = new uint8_t[payload_size_];
buffer_ = new uint8_t[buffer_size_];
size_t j = 0;
// Loop through the partitions again.
for (size_t p = 0; p < num_partitions; ++p) {
@ -70,15 +68,13 @@ void RtpFormatVp8TestHelper::GetAllPacketsAndCheck(
const bool* expected_frag_start,
size_t expected_num_packets) {
ASSERT_TRUE(inited_);
size_t send_bytes = 0;
bool last = false;
for (size_t i = 0; i < expected_num_packets; ++i) {
std::ostringstream ss;
ss << "Checking packet " << i;
SCOPED_TRACE(ss.str());
EXPECT_TRUE(packetizer->NextPacket(buffer_, &send_bytes, &last));
CheckPacket(send_bytes, expected_sizes[i], last,
expected_frag_start[i]);
EXPECT_TRUE(packetizer->NextPacket(&packet_, &last));
CheckPacket(expected_sizes[i], last, expected_frag_start[i]);
}
EXPECT_TRUE(last);
}
@ -127,67 +123,68 @@ void RtpFormatVp8TestHelper::GetAllPacketsAndCheck(
void RtpFormatVp8TestHelper::CheckHeader(bool frag_start) {
payload_start_ = 1;
EXPECT_BIT_EQ(buffer_[0], 6, 0); // Check reserved bit.
rtc::ArrayView<const uint8_t> buffer = packet_.payload();
EXPECT_BIT_EQ(buffer[0], 6, 0); // Check reserved bit.
if (hdr_info_->pictureId != kNoPictureId ||
hdr_info_->temporalIdx != kNoTemporalIdx ||
hdr_info_->tl0PicIdx != kNoTl0PicIdx ||
hdr_info_->keyIdx != kNoKeyIdx) {
EXPECT_BIT_X_EQ(buffer_[0], 1);
EXPECT_BIT_X_EQ(buffer[0], 1);
++payload_start_;
CheckPictureID();
CheckTl0PicIdx();
CheckTIDAndKeyIdx();
} else {
EXPECT_BIT_X_EQ(buffer_[0], 0);
EXPECT_BIT_X_EQ(buffer[0], 0);
}
EXPECT_BIT_N_EQ(buffer_[0], hdr_info_->nonReference ? 1 : 0);
EXPECT_BIT_S_EQ(buffer_[0], frag_start ? 1 : 0);
EXPECT_BIT_N_EQ(buffer[0], hdr_info_->nonReference ? 1 : 0);
EXPECT_BIT_S_EQ(buffer[0], frag_start ? 1 : 0);
// Check partition index.
if (!sloppy_partitioning_) {
// The test payload data is constructed such that the payload value is the
// same as the partition index.
EXPECT_EQ(buffer_[0] & 0x0F, buffer_[payload_start_]);
EXPECT_EQ(buffer[0] & 0x0F, buffer[payload_start_]);
} else {
// Partition should be set to 0.
EXPECT_EQ(buffer_[0] & 0x0F, 0);
EXPECT_EQ(buffer[0] & 0x0F, 0);
}
}
// Verify that the I bit and the PictureID field are both set in accordance
// with the information in hdr_info_->pictureId.
void RtpFormatVp8TestHelper::CheckPictureID() {
auto buffer = packet_.payload();
if (hdr_info_->pictureId != kNoPictureId) {
EXPECT_BIT_I_EQ(buffer_[1], 1);
EXPECT_BIT_I_EQ(buffer[1], 1);
if (hdr_info_->pictureId > 0x7F) {
EXPECT_BIT_EQ(buffer_[payload_start_], 7, 1);
EXPECT_EQ(buffer_[payload_start_] & 0x7F,
EXPECT_BIT_EQ(buffer[payload_start_], 7, 1);
EXPECT_EQ(buffer[payload_start_] & 0x7F,
(hdr_info_->pictureId >> 8) & 0x7F);
EXPECT_EQ(buffer_[payload_start_ + 1],
hdr_info_->pictureId & 0xFF);
EXPECT_EQ(buffer[payload_start_ + 1], hdr_info_->pictureId & 0xFF);
payload_start_ += 2;
} else {
EXPECT_BIT_EQ(buffer_[payload_start_], 7, 0);
EXPECT_EQ(buffer_[payload_start_] & 0x7F,
(hdr_info_->pictureId) & 0x7F);
EXPECT_BIT_EQ(buffer[payload_start_], 7, 0);
EXPECT_EQ(buffer[payload_start_] & 0x7F, (hdr_info_->pictureId) & 0x7F);
payload_start_ += 1;
}
} else {
EXPECT_BIT_I_EQ(buffer_[1], 0);
EXPECT_BIT_I_EQ(buffer[1], 0);
}
}
// Verify that the L bit and the TL0PICIDX field are both set in accordance
// with the information in hdr_info_->tl0PicIdx.
void RtpFormatVp8TestHelper::CheckTl0PicIdx() {
auto buffer = packet_.payload();
if (hdr_info_->tl0PicIdx != kNoTl0PicIdx) {
EXPECT_BIT_L_EQ(buffer_[1], 1);
EXPECT_EQ(buffer_[payload_start_], hdr_info_->tl0PicIdx);
EXPECT_BIT_L_EQ(buffer[1], 1);
EXPECT_EQ(buffer[payload_start_], hdr_info_->tl0PicIdx);
++payload_start_;
} else {
EXPECT_BIT_L_EQ(buffer_[1], 0);
EXPECT_BIT_L_EQ(buffer[1], 0);
}
}
@ -195,36 +192,39 @@ void RtpFormatVp8TestHelper::CheckTl0PicIdx() {
// field are all set in accordance with the information in
// hdr_info_->temporalIdx and hdr_info_->keyIdx, respectively.
void RtpFormatVp8TestHelper::CheckTIDAndKeyIdx() {
auto buffer = packet_.payload();
if (hdr_info_->temporalIdx == kNoTemporalIdx &&
hdr_info_->keyIdx == kNoKeyIdx) {
EXPECT_BIT_T_EQ(buffer_[1], 0);
EXPECT_BIT_K_EQ(buffer_[1], 0);
EXPECT_BIT_T_EQ(buffer[1], 0);
EXPECT_BIT_K_EQ(buffer[1], 0);
return;
}
if (hdr_info_->temporalIdx != kNoTemporalIdx) {
EXPECT_BIT_T_EQ(buffer_[1], 1);
EXPECT_TID_EQ(buffer_[payload_start_], hdr_info_->temporalIdx);
EXPECT_BIT_Y_EQ(buffer_[payload_start_], hdr_info_->layerSync ? 1 : 0);
EXPECT_BIT_T_EQ(buffer[1], 1);
EXPECT_TID_EQ(buffer[payload_start_], hdr_info_->temporalIdx);
EXPECT_BIT_Y_EQ(buffer[payload_start_], hdr_info_->layerSync ? 1 : 0);
} else {
EXPECT_BIT_T_EQ(buffer_[1], 0);
EXPECT_TID_EQ(buffer_[payload_start_], 0);
EXPECT_BIT_Y_EQ(buffer_[payload_start_], 0);
EXPECT_BIT_T_EQ(buffer[1], 0);
EXPECT_TID_EQ(buffer[payload_start_], 0);
EXPECT_BIT_Y_EQ(buffer[payload_start_], 0);
}
if (hdr_info_->keyIdx != kNoKeyIdx) {
EXPECT_BIT_K_EQ(buffer_[1], 1);
EXPECT_KEYIDX_EQ(buffer_[payload_start_], hdr_info_->keyIdx);
EXPECT_BIT_K_EQ(buffer[1], 1);
EXPECT_KEYIDX_EQ(buffer[payload_start_], hdr_info_->keyIdx);
} else {
EXPECT_BIT_K_EQ(buffer_[1], 0);
EXPECT_KEYIDX_EQ(buffer_[payload_start_], 0);
EXPECT_BIT_K_EQ(buffer[1], 0);
EXPECT_KEYIDX_EQ(buffer[payload_start_], 0);
}
++payload_start_;
}
// Verify that the payload (i.e., after the headers) of the packet stored in
// buffer_ is identical to the expected (as found in data_ptr_).
void RtpFormatVp8TestHelper::CheckPayload(size_t payload_end) {
void RtpFormatVp8TestHelper::CheckPayload() {
auto buffer = packet_.payload();
size_t payload_end = buffer.size();
for (size_t i = payload_start_; i < payload_end; ++i, ++data_ptr_)
EXPECT_EQ(buffer_[i], *data_ptr_);
EXPECT_EQ(buffer[i], *data_ptr_);
}
// Verify that the input variable "last" agrees with the position of data_ptr_.
@ -236,13 +236,12 @@ void RtpFormatVp8TestHelper::CheckLast(bool last) const {
// Verify the contents of a packet. Check the length versus expected_bytes,
// the header, payload, and "last" flag.
void RtpFormatVp8TestHelper::CheckPacket(size_t send_bytes,
size_t expect_bytes,
void RtpFormatVp8TestHelper::CheckPacket(size_t expect_bytes,
bool last,
bool frag_start) {
EXPECT_EQ(expect_bytes, send_bytes);
EXPECT_EQ(expect_bytes, packet_.payload_size());
CheckHeader(frag_start);
CheckPayload(send_bytes);
CheckPayload();
CheckLast(last);
}

View File

@ -21,6 +21,7 @@
#include "webrtc/base/constructormagic.h"
#include "webrtc/modules/include/module_common_types.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "webrtc/typedefs.h"
namespace webrtc {
@ -41,7 +42,10 @@ class RtpFormatVp8TestHelper {
uint8_t* payload_data() const { return payload_data_; }
size_t payload_size() const { return payload_size_; }
RTPFragmentationHeader* fragmentation() const { return fragmentation_; }
size_t buffer_size() const { return buffer_size_; }
size_t buffer_size() const {
static constexpr size_t kVp8PayloadDescriptorMaxSize = 6;
return payload_size_ + kVp8PayloadDescriptorMaxSize;
}
void set_sloppy_partitioning(bool value) { sloppy_partitioning_ = value; }
private:
@ -49,19 +53,17 @@ class RtpFormatVp8TestHelper {
void CheckPictureID();
void CheckTl0PicIdx();
void CheckTIDAndKeyIdx();
void CheckPayload(size_t payload_end);
void CheckPayload();
void CheckLast(bool last) const;
void CheckPacket(size_t send_bytes, size_t expect_bytes, bool last,
bool frag_start);
void CheckPacket(size_t expect_bytes, bool last, bool frag_start);
RtpPacketToSend packet_;
uint8_t* payload_data_;
uint8_t* buffer_;
uint8_t* data_ptr_;
RTPFragmentationHeader* fragmentation_;
const RTPVideoHeaderVP8* hdr_info_;
int payload_start_;
size_t payload_size_;
size_t buffer_size_;
bool sloppy_partitioning_;
bool inited_;

View File

@ -12,6 +12,7 @@
#include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "webrtc/test/gmock.h"
#include "webrtc/test/gtest.h"
#include "webrtc/typedefs.h"
@ -22,6 +23,11 @@
namespace webrtc {
namespace {
using ::testing::ElementsAreArray;
using ::testing::make_tuple;
constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr;
// Payload descriptor
// 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+
@ -100,8 +106,8 @@ TEST_F(RtpPacketizerVp8Test, TestStrictMode) {
ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
hdr_info_.pictureId = 200; // > 0x7F should produce 2-byte PictureID.
const size_t kMaxSize = 13;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kStrict);
const size_t kMaxPayloadSize = 13;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kStrict);
packetizer.SetPayloadData(helper_->payload_data(),
helper_->payload_size(),
helper_->fragmentation());
@ -131,8 +137,8 @@ TEST_F(RtpPacketizerVp8Test, DISABLED_TestStrictEqualTightPartitions) {
ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
hdr_info_.pictureId = 200; // > 0x7F should produce 2-byte PictureID.
const int kMaxSize = 14;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kStrict);
const int kMaxPayloadSize = 14;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kStrict);
packetizer.SetPayloadData(helper_->payload_data(), helper_->payload_size(),
helper_->fragmentation());
@ -154,8 +160,8 @@ TEST_F(RtpPacketizerVp8Test, TestAggregateMode) {
ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
hdr_info_.pictureId = 20; // <= 0x7F should produce 1-byte PictureID.
const size_t kMaxSize = 25;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kAggregate);
const size_t kMaxPayloadSize = 25;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kAggregate);
packetizer.SetPayloadData(helper_->payload_data(),
helper_->payload_size(),
helper_->fragmentation());
@ -181,8 +187,8 @@ TEST_F(RtpPacketizerVp8Test, TestAggregateModeManyPartitions1) {
ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
hdr_info_.pictureId = 20; // <= 0x7F should produce 1-byte PictureID.
const size_t kMaxSize = 1500;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kAggregate);
const size_t kMaxPayloadSize = 1000;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kAggregate);
packetizer.SetPayloadData(helper_->payload_data(),
helper_->payload_size(),
helper_->fragmentation());
@ -208,8 +214,8 @@ TEST_F(RtpPacketizerVp8Test, TestAggregateModeManyPartitions2) {
ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
hdr_info_.pictureId = 20; // <= 0x7F should produce 1-byte PictureID.
const size_t kMaxSize = 1500;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kAggregate);
const size_t kMaxPayloadSize = 1000;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kAggregate);
packetizer.SetPayloadData(helper_->payload_data(),
helper_->payload_size(),
helper_->fragmentation());
@ -235,8 +241,8 @@ TEST_F(RtpPacketizerVp8Test, TestAggregateModeTwoLargePartitions) {
ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
hdr_info_.pictureId = 20; // <= 0x7F should produce 1-byte PictureID.
const size_t kMaxSize = 1460;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kAggregate);
const size_t kMaxPayloadSize = 1460;
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kAggregate);
packetizer.SetPayloadData(helper_->payload_data(),
helper_->payload_size(),
helper_->fragmentation());
@ -262,9 +268,9 @@ TEST_F(RtpPacketizerVp8Test, TestEqualSizeModeFallback) {
const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector);
ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
hdr_info_.pictureId = 200; // > 0x7F should produce 2-byte PictureID
const size_t kMaxSize = 12; // Small enough to produce 4 packets.
RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize);
hdr_info_.pictureId = 200; // > 0x7F should produce 2-byte PictureID
const size_t kMaxPayloadSize = 12; // Small enough to produce 4 packets.
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize);
packetizer.SetPayloadData(
helper_->payload_data(), helper_->payload_size(), NULL);
@ -292,8 +298,8 @@ TEST_F(RtpPacketizerVp8Test, TestNonReferenceBit) {
ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
hdr_info_.nonReference = true;
const size_t kMaxSize = 25; // Small enough to produce two packets.
RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize);
const size_t kMaxPayloadSize = 25; // Small enough to produce two packets.
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize);
packetizer.SetPayloadData(
helper_->payload_data(), helper_->payload_size(), NULL);
@ -323,9 +329,9 @@ TEST_F(RtpPacketizerVp8Test, TestTl0PicIdxAndTID) {
hdr_info_.tl0PicIdx = 117;
hdr_info_.temporalIdx = 2;
hdr_info_.layerSync = true;
// kMaxSize is only limited by allocated buffer size.
const size_t kMaxSize = helper_->buffer_size();
RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kAggregate);
// kMaxPayloadSize is only limited by allocated buffer size.
const size_t kMaxPayloadSize = helper_->buffer_size();
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kAggregate);
packetizer.SetPayloadData(helper_->payload_data(),
helper_->payload_size(),
helper_->fragmentation());
@ -352,9 +358,9 @@ TEST_F(RtpPacketizerVp8Test, TestKeyIdx) {
ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
hdr_info_.keyIdx = 17;
// kMaxSize is only limited by allocated buffer size.
const size_t kMaxSize = helper_->buffer_size();
RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kAggregate);
// kMaxPayloadSize is only limited by allocated buffer size.
const size_t kMaxPayloadSize = helper_->buffer_size();
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kAggregate);
packetizer.SetPayloadData(helper_->payload_data(),
helper_->payload_size(),
helper_->fragmentation());
@ -382,9 +388,9 @@ TEST_F(RtpPacketizerVp8Test, TestTIDAndKeyIdx) {
hdr_info_.temporalIdx = 1;
hdr_info_.keyIdx = 5;
// kMaxSize is only limited by allocated buffer size.
const size_t kMaxSize = helper_->buffer_size();
RtpPacketizerVp8 packetizer(hdr_info_, kMaxSize, kAggregate);
// kMaxPayloadSize is only limited by allocated buffer size.
const size_t kMaxPayloadSize = helper_->buffer_size();
RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kAggregate);
packetizer.SetPayloadData(helper_->payload_data(),
helper_->payload_size(),
helper_->fragmentation());
@ -432,6 +438,7 @@ TEST_F(RtpDepacketizerVp8Test, BasicHeader) {
ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet)));
ExpectPacket(
&payload, packet + kHeaderLength, sizeof(packet) - kHeaderLength);
EXPECT_EQ(kVideoFrameDelta, payload.frame_type);
EXPECT_EQ(kRtpVideoVp8, payload.type.Video.codec);
VerifyBasicHeader(&payload.type, 0, 1, 4);
@ -564,7 +571,7 @@ TEST_F(RtpDepacketizerVp8Test, TooShortHeader) {
TEST_F(RtpDepacketizerVp8Test, TestWithPacketizer) {
const uint8_t kHeaderLength = 5;
uint8_t data[10] = {0};
uint8_t packet[20] = {0};
RtpPacketToSend packet(kNoExtensions);
RTPVideoHeaderVP8 input_header;
input_header.nonReference = true;
input_header.pictureId = 300;
@ -575,14 +582,16 @@ TEST_F(RtpDepacketizerVp8Test, TestWithPacketizer) {
RtpPacketizerVp8 packetizer(input_header, 20);
packetizer.SetPayloadData(data, 10, NULL);
bool last;
size_t send_bytes;
ASSERT_TRUE(packetizer.NextPacket(packet, &send_bytes, &last));
ASSERT_TRUE(last);
RtpDepacketizer::ParsedPayload payload;
ASSERT_TRUE(packetizer.NextPacket(&packet, &last));
EXPECT_TRUE(last);
EXPECT_TRUE(packet.Marker());
ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet)));
ExpectPacket(
&payload, packet + kHeaderLength, sizeof(packet) - kHeaderLength);
auto rtp_payload = packet.payload();
RtpDepacketizer::ParsedPayload payload;
ASSERT_TRUE(
depacketizer_->Parse(&payload, rtp_payload.data(), rtp_payload.size()));
auto vp8_payload = rtp_payload.subview(kHeaderLength);
ExpectPacket(&payload, vp8_payload.data(), vp8_payload.size());
EXPECT_EQ(kVideoFrameKey, payload.frame_type);
EXPECT_EQ(kRtpVideoVp8, payload.type.Video.codec);
VerifyBasicHeader(&payload.type, 1, 1, 0);

View File

@ -18,6 +18,7 @@
#include "webrtc/base/bitbuffer.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
#define RETURN_FALSE_ON_ERROR(x) \
if (!(x)) { \
@ -545,21 +546,22 @@ void RtpPacketizerVp9::GeneratePackets() {
assert(bytes_processed == payload_size_);
}
bool RtpPacketizerVp9::NextPacket(uint8_t* buffer,
size_t* bytes_to_send,
bool* last_packet) {
bool RtpPacketizerVp9::NextPacket(RtpPacketToSend* packet, bool* last_packet) {
RTC_DCHECK(packet);
RTC_DCHECK(last_packet);
if (packets_.empty()) {
return false;
}
PacketInfo packet_info = packets_.front();
packets_.pop();
if (!WriteHeaderAndPayload(packet_info, buffer, bytes_to_send)) {
if (!WriteHeaderAndPayload(packet_info, packet)) {
return false;
}
*last_packet =
packets_.empty() && (hdr_.spatial_idx == kNoSpatialIdx ||
hdr_.spatial_idx == hdr_.num_spatial_layers - 1);
*last_packet = packets_.empty();
packet->SetMarker(packets_.empty() &&
(hdr_.spatial_idx == kNoSpatialIdx ||
hdr_.spatial_idx == hdr_.num_spatial_layers - 1));
return true;
}
@ -600,8 +602,9 @@ bool RtpPacketizerVp9::NextPacket(uint8_t* buffer,
// +-+-+-+-+-+-+-+-+
bool RtpPacketizerVp9::WriteHeaderAndPayload(const PacketInfo& packet_info,
uint8_t* buffer,
size_t* bytes_to_send) const {
RtpPacketToSend* packet) const {
uint8_t* buffer = packet->AllocatePayload(max_payload_length_);
RTC_DCHECK(buffer);
size_t header_length;
if (!WriteHeader(packet_info, buffer, &header_length))
return false;
@ -610,7 +613,7 @@ bool RtpPacketizerVp9::WriteHeaderAndPayload(const PacketInfo& packet_info,
memcpy(&buffer[header_length],
&payload_[packet_info.payload_start_pos], packet_info.size);
*bytes_to_send = header_length + packet_info.size;
packet->SetPayloadSize(header_length + packet_info.size);
return true;
}

View File

@ -49,15 +49,11 @@ class RtpPacketizerVp9 : public RtpPacketizer {
const RTPFragmentationHeader* fragmentation) override;
// Gets the next payload with VP9 payload header.
// |buffer| is a pointer to where the output will be written.
// |bytes_to_send| is an output variable that will contain number of bytes
// written to buffer.
// |last_packet| is true for the last packet of the frame, false otherwise
// (i.e. call the function again to get the next packet).
// Write payload and set marker bit of the |packet|.
// The parameter |last_packet| is true for the last packet of the frame, false
// otherwise (i.e., call the function again to get the next packet).
// Returns true on success, false otherwise.
bool NextPacket(uint8_t* buffer,
size_t* bytes_to_send,
bool* last_packet) override;
bool NextPacket(RtpPacketToSend* packet, bool* last_packet) override;
typedef struct {
size_t payload_start_pos;
@ -76,8 +72,7 @@ class RtpPacketizerVp9 : public RtpPacketizer {
// |bytes_to_send| contains the number of written bytes to the buffer.
// Returns true on success, false otherwise.
bool WriteHeaderAndPayload(const PacketInfo& packet_info,
uint8_t* buffer,
size_t* bytes_to_send) const;
RtpPacketToSend* packet) const;
// Writes payload descriptor header to |buffer|.
// Returns true on success, false otherwise.

View File

@ -12,6 +12,7 @@
#include <vector>
#include "webrtc/modules/rtp_rtcp/source/rtp_format_vp9.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "webrtc/test/gmock.h"
#include "webrtc/test/gtest.h"
#include "webrtc/typedefs.h"
@ -123,12 +124,15 @@ void ParseAndCheckPacket(const uint8_t* packet,
class RtpPacketizerVp9Test : public ::testing::Test {
protected:
RtpPacketizerVp9Test() {}
static constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr;
static constexpr size_t kMaxPacketSize = 1200;
RtpPacketizerVp9Test() : packet_(kNoExtensions, kMaxPacketSize) {}
virtual void SetUp() {
expected_.InitRTPVideoHeaderVP9();
}
std::unique_ptr<uint8_t[]> packet_;
RtpPacketToSend packet_;
std::unique_ptr<uint8_t[]> payload_;
size_t payload_size_;
size_t payload_pos_;
@ -142,9 +146,6 @@ class RtpPacketizerVp9Test : public ::testing::Test {
payload_pos_ = 0;
packetizer_.reset(new RtpPacketizerVp9(expected_, packet_size));
packetizer_->SetPayloadData(payload_.get(), payload_size_, NULL);
const int kMaxPayloadDescriptorLength = 100;
packet_.reset(new uint8_t[payload_size_ + kMaxPayloadDescriptorLength]);
}
void CheckPayload(const uint8_t* packet,
@ -161,20 +162,22 @@ class RtpPacketizerVp9Test : public ::testing::Test {
const size_t* expected_sizes,
size_t expected_num_packets) {
ASSERT_TRUE(packetizer_.get() != NULL);
size_t length = 0;
bool last = false;
if (expected_num_packets == 0) {
EXPECT_FALSE(packetizer_->NextPacket(packet_.get(), &length, &last));
EXPECT_FALSE(packetizer_->NextPacket(&packet_, &last));
return;
}
for (size_t i = 0; i < expected_num_packets; ++i) {
EXPECT_TRUE(packetizer_->NextPacket(packet_.get(), &length, &last));
EXPECT_EQ(expected_sizes[i], length);
EXPECT_TRUE(packetizer_->NextPacket(&packet_, &last));
auto rtp_payload = packet_.payload();
EXPECT_EQ(expected_sizes[i], rtp_payload.size());
RTPVideoHeaderVP9 hdr = expected_;
hdr.beginning_of_frame = (i == 0);
hdr.end_of_frame = last;
ParseAndCheckPacket(packet_.get(), hdr, expected_hdr_sizes[i], length);
CheckPayload(packet_.get(), expected_hdr_sizes[i], length, last);
ParseAndCheckPacket(rtp_payload.data(), hdr, expected_hdr_sizes[i],
rtp_payload.size());
CheckPayload(rtp_payload.data(), expected_hdr_sizes[i],
rtp_payload.size(), last);
}
EXPECT_TRUE(last);
}
@ -429,6 +432,51 @@ TEST_F(RtpPacketizerVp9Test, TestSsData) {
CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
}
TEST_F(RtpPacketizerVp9Test, TestOnlyHighestSpatialLayerSetMarker) {
const size_t kFrameSize = 10;
const size_t kPacketSize = 9; // 2 packet per frame.
const uint8_t kFrame[kFrameSize] = {7};
const RTPFragmentationHeader* kNoFragmentation = nullptr;
RTPVideoHeaderVP9 vp9_header;
vp9_header.InitRTPVideoHeaderVP9();
vp9_header.flexible_mode = true;
vp9_header.num_spatial_layers = 3;
RtpPacketToSend packet(kNoExtensions);
bool last;
vp9_header.spatial_idx = 0;
RtpPacketizerVp9 packetizer0(vp9_header, kPacketSize);
packetizer0.SetPayloadData(kFrame, sizeof(kFrame), kNoFragmentation);
ASSERT_TRUE(packetizer0.NextPacket(&packet, &last));
EXPECT_FALSE(last);
EXPECT_FALSE(packet.Marker());
ASSERT_TRUE(packetizer0.NextPacket(&packet, &last));
EXPECT_TRUE(last);
EXPECT_FALSE(packet.Marker());
vp9_header.spatial_idx = 1;
RtpPacketizerVp9 packetizer1(vp9_header, kPacketSize);
packetizer1.SetPayloadData(kFrame, sizeof(kFrame), kNoFragmentation);
ASSERT_TRUE(packetizer1.NextPacket(&packet, &last));
EXPECT_FALSE(last);
EXPECT_FALSE(packet.Marker());
ASSERT_TRUE(packetizer1.NextPacket(&packet, &last));
EXPECT_TRUE(last);
EXPECT_FALSE(packet.Marker());
vp9_header.spatial_idx = 2;
RtpPacketizerVp9 packetizer2(vp9_header, kPacketSize);
packetizer2.SetPayloadData(kFrame, sizeof(kFrame), kNoFragmentation);
ASSERT_TRUE(packetizer2.NextPacket(&packet, &last));
EXPECT_FALSE(last);
EXPECT_FALSE(packet.Marker());
ASSERT_TRUE(packetizer2.NextPacket(&packet, &last));
EXPECT_TRUE(last);
EXPECT_TRUE(packet.Marker());
}
TEST_F(RtpPacketizerVp9Test, TestBaseLayerProtectionAndStorageType) {
const size_t kFrameSize = 10;
const size_t kPacketSize = 12;

View File

@ -362,15 +362,11 @@ bool RTPSenderVideo::SendVideo(RtpVideoCodecTypes video_type,
bool last = false;
while (!last) {
std::unique_ptr<RtpPacketToSend> packet(new RtpPacketToSend(*rtp_header));
uint8_t* payload = packet->AllocatePayload(max_data_payload_length);
RTC_DCHECK(payload);
size_t payload_bytes_in_packet = 0;
if (!packetizer->NextPacket(payload, &payload_bytes_in_packet, &last))
if (!packetizer->NextPacket(packet.get(), &last))
return false;
RTC_DCHECK_LE(packet->payload_size(), max_data_payload_length);
packet->SetPayloadSize(payload_bytes_in_packet);
packet->SetMarker(last);
if (!rtp_sender_->AssignSequenceNumber(packet.get()))
return false;