source: 3DVCSoftware/trunk/source/Lib/TLibVideoIO/TVideoIOYuv.cpp @ 1402

Last change on this file since 1402 was 1386, checked in by tech, 9 years ago

Merged 15.1-dev1@1381.

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