Fixed DevStudio 2003 build with memory check code.
[pwlib.git] / src / ptlib / unix / shmvideo.cxx
blobade33d0211af0954b1d2ab4ab3445fbec2868cf2
1 /*
2 * shmvideo.cxx
4 * This file contains the class hierarchy for both shared memory video
5 * input and output devices.
7 * Copyright (c) 2003 Pai-Hsiang Hsiao
8 * Copyright (c) 1998-2003 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * $Log$
16 * Revision 1.4 2007/05/16 07:54:21 csoutheren
17 * Fix problems created by gcc 4.2.0
19 * Revision 1.3 2007/04/20 06:34:48 csoutheren
20 * Fix compilation on MacOSX
22 * Revision 1.2 2007/04/14 07:08:55 rjongbloed
23 * Major update of video subsystem:
24 * Abstracted video frame info (width, height etc) into separate class.
25 * Changed devices, converter and video file to use above.
26 * Enhanced video file hint detection for frame rate and more
27 * flexible formats.
28 * Fixed issue if need to convert both colour format and size, had to do
29 * colour format first or it didn't convert size.
30 * Win32 video output device can be selected by "MSWIN" alone.
32 * Revision 1.1 2006/07/18 05:17:24 csoutheren
33 * Added shared memory video devices
34 * Thanks to Hannes Friederich
36 * Revision 1.2 2003/06/12 21:34:13 shawn
37 * makes code consistent with documentation
39 * Revision 1.1 2003/06/12 19:39:11 shawn
40 * Added shared memory video input/output devices. Video frames of these two
41 * devices are stored in a named shared memory region and can be accessed by
42 * other applications.
47 #define P_FORCE_STATIC_PLUGIN
49 #include <ptlib.h>
50 #include <ptlib/videoio.h>
51 #include <ptlib/vconvert.h>
52 #include <ptlib/unix/ptlib/shmvideo.h>
54 #ifdef __MACOSX__
55 namespace PWLibStupidOSXHacks {
56 int loadShmVideoStuff;
59 #endif
61 class PColourConverter;
63 static const char *
64 ShmKeyFileName()
66 return "/dev/null";
69 BOOL
70 PVideoOutputDevice_Shm::shmInit()
72 semLock = sem_open(SEM_NAME_OF_OUTPUT_DEVICE,
73 O_RDWR, S_IRUSR|S_IWUSR, 0);
75 if (semLock != (sem_t *)SEM_FAILED) {
76 shmKey = ftok(ShmKeyFileName(), 0);
77 if (shmKey >= 0) {
78 shmId = shmget(shmKey, SHMVIDEO_BUFSIZE, 0666);
79 if (shmId >= 0) {
80 shmPtr = shmat(shmId, NULL, 0);
81 if (shmPtr) {
82 return TRUE;
84 else {
85 PTRACE(1, "SHMV\t shmInit can not attach shared memory" << endl);
86 shmctl(shmId, IPC_RMID, NULL);
87 sem_close(semLock);
90 else {
91 PTRACE(1, "SHMV\t shmInit can not find the shared memory" << endl);
92 sem_close(semLock);
95 else {
96 PTRACE(1, "SHMV\t shmInit can not create key for shared memory" << endl);
97 sem_close(semLock);
100 else {
101 PTRACE(1, "SHMV\t shmInit can not create semaphore" << endl);
104 semLock = (sem_t *)SEM_FAILED;
105 shmKey = -1;
106 shmId = -1;
107 shmPtr = NULL;
109 return FALSE;
112 PVideoOutputDevice_Shm::PVideoOutputDevice_Shm()
114 colourFormat = "RGB24";
115 bytesPerPixel = 3;
116 frameStore.SetSize(frameWidth * frameHeight * bytesPerPixel);
118 semLock = (sem_t *)SEM_FAILED;
119 shmKey = -1;
120 shmId = -1;
121 shmPtr = NULL;
123 PTRACE(6, "SHMV\t Constructor of PVideoOutputDevice_Shm");
126 BOOL PVideoOutputDevice_Shm::SetColourFormat(const PString & colourFormat)
128 if( colourFormat == "RGB32")
129 bytesPerPixel = 4;
130 else if(colourFormat == "RGB24")
131 bytesPerPixel = 3;
132 else
133 return false;
135 return PVideoOutputDevice::SetColourFormat(colourFormat) && SetFrameSize(frameWidth, frameHeight);
138 BOOL PVideoOutputDevice_Shm::SetFrameSize(unsigned width, unsigned height)
140 if (!PVideoOutputDevice::SetFrameSize(width, height))
141 return FALSE;
143 return frameStore.SetSize(frameWidth*frameHeight*bytesPerPixel);
146 PINDEX PVideoOutputDevice_Shm::GetMaxFrameBytes()
148 return frameStore.GetSize();
151 BOOL PVideoOutputDevice_Shm::SetFrameData(unsigned x, unsigned y,
152 unsigned width, unsigned height,
153 const BYTE * data,
154 BOOL endFrame)
156 if (x+width > frameWidth || y+height > frameHeight)
157 return FALSE;
159 if (x == 0 && width == frameWidth && y == 0 && height == frameHeight) {
160 if (converter != NULL)
161 converter->Convert(data, frameStore.GetPointer());
162 else
163 memcpy(frameStore.GetPointer(), data, height*width*bytesPerPixel);
165 else {
166 if (converter != NULL) {
167 PAssertAlways("Converted output of partial RGB frame not supported");
168 return FALSE;
171 if (x == 0 && width == frameWidth)
172 memcpy(frameStore.GetPointer() + y*width*bytesPerPixel, data, height*width*bytesPerPixel);
173 else {
174 for (unsigned dy = 0; dy < height; dy++)
175 memcpy(frameStore.GetPointer() + ((y+dy)*width + x)*bytesPerPixel,
176 data + dy*width*bytesPerPixel, width*bytesPerPixel);
180 if (endFrame)
181 return EndFrame();
183 return TRUE;
186 BOOL
187 PVideoOutputDevice_Shm::Open(const PString & name,
188 BOOL /*startImmediate*/)
190 PTRACE(1, "SHMV\t Open of PVideoOutputDevice_Shm");
192 Close();
194 if (shmInit() == TRUE) {
195 deviceName = name;
196 return TRUE;
198 else {
199 return FALSE;
203 BOOL
204 PVideoOutputDevice_Shm::IsOpen()
206 if (semLock != (sem_t *)SEM_FAILED) {
207 return TRUE;
209 else {
210 return FALSE;
214 BOOL
215 PVideoOutputDevice_Shm::Close()
217 if (semLock != (sem_t *)SEM_FAILED) {
218 shmdt(shmPtr);
219 sem_close(semLock);
220 shmPtr = NULL;
222 return TRUE;
225 PStringList
226 PVideoOutputDevice_Shm::GetDeviceNames() const
228 PStringList list;
229 list += "shm";
230 return list;
233 BOOL
234 PVideoOutputDevice_Shm::EndFrame()
236 long *ptr = (long *)shmPtr;
238 if (semLock == (sem_t *)SEM_FAILED) {
239 return FALSE;
242 if (bytesPerPixel != 3 && bytesPerPixel != 4) {
243 PTRACE(1, "SHMV\t EndFrame() does not handle bytesPerPixel!={3,4}"<<endl);
244 return FALSE;
247 if (frameWidth*frameHeight*bytesPerPixel > SHMVIDEO_FRAMESIZE) {
248 return FALSE;
251 // write header info so the consumer knows what to expect
252 ptr[0] = frameWidth;
253 ptr[1] = frameHeight;
254 ptr[2] = bytesPerPixel;
256 PTRACE(1, "writing " << frameStore.GetSize() << " bytes" << endl);
257 if (memcpy((char *)shmPtr+sizeof(long)*3,
258 frameStore, frameStore.GetSize()) == NULL) {
259 return FALSE;
262 sem_post(semLock);
264 return TRUE;
267 ///////////////////////////////////////////////////////////////////////////////
269 PCREATE_VIDINPUT_PLUGIN(Shm);
271 BOOL
272 PVideoInputDevice_Shm::shmInit()
274 semLock = sem_open(SEM_NAME_OF_INPUT_DEVICE,
275 O_RDWR, S_IRUSR|S_IWUSR, 0);
277 if (semLock != (sem_t *)SEM_FAILED) {
278 shmKey = ftok(ShmKeyFileName(), 100);
279 if (shmKey >= 0) {
280 shmId = shmget(shmKey, SHMVIDEO_BUFSIZE, 0666);
281 if (shmId >= 0) {
282 shmPtr = shmat(shmId, NULL, 0);
283 if (shmPtr) {
284 return TRUE;
286 else {
287 PTRACE(1, "SHMV\t shmInit can not attach shared memory" << endl);
288 shmctl(shmId, IPC_RMID, NULL);
289 sem_close(semLock);
292 else {
293 PTRACE(1, "SHMV\t shmInit can not find the shared memory" << endl);
294 sem_close(semLock);
297 else {
298 PTRACE(1, "SHMV\t shmInit can not create key for shared memory" << endl);
299 sem_close(semLock);
302 else {
303 PTRACE(1, "SHMV\t shmInit can not create semaphore" << endl);
306 semLock = (sem_t *)SEM_FAILED;
307 shmKey = -1;
308 shmId = -1;
309 shmPtr = NULL;
311 return FALSE;
314 PVideoInputDevice_Shm::PVideoInputDevice_Shm()
316 semLock = (sem_t *)SEM_FAILED;
317 shmKey = -1;
318 shmId = -1;
319 shmPtr = NULL;
321 PTRACE(4, "SHMV\t Constructor of PVideoInputDevice_Shm");
324 BOOL
325 PVideoInputDevice_Shm::Open(const PString & name,
326 BOOL /*startImmediate*/)
328 PTRACE(1, "SHMV\t Open of PVideoInputDevice_Shm");
330 Close();
332 if (shmInit() == TRUE) {
333 deviceName = name;
334 return TRUE;
336 else {
337 return FALSE;
341 BOOL
342 PVideoInputDevice_Shm::IsOpen()
344 if (semLock != (sem_t *)SEM_FAILED) {
345 return TRUE;
347 else {
348 return FALSE;
352 BOOL
353 PVideoInputDevice_Shm::Close()
355 if (semLock != (sem_t *)SEM_FAILED) {
356 shmdt(shmPtr);
357 sem_close(semLock);
358 shmPtr = NULL;
360 return TRUE;
363 BOOL PVideoInputDevice_Shm::IsCapturing()
365 return TRUE;
368 PINDEX PVideoInputDevice_Shm::GetMaxFrameBytes()
370 return videoFrameSize;
373 PStringList
374 PVideoInputDevice_Shm::GetInputDeviceNames()
376 PStringList list;
377 list += "shm";
378 return list;
381 BOOL
382 PVideoInputDevice_Shm::GetFrameSizeLimits(unsigned & minWidth,
383 unsigned & minHeight,
384 unsigned & maxWidth,
385 unsigned & maxHeight)
387 minWidth = 176;
388 minHeight = 144;
389 maxWidth = 352;
390 maxHeight = 288;
392 return TRUE;
395 static void RGBtoYUV420PSameSize (const BYTE *, BYTE *, unsigned, BOOL,
396 int, int);
399 #define rgbtoyuv(r, g, b, y, u, v) \
400 y=(BYTE)(((int)30*r +(int)59*g +(int)11*b)/100); \
401 u=(BYTE)(((int)-17*r -(int)33*g +(int)50*b+12800)/100); \
402 v=(BYTE)(((int)50*r -(int)42*g -(int)8*b+12800)/100); \
406 static void RGBtoYUV420PSameSize (const BYTE * rgb,
407 BYTE * yuv,
408 unsigned rgbIncrement,
409 BOOL flip,
410 int srcFrameWidth, int srcFrameHeight)
412 const unsigned planeSize = srcFrameWidth*srcFrameHeight;
413 const unsigned halfWidth = srcFrameWidth >> 1;
415 // get pointers to the data
416 BYTE * yplane = yuv;
417 BYTE * uplane = yuv + planeSize;
418 BYTE * vplane = yuv + planeSize + (planeSize >> 2);
419 const BYTE * rgbIndex = rgb;
421 for (int y = 0; y < (int) srcFrameHeight; y++) {
422 BYTE * yline = yplane + (y * srcFrameWidth);
423 BYTE * uline = uplane + ((y >> 1) * halfWidth);
424 BYTE * vline = vplane + ((y >> 1) * halfWidth);
426 if (flip)
427 rgbIndex = rgb + (srcFrameWidth*(srcFrameHeight-1-y)*rgbIncrement);
429 for (int x = 0; x < (int) srcFrameWidth; x+=2) {
430 rgbtoyuv(rgbIndex[0], rgbIndex[1], rgbIndex[2],*yline, *uline, *vline);
431 rgbIndex += rgbIncrement;
432 yline++;
433 rgbtoyuv(rgbIndex[0], rgbIndex[1], rgbIndex[2],*yline, *uline, *vline);
434 rgbIndex += rgbIncrement;
435 yline++;
436 uline++;
437 vline++;
443 BOOL PVideoInputDevice_Shm::GetFrame(PBYTEArray & frame)
445 PINDEX returned;
446 if (!GetFrameData(frame.GetPointer(GetMaxFrameBytes()), &returned))
447 return FALSE;
449 frame.SetSize(returned);
450 return TRUE;
453 BOOL
454 PVideoInputDevice_Shm::GetFrameData(BYTE * buffer, PINDEX * bytesReturned)
456 m_pacing.Delay(1000/GetFrameRate());
458 return GetFrameDataNoDelay(buffer, bytesReturned);
461 BOOL
462 PVideoInputDevice_Shm::GetFrameDataNoDelay (BYTE *buffer, PINDEX *bytesReturned)
464 long *bufPtr = (long *)shmPtr;
466 unsigned width = 0;
467 unsigned height = 0;
468 unsigned rgbIncrement = 4;
470 GetFrameSize (width, height);
472 bufPtr[0] = width;
473 bufPtr[1] = height;
475 if (semLock != (sem_t *)SEM_FAILED && sem_trywait(semLock) == 0) {
476 if (bufPtr[0] == (long)width && bufPtr[1] == (long)height) {
477 rgbIncrement = bufPtr[2];
478 RGBtoYUV420PSameSize ((BYTE *)(bufPtr+3), buffer, rgbIncrement, FALSE,
479 width, height);
481 *bytesReturned = videoFrameSize;
482 return TRUE;
486 return FALSE;
489 BOOL PVideoInputDevice_Shm::TestAllFormats()
491 return TRUE;
494 BOOL PVideoInputDevice_Shm::Start()
496 return TRUE;
499 BOOL PVideoInputDevice_Shm::Stop()
501 return TRUE;