Commit 414c18ea authored by Miguel Casas-Sanchez's avatar Miguel Casas-Sanchez Committed by Commit Bot

VEA mojification: service-side implementation w/ unittest

This CL lands the service-side implementation of the mojom::VEA
and unit tests for it. It doesn't connect it yet, but the 
final result can be found in https://crrev.com/c/558846.

Bug: 736517
Change-Id: I6d77da653cfa8e4db9b2691707302fa2ad2d4479
Reviewed-on: https://chromium-review.googlesource.com/566262
Commit-Queue: Miguel Casas <mcasas@chromium.org>
Reviewed-by: default avatarDan Sanders <sandersd@chromium.org>
Reviewed-by: default avatarEmircan Uysaler <emircan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#487022}
parent a9a937ac
...@@ -116,6 +116,7 @@ component("gpu") { ...@@ -116,6 +116,7 @@ component("gpu") {
"//content/gpu:*", "//content/gpu:*",
"//content/renderer:*", "//content/renderer:*",
"//media/gpu/ipc/*", "//media/gpu/ipc/*",
"//media/mojo/*",
":*", ":*",
] ]
......
...@@ -86,6 +86,7 @@ source_set("unit_tests") { ...@@ -86,6 +86,7 @@ source_set("unit_tests") {
"interfaces/video_frame_struct_traits_unittest.cc", "interfaces/video_frame_struct_traits_unittest.cc",
"services/mojo_audio_output_stream_unittest.cc", "services/mojo_audio_output_stream_unittest.cc",
"services/mojo_cdm_allocator_unittest.cc", "services/mojo_cdm_allocator_unittest.cc",
"services/mojo_video_encode_accelerator_service_unittest.cc",
] ]
if (is_android) { if (is_android) {
......
...@@ -53,6 +53,8 @@ component("services") { ...@@ -53,6 +53,8 @@ component("services") {
"mojo_renderer_service.h", "mojo_renderer_service.h",
"mojo_video_decoder_service.cc", "mojo_video_decoder_service.cc",
"mojo_video_decoder_service.h", "mojo_video_decoder_service.h",
"mojo_video_encode_accelerator_service.cc",
"mojo_video_encode_accelerator_service.h",
"test_mojo_media_client.cc", "test_mojo_media_client.cc",
"test_mojo_media_client.h", "test_mojo_media_client.h",
] ]
...@@ -65,6 +67,7 @@ component("services") { ...@@ -65,6 +67,7 @@ component("services") {
public_deps = [ public_deps = [
"//base", "//base",
"//media", "//media",
"//media/gpu",
"//media/mojo:features", "//media/mojo:features",
"//media/mojo/interfaces", "//media/mojo/interfaces",
"//mojo/public/cpp/bindings", "//mojo/public/cpp/bindings",
......
// 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/services/mojo_video_encode_accelerator_service.h"
#include <memory>
#include <utility>
#include "base/logging.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/limits.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/system/platform_handle.h"
namespace media {
// static
void MojoVideoEncodeAcceleratorService::Create(
media::mojom::VideoEncodeAcceleratorRequest request,
const CreateAndInitializeVideoEncodeAcceleratorCallback&
create_vea_callback,
const gpu::GpuPreferences& gpu_preferences) {
mojo::MakeStrongBinding(base::MakeUnique<MojoVideoEncodeAcceleratorService>(
create_vea_callback, gpu_preferences),
std::move(request));
}
MojoVideoEncodeAcceleratorService::MojoVideoEncodeAcceleratorService(
const CreateAndInitializeVideoEncodeAcceleratorCallback&
create_vea_callback,
const gpu::GpuPreferences& gpu_preferences)
: create_vea_callback_(create_vea_callback),
gpu_preferences_(gpu_preferences),
output_buffer_size_(0),
weak_factory_(this) {
DVLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
MojoVideoEncodeAcceleratorService::~MojoVideoEncodeAcceleratorService() {
DVLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void MojoVideoEncodeAcceleratorService::Initialize(
media::VideoPixelFormat input_format,
const gfx::Size& input_visible_size,
media::VideoCodecProfile output_profile,
uint32_t initial_bitrate,
mojom::VideoEncodeAcceleratorClientPtr client) {
DVLOG(1) << __func__
<< " input_format=" << VideoPixelFormatToString(input_format)
<< ", input_visible_size=" << input_visible_size.ToString()
<< ", output_profile=" << GetProfileName(output_profile)
<< ", initial_bitrate=" << initial_bitrate;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!encoder_);
DCHECK_EQ(PIXEL_FORMAT_I420, input_format) << "Only I420 format supported";
if (!client) {
DLOG(ERROR) << __func__ << "null |client|";
return;
}
vea_client_ = std::move(client);
if (input_visible_size.width() > limits::kMaxDimension ||
input_visible_size.height() > limits::kMaxDimension ||
input_visible_size.GetArea() > limits::kMaxCanvas) {
DLOG(ERROR) << __func__ << "too large input_visible_size "
<< input_visible_size.ToString();
NotifyError(::media::VideoEncodeAccelerator::kInvalidArgumentError);
return;
}
encoder_ =
create_vea_callback_.Run(input_format, input_visible_size, output_profile,
initial_bitrate, this, gpu_preferences_);
if (!encoder_) {
DLOG(ERROR) << __func__ << " Error creating or initializing VEA";
NotifyError(::media::VideoEncodeAccelerator::kPlatformFailureError);
return;
}
// TODO(mcasas): We could still TryToSetupEncodeOnSeparateThread() with an
// ad-hoc background worker thread, but for the time being this doesn't seem
// necessary since we're already on a background thread.
return;
}
void MojoVideoEncodeAcceleratorService::Encode(
const scoped_refptr<VideoFrame>& frame,
bool force_keyframe,
EncodeCallback callback) {
DVLOG(2) << __func__ << " tstamp=" << frame->timestamp();
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!encoder_)
return;
if (frame->coded_size() != input_coded_size_) {
DLOG(ERROR) << __func__ << " wrong input coded size, expected "
<< input_coded_size_.ToString() << ", got "
<< frame->coded_size().ToString();
NotifyError(::media::VideoEncodeAccelerator::kInvalidArgumentError);
return;
}
frame->AddDestructionObserver(media::BindToCurrentLoop(std::move(callback)));
encoder_->Encode(frame, force_keyframe);
}
void MojoVideoEncodeAcceleratorService::UseOutputBitstreamBuffer(
int32_t bitstream_buffer_id,
mojo::ScopedSharedBufferHandle buffer) {
DVLOG(2) << __func__ << " bitstream_buffer_id=" << bitstream_buffer_id;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!encoder_)
return;
if (!buffer.is_valid()) {
DLOG(ERROR) << __func__ << " invalid |buffer|.";
NotifyError(::media::VideoEncodeAccelerator::kInvalidArgumentError);
return;
}
if (bitstream_buffer_id < 0) {
DLOG(ERROR) << __func__ << " bitstream_buffer_id=" << bitstream_buffer_id
<< " must be >= 0";
NotifyError(::media::VideoEncodeAccelerator::kInvalidArgumentError);
return;
}
base::SharedMemoryHandle handle;
size_t memory_size = 0;
bool read_only = false;
auto result = mojo::UnwrapSharedMemoryHandle(std::move(buffer), &handle,
&memory_size, &read_only);
if (result != MOJO_RESULT_OK || memory_size == 0u) {
DLOG(ERROR) << __func__ << " mojo::UnwrapSharedMemoryHandle() failed";
NotifyError(::media::VideoEncodeAccelerator::kPlatformFailureError);
return;
}
if (memory_size < output_buffer_size_) {
DLOG(ERROR) << __func__ << " bitstream_buffer_id=" << bitstream_buffer_id
<< " has a size of " << memory_size
<< "B, different from expected " << output_buffer_size_ << "B";
NotifyError(::media::VideoEncodeAccelerator::kInvalidArgumentError);
return;
}
encoder_->UseOutputBitstreamBuffer(
BitstreamBuffer(bitstream_buffer_id, handle, memory_size));
}
void MojoVideoEncodeAcceleratorService::RequestEncodingParametersChange(
uint32_t bitrate,
uint32_t framerate) {
DVLOG(2) << __func__ << " bitrate=" << bitrate << " framerate=" << framerate;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!encoder_)
return;
encoder_->RequestEncodingParametersChange(bitrate, framerate);
}
void MojoVideoEncodeAcceleratorService::RequireBitstreamBuffers(
unsigned int input_count,
const gfx::Size& input_coded_size,
size_t output_buffer_size) {
DVLOG(2) << __func__ << " input_count=" << input_count
<< " input_coded_size=" << input_coded_size.ToString()
<< " output_buffer_size=" << output_buffer_size;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!vea_client_)
return;
output_buffer_size_ = output_buffer_size;
input_coded_size_ = input_coded_size;
vea_client_->RequireBitstreamBuffers(input_count, input_coded_size,
output_buffer_size);
}
void MojoVideoEncodeAcceleratorService::BitstreamBufferReady(
int32_t bitstream_buffer_id,
size_t payload_size,
bool key_frame,
base::TimeDelta timestamp) {
DVLOG(2) << __func__ << " bitstream_buffer_id=" << bitstream_buffer_id
<< ", payload_size=" << payload_size
<< "B, key_frame=" << key_frame;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!vea_client_)
return;
vea_client_->BitstreamBufferReady(bitstream_buffer_id, payload_size,
key_frame, timestamp);
}
void MojoVideoEncodeAcceleratorService::NotifyError(
::media::VideoEncodeAccelerator::Error error) {
DVLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!vea_client_)
return;
// TODO(mcasas): Use EnumTraits, https://crbug.com/736517
Error mojo_error = Error::PLATFORM_FAILURE_ERROR;
switch (error) {
case ::media::VideoEncodeAccelerator::kIllegalStateError:
mojo_error = Error::ILLEGAL_STATE_ERROR;
break;
case ::media::VideoEncodeAccelerator::kInvalidArgumentError:
mojo_error = Error::INVALID_ARGUMENT_ERROR;
break;
case ::media::VideoEncodeAccelerator::kPlatformFailureError:
mojo_error = Error::PLATFORM_FAILURE_ERROR;
break;
}
vea_client_->NotifyError(mojo_error);
}
} // namespace media
// 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.
#ifndef MEDIA_MOJO_SERVICES_MOJO_VIDEO_ENCODE_ACCELERATOR_SERVICE_H_
#define MEDIA_MOJO_SERVICES_MOJO_VIDEO_ENCODE_ACCELERATOR_SERVICE_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <vector>
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "media/mojo/interfaces/video_encode_accelerator.mojom.h"
#include "media/mojo/services/media_mojo_export.h"
#include "media/video/video_encode_accelerator.h"
namespace gpu {
struct GpuPreferences;
} // namespace gpu
namespace media {
// This class implements the interface mojom::VideoEncodeAccelerator.
class MEDIA_MOJO_EXPORT MojoVideoEncodeAcceleratorService
: public NON_EXPORTED_BASE(mojom::VideoEncodeAccelerator),
public VideoEncodeAccelerator::Client {
public:
// Create and initialize a VEA. Returns nullptr if either part fails.
using CreateAndInitializeVideoEncodeAcceleratorCallback =
base::Callback<std::unique_ptr<::media::VideoEncodeAccelerator>(
VideoPixelFormat input_format,
const gfx::Size& input_visible_size,
VideoCodecProfile output_profile,
uint32_t initial_bitrate,
Client* client,
const gpu::GpuPreferences& gpu_preferences)>;
static void Create(media::mojom::VideoEncodeAcceleratorRequest request,
const CreateAndInitializeVideoEncodeAcceleratorCallback&
create_vea_callback,
const gpu::GpuPreferences& gpu_preferences);
MojoVideoEncodeAcceleratorService(
const CreateAndInitializeVideoEncodeAcceleratorCallback&
create_vea_callback,
const gpu::GpuPreferences& gpu_preferences);
~MojoVideoEncodeAcceleratorService() override;
// mojom::VideoEncodeAccelerator impl.
void Initialize(media::VideoPixelFormat input_format,
const gfx::Size& input_visible_size,
media::VideoCodecProfile output_profile,
uint32_t initial_bitrate,
mojom::VideoEncodeAcceleratorClientPtr client) override;
void Encode(const scoped_refptr<VideoFrame>& frame,
bool force_keyframe,
EncodeCallback callback) override;
void UseOutputBitstreamBuffer(int32_t bitstream_buffer_id,
mojo::ScopedSharedBufferHandle buffer) override;
void RequestEncodingParametersChange(uint32_t bitrate,
uint32_t framerate) override;
private:
friend class MojoVideoEncodeAcceleratorServiceTest;
// VideoEncodeAccelerator::Client implementation.
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,
base::TimeDelta timestamp) override;
void NotifyError(::media::VideoEncodeAccelerator::Error error) override;
const CreateAndInitializeVideoEncodeAcceleratorCallback create_vea_callback_;
const gpu::GpuPreferences& gpu_preferences_;
// Owned pointer to the underlying VideoEncodeAccelerator.
std::unique_ptr<::media::VideoEncodeAccelerator> encoder_;
mojom::VideoEncodeAcceleratorClientPtr vea_client_;
// Cache of parameters for sanity verification.
size_t output_buffer_size_;
gfx::Size input_coded_size_;
// Note that this class is already thread hostile when bound.
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<MojoVideoEncodeAcceleratorService> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(MojoVideoEncodeAcceleratorService);
};
} // namespace media
#endif // MEDIA_MOJO_SERVICES_MOJO_VIDEO_ENCODE_ACCELERATOR_SERVICE_H_
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
namespace media { namespace media {
static const unsigned int kMinimumInputCount = 1; static const unsigned int kMinimumInputCount = 1;
static const size_t kMinimumOutputBufferSize = 123456;
FakeVideoEncodeAccelerator::FakeVideoEncodeAccelerator( FakeVideoEncodeAccelerator::FakeVideoEncodeAccelerator(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
......
...@@ -26,6 +26,8 @@ class SingleThreadTaskRunner; ...@@ -26,6 +26,8 @@ class SingleThreadTaskRunner;
namespace media { namespace media {
static const size_t kMinimumOutputBufferSize = 123456;
class MEDIA_EXPORT FakeVideoEncodeAccelerator : public VideoEncodeAccelerator { class MEDIA_EXPORT FakeVideoEncodeAccelerator : public VideoEncodeAccelerator {
public: public:
explicit FakeVideoEncodeAccelerator( explicit FakeVideoEncodeAccelerator(
...@@ -51,6 +53,8 @@ class MEDIA_EXPORT FakeVideoEncodeAccelerator : public VideoEncodeAccelerator { ...@@ -51,6 +53,8 @@ class MEDIA_EXPORT FakeVideoEncodeAccelerator : public VideoEncodeAccelerator {
void SendDummyFrameForTesting(bool key_frame); void SendDummyFrameForTesting(bool key_frame);
void SetWillInitializationSucceed(bool will_initialization_succeed); void SetWillInitializationSucceed(bool will_initialization_succeed);
size_t minimum_output_buffer_size() const { return kMinimumOutputBufferSize; }
private: private:
void DoRequireBitstreamBuffers(unsigned int input_count, void DoRequireBitstreamBuffers(unsigned int input_count,
const gfx::Size& input_coded_size, const gfx::Size& input_coded_size,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment