encode_test_driver.cc 6.84 KB
Newer Older
John Koleszar's avatar
John Koleszar committed
1
2
3
4
5
6
7
8
9
/*
 *  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.
 */
10

11
#include "vpx_config.h"
12
#include "test/codec_factory.h"
John Koleszar's avatar
John Koleszar committed
13
#include "test/encode_test_driver.h"
14
#include "test/decode_test_driver.h"
15
#include "test/register_state_check.h"
John Koleszar's avatar
John Koleszar committed
16
17
18
19
#include "test/video_source.h"
#include "third_party/googletest/src/include/gtest/gtest.h"

namespace libvpx_test {
20
void Encoder::EncodeFrame(VideoSource *video, const unsigned long frame_flags) {
John Koleszar's avatar
John Koleszar committed
21
  if (video->img())
22
    EncodeFrameInternal(*video, frame_flags);
John Koleszar's avatar
John Koleszar committed
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  else
    Flush();

  // Handle twopass stats
  CxDataIterator iter = GetCxData();

  while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) {
    if (pkt->kind != VPX_CODEC_STATS_PKT)
      continue;

    stats_->Append(*pkt);
  }
}

void Encoder::EncodeFrameInternal(const VideoSource &video,
38
                                  const unsigned long frame_flags) {
John Koleszar's avatar
John Koleszar committed
39
40
41
42
43
44
45
46
47
  vpx_codec_err_t res;
  const vpx_image_t *img = video.img();

  // Handle first frame initialization
  if (!encoder_.priv) {
    cfg_.g_w = img->d_w;
    cfg_.g_h = img->d_h;
    cfg_.g_timebase = video.timebase();
    cfg_.rc_twopass_stats_in = stats_->buf();
48
    res = vpx_codec_enc_init(&encoder_, CodecInterface(), &cfg_,
49
                             init_flags_);
John Koleszar's avatar
John Koleszar committed
50
51
52
53
54
55
56
57
58
59
60
61
    ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
  }

  // Handle frame resizing
  if (cfg_.g_w != img->d_w || cfg_.g_h != img->d_h) {
    cfg_.g_w = img->d_w;
    cfg_.g_h = img->d_h;
    res = vpx_codec_enc_config_set(&encoder_, &cfg_);
    ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
  }

  // Encode the frame
62
63
64
65
  REGISTER_STATE_CHECK(
      res = vpx_codec_encode(&encoder_,
                             video.img(), video.pts(), video.duration(),
                             frame_flags, deadline_));
John Koleszar's avatar
John Koleszar committed
66
67
68
69
70
71
72
73
74
  ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}

void Encoder::Flush() {
  const vpx_codec_err_t res = vpx_codec_encode(&encoder_, NULL, 0, 0, 0,
                                               deadline_);
  ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}

75
76
77
78
79
void EncoderTest::InitializeConfig() {
  const vpx_codec_err_t res = codec_->DefaultEncoderConfig(&cfg_, 0);
  ASSERT_EQ(VPX_CODEC_OK, res);
}

John Koleszar's avatar
John Koleszar committed
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
void EncoderTest::SetMode(TestMode mode) {
  switch (mode) {
    case kRealTime:
      deadline_ = VPX_DL_REALTIME;
      break;

    case kOnePassGood:
    case kTwoPassGood:
      deadline_ = VPX_DL_GOOD_QUALITY;
      break;

    case kOnePassBest:
    case kTwoPassBest:
      deadline_ = VPX_DL_BEST_QUALITY;
      break;

    default:
      ASSERT_TRUE(false) << "Unexpected mode " << mode;
  }

  if (mode == kTwoPassGood || mode == kTwoPassBest)
    passes_ = 2;
  else
    passes_ = 1;
}
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// The function should return "true" most of the time, therefore no early
// break-out is implemented within the match checking process.
static bool compare_img(const vpx_image_t *img1,
                        const vpx_image_t *img2) {
  bool match = (img1->fmt == img2->fmt) &&
               (img1->d_w == img2->d_w) &&
               (img1->d_h == img2->d_h);

  const unsigned int width_y  = img1->d_w;
  const unsigned int height_y = img1->d_h;
  unsigned int i;
  for (i = 0; i < height_y; ++i)
    match = ( memcmp(img1->planes[VPX_PLANE_Y] + i * img1->stride[VPX_PLANE_Y],
                     img2->planes[VPX_PLANE_Y] + i * img2->stride[VPX_PLANE_Y],
                     width_y) == 0) && match;
  const unsigned int width_uv  = (img1->d_w + 1) >> 1;
  const unsigned int height_uv = (img1->d_h + 1) >> 1;
  for (i = 0; i <  height_uv; ++i)
    match = ( memcmp(img1->planes[VPX_PLANE_U] + i * img1->stride[VPX_PLANE_U],
                     img2->planes[VPX_PLANE_U] + i * img2->stride[VPX_PLANE_U],
                     width_uv) == 0) && match;
  for (i = 0; i < height_uv; ++i)
    match = ( memcmp(img1->planes[VPX_PLANE_V] + i * img1->stride[VPX_PLANE_V],
                     img2->planes[VPX_PLANE_V] + i * img2->stride[VPX_PLANE_V],
                     width_uv) == 0) && match;
  return match;
}
John Koleszar's avatar
John Koleszar committed
132

