/* * vsdl.cxx * * Classes to support video output via SDL * * Portable Windows Library * * Copyright (c) 1993-2000 Equivalence Pty. Ltd. * * The contents of this file are subject to the Mozilla Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is Portable Windows Library. * * The Initial Developer of the Original Code is Equivalence Pty. Ltd. * * Contributor(s): ______________________________________. * * $Log: vsdl.cxx,v $ * Revision 1.14 2005/08/09 09:08:11 rjongbloed * Merged new video code from branch back to the trunk. * * Revision 1.13.12.4 2005/08/04 08:21:58 dsandras * Added static plugin flag. * * Revision 1.13.12.3 2005/07/26 17:07:03 dsandras * Fix to make gcc happy. * * Revision 1.13.12.2 2005/07/17 12:58:15 rjongbloed * Sorted out the ordering or Red. Blue, Cr and Cb in RGB/BGR/YUV420 formats * * Revision 1.13.12.1 2005/07/17 09:27:07 rjongbloed * Major revisions of the PWLib video subsystem including: * removal of F suffix on colour formats for vertical flipping, all done with existing bool * working through use of RGB and BGR formats so now consistent * cleaning up the plug in system to use virtuals instead of pointers to functions. * rewrite of SDL to be a plug in compatible video output device. * extensive enhancement of video test program * * Revision 1.13 2004/04/09 06:52:17 rjongbloed * Removed #pargma linker command for /delayload of DLL as documentations sais that * you cannot do this. * * Revision 1.12 2004/02/23 23:52:20 csoutheren * Added pragmas to avoid every Windows application needing to include libs explicitly * * Revision 1.11 2003/12/12 05:11:56 rogerhardiman * Add SDL support on FreeBSD. Header files live in SDL11 directory * * Revision 1.10 2003/11/06 09:13:20 rjongbloed * Improved the Windows configure system to allow multiple defines based on file existence. Needed for SDL support of two different distros. * * Revision 1.9 2003/07/22 22:55:20 dereksmithies * Add memory allocation feature. * * Revision 1.8 2003/05/21 03:59:10 dereksmithies * Fix close down bug. * * Revision 1.7 2003/05/17 03:21:26 rjongbloed * Removed need to do strange things with main() function. * * Revision 1.6 2003/05/14 02:34:53 dereksmithies * Make SDL display work if only one of two display areas in use. * * Revision 1.5 2003/05/07 02:40:58 dereks * Fix to allow it to exit when the ::Terminate method called. * * Revision 1.4 2003/04/28 14:30:02 craigs * Started rearranging code * * Revision 1.3 2003/04/28 08:33:00 craigs * Linux SDL includes are in a SDL directory, but Windows is not * * Revision 1.2 2003/04/28 07:27:15 craigs * Added missed functions * * Revision 1.1 2003/04/28 07:03:55 craigs * Initial version from ohphone * */ #ifdef __GNUC__ #pragma implementation "vsdl.h" #endif #define P_FORCE_STATIC_PLUGIN #include #include #include #define new PNEW #if P_SDL extern "C" { #include }; #ifdef _MSC_VER #pragma comment(lib, P_SDL_LIBRARY) #endif class PVideoOutputDevice_SDL_PluginServiceDescriptor : public PDevicePluginServiceDescriptor { public: virtual PObject * CreateInstance(int /*userData*/) const { return new PVideoOutputDevice_SDL; } virtual PStringList GetDeviceNames(int /*userData*/) const { return PStringList("SDL"); } virtual bool ValidateDeviceName(const PString & deviceName, int /*userData*/) const { return deviceName.Find("SDL") == 0; } } PVideoOutputDevice_SDL_descriptor; PCREATE_PLUGIN(SDL, PVideoOutputDevice, &PVideoOutputDevice_SDL_descriptor); /////////////////////////////////////////////////////////////////////// PVideoOutputDevice_SDL::PVideoOutputDevice_SDL() { colourFormat = "YUV420P"; sdlThread = NULL; updateOverlay = false; screen = NULL; overlay = NULL; } PVideoOutputDevice_SDL::~PVideoOutputDevice_SDL() { Close(); } PStringList PVideoOutputDevice_SDL::GetDeviceNames() const { return PStringList("SDL"); } BOOL PVideoOutputDevice_SDL::Open(const PString & name, BOOL /*startImmediate*/) { Close(); deviceName = name; sdlThread = PThread::Create(PCREATE_NOTIFIER(SDLThreadMain), 0, PThread::NoAutoDeleteThread, PThread::LowPriority, "SDL:%x"); sdlStarted.Wait(); return screen != NULL; } BOOL PVideoOutputDevice_SDL::IsOpen() { return screen != NULL && overlay != NULL; } BOOL PVideoOutputDevice_SDL::Close() { if (IsOpen()) { sdlStop.Signal(); sdlThread->WaitForTermination(1000); delete sdlThread; } return TRUE; } BOOL PVideoOutputDevice_SDL::SetColourFormat(const PString & colourFormat) { if (colourFormat *= "YUV420P") return PVideoOutputDevice::SetColourFormat(colourFormat); return FALSE; } BOOL PVideoOutputDevice_SDL::SetFrameSize(unsigned width, unsigned height) { { PWaitAndSignal m(mutex); if (width == frameWidth && height == frameHeight) return TRUE; if (!PVideoOutputDevice::SetFrameSize(width, height)) return FALSE; } adjustSize.Signal(); return IsOpen(); } PINDEX PVideoOutputDevice_SDL::GetMaxFrameBytes() { PWaitAndSignal m(mutex); return GetMaxFrameBytesConverted(CalculateFrameBytes(frameWidth, frameHeight, colourFormat)); } BOOL PVideoOutputDevice_SDL::SetFrameData(unsigned x, unsigned y, unsigned width, unsigned height, const BYTE * data, BOOL endFrame) { PWaitAndSignal m(mutex); if (!IsOpen()) return FALSE; if (x != 0 || y != 0 || width != frameWidth || height != frameHeight || !endFrame) return FALSE; ::SDL_LockYUVOverlay(overlay); PAssert(frameWidth == (unsigned)overlay->w && frameHeight == (unsigned)overlay->h, PLogicError); PINDEX pixelsFrame = frameWidth * frameHeight; PINDEX pixelsQuartFrame = pixelsFrame >> 2; const BYTE * dataPtr = data; PBYTEArray tempStore; if (converter != NULL) { converter->Convert(data, tempStore.GetPointer(pixelsFrame+2*pixelsQuartFrame)); dataPtr = tempStore; } memcpy(overlay->pixels[0], dataPtr, pixelsFrame); memcpy(overlay->pixels[1], dataPtr + pixelsFrame, pixelsQuartFrame); memcpy(overlay->pixels[2], dataPtr + pixelsFrame + pixelsQuartFrame, pixelsQuartFrame); ::SDL_UnlockYUVOverlay(overlay); updateOverlay = true; return TRUE; } bool PVideoOutputDevice_SDL::InitialiseSDL() { // initialise the SDL library if (::SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE) < 0 ) { PTRACE(1, "Couldn't initialize SDL: " << ::SDL_GetError()); return false; } #ifdef _WIN32 SDL_SetModuleHandle(GetModuleHandle(NULL)); #endif screen = ::SDL_SetVideoMode(frameWidth, frameHeight, 0, SDL_SWSURFACE /* | SDL_RESIZABLE */); if (screen == NULL) { PTRACE(1, "Couldn't create SDL screen: " << ::SDL_GetError()); return false; } overlay = ::SDL_CreateYUVOverlay(frameWidth, frameHeight, SDL_IYUV_OVERLAY, screen); if (overlay == NULL) { PTRACE(1, "Couldn't create SDL overlay: " << ::SDL_GetError()); return false; } return true; } bool PVideoOutputDevice_SDL::ProcessSDLEvents() { if (screen == NULL || overlay == NULL) { PTRACE(6, "PSDL\t Screen and/or overlay not open, so dont process events"); return false; } SDL_Event event; while (::SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT : //User selected cross PTRACE(3, "PSDL\t user selected cross on window, close window"); return false; case SDL_VIDEORESIZE : PTRACE(3, "PSDL\t Resize window to " << event.resize.w << " x " << event.resize.h); } } return true; } void PVideoOutputDevice_SDL::SDLThreadMain(PThread &, INT) { InitialiseSDL(); sdlStarted.Signal(); PTRACE(3, "PSDL\tMain loop is underway, with SDL screen initialised"); while (ProcessSDLEvents()) { if (sdlStop.Wait(0)) break; PWaitAndSignal m(mutex); if (adjustSize.Wait(0)) { ::SDL_FreeYUVOverlay(overlay); overlay = NULL; screen = ::SDL_SetVideoMode(frameWidth, frameHeight, 0, SDL_SWSURFACE /* | SDL_RESIZABLE */); if (screen != NULL) overlay = ::SDL_CreateYUVOverlay(frameWidth, frameHeight, SDL_IYUV_OVERLAY, screen); adjustSize.Acknowledge(); } if (updateOverlay) { SDL_Rect rect; rect.x = 0; rect.y = 0; rect.w = (Uint16)frameWidth; rect.h = (Uint16)frameHeight; ::SDL_DisplayYUVOverlay(overlay, &rect); updateOverlay = true; } } if (overlay != NULL) { ::SDL_FreeYUVOverlay(overlay); overlay = NULL; } if (screen != NULL) { ::SDL_FreeSurface(screen); screen = NULL; } ::SDL_Quit(); sdlStop.Acknowledge(); PTRACE(3, "PSDL\tEnd of sdl display loop"); } #endif // P_SDL // End of file ////////////////////////////////////////////////////////////////