Line data Source code
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 0 : uint8_t* Vp9FrameBufferPool::Vp9FrameBuffer::GetData() {
24 0 : return data_.data<uint8_t>();
25 : }
26 :
27 0 : size_t Vp9FrameBufferPool::Vp9FrameBuffer::GetDataSize() const {
28 0 : return data_.size();
29 : }
30 :
31 0 : void Vp9FrameBufferPool::Vp9FrameBuffer::SetSize(size_t size) {
32 0 : data_.SetSize(size);
33 0 : }
34 :
35 0 : bool Vp9FrameBufferPool::InitializeVpxUsePool(
36 : vpx_codec_ctx* vpx_codec_context) {
37 0 : RTC_DCHECK(vpx_codec_context);
38 : // Tell libvpx to use this pool.
39 0 : 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 0 : return false;
50 : }
51 0 : return true;
52 : }
53 :
54 : rtc::scoped_refptr<Vp9FrameBufferPool::Vp9FrameBuffer>
55 0 : Vp9FrameBufferPool::GetFrameBuffer(size_t min_size) {
56 0 : RTC_DCHECK_GT(min_size, 0);
57 0 : rtc::scoped_refptr<Vp9FrameBuffer> available_buffer = nullptr;
58 : {
59 0 : rtc::CritScope cs(&buffers_lock_);
60 : // Do we have a buffer we can recycle?
61 0 : for (const auto& buffer : allocated_buffers_) {
62 0 : if (buffer->HasOneRef()) {
63 0 : available_buffer = buffer;
64 0 : break;
65 : }
66 : }
67 : // Otherwise create one.
68 0 : if (available_buffer == nullptr) {
69 0 : available_buffer = new rtc::RefCountedObject<Vp9FrameBuffer>();
70 0 : allocated_buffers_.push_back(available_buffer);
71 0 : if (allocated_buffers_.size() > max_num_buffers_) {
72 0 : LOG(LS_WARNING)
73 0 : << allocated_buffers_.size() << " Vp9FrameBuffers have been "
74 : << "allocated by a Vp9FrameBufferPool (exceeding what is "
75 0 : << "considered reasonable, " << max_num_buffers_ << ").";
76 :
77 : // TODO(phoglund): this limit is being hit in tests since Oct 5 2016.
78 : // See https://bugs.chromium.org/p/webrtc/issues/detail?id=6484.
79 : // RTC_NOTREACHED();
80 : }
81 : }
82 : }
83 :
84 0 : available_buffer->SetSize(min_size);
85 0 : return available_buffer;
86 : }
87 :
88 0 : int Vp9FrameBufferPool::GetNumBuffersInUse() const {
89 0 : int num_buffers_in_use = 0;
90 0 : rtc::CritScope cs(&buffers_lock_);
91 0 : for (const auto& buffer : allocated_buffers_) {
92 0 : if (!buffer->HasOneRef())
93 0 : ++num_buffers_in_use;
94 : }
95 0 : return num_buffers_in_use;
96 : }
97 :
98 0 : void Vp9FrameBufferPool::ClearPool() {
99 0 : rtc::CritScope cs(&buffers_lock_);
100 0 : allocated_buffers_.clear();
101 0 : }
102 :
103 : // static
104 0 : int32_t Vp9FrameBufferPool::VpxGetFrameBuffer(void* user_priv,
105 : size_t min_size,
106 : vpx_codec_frame_buffer* fb) {
107 0 : RTC_DCHECK(user_priv);
108 0 : RTC_DCHECK(fb);
109 0 : Vp9FrameBufferPool* pool = static_cast<Vp9FrameBufferPool*>(user_priv);
110 :
111 0 : rtc::scoped_refptr<Vp9FrameBuffer> buffer = pool->GetFrameBuffer(min_size);
112 0 : fb->data = buffer->GetData();
113 0 : fb->size = buffer->GetDataSize();
114 : // Store Vp9FrameBuffer* in |priv| for use in VpxReleaseFrameBuffer.
115 : // This also makes vpx_codec_get_frame return images with their |fb_priv| set
116 : // to |buffer| which is important for external reference counting.
117 : // Release from refptr so that the buffer's |ref_count_| remains 1 when
118 : // |buffer| goes out of scope.
119 0 : fb->priv = static_cast<void*>(buffer.release());
120 0 : return 0;
121 : }
122 :
123 : // static
124 0 : int32_t Vp9FrameBufferPool::VpxReleaseFrameBuffer(void* user_priv,
125 : vpx_codec_frame_buffer* fb) {
126 0 : RTC_DCHECK(user_priv);
127 0 : RTC_DCHECK(fb);
128 0 : Vp9FrameBuffer* buffer = static_cast<Vp9FrameBuffer*>(fb->priv);
129 0 : if (buffer != nullptr) {
130 0 : buffer->Release();
131 : // When libvpx fails to decode and you continue to try to decode (and fail)
132 : // libvpx can for some reason try to release the same buffer multiple times.
133 : // Setting |priv| to null protects against trying to Release multiple times.
134 0 : fb->priv = nullptr;
135 : }
136 0 : return 0;
137 : }
138 :
139 : } // namespace webrtc
|