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 + -
显示快捷键?