source: SHVCSoftware/branches/SHM-dev/source/Lib/TLibVideoIO/TVideoIOYuv.cpp @ 1263

Last change on this file since 1263 was 1260, checked in by seregin, 9 years ago

port rev 4257

  • Property svn:eol-style set to native
File size: 34.1 KB
RevLine 
[313]1/* The copyright in this software is being made available under the BSD
2 * License, included below. This software may be subject to other third party
3 * and contributor rights, including patent rights, and no such rights are
[1029]4 * granted under this license.
[313]5 *
[1259]6 * Copyright (c) 2010-2015, ITU/ISO/IEC
[313]7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 *  * Redistributions of source code must retain the above copyright notice,
13 *    this list of conditions and the following disclaimer.
14 *  * Redistributions in binary form must reproduce the above copyright notice,
15 *    this list of conditions and the following disclaimer in the documentation
16 *    and/or other materials provided with the distribution.
17 *  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
18 *    be used to endorse or promote products derived from this software without
19 *    specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31 * THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/** \file     TVideoIOYuv.cpp
35    \brief    YUV file I/O class
36*/
37
38#include <cstdlib>
39#include <fcntl.h>
40#include <assert.h>
41#include <sys/stat.h>
42#include <fstream>
43#include <iostream>
[1029]44#include <memory.h>
[313]45
46#include "TLibCommon/TComRom.h"
47#include "TVideoIOYuv.h"
48
49using namespace std;
50
[1029]51// ====================================================================================================================
52// Local Functions
53// ====================================================================================================================
[313]54
55/**
56 * Scale all pixels in img depending upon sign of shiftbits by a factor of
57 * 2<sup>shiftbits</sup>.
58 *
59 * @param img        pointer to image to be transformed
60 * @param stride  distance between vertically adjacent pixels of img.
61 * @param width   width of active area in img.
62 * @param height  height of active area in img.
63 * @param shiftbits if zero, no operation performed
64 *                  if > 0, multiply by 2<sup>shiftbits</sup>, see scalePlane()
65 *                  if < 0, divide and round by 2<sup>shiftbits</sup> and clip,
66 *                          see invScalePlane().
67 * @param minval  minimum clipping value when dividing.
68 * @param maxval  maximum clipping value when dividing.
69 */
[1029]70static Void scalePlane(Pel* img, const UInt stride, const UInt width, const UInt height, Int shiftbits, Pel minval, Pel maxval)
[313]71{
72  if (shiftbits > 0)
73  {
[1029]74    for (UInt y = 0; y < height; y++, img+=stride)
[1246]75    {
[1029]76      for (UInt x = 0; x < width; x++)
[1246]77      {
[1029]78        img[x] <<= shiftbits;
[1246]79      }
80    }
[313]81  }
[1029]82  else if (shiftbits < 0)
[313]83  {
[1029]84    shiftbits=-shiftbits;
85
86    Pel rounding = 1 << (shiftbits-1);
87    for (UInt y = 0; y < height; y++, img+=stride)
[1246]88    {
[1029]89      for (UInt x = 0; x < width; x++)
[1246]90      {
[1029]91        img[x] = Clip3(minval, maxval, Pel((img[x] + rounding) >> shiftbits));
[1246]92      }
93    }
[313]94  }
95}
96
97
98// ====================================================================================================================
99// Public member functions
100// ====================================================================================================================
101
102/**
103 * Open file for reading/writing Y'CbCr frames.
104 *
105 * Frames read/written have bitdepth fileBitDepth, and are automatically
106 * formatted as 8 or 16 bit word values (see TVideoIOYuv::write()).
107 *
108 * Image data read or written is converted to/from internalBitDepth
109 * (See scalePlane(), TVideoIOYuv::read() and TVideoIOYuv::write() for
110 * further details).
111 *
112 * \param pchFile          file name string
113 * \param bWriteMode       file open mode: true=read, false=write
[1029]114 * \param fileBitDepth     bit-depth array of input/output file data.
[1260]115 * \param MSBExtendedBitDepth
[1029]116 * \param internalBitDepth bit-depth array to scale image data to/from when reading/writing.
[313]117 */
[1029]118Void TVideoIOYuv::open( Char* pchFile, Bool bWriteMode, const Int fileBitDepth[MAX_NUM_CHANNEL_TYPE], const Int MSBExtendedBitDepth[MAX_NUM_CHANNEL_TYPE], const Int internalBitDepth[MAX_NUM_CHANNEL_TYPE] )
[313]119{
[1029]120  //NOTE: files cannot have bit depth greater than 16
121  for(UInt ch=0; ch<MAX_NUM_CHANNEL_TYPE; ch++)
122  {
123    m_fileBitdepth       [ch] = std::min<UInt>(fileBitDepth[ch], 16);
124    m_MSBExtendedBitDepth[ch] = MSBExtendedBitDepth[ch];
125    m_bitdepthShift      [ch] = internalBitDepth[ch] - m_MSBExtendedBitDepth[ch];
[313]126
[1029]127    if (m_fileBitdepth[ch] > 16)
128    {
129      if (bWriteMode)
130      {
131        std::cerr << "\nWARNING: Cannot write a yuv file of bit depth greater than 16 - output will be right-shifted down to 16-bit precision\n" << std::endl;
132      }
133      else
134      {
135        std::cerr << "\nERROR: Cannot read a yuv file of bit depth greater than 16\n" << std::endl;
136        exit(0);
137      }
138    }
139  }
140
[313]141  if ( bWriteMode )
142  {
143    m_cHandle.open( pchFile, ios::binary | ios::out );
[1029]144
[313]145    if( m_cHandle.fail() )
146    {
147      printf("\nfailed to write reconstructed YUV file\n");
148      exit(0);
149    }
150  }
151  else
152  {
153    m_cHandle.open( pchFile, ios::binary | ios::in );
[1029]154
[313]155    if( m_cHandle.fail() )
156    {
157      printf("\nfailed to open Input YUV file\n");
158      exit(0);
159    }
160  }
[1029]161
[313]162  return;
163}
164
165Void TVideoIOYuv::close()
166{
167  m_cHandle.close();
168}
169
170Bool TVideoIOYuv::isEof()
171{
172  return m_cHandle.eof();
173}
174
175Bool TVideoIOYuv::isFail()
176{
177  return m_cHandle.fail();
178}
179
180/**
181 * Skip numFrames in input.
182 *
183 * This function correctly handles cases where the input file is not
184 * seekable, by consuming bytes.
185 */
[1029]186Void TVideoIOYuv::skipFrames(UInt numFrames, UInt width, UInt height, ChromaFormat format)
[313]187{
188  if (!numFrames)
[1246]189  {
[313]190    return;
[1246]191  }
[313]192
[1029]193  //------------------
194  //set the frame size according to the chroma format
195  streamoff frameSize = 0;
196  UInt wordsize=1; // default to 8-bit, unless a channel with more than 8-bits is detected.
197  for (UInt component = 0; component < getNumberValidComponents(format); component++)
198  {
199    ComponentID compID=ComponentID(component);
200    frameSize += (width >> getComponentScaleX(compID, format)) * (height >> getComponentScaleY(compID, format));
[1246]201    if (m_fileBitdepth[toChannelType(compID)] > 8)
202    {
203      wordsize=2;
204    }
[1029]205  }
206  frameSize *= wordsize;
207  //------------------
[313]208
[1029]209  const streamoff offset = frameSize * numFrames;
210
[313]211  /* attempt to seek */
212  if (!!m_cHandle.seekg(offset, ios::cur))
[1246]213  {
[313]214    return; /* success */
[1246]215  }
[313]216  m_cHandle.clear();
217
218  /* fall back to consuming the input */
219  Char buf[512];
[1246]220  const UInt offset_mod_bufsize = offset % sizeof(buf);
[313]221  for (streamoff i = 0; i < offset - offset_mod_bufsize; i += sizeof(buf))
222  {
223    m_cHandle.read(buf, sizeof(buf));
224  }
225  m_cHandle.read(buf, offset_mod_bufsize);
226}
227
228/**
229 * Read width*height pixels from fd into dst, optionally
230 * padding the left and right edges by edge-extension.  Input may be
231 * either 8bit or 16bit little-endian lsb-aligned words.
232 *
[1258]233 * @param dst          destination image plane
234 * @param fd           input file stream
235 * @param is16bit      true if input file carries > 8bit data, false otherwise.
236 * @param stride444    distance between vertically adjacent pixels of dst.
237 * @param width444     width of active area in dst.
238 * @param height444    height of active area in dst.
239 * @param pad_x444     length of horizontal padding.
240 * @param pad_y444     length of vertical padding.
241 * @param compID       chroma component
242 * @param destFormat   chroma format of image
243 * @param fileFormat   chroma format of file
244 * @param fileBitDepth component bit depth in file
[313]245 * @return true for success, false in case of error
246 */
[1029]247static Bool readPlane(Pel* dst,
248                      istream& fd,
249                      Bool is16bit,
250                      UInt stride444,
251                      UInt width444,
252                      UInt height444,
253                      UInt pad_x444,
254                      UInt pad_y444,
255                      const ComponentID compID,
256                      const ChromaFormat destFormat,
257                      const ChromaFormat fileFormat,
258                      const UInt fileBitDepth)
[313]259{
[1029]260  const UInt csx_file =getComponentScaleX(compID, fileFormat);
261  const UInt csy_file =getComponentScaleY(compID, fileFormat);
262  const UInt csx_dest =getComponentScaleX(compID, destFormat);
263  const UInt csy_dest =getComponentScaleY(compID, destFormat);
264
265  const UInt width_dest       = width444 >>csx_dest;
266  const UInt height_dest      = height444>>csy_dest;
267  const UInt pad_x_dest       = pad_x444>>csx_dest;
268  const UInt pad_y_dest       = pad_y444>>csy_dest;
269  const UInt stride_dest      = stride444>>csx_dest;
270
271  const UInt full_width_dest  = width_dest+pad_x_dest;
272  const UInt full_height_dest = height_dest+pad_y_dest;
273
274  const UInt stride_file      = (width444 * (is16bit ? 2 : 1)) >> csx_file;
275
276  UChar  *buf   = new UChar[stride_file];
277
278  if (compID!=COMPONENT_Y && (fileFormat==CHROMA_400 || destFormat==CHROMA_400))
[313]279  {
[1029]280    if (destFormat!=CHROMA_400)
[313]281    {
[1029]282      // set chrominance data to mid-range: (1<<(fileBitDepth-1))
283      const Pel value=Pel(1<<(fileBitDepth-1));
284      for (UInt y = 0; y < full_height_dest; y++, dst+=stride_dest)
[1246]285      {
[1029]286        for (UInt x = 0; x < full_width_dest; x++)
[1246]287        {
[1029]288          dst[x] = value;
[1246]289        }
290      }
[313]291    }
292
[1029]293    if (fileFormat!=CHROMA_400)
[313]294    {
[1029]295      const UInt height_file      = height444>>csy_file;
296      fd.seekg(height_file*stride_file, ios::cur);
297      if (fd.eof() || fd.fail() )
[313]298      {
[1029]299        delete[] buf;
300        return false;
[313]301      }
302    }
[1029]303  }
304  else
305  {
306    const UInt mask_y_file=(1<<csy_file)-1;
307    const UInt mask_y_dest=(1<<csy_dest)-1;
308    for(UInt y444=0; y444<height444; y444++)
[313]309    {
[1029]310      if ((y444&mask_y_file)==0)
[313]311      {
[1029]312        // read a new line
313        fd.read(reinterpret_cast<Char*>(buf), stride_file);
314        if (fd.eof() || fd.fail() )
315        {
316          delete[] buf;
317          return false;
318        }
[313]319      }
[1029]320
321      if ((y444&mask_y_dest)==0)
322      {
323        // process current destination line
324        if (csx_file < csx_dest)
325        {
326          // eg file is 444, dest is 422.
327          const UInt sx=csx_dest-csx_file;
328          if (!is16bit)
329          {
330            for (UInt x = 0; x < width_dest; x++)
[1246]331            {
[1029]332              dst[x] = buf[x<<sx];
[1246]333            }
[1029]334          }
335          else
336          {
337            for (UInt x = 0; x < width_dest; x++)
338            {
339              dst[x] = Pel(buf[(x<<sx)*2+0]) | (Pel(buf[(x<<sx)*2+1])<<8);
340            }
341          }
342        }
343        else
344        {
345          // eg file is 422, dest is 444.
346          const UInt sx=csx_file-csx_dest;
347          if (!is16bit)
348          {
349            for (UInt x = 0; x < width_dest; x++)
[1246]350            {
[1029]351              dst[x] = buf[x>>sx];
[1246]352            }
[1029]353          }
354          else
355          {
356            for (UInt x = 0; x < width_dest; x++)
[1246]357            {
[1029]358              dst[x] = Pel(buf[(x>>sx)*2+0]) | (Pel(buf[(x>>sx)*2+1])<<8);
[1246]359            }
[1029]360          }
361        }
362
363        // process right hand side padding
364        const Pel val=dst[width_dest-1];
365        for (UInt x = width_dest; x < full_width_dest; x++)
[1246]366        {
[1029]367          dst[x] = val;
[1246]368        }
[1029]369
370        dst += stride_dest;
371      }
[313]372    }
373
[1029]374    // process lower padding
375    for (UInt y = height_dest; y < full_height_dest; y++, dst+=stride_dest)
[1246]376    {
[1029]377      for (UInt x = 0; x < full_width_dest; x++)
[1246]378      {
[1029]379        dst[x] = (dst - stride_dest)[x];
[1246]380      }
381    }
[313]382  }
383  delete[] buf;
384  return true;
385}
386
387/**
[1258]388 * Write an image plane (width444*height444 pixels) from src into output stream fd.
[313]389 *
[1258]390 * @param fd         output file stream
391 * @param src        source image
392 * @param is16bit    true if input file carries > 8bit data, false otherwise.
393 * @param stride444  distance between vertically adjacent pixels of src.
394 * @param width444   width of active area in src.
395 * @param height444  height of active area in src.
396 * @param compID       chroma component
397 * @param srcFormat    chroma format of image
398 * @param fileFormat   chroma format of file
399 * @param fileBitDepth component bit depth in file
[313]400 * @return true for success, false in case of error
401 */
402static Bool writePlane(ostream& fd, Pel* src, Bool is16bit,
[1029]403                       UInt stride444,
404                       UInt width444, UInt height444,
405                       const ComponentID compID,
406                       const ChromaFormat srcFormat,
407                       const ChromaFormat fileFormat,
408                       const UInt fileBitDepth)
[313]409{
[1029]410  const UInt csx_file =getComponentScaleX(compID, fileFormat);
411  const UInt csy_file =getComponentScaleY(compID, fileFormat);
412  const UInt csx_src  =getComponentScaleX(compID, srcFormat);
413  const UInt csy_src  =getComponentScaleY(compID, srcFormat);
414
415  const UInt stride_src      = stride444>>csx_src;
416
417  const UInt stride_file      = (width444 * (is16bit ? 2 : 1)) >> csx_file;
418  const UInt width_file       = width444 >>csx_file;
419  const UInt height_file      = height444>>csy_file;
420
421  UChar  *buf   = new UChar[stride_file];
422
423  if (compID!=COMPONENT_Y && (fileFormat==CHROMA_400 || srcFormat==CHROMA_400))
[313]424  {
[1029]425    if (fileFormat!=CHROMA_400)
[313]426    {
[1029]427      const UInt value=1<<(fileBitDepth-1);
428
429      for(UInt y=0; y< height_file; y++)
[313]430      {
[1029]431        if (!is16bit)
432        {
433          UChar val(value);
434          for (UInt x = 0; x < width_file; x++)
[1246]435          {
[1029]436            buf[x]=val;
[1246]437          }
[1029]438        }
439        else
440        {
441          UShort val(value);
442          for (UInt x = 0; x < width_file; x++)
443          {
444            buf[2*x+0]= (val>>0) & 0xff;
445            buf[2*x+1]= (val>>8) & 0xff;
446          }
447        }
448
449        fd.write(reinterpret_cast<Char*>(buf), stride_file);
450        if (fd.eof() || fd.fail() )
451        {
452          delete[] buf;
453          return false;
454        }
[313]455      }
456    }
[1029]457  }
458  else
459  {
460    const UInt mask_y_file=(1<<csy_file)-1;
461    const UInt mask_y_src =(1<<csy_src )-1;
462    for(UInt y444=0; y444<height444; y444++)
[313]463    {
[1029]464      if ((y444&mask_y_file)==0)
[313]465      {
[1029]466        // write a new line
467        if (csx_file < csx_src)
468        {
469          // eg file is 444, source is 422.
470          const UInt sx=csx_src-csx_file;
471          if (!is16bit)
472          {
473            for (UInt x = 0; x < width_file; x++)
474            {
475              buf[x] = (UChar)(src[x>>sx]);
476            }
477          }
478          else
479          {
480            for (UInt x = 0; x < width_file; x++)
481            {
482              buf[2*] = (src[x>>sx]>>0) & 0xff;
483              buf[2*x+1] = (src[x>>sx]>>8) & 0xff;
484            }
485          }
486        }
487        else
488        {
489          // eg file is 422, src is 444.
490          const UInt sx=csx_file-csx_src;
491          if (!is16bit)
492          {
493            for (UInt x = 0; x < width_file; x++)
494            {
495              buf[x] = (UChar)(src[x<<sx]);
496            }
497          }
498          else
499          {
500            for (UInt x = 0; x < width_file; x++)
501            {
502              buf[2*] = (src[x<<sx]>>0) & 0xff;
503              buf[2*x+1] = (src[x<<sx]>>8) & 0xff;
504            }
505          }
506        }
507
508        fd.write(reinterpret_cast<Char*>(buf), stride_file);
509        if (fd.eof() || fd.fail() )
510        {
511          delete[] buf;
512          return false;
513        }
[313]514      }
515
[1029]516      if ((y444&mask_y_src)==0)
517      {
518        src += stride_src;
519      }
520
[313]521    }
522  }
523  delete[] buf;
524  return true;
525}
526
[442]527static Bool writeField(ostream& fd, Pel* top, Pel* bottom, Bool is16bit,
[1029]528                       UInt stride444,
529                       UInt width444, UInt height444,
530                       const ComponentID compID,
531                       const ChromaFormat srcFormat,
532                       const ChromaFormat fileFormat,
533                       const UInt fileBitDepth, const Bool isTff)
[442]534{
[1029]535  const UInt csx_file =getComponentScaleX(compID, fileFormat);
536  const UInt csy_file =getComponentScaleY(compID, fileFormat);
537  const UInt csx_src  =getComponentScaleX(compID, srcFormat);
538  const UInt csy_src  =getComponentScaleY(compID, srcFormat);
539
540  const UInt stride_src      = stride444>>csx_src;
541
542  const UInt stride_file      = (width444 * (is16bit ? 2 : 1)) >> csx_file;
543  const UInt width_file       = width444 >>csx_file;
544  const UInt height_file      = height444>>csy_file;
545
546  UChar  *buf   = new UChar[stride_file * 2];
547
548  if (compID!=COMPONENT_Y && (fileFormat==CHROMA_400 || srcFormat==CHROMA_400))
[442]549  {
[1029]550    if (fileFormat!=CHROMA_400)
[442]551    {
[1029]552      const UInt value=1<<(fileBitDepth-1);
553
554      for(UInt y=0; y< height_file; y++)
[442]555      {
[1029]556        for (UInt field = 0; field < 2; field++)
557        {
558          UChar *fieldBuffer = buf + (field * stride_file);
559
560          if (!is16bit)
561          {
562            UChar val(value);
563            for (UInt x = 0; x < width_file; x++)
[1246]564            {
[1029]565              fieldBuffer[x]=val;
[1246]566            }
[1029]567          }
568          else
569          {
570            UShort val(value);
571            for (UInt x = 0; x < width_file; x++)
572            {
573              fieldBuffer[2*x+0]= (val>>0) & 0xff;
574              fieldBuffer[2*x+1]= (val>>8) & 0xff;
575            }
576          }
577        }
578
579        fd.write(reinterpret_cast<Char*>(buf), (stride_file * 2));
580        if (fd.eof() || fd.fail() )
581        {
582          delete[] buf;
583          return false;
584        }
[442]585      }
586    }
[1029]587  }
588  else
589  {
590    const UInt mask_y_file=(1<<csy_file)-1;
591    const UInt mask_y_src =(1<<csy_src )-1;
592    for(UInt y444=0; y444<height444; y444++)
[442]593    {
[1029]594      if ((y444&mask_y_file)==0)
[442]595      {
[1029]596        for (UInt field = 0; field < 2; field++)
597        {
598          UChar *fieldBuffer = buf + (field * stride_file);
599          Pel   *src         = (((field == 0) && isTff) || ((field == 1) && (!isTff))) ? top : bottom;
600
601          // write a new line
602          if (csx_file < csx_src)
603          {
604            // eg file is 444, source is 422.
605            const UInt sx=csx_src-csx_file;
606            if (!is16bit)
607            {
608              for (UInt x = 0; x < width_file; x++)
609              {
610                fieldBuffer[x] = (UChar)(src[x>>sx]);
611              }
612            }
613            else
614            {
615              for (UInt x = 0; x < width_file; x++)
616              {
617                fieldBuffer[2*] = (src[x>>sx]>>0) & 0xff;
618                fieldBuffer[2*x+1] = (src[x>>sx]>>8) & 0xff;
619              }
620            }
621          }
622          else
623          {
624            // eg file is 422, src is 444.
625            const UInt sx=csx_file-csx_src;
626            if (!is16bit)
627            {
628              for (UInt x = 0; x < width_file; x++)
629              {
630                fieldBuffer[x] = (UChar)(src[x<<sx]);
631              }
632            }
633            else
634            {
635              for (UInt x = 0; x < width_file; x++)
636              {
637                fieldBuffer[2*] = (src[x<<sx]>>0) & 0xff;
638                fieldBuffer[2*x+1] = (src[x<<sx]>>8) & 0xff;
639              }
640            }
641          }
642        }
643
644        fd.write(reinterpret_cast<Char*>(buf), (stride_file * 2));
645        if (fd.eof() || fd.fail() )
646        {
647          delete[] buf;
648          return false;
649        }
[442]650      }
[1029]651
652      if ((y444&mask_y_src)==0)
653      {
654        top    += stride_src;
655        bottom += stride_src;
656      }
657
[442]658    }
659  }
660  delete[] buf;
661  return true;
662}
[1029]663
[313]664/**
665 * Read one Y'CbCr frame, performing any required input scaling to change
666 * from the bitdepth of the input file to the internal bit-depth.
667 *
668 * If a bit-depth reduction is required, and internalBitdepth >= 8, then
669 * the input file is assumed to be ITU-R BT.601/709 compliant, and the
670 * resulting data is clipped to the appropriate legal range, as if the
671 * file had been provided at the lower-bitdepth compliant to Rec601/709.
672 *
[1260]673 * @param pPicYuvUser      input picture YUV buffer class pointer
674 * @param pPicYuvTrueOrg
675 * @param ipcsc
676 * @param aiPad            source padding size, aiPad[0] = horizontal, aiPad[1] = vertical
677 * @param format           chroma format
[313]678 * @return true for success, false in case of error
679 */
[1029]680Bool TVideoIOYuv::read ( TComPicYuv*  pPicYuvUser, TComPicYuv* pPicYuvTrueOrg, const InputColourSpaceConversion ipcsc, Int aiPad[2], ChromaFormat format )
[313]681{
682  // check end-of-file
[1246]683  if ( isEof() )
684  {
685    return false;
686  }
[1029]687  TComPicYuv *pPicYuv=pPicYuvTrueOrg;
[1246]688  if (format>=NUM_CHROMA_FORMAT)
689  {
690    format=pPicYuv->getChromaFormat();
691  }
[313]692
[1029]693  Bool is16bit = false;
694
695  for(UInt ch=0; ch<MAX_NUM_CHANNEL_TYPE; ch++)
[313]696  {
[1246]697    if (m_fileBitdepth[ch] > 8)
698    {
699      is16bit=true;
700    }
[313]701  }
[1029]702
703  const UInt stride444      = pPicYuv->getStride(COMPONENT_Y);
704
705  // compute actual YUV width & height excluding padding size
706  const UInt pad_h444       = aiPad[0];
707  const UInt pad_v444       = aiPad[1];
708
709  const UInt width_full444  = pPicYuv->getWidth(COMPONENT_Y);
710  const UInt height_full444 = pPicYuv->getHeight(COMPONENT_Y);
711
712  const UInt width444       = width_full444 - pad_h444;
713  const UInt height444      = height_full444 - pad_v444;
714
715  for(UInt comp=0; comp<MAX_NUM_COMPONENT; comp++)
[313]716  {
[1029]717    const ComponentID compID = ComponentID(comp);
718    const ChannelType chType=toChannelType(compID);
719
720    const Int desired_bitdepth = m_MSBExtendedBitDepth[chType] + m_bitdepthShift[chType];
721
722#if !CLIP_TO_709_RANGE
723    const Pel minval = 0;
724    const Pel maxval = (1 << desired_bitdepth) - 1;
725#else
726    const Bool b709Compliance=(m_bitdepthShift[chType] < 0 && desired_bitdepth >= 8);     /* ITU-R BT.709 compliant clipping for converting say 10b to 8b */
727    const Pel minval = b709Compliance? ((   1 << (desired_bitdepth - 8))   ) : 0;
728    const Pel maxval = b709Compliance? ((0xff << (desired_bitdepth - 8)) -1) : (1 << desired_bitdepth) - 1;
[313]729#endif
730
[1029]731    if (! readPlane(pPicYuv->getAddr(compID), m_cHandle, is16bit, stride444, width444, height444, pad_h444, pad_v444, compID, pPicYuv->getChromaFormat(), format, m_fileBitdepth[chType]))
732    {
733      return false;
734    }
[313]735
[1029]736    if (compID < pPicYuv->getNumberValidComponents() )
737    {
738      const UInt csx=getComponentScaleX(compID, pPicYuv->getChromaFormat());
739      const UInt csy=getComponentScaleY(compID, pPicYuv->getChromaFormat());
740      scalePlane(pPicYuv->getAddr(compID), stride444>>csx, width_full444>>csx, height_full444>>csy, m_bitdepthShift[chType], minval, maxval);
741    }
742  }
[313]743
[1029]744  Int internalBitDepth[MAX_NUM_CHANNEL_TYPE];
745  for(UInt chType=0; chType<MAX_NUM_CHANNEL_TYPE; chType++)
746  {
747    internalBitDepth[chType] = m_bitdepthShift[chType] + m_MSBExtendedBitDepth[chType];
748  }
749  ColourSpaceConvert(*pPicYuvTrueOrg, *pPicYuvUser, ipcsc, internalBitDepth, true);
[313]750
751  return true;
752}
753
754/**
755 * Write one Y'CbCr frame. No bit-depth conversion is performed, pcPicYuv is
756 * assumed to be at TVideoIO::m_fileBitdepth depth.
757 *
[1260]758 * @param pPicYuvUser      input picture YUV buffer class pointer
759 * @param ipCSC
760 * @param confLeft         conformance window left border
761 * @param confRight        conformance window right border
762 * @param confTop          conformance window top border
763 * @param confBottom       conformance window bottom border
764 * @param format           chroma format
[313]765 * @return true for success, false in case of error
766 */
[1029]767Bool TVideoIOYuv::write( TComPicYuv* pPicYuvUser, const InputColourSpaceConversion ipCSC, Int confLeft, Int confRight, Int confTop, Int confBottom, ChromaFormat format )
[313]768{
[1029]769  TComPicYuv cPicYuvCSCd;
770  if (ipCSC!=IPCOLOURSPACE_UNCHANGED)
771  {
772    cPicYuvCSCd.create(pPicYuvUser->getWidth(COMPONENT_Y), pPicYuvUser->getHeight(COMPONENT_Y), pPicYuvUser->getChromaFormat(), g_uiMaxCUWidth, g_uiMaxCUHeight, g_uiMaxCUDepth);
773    Int internalBitDepth[MAX_NUM_CHANNEL_TYPE];
774    for(UInt chType=0; chType<MAX_NUM_CHANNEL_TYPE; chType++)
775    {
776      internalBitDepth[chType] = m_bitdepthShift[chType] + m_MSBExtendedBitDepth[chType];
777    }
778    ColourSpaceConvert(*pPicYuvUser, cPicYuvCSCd, ipCSC, internalBitDepth, false);
779  }
780  TComPicYuv *pPicYuv=(ipCSC==IPCOLOURSPACE_UNCHANGED) ? pPicYuvUser : &cPicYuvCSCd;
781
[313]782  // compute actual YUV frame size excluding padding size
[1029]783  const Int   iStride444 = pPicYuv->getStride(COMPONENT_Y);
784  const UInt width444  = pPicYuv->getWidth(COMPONENT_Y) - confLeft - confRight;
785  const UInt height444 = pPicYuv->getHeight(COMPONENT_Y) -  confTop  - confBottom;
786  Bool is16bit = false;
787  Bool nonZeroBitDepthShift=false;
[313]788
[1029]789  if ((width444 == 0) || (height444 == 0))
[823]790  {
[1029]791    printf ("\nWarning: writing %d x %d luma sample output picture!", width444, height444);
[823]792  }
793
[1029]794  for(UInt ch=0; ch<MAX_NUM_CHANNEL_TYPE; ch++)
[313]795  {
[1246]796    if (m_fileBitdepth[ch] > 8)
797    {
798      is16bit=true;
799    }
800    if (m_bitdepthShift[ch] != 0)
801    {
802      nonZeroBitDepthShift=true;
803    }
[1029]804  }
805
806  TComPicYuv *dstPicYuv = NULL;
807  Bool retval = true;
[1246]808  if (format>=NUM_CHROMA_FORMAT)
809  {
810    format=pPicYuv->getChromaFormat();
811  }
[1029]812
813  if (nonZeroBitDepthShift)
814  {
[313]815    dstPicYuv = new TComPicYuv;
[1029]816    dstPicYuv->create( pPicYuv->getWidth(COMPONENT_Y), pPicYuv->getHeight(COMPONENT_Y), pPicYuv->getChromaFormat(), 1, 1, 0 );
817    pPicYuv->copyToPic(dstPicYuv);
818
819    for(UInt comp=0; comp<dstPicYuv->getNumberValidComponents(); comp++)
820    {
821      const ComponentID compID=ComponentID(comp);
822      const ChannelType ch=toChannelType(compID);
823#if !CLIP_TO_709_RANGE
824      const Pel minval = 0;
825      const Pel maxval = (1 << m_MSBExtendedBitDepth[ch]) - 1;
[494]826#else
[1029]827      const Bool b709Compliance=(-m_bitdepthShift[ch] < 0 && m_MSBExtendedBitDepth[ch] >= 8);     /* ITU-R BT.709 compliant clipping for converting say 10b to 8b */
828      const Pel minval = b709Compliance? ((   1 << (m_MSBExtendedBitDepth[ch] - 8))   ) : 0;
829      const Pel maxval = b709Compliance? ((0xff << (m_MSBExtendedBitDepth[ch] - 8)) -1) : (1 << m_MSBExtendedBitDepth[ch]) - 1;
[494]830#endif
[313]831
[1029]832      scalePlane(dstPicYuv->getAddr(compID), dstPicYuv->getStride(compID), dstPicYuv->getWidth(compID), dstPicYuv->getHeight(compID), -m_bitdepthShift[ch], minval, maxval);
[313]833    }
834  }
835  else
836  {
837    dstPicYuv = pPicYuv;
838  }
[1029]839
840  for(UInt comp=0; retval && comp<dstPicYuv->getNumberValidComponents(); comp++)
[313]841  {
[1029]842    const ComponentID compID = ComponentID(comp);
843    const ChannelType ch=toChannelType(compID);
844    const UInt csx = pPicYuv->getComponentScaleX(compID);
845    const UInt csy = pPicYuv->getComponentScaleY(compID);
846    const Int planeOffset =  (confLeft>>csx) + (confTop>>csy) * pPicYuv->getStride(compID);
847    if (! writePlane(m_cHandle, dstPicYuv->getAddr(compID) + planeOffset, is16bit, iStride444, width444, height444, compID, dstPicYuv->getChromaFormat(), format, m_fileBitdepth[ch]))
848    {
849      retval=false;
850    }
[313]851  }
852
[1029]853  if (nonZeroBitDepthShift)
[313]854  {
855    dstPicYuv->destroy();
856    delete dstPicYuv;
[1029]857  }
858
859  cPicYuvCSCd.destroy();
860
[313]861  return retval;
862}
863
[1029]864Bool TVideoIOYuv::write( TComPicYuv* pPicYuvUserTop, TComPicYuv* pPicYuvUserBottom, const InputColourSpaceConversion ipCSC, Int confLeft, Int confRight, Int confTop, Int confBottom, ChromaFormat format, const Bool isTff )
865{
[442]866
[1029]867  TComPicYuv cPicYuvTopCSCd;
868  TComPicYuv cPicYuvBottomCSCd;
869  if (ipCSC!=IPCOLOURSPACE_UNCHANGED)
[823]870  {
[1029]871    cPicYuvTopCSCd   .create(pPicYuvUserTop   ->getWidth(COMPONENT_Y), pPicYuvUserTop   ->getHeight(COMPONENT_Y), pPicYuvUserTop   ->getChromaFormat(), g_uiMaxCUWidth, g_uiMaxCUHeight, g_uiMaxCUDepth);
872    cPicYuvBottomCSCd.create(pPicYuvUserBottom->getWidth(COMPONENT_Y), pPicYuvUserBottom->getHeight(COMPONENT_Y), pPicYuvUserBottom->getChromaFormat(), g_uiMaxCUWidth, g_uiMaxCUHeight, g_uiMaxCUDepth);
873    Int internalBitDepth[MAX_NUM_CHANNEL_TYPE];
874    for(UInt chType=0; chType<MAX_NUM_CHANNEL_TYPE; chType++)
875    {
876      internalBitDepth[chType] = m_bitdepthShift[chType] + m_MSBExtendedBitDepth[chType];
877    }
878    ColourSpaceConvert(*pPicYuvUserTop,    cPicYuvTopCSCd,    ipCSC, internalBitDepth, false);
879    ColourSpaceConvert(*pPicYuvUserBottom, cPicYuvBottomCSCd, ipCSC, internalBitDepth, false);
[823]880  }
[1029]881  TComPicYuv *pPicYuvTop    = (ipCSC==IPCOLOURSPACE_UNCHANGED) ? pPicYuvUserTop    : &cPicYuvTopCSCd;
882  TComPicYuv *pPicYuvBottom = (ipCSC==IPCOLOURSPACE_UNCHANGED) ? pPicYuvUserBottom : &cPicYuvBottomCSCd;
883
884  Bool is16bit = false;
885  Bool nonZeroBitDepthShift=false;
886
887  for(UInt ch=0; ch<MAX_NUM_CHANNEL_TYPE; ch++)
[442]888  {
[1246]889    if (m_fileBitdepth[ch] > 8)
890    {
891      is16bit=true;
892    }
893    if (m_bitdepthShift[ch] != 0)
894    {
895      nonZeroBitDepthShift=true;
896    }
[1029]897  }
898
899  TComPicYuv *dstPicYuvTop    = NULL;
900  TComPicYuv *dstPicYuvBottom = NULL;
901
902  for (UInt field = 0; field < 2; field++)
903  {
904    TComPicYuv *pPicYuv = (field == 0) ? pPicYuvTop : pPicYuvBottom;
905
[1246]906    if (format>=NUM_CHROMA_FORMAT)
907    {
908      format=pPicYuv->getChromaFormat();
909    }
[1029]910
911    TComPicYuv* &dstPicYuv = (field == 0) ? dstPicYuvTop : dstPicYuvBottom;
912
913    if (nonZeroBitDepthShift)
914    {
915      dstPicYuv = new TComPicYuv;
916      dstPicYuv->create( pPicYuv->getWidth(COMPONENT_Y), pPicYuv->getHeight(COMPONENT_Y), pPicYuv->getChromaFormat(), 1, 1, 0 );
917      pPicYuv->copyToPic(dstPicYuv);
918
919      for(UInt comp=0; comp<dstPicYuv->getNumberValidComponents(); comp++)
920      {
921        const ComponentID compID=ComponentID(comp);
922        const ChannelType ch=toChannelType(compID);
923#if !CLIP_TO_709_RANGE
924        const Pel minval = 0;
925        const Pel maxval = (1 << m_MSBExtendedBitDepth[ch]) - 1;
[494]926#else
[1029]927        const Bool b709Compliance=(-m_bitdepthShift[ch] < 0 && m_MSBExtendedBitDepth[ch] >= 8);     /* ITU-R BT.709 compliant clipping for converting say 10b to 8b */
928        const Pel minval = b709Compliance? ((   1 << (m_MSBExtendedBitDepth[ch] - 8))   ) : 0;
929        const Pel maxval = b709Compliance? ((0xff << (m_MSBExtendedBitDepth[ch] - 8)) -1) : (1 << m_MSBExtendedBitDepth[ch]) - 1;
[494]930#endif
[1029]931
932        scalePlane(dstPicYuv->getAddr(compID), dstPicYuv->getStride(compID), dstPicYuv->getWidth(compID), dstPicYuv->getHeight(compID), -m_bitdepthShift[ch], minval, maxval);
933      }
[442]934    }
[1029]935    else
[442]936    {
[1029]937      dstPicYuv = pPicYuv;
[442]938    }
939  }
[1029]940
941  Bool retval = true;
942
943  assert(dstPicYuvTop->getNumberValidComponents() == dstPicYuvBottom->getNumberValidComponents());
944  assert(dstPicYuvTop->getChromaFormat()          == dstPicYuvBottom->getChromaFormat()         );
945  assert(dstPicYuvTop->getWidth(COMPONENT_Y)      == dstPicYuvBottom->getWidth(COMPONENT_Y)    );
946  assert(dstPicYuvTop->getHeight(COMPONENT_Y)     == dstPicYuvBottom->getHeight(COMPONENT_Y)    );
947  assert(dstPicYuvTop->getStride(COMPONENT_Y)     == dstPicYuvBottom->getStride(COMPONENT_Y)    );
948
949  for(UInt comp=0; retval && comp<dstPicYuvTop->getNumberValidComponents(); comp++)
[442]950  {
[1029]951    const ComponentID compID = ComponentID(comp);
952    const ChannelType ch=toChannelType(compID);
953
954    assert(dstPicYuvTop->getComponentScaleX(compID) == dstPicYuvBottom->getComponentScaleX(compID));
955    assert(dstPicYuvTop->getComponentScaleY(compID) == dstPicYuvBottom->getComponentScaleY(compID));
956    assert(dstPicYuvTop->getStride         (compID) == dstPicYuvBottom->getStride         (compID));
957
958    const UInt width444   = dstPicYuvTop->getWidth(COMPONENT_Y)  - (confLeft + confRight);
959    const UInt height444  = dstPicYuvTop->getHeight(COMPONENT_Y) - (confTop + confBottom);
960
961    if ((width444 == 0) || (height444 == 0))
962    {
963      printf ("\nWarning: writing %d x %d luma sample output picture!", width444, height444);
964    }
965
966    const UInt csx = dstPicYuvTop->getComponentScaleX(compID);
967    const UInt csy = dstPicYuvTop->getComponentScaleY(compID);
968    const Int planeOffset  = (confLeft>>csx) + ( confTop>>csy) * dstPicYuvTop->getStride(compID); //offset is for entire frame - round up for top field and down for bottom field
969
970    if (! writeField(m_cHandle,
971                     (dstPicYuvTop   ->getAddr(compID) + planeOffset),
972                     (dstPicYuvBottom->getAddr(compID) + planeOffset),
973                     is16bit,
974                     dstPicYuvTop->getStride(COMPONENT_Y),
975                     width444, height444, compID, dstPicYuvTop->getChromaFormat(), format, m_fileBitdepth[ch], isTff))
976    {
977      retval=false;
978    }
[442]979  }
[1029]980
981  if (nonZeroBitDepthShift)
[442]982  {
[1029]983    dstPicYuvTop->destroy();
984    dstPicYuvBottom->destroy();
985    delete dstPicYuvTop;
986    delete dstPicYuvBottom;
[442]987  }
[1029]988
989  cPicYuvTopCSCd.destroy();
990  cPicYuvBottomCSCd.destroy();
991
992  return retval;
993}
994
995static Void
996copyPlane(const TComPicYuv &src, const ComponentID srcPlane, TComPicYuv &dest, const ComponentID destPlane)
997{
998  const UInt width=src.getWidth(srcPlane);
999  const UInt height=src.getHeight(srcPlane);
1000  assert(dest.getWidth(destPlane) == width);
1001  assert(dest.getHeight(destPlane) == height);
1002  const Pel *pSrc=src.getAddr(srcPlane);
1003  Pel *pDest=dest.getAddr(destPlane);
1004  const UInt strideSrc=src.getStride(srcPlane);
1005  const UInt strideDest=dest.getStride(destPlane);
1006  for(UInt y=0; y<height; y++, pSrc+=strideSrc, pDest+=strideDest)
[442]1007  {
[1029]1008    memcpy(pDest, pSrc, width*sizeof(Pel));
[442]1009  }
[1029]1010}
1011
1012// static member
1013Void TVideoIOYuv::ColourSpaceConvert(const TComPicYuv &src, TComPicYuv &dest, const InputColourSpaceConversion conversion, const Int bitDepths[MAX_NUM_CHANNEL_TYPE], Bool bIsForwards)
1014{
1015  const ChromaFormat  format=src.getChromaFormat();
1016  const UInt          numValidComp=src.getNumberValidComponents();
1017
1018  switch (conversion)
[442]1019  {
[1029]1020    case IPCOLOURSPACE_YCbCrtoYYY:
1021      if (format!=CHROMA_444)
1022      {
1023        // only 444 is handled.
1024        assert(format==CHROMA_444);
1025        exit(1);
1026      }
1027
1028      {
1029        for(UInt comp=0; comp<numValidComp; comp++)
[1246]1030        {
[1029]1031          copyPlane(src, ComponentID(bIsForwards?0:comp), dest, ComponentID(comp));
[1246]1032        }
[1029]1033      }
1034      break;
1035    case IPCOLOURSPACE_YCbCrtoYCrCb:
1036      {
1037        for(UInt comp=0; comp<numValidComp; comp++)
[1246]1038        {
[1029]1039          copyPlane(src, ComponentID(comp), dest, ComponentID((numValidComp-comp)%numValidComp));
[1246]1040        }
[1029]1041      }
1042      break;
1043
1044    case IPCOLOURSPACE_RGBtoGBR:
1045      {
1046        if (format!=CHROMA_444)
1047        {
1048          // only 444 is handled.
1049          assert(format==CHROMA_444);
1050          exit(1);
1051        }
1052
1053        // channel re-mapping
1054        for(UInt comp=0; comp<numValidComp; comp++)
1055        {
1056          const ComponentID compIDsrc=ComponentID((comp+1)%numValidComp);
1057          const ComponentID compIDdst=ComponentID(comp);
1058          copyPlane(src, bIsForwards?compIDsrc:compIDdst, dest, bIsForwards?compIDdst:compIDsrc);
1059        }
1060      }
1061      break;
1062
1063    case IPCOLOURSPACE_UNCHANGED:
1064    default:
1065      {
1066        for(UInt comp=0; comp<numValidComp; comp++)
[1246]1067        {
[1029]1068          copyPlane(src, ComponentID(comp), dest, ComponentID(comp));
[1246]1069        }
[1029]1070      }
1071      break;
[442]1072  }
1073}
Note: See TracBrowser for help on using the repository browser.