xref: /aosp_15_r20/external/libaom/test/external_frame_buffer_test.cc (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
1 /*
2  * Copyright (c) 2018, Alliance for Open Media. All rights reserved.
3  *
4  * This source code is subject to the terms of the BSD 2 Clause License and
5  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6  * was not distributed with this source code in the LICENSE file, you can
7  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8  * Media Patent License 1.0 was not distributed with this source code in the
9  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10  */
11 
12 #include <memory>
13 #include <string>
14 #include "common/tools_common.h"
15 #include "config/aom_config.h"
16 #include "test/codec_factory.h"
17 #include "test/decode_test_driver.h"
18 #include "test/ivf_video_source.h"
19 #include "test/md5_helper.h"
20 #include "test/test_vectors.h"
21 #include "test/util.h"
22 #if CONFIG_WEBM_IO
23 #include "test/webm_video_source.h"
24 #endif
25 
26 namespace {
27 
28 const int kVideoNameParam = 1;
29 
30 struct ExternalFrameBuffer {
31   uint8_t *data;
32   size_t size;
33   int in_use;
34 };
35 
36 // Class to manipulate a list of external frame buffers.
37 class ExternalFrameBufferList {
38  public:
ExternalFrameBufferList()39   ExternalFrameBufferList()
40       : num_buffers_(0), num_used_buffers_(0), ext_fb_list_(nullptr) {}
41 
~ExternalFrameBufferList()42   virtual ~ExternalFrameBufferList() {
43     for (int i = 0; i < num_buffers_; ++i) {
44       delete[] ext_fb_list_[i].data;
45     }
46     delete[] ext_fb_list_;
47   }
48 
49   // Creates the list to hold the external buffers. Returns true on success.
CreateBufferList(int num_buffers)50   bool CreateBufferList(int num_buffers) {
51     if (num_buffers < 0) return false;
52 
53     num_buffers_ = num_buffers;
54     ext_fb_list_ = new ExternalFrameBuffer[num_buffers_];
55     if (ext_fb_list_ == nullptr) {
56       EXPECT_NE(ext_fb_list_, nullptr);
57       return false;
58     }
59     memset(ext_fb_list_, 0, sizeof(ext_fb_list_[0]) * num_buffers_);
60     return true;
61   }
62 
63   // Searches the frame buffer list for a free frame buffer. Makes sure
64   // that the frame buffer is at least |min_size| in bytes. Marks that the
65   // frame buffer is in use by libaom. Finally sets |fb| to point to the
66   // external frame buffer. Returns < 0 on an error.
GetFreeFrameBuffer(size_t min_size,aom_codec_frame_buffer_t * fb)67   int GetFreeFrameBuffer(size_t min_size, aom_codec_frame_buffer_t *fb) {
68     EXPECT_NE(fb, nullptr);
69     const int idx = FindFreeBufferIndex();
70     if (idx == num_buffers_) return -1;
71 
72     if (ext_fb_list_[idx].size < min_size) {
73       delete[] ext_fb_list_[idx].data;
74       ext_fb_list_[idx].data = new uint8_t[min_size];
75       if (ext_fb_list_[idx].data == nullptr) {
76         EXPECT_NE(ext_fb_list_[idx].data, nullptr);
77       }
78       memset(ext_fb_list_[idx].data, 0, min_size);
79       ext_fb_list_[idx].size = min_size;
80     }
81 
82     SetFrameBuffer(idx, fb);
83 
84     num_used_buffers_++;
85     return 0;
86   }
87 
88   // Test function that will not allocate any data for the frame buffer.
89   // Returns < 0 on an error.
GetZeroFrameBuffer(size_t min_size,aom_codec_frame_buffer_t * fb)90   int GetZeroFrameBuffer(size_t min_size, aom_codec_frame_buffer_t *fb) {
91     EXPECT_NE(fb, nullptr);
92     const int idx = FindFreeBufferIndex();
93     if (idx == num_buffers_) return -1;
94 
95     if (ext_fb_list_[idx].size < min_size) {
96       delete[] ext_fb_list_[idx].data;
97       ext_fb_list_[idx].data = nullptr;
98       ext_fb_list_[idx].size = min_size;
99     }
100 
101     SetFrameBuffer(idx, fb);
102     return 0;
103   }
104 
105   // Marks the external frame buffer that |fb| is pointing to as free.
106   // Returns < 0 on an error.
ReturnFrameBuffer(aom_codec_frame_buffer_t * fb)107   int ReturnFrameBuffer(aom_codec_frame_buffer_t *fb) {
108     if (fb == nullptr) {
109       EXPECT_NE(fb, nullptr);
110       return -1;
111     }
112     ExternalFrameBuffer *const ext_fb =
113         reinterpret_cast<ExternalFrameBuffer *>(fb->priv);
114     if (ext_fb == nullptr) {
115       EXPECT_NE(ext_fb, nullptr);
116       return -1;
117     }
118     EXPECT_EQ(1, ext_fb->in_use);
119     ext_fb->in_use = 0;
120     num_used_buffers_--;
121     return 0;
122   }
123 
124   // Checks that the aom_image_t data is contained within the external frame
125   // buffer private data passed back in the aom_image_t.
CheckImageFrameBuffer(const aom_image_t * img)126   void CheckImageFrameBuffer(const aom_image_t *img) {
127     const struct ExternalFrameBuffer *const ext_fb =
128         reinterpret_cast<ExternalFrameBuffer *>(img->fb_priv);
129 
130     ASSERT_TRUE(img->planes[0] >= ext_fb->data &&
131                 img->planes[0] < (ext_fb->data + ext_fb->size));
132   }
133 
num_used_buffers() const134   int num_used_buffers() const { return num_used_buffers_; }
135 
136  private:
137   // Returns the index of the first free frame buffer. Returns |num_buffers_|
138   // if there are no free frame buffers.
FindFreeBufferIndex()139   int FindFreeBufferIndex() {
140     int i;
141     // Find a free frame buffer.
142     for (i = 0; i < num_buffers_; ++i) {
143       if (!ext_fb_list_[i].in_use) break;
144     }
145     return i;
146   }
147 
148   // Sets |fb| to an external frame buffer. idx is the index into the frame
149   // buffer list.
SetFrameBuffer(int idx,aom_codec_frame_buffer_t * fb)150   void SetFrameBuffer(int idx, aom_codec_frame_buffer_t *fb) {
151     ASSERT_NE(fb, nullptr);
152     fb->data = ext_fb_list_[idx].data;
153     fb->size = ext_fb_list_[idx].size;
154     ASSERT_EQ(0, ext_fb_list_[idx].in_use);
155     ext_fb_list_[idx].in_use = 1;
156     fb->priv = &ext_fb_list_[idx];
157   }
158 
159   int num_buffers_;
160   int num_used_buffers_;
161   ExternalFrameBuffer *ext_fb_list_;
162 };
163 
164 #if CONFIG_WEBM_IO
165 
166 // Callback used by libaom to request the application to return a frame
167 // buffer of at least |min_size| in bytes.
get_aom_frame_buffer(void * user_priv,size_t min_size,aom_codec_frame_buffer_t * fb)168 int get_aom_frame_buffer(void *user_priv, size_t min_size,
169                          aom_codec_frame_buffer_t *fb) {
170   ExternalFrameBufferList *const fb_list =
171       reinterpret_cast<ExternalFrameBufferList *>(user_priv);
172   return fb_list->GetFreeFrameBuffer(min_size, fb);
173 }
174 
175 // Callback used by libaom to tell the application that |fb| is not needed
176 // anymore.
release_aom_frame_buffer(void * user_priv,aom_codec_frame_buffer_t * fb)177 int release_aom_frame_buffer(void *user_priv, aom_codec_frame_buffer_t *fb) {
178   ExternalFrameBufferList *const fb_list =
179       reinterpret_cast<ExternalFrameBufferList *>(user_priv);
180   return fb_list->ReturnFrameBuffer(fb);
181 }
182 
183 // Callback will not allocate data for frame buffer.
get_aom_zero_frame_buffer(void * user_priv,size_t min_size,aom_codec_frame_buffer_t * fb)184 int get_aom_zero_frame_buffer(void *user_priv, size_t min_size,
185                               aom_codec_frame_buffer_t *fb) {
186   ExternalFrameBufferList *const fb_list =
187       reinterpret_cast<ExternalFrameBufferList *>(user_priv);
188   return fb_list->GetZeroFrameBuffer(min_size, fb);
189 }
190 
191 // Callback will allocate one less byte than |min_size|.
get_aom_one_less_byte_frame_buffer(void * user_priv,size_t min_size,aom_codec_frame_buffer_t * fb)192 int get_aom_one_less_byte_frame_buffer(void *user_priv, size_t min_size,
193                                        aom_codec_frame_buffer_t *fb) {
194   ExternalFrameBufferList *const fb_list =
195       reinterpret_cast<ExternalFrameBufferList *>(user_priv);
196   return fb_list->GetFreeFrameBuffer(min_size - 1, fb);
197 }
198 
199 // Callback will not release the external frame buffer.
do_not_release_aom_frame_buffer(void * user_priv,aom_codec_frame_buffer_t * fb)200 int do_not_release_aom_frame_buffer(void *user_priv,
201                                     aom_codec_frame_buffer_t *fb) {
202   (void)user_priv;
203   (void)fb;
204   return 0;
205 }
206 
207 #endif  // CONFIG_WEBM_IO
208 
209 // Class for testing passing in external frame buffers to libaom.
210 class ExternalFrameBufferMD5Test
211     : public ::libaom_test::DecoderTest,
212       public ::libaom_test::CodecTestWithParam<const char *> {
213  protected:
ExternalFrameBufferMD5Test()214   ExternalFrameBufferMD5Test()
215       : DecoderTest(GET_PARAM(::libaom_test::kCodecFactoryParam)),
216         md5_file_(nullptr), num_buffers_(0) {}
217 
~ExternalFrameBufferMD5Test()218   ~ExternalFrameBufferMD5Test() override {
219     if (md5_file_ != nullptr) fclose(md5_file_);
220   }
221 
PreDecodeFrameHook(const libaom_test::CompressedVideoSource & video,libaom_test::Decoder * decoder)222   void PreDecodeFrameHook(const libaom_test::CompressedVideoSource &video,
223                           libaom_test::Decoder *decoder) override {
224     if (num_buffers_ > 0 && video.frame_number() == 0) {
225       // Have libaom use frame buffers we create.
226       ASSERT_TRUE(fb_list_.CreateBufferList(num_buffers_));
227       ASSERT_EQ(AOM_CODEC_OK,
228                 decoder->SetFrameBufferFunctions(GetAV1FrameBuffer,
229                                                  ReleaseAV1FrameBuffer, this));
230     }
231   }
232 
OpenMD5File(const std::string & md5_file_name_)233   void OpenMD5File(const std::string &md5_file_name_) {
234     md5_file_ = libaom_test::OpenTestDataFile(md5_file_name_);
235     ASSERT_NE(md5_file_, nullptr)
236         << "Md5 file open failed. Filename: " << md5_file_name_;
237   }
238 
DecompressedFrameHook(const aom_image_t & img,const unsigned int frame_number)239   void DecompressedFrameHook(const aom_image_t &img,
240                              const unsigned int frame_number) override {
241     ASSERT_NE(md5_file_, nullptr);
242     char expected_md5[33];
243     char junk[128];
244 
245     // Read correct md5 checksums.
246     const int res = fscanf(md5_file_, "%s  %s", expected_md5, junk);
247     ASSERT_NE(EOF, res) << "Read md5 data failed";
248     expected_md5[32] = '\0';
249 
250     ::libaom_test::MD5 md5_res;
251 #if FORCE_HIGHBITDEPTH_DECODING
252     const aom_img_fmt_t shifted_fmt =
253         (aom_img_fmt)(img.fmt & ~AOM_IMG_FMT_HIGHBITDEPTH);
254     if (img.bit_depth == 8 && shifted_fmt != img.fmt) {
255       aom_image_t *img_shifted =
256           aom_img_alloc(nullptr, shifted_fmt, img.d_w, img.d_h, 16);
257       img_shifted->bit_depth = img.bit_depth;
258       img_shifted->monochrome = img.monochrome;
259       aom_img_downshift(img_shifted, &img, 0);
260       md5_res.Add(img_shifted);
261       aom_img_free(img_shifted);
262     } else {
263 #endif
264       md5_res.Add(&img);
265 #if FORCE_HIGHBITDEPTH_DECODING
266     }
267 #endif
268     const char *const actual_md5 = md5_res.Get();
269 
270     // Check md5 match.
271     ASSERT_STREQ(expected_md5, actual_md5)
272         << "Md5 checksums don't match: frame number = " << frame_number;
273 
274     const struct ExternalFrameBuffer *const ext_fb =
275         reinterpret_cast<ExternalFrameBuffer *>(img.fb_priv);
276 
277     ASSERT_TRUE(img.planes[0] >= ext_fb->data &&
278                 img.planes[0] < (ext_fb->data + ext_fb->size));
279   }
280 
281   // Callback to get a free external frame buffer. Return value < 0 is an
282   // error.
GetAV1FrameBuffer(void * user_priv,size_t min_size,aom_codec_frame_buffer_t * fb)283   static int GetAV1FrameBuffer(void *user_priv, size_t min_size,
284                                aom_codec_frame_buffer_t *fb) {
285     ExternalFrameBufferMD5Test *const md5Test =
286         reinterpret_cast<ExternalFrameBufferMD5Test *>(user_priv);
287     return md5Test->fb_list_.GetFreeFrameBuffer(min_size, fb);
288   }
289 
290   // Callback to release an external frame buffer. Return value < 0 is an
291   // error.
ReleaseAV1FrameBuffer(void * user_priv,aom_codec_frame_buffer_t * fb)292   static int ReleaseAV1FrameBuffer(void *user_priv,
293                                    aom_codec_frame_buffer_t *fb) {
294     ExternalFrameBufferMD5Test *const md5Test =
295         reinterpret_cast<ExternalFrameBufferMD5Test *>(user_priv);
296     return md5Test->fb_list_.ReturnFrameBuffer(fb);
297   }
298 
set_num_buffers(int num_buffers)299   void set_num_buffers(int num_buffers) { num_buffers_ = num_buffers; }
num_buffers() const300   int num_buffers() const { return num_buffers_; }
301 
302  private:
303   FILE *md5_file_;
304   int num_buffers_;
305   ExternalFrameBufferList fb_list_;
306 };
307 
308 #if CONFIG_WEBM_IO
309 const char kAV1TestFile[] = "av1-1-b8-03-sizeup.mkv";
310 const char kAV1NonRefTestFile[] = "av1-1-b8-01-size-226x226.ivf";
311 
312 // Class for testing passing in external frame buffers to libaom.
313 class ExternalFrameBufferTest : public ::testing::Test {
314  protected:
ExternalFrameBufferTest()315   ExternalFrameBufferTest()
316       : video_(nullptr), decoder_(nullptr), num_buffers_(0) {}
317 
SetUp()318   void SetUp() override {
319     video_ = new libaom_test::WebMVideoSource(kAV1TestFile);
320     ASSERT_NE(video_, nullptr);
321     video_->Init();
322     video_->Begin();
323 
324     aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t();
325     cfg.allow_lowbitdepth = !FORCE_HIGHBITDEPTH_DECODING;
326     decoder_ = new libaom_test::AV1Decoder(cfg, 0);
327     ASSERT_NE(decoder_, nullptr);
328   }
329 
TearDown()330   void TearDown() override {
331     delete decoder_;
332     decoder_ = nullptr;
333     delete video_;
334     video_ = nullptr;
335   }
336 
337   // Passes the external frame buffer information to libaom.
SetFrameBufferFunctions(int num_buffers,aom_get_frame_buffer_cb_fn_t cb_get,aom_release_frame_buffer_cb_fn_t cb_release)338   aom_codec_err_t SetFrameBufferFunctions(
339       int num_buffers, aom_get_frame_buffer_cb_fn_t cb_get,
340       aom_release_frame_buffer_cb_fn_t cb_release) {
341     if (num_buffers > 0) {
342       num_buffers_ = num_buffers;
343       EXPECT_TRUE(fb_list_.CreateBufferList(num_buffers_));
344     }
345 
346     return decoder_->SetFrameBufferFunctions(cb_get, cb_release, &fb_list_);
347   }
348 
DecodeOneFrame()349   aom_codec_err_t DecodeOneFrame() {
350     const aom_codec_err_t res =
351         decoder_->DecodeFrame(video_->cxdata(), video_->frame_size());
352     CheckDecodedFrames();
353     if (res == AOM_CODEC_OK) video_->Next();
354     return res;
355   }
356 
DecodeRemainingFrames()357   aom_codec_err_t DecodeRemainingFrames() {
358     for (; video_->cxdata() != nullptr; video_->Next()) {
359       const aom_codec_err_t res =
360           decoder_->DecodeFrame(video_->cxdata(), video_->frame_size());
361       if (res != AOM_CODEC_OK) return res;
362       CheckDecodedFrames();
363     }
364     return AOM_CODEC_OK;
365   }
366 
367  protected:
CheckDecodedFrames()368   void CheckDecodedFrames() {
369     libaom_test::DxDataIterator dec_iter = decoder_->GetDxData();
370     const aom_image_t *img = nullptr;
371 
372     // Get decompressed data
373     while ((img = dec_iter.Next()) != nullptr) {
374       fb_list_.CheckImageFrameBuffer(img);
375     }
376   }
377 
378   libaom_test::CompressedVideoSource *video_;
379   libaom_test::AV1Decoder *decoder_;
380   int num_buffers_;
381   ExternalFrameBufferList fb_list_;
382 };
383 
384 class ExternalFrameBufferNonRefTest : public ExternalFrameBufferTest {
385  protected:
SetUp()386   void SetUp() override {
387     video_ = new libaom_test::IVFVideoSource(kAV1NonRefTestFile);
388     ASSERT_NE(video_, nullptr);
389     video_->Init();
390     video_->Begin();
391 
392     aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t();
393     cfg.allow_lowbitdepth = !FORCE_HIGHBITDEPTH_DECODING;
394     decoder_ = new libaom_test::AV1Decoder(cfg, 0);
395     ASSERT_NE(decoder_, nullptr);
396   }
397 
CheckFrameBufferRelease()398   virtual void CheckFrameBufferRelease() {
399     TearDown();
400     ASSERT_EQ(0, fb_list_.num_used_buffers());
401   }
402 };
403 #endif  // CONFIG_WEBM_IO
404 
405 // This test runs through the set of test vectors, and decodes them.
406 // Libaom will call into the application to allocate a frame buffer when
407 // needed. The md5 checksums are computed for each frame in the video file.
408 // If md5 checksums match the correct md5 data, then the test is passed.
409 // Otherwise, the test failed.
TEST_P(ExternalFrameBufferMD5Test,ExtFBMD5Match)410 TEST_P(ExternalFrameBufferMD5Test, ExtFBMD5Match) {
411   const std::string filename = GET_PARAM(kVideoNameParam);
412   aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t();
413 
414   // Number of buffers equals #AOM_MAXIMUM_REF_BUFFERS +
415   // #AOM_MAXIMUM_WORK_BUFFERS + four jitter buffers.
416   const int jitter_buffers = 4;
417   const int num_buffers =
418       AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS + jitter_buffers;
419   set_num_buffers(num_buffers);
420 
421   // Open compressed video file.
422   std::unique_ptr<libaom_test::CompressedVideoSource> video;
423   if (filename.substr(filename.length() - 3, 3) == "ivf") {
424     video.reset(new libaom_test::IVFVideoSource(filename));
425   } else {
426 #if CONFIG_WEBM_IO
427     video.reset(new libaom_test::WebMVideoSource(filename));
428 #else
429     fprintf(stderr, "WebM IO is disabled, skipping test vector %s\n",
430             filename.c_str());
431     return;
432 #endif
433   }
434   ASSERT_NE(video, nullptr);
435   video->Init();
436 
437   // Construct md5 file name.
438   const std::string md5_filename = filename + ".md5";
439   OpenMD5File(md5_filename);
440 
441   // Set decode config.
442   cfg.allow_lowbitdepth = !FORCE_HIGHBITDEPTH_DECODING;
443   set_cfg(cfg);
444 
445   // Decode frame, and check the md5 matching.
446   ASSERT_NO_FATAL_FAILURE(RunLoop(video.get(), cfg));
447 }
448 
449 #if CONFIG_WEBM_IO
TEST_F(ExternalFrameBufferTest,MinFrameBuffers)450 TEST_F(ExternalFrameBufferTest, MinFrameBuffers) {
451   // Minimum number of external frame buffers for AV1 is
452   // #AOM_MAXIMUM_REF_BUFFERS + #AOM_MAXIMUM_WORK_BUFFERS.
453   const int num_buffers = AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS;
454   ASSERT_EQ(AOM_CODEC_OK,
455             SetFrameBufferFunctions(num_buffers, get_aom_frame_buffer,
456                                     release_aom_frame_buffer));
457   ASSERT_EQ(AOM_CODEC_OK, DecodeRemainingFrames());
458 }
459 
TEST_F(ExternalFrameBufferTest,EightJitterBuffers)460 TEST_F(ExternalFrameBufferTest, EightJitterBuffers) {
461   // Number of buffers equals #AOM_MAXIMUM_REF_BUFFERS +
462   // #AOM_MAXIMUM_WORK_BUFFERS + eight jitter buffers.
463   const int jitter_buffers = 8;
464   const int num_buffers =
465       AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS + jitter_buffers;
466   ASSERT_EQ(AOM_CODEC_OK,
467             SetFrameBufferFunctions(num_buffers, get_aom_frame_buffer,
468                                     release_aom_frame_buffer));
469   ASSERT_EQ(AOM_CODEC_OK, DecodeRemainingFrames());
470 }
471 
TEST_F(ExternalFrameBufferTest,NotEnoughBuffers)472 TEST_F(ExternalFrameBufferTest, NotEnoughBuffers) {
473   // Minimum number of external frame buffers for AV1 is
474   // #AOM_MAXIMUM_REF_BUFFERS + #AOM_MAXIMUM_WORK_BUFFERS. Most files will
475   // only use 5 frame buffers at one time.
476   const int num_buffers = 2;
477   ASSERT_EQ(AOM_CODEC_OK,
478             SetFrameBufferFunctions(num_buffers, get_aom_frame_buffer,
479                                     release_aom_frame_buffer));
480   ASSERT_EQ(AOM_CODEC_OK, DecodeOneFrame());
481   // Only run this on long clips. Decoding a very short clip will return
482   // AOM_CODEC_OK even with only 2 buffers.
483   ASSERT_EQ(AOM_CODEC_MEM_ERROR, DecodeRemainingFrames());
484 }
485 
TEST_F(ExternalFrameBufferTest,NoRelease)486 TEST_F(ExternalFrameBufferTest, NoRelease) {
487   const int num_buffers = AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS;
488   ASSERT_EQ(AOM_CODEC_OK,
489             SetFrameBufferFunctions(num_buffers, get_aom_frame_buffer,
490                                     do_not_release_aom_frame_buffer));
491   ASSERT_EQ(AOM_CODEC_OK, DecodeOneFrame());
492   ASSERT_EQ(AOM_CODEC_MEM_ERROR, DecodeRemainingFrames());
493 }
494 
TEST_F(ExternalFrameBufferTest,NullRealloc)495 TEST_F(ExternalFrameBufferTest, NullRealloc) {
496   const int num_buffers = AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS;
497   ASSERT_EQ(AOM_CODEC_OK,
498             SetFrameBufferFunctions(num_buffers, get_aom_zero_frame_buffer,
499                                     release_aom_frame_buffer));
500   ASSERT_EQ(AOM_CODEC_MEM_ERROR, DecodeOneFrame());
501 }
502 
TEST_F(ExternalFrameBufferTest,ReallocOneLessByte)503 TEST_F(ExternalFrameBufferTest, ReallocOneLessByte) {
504   const int num_buffers = AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS;
505   ASSERT_EQ(AOM_CODEC_OK, SetFrameBufferFunctions(
506                               num_buffers, get_aom_one_less_byte_frame_buffer,
507                               release_aom_frame_buffer));
508   ASSERT_EQ(AOM_CODEC_MEM_ERROR, DecodeOneFrame());
509 }
510 
TEST_F(ExternalFrameBufferTest,NullGetFunction)511 TEST_F(ExternalFrameBufferTest, NullGetFunction) {
512   const int num_buffers = AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS;
513   ASSERT_EQ(
514       AOM_CODEC_INVALID_PARAM,
515       SetFrameBufferFunctions(num_buffers, nullptr, release_aom_frame_buffer));
516 }
517 
TEST_F(ExternalFrameBufferTest,NullReleaseFunction)518 TEST_F(ExternalFrameBufferTest, NullReleaseFunction) {
519   const int num_buffers = AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS;
520   ASSERT_EQ(
521       AOM_CODEC_INVALID_PARAM,
522       SetFrameBufferFunctions(num_buffers, get_aom_frame_buffer, nullptr));
523 }
524 
TEST_F(ExternalFrameBufferTest,SetAfterDecode)525 TEST_F(ExternalFrameBufferTest, SetAfterDecode) {
526   const int num_buffers = AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS;
527   ASSERT_EQ(AOM_CODEC_OK, DecodeOneFrame());
528   ASSERT_EQ(AOM_CODEC_ERROR,
529             SetFrameBufferFunctions(num_buffers, get_aom_frame_buffer,
530                                     release_aom_frame_buffer));
531 }
532 
TEST_F(ExternalFrameBufferNonRefTest,ReleaseNonRefFrameBuffer)533 TEST_F(ExternalFrameBufferNonRefTest, ReleaseNonRefFrameBuffer) {
534   const int num_buffers = AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS;
535   ASSERT_EQ(AOM_CODEC_OK,
536             SetFrameBufferFunctions(num_buffers, get_aom_frame_buffer,
537                                     release_aom_frame_buffer));
538   ASSERT_EQ(AOM_CODEC_OK, DecodeRemainingFrames());
539   CheckFrameBufferRelease();
540 }
541 #endif  // CONFIG_WEBM_IO
542 
543 AV1_INSTANTIATE_TEST_SUITE(
544     ExternalFrameBufferMD5Test,
545     ::testing::ValuesIn(libaom_test::kAV1TestVectors,
546                         libaom_test::kAV1TestVectors +
547                             libaom_test::kNumAV1TestVectors));
548 }  // namespace
549