resize_test.cc 7.98 KB
Newer Older
John Koleszar's avatar
John Koleszar committed
1
2
3
4
5
6
7
8
9
10
11
/*
 *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#include <climits>
#include <vector>
12
13
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
John Koleszar's avatar
John Koleszar committed
14
#include "test/encode_test_driver.h"
15
#include "test/i420_video_source.h"
John Koleszar's avatar
John Koleszar committed
16
#include "test/video_source.h"
17
#include "test/util.h"
John Koleszar's avatar
John Koleszar committed
18

19
20
21
// Enable(1) or Disable(0) writing of the compressed bitstream.
#define WRITE_COMPRESSED_STREAM 0

John Koleszar's avatar
John Koleszar committed
22
23
namespace {

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#if WRITE_COMPRESSED_STREAM
static void mem_put_le16(char *const mem, const unsigned int val) {
  mem[0] = val;
  mem[1] = val >> 8;
}

static void mem_put_le32(char *const mem, const unsigned int val) {
  mem[0] = val;
  mem[1] = val >> 8;
  mem[2] = val >> 16;
  mem[3] = val >> 24;
}

static void write_ivf_file_header(const vpx_codec_enc_cfg_t *const cfg,
                                  int frame_cnt, FILE *const outfile) {
  char header[32];

  header[0] = 'D';
  header[1] = 'K';
  header[2] = 'I';
  header[3] = 'F';
  mem_put_le16(header + 4,  0);                   /* version */
  mem_put_le16(header + 6,  32);                  /* headersize */
  mem_put_le32(header + 8,  0x30395056);          /* fourcc (vp9) */
  mem_put_le16(header + 12, cfg->g_w);            /* width */
  mem_put_le16(header + 14, cfg->g_h);            /* height */
  mem_put_le32(header + 16, cfg->g_timebase.den); /* rate */
  mem_put_le32(header + 20, cfg->g_timebase.num); /* scale */
  mem_put_le32(header + 24, frame_cnt);           /* length */
  mem_put_le32(header + 28, 0);                   /* unused */

  (void)fwrite(header, 1, 32, outfile);
}

static void write_ivf_frame_size(FILE *const outfile, const size_t size) {
  char header[4];
  mem_put_le32(header, static_cast<unsigned int>(size));
  (void)fwrite(header, 1, 4, outfile);
}

static void write_ivf_frame_header(const vpx_codec_cx_pkt_t *const pkt,
                                   FILE *const outfile) {
  char header[12];
  vpx_codec_pts_t pts;

  if (pkt->kind != VPX_CODEC_CX_FRAME_PKT)
    return;

  pts = pkt->data.frame.pts;
  mem_put_le32(header, static_cast<unsigned int>(pkt->data.frame.sz));
  mem_put_le32(header + 4, pts & 0xFFFFFFFF);
  mem_put_le32(header + 8, pts >> 32);

  (void)fwrite(header, 1, 12, outfile);
}
#endif  // WRITE_COMPRESSED_STREAM

John Koleszar's avatar
John Koleszar committed
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
const unsigned int kInitialWidth = 320;
const unsigned int kInitialHeight = 240;

unsigned int ScaleForFrameNumber(unsigned int frame, unsigned int val) {
  if (frame < 10)
    return val;
  if (frame < 20)
    return val / 2;
  if (frame < 30)
    return val * 2 / 3;
  if (frame < 40)
    return val / 4;
  if (frame < 50)
    return val * 7 / 8;
  return val;
}

class ResizingVideoSource : public ::libvpx_test::DummyVideoSource {
 public:
  ResizingVideoSource() {
    SetSize(kInitialWidth, kInitialHeight);
    limit_ = 60;
  }

105
106
  virtual ~ResizingVideoSource() {}

John Koleszar's avatar
John Koleszar committed
107
108
109
110
111
112
113
114
115
116
 protected:
  virtual void Next() {
    ++frame_;
    SetSize(ScaleForFrameNumber(frame_, kInitialWidth),
            ScaleForFrameNumber(frame_, kInitialHeight));
    FillFrame();
  }
};

class ResizeTest : public ::libvpx_test::EncoderTest,
117
  public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
John Koleszar's avatar
John Koleszar committed
118
 protected:
119
120
  ResizeTest() : EncoderTest(GET_PARAM(0)) {}

121
122
  virtual ~ResizeTest() {}

John Koleszar's avatar
John Koleszar committed
123
124
125
126
127
  struct FrameInfo {
    FrameInfo(vpx_codec_pts_t _pts, unsigned int _w, unsigned int _h)
        : pts(_pts), w(_w), h(_h) {}

    vpx_codec_pts_t pts;
128
129
    unsigned int w;
    unsigned int h;
John Koleszar's avatar
John Koleszar committed
130
131
132
133
  };

  virtual void SetUp() {
    InitializeConfig();
134
    SetMode(GET_PARAM(1));
John Koleszar's avatar
John Koleszar committed
135
136
  }

137
138
139
  virtual void DecompressedFrameHook(const vpx_image_t &img,
                                     vpx_codec_pts_t pts) {
    frame_info_list_.push_back(FrameInfo(pts, img.d_w, img.d_h));
John Koleszar's avatar
John Koleszar committed
140
141
142
143
144
145
146
147
148
  }

  std::vector< FrameInfo > frame_info_list_;
};

