| 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 |