diff options
Diffstat (limited to 'gst-libs/ext/mplex/bits.cc')
-rw-r--r-- | gst-libs/ext/mplex/bits.cc | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/gst-libs/ext/mplex/bits.cc b/gst-libs/ext/mplex/bits.cc new file mode 100644 index 00000000..84d05919 --- /dev/null +++ b/gst-libs/ext/mplex/bits.cc @@ -0,0 +1,358 @@ +/** @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 <sys/param.h> +#include <assert.h> +#include "mjpeg_logging.h" +#include "bits.hh" + + +/// Initializes the bitstream, sets internal variables. +// TODO: The buffer size should be set dynamically to sensible sizes. +// +BitStream::BitStream (): +user_data (NULL) +{ + totbits = 0LL; + buffer_start = 0LL; + eobs = true; + readpos = 0LL; + bfr = 0; + bfr_size = 0; +} + +/// Deconstructor. Deletes the internal buffer. +BitStream::~BitStream () +{ + delete bfr; +} + +/** + Refills an IBitStream's input buffer based on the internal variables bufcount and bfr_size. + */ +bool +IBitStream::refill_buffer () +{ + size_t i; + + if (bufcount >= bfr_size) { + SetBufSize (bfr_size + 4096); + } + + i = read_callback (this, bfr + bufcount, static_cast < size_t > (bfr_size - bufcount), user_data); + bufcount += i; + + if (i == 0) { + eobs = true; + return false; + } + return true; +} + +/** + Flushes all read input up-to *but not including* bit + unbuffer_upto. +@param flush_to the number of bits to flush +*/ + +void +IBitStream::flush (bitcount_t flush_upto) +{ + if (flush_upto > buffer_start + bufcount) + mjpeg_error_exit1 ("INTERNAL ERROR: attempt to flush input beyond buffered amount"); + + if (flush_upto < buffer_start) + mjpeg_error_exit1 + ("INTERNAL ERROR: attempt to flush input stream before first buffered byte %d last is %d", + (int) flush_upto, (int) buffer_start); + unsigned int bytes_to_flush = static_cast < unsigned int >(flush_upto - buffer_start); + + // + // Don't bother actually flushing until a good fraction of a buffer + // will be cleared. + // + + if (bytes_to_flush < bfr_size * 3 / 4) + return; + + bufcount -= bytes_to_flush; + buffer_start = flush_upto; + byteidx -= bytes_to_flush; + memmove (bfr, bfr + bytes_to_flush, static_cast < size_t > (bufcount)); +} + + +/** + 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 (BitStreamUndo & undo) +{ + undo = *(static_cast < BitStreamUndo * >(this)); +} + +/** +Undoes changes committed to an IBitStream. +@param undo handle to retrieve the undo information + */ +void +IBitStream::undochanges (BitStreamUndo & undo) +{ + *(static_cast < BitStreamUndo * >(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::read_buffered_bytes (uint8_t * dst, unsigned int length) +{ + unsigned int to_read = length; + + if (readpos < buffer_start) + mjpeg_error_exit1 + ("INTERNAL ERROR: access to input stream buffer @ %d: before first buffered byte (%d)", + (int) readpos, (int) buffer_start); + + if (readpos + length > buffer_start + bufcount) { + /* + if (!feof (fileh)) { + mjpeg_error + ("INTERNAL ERROR: access to input stream buffer beyond last buffered byte @POS=%lld END=%d REQ=%lld + %d bytes", + readpos, bufcount, readpos - (bitcount_t) buffer_start, length); + abort (); + } + */ + to_read = static_cast < unsigned int >((buffer_start + bufcount) - readpos); + } + memcpy (dst, bfr + (static_cast < unsigned int >(readpos - buffer_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 (readpos); + readpos += to_read; + return to_read; +} + +/** open the device to read the bit stream from it +@param bs_filename filename to open +@param buf_size size of the internal buffer +*/ +void +IBitStream::open (ReadCallback read_callback, void *user_data, unsigned int buf_size) +{ + this->read_callback = read_callback; + this->user_data = user_data; + + bfr_size = buf_size; + if (bfr == NULL) + bfr = new uint8_t[buf_size]; + else { + delete bfr; + + bfr = new uint8_t[buf_size]; + } + + byteidx = 0; + bitidx = 8; + totbits = 0LL; + bufcount = 0; + eobs = false; + if (!refill_buffer ()) { + if (bufcount == 0) { + mjpeg_error_exit1 ("Unable to read."); + } + } +} + + +/** sets the internal buffer size. + @param new_buf_size the new internal buffer size +*/ +void +IBitStream::SetBufSize (unsigned int new_buf_size) +{ + assert (bfr != NULL); // Must be open first! + assert (new_buf_size >= bfr_size); // Can only be increased in size... + + if (bfr_size != new_buf_size) { + uint8_t *new_buf = new uint8_t[new_buf_size]; + + memcpy (new_buf, bfr, static_cast < size_t > (bfr_size)); + delete bfr; + + bfr_size = new_buf_size; + bfr = new_buf; + } + +} + +/** + close the device containing the bit stream after a read process +*/ +void +IBitStream::close () +{ +} + + +// TODO replace with shift ops! + +uint8_t + IBitStream::masks[8] = { + 0x1, + 0x2, + 0x4, + 0x8, + 0x10, + 0x20, + 0x40, +0x80 }; + +/*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); + totbits++; + bitidx--; + if (!bitidx) { + bitidx = 8; + byteidx++; + if (byteidx == bufcount) { + refill_buffer (); + } + } + + 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++; + totbits += 8; + if (byteidx == bufcount) { + refill_buffer (); + } + i--; + } + } else { + while (i > 0) { + if (eobs) + return 0; + + j = (bfr[byteidx] & masks[bitidx - 1]) >> (bitidx - 1); + totbits++; + bitidx--; + if (!bitidx) { + bitidx = 8; + byteidx++; + if (byteidx == bufcount) { + refill_buffer (); + } + } + 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::seek_sync (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); +} + + + +/* + * Local variables: + * c-file-style: "stroustrup" + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ |