Commit 3d3751dc authored by Zijie He's avatar Zijie He Committed by Commit Bot

[Chromoting] Use WebrtcVideoEncoderSelector in WebrtcVideoStream

This change uses WebrtcVideoEncoderSelector to select a video encoder instead of
blindly select one based on SDP.

Bug: chromium:769391
Change-Id: I93db02a11b777a5c4b2aa1d19ac3938f29f42bca
Reviewed-on: https://chromium-review.googlesource.com/738891
Commit-Queue: Zijie He <zijiehe@chromium.org>
Reviewed-by: 's avatarLambros Lambrou <lambroslambrou@chromium.org>
Cr-Commit-Position: refs/heads/master@{#511922}
parent 37fd6d74
......@@ -23,6 +23,9 @@ namespace {
// there's no reason to have this set to anything greater than one.
const int kWebrtcVideoEncoderGpuOutputBufferCount = 1;
constexpr media::VideoCodecProfile kH264Profile =
media::VideoCodecProfile::H264PROFILE_MAIN;
void ArgbToI420(const webrtc::DesktopFrame& frame,
scoped_refptr<media::VideoFrame> video_frame) {
const uint8_t* rgb_data = frame.data();
......@@ -234,13 +237,40 @@ void WebrtcVideoEncoderGpu::RunAnyPendingEncode() {
}
// static
std::unique_ptr<WebrtcVideoEncoderGpu> WebrtcVideoEncoderGpu::CreateForH264() {
std::unique_ptr<WebrtcVideoEncoder> WebrtcVideoEncoderGpu::CreateForH264() {
DVLOG(3) << __func__;
LOG(WARNING) << "H264 video encoder is created.";
// HIGH profile requires Windows 8 or upper. Considering encoding latency,
// frame size and image quality, MAIN should be fine for us.
return base::WrapUnique(new WebrtcVideoEncoderGpu(
media::VideoCodecProfile::H264PROFILE_MAIN));
return base::WrapUnique(new WebrtcVideoEncoderGpu(kH264Profile));
}
// static
bool WebrtcVideoEncoderGpu::IsSupportedByH264(
const WebrtcVideoEncoderSelector::Profile& profile) {
media::VideoEncodeAccelerator::SupportedProfiles profiles =
media::GpuVideoEncodeAcceleratorFactory::GetSupportedProfiles(
gpu::GpuPreferences());
for (const auto& supported_profile : profiles) {
if (supported_profile.profile != kH264Profile) {
continue;
}
double supported_framerate = supported_profile.max_framerate_numerator;
supported_framerate /= supported_profile.max_framerate_denominator;
if (profile.frame_rate > supported_framerate) {
continue;
}
if (profile.resolution.GetArea() >
supported_profile.max_resolution.GetArea()) {
continue;
}
return true;
}
return false;
}
} // namespace remoting
......@@ -7,6 +7,7 @@
#include "media/video/video_encode_accelerator.h"
#include "remoting/codec/webrtc_video_encoder.h"
#include "remoting/codec/webrtc_video_encoder_selector.h"
namespace base {
class SharedMemory;
......@@ -34,7 +35,9 @@ namespace remoting {
class WebrtcVideoEncoderGpu : public WebrtcVideoEncoder,
public media::VideoEncodeAccelerator::Client {
public:
static std::unique_ptr<WebrtcVideoEncoderGpu> CreateForH264();
static std::unique_ptr<WebrtcVideoEncoder> CreateForH264();
static bool IsSupportedByH264(
const WebrtcVideoEncoderSelector::Profile& profile);
~WebrtcVideoEncoderGpu() override;
......
......@@ -238,15 +238,34 @@ void CreateImage(bool use_i444,
} // namespace
// static
std::unique_ptr<WebrtcVideoEncoderVpx> WebrtcVideoEncoderVpx::CreateForVP8() {
std::unique_ptr<WebrtcVideoEncoder> WebrtcVideoEncoderVpx::CreateForVP8() {
LOG(WARNING) << "VP8 video encoder is created.";
return base::WrapUnique(new WebrtcVideoEncoderVpx(false));
}
// static
std::unique_ptr<WebrtcVideoEncoderVpx> WebrtcVideoEncoderVpx::CreateForVP9() {
std::unique_ptr<WebrtcVideoEncoder> WebrtcVideoEncoderVpx::CreateForVP9() {
LOG(WARNING) << "VP9 video encoder is created.";
return base::WrapUnique(new WebrtcVideoEncoderVpx(true));
}
// See
// https://www.webmproject.org/about/faq/#what-are-the-limits-of-vp8-and-vp9-in-terms-of-resolution-datarate-and-framerate
// for the limitations of VP8 / VP9 encoders.
// static
bool WebrtcVideoEncoderVpx::IsSupportedByVP8(
const WebrtcVideoEncoderSelector::Profile& profile) {
return profile.resolution.width() <= 16384 &&
profile.resolution.height() <= 16384;
}
// static
bool WebrtcVideoEncoderVpx::IsSupportedByVP9(
const WebrtcVideoEncoderSelector::Profile& profile) {
return profile.resolution.width() <= 65536 &&
profile.resolution.height() <= 65536;
}
WebrtcVideoEncoderVpx::~WebrtcVideoEncoderVpx() {}
void WebrtcVideoEncoderVpx::SetTickClockForTests(base::TickClock* tick_clock) {
......
......@@ -13,6 +13,7 @@
#include "base/time/time.h"
#include "remoting/codec/scoped_vpx_codec.h"
#include "remoting/codec/webrtc_video_encoder.h"
#include "remoting/codec/webrtc_video_encoder_selector.h"
#include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h"
typedef struct vpx_image vpx_image_t;
......@@ -29,9 +30,15 @@ namespace remoting {
// once the old implementation is no longer in use.
class WebrtcVideoEncoderVpx : public WebrtcVideoEncoder {
public:
// Create encoder for the specified protocol.
static std::unique_ptr<WebrtcVideoEncoderVpx> CreateForVP8();
static std::unique_ptr<WebrtcVideoEncoderVpx> CreateForVP9();
// Creates encoder for the specified protocol.
static std::unique_ptr<WebrtcVideoEncoder> CreateForVP8();
static std::unique_ptr<WebrtcVideoEncoder> CreateForVP9();
// Checks the support for the specified protocol.
static bool IsSupportedByVP8(
const WebrtcVideoEncoderSelector::Profile& profile);
static bool IsSupportedByVP9(
const WebrtcVideoEncoderSelector::Profile& profile);
~WebrtcVideoEncoderVpx() override;
......
......@@ -6,6 +6,7 @@
#include <utility>
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "build/build_config.h"
......@@ -66,7 +67,19 @@ struct WebrtcVideoStream::FrameStats {
};
WebrtcVideoStream::WebrtcVideoStream()
: video_stats_dispatcher_(kStreamLabel), weak_factory_(this) {}
: video_stats_dispatcher_(kStreamLabel), weak_factory_(this) {
encoder_selector_.RegisterEncoder(
base::Bind(&WebrtcVideoEncoderVpx::IsSupportedByVP8),
base::Bind(&WebrtcVideoEncoderVpx::CreateForVP8));
encoder_selector_.RegisterEncoder(
base::Bind(&WebrtcVideoEncoderVpx::IsSupportedByVP9),
base::Bind(&WebrtcVideoEncoderVpx::CreateForVP9));
#if defined(USE_H264_ENCODER)
encoder_selector_.RegisterEncoder(
base::Bind(&WebrtcVideoEncoderGpu::IsSupportedByH264),
base::Bind(&WebrtcVideoEncoderGpu::CreateForH264));
#endif
}
WebrtcVideoStream::~WebrtcVideoStream() {
DCHECK(thread_checker_.CalledOnValidThread());
......@@ -187,13 +200,22 @@ void WebrtcVideoStream::OnCaptureResult(
}
current_frame_stats_->capturer_id = frame->capturer_id();
if (!encoder_) {
encoder_selector_.SetDesktopFrame(*frame);
encoder_ = encoder_selector_.CreateEncoder();
// TODO(zijiehe): Permanently stop the video stream if we cannot create an
// encoder for the |frame|.
}
}
DCHECK(encoder_);
current_frame_stats_->encode_started_time = base::TimeTicks::Now();
encoder_->Encode(
std::move(frame), frame_params,
base::Bind(&WebrtcVideoStream::OnFrameEncoded, base::Unretained(this)));
if (encoder_) {
current_frame_stats_->encode_started_time = base::TimeTicks::Now();
encoder_->Encode(
std::move(frame), frame_params,
base::Bind(&WebrtcVideoStream::OnFrameEncoded, base::Unretained(this)));
}
}
void WebrtcVideoStream::OnChannelInitialized(
......@@ -228,10 +250,10 @@ void WebrtcVideoStream::OnFrameEncoded(
scheduler_->OnFrameEncoded(frame.get(), &stats);
if (encode_result != WebrtcVideoEncoder::EncodeResult::SUCCEEDED) {
// TODO(zijiehe): If |encode_result| is an unrecoverable error, we should
// restart the stream and select a different encoder.
LOG(ERROR) << "Video encoder returns error "
<< EncodeResultToString(encode_result);
// TODO(zijiehe): Restart the video stream.
encoder_.reset();
return;
}
......@@ -282,19 +304,18 @@ void WebrtcVideoStream::OnFrameEncoded(
void WebrtcVideoStream::OnEncoderCreated(webrtc::VideoCodecType codec_type) {
DCHECK(thread_checker_.CalledOnValidThread());
// The preferred codec id depends on the order of
// |encoder_selector_|.RegisterEncoder().
if (codec_type == webrtc::kVideoCodecVP8) {
LOG(ERROR) << "Using VP8 video codec.";
encoder_ = base::MakeUnique<WebrtcVideoEncoderProxy>(
WebrtcVideoEncoderVpx::CreateForVP8(), encode_task_runner_);
LOG(WARNING) << "VP8 video codec is preferred.";
encoder_selector_.SetPreferredCodec(0);
} else if (codec_type == webrtc::kVideoCodecVP9) {
LOG(ERROR) << "Using VP9 video codec.";
encoder_ = base::MakeUnique<WebrtcVideoEncoderProxy>(
WebrtcVideoEncoderVpx::CreateForVP9(), encode_task_runner_);
LOG(WARNING) << "VP9 video codec is preferred.";
encoder_selector_.SetPreferredCodec(1);
} else if (codec_type == webrtc::kVideoCodecH264) {
#if defined(USE_H264_ENCODER)
LOG(ERROR) << "Using H264 video codec.";
encoder_ = base::MakeUnique<WebrtcVideoEncoderProxy>(
WebrtcVideoEncoderGpu::CreateForH264(), encode_task_runner_);
LOG(WARNING) << "H264 video codec is preferred.";
encoder_selector_.SetPreferredCodec(2);
#else
NOTIMPLEMENTED();
#endif
......
......@@ -16,6 +16,7 @@
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "remoting/codec/webrtc_video_encoder.h"
#include "remoting/codec/webrtc_video_encoder_selector.h"
#include "remoting/protocol/host_video_stats_dispatcher.h"
#include "remoting/protocol/video_stream.h"
#include "third_party/webrtc/common_types.h"
......@@ -96,6 +97,8 @@ class WebrtcVideoStream : public VideoStream,
webrtc::DesktopVector frame_dpi_;
Observer* observer_ = nullptr;
WebrtcVideoEncoderSelector encoder_selector_;
base::ThreadChecker thread_checker_;
base::WeakPtrFactory<WebrtcVideoStream> weak_factory_;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment