Added X265 video encoder feature to AVI Qt GUI.

This commit is contained in:
mjbudd77 2021-08-31 21:13:42 -04:00
parent bf3a02fe9b
commit 520e146b80
5 changed files with 192 additions and 1 deletions

1
README
View File

@ -27,6 +27,7 @@ Table of Contents
* qt5 OR qt6 - (qt version >= 5.11 recommended)
* liblua5.1 (optional) - Will statically link internally if the system cannot provide this.
* libx264 (optional) - H.264 video encoder for avi recording (recommended)
* libx265 (optional) - H.265 video encoder for avi recording (recommended)
* minizip
* zlib
* openGL

View File

@ -83,6 +83,13 @@ else(WIN32)
add_definitions( -D_USE_X264 ${X264_CFLAGS} )
endif()
pkg_check_modules( X265 x265)
if ( ${X265_FOUND} )
message( STATUS "Using System X265 Encoder Library ${X265_VERSION}" )
add_definitions( -D_USE_X265 ${X265_CFLAGS} )
endif()
#pkg_check_modules( GL gl) # Use built in find package instead for OpenGL
# Check for OpenGL
@ -540,7 +547,7 @@ target_link_libraries( ${APP_NAME}
${OPENGL_LDFLAGS}
${SDL2_LDFLAGS}
${MINIZIP_LDFLAGS} ${ZLIB_LIBRARIES}
${LUA_LDFLAGS} ${X264_LDFLAGS}
${LUA_LDFLAGS} ${X264_LDFLAGS} ${X265_LDFLAGS}
${SYS_LIBS}
)

View File

