From 730d2707713c4240070af17e56edd10d039bafd2 Mon Sep 17 00:00:00 2001 From: "pbos@webrtc.org" Date: Mon, 29 Sep 2014 08:00:22 +0000 Subject: [PATCH] Remove callback from RtpDepacketizer::Parse(). BUG= R=pbos@webrtc.org, stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/30489004 Patch from Changbin Shao . git-svn-id: http://webrtc.googlecode.com/svn/trunk@7318 4adac7df-926f-26a2-2b94-8c16560cd09d --- webrtc/modules/rtp_rtcp/source/rtp_format.cc | 9 +- webrtc/modules/rtp_rtcp/source/rtp_format.h | 15 +- .../rtp_rtcp/source/rtp_format_h264.cc | 21 +- .../modules/rtp_rtcp/source/rtp_format_h264.h | 10 +- .../source/rtp_format_h264_unittest.cc | 115 ++++++----- .../source/rtp_format_video_generic.cc | 19 +- .../source/rtp_format_video_generic.h | 11 +- .../modules/rtp_rtcp/source/rtp_format_vp8.cc | 189 ++++++++---------- .../modules/rtp_rtcp/source/rtp_format_vp8.h | 10 +- .../source/rtp_format_vp8_unittest.cc | 131 ++++++------ .../rtp_rtcp/source/rtp_receiver_video.cc | 15 +- 11 files changed, 263 insertions(+), 282 deletions(-) diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format.cc b/webrtc/modules/rtp_rtcp/source/rtp_format.cc index afb6c06d1b..d03e38c387 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_format.cc @@ -33,15 +33,14 @@ RtpPacketizer* RtpPacketizer::Create(RtpVideoCodecTypes type, return NULL; } -RtpDepacketizer* RtpDepacketizer::Create(RtpVideoCodecTypes type, - RtpData* const callback) { +RtpDepacketizer* RtpDepacketizer::Create(RtpVideoCodecTypes type) { switch (type) { case kRtpVideoH264: - return new RtpDepacketizerH264(callback); + return new RtpDepacketizerH264(); case kRtpVideoVp8: - return new RtpDepacketizerVp8(callback); + return new RtpDepacketizerVp8(); case kRtpVideoGeneric: - return new RtpDepacketizerGeneric(callback); + return new RtpDepacketizerGeneric(); case kRtpVideoNone: assert(false); } diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format.h b/webrtc/modules/rtp_rtcp/source/rtp_format.h index 07dc225c7f..faef7a0b50 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_format.h @@ -52,12 +52,21 @@ class RtpPacketizer { class RtpDepacketizer { public: - static RtpDepacketizer* Create(RtpVideoCodecTypes type, - RtpData* const callback); + struct ParsedPayload { + explicit ParsedPayload(WebRtcRTPHeader* rtp_header) + : payload(NULL), payload_length(0), header(rtp_header) {} + + const uint8_t* payload; + size_t payload_length; + WebRtcRTPHeader* header; + }; + + static RtpDepacketizer* Create(RtpVideoCodecTypes type); virtual ~RtpDepacketizer() {} - virtual bool Parse(WebRtcRTPHeader* rtp_header, + // Parses the RTP payload, parsed result will be saved in |parsed_payload|. + virtual bool Parse(ParsedPayload* parsed_payload, const uint8_t* payload_data, size_t payload_data_length) = 0; }; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc b/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc index 6b25f9c4d3..b6af1ada6f 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc @@ -290,29 +290,24 @@ std::string RtpPacketizerH264::ToString() { return "RtpPacketizerH264"; } -RtpDepacketizerH264::RtpDepacketizerH264(RtpData* const callback) - : callback_(callback) { -} - -bool RtpDepacketizerH264::Parse(WebRtcRTPHeader* rtp_header, +bool RtpDepacketizerH264::Parse(ParsedPayload* parsed_payload, const uint8_t* payload_data, size_t payload_data_length) { + assert(parsed_payload != NULL); uint8_t nal_type = payload_data[0] & kTypeMask; size_t offset = 0; if (nal_type == kFuA) { // Fragmented NAL units (FU-A). - ParseFuaNalu(rtp_header, payload_data, payload_data_length, &offset); + ParseFuaNalu( + parsed_payload->header, payload_data, payload_data_length, &offset); } else { // We handle STAP-A and single NALU's the same way here. The jitter buffer // will depacketize the STAP-A into NAL units later. - ParseSingleNalu(rtp_header, payload_data, payload_data_length); - } - if (callback_->OnReceivedPayloadData(payload_data + offset, - payload_data_length - offset, - rtp_header) != 0) { - return false; + ParseSingleNalu(parsed_payload->header, payload_data, payload_data_length); } + + parsed_payload->payload = payload_data + offset; + parsed_payload->payload_length = payload_data_length - offset; return true; } - } // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h b/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h index 830d765c47..ba293c853f 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h @@ -12,6 +12,7 @@ #define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H264_H_ #include +#include #include "webrtc/modules/rtp_rtcp/source/rtp_format.h" @@ -92,18 +93,11 @@ class RtpPacketizerH264 : public RtpPacketizer { // Depacketizer for H264. class RtpDepacketizerH264 : public RtpDepacketizer { public: - explicit RtpDepacketizerH264(RtpData* const callback); - virtual ~RtpDepacketizerH264() {} - virtual bool Parse(WebRtcRTPHeader* rtp_header, + virtual bool Parse(ParsedPayload* parsed_payload, const uint8_t* payload_data, size_t payload_data_length) OVERRIDE; - - private: - RtpData* const callback_; - - DISALLOW_COPY_AND_ASSIGN(RtpDepacketizerH264); }; } // namespace webrtc #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H264_H_ diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc index fc30a0626e..fb29b5a65c 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc @@ -17,12 +17,6 @@ #include "webrtc/modules/rtp_rtcp/source/rtp_format.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" -using ::testing::_; -using ::testing::Args; -using ::testing::ElementsAreArray; -using ::testing::Return; -using ::testing::SaveArgPointee; - namespace webrtc { namespace { const size_t kMaxPayloadSize = 1200; @@ -211,8 +205,8 @@ TEST(RtpPacketizerH264Test, TestSingleNaluTwoPackets) { } TEST(RtpPacketizerH264Test, TestStapA) { - const size_t kFrameSize = kMaxPayloadSize - 3 * kLengthFieldLength - - kNalHeaderSize; + const size_t kFrameSize = + kMaxPayloadSize - 3 * kLengthFieldLength - kNalHeaderSize; uint8_t frame[kFrameSize] = {0x07, 0xFF, // F=0, NRI=0, Type=7. 0x08, 0xFF, // F=0, NRI=0, Type=8. 0x05}; // F=0, NRI=0, Type=5. @@ -273,8 +267,8 @@ TEST(RtpPacketizerH264Test, TestTooSmallForStapAHeaders) { ASSERT_TRUE(packetizer->NextPacket(packet, &length, &last)); size_t expected_packet_size = kNalHeaderSize; for (size_t i = 0; i < 2; ++i) { - expected_packet_size += kLengthFieldLength + - fragmentation.fragmentationLength[i]; + expected_packet_size += + kLengthFieldLength + fragmentation.fragmentationLength[i]; } ASSERT_EQ(expected_packet_size, length); EXPECT_FALSE(last); @@ -388,21 +382,19 @@ TEST(RtpPacketizerH264Test, TestFUABig) { class RtpDepacketizerH264Test : public ::testing::Test { protected: RtpDepacketizerH264Test() - : callback_(), - depacketizer_(RtpDepacketizer::Create(kRtpVideoH264, &callback_)) { - memset(&last_header_, 0, sizeof(last_header_)); + : depacketizer_(RtpDepacketizer::Create(kRtpVideoH264)) {} + + void ExpectPacket(RtpDepacketizer::ParsedPayload* parsed_payload, + const uint8_t* data, + size_t length) { + ASSERT_TRUE(parsed_payload != NULL); + EXPECT_THAT(std::vector( + parsed_payload->payload, + parsed_payload->payload + parsed_payload->payload_length), + ::testing::ElementsAreArray(data, length)); } - void ExpectPacket(const uint8_t* data, size_t length) { - EXPECT_CALL(callback_, OnReceivedPayloadData(_, length, _)) - .With(Args<0, 1>(ElementsAreArray(data, length))) - .Times(1) - .WillRepeatedly(DoAll(SaveArgPointee<2>(&last_header_), Return(0))); - } - - MockRtpData callback_; scoped_ptr depacketizer_; - WebRtcRTPHeader last_header_; }; TEST_F(RtpDepacketizerH264Test, TestSingleNalu) { @@ -410,12 +402,14 @@ TEST_F(RtpDepacketizerH264Test, TestSingleNalu) { WebRtcRTPHeader expected_header; memset(&expected_header, 0, sizeof(expected_header)); - ExpectPacket(packet, sizeof(packet)); - EXPECT_TRUE(depacketizer_->Parse(&expected_header, packet, sizeof(packet))); - EXPECT_EQ(kVideoFrameKey, last_header_.frameType); - EXPECT_TRUE(last_header_.type.Video.isFirstPacket); - EXPECT_TRUE(last_header_.type.Video.codecHeader.H264.single_nalu); - EXPECT_FALSE(last_header_.type.Video.codecHeader.H264.stap_a); + RtpDepacketizer::ParsedPayload payload(&expected_header); + + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket(&payload, packet, sizeof(packet)); + EXPECT_EQ(kVideoFrameKey, payload.header->frameType); + EXPECT_TRUE(payload.header->type.Video.isFirstPacket); + EXPECT_TRUE(payload.header->type.Video.codecHeader.H264.single_nalu); + EXPECT_FALSE(payload.header->type.Video.codecHeader.H264.stap_a); } TEST_F(RtpDepacketizerH264Test, TestStapAKey) { @@ -426,12 +420,14 @@ TEST_F(RtpDepacketizerH264Test, TestStapAKey) { WebRtcRTPHeader expected_header; memset(&expected_header, 0, sizeof(expected_header)); - ExpectPacket(packet, sizeof(packet)); - EXPECT_TRUE(depacketizer_->Parse(&expected_header, packet, sizeof(packet))); - EXPECT_EQ(kVideoFrameKey, last_header_.frameType); - EXPECT_TRUE(last_header_.type.Video.isFirstPacket); - EXPECT_TRUE(last_header_.type.Video.codecHeader.H264.single_nalu); - EXPECT_TRUE(last_header_.type.Video.codecHeader.H264.stap_a); + RtpDepacketizer::ParsedPayload payload(&expected_header); + + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket(&payload, packet, sizeof(packet)); + EXPECT_EQ(kVideoFrameKey, payload.header->frameType); + EXPECT_TRUE(payload.header->type.Video.isFirstPacket); + EXPECT_TRUE(payload.header->type.Video.codecHeader.H264.single_nalu); + EXPECT_TRUE(payload.header->type.Video.codecHeader.H264.stap_a); } TEST_F(RtpDepacketizerH264Test, TestStapADelta) { @@ -442,12 +438,14 @@ TEST_F(RtpDepacketizerH264Test, TestStapADelta) { WebRtcRTPHeader expected_header; memset(&expected_header, 0, sizeof(expected_header)); - ExpectPacket(packet, sizeof(packet)); - EXPECT_TRUE(depacketizer_->Parse(&expected_header, packet, sizeof(packet))); - EXPECT_EQ(kVideoFrameDelta, last_header_.frameType); - EXPECT_TRUE(last_header_.type.Video.isFirstPacket); - EXPECT_TRUE(last_header_.type.Video.codecHeader.H264.single_nalu); - EXPECT_TRUE(last_header_.type.Video.codecHeader.H264.stap_a); + RtpDepacketizer::ParsedPayload payload(&expected_header); + + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket(&payload, packet, sizeof(packet)); + EXPECT_EQ(kVideoFrameDelta, payload.header->frameType); + EXPECT_TRUE(payload.header->type.Video.isFirstPacket); + EXPECT_TRUE(payload.header->type.Video.codecHeader.H264.single_nalu); + EXPECT_TRUE(payload.header->type.Video.codecHeader.H264.stap_a); } TEST_F(RtpDepacketizerH264Test, TestFuA) { @@ -474,30 +472,31 @@ TEST_F(RtpDepacketizerH264Test, TestFuA) { WebRtcRTPHeader expected_header; memset(&expected_header, 0, sizeof(expected_header)); + RtpDepacketizer::ParsedPayload payload(&expected_header); // We expect that the first packet is one byte shorter since the FU-A header // has been replaced by the original nal header. - ExpectPacket(kExpected1, sizeof(kExpected1)); - EXPECT_TRUE(depacketizer_->Parse(&expected_header, packet1, sizeof(packet1))); - EXPECT_EQ(kVideoFrameKey, last_header_.frameType); - EXPECT_TRUE(last_header_.type.Video.isFirstPacket); - EXPECT_FALSE(last_header_.type.Video.codecHeader.H264.single_nalu); - EXPECT_FALSE(last_header_.type.Video.codecHeader.H264.stap_a); + ASSERT_TRUE(depacketizer_->Parse(&payload, packet1, sizeof(packet1))); + ExpectPacket(&payload, kExpected1, sizeof(kExpected1)); + EXPECT_EQ(kVideoFrameKey, payload.header->frameType); + EXPECT_TRUE(payload.header->type.Video.isFirstPacket); + EXPECT_FALSE(payload.header->type.Video.codecHeader.H264.single_nalu); + EXPECT_FALSE(payload.header->type.Video.codecHeader.H264.stap_a); // Following packets will be 2 bytes shorter since they will only be appended // onto the first packet. - ExpectPacket(kExpected2, sizeof(kExpected2)); - EXPECT_TRUE(depacketizer_->Parse(&expected_header, packet2, sizeof(packet2))); - EXPECT_EQ(kVideoFrameKey, last_header_.frameType); - EXPECT_FALSE(last_header_.type.Video.isFirstPacket); - EXPECT_FALSE(last_header_.type.Video.codecHeader.H264.single_nalu); - EXPECT_FALSE(last_header_.type.Video.codecHeader.H264.stap_a); + ASSERT_TRUE(depacketizer_->Parse(&payload, packet2, sizeof(packet2))); + ExpectPacket(&payload, kExpected2, sizeof(kExpected2)); + EXPECT_EQ(kVideoFrameKey, payload.header->frameType); + EXPECT_FALSE(payload.header->type.Video.isFirstPacket); + EXPECT_FALSE(payload.header->type.Video.codecHeader.H264.single_nalu); + EXPECT_FALSE(payload.header->type.Video.codecHeader.H264.stap_a); - ExpectPacket(kExpected3, sizeof(kExpected3)); - EXPECT_TRUE(depacketizer_->Parse(&expected_header, packet3, sizeof(packet3))); - EXPECT_EQ(kVideoFrameKey, last_header_.frameType); - EXPECT_FALSE(last_header_.type.Video.isFirstPacket); - EXPECT_FALSE(last_header_.type.Video.codecHeader.H264.single_nalu); - EXPECT_FALSE(last_header_.type.Video.codecHeader.H264.stap_a); + ASSERT_TRUE(depacketizer_->Parse(&payload, packet3, sizeof(packet3))); + ExpectPacket(&payload, kExpected3, sizeof(kExpected3)); + EXPECT_EQ(kVideoFrameKey, payload.header->frameType); + EXPECT_FALSE(payload.header->type.Video.isFirstPacket); + EXPECT_FALSE(payload.header->type.Video.codecHeader.H264.single_nalu); + EXPECT_FALSE(payload.header->type.Video.codecHeader.H264.stap_a); } } // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc b/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc index c28aa13bf9..4907846f60 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc @@ -86,27 +86,24 @@ std::string RtpPacketizerGeneric::ToString() { return "RtpPacketizerGeneric"; } -RtpDepacketizerGeneric::RtpDepacketizerGeneric(RtpData* const callback) - : callback_(callback) { -} - -bool RtpDepacketizerGeneric::Parse(WebRtcRTPHeader* rtp_header, +bool RtpDepacketizerGeneric::Parse(ParsedPayload* parsed_payload, const uint8_t* payload_data, size_t payload_data_length) { + assert(parsed_payload != NULL); + assert(parsed_payload->header != NULL); + uint8_t generic_header = *payload_data++; --payload_data_length; - rtp_header->frameType = + parsed_payload->header->frameType = ((generic_header & RtpFormatVideoGeneric::kKeyFrameBit) != 0) ? kVideoFrameKey : kVideoFrameDelta; - rtp_header->type.Video.isFirstPacket = + parsed_payload->header->type.Video.isFirstPacket = (generic_header & RtpFormatVideoGeneric::kFirstPacketBit) != 0; - if (callback_->OnReceivedPayloadData( - payload_data, payload_data_length, rtp_header) != 0) { - return false; - } + parsed_payload->payload = payload_data; + parsed_payload->payload_length = payload_data_length; return true; } } // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h b/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h index 23a4e6bedd..491cab5c53 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h @@ -10,6 +10,8 @@ #ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VIDEO_GENERIC_H_ #define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VIDEO_GENERIC_H_ +#include + #include "webrtc/common_types.h" #include "webrtc/modules/rtp_rtcp/source/rtp_format.h" #include "webrtc/typedefs.h" @@ -64,18 +66,11 @@ class RtpPacketizerGeneric : public RtpPacketizer { // Depacketizer for generic codec. class RtpDepacketizerGeneric : public RtpDepacketizer { public: - explicit RtpDepacketizerGeneric(RtpData* const callback); - virtual ~RtpDepacketizerGeneric() {} - virtual bool Parse(WebRtcRTPHeader* rtp_header, + virtual bool Parse(ParsedPayload* parsed_payload, const uint8_t* payload_data, size_t payload_data_length) OVERRIDE; - - private: - RtpData* const callback_; - - DISALLOW_COPY_AND_ASSIGN(RtpDepacketizerGeneric); }; } // namespace webrtc #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VIDEO_GENERIC_H_ diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc b/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc index a3d673b388..86bdd8bdf5 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc @@ -20,13 +20,6 @@ namespace webrtc { namespace { -struct ParsedPayload { - ParsedPayload() : data(NULL), data_length(0) {} - - const uint8_t* data; // Start address of parsed payload data. - int data_length; // Length of parsed payload data. -}; - int ParseVP8PictureID(RTPVideoHeaderVP8* vp8, const uint8_t** data, int* data_length, @@ -145,92 +138,6 @@ int ParseVP8FrameSize(WebRtcRTPHeader* rtp_header, rtp_header->type.Video.height = ((data[9] << 8) + data[8]) & 0x3FFF; return 0; } - -// -// VP8 format: -// -// Payload descriptor -// 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:Y| 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| -// +-+-+-+-+-+-+-+-+ -// | ... | -// + + -bool ParseVP8(WebRtcRTPHeader* rtp_header, - const uint8_t* data, - int data_length, - ParsedPayload* payload) { - assert(rtp_header != NULL); - // Parse mandatory first byte of payload descriptor. - bool extension = (*data & 0x80) ? true : false; // X bit - bool beginning_of_partition = (*data & 0x10) ? true : false; // S bit - int partition_id = (*data & 0x0F); // PartID field - - rtp_header->type.Video.isFirstPacket = - beginning_of_partition && (partition_id == 0); - - rtp_header->type.Video.codecHeader.VP8.nonReference = - (*data & 0x20) ? true : false; // N bit - rtp_header->type.Video.codecHeader.VP8.partitionId = partition_id; - rtp_header->type.Video.codecHeader.VP8.beginningOfPartition = - beginning_of_partition; - rtp_header->type.Video.codecHeader.VP8.pictureId = kNoPictureId; - rtp_header->type.Video.codecHeader.VP8.tl0PicIdx = kNoTl0PicIdx; - rtp_header->type.Video.codecHeader.VP8.temporalIdx = kNoTemporalIdx; - rtp_header->type.Video.codecHeader.VP8.layerSync = false; - rtp_header->type.Video.codecHeader.VP8.keyIdx = kNoKeyIdx; - - if (partition_id > 8) { - // Weak check for corrupt data: PartID MUST NOT be larger than 8. - return false; - } - - // Advance data and decrease remaining payload size. - data++; - data_length--; - - if (extension) { - const int parsed_bytes = ParseVP8Extension( - &rtp_header->type.Video.codecHeader.VP8, data, data_length); - if (parsed_bytes < 0) - return false; - data += parsed_bytes; - data_length -= parsed_bytes; - } - - if (data_length <= 0) { - LOG(LS_ERROR) << "Error parsing VP8 payload descriptor!"; - return false; - } - - // Read P bit from payload header (only at beginning of first partition). - if (data_length > 0 && beginning_of_partition && partition_id == 0) { - rtp_header->frameType = (*data & 0x01) ? kVideoFrameDelta : kVideoFrameKey; - } else { - rtp_header->frameType = kVideoFrameDelta; - } - - if (0 != ParseVP8FrameSize(rtp_header, data, data_length)) { - return false; - } - payload->data = data; - payload->data_length = data_length; - return true; -} } // namespace // Define how the VP8PacketizerModes are implemented. @@ -729,24 +636,96 @@ bool RtpPacketizerVp8::TL0PicIdxFieldPresent() const { return (hdr_info_.tl0PicIdx != kNoTl0PicIdx); } -RtpDepacketizerVp8::RtpDepacketizerVp8(RtpData* const callback) - : callback_(callback) { -} - -bool RtpDepacketizerVp8::Parse(WebRtcRTPHeader* rtp_header, +// +// VP8 format: +// +// Payload descriptor +// 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:Y| 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| +// +-+-+-+-+-+-+-+-+ +// | ... | +// + + +bool RtpDepacketizerVp8::Parse(ParsedPayload* parsed_payload, const uint8_t* payload_data, size_t payload_data_length) { - ParsedPayload payload; - if (!ParseVP8(rtp_header, payload_data, payload_data_length, &payload)) - return false; + assert(parsed_payload != NULL); + assert(parsed_payload->header != NULL); - if (payload.data_length == 0) - return true; + // Parse mandatory first byte of payload descriptor. + bool extension = (*payload_data & 0x80) ? true : false; // X bit + bool beginning_of_partition = (*payload_data & 0x10) ? true : false; // S bit + int partition_id = (*payload_data & 0x0F); // PartID field - if (callback_->OnReceivedPayloadData( - payload.data, payload.data_length, rtp_header) != 0) { + parsed_payload->header->type.Video.isFirstPacket = + beginning_of_partition && (partition_id == 0); + + parsed_payload->header->type.Video.codecHeader.VP8.nonReference = + (*payload_data & 0x20) ? true : false; // N bit + parsed_payload->header->type.Video.codecHeader.VP8.partitionId = partition_id; + parsed_payload->header->type.Video.codecHeader.VP8.beginningOfPartition = + beginning_of_partition; + parsed_payload->header->type.Video.codecHeader.VP8.pictureId = kNoPictureId; + parsed_payload->header->type.Video.codecHeader.VP8.tl0PicIdx = kNoTl0PicIdx; + parsed_payload->header->type.Video.codecHeader.VP8.temporalIdx = + kNoTemporalIdx; + parsed_payload->header->type.Video.codecHeader.VP8.layerSync = false; + parsed_payload->header->type.Video.codecHeader.VP8.keyIdx = kNoKeyIdx; + + if (partition_id > 8) { + // Weak check for corrupt payload_data: PartID MUST NOT be larger than 8. return false; } + + // Advance payload_data and decrease remaining payload size. + payload_data++; + payload_data_length--; + + if (extension) { + const int parsed_bytes = + ParseVP8Extension(&parsed_payload->header->type.Video.codecHeader.VP8, + payload_data, + payload_data_length); + if (parsed_bytes < 0) + return false; + payload_data += parsed_bytes; + payload_data_length -= parsed_bytes; + } + + if (payload_data_length <= 0) { + LOG(LS_ERROR) << "Error parsing VP8 payload descriptor!"; + return false; + } + + // Read P bit from payload header (only at beginning of first partition). + if (payload_data_length > 0 && beginning_of_partition && partition_id == 0) { + parsed_payload->header->frameType = + (*payload_data & 0x01) ? kVideoFrameDelta : kVideoFrameKey; + } else { + parsed_payload->header->frameType = kVideoFrameDelta; + } + + if (0 != ParseVP8FrameSize( + parsed_payload->header, payload_data, payload_data_length)) { + return false; + } + + parsed_payload->payload = payload_data; + parsed_payload->payload_length = payload_data_length; return true; } } // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h b/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h index 85a3304deb..4b7a6a2b9c 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h @@ -26,6 +26,7 @@ #define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_H_ #include +#include #include #include "webrtc/base/constructormagic.h" @@ -218,18 +219,11 @@ class RtpPacketizerVp8 : public RtpPacketizer { // Depacketizer for VP8. class RtpDepacketizerVp8 : public RtpDepacketizer { public: - explicit RtpDepacketizerVp8(RtpData* const callback); - virtual ~RtpDepacketizerVp8() {} - virtual bool Parse(WebRtcRTPHeader* rtp_header, + virtual bool Parse(ParsedPayload* parsed_payload, const uint8_t* payload_data, size_t payload_data_length) OVERRIDE; - - private: - RtpData* const callback_; - - DISALLOW_COPY_AND_ASSIGN(RtpDepacketizerVp8); }; } // namespace webrtc #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_H_ diff --git a/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc index 7a4dbcf6d6..b13f8793b6 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc @@ -14,7 +14,6 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#include "webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h" #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h" #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h" #include "webrtc/system_wrappers/interface/compile_assert.h" @@ -24,11 +23,6 @@ COMPILE_ASSERT(expected_size == sizeof(array) / sizeof(array[0]), \ check_array_size); -using ::testing::_; -using ::testing::Args; -using ::testing::ElementsAreArray; -using ::testing::Return; - namespace webrtc { namespace { // Payload descriptor @@ -391,17 +385,18 @@ TEST_F(RtpPacketizerVp8Test, TestTIDAndKeyIdx) { class RtpDepacketizerVp8Test : public ::testing::Test { protected: RtpDepacketizerVp8Test() - : callback_(), - depacketizer_(RtpDepacketizer::Create(kRtpVideoVp8, &callback_)) {} + : depacketizer_(RtpDepacketizer::Create(kRtpVideoVp8)) {} - void ExpectPacket(const uint8_t* data, size_t length) { - EXPECT_CALL(callback_, OnReceivedPayloadData(_, length, _)) - .With(Args<0, 1>(ElementsAreArray(data, length))) - .Times(1) - .WillOnce(Return(0)); + void ExpectPacket(RtpDepacketizer::ParsedPayload* parsed_payload, + const uint8_t* data, + size_t length) { + ASSERT_TRUE(parsed_payload != NULL); + EXPECT_THAT(std::vector( + parsed_payload->payload, + parsed_payload->payload + parsed_payload->payload_length), + ::testing::ElementsAreArray(data, length)); } - MockRtpData callback_; scoped_ptr depacketizer_; }; @@ -413,14 +408,15 @@ TEST_F(RtpDepacketizerVp8Test, BasicHeader) { WebRtcRTPHeader rtp_header; memset(&rtp_header, 0, sizeof(rtp_header)); + RtpDepacketizer::ParsedPayload payload(&rtp_header); - ExpectPacket(packet + kHeaderLength, sizeof(packet) - kHeaderLength); - EXPECT_TRUE(depacketizer_->Parse(&rtp_header, packet, sizeof(packet))); - - EXPECT_EQ(kVideoFrameDelta, rtp_header.frameType); - VerifyBasicHeader(&rtp_header, 0, 1, 4); + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket( + &payload, packet + kHeaderLength, sizeof(packet) - kHeaderLength); + EXPECT_EQ(kVideoFrameDelta, payload.header->frameType); + VerifyBasicHeader(payload.header, 0, 1, 4); VerifyExtensions( - &rtp_header, kNoPictureId, kNoTl0PicIdx, kNoTemporalIdx, kNoKeyIdx); + payload.header, kNoPictureId, kNoTl0PicIdx, kNoTemporalIdx, kNoKeyIdx); } TEST_F(RtpDepacketizerVp8Test, PictureID) { @@ -434,23 +430,26 @@ TEST_F(RtpDepacketizerVp8Test, PictureID) { WebRtcRTPHeader rtp_header; memset(&rtp_header, 0, sizeof(rtp_header)); + RtpDepacketizer::ParsedPayload payload(&rtp_header); - ExpectPacket(packet + kHeaderLength1, sizeof(packet) - kHeaderLength1); - EXPECT_TRUE(depacketizer_->Parse(&rtp_header, packet, sizeof(packet))); - EXPECT_EQ(kVideoFrameDelta, rtp_header.frameType); - VerifyBasicHeader(&rtp_header, 1, 0, 0); + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket( + &payload, packet + kHeaderLength1, sizeof(packet) - kHeaderLength1); + EXPECT_EQ(kVideoFrameDelta, payload.header->frameType); + VerifyBasicHeader(payload.header, 1, 0, 0); VerifyExtensions( - &rtp_header, kPictureId, kNoTl0PicIdx, kNoTemporalIdx, kNoKeyIdx); + payload.header, kPictureId, kNoTl0PicIdx, kNoTemporalIdx, kNoKeyIdx); // Re-use packet, but change to long PictureID. packet[2] = 0x80 | kPictureId; packet[3] = kPictureId; - memset(&rtp_header, 0, sizeof(rtp_header)); + memset(payload.header, 0, sizeof(rtp_header)); - ExpectPacket(packet + kHeaderLength2, sizeof(packet) - kHeaderLength2); - EXPECT_TRUE(depacketizer_->Parse(&rtp_header, packet, sizeof(packet))); - VerifyBasicHeader(&rtp_header, 1, 0, 0); - VerifyExtensions(&rtp_header, + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket( + &payload, packet + kHeaderLength2, sizeof(packet) - kHeaderLength2); + VerifyBasicHeader(payload.header, 1, 0, 0); + VerifyExtensions(payload.header, (kPictureId << 8) + kPictureId, kNoTl0PicIdx, kNoTemporalIdx, @@ -467,13 +466,15 @@ TEST_F(RtpDepacketizerVp8Test, Tl0PicIdx) { WebRtcRTPHeader rtp_header; memset(&rtp_header, 0, sizeof(rtp_header)); + RtpDepacketizer::ParsedPayload payload(&rtp_header); - ExpectPacket(packet + kHeaderLength, sizeof(packet) - kHeaderLength); - EXPECT_TRUE(depacketizer_->Parse(&rtp_header, packet, sizeof(packet))); - EXPECT_EQ(kVideoFrameKey, rtp_header.frameType); - VerifyBasicHeader(&rtp_header, 0, 1, 0); + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket( + &payload, packet + kHeaderLength, sizeof(packet) - kHeaderLength); + EXPECT_EQ(kVideoFrameKey, payload.header->frameType); + VerifyBasicHeader(payload.header, 0, 1, 0); VerifyExtensions( - &rtp_header, kNoPictureId, kTl0PicIdx, kNoTemporalIdx, kNoKeyIdx); + payload.header, kNoPictureId, kTl0PicIdx, kNoTemporalIdx, kNoKeyIdx); } TEST_F(RtpDepacketizerVp8Test, TIDAndLayerSync) { @@ -485,13 +486,15 @@ TEST_F(RtpDepacketizerVp8Test, TIDAndLayerSync) { WebRtcRTPHeader rtp_header; memset(&rtp_header, 0, sizeof(rtp_header)); + RtpDepacketizer::ParsedPayload payload(&rtp_header); - ExpectPacket(packet + kHeaderLength, sizeof(packet) - kHeaderLength); - EXPECT_TRUE(depacketizer_->Parse(&rtp_header, packet, sizeof(packet))); - EXPECT_EQ(kVideoFrameDelta, rtp_header.frameType); - VerifyBasicHeader(&rtp_header, 0, 0, 8); - VerifyExtensions(&rtp_header, kNoPictureId, kNoTl0PicIdx, 2, kNoKeyIdx); - EXPECT_FALSE(rtp_header.type.Video.codecHeader.VP8.layerSync); + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket( + &payload, packet + kHeaderLength, sizeof(packet) - kHeaderLength); + EXPECT_EQ(kVideoFrameDelta, payload.header->frameType); + VerifyBasicHeader(payload.header, 0, 0, 8); + VerifyExtensions(payload.header, kNoPictureId, kNoTl0PicIdx, 2, kNoKeyIdx); + EXPECT_FALSE(payload.header->type.Video.codecHeader.VP8.layerSync); } TEST_F(RtpDepacketizerVp8Test, KeyIdx) { @@ -504,13 +507,15 @@ TEST_F(RtpDepacketizerVp8Test, KeyIdx) { WebRtcRTPHeader rtp_header; memset(&rtp_header, 0, sizeof(rtp_header)); + RtpDepacketizer::ParsedPayload payload(&rtp_header); - ExpectPacket(packet + kHeaderLength, sizeof(packet) - kHeaderLength); - EXPECT_TRUE(depacketizer_->Parse(&rtp_header, packet, sizeof(packet))); - EXPECT_EQ(kVideoFrameDelta, rtp_header.frameType); - VerifyBasicHeader(&rtp_header, 0, 0, 8); + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket( + &payload, packet + kHeaderLength, sizeof(packet) - kHeaderLength); + EXPECT_EQ(kVideoFrameDelta, payload.header->frameType); + VerifyBasicHeader(payload.header, 0, 0, 8); VerifyExtensions( - &rtp_header, kNoPictureId, kNoTl0PicIdx, kNoTemporalIdx, kKeyIdx); + payload.header, kNoPictureId, kNoTl0PicIdx, kNoTemporalIdx, kKeyIdx); } TEST_F(RtpDepacketizerVp8Test, MultipleExtensions) { @@ -525,12 +530,14 @@ TEST_F(RtpDepacketizerVp8Test, MultipleExtensions) { WebRtcRTPHeader rtp_header; memset(&rtp_header, 0, sizeof(rtp_header)); + RtpDepacketizer::ParsedPayload payload(&rtp_header); - ExpectPacket(packet + kHeaderLength, sizeof(packet) - kHeaderLength); - EXPECT_TRUE(depacketizer_->Parse(&rtp_header, packet, sizeof(packet))); - EXPECT_EQ(kVideoFrameDelta, rtp_header.frameType); - VerifyBasicHeader(&rtp_header, 0, 0, 8); - VerifyExtensions(&rtp_header, (17 << 8) + 17, 42, 1, 17); + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket( + &payload, packet + kHeaderLength, sizeof(packet) - kHeaderLength); + EXPECT_EQ(kVideoFrameDelta, payload.header->frameType); + VerifyBasicHeader(payload.header, 0, 0, 8); + VerifyExtensions(payload.header, (17 << 8) + 17, 42, 1, 17); } TEST_F(RtpDepacketizerVp8Test, TooShortHeader) { @@ -542,13 +549,14 @@ TEST_F(RtpDepacketizerVp8Test, TooShortHeader) { WebRtcRTPHeader rtp_header; memset(&rtp_header, 0, sizeof(rtp_header)); + RtpDepacketizer::ParsedPayload payload(&rtp_header); - EXPECT_FALSE(depacketizer_->Parse(&rtp_header, packet, sizeof(packet))); + EXPECT_FALSE(depacketizer_->Parse(&payload, packet, sizeof(packet))); } TEST_F(RtpDepacketizerVp8Test, TestWithPacketizer) { const uint8_t kHeaderLength = 5; - uint8_t payload[10] = {0}; + uint8_t data[10] = {0}; uint8_t packet[20] = {0}; RTPVideoHeaderVP8 input_header; input_header.nonReference = true; @@ -558,7 +566,7 @@ TEST_F(RtpDepacketizerVp8Test, TestWithPacketizer) { input_header.tl0PicIdx = kNoTl0PicIdx; // Disable. input_header.keyIdx = 31; RtpPacketizerVp8 packetizer(input_header, 20); - packetizer.SetPayloadData(payload, 10, NULL); + packetizer.SetPayloadData(data, 10, NULL); bool last; size_t send_bytes; ASSERT_TRUE(packetizer.NextPacket(packet, &send_bytes, &last)); @@ -566,17 +574,20 @@ TEST_F(RtpDepacketizerVp8Test, TestWithPacketizer) { WebRtcRTPHeader rtp_header; memset(&rtp_header, 0, sizeof(rtp_header)); + RtpDepacketizer::ParsedPayload payload(&rtp_header); - ExpectPacket(packet + kHeaderLength, sizeof(packet) - kHeaderLength); - EXPECT_TRUE(depacketizer_->Parse(&rtp_header, packet, sizeof(packet))); - EXPECT_EQ(kVideoFrameKey, rtp_header.frameType); - VerifyBasicHeader(&rtp_header, 1, 1, 0); - VerifyExtensions(&rtp_header, + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket( + &payload, packet + kHeaderLength, sizeof(packet) - kHeaderLength); + EXPECT_EQ(kVideoFrameKey, payload.header->frameType); + VerifyBasicHeader(payload.header, 1, 1, 0); + VerifyExtensions(payload.header, input_header.pictureId, input_header.tl0PicIdx, input_header.temporalIdx, input_header.keyIdx); - EXPECT_EQ(rtp_header.type.Video.codecHeader.VP8.layerSync, + EXPECT_EQ(payload.header->type.Video.codecHeader.VP8.layerSync, input_header.layerSync); } + } // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc b/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc index 058d91e372..dfbf35aea8 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc @@ -65,20 +65,29 @@ int32_t RTPReceiverVideo::ParseRtpPacket(WebRtcRTPHeader* rtp_header, const uint16_t payload_data_length = payload_length - rtp_header->header.paddingLength; - if (payload_data_length == 0) + if (payload == NULL || payload_data_length == 0) { return data_callback_->OnReceivedPayloadData(NULL, 0, rtp_header) == 0 ? 0 : -1; + } // We are not allowed to hold a critical section when calling below functions. scoped_ptr depacketizer( - RtpDepacketizer::Create(rtp_header->type.Video.codec, data_callback_)); + RtpDepacketizer::Create(rtp_header->type.Video.codec)); if (depacketizer.get() == NULL) { LOG(LS_ERROR) << "Failed to create depacketizer."; return -1; } rtp_header->type.Video.isFirstPacket = is_first_packet; - return depacketizer->Parse(rtp_header, payload, payload_data_length) ? 0 : -1; + RtpDepacketizer::ParsedPayload parsed_payload(rtp_header); + if (!depacketizer->Parse(&parsed_payload, payload, payload_data_length)) + return -1; + + return data_callback_->OnReceivedPayloadData(parsed_payload.payload, + parsed_payload.payload_length, + parsed_payload.header) == 0 + ? 0 + : -1; } int RTPReceiverVideo::GetPayloadTypeFrequency() const {