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