diff --git a/webrtc/test/configurable_frame_size_encoder.cc b/webrtc/test/configurable_frame_size_encoder.cc new file mode 100644 index 000000000..0046f5613 --- /dev/null +++ b/webrtc/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 + +#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* 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/webrtc/test/configurable_frame_size_encoder.h b/webrtc/test/configurable_frame_size_encoder.h new file mode 100644 index 000000000..f29038fac --- /dev/null +++ b/webrtc/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 + +#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* 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 buffer_; +}; + +} // namespace test +} // namespace webrtc + +#endif // WEBRTC_TEST_CONFIGURABLE_FRAME_SIZE_ENCODER_H_ diff --git a/webrtc/test/webrtc_test_common.gyp b/webrtc/test/webrtc_test_common.gyp index ebb2155b8..c7f6df5f5 100644 --- a/webrtc/test/webrtc_test_common.gyp +++ b/webrtc/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/webrtc/video/video_send_stream_tests.cc b/webrtc/video/video_send_stream_tests.cc index 71cb96e5f..182894ee2 100644 --- a/webrtc/video/video_send_stream_tests.cc +++ b/webrtc/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 @@ TEST_F(VideoSendStreamTest, RetransmitsNackOverRtxWithPacing) { 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 @@ TEST_F(VideoSendStreamTest, MaxPacketSize) { 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 @@ TEST_F(VideoSendStreamTest, MaxPacketSize) { 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::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);