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

Side by Side Diff: content/common/gpu/media/arc/arc_gpu_video_decode_accelerator.cc

Issue 1549473002: Add ArcGpuVideoDecodeAccelerator. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Not ready yet Created 4 years, 11 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 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(NOT_BOUND), 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(
Pawel Osciak 2016/01/07 09:22:35 Please use a ThreadChecker to make sure methods ar
Owen Lin 2016/01/12 09:30:23 Done.
31 DeviceType device,
32 ArcVideoAccelerator::Client* client) {
33 if (device != DEVICE_DECODER)
34 return EINVAL;
Pawel Osciak 2016/01/07 09:22:35 I'm not seeing any other values apart from EINVAL
Owen Lin 2016/01/12 09:30:22 Done.
Owen Lin 2016/01/12 09:30:23 Done.
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 (vda_ == nullptr) {
44 DVLOG(1) << "Must call setBufferFormat before setBufferCount";
45 return EINVAL;
46 }
47 if (port != PORT_INPUT && port != PORT_OUTPUT) {
48 DVLOG(1) << "Invalid port: " << port;
49 return EINVAL;
50 }
51 if (port == PORT_OUTPUT) {
52 std::vector<media::PictureBuffer> buffers;
53 for (int32_t id = 0, n = *count; id < n; ++id) {
54 // TODO: Make sure the size is what we want.
55 buffers.push_back(media::PictureBuffer(id, coded_size_, 0));
56 }
57 vda_->AssignPictureBuffers(buffers);
58 }
59 PortInfo* port_info = &port_info_[port];
60 port_info->buffers.clear();
61 port_info->buffers.resize(*count);
62 return 0;
63 }
64
65 status_t ArcGpuVideoDecodeAccelerator::SetBufferFormat(
66 PortType port,
67 const BufferFormat& format) {
68 switch (port) {
69 case PORT_INPUT: {
70 PortInfo* port_info = &port_info_[port];
71 if (format.memory_type != MEMORY_SHARED_MEMORY) {
72 DVLOG(1) << "Only SharedMemory is supported for input buffers";
73 return EINVAL;
74 }
75 port_info->memory_type = format.memory_type;
76 media::VideoDecodeAccelerator::Config config;
77 switch (format.pixel_format) {
78 case HAL_PIXEL_FORMAT_H264:
79 config.profile = media::H264PROFILE_MAIN;
80 vda_ = nullptr;
81 break;
82 case HAL_PIXEL_FORMAT_VP8:
83 config.profile = media::VP8PROFILE_ANY;
84 vda_ = nullptr; // TODO(owenlin): Change to real implementation.
Pawel Osciak 2016/01/07 09:22:35 Do we need this and l.80? vda_ can be constructed
Owen Lin 2016/01/12 09:30:22 Move it to Initialize.
85 break;
86 default:
87 DVLOG(1) << "Unsupported input format: " << format.pixel_format;
88 return EINVAL;
89 }
90 config.output_mode =
91 media::VideoDecodeAccelerator::Config::OutputMode::IMPORT;
92 vda_->Initialize(config, this);
Pawel Osciak 2016/01/07 09:22:35 This may fail, we should handle the return value.
Owen Lin 2016/01/12 09:30:22 Done.
93 break;
94 }
95 case PORT_OUTPUT: {
96 PortInfo* port_info = &port_info_[port];
97 if (format.memory_type != MEMORY_DMABUF) {
98 DVLOG(1) << "Only DMA buffer is supported for output buffers";
99 return EINVAL;
100 }
101 port_info->memory_type = format.memory_type;
102 break;
103 }
104 default:
105 DVLOG(1) << "Invalid port: " << port;
106 return EINVAL;
107 }
108 return 0;
109 }
110
111 ArcGpuVideoDecodeAccelerator::BufferInfo*
112 ArcGpuVideoDecodeAccelerator::GetBufferInfo(PortType port, uint32_t index) {
113 if (port != PORT_INPUT || port != PORT_OUTPUT)
114 return nullptr;
115 auto& buffers = port_info_[port].buffers;
116 return index >= buffers.size() ? nullptr : &buffers[index];
117 }
118
119 status_t ArcGpuVideoDecodeAccelerator::BindSharedBuffer(PortType port,
120 uint32_t index,
121 int ashmem_fd,
122 size_t offset,
123 size_t length) {
124 // Make sure we will close the file descriptor.
125 base::ScopedFD handle(ashmem_fd);
126 BufferInfo* buffer_info = GetBufferInfo(port, index);
127 if (buffer_info == nullptr) {
128 DVLOG(1) << "Invalid buffer port: " << port << " index: " << index;
129 return EINVAL;
130 }
131 PortInfo* port_info = &port_info_[port];
Pawel Osciak 2016/01/07 09:22:36 It's not straightforward that we are depending on
Owen Lin 2016/01/12 09:30:22 But we call GetBufferInfo a lot. In most cases, th
132 if (port_info->memory_type != MEMORY_SHARED_MEMORY) {
133 DVLOG(1) << "Unmatched memory type: " << port_info->memory_type;
134 return EINVAL;
135 }
136 if (buffer_info->state != NOT_BOUND ||
Pawel Osciak 2016/01/07 09:22:35 I think we can drop NOT_BOUND state. VDA has to ve
Owen Lin 2016/01/12 09:30:22 Done.
137 buffer_info->state != OWNED_BY_CLIENT) {
138 DVLOG(1) << "Cannot bind a buffer while in use";
139 return EINVAL;
140 }
141 buffer_info->state = OWNED_BY_CLIENT;
142 buffer_info->handle = std::move(handle);
143 buffer_info->offset = offset;
144 buffer_info->length = length;
145 return 0;
146 }
147
148 status_t ArcGpuVideoDecodeAccelerator::BindGraphicBuffer(PortType port,
149 uint32_t index,
150 int dmabuf_fd) {
151 // Make sure we will close the file descriptor.
152 base::ScopedFD handle(dmabuf_fd);
153 BufferInfo* buffer_info = GetBufferInfo(port, index);
Pawel Osciak 2016/01/07 09:22:35 Could we unify the code with the other Bind? It se
Owen Lin 2016/01/12 09:30:22 After we remove the check for buffer's state the o
154 if (buffer_info == nullptr) {
155 DVLOG(1) << "Invalid buffer port: " << port << " index: " << index;
156 return EINVAL;
157 }
158 PortInfo* port_info = &port_info_[port];
159 if (port_info->memory_type != MEMORY_DMABUF) {
160 DVLOG(1) << "Unmatched memory type: " << port_info->memory_type;
161 return EINVAL;
162 }
163 if (buffer_info->state != NOT_BOUND ||
164 buffer_info->state != OWNED_BY_CLIENT) {
165 DVLOG(1) << "Cannot bind a buffer while in use";
166 return EINVAL;
167 }
168 buffer_info->state = OWNED_BY_CLIENT;
169 std::vector<base::ScopedFD> dmabuf_fds;
170 dmabuf_fds.push_back(std::move(handle));
171 vda_->ImportBufferForPicture(index, std::move(dmabuf_fds));
172 return 0;
173 }
174
175 void ArcGpuVideoDecodeAccelerator::UseBuffer(PortType port,
176 uint32_t index,
177 const BufferMetadata& metadata) {
178 BufferInfo* buffer_info = GetBufferInfo(port, index);
179 if (buffer_info == nullptr) {
180 DVLOG(1) << "Invalid buffer port: " << port << ", index: " << index;
181 arc_client_->OnError(INVALID_ARGUMENT);
Pawel Osciak 2016/01/07 09:22:35 It would be great to remove status returns and use
Owen Lin 2016/01/12 09:30:22 I think it's the difference between the design of
182 return;
183 }
184 if (buffer_info->state != OWNED_BY_CLIENT) {
185 DVLOG(1) << "Illegal buffer state: " << buffer_info->state
186 << ", port: " << port << ", index: " << index;
187 arc_client_->OnError(ILLEGAL_STATE);
188 return;
189 }
190 buffer_info->state = OWNED_BY_US;
191 switch (port) {
192 case PORT_INPUT: {
193 if (metadata.flags & BUFFER_FLAG_EOS) {
194 // Ask VDA to return all output pictures so that we can output an EOS
195 // picture when Flush() is done.
196 // vda_->Flush(true);
197 vda_->Flush();
198 }
199 if (metadata.bytes_used > 0) {
200 int32_t bitstream_buffer_id = bitstream_buffer_serial_++;
201 if (bitstream_buffer_serial_ < 0)
202 bitstream_buffer_serial_ = 0;
Pawel Osciak 2016/01/07 09:22:35 Perhaps something like https://code.google.com/p/c
Owen Lin 2016/01/12 09:30:22 Done.
203 SetInputRecord(bitstream_buffer_id, index, metadata.timestamp);
204 base::SharedMemoryHandle shared_memory_handle(buffer_info->handle.get(),
205 false);
206 // TODO(owenlin): Make BitstreamBuffer surpport offset and use here.
207 media::BitstreamBuffer bitstream_buffer(
208 bitstream_buffer_id, shared_memory_handle, buffer_info->length);
209 buffer_info->state = OWNED_BY_VDA;
Pawel Osciak 2016/01/07 09:22:35 I'm wondering if we could merge OWNED_BY_US and OW
Owen Lin 2016/01/12 09:30:22 Done.
210 vda_->Decode(bitstream_buffer);
211 } else {
Pawel Osciak 2016/01/07 09:22:35 Perhaps reversing the if() and removing else would
Owen Lin 2016/01/12 09:30:22 Done.
212 buffer_info->state = OWNED_BY_CLIENT;
213 arc_client_->OnBufferDone(PORT_INPUT, index, BufferMetadata());
214 }
215 break;
216 }
217 case PORT_OUTPUT: {
218 SendEosIfNeededOrReusePicture(index, buffer_info);
219 break;
220 }
221 default:
222 NOTREACHED();
223 }
224 }
225
226 void ArcGpuVideoDecodeAccelerator::Reset() {
227 base::RunLoop loop;
228 reset_done_callback_ = loop.QuitClosure();
229 vda_->Reset();
230 base::MessageLoop::ScopedNestableTaskAllower allow(
231 base::MessageLoop::current());
232 // Wait for the ResetDone callback.
233 loop.Run();
234 }
235
236 void ArcGpuVideoDecodeAccelerator::ProvidePictureBuffers(
237 size_t requested_num_of_buffers,
238 const gfx::Size& dimensions,
239 uint32_t texture_target) {
240 coded_size_ = dimensions;
241 // TODO(owenlin): Think if we need to handle the pixel format.
Pawel Osciak 2016/01/07 09:22:35 Please use VDA::GetOutputFormat() here.
Owen Lin 2016/01/12 09:30:22 TODO added.
242 // It looks like the flexible pixel format is good enough.
243 VideoFormat video_format;
Pawel Osciak 2016/01/07 09:22:35 How are we handling image_size ?
Owen Lin 2016/01/12 09:30:22 We use it to request buffers from NativeWindow.
244 video_format.min_num_buffers = requested_num_of_buffers;
245 video_format.coded_width = dimensions.width();
246 video_format.coded_height = dimensions.height();
247 arc_client_->OnOutputFormatChanged(video_format);
248 }
249
250 void ArcGpuVideoDecodeAccelerator::PictureReady(const media::Picture& picture) {
251 BufferInfo* output_buffer =
252 GetBufferInfo(PORT_OUTPUT, picture.picture_buffer_id());
253 CHECK_NE(output_buffer, nullptr);
Pawel Osciak 2016/01/07 09:22:35 I know this shouldn't happen, but I'm wondering if
Owen Lin 2016/01/12 09:30:22 Done.
254
255 // Empty buffer, returned in Flushing.
256 if (picture.bitstream_buffer_id() == -1) {
257 output_buffer->state = OWNED_BY_US;
258 } else {
259 BufferMetadata metadata;
260 uint32_t index = 0;
261 GetInputRecord(picture.bitstream_buffer_id(), &index, &metadata.timestamp);
Pawel Osciak 2016/01/07 09:22:36 Could we use picture.picture_buffer_id as a key to
Owen Lin 2016/01/12 09:30:22 Sorry, I didn't get you. Here we don't use the |in
262 output_buffer->state = OWNED_BY_CLIENT;
263 arc_client_->OnBufferDone(PORT_OUTPUT, picture.picture_buffer_id(),
Pawel Osciak 2016/01/07 09:22:35 should this be s/picture.picture_buffer_id()/index
Owen Lin 2016/01/12 09:30:22 No, GetInputRecord() returns the information about
264 metadata);
265 }
266 }
267
268 void ArcGpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer(
269 int32_t bitstream_buffer_id) {
270 int64_t timestamp = 0;
271 uint32_t index = 0;
272 GetInputRecord(bitstream_buffer_id, &index, &timestamp);
273 BufferInfo* buffer_info = GetBufferInfo(PORT_OUTPUT, index);
274 CHECK(buffer_info);
Pawel Osciak 2016/01/07 09:22:35 Perhaps NotifyError(PLATFORM_FAILURE).
Owen Lin 2016/01/12 09:30:22 Done.
275 buffer_info->state = OWNED_BY_CLIENT;
276 arc_client_->OnBufferDone(PORT_INPUT, bitstream_buffer_id, BufferMetadata());
Pawel Osciak 2016/01/07 09:22:35 should this be s/bitstream_buffer_id/index/ ?
Owen Lin 2016/01/12 09:30:23 Yes, it is. Thanks.
277 }
278
279 void ArcGpuVideoDecodeAccelerator::NotifyFlushDone() {
280 pending_eos_output_buffer_ = true;
281 std::vector<BufferInfo>* buffers = &port_info_[PORT_OUTPUT].buffers;
282 for (size_t i = 0, n = buffers->size(); i < n; ++i) {
283 BufferInfo* info = &buffers->at(i);
284 if (info->state == OWNED_BY_US)
285 SendEosIfNeededOrReusePicture(i, info);
286 }
287 }
288
289 void ArcGpuVideoDecodeAccelerator::NotifyResetDone() {
290 base::ResetAndReturn(&reset_done_callback_).Run();
291 }
292
293 static ArcVideoAccelerator::Error ConvertErrorCode(
294 media::VideoDecodeAccelerator::Error error) {
295 #define CASE(t) \
Pawel Osciak 2016/01/07 09:22:35 To be honest, I'd prefer not having this macro ple
Owen Lin 2016/01/12 09:30:23 Done.
296 case media::VideoDecodeAccelerator::t: \
297 return ArcVideoAccelerator::t
298 switch (error) {
299 CASE(ILLEGAL_STATE);
300 CASE(INVALID_ARGUMENT);
301 CASE(UNREADABLE_INPUT);
302 CASE(PLATFORM_FAILURE);
303 default:
304 NOTREACHED() << "Unknown error: " << error;
305 }
306 #undef CASE
307 return static_cast<ArcVideoAccelerator::Error>(error);
308 }
309
310 void ArcGpuVideoDecodeAccelerator::NotifyError(
311 media::VideoDecodeAccelerator::Error error) {
312 arc_client_->OnError(ConvertErrorCode(error));
313 }
314
315 void ArcGpuVideoDecodeAccelerator::SendEosIfNeededOrReusePicture(
316 uint32_t index,
317 BufferInfo* info) {
318 DCHECK_EQ(info->state, OWNED_BY_US);
319 if (pending_eos_output_buffer_) {
320 BufferMetadata metadata;
321 metadata.flags = BUFFER_FLAG_EOS;
322 info->state = OWNED_BY_CLIENT;
323 arc_client_->OnBufferDone(PORT_OUTPUT, index, metadata);
324 pending_eos_output_buffer_ = false;
325 } else {
326 info->state = OWNED_BY_VDA;
327 vda_->ReusePictureBuffer(index);
328 }
329 }
330
331 void ArcGpuVideoDecodeAccelerator::SetInputRecord(int32_t bitstream_buffer_id,
332 uint32_t index,
333 int64_t timestamp) {
334 input_records_.push_front(InputRecord(bitstream_buffer_id, index, timestamp));
335 // The value is copied from media::GpuVideoDecoder.
336 const size_t kMaxInputBufferDataSize = 128;
Pawel Osciak 2016/01/07 09:22:35 In GVD we can get a theoretically unspecified numb
Owen Lin 2016/01/12 09:30:23 I think you're right, I will use the BufferInfo fo
337 if (input_records_.size() > kMaxInputBufferDataSize)
338 input_records_.pop_back();
339 }
340
341 void ArcGpuVideoDecodeAccelerator::GetInputRecord(int32_t bitstream_buffer_id,
342 uint32_t* index,
343 int64_t* timestamp) {
344 for (auto& data : input_records_) {
345 if (data.bitstream_buffer_id == bitstream_buffer_id) {
346 *index = data.index;
347 *timestamp = data.timestamp;
348 return;
349 }
350 }
351 NOTREACHED() << "Missing bitstream_buffer_id: " << bitstream_buffer_id;
352 }
353
354 } // arc
355 } // content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698