Added X265 video encoder feature to AVI Qt GUI.
This commit is contained in:
parent
bf3a02fe9b
commit
520e146b80
1
README
1
README
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
)
|
||||
|
||||
|
|
|
@ -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( ¶m, "medium", NULL ) < 0 )
|
||||
//{
|
||||
// goto x265_init_fail;
|
||||
//}
|
||||
|
||||
fps = getBaseFrameRate();
|
||||
|
||||
usec = (unsigned int)((1000000.0 / fps)+0.50);
|
||||
|
||||
x265_param_default( ¶m);
|
||||
|
||||
/* 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( ¶m, "high" ) < 0 )
|
||||
//{
|
||||
// goto x265_init_fail;
|
||||
//}
|
||||
|
||||
if( (pic = x265_picture_alloc()) == NULL )
|
||||
{
|
||||
goto x265_init_fail;
|
||||
}
|
||||
x265_picture_init( ¶m, pic );
|
||||
|
||||
hdl = x265_encoder_open( ¶m );
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -18,6 +18,9 @@ enum aviEncoderList
|
|||
#ifdef _USE_X264
|
||||
AVI_X264,
|
||||
#endif
|
||||
#ifdef _USE_X265
|
||||
AVI_X265,
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
AVI_VFW,
|
||||
#endif
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue