<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Apr 16, 2018 at 2:42 PM, Deepthi Nandakumar <span dir="ltr"><<a href="mailto:deepthipnandakumar@gmail.com" target="_blank">deepthipnandakumar@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Why are file reads required to compute vmaf? The recon and original yuv sources are available. </div></blockquote><div><br></div><div>File reads are required when you compute vmaf score of the complete file, and it is not required for frame level vmaf score. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><br></div><div>Why floating point reads? </div></div></blockquote><div><br></div><div>I believe there is no floating point reads, the vmaf score is floating point. Correct me if I am wrong.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="gmail_extra"><div><div class="h5"><br><div class="gmail_quote">On Thu, Apr 12, 2018 at 5:31 PM, Ashok Kumar Mishra <span dir="ltr"><<a href="mailto:ashok@multicorewareinc.com" target="_blank">ashok@multicorewareinc.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote"><div><div class="m_-2118448499237267861h5">On Thu, Apr 12, 2018 at 4:43 PM, <span dir="ltr"><<a href="mailto:indumathi@multicorewareinc.com" target="_blank">indumathi@multicorewareinc.co<wbr>m</a>></span> wrote:<br></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="m_-2118448499237267861h5"><span># HG changeset patch<br>
# User IndumathiR<<a href="mailto:indumathi@multicorewareinc.com" target="_blank">indumathi@multicore<wbr>wareinc.com</a>><br>
# Date 1518528290 -19800<br>
# Tue Feb 13 18:54:50 2018 +0530<br>
</span># Node ID 27e3b161cd8b59ad1cae67a96e11e3<wbr>e0506d5017<br>
# Parent 04a337abd70de269cef7d9655365f3<wbr>a3ebde02aa<br>
<span>Add VMAF suppport to report per frame and aggregate VMAF score<br>
<br>
</span>diff -r 04a337abd70d -r 27e3b161cd8b doc/reST/api.rst<br>
--- a/doc/reST/api.rst Thu Apr 12 15:10:59 2018 +0530<br>
<div><div class="m_-2118448499237267861m_-8146764849290315441h5">+++ b/doc/reST/api.rst Tue Feb 13 18:54:50 2018 +0530<br>
@@ -398,7 +398,30 @@<br>
* release library static allocations, reset configured CTU size */<br>
void x265_cleanup(void);<br>
<br>
+VMAF (Video Multi-Method Assessment Fusion)<br>
+=============================<wbr>=============<br>
<br>
+If you set the ENABLE_LIBVMAF cmake option to ON, then x265 will report per frame<br>
+and aggregate VMAF score for the given input and dump the scores in csv file.<br>
+The user also need to specify the :option:`--recon` in command line to get the VMAF scores.<br>
+<br>
+ /* x265_calculate_vmafScore:<br>
+ * returns VMAF score for the input video.<br>
+ * This api must be called only after encoding was done. */<br>
+ double x265_calculate_vmafscore(x265_<wbr>param*, x265_vmaf_data*);<br>
+<br>
+ /* x265_calculate_vmaf_framelevel<wbr>score:<br>
+ * returns VMAF score for each frame in a given input video. */<br>
+ double x265_calculate_vmaf_framelevel<wbr>score(x265_vmaf_framedata*);<br>
+<br>
+.. Note::<br>
+<br>
+ When setting ENABLE_LIBVMAF cmake option to ON, it is recommended to<br>
+ also set ENABLE_SHARED to OFF to prevent build problems.<br>
+ We only need the static library from these builds.<br>
+<br>
+ Binaries build with windows will not have VMAF support.<br>
+<br>
Multi-library Interface<br>
=======================<br>
<br>
</div></div>diff -r 04a337abd70d -r 27e3b161cd8b source/CMakeLists.txt<br>
--- a/source/CMakeLists.txt Thu Apr 12 15:10:59 2018 +0530<br>
<div><div class="m_-2118448499237267861m_-8146764849290315441h5">+++ b/source/CMakeLists.txt Tue Feb 13 18:54:50 2018 +0530<br>
@@ -29,7 +29,7 @@<br>
option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)<br>
mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)<br>
# X265_BUILD must be incremented each time the public API is changed<br>
-set(X265_BUILD 157)<br>
+set(X265_BUILD 158)<br>
configure_file("${PROJECT_SOU<wbr>RCE_DIR}/<a href="http://x265.def.in" rel="noreferrer" target="_blank">x265.def.in</a>"<br>
"${PROJECT_BINARY_DIR}/<a href="http://x265.de" target="_blank">x265.de</a><wbr>f")<br>
configure_file("${PROJECT_SOU<wbr>RCE_DIR}/<a href="http://x265_config.h.in" rel="noreferrer" target="_blank">x265_config.h.in</a>"<br>
@@ -109,6 +109,11 @@<br>
if(NO_ATOMICS)<br>
add_definitions(-DNO_ATOMICS=<wbr>1)<br>
endif(NO_ATOMICS)<br>
+ find_library(VMAF vmaf)<br>
+ option(ENABLE_LIBVMAF "Enable VMAF" OFF)<br>
+ if(ENABLE_LIBVMAF)<br>
+ add_definitions(-DENABLE_LIBVM<wbr>AF)<br>
+ endif()<br>
endif(UNIX)<br>
<br>
if(X64 AND NOT WIN32)<br>
@@ -536,6 +541,9 @@<br>
if(EXTRA_LIB)<br>
target_link_libraries(x265-st<wbr>atic ${EXTRA_LIB})<br>
endif()<br>
+if(ENABLE_LIBVMAF)<br>
+ target_link_libraries(x265-sta<wbr>tic ${VMAF})<br>
+endif()<br>
install(TARGETS x265-static<br>
LIBRARY DESTINATION ${LIB_INSTALL_DIR}<br>
ARCHIVE DESTINATION ${LIB_INSTALL_DIR})<br>
</div></div>diff -r 04a337abd70d -r 27e3b161cd8b source/common/picyuv.h<br>
--- a/source/common/picyuv.h Thu Apr 12 15:10:59 2018 +0530<br>
<span>+++ b/source/common/picyuv.h Tue Feb 13 18:54:50 2018 +0530<br>
@@ -72,6 +72,7 @@<br>
pixel m_maxChromaVLevel;<br>
pixel m_minChromaVLevel;<br>
double m_avgChromaVLevel;<br>
+ double m_vmafScore;<br>
x265_param *m_param;<br>
<br>
PicYuv();<br>
</span>diff -r 04a337abd70d -r 27e3b161cd8b source/encoder/api.cpp<br>
--- a/source/encoder/api.cpp Thu Apr 12 15:10:59 2018 +0530<br>
<div><div class="m_-2118448499237267861m_-8146764849290315441h5">+++ b/source/encoder/api.cpp Tue Feb 13 18:54:50 2018 +0530<br>
@@ -31,6 +31,10 @@<br>
#include "nal.h"<br>
#include "bitcost.h"<br>
<br>
+#if ENABLE_LIBVMAF<br>
+#include "libvmaf.h"<br>
+#endif<br>
+<br>
/* multilib namespace reflectors */<br>
#if LINKED_8BIT<br>
namespace x265_8bit {<br>
@@ -302,13 +306,34 @@<br>
encoder->fetchStats(outputSta<wbr>ts, statsSizeBytes);<br>
}<br>
}<br>
+#if ENABLE_LIBVMAF<br>
+void x265_vmaf_encoder_log(x265_enc<wbr>oder* enc, int argc, char **argv, x265_param *param, x265_vmaf_data *vmafdata)<br>
+{<br>
+ if (enc)<br>
+ {<br>
+ Encoder *encoder = static_cast<Encoder*>(enc);<br>
+ x265_stats stats;<br>
+ stats.aggregateVmafScore = x265_calculate_vmafscore(param<wbr>, vmafdata);<br>
+ if(vmafdata->reference_file)<br>
+ fclose(vmafdata->reference_fil<wbr>e);<br>
+ if(vmafdata->distorted_file)<br>
+ fclose(vmafdata->distorted_fil<wbr>e);<br>
+ if(vmafdata)<br>
+ x265_free(vmafdata);<br>
+ encoder->fetchStats(&stats, sizeof(stats));<br>
+ int padx = encoder->m_sps.conformanceWind<wbr>ow.rightOffset;<br>
+ int pady = encoder->m_sps.conformanceWind<wbr>ow.bottomOffset;<br>
+ x265_csvlog_encode(encoder->m_<wbr>param, &stats, padx, pady, argc, argv);<br>
+ }<br>
+}<br>
+#endif<br>
<br>
void x265_encoder_log(x265_encoder* enc, int argc, char **argv)<br>
{<br>
if (enc)<br>
{<br>
Encoder *encoder = static_cast<Encoder*>(enc);<br>
- x265_stats stats;<br>
+ x265_stats stats;<br>
encoder->fetchStats(&stats, sizeof(stats));<br>
int padx = encoder->m_sps.conformanceWind<wbr>ow.rightOffset;<br>
int pady = encoder->m_sps.conformanceWind<wbr>ow.bottomOffset;<br>
@@ -457,7 +482,13 @@<br>
&x265_csvlog_frame,<br>
&x265_csvlog_encode,<br>
&x265_dither_image,<br>
- &x265_set_analysis_data<br>
+ &x265_set_analysis_data,<br>
+#if ENABLE_LIBVMAF<br>
+ &x265_calculate_vmafscore,<br>
+ &x265_calculate_vmaf_frameleve<wbr>lscore,<br>
+ &x265_vmaf_encoder_log<br>
+#endif<br>
+<br>
};<br>
<br>
typedef const x265_api* (*api_get_func)(int bitDepth);<br>
@@ -751,6 +782,9 @@<br>
/* detailed performance statistics */<br>
fprintf(csvfp, ", DecideWait (ms), Row0Wait (ms), Wall time (ms), Ref Wait Wall (ms), Total CTU time (ms),"<br>
"Stall Time (ms), Total frame time (ms), Avg WPP, Row Blocks");<br>
+#if ENABLE_LIBVMAF<br>
+ fprintf(csvfp, ", VMAF Frame Score");<br>
+#endif<br>
}<br>
fprintf(csvfp, "\n");<br>
}<br>
@@ -759,6 +793,9 @@<br>
fputs(summaryCSVHeader, csvfp);<br>
if (param->csvLogLevel >= 2 || param->maxCLL || param->maxFALL)<br>
fputs("MaxCLL, MaxFALL,", csvfp);<br>
+#if ENABLE_LIBVMAF<br>
+ fputs(" Aggregate VMAF Score,", csvfp);<br>
+#endif<br>
fputs(" Version\n", csvfp);<br>
}<br>
}<br>
@@ -868,6 +905,9 @@<br>
frameStats->totalFrameTime);<br>
<br>
fprintf(param->csvfpt, " %.3lf, %d", frameStats->avgWPP, frameStats->countRowBlocks);<br>
+#if ENABLE_LIBVMAF<br>
+ fprintf(param->csvfpt, ", %lf", frameStats->vmafFrameScore);<br>
+#endif<br>
}<br>
fprintf(param->csvfpt, "\n");<br>
fflush(stderr);<br>
@@ -886,7 +926,11 @@<br>
fputs(summaryCSVHeader, p->csvfpt);<br>
if (p->csvLogLevel >= 2 || p->maxCLL || p->maxFALL)<br>
fputs("MaxCLL, MaxFALL,", p->csvfpt);<br>
+#if ENABLE_LIBVMAF<br>
+ fputs(" Aggregate VMAF score,", p->csvfpt);<br>
+#endif<br>
fputs(" Version\n",p->csvfpt);<br>
+<br>
}<br>
// CLI arguments or other<br>
if (argc)<br>
@@ -919,7 +963,6 @@<br>
char buffer[200];<br>
strftime(buffer, 128, "%c", timeinfo);<br>
fprintf(p->csvfpt, ", %s, ", buffer);<br>
-<br>
// elapsed time, fps, bitrate<br>
fprintf(p->csvfpt, "%.2f, %.2f, %.2f,",<br>
stats->elapsedEncodeTime, stats->encodedPictureCount / stats->elapsedEncodeTime, stats->bitrate);<br>
@@ -981,7 +1024,11 @@<br>
fprintf(p->csvfpt, " -, -, -, -, -, -, -,");<br>
if (p->csvLogLevel >= 2 || p->maxCLL || p->maxFALL)<br>
fprintf(p->csvfpt, " %-6u, %-6u,", stats->maxCLL, stats->maxFALL);<br>
+#if ENABLE_LIBVMAF<br>
+ fprintf(p->csvfpt, " %lf,", stats->aggregateVmafScore);<br>
+#endif<br>
fprintf(p->csvfpt, " %s\n", api->version_str);<br>
+<br>
}<br>
}<br>
<br>
@@ -1072,4 +1119,318 @@<br>
}<br>
}<br>
<br>
+#if ENABLE_LIBVMAF<br>
+/* Read y values of single frame for 8-bit input */<br>
+int read_image_byte(FILE *file, float *buf, int width, int height, int stride)<br>
+{<br>
+ char *byte_ptr = (char *)buf;<br>
+ unsigned char *tmp_buf = 0;<br>
+ int i, j;<br>
+ int ret = 1;<br>
+<br>
+ if (width <= 0 || height <= 0)<br>
+ {<br>
+ goto fail_or_end;<br>
+ }<br>
+<br>
+ if (!(tmp_buf = (unsigned char*)malloc(width)))<br>
+ {<br>
+ goto fail_or_end;<br>
+ }<br>
+<br>
+ for (i = 0; i < height; ++i)<br>
+ {<br>
+ float *row_ptr = (float *)byte_ptr;<br>
+<br>
+ if (fread(tmp_buf, 1, width, file) != (size_t)width)<br>
+ {<br>
+ goto fail_or_end;<br>
+ }<br>
+<br>
+ for (j = 0; j < width; ++j)<br>
+ {<br>
+ row_ptr[j] = tmp_buf[j];<br>
+ }<br>
+<br>
+ byte_ptr += stride;<br>
+ }<br>
+<br>
+ ret = 0;<br>
+<br>
+fail_or_end:<br>
+ free(tmp_buf);<br>
+ return ret;<br>
+}<br>
+/* Read y values of single frame for 10-bit input */<br>
+int read_image_word(FILE *file, float *buf, int width, int height, int stride)<br>
+{<br>
+ char *byte_ptr = (char *)buf;<br>
+ unsigned short *tmp_buf = 0;<br>
+ int i, j;<br>
+ int ret = 1;<br>
+<br>
+ if (width <= 0 || height <= 0)<br>
+ {<br>
+ goto fail_or_end;<br>
+ }<br>
+<br>
+ if (!(tmp_buf = (unsigned short*)malloc(width * 2))) // '*2' to accommodate words<br>
+ {<br>
+ goto fail_or_end;<br>
+ }<br>
+<br>
+ for (i = 0; i < height; ++i)<br>
+ {<br>
+ float *row_ptr = (float *)byte_ptr;<br>
+<br>
+ if (fread(tmp_buf, 2, width, file) != (size_t)width) // '2' for word<br>
+ {<br>
+ goto fail_or_end;<br>
+ }<br>
+<br>
+ for (j = 0; j < width; ++j)<br>
+ {<br>
+ row_ptr[j] = tmp_buf[j] / 4.0; // '/4' to convert from 10 to 8-bit<br>
+ }<br>
+<br>
+ byte_ptr += stride;<br>
+ }<br>
+<br>
+ ret = 0;<br>
+<br>
+fail_or_end:<br>
+ free(tmp_buf);<br>
+ return ret;<br>
+}<br>
+<br>
+int read_frame(float *reference_data, float *distorted_data, float *temp_data, int stride_byte, void *s)<br>
+{<br>
+ x265_vmaf_data *user_data = (x265_vmaf_data *)s;<br>
+ int ret;<br>
+<br>
+ // read reference y<br>
+ if (user_data->internalBitDepth == 8)<br>
+ {<br>
+ ret = read_image_byte(user_data->ref<wbr>erence_file, reference_data, user_data->width, user_data->height, stride_byte);<br>
+ }<br>
+ else if (user_data->internalBitDepth == 10)<br>
+ {<br>
+ ret = read_image_word(user_data->ref<wbr>erence_file, reference_data, user_data->width, user_data->height, stride_byte);<br>
+ }<br>
+ else<br>
+ {<br>
+ x265_log(NULL, X265_LOG_ERROR, "Invalid bitdepth\n");<br>
+ return 1;<br>
+ }<br>
+ if (ret)<br>
+ {<br>
+ if (feof(user_data->reference_fil<wbr>e))<br>
+ {<br>
+ ret = 2; // OK if end of file<br>
+ }<br>
+ return ret;<br>
+ }<br>
+<br>
+ // read distorted y<br>
+ if (user_data->internalBitDepth == 8)<br>
+ {<br>
+ ret = read_image_byte(user_data->dis<wbr>torted_file, distorted_data, user_data->width, user_data->height, stride_byte);<br>
+ }<br>
+ else if (user_data->internalBitDepth == 10)<br>
+ {<br>
+ ret = read_image_word(user_data->dis<wbr>torted_file, distorted_data, user_data->width, user_data->height, stride_byte);<br>
+ }<br>
+ else<br>
+ {<br>
+ x265_log(NULL, X265_LOG_ERROR, "Invalid bitdepth\n");<br>
+ return 1;<br>
+ }<br>
+ if (ret)<br>
+ {<br>
+ if (feof(user_data->distorted_fil<wbr>e))<br>
+ {<br>
+ ret = 2; // OK if end of file<br>
+ }<br>
+ return ret;<br>
+ }<br>
+<br>
+ // reference skip u and v<br>
+ if (user_data->internalBitDepth == 8)<br>
+ {<br>
+ if (fread(temp_data, 1, user_data->offset, user_data->reference_file) != (size_t)user_data->offset)<br>
+ {<br>
+ x265_log(NULL, X265_LOG_ERROR, "reference fread to skip u and v failed.\n");<br>
+ goto fail_or_end;<br>
+ }<br>
+ }<br>
+ else if (user_data->internalBitDepth == 10)<br>
+ {<br>
+ if (fread(temp_data, 2, user_data->offset, user_data->reference_file) != (size_t)user_data->offset)<br>
+ {<br>
+ x265_log(NULL, X265_LOG_ERROR, "reference fread to skip u and v failed.\n");<br>
+ goto fail_or_end;<br>
+ }<br>
+ }<br>
+ else<br>
+ {<br>
+ x265_log(NULL, X265_LOG_ERROR, "Invalid format\n");<br>
+ goto fail_or_end;<br>
+ }<br>
+<br>
+ // distorted skip u and v<br>
+ if (user_data->internalBitDepth == 8)<br>
+ {<br>
+ if (fread(temp_data, 1, user_data->offset, user_data->distorted_file) != (size_t)user_data->offset)<br>
+ {<br>
+ x265_log(NULL, X265_LOG_ERROR, "distorted fread to skip u and v failed.\n");<br>
+ goto fail_or_end;<br>
+ }<br>
+ }<br>
+ else if (user_data->internalBitDepth == 10)<br>
+ {<br>
+ if (fread(temp_data, 2, user_data->offset, user_data->distorted_file) != (size_t)user_data->offset)<br>
+ {<br>
+ x265_log(NULL, X265_LOG_ERROR, "distorted fread to skip u and v failed.\n");<br>
+ goto fail_or_end;<br>
+ }<br>
+ }<br>
+ else<br>
+ {<br>
+ x265_log(NULL, X265_LOG_ERROR, "Invalid format\n");<br>
+ goto fail_or_end;<br>
+ }<br>
+<br>
+<br>
+fail_or_end:<br>
+ return ret;<br>
+}<br>
+<br>
+double x265_calculate_vmafscore(x265_<wbr>param *param, x265_vmaf_data *data)<br>
+{<br>
+ double score;<br>
+<br>
+ data->width = param->sourceWidth;<br>
+ data->height = param->sourceHeight;<br>
+ data->internalBitDepth = param->internalBitDepth;<br>
+<br>
+ if (param->internalCsp == X265_CSP_I420)<br>
+ {<br>
+ if ((param->sourceWidth * param->sourceHeight) % 2 != 0)<br>
+ x265_log(NULL, X265_LOG_ERROR, "Invalid file size\n");<br>
+ data->offset = param->sourceWidth * param->sourceHeight / 2;<br>
+ }<br>
+ else if (param->internalCsp == X265_CSP_I422)<br>
+ data->offset = param->sourceWidth * param->sourceHeight;<br>
+ else if (param->internalCsp == X265_CSP_I444)<br>
+ data->offset = param->sourceWidth * param->sourceHeight * 2;<br>
+ else<br>
+ x265_log(NULL, X265_LOG_ERROR, "Invalid format\n");<br>
+<br>
+ compute_vmaf(&score, vcd->format, data->width, data->height, read_frame, data, vcd->model_path, vcd->log_path, vcd->log_fmt, vcd->disable_clip, vcd->disable_avx, vcd->enable_transform, vcd->phone_model, vcd->psnr, vcd->ssim, vcd->ms_ssim, vcd->pool);<br>
+<br>
+ return score;<br>
+}<br>
+<br>
+int read_frame_10bit(float *reference_data, float *distorted_data, float *temp_data, int stride, void *s)<br>
+{<br>
+ x265_vmaf_framedata *user_data = (x265_vmaf_framedata *)s;<br>
+<br>
+ PicYuv *reference_frame = (PicYuv *)user_data->reference_frame;<br>
+ PicYuv *distorted_frame = (PicYuv *)user_data->distorted_frame;<br>
+<br>
+ if(!user_data->frame_set) {<br>
+<br>
+ int reference_stride = reference_frame->m_stride;<br>
+ int distorted_stride = distorted_frame->m_stride;<br>
+<br>
+ const uint16_t *reference_ptr = (const uint16_t *)reference_frame->m_picOrg[0]<wbr>;<br>
+ const uint16_t *distorted_ptr = (const uint16_t *)distorted_frame->m_picOrg[0]<wbr>;<br>
+<br>
+ temp_data = reference_data;<br>
+<br>
+ int height = user_data->height;<br>
+ int width = user_data->width;<br>
+<br>
+ int i,j;<br>
+ for (i = 0; i < height; i++) {<br>
+ for ( j = 0; j < width; j++) {<br>
+ temp_data[j] = ((float)reference_ptr[j] / 4.0);<br>
+ }<br>
+ reference_ptr += reference_stride;<br>
+ temp_data += stride / sizeof(*temp_data);<br>
+ }<br>
+<br>
+ temp_data = distorted_data;<br>
+ for (i = 0; i < height; i++) {<br>
+ for (j = 0; j < width; j++) {<br>
+ temp_data[j] = ((float)distorted_ptr[j] / 4.0);<br>
+ }<br>
+ distorted_ptr += distorted_stride;<br>
+ temp_data += stride / sizeof(*temp_data);<br>
+ }<br>
+<br>
+ user_data->frame_set = 1;<br>
+ return 0;<br>
+ }<br>
+ return 2;<br>
+}<br>
+<br>
+int read_frame_8bit(float *reference_data, float *distorted_data, float *temp_data, int stride, void *s)<br>
+{<br>
+ x265_vmaf_framedata *user_data = (x265_vmaf_framedata *)s;<br>
+<br>
+ PicYuv *reference_frame = (PicYuv *)user_data->reference_frame;<br>
+ PicYuv *distorted_frame = (PicYuv *)user_data->distorted_frame;<br>
+<br>
+ if(!user_data->frame_set) {<br>
+<br>
+ int reference_stride = reference_frame->m_stride;<br>
+ int distorted_stride = distorted_frame->m_stride;<br>
+<br>
+ const uint8_t *reference_ptr = (const uint8_t *)reference_frame->m_picOrg[0]<wbr>;<br>
+ const uint8_t *distorted_ptr = (const uint8_t *)distorted_frame->m_picOrg[0]<wbr>;<br>
+<br>
+ temp_data = reference_data;<br>
+<br>
+ int height = user_data->height;<br>
+ int width = user_data->width;<br>
+<br>
+ int i,j;<br>
+ for (i = 0; i < height; i++) {<br>
+ for ( j = 0; j < width; j++) {<br>
+ temp_data[j] = (float)reference_ptr[j];<br>
+ }<br>
+ reference_ptr += reference_stride;<br>
+ temp_data += stride / sizeof(*temp_data);<br>
+ }<br>
+<br>
+ temp_data = distorted_data;<br>
+ for (i = 0; i < height; i++) {<br>
+ for (j = 0; j < width; j++) {<br>
+ temp_data[j] = (float)distorted_ptr[j];<br>
+ }<br>
+ distorted_ptr += distorted_stride;<br>
+ temp_data += stride / sizeof(*temp_data);<br>
+ }<br>
+<br>
+ user_data->frame_set = 1;<br>
+ return 0;<br>
+ }<br>
+ return 2;<br>
+}<br>
+<br>
+double x265_calculate_vmaf_framelevel<wbr>score(x265_vmaf_framedata *vmafframedata)<br>
+{<br>
+ double score;<br>
+ int (*read_frame)(float *reference_data, float *distorted_data, float *temp_data,<br>
+ int stride, void *s);<br>
+ if (vmafframedata->internalBitDep<wbr>th == 8)<br>
+ read_frame = read_frame_8bit;<br>
+ else<br>
+ read_frame = read_frame_10bit;<br>
+ compute_vmaf(&score, vcd->format, vmafframedata->width, vmafframedata->height, read_frame, vmafframedata, vcd->model_path, vcd->log_path, vcd->log_fmt, vcd->disable_clip, vcd->disable_avx, vcd->enable_transform, vcd->phone_model, vcd->psnr, vcd->ssim, vcd->ms_ssim, vcd->pool);<br>
+<br>
+ return score;<br>
+}<br>
+#endif<br>
} /* end namespace or extern "C" */<br>
</div></div>diff -r 04a337abd70d -r 27e3b161cd8b source/encoder/encoder.cpp<br>
--- a/source/encoder/encoder.cpp Thu Apr 12 15:10:59 2018 +0530<br>
<span>+++ b/source/encoder/encoder.cpp Tue Feb 13 18:54:50 2018 +0530<br>
@@ -2127,6 +2127,9 @@<br>
#define ELAPSED_MSEC(start, end) (((double)(end) - (start)) / 1000)<br>
if (m_param->csvLogLevel >= 2)<br>
{<br>
+#if ENABLE_LIBVMAF<br>
+ frameStats->vmafFrameScore = curFrame->m_fencPic->m_vmafSco<wbr>re;<br>
+#endif<br>
frameStats->decideWaitTime = ELAPSED_MSEC(0, curEncoder->m_slicetypeWaitTim<wbr>e);<br>
frameStats->row0WaitTime = ELAPSED_MSEC(curEncoder->m_sta<wbr>rtCompressTime, curEncoder->m_row0WaitTime);<br>
frameStats->wallTime = ELAPSED_MSEC(curEncoder->m_row<wbr>0WaitTime, curEncoder->m_endCompressTime)<wbr>;<br>
</span>diff -r 04a337abd70d -r 27e3b161cd8b source/encoder/frameencoder.cp<wbr>p<br>
--- a/source/encoder/frameencoder.<wbr>cpp Thu Apr 12 15:10:59 2018 +0530<br>
<span>+++ b/source/encoder/frameencoder.<wbr>cpp Tue Feb 13 18:54:50 2018 +0530<br>
</span>@@ -864,6 +864,9 @@<br>
<span> m_frameFilter.processRow(i - m_filterRowDelay);<br>
}<br>
}<br>
+#if ENABLE_LIBVMAF<br>
</span>+ vmafFrameLevelScore();<br>
<span>+#endif<br>
<br>
if (m_param->maxSlices > 1)<br>
{<br>
</span>@@ -932,7 +935,7 @@<br>
<span> updateChecksum(reconPic->m_pi<wbr>cOrg[1], m_checksum[1], height, width, stride, 0, cuHeight);<br>
updateChecksum(reconPic->m_pi<wbr>cOrg[2], m_checksum[2], height, width, stride, 0, cuHeight);<br>
}<br>
- }<br>
+ }<br>
} // end of (m_param->maxSlices > 1)<br>
<br>
if (m_param->rc.bStatWrite)<br>
</span>@@ -1189,7 +1192,7 @@<br>
<span> m_cuStats.accumulate(m_tld[i]<wbr>.analysis.m_stats[m_jpId], *m_param);<br>
#endif<br>
<br>
- m_endFrameTime = x265_mdate();<br>
+ m_endFrameTime = x265_mdate();<br>
}<br>
<br>
void FrameEncoder::encodeSlice(uint<wbr>32_t sliceAddr)<br>
</span>@@ -2058,11 +2061,36 @@<br>
m_nr->nrOffsetDenoise[cat][0] = 0;<br>
}<br>
}<br>
+#if ENABLE_LIBVMAF<br>
+void FrameEncoder::vmafFrameLevelSc<wbr>ore()<br>
+{<br>
<span>+ PicYuv *fenc = m_frame->m_fencPic;<br>
+ PicYuv *recon = m_frame->m_reconPic;<br>
+<br>
+ x265_vmaf_framedata *vmafframedata = (x265_vmaf_framedata*)x265_mal<wbr>loc(sizeof(x265_vmaf_framedata<wbr>));<br>
+ if (!vmafframedata)<br>
+ {<br>
+ x265_log(NULL, X265_LOG_ERROR, "vmaf frame data alloc failed\n");<br>
+ }<br>
+<br>
+ vmafframedata->height = fenc->m_picHeight;<br>
+ vmafframedata->width = fenc->m_picWidth;<br>
+ vmafframedata->frame_set = 0;<br>
+ vmafframedata->internalBitDept<wbr>h = m_param->internalBitDepth;<br>
+ vmafframedata->reference_frame = fenc;<br>
+ vmafframedata->distorted_frame = recon;<br>
+<br>
+ fenc->m_vmafScore = x265_calculate_vmaf_framelevel<wbr>score(vmafframedata);<br>
+<br>
+ if (vmafframedata)<br>
+ x265_free(vmafframedata);<br>
+}<br>
+#endif<br>
<br>
</span><span> Frame *FrameEncoder::getEncodedPictu<wbr>re(NALList& output)<br>
{<br>
if (m_frame)<br>
- {<br>
+ {<br>
/* block here until worker thread completes */<br>
m_done.wait();<br>
<br>
</span>diff -r 04a337abd70d -r 27e3b161cd8b source/encoder/frameencoder.h<br>
--- a/source/encoder/frameencoder.<wbr>h Thu Apr 12 15:10:59 2018 +0530<br>
+++ b/source/encoder/frameencoder.<wbr>h Tue Feb 13 18:54:50 2018 +0530<br>
@@ -240,6 +240,9 @@<br>
void enqueueRowFilter(int row) { WaveFront::enqueueRow(row * 2 + 1); }<br>
void enableRowEncoder(int row) { WaveFront::enableRow(row * 2 + 0); }<br>
void enableRowFilter(int row) { WaveFront::enableRow(row * 2 + 1); }<br>
+#if ENABLE_LIBVMAF<br>
+ void vmafFrameLevelScore();<br>
+#endif<br>
};<br>
}<br>
<br>
diff -r 04a337abd70d -r 27e3b161cd8b source/x265.cpp<br>
--- a/source/x265.cpp Thu Apr 12 15:10:59 2018 +0530<br>
<div><div class="m_-2118448499237267861m_-8146764849290315441h5">+++ b/source/x265.cpp Tue Feb 13 18:54:50 2018 +0530<br>
@@ -75,6 +75,7 @@<br>
const char* reconPlayCmd;<br>
const x265_api* api;<br>
x265_param* param;<br>
+ x265_vmaf_data* vmafData;<br>
bool bProgress;<br>
bool bForceY4m;<br>
bool bDither;<br>
@@ -96,6 +97,7 @@<br>
reconPlayCmd = NULL;<br>
api = NULL;<br>
param = NULL;<br>
+ vmafData = NULL;<br>
framesToBeEncoded = seek = 0;<br>
totalbytes = 0;<br>
bProgress = true;<br>
@@ -216,6 +218,14 @@<br>
x265_log(NULL, X265_LOG_ERROR, "param alloc failed\n");<br>
return true;<br>
}<br>
+#if ENABLE_LIBVMAF<br>
+ vmafData = (x265_vmaf_data*)x265_malloc(s<wbr>izeof(x265_vmaf_data));<br>
+ if(!vmafData)<br>
+ {<br>
+ x265_log(NULL, X265_LOG_ERROR, "vmaf data alloc failed\n");<br>
+ return true;<br>
+ }<br>
+#endif<br>
<br>
if (api->param_default_preset(par<wbr>am, preset, tune) < 0)<br>
{<br>
@@ -363,6 +373,7 @@<br>
info.frameCount = 0;<br>
getParamAspectRatio(param, info.sarWidth, info.sarHeight);<br>
<br>
+<br>
this->input = InputFile::open(info, this->bForceY4m);<br>
if (!this->input || this->input->isFail())<br>
{<br>
@@ -439,7 +450,30 @@<br>
param->sourceWidth, param->sourceHeight, param->fpsNum, param->fpsDenom,<br>
x265_source_csp_names[param-><wbr>internalCsp]);<br>
}<br>
+#if ENABLE_LIBVMAF<br>
+ if (!reconfn)<br>
+ {<br>
+ x265_log(param, X265_LOG_ERROR, "recon file must be specified to get VMAF score, try --help for help\n");<br>
+ return true;<br>
+ }<br>
+ const char *str = strrchr(info.filename, '.');<br>
<br>
+ if (!strcmp(str, ".y4m"))<br>
+ {<br>
+ x265_log(param, X265_LOG_ERROR, "VMAF supports YUV file format only.\n");<br>
+ return true;<br>
+ }<br>
+ if(param->internalCsp == X265_CSP_I420 || param->internalCsp == X265_CSP_I422 || param->internalCsp == X265_CSP_I444)<br>
+ {<br>
+ vmafData->reference_file = x265_fopen(inputfn, "rb");<br>
+ vmafData->distorted_file = x265_fopen(reconfn, "rb");<br>
+ }<br>
+ else<br>
+ {<br>
+ x265_log(param, X265_LOG_ERROR, "VMAF will support only yuv420p, yu422p, yu444p, yuv420p10le, yuv422p10le, yuv444p10le formats.\n");<br>
+ return true;<br>
+ }<br>
+#endif<br>
this->output = OutputFile::open(outputfn, info);<br>
if (this->output->isFail())<br>
{<br>
@@ -555,7 +589,9 @@<br>
<br>
x265_param* param = cliopt.param;<br>
const x265_api* api = cliopt.api;<br>
-<br>
+#if ENABLE_LIBVMAF<br>
+ x265_vmaf_data* vmafdata = cliopt.vmafData;<br>
+#endif<br>
/* This allows muxers to modify bitstream format */<br>
cliopt.output->setParam(param<wbr>);<br>
<br>
@@ -712,7 +748,7 @@<br>
if (!numEncoded)<br>
break;<br>
}<br>
-<br>
+<br>
/* clear progress report */<br>
if (cliopt.bProgress)<br>
fprintf(stderr, "%*s\r", 80, " ");<br>
@@ -723,7 +759,11 @@<br>
<br>
api->encoder_get_stats(encode<wbr>r, &stats, sizeof(stats));<br>
if (param->csvfn && !b_ctrl_c)<br>
+#if ENABLE_LIBVMAF<br>
+ api->vmaf_encoder_log(encoder, argc, argv, param, vmafdata);<br>
+#else<br>
api->encoder_log(encoder, argc, argv);<br>
+#endif<br>
api->encoder_close(encoder);<br>
<br>
int64_t second_largest_pts = 0;<br>
</div></div>diff -r 04a337abd70d -r 27e3b161cd8b source/x265.h<br>
--- a/source/x265.h Thu Apr 12 15:10:59 2018 +0530<br>
<div class="m_-2118448499237267861m_-8146764849290315441HOEnZb"><div class="m_-2118448499237267861m_-8146764849290315441h5">+++ b/source/x265.h Tue Feb 13 18:54:50 2018 +0530<br>
@@ -209,6 +209,7 @@<br>
x265_cu_stats cuStats;<br>
x265_pu_stats puStats;<br>
double totalFrameTime;<br>
+ double vmafFrameScore;<br>
} x265_frame_stats;<br>
<br>
typedef struct x265_ctu_info_t<br>
@@ -536,6 +537,7 @@<br>
double elapsedEncodeTime; /* wall time since encoder was opened */<br>
double elapsedVideoTime; /* encoded picture count / frame rate */<br>
double bitrate; /* accBits / elapsed video time */<br>
+ double aggregateVmafScore; /* aggregate VMAF score for input video*/<br>
uint64_t accBits; /* total bits output thus far */<br>
uint32_t encodedPictureCount; /* number of output pictures thus far */<br>
uint32_t totalWPFrames; /* number of uni-directional weighted frames used */<br>
@@ -572,6 +574,47 @@<br>
float bitrateFactor;<br>
} x265_zone;<br>
<br>
+/* data to calculate aggregate VMAF score */<br>
+typedef struct x265_vmaf_data<br>
+{<br>
+ int width;<br>
+ int height;<br>
+ size_t offset;<br>
+ int internalBitDepth;<br>
+ FILE *reference_file; /* FILE pointer for input file */<br>
+ FILE *distorted_file; /* FILE pointer for recon file generated*/<br>
+}x265_vmaf_data;<br>
+<br>
+/* data to calculate frame level VMAF score */<br>
+typedef struct x265_vmaf_framedata<br>
+{<br>
+ int width;<br>
+ int height;<br>
+ int frame_set;<br>
+ int internalBitDepth;<br>
+ void *reference_frame; /* points to fenc of particular frame */<br>
+ void *distorted_frame; /* points to recon of particular frame */<br>
+}x265_vmaf_framedata;<br>
+<br>
+/* common data needed to calculate both frame level and video level VMAF scores */<br>
+typedef struct x265_vmaf_commondata<br>
+{<br>
+ char *format;<br>
+ char *model_path;<br>
+ char *log_path;<br>
+ char *log_fmt;<br>
+ int disable_clip;<br>
+ int disable_avx;<br>
+ int enable_transform;<br>
+ int phone_model;<br>
+ int psnr;<br>
+ int ssim;<br>
+ int ms_ssim;<br>
+ char *pool;<br>
+}x265_vmaf_commondata;<br>
+<br>
+static const x265_vmaf_commondata vcd[] = {NULL, (char *)"/usr/local/share/model/vmaf<wbr>_v0.6.1.pkl", NULL, NULL, 0, 0, 0, 0, 0, 0, 0, NULL};<br>
+<br>
/* x265 input parameters<br>
*<br>
* For version safety you may use x265_param_alloc/free() to manage the<br>
@@ -1811,6 +1854,22 @@<br>
/* In-place downshift from a bit-depth greater than 8 to a bit-depth of 8, using<br>
* the residual bits to dither each row. */<br>
void x265_dither_image(x265_picture *, int picWidth, int picHeight, int16_t *errorBuf, int bitDepth);<br>
+#if ENABLE_LIBVMAF<br>
+/* x265_calculate_vmafScore:<br>
+ * returns VMAF score for the input video.<br>
+ * This api must be called only after encoding was done. */<br>
+double x265_calculate_vmafscore(x265_<wbr>param*, x265_vmaf_data*);<br>
+<br>
+/* x265_calculate_vmaf_framelevel<wbr>score:<br>
+ * returns VMAF score for each frame in a given input video. */<br>
+double x265_calculate_vmaf_framelevel<wbr>score(x265_vmaf_framedata*);<br>
+/* x265_vmaf_encoder_log:<br>
+ * write a line to the configured CSV file. If a CSV filename was not<br>
+ * configured, or file open failed, this function will perform no write.<br>
+ * This api will be called only when ENABLE_LIBVMAF cmake option is set */<br>
+void x265_vmaf_encoder_log(x265_enc<wbr>oder *encoder, int argc, char **argv, x265_param*, x265_vmaf_data*);<br>
+<br>
+#endif<br>
<br>
#define X265_MAJOR_VERSION 1<br>
<br>
@@ -1864,6 +1923,11 @@<br>
void (*csvlog_encode)(const x265_param*, const x265_stats *, int, int, int, char**);<br>
void (*dither_image)(x265_picture*, int, int, int16_t*, int);<br>
int (*set_analysis_data)(x265_enc<wbr>oder *encoder, x265_analysis_data *analysis_data, int poc, uint32_t cuBytes);<br>
+#if ENABLE_LIBVMAF<br>
+ double (*calculate_vmafscore)(x265_pa<wbr>ram *, x265_vmaf_data *);<br>
+ double (*calculate_vmaf_framelevelsco<wbr>re)(x265_vmaf_framedata *);<br>
+ void (*vmaf_encoder_log)(x265_encod<wbr>er*, int, char**, x265_param *, x265_vmaf_data *);<br>
+#endif<br>
/* add new pointers to the end, or increment X265_MAJOR_VERSION */<br>
} x265_api;<br>
<br>
</div></div><br></div></div>______________________________<wbr>_________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/l<wbr>istinfo/x265-devel</a><br>
<br></blockquote></div></div><div class="gmail_extra"><br></div><div class="gmail_extra">Thanks. Pushed to default.</div></div>
<br>______________________________<wbr>_________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/l<wbr>istinfo/x265-devel</a><br>
<br></blockquote></div><br><br clear="all"><div><br></div></div></div><span class="HOEnZb"><font color="#888888">-- <br><div class="m_-2118448499237267861gmail_signature" data-smartmail="gmail_signature">Deepthi</div>
</font></span></div>
<br>______________________________<wbr>_________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/<wbr>listinfo/x265-devel</a><br>
<br></blockquote></div><br></div></div>