ref: c953aeacd4ff1418a81f809e11e1d9bca4e9aac5
parent: 90625c3bc11707fb1fa6d8892a645be6f4e6a8ae
author: Yaowu Xu <yaowu@google.com>
date: Thu Aug 30 09:43:15 EDT 2012
added encode/decode matching validation to tests This commit adds the ability of validating matched encoder and decoder to unit tests. Change-Id: Ie00d69a42477b6a69b324a6bd134939684f7300b
--- /dev/null
+++ b/test/decode_test_driver.cc
@@ -1,0 +1,28 @@
+/*
+ * 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 "test/decode_test_driver.h"
+#include "third_party/googletest/src/include/gtest/gtest.h"
+
+namespace libvpx_test {
+#if CONFIG_VP8_DECODER
+void Decoder::DecodeFrame(const uint8_t *cxdata, int size) {
+ if(!decoder_.priv) {
+ const vpx_codec_err_t res_init = vpx_codec_dec_init(&decoder_,
+ &vpx_codec_vp8_dx_algo,
+ &cfg_, 0);
+ ASSERT_EQ(VPX_CODEC_OK, res_init) << DecodeError();
+ }
+
+ const vpx_codec_err_t res_dec = vpx_codec_decode(&decoder_,
+ cxdata, size, NULL, 0);
+ ASSERT_EQ(VPX_CODEC_OK, res_dec) << DecodeError();
+}
+#endif
+} // namespace libvpx_test
--- /dev/null
+++ b/test/decode_test_driver.h
@@ -1,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#ifndef TEST_DECODE_TEST_DRIVER_H_
+#define TEST_DECODE_TEST_DRIVER_H_
+#include <string>
+#include <vector>
+#include "third_party/googletest/src/include/gtest/gtest.h"
+#include "vpx_config.h"
+#include "vpx/vpx_decoder.h"
+#include "vpx/vp8dx.h"
+namespace libvpx_test {
+
+
+// Provides an object to handle decoding output
+class DxDataIterator {
+ public:
+ explicit DxDataIterator(vpx_codec_ctx_t *decoder)
+ : decoder_(decoder), iter_(NULL) {}
+
+ const vpx_image_t *Next() {
+ return vpx_codec_get_frame(decoder_, &iter_);
+ }
+
+ private:
+ vpx_codec_ctx_t *decoder_;
+ vpx_codec_iter_t iter_;
+};
+
+// Provides a simplified interface to manage one video decoding.
+//
+// TODO: similar to Encoder class, the exact services should be
+// added as more tests are added.
+class Decoder {
+ public:
+ Decoder (vpx_codec_dec_cfg_t cfg, unsigned long deadline = 0)
+ : cfg_(cfg), deadline_(deadline) {
+ memset(&decoder_, 0, sizeof(decoder_));
+ }
+
+ ~Decoder () {
+ vpx_codec_destroy(&decoder_);
+ }
+
+ void DecodeFrame(const uint8_t *cxdata, int size);
+
+ DxDataIterator GetDxData() {
+ return DxDataIterator(&decoder_);
+ }
+
+ void set_deadline(unsigned long deadline) {
+ deadline_ = deadline;
+ }
+
+ void Control(int ctrl_id, int arg) {
+ const vpx_codec_err_t res = vpx_codec_control_(&decoder_, ctrl_id, arg);
+ ASSERT_EQ(VPX_CODEC_OK, res) << DecodeError();
+ }
+
+ protected:
+ const char *DecodeError() {
+ const char *detail = vpx_codec_error_detail(&decoder_);
+ return detail ? detail : vpx_codec_error(&decoder_);
+ }
+
+ vpx_codec_ctx_t decoder_;
+ vpx_codec_dec_cfg_t cfg_;
+ unsigned int deadline_;
+};
+
+} // namespace libvpx_test
+#endif /* TEST_DECODE_TEST_DRIVER_H_ */
--- a/test/encode_test_driver.cc
+++ b/test/encode_test_driver.cc
@@ -7,12 +7,15 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
+#include "vpx_config.h"
#include "test/encode_test_driver.h"
+#if CONFIG_VP8_DECODER
+#include "test/decode_test_driver.h"
+#endif
#include "test/video_source.h"
#include "third_party/googletest/src/include/gtest/gtest.h"
namespace libvpx_test {
-
void Encoder::EncodeFrame(VideoSource *video, unsigned long flags) {
if (video->img())
EncodeFrameInternal(*video, flags);
@@ -91,8 +94,38 @@
else
passes_ = 1;
}
+// 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;
+}
+
void EncoderTest::RunLoop(VideoSource *video) {
+#if CONFIG_VP8_DECODER
+ vpx_codec_dec_cfg_t dec_cfg = {0};
+#endif
for (unsigned int pass = 0; pass < passes_; pass++) {
last_pts_ = 0;
@@ -105,7 +138,10 @@
BeginPassHook(pass);
Encoder encoder(cfg_, deadline_, &stats_);
-
+#if CONFIG_VP8_DECODER
+ Decoder decoder(dec_cfg);
+ bool has_cxdata = false;
+#endif
bool again;
for (again = true, video->Begin(); again; video->Next()) {
again = video->img() != NULL;
@@ -121,12 +157,27 @@
if (pkt->kind != VPX_CODEC_CX_FRAME_PKT)
continue;
-
+#if CONFIG_VP8_DECODER
+ has_cxdata = true;
+ decoder.DecodeFrame((const uint8_t*)pkt->data.frame.buf,
+ pkt->data.frame.sz);
+#endif
ASSERT_GE(pkt->data.frame.pts, last_pts_);
last_pts_ = pkt->data.frame.pts;
FramePktHook(pkt);
}
+#if CONFIG_VP8_DECODER
+ if (has_cxdata) {
+ const vpx_image_t *img_enc = encoder.GetPreviewFrame();
+ DxDataIterator dec_iter = decoder.GetDxData();
+ const vpx_image_t *img_dec = dec_iter.Next();
+ if(img_enc && img_dec) {
+ const bool res = compare_img(img_enc, img_dec);
+ ASSERT_TRUE(res)<< "Encoder/Decoder mismatch found.";
+ }
+ }
+#endif
if (!Continue())
break;
}
@@ -137,5 +188,4 @@
break;
}
}
-
} // namespace libvpx_test
--- a/test/encode_test_driver.h
+++ b/test/encode_test_driver.h
@@ -52,7 +52,6 @@
vpx_codec_iter_t iter_;
};
-
// Implements an in-memory store for libvpx twopass statistics
class TwopassStatsStore {
public:
@@ -92,6 +91,9 @@
return CxDataIterator(&encoder_);
}
+ const vpx_image_t *GetPreviewFrame() {
+ return vpx_codec_get_preview_frame(&encoder_);
+ }
// This is a thin wrapper around vpx_codec_encode(), so refer to
// vpx_encoder.h for its semantics.
void EncodeFrame(VideoSource *video, unsigned long flags);
@@ -127,7 +129,6 @@
unsigned long deadline_;
TwopassStatsStore *stats_;
};
-
// Common test functionality for all Encoder tests.
//
--- a/test/test.mk
+++ b/test/test.mk
@@ -16,6 +16,8 @@
LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += keyframe_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += resize_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += video_source.h
+LIBVPX_TEST_SRCS-$(CONFIG_VP8_DECODER) += decode_test_driver.cc
+LIBVPX_TEST_SRCS-$(CONFIG_VP8_DECODER) += decode_test_driver.h
##
## WHITE BOX TESTS
--
⑨