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

View File

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

View File

@ -84,9 +84,11 @@ private:
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;
// Calculate size of next chunk to send. Returns 0 if none can be sent.
int CalcNextSize(int max_payload_len, int remaining_bytes,
@ -115,10 +117,11 @@ private:
int WriteTl0PicIdxFields(WebRtc_UWord8* x_field, WebRtc_UWord8* buffer,
int buffer_length, int* extension_length) const;
// Set the T bit in the x_field, and write TID to the appropriate
// position in buffer. The function returns 0 on success, -1 otherwise.
int WriteTIDFields(WebRtc_UWord8* x_field, WebRtc_UWord8* buffer,
int buffer_length, int* extension_length) const;
// Set the T and K bits in the x_field, and write TID and KeyIdx to the
// appropriate position in buffer. The function returns 0 on success,
// -1 otherwise.
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
// 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.
bool XFieldPresent() const;
bool TIDFieldPresent() const;
bool KeyIdxFieldPresent() const;
bool TL0PicIdxFieldPresent() const;
bool PictureIdPresent() const { return (PictureIdLength() > 0); }

View File

@ -18,11 +18,7 @@
#include "typedefs.h"
#include "rtp_format_vp8.h"
namespace {
using webrtc::RTPFragmentationHeader;
using webrtc::RtpFormatVp8;
using webrtc::RTPVideoHeaderVP8;
namespace webrtc {
const int kPayloadSize = 30;
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 CheckPictureID();
void CheckTl0PicIdx();
void CheckTID();
void CheckTIDAndKeyIdx();
void CheckPayload(int payload_end);
void CheckLast(bool last) const;
void CheckPacket(int send_bytes, int expect_bytes, bool last,
@ -66,10 +62,11 @@ void RtpFormatVp8Test::SetUp() {
fragmentation_->fragmentationOffset[1] = 10;
fragmentation_->fragmentationOffset[2] = 20;
hdr_info_.pictureId = webrtc::kNoPictureId;
hdr_info_.pictureId = kNoPictureId;
hdr_info_.nonReference = false;
hdr_info_.temporalIdx = webrtc::kNoTemporalIdx;
hdr_info_.tl0PicIdx = webrtc::kNoTl0PicIdx;
hdr_info_.temporalIdx = kNoTemporalIdx;
hdr_info_.tl0PicIdx = kNoTl0PicIdx;
hdr_info_.keyIdx = kNoKeyIdx;
}
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_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,
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
if (hdr_info_.pictureId != webrtc::kNoPictureId ||
hdr_info_.temporalIdx != webrtc::kNoTemporalIdx ||
hdr_info_.tl0PicIdx != webrtc::kNoTl0PicIdx)
if (hdr_info_.pictureId != kNoPictureId ||
hdr_info_.temporalIdx != kNoTemporalIdx ||
hdr_info_.tl0PicIdx != kNoTl0PicIdx ||
hdr_info_.keyIdx != kNoKeyIdx)
{
EXPECT_BIT_X_EQ(buffer_[0], 1);
++payload_start_;
CheckPictureID();
CheckTl0PicIdx();
CheckTID();
CheckTIDAndKeyIdx();
}
else
{
@ -137,7 +139,7 @@ void RtpFormatVp8Test::CheckHeader(bool first_in_frame, bool frag_start,
void RtpFormatVp8Test::CheckPictureID()
{
if (hdr_info_.pictureId != webrtc::kNoPictureId)
if (hdr_info_.pictureId != kNoPictureId)
{
EXPECT_BIT_I_EQ(buffer_[1], 1);
if (hdr_info_.pictureId > 0x7F)
@ -165,7 +167,7 @@ void RtpFormatVp8Test::CheckPictureID()
void RtpFormatVp8Test::CheckTl0PicIdx()
{
if (hdr_info_.tl0PicIdx != webrtc::kNoTl0PicIdx)
if (hdr_info_.tl0PicIdx != kNoTl0PicIdx)
{
EXPECT_BIT_L_EQ(buffer_[1], 1);
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_TID_EQ(buffer_[payload_start_], hdr_info_.temporalIdx);
EXPECT_EQ(buffer_[payload_start_] & 0x1F, 0);
++payload_start_;
}
else
{
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)
@ -232,7 +251,7 @@ TEST_F(RtpFormatVp8Test, TestStrictMode)
hdr_info_.pictureId = 200; // > 0x7F should produce 2-byte PictureID
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
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
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
hdr_info_, *fragmentation_, webrtc::kAggregate);
hdr_info_, *fragmentation_, kAggregate);
// get first packet
// first part of first partition (balanced fragments are expected)
@ -328,9 +347,9 @@ TEST_F(RtpFormatVp8Test, TestSloppyMode)
bool last;
bool first_in_frame = true;
hdr_info_.pictureId = webrtc::kNoPictureId; // no PictureID
hdr_info_.pictureId = kNoPictureId; // no PictureID
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
hdr_info_, *fragmentation_, webrtc::kSloppy);
hdr_info_, *fragmentation_, kSloppy);
// get first packet
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
@ -431,7 +450,7 @@ TEST_F(RtpFormatVp8Test, TestTl0PicIdxAndTID) {
hdr_info_.tl0PicIdx = 117;
hdr_info_.temporalIdx = 2;
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
hdr_info_, *fragmentation_, webrtc::kAggregate);
hdr_info_, *fragmentation_, kAggregate);
// get first and only packet
EXPECT_EQ(0, packetizer.NextPacket(kBufferSize, buffer_, &send_bytes,
@ -442,10 +461,41 @@ TEST_F(RtpFormatVp8Test, TestTl0PicIdxAndTID) {
/* frag_start */ true);
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
// Verify KeyIdx field
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

View File

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

View File

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

View File

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