diff --git a/webrtc/call.h b/webrtc/call.h index 1b95c2988..5b5568210 100644 --- a/webrtc/call.h +++ b/webrtc/call.h @@ -78,8 +78,6 @@ class Call { static Call* Create(const Call::Config& config, const webrtc::Config& webrtc_config); - virtual std::vector GetVideoCodecs() = 0; - virtual VideoSendStream::Config GetDefaultSendConfig() = 0; virtual VideoSendStream* CreateVideoSendStream( diff --git a/webrtc/common_types.h b/webrtc/common_types.h index 9478a2dd6..f7e48402a 100644 --- a/webrtc/common_types.h +++ b/webrtc/common_types.h @@ -11,6 +11,10 @@ #ifndef WEBRTC_COMMON_TYPES_H_ #define WEBRTC_COMMON_TYPES_H_ +#include + +#include + #include "webrtc/typedefs.h" #if defined(_MSC_VER) @@ -657,7 +661,30 @@ struct PacketTime { // If unknown, this value will be set to zero. }; +struct VideoStream { + VideoStream() + : width(0), + height(0), + max_framerate(-1), + min_bitrate_bps(-1), + target_bitrate_bps(-1), + max_bitrate_bps(-1), + max_qp(-1) {} + + size_t width; + size_t height; + int max_framerate; + + int min_bitrate_bps; + int target_bitrate_bps; + int max_bitrate_bps; + + int max_qp; + + // Bitrate thresholds for enabling additional temporal layers. + std::vector temporal_layers; +}; + } // namespace webrtc #endif // WEBRTC_COMMON_TYPES_H_ - diff --git a/webrtc/test/encoder_settings.cc b/webrtc/test/encoder_settings.cc new file mode 100644 index 000000000..d02c29f99 --- /dev/null +++ b/webrtc/test/encoder_settings.cc @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2014 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/encoder_settings.h" + +#include +#include + +#include "webrtc/video_engine/vie_defines.h" + +namespace webrtc { +namespace test { +VideoSendStream::Config::EncoderSettings CreateEncoderSettings( + VideoEncoder* encoder, + const char* payload_name, + int payload_type, + size_t num_streams) { + assert(num_streams > 0); + + // Add more streams to the settings above with reasonable values if required. + static const size_t kNumSettings = 3; + assert(num_streams <= kNumSettings); + + VideoStream stream_settings[kNumSettings]; + + stream_settings[0].width = 320; + stream_settings[0].height = 180; + stream_settings[0].max_framerate = 30; + stream_settings[0].min_bitrate_bps = 50000; + stream_settings[0].target_bitrate_bps = stream_settings[0].max_bitrate_bps = + 150000; + stream_settings[0].max_qp = 56; + + stream_settings[1].width = 640; + stream_settings[1].height = 360; + stream_settings[1].max_framerate = 30; + stream_settings[1].min_bitrate_bps = 200000; + stream_settings[1].target_bitrate_bps = stream_settings[1].max_bitrate_bps = + 450000; + stream_settings[1].max_qp = 56; + + stream_settings[2].width = 1280; + stream_settings[2].height = 720; + stream_settings[2].max_framerate = 30; + stream_settings[2].min_bitrate_bps = 700000; + stream_settings[2].target_bitrate_bps = stream_settings[2].max_bitrate_bps = + 1500000; + stream_settings[2].max_qp = 56; + + VideoSendStream::Config::EncoderSettings settings; + + for (size_t i = 0; i < num_streams; ++i) + settings.streams.push_back(stream_settings[i]); + + settings.encoder = encoder; + settings.payload_name = payload_name; + settings.payload_type = payload_type; + return settings; +} + +VideoCodec CreateDecoderVideoCodec( + const VideoSendStream::Config::EncoderSettings& settings) { + assert(settings.streams.size() > 0); + VideoCodec codec; + memset(&codec, 0, sizeof(codec)); + + codec.plType = settings.payload_type; + strcpy(codec.plName, settings.payload_name.c_str()); + codec.codecType = + (settings.payload_name == "VP8" ? kVideoCodecVP8 : kVideoCodecGeneric); + + if (codec.codecType == kVideoCodecVP8) { + codec.codecSpecific.VP8.resilience = kResilientStream; + codec.codecSpecific.VP8.numberOfTemporalLayers = 1; + codec.codecSpecific.VP8.denoisingOn = true; + codec.codecSpecific.VP8.errorConcealmentOn = false; + codec.codecSpecific.VP8.automaticResizeOn = false; + codec.codecSpecific.VP8.frameDroppingOn = true; + codec.codecSpecific.VP8.keyFrameInterval = 3000; + } + + codec.minBitrate = settings.streams[0].min_bitrate_bps / 1000; + for (size_t i = 0; i < settings.streams.size(); ++i) { + const VideoStream& stream = settings.streams[i]; + if (stream.width > codec.width) + codec.width = static_cast(stream.width); + if (stream.height > codec.height) + codec.height = static_cast(stream.height); + if (static_cast(stream.min_bitrate_bps / 1000) < + codec.minBitrate) + codec.minBitrate = + static_cast(stream.min_bitrate_bps / 1000); + codec.maxBitrate += stream.max_bitrate_bps / 1000; + if (static_cast(stream.max_qp) > codec.qpMax) + codec.qpMax = static_cast(stream.max_qp); + } + + if (codec.minBitrate < kViEMinCodecBitrate) + codec.minBitrate = kViEMinCodecBitrate; + if (codec.maxBitrate < kViEMinCodecBitrate) + codec.maxBitrate = kViEMinCodecBitrate; + + codec.startBitrate = 300; + + if (codec.startBitrate < codec.minBitrate) + codec.startBitrate = codec.minBitrate; + if (codec.startBitrate > codec.maxBitrate) + codec.startBitrate = codec.maxBitrate; + + return codec; +} + +} // namespace test +} // namespace webrtc diff --git a/webrtc/test/encoder_settings.h b/webrtc/test/encoder_settings.h new file mode 100644 index 000000000..1d8e355ab --- /dev/null +++ b/webrtc/test/encoder_settings.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014 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_ENCODER_SETTINGS_H_ +#define WEBRTC_TEST_ENCODER_SETTINGS_H_ + +#include "webrtc/video_send_stream.h" + +namespace webrtc { +namespace test { +VideoSendStream::Config::EncoderSettings CreateEncoderSettings( + VideoEncoder* encoder, + const char* payload_name, + int payload_type, + size_t num_streams); + +VideoCodec CreateDecoderVideoCodec( + const VideoSendStream::Config::EncoderSettings& settings); +} // namespace test +} // namespace webrtc + +#endif // WEBRTC_TEST_ENCODER_SETTINGS_H_ diff --git a/webrtc/test/fake_encoder.cc b/webrtc/test/fake_encoder.cc index fc8712e56..4ff81a18f 100644 --- a/webrtc/test/fake_encoder.cc +++ b/webrtc/test/fake_encoder.cc @@ -29,40 +29,6 @@ FakeEncoder::FakeEncoder(Clock* clock) FakeEncoder::~FakeEncoder() {} -void FakeEncoder::SetCodecSettings(VideoCodec* codec, - size_t num_streams) { - assert(num_streams > 0); - assert(num_streams <= kMaxSimulcastStreams); - - static const SimulcastStream stream_settings[] = { - {320, 180, 0, 150, 150, 50, codec->qpMax}, - {640, 360, 0, 500, 500, 150, codec->qpMax}, - {1280, 720, 0, 1200, 1200, 600, codec->qpMax}}; - // Add more streams to the settings above with reasonable values if required. - assert(num_streams <= sizeof(stream_settings) / sizeof(stream_settings[0])); - - codec->numberOfSimulcastStreams = static_cast(num_streams); - - unsigned int sum_of_max_bitrates = 0; - for (size_t i = 0; i < num_streams; ++i) { - codec->simulcastStream[i] = stream_settings[i]; - sum_of_max_bitrates += stream_settings[i].maxBitrate; - } - - size_t last_stream = num_streams - 1; - codec->width = stream_settings[last_stream].width; - codec->height = stream_settings[last_stream].height; - // Start with the average for the middle stream's max/min settings. - codec->startBitrate = (stream_settings[last_stream / 2].maxBitrate + - stream_settings[last_stream / 2].minBitrate) / - 2; - codec->minBitrate = stream_settings[0].minBitrate; - codec->maxBitrate = sum_of_max_bitrates; - - codec->codecType = kVideoCodecGeneric; - strcpy(codec->plName, "FAKE"); -} - void FakeEncoder::SetMaxBitrate(int max_kbps) { assert(max_kbps >= -1); // max_kbps == -1 disables it. max_target_bitrate_kbps_ = max_kbps; @@ -99,6 +65,7 @@ int32_t FakeEncoder::Encode( bits_available = max_bits; last_encode_time_ms_ = time_now_ms; + assert(config_.numberOfSimulcastStreams > 0); for (int i = 0; i < config_.numberOfSimulcastStreams; ++i) { CodecSpecificInfo specifics; memset(&specifics, 0, sizeof(specifics)); @@ -124,6 +91,7 @@ int32_t FakeEncoder::Encode( encoded._length = 0; encoded._frameType = kSkipFrame; } + assert(callback_ != NULL); if (callback_->Encoded(encoded, &specifics, NULL) != 0) return -1; diff --git a/webrtc/test/fake_encoder.h b/webrtc/test/fake_encoder.h index e2d8d6b4a..c0709c129 100644 --- a/webrtc/test/fake_encoder.h +++ b/webrtc/test/fake_encoder.h @@ -24,7 +24,6 @@ class FakeEncoder : public VideoEncoder { explicit FakeEncoder(Clock* clock); virtual ~FakeEncoder(); - static void SetCodecSettings(VideoCodec* codec, size_t num_streams); // Sets max bitrate. Not thread-safe, call before registering the encoder. void SetMaxBitrate(int max_kbps); diff --git a/webrtc/test/webrtc_test_common.gyp b/webrtc/test/webrtc_test_common.gyp index 6920ab843..bec5803fc 100644 --- a/webrtc/test/webrtc_test_common.gyp +++ b/webrtc/test/webrtc_test_common.gyp @@ -18,6 +18,8 @@ 'configurable_frame_size_encoder.h', 'direct_transport.cc', 'direct_transport.h', + 'encoder_settings.cc', + 'encoder_settings.h', 'fake_audio_device.cc', 'fake_audio_device.h', 'fake_decoder.cc', diff --git a/webrtc/video/bitrate_estimator_tests.cc b/webrtc/video/bitrate_estimator_tests.cc index 58b196dbd..ea7c0fa0c 100644 --- a/webrtc/video/bitrate_estimator_tests.cc +++ b/webrtc/video/bitrate_estimator_tests.cc @@ -18,6 +18,7 @@ #include "webrtc/system_wrappers/interface/event_wrapper.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" #include "webrtc/test/direct_transport.h" +#include "webrtc/test/encoder_settings.h" #include "webrtc/test/fake_decoder.h" #include "webrtc/test/fake_encoder.h" #include "webrtc/test/frame_generator_capturer.h" @@ -64,14 +65,15 @@ class BitrateEstimatorTest : public ::testing::Test { send_config_ = sender_call_->GetDefaultSendConfig(); send_config_.rtp.ssrcs.push_back(kSendSsrc); - // send_config_.encoder will be set by every stream separately. - send_config_.internal_source = false; - test::FakeEncoder::SetCodecSettings(&send_config_.codec, 1); - send_config_.codec.plType = kSendPayloadType; + // Encoders will be set separately per stream. + send_config_.encoder_settings = + test::CreateEncoderSettings(NULL, "FAKE", kSendPayloadType, 1); receive_config_ = receiver_call_->GetDefaultReceiveConfig(); - receive_config_.codecs.clear(); - receive_config_.codecs.push_back(send_config_.codec); + assert(receive_config_.codecs.empty()); + VideoCodec codec = + test::CreateDecoderVideoCodec(send_config_.encoder_settings); + receive_config_.codecs.push_back(codec); // receive_config_.external_decoders will be set by every stream separately. receive_config_.rtp.remote_ssrc = send_config_.rtp.ssrcs[0]; receive_config_.rtp.local_ssrc = kReceiverLocalSsrc; @@ -163,21 +165,22 @@ class BitrateEstimatorTest : public ::testing::Test { fake_encoder_(Clock::GetRealTimeClock()), fake_decoder_() { test_->send_config_.rtp.ssrcs[0]++; - test_->send_config_.encoder = &fake_encoder_; + test_->send_config_.encoder_settings.encoder = &fake_encoder_; send_stream_ = test_->sender_call_->CreateVideoSendStream(test_->send_config_); - frame_generator_capturer_.reset( - test::FrameGeneratorCapturer::Create(send_stream_->Input(), - test_->send_config_.codec.width, - test_->send_config_.codec.height, - 30, - Clock::GetRealTimeClock())); + assert(test_->send_config_.encoder_settings.streams.size() == 1); + frame_generator_capturer_.reset(test::FrameGeneratorCapturer::Create( + send_stream_->Input(), + test_->send_config_.encoder_settings.streams[0].width, + test_->send_config_.encoder_settings.streams[0].height, + 30, + Clock::GetRealTimeClock())); send_stream_->StartSending(); frame_generator_capturer_->Start(); ExternalVideoDecoder decoder; decoder.decoder = &fake_decoder_; - decoder.payload_type = test_->send_config_.codec.plType; + decoder.payload_type = test_->send_config_.encoder_settings.payload_type; test_->receive_config_.rtp.remote_ssrc = test_->send_config_.rtp.ssrcs[0]; test_->receive_config_.rtp.local_ssrc++; test_->receive_config_.external_decoders.push_back(decoder); diff --git a/webrtc/video/call.cc b/webrtc/video/call.cc index 7c4699e44..bcdcbf768 100644 --- a/webrtc/video/call.cc +++ b/webrtc/video/call.cc @@ -65,7 +65,6 @@ class Call : public webrtc::Call, public PacketReceiver { virtual ~Call(); virtual PacketReceiver* Receiver() OVERRIDE; - virtual std::vector GetVideoCodecs() OVERRIDE; virtual VideoSendStream::Config GetDefaultSendConfig() OVERRIDE; @@ -246,28 +245,14 @@ Call::~Call() { PacketReceiver* Call::Receiver() { return this; } -std::vector Call::GetVideoCodecs() { - std::vector codecs; - - VideoCodec codec; - for (size_t i = 0; i < static_cast(codec_->NumberOfCodecs()); ++i) { - if (codec_->GetCodec(static_cast(i), codec) == 0) { - codecs.push_back(codec); - } - } - return codecs; -} - VideoSendStream::Config Call::GetDefaultSendConfig() { VideoSendStream::Config config; - codec_->GetCodec(0, config.codec); return config; } VideoSendStream* Call::CreateVideoSendStream( const VideoSendStream::Config& config) { assert(config.rtp.ssrcs.size() > 0); - assert(config.rtp.ssrcs.size() >= config.codec.numberOfSimulcastStreams); VideoSendStream* send_stream = new VideoSendStream( config_.send_transport, diff --git a/webrtc/video/call_perf_tests.cc b/webrtc/video/call_perf_tests.cc index 31cfab5f9..e2f4775ea 100644 --- a/webrtc/video/call_perf_tests.cc +++ b/webrtc/video/call_perf_tests.cc @@ -24,6 +24,7 @@ #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" #include "webrtc/test/direct_transport.h" +#include "webrtc/test/encoder_settings.h" #include "webrtc/test/fake_audio_device.h" #include "webrtc/test/fake_decoder.h" #include "webrtc/test/fake_encoder.h" @@ -54,11 +55,9 @@ class CallPerfTest : public ::testing::Test { protected: VideoSendStream::Config GetSendTestConfig(Call* call) { VideoSendStream::Config config = call->GetDefaultSendConfig(); - config.encoder = &fake_encoder_; - config.internal_source = false; config.rtp.ssrcs.push_back(kSendSsrc); - test::FakeEncoder::SetCodecSettings(&config.codec, 1); - config.codec.plType = kSendPayloadType; + config.encoder_settings = test::CreateEncoderSettings( + &fake_encoder_, "FAKE", kSendPayloadType, 1); return config; } @@ -312,11 +311,14 @@ TEST_P(ParamCallPerfTest, PlaysOutAudioAndVideoInSync) { VideoReceiveStream::Config receive_config = receiver_call->GetDefaultReceiveConfig(); - receive_config.codecs.clear(); - receive_config.codecs.push_back(send_config.codec); + assert(receive_config.codecs.empty()); + VideoCodec codec = + test::CreateDecoderVideoCodec(send_config.encoder_settings); + receive_config.codecs.push_back(codec); + assert(receive_config.external_decoders.empty()); ExternalVideoDecoder decoder; decoder.decoder = &fake_decoder; - decoder.payload_type = send_config.codec.plType; + decoder.payload_type = send_config.encoder_settings.payload_type; receive_config.external_decoders.push_back(decoder); receive_config.rtp.remote_ssrc = send_config.rtp.ssrcs[0]; receive_config.rtp.local_ssrc = kReceiverLocalSsrc; @@ -328,11 +330,12 @@ TEST_P(ParamCallPerfTest, PlaysOutAudioAndVideoInSync) { VideoReceiveStream* receive_stream = receiver_call->CreateVideoReceiveStream(receive_config); scoped_ptr capturer( - test::FrameGeneratorCapturer::Create(send_stream->Input(), - send_config.codec.width, - send_config.codec.height, - 30, - Clock::GetRealTimeClock())); + test::FrameGeneratorCapturer::Create( + send_stream->Input(), + send_config.encoder_settings.streams[0].width, + send_config.encoder_settings.streams[0].height, + 30, + Clock::GetRealTimeClock())); receive_stream->StartReceiving(); send_stream->StartSending(); capturer->Start(); @@ -480,11 +483,13 @@ void CallPerfTest::TestMinTransmitBitrate(bool pad_to_min_bitrate) { VideoReceiveStream::Config receive_config = receiver_call->GetDefaultReceiveConfig(); receive_config.codecs.clear(); - receive_config.codecs.push_back(send_config.codec); + VideoCodec codec = + test::CreateDecoderVideoCodec(send_config.encoder_settings); + receive_config.codecs.push_back(codec); test::FakeDecoder fake_decoder; ExternalVideoDecoder decoder; decoder.decoder = &fake_decoder; - decoder.payload_type = send_config.codec.plType; + decoder.payload_type = send_config.encoder_settings.payload_type; receive_config.external_decoders.push_back(decoder); receive_config.rtp.remote_ssrc = send_config.rtp.ssrcs[0]; receive_config.rtp.local_ssrc = kReceiverLocalSsrc; @@ -494,11 +499,12 @@ void CallPerfTest::TestMinTransmitBitrate(bool pad_to_min_bitrate) { VideoReceiveStream* receive_stream = receiver_call->CreateVideoReceiveStream(receive_config); scoped_ptr capturer( - test::FrameGeneratorCapturer::Create(send_stream->Input(), - send_config.codec.width, - send_config.codec.height, - 30, - Clock::GetRealTimeClock())); + test::FrameGeneratorCapturer::Create( + send_stream->Input(), + send_config.encoder_settings.streams[0].width, + send_config.encoder_settings.streams[0].height, + 30, + Clock::GetRealTimeClock())); observer.SetSendStream(send_stream); receive_stream->StartReceiving(); send_stream->StartSending(); diff --git a/webrtc/video/call_tests.cc b/webrtc/video/call_tests.cc index 6e922d3df..505c99603 100644 --- a/webrtc/video/call_tests.cc +++ b/webrtc/video/call_tests.cc @@ -19,11 +19,13 @@ #include "webrtc/call.h" #include "webrtc/frame_callback.h" #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h" +#include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h" #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" #include "webrtc/system_wrappers/interface/event_wrapper.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" #include "webrtc/system_wrappers/interface/sleep.h" #include "webrtc/test/direct_transport.h" +#include "webrtc/test/encoder_settings.h" #include "webrtc/test/fake_audio_device.h" #include "webrtc/test/fake_decoder.h" #include "webrtc/test/fake_encoder.h" @@ -69,16 +71,16 @@ class CallTest : public ::testing::Test { receive_config_ = receiver_call_->GetDefaultReceiveConfig(); send_config_.rtp.ssrcs.push_back(kSendSsrc); - send_config_.encoder = &fake_encoder_; - send_config_.internal_source = false; - test::FakeEncoder::SetCodecSettings(&send_config_.codec, 1); - send_config_.codec.plType = kSendPayloadType; + send_config_.encoder_settings = test::CreateEncoderSettings( + &fake_encoder_, "FAKE", kSendPayloadType, 1); - receive_config_.codecs.clear(); - receive_config_.codecs.push_back(send_config_.codec); + assert(receive_config_.codecs.empty()); + VideoCodec codec = + test::CreateDecoderVideoCodec(send_config_.encoder_settings); + receive_config_.codecs.push_back(codec); ExternalVideoDecoder decoder; decoder.decoder = &fake_decoder_; - decoder.payload_type = send_config_.codec.plType; + decoder.payload_type = send_config_.encoder_settings.payload_type; receive_config_.external_decoders.push_back(decoder); receive_config_.rtp.remote_ssrc = send_config_.rtp.ssrcs[0]; receive_config_.rtp.local_ssrc = kReceiverLocalSsrc; @@ -93,12 +95,12 @@ class CallTest : public ::testing::Test { } void CreateFrameGenerator() { - frame_generator_capturer_.reset( - test::FrameGeneratorCapturer::Create(send_stream_->Input(), - send_config_.codec.width, - send_config_.codec.height, - 30, - Clock::GetRealTimeClock())); + frame_generator_capturer_.reset(test::FrameGeneratorCapturer::Create( + send_stream_->Input(), + send_config_.encoder_settings.streams[0].width, + send_config_.encoder_settings.streams[0].height, + 30, + Clock::GetRealTimeClock())); } void StartSending() { @@ -401,7 +403,8 @@ TEST_F(CallTest, TransmitsFirstFrame) { StartSending(); scoped_ptr frame_generator(test::FrameGenerator::Create( - send_config_.codec.width, send_config_.codec.height)); + send_config_.encoder_settings.streams[0].width, + send_config_.encoder_settings.streams[0].height)); send_stream_->Input()->SwapFrame(frame_generator->NextFrame()); EXPECT_EQ(kEventSignaled, renderer.Wait()) @@ -552,7 +555,7 @@ void CallTest::DecodesRetransmittedFrame(bool retransmit_over_rtx) { if (retransmit_over_rtx) { send_config_.rtp.rtx.ssrcs.push_back(kSendRtxSsrc); send_config_.rtp.rtx.payload_type = kSendRtxPayloadType; - int payload_type = send_config_.codec.plType; + int payload_type = send_config_.encoder_settings.payload_type; receive_config_.rtp.rtx[payload_type].ssrc = kSendRtxSsrc; receive_config_.rtp.rtx[payload_type].payload_type = kSendRtxPayloadType; } @@ -643,11 +646,19 @@ TEST_F(CallTest, UsesFrameCallbacks) { receiver_transport.SetReceiver(sender_call_->Receiver()); CreateTestConfigs(); - send_config_.encoder = NULL; - send_config_.codec = sender_call_->GetVideoCodecs()[0]; - send_config_.codec.width = kWidth; - send_config_.codec.height = kHeight; + scoped_ptr encoder(VP8Encoder::Create()); + send_config_.encoder_settings.encoder = encoder.get(); + send_config_.encoder_settings.payload_name = "VP8"; + ASSERT_EQ(1u, send_config_.encoder_settings.streams.size()) + << "Test setup error."; + send_config_.encoder_settings.streams[0].width = kWidth; + send_config_.encoder_settings.streams[0].height = kHeight; send_config_.pre_encode_callback = &pre_encode_callback; + receive_config_.codecs.clear(); + VideoCodec codec = + test::CreateDecoderVideoCodec(send_config_.encoder_settings); + receive_config_.external_decoders.clear(); + receive_config_.codecs.push_back(codec); receive_config_.pre_render_callback = &pre_render_callback; receive_config_.renderer = &renderer; @@ -949,7 +960,7 @@ TEST_F(CallTest, SendsAndReceivesMultipleStreams) { done_->Set(); } - void Wait() { done_->Wait(kDefaultTimeoutMs); } + EventTypeWrapper Wait() { return done_->Wait(kDefaultTimeoutMs); } private: test::FrameGeneratorCapturer** capturer_; @@ -977,35 +988,49 @@ TEST_F(CallTest, SendsAndReceivesMultipleStreams) { VideoOutputObserver* observers[kNumStreams]; test::FrameGeneratorCapturer* frame_generators[kNumStreams]; + scoped_ptr encoders[kNumStreams]; + for (size_t i = 0; i < kNumStreams; ++i) + encoders[i].reset(VP8Encoder::Create()); + 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); + VideoSendStream::Config send_config = sender_call->GetDefaultSendConfig(); + send_config.rtp.ssrcs.push_back(ssrc); + send_config.encoder_settings = + test::CreateEncoderSettings(encoders[i].get(), "VP8", 124, 1); + VideoStream* stream = &send_config.encoder_settings.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); + send_streams[i]->StartSending(); + VideoReceiveStream::Config receive_config = receiver_call->GetDefaultReceiveConfig(); receive_config.renderer = observers[i]; receive_config.rtp.remote_ssrc = ssrc; receive_config.rtp.local_ssrc = kReceiverLocalSsrc; + VideoCodec codec = + test::CreateDecoderVideoCodec(send_config.encoder_settings); + receive_config.codecs.push_back(codec); receive_streams[i] = receiver_call->CreateVideoReceiveStream(receive_config); receive_streams[i]->StartReceiving(); - VideoSendStream::Config send_config = sender_call->GetDefaultSendConfig(); - send_config.rtp.ssrcs.push_back(ssrc); - send_config.codec.width = width; - send_config.codec.height = height; - send_streams[i] = sender_call->CreateVideoSendStream(send_config); - send_streams[i]->StartSending(); - frame_generators[i] = test::FrameGeneratorCapturer::Create( send_streams[i]->Input(), width, height, 30, Clock::GetRealTimeClock()); frame_generators[i]->Start(); } for (size_t i = 0; i < kNumStreams; ++i) { - observers[i]->Wait(); + EXPECT_EQ(kEventSignaled, observers[i]->Wait()) + << "Timed out while waiting for observer " << i << " to render."; } for (size_t i = 0; i < kNumStreams; ++i) { @@ -1074,7 +1099,8 @@ TEST_F(CallTest, ObserversEncodedFrames) { StartSending(); scoped_ptr frame_generator(test::FrameGenerator::Create( - send_config_.codec.width, send_config_.codec.height)); + send_config_.encoder_settings.streams[0].width, + send_config_.encoder_settings.streams[0].height)); send_stream_->Input()->SwapFrame(frame_generator->NextFrame()); EXPECT_EQ(kEventSignaled, post_encode_observer.Wait()) diff --git a/webrtc/video/full_stack.cc b/webrtc/video/full_stack.cc index 9b0def6f8..0d3c8ee9b 100644 --- a/webrtc/video/full_stack.cc +++ b/webrtc/video/full_stack.cc @@ -18,15 +18,18 @@ #include "webrtc/call.h" #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" +#include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h" #include "webrtc/system_wrappers/interface/clock.h" #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" #include "webrtc/system_wrappers/interface/event_wrapper.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" #include "webrtc/system_wrappers/interface/sleep.h" -#include "webrtc/test/testsupport/fileutils.h" #include "webrtc/test/direct_transport.h" +#include "webrtc/test/encoder_settings.h" +#include "webrtc/test/fake_encoder.h" #include "webrtc/test/frame_generator_capturer.h" #include "webrtc/test/statistics.h" +#include "webrtc/test/testsupport/fileutils.h" #include "webrtc/typedefs.h" DEFINE_int32(seconds, 10, "Seconds to run each clip."); @@ -398,13 +401,15 @@ TEST_P(FullStackTest, NoPacketLoss) { VideoSendStream::Config send_config = call->GetDefaultSendConfig(); send_config.rtp.ssrcs.push_back(kSendSsrc); - // TODO(pbos): static_cast shouldn't be required after mflodman refactors the - // VideoCodec struct. - send_config.codec.width = static_cast(params.clip.width); - send_config.codec.height = static_cast(params.clip.height); - send_config.codec.minBitrate = params.bitrate; - send_config.codec.startBitrate = params.bitrate; - send_config.codec.maxBitrate = params.bitrate; + scoped_ptr encoder(VP8Encoder::Create()); + send_config.encoder_settings = + test::CreateEncoderSettings(encoder.get(), "VP8", 124, 1); + VideoStream* stream = &send_config.encoder_settings.streams[0]; + stream->width = params.clip.width; + stream->height = params.clip.height; + stream->min_bitrate_bps = stream->target_bitrate_bps = + stream->max_bitrate_bps = params.bitrate * 1000; + stream->max_framerate = params.clip.fps; VideoSendStream* send_stream = call->CreateVideoSendStream(send_config); analyzer.input_ = send_stream->Input(); @@ -422,6 +427,9 @@ TEST_P(FullStackTest, NoPacketLoss) { << ".yuv. Is this resource file present?"; VideoReceiveStream::Config receive_config = call->GetDefaultReceiveConfig(); + VideoCodec codec = + test::CreateDecoderVideoCodec(send_config.encoder_settings); + receive_config.codecs.push_back(codec); receive_config.rtp.remote_ssrc = send_config.rtp.ssrcs[0]; receive_config.rtp.local_ssrc = kReceiverLocalSsrc; receive_config.renderer = &analyzer; diff --git a/webrtc/video/loopback.cc b/webrtc/video/loopback.cc index 48de326ef..0131aa928 100644 --- a/webrtc/video/loopback.cc +++ b/webrtc/video/loopback.cc @@ -15,9 +15,12 @@ #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/call.h" +#include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h" #include "webrtc/system_wrappers/interface/clock.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" #include "webrtc/test/direct_transport.h" +#include "webrtc/test/encoder_settings.h" +#include "webrtc/test/fake_encoder.h" #include "webrtc/test/flags.h" #include "webrtc/test/run_loop.h" #include "webrtc/test/run_tests.h" @@ -53,16 +56,18 @@ TEST_F(LoopbackTest, Test) { send_config.local_renderer = local_preview.get(); - // TODO(pbos): static_cast shouldn't be required after mflodman refactors the - // VideoCodec struct. - send_config.codec.width = static_cast(test::flags::Width()); - send_config.codec.height = static_cast(test::flags::Height()); - send_config.codec.minBitrate = - static_cast(test::flags::MinBitrate()); - send_config.codec.startBitrate = - static_cast(test::flags::StartBitrate()); - send_config.codec.maxBitrate = - static_cast(test::flags::MaxBitrate()); + scoped_ptr encoder(VP8Encoder::Create()); + send_config.encoder_settings = + test::CreateEncoderSettings(encoder.get(), "VP8", 124, 1); + VideoStream* stream = &send_config.encoder_settings.streams[0]; + stream->width = test::flags::Width(); + stream->height = test::flags::Height(); + stream->min_bitrate_bps = static_cast(test::flags::MinBitrate()) * 1000; + stream->target_bitrate_bps = + static_cast(test::flags::MaxBitrate()) * 1000; + stream->max_bitrate_bps = static_cast(test::flags::MaxBitrate()) * 1000; + stream->max_framerate = 30; + stream->max_qp = 56; VideoSendStream* send_stream = call->CreateVideoSendStream(send_config); @@ -79,6 +84,9 @@ TEST_F(LoopbackTest, Test) { receive_config.rtp.remote_ssrc = send_config.rtp.ssrcs[0]; receive_config.rtp.local_ssrc = kReceiverLocalSsrc; receive_config.renderer = loopback_video.get(); + VideoCodec codec = + test::CreateDecoderVideoCodec(send_config.encoder_settings); + receive_config.codecs.push_back(codec); VideoReceiveStream* receive_stream = call->CreateVideoReceiveStream(receive_config); diff --git a/webrtc/video/rampup_tests.cc b/webrtc/video/rampup_tests.cc index a50ebb49d..302c0a18d 100644 --- a/webrtc/video/rampup_tests.cc +++ b/webrtc/video/rampup_tests.cc @@ -28,6 +28,7 @@ #include "webrtc/system_wrappers/interface/event_wrapper.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" #include "webrtc/test/direct_transport.h" +#include "webrtc/test/encoder_settings.h" #include "webrtc/test/fake_decoder.h" #include "webrtc/test/fake_encoder.h" #include "webrtc/test/frame_generator_capturer.h" @@ -56,6 +57,7 @@ class StreamObserver : public newapi::Transport, public RemoteBitrateObserver { new RTPPayloadRegistry(-1, RTPPayloadStrategy::CreateStrategy(false))), clock_(clock), + expected_bitrate_bps_(0), rtx_media_ssrcs_(rtx_media_ssrcs), total_sent_(0), padding_sent_(0), @@ -82,10 +84,15 @@ class StreamObserver : public newapi::Transport, public RemoteBitrateObserver { rbe_factory.Create(this, clock, kRemoteBitrateEstimatorMinBitrateBps)); } + void set_expected_bitrate_bps(unsigned int expected_bitrate_bps) { + expected_bitrate_bps_ = expected_bitrate_bps; + } + virtual void OnReceiveBitrateChanged(const std::vector& ssrcs, - unsigned int bitrate) { + unsigned int bitrate) OVERRIDE { CriticalSectionScoped lock(critical_section_.get()); - if (bitrate >= kExpectedBitrateBps) { + assert(expected_bitrate_bps_ > 0); + if (bitrate >= expected_bitrate_bps_) { // Just trigger if there was any rtx padding packet. if (rtx_media_ssrcs_.empty() || rtx_media_sent_ > 0) { TriggerTestDone(); @@ -140,8 +147,6 @@ class StreamObserver : public newapi::Transport, public RemoteBitrateObserver { EventTypeWrapper Wait() { return test_done_->Wait(120 * 1000); } private: - static const unsigned int kExpectedBitrateBps = 1200000; - void ReportResult(const std::string& measurement, size_t value, const std::string& units) { @@ -170,6 +175,7 @@ class StreamObserver : public newapi::Transport, public RemoteBitrateObserver { scoped_ptr payload_registry_; scoped_ptr remote_bitrate_estimator_; Clock* clock_; + unsigned int expected_bitrate_bps_; SsrcMap rtx_media_ssrcs_; size_t total_sent_; size_t padding_sent_; @@ -418,10 +424,8 @@ class RampUpTest : public ::testing::Test { receiver_transport.SetReceiver(call->Receiver()); test::FakeEncoder encoder(Clock::GetRealTimeClock()); - send_config.encoder = &encoder; - send_config.internal_source = false; - test::FakeEncoder::SetCodecSettings(&send_config.codec, kNumberOfStreams); - send_config.codec.plType = 125; + send_config.encoder_settings = + test::CreateEncoderSettings(&encoder, "FAKE", 125, kNumberOfStreams); send_config.pacing = pacing; send_config.rtp.nack.rtp_history_ms = 1000; send_config.rtp.ssrcs = ssrcs; @@ -432,14 +436,28 @@ class RampUpTest : public ::testing::Test { send_config.rtp.extensions.push_back( RtpExtension(RtpExtension::kAbsSendTime, kAbsoluteSendTimeExtensionId)); + // Use target bitrates for all streams except the last one and the min + // bitrate for the last one. This ensures that we reach enough bitrate to + // send all streams. + int expected_bitrate_bps = + send_config.encoder_settings.streams.back().min_bitrate_bps; + for (size_t i = 0; i < send_config.encoder_settings.streams.size() - 1; + ++i) { + expected_bitrate_bps += + send_config.encoder_settings.streams[i].target_bitrate_bps; + } + + stream_observer.set_expected_bitrate_bps(expected_bitrate_bps); + VideoSendStream* send_stream = call->CreateVideoSendStream(send_config); scoped_ptr frame_generator_capturer( - test::FrameGeneratorCapturer::Create(send_stream->Input(), - send_config.codec.width, - send_config.codec.height, - 30, - Clock::GetRealTimeClock())); + test::FrameGeneratorCapturer::Create( + send_stream->Input(), + send_config.encoder_settings.streams.back().width, + send_config.encoder_settings.streams.back().height, + send_config.encoder_settings.streams.back().max_framerate, + Clock::GetRealTimeClock())); send_stream->StartSending(); frame_generator_capturer->Start(); @@ -470,12 +488,8 @@ class RampUpTest : public ::testing::Test { receiver_transport.SetReceiver(call->Receiver()); test::FakeEncoder encoder(Clock::GetRealTimeClock()); - send_config.encoder = &encoder; - send_config.internal_source = false; - test::FakeEncoder::SetCodecSettings(&send_config.codec, number_of_streams); - send_config.codec.plType = 125; - send_config.codec.startBitrate = - send_config.codec.simulcastStream[0].minBitrate; + send_config.encoder_settings = + test::CreateEncoderSettings(&encoder, "FAKE", 125, number_of_streams); send_config.rtp.nack.rtp_history_ms = 1000; send_config.rtp.ssrcs.insert( send_config.rtp.ssrcs.begin(), ssrcs.begin(), ssrcs.end()); @@ -486,10 +500,21 @@ class RampUpTest : public ::testing::Test { VideoSendStream* send_stream = call->CreateVideoSendStream(send_config); stream_observer.SetSendStream(send_stream); + size_t width = 0; + size_t height = 0; + for (size_t i = 0; i < send_config.encoder_settings.streams.size(); ++i) { + size_t stream_width = send_config.encoder_settings.streams[i].width; + size_t stream_height = send_config.encoder_settings.streams[i].height; + if (stream_width > width) + width = stream_width; + if (stream_height > height) + height = stream_height; + } + scoped_ptr frame_generator_capturer( test::FrameGeneratorCapturer::Create(send_stream->Input(), - send_config.codec.width, - send_config.codec.height, + width, + height, 30, Clock::GetRealTimeClock())); @@ -522,7 +547,8 @@ TEST_F(RampUpTest, WithoutPacing) { RunRampUpTest(false, false); } TEST_F(RampUpTest, WithPacing) { RunRampUpTest(true, false); } -TEST_F(RampUpTest, WithPacingAndRtx) { RunRampUpTest(true, true); } +// TODO(pbos): Re-enable, webrtc:2992. +TEST_F(RampUpTest, DISABLED_WithPacingAndRtx) { RunRampUpTest(true, true); } TEST_F(RampUpTest, UpDownUpOneStream) { RunRampUpDownUpTest(1, false); } diff --git a/webrtc/video/video_receive_stream.cc b/webrtc/video/video_receive_stream.cc index 337eda4d4..0301f095f 100644 --- a/webrtc/video/video_receive_stream.cc +++ b/webrtc/video/video_receive_stream.cc @@ -99,6 +99,7 @@ VideoReceiveStream::VideoReceiveStream(webrtc::VideoEngine* video_engine, codec_ = ViECodec::GetInterface(video_engine); + assert(!config_.codecs.empty()); for (size_t i = 0; i < config_.codecs.size(); ++i) { if (codec_->SetReceiveCodec(channel_, config_.codecs[i]) != 0) { // TODO(pbos): Abort gracefully, this can be a runtime error. diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc index 5cacb565b..a480acd21 100644 --- a/webrtc/video/video_send_stream.cc +++ b/webrtc/video/video_send_stream.cc @@ -21,6 +21,7 @@ #include "webrtc/video_engine/include/vie_image_process.h" #include "webrtc/video_engine/include/vie_network.h" #include "webrtc/video_engine/include/vie_rtp_rtcp.h" +#include "webrtc/video_engine/vie_defines.h" #include "webrtc/video_send_stream.h" namespace webrtc { @@ -108,25 +109,27 @@ VideoSendStream::VideoSendStream(newapi::Transport* transport, network_->SetMTU(channel_, static_cast(config_.rtp.max_packet_size + 28)); - if (config.encoder) { - external_codec_ = ViEExternalCodec::GetInterface(video_engine); - if (external_codec_->RegisterExternalSendCodec(channel_, - config.codec.plType, - config.encoder, - config.internal_source) != - 0) { - abort(); - } + assert(config.encoder_settings.encoder != NULL); + assert(config.encoder_settings.payload_type >= 0); + assert(config.encoder_settings.payload_type <= 127); + external_codec_ = ViEExternalCodec::GetInterface(video_engine); + if (external_codec_->RegisterExternalSendCodec( + channel_, + config.encoder_settings.payload_type, + config.encoder_settings.encoder, + false) != 0) { + abort(); } codec_ = ViECodec::GetInterface(video_engine); - if (!SetCodec(config_.codec)) + if (!ReconfigureVideoEncoder(config_.encoder_settings.streams, + config_.encoder_settings.encoder_settings)) { abort(); - - if (overuse_observer) { - video_engine_base_->RegisterCpuOveruseObserver(channel_, overuse_observer); } + if (overuse_observer) + video_engine_base_->RegisterCpuOveruseObserver(channel_, overuse_observer); + image_process_ = ViEImageProcess::GetInterface(video_engine); image_process_->RegisterPreEncodeCallback(channel_, config_.pre_encode_callback); @@ -170,10 +173,8 @@ VideoSendStream::~VideoSendStream() { capture_->DisconnectCaptureDevice(channel_); capture_->ReleaseCaptureDevice(capture_id_); - if (external_codec_) { - external_codec_->DeRegisterExternalSendCodec(channel_, - config_.codec.plType); - } + external_codec_->DeRegisterExternalSendCodec( + channel_, config_.encoder_settings.payload_type); video_engine_base_->DeleteChannel(channel_); @@ -221,11 +222,91 @@ void VideoSendStream::StopSending() { transport_adapter_.Disable(); } -bool VideoSendStream::SetCodec(const VideoCodec& codec) { - assert(config_.rtp.ssrcs.size() >= codec.numberOfSimulcastStreams); +bool VideoSendStream::ReconfigureVideoEncoder( + const std::vector& streams, + void* encoder_settings) { + assert(!streams.empty()); + assert(config_.rtp.ssrcs.size() >= streams.size()); + // TODO(pbos): Wire encoder_settings. + assert(encoder_settings == NULL); + // VideoStreams in config_.encoder_settings need to be locked. CriticalSectionScoped crit(codec_lock_.get()); - if (codec_->SetSendCodec(channel_, codec) != 0) + + VideoCodec video_codec; + memset(&video_codec, 0, sizeof(video_codec)); + video_codec.codecType = + (config_.encoder_settings.payload_name == "VP8" ? kVideoCodecVP8 + : kVideoCodecGeneric); + + if (video_codec.codecType == kVideoCodecVP8) { + video_codec.codecSpecific.VP8.resilience = kResilientStream; + video_codec.codecSpecific.VP8.numberOfTemporalLayers = 1; + video_codec.codecSpecific.VP8.denoisingOn = true; + video_codec.codecSpecific.VP8.errorConcealmentOn = false; + video_codec.codecSpecific.VP8.automaticResizeOn = false; + video_codec.codecSpecific.VP8.frameDroppingOn = true; + video_codec.codecSpecific.VP8.keyFrameInterval = 3000; + } + + strncpy(video_codec.plName, + config_.encoder_settings.payload_name.c_str(), + kPayloadNameSize - 1); + video_codec.plName[kPayloadNameSize - 1] = '\0'; + video_codec.plType = config_.encoder_settings.payload_type; + video_codec.numberOfSimulcastStreams = + static_cast(streams.size()); + video_codec.minBitrate = streams[0].min_bitrate_bps / 1000; + assert(streams.size() <= kMaxSimulcastStreams); + for (size_t i = 0; i < streams.size(); ++i) { + SimulcastStream* sim_stream = &video_codec.simulcastStream[i]; + assert(streams[i].width > 0); + assert(streams[i].height > 0); + assert(streams[i].max_framerate > 0); + // Different framerates not supported per stream at the moment. + assert(streams[i].max_framerate == streams[0].max_framerate); + assert(streams[i].min_bitrate_bps >= 0); + assert(streams[i].target_bitrate_bps >= streams[i].min_bitrate_bps); + assert(streams[i].max_bitrate_bps >= streams[i].target_bitrate_bps); + assert(streams[i].max_qp >= 0); + + sim_stream->width = static_cast(streams[i].width); + sim_stream->height = static_cast(streams[i].height); + sim_stream->minBitrate = streams[i].min_bitrate_bps / 1000; + sim_stream->targetBitrate = streams[i].target_bitrate_bps / 1000; + sim_stream->maxBitrate = streams[i].max_bitrate_bps / 1000; + sim_stream->qpMax = streams[i].max_qp; + // TODO(pbos): Implement mapping for temporal layers. + assert(streams[i].temporal_layers.empty()); + + video_codec.width = std::max(video_codec.width, + static_cast(streams[i].width)); + video_codec.height = std::max( + video_codec.height, static_cast(streams[i].height)); + video_codec.minBitrate = + std::min(video_codec.minBitrate, + static_cast(streams[i].min_bitrate_bps / 1000)); + video_codec.maxBitrate += streams[i].max_bitrate_bps / 1000; + video_codec.qpMax = std::max(video_codec.qpMax, + static_cast(streams[i].max_qp)); + } + + if (video_codec.minBitrate < kViEMinCodecBitrate) + video_codec.minBitrate = kViEMinCodecBitrate; + if (video_codec.maxBitrate < kViEMinCodecBitrate) + video_codec.maxBitrate = kViEMinCodecBitrate; + + video_codec.startBitrate = 300; + + if (video_codec.startBitrate < video_codec.minBitrate) + video_codec.startBitrate = video_codec.minBitrate; + if (video_codec.startBitrate > video_codec.maxBitrate) + video_codec.startBitrate = video_codec.maxBitrate; + + assert(config_.encoder_settings.streams[0].max_framerate > 0); + video_codec.maxFramerate = config_.encoder_settings.streams[0].max_framerate; + + if (codec_->SetSendCodec(channel_, video_codec) != 0) return false; for (size_t i = 0; i < config_.rtp.ssrcs.size(); ++i) { @@ -235,8 +316,8 @@ bool VideoSendStream::SetCodec(const VideoCodec& codec) { static_cast(i)); } - if (&config_.codec != &codec) - config_.codec = codec; + config_.encoder_settings.streams = streams; + config_.encoder_settings.encoder_settings = encoder_settings; if (config_.rtp.rtx.ssrcs.empty()) return true; @@ -256,11 +337,6 @@ bool VideoSendStream::SetCodec(const VideoCodec& codec) { return true; } -VideoCodec VideoSendStream::GetCodec() { - CriticalSectionScoped crit(codec_lock_.get()); - return config_.codec; -} - bool VideoSendStream::DeliverRtcp(const uint8_t* packet, size_t length) { return network_->ReceivedRTCPPacket( channel_, packet, static_cast(length)) == 0; diff --git a/webrtc/video/video_send_stream.h b/webrtc/video/video_send_stream.h index 3ea4fbfb6..15cf64243 100644 --- a/webrtc/video/video_send_stream.h +++ b/webrtc/video/video_send_stream.h @@ -50,8 +50,8 @@ class VideoSendStream : public webrtc::VideoSendStream, virtual void StopSending() OVERRIDE; - virtual bool SetCodec(const VideoCodec& codec) OVERRIDE; - virtual VideoCodec GetCodec() OVERRIDE; + virtual bool ReconfigureVideoEncoder(const std::vector& streams, + void* encoder_settings) OVERRIDE; virtual Stats GetStats() const OVERRIDE; diff --git a/webrtc/video/video_send_stream_tests.cc b/webrtc/video/video_send_stream_tests.cc index 6a6b0e13f..5a4969884 100644 --- a/webrtc/video/video_send_stream_tests.cc +++ b/webrtc/video/video_send_stream_tests.cc @@ -23,6 +23,7 @@ #include "webrtc/system_wrappers/interface/sleep.h" #include "webrtc/system_wrappers/interface/thread_wrapper.h" #include "webrtc/test/direct_transport.h" +#include "webrtc/test/encoder_settings.h" #include "webrtc/test/fake_encoder.h" #include "webrtc/test/configurable_frame_size_encoder.h" #include "webrtc/test/frame_generator_capturer.h" @@ -59,17 +60,16 @@ class VideoSendStreamTest : public ::testing::Test { call->DestroyVideoSendStream(send_stream_); } - VideoSendStream::Config GetSendTestConfig(Call* call, - size_t number_of_streams) { - assert(number_of_streams <= kNumSendSsrcs); + VideoSendStream::Config GetSendTestConfig(Call* call, size_t num_streams) { + assert(num_streams <= kNumSendSsrcs); VideoSendStream::Config config = call->GetDefaultSendConfig(); - config.encoder = &fake_encoder_; - config.internal_source = false; - for (size_t i = 0; i < number_of_streams; ++i) + config.encoder_settings = test::CreateEncoderSettings( + &fake_encoder_, "FAKE", kFakeSendPayloadType, num_streams); + config.encoder_settings.encoder = &fake_encoder_; + config.encoder_settings.payload_type = kFakeSendPayloadType; + for (size_t i = 0; i < num_streams; ++i) config.rtp.ssrcs.push_back(kSendSsrcs[i]); config.pacing = true; - test::FakeEncoder::SetCodecSettings(&config.codec, number_of_streams); - config.codec.plType = kFakeSendPayloadType; return config; } @@ -161,15 +161,17 @@ void VideoSendStreamTest::SendsSetSsrcs(size_t num_ssrcs, if (num_ssrcs > 1) { // Set low simulcast bitrates to not have to wait for bandwidth ramp-up. - for (size_t i = 0; i < num_ssrcs; ++i) { - send_config.codec.simulcastStream[i].minBitrate = 10; - send_config.codec.simulcastStream[i].targetBitrate = 10; - send_config.codec.simulcastStream[i].maxBitrate = 10; + std::vector* streams = &send_config.encoder_settings.streams; + for (size_t i = 0; i < streams->size(); ++i) { + (*streams)[i].min_bitrate_bps = 10000; + (*streams)[i].target_bitrate_bps = 10000; + (*streams)[i].max_bitrate_bps = 10000; } } + std::vector all_streams = send_config.encoder_settings.streams; if (send_single_ssrc_first) - send_config.codec.numberOfSimulcastStreams = 1; + send_config.encoder_settings.streams.resize(1); send_stream_ = call->CreateVideoSendStream(send_config); scoped_ptr frame_generator_capturer( @@ -184,9 +186,7 @@ void VideoSendStreamTest::SendsSetSsrcs(size_t num_ssrcs, if (send_single_ssrc_first) { // Set full simulcast and continue with the rest of the SSRCs. - send_config.codec.numberOfSimulcastStreams = - static_cast(num_ssrcs); - send_stream_->SetCodec(send_config.codec); + send_stream_->ReconfigureVideoEncoder(all_streams, NULL); EXPECT_EQ(kEventSignaled, observer.Wait()) << "Timed out while waiting on additional SSRCs."; } @@ -338,7 +338,7 @@ TEST_F(VideoSendStreamTest, SupportsTransmissionTimeOffset) { scoped_ptr call(Call::Create(call_config)); VideoSendStream::Config send_config = GetSendTestConfig(call.get(), 1); - send_config.encoder = &encoder; + send_config.encoder_settings.encoder = &encoder; send_config.rtp.extensions.push_back( RtpExtension(RtpExtension::kTOffset, kTOffsetExtensionId)); @@ -766,12 +766,11 @@ void VideoSendStreamTest::TestPacketFragmentationSize(VideoFormat format, send_config.rtp.fec.ulpfec_payload_type = kUlpfecPayloadType; } - if (format == kVP8) { - strcpy(send_config.codec.plName, "VP8"); - send_config.codec.codecType = kVideoCodecVP8; - } + if (format == kVP8) + send_config.encoder_settings.payload_name = "VP8"; + send_config.pacing = false; - send_config.encoder = &encoder; + send_config.encoder_settings.encoder = &encoder; send_config.rtp.max_packet_size = kMaxPacketSize; send_config.post_encode_callback = &observer; @@ -801,68 +800,6 @@ TEST_F(VideoSendStreamTest, FragmentsVp8AccordingToMaxPacketSizeWithFec) { TestPacketFragmentationSize(kVP8, true); } -TEST_F(VideoSendStreamTest, CanChangeSendCodec) { - static const uint8_t kFirstPayloadType = 121; - static const uint8_t kSecondPayloadType = 122; - - class CodecChangeObserver : public test::RtpRtcpObserver { - public: - CodecChangeObserver(VideoSendStream** send_stream_ptr) - : RtpRtcpObserver(30 * 1000), - received_first_payload_(EventWrapper::Create()), - send_stream_ptr_(send_stream_ptr) {} - - virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE { - RTPHeader header; - EXPECT_TRUE(parser_->Parse(packet, static_cast(length), &header)); - - if (header.payloadType == kFirstPayloadType) { - received_first_payload_->Set(); - } else if (header.payloadType == kSecondPayloadType) { - observation_complete_->Set(); - } - - return SEND_PACKET; - } - - virtual EventTypeWrapper Wait() OVERRIDE { - EXPECT_EQ(kEventSignaled, received_first_payload_->Wait(30 * 1000)) - << "Timed out while waiting for first payload."; - - EXPECT_TRUE((*send_stream_ptr_)->SetCodec(second_codec_)); - - EXPECT_EQ(kEventSignaled, RtpRtcpObserver::Wait()) - << "Timed out while waiting for second payload type."; - - // Return OK regardless, prevents double error reporting. - return kEventSignaled; - } - - void SetSecondCodec(const VideoCodec& codec) { second_codec_ = codec; } - - private: - scoped_ptr received_first_payload_; - VideoSendStream** send_stream_ptr_; - VideoCodec second_codec_; - } observer(&send_stream_); - - Call::Config call_config(observer.SendTransport()); - scoped_ptr call(Call::Create(call_config)); - - std::vector codecs = call->GetVideoCodecs(); - ASSERT_GE(codecs.size(), 2u) - << "Test needs at least 2 separate codecs to work."; - codecs[0].plType = kFirstPayloadType; - codecs[1].plType = kSecondPayloadType; - observer.SetSecondCodec(codecs[1]); - - VideoSendStream::Config send_config = GetSendTestConfig(call.get(), 1); - send_config.codec = codecs[0]; - send_config.encoder = NULL; - - RunSendTest(call.get(), send_config, &observer); -} - // The test will go through a number of phases. // 1. Start sending packets. // 2. As soon as the RTP stream has been detected, signal a low REMB value to @@ -1005,11 +942,10 @@ TEST_F(VideoSendStreamTest, SuspendBelowMinBitrate) { send_config.rtp.nack.rtp_history_ms = 1000; send_config.pre_encode_callback = &observer; send_config.suspend_below_min_bitrate = true; - unsigned int min_bitrate_bps = - send_config.codec.simulcastStream[0].minBitrate * 1000; + int min_bitrate_bps = send_config.encoder_settings.streams[0].min_bitrate_bps; observer.set_low_remb_bps(min_bitrate_bps - 10000); - unsigned int threshold_window = std::max(min_bitrate_bps / 10, 10000u); - ASSERT_GT(send_config.codec.simulcastStream[0].maxBitrate * 1000, + int threshold_window = std::max(min_bitrate_bps / 10, 10000); + ASSERT_GT(send_config.encoder_settings.streams[0].max_bitrate_bps, min_bitrate_bps + threshold_window + 5000); observer.set_high_remb_bps(min_bitrate_bps + threshold_window + 5000); diff --git a/webrtc/video_send_stream.h b/webrtc/video_send_stream.h index 8279c052a..3fd6ef7d3 100644 --- a/webrtc/video_send_stream.h +++ b/webrtc/video_send_stream.h @@ -61,12 +61,26 @@ class VideoSendStream { post_encode_callback(NULL), local_renderer(NULL), render_delay_ms(0), - encoder(NULL), - internal_source(false), target_delay_ms(0), pacing(false), suspend_below_min_bitrate(false) {} - VideoCodec codec; + struct EncoderSettings { + EncoderSettings() + : payload_type(-1), encoder(NULL), encoder_settings(NULL) {} + std::string payload_name; + int payload_type; + + // Uninitialized VideoEncoder instance to be used for encoding. Will be + // initialized from inside the VideoSendStream. + webrtc::VideoEncoder* encoder; + // TODO(pbos): Wire up encoder-specific settings. + // Encoder-specific settings, will be passed to the encoder during + // initialization. + void* encoder_settings; + + // List of stream settings to encode (resolution, bitrates, framerate). + std::vector streams; + } encoder_settings; static const size_t kDefaultMaxPacketSize = 1500 - 40; // TCP over IPv4. struct Rtp { @@ -125,13 +139,6 @@ class VideoSendStream { // Only valid if |renderer| is set. int render_delay_ms; - // TODO(mflodman) Move VideoEncoder to common_types.h and redefine. - // External encoding. 'encoder' is the external encoder instance and - // 'internal_source' is set to true if the encoder also captures the video - // frames. - VideoEncoder* encoder; - bool internal_source; - // Target delay in milliseconds. A positive value indicates this stream is // used for streaming instead of a real-time call. int target_delay_ms; @@ -155,8 +162,11 @@ class VideoSendStream { virtual void StartSending() = 0; virtual void StopSending() = 0; - virtual bool SetCodec(const VideoCodec& codec) = 0; - virtual VideoCodec GetCodec() = 0; + // Set which streams to send. Must have at least as many SSRCs as configured + // in the config. Encoder settings are passed on to the encoder instance along + // with the VideoStream settings. + virtual bool ReconfigureVideoEncoder(const std::vector& streams, + void* encoder_settings) = 0; virtual Stats GetStats() const = 0;