Coverage Report

Created: 2026-04-01 07:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vvenc/source/Lib/apputils/FileIOHelper.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     FileIOHelper.h
43
    \brief    file I/O helper 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
60
#if defined (_WIN32) || defined (WIN32) || defined (_WIN64) || defined (WIN64)
61
#include <io.h>
62
#include <fcntl.h>
63
#endif
64
65
//! \ingroup Interface
66
//! \{
67
68
struct vvencYUVBuffer;
69
70
namespace apputils {
71
72
typedef int16_t LPel;
73
74
// ====================================================================================================================
75
76
class FileIOHelper
77
{
78
public:
79
80
  static std::string getFileExtension( std::string fileName )
81
0
  {
82
0
    std::string ext;
83
0
    if(fileName.find_last_of(".") != std::string::npos)
84
0
    {
85
0
      ext = fileName.substr(fileName.find_last_of(".")+1);
86
0
      std::transform( ext.begin(), ext.end(), ext.begin(), ::tolower );
87
0
    }
88
0
    return ext;
89
0
  }
90
91
92
0
  static bool isY4mInputFilename( std::string fileName ) {  return ( "y4m" == getFileExtension(fileName) ); }
93
  static bool isY4mHeaderAvailable( std::string fileName )
94
0
  {
95
0
    if( fileName == "-" ) return false;
96
0
    std::fstream cfHandle;
97
0
    cfHandle.open( fileName, std::ios::binary | std::ios::in );
98
0
    if( cfHandle.fail() ) return false;
99
100
0
    char line[10] = {0};
101
0
    std::streamsize headerlinesize = cfHandle.readsome( line, 10 );
102
0
    cfHandle.close();
103
104
0
    if( headerlinesize && memcmp( line, "YUV4MPEG2", 9 ) == 0 ) return true;
105
106
0
    return false;
107
0
  }
108
109
  static int parseY4mHeader( const std::string &fileName, vvenc_config& cfg, vvencChromaFormat& inputFileChromaFormat )
110
0
  {
111
0
    std::fstream cfHandle;
112
113
0
    if( fileName == "-" )
114
0
    {
115
  #if defined (_WIN32) || defined (WIN32) || defined (_WIN64) || defined (WIN64)
116
      if( _setmode( _fileno( stdin ), _O_BINARY ) == -1 )
117
      {
118
        return -1;
119
      }
120
  #endif
121
0
    }
122
0
    else
123
0
    {
124
0
      cfHandle.open( fileName, std::ios::binary | std::ios::in );
125
0
      if( cfHandle.fail() )
126
0
      {
127
0
        return -1;
128
0
      }
129
0
    }
130
131
0
    std::istream& inStream = ( fileName == "-" ) ? std::cin : cfHandle;
132
133
    // y4m header syntax example
134
    // YUV4MPEG2 W1920 H1080 F50:1 Ip A128:117 C420p10
135
136
    // init y4m defaults (if not given in header)
137
0
    cfg.m_inputBitDepth[0]  = 8;
138
0
    inputFileChromaFormat = VVENC_CHROMA_420;
139
140
0
    std::string headerline;
141
0
    getline(inStream, headerline);
142
0
    if( headerline.empty() ){ return -1; }
143
0
    std::transform( headerline.begin(), headerline.end(), headerline.begin(), ::toupper );
144
145
0
    std::regex reg("\\s+"); // tokenize at spaces
146
0
    std::sregex_token_iterator iter(headerline.begin(), headerline.end(), reg, -1);
147
0
    std::sregex_token_iterator end;
148
0
    std::vector<std::string> vec(iter, end);
149
150
0
    bool valid=false;
151
0
    int  infosFound = 0;
152
0
    for (auto &p : vec)
153
0
    {
154
0
      if( p == "YUV4MPEG2" ) // read file signature
155
0
      { valid = true; }
156
0
      else if( p[0] == 'W' ) // width
157
0
      {
158
0
        cfg.m_SourceWidth = atoi( p.substr( 1 ).c_str());
159
0
        infosFound++;
160
0
      }
161
0
      else if( p[0] == 'H' ) // height
162
0
      {
163
0
        cfg.m_SourceHeight = atoi( p.substr( 1 ).c_str());
164
0
        infosFound++;
165
0
      }
166
0
      else if( p[0] == 'F' )  // framerate,scale
167
0
      {
168
0
        size_t sep = p.find(":");
169
0
        if( sep == std::string::npos ) return -1;
170
0
        cfg.m_FrameRate  = atoi( p.substr( 1, sep-1 ).c_str());
171
0
        cfg.m_FrameScale = atoi( p.substr( sep+1 ).c_str());
172
0
        infosFound++;
173
0
      }
174
0
      else if( p[0] == 'A' ) // aspect ratio
175
0
      {
176
0
        size_t sep = p.find(":");
177
0
        if( sep == std::string::npos ) return -1;
178
0
        cfg.m_sarWidth  = atoi( p.substr( 1, sep-1 ).c_str());
179
0
        cfg.m_sarHeight = atoi( p.substr( sep+1 ).c_str());
180
0
      }
181
0
      else if( p[0] == 'C' ) // colorspace ( e.g. C420p10)
182
0
      {
183
0
        std::vector<std::string> ignores = {"JPEG", "MPEG2", "PALVD" }; // ignore some special cases
184
0
        for( auto &i : ignores )
185
0
        {
186
0
          auto n = p.find( i );
187
0
          if (n != std::string::npos) p.erase(n, i.length()); // remove from param string (e.g. 420PALVD)
188
0
        }
189
190
0
        size_t sep = p.find("P");
191
0
        std::string chromatype;
192
0
        if( sep != std::string::npos )
193
0
        {
194
0
          chromatype = ( p.substr( 1, sep-1 ).c_str());
195
0
          cfg.m_inputBitDepth[0] = atoi( p.substr( sep+1 ).c_str());
196
0
        }
197
0
        else
198
0
        {
199
0
          sep = p.find("CMONO");
200
0
          if( sep != std::string::npos )
201
0
          {
202
0
            chromatype = "400";
203
0
            if( p == "CMONO") cfg.m_inputBitDepth[0] = 8;
204
0
            else cfg.m_inputBitDepth[0] = atoi( p.substr( sep+5 ).c_str()); // e.g. mono10
205
0
          }
206
0
          else
207
0
          {
208
0
            chromatype = ( p.substr( 1 ).c_str());
209
0
            cfg.m_inputBitDepth[0] = 8;
210
0
          }
211
0
        }
212
213
0
        if( chromatype == "400" )      { inputFileChromaFormat =  VVENC_CHROMA_400; }
214
0
        else if( chromatype == "420" ) { inputFileChromaFormat =  VVENC_CHROMA_420; }
215
0
        else if( chromatype == "422" ) { inputFileChromaFormat =  VVENC_CHROMA_422; }
216
0
        else if( chromatype == "444" ) { inputFileChromaFormat =  VVENC_CHROMA_444; }
217
0
        else { return -1; } // unsupported chroma foramt}
218
0
      }
219
0
      else if( p[0] == 'I' ) // interlaced format (ignore it, because we cannot set it in any params
220
0
      {}
221
0
      else if( p[0] == 'X' ) // ignore comments
222
0
      {}
223
0
    }
224
225
0
    if( fileName != "-" )
226
0
    {
227
0
      cfHandle.close();
228
0
    }
229
    
230
0
    if ( infosFound < 3 )
231
0
    {
232
0
      valid = false;  
233
0
    }
234
235
0
    if( !valid ) return -1;
236
237
0
    return (int)headerline.length()+1;
238
0
  }
239
240
241
  static bool checkInputFile( std::string fileName, std::string& rcErrText )
242
0
  {
243
0
    if( fileName == "-" ) return true;
244
245
0
    std::stringstream css;
246
0
    std::fstream cfHandle;
247
0
    cfHandle.open( fileName, std::ios::binary | std::ios::in );
248
0
    if( cfHandle.fail() )
249
0
    {
250
0
      css <<"cannot open input file " << fileName;
251
0
      rcErrText = css.str();
252
0
      return false;
253
0
    }
254
255
0
    cfHandle.seekg( 0, std::ios::end );
256
0
    if ( 0 >= cfHandle.tellg() )
257
0
    {
258
0
      css <<"cannot determine valid input file size of file" << fileName;
259
0
      rcErrText = css.str();
260
0
      return false;
261
0
    }
262
0
    cfHandle.close();
263
264
0
    std::string ext = getFileExtension(fileName);
265
0
    std::vector<std::string> unsupportedList { "mp4", "mkv", "ts", "mpeg", "avi" } ;
266
0
    for (auto &e : unsupportedList)
267
0
    {
268
0
      if( e == ext )
269
0
      {
270
0
        css <<"unsupported input file format " << e << " detected. support only for RAW/YUV/Y4M input files.\n";
271
0
        rcErrText = css.str();
272
0
        return false;
273
0
      }
274
0
    }
275
0
    return true;
276
0
  }
277
278
  static bool checkBitstreamFile( std::string fileName, std::string& rcErrText )
279
0
  {
280
0
    if( fileName == "-" ) return true;
281
0
    std::stringstream css;
282
0
    std::string ext = getFileExtension(fileName);
283
0
    std::vector<std::string> unsupportedList { "mp4", "mkv", "ts", "mpeg", "avi" } ;
284
0
    for (auto &e : unsupportedList)
285
0
    {
286
0
      if( e == ext )
287
0
      {
288
0
        css <<"unsupported output file format detected. no support for " << e << " container. RAW ES (e.g. *.vvc, *.266) support only.\n" << fileName;
289
0
        rcErrText = css.str();
290
0
        return false;
291
0
      }
292
0
    }
293
294
0
    return true;
295
0
  }
296
  
297
  static bool verifyYuvPlane( vvencYUVPlane& yuvPlane, const int bitDepth )
298
0
  {
299
0
    const int stride = yuvPlane.stride;
300
0
    const int width  = yuvPlane.width;
301
0
    const int height = yuvPlane.height;
302
0
    LPel* dst        = yuvPlane.ptr;
303
0
  
304
0
    const LPel mask = ~( ( 1 << bitDepth ) - 1 );
305
0
  
306
0
    for ( int y = 0; y < height; y++, dst += stride )
307
0
    {
308
0
      for ( int x = 0; x < width; x++ )
309
0
      {
310
0
        if ( ( dst[ x ] & mask ) != 0 )
311
0
        {
312
0
          return false;
313
0
        }
314
0
      }
315
0
    }
316
0
  
317
0
    return true;
318
0
  }
319
  
320
  static bool readYuvPlane( std::istream&     fd,
321
                     vvencYUVPlane&           yuvPlane,
322
                     bool                     is16bit,
323
                     int                      fileBitDepth,
324
                     int                      packedYUVInput,
325
                     const int&               compID,
326
                     const vvencChromaFormat& inputChFmt,
327
                     const vvencChromaFormat& internChFmt
328
                   )
329
0
  {
330
0
    const int csx_file = ( (compID == 0) || (inputChFmt==VVENC_CHROMA_444) ) ? 0 : 1;
331
0
    const int csy_file = ( (compID == 0) || (inputChFmt!=VVENC_CHROMA_420) ) ? 0 : 1;
332
0
    const int csx_dest = ( (compID == 0) || (internChFmt==VVENC_CHROMA_444) ) ? 0 : 1;
333
0
    const int csy_dest = ( (compID == 0) || (internChFmt!=VVENC_CHROMA_420) ) ? 0 : 1;
334
0
  
335
0
    const int stride  = yuvPlane.stride;
336
0
    const int width   = yuvPlane.width;
337
0
    const int height  = yuvPlane.height;
338
0
    LPel* dst         = yuvPlane.ptr;
339
0
  
340
0
    const int fileStride = ( ( width  << csx_dest ) * ( is16bit ? 2 : 1 ) ) >> csx_file;
341
0
    const int fileHeight = ( ( height << csy_dest )                       ) >> csy_file;
342
0
  
343
0
    if ( compID != 0 && ( inputChFmt == VVENC_CHROMA_400 || internChFmt == VVENC_CHROMA_400 ) )
344
0
    {
345
0
      if ( internChFmt != VVENC_CHROMA_400 )
346
0
      {
347
0
        // set chrominance data to mid-range: (1<<(fileBitDepth-1))
348
0
        const LPel val = 1 << ( fileBitDepth - 1 );
349
0
        for (int y = 0; y < height; y++, dst+= stride)
350
0
        {
351
0
          for (int x = 0; x < width; x++)
352
0
          {
353
0
            dst[x] = val;
354
0
          }
355
0
        }
356
0
      }
357
0
  
358
0
      if ( inputChFmt != VVENC_CHROMA_400 )
359
0
      {
360
0
        fd.seekg( fileHeight * fileStride, std::ios::cur );
361
0
        if ( fd.eof() || fd.fail() )
362
0
        {
363
0
          return false;
364
0
        }
365
0
      }
366
0
    }
367
0
    else if ( packedYUVInput )
368
0
    {
369
0
      const int fileStride_packed = ( width * 5 / 4 );
370
0
      std::vector<uint8_t> bufVec( fileStride_packed );
371
0
  
372
0
      for( int y = 0; y < height; y++ )
373
0
      {
374
0
        uint8_t *buf = &( bufVec[0] );
375
0
  
376
0
        // read a new line
377
0
        fd.read( reinterpret_cast<char*>( buf ), fileStride_packed );
378
0
        if ( fd.eof() || fd.fail() )
379
0
        {
380
0
          return false;
381
0
        }
382
0
  
383
0
        for ( int x = 0; x < width; x += 4 )
384
0
        {
385
0
          int64_t iTemp = 0;
386
0
          unsigned char* pucTemp = reinterpret_cast< unsigned char* >( &iTemp );
387
0
          pucTemp[0] = buf[0];
388
0
          pucTemp[1] = buf[1];
389
0
          pucTemp[2] = buf[2];
390
0
          pucTemp[3] = buf[3];
391
0
          pucTemp[4] = buf[4];
392
0
  
393
0
          dst[x+0] = 0x03ff & (iTemp>>0);
394
0
          dst[x+1] = 0x03ff & (iTemp>>10);
395
0
          dst[x+2] = 0x03ff & (iTemp>>20);
396
0
          dst[x+3] = 0x03ff & (iTemp>>30);
397
0
          buf += 5;
398
0
        }
399
0
        dst += stride;
400
0
      }
401
0
    }
402
0
    else
403
0
    {
404
0
      std::vector<uint8_t> bufVec( fileStride );
405
0
      uint8_t *buf = &( bufVec[0] );
406
0
      const unsigned mask_y_file = ( 1 << csy_file ) - 1;
407
0
      const unsigned mask_y_dest = ( 1 << csy_dest ) - 1;
408
0
      for( int y444 = 0; y444 < ( height << csy_dest ); y444++ )
409
0
      {
410
0
        if ( ( y444 & mask_y_file ) == 0 )
411
0
        {
412
0
          // read a new line
413
0
          fd.read( reinterpret_cast<char*>( buf ), fileStride );
414
0
          if ( fd.eof() || fd.fail() )
415
0
          {
416
0
            return false;
417
0
          }
418
0
        }
419
0
  
420
0
        if ( ( y444 & mask_y_dest ) == 0 )
421
0
        {
422
0
          // process current destination line
423
0
          if ( csx_file < csx_dest )
424
0
          {
425
0
            // eg file is 444, dest is 422.
426
0
            const int sx = csx_dest - csx_file;
427
0
            if ( ! is16bit )
428
0
            {
429
0
              for ( int x = 0; x < width; x++ )
430
0
              {
431
0
                dst[ x ] = buf[ x << sx ];
432
0
              }
433
0
            }
434
0
            else
435
0
            {
436
0
              for ( int x = 0; x < width; x++ )
437
0
              {
438
0
                dst[ x ] = LPel( buf[ ( x << sx ) * 2 + 0 ] ) | ( LPel ( buf[ ( x << sx ) * 2 + 1 ] ) << 8 );
439
0
              }
440
0
            }
441
0
          }
442
0
          else
443
0
          {
444
0
            // eg file is 422, dest is 444.
445
0
            const int sx = csx_file - csx_dest;
446
0
            if ( ! is16bit )
447
0
            {
448
0
              for ( int x = 0; x < width; x++ )
449
0
              {
450
0
                dst[ x ] = buf[ x >> sx ];
451
0
              }
452
0
            }
453
0
            else
454
0
            {
455
0
              for ( int x = 0; x < width; x++ )
456
0
              {
457
0
                dst[ x ] = LPel( buf[ ( x >> sx ) * 2 + 0 ] ) | ( LPel( buf[ ( x >> sx ) * 2 + 1 ] ) << 8 );
458
0
              }
459
0
            }
460
0
          }
461
0
  
462
0
          dst += stride;
463
0
        }
464
0
      }
465
0
  
466
0
    }
467
0
    return true;
468
0
  }
469
  
470
  static bool writeYuvPlane( std::ostream&     fd,
471
                      const vvencYUVPlane&     yuvPlane,
472
                      bool                     is16bit,
473
                      int                      fileBitDepth,
474
                      int                      packedYUVOutputMode,
475
                      const int&               compID,
476
                      const vvencChromaFormat& internChFmt,
477
                      const vvencChromaFormat& outputChFmt
478
                    )
479
0
  {
480
0
    const int stride = yuvPlane.stride;
481
0
    const int width  = yuvPlane.width;
482
0
    const int height = yuvPlane.height;
483
0
    const LPel* src  = yuvPlane.ptr;
484
0
  
485
0
    const int csx_file = ( (compID == 0) || (outputChFmt==VVENC_CHROMA_444) ) ? 0 : 1;
486
0
    const int csy_file = ( (compID == 0) || (outputChFmt!=VVENC_CHROMA_420) ) ? 0 : 1;
487
0
    const int csx_src  = ( (compID == 0) || (internChFmt==VVENC_CHROMA_444) ) ? 0 : 1;
488
0
    const int csy_src  = ( (compID == 0) || (internChFmt!=VVENC_CHROMA_420) ) ? 0 : 1;
489
0
  
490
0
    const int  fileWidth  = ( width  << csx_src ) >> csx_file;
491
0
    const int  fileHeight = ( height << csy_src ) >> csy_file;
492
0
    const bool writePYUV  = ( packedYUVOutputMode > 0 ) && ( fileBitDepth == 10 || fileBitDepth == 12 ) && ( ( fileWidth & ( 1 + ( fileBitDepth & 3 ) ) ) == 0 );
493
0
    const int  fileStride = writePYUV ? ( ( width << csx_src ) * fileBitDepth ) >> ( csx_file + 3 ) : ( ( width << csx_src ) * ( is16bit ? 2 : 1 ) ) >> csx_file;
494
0
  
495
0
    std::vector<uint8_t> bufVec( fileStride );
496
0
    uint8_t *buf = &( bufVec[ 0 ] );
497
0
  
498
0
    if ( writePYUV )
499
0
    {
500
0
      const unsigned mask_y_file = (1 << csy_file) - 1;
501
0
      const unsigned mask_y_src  = (1 << csy_src ) - 1;
502
0
      const int      widthS_file = fileWidth >> (fileBitDepth == 12 ? 1 : 2);
503
0
  
504
0
      for ( int y444 = 0; y444 < ( height << csy_src ); y444++)
505
0
      {
506
0
        if ( ( y444 & mask_y_file ) == 0 )  // write a new line to file
507
0
        {
508
0
          if ( csx_file < csx_src )
509
0
          {
510
0
            // eg file is 444, source is 422.
511
0
            const int sx = csx_src - csx_file;
512
0
  
513
0
            if (fileBitDepth == 10)  // write 4 values into 5 bytes
514
0
            {
515
0
              for ( int x = 0; x < widthS_file; x++)
516
0
              {
517
0
                const unsigned src0 = src[(4*x  ) >> sx];
518
0
                const unsigned src1 = src[(4*x+1) >> sx];
519
0
                const unsigned src2 = src[(4*x+2) >> sx];
520
0
                const unsigned src3 = src[(4*x+3) >> sx];
521
0
  
522
0
                buf[5*x  ] = ((src0     ) & 0xff); // src0:76543210
523
0
                buf[5*x+1] = ((src1 << 2) & 0xfc) + ((src0 >> 8) & 0x03);
524
0
                buf[5*x+2] = ((src2 << 4) & 0xf0) + ((src1 >> 6) & 0x0f);
525
0
                buf[5*x+3] = ((src3 << 6) & 0xc0) + ((src2 >> 4) & 0x3f);
526
0
                buf[5*x+4] = ((src3 >> 2) & 0xff); // src3:98765432
527
0
              }
528
0
            }
529
0
            else if ( fileBitDepth == 12 ) //...2 values into 3 bytes
530
0
            {
531
0
              for ( int x = 0; x < widthS_file; x++ )
532
0
              {
533
0
                const unsigned src0 = src[(2*x  ) >> sx];
534
0
                const unsigned src1 = src[(2*x+1) >> sx];
535
0
  
536
0
                buf[3*x  ] = ((src0     ) & 0xff); // src0:76543210
537
0
                buf[3*x+1] = ((src1 << 4) & 0xf0) + ((src0 >> 8) & 0x0f);
538
0
                buf[3*x+2] = ((src1 >> 4) & 0xff); // src1:BA987654
539
0
              }
540
0
            }
541
0
          }
542
0
          else
543
0
          {
544
0
            // eg file is 422, source is 444.
545
0
            const int sx = csx_file - csx_src;
546
0
  
547
0
            if (fileBitDepth == 10)  // write 4 values into 5 bytes
548
0
            {
549
0
              for ( int x = 0; x < widthS_file; x++ )
550
0
              {
551
0
                const unsigned src0 = src[(4*x  ) << sx];
552
0
                const unsigned src1 = src[(4*x+1) << sx];
553
0
                const unsigned src2 = src[(4*x+2) << sx];
554
0
                const unsigned src3 = src[(4*x+3) << sx];
555
0
  
556
0
                buf[5*x  ] = ((src0     ) & 0xff); // src0:76543210
557
0
                buf[5*x+1] = ((src1 << 2) & 0xfc) + ((src0 >> 8) & 0x03);
558
0
                buf[5*x+2] = ((src2 << 4) & 0xf0) + ((src1 >> 6) & 0x0f);
559
0
                buf[5*x+3] = ((src3 << 6) & 0xc0) + ((src2 >> 4) & 0x3f);
560
0
                buf[5*x+4] = ((src3 >> 2) & 0xff); // src3:98765432
561
0
              }
562
0
            }
563
0
            else if ( fileBitDepth == 12 ) //...2 values into 3 bytes
564
0
            {
565
0
              for ( int x = 0; x < widthS_file; x++ )
566
0
              {
567
0
                const unsigned src0 = src[(2*x  ) << sx];
568
0
                const unsigned src1 = src[(2*x+1) << sx];
569
0
  
570
0
                buf[3*x  ] = ((src0     ) & 0xff); // src0:76543210
571
0
                buf[3*x+1] = ((src1 << 4) & 0xf0) + ((src0 >> 8) & 0x0f);
572
0
                buf[3*x+2] = ((src1 >> 4) & 0xff); // src1:BA987654
573
0
              }
574
0
            }
575
0
          }
576
0
  
577
0
          fd.write( reinterpret_cast<const char*>( buf ), fileStride );
578
0
          if ( fd.eof() || fd.fail() )
579
0
          {
580
0
            return false;
581
0
          }
582
0
        }
583
0
  
584
0
        if ( ( y444 & mask_y_src ) == 0)
585
0
        {
586
0
          src += stride;
587
0
        }
588
0
      }
589
0
    }
590
0
    // !writePYUV
591
0
    else if ( compID != 0 && ( outputChFmt == VVENC_CHROMA_400 || internChFmt == VVENC_CHROMA_400 ) )
592
0
    {
593
0
      if ( outputChFmt != VVENC_CHROMA_400 )
594
0
      {
595
0
        const LPel value = 1 << ( fileBitDepth - 1 );
596
0
  
597
0
        for ( int y = 0; y < fileHeight; y++ )
598
0
        {
599
0
          if ( ! is16bit )
600
0
          {
601
0
            uint8_t val( value );
602
0
            for ( int x = 0; x < fileWidth; x++ )
603
0
            {
604
0
              buf[x]=val;
605
0
            }
606
0
          }
607
0
          else
608
0
          {
609
0
            uint16_t val( value );
610
0
            for ( int x = 0; x < fileWidth; x++ )
611
0
            {
612
0
              buf[2*x  ]= (val>>0) & 0xff;
613
0
              buf[2*x+1]= (val>>8) & 0xff;
614
0
            }
615
0
          }
616
0
  
617
0
          fd.write( reinterpret_cast<const char*>( buf ), fileStride );
618
0
          if ( fd.eof() || fd.fail() )
619
0
          {
620
0
            return false;
621
0
          }
622
0
        }
623
0
      }
624
0
    }
625
0
    else
626
0
    {
627
0
      const unsigned mask_y_file = (1 << csy_file) - 1;
628
0
      const unsigned mask_y_src  = (1 << csy_src ) - 1;
629
0
  
630
0
      for ( int y444 = 0; y444 < ( height << csy_src ); y444++ )
631
0
      {
632
0
        if ( ( y444 & mask_y_file ) == 0 )
633
0
        {
634
0
          // write a new line
635
0
          if ( csx_file < csx_src )
636
0
          {
637
0
            // eg file is 444, source is 422.
638
0
            const int sx = csx_src - csx_file;
639
0
            if ( ! is16bit )
640
0
            {
641
0
              for ( int x = 0; x < fileWidth; x++ )
642
0
              {
643
0
                buf[x] = (uint8_t)(src[x>>sx]);
644
0
              }
645
0
            }
646
0
            else
647
0
            {
648
0
              for ( int x = 0; x < fileWidth; x++ )
649
0
              {
650
0
                buf[2*x  ] = (src[x>>sx]>>0) & 0xff;
651
0
                buf[2*x+1] = (src[x>>sx]>>8) & 0xff;
652
0
              }
653
0
            }
654
0
          }
655
0
          else
656
0
          {
657
0
            // eg file is 422, source is 444.
658
0
            const int sx = csx_file - csx_src;
659
0
            if ( ! is16bit )
660
0
            {
661
0
              for ( int x = 0; x < fileWidth; x++ )
662
0
              {
663
0
                buf[x] = (uint8_t)(src[x<<sx]);
664
0
              }
665
0
            }
666
0
            else
667
0
            {
668
0
              for ( int x = 0; x < fileWidth; x++ )
669
0
              {
670
0
                buf[2*x  ] = (src[x<<sx]>>0) & 0xff;
671
0
                buf[2*x+1] = (src[x<<sx]>>8) & 0xff;
672
0
              }
673
0
            }
674
0
          }
675
0
  
676
0
          fd.write( reinterpret_cast<const char*>( buf ), fileStride );
677
0
          if ( fd.eof() || fd.fail() )
678
0
          {
679
0
            return false;
680
0
          }
681
0
        }
682
0
  
683
0
        if ( ( y444 & mask_y_src ) == 0 )
684
0
        {
685
0
          src += stride;
686
0
        }
687
0
      }
688
0
    }
689
0
    return true;
690
0
  }
691
692
  static void scaleYuvPlane( vvencYUVPlane& yuvPlaneOut, const vvencYUVPlane& yuvPlaneIn, 
693
                             const int shiftBits, const LPel minVal, const LPel maxVal )
694
0
  {
695
0
    const int stride = yuvPlaneOut.stride;
696
0
    const int width  = yuvPlaneOut.width;
697
0
    const int height = yuvPlaneOut.height;
698
0
    LPel* dst        = yuvPlaneOut.ptr;
699
0
    const LPel* src    = yuvPlaneIn.ptr;
700
0
    const int instride = yuvPlaneIn.stride;
701
0
  
702
0
    if( 0 == shiftBits )
703
0
    {
704
0
      return;
705
0
    }
706
0
  
707
0
    if( shiftBits > 0 )
708
0
    {
709
0
      for( int y = 0; y < height; y++, dst += stride, src += instride )
710
0
      {
711
0
        for( int x = 0; x < width; x++)
712
0
        {
713
0
          dst[x] = src[x] << shiftBits;
714
0
        }
715
0
      }
716
0
    }
717
0
    else if ( shiftBits < 0 )
718
0
    {
719
0
      const int shiftbitsr =- shiftBits;
720
0
      const LPel rounding = 1 << ( shiftbitsr-1 );
721
0
  
722
0
      for( int y = 0; y < height; y++, dst += stride, src += instride )
723
0
      {
724
0
        for( int x = 0; x < width; x++)
725
0
        {
726
0
          LPel val = ( src[ x ] + rounding ) >> shiftbitsr;
727
0
          dst[ x ] = std::max<LPel>( minVal, std::min<LPel>( maxVal, val ) );
728
0
        }
729
0
      }
730
0
    }
731
0
  }
732
};
733
734
} // namespace apputils
735
736
//! \}
737