changeset 2970:583b6ac45c07 libavcodec

unfinished jpeg-ls codec (feel free to finish it ...)
author michael
date Sun, 18 Dec 2005 13:17:44 +0000
parents c9f6a0946672
children 1c22981c3498
files allcodecs.c avcodec.h jpeg_ls.c mjpeg.c
diffstat 4 files changed, 457 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/allcodecs.c	Sun Dec 18 11:41:32 2005 +0000
+++ b/allcodecs.c	Sun Dec 18 13:17:44 2005 +0000
@@ -131,6 +131,9 @@
 #ifdef CONFIG_LJPEG_ENCODER
     register_avcodec(&ljpeg_encoder);
 #endif //CONFIG_LJPEG_ENCODER
+#ifdef CONFIG_JPEGLS_ENCODER
+    register_avcodec(&jpegls_encoder);
+#endif //CONFIG_JPEGLS_ENCODER
 #ifdef CONFIG_ZLIB
 #ifdef CONFIG_PNG_ENCODER
     register_avcodec(&png_encoder);
--- a/avcodec.h	Sun Dec 18 11:41:32 2005 +0000
+++ b/avcodec.h	Sun Dec 18 13:17:44 2005 +0000
@@ -44,6 +44,7 @@
     CODEC_ID_MJPEGB,
     CODEC_ID_LJPEG,
     CODEC_ID_SP5X,
+    CODEC_ID_JPEGLS,
     CODEC_ID_MPEG4,
     CODEC_ID_RAWVIDEO,
     CODEC_ID_MSMPEG4V1,
@@ -1532,6 +1533,14 @@
      * - decoding: unused
      */
     int context_model;
