Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

win32.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2002 Xavier Trochu
00003 
00004 This software is provided 'as-is', without any express or implied warranty. In no event
00005 will the authors be held liable for any damages arising from the use of this software.
00006 
00007 Permission is granted to anyone to use this software for any purpose, including commercial
00008 applications, and to alter it and redistribute it freely, subject to the following
00009 restrictions:
00010 
00011 1. The origin of this software must not be misrepresented; you must not claim that you
00012    wrote the original software. If you use this software in a product, an acknowledgment
00013    in the product documentation would be appreciated but is not required.
00014 
00015 2. Altered source versions must be plainly marked as such, and must not be misrepresented 
00016    as being the original software.
00017 
00018 3. This notice may not be removed or altered from any source distribution.
00019 */
00020 #include "win32.h"
00021 #include <sstream>
00022 #include <iomanip>
00023 #include <fstream>
00024 #include <stdexcept>
00025 #include <cstring>
00026 #include <mmsystem.h>
00027 #include <dsound.h>
00028 #ifdef DEBUG_WIN32
00029 #include <iostream>
00030 #endif
00031 
00032 
00033 using namespace std;
00034 
00035 
00036 const GUID GUID_NULL = {0};
00045 class ds_wave_out : public sound_renderer {
00046 private:
00047     IDirectSound8 * _ds;
00048     IDirectSoundBuffer8 * _dsb;
00049     int _writepos;
00050     int _oldwritepos;
00051     //~ int _totalwrite;
00052     //~ int _totalwritecall;
00053     int _size;
00054     bool _started;
00055 public:
00056     ds_wave_out() : _ds(0), _dsb(0), _started(false) {};
00057     virtual ~ds_wave_out() {
00058         if(_dsb) { _dsb->Release(); _dsb = 0; }
00059         if(_ds) { _ds->Release(); _ds = 0; }
00060         //~ if(_totalwritecall)
00061             //~ cerr << "DirectX Sound playback : _totalwrite == " << _totalwrite << ", _totalwritecall == " << _totalwritecall << ", " << ((double)_totalwrite) / _totalwritecall << endl;
00062     }
00063     bool init(int frequency, bool stereo) {
00064         HRESULT hr = DirectSoundCreate8(&DSDEVID_DefaultPlayback, &_ds, NULL);
00065         if(FAILED(hr)) throw runtime_error("DirectSoundCreate8() failed");
00066         hr = _ds->SetCooperativeLevel(GetForegroundWindow(), DSSCL_NORMAL);
00067         if(FAILED(hr)) throw runtime_error("SetCooperativeLevel() failed");
00068         WAVEFORMATEX wf;
00069         wf.wBitsPerSample = 16;
00070         wf.nChannels = stereo ? 2 : 1;
00071         wf.nSamplesPerSec = frequency;
00072         wf.nBlockAlign = wf.nChannels * wf.wBitsPerSample / 8;
00073         wf.wFormatTag = WAVE_FORMAT_PCM;
00074         wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;
00075         wf.cbSize =0;
00076         
00077         _size =  wf.nAvgBytesPerSec * 5;
00078         _writepos = 0;
00079         _oldwritepos = 0;
00080         //~ _totalwrite = 0;
00081         //~ _totalwritecall = 0;
00082         DSBUFFERDESC desc;
00083         desc.dwSize = sizeof(desc);
00084         desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_GLOBALFOCUS|DSBCAPS_STICKYFOCUS;
00085         desc.dwBufferBytes = _size; // 5 second of playback...
00086         desc.dwReserved = 0;
00087         desc.lpwfxFormat = &wf;
00088         desc.guid3DAlgorithm = GUID_NULL;
00089         hr = _ds->CreateSoundBuffer(&desc, (IDirectSoundBuffer**)&_dsb, NULL);
00090         if(FAILED(hr)) throw runtime_error("CreateSoundBuffer() failed");
00091         
00092         return true;
00093     }
00094     bool write(unsigned short * ptr, int size) {
00095         assert(_dsb && _ds);
00096         assert(size && (size < _size) && ((size % 4) == 0));
00097 
00098         unsigned short * ptr1, *ptr2;
00099         DWORD size1, size2;
00100         //~ _totalwritecall++;
00101         //~ _totalwrite += size;
00102         //~ size *= sizeof(unsigned short);
00103         _dsb->GetCurrentPosition(&size1, &size2);
00104 #ifdef DEBUG_WIN32
00105         cout << "ds_wave_out::write() == " << _writepos << ", " << size << ", " << _writepos + size << endl;
00106         cout << "DirectSoundBuffer8->GetCurrentPosition() == " << size1 << ", " << size2 << endl;
00107 #endif
00108         HRESULT hr = _dsb->Lock(_writepos, size, (void**)&ptr1, &size1, (void**)&ptr2, &size2, 0);
00109         if(SUCCEEDED(hr)) {
00110             memcpy(ptr1, ptr, size1);
00111             if(size2) memcpy(ptr2, reinterpret_cast<char*>(ptr)+size1, size2);
00112             _dsb->Unlock((void*)ptr1, size1, (void*)ptr2, size2);
00113         } else {
00114             ostringstream oss;
00115             oss << "_dsb->Lock() failed : 0x" << hex << hr  << " == " << DSERR_INVALIDPARAM << endl;
00116             throw runtime_error(oss.str());
00117         }
00118         if(!_started) { 
00119 #ifdef DEBUG_WIN32
00120             cout << "Starting DirectX Sound playback" << endl;
00121 #endif
00122             _dsb->Play(0, 0, DSBPLAY_LOOPING); 
00123             _started = true; 
00124         }
00125         _oldwritepos = _writepos;
00126         _writepos += size;
00127         if(_writepos >= _size) _writepos -= _size;
00128         
00129         return true;
00130     }
00131     bool wait() {
00132         assert(_dsb && _ds);
00133         if(!_started) return false;
00134         DWORD play;
00135         while(1) {
00136             HRESULT hr = _dsb->GetCurrentPosition(&play, NULL);
00137             if(FAILED(hr)) return false;
00138             if(_writepos < _oldwritepos && (play > _oldwritepos || play < _writepos)) return true;
00139             if(_writepos > _oldwritepos && play > _oldwritepos && play < _writepos) return true;
00140             //~ if(play >= _oldwritepos && play < _writepos) return true;
00141             //~ if(ret) cout << "ds_wave_out::wait() _writepos == " << _writepos << ", _oldwritepos == " << _oldwritepos << ", play == " << play << endl;
00142         }
00143     }
00144     bool stop() {
00145         const int SILENCE_SIZE = 2205*4; // 1 tenth of a second of silence, please...
00146         assert(_dsb && _ds);
00147         if(!_started) return true;
00148         // First we put some silence...
00149         unsigned short * ptr1, *ptr2;
00150         DWORD size1, size2;
00151         HRESULT hr = _dsb->Lock(_writepos, SILENCE_SIZE, (void**)&ptr1, &size1, (void**)&ptr2, &size2, 0);
00152         if(SUCCEEDED(hr)) {
00153             memset(ptr1, 0, size1);
00154             if(size2) memset(ptr2, 0, size2);
00155             _dsb->Unlock((void*)ptr1, size1, (void*)ptr2, size2);
00156         } else {
00157             throw runtime_error("_dsb->Lock() failed");
00158         }
00159 //      _oldwritepos = _writepos;
00160 //      _writepos = (_writepos + SILENCE_SIZE) % _size;
00161         //~ cerr << "_oldwritepos == " << _oldwritepos << ", _writepos == " << _writepos << endl;
00162         // Then we wait for the silence to be reached
00163         if(_writepos + SILENCE_SIZE > _size)
00164             _writepos = 0;
00165         while(1) {
00166             DWORD play;
00167             _dsb->GetCurrentPosition(&play, NULL);
00168             if(play > _writepos) {
00169                 _dsb->Stop();
00170                 _started = false;
00171                 return true;
00172             }
00173         }
00174         return true;
00175     }
00176 };
00177 
00178 
00179 bitmap_renderer::bitmap_renderer() throw(exception) : _padding(0) {
00180     _bmi = reinterpret_cast<BITMAPINFO *>(new char[HEADER_SIZE]);
00181     if(!_bmi) throw runtime_error("could not allocate bitmap header");
00182     _bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
00183     _bmi->bmiHeader.biWidth = 0;
00184     _bmi->bmiHeader.biHeight = 0;
00185     _bmi->bmiHeader.biPlanes = 1;
00186     _bmi->bmiHeader.biBitCount = 8;
00187     _bmi->bmiHeader.biCompression = BI_RGB;
00188     _bmi->bmiHeader.biSizeImage = 0;
00189     _bmi->bmiHeader.biXPelsPerMeter = 300;
00190     _bmi->bmiHeader.biYPelsPerMeter = 300;
00191     _bmi->bmiHeader.biClrUsed = 256;
00192     _bmi->bmiHeader.biClrImportant = 0;
00193     for(int i = 0; i < 256; i++)
00194     {
00195         _bmi->bmiColors[i].rgbBlue = 0;
00196         _bmi->bmiColors[i].rgbGreen = 0;
00197         _bmi->bmiColors[i].rgbRed = 0;
00198         _bmi->bmiColors[i].rgbReserved = 0;
00199     }
00200 }
00201 
00202 bitmap_renderer::~bitmap_renderer() throw() {
00203     delete[] reinterpret_cast<char *>(_bmi);
00204 }
00205 
00206 bool bitmap_renderer::init_frame(const point &p) throw(exception) {
00207     _bmi->bmiHeader.biWidth = p.get_x();
00208     _bmi->bmiHeader.biHeight = p.get_y();
00209     _padding = p.get_x();
00210     if(_padding & 3) {
00211         _padding = ((_padding >> 2) + 1) << 2;
00212     }
00213     _padding -= p.get_x();
00214     return base_renderer::init_frame(p);
00215 }
00216 
00217 bool bitmap_renderer::set_palette(const palette & p) throw() {
00218     base_renderer::set_palette(p);
00219     for(int i = 0; i < 256; i++)
00220     {
00221         _bmi->bmiColors[i].rgbRed = pal()[i].red();
00222         _bmi->bmiColors[i].rgbGreen = pal()[i].green();
00223         _bmi->bmiColors[i].rgbBlue = pal()[i].blue();
00224     }
00225     return true;
00226 }
00227 
00228 void bitmap_renderer::save(int frame) throw(exception) {
00229     int oldframe = get_frame();
00230     if(frame == -1) frame = get_frame();
00231     else set_frame(frame);
00232     //~ cerr << "bitmap_renderer::save(" << frame << ")" << endl;
00233     int real_width = get_width()+_padding;
00234     char * bitmap = new char[get_height() * real_width];
00235     if(!bitmap) throw runtime_error("could not allocate bitmap buffer");
00236     for(int i = 0; i < get_height(); i++) {
00237         memcpy(bitmap + i * real_width, data() + (get_height()-1-i)*get_width(), get_width());
00238     }
00239     dump(bitmap, get_height() * real_width);
00240     delete []bitmap;
00241     set_frame(oldframe);
00242 }
00243 
00244 bitmap_file_renderer::bitmap_file_renderer(const string & name) throw() : _name(name) {
00245     _bfi.bfType = 'MB';
00246     _bfi.bfSize = HEADER_SIZE + sizeof(_bfi);
00247     _bfi.bfReserved1 = 0;
00248     _bfi.bfReserved2 = 0;
00249     _bfi.bfOffBits = HEADER_SIZE + sizeof(_bfi);
00250 }
00251 
00252 bool bitmap_file_renderer::save_current() throw()
00253 {
00254 static int _current = 10000;
00255     save(_current++);
00256     return true;
00257 }
00258 
00259 bool bitmap_file_renderer::init_frame(const point &p) throw() {
00260     int padding = p.get_x();
00261     if(padding & 3) {
00262         padding = ((padding >> 2) + 1) << 2;
00263     }
00264     _bfi.bfSize = padding * p.get_y() + HEADER_SIZE + sizeof(_bfi);
00265     return bitmap_renderer::init_frame(p);
00266 }
00267 
00268 void bitmap_file_renderer::dump(char * data, int size) throw(exception) {
00269     ostringstream oss;
00270     oss << _name << setw(5) << setfill('0') << get_frame() << setw(0) << ".bmp";
00271     ofstream ofs;
00272     ofs.open(oss.str().c_str(), ios::binary);
00273     ofs.write(reinterpret_cast<const char *>(&_bfi), sizeof(_bfi));
00274     ofs.write(reinterpret_cast<const char *>(get_bmi()), HEADER_SIZE);
00275     ofs.write(data, size);
00276 }
00277 
00278 LRESULT WINAPI window_renderer::windowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
00279 {
00280     switch(uMsg) {
00281     case WM_USER:
00282         DestroyWindow(hwnd);
00283         break;
00284     case WM_USER+1:
00285         {
00286             window_renderer * wr = reinterpret_cast<window_renderer *>(GetWindowLong(hwnd, 0));
00287             SetEvent(wr->_hEvent);
00288         } break;
00289     case WM_DESTROY:
00290         PostQuitMessage(0);
00291         break;
00292     case WM_CREATE:
00293         {
00294             LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
00295             SetWindowLong(hwnd, 0, reinterpret_cast<LONG>(lpcs->lpCreateParams));
00296             PostMessage(hwnd, WM_USER+1, 0, 0);
00297         } break;
00298     case WM_PAINT:
00299         {
00300             PAINTSTRUCT ps;
00301             window_renderer * wr = reinterpret_cast<window_renderer *>(GetWindowLong(hwnd, 0));
00302             HDC hdc = BeginPaint(hwnd, &ps);
00303             WaitForSingleObject(wr->_hMutex, INFINITE);
00304             SetDIBitsToDevice(hdc, 
00305                 0, 0, 
00306                 wr->get_bmi()->bmiHeader.biWidth, abs(wr->get_bmi()->bmiHeader.biHeight), 
00307                 0, 0,
00308                 0, abs(wr->get_bmi()->bmiHeader.biHeight),
00309                 wr->_bitmap, wr->get_bmi(), DIB_RGB_COLORS);
00310             ReleaseMutex(wr->_hMutex);
00311             EndPaint(hwnd, &ps);
00312         } break;
00313     }
00314     return DefWindowProc(hwnd, uMsg, wParam, lParam);
00315 }
00316 
00317 DWORD CALLBACK window_renderer::threadProc(void * wnd)
00318 {
00319     WNDCLASS wc;
00320     wc.style = 0;
00321     wc.lpfnWndProc = windowProc;
00322     wc.cbClsExtra = 0;
00323     wc.cbWndExtra = 4;
00324     wc.hInstance = NULL;
00325     wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
00326     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
00327     wc.hbrBackground = NULL;
00328     wc.lpszMenuName = NULL;
00329     wc.lpszClassName = "myclassname";
00330     RegisterClass(&wc);
00331     HWND hwnd;
00332     reinterpret_cast<window_renderer *>(wnd)->_hwnd = hwnd = CreateWindow("myclassname", "SMUSH Viewer", WS_POPUPWINDOW | WS_CAPTION, 
00333         CW_USEDEFAULT, CW_USEDEFAULT, 
00334         CW_USEDEFAULT, CW_USEDEFAULT, 
00335         NULL, NULL, NULL, wnd);
00336     ShowWindow(hwnd, SW_SHOW);
00337     UpdateWindow(hwnd);
00338     MSG msg;
00339     while(GetMessage(&msg, NULL, 0, 0)) {
00340         TranslateMessage(&msg);
00341         DispatchMessage(&msg);
00342     }
00343     return 0;
00344 }
00345 
00346 window_renderer::window_renderer() throw(exception) : 
00347     _bitmap(0), _size(0), _clock(0), _out(0) {
00348     _hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
00349     _hMutex = CreateMutex(NULL, FALSE, NULL);
00350     _hThread = CreateThread(NULL, 0, threadProc, this, 0, NULL);
00351     WaitForSingleObject(_hEvent, INFINITE);
00352 }
00353 
00354 window_renderer::~window_renderer() throw() {
00355     if(_out) _out->stop();
00356     PostMessage(_hwnd, WM_USER, 0, 0);
00357     WaitForSingleObject(_hThread, INFINITE);
00358     CloseHandle(_hThread);
00359     CloseHandle(_hMutex);
00360     CloseHandle(_hEvent);
00361     clean();
00362     if(_out) delete _out;
00363 }
00364 
00365 bool window_renderer::init_frame(const point & p) throw(exception) {
00366     SetWindowPos(_hwnd, NULL, 0, 0, 
00367         p.get_x() + 2*GetSystemMetrics(SM_CXFIXEDFRAME), 
00368         p.get_y() + 2*GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION), 
00369         SWP_NOMOVE|SWP_NOZORDER);
00370     return bitmap_renderer::init_frame(p);
00371 }
00372 void window_renderer::dump(char * data, int size) throw(exception) {
00373     ostringstream oss;
00374     oss << "SMUSH Viewer : " << get_filename() << " : " << get_frame() + 1 << "/" << get_nbframes();
00375     SetWindowText(_hwnd, oss.str().c_str());
00376     WaitForSingleObject(_hMutex, INFINITE);
00377     if((!_bitmap) || (_size != size)) {
00378         clean();
00379         _bitmap = new char[size];
00380         _size = size;
00381     }
00382     if(!_bitmap) {
00383         throw runtime_error("window_renderer unable to allocate frame buffer");
00384     }
00385     memcpy(_bitmap, data, size);
00386     ReleaseMutex(_hMutex);
00387     InvalidateRect(_hwnd, NULL, FALSE);
00388 }
00389 
00390 void window_renderer::clean() throw() {
00391     if(_bitmap) {
00392         delete []_bitmap;
00393         _bitmap = 0;
00394     }
00395 }
00396 
00397 bool window_renderer::wait(int ms) throw() {
00398     int old = _clock;
00399     _clock = GetTickCount();
00400     if(_out && _out->wait()) return true;
00401     if(!old) return true;
00402     old += ms;
00403     while(_clock < old) {
00404         //~ if((old - _clock) > 2)
00405             //~ Sleep(1);
00406         _clock = GetTickCount();
00407         if(_out && _out->wait()) return true;
00408     }
00409     return true;
00410 }
00411 
00412 sound_renderer * window_renderer::get_sound_renderer() throw(exception)
00413 {
00414     if(! _out) _out = new ds_wave_out;
00415     return _out;
00416 }
00417 
00418 bool win32_save_as_wave(const string & fname, char * data, int size, int freq)
00419 {
00420     HMMIO       hmmio;              // file handle for open file 
00421     MMCKINFO    mmckinfoParent;     // parent chunk information 
00422     MMCKINFO    mmckinfoSubchunk;   // subchunk information structure 
00423     
00424     WAVEFORMATEX wf;
00425     wf.wBitsPerSample = 8;
00426     wf.nChannels = 1;
00427     wf.nSamplesPerSec = freq;
00428     wf.nBlockAlign = wf.nChannels * wf.wBitsPerSample / 8;
00429     wf.wFormatTag = WAVE_FORMAT_PCM;
00430     wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;
00431     wf.cbSize =0;
00432     
00433     hmmio = mmioOpen(const_cast<char*>(fname.c_str()), NULL, MMIO_CREATE | MMIO_WRITE | MMIO_ALLOCBUF);
00434     mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E'); 
00435     mmioCreateChunk(hmmio, &mmckinfoParent, MMIO_CREATERIFF);
00436     mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' '); 
00437     mmioCreateChunk(hmmio, &mmckinfoSubchunk, 0);
00438     mmioWrite(hmmio, reinterpret_cast<char*>(&wf), sizeof(wf));
00439     mmioAscend(hmmio, &mmckinfoSubchunk, 0);
00440     mmckinfoSubchunk.ckid = mmioFOURCC('d', 'a', 't', 'a'); 
00441     mmioCreateChunk(hmmio, &mmckinfoSubchunk, 0);
00442     mmioWrite(hmmio, data, size);
00443     mmioAscend(hmmio, &mmckinfoSubchunk, 0);
00444     mmioAscend(hmmio, &mmckinfoParent, 0);
00445     mmioClose(hmmio, 0); 
00446     
00447     return true;
00448 }

Generated on Fri Aug 9 22:54:30 2002 for san_player by doxygen1.2.16