📄 bitstream.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / common tools sub-project * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <gpac/bitstream.h>/*the default size for new streams allocation...*/#define BS_MEM_BLOCK_ALLOC_SIZE 250/*private types*/enum{ GF_BITSTREAM_FILE_READ = GF_BITSTREAM_WRITE + 1, GF_BITSTREAM_FILE_WRITE, /*private mode if we own the buffer*/ GF_BITSTREAM_WRITE_DYN};struct __tag_bitstream{ /*original stream data*/ FILE *stream; /*original data*/ char *original; /*the size of our buffer*/ u64 size; /*current position in BYTES*/ u64 position; /*the byte readen/written */ u32 current; /*the number of bits in the current byte*/ u32 nbBits; /*the bitstream mode*/ u32 bsmode; void (*EndOfStream)(void *par); void *par;};GF_EXPORTGF_BitStream *gf_bs_new(char *buffer, u64 BufferSize, u32 mode){ GF_BitStream *tmp; if ( (buffer && ! BufferSize)) return NULL; tmp = (GF_BitStream *)malloc(sizeof(GF_BitStream)); if (!tmp) return NULL; memset(tmp, 0, sizeof(GF_BitStream)); tmp->original = (char*)buffer; tmp->size = BufferSize; tmp->position = 0; tmp->current = 0; tmp->bsmode = mode; tmp->stream = NULL; switch (tmp->bsmode) { case GF_BITSTREAM_READ: tmp->nbBits = 8; tmp->current = 0; break; case GF_BITSTREAM_WRITE: tmp->nbBits = 0; if (! buffer) { /*if BufferSize is specified, use it. This is typically used when AvgSize of some buffers is known, but some exceed it.*/ if (BufferSize) { tmp->size = BufferSize; } else { tmp->size = BS_MEM_BLOCK_ALLOC_SIZE; } tmp->original = (char *) malloc(sizeof(char) * ((u32) tmp->size)); if (! tmp->original) { free(tmp); return NULL; } tmp->bsmode = GF_BITSTREAM_WRITE_DYN; } else { tmp->original = (char*)buffer; tmp->size = BufferSize; } break; default: /*the stream constructor is not the same...*/ free(tmp); return NULL; } return tmp;}GF_EXPORTGF_BitStream *gf_bs_from_file(FILE *f, u32 mode){ GF_BitStream *tmp; if (!f) return NULL; tmp = (GF_BitStream *)malloc(sizeof(GF_BitStream)); if (!tmp) return NULL; memset(tmp, 0, sizeof(GF_BitStream)); /*switch to internal mode*/ mode = (mode==GF_BITSTREAM_READ) ? GF_BITSTREAM_FILE_READ : GF_BITSTREAM_FILE_WRITE; tmp->bsmode = mode; tmp->current = 0; tmp->nbBits = (mode == GF_BITSTREAM_FILE_READ) ? 8 : 0; tmp->original = NULL; tmp->position = 0; tmp->stream = f; /*get the size of this file (for read streams)*/ tmp->position = gf_f64_tell(f); gf_f64_seek(f, 0, SEEK_END); tmp->size = gf_f64_tell(f); gf_f64_seek(f, tmp->position, SEEK_SET); return tmp;}GF_EXPORTvoid gf_bs_del(GF_BitStream *bs){ if (!bs) return; /*if we are in dynamic mode (alloc done by the bitstream), free the buffer if still present*/ if ((bs->bsmode == GF_BITSTREAM_WRITE_DYN) && bs->original) free(bs->original); free(bs);}/*returns 1 if aligned wrt current mode, 0 otherwise*/static Bool BS_IsAlign(GF_BitStream *bs){ switch (bs->bsmode) { case GF_BITSTREAM_READ: case GF_BITSTREAM_FILE_READ: return ( (8 == bs->nbBits) ? 1 : 0); default: return !bs->nbBits; }}/*fetch a new byte in the bitstream switch between packets*/static u8 BS_ReadByte(GF_BitStream *bs){ if (bs->bsmode == GF_BITSTREAM_READ) { if (bs->position == bs->size) { if (bs->EndOfStream) bs->EndOfStream(bs->par); return 0; } return (u32) bs->original[bs->position++]; } /*we are in FILE mode, test for end of file*/ if (!feof(bs->stream)) { bs->position++; return (u32) fgetc(bs->stream); } if (bs->EndOfStream) bs->EndOfStream(bs->par); return 0;}#define NO_OPTS#ifndef NO_OPTSstatic u32 bit_mask[] = {0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1};static u32 bits_mask[] = {0x0, 0x1, 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F};#endifGF_EXPORTu8 gf_bs_read_bit(GF_BitStream *bs){ if (bs->nbBits == 8) { bs->current = BS_ReadByte(bs); bs->nbBits = 0; }#ifdef NO_OPTS { s32 ret; bs->current <<= 1; bs->nbBits++; ret = (bs->current & 0x100) >> 8; return (u8) ret; }#else return (u8) (bs->current & bit_mask[bs->nbBits++]) ? 1 : 0;#endif}GF_EXPORTu32 gf_bs_read_int(GF_BitStream *bs, u32 nBits){ u32 ret;#ifndef NO_OPTS if (nBits + bs->nbBits <= 8) { bs->nbBits += nBits; ret = (bs->current >> (8 - bs->nbBits) ) & bits_mask[nBits]; return ret; }#endif ret = 0; while (nBits-- > 0) { ret <<= 1; ret |= gf_bs_read_bit(bs); } return ret;}GF_EXPORTu32 gf_bs_read_u8(GF_BitStream *bs){ assert(bs->nbBits==8); return (u32) BS_ReadByte(bs);}GF_EXPORTu32 gf_bs_read_u16(GF_BitStream *bs){ u32 ret; assert(bs->nbBits==8); ret = BS_ReadByte(bs); ret<<=8; ret |= BS_ReadByte(bs); return ret;}GF_EXPORTu32 gf_bs_read_u24(GF_BitStream *bs){ u32 ret; assert(bs->nbBits==8); ret = BS_ReadByte(bs); ret<<=8; ret |= BS_ReadByte(bs); ret<<=8; ret |= BS_ReadByte(bs); return ret;}GF_EXPORTu32 gf_bs_read_u32(GF_BitStream *bs){ u32 ret; assert(bs->nbBits==8); ret = BS_ReadByte(bs); ret<<=8; ret |= BS_ReadByte(bs); ret<<=8; ret |= BS_ReadByte(bs); ret<<=8; ret |= BS_ReadByte(bs); return ret;}GF_EXPORTu64 gf_bs_read_u64(GF_BitStream *bs){ u64 ret; ret = gf_bs_read_u32(bs); ret<<=32; ret |= gf_bs_read_u32(bs); return ret;}GF_EXPORTu64 gf_bs_read_long_int(GF_BitStream *bs, u32 nBits){ u64 ret = 0; while (nBits-- > 0) { ret <<= 1; ret |= gf_bs_read_bit(bs); } return ret;}GF_EXPORTFloat gf_bs_read_float(GF_BitStream *bs){ char buf [4] = "\0\0\0";#ifdef NO_OPTS s32 i; for (i = 0; i < 32; i++) buf[3-i/8] |= gf_bs_read_bit(bs) << (7 - i%8);#else buf[3] = gf_bs_read_int(bs, 8); buf[2] = gf_bs_read_int(bs, 8); buf[1] = gf_bs_read_int(bs, 8); buf[0] = gf_bs_read_int(bs, 8);#endif return (* (Float *) buf);}GF_EXPORTDouble gf_bs_read_double(GF_BitStream *bs){ char buf [8] = "\0\0\0\0\0\0\0"; s32 i; for (i = 0; i < 64; i++) buf[7-i/8] |= gf_bs_read_bit(bs) << (7 - i%8); return (* (Double *) buf);}GF_EXPORTu32 gf_bs_read_data(GF_BitStream *bs, char *data, u32 nbBytes){ u64 orig = bs->position; if (bs->position+nbBytes > bs->size) return 0; if (BS_IsAlign(bs)) { switch (bs->bsmode) { case GF_BITSTREAM_READ: memcpy(data, bs->original + bs->position, nbBytes); bs->position += nbBytes; return nbBytes; case GF_BITSTREAM_FILE_READ: case GF_BITSTREAM_FILE_WRITE: fread(data, nbBytes, 1, bs->stream); bs->position += nbBytes; return nbBytes; default: return 0; } } while (nbBytes-- > 0) { *data++ = gf_bs_read_int(bs, 8); } return (u32) (bs->position - orig);}static void BS_WriteByte(GF_BitStream *bs, u8 val){ /*we don't allow write on READ buffers*/ if ( (bs->bsmode == GF_BITSTREAM_READ) || (bs->bsmode == GF_BITSTREAM_FILE_READ) ) return; if (!bs->original && !bs->stream) return; /*we are in MEM mode*/ if ( (bs->bsmode == GF_BITSTREAM_WRITE) || (bs->bsmode == GF_BITSTREAM_WRITE_DYN) ) { if (bs->position == bs->size) { /*no more space...*/ if (bs->bsmode != GF_BITSTREAM_WRITE_DYN) return; /*realloc if enough space...*/ if (bs->size > 0xFFFFFFFF) return; bs->original = (char*)realloc(bs->original, (u32) (bs->size + BS_MEM_BLOCK_ALLOC_SIZE)); if (!bs->original) return; bs->size += BS_MEM_BLOCK_ALLOC_SIZE; } bs->original[bs->position] = val; bs->position++; return; } /*we are in FILE mode, no pb for any realloc...*/ fputc(val, bs->stream); /*check we didn't rewind the stream*/ if (bs->size == bs->position) bs->size++; bs->position += 1;}static void BS_WriteBit(GF_BitStream *bs, u32 bit){ bs->current <<= 1; bs->current |= bit; if (++ bs->nbBits == 8) { bs->nbBits = 0; BS_WriteByte(bs, (u8) bs->current); bs->current = 0; }}GF_EXPORTvoid gf_bs_write_int(GF_BitStream *bs, s32 value, s32 nBits){ value <<= sizeof (s32) * 8 - nBits; while (--nBits >= 0) { BS_WriteBit (bs, value < 0); value <<= 1; }}GF_EXPORTvoid gf_bs_write_long_int(GF_BitStream *bs, s64 value, s32 nBits){ value <<= sizeof (s64) * 8 - nBits; while (--nBits >= 0) { BS_WriteBit (bs, value < 0); value <<= 1; }}GF_EXPORTvoid gf_bs_write_u8(GF_BitStream *bs, u32 value){ assert(!bs->nbBits); BS_WriteByte(bs, (u8) value);}GF_EXPORTvoid gf_bs_write_u16(GF_BitStream *bs, u32 value){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -