[x265] [PATCH 1 of 3] api: large reorg of logging and statistics

Steve Borho steve at borho.org
Thu Oct 24 00:05:11 CEST 2013


# HG changeset patch
# User Steve Borho <steve at borho.org>
# Date 1382562719 18000
#      Wed Oct 23 16:11:59 2013 -0500
# Node ID 6fefac92031188ddc2c620956576b31981ecf515
# Parent  c769d32fe9a18344ce943f18a80297fe155215d5
api: large reorg of logging and statistics

* move all CSV logging into the encoder so API users can take advantage of it
* remove hacky global PSNR return value from x265_encoder_close
* add time and bitrate values to x265_stats_t
* remove some dead HM code
* use x265_log in the CLI

diff -r c769d32fe9a1 -r 6fefac920311 source/CMakeLists.txt
--- a/source/CMakeLists.txt	Wed Oct 23 16:03:17 2013 +0530
+++ b/source/CMakeLists.txt	Wed Oct 23 16:11:59 2013 -0500
@@ -10,7 +10,7 @@
 cmake_minimum_required (VERSION 2.8.8) # OBJECT libraries require 2.8.8
 
 # X265_BUILD must be incremented each time the public API is changed
-set(X265_BUILD 1)
+set(X265_BUILD 2)
 configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
                "${PROJECT_BINARY_DIR}/x265.def")
 configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
diff -r c769d32fe9a1 -r 6fefac920311 source/Lib/TLibCommon/CommonDef.h
--- a/source/Lib/TLibCommon/CommonDef.h	Wed Oct 23 16:03:17 2013 +0530
+++ b/source/Lib/TLibCommon/CommonDef.h	Wed Oct 23 16:11:59 2013 -0500
@@ -126,9 +126,6 @@
 
 #define CABAC_INIT_PRESENT_FLAG     1
 
-#define _SUMMARY_OUT_               0           ///< print-out PSNR results of all slices to summary.txt
-#define _SUMMARY_PIC_               0           ///< print-out PSNR results for each slice type to summary.txt
-
 #define MAX_GOP                     64          ///< max. value of hierarchical GOP size
 
 #define MAX_NUM_REF_PICS            16          ///< max. number of pictures used for reference
diff -r c769d32fe9a1 -r 6fefac920311 source/common/common.cpp
--- a/source/common/common.cpp	Wed Oct 23 16:03:17 2013 +0530
+++ b/source/common/common.cpp	Wed Oct 23 16:11:59 2013 -0500
@@ -477,6 +477,8 @@
     if (0) ;
     OPT("fps")
         p->frameRate = atoi(value);
+    OPT("csv")
+        p->csvfn = value;
     OPT("threads")
         p->poolNumThreads = atoi(value);
     OPT("frame-threads")
diff -r c769d32fe9a1 -r 6fefac920311 source/dllmain.cpp
--- a/source/dllmain.cpp	Wed Oct 23 16:03:17 2013 +0530
+++ b/source/dllmain.cpp	Wed Oct 23 16:11:59 2013 -0500
@@ -31,5 +31,5 @@
 
     x265_param_default(&param);
     x265_t *enc = x265_encoder_open(&param);
-    x265_encoder_close(enc, 0);
+    x265_encoder_close(enc);
 }
diff -r c769d32fe9a1 -r 6fefac920311 source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp	Wed Oct 23 16:03:17 2013 +0530
+++ b/source/encoder/encoder.cpp	Wed Oct 23 16:11:59 2013 -0500
@@ -44,6 +44,7 @@
 #include <math.h> // log10
 #include <stdio.h>
 #include <string.h>
+#include <time.h>
 
 using namespace x265;
 
@@ -96,7 +97,9 @@
     m_lookahead = new Lookahead(this, m_threadPool);
     m_dpb = new DPB(this);
     m_rateControl = new RateControl(this);
