source: SHVCSoftware/branches/SHM-dev/source/Lib/TLibCommon/TComBitStream.cpp @ 1510

Last change on this file since 1510 was 1442, checked in by seregin, 9 years ago

port rev 4590

  • Property svn:eol-style set to native
File size: 12.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-2015, 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     TComBitStream.cpp
35    \brief    class for handling bitstream
36*/
37
38#include <stdint.h>
39#include <vector>
40#include "TComBitStream.h"
41#include <string.h>
42#include <memory.h>
43
44using namespace std;
45
46//! \ingroup TLibCommon
47//! \{
48
49// ====================================================================================================================
50// Constructor / destructor / create / destroy
51// ====================================================================================================================
52
53TComOutputBitstream::TComOutputBitstream()
54{
55  clear();
56}
57
58TComOutputBitstream::~TComOutputBitstream()
59{
60}
61
62
63TComInputBitstream::TComInputBitstream()
64: m_fifo()
65, m_emulationPreventionByteLocation()
66, m_fifo_idx(0)
67, m_num_held_bits(0)
68, m_held_bits(0)
69, m_numBitsRead(0)
70{ }
71
72TComInputBitstream::TComInputBitstream(const TComInputBitstream &src)
73: m_fifo(src.m_fifo)
74, m_emulationPreventionByteLocation(src.m_emulationPreventionByteLocation)
75, m_fifo_idx(src.m_fifo_idx)
76, m_num_held_bits(src.m_num_held_bits)
77, m_held_bits(src.m_held_bits)
78, m_numBitsRead(src.m_numBitsRead)
79{ }
80
81// ====================================================================================================================
82// Public member functions
83// ====================================================================================================================
84
85Void TComInputBitstream::resetToStart()
86{
87  m_fifo_idx=0;
88  m_num_held_bits=0;
89  m_held_bits=0;
90  m_numBitsRead=0;
91}
92
93UChar* TComOutputBitstream::getByteStream() const
94{
95  return (UChar*) &m_fifo.front();
96}
97
98UInt TComOutputBitstream::getByteStreamLength()
99{
100  return UInt(m_fifo.size());
101}
102
103Void TComOutputBitstream::clear()
104{
105  m_fifo.clear();
106  m_held_bits = 0;
107  m_num_held_bits = 0;
108}
109
110Void TComOutputBitstream::write   ( UInt uiBits, UInt uiNumberOfBits )
111{
112  assert( uiNumberOfBits <= 32 );
113  assert( uiNumberOfBits == 32 || (uiBits & (~0 << uiNumberOfBits)) == 0 );
114
115  /* any modulo 8 remainder of num_total_bits cannot be written this time,
116   * and will be held until next time. */
117  UInt num_total_bits = uiNumberOfBits + m_num_held_bits;
118  UInt next_num_held_bits = num_total_bits % 8;
119
120  /* form a byte aligned word (write_bits), by concatenating any held bits
121   * with the new bits, discarding the bits that will form the next_held_bits.
122   * eg: H = held bits, V = n new bits        /---- next_held_bits
123   * len(H)=7, len(V)=1: ... ---- HHHH HHHV . 0000 0000, next_num_held_bits=0
124   * len(H)=7, len(V)=2: ... ---- HHHH HHHV . V000 0000, next_num_held_bits=1
125   * if total_bits < 8, the value of v_ is not used */
126  UChar next_held_bits = uiBits << (8 - next_num_held_bits);
127
128  if (!(num_total_bits >> 3))
129  {
130    /* insufficient bits accumulated to write out, append new_held_bits to
131     * current held_bits */
132    /* NB, this requires that v only contains 0 in bit positions {31..n} */
133    m_held_bits |= next_held_bits;
134    m_num_held_bits = next_num_held_bits;
135    return;
136  }
137
138  /* topword serves to justify held_bits to align with the msb of uiBits */
139  UInt topword = (uiNumberOfBits - next_num_held_bits) & ~((1 << 3) -1);
140  UInt write_bits = (m_held_bits << topword) | (uiBits >> next_num_held_bits);
141
142  switch (num_total_bits >> 3)
143  {
144  case 4: m_fifo.push_back(write_bits >> 24);
145  case 3: m_fifo.push_back(write_bits >> 16);
146  case 2: m_fifo.push_back(write_bits >> 8);
147  case 1: m_fifo.push_back(write_bits);
148  }
149
150  m_held_bits = next_held_bits;
151  m_num_held_bits = next_num_held_bits;
152}
153
154Void TComOutputBitstream::writeAlignOne()
155{
156  UInt num_bits = getNumBitsUntilByteAligned();
157  write((1 << num_bits) - 1, num_bits);
158  return;
159}
160
161Void TComOutputBitstream::writeAlignZero()
162{
163  if (0 == m_num_held_bits)
164  {
165    return;
166  }
167  m_fifo.push_back(m_held_bits);
168  m_held_bits = 0;
169  m_num_held_bits = 0;
170}
171
172/**
173 - add substream to the end of the current bitstream
174 .
175 \param  pcSubstream  substream to be added
176 */
177Void   TComOutputBitstream::addSubstream( TComOutputBitstream* pcSubstream )
178{
179  UInt uiNumBits = pcSubstream->getNumberOfWrittenBits();
180
181  const vector<uint8_t>& rbsp = pcSubstream->getFIFO();
182  for (vector<uint8_t>::const_iterator it = rbsp.begin(); it != rbsp.end();)
183  {
184    write(*it++, 8);
185  }
186  if (uiNumBits&0x7)
187  {
188    write(pcSubstream->getHeldBits()>>(8-(uiNumBits&0x7)), uiNumBits&0x7);
189  }
190}
191
192Void TComOutputBitstream::writeByteAlignment()
193{
194  write( 1, 1);
195  writeAlignZero();
196}
197
198Int TComOutputBitstream::countStartCodeEmulations()
199{
200  UInt cnt = 0;
201  vector<uint8_t>& rbsp   = getFIFO();
202  for (vector<uint8_t>::iterator it = rbsp.begin(); it != rbsp.end();)
203  {
204    vector<uint8_t>::iterator found = it;
205    do
206    {
207      // find the next emulated 00 00 {00,01,02,03}
208      // NB, end()-1, prevents finding a trailing two byte sequence
209      found = search_n(found, rbsp.end()-1, 2, 0);
210      found++;
211      // if not found, found == end, otherwise found = second zero byte
212      if (found == rbsp.end())
213      {
214        break;
215      }
216      if (*(++found) <= 3)
217      {
218        break;
219      }
220    } while (true);
221    it = found;
222    if (found != rbsp.end())
223    {
224      cnt++;
225    }
226  }
227  return cnt;
228}
229
230/**
231 * read uiNumberOfBits from bitstream without updating the bitstream
232 * state, storing the result in ruiBits.
233 *
234 * If reading uiNumberOfBits would overrun the bitstream buffer,
235 * the bitstream is effectively padded with sufficient zero-bits to
236 * avoid the overrun.
237 */
238Void TComInputBitstream::pseudoRead ( UInt uiNumberOfBits, UInt& ruiBits )
239{
240  UInt saved_num_held_bits = m_num_held_bits;
241  UChar saved_held_bits = m_held_bits;
242  UInt saved_fifo_idx = m_fifo_idx;
243#if P0138_USE_ALT_CPB_PARAMS_FLAG
244  UInt saved_numBitsRead = m_numBitsRead;
245#endif
246
247  UInt num_bits_to_read = min(uiNumberOfBits, getNumBitsLeft());
248  read(num_bits_to_read, ruiBits);
249  ruiBits <<= (uiNumberOfBits - num_bits_to_read);
250
251  m_fifo_idx = saved_fifo_idx;
252  m_held_bits = saved_held_bits;
253  m_num_held_bits = saved_num_held_bits;
254#if P0138_USE_ALT_CPB_PARAMS_FLAG
255  m_numBitsRead = saved_numBitsRead;
256#endif
257}
258
259
260Void TComInputBitstream::read (UInt uiNumberOfBits, UInt& ruiBits)
261{
262  assert( uiNumberOfBits <= 32 );
263
264  m_numBitsRead += uiNumberOfBits;
265
266  /* NB, bits are extracted from the MSB of each byte. */
267  UInt retval = 0;
268  if (uiNumberOfBits <= m_num_held_bits)
269  {
270    /* n=1, len(H)=7:   -VHH HHHH, shift_down=6, mask=0xfe
271     * n=3, len(H)=7:   -VVV HHHH, shift_down=4, mask=0xf8
272     */
273    retval = m_held_bits >> (m_num_held_bits - uiNumberOfBits);
274    retval &= ~(0xff << uiNumberOfBits);
275    m_num_held_bits -= uiNumberOfBits;
276    ruiBits = retval;
277    return;
278  }
279
280  /* all num_held_bits will go into retval
281   *   => need to mask leftover bits from previous extractions
282   *   => align retval with top of extracted word */
283  /* n=5, len(H)=3: ---- -VVV, mask=0x07, shift_up=5-3=2,
284   * n=9, len(H)=3: ---- -VVV, mask=0x07, shift_up=9-3=6 */
285  uiNumberOfBits -= m_num_held_bits;
286  retval = m_held_bits & ~(0xff << m_num_held_bits);
287  retval <<= uiNumberOfBits;
288
289  /* number of whole bytes that need to be loaded to form retval */
290  /* n=32, len(H)=0, load 4bytes, shift_down=0
291   * n=32, len(H)=1, load 4bytes, shift_down=1
292   * n=31, len(H)=1, load 4bytes, shift_down=1+1
293   * n=8,  len(H)=0, load 1byte,  shift_down=0
294   * n=8,  len(H)=3, load 1byte,  shift_down=3
295   * n=5,  len(H)=1, load 1byte,  shift_down=1+3
296   */
297  UInt aligned_word = 0;
298  UInt num_bytes_to_load = (uiNumberOfBits - 1) >> 3;
299  assert(m_fifo_idx + num_bytes_to_load < m_fifo.size());
300
301  switch (num_bytes_to_load)
302  {
303  case 3: aligned_word  = m_fifo[m_fifo_idx++] << 24;
304  case 2: aligned_word |= m_fifo[m_fifo_idx++] << 16;
305  case 1: aligned_word |= m_fifo[m_fifo_idx++] <<  8;
306  case 0: aligned_word |= m_fifo[m_fifo_idx++];
307  }
308
309  /* resolve remainder bits */
310  UInt next_num_held_bits = (32 - uiNumberOfBits) % 8;
311
312  /* copy required part of aligned_word into retval */
313  retval |= aligned_word >> next_num_held_bits;
314
315  /* store held bits */
316  m_num_held_bits = next_num_held_bits;
317  m_held_bits = aligned_word;
318
319  ruiBits = retval;
320}
321
322/**
323 * insert the contents of the bytealigned (and flushed) bitstream src
324 * into this at byte position pos.
325 */
326Void TComOutputBitstream::insertAt(const TComOutputBitstream& src, UInt pos)
327{
328  UInt src_bits = src.getNumberOfWrittenBits();
329  assert(0 == src_bits % 8);
330
331  vector<uint8_t>::iterator at = m_fifo.begin() + pos;
332  m_fifo.insert(at, src.m_fifo.begin(), src.m_fifo.end());
333}
334
335UInt TComInputBitstream::readOutTrailingBits ()
336{
337  UInt count=0;
338  UInt uiBits = 0;
339
340  while ( ( getNumBitsLeft() > 0 ) && (getNumBitsUntilByteAligned()!=0) )
341  {
342    count++;
343    read ( 1, uiBits );
344  }
345  return count;
346}
347//
348//TComOutputBitstream& TComOutputBitstream::operator= (const TComOutputBitstream& src)
349//{
350//  vector<uint8_t>::iterator at = m_fifo.begin();
351//  m_fifo.insert(at, src.m_fifo.begin(), src.m_fifo.end());
352//
353//  m_num_held_bits             = src.m_num_held_bits;
354//  m_held_bits                 = src.m_held_bits;
355//
356//  return *this;
357//}
358
359/**
360 Extract substream from the current bitstream.
361
362 \param  uiNumBits    number of bits to transfer
363 */
364TComInputBitstream *TComInputBitstream::extractSubstream( UInt uiNumBits )
365{
366  UInt uiNumBytes = uiNumBits/8;
367  TComInputBitstream *pResult = new TComInputBitstream;
368
369  std::vector<uint8_t> &buf = pResult->getFifo();
370  buf.reserve((uiNumBits+7)>>3);
371
372  if (m_num_held_bits == 0)
373  {
374    std::size_t currentOutputBufferSize=buf.size();
375    const UInt uiNumBytesToReadFromFifo = std::min<UInt>(uiNumBytes, (UInt)m_fifo.size() - m_fifo_idx);
376    buf.resize(currentOutputBufferSize+uiNumBytes);
377    memcpy(&(buf[currentOutputBufferSize]), &(m_fifo[m_fifo_idx]), uiNumBytesToReadFromFifo); m_fifo_idx+=uiNumBytesToReadFromFifo;
378    if (uiNumBytesToReadFromFifo != uiNumBytes)
379    {
380      memset(&(buf[currentOutputBufferSize+uiNumBytesToReadFromFifo]), 0, uiNumBytes - uiNumBytesToReadFromFifo);
381    }
382  }
383  else
384  {
385    for (UInt ui = 0; ui < uiNumBytes; ui++)
386    {
387      UInt uiByte;
388      read(8, uiByte);
389      buf.push_back(uiByte);
390    }
391  }
392  if (uiNumBits&0x7)
393  {
394    UInt uiByte = 0;
395    read(uiNumBits&0x7, uiByte);
396    uiByte <<= 8-(uiNumBits&0x7);
397    buf.push_back(uiByte);
398  }
399  return pResult;
400}
401
402UInt TComInputBitstream::readByteAlignment()
403{
404  UInt code = 0;
405  read( 1, code );
406  assert(code == 1);
407
408  UInt numBits = getNumBitsUntilByteAligned();
409  if(numBits)
410  {
411    assert(numBits <= getNumBitsLeft());
412    read( numBits, code );
413    assert(code == 0);
414  }
415  return numBits+1;
416}
417
418//! \}
Note: See TracBrowser for help on using the repository browser.