Home | History | Annotate | Download | only in test
      1 /*
      2  *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include <string.h>
     12 
     13 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
     14 #include "webrtc/modules/video_processing/include/video_processing.h"
     15 #include "webrtc/modules/video_processing/test/video_processing_unittest.h"
     16 #include "webrtc/modules/video_processing/video_denoiser.h"
     17 
     18 namespace webrtc {
     19 
     20 TEST_F(VideoProcessingTest, CopyMem) {
     21   rtc::scoped_ptr<DenoiserFilter> df_c(DenoiserFilter::Create(false));
     22   rtc::scoped_ptr<DenoiserFilter> df_sse_neon(DenoiserFilter::Create(true));
     23   uint8_t src[16 * 16], dst[16 * 16];
     24   for (int i = 0; i < 16; ++i) {
     25     for (int j = 0; j < 16; ++j) {
     26       src[i * 16 + j] = i * 16 + j;
     27     }
     28   }
     29 
     30   memset(dst, 0, 8 * 8);
     31   df_c->CopyMem8x8(src, 8, dst, 8);
     32   EXPECT_EQ(0, memcmp(src, dst, 8 * 8));
     33 
     34   memset(dst, 0, 16 * 16);
     35   df_c->CopyMem16x16(src, 16, dst, 16);
     36   EXPECT_EQ(0, memcmp(src, dst, 16 * 16));
     37 
     38   memset(dst, 0, 8 * 8);
     39   df_sse_neon->CopyMem16x16(src, 8, dst, 8);
     40   EXPECT_EQ(0, memcmp(src, dst, 8 * 8));
     41 
     42   memset(dst, 0, 16 * 16);
     43   df_sse_neon->CopyMem16x16(src, 16, dst, 16);
     44   EXPECT_EQ(0, memcmp(src, dst, 16 * 16));
     45 }
     46 
     47 TEST_F(VideoProcessingTest, Variance) {
     48   rtc::scoped_ptr<DenoiserFilter> df_c(DenoiserFilter::Create(false));
     49   rtc::scoped_ptr<DenoiserFilter> df_sse_neon(DenoiserFilter::Create(true));
     50   uint8_t src[16 * 16], dst[16 * 16];
     51   uint32_t sum = 0, sse = 0, var;
     52   for (int i = 0; i < 16; ++i) {
     53     for (int j = 0; j < 16; ++j) {
     54       src[i * 16 + j] = i * 16 + j;
     55     }
     56   }
     57   // Compute the 16x8 variance of the 16x16 block.
     58   for (int i = 0; i < 8; ++i) {
     59     for (int j = 0; j < 16; ++j) {
     60       sum += (i * 32 + j);
     61       sse += (i * 32 + j) * (i * 32 + j);
     62     }
     63   }
     64   var = sse - ((sum * sum) >> 7);
     65   memset(dst, 0, 16 * 16);
     66   EXPECT_EQ(var, df_c->Variance16x8(src, 16, dst, 16, &sse));
     67   EXPECT_EQ(var, df_sse_neon->Variance16x8(src, 16, dst, 16, &sse));
     68 }
     69 
     70 TEST_F(VideoProcessingTest, MbDenoise) {
     71   rtc::scoped_ptr<DenoiserFilter> df_c(DenoiserFilter::Create(false));
     72   rtc::scoped_ptr<DenoiserFilter> df_sse_neon(DenoiserFilter::Create(true));
     73   uint8_t running_src[16 * 16], src[16 * 16], dst[16 * 16], dst_ref[16 * 16];
     74 
     75   // Test case: |diff| <= |3 + shift_inc1|
     76   for (int i = 0; i < 16; ++i) {
     77     for (int j = 0; j < 16; ++j) {
     78       running_src[i * 16 + j] = i * 11 + j;
     79       src[i * 16 + j] = i * 11 + j + 2;
     80       dst_ref[i * 16 + j] = running_src[i * 16 + j];
     81     }
     82   }
     83   memset(dst, 0, 16 * 16);
     84   df_c->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1);
     85   EXPECT_EQ(0, memcmp(dst, dst_ref, 16 * 16));
     86 
     87   // Test case: |diff| >= |4 + shift_inc1|
     88   for (int i = 0; i < 16; ++i) {
     89     for (int j = 0; j < 16; ++j) {
     90       running_src[i * 16 + j] = i * 11 + j;
     91       src[i * 16 + j] = i * 11 + j + 5;
     92       dst_ref[i * 16 + j] = src[i * 16 + j] - 2;
     93     }
     94   }
     95   memset(dst, 0, 16 * 16);
     96   df_c->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1);
     97   EXPECT_EQ(0, memcmp(dst, dst_ref, 16 * 16));
     98   memset(dst, 0, 16 * 16);
     99   df_sse_neon->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1);
    100   EXPECT_EQ(0, memcmp(dst, dst_ref, 16 * 16));
    101 
    102   // Test case: |diff| >= 8
    103   for (int i = 0; i < 16; ++i) {
    104     for (int j = 0; j < 16; ++j) {
    105       running_src[i * 16 + j] = i * 11 + j;
    106       src[i * 16 + j] = i * 11 + j + 8;
    107       dst_ref[i * 16 + j] = src[i * 16 + j] - 6;
    108     }
    109   }
    110   memset(dst, 0, 16 * 16);
    111   df_c->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1);
    112   EXPECT_EQ(0, memcmp(dst, dst_ref, 16 * 16));
    113   memset(dst, 0, 16 * 16);
    114   df_sse_neon->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1);
    115   EXPECT_EQ(0, memcmp(dst, dst_ref, 16 * 16));
    116 
    117   // Test case: |diff| > 15
    118   for (int i = 0; i < 16; ++i) {
    119     for (int j = 0; j < 16; ++j) {
    120       running_src[i * 16 + j] = i * 11 + j;
    121       src[i * 16 + j] = i * 11 + j + 16;
    122     }
    123   }
    124   memset(dst, 0, 16 * 16);
    125   DenoiserDecision decision =
    126       df_c->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1);
    127   EXPECT_EQ(COPY_BLOCK, decision);
    128   decision = df_sse_neon->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1);
    129   EXPECT_EQ(COPY_BLOCK, decision);
    130 }
    131 
    132 TEST_F(VideoProcessingTest, Denoiser) {
    133   // Create pure C denoiser.
    134   VideoDenoiser denoiser_c(false);
    135   // Create SSE or NEON denoiser.
    136   VideoDenoiser denoiser_sse_neon(true);
    137   VideoFrame denoised_frame_c;
    138   VideoFrame denoised_frame_sse_neon;
    139 
    140   rtc::scoped_ptr<uint8_t[]> video_buffer(new uint8_t[frame_length_]);
    141   while (fread(video_buffer.get(), 1, frame_length_, source_file_) ==
    142          frame_length_) {
    143     // Using ConvertToI420 to add stride to the image.
    144     EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, width_, height_,
    145                                0, kVideoRotation_0, &video_frame_));
    146 
    147     denoiser_c.DenoiseFrame(video_frame_, &denoised_frame_c);
    148     denoiser_sse_neon.DenoiseFrame(video_frame_, &denoised_frame_sse_neon);
    149 
    150     // Denoising results should be the same for C and SSE/NEON denoiser.
    151     ASSERT_EQ(true, denoised_frame_c.EqualsFrame(denoised_frame_sse_neon));
    152   }
    153   ASSERT_NE(0, feof(source_file_)) << "Error reading source file";
    154 }
    155 
    156 }  // namespace webrtc
    157