Make VideoSendStreamTest::MaxPacketSize test a whole range of frame sizes, to make sure all corner cases are covered.
BUG=2428
R=pbos@webrtc.org, phoglund@webrtc.org, stefan@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/4849004
git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@5229 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/test/configurable_frame_size_encoder.cc b/test/configurable_frame_size_encoder.cc
new file mode 100644
index 0000000..0046f56
--- /dev/null
+++ b/test/configurable_frame_size_encoder.cc
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2013 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.
+ */
+
+#include "webrtc/test/configurable_frame_size_encoder.h"
+
+#include <string.h>
+
+#include "webrtc/common_video/interface/video_image.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace webrtc {
+namespace test {
+
+ConfigurableFrameSizeEncoder::ConfigurableFrameSizeEncoder(
+ uint32_t max_frame_size)
+ : callback_(NULL),
+ max_frame_size_(max_frame_size),
+ current_frame_size_(max_frame_size),
+ buffer_(new uint8_t[max_frame_size]) {
+ memset(buffer_.get(), 0, max_frame_size);
+}
+
+ConfigurableFrameSizeEncoder::~ConfigurableFrameSizeEncoder() {}
+
+int32_t ConfigurableFrameSizeEncoder::InitEncode(
+ const VideoCodec* codec_settings,
+ int32_t number_of_cores,
+ uint32_t max_payload_size) {
+ return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t ConfigurableFrameSizeEncoder::Encode(
+ const I420VideoFrame& inputImage,
+ const CodecSpecificInfo* codecSpecificInfo,
+ const std::vector<VideoFrameType>* frame_types) {
+ EncodedImage encodedImage(
+ buffer_.get(), current_frame_size_, max_frame_size_);
+ encodedImage._completeFrame = true;
+ encodedImage._encodedHeight = inputImage.height();
+ encodedImage._encodedWidth = inputImage.width();
+ encodedImage._frameType = kKeyFrame;
+ encodedImage._timeStamp = inputImage.timestamp();
+ encodedImage.capture_time_ms_ = inputImage.render_time_ms();
+ RTPFragmentationHeader* fragmentation = NULL;
+ callback_->Encoded(encodedImage, codecSpecificInfo, fragmentation);
+
+ return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t ConfigurableFrameSizeEncoder::RegisterEncodeCompleteCallback(
+ EncodedImageCallback* callback) {
+ callback_ = callback;
+ return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t ConfigurableFrameSizeEncoder::Release() {
+ return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t ConfigurableFrameSizeEncoder::SetChannelParameters(uint32_t packet_loss,
+ int rtt) {
+ return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t ConfigurableFrameSizeEncoder::SetRates(uint32_t new_bit_rate,
+ uint32_t frame_rate) {
+ return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t ConfigurableFrameSizeEncoder::SetPeriodicKeyFrames(bool enable) {
+ return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t ConfigurableFrameSizeEncoder::CodecConfigParameters(uint8_t* buffer,
+ int32_t size) {
+ return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t ConfigurableFrameSizeEncoder::SetFrameSize(uint32_t size) {
+ assert(size <= max_frame_size_);
+ current_frame_size_ = size;
+ return WEBRTC_VIDEO_CODEC_OK;
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/test/configurable_frame_size_encoder.h b/test/configurable_frame_size_encoder.h
new file mode 100644
index 0000000..f29038f
--- /dev/null
+++ b/test/configurable_frame_size_encoder.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013 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.
+ */
+
+#ifndef WEBRTC_TEST_CONFIGURABLE_FRAME_SIZE_ENCODER_H_
+#define WEBRTC_TEST_CONFIGURABLE_FRAME_SIZE_ENCODER_H_
+
+#include <vector>
+
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
+
+namespace webrtc {
+namespace test {
+
+class ConfigurableFrameSizeEncoder : public VideoEncoder {
+ public:
+ explicit ConfigurableFrameSizeEncoder(uint32_t max_frame_size);
+ virtual ~ConfigurableFrameSizeEncoder();
+
+ virtual int32_t InitEncode(const VideoCodec* codec_settings,
+ int32_t number_of_cores,
+ uint32_t max_payload_size) OVERRIDE;
+
+ virtual int32_t Encode(const I420VideoFrame& input_image,
+ const CodecSpecificInfo* codec_specific_info,
+ const std::vector<VideoFrameType>* frame_types)
+ OVERRIDE;
+
+ virtual int32_t RegisterEncodeCompleteCallback(EncodedImageCallback* callback)
+ OVERRIDE;
+
+ virtual int32_t Release() OVERRIDE;
+
+ virtual int32_t SetChannelParameters(uint32_t packet_loss, int rtt) OVERRIDE;
+
+ virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
+
+ virtual int32_t SetPeriodicKeyFrames(bool enable) OVERRIDE;
+
+ virtual int32_t CodecConfigParameters(uint8_t* buffer, int32_t size) OVERRIDE;
+
+ int32_t SetFrameSize(uint32_t size);
+
+ private:
+ EncodedImageCallback* callback_;
+ const uint32_t max_frame_size_;
+ uint32_t current_frame_size_;
+ scoped_ptr<uint8_t[]> buffer_;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // WEBRTC_TEST_CONFIGURABLE_FRAME_SIZE_ENCODER_H_
diff --git a/test/webrtc_test_common.gyp b/test/webrtc_test_common.gyp
index ebb2155..c7f6df5 100644
--- a/test/webrtc_test_common.gyp
+++ b/test/webrtc_test_common.gyp
@@ -14,6 +14,8 @@
'target_name': 'webrtc_test_common',
'type': 'static_library',
'sources': [
+ 'configurable_frame_size_encoder.cc',
+ 'configurable_frame_size_encoder.h',
'direct_transport.cc',
'direct_transport.h',
'fake_audio_device.cc',
diff --git a/video/video_send_stream_tests.cc b/video/video_send_stream_tests.cc
index 71cb96e..182894e 100644
--- a/video/video_send_stream_tests.cc
+++ b/video/video_send_stream_tests.cc
@@ -24,6 +24,7 @@
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "webrtc/test/direct_transport.h"
#include "webrtc/test/fake_encoder.h"
+#include "webrtc/test/configurable_frame_size_encoder.h"
#include "webrtc/test/frame_generator_capturer.h"
#include "webrtc/test/null_transport.h"
#include "webrtc/test/rtp_rtcp_observer.h"
@@ -528,11 +529,23 @@
TestNackRetransmission(kSendRtxSsrc, kSendRtxPayloadType, true);
}
-TEST_F(VideoSendStreamTest, MaxPacketSize) {
- class PacketSizeObserver : public test::RtpRtcpObserver {
+TEST_F(VideoSendStreamTest, FragmentsAccordingToMaxPacketSize) {
+ // Observer that verifies that the expected number of packets and bytes
+ // arrive for each frame size, then increases frame size by one until
+ // stop_size has been reached.
+ class FrameFragmentationObserver : public test::RtpRtcpObserver {
public:
- PacketSizeObserver(size_t max_length) : RtpRtcpObserver(30 * 1000),
- max_length_(max_length), accumulated_size_(0) {}
+ FrameFragmentationObserver(size_t max_length,
+ uint32_t start_size,
+ uint32_t stop_size,
+ test::ConfigurableFrameSizeEncoder* encoder)
+ : RtpRtcpObserver(30 * 1000),
+ max_length_(max_length),
+ accumulated_size_(0),
+ accumulated_payload_(0),
+ stop_size_(stop_size),
+ current_size_(start_size),
+ encoder_(encoder) {}
virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
RTPHeader header;
@@ -542,15 +555,25 @@
EXPECT_LE(length, max_length_);
accumulated_size_ += length;
+ // Payload size = packet size - minus RTP header, padding and one byte
+ // generic header.
+ accumulated_payload_ +=
+ length - (header.headerLength + header.paddingLength + 1);
- // Marker bit set indicates last fragment of a packet
+ // Marker bit set indicates last packet of a frame.
if (header.markerBit) {
- if (accumulated_size_ + length > max_length_) {
- // The packet was fragmented, total size was larger than max size,
- // but size of individual fragments were within size limit => pass!
+ EXPECT_GE(accumulated_size_, current_size_);
+ EXPECT_EQ(accumulated_payload_, current_size_);
+
+ if (current_size_ == stop_size_) {
+ EXPECT_GE(current_size_, max_length_);
observation_complete_->Set();
+ } else {
+ // Last packet of frame; reset and increase frame size.
+ accumulated_size_ = 0;
+ accumulated_payload_ = 0;
+ encoder_->SetFrameSize(++current_size_);
}
- accumulated_size_ = 0; // Last fragment, reset packet size
}
return SEND_PACKET;
@@ -559,15 +582,28 @@
private:
size_t max_length_;
size_t accumulated_size_;
+ size_t accumulated_payload_;
+
+ uint32_t stop_size_;
+ uint32_t current_size_;
+ test::ConfigurableFrameSizeEncoder* encoder_;
};
+ // Use a fake encoder to output a frame of every size in the range [90, 290],
+ // for each size making sure that the exact number of payload bytes received
+ // is correct and that packets are fragmented to respect max packet size.
static const uint32_t kMaxPacketSize = 128;
+ static const uint32_t start = 90;
+ static const uint32_t stop = 290;
- PacketSizeObserver observer(kMaxPacketSize);
+ test::ConfigurableFrameSizeEncoder encoder(stop);
+ encoder.SetFrameSize(start);
+ FrameFragmentationObserver observer(kMaxPacketSize, start, stop, &encoder);
Call::Config call_config(observer.SendTransport());
scoped_ptr<Call> call(Call::Create(call_config));
VideoSendStream::Config send_config = GetSendTestConfig(call.get(), 1);
+ send_config.encoder = &encoder;
send_config.rtp.max_packet_size = kMaxPacketSize;
RunSendTest(call.get(), send_config, &observer);