shithub: openh264

ref: a913cc853e517c2a5a0f79cc72cd5df590d82317
dir: /processing/src/testbed/WelsVideoProcessor.cpp/

View raw version
/*!
 * \copy
 *     Copyright (c)  2013, Cisco Systems
 *     All rights reserved.
 *
 *     Redistribution and use in source and binary forms, with or without
 *     modification, are permitted provided that the following conditions
 *     are met:
 *
 *        * Redistributions of source code must retain the above copyright
 *          notice, this list of conditions and the following disclaimer.
 *
 *        * Redistributions in binary form must reproduce the above copyright
 *          notice, this list of conditions and the following disclaimer in
 *          the documentation and/or other materials provided with the
 *          distribution.
 *
 *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *     COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *     POSSIBILITY OF SUCH DAMAGE.
 *
 */

// WelsVideoProcessor.cpp : Defines the entry point for the console application.
//

#include <tchar.h>
#include "stdafx.h"
#include "wels_process.h"

//////////////////////////////////////////////////////////////////////////
typedef struct {
  FILE*    srcfile;
  FILE*    dstfile;
  vPixMap  src;
  vPixMap  dst;
  vMethods methods[vMethods_Mask];
} VpConfigure;
//////////////////////////////////////////////////////////////////////////

void PrintHelp (TCHAR* strAppName, TCHAR* strError) {
  if (strError) {
    _tprintf (_T ("Error: %s\n"), strError);
  } else {
    _tprintf (_T ("Welsvp Sample Console\n"));
  }

  _tprintf (_T ("Usage1: %s [Options] -i InputFile -o OutputFile -w 640 -h 480\n"), strAppName);
  _tprintf (_T ("Options: \n"));

  _tprintf (_T ("   [-sx  x]       - cropX  of src video (def: 0)\n"));
  _tprintf (_T ("   [-sy  y]       - cropY  of src video (def: 0)\n"));
  _tprintf (_T ("   [-sw  width]   - cropW  of src video (def: width)\n"));
  _tprintf (_T ("   [-sh  height]  - cropH  of src video (def: height)\n"));
  _tprintf (_T ("   [-scc format]  - format (FourCC) of src video (def: support yv12|yuy2|rgb3|rgb4)\n"));

  _tprintf (_T ("   [-dx  x]       - cropX  of dst video (def: 0)\n"));
  _tprintf (_T ("   [-dy  y]       - cropY  of dst video (def: 0)\n"));
  _tprintf (_T ("   [-dw  width]   - cropW  of dst video (def: width)\n"));
  _tprintf (_T ("   [-dh  height]  - cropH  of dst video (def: height)\n"));
  _tprintf (_T ("   [-dcc format]  - format (FourCC) of dst video (def: nv12. support nv12|yuy2)\n"));

  _tprintf (_T ("   Video Processing Algorithms\n"));
  _tprintf (_T ("   [-vaa]         - enable video analysis algorithm \n"));
  _tprintf (_T ("   [-bgd]         - enable background detection algorithm \n"));
  _tprintf (_T ("   [-scd]         - enable scene change detection algorithm \n"));
  _tprintf (_T ("   [-denoise]     - enable denoise algorithm \n"));
  _tprintf (_T ("   [-downsample]  - enable downsample algorithm \n"));

  _tprintf (_T ("   [-n frames]    - number of frames to VP process\n\n"));
  _tprintf (_T ("\n"));

  _tprintf (_T ("Usage2: %s -sw 640 -sh 480 -scc rgb3 -dw 320 -dh 240 -dcc i420 -denoise -vaa -i in.rgb -o out.yuv\n"),
            strAppName);
  _tprintf (_T ("\n"));
}

