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