Changed output and intermediate directories, tuned up compile parameters for Windows...
[pwlib.git] / src / ptclib / pvfiledev.cxx
blobc875f5f86aff8c99834e0d8287cf1a17800444af
1 /*
2 * pvfiledev.cxx
4 * Video file declaration
6 * Portable Windows Library
8 * Copyright (C) 2004 Post Increment
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * 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.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is
23 * Craig Southeren <craigs@postincrement.com>
25 * All Rights Reserved.
27 * Contributor(s): ______________________________________.
29 * $Log$
30 * Revision 1.12 2007/04/03 12:09:38 rjongbloed
31 * Fixed various "file video device" issues:
32 * Remove filename from PVideoDevice::OpenArgs (use deviceName)
33 * Added driverName to PVideoDevice::OpenArgs (so can select YUVFile)
34 * Added new statics to create correct video input/output device object
35 * given a PVideoDevice::OpenArgs structure.
36 * Fixed begin able to write to YUVFile when YUV420P colour format
37 * is not actually selected.
38 * Fixed truncating output video file if overwriting.
40 * Revision 1.11 2007/04/02 05:29:54 rjongbloed
41 * Tidied some trace logs to assure all have a category (bit before a tab character) set.
43 * Revision 1.10 2006/11/01 00:46:01 csoutheren
44 * Fix problem in video output file device
46 * Revision 1.9 2006/10/31 04:10:40 csoutheren
47 * Make sure PVidFileDev class is loaded, and make it work with OPAL
49 * Revision 1.8 2006/06/21 03:28:44 csoutheren
50 * Various cleanups thanks for Frederic Heem
52 * Revision 1.7 2006/04/19 04:09:04 csoutheren
53 * Allow frame size conversions
55 * Revision 1.6 2006/03/17 06:55:33 csoutheren
56 * Removed unused member variable
58 * Revision 1.5 2006/03/06 06:04:13 csoutheren
59 * Added YUVFile video output device
61 * Revision 1.4 2006/02/24 04:51:26 csoutheren
62 * Fixed problem with using CIF from video files
63 * Added support for video files in y4m format
65 * Revision 1.3 2006/02/20 09:31:58 csoutheren
66 * Fixed link problem on Linux
68 * Revision 1.2 2006/02/20 06:49:45 csoutheren
69 * Added video file and video file input device code
71 * Revision 1.1 2006/02/20 06:17:28 csoutheren
72 * Added ability to read video from a file
76 #ifdef __GNUC__
77 #pragma implementation "pvfiledev.h"
78 #endif
80 #define P_FORCE_STATIC_PLUGIN
82 #include <ptlib.h>
84 #if P_VIDFILE
86 namespace PWLibStupidHacks {
87 int loadVideoFileStuff;
90 #include <ptlib/vconvert.h>
91 #include <ptclib/pvfiledev.h>
92 #include <ptlib/pfactory.h>
93 #include <ptlib/pluginmgr.h>
94 #include <ptlib/videoio.h>
96 ///////////////////////////////////////////////////////////////////////////////
97 // PVideoInputDevice_YUVFile
99 PINSTANTIATE_FACTORY(PVideoInputDevice, YUVFile)
101 class PVideoInputDevice_YUVFile_PluginServiceDescriptor : public PDevicePluginServiceDescriptor
103 public:
104 virtual PObject * CreateInstance(int /*userData*/) const { return new PVideoInputDevice_YUVFile; }
105 virtual PStringList GetDeviceNames(int /*userData*/) const { return PVideoInputDevice_YUVFile::GetInputDeviceNames(); }
106 virtual bool ValidateDeviceName(const PString & deviceName, int /*userData*/) const { return PFile::Access(deviceName, PFile::ReadOnly); }
107 } PVideoInputDevice_YUVFile_descriptor;
109 PCREATE_PLUGIN(YUVFile, PVideoInputDevice, &PVideoInputDevice_YUVFile_descriptor);
113 PVideoInputDevice_YUVFile::PVideoInputDevice_YUVFile()
115 SetColourFormat("YUV420P");
116 channelNumber = 0;
117 grabCount = 0;
118 SetFrameRate(10);
122 BOOL PVideoInputDevice_YUVFile::Open(const PString & devName, BOOL /*startImmediate*/)
124 PFilePath fn(devName);
126 if (!file.Open(fn, PFile::ReadOnly, PFile::MustExist))
127 return FALSE;
129 deviceName = fn.GetTitle();
131 return TRUE;
135 BOOL PVideoInputDevice_YUVFile::IsOpen()
137 return file.IsOpen();
141 BOOL PVideoInputDevice_YUVFile::Close()
143 return file.Close();
147 BOOL PVideoInputDevice_YUVFile::Start()
149 return TRUE;
153 BOOL PVideoInputDevice_YUVFile::Stop()
155 return TRUE;
159 BOOL PVideoInputDevice_YUVFile::IsCapturing()
161 return IsOpen();
165 PStringList PVideoInputDevice_YUVFile::GetInputDeviceNames()
167 PStringList list;
168 list.AppendString("*.yuv");
169 return list;
173 BOOL PVideoInputDevice_YUVFile::SetVideoFormat(VideoFormat newFormat)
175 return PVideoDevice::SetVideoFormat(newFormat);
179 int PVideoInputDevice_YUVFile::GetNumChannels()
181 return ChannelCount;
185 BOOL PVideoInputDevice_YUVFile::SetChannel(int newChannel)
187 return PVideoDevice::SetChannel(newChannel);
190 BOOL PVideoInputDevice_YUVFile::SetColourFormat(const PString & newFormat)
192 if (!(newFormat *= "YUV420P"))
193 return FALSE;
195 return PVideoDevice::SetColourFormat(newFormat);
199 BOOL PVideoInputDevice_YUVFile::SetFrameRate(unsigned rate)
201 if (rate < 1)
202 rate = 1;
203 else if (rate > 50)
204 rate = 50;
206 return PVideoDevice::SetFrameRate(rate);
210 BOOL PVideoInputDevice_YUVFile::GetFrameSizeLimits(unsigned & minWidth,
211 unsigned & minHeight,
212 unsigned & maxWidth,
213 unsigned & maxHeight)
215 if (file.GetWidth() != 0 && file.GetHeight() != 0) {
216 minWidth = maxWidth = file.GetWidth();
217 minHeight = maxHeight = file.GetHeight();
219 else
221 minWidth = 16;
222 minHeight = 12;
223 maxWidth = 1024;
224 maxHeight = 768;
227 return TRUE;
230 BOOL PVideoInputDevice_YUVFile::SetFrameSizeConverter(
231 unsigned width, ///< New width of frame
232 unsigned height, ///< New height of frame
233 BOOL bScaleNotCrop ///< Scale or crop/pad preference
236 // if the file does not know what size it is, then set it
237 if (file.GetWidth() == 0 && file.GetHeight() == 0) {
238 file.SetWidth(width);
239 file.SetHeight(height);
242 return PVideoInputDevice::SetFrameSizeConverter(width, height, bScaleNotCrop);
245 BOOL PVideoInputDevice_YUVFile::SetFrameSize(unsigned width, unsigned height)
247 // if the file does not know what size it is, then set it
248 if (file.GetWidth() == 0 && file.GetHeight() == 0) {
249 file.SetWidth(width);
250 file.SetHeight(height);
253 if (width != (unsigned)file.GetWidth() || height != (unsigned)file.GetHeight())
254 return FALSE;
256 frameWidth = width;
257 frameHeight = height;
259 videoFrameSize = CalculateFrameBytes(frameWidth, frameHeight, colourFormat);
260 scanLineWidth = videoFrameSize/frameHeight;
261 return videoFrameSize > 0;
265 PINDEX PVideoInputDevice_YUVFile::GetMaxFrameBytes()
267 return GetMaxFrameBytesConverted(videoFrameSize);
271 BOOL PVideoInputDevice_YUVFile::GetFrameData(BYTE * buffer, PINDEX * bytesReturned)
273 frameTimeError += msBetweenFrames;
275 PTime now;
276 PTimeInterval delay = now - previousFrameTime;
277 frameTimeError -= (int)delay.GetMilliSeconds();
278 previousFrameTime = now;
280 if (frameTimeError > 0) {
281 PTRACE(6, "YUVFile\tSleep for " << frameTimeError << " milli seconds");
282 PThread::Sleep(frameTimeError);
285 return GetFrameDataNoDelay(buffer, bytesReturned);
289 BOOL PVideoInputDevice_YUVFile::GetFrameDataNoDelay(BYTE *destFrame, PINDEX * bytesReturned)
291 grabCount++;
293 BYTE * readBuffer = destFrame;
295 if (converter != NULL)
296 readBuffer = frameStore.GetPointer(videoFrameSize);
298 if (file.IsOpen()) {
299 if (!file.ReadFrame(readBuffer))
300 file.Close();
303 if (!file.IsOpen()) {
304 switch (channelNumber) {
305 case Channel_PlayAndClose:
306 default:
307 return FALSE;
309 case Channel_PlayAndRepeat:
310 if (!file.Open() || !file.ReadFrame(readBuffer))
311 return FALSE;
312 break;
314 case Channel_PlayAndKeepLast:
315 break;
317 case Channel_PlayAndShowBlack:
318 FillRect(readBuffer, 0, 0, frameWidth, frameHeight, 0, 0, 0);
319 break;
323 if (converter == NULL) {
324 if (bytesReturned != NULL)
325 *bytesReturned = videoFrameSize;
326 } else {
327 converter->SetSrcFrameSize(frameWidth, frameHeight);
328 if (!converter->Convert(readBuffer, destFrame, bytesReturned))
329 return FALSE;
330 if (bytesReturned != NULL)
331 *bytesReturned = converter->GetMaxDstFrameBytes();
334 return TRUE;
338 void PVideoInputDevice_YUVFile::GrabBlankImage(BYTE *resFrame)
340 // Change colour every second, cycle is:
341 // black, red, green, yellow, blue, magenta, cyan, white
342 int mask = grabCount/frameRate;
343 FillRect(resFrame,
344 0, 0, frameWidth, frameHeight, //Fill the whole frame with the colour.
345 (mask&1) ? 255 : 0, // red
346 (mask&2) ? 255 : 0, // green
347 (mask&4) ? 255 : 0);//blue
350 void PVideoInputDevice_YUVFile::FillRect(BYTE * frame,
351 int xPos, int initialYPos,
352 int rectWidth, int rectHeight,
353 int r, int g, int b)
355 // PTRACE(0,"x,y is"<<xPos<<" "<<yPos<<" and size is "<<rectWidth<<" "<<rectHeight);
357 //This routine fills a region of the video image with data. It is used as the central
358 //point because one only has to add other image formats here.
360 int yPos = initialYPos;
362 int offset = ( yPos * frameWidth ) + xPos;
363 int colourOffset = ( (yPos * frameWidth) >> 2) + (xPos >> 1);
365 int Y = ( 257 * r + 504 * g + 98 * b)/1000 + 16;
366 int Cb = (-148 * r - 291 * g + 439 * b)/1000 + 128;
367 int Cr = ( 439 * r - 368 * g - 71 * b)/1000 + 128;
369 unsigned char * Yptr = frame + offset;
370 unsigned char * CbPtr = frame + (frameWidth * frameHeight) + colourOffset;
371 unsigned char * CrPtr = frame + (frameWidth * frameHeight) + (frameWidth * frameHeight/4) + colourOffset;
373 int rr ;
374 int halfRectWidth = rectWidth >> 1;
375 int halfWidth = frameWidth >> 1;
377 for (rr = 0; rr < rectHeight;rr+=2) {
378 memset(Yptr, Y, rectWidth);
379 Yptr += frameWidth;
380 memset(Yptr, Y, rectWidth);
381 Yptr += frameWidth;
383 memset(CbPtr, Cb, halfRectWidth);
384 memset(CrPtr, Cr, halfRectWidth);
386 CbPtr += halfWidth;
387 CrPtr += halfWidth;
391 ///////////////////////////////////////////////////////////////////////////////
392 // PVideoOutputDevice_YUVFile
394 PINSTANTIATE_FACTORY(PVideoOutputDevice, YUVFile)
396 class PVideoOutputDevice_YUVFile_PluginServiceDescriptor : public PDevicePluginServiceDescriptor
398 public:
399 virtual PObject * CreateInstance(int /*userData*/) const { return new PVideoOutputDevice_YUVFile; }
400 virtual PStringList GetDeviceNames(int /*userData*/) const { return PVideoOutputDevice_YUVFile::GetOutputDeviceNames(); }
401 virtual bool ValidateDeviceName(const PString & deviceName, int /*userData*/) const { return PFile::Access(deviceName, PFile::WriteOnly); }
402 } PVideoOutputDevice_YUVFile_descriptor;
404 PCREATE_PLUGIN(YUVFile, PVideoOutputDevice, &PVideoOutputDevice_YUVFile_descriptor);
407 PVideoOutputDevice_YUVFile::PVideoOutputDevice_YUVFile()
412 BOOL PVideoOutputDevice_YUVFile::Open(const PString & _deviceName, BOOL /*startImmediate*/)
414 deviceName = _deviceName;
415 if (!file.Open(deviceName, PFile::WriteOnly, PFile::Create|PFile::Truncate)) {
416 PTRACE(1, "YUVFile\tCannot create file " << deviceName << " as video output device");
417 return FALSE;
420 return TRUE;
423 BOOL PVideoOutputDevice_YUVFile::Close()
425 return file.Close();
428 BOOL PVideoOutputDevice_YUVFile::Start()
430 file.SetHeight(frameHeight);
431 file.SetWidth(frameWidth);
432 return TRUE;
435 BOOL PVideoOutputDevice_YUVFile::Stop()
437 return TRUE;
440 BOOL PVideoOutputDevice_YUVFile::IsOpen()
442 return file.IsOpen();
446 PStringList PVideoOutputDevice_YUVFile::GetOutputDeviceNames()
448 PStringList list;
449 list.AppendString("*.yuv");
450 return list;
454 BOOL PVideoOutputDevice_YUVFile::SetColourFormat(const PString & newFormat)
456 if (!(newFormat *= "YUV420P"))
457 return FALSE;
459 return PVideoDevice::SetColourFormat(newFormat);
463 PINDEX PVideoOutputDevice_YUVFile::GetMaxFrameBytes()
465 return GetMaxFrameBytesConverted(CalculateFrameBytes(frameWidth, frameHeight, colourFormat));
469 BOOL PVideoOutputDevice_YUVFile::SetFrameData(unsigned x, unsigned y,
470 unsigned width, unsigned height,
471 const BYTE * data,
472 BOOL /*endFrame*/)
474 if (x != 0 || y != 0 || width != frameWidth || height != frameHeight) {
475 PTRACE(1, "YUVFile\tOutput device only supports full frame writes");
476 return FALSE;
479 if ((file.GetWidth() == 0) && (file.GetHeight() == 0)) {
480 file.SetWidth(width);
481 file.SetHeight(height);
483 else if (((unsigned)file.GetWidth() != width) || ((unsigned)file.GetHeight() != height))
484 return FALSE;
486 if (converter == NULL)
487 return file.WriteFrame(data);
489 PBYTEArray tempStore;
490 converter->Convert(data, tempStore.GetPointer(GetMaxFrameBytes()));
491 return file.WriteFrame(tempStore);
495 BOOL PVideoOutputDevice_YUVFile::EndFrame()
497 return TRUE;
502 #endif // P_VIDFILE