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

Unified Diff: extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc

Issue 1900233004: [chrome.displaySource] Implement software based H.264 video encoder. (Closed) Base URL: https://chromium.googlesource.com/chromium/src@master
Patch Set: Check proprietary_codecs Created 4 years, 8 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
« no previous file with comments | « extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc
diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc b/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3a62e907ab1cd285335187be7eb3cc3d82d4c2c8
--- /dev/null
+++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc
@@ -0,0 +1,208 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/task_runner_util.h"
+#include "base/thread_task_runner_handle.h"
+#include "extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder.h"
+#include "third_party/openh264/src/codec/api/svc/codec_api.h"
+#include "third_party/openh264/src/codec/api/svc/codec_app_def.h"
+#include "third_party/openh264/src/codec/api/svc/codec_def.h"
+
+namespace extensions {
+
+namespace {
+
+size_t CalculateLayerBitStreamLength(const SLayerBSInfo& layer_info) {
+ size_t length = 0u;
+ for (int i = 0; i < layer_info.iNalCount; ++i)
+ length += static_cast<size_t>(layer_info.pNalLengthInByte[i]);
+ return length;
+}
+
+size_t CalculateFrameBitStreamLength(const SFrameBSInfo& frame_info) {
+ size_t length = 0u;
+ for (int i = 0; i < frame_info.iLayerNum; ++i)
+ length += CalculateLayerBitStreamLength(frame_info.sLayerInfo[i]);
+ return length;
+}
+
+// This video encoder implements software H.264 video encoding using OpenH264
+// library.
+class WiFiDisplayVideoEncoderSVC final : public WiFiDisplayVideoEncoder {
+ public:
+ static void Create(const InitParameters& params,
+ const VideoEncoderCallback& encoder_callback);
+
+ private:
+ WiFiDisplayVideoEncoderSVC(
+ scoped_refptr<base::SingleThreadTaskRunner> client_task_runner,
+ std::unique_ptr<base::Thread> media_thread);
+ ~WiFiDisplayVideoEncoderSVC() override;
+
+ scoped_refptr<WiFiDisplayVideoEncoder> InitOnMediaThread(
+ const InitParameters& params);
+ void InsertFrameOnMediaThread(scoped_refptr<media::VideoFrame> video_frame,
+ base::TimeTicks reference_time,
+ bool send_idr) override;
+
+ scoped_refptr<base::SingleThreadTaskRunner> client_task_runner_;
+ std::unique_ptr<base::Thread> media_thread_;
+ ISVCEncoder* openh264_encoder_;
+ base::TimeTicks start_time_;
+};
+
+// static
+void WiFiDisplayVideoEncoderSVC::Create(
+ const InitParameters& params,
+ const VideoEncoderCallback& encoder_callback) {
+ // TODO(e_hakkinen): Use normal media thread once it is exposed to extensions
+ // and can be passed to this class.
+ std::unique_ptr<base::Thread> media_thread(
+ new base::Thread("WiFiDisplaySVCMedia"));
+ media_thread->Start();
+
+ base::PostTaskAndReplyWithResult(
+ media_thread->task_runner().get(), FROM_HERE,
+ base::Bind(
+ &WiFiDisplayVideoEncoderSVC::InitOnMediaThread,
+ make_scoped_refptr(new WiFiDisplayVideoEncoderSVC(
+ base::ThreadTaskRunnerHandle::Get(), std::move(media_thread))),
+ params),
+ encoder_callback);
+}
+
+WiFiDisplayVideoEncoderSVC::WiFiDisplayVideoEncoderSVC(
+ scoped_refptr<base::SingleThreadTaskRunner> client_task_runner,
+ std::unique_ptr<base::Thread> media_thread)
+ : WiFiDisplayVideoEncoder(media_thread->task_runner()),
+ client_task_runner_(std::move(client_task_runner)),
+ media_thread_(std::move(media_thread)),
+ openh264_encoder_(nullptr) {}
+
+WiFiDisplayVideoEncoderSVC::~WiFiDisplayVideoEncoderSVC() {
+ if (openh264_encoder_) {
+ if (int err = openh264_encoder_->Uninitialize()) {
+ DVLOG(1) << "Failed to uninit OpenH264 encoder: error=" << err;
+ }
+ WelsDestroySVCEncoder(openh264_encoder_);
+ }
+ client_task_runner_->DeleteSoon(FROM_HERE, media_thread_.release());
+}
+
+scoped_refptr<WiFiDisplayVideoEncoder>
+WiFiDisplayVideoEncoderSVC::InitOnMediaThread(const InitParameters& params) {
+ DCHECK(!openh264_encoder_);
+
+ if (int err = WelsCreateSVCEncoder(&openh264_encoder_)) {
+ DVLOG(1) << "Failed to create OpenH264 encoder: error=" << err;
+ return nullptr;
+ }
+
+ SEncParamExt svc_params;
+ if (int err = openh264_encoder_->GetDefaultParams(&svc_params)) {
+ DVLOG(1) << "Failed to get default OpenH264 parameters: error=" << err;
+ return nullptr;
+ }
+
+ svc_params.fMaxFrameRate = params.frame_rate;
+ svc_params.iPicHeight = params.frame_size.height();
+ svc_params.iPicWidth = params.frame_size.width();
+ svc_params.iTargetBitrate = params.bit_rate;
+ svc_params.iUsageType = SCREEN_CONTENT_REAL_TIME;
+ svc_params.sSpatialLayers[0].fFrameRate = svc_params.fMaxFrameRate;
+ svc_params.sSpatialLayers[0].iMaxSpatialBitrate = svc_params.iTargetBitrate;
+ svc_params.sSpatialLayers[0].iSpatialBitrate = svc_params.iTargetBitrate;
+ svc_params.sSpatialLayers[0].iVideoHeight = svc_params.iPicHeight;
+ svc_params.sSpatialLayers[0].iVideoWidth = svc_params.iPicWidth;
+
+ if (int err = openh264_encoder_->InitializeExt(&svc_params)) {
+ DVLOG(1) << "Failed to init OpenH264 encoder: error=" << err;
+ return nullptr;
+ }
+
+ int video_format = EVideoFormatType::videoFormatI420;
+ if (int err = openh264_encoder_->SetOption(ENCODER_OPTION_DATAFORMAT,
+ &video_format)) {
+ DVLOG(1) << "Failed to set data format for OpenH264 encoder: error=" << err;
+ return nullptr;
+ }
+
+ return this;
+}
+
+void WiFiDisplayVideoEncoderSVC::InsertFrameOnMediaThread(
+ scoped_refptr<media::VideoFrame> video_frame,
+ base::TimeTicks reference_time,
+ bool send_idr) {
+ DCHECK_EQ(media::PIXEL_FORMAT_I420, video_frame->format());
+
+ if (start_time_.is_null())
+ start_time_ = reference_time;
+
+ SSourcePicture picture;
+ std::memset(&picture, 0, sizeof(picture));
+ picture.iColorFormat = EVideoFormatType::videoFormatI420;
+ picture.iPicHeight = video_frame->coded_size().height();
+ picture.iPicWidth = video_frame->coded_size().width();
+ picture.uiTimeStamp = (reference_time - start_time_).InMilliseconds();
+ for (size_t plane_count = video_frame->NumPlanes(video_frame->format()),
+ plane = 0u;
+ plane < plane_count; ++plane) {
+ picture.pData[plane] = video_frame->data(plane);
+ picture.iStride[plane] = video_frame->stride(plane);
+ }
+
+ if (send_idr) {
+ if (int err = openh264_encoder_->ForceIntraFrame(true)) {
+ DVLOG(1) << "Failed to force intra frame using OpenH264 encoder: error="
+ << err;
+ }
+ }
+
+ SFrameBSInfo info;
+ std::memset(&info, 0, sizeof(info));
+ if (int err = openh264_encoder_->EncodeFrame(&picture, &info)) {
+ DVLOG(1) << "Failed to encode frame using OpenH264 encoder: error=" << err;
+ return;
+ }
+
+ if (encoded_callback_.is_null())
+ return;
+
+ switch (info.eFrameType) {
+ case EVideoFrameType::videoFrameTypeInvalid:
+ case EVideoFrameType::videoFrameTypeSkip:
+ return;
+ default:
+ break;
+ }
+
+ std::string data;
+ data.reserve(CalculateFrameBitStreamLength(info));
+
+ for (int i = 0; i < info.iLayerNum; ++i) {
+ const SLayerBSInfo& layer_info = info.sLayerInfo[i];
+ data.append(reinterpret_cast<const char*>(layer_info.pBsBuf),
+ CalculateLayerBitStreamLength(layer_info));
+ }
+
+ const bool key_frame = info.eFrameType == EVideoFrameType::videoFrameTypeIDR;
+ encoded_callback_.Run(
+ std::unique_ptr<WiFiDisplayEncodedFrame>(new WiFiDisplayEncodedFrame(
+ std::move(data), reference_time, base::TimeTicks::Now(), key_frame)));
+}
+
+} // namespace
+
+// static
+void WiFiDisplayVideoEncoder::CreateSVC(
+ const InitParameters& params,
+ const VideoEncoderCallback& encoder_callback) {
+ WiFiDisplayVideoEncoderSVC::Create(params, encoder_callback);
+}
+
+} // namespace extensions
« no previous file with comments | « extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698