Chromium Code Reviews| 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 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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. |
| 203 #ifdef ANDROID | 199 #ifdef ANDROID |
| 204 const bool kVDACanHandleMidstreamResize = false; | 200 const bool kVDACanHandleMidstreamResize = false; |
| 205 #else | 201 #else |
| 206 const bool kVDACanHandleMidstreamResize = true; | 202 const bool kVDACanHandleMidstreamResize = true; |
| 207 #endif | 203 #endif |
| 208 | 204 |
| 209 bool need_to_reset_for_midstream_resize = false; | 205 bool need_to_reset_for_midstream_resize = false; |
| 210 if (inputImage._frameType == webrtc::kKeyFrame) { | 206 if (inputImage._frameType == webrtc::kKeyFrame) { |
| 211 DVLOG(2) << "Got key frame. size=" << inputImage._encodedWidth << "x" | 207 // TODO(kcwu): What if VDA cannot handle mid stream resize and |
| 212 << inputImage._encodedHeight; | 208 // encoded size is unknown?? |
|
Pawel Osciak
2014/08/10 00:02:21
s/??/?/
Not sure what you mean here, VDA will alw
kcwu
2014/08/12 03:50:47
1. Should I still use client provided size if avai
Pawel Osciak
2014/08/12 04:05:07
Given that some vdas can't provide visible size, I
kcwu
2014/08/12 04:48:06
Okay, then should I leave comment here to indicate
Pawel Osciak
2014/08/12 04:59:24
Yes please.
| |
| 213 gfx::Size prev_frame_size = frame_size_; | 209 if (inputImage._encodedWidth && inputImage._encodedHeight) { |
| 214 frame_size_.SetSize(inputImage._encodedWidth, inputImage._encodedHeight); | 210 DVLOG(2) << "Got key frame. size=" << inputImage._encodedWidth << "x" |
| 215 if (!kVDACanHandleMidstreamResize && !prev_frame_size.IsEmpty() && | 211 << inputImage._encodedHeight; |
| 216 prev_frame_size != frame_size_) { | 212 gfx::Size prev_frame_size = frame_size_; |
| 217 need_to_reset_for_midstream_resize = true; | 213 frame_size_.SetSize(inputImage._encodedWidth, inputImage._encodedHeight); |
| 214 if (!kVDACanHandleMidstreamResize && !prev_frame_size.IsEmpty() && | |
| 215 prev_frame_size != frame_size_) { | |
| 216 need_to_reset_for_midstream_resize = true; | |
| 217 } | |
| 218 } | 218 } |
| 219 } else if (IsFirstBufferAfterReset(next_bitstream_buffer_id_, | 219 } else if (IsFirstBufferAfterReset(next_bitstream_buffer_id_, |
| 220 reset_bitstream_buffer_id_)) { | 220 reset_bitstream_buffer_id_)) { |
| 221 // TODO(wuchengli): VDA should handle it. Remove this when | 221 // TODO(wuchengli): VDA should handle it. Remove this when |
| 222 // http://crosbug.com/p/21913 is fixed. | 222 // http://crosbug.com/p/21913 is fixed. |
| 223 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."; |
| 224 return WEBRTC_VIDEO_CODEC_ERROR; | 224 return WEBRTC_VIDEO_CODEC_ERROR; |
| 225 } | 225 } |
| 226 | 226 |
| 227 // Create buffer metadata. | 227 // Create buffer metadata. |
| 228 BufferData buffer_data(next_bitstream_buffer_id_, | 228 BufferData buffer_data(next_bitstream_buffer_id_, |
| 229 inputImage._timeStamp, | 229 inputImage._timeStamp, |
| 230 frame_size_.width(), | |
| 231 frame_size_.height(), | |
| 232 inputImage._length); | 230 inputImage._length); |
| 233 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. | 231 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. |
| 234 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & ID_LAST; | 232 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & ID_LAST; |
| 235 | 233 |
| 236 // If a shared memory segment is available, there are no pending buffers, and | 234 // 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 | 235 // 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. | 236 // immediately. Otherwise, save the buffer in the queue for later decode. |
| 239 scoped_ptr<SHMBuffer> shm_buffer; | 237 scoped_ptr<SHMBuffer> shm_buffer; |
| 240 if (!need_to_reset_for_midstream_resize && pending_buffers_.size() == 0) | 238 if (!need_to_reset_for_midstream_resize && pending_buffers_.size() == 0) |
| 241 shm_buffer = GetSHM_Locked(inputImage._length); | 239 shm_buffer = GetSHM_Locked(inputImage._length); |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 358 std::map<int32, media::PictureBuffer>::iterator it = | 356 std::map<int32, media::PictureBuffer>::iterator it = |
| 359 assigned_picture_buffers_.find(picture.picture_buffer_id()); | 357 assigned_picture_buffers_.find(picture.picture_buffer_id()); |
| 360 if (it == assigned_picture_buffers_.end()) { | 358 if (it == assigned_picture_buffers_.end()) { |
| 361 NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id(); | 359 NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id(); |
| 362 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | 360 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); |
| 363 return; | 361 return; |
| 364 } | 362 } |
| 365 const media::PictureBuffer& pb = it->second; | 363 const media::PictureBuffer& pb = it->second; |
| 366 | 364 |
| 367 // Create a media::VideoFrame. | 365 // Create a media::VideoFrame. |
| 368 uint32_t timestamp = 0, width = 0, height = 0; | 366 uint32_t timestamp = 0; |
| 369 size_t size = 0; | 367 size_t size = 0; |
| 370 GetBufferData( | 368 GetBufferData( |
| 371 picture.bitstream_buffer_id(), ×tamp, &width, &height, &size); | 369 picture.bitstream_buffer_id(), ×tamp); |
| 372 scoped_refptr<media::VideoFrame> frame = | 370 scoped_refptr<media::VideoFrame> frame = |
| 373 CreateVideoFrame(picture, pb, timestamp, width, height, size); | 371 CreateVideoFrame(picture, pb, timestamp, size); |
| 374 bool inserted = | 372 bool inserted = |
| 375 picture_buffers_at_display_.insert(std::make_pair( | 373 picture_buffers_at_display_.insert(std::make_pair( |
| 376 picture.picture_buffer_id(), | 374 picture.picture_buffer_id(), |
| 377 pb.texture_id())).second; | 375 pb.texture_id())).second; |
| 378 DCHECK(inserted); | 376 DCHECK(inserted); |
| 379 | 377 |
| 380 // Create a WebRTC video frame. | 378 // Create a WebRTC video frame. |
| 381 webrtc::RefCountImpl<NativeHandleImpl>* handle = | 379 webrtc::RefCountImpl<NativeHandleImpl>* handle = |
| 382 new webrtc::RefCountImpl<NativeHandleImpl>(frame); | 380 new webrtc::RefCountImpl<NativeHandleImpl>(frame); |
| 383 webrtc::TextureVideoFrame decoded_image(handle, width, height, timestamp, 0); | 381 webrtc::TextureVideoFrame decoded_image(handle, |
| 382 picture.size().width(), | |
| 383 picture.size().height(), | |
| 384 timestamp, | |
| 385 0); | |
| 384 | 386 |
| 385 // Invoke decode callback. WebRTC expects no callback after Reset or Release. | 387 // Invoke decode callback. WebRTC expects no callback after Reset or Release. |
| 386 { | 388 { |
| 387 base::AutoLock auto_lock(lock_); | 389 base::AutoLock auto_lock(lock_); |
| 388 DCHECK(decode_complete_callback_ != NULL); | 390 DCHECK(decode_complete_callback_ != NULL); |
| 389 if (IsBufferAfterReset(picture.bitstream_buffer_id(), | 391 if (IsBufferAfterReset(picture.bitstream_buffer_id(), |
| 390 reset_bitstream_buffer_id_)) { | 392 reset_bitstream_buffer_id_)) { |
| 391 decode_complete_callback_->Decoded(decoded_image); | 393 decode_complete_callback_->Decoded(decoded_image); |
| 392 } | 394 } |
| 393 } | 395 } |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 417 pixels, | 419 pixels, |
| 418 &event))) | 420 &event))) |
| 419 return; | 421 return; |
| 420 event.Wait(); | 422 event.Wait(); |
| 421 } | 423 } |
| 422 | 424 |
| 423 scoped_refptr<media::VideoFrame> RTCVideoDecoder::CreateVideoFrame( | 425 scoped_refptr<media::VideoFrame> RTCVideoDecoder::CreateVideoFrame( |
| 424 const media::Picture& picture, | 426 const media::Picture& picture, |
| 425 const media::PictureBuffer& pb, | 427 const media::PictureBuffer& pb, |
| 426 uint32_t timestamp, | 428 uint32_t timestamp, |
| 427 uint32_t width, | |
| 428 uint32_t height, | |
| 429 size_t size) { | 429 size_t size) { |
| 430 gfx::Rect visible_rect(width, height); | 430 gfx::Rect visible_rect(picture.size()); |
| 431 DCHECK(decoder_texture_target_); | 431 DCHECK(decoder_texture_target_); |
| 432 // Convert timestamp from 90KHz to ms. | 432 // Convert timestamp from 90KHz to ms. |
| 433 base::TimeDelta timestamp_ms = base::TimeDelta::FromInternalValue( | 433 base::TimeDelta timestamp_ms = base::TimeDelta::FromInternalValue( |
| 434 base::checked_cast<uint64_t>(timestamp) * 1000 / 90); | 434 base::checked_cast<uint64_t>(timestamp) * 1000 / 90); |
| 435 return media::VideoFrame::WrapNativeTexture( | 435 return media::VideoFrame::WrapNativeTexture( |
| 436 make_scoped_ptr(new gpu::MailboxHolder( | 436 make_scoped_ptr(new gpu::MailboxHolder( |
| 437 pb.texture_mailbox(), decoder_texture_target_, 0)), | 437 pb.texture_mailbox(), decoder_texture_target_, 0)), |
| 438 media::BindToCurrentLoop(base::Bind(&RTCVideoDecoder::ReleaseMailbox, | 438 media::BindToCurrentLoop(base::Bind(&RTCVideoDecoder::ReleaseMailbox, |
| 439 weak_factory_.GetWeakPtr(), | 439 weak_factory_.GetWeakPtr(), |
| 440 factories_, | 440 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 | 770 // 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). | 771 // using too-high a value is low (192 bits per extra slot). |
| 772 static const size_t kMaxInputBufferDataSize = 128; | 772 static const size_t kMaxInputBufferDataSize = 128; |
| 773 // 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 |
| 774 // to be useful in the future data. | 774 // to be useful in the future data. |
| 775 if (input_buffer_data_.size() > kMaxInputBufferDataSize) | 775 if (input_buffer_data_.size() > kMaxInputBufferDataSize) |
| 776 input_buffer_data_.pop_back(); | 776 input_buffer_data_.pop_back(); |
| 777 } | 777 } |
| 778 | 778 |
| 779 void RTCVideoDecoder::GetBufferData(int32 bitstream_buffer_id, | 779 void RTCVideoDecoder::GetBufferData(int32 bitstream_buffer_id, |
| 780 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(); | 781 for (std::list<BufferData>::iterator it = input_buffer_data_.begin(); |
| 785 it != input_buffer_data_.end(); | 782 it != input_buffer_data_.end(); |
| 786 ++it) { | 783 ++it) { |
| 787 if (it->bitstream_buffer_id != bitstream_buffer_id) | 784 if (it->bitstream_buffer_id != bitstream_buffer_id) |
| 788 continue; | 785 continue; |
| 789 *timestamp = it->timestamp; | 786 *timestamp = it->timestamp; |
| 790 *width = it->width; | |
| 791 *height = it->height; | |
| 792 return; | 787 return; |
| 793 } | 788 } |
| 794 NOTREACHED() << "Missing bitstream buffer id: " << bitstream_buffer_id; | 789 NOTREACHED() << "Missing bitstream buffer id: " << bitstream_buffer_id; |
| 795 } | 790 } |
| 796 | 791 |
| 797 int32_t RTCVideoDecoder::RecordInitDecodeUMA(int32_t status) { | 792 int32_t RTCVideoDecoder::RecordInitDecodeUMA(int32_t status) { |
| 798 // Logging boolean is enough to know if HW decoding has been used. Also, | 793 // 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. | 794 // InitDecode is less likely to return an error so enum is not used here. |
| 800 bool sample = (status == WEBRTC_VIDEO_CODEC_OK) ? true : false; | 795 bool sample = (status == WEBRTC_VIDEO_CODEC_OK) ? true : false; |
| 801 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoDecoderInitDecodeSuccess", sample); | 796 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoDecoderInitDecodeSuccess", sample); |
| 802 return status; | 797 return status; |
| 803 } | 798 } |
| 804 | 799 |
| 805 void RTCVideoDecoder::DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent() | 800 void RTCVideoDecoder::DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent() |
| 806 const { | 801 const { |
| 807 DCHECK(factories_->GetTaskRunner()->BelongsToCurrentThread()); | 802 DCHECK(factories_->GetTaskRunner()->BelongsToCurrentThread()); |
| 808 } | 803 } |
| 809 | 804 |
| 810 } // namespace content | 805 } // namespace content |
| OLD | NEW |