in RtpPacketizerVp8 factor out payload splitter function

so that it can be shared between different packetizers
and thus easier to extend

Bug: webrtc:9680
Change-Id: Ie5e904ad27afb8dd2ed35ef9e009f7f408017b2f
Reviewed-on: https://webrtc-review.googlesource.com/97661
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24555}
This commit is contained in:
Danil Chapovalov
2018-09-04 16:11:58 +02:00
committed by Commit Bot
parent b0800519b0
commit 376e1147e6
6 changed files with 323 additions and 318 deletions

View File

@ -225,6 +225,7 @@ rtc_static_library("rtp_rtcp") {
"../../system_wrappers:metrics_api",
"../audio_coding:audio_format_conversion",
"../remote_bitrate_estimator",
"//third_party/abseil-cpp/absl/container:inlined_vector",
"//third_party/abseil-cpp/absl/memory",
"//third_party/abseil-cpp/absl/types:optional",
]
@ -393,6 +394,7 @@ if (rtc_include_tests) {
"source/rtcp_transceiver_unittest.cc",
"source/rtp_fec_unittest.cc",
"source/rtp_format_h264_unittest.cc",
"source/rtp_format_unittest.cc",
"source/rtp_format_video_generic_unittest.cc",
"source/rtp_format_vp8_test_helper.cc",
"source/rtp_format_vp8_test_helper.h",

View File

@ -17,6 +17,7 @@
#include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
#include "modules/rtp_rtcp/source/rtp_format_vp8.h"
#include "modules/rtp_rtcp/source/rtp_format_vp9.h"
#include "rtc_base/checks.h"
namespace webrtc {
@ -61,6 +62,47 @@ std::unique_ptr<RtpPacketizer> RtpPacketizer::Create(
}
}
std::vector<size_t> RtpPacketizer::SplitAboutEqually(
size_t payload_len,
const PayloadSizeLimits& limits) {
RTC_CHECK_GT(limits.max_payload_len, limits.last_packet_reduction_len);
// Last packet can be smaller. Pretend that it's the same size, but we must
// write more payload to it.
size_t total_bytes = payload_len + limits.last_packet_reduction_len;
// Integer divisions with rounding up.
size_t num_packets_left =
(total_bytes + limits.max_payload_len - 1) / limits.max_payload_len;
size_t bytes_per_packet = total_bytes / num_packets_left;
size_t num_larger_packets = total_bytes % num_packets_left;
size_t remaining_data = payload_len;
std::vector<size_t> result;
result.reserve(num_packets_left);
while (remaining_data > 0) {
// Last num_larger_packets are 1 byte wider than the rest. Increase
// per-packet payload size when needed.
if (num_packets_left == num_larger_packets)
++bytes_per_packet;
size_t current_packet_bytes = bytes_per_packet;
if (current_packet_bytes > remaining_data) {
current_packet_bytes = remaining_data;
}
// This is not the last packet in the whole payload, but there's no data
// left for the last packet. Leave at least one byte for the last packet.
if (num_packets_left == 2 && current_packet_bytes == remaining_data) {
--current_packet_bytes;
}
result.push_back(current_packet_bytes);
remaining_data -= current_packet_bytes;
--num_packets_left;
}
return result;
}
RtpDepacketizer* RtpDepacketizer::Create(VideoCodecType type) {
switch (type) {
case kVideoCodecH264:

View File

@ -13,6 +13,7 @@
#include <memory>
#include <string>
#include <vector>
#include "api/array_view.h"
#include "common_types.h" // NOLINT(build/include)
@ -47,6 +48,10 @@ class RtpPacketizer {
// Write payload and set marker bit of the |packet|.
// Returns true on success, false otherwise.
virtual bool NextPacket(RtpPacketToSend* packet) = 0;
// Split payload_len into sum of integers with respect to |limits|.
static std::vector<size_t> SplitAboutEqually(size_t payload_len,
const PayloadSizeLimits& limits);
};
// TODO(sprang): Update the depacketizer to return a std::unqie_ptr with a copy

View File

@ -0,0 +1,168 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/rtp_rtcp/source/rtp_format.h"
#include <memory>
#include <numeric>
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
using ::testing::ElementsAre;
using ::testing::Le;
using ::testing::Each;
using ::testing::IsEmpty;
using ::testing::Not;
using ::testing::SizeIs;
// Calculate difference between largest and smallest packets respecting sizes
// adjustement provided by limits,
// i.e. last packet expected to be smaller than 'average' by reduction_len.
int EffectivePacketsSizeDifference(
std::vector<size_t> sizes,
const RtpPacketizer::PayloadSizeLimits& limits) {
// Account for larger last packet header.
sizes.back() += limits.last_packet_reduction_len;
auto minmax = std::minmax_element(sizes.begin(), sizes.end());
// MAX-MIN
return *minmax.second - *minmax.first;
}
size_t Sum(const std::vector<size_t>& sizes) {
return std::accumulate(sizes.begin(), sizes.end(), 0);
}
TEST(RtpPacketizerSplitAboutEqually, AllPacketsAreEqualSumToPayloadLen) {
RtpPacketizer::PayloadSizeLimits limits;
limits.max_payload_len = 5;
limits.last_packet_reduction_len = 2;
std::vector<size_t> payload_sizes =
RtpPacketizer::SplitAboutEqually(13, limits);
EXPECT_THAT(Sum(payload_sizes), 13);
}
TEST(RtpPacketizerSplitAboutEqually, AllPacketsAreEqualRespectsMaxPayloadSize) {
RtpPacketizer::PayloadSizeLimits limits;
limits.max_payload_len = 5;
limits.last_packet_reduction_len = 2;
std::vector<size_t> payload_sizes =
RtpPacketizer::SplitAboutEqually(13, limits);
EXPECT_THAT(payload_sizes, Each(Le(limits.max_payload_len)));
}
TEST(RtpPacketizerSplitAboutEqually,
AllPacketsAreEqualRespectsLastPacketReductionLength) {
RtpPacketizer::PayloadSizeLimits limits;
limits.max_payload_len = 5;
limits.last_packet_reduction_len = 2;
std::vector<size_t> payload_sizes =
RtpPacketizer::SplitAboutEqually(13, limits);
ASSERT_THAT(payload_sizes, Not(IsEmpty()));
EXPECT_LE(payload_sizes.back() + limits.last_packet_reduction_len,
limits.max_payload_len);
}
TEST(RtpPacketizerSplitAboutEqually, AllPacketsAreEqualInSize) {
RtpPacketizer::PayloadSizeLimits limits;
limits.max_payload_len = 5;
limits.last_packet_reduction_len = 2;
std::vector<size_t> payload_sizes =
RtpPacketizer::SplitAboutEqually(13, limits);
EXPECT_EQ(EffectivePacketsSizeDifference(payload_sizes, limits), 0);
}
TEST(RtpPacketizerSplitAboutEqually,
AllPacketsAreEqualGeneratesMinimumNumberOfPackets) {
RtpPacketizer::PayloadSizeLimits limits;
limits.max_payload_len = 5;
limits.last_packet_reduction_len = 2;
std::vector<size_t> payload_sizes =
RtpPacketizer::SplitAboutEqually(13, limits);
// Computed by hand. 3 packets would have exactly capacity 3*5-2=13
// (max length - for each packet minus last packet reduction).
EXPECT_THAT(payload_sizes, SizeIs(3));
}
TEST(RtpPacketizerSplitAboutEqually, SomePacketsAreSmallerSumToPayloadLen) {
RtpPacketizer::PayloadSizeLimits limits;
limits.max_payload_len = 7;
limits.last_packet_reduction_len = 5;
std::vector<size_t> payload_sizes =
RtpPacketizer::SplitAboutEqually(28, limits);
EXPECT_THAT(Sum(payload_sizes), 28);
}
TEST(RtpPacketizerVideoGeneric, SomePacketsAreSmallerRespectsMaxPayloadSize) {
RtpPacketizer::PayloadSizeLimits limits;
limits.max_payload_len = 7;
limits.last_packet_reduction_len = 5;
std::vector<size_t> payload_sizes =
RtpPacketizer::SplitAboutEqually(28, limits);
EXPECT_THAT(payload_sizes, Each(Le(limits.max_payload_len)));
}
TEST(RtpPacketizerVideoGeneric,
SomePacketsAreSmallerRespectsLastPacketReductionLength) {
RtpPacketizer::PayloadSizeLimits limits;
limits.max_payload_len = 7;
limits.last_packet_reduction_len = 5;
std::vector<size_t> payload_sizes =
RtpPacketizer::SplitAboutEqually(28, limits);
EXPECT_LE(payload_sizes.back(),
limits.max_payload_len - limits.last_packet_reduction_len);
}
TEST(RtpPacketizerVideoGeneric, SomePacketsAreSmallerPacketsAlmostEqualInSize) {
RtpPacketizer::PayloadSizeLimits limits;
limits.max_payload_len = 7;
limits.last_packet_reduction_len = 5;
std::vector<size_t> payload_sizes =
RtpPacketizer::SplitAboutEqually(28, limits);
EXPECT_LE(EffectivePacketsSizeDifference(payload_sizes, limits), 1);
}
TEST(RtpPacketizerVideoGeneric,
SomePacketsAreSmallerGeneratesMinimumNumberOfPackets) {
RtpPacketizer::PayloadSizeLimits limits;
limits.max_payload_len = 7;
limits.last_packet_reduction_len = 5;
std::vector<size_t> payload_sizes =
RtpPacketizer::SplitAboutEqually(24, limits);
// Computed by hand. 4 packets would have capacity 4*7-5=23 (max length -
// for each packet minus last packet reduction).
// 5 packets is enough for kPayloadSize.
EXPECT_THAT(payload_sizes, SizeIs(5));
}
} // namespace
} // namespace webrtc

View File

@ -23,8 +23,15 @@
namespace webrtc {
namespace {
// Length of VP8 payload descriptors' fixed part.
constexpr int kVp8FixedPayloadDescriptorSize = 1;
constexpr int kXBit = 0x80;
constexpr int kNBit = 0x20;
constexpr int kSBit = 0x10;
constexpr int kKeyIdxField = 0x1F;
constexpr int kIBit = 0x80;
constexpr int kLBit = 0x40;
constexpr int kTBit = 0x20;
constexpr int kKBit = 0x10;
constexpr int kYBit = 0x20;
int ParseVP8PictureID(RTPVideoHeaderVP8* vp8,
const uint8_t** data,
@ -165,259 +172,113 @@ bool ValidateHeader(const RTPVideoHeaderVP8& hdr_info) {
RtpPacketizerVp8::RtpPacketizerVp8(rtc::ArrayView<const uint8_t> payload,
PayloadSizeLimits limits,
const RTPVideoHeaderVP8& hdr_info)
: payload_data_(payload.data()), hdr_info_(hdr_info), limits_(limits) {
RTC_DCHECK(ValidateHeader(hdr_info));
GeneratePackets(payload.size());
: hdr_(BuildHeader(hdr_info)), remaining_payload_(payload) {
if (limits.max_payload_len - limits.last_packet_reduction_len <
hdr_.size() + 1) {
// The provided payload length is not long enough for the payload
// descriptor and one payload byte in the last packet.
current_packet_ = payload_sizes_.begin();
return;
}
limits.max_payload_len -= hdr_.size();
payload_sizes_ = SplitAboutEqually(payload.size(), limits);
current_packet_ = payload_sizes_.begin();
}
RtpPacketizerVp8::~RtpPacketizerVp8() = default;
size_t RtpPacketizerVp8::NumPackets() const {
return packets_.size();
return payload_sizes_.end() - current_packet_;
}
bool RtpPacketizerVp8::NextPacket(RtpPacketToSend* packet) {
RTC_DCHECK(packet);
if (packets_.empty()) {
if (current_packet_ == payload_sizes_.end()) {
return false;
}
InfoStruct packet_info = packets_.front();
packets_.pop();
size_t packet_payload_len =
packets_.empty()
? limits_.max_payload_len - limits_.last_packet_reduction_len
: limits_.max_payload_len;
uint8_t* buffer = packet->AllocatePayload(packet_payload_len);
int bytes = WriteHeaderAndPayload(packet_info, buffer, packet_payload_len);
if (bytes < 0) {
return false;
}
packet->SetPayloadSize(bytes);
packet->SetMarker(packets_.empty());
size_t packet_payload_len = *current_packet_;
++current_packet_;
uint8_t* buffer = packet->AllocatePayload(hdr_.size() + packet_payload_len);
RTC_CHECK(buffer);
memcpy(buffer, hdr_.data(), hdr_.size());
memcpy(buffer + hdr_.size(), remaining_payload_.data(), packet_payload_len);
remaining_payload_ = remaining_payload_.subview(packet_payload_len);
hdr_[0] &= (~kSBit); // Clear 'Start of partition' bit.
packet->SetMarker(current_packet_ == payload_sizes_.end());
return true;
}
void RtpPacketizerVp8::GeneratePackets(size_t payload_len) {
if (limits_.max_payload_len - limits_.last_packet_reduction_len <
kVp8FixedPayloadDescriptorSize + PayloadDescriptorExtraLength() + 1) {
// The provided payload length is not long enough for the payload
// descriptor and one payload byte in the last packet.
return;
// Write the VP8 payload descriptor.
// 0
// 0 1 2 3 4 5 6 7 8
// +-+-+-+-+-+-+-+-+-+
// |X| |N|S| PART_ID |
// +-+-+-+-+-+-+-+-+-+
// X: |I|L|T|K| | (mandatory if any of the below are used)
// +-+-+-+-+-+-+-+-+-+
// I: |PictureID (16b)| (optional)
// +-+-+-+-+-+-+-+-+-+
// L: | TL0PIC_IDX | (optional)
// +-+-+-+-+-+-+-+-+-+
// T/K: |TID:Y| KEYIDX | (optional)
// +-+-+-+-+-+-+-+-+-+
RtpPacketizerVp8::RawHeader RtpPacketizerVp8::BuildHeader(
const RTPVideoHeaderVP8& header) {
RTC_DCHECK(ValidateHeader(header));
RawHeader result;
bool tid_present = header.temporalIdx != kNoTemporalIdx;
bool keyid_present = header.keyIdx != kNoKeyIdx;
bool tl0_pid_present = header.tl0PicIdx != kNoTl0PicIdx;
bool pid_present = header.pictureId != kNoPictureId;
uint8_t x_field = 0;
if (pid_present)
x_field |= kIBit;
if (tl0_pid_present)
x_field |= kLBit;
if (tid_present)
x_field |= kTBit;
if (keyid_present)
x_field |= kKBit;
uint8_t flags = 0;
if (x_field != 0)
flags |= kXBit;
if (header.nonReference)
flags |= kNBit;
// Create header as first packet in the frame. NextPacket() will clear it
// after first use.
flags |= kSBit;
result.push_back(flags);
if (x_field == 0) {
return result;
}
size_t capacity = limits_.max_payload_len - (kVp8FixedPayloadDescriptorSize +
PayloadDescriptorExtraLength());
// Last packet of the last partition is smaller. Pretend that it's the same
// size, but we must write more payload to it.
size_t total_bytes = payload_len + limits_.last_packet_reduction_len;
// Integer divisions with rounding up.
size_t num_packets_left = (total_bytes + capacity - 1) / capacity;
size_t bytes_per_packet = total_bytes / num_packets_left;
size_t num_larger_packets = total_bytes % num_packets_left;
size_t remaining_data = payload_len;
while (remaining_data > 0) {
// Last num_larger_packets are 1 byte wider than the rest. Increase
// per-packet payload size when needed.
if (num_packets_left == num_larger_packets)
++bytes_per_packet;
size_t current_packet_bytes = bytes_per_packet;
if (current_packet_bytes > remaining_data) {
current_packet_bytes = remaining_data;
result.push_back(x_field);
if (pid_present) {
const uint16_t pic_id = static_cast<uint16_t>(header.pictureId);
result.push_back(0x80 | ((pic_id >> 8) & 0x7F));
result.push_back(pic_id & 0xFF);
}
if (tl0_pid_present) {
result.push_back(header.tl0PicIdx);
}
if (tid_present || keyid_present) {
uint8_t data_field = 0;
if (tid_present) {
data_field |= header.temporalIdx << 6;
if (header.layerSync)
data_field |= kYBit;
}
// This is not the last packet in the whole payload, but there's no data
// left for the last packet. Leave at least one byte for the last packet.
if (num_packets_left == 2 && current_packet_bytes == remaining_data) {
--current_packet_bytes;
if (keyid_present) {
data_field |= (header.keyIdx & kKeyIdxField);
}
QueuePacket(payload_len - remaining_data, current_packet_bytes,
/*first_packet=*/remaining_data == payload_len);
remaining_data -= current_packet_bytes;
--num_packets_left;
result.push_back(data_field);
}
}
void RtpPacketizerVp8::QueuePacket(size_t start_pos,
size_t packet_size,
bool first_packet) {
// Write info to packet info struct and store in packet info queue.
InfoStruct packet_info;
packet_info.payload_start_pos = start_pos;
packet_info.size = packet_size;
packet_info.first_packet = first_packet;
packets_.push(packet_info);
}
int RtpPacketizerVp8::WriteHeaderAndPayload(const InfoStruct& packet_info,
uint8_t* buffer,
size_t buffer_length) const {
// Write the VP8 payload descriptor.
// 0
// 0 1 2 3 4 5 6 7 8
// +-+-+-+-+-+-+-+-+-+
// |X| |N|S| PART_ID |
// +-+-+-+-+-+-+-+-+-+
// X: |I|L|T|K| | (mandatory if any of the below are used)
// +-+-+-+-+-+-+-+-+-+
// I: |PictureID (8/16b)| (optional)
// +-+-+-+-+-+-+-+-+-+
// L: | TL0PIC_IDX | (optional)
// +-+-+-+-+-+-+-+-+-+
// T/K: |TID:Y| KEYIDX | (optional)
// +-+-+-+-+-+-+-+-+-+
RTC_DCHECK_GT(packet_info.size, 0);
buffer[0] = 0;
if (XFieldPresent())
buffer[0] |= kXBit;
if (hdr_info_.nonReference)
buffer[0] |= kNBit;
if (packet_info.first_packet)
buffer[0] |= kSBit;
const int extension_length = WriteExtensionFields(buffer, buffer_length);
if (extension_length < 0)
return -1;
memcpy(&buffer[kVp8FixedPayloadDescriptorSize + extension_length],
&payload_data_[packet_info.payload_start_pos], packet_info.size);
// Return total length of written data.
return packet_info.size + kVp8FixedPayloadDescriptorSize + extension_length;
}
int RtpPacketizerVp8::WriteExtensionFields(uint8_t* buffer,
size_t buffer_length) const {
size_t extension_length = 0;
if (XFieldPresent()) {
uint8_t* x_field = buffer + kVp8FixedPayloadDescriptorSize;
*x_field = 0;
extension_length = 1; // One octet for the X field.
if (PictureIdPresent()) {
if (WritePictureIDFields(x_field, buffer, buffer_length,
&extension_length) < 0) {
return -1;
}
}
if (TL0PicIdxFieldPresent()) {
if (WriteTl0PicIdxFields(x_field, buffer, buffer_length,
&extension_length) < 0) {
return -1;
}
}
if (TIDFieldPresent() || KeyIdxFieldPresent()) {
if (WriteTIDAndKeyIdxFields(x_field, buffer, buffer_length,
&extension_length) < 0) {
return -1;
}
}
RTC_DCHECK_EQ(extension_length, PayloadDescriptorExtraLength());
}
return static_cast<int>(extension_length);
}
int RtpPacketizerVp8::WritePictureIDFields(uint8_t* x_field,
uint8_t* buffer,
size_t buffer_length,
size_t* extension_length) const {
*x_field |= kIBit;
RTC_DCHECK_GE(buffer_length,
kVp8FixedPayloadDescriptorSize + *extension_length);
const int pic_id_length = WritePictureID(
buffer + kVp8FixedPayloadDescriptorSize + *extension_length,
buffer_length - kVp8FixedPayloadDescriptorSize - *extension_length);
if (pic_id_length < 0)
return -1;
*extension_length += pic_id_length;
return 0;
}
int RtpPacketizerVp8::WritePictureID(uint8_t* buffer,
size_t buffer_length) const {
const uint16_t pic_id = static_cast<uint16_t>(hdr_info_.pictureId);
size_t picture_id_len = PictureIdLength();
if (picture_id_len > buffer_length)
return -1;
if (picture_id_len == 2) {
buffer[0] = 0x80 | ((pic_id >> 8) & 0x7F);
buffer[1] = pic_id & 0xFF;
} else if (picture_id_len == 1) {
buffer[0] = pic_id & 0x7F;
}
return static_cast<int>(picture_id_len);
}
int RtpPacketizerVp8::WriteTl0PicIdxFields(uint8_t* x_field,
uint8_t* buffer,
size_t buffer_length,
size_t* extension_length) const {
if (buffer_length < kVp8FixedPayloadDescriptorSize + *extension_length + 1) {
return -1;
}
*x_field |= kLBit;
buffer[kVp8FixedPayloadDescriptorSize + *extension_length] =
hdr_info_.tl0PicIdx;
++*extension_length;
return 0;
}
int RtpPacketizerVp8::WriteTIDAndKeyIdxFields(uint8_t* x_field,
uint8_t* buffer,
size_t buffer_length,
size_t* extension_length) const {
if (buffer_length < kVp8FixedPayloadDescriptorSize + *extension_length + 1) {
return -1;
}
uint8_t* data_field =
&buffer[kVp8FixedPayloadDescriptorSize + *extension_length];
*data_field = 0;
if (TIDFieldPresent()) {
*x_field |= kTBit;
*data_field |= hdr_info_.temporalIdx << 6;
*data_field |= hdr_info_.layerSync ? kYBit : 0;
}
if (KeyIdxFieldPresent()) {
*x_field |= kKBit;
*data_field |= (hdr_info_.keyIdx & kKeyIdxField);
}
++*extension_length;
return 0;
}
size_t RtpPacketizerVp8::PayloadDescriptorExtraLength() const {
size_t length_bytes = PictureIdLength();
if (TL0PicIdxFieldPresent())
++length_bytes;
if (TIDFieldPresent() || KeyIdxFieldPresent())
++length_bytes;
if (length_bytes > 0)
++length_bytes; // Include the extension field.
return length_bytes;
}
size_t RtpPacketizerVp8::PictureIdLength() const {
if (hdr_info_.pictureId == kNoPictureId) {
return 0;
}
return 2;
}
bool RtpPacketizerVp8::XFieldPresent() const {
return (TIDFieldPresent() || TL0PicIdxFieldPresent() || PictureIdPresent() ||
KeyIdxFieldPresent());
}
bool RtpPacketizerVp8::TIDFieldPresent() const {
return (hdr_info_.temporalIdx != kNoTemporalIdx);
}
bool RtpPacketizerVp8::KeyIdxFieldPresent() const {
return (hdr_info_.keyIdx != kNoKeyIdx);
}
bool RtpPacketizerVp8::TL0PicIdxFieldPresent() const {
return (hdr_info_.tl0PicIdx != kNoTl0PicIdx);
return result;
}
//

View File

@ -25,10 +25,11 @@
#ifndef MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_H_
#define MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_H_
#include <queue>
#include <string>
#include <vector>
#include "absl/container/inlined_vector.h"
#include "api/array_view.h"
#include "modules/include/module_common_types.h"
#include "modules/rtp_rtcp/source/rtp_format.h"
#include "rtc_base/constructormagic.h"
@ -54,88 +55,14 @@ class RtpPacketizerVp8 : public RtpPacketizer {
bool NextPacket(RtpPacketToSend* packet) override;
private:
typedef struct {
size_t payload_start_pos;
size_t size;
bool first_packet;
} InfoStruct;
typedef std::queue<InfoStruct> InfoQueue;
// VP8 header can use up to 6 bytes.
using RawHeader = absl::InlinedVector<uint8_t, 6>;
static RawHeader BuildHeader(const RTPVideoHeaderVP8& header);
static const int kXBit = 0x80;
static const int kNBit = 0x20;
static const int kSBit = 0x10;
static const int kPartIdField = 0x0F;
static const int kKeyIdxField = 0x1F;
static const int kIBit = 0x80;
static const int kLBit = 0x40;
static const int kTBit = 0x20;
static const int kKBit = 0x10;
static const int kYBit = 0x20;
// Calculate all packet sizes and load to packet info queue.
void GeneratePackets(size_t payload_len);
// Insert packet into packet queue.
void QueuePacket(size_t start_pos, size_t packet_size, bool first_packet);
// Write the payload header and copy the payload to the buffer.
// The info in packet_info determines which part of the payload is written
// and what to write in the header fields.
int WriteHeaderAndPayload(const InfoStruct& packet_info,
uint8_t* buffer,
size_t buffer_length) const;
// Write the X field and the appropriate extension fields to buffer.
// The function returns the extension length (including X field), or -1
// on error.
int WriteExtensionFields(uint8_t* buffer, size_t buffer_length) const;
// Set the I bit in the x_field, and write PictureID to the appropriate
// position in buffer. The function returns 0 on success, -1 otherwise.
int WritePictureIDFields(uint8_t* x_field,
uint8_t* buffer,
size_t buffer_length,
size_t* extension_length) const;
// Set the L bit in the x_field, and write Tl0PicIdx to the appropriate
// position in buffer. The function returns 0 on success, -1 otherwise.
int WriteTl0PicIdxFields(uint8_t* x_field,
uint8_t* buffer,
size_t buffer_length,
size_t* extension_length) const;
// Set the T and K bits in the x_field, and write TID, Y and KeyIdx to the
// appropriate position in buffer. The function returns 0 on success,
// -1 otherwise.
int WriteTIDAndKeyIdxFields(uint8_t* x_field,
uint8_t* buffer,
size_t buffer_length,
size_t* extension_length) const;
// Write the PictureID from codec_specific_info_ to buffer. One or two
// bytes are written, depending on magnitude of PictureID. The function
// returns the number of bytes written.
int WritePictureID(uint8_t* buffer, size_t buffer_length) const;
// Calculate and return length (octets) of the variable header fields in
// the next header (i.e., header length in addition to vp8_header_bytes_).
size_t PayloadDescriptorExtraLength() const;
// Calculate and return length (octets) of PictureID field in the next
// header. Can be 0, 1, or 2.
size_t PictureIdLength() const;
// Check whether each of the optional fields will be included in the header.
bool XFieldPresent() const;
bool TIDFieldPresent() const;
bool KeyIdxFieldPresent() const;
bool TL0PicIdxFieldPresent() const;
bool PictureIdPresent() const { return (PictureIdLength() > 0); }
const uint8_t* payload_data_;
const RTPVideoHeaderVP8 hdr_info_;
const PayloadSizeLimits limits_;
InfoQueue packets_;
RawHeader hdr_;
rtc::ArrayView<const uint8_t> remaining_payload_;
std::vector<size_t> payload_sizes_;
std::vector<size_t>::const_iterator current_packet_;
RTC_DISALLOW_COPY_AND_ASSIGN(RtpPacketizerVp8);
};