-    if (param.csvfn && param.logLevel >= X265_LOG_DEBUG)
+
+    /* Try to open CSV file handle */
+    if (param.csvfn)
     {
         m_csvfpt = fopen(param.csvfn, "r");
         if (m_csvfpt)
@@ -111,7 +114,10 @@
             m_csvfpt = fopen(param.csvfn, "wb");
             if (m_csvfpt)
             {
-                fprintf(m_csvfpt, "Encode Order, Type, POC, nQP, QP, Bits, PSNR Y, PSNR U, PSNR V, PSNR, SSIM, Encoding time, Elapsed time, List 0, List 1\n");
+                if (param.logLevel >= X265_LOG_DEBUG)
+                    fprintf(m_csvfpt, "Encode Order, Type, POC, nQP, QP, Bits, PSNR Y, PSNR U, PSNR V, PSNR, SSIM, Encoding time, Elapsed time, List 0, List 1\n");
+                else
+                    fprintf(m_csvfpt, "CLI arguments, date/time, elapsed time, fps, bitrate, global PSNR Y, global PSNR U, global PSNR V, global PSNR, global SSIM, version\n");
             }
         }
     }
@@ -168,6 +174,7 @@
         }
     }
     m_lookahead->init();
+    m_encodeStartTime = x265_mdate();
 }
 
 int Encoder::getStreamHeaders(NALUnitEBSP **nalunits)
@@ -305,7 +312,7 @@
     return ret;
 }
 
-double Encoder::printSummary()
+void Encoder::printSummary()
 {
     double fps = (double)param.frameRate;
 
@@ -316,20 +323,6 @@
         m_analyzeB.printOut('b', fps);
         m_analyzeAll.printOut('a', fps);
     }
-
-#if _SUMMARY_OUT_
-    m_analyzeAll.printSummaryOut(fps);
-#endif
-#if _SUMMARY_PIC_
-    m_analyzeI.printSummary('I', fps);
-    m_analyzeP.printSummary('P', fps);
-    m_analyzeB.printSummary('B', fps);
-#endif
-
-    if (m_analyzeAll.getNumPic())
-        return (m_analyzeAll.getPsnrY() * 6 + m_analyzeAll.getPsnrU() + m_analyzeAll.getPsnrV()) / (8 * m_analyzeAll.getNumPic());
-    else
-        return 100.0;
 }
 
 void Encoder::fetchStats(x265_stats_t *stats)
@@ -337,18 +330,64 @@
     stats->globalPsnrY = m_analyzeAll.getPsnrY();
     stats->globalPsnrU = m_analyzeAll.getPsnrU();
     stats->globalPsnrV = m_analyzeAll.getPsnrV();
-    stats->totalNumPics = m_analyzeAll.getNumPic();
+    stats->encodedPictureCount = m_analyzeAll.getNumPic();
     stats->accBits = m_analyzeAll.getBits();
-    if (stats->totalNumPics > 0)
+    if (stats->encodedPictureCount > 0)
     {
-        stats->globalSsim = m_globalSsim / stats->totalNumPics;
-        stats->globalPsnr = (stats->globalPsnrY * 6 + stats->globalPsnrU + stats->globalPsnrV) / (8 * stats->totalNumPics);
+        stats->globalSsim = m_globalSsim / stats->encodedPictureCount;
+        stats->globalPsnr = (stats->globalPsnrY * 6 + stats->globalPsnrU + stats->globalPsnrV) / (8 * stats->encodedPictureCount);
     }
     else
     {
         stats->globalSsim = 0;
         stats->globalPsnr = 0;
     }
