/*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // // By downloading, copying, installing or using the software you agree to this license. // If you do not agree to this license, do not download, install, // copy or use the software. // // // Intel License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000, Intel Corporation, all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistribution's of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistribution's in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * The name of Intel Corporation may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and // any express or implied warranties, including, but not limited to, the implied // warranties of merchantability and fitness for a particular purpose are disclaimed. // In no event shall the Intel Corporation or contributors be liable for any direct, // indirect, incidental, special, exemplary, or consequential damages // (including, but not limited to, procurement of substitute goods or services; // loss of use, data, or profits; or business interruption) however caused // and on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out of // the use of this software, even if advised of the possibility of such damage. // //M*/ #include "_highgui.h" #include "bitstrm.h" #define BS_DEF_BLOCK_SIZE (1<<15) const ulong bs_bit_mask[] = { 0, 0x00000001, 0x00000003, 0x00000007, 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF }; void bsBSwapBlock( uchar *start, uchar *end ) { ulong* data = (ulong*)start; int i, size = (int)(end - start+3)/4; for( i = 0; i < size; i++ ) { ulong temp = data[i]; temp = BSWAP( temp ); data[i] = temp; } } bool bsIsBigEndian( void ) { return (((const int*)"\0\x1\x2\x3\x4\x5\x6\x7")[0] & 255) != 0; } ///////////////////////// RBaseStream //////////////////////////// bool RBaseStream::IsOpened() { return m_is_opened; } void RBaseStream::Allocate() { if( !m_start ) { m_start = new uchar[m_block_size + m_unGetsize]; m_start+= m_unGetsize; } m_end = m_start + m_block_size; m_current = m_end; } RBaseStream::RBaseStream() { m_start = m_end = m_current = 0; m_file = 0; m_block_size = BS_DEF_BLOCK_SIZE; m_unGetsize = 4; // 32 bits m_is_opened = false; m_jmp_set = false; } RBaseStream::~RBaseStream() { Close(); // Close files Release(); // free buffers } void RBaseStream::ReadBlock() { size_t readed; assert( m_file != 0 ); // copy unget buffer if( m_start ) { memcpy( m_start - m_unGetsize, m_end - m_unGetsize, m_unGetsize ); } SetPos( GetPos() ); // normalize position fseek( m_file, m_block_pos, SEEK_SET ); readed = fread( m_start, 1, m_block_size, m_file ); m_end = m_start + readed; m_current -= m_block_size; m_block_pos += m_block_size; if( readed == 0 || m_current >= m_end ) { if( m_jmp_set ) longjmp( m_jmp_buf, RBS_THROW_EOS ); } } bool RBaseStream::Open( const char* filename ) { Close(); Allocate(); m_file = fopen( filename, "rb" ); if( m_file ) { m_is_opened = true; SetPos(0); } return m_file != 0; } void RBaseStream::Close() { if( m_file ) { fclose( m_file ); m_file = 0; } m_is_opened = false; } void RBaseStream::Release() { if( m_start ) { delete[] (m_start - m_unGetsize); } m_start = m_end = m_current = 0; } void RBaseStream::SetBlockSize( int block_size, int unGetsize ) { assert( unGetsize >= 0 && block_size > 0 && (block_size & (block_size-1)) == 0 ); if( m_start && block_size == m_block_size && unGetsize == m_unGetsize ) return; Release(); m_block_size = block_size; m_unGetsize = unGetsize; Allocate(); } void RBaseStream::SetPos( int pos ) { int offset = pos & (m_block_size - 1); int block_pos = pos - offset; assert( IsOpened() && pos >= 0 ); if( m_current < m_end && block_pos == m_block_pos - m_block_size ) { m_current = m_start + offset; } else { m_block_pos = block_pos; m_current = m_start + m_block_size + offset; } } int RBaseStream::GetPos() { assert( IsOpened() ); return m_block_pos - m_block_size + (int)(m_current - m_start); } void RBaseStream::Skip( int bytes ) { assert( bytes >= 0 ); m_current += bytes; } jmp_buf& RBaseStream::JmpBuf() { m_jmp_set = true; return m_jmp_buf; } ///////////////////////// RLByteStream //////////////////////////// RLByteStream::~RLByteStream() { } int RLByteStream::GetByte() { uchar *current = m_current; int val; if( current >= m_end ) { ReadBlock(); current = m_current; } val = *((uchar*)current); m_current = current + 1; return val; } void RLByteStream::GetBytes( void* buffer, int count, int* readed ) { uchar* data = (uchar*)buffer; assert( count >= 0 ); if( readed) *readed = 0; while( count > 0 ) { int l; for(;;) { l = (int)(m_end - m_current); if( l > count ) l = count; if( l > 0 ) break; ReadBlock(); } memcpy( data, m_current, l ); m_current += l; data += l; count -= l; if( readed ) *readed += l; } } //////////// RLByteStream & RMByteStream s //////////////// RMByteStream::~RMByteStream() { } int RLByteStream::GetWord() { uchar *current = m_current; int val; if( current+1 < m_end ) { val = current[0] + (current[1] << 8); m_current = current + 2; } else { val = GetByte(); val|= GetByte() << 8; } return val; } int RLByteStream::GetDWord() { uchar *current = m_current; int val; if( current+3 < m_end ) { val = current[0] + (current[1] << 8) + (current[2] << 16) + (current[3] << 24); m_current = current + 4; } else { val = GetByte(); val |= GetByte() << 8; val |= GetByte() << 16; val |= GetByte() << 24; } return val; } int RMByteStream::GetWord() { uchar *current = m_current; int val; if( current+1 < m_end ) { val = (current[0] << 8) + current[1]; m_current = current + 2; } else { val = GetByte() << 8; val|= GetByte(); } return val; } int RMByteStream::GetDWord() { uchar *current = m_current; int val; if( current+3 < m_end ) { val = (current[0] << 24) + (current[1] << 16) + (current[2] << 8) + current[3]; m_current = current + 4; } else { val = GetByte() << 24; val |= GetByte() << 16; val |= GetByte() << 8; val |= GetByte(); } return val; } ///////////////////////// RLBitStream //////////////////////////// RLBitStream::~RLBitStream() { } void RLBitStream::ReadBlock() { RBaseStream::ReadBlock(); if( bsIsBigEndian() ) bsBSwapBlock( m_start, m_end ); } void RLBitStream::SetPos( int pos ) { RBaseStream::SetPos(pos); int offset = (int)(m_current - m_end); m_current = m_end + (offset & -4); m_bit_idx = (offset&3)*8; } int RLBitStream::GetPos() { return RBaseStream::GetPos() + (m_bit_idx >> 3); } int RLBitStream::Get( int bits ) { int bit_idx = m_bit_idx; int new_bit_idx = bit_idx + bits; int mask = new_bit_idx >= 32 ? -1 : 0; ulong* current = (ulong*)m_current; assert( (unsigned)bits < 32 ); if( (m_current = (uchar*)(current - mask)) >= m_end ) { ReadBlock(); current = ((ulong*)m_current) + mask; } m_bit_idx = new_bit_idx & 31; return ((current[0] >> bit_idx) | ((current[1] <<-bit_idx) & mask)) & bs_bit_mask[bits]; } int RLBitStream::Show( int bits ) { int bit_idx = m_bit_idx; int new_bit_idx = bit_idx + bits; int mask = new_bit_idx >= 32 ? -1 : 0; ulong* current = (ulong*)m_current; assert( (unsigned)bits < 32 ); if( (uchar*)(current - mask) >= m_end ) { ReadBlock(); current = ((ulong*)m_current) + mask; m_current = (uchar*)current; } return ((current[0] >> bit_idx) | ((current[1] <<-bit_idx) & mask)) & bs_bit_mask[bits]; } void RLBitStream::Move( int shift ) { int new_bit_idx = m_bit_idx + shift; m_current += (new_bit_idx >> 5) << 2; m_bit_idx = new_bit_idx & 31; } int RLBitStream::GetHuff( const short* table ) { int val; int code_bits; for(;;) { int table_bits = table[0]; val = table[Show(table_bits) + 2]; code_bits = val & 15; val >>= 4; if( code_bits != 0 ) break; table += val*2; Move( table_bits ); } Move( code_bits ); if( val == RBS_HUFF_FORB ) { if( m_jmp_set ) longjmp( m_jmp_buf, RBS_THROW_FORB ); } return val; } void RLBitStream::Skip( int bytes ) { Move( bytes*8 ); } ///////////////////////// RMBitStream //////////////////////////// RMBitStream::~RMBitStream() { } void RMBitStream::ReadBlock() { RBaseStream::ReadBlock(); if( !bsIsBigEndian() ) bsBSwapBlock( m_start, m_end ); } void RMBitStream::SetPos( int pos ) { RBaseStream::SetPos(pos); int offset = (int)(m_current - m_end); m_current = m_end + ((offset - 1) & -4); m_bit_idx = (32 - (offset&3)*8) & 31; } int RMBitStream::GetPos() { return RBaseStream::GetPos() + ((32 - m_bit_idx) >> 3); } int RMBitStream::Get( int bits ) { int bit_idx = m_bit_idx - bits; int mask = bit_idx >> 31; ulong* current = ((ulong*)m_current) - mask; assert( (unsigned)bits < 32 ); if( (m_current = (uchar*)current) >= m_end ) { ReadBlock(); current = (ulong*)m_current; } m_bit_idx = bit_idx &= 31; return (((current[-1] << -bit_idx) & mask)| (current[0] >> bit_idx)) & bs_bit_mask[bits]; } int RMBitStream::Show( int bits ) { int bit_idx = m_bit_idx - bits; int mask = bit_idx >> 31; ulong* current = ((ulong*)m_current) - mask; assert( (unsigned)bits < 32 ); if( ((uchar*)current) >= m_end ) { m_current = (uchar*)current; ReadBlock(); current = (ulong*)m_current; m_current -= 4; } return (((current[-1]<<-bit_idx) & mask)| (current[0] >> bit_idx)) & bs_bit_mask[bits]; } int RMBitStream::GetHuff( const short* table ) { int val; int code_bits; for(;;) { int table_bits = table[0]; val = table[Show(table_bits) + 1]; code_bits = val & 15; val >>= 4; if( code_bits != 0 ) break; table += val; Move( table_bits ); } Move( code_bits ); if( val == RBS_HUFF_FORB ) { if( m_jmp_set ) longjmp( m_jmp_buf, RBS_THROW_FORB ); } return val; } void RMBitStream::Move( int shift ) { int new_bit_idx = m_bit_idx - shift; m_current -= (new_bit_idx >> 5)<<2; m_bit_idx = new_bit_idx & 31; } void RMBitStream::Skip( int bytes ) { Move( bytes*8 ); } static const int huff_val_shift = 20, huff_code_mask = (1 << huff_val_shift) - 1; bool bsCreateDecodeHuffmanTable( const int* src, short* table, int max_size ) { const int forbidden_entry = (RBS_HUFF_FORB << 4)|1; int first_bits = src[0]; struct { int bits; int offset; } sub_tables[1 << 11]; int size = (1 << first_bits) + 1; int i, k; /* calc bit depths of sub tables */ memset( sub_tables, 0, ((size_t)1 << first_bits)*sizeof(sub_tables[0]) ); for( i = 1, k = 1; src[k] >= 0; i++ ) { int code_count = src[k++]; int sb = i - first_bits; if( sb <= 0 ) k += code_count; else for( code_count += k; k < code_count; k++ ) { int code = src[k] & huff_code_mask; sub_tables[code >> sb].bits = sb; } } /* calc offsets of sub tables and whole size of table */ for( i = 0; i < (1 << first_bits); i++ ) { int b = sub_tables[i].bits; if( b > 0 ) { b = 1 << b; sub_tables[i].offset = size; size += b + 1; } } if( size > max_size ) { assert(0); return false; } /* fill first table and subtables with forbidden values */ for( i = 0; i < size; i++ ) { table[i] = (short)forbidden_entry; } /* write header of first table */ table[0] = (short)first_bits; /* fill first table and sub tables */ for( i = 1, k = 1; src[k] >= 0; i++ ) { int code_count = src[k++]; for( code_count += k; k < code_count; k++ ) { int table_bits= first_bits; int code_bits = i; int code = src[k] & huff_code_mask; int val = src[k] >>huff_val_shift; int j, offset = 0; if( code_bits > table_bits ) { int idx = code >> (code_bits -= table_bits); code &= (1 << code_bits) - 1; offset = sub_tables[idx].offset; table_bits= sub_tables[idx].bits; /* write header of subtable */ table[offset] = (short)table_bits; /* write jump to subtable */ table[idx + 1]= (short)(offset << 4); } table_bits -= code_bits; assert( table_bits >= 0 ); val = (val << 4) | code_bits; offset += (code << table_bits) + 1; for( j = 0; j < (1 << table_bits); j++ ) { assert( table[offset + j] == forbidden_entry ); table[ offset + j ] = (short)val; } } } return true; } int* bsCreateSourceHuffmanTable( const uchar* src, int* dst, int max_bits, int first_bits ) { int i, val_idx, code = 0; int* table = dst; *dst++ = first_bits; for( i = 1, val_idx = max_bits; i <= max_bits; i++ ) { int code_count = src[i - 1]; dst[0] = code_count; code <<= 1; for( int k = 0; k < code_count; k++ ) { dst[k + 1] = (src[val_idx + k] << huff_val_shift)|(code + k); } code += code_count; dst += code_count + 1; val_idx += code_count; } dst[0] = -1; return table; } /////////////////////////// WBaseStream ///////////////////////////////// // WBaseStream - base class for output streams WBaseStream::WBaseStream() { m_start = m_end = m_current = 0; m_file = 0; m_block_size = BS_DEF_BLOCK_SIZE; m_is_opened = false; } WBaseStream::~WBaseStream() { Close(); // Close files Release(); // free buffers } bool WBaseStream::IsOpened() { return m_is_opened; } void WBaseStream::Allocate() { if( !m_start ) m_start = new uchar[m_block_size]; m_end = m_start + m_block_size; m_current = m_start; } void WBaseStream::WriteBlock() { int size = (int)(m_current - m_start); assert( m_file != 0 ); //fseek( m_file, m_block_pos, SEEK_SET ); fwrite( m_start, 1, size, m_file ); m_current = m_start; /*if( written < size ) throw RBS_THROW_EOS;*/ m_block_pos += size; } bool WBaseStream::Open( const char* filename ) { Close(); Allocate(); m_file = fopen( filename, "wb" ); if( m_file ) { m_is_opened = true; m_block_pos = 0; m_current = m_start; } return m_file != 0; } void WBaseStream::Close() { if( m_file ) { WriteBlock(); fclose( m_file ); m_file = 0; } m_is_opened = false; } void WBaseStream::Release() { if( m_start ) { delete[] m_start; } m_start = m_end = m_current = 0; } void WBaseStream::SetBlockSize( int block_size ) { assert( block_size > 0 && (block_size & (block_size-1)) == 0 ); if( m_start && block_size == m_block_size ) return; Release(); m_block_size = block_size; Allocate(); } int WBaseStream::GetPos() { assert( IsOpened() ); return m_block_pos + (int)(m_current - m_start); } ///////////////////////////// WLByteStream /////////////////////////////////// WLByteStream::~WLByteStream() { } void WLByteStream::PutByte( int val ) { *m_current++ = (uchar)val; if( m_current >= m_end ) WriteBlock(); } void WLByteStream::PutBytes( const void* buffer, int count ) { uchar* data = (uchar*)buffer; assert( data && m_current && count >= 0 ); while( count ) { int l = (int)(m_end - m_current); if( l > count ) l = count; if( l > 0 ) { memcpy( m_current, data, l ); m_current += l; data += l; count -= l; } if( m_current == m_end ) WriteBlock(); } } void WLByteStream::PutWord( int val ) { uchar *current = m_current; if( current+1 < m_end ) { current[0] = (uchar)val; current[1] = (uchar)(val >> 8); m_current = current + 2; if( m_current == m_end ) WriteBlock(); } else { PutByte(val); PutByte(val >> 8); } } void WLByteStream::PutDWord( int val ) { uchar *current = m_current; if( current+3 < m_end ) { current[0] = (uchar)val; current[1] = (uchar)(val >> 8); current[2] = (uchar)(val >> 16); current[3] = (uchar)(val >> 24); m_current = current + 4; if( m_current == m_end ) WriteBlock(); } else { PutByte(val); PutByte(val >> 8); PutByte(val >> 16); PutByte(val >> 24); } } ///////////////////////////// WMByteStream /////////////////////////////////// WMByteStream::~WMByteStream() { } void WMByteStream::PutWord( int val ) { uchar *current = m_current; if( current+1 < m_end ) { current[0] = (uchar)(val >> 8); current[1] = (uchar)val; m_current = current + 2; if( m_current == m_end ) WriteBlock(); } else { PutByte(val >> 8); PutByte(val); } } void WMByteStream::PutDWord( int val ) { uchar *current = m_current; if( current+3 < m_end ) { current[0] = (uchar)(val >> 24); current[1] = (uchar)(val >> 16); current[2] = (uchar)(val >> 8); current[3] = (uchar)val; m_current = current + 4; if( m_current == m_end ) WriteBlock(); } else { PutByte(val >> 24); PutByte(val >> 16); PutByte(val >> 8); PutByte(val); } } ///////////////////////////// WMBitStream /////////////////////////////////// WMBitStream::WMBitStream() { m_pad_val = 0; ResetBuffer(); } WMBitStream::~WMBitStream() { } bool WMBitStream::Open( const char* filename ) { ResetBuffer(); return WBaseStream::Open( filename ); } void WMBitStream::ResetBuffer() { m_val = 0; m_bit_idx = 32; m_current = m_start; } void WMBitStream::Flush() { if( m_bit_idx < 32 ) { Put( m_pad_val, m_bit_idx & 7 ); *((ulong*&)m_current)++ = m_val; } } void WMBitStream::Close() { if( m_is_opened ) { Flush(); WBaseStream::Close(); } } void WMBitStream::WriteBlock() { if( !bsIsBigEndian() ) bsBSwapBlock( m_start, m_current ); WBaseStream::WriteBlock(); } int WMBitStream::GetPos() { return WBaseStream::GetPos() + ((32 - m_bit_idx) >> 3); } void WMBitStream::Put( int val, int bits ) { int bit_idx = m_bit_idx - bits; ulong curval = m_val; assert( 0 <= bits && bits < 32 ); val &= bs_bit_mask[bits]; if( bit_idx >= 0 ) { curval |= val << bit_idx; } else { *((ulong*&)m_current)++ = curval | ((unsigned)val >> -bit_idx); if( m_current >= m_end ) { WriteBlock(); } bit_idx += 32; curval = val << bit_idx; } m_val = curval; m_bit_idx = bit_idx; } void WMBitStream::PutHuff( int val, const ulong* table ) { int min_val = (int)table[0]; val -= min_val; assert( (unsigned)val < table[1] ); ulong code = table[val + 2]; assert( code != 0 ); Put( code >> 8, code & 255 ); } bool bsCreateEncodeHuffmanTable( const int* src, ulong* table, int max_size ) { int i, k; int min_val = INT_MAX, max_val = INT_MIN; int size; /* calc min and max values in the table */ for( i = 1, k = 1; src[k] >= 0; i++ ) { int code_count = src[k++]; for( code_count += k; k < code_count; k++ ) { int val = src[k] >> huff_val_shift; if( val < min_val ) min_val = val; if( val > max_val ) max_val = val; } } size = max_val - min_val + 3; if( size > max_size ) { assert(0); return false; } memset( table, 0, size*sizeof(table[0])); table[0] = min_val; table[1] = size - 2; for( i = 1, k = 1; src[k] >= 0; i++ ) { int code_count = src[k++]; for( code_count += k; k < code_count; k++ ) { int val = src[k] >> huff_val_shift; int code = src[k] & huff_code_mask; table[val - min_val + 2] = (code << 8) | i; } } return true; }