Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 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::BufferInfo::BufferInfo() | |
| 14 : state(OWNED_BY_CLIENT), offset(0), length(0) {} | |
| 15 | |
| 16 ArcGpuVideoDecodeAccelerator::PortInfo::PortInfo() | |
| 17 : memory_type(MEMORY_DMABUF) {} | |
| 18 | |
| 19 ArcGpuVideoDecodeAccelerator::InputRecord::InputRecord( | |
| 20 int32_t bitstream_buffer_id, | |
| 21 uint32_t index, | |
| 22 int64_t timestamp) | |
| 23 : bitstream_buffer_id(bitstream_buffer_id), | |
| 24 index(index), | |
| 25 timestamp(timestamp) {} | |
| 26 | |
| 27 ArcGpuVideoDecodeAccelerator::ArcGpuVideoDecodeAccelerator() | |
| 28 : arc_client_(nullptr) {} | |
| 29 | |
| 30 status_t ArcGpuVideoDecodeAccelerator::initialize( | |
| 31 DeviceType device, | |
| 32 ArcVideoAccelerator::Client* client) { | |
| 33 if (device != DEVICE_DECODER) | |
| 34 return EINVAL; | |
| 35 DCHECK(client); | |
| 36 DCHECK(!arc_client_); | |
| 37 arc_client_ = client; | |
| 38 return 0; | |
| 39 } | |
| 40 | |
| 41 status_t ArcGpuVideoDecodeAccelerator::setBufferCount(PortType port, | |
| 42 size_t* count) { | |
| 43 if (arc_vda_ == nullptr) { | |
| 44 DVLOG(1) << "Must call setBufferFormat before setBufferCount"; | |
| 45 return EINVAL; | |
| 46 } | |
| 47 if (port == PORT_OUTPUT) { | |
| 48 size_t try_count = *count; | |
| 49 for (; try_count > 0; --try_count) { | |
| 50 if (arc_vda_->SetPictureCount(*count)) { | |
| 51 *count = try_count; | |
| 52 break; | |
| 53 } | |
| 54 } | |
| 55 if (try_count == 0) { | |
| 56 DVLOG(1) << "Failed to find valid buffer count"; | |
| 57 return EIO; | |
| 58 } | |
| 59 } | |
| 60 PortInfo* port_info = &port_info_[port]; | |
|
kcwu
2015/12/23 06:25:43
validate value of |port|
Owen Lin
2015/12/31 07:22:14
Done.
| |
| 61 port_info->buffers.clear(); | |
| 62 port_info->buffers.resize(*count); | |
| 63 return 0; | |
| 64 } | |
| 65 | |
| 66 status_t ArcGpuVideoDecodeAccelerator::setBufferFormat( | |
| 67 PortType port, | |
| 68 const BufferFormat& format) { | |
| 69 PortInfo* port_info = &port_info_[port]; | |
| 70 switch (port) { | |
| 71 case PORT_INPUT: | |
| 72 if (format.memory_type != MEMORY_SHARED_MEMORY) { | |
| 73 DVLOG(1) << "Only SharedMemory is supported for input buffers"; | |
| 74 return EINVAL; | |
| 75 } | |
| 76 port_info->memory_type = format.memory_type; | |
| 77 switch (format.pixel_format) { | |
| 78 case HAL_PIXEL_FORMAT_H264: | |
| 79 case HAL_PIXEL_FORMAT_VP8: | |
| 80 arc_vda_ = nullptr; // TODO(owenlin): Change to real implementation. | |
| 81 break; | |
| 82 default: | |
| 83 DVLOG(1) << "Unsupported input format: " << format.pixel_format; | |
| 84 return EINVAL; | |
| 85 } | |
| 86 break; | |
| 87 case PORT_OUTPUT: | |
| 88 if (format.memory_type != MEMORY_DMABUF) { | |
| 89 DVLOG(1) << "Only DMA buffer is supported for output buffers"; | |
| 90 return EINVAL; | |
| 91 } | |
| 92 port_info->memory_type = format.memory_type; | |
| 93 break; | |
| 94 default: | |
| 95 NOTREACHED(); | |
|
kcwu
2015/12/23 06:25:43
return EINVAL;
|port| may come from less trusted c
Owen Lin
2015/12/31 07:22:14
Done.
| |
| 96 } | |
| 97 return 0; | |
| 98 } | |
| 99 | |
| 100 ArcGpuVideoDecodeAccelerator::BufferInfo* | |
| 101 ArcGpuVideoDecodeAccelerator::GetBufferInfo(PortType port, uint32_t index) { | |
| 102 if (port < 0 || port >= PORT_COUNT) | |
| 103 return nullptr; | |
| 104 std::vector<BufferInfo>* buffers = &port_info_[port].buffers; | |
|
kcwu
2015/12/23 06:25:43
How about:
auto& buffers = port_info_[port].buffer
Owen Lin
2015/12/31 07:22:14
Done.
| |
| 105 return index >= buffers->size() ? nullptr : &buffers->at(index); | |
| 106 } | |
| 107 | |
| 108 status_t ArcGpuVideoDecodeAccelerator::bindSharedBuffer(PortType port, | |
| 109 uint32_t index, | |
| 110 int ashmem_fd, | |
| 111 size_t offset, | |
| 112 size_t length) { | |
| 113 // Make sure we will close the file descriptor. | |
| 114 base::ScopedFD handle(ashmem_fd); | |
| 115 PortInfo* port_info = &port_info_[port]; | |
|
kcwu
2015/12/23 06:25:43
Value of |port| need to validate.
Please either
1.
Owen Lin
2015/12/31 07:22:14
Done.
| |
| 116 if (port_info->memory_type != MEMORY_SHARED_MEMORY) { | |
| 117 DVLOG(1) << "Unmatched memory type: " << port_info->memory_type; | |
| 118 return EINVAL; | |
| 119 } | |
| 120 BufferInfo* buffer_info = GetBufferInfo(port, index); | |
| 121 if (buffer_info == nullptr) { | |
| 122 DVLOG(1) << "Invalid buffer port: " << port << " index: " << index; | |
| 123 return EINVAL; | |
| 124 } | |
| 125 if (buffer_info->state != OWNED_BY_CLIENT) { | |
| 126 DVLOG(1) << "Cannot bind a buffer while in use"; | |
| 127 return EINVAL; | |
| 128 } | |
| 129 buffer_info->handle = std::move(handle); | |
| 130 buffer_info->offset = offset; | |
| 131 buffer_info->length = length; | |
| 132 return 0; | |
| 133 } | |
| 134 | |
| 135 status_t ArcGpuVideoDecodeAccelerator::bindGraphicBuffer(PortType port, | |
| 136 uint32_t index, | |
| 137 int dmabuf_fd) { | |
| 138 // Make sure we will close the file descriptor. | |
| 139 base::ScopedFD handle(dmabuf_fd); | |
| 140 PortInfo* port_info = &port_info_[port]; | |
|
kcwu
2015/12/23 06:25:43
Ditto, check value of |port|
Owen Lin
2015/12/31 07:22:14
Done.
| |
| 141 if (port_info->memory_type != MEMORY_DMABUF) { | |
| 142 DVLOG(1) << "Unmatched memory type: " << port_info->memory_type; | |
| 143 return EINVAL; | |
| 144 } | |
| 145 BufferInfo* buffer_info = GetBufferInfo(port, index); | |
| 146 if (buffer_info == nullptr) { | |
| 147 DVLOG(1) << "Invalid buffer port: " << port << " index: " << index; | |
| 148 return EINVAL; | |
| 149 } | |
| 150 if (buffer_info->state != OWNED_BY_CLIENT) { | |
| 151 DVLOG(1) << "Cannot bind a buffer while in use"; | |
| 152 return EINVAL; | |
| 153 } | |
| 154 return arc_vda_->AssignPictureBuffer(index, std::move(handle)) ? 0 : EIO; | |
| 155 } | |
| 156 | |
| 157 void ArcGpuVideoDecodeAccelerator::useBuffer(PortType port, | |
| 158 uint32_t index, | |
| 159 const BufferMetadata& metadata) { | |
| 160 BufferInfo* buffer_info = GetBufferInfo(port, index); | |
| 161 if (buffer_info == nullptr) { | |
| 162 DVLOG(1) << "Invalid buffer port: " << port << ", index: " << index; | |
| 163 arc_client_->onError(INVALID_ARGUMENT); | |
| 164 return; | |
| 165 } | |
| 166 if (!buffer_info->handle.is_valid()) { | |
| 167 DVLOG(1) << "Must bind a buffer before using it, port: " << port | |
| 168 << ", index: " << index; | |
| 169 arc_client_->onError(ILLEGAL_STATE); | |
| 170 return; | |
| 171 } | |
| 172 buffer_info->state = OWNED_BY_US; | |
| 173 switch (port) { | |
| 174 case PORT_INPUT: { | |
| 175 if (metadata.flags & BUFFER_FLAG_EOS) { | |
| 176 // Ask VDA to return all output pictures so that we can output an EOS | |
| 177 // picture when Flush() is done. | |
| 178 arc_vda_->Flush(true); | |
| 179 } | |
| 180 if (metadata.bytes_used > 0) { | |
| 181 int32_t bitstream_buffer_id = bitstream_buffer_serial_++; | |
| 182 if (bitstream_buffer_serial_ < 0) | |
| 183 bitstream_buffer_serial_ = 0; | |
| 184 SetInputRecord(bitstream_buffer_id, index, metadata.timestamp); | |
| 185 base::SharedMemoryHandle shared_memory_handle(buffer_info->handle.get(), | |
|
kcwu
2015/12/23 06:25:43
when will the handle be closed?
Owen Lin
2015/12/31 07:22:14
For now, it will be close when this ArcGVDA destro
| |
| 186 false); | |
| 187 // TODO(owenlin): Make BitstreamBuffer surpport offset and use here. | |
| 188 media::BitstreamBuffer bitstream_buffer( | |
| 189 bitstream_buffer_id, shared_memory_handle, buffer_info->length); | |
| 190 buffer_info->state = OWNED_BY_VDA; | |
| 191 arc_vda_->Decode(bitstream_buffer); | |
| 192 } else { | |
| 193 buffer_info->state = OWNED_BY_CLIENT; | |
| 194 arc_client_->onBufferDone(PORT_INPUT, index, BufferMetadata()); | |
| 195 } | |
| 196 break; | |
| 197 } | |
| 198 case PORT_OUTPUT: { | |
| 199 SendEosIfNeededOrReusePicture(index, buffer_info); | |
| 200 break; | |
| 201 } | |
| 202 default: | |
| 203 NOTREACHED(); | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 void ArcGpuVideoDecodeAccelerator::reset() { | |
| 208 base::RunLoop loop; | |
| 209 reset_done_callback_ = loop.QuitClosure(); | |
| 210 arc_vda_->Reset(); | |
| 211 base::MessageLoop::ScopedNestableTaskAllower allow( | |
| 212 base::MessageLoop::current()); | |
| 213 // Wait for the ResetDone callback. | |
| 214 loop.Run(); | |
| 215 } | |
| 216 | |
| 217 void ArcGpuVideoDecodeAccelerator::RequestPictureBuffers( | |
| 218 size_t requested_num_of_buffers, | |
| 219 const gfx::Size& coded_size, | |
| 220 const gfx::Rect& crop_rect) { | |
| 221 // TODO(owenlin): Think if we need to handle the pixel format. | |
| 222 // It looks like the flexible pixel format is good enough. | |
| 223 VideoFormat video_format; | |
| 224 video_format.min_num_buffers = requested_num_of_buffers; | |
| 225 video_format.coded_width = coded_size.width(); | |
| 226 video_format.coded_height = coded_size.height(); | |
| 227 video_format.crop_left = crop_rect.x(); | |
| 228 video_format.crop_top = crop_rect.y(); | |
| 229 video_format.crop_width = crop_rect.width(); | |
| 230 video_format.crop_height = crop_rect.height(); | |
| 231 arc_client_->onOutputFormatChanged(video_format); | |
| 232 } | |
| 233 | |
| 234 void ArcGpuVideoDecodeAccelerator::PictureReady(const media::Picture& picture) { | |
| 235 BufferInfo* output_buffer = | |
| 236 GetBufferInfo(PORT_OUTPUT, picture.picture_buffer_id()); | |
| 237 CHECK_NE(output_buffer, nullptr); | |
| 238 | |
| 239 // Empty buffer, returned in Flushing. | |
| 240 if (picture.bitstream_buffer_id() == -1) { | |
| 241 output_buffer->state = OWNED_BY_US; | |
| 242 } else { | |
| 243 BufferMetadata metadata; | |
| 244 uint32_t index = 0; | |
| 245 GetInputRecord(picture.bitstream_buffer_id(), &index, &metadata.timestamp); | |
| 246 output_buffer->state = OWNED_BY_CLIENT; | |
| 247 arc_client_->onBufferDone(PORT_OUTPUT, picture.picture_buffer_id(), | |
| 248 metadata); | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 void ArcGpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( | |
| 253 int32_t bitstream_buffer_id) { | |
| 254 int64_t timestamp = 0; | |
| 255 uint32_t index = 0; | |
| 256 GetInputRecord(bitstream_buffer_id, &index, ×tamp); | |
| 257 BufferInfo* buffer_info = GetBufferInfo(PORT_OUTPUT, index); | |
| 258 CHECK(buffer_info); | |
| 259 buffer_info->state = OWNED_BY_CLIENT; | |
| 260 arc_client_->onBufferDone(PORT_INPUT, bitstream_buffer_id, BufferMetadata()); | |
| 261 } | |
| 262 | |
| 263 void ArcGpuVideoDecodeAccelerator::NotifyFlushDone() { | |
| 264 pending_eos_output_buffer_ = true; | |
| 265 std::vector<BufferInfo>* buffers = &port_info_[PORT_OUTPUT].buffers; | |
| 266 for (size_t i = 0, n = buffers->size(); i < n; ++i) { | |
| 267 BufferInfo* info = &buffers->at(i); | |
| 268 if (info->state == OWNED_BY_US) | |
| 269 SendEosIfNeededOrReusePicture(i, info); | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 void ArcGpuVideoDecodeAccelerator::NotifyResetDone() { | |
| 274 base::ResetAndReturn(&reset_done_callback_).Run(); | |
| 275 } | |
| 276 | |
| 277 static ArcVideoAccelerator::Error convertErrorCode( | |
|
kcwu
2015/12/23 06:25:43
s/convert/Convert/
Owen Lin
2015/12/31 07:22:14
Done.
| |
| 278 ArcVideoDecodeAccelerator::Error error) { | |
| 279 #define CASE(t) \ | |
| 280 case ArcVideoDecodeAccelerator::t: \ | |
| 281 return ArcVideoAccelerator::t | |
| 282 switch (error) { | |
| 283 CASE(ILLEGAL_STATE); | |
| 284 CASE(INVALID_ARGUMENT); | |
| 285 CASE(UNREADABLE_INPUT); | |
| 286 CASE(PLATFORM_FAILURE); | |
| 287 default: | |
| 288 NOTREACHED() << "Unknown error: " << error; | |
| 289 } | |
| 290 #undef CASE | |
| 291 return static_cast<ArcVideoAccelerator::Error>(error); | |
| 292 } | |
| 293 | |
| 294 void ArcGpuVideoDecodeAccelerator::NotifyError( | |
| 295 ArcVideoDecodeAccelerator::Error error) { | |
| 296 arc_client_->onError(convertErrorCode(error)); | |
| 297 } | |
| 298 | |
| 299 void ArcGpuVideoDecodeAccelerator::SendEosIfNeededOrReusePicture( | |
| 300 uint32_t index, | |
| 301 BufferInfo* info) { | |
| 302 DCHECK_EQ(info->state, OWNED_BY_US); | |
| 303 if (pending_eos_output_buffer_) { | |
| 304 BufferMetadata metadata; | |
| 305 metadata.flags = BUFFER_FLAG_EOS; | |
| 306 info->state = OWNED_BY_CLIENT; | |
| 307 arc_client_->onBufferDone(PORT_OUTPUT, index, metadata); | |
| 308 pending_eos_output_buffer_ = false; | |
| 309 } else { | |
| 310 info->state = OWNED_BY_VDA; | |
| 311 arc_vda_->ReusePictureBuffer(index); | |
| 312 } | |
| 313 } | |
| 314 | |
| 315 void ArcGpuVideoDecodeAccelerator::SetInputRecord(int32_t bitstream_buffer_id, | |
| 316 uint32_t index, | |
| 317 int64_t timestamp) { | |
| 318 input_records_.push_front(InputRecord(bitstream_buffer_id, index, timestamp)); | |
| 319 // The value is copied from media::GpuVideoDecoder. | |
| 320 static const size_t kMaxInputBufferDataSize = 128; | |
|
kcwu
2015/12/23 06:25:43
s/static//
local constant doesn't need static stor
Owen Lin
2015/12/31 07:22:14
Done.
| |
| 321 if (input_records_.size() > kMaxInputBufferDataSize) | |
| 322 input_records_.pop_back(); | |
| 323 } | |
| 324 | |
| 325 void ArcGpuVideoDecodeAccelerator::GetInputRecord(int32_t bitstream_buffer_id, | |
| 326 uint32_t* index, | |
| 327 int64_t* timestamp) { | |
| 328 for (auto& data : input_records_) { | |
| 329 if (data.bitstream_buffer_id == bitstream_buffer_id) { | |
| 330 *index = data.index; | |
| 331 *timestamp = data.timestamp; | |
| 332 return; | |
| 333 } | |
| 334 } | |
| 335 NOTREACHED() << "Missing bitstream_buffer_id: " << bitstream_buffer_id; | |
| 336 } | |
| 337 | |
| 338 } // arc | |
| 339 } // content | |
| OLD | NEW |