/*
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
 *
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
 */

#include <climits>
#include <vector>
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/i420_video_source.h"
#include "test/video_source.h"
#include "test/util.h"

namespace {

const unsigned int kCqLevel = 18;
const double kMaxPsnr = 100.0;

// kPsnrThreshold represents the psnr threshold used to validate the quality of
// the first frame. The indices correspond to one/two-pass, allintra and
// realtime encoding modes.
const double kPsnrThreshold[3] = { 29.0, 41.5, 41.5 };

// kPsnrFluctuation represents the maximum allowed psnr fluctuation w.r.t first
// frame. The indices correspond to one/two-pass, allintra and realtime
// encoding modes.
const double kPsnrFluctuation[3] = { 2.5, 0.3, 16.0 };

class MonochromeTest
    : public ::libaom_test::CodecTestWith3Params<libaom_test::TestMode, int,
                                                 int>,
      public ::libaom_test::EncoderTest {
 protected:
  MonochromeTest()
      : EncoderTest(GET_PARAM(0)), lossless_(GET_PARAM(2)),
        frame0_psnr_y_(0.0) {}

  virtual ~MonochromeTest() {}

  virtual void SetUp() { InitializeConfig(GET_PARAM(1)); }

  virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
                                  ::libaom_test::Encoder *encoder) {
    if (video->frame() == 0) {
      encoder->Control(AOME_SET_CPUUSED, GET_PARAM(3));
      if (mode_ == ::libaom_test::kAllIntra) {
        encoder->Control(AOME_SET_CQ_LEVEL, kCqLevel);
      }
      if (lossless_) {
        encoder->Control(AV1E_SET_LOSSLESS, 1);
      }
    }
  }

  virtual void DecompressedFrameHook(const aom_image_t &img,
                                     aom_codec_pts_t pts) {
    (void)pts;

    // Get value of top-left corner pixel of U plane
    int chroma_value = img.planes[AOM_PLANE_U][0];

    bool is_chroma_constant =
        ComparePlaneToValue(img, AOM_PLANE_U, chroma_value) &&
        ComparePlaneToValue(img, AOM_PLANE_V, chroma_value);

    // Chroma planes should be constant
    EXPECT_TRUE(is_chroma_constant);

    // Monochrome flag on image should be set
    EXPECT_EQ(img.monochrome, 1);

    chroma_value_list_.push_back(chroma_value);
  }

  // Returns true if all pixels on the plane are equal to value, and returns
  // false otherwise.
  bool ComparePlaneToValue(const aom_image_t &img, const int plane,
                           const int value) {
    const int w = aom_img_plane_width(&img, plane);
    const int h = aom_img_plane_height(&img, plane);
    const uint8_t *const buf = img.planes[plane];
    const int stride = img.stride[plane];

    for (int r = 0; r < h; ++r) {
      for (int c = 0; c < w; ++c) {
        if (buf[r * stride + c] != value) return false;
      }
    }
    return true;
  }

  virtual void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) {
    // Check average PSNR value is >= 100 db in case of lossless encoding.
    if (lossless_) {
      EXPECT_GE(pkt->data.psnr.psnr[0], kMaxPsnr);
      return;
    }
    const int psnr_index = (mode_ == ::libaom_test::kRealTime)   ? 2
                           : (mode_ == ::libaom_test::kAllIntra) ? 1
                                                                 : 0;
    // Check that the initial Y PSNR value is 'high enough', and check that
    // subsequent Y PSNR values are 'close' to this initial value.
    if (frame0_psnr_y_ == 0.0) {
      frame0_psnr_y_ = pkt->data.psnr.psnr[1];
      EXPECT_GT(frame0_psnr_y_, kPsnrThreshold[psnr_index]);
    }
    EXPECT_NEAR(pkt->data.psnr.psnr[1], frame0_psnr_y_,
                kPsnrFluctuation[psnr_index]);
  }

  int lossless_;
  std::vector<int> chroma_value_list_;
  double frame0_psnr_y_;
};

TEST_P(MonochromeTest, TestMonochromeEncoding) {
  ::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
                                       30, 1, 0, 5);

  init_flags_ = AOM_CODEC_USE_PSNR;

  cfg_.rc_buf_initial_sz = 500;
  cfg_.rc_buf_optimal_sz = 600;
  cfg_.rc_buf_sz = 1000;
  cfg_.rc_min_quantizer = 2;
  cfg_.rc_max_quantizer = 56;
  cfg_.rc_undershoot_pct = 50;
  cfg_.rc_overshoot_pct = 50;
  cfg_.rc_end_usage = AOM_CBR;
  cfg_.g_lag_in_frames = 1;
  cfg_.kf_min_dist = cfg_.kf_max_dist = 3000;
  // Enable dropped frames.
  cfg_.rc_dropframe_thresh = 1;
  // Run at low bitrate.
  cfg_.rc_target_bitrate = 40;
  // Set monochrome encoding flag
  cfg_.monochrome = 1;

  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));

  // Check that the chroma planes are equal across all frames
  std::vector<int>::const_iterator iter = chroma_value_list_.begin();
  int initial_chroma_value = *iter;
  for (; iter != chroma_value_list_.end(); ++iter) {
    // Check that all decoded frames have the same constant chroma planes.
    EXPECT_EQ(*iter, initial_chroma_value);
  }
}

class MonochromeAllIntraTest : public MonochromeTest {};

TEST_P(MonochromeAllIntraTest, TestMonochromeEncoding) {
  ::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
                                       30, 1, 0, 5);
  init_flags_ = AOM_CODEC_USE_PSNR;
  // Set monochrome encoding flag
  cfg_.monochrome = 1;
  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));

  // Check that the chroma planes are equal across all frames
  std::vector<int>::const_iterator iter = chroma_value_list_.begin();
  int initial_chroma_value = *iter;
  for (; iter != chroma_value_list_.end(); ++iter) {
    // Check that all decoded frames have the same constant chroma planes.
    EXPECT_EQ(*iter, initial_chroma_value);
  }
}

class MonochromeRealtimeTest : public MonochromeTest {};

TEST_P(MonochromeRealtimeTest, TestMonochromeEncoding) {
  ::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
                                       30, 1, 0, 30);
  init_flags_ = AOM_CODEC_USE_PSNR;
  // Set monochrome encoding flag
  cfg_.monochrome = 1;
  // Run at low bitrate.
  cfg_.rc_target_bitrate = 40;
  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));

  // Check that the chroma planes are equal across all frames
  std::vector<int>::const_iterator iter = chroma_value_list_.begin();
  int initial_chroma_value = *iter;
  for (; iter != chroma_value_list_.end(); ++iter) {
    // Check that all decoded frames have the same constant chroma planes.
    EXPECT_EQ(*iter, initial_chroma_value);
  }
}

AV1_INSTANTIATE_TEST_SUITE(MonochromeTest,
                           ::testing::Values(::libaom_test::kOnePassGood,
                                             ::libaom_test::kTwoPassGood),
                           ::testing::Values(0),   // lossless
                           ::testing::Values(0));  // cpu_used

AV1_INSTANTIATE_TEST_SUITE(MonochromeAllIntraTest,
                           ::testing::Values(::libaom_test::kAllIntra),
                           ::testing::Values(0, 1),   // lossless
                           ::testing::Values(6, 9));  // cpu_used

AV1_INSTANTIATE_TEST_SUITE(MonochromeRealtimeTest,
                           ::testing::Values(::libaom_test::kRealTime),
                           ::testing::Values(0),          // lossless
                           ::testing::Values(6, 8, 10));  // cpu_used

}  // namespace
