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

Yaowu Xu's avatar
Yaowu Xu committed
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
  API_REGISTER_STATE_CHECK(
63 64 65
      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
// 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)
Yaowu Xu's avatar
Yaowu Xu committed
117 118 119
    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;
120 121 122
  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)
Yaowu Xu's avatar
Yaowu Xu committed
123 124 125
    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;
126
  for (i = 0; i < height_uv; ++i)
Yaowu Xu's avatar
Yaowu Xu committed
127 128 129
    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;
130 131
  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