+    stats->elapsedEncodeTime = (double)(x265_mdate() - m_encodeStartTime) / 1000000;
+    stats->elapsedVideoTime = stats->encodedPictureCount / param.frameRate;
+    stats->bitrate = (0.008f * stats->accBits) / stats->elapsedVideoTime;
+}
+
+void Encoder::writeLog(int argc, char **argv)
+{
+    if (param.logLevel < X265_LOG_DEBUG && m_csvfpt)
+    {
+        // CLI arguments or other
+        fprintf(m_csvfpt, "\n");
+        for (int i = 1; i < argc; i++)
+        {
+            if (i) fputc(' ', m_csvfpt);
+            fputs(argv[i], m_csvfpt);
+        }
+
+        // current date and time
+        time_t now;
+        struct tm* timeinfo;
+        time(&now);
+        timeinfo = localtime(&now);
+        char buffer[128];
+        strftime(buffer, 128, "%c", timeinfo);
+        fprintf(m_csvfpt, ", %s, ", buffer);
+
+        x265_stats_t stats;
+        fetchStats(&stats);
+
+        // elapsed time, fps, bitrate
+        fprintf(m_csvfpt, "%.2f, %.2f, %.2f,",
+            stats.elapsedEncodeTime, stats.encodedPictureCount / stats.elapsedEncodeTime, stats.bitrate);
+
+        if (param.bEnablePsnr)
+            fprintf(m_csvfpt, " %.3lf, %.3lf, %.3lf, %.3lf,",
+            stats.globalPsnrY/stats.encodedPictureCount, stats.globalPsnrU/stats.encodedPictureCount,
+            stats.globalPsnrV/stats.encodedPictureCount, stats.globalPsnr);
+        else
+            fprintf(m_csvfpt, " -, -, -, -,");
+        if (param.bEnableSsim)
+            fprintf(m_csvfpt, " %.2f,", stats.globalSsim);
+        else
+            fprintf(m_csvfpt, " -,");
+
+        fprintf(m_csvfpt, " %s\n", x265_version_str);
+    }
 }
 
 #define VERBOSE_RATE 0
@@ -1272,16 +1311,20 @@
 }
 
 extern "C"
-void x265_encoder_close(x265_t *enc, double *outPsnr)
+void x265_encoder_log(x265_t* enc, int argc, char **argv)
 {
     Encoder *encoder = static_cast<Encoder*>(enc);
-    double globalPsnr = encoder->printSummary();
 
-    if (outPsnr)
-        *outPsnr = globalPsnr;
+    encoder->writeLog(argc, argv);
+}
 
+extern "C"
+void x265_encoder_close(x265_t *enc)
+{
+    Encoder *encoder = static_cast<Encoder*>(enc);
     REPORT_CYCLE_COUNTER(ME);
 
+    encoder->printSummary();
     encoder->destroy();
     delete encoder;
 }
diff -r c769d32fe9a1 -r 6fefac920311 source/encoder/encoder.h
--- a/source/encoder/encoder.h	Wed Oct 23 16:03:17 2013 +0530
+++ b/source/encoder/encoder.h	Wed Oct 23 16:11:59 2013 -0500
@@ -67,13 +67,15 @@
     TEncAnalyze        m_analyzeB;
     double             m_globalSsim;
     FILE*              m_csvfpt;
+    int64_t            m_encodeStartTime;
+
     // quality control
     TComScalingList    m_scalingList;      ///< quantization matrix information
 
 public:
 
-    x265_nal_t *m_nals;
-    char *m_packetData;
+    x265_nal_t* m_nals;
+    char*       m_packetData;
 
     Encoder();
 
@@ -92,7 +94,9 @@
 
     void fetchStats(x265_stats_t* stats);
 
-    double printSummary();
+    void writeLog(int argc, char **argv);
+
+    void printSummary();
 
     TComScalingList* getScalingList() { return &m_scalingList; }
 
diff -r c769d32fe9a1 -r 6fefac920311 source/x265.cpp
--- a/source/x265.cpp	Wed Oct 23 16:03:17 2013 +0530
+++ b/source/x265.cpp	Wed Oct 23 16:11:59 2013 -0500
@@ -154,16 +154,12 @@
     Input*  input;
     Output* recon;
     std::fstream bitstreamFile;
-    FILE *csvfp;
     int bProgress;
-    int cli_log_level;
+    int totalbytes;
 
     uint32_t frameSkip;         // number of frames to skip from the beginning
     uint32_t framesToBeEncoded; // number of frames to encode
 
