Updating to VP8 RTP spec rev -02

Updating the VP8 packetizer class (RtpFormatVp8) and VP8 parser
(in class RTPPayloadParser) to follow the -02 revision of the spec.
See http://tools.ietf.org/html/draft-ietf-payload-vp8-02.

Updating the unit tests, too. Finally, updating the tests to
follow the recommendations from the test team; specifically
including the test code in the webrtc namespace, and omitting
the main function at the end of each test file.

Review URL: http://webrtc-codereview.appspot.com/296003

git-svn-id: http://webrtc.googlecode.com/svn/trunk@1013 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
henrik.lundin@webrtc.org 2011-11-24 12:52:40 +00:00
parent 517dcb71f2
commit 6f2c0168f0
7 changed files with 259 additions and 158 deletions

View File

@ -46,6 +46,7 @@ struct RTPVideoHeaderH263
enum {kNoPictureId = -1}; enum {kNoPictureId = -1};
enum {kNoTl0PicIdx = -1}; enum {kNoTl0PicIdx = -1};
enum {kNoTemporalIdx = -1}; enum {kNoTemporalIdx = -1};
enum {kNoKeyIdx = -1};
enum {kNoSimulcastIdx = 0}; enum {kNoSimulcastIdx = 0};
struct RTPVideoHeaderVP8 struct RTPVideoHeaderVP8
@ -56,6 +57,7 @@ struct RTPVideoHeaderVP8
pictureId = kNoPictureId; pictureId = kNoPictureId;
tl0PicIdx = kNoTl0PicIdx; tl0PicIdx = kNoTl0PicIdx;
temporalIdx = kNoTemporalIdx; temporalIdx = kNoTemporalIdx;
keyIdx = kNoKeyIdx;
partitionId = 0; partitionId = 0;
beginningOfPartition = false; beginningOfPartition = false;
frameWidth = 0; frameWidth = 0;
@ -68,6 +70,7 @@ struct RTPVideoHeaderVP8
WebRtc_Word16 tl0PicIdx; // TL0PIC_IDX, 8 bits; WebRtc_Word16 tl0PicIdx; // TL0PIC_IDX, 8 bits;
// kNoTl0PicIdx means no value provided. // kNoTl0PicIdx means no value provided.
WebRtc_Word8 temporalIdx; // Temporal layer index, or kNoTemporalIdx. WebRtc_Word8 temporalIdx; // Temporal layer index, or kNoTemporalIdx.
int keyIdx; // 5 bits; kNoKeyIdx means not used.
int partitionId; // VP8 partition ID int partitionId; // VP8 partition ID
bool beginningOfPartition; // True if this packet is the first bool beginningOfPartition; // True if this packet is the first
// in a VP8 partition. Otherwise false // in a VP8 partition. Otherwise false

View File

