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

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

Powered by Google App Engine
This is Rietveld 408576698