-    uint32_t essentialBytes;    // total essential NAL bytes written to bitstream
-    uint32_t totalBytes;        // total bytes written to bitstream
-
     int64_t startTime;
     int64_t prevUpdateTime;
 
@@ -174,23 +170,17 @@
     {
         input = NULL;
         recon = NULL;
-        csvfp = NULL;
-        framesToBeEncoded = frameSkip = 0;
-        essentialBytes = 0;
-        totalBytes = 0;
+        framesToBeEncoded = frameSkip = totalbytes = 0;
         bProgress = true;
         startTime = x265_mdate();
         prevUpdateTime = 0;
-        cli_log_level = X265_LOG_INFO;
     }
 
     void destroy();
-    void rateStatsAccum(NalUnitType nalUnitType, uint32_t annexBsize);
     void writeNALs(const x265_nal_t* nal, int nalcount);
     void printStatus(int frameNum, x265_param_t *param);
-    void log(int level, const char *fmt, ...);
-    void print_version(x265_param_t *param);
-    void do_help(x265_param_t *param);
+    void printVersion(x265_param_t *param);
+    void showHelp(x265_param_t *param);
     bool parse(int argc, char **argv, x265_param_t* param);
 };
 
@@ -202,41 +192,6 @@
     if (recon)
         recon->release();
     recon = NULL;
-    if (csvfp)
-        fclose(csvfp);
-    csvfp = NULL;
-}
-
-void CLIOptions::rateStatsAccum(NalUnitType nalUnitType, uint32_t annexBsize)
-{
-    switch (nalUnitType)
-    {
-    case NAL_UNIT_CODED_SLICE_TRAIL_R:
-    case NAL_UNIT_CODED_SLICE_TRAIL_N:
-    case NAL_UNIT_CODED_SLICE_TLA_R:
-    case NAL_UNIT_CODED_SLICE_TSA_N:
-    case NAL_UNIT_CODED_SLICE_STSA_R:
-    case NAL_UNIT_CODED_SLICE_STSA_N:
-    case NAL_UNIT_CODED_SLICE_BLA_W_LP:
-    case NAL_UNIT_CODED_SLICE_BLA_W_RADL:
-    case NAL_UNIT_CODED_SLICE_BLA_N_LP:
-    case NAL_UNIT_CODED_SLICE_IDR_W_RADL:
-    case NAL_UNIT_CODED_SLICE_IDR_N_LP:
-    case NAL_UNIT_CODED_SLICE_CRA:
-    case NAL_UNIT_CODED_SLICE_RADL_N:
-    case NAL_UNIT_CODED_SLICE_RADL_R:
-    case NAL_UNIT_CODED_SLICE_RASL_N:
-    case NAL_UNIT_CODED_SLICE_RASL_R:
-    case NAL_UNIT_VPS:
-    case NAL_UNIT_SPS:
-    case NAL_UNIT_PPS:
-        essentialBytes += annexBsize;
-        break;
-    default:
-        break;
-    }
-
-    totalBytes += annexBsize;
 }
 
 void CLIOptions::writeNALs(const x265_nal_t* nal, int nalcount)
@@ -245,7 +200,7 @@
     for (int i = 0; i < nalcount; i++)
     {
         bitstreamFile.write((const char*)nal->p_payload, nal->i_payload);
-        rateStatsAccum((NalUnitType)nal->i_type, nal->i_payload);
+        totalbytes += nal->i_payload;
         nal++;
     }
 }
