source: 3DVCSoftware/branches/0.1-poznan-univ/source/Lib/TLibVideoIO/TVideoIOYuv.cpp @ 165

Last change on this file since 165 was 2, checked in by hhi, 13 years ago

inital import

  • Property svn:eol-style set to native
File size: 11.8 KB
Line 
1
2
3/** \file     TVideoIOYuv.cpp
4    \brief    YUV file I/O class
5*/
6
7#include <cstdlib>
8#include <fcntl.h>
9#include <assert.h>
10#include <sys/stat.h>
11#include <fstream>
12#include <iostream>
13
14#include "TVideoIOYuv.h"
15
16using namespace std;
17
18/**
19 * Perform division with rounding of all pixels in #img by
20 * \f$ 2^{#shiftbits} \f$. All pixels are clipped to [minval, maxval]
21 *
22 * @param stride  distance between vertically adjacent pixels of #img.
23 * @param width   width of active area in #img.
24 * @param height  height of active area in #img.
25 * @param minval  minimum clipping value
26 * @param maxval  maximum clipping value
27 */
28static void invScalePlane(Pel* img, unsigned int stride, unsigned int width, unsigned int height,
29                       unsigned int shiftbits, Pel minval, Pel maxval)
30{
31  Pel offset = 1 << (shiftbits-1);
32  for (unsigned int y = 0; y < height; y++)
33  {
34    for (unsigned int x = 0; x < width; x++)
35    {
36      Pel val = (img[x] + offset) >> shiftbits;
37      img[x] = Clip3(minval, maxval, val);
38    }
39    img += stride;
40  }
41}
42
43/**
44 * Multiply all pixels in #img by \f$ 2^{#shiftbits} \f$.
45 *
46 * @param stride  distance between vertically adjacent pixels of #img.
47 * @param width   width of active area in #img.
48 * @param height  height of active area in #img.
49 */
50static void scalePlane(Pel* img, unsigned int stride, unsigned int width, unsigned int height,
51                       unsigned int shiftbits)
52{
53  for (unsigned int y = 0; y < height; y++)
54  {
55    for (unsigned int x = 0; x < width; x++)
56    {
57      img[x] <<= shiftbits;
58    }
59    img += stride;
60  }
61}
62
63/**
64 * Scale all pixels in #img depending upon sign of #shiftbits by a factor of
65 * \f$ 2^{#shiftbits} \f$.
66 *
67 * @param stride  distance between vertically adjacent pixels of #img.
68 * @param width   width of active area in #img.
69 * @param height  height of active area in #img.
70 * @param shiftbits if zero, no operation performed
71 *                  if > 0, multiply by \f$ 2^{#shiftbits} \f$, see scalePlane()
72 *                  if < 0, divide and round by \f$ 2^{#shiftbits} \f$ and clip,
73 *                          see invScalePlane().
74 * @param minval  minimum clipping value when dividing.
75 * @param maxval  maximum clipping value when dividing.
76 */
77static void scalePlane(Pel* img, unsigned int stride, unsigned int width, unsigned int height,
78                       int shiftbits, Pel minval, Pel maxval)
79{
80  if (shiftbits == 0)
81  {
82    return;
83  }
84
85  if (shiftbits > 0)
86  {
87    scalePlane(img, stride, width, height, shiftbits);
88  }
89  else
90  {
91    invScalePlane(img, stride, width, height, -shiftbits, minval, maxval);
92  }
93}
94
95
96// ====================================================================================================================
97// Public member functions
98// ====================================================================================================================
99
100/**
101 * Open file for reading/writing Y'CbCr frames.
102 *
103 * Frames read/written have bitdepth #fileBitDepth, and are automatically
104 * formatted as 8 or 16 bit word values (see TVideoIOYuv::write()).
105 *
106 * Image data read or written is converted to/from #internalBitDepth
107 * (See scalePlane(), TVideoIOYuv::read() and TVideoIOYuv::write() for
108 * further details).
109 *
110 * \param pchFile          file name string
111 * \param bWriteMode       file open mode: true=read, false=write
112 * \param fileBitDepth     bit-depth of input/output file data.
113 * \param internalBitDepth bit-depth to scale image data to/from when reading/writing.
114 */
115Void TVideoIOYuv::open( char* pchFile, Bool bWriteMode, unsigned int fileBitDepth, unsigned int internalBitDepth )
116{
117  m_bitdepthShift = internalBitDepth - fileBitDepth;
118  m_fileBitdepth = fileBitDepth;
119
120  if ( bWriteMode )
121  {
122    m_cHandle.open( pchFile, ios::binary | ios::out );
123   
124    if( m_cHandle.fail() )
125    {
126      printf("\nfailed to write reconstructed YUV file\n");
127      exit(0);
128    }
129  }
130  else
131  {
132    m_cHandle.open( pchFile, ios::binary | ios::in );
133   
134    if( m_cHandle.fail() )
135    {
136      printf("\nfailed to open Input YUV file\n");
137      exit(0);
138    }
139  }
140 
141  return;
142}
143
144Void TVideoIOYuv::close()
145{
146  m_cHandle.close();
147}
148
149Bool TVideoIOYuv::isEof()
150{
151  return m_cHandle.eof();
152}
153
154/**
155 * Skip @numFrames in input.
156 *
157 * This function correctly handles cases where the input file is not
158 * seekable, by consuming bytes.
159 */
160void TVideoIOYuv::skipFrames(unsigned int numFrames, unsigned int width, unsigned int height)
161{
162  if (!numFrames)
163    return;
164
165  const unsigned int wordsize = m_fileBitdepth > 8 ? 2 : 1;
166  const streamoff framesize = wordsize * width * height * 3 / 2;
167  const streamoff offset = framesize * numFrames;
168
169  /* attempt to seek */
170  if (!!m_cHandle.seekg(offset, ios::cur))
171    return; /* success */
172  m_cHandle.clear();
173
174  /* fall back to consuming the input */
175  char buf[512];
176  const unsigned offset_mod_bufsize = offset % sizeof(buf);
177  for (streamoff i = 0; i < offset - offset_mod_bufsize; i += sizeof(buf))
178  {
179    m_cHandle.read(buf, sizeof(buf));
180  }
181  m_cHandle.read(buf, offset_mod_bufsize);
182}
183
184/**
185 * Read \f$ #width * #height \f$ pixels from #fd into #dst, optionally
186 * padding the left and right edges by edge-extension.  Input may be
187 * either 8bit or 16bit little-endian lsb-aligned words.
188 *
189 * @param dst     destination image
190 * @param is16bit true if input file carries > 8bit data, false otherwise.
191 * @param stride  distance between vertically adjacent pixels of #dst.
192 * @param width   width of active area in #dst.
193 * @param height  height of active area in #dst.
194 * @param pad_x   length of horizontal padding.
195 * @param pad_y   length of vertical padding.
196 */
197static void readPlane(Pel* dst, istream& fd, bool is16bit,
198                      unsigned int stride,
199                      unsigned int width, unsigned int height,
200                      unsigned int pad_x, unsigned int pad_y)
201{
202  int read_len = width * (is16bit ? 2 : 1);
203  unsigned char *buf = new unsigned char[read_len];
204  for (int y = 0; y < height; y++)
205  {
206    fd.read(reinterpret_cast<char*>(buf), read_len);
207    if (!is16bit) {
208      for (int x = 0; x < width; x++) {
209        dst[x] = buf[x];
210      }
211    }
212    else {
213      for (int x = 0; x < width; x++) {
214        dst[x] = (buf[2*x+1] << 8) | buf[2*x];
215      }
216    }
217
218    for (int x = width; x < width + pad_x; x++)
219    {
220      dst[x] = dst[width - 1];
221    }
222    dst += stride;
223  }
224  for (int y = height; y < height + pad_y; y++)
225  {
226    for (int x = width; x < width + pad_x; x++)
227    {
228      dst[x] = dst[x - stride];
229    }
230    dst += stride;
231  }
232  delete[] buf;
233}
234
235/**
236 * Write \f$ #width * #height \f$ pixels info #fd from #src.
237 *
238 * @param src     source image
239 * @param is16bit true if input file carries > 8bit data, false otherwise.
240 * @param stride  distance between vertically adjacent pixels of #src.
241 * @param width   width of active area in #src.
242 * @param height  height of active area in #src.
243 */
244static void writePlane(ostream& fd, Pel* src, bool is16bit,
245                       unsigned int stride,
246                       unsigned int width, unsigned int height)
247{
248  int write_len = width * (is16bit ? 2 : 1);
249  unsigned char *buf = new unsigned char[write_len];
250  for (int y = 0; y < height; y++)
251  {
252    if (!is16bit) 
253    {
254      for (int x = 0; x < width; x++) 
255      {
256        buf[x] = (unsigned char) src[x];
257      }
258    }
259    else 
260    {
261      for (int x = 0; x < width; x++) 
262      {
263        buf[2*x] = src[x] & 0xff;
264        buf[2*x+1] = (src[x] >> 8) & 0xff;
265      }
266    }
267
268    fd.write(reinterpret_cast<char*>(buf), write_len);
269    src += stride;
270  }
271  delete[] buf;
272}
273
274/**
275 * Read one Y'CbCr frame, performing any required input scaling to change
276 * from the bitdepth of the input file to the internal bit-depth.
277 *
278 * If a bit-depth reduction is requried, and internalBitdepth >= 8, then
279 * the input file is assumed to be ITU-R BT.601/709 compliant, and the
280 * resulting data is clipped to the appropriate legal range, as if the
281 * file had been provided at the lower-bitdepth compliant to Rec601/709.
282 *
283 \param rpcPicYuv      input picture YUV buffer class pointer
284 \param aiPad[2]       source padding size, aiPad[0] = horizontal, aiPad[1] = vertical
285 */
286Void TVideoIOYuv::read ( TComPicYuv*&  rpcPicYuv, Int aiPad[2], Bool bRewind /* = false */ )
287{
288  // check end-of-file
289  if ( isEof() ) return;
290 
291  Int   iStride = rpcPicYuv->getStride();
292 
293  // compute actual YUV width & height excluding padding size
294  unsigned int pad_h = aiPad[0];
295  unsigned int pad_v = aiPad[1];
296  unsigned int width_full = rpcPicYuv->getWidth();
297  unsigned int height_full = rpcPicYuv->getHeight();
298  unsigned int width  = width_full - pad_h;
299  unsigned int height = height_full - pad_v;
300  bool is16bit = m_fileBitdepth > 8;
301
302  int desired_bitdepth = m_fileBitdepth + m_bitdepthShift;
303  Pel minval = 0;
304  Pel maxval = (1 << desired_bitdepth) - 1;
305#if CLIP_TO_709_RANGE
306  if (m_bitdepthShift < 0 && desired_bitdepth >= 8)
307  {
308    /* ITU-R BT.709 compliant clipping for converting say 10b to 8b */
309    minval = 1 << (desired_bitdepth - 8);
310    maxval = (0xff << (desired_bitdepth - 8)) -1;
311  }
312#endif
313 
314  readPlane(rpcPicYuv->getLumaAddr(), m_cHandle, is16bit, iStride, width, height, pad_h, pad_v);
315  scalePlane(rpcPicYuv->getLumaAddr(), iStride, width_full, height_full, m_bitdepthShift, minval, maxval);
316
317  iStride >>= 1;
318  width_full >>= 1;
319  height_full >>= 1;
320  width >>= 1;
321  height >>= 1;
322  pad_h >>= 1;
323  pad_v >>= 1;
324
325  readPlane(rpcPicYuv->getCbAddr(), m_cHandle, is16bit, iStride, width, height, pad_h, pad_v);
326  scalePlane(rpcPicYuv->getCbAddr(), iStride, width_full, height_full, m_bitdepthShift, minval, maxval);
327
328  readPlane(rpcPicYuv->getCrAddr(), m_cHandle, is16bit, iStride, width, height, pad_h, pad_v);
329  scalePlane(rpcPicYuv->getCrAddr(), iStride, width_full, height_full, m_bitdepthShift, minval, maxval);
330
331  if( bRewind )
332  {
333    Int iFrameSize = ( is16bit ? 2 : 1 ) * 6 * width * height;
334    m_cHandle.seekg( -iFrameSize, std::ios_base::cur );
335  }
336}
337
338/**
339 * Write one Y'CbCr frame. No bit-depth conversion is performed, #pcPicYuv is
340 * assumed to be at TVideoIO::m_fileBitdepth depth.
341 *
342 \param pcPicYuv     input picture YUV buffer class pointer
343 \param aiPad[2]     source padding size, aiPad[0] = horizontal, aiPad[1] = vertical
344 */
345Void TVideoIOYuv::write( TComPicYuv* pcPicYuv, Int aiPad[2] )
346{
347  // compute actual YUV frame size excluding padding size
348  Int   iStride = pcPicYuv->getStride();
349  unsigned int width  = pcPicYuv->getWidth() - aiPad[0];
350  unsigned int height = pcPicYuv->getHeight() - aiPad[1];
351  bool is16bit = m_fileBitdepth > 8;
352  TComPicYuv *dstPicYuv = NULL;
353
354  if (m_bitdepthShift != 0)
355  {
356    dstPicYuv = new TComPicYuv;
357    dstPicYuv->create( pcPicYuv->getWidth(), pcPicYuv->getHeight(), 1, 1, 0 );
358    pcPicYuv->copyToPic(dstPicYuv);
359
360    Pel minval = 0;
361    Pel maxval = (1 << m_fileBitdepth) - 1;
362#if CLIP_TO_709_RANGE
363    if (-m_bitdepthShift < 0 && m_fileBitdepth >= 8)
364    {
365      /* ITU-R BT.709 compliant clipping for converting say 10b to 8b */
366      minval = 1 << (m_fileBitdepth - 8);
367      maxval = (0xff << (m_fileBitdepth - 8)) -1;
368    }
369#endif
370    scalePlane(dstPicYuv->getLumaAddr(), dstPicYuv->getStride(), dstPicYuv->getWidth(), dstPicYuv->getHeight(), -m_bitdepthShift, minval, maxval);
371    scalePlane(dstPicYuv->getCbAddr(), dstPicYuv->getCStride(), dstPicYuv->getWidth()>>1, dstPicYuv->getHeight()>>1, -m_bitdepthShift, minval, maxval);
372    scalePlane(dstPicYuv->getCrAddr(), dstPicYuv->getCStride(), dstPicYuv->getWidth()>>1, dstPicYuv->getHeight()>>1, -m_bitdepthShift, minval, maxval);
373  }
374  else
375  {
376    dstPicYuv = pcPicYuv;
377  }
378 
379  writePlane(m_cHandle, dstPicYuv->getLumaAddr(), is16bit, iStride, width, height);
380
381  width >>= 1;
382  height >>= 1;
383  iStride >>= 1;
384  writePlane(m_cHandle, dstPicYuv->getCbAddr(), is16bit, iStride, width, height);
385  writePlane(m_cHandle, dstPicYuv->getCrAddr(), is16bit, iStride, width, height);
386 
387  if (m_bitdepthShift != 0)
388  {
389    dstPicYuv->destroy();
390    delete dstPicYuv;
391  } 
392}
393
Note: See TracBrowser for help on using the repository browser.