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)
|
* qt5 OR qt6 - (qt version >= 5.11 recommended)
|
||||||
* liblua5.1 (optional) - Will statically link internally if the system cannot provide this.
|
* liblua5.1 (optional) - Will statically link internally if the system cannot provide this.
|
||||||
* libx264 (optional) - H.264 video encoder for avi recording (recommended)
|
* libx264 (optional) - H.264 video encoder for avi recording (recommended)
|
||||||
|
* libx265 (optional) - H.265 video encoder for avi recording (recommended)
|
||||||
* minizip
|
* minizip
|
||||||
* zlib
|
* zlib
|
||||||
* openGL
|
* openGL
|
||||||
|
|
|
@ -83,6 +83,13 @@ else(WIN32)
|
||||||
add_definitions( -D_USE_X264 ${X264_CFLAGS} )
|
add_definitions( -D_USE_X264 ${X264_CFLAGS} )
|
||||||
endif()
|
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
|
#pkg_check_modules( GL gl) # Use built in find package instead for OpenGL
|
||||||
|
|
||||||
# Check for OpenGL
|
# Check for OpenGL
|
||||||
|
@ -540,7 +547,7 @@ target_link_libraries( ${APP_NAME}
|
||||||
${OPENGL_LDFLAGS}
|
${OPENGL_LDFLAGS}
|
||||||
${SDL2_LDFLAGS}
|
${SDL2_LDFLAGS}
|
||||||
${MINIZIP_LDFLAGS} ${ZLIB_LIBRARIES}
|
${MINIZIP_LDFLAGS} ${ZLIB_LIBRARIES}
|
||||||
${LUA_LDFLAGS} ${X264_LDFLAGS}
|
${LUA_LDFLAGS} ${X264_LDFLAGS} ${X265_LDFLAGS}
|
||||||
${SYS_LIBS}
|
${SYS_LIBS}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,9 @@
|
||||||
#ifdef _USE_X264
|
#ifdef _USE_X264
|
||||||
#include "x264.h"
|
#include "x264.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _USE_X265
|
||||||
|
#include "x265.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Qt/AviRecord.h"
|
#include "Qt/AviRecord.h"
|
||||||
#include "Qt/avi/gwavi.h"
|
#include "Qt/avi/gwavi.h"
|
||||||
|
@ -323,6 +326,149 @@ static int close(void)
|
||||||
}; // End X264 namespace
|
}; // End X264 namespace
|
||||||
#endif
|
#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
|
// Windows VFW Interface
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
namespace VFW
|
namespace VFW
|
||||||
|
@ -641,6 +787,12 @@ int aviRecordOpenFile( const char *filepath )
|
||||||
strcpy( fourcc, "X264");
|
strcpy( fourcc, "X264");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _USE_X265
|
||||||
|
else if ( videoFormat == AVI_X265 )
|
||||||
|
{
|
||||||
|
strcpy( fourcc, "H265");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
else if ( videoFormat == AVI_VFW )
|
else if ( videoFormat == AVI_VFW )
|
||||||
{
|
{
|
||||||
|
@ -864,6 +1016,11 @@ int FCEUD_AviGetFormatOpts( std::vector <std::string> &formatList )
|
||||||
s.assign("X264 (H.264)");
|
s.assign("X264 (H.264)");
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _USE_X265
|
||||||
|
case AVI_X265:
|
||||||
|
s.assign("X265 (H.265)");
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
case AVI_VFW:
|
case AVI_VFW:
|
||||||
s.assign("VfW (Video for Windows)");
|
s.assign("VfW (Video for Windows)");
|
||||||
|
@ -932,6 +1089,12 @@ void AviRecordDiskThread_t::run(void)
|
||||||
X264::init( width, height );
|
X264::init( width, height );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _USE_X265
|
||||||
|
if ( localVideoFormat == AVI_X265)
|
||||||
|
{
|
||||||
|
X265::init( width, height );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
if ( localVideoFormat == AVI_VFW)
|
if ( localVideoFormat == AVI_VFW)
|
||||||
{
|
{
|
||||||
|
@ -970,6 +1133,13 @@ void AviRecordDiskThread_t::run(void)
|
||||||
X264::encode_frame( rgb24, width, height );
|
X264::encode_frame( rgb24, width, height );
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
#ifdef WIN32
|
||||||
else if ( localVideoFormat == AVI_VFW)
|
else if ( localVideoFormat == AVI_VFW)
|
||||||
{
|
{
|
||||||
|
@ -1026,6 +1196,12 @@ void AviRecordDiskThread_t::run(void)
|
||||||
X264::close();
|
X264::close();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _USE_X265
|
||||||
|
if ( localVideoFormat == AVI_X265)
|
||||||
|
{
|
||||||
|
X265::close();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
if ( localVideoFormat == AVI_VFW)
|
if ( localVideoFormat == AVI_VFW)
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,6 +18,9 @@ enum aviEncoderList
|
||||||
#ifdef _USE_X264
|
#ifdef _USE_X264
|
||||||
AVI_X264,
|
AVI_X264,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _USE_X265
|
||||||
|
AVI_X265,
|
||||||
|
#endif
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
AVI_VFW,
|
AVI_VFW,
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -155,6 +155,10 @@ gwavi_t::open(const char *filename, unsigned int width, unsigned int height,
|
||||||
{ // X264 H.264
|
{ // X264 H.264
|
||||||
bits_per_pixel = 12;
|
bits_per_pixel = 12;
|
||||||
}
|
}
|
||||||
|
else if ( strcmp( fourcc, "H265" ) == 0 )
|
||||||
|
{ // X265 H.265
|
||||||
|
bits_per_pixel = 12;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{ // Plain RGB24
|
{ // Plain RGB24
|
||||||
bits_per_pixel = 24;
|
bits_per_pixel = 24;
|
||||||
|
|
Loading…
Reference in New Issue