blob: c70c7da083e739cce7e0317c0a21e485f6692286 [file] [log] [blame]
// Copyright 2017 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 "media/mojo/clients/mojo_video_encode_accelerator.h"
#include <utility>
#include "base/bind.h"
#include "base/logging.h"
#include "build/build_config.h"
#include "gpu/ipc/client/gpu_channel_host.h"
#include "media/base/video_frame.h"
#include "media/gpu/gpu_video_accelerator_util.h"
#include "media/mojo/common/mojo_shared_buffer_video_frame.h"
#include "media/mojo/mojom/video_encoder_info.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/system/platform_handle.h"
namespace media {
namespace {
// File-static mojom::VideoEncodeAcceleratorClient implementation to trampoline
// method calls to its |client_|. Note that this class is thread hostile when
// bound.
class VideoEncodeAcceleratorClient
: public mojom::VideoEncodeAcceleratorClient {
public:
VideoEncodeAcceleratorClient(
VideoEncodeAccelerator::Client* client,
mojo::PendingReceiver<mojom::VideoEncodeAcceleratorClient> receiver);
VideoEncodeAcceleratorClient(const VideoEncodeAcceleratorClient&) = delete;
VideoEncodeAcceleratorClient& operator=(const VideoEncodeAcceleratorClient&) =
delete;
~VideoEncodeAcceleratorClient() override = default;
// mojom::VideoEncodeAcceleratorClient impl.
void RequireBitstreamBuffers(uint32_t input_count,
const gfx::Size& input_coded_size,
uint32_t output_buffer_size) override;
void BitstreamBufferReady(
int32_t bitstream_buffer_id,
const media::BitstreamBufferMetadata& metadata) override;
void NotifyError(VideoEncodeAccelerator::Error error) override;
void NotifyEncoderInfoChange(const VideoEncoderInfo& info) override;
private:
VideoEncodeAccelerator::Client* client_;
mojo::Receiver<mojom::VideoEncodeAcceleratorClient> receiver_;
};
VideoEncodeAcceleratorClient::VideoEncodeAcceleratorClient(
VideoEncodeAccelerator::Client* client,
mojo::PendingReceiver<mojom::VideoEncodeAcceleratorClient> receiver)
: client_(client), receiver_(this, std::move(receiver)) {
DCHECK(client_);
}
void VideoEncodeAcceleratorClient::RequireBitstreamBuffers(
uint32_t input_count,
const gfx::Size& input_coded_size,
uint32_t output_buffer_size) {
DVLOG(2) << __func__ << " input_count= " << input_count
<< " input_coded_size= " << input_coded_size.ToString()
<< " output_buffer_size=" << output_buffer_size;
client_->RequireBitstreamBuffers(input_count, input_coded_size,
output_buffer_size);
}
void VideoEncodeAcceleratorClient::BitstreamBufferReady(
int32_t bitstream_buffer_id,
const media::BitstreamBufferMetadata& metadata) {
DVLOG(2) << __func__ << " bitstream_buffer_id=" << bitstream_buffer_id
<< ", payload_size=" << metadata.payload_size_bytes
<< "B, key_frame=" << metadata.key_frame;
client_->BitstreamBufferReady(bitstream_buffer_id, metadata);
}
void VideoEncodeAcceleratorClient::NotifyError(
VideoEncodeAccelerator::Error error) {
DVLOG(2) << __func__;
client_->NotifyError(error);
}
void VideoEncodeAcceleratorClient::NotifyEncoderInfoChange(
const VideoEncoderInfo& info) {
DVLOG(2) << __func__;
client_->NotifyEncoderInfoChange(info);
}
} // anonymous namespace
MojoVideoEncodeAccelerator::MojoVideoEncodeAccelerator(
mojo::PendingRemote<mojom::VideoEncodeAccelerator> vea,
const SupportedProfiles& supported_profiles)
: vea_(std::move(vea)), supported_profiles_(supported_profiles) {
DVLOG(1) << __func__;
DCHECK(vea_);
}
VideoEncodeAccelerator::SupportedProfiles
MojoVideoEncodeAccelerator::GetSupportedProfiles() {
DVLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return supported_profiles_;
}
bool MojoVideoEncodeAccelerator::Initialize(const Config& config,
Client* client) {
DVLOG(2) << __func__ << " " << config.AsHumanReadableString();
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!client)
return false;
// Get a mojom::VideoEncodeAcceleratorClient bound to a local implementation
// (VideoEncodeAcceleratorClient) and send the remote.
mojo::PendingRemote<mojom::VideoEncodeAcceleratorClient> vea_client_remote;
vea_client_ = std::make_unique<VideoEncodeAcceleratorClient>(
client, vea_client_remote.InitWithNewPipeAndPassReceiver());
bool result = false;
vea_->Initialize(config, std::move(vea_client_remote), &result);
return result;
}
void MojoVideoEncodeAccelerator::Encode(scoped_refptr<VideoFrame> frame,
bool force_keyframe) {
DVLOG(2) << __func__ << " tstamp=" << frame->timestamp();
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
size_t num_planes = VideoFrame::NumPlanes(frame->format());
DCHECK_EQ(num_planes, frame->layout().num_planes());
DCHECK(vea_.is_bound());
// GPU memory path: Pass-through.
if (frame->storage_type() == VideoFrame::STORAGE_GPU_MEMORY_BUFFER) {
vea_->Encode(frame, force_keyframe,
base::BindOnce([](scoped_refptr<VideoFrame>) {}, frame));
return;
}
// Mappable memory path: Copy buffer to shared memory.
if (frame->format() != PIXEL_FORMAT_I420 &&
frame->format() != PIXEL_FORMAT_NV12) {
DLOG(ERROR) << "Unexpected pixel format: "
<< VideoPixelFormatToString(frame->format());
return;
}
if (frame->storage_type() != VideoFrame::STORAGE_SHMEM &&
frame->storage_type() != VideoFrame::STORAGE_UNOWNED_MEMORY) {
DLOG(ERROR) << "Unexpected storage type: "
<< VideoFrame::StorageTypeToString(frame->storage_type());
return;
}
scoped_refptr<MojoSharedBufferVideoFrame> mojo_frame =
MojoSharedBufferVideoFrame::CreateFromYUVFrame(*frame);
if (!mojo_frame) {
DLOG(ERROR) << "Failed creating MojoSharedBufferVideoFrame from YUV";
return;
}
vea_->Encode(
std::move(mojo_frame), force_keyframe,
base::BindOnce([](scoped_refptr<VideoFrame>) {}, std::move(frame)));
}
void MojoVideoEncodeAccelerator::UseOutputBitstreamBuffer(
BitstreamBuffer buffer) {
DVLOG(2) << __func__ << " buffer.id()= " << buffer.id()
<< " buffer.size()= " << buffer.size() << "B";
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(buffer.region().IsValid());
auto buffer_handle =
mojo::WrapPlatformSharedMemoryRegion(buffer.TakeRegion());
vea_->UseOutputBitstreamBuffer(buffer.id(), std::move(buffer_handle));
}
void MojoVideoEncodeAccelerator::RequestEncodingParametersChange(
const Bitrate& bitrate,
uint32_t framerate) {
DVLOG(2) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(vea_.is_bound());
vea_->RequestEncodingParametersChangeWithBitrate(bitrate, framerate);
}
void MojoVideoEncodeAccelerator::RequestEncodingParametersChange(
const VideoBitrateAllocation& bitrate,
uint32_t framerate) {
DVLOG(2) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(vea_.is_bound());
vea_->RequestEncodingParametersChangeWithLayers(bitrate, framerate);
}
bool MojoVideoEncodeAccelerator::IsFlushSupported() {
DVLOG(2) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(vea_.is_bound());
bool flush_support = false;
vea_->IsFlushSupported(&flush_support);
return flush_support;
}
void MojoVideoEncodeAccelerator::Flush(FlushCallback flush_callback) {
DVLOG(2) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(vea_.is_bound());
vea_->Flush(std::move(flush_callback));
}
void MojoVideoEncodeAccelerator::Destroy() {
DVLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
vea_client_.reset();
vea_.reset();
// See media::VideoEncodeAccelerator for more info on this peculiar pattern.
delete this;
}
MojoVideoEncodeAccelerator::~MojoVideoEncodeAccelerator() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
} // namespace media