1 /* 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 * 10 */ 11 12 #include "webrtc/modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.h" 13 14 #include "vpx/vpx_codec.h" 15 #include "vpx/vpx_decoder.h" 16 #include "vpx/vpx_frame_buffer.h" 17 18 #include "webrtc/base/checks.h" 19 #include "webrtc/base/logging.h" 20 21 namespace webrtc { 22 23 uint8_t* Vp9FrameBufferPool::Vp9FrameBuffer::GetData() { 24 return data_.data<uint8_t>(); 25 } 26 27 size_t Vp9FrameBufferPool::Vp9FrameBuffer::GetDataSize() const { 28 return data_.size(); 29 } 30 31 void Vp9FrameBufferPool::Vp9FrameBuffer::SetSize(size_t size) { 32 data_.SetSize(size); 33 } 34 35 bool Vp9FrameBufferPool::InitializeVpxUsePool( 36 vpx_codec_ctx* vpx_codec_context) { 37 RTC_DCHECK(vpx_codec_context); 38 // Tell libvpx to use this pool. 39 if (vpx_codec_set_frame_buffer_functions( 40 // In which context to use these callback functions. 41 vpx_codec_context, 42 // Called by libvpx when it needs another frame buffer. 43 &Vp9FrameBufferPool::VpxGetFrameBuffer, 44 // Called by libvpx when it no longer uses a frame buffer. 45 &Vp9FrameBufferPool::VpxReleaseFrameBuffer, 46 // |this| will be passed as |user_priv| to VpxGetFrameBuffer. 47 this)) { 48 // Failed to configure libvpx to use Vp9FrameBufferPool. 49 return false; 50 } 51 return true; 52 } 53 54 rtc::scoped_refptr<Vp9FrameBufferPool::Vp9FrameBuffer> 55 Vp9FrameBufferPool::GetFrameBuffer(size_t min_size) { 56 RTC_DCHECK_GT(min_size, 0u); 57 rtc::scoped_refptr<Vp9FrameBuffer> available_buffer = nullptr; 58 { 59 rtc::CritScope cs(&buffers_lock_); 60 // Do we have a buffer we can recycle? 61 for (const auto& buffer : allocated_buffers_) { 62 if (buffer->HasOneRef()) { 63 available_buffer = buffer; 64 break; 65 } 66 } 67 // Otherwise create one. 68 if (available_buffer == nullptr) { 69 available_buffer = new rtc::RefCountedObject<Vp9FrameBuffer>(); 70 allocated_buffers_.push_back(available_buffer); 71 if (allocated_buffers_.size() > max_num_buffers_) { 72 LOG(LS_WARNING) 73 << allocated_buffers_.size() << " Vp9FrameBuffers have been " 74 << "allocated by a Vp9FrameBufferPool (exceeding what is " 75 << "considered reasonable, " << max_num_buffers_ << ")."; 76 RTC_NOTREACHED(); 77 } 78 } 79 } 80 81 available_buffer->SetSize(min_size); 82 return available_buffer; 83 } 84 85 int Vp9FrameBufferPool::GetNumBuffersInUse() const { 86 int num_buffers_in_use = 0; 87 rtc::CritScope cs(&buffers_lock_); 88 for (const auto& buffer : allocated_buffers_) { 89 if (!buffer->HasOneRef()) 90 ++num_buffers_in_use; 91 } 92 return num_buffers_in_use; 93 } 94 95 void Vp9FrameBufferPool::ClearPool() { 96 rtc::CritScope cs(&buffers_lock_); 97 allocated_buffers_.clear(); 98 } 99 100 // static 101 int32_t Vp9FrameBufferPool::VpxGetFrameBuffer(void* user_priv, 102 size_t min_size, 103 vpx_codec_frame_buffer* fb) { 104 RTC_DCHECK(user_priv); 105 RTC_DCHECK(fb); 106 Vp9FrameBufferPool* pool = static_cast<Vp9FrameBufferPool*>(user_priv); 107 108 rtc::scoped_refptr<Vp9FrameBuffer> buffer = pool->GetFrameBuffer(min_size); 109 fb->data = buffer->GetData(); 110 fb->size = buffer->GetDataSize(); 111 // Store Vp9FrameBuffer* in |priv| for use in VpxReleaseFrameBuffer. 112 // This also makes vpx_codec_get_frame return images with their |fb_priv| set 113 // to |buffer| which is important for external reference counting. 114 // Release from refptr so that the buffer's |ref_count_| remains 1 when 115 // |buffer| goes out of scope. 116 fb->priv = static_cast<void*>(buffer.release()); 117 return 0; 118 } 119 120 // static 121 int32_t Vp9FrameBufferPool::VpxReleaseFrameBuffer(void* user_priv, 122 vpx_codec_frame_buffer* fb) { 123 RTC_DCHECK(user_priv); 124 RTC_DCHECK(fb); 125 Vp9FrameBuffer* buffer = static_cast<Vp9FrameBuffer*>(fb->priv); 126 if (buffer != nullptr) { 127 buffer->Release(); 128 // When libvpx fails to decode and you continue to try to decode (and fail) 129 // libvpx can for some reason try to release the same buffer multiple times. 130 // Setting |priv| to null protects against trying to Release multiple times. 131 fb->priv = nullptr; 132 } 133 return 0; 134 } 135 136 } // namespace webrtc 137