[x265] [PATCH for review] cli: Timebase, PTS and output module

Xinyue Lu maillist at 7086.in
Sat Apr 4 01:25:07 CEST 2015


# Final version

# HG changeset patch
# User Xinyue Lu <i at 7086.in>
# Date 1428103358 25200
#      Fri Apr 03 16:22:38 2015 -0700
# Branch Yuuki
# Node ID f79424a65d40f958a71e79002eb4a92573c8ae73
# Parent  335c728bbd62018e1e3ed03a4df0514c213e9a4e
cli: move raw bitstream output to separate file

Timebase and PTS are passed to output module

diff -r 335c728bbd62 -r f79424a65d40 source/input/input.h
--- a/source/input/input.h	Fri Apr 03 14:27:32 2015 -0500
+++ b/source/input/input.h	Fri Apr 03 16:22:38 2015 -0700
@@ -48,6 +48,8 @@
      int sarWidth;
      int sarHeight;
      int frameCount;
+    int timebaseNum;
+    int timebaseDenom;

      /* user supplied */
      int skipFrames;
diff -r 335c728bbd62 -r f79424a65d40 source/output/output.cpp
--- a/source/output/output.cpp	Fri Apr 03 14:27:32 2015 -0500
+++ b/source/output/output.cpp	Fri Apr 03 16:22:38 2015 -0700
@@ -1,7 +1,8 @@
  /*****************************************************************************
- * Copyright (C) 2013 x265 project
+ * Copyright (C) 2013-2015 x265 project
   *
   * Authors: Steve Borho <steve at borho.org>
+ *          Xinyue Lu <i at 7086.in>
   *
   * 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
@@ -25,6 +26,8 @@
  #include "yuv.h"
  #include "y4m.h"

+#include "raw.h"
+
  using namespace x265;

  ReconFile* ReconFile::open(const char *fname, int width, int height, uint32_t bitdepth, uint32_t fpsNum, uint32_t 
fpsDenom, int csp)
@@ -36,3 +39,8 @@
      else
          return new YUVOutput(fname, width, height, bitdepth, csp);
  }
+
+OutputFile* OutputFile::open(const char *fname, InputFileInfo& inputInfo)
+{
+    return new RAWOutput(fname, inputInfo);
+}
diff -r 335c728bbd62 -r f79424a65d40 source/output/output.h
--- a/source/output/output.h	Fri Apr 03 14:27:32 2015 -0500
+++ b/source/output/output.h	Fri Apr 03 16:22:38 2015 -0700
@@ -1,7 +1,8 @@
  /*****************************************************************************
- * Copyright (C) 2013 x265 project
+ * Copyright (C) 2013-2015 x265 project
   *
   * Authors: Steve Borho <steve at borho.org>
+ *          Xinyue Lu <i at 7086.in>
   *
   * 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
@@ -25,6 +26,7 @@
  #define X265_OUTPUT_H

  #include "x265.h"
+#include "input/input.h"

  namespace x265 {
  // private x265 namespace
@@ -50,6 +52,35 @@

      virtual const char *getName() const = 0;
  };
+
+class OutputFile
+{
+protected:
+
+    virtual ~OutputFile() {}
+
+public:
+
+    OutputFile() {}
+
+    static OutputFile* open(const char *fname, InputFileInfo& inputInfo);
+
+    virtual bool isFail() const = 0;
+
+    virtual bool needPTS() const = 0;
+
+    virtual void release() = 0;
+
+    virtual const char *getName() const = 0;
+
+    virtual void setParam(x265_param *param, x265_encoder *encoder) = 0;
+
+    virtual int writeHeaders(const x265_nal* nal, uint32_t nalcount) = 0;
+
+    virtual int writeFrame(const x265_nal* nal, uint32_t nalcount, x265_picture& pic) = 0;
+
+    virtual void closeFile(int64_t largest_pts, int64_t second_largest_pts) = 0;
+};
  }

  #endif // ifndef X265_OUTPUT_H
diff -r 335c728bbd62 -r f79424a65d40 source/output/raw.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/output/raw.cpp	Fri Apr 03 16:22:38 2015 -0700
@@ -0,0 +1,77 @@
+/*****************************************************************************
+ * Copyright (C) 2013-2015 x265 project
+ *
+ * Authors: Steve Borho <steve at borho.org>
+ *          Xinyue Lu <i at 7086.in>
+ *
+ * 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 "raw.h"
+
+using namespace x265;
+using namespace std;
+
+RAWOutput::RAWOutput(const char *fname, InputFileInfo&)
+{
+    b_fail = false;
+    if (!strcmp(fname, "-"))
+    {
+        ofs = &cout;
+        return;
+    }
+    ofs = new ofstream(fname, ios::binary | ios::out);
+    if (ofs->fail())
+        b_fail = true;
+}
+
+void RAWOutput::setParam(x265_param *, x265_encoder *) { }
+
+int RAWOutput::writeHeaders(const x265_nal* nal, uint32_t nalcount)
+{
+    uint32_t bytes = 0;
+
+    for (uint32_t i = 0; i < nalcount; i++)
+    {
+        ofs->write((const char*)nal->payload, nal->sizeBytes);
+        bytes += nal->sizeBytes;
+        nal++;
+    }
+
+    return bytes;
+}
+
+int RAWOutput::writeFrame(const x265_nal* nal, uint32_t nalcount, x265_picture&)
+{
+    uint32_t bytes = 0;
+
+    for (uint32_t i = 0; i < nalcount; i++)
+    {
+        ofs->write((const char*)nal->payload, nal->sizeBytes);
+        bytes += nal->sizeBytes;
+        nal++;
+    }
+
+    return bytes;
+}
+
+void RAWOutput::closeFile(int64_t, int64_t)
+{
+    if (ofs != &cout)
+        delete ofs;
+}
diff -r 335c728bbd62 -r f79424a65d40 source/output/raw.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/output/raw.h	Fri Apr 03 16:22:38 2015 -0700
@@ -0,0 +1,64 @@
+/*****************************************************************************
+ * Copyright (C) 2013-2015 x265 project
+ *
+ * Authors: Steve Borho <steve at borho.org>
+ *          Xinyue Lu <i at 7086.in>
+ *
+ * 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_HEVC_RAW_H
+#define X265_HEVC_RAW_H
+
+#include "output.h"
+#include "common.h"
+#include <fstream>
+#include <iostream>
+
+namespace x265 {
+class RAWOutput : public OutputFile
+{
+protected:
+
+    std::ostream *ofs;
+
+    bool b_fail;
+
+public:
+
+    RAWOutput(const char *fname, InputFileInfo&);
+
+    bool isFail() const { return b_fail; }
+
+    bool needPTS() const { return false; }
+
+    void release() { delete this; }
+
+    const char *getName() const { return "RAW Bitstream"; }
+
+    void setParam(x265_param *param, x265_encoder *);
+
+    int writeHeaders(const x265_nal* nal, uint32_t nalcount);
+
+    int writeFrame(const x265_nal* nal, uint32_t nalcount, x265_picture&);
+
+    void closeFile(int64_t largest_pts, int64_t second_largest_pts);
+};
+}
+
+#endif // ifndef X265_HEVC_RAW_H
diff -r 335c728bbd62 -r f79424a65d40 source/x265.cpp
--- a/source/x265.cpp	Fri Apr 03 14:27:32 2015 -0500
+++ b/source/x265.cpp	Fri Apr 03 16:22:38 2015 -0700
@@ -46,6 +46,7 @@
  #include <string>
  #include <ostream>
  #include <fstream>
+#include <queue>

  #define CONSOLE_TITLE_SIZE 200
  #ifdef _WIN32
@@ -70,7 +71,7 @@
  {
      InputFile* input;
      ReconFile* recon;
-    std::fstream bitstreamFile;
+    OutputFile* output;
      bool bProgress;
      bool bForceY4m;
      bool bDither;
@@ -95,6 +96,7 @@
          frameRate = 0.f;
          input = NULL;
          recon = NULL;
+        output = NULL;
          framesToBeEncoded = seek = 0;
          totalbytes = 0;
          bProgress = true;
@@ -109,7 +111,6 @@
      }

      void destroy();
-    void writeNALs(const x265_nal* nal, uint32_t nalcount);
      void printStatus(uint32_t frameNum, x265_param *param);
      bool parse(int argc, char **argv, x265_param* param);
      bool parseQPFile(x265_picture &pic_org);
@@ -130,17 +131,9 @@
      if (analysisFile)
          fclose(analysisFile);
      analysisFile = NULL;
-}
-
-void CLIOptions::writeNALs(const x265_nal* nal, uint32_t nalcount)
-{
-    ProfileScopeEvent(bitstreamWrite);
-    for (uint32_t i = 0; i < nalcount; i++)
-    {
-        bitstreamFile.write((const char*)nal->payload, nal->sizeBytes);
-        totalbytes += nal->sizeBytes;
-        nal++;
-    }
+    if (output)
+        output->release();
+    output = NULL;
  }

  void CLIOptions::printStatus(uint32_t frameNum, x265_param *param)
@@ -178,7 +171,7 @@
      int reconFileBitDepth = 0;
      const char *inputfn = NULL;
      const char *reconfn = NULL;
-    const char *bitstreamfn = NULL;
+    const char *outputfn = NULL;
      const char *preset = NULL;
      const char *tune = NULL;
      const char *profile = NULL;
@@ -264,7 +257,7 @@
              OPT2("frame-skip", "seek") this->seek = (uint32_t)x265_atoi(optarg, bError);
              OPT("frames") this->framesToBeEncoded = (uint32_t)x265_atoi(optarg, bError);
              OPT("no-progress") this->bProgress = false;
-            OPT("output") bitstreamfn = optarg;
+            OPT("output") outputfn = optarg;
              OPT("input") inputfn = optarg;
              OPT("recon") reconfn = optarg;
              OPT("input-depth") inputBitDepth = (uint32_t)x265_atoi(optarg, bError);
@@ -298,8 +291,8 @@

      if (optind < argc && !inputfn)
          inputfn = argv[optind++];
-    if (optind < argc && !bitstreamfn)
-        bitstreamfn = argv[optind++];
+    if (optind < argc && !outputfn)
+        outputfn = argv[optind++];
      if (optind < argc)
      {
          x265_log(param, X265_LOG_WARNING, "extra unused command arguments given <%s>\n", argv[optind]);
@@ -309,7 +302,7 @@
      if (argc <= 1 || help)
          showHelp(param);

-    if (inputfn == NULL || bitstreamfn == NULL)
+    if (inputfn == NULL || outputfn == NULL)
      {
          x265_log(param, X265_LOG_ERROR, "input or output file not specified, try -V for help\n");
          return true;
@@ -365,6 +358,10 @@
          this->framesToBeEncoded = info.frameCount - seek;
      param->totalFrames = this->framesToBeEncoded;

+    /* Force CFR until we have support for VFR */
+    info.timebaseNum = info.fpsDenom;
+    info.timebaseDenom = info.fpsNum;
+
      if (x265_param_apply_profile(param, profile))
          return true;

