Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/gpu/gpu_arc_video_encode_accelerator.h" | |
| 6 | |
| 7 #include <utility> | |
| 8 | |
| 9 #include "base/logging.h" | |
| 10 #include "base/sys_info.h" | |
| 11 #include "media/base/video_types.h" | |
| 12 #include "media/gpu/gpu_video_encode_accelerator_factory.h" | |
| 13 #include "mojo/public/cpp/bindings/strong_binding.h" | |
| 14 #include "mojo/public/cpp/bindings/type_converter.h" | |
| 15 #include "mojo/public/cpp/system/platform_handle.h" | |
| 16 | |
| 17 namespace chromeos { | |
| 18 namespace arc { | |
| 19 | |
| 20 GpuArcVideoEncodeAccelerator::GpuArcVideoEncodeAccelerator( | |
| 21 const gpu::GpuPreferences& gpu_preferences) | |
| 22 : gpu_preferences_(gpu_preferences) {} | |
| 23 | |
| 24 GpuArcVideoEncodeAccelerator::~GpuArcVideoEncodeAccelerator() = default; | |
| 25 | |
| 26 // VideoEncodeAccelerator::Client implementation. | |
| 27 void GpuArcVideoEncodeAccelerator::RequireBitstreamBuffers( | |
| 28 unsigned int input_count, | |
| 29 const gfx::Size& coded_size, | |
| 30 size_t output_buffer_size) { | |
| 31 DVLOG(2) << "RequireBitstreamBuffers(input_count=" << input_count | |
| 32 << ", coded_size=" << coded_size.ToString() | |
| 33 << ", output_buffer_size=" << output_buffer_size << ")"; | |
| 34 DCHECK(client_); | |
| 35 coded_size_ = coded_size; | |
| 36 client_->RequireBitstreamBuffers(input_count, coded_size, output_buffer_size); | |
| 37 } | |
| 38 | |
| 39 void GpuArcVideoEncodeAccelerator::BitstreamBufferReady( | |
| 40 int32_t bitstream_buffer_id, | |
| 41 size_t payload_size, | |
| 42 bool key_frame, | |
| 43 base::TimeDelta timestamp) { | |
| 44 DVLOG(2) << "BitstreamBufferReady(id=" << bitstream_buffer_id << ")"; | |
| 45 DCHECK(client_); | |
| 46 client_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame, | |
| 47 timestamp.InMicroseconds()); | |
| 48 } | |
| 49 | |
| 50 void GpuArcVideoEncodeAccelerator::NotifyError(Error error) { | |
| 51 DVLOG(2) << "NotifyError(" << error << ")"; | |
| 52 DCHECK(client_); | |
| 53 client_->NotifyError(error); | |
| 54 } | |
| 55 | |
| 56 // ::arc::mojom::VideoEncodeAccelerator implementation. | |
| 57 void GpuArcVideoEncodeAccelerator::GetSupportedProfiles( | |
| 58 const GetSupportedProfilesCallback& callback) { | |
| 59 callback.Run( | |
| 60 std::move(media::GpuVideoEncodeAcceleratorFactory::GetSupportedProfiles( | |
|
Luis Héctor Chávez
2017/06/07 16:02:36
nit: this std::move() is not needed since it's not
Owen Lin
2017/06/08 04:15:47
I see. Thanks.
| |
| 61 gpu_preferences_))); | |
| 62 } | |
| 63 | |
| 64 void GpuArcVideoEncodeAccelerator::Initialize( | |
| 65 VideoPixelFormat input_format, | |
| 66 const gfx::Size& visible_size, | |
| 67 VideoEncodeAccelerator::StorageType input_storage, | |
| 68 VideoCodecProfile output_profile, | |
| 69 uint32_t initial_bitrate, | |
| 70 VideoEncodeClientPtr client, | |
| 71 const InitializeCallback& callback) { | |
| 72 DVLOG(2) << "Initialize()"; | |
| 73 | |
| 74 if (!client) { | |
| 75 DLOG(ERROR) << "Invalid client"; | |
| 76 callback.Run(false); | |
| 77 return; | |
| 78 } | |
| 79 | |
| 80 input_pixel_format_ = static_cast<media::VideoPixelFormat>(input_format); | |
| 81 visible_size_ = visible_size; | |
| 82 accelerator_ = media::GpuVideoEncodeAcceleratorFactory::CreateVEA( | |
| 83 input_pixel_format_, visible_size_, | |
| 84 static_cast<media::VideoCodecProfile>(output_profile), initial_bitrate, | |
| 85 this, gpu_preferences_); | |
| 86 if (accelerator_ == nullptr) { | |
| 87 DLOG(ERROR) << "failed to create vea."; | |
|
Luis Héctor Chávez
2017/06/07 16:02:36
nit: s/vea/Accelerator/, for consistency with the
Owen Lin
2017/06/08 04:15:47
Done.
| |
| 88 callback.Run(false); | |
| 89 return; | |
| 90 } | |
| 91 client_ = std::move(client); | |
| 92 callback.Run(true); | |
| 93 } | |
| 94 | |
| 95 static void DropSharedMemory(std::unique_ptr<base::SharedMemory> shm) { | |
| 96 // Just let |shm| fall out of scope. | |
| 97 } | |
| 98 | |
| 99 void GpuArcVideoEncodeAccelerator::Encode( | |
| 100 mojo::ScopedHandle handle, | |
| 101 std::vector<::arc::VideoFramePlane> planes, | |
| 102 int64_t timestamp, | |
| 103 bool force_keyframe) { | |
| 104 DVLOG(2) << "Encode(timestamp=" << timestamp << ")"; | |
| 105 if (!accelerator_) { | |
| 106 DLOG(ERROR) << "Accelerator not initialized"; | |
| 107 return; | |
| 108 } | |
| 109 | |
| 110 scoped_refptr<media::VideoFrame> frame; | |
| 111 if (planes.empty()) { // EOS | |
| 112 frame = media::VideoFrame::CreateEOSFrame(); | |
|
Luis Héctor Chávez
2017/06/07 16:02:36
nit:
use guard clause pattern:
if (planes.empty(
Owen Lin
2017/06/08 04:15:46
Done.
| |
| 113 } else { | |
| 114 base::ScopedFD fd = UnwrapFdFromMojoHandle(std::move(handle)); | |
| 115 if (!fd.is_valid()) | |
| 116 return; | |
| 117 | |
| 118 size_t allocation_size = | |
| 119 media::VideoFrame::AllocationSize(input_pixel_format_, coded_size_); | |
| 120 | |
| 121 // TODO(rockot): Pass GUIDs through Mojo. https://crbug.com/713763. | |
| 122 // TODO(rockot): This fd comes from a mojo::ScopedHandle in | |
| 123 // GpuArcVideoService::BindSharedMemory. That should be passed through, | |
| 124 // rather than pulling out the fd. https://crbug.com/713763. | |
| 125 // TODO(rockot): Pass through a real size rather than |0|. | |
| 126 base::UnguessableToken guid = base::UnguessableToken::Create(); | |
| 127 base::SharedMemoryHandle shm_handle( | |
| 128 base::FileDescriptor(fd.release(), true), 0u, guid); | |
| 129 auto shm = base::MakeUnique<base::SharedMemory>(shm_handle, true); | |
| 130 | |
| 131 base::CheckedNumeric<off_t> map_offset = planes[0].offset; | |
| 132 base::CheckedNumeric<size_t> map_size = allocation_size; | |
| 133 const uint32_t aligned_offset = | |
| 134 planes[0].offset % base::SysInfo::VMAllocationGranularity(); | |
| 135 map_offset -= aligned_offset; | |
| 136 map_size += aligned_offset; | |
| 137 | |
| 138 if (!map_offset.IsValid() || !map_size.IsValid()) { | |
| 139 DLOG(ERROR) << "Invalid map_offset or map_size"; | |
| 140 client_->NotifyError(Error::kInvalidArgumentError); | |
| 141 return; | |
| 142 } | |
| 143 if (!shm->MapAt(map_offset.ValueOrDie(), map_size.ValueOrDie())) { | |
| 144 DLOG(ERROR) << "Could not map memroy"; | |
|
Luis Héctor Chávez
2017/06/07 16:17:36
nit: s/memroy/memory/
Owen Lin
2017/06/08 04:15:47
Done.
| |
| 145 client_->NotifyError(Error::kPlatformFailureError); | |
| 146 return; | |
| 147 } | |
| 148 | |
| 149 uint8_t* shm_memory = reinterpret_cast<uint8_t*>(shm->memory()); | |
| 150 frame = media::VideoFrame::WrapExternalSharedMemory( | |
| 151 input_pixel_format_, coded_size_, gfx::Rect(visible_size_), | |
| 152 visible_size_, shm_memory + aligned_offset, allocation_size, shm_handle, | |
| 153 planes[0].offset, base::TimeDelta::FromMicroseconds(timestamp)); | |
| 154 | |
| 155 // Wrap |shm| in a callback and add it as a destruction observer, so it | |
| 156 // stays alive and mapped until |frame| goes out of scope. | |
| 157 frame->AddDestructionObserver( | |
| 158 base::Bind(&DropSharedMemory, base::Passed(&shm))); | |
| 159 } | |
| 160 accelerator_->Encode(frame, force_keyframe); | |
| 161 } | |
| 162 | |
| 163 void GpuArcVideoEncodeAccelerator::UseOutputBitstreamBuffer( | |
| 164 int32_t bitstream_buffer_id, | |
| 165 mojo::ScopedHandle shmem_fd, | |
| 166 uint32_t offset, | |
| 167 uint32_t size) { | |
| 168 DVLOG(2) << "UseOutputBitstreamBuffer(id=" << bitstream_buffer_id << ")"; | |
| 169 if (!accelerator_) { | |
| 170 DLOG(ERROR) << "Accelerator not initialized"; | |
| 171 return; | |
| 172 } | |
| 173 | |
| 174 base::ScopedFD fd = UnwrapFdFromMojoHandle(std::move(shmem_fd)); | |
| 175 if (!fd.is_valid()) | |
| 176 return; | |
| 177 | |
| 178 // TODO(rockot): Pass GUIDs through Mojo. https://crbug.com/713763. | |
| 179 // TODO(rockot): This fd comes from a mojo::ScopedHandle in | |
| 180 // GpuArcVideoService::BindSharedMemory. That should be passed through, | |
| 181 // rather than pulling out the fd. https://crbug.com/713763. | |
| 182 // TODO(rockot): Pass through a real size rather than |0|. | |
| 183 base::UnguessableToken guid = base::UnguessableToken::Create(); | |
| 184 base::SharedMemoryHandle shm_handle(base::FileDescriptor(fd.release(), true), | |
| 185 0u, guid); | |
| 186 accelerator_->UseOutputBitstreamBuffer( | |
| 187 media::BitstreamBuffer(bitstream_buffer_id, shm_handle, size, offset)); | |
| 188 } | |
| 189 | |
| 190 void GpuArcVideoEncodeAccelerator::RequestEncodingParametersChange( | |
| 191 uint32_t bitrate, | |
| 192 uint32_t framerate) { | |
| 193 DVLOG(2) << "RequestEncodingParametersChange(" << bitrate << ", " << framerate | |
| 194 << ")"; | |
| 195 if (!accelerator_) { | |
| 196 DLOG(ERROR) << "Accelerator not initialized"; | |
| 197 return; | |
| 198 } | |
| 199 accelerator_->RequestEncodingParametersChange(bitrate, framerate); | |
| 200 } | |
| 201 | |
| 202 base::ScopedFD GpuArcVideoEncodeAccelerator::UnwrapFdFromMojoHandle( | |
| 203 mojo::ScopedHandle handle) { | |
| 204 DCHECK(client_); | |
| 205 if (!handle.is_valid()) { | |
| 206 DLOG(ERROR) << "handle is invalid"; | |
| 207 client_->NotifyError(Error::kInvalidArgumentError); | |
| 208 return base::ScopedFD(); | |
| 209 } | |
| 210 | |
| 211 base::PlatformFile platform_file; | |
| 212 MojoResult mojo_result = | |
| 213 mojo::UnwrapPlatformFile(std::move(handle), &platform_file); | |
| 214 if (mojo_result != MOJO_RESULT_OK) { | |
| 215 DLOG(ERROR) << "UnwrapPlatformFile failed: " << mojo_result; | |
| 216 client_->NotifyError(Error::kPlatformFailureError); | |
| 217 return base::ScopedFD(); | |
| 218 } | |
| 219 | |
| 220 return base::ScopedFD(platform_file); | |
| 221 } | |
| 222 | |
| 223 } // namespace arc | |
| 224 } // namespace chromeos | |
| OLD | NEW |