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

Side by Side Diff: content/common/gpu/omx_video_decode_accelerator.cc

Issue 6979017: Revert 86681 - Updated OMX decoder for recent PPAPI changes, and added to the build. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 7 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 | Annotate | Revision Log
« no previous file with comments | « content/common/gpu/omx_video_decode_accelerator.h ('k') | content/content_common.gypi » ('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 (c) 2011 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 "content/common/gpu/omx_video_decode_accelerator.h"
6
7 #include "base/stl_util-inl.h"
8 #include "base/string_util.h"
9 #include "content/common/gpu/gles2_texture_to_egl_image_translator.h"
10 #include "content/common/gpu/gpu_channel.h"
11 #include "media/base/bitstream_buffer.h"
12 #include "media/video/picture.h"
13
14 enum { kNumPictureBuffers = 4 };
15
16 // Open the libnvomx here for now.
17 void* omx_handle = dlopen("libnvomx.so", RTLD_NOW);
18
19 typedef OMX_ERRORTYPE (*OMXInit)();
20 typedef OMX_ERRORTYPE (*OMXGetHandle)(
21 OMX_HANDLETYPE*, OMX_STRING, OMX_PTR, OMX_CALLBACKTYPE*);
22 typedef OMX_ERRORTYPE (*OMXGetComponentsOfRole)(OMX_STRING, OMX_U32*, OMX_U8**);
23 typedef OMX_ERRORTYPE (*OMXFreeHandle)(OMX_HANDLETYPE);
24 typedef OMX_ERRORTYPE (*OMXDeinit)();
25
26 OMXInit omx_init = reinterpret_cast<OMXInit>(dlsym(omx_handle, "OMX_Init"));
27 OMXGetHandle omx_gethandle =
28 reinterpret_cast<OMXGetHandle>(dlsym(omx_handle, "OMX_GetHandle"));
29 OMXGetComponentsOfRole omx_get_components_of_role =
30 reinterpret_cast<OMXGetComponentsOfRole>(
31 dlsym(omx_handle, "OMX_GetComponentsOfRole"));
32 OMXFreeHandle omx_free_handle =
33 reinterpret_cast<OMXFreeHandle>(dlsym(omx_handle, "OMX_FreeHandle"));
34 OMXDeinit omx_deinit =
35 reinterpret_cast<OMXDeinit>(dlsym(omx_handle, "OMX_Deinit"));
36
37 static bool AreOMXFunctionPointersInitialized() {
38 return (omx_init && omx_gethandle && omx_get_components_of_role &&
39 omx_free_handle && omx_deinit);
40 }
41
42 OmxVideoDecodeAccelerator::OmxVideoDecodeAccelerator(
43 media::VideoDecodeAccelerator::Client* client,
44 MessageLoop* message_loop)
45 : message_loop_(message_loop),
46 component_handle_(NULL),
47 width_(-1),
48 height_(-1),
49 input_buffer_count_(0),
50 input_buffer_size_(0),
51 input_port_(0),
52 input_buffers_at_component_(0),
53 output_buffer_count_(0),
54 output_buffer_size_(0),
55 output_port_(0),
56 output_buffers_at_component_(0),
57 uses_egl_image_(false),
58 client_(client) {
59 if (!AreOMXFunctionPointersInitialized()) {
60 LOG(ERROR) << "Failed to load openmax library";
61 return;
62 }
63 OMX_ERRORTYPE result = omx_init();
64 if (result != OMX_ErrorNone)
65 LOG(ERROR) << "Failed to init OpenMAX core";
66 }
67
68 OmxVideoDecodeAccelerator::~OmxVideoDecodeAccelerator() {
69 DCHECK(free_input_buffers_.empty());
70 DCHECK_EQ(0, input_buffers_at_component_);
71 DCHECK_EQ(0, output_buffers_at_component_);
72 DCHECK(output_pictures_.empty());
73 }
74
75 void OmxVideoDecodeAccelerator::GetConfigs(
76 const std::vector<uint32>& requested_configs,
77 std::vector<uint32>* matched_configs) {
78 // TODO(vhiremath@nvidia.com) use this properly
79 NOTIMPLEMENTED();
80 }
81
82 // This is to initialize the OMX data structures to default values.
83 template <typename T>
84 static void InitParam(const OmxVideoDecodeAccelerator& dec, T* param) {
85 memset(param, 0, sizeof(T));
86 param->nVersion.nVersion = 0x00000101;
87 param->nSize = sizeof(T);
88 }
89
90 bool OmxVideoDecodeAccelerator::Initialize(const std::vector<uint32>& config) {
91 // TODO(vhiremath@nvidia.com) get these actual values from config
92 // Assume qvga for now
93 width_ = 320;
94 height_ = 240;
95
96 client_state_ = OMX_StateLoaded;
97 if (!CreateComponent()) {
98 StopOnError();
99 return false;
100 }
101 // Transition component to Idle state
102 on_state_event_func_ =
103 &OmxVideoDecodeAccelerator::OnStateChangeLoadedToIdle;
104 if (!TransitionToState(OMX_StateIdle))
105 return false;
106
107 if (!AllocateInputBuffers()) {
108 LOG(ERROR) << "OMX_AllocateBuffer() Input buffer error";
109 StopOnError();
110 return false;
111 }
112
113 // After AllocateInputBuffers ideally this should be AllocateOutputBuffers.
114 // Since in this case app provides the output buffers,
115 // we query this through ProvidePictureBuffers.
116 // This is call to ppapi to provide the output buffers initially.
117 // ProvidePictureBuffers will provide
118 // - SharedMemHandle in case of decoding to system memory.
119 // - Textures in case of decoding to egl-images.
120
121 // Output buffers will be eventually handed to us via
122 // Assign{GLES,Sysmem}Buffers().
123 output_buffer_count_ = kNumPictureBuffers;
124 client_->ProvidePictureBuffers(
125 output_buffer_count_, gfx::Size(width_, height_),
126 PICTUREBUFFER_MEMORYTYPE_GL_TEXTURE);
127 // TODO(fischman): we always ask for GLES buffers above. So why maintain the
128 // !uses_egl_image_ path in this class at all? Theoretically it could be
129 // useful for testing, but today there's no such testing. Consider ripping it
130 // out of this class and replacing AssignSysmemBuffers() with
131 // NOTIMPLEMENTED().
132 return true;
133 }
134
135 bool OmxVideoDecodeAccelerator::CreateComponent() {
136 OMX_CALLBACKTYPE omx_accelerator_callbacks = {
137 &OmxVideoDecodeAccelerator::EventHandler,
138 &OmxVideoDecodeAccelerator::EmptyBufferCallback,
139 &OmxVideoDecodeAccelerator::FillBufferCallback
140 };
141 OMX_ERRORTYPE result = OMX_ErrorNone;
142
143 // 1. Set the role and get all components of this role.
144 // TODO(vhiremath@nvidia.com) Get this role_name from the configs
145 // For now hard coding to avc.
146 const char* role_name = "video_decoder.avc";
147 OMX_U32 num_roles = 0;
148 // Get all the components with this role.
149 result = (*omx_get_components_of_role)(
150 const_cast<OMX_STRING>(role_name), &num_roles, 0);
151 if (result != OMX_ErrorNone || num_roles == 0) {
152 LOG(ERROR) << "Unsupported Role: " << role_name;
153 StopOnError();
154 return false;
155 }
156
157 // We haven't seen HW that needs more yet,
158 // but there is no reason not to raise.
159 const OMX_U32 kMaxRolePerComponent = 3;
160 CHECK_LT(num_roles, kMaxRolePerComponent);
161
162 scoped_array<scoped_array<OMX_U8> > component_names(
163 new scoped_array<OMX_U8>[num_roles]);
164 for (size_t i = 0; i < num_roles; ++i)
165 component_names[i].reset(new OMX_U8[OMX_MAX_STRINGNAME_SIZE]);
166 result = (*omx_get_components_of_role)(
167 const_cast<OMX_STRING>(role_name),
168 &num_roles, reinterpret_cast<OMX_U8**>(component_names.get()));
169
170 // Use first component only. Copy the name of the first component
171 // so that we could free the memory.
172 std::string component_name;
173 if (result == OMX_ErrorNone)
174 component_name = reinterpret_cast<char*>(component_names[0].get());
175
176 if (result != OMX_ErrorNone || num_roles == 0) {
177 LOG(ERROR) << "Unsupported Role: " << component_name.c_str();
178 StopOnError();
179 return false;
180 }
181
182 // 3. Get the handle to the component.
183 // After OMX_GetHandle(), the component is in loaded state.
184 OMX_STRING component = const_cast<OMX_STRING>(component_name.c_str());
185 result = omx_gethandle(&component_handle_, component, this,
186 &omx_accelerator_callbacks);
187 if (result != OMX_ErrorNone) {
188 LOG(ERROR) << "Failed to Load the component: " << component;
189 StopOnError();
190 return false;
191 }
192
193 // 4. Get the port information. This will obtain information about the
194 // number of ports and index of the first port.
195 OMX_PORT_PARAM_TYPE port_param;
196 InitParam(*this, &port_param);
197 result = OMX_GetParameter(component_handle_, OMX_IndexParamVideoInit,
198 &port_param);
199 if ((result != OMX_ErrorNone) || (port_param.nPorts != 2)) {
200 LOG(ERROR) << "Failed to get Port Param";
201 StopOnError();
202 return false;
203 }
204 input_port_ = port_param.nStartPortNumber;
205 output_port_ = input_port_ + 1;
206 // 5. Set role for the component because components can have multiple roles.
207 OMX_PARAM_COMPONENTROLETYPE role_type;
208 InitParam(*this, &role_type);
209 base::strlcpy(reinterpret_cast<char*>(role_type.cRole),
210 role_name,
211 OMX_MAX_STRINGNAME_SIZE);
212
213 result = OMX_SetParameter(component_handle_,
214 OMX_IndexParamStandardComponentRole,
215 &role_type);
216 if (result != OMX_ErrorNone) {
217 LOG(ERROR) << "Failed to Set Role";
218 StopOnError();
219 return false;
220 }
221
222 // 7. Populate input-buffer-related members based on input port data.
223 OMX_PARAM_PORTDEFINITIONTYPE port_format;
224 InitParam(*this, &port_format);
225 port_format.nPortIndex = input_port_;
226 result = OMX_GetParameter(component_handle_,
227 OMX_IndexParamPortDefinition,
228 &port_format);
229 if (result != OMX_ErrorNone) {
230 LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) failed";
231 StopOnError();
232 return false;
233 }
234 if (OMX_DirInput != port_format.eDir) {
235 LOG(ERROR) << "Expected input port";
236 StopOnError();
237 return false;
238 }
239 input_buffer_count_ = port_format.nBufferCountActual;
240 input_buffer_size_ = port_format.nBufferSize;
241
242 // OMX_IndexParamPortDefinition on output port to be done in
243 // AllocateOutputBuffers.
244 // Since at this point we dont know if we will be using system memory
245 // or egl-image for decoding.
246 // We get this info in AssignPictureBuffers() from plugin.
247
248 return true;
249 }
250
251 bool OmxVideoDecodeAccelerator::Decode(
252 const media::BitstreamBuffer& bitstream_buffer) {
253 DCHECK(!free_input_buffers_.empty());
254
255 if (!CanAcceptInput()) {
256 return false;
257 }
258
259 OMX_BUFFERHEADERTYPE* omx_buffer = free_input_buffers_.front();
260 free_input_buffers_.pop();
261
262 // Setup |omx_buffer|.
263 scoped_ptr<base::SharedMemory> shm(
264 new base::SharedMemory(bitstream_buffer.handle(), true));
265 if (!shm->Map(bitstream_buffer.size())) {
266 LOG(ERROR) << "Failed to SharedMemory::Map().";
267 return false;
268 }
269 omx_buffer->pBuffer = static_cast<OMX_U8*>(shm->memory());
270 omx_buffer->nFilledLen = bitstream_buffer.size();
271 omx_buffer->nAllocLen = omx_buffer->nFilledLen;
272
273 omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
274 omx_buffer->nTimeStamp = 0;
275
276 // Give this buffer to OMX.
277 OMX_ERRORTYPE result = OMX_ErrorNone;
278 result = OMX_EmptyThisBuffer(component_handle_, omx_buffer);
279 if (result != OMX_ErrorNone) {
280 LOG(ERROR) << "OMX_EmptyThisBuffer() failed with result " << result;
281 StopOnError();
282 return false;
283 }
284 input_buffers_at_component_++;
285 // OMX_EmptyThisBuffer is a non blocking call and should
286 // not make any assumptions about its completion.
287 omx_buff_ids_.insert(std::make_pair(
288 omx_buffer, std::make_pair(shm.release(), bitstream_buffer.id())));
289 return true;
290 }
291
292 // NOTE: this is only partially-implemented as never unsets uses_egl_image_ once
293 // set.
294 void OmxVideoDecodeAccelerator::AssignGLESBuffers(
295 const std::vector<media::GLESBuffer>& buffers) {
296 uses_egl_image_ = true;
297 std::vector<media::BaseBuffer*> base_buffers(buffers.size());
298 for (size_t i = 0; i < buffers.size(); ++i)
299 base_buffers[i] = new media::GLESBuffer(buffers[i]);
300 AssignBuffersHelper(base_buffers);
301 }
302
303 void OmxVideoDecodeAccelerator::AssignSysmemBuffers(
304 const std::vector<media::SysmemBuffer>& buffers) {
305 DCHECK(!uses_egl_image_);
306 std::vector<media::BaseBuffer*> base_buffers(buffers.size());
307 for (size_t i = 0; i < buffers.size(); ++i)
308 base_buffers[i] = new media::SysmemBuffer(buffers[i]);
309 AssignBuffersHelper(base_buffers);
310 }
311
312 void OmxVideoDecodeAccelerator::AssignBuffersHelper(
313 const std::vector<media::BaseBuffer*>& buffers) {
314 assigned_picture_buffers_.insert(
315 assigned_picture_buffers_.end(), buffers.begin(), buffers.end());
316
317 if (assigned_picture_buffers_.size() < kNumPictureBuffers)
318 return; // get all the buffers first.
319
320 // Obtain the information about the output port.
321 OMX_PARAM_PORTDEFINITIONTYPE port_format;
322 InitParam(*this, &port_format);
323 port_format.nPortIndex = output_port_;
324 OMX_ERRORTYPE result = OMX_GetParameter(component_handle_,
325 OMX_IndexParamPortDefinition,
326 &port_format);
327 if (result != OMX_ErrorNone) {
328 LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) failed";
329 StopOnError();
330 return;
331 }
332 if (OMX_DirOutput != port_format.eDir) {
333 LOG(ERROR) << "Expect Output Port";
334 StopOnError();
335 return;
336 }
337
338 if (uses_egl_image_) {
339 port_format.nBufferCountActual = kNumPictureBuffers;
340 port_format.nBufferCountMin = kNumPictureBuffers;
341 output_buffer_count_ = kNumPictureBuffers;
342
343 result = OMX_SetParameter(component_handle_,
344 OMX_IndexParamPortDefinition,
345 &port_format);
346 if (result != OMX_ErrorNone) {
347 LOG(ERROR) << "SetParameter(OMX_IndexParamPortDefinition) failed";
348 StopOnError();
349 return;
350 }
351 } else {
352 output_buffer_count_ = port_format.nBufferCountActual;
353 }
354 output_buffer_size_ = port_format.nBufferSize;
355
356 if (!AllocateOutputBuffers()) {
357 LOG(ERROR) << "OMX_AllocateBuffer() Output buffer error";
358 StopOnError();
359 }
360 }
361
362 void OmxVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
363 // TODO(vhiremath@nvidia.com) Avoid leaking of the picture buffer.
364 if (!CanFillBuffer())
365 return;
366
367 for (int i = 0; i < output_buffer_count_; ++i) {
368 if (picture_buffer_id != assigned_picture_buffers_[i]->id())
369 continue;
370 output_buffers_at_component_++;
371 OMX_ERRORTYPE result =
372 OMX_FillThisBuffer(component_handle_, output_pictures_[i].second);
373 if (result != OMX_ErrorNone) {
374 LOG(ERROR) << "OMX_FillThisBuffer() failed with result " << result;
375 StopOnError();
376 }
377 // Sent one buffer to omx.
378 return;
379 }
380 }
381
382 void OmxVideoDecodeAccelerator::InitialFillBuffer() {
383 if (!CanFillBuffer())
384 return;
385
386 // Ask the decoder to fill the output buffers.
387 for (uint32 i = 0; i < output_pictures_.size(); ++i) {
388 OMX_BUFFERHEADERTYPE* omx_buffer = output_pictures_[i].second;
389 // clear EOS flag.
390 omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
391 omx_buffer->nOutputPortIndex = output_port_;
392 output_buffers_at_component_++;
393 OMX_ERRORTYPE result = OMX_FillThisBuffer(component_handle_, omx_buffer);
394 if (result != OMX_ErrorNone) {
395 LOG(ERROR) << "OMX_FillThisBuffer() failed with result " << result;
396 StopOnError();
397 return;
398 }
399 }
400 }
401
402 bool OmxVideoDecodeAccelerator::Flush() {
403 OMX_STATETYPE il_state;
404 OMX_GetState(component_handle_, &il_state);
405 DCHECK_EQ(il_state, OMX_StateExecuting);
406 if (il_state != OMX_StateExecuting) {
407 client_->NotifyFlushDone();
408 return false;
409 }
410 on_buffer_flag_event_func_ = &OmxVideoDecodeAccelerator::FlushBegin;
411
412 OMX_BUFFERHEADERTYPE* omx_buffer = free_input_buffers_.front();
413 free_input_buffers_.pop();
414 omx_buffer->nFilledLen = 0;
415 omx_buffer->nAllocLen = omx_buffer->nFilledLen;
416 omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
417 omx_buffer->nTimeStamp = 0;
418 // Give this buffer to OMX.
419 OMX_ERRORTYPE result = OMX_ErrorNone;
420 result = OMX_EmptyThisBuffer(component_handle_, omx_buffer);
421 if (result != OMX_ErrorNone) {
422 LOG(ERROR) << "OMX_EmptyThisBuffer() failed with result " << result;
423 StopOnError();
424 return false;
425 }
426 input_buffers_at_component_++;
427 return true;
428 }
429
430 void OmxVideoDecodeAccelerator::FlushBegin() {
431 VLOG(1) << "Starting actual flush for EOS";
432 on_state_event_func_ = &OmxVideoDecodeAccelerator::PauseFromExecuting;
433 TransitionToState(OMX_StatePause);
434 }
435
436 void OmxVideoDecodeAccelerator::PauseFromExecuting(OMX_STATETYPE ignored) {
437 on_state_event_func_ = NULL;
438 FlushIOPorts();
439 }
440
441 void OmxVideoDecodeAccelerator::FlushIOPorts() {
442 // TODO(vhiremath@nvidia.com) review again for trick modes.
443 VLOG(1) << "FlushIOPorts";
444
445 // Flush input port first.
446 on_flush_event_func_ = &OmxVideoDecodeAccelerator::PortFlushDone;
447 OMX_ERRORTYPE result;
448 result = OMX_SendCommand(component_handle_,
449 OMX_CommandFlush,
450 input_port_, 0);
451 if (result != OMX_ErrorNone) {
452 LOG(ERROR) << "OMX_SendCommand(OMX_CommandFlush) failed";
453 StopOnError();
454 return;
455 }
456 }
457
458 void OmxVideoDecodeAccelerator::PortFlushDone(int port) {
459 DCHECK_NE(port, static_cast<int>(OMX_ALL));
460
461 if (port == input_port_) {
462 VLOG(1) << "Input Port had been flushed";
463 DCHECK_EQ(input_buffers_at_component_, 0);
464 // Flush output port next.
465 OMX_ERRORTYPE result;
466 result = OMX_SendCommand(component_handle_,
467 OMX_CommandFlush,
468 output_port_, 0);
469 if (result != OMX_ErrorNone) {
470 LOG(ERROR) << "OMX_SendCommand(OMX_CommandFlush) failed";
471 StopOnError();
472 return;
473 }
474 return;
475 }
476
477 if (port == output_port_) {
478 VLOG(1) << "Output Port had been flushed";
479 DCHECK_EQ(output_buffers_at_component_, 0);
480 }
481
482 client_state_ = OMX_StatePause;
483 // So Finally call OnPortCommandFlush which should
484 // internally call DismissPictureBuffer();
485 OnPortCommandFlush(OMX_StateExecuting);
486 }
487
488 bool OmxVideoDecodeAccelerator::Abort() {
489 // TODO(vhiremath@nvidia.com)
490 // Need more thinking on this to handle w.r.t OMX.
491 // There is no explicit UnInitialize call for this.
492 // Also review again for trick modes.
493 client_->NotifyAbortDone();
494 return true;
495 }
496
497 // Event callback during initialization to handle DoneStateSet to idle
498 void OmxVideoDecodeAccelerator::OnStateChangeLoadedToIdle(OMX_STATETYPE state) {
499 DCHECK_EQ(client_state_, OMX_StateLoaded);
500 DCHECK_EQ(OMX_StateIdle, state);
501 VLOG(1) << "OMX video decode engine is in Idle";
502
503 on_state_event_func_ =
504 &OmxVideoDecodeAccelerator::OnStateChangeIdleToExecuting;
505 if (!TransitionToState(OMX_StateExecuting))
506 return;
507 }
508
509 // Event callback during initialization to handle DoneStateSet to executing
510 void OmxVideoDecodeAccelerator::OnStateChangeIdleToExecuting(
511 OMX_STATETYPE state) {
512 DCHECK_EQ(OMX_StateExecuting, state);
513 VLOG(1) << "OMX video decode engine is in Executing";
514
515 client_state_ = OMX_StateExecuting;
516 on_state_event_func_ = NULL;
517 // This will kickoff the actual decoding
518 InitialFillBuffer();
519 }
520
521 // Send state transition command to component.
522 bool OmxVideoDecodeAccelerator::TransitionToState(OMX_STATETYPE new_state) {
523 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_,
524 OMX_CommandStateSet,
525 new_state, 0);
526 if (result != OMX_ErrorNone) {
527 LOG(ERROR) << "SendCommand(OMX_CommandStateSet) failed";
528 StopOnError();
529 return false;
530 }
531 return true;
532 }
533
534 void OmxVideoDecodeAccelerator::OnPortCommandFlush(OMX_STATETYPE state) {
535 DCHECK_EQ(state, OMX_StateExecuting);
536
537 VLOG(1) << "Deinit from Executing";
538 on_state_event_func_ =
539 &OmxVideoDecodeAccelerator::OnStateChangeExecutingToIdle;
540 TransitionToState(OMX_StateIdle);
541 for (int i = 0; i < output_buffer_count_; ++i) {
542 OutputPicture output_picture = output_pictures_[i];
543 client_->DismissPictureBuffer(output_picture.first);
544 }
545 STLDeleteElements(&assigned_picture_buffers_);
546 }
547
548 void OmxVideoDecodeAccelerator::OnStateChangeExecutingToIdle(
549 OMX_STATETYPE state) {
550 DCHECK_EQ(state, OMX_StateIdle);
551
552 VLOG(1) << "Deinit from Idle";
553 on_state_event_func_ =
554 &OmxVideoDecodeAccelerator::OnStateChangeIdleToLoaded;
555 TransitionToState(OMX_StateLoaded);
556
557 if (!input_buffers_at_component_)
558 FreeInputBuffers();
559
560 if (!output_buffers_at_component_)
561 FreeOutputBuffers();
562 }
563
564 void OmxVideoDecodeAccelerator::OnStateChangeIdleToLoaded(OMX_STATETYPE state) {
565 DCHECK_EQ(state, OMX_StateLoaded);
566
567 VLOG(1) << "Idle to Loaded";
568
569 if (component_handle_) {
570 OMX_ERRORTYPE result = (*omx_free_handle)(component_handle_);
571 if (result != OMX_ErrorNone)
572 LOG(ERROR) << "OMX_FreeHandle() error. Error code: " << result;
573 component_handle_ = NULL;
574 }
575 client_state_ = OMX_StateLoaded;
576 (*omx_deinit)();
577 VLOG(1) << "OMX Deinit Clean exit done";
578 client_->NotifyFlushDone();
579 }
580
581 void OmxVideoDecodeAccelerator::StopOnError() {
582 OMX_STATETYPE il_state;
583 OMX_GetState(component_handle_, &il_state);
584 client_state_ = OMX_StateInvalid;
585 switch (il_state) {
586 case OMX_StateExecuting:
587 OnPortCommandFlush(OMX_StateExecuting);
588 return;
589 case OMX_StateIdle:
590 OnStateChangeExecutingToIdle(OMX_StateIdle);
591 return;
592 case OMX_StateLoaded:
593 OnStateChangeIdleToLoaded(OMX_StateLoaded);
594 return;
595 default:
596 // LOG unexpected state or just ignore?
597 return;
598 }
599 }
600
601 bool OmxVideoDecodeAccelerator::AllocateInputBuffers() {
602 scoped_array<uint8> data(new uint8[input_buffer_size_]);
603
604 for (int i = 0; i < input_buffer_count_; ++i) {
605 OMX_BUFFERHEADERTYPE* buffer;
606 OMX_ERRORTYPE result =
607 OMX_UseBuffer(component_handle_, &buffer, input_port_,
608 this, input_buffer_size_, data.get());
609 if (result != OMX_ErrorNone)
610 return false;
611 buffer->nInputPortIndex = input_port_;
612 buffer->nOffset = 0;
613 buffer->nFlags = 0;
614 free_input_buffers_.push(buffer);
615 }
616 return true;
617 }
618
619 bool OmxVideoDecodeAccelerator::AllocateOutputBuffers() {
620 static Gles2TextureToEglImageTranslator* texture2eglImage_translator(
621 new Gles2TextureToEglImageTranslator(NULL, 0));
622
623 gfx::Size decoded_pixel_size(width_, height_);
624 gfx::Size visible_pixel_size(width_, height_);
625 // TODO(fischman): remove garbage bitstream buffer id's below (42 and 24) when
626 // the bitstream_buffer_id field is removed from Picture.
627 if (uses_egl_image_) {
628 for (uint32 i = 0; i < assigned_picture_buffers_.size(); i++) {
629 media::GLESBuffer* gles_buffer =
630 reinterpret_cast<media::GLESBuffer*>(assigned_picture_buffers_[i]);
631 OMX_BUFFERHEADERTYPE* omx_buffer;
632 void* egl = texture2eglImage_translator->TranslateToEglImage(
633 gles_buffer->texture_id());
634 OMX_ERRORTYPE result = OMX_UseEGLImage(
635 component_handle_, &omx_buffer, output_port_, gles_buffer, egl);
636 if (result != OMX_ErrorNone) {
637 LOG(ERROR) << "OMX_UseEGLImage failed";
638 return false;
639 }
640 omx_buffer->pAppPrivate =
641 new media::Picture(gles_buffer->id(),
642 42 /* garbage bitstreambuffer id */,
643 decoded_pixel_size, visible_pixel_size);
644 output_pictures_.push_back(
645 std::make_pair(assigned_picture_buffers_[i]->id(), omx_buffer));
646 }
647 } else {
648 for (uint32 i = 0; i < assigned_picture_buffers_.size(); i++) {
649 media::SysmemBuffer* sysmem_buffer =
650 reinterpret_cast<media::SysmemBuffer*>(assigned_picture_buffers_[i]);
651 OMX_BUFFERHEADERTYPE* omx_buffer;
652 OMX_ERRORTYPE result = OMX_AllocateBuffer(
653 component_handle_, &omx_buffer, output_port_, NULL,
654 output_buffer_size_);
655 if (result != OMX_ErrorNone)
656 return false;
657 omx_buffer->pAppPrivate = new media::Picture(
658 sysmem_buffer->id(),
659 24 /* garbage bitstreambuffer id */,
660 decoded_pixel_size, visible_pixel_size);
661 output_pictures_.push_back(
662 std::make_pair(sysmem_buffer->id(), omx_buffer));
663 }
664 }
665 return true;
666 }
667
668 void OmxVideoDecodeAccelerator::FreeInputBuffers() {
669 // Calls to OMX to free buffers.
670 OMX_ERRORTYPE result;
671 OMX_BUFFERHEADERTYPE* omx_buffer;
672 while (!free_input_buffers_.empty()) {
673 omx_buffer = free_input_buffers_.front();
674 free_input_buffers_.pop();
675 result = OMX_FreeBuffer(component_handle_, input_port_, omx_buffer);
676 if (result != OMX_ErrorNone) {
677 LOG(ERROR) << "SendCommand(OMX_CommandPortDisable) failed";
678 StopOnError();
679 return;
680 }
681 }
682 }
683
684 void OmxVideoDecodeAccelerator::FreeOutputBuffers() {
685 // Calls to OMX to free buffers.
686 OMX_ERRORTYPE result;
687 for (size_t i = 0; i < output_pictures_.size(); ++i) {
688 OMX_BUFFERHEADERTYPE* omx_buffer = output_pictures_[i].second;
689 CHECK(omx_buffer);
690 delete reinterpret_cast<media::Picture*>(omx_buffer->pAppPrivate);
691 result = OMX_FreeBuffer(component_handle_, output_port_, omx_buffer);
692 if (result != OMX_ErrorNone) {
693 LOG(ERROR) << "SendCommand(OMX_CommandPortDisable) failed";
694 StopOnError();
695 return;
696 }
697 }
698 output_pictures_.clear();
699 }
700
701 void OmxVideoDecodeAccelerator::OnPortSettingsChangedRun(
702 int port, OMX_INDEXTYPE index) {
703 // TODO(vhiremath@nvidia.com) visit again later
704 // Port settings changes can be called during run time
705 // changes in the resolution of video playback.
706 // In this case, the component detects PortSettingsChanged
707 // and sends the particular event to the IL-client.
708 // This needs to be handled in this method.
709 return;
710 }
711
712 void OmxVideoDecodeAccelerator::FillBufferDoneTask(
713 OMX_BUFFERHEADERTYPE* buffer) {
714 DCHECK_GT(output_buffers_at_component_, 0);
715 output_buffers_at_component_--;
716 client_->PictureReady(*reinterpret_cast<media::Picture*>(
717 buffer->pAppPrivate));
718 }
719
720 void OmxVideoDecodeAccelerator::EmptyBufferDoneTask(
721 OMX_BUFFERHEADERTYPE* buffer) {
722 DCHECK_GT(input_buffers_at_component_, 0);
723 free_input_buffers_.push(buffer);
724 input_buffers_at_component_--;
725 if (buffer->nFlags & OMX_BUFFERFLAG_EOS)
726 return;
727 // Retrieve the corresponding BitstreamBuffer's id and notify the client of
728 // its completion.
729 OMXBufferIdMap::iterator it = omx_buff_ids_.find(buffer);
730 if (it == omx_buff_ids_.end()) {
731 LOG(ERROR) << "Unexpectedly failed to find a buffer id.";
732 StopOnError();
733 return;
734 }
735 delete it->second.first;
736 client_->NotifyEndOfBitstreamBuffer(it->second.second);
737 omx_buff_ids_.erase(it);
738 }
739
740 void OmxVideoDecodeAccelerator::EventHandlerCompleteTask(OMX_EVENTTYPE event,
741 OMX_U32 data1,
742 OMX_U32 data2) {
743 switch (event) {
744 case OMX_EventCmdComplete: {
745 // If the last command was successful, we have completed
746 // a state transition. So notify that we have done it
747 // accordingly.
748 OMX_COMMANDTYPE cmd = static_cast<OMX_COMMANDTYPE>(data1);
749 switch (cmd) {
750 case OMX_CommandPortDisable: {
751 if (on_port_disable_event_func_)
752 (this->*on_port_disable_event_func_)(static_cast<int>(data2));
753 }
754 break;
755 case OMX_CommandPortEnable: {
756 if (on_port_enable_event_func_)
757 (this->*on_port_enable_event_func_)(static_cast<int>(data2));
758 }
759 break;
760 case OMX_CommandStateSet:
761 (this->*on_state_event_func_)(static_cast<OMX_STATETYPE>(data2));
762 break;
763 case OMX_CommandFlush:
764 (this->*on_flush_event_func_)(data2);
765 break;
766 default:
767 LOG(ERROR) << "Unknown command completed\n" << data1;
768 break;
769 }
770 break;
771 }
772 case OMX_EventError:
773 if (static_cast<OMX_ERRORTYPE>(data1) == OMX_ErrorInvalidState)
774 StopOnError();
775 break;
776 case OMX_EventPortSettingsChanged:
777 // TODO(vhiremath@nvidia.com) remove this hack
778 // when all vendors observe same spec.
779 if (data1 < OMX_IndexComponentStartUnused) {
780 OnPortSettingsChangedRun(static_cast<int>(data1),
781 static_cast<OMX_INDEXTYPE>(data2));
782 } else {
783 OnPortSettingsChangedRun(static_cast<int>(data2),
784 static_cast<OMX_INDEXTYPE>(data1));
785 }
786 break;
787 case OMX_EventBufferFlag:
788 if (data1 == static_cast<OMX_U32>(output_port_)) {
789 (this->*on_buffer_flag_event_func_)();
790 }
791 break;
792 default:
793 LOG(ERROR) << "Warning - Unknown event received\n";
794 break;
795 }
796 }
797
798 // static
799 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EventHandler(OMX_HANDLETYPE component,
800 OMX_PTR priv_data,
801 OMX_EVENTTYPE event,
802 OMX_U32 data1,
803 OMX_U32 data2,
804 OMX_PTR event_data) {
805 OmxVideoDecodeAccelerator* decoder =
806 static_cast<OmxVideoDecodeAccelerator*>(priv_data);
807 DCHECK_EQ(component, decoder->component_handle_);
808
809 decoder->message_loop_->PostTask(
810 FROM_HERE,
811 NewRunnableMethod(decoder,
812 &OmxVideoDecodeAccelerator::EventHandlerCompleteTask,
813 event, data1, data2));
814
815 return OMX_ErrorNone;
816 }
817
818 // static
819 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EmptyBufferCallback(
820 OMX_HANDLETYPE component,
821 OMX_PTR priv_data,
822 OMX_BUFFERHEADERTYPE* buffer) {
823 OmxVideoDecodeAccelerator* decoder =
824 static_cast<OmxVideoDecodeAccelerator*>(priv_data);
825 DCHECK_EQ(component, decoder->component_handle_);
826
827 decoder->message_loop_->PostTask(
828 FROM_HERE,
829 NewRunnableMethod(
830 decoder,
831 &OmxVideoDecodeAccelerator::EmptyBufferDoneTask, buffer));
832 return OMX_ErrorNone;
833 }
834
835 // static
836 OMX_ERRORTYPE OmxVideoDecodeAccelerator::FillBufferCallback(
837 OMX_HANDLETYPE component,
838 OMX_PTR priv_data,
839 OMX_BUFFERHEADERTYPE* buffer) {
840 OmxVideoDecodeAccelerator* decoder =
841 static_cast<OmxVideoDecodeAccelerator*>(priv_data);
842 DCHECK_EQ(component, decoder->component_handle_);
843
844 decoder->message_loop_->PostTask(
845 FROM_HERE,
846 NewRunnableMethod(
847 decoder,
848 &OmxVideoDecodeAccelerator::FillBufferDoneTask, buffer));
849 return OMX_ErrorNone;
850 }
851
852 bool OmxVideoDecodeAccelerator::CanAcceptInput() {
853 // We can't take input buffer when in error state.
854 return (client_state_ != OMX_StateInvalid &&
855 client_state_ != OMX_StatePause &&
856 client_state_ != OMX_StateLoaded);
857 }
858
859 bool OmxVideoDecodeAccelerator::CanFillBuffer() {
860 // Make sure component is in the executing state and end-of-stream
861 // has not been reached.
862 OMX_ERRORTYPE result;
863 OMX_STATETYPE il_state;
864 if (client_state_ == OMX_StateLoaded)
865 return false;
866 result = OMX_GetState(component_handle_, &il_state);
867 if (result != OMX_ErrorNone) {
868 LOG(ERROR) << "SendCommand(OMX_CommandPortDisable) failed";
869 StopOnError();
870 return false;
871 }
872 return (il_state == OMX_StateExecuting);
873 }
874
875 // Send command to disable/enable port.
876 void OmxVideoDecodeAccelerator::ChangePort(
877 OMX_COMMANDTYPE cmd, int port_index) {
878 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_,
879 cmd, port_index, 0);
880 if (result != OMX_ErrorNone) {
881 LOG(ERROR) << "SendCommand(OMX_CommandPortDisable) failed";
882 StopOnError();
883 return;
884 }
885 }
886
887 DISABLE_RUNNABLE_METHOD_REFCOUNT(OmxVideoDecodeAccelerator);
OLDNEW
« no previous file with comments | « content/common/gpu/omx_video_decode_accelerator.h ('k') | content/content_common.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698