@@ -408,12 +405,13 @@
                      x265_source_csp_names[param->internalCsp]);
      }

-    this->bitstreamFile.open(bitstreamfn, std::fstream::binary | std::fstream::out);
-    if (!this->bitstreamFile)
+    this->output = OutputFile::open(outputfn, info);
+    if (this->output->isFail())
      {
-        x265_log(NULL, X265_LOG_ERROR, "failed to open bitstream file <%s> for writing\n", bitstreamfn);
+        x265_log(NULL, X265_LOG_ERROR, "failed to open output file <%s> for writing\n", outputfn);
          return true;
      }
+    general_log(param, "out", X265_LOG_INFO, "Using %s\n", this->output->getName());
      return false;
  }

@@ -509,7 +507,8 @@
      x265_picture pic_orig, pic_out;
      x265_picture *pic_in = &pic_orig;
      /* Allocate recon picture if analysisMode is enabled */
-    x265_picture *pic_recon = (cliopt.recon || !!param->analysisMode) ? &pic_out : NULL;
+    bool usePTS = cliopt.output->needPTS();
+    x265_picture *pic_recon = (cliopt.recon || !!param->analysisMode || usePTS) ? &pic_out : NULL;
      uint32_t inFrameCount = 0;
      uint32_t outFrameCount = 0;
      x265_nal *p_nal;
