diff --git a/webrtc/test/fake_encoder.cc b/webrtc/test/fake_encoder.cc index 46b51b6aa4..ac7144079b 100644 --- a/webrtc/test/fake_encoder.cc +++ b/webrtc/test/fake_encoder.cc @@ -10,10 +10,14 @@ #include "webrtc/test/fake_encoder.h" +#include + #include +#include #include "webrtc/base/atomicops.h" #include "webrtc/base/checks.h" +#include "webrtc/common_types.h" #include "webrtc/modules/video_coding/include/video_codec_interface.h" #include "webrtc/system_wrappers/include/sleep.h" #include "webrtc/test/gtest.h" @@ -23,7 +27,7 @@ namespace test { FakeEncoder::FakeEncoder(Clock* clock) : clock_(clock), - callback_(NULL), + callback_(nullptr), max_target_bitrate_kbps_(-1), last_encode_time_ms_(0) { // Generate some arbitrary not-all-zero data @@ -36,12 +40,14 @@ FakeEncoder::~FakeEncoder() {} void FakeEncoder::SetMaxBitrate(int max_kbps) { RTC_DCHECK_GE(max_kbps, -1); // max_kbps == -1 disables it. + rtc::CritScope cs(&crit_sect_); max_target_bitrate_kbps_ = max_kbps; } int32_t FakeEncoder::InitEncode(const VideoCodec* config, int32_t number_of_cores, size_t max_payload_size) { + rtc::CritScope cs(&crit_sect_); config_ = *config; target_bitrate_.SetBitrate(0, 0, config_.startBitrate * 1000); return 0; @@ -50,43 +56,70 @@ int32_t FakeEncoder::InitEncode(const VideoCodec* config, int32_t FakeEncoder::Encode(const VideoFrame& input_image, const CodecSpecificInfo* codec_specific_info, const std::vector* frame_types) { - RTC_DCHECK_GT(config_.maxFramerate, 0); - int64_t time_since_last_encode_ms = 1000 / config_.maxFramerate; + unsigned char max_framerate; + unsigned char num_simulcast_streams; + SimulcastStream simulcast_streams[kMaxSimulcastStreams]; + EncodedImageCallback* callback; + uint32_t target_bitrate_sum_kbps; + int max_target_bitrate_kbps; + int64_t last_encode_time_ms; + size_t num_encoded_bytes; + { + rtc::CritScope cs(&crit_sect_); + max_framerate = config_.maxFramerate; + num_simulcast_streams = config_.numberOfSimulcastStreams; + for (int i = 0; i < num_simulcast_streams; ++i) { + simulcast_streams[i] = config_.simulcastStream[i]; + } + callback = callback_; + target_bitrate_sum_kbps = target_bitrate_.get_sum_kbps(); + max_target_bitrate_kbps = max_target_bitrate_kbps_; + last_encode_time_ms = last_encode_time_ms_; + num_encoded_bytes = sizeof(encoded_buffer_); + } + int64_t time_now_ms = clock_->TimeInMilliseconds(); - const bool first_encode = last_encode_time_ms_ == 0; + const bool first_encode = (last_encode_time_ms == 0); + RTC_DCHECK_GT(max_framerate, 0); + int64_t time_since_last_encode_ms = 1000 / max_framerate; if (!first_encode) { // For all frames but the first we can estimate the display time by looking // at the display time of the previous frame. - time_since_last_encode_ms = time_now_ms - last_encode_time_ms_; + time_since_last_encode_ms = time_now_ms - last_encode_time_ms; } - if (time_since_last_encode_ms > 3 * 1000 / config_.maxFramerate) { + if (time_since_last_encode_ms > 3 * 1000 / max_framerate) { // Rudimentary check to make sure we don't widely overshoot bitrate target // when resuming encoding after a suspension. - time_since_last_encode_ms = 3 * 1000 / config_.maxFramerate; + time_since_last_encode_ms = 3 * 1000 / max_framerate; } - size_t bits_available = static_cast(target_bitrate_.get_sum_kbps() * - time_since_last_encode_ms); - size_t min_bits = static_cast( - config_.simulcastStream[0].minBitrate * time_since_last_encode_ms); + size_t bits_available = + static_cast(target_bitrate_sum_kbps * time_since_last_encode_ms); + size_t min_bits = static_cast(simulcast_streams[0].minBitrate * + time_since_last_encode_ms); + if (bits_available < min_bits) bits_available = min_bits; size_t max_bits = - static_cast(max_target_bitrate_kbps_ * time_since_last_encode_ms); + static_cast(max_target_bitrate_kbps * time_since_last_encode_ms); if (max_bits > 0 && max_bits < bits_available) bits_available = max_bits; - last_encode_time_ms_ = time_now_ms; - RTC_DCHECK_GT(config_.numberOfSimulcastStreams, 0); - for (unsigned char i = 0; i < config_.numberOfSimulcastStreams; ++i) { + { + rtc::CritScope cs(&crit_sect_); + last_encode_time_ms_ = time_now_ms; + } + + RTC_DCHECK_GT(num_simulcast_streams, 0); + for (unsigned char i = 0; i < num_simulcast_streams; ++i) { CodecSpecificInfo specifics; memset(&specifics, 0, sizeof(specifics)); specifics.codecType = kVideoCodecGeneric; specifics.codecSpecific.generic.simulcast_idx = i; size_t min_stream_bits = static_cast( - config_.simulcastStream[i].minBitrate * time_since_last_encode_ms); + simulcast_streams[i].minBitrate * time_since_last_encode_ms); size_t max_stream_bits = static_cast( - config_.simulcastStream[i].maxBitrate * time_since_last_encode_ms); + simulcast_streams[i].maxBitrate * time_since_last_encode_ms); size_t stream_bits = (bits_available > max_stream_bits) ? max_stream_bits : bits_available; size_t stream_bytes = (stream_bits + 7) / 8; @@ -96,23 +129,25 @@ int32_t FakeEncoder::Encode(const VideoFrame& input_image, // encodes so that it can compensate for oversized frames. stream_bytes *= 10; } - if (stream_bytes > sizeof(encoded_buffer_)) - stream_bytes = sizeof(encoded_buffer_); + if (stream_bytes > num_encoded_bytes) + stream_bytes = num_encoded_bytes; // Always encode something on the first frame. if (min_stream_bits > bits_available && i > 0) continue; - EncodedImage encoded( - encoded_buffer_, stream_bytes, sizeof(encoded_buffer_)); + + std::unique_ptr encoded_buffer(new uint8_t[num_encoded_bytes]); + memcpy(encoded_buffer.get(), encoded_buffer_, num_encoded_bytes); + EncodedImage encoded(encoded_buffer.get(), stream_bytes, num_encoded_bytes); encoded._timeStamp = input_image.timestamp(); encoded.capture_time_ms_ = input_image.render_time_ms(); encoded._frameType = (*frame_types)[i]; - encoded._encodedWidth = config_.simulcastStream[i].width; - encoded._encodedHeight = config_.simulcastStream[i].height; + encoded._encodedWidth = simulcast_streams[i].width; + encoded._encodedHeight = simulcast_streams[i].height; encoded.rotation_ = input_image.rotation(); - RTC_DCHECK(callback_ != NULL); specifics.codec_name = ImplementationName(); - if (callback_->OnEncodedImage(encoded, &specifics, NULL).error != + RTC_DCHECK(callback); + if (callback->OnEncodedImage(encoded, &specifics, nullptr).error != EncodedImageCallback::Result::OK) { return -1; } @@ -123,6 +158,7 @@ int32_t FakeEncoder::Encode(const VideoFrame& input_image, int32_t FakeEncoder::RegisterEncodeCompleteCallback( EncodedImageCallback* callback) { + rtc::CritScope cs(&crit_sect_); callback_ = callback; return 0; } @@ -135,6 +171,7 @@ int32_t FakeEncoder::SetChannelParameters(uint32_t packet_loss, int64_t rtt) { int32_t FakeEncoder::SetRateAllocation(const BitrateAllocation& rate_allocation, uint32_t framerate) { + rtc::CritScope cs(&crit_sect_); target_bitrate_ = rate_allocation; return 0; } @@ -145,12 +182,13 @@ const char* FakeEncoder::ImplementationName() const { } FakeH264Encoder::FakeH264Encoder(Clock* clock) - : FakeEncoder(clock), callback_(NULL), idr_counter_(0) { + : FakeEncoder(clock), callback_(nullptr), idr_counter_(0) { FakeEncoder::RegisterEncodeCompleteCallback(this); } int32_t FakeH264Encoder::RegisterEncodeCompleteCallback( EncodedImageCallback* callback) { + rtc::CritScope cs(&local_crit_sect_); callback_ = callback; return 0; } @@ -162,8 +200,16 @@ EncodedImageCallback::Result FakeH264Encoder::OnEncodedImage( const size_t kSpsSize = 8; const size_t kPpsSize = 11; const int kIdrFrequency = 10; + EncodedImageCallback* callback; + int current_idr_counter; + { + rtc::CritScope cs(&local_crit_sect_); + callback = callback_; + current_idr_counter = idr_counter_; + ++idr_counter_; + } RTPFragmentationHeader fragmentation; - if (idr_counter_++ % kIdrFrequency == 0 && + if (current_idr_counter % kIdrFrequency == 0 && encoded_image._length > kSpsSize + kPpsSize + 1) { const size_t kNumSlices = 3; fragmentation.VerifyAndAllocateFragmentationHeader(kNumSlices); @@ -203,7 +249,8 @@ EncodedImageCallback::Result FakeH264Encoder::OnEncodedImage( specifics.codecType = kVideoCodecH264; specifics.codecSpecific.H264.packetization_mode = H264PacketizationMode::NonInterleaved; - return callback_->OnEncodedImage(encoded_image, &specifics, &fragmentation); + RTC_DCHECK(callback); + return callback->OnEncodedImage(encoded_image, &specifics, &fragmentation); } DelayedEncoder::DelayedEncoder(Clock* clock, int delay_ms) @@ -211,7 +258,7 @@ DelayedEncoder::DelayedEncoder(Clock* clock, int delay_ms) delay_ms_(delay_ms) {} void DelayedEncoder::SetDelay(int delay_ms) { - rtc::CritScope lock(&lock_); + rtc::CritScope cs(&local_crit_sect_); delay_ms_ = delay_ms; } @@ -220,24 +267,24 @@ int32_t DelayedEncoder::Encode(const VideoFrame& input_image, const std::vector* frame_types) { int delay_ms = 0; { - rtc::CritScope lock(&lock_); + rtc::CritScope cs(&local_crit_sect_); delay_ms = delay_ms_; } SleepMs(delay_ms); return FakeEncoder::Encode(input_image, codec_specific_info, frame_types); } -MultiThreadedFakeH264Encoder::MultiThreadedFakeH264Encoder(Clock* clock) +MultithreadedFakeH264Encoder::MultithreadedFakeH264Encoder(Clock* clock) : test::FakeH264Encoder(clock), current_queue_(0), queue1_("Queue 1"), queue2_("Queue 2") {} -MultiThreadedFakeH264Encoder::~MultiThreadedFakeH264Encoder() = default; +MultithreadedFakeH264Encoder::~MultithreadedFakeH264Encoder() = default; -class MultiThreadedFakeH264Encoder::EncodeTask : public rtc::QueuedTask { +class MultithreadedFakeH264Encoder::EncodeTask : public rtc::QueuedTask { public: - EncodeTask(MultiThreadedFakeH264Encoder* encoder, + EncodeTask(MultithreadedFakeH264Encoder* encoder, const VideoFrame& input_image, const CodecSpecificInfo* codec_specific_info, const std::vector* frame_types) @@ -256,13 +303,13 @@ class MultiThreadedFakeH264Encoder::EncodeTask : public rtc::QueuedTask { return true; } - MultiThreadedFakeH264Encoder* const encoder_; + MultithreadedFakeH264Encoder* const encoder_; VideoFrame input_image_; CodecSpecificInfo codec_specific_info_; std::vector frame_types_; }; -int32_t MultiThreadedFakeH264Encoder::Encode( +int32_t MultithreadedFakeH264Encoder::Encode( const VideoFrame& input_image, const CodecSpecificInfo* codec_specific_info, const std::vector* frame_types) { @@ -275,7 +322,7 @@ int32_t MultiThreadedFakeH264Encoder::Encode( return 0; } -int32_t MultiThreadedFakeH264Encoder::EncodeCallback( +int32_t MultithreadedFakeH264Encoder::EncodeCallback( const VideoFrame& input_image, const CodecSpecificInfo* codec_specific_info, const std::vector* frame_types) { diff --git a/webrtc/test/fake_encoder.h b/webrtc/test/fake_encoder.h index b81a04b43f..39c3e3e67f 100644 --- a/webrtc/test/fake_encoder.h +++ b/webrtc/test/fake_encoder.h @@ -47,12 +47,13 @@ class FakeEncoder : public VideoEncoder { static const char* kImplementationName; protected: + rtc::CriticalSection crit_sect_; Clock* const clock_; - VideoCodec config_; - EncodedImageCallback* callback_; - BitrateAllocation target_bitrate_; - int max_target_bitrate_kbps_; - int64_t last_encode_time_ms_; + VideoCodec config_ GUARDED_BY(crit_sect_); + EncodedImageCallback* callback_ GUARDED_BY(crit_sect_); + BitrateAllocation target_bitrate_ GUARDED_BY(crit_sect_); + int max_target_bitrate_kbps_ GUARDED_BY(crit_sect_); + int64_t last_encode_time_ms_ GUARDED_BY(crit_sect_); uint8_t encoded_buffer_[100000]; }; @@ -69,8 +70,9 @@ class FakeH264Encoder : public FakeEncoder, public EncodedImageCallback { const RTPFragmentationHeader* fragments) override; private: - EncodedImageCallback* callback_; - int idr_counter_; + rtc::CriticalSection local_crit_sect_; + EncodedImageCallback* callback_ GUARDED_BY(local_crit_sect_); + int idr_counter_ GUARDED_BY(local_crit_sect_); }; class DelayedEncoder : public test::FakeEncoder { @@ -84,17 +86,17 @@ class DelayedEncoder : public test::FakeEncoder { const std::vector* frame_types) override; private: - rtc::CriticalSection lock_; - int delay_ms_ GUARDED_BY(&lock_); + rtc::CriticalSection local_crit_sect_; + int delay_ms_ GUARDED_BY(&local_crit_sect_); }; // This class implements a multi-threaded fake encoder by posting // FakeH264Encoder::Encode(.) tasks to |queue1_| and |queue2_|, in an // alternating fashion. -class MultiThreadedFakeH264Encoder : public test::FakeH264Encoder { +class MultithreadedFakeH264Encoder : public test::FakeH264Encoder { public: - MultiThreadedFakeH264Encoder(Clock* clock); - virtual ~MultiThreadedFakeH264Encoder() override; + explicit MultithreadedFakeH264Encoder(Clock* clock); + virtual ~MultithreadedFakeH264Encoder() override; int32_t Encode(const VideoFrame& input_image, const CodecSpecificInfo* codec_specific_info, diff --git a/webrtc/video/video_send_stream_tests.cc b/webrtc/video/video_send_stream_tests.cc index 12f2bda744..f6b7450473 100644 --- a/webrtc/video/video_send_stream_tests.cc +++ b/webrtc/video/video_send_stream_tests.cc @@ -449,9 +449,6 @@ class UlpfecObserver : public test::EndToEndTest { VideoSendStream::Config* send_config, std::vector* receive_configs, VideoEncoderConfig* encoder_config) override { - transport_adapter_.reset( - new internal::TransportAdapter(send_config->send_transport)); - transport_adapter_->Enable(); if (use_nack_) { send_config->rtp.nack.rtp_history_ms = (*receive_configs)[0].rtp.nack.rtp_history_ms = @@ -481,7 +478,6 @@ class UlpfecObserver : public test::EndToEndTest { << "Timed out waiting for ULPFEC and/or media packets."; } - std::unique_ptr transport_adapter_; VideoEncoder* const encoder_; std::string payload_name_; const bool use_nack_; @@ -538,9 +534,9 @@ TEST_F(VideoSendStreamTest, DoesUtilizeUlpfecForVp9WithNackEnabled) { } #endif // !defined(RTC_DISABLE_VP9) -TEST_F(VideoSendStreamTest, SupportsUlpfecWithMultiThreadedH264) { +TEST_F(VideoSendStreamTest, SupportsUlpfecWithMultithreadedH264) { std::unique_ptr encoder( - new test::MultiThreadedFakeH264Encoder(Clock::GetRealTimeClock())); + new test::MultithreadedFakeH264Encoder(Clock::GetRealTimeClock())); UlpfecObserver test(false, false, true, true, "H264", encoder.get()); RunBaseTest(&test); } @@ -606,9 +602,6 @@ class FlexfecObserver : public test::EndToEndTest { VideoSendStream::Config* send_config, std::vector* receive_configs, VideoEncoderConfig* encoder_config) override { - transport_adapter_.reset( - new internal::TransportAdapter(send_config->send_transport)); - transport_adapter_->Enable(); if (use_nack_) { send_config->rtp.nack.rtp_history_ms = (*receive_configs)[0].rtp.nack.rtp_history_ms = @@ -632,7 +625,6 @@ class FlexfecObserver : public test::EndToEndTest { << "Timed out waiting for FlexFEC and/or media packets."; } - std::unique_ptr transport_adapter_; VideoEncoder* const encoder_; std::string payload_name_; const bool use_nack_; @@ -687,9 +679,9 @@ TEST_F(VideoSendStreamTest, SupportsFlexfecWithNackH264) { RunBaseTest(&test); } -TEST_F(VideoSendStreamTest, SupportsFlexfecWithMultiThreadedH264) { +TEST_F(VideoSendStreamTest, SupportsFlexfecWithMultithreadedH264) { std::unique_ptr encoder( - new test::MultiThreadedFakeH264Encoder(Clock::GetRealTimeClock())); + new test::MultithreadedFakeH264Encoder(Clock::GetRealTimeClock())); FlexfecObserver test(false, false, "H264", encoder.get()); RunBaseTest(&test); } @@ -2639,8 +2631,13 @@ TEST_F(VideoSendStreamTest, ReportsSentResolution) { encoded._frameType = (*frame_types)[i]; encoded._encodedWidth = kEncodedResolution[i].width; encoded._encodedHeight = kEncodedResolution[i].height; - RTC_DCHECK(callback_); - if (callback_->OnEncodedImage(encoded, &specifics, nullptr).error != + EncodedImageCallback* callback; + { + rtc::CritScope cs(&crit_sect_); + callback = callback_; + } + RTC_DCHECK(callback); + if (callback->OnEncodedImage(encoded, &specifics, nullptr).error != EncodedImageCallback::Result::OK) { return -1; } diff --git a/webrtc/video/vie_encoder_unittest.cc b/webrtc/video/vie_encoder_unittest.cc index c42825d05c..a50f7aaf98 100644 --- a/webrtc/video/vie_encoder_unittest.cc +++ b/webrtc/video/vie_encoder_unittest.cc @@ -186,12 +186,12 @@ class ViEEncoderTest : public ::testing::Test { continue_encode_event_(false, false) {} VideoCodec codec_config() { - rtc::CritScope lock(&crit_); + rtc::CritScope lock(&crit_sect_); return config_; } void BlockNextEncode() { - rtc::CritScope lock(&crit_); + rtc::CritScope lock(&local_crit_sect_); block_next_encode_ = true; } @@ -203,7 +203,7 @@ class ViEEncoderTest : public ::testing::Test { void CheckLastTimeStampsMatch(int64_t ntp_time_ms, uint32_t timestamp) const { - rtc::CritScope lock(&crit_); + rtc::CritScope lock(&local_crit_sect_); EXPECT_EQ(timestamp_, timestamp); EXPECT_EQ(ntp_time_ms_, ntp_time_ms); } @@ -214,7 +214,7 @@ class ViEEncoderTest : public ::testing::Test { const std::vector* frame_types) override { bool block_encode; { - rtc::CritScope lock(&crit_); + rtc::CritScope lock(&local_crit_sect_); EXPECT_GT(input_image.timestamp(), timestamp_); EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_); EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90); @@ -233,7 +233,7 @@ class ViEEncoderTest : public ::testing::Test { return result; } - rtc::CriticalSection crit_; + rtc::CriticalSection local_crit_sect_; bool block_next_encode_ = false; rtc::Event continue_encode_event_; uint32_t timestamp_ = 0;