Chromium Code Reviews| 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 21 matching lines...) Expand all Loading... | |
| 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()); |
| 429 DCHECK_EQ(current_state_change_, NO_TRANSITION); | 427 DCHECK_EQ(current_state_change_, NO_TRANSITION); |
| 428 // If we were never initializeed there's no teardown to do. | |
| 429 if (client_state_ == OMX_StateMax) | |
| 430 return; | |
| 431 // If we can already call OMX_FreeHandle, simply do so. | |
| 432 if (client_state_ == OMX_StateInvalid || client_state_ == OMX_StateLoaded) { | |
| 433 ShutdownComponent(); | |
| 434 return; | |
| 435 } | |
| 430 DCHECK_EQ(client_state_, OMX_StateExecuting); | 436 DCHECK_EQ(client_state_, OMX_StateExecuting); |
| 431 current_state_change_ = DESTROYING; | 437 current_state_change_ = DESTROYING; |
| 438 client_ = NULL; | |
|
vhiremath
2011/07/14 14:29:15
Do we really want to do it here ?
What if OVDA has
Ami GONE FROM CHROMIUM
2011/07/14 16:23:03
It is incorrect to call Destroy() while a Reset()
| |
| 432 BeginTransitionToState(OMX_StateIdle); | 439 BeginTransitionToState(OMX_StateIdle); |
| 440 BusyLoopInDestroying(); | |
| 433 } | 441 } |
| 434 | 442 |
| 435 void OmxVideoDecodeAccelerator::BeginTransitionToState( | 443 void OmxVideoDecodeAccelerator::BeginTransitionToState( |
| 436 OMX_STATETYPE new_state) { | 444 OMX_STATETYPE new_state) { |
| 437 DCHECK_EQ(message_loop_, MessageLoop::current()); | 445 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 438 DCHECK_NE(current_state_change_, NO_TRANSITION); | 446 DCHECK_NE(current_state_change_, NO_TRANSITION); |
| 447 DCHECK_NE(current_state_change_, ERRORING); | |
| 448 if (current_state_change_ == NO_TRANSITION || | |
| 449 current_state_change_ == ERRORING) { | |
| 450 return; | |
| 451 } | |
| 439 OMX_ERRORTYPE result = OMX_SendCommand( | 452 OMX_ERRORTYPE result = OMX_SendCommand( |
| 440 component_handle_, OMX_CommandStateSet, new_state, 0); | 453 component_handle_, OMX_CommandStateSet, new_state, 0); |
| 441 RETURN_ON_OMX_FAILURE(result, "SendCommand(OMX_CommandStateSet) failed", | 454 RETURN_ON_OMX_FAILURE(result, "SendCommand(OMX_CommandStateSet) failed", |
| 442 VIDEODECODERERROR_INVALIDINPUT,); | 455 VIDEODECODERERROR_INVALIDINPUT,); |
| 443 } | 456 } |
| 444 | 457 |
| 445 void OmxVideoDecodeAccelerator::OnReachedIdleInInitializing() { | 458 void OmxVideoDecodeAccelerator::OnReachedIdleInInitializing() { |
| 446 DCHECK_EQ(client_state_, OMX_StateLoaded); | 459 DCHECK_EQ(client_state_, OMX_StateLoaded); |
| 447 client_state_ = OMX_StateIdle; | 460 client_state_ = OMX_StateIdle; |
| 448 BeginTransitionToState(OMX_StateExecuting); | 461 BeginTransitionToState(OMX_StateExecuting); |
| 449 } | 462 } |
| 450 | 463 |
| 451 void OmxVideoDecodeAccelerator::OnReachedExecutingInInitializing() { | 464 void OmxVideoDecodeAccelerator::OnReachedExecutingInInitializing() { |
| 452 DCHECK_EQ(client_state_, OMX_StateIdle); | 465 DCHECK_EQ(client_state_, OMX_StateIdle); |
| 453 client_state_ = OMX_StateExecuting; | 466 client_state_ = OMX_StateExecuting; |
| 454 current_state_change_ = NO_TRANSITION; | 467 current_state_change_ = NO_TRANSITION; |
| 455 | 468 |
| 456 // Request filling of our fake buffers to trigger decode processing. In | 469 // 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 | 470 // reality as soon as any data is decoded these will get dismissed due to |
| 458 // dimension mismatch. | 471 // dimension mismatch. |
| 459 for (std::set<OMX_BUFFERHEADERTYPE*>::iterator it = | 472 for (std::set<OMX_BUFFERHEADERTYPE*>::iterator it = |
| 460 fake_output_buffers_.begin(); | 473 fake_output_buffers_.begin(); |
| 461 it != fake_output_buffers_.end(); ++it) { | 474 it != fake_output_buffers_.end(); ++it) { |
| 462 OMX_BUFFERHEADERTYPE* buffer = *it; | 475 OMX_BUFFERHEADERTYPE* buffer = *it; |
| 463 OMX_ERRORTYPE result = OMX_FillThisBuffer(component_handle_, buffer); | 476 OMX_ERRORTYPE result = OMX_FillThisBuffer(component_handle_, buffer); |
| 464 RETURN_ON_OMX_FAILURE(result, | 477 RETURN_ON_OMX_FAILURE(result, "OMX_FillThisBuffer()", |
| 465 "OMX_FillThisBuffer() failed with: " << result, | |
| 466 VIDEODECODERERROR_INVALIDINPUT,); | 478 VIDEODECODERERROR_INVALIDINPUT,); |
| 467 ++output_buffers_at_component_; | 479 ++output_buffers_at_component_; |
| 468 } | 480 } |
| 469 | 481 |
| 470 client_->NotifyInitializeDone(); | 482 if (client_) |
| 483 client_->NotifyInitializeDone(); | |
| 471 } | 484 } |
| 472 | 485 |
| 473 void OmxVideoDecodeAccelerator::OnReachedPauseInFlushing() { | 486 void OmxVideoDecodeAccelerator::OnReachedPauseInFlushing() { |
| 474 DCHECK_EQ(client_state_, OMX_StateExecuting); | 487 DCHECK_EQ(client_state_, OMX_StateExecuting); |
| 475 client_state_ = OMX_StatePause; | 488 client_state_ = OMX_StatePause; |
| 476 FlushIOPorts(); | 489 FlushIOPorts(); |
| 477 } | 490 } |
| 478 | 491 |
| 479 void OmxVideoDecodeAccelerator::OnReachedExecutingInFlushing() { | 492 void OmxVideoDecodeAccelerator::OnReachedExecutingInFlushing() { |
| 480 DCHECK_EQ(client_state_, OMX_StatePause); | 493 DCHECK_EQ(client_state_, OMX_StatePause); |
| 481 client_state_ = OMX_StateExecuting; | 494 client_state_ = OMX_StateExecuting; |
| 482 DCHECK(saw_eos_during_flush_); | 495 DCHECK(saw_eos_during_flush_); |
| 483 saw_eos_during_flush_ = false; | 496 saw_eos_during_flush_ = false; |
| 484 current_state_change_ = NO_TRANSITION; | 497 current_state_change_ = NO_TRANSITION; |
| 485 client_->NotifyFlushDone(); | 498 if (client_) |
| 499 client_->NotifyFlushDone(); | |
| 486 } | 500 } |
| 487 | 501 |
| 488 void OmxVideoDecodeAccelerator::OnReachedPauseInResetting() { | 502 void OmxVideoDecodeAccelerator::OnReachedPauseInResetting() { |
| 489 DCHECK_EQ(client_state_, OMX_StateExecuting); | 503 DCHECK_EQ(client_state_, OMX_StateExecuting); |
| 490 client_state_ = OMX_StatePause; | 504 client_state_ = OMX_StatePause; |
| 491 FlushIOPorts(); | 505 FlushIOPorts(); |
| 492 } | 506 } |
| 493 | 507 |
| 494 void OmxVideoDecodeAccelerator::OnReachedExecutingInResetting() { | 508 void OmxVideoDecodeAccelerator::OnReachedExecutingInResetting() { |
| 495 DCHECK_EQ(client_state_, OMX_StatePause); | 509 DCHECK_EQ(client_state_, OMX_StatePause); |
| 496 client_state_ = OMX_StateExecuting; | 510 client_state_ = OMX_StateExecuting; |
| 497 current_state_change_ = NO_TRANSITION; | 511 current_state_change_ = NO_TRANSITION; |
| 498 client_->NotifyResetDone(); | 512 if (client_) |
| 513 client_->NotifyResetDone(); | |
| 514 } | |
| 515 | |
| 516 // Alert: HORROR ahead! OMX shutdown is an asynchronous dance but our clients | |
| 517 // enjoy the fire-and-forget nature of a synchronous Destroy() call that | |
| 518 // ensures no further callbacks are made. Since the interface between OMX | |
| 519 // callbacks and this class is a MessageLoop, we need to ensure the loop | |
| 520 // outlives the shutdown dance, even during process shutdown. We do this by | |
| 521 // repeatedly enqueuing a no-op task until shutdown is complete, since | |
| 522 // MessageLoop's shutdown drains pending tasks. | |
| 523 void OmxVideoDecodeAccelerator::BusyLoopInDestroying() { | |
| 524 if (!component_handle_) return; | |
| 525 // Can't use PostDelayedTask here because MessageLoop doesn't drain delayed | |
| 526 // tasks. Instead we sleep for 5ms. Really. | |
| 527 base::PlatformThread::Sleep(5); | |
|
vhiremath
2011/07/14 14:29:15
Why do we want to delay PostTask here ?
May cause
Ami GONE FROM CHROMIUM
2011/07/14 16:23:03
To reduce the CPU load of what otherwise would be
| |
| 528 message_loop_->PostTask( | |
| 529 FROM_HERE, NewRunnableMethod( | |
| 530 this, &OmxVideoDecodeAccelerator::BusyLoopInDestroying)); | |
| 499 } | 531 } |
|
vhiremath
2011/07/14 14:29:15
Please explain how this logic works.
Note: We have
Ami GONE FROM CHROMIUM
2011/07/14 16:23:03
I think so.
The purpose of this method is simple:
| |
| 500 | 532 |
| 501 void OmxVideoDecodeAccelerator::OnReachedIdleInDestroying() { | 533 void OmxVideoDecodeAccelerator::OnReachedIdleInDestroying() { |
| 502 DCHECK_EQ(client_state_, OMX_StateExecuting); | 534 DCHECK_EQ(client_state_, OMX_StateExecuting); |
| 503 client_state_ = OMX_StateIdle; | 535 client_state_ = OMX_StateIdle; |
| 504 | 536 |
| 505 // Note that during the Executing -> Idle transition, the OMX spec guarantees | 537 // 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 | 538 // buffers have been returned to the client, so we don't need to do an |
| 507 // explicit FlushIOPorts(). | 539 // explicit FlushIOPorts(). |
| 508 | 540 |
| 509 BeginTransitionToState(OMX_StateLoaded); | 541 BeginTransitionToState(OMX_StateLoaded); |
| 510 | 542 |
| 511 // TODO(fischman): evaluate what these conditionals are doing. What happens | 543 // TODO(fischman): evaluate what these conditionals are doing. What happens |
| 512 // if they're false?? | 544 // if they're false?? |
| 513 if (!input_buffers_at_component_) | 545 if (!input_buffers_at_component_) |
| 514 FreeInputBuffers(); | 546 FreeInputBuffers(); |
| 515 if (!output_buffers_at_component_) | 547 if (!output_buffers_at_component_) |
| 516 FreeOutputBuffers(); | 548 FreeOutputBuffers(); |
| 517 } | |
| 518 | 549 |
| 519 void OmxVideoDecodeAccelerator::ShutdownComponent() { | 550 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 } | 551 } |
| 527 | 552 |
| 528 void OmxVideoDecodeAccelerator::OnReachedLoadedInDestroying() { | 553 void OmxVideoDecodeAccelerator::OnReachedLoadedInDestroying() { |
| 529 DCHECK_EQ(client_state_, OMX_StateIdle); | 554 DCHECK_EQ(client_state_, OMX_StateIdle); |
| 530 client_state_ = OMX_StateLoaded; | 555 client_state_ = OMX_StateLoaded; |
| 531 current_state_change_ = NO_TRANSITION; | 556 current_state_change_ = NO_TRANSITION; |
| 532 ShutdownComponent(); | 557 ShutdownComponent(); |
| 533 client_->NotifyDestroyDone(); | |
| 534 } | 558 } |
| 535 | 559 |
| 536 void OmxVideoDecodeAccelerator::OnReachedInvalidInErroring() { | 560 void OmxVideoDecodeAccelerator::OnReachedInvalidInErroring() { |
| 537 client_state_ = OMX_StateInvalid; | 561 client_state_ = OMX_StateInvalid; |
| 538 ShutdownComponent(); | 562 ShutdownComponent(); |
| 539 } | 563 } |
| 540 | 564 |
| 565 void OmxVideoDecodeAccelerator::ShutdownComponent() { | |
| 566 OMX_ERRORTYPE result = omx_free_handle(component_handle_); | |
| 567 if (result != OMX_ErrorNone) | |
| 568 LOG(ERROR) << "OMX_FreeHandle() error. Error code: " << result; | |
| 569 component_handle_ = NULL; | |
| 570 client_state_ = OMX_StateMax; | |
| 571 // This Release() call must happen *after* any access to |*this| because it | |
| 572 // might result in |this| being deleted. | |
| 573 Release(); // Since OMX no longer has |this| to call back to. | |
| 574 omx_deinit(); | |
| 575 } | |
| 576 | |
| 541 void OmxVideoDecodeAccelerator::StopOnError( | 577 void OmxVideoDecodeAccelerator::StopOnError( |
| 542 media::VideoDecodeAccelerator::Error error) { | 578 media::VideoDecodeAccelerator::Error error) { |
| 543 DCHECK_EQ(message_loop_, MessageLoop::current()); | 579 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 544 current_state_change_ = ERRORING; | |
| 545 | 580 |
| 546 client_->NotifyError(error); | 581 if (client_) |
| 582 client_->NotifyError(error); | |
| 547 | 583 |
| 548 if (client_state_ == OMX_StateInvalid || client_state_ == OMX_StateMax) | 584 if (client_state_ == OMX_StateInvalid || client_state_ == OMX_StateMax) |
| 549 return; | 585 return; |
| 550 | 586 |
| 551 BeginTransitionToState(OMX_StateInvalid); | 587 BeginTransitionToState(OMX_StateInvalid); |
| 588 current_state_change_ = ERRORING; | |
| 552 } | 589 } |
| 553 | 590 |
| 554 bool OmxVideoDecodeAccelerator::AllocateInputBuffers() { | 591 bool OmxVideoDecodeAccelerator::AllocateInputBuffers() { |
| 555 DCHECK_EQ(message_loop_, MessageLoop::current()); | 592 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 556 for (int i = 0; i < input_buffer_count_; ++i) { | 593 for (int i = 0; i < input_buffer_count_; ++i) { |
| 557 OMX_BUFFERHEADERTYPE* buffer; | 594 OMX_BUFFERHEADERTYPE* buffer; |
| 558 // While registering the buffer header we use fake buffer information | 595 // While registering the buffer header we use fake buffer information |
| 559 // (length 0, at memory address 0x1) to fake out the "safety" check in | 596 // (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 | 597 // 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 | 598 // 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()); | 619 gfx::Size decoded_pixel_size(pictures_.begin()->second.gles_buffer.size()); |
| 583 gfx::Size visible_pixel_size(pictures_.begin()->second.gles_buffer.size()); | 620 gfx::Size visible_pixel_size(pictures_.begin()->second.gles_buffer.size()); |
| 584 for (OutputPictureById::iterator it = pictures_.begin(); | 621 for (OutputPictureById::iterator it = pictures_.begin(); |
| 585 it != pictures_.end(); ++it) { | 622 it != pictures_.end(); ++it) { |
| 586 media::GLESBuffer& gles_buffer = it->second.gles_buffer; | 623 media::GLESBuffer& gles_buffer = it->second.gles_buffer; |
| 587 OMX_BUFFERHEADERTYPE** omx_buffer = &it->second.omx_buffer_header; | 624 OMX_BUFFERHEADERTYPE** omx_buffer = &it->second.omx_buffer_header; |
| 588 DCHECK(!*omx_buffer); | 625 DCHECK(!*omx_buffer); |
| 589 OMX_ERRORTYPE result = OMX_UseEGLImage( | 626 OMX_ERRORTYPE result = OMX_UseEGLImage( |
| 590 component_handle_, omx_buffer, output_port_, &gles_buffer, | 627 component_handle_, omx_buffer, output_port_, &gles_buffer, |
| 591 it->second.egl_image); | 628 it->second.egl_image); |
| 592 RETURN_ON_OMX_FAILURE(result, "OMX_UseEGLImage failed with: " << result, | 629 RETURN_ON_OMX_FAILURE(result, "OMX_UseEGLImage", |
| 593 VIDEODECODERERROR_MEMFAILURE, false); | 630 VIDEODECODERERROR_MEMFAILURE, false); |
| 594 // Here we set a garbage bitstream buffer id, and then overwrite it before | 631 // Here we set a garbage bitstream buffer id, and then overwrite it before |
| 595 // passing to PictureReady. | 632 // passing to PictureReady. |
| 596 int garbage_bitstream_buffer_id = -1; | 633 int garbage_bitstream_buffer_id = -1; |
| 597 (*omx_buffer)->pAppPrivate = | 634 (*omx_buffer)->pAppPrivate = |
| 598 new media::Picture(gles_buffer.id(), garbage_bitstream_buffer_id, | 635 new media::Picture(gles_buffer.id(), garbage_bitstream_buffer_id, |
| 599 decoded_pixel_size, visible_pixel_size); | 636 decoded_pixel_size, visible_pixel_size); |
| 600 } | 637 } |
| 601 return true; | 638 return true; |
| 602 } | 639 } |
| 603 | 640 |
| 604 void OmxVideoDecodeAccelerator::FreeInputBuffers() { | 641 void OmxVideoDecodeAccelerator::FreeInputBuffers() { |
| 605 DCHECK_EQ(message_loop_, MessageLoop::current()); | 642 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 606 // Calls to OMX to free buffers. | 643 // Calls to OMX to free buffers. |
| 607 OMX_ERRORTYPE result; | 644 OMX_ERRORTYPE result; |
| 608 OMX_BUFFERHEADERTYPE* omx_buffer; | 645 OMX_BUFFERHEADERTYPE* omx_buffer; |
| 609 while (!free_input_buffers_.empty()) { | 646 while (!free_input_buffers_.empty()) { |
| 610 omx_buffer = free_input_buffers_.front(); | 647 omx_buffer = free_input_buffers_.front(); |
| 611 free_input_buffers_.pop(); | 648 free_input_buffers_.pop(); |
| 612 result = OMX_FreeBuffer(component_handle_, input_port_, omx_buffer); | 649 result = OMX_FreeBuffer(component_handle_, input_port_, omx_buffer); |
| 613 RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer failed with: " << result, | 650 RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer", |
| 614 VIDEODECODERERROR_INVALIDINPUT,); | 651 VIDEODECODERERROR_INVALIDINPUT,); |
| 615 } | 652 } |
| 616 VLOG(1) << "Input buffers freed."; | |
| 617 } | 653 } |
| 618 | 654 |
| 619 void OmxVideoDecodeAccelerator::FreeOutputBuffers() { | 655 void OmxVideoDecodeAccelerator::FreeOutputBuffers() { |
| 620 DCHECK_EQ(message_loop_, MessageLoop::current()); | 656 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 621 // Calls to OMX to free buffers. | 657 // Calls to OMX to free buffers. |
| 622 OMX_ERRORTYPE result; | 658 OMX_ERRORTYPE result; |
| 623 static Gles2TextureToEglImageTranslator texture2eglImage_translator; | 659 static Gles2TextureToEglImageTranslator texture2eglImage_translator; |
| 624 for (OutputPictureById::iterator it = pictures_.begin(); | 660 for (OutputPictureById::iterator it = pictures_.begin(); |
| 625 it != pictures_.end(); ++it) { | 661 it != pictures_.end(); ++it) { |
| 626 OMX_BUFFERHEADERTYPE* omx_buffer = it->second.omx_buffer_header; | 662 OMX_BUFFERHEADERTYPE* omx_buffer = it->second.omx_buffer_header; |
| 627 CHECK(omx_buffer); | 663 CHECK(omx_buffer); |
| 628 delete reinterpret_cast<media::Picture*>(omx_buffer->pAppPrivate); | 664 delete reinterpret_cast<media::Picture*>(omx_buffer->pAppPrivate); |
| 629 result = OMX_FreeBuffer(component_handle_, output_port_, omx_buffer); | 665 result = OMX_FreeBuffer(component_handle_, output_port_, omx_buffer); |
| 630 RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer failed with: " << result, | 666 RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer", |
| 631 VIDEODECODERERROR_INVALIDINPUT,); | 667 VIDEODECODERERROR_INVALIDINPUT,); |
| 632 texture2eglImage_translator.DestroyEglImage(egl_display_, | 668 texture2eglImage_translator.DestroyEglImage(egl_display_, |
| 633 it->second.egl_image); | 669 it->second.egl_image); |
| 634 client_->DismissPictureBuffer(it->first); | 670 if (client_) |
| 671 client_->DismissPictureBuffer(it->first); | |
| 635 } | 672 } |
| 636 pictures_.clear(); | 673 pictures_.clear(); |
| 637 } | 674 } |
| 638 | 675 |
| 639 void OmxVideoDecodeAccelerator::OnOutputPortDisabled() { | 676 void OmxVideoDecodeAccelerator::OnOutputPortDisabled() { |
| 640 DCHECK_EQ(message_loop_, MessageLoop::current()); | 677 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 641 OMX_PARAM_PORTDEFINITIONTYPE port_format; | 678 OMX_PARAM_PORTDEFINITIONTYPE port_format; |
| 642 InitParam(*this, &port_format); | 679 InitParam(*this, &port_format); |
| 643 port_format.nPortIndex = output_port_; | 680 port_format.nPortIndex = output_port_; |
| 644 OMX_ERRORTYPE result = OMX_GetParameter( | 681 OMX_ERRORTYPE result = OMX_GetParameter( |
| 645 component_handle_, OMX_IndexParamPortDefinition, &port_format); | 682 component_handle_, OMX_IndexParamPortDefinition, &port_format); |
| 646 RETURN_ON_OMX_FAILURE(result, "OMX_GetParameter failed with: " << result, | 683 RETURN_ON_OMX_FAILURE(result, "OMX_GetParameter", |
| 647 VIDEODECODERERROR_UNSUPPORTED,); | 684 VIDEODECODERERROR_UNSUPPORTED,); |
| 648 DCHECK_EQ(port_format.nBufferCountMin, kNumPictureBuffers); | 685 DCHECK_EQ(port_format.nBufferCountMin, kNumPictureBuffers); |
| 649 | 686 |
| 650 // TODO(fischman): to support mid-stream resize, need to free/dismiss any | 687 // 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 | 688 // |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). | 689 // this (there's already freeing logic there, which should not be duplicated). |
| 653 | 690 |
| 654 // Request picture buffers to be handed to the component. | 691 // Request picture buffers to be handed to the component. |
| 655 // ProvidePictureBuffers() will trigger AssignGLESBuffers, which ultimately | 692 // ProvidePictureBuffers() will trigger AssignGLESBuffers, which ultimately |
| 656 // assigns the textures to the component and re-enables the port. | 693 // assigns the textures to the component and re-enables the port. |
| 657 const OMX_VIDEO_PORTDEFINITIONTYPE& vformat = port_format.format.video; | 694 const OMX_VIDEO_PORTDEFINITIONTYPE& vformat = port_format.format.video; |
| 658 client_->ProvidePictureBuffers( | 695 if (client_) { |
| 659 kNumPictureBuffers, | 696 client_->ProvidePictureBuffers( |
| 660 gfx::Size(vformat.nFrameWidth, vformat.nFrameHeight), | 697 kNumPictureBuffers, |
| 661 PICTUREBUFFER_MEMORYTYPE_GL_TEXTURE); | 698 gfx::Size(vformat.nFrameWidth, vformat.nFrameHeight), |
| 699 PICTUREBUFFER_MEMORYTYPE_GL_TEXTURE); | |
| 700 } | |
| 662 } | 701 } |
| 663 | 702 |
| 664 void OmxVideoDecodeAccelerator::OnOutputPortEnabled() { | 703 void OmxVideoDecodeAccelerator::OnOutputPortEnabled() { |
| 665 DCHECK_EQ(message_loop_, MessageLoop::current()); | 704 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 666 | 705 |
| 667 if (!CanFillBuffer()) { | 706 if (!CanFillBuffer()) { |
| 668 StopOnError(VIDEODECODERERROR_UNSUPPORTED); // Should be STATE_ERROR. | 707 StopOnError(VIDEODECODERERROR_UNSUPPORTED); // Should be STATE_ERROR. |
| 669 return; | 708 return; |
| 670 } | 709 } |
| 671 | 710 |
| 672 // Provide output buffers to decoder. | 711 // Provide output buffers to decoder. |
| 673 for (OutputPictureById::iterator it = pictures_.begin(); | 712 for (OutputPictureById::iterator it = pictures_.begin(); |
| 674 it != pictures_.end(); ++it) { | 713 it != pictures_.end(); ++it) { |
| 675 OMX_BUFFERHEADERTYPE* omx_buffer = it->second.omx_buffer_header; | 714 OMX_BUFFERHEADERTYPE* omx_buffer = it->second.omx_buffer_header; |
| 676 DCHECK(omx_buffer); | 715 DCHECK(omx_buffer); |
| 677 // Clear EOS flag. | 716 // Clear EOS flag. |
| 678 omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS; | 717 omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS; |
| 679 omx_buffer->nOutputPortIndex = output_port_; | 718 omx_buffer->nOutputPortIndex = output_port_; |
| 680 ++output_buffers_at_component_; | 719 ++output_buffers_at_component_; |
| 681 OMX_ERRORTYPE result = OMX_FillThisBuffer(component_handle_, omx_buffer); | 720 OMX_ERRORTYPE result = OMX_FillThisBuffer(component_handle_, omx_buffer); |
| 682 RETURN_ON_OMX_FAILURE(result, | 721 RETURN_ON_OMX_FAILURE(result, "OMX_FillThisBuffer() failed", |
| 683 "OMX_FillThisBuffer() failed with result " << result, | |
| 684 VIDEODECODERERROR_INSUFFICIENT_BUFFERS,); | 722 VIDEODECODERERROR_INSUFFICIENT_BUFFERS,); |
| 685 } | 723 } |
| 686 } | 724 } |
| 687 | 725 |
| 688 void OmxVideoDecodeAccelerator::FillBufferDoneTask( | 726 void OmxVideoDecodeAccelerator::FillBufferDoneTask( |
| 689 OMX_BUFFERHEADERTYPE* buffer) { | 727 OMX_BUFFERHEADERTYPE* buffer) { |
| 690 DCHECK_EQ(message_loop_, MessageLoop::current()); | 728 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 691 DCHECK_GT(output_buffers_at_component_, 0); | 729 DCHECK_GT(output_buffers_at_component_, 0); |
| 692 --output_buffers_at_component_; | 730 --output_buffers_at_component_; |
| 693 | 731 |
| 694 if (fake_output_buffers_.size() && fake_output_buffers_.count(buffer)) { | 732 if (fake_output_buffers_.size() && fake_output_buffers_.count(buffer)) { |
| 695 CHECK_EQ(fake_output_buffers_.erase(buffer), 1U); | 733 CHECK_EQ(fake_output_buffers_.erase(buffer), 1U); |
| 696 OMX_ERRORTYPE result = | 734 OMX_ERRORTYPE result = |
| 697 OMX_FreeBuffer(component_handle_, output_port_, buffer); | 735 OMX_FreeBuffer(component_handle_, output_port_, buffer); |
| 698 RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer failed with: " << result, | 736 RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer failed", |
| 699 VIDEODECODERERROR_INVALIDINPUT,); | 737 VIDEODECODERERROR_INVALIDINPUT,); |
| 700 return; | 738 return; |
| 701 } | 739 } |
| 702 CHECK(!fake_output_buffers_.size()); | 740 CHECK(!fake_output_buffers_.size()); |
| 703 | 741 |
| 704 if (current_state_change_ == FLUSHING && | 742 if (current_state_change_ == FLUSHING && |
| 705 buffer->nFlags & OMX_BUFFERFLAG_EOS) { | 743 buffer->nFlags & OMX_BUFFERFLAG_EOS) { |
| 706 DCHECK(!saw_eos_during_flush_); | 744 DCHECK(!saw_eos_during_flush_); |
| 707 saw_eos_during_flush_ = true; | 745 saw_eos_during_flush_ = true; |
| 708 } | 746 } |
| 709 | 747 |
| 710 // During the transition from Executing to Idle, and during port-flushing, all | 748 // 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. | 749 // pictures are sent back through here. Avoid giving them to the client. |
| 712 // Also avoid sending the (fake) EOS buffer to the client. | 750 // Also avoid sending the (fake) EOS buffer to the client. |
| 713 if ((current_state_change_ != NO_TRANSITION && | 751 if ((current_state_change_ != NO_TRANSITION && |
| 714 current_state_change_ != FLUSHING) || | 752 current_state_change_ != FLUSHING) || |
| 715 saw_eos_during_flush_) { | 753 saw_eos_during_flush_) { |
| 716 return; | 754 return; |
| 717 } | 755 } |
| 718 | 756 |
| 719 CHECK(buffer->pAppPrivate); | 757 CHECK(buffer->pAppPrivate); |
| 720 media::Picture* picture = | 758 media::Picture* picture = |
| 721 reinterpret_cast<media::Picture*>(buffer->pAppPrivate); | 759 reinterpret_cast<media::Picture*>(buffer->pAppPrivate); |
| 722 // See Decode() for an explanation of this abuse of nTimeStamp. | 760 // See Decode() for an explanation of this abuse of nTimeStamp. |
| 723 picture->set_bitstream_buffer_id(buffer->nTimeStamp); | 761 picture->set_bitstream_buffer_id(buffer->nTimeStamp); |
| 724 client_->PictureReady(*picture); | 762 if (client_) |
| 763 client_->PictureReady(*picture); | |
| 725 } | 764 } |
| 726 | 765 |
| 727 void OmxVideoDecodeAccelerator::EmptyBufferDoneTask( | 766 void OmxVideoDecodeAccelerator::EmptyBufferDoneTask( |
| 728 OMX_BUFFERHEADERTYPE* buffer) { | 767 OMX_BUFFERHEADERTYPE* buffer) { |
| 729 DCHECK_EQ(message_loop_, MessageLoop::current()); | 768 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 730 DCHECK_GT(input_buffers_at_component_, 0); | 769 DCHECK_GT(input_buffers_at_component_, 0); |
| 731 free_input_buffers_.push(buffer); | 770 free_input_buffers_.push(buffer); |
| 732 input_buffers_at_component_--; | 771 input_buffers_at_component_--; |
| 733 if (buffer->nFlags & OMX_BUFFERFLAG_EOS) | 772 if (buffer->nFlags & OMX_BUFFERFLAG_EOS) |
| 734 return; | 773 return; |
| 735 | 774 |
| 736 // Retrieve the corresponding BitstreamBuffer's id and notify the client of | 775 // Retrieve the corresponding BitstreamBuffer's id and notify the client of |
| 737 // its completion. | 776 // its completion. |
| 738 SharedMemoryAndId* input_buffer_details = | 777 SharedMemoryAndId* input_buffer_details = |
| 739 reinterpret_cast<SharedMemoryAndId*>(buffer->pAppPrivate); | 778 reinterpret_cast<SharedMemoryAndId*>(buffer->pAppPrivate); |
| 740 DCHECK(input_buffer_details); | 779 DCHECK(input_buffer_details); |
| 741 buffer->pAppPrivate = NULL; | 780 buffer->pAppPrivate = NULL; |
| 742 client_->NotifyEndOfBitstreamBuffer(input_buffer_details->second); | 781 if (client_) |
| 782 client_->NotifyEndOfBitstreamBuffer(input_buffer_details->second); | |
| 743 delete input_buffer_details; | 783 delete input_buffer_details; |
| 744 } | 784 } |
| 745 | 785 |
| 746 void OmxVideoDecodeAccelerator::DispatchStateReached(OMX_STATETYPE reached) { | 786 void OmxVideoDecodeAccelerator::DispatchStateReached(OMX_STATETYPE reached) { |
| 747 DCHECK_EQ(message_loop_, MessageLoop::current()); | 787 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 748 switch (current_state_change_) { | 788 switch (current_state_change_) { |
| 749 case INITIALIZING: | 789 case INITIALIZING: |
| 750 switch (reached) { | 790 switch (reached) { |
| 751 case OMX_StateIdle: | 791 case OMX_StateIdle: |
| 752 OnReachedIdleInInitializing(); | 792 OnReachedIdleInInitializing(); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 794 NOTREACHED() << "Unexpected state in " << current_state_change_ | 834 NOTREACHED() << "Unexpected state in " << current_state_change_ |
| 795 << ": " << reached; | 835 << ": " << reached; |
| 796 } | 836 } |
| 797 } | 837 } |
| 798 | 838 |
| 799 void OmxVideoDecodeAccelerator::EventHandlerCompleteTask(OMX_EVENTTYPE event, | 839 void OmxVideoDecodeAccelerator::EventHandlerCompleteTask(OMX_EVENTTYPE event, |
| 800 OMX_U32 data1, | 840 OMX_U32 data1, |
| 801 OMX_U32 data2) { | 841 OMX_U32 data2) { |
| 802 DCHECK_EQ(message_loop_, MessageLoop::current()); | 842 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 803 switch (event) { | 843 switch (event) { |
| 804 case OMX_EventCmdComplete: { | 844 case OMX_EventCmdComplete: |
| 805 // If the last command was successful, we have completed | 845 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: | 846 case OMX_CommandPortDisable: |
| 811 DCHECK_EQ(data2, output_port_); | 847 DCHECK_EQ(data2, output_port_); |
| 812 OnOutputPortDisabled(); | 848 OnOutputPortDisabled(); |
| 813 break; | 849 return; |
| 814 case OMX_CommandPortEnable: | 850 case OMX_CommandPortEnable: |
| 815 DCHECK_EQ(data2, output_port_); | 851 DCHECK_EQ(data2, output_port_); |
| 816 OnOutputPortEnabled(); | 852 OnOutputPortEnabled(); |
| 817 break; | 853 return; |
| 818 case OMX_CommandStateSet: | 854 case OMX_CommandStateSet: |
| 819 DispatchStateReached(static_cast<OMX_STATETYPE>(data2)); | 855 DispatchStateReached(static_cast<OMX_STATETYPE>(data2)); |
| 820 break; | 856 return; |
| 821 case OMX_CommandFlush: | 857 case OMX_CommandFlush: |
| 822 DCHECK(current_state_change_ == FLUSHING || | 858 DCHECK(current_state_change_ == FLUSHING || |
| 823 current_state_change_ == RESETTING || | 859 current_state_change_ == RESETTING || |
| 824 current_state_change_ == DESTROYING); | 860 current_state_change_ == DESTROYING); |
| 825 if (data2 == input_port_) | 861 if (data2 == input_port_) |
| 826 InputPortFlushDone(); | 862 InputPortFlushDone(); |
| 827 else if (data2 == output_port_) | 863 else if (data2 == output_port_) |
| 828 OutputPortFlushDone(); | 864 OutputPortFlushDone(); |
| 829 else | 865 else |
| 830 NOTREACHED() << "Unexpected port flushed: " << data2; | 866 NOTREACHED() << "Unexpected port flushed: " << data2; |
| 831 break; | 867 return; |
| 832 default: | 868 default: |
| 833 RETURN_ON_FAILURE(false, "Unknown command completed: " << data1, | 869 RETURN_ON_FAILURE(false, "Unknown command completed: " << data1, |
| 834 VIDEODECODERERROR_HARDWARE,); | 870 VIDEODECODERERROR_HARDWARE,); |
| 835 } | 871 } |
| 836 break; | 872 return; |
| 837 } | |
| 838 case OMX_EventError: | 873 case OMX_EventError: |
| 839 RETURN_ON_FAILURE(false, "EventError: " << data1, | 874 if (current_state_change_ != DESTROYING && |
| 840 VIDEODECODERERROR_HARDWARE,); | 875 current_state_change_ != ERRORING) { |
| 876 RETURN_ON_FAILURE(false, "EventError: 0x" << std::hex << data1, | |
| 877 VIDEODECODERERROR_HARDWARE,); | |
| 878 } | |
| 879 return; | |
| 841 case OMX_EventPortSettingsChanged: | 880 case OMX_EventPortSettingsChanged: |
| 842 if (data2 == OMX_IndexParamPortDefinition) { | 881 if (data2 == OMX_IndexParamPortDefinition) { |
| 843 DCHECK_EQ(data1, output_port_); | 882 DCHECK_EQ(data1, output_port_); |
| 844 // This event is only used for output resize; kick off handling that by | 883 // This event is only used for output resize; kick off handling that by |
| 845 // pausing the output port. | 884 // pausing the output port. |
| 846 SendCommandToPort(OMX_CommandPortDisable, output_port_); | 885 SendCommandToPort(OMX_CommandPortDisable, output_port_); |
| 847 } else if (data1 == output_port_ && | 886 } else if (data1 == output_port_ && |
| 848 data2 == OMX_IndexConfigCommonOutputCrop) { | 887 data2 == OMX_IndexConfigCommonOutputCrop) { |
| 849 // TODO(vjain): Handle video crop rect. | 888 // TODO(vjain): Handle video crop rect. |
| 850 } else { | 889 } else { |
| 851 RETURN_ON_FAILURE(false, | 890 RETURN_ON_FAILURE(false, |
| 852 "Unexpected EventPortSettingsChanged: " | 891 "Unexpected EventPortSettingsChanged: " |
| 853 << data1 << ", " << data2, | 892 << data1 << ", " << data2, |
| 854 VIDEODECODERERROR_HARDWARE,); | 893 VIDEODECODERERROR_HARDWARE,); |
| 855 } | 894 } |
| 856 break; | 895 return; |
| 857 case OMX_EventBufferFlag: | 896 case OMX_EventBufferFlag: |
| 858 if (data1 == output_port_) { | 897 if (data1 == output_port_) { |
| 859 DCHECK_EQ(current_state_change_, FLUSHING); | 898 DCHECK_EQ(current_state_change_, FLUSHING); |
| 860 OnReachedEOSInFlushing(); | 899 OnReachedEOSInFlushing(); |
| 861 } else { | 900 } else { |
| 862 RETURN_ON_FAILURE(false, | 901 RETURN_ON_FAILURE(false, |
| 863 "Unexpected OMX_EventBufferFlag: " | 902 "Unexpected OMX_EventBufferFlag: " |
| 864 << data1 << ", " << data2, | 903 << data1 << ", " << data2, |
| 865 VIDEODECODERERROR_HARDWARE,); | 904 VIDEODECODERERROR_HARDWARE,); |
| 866 } | 905 } |
| 867 break; | 906 return; |
| 868 default: | 907 default: |
| 869 RETURN_ON_FAILURE(false, "Unexpected unhandled event: " << event, | 908 RETURN_ON_FAILURE(false, "Unexpected unhandled event: " << event, |
| 870 VIDEODECODERERROR_HARDWARE,); | 909 VIDEODECODERERROR_HARDWARE,); |
| 871 } | 910 } |
| 872 } | 911 } |
| 873 | 912 |
| 874 // static | 913 // static |
| 875 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EventHandler(OMX_HANDLETYPE component, | 914 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EventHandler(OMX_HANDLETYPE component, |
| 876 OMX_PTR priv_data, | 915 OMX_PTR priv_data, |
| 877 OMX_EVENTTYPE event, | 916 OMX_EVENTTYPE event, |
| 878 OMX_U32 data1, | 917 OMX_U32 data1, |
| 879 OMX_U32 data2, | 918 OMX_U32 data2, |
| 880 OMX_PTR event_data) { | 919 OMX_PTR event_data) { |
| 881 // Called on the OMX thread. | 920 // Called on the OMX thread. |
| 882 OmxVideoDecodeAccelerator* decoder = | 921 OmxVideoDecodeAccelerator* decoder = |
| 883 static_cast<OmxVideoDecodeAccelerator*>(priv_data); | 922 static_cast<OmxVideoDecodeAccelerator*>(priv_data); |
| 884 DCHECK_EQ(component, decoder->component_handle_); | 923 DCHECK_EQ(component, decoder->component_handle_); |
| 885 decoder->message_loop_->PostTask( | 924 decoder->message_loop_->PostTask( |
| 886 FROM_HERE, | 925 FROM_HERE, NewRunnableMethod( |
| 887 NewRunnableMethod(decoder, | 926 decoder, &OmxVideoDecodeAccelerator::EventHandlerCompleteTask, |
| 888 &OmxVideoDecodeAccelerator::EventHandlerCompleteTask, | 927 event, data1, data2)); |
| 889 event, data1, data2)); | |
| 890 return OMX_ErrorNone; | 928 return OMX_ErrorNone; |
| 891 } | 929 } |
| 892 | 930 |
| 893 // static | 931 // static |
| 894 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EmptyBufferCallback( | 932 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EmptyBufferCallback( |
| 895 OMX_HANDLETYPE component, | 933 OMX_HANDLETYPE component, |
| 896 OMX_PTR priv_data, | 934 OMX_PTR priv_data, |
| 897 OMX_BUFFERHEADERTYPE* buffer) { | 935 OMX_BUFFERHEADERTYPE* buffer) { |
| 898 // Called on the OMX thread. | 936 // Called on the OMX thread. |
| 899 OmxVideoDecodeAccelerator* decoder = | 937 OmxVideoDecodeAccelerator* decoder = |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 919 decoder->message_loop_->PostTask( | 957 decoder->message_loop_->PostTask( |
| 920 FROM_HERE, | 958 FROM_HERE, |
| 921 NewRunnableMethod(decoder, | 959 NewRunnableMethod(decoder, |
| 922 &OmxVideoDecodeAccelerator::FillBufferDoneTask, | 960 &OmxVideoDecodeAccelerator::FillBufferDoneTask, |
| 923 buffer)); | 961 buffer)); |
| 924 return OMX_ErrorNone; | 962 return OMX_ErrorNone; |
| 925 } | 963 } |
| 926 | 964 |
| 927 bool OmxVideoDecodeAccelerator::CanFillBuffer() { | 965 bool OmxVideoDecodeAccelerator::CanFillBuffer() { |
| 928 DCHECK_EQ(message_loop_, MessageLoop::current()); | 966 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 967 if (current_state_change_ == DESTROYING || | |
| 968 current_state_change_ == ERRORING) { | |
| 969 return false; | |
| 970 } | |
| 929 return client_state_ == OMX_StateIdle || | 971 return client_state_ == OMX_StateIdle || |
| 930 client_state_ == OMX_StateExecuting || | 972 client_state_ == OMX_StateExecuting || |
| 931 client_state_ == OMX_StatePause; | 973 client_state_ == OMX_StatePause; |
| 932 } | 974 } |
| 933 | 975 |
| 934 bool OmxVideoDecodeAccelerator::SendCommandToPort( | 976 bool OmxVideoDecodeAccelerator::SendCommandToPort( |
| 935 OMX_COMMANDTYPE cmd, int port_index) { | 977 OMX_COMMANDTYPE cmd, int port_index) { |
| 936 DCHECK_EQ(message_loop_, MessageLoop::current()); | 978 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 937 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, | 979 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, |
| 938 cmd, port_index, 0); | 980 cmd, port_index, 0); |
| 939 RETURN_ON_OMX_FAILURE(result, "SendCommand() failed" << cmd << ":" << result, | 981 RETURN_ON_OMX_FAILURE(result, "SendCommand() failed" << cmd, |
| 940 VIDEODECODERERROR_INVALIDINPUT, false); | 982 VIDEODECODERERROR_INVALIDINPUT, false); |
| 941 return true; | 983 return true; |
| 942 } | 984 } |
| 943 | |
| 944 DISABLE_RUNNABLE_METHOD_REFCOUNT(OmxVideoDecodeAccelerator); | |
| OLD | NEW |