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