Let ViEEncoder tell VideoSendStream about reconfigurations.

This cl change so that all encoder configuration changes are reported to VideoSendStream through the ViEEncoder.
Also, the PayLoadRouter is changed to never stop sending on a an ssrc due to the encoder video frame size changes. Instead, the number of sending streams is only decided by the number of sending ssrc.

This cl is a preparation for moving encoder reconfiguration due to input video frame size changes from WebRtcVideoSendStream to ViEEncoder.

BUG=webrtc:5687, webrtc:6371
R=mflodman@webrtc.org

Review URL: https://codereview.webrtc.org/2338133003 .

Cr-Commit-Position: refs/heads/master@{#14371}
This commit is contained in:
Per 2016-09-23 15:52:06 +02:00
parent 2a27b0a478
commit 512ecb3206
7 changed files with 171 additions and 126 deletions

View File

@ -90,10 +90,8 @@ void CopyCodecSpecific(const CodecSpecificInfo* info, RTPVideoHeader* rtp) {
PayloadRouter::PayloadRouter(const std::vector<RtpRtcp*>& rtp_modules,
int payload_type)
: active_(false),
num_sending_modules_(1),
rtp_modules_(rtp_modules),
payload_type_(payload_type) {
UpdateModuleSendingState();
}
PayloadRouter::~PayloadRouter() {}
@ -108,7 +106,11 @@ void PayloadRouter::set_active(bool active) {
if (active_ == active)
return;
active_ = active;
UpdateModuleSendingState();
for (auto& module : rtp_modules_) {
module->SetSendingStatus(active_);
module->SetSendingMediaStatus(active_);
}
}
bool PayloadRouter::active() {
@ -116,34 +118,13 @@ bool PayloadRouter::active() {
return active_ && !rtp_modules_.empty();
}
void PayloadRouter::SetSendStreams(const std::vector<VideoStream>& streams) {
RTC_DCHECK_LE(streams.size(), rtp_modules_.size());
rtc::CritScope lock(&crit_);
num_sending_modules_ = streams.size();
streams_ = streams;
// TODO(perkj): Should SetSendStreams also call SetTargetSendBitrate?
UpdateModuleSendingState();
}
void PayloadRouter::UpdateModuleSendingState() {
for (size_t i = 0; i < num_sending_modules_; ++i) {
rtp_modules_[i]->SetSendingStatus(active_);
rtp_modules_[i]->SetSendingMediaStatus(active_);
}
// Disable inactive modules.
for (size_t i = num_sending_modules_; i < rtp_modules_.size(); ++i) {
rtp_modules_[i]->SetSendingStatus(false);
rtp_modules_[i]->SetSendingMediaStatus(false);
}
}
EncodedImageCallback::Result PayloadRouter::OnEncodedImage(
const EncodedImage& encoded_image,
const CodecSpecificInfo* codec_specific_info,
const RTPFragmentationHeader* fragmentation) {
rtc::CritScope lock(&crit_);
RTC_DCHECK(!rtp_modules_.empty());
if (!active_ || num_sending_modules_ == 0)
if (!active_)
return Result(Result::ERROR_SEND_FAILED);
int stream_index = 0;
@ -154,12 +135,6 @@ EncodedImageCallback::Result PayloadRouter::OnEncodedImage(
CopyCodecSpecific(codec_specific_info, &rtp_video_header);
rtp_video_header.rotation = encoded_image.rotation_;
rtp_video_header.playout_delay = encoded_image.playout_delay_;
RTC_DCHECK_LT(rtp_video_header.simulcastIdx, rtp_modules_.size());
// The simulcast index might actually be larger than the number of modules
// in case the encoder was processing a frame during a codec reconfig.
if (rtp_video_header.simulcastIdx >= num_sending_modules_)
return Result(Result::ERROR_SEND_FAILED);
stream_index = rtp_video_header.simulcastIdx;
uint32_t frame_id;
@ -168,6 +143,7 @@ EncodedImageCallback::Result PayloadRouter::OnEncodedImage(
encoded_image.capture_time_ms_, encoded_image._buffer,
encoded_image._length, fragmentation, &rtp_video_header, &frame_id);
RTC_DCHECK_LT(rtp_video_header.simulcastIdx, rtp_modules_.size());
if (send_result < 0)
return Result(Result::ERROR_SEND_FAILED);
@ -177,7 +153,7 @@ EncodedImageCallback::Result PayloadRouter::OnEncodedImage(
size_t PayloadRouter::MaxPayloadLength() const {
size_t min_payload_length = DefaultMaxPayloadLength();
rtc::CritScope lock(&crit_);
for (size_t i = 0; i < num_sending_modules_; ++i) {
for (size_t i = 0; i < rtp_modules_.size(); ++i) {
size_t module_payload_length = rtp_modules_[i]->MaxDataPayloadLength();
if (module_payload_length < min_payload_length)
min_payload_length = module_payload_length;

View File

@ -37,7 +37,6 @@ class PayloadRouter : public EncodedImageCallback {
~PayloadRouter();
static size_t DefaultMaxPayloadLength();
void SetSendStreams(const std::vector<VideoStream>& streams);
// PayloadRouter will only route packets if being active, all packets will be
// dropped otherwise.
@ -60,8 +59,6 @@ class PayloadRouter : public EncodedImageCallback {
rtc::CriticalSection crit_;
bool active_ GUARDED_BY(crit_);
std::vector<VideoStream> streams_ GUARDED_BY(crit_);
size_t num_sending_modules_ GUARDED_BY(crit_);
// Rtp modules are assumed to be sorted in simulcast index order. Not owned.
const std::vector<RtpRtcp*> rtp_modules_;

View File

@ -39,7 +39,6 @@ TEST(PayloadRouterTest, SendOnOneModule) {
encoded_image._length = 1;
PayloadRouter payload_router(modules, payload_type);
payload_router.SetSendStreams(streams);
EXPECT_CALL(rtp, SendOutgoingData(encoded_image._frameType, payload_type,
encoded_image._timeStamp,
@ -71,15 +70,6 @@ TEST(PayloadRouterTest, SendOnOneModule) {
encoded_image._length, nullptr, _, _))
.Times(1);
EXPECT_EQ(0, payload_router.Encoded(encoded_image, nullptr, nullptr));
streams.clear();
payload_router.SetSendStreams(streams);
EXPECT_CALL(rtp, SendOutgoingData(encoded_image._frameType, payload_type,
encoded_image._timeStamp,
encoded_image.capture_time_ms_, &payload,
encoded_image._length, nullptr, _, _))
.Times(0);
EXPECT_EQ(-1, payload_router.Encoded(encoded_image, nullptr, nullptr));
}
TEST(PayloadRouterTest, SendSimulcast) {
@ -100,7 +90,6 @@ TEST(PayloadRouterTest, SendSimulcast) {
encoded_image._length = 1;
PayloadRouter payload_router(modules, payload_type);
payload_router.SetSendStreams(streams);
CodecSpecificInfo codec_info_1;
memset(&codec_info_1, 0, sizeof(CodecSpecificInfo));
@ -138,17 +127,6 @@ TEST(PayloadRouterTest, SendSimulcast) {
.Times(0);
EXPECT_EQ(-1, payload_router.Encoded(encoded_image, &codec_info_1, nullptr));
EXPECT_EQ(-1, payload_router.Encoded(encoded_image, &codec_info_2, nullptr));
// Invalid simulcast index.
streams.pop_back(); // Remove a stream.
payload_router.SetSendStreams(streams);
payload_router.set_active(true);
EXPECT_CALL(rtp_1, SendOutgoingData(_, _, _, _, _, _, _, _, _))
.Times(0);
EXPECT_CALL(rtp_2, SendOutgoingData(_, _, _, _, _, _, _, _, _))
.Times(0);
codec_info_2.codecSpecific.VP8.simulcastIdx = 1;
EXPECT_EQ(-1, payload_router.Encoded(encoded_image, &codec_info_2, nullptr));
}
TEST(PayloadRouterTest, MaxPayloadLength) {
@ -164,7 +142,6 @@ TEST(PayloadRouterTest, MaxPayloadLength) {
EXPECT_EQ(kDefaultMaxLength, PayloadRouter::DefaultMaxPayloadLength());
std::vector<VideoStream> streams(2);
payload_router.SetSendStreams(streams);
// Modules return a higher length than the default value.
EXPECT_CALL(rtp_1, MaxDataPayloadLength())

View File

@ -202,23 +202,23 @@ bool PayloadTypeSupportsSkippingFecPackets(const std::string& payload_name) {
return false;
}
int CalculateMaxPadBitrateBps(const VideoEncoderConfig& config,
int CalculateMaxPadBitrateBps(std::vector<VideoStream> streams,
int min_transmit_bitrate_bps,
bool pad_to_min_bitrate) {
int pad_up_to_bitrate_bps = 0;
// Calculate max padding bitrate for a multi layer codec.
if (config.streams.size() > 1) {
if (streams.size() > 1) {
// Pad to min bitrate of the highest layer.
pad_up_to_bitrate_bps =
config.streams[config.streams.size() - 1].min_bitrate_bps;
pad_up_to_bitrate_bps = streams[streams.size() - 1].min_bitrate_bps;
// Add target_bitrate_bps of the lower layers.
for (size_t i = 0; i < config.streams.size() - 1; ++i)
pad_up_to_bitrate_bps += config.streams[i].target_bitrate_bps;
for (size_t i = 0; i < streams.size() - 1; ++i)
pad_up_to_bitrate_bps += streams[i].target_bitrate_bps;
} else if (pad_to_min_bitrate) {
pad_up_to_bitrate_bps = config.streams[0].min_bitrate_bps;
pad_up_to_bitrate_bps = streams[0].min_bitrate_bps;
}
pad_up_to_bitrate_bps =
std::max(pad_up_to_bitrate_bps, config.min_transmit_bitrate_bps);
std::max(pad_up_to_bitrate_bps, min_transmit_bitrate_bps);
return pad_up_to_bitrate_bps;
}
@ -236,7 +236,7 @@ namespace internal {
// arbitrary thread.
class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver,
public webrtc::VCMProtectionCallback,
public EncodedImageCallback {
public ViEEncoder::EncoderSink {
public:
VideoSendStreamImpl(SendStatisticsProxy* stats_proxy,
rtc::TaskQueue* worker_queue,
@ -248,6 +248,7 @@ class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver,
ViEEncoder* vie_encoder,
RtcEventLog* event_log,
const VideoSendStream::Config* config,
int initial_encoder_max_bitrate,
std::map<uint32_t, RtpState> suspended_ssrcs);
~VideoSendStreamImpl() override;
@ -264,11 +265,11 @@ class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver,
void Start();
void Stop();
void SignalEncoderConfigurationChanged(const VideoEncoderConfig& config);
VideoSendStream::RtpStateMap GetRtpStates() const;
private:
class CheckEncoderActivityTask;
class EncoderReconfiguredTask;
// Implements BitrateAllocatorObserver.
uint32_t OnBitrateUpdated(uint32_t bitrate_bps,
@ -282,6 +283,9 @@ class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver,
uint32_t* sent_nack_rate_bps,
uint32_t* sent_fec_rate_bps) override;
void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
int min_transmit_bitrate_bps) override;
// Implements EncodedImageCallback. The implementation routes encoded frames
// to the |payload_router_| and |config.pre_encode_callback| if set.
// Called on an arbitrary encoder callback thread.
@ -306,6 +310,7 @@ class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver,
rtc::CriticalSection encoder_activity_crit_sect_;
CheckEncoderActivityTask* check_encoder_activity_task_
GUARDED_BY(encoder_activity_crit_sect_);
CallStats* const call_stats_;
CongestionController* const congestion_controller_;
BitrateAllocator* const bitrate_allocator_;
@ -346,6 +351,7 @@ class VideoSendStream::ConstructionTask : public rtc::QueuedTask {
VieRemb* remb,
RtcEventLog* event_log,
const VideoSendStream::Config* config,
int initial_encoder_max_bitrate,
const std::map<uint32_t, RtpState>& suspended_ssrcs)
: send_stream_(send_stream),
done_event_(done_event),
@ -358,6 +364,7 @@ class VideoSendStream::ConstructionTask : public rtc::QueuedTask {
remb_(remb),
event_log_(event_log),
config_(config),
initial_encoder_max_bitrate_(initial_encoder_max_bitrate),
suspended_ssrcs_(suspended_ssrcs) {}
~ConstructionTask() override { done_event_->Set(); }
@ -367,7 +374,8 @@ class VideoSendStream::ConstructionTask : public rtc::QueuedTask {
send_stream_->reset(new VideoSendStreamImpl(
stats_proxy_, rtc::TaskQueue::Current(), call_stats_,
congestion_controller_, bitrate_allocator_, send_delay_stats_, remb_,
vie_encoder_, event_log_, config_, std::move(suspended_ssrcs_)));
vie_encoder_, event_log_, config_, initial_encoder_max_bitrate_,
std::move(suspended_ssrcs_)));
return true;
}
@ -382,6 +390,7 @@ class VideoSendStream::ConstructionTask : public rtc::QueuedTask {
VieRemb* const remb_;
RtcEventLog* const event_log_;
const VideoSendStream::Config* config_;
int initial_encoder_max_bitrate_;
std::map<uint32_t, RtpState> suspended_ssrcs_;
};
@ -461,20 +470,25 @@ class VideoSendStreamImpl::CheckEncoderActivityTask : public rtc::QueuedTask {
bool timed_out_;
};
class ReconfigureVideoEncoderTask : public rtc::QueuedTask {
class VideoSendStreamImpl::EncoderReconfiguredTask : public rtc::QueuedTask {
public:
ReconfigureVideoEncoderTask(VideoSendStreamImpl* send_stream,
VideoEncoderConfig config)
: send_stream_(send_stream), config_(std::move(config)) {}
EncoderReconfiguredTask(VideoSendStreamImpl* send_stream,
std::vector<VideoStream> streams,
int min_transmit_bitrate_bps)
: send_stream_(send_stream),
streams_(std::move(streams)),
min_transmit_bitrate_bps_(min_transmit_bitrate_bps) {}
private:
bool Run() override {
send_stream_->SignalEncoderConfigurationChanged(std::move(config_));
send_stream_->OnEncoderConfigurationChanged(std::move(streams_),
min_transmit_bitrate_bps_);
return true;
}
VideoSendStreamImpl* send_stream_;
VideoEncoderConfig config_;
std::vector<VideoStream> streams_;
int min_transmit_bitrate_bps_;
};
VideoSendStream::VideoSendStream(
@ -501,11 +515,18 @@ VideoSendStream::VideoSendStream(
config_.pre_encode_callback, config_.overuse_callback,
config_.post_encode_callback));
// TODO(perkj): Remove vector<VideoStreams> from VideoEncoderConfig and
// replace with max_bitrate. The VideoStream should be created by ViEEncoder
// when the video resolution is known.
int initial_max_encoder_bitrate = 0;
for (const auto& stream : encoder_config.streams)
initial_max_encoder_bitrate += stream.max_bitrate_bps;
worker_queue_->PostTask(std::unique_ptr<rtc::QueuedTask>(new ConstructionTask(
&send_stream_, &thread_sync_event_, &stats_proxy_, vie_encoder_.get(),
module_process_thread, call_stats, congestion_controller,
bitrate_allocator, send_delay_stats, remb, event_log, &config_,
suspended_ssrcs)));
initial_max_encoder_bitrate, suspended_ssrcs)));
// Wait for ConstructionTask to complete so that |send_stream_| can be used.
// |module_process_thread| must be registered and deregistered on the thread
@ -558,10 +579,8 @@ void VideoSendStream::ReconfigureVideoEncoder(VideoEncoderConfig config) {
// TODO(perkj): Move logic for reconfiguration the encoder due to frame size
// change from WebRtcVideoChannel2::WebRtcVideoSendStream::OnFrame to
// be internally handled by ViEEncoder.
vie_encoder_->ConfigureEncoder(config, config_.rtp.max_packet_size);
worker_queue_->PostTask(std::unique_ptr<rtc::QueuedTask>(
new ReconfigureVideoEncoderTask(send_stream_.get(), std::move(config))));
vie_encoder_->ConfigureEncoder(std::move(config),
config_.rtp.max_packet_size);
}
VideoSendStream::Stats VideoSendStream::GetStats() {
@ -607,6 +626,7 @@ VideoSendStreamImpl::VideoSendStreamImpl(
ViEEncoder* vie_encoder,
RtcEventLog* event_log,
const VideoSendStream::Config* config,
int initial_encoder_max_bitrate,
std::map<uint32_t, RtpState> suspended_ssrcs)
: stats_proxy_(stats_proxy),
config_(config),
@ -620,7 +640,7 @@ VideoSendStreamImpl::VideoSendStreamImpl(
remb_(remb),
max_padding_bitrate_(0),
encoder_min_bitrate_bps_(0),
encoder_max_bitrate_bps_(0),
encoder_max_bitrate_bps_(initial_encoder_max_bitrate),
encoder_target_rate_bps_(0),
vie_encoder_(vie_encoder),
encoder_feedback_(Clock::GetRealTimeClock(),
@ -801,35 +821,44 @@ void VideoSendStreamImpl::SignalEncoderActive() {
max_padding_bitrate_, !config_->suspend_below_min_bitrate);
}
void VideoSendStreamImpl::SignalEncoderConfigurationChanged(
const VideoEncoderConfig& config) {
RTC_DCHECK_GE(config_->rtp.ssrcs.size(), config.streams.size());
TRACE_EVENT0("webrtc", "VideoSendStream::SignalEncoderConfigurationChanged");
LOG(LS_INFO) << "SignalEncoderConfigurationChanged: " << config.ToString();
RTC_DCHECK_GE(config_->rtp.ssrcs.size(), config.streams.size());
void VideoSendStreamImpl::OnEncoderConfigurationChanged(
std::vector<VideoStream> streams,
int min_transmit_bitrate_bps) {
if (!worker_queue_->IsCurrent()) {
// TODO(perkj): Using |this| in post is safe for now since destruction of
// VideoSendStreamImpl is synchronized in
// VideoSendStream::StopPermanentlyAndGetRtpStates. But we should really
// use some kind of weak_ptr to guarantee that VideoSendStreamImpl is still
// alive when this task runs.
worker_queue_->PostTask(
std::unique_ptr<rtc::QueuedTask>(new EncoderReconfiguredTask(
this, std::move(streams), min_transmit_bitrate_bps)));
return;
}
RTC_DCHECK_GE(config_->rtp.ssrcs.size(), streams.size());
TRACE_EVENT0("webrtc", "VideoSendStream::OnEncoderConfigurationChanged");
RTC_DCHECK_GE(config_->rtp.ssrcs.size(), streams.size());
RTC_DCHECK_RUN_ON(worker_queue_);
const int kEncoderMinBitrateBps = 30000;
encoder_min_bitrate_bps_ =
std::max(config.streams[0].min_bitrate_bps, kEncoderMinBitrateBps);
std::max(streams[0].min_bitrate_bps, kEncoderMinBitrateBps);
encoder_max_bitrate_bps_ = 0;
for (const auto& stream : config.streams)
for (const auto& stream : streams)
encoder_max_bitrate_bps_ += stream.max_bitrate_bps;
max_padding_bitrate_ =
CalculateMaxPadBitrateBps(config, config_->suspend_below_min_bitrate);
payload_router_.SetSendStreams(config.streams);
max_padding_bitrate_ = CalculateMaxPadBitrateBps(
streams, min_transmit_bitrate_bps, config_->suspend_below_min_bitrate);
// Clear stats for disabled layers.
for (size_t i = config.streams.size(); i < config_->rtp.ssrcs.size(); ++i) {
for (size_t i = streams.size(); i < config_->rtp.ssrcs.size(); ++i) {
stats_proxy_->OnInactiveSsrc(config_->rtp.ssrcs[i]);
}
size_t number_of_temporal_layers =
config.streams.back().temporal_layer_thresholds_bps.size() + 1;
streams.back().temporal_layer_thresholds_bps.size() + 1;
protection_bitrate_calculator_.SetEncodingData(
config.streams[0].width, config.streams[0].height,
number_of_temporal_layers, config_->rtp.max_packet_size);
streams[0].width, streams[0].height, number_of_temporal_layers,
config_->rtp.max_packet_size);
if (payload_router_.active()) {
// The send stream is started already. Update the allocator with new bitrate

View File

@ -12,6 +12,7 @@
#include <algorithm>
#include <limits>
#include <utility>
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
@ -367,7 +368,7 @@ void ViEEncoder::SetSource(rtc::VideoSourceInterface<VideoFrame>* source) {
source_proxy_->SetSource(source);
}
void ViEEncoder::SetSink(EncodedImageCallback* sink) {
void ViEEncoder::SetSink(EncoderSink* sink) {
encoder_queue_.PostTask([this, sink] {
RTC_DCHECK_RUN_ON(&encoder_queue_);
sink_ = sink;
@ -381,18 +382,25 @@ void ViEEncoder::SetStartBitrate(int start_bitrate_bps) {
});
}
void ViEEncoder::ConfigureEncoder(const VideoEncoderConfig& config,
void ViEEncoder::ConfigureEncoder(VideoEncoderConfig config,
size_t max_data_payload_length) {
VideoCodec video_codec = VideoEncoderConfigToVideoCodec(
config, settings_.payload_name, settings_.payload_type);
encoder_queue_.PostTask([this, video_codec, max_data_payload_length] {
ConfigureEncoderInternal(video_codec, max_data_payload_length);
LOG(LS_INFO) << "ConfigureEncoder: " << config.ToString();
std::vector<VideoStream> stream = std::move(config.streams);
int min_transmit_bitrate = config.min_transmit_bitrate_bps;
encoder_queue_.PostTask([this, video_codec, max_data_payload_length, stream,
min_transmit_bitrate] {
ConfigureEncoderInternal(video_codec, max_data_payload_length, stream,
min_transmit_bitrate);
});
return;
}
void ViEEncoder::ConfigureEncoderInternal(const VideoCodec& video_codec,
size_t max_data_payload_length) {
size_t max_data_payload_length,
std::vector<VideoStream> stream,
int min_transmit_bitrate) {
RTC_DCHECK_RUN_ON(&encoder_queue_);
RTC_DCHECK_GE(encoder_start_bitrate_bps_, 0);
RTC_DCHECK(sink_);
@ -434,6 +442,8 @@ void ViEEncoder::ConfigureEncoderInternal(const VideoCodec& video_codec,
}
stats_proxy_->SetContentType(content_type);
}
sink_->OnEncoderConfigurationChanged(stream, min_transmit_bitrate);
}
void ViEEncoder::OnFrame(const VideoFrame& video_frame) {

View File

@ -49,6 +49,15 @@ class ViEEncoder : public rtc::VideoSinkInterface<VideoFrame>,
public VCMSendStatisticsCallback,
public CpuOveruseObserver {
public:
// Interface for receiving encoded video frames and notifications about
// configuration changes.
class EncoderSink : public EncodedImageCallback {
public:
virtual void OnEncoderConfigurationChanged(
std::vector<VideoStream> streams,
int min_transmit_bitrate_bps) = 0;
};
ViEEncoder(uint32_t number_of_cores,
SendStatisticsProxy* stats_proxy,
const webrtc::VideoSendStream::Config::EncoderSettings& settings,
@ -64,12 +73,12 @@ class ViEEncoder : public rtc::VideoSinkInterface<VideoFrame>,
void DeRegisterProcessThread();
void SetSource(rtc::VideoSourceInterface<VideoFrame>* source);
void SetSink(EncodedImageCallback* sink);
void SetSink(EncoderSink* sink);
// TODO(perkj): Can we remove VideoCodec.startBitrate ?
void SetStartBitrate(int start_bitrate_bps);
void ConfigureEncoder(const VideoEncoderConfig& config,
void ConfigureEncoder(VideoEncoderConfig config,
size_t max_data_payload_length);
// Permanently stop encoding. After this method has returned, it is
@ -92,7 +101,9 @@ class ViEEncoder : public rtc::VideoSinkInterface<VideoFrame>,
class VideoSourceProxy;
void ConfigureEncoderInternal(const VideoCodec& video_codec,
size_t max_data_payload_length);
size_t max_data_payload_length,
std::vector<VideoStream> stream,
int min_transmit_bitrate);
// Implements VideoSinkInterface.
void OnFrame(const VideoFrame& video_frame) override;
@ -123,7 +134,7 @@ class ViEEncoder : public rtc::VideoSinkInterface<VideoFrame>,
const uint32_t number_of_cores_;
const std::unique_ptr<VideoSourceProxy> source_proxy_;
EncodedImageCallback* sink_;
EncoderSink* sink_;
const VideoSendStream::Config::EncoderSettings settings_;
const std::unique_ptr<VideoProcessing> vp_;

View File

@ -8,6 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include <utility>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/logging.h"
#include "webrtc/test/encoder_settings.h"
@ -36,7 +38,10 @@ class ViEEncoderTest : public ::testing::Test {
video_send_config_.encoder_settings.payload_name = "FAKE";
video_send_config_.encoder_settings.payload_type = 125;
video_encoder_config_.streams = test::CreateVideoStreams(1);
VideoEncoderConfig video_encoder_config;
video_encoder_config.streams = test::CreateVideoStreams(1);
codec_width_ = static_cast<int>(video_encoder_config.streams[0].width);
codec_height_ = static_cast<int>(video_encoder_config.streams[0].height);
vie_encoder_.reset(new ViEEncoder(
1 /* number_of_cores */, &stats_proxy_,
@ -45,7 +50,7 @@ class ViEEncoderTest : public ::testing::Test {
vie_encoder_->SetSink(&sink_);
vie_encoder_->SetSource(&video_source_);
vie_encoder_->SetStartBitrate(10000);
vie_encoder_->ConfigureEncoder(video_encoder_config_, 1440);
vie_encoder_->ConfigureEncoder(std::move(video_encoder_config), 1440);
}
VideoFrame CreateFrame(int64_t ntp_ts, rtc::Event* destruction_event) const {
@ -63,12 +68,9 @@ class ViEEncoderTest : public ::testing::Test {
rtc::Event* const event_;
};
VideoFrame frame(
new rtc::RefCountedObject<TestBuffer>(
destruction_event,
static_cast<int>(video_encoder_config_.streams[0].width),
static_cast<int>(video_encoder_config_.streams[0].height)),
99, 99, kVideoRotation_0);
VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
destruction_event, codec_width_, codec_height_),
99, 99, kVideoRotation_0);
frame.set_ntp_time_ms(ntp_ts);
return frame;
}
@ -123,21 +125,11 @@ class ViEEncoderTest : public ::testing::Test {
int64_t ntp_time_ms_ = 0;
};
class TestSink : public EncodedImageCallback {
class TestSink : public ViEEncoder::EncoderSink {
public:
explicit TestSink(TestEncoder* test_encoder)
: test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
int32_t Encoded(const EncodedImage& encoded_image,
const CodecSpecificInfo* codec_specific_info,
const RTPFragmentationHeader* fragmentation) override {
rtc::CritScope lock(&crit_);
EXPECT_TRUE(expect_frames_);
timestamp_ = encoded_image._timeStamp;
encoded_frame_event_.Set();
return 0;
}
void WaitForEncodedFrame(int64_t expected_ntp_time) {
uint32_t timestamp = 0;
EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
@ -153,16 +145,46 @@ class ViEEncoderTest : public ::testing::Test {
expect_frames_ = false;
}
int number_of_reconfigurations() {
rtc::CritScope lock(&crit_);
return number_of_reconfigurations_;
}
int last_min_transmit_bitrate() {
rtc::CritScope lock(&crit_);
return min_transmit_bitrate_bps_;
}
private:
int32_t Encoded(const EncodedImage& encoded_image,
const CodecSpecificInfo* codec_specific_info,
const RTPFragmentationHeader* fragmentation) override {
rtc::CritScope lock(&crit_);
EXPECT_TRUE(expect_frames_);
timestamp_ = encoded_image._timeStamp;
encoded_frame_event_.Set();
return 0;
}
void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
int min_transmit_bitrate_bps) override {
rtc::CriticalSection crit_;
++number_of_reconfigurations_;
min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
}
rtc::CriticalSection crit_;
TestEncoder* test_encoder_;
rtc::Event encoded_frame_event_;
uint32_t timestamp_ = 0;
bool expect_frames_ = true;
int number_of_reconfigurations_ = 0;
int min_transmit_bitrate_bps_ = 0;
};
VideoSendStream::Config video_send_config_;
VideoEncoderConfig video_encoder_config_;
int codec_width_;
int codec_height_;
TestEncoder fake_encoder_;
SendStatisticsProxy stats_proxy_;
TestSink sink_;
@ -255,4 +277,27 @@ TEST_F(ViEEncoderTest, DropsPendingFramesOnSlowEncode) {
vie_encoder_->Stop();
}
TEST_F(ViEEncoderTest, ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
const int kTargetBitrateBps = 100000;
vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
// Capture a frame and wait for it to synchronize with the encoder thread.
vie_encoder_->IncomingCapturedFrame(CreateFrame(1, nullptr));
sink_.WaitForEncodedFrame(1);
EXPECT_EQ(1, sink_.number_of_reconfigurations());
VideoEncoderConfig video_encoder_config;
video_encoder_config.streams = test::CreateVideoStreams(1);
video_encoder_config.min_transmit_bitrate_bps = 9999;
vie_encoder_->ConfigureEncoder(std::move(video_encoder_config), 1440);
// Capture a frame and wait for it to synchronize with the encoder thread.
vie_encoder_->IncomingCapturedFrame(CreateFrame(2, nullptr));
sink_.WaitForEncodedFrame(2);
EXPECT_EQ(2, sink_.number_of_reconfigurations());
EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
vie_encoder_->Stop();
}
} // namespace webrtc