summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpbos@webrtc.org <pbos@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d>2014-03-19 08:43:57 +0000
committerpbos@webrtc.org <pbos@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d>2014-03-19 08:43:57 +0000
commite2a7a77646b23fb3704d267e6079e04bde493543 (patch)
tree85eab4d63bac08829f30d457caf80858d740b5da
parent76cd2f7dec281c9842ebc5417eeea376fa54746c (diff)
downloadwebrtc-e2a7a77646b23fb3704d267e6079e04bde493543.tar.gz
Remove internal codecs from VideoSendStream.
Replaces VideoCodec in VideoSendStream::Config with an EncoderSettings struct. The EncoderSettings struct uses an external encoder for all codecs. This means that external users, such as libjingle, will provide the encoders themselves, removing the previous distinction of internal and external codecs. For now VideoSendStream translates to VideoCodec internally. In the interrim (before the corresponding change is implemented in VideoReceiveStream) tests convert EncoderSettings to VideoCodecs. Removes Call::GetVideoCodecs(). Disables RampUpTest.WithPacingAndRtx as its further exposed with changes to bitrates used in tests. BUG=2854,2992 R=mflodman@webrtc.org, stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/7919004 git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@5722 4adac7df-926f-26a2-2b94-8c16560cd09d
-rw-r--r--call.h2
-rw-r--r--common_types.h29
-rw-r--r--test/encoder_settings.cc120
-rw-r--r--test/encoder_settings.h28
-rw-r--r--test/fake_encoder.cc36
-rw-r--r--test/fake_encoder.h1
-rw-r--r--test/webrtc_test_common.gyp2
-rw-r--r--video/bitrate_estimator_tests.cc31
-rw-r--r--video/call.cc15
-rw-r--r--video/call_perf_tests.cc44
-rw-r--r--video/call_tests.cc84
-rw-r--r--video/full_stack.cc24
-rw-r--r--video/loopback.cc28
-rw-r--r--video/rampup_tests.cc70
-rw-r--r--video/video_receive_stream.cc1
-rw-r--r--video/video_send_stream.cc128
-rw-r--r--video/video_send_stream.h4
-rw-r--r--video/video_send_stream_tests.cc112
-rw-r--r--video_send_stream.h34
19 files changed, 510 insertions, 283 deletions
diff --git a/call.h b/call.h
index 1b95c298..5b556821 100644
--- a/call.h
+++ b/call.h
@@ -78,8 +78,6 @@ class Call {
static Call* Create(const Call::Config& config,
const webrtc::Config& webrtc_config);
- virtual std::vector<VideoCodec> GetVideoCodecs() = 0;
-
virtual VideoSendStream::Config GetDefaultSendConfig() = 0;
virtual VideoSendStream* CreateVideoSendStream(
diff --git a/common_types.h b/common_types.h
index 9478a2dd..f7e48402 100644
--- a/common_types.h
+++ b/common_types.h
@@ -11,6 +11,10 @@
#ifndef WEBRTC_COMMON_TYPES_H_
#define WEBRTC_COMMON_TYPES_H_
+#include <stddef.h>
+
+#include <vector>
+
#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<int> temporal_layers;
+};
+
} // namespace webrtc
#endif // WEBRTC_COMMON_TYPES_H_
-
diff --git a/test/encoder_settings.cc b/test/encoder_settings.cc
new file mode 100644
index 00000000..d02c29f9
--- /dev/null
+++ b/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 <assert.h>
+#include <string.h>
+
+#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<unsigned short>(stream.width);
+ if (stream.height > codec.height)
+ codec.height = static_cast<unsigned short>(stream.height);
+ if (static_cast<unsigned int>(stream.min_bitrate_bps / 1000) <
+ codec.minBitrate)
+ codec.minBitrate =
+ static_cast<unsigned int>(stream.min_bitrate_bps / 1000);
+ codec.maxBitrate += stream.max_bitrate_bps / 1000;
+ if (static_cast<unsigned int>(stream.max_qp) > codec.qpMax)
+ codec.qpMax = static_cast<unsigned int>(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/test/encoder_settings.h b/test/encoder_settings.h
new file mode 100644
index 00000000..1d8e355a
--- /dev/null
+++ b/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/test/fake_encoder.cc b/test/fake_encoder.cc
index fc8712e5..4ff81a18 100644
--- a/test/fake_encoder.cc
+++ b/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<unsigned char>(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/test/fake_encoder.h b/test/fake_encoder.h
index e2d8d6b4..c0709c12 100644
--- a/test/fake_encoder.h
+++ b/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/test/webrtc_test_common.gyp b/test/webrtc_test_common.gyp
index 6920ab84..bec5803f 100644
--- a/test/webrtc_test_common.gyp
+++ b/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/video/bitrate_estimator_tests.cc b/video/bitrate_estimator_tests.cc
index 58b196db..ea7c0fa0 100644
--- a/video/bitrate_estimator_tests.cc
+++ b/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/video/call.cc b/video/call.cc
index 7c4699e4..bcdcbf76 100644
--- a/video/call.cc
+++ b/video/call.cc
@@ -65,7 +65,6 @@ class Call : public webrtc::Call, public PacketReceiver {
virtual ~Call();
virtual PacketReceiver* Receiver() OVERRIDE;
- virtual std::vector<VideoCodec> GetVideoCodecs() OVERRIDE;
virtual VideoSendStream::Config GetDefaultSendConfig() OVERRIDE;
@@ -246,28 +245,14 @@ Call::~Call() {
PacketReceiver* Call::Receiver() { return this; }
-std::vector<VideoCodec> Call::GetVideoCodecs() {
- std::vector<VideoCodec> codecs;
-
- VideoCodec codec;
- for (size_t i = 0; i < static_cast<size_t>(codec_->NumberOfCodecs()); ++i) {
- if (codec_->GetCodec(static_cast<unsigned char>(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/video/call_perf_tests.cc b/video/call_perf_tests.cc
index 31cfab5f..e2f4775e 100644
--- a/video/call_perf_tests.cc
+++ b/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<test::FrameGeneratorCapturer> 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<test::FrameGeneratorCapturer> 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/video/call_tests.cc b/video/call_tests.cc
index 6e922d3d..505c9960 100644
--- a/video/call_tests.cc
+++ b/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<test::FrameGenerator> 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<VP8Encoder> 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<VP8Encoder> 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<test::FrameGenerator> 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/video/full_stack.cc b/video/full_stack.cc
index 9b0def6f..0d3c8ee9 100644
--- a/video/full_stack.cc
+++ b/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<uint16_t>(params.clip.width);
- send_config.codec.height = static_cast<uint16_t>(params.clip.height);
- send_config.codec.minBitrate = params.bitrate;
- send_config.codec.startBitrate = params.bitrate;
- send_config.codec.maxBitrate = params.bitrate;
+ scoped_ptr<VP8Encoder> 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/video/loopback.cc b/video/loopback.cc
index 48de326e..0131aa92 100644
--- a/video/loopback.cc
+++ b/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<uint16_t>(test::flags::Width());
- send_config.codec.height = static_cast<uint16_t>(test::flags::Height());
- send_config.codec.minBitrate =
- static_cast<unsigned int>(test::flags::MinBitrate());
- send_config.codec.startBitrate =
- static_cast<unsigned int>(test::flags::StartBitrate());
- send_config.codec.maxBitrate =
- static_cast<unsigned int>(test::flags::MaxBitrate());
+ scoped_ptr<VP8Encoder> 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<int>(test::flags::MinBitrate()) * 1000;
+ stream->target_bitrate_bps =
+ static_cast<int>(test::flags::MaxBitrate()) * 1000;
+ stream->max_bitrate_bps = static_cast<int>(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/video/rampup_tests.cc b/video/rampup_tests.cc
index a50ebb49..302c0a18 100644
--- a/video/rampup_tests.cc
+++ b/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<unsigned int>& 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<RTPPayloadRegistry> payload_registry_;
scoped_ptr<RemoteBitrateEstimator> 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<test::FrameGeneratorCapturer> 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<test::FrameGeneratorCapturer> 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/video/video_receive_stream.cc b/video/video_receive_stream.cc
index 337eda4d..0301f095 100644
--- a/video/video_receive_stream.cc
+++ b/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/video/video_send_stream.cc b/video/video_send_stream.cc
index 5cacb565..a480acd2 100644
--- a/video/video_send_stream.cc
+++ b/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,24 +109,26 @@ VideoSendStream::VideoSendStream(newapi::Transport* transport,
network_->SetMTU(channel_,
static_cast<unsigned int>(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) {
+ if (overuse_observer)
video_engine_base_->RegisterCpuOveruseObserver(channel_, overuse_observer);
- }
image_process_ = ViEImageProcess::GetInterface(video_engine);
image_process_->RegisterPreEncodeCallback(channel_,
@@ -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<VideoStream>& 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<unsigned char>(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<unsigned short>(streams[i].width);
+ sim_stream->height = static_cast<unsigned short>(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<unsigned short>(streams[i].width));
+ video_codec.height = std::max(
+ video_codec.height, static_cast<unsigned short>(streams[i].height));
+ video_codec.minBitrate =
+ std::min(video_codec.minBitrate,
+ static_cast<unsigned int>(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<unsigned int>(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<unsigned char>(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<int>(length)) == 0;
diff --git a/video/video_send_stream.h b/video/video_send_stream.h
index 3ea4fbfb..15cf6424 100644
--- a/video/video_send_stream.h
+++ b/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<VideoStream>& streams,
+ void* encoder_settings) OVERRIDE;
virtual Stats GetStats() const OVERRIDE;
diff --git a/video/video_send_stream_tests.cc b/video/video_send_stream_tests.cc
index 6a6b0e13..5a496988 100644
--- a/video/video_send_stream_tests.cc
+++ b/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<VideoStream>* 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<VideoStream> 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<test::FrameGeneratorCapturer> 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<unsigned char>(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(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<int>(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<EventWrapper> received_first_payload_;
- VideoSendStream** send_stream_ptr_;
- VideoCodec second_codec_;
- } observer(&send_stream_);
-
- Call::Config call_config(observer.SendTransport());
- scoped_ptr<Call> call(Call::Create(call_config));
-
- std::vector<VideoCodec> 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/video_send_stream.h b/video_send_stream.h
index 8279c052..3fd6ef7d 100644
--- a/video_send_stream.h
+++ b/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<VideoStream> 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<VideoStream>& streams,
+ void* encoder_settings) = 0;
virtual Stats GetStats() const = 0;