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/
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
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
47 #define P_FORCE_STATIC_PLUGIN
50 #include <ptlib/videoio.h>
51 #include <ptlib/vconvert.h>
52 #include <ptlib/unix/ptlib/shmvideo.h>
55 namespace PWLibStupidOSXHacks
{
56 int loadShmVideoStuff
;
61 class PColourConverter
;
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);
78 shmId
= shmget(shmKey
, SHMVIDEO_BUFSIZE
, 0666);
80 shmPtr
= shmat(shmId
, NULL
, 0);
85 PTRACE(1, "SHMV\t shmInit can not attach shared memory" << endl
);
86 shmctl(shmId
, IPC_RMID
, NULL
);
91 PTRACE(1, "SHMV\t shmInit can not find the shared memory" << endl
);
96 PTRACE(1, "SHMV\t shmInit can not create key for shared memory" << endl
);
101 PTRACE(1, "SHMV\t shmInit can not create semaphore" << endl
);
104 semLock
= (sem_t
*)SEM_FAILED
;
112 PVideoOutputDevice_Shm::PVideoOutputDevice_Shm()
114 colourFormat
= "RGB24";
116 frameStore
.SetSize(frameWidth
* frameHeight
* bytesPerPixel
);
118 semLock
= (sem_t
*)SEM_FAILED
;
123 PTRACE(6, "SHMV\t Constructor of PVideoOutputDevice_Shm");
126 BOOL
PVideoOutputDevice_Shm::SetColourFormat(const PString
& colourFormat
)
128 if( colourFormat
== "RGB32")
130 else if(colourFormat
== "RGB24")
135 return PVideoOutputDevice::SetColourFormat(colourFormat
) && SetFrameSize(frameWidth
, frameHeight
);
138 BOOL
PVideoOutputDevice_Shm::SetFrameSize(unsigned width
, unsigned height
)
140 if (!PVideoOutputDevice::SetFrameSize(width
, height
))
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
,
156 if (x
+width
> frameWidth
|| y
+height
> frameHeight
)
159 if (x
== 0 && width
== frameWidth
&& y
== 0 && height
== frameHeight
) {
160 if (converter
!= NULL
)
161 converter
->Convert(data
, frameStore
.GetPointer());
163 memcpy(frameStore
.GetPointer(), data
, height
*width
*bytesPerPixel
);
166 if (converter
!= NULL
) {
167 PAssertAlways("Converted output of partial RGB frame not supported");
171 if (x
== 0 && width
== frameWidth
)
172 memcpy(frameStore
.GetPointer() + y
*width
*bytesPerPixel
, data
, height
*width
*bytesPerPixel
);
174 for (unsigned dy
= 0; dy
< height
; dy
++)
175 memcpy(frameStore
.GetPointer() + ((y
+dy
)*width
+ x
)*bytesPerPixel
,
176 data
+ dy
*width
*bytesPerPixel
, width
*bytesPerPixel
);
187 PVideoOutputDevice_Shm::Open(const PString
& name
,
188 BOOL
/*startImmediate*/)
190 PTRACE(1, "SHMV\t Open of PVideoOutputDevice_Shm");
194 if (shmInit() == TRUE
) {
204 PVideoOutputDevice_Shm::IsOpen()
206 if (semLock
!= (sem_t
*)SEM_FAILED
) {
215 PVideoOutputDevice_Shm::Close()
217 if (semLock
!= (sem_t
*)SEM_FAILED
) {
226 PVideoOutputDevice_Shm::GetDeviceNames() const
234 PVideoOutputDevice_Shm::EndFrame()
236 long *ptr
= (long *)shmPtr
;
238 if (semLock
== (sem_t
*)SEM_FAILED
) {
242 if (bytesPerPixel
!= 3 && bytesPerPixel
!= 4) {
243 PTRACE(1, "SHMV\t EndFrame() does not handle bytesPerPixel!={3,4}"<<endl
);
247 if (frameWidth
*frameHeight
*bytesPerPixel
> SHMVIDEO_FRAMESIZE
) {
251 // write header info so the consumer knows what to expect
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
) {
267 ///////////////////////////////////////////////////////////////////////////////
269 PCREATE_VIDINPUT_PLUGIN(Shm
);
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);
280 shmId
= shmget(shmKey
, SHMVIDEO_BUFSIZE
, 0666);
282 shmPtr
= shmat(shmId
, NULL
, 0);
287 PTRACE(1, "SHMV\t shmInit can not attach shared memory" << endl
);
288 shmctl(shmId
, IPC_RMID
, NULL
);
293 PTRACE(1, "SHMV\t shmInit can not find the shared memory" << endl
);
298 PTRACE(1, "SHMV\t shmInit can not create key for shared memory" << endl
);
303 PTRACE(1, "SHMV\t shmInit can not create semaphore" << endl
);
306 semLock
= (sem_t
*)SEM_FAILED
;
314 PVideoInputDevice_Shm::PVideoInputDevice_Shm()
316 semLock
= (sem_t
*)SEM_FAILED
;
321 PTRACE(4, "SHMV\t Constructor of PVideoInputDevice_Shm");
325 PVideoInputDevice_Shm::Open(const PString
& name
,
326 BOOL
/*startImmediate*/)
328 PTRACE(1, "SHMV\t Open of PVideoInputDevice_Shm");
332 if (shmInit() == TRUE
) {
342 PVideoInputDevice_Shm::IsOpen()
344 if (semLock
!= (sem_t
*)SEM_FAILED
) {
353 PVideoInputDevice_Shm::Close()
355 if (semLock
!= (sem_t
*)SEM_FAILED
) {
363 BOOL
PVideoInputDevice_Shm::IsCapturing()
368 PINDEX
PVideoInputDevice_Shm::GetMaxFrameBytes()
370 return videoFrameSize
;
374 PVideoInputDevice_Shm::GetInputDeviceNames()
382 PVideoInputDevice_Shm::GetFrameSizeLimits(unsigned & minWidth
,
383 unsigned & minHeight
,
385 unsigned & maxHeight
)
395 static void RGBtoYUV420PSameSize (const BYTE
*, BYTE
*, unsigned, BOOL
,
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,
408 unsigned rgbIncrement
,
410 int srcFrameWidth
, int srcFrameHeight
)
412 const unsigned planeSize
= srcFrameWidth
*srcFrameHeight
;
413 const unsigned halfWidth
= srcFrameWidth
>> 1;
415 // get pointers to the data
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
);
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
;
433 rgbtoyuv(rgbIndex
[0], rgbIndex
[1], rgbIndex
[2],*yline
, *uline
, *vline
);
434 rgbIndex
+= rgbIncrement
;
443 BOOL
PVideoInputDevice_Shm::GetFrame(PBYTEArray
& frame
)
446 if (!GetFrameData(frame
.GetPointer(GetMaxFrameBytes()), &returned
))
449 frame
.SetSize(returned
);
454 PVideoInputDevice_Shm::GetFrameData(BYTE
* buffer
, PINDEX
* bytesReturned
)
456 m_pacing
.Delay(1000/GetFrameRate());
458 return GetFrameDataNoDelay(buffer
, bytesReturned
);
462 PVideoInputDevice_Shm::GetFrameDataNoDelay (BYTE
*buffer
, PINDEX
*bytesReturned
)
464 long *bufPtr
= (long *)shmPtr
;
468 unsigned rgbIncrement
= 4;
470 GetFrameSize (width
, 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
,
481 *bytesReturned
= videoFrameSize
;
489 BOOL
PVideoInputDevice_Shm::TestAllFormats()
494 BOOL
PVideoInputDevice_Shm::Start()
499 BOOL
PVideoInputDevice_Shm::Stop()