OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/common/gpu/media/omx_video_decode_accelerator.h" | 5 #include "content/common/gpu/media/omx_video_decode_accelerator.h" |
6 | 6 |
7 #include "base/stl_util-inl.h" | 7 #include "base/stl_util-inl.h" |
8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
9 #include "content/common/gpu/gpu_channel.h" | 9 #include "content/common/gpu/gpu_channel.h" |
10 #include "content/common/gpu/media/gles2_texture_to_egl_image_translator.h" | 10 #include "content/common/gpu/media/gles2_texture_to_egl_image_translator.h" |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 #define RETURN_ON_FAILURE(result, log, error, ret_val) \ | 50 #define RETURN_ON_FAILURE(result, log, error, ret_val) \ |
51 do { \ | 51 do { \ |
52 if (!(result)) { \ | 52 if (!(result)) { \ |
53 LOG(ERROR) << log; \ | 53 LOG(ERROR) << log; \ |
54 StopOnError(error); \ | 54 StopOnError(error); \ |
55 return ret_val; \ | 55 return ret_val; \ |
56 } \ | 56 } \ |
57 } while (0) | 57 } while (0) |
58 | 58 |
59 // OMX-specific version of RETURN_ON_FAILURE which compares with OMX_ErrorNone. | 59 // OMX-specific version of RETURN_ON_FAILURE which compares with OMX_ErrorNone. |
60 #define RETURN_ON_OMX_FAILURE(omx_result, log, error, ret_val) \ | 60 #define RETURN_ON_OMX_FAILURE(omx_result, log, error, ret_val) \ |
61 RETURN_ON_FAILURE( \ | 61 RETURN_ON_FAILURE( \ |
62 ((omx_result) == OMX_ErrorNone), \ | 62 ((omx_result) == OMX_ErrorNone), \ |
63 log << ", OMX result: " << std::hex << std::showbase << omx_result, \ | 63 log << ", OMX result: 0x" << std::hex << omx_result, \ |
64 error, ret_val) | 64 error, ret_val) |
65 | 65 |
66 OmxVideoDecodeAccelerator::OmxVideoDecodeAccelerator( | 66 OmxVideoDecodeAccelerator::OmxVideoDecodeAccelerator( |
67 media::VideoDecodeAccelerator::Client* client) | 67 media::VideoDecodeAccelerator::Client* client) |
68 : message_loop_(MessageLoop::current()), | 68 : message_loop_(MessageLoop::current()), |
69 component_handle_(NULL), | 69 component_handle_(NULL), |
70 client_state_(OMX_StateMax), | 70 client_state_(OMX_StateMax), |
71 current_state_change_(NO_TRANSITION), | 71 current_state_change_(NO_TRANSITION), |
72 saw_eos_during_flush_(false), | 72 saw_eos_during_flush_(false), |
73 input_buffer_count_(0), | 73 input_buffer_count_(0), |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 scoped_array<OMX_U8> component(new OMX_U8[OMX_MAX_STRINGNAME_SIZE]); | 175 scoped_array<OMX_U8> component(new OMX_U8[OMX_MAX_STRINGNAME_SIZE]); |
176 OMX_ERRORTYPE result = omx_get_components_of_role( | 176 OMX_ERRORTYPE result = omx_get_components_of_role( |
177 role_name, &num_components, reinterpret_cast<OMX_U8**>(&component)); | 177 role_name, &num_components, reinterpret_cast<OMX_U8**>(&component)); |
178 RETURN_ON_OMX_FAILURE(result, "Unsupport role: " << role_name, | 178 RETURN_ON_OMX_FAILURE(result, "Unsupport role: " << role_name, |
179 VIDEODECODERERROR_UNSUPPORTED, false); | 179 VIDEODECODERERROR_UNSUPPORTED, false); |
180 RETURN_ON_FAILURE(num_components == 1, | 180 RETURN_ON_FAILURE(num_components == 1, |
181 "No components for: " << role_name, | 181 "No components for: " << role_name, |
182 VIDEODECODERERROR_UNSUPPORTED, false); | 182 VIDEODECODERERROR_UNSUPPORTED, false); |
183 | 183 |
184 // Get the handle to the component. | 184 // Get the handle to the component. |
| 185 AddRef(); // To reflect passing |this| to OMX_GetHandle below. |
185 result = omx_gethandle( | 186 result = omx_gethandle( |
186 &component_handle_, reinterpret_cast<OMX_STRING>(component.get()), | 187 &component_handle_, reinterpret_cast<OMX_STRING>(component.get()), |
187 this, &omx_accelerator_callbacks); | 188 this, &omx_accelerator_callbacks); |
188 RETURN_ON_OMX_FAILURE(result, | 189 RETURN_ON_OMX_FAILURE(result, |
189 "Failed to OMX_GetHandle on: " << component.get(), | 190 "Failed to OMX_GetHandle on: " << component.get(), |
190 VIDEODECODERERROR_INSUFFICIENT_RESOURCES, false); | 191 VIDEODECODERERROR_INSUFFICIENT_RESOURCES, false); |
191 client_state_ = OMX_StateLoaded; | 192 client_state_ = OMX_StateLoaded; |
192 | 193 |
193 // Get the port information. This will obtain information about the number of | 194 // Get the port information. This will obtain information about the number of |
194 // ports and index of the first port. | 195 // ports and index of the first port. |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 RETURN_ON_OMX_FAILURE(result, | 259 RETURN_ON_OMX_FAILURE(result, |
259 "SetParameter(OMX_IndexParamPortDefinition) failed", | 260 "SetParameter(OMX_IndexParamPortDefinition) failed", |
260 VIDEODECODERERROR_INVALIDINPUT, false); | 261 VIDEODECODERERROR_INVALIDINPUT, false); |
261 | 262 |
262 // Fill the component with fake output buffers. This seems to be required for | 263 // Fill the component with fake output buffers. This seems to be required for |
263 // the component to move from Loaded to Idle. How bogus. | 264 // the component to move from Loaded to Idle. How bogus. |
264 for (int i = 0; i < kNumPictureBuffers; ++i) { | 265 for (int i = 0; i < kNumPictureBuffers; ++i) { |
265 OMX_BUFFERHEADERTYPE* buffer; | 266 OMX_BUFFERHEADERTYPE* buffer; |
266 result = OMX_UseBuffer(component_handle_, &buffer, output_port_, | 267 result = OMX_UseBuffer(component_handle_, &buffer, output_port_, |
267 NULL, 0, reinterpret_cast<OMX_U8*>(0x1)); | 268 NULL, 0, reinterpret_cast<OMX_U8*>(0x1)); |
268 RETURN_ON_OMX_FAILURE(result, "OMX_UseBuffer failed with: " << result, | 269 RETURN_ON_OMX_FAILURE(result, "OMX_UseBuffer failed", |
269 VIDEODECODERERROR_INVALIDINPUT, false); | 270 VIDEODECODERERROR_INVALIDINPUT, false); |
270 buffer->pAppPrivate = NULL; | 271 buffer->pAppPrivate = NULL; |
271 buffer->nTimeStamp = -1; | 272 buffer->nTimeStamp = -1; |
272 buffer->nOutputPortIndex = output_port_; | 273 buffer->nOutputPortIndex = output_port_; |
273 CHECK(fake_output_buffers_.insert(buffer).second); | 274 CHECK(fake_output_buffers_.insert(buffer).second); |
274 } | 275 } |
275 | 276 |
276 return true; | 277 return true; |
277 } | 278 } |
278 | 279 |
279 void OmxVideoDecodeAccelerator::Decode( | 280 void OmxVideoDecodeAccelerator::Decode( |
280 const media::BitstreamBuffer& bitstream_buffer) { | 281 const media::BitstreamBuffer& bitstream_buffer) { |
281 DCHECK_EQ(message_loop_, MessageLoop::current()); | 282 DCHECK_EQ(message_loop_, MessageLoop::current()); |
282 DCHECK(!free_input_buffers_.empty()); | 283 DCHECK(!free_input_buffers_.empty()); |
283 | 284 |
284 RETURN_ON_FAILURE(current_state_change_ == NO_TRANSITION && | 285 RETURN_ON_FAILURE(current_state_change_ == NO_TRANSITION && |
285 (client_state_ == OMX_StateIdle || | 286 (client_state_ == OMX_StateIdle || |
286 client_state_ == OMX_StateExecuting), | 287 client_state_ == OMX_StateExecuting), |
287 "Call to Decode() during invalid state or transition:" | 288 "Call to Decode() during invalid state or transition: " |
288 << current_state_change_ << ", " << client_state_, | 289 << current_state_change_ << ", " << client_state_, |
289 VIDEODECODERERROR_UNSUPPORTED,); | 290 VIDEODECODERERROR_UNSUPPORTED,); |
290 | 291 |
291 OMX_BUFFERHEADERTYPE* omx_buffer = free_input_buffers_.front(); | 292 OMX_BUFFERHEADERTYPE* omx_buffer = free_input_buffers_.front(); |
292 free_input_buffers_.pop(); | 293 free_input_buffers_.pop(); |
293 | 294 |
294 // Setup |omx_buffer|. | 295 // Setup |omx_buffer|. |
295 scoped_ptr<base::SharedMemory> shm( | 296 scoped_ptr<base::SharedMemory> shm( |
296 new base::SharedMemory(bitstream_buffer.handle(), true)); | 297 new base::SharedMemory(bitstream_buffer.handle(), true)); |
297 RETURN_ON_FAILURE(shm->Map(bitstream_buffer.size()), | 298 RETURN_ON_FAILURE(shm->Map(bitstream_buffer.size()), |
(...skipping 10 matching lines...) Expand all Loading... |
308 omx_buffer->nFilledLen = bitstream_buffer.size(); | 309 omx_buffer->nFilledLen = bitstream_buffer.size(); |
309 omx_buffer->nAllocLen = omx_buffer->nFilledLen; | 310 omx_buffer->nAllocLen = omx_buffer->nFilledLen; |
310 omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS; | 311 omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS; |
311 // Abuse the header's nTimeStamp field to propagate the bitstream buffer ID to | 312 // Abuse the header's nTimeStamp field to propagate the bitstream buffer ID to |
312 // the output buffer's nTimeStamp field, so we can report it back to the | 313 // the output buffer's nTimeStamp field, so we can report it back to the |
313 // client in PictureReady(). | 314 // client in PictureReady(). |
314 omx_buffer->nTimeStamp = bitstream_buffer.id(); | 315 omx_buffer->nTimeStamp = bitstream_buffer.id(); |
315 | 316 |
316 // Give this buffer to OMX. | 317 // Give this buffer to OMX. |
317 OMX_ERRORTYPE result = OMX_EmptyThisBuffer(component_handle_, omx_buffer); | 318 OMX_ERRORTYPE result = OMX_EmptyThisBuffer(component_handle_, omx_buffer); |
318 RETURN_ON_OMX_FAILURE(result, | 319 RETURN_ON_OMX_FAILURE(result, "OMX_EmptyThisBuffer() failed", |
319 "OMX_EmptyThisBuffer() failed with result " << result, | |
320 VIDEODECODERERROR_INVALIDINPUT,); | 320 VIDEODECODERERROR_INVALIDINPUT,); |
321 | 321 |
322 input_buffers_at_component_++; | 322 input_buffers_at_component_++; |
323 } | 323 } |
324 | 324 |
325 void OmxVideoDecodeAccelerator::AssignGLESBuffers( | 325 void OmxVideoDecodeAccelerator::AssignGLESBuffers( |
326 const std::vector<media::GLESBuffer>& buffers) { | 326 const std::vector<media::GLESBuffer>& buffers) { |
327 DCHECK_EQ(message_loop_, MessageLoop::current()); | 327 DCHECK_EQ(message_loop_, MessageLoop::current()); |
328 RETURN_ON_FAILURE(CanFillBuffer(), "Can't fill buffer", | 328 RETURN_ON_FAILURE(CanFillBuffer(), "Can't fill buffer", |
329 VIDEODECODERERROR_UNSUPPORTED,); | 329 VIDEODECODERERROR_UNSUPPORTED,); |
(...skipping 28 matching lines...) Expand all Loading... |
358 | 358 |
359 OutputPictureById::iterator it = pictures_.find(picture_buffer_id); | 359 OutputPictureById::iterator it = pictures_.find(picture_buffer_id); |
360 RETURN_ON_FAILURE(it != pictures_.end(), | 360 RETURN_ON_FAILURE(it != pictures_.end(), |
361 "Missing picture buffer id: " << picture_buffer_id, | 361 "Missing picture buffer id: " << picture_buffer_id, |
362 VIDEODECODERERROR_UNSUPPORTED,); | 362 VIDEODECODERERROR_UNSUPPORTED,); |
363 OutputPicture& output_picture = it->second; | 363 OutputPicture& output_picture = it->second; |
364 | 364 |
365 ++output_buffers_at_component_; | 365 ++output_buffers_at_component_; |
366 OMX_ERRORTYPE result = | 366 OMX_ERRORTYPE result = |
367 OMX_FillThisBuffer(component_handle_, output_picture.omx_buffer_header); | 367 OMX_FillThisBuffer(component_handle_, output_picture.omx_buffer_header); |
368 RETURN_ON_OMX_FAILURE(result, | 368 RETURN_ON_OMX_FAILURE(result, "OMX_FillThisBuffer() failed", |
369 "OMX_FillThisBuffer() failed with result " << result, | |
370 VIDEODECODERERROR_INVALIDINPUT,); | 369 VIDEODECODERERROR_INVALIDINPUT,); |
371 } | 370 } |
372 | 371 |
373 void OmxVideoDecodeAccelerator::Flush() { | 372 void OmxVideoDecodeAccelerator::Flush() { |
374 DCHECK_EQ(message_loop_, MessageLoop::current()); | 373 DCHECK_EQ(message_loop_, MessageLoop::current()); |
375 DCHECK_EQ(current_state_change_, NO_TRANSITION); | 374 DCHECK_EQ(current_state_change_, NO_TRANSITION); |
376 DCHECK_EQ(client_state_, OMX_StateExecuting); | 375 DCHECK_EQ(client_state_, OMX_StateExecuting); |
377 current_state_change_ = FLUSHING; | 376 current_state_change_ = FLUSHING; |
378 | 377 |
379 // Cook up an empty buffer w/ EOS set and feed it to OMX. | 378 // Cook up an empty buffer w/ EOS set and feed it to OMX. |
380 OMX_BUFFERHEADERTYPE* omx_buffer = free_input_buffers_.front(); | 379 OMX_BUFFERHEADERTYPE* omx_buffer = free_input_buffers_.front(); |
381 free_input_buffers_.pop(); | 380 free_input_buffers_.pop(); |
382 omx_buffer->nFilledLen = 0; | 381 omx_buffer->nFilledLen = 0; |
383 omx_buffer->nAllocLen = omx_buffer->nFilledLen; | 382 omx_buffer->nAllocLen = omx_buffer->nFilledLen; |
384 omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS; | 383 omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS; |
385 omx_buffer->nTimeStamp = -2; | 384 omx_buffer->nTimeStamp = -2; |
386 OMX_ERRORTYPE result = OMX_EmptyThisBuffer(component_handle_, omx_buffer); | 385 OMX_ERRORTYPE result = OMX_EmptyThisBuffer(component_handle_, omx_buffer); |
387 RETURN_ON_OMX_FAILURE(result, | 386 RETURN_ON_OMX_FAILURE(result, "OMX_EmptyThisBuffer() failed", |
388 "OMX_EmptyThisBuffer() failed with result " << result, | |
389 VIDEODECODERERROR_INVALIDINPUT,); | 387 VIDEODECODERERROR_INVALIDINPUT,); |
390 input_buffers_at_component_++; | 388 input_buffers_at_component_++; |
391 } | 389 } |
392 | 390 |
393 void OmxVideoDecodeAccelerator::OnReachedEOSInFlushing() { | 391 void OmxVideoDecodeAccelerator::OnReachedEOSInFlushing() { |
394 DCHECK_EQ(message_loop_, MessageLoop::current()); | 392 DCHECK_EQ(message_loop_, MessageLoop::current()); |
395 BeginTransitionToState(OMX_StatePause); | 393 BeginTransitionToState(OMX_StatePause); |
396 } | 394 } |
397 | 395 |
398 void OmxVideoDecodeAccelerator::FlushIOPorts() { | 396 void OmxVideoDecodeAccelerator::FlushIOPorts() { |
(...skipping 20 matching lines...) Expand all Loading... |
419 void OmxVideoDecodeAccelerator::Reset() { | 417 void OmxVideoDecodeAccelerator::Reset() { |
420 DCHECK_EQ(message_loop_, MessageLoop::current()); | 418 DCHECK_EQ(message_loop_, MessageLoop::current()); |
421 DCHECK_EQ(current_state_change_, NO_TRANSITION); | 419 DCHECK_EQ(current_state_change_, NO_TRANSITION); |
422 DCHECK_EQ(client_state_, OMX_StateExecuting); | 420 DCHECK_EQ(client_state_, OMX_StateExecuting); |
423 current_state_change_ = RESETTING; | 421 current_state_change_ = RESETTING; |
424 BeginTransitionToState(OMX_StatePause); | 422 BeginTransitionToState(OMX_StatePause); |
425 } | 423 } |
426 | 424 |
427 void OmxVideoDecodeAccelerator::Destroy() { | 425 void OmxVideoDecodeAccelerator::Destroy() { |
428 DCHECK_EQ(message_loop_, MessageLoop::current()); | 426 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 427 if (current_state_change_ == ERRORING) |
| 428 return; |
429 DCHECK_EQ(current_state_change_, NO_TRANSITION); | 429 DCHECK_EQ(current_state_change_, NO_TRANSITION); |
| 430 // If we were never initializeed there's no teardown to do. |
| 431 if (client_state_ == OMX_StateMax) |
| 432 return; |
| 433 // If we can already call OMX_FreeHandle, simply do so. |
| 434 if (client_state_ == OMX_StateInvalid || client_state_ == OMX_StateLoaded) { |
| 435 ShutdownComponent(); |
| 436 return; |
| 437 } |
430 DCHECK_EQ(client_state_, OMX_StateExecuting); | 438 DCHECK_EQ(client_state_, OMX_StateExecuting); |
431 current_state_change_ = DESTROYING; | 439 current_state_change_ = DESTROYING; |
| 440 client_ = NULL; |
432 BeginTransitionToState(OMX_StateIdle); | 441 BeginTransitionToState(OMX_StateIdle); |
| 442 BusyLoopInDestroying(); |
433 } | 443 } |
434 | 444 |
435 void OmxVideoDecodeAccelerator::BeginTransitionToState( | 445 void OmxVideoDecodeAccelerator::BeginTransitionToState( |
436 OMX_STATETYPE new_state) { | 446 OMX_STATETYPE new_state) { |
437 DCHECK_EQ(message_loop_, MessageLoop::current()); | 447 DCHECK_EQ(message_loop_, MessageLoop::current()); |
438 DCHECK_NE(current_state_change_, NO_TRANSITION); | 448 DCHECK_NE(current_state_change_, NO_TRANSITION); |
| 449 DCHECK_NE(current_state_change_, ERRORING); |
| 450 if (current_state_change_ == NO_TRANSITION || |
| 451 current_state_change_ == ERRORING) { |
| 452 return; |
| 453 } |
439 OMX_ERRORTYPE result = OMX_SendCommand( | 454 OMX_ERRORTYPE result = OMX_SendCommand( |
440 component_handle_, OMX_CommandStateSet, new_state, 0); | 455 component_handle_, OMX_CommandStateSet, new_state, 0); |
441 RETURN_ON_OMX_FAILURE(result, "SendCommand(OMX_CommandStateSet) failed", | 456 RETURN_ON_OMX_FAILURE(result, "SendCommand(OMX_CommandStateSet) failed", |
442 VIDEODECODERERROR_INVALIDINPUT,); | 457 VIDEODECODERERROR_INVALIDINPUT,); |
443 } | 458 } |
444 | 459 |
445 void OmxVideoDecodeAccelerator::OnReachedIdleInInitializing() { | 460 void OmxVideoDecodeAccelerator::OnReachedIdleInInitializing() { |
446 DCHECK_EQ(client_state_, OMX_StateLoaded); | 461 DCHECK_EQ(client_state_, OMX_StateLoaded); |
447 client_state_ = OMX_StateIdle; | 462 client_state_ = OMX_StateIdle; |
448 BeginTransitionToState(OMX_StateExecuting); | 463 BeginTransitionToState(OMX_StateExecuting); |
449 } | 464 } |
450 | 465 |
451 void OmxVideoDecodeAccelerator::OnReachedExecutingInInitializing() { | 466 void OmxVideoDecodeAccelerator::OnReachedExecutingInInitializing() { |
452 DCHECK_EQ(client_state_, OMX_StateIdle); | 467 DCHECK_EQ(client_state_, OMX_StateIdle); |
453 client_state_ = OMX_StateExecuting; | 468 client_state_ = OMX_StateExecuting; |
454 current_state_change_ = NO_TRANSITION; | 469 current_state_change_ = NO_TRANSITION; |
455 | 470 |
456 // Request filling of our fake buffers to trigger decode processing. In | 471 // Request filling of our fake buffers to trigger decode processing. In |
457 // reality as soon as any data is decoded these will get dismissed due to | 472 // reality as soon as any data is decoded these will get dismissed due to |
458 // dimension mismatch. | 473 // dimension mismatch. |
459 for (std::set<OMX_BUFFERHEADERTYPE*>::iterator it = | 474 for (std::set<OMX_BUFFERHEADERTYPE*>::iterator it = |
460 fake_output_buffers_.begin(); | 475 fake_output_buffers_.begin(); |
461 it != fake_output_buffers_.end(); ++it) { | 476 it != fake_output_buffers_.end(); ++it) { |
462 OMX_BUFFERHEADERTYPE* buffer = *it; | 477 OMX_BUFFERHEADERTYPE* buffer = *it; |
463 OMX_ERRORTYPE result = OMX_FillThisBuffer(component_handle_, buffer); | 478 OMX_ERRORTYPE result = OMX_FillThisBuffer(component_handle_, buffer); |
464 RETURN_ON_OMX_FAILURE(result, | 479 RETURN_ON_OMX_FAILURE(result, "OMX_FillThisBuffer()", |
465 "OMX_FillThisBuffer() failed with: " << result, | |
466 VIDEODECODERERROR_INVALIDINPUT,); | 480 VIDEODECODERERROR_INVALIDINPUT,); |
467 ++output_buffers_at_component_; | 481 ++output_buffers_at_component_; |
468 } | 482 } |
469 | 483 |
470 client_->NotifyInitializeDone(); | 484 if (client_) |
| 485 client_->NotifyInitializeDone(); |
471 } | 486 } |
472 | 487 |
473 void OmxVideoDecodeAccelerator::OnReachedPauseInFlushing() { | 488 void OmxVideoDecodeAccelerator::OnReachedPauseInFlushing() { |
474 DCHECK_EQ(client_state_, OMX_StateExecuting); | 489 DCHECK_EQ(client_state_, OMX_StateExecuting); |
475 client_state_ = OMX_StatePause; | 490 client_state_ = OMX_StatePause; |
476 FlushIOPorts(); | 491 FlushIOPorts(); |
477 } | 492 } |
478 | 493 |
479 void OmxVideoDecodeAccelerator::OnReachedExecutingInFlushing() { | 494 void OmxVideoDecodeAccelerator::OnReachedExecutingInFlushing() { |
480 DCHECK_EQ(client_state_, OMX_StatePause); | 495 DCHECK_EQ(client_state_, OMX_StatePause); |
481 client_state_ = OMX_StateExecuting; | 496 client_state_ = OMX_StateExecuting; |
482 DCHECK(saw_eos_during_flush_); | 497 DCHECK(saw_eos_during_flush_); |
483 saw_eos_during_flush_ = false; | 498 saw_eos_during_flush_ = false; |
484 current_state_change_ = NO_TRANSITION; | 499 current_state_change_ = NO_TRANSITION; |
485 client_->NotifyFlushDone(); | 500 if (client_) |
| 501 client_->NotifyFlushDone(); |
486 } | 502 } |
487 | 503 |
488 void OmxVideoDecodeAccelerator::OnReachedPauseInResetting() { | 504 void OmxVideoDecodeAccelerator::OnReachedPauseInResetting() { |
489 DCHECK_EQ(client_state_, OMX_StateExecuting); | 505 DCHECK_EQ(client_state_, OMX_StateExecuting); |
490 client_state_ = OMX_StatePause; | 506 client_state_ = OMX_StatePause; |
491 FlushIOPorts(); | 507 FlushIOPorts(); |
492 } | 508 } |
493 | 509 |
494 void OmxVideoDecodeAccelerator::OnReachedExecutingInResetting() { | 510 void OmxVideoDecodeAccelerator::OnReachedExecutingInResetting() { |
495 DCHECK_EQ(client_state_, OMX_StatePause); | 511 DCHECK_EQ(client_state_, OMX_StatePause); |
496 client_state_ = OMX_StateExecuting; | 512 client_state_ = OMX_StateExecuting; |
497 current_state_change_ = NO_TRANSITION; | 513 current_state_change_ = NO_TRANSITION; |
498 client_->NotifyResetDone(); | 514 if (client_) |
| 515 client_->NotifyResetDone(); |
| 516 } |
| 517 |
| 518 // Alert: HORROR ahead! OMX shutdown is an asynchronous dance but our clients |
| 519 // enjoy the fire-and-forget nature of a synchronous Destroy() call that |
| 520 // ensures no further callbacks are made. Since the interface between OMX |
| 521 // callbacks and this class is a MessageLoop, we need to ensure the loop |
| 522 // outlives the shutdown dance, even during process shutdown. We do this by |
| 523 // repeatedly enqueuing a no-op task until shutdown is complete, since |
| 524 // MessageLoop's shutdown drains pending tasks. |
| 525 void OmxVideoDecodeAccelerator::BusyLoopInDestroying() { |
| 526 if (!component_handle_) return; |
| 527 // Can't use PostDelayedTask here because MessageLoop doesn't drain delayed |
| 528 // tasks. Instead we sleep for 5ms. Really. |
| 529 base::PlatformThread::Sleep(5); |
| 530 message_loop_->PostTask( |
| 531 FROM_HERE, NewRunnableMethod( |
| 532 this, &OmxVideoDecodeAccelerator::BusyLoopInDestroying)); |
499 } | 533 } |
500 | 534 |
501 void OmxVideoDecodeAccelerator::OnReachedIdleInDestroying() { | 535 void OmxVideoDecodeAccelerator::OnReachedIdleInDestroying() { |
502 DCHECK_EQ(client_state_, OMX_StateExecuting); | 536 DCHECK_EQ(client_state_, OMX_StateExecuting); |
503 client_state_ = OMX_StateIdle; | 537 client_state_ = OMX_StateIdle; |
504 | 538 |
505 // Note that during the Executing -> Idle transition, the OMX spec guarantees | 539 // Note that during the Executing -> Idle transition, the OMX spec guarantees |
506 // buffers have been returned to the client, so we don't need to do an | 540 // buffers have been returned to the client, so we don't need to do an |
507 // explicit FlushIOPorts(). | 541 // explicit FlushIOPorts(). |
508 | 542 |
509 BeginTransitionToState(OMX_StateLoaded); | 543 BeginTransitionToState(OMX_StateLoaded); |
510 | 544 |
511 // TODO(fischman): evaluate what these conditionals are doing. What happens | 545 // TODO(fischman): evaluate what these conditionals are doing. What happens |
512 // if they're false?? | 546 // if they're false?? |
513 if (!input_buffers_at_component_) | 547 if (!input_buffers_at_component_) |
514 FreeInputBuffers(); | 548 FreeInputBuffers(); |
515 if (!output_buffers_at_component_) | 549 if (!output_buffers_at_component_) |
516 FreeOutputBuffers(); | 550 FreeOutputBuffers(); |
517 } | |
518 | 551 |
519 void OmxVideoDecodeAccelerator::ShutdownComponent() { | 552 BusyLoopInDestroying(); |
520 OMX_ERRORTYPE result = omx_free_handle(component_handle_); | |
521 if (result != OMX_ErrorNone) | |
522 LOG(ERROR) << "OMX_FreeHandle() error. Error code: " << result; | |
523 component_handle_ = NULL; | |
524 omx_deinit(); | |
525 client_state_ = OMX_StateMax; | |
526 } | 553 } |
527 | 554 |
528 void OmxVideoDecodeAccelerator::OnReachedLoadedInDestroying() { | 555 void OmxVideoDecodeAccelerator::OnReachedLoadedInDestroying() { |
529 DCHECK_EQ(client_state_, OMX_StateIdle); | 556 DCHECK_EQ(client_state_, OMX_StateIdle); |
530 client_state_ = OMX_StateLoaded; | 557 client_state_ = OMX_StateLoaded; |
531 current_state_change_ = NO_TRANSITION; | 558 current_state_change_ = NO_TRANSITION; |
532 ShutdownComponent(); | 559 ShutdownComponent(); |
533 client_->NotifyDestroyDone(); | |
534 } | 560 } |
535 | 561 |
536 void OmxVideoDecodeAccelerator::OnReachedInvalidInErroring() { | 562 void OmxVideoDecodeAccelerator::OnReachedInvalidInErroring() { |
537 client_state_ = OMX_StateInvalid; | 563 client_state_ = OMX_StateInvalid; |
538 ShutdownComponent(); | 564 ShutdownComponent(); |
539 } | 565 } |
540 | 566 |
| 567 void OmxVideoDecodeAccelerator::ShutdownComponent() { |
| 568 OMX_ERRORTYPE result = omx_free_handle(component_handle_); |
| 569 if (result != OMX_ErrorNone) |
| 570 LOG(ERROR) << "OMX_FreeHandle() error. Error code: " << result; |
| 571 component_handle_ = NULL; |
| 572 client_state_ = OMX_StateMax; |
| 573 // This Release() call must happen *after* any access to |*this| because it |
| 574 // might result in |this| being deleted. |
| 575 Release(); // Since OMX no longer has |this| to call back to. |
| 576 omx_deinit(); |
| 577 } |
| 578 |
541 void OmxVideoDecodeAccelerator::StopOnError( | 579 void OmxVideoDecodeAccelerator::StopOnError( |
542 media::VideoDecodeAccelerator::Error error) { | 580 media::VideoDecodeAccelerator::Error error) { |
543 DCHECK_EQ(message_loop_, MessageLoop::current()); | 581 DCHECK_EQ(message_loop_, MessageLoop::current()); |
544 current_state_change_ = ERRORING; | |
545 | 582 |
546 client_->NotifyError(error); | 583 if (client_) |
| 584 client_->NotifyError(error); |
| 585 client_ = NULL; |
547 | 586 |
548 if (client_state_ == OMX_StateInvalid || client_state_ == OMX_StateMax) | 587 if (client_state_ == OMX_StateInvalid || client_state_ == OMX_StateMax) |
549 return; | 588 return; |
550 | 589 |
551 BeginTransitionToState(OMX_StateInvalid); | 590 BeginTransitionToState(OMX_StateInvalid); |
| 591 current_state_change_ = ERRORING; |
552 } | 592 } |
553 | 593 |
554 bool OmxVideoDecodeAccelerator::AllocateInputBuffers() { | 594 bool OmxVideoDecodeAccelerator::AllocateInputBuffers() { |
555 DCHECK_EQ(message_loop_, MessageLoop::current()); | 595 DCHECK_EQ(message_loop_, MessageLoop::current()); |
556 for (int i = 0; i < input_buffer_count_; ++i) { | 596 for (int i = 0; i < input_buffer_count_; ++i) { |
557 OMX_BUFFERHEADERTYPE* buffer; | 597 OMX_BUFFERHEADERTYPE* buffer; |
558 // While registering the buffer header we use fake buffer information | 598 // While registering the buffer header we use fake buffer information |
559 // (length 0, at memory address 0x1) to fake out the "safety" check in | 599 // (length 0, at memory address 0x1) to fake out the "safety" check in |
560 // OMX_UseBuffer. When it comes time to actually use this header in Decode | 600 // OMX_UseBuffer. When it comes time to actually use this header in Decode |
561 // we set these fields to their real values (for the duration of that | 601 // we set these fields to their real values (for the duration of that |
(...skipping 20 matching lines...) Expand all Loading... |
582 gfx::Size decoded_pixel_size(pictures_.begin()->second.gles_buffer.size()); | 622 gfx::Size decoded_pixel_size(pictures_.begin()->second.gles_buffer.size()); |
583 gfx::Size visible_pixel_size(pictures_.begin()->second.gles_buffer.size()); | 623 gfx::Size visible_pixel_size(pictures_.begin()->second.gles_buffer.size()); |
584 for (OutputPictureById::iterator it = pictures_.begin(); | 624 for (OutputPictureById::iterator it = pictures_.begin(); |
585 it != pictures_.end(); ++it) { | 625 it != pictures_.end(); ++it) { |
586 media::GLESBuffer& gles_buffer = it->second.gles_buffer; | 626 media::GLESBuffer& gles_buffer = it->second.gles_buffer; |
587 OMX_BUFFERHEADERTYPE** omx_buffer = &it->second.omx_buffer_header; | 627 OMX_BUFFERHEADERTYPE** omx_buffer = &it->second.omx_buffer_header; |
588 DCHECK(!*omx_buffer); | 628 DCHECK(!*omx_buffer); |
589 OMX_ERRORTYPE result = OMX_UseEGLImage( | 629 OMX_ERRORTYPE result = OMX_UseEGLImage( |
590 component_handle_, omx_buffer, output_port_, &gles_buffer, | 630 component_handle_, omx_buffer, output_port_, &gles_buffer, |
591 it->second.egl_image); | 631 it->second.egl_image); |
592 RETURN_ON_OMX_FAILURE(result, "OMX_UseEGLImage failed with: " << result, | 632 RETURN_ON_OMX_FAILURE(result, "OMX_UseEGLImage", |
593 VIDEODECODERERROR_MEMFAILURE, false); | 633 VIDEODECODERERROR_MEMFAILURE, false); |
594 // Here we set a garbage bitstream buffer id, and then overwrite it before | 634 // Here we set a garbage bitstream buffer id, and then overwrite it before |
595 // passing to PictureReady. | 635 // passing to PictureReady. |
596 int garbage_bitstream_buffer_id = -1; | 636 int garbage_bitstream_buffer_id = -1; |
597 (*omx_buffer)->pAppPrivate = | 637 (*omx_buffer)->pAppPrivate = |
598 new media::Picture(gles_buffer.id(), garbage_bitstream_buffer_id, | 638 new media::Picture(gles_buffer.id(), garbage_bitstream_buffer_id, |
599 decoded_pixel_size, visible_pixel_size); | 639 decoded_pixel_size, visible_pixel_size); |
600 } | 640 } |
601 return true; | 641 return true; |
602 } | 642 } |
603 | 643 |
604 void OmxVideoDecodeAccelerator::FreeInputBuffers() { | 644 void OmxVideoDecodeAccelerator::FreeInputBuffers() { |
605 DCHECK_EQ(message_loop_, MessageLoop::current()); | 645 DCHECK_EQ(message_loop_, MessageLoop::current()); |
606 // Calls to OMX to free buffers. | 646 // Calls to OMX to free buffers. |
607 OMX_ERRORTYPE result; | 647 OMX_ERRORTYPE result; |
608 OMX_BUFFERHEADERTYPE* omx_buffer; | 648 OMX_BUFFERHEADERTYPE* omx_buffer; |
609 while (!free_input_buffers_.empty()) { | 649 while (!free_input_buffers_.empty()) { |
610 omx_buffer = free_input_buffers_.front(); | 650 omx_buffer = free_input_buffers_.front(); |
611 free_input_buffers_.pop(); | 651 free_input_buffers_.pop(); |
612 result = OMX_FreeBuffer(component_handle_, input_port_, omx_buffer); | 652 result = OMX_FreeBuffer(component_handle_, input_port_, omx_buffer); |
613 RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer failed with: " << result, | 653 RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer", |
614 VIDEODECODERERROR_INVALIDINPUT,); | 654 VIDEODECODERERROR_INVALIDINPUT,); |
615 } | 655 } |
616 VLOG(1) << "Input buffers freed."; | |
617 } | 656 } |
618 | 657 |
619 void OmxVideoDecodeAccelerator::FreeOutputBuffers() { | 658 void OmxVideoDecodeAccelerator::FreeOutputBuffers() { |
620 DCHECK_EQ(message_loop_, MessageLoop::current()); | 659 DCHECK_EQ(message_loop_, MessageLoop::current()); |
621 // Calls to OMX to free buffers. | 660 // Calls to OMX to free buffers. |
622 OMX_ERRORTYPE result; | 661 OMX_ERRORTYPE result; |
623 static Gles2TextureToEglImageTranslator texture2eglImage_translator; | 662 static Gles2TextureToEglImageTranslator texture2eglImage_translator; |
624 for (OutputPictureById::iterator it = pictures_.begin(); | 663 for (OutputPictureById::iterator it = pictures_.begin(); |
625 it != pictures_.end(); ++it) { | 664 it != pictures_.end(); ++it) { |
626 OMX_BUFFERHEADERTYPE* omx_buffer = it->second.omx_buffer_header; | 665 OMX_BUFFERHEADERTYPE* omx_buffer = it->second.omx_buffer_header; |
627 CHECK(omx_buffer); | 666 CHECK(omx_buffer); |
628 delete reinterpret_cast<media::Picture*>(omx_buffer->pAppPrivate); | 667 delete reinterpret_cast<media::Picture*>(omx_buffer->pAppPrivate); |
629 result = OMX_FreeBuffer(component_handle_, output_port_, omx_buffer); | 668 result = OMX_FreeBuffer(component_handle_, output_port_, omx_buffer); |
630 RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer failed with: " << result, | 669 RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer", |
631 VIDEODECODERERROR_INVALIDINPUT,); | 670 VIDEODECODERERROR_INVALIDINPUT,); |
632 texture2eglImage_translator.DestroyEglImage(egl_display_, | 671 texture2eglImage_translator.DestroyEglImage(egl_display_, |
633 it->second.egl_image); | 672 it->second.egl_image); |
634 client_->DismissPictureBuffer(it->first); | 673 if (client_) |
| 674 client_->DismissPictureBuffer(it->first); |
635 } | 675 } |
636 pictures_.clear(); | 676 pictures_.clear(); |
637 } | 677 } |
638 | 678 |
639 void OmxVideoDecodeAccelerator::OnOutputPortDisabled() { | 679 void OmxVideoDecodeAccelerator::OnOutputPortDisabled() { |
640 DCHECK_EQ(message_loop_, MessageLoop::current()); | 680 DCHECK_EQ(message_loop_, MessageLoop::current()); |
641 OMX_PARAM_PORTDEFINITIONTYPE port_format; | 681 OMX_PARAM_PORTDEFINITIONTYPE port_format; |
642 InitParam(*this, &port_format); | 682 InitParam(*this, &port_format); |
643 port_format.nPortIndex = output_port_; | 683 port_format.nPortIndex = output_port_; |
644 OMX_ERRORTYPE result = OMX_GetParameter( | 684 OMX_ERRORTYPE result = OMX_GetParameter( |
645 component_handle_, OMX_IndexParamPortDefinition, &port_format); | 685 component_handle_, OMX_IndexParamPortDefinition, &port_format); |
646 RETURN_ON_OMX_FAILURE(result, "OMX_GetParameter failed with: " << result, | 686 RETURN_ON_OMX_FAILURE(result, "OMX_GetParameter", |
647 VIDEODECODERERROR_UNSUPPORTED,); | 687 VIDEODECODERERROR_UNSUPPORTED,); |
648 DCHECK_EQ(port_format.nBufferCountMin, kNumPictureBuffers); | 688 DCHECK_EQ(port_format.nBufferCountMin, kNumPictureBuffers); |
649 | 689 |
650 // TODO(fischman): to support mid-stream resize, need to free/dismiss any | 690 // TODO(fischman): to support mid-stream resize, need to free/dismiss any |
651 // |pictures_| we already have. Make sure that the shutdown-path agrees with | 691 // |pictures_| we already have. Make sure that the shutdown-path agrees with |
652 // this (there's already freeing logic there, which should not be duplicated). | 692 // this (there's already freeing logic there, which should not be duplicated). |
653 | 693 |
654 // Request picture buffers to be handed to the component. | 694 // Request picture buffers to be handed to the component. |
655 // ProvidePictureBuffers() will trigger AssignGLESBuffers, which ultimately | 695 // ProvidePictureBuffers() will trigger AssignGLESBuffers, which ultimately |
656 // assigns the textures to the component and re-enables the port. | 696 // assigns the textures to the component and re-enables the port. |
657 const OMX_VIDEO_PORTDEFINITIONTYPE& vformat = port_format.format.video; | 697 const OMX_VIDEO_PORTDEFINITIONTYPE& vformat = port_format.format.video; |
658 client_->ProvidePictureBuffers( | 698 if (client_) { |
659 kNumPictureBuffers, | 699 client_->ProvidePictureBuffers( |
660 gfx::Size(vformat.nFrameWidth, vformat.nFrameHeight), | 700 kNumPictureBuffers, |
661 PICTUREBUFFER_MEMORYTYPE_GL_TEXTURE); | 701 gfx::Size(vformat.nFrameWidth, vformat.nFrameHeight), |
| 702 PICTUREBUFFER_MEMORYTYPE_GL_TEXTURE); |
| 703 } |
662 } | 704 } |
663 | 705 |
664 void OmxVideoDecodeAccelerator::OnOutputPortEnabled() { | 706 void OmxVideoDecodeAccelerator::OnOutputPortEnabled() { |
665 DCHECK_EQ(message_loop_, MessageLoop::current()); | 707 DCHECK_EQ(message_loop_, MessageLoop::current()); |
666 | 708 |
667 if (!CanFillBuffer()) { | 709 if (!CanFillBuffer()) { |
668 StopOnError(VIDEODECODERERROR_UNSUPPORTED); // Should be STATE_ERROR. | 710 StopOnError(VIDEODECODERERROR_UNSUPPORTED); // Should be STATE_ERROR. |
669 return; | 711 return; |
670 } | 712 } |
671 | 713 |
672 // Provide output buffers to decoder. | 714 // Provide output buffers to decoder. |
673 for (OutputPictureById::iterator it = pictures_.begin(); | 715 for (OutputPictureById::iterator it = pictures_.begin(); |
674 it != pictures_.end(); ++it) { | 716 it != pictures_.end(); ++it) { |
675 OMX_BUFFERHEADERTYPE* omx_buffer = it->second.omx_buffer_header; | 717 OMX_BUFFERHEADERTYPE* omx_buffer = it->second.omx_buffer_header; |
676 DCHECK(omx_buffer); | 718 DCHECK(omx_buffer); |
677 // Clear EOS flag. | 719 // Clear EOS flag. |
678 omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS; | 720 omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS; |
679 omx_buffer->nOutputPortIndex = output_port_; | 721 omx_buffer->nOutputPortIndex = output_port_; |
680 ++output_buffers_at_component_; | 722 ++output_buffers_at_component_; |
681 OMX_ERRORTYPE result = OMX_FillThisBuffer(component_handle_, omx_buffer); | 723 OMX_ERRORTYPE result = OMX_FillThisBuffer(component_handle_, omx_buffer); |
682 RETURN_ON_OMX_FAILURE(result, | 724 RETURN_ON_OMX_FAILURE(result, "OMX_FillThisBuffer() failed", |
683 "OMX_FillThisBuffer() failed with result " << result, | |
684 VIDEODECODERERROR_INSUFFICIENT_BUFFERS,); | 725 VIDEODECODERERROR_INSUFFICIENT_BUFFERS,); |
685 } | 726 } |
686 } | 727 } |
687 | 728 |
688 void OmxVideoDecodeAccelerator::FillBufferDoneTask( | 729 void OmxVideoDecodeAccelerator::FillBufferDoneTask( |
689 OMX_BUFFERHEADERTYPE* buffer) { | 730 OMX_BUFFERHEADERTYPE* buffer) { |
690 DCHECK_EQ(message_loop_, MessageLoop::current()); | 731 DCHECK_EQ(message_loop_, MessageLoop::current()); |
691 DCHECK_GT(output_buffers_at_component_, 0); | 732 DCHECK_GT(output_buffers_at_component_, 0); |
692 --output_buffers_at_component_; | 733 --output_buffers_at_component_; |
693 | 734 |
694 if (fake_output_buffers_.size() && fake_output_buffers_.count(buffer)) { | 735 if (fake_output_buffers_.size() && fake_output_buffers_.count(buffer)) { |
695 CHECK_EQ(fake_output_buffers_.erase(buffer), 1U); | 736 CHECK_EQ(fake_output_buffers_.erase(buffer), 1U); |
696 OMX_ERRORTYPE result = | 737 OMX_ERRORTYPE result = |
697 OMX_FreeBuffer(component_handle_, output_port_, buffer); | 738 OMX_FreeBuffer(component_handle_, output_port_, buffer); |
698 RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer failed with: " << result, | 739 RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer failed", |
699 VIDEODECODERERROR_INVALIDINPUT,); | 740 VIDEODECODERERROR_INVALIDINPUT,); |
700 return; | 741 return; |
701 } | 742 } |
702 CHECK(!fake_output_buffers_.size()); | 743 CHECK(!fake_output_buffers_.size()); |
703 | 744 |
704 if (current_state_change_ == FLUSHING && | 745 if (current_state_change_ == FLUSHING && |
705 buffer->nFlags & OMX_BUFFERFLAG_EOS) { | 746 buffer->nFlags & OMX_BUFFERFLAG_EOS) { |
706 DCHECK(!saw_eos_during_flush_); | 747 DCHECK(!saw_eos_during_flush_); |
707 saw_eos_during_flush_ = true; | 748 saw_eos_during_flush_ = true; |
708 } | 749 } |
709 | 750 |
710 // During the transition from Executing to Idle, and during port-flushing, all | 751 // During the transition from Executing to Idle, and during port-flushing, all |
711 // pictures are sent back through here. Avoid giving them to the client. | 752 // pictures are sent back through here. Avoid giving them to the client. |
712 // Also avoid sending the (fake) EOS buffer to the client. | 753 // Also avoid sending the (fake) EOS buffer to the client. |
713 if ((current_state_change_ != NO_TRANSITION && | 754 if ((current_state_change_ != NO_TRANSITION && |
714 current_state_change_ != FLUSHING) || | 755 current_state_change_ != FLUSHING) || |
715 saw_eos_during_flush_) { | 756 saw_eos_during_flush_) { |
716 return; | 757 return; |
717 } | 758 } |
718 | 759 |
719 CHECK(buffer->pAppPrivate); | 760 CHECK(buffer->pAppPrivate); |
720 media::Picture* picture = | 761 media::Picture* picture = |
721 reinterpret_cast<media::Picture*>(buffer->pAppPrivate); | 762 reinterpret_cast<media::Picture*>(buffer->pAppPrivate); |
722 // See Decode() for an explanation of this abuse of nTimeStamp. | 763 // See Decode() for an explanation of this abuse of nTimeStamp. |
723 picture->set_bitstream_buffer_id(buffer->nTimeStamp); | 764 picture->set_bitstream_buffer_id(buffer->nTimeStamp); |
724 client_->PictureReady(*picture); | 765 if (client_) |
| 766 client_->PictureReady(*picture); |
725 } | 767 } |
726 | 768 |
727 void OmxVideoDecodeAccelerator::EmptyBufferDoneTask( | 769 void OmxVideoDecodeAccelerator::EmptyBufferDoneTask( |
728 OMX_BUFFERHEADERTYPE* buffer) { | 770 OMX_BUFFERHEADERTYPE* buffer) { |
729 DCHECK_EQ(message_loop_, MessageLoop::current()); | 771 DCHECK_EQ(message_loop_, MessageLoop::current()); |
730 DCHECK_GT(input_buffers_at_component_, 0); | 772 DCHECK_GT(input_buffers_at_component_, 0); |
731 free_input_buffers_.push(buffer); | 773 free_input_buffers_.push(buffer); |
732 input_buffers_at_component_--; | 774 input_buffers_at_component_--; |
733 if (buffer->nFlags & OMX_BUFFERFLAG_EOS) | 775 if (buffer->nFlags & OMX_BUFFERFLAG_EOS) |
734 return; | 776 return; |
735 | 777 |
736 // Retrieve the corresponding BitstreamBuffer's id and notify the client of | 778 // Retrieve the corresponding BitstreamBuffer's id and notify the client of |
737 // its completion. | 779 // its completion. |
738 SharedMemoryAndId* input_buffer_details = | 780 SharedMemoryAndId* input_buffer_details = |
739 reinterpret_cast<SharedMemoryAndId*>(buffer->pAppPrivate); | 781 reinterpret_cast<SharedMemoryAndId*>(buffer->pAppPrivate); |
740 DCHECK(input_buffer_details); | 782 DCHECK(input_buffer_details); |
741 buffer->pAppPrivate = NULL; | 783 buffer->pAppPrivate = NULL; |
742 client_->NotifyEndOfBitstreamBuffer(input_buffer_details->second); | 784 if (client_) |
| 785 client_->NotifyEndOfBitstreamBuffer(input_buffer_details->second); |
743 delete input_buffer_details; | 786 delete input_buffer_details; |
744 } | 787 } |
745 | 788 |
746 void OmxVideoDecodeAccelerator::DispatchStateReached(OMX_STATETYPE reached) { | 789 void OmxVideoDecodeAccelerator::DispatchStateReached(OMX_STATETYPE reached) { |
747 DCHECK_EQ(message_loop_, MessageLoop::current()); | 790 DCHECK_EQ(message_loop_, MessageLoop::current()); |
748 switch (current_state_change_) { | 791 switch (current_state_change_) { |
749 case INITIALIZING: | 792 case INITIALIZING: |
750 switch (reached) { | 793 switch (reached) { |
751 case OMX_StateIdle: | 794 case OMX_StateIdle: |
752 OnReachedIdleInInitializing(); | 795 OnReachedIdleInInitializing(); |
(...skipping 30 matching lines...) Expand all Loading... |
783 switch (reached) { | 826 switch (reached) { |
784 case OMX_StateIdle: | 827 case OMX_StateIdle: |
785 OnReachedIdleInDestroying(); | 828 OnReachedIdleInDestroying(); |
786 return; | 829 return; |
787 case OMX_StateLoaded: | 830 case OMX_StateLoaded: |
788 OnReachedLoadedInDestroying(); | 831 OnReachedLoadedInDestroying(); |
789 return; | 832 return; |
790 default: | 833 default: |
791 NOTREACHED() << "Unexpected state in DESTROYING: " << reached; | 834 NOTREACHED() << "Unexpected state in DESTROYING: " << reached; |
792 } | 835 } |
| 836 case ERRORING: |
| 837 switch (reached) { |
| 838 case OMX_StateInvalid: |
| 839 OnReachedInvalidInErroring(); |
| 840 return; |
| 841 default: |
| 842 NOTREACHED() << "Unexpected state in ERRORING: " << reached; |
| 843 } |
793 default: | 844 default: |
794 NOTREACHED() << "Unexpected state in " << current_state_change_ | 845 NOTREACHED() << "Unexpected state in " << current_state_change_ |
795 << ": " << reached; | 846 << ": " << reached; |
796 } | 847 } |
797 } | 848 } |
798 | 849 |
799 void OmxVideoDecodeAccelerator::EventHandlerCompleteTask(OMX_EVENTTYPE event, | 850 void OmxVideoDecodeAccelerator::EventHandlerCompleteTask(OMX_EVENTTYPE event, |
800 OMX_U32 data1, | 851 OMX_U32 data1, |
801 OMX_U32 data2) { | 852 OMX_U32 data2) { |
802 DCHECK_EQ(message_loop_, MessageLoop::current()); | 853 DCHECK_EQ(message_loop_, MessageLoop::current()); |
803 switch (event) { | 854 switch (event) { |
804 case OMX_EventCmdComplete: { | 855 case OMX_EventCmdComplete: |
805 // If the last command was successful, we have completed | 856 switch (data1) { |
806 // a state transition. So notify that we have done it | |
807 // accordingly. | |
808 OMX_COMMANDTYPE cmd = static_cast<OMX_COMMANDTYPE>(data1); | |
809 switch (cmd) { | |
810 case OMX_CommandPortDisable: | 857 case OMX_CommandPortDisable: |
811 DCHECK_EQ(data2, output_port_); | 858 DCHECK_EQ(data2, output_port_); |
812 OnOutputPortDisabled(); | 859 OnOutputPortDisabled(); |
813 break; | 860 return; |
814 case OMX_CommandPortEnable: | 861 case OMX_CommandPortEnable: |
815 DCHECK_EQ(data2, output_port_); | 862 DCHECK_EQ(data2, output_port_); |
816 OnOutputPortEnabled(); | 863 OnOutputPortEnabled(); |
817 break; | 864 return; |
818 case OMX_CommandStateSet: | 865 case OMX_CommandStateSet: |
819 DispatchStateReached(static_cast<OMX_STATETYPE>(data2)); | 866 DispatchStateReached(static_cast<OMX_STATETYPE>(data2)); |
820 break; | 867 return; |
821 case OMX_CommandFlush: | 868 case OMX_CommandFlush: |
822 DCHECK(current_state_change_ == FLUSHING || | 869 DCHECK(current_state_change_ == FLUSHING || |
823 current_state_change_ == RESETTING || | 870 current_state_change_ == RESETTING || |
824 current_state_change_ == DESTROYING); | 871 current_state_change_ == DESTROYING); |
825 if (data2 == input_port_) | 872 if (data2 == input_port_) |
826 InputPortFlushDone(); | 873 InputPortFlushDone(); |
827 else if (data2 == output_port_) | 874 else if (data2 == output_port_) |
828 OutputPortFlushDone(); | 875 OutputPortFlushDone(); |
829 else | 876 else |
830 NOTREACHED() << "Unexpected port flushed: " << data2; | 877 NOTREACHED() << "Unexpected port flushed: " << data2; |
831 break; | 878 return; |
832 default: | 879 default: |
833 RETURN_ON_FAILURE(false, "Unknown command completed: " << data1, | 880 RETURN_ON_FAILURE(false, "Unknown command completed: " << data1, |
834 VIDEODECODERERROR_HARDWARE,); | 881 VIDEODECODERERROR_HARDWARE,); |
835 } | 882 } |
836 break; | 883 return; |
837 } | |
838 case OMX_EventError: | 884 case OMX_EventError: |
839 RETURN_ON_FAILURE(false, "EventError: " << data1, | 885 if (current_state_change_ != DESTROYING && |
840 VIDEODECODERERROR_HARDWARE,); | 886 current_state_change_ != ERRORING) { |
| 887 RETURN_ON_FAILURE(false, "EventError: 0x" << std::hex << data1, |
| 888 VIDEODECODERERROR_HARDWARE,); |
| 889 } |
| 890 return; |
841 case OMX_EventPortSettingsChanged: | 891 case OMX_EventPortSettingsChanged: |
842 if (data2 == OMX_IndexParamPortDefinition) { | 892 if (data2 == OMX_IndexParamPortDefinition) { |
843 DCHECK_EQ(data1, output_port_); | 893 DCHECK_EQ(data1, output_port_); |
844 // This event is only used for output resize; kick off handling that by | 894 // This event is only used for output resize; kick off handling that by |
845 // pausing the output port. | 895 // pausing the output port. |
846 SendCommandToPort(OMX_CommandPortDisable, output_port_); | 896 SendCommandToPort(OMX_CommandPortDisable, output_port_); |
847 } else if (data1 == output_port_ && | 897 } else if (data1 == output_port_ && |
848 data2 == OMX_IndexConfigCommonOutputCrop) { | 898 data2 == OMX_IndexConfigCommonOutputCrop) { |
849 // TODO(vjain): Handle video crop rect. | 899 // TODO(vjain): Handle video crop rect. |
850 } else { | 900 } else { |
851 RETURN_ON_FAILURE(false, | 901 RETURN_ON_FAILURE(false, |
852 "Unexpected EventPortSettingsChanged: " | 902 "Unexpected EventPortSettingsChanged: " |
853 << data1 << ", " << data2, | 903 << data1 << ", " << data2, |
854 VIDEODECODERERROR_HARDWARE,); | 904 VIDEODECODERERROR_HARDWARE,); |
855 } | 905 } |
856 break; | 906 return; |
857 case OMX_EventBufferFlag: | 907 case OMX_EventBufferFlag: |
858 if (data1 == output_port_) { | 908 if (data1 == output_port_) { |
859 DCHECK_EQ(current_state_change_, FLUSHING); | 909 DCHECK_EQ(current_state_change_, FLUSHING); |
860 OnReachedEOSInFlushing(); | 910 OnReachedEOSInFlushing(); |
861 } else { | 911 } else { |
862 RETURN_ON_FAILURE(false, | 912 RETURN_ON_FAILURE(false, |
863 "Unexpected OMX_EventBufferFlag: " | 913 "Unexpected OMX_EventBufferFlag: " |
864 << data1 << ", " << data2, | 914 << data1 << ", " << data2, |
865 VIDEODECODERERROR_HARDWARE,); | 915 VIDEODECODERERROR_HARDWARE,); |
866 } | 916 } |
867 break; | 917 return; |
868 default: | 918 default: |
869 RETURN_ON_FAILURE(false, "Unexpected unhandled event: " << event, | 919 RETURN_ON_FAILURE(false, "Unexpected unhandled event: " << event, |
870 VIDEODECODERERROR_HARDWARE,); | 920 VIDEODECODERERROR_HARDWARE,); |
871 } | 921 } |
872 } | 922 } |
873 | 923 |
874 // static | 924 // static |
875 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EventHandler(OMX_HANDLETYPE component, | 925 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EventHandler(OMX_HANDLETYPE component, |
876 OMX_PTR priv_data, | 926 OMX_PTR priv_data, |
877 OMX_EVENTTYPE event, | 927 OMX_EVENTTYPE event, |
878 OMX_U32 data1, | 928 OMX_U32 data1, |
879 OMX_U32 data2, | 929 OMX_U32 data2, |
880 OMX_PTR event_data) { | 930 OMX_PTR event_data) { |
881 // Called on the OMX thread. | 931 // Called on the OMX thread. |
882 OmxVideoDecodeAccelerator* decoder = | 932 OmxVideoDecodeAccelerator* decoder = |
883 static_cast<OmxVideoDecodeAccelerator*>(priv_data); | 933 static_cast<OmxVideoDecodeAccelerator*>(priv_data); |
884 DCHECK_EQ(component, decoder->component_handle_); | 934 DCHECK_EQ(component, decoder->component_handle_); |
885 decoder->message_loop_->PostTask( | 935 decoder->message_loop_->PostTask( |
886 FROM_HERE, | 936 FROM_HERE, NewRunnableMethod( |
887 NewRunnableMethod(decoder, | 937 decoder, &OmxVideoDecodeAccelerator::EventHandlerCompleteTask, |
888 &OmxVideoDecodeAccelerator::EventHandlerCompleteTask, | 938 event, data1, data2)); |
889 event, data1, data2)); | |
890 return OMX_ErrorNone; | 939 return OMX_ErrorNone; |
891 } | 940 } |
892 | 941 |
893 // static | 942 // static |
894 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EmptyBufferCallback( | 943 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EmptyBufferCallback( |
895 OMX_HANDLETYPE component, | 944 OMX_HANDLETYPE component, |
896 OMX_PTR priv_data, | 945 OMX_PTR priv_data, |
897 OMX_BUFFERHEADERTYPE* buffer) { | 946 OMX_BUFFERHEADERTYPE* buffer) { |
898 // Called on the OMX thread. | 947 // Called on the OMX thread. |
899 OmxVideoDecodeAccelerator* decoder = | 948 OmxVideoDecodeAccelerator* decoder = |
(...skipping 19 matching lines...) Expand all Loading... |
919 decoder->message_loop_->PostTask( | 968 decoder->message_loop_->PostTask( |
920 FROM_HERE, | 969 FROM_HERE, |
921 NewRunnableMethod(decoder, | 970 NewRunnableMethod(decoder, |
922 &OmxVideoDecodeAccelerator::FillBufferDoneTask, | 971 &OmxVideoDecodeAccelerator::FillBufferDoneTask, |
923 buffer)); | 972 buffer)); |
924 return OMX_ErrorNone; | 973 return OMX_ErrorNone; |
925 } | 974 } |
926 | 975 |
927 bool OmxVideoDecodeAccelerator::CanFillBuffer() { | 976 bool OmxVideoDecodeAccelerator::CanFillBuffer() { |
928 DCHECK_EQ(message_loop_, MessageLoop::current()); | 977 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 978 if (current_state_change_ == DESTROYING || |
| 979 current_state_change_ == ERRORING) { |
| 980 return false; |
| 981 } |
929 return client_state_ == OMX_StateIdle || | 982 return client_state_ == OMX_StateIdle || |
930 client_state_ == OMX_StateExecuting || | 983 client_state_ == OMX_StateExecuting || |
931 client_state_ == OMX_StatePause; | 984 client_state_ == OMX_StatePause; |
932 } | 985 } |
933 | 986 |
934 bool OmxVideoDecodeAccelerator::SendCommandToPort( | 987 bool OmxVideoDecodeAccelerator::SendCommandToPort( |
935 OMX_COMMANDTYPE cmd, int port_index) { | 988 OMX_COMMANDTYPE cmd, int port_index) { |
936 DCHECK_EQ(message_loop_, MessageLoop::current()); | 989 DCHECK_EQ(message_loop_, MessageLoop::current()); |
937 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, | 990 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, |
938 cmd, port_index, 0); | 991 cmd, port_index, 0); |
939 RETURN_ON_OMX_FAILURE(result, "SendCommand() failed" << cmd << ":" << result, | 992 RETURN_ON_OMX_FAILURE(result, "SendCommand() failed" << cmd, |
940 VIDEODECODERERROR_INVALIDINPUT, false); | 993 VIDEODECODERERROR_INVALIDINPUT, false); |
941 return true; | 994 return true; |
942 } | 995 } |
943 | |
944 DISABLE_RUNNABLE_METHOD_REFCOUNT(OmxVideoDecodeAccelerator); | |
OLD | NEW |