bits.cpp
来自「Motion JPEG编解码器源代码」· C++ 代码 · 共 503 行
CPP
503 行
/** @file bits.cc, bit-level output *//* Copyright (C) 2001, Andrew Stevens <andrew.stevens@philips.com> * * * Disclaimer of Warranty * * These software programs are available to the user without any license fee or * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims * any and all warranties, whether express, implied, or statuary, including any * implied warranties or merchantability or of fitness for a particular * purpose. In no event shall the copyright-holder be liable for any * incidental, punitive, or consequential damages of any kind whatsoever * arising from the use of these programs. * * This disclaimer of warranty extends to the user of these programs and user's * customers, employees, agents, transferees, successors, and assigns. * * The MPEG Software Simulation Group does not represent or warrant that the * programs furnished hereunder are free of infringement of any third-party * patents. * * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, * are subject to royalty fees to patent holders. Many of these patents are * general enough such that they are unavoidable regardless of implementation * design. * */#include <config.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <assert.h>#include "mjpeg_logging.h"#include "bits.hpp"const unsigned int BitStreamBuffering::BUFFER_SIZE = 64 * 1024;const unsigned int BitStreamBuffering::BUFFER_CEILING = 32 * 1024 * 1024;BitStreamBuffering::BitStreamBuffering() : bfr(0), bfr_size(0), buffered(0) {}/***** * * Pseudo-destructor. Frees the internal buffer and marks buffer as * empty. * *****/void BitStreamBuffering::Release(){ if( bfr != 0) delete bfr; bfr = 0; bfr_size = 0; buffered = 0;}/***** * * Empty the buffer. * *****/void BitStreamBuffering::Empty(){ buffered = 0;}/** sets the internal buffer size. @param new_buf_size requests new internal buffer size */void BitStreamBuffering::SetBufSize( unsigned int new_buf_size){ // // If size has changed and we won't lose buffered data // we adjust the buffer size, otherwise we ignore the request // if( new_buf_size > BUFFER_CEILING ) { mjpeg_error_exit1("INTERNAL ERROR: additional data required but " " input buffer size would exceed ceiling"); } if( new_buf_size > buffered && bfr_size != new_buf_size ) { uint8_t *new_buf = new uint8_t[new_buf_size]; memcpy( new_buf, bfr, static_cast<size_t>(buffered) ); if( bfr != 0 ) delete [] bfr; bfr_size = new_buf_size; bfr = new_buf; }}/**************************** * * Return the pointer to where (after, if necessary extending the * buffer) up to to_append bytes may be appended to the buffered bytes * ****************************/uint8_t *BitStreamBuffering::StartAppendPoint( unsigned int to_append ){ unsigned int resize_size = bfr_size; assert( resize_size != 0 ); while( resize_size - buffered < to_append ) { resize_size *= 2; } if( resize_size != bfr_size ) SetBufSize( resize_size ); return bfr+buffered;}/** Refills an IBitStream's input buffer based on the internal variables buffered and bfr_size. Strategy: we read 1/4 of a buffer, always. */bool IBitStream::ReadIntoBuffer(unsigned int to_read){ size_t i; unsigned int read_pow2 = BUFFER_SIZE/4; while( read_pow2 < to_read ) read_pow2 <<= 1; i = ReadStreamBytes( StartAppendPoint(read_pow2), static_cast<size_t>(read_pow2) ); //i = fread(StartAppendPoint(read_pow2), sizeof(uint8_t), // static_cast<size_t>(read_pow2), fileh); Appended(static_cast<unsigned int>(i)); if ( i == 0 ) { eobs = true; return false; } return true;}#define masks(idx) (1<<(idx))/*read 1 bit from the bit stream @returns the read bit, 0 on EOF */uint32_t IBitStream::Get1Bit(){ unsigned int bit; if (eobs) return 0; bit = (bfr[byteidx] & masks(bitidx - 1)) >> (bitidx - 1); bitreadpos++; bitidx--; if (!bitidx) { bitidx = 8; byteidx++; if (byteidx == buffered) { ReadIntoBuffer(); } } return bit;}/*read N bits from the bit stream @returns the read bits, 0 on EOF */uint32_t IBitStream::GetBits(int N){ uint32_t val = 0; int i = N; unsigned int j; // Optimize: we are on byte boundary and want to read multiple of bytes! if ((bitidx == 8) && ((N & 7) == 0)) { i = N >> 3; while (i > 0) { if (eobs) return 0; val = (val << 8) | bfr[byteidx]; byteidx++; bitreadpos += 8; if (byteidx == buffered) { ReadIntoBuffer(); } i--; } } else { while (i > 0) { if (eobs) return 0; j = (bfr[byteidx] & masks(bitidx - 1)) >> (bitidx - 1); bitreadpos++; bitidx--; if (!bitidx) { bitidx = 8; byteidx++; if (byteidx == buffered) { ReadIntoBuffer(); } } val = (val << 1) | j; i--; } } return val;}/** This function seeks for a byte aligned sync word (max 32 bits) in the bit stream and places the bit stream pointer right after the sync. This function returns 1 if the sync was found otherwise it returns 0@param sync the sync word to search for@param N the number of bits to retrieve@param lim number of bytes to search through@returns false on error */bool IBitStream::SeekSync(uint32_t sync, int N, int lim){ uint32_t val, val1; uint32_t maxi = ((1U<<N)-1); /* pow(2.0, (double)N) - 1 */; if( maxi == 0 ) { maxi = 0xffffffff; } while (bitidx != 8) { Get1Bit(); } val = GetBits(N); if( eobs ) return false; while ((val & maxi) != sync && --lim) { val <<= 8; val1 = GetBits( 8 ); val |= val1; if( eobs ) return false; } return (!!lim);}/**************** * * Move the bit read position forward a specified number of bytes * buffering bytes skipped over that are not already buffered * ***************/void IBitStream::SeekFwdBits( unsigned int bytes_to_seek_fwd){ assert(bitidx == 8); unsigned int req_byteidx = byteidx + bytes_to_seek_fwd; while( req_byteidx >= buffered && !eobs) { ReadIntoBuffer( req_byteidx - (buffered-1) ); } eobs = ( req_byteidx >= buffered ); if( eobs ) bitreadpos += (buffered - byteidx)*8; else bitreadpos += bytes_to_seek_fwd*8; byteidx = req_byteidx;}/** Flushes all read input up-to *but not including* byte flush_upto. @param flush_to the number of bits to flush*/void IBitStream::Flush(bitcount_t flush_upto ){ if( flush_upto > bfr_start+buffered ) mjpeg_error_exit1("INTERNAL ERROR: attempt to flush input beyond buffered amount" ); if( flush_upto < bfr_start ) mjpeg_error_exit1("INTERNAL ERROR: attempt to flush input stream before first buffered byte %lld last is %lld", flush_upto, bfr_start ); unsigned int bytes_to_flush = static_cast<unsigned int>(flush_upto - bfr_start); // // Don't bother actually flushing until a good fraction of a buffer // will be cleared. // if( bytes_to_flush < bfr_size/2 ) return; buffered -= bytes_to_flush; bfr_start = flush_upto; byteidx -= bytes_to_flush; memmove( bfr, bfr+bytes_to_flush, static_cast<size_t>(buffered));}/** Undo scanning / reading N.b buffer *must not* be flushed between prepareundo and undochanges. @param undo handle to store the undo information*/void IBitStream::PrepareUndo( IBitStreamUndo &undo){ undo = *(static_cast<IBitStreamUndo*>(this));}/**Undoes changes committed to an IBitStream. @param undo handle to retrieve the undo information */void IBitStream::UndoChanges( IBitStreamUndo &undo){ *(static_cast<IBitStreamUndo*>(this)) = undo;}/** Read a number bytes over an IBitStream, using the buffer. @param dst buffer to read to @param length the number of bytes to read */unsigned int IBitStream::GetBytes(uint8_t *dst, unsigned int length){ unsigned int to_read = length; if( bytereadpos < bfr_start) mjpeg_error_exit1("INTERNAL ERROR: access to input stream buffer @ %lld: before first buffered byte (%lld)", bytereadpos, bfr_start ); if( bytereadpos+length > bfr_start+buffered ) { if( !EndOfStream() ) { mjpeg_error("INTERNAL ERROR: access to input stream buffer beyond last buffered byte @POS=%lld END=%d REQ=%lld + %d bytes", bytereadpos, buffered, bytereadpos-bfr_start, length ); abort(); } to_read = static_cast<unsigned int>( (bfr_start+buffered)- bytereadpos ); } memcpy( dst, bfr+(static_cast<unsigned int>( bytereadpos-bfr_start)), to_read); // We only ever flush up to the start of a read as we // have only scanned up to a header *beginning* a block that is then // read //flush( bytereadpos ); bytereadpos += to_read; return to_read;}#ifdef REDUNDANT_CODE/** Initialize buffer, call once before first putbits or alignbits. @param bs_filename output filename @param buf_size size of the temporary output buffer to use*/void OBitStream::open(char *bs_filename, unsigned int buf_size){ if ((fileh = fopen(bs_filename, "wb")) == NULL) { mjpeg_error_exit1( "Unable to open file %s for writing; %s", bs_filename, strerror(errno)); } filename = strcpy( new char[strlen(bs_filename)+1], bs_filename ); SetBufSize(buf_size); // Save multiple buffering... setvbuf(fileh, 0, _IONBF, 0 ); bitidx = 8; byteidx = 0; bitwritepos = 0LL; outbyte = 0;}/** Closes the OBitStream. Flushes the output buffer and closes the output file if one was open. */void OBitStream::close(){ if (fileh) { if (byteidx != 0) fwrite(bfr, sizeof(uint8_t), byteidx, fileh); fclose(fileh); delete filename; fileh = NULL; }}/** Puts a byte into the OBitStream. Puts the byte into the internal buffer; if the buffer is full, it flushes the buffer to disk. */void OBitStream::putbyte(){ bfr[byteidx++] = outbyte; if (byteidx == bfr_size) { if (fwrite(bfr, sizeof(uint8_t), bfr_size, fileh) != bfr_size) mjpeg_error_exit1( "Write failed: %s", strerror(errno)); byteidx = 0; } bitidx = 8;}/** write rightmost n (0<=n<=32) bits of val to outfile @param val value to write bitwise@param n number of bits to write*/void OBitStream::putbits(uint32_t val, int n){ int i; unsigned int mask; bitwritepos += n; while( n >= bitidx ) { outbyte = (outbyte<<bitidx) | ((val >> (n-bitidx)) & ((1u<<bitidx)-1)); n -= bitidx; putbyte(); } if( n > 0 ) { bitidx -= n; outbyte = val & ((1u<<bitidx)-1); }#ifdef ORIGINAL mask = 1 << (n - 1); /* selects first (leftmost, msb) bit */ for (i = 0; i < n; i++) { bitwritepos += 1; outbyte <<= 1; if (val & mask) outbyte |= 1; mask >>= 1; /* select next bit */ bitidx--; if (bitidx == 0) /* 8 bit buffer full */ putbyte(); }#endif}/** write rightmost bit of val to outfile @param val value to write one bit of*/void OBitStream::put1bit(int val){ ++bitwritepos; outbyte = (outbyte<<1) | (val & 0x1); --bitidx; if (bitidx == 0) /* 8 bit buffer full */ putbyte();}/** zero bit stuffing to next byte boundary (5.2.3, 6.2.1) */void OBitStream::alignbits(){ if (bitidx != 8) putbits( 0, bitidx); flush_bytes();}#endif/* * Local variables: * c-file-style: "stroustrup" * tab-width: 4 * indent-tabs-mode: nil * End: */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?