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

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: Change ArcVideoAccelerator::Reset to asynchronous. Created 4 years, 9 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
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
11 namespace chromeos {
12 namespace arc {
13
14 ArcGpuVideoDecodeAccelerator::InputRecord::InputRecord(
15 int32_t bitstream_buffer_id,
16 uint32_t buffer_index,
17 int64_t timestamp)
18 : bitstream_buffer_id(bitstream_buffer_id),
19 buffer_index(buffer_index),
20 timestamp(timestamp) {}
21
22 ArcGpuVideoDecodeAccelerator::ArcGpuVideoDecodeAccelerator()
23 : pending_eos_output_buffer_(false),
24 arc_client_(nullptr),
25 next_bitstream_buffer_id_(0),
26 output_buffer_size_(0) {}
27
28 ArcGpuVideoDecodeAccelerator::~ArcGpuVideoDecodeAccelerator() {}
29
30 // An arbitrary chosen limit of the number of buffers. The number of
31 // buffers used is requested from the client side (less trusted).
Pawel Osciak 2016/03/22 10:21:12 s/less trusted/untrusted/
Owen Lin 2016/03/24 03:01:11 Done.
32 static const size_t kMaxBufferCount = 128;
Pawel Osciak 2016/03/22 10:21:12 Perhaps anonymous namespace?
Owen Lin 2016/03/24 03:01:11 Done.
33
34 bool ArcGpuVideoDecodeAccelerator::Initialize(
35 const Config& config,
36 ArcVideoAccelerator::Client* client) {
37 DVLOG(5) << "Initialize(device=" << config.device_type
38 << ", input_pixel_format=" << config.input_pixel_format
39 << ", num_input_buffers=" << config.num_input_buffers << ")";
40 DCHECK(thread_checker_.CalledOnValidThread());
41 if (config.device_type != Config::DEVICE_DECODER)
42 return false;
43 DCHECK(client);
44 DCHECK(!arc_client_);
45 arc_client_ = client;
46
47 if (config.num_input_buffers > kMaxBufferCount) {
48 DLOG(ERROR) << "Request too many buffers: " << config.num_input_buffers;
49 return false;
50 }
51 input_buffer_info_.resize(config.num_input_buffers);
Pawel Osciak 2016/03/22 10:21:12 We should probably clear() first to release any pr
Owen Lin 2016/03/24 03:01:11 For now, let's deny re-Initialize().
52
53 media::VideoDecodeAccelerator::Config vda_config;
54 switch (config.input_pixel_format) {
55 case HAL_PIXEL_FORMAT_H264:
56 vda_config.profile = media::H264PROFILE_MAIN;
57 break;
58 case HAL_PIXEL_FORMAT_VP8:
59 vda_config.profile = media::VP8PROFILE_ANY;
60 break;
61 default:
62 DLOG(ERROR) << "Unsupported input format: " << config.input_pixel_format;
63 return false;
64 }
65 vda_config.output_mode =
66 media::VideoDecodeAccelerator::Config::OutputMode::IMPORT;
67
68 scoped_ptr<content::GpuVideoDecodeAcceleratorFactory> vda_factory =
69 content::GpuVideoDecodeAcceleratorFactory::CreateWithNoGL();
70 vda_ = std::move(vda_factory->CreateVDA(this, vda_config));
71 if (!vda_) {
72 DLOG(ERROR) << "Failed to create VDA.";
73 return false;
74 }
75 return true;
76 }
77
78 void ArcGpuVideoDecodeAccelerator::SetNumberOfOutputBuffers(size_t number) {
79 DVLOG(5) << "SetNumberOfOutputBuffers(" << number << ")";
80 DCHECK(thread_checker_.CalledOnValidThread());
81 if (!vda_) {
82 DLOG(ERROR) << "VDA not initialized";
83 return;
84 }
85
86 if (number > kMaxBufferCount) {
87 DLOG(ERROR) << "Too many buffers: " << number;
88 arc_client_->OnError(INVALID_ARGUMENT);
89 return;
90 }
91
92 std::vector<media::PictureBuffer> buffers;
93 for (int32_t id = 0, n = number; id < n; ++id) {
Pawel Osciak 2016/03/22 10:21:12 Is n needed?
Owen Lin 2016/03/24 03:01:11 Just to prevent warning about comparing signed and
94 // TODO: Make sure the |coded_size| is what we want.
95 buffers.push_back(media::PictureBuffer(id, coded_size_, 0));
96 }
97 vda_->AssignPictureBuffers(buffers);
98
99 pending_import_buffer_.clear();
100 pending_import_buffer_.resize(number);
101 }
102
103 void ArcGpuVideoDecodeAccelerator::BindSharedMemory(PortType port,
104 uint32_t index,
105 int ashmem_fd,
106 off_t offset,
107 size_t length) {
108 DVLOG(5) << "ArcGVDA::BindSharedMemory, offset: " << offset
109 << ", length: " << length;
110 DCHECK(thread_checker_.CalledOnValidThread());
111 if (!vda_) {
112 DLOG(ERROR) << "VDA not initialized";
113 return;
114 }
115
116 // Make sure we will close the file descriptor.
117 base::ScopedFD handle(ashmem_fd);
118 if (port != PORT_INPUT) {
119 DLOG(ERROR) << "SharedBuffer is only supported for input";
120 arc_client_->OnError(INVALID_ARGUMENT);
121 return;
122 }
123 if (!ValidatePortAndIndex(port, index)) {
124 arc_client_->OnError(INVALID_ARGUMENT);
125 return;
126 }
127 InputBufferInfo* input_info = &input_buffer_info_[index];
Pawel Osciak 2016/03/22 10:21:12 Do we need to make sure we don't bind over existin
Owen Lin 2016/03/24 03:01:11 Actually, it is fine to bind another buffer at any
Pawel Osciak 2016/03/25 08:38:44 Acknowledged.
128 input_info->handle = std::move(handle);
129 input_info->offset = offset;
130 input_info->length = length;
131 }
132
133 void ArcGpuVideoDecodeAccelerator::BindDmabuf(PortType port,
134 uint32_t index,
135 int dmabuf_fd) {
136 DCHECK(thread_checker_.CalledOnValidThread());
137
138 if (!vda_) {
139 DLOG(ERROR) << "VDA not initialized";
140 return;
141 }
142
143 // Make sure we will close the file descriptor.
144 base::ScopedFD handle(dmabuf_fd);
145 if (port != PORT_OUTPUT) {
146 DLOG(ERROR) << "GraphicBuffer is only supported for input";
Pawel Osciak 2016/03/22 10:21:12 s/GraphicBuffer/Dmabuf/
Owen Lin 2016/03/24 03:01:11 Done.
147 arc_client_->OnError(INVALID_ARGUMENT);
148 return;
149 }
150 if (!ValidatePortAndIndex(port, index)) {
151 arc_client_->OnError(INVALID_ARGUMENT);
152 return;
153 }
154 pending_import_buffer_[index] = std::move(handle);
155 }
156
157 void ArcGpuVideoDecodeAccelerator::UseBuffer(PortType port,
158 uint32_t index,
159 const BufferMetadata& metadata) {
160 DVLOG(5) << "UseBuffer(port=" << port << ", index=" << index
161 << ", metadata=(bytes_used=" << metadata.bytes_used
162 << ", timestamp=" << metadata.timestamp << ")";
163 DCHECK(thread_checker_.CalledOnValidThread());
164 if (!vda_) {
165 DLOG(ERROR) << "VDA not initialized";
166 return;
167 }
168 if (!ValidatePortAndIndex(port, index)) {
169 arc_client_->OnError(INVALID_ARGUMENT);
170 return;
171 }
172 switch (port) {
173 case PORT_INPUT: {
174 InputBufferInfo* input_info = &input_buffer_info_[index];
175 int32_t bitstream_buffer_id = next_bitstream_buffer_id_;
176 // Mask against 30 bits, to avoid (undefined) wraparound on signed
177 // integer.
178 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF;
179 SetInputRecord(bitstream_buffer_id, index, metadata.timestamp);
180 int dup_fd = HANDLE_EINTR(dup(input_info->handle.get()));
181 if (dup_fd < 0) {
182 DLOG(ERROR) << "dup() failed.";
183 arc_client_->OnError(PLATFORM_FAILURE);
184 return;
Pawel Osciak 2016/03/22 10:21:12 Should we first dup, and then create the InputReco
Owen Lin 2016/03/24 03:01:11 Done.
185 }
186 vda_->Decode(media::BitstreamBuffer(
187 bitstream_buffer_id, base::SharedMemoryHandle(dup_fd, true),
188 metadata.bytes_used, input_info->offset));
189 if (metadata.flags & BUFFER_FLAG_EOS) {
190 vda_->Flush(true);
191 }
192 break;
193 }
194 case PORT_OUTPUT: {
195 SendEosIfNeededOrReusePicture(index);
196 break;
197 }
198 default:
199 NOTREACHED();
200 }
201 }
202
203 void ArcGpuVideoDecodeAccelerator::Reset() {
204 DCHECK(thread_checker_.CalledOnValidThread());
205 if (!vda_) {
206 DLOG(ERROR) << "VDA not initialized";
207 return;
208 }
209 vda_->Reset();
210 }
211
212 void ArcGpuVideoDecodeAccelerator::ProvidePictureBuffers(
213 size_t requested_num_of_buffers,
214 const gfx::Size& dimensions,
215 uint32_t texture_target) {
216 DVLOG(5) << "ProvidePictureBuffers("
217 << "requested_num_of_buffers=" << requested_num_of_buffers
218 << ", dimensions=" << dimensions.ToString() << ")";
219 DCHECK(thread_checker_.CalledOnValidThread());
220 coded_size_ = dimensions;
221 // TODO(owenlin): use VDA::GetOutputFormat() here and calculate correct
Pawel Osciak 2016/03/22 10:21:12 Could we use it already, potentially only handling
Owen Lin 2016/03/24 03:01:11 It is still not clear how should this info get han
Pawel Osciak 2016/03/25 08:38:44 I basically meant this (possibly replacing PIXEL_F
Owen Lin 2016/03/29 07:10:41 Done.
222 // |buffer_size|.
223 VideoFormat video_format;
224 video_format.buffer_size = dimensions.GetArea() * 3 / 2;
225 output_buffer_size_ = video_format.buffer_size;
226 video_format.min_num_buffers = requested_num_of_buffers;
227 video_format.coded_width = dimensions.width();
228 video_format.coded_height = dimensions.height();
229 // TODO(owenlin): How to get visible size?
230 video_format.crop_top = 0;
231 video_format.crop_left = 0;
232 video_format.crop_width = dimensions.width();
233 video_format.crop_height = dimensions.height();
234 arc_client_->OnOutputFormatChanged(video_format);
235 }
236
237 void ArcGpuVideoDecodeAccelerator::DismissPictureBuffer(
238 int32_t picture_buffer) {
239 // no-op
240 }
241
242 void ArcGpuVideoDecodeAccelerator::PictureReady(const media::Picture& picture) {
243 DVLOG(5) << "PictureReady(picture_buffer_id=" << picture.picture_buffer_id()
244 << ", bitstream_buffer_id=" << picture.bitstream_buffer_id();
245 DCHECK(thread_checker_.CalledOnValidThread());
246
247 // Empty buffer, returned in Flushing.
248 if (picture.bitstream_buffer_id() == -1) {
249 buffers_pending_eos_.push(picture.picture_buffer_id());
250 return;
251 }
252 InputRecord* input_record = FindInputRecord(picture.bitstream_buffer_id());
253 if (input_record == nullptr) {
254 DLOG(ERROR) << "Cannot find for bitstream buffer id: "
255 << picture.bitstream_buffer_id();
256 arc_client_->OnError(PLATFORM_FAILURE);
257 return;
258 }
259
260 BufferMetadata metadata;
261 metadata.timestamp = input_record->timestamp;
262 metadata.bytes_used = output_buffer_size_;
263 arc_client_->OnBufferDone(PORT_OUTPUT, picture.picture_buffer_id(), metadata);
264 }
265
266 void ArcGpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer(
267 int32_t bitstream_buffer_id) {
268 DVLOG(5) << "NotifyEndOfBitstreamBuffer(" << bitstream_buffer_id << ")";
269 DCHECK(thread_checker_.CalledOnValidThread());
270 InputRecord* input_record = FindInputRecord(bitstream_buffer_id);
271 if (input_record == nullptr) {
272 arc_client_->OnError(PLATFORM_FAILURE);
273 return;
274 }
275 arc_client_->OnBufferDone(PORT_INPUT, input_record->buffer_index,
276 BufferMetadata());
277 }
278
279 void ArcGpuVideoDecodeAccelerator::NotifyFlushDone() {
280 DCHECK(thread_checker_.CalledOnValidThread());
281 pending_eos_output_buffer_ = true;
282 while (!buffers_pending_eos_.empty()) {
283 SendEosIfNeededOrReusePicture(buffers_pending_eos_.front());
284 buffers_pending_eos_.pop();
285 }
286 }
287
288 void ArcGpuVideoDecodeAccelerator::NotifyResetDone() {
289 DCHECK(thread_checker_.CalledOnValidThread());
290 arc_client_->OnResetDone();
291 }
292
293 static ArcVideoAccelerator::Error ConvertErrorCode(
294 media::VideoDecodeAccelerator::Error error) {
295 switch (error) {
296 case media::VideoDecodeAccelerator::ILLEGAL_STATE:
297 return ArcVideoAccelerator::ILLEGAL_STATE;
298 case media::VideoDecodeAccelerator::INVALID_ARGUMENT:
299 return ArcVideoAccelerator::INVALID_ARGUMENT;
300 case media::VideoDecodeAccelerator::UNREADABLE_INPUT:
301 return ArcVideoAccelerator::UNREADABLE_INPUT;
302 case media::VideoDecodeAccelerator::PLATFORM_FAILURE:
303 return ArcVideoAccelerator::PLATFORM_FAILURE;
304 default:
305 DLOG(ERROR) << "Unknown error: " << error;
306 return ArcVideoAccelerator::PLATFORM_FAILURE;
307 }
308 }
309
310 void ArcGpuVideoDecodeAccelerator::NotifyError(
311 media::VideoDecodeAccelerator::Error error) {
312 DCHECK(thread_checker_.CalledOnValidThread());
313 DLOG(ERROR) << "Error notified: " << error;
314 arc_client_->OnError(ConvertErrorCode(error));
315 }
316
317 void ArcGpuVideoDecodeAccelerator::SendEosIfNeededOrReusePicture(
318 uint32_t index) {
319 if (pending_eos_output_buffer_) {
320 BufferMetadata metadata;
321 metadata.flags = BUFFER_FLAG_EOS;
322 arc_client_->OnBufferDone(PORT_OUTPUT, index, metadata);
323 pending_eos_output_buffer_ = false;
324 } else {
325 if (pending_import_buffer_[index].is_valid()) {
326 std::vector<gfx::GpuMemoryBufferHandle> buffers;
327 buffers.push_back(gfx::GpuMemoryBufferHandle());
328 buffers.back().native_pixmap_handle.fd =
329 base::FileDescriptor(pending_import_buffer_[index].release(), true);
330 vda_->ImportBufferForPicture(index, buffers);
331 DCHECK(!pending_import_buffer_[index].is_valid());
Pawel Osciak 2016/03/22 10:21:12 This is probably not needed since we call release(
Owen Lin 2016/03/24 03:01:11 Done.
332 } else {
333 vda_->ReusePictureBuffer(index);
334 }
335 }
336 }
337
338 void ArcGpuVideoDecodeAccelerator::SetInputRecord(int32_t bitstream_buffer_id,
339 uint32_t buffer_index,
340 int64_t timestamp) {
341 input_records_.push_front(
342 InputRecord(bitstream_buffer_id, buffer_index, timestamp));
343 // The same value copied from media::GpuVideoDecoder.
344 const size_t kMaxNumberOfInputRecords = 128;
Pawel Osciak 2016/03/22 10:21:12 Should we use kMaxBufferCount?
Owen Lin 2016/03/24 03:01:11 They are different in meaning. The MaxNumberOfInpu
Pawel Osciak 2016/03/25 08:38:44 Acknowledged.
345 if (input_records_.size() > kMaxNumberOfInputRecords)
Pawel Osciak 2016/03/22 10:21:12 Please add a comment why we keep a rolling record
Owen Lin 2016/03/24 03:01:11 Done.
346 input_records_.pop_back();
347 }
348
349 ArcGpuVideoDecodeAccelerator::InputRecord*
350 ArcGpuVideoDecodeAccelerator::FindInputRecord(int32_t bitstream_buffer_id) {
351 for (auto& record : input_records_) {
352 if (record.bitstream_buffer_id == bitstream_buffer_id)
353 return &record;
354 }
355 return nullptr;
356 }
357
358 bool ArcGpuVideoDecodeAccelerator::ValidatePortAndIndex(PortType port,
359 uint32_t index) {
360 switch (port) {
361 case PORT_INPUT:
362 if (index >= input_buffer_info_.size()) {
363 DLOG(ERROR) << "Invalid index: " << index;
364 return false;
365 }
366 return true;
367 case PORT_OUTPUT:
368 if (index >= pending_import_buffer_.size()) {
369 DLOG(ERROR) << "Invalid index: " << index;
370 return false;
371 }
372 return true;
373 default:
374 DLOG(ERROR) << "Invalid port: " << port;
375 return false;
376 }
377 }
378
379 } // namespace arc
380 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698