From 8b8819262f4ec2333656aa6eb0b76e7a893b683a Mon Sep 17 00:00:00 2001 From: "sprang@webrtc.org" Date: Tue, 10 Dec 2013 10:05:17 +0000 Subject: [PATCH] Improve VideoSendStreamTest::MaxPacketSize This CL was submitted as issue https://webrtc-codereview.appspot.com/4849004/, but was reverted because of flakiness. This new issue will correct that. Patch Set 1 contains the code that was submitted in 4849004. BUG=2428 R=pbos@webrtc.org, phoglund@webrtc.org, stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/5399004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5251 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../test/configurable_frame_size_encoder.cc | 93 +++++++++++++++++++ webrtc/test/configurable_frame_size_encoder.h | 61 ++++++++++++ webrtc/test/webrtc_test_common.gyp | 2 + webrtc/video/video_send_stream_tests.cc | 77 ++++++++++++--- 4 files changed, 221 insertions(+), 12 deletions(-) create mode 100644 webrtc/test/configurable_frame_size_encoder.cc create mode 100644 webrtc/test/configurable_frame_size_encoder.h 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..d45a9c3ef 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,47 +529,99 @@ 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, from start_size to stop_size. + class FrameFragmentationObserver : public test::RtpRtcpObserver, + public EncodedFrameObserver { public: - PacketSizeObserver(size_t max_length) : RtpRtcpObserver(30 * 1000), - max_length_(max_length), accumulated_size_(0) {} + FrameFragmentationObserver(size_t max_packet_size, + uint32_t start_size, + uint32_t stop_size, + test::ConfigurableFrameSizeEncoder* encoder) + : RtpRtcpObserver(30 * 1000), + max_packet_size_(max_packet_size), + accumulated_size_(0), + accumulated_payload_(0), + stop_size_(stop_size), + current_size_rtp_(start_size), + current_size_frame_(start_size), + encoder_(encoder) { + // Fragmentation required, this test doesn't make sense without it. + assert(stop_size > max_packet_size); + } virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE { RTPHeader header; EXPECT_TRUE( parser_->Parse(packet, static_cast(length), &header)); - EXPECT_LE(length, max_length_); + EXPECT_LE(length, max_packet_size_); 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_rtp_); + EXPECT_EQ(accumulated_payload_, current_size_rtp_); + + // Last packet of frame; reset counters. + accumulated_size_ = 0; + accumulated_payload_ = 0; + if (current_size_rtp_ == stop_size_) { + // Done! (Don't increase size again, might arrive more @ stop_size). observation_complete_->Set(); + } else { + // Increase next expected frame size. + ++current_size_rtp_; } - accumulated_size_ = 0; // Last fragment, reset packet size } return SEND_PACKET; } + virtual void EncodedFrameCallback(const EncodedFrame& encoded_frame) { + // Increase frame size for next encoded frame, in the context of the + // encoder thread. + if (current_size_frame_ < stop_size_) { + ++current_size_frame_; + } + encoder_->SetFrameSize(current_size_frame_); + } + private: - size_t max_length_; + size_t max_packet_size_; size_t accumulated_size_; + size_t accumulated_payload_; + + uint32_t stop_size_; + uint32_t current_size_rtp_; + uint32_t current_size_frame_; + 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; + send_config.post_encode_callback = &observer; RunSendTest(call.get(), send_config, &observer); }