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