[x265] [PATCH] cli: move CSV and dither features into x265-extras, export from CLI on Windows

Steve Borho steve at borho.org
Sat Jul 11 23:59:53 CEST 2015


# HG changeset patch
# User Steve Borho <steve at borho.org>
# Date 1436651891 18000
#      Sat Jul 11 16:58:11 2015 -0500
# Node ID 3a22c76ff2a4249985a0a45e361cda2428cf7aa7
# Parent  79f4906e9cb847e9bf6325cb0d2e6914ec9b9c65
cli: move CSV and dither features into x265-extras, export from CLI on Windows

If other applications would like to take advantage of our CSV file writing
functions, or the dither feature, they may either build x265-extras.cpp into
their application, or on Windows they can use these functions directly from the
CLI (just change the extension from EXE to DLL and use it as a shared library).

diff -r 79f4906e9cb8 -r 3a22c76ff2a4 source/CMakeLists.txt
--- a/source/CMakeLists.txt	Sat Jul 11 12:31:21 2015 -0500
+++ b/source/CMakeLists.txt	Sat Jul 11 16:58:11 2015 -0500
@@ -511,7 +511,6 @@
     file(GLOB OutputFiles output/output.cpp output/reconplay.cpp output/*.h
                           output/yuv.cpp output/y4m.cpp # recon
                           output/raw.cpp)               # muxers
-    file(GLOB FilterFiles filters/*.cpp filters/*.h)
     source_group(input FILES ${InputFiles})
     source_group(output FILES ${OutputFiles})
     source_group(filters FILES ${FilterFiles})
@@ -530,11 +529,12 @@
 
     if(XCODE)
         # Xcode seems unable to link the CLI with libs, so link as one targget
-        add_executable(cli ../COPYING ${InputFiles} ${OutputFiles} ${FilterFiles} ${GETOPT} x265.cpp x265.h x265cli.h
-                           $<TARGET_OBJECTS:encoder> $<TARGET_OBJECTS:common> ${YASM_OBJS} ${YASM_SRCS})
+        add_executable(cli ../COPYING ${InputFiles} ${OutputFiles} ${FilterFiles} ${GETOPT}
+                       x265.cpp x265.h x265cli.h x265-extras.h x265-extras.cpp
+                       $<TARGET_OBJECTS:encoder> $<TARGET_OBJECTS:common> ${YASM_OBJS} ${YASM_SRCS})
     else()
         add_executable(cli ../COPYING ${InputFiles} ${OutputFiles} ${FilterFiles} ${GETOPT} ${X265_RC_FILE}
-                       ${ExportDefs} x265.cpp x265.h x265cli.h)
+                       ${ExportDefs} x265.cpp x265.h x265cli.h x265-extras.h x265-extras.cpp)
         if(WIN32 OR NOT ENABLE_SHARED OR INTEL_CXX)
             # The CLI cannot link to the shared library on Windows, it
             # requires internal APIs not exported from the DLL
diff -r 79f4906e9cb8 -r 3a22c76ff2a4 source/filters/filters.cpp
--- a/source/filters/filters.cpp	Sat Jul 11 12:31:21 2015 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*****************************************************************************
- * Copyright (C) 2013 x265 project
- *
- * Authors: Selvakumar Nithiyaruban <selvakumar at multicorewareinc.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
- *
- * This program is also available under a commercial proprietary license.
- * For more information, contact us at license @ x265.com.
- *****************************************************************************/
-
-#include "filters.h"
-#include "common.h"
-
-using namespace X265_NS;
-
-/* The dithering algorithm is based on Sierra-2-4A error diffusion. */
-void ditherPlane(pixel *dst, int dstStride, uint16_t *src, int srcStride,
-                 int width, int height, int16_t *errors, int bitDepth)
-{
-    const int lShift = 16 - bitDepth;
-    const int rShift = 16 - bitDepth + 2;
-    const int half = (1 << (16 - bitDepth + 1));
-    const int pixelMax = (1 << bitDepth) - 1;
-
-    memset(errors, 0, (width + 1) * sizeof(int16_t));
-    int pitch = 1;
-    for (int y = 0; y < height; y++, src += srcStride, dst += dstStride)
-    {
-        int16_t err = 0;
-        for (int x = 0; x < width; x++)
-        {
-            err = err * 2 + errors[x] + errors[x + 1];
-            dst[x * pitch] = (pixel)x265_clip3(0, pixelMax, ((src[x * 1] << 2) + err + half) >> rShift);
-            errors[x] = err = src[x * pitch] - (dst[x * pitch] << lShift);
-        }
-    }
-}
-
-void ditherImage(x265_picture& picIn, int picWidth, int picHeight, int16_t *errorBuf, int bitDepth)
-{
-    /* This portion of code is from readFrame in x264. */
-    for (int i = 0; i < x265_cli_csps[picIn.colorSpace].planes; i++)
-    {
-        if ((picIn.bitDepth & 7) && (picIn.bitDepth != 16))
-        {
-            /* upconvert non 16bit high depth planes to 16bit */
-            uint16_t *plane = (uint16_t*)picIn.planes[i];
-            uint32_t pixelCount = x265_picturePlaneSize(picIn.colorSpace, picWidth, picHeight, i);
-            int lShift = 16 - picIn.bitDepth;
-
-            /* This loop assumes width is equal to stride which
-               happens to be true for file reader outputs */
-            for (uint32_t j = 0; j < pixelCount; j++)
-            {
-                plane[j] = plane[j] << lShift;
-            }
-        }
-    }
-
-    for (int i = 0; i < x265_cli_csps[picIn.colorSpace].planes; i++)
-    {
-        int height = (int)(picHeight >> x265_cli_csps[picIn.colorSpace].height[i]);
-        int width = (int)(picWidth >> x265_cli_csps[picIn.colorSpace].width[i]);
-
-        ditherPlane(((pixel*)picIn.planes[i]), picIn.stride[i] / sizeof(pixel), ((uint16_t*)picIn.planes[i]),
-                    picIn.stride[i] / 2, width, height, errorBuf, bitDepth);
-    }
-}
diff -r 79f4906e9cb8 -r 3a22c76ff2a4 source/filters/filters.h
--- a/source/filters/filters.h	Sat Jul 11 12:31:21 2015 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-/*****************************************************************************
- * Copyright (C) 2013 x265 project
- *
- * Authors: Selvakumar Nithiyaruban <selvakumar at multicorewareinc.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
- *
- * This program is also available under a commercial proprietary license.
- * For more information, contact us at license @ x265.com.
- *****************************************************************************/
-
-#ifndef X265_FILTERS_H
-#define X265_FILTERS_H
-
-#include "x265.h"
-
-void ditherImage(x265_picture&, int picWidth, int picHeight, int16_t *errorBuf, int bitDepth);
-
-#endif //X265_FILTERS_H
diff -r 79f4906e9cb8 -r 3a22c76ff2a4 source/x265-extras.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/x265-extras.cpp	Sat Jul 11 16:58:11 2015 -0500
@@ -0,0 +1,253 @@
+/*****************************************************************************
+ * Copyright (C) 2015 x265 project
+ *
+ * Authors: Steve Borho <steve at borho.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
+ *
+ * This program is also available under a commercial proprietary license.
+ * For more information, contact us at license @ x265.com.
+ *****************************************************************************/
+
+#include "common.h"
+
+#include "x265.h"
+#include "x265-extras.h"
+
+using namespace X265_NS;
+
+static const char* summaryCSVHeader =
+    "Command, Date/Time, Elapsed Time, FPS, Bitrate, "
+    "Y PSNR, U PSNR, V PSNR, Global PSNR, SSIM, SSIM (dB), "
+    "I count, I ave-QP, I kbps, I-PSNR Y, I-PSNR U, I-PSNR V, I-SSIM (dB), "
+    "P count, P ave-QP, P kbps, P-PSNR Y, P-PSNR U, P-PSNR V, P-SSIM (dB), "
+    "B count, B ave-QP, B kbps, B-PSNR Y, B-PSNR U, B-PSNR V, B-SSIM (dB), "
+    "Version\n";
+
+FILE* x265_open_csv(const x265_param& param, const char* fname, int level)
+{
+    FILE *csvfp = fopen(fname, "r");
+    if (csvfp)
+    {
+        /* file already exists, re-open for append */
+        fclose(csvfp);
+        return fopen(fname, "ab");
+    }
+    else
+    {
+        /* new CSV file, write header */
+        csvfp = fopen(fname, "wb");
+        if (csvfp)
+        {
+            if (level)
+            {
+                fprintf(csvfp, "Encode Order, Type, POC, QP, Bits, ");
+                if (param.rc.rateControlMode == X265_RC_CRF)
+                    fprintf(csvfp, "RateFactor, ");
+                fprintf(csvfp, "Y PSNR, U PSNR, V PSNR, YUV PSNR, SSIM, SSIM (dB),  List 0, List 1");
+                /* detailed performance statistics */
+                fprintf(csvfp, ", DecideWait (ms), Row0Wait (ms), Wall time (ms), Ref Wait Wall (ms), Total CTU time (ms), Stall Time (ms), Avg WPP, Row Blocks\n");
+            }
+            else
+                fputs(summaryCSVHeader, csvfp);
+        }
+        return csvfp;
+    }
+}
+
+// per frame CSV logging
+void x265_csvlog_frame(FILE* csvfp, const x265_param& param, const x265_picture& pic)
+{
+    if (!csvfp)
+        return;
+
+    const x265_frame_stats* frameStats = &pic.frameData;
+    fprintf(csvfp, "%d, %c-SLICE, %4d, %2.2lf, %10d,", frameStats->encoderOrder, frameStats->sliceType, frameStats->poc, frameStats->qp, (int)frameStats->bits);
+    if (param.rc.rateControlMode == X265_RC_CRF)
+        fprintf(csvfp, "%.3lf,", frameStats->rateFactor);
+    if (param.bEnablePsnr)
+        fprintf(csvfp, "%.3lf, %.3lf, %.3lf, %.3lf,", frameStats->psnrY, frameStats->psnrU, frameStats->psnrV, frameStats->psnr);
+    else
+        fputs(" -, -, -, -,", csvfp);
+    if (param.bEnableSsim)
+        fprintf(csvfp, " %.6f, %6.3f,", frameStats->ssim, x265_ssim2dB(frameStats->ssim));
+    else
+        fputs(" -, -,", csvfp);
+    if (frameStats->sliceType == 'I')
+        fputs(" -, -,", csvfp);
+    else
+    {
+        int i = 0;
+        while (frameStats->list0POC[i] != -1)
+            fprintf(csvfp, "%d ", frameStats->list0POC[i++]);
+        fprintf(csvfp, ",");
+        if (frameStats->sliceType != 'P')
+        {
+            i = 0;
+            while (frameStats->list1POC[i] != -1)
+                fprintf(csvfp, "%d ", frameStats->list1POC[i++]);
+            fprintf(csvfp, ",");
+        }
+        else
+            fputs(" -,", csvfp);
+    }
+    fprintf(csvfp, " %.1lf, %.1lf, %.1lf, %.1lf, %.1lf, %.1lf,", frameStats->decideWaitTime, frameStats->row0WaitTime, frameStats->wallTime, frameStats->refWaitWallTime, frameStats->totalCTUTime, frameStats->stallTime);
+    fprintf(csvfp, " %.3lf, %d", frameStats->avgWPP, frameStats->countRowBlocks);
+    fprintf(csvfp, "\n");
+    fflush(stderr);
+}
+
+void x265_csvlog_encode(FILE* csvfp, const x265_api& api, const x265_param& param, const x265_stats& stats, int level, int argc, char** argv)
+{
+    if (!csvfp)
+        return;
+
+    if (level)
+    {
+        // adding summary to a per-frame csv log file, so it needs a summary header
+        fprintf(csvfp, "\nSummary\n");
+        fputs(summaryCSVHeader, csvfp);
+    }
+
+    // CLI arguments or other
+    for (int i = 1; i < argc; i++)
+    {
+        if (i) fputc(' ', csvfp);
+        fputs(argv[i], csvfp);
+    }
+
+    // current date and time
+    time_t now;
+    struct tm* timeinfo;
+    time(&now);
+    timeinfo = localtime(&now);
+    char buffer[200];
+    strftime(buffer, 128, "%c", timeinfo);
+    fprintf(csvfp, ", %s, ", buffer);
+
+    // elapsed time, fps, bitrate
+    fprintf(csvfp, "%.2f, %.2f, %.2f,",
+        stats.elapsedEncodeTime, stats.encodedPictureCount / stats.elapsedEncodeTime, stats.bitrate);
+
+    if (param.bEnablePsnr)
+        fprintf(csvfp, " %.3lf, %.3lf, %.3lf, %.3lf,",
+        stats.globalPsnrY / stats.encodedPictureCount, stats.globalPsnrU / stats.encodedPictureCount,
+        stats.globalPsnrV / stats.encodedPictureCount, stats.globalPsnr);
+    else
+        fprintf(csvfp, " -, -, -, -,");
+    if (param.bEnableSsim)
+        fprintf(csvfp, " %.6f, %6.3f,", stats.globalSsim, x265_ssim2dB(stats.globalSsim));
+    else
+        fprintf(csvfp, " -, -,");
+
+    if (stats.statsI.numPics)
+    {
+        fprintf(csvfp, " %-6u, %2.2lf, %-8.2lf,", stats.statsI.numPics, stats.statsI.avgQp, stats.statsI.bitrate);
+        if (param.bEnablePsnr)
+            fprintf(csvfp, " %.3lf, %.3lf, %.3lf,", stats.statsI.psnrY, stats.statsI.psnrU, stats.statsI.psnrV);
+        else
+            fprintf(csvfp, " -, -, -,");
+        if (param.bEnableSsim)
+            fprintf(csvfp, " %.3lf,", stats.statsI.ssim);
+        else
+            fprintf(csvfp, " -,");
+    }
+    else
+        fprintf(csvfp, " -, -, -, -, -, -, -,");
+
+    if (stats.statsP.numPics)
+    {
+        fprintf(csvfp, " %-6u, %2.2lf, %-8.2lf,", stats.statsP.numPics, stats.statsP.avgQp, stats.statsP.bitrate);
+        if (param.bEnablePsnr)
+            fprintf(csvfp, " %.3lf, %.3lf, %.3lf,", stats.statsP.psnrY, stats.statsP.psnrU, stats.statsP.psnrV);
+        else
+            fprintf(csvfp, " -, -, -,");
+        if (param.bEnableSsim)
+            fprintf(csvfp, " %.3lf,", stats.statsP.ssim);
+        else
+            fprintf(csvfp, " -,");
+    }
+    else
+        fprintf(csvfp, " -, -, -, -, -, -, -,");
+
+    if (stats.statsB.numPics)
+    {
+        fprintf(csvfp, " %-6u, %2.2lf, %-8.2lf,", stats.statsB.numPics, stats.statsB.avgQp, stats.statsB.bitrate);
+        if (param.bEnablePsnr)
+            fprintf(csvfp, " %.3lf, %.3lf, %.3lf,", stats.statsB.psnrY, stats.statsB.psnrU, stats.statsB.psnrV);
+        else
+            fprintf(csvfp, " -, -, -,");
+        if (param.bEnableSsim)
+            fprintf(csvfp, " %.3lf,", stats.statsB.ssim);
+        else
+            fprintf(csvfp, " -,");
+    }
+    else
+        fprintf(csvfp, " -, -, -, -, -, -, -,");
+
+    fprintf(csvfp, " %s\n", api.version_str);
+}
+
+/* The dithering algorithm is based on Sierra-2-4A error diffusion. */
+static void ditherPlane(pixel *dst, int dstStride, uint16_t *src, int srcStride,
+                        int width, int height, int16_t *errors, int bitDepth)
+{
+    const int lShift = 16 - bitDepth;
+    const int rShift = 16 - bitDepth + 2;
+    const int half = (1 << (16 - bitDepth + 1));
+    const int pixelMax = (1 << bitDepth) - 1;
+
+    memset(errors, 0, (width + 1) * sizeof(int16_t));
+    int pitch = 1;
+    for (int y = 0; y < height; y++, src += srcStride, dst += dstStride)
+    {
+        int16_t err = 0;
+        for (int x = 0; x < width; x++)
+        {
+            err = err * 2 + errors[x] + errors[x + 1];
+            dst[x * pitch] = (pixel)x265_clip3(0, pixelMax, ((src[x * 1] << 2) + err + half) >> rShift);
+            errors[x] = err = src[x * pitch] - (dst[x * pitch] << lShift);
+        }
+    }
+}
+
+void x265_dither_image(x265_picture& picIn, int picWidth, int picHeight, int16_t *errorBuf, int bitDepth)
+{
+    /* This portion of code is from readFrame in x264. */
+    for (int i = 0; i < x265_cli_csps[picIn.colorSpace].planes; i++)
+    {
+        if ((picIn.bitDepth & 7) && (picIn.bitDepth != 16))
+        {
+            /* upconvert non 16bit high depth planes to 16bit */
+            uint16_t *plane = (uint16_t*)picIn.planes[i];
+            uint32_t pixelCount = x265_picturePlaneSize(picIn.colorSpace, picWidth, picHeight, i);
+            int lShift = 16 - picIn.bitDepth;
+
+            /* This loop assumes width is equal to stride which
+             * happens to be true for file reader outputs */
+            for (uint32_t j = 0; j < pixelCount; j++)
+                plane[j] = plane[j] << lShift;
+        }
+    }
+
+    for (int i = 0; i < x265_cli_csps[picIn.colorSpace].planes; i++)
+    {
+        int height = (int)(picHeight >> x265_cli_csps[picIn.colorSpace].height[i]);
+        int width = (int)(picWidth >> x265_cli_csps[picIn.colorSpace].width[i]);
+
+        ditherPlane(((pixel*)picIn.planes[i]), picIn.stride[i] / sizeof(pixel), ((uint16_t*)picIn.planes[i]),
+                    picIn.stride[i] / 2, width, height, errorBuf, bitDepth);
+    }
+}
diff -r 79f4906e9cb8 -r 3a22c76ff2a4 source/x265-extras.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/x265-extras.h	Sat Jul 11 16:58:11 2015 -0500
@@ -0,0 +1,49 @@
+/*****************************************************************************
+ * Copyright (C) 2015 x265 project
+ *
+ * Authors: Steve Borho <steve at borho.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
+ *
+ * This program is also available under a commercial proprietary license.
+ * For more information, contact us at license @ x265.com.
+ *****************************************************************************/
+
+#ifndef X265_EXTRAS_H
+#define X265_EXTRAS_H 1
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if _WIN32
+#define LIBAPI __declspec(dllexport)
+#else
+#define LIBAPI
+#endif
+
+LIBAPI FILE* x265_open_csv(const x265_param& param, const char* fname, int level);
+LIBAPI void x265_csvlog_frame(FILE* csvfp, const x265_param& param, const x265_picture& pic);
+LIBAPI void x265_csvlog_encode(FILE* csvfp, const x265_api& api, const x265_param& param, const x265_stats& stats, int level, int argc, char** argv);
+
+LIBAPI void x265_dither_image(x265_picture&, int picWidth, int picHeight, int16_t *errorBuf, int bitDepth);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff -r 79f4906e9cb8 -r 3a22c76ff2a4 source/x265.cpp
--- a/source/x265.cpp	Sat Jul 11 12:31:21 2015 -0500
+++ b/source/x265.cpp	Sat Jul 11 16:58:11 2015 -0500
@@ -25,15 +25,17 @@
 #pragma warning(disable: 4127) // conditional expression is constant, yes I know
 #endif
 
+#include "x265.h"
+#include "x265-extras.h"
+#include "x265cli.h"
+
+#include "common.h"
 #include "input/input.h"
 #include "output/output.h"
 #include "output/reconplay.h"
-#include "filters/filters.h"
-#include "common.h"
+
 #include "param.h"
 #include "cpu.h"
-#include "x265.h"
-#include "x265cli.h"
 
 #if HAVE_VLD
 /* Visual Leak Detector */
@@ -68,14 +70,6 @@
     b_ctrl_c = 1;
 }
 
