Implement VP8 packetizer and unit tests

Implemented a new VP8 packetizer with three modes. The packetizer
class needs access to the fragmentation information, which is
now created in the codec wrapper and passed through the callback
chain to the RTPSenderVideo::SendVP8().

A unit test for the VP8 packetizer was also implemented. It tests the
three different modes. The tests could definitely be more elaborate.
Review URL: http://webrtc-codereview.appspot.com/34003

git-svn-id: http://webrtc.googlecode.com/svn/trunk@48 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
hlundin@google.com 2011-06-07 12:23:14 +00:00
parent 8dcd789d2b
commit d2c7bff3a1
6 changed files with 209 additions and 692 deletions

View File

@ -8,10 +8,6 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
/*
* This file contains the implementation of the VP8 packetizer class.
*/
#include "rtp_format_vp8.h" #include "rtp_format_vp8.h"
#include <cassert> // assert #include <cassert> // assert
@ -19,14 +15,13 @@
namespace webrtc { namespace webrtc {
RTPFormatVP8::RTPFormatVP8(const WebRtc_UWord8* payload_data, RtpFormatVp8::RtpFormatVp8(const WebRtc_UWord8* payload_data,
const WebRtc_UWord32 payload_size, WebRtc_UWord32 payload_size,
const RTPFragmentationHeader* fragmentation, const RTPFragmentationHeader* fragmentation,
const VP8PacketizerMode mode) VP8PacketizerMode mode)
: : payload_data_(payload_data),
payload_data_(payload_data),
payload_size_(payload_size), payload_size_(payload_size),
bytes_sent_(0), payload_bytes_sent_(0),
mode_(mode), mode_(mode),
beginning_(true), beginning_(true),
first_fragment_(true), first_fragment_(true),
@ -44,23 +39,38 @@ RTPFormatVP8::RTPFormatVP8(const WebRtc_UWord8* payload_data,
} }
} }
bool RTPFormatVP8::NextPacket(const int max_payload_len, WebRtc_UWord8* buffer, RtpFormatVp8::RtpFormatVp8(const WebRtc_UWord8* payload_data,
int* bytes_to_send) WebRtc_UWord32 payload_size)
{ : payload_data_(payload_data),
// Convenience variables payload_size_(payload_size),
const int num_fragments = frag_info_.fragmentationVectorSize; frag_info_(),
payload_bytes_sent_(0),
mode_(kSloppy),
beginning_(true),
first_fragment_(true),
vp8_header_bytes_(1)
{}
int RtpFormatVp8::GetFragIdx()
{
// Which fragment are we in? // Which fragment are we in?
int frag_ix = 0; int frag_ix = 0;
while ((frag_ix + 1 < num_fragments) && while ((frag_ix + 1 < frag_info_.fragmentationVectorSize) &&
(bytes_sent_ >= frag_info_.fragmentationOffset[frag_ix + 1])) (payload_bytes_sent_ >= frag_info_.fragmentationOffset[frag_ix + 1]))
{ {
++frag_ix; ++frag_ix;
} }
return frag_ix;
}
// How much data to send in this packet? int RtpFormatVp8::NextPacket(int max_payload_len, WebRtc_UWord8* buffer,
int send_bytes = 0; int* bytes_to_send, bool* last_packet)
bool last_fragment = false; {
// Convenience variables
const int num_fragments = frag_info_.fragmentationVectorSize;
int frag_ix = GetFragIdx(); //TODO (hlundin): Store frag_ix as a member?
int send_bytes = 0; // How much data to send in this packet.
bool end_of_fragment = false;
switch (mode_) switch (mode_)
{ {
@ -75,16 +85,17 @@ bool RTPFormatVP8::NextPacket(const int max_payload_len, WebRtc_UWord8* buffer,
{ {
// Pack as many whole partitions we can into this packet; // Pack as many whole partitions we can into this packet;
// don't fragment. // don't fragment.
while (send_bytes + vp8_header_bytes_ while ((frag_ix < num_fragments) &&
(send_bytes + vp8_header_bytes_
+ frag_info_.fragmentationLength[frag_ix] + frag_info_.fragmentationLength[frag_ix]
<= max_payload_len) <= max_payload_len))
{ {
send_bytes += frag_info_.fragmentationLength[frag_ix]; send_bytes += frag_info_.fragmentationLength[frag_ix];
++frag_ix; ++frag_ix;
} }
// This packet ends on a complete fragment. // This packet ends on a complete fragment.
last_fragment = true; end_of_fragment = true;
break; // Jump out of case statement. break; // Jump out of case statement.
} }
} }
@ -99,7 +110,7 @@ bool RTPFormatVP8::NextPacket(const int max_payload_len, WebRtc_UWord8* buffer,
{ {
// Find out how much is left to send in the current partition. // Find out how much is left to send in the current partition.
const int remaining_bytes = frag_info_.fragmentationOffset[frag_ix] const int remaining_bytes = frag_info_.fragmentationOffset[frag_ix]
- bytes_sent_ + frag_info_.fragmentationLength[frag_ix]; - payload_bytes_sent_ + frag_info_.fragmentationLength[frag_ix];
assert(remaining_bytes > 0); assert(remaining_bytes > 0);
assert(remaining_bytes <= frag_info_.fragmentationLength[frag_ix]); assert(remaining_bytes <= frag_info_.fragmentationLength[frag_ix]);
@ -112,7 +123,7 @@ bool RTPFormatVP8::NextPacket(const int max_payload_len, WebRtc_UWord8* buffer,
{ {
// last packet from this partition // last packet from this partition
send_bytes = remaining_bytes; send_bytes = remaining_bytes;
last_fragment = true; end_of_fragment = true;
} }
break; break;
} }
@ -120,17 +131,17 @@ bool RTPFormatVP8::NextPacket(const int max_payload_len, WebRtc_UWord8* buffer,
case kSloppy: case kSloppy:
{ {
// Send a full packet, or what is left of the payload. // Send a full packet, or what is left of the payload.
const int remaining_bytes = payload_size_ - bytes_sent_; const int remaining_bytes = payload_size_ - payload_bytes_sent_;
if (remaining_bytes + vp8_header_bytes_ > max_payload_len) if (remaining_bytes + vp8_header_bytes_ > max_payload_len)
{ {
send_bytes = max_payload_len - vp8_header_bytes_; send_bytes = max_payload_len - vp8_header_bytes_;
last_fragment = false; end_of_fragment = false;
} }
else else
{ {
send_bytes = remaining_bytes; send_bytes = remaining_bytes;
last_fragment = true; end_of_fragment = true;
} }
break; break;
} }
@ -138,20 +149,23 @@ bool RTPFormatVP8::NextPacket(const int max_payload_len, WebRtc_UWord8* buffer,
default: default:
// Should not end up here // Should not end up here
assert(false); assert(false);
return -1;
} }
// Write the payload header and the payload to buffer. // Write the payload header and the payload to buffer.
*bytes_to_send = WriteHeaderAndPayload(send_bytes, last_fragment, buffer); *bytes_to_send = WriteHeaderAndPayload(send_bytes, end_of_fragment, buffer);
if (*bytes_to_send < 0)
{
return -1;
}
// Anything left to send? *last_packet = payload_bytes_sent_ >= payload_size_;
if (bytes_sent_ < payload_size_) assert(!*last_packet || (payload_bytes_sent_ == payload_size_));
return false; return 0;
else
return true;
} }
int RTPFormatVP8::WriteHeaderAndPayload(const int send_bytes, int RtpFormatVp8::WriteHeaderAndPayload(int send_bytes,
const bool last_fragment, bool end_of_fragment,
WebRtc_UWord8* buffer) WebRtc_UWord8* buffer)
{ {
// Write the VP8 payload header. // Write the VP8 payload header.
@ -160,25 +174,34 @@ int RTPFormatVP8::WriteHeaderAndPayload(const int send_bytes,
// | RSV |I|N|FI |B| // | RSV |I|N|FI |B|
// +-+-+-+-+-+-+-+-+ // +-+-+-+-+-+-+-+-+
if (send_bytes < 0)
{
return -1;
}
if (payload_bytes_sent_ + send_bytes > payload_size_)
{
return -1;
}
// PictureID always present in first packet // PictureID always present in first packet
const int pictureid_present = beginning_; const int picture_id_present = beginning_;
// TODO(hlundin): must pipe this info from VP8 encoder // TODO(hlundin): must pipe this info from VP8 encoder
const int nonref_frame = 0; const int kNonrefFrame = 0;
buffer[0] = 0 | (pictureid_present << 4) // I buffer[0] = 0;
| (nonref_frame << 3) // N if (picture_id_present) buffer[0] |= (0x01 << 4); // I
| (!first_fragment_ << 2) | (!last_fragment << 1) // FI if (kNonrefFrame) buffer[0] |= (0x01 << 3); // N
| (beginning_); if (!first_fragment_) buffer[0] |= (0x01 << 2); // FI
if (!end_of_fragment) buffer[0] |= (0x01 << 1); // FI
if (beginning_) buffer[0] |= 0x01; // B
// Copy the payload. memcpy(&buffer[vp8_header_bytes_], &payload_data_[payload_bytes_sent_],
assert(bytes_sent_ + send_bytes <= payload_size_); send_bytes);
memcpy(&buffer[vp8_header_bytes_], &payload_data_[bytes_sent_], send_bytes);
// Update state variables.
beginning_ = false; // next packet cannot be first packet in frame beginning_ = false; // next packet cannot be first packet in frame
// next packet starts new fragment if this ended one // next packet starts new fragment if this ended one
first_fragment_ = last_fragment; first_fragment_ = end_of_fragment;
bytes_sent_ += send_bytes; payload_bytes_sent_ += send_bytes;
// Return total length of written data. // Return total length of written data.
return send_bytes + vp8_header_bytes_; return send_bytes + vp8_header_bytes_;

View File

@ -10,78 +10,16 @@
/* /*
* This file contains the declaration of the VP8 packetizer class. * This file contains the declaration of the VP8 packetizer class.
*/ * A packetizer object is created for each encoded video frame. The
* constructor is called with the payload data and size,
#ifndef WEBRTC_MODULES_RTP_RTCP_RTP_FORMAT_VP8_H_ * together with the fragmentation information and a packetizer mode
#define WEBRTC_MODULES_RTP_RTCP_RTP_FORMAT_VP8_H_ * of choice. Alternatively, if no fragmentation info is available, the
* second constructor can be used with only payload data and size; in that
#include "module_common_types.h" * case the mode kSloppy is used.
#include "typedefs.h"
namespace webrtc
{
// VP8 packetization modes.
enum VP8PacketizerMode
{
kStrict = 0, // split partitions if too large; never aggregate partitions
kAggregate, // split partitions if too large; aggregate partitions/fragments
kSloppy, // split entire payload without considering partition boundaries
};
// Packetizer for VP8.
class RTPFormatVP8
{
public:
// Constructor.
// Initialize with payload from encoder and fragmentation info.
// If fragmentation info is NULL, mode will be forced to kSloppy.
RTPFormatVP8(const WebRtc_UWord8* payload_data,
const WebRtc_UWord32 payload_size,
const RTPFragmentationHeader* fragmentation,
const VP8PacketizerMode mode = kStrict);
// Get the next payload with VP8 payload header.
// max_payload_len limits the sum length of payload and VP8 payload header.
// buffer is a pointer to where the output will be written.
// bytes_to_send is an output variable that will contain number of bytes
// written to buffer.
bool NextPacket(const int max_payload_len, WebRtc_UWord8* buffer,
int* bytes_to_send);
private:
// Write the payload header and copy the payload to the buffer.
// Will copy send_bytes bytes from the current position on the payload data.
// last_fragment indicates that this packet ends with the last byte of a
// partition.
int WriteHeaderAndPayload(const int send_bytes, const bool last_fragment,
WebRtc_UWord8* buffer);
const WebRtc_UWord8* payload_data_;
const WebRtc_UWord32 payload_size_;
RTPFragmentationHeader frag_info_;
int bytes_sent_;
VP8PacketizerMode mode_;
bool beginning_; // first partition in this frame
bool first_fragment_; // first fragment of a partition
const int vp8_header_bytes_; // length of VP8 payload header
};
}
#endif /* WEBRTC_MODULES_RTP_RTCP_RTP_FORMAT_VP8_H_ */
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
* *
* Use of this source code is governed by a BSD-style license * After creating the packetizer, the method NextPacket is called
* that can be found in the LICENSE file in the root of the source * repeatedly to get all packets for the frame. The method returns
* tree. An additional intellectual property rights grant can be found * false as long as there are more packets left to fetch.
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
/*
* This file contains the declaration of the VP8 packetizer class.
*/ */
#ifndef WEBRTC_MODULES_RTP_RTCP_RTP_FORMAT_VP8_H_ #ifndef WEBRTC_MODULES_RTP_RTCP_RTP_FORMAT_VP8_H_
@ -93,46 +31,54 @@ private:
namespace webrtc namespace webrtc
{ {
// VP8 packetization modes.
enum VP8PacketizerMode enum VP8PacketizerMode
{ {
kStrict = 0, // split partitions if too large; never aggregate partitions kStrict = 0, // split partitions if too large; never aggregate partitions
kAggregate, // split partitions if too large; aggregate partitions/fragments kAggregate, // split partitions if too large; aggregate whole partitions
kSloppy, // split entire payload without considering partition boundaries kSloppy, // split entire payload without considering partition boundaries
}; };
// Packetizer for VP8. // Packetizer for VP8.
class RTPFormatVP8 class RtpFormatVp8
{ {
public: public:
// Constructor.
// Initialize with payload from encoder and fragmentation info. // Initialize with payload from encoder and fragmentation info.
// If fragmentation info is NULL, mode will be forced to kSloppy. // The payload_data must be exactly one encoded VP8 frame.
RTPFormatVP8(const WebRtc_UWord8* payload_data, RtpFormatVp8(const WebRtc_UWord8* payload_data,
const WebRtc_UWord32 payload_size, WebRtc_UWord32 payload_size,
const RTPFragmentationHeader* fragmentation, const RTPFragmentationHeader* fragmentation,
const VP8PacketizerMode mode = kStrict); VP8PacketizerMode mode);
// Initialize without fragmentation info. Mode kSloppy will be used.
// The payload_data must be exactly one encoded VP8 frame.
RtpFormatVp8(const WebRtc_UWord8* payload_data,
WebRtc_UWord32 payload_size);
// Get the next payload with VP8 payload header. // Get the next payload with VP8 payload header.
// max_payload_len limits the sum length of payload and VP8 payload header. // max_payload_len limits the sum length of payload and VP8 payload header.
// buffer is a pointer to where the output will be written. // buffer is a pointer to where the output will be written.
// bytes_to_send is an output variable that will contain number of bytes // bytes_to_send is an output variable that will contain number of bytes
// written to buffer. // written to buffer.
bool NextPacket(const int max_payload_len, WebRtc_UWord8* buffer, // Returns true for the last packet of the frame, false otherwise (i.e.,
int* bytes_to_send); // call the function again to get the next packet).
int NextPacket(int max_payload_len, WebRtc_UWord8* buffer,
int* bytes_to_send, bool* last_packet);
private: private:
// Determine from which fragment the next byte to send will be taken.
int GetFragIdx();
// Write the payload header and copy the payload to the buffer. // Write the payload header and copy the payload to the buffer.
// Will copy send_bytes bytes from the current position on the payload data. // Will copy send_bytes bytes from the current position on the payload data.
// last_fragment indicates that this packet ends with the last byte of a // last_fragment indicates that this packet ends with the last byte of a
// partition. // partition.
int WriteHeaderAndPayload(const int send_bytes, const bool last_fragment, int WriteHeaderAndPayload(int send_bytes, bool end_of_fragment,
WebRtc_UWord8* buffer); WebRtc_UWord8* buffer);
const WebRtc_UWord8* payload_data_; const WebRtc_UWord8* payload_data_;
const WebRtc_UWord32 payload_size_; const WebRtc_UWord32 payload_size_;
RTPFragmentationHeader frag_info_; RTPFragmentationHeader frag_info_;
int bytes_sent_; int payload_bytes_sent_;
VP8PacketizerMode mode_; VP8PacketizerMode mode_;
bool beginning_; // first partition in this frame bool beginning_; // first partition in this frame
bool first_fragment_; // first fragment of a partition bool first_fragment_; // first fragment of a partition

View File

@ -1106,14 +1106,17 @@ RTPSenderVideo::SendVP8(const FrameType frameType,
WebRtc_UWord16 maxPayloadLengthVP8 = _rtpSender.MaxPayloadLength() WebRtc_UWord16 maxPayloadLengthVP8 = _rtpSender.MaxPayloadLength()
- FECPacketOverhead() - rtpHeaderLength; - FECPacketOverhead() - rtpHeaderLength;
RTPFormatVP8 packetizer(data, payloadBytesToSend, fragmentation, kStrict); RtpFormatVp8 packetizer(data, payloadBytesToSend, fragmentation, kStrict);
bool last = false; bool last = false;
while (!last) while (!last)
{ {
// Write VP8 Payload Descriptor and VP8 payload. // Write VP8 Payload Descriptor and VP8 payload.
last = packetizer.NextPacket(maxPayloadLengthVP8, if (packetizer.NextPacket(maxPayloadLengthVP8,
&dataBuffer[rtpHeaderLength], &payloadBytesInPacket); &dataBuffer[rtpHeaderLength], &payloadBytesInPacket, &last) < 0)
{
return -1;
}
// Write RTP header. // Write RTP header.
// Set marker bit true if this is the last packet in frame. // Set marker bit true if this is the last packet in frame.

View File

@ -18,65 +18,13 @@
'../../source/rtp_rtcp.gyp:rtp_rtcp', '../../source/rtp_rtcp.gyp:rtp_rtcp',
'../../../../../testing/gtest.gyp:gtest', '../../../../../testing/gtest.gyp:gtest',
'../../../../../testing/gtest.gyp:gtest_main', '../../../../../testing/gtest.gyp:gtest_main',
# '../../../signal_processing_library/main/source/spl.gyp:spl',
], ],
'include_dirs': [ 'include_dirs': [
'../../source', '../../source',
], ],
# 'direct_dependent_settings': {
# 'include_dirs': [
# '../interface',
# ],
# },
'sources': [ 'sources': [
'unit_test.h', 'unit_test.h',
'unit_test.cc', 'unit_test.cc',
'../../source/rtp_format_vp8.h',
'../../source/rtp_format_vp8.cc',
],
},
],
}
# Local Variables:
# tab-width:2
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=2 shiftwidth=2:
# Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
{
'includes': [
'../../../../common_settings.gypi', # Common settings
],
'targets': [
{
'target_name': 'test_rtp_format_vp8',
'type': 'executable',
'dependencies': [
'../../source/rtp_rtcp.gyp:rtp_rtcp',
'../../../../../testing/gtest.gyp:gtest',
'../../../../../testing/gtest.gyp:gtest_main',
# '../../../signal_processing_library/main/source/spl.gyp:spl',
],
'include_dirs': [
'../../source',
],
# 'direct_dependent_settings': {
# 'include_dirs': [
# '../interface',
# ],
# },
'sources': [
'unit_test.h',
'unit_test.cc',
'../../source/rtp_format_vp8.h',
'../../source/rtp_format_vp8.cc', '../../source/rtp_format_vp8.cc',
], ],
}, },

View File

@ -13,19 +13,30 @@
* This file includes unit tests for the VP8 packetizer. * This file includes unit tests for the VP8 packetizer.
*/ */
#include "unit_test.h" #include <gtest/gtest.h>
#include "typedefs.h"
#include "rtp_format_vp8.h" #include "rtp_format_vp8.h"
namespace webrtc { namespace {
RTPFormatVP8Test::RTPFormatVP8Test() using webrtc::RTPFragmentationHeader;
{ using webrtc::RtpFormatVp8;
}
void RTPFormatVP8Test::SetUp() { const WebRtc_UWord32 kPayloadSize = 30;
payload_data = new WebRtc_UWord8[30];
payload_size = 30; class RtpFormatVp8Test : public ::testing::Test {
for (int i = 0; i < payload_size; i++) protected:
RtpFormatVp8Test() {};
virtual void SetUp();
virtual void TearDown();
WebRtc_UWord8* payload_data;
RTPFragmentationHeader* fragmentation;
};
void RtpFormatVp8Test::SetUp() {
payload_data = new WebRtc_UWord8[kPayloadSize];
for (int i = 0; i < kPayloadSize; i++)
{ {
payload_data[i] = i / 10; // integer division payload_data[i] = i / 10; // integer division
} }
@ -39,7 +50,7 @@ void RTPFormatVP8Test::SetUp() {
fragmentation->fragmentationOffset[2] = 20; fragmentation->fragmentationOffset[2] = 20;
} }
void RTPFormatVP8Test::TearDown() { void RtpFormatVp8Test::TearDown() {
delete [] payload_data; delete [] payload_data;
delete fragmentation; delete fragmentation;
} }
@ -57,15 +68,18 @@ void RTPFormatVP8Test::TearDown() {
#define EXPECT_BIT_B_EQ(x,a) EXPECT_EQ((((x)&0x01) > 0), (a > 0)) #define EXPECT_BIT_B_EQ(x,a) EXPECT_EQ((((x)&0x01) > 0), (a > 0))
TEST_F(RTPFormatVP8Test, TestStrictMode) TEST_F(RtpFormatVp8Test, TestStrictMode)
{ {
WebRtc_UWord8 buffer[20]; WebRtc_UWord8 buffer[20];
int send_bytes = 0; int send_bytes = 0;
bool last;
RTPFormatVP8 packetizer = RTPFormatVP8(payload_data, payload_size, fragmentation, kStrict); RtpFormatVp8 packetizer = RtpFormatVp8(payload_data, kPayloadSize,
fragmentation, webrtc::kStrict);
// get first packet // get first packet
EXPECT_FALSE(packetizer.NextPacket(8, buffer, &send_bytes)); EXPECT_EQ(0, packetizer.NextPacket(8, buffer, &send_bytes, &last));
EXPECT_FALSE(last);
EXPECT_EQ(send_bytes,8); EXPECT_EQ(send_bytes,8);
EXPECT_RSV_ZERO(buffer[0]); EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 1); EXPECT_BIT_I_EQ(buffer[0], 1);
@ -78,7 +92,8 @@ TEST_F(RTPFormatVP8Test, TestStrictMode)
} }
// get second packet // get second packet
EXPECT_FALSE(packetizer.NextPacket(8, buffer, &send_bytes)); EXPECT_EQ(0, packetizer.NextPacket(8, buffer, &send_bytes, &last));
EXPECT_FALSE(last);
EXPECT_EQ(send_bytes,4); // 3 remaining from partition, 1 header EXPECT_EQ(send_bytes,4); // 3 remaining from partition, 1 header
EXPECT_RSV_ZERO(buffer[0]); EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0); EXPECT_BIT_I_EQ(buffer[0], 0);
@ -92,7 +107,8 @@ TEST_F(RTPFormatVP8Test, TestStrictMode)
// Second partition // Second partition
// Get first (and only) packet // Get first (and only) packet
EXPECT_FALSE(packetizer.NextPacket(20, buffer, &send_bytes)); EXPECT_EQ(0, packetizer.NextPacket(20, buffer, &send_bytes, &last));
EXPECT_FALSE(last);
EXPECT_EQ(send_bytes,11); EXPECT_EQ(send_bytes,11);
EXPECT_RSV_ZERO(buffer[0]); EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0); EXPECT_BIT_I_EQ(buffer[0], 0);
@ -106,7 +122,8 @@ TEST_F(RTPFormatVP8Test, TestStrictMode)
// Third partition // Third partition
// Get first packet (of three) // Get first packet (of three)
EXPECT_FALSE(packetizer.NextPacket(5, buffer, &send_bytes)); EXPECT_EQ(0, packetizer.NextPacket(5, buffer, &send_bytes, &last));
EXPECT_FALSE(last);
EXPECT_EQ(send_bytes,5); EXPECT_EQ(send_bytes,5);
EXPECT_RSV_ZERO(buffer[0]); EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0); EXPECT_BIT_I_EQ(buffer[0], 0);
@ -119,7 +136,8 @@ TEST_F(RTPFormatVP8Test, TestStrictMode)
} }
// Get second packet (of three) // Get second packet (of three)
EXPECT_FALSE(packetizer.NextPacket(5, buffer, &send_bytes)); EXPECT_EQ(0, packetizer.NextPacket(5, buffer, &send_bytes, &last));
EXPECT_FALSE(last);
EXPECT_EQ(send_bytes,5); EXPECT_EQ(send_bytes,5);
EXPECT_RSV_ZERO(buffer[0]); EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0); EXPECT_BIT_I_EQ(buffer[0], 0);
@ -132,7 +150,8 @@ TEST_F(RTPFormatVP8Test, TestStrictMode)
} }
// Get third and last packet // Get third and last packet
EXPECT_TRUE(packetizer.NextPacket(5, buffer, &send_bytes)); // last packet in frame EXPECT_EQ(0, packetizer.NextPacket(5, buffer, &send_bytes, &last));
EXPECT_TRUE(last); // last packet in frame
EXPECT_EQ(send_bytes,3); // 2 bytes payload left, 1 header EXPECT_EQ(send_bytes,3); // 2 bytes payload left, 1 header
EXPECT_RSV_ZERO(buffer[0]); EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0); EXPECT_BIT_I_EQ(buffer[0], 0);
@ -146,72 +165,78 @@ TEST_F(RTPFormatVP8Test, TestStrictMode)
} }
TEST_F(RTPFormatVP8Test, TestAggregateMode) TEST_F(RtpFormatVp8Test, TestAggregateMode)
{ {
WebRtc_UWord8 buffer[30]; WebRtc_UWord8 buffer[kPayloadSize];
int send_bytes = 0; int send_bytes = 0;
bool last;
RTPFormatVP8 packetizer = RTPFormatVP8(payload_data, payload_size, fragmentation, RtpFormatVp8 packetizer = RtpFormatVp8(payload_data, kPayloadSize,
kAggregate); fragmentation, webrtc::kAggregate);
// get first packet // get first packet
// first two partitions aggregated // first half of first partition
EXPECT_FALSE(packetizer.NextPacket(25, buffer, &send_bytes)); EXPECT_EQ(0, packetizer.NextPacket(6, buffer, &send_bytes, &last));
EXPECT_EQ(send_bytes,21); // Two 10-byte partitions and 1 byte header EXPECT_FALSE(last);
EXPECT_EQ(send_bytes,6); // First 5 from first partition, 1 header
EXPECT_RSV_ZERO(buffer[0]); EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 1); EXPECT_BIT_I_EQ(buffer[0], 1);
EXPECT_BIT_N_EQ(buffer[0], 0); EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x00); EXPECT_FI_EQ(buffer[0], 0x01);
EXPECT_BIT_B_EQ(buffer[0], 1); EXPECT_BIT_B_EQ(buffer[0], 1);
for (int i = 1; i < 11; i++) for (int i = 1; i < 6; i++)
{ {
EXPECT_EQ(buffer[i], 0); EXPECT_EQ(buffer[i], 0);
} }
for (int i = 11; i < 21; i++)
{
EXPECT_EQ(buffer[i], 1);
}
// get second packet // get second packet
// first half of last partition // second half of first partition
EXPECT_FALSE(packetizer.NextPacket(6, buffer, &send_bytes)); EXPECT_EQ(0, packetizer.NextPacket(10, buffer, &send_bytes, &last));
EXPECT_EQ(send_bytes,6); // First 5 from last partition, 1 header EXPECT_FALSE(last);
EXPECT_RSV_ZERO(buffer[0]); EXPECT_EQ(send_bytes,6); // Last 5 from first partition, 1 header
EXPECT_BIT_I_EQ(buffer[0], 0);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x01);
EXPECT_BIT_B_EQ(buffer[0], 0);
for (int i = 1; i < 6; i++)
{
EXPECT_EQ(buffer[i], 2);
}
// get third packet
// second half of last partition
EXPECT_TRUE(packetizer.NextPacket(6, buffer, &send_bytes)); // last packet
EXPECT_EQ(send_bytes,6); // Last 5 from last partition, 1 header
EXPECT_RSV_ZERO(buffer[0]); EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0); EXPECT_BIT_I_EQ(buffer[0], 0);
EXPECT_BIT_N_EQ(buffer[0], 0); EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x02); EXPECT_FI_EQ(buffer[0], 0x02);
EXPECT_BIT_B_EQ(buffer[0], 0); EXPECT_BIT_B_EQ(buffer[0], 0);
for (int i = 1; i < 6; i++) for (int i = 1; i < 6; i++)
{
EXPECT_EQ(buffer[i], 0);
}
// get third packet
// last two partitions aggregated
EXPECT_EQ(0, packetizer.NextPacket(25, buffer, &send_bytes, &last));
EXPECT_TRUE(last); // last packet
EXPECT_EQ(send_bytes,21); // Two 10-byte partitions and 1 byte header
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x00);
EXPECT_BIT_B_EQ(buffer[0], 0);
for (int i = 1; i < 11; i++)
{
EXPECT_EQ(buffer[i], 1);
}
for (int i = 11; i < 21; i++)
{ {
EXPECT_EQ(buffer[i], 2); EXPECT_EQ(buffer[i], 2);
} }
} }
TEST_F(RTPFormatVP8Test, TestSloppyMode) TEST_F(RtpFormatVp8Test, TestSloppyMode)
{ {
WebRtc_UWord8 buffer[30]; WebRtc_UWord8 buffer[kPayloadSize];
int send_bytes = 0; int send_bytes = 0;
bool last;
RTPFormatVP8 packetizer = RTPFormatVP8(payload_data, payload_size, fragmentation, RtpFormatVp8 packetizer = RtpFormatVp8(payload_data, kPayloadSize,
kSloppy); fragmentation, webrtc::kSloppy);
// get first packet // get first packet
EXPECT_FALSE(packetizer.NextPacket(9, buffer, &send_bytes)); EXPECT_EQ(0, packetizer.NextPacket(9, buffer, &send_bytes, &last));
EXPECT_FALSE(last);
EXPECT_EQ(send_bytes,9); // 8 bytes payload and 1 byte header EXPECT_EQ(send_bytes,9); // 8 bytes payload and 1 byte header
EXPECT_RSV_ZERO(buffer[0]); EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 1); EXPECT_BIT_I_EQ(buffer[0], 1);
@ -225,7 +250,8 @@ TEST_F(RTPFormatVP8Test, TestSloppyMode)
// get second packet // get second packet
// fragments of first and second partitions // fragments of first and second partitions
EXPECT_FALSE(packetizer.NextPacket(9, buffer, &send_bytes)); EXPECT_EQ(0, packetizer.NextPacket(9, buffer, &send_bytes, &last));
EXPECT_FALSE(last);
EXPECT_EQ(send_bytes,9); // 8 bytes (2+6) payload and 1 byte header EXPECT_EQ(send_bytes,9); // 8 bytes (2+6) payload and 1 byte header
EXPECT_RSV_ZERO(buffer[0]); EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0); EXPECT_BIT_I_EQ(buffer[0], 0);
@ -243,7 +269,8 @@ TEST_F(RTPFormatVP8Test, TestSloppyMode)
// get third packet // get third packet
// fragments of second and third partitions // fragments of second and third partitions
EXPECT_FALSE(packetizer.NextPacket(9, buffer, &send_bytes)); EXPECT_EQ(0, packetizer.NextPacket(9, buffer, &send_bytes, &last));
EXPECT_FALSE(last);
EXPECT_EQ(send_bytes,9); // 8 bytes (4+4) payload and 1 byte header EXPECT_EQ(send_bytes,9); // 8 bytes (4+4) payload and 1 byte header
EXPECT_RSV_ZERO(buffer[0]); EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0); EXPECT_BIT_I_EQ(buffer[0], 0);
@ -261,7 +288,8 @@ TEST_F(RTPFormatVP8Test, TestSloppyMode)
// get fourth packet // get fourth packet
// second half of last partition // second half of last partition
EXPECT_TRUE(packetizer.NextPacket(9, buffer, &send_bytes)); // last packet EXPECT_EQ(0, packetizer.NextPacket(9, buffer, &send_bytes, &last));
EXPECT_TRUE(last); // last packet
EXPECT_EQ(send_bytes,7); // Last 6 from last partition, 1 header EXPECT_EQ(send_bytes,7); // Last 6 from last partition, 1 header
EXPECT_RSV_ZERO(buffer[0]); EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0); EXPECT_BIT_I_EQ(buffer[0], 0);
@ -276,16 +304,18 @@ TEST_F(RTPFormatVP8Test, TestSloppyMode)
} }
// Verify that sloppy mode is forced if fragmentation info is missing. // Verify that sloppy mode is forced if fragmentation info is missing.
TEST_F(RTPFormatVP8Test, TestSloppyModeFallback) TEST_F(RtpFormatVp8Test, TestSloppyModeFallback)
{ {
WebRtc_UWord8 buffer[30]; WebRtc_UWord8 buffer[kPayloadSize];
int send_bytes = 0; int send_bytes = 0;
bool last;
RTPFormatVP8 packetizer = RTPFormatVP8(payload_data, payload_size, NULL /*fragmentation*/, RtpFormatVp8 packetizer = RtpFormatVp8(payload_data, kPayloadSize,
kStrict); // should be changed to kSlopy NULL /*fragInfo*/, webrtc::kStrict); // should be changed to kSloppy
// get first packet // get first packet
EXPECT_FALSE(packetizer.NextPacket(9, buffer, &send_bytes)); EXPECT_EQ(0, packetizer.NextPacket(9, buffer, &send_bytes, &last));
EXPECT_FALSE(last);
EXPECT_EQ(send_bytes,9); // 8 bytes payload and 1 byte header EXPECT_EQ(send_bytes,9); // 8 bytes payload and 1 byte header
EXPECT_RSV_ZERO(buffer[0]); EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 1); EXPECT_BIT_I_EQ(buffer[0], 1);
@ -299,7 +329,8 @@ TEST_F(RTPFormatVP8Test, TestSloppyModeFallback)
// get second packet // get second packet
// fragments of first and second partitions // fragments of first and second partitions
EXPECT_FALSE(packetizer.NextPacket(9, buffer, &send_bytes)); EXPECT_EQ(0, packetizer.NextPacket(9, buffer, &send_bytes, &last));
EXPECT_FALSE(last);
EXPECT_EQ(send_bytes,9); // 8 bytes (2+6) payload and 1 byte header EXPECT_EQ(send_bytes,9); // 8 bytes (2+6) payload and 1 byte header
EXPECT_RSV_ZERO(buffer[0]); EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0); EXPECT_BIT_I_EQ(buffer[0], 0);
@ -317,7 +348,8 @@ TEST_F(RTPFormatVP8Test, TestSloppyModeFallback)
// get third packet // get third packet
// fragments of second and third partitions // fragments of second and third partitions
EXPECT_FALSE(packetizer.NextPacket(9, buffer, &send_bytes)); EXPECT_EQ(0, packetizer.NextPacket(9, buffer, &send_bytes, &last));
EXPECT_FALSE(last);
EXPECT_EQ(send_bytes,9); // 8 bytes (4+4) payload and 1 byte header EXPECT_EQ(send_bytes,9); // 8 bytes (4+4) payload and 1 byte header
EXPECT_RSV_ZERO(buffer[0]); EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0); EXPECT_BIT_I_EQ(buffer[0], 0);
@ -335,7 +367,8 @@ TEST_F(RTPFormatVP8Test, TestSloppyModeFallback)
// get fourth packet // get fourth packet
// second half of last partition // second half of last partition
EXPECT_TRUE(packetizer.NextPacket(9, buffer, &send_bytes)); // last packet EXPECT_EQ(0, packetizer.NextPacket(9, buffer, &send_bytes, &last));
EXPECT_TRUE(last); // last packet
EXPECT_EQ(send_bytes,7); // Last 6 from last partition, 1 header EXPECT_EQ(send_bytes,7); // Last 6 from last partition, 1 header
EXPECT_RSV_ZERO(buffer[0]); EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0); EXPECT_BIT_I_EQ(buffer[0], 0);
@ -355,362 +388,4 @@ int main(int argc, char** argv) {
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();
} }
} } // namespace
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
/*
* This file includes unit tests for the VP8 packetizer.
*/
#include "unit_test.h"
#include "rtp_format_vp8.h"
namespace webrtc {
RTPFormatVP8Test::RTPFormatVP8Test()
{
}
void RTPFormatVP8Test::SetUp() {
payload_data = new WebRtc_UWord8[30];
payload_size = 30;
for (int i = 0; i < payload_size; i++)
{
payload_data[i] = i / 10; // integer division
}
fragmentation = new RTPFragmentationHeader;
fragmentation->VerifyAndAllocateFragmentationHeader(3);
fragmentation->fragmentationLength[0] = 10;
fragmentation->fragmentationLength[1] = 10;
fragmentation->fragmentationLength[2] = 10;
fragmentation->fragmentationOffset[0] = 0;
fragmentation->fragmentationOffset[1] = 10;
fragmentation->fragmentationOffset[2] = 20;
}
void RTPFormatVP8Test::TearDown() {
delete [] payload_data;
delete fragmentation;
}
#define EXPECT_BIT_EQ(x,n,a) EXPECT_EQ((((x)>>n)&0x1), a)
#define EXPECT_RSV_ZERO(x) EXPECT_EQ(((x)&0xE0), 0)
//#define EXPECT_BIT_I_EQ(x,a) EXPECT_EQ((((x)&0x10) > 0), (a > 0))
#define EXPECT_BIT_I_EQ(x,a) EXPECT_BIT_EQ(x, 4, a)
#define EXPECT_BIT_N_EQ(x,a) EXPECT_EQ((((x)&0x08) > 0), (a > 0))
#define EXPECT_FI_EQ(x,a) EXPECT_EQ((((x)&0x06) >> 1), a)
#define EXPECT_BIT_B_EQ(x,a) EXPECT_EQ((((x)&0x01) > 0), (a > 0))
TEST_F(RTPFormatVP8Test, TestStrictMode)
{
WebRtc_UWord8 buffer[20];
int send_bytes = 0;
RTPFormatVP8 packetizer = RTPFormatVP8(payload_data, payload_size, fragmentation, kStrict);
// get first packet
EXPECT_FALSE(packetizer.NextPacket(8, buffer, &send_bytes));
EXPECT_EQ(send_bytes,8);
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 1);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x01);
EXPECT_BIT_B_EQ(buffer[0], 1);
for (int i = 1; i < 8; i++)
{
EXPECT_EQ(buffer[i], 0);
}
// get second packet
EXPECT_FALSE(packetizer.NextPacket(8, buffer, &send_bytes));
EXPECT_EQ(send_bytes,4); // 3 remaining from partition, 1 header
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x02);
EXPECT_BIT_B_EQ(buffer[0], 0);
for (int i = 1; i < 4; i++)
{
EXPECT_EQ(buffer[i], 0);
}
// Second partition
// Get first (and only) packet
EXPECT_FALSE(packetizer.NextPacket(20, buffer, &send_bytes));
EXPECT_EQ(send_bytes,11);
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x00);
EXPECT_BIT_B_EQ(buffer[0], 0);
for (int i = 1; i < 11; i++)
{
EXPECT_EQ(buffer[i], 1);
}
// Third partition
// Get first packet (of three)
EXPECT_FALSE(packetizer.NextPacket(5, buffer, &send_bytes));
EXPECT_EQ(send_bytes,5);
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x01); // first fragment
EXPECT_BIT_B_EQ(buffer[0], 0);
for (int i = 1; i < 5; i++)
{
EXPECT_EQ(buffer[i], 2);
}
// Get second packet (of three)
EXPECT_FALSE(packetizer.NextPacket(5, buffer, &send_bytes));
EXPECT_EQ(send_bytes,5);
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x03); // middle fragment
EXPECT_BIT_B_EQ(buffer[0], 0);
for (int i = 1; i < 5; i++)
{
EXPECT_EQ(buffer[i], 2);
}
// Get third and last packet
EXPECT_TRUE(packetizer.NextPacket(5, buffer, &send_bytes)); // last packet in frame
EXPECT_EQ(send_bytes,3); // 2 bytes payload left, 1 header
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x02); // last fragment
EXPECT_BIT_B_EQ(buffer[0], 0);
for (int i = 1; i < 3; i++)
{
EXPECT_EQ(buffer[i], 2);
}
}
TEST_F(RTPFormatVP8Test, TestAggregateMode)
{
WebRtc_UWord8 buffer[30];
int send_bytes = 0;
RTPFormatVP8 packetizer = RTPFormatVP8(payload_data, payload_size, fragmentation,
kAggregate);
// get first packet
// first two partitions aggregated
EXPECT_FALSE(packetizer.NextPacket(25, buffer, &send_bytes));
EXPECT_EQ(send_bytes,21); // Two 10-byte partitions and 1 byte header
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 1);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x00);
EXPECT_BIT_B_EQ(buffer[0], 1);
for (int i = 1; i < 11; i++)
{
EXPECT_EQ(buffer[i], 0);
}
for (int i = 11; i < 21; i++)
{
EXPECT_EQ(buffer[i], 1);
}
// get second packet
// first half of last partition
EXPECT_FALSE(packetizer.NextPacket(6, buffer, &send_bytes));
EXPECT_EQ(send_bytes,6); // First 5 from last partition, 1 header
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x01);
EXPECT_BIT_B_EQ(buffer[0], 0);
for (int i = 1; i < 6; i++)
{
EXPECT_EQ(buffer[i], 2);
}
// get third packet
// second half of last partition
EXPECT_TRUE(packetizer.NextPacket(6, buffer, &send_bytes)); // last packet
EXPECT_EQ(send_bytes,6); // Last 5 from last partition, 1 header
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x02);
EXPECT_BIT_B_EQ(buffer[0], 0);
for (int i = 1; i < 6; i++)
{
EXPECT_EQ(buffer[i], 2);
}
}
TEST_F(RTPFormatVP8Test, TestSloppyMode)
{
WebRtc_UWord8 buffer[30];
int send_bytes = 0;
RTPFormatVP8 packetizer = RTPFormatVP8(payload_data, payload_size, fragmentation,
kSloppy);
// get first packet
EXPECT_FALSE(packetizer.NextPacket(9, buffer, &send_bytes));
EXPECT_EQ(send_bytes,9); // 8 bytes payload and 1 byte header
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 1);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x01);
EXPECT_BIT_B_EQ(buffer[0], 1);
for (int i = 1; i < 9; i++)
{
EXPECT_EQ(buffer[i], 0);
}
// get second packet
// fragments of first and second partitions
EXPECT_FALSE(packetizer.NextPacket(9, buffer, &send_bytes));
EXPECT_EQ(send_bytes,9); // 8 bytes (2+6) payload and 1 byte header
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x03);
EXPECT_BIT_B_EQ(buffer[0], 0);
for (int i = 1; i <= 2; i++)
{
EXPECT_EQ(buffer[i], 0);
}
for (int i = 3; i < 9; i++)
{
EXPECT_EQ(buffer[i], 1);
}
// get third packet
// fragments of second and third partitions
EXPECT_FALSE(packetizer.NextPacket(9, buffer, &send_bytes));
EXPECT_EQ(send_bytes,9); // 8 bytes (4+4) payload and 1 byte header
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x03);
EXPECT_BIT_B_EQ(buffer[0], 0);
for (int i = 1; i <= 4; i++)
{
EXPECT_EQ(buffer[i], 1);
}
for (int i = 5; i < 9; i++)
{
EXPECT_EQ(buffer[i], 2);
}
// get fourth packet
// second half of last partition
EXPECT_TRUE(packetizer.NextPacket(9, buffer, &send_bytes)); // last packet
EXPECT_EQ(send_bytes,7); // Last 6 from last partition, 1 header
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x02);
EXPECT_BIT_B_EQ(buffer[0], 0);
for (int i = 1; i < 5; i++)
{
EXPECT_EQ(buffer[i], 2);
}
}
// Verify that sloppy mode is forced if fragmentation info is missing.
TEST_F(RTPFormatVP8Test, TestSloppyModeFallback)
{
WebRtc_UWord8 buffer[30];
int send_bytes = 0;
RTPFormatVP8 packetizer = RTPFormatVP8(payload_data, payload_size, NULL /*fragmentation*/,
kStrict); // should be changed to kSlopy
// get first packet
EXPECT_FALSE(packetizer.NextPacket(9, buffer, &send_bytes));
EXPECT_EQ(send_bytes,9); // 8 bytes payload and 1 byte header
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 1);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x01);
EXPECT_BIT_B_EQ(buffer[0], 1);
for (int i = 1; i < 9; i++)
{
EXPECT_EQ(buffer[i], 0);
}
// get second packet
// fragments of first and second partitions
EXPECT_FALSE(packetizer.NextPacket(9, buffer, &send_bytes));
EXPECT_EQ(send_bytes,9); // 8 bytes (2+6) payload and 1 byte header
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x03);
EXPECT_BIT_B_EQ(buffer[0], 0);
for (int i = 1; i <= 2; i++)
{
EXPECT_EQ(buffer[i], 0);
}
for (int i = 3; i < 9; i++)
{
EXPECT_EQ(buffer[i], 1);
}
// get third packet
// fragments of second and third partitions
EXPECT_FALSE(packetizer.NextPacket(9, buffer, &send_bytes));
EXPECT_EQ(send_bytes,9); // 8 bytes (4+4) payload and 1 byte header
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x03);
EXPECT_BIT_B_EQ(buffer[0], 0);
for (int i = 1; i <= 4; i++)
{
EXPECT_EQ(buffer[i], 1);
}
for (int i = 5; i < 9; i++)
{
EXPECT_EQ(buffer[i], 2);
}
// get fourth packet
// second half of last partition
EXPECT_TRUE(packetizer.NextPacket(9, buffer, &send_bytes)); // last packet
EXPECT_EQ(send_bytes,7); // Last 6 from last partition, 1 header
EXPECT_RSV_ZERO(buffer[0]);
EXPECT_BIT_I_EQ(buffer[0], 0);
EXPECT_BIT_N_EQ(buffer[0], 0);
EXPECT_FI_EQ(buffer[0], 0x02);
EXPECT_BIT_B_EQ(buffer[0], 0);
for (int i = 1; i < 5; i++)
{
EXPECT_EQ(buffer[i], 2);
}
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
}