vVideoFormat Str2FourCC (TCHAR* strInput) {
  vVideoFormat format = vVideoFormat_I420; // as default

  if (0 == _tcscmp (strInput, _T ("yv12"))) {
    format = vVideoFormat_YV12;
  } else if (0 == _tcscmp (strInput, _T ("i420"))) {
    format = vVideoFormat_I420;
  } else if (0 == _tcscmp (strInput, _T ("rgb24"))) {
    format = vVideoFormat_RGB24;
  } else if (0 == _tcscmp (strInput, _T ("rgb32"))) {
    format = vVideoFormat_RGB32;
  } else if (0 == _tcscmp (strInput, _T ("yuy2"))) {
    format = vVideoFormat_YUY2;
  } else if (0 == _tcscmp (strInput, _T ("nv12"))) {
    format = vVideoFormat_NV12;
  }

  return format;
}

int ReadFile (vPixMap& pixmap, FILE* fp) {
  int ret = 0;

  int size = pixmap.Rect.width * pixmap.Rect.height;
  switch (pixmap.eFormat) {
  case vVideoFormat_I420:
  case vVideoFormat_YV12: {
    if (fread (pixmap.pPixel[0], pixmap.nSizeInBits / 8, (3 * size) >> 1, fp) <= 0)
      ret = 1;
  }
  break;
  case vVideoFormat_YUY2: {
    if (fread (pixmap.pPixel[0], pixmap.nSizeInBits / 8, 2 * size, fp) <= 0)
      ret = 1;
  }
  break;
  case vVideoFormat_RGB24: {
    if (fread (pixmap.pPixel[0], pixmap.nSizeInBits / 8, 3 * size, fp) <= 0)
      ret = 1;
  }
  break;
  case vVideoFormat_RGB32: {
    if (fread (pixmap.pPixel[0], pixmap.nSizeInBits / 8, 4 * size, fp) <= 0)
      ret = 1;
  }
  break;
  default:
    ret = 1;
    break;
  }
  return ret;
}

int WriteFile (vPixMap& pixmap, FILE* fp) {
  int ret = 0;
  int size = pixmap.Rect.width * pixmap.Rect.height;
  switch (pixmap.eFormat) {
  case vVideoFormat_I420:
  case vVideoFormat_YV12: {
    if (fwrite (pixmap.pPixel[0], pixmap.nSizeInBits / 8, (3 * size) >> 1, fp) <= 0)
      ret = 1;
  }
  break;
  case vVideoFormat_YUY2: {
    if (fwrite (pixmap.pPixel[0], pixmap.nSizeInBits / 8, 2 * size, fp) <= 0)
      ret = 1;
  }
  break;
  case vVideoFormat_RGB24: {
    if (fwrite (pixmap.pPixel[0], pixmap.nSizeInBits / 8, 3 * size, fp) <= 0)
      ret = 1;
  }
  break;
  case vVideoFormat_RGB32: {
    if (fwrite (pixmap.pPixel[0], pixmap.nSizeInBits / 8, 4 * size, fp) <= 0)
      ret = 1;
  }
  break;
  default:
    ret = 1;
    break;
  }
  return ret;
}


