| Index: webrtc/video/end_to_end_tests.cc
|
| diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc
|
| index 33fc75e20d7bb72b8c6f61fe24162dddb37736f3..02f5f7a4d93768a23c4285ec106cf6e7f96834d3 100644
|
| --- a/webrtc/video/end_to_end_tests.cc
|
| +++ b/webrtc/video/end_to_end_tests.cc
|
| @@ -1133,120 +1133,304 @@ TEST_F(EndToEndTest, UsesRtcpReducedSizeMode) {
|
|
|
| // Test sets up a Call multiple senders with different resolutions and SSRCs.
|
| // Another is set up to receive all three of these with different renderers.
|
| +class MultiStreamTest {
|
| + public:
|
| + static const size_t kNumStreams = 3;
|
| + struct CodecSettings {
|
| + uint32_t ssrc;
|
| + int width;
|
| + int height;
|
| + } codec_settings[kNumStreams];
|
| +
|
| + MultiStreamTest() {
|
| + // TODO(sprang): Cleanup when msvc supports explicit initializers for array.
|
| + codec_settings[0] = {1, 640, 480};
|
| + codec_settings[1] = {2, 320, 240};
|
| + codec_settings[2] = {3, 240, 160};
|
| + }
|
| +
|
| + virtual ~MultiStreamTest() {}
|
| +
|
| + void RunTest() {
|
| + rtc::scoped_ptr<test::DirectTransport> sender_transport(
|
| + CreateSendTransport());
|
| + rtc::scoped_ptr<test::DirectTransport> receiver_transport(
|
| + CreateReceiveTransport());
|
| +
|
| + rtc::scoped_ptr<Call> sender_call(
|
| + Call::Create(Call::Config(sender_transport.get())));
|
| + rtc::scoped_ptr<Call> receiver_call(
|
| + Call::Create(Call::Config(receiver_transport.get())));
|
| + sender_transport->SetReceiver(receiver_call->Receiver());
|
| + receiver_transport->SetReceiver(sender_call->Receiver());
|
| +
|
| + rtc::scoped_ptr<VideoEncoder> encoders[kNumStreams];
|
| + for (size_t i = 0; i < kNumStreams; ++i)
|
| + encoders[i].reset(VideoEncoder::Create(VideoEncoder::kVp8));
|
| +
|
| + VideoSendStream* send_streams[kNumStreams];
|
| + VideoReceiveStream* receive_streams[kNumStreams];
|
| +
|
| + test::FrameGeneratorCapturer* frame_generators[kNumStreams];
|
| + ScopedVector<VideoDecoder> allocated_decoders;
|
| + for (size_t i = 0; i < kNumStreams; ++i) {
|
| + uint32_t ssrc = codec_settings[i].ssrc;
|
| + int width = codec_settings[i].width;
|
| + int height = codec_settings[i].height;
|
| +
|
| + VideoSendStream::Config send_config;
|
| + send_config.rtp.ssrcs.push_back(ssrc);
|
| + send_config.encoder_settings.encoder = encoders[i].get();
|
| + send_config.encoder_settings.payload_name = "VP8";
|
| + send_config.encoder_settings.payload_type = 124;
|
| + VideoEncoderConfig encoder_config;
|
| + encoder_config.streams = test::CreateVideoStreams(1);
|
| + VideoStream* stream = &encoder_config.streams[0];
|
| + stream->width = width;
|
| + stream->height = height;
|
| + stream->max_framerate = 5;
|
| + stream->min_bitrate_bps = stream->target_bitrate_bps =
|
| + stream->max_bitrate_bps = 100000;
|
| +
|
| + UpdateSendConfig(i, &send_config, &encoder_config, &frame_generators[i]);
|
| +
|
| + send_streams[i] =
|
| + sender_call->CreateVideoSendStream(send_config, encoder_config);
|
| + send_streams[i]->Start();
|
| +
|
| + VideoReceiveStream::Config receive_config;
|
| + receive_config.rtp.remote_ssrc = ssrc;
|
| + receive_config.rtp.local_ssrc = test::CallTest::kReceiverLocalSsrc;
|
| + VideoReceiveStream::Decoder decoder =
|
| + test::CreateMatchingDecoder(send_config.encoder_settings);
|
| + allocated_decoders.push_back(decoder.decoder);
|
| + receive_config.decoders.push_back(decoder);
|
| +
|
| + UpdateReceiveConfig(i, &receive_config);
|
| +
|
| + receive_streams[i] =
|
| + receiver_call->CreateVideoReceiveStream(receive_config);
|
| + receive_streams[i]->Start();
|
| +
|
| + frame_generators[i] = test::FrameGeneratorCapturer::Create(
|
| + send_streams[i]->Input(), width, height, 30,
|
| + Clock::GetRealTimeClock());
|
| + frame_generators[i]->Start();
|
| + }
|
| +
|
| + Wait();
|
| +
|
| + for (size_t i = 0; i < kNumStreams; ++i) {
|
| + frame_generators[i]->Stop();
|
| + sender_call->DestroyVideoSendStream(send_streams[i]);
|
| + receiver_call->DestroyVideoReceiveStream(receive_streams[i]);
|
| + delete frame_generators[i];
|
| + }
|
| +
|
| + sender_transport->StopSending();
|
| + receiver_transport->StopSending();
|
| + }
|
| +
|
| + protected:
|
| + virtual void Wait() = 0;
|
| + // Note: frame_generator is a point-to-pointer, since the actual instance
|
| + // hasn't been created at the time of this call. Only when packets/frames
|
| + // start flowing should this be dereferenced.
|
| + virtual void UpdateSendConfig(
|
| + size_t stream_index,
|
| + VideoSendStream::Config* send_config,
|
| + VideoEncoderConfig* encoder_config,
|
| + test::FrameGeneratorCapturer** frame_generator) {}
|
| + virtual void UpdateReceiveConfig(size_t stream_index,
|
| + VideoReceiveStream::Config* receive_config) {
|
| + }
|
| + virtual test::DirectTransport* CreateSendTransport() {
|
| + return new test::DirectTransport();
|
| + }
|
| + virtual test::DirectTransport* CreateReceiveTransport() {
|
| + return new test::DirectTransport();
|
| + }
|
| +};
|
| +
|
| // Each renderer verifies that it receives the expected resolution, and as soon
|
| // as every renderer has received a frame, the test finishes.
|
| TEST_F(EndToEndTest, SendsAndReceivesMultipleStreams) {
|
| - static const size_t kNumStreams = 3;
|
| -
|
| class VideoOutputObserver : public VideoRenderer {
|
| public:
|
| - VideoOutputObserver(test::FrameGeneratorCapturer** capturer,
|
| - int width,
|
| - int height)
|
| - : capturer_(capturer),
|
| - width_(width),
|
| - height_(height),
|
| + VideoOutputObserver(const MultiStreamTest::CodecSettings& settings,
|
| + uint32_t ssrc,
|
| + test::FrameGeneratorCapturer** frame_generator)
|
| + : settings_(settings),
|
| + ssrc_(ssrc),
|
| + frame_generator_(frame_generator),
|
| done_(EventWrapper::Create()) {}
|
|
|
| void RenderFrame(const VideoFrame& video_frame,
|
| int time_to_render_ms) override {
|
| - EXPECT_EQ(width_, video_frame.width());
|
| - EXPECT_EQ(height_, video_frame.height());
|
| - (*capturer_)->Stop();
|
| + EXPECT_EQ(settings_.width, video_frame.width());
|
| + EXPECT_EQ(settings_.height, video_frame.height());
|
| + (*frame_generator_)->Stop();
|
| done_->Set();
|
| }
|
|
|
| + uint32_t Ssrc() { return ssrc_; }
|
| +
|
| bool IsTextureSupported() const override { return false; }
|
|
|
| EventTypeWrapper Wait() { return done_->Wait(kDefaultTimeoutMs); }
|
|
|
| private:
|
| - test::FrameGeneratorCapturer** capturer_;
|
| - int width_;
|
| - int height_;
|
| + const MultiStreamTest::CodecSettings& settings_;
|
| + const uint32_t ssrc_;
|
| + test::FrameGeneratorCapturer** const frame_generator_;
|
| rtc::scoped_ptr<EventWrapper> done_;
|
| };
|
|
|
| - struct {
|
| - uint32_t ssrc;
|
| - int width;
|
| - int height;
|
| - } codec_settings[kNumStreams] = {{1, 640, 480}, {2, 320, 240}, {3, 240, 160}};
|
| + class Tester : public MultiStreamTest {
|
| + public:
|
| + Tester() {}
|
| + virtual ~Tester() {}
|
| +
|
| + protected:
|
| + void Wait() override {
|
| + for (const auto& observer : observers_) {
|
| + EXPECT_EQ(EventTypeWrapper::kEventSignaled, observer->Wait())
|
| + << "Time out waiting for from on ssrc " << observer->Ssrc();
|
| + }
|
| + }
|
|
|
| - test::DirectTransport sender_transport, receiver_transport;
|
| - rtc::scoped_ptr<Call> sender_call(
|
| - Call::Create(Call::Config(&sender_transport)));
|
| - rtc::scoped_ptr<Call> receiver_call(
|
| - Call::Create(Call::Config(&receiver_transport)));
|
| - sender_transport.SetReceiver(receiver_call->Receiver());
|
| - receiver_transport.SetReceiver(sender_call->Receiver());
|
| -
|
| - VideoSendStream* send_streams[kNumStreams];
|
| - VideoReceiveStream* receive_streams[kNumStreams];
|
| -
|
| - VideoOutputObserver* observers[kNumStreams];
|
| - test::FrameGeneratorCapturer* frame_generators[kNumStreams];
|
| -
|
| - rtc::scoped_ptr<VideoEncoder> encoders[kNumStreams];
|
| - for (size_t i = 0; i < kNumStreams; ++i)
|
| - encoders[i].reset(VideoEncoder::Create(VideoEncoder::kVp8));
|
| -
|
| - ScopedVector<VideoDecoder> allocated_decoders;
|
| - for (size_t i = 0; i < kNumStreams; ++i) {
|
| - uint32_t ssrc = codec_settings[i].ssrc;
|
| - int width = codec_settings[i].width;
|
| - int height = codec_settings[i].height;
|
| - observers[i] = new VideoOutputObserver(&frame_generators[i], width, height);
|
| + void UpdateSendConfig(
|
| + size_t stream_index,
|
| + VideoSendStream::Config* send_config,
|
| + VideoEncoderConfig* encoder_config,
|
| + test::FrameGeneratorCapturer** frame_generator) override {
|
| + observers_[stream_index].reset(new VideoOutputObserver(
|
| + codec_settings[stream_index], send_config->rtp.ssrcs.front(),
|
| + frame_generator));
|
| + }
|
|
|
| - VideoSendStream::Config send_config;
|
| - send_config.rtp.ssrcs.push_back(ssrc);
|
| - send_config.encoder_settings.encoder = encoders[i].get();
|
| - send_config.encoder_settings.payload_name = "VP8";
|
| - send_config.encoder_settings.payload_type = 124;
|
| - VideoEncoderConfig encoder_config;
|
| - encoder_config.streams = test::CreateVideoStreams(1);
|
| - VideoStream* stream = &encoder_config.streams[0];
|
| - stream->width = width;
|
| - stream->height = height;
|
| - stream->max_framerate = 5;
|
| - stream->min_bitrate_bps = stream->target_bitrate_bps =
|
| - stream->max_bitrate_bps = 100000;
|
| - send_streams[i] =
|
| - sender_call->CreateVideoSendStream(send_config, encoder_config);
|
| - send_streams[i]->Start();
|
| + void UpdateReceiveConfig(
|
| + size_t stream_index,
|
| + VideoReceiveStream::Config* receive_config) override {
|
| + receive_config->renderer = observers_[stream_index].get();
|
| + }
|
|
|
| - VideoReceiveStream::Config receive_config;
|
| - receive_config.renderer = observers[i];
|
| - receive_config.rtp.remote_ssrc = ssrc;
|
| - receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
|
| - VideoReceiveStream::Decoder decoder =
|
| - test::CreateMatchingDecoder(send_config.encoder_settings);
|
| - allocated_decoders.push_back(decoder.decoder);
|
| - receive_config.decoders.push_back(decoder);
|
| - receive_streams[i] =
|
| - receiver_call->CreateVideoReceiveStream(receive_config);
|
| - receive_streams[i]->Start();
|
| + private:
|
| + rtc::scoped_ptr<VideoOutputObserver> observers_[kNumStreams];
|
| + } tester;
|
|
|
| - frame_generators[i] = test::FrameGeneratorCapturer::Create(
|
| - send_streams[i]->Input(), width, height, 30, Clock::GetRealTimeClock());
|
| - frame_generators[i]->Start();
|
| - }
|
| + tester.RunTest();
|
| +}
|
|
|
| - for (size_t i = 0; i < kNumStreams; ++i) {
|
| - EXPECT_EQ(kEventSignaled, observers[i]->Wait())
|
| - << "Timed out while waiting for observer " << i << " to render.";
|
| - }
|
| +TEST_F(EndToEndTest, AssignsTransportSequenceNumbers) {
|
| + // TODO(sprang): Extend this to verify received values once send-side BWE
|
| + // is in place.
|
|
|
| - for (size_t i = 0; i < kNumStreams; ++i) {
|
| - frame_generators[i]->Stop();
|
| - sender_call->DestroyVideoSendStream(send_streams[i]);
|
| - receiver_call->DestroyVideoReceiveStream(receive_streams[i]);
|
| - delete frame_generators[i];
|
| - delete observers[i];
|
| - }
|
| + static const int kExtensionId = 5;
|
|
|
| - sender_transport.StopSending();
|
| - receiver_transport.StopSending();
|
| + class RtpExtensionHeaderObserver : public test::DirectTransport {
|
| + public:
|
| + RtpExtensionHeaderObserver()
|
| + : done_(EventWrapper::Create()),
|
| + parser_(RtpHeaderParser::Create()),
|
| + last_seq_(0),
|
| + padding_observed_(false),
|
| + rtx_padding_observed_(false) {
|
| + parser_->RegisterRtpHeaderExtension(kRtpExtensionTransportSequenceNumber,
|
| + kExtensionId);
|
| + }
|
| + virtual ~RtpExtensionHeaderObserver() {}
|
| +
|
| + bool SendRtp(const uint8_t* data, size_t length) override {
|
| + RTPHeader header;
|
| + EXPECT_TRUE(parser_->Parse(data, length, &header));
|
| + if (header.extension.hasTransportSequenceNumber) {
|
| + if (!streams_observed_.empty()) {
|
| + EXPECT_EQ(static_cast<uint16_t>(last_seq_ + 1),
|
| + header.extension.transportSequenceNumber);
|
| + }
|
| + last_seq_ = header.extension.transportSequenceNumber;
|
| +
|
| + size_t payload_length =
|
| + length - (header.headerLength + header.paddingLength);
|
| + if (payload_length == 0) {
|
| + padding_observed_ = true;
|
| + } else if (header.payloadType == kSendRtxPayloadType) {
|
| + rtx_padding_observed_ = true;
|
| + } else {
|
| + streams_observed_.insert(header.ssrc);
|
| + }
|
| +
|
| + if (streams_observed_.size() == MultiStreamTest::kNumStreams &&
|
| + padding_observed_ && rtx_padding_observed_) {
|
| + done_->Set();
|
| + }
|
| + }
|
| + return test::DirectTransport::SendRtp(data, length);
|
| + }
|
| +
|
| + EventTypeWrapper Wait() { return done_->Wait(kDefaultTimeoutMs); }
|
| +
|
| + rtc::scoped_ptr<EventWrapper> done_;
|
| + rtc::scoped_ptr<RtpHeaderParser> parser_;
|
| + uint16_t last_seq_;
|
| + std::set<uint32_t> streams_observed_;
|
| + bool padding_observed_;
|
| + bool rtx_padding_observed_;
|
| + };
|
| +
|
| + class TransportSequenceNumberTester : public MultiStreamTest {
|
| + public:
|
| + TransportSequenceNumberTester() : observer_(nullptr) {}
|
| + virtual ~TransportSequenceNumberTester() {}
|
| +
|
| + protected:
|
| + void Wait() override {
|
| + DCHECK(observer_ != nullptr);
|
| + EXPECT_EQ(EventTypeWrapper::kEventSignaled, observer_->Wait());
|
| + }
|
| +
|
| + void UpdateSendConfig(
|
| + size_t stream_index,
|
| + VideoSendStream::Config* send_config,
|
| + VideoEncoderConfig* encoder_config,
|
| + test::FrameGeneratorCapturer** frame_generator) override {
|
| + send_config->rtp.extensions.clear();
|
| + send_config->rtp.extensions.push_back(
|
| + RtpExtension(RtpExtension::kTransportSequenceNumber, kExtensionId));
|
| +
|
| + // Force some padding to be sent.
|
| + const int kPaddingBitrateBps = 50000;
|
| + int total_target_bitrate = 0;
|
| + for (const VideoStream& stream : encoder_config->streams)
|
| + total_target_bitrate += stream.target_bitrate_bps;
|
| + encoder_config->min_transmit_bitrate_bps =
|
| + total_target_bitrate + kPaddingBitrateBps;
|
| +
|
| + // Configure RTX for redundant payload padding.
|
| + send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
| + send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
|
| + send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
|
| + }
|
| +
|
| + void UpdateReceiveConfig(
|
| + size_t stream_index,
|
| + VideoReceiveStream::Config* receive_config) override {
|
| + receive_config->rtp.extensions.clear();
|
| + receive_config->rtp.extensions.push_back(
|
| + RtpExtension(RtpExtension::kTransportSequenceNumber, kExtensionId));
|
| + }
|
| +
|
| + virtual test::DirectTransport* CreateSendTransport() {
|
| + observer_ = new RtpExtensionHeaderObserver();
|
| + return observer_;
|
| + }
|
| +
|
| + private:
|
| + RtpExtensionHeaderObserver* observer_;
|
| + } tester;
|
| +
|
| + tester.RunTest();
|
| }
|
|
|
| TEST_F(EndToEndTest, ObserversEncodedFrames) {
|
| @@ -1803,7 +1987,8 @@ void EndToEndTest::TestSendsSetSsrcs(size_t num_ssrcs,
|
| num_ssrcs_(num_ssrcs),
|
| send_single_ssrc_first_(send_single_ssrc_first),
|
| ssrcs_to_observe_(num_ssrcs),
|
| - expect_single_ssrc_(send_single_ssrc_first) {
|
| + expect_single_ssrc_(send_single_ssrc_first),
|
| + send_stream_(nullptr) {
|
| for (size_t i = 0; i < num_ssrcs; ++i)
|
| valid_ssrcs_[ssrcs[i]] = true;
|
| }
|
| @@ -1895,7 +2080,9 @@ TEST_F(EndToEndTest, ReportsSetEncoderRates) {
|
| public:
|
| EncoderRateStatsTest()
|
| : EndToEndTest(kDefaultTimeoutMs),
|
| - FakeEncoder(Clock::GetRealTimeClock()) {}
|
| + FakeEncoder(Clock::GetRealTimeClock()),
|
| + send_stream_(nullptr),
|
| + bitrate_kbps_(0) {}
|
|
|
| void OnStreamsCreated(
|
| VideoSendStream* send_stream,
|
| @@ -2531,6 +2718,8 @@ TEST_F(EndToEndTest, RespectsNetworkState) {
|
| FakeEncoder(Clock::GetRealTimeClock()),
|
| encoded_frames_(EventWrapper::Create()),
|
| packet_event_(EventWrapper::Create()),
|
| + sender_call_(nullptr),
|
| + receiver_call_(nullptr),
|
| sender_state_(kNetworkUp),
|
| sender_rtp_(0),
|
| sender_rtcp_(0),
|
|
|