summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2004-10-30 01:43:37 +0000
committerMichael Niedermayer <michaelni@gmx.at>2004-10-30 01:43:37 +0000
commit672a19aac24f94d4a55394099596a84add67c39b (patch)
tree1761e80c64a703a0b93d8b62298a30accb543231
parent9287acd1970986de093578c6724c8ba1877c7485 (diff)
range coder
Originally committed as revision 3654 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r--libavcodec/Makefile2
-rw-r--r--libavcodec/rangecoder.c178
-rw-r--r--libavcodec/rangecoder.h129
3 files changed, 308 insertions, 1 deletions
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index e41956ba6f..adc05033af 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -21,7 +21,7 @@ OBJS= common.o utils.o mem.o allcodecs.o \
msvideo1.o vqavideo.o idcinvideo.o adx.o rational.o faandct.o 8bps.o \
smc.o parser.o flicvideo.o truemotion1.o vmdav.o lcl.o qtrle.o g726.o \
flac.o vp3dsp.o integer.o snow.o tscc.o sonic.o ulti.o h264idct.o \
- qdrw.o xl.o
+ qdrw.o xl.o rangecoder.o
ifeq ($(AMR_NB),yes)
ifeq ($(AMR_NB_FIXED),yes)
diff --git a/libavcodec/rangecoder.c b/libavcodec/rangecoder.c
new file mode 100644
index 0000000000..159607c652
--- /dev/null
+++ b/libavcodec/rangecoder.c
@@ -0,0 +1,178 @@
+/*
+ * Range coder
+ * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/**
+ * @file rangecoder.c
+ * Range coder.
+ * based upon
+ * "Range encoding: an algorithm for removing redundancy from a digitised
+ * message.
+ * G. N. N. Martin Presented in March 1979 to the Video &
+ * Data Recording Conference,
+ * IBM UK Scientific Center held in Southampton July 24-27 1979."
+ *
+ */
+
+#include <string.h>
+
+#include "avcodec.h"
+#include "common.h"
+#include "rangecoder.h"
+
+
+void ff_init_range_encoder(RangeCoder *c, uint8_t *buf, int buf_size){
+ c->bytestream_start=
+ c->bytestream= buf;
+ c->bytestream_end= buf + buf_size;
+
+ c->low= 0;
+ c->range= 0xFF00;
+ c->outstanding_count= 0;
+ c->outstanding_byte= -1;
+}
+
+void ff_init_range_decoder(RangeCoder *c, const uint8_t *buf, int buf_size){
+ ff_init_range_encoder(c, buf, buf_size);
+
+ c->low =(*c->bytestream++)<<8;
+ c->low+= *c->bytestream++;
+}
+
+void ff_build_rac_states(RangeCoder *c, int factor, int max_p){
+ const int64_t one= 1LL<<32;
+ int64_t p;
+ int last_p8, p8, i, j;
+
+ memset(c->zero_state, 0, sizeof(c->zero_state));
+ memset(c-> one_state, 0, sizeof(c-> one_state));
+
+#if 0
+ for(i=1; i<256; i++){
+ if(c->one_state[i])
+ continue;
+
+ p= (i*one + 128) >> 8;
+ last_p8= i;
+ for(;;){
+ p+= ((one-p)*factor + one/2) >> 32;
+ p8= (256*p + one/2) >> 32; //FIXME try without the one
+ if(p8 <= last_p8) p8= last_p8+1;
+ if(p8 > max_p) p8= max_p;
+ if(p8 < last_p8)
+ break;
+ c->one_state[last_p8]= p8;
+ if(p8 == last_p8)
+ break;
+ last_p8= p8;
+ }
+ }
+#endif
+#if 1
+ last_p8= 0;
+ p= one/2;
+ for(i=0; i<128; i++){
+ p8= (256*p + one/2) >> 32; //FIXME try without the one
+ if(p8 <= last_p8) p8= last_p8+1;
+ if(last_p8 && last_p8<256 && p8<=max_p)
+ c->one_state[last_p8]= p8;
+
+ p+= ((one-p)*factor + one/2) >> 32;
+ last_p8= p8;
+ }
+#endif
+ for(i=256-max_p; i<=max_p; i++){
+ if(c->one_state[i])
+ continue;
+
+ p= (i*one + 128) >> 8;
+ p+= ((one-p)*factor + one/2) >> 32;
+ p8= (256*p + one/2) >> 32; //FIXME try without the one
+ if(p8 <= i) p8= i+1;
+ if(p8 > max_p) p8= max_p;
+ c->one_state[ i]= p8;
+ }
+
+ for(i=0; i<256; i++)
+ c->zero_state[i]= 256-c->one_state[256-i];
+#if 0
+ for(i=0; i<256; i++)
+ av_log(NULL, AV_LOG_DEBUG, "%3d %3d\n", i, c->one_state[i]);
+#endif
+}
+
+/**
+ *
+ * @return the number of bytes written
+ */
+int ff_rac_terminate(RangeCoder *c){
+ c->range=0xFF;
+ c->low +=0xFF;
+ renorm_encoder(c);
+ c->range=0xFF;
+ renorm_encoder(c);
+
+ assert(c->low == 0);
+ assert(c->range >= 0x100);
+
+ return c->bytestream - c->bytestream_start;
+}
+
+#if 0 //selftest
+#define SIZE 10240
+int main(){
+ RangeCoder c;
+ uint8_t b[9*SIZE];
+ uint8_t r[9*SIZE];
+ int i;
+ uint8_t state[10]= {0};
+
+ ff_init_range_encoder(&c, b, SIZE);
+ ff_build_rac_states(&c, 0.05*(1LL<<32), 128+64+32+16);
+
+ memset(state, 128, sizeof(state));
+
+ for(i=0; i<SIZE; i++){
+ r[i]= random()%7;
+ }
+
+
+ for(i=0; i<SIZE; i++){
+START_TIMER
+ put_rac(&c, state, r[i]&1);
+STOP_TIMER("put_rac")
+ }
+
+ ff_put_rac_terminate(&c);
+
+ ff_init_range_decoder(&c, b, SIZE);
+
+ memset(state, 128, sizeof(state));
+
+ for(i=0; i<SIZE; i++){
+START_TIMER
+ if( (r[i]&1) != get_rac(&c, state) )
+ av_log(NULL, AV_LOG_DEBUG, "rac failure at %d\n", i);
+STOP_TIMER("get_rac")
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libavcodec/rangecoder.h b/libavcodec/rangecoder.h
new file mode 100644
index 0000000000..3c363ac32c
--- /dev/null
+++ b/libavcodec/rangecoder.h
@@ -0,0 +1,129 @@
+/*
+ * Range coder
+ * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/**
+ * @file rangecoder.h
+ * Range coder.
+ */
+
+
+#undef NDEBUG
+#include <assert.h>
+
+typedef struct RangeCoder{
+ int low;
+ int range;
+ int outstanding_count;
+ int outstanding_byte;
+ uint8_t zero_state[256];
+ uint8_t one_state[256];
+ uint8_t *bytestream_start;
+ uint8_t *bytestream;
+ uint8_t *bytestream_end;
+}RangeCoder;
+
+void ff_init_range_encoder(RangeCoder *c, uint8_t *buf, int buf_size);
+void ff_init_range_decoder(RangeCoder *c, const uint8_t *buf, int buf_size);
+int ff_rac_terminate(RangeCoder *c);
+void ff_build_rac_states(RangeCoder *c, int factor, int max_p);
+
+static inline void renorm_encoder(RangeCoder *c){
+ //FIXME optimize
+ while(c->range < 0x100){
+ if(c->outstanding_byte < 0){
+ c->outstanding_byte= c->low>>8;
+ }else if(c->low <= 0xFF00){
+ *c->bytestream++ = c->outstanding_byte;
+ for(;c->outstanding_count; c->outstanding_count--)
+ *c->bytestream++ = 0xFF;
+ c->outstanding_byte= c->low>>8;
+ }else if(c->low >= 0x10000){
+ *c->bytestream++ = c->outstanding_byte + 1;
+ for(;c->outstanding_count; c->outstanding_count--)
+ *c->bytestream++ = 0x00;
+ c->outstanding_byte= (c->low>>8) & 0xFF;
+ }else{
+ c->outstanding_count++;
+ }
+
+ c->low = (c->low & 0xFF)<<8;
+ c->range <<= 8;
+ }
+}
+
+static inline void put_rac(RangeCoder *c, uint8_t * const state, int bit){
+ int range1= (c->range * (*state)) >> 8;
+
+ assert(*state);
+ assert(range1 < c->range);
+ assert(range1 > 0);
+ if(!bit){
+ c->range -= range1;
+ *state= c->zero_state[*state];
+ }else{
+ c->low += c->range - range1;
+ c->range = range1;
+ *state= c->one_state[*state];
+ }
+
+ renorm_encoder(c);
+}
+
+static inline void refill(RangeCoder *c){
+ if(c->range < 0x100){
+ c->range <<= 8;
+ c->low <<= 8;
+ if(c->bytestream < c->bytestream_end)
+ c->low+= c->bytestream[0];
+ c->bytestream++;
+ }
+}
+
+static inline int get_rac(RangeCoder *c, uint8_t * const state){
+ int range1= (c->range * (*state)) >> 8;
+ int one_mask;
+
+ c->range -= range1;
+#if 1
+ if(c->low < c->range){
+ *state= c->zero_state[*state];
+ refill(c);
+ return 0;
+ }else{
+ c->low -= c->range;
+ *state= c->one_state[*state];
+ c->range = range1;
+ refill(c);
+ return 1;
+ }
+#else
+ one_mask= (c->range - c->low-1)>>31;
+
+ c->low -= c->range & one_mask;
+ c->range += (range1 - c->range) & one_mask;
+
+ *state= c->zero_state[(*state) + (256&one_mask)];
+
+ refill(c);
+
+ return one_mask&1;
+#endif
+}
+