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/numerics/safe_conversions.h" | 12 #include "base/numerics/safe_conversions.h" |
13 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
14 #include "base/synchronization/waitable_event.h" | |
15 #include "base/task_runner_util.h" | 14 #include "base/task_runner_util.h" |
16 #include "content/child/child_thread.h" | 15 #include "content/child/child_thread.h" |
17 #include "content/renderer/media/native_handle_impl.h" | 16 #include "content/renderer/media/native_handle_impl.h" |
18 #include "media/base/bind_to_current_loop.h" | 17 #include "media/base/bind_to_current_loop.h" |
19 #include "media/filters/gpu_video_accelerator_factories.h" | 18 #include "media/filters/gpu_video_accelerator_factories.h" |
20 #include "third_party/skia/include/core/SkBitmap.h" | |
21 #include "third_party/webrtc/common_video/interface/texture_video_frame.h" | 19 #include "third_party/webrtc/common_video/interface/texture_video_frame.h" |
22 #include "third_party/webrtc/system_wrappers/interface/ref_count.h" | 20 #include "third_party/webrtc/system_wrappers/interface/ref_count.h" |
23 | 21 |
24 namespace content { | 22 namespace content { |
25 | 23 |
26 const int32 RTCVideoDecoder::ID_LAST = 0x3FFFFFFF; | 24 const int32 RTCVideoDecoder::ID_LAST = 0x3FFFFFFF; |
27 const int32 RTCVideoDecoder::ID_HALF = 0x20000000; | 25 const int32 RTCVideoDecoder::ID_HALF = 0x20000000; |
28 const int32 RTCVideoDecoder::ID_INVALID = -1; | 26 const int32 RTCVideoDecoder::ID_INVALID = -1; |
29 | 27 |
30 // Maximum number of concurrent VDA::Decode() operations RVD will maintain. | 28 // Maximum number of concurrent VDA::Decode() operations RVD will maintain. |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 decoder_texture_target_(0), | 78 decoder_texture_target_(0), |
81 next_picture_buffer_id_(0), | 79 next_picture_buffer_id_(0), |
82 state_(UNINITIALIZED), | 80 state_(UNINITIALIZED), |
83 decode_complete_callback_(NULL), | 81 decode_complete_callback_(NULL), |
84 num_shm_buffers_(0), | 82 num_shm_buffers_(0), |
85 next_bitstream_buffer_id_(0), | 83 next_bitstream_buffer_id_(0), |
86 reset_bitstream_buffer_id_(ID_INVALID), | 84 reset_bitstream_buffer_id_(ID_INVALID), |
87 weak_factory_(this) { | 85 weak_factory_(this) { |
88 DCHECK(!vda_task_runner_->BelongsToCurrentThread()); | 86 DCHECK(!vda_task_runner_->BelongsToCurrentThread()); |
89 weak_this_ = weak_factory_.GetWeakPtr(); | 87 weak_this_ = weak_factory_.GetWeakPtr(); |
| 88 |
| 89 base::WaitableEvent message_loop_async_waiter(false, false); |
| 90 // Waiting here is safe. The media thread is stopped in the child thread and |
| 91 // the child thread is blocked when VideoDecoderFactory::CreateVideoDecoder |
| 92 // runs. |
| 93 vda_task_runner_->PostTask(FROM_HERE, |
| 94 base::Bind(&RTCVideoDecoder::Initialize, |
| 95 base::Unretained(this), |
| 96 &message_loop_async_waiter)); |
| 97 message_loop_async_waiter.Wait(); |
90 } | 98 } |
91 | 99 |
92 RTCVideoDecoder::~RTCVideoDecoder() { | 100 RTCVideoDecoder::~RTCVideoDecoder() { |
93 DVLOG(2) << "~RTCVideoDecoder"; | 101 DVLOG(2) << "~RTCVideoDecoder"; |
94 DCHECK(vda_task_runner_->BelongsToCurrentThread()); | 102 // Destroy VDA and remove |this| from the observer if this is vda thread. |
95 DestroyVDA(); | 103 if (vda_task_runner_->BelongsToCurrentThread()) { |
| 104 base::MessageLoop::current()->RemoveDestructionObserver(this); |
| 105 DestroyVDA(); |
| 106 } else { |
| 107 // VDA should have been destroyed in WillDestroyCurrentMessageLoop. |
| 108 DCHECK(!vda_); |
| 109 } |
96 | 110 |
97 // Delete all shared memories. | 111 // Delete all shared memories. |
98 STLDeleteElements(&available_shm_segments_); | 112 STLDeleteElements(&available_shm_segments_); |
99 STLDeleteValues(&bitstream_buffers_in_decoder_); | 113 STLDeleteValues(&bitstream_buffers_in_decoder_); |
100 STLDeleteContainerPairFirstPointers(decode_buffers_.begin(), | 114 STLDeleteContainerPairFirstPointers(decode_buffers_.begin(), |
101 decode_buffers_.end()); | 115 decode_buffers_.end()); |
102 decode_buffers_.clear(); | 116 decode_buffers_.clear(); |
103 | 117 |
104 // Delete WebRTC input buffers. | 118 // Delete WebRTC input buffers. |
105 for (std::deque<std::pair<webrtc::EncodedImage, BufferData> >::iterator it = | 119 for (std::deque<std::pair<webrtc::EncodedImage, BufferData> >::iterator it = |
106 pending_buffers_.begin(); | 120 pending_buffers_.begin(); |
107 it != pending_buffers_.end(); | 121 it != pending_buffers_.end(); |
108 ++it) { | 122 ++it) { |
109 delete[] it->first._buffer; | 123 delete[] it->first._buffer; |
110 } | 124 } |
111 } | 125 } |
112 | 126 |
113 // static | |
114 scoped_ptr<RTCVideoDecoder> RTCVideoDecoder::Create( | 127 scoped_ptr<RTCVideoDecoder> RTCVideoDecoder::Create( |
115 webrtc::VideoCodecType type, | 128 webrtc::VideoCodecType type, |
116 const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories) { | 129 const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories) { |
117 scoped_ptr<RTCVideoDecoder> decoder; | 130 scoped_ptr<RTCVideoDecoder> decoder; |
118 // Convert WebRTC codec type to media codec profile. | 131 // Convert WebRTC codec type to media codec profile. |
119 media::VideoCodecProfile profile; | 132 media::VideoCodecProfile profile; |
120 switch (type) { | 133 switch (type) { |
121 case webrtc::kVideoCodecVP8: | 134 case webrtc::kVideoCodecVP8: |
122 profile = media::VP8PROFILE_MAIN; | 135 profile = media::VP8PROFILE_MAIN; |
123 break; | 136 break; |
124 default: | 137 default: |
125 DVLOG(2) << "Video codec not supported:" << type; | 138 DVLOG(2) << "Video codec not supported:" << type; |
126 return decoder.Pass(); | 139 return decoder.Pass(); |
127 } | 140 } |
128 | 141 |
129 base::WaitableEvent waiter(true, false); | |
130 decoder.reset(new RTCVideoDecoder(factories)); | 142 decoder.reset(new RTCVideoDecoder(factories)); |
131 decoder->vda_task_runner_->PostTask( | 143 decoder->vda_ = |
132 FROM_HERE, | 144 factories->CreateVideoDecodeAccelerator(profile, decoder.get()).Pass(); |
133 base::Bind(&RTCVideoDecoder::CreateVDA, | |
134 base::Unretained(decoder.get()), | |
135 profile, | |
136 &waiter)); | |
137 waiter.Wait(); | |
138 // vda can be NULL if VP8 is not supported. | 145 // vda can be NULL if VP8 is not supported. |
139 if (decoder->vda_ != NULL) { | 146 if (decoder->vda_ != NULL) { |
140 decoder->state_ = INITIALIZED; | 147 decoder->state_ = INITIALIZED; |
141 } else { | 148 } else { |
142 factories->GetTaskRunner()->DeleteSoon(FROM_HERE, decoder.release()); | 149 factories->GetTaskRunner()->DeleteSoon(FROM_HERE, decoder.release()); |
143 } | 150 } |
144 return decoder.Pass(); | 151 return decoder.Pass(); |
145 } | 152 } |
146 | 153 |
147 int32_t RTCVideoDecoder::InitDecode(const webrtc::VideoCodec* codecSettings, | 154 int32_t RTCVideoDecoder::InitDecode(const webrtc::VideoCodec* codecSettings, |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
392 { | 399 { |
393 base::AutoLock auto_lock(lock_); | 400 base::AutoLock auto_lock(lock_); |
394 DCHECK(decode_complete_callback_ != NULL); | 401 DCHECK(decode_complete_callback_ != NULL); |
395 if (IsBufferAfterReset(picture.bitstream_buffer_id(), | 402 if (IsBufferAfterReset(picture.bitstream_buffer_id(), |
396 reset_bitstream_buffer_id_)) { | 403 reset_bitstream_buffer_id_)) { |
397 decode_complete_callback_->Decoded(decoded_image); | 404 decode_complete_callback_->Decoded(decoded_image); |
398 } | 405 } |
399 } | 406 } |
400 } | 407 } |
401 | 408 |
402 static void ReadPixelsSyncInner( | |
403 const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories, | |
404 uint32 texture_id, | |
405 const gfx::Rect& visible_rect, | |
406 const SkBitmap& pixels, | |
407 base::WaitableEvent* event) { | |
408 factories->ReadPixels(texture_id, visible_rect, pixels); | |
409 event->Signal(); | |
410 } | |
411 | |
412 static void ReadPixelsSync( | |
413 const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories, | |
414 uint32 texture_id, | |
415 const gfx::Rect& visible_rect, | |
416 const SkBitmap& pixels) { | |
417 base::WaitableEvent event(true, false); | |
418 if (!factories->GetTaskRunner()->PostTask(FROM_HERE, | |
419 base::Bind(&ReadPixelsSyncInner, | |
420 factories, | |
421 texture_id, | |
422 visible_rect, | |
423 pixels, | |
424 &event))) | |
425 return; | |
426 event.Wait(); | |
427 } | |
428 | |
429 scoped_refptr<media::VideoFrame> RTCVideoDecoder::CreateVideoFrame( | 409 scoped_refptr<media::VideoFrame> RTCVideoDecoder::CreateVideoFrame( |
430 const media::Picture& picture, | 410 const media::Picture& picture, |
431 const media::PictureBuffer& pb, | 411 const media::PictureBuffer& pb, |
432 uint32_t timestamp, | 412 uint32_t timestamp, |
433 uint32_t width, | 413 uint32_t width, |
434 uint32_t height, | 414 uint32_t height, |
435 size_t size) { | 415 size_t size) { |
436 gfx::Rect visible_rect(width, height); | 416 gfx::Rect visible_rect(width, height); |
| 417 gfx::Size natural_size(width, height); |
437 DCHECK(decoder_texture_target_); | 418 DCHECK(decoder_texture_target_); |
438 // Convert timestamp from 90KHz to ms. | 419 // Convert timestamp from 90KHz to ms. |
439 base::TimeDelta timestamp_ms = base::TimeDelta::FromInternalValue( | 420 base::TimeDelta timestamp_ms = base::TimeDelta::FromInternalValue( |
440 base::checked_cast<uint64_t>(timestamp) * 1000 / 90); | 421 base::checked_cast<uint64_t>(timestamp) * 1000 / 90); |
441 return media::VideoFrame::WrapNativeTexture( | 422 return media::VideoFrame::WrapNativeTexture( |
442 make_scoped_ptr(new media::VideoFrame::MailboxHolder( | 423 make_scoped_ptr(new media::VideoFrame::MailboxHolder( |
443 pb.texture_mailbox(), | 424 pb.texture_mailbox(), |
444 0, // sync_point | 425 0, // sync_point |
445 media::BindToCurrentLoop( | 426 media::BindToCurrentLoop( |
446 base::Bind(&RTCVideoDecoder::ReusePictureBuffer, | 427 base::Bind(&RTCVideoDecoder::ReusePictureBuffer, |
447 weak_this_, | 428 weak_this_, |
448 picture.picture_buffer_id())))), | 429 picture.picture_buffer_id())))), |
449 decoder_texture_target_, | 430 decoder_texture_target_, |
450 pb.size(), | 431 pb.size(), |
451 visible_rect, | 432 visible_rect, |
452 visible_rect.size(), | 433 natural_size, |
453 timestamp_ms, | 434 timestamp_ms, |
454 base::Bind(&ReadPixelsSync, factories_, pb.texture_id(), visible_rect), | 435 base::Bind(&media::GpuVideoAcceleratorFactories::ReadPixels, |
| 436 factories_, |
| 437 pb.texture_id(), |
| 438 natural_size), |
455 base::Closure()); | 439 base::Closure()); |
456 } | 440 } |
457 | 441 |
458 void RTCVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) { | 442 void RTCVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) { |
459 DVLOG(3) << "NotifyEndOfBitstreamBuffer. id=" << id; | 443 DVLOG(3) << "NotifyEndOfBitstreamBuffer. id=" << id; |
460 DCHECK(vda_task_runner_->BelongsToCurrentThread()); | 444 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
461 | 445 |
462 std::map<int32, SHMBuffer*>::iterator it = | 446 std::map<int32, SHMBuffer*>::iterator it = |
463 bitstream_buffers_in_decoder_.find(id); | 447 bitstream_buffers_in_decoder_.find(id); |
464 if (it == bitstream_buffers_in_decoder_.end()) { | 448 if (it == bitstream_buffers_in_decoder_.end()) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
505 LOG(ERROR) << "VDA Error:" << error; | 489 LOG(ERROR) << "VDA Error:" << error; |
506 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoDecoderError", | 490 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoDecoderError", |
507 error, | 491 error, |
508 media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM); | 492 media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM); |
509 DestroyVDA(); | 493 DestroyVDA(); |
510 | 494 |
511 base::AutoLock auto_lock(lock_); | 495 base::AutoLock auto_lock(lock_); |
512 state_ = DECODE_ERROR; | 496 state_ = DECODE_ERROR; |
513 } | 497 } |
514 | 498 |
| 499 void RTCVideoDecoder::WillDestroyCurrentMessageLoop() { |
| 500 DVLOG(2) << "WillDestroyCurrentMessageLoop"; |
| 501 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
| 502 factories_->Abort(); |
| 503 weak_factory_.InvalidateWeakPtrs(); |
| 504 DestroyVDA(); |
| 505 } |
| 506 |
| 507 void RTCVideoDecoder::Initialize(base::WaitableEvent* waiter) { |
| 508 DVLOG(2) << "Initialize"; |
| 509 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
| 510 base::MessageLoop::current()->AddDestructionObserver(this); |
| 511 waiter->Signal(); |
| 512 } |
| 513 |
515 void RTCVideoDecoder::RequestBufferDecode() { | 514 void RTCVideoDecoder::RequestBufferDecode() { |
516 DCHECK(vda_task_runner_->BelongsToCurrentThread()); | 515 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
517 if (!vda_) | 516 if (!vda_) |
518 return; | 517 return; |
519 | 518 |
520 MovePendingBuffersToDecodeBuffers(); | 519 MovePendingBuffersToDecodeBuffers(); |
521 | 520 |
522 while (CanMoreDecodeWorkBeDone()) { | 521 while (CanMoreDecodeWorkBeDone()) { |
523 // Get a buffer and data from the queue. | 522 // Get a buffer and data from the queue. |
524 SHMBuffer* shm_buffer = NULL; | 523 SHMBuffer* shm_buffer = NULL; |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
664 factories_->DeleteTexture(it->second.texture_id()); | 663 factories_->DeleteTexture(it->second.texture_id()); |
665 dismissed_picture_buffers_.erase(it); | 664 dismissed_picture_buffers_.erase(it); |
666 return; | 665 return; |
667 } | 666 } |
668 | 667 |
669 factories_->WaitSyncPoint(sync_point); | 668 factories_->WaitSyncPoint(sync_point); |
670 | 669 |
671 vda_->ReusePictureBuffer(picture_buffer_id); | 670 vda_->ReusePictureBuffer(picture_buffer_id); |
672 } | 671 } |
673 | 672 |
674 void RTCVideoDecoder::CreateVDA(media::VideoCodecProfile profile, | |
675 base::WaitableEvent* waiter) { | |
676 DCHECK(vda_task_runner_->BelongsToCurrentThread()); | |
677 vda_ = factories_->CreateVideoDecodeAccelerator(profile, this); | |
678 waiter->Signal(); | |
679 } | |
680 | |
681 void RTCVideoDecoder::DestroyTextures() { | 673 void RTCVideoDecoder::DestroyTextures() { |
682 DCHECK(vda_task_runner_->BelongsToCurrentThread()); | 674 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
683 std::map<int32, media::PictureBuffer>::iterator it; | 675 std::map<int32, media::PictureBuffer>::iterator it; |
684 | 676 |
685 for (it = assigned_picture_buffers_.begin(); | 677 for (it = assigned_picture_buffers_.begin(); |
686 it != assigned_picture_buffers_.end(); | 678 it != assigned_picture_buffers_.end(); |
687 ++it) { | 679 ++it) { |
688 factories_->DeleteTexture(it->second.texture_id()); | 680 factories_->DeleteTexture(it->second.texture_id()); |
689 } | 681 } |
690 assigned_picture_buffers_.clear(); | 682 assigned_picture_buffers_.clear(); |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
786 | 778 |
787 int32_t RTCVideoDecoder::RecordInitDecodeUMA(int32_t status) { | 779 int32_t RTCVideoDecoder::RecordInitDecodeUMA(int32_t status) { |
788 // Logging boolean is enough to know if HW decoding has been used. Also, | 780 // Logging boolean is enough to know if HW decoding has been used. Also, |
789 // InitDecode is less likely to return an error so enum is not used here. | 781 // InitDecode is less likely to return an error so enum is not used here. |
790 bool sample = (status == WEBRTC_VIDEO_CODEC_OK) ? true : false; | 782 bool sample = (status == WEBRTC_VIDEO_CODEC_OK) ? true : false; |
791 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoDecoderInitDecodeSuccess", sample); | 783 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoDecoderInitDecodeSuccess", sample); |
792 return status; | 784 return status; |
793 } | 785 } |
794 | 786 |
795 } // namespace content | 787 } // namespace content |
OLD | NEW |