Restructured Qt AVI writer to run is its own thread.

This commit is contained in:
mjbudd77 2021-04-29 21:50:45 -04:00
parent e9dbe9428a
commit b9f6bf281f
6 changed files with 193 additions and 10 deletions

View File

@ -4,13 +4,23 @@
#include <string.h>
#include "driver.h"
#include "common/os_utils.h"
#include "Qt/AviRecord.h"
#include "Qt/avi/gwavi.h"
#include "Qt/nes_shm.h"
#include "Qt/ConsoleUtilities.h"
static gwavi_t *gwavi = NULL;
static bool recordEnable = false;
static int vbufHead = 0;
static int vbufTail = 0;
static int vbufSize = 0;
static int abufHead = 0;
static int abufTail = 0;
static int abufSize = 0;
static uint32_t *rawVideoBuf = NULL;
static int16_t *rawAudioBuf = NULL;
//**************************************************************************************
static void convertRgb_32_to_24( const unsigned char *src, unsigned char *dest, int w, int h, int nPix )
@ -64,6 +74,12 @@ int aviRecordOpenFile( const char *filepath, int format, int width, int height )
return -1;
}
vbufSize = 1024 * 1024 * 60;
rawVideoBuf = (uint32_t*)malloc( vbufSize * sizeof(uint32_t) );
abufSize = 48000;
rawAudioBuf = (int16_t*)malloc( abufSize * sizeof(uint16_t) );
recordEnable = true;
return 0;
}
@ -79,18 +95,38 @@ int aviRecordAddFrame( void )
{
return -1;
}
int numPixels, bufferSize;
int i, head, numPixels, availSize;
numPixels = nes_shm->video.ncol * nes_shm->video.nrow;
bufferSize = numPixels * sizeof(uint32_t);
availSize = (vbufTail - vbufHead);
if ( availSize <= 0 )
{
unsigned char rgb24[bufferSize];
convertRgb_32_to_24( (const unsigned char*)nes_shm->pixbuf, rgb24,
nes_shm->video.ncol, nes_shm->video.nrow, numPixels );
gwavi->add_frame( rgb24, numPixels*3 );
availSize += vbufSize;
}
while ( numPixels > availSize )
{
//printf("Video Unavail %i \n", availSize );
msleep(1);
availSize = (vbufTail - vbufHead);
if ( availSize <= 0 )
{
availSize += vbufSize;
}
}
i = 0; head = vbufHead;
while ( i < numPixels )
{
rawVideoBuf[ head ] = nes_shm->pixbuf[i]; i++;
head = (head + 1) % vbufSize;
}
vbufHead = head;
return 0;
}
//**************************************************************************************
@ -105,13 +141,15 @@ int aviRecordAddAudioFrame( int32_t *buf, int numSamples )
{
return -1;
}
int16_t lclBuf[numSamples];
for (int i=0; i<numSamples; i++)
{
lclBuf[i] = buf[i];
rawAudioBuf[ abufHead ] = buf[i];
abufHead = (abufHead + 1) % abufSize;
}
gwavi->add_audio( (unsigned char *)lclBuf, numSamples*2);
return 0;
}
//**************************************************************************************
int aviRecordClose(void)
@ -125,6 +163,17 @@ int aviRecordClose(void)
delete gwavi; gwavi = NULL;
}
if ( rawVideoBuf != NULL )
{
free(rawVideoBuf); rawVideoBuf = NULL;
}
if ( rawAudioBuf != NULL )
{
free(rawAudioBuf); rawAudioBuf = NULL;
}
vbufTail = abufTail = 0;
vbufSize = abufSize = 0;
return 0;
}
//**************************************************************************************
@ -133,3 +182,91 @@ bool aviRecordRunning(void)
return recordEnable;
}
//**************************************************************************************
// AVI Recorder Disk Thread
//**************************************************************************************
//----------------------------------------------------
AviRecordDiskThread_t::AviRecordDiskThread_t( QObject *parent )
: QThread(parent)
{
}
//----------------------------------------------------
AviRecordDiskThread_t::~AviRecordDiskThread_t(void)
{
}
//----------------------------------------------------
void AviRecordDiskThread_t::run(void)
{
int numPixels, width, height, numPixelsReady = 0;
int numSamples = 0;
unsigned char *rgb24;
int16_t audioOut[48000];
uint32_t videoOut[1048576];
printf("AVI Record Disk Start\n");
setPriority( QThread::HighestPriority );
//avgAudioPerFrame = 48000 / 60;
width = nes_shm->video.ncol;
height = nes_shm->video.nrow;
numPixels = width * height;
rgb24 = (unsigned char *)malloc( numPixels * sizeof(uint32_t) );
while ( !isInterruptionRequested() )
{
while ( (numPixelsReady < numPixels) && (vbufTail != vbufHead) )
{
videoOut[ numPixelsReady ] = rawVideoBuf[ vbufTail ]; numPixelsReady++;
vbufTail = (vbufTail + 1) % vbufSize;
}
if ( numPixelsReady >= numPixels )
{
convertRgb_32_to_24( (const unsigned char*)videoOut, rgb24,
width, height, numPixels );
gwavi->add_frame( rgb24, numPixels*3 );
numPixelsReady = 0;
numSamples = 0;
while ( abufHead != abufTail )
{
audioOut[ numSamples ] = rawAudioBuf[ abufTail ]; numSamples++;
abufTail = (abufTail + 1) % abufSize;
//if ( numSamples > avgAudioPerFrame )
//{
// break;
//}
}
if ( numSamples > 0 )
{
//printf("NUM Audio Samples: %i \n", numSamples );
gwavi->add_audio( (unsigned char *)audioOut, numSamples*2);
numSamples = 0;
}
}
else
{
msleep(1);
}
}
free(rgb24);
aviRecordClose();
printf("AVI Record Disk Exit\n");
emit finished();
}
//----------------------------------------------------
//**************************************************************************************

