xref: /aosp_15_r20/external/libgav1/examples/file_writer_test.cc (revision 095378508e87ed692bf8dfeb34008b65b3735891)
1 // Copyright 2021 The libgav1 Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "examples/file_writer.h"
16 
17 #include <cstddef>
18 #include <cstdint>
19 #include <cstring>
20 #include <memory>
21 #include <new>
22 #include <ostream>
23 #include <string>
24 #include <utility>
25 
26 #include "absl/memory/memory.h"
27 #include "gav1/decoder_buffer.h"
28 #include "gtest/gtest.h"
29 #include "tests/utils.h"
30 
31 namespace libgav1 {
32 namespace {
33 
34 const char kExpectedY4mHeader8bit[] = "YUV4MPEG2 W352 H288 F30:1 Ip C420jpeg\n";
35 const char kExpectedY4mHeader10bit[] = "YUV4MPEG2 W352 H288 F30:1 Ip C420p10\n";
36 const char kExpectedY4mHeader8bitMonochrome[] =
37     "YUV4MPEG2 W352 H288 F30:1 Ip Cmono\n";
38 const char kExpectedY4mHeader10bitMonochrome[] =
39     "YUV4MPEG2 W352 H288 F30:1 Ip Cmono10\n";
40 
41 // Note: These are non-const because DecoderBuffer.plane is non-const.
42 char fake_plane0[] = "PLANE0\n";
43 char fake_plane1[] = "PLANE1\n";
44 char fake_plane2[] = "PLANE2\n";
45 
46 constexpr size_t kExpectedRawDataBufferCount = 3;
47 const char* kExpectedRawData[kExpectedRawDataBufferCount] = {
48     fake_plane0, fake_plane1, fake_plane2};
49 
50 const char* const kExpectedRawDataMonochrome = fake_plane0;
51 
52 constexpr size_t kExpectedY4mDataBufferCount = 5;
53 const char* const kExpectedY4mFileData8bit[kExpectedY4mDataBufferCount] = {
54     kExpectedY4mHeader8bit, "FRAME\n", fake_plane0, fake_plane1, fake_plane2};
55 const char* const kExpectedY4mFileData10bit[kExpectedY4mDataBufferCount] = {
56     kExpectedY4mHeader10bit, "FRAME\n", fake_plane0, fake_plane1, fake_plane2};
57 
58 constexpr size_t kExpectedY4mDataBufferCountMonochrome = 3;
59 const char* const
60     kExpectedY4mFileData8bitMonochrome[kExpectedY4mDataBufferCountMonochrome] =
61         {kExpectedY4mHeader8bitMonochrome, "FRAME\n", fake_plane0};
62 const char* const
63     kExpectedY4mFileData10bitMonochrome[kExpectedY4mDataBufferCountMonochrome] =
64         {kExpectedY4mHeader10bitMonochrome, "FRAME\n", fake_plane0};
65 
66 // TODO(tomfinegan): Add a bitdepth arg, and test writing 10 bit frame buffers.
GetFakeDecoderBuffer(ImageFormat image_format)67 std::unique_ptr<DecoderBuffer> GetFakeDecoderBuffer(ImageFormat image_format) {
68   auto buffer = absl::WrapUnique(new (std::nothrow) DecoderBuffer);
69   if (buffer == nullptr) return nullptr;
70   buffer->chroma_sample_position = kChromaSamplePositionUnknown;
71   buffer->image_format = image_format;
72   buffer->bitdepth = 8;
73   buffer->displayed_width[0] = static_cast<int>(strlen(fake_plane0));
74   buffer->displayed_width[1] = static_cast<int>(strlen(fake_plane1));
75   buffer->displayed_width[2] = static_cast<int>(strlen(fake_plane2));
76   buffer->displayed_height[0] = 1;
77   buffer->displayed_height[1] = 1;
78   buffer->displayed_height[2] = 1;
79   buffer->stride[0] = static_cast<int>(strlen(fake_plane0));
80   buffer->stride[1] = static_cast<int>(strlen(fake_plane1));
81   buffer->stride[2] = static_cast<int>(strlen(fake_plane2));
82   buffer->plane[0] = reinterpret_cast<uint8_t*>(fake_plane0);
83   buffer->plane[1] = reinterpret_cast<uint8_t*>(fake_plane1);
84   buffer->plane[2] = reinterpret_cast<uint8_t*>(fake_plane2);
85   buffer->user_private_data = 0;
86   buffer->buffer_private_data = nullptr;
87   return buffer;
88 }
89 
TEST(FileWriterTest,FailOpen)90 TEST(FileWriterTest, FailOpen) {
91   EXPECT_EQ(FileWriter::Open(test_utils::GetTestOutputFilePath("fail_open"),
92                              static_cast<FileWriter::FileType>(3), nullptr),
93             nullptr);
94   EXPECT_EQ(FileWriter::Open(test_utils::GetTestOutputFilePath("fail_open"),
95                              FileWriter::kFileTypeY4m, nullptr),
96             nullptr);
97 }
98 
99 struct FileWriterY4mHeaderTestParameters {
100   FileWriterY4mHeaderTestParameters() = default;
101   FileWriterY4mHeaderTestParameters(const FileWriterY4mHeaderTestParameters&) =
102       default;
103   FileWriterY4mHeaderTestParameters& operator=(
104       const FileWriterY4mHeaderTestParameters&) = default;
105   FileWriterY4mHeaderTestParameters(FileWriterY4mHeaderTestParameters&&) =
106       default;
107   FileWriterY4mHeaderTestParameters& operator=(
108       FileWriterY4mHeaderTestParameters&&) = default;
109   ~FileWriterY4mHeaderTestParameters() = default;
110 
FileWriterY4mHeaderTestParameterslibgav1::__anon51d469d90111::FileWriterY4mHeaderTestParameters111   FileWriterY4mHeaderTestParameters(std::string file_name,
112                                     ChromaSamplePosition chroma_sample_position,
113                                     ImageFormat image_format, int bitdepth,
114                                     const char* expected_header_string)
115       : file_name(std::move(file_name)),
116         chroma_sample_position(chroma_sample_position),
117         image_format(image_format),
118         bitdepth(bitdepth),
119         expected_header_string(expected_header_string) {}
120   std::string file_name;
121   ChromaSamplePosition chroma_sample_position = kChromaSamplePositionUnknown;
122   ImageFormat image_format = kImageFormatMonochrome400;
123   int bitdepth = 8;
124   const char* expected_header_string = nullptr;
125 };
126 
operator <<(std::ostream & stream,const FileWriterY4mHeaderTestParameters & parameters)127 std::ostream& operator<<(std::ostream& stream,
128                          const FileWriterY4mHeaderTestParameters& parameters) {
129   stream << "file_name=" << parameters.file_name << "\n"
130          << "chroma_sample_position=" << parameters.chroma_sample_position
131          << "\n"
132          << "image_format=" << parameters.image_format << "\n"
133          << "bitdepth=" << parameters.bitdepth << "\n"
134          << "expected_header_string=" << parameters.expected_header_string
135          << "\n";
136   return stream;
137 }
138 
139 class FileWriterY4mHeaderTest
140     : public testing::TestWithParam<FileWriterY4mHeaderTestParameters> {
141  public:
FileWriterY4mHeaderTest()142   FileWriterY4mHeaderTest() {
143     test_parameters_ = GetParam();
144     y4m_parameters_.width = 352;
145     y4m_parameters_.height = 288;
146     y4m_parameters_.frame_rate_numerator = 30;
147     y4m_parameters_.frame_rate_denominator = 1;
148     y4m_parameters_.chroma_sample_position =
149         test_parameters_.chroma_sample_position;
150     y4m_parameters_.image_format = test_parameters_.image_format;
151     y4m_parameters_.bitdepth = test_parameters_.bitdepth;
152   }
153   FileWriterY4mHeaderTest(const FileWriterY4mHeaderTest&) = delete;
154   FileWriterY4mHeaderTest& operator=(const FileWriterY4mHeaderTest&) = delete;
155   ~FileWriterY4mHeaderTest() override = default;
156 
157  protected:
158   FileWriterY4mHeaderTestParameters test_parameters_;
159   FileWriter::Y4mParameters y4m_parameters_;
160 };
161 
TEST_P(FileWriterY4mHeaderTest,WriteY4mHeader)162 TEST_P(FileWriterY4mHeaderTest, WriteY4mHeader) {
163   const std::string file_name =
164       test_utils::GetTestOutputFilePath(test_parameters_.file_name);
165   EXPECT_NE(
166       FileWriter::Open(file_name, FileWriter::kFileTypeY4m, &y4m_parameters_),
167       nullptr);
168   std::string y4m_header_string;
169   test_utils::GetTestData(test_parameters_.file_name, true, &y4m_header_string);
170   EXPECT_STREQ(y4m_header_string.c_str(),
171                test_parameters_.expected_header_string);
172 }
173 
174 INSTANTIATE_TEST_SUITE_P(
175     WriteY4mHeader, FileWriterY4mHeaderTest,
176     testing::Values(
177         FileWriterY4mHeaderTestParameters(
178             "y4m_header_8bit", kChromaSamplePositionUnknown, kImageFormatYuv420,
179             /*bitdepth=*/8, kExpectedY4mHeader8bit),
180         FileWriterY4mHeaderTestParameters("y4m_header_10bit",
181                                           kChromaSamplePositionUnknown,
182                                           kImageFormatYuv420, /*bitdepth=*/10,
183                                           kExpectedY4mHeader10bit),
184         FileWriterY4mHeaderTestParameters("y4m_header_8bit_monochrome",
185                                           kChromaSamplePositionUnknown,
186                                           kImageFormatMonochrome400,
187                                           /*bitdepth=*/8,
188                                           kExpectedY4mHeader8bitMonochrome),
189         FileWriterY4mHeaderTestParameters("y4m_header_10bit_monochrome",
190                                           kChromaSamplePositionUnknown,
191                                           kImageFormatMonochrome400,
192                                           /*bitdepth=*/10,
193                                           kExpectedY4mHeader10bitMonochrome)));
194 
195 struct FileWriterTestParameters {
196   FileWriterTestParameters() = default;
197   FileWriterTestParameters(const FileWriterTestParameters&) = default;
198   FileWriterTestParameters& operator=(const FileWriterTestParameters&) =
199       default;
200   FileWriterTestParameters(FileWriterTestParameters&&) = default;
201   FileWriterTestParameters& operator=(FileWriterTestParameters&&) = default;
202   ~FileWriterTestParameters() = default;
203 
FileWriterTestParameterslibgav1::__anon51d469d90111::FileWriterTestParameters204   FileWriterTestParameters(std::string file_name,
205                            FileWriter::FileType file_type,
206                            const FileWriter::Y4mParameters* y4m_parameters,
207                            size_t num_frames)
208       : file_name(std::move(file_name)),
209         file_type(file_type),
210         y4m_parameters(y4m_parameters),
211         num_frames(num_frames) {}
212   std::string file_name;
213   FileWriter::FileType file_type = FileWriter::kFileTypeRaw;
214   const FileWriter::Y4mParameters* y4m_parameters = nullptr;
215   size_t num_frames = 1;
216 };
217 
operator <<(std::ostream & stream,const ChromaSamplePosition & position)218 std::ostream& operator<<(std::ostream& stream,
219                          const ChromaSamplePosition& position) {
220   switch (position) {
221     case kChromaSamplePositionUnknown:
222       stream << "kCromaSamplePositionUnknown";
223       break;
224     case kChromaSamplePositionVertical:
225       stream << "kChromaSamplePositionVertical";
226       break;
227     case kChromaSamplePositionColocated:
228       stream << "kChromaSamplePositionColocated";
229       break;
230     case kChromaSamplePositionReserved:
231       stream << "kChromaSamplePositionReserved";
232       break;
233   }
234   return stream;
235 }
236 
operator <<(std::ostream & stream,const ImageFormat & image_format)237 std::ostream& operator<<(std::ostream& stream,
238                          const ImageFormat& image_format) {
239   switch (image_format) {
240     case kImageFormatMonochrome400:
241       stream << "kImageFormatMonochrome400";
242       break;
243     case kImageFormatYuv420:
244       stream << "kImageFormatYuv420";
245       break;
246     case kImageFormatYuv422:
247       stream << "kImageFormatYuv422";
248       break;
249     case kImageFormatYuv444:
250       stream << "kImageFormatYuv444";
251       break;
252   }
253   return stream;
254 }
255 
operator <<(std::ostream & stream,const FileWriter::Y4mParameters & parameters)256 std::ostream& operator<<(std::ostream& stream,
257                          const FileWriter::Y4mParameters& parameters) {
258   stream << "y4m_parameters:\n"
259          << "  width=" << parameters.width << "\n"
260          << "  height=" << parameters.height << "\n"
261          << "  frame_rate_numerator=" << parameters.frame_rate_numerator << "\n"
262          << "  frame_rate_denominator=" << parameters.frame_rate_denominator
263          << "\n"
264          << "  chroma_sample_position=" << parameters.chroma_sample_position
265          << "\n"
266          << "  image_format=" << parameters.image_format << "\n"
267          << "  bitdepth=" << parameters.bitdepth << "\n";
268 
269   return stream;
270 }
271 
operator <<(std::ostream & stream,const FileWriterTestParameters & parameters)272 std::ostream& operator<<(std::ostream& stream,
273                          const FileWriterTestParameters& parameters) {
274   stream << "file_name=" << parameters.file_name << "\n"
275          << "file_type="
276          << (parameters.file_type == FileWriter::kFileTypeRaw ? "kFileTypeRaw"
277                                                               : "kFileTypeY4m")
278          << "\n";
279   if (parameters.y4m_parameters != nullptr) {
280     stream << *parameters.y4m_parameters;
281   } else {
282     stream << "y4m_parameters: <nullptr>\n";
283   }
284   stream << "num_frames=" << parameters.num_frames << "\n";
285   return stream;
286 }
287 
288 class FileWriterTestBase
289     : public testing::TestWithParam<FileWriterTestParameters> {
290  public:
291   FileWriterTestBase() = default;
292   FileWriterTestBase(const FileWriterTestBase&) = delete;
293   FileWriterTestBase& operator=(const FileWriterTestBase&) = delete;
294   ~FileWriterTestBase() override = default;
295 
296  protected:
SetUp()297   void SetUp() override { OpenWriter(GetParam()); }
298 
OpenWriter(const FileWriterTestParameters & parameters)299   void OpenWriter(const FileWriterTestParameters& parameters) {
300     parameters_ = parameters;
301     parameters_.file_name = parameters.file_name;
302     file_writer_ = FileWriter::Open(
303         test_utils::GetTestOutputFilePath(parameters.file_name),
304         parameters_.file_type, parameters_.y4m_parameters);
305     ASSERT_NE(file_writer_, nullptr);
306   }
307 
WriteFramesAndCloseFile()308   void WriteFramesAndCloseFile() {
309     if (parameters_.y4m_parameters != nullptr) {
310       image_format_ = parameters_.y4m_parameters->image_format;
311     }
312     decoder_buffer_ = GetFakeDecoderBuffer(image_format_);
313     for (size_t frame_num = 0; frame_num < parameters_.num_frames;
314          ++frame_num) {
315       ASSERT_TRUE(file_writer_->WriteFrame(*decoder_buffer_));
316     }
317     file_writer_ = nullptr;
318   }
319 
320   ImageFormat image_format_ = kImageFormatYuv420;
321   FileWriterTestParameters parameters_;
322   std::unique_ptr<FileWriter> file_writer_;
323   std::unique_ptr<DecoderBuffer> decoder_buffer_;
324 };
325 
326 class FileWriterTestRaw : public FileWriterTestBase {
327  public:
328   FileWriterTestRaw() = default;
329   FileWriterTestRaw(const FileWriterTestRaw&) = delete;
330   FileWriterTestRaw& operator=(const FileWriterTestRaw&) = delete;
331   ~FileWriterTestRaw() override = default;
332 
333  protected:
SetUp()334   void SetUp() override { FileWriterTestBase::SetUp(); }
335 };
336 
337 class FileWriterTestY4m : public FileWriterTestBase {
338  public:
339   FileWriterTestY4m() = default;
340   FileWriterTestY4m(const FileWriterTestY4m&) = delete;
341   FileWriterTestY4m& operator=(const FileWriterTestY4m&) = delete;
342   ~FileWriterTestY4m() override = default;
343 
344  protected:
SetUp()345   void SetUp() override { FileWriterTestBase::SetUp(); }
346 };
347 
TEST_P(FileWriterTestRaw,WriteRawFrames)348 TEST_P(FileWriterTestRaw, WriteRawFrames) {
349   WriteFramesAndCloseFile();
350 
351   std::string actual_file_data;
352   test_utils::GetTestData(parameters_.file_name, true, &actual_file_data);
353 
354   std::string expected_file_data;
355   for (size_t frame_num = 0; frame_num < parameters_.num_frames; ++frame_num) {
356     if (image_format_ == kImageFormatMonochrome400) {
357       expected_file_data += kExpectedRawDataMonochrome;
358     } else {
359       for (const auto& buffer : kExpectedRawData) {
360         expected_file_data += buffer;
361       }
362     }
363   }
364 
365   ASSERT_EQ(actual_file_data, expected_file_data);
366 }
367 
TEST_P(FileWriterTestY4m,WriteY4mFrames)368 TEST_P(FileWriterTestY4m, WriteY4mFrames) {
369   WriteFramesAndCloseFile();
370 
371   std::string actual_file_data;
372   test_utils::GetTestData(parameters_.file_name, true, &actual_file_data);
373 
374   std::string expected_file_data;
375   for (size_t frame_num = 0; frame_num < parameters_.num_frames; ++frame_num) {
376     if (image_format_ == kImageFormatMonochrome400) {
377       const char* const* expected_data_planes =
378           (parameters_.y4m_parameters->bitdepth == 8)
379               ? kExpectedY4mFileData8bitMonochrome
380               : kExpectedY4mFileData10bitMonochrome;
381       // Skip the Y4M file header "plane" after frame 0.
382       for (size_t buffer_num = (frame_num == 0) ? 0 : 1;
383            buffer_num < kExpectedY4mDataBufferCountMonochrome; ++buffer_num) {
384         expected_file_data += expected_data_planes[buffer_num];
385       }
386     } else {
387       const char* const* expected_data_planes =
388           (parameters_.y4m_parameters->bitdepth == 8)
389               ? kExpectedY4mFileData8bit
390               : kExpectedY4mFileData10bit;
391 
392       // Skip the Y4M file header "plane" after frame 0.
393       for (size_t buffer_num = (frame_num == 0) ? 0 : 1;
394            buffer_num < kExpectedY4mDataBufferCount; ++buffer_num) {
395         expected_file_data += expected_data_planes[buffer_num];
396       }
397     }
398   }
399 
400   ASSERT_EQ(actual_file_data, expected_file_data);
401 }
402 
403 INSTANTIATE_TEST_SUITE_P(
404     WriteRawFrames, FileWriterTestRaw,
405     testing::Values(
406         FileWriterTestParameters("raw_frames_test_1frame",
407                                  FileWriter::kFileTypeRaw,
408                                  /*y4m_parameters=*/nullptr,
409                                  /*num_frames=*/1),
410         FileWriterTestParameters("raw_frames_test_5frames",
411                                  FileWriter::kFileTypeRaw,
412                                  /*y4m_parameters=*/nullptr,
413                                  /*num_frames=*/5),
414         FileWriterTestParameters("raw_frames_test_1frame_monochrome",
415                                  FileWriter::kFileTypeRaw,
416                                  /*y4m_parameters=*/nullptr,
417                                  /*num_frames=*/1),
418         FileWriterTestParameters("raw_frames_test_5frames_monochrome",
419                                  FileWriter::kFileTypeRaw,
420                                  /*y4m_parameters=*/nullptr,
421                                  /*num_frames=*/5)));
422 
423 const FileWriter::Y4mParameters kY4mParameters8Bit = {
424     352,  // width
425     288,  // height
426     30,   // frame_rate_numerator
427     1,    // frame_rate_denominator
428     kChromaSamplePositionUnknown,
429     kImageFormatYuv420,
430     8  // bitdepth
431 };
432 
433 const FileWriter::Y4mParameters kY4mParameters10Bit = {
434     352,  // width
435     288,  // height
436     30,   // frame_rate_numerator
437     1,    // frame_rate_denominator
438     kChromaSamplePositionUnknown,
439     kImageFormatYuv420,
440     10  // bitdepth
441 };
442 
443 const FileWriter::Y4mParameters kY4mParameters8BitMonochrome = {
444     352,  // width
445     288,  // height
446     30,   // frame_rate_numerator
447     1,    // frame_rate_denominator
448     kChromaSamplePositionUnknown,
449     kImageFormatMonochrome400,
450     8  // bitdepth
451 };
452 
453 const FileWriter::Y4mParameters kY4mParameters10BitMonochrome = {
454     352,  // width
455     288,  // height
456     30,   // frame_rate_numerator
457     1,    // frame_rate_denominator
458     kChromaSamplePositionUnknown,
459     kImageFormatMonochrome400,
460     10  // bitdepth
461 };
462 
463 INSTANTIATE_TEST_SUITE_P(
464     WriteY4mFrames, FileWriterTestY4m,
465     testing::Values(
466         FileWriterTestParameters("y4m_frames_test_8bit_1frame",
467                                  FileWriter::kFileTypeY4m, &kY4mParameters8Bit,
468                                  /*num_frames=*/1),
469         FileWriterTestParameters("y4m_frames_test_8bit_5frames",
470                                  FileWriter::kFileTypeY4m, &kY4mParameters8Bit,
471                                  /*num_frames=*/5),
472         FileWriterTestParameters("y4m_frames_test_10bit_1frame",
473                                  FileWriter::kFileTypeY4m, &kY4mParameters10Bit,
474                                  /*num_frames=*/1),
475         FileWriterTestParameters("y4m_frames_test_10bit_5frames",
476                                  FileWriter::kFileTypeY4m, &kY4mParameters10Bit,
477                                  /*num_frames=*/5),
478         FileWriterTestParameters("y4m_frames_test_8bit_1frame_monochrome",
479                                  FileWriter::kFileTypeY4m,
480                                  &kY4mParameters8BitMonochrome,
481                                  /*num_frames=*/1),
482         FileWriterTestParameters("y4m_frames_test_8bit_5frames_monochrome",
483                                  FileWriter::kFileTypeY4m,
484                                  &kY4mParameters8BitMonochrome,
485                                  /*num_frames=*/5),
486         FileWriterTestParameters("y4m_frames_test_10bit_1frame_monochrome",
487                                  FileWriter::kFileTypeY4m,
488                                  &kY4mParameters10BitMonochrome,
489                                  /*num_frames=*/1),
490         FileWriterTestParameters("y4m_frames_test_10bit_5frames_monochrome",
491                                  FileWriter::kFileTypeY4m,
492                                  &kY4mParameters10BitMonochrome,
493                                  /*num_frames=*/5)));
494 
495 }  // namespace
496 }  // namespace libgav1
497