-static const char* summaryCSVHeader =
-    "Command, Date/Time, Elapsed Time, FPS, Bitrate, "
-    "Y PSNR, U PSNR, V PSNR, Global PSNR, SSIM, SSIM (dB), "
-    "I count, I ave-QP, I kbps, I-PSNR Y, I-PSNR U, I-PSNR V, I-SSIM (dB), "
-    "P count, P ave-QP, P kbps, P-PSNR Y, P-PSNR U, P-PSNR V, P-SSIM (dB), "
-    "B count, B ave-QP, B kbps, B-PSNR Y, B-PSNR U, B-PSNR V, B-SSIM (dB), "
-    "Version\n";
-
 struct CLIOptions
 {
     InputFile* input;
@@ -122,9 +116,6 @@
     }
 
     void destroy();
-    bool parseCSVFile();
-    void writeLog(int argc, char **argv, x265_stats* stats);
-    void writeFrameLog(x265_frame_stats* frameStats);
     void printStatus(uint32_t frameNum);
     bool parse(int argc, char **argv);
     bool parseQPFile(x265_picture &pic_org);
@@ -149,174 +140,6 @@
     output = NULL;
 }
 
-bool CLIOptions::parseCSVFile()
-{
-    csvfpt = fopen(csvfn, "r");
-    if (csvfpt)
-    {
-        /* file already exists, re-open for append */
-        fclose(csvfpt);
-        csvfpt = fopen(csvfn, "ab");
-    }
-    else
-    {
-        /* new CSV file, write header */
-        csvfpt = fopen(csvfn, "wb");
-        if (csvfpt)
-        {
-            if (csvLogLevel)
-            {
-                fprintf(csvfpt, "Encode Order, Type, POC, QP, Bits, ");
-                if (param->rc.rateControlMode == X265_RC_CRF)
-                    fprintf(csvfpt, "RateFactor, ");
-                fprintf(csvfpt, "Y PSNR, U PSNR, V PSNR, YUV PSNR, SSIM, SSIM (dB),  List 0, List 1");
-                /* detailed performance statistics */
-                fprintf(csvfpt, ", DecideWait (ms), Row0Wait (ms), Wall time (ms), Ref Wait Wall (ms), Total CTU time (ms), Stall Time (ms), Avg WPP, Row Blocks\n");
-            }
-            else
-                fputs(summaryCSVHeader, csvfpt);
-        }
-    }
-
-    if (!csvfpt)
-    {
-        x265_log(param, X265_LOG_ERROR, "Unable to open CSV log file <%s>, aborting\n", csvfn);
-        return true;
-    }
-    return false;
-}
-
-void CLIOptions::writeLog(int argc, char **argv, x265_stats* stats)
-{
-    if (csvfpt)
-    {
-        if (csvLogLevel)
-        {
-            // adding summary to a per-frame csv log file needs a summary header
-            fprintf(csvfpt, "\nSummary\n");
-            fputs(summaryCSVHeader, csvfpt);
-        }
-        // CLI arguments or other
-        for (int i = 1; i < argc; i++)
-        {
-            if (i) fputc(' ', csvfpt);
-            fputs(argv[i], csvfpt);
-        }
-
-        // current date and time
-        time_t now;
-        struct tm* timeinfo;
-        time(&now);
-        timeinfo = localtime(&now);
-        char buffer[200];
-        strftime(buffer, 128, "%c", timeinfo);
-        fprintf(csvfpt, ", %s, ", buffer);
-
-        // elapsed time, fps, bitrate
-        fprintf(csvfpt, "%.2f, %.2f, %.2f,",
-            stats->elapsedEncodeTime, stats->encodedPictureCount / stats->elapsedEncodeTime, stats->bitrate);
-
-        if (param->bEnablePsnr)
-            fprintf(csvfpt, " %.3lf, %.3lf, %.3lf, %.3lf,",
-            stats->globalPsnrY / stats->encodedPictureCount, stats->globalPsnrU / stats->encodedPictureCount,
-            stats->globalPsnrV / stats->encodedPictureCount, stats->globalPsnr);
-        else
-            fprintf(csvfpt, " -, -, -, -,");
-        if (param->bEnableSsim)
-            fprintf(csvfpt, " %.6f, %6.3f,", stats->globalSsim, x265_ssim2dB(stats->globalSsim));
-        else
-            fprintf(csvfpt, " -, -,");
-
-        if (stats->statsI.numPics)
-        {
-            fprintf(csvfpt, " %-6u, %2.2lf, %-8.2lf,", stats->statsI.numPics, stats->statsI.avgQp, stats->statsI.bitrate);
-            if (param->bEnablePsnr)
-                fprintf(csvfpt, " %.3lf, %.3lf, %.3lf,", stats->statsI.psnrY, stats->statsI.psnrU, stats->statsI.psnrV);
-            else
-                fprintf(csvfpt, " -, -, -,");
-            if (param->bEnableSsim)
-                fprintf(csvfpt, " %.3lf,", stats->statsI.ssim);
-            else
-                fprintf(csvfpt, " -,");
-        }
-        else
-            fprintf(csvfpt, " -, -, -, -, -, -, -,");
-
-        if (stats->statsP.numPics)
-        {
-            fprintf(csvfpt, " %-6u, %2.2lf, %-8.2lf,", stats->statsP.numPics, stats->statsP.avgQp, stats->statsP.bitrate);
-            if (param->bEnablePsnr)
-                fprintf(csvfpt, " %.3lf, %.3lf, %.3lf,", stats->statsP.psnrY, stats->statsP.psnrU, stats->statsP.psnrV);
-            else
-                fprintf(csvfpt, " -, -, -,");
-            if (param->bEnableSsim)
-                fprintf(csvfpt, " %.3lf,", stats->statsP.ssim);
-            else
-                fprintf(csvfpt, " -,");
-        }
-        else
-            fprintf(csvfpt, " -, -, -, -, -, -, -,");
-
-        if (stats->statsB.numPics)
-        {
-            fprintf(csvfpt, " %-6u, %2.2lf, %-8.2lf,", stats->statsB.numPics, stats->statsB.avgQp, stats->statsB.bitrate);
-            if (param->bEnablePsnr)
-                fprintf(csvfpt, " %.3lf, %.3lf, %.3lf,", stats->statsB.psnrY, stats->statsB.psnrU, stats->statsB.psnrV);
-            else
-                fprintf(csvfpt, " -, -, -,");
-            if (param->bEnableSsim)
-                fprintf(csvfpt, " %.3lf,", stats->statsB.ssim);
-            else
-                fprintf(csvfpt, " -,");
-        }
-        else
-            fprintf(csvfpt, " -, -, -, -, -, -, -,");
-
-        fprintf(csvfpt, " %s\n", api->version_str);
-    }
-}
-
-void CLIOptions::writeFrameLog(x265_frame_stats* frameStats)
-{
-    if (csvfpt)
-    {
-        // per frame CSV logging if the file handle is valid
-        fprintf(csvfpt, "%d, %c-SLICE, %4d, %2.2lf, %10d,", frameStats->encoderOrder, frameStats->sliceType, frameStats->poc, frameStats->qp, (int)frameStats->bits);
-        if (param->rc.rateControlMode == X265_RC_CRF)
-            fprintf(csvfpt, "%.3lf,", frameStats->rateFactor);
-        if (param->bEnablePsnr)
-            fprintf(csvfpt, "%.3lf, %.3lf, %.3lf, %.3lf,", frameStats->psnrY, frameStats->psnrU, frameStats->psnrV, frameStats->psnr);
-        else
-            fputs(" -, -, -, -,", csvfpt);
-        if (param->bEnableSsim)
-            fprintf(csvfpt, " %.6f, %6.3f,", frameStats->ssim, x265_ssim2dB(frameStats->ssim));
-        else
-            fputs(" -, -,", csvfpt);
-        if (frameStats->sliceType == 'I')
-            fputs(" -, -,", csvfpt);
-        else
-        {
-            int i = 0;
-            while (frameStats->list0POC[i] != -1)
-                fprintf(csvfpt, "%d ", frameStats->list0POC[i++]);
-            fprintf(csvfpt, ",");
-            if (frameStats->sliceType != 'P')
-            {
-                i = 0;
-                while (frameStats->list1POC[i] != -1)
-                    fprintf(csvfpt, "%d ", frameStats->list1POC[i++]);
-                fprintf(csvfpt, ",");
-            }
-            else
-                fputs(" -,", csvfpt);
-        }
-        fprintf(csvfpt, " %.1lf, %.1lf, %.1lf, %.1lf, %.1lf, %.1lf,", frameStats->decideWaitTime, frameStats->row0WaitTime, frameStats->wallTime, frameStats->refWaitWallTime, frameStats->totalCTUTime, frameStats->stallTime);
-        fprintf(csvfpt, " %.3lf, %d", frameStats->avgWPP, frameStats->countRowBlocks);
-        fprintf(csvfpt, "\n");
-        fflush(stderr);
-    }
-}
-
 void CLIOptions::printStatus(uint32_t frameNum)
 {
     char buf[200];
@@ -703,8 +526,10 @@
 
     if (cliopt.csvfn)
     {
-        if (cliopt.parseCSVFile())
+        cliopt.csvfpt = x265_open_csv(*param, cliopt.csvfn, cliopt.csvLogLevel);
+        if (!cliopt.csvfpt)
         {
+            x265_log(param, X265_LOG_ERROR, "Unable to open CSV log file <%s>, aborting\n", cliopt.csvfn);
             cliopt.destroy();
             if (cliopt.api)
                 cliopt.api->param_free(cliopt.param);
@@ -794,7 +619,7 @@
         {
             if (pic_in->bitDepth > param->internalBitDepth && cliopt.bDither)
             {
-                ditherImage(*pic_in, param->sourceWidth, param->sourceHeight, errorBuf, param->internalBitDepth);
+                x265_dither_image(*pic_in, param->sourceWidth, param->sourceHeight, errorBuf, param->internalBitDepth);
                 pic_in->bitDepth = param->internalBitDepth;
             }
             /* Overwrite PTS */
@@ -829,7 +654,7 @@
 
         cliopt.printStatus(outFrameCount);
         if (numEncoded && cliopt.csvLogLevel)
-            cliopt.writeFrameLog(&(pic_recon->frameData));
+            x265_csvlog_frame(cliopt.csvfpt, *param, *pic_recon);
     }
 
     /* Flush the encoder */
@@ -861,7 +686,7 @@
 
         cliopt.printStatus(outFrameCount);
         if (numEncoded && cliopt.csvLogLevel)
-            cliopt.writeFrameLog(&(pic_recon->frameData));
+            x265_csvlog_frame(cliopt.csvfpt, *param, *pic_recon);
 
         if (!numEncoded)
             break;
@@ -876,8 +701,8 @@
     delete reconPlay;
 
     api->encoder_get_stats(encoder, &stats, sizeof(stats));
-    if (cliopt.csvfn && !b_ctrl_c)
-        cliopt.writeLog(argc, argv, &stats);
+    if (cliopt.csvfpt && !b_ctrl_c)
+        x265_csvlog_encode(cliopt.csvfpt, *api, *param, stats, cliopt.csvLogLevel, argc, argv);
     api->encoder_close(encoder);
 
     int64_t second_largest_pts = 0;
diff -r 79f4906e9cb8 -r 3a22c76ff2a4 source/x265cli.h
--- a/source/x265cli.h	Sat Jul 11 12:31:21 2015 -0500
+++ b/source/x265cli.h	Sat Jul 11 16:58:11 2015 -0500
@@ -24,6 +24,9 @@
 #ifndef X265CLI_H
 #define X265CLI_H 1
 
+#include "common.h"
+#include "param.h"
+
 #include <getopt.h>
 
 #ifdef __cplusplus


More information about the x265-devel mailing list