diff --git a/VBA.vcproj b/VBA.vcproj
index 77a74dff..196ee02e 100644
--- a/VBA.vcproj
+++ b/VBA.vcproj
@@ -1,7 +1,7 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -548,6 +538,16 @@
Outputs=""$(IntDir)\$(InputName).obj""
/>
+
+
+
@@ -623,16 +623,6 @@
Outputs=""$(IntDir)\$(InputName).obj""
/>
-
-
-
@@ -643,6 +633,16 @@
Outputs=""$(IntDir)\$(InputName).obj""
/>
+
+
+
@@ -667,16 +667,6 @@
Outputs=""$(IntDir)\$(InputName).obj""
/>
-
-
-
@@ -687,6 +677,16 @@
Outputs=""$(IntDir)\$(InputName).obj""
/>
+
+
+
@@ -711,16 +711,6 @@
Outputs=""$(IntDir)\$(InputName).obj""
/>
-
-
-
@@ -731,6 +721,16 @@
Outputs=""$(IntDir)\$(InputName).obj""
/>
+
+
+
@@ -755,16 +755,6 @@
Outputs=""$(IntDir)\$(InputName).obj""
/>
-
-
-
@@ -775,6 +765,16 @@
Outputs=""$(IntDir)\$(InputName).obj""
/>
+
+
+
@@ -1347,7 +1347,7 @@
/>
> 8) & 255;
}
-void utilWriteBMP(char *buf, int w, int h, u8 *pix)
-{
- u8 *b = (u8 *)buf;
-
- int sizeX = w;
- int sizeY = h;
-
- switch(systemColorDepth) {
- case 16:
- {
- u16 *p = (u16 *)(pix+(w+2)*(h)*2); // skip first black line
- for(int y = 0; y < sizeY; y++) {
- for(int x = 0; x < sizeX; x++) {
- u16 v = *p++;
-
- *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B
- *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
- *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
- }
- p++; // skip black pixel for filters
- p++; // skip black pixel for filters
- p -= 2*(w+2);
- }
- }
- break;
- case 24:
- {
- u8 *pixU8 = (u8 *)pix+3*w*(h-1);
- for(int y = 0; y < sizeY; y++) {
- for(int x = 0; x < sizeX; x++) {
- if(systemRedShift > systemBlueShift) {
- *b++ = *pixU8++; // B
- *b++ = *pixU8++; // G
- *b++ = *pixU8++; // R
- } else {
- int red = *pixU8++;
- int green = *pixU8++;
- int blue = *pixU8++;
-
- *b++ = blue;
- *b++ = green;
- *b++ = red;
- }
- }
- pixU8 -= 2*3*w;
- }
- }
- break;
- case 32:
- {
- u32 *pixU32 = (u32 *)(pix+4*(w+1)*(h));
- for(int y = 0; y < sizeY; y++) {
- for(int x = 0; x < sizeX; x++) {
- u32 v = *pixU32++;
-
- *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B
- *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
- *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
- }
- pixU32++;
- pixU32 -= 2*(w+1);
- }
- }
- break;
- }
-}
-
bool utilWriteBMPFile(const char *fileName, int w, int h, u8 *pix)
{
u8 writeBuffer[512 * 3];
diff --git a/src/Util.h b/src/Util.h
index 3fc1aff2..62ca8ecc 100644
--- a/src/Util.h
+++ b/src/Util.h
@@ -38,7 +38,6 @@ typedef struct {
extern bool utilWritePNGFile(const char *, int, int, u8 *);
extern bool utilWriteBMPFile(const char *, int, int, u8 *);
extern void utilApplyIPS(const char *ips, u8 **rom, int *size);
-extern void utilWriteBMP(char *, int, int, u8 *);
extern bool utilIsGBAImage(const char *);
extern bool utilIsGBImage(const char *);
extern bool utilIsZipFile(const char *);
diff --git a/src/win32/AVIWrite.cpp b/src/win32/AVIWrite.cpp
index 79f3a4f6..6f681f2f 100644
--- a/src/win32/AVIWrite.cpp
+++ b/src/win32/AVIWrite.cpp
@@ -1,6 +1,5 @@
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
-// Copyright (C) 1999-2003 Forgotten
-// Copyright (C) 2004 Forgotten and the VBA development team
+// Copyright (C) 2007 VBA-M development team
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -16,172 +15,242 @@
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#include "stdafx.h"
+
#include "AVIWrite.h"
+#pragma comment( lib, "vfw32.lib" )
+
AVIWrite::AVIWrite()
{
- m_failed = false;
- m_file = NULL;
- m_stream = NULL;
- m_streamCompressed = NULL;
- m_streamSound = NULL;
- m_samplesSound = 0;
+ m_failed = false;
+ m_file = NULL;
+ m_videoStream = NULL;
+ m_audioStream = NULL;
+ m_frameRate = 0;
+ m_frameCounter = 0;
+ m_sampleCounter = 0;
+ m_videoFrameSize = 0;
+ m_audioFrameSize = 0;
- AVIFileInit();
+ AVIFileInit();
}
+
AVIWrite::~AVIWrite()
{
- if(m_streamSound)
- AVIStreamClose(m_streamSound);
+ if( m_audioStream ) {
+ AVIStreamRelease( m_audioStream );
+ }
- if(m_streamCompressed)
- AVIStreamClose(m_streamCompressed);
+ if( m_videoStream ) {
+ AVIStreamRelease( m_videoStream );
+ }
- if(m_stream)
- AVIStreamClose(m_stream);
+ if( m_file ) {
+ AVIFileRelease( m_file );
+ }
- if(m_file)
- AVIFileClose(m_file);
-
- AVIFileExit();
+ AVIFileExit();
}
-void AVIWrite::SetVideoFormat(BITMAPINFOHEADER *bh)
+
+bool AVIWrite::CreateAVIFile( LPCTSTR filename )
{
- // force size to 0x28 to avoid extra fields
- memcpy(&m_bitmap, bh, 0x28);
+ if( m_file || m_failed ) return false;
+
+ HRESULT err = 0;
+
+ // -- create the AVI file --
+ err = AVIFileOpen(
+ &m_file,
+ filename,
+ OF_CREATE | OF_WRITE | OF_SHARE_EXCLUSIVE,
+ NULL
+ );
+
+ if( FAILED( err ) ) {
+ m_failed = true;
+ return false;
+ }
+
+ return true;
}
-void AVIWrite::SetSoundFormat(WAVEFORMATEX *format)
+
+// colorBits: 16, 24 or 32
+bool AVIWrite::CreateVideoStream( LONG imageWidth, LONG imageHeight, WORD colorBits, DWORD framesPerSecond )
{
- memcpy(&m_soundFormat, format, sizeof(WAVEFORMATEX));
- ZeroMemory(&m_soundHeader, sizeof(AVISTREAMINFO));
- // setup the sound stream header
- m_soundHeader.fccType = streamtypeAUDIO;
- m_soundHeader.dwQuality = (DWORD)-1;
- m_soundHeader.dwScale = format->nBlockAlign;
- m_soundHeader.dwInitialFrames = 1;
- m_soundHeader.dwRate = format->nAvgBytesPerSec;
- m_soundHeader.dwSampleSize = format->nBlockAlign;
+ if( m_videoStream || m_failed ) return false;
- // create the sound stream
- if(FAILED(AVIFileCreateStream(m_file, &m_streamSound, &m_soundHeader))) {
- m_failed = true;
- return;
- }
+ HRESULT err = 0;
+ AVISTREAMINFO videoInfo;
+ BITMAPINFOHEADER bitmapInfo;
+ ZeroMemory( &videoInfo, sizeof( videoInfo ) );
+ ZeroMemory( &bitmapInfo, sizeof( bitmapInfo ) );
- // setup the sound stream format
- if(FAILED(AVIStreamSetFormat(m_streamSound, 0 , (void *)&m_soundFormat,
- sizeof(WAVEFORMATEX)))) {
- m_failed = true;
- return;
- }
+ // -- initialize the video stream information --
+ videoInfo.fccType = streamtypeVIDEO;
+ videoInfo.dwScale = 1;
+ videoInfo.dwRate = framesPerSecond;
+ videoInfo.dwSuggestedBufferSize = imageWidth * imageHeight * ( colorBits >> 3 );
+
+ // -- create the video stream --
+ err = AVIFileCreateStream(
+ m_file,
+ &m_videoStream,
+ &videoInfo
+ );
+
+ if( FAILED( err ) ) {
+ m_failed = true;
+ return false;
+ }
+
+
+ // -- initialize the video stream format --
+ bitmapInfo.biSize = sizeof( bitmapInfo );
+ bitmapInfo.biWidth = imageWidth;
+ bitmapInfo.biHeight = imageHeight;
+ bitmapInfo.biBitCount = colorBits;
+ bitmapInfo.biPlanes = 1;
+ bitmapInfo.biCompression = BI_RGB;
+ bitmapInfo.biSizeImage = imageWidth * imageHeight * ( colorBits >> 3 );
+
+ // -- set the video stream format --
+ err = AVIStreamSetFormat(
+ m_videoStream,
+ 0,
+ &bitmapInfo,
+ sizeof( bitmapInfo )
+ );
+
+ if( FAILED( err ) ) {
+ m_failed = true;
+ return false;
+ }
+
+ m_frameRate = framesPerSecond;
+ m_videoFrameSize = imageWidth * imageHeight * ( colorBits >> 3 );
+
+ return true;
}
-bool AVIWrite::Open(const char *filename)
+
+// call AddVideoStream() first
+// channelCount: max. 2
+// sampleBits: max. 16
+bool AVIWrite::CreateAudioStream( WORD channelCount, DWORD sampleRate, WORD sampleBits )
{
- // create the AVI file
- if(FAILED(AVIFileOpen(&m_file,
- filename,
- OF_WRITE | OF_CREATE,
- NULL))) {
- m_failed = true;
- return false;
- }
- // setup the video stream information
- ZeroMemory(&m_header, sizeof(AVISTREAMINFO));
- m_header.fccType = streamtypeVIDEO;
- m_header.dwScale = 1;
- m_header.dwRate = m_fps;
- m_header.dwSuggestedBufferSize = m_bitmap.biSizeImage;
+ if( m_audioStream || m_failed ) return false;
- // create the video stream
- if(FAILED(AVIFileCreateStream(m_file,
- &m_stream,
- &m_header))) {
- m_failed = true;
- return false;
- }
+ HRESULT err = 0;
+ AVISTREAMINFO audioInfo;
+ WAVEFORMATEX waveInfo;
+ ZeroMemory( &audioInfo, sizeof( audioInfo ) );
+ ZeroMemory( &waveInfo, sizeof( waveInfo ) );
- ZeroMemory(&m_options, sizeof(AVICOMPRESSOPTIONS));
- m_arrayOptions[0] = &m_options;
+ // -- initialize the audio stream information --
+ audioInfo.fccType = streamtypeAUDIO;
+ audioInfo.dwQuality = (DWORD)-1;
+ audioInfo.dwScale = channelCount * ( sampleBits >> 3 );
+ audioInfo.dwRate = channelCount * ( sampleBits >> 3 ) * sampleRate;
+ audioInfo.dwInitialFrames = 1;
+ audioInfo.dwSampleSize = channelCount * ( sampleBits >> 3 );
+ audioInfo.dwSuggestedBufferSize = 0;
- // call the dialog to setup the compress options to be used
- if(!AVISaveOptions(AfxGetApp()->m_pMainWnd->GetSafeHwnd(), 0, 1, &m_stream, m_arrayOptions)) {
- m_failed = true;
- return false;
- }
+ // -- create the audio stream --
+ err = AVIFileCreateStream(
+ m_file,
+ &m_audioStream,
+ &audioInfo
+ );
- // create the compressed stream
- if(FAILED(AVIMakeCompressedStream(&m_streamCompressed, m_stream, &m_options, NULL))) {
- m_failed = true;
- return false;
- }
+ if( FAILED( err ) ) {
+ m_failed = true;
+ return false;
+ }
- // setup the video stream format
- if(FAILED( AVIStreamSetFormat(m_streamCompressed, 0,
- &m_bitmap,
- m_bitmap.biSize +
- m_bitmap.biClrUsed * sizeof(RGBQUAD)))) {
- m_failed = true;
- return false;
- }
- return true;
+ // -- initialize the audio stream format --
+ waveInfo.wFormatTag = WAVE_FORMAT_PCM;
+ waveInfo.nChannels = channelCount;
+ waveInfo.nSamplesPerSec = sampleRate;
+ waveInfo.nAvgBytesPerSec = channelCount * ( sampleBits >> 3 ) * sampleRate;
+ waveInfo.nBlockAlign = channelCount * ( sampleBits >> 3 );
+ waveInfo.wBitsPerSample = sampleBits;
+ waveInfo.cbSize = 0;
+
+ // -- set the audio stream format --
+ err = AVIStreamSetFormat(
+ m_audioStream,
+ 0,
+ &waveInfo,
+ sizeof( waveInfo )
+ );
+
+ if( FAILED( err ) ) {
+ m_failed = true;
+ return false;
+ }
+
+ m_audioBlockAlign = channelCount * ( sampleBits >> 3 );
+ m_audioFrameSize = channelCount * ( sampleBits >> 3 ) * ( sampleRate / m_frameRate );
+
+ return true;
}
-bool AVIWrite::AddSound(const char *sound, int len)
+
+bool AVIWrite::AddVideoFrame( LPVOID imageData )
{
- // return if we failed somewhere already
- if(m_failed)
- return false;
+ if( !m_videoStream || m_failed ) return false;
- int samples = len / m_soundFormat.nBlockAlign;
+ HRESULT err = 0;
- if(FAILED(AVIStreamWrite(m_streamSound,
- m_samplesSound,
- samples,
- (LPVOID)sound,
- len,
- 0,
- NULL,
- NULL))) {
- m_failed = true;
- return false;
- }
- m_samplesSound += samples;
+ err = AVIStreamWrite(
+ m_videoStream,
+ m_frameCounter,
+ 1,
+ imageData,
+ m_videoFrameSize,
+ AVIIF_KEYFRAME,
+ NULL,
+ NULL
+ );
- return true;
+ if( FAILED( err ) ) {
+ m_failed = true;
+ return false;
+ }
+
+ m_frameCounter++;
+
+ return true;
}
-bool AVIWrite::AddFrame(const int frame, const char *bmp)
+
+bool AVIWrite::AddAudioFrame( LPVOID soundData )
{
- if (m_failed)
- return false;
+ if( !m_audioStream || m_failed ) return false;
- // write the frame to the video stream
- if(FAILED(AVIStreamWrite(m_streamCompressed,
- frame,
- 1,
- (LPVOID)bmp,
- m_bitmap.biSizeImage,
- AVIIF_KEYFRAME,
- NULL,
- NULL))) {
- m_failed = true;
- return false;
- }
- return true;
-}
+ HRESULT err = 0;
-bool AVIWrite::IsSoundAdded()
-{
- return m_streamSound != NULL;
-}
+ err = AVIStreamWrite(
+ m_audioStream,
+ m_sampleCounter,
+ m_audioFrameSize / m_audioBlockAlign,
+ soundData,
+ m_audioFrameSize,
+ 0,
+ NULL,
+ NULL
+ );
-void AVIWrite::SetFPS(int f)
-{
- m_fps = f;
+ if( FAILED( err ) ) {
+ m_failed = true;
+ return false;
+ }
+
+ m_sampleCounter += m_audioFrameSize / m_audioBlockAlign;
+
+ return true;
}
diff --git a/src/win32/AVIWrite.h b/src/win32/AVIWrite.h
index 74daab98..d4e2146a 100644
--- a/src/win32/AVIWrite.h
+++ b/src/win32/AVIWrite.h
@@ -1,7 +1,5 @@
-// -*- C++ -*-
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
-// Copyright (C) 1999-2003 Forgotten
-// Copyright (C) 2004 Forgotten and the VBA development team
+// Copyright (C) 2007 VBA-M development team
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -17,33 +15,33 @@
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include "stdafx.h"
#include
-class AVIWrite {
- public:
- AVIWrite();
- virtual ~AVIWrite();
- bool Open(const char *filename);
- virtual bool AddFrame(const int number, const char * bmp);
- void SetFPS(int fps);
- void SetVideoFormat(BITMAPINFOHEADER *);
- bool IsSoundAdded();
- void SetSoundFormat(WAVEFORMATEX *);
- bool AddSound(const char *sound, int len);
+// info: recreate the whole AVIWrite object if any method fails
+class AVIWrite
+{
+public:
+ AVIWrite();
+ virtual ~AVIWrite();
- private:
- int m_fps;
- WAVEFORMATEX m_soundFormat;
- BITMAPINFOHEADER m_bitmap;
- AVISTREAMINFO m_header;
- AVISTREAMINFO m_soundHeader;
- PAVIFILE m_file;
- PAVISTREAM m_stream;
- PAVISTREAM m_streamCompressed;
- PAVISTREAM m_streamSound;
- AVICOMPRESSOPTIONS m_options;
- AVICOMPRESSOPTIONS *m_arrayOptions[1];
- int m_samplesSound;
- bool m_failed;
+ bool CreateAVIFile( LPCTSTR filename );
+ bool CreateVideoStream( LONG imageWidth, LONG imageHeight, WORD colorBits, DWORD framesPerSecond );
+ bool CreateAudioStream( WORD channelCount, DWORD sampleRate, WORD sampleBits );
+ bool AddVideoFrame( LPVOID imageData );
+ bool AddAudioFrame( LPVOID soundData );
+
+private:
+ bool m_failed;
+ PAVIFILE m_file;
+ PAVISTREAM m_videoStream;
+ PAVISTREAM m_audioStream;
+ DWORD m_frameRate;
+ LONG m_frameCounter;
+ LONG m_sampleCounter;
+ LONG m_videoFrameSize;
+ LONG m_audioFrameSize;
+ WORD m_audioBlockAlign;
};
diff --git a/src/win32/Display.h b/src/win32/Display.h
index 894623c0..d88e4662 100644
--- a/src/win32/Display.h
+++ b/src/win32/Display.h
@@ -45,6 +45,7 @@ class IDisplay {
virtual int selectFullScreenMode(GUID **) = 0;
};
+
inline void cpyImg32( unsigned char *dst, unsigned int dstPitch, unsigned char *src, unsigned int srcPitch, unsigned short width, unsigned short height )
{
// fast, iterative C version
@@ -59,6 +60,32 @@ inline void cpyImg32( unsigned char *dst, unsigned int dstPitch, unsigned char *
}
}
+
+inline void cpyImg32bmp( unsigned char *dst, unsigned char *src, unsigned int srcPitch, unsigned short width, unsigned short height )
+{
+ // dst will be an upside down bitmap with 24bit colors
+ // pix must contain 32bit colors (XRGB)
+ unsigned short srcLineSize = width<<2;
+ dst += height * width * 3; // move to the last scanline
+ register unsigned char r, g, b;
+
+ while( height-- ) {
+ unsigned short x = width;
+ src += srcLineSize;
+ while( x-- ) {
+ --src; // ignore one of 4 bytes
+ b = *--src;
+ g = *--src;
+ r = *--src;
+ *--dst = b;
+ *--dst = g;
+ *--dst = r;
+ }
+ src += srcPitch;
+ }
+}
+
+
inline void cpyImg16( unsigned char *dst, unsigned int dstPitch, unsigned char *src, unsigned int srcPitch, unsigned short width, unsigned short height )
{
register unsigned short lineSize = width<<1;
@@ -69,3 +96,17 @@ inline void cpyImg16( unsigned char *dst, unsigned int dstPitch, unsigned char *
dst += dstPitch;
}
}
+
+
+inline void cpyImg16bmp( unsigned char *dst, unsigned char *src, unsigned int srcPitch, unsigned short width, unsigned short height )
+{
+ // dst will be an upside down bitmap with 16bit colors
+ register unsigned short lineSize = width<<1;
+ dst += ( height - 1 ) * lineSize; // move to the last scanline
+
+ while( height-- ) {
+ memcpy( dst, src, lineSize );
+ src += srcPitch;
+ dst -= lineSize;
+ }
+}
diff --git a/src/win32/MainWndTools.cpp b/src/win32/MainWndTools.cpp
index 7a96ec11..8f9b2402 100644
--- a/src/win32/MainWndTools.cpp
+++ b/src/win32/MainWndTools.cpp
@@ -42,6 +42,7 @@
#include "../GBA.h"
#include "../Globals.h"
+#include "../Sound.h"
#ifdef _DEBUG
#define new DEBUG_NEW
@@ -341,61 +342,117 @@ void MainWnd::OnUpdateOptionsSoundStoprecording(CCmdUI* pCmdUI)
pCmdUI->Enable(theApp.soundRecording);
}
+
void MainWnd::OnToolsRecordStartavirecording()
{
- theApp.winCheckFullscreen();
- CString captureBuffer;
+ theApp.winCheckFullscreen();
+
+ CString captureBuffer;
+ CString capdir = regQueryStringValue( "aviRecordDir", NULL );
+
+ if( capdir.IsEmpty() ) {
+ capdir = getDirFromFile( theApp.filename );
+ }
+
+ CString filter = theApp.winLoadFilter( IDS_FILTER_AVI );
+ CString title = winResLoadString( IDS_SELECT_AVI_NAME );
+
+ LPCTSTR exts[] = { ".AVI" };
+
+ FileDlg dlg( this, "", filter, 1, "AVI", exts, capdir, title, true );
+
+ if( dlg.DoModal() == IDCANCEL ) {
+ return;
+ }
+
+ captureBuffer = theApp.soundRecordName = dlg.GetPathName();
+ theApp.aviRecordName = captureBuffer;
+ theApp.aviRecording = true;
+
+ if( dlg.m_ofn.nFileOffset > 0 ) {
+ captureBuffer = captureBuffer.Left( dlg.m_ofn.nFileOffset );
+ }
+
+ int len = captureBuffer.GetLength();
+
+ if( ( len > 3 ) && captureBuffer[ len - 1 ] == '\\' ) {
+ captureBuffer = captureBuffer.Left( len - 1 );
+ }
+
+ regSetStringValue( "aviRecordDir", captureBuffer );
- CString capdir = regQueryStringValue("aviRecordDir", NULL);
- if(capdir.IsEmpty())
- capdir = getDirFromFile(theApp.filename);
+ // create AVI file
+ bool ret;
- CString filter = theApp.winLoadFilter(IDS_FILTER_AVI);
- CString title = winResLoadString(IDS_SELECT_AVI_NAME);
+ if( theApp.aviRecorder ) {
+ delete theApp.aviRecorder;
+ theApp.aviRecorder = NULL;
+ }
+ theApp.aviRecorder = new AVIWrite();
- LPCTSTR exts[] = { ".AVI" };
+ // create AVI file
+ ret = theApp.aviRecorder->CreateAVIFile( theApp.aviRecordName );
+ if( !ret ) {
+ systemMessage( IDS_AVI_CANNOT_CREATE_AVI, "Cannot create AVI file." );
+ delete theApp.aviRecorder;
+ theApp.aviRecorder = NULL;
+ theApp.aviRecording = false;
+ return;
+ }
- FileDlg dlg(this, "", filter, 1, "AVI", exts, capdir, title, true);
+ // add video stream
+ ret = theApp.aviRecorder->CreateVideoStream(
+ theApp.sizeX,
+ theApp.sizeY,
+ ( systemColorDepth == 32 ) ? 24 : 16,
+ 60
+ );
+ if( !ret ) {
+ systemMessage( IDS_AVI_CANNOT_CREATE_VIDEO, "Cannot create video stream in AVI file." );
+ delete theApp.aviRecorder;
+ theApp.aviRecorder = NULL;
+ theApp.aviRecording = false;
+ return;
+ }
- if(dlg.DoModal() == IDCANCEL) {
- return;
- }
-
- captureBuffer = theApp.soundRecordName = dlg.GetPathName();
- theApp.aviRecordName = captureBuffer;
- theApp.aviRecording = true;
-
- if(dlg.m_ofn.nFileOffset > 0) {
- captureBuffer = captureBuffer.Left(dlg.m_ofn.nFileOffset);
- }
-
- int len = captureBuffer.GetLength();
-
- if(len > 3 && captureBuffer[len-1] == '\\')
- captureBuffer = captureBuffer.Left(len-1);
-
- regSetStringValue("aviRecordDir", captureBuffer);
+ // add audio stream
+ if( !soundOffFlag ) {
+ ret = theApp.aviRecorder->CreateAudioStream(
+ 2,
+ 44100 / soundQuality,
+ 16
+ );
+ if( !ret ) {
+ systemMessage( IDS_AVI_CANNOT_CREATE_AUDIO, "Cannot create audio stream in AVI file." );
+ delete theApp.aviRecorder;
+ theApp.aviRecorder = NULL;
+ theApp.aviRecording = false;
+ return;
+ }
+ }
}
+
void MainWnd::OnUpdateToolsRecordStartavirecording(CCmdUI* pCmdUI)
{
- pCmdUI->Enable(!theApp.aviRecording);
+ pCmdUI->Enable( !theApp.aviRecording && emulating );
}
+
void MainWnd::OnToolsRecordStopavirecording()
{
- if(theApp.aviRecorder != NULL) {
- delete theApp.aviRecorder;
- theApp.aviRecorder = NULL;
- theApp.aviFrameNumber = 0;
- }
- theApp.aviRecording = false;
+ if( theApp.aviRecorder ) {
+ delete theApp.aviRecorder;
+ theApp.aviRecorder = NULL;
+ }
+ theApp.aviRecording = false;
}
+
void MainWnd::OnUpdateToolsRecordStopavirecording(CCmdUI* pCmdUI)
{
- pCmdUI->Enable(theApp.aviRecording);
+ pCmdUI->Enable( theApp.aviRecording );
}
void MainWnd::OnToolsRecordStartmovierecording()
diff --git a/src/win32/VBA.cpp b/src/win32/VBA.cpp
index 687feaab..4c3d80df 100644
--- a/src/win32/VBA.cpp
+++ b/src/win32/VBA.cpp
@@ -1,6 +1,7 @@
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
// Copyright (C) 1999-2003 Forgotten
// Copyright (C) 2005 Forgotten and the VBA development team
+// Copyright (C) 2007 VBA-M development team
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -316,8 +317,8 @@ VBA::VBA()
sound = NULL;
aviRecording = false;
aviRecorder = NULL;
- aviFrameNumber = 0;
painting = false;
+ skipAudioFrames = 0;
movieRecording = false;
moviePlaying = false;
movieFrame = 0;
@@ -1000,49 +1001,32 @@ void systemDrawScreen()
if (Sm60FPS_CanSkipFrame())
return;
- if(theApp.aviRecording && !theApp.painting) {
- int width = 240;
- int height = 160;
- switch(theApp.cartridgeType) {
- case 0:
- width = 240;
- height = 160;
- break;
- case 1:
- if(gbBorderOn) {
- width = 256;
- height = 224;
- } else {
- width = 160;
- height = 144;
- }
- break;
- }
-
- if(theApp.aviRecorder == NULL) {
- theApp.aviRecorder = new AVIWrite();
- theApp.aviFrameNumber = 0;
-
- theApp.aviRecorder->SetFPS(60);
-
- BITMAPINFOHEADER bi;
- memset(&bi, 0, sizeof(bi));
- bi.biSize = 0x28;
- bi.biPlanes = 1;
- bi.biBitCount = 24;
- bi.biWidth = width;
- bi.biHeight = height;
- bi.biSizeImage = 3*width*height;
- theApp.aviRecorder->SetVideoFormat(&bi);
- theApp.aviRecorder->Open(theApp.aviRecordName);
- }
-
- char *bmp = new char[width*height*3];
-
- utilWriteBMP(bmp, width, height, pix);
- theApp.aviRecorder->AddFrame(theApp.aviFrameNumber, bmp);
-
- delete bmp;
+ if( theApp.aviRecording ) {
+ if( theApp.painting ) {
+ theApp.skipAudioFrames++;
+ } else {
+ unsigned char *bmp;
+ unsigned short srcPitch = theApp.sizeX * ( systemColorDepth >> 3 ) + 4;
+ switch( systemColorDepth )
+ {
+ case 16:
+ bmp = new unsigned char[ theApp.sizeX * theApp.sizeY * 2 ];
+ cpyImg16bmp( bmp, pix + srcPitch, srcPitch, theApp.sizeX, theApp.sizeY );
+ break;
+ case 32:
+ // use 24 bit colors to reduce video size
+ bmp = new unsigned char[ theApp.sizeX * theApp.sizeY * 3 ];
+ cpyImg32bmp( bmp, pix + srcPitch, srcPitch, theApp.sizeX, theApp.sizeY );
+ break;
+ }
+ if( false == theApp.aviRecorder->AddVideoFrame( bmp ) ) {
+ systemMessage( IDS_AVI_CANNOT_WRITE_VIDEO, "Cannot write video frame to AVI file." );
+ delete theApp.aviRecorder;
+ theApp.aviRecorder = NULL;
+ theApp.aviRecording = false;
+ }
+ delete bmp;
+ }
}
if( theApp.ifbFunction ) {
@@ -1115,14 +1099,15 @@ void systemShowSpeed(int speed)
}
}
+
void systemFrame()
{
- if(theApp.aviRecording)
- theApp.aviFrameNumber++;
- if(theApp.movieRecording || theApp.moviePlaying)
- theApp.movieFrame++;
+ if( theApp.movieRecording || theApp.moviePlaying ) {
+ theApp.movieFrame++;
+ }
}
+
void system10Frames(int rate)
{
u32 time = systemGetClock();
@@ -1220,17 +1205,17 @@ void systemSoundShutdown()
if( theApp.aviRecorder ) {
delete theApp.aviRecorder;
theApp.aviRecorder = NULL;
- theApp.aviFrameNumber = 0;
}
+ theApp.aviRecording = false;
- if( theApp.soundRecording ) {
- if( theApp.soundRecorder ) {
- delete theApp.soundRecorder;
- theApp.soundRecorder = NULL;
- }
- theApp.soundRecording = false;
+
+ if( theApp.soundRecorder ) {
+ delete theApp.soundRecorder;
+ theApp.soundRecorder = NULL;
}
+ theApp.soundRecording = false;
+
if( theApp.sound ) {
delete theApp.sound;
theApp.sound = NULL;
@@ -1278,18 +1263,16 @@ void systemWriteDataToSoundBuffer()
}
if( theApp.aviRecording && theApp.aviRecorder ) {
- if( !theApp.aviRecorder->IsSoundAdded() ) {
- WAVEFORMATEX format;
- format.cbSize = 0;
- format.wFormatTag = WAVE_FORMAT_PCM;
- format.nChannels = 2;
- format.nSamplesPerSec = 44100 / soundQuality;
- format.wBitsPerSample = 16;
- format.nBlockAlign = format.nChannels * ( format.wBitsPerSample >> 3 );
- format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
- theApp.aviRecorder->SetSoundFormat( &format );
+ if( theApp.skipAudioFrames ) {
+ theApp.skipAudioFrames--;
+ } else {
+ if( false == theApp.aviRecorder->AddAudioFrame( soundFinalWave ) ) {
+ systemMessage( IDS_AVI_CANNOT_WRITE_AUDIO, "Cannot write audio frame to AVI file." );
+ delete theApp.aviRecorder;
+ theApp.aviRecorder = NULL;
+ theApp.aviRecording = false;
+ }
}
- theApp.aviRecorder->AddSound( (const char *)soundFinalWave, soundBufferLen );
}
if( theApp.sound ) {
diff --git a/src/win32/VBA.h b/src/win32/VBA.h
index 489924bd..0e975e22 100644
--- a/src/win32/VBA.h
+++ b/src/win32/VBA.h
@@ -193,8 +193,8 @@ class VBA : public CWinApp
bool aviRecording;
AVIWrite *aviRecorder;
CString aviRecordName;
- int aviFrameNumber;
bool painting;
+ unsigned int skipAudioFrames;
bool movieRecording;
bool moviePlaying;
int movieFrame;
diff --git a/src/win32/VBA.rc b/src/win32/VBA.rc
index 95cf0141..254775ae 100644
--- a/src/win32/VBA.rc
+++ b/src/win32/VBA.rc
@@ -2203,8 +2203,17 @@ BEGIN
"Invalid rewind interval value. Please enter a number between 0 and 600 seconds."
IDS_REGISTRY "VisualBoyAdvance no longer uses the registry to store its settings. Your previous settings have been exported into the file: %s"
IDS_MOVIE_PLAY "Playing a movie will load a save state which may erase your previous battery saves. Please be sure to have a saved state if you don't want to loose any previous data."
+END
+
+STRINGTABLE
+BEGIN
IDS_OAL_NODEVICE "There are no sound devices present on this system."
IDS_OAL_NODLL "OpenAL32.dll could not be found on your system. Please install the runtime from http://openal.org"
+ IDS_AVI_CANNOT_CREATE_AVI "Cannot create AVI file."
+ IDS_AVI_CANNOT_CREATE_VIDEO "Cannot create video stream in AVI file."
+ IDS_AVI_CANNOT_CREATE_AUDIO "Cannot create audio stream in AVI file."
+ IDS_AVI_CANNOT_WRITE_VIDEO "Cannot write video frame to AVI file."
+ IDS_AVI_CANNOT_WRITE_AUDIO "Cannot write audio frame to AVI file."
END
#endif // English (U.S.) resources
diff --git a/src/win32/resource.h b/src/win32/resource.h
index 02b4dd89..aa22cfc9 100644
--- a/src/win32/resource.h
+++ b/src/win32/resource.h
@@ -380,9 +380,7 @@
#define IDC_SAVE_OBJ 1138
#define IDC_MAP_VIEW_ZOOM 1138
#define IDS_MOVIE_PLAY 1138
-#define IDS_OAL_NODEVICE 1139
#define IDC_VIEWER 1140
-#define IDS_OAL_NODLL 1140
#define IDC_ADDRESSES 1141
#define IDC_GO 1143
#define IDC_8_BIT 1144
@@ -514,6 +512,13 @@
#define IDC_DEVICE 1269
#define IDC_SLIDER_BUFFERCOUNT 1270
#define IDC_BUFFERINFO 1271
+#define IDS_OAL_NODEVICE 2000
+#define IDS_OAL_NODLL 2001
+#define IDS_AVI_CANNOT_CREATE_AVI 2002
+#define IDS_AVI_CANNOT_CREATE_VIDEO 2003
+#define IDS_AVI_CANNOT_CREATE_AUDIO 2004
+#define IDS_AVI_CANNOT_WRITE_VIDEO 2005
+#define IDS_AVI_CANNOT_WRITE_AUDIO 2006
#define ID_HELP_ABOUT 40001
#define ID_FILE_EXIT 40002
#define ID_OPTIONS_VIDEO_FRAMESKIP_0 40003