From 6f2c0168f0611bdff18c7659c63f09d873aacd3e Mon Sep 17 00:00:00 2001 From: "henrik.lundin@webrtc.org" Date: Thu, 24 Nov 2011 12:52:40 +0000 Subject: [PATCH] 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 --- src/modules/interface/module_common_types.h | 3 + src/modules/rtp_rtcp/source/rtp_format_vp8.cc | 66 ++++--- src/modules/rtp_rtcp/source/rtp_format_vp8.h | 12 +- .../source/rtp_format_vp8_unittest.cc | 106 ++++++++--- src/modules/rtp_rtcp/source/rtp_utility.cc | 52 +++--- src/modules/rtp_rtcp/source/rtp_utility.h | 10 +- .../rtp_rtcp/source/rtp_utility_test.cc | 168 ++++++++++-------- 7 files changed, 259 insertions(+), 158 deletions(-) diff --git a/src/modules/interface/module_common_types.h b/src/modules/interface/module_common_types.h index 2070029ca2..6cb19481bb 100644 --- a/src/modules/interface/module_common_types.h +++ b/src/modules/interface/module_common_types.h @@ -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 diff --git a/src/modules/rtp_rtcp/source/rtp_format_vp8.cc b/src/modules/rtp_rtcp/source/rtp_format_vp8.cc index 6de1dafbf7..3e2446cb4f 100644 --- a/src/modules/rtp_rtcp/source/rtp_format_vp8.cc +++ b/src/modules/rtp_rtcp/source/rtp_format_vp8.cc @@ -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); diff --git a/src/modules/rtp_rtcp/source/rtp_format_vp8.h b/src/modules/rtp_rtcp/source/rtp_format_vp8.h index 48905d90ef..f5cc2b3e4f 100644 --- a/src/modules/rtp_rtcp/source/rtp_format_vp8.h +++ b/src/modules/rtp_rtcp/source/rtp_format_vp8.h @@ -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); } diff --git a/src/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc b/src/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc index 44edf58564..f87ef2277f 100644 --- a/src/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc +++ b/src/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc @@ -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 diff --git a/src/modules/rtp_rtcp/source/rtp_utility.cc b/src/modules/rtp_rtcp/source/rtp_utility.cc index 08be8a07d7..f5410ef203 100644 --- a/src/modules/rtp_rtcp/source/rtp_utility.cc +++ b/src/modules/rtp_rtcp/source/rtp_utility.cc @@ -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)--; diff --git a/src/modules/rtp_rtcp/source/rtp_utility.h b/src/modules/rtp_rtcp/source/rtp_utility.h index 72127ce262..b1865ad2c4 100644 --- a/src/modules/rtp_rtcp/source/rtp_utility.h +++ b/src/modules/rtp_rtcp/source/rtp_utility.h @@ -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, diff --git a/src/modules/rtp_rtcp/source/rtp_utility_test.cc b/src/modules/rtp_rtcp/source/rtp_utility_test.cc index 1031eb109c..8426082e67 100644 --- a/src/modules/rtp_rtcp/source/rtp_utility_test.cc +++ b/src/modules/rtp_rtcp/source/rtp_utility_test.cc @@ -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