@ -173,19 +173,19 @@ int RtpFormatVp8::WriteHeaderAndPayload(int payload_bytes,
int buffer_length) int buffer_length)
{ {
// Write the VP8 payload descriptor. // Write the VP8 payload descriptor.
// 0 // 0
// 0 1 2 3 4 5 6 7 8 // 0 1 2 3 4 5 6 7 8
// +-+-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+-+
// |X| |N|S| PART_ID | // |X| |N|S| PART_ID |
// +-+-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+-+
// X: |I|L|T| | (mandatory if any of the below are used) // X: |I|L|T|K| | (mandatory if any of the below are used)
// +-+-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+-+
// I: |PictureID (8/16b)| (optional) // I: |PictureID (8/16b)| (optional)
// +-+-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+-+
// L: | TL0PIC_IDX | (optional) // L: | TL0PIC_IDX | (optional)
// +-+-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+-+
// T: | TID | | (optional) // T/K: | TID | KEYIDX | (optional)
// +-+-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+-+
assert(payload_bytes > 0); assert(payload_bytes > 0);
assert(payload_bytes_sent_ + payload_bytes <= payload_size_); assert(payload_bytes_sent_ + payload_bytes <= payload_size_);
@ -235,9 +235,9 @@ const
return -1; return -1;
} }
} }
if (TIDFieldPresent()) if (TIDFieldPresent() || KeyIdxFieldPresent())
{ {
if (WriteTIDFields(x_field, buffer, buffer_length, if (WriteTIDAndKeyIdxFields(x_field, buffer, buffer_length,
&extension_length) < 0) &extension_length) < 0)
{ {
return -1; return -1;
@ -299,19 +299,29 @@ int RtpFormatVp8::WriteTl0PicIdxFields(WebRtc_UWord8* x_field,
return 0; return 0;
} }
int RtpFormatVp8::WriteTIDFields(WebRtc_UWord8* x_field, int RtpFormatVp8::WriteTIDAndKeyIdxFields(WebRtc_UWord8* x_field,
WebRtc_UWord8* buffer, WebRtc_UWord8* buffer,
int buffer_length, int buffer_length,
int* extension_length) const int* extension_length) const
{ {
if (buffer_length < vp8_fixed_payload_descriptor_bytes_ + *extension_length if (buffer_length < vp8_fixed_payload_descriptor_bytes_ + *extension_length
+ 1) + 1)
{ {
return -1; return -1;
} }
*x_field |= kTBit; WebRtc_UWord8* data_field =
buffer[vp8_fixed_payload_descriptor_bytes_ + *extension_length] &buffer[vp8_fixed_payload_descriptor_bytes_ + *extension_length];
= hdr_info_.temporalIdx << 5; *data_field = 0;
if (TIDFieldPresent())
{
*x_field |= kTBit;
*data_field |= hdr_info_.temporalIdx << 5;
}
if (KeyIdxFieldPresent())
{
*x_field |= kKBit;
*data_field |= (hdr_info_.keyIdx & kKeyIdxField);
}
++*extension_length; ++*extension_length;
return 0; return 0;
} }
@ -320,8 +330,8 @@ int RtpFormatVp8::PayloadDescriptorExtraLength() const
{ {
int length_bytes = PictureIdLength(); int length_bytes = PictureIdLength();
if (TL0PicIdxFieldPresent()) ++length_bytes; if (TL0PicIdxFieldPresent()) ++length_bytes;
if (TIDFieldPresent()) ++length_bytes; if (TIDFieldPresent() || KeyIdxFieldPresent()) ++length_bytes;
if (length_bytes > 0) ++length_bytes; // Include the extension field. if (length_bytes > 0) ++length_bytes; // Include the extension field.
return length_bytes; return length_bytes;
} }
@ -340,7 +350,8 @@ int RtpFormatVp8::PictureIdLength() const
bool RtpFormatVp8::XFieldPresent() const bool RtpFormatVp8::XFieldPresent() const
{ {
return (TIDFieldPresent() || TL0PicIdxFieldPresent() || PictureIdPresent()); return (TIDFieldPresent() || TL0PicIdxFieldPresent() || PictureIdPresent()
|| KeyIdxFieldPresent());
} }
bool RtpFormatVp8::TIDFieldPresent() const bool RtpFormatVp8::TIDFieldPresent() const
@ -348,6 +359,11 @@ bool RtpFormatVp8::TIDFieldPresent() const
return (hdr_info_.temporalIdx != kNoTemporalIdx); return (hdr_info_.temporalIdx != kNoTemporalIdx);
} }
bool RtpFormatVp8::KeyIdxFieldPresent() const
{
return (hdr_info_.keyIdx != kNoKeyIdx);
}
bool RtpFormatVp8::TL0PicIdxFieldPresent() const bool RtpFormatVp8::TL0PicIdxFieldPresent() const
{ {
return (hdr_info_.tl0PicIdx != kNoTl0PicIdx); return (hdr_info_.tl0PicIdx != kNoTl0PicIdx);

View File

@ -84,9 +84,11 @@ private:
static const int kNBit = 0x20; static const int kNBit = 0x20;
static const int kSBit = 0x10; static const int kSBit = 0x10;
static const int kPartIdField = 0x0F; static const int kPartIdField = 0x0F;
static const int kKeyIdxField = 0x1F;
static const int kIBit = 0x80; static const int kIBit = 0x80;
static const int kLBit = 0x40; static const int kLBit = 0x40;
static const int kTBit = 0x20; static const int kTBit = 0x20;
static const int kKBit = 0x10;
// Calculate size of next chunk to send. Returns 0 if none can be sent. // Calculate size of next chunk to send. Returns 0 if none can be sent.
int CalcNextSize(int max_payload_len, int remaining_bytes, int CalcNextSize(int max_payload_len, int remaining_bytes,
@ -115,10 +117,11 @@ private:
int WriteTl0PicIdxFields(WebRtc_UWord8* x_field, WebRtc_UWord8* buffer, int WriteTl0PicIdxFields(WebRtc_UWord8* x_field, WebRtc_UWord8* buffer,
int buffer_length, int* extension_length) const; int buffer_length, int* extension_length) const;
// Set the T bit in the x_field, and write TID to the appropriate // Set the T and K bits in the x_field, and write TID and KeyIdx to the
// position in buffer. The function returns 0 on success, -1 otherwise. // appropriate position in buffer. The function returns 0 on success,
int WriteTIDFields(WebRtc_UWord8* x_field, WebRtc_UWord8* buffer, // -1 otherwise.
int buffer_length, int* extension_length) const; int WriteTIDAndKeyIdxFields(WebRtc_UWord8* x_field, WebRtc_UWord8* buffer,
int buffer_length, int* extension_length) const;
// Write the PictureID from codec_specific_info_ to buffer. One or two // Write the PictureID from codec_specific_info_ to buffer. One or two
// bytes are written, depending on magnitude of PictureID. The function // bytes are written, depending on magnitude of PictureID. The function
@ -136,6 +139,7 @@ private:
// Check whether each of the optional fields will be included in the header. // Check whether each of the optional fields will be included in the header.
bool XFieldPresent() const; bool XFieldPresent() const;
bool TIDFieldPresent() const; bool TIDFieldPresent() const;
bool KeyIdxFieldPresent() const;
bool TL0PicIdxFieldPresent() const; bool TL0PicIdxFieldPresent() const;
bool PictureIdPresent() const { return (PictureIdLength() > 0); } bool PictureIdPresent() const { return (PictureIdLength() > 0); }

View File

@ -18,11 +18,7 @@
#include "typedefs.h" #include "typedefs.h"
#include "rtp_format_vp8.h" #include "rtp_format_vp8.h"
namespace { namespace webrtc {
using webrtc::RTPFragmentationHeader;
using webrtc::RtpFormatVp8;
using webrtc::RTPVideoHeaderVP8;
const int kPayloadSize = 30; const int kPayloadSize = 30;
const int kBufferSize = kPayloadSize + 6; // Add space for payload descriptor. const int kBufferSize = kPayloadSize + 6; // Add space for payload descriptor.
@ -35,7 +31,7 @@ class RtpFormatVp8Test : public ::testing::Test {
void CheckHeader(bool first_in_frame, bool frag_start, int part_id); void CheckHeader(bool first_in_frame, bool frag_start, int part_id);
void CheckPictureID(); void CheckPictureID();
void CheckTl0PicIdx(); void CheckTl0PicIdx();
void CheckTID(); void CheckTIDAndKeyIdx();
void CheckPayload(int payload_end); void CheckPayload(int payload_end);
void CheckLast(bool last) const; void CheckLast(bool last) const;
void CheckPacket(int send_bytes, int expect_bytes, bool last, void CheckPacket(int send_bytes, int expect_bytes, bool last,
@ -66,10 +62,11 @@ void RtpFormatVp8Test::SetUp() {
fragmentation_->fragmentationOffset[1] = 10; fragmentation_->fragmentationOffset[1] = 10;
fragmentation_->fragmentationOffset[2] = 20; fragmentation_->fragmentationOffset[2] = 20;
hdr_info_.pictureId = webrtc::kNoPictureId; hdr_info_.pictureId = kNoPictureId;
hdr_info_.nonReference = false; hdr_info_.nonReference = false;
hdr_info_.temporalIdx = webrtc::kNoTemporalIdx; hdr_info_.temporalIdx = kNoTemporalIdx;
hdr_info_.tl0PicIdx = webrtc::kNoTl0PicIdx; hdr_info_.tl0PicIdx = kNoTl0PicIdx;
hdr_info_.keyIdx = kNoKeyIdx;
} }
void RtpFormatVp8Test::TearDown() { void RtpFormatVp8Test::TearDown() {
@ -96,7 +93,11 @@ void RtpFormatVp8Test::TearDown() {
#define EXPECT_BIT_T_EQ(x,a) EXPECT_BIT_EQ(x, 5, a) #define EXPECT_BIT_T_EQ(x,a) EXPECT_BIT_EQ(x, 5, a)
#define EXPECT_TID_EQ(x,a) EXPECT_EQ((((x)&0xE0) >> 5), a) #define EXPECT_BIT_K_EQ(x,a) EXPECT_BIT_EQ(x, 4, a)
#define EXPECT_TID_EQ(x,a) EXPECT_EQ((((x) & 0xE0) >> 5), a)
#define EXPECT_KEYIDX_EQ(x,a) EXPECT_EQ(((x) & 0x1F), a)
void RtpFormatVp8Test::CheckHeader(bool first_in_frame, bool frag_start, void RtpFormatVp8Test::CheckHeader(bool first_in_frame, bool frag_start,
int part_id) int part_id)
@ -105,15 +106,16 @@ void RtpFormatVp8Test::CheckHeader(bool first_in_frame, bool frag_start,
EXPECT_BIT_EQ(buffer_[0], 6, 0); // check reserved bit EXPECT_BIT_EQ(buffer_[0], 6, 0); // check reserved bit
if (hdr_info_.pictureId != webrtc::kNoPictureId || if (hdr_info_.pictureId != kNoPictureId ||
hdr_info_.temporalIdx != webrtc::kNoTemporalIdx || hdr_info_.temporalIdx != kNoTemporalIdx ||
hdr_info_.tl0PicIdx != webrtc::kNoTl0PicIdx) hdr_info_.tl0PicIdx != kNoTl0PicIdx ||
hdr_info_.keyIdx != kNoKeyIdx)
{ {
EXPECT_BIT_X_EQ(buffer_[0], 1); EXPECT_BIT_X_EQ(buffer_[0], 1);
++payload_start_; ++payload_start_;
CheckPictureID(); CheckPictureID();
CheckTl0PicIdx(); CheckTl0PicIdx();
CheckTID(); CheckTIDAndKeyIdx();
} }
else else
{ {
@ -137,7 +139,7 @@ void RtpFormatVp8Test::CheckHeader(bool first_in_frame, bool frag_start,
void RtpFormatVp8Test::CheckPictureID() void RtpFormatVp8Test::CheckPictureID()
{ {
if (hdr_info_.pictureId != webrtc::kNoPictureId) if (hdr_info_.pictureId != kNoPictureId)
{ {
EXPECT_BIT_I_EQ(buffer_[1], 1); EXPECT_BIT_I_EQ(buffer_[1], 1);
if (hdr_info_.pictureId > 0x7F) if (hdr_info_.pictureId > 0x7F)
@ -165,7 +167,7 @@ void RtpFormatVp8Test::CheckPictureID()
void RtpFormatVp8Test::CheckTl0PicIdx() void RtpFormatVp8Test::CheckTl0PicIdx()
{ {
if (hdr_info_.tl0PicIdx != webrtc::kNoTl0PicIdx) if (hdr_info_.tl0PicIdx != kNoTl0PicIdx)
{ {
EXPECT_BIT_L_EQ(buffer_[1], 1); EXPECT_BIT_L_EQ(buffer_[1], 1);
EXPECT_EQ(buffer_[payload_start_], hdr_info_.tl0PicIdx); EXPECT_EQ(buffer_[payload_start_], hdr_info_.tl0PicIdx);
@ -177,19 +179,36 @@ void RtpFormatVp8Test::CheckTl0PicIdx()
} }
} }
void RtpFormatVp8Test::CheckTID() void RtpFormatVp8Test::CheckTIDAndKeyIdx()
{ {
if (hdr_info_.temporalIdx != webrtc::kNoTemporalIdx) if (hdr_info_.temporalIdx == kNoTemporalIdx &&
hdr_info_.keyIdx == kNoKeyIdx)
{
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_BIT_T_EQ(buffer_[1], 1);
EXPECT_TID_EQ(buffer_[payload_start_], hdr_info_.temporalIdx); EXPECT_TID_EQ(buffer_[payload_start_], hdr_info_.temporalIdx);
EXPECT_EQ(buffer_[payload_start_] & 0x1F, 0);
++payload_start_;
} }
else else
{ {
EXPECT_BIT_T_EQ(buffer_[1], 0); EXPECT_BIT_T_EQ(buffer_[1], 0);
EXPECT_TID_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);
}
else
{
EXPECT_BIT_K_EQ(buffer_[1], 0);
EXPECT_KEYIDX_EQ(buffer_[payload_start_], 0);
}
++payload_start_;
} }
void RtpFormatVp8Test::CheckPayload(int payload_end) void RtpFormatVp8Test::CheckPayload(int payload_end)
@ -232,7 +251,7 @@ TEST_F(RtpFormatVp8Test, TestStrictMode)
hdr_info_.pictureId = 200; // > 0x7F should produce 2-byte PictureID hdr_info_.pictureId = 200; // > 0x7F should produce 2-byte PictureID
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize, RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
hdr_info_, *fragmentation_, webrtc::kStrict); hdr_info_, *fragmentation_, kStrict);
// get first packet, expect balanced size ~= same as second packet // get first packet, expect balanced size ~= same as second packet
EXPECT_EQ(0, packetizer.NextPacket(13, buffer_, &send_bytes, &last)); EXPECT_EQ(0, packetizer.NextPacket(13, buffer_, &send_bytes, &last));
@ -289,7 +308,7 @@ TEST_F(RtpFormatVp8Test, TestAggregateMode)
hdr_info_.pictureId = 20; // <= 0x7F should produce 1-byte PictureID hdr_info_.pictureId = 20; // <= 0x7F should produce 1-byte PictureID
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize, RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
hdr_info_, *fragmentation_, webrtc::kAggregate); hdr_info_, *fragmentation_, kAggregate);
// get first packet // get first packet
// first part of first partition (balanced fragments are expected) // first part of first partition (balanced fragments are expected)
@ -328,9 +347,9 @@ TEST_F(RtpFormatVp8Test, TestSloppyMode)
bool last; bool last;
bool first_in_frame = true; bool first_in_frame = true;
hdr_info_.pictureId = webrtc::kNoPictureId; // no PictureID hdr_info_.pictureId = kNoPictureId; // no PictureID
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize, RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
hdr_info_, *fragmentation_, webrtc::kSloppy); hdr_info_, *fragmentation_, kSloppy);
// get first packet // get first packet
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last)); EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
@ -431,7 +450,7 @@ TEST_F(RtpFormatVp8Test, TestTl0PicIdxAndTID) {
hdr_info_.tl0PicIdx = 117; hdr_info_.tl0PicIdx = 117;
hdr_info_.temporalIdx = 2; hdr_info_.temporalIdx = 2;
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize, RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
hdr_info_, *fragmentation_, webrtc::kAggregate); hdr_info_, *fragmentation_, kAggregate);
// get first and only packet // get first and only packet
EXPECT_EQ(0, packetizer.NextPacket(kBufferSize, buffer_, &send_bytes, EXPECT_EQ(0, packetizer.NextPacket(kBufferSize, buffer_, &send_bytes,
@ -442,10 +461,41 @@ TEST_F(RtpFormatVp8Test, TestTl0PicIdxAndTID) {
/* frag_start */ true); /* frag_start */ true);
} }
int main(int argc, char** argv) { // Verify KeyIdx field
::testing::InitGoogleTest(&argc, argv); TEST_F(RtpFormatVp8Test, TestKeyIdx) {
int send_bytes = 0;
bool last;
return RUN_ALL_TESTS(); hdr_info_.keyIdx = 17;
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
hdr_info_, *fragmentation_, kAggregate);
// get first and only packet
EXPECT_EQ(0, packetizer.NextPacket(kBufferSize, buffer_, &send_bytes,
&last));
bool first_in_frame = true;
CheckPacket(send_bytes, kPayloadSize + 3, last,
first_in_frame,
/* frag_start */ true);
}
// Verify TID field and KeyIdx field in combination
TEST_F(RtpFormatVp8Test, TestTIDAndKeyIdx) {
int send_bytes = 0;
bool last;
hdr_info_.temporalIdx = 1;
hdr_info_.keyIdx = 5;
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
hdr_info_, *fragmentation_, kAggregate);
// get first and only packet
EXPECT_EQ(0, packetizer.NextPacket(kBufferSize, buffer_, &send_bytes,
&last));
bool first_in_frame = true;
CheckPacket(send_bytes, kPayloadSize + 3, last,
first_in_frame,
/* frag_start */ true);
} }
} // namespace } // namespace

View File

@ -808,26 +808,26 @@ ModuleRTPUtility::RTPPayloadParser::ParseMPEG4(
// VP8 format: // VP8 format:
// //
// Payload descriptor // Payload descriptor
// 0 1 2 3 4 5 6 7 // 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// |X|R|N|S|PartID | (REQUIRED) // |X|R|N|S|PartID | (REQUIRED)
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// X: |I|L|T| RSV-A | (OPTIONAL) // X: |I|L|T|K| RSV | (OPTIONAL)
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// I: | PictureID | (OPTIONAL) // I: | PictureID | (OPTIONAL)
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// L: | TL0PICIDX | (OPTIONAL) // L: | TL0PICIDX | (OPTIONAL)
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// T: | TID | RSV-B | (OPTIONAL) // T/K: | TID | KEYIDX | (OPTIONAL)
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// //
// Payload header (considered part of the actual payload, sent to decoder) // Payload header (considered part of the actual payload, sent to decoder)
// 0 1 2 3 4 5 6 7 // 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// |Size0|H| VER |P| // |Size0|H| VER |P|
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// | ... | // | ... |
// + + // + +
bool bool
ModuleRTPUtility::RTPPayloadParser::ParseVP8(RTPPayload& parsedPacket) const ModuleRTPUtility::RTPPayloadParser::ParseVP8(RTPPayload& parsedPacket) const
@ -912,6 +912,7 @@ int ModuleRTPUtility::RTPPayloadParser::ParseVP8Extension(
vp8->hasPictureID = (*dataPtr & 0x80) ? true : false; // I bit vp8->hasPictureID = (*dataPtr & 0x80) ? true : false; // I bit
vp8->hasTl0PicIdx = (*dataPtr & 0x40) ? true : false; // L bit vp8->hasTl0PicIdx = (*dataPtr & 0x40) ? true : false; // L bit
vp8->hasTID = (*dataPtr & 0x20) ? true : false; // T bit vp8->hasTID = (*dataPtr & 0x20) ? true : false; // T bit
vp8->hasKeyIdx = (*dataPtr & 0x10) ? true : false; // K bit
// Advance dataPtr and decrease remaining payload size // Advance dataPtr and decrease remaining payload size
dataPtr++; dataPtr++;
@ -934,9 +935,9 @@ int ModuleRTPUtility::RTPPayloadParser::ParseVP8Extension(
} }
} }
if (vp8->hasTID) if (vp8->hasTID || vp8->hasKeyIdx)
{ {
if (ParseVP8TID(vp8, &dataPtr, &dataLength, &parsedBytes) != 0) if (ParseVP8TIDAndKeyIdx(vp8, &dataPtr, &dataLength, &parsedBytes) != 0)
{ {
return -1; return -1;
} }
@ -982,14 +983,21 @@ ModuleRTPUtility::RTPPayloadParser::ParseVP8Tl0PicIdx(
return 0; return 0;
} }
int ModuleRTPUtility::RTPPayloadParser::ParseVP8TID( int ModuleRTPUtility::RTPPayloadParser::ParseVP8TIDAndKeyIdx(
RTPPayloadVP8 *vp8, RTPPayloadVP8 *vp8,
const WebRtc_UWord8 **dataPtr, const WebRtc_UWord8 **dataPtr,
int *dataLength, int *dataLength,
int *parsedBytes) const int *parsedBytes) const
{ {
if (*dataLength <= 0) return -1; if (*dataLength <= 0) return -1;
vp8->tID = ((**dataPtr >> 5) & 0x07); if (vp8->hasTID)
{
vp8->tID = ((**dataPtr >> 5) & 0x07);
}
if (vp8->hasKeyIdx)
{
vp8->keyIdx = (**dataPtr & 0x1F);
}
(*dataPtr)++; (*dataPtr)++;
(*parsedBytes)++; (*parsedBytes)++;
(*dataLength)--; (*dataLength)--;

View File

@ -145,9 +145,11 @@ namespace ModuleRTPUtility
bool hasPictureID; bool hasPictureID;
bool hasTl0PicIdx; bool hasTl0PicIdx;
bool hasTID; bool hasTID;
bool hasKeyIdx;
int pictureID; int pictureID;
int tl0PicIdx; int tl0PicIdx;
int tID; int tID;
int keyIdx;
int frameWidth; int frameWidth;
int frameHeight; int frameHeight;
@ -208,10 +210,10 @@ namespace ModuleRTPUtility
int *dataLength, int *dataLength,
int *parsedBytes) const; int *parsedBytes) const;
int ParseVP8TID(RTPPayloadVP8 *vp8, int ParseVP8TIDAndKeyIdx(RTPPayloadVP8 *vp8,
const WebRtc_UWord8 **dataPtr, const WebRtc_UWord8 **dataPtr,
int *dataLength, int *dataLength,
int *parsedBytes) const; int *parsedBytes) const;
int ParseVP8FrameSize(RTPPayload& parsedPacket, int ParseVP8FrameSize(RTPPayload& parsedPacket,
const WebRtc_UWord8 *dataPtr, const WebRtc_UWord8 *dataPtr,

View File

@ -19,44 +19,43 @@
#include "rtp_utility.h" #include "rtp_utility.h"
#include "rtp_format_vp8.h" #include "rtp_format_vp8.h"
namespace { namespace webrtc {
using webrtc::ModuleRTPUtility::RTPPayloadParser; using ModuleRTPUtility::RTPPayloadParser;
using webrtc::ModuleRTPUtility::RTPPayload; using ModuleRTPUtility::RTPPayload;
using webrtc::ModuleRTPUtility::RTPPayloadVP8; using ModuleRTPUtility::RTPPayloadVP8;
using webrtc::RtpVideoCodecTypes;
// Payload descriptor // Payload descriptor
// 0 1 2 3 4 5 6 7 // 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// |X|R|N|S|PartID | (REQUIRED) // |X|R|N|S|PartID | (REQUIRED)
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// X: |I|L|T| RSV-A | (OPTIONAL) // X: |I|L|T|K| RSV | (OPTIONAL)
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// I: | PictureID | (OPTIONAL) // I: | PictureID | (OPTIONAL)
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// L: | TL0PICIDX | (OPTIONAL) // L: | TL0PICIDX | (OPTIONAL)
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// T: | TID | RSV-B | (OPTIONAL) // T/K: | TID | KEYIDX | (OPTIONAL)
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// //
// Payload header // Payload header
// 0 1 2 3 4 5 6 7 // 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// |Size0|H| VER |P| // |Size0|H| VER |P|
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// | Size1 | // | Size1 |
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// | Size2 | // | Size2 |
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// | Bytes 4..N of | // | Bytes 4..N of |
// | VP8 payload | // | VP8 payload |
// : : // : :
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
// | OPTIONAL RTP | // | OPTIONAL RTP |
// | padding | // | padding |
// : : // : :
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
void VerifyBasicHeader(const RTPPayloadVP8 &header, bool N, bool S, int PartID) void VerifyBasicHeader(const RTPPayloadVP8 &header, bool N, bool S, int PartID)
{ {
@ -65,11 +64,13 @@ void VerifyBasicHeader(const RTPPayloadVP8 &header, bool N, bool S, int PartID)
EXPECT_EQ(PartID, header.partitionID); EXPECT_EQ(PartID, header.partitionID);
} }
void VerifyExtensions(const RTPPayloadVP8 &header, bool I, bool L, bool T) void VerifyExtensions(const RTPPayloadVP8 &header,
bool I, bool L, bool T, bool K)
{ {
EXPECT_EQ(I, header.hasPictureID); EXPECT_EQ(I, header.hasPictureID);
EXPECT_EQ(L, header.hasTl0PicIdx); EXPECT_EQ(L, header.hasTl0PicIdx);
EXPECT_EQ(T, header.hasTID); EXPECT_EQ(T, header.hasTID);
EXPECT_EQ(K, header.hasKeyIdx);
} }
TEST(ParseVP8Test, BasicHeader) { TEST(ParseVP8Test, BasicHeader) {
@ -77,16 +78,16 @@ TEST(ParseVP8Test, BasicHeader) {
payload[0] = 0x14; // binary 0001 0100; S = 1, PartID = 4 payload[0] = 0x14; // binary 0001 0100; S = 1, PartID = 4
payload[1] = 0x01; // P frame payload[1] = 0x01; // P frame
RTPPayloadParser rtpPayloadParser(webrtc::kRtpVp8Video, payload, 4, 0); RTPPayloadParser rtpPayloadParser(kRtpVp8Video, payload, 4, 0);
RTPPayload parsedPacket; RTPPayload parsedPacket;
ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket)); ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket));
EXPECT_EQ(webrtc::ModuleRTPUtility::kPFrame, parsedPacket.frameType); EXPECT_EQ(ModuleRTPUtility::kPFrame, parsedPacket.frameType);
EXPECT_EQ(webrtc::kRtpVp8Video, parsedPacket.type); EXPECT_EQ(kRtpVp8Video, parsedPacket.type);
VerifyBasicHeader(parsedPacket.info.VP8, 0 /*N*/, 1 /*S*/, 4 /*PartID*/); VerifyBasicHeader(parsedPacket.info.VP8, 0 /*N*/, 1 /*S*/, 4 /*PartID*/);
VerifyExtensions(parsedPacket.info.VP8, 0 /*I*/, 0 /*L*/, 0 /*T*/); VerifyExtensions(parsedPacket.info.VP8, 0 /*I*/, 0 /*L*/, 0 /*T*/, 0 /*K*/);
EXPECT_EQ(payload + 1, parsedPacket.info.VP8.data); EXPECT_EQ(payload + 1, parsedPacket.info.VP8.data);
EXPECT_EQ(4 - 1, parsedPacket.info.VP8.dataLength); EXPECT_EQ(4 - 1, parsedPacket.info.VP8.dataLength);
@ -98,16 +99,16 @@ TEST(ParseVP8Test, PictureID) {
payload[1] = 0x80; payload[1] = 0x80;
payload[2] = 17; payload[2] = 17;
RTPPayloadParser rtpPayloadParser(webrtc::kRtpVp8Video, payload, 10, 0); RTPPayloadParser rtpPayloadParser(kRtpVp8Video, payload, 10, 0);
RTPPayload parsedPacket; RTPPayload parsedPacket;
ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket)); ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket));
EXPECT_EQ(webrtc::ModuleRTPUtility::kPFrame, parsedPacket.frameType); EXPECT_EQ(ModuleRTPUtility::kPFrame, parsedPacket.frameType);
EXPECT_EQ(webrtc::kRtpVp8Video, parsedPacket.type); EXPECT_EQ(kRtpVp8Video, parsedPacket.type);
VerifyBasicHeader(parsedPacket.info.VP8, 1 /*N*/, 0 /*S*/, 0 /*PartID*/); VerifyBasicHeader(parsedPacket.info.VP8, 1 /*N*/, 0 /*S*/, 0 /*PartID*/);
VerifyExtensions(parsedPacket.info.VP8, 1 /*I*/, 0 /*L*/, 0 /*T*/); VerifyExtensions(parsedPacket.info.VP8, 1 /*I*/, 0 /*L*/, 0 /*T*/, 0 /*K*/);
EXPECT_EQ(17, parsedPacket.info.VP8.pictureID); EXPECT_EQ(17, parsedPacket.info.VP8.pictureID);
@ -118,12 +119,12 @@ TEST(ParseVP8Test, PictureID) {
// Re-use payload, but change to long PictureID // Re-use payload, but change to long PictureID
payload[2] = 0x80 | 17; payload[2] = 0x80 | 17;
payload[3] = 17; payload[3] = 17;
RTPPayloadParser rtpPayloadParser2(webrtc::kRtpVp8Video, payload, 10, 0); RTPPayloadParser rtpPayloadParser2(kRtpVp8Video, payload, 10, 0);
ASSERT_TRUE(rtpPayloadParser2.Parse(parsedPacket)); ASSERT_TRUE(rtpPayloadParser2.Parse(parsedPacket));
VerifyBasicHeader(parsedPacket.info.VP8, 1 /*N*/, 0 /*S*/, 0 /*PartID*/); VerifyBasicHeader(parsedPacket.info.VP8, 1 /*N*/, 0 /*S*/, 0 /*PartID*/);
VerifyExtensions(parsedPacket.info.VP8, 1 /*I*/, 0 /*L*/, 0 /*T*/); VerifyExtensions(parsedPacket.info.VP8, 1 /*I*/, 0 /*L*/, 0 /*T*/, 0 /*K*/);
EXPECT_EQ((17<<8) + 17, parsedPacket.info.VP8.pictureID); EXPECT_EQ((17<<8) + 17, parsedPacket.info.VP8.pictureID);
@ -137,16 +138,16 @@ TEST(ParseVP8Test, Tl0PicIdx) {
payload[1] = 0x40; payload[1] = 0x40;
payload[2] = 17; payload[2] = 17;
RTPPayloadParser rtpPayloadParser(webrtc::kRtpVp8Video, payload, 13, 0); RTPPayloadParser rtpPayloadParser(kRtpVp8Video, payload, 13, 0);
RTPPayload parsedPacket; RTPPayload parsedPacket;
ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket)); ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket));
EXPECT_EQ(webrtc::ModuleRTPUtility::kIFrame, parsedPacket.frameType); EXPECT_EQ(ModuleRTPUtility::kIFrame, parsedPacket.frameType);
EXPECT_EQ(webrtc::kRtpVp8Video, parsedPacket.type); EXPECT_EQ(kRtpVp8Video, parsedPacket.type);
VerifyBasicHeader(parsedPacket.info.VP8, 0 /*N*/, 1 /*S*/, 0 /*PartID*/); VerifyBasicHeader(parsedPacket.info.VP8, 0 /*N*/, 1 /*S*/, 0 /*PartID*/);
VerifyExtensions(parsedPacket.info.VP8, 0 /*I*/, 1 /*L*/, 0 /*T*/); VerifyExtensions(parsedPacket.info.VP8, 0 /*I*/, 1 /*L*/, 0 /*T*/, 0 /*K*/);
EXPECT_EQ(17, parsedPacket.info.VP8.tl0PicIdx); EXPECT_EQ(17, parsedPacket.info.VP8.tl0PicIdx);
@ -160,16 +161,16 @@ TEST(ParseVP8Test, TID) {
payload[1] = 0x20; payload[1] = 0x20;
payload[2] = 0x40; payload[2] = 0x40;
RTPPayloadParser rtpPayloadParser(webrtc::kRtpVp8Video, payload, 10, 0); RTPPayloadParser rtpPayloadParser(kRtpVp8Video, payload, 10, 0);
RTPPayload parsedPacket; RTPPayload parsedPacket;
ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket)); ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket));
EXPECT_EQ(webrtc::ModuleRTPUtility::kPFrame, parsedPacket.frameType); EXPECT_EQ(ModuleRTPUtility::kPFrame, parsedPacket.frameType);
EXPECT_EQ(webrtc::kRtpVp8Video, parsedPacket.type); EXPECT_EQ(kRtpVp8Video, parsedPacket.type);
VerifyBasicHeader(parsedPacket.info.VP8, 0 /*N*/, 0 /*S*/, 8 /*PartID*/); VerifyBasicHeader(parsedPacket.info.VP8, 0 /*N*/, 0 /*S*/, 8 /*PartID*/);
VerifyExtensions(parsedPacket.info.VP8, 0 /*I*/, 0 /*L*/, 1 /*T*/); VerifyExtensions(parsedPacket.info.VP8, 0 /*I*/, 0 /*L*/, 1 /*T*/, 0 /*K*/);
EXPECT_EQ(2, parsedPacket.info.VP8.tID); EXPECT_EQ(2, parsedPacket.info.VP8.tID);
@ -177,29 +178,53 @@ TEST(ParseVP8Test, TID) {
EXPECT_EQ(10 - 3, parsedPacket.info.VP8.dataLength); EXPECT_EQ(10 - 3, parsedPacket.info.VP8.dataLength);
} }
TEST(ParseVP8Test, KeyIdx) {
WebRtc_UWord8 payload[10] = {0};
payload[0] = 0x88;
payload[1] = 0x10; // K = 1
payload[2] = 0x11; // KEYIDX = 17 decimal
RTPPayloadParser rtpPayloadParser(kRtpVp8Video, payload, 10, 0);
RTPPayload parsedPacket;
ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket));
EXPECT_EQ(ModuleRTPUtility::kPFrame, parsedPacket.frameType);
EXPECT_EQ(kRtpVp8Video, parsedPacket.type);
VerifyBasicHeader(parsedPacket.info.VP8, 0 /*N*/, 0 /*S*/, 8 /*PartID*/);
VerifyExtensions(parsedPacket.info.VP8, 0 /*I*/, 0 /*L*/, 0 /*T*/, 1 /*K*/);
EXPECT_EQ(17, parsedPacket.info.VP8.keyIdx);
EXPECT_EQ(payload + 3, parsedPacket.info.VP8.data);
EXPECT_EQ(10 - 3, parsedPacket.info.VP8.dataLength);
}
TEST(ParseVP8Test, MultipleExtensions) { TEST(ParseVP8Test, MultipleExtensions) {
WebRtc_UWord8 payload[10] = {0}; WebRtc_UWord8 payload[10] = {0};
payload[0] = 0x88; payload[0] = 0x88;
payload[1] = 0x80 | 0x40 | 0x20; payload[1] = 0x80 | 0x40 | 0x20 | 0x10;
payload[2] = 0x80 | 17; // PictureID, high 7 bits payload[2] = 0x80 | 17; // PictureID, high 7 bits
payload[3] = 17; // PictureID, low 8 bits payload[3] = 17; // PictureID, low 8 bits
payload[4] = 42; // Tl0PicIdx payload[4] = 42; // Tl0PicIdx
payload[5] = 0x40; // TID payload[5] = 0x40 | 0x11; // TID + KEYIDX
RTPPayloadParser rtpPayloadParser(webrtc::kRtpVp8Video, payload, 10, 0); RTPPayloadParser rtpPayloadParser(kRtpVp8Video, payload, 10, 0);
RTPPayload parsedPacket; RTPPayload parsedPacket;
ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket)); ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket));
EXPECT_EQ(webrtc::ModuleRTPUtility::kPFrame, parsedPacket.frameType); EXPECT_EQ(ModuleRTPUtility::kPFrame, parsedPacket.frameType);
EXPECT_EQ(webrtc::kRtpVp8Video, parsedPacket.type); EXPECT_EQ(kRtpVp8Video, parsedPacket.type);
VerifyBasicHeader(parsedPacket.info.VP8, 0 /*N*/, 0 /*S*/, 8 /*PartID*/); VerifyBasicHeader(parsedPacket.info.VP8, 0 /*N*/, 0 /*S*/, 8 /*PartID*/);
VerifyExtensions(parsedPacket.info.VP8, 1 /*I*/, 1 /*L*/, 1 /*T*/); VerifyExtensions(parsedPacket.info.VP8, 1 /*I*/, 1 /*L*/, 1 /*T*/, 1 /*K*/);
EXPECT_EQ((17<<8) + 17, parsedPacket.info.VP8.pictureID); EXPECT_EQ((17<<8) + 17, parsedPacket.info.VP8.pictureID);
EXPECT_EQ(42, parsedPacket.info.VP8.tl0PicIdx); EXPECT_EQ(42, parsedPacket.info.VP8.tl0PicIdx);
EXPECT_EQ(2, parsedPacket.info.VP8.tID); EXPECT_EQ(2, parsedPacket.info.VP8.tID);
EXPECT_EQ(17, parsedPacket.info.VP8.keyIdx);
EXPECT_EQ(payload + 6, parsedPacket.info.VP8.data); EXPECT_EQ(payload + 6, parsedPacket.info.VP8.data);
EXPECT_EQ(10 - 6, parsedPacket.info.VP8.dataLength); EXPECT_EQ(10 - 6, parsedPacket.info.VP8.dataLength);
@ -208,19 +233,16 @@ TEST(ParseVP8Test, MultipleExtensions) {
TEST(ParseVP8Test, TooShortHeader) { TEST(ParseVP8Test, TooShortHeader) {
WebRtc_UWord8 payload[4] = {0}; WebRtc_UWord8 payload[4] = {0};
payload[0] = 0x88; payload[0] = 0x88;
payload[1] = 0x80 | 0x40 | 0x20; // All extensions are enabled payload[1] = 0x80 | 0x40 | 0x20 | 0x10; // All extensions are enabled
payload[2] = 0x80 | 17; //... but only 2 bytes PictureID is provided payload[2] = 0x80 | 17; //... but only 2 bytes PictureID is provided
payload[3] = 17; // PictureID, low 8 bits payload[3] = 17; // PictureID, low 8 bits
RTPPayloadParser rtpPayloadParser(webrtc::kRtpVp8Video, payload, 4, 0); RTPPayloadParser rtpPayloadParser(kRtpVp8Video, payload, 4, 0);
RTPPayload parsedPacket; RTPPayload parsedPacket;
EXPECT_FALSE(rtpPayloadParser.Parse(parsedPacket)); EXPECT_FALSE(rtpPayloadParser.Parse(parsedPacket));
} }
using webrtc::RtpFormatVp8;
using webrtc::RTPVideoHeaderVP8;
TEST(ParseVP8Test, TestWithPacketizer) { TEST(ParseVP8Test, TestWithPacketizer) {
WebRtc_UWord8 payload[10] = {0}; WebRtc_UWord8 payload[10] = {0};
WebRtc_UWord8 packet[20] = {0}; WebRtc_UWord8 packet[20] = {0};
@ -228,21 +250,21 @@ TEST(ParseVP8Test, TestWithPacketizer) {
inputHeader.nonReference = true; inputHeader.nonReference = true;
inputHeader.pictureId = 300; inputHeader.pictureId = 300;
inputHeader.temporalIdx = 1; inputHeader.temporalIdx = 1;
inputHeader.tl0PicIdx = -1; // disable inputHeader.tl0PicIdx = kNoTl0PicIdx; // disable
inputHeader.keyIdx = 31;
RtpFormatVp8 packetizer = RtpFormatVp8(payload, 10, inputHeader); RtpFormatVp8 packetizer = RtpFormatVp8(payload, 10, inputHeader);
bool last; bool last;
int send_bytes; int send_bytes;
ASSERT_EQ(0, packetizer.NextPacket(20, packet, &send_bytes, &last)); ASSERT_EQ(0, packetizer.NextPacket(20, packet, &send_bytes, &last));
ASSERT_TRUE(last); ASSERT_TRUE(last);
RTPPayloadParser rtpPayloadParser(webrtc::kRtpVp8Video, packet, send_bytes, RTPPayloadParser rtpPayloadParser(kRtpVp8Video, packet, send_bytes, 0);
0);
RTPPayload parsedPacket; RTPPayload parsedPacket;
ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket)); ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket));
EXPECT_EQ(webrtc::ModuleRTPUtility::kIFrame, parsedPacket.frameType); EXPECT_EQ(ModuleRTPUtility::kIFrame, parsedPacket.frameType);
EXPECT_EQ(webrtc::kRtpVp8Video, parsedPacket.type); EXPECT_EQ(kRtpVp8Video, parsedPacket.type);
VerifyBasicHeader(parsedPacket.info.VP8, VerifyBasicHeader(parsedPacket.info.VP8,
inputHeader.nonReference /*N*/, inputHeader.nonReference /*N*/,
@ -251,19 +273,15 @@ TEST(ParseVP8Test, TestWithPacketizer) {
VerifyExtensions(parsedPacket.info.VP8, VerifyExtensions(parsedPacket.info.VP8,
1 /*I*/, 1 /*I*/,
0 /*L*/, 0 /*L*/,
1 /*T*/); 1 /*T*/,
1 /*K*/);
EXPECT_EQ(inputHeader.pictureId, parsedPacket.info.VP8.pictureID); EXPECT_EQ(inputHeader.pictureId, parsedPacket.info.VP8.pictureID);
EXPECT_EQ(inputHeader.temporalIdx, parsedPacket.info.VP8.tID); EXPECT_EQ(inputHeader.temporalIdx, parsedPacket.info.VP8.tID);
EXPECT_EQ(inputHeader.keyIdx, parsedPacket.info.VP8.keyIdx);
EXPECT_EQ(packet + 5, parsedPacket.info.VP8.data); EXPECT_EQ(packet + 5, parsedPacket.info.VP8.data);
EXPECT_EQ(send_bytes - 5, parsedPacket.info.VP8.dataLength); EXPECT_EQ(send_bytes - 5, parsedPacket.info.VP8.dataLength);
} }
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
} // namespace } // namespace