| 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
|
|
|