Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/renderer/media/rtc_video_decoder.h" | 5 #include "content/renderer/media/rtc_video_decoder.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/memory/ref_counted.h" | 9 #include "base/memory/ref_counted.h" |
| 10 #include "base/message_loop/message_loop_proxy.h" | 10 #include "base/message_loop/message_loop_proxy.h" |
| 11 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 12 #include "base/safe_numerics.h" | 12 #include "base/safe_numerics.h" |
| 13 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
| 14 #include "base/synchronization/waitable_event.h" | |
| 14 #include "base/task_runner_util.h" | 15 #include "base/task_runner_util.h" |
| 15 #include "content/child/child_thread.h" | 16 #include "content/child/child_thread.h" |
| 16 #include "content/renderer/media/native_handle_impl.h" | 17 #include "content/renderer/media/native_handle_impl.h" |
| 17 #include "media/base/bind_to_loop.h" | 18 #include "media/base/bind_to_loop.h" |
| 18 #include "media/filters/gpu_video_accelerator_factories.h" | 19 #include "media/filters/gpu_video_accelerator_factories.h" |
| 20 #include "third_party/skia/include/core/SkBitmap.h" | |
| 19 #include "third_party/webrtc/common_video/interface/texture_video_frame.h" | 21 #include "third_party/webrtc/common_video/interface/texture_video_frame.h" |
| 20 #include "third_party/webrtc/system_wrappers/interface/ref_count.h" | 22 #include "third_party/webrtc/system_wrappers/interface/ref_count.h" |
| 21 | 23 |
| 22 namespace content { | 24 namespace content { |
| 23 | 25 |
| 24 const int32 RTCVideoDecoder::ID_LAST = 0x3FFFFFFF; | 26 const int32 RTCVideoDecoder::ID_LAST = 0x3FFFFFFF; |
| 25 const int32 RTCVideoDecoder::ID_HALF = 0x20000000; | 27 const int32 RTCVideoDecoder::ID_HALF = 0x20000000; |
| 26 const int32 RTCVideoDecoder::ID_INVALID = -1; | 28 const int32 RTCVideoDecoder::ID_INVALID = -1; |
| 27 | 29 |
| 28 // Maximum number of concurrent VDA::Decode() operations RVD will maintain. | 30 // Maximum number of concurrent VDA::Decode() operations RVD will maintain. |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 76 : weak_factory_(this), | 78 : weak_factory_(this), |
| 77 weak_this_(weak_factory_.GetWeakPtr()), | 79 weak_this_(weak_factory_.GetWeakPtr()), |
| 78 factories_(factories), | 80 factories_(factories), |
| 79 vda_loop_proxy_(factories->GetMessageLoop()), | 81 vda_loop_proxy_(factories->GetMessageLoop()), |
| 80 decoder_texture_target_(0), | 82 decoder_texture_target_(0), |
| 81 next_picture_buffer_id_(0), | 83 next_picture_buffer_id_(0), |
| 82 state_(UNINITIALIZED), | 84 state_(UNINITIALIZED), |
| 83 decode_complete_callback_(NULL), | 85 decode_complete_callback_(NULL), |
| 84 num_shm_buffers_(0), | 86 num_shm_buffers_(0), |
| 85 next_bitstream_buffer_id_(0), | 87 next_bitstream_buffer_id_(0), |
| 86 reset_bitstream_buffer_id_(ID_INVALID) { | 88 reset_bitstream_buffer_id_(ID_INVALID) {} |
| 87 DCHECK(!vda_loop_proxy_->BelongsToCurrentThread()); | |
| 88 base::WaitableEvent message_loop_async_waiter(false, false); | |
| 89 // Waiting here is safe. The media thread is stopped in the child thread and | |
| 90 // the child thread is blocked when VideoDecoderFactory::CreateVideoDecoder | |
| 91 // runs. | |
| 92 vda_loop_proxy_->PostTask(FROM_HERE, | |
| 93 base::Bind(&RTCVideoDecoder::Initialize, | |
| 94 base::Unretained(this), | |
| 95 &message_loop_async_waiter)); | |
| 96 message_loop_async_waiter.Wait(); | |
| 97 } | |
| 98 | 89 |
| 99 RTCVideoDecoder::~RTCVideoDecoder() { | 90 RTCVideoDecoder::~RTCVideoDecoder() { |
| 100 DVLOG(2) << "~RTCVideoDecoder"; | 91 DVLOG(2) << "~RTCVideoDecoder"; |
| 101 // Destroy VDA and remove |this| from the observer if this is vda thread. | 92 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); |
| 102 if (vda_loop_proxy_->BelongsToCurrentThread()) { | 93 DestroyVDA(); |
| 103 base::MessageLoop::current()->RemoveDestructionObserver(this); | |
| 104 DestroyVDA(); | |
| 105 } else { | |
| 106 // VDA should have been destroyed in WillDestroyCurrentMessageLoop. | |
| 107 DCHECK(!vda_); | |
| 108 } | |
| 109 | 94 |
| 110 // Delete all shared memories. | 95 // Delete all shared memories. |
| 111 STLDeleteElements(&available_shm_segments_); | 96 STLDeleteElements(&available_shm_segments_); |
| 112 STLDeleteValues(&bitstream_buffers_in_decoder_); | 97 STLDeleteValues(&bitstream_buffers_in_decoder_); |
| 113 STLDeleteContainerPairFirstPointers(decode_buffers_.begin(), | 98 STLDeleteContainerPairFirstPointers(decode_buffers_.begin(), |
| 114 decode_buffers_.end()); | 99 decode_buffers_.end()); |
| 115 decode_buffers_.clear(); | 100 decode_buffers_.clear(); |
| 116 | 101 |
| 117 // Delete WebRTC input buffers. | 102 // Delete WebRTC input buffers. |
| 118 for (std::deque<std::pair<webrtc::EncodedImage, BufferData> >::iterator it = | 103 for (std::deque<std::pair<webrtc::EncodedImage, BufferData> >::iterator it = |
| 119 pending_buffers_.begin(); | 104 pending_buffers_.begin(); |
| 120 it != pending_buffers_.end(); | 105 it != pending_buffers_.end(); |
| 121 ++it) { | 106 ++it) { |
| 122 delete[] it->first._buffer; | 107 delete[] it->first._buffer; |
| 123 } | 108 } |
| 124 } | 109 } |
| 125 | 110 |
| 111 // static | |
| 126 scoped_ptr<RTCVideoDecoder> RTCVideoDecoder::Create( | 112 scoped_ptr<RTCVideoDecoder> RTCVideoDecoder::Create( |
| 127 webrtc::VideoCodecType type, | 113 webrtc::VideoCodecType type, |
| 128 const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories) { | 114 const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories) { |
| 129 scoped_ptr<RTCVideoDecoder> decoder; | 115 scoped_ptr<RTCVideoDecoder> decoder; |
| 130 // Convert WebRTC codec type to media codec profile. | 116 // Convert WebRTC codec type to media codec profile. |
| 131 media::VideoCodecProfile profile; | 117 media::VideoCodecProfile profile; |
| 132 switch (type) { | 118 switch (type) { |
| 133 case webrtc::kVideoCodecVP8: | 119 case webrtc::kVideoCodecVP8: |
| 134 profile = media::VP8PROFILE_MAIN; | 120 profile = media::VP8PROFILE_MAIN; |
| 135 break; | 121 break; |
| 136 default: | 122 default: |
| 137 DVLOG(2) << "Video codec not supported:" << type; | 123 DVLOG(2) << "Video codec not supported:" << type; |
| 138 return decoder.Pass(); | 124 return decoder.Pass(); |
| 139 } | 125 } |
| 140 | 126 |
| 127 base::WaitableEvent waiter(true, false); | |
| 141 decoder.reset(new RTCVideoDecoder(factories)); | 128 decoder.reset(new RTCVideoDecoder(factories)); |
| 142 decoder->vda_ = | 129 decoder->vda_loop_proxy_->PostTask(FROM_HERE, |
| 143 factories->CreateVideoDecodeAccelerator(profile, decoder.get()).Pass(); | 130 base::Bind(&RTCVideoDecoder::CreateVDA, |
| 131 base::Unretained(decoder.get()), | |
| 132 profile, | |
| 133 &waiter)); | |
| 134 waiter.Wait(); | |
|
jam
2013/10/28 20:11:08
is this running on the main thread?
sheu
2013/10/28 20:32:58
It's running on WebRtc's main thread, which I beli
Ami GONE FROM CHROMIUM
2013/10/28 20:38:22
No, it's not. RTCVideoDecoder::Create() is called
jam
2013/10/28 20:43:25
ah ok, good to hear, thanks
| |
| 144 // vda can be NULL if VP8 is not supported. | 135 // vda can be NULL if VP8 is not supported. |
| 145 if (decoder->vda_ != NULL) { | 136 if (decoder->vda_ != NULL) { |
| 146 decoder->state_ = INITIALIZED; | 137 decoder->state_ = INITIALIZED; |
| 147 } else { | 138 } else { |
| 148 factories->GetMessageLoop()->DeleteSoon(FROM_HERE, decoder.release()); | 139 factories->GetMessageLoop()->DeleteSoon(FROM_HERE, decoder.release()); |
| 149 } | 140 } |
| 150 return decoder.Pass(); | 141 return decoder.Pass(); |
| 151 } | 142 } |
| 152 | 143 |
| 153 int32_t RTCVideoDecoder::InitDecode(const webrtc::VideoCodec* codecSettings, | 144 int32_t RTCVideoDecoder::InitDecode(const webrtc::VideoCodec* codecSettings, |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 399 0, // sync_point | 390 0, // sync_point |
| 400 media::BindToCurrentLoop( | 391 media::BindToCurrentLoop( |
| 401 base::Bind(&RTCVideoDecoder::ReusePictureBuffer, | 392 base::Bind(&RTCVideoDecoder::ReusePictureBuffer, |
| 402 weak_this_, | 393 weak_this_, |
| 403 picture.picture_buffer_id()))), | 394 picture.picture_buffer_id()))), |
| 404 decoder_texture_target_, | 395 decoder_texture_target_, |
| 405 pb.size(), | 396 pb.size(), |
| 406 visible_rect, | 397 visible_rect, |
| 407 natural_size, | 398 natural_size, |
| 408 timestamp_ms, | 399 timestamp_ms, |
| 409 base::Bind(&media::GpuVideoAcceleratorFactories::ReadPixels, | 400 media::BindToLoopSync( |
| 410 factories_, | 401 factories_->GetMessageLoop(), |
| 411 pb.texture_id(), | 402 base::Bind(&media::GpuVideoAcceleratorFactories::ReadPixels, |
| 412 natural_size), | 403 factories_, |
| 404 pb.texture_id(), | |
| 405 natural_size)), | |
| 413 base::Closure()); | 406 base::Closure()); |
| 414 } | 407 } |
| 415 | 408 |
| 416 void RTCVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) { | 409 void RTCVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) { |
| 417 DVLOG(3) << "NotifyEndOfBitstreamBuffer. id=" << id; | 410 DVLOG(3) << "NotifyEndOfBitstreamBuffer. id=" << id; |
| 418 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 411 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); |
| 419 | 412 |
| 420 std::map<int32, SHMBuffer*>::iterator it = | 413 std::map<int32, SHMBuffer*>::iterator it = |
| 421 bitstream_buffers_in_decoder_.find(id); | 414 bitstream_buffers_in_decoder_.find(id); |
| 422 if (it == bitstream_buffers_in_decoder_.end()) { | 415 if (it == bitstream_buffers_in_decoder_.end()) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 463 LOG(ERROR) << "VDA Error:" << error; | 456 LOG(ERROR) << "VDA Error:" << error; |
| 464 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoDecoderError", | 457 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoDecoderError", |
| 465 error, | 458 error, |
| 466 media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM); | 459 media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM); |
| 467 DestroyVDA(); | 460 DestroyVDA(); |
| 468 | 461 |
| 469 base::AutoLock auto_lock(lock_); | 462 base::AutoLock auto_lock(lock_); |
| 470 state_ = DECODE_ERROR; | 463 state_ = DECODE_ERROR; |
| 471 } | 464 } |
| 472 | 465 |
| 473 void RTCVideoDecoder::WillDestroyCurrentMessageLoop() { | |
| 474 DVLOG(2) << "WillDestroyCurrentMessageLoop"; | |
| 475 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
| 476 factories_->Abort(); | |
| 477 weak_factory_.InvalidateWeakPtrs(); | |
| 478 DestroyVDA(); | |
| 479 } | |
| 480 | |
| 481 void RTCVideoDecoder::Initialize(base::WaitableEvent* waiter) { | |
| 482 DVLOG(2) << "Initialize"; | |
| 483 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
| 484 base::MessageLoop::current()->AddDestructionObserver(this); | |
| 485 waiter->Signal(); | |
| 486 } | |
| 487 | |
| 488 void RTCVideoDecoder::RequestBufferDecode() { | 466 void RTCVideoDecoder::RequestBufferDecode() { |
| 489 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 467 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); |
| 490 if (!vda_) | 468 if (!vda_) |
| 491 return; | 469 return; |
| 492 | 470 |
| 493 MovePendingBuffersToDecodeBuffers(); | 471 MovePendingBuffersToDecodeBuffers(); |
| 494 | 472 |
| 495 while (CanMoreDecodeWorkBeDone()) { | 473 while (CanMoreDecodeWorkBeDone()) { |
| 496 // Get a buffer and data from the queue. | 474 // Get a buffer and data from the queue. |
| 497 SHMBuffer* shm_buffer = NULL; | 475 SHMBuffer* shm_buffer = NULL; |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 637 factories_->DeleteTexture(it->second.texture_id()); | 615 factories_->DeleteTexture(it->second.texture_id()); |
| 638 dismissed_picture_buffers_.erase(it); | 616 dismissed_picture_buffers_.erase(it); |
| 639 return; | 617 return; |
| 640 } | 618 } |
| 641 | 619 |
| 642 factories_->WaitSyncPoint(sync_point); | 620 factories_->WaitSyncPoint(sync_point); |
| 643 | 621 |
| 644 vda_->ReusePictureBuffer(picture_buffer_id); | 622 vda_->ReusePictureBuffer(picture_buffer_id); |
| 645 } | 623 } |
| 646 | 624 |
| 625 void RTCVideoDecoder::CreateVDA(media::VideoCodecProfile profile, | |
| 626 base::WaitableEvent* waiter) { | |
| 627 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
| 628 vda_ = factories_->CreateVideoDecodeAccelerator(profile, this); | |
| 629 waiter->Signal(); | |
| 630 } | |
| 631 | |
| 647 void RTCVideoDecoder::DestroyTextures() { | 632 void RTCVideoDecoder::DestroyTextures() { |
| 648 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 633 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); |
| 649 std::map<int32, media::PictureBuffer>::iterator it; | 634 std::map<int32, media::PictureBuffer>::iterator it; |
| 650 | 635 |
| 651 for (it = assigned_picture_buffers_.begin(); | 636 for (it = assigned_picture_buffers_.begin(); |
| 652 it != assigned_picture_buffers_.end(); | 637 it != assigned_picture_buffers_.end(); |
| 653 ++it) { | 638 ++it) { |
| 654 factories_->DeleteTexture(it->second.texture_id()); | 639 factories_->DeleteTexture(it->second.texture_id()); |
| 655 } | 640 } |
| 656 assigned_picture_buffers_.clear(); | 641 assigned_picture_buffers_.clear(); |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 752 | 737 |
| 753 int32_t RTCVideoDecoder::RecordInitDecodeUMA(int32_t status) { | 738 int32_t RTCVideoDecoder::RecordInitDecodeUMA(int32_t status) { |
| 754 // Logging boolean is enough to know if HW decoding has been used. Also, | 739 // Logging boolean is enough to know if HW decoding has been used. Also, |
| 755 // InitDecode is less likely to return an error so enum is not used here. | 740 // InitDecode is less likely to return an error so enum is not used here. |
| 756 bool sample = (status == WEBRTC_VIDEO_CODEC_OK) ? true : false; | 741 bool sample = (status == WEBRTC_VIDEO_CODEC_OK) ? true : false; |
| 757 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoDecoderInitDecodeSuccess", sample); | 742 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoDecoderInitDecodeSuccess", sample); |
| 758 return status; | 743 return status; |
| 759 } | 744 } |
| 760 | 745 |
| 761 } // namespace content | 746 } // namespace content |
| OLD | NEW |