View File

@ -1,6 +1,11 @@
// AviRecord.h
//
#ifndef __AVI_RECORD_H__
#define __AVI_RECORD_H__
#include <stdint.h>
#include <QThread>
int aviRecordOpenFile( const char *filepath, int format, int width, int height );
@ -11,3 +16,21 @@ int aviRecordAddAudioFrame( int32_t *buf, int numSamples );
int aviRecordClose(void);
bool aviRecordRunning(void);
class AviRecordDiskThread_t : public QThread
{
Q_OBJECT
protected:
void run( void ) override;
public:
AviRecordDiskThread_t( QObject *parent = 0 );
~AviRecordDiskThread_t(void);
private:
signals:
void finished(void);
};
#endif

View File

@ -209,6 +209,10 @@ consoleWin_t::consoleWin_t(QWidget *parent)
// Viewport Cursor Type and Visibility
loadCursor();
// Create AVI Recording Disk Thread
aviDiskThread = new AviRecordDiskThread_t(this);
}
consoleWin_t::~consoleWin_t(void)
@ -244,6 +248,10 @@ consoleWin_t::~consoleWin_t(void)
emulatorThread->quit();
emulatorThread->wait( 1000 );
aviDiskThread->requestInterruption();
aviDiskThread->quit();
aviDiskThread->wait( 10000 );
fceuWrapperLock();
fceuWrapperClose();
fceuWrapperUnLock();
@ -3100,13 +3108,16 @@ void consoleWin_t::aviOpen(void)
if ( aviRecordRunning() )
{
fceuWrapperLock();
aviRecordClose();
aviDiskThread->requestInterruption();
aviDiskThread->quit();
aviDiskThread->wait(10000);
fceuWrapperUnLock();
}
else
{
fceuWrapperLock();
aviRecordOpenFile( NULL, 0, 256, 240 );
aviDiskThread->start();
fceuWrapperUnLock();
}
}

View File

@ -27,6 +27,7 @@
#include "Qt/ConsoleViewerGL.h"
#include "Qt/ConsoleViewerSDL.h"
#include "Qt/GamePadConf.h"
#include "Qt/AviRecord.h"
class emulatorThread_t : public QThread
{
@ -123,6 +124,7 @@ class consoleWin_t : public QMainWindow
int loadVideoDriver( int driverId );
emulatorThread_t *emulatorThread;
AviRecordDiskThread_t *aviDiskThread;
void addRecentRom( const char *rom );

View File

@ -81,6 +81,11 @@ gwavi_t::gwavi_t(void)
offset_count = 0;
}
gwavi_t::~gwavi_t(void)
{
}
int
gwavi_t::open(const char *filename, unsigned int width, unsigned int height,
@ -105,9 +110,13 @@ gwavi_t::open(const char *filename, unsigned int width, unsigned int height,
avi_header.flags = 0x10;
if (audio)
{
avi_header.data_streams = 2;
}
else
{
avi_header.data_streams = 1;
}
/* this field gets updated when calling gwavi_close() */
avi_header.number_of_frames = 0;

View File

@ -115,6 +115,7 @@ class gwavi_t
{
public:
gwavi_t(void);
~gwavi_t(void);
int open(const char *filename, unsigned int width,
unsigned int height, const char *fourcc, unsigned int fps,