@@ -261,7 +216,7 @@
     double fps = i_elapsed > 0 ? i_frame * 1000000. / i_elapsed : 0;
     if (framesToBeEncoded && i_frame)
     {
-        float bitrate = 0.008f * totalBytes / ((float)i_frame / param->frameRate);
+        float bitrate = 0.008f * totalbytes / ((float)i_frame / param->frameRate);
         int eta = (int)(i_elapsed * (framesToBeEncoded - i_frame) / ((int64_t)i_frame * 1000000));
         sprintf(buf, "x265 [%.1f%%] %d/%d frames, %.2f fps, %.2f kb/s, eta %d:%02d:%02d",
                 100. * i_frame / framesToBeEncoded, i_frame, framesToBeEncoded, fps, bitrate,
@@ -269,7 +224,7 @@
     }
     else
     {
-        double bitrate = (double)totalBytes * 8 / ((double)1000 * param->frameRate);
+        double bitrate = (double)totalbytes * 8 / ((double)1000 * param->frameRate);
         sprintf(buf, "x265 %d frames: %.2f fps, %.2f kb/s", i_frame, fps, bitrate);
     }
     fprintf(stderr, "%s  \r", buf + 5);
@@ -278,48 +233,17 @@
     prevUpdateTime = i_time;
 }
 
-void CLIOptions::log(int level, const char *fmt, ...)
-{
-    if (level > cli_log_level)
-        return;
-    const char *levelstr;
-    switch (level)
-    {
-    case X265_LOG_ERROR:
-        levelstr = "error";
-        break;
-    case X265_LOG_WARNING:
-        levelstr = "warning";
-        break;
-    case X265_LOG_INFO:
-        levelstr = "info";
-        break;
-    case X265_LOG_DEBUG:
-        levelstr = "debug";
-        break;
-    default:
-        levelstr = "unknown";
-        break;
-    }
-
-    fprintf(stderr, "x265 [%s]: ", levelstr);
-    va_list arg;
-    va_start(arg, fmt);
-    vfprintf(stderr, fmt, arg);
-    va_end(arg);
-}
-
-void CLIOptions::print_version(x265_param_t *param)
+void CLIOptions::printVersion(x265_param_t *param)
 {
     fprintf(stderr, "x265 [info]: HEVC encoder version %s\n", x265_version_str);
     fprintf(stderr, "x265 [info]: build info %s\n", x265_build_info_str);
     x265_setup_primitives(param, 0);
 }
 
-void CLIOptions::do_help(x265_param_t *param)
+void CLIOptions::showHelp(x265_param_t *param)
 {
     x265_param_default(param);
-    print_version(param);
+    printVersion(param);
     int inputBitDepth = 8, outputBitDepth = param->internalBitDepth;
 #define H0 printf
 #define OPT(value) (value ? "enabled" : "disabled")
@@ -333,7 +257,7 @@
     H0("   --threads                     Number of threads for thread pool (0: detect CPU core count, default)\n");
     H0("-F/--frame-threads               Number of concurrently encoded frames. Default %d\n", param->frameNumThreads);
     H0("   --log                         Logging level 0:ERROR 1:WARNING 2:INFO 3:DEBUG -1:NONE. Default %d\n", param->logLevel);
-    H0("   --csv                         Comma separated value log file, appends one line per run\n");
+    H0("   --csv                         Comma separated log file, log level >= 3 frame log, else one line per run\n");
     H0("   --no-progress                 Disable CLI progress reports\n");
     H0("-o/--output                      Bitstream output file name\n");
     H0("\nInput Options:\n");
@@ -424,11 +348,11 @@
         switch (c)
         {
         case 'h':
-            do_help(param);
+            showHelp(param);
             break;
 
         case 'V':
-            print_version(param);
+            printVersion(param);
             exit(0);
 
         default:
@@ -447,13 +371,13 @@
                 {
                     /* getopt_long might have already printed an error message */
                     if (c != 63)
-                        log(X265_LOG_WARNING, "internal error: short option '%c' has no long option\n", c);
+                        x265_log(NULL, X265_LOG_WARNING, "internal error: short option '%c' has no long option\n", c);
                     return true;
                 }
             }
             if (long_options_index < 0)
             {
-                log(X265_LOG_WARNING, "short option '%c' unrecognized\n", c);
+                x265_log(NULL, X265_LOG_WARNING, "short option '%c' unrecognized\n", c);
                 return true;
             }
 #define OPT(longname) \
@@ -464,7 +388,6 @@
             OPT("frames") this->framesToBeEncoded = (uint32_t)atoi(optarg);
             OPT("no-progress") this->bProgress = false;
             OPT("frame-skip") this->frameSkip = (uint32_t)atoi(optarg);
-            OPT("csv") param->csvfn = optarg;
             OPT("output") bitstreamfn = optarg;
             OPT("input") inputfn = optarg;
             OPT("recon") reconfn = optarg;
@@ -477,36 +400,35 @@
         if (berror)
         {
             const char *name = long_options_index > 0 ? long_options[long_options_index].name : argv[optind-2];
-            log(X265_LOG_ERROR, "invalid argument: %s = %s\n", name, optarg);
+            x265_log(NULL, X265_LOG_ERROR, "invalid argument: %s = %s\n", name, optarg);
             return true;
         }
 #undef OPT
         }
     }
 
