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

Unified Diff: chrome/gpu/gpu_arc_video_encode_accelerator.cc

Issue 2892863002: ArcBridge: Add VideoEncodeAccelerator implementation. (Closed)
Patch Set: Created 3 years, 7 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: chrome/gpu/gpu_arc_video_encode_accelerator.cc
diff --git a/chrome/gpu/gpu_arc_video_encode_accelerator.cc b/chrome/gpu/gpu_arc_video_encode_accelerator.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e23700f265bfc39547dd1638a04716b8f7951e56
--- /dev/null
+++ b/chrome/gpu/gpu_arc_video_encode_accelerator.cc
@@ -0,0 +1,308 @@
+// 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 "chrome/gpu/gpu_arc_video_encode_accelerator.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/sys_info.h"
+#include "media/base/video_types.h"
+#include "media/gpu/gpu_video_encode_accelerator_factory.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/type_converter.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+
+namespace mojo {
+
+// Make sure arc::mojom::VideoEncodeAccelerator::Error and
+// media::VideoEncodeAccelerator::Error match.
+#define CHECK_ERROR_ENUM(value) \
+ static_assert( \
+ static_cast<int>(arc::mojom::VideoEncodeAccelerator::Error::value) == \
+ media::VideoEncodeAccelerator::Error::value, \
Luis Héctor Chávez 2017/05/19 15:14:44 Why not make a typemap for this? You also get comp
Owen Lin 2017/06/03 13:32:32 Done.
+ "enum ##value mismatch")
+
+CHECK_ERROR_ENUM(kIllegalStateError);
+CHECK_ERROR_ENUM(kInvalidArgumentError);
+CHECK_ERROR_ENUM(kPlatformFailureError);
+CHECK_ERROR_ENUM(kErrorMax);
+
+#undef CHECK_ERROR_ENUM
+
+// Make sure values in arc::mojom::VideoPixelFormat match to the values in
+// media::VideoPixelFormat. The former is a subset of the later.
+#define CHECK_PIXEL_FORMAT_ENUM(value) \
+ static_assert( \
+ static_cast<int>(arc::mojom::VideoPixelFormat::value) == media::value, \
+ "enum ##value mismatch")
+
+CHECK_PIXEL_FORMAT_ENUM(PIXEL_FORMAT_I420);
+
+#undef CHECK_PXIEL_FORMAT_ENUM
+
+// Make sure values in arc::mojom::VideoCodecProfile match to the values in
+// media::VideoCodecProfile.
+#define CHECK_PROFILE_ENUM(value) \
+ static_assert( \
+ static_cast<int>(arc::mojom::VideoCodecProfile::value) == media::value, \
+ "enum ##value mismatch")
+
+CHECK_PROFILE_ENUM(H264PROFILE_BASELINE);
+CHECK_PROFILE_ENUM(H264PROFILE_MAIN);
+CHECK_PROFILE_ENUM(H264PROFILE_EXTENDED);
+CHECK_PROFILE_ENUM(H264PROFILE_HIGH);
+CHECK_PROFILE_ENUM(H264PROFILE_HIGH10PROFILE);
+CHECK_PROFILE_ENUM(H264PROFILE_HIGH422PROFILE);
+CHECK_PROFILE_ENUM(H264PROFILE_HIGH444PREDICTIVEPROFILE);
+CHECK_PROFILE_ENUM(H264PROFILE_SCALABLEBASELINE);
+CHECK_PROFILE_ENUM(H264PROFILE_SCALABLEHIGH);
+CHECK_PROFILE_ENUM(H264PROFILE_STEREOHIGH);
+CHECK_PROFILE_ENUM(H264PROFILE_MULTIVIEWHIGH);
+CHECK_PROFILE_ENUM(VP8PROFILE_ANY);
+CHECK_PROFILE_ENUM(VP9PROFILE_PROFILE0);
+CHECK_PROFILE_ENUM(VP9PROFILE_PROFILE1);
+CHECK_PROFILE_ENUM(VP9PROFILE_PROFILE2);
+CHECK_PROFILE_ENUM(VP9PROFILE_PROFILE3);
+
+#undef CHECK_PROFILE_ENUM
+
+template <>
+struct TypeConverter<arc::mojom::VideoEncodeProfilePtr,
Luis Héctor Chávez 2017/05/19 15:14:44 same here, TypeConverters are discouraged in new c
Owen Lin 2017/06/03 13:32:32 Done.
+ media::VideoEncodeAccelerator::SupportedProfile> {
+ static arc::mojom::VideoEncodeProfilePtr Convert(
+ media::VideoEncodeAccelerator::SupportedProfile input) {
+ auto result = arc::mojom::VideoEncodeProfile::New();
+ result->profile = static_cast<arc::mojom::VideoCodecProfile>(input.profile);
+ result->max_resolution = input.max_resolution;
+ result->max_framerate_numerator = input.max_framerate_numerator;
+ result->max_framerate_denominator = input.max_framerate_denominator;
+ return result;
+ }
+};
+
+} // namespace mojo
+
+namespace chromeos {
+namespace arc {
+
+GpuArcVideoEncodeAccelerator::GpuArcVideoEncodeAccelerator(
+ const gpu::GpuPreferences& gpu_preferences)
+ : gpu_preferences_(gpu_preferences) {}
+
+GpuArcVideoEncodeAccelerator::~GpuArcVideoEncodeAccelerator() = default;
+
+// VideoEncodeAccelerator::Client implementation.
+void GpuArcVideoEncodeAccelerator::RequireBitstreamBuffers(
+ unsigned int input_count,
+ const gfx::Size& input_coded_size,
+ size_t output_buffer_size) {
+ DVLOG(2) << "RequireBitstreamBuffers(input_count=" << input_count
+ << ", input_coded_size=" << input_coded_size.ToString()
+ << ", output_buffer_size=" << output_buffer_size << ")";
+ DCHECK(client_);
+ input_coded_size_ = input_coded_size;
+ client_->RequireBitstreamBuffers(input_count, input_coded_size,
+ output_buffer_size);
+}
+
+void GpuArcVideoEncodeAccelerator::BitstreamBufferReady(
+ int32_t bitstream_buffer_id,
+ size_t payload_size,
+ bool key_frame,
+ base::TimeDelta timestamp) {
+ DVLOG(2) << "BitstreamBufferReady(id=" << bitstream_buffer_id << ")";
+ DCHECK(client_);
+ client_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame,
+ timestamp.InMicroseconds());
+}
+
+void GpuArcVideoEncodeAccelerator::NotifyError(
+ media::VideoEncodeAccelerator::Error error) {
+ DVLOG(2) << "NotifyError(" << error << ")";
+ DCHECK(client_);
+ client_->NotifyError(static_cast<VideoEncodeAccelerator::Error>(error));
+}
+
+// ::arc::mojom::VideoEncodeAccelerator implementation.
+void GpuArcVideoEncodeAccelerator::GetSupportedProfiles(
+ const GetSupportedProfilesCallback& callback) {
+ std::vector<::arc::mojom::VideoEncodeProfilePtr> profiles;
+ for (auto p : media::GpuVideoEncodeAcceleratorFactory::GetSupportedProfiles(
+ gpu_preferences_))
Luis Héctor Chávez 2017/05/19 15:14:44 nit: you cannot elide braces if the 'for' does not
Owen Lin 2017/06/03 13:32:31 Code is modified.
+ profiles.push_back(::arc::mojom::VideoEncodeProfile::From(p));
+ callback.Run(std::move(profiles));
+}
+
+void GpuArcVideoEncodeAccelerator::Initialize(
+ VideoPixelFormat input_format,
+ const gfx::Size& visible_size,
+ VideoEncodeAccelerator::StorageType input_storage,
+ VideoCodecProfile output_profile,
+ uint32_t initial_bitrate,
+ VideoEncodeClientPtr client,
+ const InitializeCallback& callback) {
+ DVLOG(2) << "Initialize()";
+
+ if (!::arc::mojom::IsKnownEnumValue(input_format)) {
+ DLOG(ERROR) << "Invalid input_format: " << input_format;
+ callback.Run(false);
+ return;
+ }
+ if (!::arc::mojom::IsKnownEnumValue(output_profile)) {
+ DLOG(ERROR) << "Invalid codec profile: " << output_profile;
+ callback.Run(false);
+ return;
+ }
+ if (!client) {
+ DLOG(ERROR) << "Invalid client";
+ callback.Run(false);
+ return;
+ }
+
+ input_pixel_format_ = static_cast<media::VideoPixelFormat>(input_format);
+ accelerator_ = media::GpuVideoEncodeAcceleratorFactory::CreateVEA(
+ input_pixel_format_, visible_size,
+ static_cast<media::VideoCodecProfile>(output_profile), initial_bitrate,
+ this, gpu_preferences_);
+ if (accelerator_ == nullptr) {
+ DLOG(ERROR) << "failed to create vea.";
+ callback.Run(false);
+ return;
+ }
+ client_ = std::move(client);
+ callback.Run(true);
+}
+
+static void DropSharedMemory(std::unique_ptr<base::SharedMemory> shm) {
+ // Just let |shm| fall out of scope.
+}
+
+void GpuArcVideoEncodeAccelerator::Encode(
+ mojo::ScopedHandle handle,
+ std::vector<::arc::VideoFramePlane> planes,
+ const gfx::Size& visible_size,
+ int64_t timestamp,
+ bool force_keyframe) {
+ DVLOG(2) << "Encode(timestamp=" << timestamp << ")";
+ if (!accelerator_) {
+ DLOG(ERROR) << "Accelerator not initialized";
+ return;
+ }
+
+ scoped_refptr<media::VideoFrame> frame;
+ if (planes.empty()) { // EOS
+ frame = media::VideoFrame::CreateEOSFrame();
+ } else {
+ base::ScopedFD fd = UnwrapFdFromMojoHandle(std::move(handle));
+ if (!fd.is_valid())
+ return;
+
+ size_t allocation_size = media::VideoFrame::AllocationSize(
+ input_pixel_format_, input_coded_size_);
+
+ // TODO(rockot): Pass GUIDs through Mojo. https://crbug.com/713763.
+ // TODO(rockot): This fd comes from a mojo::ScopedHandle in
+ // GpuArcVideoService::BindSharedMemory. That should be passed through,
+ // rather than pulling out the fd. https://crbug.com/713763.
+ // TODO(rockot): Pass through a real size rather than |0|.
+ base::UnguessableToken guid = base::UnguessableToken::Create();
+ base::SharedMemoryHandle shm_handle(
+ base::FileDescriptor(fd.release(), true), 0u, guid);
+ auto shm = base::MakeUnique<base::SharedMemory>(shm_handle, true);
+
+ base::CheckedNumeric<off_t> map_offset = planes[0].offset;
+ base::CheckedNumeric<size_t> map_size = allocation_size;
+ const uint32_t aligned_offset =
+ planes[0].offset % base::SysInfo::VMAllocationGranularity();
+ map_offset -= aligned_offset;
+ map_size += aligned_offset;
+
+ if (!map_offset.IsValid() || !map_size.IsValid()) {
+ DLOG(ERROR) << "Invalid map_offset or map_size";
+ client_->NotifyError(Error::kInvalidArgumentError);
+ return;
+ }
+ if (!shm->MapAt(map_offset.ValueOrDie(), map_size.ValueOrDie())) {
+ DLOG(ERROR) << "Could not map memroy";
+ client_->NotifyError(Error::kPlatformFailureError);
+ return;
+ }
+
+ uint8_t* shm_memory = reinterpret_cast<uint8_t*>(shm->memory());
+ frame = media::VideoFrame::WrapExternalSharedMemory(
+ input_pixel_format_, input_coded_size_, gfx::Rect(visible_size),
+ visible_size, shm_memory + aligned_offset, allocation_size, shm_handle,
+ planes[0].offset, base::TimeDelta::FromMicroseconds(timestamp));
+
+ // Wrap |shm| in a callback and add it as a destruction observer, so it
+ // stays alive and mapped until |frame| goes out of scope.
+ frame->AddDestructionObserver(
+ base::Bind(&DropSharedMemory, base::Passed(&shm)));
+ }
+ accelerator_->Encode(frame, force_keyframe);
+}
+
+void GpuArcVideoEncodeAccelerator::UseOutputBitstreamBuffer(
+ int32_t bitstream_buffer_id,
+ mojo::ScopedHandle shmem_fd,
+ uint32_t offset,
+ uint32_t size) {
+ DVLOG(2) << "UseOutputBitstreamBuffer(id=" << bitstream_buffer_id << ")";
+ if (!accelerator_) {
+ DLOG(ERROR) << "Accelerator not initialized";
+ return;
+ }
+
+ base::ScopedFD fd = UnwrapFdFromMojoHandle(std::move(shmem_fd));
+ if (!fd.is_valid())
+ return;
+
+ // TODO(rockot): Pass GUIDs through Mojo. https://crbug.com/713763.
+ // TODO(rockot): This fd comes from a mojo::ScopedHandle in
+ // GpuArcVideoService::BindSharedMemory. That should be passed through,
+ // rather than pulling out the fd. https://crbug.com/713763.
+ // TODO(rockot): Pass through a real size rather than |0|.
+ base::UnguessableToken guid = base::UnguessableToken::Create();
+ base::SharedMemoryHandle shm_handle(base::FileDescriptor(fd.release(), true),
+ 0u, guid);
+ accelerator_->UseOutputBitstreamBuffer(
+ media::BitstreamBuffer(bitstream_buffer_id, shm_handle, size, offset));
+}
+
+void GpuArcVideoEncodeAccelerator::RequestEncodingParametersChange(
+ uint32_t bitrate,
+ uint32_t framerate) {
+ DVLOG(2) << "RequestEncodingParametersChange(" << bitrate << ", " << framerate
+ << ")";
+ if (!accelerator_) {
+ DLOG(ERROR) << "Accelerator not initialized";
+ return;
+ }
+ accelerator_->RequestEncodingParametersChange(bitrate, framerate);
+}
+
+base::ScopedFD GpuArcVideoEncodeAccelerator::UnwrapFdFromMojoHandle(
+ mojo::ScopedHandle handle) {
+ DCHECK(client_);
+ if (!handle.is_valid()) {
+ DLOG(ERROR) << "handle is invalid";
+ client_->NotifyError(Error::kInvalidArgumentError);
+ return base::ScopedFD();
+ }
+
+ base::PlatformFile platform_file;
+ MojoResult mojo_result =
+ mojo::UnwrapPlatformFile(std::move(handle), &platform_file);
+ if (mojo_result != MOJO_RESULT_OK) {
+ DLOG(ERROR) << "UnwrapPlatformFile failed: " << mojo_result;
+ client_->NotifyError(Error::kPlatformFailureError);
+ return base::ScopedFD();
+ }
+
+ return base::ScopedFD(platform_file);
+}
+
+} // namespace arc
+} // namespace chromeos

Powered by Google App Engine
This is Rietveld 408576698