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

Last change on this file since 1554 was 1549, checked in by seregin, 9 years ago

port rev 4732, update copyright notice to include 2016

  • Property svn:eol-style set to native
File size: 33.1 KB
Line 
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
4 * granted under this license.
5 *
6 * Copyright (c) 2010-2016, ITU/ISO/IEC
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>
44#include <memory.h>
45
46#include "TLibCommon/TComRom.h"
47#include "TVideoIOYuv.h"
48
49using namespace std;
50
51// ====================================================================================================================
52// Local Functions
53// ====================================================================================================================
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 */
70static Void scalePlane(Pel* img, const UInt stride, const UInt width, const UInt height, Int shiftbits, Pel minval, Pel maxval)
71{
72  if (shiftbits > 0)
73  {
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    }
81  }
82  else if (shiftbits < 0)
83  {
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    }
94  }
95}
96
97static Void
98copyPlane(const TComPicYuv &src, const ComponentID srcPlane, TComPicYuv &dest, const ComponentID destPlane);
99
100// ====================================================================================================================
101// Public member functions
102// ====================================================================================================================
103
104/**
105 * Open file for reading/writing Y'CbCr frames.
106 *
107 * Frames read/written have bitdepth fileBitDepth, and are automatically
108 * formatted as 8 or 16 bit word values (see TVideoIOYuv::write()).
109 *
110 * Image data read or written is converted to/from internalBitDepth
111 * (See scalePlane(), TVideoIOYuv::read() and TVideoIOYuv::write() for
112 * further details).
113 *
114 * \param pchFile          file name string
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.
119 */
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] )
121{
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];
128
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
143  if ( bWriteMode )
144  {
145    m_cHandle.open( fileName.c_str(), ios::binary | ios::out );
146
147    if( m_cHandle.fail() )
148    {
149      printf("\nfailed to write reconstructed YUV file\n");
150      exit(0);
151    }
152  }
153  else
154  {
155    m_cHandle.open( fileName.c_str(), ios::binary | ios::in );
156
157    if( m_cHandle.fail() )
158    {
159      printf("\nfailed to open Input YUV file\n");
160      exit(0);
161    }
162  }
163
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
177Bool TVideoIOYuv::isFail()
178{
179  return m_cHandle.fail();
180}
181
182/**
183 * Skip numFrames in input.
184 *
185 * This function correctly handles cases where the input file is not
186 * seekable, by consuming bytes.
187 */
188Void TVideoIOYuv::skipFrames(UInt numFrames, UInt width, UInt height, ChromaFormat format)
189{
190  if (!numFrames)
191  {
192    return;
193  }
194
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  //------------------
210
211  const streamoff offset = frameSize * numFrames;
212
213  /* attempt to seek */
214  if (!!m_cHandle.seekg(offset, ios::cur))
215  {
216    return; /* success */
217  }
218  m_cHandle.clear();
219
220  /* fall back to consuming the input */
221  TChar buf[512];
222  const streamoff offset_mod_bufsize = offset % sizeof(buf);
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/**
231 * Read width*height pixels from fd into dst, optionally
232 * padding the left and right edges by edge-extension.  Input may be
233 * either 8bit or 16bit little-endian lsb-aligned words.
234 *
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
247 * @return true for success, false in case of error
248 */
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)
261{
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  std::vector<UChar> bufVec(stride_file);
278  UChar *buf=&(bufVec[0]);
279
280  if (compID!=COMPONENT_Y && (fileFormat==CHROMA_400 || destFormat==CHROMA_400))
281  {
282    if (destFormat!=CHROMA_400)
283    {
284      // set chrominance data to mid-range: (1<<(fileBitDepth-1))
285      const Pel value=Pel(1<<(fileBitDepth-1));
286      for (UInt y = 0; y < full_height_dest; y++, dst+=stride_dest)
287      {
288        for (UInt x = 0; x < full_width_dest; x++)
289        {
290          dst[x] = value;
291        }
292      }
293    }
294
295    if (fileFormat!=CHROMA_400)
296    {
297      const UInt height_file      = height444>>csy_file;
298      fd.seekg(height_file*stride_file, ios::cur);
299      if (fd.eof() || fd.fail() )
300      {
301        return false;
302      }
303    }
304  }
305  else
306  {
307    const UInt mask_y_file=(1<<csy_file)-1;
308    const UInt mask_y_dest=(1<<csy_dest)-1;
309    for(UInt y444=0; y444<height444; y444++)
310    {
311      if ((y444&mask_y_file)==0)
312      {
313        // read a new line
314        fd.read(reinterpret_cast<TChar*>(buf), stride_file);
315        if (fd.eof() || fd.fail() )
316        {
317          return false;
318        }
319      }
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++)
331            {
332              dst[x] = buf[x<<sx];
333            }
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++)
350            {
351              dst[x] = buf[x>>sx];
352            }
353          }
354          else
355          {
356            for (UInt x = 0; x < width_dest; x++)
357            {
358              dst[x] = Pel(buf[(x>>sx)*2+0]) | (Pel(buf[(x>>sx)*2+1])<<8);
359            }
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++)
366        {
367          dst[x] = val;
368        }
369
370        dst += stride_dest;
371      }
372    }
373
374    // process lower padding
375    for (UInt y = height_dest; y < full_height_dest; y++, dst+=stride_dest)
376    {
377      for (UInt x = 0; x < full_width_dest; x++)
378      {
379        dst[x] = (dst - stride_dest)[x];
380      }
381    }
382  }
383  return true;
384}
385
386/**
387 * Write an image plane (width444*height444 pixels) from src into output stream fd.
388 *
389 * @param fd         output file stream
390 * @param src        source image
391 * @param is16bit    true if input file carries > 8bit data, false otherwise.
392 * @param stride444  distance between vertically adjacent pixels of src.
393 * @param width444   width of active area in src.
394 * @param height444  height of active area in src.
395 * @param compID       chroma component
396 * @param srcFormat    chroma format of image
397 * @param fileFormat   chroma format of file
398 * @param fileBitDepth component bit depth in file
399 * @return true for success, false in case of error
400 */
401static Bool writePlane(ostream& fd, Pel* src, Bool is16bit,
402                       UInt stride444,
403                       UInt width444, UInt height444,
404                       const ComponentID compID,
405                       const ChromaFormat srcFormat,
406                       const ChromaFormat fileFormat,
407                       const UInt fileBitDepth)
408{
409  const UInt csx_file =getComponentScaleX(compID, fileFormat);
410  const UInt csy_file =getComponentScaleY(compID, fileFormat);
411  const UInt csx_src  =getComponentScaleX(compID, srcFormat);
412  const UInt csy_src  =getComponentScaleY(compID, srcFormat);
413
414  const UInt stride_src      = stride444>>csx_src;
415
416  const UInt stride_file      = (width444 * (is16bit ? 2 : 1)) >> csx_file;
417  const UInt width_file       = width444 >>csx_file;
418  const UInt height_file      = height444>>csy_file;
419
420  std::vector<UChar> bufVec(stride_file);
421  UChar *buf=&(bufVec[0]);
422
423  if (compID!=COMPONENT_Y && (fileFormat==CHROMA_400 || srcFormat==CHROMA_400))
424  {
425    if (fileFormat!=CHROMA_400)
426    {
427      const UInt value=1<<(fileBitDepth-1);
428
429      for(UInt y=0; y< height_file; y++)
430      {
431        if (!is16bit)
432        {
433          UChar val(value);
434          for (UInt x = 0; x < width_file; x++)
435          {
436            buf[x]=val;
437          }
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<const TChar*>(buf), stride_file);
450        if (fd.eof() || fd.fail() )
451        {
452          return false;
453        }
454      }
455    }
456  }
457  else
458  {
459    const UInt mask_y_file=(1<<csy_file)-1;
460    const UInt mask_y_src =(1<<csy_src )-1;
461    for(UInt y444=0; y444<height444; y444++)
462    {
463      if ((y444&mask_y_file)==0)
464      {
465        // write a new line
466        if (csx_file < csx_src)
467        {
468          // eg file is 444, source is 422.
469          const UInt sx=csx_src-csx_file;
470          if (!is16bit)
471          {
472            for (UInt x = 0; x < width_file; x++)
473            {
474              buf[x] = (UChar)(src[x>>sx]);
475            }
476          }
477          else
478          {
479            for (UInt x = 0; x < width_file; x++)
480            {
481              buf[2*] = (src[x>>sx]>>0) & 0xff;
482              buf[2*x+1] = (src[x>>sx]>>8) & 0xff;
483            }
484          }
485        }
486        else
487        {
488          // eg file is 422, src is 444.
489          const UInt sx=csx_file-csx_src;
490          if (!is16bit)
491          {
492            for (UInt x = 0; x < width_file; x++)
493            {
494              buf[x] = (UChar)(src[x<<sx]);
495            }
496          }
497          else
498          {
499            for (UInt x = 0; x < width_file; x++)
500            {
501              buf[2*] = (src[x<<sx]>>0) & 0xff;
502              buf[2*x+1] = (src[x<<sx]>>8) & 0xff;
503            }
504          }
505        }
506
507        fd.write(reinterpret_cast<const TChar*>(buf), stride_file);
508        if (fd.eof() || fd.fail() )
509        {
510          return false;
511        }
512      }
513
514      if ((y444&mask_y_src)==0)
515      {
516        src += stride_src;
517      }
518
519    }
520  }
521  return true;
522}
523
524static Bool writeField(ostream& fd, Pel* top, Pel* bottom, Bool is16bit,
525                       UInt stride444,
526                       UInt width444, UInt height444,
527                       const ComponentID compID,
528                       const ChromaFormat srcFormat,
529                       const ChromaFormat fileFormat,
530                       const UInt fileBitDepth, const Bool isTff)
531{
532  const UInt csx_file =getComponentScaleX(compID, fileFormat);
533  const UInt csy_file =getComponentScaleY(compID, fileFormat);
534  const UInt csx_src  =getComponentScaleX(compID, srcFormat);
535  const UInt csy_src  =getComponentScaleY(compID, srcFormat);
536
537  const UInt stride_src      = stride444>>csx_src;
538
539  const UInt stride_file      = (width444 * (is16bit ? 2 : 1)) >> csx_file;
540  const UInt width_file       = width444 >>csx_file;
541  const UInt height_file      = height444>>csy_file;
542
543  std::vector<UChar> bufVec(stride_file * 2);
544  UChar *buf=&(bufVec[0]);
545
546  if (compID!=COMPONENT_Y && (fileFormat==CHROMA_400 || srcFormat==CHROMA_400))
547  {
548    if (fileFormat!=CHROMA_400)
549    {
550      const UInt value=1<<(fileBitDepth-1);
551
552      for(UInt y=0; y< height_file; y++)
553      {
554        for (UInt field = 0; field < 2; field++)
555        {
556          UChar *fieldBuffer = buf + (field * stride_file);
557
558          if (!is16bit)
559          {
560            UChar val(value);
561            for (UInt x = 0; x < width_file; x++)
562            {
563              fieldBuffer[x]=val;
564            }
565          }
566          else
567          {
568            UShort val(value);
569            for (UInt x = 0; x < width_file; x++)
570            {
571              fieldBuffer[2*x+0]= (val>>0) & 0xff;
572              fieldBuffer[2*x+1]= (val>>8) & 0xff;
573            }
574          }
575        }
576
577        fd.write(reinterpret_cast<const TChar*>(buf), (stride_file * 2));
578        if (fd.eof() || fd.fail() )
579        {
580          return false;
581        }
582      }
583    }
584  }
585  else
586  {
587    const UInt mask_y_file=(1<<csy_file)-1;
588    const UInt mask_y_src =(1<<csy_src )-1;
589    for(UInt y444=0; y444<height444; y444++)
590    {
591      if ((y444&mask_y_file)==0)
592      {
593        for (UInt field = 0; field < 2; field++)
594        {
595          UChar *fieldBuffer = buf + (field * stride_file);
596          Pel   *src         = (((field == 0) && isTff) || ((field == 1) && (!isTff))) ? top : bottom;
597
598          // write a new line
599          if (csx_file < csx_src)
600          {
601            // eg file is 444, source is 422.
602            const UInt sx=csx_src-csx_file;
603            if (!is16bit)
604            {
605              for (UInt x = 0; x < width_file; x++)
606              {
607                fieldBuffer[x] = (UChar)(src[x>>sx]);
608              }
609            }
610            else
611            {
612              for (UInt x = 0; x < width_file; x++)
613              {
614                fieldBuffer[2*] = (src[x>>sx]>>0) & 0xff;
615                fieldBuffer[2*x+1] = (src[x>>sx]>>8) & 0xff;
616              }
617            }
618          }
619          else
620          {
621            // eg file is 422, src is 444.
622            const UInt sx=csx_file-csx_src;
623            if (!is16bit)
624            {
625              for (UInt x = 0; x < width_file; x++)
626              {
627                fieldBuffer[x] = (UChar)(src[x<<sx]);
628              }
629            }
630            else
631            {
632              for (UInt x = 0; x < width_file; x++)
633              {
634                fieldBuffer[2*] = (src[x<<sx]>>0) & 0xff;
635                fieldBuffer[2*x+1] = (src[x<<sx]>>8) & 0xff;
636              }
637            }
638          }
639        }
640
641        fd.write(reinterpret_cast<const TChar*>(buf), (stride_file * 2));
642        if (fd.eof() || fd.fail() )
643        {
644          return false;
645        }
646      }
647
648      if ((y444&mask_y_src)==0)
649      {
650        top    += stride_src;
651        bottom += stride_src;
652      }
653
654    }
655  }
656  return true;
657}
658
659/**
660 * Read one Y'CbCr frame, performing any required input scaling to change
661 * from the bitdepth of the input file to the internal bit-depth.
662 *
663 * If a bit-depth reduction is required, and internalBitdepth >= 8, then
664 * the input file is assumed to be ITU-R BT.601/709 compliant, and the
665 * resulting data is clipped to the appropriate legal range, as if the
666 * file had been provided at the lower-bitdepth compliant to Rec601/709.
667 *
668 * @param pPicYuvUser      input picture YUV buffer class pointer
669 * @param pPicYuvTrueOrg
670 * @param ipcsc
671 * @param aiPad            source padding size, aiPad[0] = horizontal, aiPad[1] = vertical
672 * @param format           chroma format
673 * @return true for success, false in case of error
674 */
675Bool TVideoIOYuv::read ( TComPicYuv*  pPicYuvUser, TComPicYuv* pPicYuvTrueOrg, const InputColourSpaceConversion ipcsc, Int aiPad[2], ChromaFormat format, const Bool bClipToRec709 )
676{
677  // check end-of-file
678  if ( isEof() )
679  {
680    return false;
681  }
682  TComPicYuv *pPicYuv=pPicYuvTrueOrg;
683  if (format>=NUM_CHROMA_FORMAT)
684  {
685    format=pPicYuv->getChromaFormat();
686  }
687
688  Bool is16bit = false;
689
690  for(UInt ch=0; ch<MAX_NUM_CHANNEL_TYPE; ch++)
691  {
692    if (m_fileBitdepth[ch] > 8)
693    {
694      is16bit=true;
695    }
696  }
697
698  const UInt stride444      = pPicYuv->getStride(COMPONENT_Y);
699
700  // compute actual YUV width & height excluding padding size
701  const UInt pad_h444       = aiPad[0];
702  const UInt pad_v444       = aiPad[1];
703
704  const UInt width_full444  = pPicYuv->getWidth(COMPONENT_Y);
705  const UInt height_full444 = pPicYuv->getHeight(COMPONENT_Y);
706
707  const UInt width444       = width_full444 - pad_h444;
708  const UInt height444      = height_full444 - pad_v444;
709
710  for(UInt comp=0; comp<MAX_NUM_COMPONENT; comp++)
711  {
712    const ComponentID compID = ComponentID(comp);
713    const ChannelType chType=toChannelType(compID);
714
715    const Int desired_bitdepth = m_MSBExtendedBitDepth[chType] + m_bitdepthShift[chType];
716
717    const Bool b709Compliance=(bClipToRec709) && (m_bitdepthShift[chType] < 0 && desired_bitdepth >= 8);     /* ITU-R BT.709 compliant clipping for converting say 10b to 8b */
718    const Pel minval = b709Compliance? ((   1 << (desired_bitdepth - 8))   ) : 0;
719    const Pel maxval = b709Compliance? ((0xff << (desired_bitdepth - 8)) -1) : (1 << desired_bitdepth) - 1;
720
721    if (! readPlane(pPicYuv->getAddr(compID), m_cHandle, is16bit, stride444, width444, height444, pad_h444, pad_v444, compID, pPicYuv->getChromaFormat(), format, m_fileBitdepth[chType]))
722    {
723      return false;
724    }
725
726    if (compID < pPicYuv->getNumberValidComponents() )
727    {
728      const UInt csx=getComponentScaleX(compID, pPicYuv->getChromaFormat());
729      const UInt csy=getComponentScaleY(compID, pPicYuv->getChromaFormat());
730      scalePlane(pPicYuv->getAddr(compID), stride444>>csx, width_full444>>csx, height_full444>>csy, m_bitdepthShift[chType], minval, maxval);
731    }
732  }
733
734  ColourSpaceConvert(*pPicYuvTrueOrg, *pPicYuvUser, ipcsc, true);
735
736  return true;
737}
738
739/**
740 * Write one Y'CbCr frame. No bit-depth conversion is performed, pcPicYuv is
741 * assumed to be at TVideoIO::m_fileBitdepth depth.
742 *
743 * @param pPicYuvUser      input picture YUV buffer class pointer
744 * @param ipCSC
745 * @param confLeft         conformance window left border
746 * @param confRight        conformance window right border
747 * @param confTop          conformance window top border
748 * @param confBottom       conformance window bottom border
749 * @param format           chroma format
750 * @return true for success, false in case of error
751 */
752Bool TVideoIOYuv::write( TComPicYuv* pPicYuvUser, const InputColourSpaceConversion ipCSC, Int confLeft, Int confRight, Int confTop, Int confBottom, ChromaFormat format, const Bool bClipToRec709 )
753{
754  TComPicYuv cPicYuvCSCd;
755  if (ipCSC!=IPCOLOURSPACE_UNCHANGED)
756  {
757    cPicYuvCSCd.createWithoutCUInfo(pPicYuvUser->getWidth(COMPONENT_Y), pPicYuvUser->getHeight(COMPONENT_Y), pPicYuvUser->getChromaFormat() );
758    ColourSpaceConvert(*pPicYuvUser, cPicYuvCSCd, ipCSC, false);
759  }
760  TComPicYuv *pPicYuv=(ipCSC==IPCOLOURSPACE_UNCHANGED) ? pPicYuvUser : &cPicYuvCSCd;
761
762  // compute actual YUV frame size excluding padding size
763  Bool is16bit = false;
764  Bool nonZeroBitDepthShift=false;
765
766  for(UInt ch=0; ch<MAX_NUM_CHANNEL_TYPE; ch++)
767  {
768    if (m_fileBitdepth[ch] > 8)
769    {
770      is16bit=true;
771    }
772    if (m_bitdepthShift[ch] != 0)
773    {
774      nonZeroBitDepthShift=true;
775    }
776  }
777
778  TComPicYuv *dstPicYuv = NULL;
779  Bool retval = true;
780  if (format>=NUM_CHROMA_FORMAT)
781  {
782    format=pPicYuv->getChromaFormat();
783  }
784
785  if (nonZeroBitDepthShift)
786  {
787    dstPicYuv = new TComPicYuv;
788    dstPicYuv->createWithoutCUInfo( pPicYuv->getWidth(COMPONENT_Y), pPicYuv->getHeight(COMPONENT_Y), pPicYuv->getChromaFormat() );
789
790    for(UInt comp=0; comp<dstPicYuv->getNumberValidComponents(); comp++)
791    {
792      const ComponentID compID=ComponentID(comp);
793      const ChannelType ch=toChannelType(compID);
794      const Bool b709Compliance = bClipToRec709 && (-m_bitdepthShift[ch] < 0 && m_MSBExtendedBitDepth[ch] >= 8);     /* ITU-R BT.709 compliant clipping for converting say 10b to 8b */
795      const Pel minval = b709Compliance? ((   1 << (m_MSBExtendedBitDepth[ch] - 8))   ) : 0;
796      const Pel maxval = b709Compliance? ((0xff << (m_MSBExtendedBitDepth[ch] - 8)) -1) : (1 << m_MSBExtendedBitDepth[ch]) - 1;
797
798      copyPlane(*pPicYuv, compID, *dstPicYuv, compID);
799      scalePlane(dstPicYuv->getAddr(compID), dstPicYuv->getStride(compID), dstPicYuv->getWidth(compID), dstPicYuv->getHeight(compID), -m_bitdepthShift[ch], minval, maxval);
800    }
801  }
802  else
803  {
804    dstPicYuv = pPicYuv;
805  }
806
807  const Int  stride444 = dstPicYuv->getStride(COMPONENT_Y);
808  const UInt width444  = dstPicYuv->getWidth(COMPONENT_Y) - confLeft - confRight;
809  const UInt height444 = dstPicYuv->getHeight(COMPONENT_Y) -  confTop  - confBottom;
810
811  if ((width444 == 0) || (height444 == 0))
812  {
813    printf ("\nWarning: writing %d x %d luma sample output picture!", width444, height444);
814  }
815
816  for(UInt comp=0; retval && comp<dstPicYuv->getNumberValidComponents(); comp++)
817  {
818    const ComponentID compID = ComponentID(comp);
819    const ChannelType ch=toChannelType(compID);
820    const UInt csx = dstPicYuv->getComponentScaleX(compID);
821    const UInt csy = dstPicYuv->getComponentScaleY(compID);
822    const Int planeOffset =  (confLeft>>csx) + (confTop>>csy) * dstPicYuv->getStride(compID);
823    if (! writePlane(m_cHandle, dstPicYuv->getAddr(compID) + planeOffset, is16bit, stride444, width444, height444, compID, dstPicYuv->getChromaFormat(), format, m_fileBitdepth[ch]))
824    {
825      retval=false;
826    }
827  }
828
829  if (nonZeroBitDepthShift)
830  {
831    dstPicYuv->destroy();
832    delete dstPicYuv;
833  }
834
835  cPicYuvCSCd.destroy();
836
837  return retval;
838}
839
840Bool 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 )
841{
842
843  TComPicYuv cPicYuvTopCSCd;
844  TComPicYuv cPicYuvBottomCSCd;
845  if (ipCSC!=IPCOLOURSPACE_UNCHANGED)
846  {
847    cPicYuvTopCSCd   .createWithoutCUInfo(pPicYuvUserTop   ->getWidth(COMPONENT_Y), pPicYuvUserTop   ->getHeight(COMPONENT_Y), pPicYuvUserTop   ->getChromaFormat() );
848    cPicYuvBottomCSCd.createWithoutCUInfo(pPicYuvUserBottom->getWidth(COMPONENT_Y), pPicYuvUserBottom->getHeight(COMPONENT_Y), pPicYuvUserBottom->getChromaFormat() );
849    ColourSpaceConvert(*pPicYuvUserTop,    cPicYuvTopCSCd,    ipCSC, false);
850    ColourSpaceConvert(*pPicYuvUserBottom, cPicYuvBottomCSCd, ipCSC, false);
851  }
852  TComPicYuv *pPicYuvTop    = (ipCSC==IPCOLOURSPACE_UNCHANGED) ? pPicYuvUserTop    : &cPicYuvTopCSCd;
853  TComPicYuv *pPicYuvBottom = (ipCSC==IPCOLOURSPACE_UNCHANGED) ? pPicYuvUserBottom : &cPicYuvBottomCSCd;
854
855  Bool is16bit = false;
856  Bool nonZeroBitDepthShift=false;
857
858  for(UInt ch=0; ch<MAX_NUM_CHANNEL_TYPE; ch++)
859  {
860    if (m_fileBitdepth[ch] > 8)
861    {
862      is16bit=true;
863    }
864    if (m_bitdepthShift[ch] != 0)
865    {
866      nonZeroBitDepthShift=true;
867    }
868  }
869
870  TComPicYuv *dstPicYuvTop    = NULL;
871  TComPicYuv *dstPicYuvBottom = NULL;
872
873  for (UInt field = 0; field < 2; field++)
874  {
875    TComPicYuv *pPicYuv = (field == 0) ? pPicYuvTop : pPicYuvBottom;
876
877    if (format>=NUM_CHROMA_FORMAT)
878    {
879      format=pPicYuv->getChromaFormat();
880    }
881
882    TComPicYuv* &dstPicYuv = (field == 0) ? dstPicYuvTop : dstPicYuvBottom;
883
884    if (nonZeroBitDepthShift)
885    {
886      dstPicYuv = new TComPicYuv;
887      dstPicYuv->createWithoutCUInfo( pPicYuv->getWidth(COMPONENT_Y), pPicYuv->getHeight(COMPONENT_Y), pPicYuv->getChromaFormat() );
888
889      for(UInt comp=0; comp<dstPicYuv->getNumberValidComponents(); comp++)
890      {
891        const ComponentID compID=ComponentID(comp);
892        const ChannelType ch=toChannelType(compID);
893        const Bool b709Compliance=bClipToRec709 && (-m_bitdepthShift[ch] < 0 && m_MSBExtendedBitDepth[ch] >= 8);     /* ITU-R BT.709 compliant clipping for converting say 10b to 8b */
894        const Pel minval = b709Compliance? ((   1 << (m_MSBExtendedBitDepth[ch] - 8))   ) : 0;
895        const Pel maxval = b709Compliance? ((0xff << (m_MSBExtendedBitDepth[ch] - 8)) -1) : (1 << m_MSBExtendedBitDepth[ch]) - 1;
896
897        copyPlane(*pPicYuv, compID, *dstPicYuv, compID);
898        scalePlane(dstPicYuv->getAddr(compID), dstPicYuv->getStride(compID), dstPicYuv->getWidth(compID), dstPicYuv->getHeight(compID), -m_bitdepthShift[ch], minval, maxval);
899      }
900    }
901    else
902    {
903      dstPicYuv = pPicYuv;
904    }
905  }
906
907  Bool retval = true;
908
909  assert(dstPicYuvTop->getNumberValidComponents() == dstPicYuvBottom->getNumberValidComponents());
910  assert(dstPicYuvTop->getChromaFormat()          == dstPicYuvBottom->getChromaFormat()         );
911
912  for(UInt comp=0; retval && comp<dstPicYuvTop->getNumberValidComponents(); comp++)
913  {
914    const ComponentID compID = ComponentID(comp);
915    const ChannelType ch=toChannelType(compID);
916
917    assert(dstPicYuvTop->getWidth          (compID) == dstPicYuvBottom->getWidth          (compID));
918    assert(dstPicYuvTop->getHeight         (compID) == dstPicYuvBottom->getHeight         (compID));
919    assert(dstPicYuvTop->getComponentScaleX(compID) == dstPicYuvBottom->getComponentScaleX(compID));
920    assert(dstPicYuvTop->getComponentScaleY(compID) == dstPicYuvBottom->getComponentScaleY(compID));
921    assert(dstPicYuvTop->getStride         (compID) == dstPicYuvBottom->getStride         (compID));
922
923    const UInt width444   = dstPicYuvTop->getWidth(COMPONENT_Y)  - (confLeft + confRight);
924    const UInt height444  = dstPicYuvTop->getHeight(COMPONENT_Y) - (confTop + confBottom);
925
926    if ((width444 == 0) || (height444 == 0))
927    {
928      printf ("\nWarning: writing %d x %d luma sample output picture!", width444, height444);
929    }
930
931    const UInt csx = dstPicYuvTop->getComponentScaleX(compID);
932    const UInt csy = dstPicYuvTop->getComponentScaleY(compID);
933    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
934
935    if (! writeField(m_cHandle,
936                     (dstPicYuvTop   ->getAddr(compID) + planeOffset),
937                     (dstPicYuvBottom->getAddr(compID) + planeOffset),
938                     is16bit,
939                     dstPicYuvTop->getStride(COMPONENT_Y),
940                     width444, height444, compID, dstPicYuvTop->getChromaFormat(), format, m_fileBitdepth[ch], isTff))
941    {
942      retval=false;
943    }
944  }
945
946  if (nonZeroBitDepthShift)
947  {
948    dstPicYuvTop->destroy();
949    dstPicYuvBottom->destroy();
950    delete dstPicYuvTop;
951    delete dstPicYuvBottom;
952  }
953
954  cPicYuvTopCSCd.destroy();
955  cPicYuvBottomCSCd.destroy();
956
957  return retval;
958}
959
960static Void
961copyPlane(const TComPicYuv &src, const ComponentID srcPlane, TComPicYuv &dest, const ComponentID destPlane)
962{
963  const UInt width=src.getWidth(srcPlane);
964  const UInt height=src.getHeight(srcPlane);
965  assert(dest.getWidth(destPlane) == width);
966  assert(dest.getHeight(destPlane) == height);
967  const Pel *pSrc=src.getAddr(srcPlane);
968  Pel *pDest=dest.getAddr(destPlane);
969  const UInt strideSrc=src.getStride(srcPlane);
970  const UInt strideDest=dest.getStride(destPlane);
971  for(UInt y=0; y<height; y++, pSrc+=strideSrc, pDest+=strideDest)
972  {
973    memcpy(pDest, pSrc, width*sizeof(Pel));
974  }
975}
976
977// static member
978Void TVideoIOYuv::ColourSpaceConvert(const TComPicYuv &src, TComPicYuv &dest, const InputColourSpaceConversion conversion, Bool bIsForwards)
979{
980  const ChromaFormat  format=src.getChromaFormat();
981  const UInt          numValidComp=src.getNumberValidComponents();
982
983  switch (conversion)
984  {
985    case IPCOLOURSPACE_YCbCrtoYYY:
986      if (format!=CHROMA_444)
987      {
988        // only 444 is handled.
989        assert(format==CHROMA_444);
990        exit(1);
991      }
992
993      {
994        for(UInt comp=0; comp<numValidComp; comp++)
995        {
996          copyPlane(src, ComponentID(bIsForwards?0:comp), dest, ComponentID(comp));
997        }
998      }
999      break;
1000    case IPCOLOURSPACE_YCbCrtoYCrCb:
1001      {
1002        for(UInt comp=0; comp<numValidComp; comp++)
1003        {
1004          copyPlane(src, ComponentID(comp), dest, ComponentID((numValidComp-comp)%numValidComp));
1005        }
1006      }
1007      break;
1008
1009    case IPCOLOURSPACE_RGBtoGBR:
1010      {
1011        if (format!=CHROMA_444)
1012        {
1013          // only 444 is handled.
1014          assert(format==CHROMA_444);
1015          exit(1);
1016        }
1017
1018        // channel re-mapping
1019        for(UInt comp=0; comp<numValidComp; comp++)
1020        {
1021          const ComponentID compIDsrc=ComponentID((comp+1)%numValidComp);
1022          const ComponentID compIDdst=ComponentID(comp);
1023          copyPlane(src, bIsForwards?compIDsrc:compIDdst, dest, bIsForwards?compIDdst:compIDsrc);
1024        }
1025      }
1026      break;
1027
1028    case IPCOLOURSPACE_UNCHANGED:
1029    default:
1030      {
1031        for(UInt comp=0; comp<numValidComp; comp++)
1032        {
1033          copyPlane(src, ComponentID(comp), dest, ComponentID(comp));
1034        }
1035      }
1036      break;
1037  }
1038}
Note: See TracBrowser for help on using the repository browser.