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

Side by Side Diff: chrome/gpu/arc_gpu_video_decode_accelerator.cc

Issue 1549473002: Add ArcGpuVideoDecodeAccelerator. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: add out-of-line ctor/dtor Created 4 years, 8 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 unified diff | Download patch
« no previous file with comments | « chrome/gpu/arc_gpu_video_decode_accelerator.h ('k') | chrome/gpu/gpu_arc_video_service.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 "chrome/gpu/arc_gpu_video_decode_accelerator.h"
9 #include "content/public/gpu/gpu_video_decode_accelerator_factory.h"
10 #include "media/base/video_frame.h"
11
12 namespace chromeos {
13 namespace arc {
14
15 ArcGpuVideoDecodeAccelerator::InputRecord::InputRecord(
16 int32_t bitstream_buffer_id,
17 uint32_t buffer_index,
18 int64_t timestamp)
19 : bitstream_buffer_id(bitstream_buffer_id),
20 buffer_index(buffer_index),
21 timestamp(timestamp) {}
22
23 ArcGpuVideoDecodeAccelerator::InputBufferInfo::InputBufferInfo()
24 : offset(0), length(0) {}
25
26 ArcGpuVideoDecodeAccelerator::InputBufferInfo::InputBufferInfo(
27 InputBufferInfo&& other)
28 : handle(std::move(other.handle)),
29 offset(other.offset),
30 length(other.length) {}
31
32 ArcGpuVideoDecodeAccelerator::InputBufferInfo::~InputBufferInfo() {}
33
34 ArcGpuVideoDecodeAccelerator::ArcGpuVideoDecodeAccelerator()
35 : pending_eos_output_buffer_(false),
36 arc_client_(nullptr),
37 next_bitstream_buffer_id_(0),
38 output_buffer_size_(0) {}
39
40 ArcGpuVideoDecodeAccelerator::~ArcGpuVideoDecodeAccelerator() {}
41
42 namespace {
43
44 // An arbitrary chosen limit of the number of buffers. The number of
45 // buffers used is requested from the untrusted client side.
46 const size_t kMaxBufferCount = 128;
47
48 } // anonymous namespace
49
50 bool ArcGpuVideoDecodeAccelerator::Initialize(
51 const Config& config,
52 ArcVideoAccelerator::Client* client) {
53 DVLOG(5) << "Initialize(device=" << config.device_type
54 << ", input_pixel_format=" << config.input_pixel_format
55 << ", num_input_buffers=" << config.num_input_buffers << ")";
56 DCHECK(thread_checker_.CalledOnValidThread());
57 if (config.device_type != Config::DEVICE_DECODER)
58 return false;
59 DCHECK(client);
60
61 if (arc_client_) {
62 DLOG(ERROR) << "Re-Initialize() is not allowed";
63 return false;
64 }
65
66 arc_client_ = client;
67
68 if (config.num_input_buffers > kMaxBufferCount) {
69 DLOG(ERROR) << "Request too many buffers: " << config.num_input_buffers;
70 return false;
71 }
72 input_buffer_info_.resize(config.num_input_buffers);
73
74 media::VideoDecodeAccelerator::Config vda_config;
75 switch (config.input_pixel_format) {
76 case HAL_PIXEL_FORMAT_H264:
77 vda_config.profile = media::H264PROFILE_MAIN;
78 break;
79 case HAL_PIXEL_FORMAT_VP8:
80 vda_config.profile = media::VP8PROFILE_ANY;
81 break;
82 default:
83 DLOG(ERROR) << "Unsupported input format: " << config.input_pixel_format;
84 return false;
85 }
86 vda_config.output_mode =
87 media::VideoDecodeAccelerator::Config::OutputMode::IMPORT;
88
89 scoped_ptr<content::GpuVideoDecodeAcceleratorFactory> vda_factory =
90 content::GpuVideoDecodeAcceleratorFactory::CreateWithNoGL();
91 vda_ = vda_factory->CreateVDA(this, vda_config);
92 if (!vda_) {
93 DLOG(ERROR) << "Failed to create VDA.";
94 return false;
95 }
96 return true;
97 }
98
99 void ArcGpuVideoDecodeAccelerator::SetNumberOfOutputBuffers(size_t number) {
100 DVLOG(5) << "SetNumberOfOutputBuffers(" << number << ")";
101 DCHECK(thread_checker_.CalledOnValidThread());
102 if (!vda_) {
103 DLOG(ERROR) << "VDA not initialized";
104 return;
105 }
106
107 if (number > kMaxBufferCount) {
108 DLOG(ERROR) << "Too many buffers: " << number;
109 arc_client_->OnError(INVALID_ARGUMENT);
110 return;
111 }
112
113 std::vector<media::PictureBuffer> buffers;
114 for (size_t id = 0; id < number; ++id) {
115 media::PictureBuffer::TextureIds texture_ids;
116 texture_ids.push_back(0);
117
118 // TODO(owenlin): Make sure the |coded_size| is what we want.
119 buffers.push_back(media::PictureBuffer(base::checked_cast<int32_t>(id),
120 coded_size_, texture_ids));
121 }
122 vda_->AssignPictureBuffers(buffers);
123
124 buffers_pending_import_.clear();
125 buffers_pending_import_.resize(number);
126 }
127
128 void ArcGpuVideoDecodeAccelerator::BindSharedMemory(PortType port,
129 uint32_t index,
130 base::ScopedFD ashmem_fd,
131 off_t offset,
132 size_t length) {
133 DVLOG(5) << "ArcGVDA::BindSharedMemory, offset: " << offset
134 << ", length: " << length;
135 DCHECK(thread_checker_.CalledOnValidThread());
136 if (!vda_) {
137 DLOG(ERROR) << "VDA not initialized";
138 return;
139 }
140
141 if (port != PORT_INPUT) {
142 DLOG(ERROR) << "SharedBuffer is only supported for input";
143 arc_client_->OnError(INVALID_ARGUMENT);
144 return;
145 }
146 if (!ValidatePortAndIndex(port, index)) {
147 arc_client_->OnError(INVALID_ARGUMENT);
148 return;
149 }
150 InputBufferInfo* input_info = &input_buffer_info_[index];
151 input_info->handle = std::move(ashmem_fd);
152 input_info->offset = offset;
153 input_info->length = length;
154 }
155
156 void ArcGpuVideoDecodeAccelerator::BindDmabuf(PortType port,
157 uint32_t index,
158 base::ScopedFD dmabuf_fd) {
159 DCHECK(thread_checker_.CalledOnValidThread());
160
161 if (!vda_) {
162 DLOG(ERROR) << "VDA not initialized";
163 return;
164 }
165
166 if (port != PORT_OUTPUT) {
167 DLOG(ERROR) << "Dmabuf is only supported for input";
168 arc_client_->OnError(INVALID_ARGUMENT);
169 return;
170 }
171 if (!ValidatePortAndIndex(port, index)) {
172 arc_client_->OnError(INVALID_ARGUMENT);
173 return;
174 }
175 buffers_pending_import_[index] = std::move(dmabuf_fd);
176 }
177
178 void ArcGpuVideoDecodeAccelerator::UseBuffer(PortType port,
179 uint32_t index,
180 const BufferMetadata& metadata) {
181 DVLOG(5) << "UseBuffer(port=" << port << ", index=" << index
182 << ", metadata=(bytes_used=" << metadata.bytes_used
183 << ", timestamp=" << metadata.timestamp << ")";
184 DCHECK(thread_checker_.CalledOnValidThread());
185 if (!vda_) {
186 DLOG(ERROR) << "VDA not initialized";
187 return;
188 }
189 if (!ValidatePortAndIndex(port, index)) {
190 arc_client_->OnError(INVALID_ARGUMENT);
191 return;
192 }
193 switch (port) {
194 case PORT_INPUT: {
195 InputBufferInfo* input_info = &input_buffer_info_[index];
196 int32_t bitstream_buffer_id = next_bitstream_buffer_id_;
197 // Mask against 30 bits, to avoid (undefined) wraparound on signed
198 // integer.
199 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF;
200 int dup_fd = HANDLE_EINTR(dup(input_info->handle.get()));
201 if (dup_fd < 0) {
202 DLOG(ERROR) << "dup() failed.";
203 arc_client_->OnError(PLATFORM_FAILURE);
204 return;
205 }
206 CreateInputRecord(bitstream_buffer_id, index, metadata.timestamp);
207 vda_->Decode(media::BitstreamBuffer(
208 bitstream_buffer_id, base::SharedMemoryHandle(dup_fd, true),
209 metadata.bytes_used, input_info->offset));
210 if (metadata.flags & BUFFER_FLAG_EOS) {
211 vda_->Flush();
212 }
213 break;
214 }
215 case PORT_OUTPUT: {
216 SendEosIfNeededOrReusePicture(index);
217 break;
218 }
219 default:
220 NOTREACHED();
221 }
222 }
223
224 void ArcGpuVideoDecodeAccelerator::Reset() {
225 DCHECK(thread_checker_.CalledOnValidThread());
226 if (!vda_) {
227 DLOG(ERROR) << "VDA not initialized";
228 return;
229 }
230 vda_->Reset();
231 }
232
233 void ArcGpuVideoDecodeAccelerator::ProvidePictureBuffers(
234 uint32_t requested_num_of_buffers,
235 uint32_t textures_per_buffer,
236 const gfx::Size& dimensions,
237 uint32_t texture_target) {
238 DVLOG(5) << "ProvidePictureBuffers("
239 << "requested_num_of_buffers=" << requested_num_of_buffers
240 << ", dimensions=" << dimensions.ToString() << ")";
241 DCHECK(thread_checker_.CalledOnValidThread());
242 coded_size_ = dimensions;
243
244 VideoFormat video_format;
245 media::VideoPixelFormat output_format = vda_->GetOutputFormat();
246 switch (output_format) {
247 case media::PIXEL_FORMAT_I420:
248 case media::PIXEL_FORMAT_YV12:
249 case media::PIXEL_FORMAT_NV12:
250 case media::PIXEL_FORMAT_NV21:
251 // HAL_PIXEL_FORMAT_YCbCr_420_888 is the flexible pixel format in Android
252 // which handles all 420 formats, with both orderings of chroma (CbCr and
253 // CrCb) as well as planar and semi-planar layouts.
254 video_format.pixel_format = HAL_PIXEL_FORMAT_YCbCr_420_888;
255 break;
256 default:
257 DLOG(ERROR) << "Format not supported: " << output_format;
258 arc_client_->OnError(PLATFORM_FAILURE);
259 return;
260 }
261 video_format.buffer_size =
262 media::VideoFrame::AllocationSize(output_format, coded_size_);
263 output_buffer_size_ = video_format.buffer_size;
264 video_format.min_num_buffers = requested_num_of_buffers;
265 video_format.coded_width = dimensions.width();
266 video_format.coded_height = dimensions.height();
267 // TODO(owenlin): How to get visible size?
268 video_format.crop_top = 0;
269 video_format.crop_left = 0;
270 video_format.crop_width = dimensions.width();
271 video_format.crop_height = dimensions.height();
272 arc_client_->OnOutputFormatChanged(video_format);
273 }
274
275 void ArcGpuVideoDecodeAccelerator::DismissPictureBuffer(
276 int32_t picture_buffer) {
277 // no-op
278 }
279
280 void ArcGpuVideoDecodeAccelerator::PictureReady(const media::Picture& picture) {
281 DVLOG(5) << "PictureReady(picture_buffer_id=" << picture.picture_buffer_id()
282 << ", bitstream_buffer_id=" << picture.bitstream_buffer_id();
283 DCHECK(thread_checker_.CalledOnValidThread());
284
285 // Empty buffer, returned in Flushing.
286 if (picture.bitstream_buffer_id() == -1) {
287 buffers_pending_eos_.push(picture.picture_buffer_id());
288 return;
289 }
290 InputRecord* input_record = FindInputRecord(picture.bitstream_buffer_id());
291 if (input_record == nullptr) {
292 DLOG(ERROR) << "Cannot find for bitstream buffer id: "
293 << picture.bitstream_buffer_id();
294 arc_client_->OnError(PLATFORM_FAILURE);
295 return;
296 }
297
298 BufferMetadata metadata;
299 metadata.timestamp = input_record->timestamp;
300 metadata.bytes_used = output_buffer_size_;
301 arc_client_->OnBufferDone(PORT_OUTPUT, picture.picture_buffer_id(), metadata);
302 }
303
304 void ArcGpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer(
305 int32_t bitstream_buffer_id) {
306 DVLOG(5) << "NotifyEndOfBitstreamBuffer(" << bitstream_buffer_id << ")";
307 DCHECK(thread_checker_.CalledOnValidThread());
308 InputRecord* input_record = FindInputRecord(bitstream_buffer_id);
309 if (input_record == nullptr) {
310 arc_client_->OnError(PLATFORM_FAILURE);
311 return;
312 }
313 arc_client_->OnBufferDone(PORT_INPUT, input_record->buffer_index,
314 BufferMetadata());
315 }
316
317 void ArcGpuVideoDecodeAccelerator::NotifyFlushDone() {
318 DCHECK(thread_checker_.CalledOnValidThread());
319 pending_eos_output_buffer_ = true;
320 while (!buffers_pending_eos_.empty()) {
321 SendEosIfNeededOrReusePicture(buffers_pending_eos_.front());
322 buffers_pending_eos_.pop();
323 }
324 }
325
326 void ArcGpuVideoDecodeAccelerator::NotifyResetDone() {
327 DCHECK(thread_checker_.CalledOnValidThread());
328 arc_client_->OnResetDone();
329 }
330
331 static ArcVideoAccelerator::Error ConvertErrorCode(
332 media::VideoDecodeAccelerator::Error error) {
333 switch (error) {
334 case media::VideoDecodeAccelerator::ILLEGAL_STATE:
335 return ArcVideoAccelerator::ILLEGAL_STATE;
336 case media::VideoDecodeAccelerator::INVALID_ARGUMENT:
337 return ArcVideoAccelerator::INVALID_ARGUMENT;
338 case media::VideoDecodeAccelerator::UNREADABLE_INPUT:
339 return ArcVideoAccelerator::UNREADABLE_INPUT;
340 case media::VideoDecodeAccelerator::PLATFORM_FAILURE:
341 return ArcVideoAccelerator::PLATFORM_FAILURE;
342 default:
343 DLOG(ERROR) << "Unknown error: " << error;
344 return ArcVideoAccelerator::PLATFORM_FAILURE;
345 }
346 }
347
348 void ArcGpuVideoDecodeAccelerator::NotifyError(
349 media::VideoDecodeAccelerator::Error error) {
350 DCHECK(thread_checker_.CalledOnValidThread());
351 DLOG(ERROR) << "Error notified: " << error;
352 arc_client_->OnError(ConvertErrorCode(error));
353 }
354
355 void ArcGpuVideoDecodeAccelerator::SendEosIfNeededOrReusePicture(
356 uint32_t index) {
357 if (pending_eos_output_buffer_) {
358 BufferMetadata metadata;
359 metadata.flags = BUFFER_FLAG_EOS;
360 arc_client_->OnBufferDone(PORT_OUTPUT, index, metadata);
361 pending_eos_output_buffer_ = false;
362 } else {
363 if (buffers_pending_import_[index].is_valid()) {
364 std::vector<gfx::GpuMemoryBufferHandle> buffers;
365 buffers.push_back(gfx::GpuMemoryBufferHandle());
366 #if defined(USE_OZONE)
367 buffers.back().native_pixmap_handle.fd =
368 base::FileDescriptor(buffers_pending_import_[index].release(), true);
369 #endif
370 vda_->ImportBufferForPicture(index, buffers);
371 } else {
372 vda_->ReusePictureBuffer(index);
373 }
374 }
375 }
376
377 void ArcGpuVideoDecodeAccelerator::CreateInputRecord(
378 int32_t bitstream_buffer_id,
379 uint32_t buffer_index,
380 int64_t timestamp) {
381 input_records_.push_front(
382 InputRecord(bitstream_buffer_id, buffer_index, timestamp));
383
384 // The same value copied from media::GpuVideoDecoder. The input record is
385 // needed when the input buffer or the corresponding output buffer are
386 // returned from VDA. However there is no guarantee how much buffers will be
387 // kept in the VDA. We kept the last |kMaxNumberOfInputRecords| in
388 // |input_records_| and drop the others.
389 const size_t kMaxNumberOfInputRecords = 128;
390 if (input_records_.size() > kMaxNumberOfInputRecords)
391 input_records_.pop_back();
392 }
393
394 ArcGpuVideoDecodeAccelerator::InputRecord*
395 ArcGpuVideoDecodeAccelerator::FindInputRecord(int32_t bitstream_buffer_id) {
396 for (auto& record : input_records_) {
397 if (record.bitstream_buffer_id == bitstream_buffer_id)
398 return &record;
399 }
400 return nullptr;
401 }
402
403 bool ArcGpuVideoDecodeAccelerator::ValidatePortAndIndex(PortType port,
404 uint32_t index) {
405 switch (port) {
406 case PORT_INPUT:
407 if (index >= input_buffer_info_.size()) {
408 DLOG(ERROR) << "Invalid index: " << index;
409 return false;
410 }
411 return true;
412 case PORT_OUTPUT:
413 if (index >= buffers_pending_import_.size()) {
414 DLOG(ERROR) << "Invalid index: " << index;
415 return false;
416 }
417 return true;
418 default:
419 DLOG(ERROR) << "Invalid port: " << port;
420 return false;
421 }
422 }
423
424 } // namespace arc
425 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/gpu/arc_gpu_video_decode_accelerator.h ('k') | chrome/gpu/gpu_arc_video_service.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698