git-svn-id: http://webrtc.googlecode.com/svn/trunk@164 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
f50cf1f9da
commit
9ad0cf1ae2
@ -41,10 +41,14 @@ struct RTPVideoHeaderH263
|
|||||||
bool bits; // H.263 mode B, Xor the lasy byte of previus packet with the
|
bool bits; // H.263 mode B, Xor the lasy byte of previus packet with the
|
||||||
// first byte of this packet
|
// first byte of this packet
|
||||||
};
|
};
|
||||||
|
enum {kNoPictureId = -1};
|
||||||
struct RTPVideoHeaderVP8
|
struct RTPVideoHeaderVP8
|
||||||
{
|
{
|
||||||
bool startBit; // Start of partition
|
bool startBit; // Start of partition.
|
||||||
bool stopBit; // Stop of partition
|
bool stopBit; // Stop of partition.
|
||||||
|
WebRtc_Word16 pictureId; // Picture ID index, 15 bits;
|
||||||
|
// kNoPictureId if PictureID does not exist.
|
||||||
|
bool nonReference; // Frame is discardable.
|
||||||
};
|
};
|
||||||
union RTPVideoTypeHeader
|
union RTPVideoTypeHeader
|
||||||
{
|
{
|
||||||
|
@ -47,21 +47,23 @@ public:
|
|||||||
// The payload_data must be exactly one encoded VP8 frame.
|
// The payload_data must be exactly one encoded VP8 frame.
|
||||||
RtpFormatVp8(const WebRtc_UWord8* payload_data,
|
RtpFormatVp8(const WebRtc_UWord8* payload_data,
|
||||||
WebRtc_UWord32 payload_size,
|
WebRtc_UWord32 payload_size,
|
||||||
|
const RTPVideoHeaderVP8& hdr_info,
|
||||||
const RTPFragmentationHeader& fragmentation,
|
const RTPFragmentationHeader& fragmentation,
|
||||||
VP8PacketizerMode mode);
|
VP8PacketizerMode mode);
|
||||||
|
|
||||||
// Initialize without fragmentation info. Mode kSloppy will be used.
|
// Initialize without fragmentation info. Mode kSloppy will be used.
|
||||||
// The payload_data must be exactly one encoded VP8 frame.
|
// The payload_data must be exactly one encoded VP8 frame.
|
||||||
RtpFormatVp8(const WebRtc_UWord8* payload_data,
|
RtpFormatVp8(const WebRtc_UWord8* payload_data,
|
||||||
WebRtc_UWord32 payload_size);
|
WebRtc_UWord32 payload_size,
|
||||||
|
const RTPVideoHeaderVP8& hdr_info);
|
||||||
|
|
||||||
// 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. Parameter last_packet is true for the last packet of
|
||||||
// Returns true for the last packet of the frame, false otherwise (i.e.,
|
// the frame, false otherwise (i.e., call the function again to get the
|
||||||
// call the function again to get the next packet).
|
// next packet). Returns negative on error, zero otherwise.
|
||||||
int NextPacket(int max_payload_len, WebRtc_UWord8* buffer,
|
int NextPacket(int max_payload_len, WebRtc_UWord8* buffer,
|
||||||
int* bytes_to_send, bool* last_packet);
|
int* bytes_to_send, bool* last_packet);
|
||||||
|
|
||||||
@ -74,8 +76,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const AggregationMode aggr_modes_[kNumModes];
|
static const AggregationMode aggr_modes_[kNumModes];
|
||||||
static const bool bal_modes_[kNumModes];
|
static const bool balance_modes_[kNumModes];
|
||||||
static const bool sep_first_modes_[kNumModes];
|
static const bool separate_first_modes_[kNumModes];
|
||||||
|
|
||||||
// Calculate size of next chunk to send. Returns 0 if none can be sent.
|
// Calculate size of next chunk to send. Returns 0 if none can be sent.
|
||||||
int CalcNextSize(int max_payload_len, int remaining_bytes,
|
int CalcNextSize(int max_payload_len, int remaining_bytes,
|
||||||
@ -86,7 +88,20 @@ private:
|
|||||||
// 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(int send_bytes, bool end_of_fragment,
|
int WriteHeaderAndPayload(int send_bytes, bool end_of_fragment,
|
||||||
WebRtc_UWord8* buffer);
|
WebRtc_UWord8* buffer, int buffer_length);
|
||||||
|
|
||||||
|
// Write the PictureID from codec_specific_info_ to buffer. One or two
|
||||||
|
// bytes are written, depending on magnitude of PictureID. The function
|
||||||
|
// returns the number of bytes written.
|
||||||
|
int WritePictureID(WebRtc_UWord8* buffer, int buffer_length) const;
|
||||||
|
|
||||||
|
// Calculate and return length (octets) of the variable header fields in
|
||||||
|
// the next header (i.e., header length in addition to vp8_header_bytes_).
|
||||||
|
int FirstHeaderExtraLength() const;
|
||||||
|
|
||||||
|
// Calculate and return length (octets) of PictureID field in the next
|
||||||
|
// header. Can be 0, 1, or 2.
|
||||||
|
int PictureIdLength() const;
|
||||||
|
|
||||||
const WebRtc_UWord8* payload_data_;
|
const WebRtc_UWord8* payload_data_;
|
||||||
const int payload_size_;
|
const int payload_size_;
|
||||||
@ -95,10 +110,11 @@ private:
|
|||||||
int part_ix_;
|
int part_ix_;
|
||||||
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
|
||||||
const int vp8_header_bytes_; // length of VP8 payload header
|
const int vp8_header_bytes_; // length of VP8 payload header's fixed part
|
||||||
AggregationMode aggr_mode_;
|
AggregationMode aggr_mode_;
|
||||||
bool balance_;
|
bool balance_;
|
||||||
bool separate_first_;
|
bool separate_first_;
|
||||||
|
const RTPVideoHeaderVP8 hdr_info_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
353
src/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc
Normal file
353
src/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc
Normal file
@ -0,0 +1,353 @@
|
|||||||
|
/*
|
||||||
|
* 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 <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "typedefs.h"
|
||||||
|
#include "rtp_format_vp8.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using webrtc::RTPFragmentationHeader;
|
||||||
|
using webrtc::RtpFormatVp8;
|
||||||
|
using webrtc::RTPVideoHeaderVP8;
|
||||||
|
|
||||||
|
const WebRtc_UWord32 kPayloadSize = 30;
|
||||||
|
|
||||||
|
class RtpFormatVp8Test : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
RtpFormatVp8Test() {};
|
||||||
|
virtual void SetUp();
|
||||||
|
virtual void TearDown();
|
||||||
|
void CheckHeader(bool first_in_frame, bool frag_start, bool frag_end);
|
||||||
|
void CheckPayload(int payload_end);
|
||||||
|
void CheckLast(bool last) const;
|
||||||
|
void CheckPacket(int send_bytes, int expect_bytes, bool last,
|
||||||
|
bool first_in_frame, bool frag_start, bool frag_end);
|
||||||
|
WebRtc_UWord8 payload_data_[kPayloadSize];
|
||||||
|
WebRtc_UWord8 buffer_[kPayloadSize];
|
||||||
|
WebRtc_UWord8 *data_ptr_;
|
||||||
|
RTPFragmentationHeader* fragmentation_;
|
||||||
|
RTPVideoHeaderVP8 hdr_info_;
|
||||||
|
int payload_start_;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RtpFormatVp8Test::SetUp() {
|
||||||
|
for (int i = 0; i < kPayloadSize; i++)
|
||||||
|
{
|
||||||
|
payload_data_[i] = i / 10; // integer division
|
||||||
|
}
|
||||||
|
data_ptr_ = payload_data_;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
hdr_info_.pictureId = 0;
|
||||||
|
hdr_info_.nonReference = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtpFormatVp8Test::TearDown() {
|
||||||
|
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))
|
||||||
|
|
||||||
|
void RtpFormatVp8Test::CheckHeader(bool first_in_frame, bool frag_start,
|
||||||
|
bool frag_end)
|
||||||
|
{
|
||||||
|
payload_start_ = 1;
|
||||||
|
EXPECT_RSV_ZERO(buffer_[0]);
|
||||||
|
if (first_in_frame & hdr_info_.pictureId != webrtc::kNoPictureId)
|
||||||
|
{
|
||||||
|
EXPECT_BIT_I_EQ(buffer_[0], 1);
|
||||||
|
if (hdr_info_.pictureId > 0x7F)
|
||||||
|
{
|
||||||
|
EXPECT_BIT_EQ(buffer_[1], 7, 1);
|
||||||
|
EXPECT_EQ(buffer_[1] & 0x7F,
|
||||||
|
(hdr_info_.pictureId >> 8) & 0x7F);
|
||||||
|
EXPECT_EQ(buffer_[2], hdr_info_.pictureId & 0xFF);
|
||||||
|
payload_start_ += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EXPECT_BIT_EQ(buffer_[1], 7, 0);
|
||||||
|
EXPECT_EQ(buffer_[1] & 0x7F,
|
||||||
|
(hdr_info_.pictureId) & 0x7F);
|
||||||
|
payload_start_ += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_BIT_N_EQ(buffer_[0], 0);
|
||||||
|
WebRtc_UWord8 fi = 0x03;
|
||||||
|
if (frag_start) fi = fi & 0x01;
|
||||||
|
if (frag_end) fi = fi & 0x02;
|
||||||
|
EXPECT_FI_EQ(buffer_[0], fi);
|
||||||
|
if (first_in_frame) EXPECT_BIT_B_EQ(buffer_[0], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtpFormatVp8Test::CheckPayload(int payload_end)
|
||||||
|
{
|
||||||
|
for (int i = payload_start_; i < payload_end; i++, data_ptr_++)
|
||||||
|
EXPECT_EQ(buffer_[i], *data_ptr_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtpFormatVp8Test::CheckLast(bool last) const
|
||||||
|
{
|
||||||
|
EXPECT_EQ(last, data_ptr_ == payload_data_ + kPayloadSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtpFormatVp8Test::CheckPacket(int send_bytes, int expect_bytes, bool last,
|
||||||
|
bool first_in_frame, bool frag_start, bool frag_end)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(send_bytes, expect_bytes);
|
||||||
|
CheckHeader(first_in_frame, frag_start, frag_end);
|
||||||
|
CheckPayload(send_bytes);
|
||||||
|
CheckLast(last);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RtpFormatVp8Test, TestStrictMode)
|
||||||
|
{
|
||||||
|
int send_bytes = 0;
|
||||||
|
bool last;
|
||||||
|
bool first_in_frame = true;
|
||||||
|
|
||||||
|
hdr_info_.pictureId = 200; // > 0x7F should produce 2-byte PictureID
|
||||||
|
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
|
||||||
|
hdr_info_, *fragmentation_, webrtc::kStrict);
|
||||||
|
|
||||||
|
// get first packet, expect balanced size = same as second packet
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(8, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 7, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ true,
|
||||||
|
/* frag_end */ false);
|
||||||
|
first_in_frame = false;
|
||||||
|
|
||||||
|
// get second packet
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(8, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 7, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ false,
|
||||||
|
/* frag_end */ true);
|
||||||
|
|
||||||
|
// Second partition
|
||||||
|
// Get first (and only) packet
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(20, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 11, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ true,
|
||||||
|
/* frag_end */ true);
|
||||||
|
|
||||||
|
// Third partition
|
||||||
|
// Get first packet (of four)
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(4, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 4, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ true,
|
||||||
|
/* frag_end */ false);
|
||||||
|
|
||||||
|
// Get second packet (of four)
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(4, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 3, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ false,
|
||||||
|
/* frag_end */ false);
|
||||||
|
|
||||||
|
// Get third packet (of four)
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(4, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 4, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ false,
|
||||||
|
/* frag_end */ false);
|
||||||
|
|
||||||
|
// Get fourth and last packet
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(4, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 3, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ false,
|
||||||
|
/* frag_end */ true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RtpFormatVp8Test, TestAggregateMode)
|
||||||
|
{
|
||||||
|
int send_bytes = 0;
|
||||||
|
bool last;
|
||||||
|
bool first_in_frame = true;
|
||||||
|
|
||||||
|
hdr_info_.pictureId = 20; // <= 0x7F should produce 1-byte PictureID
|
||||||
|
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
|
||||||
|
hdr_info_, *fragmentation_, webrtc::kAggregate);
|
||||||
|
|
||||||
|
// get first packet
|
||||||
|
// first half of first partition
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(6, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 6, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ true,
|
||||||
|
/* frag_end */ false);
|
||||||
|
first_in_frame = false;
|
||||||
|
|
||||||
|
// get second packet
|
||||||
|
// second half of first partition
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(10, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 7, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ false,
|
||||||
|
/* frag_end */ true);
|
||||||
|
|
||||||
|
// get third packet
|
||||||
|
// last two partitions aggregated
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(25, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 21, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ true,
|
||||||
|
/* frag_end */ true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RtpFormatVp8Test, TestSloppyMode)
|
||||||
|
{
|
||||||
|
int send_bytes = 0;
|
||||||
|
bool last;
|
||||||
|
bool first_in_frame = true;
|
||||||
|
|
||||||
|
hdr_info_.pictureId = webrtc::kNoPictureId; // no PictureID
|
||||||
|
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
|
||||||
|
hdr_info_, *fragmentation_, webrtc::kSloppy);
|
||||||
|
|
||||||
|
// get first packet
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 9, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ true,
|
||||||
|
/* frag_end */ false);
|
||||||
|
first_in_frame = false;
|
||||||
|
|
||||||
|
// get second packet
|
||||||
|
// fragments of first and second partitions
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 9, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ false,
|
||||||
|
/* frag_end */ false);
|
||||||
|
|
||||||
|
// get third packet
|
||||||
|
// fragments of second and third partitions
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 9, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ false,
|
||||||
|
/* frag_end */ false);
|
||||||
|
|
||||||
|
// get fourth packet
|
||||||
|
// second half of last partition
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 7, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ false,
|
||||||
|
/* frag_end */ true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that sloppy mode is forced if fragmentation info is missing.
|
||||||
|
TEST_F(RtpFormatVp8Test, TestSloppyModeFallback)
|
||||||
|
{
|
||||||
|
int send_bytes = 0;
|
||||||
|
bool last;
|
||||||
|
bool first_in_frame = true;
|
||||||
|
|
||||||
|
hdr_info_.pictureId = 200; // > 0x7F should produce 2-byte PictureID
|
||||||
|
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
|
||||||
|
hdr_info_);
|
||||||
|
|
||||||
|
// get first packet
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 9, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ true,
|
||||||
|
/* frag_end */ false);
|
||||||
|
first_in_frame = false;
|
||||||
|
|
||||||
|
// get second packet
|
||||||
|
// fragments of first and second partitions
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 9, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ false,
|
||||||
|
/* frag_end */ false);
|
||||||
|
|
||||||
|
// get third packet
|
||||||
|
// fragments of second and third partitions
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 9, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ false,
|
||||||
|
/* frag_end */ false);
|
||||||
|
|
||||||
|
// get fourth packet
|
||||||
|
// second half of last partition
|
||||||
|
EXPECT_EQ(0, packetizer.NextPacket(9, buffer_, &send_bytes, &last));
|
||||||
|
CheckPacket(send_bytes, 9, last,
|
||||||
|
first_in_frame,
|
||||||
|
/* frag_start */ false,
|
||||||
|
/* frag_end */ true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that non-reference bit is set.
|
||||||
|
TEST_F(RtpFormatVp8Test, TestNonReferenceBit) {
|
||||||
|
int send_bytes = 0;
|
||||||
|
bool last;
|
||||||
|
bool first_in_frame = true;
|
||||||
|
|
||||||
|
hdr_info_.nonReference = true;
|
||||||
|
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data_, kPayloadSize,
|
||||||
|
hdr_info_);
|
||||||
|
|
||||||
|
// get first packet
|
||||||
|
ASSERT_EQ(0, packetizer.NextPacket(25, buffer_, &send_bytes, &last));
|
||||||
|
ASSERT_FALSE(last);
|
||||||
|
EXPECT_BIT_N_EQ(buffer_[0], 1);
|
||||||
|
|
||||||
|
// get second packet
|
||||||
|
ASSERT_EQ(0, packetizer.NextPacket(25, buffer_, &send_bytes, &last));
|
||||||
|
ASSERT_TRUE(last);
|
||||||
|
EXPECT_BIT_N_EQ(buffer_[0], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
@ -8,24 +8,23 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
'includes': [
|
'includes': [
|
||||||
'../../../../common_settings.gypi', # Common settings
|
'../../../common_settings.gypi', # Common settings
|
||||||
],
|
],
|
||||||
'targets': [
|
'targets': [
|
||||||
{
|
{
|
||||||
'target_name': 'test_rtp_format_vp8',
|
'target_name': 'rtp_format_vp8_unittest',
|
||||||
'type': 'executable',
|
'type': 'executable',
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
'../../source/rtp_rtcp.gyp:rtp_rtcp',
|
'rtp_rtcp.gyp:rtp_rtcp',
|
||||||
'../../../../../testing/gtest.gyp:gtest',
|
'../../../../testing/gtest.gyp:gtest',
|
||||||
'../../../../../testing/gtest.gyp:gtest_main',
|
'../../../../testing/gtest.gyp:gtest_main',
|
||||||
],
|
],
|
||||||
'include_dirs': [
|
'include_dirs': [
|
||||||
'../../source',
|
'.',
|
||||||
],
|
],
|
||||||
'sources': [
|
'sources': [
|
||||||
'unit_test.h',
|
'rtp_format_vp8_unittest.h',
|
||||||
'unit_test.cc',
|
'rtp_format_vp8_unittest.cc',
|
||||||
'../../source/rtp_format_vp8.cc',
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
@ -1195,17 +1195,6 @@ RTPSenderVideo::SendH263MBs(const FrameType frameType,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
0 1 2 3
|
|
||||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
||||||
| RSV |I|N|FI |B| PictureID (integer #bytes) |
|
|
||||||
+-+-+-+-+-+-+-+-+ |
|
|
||||||
: :
|
|
||||||
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
||||||
| : (VP8 data or VP8 payload header; byte aligned)|
|
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
||||||
*/
|
|
||||||
WebRtc_Word32
|
WebRtc_Word32
|
||||||
RTPSenderVideo::SendVP8(const FrameType frameType,
|
RTPSenderVideo::SendVP8(const FrameType frameType,
|
||||||
const WebRtc_Word8 payloadType,
|
const WebRtc_Word8 payloadType,
|
||||||
@ -1227,7 +1216,9 @@ 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);
|
assert(rtpTypeHdr);
|
||||||
|
RtpFormatVp8 packetizer(data, payloadBytesToSend, rtpTypeHdr->VP8,
|
||||||
|
*fragmentation, kStrict);
|
||||||
|
|
||||||
bool last = false;
|
bool last = false;
|
||||||
while (!last)
|
while (!last)
|
||||||
|
@ -120,8 +120,7 @@ private:
|
|||||||
const WebRtc_UWord8* payloadData,
|
const WebRtc_UWord8* payloadData,
|
||||||
const WebRtc_UWord32 payloadSize,
|
const WebRtc_UWord32 payloadSize,
|
||||||
const RTPFragmentationHeader* fragmentation,
|
const RTPFragmentationHeader* fragmentation,
|
||||||
const RTPVideoTypeHeader* /*rtpTypeHdr*/);
|
const RTPVideoTypeHeader* rtpTypeHdr);
|
||||||
// TODO(hlundin): Remove comments once we start using rtpTypeHdr.
|
|
||||||
|
|
||||||
// MPEG 4
|
// MPEG 4
|
||||||
WebRtc_Word32 FindMPEG4NALU(const WebRtc_UWord8* inData ,WebRtc_Word32 MaxPayloadLength);
|
WebRtc_Word32 FindMPEG4NALU(const WebRtc_UWord8* inData ,WebRtc_Word32 MaxPayloadLength);
|
||||||
|
@ -1,404 +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 file includes unit tests for the VP8 packetizer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
|
|
||||||
#include "typedefs.h"
|
|
||||||
#include "rtp_format_vp8.h"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
using webrtc::RTPFragmentationHeader;
|
|
||||||
using webrtc::RtpFormatVp8;
|
|
||||||
|
|
||||||
const WebRtc_UWord32 kPayloadSize = 30;
|
|
||||||
|
|
||||||
class RtpFormatVp8Test : public ::testing::Test {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
bool last;
|
|
||||||
|
|
||||||
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data, kPayloadSize,
|
|
||||||
*fragmentation, webrtc::kStrict);
|
|
||||||
|
|
||||||
// get first packet, expect balanced size = same as second packet
|
|
||||||
EXPECT_EQ(0, packetizer.NextPacket(8, buffer, &send_bytes, &last));
|
|
||||||
EXPECT_FALSE(last);
|
|
||||||
EXPECT_EQ(send_bytes,6);
|
|
||||||
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 < 6; i++)
|
|
||||||
{
|
|
||||||
EXPECT_EQ(buffer[i], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get second packet
|
|
||||||
EXPECT_EQ(0, packetizer.NextPacket(8, buffer, &send_bytes, &last));
|
|
||||||
EXPECT_FALSE(last);
|
|
||||||
EXPECT_EQ(send_bytes,6); // 5 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 < 6; i++)
|
|
||||||
{
|
|
||||||
EXPECT_EQ(buffer[i], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Second partition
|
|
||||||
// Get first (and only) packet
|
|
||||||
EXPECT_EQ(0, packetizer.NextPacket(20, buffer, &send_bytes, &last));
|
|
||||||
EXPECT_FALSE(last);
|
|
||||||
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 four)
|
|
||||||
EXPECT_EQ(0, packetizer.NextPacket(4, buffer, &send_bytes, &last));
|
|
||||||
EXPECT_FALSE(last);
|
|
||||||
EXPECT_EQ(send_bytes,4);
|
|
||||||
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 < 4; i++)
|
|
||||||
{
|
|
||||||
EXPECT_EQ(buffer[i], 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get second packet (of four)
|
|
||||||
EXPECT_EQ(0, packetizer.NextPacket(4, buffer, &send_bytes, &last));
|
|
||||||
EXPECT_FALSE(last);
|
|
||||||
EXPECT_EQ(send_bytes,3);
|
|
||||||
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 < 3; i++)
|
|
||||||
{
|
|
||||||
EXPECT_EQ(buffer[i], 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get third packet (of four)
|
|
||||||
EXPECT_EQ(0, packetizer.NextPacket(4, buffer, &send_bytes, &last));
|
|
||||||
EXPECT_FALSE(last);
|
|
||||||
EXPECT_EQ(send_bytes,4);
|
|
||||||
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 < 4; i++)
|
|
||||||
{
|
|
||||||
EXPECT_EQ(buffer[i], 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get fourth and last packet
|
|
||||||
EXPECT_EQ(0, packetizer.NextPacket(4, buffer, &send_bytes, &last));
|
|
||||||
EXPECT_TRUE(last); // 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[kPayloadSize];
|
|
||||||
int send_bytes = 0;
|
|
||||||
bool last;
|
|
||||||
|
|
||||||
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data, kPayloadSize,
|
|
||||||
*fragmentation, webrtc::kAggregate);
|
|
||||||
|
|
||||||
// get first packet
|
|
||||||
// first half of first partition
|
|
||||||
EXPECT_EQ(0, packetizer.NextPacket(6, buffer, &send_bytes, &last));
|
|
||||||
EXPECT_FALSE(last);
|
|
||||||
EXPECT_EQ(send_bytes,6); // First 5 from first partition, 1 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 < 6; i++)
|
|
||||||
{
|
|
||||||
EXPECT_EQ(buffer[i], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get second packet
|
|
||||||
// second half of first partition
|
|
||||||
EXPECT_EQ(0, packetizer.NextPacket(10, buffer, &send_bytes, &last));
|
|
||||||
EXPECT_FALSE(last);
|
|
||||||
EXPECT_EQ(send_bytes,6); // Last 5 from first 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], 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpFormatVp8Test, TestSloppyMode)
|
|
||||||
{
|
|
||||||
WebRtc_UWord8 buffer[kPayloadSize];
|
|
||||||
int send_bytes = 0;
|
|
||||||
bool last;
|
|
||||||
|
|
||||||
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data, kPayloadSize,
|
|
||||||
*fragmentation, webrtc::kSloppy);
|
|
||||||
|
|
||||||
// get first packet
|
|
||||||
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_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_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_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_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_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_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_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[kPayloadSize];
|
|
||||||
int send_bytes = 0;
|
|
||||||
bool last;
|
|
||||||
|
|
||||||
RtpFormatVp8 packetizer = RtpFormatVp8(payload_data, kPayloadSize);
|
|
||||||
|
|
||||||
// get first packet
|
|
||||||
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_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_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_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_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_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_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_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();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
@ -27,6 +27,8 @@ struct CodecSpecificInfoVP8
|
|||||||
WebRtc_UWord8 pictureIdSLI;
|
WebRtc_UWord8 pictureIdSLI;
|
||||||
bool hasReceivedRPSI;
|
bool hasReceivedRPSI;
|
||||||
WebRtc_UWord64 pictureIdRPSI;
|
WebRtc_UWord64 pictureIdRPSI;
|
||||||
|
WebRtc_Word16 pictureId; // negative value to skip pictureId
|
||||||
|
bool nonReference;
|
||||||
};
|
};
|
||||||
|
|
||||||
union CodecSpecificInfoUnion
|
union CodecSpecificInfoUnion
|
||||||
|
@ -241,7 +241,7 @@ VP8Encoder::InitEncode(const VideoCodec* inst,
|
|||||||
_height = inst->height;
|
_height = inst->height;
|
||||||
|
|
||||||
// random start 16 bits is enough
|
// random start 16 bits is enough
|
||||||
_pictureID = (WebRtc_UWord16)rand();
|
_pictureID = ((WebRtc_UWord16)rand()) % 0x7FFF;
|
||||||
|
|
||||||
// allocate memory for encoded image
|
// allocate memory for encoded image
|
||||||
if (_encodedImage._buffer != NULL)
|
if (_encodedImage._buffer != NULL)
|
||||||
@ -535,26 +535,16 @@ VP8Encoder::Encode(const RawImage& inputImage,
|
|||||||
}
|
}
|
||||||
else if (pkt->kind == VPX_CODEC_CX_FRAME_PKT)
|
else if (pkt->kind == VPX_CODEC_CX_FRAME_PKT)
|
||||||
{
|
{
|
||||||
// attach Picture ID
|
CodecSpecificInfo codecSpecific;
|
||||||
// we use 14 bits generating 1 or 2 bytes
|
codecSpecific.codecType = kVideoCodecVP8;
|
||||||
// TODO(hlundin): update to follow latest RTP spec
|
CodecSpecificInfoVP8 *vp8Info = &(codecSpecific.codecSpecific.VP8);
|
||||||
WebRtc_UWord8 pictureIdSize = 2;
|
|
||||||
// TODO(hlundin): we should refactor this so that the pictureID is
|
|
||||||
// signaled through a codec specific struct and added in the RTP module.
|
|
||||||
if (_pictureID > 0x7f)
|
|
||||||
{
|
|
||||||
// more than 7 bits
|
|
||||||
_encodedImage._buffer[0] = 0x80 | (WebRtc_UWord8)(_pictureID >> 7);
|
|
||||||
_encodedImage._buffer[1] = (WebRtc_UWord8)(_pictureID & 0x7f);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_encodedImage._buffer[0] = (WebRtc_UWord8)_pictureID;
|
|
||||||
pictureIdSize = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(_encodedImage._buffer+pictureIdSize, pkt->data.frame.buf, pkt->data.frame.sz);
|
vp8Info->pictureId = _pictureID;
|
||||||
_encodedImage._length = WebRtc_UWord32(pkt->data.frame.sz) + pictureIdSize;
|
vp8Info->nonReference
|
||||||
|
= (pkt->data.frame.flags & VPX_FRAME_IS_DROPPABLE);
|
||||||
|
|
||||||
|
memcpy(_encodedImage._buffer, pkt->data.frame.buf, pkt->data.frame.sz);
|
||||||
|
_encodedImage._length = WebRtc_UWord32(pkt->data.frame.sz);
|
||||||
_encodedImage._encodedHeight = _raw->h;
|
_encodedImage._encodedHeight = _raw->h;
|
||||||
_encodedImage._encodedWidth = _raw->w;
|
_encodedImage._encodedWidth = _raw->w;
|
||||||
|
|
||||||
@ -574,12 +564,10 @@ VP8Encoder::Encode(const RawImage& inputImage,
|
|||||||
|
|
||||||
// First partition
|
// First partition
|
||||||
fragInfo.fragmentationOffset[0] = 0;
|
fragInfo.fragmentationOffset[0] = 0;
|
||||||
WebRtc_UWord8 *firstByte = &_encodedImage._buffer[pictureIdSize];
|
WebRtc_UWord8 *firstByte = _encodedImage._buffer;
|
||||||
WebRtc_UWord32 tmpSize = (firstByte[2] << 16) | (firstByte[1] << 8)
|
WebRtc_UWord32 tmpSize = (firstByte[2] << 16) | (firstByte[1] << 8)
|
||||||
| firstByte[0];
|
| firstByte[0];
|
||||||
fragInfo.fragmentationLength[0] = (tmpSize >> 5) & 0x7FFFF;
|
fragInfo.fragmentationLength[0] = (tmpSize >> 5) & 0x7FFFF;
|
||||||
// Let the PictureID belong to the first partition.
|
|
||||||
fragInfo.fragmentationLength[0] += pictureIdSize;
|
|
||||||
fragInfo.fragmentationPlType[0] = 0; // not known here
|
fragInfo.fragmentationPlType[0] = 0; // not known here
|
||||||
fragInfo.fragmentationTimeDiff[0] = 0;
|
fragInfo.fragmentationTimeDiff[0] = 0;
|
||||||
|
|
||||||
@ -590,10 +578,11 @@ VP8Encoder::Encode(const RawImage& inputImage,
|
|||||||
fragInfo.fragmentationPlType[1] = 0; // not known here
|
fragInfo.fragmentationPlType[1] = 0; // not known here
|
||||||
fragInfo.fragmentationTimeDiff[1] = 0;
|
fragInfo.fragmentationTimeDiff[1] = 0;
|
||||||
|
|
||||||
_encodedCompleteCallback->Encoded(_encodedImage, NULL, &fragInfo);
|
_encodedCompleteCallback->Encoded(_encodedImage, &codecSpecific,
|
||||||
|
&fragInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
_pictureID++; // prepare next
|
_pictureID = (_pictureID + 1) % 0x7FFF; // prepare next
|
||||||
return WEBRTC_VIDEO_CODEC_OK;
|
return WEBRTC_VIDEO_CODEC_OK;
|
||||||
}
|
}
|
||||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||||
@ -732,18 +721,16 @@ VP8Decoder::Decode(const EncodedImage& inputImage,
|
|||||||
}
|
}
|
||||||
vpx_dec_iter_t _iter = NULL;
|
vpx_dec_iter_t _iter = NULL;
|
||||||
vpx_image_t* img;
|
vpx_image_t* img;
|
||||||
WebRtc_UWord64 pictureID = 0;
|
|
||||||
|
|
||||||
// scan for number of bytes used for picture ID
|
// scan for number of bytes used for picture ID
|
||||||
WebRtc_UWord8 numberOfBytes;
|
WebRtc_UWord64 pictureID = inputImage._buffer[0] & 0x7F;
|
||||||
for (numberOfBytes = 0;(inputImage._buffer[numberOfBytes] & 0x80 ) &&
|
WebRtc_UWord8 numberOfBytes = 1;
|
||||||
numberOfBytes < 8; numberOfBytes++)
|
if (inputImage._buffer[0] & 0x80)
|
||||||
{
|
{
|
||||||
pictureID += inputImage._buffer[numberOfBytes] & 0x7f;
|
pictureID <<= 8;
|
||||||
pictureID <<= 7;
|
pictureID += inputImage._buffer[1];
|
||||||
|
++numberOfBytes;
|
||||||
}
|
}
|
||||||
pictureID += inputImage._buffer[numberOfBytes] & 0x7f;
|
|
||||||
numberOfBytes++;
|
|
||||||
|
|
||||||
// check for missing frames
|
// check for missing frames
|
||||||
if (missingFrames)
|
if (missingFrames)
|
||||||
|
@ -247,7 +247,18 @@ void VCMEncodedFrameCallback::CopyCodecSpecific(const CodecSpecificInfo& info,
|
|||||||
RTPVideoTypeHeader** rtp) {
|
RTPVideoTypeHeader** rtp) {
|
||||||
switch (info.codecType)
|
switch (info.codecType)
|
||||||
{
|
{
|
||||||
//TODO(hlundin): Implement case for kVideoCodecVP8.
|
case kVideoCodecVP8: {
|
||||||
|
if (info.codecSpecific.VP8.pictureId < 0)
|
||||||
|
{
|
||||||
|
(*rtp)->VP8.pictureId = kNoPictureId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*rtp)->VP8.pictureId = info.codecSpecific.VP8.pictureId;
|
||||||
|
}
|
||||||
|
(*rtp)->VP8.nonReference = info.codecSpecific.VP8.nonReference;
|
||||||
|
return;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
// No codec specific info. Change RTP header pointer to NULL.
|
// No codec specific info. Change RTP header pointer to NULL.
|
||||||
*rtp = NULL;
|
*rtp = NULL;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user