int AllocPixMap (vPixMap& pixmap) {
  pixmap.nSizeInBits = sizeof (unsigned char) * 8;

  switch (pixmap.eFormat) {
  case vVideoFormat_I420:
  case vVideoFormat_YV12: {
    pixmap.nStride[0]  = pixmap.Rect.width;
    pixmap.nStride[1]  = pixmap.nStride[2]  = pixmap.Rect.width / 2;
    pixmap.pPixel[0]   = new void* [pixmap.nStride[0] * pixmap.Rect.height * pixmap.nSizeInBits / 8 * 3 / 2];
    pixmap.pPixel[1]   = (unsigned char*)pixmap.pPixel[0] + pixmap.nStride[0] * pixmap.Rect.height * pixmap.nSizeInBits / 8;
    pixmap.pPixel[2]   = (unsigned char*)pixmap.pPixel[0] + pixmap.nStride[0] * pixmap.Rect.height * pixmap.nSizeInBits /
                         8 * 5 / 4;
  }
  break;

  case vVideoFormat_YUY2: {
    pixmap.nStride[0]  = pixmap.nStride[1]  = pixmap.nStride[2]  = pixmap.Rect.width * 2;
    pixmap.pPixel[0]   = new void* [pixmap.nStride[0] * pixmap.Rect.height * pixmap.nSizeInBits / 8 * 2];
    pixmap.pPixel[1]   = pixmap.pPixel[2] = NULL;
  }
  break;

  case vVideoFormat_RGB24: {
    pixmap.nStride[0]  = pixmap.nStride[1]  = pixmap.nStride[2]  = pixmap.Rect.width * 3;
    pixmap.pPixel[0]   = new void* [pixmap.nStride[0] * pixmap.Rect.height * pixmap.nSizeInBits / 8 * 3];
    pixmap.pPixel[1]   = pixmap.pPixel[2] = NULL;
  }
  break;

  case vVideoFormat_RGB32: {
    pixmap.nStride[0]  = pixmap.nStride[1]  = pixmap.nStride[2]  = pixmap.Rect.width * 4;
    pixmap.pPixel[0]   = new void* [pixmap.nStride[0] * pixmap.Rect.height * pixmap.nSizeInBits / 8 * 4];
    pixmap.pPixel[1]   = pixmap.pPixel[2] = NULL;
  }
  break;

  default:
    return 1;
  }

  return (pixmap.pPixel[0]) ? 0 : 1;
}

void FreePixMap (vPixMap& pixmap) {
  if (pixmap.pPixel[0]) {
    free (pixmap.pPixel[0]);
    pixmap.pPixel[0] = pixmap.pPixel[1] = pixmap.pPixel[2] = NULL;
  }
}

int InitResource (TCHAR* strAppName, VpConfigure& cfg) {
  if (0 == cfg.srcfile) {
    PrintHelp (strAppName, _T ("Source file can not found!\n"));
    goto exit;
  };

  if (0 == cfg.dstfile) {
    PrintHelp (strAppName, _T ("Destination file name not found"));
    goto exit;
  };

  if (cfg.dst.Rect.width == 0)
    cfg.dst.Rect.width = cfg.src.Rect.width;
  if (cfg.dst.Rect.height == 0)
    cfg.dst.Rect.height = cfg.src.Rect.height;

  cfg.methods[vMethods_ColorSpaceConvert] = vMethods_ColorSpaceConvert;

  if (AllocPixMap (cfg.src))
    goto exit;

  if (AllocPixMap (cfg.dst))
    goto exit;

  return 0;

exit:
  FreePixMap (cfg.src);
  FreePixMap (cfg.dst);
  return 1;
}

