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

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

Issue 1905683002: [chrome.displaySource] Implement hardware accelerated H.264 video encoder. (Closed) Base URL: https://chromium.googlesource.com/chromium/src@master
Patch Set: Error logging, scoped_refptr, unique_ptr 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
Index: extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_vea.cc
diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_vea.cc b/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_vea.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a6f1aa77350a0c757bee8667e11b23022ea555ad
--- /dev/null
+++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_vea.cc
@@ -0,0 +1,237 @@
+// 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 "extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder.h"
+
+#include <list>
+#include <memory>
+#include <string>
+
+#include "base/bind.h"
+#include "base/task_runner_util.h"
+#include "content/public/renderer/video_encode_accelerator.h"
+#include "media/base/bind_to_current_loop.h"
+
+namespace extensions {
+
+namespace {
+
+// This video encoder implements hardware accelerated H.264 video encoding
+// using media::VideoEncodeAccelerator.
+class WiFiDisplayVideoEncoderVEA final
+ : public WiFiDisplayVideoEncoder,
+ public media::VideoEncodeAccelerator::Client {
+ public:
+ static void Create(
+ const InitParameters& params,
+ const VideoEncoderCallback& encoder_callback,
+ scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
+ std::unique_ptr<media::VideoEncodeAccelerator> vea);
+
+ private:
+ WiFiDisplayVideoEncoderVEA(
+ scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
+ media::VideoEncodeAccelerator* vea,
+ const CreateEncodeMemoryCallback& create_memory_callback);
+ ~WiFiDisplayVideoEncoderVEA() override;
+
+ // media::VideoEncodeAccelerator::Client
+ void RequireBitstreamBuffers(unsigned int input_count,
+ const gfx::Size& input_coded_size,
+ size_t output_buffer_size) override;
+
+ void BitstreamBufferReady(int32_t bitstream_buffer_id,
+ size_t payload_size,
+ bool key_frame) override;
+ void NotifyError(media::VideoEncodeAccelerator::Error error) override;
+
+ scoped_refptr<WiFiDisplayVideoEncoder> InitOnMediaThread(
+ const InitParameters& params);
+ void InsertFrameOnMediaThread(scoped_refptr<media::VideoFrame> video_frame,
+ base::TimeTicks reference_time,
+ bool send_idr) override;
+ void OnCreateSharedMemory(std::unique_ptr<base::SharedMemory> memory);
+ void OnReceivedSharedMemory(std::unique_ptr<base::SharedMemory> memory);
+
+ private:
+ struct InProgressFrameEncode {
+ InProgressFrameEncode(scoped_refptr<media::VideoFrame> video_frame,
+ base::TimeTicks reference_time);
+ ~InProgressFrameEncode();
+ // The source content to encode.
+ const scoped_refptr<media::VideoFrame> video_frame;
+
+ // The reference time for this frame.
+ const base::TimeTicks reference_time;
+ };
+ // FIFO list.
+ std::list<InProgressFrameEncode> in_progress_frame_encodes_;
+ media::VideoEncodeAccelerator* vea_; // Owned on media thread.
+ ScopedVector<base::SharedMemory> output_buffers_;
+ size_t output_buffers_count_;
+ CreateEncodeMemoryCallback create_video_encode_memory_cb_;
+};
+
+WiFiDisplayVideoEncoderVEA::InProgressFrameEncode::InProgressFrameEncode(
+ scoped_refptr<media::VideoFrame> video_frame,
+ base::TimeTicks reference_time)
+ : video_frame(std::move(video_frame)), reference_time(reference_time) {}
+
+WiFiDisplayVideoEncoderVEA::InProgressFrameEncode::~InProgressFrameEncode() =
+ default;
+
+// static
+void WiFiDisplayVideoEncoderVEA::Create(
+ const InitParameters& params,
+ const VideoEncoderCallback& encoder_callback,
+ scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
+ std::unique_ptr<media::VideoEncodeAccelerator> vea) {
+ if (!vea || !media_task_runner) {
+ encoder_callback.Run(nullptr);
+ return;
+ }
+
+ base::PostTaskAndReplyWithResult(
+ media_task_runner.get(), FROM_HERE,
+ base::Bind(&WiFiDisplayVideoEncoderVEA::InitOnMediaThread,
+ make_scoped_refptr(new WiFiDisplayVideoEncoderVEA(
+ std::move(media_task_runner), vea.release(),
+ params.create_memory_callback)),
+ params),
+ encoder_callback);
+}
+
+WiFiDisplayVideoEncoderVEA::WiFiDisplayVideoEncoderVEA(
+ scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
+ media::VideoEncodeAccelerator* vea,
+ const CreateEncodeMemoryCallback& create_video_encode_memory_cb)
+ : WiFiDisplayVideoEncoder(std::move(media_task_runner)),
+ vea_(vea),
+ output_buffers_count_(0),
+ create_video_encode_memory_cb_(create_video_encode_memory_cb) {}
+
+WiFiDisplayVideoEncoderVEA::~WiFiDisplayVideoEncoderVEA() {
+ media_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&media::VideoEncodeAccelerator::Destroy,
+ base::Unretained(vea_)));
+}
+
+scoped_refptr<WiFiDisplayVideoEncoder>
+WiFiDisplayVideoEncoderVEA::InitOnMediaThread(const InitParameters& params) {
+ // TODO: Select media profile based on video format capabilities negotiations
+ // with sink device.
+ bool success =
+ vea_->Initialize(media::PIXEL_FORMAT_I420, params.frame_size,
+ media::H264PROFILE_MAIN, params.bit_rate, this);
+ if (success)
+ return this;
+
+ DVLOG(1) << "Failed to init VEA";
+ return nullptr;
+}
+
+// Called to allocate the input and output buffers.
+void WiFiDisplayVideoEncoderVEA::RequireBitstreamBuffers(
+ unsigned int input_count,
+ const gfx::Size& input_coded_size,
+ size_t output_buffer_size) {
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
+ output_buffers_count_ = input_count;
+ for (size_t i = 0; i < input_count; ++i) {
+ create_video_encode_memory_cb_.Run(
+ output_buffer_size,
+ base::Bind(&WiFiDisplayVideoEncoderVEA::OnCreateSharedMemory, this));
+ }
+}
+
+// Note: This method can be called on any thread.
+void WiFiDisplayVideoEncoderVEA::OnCreateSharedMemory(
+ std::unique_ptr<base::SharedMemory> memory) {
+ media_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&WiFiDisplayVideoEncoderVEA::OnReceivedSharedMemory,
+ this, base::Passed(&memory)));
+}
+
+void WiFiDisplayVideoEncoderVEA::OnReceivedSharedMemory(
+ std::unique_ptr<base::SharedMemory> memory) {
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
+
+ output_buffers_.push_back(std::move(memory));
+
+ // Wait until all requested buffers are received.
+ if (output_buffers_.size() < output_buffers_count_)
+ return;
+
+ // Immediately provide all output buffers to the VEA.
+ for (size_t i = 0; i < output_buffers_.size(); ++i) {
+ vea_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
+ static_cast<int32_t>(i), output_buffers_[i]->handle(),
+ output_buffers_[i]->mapped_size()));
+ }
+}
+
+void WiFiDisplayVideoEncoderVEA::InsertFrameOnMediaThread(
+ scoped_refptr<media::VideoFrame> video_frame,
+ base::TimeTicks reference_time,
+ bool send_idr) {
+ in_progress_frame_encodes_.emplace_back(video_frame, reference_time);
+ DCHECK(vea_);
+ vea_->Encode(video_frame, send_idr);
+}
+
+void WiFiDisplayVideoEncoderVEA::BitstreamBufferReady(
+ int32_t bitstream_buffer_id,
+ size_t payload_size,
+ bool key_frame) {
+ if (bitstream_buffer_id >= static_cast<int>(output_buffers_.size())) {
+ DVLOG(1) << "WiFiDisplayVideoEncoderVEA::BitstreamBufferReady()"
+ << ": invalid bitstream_buffer_id=" << bitstream_buffer_id;
+ return;
+ }
+ base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id];
+ if (payload_size > output_buffer->mapped_size()) {
+ DVLOG(1) << "WiFiDisplayVideoEncoderVEA::BitstreamBufferReady()"
+ << ": invalid payload_size=" << payload_size;
+ return;
+ }
+ if (in_progress_frame_encodes_.empty()) {
+ DVLOG(1) << "WiFiDisplayVideoEncoderVEA::BitstreamBufferReady()"
+ << ": unexpected frame";
+ return;
+ }
+ const InProgressFrameEncode& request = in_progress_frame_encodes_.front();
+
+ if (!encoded_callback_.is_null()) {
+ encoded_callback_.Run(
+ std::unique_ptr<WiFiDisplayEncodedFrame>(new WiFiDisplayEncodedFrame(
+ std::string(reinterpret_cast<const char*>(output_buffer->memory()),
+ payload_size),
+ request.reference_time, base::TimeTicks::Now(), key_frame)));
+ }
+ DCHECK(vea_);
+ vea_->UseOutputBitstreamBuffer(
+ media::BitstreamBuffer(bitstream_buffer_id, output_buffer->handle(),
+ output_buffer->mapped_size()));
+
+ in_progress_frame_encodes_.pop_front();
+}
+
+void WiFiDisplayVideoEncoderVEA::NotifyError(
+ media::VideoEncodeAccelerator::Error error) {
+ if (!error_callback_.is_null())
+ error_callback_.Run();
+}
+
+} // namespace
+
+// static
+void WiFiDisplayVideoEncoder::CreateVEA(
+ const InitParameters& params,
+ const VideoEncoderCallback& encoder_callback) {
+ auto on_vea_cb =
+ base::Bind(&WiFiDisplayVideoEncoderVEA::Create, params, encoder_callback);
+ params.vea_create_callback.Run(media::BindToCurrentLoop(on_vea_cb));
+}
+
+} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698