Класс-оболочка x264, использующий общий интерфейс ICodecv3 для последовательного использования других кодеков, может быть полезен для других. Это определение и реализация класса:
// Class to encapsulate the X264 encoder.
#pragma once
#include <inttypes.h>
#include <stdint.h>
#include <x264.h>
#include <ICodecv3.h>
#include <string>
#include <vector>
#include <chrono>
#include <unordered_map>
class X264Encoder : public ICodecv3
{
public:
X264Encoder(void);
~X264Encoder(void);
//--------------- ICodecv3 Interface ----------------------------------------------------
int GetParameter(const std::string type, std::string& value);
int SetParameter(const std::string type, const std::string& value);
void GetParameterName(int ordinal, std::string& name) {}
std::string GetErrorStrEx(void) { std::string errStr = _errStr; _errStr.clear(); return(errStr); } // Clear after use
int Ready(void) { if (_x264VideoEncoder != NULL) return(1); return(0); }
long GetCompressedBitLengthL(void) { return(_encodedFrameSize*8); }
long GetCompressedByteLengthL(void) { return(_encodedFrameSize); }
void* GetReference(int refNum) { return(NULL); }
void Restart(void) { _idrFrameRequired = true; }
int Open(void);
int Close(void);
int Encode(void* pSrc, void* pCmp, void* codeParameter);
int Decode(void* pCmp, int bitLength, void* pDst) { return(0); } // Decoding is not implemented.
//--------------- ICodecv2 Interface ----------------------------------------------------
// Version 2 has been superceded by version 3 and therefore none are implemented. For
// backward compatibility only.
int GetParameter(const char* type, int* length, void* value) { return(0); }
void GetParameterName(int ordinal, const char** name, int* length) {}
int SetParameter(const char* type, const char* value) { return(0); }
char* GetErrorStr(void) { return(NULL); }
int GetCompressedBitLength(void) { return(0); }
int GetCompressedByteLength(void) { return(0); }
int Code(void* pSrc, void* pCmp, int codeParameter) { return(0); }
//--------------- Implementation specific Interface --------------------------------------
private:
public:
private:
x264_t* _x264VideoEncoder;
x264_param_t _param;
x264_picture_t _picIn;
bool _inPicIsAllocated;
x264_picture_t _picOut;
int _frameNum; // Used for internal pts timestamp incremented after each encode.
long _encodedFrameSize;
bool _idrFrameRequired; // Signal an IDR-frame to the Encode() method
x264_nal_t* _nal;
int _nalCnt;
std::string _errStr;
uint32_t _colourSpace;
uint32_t _width;
uint32_t _height;
uint32_t _videoRateNumerator;
uint32_t _videoRateDenominator;
uint32_t _avgBitsPerSecond;
uint32_t _lastPicType; // 0=IDR-frame, 1=P/D-frame
// Implementation specific params.
std::string _encoderSpeedPreset;
std::string _profile;
std::unordered_map<std::string, void*> _parameters = // Hold all the settings for the encoder.
{
{ "incolour", &_colourSpace },
{ "width", &_width },
{ "height", &_height },
{ "frame rate numerator", &_videoRateNumerator },
{ "frame rate denominator", &_videoRateDenominator },
{ "avg bits per second", &_avgBitsPerSecond },
{ "encoder speed preset", &_encoderSpeedPreset },
{ "profile", &_profile },
{ "last pic coding type", &_lastPicType } // Read only.
};
std::unordered_map<uint32_t, int> _colourSpaceMapping = // Translate external "incolour" to x264 csp
{
{ 17, X264_CSP_I420 },
{ 18, X264_CSP_NV12 },
{ 0, X264_CSP_BGR },
{ 1, X264_CSP_BGRA }
};
};//end X264Encoder.
// Class to encapsulate the X264 encoder.
#include <X264Encoder.h>
#include <memory.h>
using namespace std;
X264Encoder::X264Encoder(void) :
_x264VideoEncoder(NULL),
_nal(NULL),
_nalCnt(0),
_errStr(""),
_width(0),
_height(0),
_videoRateNumerator(25),
_videoRateDenominator(1),
_avgBitsPerSecond(0),
_frameNum(0),
_encodedFrameSize(0),
_idrFrameRequired(true),
_lastPicType(0),
_inPicIsAllocated(false),
_encoderSpeedPreset("fast"),
_profile("baseline")
{
// Initialise the _param member with something.
x264_param_default_preset(&_param, _encoderSpeedPreset.c_str(), NULL);
}//end constructor.
X264Encoder::~X264Encoder(void)
{
Close();
}//end destructor.
int X264Encoder::GetParameter(const string type, string& value)
{
// _parameters map is never empty so no check required.
void* vp = _parameters[type];
if (vp != NULL)
{
if ((type == "encoder speed preset") || (type == "profile"))
value = *((string*)vp);
// else if (type == "timestamp units") // int32_t type
// value = to_string(*((int32_t*)vp));
// else if (type == "timestamp offset") // int64_t type
// value = to_string(*((int64_t*)vp));
else
value = to_string(*((uint32_t*)vp)); // For parameter values that are all uint32_t
}//end if vp...
else
return(0);
return(1);
}//end GetParameter.
int X264Encoder::SetParameter(const string type, const string& value)
{
if (value.empty()) return(0);
// _parameters is never empty so no check required.
void* vp = _parameters[type];
if (vp != NULL)
{
if ((type == "encoder speed preset") || (type == "profile"))
*((string*)vp) = value;
// else if (type == "timestamp units") // int32_t type
// *((int32_t*)vp) = stoi(value);
// else if (type == "timestamp offset") // int64_t type
// *((int64_t*)vp) = stoi(value);
else if (type == "last pic coding type") // Read only - do not set.
return(1);
else
*((uint32_t*)vp) = stoi(value);
}//end if vp...
else
return(0);
return(1);
}//end SetParameter.
// Open the X264 encoder.
// Any non-default parameters must be set prior to calling this method. Create a default set and
// modify them with the new parameters. then the encoder is instantiated.
// Return 1=success, 0=failure.
int X264Encoder::Open(void)
{
if (_x264VideoEncoder != NULL)
Close();
// Set up default parameters.
if (x264_param_default_preset(&_param, _encoderSpeedPreset.c_str(), "zerolatency") < 0) // 0=success, -1=failed
{ _errStr = "X264Encoder::Open: Default parameter preset failed with " + _encoderSpeedPreset; return(0); }
// Set non-default params.
_param.i_bitdepth = 8;
_param.i_csp = _colourSpaceMapping[_colourSpace]; // Input colour space
if(!_param.i_csp)
{ _errStr = "X264Encoder::Open: Incompatible colour space " + to_string(_colourSpace); return(0); }
_param.i_width = _width;
_param.i_height = _height;
_param.i_fps_num = _videoRateNumerator;
_param.i_fps_den = _videoRateDenominator;
_param.rc.i_bitrate = _avgBitsPerSecond / 1000; // bitrate units are in kbits/s
_param.i_threads = 1;
_param.b_vfr_input = 0; // VFR input. If 1, use timebase and timestamps for ratecontrol purposes. If 0, use fps only.
_param.b_repeat_headers = 1; // Put SPS/PPS before each keyframe
_param.b_annexb = 1; // If set, place start codes (4 bytes) before NAL units, otherwise place size (4 bytes) before NAL units.
// Apply profile restrictions.
if (x264_param_apply_profile(&_param, _profile.c_str()) < 0) // 0=success, -1=failed
{ _errStr = "X264Encoder::Open: Unable to set profile " + _profile; return(0); }
// Initialise the encoder input pic buffer.
if (x264_picture_alloc(&_picIn, _param.i_csp, _param.i_width, _param.i_height) < 0)
{ _errStr = "X264Encoder::Open: Unable to alloc input picture buffer"; return(0); }
_inPicIsAllocated = true;
// Instantiate the encoder.
_x264VideoEncoder = x264_encoder_open(&_param);
if (_x264VideoEncoder == NULL)
{
_errStr = "X264Encoder::Open: Unable to instantiate the encoder";
// Clean up before exit.
x264_picture_clean(&_picIn);
_inPicIsAllocated = false;
return(0);
}//end if !_x264VideoEncoder...
// Frame counting for pts timestamps.
_frameNum = 0;
_lastPicType = 0; // IDR-frame
return(1);
}//end Open.
// Close the encoder.
int X264Encoder::Close(void)
{
if (_x264VideoEncoder != NULL)
{
x264_encoder_close(_x264VideoEncoder);
_x264VideoEncoder = NULL;
}//end if _x264VideoEncoder...
// Input pic structure.
if (_inPicIsAllocated)
x264_picture_clean(&_picIn);
_inPicIsAllocated = false;
return(1);
}//end Close.
int X264Encoder::Encode(void* pSrc, void* pCmp, void* codeParameter)
{
_encodedFrameSize = 0;
// Validation house work.
if(!Ready())
{ _errStr = "X264Encoder::Encode: Not ready"; return(0); }
if(!pSrc || !pCmp)
{ _errStr = "X264Encoder::Encode: Invalid function parameter list"; return(0); }
// Load input image.
if(_param.i_csp != X264_CSP_I420) // Can only process I420 input colour space.
{ _errStr = "X264Encoder::Encode: I420 colour space required"; return(0); }
uint32_t lumSize = _width * _height;
uint32_t chrSize = lumSize / 4;
// Transfer the input source image into the x264 picture img structure.
uint8_t* pImg = static_cast<uint8_t*>(pSrc);
memcpy_s(_picIn.img.plane[0], lumSize, pImg, lumSize);
pImg += lumSize;
memcpy_s(_picIn.img.plane[1], chrSize, pImg, chrSize);
pImg += chrSize;
memcpy_s(_picIn.img.plane[2], chrSize, pImg, chrSize);
// Encode single frame
_picIn.i_pts = _frameNum;
if (_idrFrameRequired)
{
_picIn.i_type = X264_TYPE_IDR;
//... and clear the signal.
_idrFrameRequired = false;
}//end if _idrFrameRequired...
else
_picIn.i_type = X264_TYPE_AUTO;
_encodedFrameSize = x264_encoder_encode(_x264VideoEncoder, &_nal, &_nalCnt, &_picIn, &_picOut);
if (_encodedFrameSize > 0)
{
// Write the encoded stream to the output.
uint8_t* pOut = static_cast<uint8_t*>(pCmp);
memcpy_s(pOut, _encodedFrameSize, _nal->p_payload, _encodedFrameSize);
}//end else if _encodedFrameSize...
else
{ _errStr = "X264Encoder::Encode: Encode process failed"; return(0); }
_lastPicType = 1; // Non-IDR
if (_picOut.i_type == X264_TYPE_IDR)
_lastPicType = 0; // IDR
_frameNum++;
return(1);
}//end Encode...
Надеюсь кому-нибудь это пригодится...
person
Keith
schedule
28.10.2020
but this has not worked
Что в нем не сработало? Меня устраивает. - person szatmary   schedule 27.10.2020