-    cli_log_level = param->logLevel;
     if (optind < argc && !inputfn)
         inputfn = argv[optind++];
     if (optind < argc && !bitstreamfn)
         bitstreamfn = argv[optind++];
     if (optind < argc)
     {
-        log(X265_LOG_WARNING, "extra unused command arguments given <%s>\n", argv[optind]);
+        x265_log(param, X265_LOG_WARNING, "extra unused command arguments given <%s>\n", argv[optind]);
         return true;
     }
 
     if (argc <= 1 || help)
-        do_help(param);
+        showHelp(param);
 
     if (inputfn == NULL || bitstreamfn == NULL)
     {
-        log(X265_LOG_ERROR, "input or output file not specified, try -V for help\n");
+        x265_log(param, X265_LOG_ERROR, "input or output file not specified, try -V for help\n");
         return true;
     }
     this->input = Input::open(inputfn);
     if (!this->input || this->input->isFail())
     {
-        log(X265_LOG_ERROR, "unable to open input file <%s>\n", inputfn);
+        x265_log(param, X265_LOG_ERROR, "unable to open input file <%s>\n", inputfn);
         return true;
     }
     if (this->input->getWidth())
@@ -525,7 +447,7 @@
     }
     else if (param->sourceHeight <= 0 || param->sourceWidth <= 0 || param->frameRate <= 0)
     {
-        log(X265_LOG_ERROR, "YUV input requires source width, height, and rate to be specified\n");
+        x265_log(param, X265_LOG_ERROR, "YUV input requires source width, height, and rate to be specified\n");
         return true;
     }
     else
@@ -547,7 +469,7 @@
 
     this->framesToBeEncoded = this->framesToBeEncoded ? X265_MIN(this->framesToBeEncoded, numRemainingFrames) : numRemainingFrames;
 