+#if 0
+    /**
+     *
+     * - encoding: unused
+     * - decoding: set by user.
+     */
+    uint8_t * (*realloc)(struct AVCodecContext *s, uint8_t *buf, int buf_size);
+#endif
 
     /**
      * slice flags
@@ -1944,6 +1953,7 @@
 extern AVCodec dvvideo_encoder;
 extern AVCodec mjpeg_encoder;
 extern AVCodec ljpeg_encoder;
+extern AVCodec jpegls_encoder;
 extern AVCodec png_encoder;
 extern AVCodec ppm_encoder;
 extern AVCodec pgm_encoder;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jpeg_ls.c	Sun Dec 18 13:17:44 2005 +0000
@@ -0,0 +1,391 @@
+/*
+ * JPEG-LS encoder and decoder
+ * Copyright (c) 2003 Michael Niedermayer
+ *
+ * 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 jpeg_ls.c
+ * JPEG-LS encoder and decoder.
+ */
+
+#undef printf
+#undef fprintf
+
+static inline int quantize(MJpegDecodeContext *s, int v){ //FIXME optimize
+    if(v==0) return 0;
+    if(v < 0){
+        if     (v >-s->t1) return -1;
+        else if(v >-s->t2) return -2;
+        else if(v >-s->t3) return -3;
+        else               return -4;
+    }else{
+        if     (v < s->t1) return 1;
+        else if(v < s->t2) return 2;
+        else if(v < s->t3) return 3;
+        else               return 4;
+    }
+}
+
+static inline int predict8(uint8_t *src, uint8_t *last){ //FIXME perhaps its better to suppress these 2
+    const int LT= last[-1];
+    const int  T= last[ 0];
+    const int L =  src[-1];
+
+    return mid_pred(L, L + T - LT, T);
+}
+
+static inline int predict16(uint16_t *src, uint16_t *last){
+    const int LT= last[-1];
+    const int  T= last[ 0];
+    const int L =  src[-1];
+
+    return mid_pred(L, L + T - LT, T);
+}
+
+static int encode_picture_ls(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data){
+    return 0;
+}
+
+static int iso_clip(int v, int vmin, int vmax){
+    if(v > vmax || v < vmin) return vmin;
+    else                     return v;
+}
+
+static void reset_ls_coding_parameters(MJpegDecodeContext *s, int reset_all){
+    const int basic_t1= 3;
+    const int basic_t2= 7;
+    const int basic_t3= 21;
+    int factor;
+
+    if(s->maxval==0 || reset_all) s->maxval= (1<<s->bits) - 1;
+    
+    if(s->maxval >=128){
+        factor= (FFMIN(s->maxval, 4096) + 128)>>8;
+
+        if(s->t1==0     || reset_all)
+            s->t1= iso_clip(factor*(basic_t1-2) + 2 + 3*s->near, s->near+1, s->maxval);
+        if(s->t2==0     || reset_all)
+            s->t2= iso_clip(factor*(basic_t2-3) + 3 + 5*s->near, s->t1, s->maxval);
+        if(s->t3==0     || reset_all)
+            s->t3= iso_clip(factor*(basic_t3-4) + 4 + 7*s->near, s->t2, s->maxval);
+    }else{
+        factor= 256 / (s->maxval + 1);
+
+        if(s->t1==0     || reset_all)
+            s->t1= iso_clip(FFMAX(2, basic_t1/factor + 3*s->near), s->near+1, s->maxval);
+        if(s->t2==0     || reset_all)
+            s->t2= iso_clip(FFMAX(3, basic_t2/factor + 5*s->near), s->t1, s->maxval);
+        if(s->t3==0     || reset_all)
+            s->t3= iso_clip(FFMAX(4, basic_t3/factor + 6*s->near), s->t2, s->maxval);
+    }
+
+    if(s->reset==0  || reset_all) s->reset= 64;
+}
+
+static int decode_lse(MJpegDecodeContext *s)
+{
+    int len, id;
+
+    /* XXX: verify len field validity */
+    len = get_bits(&s->gb, 16);
+    id = get_bits(&s->gb, 8);
+    
+    switch(id){
+    case 1:
+        s->maxval= get_bits(&s->gb, 16);
+        s->t1= get_bits(&s->gb, 16);
+        s->t2= get_bits(&s->gb, 16);
+        s->t3= get_bits(&s->gb, 16);
+        s->reset= get_bits(&s->gb, 16);
+        
+        reset_ls_coding_parameters(s, 0);
+        //FIXME quant table?
+    break;
+    case 2:
+    case 3:
+        printf("palette not supported\n");
+        return -1;
+    case 4:
+        printf("oversize image not supported\n");
+        return -1;
+    default:
+        printf("invalid id %d\n", id);
+        return -1;
+    }
+
+    return 0;
+}
+#if 0
+static inline void update_vlc_state(VlcState * const state, const int v, int half_count){
+    int drift= state->drift;
+    int count= state->count;
+    state->error_sum += ABS(v);
+    drift += v;
+
+    if(count == half_count){
+        count >>= 1;
+        drift >>= 1;
+        state->error_sum >>= 1;
+    }
+    count++;
+
+    if(drift <= -count){
+        if(state->bias > -128) state->bias--;
+        
+        drift += count;
+        if(drift <= -count)
+            drift= -count + 1;
+    }else if(drift > 0){
+        if(state->bias <  127) state->bias++;
+        
+        drift -= count;
+        if(drift > 0) 
+            drift= 0;
+    }
+
+    state->drift= drift;
+    state->count= count;
+}
+
+#define R(p, i) (is_uint8 ? (((uint8_t*)p)[i] : ((uint16_t*)p)[i])
+
+static inline int ls_decode_line(MJpegDecodeContext *s, void *lastv, void *dstv, int last2,
+                                 int w, int point_transform, int is_uint8){
+    int i, x, y;
+
+    for(x=0; x < w; x++){
+        int l, t, lt, rt;
+    
+        t= R(last, 0);
+        if(x){
+            l = t;
+            lt= last2;
+        }else{
+            l = R(dst, x-1);
+            lt= R(last, x-1);
+        }
+
+        if(x<w-1) rt= R(last, x+1);
+        else      rt= t;
+        
+        hr_gradient= rt - t;
+        hl_gradient= t - lt;
+         v_gradient= lt - l;
+            
+        context= quantize(s, v_gradient) + 9*(quantize(s, hl_gradient) + 9*quantize(s, hr_gradient));
+
+        if(context){
+            int pred= mid_pred(l, l + t - lt, t);
+
+            if(context < 0){
+                context= -context;
+                sign= 1;
+                pred= clip(0, pred - state->bias, maxval);
+            }else{
+                sign= 0;
+                pred= clip(0, pred + state->bias, maxval);
+            }
+
+            i= state->count;
+            k=0;
+            while(i < state->error_sum){ //FIXME optimize
+                k++;
+                i += i;
+            }
+            
+            v= get_ur_golomb_jpegls(gb, k, LIMIT-qbpp, qbpp);
+#if 1
+    v++;
+    if(v&1) v=  (v>>1);
+    else    v= -(v>>1);
+
+    if(k==0 && 2*state->drift <= - state->count) v ^= (-1);
+#else
+    v ^= (k==0 && 2*state->drift <= - state->count);
+    v++;
+    if(v&1) v=  (v>>1);
+    else    v= -(v>>1);
+
+#endif
+            update_vlc_state(state, v, half_count);
+            
+            if(sign) v= -v;
+            
+            if(is_uint8) ((uint8_t *)dst)[x]= (pred + v) & maxval;
+            else         ((uint16_t*)dst)[x]= (pred + v) & maxval;
+        }else{
+            int run_count;
+
+            while(get_bits1(&s->gb)){
+                run_count = 1<<log2_run[run_index];
+                if(x + run_count > w) run_count= w - x;
+                else                  run_index++;
+                
+                for(; run_count; run_count--){
+                    if(is_uint8) ((uint8_t *)dst)[x++]= l;
+                    else         ((uint16_t*)dst)[x++]= l;
+                }
+                
+                if(x >= w) return 0; 
+            }
+            
+            run_count= get_bits(&s->gb, log2_run[run_index]);
+
+            for(; run_count; run_count--){
+                if(is_uint8) ((uint8_t *)dst)[x++]= l;
+                else         ((uint16_t*)dst)[x++]= l;
+            }
+            
+            if(run_index) run_index--;
+            
+            if(x >= w) return 0;
+
+            t= R(last, 0);
+            
+            RItype= (l==t);
+            if(l==t){
+                state= 366;
+                temp= state->error_sum + (state->count>>1);
+            }else{
+                state= 365;
+                temp= state->error_sum;
+            }
+            
+            pred= t;
+            sign= l > t;
+            
+            i= state->count;
+            k=0;
+            while(i < temp){ //FIXME optimize
+                k++;
+                i += i;
+            }
+            
+            assert(Errval != 0);
+            map = (k==0 && 2*Nn < state->count) == (Errval>0); 
+            
+            
+                    if(run_count==0 && run_mode==1){
+                        if(get_bits1(&s->gb)){
+                            run_count = 1<<log2_run[run_index];
+                            if(x + run_count <= w) run_index++;
+                        }else{
+                            if(log2_run[run_index]) run_count = get_bits(&s->gb, log2_run[run_index]);
+                            else run_count=0;
+                            if(run_index) run_index--;
+                            run_mode=2;
+                        }
+                    }
+                    run_count--;
+                    if(run_count < 0){
+                        run_mode=0;
+                        run_count=0;
+                        diff= get_vlc_symbol(&s->gb, &p->vlc_state[context]);
+                        if(diff>=0) diff++;
+                    }else
+                        diff=0;
+        
+        }
+    }
+
+/*                if (s->restart_interval && !s->restart_count)
+                    s->restart_count = s->restart_interval;*/
+
+            if(mb_x==0 || mb_y==0 || s->interlaced){
+                for(i=0;i<nb_components;i++) {
+                    uint8_t *ptr;
+                    int n, h, v, x, y, c, j, linesize;
+                    n = s->nb_blocks[i];
+                    c = s->comp_index[i];
+                    h = s->h_scount[i];
+                    v = s->v_scount[i];
+                    x = 0;
+                    y = 0;
+                    linesize= s->linesize[c];
+                    
+                    for(j=0; j<n; j++) {
+                        int pred;
+
+                        ptr = s->current_picture[c] + (linesize * (v * mb_y + y)) + (h * mb_x + x); //FIXME optimize this crap
+                        if(y==0 && mb_y==0){
+                            if(x==0 && mb_x==0){
+                                pred= 128 << point_transform;
+                            }else{
+                                pred= ptr[-1];
+                            }
+                        }else{
+                            if(x==0 && mb_x==0){
+                                pred= ptr[-linesize];
+                            }else{
+                                PREDICT(pred, ptr[-linesize-1], ptr[-linesize], ptr[-1], predictor);
+                            }
+                        }
+                        
+                        if (s->interlaced && s->bottom_field)
+                            ptr += linesize >> 1;
+                        *ptr= pred + (mjpeg_decode_dc(s, s->dc_index[i]) << point_transform);
+
+                        if (++x == h) {
+                            x = 0;
+                            y++;
+                        }
+                    }
+                }
+            }else{
+                for(i=0;i<nb_components;i++) {
+                    uint8_t *ptr;
+                    int n, h, v, x, y, c, j, linesize;
+                    n = s->nb_blocks[i];
+                    c = s->comp_index[i];
+                    h = s->h_scount[i];
+                    v = s->v_scount[i];
+                    x = 0;
+                    y = 0;
+                    linesize= s->linesize[c];
+                    
+                    for(j=0; j<n; j++) {
+                        int pred;
+
+                        ptr = s->current_picture[c] + (linesize * (v * mb_y + y)) + (h * mb_x + x); //FIXME optimize this crap
+                        PREDICT(pred, ptr[-linesize-1], ptr[-linesize], ptr[-1], predictor);
+                        *ptr= pred + (mjpeg_decode_dc(s, s->dc_index[i]) << point_transform);
+                        if (++x == h) {
+                            x = 0;
+                            y++;
+                        }
+                    }
+                }
+            }
+            if (s->restart_interval && !--s->restart_count) {
+                align_get_bits(&s->gb);
+                skip_bits(&s->gb, 16); /* skip RSTn */
+            }
+    return 0;
+}
+#endif
+
+#ifdef CONFIG_ENCODERS
+AVCodec jpegls_encoder = { //FIXME avoid MPV_* lossless jpeg shouldnt need them
+    "jpegls",
+    CODEC_TYPE_VIDEO,
+    CODEC_ID_JPEGLS,
+    sizeof(MpegEncContext),
+    MPV_encode_init,
+    encode_picture_ls,
+    MPV_encode_end,
+};
+#endif
--- a/mjpeg.c	Sun Dec 18 11:41:32 2005 +0000
+++ b/mjpeg.c	Sun Dec 18 13:17:44 2005 +0000
@@ -118,8 +118,8 @@
     JPG4  = 0xf4,
     JPG5  = 0xf5,
     JPG6  = 0xf6,
