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

Last change on this file since 1037 was 1029, checked in by seregin, 10 years ago

merge with SHM-upgrade branch

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