OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "base/bind.h" | 5 #include "base/bind.h" |
6 #include "base/command_line.h" | 6 #include "base/command_line.h" |
7 #include "base/debug/trace_event.h" | 7 #include "base/debug/trace_event.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
(...skipping 18 matching lines...) Expand all Loading... |
29 using content::VaapiH264Decoder; | 29 using content::VaapiH264Decoder; |
30 | 30 |
31 VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() { | 31 VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() { |
32 } | 32 } |
33 | 33 |
34 VaapiVideoDecodeAccelerator::InputBuffer::~InputBuffer() { | 34 VaapiVideoDecodeAccelerator::InputBuffer::~InputBuffer() { |
35 } | 35 } |
36 | 36 |
37 void VaapiVideoDecodeAccelerator::NotifyError(Error error) { | 37 void VaapiVideoDecodeAccelerator::NotifyError(Error error) { |
38 if (message_loop_ != MessageLoop::current()) { | 38 if (message_loop_ != MessageLoop::current()) { |
| 39 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); |
39 message_loop_->PostTask(FROM_HERE, base::Bind( | 40 message_loop_->PostTask(FROM_HERE, base::Bind( |
40 &VaapiVideoDecodeAccelerator::NotifyError, this, error)); | 41 &VaapiVideoDecodeAccelerator::NotifyError, weak_this_, error)); |
41 return; | 42 return; |
42 } | 43 } |
43 | 44 |
44 DVLOG(1) << "Notifying of error " << error; | 45 DVLOG(1) << "Notifying of error " << error; |
45 | 46 |
46 if (client_) { | 47 if (client_) { |
47 client_->NotifyError(error); | 48 client_->NotifyError(error); |
48 client_ptr_factory_.InvalidateWeakPtrs(); | 49 client_ptr_factory_.InvalidateWeakPtrs(); |
49 } | 50 } |
50 Destroy(); | 51 Cleanup(); |
51 } | 52 } |
52 | 53 |
53 VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( | 54 VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( |
54 Client* client, | 55 Client* client, |
55 const base::Callback<bool(void)>& make_context_current) | 56 const base::Callback<bool(void)>& make_context_current) |
56 : make_context_current_(make_context_current), | 57 : make_context_current_(make_context_current), |
57 state_(kUninitialized), | 58 state_(kUninitialized), |
58 input_ready_(&lock_), | 59 input_ready_(&lock_), |
59 output_ready_(&lock_), | 60 output_ready_(&lock_), |
60 message_loop_(MessageLoop::current()), | 61 message_loop_(MessageLoop::current()), |
| 62 weak_this_(base::AsWeakPtr(this)), |
61 client_ptr_factory_(client), | 63 client_ptr_factory_(client), |
62 client_(client_ptr_factory_.GetWeakPtr()), | 64 client_(client_ptr_factory_.GetWeakPtr()), |
63 decoder_thread_("VaapiDecoderThread") { | 65 decoder_thread_("VaapiDecoderThread") { |
64 DCHECK(client); | 66 DCHECK(client); |
65 } | 67 } |
66 | 68 |
67 VaapiVideoDecodeAccelerator::~VaapiVideoDecodeAccelerator() { | 69 VaapiVideoDecodeAccelerator::~VaapiVideoDecodeAccelerator() { |
68 DCHECK_EQ(message_loop_, MessageLoop::current()); | 70 DCHECK_EQ(message_loop_, MessageLoop::current()); |
69 } | 71 } |
70 | 72 |
71 bool VaapiVideoDecodeAccelerator::Initialize( | 73 bool VaapiVideoDecodeAccelerator::Initialize( |
72 media::VideoCodecProfile profile) { | 74 media::VideoCodecProfile profile) { |
73 DCHECK_EQ(message_loop_, MessageLoop::current()); | 75 DCHECK_EQ(message_loop_, MessageLoop::current()); |
74 | 76 |
75 base::AutoLock auto_lock(lock_); | 77 base::AutoLock auto_lock(lock_); |
76 DCHECK_EQ(state_, kUninitialized); | 78 DCHECK_EQ(state_, kUninitialized); |
77 DVLOG(2) << "Initializing VAVDA, profile: " << profile; | 79 DVLOG(2) << "Initializing VAVDA, profile: " << profile; |
78 | 80 |
79 bool res = decoder_.Initialize( | 81 bool res = decoder_.Initialize( |
80 profile, x_display_, glx_context_, make_context_current_, | 82 profile, x_display_, glx_context_, make_context_current_, |
81 base::Bind(&VaapiVideoDecodeAccelerator::OutputPicCallback, this)); | 83 base::Bind(&VaapiVideoDecodeAccelerator::OutputPicCallback, |
| 84 base::Unretained(this))); |
82 if (!res) { | 85 if (!res) { |
83 DVLOG(1) << "Failed initializing decoder"; | 86 DVLOG(1) << "Failed initializing decoder"; |
84 return false; | 87 return false; |
85 } | 88 } |
86 | 89 |
87 CHECK(decoder_thread_.Start()); | 90 CHECK(decoder_thread_.Start()); |
88 | 91 |
89 state_ = kInitialized; | 92 state_ = kInitialized; |
90 | 93 |
91 message_loop_->PostTask(FROM_HERE, base::Bind( | 94 message_loop_->PostTask(FROM_HERE, base::Bind( |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 DVLOG(1) << "Requesting " << num_pics << " pictures of size: " | 177 DVLOG(1) << "Requesting " << num_pics << " pictures of size: " |
175 << size.width() << "x" << size.height(); | 178 << size.width() << "x" << size.height(); |
176 message_loop_->PostTask(FROM_HERE, base::Bind( | 179 message_loop_->PostTask(FROM_HERE, base::Bind( |
177 &Client::ProvidePictureBuffers, client_, | 180 &Client::ProvidePictureBuffers, client_, |
178 num_pics, size, GL_TEXTURE_2D)); | 181 num_pics, size, GL_TEXTURE_2D)); |
179 } else { | 182 } else { |
180 base::AutoLock auto_lock(lock_); | 183 base::AutoLock auto_lock(lock_); |
181 DCHECK_EQ(state_, kIdle); | 184 DCHECK_EQ(state_, kIdle); |
182 state_ = kDecoding; | 185 state_ = kDecoding; |
183 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 186 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
184 &VaapiVideoDecodeAccelerator::DecodeTask, this)); | 187 &VaapiVideoDecodeAccelerator::DecodeTask, |
| 188 base::Unretained(this))); |
185 } | 189 } |
186 return; | 190 return; |
187 | 191 |
188 case VaapiH264Decoder::kNeedMoreStreamData: | 192 case VaapiH264Decoder::kNeedMoreStreamData: |
189 ReturnCurrInputBuffer(); | 193 ReturnCurrInputBuffer(); |
190 break; | 194 break; |
191 | 195 |
192 case VaapiH264Decoder::kDecodeError: | 196 case VaapiH264Decoder::kDecodeError: |
193 RETURN_AND_NOTIFY_ON_FAILURE(false, "Error in decoding", | 197 RETURN_AND_NOTIFY_ON_FAILURE(false, "Error in decoding", |
194 PLATFORM_FAILURE, ); | 198 PLATFORM_FAILURE, ); |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
335 TRACE_EVENT1("Video Decoder", "VAVDA::Decode", "Buffer id", | 339 TRACE_EVENT1("Video Decoder", "VAVDA::Decode", "Buffer id", |
336 bitstream_buffer.id()); | 340 bitstream_buffer.id()); |
337 | 341 |
338 // We got a new input buffer from the client, map it and queue for later use. | 342 // We got a new input buffer from the client, map it and queue for later use. |
339 MapAndQueueNewInputBuffer(bitstream_buffer); | 343 MapAndQueueNewInputBuffer(bitstream_buffer); |
340 | 344 |
341 base::AutoLock auto_lock(lock_); | 345 base::AutoLock auto_lock(lock_); |
342 switch (state_) { | 346 switch (state_) { |
343 case kInitialized: | 347 case kInitialized: |
344 // Initial decode to get the required size of output buffers. | 348 // Initial decode to get the required size of output buffers. |
345 decoder_thread_.message_loop()->PostTask(FROM_HERE, | 349 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
346 base::Bind(&VaapiVideoDecodeAccelerator::InitialDecodeTask, this)); | 350 &VaapiVideoDecodeAccelerator::InitialDecodeTask, |
| 351 base::Unretained(this))); |
347 break; | 352 break; |
348 | 353 |
349 case kPicturesRequested: | 354 case kPicturesRequested: |
350 // Waiting for pictures, return. | 355 // Waiting for pictures, return. |
351 break; | 356 break; |
352 | 357 |
353 case kDecoding: | 358 case kDecoding: |
354 break; | 359 break; |
355 | 360 |
356 case kIdle: | 361 case kIdle: |
357 // Need to get decoder into suitable stream location to resume. | 362 // Need to get decoder into suitable stream location to resume. |
358 decoder_thread_.message_loop()->PostTask(FROM_HERE, | 363 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
359 base::Bind(&VaapiVideoDecodeAccelerator::InitialDecodeTask, this)); | 364 &VaapiVideoDecodeAccelerator::InitialDecodeTask, |
| 365 base::Unretained(this))); |
360 break; | 366 break; |
361 | 367 |
362 default: | 368 default: |
363 DVLOG(1) << "Decode request from client in invalid state: " << state_; | 369 DVLOG(1) << "Decode request from client in invalid state: " << state_; |
364 return; | 370 return; |
365 } | 371 } |
366 } | 372 } |
367 | 373 |
368 void VaapiVideoDecodeAccelerator::AssignPictureBuffers( | 374 void VaapiVideoDecodeAccelerator::AssignPictureBuffers( |
369 const std::vector<media::PictureBuffer>& buffers) { | 375 const std::vector<media::PictureBuffer>& buffers) { |
370 DCHECK_EQ(message_loop_, MessageLoop::current()); | 376 DCHECK_EQ(message_loop_, MessageLoop::current()); |
371 | 377 |
372 base::AutoLock auto_lock(lock_); | 378 base::AutoLock auto_lock(lock_); |
373 DCHECK_EQ(state_, kPicturesRequested); | 379 DCHECK_EQ(state_, kPicturesRequested); |
374 | 380 |
375 for (size_t i = 0; i < buffers.size(); ++i) { | 381 for (size_t i = 0; i < buffers.size(); ++i) { |
376 DVLOG(2) << "Assigning picture id " << buffers[i].id() | 382 DVLOG(2) << "Assigning picture id " << buffers[i].id() |
377 << " to texture id " << buffers[i].texture_id(); | 383 << " to texture id " << buffers[i].texture_id(); |
378 | 384 |
379 bool res = decoder_.AssignPictureBuffer(buffers[i].id(), | 385 bool res = decoder_.AssignPictureBuffer(buffers[i].id(), |
380 buffers[i].texture_id()); | 386 buffers[i].texture_id()); |
381 RETURN_AND_NOTIFY_ON_FAILURE( | 387 RETURN_AND_NOTIFY_ON_FAILURE( |
382 res, "Failed assigning picture buffer id: " << buffers[i].id() << | 388 res, "Failed assigning picture buffer id: " << buffers[i].id() << |
383 ", texture id: " << buffers[i].texture_id(), PLATFORM_FAILURE, ); | 389 ", texture id: " << buffers[i].texture_id(), PLATFORM_FAILURE, ); |
384 } | 390 } |
385 | 391 |
386 state_ = kDecoding; | 392 state_ = kDecoding; |
387 decoder_thread_.message_loop()->PostTask(FROM_HERE, | 393 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
388 base::Bind(&VaapiVideoDecodeAccelerator::DecodeTask, this)); | 394 &VaapiVideoDecodeAccelerator::DecodeTask, base::Unretained(this))); |
389 } | 395 } |
390 | 396 |
391 void VaapiVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { | 397 void VaapiVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { |
392 DCHECK_EQ(message_loop_, MessageLoop::current()); | 398 DCHECK_EQ(message_loop_, MessageLoop::current()); |
393 TRACE_EVENT1("Video Decoder", "VAVDA::ReusePictureBuffer", "Picture id", | 399 TRACE_EVENT1("Video Decoder", "VAVDA::ReusePictureBuffer", "Picture id", |
394 picture_buffer_id); | 400 picture_buffer_id); |
395 | 401 |
396 base::AutoLock auto_lock(lock_); | 402 base::AutoLock auto_lock(lock_); |
397 output_buffers_.push(picture_buffer_id); | 403 output_buffers_.push(picture_buffer_id); |
398 output_ready_.Signal(); | 404 output_ready_.Signal(); |
399 } | 405 } |
400 | 406 |
401 void VaapiVideoDecodeAccelerator::FlushTask() { | 407 void VaapiVideoDecodeAccelerator::FlushTask() { |
402 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); | 408 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); |
403 DVLOG(1) << "Flush task"; | 409 DVLOG(1) << "Flush task"; |
404 | 410 |
405 // First flush all the pictures that haven't been outputted, notifying the | 411 // First flush all the pictures that haven't been outputted, notifying the |
406 // client to output them. | 412 // client to output them. |
407 bool res = decoder_.Flush(); | 413 bool res = decoder_.Flush(); |
408 RETURN_AND_NOTIFY_ON_FAILURE(res, "Failed flushing the decoder.", | 414 RETURN_AND_NOTIFY_ON_FAILURE(res, "Failed flushing the decoder.", |
409 PLATFORM_FAILURE, ); | 415 PLATFORM_FAILURE, ); |
410 | 416 |
411 // Put the decoder in idle state, ready to resume. | 417 // Put the decoder in idle state, ready to resume. |
412 decoder_.Reset(); | 418 decoder_.Reset(); |
413 | 419 |
414 message_loop_->PostTask(FROM_HERE, | 420 message_loop_->PostTask(FROM_HERE, base::Bind( |
415 base::Bind(&VaapiVideoDecodeAccelerator::FinishFlush, this)); | 421 &VaapiVideoDecodeAccelerator::FinishFlush, weak_this_)); |
416 } | 422 } |
417 | 423 |
418 void VaapiVideoDecodeAccelerator::Flush() { | 424 void VaapiVideoDecodeAccelerator::Flush() { |
419 DCHECK_EQ(message_loop_, MessageLoop::current()); | 425 DCHECK_EQ(message_loop_, MessageLoop::current()); |
420 DVLOG(1) << "Got flush request"; | 426 DVLOG(1) << "Got flush request"; |
421 | 427 |
422 base::AutoLock auto_lock(lock_); | 428 base::AutoLock auto_lock(lock_); |
423 state_ = kFlushing; | 429 state_ = kFlushing; |
424 // Queue a flush task after all existing decoding tasks to clean up. | 430 // Queue a flush task after all existing decoding tasks to clean up. |
425 decoder_thread_.message_loop()->PostTask(FROM_HERE, | 431 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
426 base::Bind(&VaapiVideoDecodeAccelerator::FlushTask, this)); | 432 &VaapiVideoDecodeAccelerator::FlushTask, base::Unretained(this))); |
427 | 433 |
428 input_ready_.Signal(); | 434 input_ready_.Signal(); |
429 output_ready_.Signal(); | 435 output_ready_.Signal(); |
430 } | 436 } |
431 | 437 |
432 void VaapiVideoDecodeAccelerator::FinishFlush() { | 438 void VaapiVideoDecodeAccelerator::FinishFlush() { |
433 DCHECK_EQ(message_loop_, MessageLoop::current()); | 439 DCHECK_EQ(message_loop_, MessageLoop::current()); |
434 | 440 |
435 base::AutoLock auto_lock(lock_); | 441 base::AutoLock auto_lock(lock_); |
436 if (state_ != kFlushing) { | 442 if (state_ != kFlushing) { |
(...skipping 16 matching lines...) Expand all Loading... |
453 // by now, as this task was scheduled after them and client is expected not | 459 // by now, as this task was scheduled after them and client is expected not |
454 // to call Decode() after Reset() and before NotifyResetDone. | 460 // to call Decode() after Reset() and before NotifyResetDone. |
455 decoder_.Reset(); | 461 decoder_.Reset(); |
456 | 462 |
457 // Return current input buffer, if present. | 463 // Return current input buffer, if present. |
458 if (curr_input_buffer_.get()) | 464 if (curr_input_buffer_.get()) |
459 ReturnCurrInputBuffer(); | 465 ReturnCurrInputBuffer(); |
460 | 466 |
461 // And let client know that we are done with reset. | 467 // And let client know that we are done with reset. |
462 message_loop_->PostTask(FROM_HERE, base::Bind( | 468 message_loop_->PostTask(FROM_HERE, base::Bind( |
463 &VaapiVideoDecodeAccelerator::FinishReset, this)); | 469 &VaapiVideoDecodeAccelerator::FinishReset, weak_this_)); |
464 } | 470 } |
465 | 471 |
466 void VaapiVideoDecodeAccelerator::Reset() { | 472 void VaapiVideoDecodeAccelerator::Reset() { |
467 DCHECK_EQ(message_loop_, MessageLoop::current()); | 473 DCHECK_EQ(message_loop_, MessageLoop::current()); |
468 DVLOG(1) << "Got reset request"; | 474 DVLOG(1) << "Got reset request"; |
469 | 475 |
470 // This will make any new decode tasks exit early. | 476 // This will make any new decode tasks exit early. |
471 base::AutoLock auto_lock(lock_); | 477 base::AutoLock auto_lock(lock_); |
472 state_ = kResetting; | 478 state_ = kResetting; |
473 | 479 |
474 decoder_thread_.message_loop()->PostTask(FROM_HERE, | 480 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
475 base::Bind(&VaapiVideoDecodeAccelerator::ResetTask, this)); | 481 &VaapiVideoDecodeAccelerator::ResetTask, base::Unretained(this))); |
476 | 482 |
477 input_ready_.Signal(); | 483 input_ready_.Signal(); |
478 output_ready_.Signal(); | 484 output_ready_.Signal(); |
479 } | 485 } |
480 | 486 |
481 void VaapiVideoDecodeAccelerator::FinishReset() { | 487 void VaapiVideoDecodeAccelerator::FinishReset() { |
482 DCHECK_EQ(message_loop_, MessageLoop::current()); | 488 DCHECK_EQ(message_loop_, MessageLoop::current()); |
483 | 489 |
484 base::AutoLock auto_lock(lock_); | 490 base::AutoLock auto_lock(lock_); |
485 if (state_ != kResetting) { | 491 if (state_ != kResetting) { |
(...skipping 10 matching lines...) Expand all Loading... |
496 } | 502 } |
497 | 503 |
498 state_ = kIdle; | 504 state_ = kIdle; |
499 | 505 |
500 message_loop_->PostTask(FROM_HERE, base::Bind( | 506 message_loop_->PostTask(FROM_HERE, base::Bind( |
501 &Client::NotifyResetDone, client_)); | 507 &Client::NotifyResetDone, client_)); |
502 | 508 |
503 DVLOG(1) << "Reset finished"; | 509 DVLOG(1) << "Reset finished"; |
504 } | 510 } |
505 | 511 |
506 void VaapiVideoDecodeAccelerator::Destroy() { | 512 void VaapiVideoDecodeAccelerator::Cleanup() { |
507 DCHECK_EQ(message_loop_, MessageLoop::current()); | 513 DCHECK_EQ(message_loop_, MessageLoop::current()); |
508 | 514 |
509 if (state_ == kUninitialized || state_ == kDestroying) | 515 if (state_ == kUninitialized || state_ == kDestroying) |
510 return; | 516 return; |
511 | 517 |
512 DVLOG(1) << "Destroying VAVDA"; | 518 DVLOG(1) << "Destroying VAVDA"; |
513 base::AutoLock auto_lock(lock_); | 519 base::AutoLock auto_lock(lock_); |
514 state_ = kDestroying; | 520 state_ = kDestroying; |
515 | 521 |
516 client_ptr_factory_.InvalidateWeakPtrs(); | 522 client_ptr_factory_.InvalidateWeakPtrs(); |
517 | 523 |
518 { | 524 { |
519 base::AutoUnlock auto_unlock(lock_); | 525 base::AutoUnlock auto_unlock(lock_); |
520 // Post a dummy task to the decoder_thread_ to ensure it is drained. | 526 // Post a dummy task to the decoder_thread_ to ensure it is drained. |
521 base::WaitableEvent waiter(false, false); | 527 base::WaitableEvent waiter(false, false); |
522 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 528 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
523 &base::WaitableEvent::Signal, base::Unretained(&waiter))); | 529 &base::WaitableEvent::Signal, base::Unretained(&waiter))); |
524 input_ready_.Signal(); | 530 input_ready_.Signal(); |
525 output_ready_.Signal(); | 531 output_ready_.Signal(); |
526 waiter.Wait(); | 532 waiter.Wait(); |
| 533 decoder_thread_.Stop(); |
527 } | 534 } |
528 | 535 |
529 decoder_.Destroy(); | 536 decoder_.Destroy(); |
530 state_ = kUninitialized; | 537 state_ = kUninitialized; |
531 } | 538 } |
532 | 539 |
| 540 void VaapiVideoDecodeAccelerator::Destroy() { |
| 541 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 542 Cleanup(); |
| 543 delete this; |
| 544 } |
| 545 |
533 void VaapiVideoDecodeAccelerator::OutputPicCallback(int32 input_id, | 546 void VaapiVideoDecodeAccelerator::OutputPicCallback(int32 input_id, |
534 int32 output_id) { | 547 int32 output_id) { |
535 TRACE_EVENT2("Video Decoder", "VAVDA::OutputPicCallback", | 548 TRACE_EVENT2("Video Decoder", "VAVDA::OutputPicCallback", |
536 "Input id", input_id, "Picture id", output_id); | 549 "Input id", input_id, "Picture id", output_id); |
537 DVLOG(4) << "Outputting picture, input id: " << input_id | 550 DVLOG(4) << "Outputting picture, input id: " << input_id |
538 << " output id: " << output_id; | 551 << " output id: " << output_id; |
539 | 552 |
540 // Forward the request to the main thread. | 553 // Forward the request to the main thread. |
541 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); | 554 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); |
542 message_loop_->PostTask(FROM_HERE, | 555 message_loop_->PostTask(FROM_HERE, base::Bind( |
543 base::Bind(&VaapiVideoDecodeAccelerator::SyncAndNotifyPictureReady, | 556 &VaapiVideoDecodeAccelerator::SyncAndNotifyPictureReady, weak_this_, |
544 this, input_id, output_id)); | 557 input_id, output_id)); |
545 } | 558 } |
OLD | NEW |