TEST_P(ResizeTest, TestExternalResizeWorks) {
  ResizingVideoSource video;
  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));

149
  for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
John Koleszar's avatar
John Koleszar committed
150
       info != frame_info_list_.end(); ++info) {
James Zern's avatar
James Zern committed
151
152
153
    const unsigned int frame = static_cast<unsigned>(info->pts);
    const unsigned int expected_w = ScaleForFrameNumber(frame, kInitialWidth);
    const unsigned int expected_h = ScaleForFrameNumber(frame, kInitialHeight);
John Koleszar's avatar
John Koleszar committed
154
155

    EXPECT_EQ(expected_w, info->w)
James Zern's avatar
James Zern committed
156
        << "Frame " << frame << "had unexpected width";
John Koleszar's avatar
John Koleszar committed
157
    EXPECT_EQ(expected_h, info->h)
James Zern's avatar
James Zern committed
158
        << "Frame " << frame << "had unexpected height";
John Koleszar's avatar
John Koleszar committed
159
160
161
  }
}

162
163
164
const unsigned int kStepDownFrame = 3;
const unsigned int kStepUpFrame = 6;

165
166
class ResizeInternalTest : public ResizeTest {
 protected:
167
168
169
170
171
172
173
#if WRITE_COMPRESSED_STREAM
  ResizeInternalTest()
      : ResizeTest(),
        frame0_psnr_(0.0),
        outfile_(NULL),
        out_frames_(0) {}
#else
174
  ResizeInternalTest() : ResizeTest(), frame0_psnr_(0.0) {}
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#endif

  virtual ~ResizeInternalTest() {}

  virtual void BeginPassHook(unsigned int /*pass*/) {
#if WRITE_COMPRESSED_STREAM
    outfile_ = fopen("vp90-2-05-resize.ivf", "wb");
#endif
  }

  virtual void EndPassHook() {
#if WRITE_COMPRESSED_STREAM
    if (outfile_) {
      if (!fseek(outfile_, 0, SEEK_SET))
        write_ivf_file_header(&cfg_, out_frames_, outfile_);
      fclose(outfile_);
      outfile_ = NULL;
    }
#endif
  }
195
196
197

  virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
                                  libvpx_test::Encoder *encoder) {
198
    if (video->frame() == kStepDownFrame) {
199
200
201
      struct vpx_scaling_mode mode = {VP8E_FOURFIVE, VP8E_THREEFIVE};
      encoder->Control(VP8E_SET_SCALEMODE, &mode);
    }
202
    if (video->frame() == kStepUpFrame) {
203
204
205
      struct vpx_scaling_mode mode = {VP8E_NORMAL, VP8E_NORMAL};
      encoder->Control(VP8E_SET_SCALEMODE, &mode);
    }
206
  }
207
208
209
210

  virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) {
    if (!frame0_psnr_)
      frame0_psnr_ = pkt->data.psnr.psnr[0];
211
    EXPECT_NEAR(pkt->data.psnr.psnr[0], frame0_psnr_, 2.0);
212
213
  }

214
215
216
217
218
219
220
221
222
223
224
225
226
227
  virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
#if WRITE_COMPRESSED_STREAM
    ++out_frames_;

    // Write initial file header if first frame.
    if (pkt->data.frame.pts == 0)
      write_ivf_file_header(&cfg_, 0, outfile_);

    // Write frame header and data.
    write_ivf_frame_header(pkt, outfile_);
    (void)fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_);
#endif
  }

228
  double frame0_psnr_;
229
230
231
232
#if WRITE_COMPRESSED_STREAM
  FILE *outfile_;
  unsigned int out_frames_;
#endif
233
234
235
236
};

TEST_P(ResizeInternalTest, TestInternalResizeWorks) {
  ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
237
238
                                       30, 1, 0, 10);
  init_flags_ = VPX_CODEC_USE_PSNR;
239

240
241
242
  // q picked such that initial keyframe on this clip is ~30dB PSNR
  cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = 48;

243
244
245
246
247
  // If the number of frames being encoded is smaller than g_lag_in_frames
  // the encoded frame is unavailable using the current API. Comparing
  // frames to detect mismatch would then not be possible. Set
  // g_lag_in_frames = 0 to get around this.
  cfg_.g_lag_in_frames = 0;
248
249
  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));

250
  for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
251
252
       info != frame_info_list_.end(); ++info) {
    const vpx_codec_pts_t pts = info->pts;
253
    if (pts >= kStepDownFrame && pts < kStepUpFrame) {
254
255
256
257
258
259
260
261
262
      ASSERT_EQ(282U, info->w) << "Frame " << pts << " had unexpected width";
      ASSERT_EQ(173U, info->h) << "Frame " << pts << " had unexpected height";
    } else {
      EXPECT_EQ(352U, info->w) << "Frame " << pts << " had unexpected width";
      EXPECT_EQ(288U, info->h) << "Frame " << pts << " had unexpected height";
    }
  }
}

263
VP8_INSTANTIATE_TEST_CASE(ResizeTest, ONE_PASS_TEST_MODES);
264
265
VP9_INSTANTIATE_TEST_CASE(ResizeInternalTest,
                          ::testing::Values(::libvpx_test::kOnePassBest));
John Koleszar's avatar
John Koleszar committed
266
}  // namespace