/* * Copyright (c) 2018, Alliance for Open Media. All rights reserved. * * This source code is subject to the terms of the BSD 2 Clause License and * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License * was not distributed with this source code in the LICENSE file, you can * obtain it at www.aomedia.org/license/software. If the Alliance for Open * Media Patent License 1.0 was not distributed with this source code in the * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
struct ExternalFrameBuffer {
uint8_t *data;
size_t size; int in_use;
};
// Class to manipulate a list of external frame buffers. class ExternalFrameBufferList { public:
ExternalFrameBufferList()
: num_buffers_(0), num_used_buffers_(0), ext_fb_list_(nullptr) {}
virtual ~ExternalFrameBufferList() { for (int i = 0; i < num_buffers_; ++i) { delete[] ext_fb_list_[i].data;
} delete[] ext_fb_list_;
}
// Creates the list to hold the external buffers. Returns true on success. bool CreateBufferList(int num_buffers) { if (num_buffers < 0) returnfalse;
// Searches the frame buffer list for a free frame buffer. Makes sure // that the frame buffer is at least |min_size| in bytes. Marks that the // frame buffer is in use by libaom. Finally sets |fb| to point to the // external frame buffer. Returns < 0 on an error. int GetFreeFrameBuffer(size_t min_size, aom_codec_frame_buffer_t *fb) {
EXPECT_NE(fb, nullptr); constint idx = FindFreeBufferIndex(); if (idx == num_buffers_) return -1;
if (ext_fb_list_[idx].size < min_size) { delete[] ext_fb_list_[idx].data;
ext_fb_list_[idx].data = new uint8_t[min_size]; if (ext_fb_list_[idx].data == nullptr) {
EXPECT_NE(ext_fb_list_[idx].data, nullptr);
}
memset(ext_fb_list_[idx].data, 0, min_size);
ext_fb_list_[idx].size = min_size;
}
SetFrameBuffer(idx, fb);
num_used_buffers_++; return 0;
}
// Test function that will not allocate any data for the frame buffer. // Returns < 0 on an error. int GetZeroFrameBuffer(size_t min_size, aom_codec_frame_buffer_t *fb) {
EXPECT_NE(fb, nullptr); constint idx = FindFreeBufferIndex(); if (idx == num_buffers_) return -1;
// Marks the external frame buffer that |fb| is pointing to as free. // Returns < 0 on an error. int ReturnFrameBuffer(aom_codec_frame_buffer_t *fb) { if (fb == nullptr) {
EXPECT_NE(fb, nullptr); return -1;
}
ExternalFrameBuffer *const ext_fb = reinterpret_cast<ExternalFrameBuffer *>(fb->priv); if (ext_fb == nullptr) {
EXPECT_NE(ext_fb, nullptr); return -1;
}
EXPECT_EQ(1, ext_fb->in_use);
ext_fb->in_use = 0;
num_used_buffers_--; return 0;
}
// Checks that the aom_image_t data is contained within the external frame // buffer private data passed back in the aom_image_t. void CheckImageFrameBuffer(const aom_image_t *img) { conststruct ExternalFrameBuffer *const ext_fb = reinterpret_cast<ExternalFrameBuffer *>(img->fb_priv);
int num_used_buffers() const { return num_used_buffers_; }
private: // Returns the index of the first free frame buffer. Returns |num_buffers_| // if there are no free frame buffers. int FindFreeBufferIndex() { int i; // Find a free frame buffer. for (i = 0; i < num_buffers_; ++i) { if (!ext_fb_list_[i].in_use) break;
} return i;
}
// Sets |fb| to an external frame buffer. idx is the index into the frame // buffer list. void SetFrameBuffer(int idx, aom_codec_frame_buffer_t *fb) {
ASSERT_NE(fb, nullptr);
fb->data = ext_fb_list_[idx].data;
fb->size = ext_fb_list_[idx].size;
ASSERT_EQ(0, ext_fb_list_[idx].in_use);
ext_fb_list_[idx].in_use = 1;
fb->priv = &ext_fb_list_[idx];
}
int num_buffers_; int num_used_buffers_;
ExternalFrameBuffer *ext_fb_list_;
};
#if CONFIG_WEBM_IO
// Callback used by libaom to request the application to return a frame // buffer of at least |min_size| in bytes. int get_aom_frame_buffer(void *user_priv, size_t min_size,
aom_codec_frame_buffer_t *fb) {
ExternalFrameBufferList *const fb_list = reinterpret_cast<ExternalFrameBufferList *>(user_priv); return fb_list->GetFreeFrameBuffer(min_size, fb);
}
// Callback used by libaom to tell the application that |fb| is not needed // anymore. int release_aom_frame_buffer(void *user_priv, aom_codec_frame_buffer_t *fb) {
ExternalFrameBufferList *const fb_list = reinterpret_cast<ExternalFrameBufferList *>(user_priv); return fb_list->ReturnFrameBuffer(fb);
}
// Callback will not allocate data for frame buffer. int get_aom_zero_frame_buffer(void *user_priv, size_t min_size,
aom_codec_frame_buffer_t *fb) {
ExternalFrameBufferList *const fb_list = reinterpret_cast<ExternalFrameBufferList *>(user_priv); return fb_list->GetZeroFrameBuffer(min_size, fb);
}
// Callback will allocate one less byte than |min_size|. int get_aom_one_less_byte_frame_buffer(void *user_priv, size_t min_size,
aom_codec_frame_buffer_t *fb) {
ExternalFrameBufferList *const fb_list = reinterpret_cast<ExternalFrameBufferList *>(user_priv); return fb_list->GetFreeFrameBuffer(min_size - 1, fb);
}
// Callback will not release the external frame buffer. int do_not_release_aom_frame_buffer(void *user_priv,
aom_codec_frame_buffer_t *fb) {
(void)user_priv;
(void)fb; return 0;
}
#endif// CONFIG_WEBM_IO
// Class for testing passing in external frame buffers to libaom. class ExternalFrameBufferMD5Test
: public ::libaom_test::DecoderTest, public ::libaom_test::CodecTestWithParam<constchar *> { protected:
ExternalFrameBufferMD5Test()
: DecoderTest(GET_PARAM(::libaom_test::kCodecFactoryParam)),
md5_file_(nullptr), num_buffers_(0) {}
~ExternalFrameBufferMD5Test() override { if (md5_file_ != nullptr) fclose(md5_file_);
}
void PreDecodeFrameHook(const libaom_test::CompressedVideoSource &video,
libaom_test::Decoder *decoder) override { if (num_buffers_ > 0 && video.frame_number() == 0) { // Have libaom use frame buffers we create.
ASSERT_TRUE(fb_list_.CreateBufferList(num_buffers_));
ASSERT_EQ(AOM_CODEC_OK,
decoder->SetFrameBufferFunctions(GetAV1FrameBuffer,
ReleaseAV1FrameBuffer, this));
}
}
// Class for testing passing in external frame buffers to libaom. class ExternalFrameBufferTest : public ::testing::Test { protected:
ExternalFrameBufferTest()
: video_(nullptr), decoder_(nullptr), num_buffers_(0) {}
// This test runs through the set of test vectors, and decodes them. // Libaom will call into the application to allocate a frame buffer when // needed. The md5 checksums are computed for each frame in the video file. // If md5 checksums match the correct md5 data, then the test is passed. // Otherwise, the test failed.
TEST_P(ExternalFrameBufferMD5Test, ExtFBMD5Match) { const std::string filename = GET_PARAM(kVideoNameParam);
aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t();
// Number of buffers equals #AOM_MAXIMUM_REF_BUFFERS + // #AOM_MAXIMUM_WORK_BUFFERS + four jitter buffers. constint jitter_buffers = 4; constint num_buffers =
AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS + jitter_buffers;
set_num_buffers(num_buffers);
// Open compressed video file.
std::unique_ptr<libaom_test::CompressedVideoSource> video; if (filename.substr(filename.length() - 3, 3) == "ivf") {
video.reset(new libaom_test::IVFVideoSource(filename));
} else { #if CONFIG_WEBM_IO
video.reset(new libaom_test::WebMVideoSource(filename)); #else
fprintf(stderr, "WebM IO is disabled, skipping test vector %s\n",
filename.c_str()); return; #endif
}
ASSERT_NE(video, nullptr);
video->Init();
TEST_F(ExternalFrameBufferTest, NotEnoughBuffers) { // Minimum number of external frame buffers for AV1 is // #AOM_MAXIMUM_REF_BUFFERS + #AOM_MAXIMUM_WORK_BUFFERS. Most files will // only use 5 frame buffers at one time. constint num_buffers = 2;
ASSERT_EQ(AOM_CODEC_OK,
SetFrameBufferFunctions(num_buffers, get_aom_frame_buffer,
release_aom_frame_buffer));
ASSERT_EQ(AOM_CODEC_OK, DecodeOneFrame()); // Only run this on long clips. Decoding a very short clip will return // AOM_CODEC_OK even with only 2 buffers.
ASSERT_EQ(AOM_CODEC_MEM_ERROR, DecodeRemainingFrames());
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.