1 /*
2  * pvidfile.cxx
3  *
4  * Video file implementation
5  *
6  * Portable Windows Library
7  *
8  * Copyright (C) 2004 Post Increment
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
23  * Craig Southeren <craigs@postincrement.com>
24  *
25  * All Rights Reserved.
26  *
27  * Contributor(s): ______________________________________.
28  *
29  * $Revision: 26686 $
30  * $Author: rjongbloed $
31  * $Date: 2011-11-23 20:22:20 -0600 (Wed, 23 Nov 2011) $
32  */
33 
34 #ifdef __GNUC__
35 #pragma implementation "pvidfile.h"
36 #endif
37 
38 #include <ptlib.h>
39 
40 #if P_VIDEO
41 #if P_VIDFILE
42 
43 #include <ptclib/pvidfile.h>
44 #include <ptlib/videoio.h>
45 
46 
47 ///////////////////////////////////////////////////////////////////////////////
48 
PVideoFile()49 PVideoFile::PVideoFile()
50   : m_fixedFrameSize(false)
51   , m_fixedFrameRate(false)
52   , m_frameBytes(CalculateFrameBytes())
53   , m_headerOffset(0)
54 {
55 }
56 
57 
Open(const PFilePath & name,PFile::OpenMode mode,int opts)58 PBoolean PVideoFile::Open(const PFilePath & name, PFile::OpenMode mode, int opts)
59 {
60   static PRegularExpression res("_(sqcif|qcif|cif|cif4|cif16|[0-9]+x[0-9]+)[^a-z0-9]", PRegularExpression::Extended|PRegularExpression::IgnoreCase);
61   static PRegularExpression fps("_[0-9]+fps[^a-z]",     PRegularExpression::Extended|PRegularExpression::IgnoreCase);
62 
63   PINDEX pos, len;
64 
65   if (name.FindRegEx(res, pos, len)) {
66     m_fixedFrameSize = Parse(name.Mid(pos+1, len-2));
67     if (m_fixedFrameSize)
68       m_frameBytes = CalculateFrameBytes();
69   }
70 
71   if ((pos = name.FindRegEx(fps)) != P_MAX_INDEX)
72     m_fixedFrameRate = PVideoFrameInfo::SetFrameRate(name.Mid(pos+1).AsUnsigned());
73 
74   return m_file.Open(name, mode, opts);
75 }
76 
77 
WriteFrame(const void * frame)78 PBoolean PVideoFile::WriteFrame(const void * frame)
79 {
80   return m_file.Write(frame, m_frameBytes);
81 }
82 
83 
ReadFrame(void * frame)84 PBoolean PVideoFile::ReadFrame(void * frame)
85 {
86   if (m_file.Read(frame, m_frameBytes) && m_file.GetLastReadCount() == m_frameBytes)
87     return true;
88 
89 #if PTRACING
90   if (m_file.GetErrorCode(PFile::LastReadError) != PFile::NoError)
91     PTRACE(2, "VidFile\tError reading file \"" << m_file.GetFilePath()
92            << "\" - " << m_file.GetErrorText(PFile::LastReadError));
93   else
94     PTRACE(4, "VidFile\tEnd of file \"" << m_file.GetFilePath() << '"');
95 #endif
96   return false;
97 }
98 
99 
GetLength() const100 off_t PVideoFile::GetLength() const
101 {
102   off_t len = m_file.GetLength();
103   return len < m_headerOffset ? 0 : ((len - m_headerOffset)/m_frameBytes);
104 }
105 
106 
SetLength(off_t len)107 PBoolean PVideoFile::SetLength(off_t len)
108 {
109   return m_file.SetLength(len*m_frameBytes + m_headerOffset);
110 }
111 
112 
GetPosition() const113 off_t PVideoFile::GetPosition() const
114 {
115   off_t pos = m_file.GetPosition();
116   return pos < m_headerOffset ? 0 : ((pos - m_headerOffset)/m_frameBytes);
117 }
118 
119 
SetPosition(off_t pos,PFile::FilePositionOrigin origin)120 PBoolean PVideoFile::SetPosition(off_t pos, PFile::FilePositionOrigin origin)
121 {
122   pos *= m_frameBytes;
123   if (origin == PFile::Start)
124     pos += m_headerOffset;
125 
126   return m_file.SetPosition(pos, origin);
127 }
128 
129 
SetFrameSize(unsigned width,unsigned height)130 PBoolean PVideoFile::SetFrameSize(unsigned width, unsigned height)
131 {
132   if (frameWidth == width && frameHeight == height)
133     return true;
134 
135   if (m_fixedFrameSize)
136     return false;
137 
138   if (!PVideoFrameInfo::SetFrameSize(width, height))
139     return false;
140 
141   m_frameBytes = CalculateFrameBytes();
142   return m_frameBytes > 0;
143 }
144 
145 
SetFrameRate(unsigned rate)146 PBoolean PVideoFile::SetFrameRate(unsigned rate)
147 {
148   if (frameRate == rate)
149     return true;
150 
151   if (m_fixedFrameRate)
152     return false;
153 
154   return PVideoFrameInfo::SetFrameRate(rate);
155 }
156 
157 
158 
159 ///////////////////////////////////////////////////////////////////////////////
160 
161 PFACTORY_CREATE(PFactory<PVideoFile>, PYUVFile, "yuv", false);
162 static PFactory<PVideoFile>::Worker<PYUVFile> y4mFileFactory("y4m");
163 
164 
PYUVFile()165 PYUVFile::PYUVFile()
166   : m_y4mMode(false)
167 {
168 }
169 
170 
Open(const PFilePath & name,PFile::OpenMode mode,int opts)171 PBoolean PYUVFile::Open(const PFilePath & name, PFile::OpenMode mode, int opts)
172 {
173   if (!PVideoFile::Open(name, mode, opts))
174     return false;
175 
176   m_y4mMode = name.GetType() *= ".y4m";
177 
178   if (m_y4mMode) {
179     int ch;
180     do {
181       if ((ch = m_file.ReadChar()) < 0)
182         return false;
183     }
184     while (ch != '\n');
185     m_headerOffset = m_file.GetPosition();
186   }
187 
188   return true;
189 }
190 
191 
WriteFrame(const void * frame)192 PBoolean PYUVFile::WriteFrame(const void * frame)
193 {
194   if (m_y4mMode)
195     m_file.WriteChar('\n');
196 
197   return m_file.Write(frame, m_frameBytes);
198 }
199 
200 
ReadFrame(void * frame)201 PBoolean PYUVFile::ReadFrame(void * frame)
202 {
203   if (m_y4mMode) {
204     PString info;
205     info.ReadFrom(m_file);
206     PTRACE(4, "VidFile\ty4m \"" << info << '"');
207   }
208 
209   return PVideoFile::ReadFrame(frame);
210 }
211 
212 
213 #endif  // P_VIDFILE
214 #endif  // P_VIDEO
215