@@ -517,6 +516,7 @@
      uint32_t nal;
      int16_t *errorBuf = NULL;
      int ret = 0;
+    std::priority_queue<int64_t> pts_queue;

      if (!param->bRepeatHeaders)
      {
@@ -527,7 +527,10 @@
              goto fail;
          }
          else
-            cliopt.writeNALs(p_nal, nal);
+        {
+            cliopt.output->setParam(param, encoder);
+            cliopt.totalbytes += cliopt.output->writeHeaders(p_nal, nal);
+        }
      }

      api->picture_init(param, pic_in);
@@ -569,6 +572,8 @@
                  ditherImage(*pic_in, param->sourceWidth, param->sourceHeight, errorBuf, X265_DEPTH);
                  pic_in->bitDepth = X265_DEPTH;
              }
+            /* Overwrite PTS */
+            pic_in->pts = pic_in->poc;
          }

          int numEncoded = api->encoder_encode(encoder, &p_nal, &nal, pic_in, pic_recon);
@@ -583,7 +588,15 @@
          if (numEncoded && pic_recon && cliopt.recon)
              cliopt.recon->writePicture(pic_out);
          if (nal)
-            cliopt.writeNALs(p_nal, nal);
+        {
+            cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);
+            if (usePTS)
+            {
+                pts_queue.push(-pic_out.pts);
+                if (pts_queue.size() > 2)
+                    pts_queue.pop();
+            }
+        }

          cliopt.printStatus(outFrameCount, param);
      }
@@ -601,7 +614,15 @@
          if (numEncoded && pic_recon && cliopt.recon)
              cliopt.recon->writePicture(pic_out);
          if (nal)
-            cliopt.writeNALs(p_nal, nal);
+        {
+            cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);
+            if (usePTS)
+            {
+                pts_queue.push(-pic_out.pts);
+                if (pts_queue.size() > 2)
+                    pts_queue.pop();
+            }
+        }

          cliopt.printStatus(outFrameCount, param);

@@ -618,7 +639,17 @@
      if (param->csvfn && !b_ctrl_c)
          api->encoder_log(encoder, argc, argv);
      api->encoder_close(encoder);
-    cliopt.bitstreamFile.close();
+
+    int64_t second_largest_pts = 0;
+    int64_t largest_pts = 0;
+    if (usePTS && pts_queue.size() >= 2)
+    {
+        second_largest_pts = -pts_queue.top();
+        pts_queue.pop();
+        largest_pts = -pts_queue.top();
+        pts_queue.pop();
+    }
+    cliopt.output->closeFile(largest_pts, second_largest_pts);

      if (b_ctrl_c)
          general_log(param, NULL, X265_LOG_INFO, "aborted at input frame %d, output frame %d\n",



More information about the x265-devel mailing list