1/*
2 *  Copyright (c) 2012 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 <string>
12
13#include "third_party/googletest/src/include/gtest/gtest.h"
14
15#include "./vpx_config.h"
16#include "./y4menc.h"
17#include "test/md5_helper.h"
18#include "test/util.h"
19#include "test/y4m_video_source.h"
20
21namespace {
22
23using std::string;
24
25static const unsigned int kWidth  = 160;
26static const unsigned int kHeight = 90;
27static const unsigned int kFrames = 10;
28
29struct Y4mTestParam {
30  const char *filename;
31  unsigned int bit_depth;
32  vpx_img_fmt format;
33  const char *md5raw;
34};
35
36const Y4mTestParam kY4mTestVectors[] = {
37  {"park_joy_90p_8_420.y4m", 8, VPX_IMG_FMT_I420,
38    "e5406275b9fc6bb3436c31d4a05c1cab"},
39  {"park_joy_90p_8_422.y4m", 8, VPX_IMG_FMT_I422,
40    "284a47a47133b12884ec3a14e959a0b6"},
41  {"park_joy_90p_8_444.y4m", 8, VPX_IMG_FMT_I444,
42    "90517ff33843d85de712fd4fe60dbed0"},
43  {"park_joy_90p_10_420.y4m", 10, VPX_IMG_FMT_I42016,
44    "63f21f9f717d8b8631bd2288ee87137b"},
45  {"park_joy_90p_10_422.y4m", 10, VPX_IMG_FMT_I42216,
46    "48ab51fb540aed07f7ff5af130c9b605"},
47  {"park_joy_90p_10_444.y4m", 10, VPX_IMG_FMT_I44416,
48    "067bfd75aa85ff9bae91fa3e0edd1e3e"},
49  {"park_joy_90p_12_420.y4m", 12, VPX_IMG_FMT_I42016,
50    "9e6d8f6508c6e55625f6b697bc461cef"},
51  {"park_joy_90p_12_422.y4m", 12, VPX_IMG_FMT_I42216,
52    "b239c6b301c0b835485be349ca83a7e3"},
53  {"park_joy_90p_12_444.y4m", 12, VPX_IMG_FMT_I44416,
54    "5a6481a550821dab6d0192f5c63845e9"},
55};
56
57static void write_image_file(const vpx_image_t *img, FILE *file) {
58  int plane, y;
59  for (plane = 0; plane < 3; ++plane) {
60    const unsigned char *buf = img->planes[plane];
61    const int stride = img->stride[plane];
62    const int bytes_per_sample = (img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
63    const int h = (plane ? (img->d_h + img->y_chroma_shift) >>
64                   img->y_chroma_shift : img->d_h);
65    const int w = (plane ? (img->d_w + img->x_chroma_shift) >>
66                   img->x_chroma_shift : img->d_w);
67    for (y = 0; y < h; ++y) {
68      fwrite(buf, bytes_per_sample, w, file);
69      buf += stride;
70    }
71  }
72}
73
74class Y4mVideoSourceTest
75    : public ::testing::TestWithParam<Y4mTestParam>,
76      public ::libvpx_test::Y4mVideoSource {
77 protected:
78  Y4mVideoSourceTest() : Y4mVideoSource("", 0, 0) {}
79
80  virtual ~Y4mVideoSourceTest() {
81    CloseSource();
82  }
83
84  virtual void Init(const std::string &file_name, int limit) {
85    file_name_ = file_name;
86    start_ = 0;
87    limit_ = limit;
88    frame_ = 0;
89    Begin();
90  }
91
92  // Checks y4m header information
93  void HeaderChecks(unsigned int bit_depth, vpx_img_fmt_t fmt) {
94    ASSERT_TRUE(input_file_ != NULL);
95    ASSERT_EQ(y4m_.pic_w, (int)kWidth);
96    ASSERT_EQ(y4m_.pic_h, (int)kHeight);
97    ASSERT_EQ(img()->d_w, kWidth);
98    ASSERT_EQ(img()->d_h, kHeight);
99    ASSERT_EQ(y4m_.bit_depth, bit_depth);
100    ASSERT_EQ(y4m_.vpx_fmt, fmt);
101    if (fmt == VPX_IMG_FMT_I420 || fmt == VPX_IMG_FMT_I42016) {
102      ASSERT_EQ(y4m_.bps, (int)y4m_.bit_depth * 3 / 2);
103      ASSERT_EQ(img()->x_chroma_shift, 1U);
104      ASSERT_EQ(img()->y_chroma_shift, 1U);
105    }
106    if (fmt == VPX_IMG_FMT_I422 || fmt == VPX_IMG_FMT_I42216) {
107      ASSERT_EQ(y4m_.bps, (int)y4m_.bit_depth * 2);
108      ASSERT_EQ(img()->x_chroma_shift, 1U);
109      ASSERT_EQ(img()->y_chroma_shift, 0U);
110    }
111    if (fmt == VPX_IMG_FMT_I444 || fmt == VPX_IMG_FMT_I44416) {
112      ASSERT_EQ(y4m_.bps, (int)y4m_.bit_depth * 3);
113      ASSERT_EQ(img()->x_chroma_shift, 0U);
114      ASSERT_EQ(img()->y_chroma_shift, 0U);
115    }
116  }
117
118  // Checks MD5 of the raw frame data
119  void Md5Check(const string &expected_md5) {
120    ASSERT_TRUE(input_file_ != NULL);
121    libvpx_test::MD5 md5;
122    for (unsigned int i = start_; i < limit_; i++) {
123      md5.Add(img());
124      Next();
125    }
126    ASSERT_EQ(string(md5.Get()), expected_md5);
127  }
128};
129
130TEST_P(Y4mVideoSourceTest, SourceTest) {
131  const Y4mTestParam t = GetParam();
132  Init(t.filename, kFrames);
133  HeaderChecks(t.bit_depth, t.format);
134  Md5Check(t.md5raw);
135}
136
137INSTANTIATE_TEST_CASE_P(C, Y4mVideoSourceTest,
138                        ::testing::ValuesIn(kY4mTestVectors));
139
140class Y4mVideoWriteTest
141    : public Y4mVideoSourceTest {
142 protected:
143  Y4mVideoWriteTest() {}
144
145  virtual ~Y4mVideoWriteTest() {
146    delete tmpfile_;
147    input_file_ = NULL;
148  }
149
150  void ReplaceInputFile(FILE *input_file) {
151    CloseSource();
152    frame_ = 0;
153    input_file_ = input_file;
154    rewind(input_file_);
155    ReadSourceToStart();
156  }
157
158  // Writes out a y4m file and then reads it back
159  void WriteY4mAndReadBack() {
160    ASSERT_TRUE(input_file_ != NULL);
161    char buf[Y4M_BUFFER_SIZE] = {0};
162    const struct VpxRational framerate = {y4m_.fps_n, y4m_.fps_d};
163    tmpfile_ = new libvpx_test::TempOutFile;
164    ASSERT_TRUE(tmpfile_->file() != NULL);
165    y4m_write_file_header(buf, sizeof(buf),
166                          kWidth, kHeight,
167                          &framerate, y4m_.vpx_fmt,
168                          y4m_.bit_depth);
169    fputs(buf, tmpfile_->file());
170    for (unsigned int i = start_; i < limit_; i++) {
171      y4m_write_frame_header(buf, sizeof(buf));
172      fputs(buf, tmpfile_->file());
173      write_image_file(img(), tmpfile_->file());
174      Next();
175    }
176    ReplaceInputFile(tmpfile_->file());
177  }
178
179  virtual void Init(const std::string &file_name, int limit) {
180    Y4mVideoSourceTest::Init(file_name, limit);
181    WriteY4mAndReadBack();
182  }
183  libvpx_test::TempOutFile *tmpfile_;
184};
185
186TEST_P(Y4mVideoWriteTest, WriteTest) {
187  const Y4mTestParam t = GetParam();
188  Init(t.filename, kFrames);
189  HeaderChecks(t.bit_depth, t.format);
190  Md5Check(t.md5raw);
191}
192
193INSTANTIATE_TEST_CASE_P(C, Y4mVideoWriteTest,
194                        ::testing::ValuesIn(kY4mTestVectors));
195}  // namespace
196