-    if (this->cli_log_level >= X265_LOG_INFO)
+    if (param->logLevel >= X265_LOG_INFO)
     {
         fprintf(stderr, "%s  [info]: %dx%d %dHz, frames %u - %d of %d\n", input->getName(),
                 param->sourceWidth, param->sourceHeight, param->frameRate,
@@ -559,7 +481,7 @@
         this->recon = Output::open(reconfn, param->sourceWidth, param->sourceHeight, outputBitDepth, param->frameRate);
         if (this->recon->isFail())
         {
-            log(X265_LOG_WARNING, "unable to write reconstruction file\n");
+            x265_log(param, X265_LOG_WARNING, "unable to write reconstruction file\n");
             this->recon->release();
             this->recon = 0;
         }
@@ -568,7 +490,7 @@
 #if !HIGH_BIT_DEPTH
     if (inputBitDepth != 8 || outputBitDepth != 8 || param->internalBitDepth != 8)
     {
-        log(X265_LOG_ERROR, "not compiled for bit depths greater than 8\n");
+        x265_log(NULL, X265_LOG_ERROR, "not compiled for bit depths greater than 8\n");
         return true;
     }
 #endif
@@ -576,29 +498,10 @@
     this->bitstreamFile.open(bitstreamfn, std::fstream::binary | std::fstream::out);
     if (!this->bitstreamFile)
     {
-        log(X265_LOG_ERROR, "failed to open bitstream file <%s> for writing\n", bitstreamfn);
+        x265_log(NULL, X265_LOG_ERROR, "failed to open bitstream file <%s> for writing\n", bitstreamfn);
         return true;
     }
 
-    if (param->csvfn && param->logLevel < X265_LOG_DEBUG)
-    {
-        csvfp = fopen(param->csvfn, "r");
-        if (csvfp)
-        {
-            // file already exists, re-open for append
-            fclose(csvfp);
-            csvfp = fopen(param->csvfn, "ab");
-        }
-        else
-        {
-            // new CSV file, write header
-            csvfp = fopen(param->csvfn, "wb");
-            if (csvfp)
-            {
-                fprintf(csvfp, "CLI arguments, date/time, elapsed time, fps, bitrate, global PSNR Y, global PSNR U, global PSNR V, global PSNR, global SSIM, version\n");
-            }
-        }
-    }
     x265_setup_primitives(param, cpuid);
 
     return false;
@@ -629,7 +532,7 @@
     x265_t *encoder = x265_encoder_open(&param);
     if (!encoder)
     {
-        cliopt.log(X265_LOG_ERROR, "failed to open encoder\n");
+        x265_log(&param, X265_LOG_ERROR, "failed to open encoder\n");
         cliopt.destroy();
         x265_cleanup();
         exit(1);
@@ -637,7 +540,7 @@
 
     /* Control-C handler */
     if (signal(SIGINT, sigint_handler) == SIG_ERR)
-        cliopt.log(X265_LOG_ERROR, "Unable to register CTRL+C handler: %s\n", strerror(errno));
+        x265_log(&param, X265_LOG_ERROR, "Unable to register CTRL+C handler: %s\n", strerror(errno));
 
     x265_picture_t pic_orig, pic_out;
     x265_picture_t *pic_in = &pic_orig;
@@ -704,17 +607,17 @@
         fprintf(stderr, "                                                                               \r");
 
     x265_encoder_get_stats(encoder, &stats);
-    x265_encoder_close(encoder, NULL);
+    if (param.csvfn && !b_ctrl_c)
+        x265_encoder_log(encoder, argc, argv);
+    x265_encoder_close(encoder);
     cliopt.bitstreamFile.close();
 
     if (b_ctrl_c)
-        fprintf(stderr, "aborted at input frame %d, output frame %d\n", cliopt.frameSkip + inFrameCount, outFrameCount);
+        fprintf(stderr, "aborted at input frame %d, output frame %d\n", 
+                cliopt.frameSkip + inFrameCount, stats.encodedPictureCount);
 
-    double elapsed = (double)(x265_mdate() - cliopt.startTime) / 1000000;
-    double vidtime = (double)inFrameCount / param.frameRate;
-    double bitrate = (0.008f * cliopt.totalBytes) / vidtime;
-    printf("\nencoded %d frames in %.2fs (%.2f fps), %.2f kb/s, ",
-           outFrameCount, elapsed, outFrameCount / elapsed, bitrate);
+    printf("\nencoded %d frames in %.2fs (%.2f fps), %.2f kb/s, ", stats.encodedPictureCount,
+           stats.elapsedEncodeTime, stats.encodedPictureCount / stats.elapsedEncodeTime, stats.bitrate);
 
     if (param.bEnablePsnr)
         printf("Global PSNR: %.3f\n", stats.globalPsnr);
@@ -724,36 +627,6 @@
 
     x265_cleanup(); /* Free library singletons */
 
-    if (param.logLevel < X265_LOG_DEBUG && cliopt.csvfp)
-    {
-        // CLI arguments, date/time, elapsed time, fps, bitrate, global PSNR
-        fprintf(cliopt.csvfp,"\n");
-        for (int i = 1; i < argc; i++)
-        {
-            if (i) fputc(' ', cliopt.csvfp);
-            fputs(argv[i], cliopt.csvfp);
-        }
-
-        time_t now;
-        struct tm* timeinfo;
-        time(&now);
-        timeinfo = localtime(&now);
-        char buffer[128];
-        strftime(buffer, 128, "%c", timeinfo);
-        fprintf(cliopt.csvfp, ", %s, %.2f, %.2f, %.2f,", buffer, elapsed, outFrameCount / elapsed, bitrate);
-        if (param.bEnablePsnr)
-            fprintf(cliopt.csvfp, " %.3lf, %.3lf, %.3lf, %.3lf,",
-                    stats.globalPsnrY/stats.totalNumPics, stats.globalPsnrU/stats.totalNumPics,
-                    stats.globalPsnrV/stats.totalNumPics, stats.globalPsnr);
-        else
-            fprintf(cliopt.csvfp, " -, -, -, -,");
-        if (param.bEnableSsim)
-            fprintf(cliopt.csvfp, " %.2f,", stats.globalSsim);
-        else
-            fprintf(cliopt.csvfp, " -,");
-        fprintf(cliopt.csvfp, " %s\n", x265_version_str);
-    }
-
     cliopt.destroy();
 
 #if HAVE_VLD
diff -r c769d32fe9a1 -r 6fefac920311 source/x265.h
--- a/source/x265.h	Wed Oct 23 16:03:17 2013 +0530
+++ b/source/x265.h	Wed Oct 23 16:11:59 2013 -0500
@@ -239,10 +239,12 @@
     double    globalPsnrV;
     double    globalPsnr;
     double    globalSsim;
-    double    accBits;
-    uint32_t  totalNumPics;
-}
-x265_stats_t;
+    double    accBits;              // total bits output thus far
+    uint32_t  encodedPictureCount;  // number of output pictures thus far
+    double    elapsedEncodeTime;    // wall time since encoder was opened
+    double    elapsedVideoTime;     // encoded picture count / frame rate
+    double    bitrate;              // accBits / elapsed video time
+} x265_stats_t;
 
 /* Input parameters to the encoder */
 typedef struct x265_param_t
@@ -252,9 +254,9 @@
     int       poolNumThreads;                  ///< number of threads to allocate for thread pool
     int       frameNumThreads;                 ///< number of concurrently encoded frames
 
-    int       internalBitDepth;                ///< bit-depth the codec operates at
+    int       internalBitDepth;                ///< bit-depth at which the encoder operates
 
-    const char *csvfn;                        ///< csv log filename
+    const char *csvfn;                         ///< csv log filename. logLevel >= 3 is frame logging, else one line per run
 
     // source specification
     int       frameRate;                       ///< source frame-rate in Hz
@@ -416,13 +418,19 @@
  *      the payloads of all output NALs are guaranteed to be sequential in memory. */
 int x265_encoder_encode(x265_t *encoder, x265_nal_t **pp_nal, int *pi_nal, x265_picture_t *pic_in, x265_picture_t *pic_out);
 
-/* x265_encoder_stats:
-*       returns output stats from the encoder */
+/* x265_encoder_get_stats:
+ *       returns encoder statistics */
 void x265_encoder_get_stats(x265_t *encoder, x265_stats_t *);
 
+/* x265_encoder_log:
+ *       write a line to the configured CSV file.  If a CSV filename was not
+ *       configured, or file open failed, or the log level indicated frame level
+ *       logging, this function will perform no write. */
+void x265_encoder_log(x265_t *encoder, int argc, char **argv);
+
 /* x265_encoder_close:
- *      close an encoder handler.  Optionally return the global PSNR value (6 * psnrY + psnrU + psnrV) / 8 */
-void x265_encoder_close(x265_t *, double *globalPsnr);
+ *      close an encoder handler */
+void x265_encoder_close(x265_t *);
 
 /***
  * Release library static allocations


More information about the x265-devel mailing list