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