Add ability to resize buffers pool in decoder and use it in IVF generator
Bug: webrtc:10138
Change-Id: I452f08f1d9af57de789bd947a1fcb95536845f80
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/162183
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30098}
diff --git a/api/video_codecs/video_codec.h b/api/video_codecs/video_codec.h
index a248d19..330bbbc 100644
--- a/api/video_codecs/video_codec.h
+++ b/api/video_codecs/video_codec.h
@@ -16,6 +16,7 @@
#include <string>
+#include "absl/types/optional.h"
#include "api/video/video_bitrate_allocation.h"
#include "api/video/video_codec_type.h"
#include "common_types.h" // NOLINT(build/include)
@@ -126,6 +127,12 @@
VideoCodecMode mode;
bool expect_encode_from_texture;
+ // The size of pool which is used to store video frame buffers inside decoder.
+ // If value isn't present some codec-default value will be used.
+ // If value is present and decoder doesn't have buffer pool the
+ // value will be ignored.
+ absl::optional<int> buffer_pool_size;
+
// Timing frames configuration. There is delay of delay_ms between two
// consequent timing frames, excluding outliers. Frame is always made a
// timing frame if it's at least outlier_ratio in percent of "ideal" average
diff --git a/common_video/i420_buffer_pool.cc b/common_video/i420_buffer_pool.cc
index e970419..d13da6a 100644
--- a/common_video/i420_buffer_pool.cc
+++ b/common_video/i420_buffer_pool.cc
@@ -29,6 +29,36 @@
buffers_.clear();
}
+bool I420BufferPool::Resize(size_t max_number_of_buffers) {
+ RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
+ size_t used_buffers_count = 0;
+ for (const rtc::scoped_refptr<PooledI420Buffer>& buffer : buffers_) {
+ // If the buffer is in use, the ref count will be >= 2, one from the list we
+ // are looping over and one from the application. If the ref count is 1,
+ // then the list we are looping over holds the only reference and it's safe
+ // to reuse.
+ if (!buffer->HasOneRef()) {
+ used_buffers_count++;
+ }
+ }
+ if (used_buffers_count > max_number_of_buffers) {
+ return false;
+ }
+ max_number_of_buffers_ = max_number_of_buffers;
+
+ size_t buffers_to_purge = buffers_.size() - max_number_of_buffers_;
+ auto iter = buffers_.begin();
+ while (iter != buffers_.end() && buffers_to_purge > 0) {
+ if ((*iter)->HasOneRef()) {
+ iter = buffers_.erase(iter);
+ buffers_to_purge--;
+ } else {
+ ++iter;
+ }
+ }
+ return true;
+}
+
rtc::scoped_refptr<I420Buffer> I420BufferPool::CreateBuffer(int width,
int height) {
// Default stride_y is width, default uv stride is width / 2 (rounding up).
diff --git a/common_video/include/i420_buffer_pool.h b/common_video/include/i420_buffer_pool.h
index d0ccee5..44f4821 100644
--- a/common_video/include/i420_buffer_pool.h
+++ b/common_video/include/i420_buffer_pool.h
@@ -48,6 +48,11 @@
int stride_u,
int stride_v);
+ // Changes the max amount of buffers in the pool to the new value.
+ // Returns true if change was successful and false if the amount of already
+ // allocated buffers is bigger than new value.
+ bool Resize(size_t max_number_of_buffers);
+
// Clears buffers_ and detaches the thread checker so that it can be reused
// later from another thread.
void Release();
@@ -66,7 +71,7 @@
// has to do with "Use-of-uninitialized-value" on "Linux_msan_chrome".
const bool zero_initialize_;
// Max number of buffers this pool can have pending.
- const size_t max_number_of_buffers_;
+ size_t max_number_of_buffers_;
};
} // namespace webrtc
diff --git a/modules/video_coding/codecs/h264/h264_decoder_impl.cc b/modules/video_coding/codecs/h264/h264_decoder_impl.cc
index fa5af98..6725a3b 100644
--- a/modules/video_coding/codecs/h264/h264_decoder_impl.cc
+++ b/modules/video_coding/codecs/h264/h264_decoder_impl.cc
@@ -218,6 +218,12 @@
}
av_frame_.reset(av_frame_alloc());
+
+ if (codec_settings && codec_settings->buffer_pool_size) {
+ if (!pool_.Resize(*codec_settings->buffer_pool_size)) {
+ return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
+ }
+ }
return WEBRTC_VIDEO_CODEC_OK;
}
diff --git a/modules/video_coding/codecs/vp8/libvpx_vp8_decoder.cc b/modules/video_coding/codecs/vp8/libvpx_vp8_decoder.cc
index bc4ddf6..a3ee2c0 100644
--- a/modules/video_coding/codecs/vp8/libvpx_vp8_decoder.cc
+++ b/modules/video_coding/codecs/vp8/libvpx_vp8_decoder.cc
@@ -149,6 +149,11 @@
// Always start with a complete key frame.
key_frame_required_ = true;
+ if (inst && inst->buffer_pool_size) {
+ if (!buffer_pool_.Resize(*inst->buffer_pool_size)) {
+ return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
+ }
+ }
return WEBRTC_VIDEO_CODEC_OK;
}
diff --git a/modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.cc b/modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.cc
index 372a813..4e47507 100644
--- a/modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.cc
+++ b/modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.cc
@@ -97,6 +97,36 @@
return num_buffers_in_use;
}
+bool Vp9FrameBufferPool::Resize(size_t max_number_of_buffers) {
+ rtc::CritScope cs(&buffers_lock_);
+ size_t used_buffers_count = 0;
+ for (const auto& buffer : allocated_buffers_) {
+ // If the buffer is in use, the ref count will be >= 2, one from the list we
+ // are looping over and one from the application. If the ref count is 1,
+ // then the list we are looping over holds the only reference and it's safe
+ // to reuse.
+ if (!buffer->HasOneRef()) {
+ used_buffers_count++;
+ }
+ }
+ if (used_buffers_count > max_number_of_buffers) {
+ return false;
+ }
+ max_num_buffers_ = max_number_of_buffers;
+
+ size_t buffers_to_purge = allocated_buffers_.size() - max_num_buffers_;
+ auto iter = allocated_buffers_.begin();
+ while (iter != allocated_buffers_.end() && buffers_to_purge > 0) {
+ if ((*iter)->HasOneRef()) {
+ iter = allocated_buffers_.erase(iter);
+ buffers_to_purge--;
+ } else {
+ ++iter;
+ }
+ }
+ return true;
+}
+
void Vp9FrameBufferPool::ClearPool() {
rtc::CritScope cs(&buffers_lock_);
allocated_buffers_.clear();
diff --git a/modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.h b/modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.h
index df6d451..02d2b26 100644
--- a/modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.h
+++ b/modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.h
@@ -26,6 +26,17 @@
namespace webrtc {
+// If more buffers than this are allocated we print warnings and crash if in
+// debug mode. VP9 is defined to have 8 reference buffers, of which 3 can be
+// referenced by any frame, see
+// https://tools.ietf.org/html/draft-grange-vp9-bitstream-00#section-2.2.2.
+// Assuming VP9 holds on to at most 8 buffers, any more buffers than that
+// would have to be by application code. Decoded frames should not be
+// referenced for longer than necessary. If we allow ~60 additional buffers
+// then the application has ~1 second to e.g. render each frame of a 60 fps
+// video.
+constexpr size_t kDefaultMaxNumBuffers = 68;
+
// This memory pool is used to serve buffers to libvpx for decoding purposes in
// VP9, which is set up in InitializeVPXUsePool. After the initialization any
// time libvpx wants to decode a frame it will use buffers provided and released
@@ -77,6 +88,10 @@
rtc::scoped_refptr<Vp9FrameBuffer> GetFrameBuffer(size_t min_size);
// Gets the number of buffers currently in use (not ready to be recycled).
int GetNumBuffersInUse() const;
+ // Changes the max amount of buffers in the pool to the new value.
+ // Returns true if change was successful and false if the amount of already
+ // allocated buffers is bigger than new value.
+ bool Resize(size_t max_number_of_buffers);
// Releases allocated buffers, deleting available buffers. Buffers in use are
// not deleted until they are no longer referenced.
void ClearPool();
@@ -108,16 +123,7 @@
// All buffers, in use or ready to be recycled.
std::vector<rtc::scoped_refptr<Vp9FrameBuffer>> allocated_buffers_
RTC_GUARDED_BY(buffers_lock_);
- // If more buffers than this are allocated we print warnings and crash if in
- // debug mode. VP9 is defined to have 8 reference buffers, of which 3 can be
- // referenced by any frame, see
- // https://tools.ietf.org/html/draft-grange-vp9-bitstream-00#section-2.2.2.
- // Assuming VP9 holds on to at most 8 buffers, any more buffers than that
- // would have to be by application code. Decoded frames should not be
- // referenced for longer than necessary. If we allow ~60 additional buffers
- // then the application has ~1 second to e.g. render each frame of a 60 fps
- // video.
- static const size_t max_num_buffers_ = 68;
+ size_t max_num_buffers_ = kDefaultMaxNumBuffers;
};
} // namespace webrtc
diff --git a/modules/video_coding/codecs/vp9/vp9_impl.cc b/modules/video_coding/codecs/vp9/vp9_impl.cc
index b926fe3..06b7fe1 100644
--- a/modules/video_coding/codecs/vp9/vp9_impl.cc
+++ b/modules/video_coding/codecs/vp9/vp9_impl.cc
@@ -1652,6 +1652,11 @@
inited_ = true;
// Always start with a complete key frame.
key_frame_required_ = true;
+ if (inst && inst->buffer_pool_size) {
+ if (!frame_buffer_pool_.Resize(*inst->buffer_pool_size)) {
+ return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
+ }
+ }
return WEBRTC_VIDEO_CODEC_OK;
}
diff --git a/test/testsupport/ivf_video_frame_generator.cc b/test/testsupport/ivf_video_frame_generator.cc
index 9fb057f..81155f8 100644
--- a/test/testsupport/ivf_video_frame_generator.cc
+++ b/test/testsupport/ivf_video_frame_generator.cc
@@ -10,6 +10,8 @@
#include "test/testsupport/ivf_video_frame_generator.h"
+#include <limits>
+
#include "api/video/encoded_image.h"
#include "api/video/i420_buffer.h"
#include "api/video_codecs/video_codec.h"
@@ -40,6 +42,10 @@
codec_settings.codecType = file_reader_->GetVideoCodecType();
codec_settings.width = file_reader_->GetFrameWidth();
codec_settings.height = file_reader_->GetFrameHeight();
+ // Set buffer pool size to max value to ensure that if users of generator,
+ // ex. test frameworks, will retain frames for quite a long time, decoder
+ // won't crash with buffers pool overflow error.
+ codec_settings.buffer_pool_size = std::numeric_limits<int>::max();
RTC_CHECK_EQ(video_decoder_->RegisterDecodeCompleteCallback(&callback_),
WEBRTC_VIDEO_CODEC_OK);
RTC_CHECK_EQ(