-    JPG7  = 0xf7,
-    JPG8  = 0xf8,
+    SOF48 = 0xf7,        ///< JPEG-LS
+    LSE   = 0xf8,        ///< JPEG-LS extension parameters
     JPG9  = 0xf9,
     JPG10 = 0xfa,
     JPG11 = 0xfb,
@@ -417,7 +417,10 @@
 
 void mjpeg_picture_header(MpegEncContext *s)
 {
-    const int lossless= s->avctx->codec_id == CODEC_ID_LJPEG;
+    const int lossless= s->avctx->codec_id != CODEC_ID_MJPEG;
+    const int ls      = s->avctx->codec_id == CODEC_ID_JPEGLS;
+
+    assert(!(ls && s->mjpeg_write_tables));
 
     put_marker(&s->pb, SOI);
 
@@ -427,7 +430,12 @@
 
     if (s->mjpeg_write_tables) jpeg_table_header(s);
 
-    put_marker(&s->pb, lossless ? SOF3 : SOF0);
+    switch(s->avctx->codec_id){
+    case CODEC_ID_MJPEG:  put_marker(&s->pb, SOF0 ); break;
+    case CODEC_ID_LJPEG:  put_marker(&s->pb, SOF3 ); break;
+    case CODEC_ID_JPEGLS: put_marker(&s->pb, SOF48); break;
+    default: assert(0);
+    }
 
     put_bits(&s->pb, 16, 17);
     if(lossless && s->avctx->pix_fmt == PIX_FMT_RGBA32)
@@ -485,9 +493,18 @@
     put_bits(&s->pb, 4, 1); /* DC huffman table index */
     put_bits(&s->pb, 4, lossless ? 0 : 1); /* AC huffman table index */
 
-    put_bits(&s->pb, 8, lossless ? s->avctx->prediction_method+1 : 0); /* Ss (not used) */
-    put_bits(&s->pb, 8, lossless ? 0 : 63); /* Se (not used) */
+    put_bits(&s->pb, 8, (lossless && !ls) ? s->avctx->prediction_method+1 : 0); /* Ss (not used) */
+
+    switch(s->avctx->codec_id){
+    case CODEC_ID_MJPEG:  put_bits(&s->pb, 8, 63); break; /* Se (not used) */
+    case CODEC_ID_LJPEG:  put_bits(&s->pb, 8,  0); break; /* not used */
+    case CODEC_ID_JPEGLS: put_bits(&s->pb, 8,  1); break; /* ILV = line interleaved */
+    default: assert(0);
+    }
+
     put_bits(&s->pb, 8, 0); /* Ah/Al (not used) */
+
+    //FIXME DC/AC entropy table selectors stuff in jpegls
 }
 
 static void escape_FF(MpegEncContext *s, int start)
