mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-08 18:39:54 +00:00
2f0cc8ec30
Original commit message from CVS: Moved from gst-plugins/ext/mplex/. See that directory for older changelogs.
358 lines
8 KiB
C++
358 lines
8 KiB
C++
/** @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:
|
||
*/
|