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, | |
66 size_t size) | 64 size_t size) |
67 : bitstream_buffer_id(bitstream_buffer_id), | 65 : bitstream_buffer_id(bitstream_buffer_id), |
68 timestamp(timestamp), | 66 timestamp(timestamp), |
69 width(width), | |
70 height(height), | |
71 size(size) {} | 67 size(size) {} |
72 | 68 |
73 RTCVideoDecoder::BufferData::BufferData() {} | 69 RTCVideoDecoder::BufferData::BufferData() {} |
74 | 70 |
75 RTCVideoDecoder::BufferData::~BufferData() {} | 71 RTCVideoDecoder::BufferData::~BufferData() {} |
76 | 72 |
77 RTCVideoDecoder::RTCVideoDecoder( | 73 RTCVideoDecoder::RTCVideoDecoder( |
78 const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories) | 74 const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories) |
79 : factories_(factories), | 75 : factories_(factories), |
80 decoder_texture_target_(0), | 76 decoder_texture_target_(0), |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
193 DLOG(ERROR) << "Missing or incomplete frames."; | 189 DLOG(ERROR) << "Missing or incomplete frames."; |
194 // Unlike the SW decoder in libvpx, hw decoder cannot handle broken frames. | 190 // Unlike the SW decoder in libvpx, hw decoder cannot handle broken frames. |
195 // Return an error to request a key frame. | 191 // Return an error to request a key frame. |
196 return WEBRTC_VIDEO_CODEC_ERROR; | 192 return WEBRTC_VIDEO_CODEC_ERROR; |
197 } | 193 } |
198 | 194 |
199 // Most platforms' VDA implementations support mid-stream resolution change | 195 // Most platforms' VDA implementations support mid-stream resolution change |
200 // internally. Platforms whose VDAs fail to support mid-stream resolution | 196 // internally. Platforms whose VDAs fail to support mid-stream resolution |
201 // change gracefully need to have their clients cover for them, and we do that | 197 // change gracefully need to have their clients cover for them, and we do that |
202 // here. | 198 // here. |
199 // Note this may not work because encoded size is not always available. | |
203 #ifdef ANDROID | 200 #ifdef ANDROID |
204 const bool kVDACanHandleMidstreamResize = false; | 201 const bool kVDACanHandleMidstreamResize = false; |
205 #else | 202 #else |
206 const bool kVDACanHandleMidstreamResize = true; | 203 const bool kVDACanHandleMidstreamResize = true; |
207 #endif | 204 #endif |
208 | 205 |
209 bool need_to_reset_for_midstream_resize = false; | 206 bool need_to_reset_for_midstream_resize = false; |
210 if (inputImage._frameType == webrtc::kKeyFrame) { | 207 if (inputImage._frameType == webrtc::kKeyFrame) { |
211 DVLOG(2) << "Got key frame. size=" << inputImage._encodedWidth << "x" | 208 DVLOG(2) << "Got key frame. size=" << inputImage._encodedWidth << "x" |
212 << inputImage._encodedHeight; | 209 << inputImage._encodedHeight; |
213 gfx::Size prev_frame_size = frame_size_; | 210 gfx::Size prev_frame_size = frame_size_; |
214 frame_size_.SetSize(inputImage._encodedWidth, inputImage._encodedHeight); | 211 frame_size_.SetSize(inputImage._encodedWidth, inputImage._encodedHeight); |
215 if (!kVDACanHandleMidstreamResize && !prev_frame_size.IsEmpty() && | 212 if (!kVDACanHandleMidstreamResize && !prev_frame_size.IsEmpty() && |
216 prev_frame_size != frame_size_) { | 213 prev_frame_size != frame_size_) { |
217 need_to_reset_for_midstream_resize = true; | 214 need_to_reset_for_midstream_resize = true; |
218 } | 215 } |
219 } else if (IsFirstBufferAfterReset(next_bitstream_buffer_id_, | 216 } else if (IsFirstBufferAfterReset(next_bitstream_buffer_id_, |
220 reset_bitstream_buffer_id_)) { | 217 reset_bitstream_buffer_id_)) { |
221 // TODO(wuchengli): VDA should handle it. Remove this when | 218 // TODO(wuchengli): VDA should handle it. Remove this when |
222 // http://crosbug.com/p/21913 is fixed. | 219 // http://crosbug.com/p/21913 is fixed. |
223 DVLOG(1) << "The first frame should be a key frame. Drop this."; | 220 DVLOG(1) << "The first frame should be a key frame. Drop this."; |
224 return WEBRTC_VIDEO_CODEC_ERROR; | 221 return WEBRTC_VIDEO_CODEC_ERROR; |
225 } | 222 } |
226 | 223 |
227 // Create buffer metadata. | 224 // Create buffer metadata. |
228 BufferData buffer_data(next_bitstream_buffer_id_, | 225 BufferData buffer_data(next_bitstream_buffer_id_, |
229 inputImage._timeStamp, | 226 inputImage._timeStamp, |
230 frame_size_.width(), | |
231 frame_size_.height(), | |
232 inputImage._length); | 227 inputImage._length); |
233 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. | 228 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. |
234 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & ID_LAST; | 229 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & ID_LAST; |
235 | 230 |
236 // If a shared memory segment is available, there are no pending buffers, and | 231 // If a shared memory segment is available, there are no pending buffers, and |
237 // this isn't a mid-stream resolution change, then send the buffer for decode | 232 // this isn't a mid-stream resolution change, then send the buffer for decode |
238 // immediately. Otherwise, save the buffer in the queue for later decode. | 233 // immediately. Otherwise, save the buffer in the queue for later decode. |
239 scoped_ptr<SHMBuffer> shm_buffer; | 234 scoped_ptr<SHMBuffer> shm_buffer; |
240 if (!need_to_reset_for_midstream_resize && pending_buffers_.size() == 0) | 235 if (!need_to_reset_for_midstream_resize && pending_buffers_.size() == 0) |
241 shm_buffer = GetSHM_Locked(inputImage._length); | 236 shm_buffer = GetSHM_Locked(inputImage._length); |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
357 | 352 |
358 std::map<int32, media::PictureBuffer>::iterator it = | 353 std::map<int32, media::PictureBuffer>::iterator it = |
359 assigned_picture_buffers_.find(picture.picture_buffer_id()); | 354 assigned_picture_buffers_.find(picture.picture_buffer_id()); |
360 if (it == assigned_picture_buffers_.end()) { | 355 if (it == assigned_picture_buffers_.end()) { |
361 NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id(); | 356 NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id(); |
362 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | 357 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); |
363 return; | 358 return; |
364 } | 359 } |
365 const media::PictureBuffer& pb = it->second; | 360 const media::PictureBuffer& pb = it->second; |
366 | 361 |
362 // Validate picture size from GPU | |
363 if (picture.size().IsEmpty() || | |
364 !gfx::Rect(pb.size()).Contains(gfx::Rect(picture.size()))) { | |
365 LOG(ERROR) << "Invalid picture size: " << pb.size().ToString() | |
366 << " from PictureBuffer, but " << picture.size().ToString() | |
367 << " from GPU"; | |
Pawel Osciak
2014/08/18 07:59:03
Perhaps:
"Invalid picture size from VDA: " << pb.
kcwu
2014/08/18 08:07:18
Done.
But you exchanged two sizes?
Pawel Osciak
2014/08/18 08:12:23
Ah yes, sorry. Should be the other way around.
| |
368 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | |
369 return; | |
370 } | |
371 | |
367 // Create a media::VideoFrame. | 372 // Create a media::VideoFrame. |
368 uint32_t timestamp = 0, width = 0, height = 0; | 373 uint32_t timestamp = 0; |
369 size_t size = 0; | 374 GetBufferData(picture.bitstream_buffer_id(), ×tamp); |
370 GetBufferData( | |
371 picture.bitstream_buffer_id(), ×tamp, &width, &height, &size); | |
372 scoped_refptr<media::VideoFrame> frame = | 375 scoped_refptr<media::VideoFrame> frame = |
373 CreateVideoFrame(picture, pb, timestamp, width, height, size); | 376 CreateVideoFrame(picture, pb, timestamp); |
374 bool inserted = | 377 bool inserted = |
375 picture_buffers_at_display_.insert(std::make_pair( | 378 picture_buffers_at_display_.insert(std::make_pair( |
376 picture.picture_buffer_id(), | 379 picture.picture_buffer_id(), |
377 pb.texture_id())).second; | 380 pb.texture_id())).second; |
378 DCHECK(inserted); | 381 DCHECK(inserted); |
379 | 382 |
380 // Create a WebRTC video frame. | 383 // Create a WebRTC video frame. |
381 webrtc::RefCountImpl<NativeHandleImpl>* handle = | 384 webrtc::RefCountImpl<NativeHandleImpl>* handle = |
382 new webrtc::RefCountImpl<NativeHandleImpl>(frame); | 385 new webrtc::RefCountImpl<NativeHandleImpl>(frame); |
383 webrtc::TextureVideoFrame decoded_image(handle, width, height, timestamp, 0); | 386 webrtc::TextureVideoFrame decoded_image( |
387 handle, picture.size().width(), picture.size().height(), timestamp, 0); | |
384 | 388 |
385 // Invoke decode callback. WebRTC expects no callback after Reset or Release. | 389 // Invoke decode callback. WebRTC expects no callback after Reset or Release. |
386 { | 390 { |
387 base::AutoLock auto_lock(lock_); | 391 base::AutoLock auto_lock(lock_); |
388 DCHECK(decode_complete_callback_ != NULL); | 392 DCHECK(decode_complete_callback_ != NULL); |
389 if (IsBufferAfterReset(picture.bitstream_buffer_id(), | 393 if (IsBufferAfterReset(picture.bitstream_buffer_id(), |
390 reset_bitstream_buffer_id_)) { | 394 reset_bitstream_buffer_id_)) { |
391 decode_complete_callback_->Decoded(decoded_image); | 395 decode_complete_callback_->Decoded(decoded_image); |
392 } | 396 } |
393 } | 397 } |
(...skipping 22 matching lines...) Expand all Loading... | |
416 visible_rect, | 420 visible_rect, |
417 pixels, | 421 pixels, |
418 &event))) | 422 &event))) |
419 return; | 423 return; |
420 event.Wait(); | 424 event.Wait(); |
421 } | 425 } |
422 | 426 |
423 scoped_refptr<media::VideoFrame> RTCVideoDecoder::CreateVideoFrame( | 427 scoped_refptr<media::VideoFrame> RTCVideoDecoder::CreateVideoFrame( |
424 const media::Picture& picture, | 428 const media::Picture& picture, |
425 const media::PictureBuffer& pb, | 429 const media::PictureBuffer& pb, |
426 uint32_t timestamp, | 430 uint32_t timestamp) { |
427 uint32_t width, | 431 gfx::Rect visible_rect(picture.size()); |
428 uint32_t height, | |
429 size_t size) { | |
430 gfx::Rect visible_rect(width, height); | |
431 DCHECK(decoder_texture_target_); | 432 DCHECK(decoder_texture_target_); |
432 // Convert timestamp from 90KHz to ms. | 433 // Convert timestamp from 90KHz to ms. |
433 base::TimeDelta timestamp_ms = base::TimeDelta::FromInternalValue( | 434 base::TimeDelta timestamp_ms = base::TimeDelta::FromInternalValue( |
434 base::checked_cast<uint64_t>(timestamp) * 1000 / 90); | 435 base::checked_cast<uint64_t>(timestamp) * 1000 / 90); |
435 return media::VideoFrame::WrapNativeTexture( | 436 return media::VideoFrame::WrapNativeTexture( |
436 make_scoped_ptr(new gpu::MailboxHolder( | 437 make_scoped_ptr(new gpu::MailboxHolder( |
437 pb.texture_mailbox(), decoder_texture_target_, 0)), | 438 pb.texture_mailbox(), decoder_texture_target_, 0)), |
438 media::BindToCurrentLoop(base::Bind(&RTCVideoDecoder::ReleaseMailbox, | 439 media::BindToCurrentLoop(base::Bind(&RTCVideoDecoder::ReleaseMailbox, |
439 weak_factory_.GetWeakPtr(), | 440 weak_factory_.GetWeakPtr(), |
440 factories_, | 441 factories_, |
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
770 // that's too small for some pathological B-frame test videos. The cost of | 771 // that's too small for some pathological B-frame test videos. The cost of |
771 // using too-high a value is low (192 bits per extra slot). | 772 // using too-high a value is low (192 bits per extra slot). |
772 static const size_t kMaxInputBufferDataSize = 128; | 773 static const size_t kMaxInputBufferDataSize = 128; |
773 // Pop from the back of the list, because that's the oldest and least likely | 774 // Pop from the back of the list, because that's the oldest and least likely |
774 // to be useful in the future data. | 775 // to be useful in the future data. |
775 if (input_buffer_data_.size() > kMaxInputBufferDataSize) | 776 if (input_buffer_data_.size() > kMaxInputBufferDataSize) |
776 input_buffer_data_.pop_back(); | 777 input_buffer_data_.pop_back(); |
777 } | 778 } |
778 | 779 |
779 void RTCVideoDecoder::GetBufferData(int32 bitstream_buffer_id, | 780 void RTCVideoDecoder::GetBufferData(int32 bitstream_buffer_id, |
780 uint32_t* timestamp, | 781 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(); | 782 for (std::list<BufferData>::iterator it = input_buffer_data_.begin(); |
785 it != input_buffer_data_.end(); | 783 it != input_buffer_data_.end(); |
786 ++it) { | 784 ++it) { |
787 if (it->bitstream_buffer_id != bitstream_buffer_id) | 785 if (it->bitstream_buffer_id != bitstream_buffer_id) |
788 continue; | 786 continue; |
789 *timestamp = it->timestamp; | 787 *timestamp = it->timestamp; |
790 *width = it->width; | |
791 *height = it->height; | |
792 return; | 788 return; |
793 } | 789 } |
794 NOTREACHED() << "Missing bitstream buffer id: " << bitstream_buffer_id; | 790 NOTREACHED() << "Missing bitstream buffer id: " << bitstream_buffer_id; |
795 } | 791 } |
796 | 792 |
797 int32_t RTCVideoDecoder::RecordInitDecodeUMA(int32_t status) { | 793 int32_t RTCVideoDecoder::RecordInitDecodeUMA(int32_t status) { |
798 // Logging boolean is enough to know if HW decoding has been used. Also, | 794 // Logging boolean is enough to know if HW decoding has been used. Also, |
799 // InitDecode is less likely to return an error so enum is not used here. | 795 // InitDecode is less likely to return an error so enum is not used here. |
800 bool sample = (status == WEBRTC_VIDEO_CODEC_OK) ? true : false; | 796 bool sample = (status == WEBRTC_VIDEO_CODEC_OK) ? true : false; |
801 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoDecoderInitDecodeSuccess", sample); | 797 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoDecoderInitDecodeSuccess", sample); |
802 return status; | 798 return status; |
803 } | 799 } |
804 | 800 |
805 void RTCVideoDecoder::DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent() | 801 void RTCVideoDecoder::DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent() |
806 const { | 802 const { |
807 DCHECK(factories_->GetTaskRunner()->BelongsToCurrentThread()); | 803 DCHECK(factories_->GetTaskRunner()->BelongsToCurrentThread()); |
808 } | 804 } |
809 | 805 |
810 } // namespace content | 806 } // namespace content |
OLD | NEW |