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" |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 const size_t size; | 54 const size_t size; |
55 }; | 55 }; |
56 | 56 |
57 RTCVideoDecoder::SHMBuffer::SHMBuffer(base::SharedMemory* shm, size_t size) | 57 RTCVideoDecoder::SHMBuffer::SHMBuffer(base::SharedMemory* shm, size_t size) |
58 : shm(shm), size(size) {} | 58 : shm(shm), size(size) {} |
59 | 59 |
60 RTCVideoDecoder::SHMBuffer::~SHMBuffer() { shm->Close(); } | 60 RTCVideoDecoder::SHMBuffer::~SHMBuffer() { shm->Close(); } |
61 | 61 |
62 RTCVideoDecoder::BufferData::BufferData(int32 bitstream_buffer_id, | 62 RTCVideoDecoder::BufferData::BufferData(int32 bitstream_buffer_id, |
63 uint32_t timestamp, | 63 uint32_t timestamp, |
| 64 int width, |
| 65 int height, |
64 size_t size) | 66 size_t size) |
65 : bitstream_buffer_id(bitstream_buffer_id), | 67 : bitstream_buffer_id(bitstream_buffer_id), |
66 timestamp(timestamp), | 68 timestamp(timestamp), |
| 69 width(width), |
| 70 height(height), |
67 size(size) {} | 71 size(size) {} |
68 | 72 |
69 RTCVideoDecoder::BufferData::BufferData() {} | 73 RTCVideoDecoder::BufferData::BufferData() {} |
70 | 74 |
71 RTCVideoDecoder::BufferData::~BufferData() {} | 75 RTCVideoDecoder::BufferData::~BufferData() {} |
72 | 76 |
73 RTCVideoDecoder::RTCVideoDecoder( | 77 RTCVideoDecoder::RTCVideoDecoder( |
74 const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories) | 78 const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories) |
75 : factories_(factories), | 79 : factories_(factories), |
76 decoder_texture_target_(0), | 80 decoder_texture_target_(0), |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 reset_bitstream_buffer_id_)) { | 220 reset_bitstream_buffer_id_)) { |
217 // TODO(wuchengli): VDA should handle it. Remove this when | 221 // TODO(wuchengli): VDA should handle it. Remove this when |
218 // http://crosbug.com/p/21913 is fixed. | 222 // http://crosbug.com/p/21913 is fixed. |
219 DVLOG(1) << "The first frame should be a key frame. Drop this."; | 223 DVLOG(1) << "The first frame should be a key frame. Drop this."; |
220 return WEBRTC_VIDEO_CODEC_ERROR; | 224 return WEBRTC_VIDEO_CODEC_ERROR; |
221 } | 225 } |
222 | 226 |
223 // Create buffer metadata. | 227 // Create buffer metadata. |
224 BufferData buffer_data(next_bitstream_buffer_id_, | 228 BufferData buffer_data(next_bitstream_buffer_id_, |
225 inputImage._timeStamp, | 229 inputImage._timeStamp, |
| 230 frame_size_.width(), |
| 231 frame_size_.height(), |
226 inputImage._length); | 232 inputImage._length); |
227 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. | 233 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. |
228 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & ID_LAST; | 234 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & ID_LAST; |
229 | 235 |
230 // If a shared memory segment is available, there are no pending buffers, and | 236 // If a shared memory segment is available, there are no pending buffers, and |
231 // this isn't a mid-stream resolution change, then send the buffer for decode | 237 // this isn't a mid-stream resolution change, then send the buffer for decode |
232 // immediately. Otherwise, save the buffer in the queue for later decode. | 238 // immediately. Otherwise, save the buffer in the queue for later decode. |
233 scoped_ptr<SHMBuffer> shm_buffer; | 239 scoped_ptr<SHMBuffer> shm_buffer; |
234 if (!need_to_reset_for_midstream_resize && pending_buffers_.size() == 0) | 240 if (!need_to_reset_for_midstream_resize && pending_buffers_.size() == 0) |
235 shm_buffer = GetSHM_Locked(inputImage._length); | 241 shm_buffer = GetSHM_Locked(inputImage._length); |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 | 357 |
352 std::map<int32, media::PictureBuffer>::iterator it = | 358 std::map<int32, media::PictureBuffer>::iterator it = |
353 assigned_picture_buffers_.find(picture.picture_buffer_id()); | 359 assigned_picture_buffers_.find(picture.picture_buffer_id()); |
354 if (it == assigned_picture_buffers_.end()) { | 360 if (it == assigned_picture_buffers_.end()) { |
355 NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id(); | 361 NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id(); |
356 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | 362 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); |
357 return; | 363 return; |
358 } | 364 } |
359 const media::PictureBuffer& pb = it->second; | 365 const media::PictureBuffer& pb = it->second; |
360 | 366 |
361 // Validate picture rectangle from GPU. | |
362 if (picture.visible_rect().IsEmpty() || | |
363 !gfx::Rect(pb.size()).Contains(picture.visible_rect())) { | |
364 NOTREACHED() << "Invalid picture size from VDA: " | |
365 << picture.visible_rect().ToString() << " should fit in " | |
366 << pb.size().ToString(); | |
367 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | |
368 return; | |
369 } | |
370 | |
371 // Create a media::VideoFrame. | 367 // Create a media::VideoFrame. |
372 uint32_t timestamp = 0; | 368 uint32_t timestamp = 0, width = 0, height = 0; |
373 GetBufferData(picture.bitstream_buffer_id(), ×tamp); | 369 size_t size = 0; |
| 370 GetBufferData( |
| 371 picture.bitstream_buffer_id(), ×tamp, &width, &height, &size); |
374 scoped_refptr<media::VideoFrame> frame = | 372 scoped_refptr<media::VideoFrame> frame = |
375 CreateVideoFrame(picture, pb, timestamp); | 373 CreateVideoFrame(picture, pb, timestamp, width, height, size); |
376 bool inserted = | 374 bool inserted = |
377 picture_buffers_at_display_.insert(std::make_pair( | 375 picture_buffers_at_display_.insert(std::make_pair( |
378 picture.picture_buffer_id(), | 376 picture.picture_buffer_id(), |
379 pb.texture_id())).second; | 377 pb.texture_id())).second; |
380 DCHECK(inserted); | 378 DCHECK(inserted); |
381 | 379 |
382 // Create a WebRTC video frame. | 380 // Create a WebRTC video frame. |
383 webrtc::RefCountImpl<NativeHandleImpl>* handle = | 381 webrtc::RefCountImpl<NativeHandleImpl>* handle = |
384 new webrtc::RefCountImpl<NativeHandleImpl>(frame); | 382 new webrtc::RefCountImpl<NativeHandleImpl>(frame); |
385 webrtc::TextureVideoFrame decoded_image(handle, | 383 webrtc::TextureVideoFrame decoded_image(handle, width, height, timestamp, 0); |
386 picture.visible_rect().width(), | |
387 picture.visible_rect().height(), | |
388 timestamp, | |
389 0); | |
390 | 384 |
391 // Invoke decode callback. WebRTC expects no callback after Reset or Release. | 385 // Invoke decode callback. WebRTC expects no callback after Reset or Release. |
392 { | 386 { |
393 base::AutoLock auto_lock(lock_); | 387 base::AutoLock auto_lock(lock_); |
394 DCHECK(decode_complete_callback_ != NULL); | 388 DCHECK(decode_complete_callback_ != NULL); |
395 if (IsBufferAfterReset(picture.bitstream_buffer_id(), | 389 if (IsBufferAfterReset(picture.bitstream_buffer_id(), |
396 reset_bitstream_buffer_id_)) { | 390 reset_bitstream_buffer_id_)) { |
397 decode_complete_callback_->Decoded(decoded_image); | 391 decode_complete_callback_->Decoded(decoded_image); |
398 } | 392 } |
399 } | 393 } |
(...skipping 22 matching lines...) Expand all Loading... |
422 visible_rect, | 416 visible_rect, |
423 pixels, | 417 pixels, |
424 &event))) | 418 &event))) |
425 return; | 419 return; |
426 event.Wait(); | 420 event.Wait(); |
427 } | 421 } |
428 | 422 |
429 scoped_refptr<media::VideoFrame> RTCVideoDecoder::CreateVideoFrame( | 423 scoped_refptr<media::VideoFrame> RTCVideoDecoder::CreateVideoFrame( |
430 const media::Picture& picture, | 424 const media::Picture& picture, |
431 const media::PictureBuffer& pb, | 425 const media::PictureBuffer& pb, |
432 uint32_t timestamp) { | 426 uint32_t timestamp, |
433 gfx::Rect visible_rect(picture.visible_rect()); | 427 uint32_t width, |
| 428 uint32_t height, |
| 429 size_t size) { |
| 430 gfx::Rect visible_rect(width, height); |
434 DCHECK(decoder_texture_target_); | 431 DCHECK(decoder_texture_target_); |
435 // Convert timestamp from 90KHz to ms. | 432 // Convert timestamp from 90KHz to ms. |
436 base::TimeDelta timestamp_ms = base::TimeDelta::FromInternalValue( | 433 base::TimeDelta timestamp_ms = base::TimeDelta::FromInternalValue( |
437 base::checked_cast<uint64_t>(timestamp) * 1000 / 90); | 434 base::checked_cast<uint64_t>(timestamp) * 1000 / 90); |
438 return media::VideoFrame::WrapNativeTexture( | 435 return media::VideoFrame::WrapNativeTexture( |
439 make_scoped_ptr(new gpu::MailboxHolder( | 436 make_scoped_ptr(new gpu::MailboxHolder( |
440 pb.texture_mailbox(), decoder_texture_target_, 0)), | 437 pb.texture_mailbox(), decoder_texture_target_, 0)), |
441 media::BindToCurrentLoop(base::Bind(&RTCVideoDecoder::ReleaseMailbox, | 438 media::BindToCurrentLoop(base::Bind(&RTCVideoDecoder::ReleaseMailbox, |
442 weak_factory_.GetWeakPtr(), | 439 weak_factory_.GetWeakPtr(), |
443 factories_, | 440 factories_, |
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
773 // that's too small for some pathological B-frame test videos. The cost of | 770 // that's too small for some pathological B-frame test videos. The cost of |
774 // using too-high a value is low (192 bits per extra slot). | 771 // using too-high a value is low (192 bits per extra slot). |
775 static const size_t kMaxInputBufferDataSize = 128; | 772 static const size_t kMaxInputBufferDataSize = 128; |
776 // Pop from the back of the list, because that's the oldest and least likely | 773 // Pop from the back of the list, because that's the oldest and least likely |
777 // to be useful in the future data. | 774 // to be useful in the future data. |
778 if (input_buffer_data_.size() > kMaxInputBufferDataSize) | 775 if (input_buffer_data_.size() > kMaxInputBufferDataSize) |
779 input_buffer_data_.pop_back(); | 776 input_buffer_data_.pop_back(); |
780 } | 777 } |
781 | 778 |
782 void RTCVideoDecoder::GetBufferData(int32 bitstream_buffer_id, | 779 void RTCVideoDecoder::GetBufferData(int32 bitstream_buffer_id, |
783 uint32_t* timestamp) { | 780 uint32_t* timestamp, |
| 781 uint32_t* width, |
| 782 uint32_t* height, |
| 783 size_t* size) { |
784 for (std::list<BufferData>::iterator it = input_buffer_data_.begin(); | 784 for (std::list<BufferData>::iterator it = input_buffer_data_.begin(); |
785 it != input_buffer_data_.end(); | 785 it != input_buffer_data_.end(); |
786 ++it) { | 786 ++it) { |
787 if (it->bitstream_buffer_id != bitstream_buffer_id) | 787 if (it->bitstream_buffer_id != bitstream_buffer_id) |
788 continue; | 788 continue; |
789 *timestamp = it->timestamp; | 789 *timestamp = it->timestamp; |
| 790 *width = it->width; |
| 791 *height = it->height; |
790 return; | 792 return; |
791 } | 793 } |
792 NOTREACHED() << "Missing bitstream buffer id: " << bitstream_buffer_id; | 794 NOTREACHED() << "Missing bitstream buffer id: " << bitstream_buffer_id; |
793 } | 795 } |
794 | 796 |
795 int32_t RTCVideoDecoder::RecordInitDecodeUMA(int32_t status) { | 797 int32_t RTCVideoDecoder::RecordInitDecodeUMA(int32_t status) { |
796 // Logging boolean is enough to know if HW decoding has been used. Also, | 798 // Logging boolean is enough to know if HW decoding has been used. Also, |
797 // InitDecode is less likely to return an error so enum is not used here. | 799 // InitDecode is less likely to return an error so enum is not used here. |
798 bool sample = (status == WEBRTC_VIDEO_CODEC_OK) ? true : false; | 800 bool sample = (status == WEBRTC_VIDEO_CODEC_OK) ? true : false; |
799 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoDecoderInitDecodeSuccess", sample); | 801 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoDecoderInitDecodeSuccess", sample); |
800 return status; | 802 return status; |
801 } | 803 } |
802 | 804 |
803 void RTCVideoDecoder::DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent() | 805 void RTCVideoDecoder::DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent() |
804 const { | 806 const { |
805 DCHECK(factories_->GetTaskRunner()->BelongsToCurrentThread()); | 807 DCHECK(factories_->GetTaskRunner()->BelongsToCurrentThread()); |
806 } | 808 } |
807 | 809 |
808 } // namespace content | 810 } // namespace content |
OLD | NEW |