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