133
134
135
136
137
void EncoderTest::MismatchHook(const vpx_image_t *img1,
                               const vpx_image_t *img2) {
  ASSERT_TRUE(0) << "Encode/Decode mismatch found";
}

John Koleszar's avatar
John Koleszar committed
138
void EncoderTest::RunLoop(VideoSource *video) {
139
  vpx_codec_dec_cfg_t dec_cfg = {0};
140
141
142

  stats_.Reset();

143
  ASSERT_TRUE(passes_ == 1 || passes_ == 2);
John Koleszar's avatar
John Koleszar committed
144
  for (unsigned int pass = 0; pass < passes_; pass++) {
145
146
    last_pts_ = 0;

John Koleszar's avatar
John Koleszar committed
147
148
149
150
151
152
153
154
    if (passes_ == 1)
      cfg_.g_pass = VPX_RC_ONE_PASS;
    else if (pass == 0)
      cfg_.g_pass = VPX_RC_FIRST_PASS;
    else
      cfg_.g_pass = VPX_RC_LAST_PASS;

    BeginPassHook(pass);
155
156
157
158
    Encoder* const encoder = codec_->CreateEncoder(cfg_, deadline_, init_flags_,
                                                   &stats_);
    ASSERT_TRUE(encoder != NULL);
    Decoder* const decoder = codec_->CreateDecoder(dec_cfg, 0);
John Koleszar's avatar
John Koleszar committed
159
    bool again;
Jim Bankoski's avatar
Jim Bankoski committed
160
    for (again = true, video->Begin(); again; video->Next()) {
161
      again = (video->img() != NULL);
John Koleszar's avatar
John Koleszar committed
162
163

      PreEncodeFrameHook(video);
164
165
      PreEncodeFrameHook(video, encoder);
      encoder->EncodeFrame(video, frame_flags_);
John Koleszar's avatar
John Koleszar committed
166

167
      CxDataIterator iter = encoder->GetCxData();
John Koleszar's avatar
John Koleszar committed
168

169
170
      bool has_cxdata = false;
      bool has_dxdata = false;
John Koleszar's avatar
John Koleszar committed
171
      while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) {
John Koleszar's avatar
John Koleszar committed
172
        pkt = MutateEncoderOutputHook(pkt);
John Koleszar's avatar
John Koleszar committed
173
        again = true;
174
175
176
        switch (pkt->kind) {
          case VPX_CODEC_CX_FRAME_PKT:
            has_cxdata = true;
177
            if (decoder && DoDecode()) {
178
179
180
              vpx_codec_err_t res_dec = decoder->DecodeFrame(
                  (const uint8_t*)pkt->data.frame.buf, pkt->data.frame.sz);
              ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder->DecodeError();
181
182
              has_dxdata = true;
            }
183
184
185
186
187
188
189
190
191
192
193
194
            ASSERT_GE(pkt->data.frame.pts, last_pts_);
            last_pts_ = pkt->data.frame.pts;
            FramePktHook(pkt);
            break;

          case VPX_CODEC_PSNR_PKT:
            PSNRPktHook(pkt);
            break;

          default:
            break;
        }
John Koleszar's avatar
John Koleszar committed
195
196
      }

197
      if (has_dxdata && has_cxdata) {
198
199
        const vpx_image_t *img_enc = encoder->GetPreviewFrame();
        DxDataIterator dec_iter = decoder->GetDxData();
200
        const vpx_image_t *img_dec = dec_iter.Next();
201
        if (img_enc && img_dec) {
202
          const bool res = compare_img(img_enc, img_dec);
203
204
205
          if (!res) {  // Mismatch
            MismatchHook(img_enc, img_dec);
          }
206
        }
207
208
        if (img_dec)
          DecompressedFrameHook(*img_dec, video->pts());
209
      }
John Koleszar's avatar
John Koleszar committed
210
211
212
213
214
215
      if (!Continue())
        break;
    }

    EndPassHook();

216
217
218
219
    if (decoder)
      delete decoder;
    delete encoder;

John Koleszar's avatar
John Koleszar committed
220
221
222
223
    if (!Continue())
      break;
  }
}
224

John Koleszar's avatar
John Koleszar committed
225
}  // namespace libvpx_test