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 |