Windows Port: Do a complete code cleanup and refactor of aviout.cpp to use proper C++ objects.
- aviout.cpp now uses Windows-style line-endings instead of Unix-style line-endings. - AVI segments now fill up much closer to the 2 GB file limit than before. - Error handling in the file writing thread is much more robust.
This commit is contained in:
parent
cbe4717d2f
commit
db1a19ad86
File diff suppressed because it is too large
Load Diff
|
@ -18,16 +18,134 @@
|
||||||
#ifndef _AVIOUT_H_
|
#ifndef _AVIOUT_H_
|
||||||
#define _AVIOUT_H_
|
#define _AVIOUT_H_
|
||||||
|
|
||||||
#include "types.h"
|
#include <windows.h>
|
||||||
|
#include <vfw.h>
|
||||||
|
|
||||||
bool DRV_AviBegin(const char* fname, bool newsegment = false);
|
#include "GPU.h"
|
||||||
void DRV_AviEnd(bool newsegment = false);
|
#include "SPU.h"
|
||||||
|
#include "utils/task.h"
|
||||||
|
|
||||||
|
#define VIDEO_STREAM 0
|
||||||
|
#define AUDIO_STREAM 1
|
||||||
|
#define MAX_CONVERT_THREADS 32
|
||||||
|
|
||||||
|
#define AUDIO_STREAM_BUFFER_SIZE ((DESMUME_SAMPLE_RATE * sizeof(u16) * 2) / 30) // 16-bit samples, 2 channels, 2 frames (need only 1 frame's worth, but have 2 frame's worth for safety)
|
||||||
|
#define MAX_AVI_FILE_SIZE (2ULL * 1024ULL * 1024ULL * 1024ULL) // Max file size should be 2 GB due to the Video for Windows AVI limit.
|
||||||
|
#define PENDING_BUFFER_COUNT 2 // Number of pending buffers to maintain for file writes. Each pending buffer will store 1 frame's worth of the audio/video streams.
|
||||||
|
|
||||||
|
class NDSCaptureObject;
|
||||||
|
class AVIFileStream;
|
||||||
|
|
||||||
|
struct VideoConvertParam
|
||||||
|
{
|
||||||
|
NDSCaptureObject *captureObj;
|
||||||
|
|
||||||
|
const void *src;
|
||||||
|
u8 *dst;
|
||||||
|
|
||||||
|
size_t srcOffset;
|
||||||
|
size_t dstOffset;
|
||||||
|
|
||||||
|
size_t firstLineIndex;
|
||||||
|
size_t lastLineIndex;
|
||||||
|
size_t frameWidth;
|
||||||
|
};
|
||||||
|
typedef struct VideoConvertParam VideoConvertParam;
|
||||||
|
|
||||||
|
struct AVIFileWriteParam
|
||||||
|
{
|
||||||
|
AVIFileStream *fs;
|
||||||
|
u8 *srcVideo;
|
||||||
|
u8 *srcAudio;
|
||||||
|
size_t videoBufferSize;
|
||||||
|
size_t audioBufferSize;
|
||||||
|
};
|
||||||
|
typedef struct AVIFileWriteParam AVIFileWriteParam;
|
||||||
|
|
||||||
|
class AVIFileStream
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static bool __needAviLibraryInit;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
PAVIFILE _file;
|
||||||
|
PAVISTREAM _stream[2];
|
||||||
|
PAVISTREAM _compressedStream[2];
|
||||||
|
AVISTREAMINFO _streamInfo[2];
|
||||||
|
|
||||||
|
AVICOMPRESSOPTIONS _compressionOptions[2];
|
||||||
|
BITMAPINFOHEADER _bmpFormat;
|
||||||
|
WAVEFORMATEX _wavFormat;
|
||||||
|
|
||||||
|
char _baseFileName[MAX_PATH];
|
||||||
|
char _baseFileNameExt[MAX_PATH];
|
||||||
|
size_t _segmentNumber;
|
||||||
|
|
||||||
|
size_t _expectedFrameSize;
|
||||||
|
size_t _writtenBytes;
|
||||||
|
LONG _writtenVideoFrameCount;
|
||||||
|
LONG _writtenAudioSampleCount;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AVIFileStream();
|
||||||
|
~AVIFileStream();
|
||||||
|
|
||||||
|
HRESULT Open(const char *fileName, BITMAPINFOHEADER *bmpFormat, WAVEFORMATEX *wavFormat);
|
||||||
|
void Close();
|
||||||
|
bool IsValid();
|
||||||
|
|
||||||
|
HRESULT FlushVideo(u8 *srcBuffer, const LONG bufferSize);
|
||||||
|
HRESULT FlushAudio(u8 *srcBuffer, const LONG bufferSize);
|
||||||
|
HRESULT WriteOneFrame(u8 *srcVideo, const LONG videoBufferSize, u8 *srcAudio, const LONG audioBufferSize);
|
||||||
|
};
|
||||||
|
|
||||||
|
class NDSCaptureObject
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
AVIFileStream *_fs;
|
||||||
|
|
||||||
|
BITMAPINFOHEADER _bmpFormat;
|
||||||
|
WAVEFORMATEX _wavFormat;
|
||||||
|
|
||||||
|
u8 *_pendingVideoBuffer;
|
||||||
|
u8 _pendingAudioBuffer[AUDIO_STREAM_BUFFER_SIZE * PENDING_BUFFER_COUNT];
|
||||||
|
size_t _pendingAudioWriteSize[2];
|
||||||
|
size_t _currentBufferIndex;
|
||||||
|
|
||||||
|
size_t _numThreads;
|
||||||
|
Task *_fileWriteThread;
|
||||||
|
Task *_convertThread[MAX_CONVERT_THREADS];
|
||||||
|
VideoConvertParam _convertParam[MAX_CONVERT_THREADS];
|
||||||
|
AVIFileWriteParam _fileWriteParam;
|
||||||
|
|
||||||
|
public:
|
||||||
|
NDSCaptureObject();
|
||||||
|
NDSCaptureObject(size_t videoWidth, size_t videoHeight, const WAVEFORMATEX *wfex);
|
||||||
|
~NDSCaptureObject();
|
||||||
|
|
||||||
|
HRESULT OpenFileStream(const char *fileName);
|
||||||
|
void CloseFileStream();
|
||||||
|
bool IsFileStreamValid();
|
||||||
|
|
||||||
|
void StartFrame();
|
||||||
|
void StreamWriteStart();
|
||||||
|
void StreamWriteFinish();
|
||||||
|
|
||||||
|
void ConvertVideoSlice555Xto888(const VideoConvertParam ¶m);
|
||||||
|
void ConvertVideoSlice888Xto888(const VideoConvertParam ¶m);
|
||||||
|
|
||||||
|
void ReadVideoFrame(const void *srcVideoFrame, const size_t inFrameWidth, const size_t inFrameHeight, const NDSColorFormat colorFormat);
|
||||||
|
void ReadAudioFrames(const void *srcAudioBuffer, const size_t inSampleCount);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool DRV_AviBegin(const char *fileName);
|
||||||
|
void DRV_AviEnd();
|
||||||
bool AVI_IsRecording();
|
bool AVI_IsRecording();
|
||||||
|
|
||||||
void DRV_AviFrameStart();
|
void DRV_AviFrameStart();
|
||||||
void DRV_AviVideoUpdate();
|
void DRV_AviVideoUpdate(const NDSDisplayInfo &displayInfo);
|
||||||
void DRV_AviSoundUpdate(void* soundData, int soundLen);
|
void DRV_AviSoundUpdate(void *soundData, const int soundLen);
|
||||||
void DRV_AviFileWrite();
|
void DRV_AviFileWriteStart();
|
||||||
void DRV_AviFileWriteFinish();
|
void DRV_AviFileWriteFinish();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -548,7 +548,7 @@ public:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DRV_AviVideoUpdate();
|
DRV_AviVideoUpdate(latestDisplayInfo);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2235,7 +2235,7 @@ static void StepRunLoop_Core()
|
||||||
}
|
}
|
||||||
inFrameBoundary = true;
|
inFrameBoundary = true;
|
||||||
|
|
||||||
DRV_AviFileWrite();
|
DRV_AviFileWriteStart();
|
||||||
|
|
||||||
CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION);
|
CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION);
|
||||||
ServiceDisplayThreadInvocations();
|
ServiceDisplayThreadInvocations();
|
||||||
|
@ -3515,7 +3515,6 @@ int _main()
|
||||||
|
|
||||||
KillDisplay();
|
KillDisplay();
|
||||||
|
|
||||||
DRV_AviFileWriteFinish();
|
|
||||||
DRV_AviEnd();
|
DRV_AviEnd();
|
||||||
WAV_End();
|
WAV_End();
|
||||||
|
|
||||||
|
@ -3807,8 +3806,11 @@ void SetRotate(HWND hwnd, int rot, bool user)
|
||||||
void AviEnd()
|
void AviEnd()
|
||||||
{
|
{
|
||||||
NDS_Pause();
|
NDS_Pause();
|
||||||
DRV_AviFileWriteFinish();
|
|
||||||
DRV_AviEnd();
|
DRV_AviEnd();
|
||||||
|
LOG("AVI recording ended.");
|
||||||
|
driver->AddLine("AVI recording ended.");
|
||||||
|
|
||||||
NDS_UnPause();
|
NDS_UnPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3868,9 +3870,21 @@ void AviRecordTo()
|
||||||
ofn.nMaxFile = MAX_PATH;
|
ofn.nMaxFile = MAX_PATH;
|
||||||
ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST;
|
ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST;
|
||||||
|
|
||||||
if(GetSaveFileName(&ofn))
|
if (GetSaveFileName(&ofn))
|
||||||
{
|
{
|
||||||
DRV_AviBegin(folder);
|
if (AVI_IsRecording())
|
||||||
|
{
|
||||||
|
DRV_AviEnd();
|
||||||
|
LOG("AVI recording ended.");
|
||||||
|
driver->AddLine("AVI recording ended.");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool result = DRV_AviBegin(folder);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
LOG("AVI recording started.");
|
||||||
|
driver->AddLine("AVI recording started.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NDS_UnPause();
|
NDS_UnPause();
|
||||||
|
|
Loading…
Reference in New Issue