@@ -827,11 +844,17 @@
     int interlaced;     /* true if interlaced */
     int bottom_field;   /* true if bottom field */
     int lossless;
+    int ls;
     int rgb;
     int rct;            /* standard rct */
     int pegasus_rct;    /* pegasus reversible colorspace transform */
     int bits;           /* bits per component */
 
+    int maxval;
+    int near;         ///< near lossless bound (si 0 for lossless)
+    int t1,t2,t3;
+    int reset;        ///< context halfing intervall ?rename
+
     int width, height;
     int mb_width, mb_height;
     int nb_components;
@@ -864,6 +887,8 @@
     int mjpb_skiptosod;
 } MJpegDecodeContext;
 
+#include "jpeg_ls.c" //FIXME make jpeg-ls more independant
+
 static int mjpeg_decode_dht(MJpegDecodeContext *s);
 
 static int build_vlc(VLC *vlc, const uint8_t *bits_table, const uint8_t *val_table,
@@ -1521,8 +1546,8 @@
 #endif
     }
 
-    predictor= get_bits(&s->gb, 8); /* lossless predictor or start of spectral (Ss) */
-    skip_bits(&s->gb, 8); /* Se */
+    predictor= get_bits(&s->gb, 8); /* JPEG Ss / lossless JPEG predictor /JPEG-LS NEAR */
+    int ilv= get_bits(&s->gb, 8);    /* JPEG Se / JPEG-LS ILV */
     skip_bits(&s->gb, 4); /* Ah */
     point_transform= get_bits(&s->gb, 4); /* Al */
 
