1 /*
2  * videoio.cxx
3  *
4  * Classes to support streaming video input (grabbing) and output.
5  *
6  * Portable Windows Library
7  *
8  * Copyright (c) 1993-2000 Equivalence Pty. Ltd.
9  *
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/
14  *
15  * Software distributed under the License is distributed on an "AS IS"
16  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17  * the License for the specific language governing rights and limitations
18  * under the License.
19  *
20  * The Original Code is Portable Windows Library.
21  *
22  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
23  *
24  * Contributor(s): Mark Cooke (mpc@star.sr.bham.ac.uk)
25  *
26  * $Revision: 29328 $
27  * $Author: rjongbloed $
28  * $Date: 2013-03-26 18:23:37 -0500 (Tue, 26 Mar 2013) $
29  */
30 
31 #ifdef __GNUC__
32 #pragma implementation "videoio.h"
33 #endif
34 
35 #include <ptlib.h>
36 
37 #if P_VIDEO
38 
39 #include <ptlib/pluginmgr.h>
40 #include <ptlib/videoio.h>
41 #include <ptlib/vconvert.h>
42 
43 
44 namespace PWLib {
45   PFactory<PDevicePluginAdapterBase>::Worker< PDevicePluginAdapter<PVideoInputDevice> > vidinChannelFactoryAdapter("PVideoInputDevice", PTrue);
46   PFactory<PDevicePluginAdapterBase>::Worker< PDevicePluginAdapter<PVideoOutputDevice> > vidoutChannelFactoryAdapter("PVideoOutputDevice", PTrue);
47 };
48 
Create(const PString & type) const49 template <> PVideoInputDevice * PDevicePluginFactory<PVideoInputDevice>::Worker::Create(const PString & type) const
50 {
51   return PVideoInputDevice::CreateDevice(type);
52 }
53 
Create(const PString & type) const54 template <> PVideoOutputDevice * PDevicePluginFactory<PVideoOutputDevice>::Worker::Create(const PString & type) const
55 {
56   return PVideoOutputDevice::CreateDevice(type);
57 }
58 
59 ///////////////////////////////////////////////////////////////////////////////
60 
61 #if PTRACING
operator <<(ostream & strm,PVideoDevice::VideoFormat fmt)62 ostream & operator<<(ostream & strm, PVideoDevice::VideoFormat fmt)
63 {
64   static const char * const VideoFormatNames[PVideoDevice::NumVideoFormats] = {
65     "PAL",
66     "NTSC",
67     "SECAM",
68     "Auto"
69   };
70 
71   if (fmt < PVideoDevice::NumVideoFormats && VideoFormatNames[fmt] != NULL)
72     strm << VideoFormatNames[fmt];
73   else
74     strm << "VideoFormat<" << (unsigned)fmt << '>';
75 
76   return strm;
77 }
78 #endif
79 
80 
81 //Colour format bit per pixel table.
82 // These are in rough order of colour gamut size and "popularity"
83 static struct {
84   const char * colourFormat;
85   unsigned     bitsPerPixel;
86 } ColourFormatBPPTab[] = {
87   { "YUV420P", 12 },
88   { "I420",    12 },
89   { "IYUV",    12 },
90   { "YUV420",  12 },
91   { "RGB32",   32 },
92   { "BGR32",   32 },
93   { "RGB24",   24 },
94   { "BGR24",   24 },
95   { "YUY2",    16 },
96   { "YUV422",  16 },
97   { "YUV422P", 16 },
98   { "YUV411",  12 },
99   { "YUV411P", 12 },
100   { "RGB565",  16 },
101   { "RGB555",  16 },
102   { "RGB16",   16 },
103   { "YUV410",  10 },
104   { "YUV410P", 10 },
105   { "Grey",     8 },
106   { "GreyF",    8 },
107   { "UYVY422", 16 },
108   { "UYV444",  24 },
109   { "SBGGR8",   8 },
110   { "JPEG",    24 },
111   { "MJPEG",   24 }
112 };
113 
114 
115 template <class VideoDevice>
CreateDeviceWithDefaults(PString & adjustedDeviceName,const PString & driverName,PPluginManager * pluginMgr)116 static VideoDevice * CreateDeviceWithDefaults(PString & adjustedDeviceName,
117                                               const PString & driverName,
118                                               PPluginManager * pluginMgr)
119 {
120   if (adjustedDeviceName == "*")
121     adjustedDeviceName.MakeEmpty();
122 
123   PString adjustedDriverName = driverName;
124   if (adjustedDriverName == "*")
125     adjustedDriverName.MakeEmpty();
126 
127   if (adjustedDeviceName.IsEmpty()) {
128     if (adjustedDriverName.IsEmpty()) {
129       PStringArray drivers = VideoDevice::GetDriverNames(pluginMgr);
130       if (drivers.IsEmpty())
131         return NULL;
132 
133       // Give precedence to drivers like camera grabbers, Window
134       static const char * prioritisedDrivers[] = {
135         "Window", "SDL", "DirectShow", "VideoForWindows", "V4L", "V4L2", "1394DC", "1394AVC", "BSDCAPTURE", "FakeVideo", "NULLOutput"
136       };
137       for (PINDEX i = 0; i < PARRAYSIZE(prioritisedDrivers); i++) {
138         PINDEX driverIndex = drivers.GetValuesIndex(PString(prioritisedDrivers[i]));
139         if (driverIndex != P_MAX_INDEX) {
140           PStringArray devices = VideoDevice::GetDriversDeviceNames(drivers[driverIndex]);
141           if (!devices.IsEmpty()) {
142             adjustedDeviceName = devices[0];
143             adjustedDriverName = drivers[driverIndex];
144             break;
145           }
146         }
147       }
148 
149       if (adjustedDriverName.IsEmpty())
150         adjustedDriverName = drivers[0];
151     }
152 
153     if (adjustedDeviceName.IsEmpty()) {
154       PStringArray devices = VideoDevice::GetDriversDeviceNames(adjustedDriverName);
155       if (devices.IsEmpty())
156         return NULL;
157 
158       adjustedDeviceName = devices[0];
159     }
160   }
161 
162   return VideoDevice::CreateDeviceByName(adjustedDeviceName, adjustedDriverName, pluginMgr);
163 }
164 
165 
166 ///////////////////////////////////////////////////////////////////////////////
167 // PVideoDevice
168 
operator <<(ostream & strm,PVideoFrameInfo::ResizeMode mode)169 ostream & operator<<(ostream & strm, PVideoFrameInfo::ResizeMode mode)
170 {
171   switch (mode) {
172     case PVideoFrameInfo::eScale :
173       return strm << "Scaled";
174     case PVideoFrameInfo::eCropCentre :
175       return strm << "Centred";
176     case PVideoFrameInfo::eCropTopLeft :
177       return strm << "Cropped";
178     default :
179       return strm << "ResizeMode<" << (int)mode << '>';
180   }
181 }
182 
183 
PVideoFrameInfo()184 PVideoFrameInfo::PVideoFrameInfo()
185   : frameWidth(CIFWidth)
186   , frameHeight(CIFHeight)
187   , frameRate(25)
188   , colourFormat("YUV420P")
189   , resizeMode(eScale)
190 {
191 }
192 
193 
PVideoFrameInfo(unsigned width,unsigned height,const PString & format,unsigned rate,ResizeMode resize)194 PVideoFrameInfo::PVideoFrameInfo(unsigned        width,
195                                  unsigned        height,
196                                  const PString & format,
197                                  unsigned        rate,
198                                  ResizeMode      resize)
199   : frameWidth(width)
200   , frameHeight(height)
201   , frameRate(rate)
202   , colourFormat(format)
203   , resizeMode(resize)
204 {
205 }
206 
207 
Compare(const PObject & obj) const208 PObject::Comparison PVideoFrameInfo::Compare(const PObject & obj) const
209 {
210   const PVideoFrameInfo & other = dynamic_cast<const PVideoFrameInfo &>(obj);
211 
212   unsigned area = frameWidth*frameHeight;
213   unsigned otherArea = other.frameWidth*other.frameHeight;
214   if (area < otherArea)
215     return LessThan;
216   if (area > otherArea)
217     return GreaterThan;
218 
219   if (frameRate < other.frameRate)
220     return LessThan;
221   if (frameRate > other.frameRate)
222     return GreaterThan;
223 
224   return colourFormat.Compare(other.colourFormat);
225 }
226 
227 
PrintOn(ostream & strm) const228 void PVideoFrameInfo::PrintOn(ostream & strm) const
229 {
230   if (!colourFormat.IsEmpty())
231     strm << colourFormat << ':';
232 
233   strm << AsString(frameWidth, frameHeight);
234 
235   if (frameRate > 0)
236     strm << '@' << frameRate;
237 
238   if (resizeMode < eMaxResizeMode)
239     strm << '/' << resizeMode;
240 }
241 
242 
SetFrameSize(unsigned width,unsigned height)243 PBoolean PVideoFrameInfo::SetFrameSize(unsigned width, unsigned height)
244 {
245   if (width < 8 || height < 8)
246     return PFalse;
247   frameWidth = width;
248   frameHeight = height;
249   return PTrue;
250 }
251 
252 
GetFrameSize(unsigned & width,unsigned & height) const253 PBoolean PVideoFrameInfo::GetFrameSize(unsigned & width, unsigned & height) const
254 {
255   width = frameWidth;
256   height = frameHeight;
257   return PTrue;
258 }
259 
260 
GetFrameWidth() const261 unsigned PVideoFrameInfo::GetFrameWidth() const
262 {
263   unsigned w,h;
264   GetFrameSize(w, h);
265   return w;
266 }
267 
268 
GetFrameHeight() const269 unsigned PVideoFrameInfo::GetFrameHeight() const
270 {
271   unsigned w,h;
272   GetFrameSize(w, h);
273   return h;
274 }
275 
SetFrameSar(unsigned width,unsigned height)276 PBoolean PVideoFrameInfo::SetFrameSar(unsigned width, unsigned height)
277 {
278     if(height == 0 || width == 0)
279     {
280         return PFalse;
281     }
282   sarWidth  = width;
283   sarHeight = height;
284   return PTrue;
285 }
286 
GetSarSize(unsigned & width,unsigned & height) const287 PBoolean PVideoFrameInfo::GetSarSize(unsigned & width, unsigned & height) const
288 {
289   width  = sarWidth;
290   height = sarHeight;
291   return PTrue;
292 }
293 
GetSarWidth() const294 unsigned PVideoFrameInfo::GetSarWidth() const
295 {
296   unsigned w,h;
297   GetSarSize(w, h);
298   return w;
299 }
300 
301 
GetSarHeight() const302 unsigned PVideoFrameInfo::GetSarHeight() const
303 {
304   unsigned w,h;
305   GetSarSize(w, h);
306   return h;
307 }
308 
SetFrameRate(unsigned rate)309 PBoolean PVideoFrameInfo::SetFrameRate(unsigned rate)
310 {
311   if (rate < 1 || rate > 999)
312     return PFalse;
313 
314   frameRate = rate;
315   return PTrue;
316 }
317 
318 
GetFrameRate() const319 unsigned PVideoFrameInfo::GetFrameRate() const
320 {
321   return frameRate;
322 }
323 
324 
SetColourFormat(const PString & colourFmt)325 PBoolean PVideoFrameInfo::SetColourFormat(const PString & colourFmt)
326 {
327   if (!colourFmt) {
328     colourFormat = colourFmt.ToUpper();
329     return PTrue;
330   }
331 
332   for (PINDEX i = 0; i < PARRAYSIZE(ColourFormatBPPTab); i++) {
333     if (SetColourFormat(ColourFormatBPPTab[i].colourFormat))
334       return PTrue;
335   }
336 
337   return PFalse;
338 }
339 
340 
GetColourFormat() const341 const PString & PVideoFrameInfo::GetColourFormat() const
342 {
343   return colourFormat;
344 }
345 
346 
CalculateFrameBytes(unsigned width,unsigned height,const PString & colourFormat)347 PINDEX PVideoFrameInfo::CalculateFrameBytes(unsigned width, unsigned height,
348                                               const PString & colourFormat)
349 {
350   for (PINDEX i = 0; i < PARRAYSIZE(ColourFormatBPPTab); i++) {
351     if (colourFormat *= ColourFormatBPPTab[i].colourFormat)
352       return width * height * ColourFormatBPPTab[i].bitsPerPixel/8;
353   }
354   return 0;
355 }
356 
357 
Parse(const PString & str)358 bool PVideoFrameInfo::Parse(const PString & str)
359 {
360   PString newFormat = colourFormat;
361   PINDEX formatOffset = str.Find(':');
362   if (formatOffset == 0)
363     return false;
364 
365   if (formatOffset == P_MAX_INDEX)
366     formatOffset = 0;
367   else
368     newFormat = str.Left(formatOffset++);
369 
370 
371   ResizeMode newMode = resizeMode;
372   PINDEX resizeOffset = str.Find('/', formatOffset);
373   if (resizeOffset != P_MAX_INDEX) {
374     static struct {
375       const char * name;
376       ResizeMode   mode;
377     } const ResizeNames[] = {
378       { "scale",   eScale },
379       { "resize",  eScale },
380       { "scaled",  eScale },
381       { "centre",  eCropCentre },
382       { "centred", eCropCentre },
383       { "center",  eCropCentre },
384       { "centered",eCropCentre },
385       { "crop",    eCropTopLeft },
386       { "cropped", eCropTopLeft },
387       { "topleft", eCropTopLeft }
388     };
389 
390     PCaselessString crop = str.Mid(resizeOffset+1);
391     PINDEX resizeIndex = 0;
392     while (crop != ResizeNames[resizeIndex].name) {
393       if (++resizeIndex >= PARRAYSIZE(ResizeNames))
394         return false;
395     }
396     newMode = ResizeNames[resizeIndex].mode;
397   }
398 
399 
400   int newRate = frameRate;
401   PINDEX rateOffset = str.Find('@', formatOffset);
402   if (rateOffset == P_MAX_INDEX)
403     rateOffset = resizeOffset;
404   else {
405     newRate = str.Mid(rateOffset+1).AsInteger();
406     if (newRate < 1 || newRate > 100)
407       return false;
408   }
409 
410   if (!ParseSize(str(formatOffset, rateOffset-1), frameWidth, frameHeight))
411     return false;
412 
413   colourFormat = newFormat;
414   frameRate = newRate;
415   resizeMode = newMode;
416   return true;
417 }
418 
419 
420 static struct {
421   const char * name;
422   unsigned width;
423   unsigned height;
424 } const SizeTable[] = {
425     { "CIF",    PVideoDevice::CIFWidth,   PVideoDevice::CIFHeight   },
426     { "QCIF",   PVideoDevice::QCIFWidth,  PVideoDevice::QCIFHeight  },
427     { "SQCIF",  PVideoDevice::SQCIFWidth, PVideoDevice::SQCIFHeight },
428     { "CIF4",   PVideoDevice::CIF4Width,  PVideoDevice::CIF4Height  },
429     { "4CIF",   PVideoDevice::CIF4Width,  PVideoDevice::CIF4Height  },
430     { "CIF16",  PVideoDevice::CIF16Width, PVideoDevice::CIF16Height },
431     { "16CIF",  PVideoDevice::CIF16Width, PVideoDevice::CIF16Height },
432 
433     { "CCIR601",720,                      486                       },
434     { "NTSC",   720,                      480                       },
435     { "PAL",    768,                      576                       },
436     { "HD480",  PVideoDevice::HD480Width, PVideoDevice::HD480Height },
437     { "HDTVP",  PVideoDevice::HD720Width, PVideoDevice::HD720Height },
438     { "HD720",  PVideoDevice::HD720Width, PVideoDevice::HD720Height },
439     { "HDTVI",  PVideoDevice::HD1080Width,PVideoDevice::HD1080Height},
440     { "HD1080", PVideoDevice::HD1080Width,PVideoDevice::HD1080Height},
441 
442     { "CGA",    320,                      240                       },
443     { "VGA",    640,                      480                       },
444     { "WVGA",   854,                      480                       },
445     { "SVGA",   800,                      600                       },
446     { "XGA",    1024,                     768                       },
447     { "SXGA",   1280,                     1024                      },
448     { "WSXGA",  1440,                     900                       },
449     { "SXGA+",  1400,                     1050                      },
450     { "WSXGA+", 1680,                     1050                      },
451     { "UXGA",   1600,                     1200                      },
452     { "WUXGA",  1920,                     1200                      },
453     { "QXGA",   2048,                     1536                      },
454     { "WQXGA",  2560,                     1600                      },
455 };
456 
ParseSize(const PString & str,unsigned & width,unsigned & height)457 bool PVideoFrameInfo::ParseSize(const PString & str, unsigned & width, unsigned & height)
458 {
459   for (int i = 0; i < PARRAYSIZE(SizeTable); i++) {
460     if (str *= SizeTable[i].name) {
461       width = SizeTable[i].width;
462       height = SizeTable[i].height;
463       return true;
464     }
465   }
466 
467   return sscanf(str, "%ux%u", &width, &height) == 2 && width > 0 && height > 0;
468 }
469 
470 
AsString(unsigned width,unsigned height)471 PString PVideoFrameInfo::AsString(unsigned width, unsigned height)
472 {
473   for (int i = 0; i < PARRAYSIZE(SizeTable); i++) {
474     if (SizeTable[i].width == width && SizeTable[i].height == height)
475       return SizeTable[i].name;
476   }
477 
478   return psprintf("%ux%u", width, height);
479 }
480 
481 
GetSizeNames()482 PStringArray PVideoFrameInfo::GetSizeNames()
483 {
484   PStringArray names(PARRAYSIZE(SizeTable));
485   for (int i = 0; i < PARRAYSIZE(SizeTable); i++)
486     names[i] = SizeTable[i].name;
487   return names;
488 }
489 
490 
491 ///////////////////////////////////////////////////////////////////////////////
492 // PVideoDevice
493 
PVideoDevice()494 PVideoDevice::PVideoDevice()
495 {
496   lastError = 0;
497 
498   videoFormat = Auto;
499   channelNumber = -1;  // -1 will find the first working channel number.
500   nativeVerticalFlip = PFalse;
501 
502   converter = NULL;
503 }
504 
~PVideoDevice()505 PVideoDevice::~PVideoDevice()
506 {
507   if (converter)
508     delete converter;
509 }
510 
511 
OpenArgs()512 PVideoDevice::OpenArgs::OpenArgs()
513   : pluginMgr(NULL),
514     deviceName("#1"),
515     videoFormat(Auto),
516     channelNumber(0),
517     colourFormat("YUV420P"),
518     convertFormat(PTrue),
519     rate(0),
520     width(CIFWidth),
521     height(CIFHeight),
522     convertSize(PTrue),
523     resizeMode(eScale),
524     flip(PFalse),
525     brightness(-1),
526     whiteness(-1),
527     contrast(-1),
528     colour(-1),
529     hue(-1)
530 {
531 }
532 
533 
OpenFull(const OpenArgs & args,PBoolean startImmediate)534 PBoolean PVideoDevice::OpenFull(const OpenArgs & args, PBoolean startImmediate)
535 {
536   if (args.deviceName[0] == '#') {
537     PStringArray devices = GetDeviceNames();
538     PINDEX id = args.deviceName.Mid(1).AsUnsigned();
539     if (id == 0 || id > devices.GetSize())
540       return PFalse;
541 
542     if (!Open(devices[id-1], PFalse))
543       return PFalse;
544   }
545   else {
546     if (!Open(args.deviceName, PFalse))
547       return PFalse;
548   }
549 
550   if (!SetVideoFormat(args.videoFormat))
551     return PFalse;
552 
553   if (!SetChannel(args.channelNumber))
554     return PFalse;
555 
556   if (args.convertFormat) {
557     if (!SetColourFormatConverter(args.colourFormat))
558       return PFalse;
559   }
560   else {
561     if (!SetColourFormat(args.colourFormat))
562       return PFalse;
563   }
564 
565   if (args.rate > 0) {
566     if (!SetFrameRate(args.rate))
567       return PFalse;
568   }
569 
570   if (args.convertSize) {
571     if (!SetFrameSizeConverter(args.width, args.height, args.resizeMode))
572       return PFalse;
573   }
574   else {
575     if (!SetFrameSize(args.width, args.height))
576       return PFalse;
577   }
578 
579   if (!SetVFlipState(args.flip))
580     return PFalse;
581 
582   if (args.brightness >= 0) {
583     if (!SetBrightness(args.brightness))
584       return PFalse;
585   }
586 
587   if (args.whiteness >= 0) {
588     if (!SetWhiteness(args.whiteness))
589       return PFalse;
590   }
591 
592   if (args.contrast >= 0) {
593     if (!SetContrast(args.contrast))
594       return PFalse;
595   }
596 
597   if (args.colour >= 0) {
598     if (!SetColour(args.colour))
599       return PFalse;
600   }
601 
602   if (args.hue >= 0) {
603     if (!SetColour(args.hue))
604       return PFalse;
605   }
606 
607   if (startImmediate)
608     return Start();
609 
610   return PTrue;
611 }
612 
613 
Close()614 PBoolean PVideoDevice::Close()
615 {
616   return PTrue;
617 }
618 
619 
Start()620 PBoolean PVideoDevice::Start()
621 {
622   return PTrue;
623 }
624 
625 
Stop()626 PBoolean PVideoDevice::Stop()
627 {
628   return PTrue;
629 }
630 
631 
SetVideoFormat(VideoFormat videoFmt)632 PBoolean PVideoDevice::SetVideoFormat(VideoFormat videoFmt)
633 {
634   videoFormat = videoFmt;
635   return PTrue;
636 }
637 
638 
GetVideoFormat() const639 PVideoDevice::VideoFormat PVideoDevice::GetVideoFormat() const
640 {
641   return videoFormat;
642 }
643 
644 
GetNumChannels()645 int PVideoDevice::GetNumChannels()
646 {
647   return 1;
648 }
649 
650 
SetChannel(int channelNum)651 PBoolean PVideoDevice::SetChannel(int channelNum)
652 {
653   if (channelNum < 0) { // Seek out the first available channel
654     for (int c = 0; c < GetNumChannels(); c++) {
655       if (SetChannel(c))
656         return PTrue;
657     }
658     return PFalse;
659   }
660 
661   if (channelNum >= GetNumChannels()) {
662     PTRACE(2, "PVidDev\tSetChannel number (" << channelNum << ") too large.");
663     return PFalse;
664   }
665 
666   channelNumber = channelNum;
667   return PTrue;
668 }
669 
670 
GetChannel() const671 int PVideoDevice::GetChannel() const
672 {
673   return channelNumber;
674 }
675 
676 
SetColourFormatConverter(const PString & newColourFmt)677 PBoolean PVideoDevice::SetColourFormatConverter(const PString & newColourFmt)
678 {
679   if (converter != NULL) {
680     if (CanCaptureVideo()) {
681       if (converter->GetDstColourFormat() == newColourFmt)
682         return true;
683     }
684     else {
685       if (converter->GetSrcColourFormat() == newColourFmt)
686         return true;
687     }
688   }
689   else {
690     if (colourFormat == newColourFmt)
691       return true;
692   }
693 
694   PString newColourFormat = newColourFmt; // make copy, just in case newColourFmt is reference to member colourFormat
695 
696   if (!SetColourFormat(newColourFormat) &&
697         (preferredColourFormat.IsEmpty() || !SetColourFormat(preferredColourFormat))) {
698     /************************
699       Eventually, need something more sophisticated than this, but for the
700       moment pick the known colour formats that the device is very likely to
701       support and then look for a conversion routine from that to the
702       destination format.
703 
704       What we really want is some sort of better heuristic that looks at
705       computational requirements of each converter and picks a pair of formats
706       that the hardware supports and uses the least CPU.
707     */
708 
709     PINDEX knownFormatIdx = 0;
710     while (!SetColourFormat(ColourFormatBPPTab[knownFormatIdx].colourFormat)) {
711       if (++knownFormatIdx >= PARRAYSIZE(ColourFormatBPPTab)) {
712         PTRACE(2, "PVidDev\tSetColourFormatConverter FAILED for " << newColourFormat);
713         return false;
714       }
715     }
716   }
717 
718   PTRACE(3, "PVidDev\tSetColourFormatConverter success for native " << colourFormat);
719 
720   PVideoFrameInfo src = *this;
721   PVideoFrameInfo dst = *this;
722 
723   if (converter != NULL) {
724     converter->GetSrcFrameInfo(src);
725     converter->GetDstFrameInfo(dst);
726     delete converter;
727     converter = NULL;
728   }
729 
730   if (nativeVerticalFlip || colourFormat != newColourFormat) {
731     if (CanCaptureVideo()) {
732       src.SetColourFormat(colourFormat);
733       dst.SetColourFormat(newColourFormat);
734     }
735     else {
736       src.SetColourFormat(newColourFormat);
737       dst.SetColourFormat(colourFormat);
738     }
739 
740     converter = PColourConverter::Create(src, dst);
741     if (converter == NULL) {
742       PTRACE(2, "PVidDev\tSetColourFormatConverter failed to crate converter from " << src << " to " << dst);
743       return false;
744     }
745 
746     converter->SetVFlipState(nativeVerticalFlip);
747   }
748 
749   return true;
750 }
751 
752 
GetVFlipState()753 PBoolean PVideoDevice::GetVFlipState()
754 {
755   if (converter != NULL)
756     return converter->GetVFlipState() ^ nativeVerticalFlip;
757 
758   return nativeVerticalFlip;
759 }
760 
761 
SetVFlipState(PBoolean newVFlip)762 PBoolean PVideoDevice::SetVFlipState(PBoolean newVFlip)
763 {
764   if (newVFlip && converter == NULL) {
765     converter = PColourConverter::Create(*this, *this);
766     if (PAssertNULL(converter) == NULL)
767       return PFalse;
768   }
769 
770   if (converter != NULL)
771     converter->SetVFlipState(newVFlip ^ nativeVerticalFlip);
772 
773   return PTrue;
774 }
775 
776 
GetFrameSizeLimits(unsigned & minWidth,unsigned & minHeight,unsigned & maxWidth,unsigned & maxHeight)777 PBoolean PVideoDevice::GetFrameSizeLimits(unsigned & minWidth,
778                                       unsigned & minHeight,
779                                       unsigned & maxWidth,
780                                       unsigned & maxHeight)
781 {
782   minWidth = minHeight = 1;
783   maxWidth = maxHeight = UINT_MAX;
784   return PFalse;
785 }
786 
787 
SetFrameSizeConverter(unsigned width,unsigned height,ResizeMode resizeMode)788 PBoolean PVideoDevice::SetFrameSizeConverter(unsigned width, unsigned height, ResizeMode resizeMode)
789 {
790   if (SetFrameSize(width, height)) {
791     if (nativeVerticalFlip && converter == NULL) {
792       converter = PColourConverter::Create(*this, *this);
793       if (PAssertNULL(converter) == NULL)
794         return PFalse;
795     }
796     if (converter != NULL) {
797       converter->SetFrameSize(frameWidth, frameHeight);
798       converter->SetVFlipState(nativeVerticalFlip);
799     }
800     return PTrue;
801   }
802 
803   // Try and get the most compatible physical frame size to convert from/to
804   if (!SetNearestFrameSize(width, height)) {
805     PTRACE(1, "PVidDev\tCannot set an apropriate size to scale from.");
806     return false;
807   }
808 
809   // Now create the converter ( if not already exist)
810   if (converter == NULL) {
811     PVideoFrameInfo src = *this;
812     PVideoFrameInfo dst = *this;
813     if (CanCaptureVideo())
814       dst.SetFrameSize(width, height);
815     else
816       src.SetFrameSize(width, height);
817     dst.SetResizeMode(resizeMode);
818     converter = PColourConverter::Create(src, dst);
819     if (converter == NULL) {
820       PTRACE(1, "PVidDev\tSetFrameSizeConverter Colour converter creation failed");
821       return PFalse;
822     }
823   }
824   else
825   {
826     if (CanCaptureVideo())
827       converter->SetDstFrameSize(width, height);
828     else
829       converter->SetSrcFrameSize(width, height);
830     converter->SetResizeMode(resizeMode);
831   }
832 
833   PTRACE(3,"PVidDev\tColour converter used from " << converter->GetSrcFrameWidth() << 'x' << converter->GetSrcFrameHeight() << " [" << converter->GetSrcColourFormat() << "]" << " to " << converter->GetDstFrameWidth() << 'x' << converter->GetDstFrameHeight() << " [" << converter->GetDstColourFormat() << "]");
834 
835   return PTrue;
836 }
837 
838 
SetNearestFrameSize(unsigned width,unsigned height)839 PBoolean PVideoDevice::SetNearestFrameSize(unsigned width, unsigned height)
840 {
841   unsigned minWidth, minHeight, maxWidth, maxHeight;
842   if (GetFrameSizeLimits(minWidth, minHeight, maxWidth, maxHeight)) {
843     if (width < minWidth)
844       width = minWidth;
845     else if (width > maxWidth)
846       width = maxWidth;
847 
848     if (height < minHeight)
849       height = minHeight;
850     else if (height > maxHeight)
851       height = maxHeight;
852   }
853 
854   return SetFrameSize(width, height);
855 }
856 
857 
SetFrameSize(unsigned width,unsigned height)858 PBoolean PVideoDevice::SetFrameSize(unsigned width, unsigned height)
859 {
860 #if PTRACING
861   unsigned oldWidth = frameWidth;
862   unsigned oldHeight = frameHeight;
863 #endif
864 
865   frameWidth = width;
866   frameHeight = height;
867 
868   if (converter != NULL) {
869     if ((!converter->SetSrcFrameSize(width, height)) ||
870         (!converter->SetDstFrameSize(width, height))) {
871       PTRACE(1, "PVidDev\tSetFrameSize with converter failed with " << width << 'x' << height);
872       return PFalse;
873     }
874   }
875 
876   PTRACE_IF(3, oldWidth != frameWidth || oldHeight != frameHeight,
877             "PVidDev\tSetFrameSize to " << frameWidth << 'x' << frameHeight);
878   return PTrue;
879 }
880 
881 
GetFrameSize(unsigned & width,unsigned & height) const882 PBoolean PVideoDevice::GetFrameSize(unsigned & width, unsigned & height) const
883 {
884   // Channels get very upset at this not returning the output size.
885   return converter != NULL ? converter->GetDstFrameSize(width, height) : PVideoFrameInfo::GetFrameSize(width, height);
886 }
887 
888 
GetMaxFrameBytesConverted(PINDEX rawFrameBytes) const889 PINDEX PVideoDevice::GetMaxFrameBytesConverted(PINDEX rawFrameBytes) const
890 {
891   if (converter == NULL)
892     return rawFrameBytes;
893 
894   PINDEX srcFrameBytes = converter->GetMaxSrcFrameBytes();
895   PINDEX dstFrameBytes = converter->GetMaxDstFrameBytes();
896   PINDEX convertedFrameBytes = PMAX(srcFrameBytes, dstFrameBytes);
897   return PMAX(rawFrameBytes, convertedFrameBytes);
898 }
899 
900 
GetBrightness()901 int PVideoDevice::GetBrightness()
902 {
903   return frameBrightness;
904 }
905 
906 
SetBrightness(unsigned newBrightness)907 PBoolean PVideoDevice::SetBrightness(unsigned newBrightness)
908 {
909   frameBrightness = newBrightness;
910   return PTrue;
911 }
912 
913 
GetWhiteness()914 int PVideoDevice::GetWhiteness()
915 {
916   return frameWhiteness;
917 }
918 
919 
SetWhiteness(unsigned newWhiteness)920 PBoolean PVideoDevice::SetWhiteness(unsigned newWhiteness)
921 {
922   frameWhiteness = newWhiteness;
923   return PTrue;
924 }
925 
926 
GetColour()927 int PVideoDevice::GetColour()
928 {
929   return frameColour;
930 }
931 
932 
SetColour(unsigned newColour)933 PBoolean PVideoDevice::SetColour(unsigned newColour)
934 {
935   frameColour=newColour;
936   return PTrue;
937 }
938 
939 
GetContrast()940 int PVideoDevice::GetContrast()
941 {
942   return frameContrast;
943 }
944 
945 
SetContrast(unsigned newContrast)946 PBoolean PVideoDevice::SetContrast(unsigned newContrast)
947 {
948   frameContrast=newContrast;
949   return PTrue;
950 }
951 
952 
GetHue()953 int PVideoDevice::GetHue()
954 {
955   return frameHue;
956 }
957 
958 
SetHue(unsigned newHue)959 PBoolean PVideoDevice::SetHue(unsigned newHue)
960 {
961   frameHue=newHue;
962   return PTrue;
963 }
964 
965 
GetParameters(int * whiteness,int * brightness,int * colour,int * contrast,int * hue)966 PBoolean PVideoDevice::GetParameters (int *whiteness,
967                                   int *brightness,
968                                   int *colour,
969                                   int *contrast,
970                                   int *hue)
971 {
972   if (!IsOpen())
973     return PFalse;
974 
975   *brightness = frameBrightness;
976   *colour     = frameColour;
977   *contrast   = frameContrast;
978   *hue        = frameHue;
979   *whiteness  = frameWhiteness;
980 
981   return PTrue;
982 }
983 
SetVideoChannelFormat(int newNumber,VideoFormat newFormat)984 PBoolean PVideoDevice::SetVideoChannelFormat (int newNumber, VideoFormat newFormat)
985 {
986   PBoolean err1, err2;
987 
988   err1 = SetChannel (newNumber);
989   err2 = SetVideoFormat (newFormat);
990 
991   return (err1 && err2);
992 }
993 
GetDeviceNames() const994 PStringArray PVideoDevice::GetDeviceNames() const
995 {
996   return PStringArray();
997 }
998 
999 ////////////////////////////////////////////////////////////////////////////////////////////
1000 
AsString(const InputControlType & ctype)1001 PString PVideoControlInfo::AsString(const InputControlType & ctype)
1002 {
1003 	switch (ctype) {
1004 		case ControlPan:
1005 			return "Pan";
1006 		case ControlTilt:
1007 			return "Tilt";
1008 		case ControlZoom:
1009 			return "Zoom";
1010 	}
1011 	return PString();
1012 }
1013 
1014 ////////////////////////////////////////////////////////////////////////////////////////////
1015 
AsString(const InputInteractType & ctype)1016 PString PVideoInteractionInfo::AsString(const InputInteractType & ctype)
1017 {
1018 	switch (ctype) {
1019 		case InteractKey:
1020 			return "Remote Key Press";
1021 		case InteractMouse:
1022 			return "Remote Mouse Move/Click";
1023 		case InteractNavigate:
1024 			return "Remote Navigation";
1025 		case InteractRTSP:
1026 			return "Remote RTSP Commands";
1027 		case InteractOther:
1028 			return "Custom/Other";
1029 	}
1030 	return PString();
1031 }
1032 
1033 /////////////////////////////////////////////////////////////////////////////////////////////
1034 
~PVideoInputControl()1035 PVideoInputControl::~PVideoInputControl()
1036 {
1037 	Reset();
1038 }
1039 
Pan(long,bool)1040 PBoolean PVideoInputControl::Pan(long /*value*/, bool /*absolute*/)
1041 {
1042 	return false;
1043 }
1044 
Tilt(long,bool)1045 PBoolean PVideoInputControl::Tilt(long /*value*/, bool /*absolute*/)
1046 {
1047 	return false;
1048 }
1049 
Zoom(long,bool)1050 PBoolean PVideoInputControl::Zoom(long /*value*/, bool /*absolute*/)
1051 {
1052 	return false;
1053 }
1054 
GetPan()1055 long PVideoInputControl::GetPan()
1056 {
1057 	long position;
1058 	if (GetCurrentPosition(ControlPan, position))
1059 		  return position;
1060 
1061 	return 0;
1062 }
1063 
GetTilt()1064 long PVideoInputControl::GetTilt()
1065 {
1066 	long position;
1067 	if (GetCurrentPosition(ControlTilt, position))
1068 		   return position;
1069 
1070     return 0;
1071 }
1072 
GetZoom()1073 long PVideoInputControl::GetZoom()
1074 {
1075 	long position;
1076 	if (GetCurrentPosition(ControlZoom, position))
1077 		   return position;
1078 
1079     return 0;
1080 }
1081 
Reset()1082 void PVideoInputControl::Reset()
1083 {
1084 	PTRACE(4,"CC\tResetting camera to default position.");
1085 
1086 	long position;
1087 
1088 	if (GetDefaultPosition(ControlPan, position))
1089 		   Pan(position,true);
1090 
1091 	if (GetDefaultPosition(ControlTilt, position))
1092 		   Tilt(position,true);
1093 
1094 	if (GetDefaultPosition(ControlZoom, position))
1095 		   Zoom(position,true);
1096 
1097 }
1098 
GetVideoControlInfo(const InputControlType ctype,PVideoControlInfo & control)1099 PBoolean PVideoInputControl::GetVideoControlInfo(const InputControlType ctype, PVideoControlInfo & control)
1100 {
1101 	 for (std::list<PVideoControlInfo>::iterator r = m_info.begin(); r != m_info.end(); ++r) {
1102 		 if (r->type == ctype) {
1103 			 control = *r;
1104 			 return true;
1105 		 }
1106 	 }
1107 
1108 	 return false;
1109 }
1110 
GetDefaultPosition(const InputControlType ctype,long & def)1111 PBoolean PVideoInputControl::GetDefaultPosition(const InputControlType ctype, long & def)
1112 {
1113 	 for (std::list<PVideoControlInfo>::const_iterator r = m_info.begin(); r != m_info.end(); ++r) {
1114 		 if (r->type == ctype) {
1115 			 def = r->def;
1116 			 return true;
1117 		 }
1118 	 }
1119 	 return false;
1120 }
1121 
GetCurrentPosition(const InputControlType ctype,long & current)1122 PBoolean PVideoInputControl::GetCurrentPosition(const InputControlType ctype, long & current)
1123 {
1124 	 for (std::list<PVideoControlInfo>::const_iterator r = m_info.begin(); r != m_info.end(); ++r) {
1125 		 if (r->type == ctype) {
1126 			 current = r->current;
1127 			 return true;
1128 		 }
1129 	 }
1130 	 return false;
1131 }
1132 
1133 
SetCurrentPosition(const InputControlType ctype,long current)1134 void PVideoInputControl::SetCurrentPosition(const InputControlType ctype, long current)
1135 {
1136 	 for (std::list<PVideoControlInfo>::iterator r = m_info.begin(); r != m_info.end(); ++r) {
1137 		 if (r->type == ctype) {
1138 			 r->current = current;
1139 			 break;
1140 		 }
1141 	 }
1142 }
1143 
1144 
1145 
1146 
1147 ///////////////////////////////////////////////////////////////////////////////
1148 // PVideoOutputDevice
1149 
PVideoOutputDevice()1150 PVideoOutputDevice::PVideoOutputDevice()
1151 {
1152 }
1153 
1154 
CanCaptureVideo() const1155 PBoolean PVideoOutputDevice::CanCaptureVideo() const
1156 {
1157   return PFalse;
1158 }
1159 
1160 
GetPosition(int &,int &) const1161 PBoolean PVideoOutputDevice::GetPosition(int &, int &) const
1162 {
1163   return PFalse;
1164 }
1165 
1166 
SetPosition(int,int)1167 bool PVideoOutputDevice::SetPosition(int, int)
1168 {
1169   return false;
1170 }
1171 
1172 
1173 ///////////////////////////////////////////////////////////////////////////////
1174 // PVideoOutputDeviceRGB
1175 
PVideoOutputDeviceRGB()1176 PVideoOutputDeviceRGB::PVideoOutputDeviceRGB()
1177 {
1178   PTRACE(6, "RGB\t Constructor of PVideoOutputDeviceRGB");
1179 
1180   colourFormat = "RGB24";
1181   bytesPerPixel = 3;
1182   swappedRedAndBlue = false;
1183 //  SetFrameSize(frameWidth, frameHeight);
1184 }
1185 
1186 
SetColourFormat(const PString & colourFormat)1187 PBoolean PVideoOutputDeviceRGB::SetColourFormat(const PString & colourFormat)
1188 {
1189   PWaitAndSignal m(mutex);
1190 
1191   PINDEX newBytesPerPixel;
1192 
1193   if (colourFormat *= "RGB32") {
1194     newBytesPerPixel = 4;
1195     swappedRedAndBlue = false;
1196   }
1197   else if (colourFormat *= "RGB24") {
1198     newBytesPerPixel = 3;
1199     swappedRedAndBlue = false;
1200   }
1201   else if (colourFormat *= "BGR32") {
1202     newBytesPerPixel = 4;
1203     swappedRedAndBlue = true;
1204   }
1205   else if (colourFormat *= "BGR24") {
1206     newBytesPerPixel = 3;
1207     swappedRedAndBlue = true;
1208   }
1209   else
1210     return PFalse;
1211 
1212   if (!PVideoOutputDevice::SetColourFormat(colourFormat))
1213     return PFalse;
1214 
1215   bytesPerPixel = newBytesPerPixel;
1216   scanLineWidth = ((frameWidth*bytesPerPixel+3)/4)*4;
1217   return frameStore.SetSize(frameHeight*scanLineWidth);
1218 }
1219 
1220 
SetFrameSize(unsigned width,unsigned height)1221 PBoolean PVideoOutputDeviceRGB::SetFrameSize(unsigned width, unsigned height)
1222 {
1223   PWaitAndSignal m(mutex);
1224 
1225   if (frameWidth == width && frameHeight == height)
1226     return true;
1227 
1228   if (!PVideoOutputDevice::SetFrameSize(width, height))
1229     return PFalse;
1230 
1231   scanLineWidth = ((frameWidth*bytesPerPixel+3)/4)*4;
1232   return frameStore.SetSize(frameHeight*scanLineWidth);
1233 }
1234 
1235 
GetMaxFrameBytes()1236 PINDEX PVideoOutputDeviceRGB::GetMaxFrameBytes()
1237 {
1238   PWaitAndSignal m(mutex);
1239   return GetMaxFrameBytesConverted(frameStore.GetSize());
1240 }
1241 
1242 
SetFrameData(unsigned x,unsigned y,unsigned width,unsigned height,const BYTE * data,PBoolean endFrame)1243 PBoolean PVideoOutputDeviceRGB::SetFrameData(unsigned x, unsigned y,
1244                                          unsigned width, unsigned height,
1245                                          const BYTE * data,
1246                                          PBoolean endFrame)
1247 {
1248   PWaitAndSignal m(mutex);
1249 
1250   if (x+width > frameWidth || y+height > frameHeight || PAssertNULL(data) == NULL)
1251     return PFalse;
1252 
1253   if (x == 0 && width == frameWidth && y == 0 && height == frameHeight) {
1254     if (converter != NULL)
1255       converter->Convert(data, frameStore.GetPointer());
1256     else
1257       memcpy(frameStore.GetPointer(), data, height*scanLineWidth);
1258   }
1259   else {
1260     if (converter != NULL) {
1261       PAssertAlways("Converted output of partial RGB frame not supported");
1262       return PFalse;
1263     }
1264 
1265     if (x == 0 && width == frameWidth)
1266       memcpy(frameStore.GetPointer() + y*scanLineWidth, data, height*scanLineWidth);
1267     else {
1268       for (unsigned dy = 0; dy < height; dy++)
1269         memcpy(frameStore.GetPointer() + (y+dy)*scanLineWidth + x*bytesPerPixel,
1270                data + dy*width*bytesPerPixel, width*bytesPerPixel);
1271     }
1272   }
1273 
1274   if (endFrame)
1275     return FrameComplete();
1276 
1277   return PTrue;
1278 }
1279 
1280 
1281 ///////////////////////////////////////////////////////////////////////////////
1282 // PVideoOutputDevicePPM
1283 
1284 #ifdef SHOULD_BE_MOVED_TO_PLUGIN
1285 
PVideoOutputDevicePPM()1286 PVideoOutputDevicePPM::PVideoOutputDevicePPM()
1287 {
1288   PTRACE(6, "PPM\t Constructor of PVideoOutputDevicePPM");
1289   frameNumber = 0;
1290 }
1291 
1292 
Open(const PString & name,PBoolean)1293 PBoolean PVideoOutputDevicePPM::Open(const PString & name,
1294                                  PBoolean /*startImmediate*/)
1295 {
1296   Close();
1297 
1298   PFilePath path = name;
1299   if (!PDirectory::Exists(path.GetDirectory()))
1300     return PFalse;
1301 
1302   if (path != psprintf(path, 12345))
1303     deviceName = path;
1304   else
1305     deviceName = path.GetDirectory() + path.GetTitle() + "%u" + path.GetType();
1306 
1307   return PTrue;
1308 }
1309 
1310 
IsOpen()1311 PBoolean PVideoOutputDevicePPM::IsOpen()
1312 {
1313   return !deviceName;
1314 }
1315 
1316 
Close()1317 PBoolean PVideoOutputDevicePPM::Close()
1318 {
1319   deviceName.MakeEmpty();
1320   return PTrue;
1321 }
1322 
1323 
GetDeviceNames() const1324 PStringArray PVideoOutputDevicePPM::GetDeviceNames() const
1325 {
1326   return PDirectory();
1327 }
1328 
1329 
EndFrame()1330 PBoolean PVideoOutputDevicePPM::EndFrame()
1331 {
1332   PFile file;
1333   if (!file.Open(psprintf(deviceName, frameNumber++), PFile::WriteOnly)) {
1334     PTRACE(1, "PPMVid\tFailed to open PPM output file \""
1335            << file.GetName() << "\": " << file.GetErrorText());
1336     return PFalse;
1337   }
1338 
1339   file << "P6 " << frameWidth  << " " << frameHeight << " " << 255 << "\n";
1340 
1341   if (!file.Write(frameStore, frameStore.GetSize())) {
1342     PTRACE(1, "PPMVid\tFailed to write frame data to PPM output file " << file.GetName());
1343     return PFalse;
1344   }
1345 
1346   PTRACE(6, "PPMVid\tFinished writing PPM file " << file.GetName());
1347   return file.Close();
1348 }
1349 
1350 #endif // SHOULD_BE_MOVED_TO_PLUGIN
1351 
1352 
1353 ///////////////////////////////////////////////////////////////////////////////
1354 // PVideoInputDevice
1355 
CanCaptureVideo() const1356 PBoolean PVideoInputDevice::CanCaptureVideo() const
1357 {
1358   return PTrue;
1359 }
1360 
1361 static const char videoInputPluginBaseClass[] = "PVideoInputDevice";
1362 
1363 
GetDriverNames(PPluginManager * pluginMgr)1364 PStringArray PVideoInputDevice::GetDriverNames(PPluginManager * pluginMgr)
1365 {
1366   if (pluginMgr == NULL)
1367     pluginMgr = &PPluginManager::GetPluginManager();
1368 
1369   return pluginMgr->GetPluginsProviding(videoInputPluginBaseClass);
1370 }
1371 
1372 
GetDriversDeviceNames(const PString & driverName,PPluginManager * pluginMgr)1373 PStringArray PVideoInputDevice::GetDriversDeviceNames(const PString & driverName, PPluginManager * pluginMgr)
1374 {
1375   if (pluginMgr == NULL)
1376     pluginMgr = &PPluginManager::GetPluginManager();
1377 
1378   return pluginMgr->GetPluginsDeviceNames(driverName, videoInputPluginBaseClass);
1379 }
1380 
1381 
CreateDevice(const PString & driverName,PPluginManager * pluginMgr)1382 PVideoInputDevice * PVideoInputDevice::CreateDevice(const PString &driverName, PPluginManager * pluginMgr)
1383 {
1384   if (pluginMgr == NULL)
1385     pluginMgr = &PPluginManager::GetPluginManager();
1386 
1387   return (PVideoInputDevice *)pluginMgr->CreatePluginsDevice(driverName, videoInputPluginBaseClass);
1388 }
1389 
1390 
CreateDeviceByName(const PString & deviceName,const PString & driverName,PPluginManager * pluginMgr)1391 PVideoInputDevice * PVideoInputDevice::CreateDeviceByName(const PString & deviceName, const PString & driverName, PPluginManager * pluginMgr)
1392 {
1393   if (pluginMgr == NULL)
1394     pluginMgr = &PPluginManager::GetPluginManager();
1395 
1396   return (PVideoInputDevice *)pluginMgr->CreatePluginsDeviceByName(deviceName, videoInputPluginBaseClass,0,driverName);
1397 }
1398 
1399 
GetDeviceCapabilities(const PString & deviceName,Capabilities * caps,PPluginManager * pluginMgr)1400 PBoolean PVideoInputDevice::GetDeviceCapabilities(const PString & deviceName, Capabilities * caps, PPluginManager * pluginMgr)
1401 {
1402   return GetDeviceCapabilities(deviceName, "*", caps, pluginMgr);
1403 }
1404 
1405 
GetDeviceCapabilities(const PString & deviceName,const PString & driverName,Capabilities * caps,PPluginManager * pluginMgr)1406 PBoolean PVideoInputDevice::GetDeviceCapabilities(const PString & deviceName, const PString & driverName, Capabilities * caps, PPluginManager * pluginMgr)
1407 {
1408   if (pluginMgr == NULL)
1409     pluginMgr = &PPluginManager::GetPluginManager();
1410 
1411   return pluginMgr->GetPluginsDeviceCapabilities(videoInputPluginBaseClass,driverName,deviceName, caps);
1412 }
1413 
GetVideoInputControls()1414 PVideoInputControl * PVideoInputDevice::GetVideoInputControls()
1415 {
1416 	return NULL;
1417 }
1418 
1419 
CreateOpenedDevice(const PString & driverName,const PString & deviceName,PBoolean startImmediate,PPluginManager * pluginMgr)1420 PVideoInputDevice * PVideoInputDevice::CreateOpenedDevice(const PString & driverName,
1421                                                           const PString & deviceName,
1422                                                           PBoolean startImmediate,
1423                                                           PPluginManager * pluginMgr)
1424 {
1425   PString adjustedDeviceName = deviceName;
1426   PVideoInputDevice * device = CreateDeviceWithDefaults<PVideoInputDevice>(adjustedDeviceName, driverName, pluginMgr);
1427   if (device == NULL)
1428     return NULL;
1429 
1430   if (device->Open(adjustedDeviceName, startImmediate))
1431     return device;
1432 
1433   delete device;
1434   return NULL;
1435 }
1436 
1437 
CreateOpenedDevice(const OpenArgs & args,PBoolean startImmediate)1438 PVideoInputDevice * PVideoInputDevice::CreateOpenedDevice(const OpenArgs & args,
1439                                                           PBoolean startImmediate)
1440 {
1441   OpenArgs adjustedArgs = args;
1442   PVideoInputDevice * device = CreateDeviceWithDefaults<PVideoInputDevice>(adjustedArgs.deviceName, args.driverName, NULL);
1443   if (device == NULL)
1444     return NULL;
1445 
1446   if (device->OpenFull(adjustedArgs, startImmediate))
1447     return device;
1448 
1449   delete device;
1450   return NULL;
1451 }
1452 
1453 
SetNearestFrameSize(unsigned width,unsigned height)1454 PBoolean PVideoInputDevice::SetNearestFrameSize(unsigned width, unsigned height)
1455 {
1456   if (PVideoDevice::SetNearestFrameSize(width, height))
1457     return true;
1458 
1459   // Get the discrete sizes grabber is capable of
1460   Capabilities caps;
1461   if (!GetDeviceCapabilities(&caps))
1462     return false;
1463 
1464   // First try and pick one with the same width
1465   std::list<PVideoFrameInfo>::iterator it;
1466   for (it = caps.framesizes.begin(); it != caps.framesizes.end(); ++it) {
1467     if (it->GetFrameWidth() == width)
1468       return SetFrameSize(width, it->GetFrameHeight());
1469   }
1470 
1471   // Then try for the same height
1472   for (it = caps.framesizes.begin(); it != caps.framesizes.end(); ++it) {
1473     if (it->GetFrameHeight() == height)
1474       return SetFrameSize(it->GetFrameWidth(), height);
1475   }
1476 
1477   // Then try for double the size
1478   for (it = caps.framesizes.begin(); it != caps.framesizes.end(); ++it) {
1479     unsigned w, h;
1480     it->GetFrameSize(w, h);
1481     if (w == width*2 && h == height*2)
1482       return SetFrameSize(w, h);
1483   }
1484 
1485   // Then try for half the size
1486   for (it = caps.framesizes.begin(); it != caps.framesizes.end(); ++it) {
1487     unsigned w, h;
1488     it->GetFrameSize(w, h);
1489     if (w == width/2 && h == height/2)
1490       return SetFrameSize(w, h);
1491   }
1492 
1493   // Now try and pick one that has the nearest number of pixels in total.
1494   unsigned pixels = width*height;
1495   unsigned widthToUse = 0, heightToUse = 0;
1496   int diff = INT_MAX;
1497   for (it = caps.framesizes.begin(); it != caps.framesizes.end(); ++it) {
1498     unsigned w, h;
1499     it->GetFrameSize(w, h);
1500     int d = w*h - pixels;
1501     if (d < 0)
1502       d = -d;
1503     if (diff > d &&
1504           // Ensure we don't pick one dimension greater and one
1505           // lower because we can't shrink one and grow the other.
1506           ((w < width && h < height) ||
1507 	       (w > width && h > height))
1508     ) {
1509       diff = d;
1510       widthToUse = w;
1511       heightToUse = h;
1512     }
1513   }
1514 
1515   if (widthToUse == 0)
1516     return false;
1517 
1518   return SetFrameSize(widthToUse, heightToUse);
1519 }
1520 
1521 
GetFrame(PBYTEArray & frame)1522 PBoolean PVideoInputDevice::GetFrame(PBYTEArray & frame)
1523 {
1524   PINDEX returned;
1525   if (!GetFrameData(frame.GetPointer(GetMaxFrameBytes()), &returned))
1526     return PFalse;
1527 
1528   frame.SetSize(returned);
1529   return PTrue;
1530 }
1531 
GetFrameData(BYTE * buffer,PINDEX * bytesReturned,unsigned int & flags)1532 PBoolean PVideoInputDevice::GetFrameData(
1533   BYTE * buffer,
1534   PINDEX * bytesReturned,
1535   unsigned int & flags
1536 )
1537 {
1538   flags = 0;
1539   return GetFrameData(buffer, bytesReturned);
1540 }
1541 
GetFrameDataNoDelay(BYTE * buffer,PINDEX * bytesReturned,unsigned & flags)1542 PBoolean PVideoInputDevice::GetFrameDataNoDelay(
1543   BYTE * buffer,
1544   PINDEX * bytesReturned,
1545   unsigned & flags
1546 )
1547 {
1548   flags = 0;
1549   return GetFrameDataNoDelay(buffer, bytesReturned);
1550 }
1551 
FlowControl(const void *)1552 bool PVideoInputDevice::FlowControl(const void * /*flowData*/)
1553 {
1554     return false;
1555 }
1556 
1557 
SetCaptureMode(unsigned)1558 bool PVideoInputDevice::SetCaptureMode(unsigned)
1559 {
1560   return false;
1561 }
1562 
1563 
GetCaptureMode() const1564 int PVideoInputDevice::GetCaptureMode() const
1565 {
1566   return -1;
1567 }
1568 
1569 
SetFrameData(unsigned x,unsigned y,unsigned width,unsigned height,const BYTE * data,PBoolean endFrame,unsigned)1570 PBoolean PVideoOutputDevice::SetFrameData(
1571       unsigned x,
1572       unsigned y,
1573       unsigned width,
1574       unsigned height,
1575       const BYTE * data,
1576       PBoolean endFrame,
1577       unsigned /*flags*/
1578 )
1579 {
1580   return SetFrameData(x, y, width, height, data, endFrame);
1581 }
1582 
SetFrameData(unsigned x,unsigned y,unsigned width,unsigned height,unsigned,unsigned,const BYTE * data,PBoolean endFrame,unsigned flags,const void *)1583 PBoolean PVideoOutputDevice::SetFrameData(
1584       unsigned x,
1585       unsigned y,
1586       unsigned width,
1587       unsigned height,
1588       unsigned /*sarwidth*/,
1589       unsigned /*sarheight*/,
1590       const BYTE * data,
1591       PBoolean endFrame,
1592       unsigned flags,
1593 	  const void * /*mark*/
1594 )
1595 {
1596   return SetFrameData(x, y, width, height, data, endFrame, flags);
1597 }
1598 
DisableDecode()1599 PBoolean PVideoOutputDevice::DisableDecode()
1600 {
1601 	return false;
1602 }
1603 
1604 
1605 ////////////////////////////////////////////////////////////////////////////////////////////
1606 
1607 static const char videoOutputPluginBaseClass[] = "PVideoOutputDevice";
1608 
1609 
GetDriverNames(PPluginManager * pluginMgr)1610 PStringArray PVideoOutputDevice::GetDriverNames(PPluginManager * pluginMgr)
1611 {
1612   if (pluginMgr == NULL)
1613     pluginMgr = &PPluginManager::GetPluginManager();
1614 
1615   return pluginMgr->GetPluginsProviding(videoOutputPluginBaseClass);
1616 }
1617 
1618 
GetDriversDeviceNames(const PString & driverName,PPluginManager * pluginMgr)1619 PStringArray PVideoOutputDevice::GetDriversDeviceNames(const PString & driverName, PPluginManager * pluginMgr)
1620 {
1621   if (pluginMgr == NULL)
1622     pluginMgr = &PPluginManager::GetPluginManager();
1623 
1624   return pluginMgr->GetPluginsDeviceNames(driverName, videoOutputPluginBaseClass);
1625 }
1626 
1627 
CreateDevice(const PString & driverName,PPluginManager * pluginMgr)1628 PVideoOutputDevice * PVideoOutputDevice::CreateDevice(const PString & driverName, PPluginManager * pluginMgr)
1629 {
1630   if (pluginMgr == NULL)
1631     pluginMgr = &PPluginManager::GetPluginManager();
1632 
1633   return (PVideoOutputDevice *)pluginMgr->CreatePluginsDevice(driverName, videoOutputPluginBaseClass);
1634 }
1635 
1636 
CreateDeviceByName(const PString & deviceName,const PString & driverName,PPluginManager * pluginMgr)1637 PVideoOutputDevice * PVideoOutputDevice::CreateDeviceByName(const PString & deviceName, const PString & driverName, PPluginManager * pluginMgr)
1638 {
1639   if (pluginMgr == NULL)
1640     pluginMgr = &PPluginManager::GetPluginManager();
1641 
1642   return (PVideoOutputDevice *)pluginMgr->CreatePluginsDeviceByName(deviceName, videoOutputPluginBaseClass, 0, driverName);
1643 }
1644 
1645 
CreateOpenedDevice(const PString & driverName,const PString & deviceName,PBoolean startImmediate,PPluginManager * pluginMgr)1646 PVideoOutputDevice * PVideoOutputDevice::CreateOpenedDevice(const PString &driverName,
1647                                                             const PString &deviceName,
1648                                                             PBoolean startImmediate,
1649                                                             PPluginManager * pluginMgr)
1650 {
1651   PString adjustedDeviceName = deviceName;
1652   PVideoOutputDevice * device = CreateDeviceWithDefaults<PVideoOutputDevice>(adjustedDeviceName, driverName, pluginMgr);
1653   if (device == NULL)
1654     return NULL;
1655 
1656   if (device->Open(adjustedDeviceName, startImmediate))
1657     return device;
1658 
1659   delete device;
1660   return NULL;
1661 }
1662 
1663 
CreateOpenedDevice(const OpenArgs & args,PBoolean startImmediate)1664 PVideoOutputDevice * PVideoOutputDevice::CreateOpenedDevice(const OpenArgs & args,
1665                                                             PBoolean startImmediate)
1666 {
1667   OpenArgs adjustedArgs = args;
1668   PVideoOutputDevice * device = CreateDeviceWithDefaults<PVideoOutputDevice>(adjustedArgs.deviceName, args.driverName, NULL);
1669   if (device == NULL)
1670     return NULL;
1671 
1672   if (device->OpenFull(adjustedArgs, startImmediate))
1673     return device;
1674 
1675   delete device;
1676   return NULL;
1677 }
1678 
1679 #endif // P_VIDEO
1680 
1681 // End Of File ///////////////////////////////////////////////////////////////
1682