Restructured Qt AVI writer to run is its own thread.
This commit is contained in:
parent
e9dbe9428a
commit
b9f6bf281f
|
@ -4,13 +4,23 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "driver.h"
|
#include "driver.h"
|
||||||
|
#include "common/os_utils.h"
|
||||||
|
|
||||||
#include "Qt/AviRecord.h"
|
#include "Qt/AviRecord.h"
|
||||||
#include "Qt/avi/gwavi.h"
|
#include "Qt/avi/gwavi.h"
|
||||||
#include "Qt/nes_shm.h"
|
#include "Qt/nes_shm.h"
|
||||||
|
#include "Qt/ConsoleUtilities.h"
|
||||||
|
|
||||||
static gwavi_t *gwavi = NULL;
|
static gwavi_t *gwavi = NULL;
|
||||||
static bool recordEnable = false;
|
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 )
|
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;
|
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;
|
recordEnable = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -79,18 +95,38 @@ int aviRecordAddFrame( void )
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int numPixels, bufferSize;
|
int i, head, numPixels, availSize;
|
||||||
|
|
||||||
numPixels = nes_shm->video.ncol * nes_shm->video.nrow;
|
numPixels = nes_shm->video.ncol * nes_shm->video.nrow;
|
||||||
bufferSize = numPixels * sizeof(uint32_t);
|
|
||||||
|
|
||||||
|
availSize = (vbufTail - vbufHead);
|
||||||
|
if ( availSize <= 0 )
|
||||||
{
|
{
|
||||||
unsigned char rgb24[bufferSize];
|
availSize += vbufSize;
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
//**************************************************************************************
|
//**************************************************************************************
|
||||||
|
@ -105,13 +141,15 @@ int aviRecordAddAudioFrame( int32_t *buf, int numSamples )
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int16_t lclBuf[numSamples];
|
|
||||||
|
|
||||||
for (int i=0; i<numSamples; i++)
|
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)
|
int aviRecordClose(void)
|
||||||
|
@ -125,6 +163,17 @@ int aviRecordClose(void)
|
||||||
delete gwavi; gwavi = NULL;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
//**************************************************************************************
|
//**************************************************************************************
|
||||||
|
@ -133,3 +182,91 @@ bool aviRecordRunning(void)
|
||||||
return recordEnable;
|
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();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------
|
||||||
|
//**************************************************************************************
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
// AviRecord.h
|
// AviRecord.h
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#ifndef __AVI_RECORD_H__
|
||||||
|
#define __AVI_RECORD_H__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
int aviRecordOpenFile( const char *filepath, int format, int width, int height );
|
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);
|
int aviRecordClose(void);
|
||||||
|
|
||||||
bool aviRecordRunning(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
|
||||||
|
|
|
@ -209,6 +209,10 @@ consoleWin_t::consoleWin_t(QWidget *parent)
|
||||||
|
|
||||||
// Viewport Cursor Type and Visibility
|
// Viewport Cursor Type and Visibility
|
||||||
loadCursor();
|
loadCursor();
|
||||||
|
|
||||||
|
// Create AVI Recording Disk Thread
|
||||||
|
aviDiskThread = new AviRecordDiskThread_t(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
consoleWin_t::~consoleWin_t(void)
|
consoleWin_t::~consoleWin_t(void)
|
||||||
|
@ -244,6 +248,10 @@ consoleWin_t::~consoleWin_t(void)
|
||||||
emulatorThread->quit();
|
emulatorThread->quit();
|
||||||
emulatorThread->wait( 1000 );
|
emulatorThread->wait( 1000 );
|
||||||
|
|
||||||
|
aviDiskThread->requestInterruption();
|
||||||
|
aviDiskThread->quit();
|
||||||
|
aviDiskThread->wait( 10000 );
|
||||||
|
|
||||||
fceuWrapperLock();
|
fceuWrapperLock();
|
||||||
fceuWrapperClose();
|
fceuWrapperClose();
|
||||||
fceuWrapperUnLock();
|
fceuWrapperUnLock();
|
||||||
|
@ -3100,13 +3108,16 @@ void consoleWin_t::aviOpen(void)
|
||||||
if ( aviRecordRunning() )
|
if ( aviRecordRunning() )
|
||||||
{
|
{
|
||||||
fceuWrapperLock();
|
fceuWrapperLock();
|
||||||
aviRecordClose();
|
aviDiskThread->requestInterruption();
|
||||||
|
aviDiskThread->quit();
|
||||||
|
aviDiskThread->wait(10000);
|
||||||
fceuWrapperUnLock();
|
fceuWrapperUnLock();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fceuWrapperLock();
|
fceuWrapperLock();
|
||||||
aviRecordOpenFile( NULL, 0, 256, 240 );
|
aviRecordOpenFile( NULL, 0, 256, 240 );
|
||||||
|
aviDiskThread->start();
|
||||||
fceuWrapperUnLock();
|
fceuWrapperUnLock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "Qt/ConsoleViewerGL.h"
|
#include "Qt/ConsoleViewerGL.h"
|
||||||
#include "Qt/ConsoleViewerSDL.h"
|
#include "Qt/ConsoleViewerSDL.h"
|
||||||
#include "Qt/GamePadConf.h"
|
#include "Qt/GamePadConf.h"
|
||||||
|
#include "Qt/AviRecord.h"
|
||||||
|
|
||||||
class emulatorThread_t : public QThread
|
class emulatorThread_t : public QThread
|
||||||
{
|
{
|
||||||
|
@ -123,6 +124,7 @@ class consoleWin_t : public QMainWindow
|
||||||
int loadVideoDriver( int driverId );
|
int loadVideoDriver( int driverId );
|
||||||
|
|
||||||
emulatorThread_t *emulatorThread;
|
emulatorThread_t *emulatorThread;
|
||||||
|
AviRecordDiskThread_t *aviDiskThread;
|
||||||
|
|
||||||
void addRecentRom( const char *rom );
|
void addRecentRom( const char *rom );
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,11 @@ gwavi_t::gwavi_t(void)
|
||||||
offset_count = 0;
|
offset_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gwavi_t::~gwavi_t(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
gwavi_t::open(const char *filename, unsigned int width, unsigned int height,
|
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;
|
avi_header.flags = 0x10;
|
||||||
|
|
||||||
if (audio)
|
if (audio)
|
||||||
|
{
|
||||||
avi_header.data_streams = 2;
|
avi_header.data_streams = 2;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
avi_header.data_streams = 1;
|
avi_header.data_streams = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* this field gets updated when calling gwavi_close() */
|
/* this field gets updated when calling gwavi_close() */
|
||||||
avi_header.number_of_frames = 0;
|
avi_header.number_of_frames = 0;
|
||||||
|
|
|
@ -115,6 +115,7 @@ class gwavi_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
gwavi_t(void);
|
gwavi_t(void);
|
||||||
|
~gwavi_t(void);
|
||||||
|
|
||||||
int open(const char *filename, unsigned int width,
|
int open(const char *filename, unsigned int width,
|
||||||
unsigned int height, const char *fourcc, unsigned int fps,
|
unsigned int height, const char *fourcc, unsigned int fps,
|
||||||
|
|
Loading…
Reference in New Issue