@@ -1544,13 +1569,19 @@
     }
 
     if(s->avctx->debug & FF_DEBUG_PICT_INFO)
-        av_log(s->avctx, AV_LOG_DEBUG, "%s %s p:%d >>:%d\n", s->lossless ? "lossless" : "sequencial DCT", s->rgb ? "RGB" : "", predictor, point_transform);
+        av_log(s->avctx, AV_LOG_DEBUG, "%s %s p:%d >>:%d ilv:%d bits:%d %s\n", s->lossless ? "lossless" : "sequencial DCT", s->rgb ? "RGB" : "",
+               predictor, point_transform, ilv, s->bits,
+               s->pegasus_rct ? "PRCT" : (s->rct ? "RCT" : ""));
+
 
     /* mjpeg-b can have padding bytes between sos and image data, skip them */
     for (i = s->mjpb_skiptosod; i > 0; i--)
         skip_bits(&s->gb, 8);
 
     if(s->lossless){
+        if(s->ls){
+//            for(){
+        }else{
             if(s->rgb){
                 if(ljpeg_decode_rgb_scan(s, predictor, point_transform) < 0)
                     return -1;
@@ -1558,6 +1589,7 @@
                 if(ljpeg_decode_yuv_scan(s, predictor, point_transform) < 0)
                     return -1;
             }
+        }
     }else{
         if(mjpeg_decode_scan(s) < 0)
             return -1;
@@ -1894,6 +1926,8 @@
                 switch(start_code) {
                 case SOI:
 		    s->restart_interval = 0;
+                    reset_ls_coding_parameters(s, 1);
+
 		    s->restart_count = 0;
                     /* nothing to do on SOI */
                     break;
@@ -1916,6 +1950,16 @@
                     if (mjpeg_decode_sof(s) < 0)
 			return -1;
                     break;
+                case SOF48:
+                    s->lossless=1;
+                    s->ls=1;
+                    if (mjpeg_decode_sof(s) < 0)
+                        return -1;
+                    break;
+                case LSE:
+                    if (decode_lse(s) < 0)
+                        return -1;
+                    break;
 		case EOI:
 		    if ((s->buggy_avid && !s->interlaced) || s->restart_interval)
                         break;