1233d2500723e5594f3e7c70896ffeeef32b9c950ywan/*
2233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
3233d2500723e5594f3e7c70896ffeeef32b9c950ywan *
4233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  Use of this source code is governed by a BSD-style license
5233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  that can be found in the LICENSE file in the root of the source
6233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  tree. An additional intellectual property rights grant can be found
7233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  in the file PATENTS.  All contributing project authors may
8233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  be found in the AUTHORS file in the root of the source tree.
9233d2500723e5594f3e7c70896ffeeef32b9c950ywan */
10233d2500723e5594f3e7c70896ffeeef32b9c950ywan
11233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "./vpx_config.h"
12233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "test/codec_factory.h"
13233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "test/encode_test_driver.h"
14233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "test/decode_test_driver.h"
15233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "test/register_state_check.h"
16233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "test/video_source.h"
17233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "third_party/googletest/src/include/gtest/gtest.h"
18233d2500723e5594f3e7c70896ffeeef32b9c950ywan
19233d2500723e5594f3e7c70896ffeeef32b9c950ywannamespace libvpx_test {
20233d2500723e5594f3e7c70896ffeeef32b9c950ywanvoid Encoder::EncodeFrame(VideoSource *video, const unsigned long frame_flags) {
21233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (video->img())
22233d2500723e5594f3e7c70896ffeeef32b9c950ywan    EncodeFrameInternal(*video, frame_flags);
23233d2500723e5594f3e7c70896ffeeef32b9c950ywan  else
24233d2500723e5594f3e7c70896ffeeef32b9c950ywan    Flush();
25233d2500723e5594f3e7c70896ffeeef32b9c950ywan
26233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Handle twopass stats
27233d2500723e5594f3e7c70896ffeeef32b9c950ywan  CxDataIterator iter = GetCxData();
28233d2500723e5594f3e7c70896ffeeef32b9c950ywan
29233d2500723e5594f3e7c70896ffeeef32b9c950ywan  while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) {
30233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (pkt->kind != VPX_CODEC_STATS_PKT)
31233d2500723e5594f3e7c70896ffeeef32b9c950ywan      continue;
32233d2500723e5594f3e7c70896ffeeef32b9c950ywan
33233d2500723e5594f3e7c70896ffeeef32b9c950ywan    stats_->Append(*pkt);
34233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
35233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
36233d2500723e5594f3e7c70896ffeeef32b9c950ywan
37233d2500723e5594f3e7c70896ffeeef32b9c950ywanvoid Encoder::EncodeFrameInternal(const VideoSource &video,
38233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                  const unsigned long frame_flags) {
39233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_codec_err_t res;
40233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const vpx_image_t *img = video.img();
41233d2500723e5594f3e7c70896ffeeef32b9c950ywan
42233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Handle first frame initialization
43233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!encoder_.priv) {
44233d2500723e5594f3e7c70896ffeeef32b9c950ywan    cfg_.g_w = img->d_w;
45233d2500723e5594f3e7c70896ffeeef32b9c950ywan    cfg_.g_h = img->d_h;
46233d2500723e5594f3e7c70896ffeeef32b9c950ywan    cfg_.g_timebase = video.timebase();
47233d2500723e5594f3e7c70896ffeeef32b9c950ywan    cfg_.rc_twopass_stats_in = stats_->buf();
48233d2500723e5594f3e7c70896ffeeef32b9c950ywan    res = vpx_codec_enc_init(&encoder_, CodecInterface(), &cfg_,
49233d2500723e5594f3e7c70896ffeeef32b9c950ywan                             init_flags_);
50233d2500723e5594f3e7c70896ffeeef32b9c950ywan    ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
51233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
52233d2500723e5594f3e7c70896ffeeef32b9c950ywan
53233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Handle frame resizing
54233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (cfg_.g_w != img->d_w || cfg_.g_h != img->d_h) {
55233d2500723e5594f3e7c70896ffeeef32b9c950ywan    cfg_.g_w = img->d_w;
56233d2500723e5594f3e7c70896ffeeef32b9c950ywan    cfg_.g_h = img->d_h;
57233d2500723e5594f3e7c70896ffeeef32b9c950ywan    res = vpx_codec_enc_config_set(&encoder_, &cfg_);
58233d2500723e5594f3e7c70896ffeeef32b9c950ywan    ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
59233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
60233d2500723e5594f3e7c70896ffeeef32b9c950ywan
61233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Encode the frame
62233d2500723e5594f3e7c70896ffeeef32b9c950ywan  REGISTER_STATE_CHECK(
63233d2500723e5594f3e7c70896ffeeef32b9c950ywan      res = vpx_codec_encode(&encoder_,
64233d2500723e5594f3e7c70896ffeeef32b9c950ywan                             video.img(), video.pts(), video.duration(),
65233d2500723e5594f3e7c70896ffeeef32b9c950ywan                             frame_flags, deadline_));
66233d2500723e5594f3e7c70896ffeeef32b9c950ywan  ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
67233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
68233d2500723e5594f3e7c70896ffeeef32b9c950ywan
69233d2500723e5594f3e7c70896ffeeef32b9c950ywanvoid Encoder::Flush() {
70233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const vpx_codec_err_t res = vpx_codec_encode(&encoder_, NULL, 0, 0, 0,
71233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                               deadline_);
72233d2500723e5594f3e7c70896ffeeef32b9c950ywan  ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
73233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
74233d2500723e5594f3e7c70896ffeeef32b9c950ywan
75233d2500723e5594f3e7c70896ffeeef32b9c950ywanvoid EncoderTest::InitializeConfig() {
76233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const vpx_codec_err_t res = codec_->DefaultEncoderConfig(&cfg_, 0);
77233d2500723e5594f3e7c70896ffeeef32b9c950ywan  ASSERT_EQ(VPX_CODEC_OK, res);
78233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
79233d2500723e5594f3e7c70896ffeeef32b9c950ywan
80233d2500723e5594f3e7c70896ffeeef32b9c950ywanvoid EncoderTest::SetMode(TestMode mode) {
81233d2500723e5594f3e7c70896ffeeef32b9c950ywan  switch (mode) {
82233d2500723e5594f3e7c70896ffeeef32b9c950ywan    case kRealTime:
83233d2500723e5594f3e7c70896ffeeef32b9c950ywan      deadline_ = VPX_DL_REALTIME;
84233d2500723e5594f3e7c70896ffeeef32b9c950ywan      break;
85233d2500723e5594f3e7c70896ffeeef32b9c950ywan
86233d2500723e5594f3e7c70896ffeeef32b9c950ywan    case kOnePassGood:
87233d2500723e5594f3e7c70896ffeeef32b9c950ywan    case kTwoPassGood:
88233d2500723e5594f3e7c70896ffeeef32b9c950ywan      deadline_ = VPX_DL_GOOD_QUALITY;
89233d2500723e5594f3e7c70896ffeeef32b9c950ywan      break;
90233d2500723e5594f3e7c70896ffeeef32b9c950ywan
91233d2500723e5594f3e7c70896ffeeef32b9c950ywan    case kOnePassBest:
92233d2500723e5594f3e7c70896ffeeef32b9c950ywan    case kTwoPassBest:
93233d2500723e5594f3e7c70896ffeeef32b9c950ywan      deadline_ = VPX_DL_BEST_QUALITY;
94233d2500723e5594f3e7c70896ffeeef32b9c950ywan      break;
95233d2500723e5594f3e7c70896ffeeef32b9c950ywan
96233d2500723e5594f3e7c70896ffeeef32b9c950ywan    default:
97233d2500723e5594f3e7c70896ffeeef32b9c950ywan      ASSERT_TRUE(false) << "Unexpected mode " << mode;
98233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
99233d2500723e5594f3e7c70896ffeeef32b9c950ywan
100233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (mode == kTwoPassGood || mode == kTwoPassBest)
101233d2500723e5594f3e7c70896ffeeef32b9c950ywan    passes_ = 2;
102233d2500723e5594f3e7c70896ffeeef32b9c950ywan  else
103233d2500723e5594f3e7c70896ffeeef32b9c950ywan    passes_ = 1;
104233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
105233d2500723e5594f3e7c70896ffeeef32b9c950ywan// The function should return "true" most of the time, therefore no early
106233d2500723e5594f3e7c70896ffeeef32b9c950ywan// break-out is implemented within the match checking process.
107233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic bool compare_img(const vpx_image_t *img1,
108233d2500723e5594f3e7c70896ffeeef32b9c950ywan                        const vpx_image_t *img2) {
109233d2500723e5594f3e7c70896ffeeef32b9c950ywan  bool match = (img1->fmt == img2->fmt) &&
110233d2500723e5594f3e7c70896ffeeef32b9c950ywan               (img1->d_w == img2->d_w) &&
111233d2500723e5594f3e7c70896ffeeef32b9c950ywan               (img1->d_h == img2->d_h);
112233d2500723e5594f3e7c70896ffeeef32b9c950ywan
113233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const unsigned int width_y  = img1->d_w;
114233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const unsigned int height_y = img1->d_h;
115233d2500723e5594f3e7c70896ffeeef32b9c950ywan  unsigned int i;
116233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (i = 0; i < height_y; ++i)
117233d2500723e5594f3e7c70896ffeeef32b9c950ywan    match = (memcmp(img1->planes[VPX_PLANE_Y] + i * img1->stride[VPX_PLANE_Y],
118233d2500723e5594f3e7c70896ffeeef32b9c950ywan                    img2->planes[VPX_PLANE_Y] + i * img2->stride[VPX_PLANE_Y],
119233d2500723e5594f3e7c70896ffeeef32b9c950ywan                    width_y) == 0) && match;
120233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const unsigned int width_uv  = (img1->d_w + 1) >> 1;
121233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const unsigned int height_uv = (img1->d_h + 1) >> 1;
122233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (i = 0; i <  height_uv; ++i)
123233d2500723e5594f3e7c70896ffeeef32b9c950ywan    match = (memcmp(img1->planes[VPX_PLANE_U] + i * img1->stride[VPX_PLANE_U],
124233d2500723e5594f3e7c70896ffeeef32b9c950ywan                    img2->planes[VPX_PLANE_U] + i * img2->stride[VPX_PLANE_U],
125233d2500723e5594f3e7c70896ffeeef32b9c950ywan                    width_uv) == 0) && match;
126233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (i = 0; i < height_uv; ++i)
127233d2500723e5594f3e7c70896ffeeef32b9c950ywan    match = (memcmp(img1->planes[VPX_PLANE_V] + i * img1->stride[VPX_PLANE_V],
128233d2500723e5594f3e7c70896ffeeef32b9c950ywan                    img2->planes[VPX_PLANE_V] + i * img2->stride[VPX_PLANE_V],
129233d2500723e5594f3e7c70896ffeeef32b9c950ywan                    width_uv) == 0) && match;
130233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return match;
131233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
132233d2500723e5594f3e7c70896ffeeef32b9c950ywan
133233d2500723e5594f3e7c70896ffeeef32b9c950ywanvoid EncoderTest::MismatchHook(const vpx_image_t *img1,
134233d2500723e5594f3e7c70896ffeeef32b9c950ywan                               const vpx_image_t *img2) {
135233d2500723e5594f3e7c70896ffeeef32b9c950ywan  ASSERT_TRUE(0) << "Encode/Decode mismatch found";
136233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
137233d2500723e5594f3e7c70896ffeeef32b9c950ywan
138233d2500723e5594f3e7c70896ffeeef32b9c950ywanvoid EncoderTest::RunLoop(VideoSource *video) {
139233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_codec_dec_cfg_t dec_cfg = {0};
140233d2500723e5594f3e7c70896ffeeef32b9c950ywan
141233d2500723e5594f3e7c70896ffeeef32b9c950ywan  stats_.Reset();
142233d2500723e5594f3e7c70896ffeeef32b9c950ywan
143233d2500723e5594f3e7c70896ffeeef32b9c950ywan  ASSERT_TRUE(passes_ == 1 || passes_ == 2);
144233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (unsigned int pass = 0; pass < passes_; pass++) {
145233d2500723e5594f3e7c70896ffeeef32b9c950ywan    last_pts_ = 0;
146233d2500723e5594f3e7c70896ffeeef32b9c950ywan
147233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (passes_ == 1)
148233d2500723e5594f3e7c70896ffeeef32b9c950ywan      cfg_.g_pass = VPX_RC_ONE_PASS;
149233d2500723e5594f3e7c70896ffeeef32b9c950ywan    else if (pass == 0)
150233d2500723e5594f3e7c70896ffeeef32b9c950ywan      cfg_.g_pass = VPX_RC_FIRST_PASS;
151233d2500723e5594f3e7c70896ffeeef32b9c950ywan    else
152233d2500723e5594f3e7c70896ffeeef32b9c950ywan      cfg_.g_pass = VPX_RC_LAST_PASS;
153233d2500723e5594f3e7c70896ffeeef32b9c950ywan
154233d2500723e5594f3e7c70896ffeeef32b9c950ywan    BeginPassHook(pass);
155233d2500723e5594f3e7c70896ffeeef32b9c950ywan    Encoder* const encoder = codec_->CreateEncoder(cfg_, deadline_, init_flags_,
156233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                                   &stats_);
157233d2500723e5594f3e7c70896ffeeef32b9c950ywan    ASSERT_TRUE(encoder != NULL);
158233d2500723e5594f3e7c70896ffeeef32b9c950ywan    Decoder* const decoder = codec_->CreateDecoder(dec_cfg, 0);
159233d2500723e5594f3e7c70896ffeeef32b9c950ywan    bool again;
160233d2500723e5594f3e7c70896ffeeef32b9c950ywan    for (again = true, video->Begin(); again; video->Next()) {
161233d2500723e5594f3e7c70896ffeeef32b9c950ywan      again = (video->img() != NULL);
162233d2500723e5594f3e7c70896ffeeef32b9c950ywan
163233d2500723e5594f3e7c70896ffeeef32b9c950ywan      PreEncodeFrameHook(video);
164233d2500723e5594f3e7c70896ffeeef32b9c950ywan      PreEncodeFrameHook(video, encoder);
165233d2500723e5594f3e7c70896ffeeef32b9c950ywan      encoder->EncodeFrame(video, frame_flags_);
166233d2500723e5594f3e7c70896ffeeef32b9c950ywan
167233d2500723e5594f3e7c70896ffeeef32b9c950ywan      CxDataIterator iter = encoder->GetCxData();
168233d2500723e5594f3e7c70896ffeeef32b9c950ywan
169233d2500723e5594f3e7c70896ffeeef32b9c950ywan      bool has_cxdata = false;
170233d2500723e5594f3e7c70896ffeeef32b9c950ywan      bool has_dxdata = false;
171233d2500723e5594f3e7c70896ffeeef32b9c950ywan      while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) {
172233d2500723e5594f3e7c70896ffeeef32b9c950ywan        pkt = MutateEncoderOutputHook(pkt);
173233d2500723e5594f3e7c70896ffeeef32b9c950ywan        again = true;
174233d2500723e5594f3e7c70896ffeeef32b9c950ywan        switch (pkt->kind) {
175233d2500723e5594f3e7c70896ffeeef32b9c950ywan          case VPX_CODEC_CX_FRAME_PKT:
176233d2500723e5594f3e7c70896ffeeef32b9c950ywan            has_cxdata = true;
177233d2500723e5594f3e7c70896ffeeef32b9c950ywan            if (decoder && DoDecode()) {
178233d2500723e5594f3e7c70896ffeeef32b9c950ywan              vpx_codec_err_t res_dec = decoder->DecodeFrame(
179233d2500723e5594f3e7c70896ffeeef32b9c950ywan                  (const uint8_t*)pkt->data.frame.buf, pkt->data.frame.sz);
180233d2500723e5594f3e7c70896ffeeef32b9c950ywan              ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder->DecodeError();
181233d2500723e5594f3e7c70896ffeeef32b9c950ywan              has_dxdata = true;
182233d2500723e5594f3e7c70896ffeeef32b9c950ywan            }
183233d2500723e5594f3e7c70896ffeeef32b9c950ywan            ASSERT_GE(pkt->data.frame.pts, last_pts_);
184233d2500723e5594f3e7c70896ffeeef32b9c950ywan            last_pts_ = pkt->data.frame.pts;
185233d2500723e5594f3e7c70896ffeeef32b9c950ywan            FramePktHook(pkt);
186233d2500723e5594f3e7c70896ffeeef32b9c950ywan            break;
187233d2500723e5594f3e7c70896ffeeef32b9c950ywan
188233d2500723e5594f3e7c70896ffeeef32b9c950ywan          case VPX_CODEC_PSNR_PKT:
189233d2500723e5594f3e7c70896ffeeef32b9c950ywan            PSNRPktHook(pkt);
190233d2500723e5594f3e7c70896ffeeef32b9c950ywan            break;
191233d2500723e5594f3e7c70896ffeeef32b9c950ywan
192233d2500723e5594f3e7c70896ffeeef32b9c950ywan          default:
193233d2500723e5594f3e7c70896ffeeef32b9c950ywan            break;
194233d2500723e5594f3e7c70896ffeeef32b9c950ywan        }
195233d2500723e5594f3e7c70896ffeeef32b9c950ywan      }
196233d2500723e5594f3e7c70896ffeeef32b9c950ywan
197233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (has_dxdata && has_cxdata) {
198233d2500723e5594f3e7c70896ffeeef32b9c950ywan        const vpx_image_t *img_enc = encoder->GetPreviewFrame();
199233d2500723e5594f3e7c70896ffeeef32b9c950ywan        DxDataIterator dec_iter = decoder->GetDxData();
200233d2500723e5594f3e7c70896ffeeef32b9c950ywan        const vpx_image_t *img_dec = dec_iter.Next();
201233d2500723e5594f3e7c70896ffeeef32b9c950ywan        if (img_enc && img_dec) {
202233d2500723e5594f3e7c70896ffeeef32b9c950ywan          const bool res = compare_img(img_enc, img_dec);
203233d2500723e5594f3e7c70896ffeeef32b9c950ywan          if (!res) {  // Mismatch
204233d2500723e5594f3e7c70896ffeeef32b9c950ywan            MismatchHook(img_enc, img_dec);
205233d2500723e5594f3e7c70896ffeeef32b9c950ywan          }
206233d2500723e5594f3e7c70896ffeeef32b9c950ywan        }
207233d2500723e5594f3e7c70896ffeeef32b9c950ywan        if (img_dec)
208233d2500723e5594f3e7c70896ffeeef32b9c950ywan          DecompressedFrameHook(*img_dec, video->pts());
209233d2500723e5594f3e7c70896ffeeef32b9c950ywan      }
210233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (!Continue())
211233d2500723e5594f3e7c70896ffeeef32b9c950ywan        break;
212233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
213233d2500723e5594f3e7c70896ffeeef32b9c950ywan
214233d2500723e5594f3e7c70896ffeeef32b9c950ywan    EndPassHook();
215233d2500723e5594f3e7c70896ffeeef32b9c950ywan
216233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (decoder)
217233d2500723e5594f3e7c70896ffeeef32b9c950ywan      delete decoder;
218233d2500723e5594f3e7c70896ffeeef32b9c950ywan    delete encoder;
219233d2500723e5594f3e7c70896ffeeef32b9c950ywan
220233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (!Continue())
221233d2500723e5594f3e7c70896ffeeef32b9c950ywan      break;
222233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
223233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
224233d2500723e5594f3e7c70896ffeeef32b9c950ywan
225233d2500723e5594f3e7c70896ffeeef32b9c950ywan}  // namespace libvpx_test
226