int ParseCommond (TCHAR* strInput[], int nArgNum, VpConfigure& cfg) {
  if (nArgNum < 9) {
    PrintHelp (strInput[0], _T ("please specify all necessary parameters!"));
    return 1;
  }

  int width = 0, height = 0;
  for (int i = 1; i < nArgNum; i++) {
    if (strInput[i]) {
      if (0 == _tcscmp (strInput[i], _T ("-i"))) {
        i++;
        _tfopen_s (&cfg.srcfile, strInput[i], _T ("rb"));
      } else if (0 == _tcscmp (strInput[i], _T ("-o"))) {
        i++;
        _tfopen_s (&cfg.dstfile, strInput[i], _T ("wb"));
      } else if (0 == _tcscmp (strInput[i], _T ("-w"))) {
        i++;
        _stscanf_s (strInput[i], _T ("%d"), &width);
      } else if (0 == _tcscmp (strInput[i], _T ("-h"))) {
        i++;
        _stscanf_s (strInput[i], _T ("%d"), &height);
      }
      //-----------------------------------------------------------------------------------
      else if (0 == _tcscmp (strInput[i], _T ("-sx"))) {
        i++;
        _stscanf_s (strInput[i], _T ("%hd"), &cfg.src.Rect.top);
      } else if (0 == _tcscmp (strInput[i], _T ("-sy"))) {
        i++;
        _stscanf_s (strInput[i], _T ("%hd"), &cfg.src.Rect.left);
      } else if (0 == _tcscmp (strInput[i], _T ("-sw"))) {
        i++;
        TCHAR* a = strInput[i];
        _stscanf_s (strInput[i], _T ("%hd"), &cfg.src.Rect.width);
      } else if (0 == _tcscmp (strInput[i], _T ("-sh"))) {
        i++;
        _stscanf_s (strInput[i], _T ("%hd"), &cfg.src.Rect.height);
      } else if (0 == _tcscmp (strInput[i], _T ("-scc"))) {
        i++;
        cfg.src.eFormat = Str2FourCC (strInput[i]);
      }
      //-----------------------------------------------------------------------------------
      else if (0 == _tcscmp (strInput[i], _T ("-dx"))) {
        i++;
        _stscanf_s (strInput[i], _T ("%hd"), &cfg.dst.Rect.top);
      } else if (0 == _tcscmp (strInput[i], _T ("-dy"))) {
        i++;
        _stscanf_s (strInput[i], _T ("%hd"), &cfg.dst.Rect.left);
      } else if (0 == _tcscmp (strInput[i], _T ("-dw"))) {
        i++;
        _stscanf_s (strInput[i], _T ("%hd"), &cfg.dst.Rect.width);
      } else if (0 == _tcscmp (strInput[i], _T ("-dh"))) {
        i++;
        _stscanf_s (strInput[i], _T ("%hd"), &cfg.dst.Rect.height);
      } else if (0 == _tcscmp (strInput[i], _T ("-dcc"))) {
        i++;
        cfg.dst.eFormat = Str2FourCC (strInput[i]);
      }
      //-----------------------------------------------------------------------------------
      else if (0 == _tcscmp (strInput[i], _T ("-denoise"))) {
        cfg.methods[vMethods_Denoise] = vMethods_Denoise;
      } else if (0 == _tcscmp (strInput[i], _T ("-scd"))) {
        cfg.methods[vMethods_SceneChangeDetection] = vMethods_SceneChangeDetection;
      } else if (0 == _tcscmp (strInput[i], _T ("-downsample"))) {
      } else if (0 == _tcscmp (strInput[i], _T ("-vaa"))) {
      } else if (0 == _tcscmp (strInput[i], _T ("-bgd"))) {
      } else if (0 == _tcscmp (strInput[i], _T ("-aq"))) {
      }
    }
  }

  if (cfg.src.Rect.width == 0)  cfg.src.Rect.width  = width;
  if (cfg.src.Rect.height == 0) cfg.src.Rect.height = height;
  if (cfg.dst.Rect.width == 0)  cfg.dst.Rect.width  = width;
  if (cfg.dst.Rect.height == 0) cfg.dst.Rect.height = height;

  return InitResource (strInput[0], cfg);
}

int _tmain (int argc, _TCHAR* argv[]) {
  int   ret           = 0;
  VpConfigure cfg     = {0};
  IWelsVpPlugin* pVpp = NULL;

  ret = ParseCommond (argv, argc, cfg);
  if (ret)
    goto exit;

  pVpp = new IWelsVpPlugin (ret);
  if (pVpp && ret == 0) {
    vResult vret = vRet_Success;
    while (1) {
      if (feof (cfg.srcfile))
        break;

      if (ReadFile (cfg.src, cfg.srcfile))
        break;

      vret = pVpp->Process (cfg.methods[vMethods_ColorSpaceConvert], &cfg.src, &cfg.dst);
      if (vret)
        break;

      vret = pVpp->Process (cfg.methods[vMethods_Denoise], &cfg.dst, NULL);
      if (vret)
        break;

      if (WriteFile (cfg.dst, cfg.dstfile))
        break;
    }
  }

exit:

  if (pVpp) {
    delete pVpp;
    pVpp = NULL;
  }

  if (cfg.srcfile)
    fclose (cfg.srcfile);
  if (cfg.dstfile)
    fclose (cfg.dstfile);

  FreePixMap (cfg.src);
  FreePixMap (cfg.dst);

  return 0;
}