@ -40,6 +40,9 @@
#ifdef _USE_X264
#include "x264.h"
#endif
#ifdef _USE_X265
#include "x265.h"
#endif
#include "Qt/AviRecord.h"
#include "Qt/avi/gwavi.h"
@ -323,6 +326,149 @@ static int close(void)
}; // End X264 namespace
#endif
//**************************************************************************************
#ifdef _USE_X265
namespace X265
{
static x265_param param;
static x265_picture *pic = NULL;
static x265_picture pic_out;
static x265_encoder *hdl = NULL;
static x265_nal *nal = NULL;
static unsigned int i_nal = 0;
static int i_frame = 0;
static int init( int width, int height )
{
double fps;
unsigned int usec;
/* Get default params for preset/tuning */
//if( x265_param_default_preset( &param, "medium", NULL ) < 0 )
//{
// goto x265_init_fail;
//}
fps = getBaseFrameRate();
usec = (unsigned int)((1000000.0 / fps)+0.50);
x265_param_default( &param);
/* Configure non-default params */
param.internalCsp = X265_CSP_I420;
param.sourceWidth = width;
param.sourceHeight = height;
param.bRepeatHeaders = 1;
param.fpsNum = 1000000;
param.fpsDenom = usec;
/* Apply profile restrictions. */
//if( x265_param_apply_profile( &param, "high" ) < 0 )
//{
// goto x265_init_fail;
//}
if( (pic = x265_picture_alloc()) == NULL )
{
goto x265_init_fail;
}
x265_picture_init( &param, pic );
hdl = x265_encoder_open( &param );
if ( hdl == NULL )
{
goto x265_init_fail;
}
i_frame = 0;
return 0;
x265_init_fail:
return -1;
}
static int encode_frame( unsigned char *inBuf, int width, int height )
{
int luma_size = width * height;
int chroma_size = luma_size / 4;
int ret = 0;
int ofs;
unsigned int flags = 0, totalPayload = 0;
ofs = 0;
pic->planes[0] = &inBuf[ofs]; ofs += luma_size;
pic->planes[1] = &inBuf[ofs]; ofs += chroma_size;
pic->planes[2] = &inBuf[ofs]; ofs += chroma_size;
pic->stride[0] = width;
pic->stride[1] = width/2;
pic->stride[2] = width/2;
ret = x265_encoder_encode( hdl, &nal, &i_nal, pic, &pic_out );
if ( ret <= 0 )
{
return -1;
}
else if ( i_nal > 0 )
{
flags = 0;
totalPayload = 0;
if ( IS_X265_TYPE_I(pic_out.sliceType) )
{
flags |= gwavi_t::IF_KEYFRAME;
}
for (unsigned int i=0; i<i_nal; i++)
{
totalPayload += nal[i].sizeBytes;
}
gwavi->add_frame( nal[0].payload, totalPayload, flags );
}
return ret;
}
static int close(void)
{
int ret;
unsigned int flags = 0, totalPayload = 0;
/* Flush delayed frames */
while( hdl != NULL )
{
ret = x265_encoder_encode( hdl, &nal, &i_nal, NULL, &pic_out );
if ( ret <= 0 )
{
break;
}
else if ( i_nal > 0 )
{
totalPayload = 0;
flags = 0;
if ( IS_X265_TYPE_I(pic_out.sliceType) )
{
flags |= gwavi_t::IF_KEYFRAME;
}
for (unsigned int i=0; i<i_nal; i++)
{
totalPayload += nal[i].sizeBytes;
}
gwavi->add_frame( nal[0].payload, totalPayload, flags );
}
}
x265_encoder_close( hdl );
x265_picture_free( pic );
return 0;
}
}; // End X265 namespace
#endif
//**************************************************************************************
// Windows VFW Interface
#ifdef WIN32
namespace VFW
@ -641,6 +787,12 @@ int aviRecordOpenFile( const char *filepath )
strcpy( fourcc, "X264");
}
#endif
#ifdef _USE_X265
else if ( videoFormat == AVI_X265 )
{
strcpy( fourcc, "H265");
}
#endif
#ifdef WIN32
else if ( videoFormat == AVI_VFW )
{
@ -864,6 +1016,11 @@ int FCEUD_AviGetFormatOpts( std::vector <std::string> &formatList )
s.assign("X264 (H.264)");
break;
#endif
#ifdef _USE_X265
case AVI_X265:
s.assign("X265 (H.265)");
break;
#endif
#ifdef WIN32
case AVI_VFW:
s.assign("VfW (Video for Windows)");
@ -932,6 +1089,12 @@ void AviRecordDiskThread_t::run(void)
X264::init( width, height );
}
#endif
#ifdef _USE_X265
if ( localVideoFormat == AVI_X265)
{
X265::init( width, height );
}
#endif
#ifdef WIN32
if ( localVideoFormat == AVI_VFW)
{
@ -970,6 +1133,13 @@ void AviRecordDiskThread_t::run(void)
X264::encode_frame( rgb24, width, height );
}
#endif
#ifdef _USE_X265
else if ( localVideoFormat == AVI_X265)
{
Convert_4byte_To_I420Frame<4>(videoOut,rgb24,numPixels,width);
X265::encode_frame( rgb24, width, height );
}
#endif
#ifdef WIN32
else if ( localVideoFormat == AVI_VFW)
{
@ -1026,6 +1196,12 @@ void AviRecordDiskThread_t::run(void)
X264::close();
}
#endif
#ifdef _USE_X265
if ( localVideoFormat == AVI_X265)
{
X265::close();
}
#endif
#ifdef WIN32
if ( localVideoFormat == AVI_VFW)
{

View File

@ -18,6 +18,9 @@ enum aviEncoderList
#ifdef _USE_X264
AVI_X264,
#endif
#ifdef _USE_X265
AVI_X265,
#endif
#ifdef WIN32
AVI_VFW,
#endif

View File

@ -155,6 +155,10 @@ gwavi_t::open(const char *filename, unsigned int width, unsigned int height,
{ // X264 H.264
bits_per_pixel = 12;
}
else if ( strcmp( fourcc, "H265" ) == 0 )
{ // X265 H.265
bits_per_pixel = 12;
}
else
{ // Plain RGB24
bits_per_pixel = 24;