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 |