Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(502)

Unified Diff: webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.cc

Issue 2964953002: Remove webrtc::VideoEncoderFactory (Closed)
Patch Set: Add dep to base:sequenced_task_checker Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.cc
diff --git a/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.cc b/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.cc
deleted file mode 100644
index dbf8b258ecdb84ce43a61654e7fbdbc62d1ab6cd..0000000000000000000000000000000000000000
--- a/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.cc
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * 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/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.h"
-
-#include <algorithm>
-
-// NOTE(ajm): Path provided by gyp.
-#include "libyuv/scale.h" // NOLINT
-
-#include "webrtc/api/video/i420_buffer.h"
-#include "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h"
-#include "webrtc/modules/video_coding/codecs/vp8/simulcast_rate_allocator.h"
-#include "webrtc/rtc_base/checks.h"
-#include "webrtc/system_wrappers/include/clock.h"
-
-namespace {
-
-const unsigned int kDefaultMinQp = 2;
-const unsigned int kDefaultMaxQp = 56;
-// Max qp for lowest spatial resolution when doing simulcast.
-const unsigned int kLowestResMaxQp = 45;
-
-uint32_t SumStreamMaxBitrate(int streams, const webrtc::VideoCodec& codec) {
- uint32_t bitrate_sum = 0;
- for (int i = 0; i < streams; ++i) {
- bitrate_sum += codec.simulcastStream[i].maxBitrate;
- }
- return bitrate_sum;
-}
-
-int NumberOfStreams(const webrtc::VideoCodec& codec) {
- int streams =
- codec.numberOfSimulcastStreams < 1 ? 1 : codec.numberOfSimulcastStreams;
- uint32_t simulcast_max_bitrate = SumStreamMaxBitrate(streams, codec);
- if (simulcast_max_bitrate == 0) {
- streams = 1;
- }
- return streams;
-}
-
-bool ValidSimulcastResolutions(const webrtc::VideoCodec& codec,
- int num_streams) {
- if (codec.width != codec.simulcastStream[num_streams - 1].width ||
- codec.height != codec.simulcastStream[num_streams - 1].height) {
- return false;
- }
- for (int i = 0; i < num_streams; ++i) {
- if (codec.width * codec.simulcastStream[i].height !=
- codec.height * codec.simulcastStream[i].width) {
- return false;
- }
- }
- return true;
-}
-
-int VerifyCodec(const webrtc::VideoCodec* inst) {
- if (inst == nullptr) {
- return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
- }
- if (inst->maxFramerate < 1) {
- return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
- }
- // allow zero to represent an unspecified maxBitRate
- if (inst->maxBitrate > 0 && inst->startBitrate > inst->maxBitrate) {
- return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
- }
- if (inst->width <= 1 || inst->height <= 1) {
- return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
- }
- if (inst->VP8().automaticResizeOn && inst->numberOfSimulcastStreams > 1) {
- return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
- }
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-// An EncodedImageCallback implementation that forwards on calls to a
-// SimulcastEncoderAdapter, but with the stream index it's registered with as
-// the first parameter to Encoded.
-class AdapterEncodedImageCallback : public webrtc::EncodedImageCallback {
- public:
- AdapterEncodedImageCallback(webrtc::SimulcastEncoderAdapter* adapter,
- size_t stream_idx)
- : adapter_(adapter), stream_idx_(stream_idx) {}
-
- EncodedImageCallback::Result OnEncodedImage(
- const webrtc::EncodedImage& encoded_image,
- const webrtc::CodecSpecificInfo* codec_specific_info,
- const webrtc::RTPFragmentationHeader* fragmentation) override {
- return adapter_->OnEncodedImage(stream_idx_, encoded_image,
- codec_specific_info, fragmentation);
- }
-
- private:
- webrtc::SimulcastEncoderAdapter* const adapter_;
- const size_t stream_idx_;
-};
-
-// Utility class used to adapt the simulcast id as reported by the temporal
-// layers factory, since each sub-encoder will report stream 0.
-class TemporalLayersFactoryAdapter : public webrtc::TemporalLayersFactory {
- public:
- TemporalLayersFactoryAdapter(int adapted_simulcast_id,
- const TemporalLayersFactory& tl_factory)
- : adapted_simulcast_id_(adapted_simulcast_id), tl_factory_(tl_factory) {}
- ~TemporalLayersFactoryAdapter() override {}
- webrtc::TemporalLayers* Create(int simulcast_id,
- int temporal_layers,
- uint8_t initial_tl0_pic_idx) const override {
- return tl_factory_.Create(adapted_simulcast_id_, temporal_layers,
- initial_tl0_pic_idx);
- }
-
- const int adapted_simulcast_id_;
- const TemporalLayersFactory& tl_factory_;
-};
-
-} // namespace
-
-namespace webrtc {
-
-SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory)
- : inited_(0),
- factory_(factory),
- encoded_complete_callback_(nullptr),
- implementation_name_("SimulcastEncoderAdapter") {
- // The adapter is typically created on the worker thread, but operated on
- // the encoder task queue.
- encoder_queue_.Detach();
-
- memset(&codec_, 0, sizeof(webrtc::VideoCodec));
-}
-
-SimulcastEncoderAdapter::~SimulcastEncoderAdapter() {
- RTC_DCHECK(!Initialized());
- DestroyStoredEncoders();
-}
-
-int SimulcastEncoderAdapter::Release() {
- RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
-
- while (!streaminfos_.empty()) {
- VideoEncoder* encoder = streaminfos_.back().encoder;
- encoder->Release();
- // Even though it seems very unlikely, there are no guarantees that the
- // encoder will not call back after being Release()'d. Therefore, we disable
- // the callbacks here.
- encoder->RegisterEncodeCompleteCallback(nullptr);
- streaminfos_.pop_back(); // Deletes callback adapter.
- stored_encoders_.push(encoder);
- }
-
- // It's legal to move the encoder to another queue now.
- encoder_queue_.Detach();
-
- rtc::AtomicOps::ReleaseStore(&inited_, 0);
-
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-int SimulcastEncoderAdapter::InitEncode(const VideoCodec* inst,
- int number_of_cores,
- size_t max_payload_size) {
- RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
-
- if (number_of_cores < 1) {
- return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
- }
-
- int ret = VerifyCodec(inst);
- if (ret < 0) {
- return ret;
- }
-
- ret = Release();
- if (ret < 0) {
- return ret;
- }
-
- int number_of_streams = NumberOfStreams(*inst);
- RTC_DCHECK_LE(number_of_streams, kMaxSimulcastStreams);
- const bool doing_simulcast = (number_of_streams > 1);
-
- if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) {
- return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
- }
-
- codec_ = *inst;
- SimulcastRateAllocator rate_allocator(codec_, nullptr);
- BitrateAllocation allocation = rate_allocator.GetAllocation(
- codec_.startBitrate * 1000, codec_.maxFramerate);
- std::vector<uint32_t> start_bitrates;
- for (int i = 0; i < kMaxSimulcastStreams; ++i) {
- uint32_t stream_bitrate = allocation.GetSpatialLayerSum(i) / 1000;
- start_bitrates.push_back(stream_bitrate);
- }
-
- std::string implementation_name;
- // Create |number_of_streams| of encoder instances and init them.
- for (int i = 0; i < number_of_streams; ++i) {
- VideoCodec stream_codec;
- uint32_t start_bitrate_kbps = start_bitrates[i];
- if (!doing_simulcast) {
- stream_codec = codec_;
- stream_codec.numberOfSimulcastStreams = 1;
- } else {
- // Cap start bitrate to the min bitrate in order to avoid strange codec
- // behavior. Since sending sending will be false, this should not matter.
- start_bitrate_kbps =
- std::max(codec_.simulcastStream[i].minBitrate, start_bitrate_kbps);
- bool highest_resolution_stream = (i == (number_of_streams - 1));
- PopulateStreamCodec(codec_, i, start_bitrate_kbps,
- highest_resolution_stream, &stream_codec);
- }
- TemporalLayersFactoryAdapter tl_factory_adapter(i,
- *codec_.VP8()->tl_factory);
- stream_codec.VP8()->tl_factory = &tl_factory_adapter;
-
- // TODO(ronghuawu): Remove once this is handled in VP8EncoderImpl.
- if (stream_codec.qpMax < kDefaultMinQp) {
- stream_codec.qpMax = kDefaultMaxQp;
- }
-
- // If an existing encoder instance exists, reuse it.
- // TODO(brandtr): Set initial RTP state (e.g., picture_id/tl0_pic_idx) here,
- // when we start storing that state outside the encoder wrappers.
- VideoEncoder* encoder;
- if (!stored_encoders_.empty()) {
- encoder = stored_encoders_.top();
- stored_encoders_.pop();
- } else {
- encoder = factory_->Create();
- }
-
- ret = encoder->InitEncode(&stream_codec, number_of_cores, max_payload_size);
- if (ret < 0) {
- // Explicitly destroy the current encoder; because we haven't registered a
- // StreamInfo for it yet, Release won't do anything about it.
- factory_->Destroy(encoder);
- Release();
- return ret;
- }
- std::unique_ptr<EncodedImageCallback> callback(
- new AdapterEncodedImageCallback(this, i));
- encoder->RegisterEncodeCompleteCallback(callback.get());
- streaminfos_.emplace_back(encoder, std::move(callback), stream_codec.width,
- stream_codec.height, start_bitrate_kbps > 0);
-
- if (i != 0) {
- implementation_name += ", ";
- }
- implementation_name += streaminfos_[i].encoder->ImplementationName();
- }
-
- if (doing_simulcast) {
- implementation_name_ =
- "SimulcastEncoderAdapter (" + implementation_name + ")";
- } else {
- implementation_name_ = implementation_name;
- }
-
- // To save memory, don't store encoders that we don't use.
- DestroyStoredEncoders();
-
- rtc::AtomicOps::ReleaseStore(&inited_, 1);
-
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-int SimulcastEncoderAdapter::Encode(
- const VideoFrame& input_image,
- const CodecSpecificInfo* codec_specific_info,
- const std::vector<FrameType>* frame_types) {
- RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
-
- if (!Initialized()) {
- return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
- }
- if (encoded_complete_callback_ == nullptr) {
- return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
- }
-
- // All active streams should generate a key frame if
- // a key frame is requested by any stream.
- bool send_key_frame = false;
- if (frame_types) {
- for (size_t i = 0; i < frame_types->size(); ++i) {
- if (frame_types->at(i) == kVideoFrameKey) {
- send_key_frame = true;
- break;
- }
- }
- }
- for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
- if (streaminfos_[stream_idx].key_frame_request &&
- streaminfos_[stream_idx].send_stream) {
- send_key_frame = true;
- break;
- }
- }
-
- int src_width = input_image.width();
- int src_height = input_image.height();
- for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
- // Don't encode frames in resolutions that we don't intend to send.
- if (!streaminfos_[stream_idx].send_stream) {
- continue;
- }
-
- std::vector<FrameType> stream_frame_types;
- if (send_key_frame) {
- stream_frame_types.push_back(kVideoFrameKey);
- streaminfos_[stream_idx].key_frame_request = false;
- } else {
- stream_frame_types.push_back(kVideoFrameDelta);
- }
-
- int dst_width = streaminfos_[stream_idx].width;
- int dst_height = streaminfos_[stream_idx].height;
- // If scaling isn't required, because the input resolution
- // matches the destination or the input image is empty (e.g.
- // a keyframe request for encoders with internal camera
- // sources) or the source image has a native handle, pass the image on
- // directly. Otherwise, we'll scale it to match what the encoder expects
- // (below).
- // For texture frames, the underlying encoder is expected to be able to
- // correctly sample/scale the source texture.
- // TODO(perkj): ensure that works going forward, and figure out how this
- // affects webrtc:5683.
- if ((dst_width == src_width && dst_height == src_height) ||
- input_image.video_frame_buffer()->type() ==
- VideoFrameBuffer::Type::kNative) {
- int ret = streaminfos_[stream_idx].encoder->Encode(
- input_image, codec_specific_info, &stream_frame_types);
- if (ret != WEBRTC_VIDEO_CODEC_OK) {
- return ret;
- }
- } else {
- rtc::scoped_refptr<I420Buffer> dst_buffer =
- I420Buffer::Create(dst_width, dst_height);
- rtc::scoped_refptr<I420BufferInterface> src_buffer =
- input_image.video_frame_buffer()->ToI420();
- libyuv::I420Scale(src_buffer->DataY(), src_buffer->StrideY(),
- src_buffer->DataU(), src_buffer->StrideU(),
- src_buffer->DataV(), src_buffer->StrideV(), src_width,
- src_height, dst_buffer->MutableDataY(),
- dst_buffer->StrideY(), dst_buffer->MutableDataU(),
- dst_buffer->StrideU(), dst_buffer->MutableDataV(),
- dst_buffer->StrideV(), dst_width, dst_height,
- libyuv::kFilterBilinear);
-
- int ret = streaminfos_[stream_idx].encoder->Encode(
- VideoFrame(dst_buffer, input_image.timestamp(),
- input_image.render_time_ms(), webrtc::kVideoRotation_0),
- codec_specific_info, &stream_frame_types);
- if (ret != WEBRTC_VIDEO_CODEC_OK) {
- return ret;
- }
- }
- }
-
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-int SimulcastEncoderAdapter::RegisterEncodeCompleteCallback(
- EncodedImageCallback* callback) {
- RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
- encoded_complete_callback_ = callback;
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-int SimulcastEncoderAdapter::SetChannelParameters(uint32_t packet_loss,
- int64_t rtt) {
- RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
- for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
- streaminfos_[stream_idx].encoder->SetChannelParameters(packet_loss, rtt);
- }
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-int SimulcastEncoderAdapter::SetRateAllocation(const BitrateAllocation& bitrate,
- uint32_t new_framerate) {
- RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
-
- if (!Initialized()) {
- return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
- }
-
- if (new_framerate < 1) {
- return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
- }
-
- if (codec_.maxBitrate > 0 && bitrate.get_sum_kbps() > codec_.maxBitrate) {
- return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
- }
-
- if (bitrate.get_sum_bps() > 0) {
- // Make sure the bitrate fits the configured min bitrates. 0 is a special
- // value that means paused, though, so leave it alone.
- if (bitrate.get_sum_kbps() < codec_.minBitrate) {
- return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
- }
-
- if (codec_.numberOfSimulcastStreams > 0 &&
- bitrate.get_sum_kbps() < codec_.simulcastStream[0].minBitrate) {
- return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
- }
- }
-
- codec_.maxFramerate = new_framerate;
-
- for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
- uint32_t stream_bitrate_kbps =
- bitrate.GetSpatialLayerSum(stream_idx) / 1000;
-
- // Need a key frame if we have not sent this stream before.
- if (stream_bitrate_kbps > 0 && !streaminfos_[stream_idx].send_stream) {
- streaminfos_[stream_idx].key_frame_request = true;
- }
- streaminfos_[stream_idx].send_stream = stream_bitrate_kbps > 0;
-
- // Slice the temporal layers out of the full allocation and pass it on to
- // the encoder handling the current simulcast stream.
- BitrateAllocation stream_allocation;
- for (int i = 0; i < kMaxTemporalStreams; ++i) {
- stream_allocation.SetBitrate(0, i, bitrate.GetBitrate(stream_idx, i));
- }
- streaminfos_[stream_idx].encoder->SetRateAllocation(stream_allocation,
- new_framerate);
- }
-
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-// TODO(brandtr): Add task checker to this member function, when all encoder
-// callbacks are coming in on the encoder queue.
-EncodedImageCallback::Result SimulcastEncoderAdapter::OnEncodedImage(
- size_t stream_idx,
- const EncodedImage& encodedImage,
- const CodecSpecificInfo* codecSpecificInfo,
- const RTPFragmentationHeader* fragmentation) {
- CodecSpecificInfo stream_codec_specific = *codecSpecificInfo;
- stream_codec_specific.codec_name = implementation_name_.c_str();
- CodecSpecificInfoVP8* vp8Info = &(stream_codec_specific.codecSpecific.VP8);
- vp8Info->simulcastIdx = stream_idx;
-
- return encoded_complete_callback_->OnEncodedImage(
- encodedImage, &stream_codec_specific, fragmentation);
-}
-
-void SimulcastEncoderAdapter::PopulateStreamCodec(
- const webrtc::VideoCodec& inst,
- int stream_index,
- uint32_t start_bitrate_kbps,
- bool highest_resolution_stream,
- webrtc::VideoCodec* stream_codec) {
- *stream_codec = inst;
-
- // Stream specific settings.
- stream_codec->VP8()->numberOfTemporalLayers =
- inst.simulcastStream[stream_index].numberOfTemporalLayers;
- stream_codec->numberOfSimulcastStreams = 0;
- stream_codec->width = inst.simulcastStream[stream_index].width;
- stream_codec->height = inst.simulcastStream[stream_index].height;
- stream_codec->maxBitrate = inst.simulcastStream[stream_index].maxBitrate;
- stream_codec->minBitrate = inst.simulcastStream[stream_index].minBitrate;
- stream_codec->qpMax = inst.simulcastStream[stream_index].qpMax;
- // Settings that are based on stream/resolution.
- const bool lowest_resolution_stream = (stream_index == 0);
- if (lowest_resolution_stream) {
- // Settings for lowest spatial resolutions.
- stream_codec->qpMax = kLowestResMaxQp;
- }
- if (!highest_resolution_stream) {
- // For resolutions below CIF, set the codec |complexity| parameter to
- // kComplexityHigher, which maps to cpu_used = -4.
- int pixels_per_frame = stream_codec->width * stream_codec->height;
- if (pixels_per_frame < 352 * 288) {
- stream_codec->VP8()->complexity = webrtc::kComplexityHigher;
- }
- // Turn off denoising for all streams but the highest resolution.
- stream_codec->VP8()->denoisingOn = false;
- }
- // TODO(ronghuawu): what to do with targetBitrate.
-
- stream_codec->startBitrate = start_bitrate_kbps;
-}
-
-bool SimulcastEncoderAdapter::Initialized() const {
- return rtc::AtomicOps::AcquireLoad(&inited_) == 1;
-}
-
-void SimulcastEncoderAdapter::DestroyStoredEncoders() {
- while (!stored_encoders_.empty()) {
- VideoEncoder* encoder = stored_encoders_.top();
- factory_->Destroy(encoder);
- stored_encoders_.pop();
- }
-}
-
-bool SimulcastEncoderAdapter::SupportsNativeHandle() const {
- RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
- // We should not be calling this method before streaminfos_ are configured.
- RTC_DCHECK(!streaminfos_.empty());
- for (const auto& streaminfo : streaminfos_) {
- if (!streaminfo.encoder->SupportsNativeHandle()) {
- return false;
- }
- }
- return true;
-}
-
-VideoEncoder::ScalingSettings SimulcastEncoderAdapter::GetScalingSettings()
- const {
- // TODO(brandtr): Investigate why the sequence checker below fails on mac.
- // RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
- // Turn off quality scaling for simulcast.
- if (!Initialized() || NumberOfStreams(codec_) != 1) {
- return VideoEncoder::ScalingSettings(false);
- }
- return streaminfos_[0].encoder->GetScalingSettings();
-}
-
-const char* SimulcastEncoderAdapter::ImplementationName() const {
- RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
- return implementation_name_.c_str();
-}
-
-} // namespace webrtc

Powered by Google App Engine
This is Rietveld 408576698