First successful test of VFW avi recording on Qt GUI.

This commit is contained in:
mjbudd77 2021-05-01 01:08:34 -04:00
parent 22523076de
commit 33d645f911
4 changed files with 236 additions and 26 deletions

View File

@ -34,7 +34,7 @@ if(WIN32)
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib )
set( OPENGL_LDFLAGS OpenGL::GL )
set( SDL2_LDFLAGS ${SDL_INSTALL_PREFIX}/SDL2/lib/x64/SDL2.lib )
set( SYS_LIBS wsock32 ws2_32 )
set( SYS_LIBS wsock32 ws2_32 vfw32 )
else(WIN32)
# Non Windows System
# UNIX (Linux or Mac OSX)

View File

@ -3,6 +3,11 @@
#include <stdint.h>
#include <string.h>
#ifdef WIN32
#include <windows.h>
#include <vfw.h>
#endif
#include "driver.h"
#include "common/os_utils.h"
@ -13,6 +18,7 @@
#include "Qt/AviRecord.h"
#include "Qt/avi/gwavi.h"
#include "Qt/nes_shm.h"
#include "Qt/ConsoleWindow.h"
#include "Qt/ConsoleUtilities.h"
#include "Qt/fceuWrapper.h"
@ -26,31 +32,48 @@ static int abufTail = 0;
static int abufSize = 0;
static uint32_t *rawVideoBuf = NULL;
static int16_t *rawAudioBuf = NULL;
static int videoFormat = 2;
static int videoFormat = AVI_VFW;
static int audioSampleRate = 48000;
//**************************************************************************************
static void convertRgb_32_to_24( const unsigned char *src, unsigned char *dest, int w, int h, int nPix )
static void convertRgb_32_to_24( const unsigned char *src, unsigned char *dest, int w, int h, int nPix, bool verticalFlip )
{
int i=0, j=0, x, y;
// Uncompressed RGB needs to be flipped vertically
y = h-1;
while ( y >= 0 )
if ( verticalFlip )
{
x = 0;
i = y*w*4;
// Uncompressed RGB needs to be flipped vertically
y = h-1;
while ( x < w )
while ( y >= 0 )
{
dest[j] = src[i]; i++; j++;
dest[j] = src[i]; i++; j++;
dest[j] = src[i]; i++; j++;
i++;
x++;
x = 0;
i = y*w*4;
while ( x < w )
{
dest[j] = src[i]; i++; j++;
dest[j] = src[i]; i++; j++;
dest[j] = src[i]; i++; j++;
i++;
x++;
}
y--;
}
}
else
{
int size;
size = nPix*4;
i=0;
while ( i < size )
{
dest[j] = src[i]; i++; j++;
dest[j] = src[i]; i++; j++;
dest[j] = src[i]; i++; j++;
i++;
}
y--;
}
}
//**************************************************************************************
@ -260,6 +283,127 @@ static int close(void)
}; // End X264 namespace
#endif
//**************************************************************************************
// Windows VFW Interface
#ifdef WIN32
namespace VFW
{
static bool cmpSet = false;
static COMPVARS cmpvars;
static DWORD dwFlags = 0;
static BITMAPINFOHEADER bmapIn;
static LPBITMAPINFOHEADER bmapOut = NULL;
static DWORD frameNum = 0;
static DWORD dwQuality = 0;
static LPVOID outBuf = NULL;
static int chooseConfig(int width, int height)
{
bool ret;
if ( cmpSet )
{
ICCompressorFree( &cmpvars );
cmpSet = false;
}
memset( &cmpvars, 0, sizeof(COMPVARS));
cmpvars.cbSize = sizeof(COMPVARS);
ret = ICCompressorChoose( HWND(consoleWindow->winId()), ICMF_CHOOSE_ALLCOMPRESSORS,
0, NULL, &cmpvars, 0);
//printf("hic:%i\n", cmpvars.hic);
printf("FCC:%08X %c%c%c%c \n", cmpvars.fccHandler,
(cmpvars.fccHandler & 0x000000FF) ,
(cmpvars.fccHandler & 0x0000FF00) >> 8,
(cmpvars.fccHandler & 0x00FF0000) >> 16,
(cmpvars.fccHandler & 0xFF000000) >> 24 );
if ( ret )
{
cmpSet = true;
}
return (cmpSet == false) ? -1 : 0;
}
static int init( int width, int height )
{
void *h;
DWORD dwFormatSize, dwCompressBufferSize;
memset( &bmapIn, 0, sizeof(bmapIn));
bmapIn.biSize = sizeof(BITMAPINFOHEADER);
bmapIn.biWidth = width;
bmapIn.biHeight = height;
bmapIn.biPlanes = 1;
bmapIn.biBitCount = 24;
bmapIn.biCompression = BI_RGB;
bmapIn.biSizeImage = width * height * 3;
dwFormatSize = ICCompressGetFormatSize( cmpvars.hic, &bmapIn );
printf("Format Size:%i %zi\n", dwFormatSize, sizeof(BITMAPINFOHEADER));
h = GlobalAlloc(GHND, dwFormatSize);
bmapOut = (LPBITMAPINFOHEADER)GlobalLock(h);
memset( bmapOut, 0, sizeof(bmapOut));
bmapOut->biSize = sizeof(BITMAPINFOHEADER);
ICCompressGetFormat( cmpvars.hic, &bmapIn, bmapOut);
// Find the worst-case buffer size.
dwCompressBufferSize = ICCompressGetSize( cmpvars.hic, &bmapIn, bmapOut);
printf("Worst Case Compress Buffer Size: %i\n", dwCompressBufferSize );
// Allocate a buffer and get lpOutput to point to it.
h = GlobalAlloc(GHND, dwCompressBufferSize);
outBuf = (LPVOID)GlobalLock(h);
dwQuality = ICGetDefaultQuality( cmpvars.hic );
ICCompressBegin( cmpvars.hic, &bmapIn, bmapOut );
//msleep(5000);
return 0;
}
static int close(void)
{
ICCompressEnd( cmpvars.hic);
return 0;
}
static int encode_frame( unsigned char *inBuf, int width, int height )
{
DWORD ret;
DWORD flagsOut = 0, reserved = 0;
int bytesWritten = 0;
ret = ICCompress(
cmpvars.hic,
dwFlags,
bmapOut,
outBuf,
&bmapIn,
inBuf,
&reserved,
&flagsOut,
frameNum++,
0,
dwQuality,
NULL, NULL );
if ( ret == ICERR_OK )
{
//printf("Compressing Frame:%i Size:%i\n", frameNum, bmapOut->biSizeImage);
bytesWritten = bmapOut->biSizeImage;
gwavi->add_frame( (unsigned char*)outBuf, bytesWritten );
}
return bytesWritten;
}
} // End namespace VFW
#endif
//**************************************************************************************
int aviRecordOpenFile( const char *filepath )
{
char fourcc[8];
@ -267,6 +411,18 @@ int aviRecordOpenFile( const char *filepath )
unsigned int fps;
char fileName[1024];
#ifdef WIN32
if ( videoFormat == AVI_VFW )
{
if ( !VFW::cmpSet )
{
if ( VFW::chooseConfig( nes_shm->video.ncol, nes_shm->video.nrow ) )
{
return -1;
}
}
}
#endif
if ( filepath != NULL )
{
@ -318,15 +474,23 @@ int aviRecordOpenFile( const char *filepath )
memset( fourcc, 0, sizeof(fourcc) );
if ( videoFormat == 1 )
if ( videoFormat == AVI_I420 )
{
strcpy( fourcc, "I420");
}
else if ( videoFormat == 2 )
#ifdef _USE_X264
else if ( videoFormat == AVI_X264 )
{
strcpy( fourcc, "X264");
}
#endif
#ifdef WIN32
else if ( videoFormat == AVI_VFW )
{
memcpy( fourcc, &VFW::cmpvars.fccHandler, 4);
printf("Set VFW FourCC: %s", fourcc);
}
#endif
gwavi = new gwavi_t();
@ -473,8 +637,8 @@ void AviRecordDiskThread_t::run(void)
int numPixels, width, height, numPixelsReady = 0;
int fps = 60, numSamples = 0;
unsigned char *rgb24;
int16_t audioOut[48000];
uint32_t videoOut[1048576];
int16_t *audioOut;
uint32_t *videoOut;
char writeAudio = 1;
int avgAudioPerFrame, localVideoFormat;
@ -506,11 +670,20 @@ void AviRecordDiskThread_t::run(void)
localVideoFormat = videoFormat;
#ifdef _USE_X264
if ( localVideoFormat == 2)
if ( localVideoFormat == AVI_X264)
{
X264::init( width, height );
}
#endif
#ifdef WIN32
if ( localVideoFormat == AVI_VFW)
{
VFW::init( width, height );
}
#endif
audioOut = (int16_t *)malloc(48000);
videoOut = (uint32_t*)malloc(1048576);
while ( !isInterruptionRequested() )
{
@ -528,22 +701,30 @@ void AviRecordDiskThread_t::run(void)
writeAudio = 1;
if ( localVideoFormat == 1)
if ( localVideoFormat == AVI_I420)
{
Convert_4byte_To_I420Frame<4>(videoOut,rgb24,numPixels,width);
gwavi->add_frame( rgb24, (numPixels*3)/2 );
}
#ifdef _USE_X264
else if ( localVideoFormat == 2)
else if ( localVideoFormat == AVI_X264)
{
Convert_4byte_To_I420Frame<4>(videoOut,rgb24,numPixels,width);
X264::encode_frame( rgb24, width, height );
}
#endif
#ifdef WIN32
else if ( localVideoFormat == AVI_VFW)
{
convertRgb_32_to_24( (const unsigned char*)videoOut, rgb24,
width, height, numPixels, true );
writeAudio = VFW::encode_frame( rgb24, width, height ) > 0;
}
#endif
else
{
convertRgb_32_to_24( (const unsigned char*)videoOut, rgb24,
width, height, numPixels );
width, height, numPixels, true );
gwavi->add_frame( rgb24, numPixels*3 );
}
@ -583,13 +764,22 @@ void AviRecordDiskThread_t::run(void)
free(rgb24);
#ifdef _USE_X264
if ( localVideoFormat == 2)
if ( localVideoFormat == AVI_X264)
{
X264::close();
}
#endif
#ifdef WIN32
if ( localVideoFormat == AVI_VFW)
{
VFW::close();
}
#endif
aviRecordClose();
free(audioOut);
free(videoOut);
printf("AVI Record Disk Exit\n");
emit finished();
}

View File

@ -7,6 +7,19 @@
#include <stdint.h>
#include <QThread>
enum aviEncoderList
{
AVI_RGB24 = 0,
AVI_I420,
#ifdef _USE_X264
AVI_X264,
#endif
#ifdef WIN32
AVI_VFW,
#endif
AVI_NUM_ENC
};
int aviRecordOpenFile( const char *filepath );
int aviRecordAddFrame( void );

View File

@ -83,6 +83,13 @@ int main( int argc, char *argv[] )
QApplication app(argc, argv);
//const char *styleSheetEnv = NULL;
#ifdef WIN32
if (AttachConsole(ATTACH_PARENT_PROCESS))
{
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
}
#endif
//app.setStyle( new MenuStyle() );
//styleSheetEnv = ::getenv("FCEUX_QT_STYLESHEET");