Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 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 "base/callback_helpers.h" | |
| 6 #include "base/logging.h" | |
| 7 #include "base/run_loop.h" | |
| 8 #include "content/common/gpu/media/arc/arc_gpu_video_decode_accelerator.h" | |
| 9 | |
| 10 namespace content { | |
| 11 namespace arc { | |
| 12 | |
| 13 ArcGpuVideoDecodeAccelerator::InputRecord::InputRecord() | |
| 14 : offset(0), length(0), bitstream_buffer_id(-1), timestamp(0) {} | |
| 15 | |
| 16 ArcGpuVideoDecodeAccelerator::PortInfo::PortInfo() | |
| 17 : memory_type(MEMORY_DMABUF), num_buffers(0) {} | |
| 18 | |
| 19 ArcGpuVideoDecodeAccelerator::ArcGpuVideoDecodeAccelerator() | |
| 20 : arc_client_(nullptr), next_bitstream_buffer_id_(0) {} | |
| 21 | |
| 22 bool ArcGpuVideoDecodeAccelerator::Initialize( | |
| 23 DeviceType device, | |
| 24 ArcVideoAccelerator::Client* client) { | |
| 25 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 26 if (device != DEVICE_DECODER) | |
| 27 return false; | |
| 28 DCHECK(client); | |
| 29 DCHECK(!arc_client_); | |
| 30 arc_client_ = client; | |
| 31 vda_ = nullptr; // TODO: connect to a real vda. | |
| 32 return true; | |
| 33 } | |
| 34 | |
| 35 bool ArcGpuVideoDecodeAccelerator::SetBufferCount(PortType port, | |
| 36 size_t* count) { | |
| 37 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 38 if (!ValidatePort(port)) | |
| 39 return false; | |
| 40 if (vda_ == nullptr) { | |
| 41 DVLOG(1) << "Must call setBufferFormat before setBufferCount"; | |
| 42 return false; | |
| 43 } | |
| 44 if (port == PORT_OUTPUT) { | |
| 45 std::vector<media::PictureBuffer> buffers; | |
| 46 for (int32_t id = 0, n = *count; id < n; ++id) { | |
|
kcwu
2016/01/20 09:11:05
how about just
for (int32_t id = 0; id < *count; +
Owen Lin
2016/02/02 09:08:06
Also prevent comparing signed and unsigned numbers
kcwu
2016/03/09 07:58:21
If so, how about just cast explicitly?
| |
| 47 // TODO: Make sure the size is what we want. | |
| 48 buffers.push_back(media::PictureBuffer(id, coded_size_, 0)); | |
|
kcwu
2016/01/20 09:11:05
need to make sure the value of *count is not too b
Owen Lin
2016/02/02 09:08:06
Done.
| |
| 49 } | |
| 50 vda_->AssignPictureBuffers(buffers); | |
| 51 } | |
| 52 PortInfo* port_info = &port_info_[port]; | |
| 53 port_info->num_buffers = *count; | |
| 54 if (port == PORT_INPUT) { | |
| 55 input_records_.clear(); | |
| 56 input_records_.resize(port_info->num_buffers); | |
| 57 } | |
| 58 return true; | |
| 59 } | |
| 60 | |
| 61 bool ArcGpuVideoDecodeAccelerator::SetBufferFormat(PortType port, | |
| 62 const BufferFormat& format) { | |
| 63 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 64 if (!ValidatePort(port)) | |
| 65 return false; | |
| 66 switch (port) { | |
| 67 case PORT_INPUT: { | |
| 68 PortInfo* port_info = &port_info_[port]; | |
| 69 if (format.memory_type != MEMORY_SHARED_MEMORY) { | |
| 70 DVLOG(1) << "Only SharedMemory is supported for input buffers"; | |
|
kcwu
2016/01/20 09:11:05
I feel most of DVLOG(1) in this file should be DLO
Owen Lin
2016/02/02 09:08:06
Done.
| |
| 71 return false; | |
| 72 } | |
| 73 port_info->memory_type = format.memory_type; | |
| 74 media::VideoDecodeAccelerator::Config config; | |
| 75 switch (format.pixel_format) { | |
| 76 case HAL_PIXEL_FORMAT_H264: | |
| 77 config.profile = media::H264PROFILE_MAIN; | |
| 78 break; | |
| 79 case HAL_PIXEL_FORMAT_VP8: | |
| 80 config.profile = media::VP8PROFILE_ANY; | |
| 81 break; | |
| 82 default: | |
| 83 DVLOG(1) << "Unsupported input format: " << format.pixel_format; | |
| 84 return false; | |
| 85 } | |
| 86 config.output_mode = | |
| 87 media::VideoDecodeAccelerator::Config::OutputMode::IMPORT; | |
| 88 if (!vda_->Initialize(config, this)) { | |
| 89 DVLOG(1) << "VDA::Initialize() failed."; | |
| 90 return false; | |
| 91 } | |
| 92 break; | |
| 93 } | |
| 94 case PORT_OUTPUT: { | |
| 95 PortInfo* port_info = &port_info_[port]; | |
| 96 if (format.memory_type != MEMORY_DMABUF) { | |
| 97 DVLOG(1) << "Only DMA buffer is supported for output buffers"; | |
| 98 return false; | |
| 99 } | |
| 100 port_info->memory_type = format.memory_type; | |
| 101 break; | |
| 102 } | |
| 103 default: | |
| 104 NOTREACHED() << "Invalid port: " << port; | |
| 105 return false; | |
| 106 } | |
| 107 return true; | |
| 108 } | |
| 109 | |
| 110 bool ArcGpuVideoDecodeAccelerator::ValidatePort(PortType port) { | |
|
kcwu
2016/01/20 09:11:04
Move these two helpers below or above, don't mix w
Owen Lin
2016/02/02 09:08:06
Done.
| |
| 111 if (port != PORT_INPUT && port != PORT_OUTPUT) { | |
| 112 DVLOG(1) << "Invalid port: " << port; | |
| 113 return false; | |
| 114 } | |
| 115 return true; | |
| 116 } | |
| 117 | |
| 118 bool ArcGpuVideoDecodeAccelerator::ValidatePortAndIndex(PortType port, | |
| 119 uint32_t index) { | |
| 120 if (!ValidatePort(port)) | |
| 121 return false; | |
| 122 if (index >= port_info_[port].num_buffers) { | |
| 123 DVLOG(1) << "Invalid buffer - port: " << port << ", index: " << index; | |
| 124 return false; | |
| 125 } | |
| 126 return true; | |
| 127 } | |
| 128 | |
| 129 bool ArcGpuVideoDecodeAccelerator::BindSharedMemory(PortType port, | |
| 130 uint32_t index, | |
| 131 int ashmem_fd, | |
| 132 size_t offset, | |
| 133 size_t length) { | |
| 134 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 135 | |
| 136 // Make sure we will close the file descriptor. | |
| 137 base::ScopedFD handle(ashmem_fd); | |
| 138 if (!ValidatePortAndIndex(port, index)) | |
| 139 return false; | |
| 140 if (port != PORT_INPUT) { | |
| 141 DVLOG(1) << "SharedBuffer is only supported for input"; | |
| 142 return false; | |
| 143 } | |
| 144 InputRecord* input_record = &input_records_[index]; | |
| 145 input_record->handle = std::move(handle); | |
| 146 input_record->offset = offset; | |
| 147 input_record->length = length; | |
| 148 return true; | |
| 149 } | |
| 150 | |
| 151 bool ArcGpuVideoDecodeAccelerator::BindDmabuf(PortType port, | |
| 152 uint32_t index, | |
| 153 int dmabuf_fd) { | |
| 154 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 155 base::ScopedFD handle(dmabuf_fd); | |
| 156 | |
| 157 // Make sure we will close the file descriptor. | |
|
kcwu
2016/01/20 09:11:05
this comment should be in front of line 155
Owen Lin
2016/02/02 09:08:06
Done.
| |
| 158 if (!ValidatePortAndIndex(port, index)) | |
| 159 return false; | |
| 160 if (port != PORT_OUTPUT) { | |
| 161 DVLOG(1) << "GraphicBuffer is only supported for input"; | |
| 162 return false; | |
| 163 } | |
| 164 std::vector<base::ScopedFD> dmabuf_fds; | |
| 165 dmabuf_fds.push_back(std::move(handle)); | |
| 166 vda_->ImportBufferForPicture(index, std::move(dmabuf_fds)); | |
| 167 return true; | |
| 168 } | |
| 169 | |
| 170 void ArcGpuVideoDecodeAccelerator::UseBuffer(PortType port, | |
| 171 uint32_t index, | |
| 172 const BufferMetadata& metadata) { | |
| 173 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 174 if (!ValidatePortAndIndex(port, index)) { | |
| 175 arc_client_->OnError(INVALID_ARGUMENT); | |
| 176 return; | |
| 177 } | |
| 178 switch (port) { | |
| 179 case PORT_INPUT: { | |
| 180 InputRecord* input_record = &input_records_[index]; | |
| 181 if (metadata.flags & BUFFER_FLAG_EOS) { | |
| 182 // Ask VDA to return all output pictures so that we can output an EOS | |
| 183 // picture when Flush() is done. | |
| 184 // vda_->Flush(true); | |
| 185 vda_->Flush(); | |
| 186 } | |
| 187 if (metadata.bytes_used == 0) { | |
| 188 arc_client_->OnBufferDone(PORT_INPUT, index, BufferMetadata()); | |
| 189 return; | |
| 190 } | |
| 191 input_record->bitstream_buffer_id = next_bitstream_buffer_id_; | |
| 192 // Mask against 30 bits, to avoid (undefined wraparound on signed integer) | |
| 193 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF; | |
| 194 input_record->timestamp = metadata.timestamp; | |
| 195 int dup_fd = HANDLE_EINTR(dup(input_record->handle.get())); | |
| 196 if (dup_fd < 0) { | |
| 197 DVLOG(1) << "dup() failed."; | |
| 198 arc_client_->OnError(PLATFORM_FAILURE); | |
| 199 return; | |
| 200 } | |
| 201 base::SharedMemoryHandle shared_memory_handle(dup_fd, true); | |
| 202 // TODO(owenlin): Make BitstreamBuffer surpport offset and use here. | |
| 203 media::BitstreamBuffer bitstream_buffer(input_record->bitstream_buffer_id, | |
| 204 shared_memory_handle, | |
| 205 input_record->length); | |
| 206 vda_->Decode(bitstream_buffer); | |
| 207 } | |
|
kcwu
2016/01/20 09:11:05
break;
Owen Lin
2016/02/02 09:08:06
Thanks. I spend few minutes on this. :p
| |
| 208 case PORT_OUTPUT: { | |
| 209 SendEosIfNeededOrReusePicture(index); | |
| 210 break; | |
| 211 } | |
| 212 default: | |
| 213 NOTREACHED(); | |
| 214 } | |
| 215 } | |
| 216 | |
| 217 void ArcGpuVideoDecodeAccelerator::Reset() { | |
| 218 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 219 base::RunLoop loop; | |
| 220 reset_done_callback_ = loop.QuitClosure(); | |
| 221 vda_->Reset(); | |
|
kcwu
2016/01/20 09:11:05
check vda_ is not null.
Owen Lin
2016/02/02 09:08:06
Done.
| |
| 222 base::MessageLoop::ScopedNestableTaskAllower allow( | |
| 223 base::MessageLoop::current()); | |
| 224 // Wait for the ResetDone callback. | |
| 225 loop.Run(); | |
| 226 } | |
| 227 | |
| 228 void ArcGpuVideoDecodeAccelerator::ProvidePictureBuffers( | |
| 229 size_t requested_num_of_buffers, | |
| 230 const gfx::Size& dimensions, | |
| 231 uint32_t texture_target) { | |
| 232 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 233 coded_size_ = dimensions; | |
| 234 // TODO(owenlin): use VDA::GetOutputFormat() here. | |
| 235 VideoFormat video_format; | |
| 236 video_format.min_num_buffers = requested_num_of_buffers; | |
| 237 video_format.coded_width = dimensions.width(); | |
| 238 video_format.coded_height = dimensions.height(); | |
| 239 arc_client_->OnOutputFormatChanged(video_format); | |
| 240 } | |
| 241 | |
| 242 void ArcGpuVideoDecodeAccelerator::PictureReady(const media::Picture& picture) { | |
| 243 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 244 if (!ValidatePortAndIndex(PORT_OUTPUT, picture.picture_buffer_id())) { | |
| 245 DVLOG(1) << "Invalid index: " << picture.picture_buffer_id(); | |
| 246 arc_client_->OnError(PLATFORM_FAILURE); | |
| 247 return; | |
| 248 } | |
| 249 | |
| 250 // Empty buffer, returned in Flushing. | |
| 251 if (picture.bitstream_buffer_id() == -1) { | |
| 252 buffers_pending_eos_.push(picture.picture_buffer_id()); | |
| 253 return; | |
| 254 } | |
| 255 uint32_t index = | |
| 256 FindInputRecordByBitstreamBufferId(picture.bitstream_buffer_id()); | |
| 257 PortInfo* input_port = &port_info_[PORT_INPUT]; | |
| 258 if (index >= input_port->num_buffers) { | |
| 259 DVLOG(1) << "Cannot find for bitstream buffer id: " | |
| 260 << picture.bitstream_buffer_id(); | |
| 261 arc_client_->OnError(PLATFORM_FAILURE); | |
| 262 return; | |
| 263 } | |
| 264 | |
| 265 BufferMetadata metadata; | |
| 266 metadata.timestamp = input_records_[index].timestamp; | |
| 267 arc_client_->OnBufferDone(PORT_OUTPUT, picture.picture_buffer_id(), metadata); | |
| 268 } | |
| 269 | |
| 270 void ArcGpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( | |
| 271 int32_t bitstream_buffer_id) { | |
| 272 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 273 uint32_t index = FindInputRecordByBitstreamBufferId(bitstream_buffer_id); | |
| 274 if (!ValidatePortAndIndex(PORT_INPUT, index)) { | |
| 275 arc_client_->OnError(PLATFORM_FAILURE); | |
| 276 return; | |
| 277 } | |
| 278 arc_client_->OnBufferDone(PORT_INPUT, index, BufferMetadata()); | |
| 279 } | |
| 280 | |
| 281 void ArcGpuVideoDecodeAccelerator::NotifyFlushDone() { | |
| 282 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 283 pending_eos_output_buffer_ = true; | |
| 284 while (!buffers_pending_eos_.empty()) { | |
| 285 SendEosIfNeededOrReusePicture(buffers_pending_eos_.front()); | |
| 286 buffers_pending_eos_.pop(); | |
| 287 } | |
| 288 } | |
| 289 | |
| 290 void ArcGpuVideoDecodeAccelerator::NotifyResetDone() { | |
| 291 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 292 base::ResetAndReturn(&reset_done_callback_).Run(); | |
| 293 } | |
| 294 | |
| 295 static ArcVideoAccelerator::Error ConvertErrorCode( | |
| 296 media::VideoDecodeAccelerator::Error error) { | |
| 297 switch (error) { | |
| 298 case media::VideoDecodeAccelerator::ILLEGAL_STATE: | |
| 299 return ArcVideoAccelerator::ILLEGAL_STATE; | |
| 300 case media::VideoDecodeAccelerator::INVALID_ARGUMENT: | |
| 301 return ArcVideoAccelerator::INVALID_ARGUMENT; | |
| 302 case media::VideoDecodeAccelerator::UNREADABLE_INPUT: | |
| 303 return ArcVideoAccelerator::UNREADABLE_INPUT; | |
| 304 case media::VideoDecodeAccelerator::PLATFORM_FAILURE: | |
| 305 return ArcVideoAccelerator::PLATFORM_FAILURE; | |
| 306 default: | |
| 307 DVLOG(1) << "Unknown error: " << error; | |
| 308 return ArcVideoAccelerator::PLATFORM_FAILURE; | |
| 309 } | |
| 310 } | |
| 311 | |
| 312 void ArcGpuVideoDecodeAccelerator::NotifyError( | |
| 313 media::VideoDecodeAccelerator::Error error) { | |
| 314 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 315 arc_client_->OnError(ConvertErrorCode(error)); | |
| 316 } | |
| 317 | |
| 318 void ArcGpuVideoDecodeAccelerator::SendEosIfNeededOrReusePicture( | |
| 319 uint32_t index) { | |
| 320 if (pending_eos_output_buffer_) { | |
| 321 BufferMetadata metadata; | |
| 322 metadata.flags = BUFFER_FLAG_EOS; | |
| 323 arc_client_->OnBufferDone(PORT_OUTPUT, index, metadata); | |
| 324 pending_eos_output_buffer_ = false; | |
| 325 } else { | |
| 326 vda_->ReusePictureBuffer(index); | |
| 327 } | |
| 328 } | |
| 329 | |
| 330 uint32_t ArcGpuVideoDecodeAccelerator::FindInputRecordByBitstreamBufferId( | |
| 331 int32_t bitstream_buffer_id) { | |
| 332 uint32_t index = 0; | |
| 333 for (; index < input_records_.size(); ++index) { | |
| 334 if (input_records_[index].bitstream_buffer_id == bitstream_buffer_id) | |
| 335 break; | |
| 336 } | |
| 337 return index; | |
| 338 } | |
| 339 | |
| 340 } // arc | |
| 341 } // content | |
| OLD | NEW |