video_coding: Moving video metrics computation to a designated file.
This is the first stage of a general clean-up to test_util. Will try to divide this clean-up to small changes, so it will be easier to review. Review URL: http://webrtc-codereview.appspot.com/120004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@466 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
e46d69f762
commit
552f173979
@ -37,6 +37,7 @@
|
|||||||
'../test/release_test.h',
|
'../test/release_test.h',
|
||||||
'../test/rtp_player.h',
|
'../test/rtp_player.h',
|
||||||
'../test/test_util.h',
|
'../test/test_util.h',
|
||||||
|
'../test/video_metrics.h',
|
||||||
'../test/video_source.h',
|
'../test/video_source.h',
|
||||||
|
|
||||||
# sources
|
# sources
|
||||||
@ -52,6 +53,7 @@
|
|||||||
'../test/rtp_player.cc',
|
'../test/rtp_player.cc',
|
||||||
'../test/test_util.cc',
|
'../test/test_util.cc',
|
||||||
'../test/tester_main.cc',
|
'../test/tester_main.cc',
|
||||||
|
'../test/video_metrics.cc',
|
||||||
'../test/video_rtp_play_mt.cc',
|
'../test/video_rtp_play_mt.cc',
|
||||||
'../test/video_rtp_play.cc',
|
'../test/video_rtp_play.cc',
|
||||||
'../test/video_source.cc',
|
'../test/video_source.cc',
|
||||||
|
@ -12,15 +12,18 @@
|
|||||||
// testing is done via the VCM module, no specific CodecDataBase module functionality.
|
// testing is done via the VCM module, no specific CodecDataBase module functionality.
|
||||||
|
|
||||||
#include "codec_database_test.h"
|
#include "codec_database_test.h"
|
||||||
#include "vp8.h" // for external codecs test
|
|
||||||
#include "../source/event.h"
|
|
||||||
#include "test_macros.h"
|
|
||||||
#include "test_util.h"
|
|
||||||
#include "../../../../engine_configurations.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "../../../../engine_configurations.h"
|
||||||
|
#include "../source/event.h"
|
||||||
|
#include "test_macros.h"
|
||||||
|
#include "test_util.h"
|
||||||
|
#include "video_metrics.h"
|
||||||
|
#include "vp8.h" // for external codecs test
|
||||||
|
|
||||||
|
|
||||||
using namespace webrtc;
|
using namespace webrtc;
|
||||||
|
|
||||||
int CodecDataBaseTest::RunTest(CmdArgs& args)
|
int CodecDataBaseTest::RunTest(CmdArgs& args)
|
||||||
@ -362,7 +365,7 @@ CodecDataBaseTest::Perform(CmdArgs& args)
|
|||||||
// closing and calculating PSNR for prior encoder-decoder test
|
// closing and calculating PSNR for prior encoder-decoder test
|
||||||
TearDown(); // closing open files
|
TearDown(); // closing open files
|
||||||
double psnr = 0;
|
double psnr = 0;
|
||||||
PSNRfromFiles(_inname.c_str(), _outname.c_str(), _width, _height, &psnr);
|
PsnrFromFiles(_inname.c_str(), _outname.c_str(), _width, _height, &psnr);
|
||||||
printf(" \n @ %d KBPS: ", sendCodec.startBitrate);
|
printf(" \n @ %d KBPS: ", sendCodec.startBitrate);
|
||||||
printf("PSNR from encoder-decoder send-receive control test is %f \n \n", psnr);
|
printf("PSNR from encoder-decoder send-receive control test is %f \n \n", psnr);
|
||||||
} // end of #codecs >1
|
} // end of #codecs >1
|
||||||
|
@ -11,18 +11,21 @@
|
|||||||
// Implementation of Media Optimization Test
|
// Implementation of Media Optimization Test
|
||||||
// testing is done via the VCM module, no specific Media opt functionality.
|
// testing is done via the VCM module, no specific Media opt functionality.
|
||||||
|
|
||||||
#include "receiver_tests.h" // receive side callbacks
|
|
||||||
#include "video_coding.h"
|
|
||||||
#include "rtp_rtcp.h"
|
|
||||||
#include "test_macros.h"
|
|
||||||
#include "test_util.h" // send side callback
|
|
||||||
#include "media_opt_test.h"
|
#include "media_opt_test.h"
|
||||||
#include "../source/event.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <vector>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../source/event.h"
|
||||||
|
#include "receiver_tests.h" // receive side callbacks
|
||||||
|
#include "rtp_rtcp.h"
|
||||||
|
#include "test_macros.h"
|
||||||
|
#include "test_util.h" // send side callback
|
||||||
|
#include "video_coding.h"
|
||||||
|
#include "video_metrics.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace webrtc;
|
using namespace webrtc;
|
||||||
|
|
||||||
@ -465,7 +468,7 @@ MediaOptTest::Print(int mode)
|
|||||||
double ActualBitRate = 8.0 *( _sumEncBytes / (_frameCnt / _frameRate));
|
double ActualBitRate = 8.0 *( _sumEncBytes / (_frameCnt / _frameRate));
|
||||||
double actualBitRate = ActualBitRate / 1000.0;
|
double actualBitRate = ActualBitRate / 1000.0;
|
||||||
double psnr;
|
double psnr;
|
||||||
PSNRfromFiles(_actualSourcename.c_str(), _outname.c_str(), _width, _height, &psnr);
|
PsnrFromFiles(_actualSourcename.c_str(), _outname.c_str(), _width, _height, &psnr);
|
||||||
|
|
||||||
(_log) << "VCM: Media Optimization Test Cycle Completed!" << std::endl;
|
(_log) << "VCM: Media Optimization Test Cycle Completed!" << std::endl;
|
||||||
(_log) << "Input file: " << _inname << std::endl;
|
(_log) << "Input file: " << _inname << std::endl;
|
||||||
|
@ -9,17 +9,21 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "normal_test.h"
|
#include "normal_test.h"
|
||||||
#include "../source/event.h"
|
|
||||||
#include "tick_time.h"
|
|
||||||
#include "common_types.h"
|
|
||||||
#include "trace.h"
|
|
||||||
#include "test_macros.h"
|
|
||||||
#include "test_util.h"
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "../source/event.h"
|
||||||
|
#include "common_types.h"
|
||||||
|
#include "test_macros.h"
|
||||||
|
#include "test_util.h"
|
||||||
|
#include "tick_time.h"
|
||||||
|
#include "trace.h"
|
||||||
|
#include "video_metrics.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace webrtc;
|
using namespace webrtc;
|
||||||
|
|
||||||
int NormalTest::RunTest(CmdArgs& args)
|
int NormalTest::RunTest(CmdArgs& args)
|
||||||
@ -141,7 +145,7 @@ VCMNTEncodeCompleteCallback::SkipCnt()
|
|||||||
return _skipCnt;
|
return _skipCnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decoded Frame Callback Implmentation
|
// Decoded Frame Callback Implementation
|
||||||
VCMNTDecodeCompleCallback::~VCMNTDecodeCompleCallback()
|
VCMNTDecodeCompleCallback::~VCMNTDecodeCompleCallback()
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
@ -359,8 +363,8 @@ NormalTest::Print()
|
|||||||
double avgDecTime = _totalDecodeTime / _frameCnt;
|
double avgDecTime = _totalDecodeTime / _frameCnt;
|
||||||
double psnr;
|
double psnr;
|
||||||
double ssim;
|
double ssim;
|
||||||
PSNRfromFiles(_inname.c_str(), _outname.c_str(), _width, _height, &psnr);
|
PsnrFromFiles(_inname.c_str(), _outname.c_str(), _width, _height, &psnr);
|
||||||
SSIMfromFiles(_inname.c_str(), _outname.c_str(), _width, _height, &ssim);
|
SsimFromFiles(_inname.c_str(), _outname.c_str(), _width, _height, &ssim);
|
||||||
printf("Actual bitrate: %f kbps\n", actualBitRate);
|
printf("Actual bitrate: %f kbps\n", actualBitRate);
|
||||||
printf("Target bitrate: %f kbps\n", _bitRate);
|
printf("Target bitrate: %f kbps\n", _bitRate);
|
||||||
( _log) << "Actual bitrate: " << actualBitRate<< " kbps\tTarget: " << _bitRate << " kbps" << std::endl;
|
( _log) << "Actual bitrate: " << actualBitRate<< " kbps\tTarget: " << _bitRate << " kbps" << std::endl;
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
* be found in the AUTHORS file in the root of the source tree.
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "system_wrappers/interface/cpu_features_wrapper.h"
|
|
||||||
#include "test_util.h"
|
#include "test_util.h"
|
||||||
#include "test_macros.h"
|
#include "test_macros.h"
|
||||||
#include "rtp_dump.h"
|
#include "rtp_dump.h"
|
||||||
@ -420,282 +419,6 @@ PacketRequester::ResendPackets(const WebRtc_UWord16* sequenceNumbers,
|
|||||||
return _rtp.SendNACK(sequenceNumbers, length);
|
return _rtp.SendNACK(sequenceNumbers, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
WebRtc_Word32
|
|
||||||
PSNRfromFiles(const WebRtc_Word8 *refFileName, const WebRtc_Word8 *testFileName,
|
|
||||||
WebRtc_Word32 width, WebRtc_Word32 height, double *YPSNRptr)
|
|
||||||
{
|
|
||||||
FILE *refFp = fopen(refFileName, "rb");
|
|
||||||
if( refFp == NULL ) {
|
|
||||||
// cannot open reference file
|
|
||||||
fprintf(stderr, "Cannot open file %s\n", refFileName);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *testFp = fopen(testFileName, "rb");
|
|
||||||
if( testFp == NULL ) {
|
|
||||||
// cannot open test file
|
|
||||||
fprintf(stderr, "Cannot open file %s\n", testFileName);
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
double mse = 0.0;
|
|
||||||
double mseLogSum = 0.0;
|
|
||||||
WebRtc_Word32 frames = 0;
|
|
||||||
|
|
||||||
// Allocating size for one I420 frame.
|
|
||||||
WebRtc_Word32 frameBytes = 3 * width * height >> 1;
|
|
||||||
WebRtc_UWord8 *ref = new WebRtc_UWord8[frameBytes];
|
|
||||||
WebRtc_UWord8 *test = new WebRtc_UWord8[frameBytes];
|
|
||||||
|
|
||||||
WebRtc_Word32 refBytes = (WebRtc_Word32) fread(ref, 1, frameBytes, refFp);
|
|
||||||
WebRtc_Word32 testBytes = (WebRtc_Word32) fread(test, 1, frameBytes, testFp);
|
|
||||||
|
|
||||||
while( refBytes == frameBytes && testBytes == frameBytes )
|
|
||||||
{
|
|
||||||
mse = 0.0;
|
|
||||||
|
|
||||||
int sh = 8;//boundary offset
|
|
||||||
for( int k2 = sh; k2 < height-sh;k2++)
|
|
||||||
for( int k = sh; k < width-sh;k++)
|
|
||||||
{
|
|
||||||
int kk = k2*width + k;
|
|
||||||
mse += (test[kk] - ref[kk]) * (test[kk] - ref[kk]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// divide by number of pixels
|
|
||||||
mse /= (double) (width * height);
|
|
||||||
|
|
||||||
// accumulate for total average
|
|
||||||
mseLogSum += std::log10( mse );
|
|
||||||
frames++;
|
|
||||||
|
|
||||||
refBytes = (int) fread(ref, 1, frameBytes, refFp);
|
|
||||||
testBytes = (int) fread(test, 1, frameBytes, testFp);
|
|
||||||
}
|
|
||||||
// for identical reproduction:
|
|
||||||
if (mse == 0)
|
|
||||||
{
|
|
||||||
*YPSNRptr = 48;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*YPSNRptr = 20.0 * std::log10(255.0) - 10.0 * mseLogSum / frames;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
delete [] ref;
|
|
||||||
delete [] test;
|
|
||||||
|
|
||||||
fclose(refFp);
|
|
||||||
fclose(testFp);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
static double
|
|
||||||
similarity(unsigned long sum_s, unsigned long sum_r, unsigned long sum_sq_s,
|
|
||||||
unsigned long sum_sq_r, unsigned long sum_sxr, int count
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int64_t ssim_n, ssim_d;
|
|
||||||
int64_t c1, c2;
|
|
||||||
const int64_t cc1 = 26634; // (64^2*(.01*255)^2
|
|
||||||
const int64_t cc2 = 239708; // (64^2*(.03*255)^2
|
|
||||||
|
|
||||||
//scale the constants by number of pixels
|
|
||||||
c1 = (cc1*count*count)>>12;
|
|
||||||
c2 = (cc2*count*count)>>12;
|
|
||||||
|
|
||||||
ssim_n = (2*sum_s*sum_r+ c1)*((int64_t) 2*count*sum_sxr-
|
|
||||||
(int64_t) 2*sum_s*sum_r+c2);
|
|
||||||
|
|
||||||
ssim_d = (sum_s*sum_s +sum_r*sum_r+c1)*
|
|
||||||
((int64_t)count*sum_sq_s-(int64_t)sum_s*sum_s +
|
|
||||||
(int64_t)count*sum_sq_r-(int64_t) sum_r*sum_r +c2) ;
|
|
||||||
|
|
||||||
return ssim_n * 1.0 / ssim_d;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double
|
|
||||||
ssim_8x8_c(unsigned char *s, int sp, unsigned char *r, int rp)
|
|
||||||
{
|
|
||||||
unsigned long sum_s = 0;
|
|
||||||
unsigned long sum_r = 0;
|
|
||||||
unsigned long sum_sq_s = 0;
|
|
||||||
unsigned long sum_sq_r = 0;
|
|
||||||
unsigned long sum_sxr = 0;
|
|
||||||
|
|
||||||
int i,j;
|
|
||||||
for (i = 0;i < 8; i++, s += sp,r += rp)
|
|
||||||
{
|
|
||||||
for (j = 0; j < 8; j++)
|
|
||||||
{
|
|
||||||
sum_s += s[j];
|
|
||||||
sum_r += r[j];
|
|
||||||
sum_sq_s += s[j] * s[j];
|
|
||||||
sum_sq_r += r[j] * r[j];
|
|
||||||
sum_sxr += s[j] * r[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(WEBRTC_USE_SSE2)
|
|
||||||
#include <xmmintrin.h>
|
|
||||||
static double
|
|
||||||
ssim_8x8_sse2(unsigned char *s, int sp, unsigned char *r, int rp)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
const __m128i z = _mm_setzero_si128();
|
|
||||||
__m128i sum_s_16 = _mm_setzero_si128();
|
|
||||||
__m128i sum_r_16 = _mm_setzero_si128();
|
|
||||||
__m128i sum_sq_s_32 = _mm_setzero_si128();
|
|
||||||
__m128i sum_sq_r_32 = _mm_setzero_si128();
|
|
||||||
__m128i sum_sxr_32 = _mm_setzero_si128();
|
|
||||||
|
|
||||||
for (i = 0;i < 8; i++,s += sp,r += rp)
|
|
||||||
{
|
|
||||||
const __m128i s_8 = _mm_loadl_epi64((__m128i*)(s));
|
|
||||||
const __m128i r_8 = _mm_loadl_epi64((__m128i*)(r));
|
|
||||||
|
|
||||||
const __m128i s_16 = _mm_unpacklo_epi8(s_8,z);
|
|
||||||
const __m128i r_16 = _mm_unpacklo_epi8(r_8,z);
|
|
||||||
|
|
||||||
sum_s_16 = _mm_adds_epu16(sum_s_16, s_16);
|
|
||||||
sum_r_16 = _mm_adds_epu16(sum_r_16, r_16);
|
|
||||||
const __m128i sq_s_32 = _mm_madd_epi16(s_16, s_16);
|
|
||||||
sum_sq_s_32 = _mm_add_epi32(sum_sq_s_32, sq_s_32);
|
|
||||||
const __m128i sq_r_32 = _mm_madd_epi16(r_16, r_16);
|
|
||||||
sum_sq_r_32 = _mm_add_epi32(sum_sq_r_32, sq_r_32);
|
|
||||||
const __m128i sxr_32 = _mm_madd_epi16(s_16, r_16);
|
|
||||||
sum_sxr_32 = _mm_add_epi32(sum_sxr_32, sxr_32);
|
|
||||||
}
|
|
||||||
|
|
||||||
const __m128i sum_s_32 = _mm_add_epi32(_mm_unpackhi_epi16(sum_s_16, z),
|
|
||||||
_mm_unpacklo_epi16(sum_s_16, z));
|
|
||||||
const __m128i sum_r_32 = _mm_add_epi32(_mm_unpackhi_epi16(sum_r_16, z),
|
|
||||||
_mm_unpacklo_epi16(sum_r_16, z));
|
|
||||||
|
|
||||||
unsigned long sum_s_64[2];
|
|
||||||
unsigned long sum_r_64[2];
|
|
||||||
unsigned long sum_sq_s_64[2];
|
|
||||||
unsigned long sum_sq_r_64[2];
|
|
||||||
unsigned long sum_sxr_64[2];
|
|
||||||
|
|
||||||
_mm_store_si128 ((__m128i*)sum_s_64,
|
|
||||||
_mm_add_epi64(_mm_unpackhi_epi32(sum_s_32, z),
|
|
||||||
_mm_unpacklo_epi32(sum_s_32, z)));
|
|
||||||
_mm_store_si128 ((__m128i*)sum_r_64,
|
|
||||||
_mm_add_epi64(_mm_unpackhi_epi32(sum_r_32, z),
|
|
||||||
_mm_unpacklo_epi32(sum_r_32, z)));
|
|
||||||
_mm_store_si128 ((__m128i*)sum_sq_s_64,
|
|
||||||
_mm_add_epi64(_mm_unpackhi_epi32(sum_sq_s_32, z),
|
|
||||||
_mm_unpacklo_epi32(sum_sq_s_32, z)));
|
|
||||||
_mm_store_si128 ((__m128i*)sum_sq_r_64,
|
|
||||||
_mm_add_epi64(_mm_unpackhi_epi32(sum_sq_r_32, z),
|
|
||||||
_mm_unpacklo_epi32(sum_sq_r_32, z)));
|
|
||||||
_mm_store_si128 ((__m128i*)sum_sxr_64,
|
|
||||||
_mm_add_epi64(_mm_unpackhi_epi32(sum_sxr_32, z),
|
|
||||||
_mm_unpacklo_epi32(sum_sxr_32, z)));
|
|
||||||
|
|
||||||
const unsigned long sum_s = sum_s_64[0] + sum_s_64[1];
|
|
||||||
const unsigned long sum_r = sum_r_64[0] + sum_r_64[1];
|
|
||||||
const unsigned long sum_sq_s = sum_sq_s_64[0] + sum_sq_s_64[1];
|
|
||||||
const unsigned long sum_sq_r = sum_sq_r_64[0] + sum_sq_r_64[1];
|
|
||||||
const unsigned long sum_sxr = sum_sxr_64[0] + sum_sxr_64[1];
|
|
||||||
|
|
||||||
return similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, 64);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
double
|
|
||||||
SSIM_frame(unsigned char *img1, unsigned char *img2, int stride_img1,
|
|
||||||
int stride_img2,int width, int height)
|
|
||||||
{
|
|
||||||
int i,j;
|
|
||||||
unsigned int samples = 0;
|
|
||||||
double ssim_total = 0;
|
|
||||||
double (*ssim_8x8)(unsigned char*, int, unsigned char*, int rp);
|
|
||||||
|
|
||||||
ssim_8x8 = ssim_8x8_c;
|
|
||||||
if (WebRtc_GetCPUInfo(kSSE2))
|
|
||||||
{
|
|
||||||
#if defined(WEBRTC_USE_SSE2)
|
|
||||||
ssim_8x8 = ssim_8x8_sse2;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// sample point start with each 4x4 location
|
|
||||||
for (i = 0; i < height-8; i += 4, img1 += stride_img1 * 4,
|
|
||||||
img2 += stride_img2 * 4)
|
|
||||||
{
|
|
||||||
for (j = 0; j < width - 8; j += 4 )
|
|
||||||
{
|
|
||||||
double v = ssim_8x8(img1 + j, stride_img1, img2 + j, stride_img2);
|
|
||||||
ssim_total += v;
|
|
||||||
samples++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ssim_total /= samples;
|
|
||||||
return ssim_total;
|
|
||||||
}
|
|
||||||
|
|
||||||
WebRtc_Word32
|
|
||||||
SSIMfromFiles(const WebRtc_Word8 *refFileName, const WebRtc_Word8 *testFileName,
|
|
||||||
WebRtc_Word32 width, WebRtc_Word32 height, double *SSIMptr)
|
|
||||||
{
|
|
||||||
FILE *refFp = fopen(refFileName, "rb");
|
|
||||||
if ( refFp == NULL )
|
|
||||||
{
|
|
||||||
// cannot open reference file
|
|
||||||
fprintf(stderr, "Cannot open file %s\n", refFileName);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *testFp = fopen(testFileName, "rb");
|
|
||||||
if ( testFp == NULL )
|
|
||||||
{
|
|
||||||
// cannot open test file
|
|
||||||
fprintf(stderr, "Cannot open file %s\n", testFileName);
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
int frames = 0;
|
|
||||||
|
|
||||||
const int frameBytes = 3 * width *height / 2; // bytes in one frame I420
|
|
||||||
unsigned char *ref = new unsigned char[frameBytes];
|
|
||||||
unsigned char *test = new unsigned char[frameBytes];
|
|
||||||
|
|
||||||
int refBytes = (int) fread(ref, 1, frameBytes, refFp);
|
|
||||||
int testBytes = (int) fread(test, 1, frameBytes, testFp);
|
|
||||||
|
|
||||||
double ssimScene = 0.0; //avgerage SSIM for sequence
|
|
||||||
|
|
||||||
while( refBytes == frameBytes && testBytes == frameBytes )
|
|
||||||
{
|
|
||||||
ssimScene += SSIM_frame(ref, test, width, width, width, height);
|
|
||||||
|
|
||||||
frames++;
|
|
||||||
|
|
||||||
refBytes = (int) fread(ref, 1, frameBytes, refFp);
|
|
||||||
testBytes = (int) fread(test, 1, frameBytes, testFp);
|
|
||||||
}
|
|
||||||
|
|
||||||
//SSIM: normalize/average for sequence
|
|
||||||
ssimScene = ssimScene / frames;
|
|
||||||
*SSIMptr = ssimScene;
|
|
||||||
|
|
||||||
|
|
||||||
delete [] ref;
|
|
||||||
delete [] test;
|
|
||||||
|
|
||||||
|
|
||||||
fclose(refFp);
|
|
||||||
fclose(testFp);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
RTPVideoCodecTypes
|
RTPVideoCodecTypes
|
||||||
ConvertCodecType(const char* plname)
|
ConvertCodecType(const char* plname)
|
||||||
|
@ -262,17 +262,6 @@ private:
|
|||||||
webrtc::RtpRtcp& _rtp;
|
webrtc::RtpRtcp& _rtp;
|
||||||
};
|
};
|
||||||
|
|
||||||
// PSNR & SSIM calculations
|
|
||||||
WebRtc_Word32
|
|
||||||
PSNRfromFiles(const WebRtc_Word8 *refFileName,
|
|
||||||
const WebRtc_Word8 *testFileName, WebRtc_Word32 width,
|
|
||||||
WebRtc_Word32 height, double *YPSNRptr);
|
|
||||||
|
|
||||||
WebRtc_Word32
|
|
||||||
SSIMfromFiles(const WebRtc_Word8 *refFileName,
|
|
||||||
const WebRtc_Word8 *testFileName, WebRtc_Word32 width,
|
|
||||||
WebRtc_Word32 height, double *SSIMptr);
|
|
||||||
|
|
||||||
// Codec type conversion
|
// Codec type conversion
|
||||||
webrtc::RTPVideoCodecTypes
|
webrtc::RTPVideoCodecTypes
|
||||||
ConvertCodecType(const char* plname);
|
ConvertCodecType(const char* plname);
|
||||||
|
292
src/modules/video_coding/main/test/video_metrics.cc
Normal file
292
src/modules/video_coding/main/test/video_metrics.cc
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 The WebRTC 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 <cmath>
|
||||||
|
#include "system_wrappers/interface/cpu_features_wrapper.h"
|
||||||
|
#include "test_util.h"
|
||||||
|
|
||||||
|
WebRtc_Word32
|
||||||
|
PsnrFromFiles(const WebRtc_Word8 *refFileName, const WebRtc_Word8 *testFileName,
|
||||||
|
WebRtc_Word32 width, WebRtc_Word32 height, double *YPsnrPtr)
|
||||||
|
{
|
||||||
|
FILE *refFp = fopen(refFileName, "rb");
|
||||||
|
if (refFp == NULL )
|
||||||
|
{
|
||||||
|
// cannot open reference file
|
||||||
|
fprintf(stderr, "Cannot open file %s\n", refFileName);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *testFp = fopen(testFileName, "rb");
|
||||||
|
if (testFp == NULL )
|
||||||
|
{
|
||||||
|
// cannot open test file
|
||||||
|
fprintf(stderr, "Cannot open file %s\n", testFileName);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
double mse = 0.0;
|
||||||
|
double mseLogSum = 0.0;
|
||||||
|
WebRtc_Word32 frames = 0;
|
||||||
|
|
||||||
|
// Allocating size for one I420 frame.
|
||||||
|
WebRtc_Word32 frameBytes = 3 * width * height >> 1;
|
||||||
|
WebRtc_UWord8 *ref = new WebRtc_UWord8[frameBytes];
|
||||||
|
WebRtc_UWord8 *test = new WebRtc_UWord8[frameBytes];
|
||||||
|
|
||||||
|
WebRtc_Word32 refBytes = (WebRtc_Word32) fread(ref, 1, frameBytes, refFp);
|
||||||
|
WebRtc_Word32 testBytes = (WebRtc_Word32) fread(test, 1, frameBytes, testFp);
|
||||||
|
|
||||||
|
while (refBytes == frameBytes && testBytes == frameBytes)
|
||||||
|
{
|
||||||
|
mse = 0.0;
|
||||||
|
|
||||||
|
WebRtc_Word32 sh = 8; //boundary offset
|
||||||
|
for (WebRtc_Word32 k2 = sh; k2 < height - sh; k2++)
|
||||||
|
for (WebRtc_Word32 k = sh; k < width - sh; k++)
|
||||||
|
{
|
||||||
|
WebRtc_Word32 kk = k2 * width + k;
|
||||||
|
mse += (test[kk] - ref[kk]) * (test[kk] - ref[kk]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// divide by number of pixels
|
||||||
|
mse /= (double) (width * height);
|
||||||
|
|
||||||
|
// accumulate for total average
|
||||||
|
mseLogSum += std::log10(mse);
|
||||||
|
frames++;
|
||||||
|
|
||||||
|
refBytes = (WebRtc_Word32) fread(ref, 1, frameBytes, refFp);
|
||||||
|
testBytes = (WebRtc_Word32) fread(test, 1, frameBytes, testFp);
|
||||||
|
}
|
||||||
|
// for identical reproduction:
|
||||||
|
if (mse == 0)
|
||||||
|
{
|
||||||
|
*YPsnrPtr = 48;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*YPsnrPtr = 20.0 * std::log10(255.0) - 10.0 * mseLogSum / frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
delete [] ref;
|
||||||
|
delete [] test;
|
||||||
|
|
||||||
|
fclose(refFp);
|
||||||
|
fclose(testFp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double
|
||||||
|
Similarity(WebRtc_UWord64 sum_s, WebRtc_UWord64 sum_r, WebRtc_UWord64 sum_sq_s,
|
||||||
|
WebRtc_UWord64 sum_sq_r, WebRtc_UWord64 sum_sxr, WebRtc_Word32 count)
|
||||||
|
{
|
||||||
|
WebRtc_Word64 ssim_n, ssim_d;
|
||||||
|
WebRtc_Word64 c1, c2;
|
||||||
|
const WebRtc_Word64 cc1 = 26634; // (64^2*(.01*255)^2
|
||||||
|
const WebRtc_Word64 cc2 = 239708; // (64^2*(.03*255)^2
|
||||||
|
|
||||||
|
// Scale the constants by number of pixels
|
||||||
|
c1 = (cc1 * count * count) >> 12;
|
||||||
|
c2 = (cc2 * count * count) >> 12;
|
||||||
|
|
||||||
|
ssim_n = (2 * sum_s * sum_r + c1) * ((WebRtc_Word64) 2 * count * sum_sxr-
|
||||||
|
(WebRtc_Word64) 2 * sum_s * sum_r + c2);
|
||||||
|
|
||||||
|
ssim_d = (sum_s * sum_s + sum_r * sum_r + c1)*
|
||||||
|
((WebRtc_Word64)count * sum_sq_s - (WebRtc_Word64)sum_s * sum_s +
|
||||||
|
(WebRtc_Word64)count * sum_sq_r - (WebRtc_Word64) sum_r * sum_r + c2);
|
||||||
|
|
||||||
|
return ssim_n * 1.0 / ssim_d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double
|
||||||
|
Ssim8x8C(WebRtc_UWord8 *s, WebRtc_Word32 sp,
|
||||||
|
WebRtc_UWord8 *r, WebRtc_Word32 rp)
|
||||||
|
{
|
||||||
|
WebRtc_UWord64 sum_s = 0;
|
||||||
|
WebRtc_UWord64 sum_r = 0;
|
||||||
|
WebRtc_UWord64 sum_sq_s = 0;
|
||||||
|
WebRtc_UWord64 sum_sq_r = 0;
|
||||||
|
WebRtc_UWord64 sum_sxr = 0;
|
||||||
|
|
||||||
|
WebRtc_Word32 i, j;
|
||||||
|
for (i = 0; i < 8; i++, s += sp,r += rp)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
{
|
||||||
|
sum_s += s[j];
|
||||||
|
sum_r += r[j];
|
||||||
|
sum_sq_s += s[j] * s[j];
|
||||||
|
sum_sq_r += r[j] * r[j];
|
||||||
|
sum_sxr += s[j] * r[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(WEBRTC_USE_SSE2)
|
||||||
|
#include <xmmintrin.h>
|
||||||
|
static double
|
||||||
|
Ssim8x8Sse2(WebRtc_UWord8 *s, WebRtc_Word32 sp,
|
||||||
|
WebRtc_UWord8 *r, WebRtc_Word32 rp)
|
||||||
|
{
|
||||||
|
WebRtc_Word32 i;
|
||||||
|
const __m128i z = _mm_setzero_si128();
|
||||||
|
__m128i sum_s_16 = _mm_setzero_si128();
|
||||||
|
__m128i sum_r_16 = _mm_setzero_si128();
|
||||||
|
__m128i sum_sq_s_32 = _mm_setzero_si128();
|
||||||
|
__m128i sum_sq_r_32 = _mm_setzero_si128();
|
||||||
|
__m128i sum_sxr_32 = _mm_setzero_si128();
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++, s += sp,r += rp)
|
||||||
|
{
|
||||||
|
const __m128i s_8 = _mm_loadl_epi64((__m128i*)(s));
|
||||||
|
const __m128i r_8 = _mm_loadl_epi64((__m128i*)(r));
|
||||||
|
|
||||||
|
const __m128i s_16 = _mm_unpacklo_epi8(s_8,z);
|
||||||
|
const __m128i r_16 = _mm_unpacklo_epi8(r_8,z);
|
||||||
|
|
||||||
|
sum_s_16 = _mm_adds_epu16(sum_s_16, s_16);
|
||||||
|
sum_r_16 = _mm_adds_epu16(sum_r_16, r_16);
|
||||||
|
const __m128i sq_s_32 = _mm_madd_epi16(s_16, s_16);
|
||||||
|
sum_sq_s_32 = _mm_add_epi32(sum_sq_s_32, sq_s_32);
|
||||||
|
const __m128i sq_r_32 = _mm_madd_epi16(r_16, r_16);
|
||||||
|
sum_sq_r_32 = _mm_add_epi32(sum_sq_r_32, sq_r_32);
|
||||||
|
const __m128i sxr_32 = _mm_madd_epi16(s_16, r_16);
|
||||||
|
sum_sxr_32 = _mm_add_epi32(sum_sxr_32, sxr_32);
|
||||||
|
}
|
||||||
|
|
||||||
|
const __m128i sum_s_32 = _mm_add_epi32(_mm_unpackhi_epi16(sum_s_16, z),
|
||||||
|
_mm_unpacklo_epi16(sum_s_16, z));
|
||||||
|
const __m128i sum_r_32 = _mm_add_epi32(_mm_unpackhi_epi16(sum_r_16, z),
|
||||||
|
_mm_unpacklo_epi16(sum_r_16, z));
|
||||||
|
|
||||||
|
WebRtc_UWord64 sum_s_64[2];
|
||||||
|
WebRtc_UWord64 sum_r_64[2];
|
||||||
|
WebRtc_UWord64 sum_sq_s_64[2];
|
||||||
|
WebRtc_UWord64 sum_sq_r_64[2];
|
||||||
|
WebRtc_UWord64 sum_sxr_64[2];
|
||||||
|
|
||||||
|
_mm_store_si128 ((__m128i*)sum_s_64,
|
||||||
|
_mm_add_epi64(_mm_unpackhi_epi32(sum_s_32, z),
|
||||||
|
_mm_unpacklo_epi32(sum_s_32, z)));
|
||||||
|
_mm_store_si128 ((__m128i*)sum_r_64,
|
||||||
|
_mm_add_epi64(_mm_unpackhi_epi32(sum_r_32, z),
|
||||||
|
_mm_unpacklo_epi32(sum_r_32, z)));
|
||||||
|
_mm_store_si128 ((__m128i*)sum_sq_s_64,
|
||||||
|
_mm_add_epi64(_mm_unpackhi_epi32(sum_sq_s_32, z),
|
||||||
|
_mm_unpacklo_epi32(sum_sq_s_32, z)));
|
||||||
|
_mm_store_si128 ((__m128i*)sum_sq_r_64,
|
||||||
|
_mm_add_epi64(_mm_unpackhi_epi32(sum_sq_r_32, z),
|
||||||
|
_mm_unpacklo_epi32(sum_sq_r_32, z)));
|
||||||
|
_mm_store_si128 ((__m128i*)sum_sxr_64,
|
||||||
|
_mm_add_epi64(_mm_unpackhi_epi32(sum_sxr_32, z),
|
||||||
|
_mm_unpacklo_epi32(sum_sxr_32, z)));
|
||||||
|
|
||||||
|
const WebRtc_UWord64 sum_s = sum_s_64[0] + sum_s_64[1];
|
||||||
|
const WebRtc_UWord64 sum_r = sum_r_64[0] + sum_r_64[1];
|
||||||
|
const WebRtc_UWord64 sum_sq_s = sum_sq_s_64[0] + sum_sq_s_64[1];
|
||||||
|
const WebRtc_UWord64 sum_sq_r = sum_sq_r_64[0] + sum_sq_r_64[1];
|
||||||
|
const WebRtc_UWord64 sum_sxr = sum_sxr_64[0] + sum_sxr_64[1];
|
||||||
|
|
||||||
|
return Similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, 64);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
double
|
||||||
|
SsimFrame(WebRtc_UWord8 *img1, WebRtc_UWord8 *img2, WebRtc_Word32 stride_img1,
|
||||||
|
WebRtc_Word32 stride_img2, WebRtc_Word32 width, WebRtc_Word32 height)
|
||||||
|
{
|
||||||
|
WebRtc_Word32 i,j;
|
||||||
|
WebRtc_UWord32 samples = 0;
|
||||||
|
double ssim_total = 0;
|
||||||
|
double (*ssim_8x8)(WebRtc_UWord8*, WebRtc_Word32,
|
||||||
|
WebRtc_UWord8*, WebRtc_Word32 rp);
|
||||||
|
|
||||||
|
ssim_8x8 = Ssim8x8C;
|
||||||
|
if (WebRtc_GetCPUInfo(kSSE2))
|
||||||
|
{
|
||||||
|
#if defined(WEBRTC_USE_SSE2)
|
||||||
|
ssim_8x8 = Ssim8x8Sse2;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sample point start with each 4x4 location
|
||||||
|
for (i = 0; i < height - 8; i += 4, img1 += stride_img1 * 4,
|
||||||
|
img2 += stride_img2 * 4)
|
||||||
|
{
|
||||||
|
for (j = 0; j < width - 8; j += 4 )
|
||||||
|
{
|
||||||
|
double v = ssim_8x8(img1 + j, stride_img1, img2 + j, stride_img2);
|
||||||
|
ssim_total += v;
|
||||||
|
samples++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ssim_total /= samples;
|
||||||
|
return ssim_total;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebRtc_Word32
|
||||||
|
SsimFromFiles(const WebRtc_Word8 *refFileName, const WebRtc_Word8 *testFileName,
|
||||||
|
WebRtc_Word32 width, WebRtc_Word32 height, double *YSsimPtr)
|
||||||
|
{
|
||||||
|
FILE *refFp = fopen(refFileName, "rb");
|
||||||
|
if (refFp == NULL)
|
||||||
|
{
|
||||||
|
// cannot open reference file
|
||||||
|
fprintf(stderr, "Cannot open file %s\n", refFileName);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *testFp = fopen(testFileName, "rb");
|
||||||
|
if (testFp == NULL)
|
||||||
|
{
|
||||||
|
// cannot open test file
|
||||||
|
fprintf(stderr, "Cannot open file %s\n", testFileName);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebRtc_Word32 frames = 0;
|
||||||
|
|
||||||
|
// Bytes in one frame I420
|
||||||
|
const WebRtc_Word32 frameBytes = 3 * width * height / 2;
|
||||||
|
WebRtc_UWord8 *ref = new WebRtc_UWord8[frameBytes];
|
||||||
|
WebRtc_UWord8 *test = new WebRtc_UWord8[frameBytes];
|
||||||
|
|
||||||
|
WebRtc_Word32 refBytes = (WebRtc_Word32) fread(ref, 1, frameBytes, refFp);
|
||||||
|
WebRtc_Word32 testBytes = (WebRtc_Word32) fread(test, 1, frameBytes, testFp);
|
||||||
|
|
||||||
|
double ssimScene = 0.0; //average SSIM for sequence
|
||||||
|
|
||||||
|
while (refBytes == frameBytes && testBytes == frameBytes )
|
||||||
|
{
|
||||||
|
ssimScene += SsimFrame(ref, test, width, width, width, height);
|
||||||
|
|
||||||
|
frames++;
|
||||||
|
|
||||||
|
refBytes = (WebRtc_Word32) fread(ref, 1, frameBytes, refFp);
|
||||||
|
testBytes = (WebRtc_Word32) fread(test, 1, frameBytes, testFp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSIM: normalize/average for sequence
|
||||||
|
ssimScene = ssimScene / frames;
|
||||||
|
*YSsimPtr = ssimScene;
|
||||||
|
|
||||||
|
delete [] ref;
|
||||||
|
delete [] test;
|
||||||
|
|
||||||
|
fclose(refFp);
|
||||||
|
fclose(testFp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
28
src/modules/video_coding/main/test/video_metrics.h
Normal file
28
src/modules/video_coding/main/test/video_metrics.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011 The WebRTC 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 WEBRTC_MODULES_VIDEO_CODING_TEST_VIDEO_METRICS_H_
|
||||||
|
#define WEBRTC_MODULES_VIDEO_CODING_TEST_VIDEO_METRICS_H_
|
||||||
|
|
||||||
|
|
||||||
|
// PSNR & SSIM calculations
|
||||||
|
WebRtc_Word32
|
||||||
|
PsnrFromFiles(const WebRtc_Word8 *refFileName,
|
||||||
|
const WebRtc_Word8 *testFileName, WebRtc_Word32 width,
|
||||||
|
WebRtc_Word32 height, double *YPsnrPtr);
|
||||||
|
|
||||||
|
WebRtc_Word32
|
||||||
|
SsimFromFiles(const WebRtc_Word8 *refFileName,
|
||||||
|
const WebRtc_Word8 *testFileName, WebRtc_Word32 width,
|
||||||
|
WebRtc_Word32 height, double *YSsimPtr);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // WEBRTC_MODULES_VIDEO_CODING_TEST_VIDEO_METRICS_H_
|
Loading…
Reference in New Issue
Block a user