/src/vvenc/source/Lib/apputils/YuvFileIO.h
Line | Count | Source |
1 | | /* ----------------------------------------------------------------------------- |
2 | | The copyright in this software is being made available under the Clear BSD |
3 | | License, included below. No patent rights, trademark rights and/or |
4 | | other Intellectual Property Rights other than the copyrights concerning |
5 | | the Software are granted under this license. |
6 | | |
7 | | The Clear BSD License |
8 | | |
9 | | Copyright (c) 2019-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVenC Authors. |
10 | | All rights reserved. |
11 | | |
12 | | Redistribution and use in source and binary forms, with or without modification, |
13 | | are permitted (subject to the limitations in the disclaimer below) provided that |
14 | | the following conditions are met: |
15 | | |
16 | | * Redistributions of source code must retain the above copyright notice, |
17 | | this list of conditions and the following disclaimer. |
18 | | |
19 | | * Redistributions in binary form must reproduce the above copyright |
20 | | notice, this list of conditions and the following disclaimer in the |
21 | | documentation and/or other materials provided with the distribution. |
22 | | |
23 | | * Neither the name of the copyright holder nor the names of its |
24 | | contributors may be used to endorse or promote products derived from this |
25 | | software without specific prior written permission. |
26 | | |
27 | | NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY |
28 | | THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
29 | | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
30 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
31 | | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
32 | | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
33 | | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
34 | | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
35 | | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
36 | | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
37 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
38 | | POSSIBILITY OF SUCH DAMAGE. |
39 | | |
40 | | |
41 | | ------------------------------------------------------------------------------------------- */ |
42 | | /** \file YuvFileIO.h |
43 | | \brief yuv file I/O class (header) |
44 | | */ |
45 | | |
46 | | #pragma once |
47 | | |
48 | | #include <iostream> |
49 | | #include <fstream> |
50 | | #include <sstream> |
51 | | #include <string> |
52 | | #include <vector> |
53 | | #include <algorithm> |
54 | | #include <regex> |
55 | | |
56 | | #include "vvenc/vvencCfg.h" |
57 | | #include "vvenc/vvenc.h" |
58 | | |
59 | | #include "FileIOHelper.h" |
60 | | #include "LogoRenderer.h" |
61 | | |
62 | | #if defined (_WIN32) || defined (WIN32) || defined (_WIN64) || defined (WIN64) |
63 | | #include <io.h> |
64 | | #include <fcntl.h> |
65 | | #endif |
66 | | |
67 | | //! \ingroup Interface |
68 | | //! \{ |
69 | | |
70 | | struct vvencYUVBuffer; |
71 | | |
72 | | namespace apputils { |
73 | | |
74 | | typedef int16_t LPel; |
75 | | |
76 | | // ==================================================================================================================== |
77 | | |
78 | | class YuvFileIO |
79 | | { |
80 | | private: |
81 | | std::string m_lastError; ///< temporal storage for last occured error |
82 | | std::fstream m_cHandle; ///< file handle |
83 | | int m_fileBitdepth = 0; ///< bitdepth of input/output video file |
84 | | int m_MSBExtendedBitDepth = 0; ///< bitdepth after addition of MSBs (with value 0) |
85 | | int m_bitdepthShift = 0; ///< number of bits to increase or decrease image by before/after write/read |
86 | | vvencChromaFormat m_fileChrFmt = VVENC_CHROMA_420; ///< chroma format of the file |
87 | | vvencChromaFormat m_bufferChrFmt = VVENC_CHROMA_420; ///< chroma format of the buffer |
88 | | bool m_clipToRec709 = false; ///< clip data according to Recom.709 |
89 | | bool m_packedYUVMode = false; ///< used packed buffer file format |
90 | | bool m_readStdin = false; ///< read input from stdin |
91 | | bool m_y4mMode = false; ///< use/force y4m file format |
92 | | size_t m_packetCount = 0; |
93 | | LogoRenderer m_cLogoRenderer; |
94 | | |
95 | | public: |
96 | | |
97 | | int open( const std::string &fileName, bool bWriteMode, int fileBitDepth, int MSBExtendedBitDepth, int internalBitDepth, |
98 | | vvencChromaFormat fileChrFmt, vvencChromaFormat bufferChrFmt, bool clipToRec709, bool packedYUVMode, bool y4mMode, |
99 | | std::string cLogoFilename = "" ) |
100 | 0 | { |
101 | 0 | //NOTE: files cannot have bit depth greater than 16 |
102 | 0 | m_fileBitdepth = std::min<unsigned>( fileBitDepth, 16 ); |
103 | 0 | m_MSBExtendedBitDepth = MSBExtendedBitDepth; |
104 | 0 | m_bitdepthShift = internalBitDepth - m_MSBExtendedBitDepth; |
105 | 0 | if( internalBitDepth == 8 && fileBitDepth == 10 && MSBExtendedBitDepth == fileBitDepth ) |
106 | 0 | { |
107 | 0 | m_bitdepthShift = 0; |
108 | 0 | } |
109 | 0 | m_fileChrFmt = fileChrFmt; |
110 | 0 | m_bufferChrFmt = bufferChrFmt; |
111 | 0 | m_clipToRec709 = clipToRec709; |
112 | 0 | m_packedYUVMode = packedYUVMode; |
113 | 0 | m_readStdin = false; |
114 | 0 | m_y4mMode = y4mMode; |
115 | 0 | m_packetCount = 0; |
116 | 0 |
|
117 | 0 | if( m_packedYUVMode && !bWriteMode && m_fileBitdepth != 10 ) |
118 | 0 | { |
119 | 0 | m_lastError = "\nERROR: file bitdepth for packed yuv input must be 10"; |
120 | 0 | return -1; |
121 | 0 | } |
122 | 0 |
|
123 | 0 | if ( m_fileBitdepth > 16 ) |
124 | 0 | { |
125 | 0 | m_lastError = "\nERROR: Cannot handle a yuv file of bit depth greater than 16"; |
126 | 0 | return -1; |
127 | 0 | } |
128 | 0 |
|
129 | 0 | if ( m_y4mMode && bWriteMode ) |
130 | 0 | { |
131 | 0 | m_lastError = "\nERROR: Cannot handle y4m yuv output (only support for y4m input)"; |
132 | 0 | return -1; |
133 | 0 | } |
134 | 0 |
|
135 | 0 | if( bWriteMode ) |
136 | 0 | { |
137 | 0 | m_cHandle.open( fileName.c_str(), std::ios::binary | std::ios::out ); |
138 | 0 |
|
139 | 0 | if( m_cHandle.fail() ) |
140 | 0 | { |
141 | 0 | m_lastError = "\nFailed to open output YUV file: " + fileName; |
142 | 0 | return -1; |
143 | 0 | } |
144 | 0 | } |
145 | 0 | else |
146 | 0 | { |
147 | 0 | if( !cLogoFilename.empty() ) |
148 | 0 | { |
149 | 0 | std::stringstream strstr; |
150 | 0 | if ( 0 != m_cLogoRenderer.init( cLogoFilename, m_bufferChrFmt, strstr ) ) |
151 | 0 | { |
152 | 0 | if( !strstr.str().empty() ) |
153 | 0 | m_lastError = strstr.str(); |
154 | 0 | else |
155 | 0 | m_lastError = "failed to open Logo overlay renderer"; |
156 | 0 | return -1; |
157 | 0 | } |
158 | 0 | } |
159 | 0 |
|
160 | 0 | if( !strcmp( fileName.c_str(), "-" ) ) |
161 | 0 | { |
162 | 0 | m_readStdin = true; |
163 | 0 | #if defined (_WIN32) || defined (WIN32) || defined (_WIN64) || defined (WIN64) |
164 | 0 | if( _setmode( _fileno( stdin ), _O_BINARY ) == -1 ) |
165 | 0 | { |
166 | 0 | m_lastError = "\nError: Failed to set stdin to binary mode"; |
167 | 0 | return -1; |
168 | 0 | } |
169 | 0 | #endif |
170 | 0 | return 0; |
171 | 0 | } |
172 | 0 |
|
173 | 0 | m_cHandle.open( fileName.c_str(), std::ios::binary | std::ios::in ); |
174 | 0 |
|
175 | 0 | if( m_cHandle.fail() ) |
176 | 0 | { |
177 | 0 | m_lastError = "\nFailed to open input YUV file: " + fileName; |
178 | 0 | return -1; |
179 | 0 | } |
180 | 0 |
|
181 | 0 | if ( m_y4mMode || FileIOHelper::isY4mInputFilename( fileName ) ) |
182 | 0 | { |
183 | 0 | std::istream& inStream = m_cHandle; |
184 | 0 | std::string headerline; |
185 | 0 | getline(inStream, headerline); // jump over y4m header |
186 | 0 | m_y4mMode = true; |
187 | 0 | } |
188 | 0 | } |
189 | 0 | return 0; |
190 | 0 | } |
191 | | |
192 | | void close() |
193 | 0 | { |
194 | 0 | if( !m_readStdin ) |
195 | 0 | m_cHandle.close(); |
196 | 0 |
|
197 | 0 | if( m_cLogoRenderer.isInitialized() ) |
198 | 0 | { |
199 | 0 | m_cLogoRenderer.uninit(); |
200 | 0 | } |
201 | 0 | } |
202 | | |
203 | 0 | bool isOpen() { return m_cHandle.is_open(); } |
204 | 0 | bool isEof() { return m_cHandle.eof(); } |
205 | 0 | bool isFail() { return m_cHandle.fail(); } |
206 | 0 | std::string getLastError() const { return m_lastError; } |
207 | | |
208 | | int skipYuvFrames ( int numFrames, int width, int height ) |
209 | 0 | { |
210 | 0 | if ( numFrames <= 0 ) |
211 | 0 | { |
212 | 0 | return -1; |
213 | 0 | } |
214 | 0 |
|
215 | 0 | //set the frame size according to the chroma format |
216 | 0 | std::streamoff frameSize = 0; |
217 | 0 | const int numComp = (m_fileChrFmt==VVENC_CHROMA_400) ? 1 : 3; |
218 | 0 |
|
219 | 0 | if( m_packedYUVMode) |
220 | 0 | { |
221 | 0 | for ( int i = 0; i < numComp; i++ ) |
222 | 0 | { |
223 | 0 | const int csx_file = ( (i == 0) || (m_fileChrFmt==VVENC_CHROMA_444) ) ? 0 : 1; |
224 | 0 | const int csy_file = ( (i == 0) || (m_fileChrFmt!=VVENC_CHROMA_420) ) ? 0 : 1; |
225 | 0 | frameSize += (( ( width * 5 / 4 ) >> csx_file) * (height >> csy_file)); |
226 | 0 | } |
227 | 0 | } |
228 | 0 | else |
229 | 0 | { |
230 | 0 | unsigned wordsize = ( m_fileBitdepth > 8 ) ? 2 : 1; |
231 | 0 | for ( int i = 0; i < numComp; i++ ) |
232 | 0 | { |
233 | 0 | const int csx_file = ( (i == 0) || (m_fileChrFmt==VVENC_CHROMA_444) ) ? 0 : 1; |
234 | 0 | const int csy_file = ( (i == 0) || (m_fileChrFmt!=VVENC_CHROMA_420) ) ? 0 : 1; |
235 | 0 | frameSize += ( width >> csx_file ) * ( height >> csy_file ); |
236 | 0 | } |
237 | 0 | frameSize *= wordsize; |
238 | 0 | } |
239 | 0 |
|
240 | 0 | if( m_y4mMode ) |
241 | 0 | { |
242 | 0 | const char Y4MHeader[] = {'F','R','A','M','E'}; |
243 | 0 | frameSize += (sizeof(Y4MHeader) + 1); /* assume basic FRAME\n headers */; |
244 | 0 | } |
245 | 0 |
|
246 | 0 | const std::streamoff offset = frameSize * numFrames; |
247 | 0 |
|
248 | 0 | std::istream& inStream = m_readStdin ? std::cin : m_cHandle; |
249 | 0 |
|
250 | 0 | // check for file size |
251 | 0 | if( !m_readStdin ) |
252 | 0 | { |
253 | 0 | std::streamoff fsize = m_cHandle.tellg(); |
254 | 0 | m_cHandle.seekg( 0, std::ios::end ); |
255 | 0 | std::streamoff filelength = m_cHandle.tellg() - fsize; |
256 | 0 | m_cHandle.seekg( fsize, std::ios::beg ); |
257 | 0 | if( offset >= filelength ) |
258 | 0 | { |
259 | 0 | return -1; |
260 | 0 | } |
261 | 0 | } |
262 | 0 |
|
263 | 0 | // attempt to seek |
264 | 0 | if ( !! inStream.seekg( offset, std::ios::cur ) ) |
265 | 0 | { |
266 | 0 | return 0; /* success */ |
267 | 0 | } |
268 | 0 |
|
269 | 0 | inStream.clear(); |
270 | 0 |
|
271 | 0 | // fall back to consuming the input |
272 | 0 | char buf[ 512 ]; |
273 | 0 | const std::streamsize bufsize = static_cast<std::streamsize>( sizeof( buf ) ); |
274 | 0 | const std::streamsize offset_mod_bufsize = static_cast<std::streamsize>( ( offset % sizeof( buf ) ) ); |
275 | 0 | for ( std::streamoff i = 0; i < offset - offset_mod_bufsize; i += bufsize ) |
276 | 0 | { |
277 | 0 | inStream.read( buf, bufsize ); |
278 | 0 | } |
279 | 0 | inStream.read( buf, offset_mod_bufsize ); |
280 | 0 |
|
281 | 0 | return 0; |
282 | 0 | } |
283 | | |
284 | | |
285 | | int readYuvBuf ( vvencYUVBuffer& yuvInBuf, bool& eof ) |
286 | 0 | { |
287 | 0 | eof = false; |
288 | 0 | // check end-of-file |
289 | 0 | if ( isEof() ) |
290 | 0 | { |
291 | 0 | m_lastError = "end of file"; |
292 | 0 | eof = true; |
293 | 0 | return 0; |
294 | 0 | } |
295 | 0 |
|
296 | 0 | if ( m_packedYUVMode && ( 0 != (yuvInBuf.planes[0].width >> 1) % 4 ) ) |
297 | 0 | { |
298 | 0 | m_lastError = "unsupported file width for packed input"; |
299 | 0 | return -1; |
300 | 0 | } |
301 | 0 |
|
302 | 0 | const bool monochromFix = ( m_bufferChrFmt==VVENC_CHROMA_400 && m_fileChrFmt!=VVENC_CHROMA_400 ); |
303 | 0 | const bool is16bit = m_fileBitdepth > 8; |
304 | 0 | const int desired_bitdepth = m_MSBExtendedBitDepth + m_bitdepthShift; |
305 | 0 | const bool b709Compliance = ( m_clipToRec709 ) && ( m_bitdepthShift < 0 && desired_bitdepth >= 8 ); /* ITU-R BT.709 compliant clipping for converting say 10b to 8b */ |
306 | 0 | const LPel minVal = b709Compliance ? ( ( 1 << ( desired_bitdepth - 8 ) ) ) : 0; |
307 | 0 | const LPel maxVal = b709Compliance ? ( ( 0xff << ( desired_bitdepth - 8 ) ) -1 ) : ( 1 << desired_bitdepth ) - 1; |
308 | 0 | const int numComp = (m_fileChrFmt==VVENC_CHROMA_400) ? 1 : 3; |
309 | 0 |
|
310 | 0 | for( int comp = 0; comp < numComp; comp++ ) |
311 | 0 | { |
312 | 0 | vvencYUVPlane yuvPlane = yuvInBuf.planes[ comp ]; |
313 | 0 |
|
314 | 0 | if( monochromFix && comp ) |
315 | 0 | { |
316 | 0 | yuvPlane.width = yuvInBuf.planes[0].width >> (m_fileChrFmt == VVENC_CHROMA_444 ? 0 : 1); |
317 | 0 | yuvPlane.height = 2*yuvInBuf.planes[0].height >> (m_fileChrFmt != VVENC_CHROMA_420 ? 0 : 1); |
318 | 0 | yuvPlane.stride = yuvPlane.width; |
319 | 0 | } |
320 | 0 |
|
321 | 0 | std::istream& inStream = m_readStdin ? std::cin : m_cHandle; |
322 | 0 |
|
323 | 0 | if( m_y4mMode && comp == 0 ) |
324 | 0 | { |
325 | 0 | std::string y4mPrefix; |
326 | 0 | getline(inStream, y4mPrefix); /* assume basic FRAME\n headers */ |
327 | 0 | if( y4mPrefix != "FRAME") |
328 | 0 | { |
329 | 0 | m_lastError = "Source image does not contain valid y4m header (FRAME) - end of stream"; |
330 | 0 | eof = true; |
331 | 0 | return ( m_packetCount ? 0 : -1); // return error if no frames has been proceeded, otherwise expect eof |
332 | 0 | } |
333 | 0 | } |
334 | 0 |
|
335 | 0 | if ( ! FileIOHelper::readYuvPlane( inStream, yuvPlane, is16bit, m_fileBitdepth, m_packedYUVMode, comp, m_fileChrFmt, m_bufferChrFmt ) ) |
336 | 0 | { |
337 | 0 | eof = true; |
338 | 0 | return 0; |
339 | 0 | } |
340 | 0 |
|
341 | 0 | if ( m_bufferChrFmt == VVENC_CHROMA_400 && comp) |
342 | 0 | continue; |
343 | 0 |
|
344 | 0 | FileIOHelper::scaleYuvPlane( yuvPlane, yuvPlane, m_bitdepthShift, minVal, maxVal ); |
345 | 0 | } |
346 | 0 |
|
347 | 0 | if( m_cLogoRenderer.isInitialized() ) |
348 | 0 | { |
349 | 0 | LogoInputOptions cLogo = m_cLogoRenderer.getLogoInputOptions(); |
350 | 0 | if ( cLogo.sourceWidth > yuvInBuf.planes[0].width || cLogo.sourceHeight > yuvInBuf.planes[0].height ) |
351 | 0 | { |
352 | 0 | std::stringstream css; |
353 | 0 | css << "input picture size (" << yuvInBuf.planes[0].width << "x" << yuvInBuf.planes[0].height << ") < logo size (" << |
354 | 0 | cLogo.sourceWidth << "x" << cLogo.sourceHeight << ") cannot render logo" << std::endl; |
355 | 0 | m_lastError = css.str(); |
356 | 0 | return -1; |
357 | 0 | } |
358 | 0 |
|
359 | 0 | if( 0 != m_cLogoRenderer.renderLogo( yuvInBuf ) ) |
360 | 0 | { |
361 | 0 | m_lastError = "failed to render Logo"; |
362 | 0 | return -1; |
363 | 0 | } |
364 | 0 | } |
365 | 0 |
|
366 | 0 | m_packetCount++; |
367 | 0 |
|
368 | 0 | return 0; |
369 | 0 | } |
370 | | |
371 | | |
372 | | bool writeYuvBuf ( const vvencYUVBuffer& yuvOutBuf ) |
373 | 0 | { |
374 | 0 | // compute actual YUV frame size excluding padding size |
375 | 0 | bool is16bit = m_fileBitdepth > 8; |
376 | 0 | bool nonZeroBitDepthShift = m_bitdepthShift != 0; |
377 | 0 |
|
378 | 0 | vvencYUVBuffer yuvScaled; |
379 | 0 | vvenc_YUVBuffer_default( &yuvScaled ); |
380 | 0 | vvenc_YUVBuffer_alloc_buffer( &yuvScaled, m_bufferChrFmt, yuvOutBuf.planes[ 0 ].width, yuvOutBuf.planes[ 0 ].height ); |
381 | 0 |
|
382 | 0 | if ( nonZeroBitDepthShift ) |
383 | 0 | { |
384 | 0 | const bool b709Compliance = m_clipToRec709 && ( -m_bitdepthShift < 0 && m_MSBExtendedBitDepth >= 8 ); /* ITU-R BT.709 compliant clipping for converting say 10b to 8b */ |
385 | 0 | const LPel minVal = b709Compliance? ( ( 1 << ( m_MSBExtendedBitDepth - 8 ) ) ) : 0; |
386 | 0 | const LPel maxVal = b709Compliance? ( ( 0xff << ( m_MSBExtendedBitDepth - 8 ) ) -1 ) : ( 1 << m_MSBExtendedBitDepth ) - 1; |
387 | 0 | const int numComp = (m_bufferChrFmt==VVENC_CHROMA_400) ? 1 : 3; |
388 | 0 |
|
389 | 0 | for( int comp = 0; comp < numComp; comp++ ) |
390 | 0 | { |
391 | 0 | FileIOHelper::scaleYuvPlane( yuvScaled.planes[ comp ], yuvOutBuf.planes[ comp ],-m_bitdepthShift, minVal, maxVal ); |
392 | 0 | } |
393 | 0 | } |
394 | 0 |
|
395 | 0 | const vvencYUVBuffer& yuvWriteBuf = nonZeroBitDepthShift ? yuvScaled : yuvOutBuf; |
396 | 0 |
|
397 | 0 | const int numComp = (m_fileChrFmt==VVENC_CHROMA_400) ? 1 : 3; |
398 | 0 | for( int comp = 0; comp < numComp; comp++ ) |
399 | 0 | { |
400 | 0 | if ( ! FileIOHelper::writeYuvPlane( m_cHandle, yuvWriteBuf.planes[ comp ], is16bit, m_fileBitdepth, m_packedYUVMode, comp, m_bufferChrFmt, m_fileChrFmt ) ) |
401 | 0 | { |
402 | 0 | vvenc_YUVBuffer_free_buffer( &yuvScaled ); |
403 | 0 | return false; |
404 | 0 | } |
405 | 0 | } |
406 | 0 |
|
407 | 0 | m_packetCount++; |
408 | 0 | vvenc_YUVBuffer_free_buffer( &yuvScaled ); |
409 | 0 |
|
410 | 0 | return true; |
411 | 0 | } |
412 | | |
413 | | int countYuvFrames( int width, int height, bool countFromStart = true ) |
414 | 0 | { |
415 | 0 | if( m_readStdin ) return -1; |
416 | 0 |
|
417 | 0 | //set the frame size according to the chroma format |
418 | 0 | std::streamoff frameSize = 0; |
419 | 0 | const int numComp = (m_fileChrFmt==VVENC_CHROMA_400) ? 1 : 3; |
420 | 0 |
|
421 | 0 | if( m_packedYUVMode) |
422 | 0 | { |
423 | 0 | for ( int i = 0; i < numComp; i++ ) |
424 | 0 | { |
425 | 0 | const int csx_file = ( (i == 0) || (m_fileChrFmt==VVENC_CHROMA_444) ) ? 0 : 1; |
426 | 0 | const int csy_file = ( (i == 0) || (m_fileChrFmt!=VVENC_CHROMA_420) ) ? 0 : 1; |
427 | 0 | frameSize += (( ( width * 5 / 4 ) >> csx_file) * (height >> csy_file)); |
428 | 0 | } |
429 | 0 | } |
430 | 0 | else |
431 | 0 | { |
432 | 0 | unsigned wordsize = ( m_fileBitdepth > 8 ) ? 2 : 1; |
433 | 0 | for ( int i = 0; i < numComp; i++ ) |
434 | 0 | { |
435 | 0 | const int csx_file = ( (i == 0) || (m_fileChrFmt==VVENC_CHROMA_444) ) ? 0 : 1; |
436 | 0 | const int csy_file = ( (i == 0) || (m_fileChrFmt!=VVENC_CHROMA_420) ) ? 0 : 1; |
437 | 0 | frameSize += ( width >> csx_file ) * ( height >> csy_file ); |
438 | 0 | } |
439 | 0 | frameSize *= wordsize; |
440 | 0 | } |
441 | 0 |
|
442 | 0 | if( m_y4mMode ) |
443 | 0 | { |
444 | 0 | const char Y4MHeader[] = {'F','R','A','M','E'}; |
445 | 0 | frameSize += (sizeof(Y4MHeader) + 1); /* assume basic FRAME\n headers */; |
446 | 0 | } |
447 | 0 |
|
448 | 0 | std::streamoff lastPos = m_cHandle.tellg(); // backup last position |
449 | 0 |
|
450 | 0 | if( countFromStart ) |
451 | 0 | { |
452 | 0 | m_cHandle.seekg( 0, std::ios::beg ); |
453 | 0 | } |
454 | 0 | std::streamoff curPos = m_cHandle.tellg(); |
455 | 0 |
|
456 | 0 | m_cHandle.seekg( 0, std::ios::end ); |
457 | 0 | std::streamoff filelength = m_cHandle.tellg() - curPos; |
458 | 0 |
|
459 | 0 | m_cHandle.seekg( lastPos, std::ios::beg ); // rewind to last pos |
460 | 0 |
|
461 | 0 | return (int)(filelength / frameSize); |
462 | 0 | } |
463 | | }; |
464 | | |
465 | | } // namespace apputils |
466 | | |
467 | | //! \} |
468 | | |