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

Steve Borho steve at borho.org
Fri Apr 3 17:39:40 CEST 2015


On 04/02, Xinyue Lu wrote:
> # HG changeset patch
> # User Xinyue Lu <i at 7086.in>
> # Date 1428042046 25200
> #      Thu Apr 02 23:20:46 2015 -0700
> # Branch Yuuki
> # Node ID 7db1a4923bbd2533dd9ba3596f483790f4ca4981
> # Parent  9a5fa67583feb6ffb7668f82632f7e93e5ec9415
> cli: move raw bitstream output to separate file
> 
> Timebase and PTS are passed to output module
> 
> diff -r 9a5fa67583fe -r 7db1a4923bbd source/input/input.h
> --- a/source/input/input.h	Thu Apr 02 13:21:32 2015 -0500
> +++ b/source/input/input.h	Thu Apr 02 23:20:46 2015 -0700
> @@ -48,6 +48,8 @@
>      int sarWidth;
>      int sarHeight;
>      int frameCount;
> +    int timebaseNum;
> +    int timebaseDenom;
> 
>      /* user supplied */
>      int skipFrames;
> diff -r 9a5fa67583fe -r 7db1a4923bbd source/output/output.cpp
> --- a/source/output/output.cpp	Thu Apr 02 13:21:32 2015 -0500
> +++ b/source/output/output.cpp	Thu Apr 02 23:20:46 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 9a5fa67583fe -r 7db1a4923bbd source/output/output.h
> --- a/source/output/output.h	Thu Apr 02 13:21:32 2015 -0500
> +++ b/source/output/output.h	Thu Apr 02 23:20:46 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 9a5fa67583fe -r 7db1a4923bbd source/output/raw.cpp
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/source/output/raw.cpp	Thu Apr 02 23:20:46 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 9a5fa67583fe -r 7db1a4923bbd source/output/raw.h
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/source/output/raw.h	Thu Apr 02 23:20:46 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 9a5fa67583fe -r 7db1a4923bbd source/x265.cpp
> --- a/source/x265.cpp	Thu Apr 02 13:21:32 2015 -0500
> +++ b/source/x265.cpp	Thu Apr 02 23:20:46 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,16 @@
>      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) {

other than this brace, the patch looks good

> +        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",
> _______________________________________________
> x265-devel mailing list
> x265-devel at videolan.org
> https://mailman.videolan.org/listinfo/x265-devel

-- 
Steve Borho


More information about the x265-devel mailing list