View File

@ -1,78 +0,0 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
/*
* This header file includes declaration for unit tests for the VP8 packetizer.
*/
#ifndef WEBRTC_RTP_FORMAT_VP8_UNIT_TEST_H_
#define WEBRTC_RTP_FORMAT_VP8_UNIT_TEST_H_
#include <gtest/gtest.h>
#include "typedefs.h"
namespace webrtc {
class RTPFragmentationHeader;
class RTPFormatVP8Test : public ::testing::Test {
protected:
RTPFormatVP8Test();
virtual void SetUp();
virtual void TearDown();
WebRtc_UWord8* payload_data;
WebRtc_UWord32 payload_size;
RTPFragmentationHeader* fragmentation;
};
}
#endif // WEBRTC_RTP_FORMAT_VP8_UNIT_TEST_H_
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
/*
* This header file includes declaration for unit tests for the VP8 packetizer.
*/
#ifndef WEBRTC_RTP_FORMAT_VP8_UNIT_TEST_H_
#define WEBRTC_RTP_FORMAT_VP8_UNIT_TEST_H_
#include <gtest/gtest.h>
#include "typedefs.h"
namespace webrtc {
class RTPFragmentationHeader;
class RTPFormatVP8Test : public ::testing::Test {
protected:
RTPFormatVP8Test();
virtual void SetUp();
virtual void TearDown();
WebRtc_UWord8* payload_data;
WebRtc_UWord32 payload_size;
RTPFragmentationHeader* fragmentation;
};
}
#endif // WEBRTC_RTP_FORMAT_VP8_UNIT_TEST_H_