Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I properly use the OpenH264 Usage Code Example for Encoding?

I have an image and want to encode it with OpenH264.

So far this is the code I derived from their wiki:

#include <fstream>
#include <iterator>

#include <iostream>
#include <codec_api.h> //standard api for openh264

//additional libaries used by sample code
#include <codec_app_def.h>
#include <codec_def.h>
#include <codec_ver.h>
#include <assert.h>
#include <vector>
#include <cstring>
int main()
{
  //parameter values
  int width = 1920;
  int height = 1080;
  int framerate = 60;
  int bitrate = 5000000;
  int total_num = 500; //what does this value do?
  //end parameter values

  //Read in the File from bmp
  std::vector<char> buf; //to store the image information

  std::basic_ifstream<char> file("/home/megamol/Git/h264_sample/build/test.bmp", std::ios::binary); //opens bitstream to source
  buf = std::vector<char>((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); // reads in data to the vector

  std::cout << "sizeof buf: " << buf.size() << std::endl;

  //Step 1: set up Encoder

  ISVCEncoder* encoder_;    //declaration of encoder pointer
  int rv = WelsCreateSVCEncoder (&encoder_);

  //Step 2: initialize with basic parameter

  SEncParamBase param;
  memset(&param, 0, sizeof (SEncParamBase));
  param.iUsageType = EUsageType::SCREEN_CONTENT_REAL_TIME;
  param.fMaxFrameRate = framerate;
  param.iPicWidth = width;
  param.iPicHeight = height;
  param.iTargetBitrate = bitrate; //default value of example
  encoder_->Initialize(&param);

  //Step 3: set video format

  int videoFormat = videoFormatI420;
  encoder_->SetOption (ENCODER_OPTION_DATAFORMAT, &videoFormat);

  //Step 4: encocode and store output bitstream
  int frameSize = width * height * 3 / 2;
  buf.resize(frameSize);  

  SFrameBSInfo info;
  std::vector<char> compressedData;

  memset (&info, 0, sizeof (SFrameBSInfo));
  SSourcePicture pic;
  memset (&pic, 0, sizeof (SSourcePicture));
  pic.iPicWidth = width;
  pic.iPicHeight = height;
  pic.iColorFormat = videoFormatI420;
  pic.iStride[0] = pic.iPicWidth;
  pic.iStride[1] = pic.iStride[2] = pic.iPicWidth >> 1;
  pic.pData[0] = reinterpret_cast<unsigned char*>(&buf[0]);
  pic.pData[1] = pic.pData[0] + width * height;
  pic.pData[2] = pic.pData[1] + (width * height >> 2);

   //encodes the frame
   rv = encoder_->EncodeFrame (&pic, &info); // encodes the Frame
   //encoding done encoded Frame should be stored in &info

   //begin decoding block
   ISVCDecoder *pSvcDecoder;
   unsigned char *pBuf= &info;

  return 0;
}

I'm not entirely sure whether this is the correct usage of OpenH264 but I'm also not sure how to test it properly.

Now the code example is kind of poorly documented.

What is BufferedData buf; for example? I get that that's supposed to be the input but what is that type? Like how do I load my test.bmp as BufferedData? I don't think that I'm doing that correctly yet.

Another thing I'm pretty confused about is how do I access the output after the encoding? In the example it just says //output bitstream and nothing about saving this output anywhere. I thought the output was info like it says in the codec_api.h header file:

  /**
  * @brief Encode one frame
  * @param kpSrcPic the pointer to the source luminance plane
  *        chrominance data:
  *        CbData = kpSrc  +  m_iMaxPicWidth * m_iMaxPicHeight;
  *        CrData = CbData + (m_iMaxPicWidth * m_iMaxPicHeight)/4;
  *        the application calling this interface needs to ensure the data validation between the location
  * @param pBsInfo output bit stream
  * @return  0 - success; otherwise -failed;
  */
  virtual int EXTAPI EncodeFrame (const SSourcePicture* kpSrcPic, SFrameBSInfo* pBsInfo) = 0;

But apparently it only saves informations about the output. I'm just really confused about all of this.

like image 490
dYTe Avatar asked Oct 17 '22 16:10

dYTe


1 Answers

Based on https://github.com/cisco/openh264/blob/master/codec/console/enc/src/welsenc.cpp

#include <codec_api.h>
#include <cassert>
#include <cstring>
#include <vector>
#include <fstream>
#include <iostream>

//Tested with OpenCV 3.3
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

using namespace std;
using namespace cv;

int main()
{
    ISVCEncoder *encoder_ = nullptr;
    int rv = WelsCreateSVCEncoder (&encoder_);
    assert (0==rv);
    assert (encoder_ != nullptr);

    int width = 640;
    int height = 480;
    int total_num = 100;

    SEncParamBase param;
    memset (&param, 0, sizeof (SEncParamBase));
    param.iUsageType = CAMERA_VIDEO_REAL_TIME;
    param.fMaxFrameRate = 30;
    param.iPicWidth = width;
    param.iPicHeight = height;
    param.iTargetBitrate = 5000000;
    encoder_->Initialize (&param);

    Mat image = imread("test.jpg", IMREAD_COLOR );
    Mat imageResized, imageYuv, imageYuvMini; 
    resize(image, imageResized, Size(width, height));
    Mat imageYuvCh[3], imageYuvMiniCh[3];
    cvtColor(imageResized, imageYuv, cv::COLOR_BGR2YUV);
    split(imageYuv, imageYuvCh);
    resize(imageYuv, imageYuvMini, Size(width/2, height/2));
    split(imageYuvMini, imageYuvMiniCh);

    SFrameBSInfo info;
    memset (&info, 0, sizeof (SFrameBSInfo));
    SSourcePicture pic;
    memset (&pic, 0, sizeof (SSourcePicture));
    pic.iPicWidth = width;
    pic.iPicHeight = height;
    pic.iColorFormat = videoFormatI420;
    pic.iStride[0] = imageYuvCh[0].step;
    pic.iStride[1] = imageYuvMiniCh[1].step;
    pic.iStride[2] = imageYuvMiniCh[2].step;
    pic.pData[0] = imageYuvCh[0].data;
    pic.pData[1] = imageYuvMiniCh[1].data;
    pic.pData[2] = imageYuvMiniCh[2].data;

    ofstream outFi;
    outFi.open ("test.264", ios::out | ios::binary);

    for(int num = 0; num<total_num; num++) 
    {
        //prepare input data
        rv = encoder_->EncodeFrame (&pic, &info);
        assert (rv == cmResultSuccess);
        if (info.eFrameType != videoFrameTypeSkip /*&& cbk != nullptr*/) 
        {
            //output bitstream
            for (int iLayer=0; iLayer < info.iLayerNum; iLayer++)
            {
                SLayerBSInfo* pLayerBsInfo = &info.sLayerInfo[iLayer];

                int iLayerSize = 0;
                int iNalIdx = pLayerBsInfo->iNalCount - 1;
                do {
                    iLayerSize += pLayerBsInfo->pNalLengthInByte[iNalIdx];
                    --iNalIdx;
                } while (iNalIdx >= 0);

                unsigned char *outBuf = pLayerBsInfo->pBsBuf;
                outFi.write((char *)outBuf, iLayerSize);
            }

        }
    }

    if (encoder_) {
        encoder_->Uninitialize();
        WelsDestroySVCEncoder (encoder_);
    }

    outFi.close();
}
like image 176
TimSC Avatar answered Oct 31 '22 19:10

TimSC