[Ffmpeg-devel] [RFC] Some Progressive JPEG support

Kostya kostya.shishkov
Mon Nov 6 07:18:45 CET 2006


Here is result of my efforts to add Progressive JPEG support.
It is not complete (as it ignores refinement planes but that
is not possible to implement without keeping all DCT coefficients).
But progressive jpegs should be decoded correctly.

I won't have time to work on it and will be happy if somebody
will finish it.
-------------- next part --------------
Index: libavcodec/mjpeg.c
===================================================================
--- libavcodec/mjpeg.c	(revision 6882)
+++ libavcodec/mjpeg.c	(working copy)
@@ -854,6 +854,7 @@
     int bottom_field;   /* true if bottom field */
     int lossless;
     int ls;
+    int progressive;
     int rgb;
     int rct;            /* standard rct */
     int pegasus_rct;    /* pegasus reversible colorspace transform */
@@ -885,6 +886,7 @@
     DECLARE_ALIGNED_8(DCTELEM, block[64]);
     ScanTable scantable;
     void (*idct_put)(uint8_t *dest/*align 8*/, int line_size, DCTELEM *block/*align 16*/);
+    void (*idct_add)(uint8_t *dest/*align 8*/, int line_size, DCTELEM *block/*align 16*/);
 
     int restart_interval;
     int restart_count;
@@ -941,6 +943,7 @@
 
     s->scantable= s2.intra_scantable;
     s->idct_put= s2.dsp.idct_put;
+    s->idct_add= s2.dsp.idct_add;
 
     s->mpeg_enc_ctx_allocated = 0;
     s->buffer_size = 0;
@@ -1251,6 +1254,12 @@
         dprintf("decode_sof0: error, len(%d) mismatch\n", len);
     }
 
+    /* totally blank picture as progressive JPEG will only add details to it */
+    if(s->progressive){
+        memset(s->picture.data[0], 0, s->picture.linesize[0] * s->height);
+        memset(s->picture.data[1], 0, s->picture.linesize[1] * s->height >> (s->v_max - s->v_count[1]));
+        memset(s->picture.data[2], 0, s->picture.linesize[2] * s->height >> (s->v_max - s->v_count[2]));
+    }
     return 0;
 }
 
@@ -1328,6 +1337,86 @@
     return 0;
 }
 
+/* decode block and dequantize - progressive JPEG version */
+static int decode_block_progressive(MJpegDecodeContext *s, DCTELEM *block,
+                        int component, int dc_index, int ac_index, int16_t *quant_matrix,
+                        int ss, int se, int Ah, int Al, int *EOBRUN)
+{
+    int code, i, j, level, val, run;
+
+    /* DC coef */
+    if(!ss){
+        if(Ah)
+            val = get_bits1(&s->gb) << Al;
+        else
+            val = mjpeg_decode_dc(s, dc_index);
+        if (val == 0xffff) {
+            dprintf("error dc\n");
+            return -1;
+        }
+        val = (val * quant_matrix[0] << Al) + s->last_dc[component];
+    }else
+        val = 0;
+    s->last_dc[component] = val;
+    block[0] = val;
+    if(!se) return 0;
+    /* AC coefs */
+    if(*EOBRUN){
+        (*EOBRUN)--;
+        return 0;
+    }
+    {OPEN_READER(re, &s->gb)
+    for(i=ss;;i++) {
+        UPDATE_CACHE(re, &s->gb);
+        GET_VLC(code, re, &s->gb, s->vlcs[1][ac_index].table, 9, 2)
+        /* Progressive JPEG use AC coeffs from zero and this decoder sets offset 16 by default */
+        code -= 16;
+        if(code & 0xF) {
+            i += ((unsigned) code) >> 4;
+            code &= 0xf;
+            if(code > MIN_CACHE_BITS - 16){
+                UPDATE_CACHE(re, &s->gb)
+            }
+            {
+                int cache=GET_CACHE(re,&s->gb);
+                int sign=(~cache)>>31;
+                level = (NEG_USR32(sign ^ cache,code) ^ sign) - sign;
+            }
+
+            LAST_SKIP_BITS(re, &s->gb, code)
+
+            if (i >= se) {
+                if(i == se){
+                    j = s->scantable.permutated[se];
+                    block[j] = level * quant_matrix[j] << Al;
+                    break;
+                }
+                dprintf("error count: %d\n", i);
+                return -1;
+            }
+            j = s->scantable.permutated[i];
+            block[j] = level * quant_matrix[j] << Al;
+        }else{
+            run = ((unsigned) code) >> 4;
+            if(run == 0xF){// ZRL - skip 15 coefficients
+                i += 15;
+            }else{
+                val = run;
+                run = (1 << run);
+                UPDATE_CACHE(re, &s->gb);
+                run += (GET_CACHE(re, &s->gb) >> (32 - val)) & (run - 1);
+                if(val)
+                    LAST_SKIP_BITS(re, &s->gb, val);
+                *EOBRUN = run - 1;
+                break;
+            }
+        }
+    }
+    CLOSE_READER(re, &s->gb)}
+
+    return 0;
+}
+
 static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s, int predictor, int point_transform){
     int i, mb_x, mb_y;
     uint16_t buffer[32768][4];
@@ -1532,12 +1621,68 @@
     return 0;
 }
 
+static int mjpeg_decode_scan_progressive(MJpegDecodeContext *s, int nb_components, int ss, int se, int Ah, int Al){
+    int i, mb_x, mb_y;
+    int EOBRUN = 0;
+
+    if(Ah) return 0; // TODO decode refinement scans
+
+    for(mb_y = 0; mb_y < s->mb_height; mb_y++) {
+        for(mb_x = 0; mb_x < s->mb_width; mb_x++) {
+            if (s->restart_interval && !s->restart_count)
+                s->restart_count = s->restart_interval;
+
+            for(i=0;i<nb_components;i++) {
+                uint8_t *ptr;
+                int n, h, v, x, y, c, j;
+
+                n = s->nb_blocks[i];
+                c = s->comp_index[i];
+                h = s->h_scount[i];
+                v = s->v_scount[i];
+                x = 0;
+                y = 0;
+                for(j=0;j<n;j++) {
+                    memset(s->block, 0, sizeof(s->block));
+                    if (decode_block_progressive(s, s->block, i,
+                                     s->dc_index[i], s->ac_index[i],
+                                     s->quant_matrixes[ s->quant_index[c] ], ss, se, Ah, Al, &EOBRUN) < 0) {
+                        dprintf("error y=%d x=%d\n", mb_y, mb_x);
+                        return -1;
+                    }
+//                    dprintf("mb: %d %d processed\n", mb_y, mb_x);
+                    ptr = s->picture.data[c] +
+                        (((s->linesize[c] * (v * mb_y + y) * 8) +
+                        (h * mb_x + x) * 8) >> s->avctx->lowres);
+                    if (s->interlaced && s->bottom_field)
+                        ptr += s->linesize[c] >> 1;
+//av_log(NULL, AV_LOG_DEBUG, "%d %d %d %d %d %d %d %d \n", mb_x, mb_y, x, y, c, s->bottom_field, (v * mb_y + y) * 8, (h * mb_x + x) * 8);
+                    s->idct_add(ptr, s->linesize[c], s->block);
+                    if (++x == h) {
+                        x = 0;
+                        y++;
+                    }
+                }
+            }
+            /* (< 1350) buggy workaround for Spectralfan.mov, should be fixed */
+            if (s->restart_interval && (s->restart_interval < 1350) &&
+                !--s->restart_count) {
+                align_get_bits(&s->gb);
+                skip_bits(&s->gb, 16); /* skip RSTn */
+                for (i=0; i<nb_components; i++) /* reset dc */
+                    s->last_dc[i] = 1024;
+            }
+        }
+    }
+    return 0;
+}
+
 static int mjpeg_decode_sos(MJpegDecodeContext *s)
 {
     int len, nb_components, i, h, v, predictor, point_transform;
     int vmax, hmax, index, id;
     const int block_size= s->lossless ? 1 : 8;
-    int ilv;
+    int ilv, prev_shift;
 
     /* XXX: verify len field validity */
     len = get_bits(&s->gb, 16);
@@ -1548,7 +1693,7 @@
         return -1;
     }
     /* XXX: only interleaved scan accepted */
-    if ((nb_components != s->nb_components) && !s->ls)
+    if ((nb_components != s->nb_components) && !s->ls && !s->progressive)
     {
         dprintf("decode_sos: components(%d) mismatch\n", nb_components);
         return -1;
@@ -1602,7 +1747,7 @@
 
     predictor= get_bits(&s->gb, 8); /* JPEG Ss / lossless JPEG predictor /JPEG-LS NEAR */
     ilv= get_bits(&s->gb, 8);    /* JPEG Se / JPEG-LS ILV */
-    skip_bits(&s->gb, 4); /* Ah */
+    prev_shift = get_bits(&s->gb, 4); /* Ah */
     point_transform= get_bits(&s->gb, 4); /* Al */
 
     for(i=0;i<nb_components;i++)
@@ -1647,6 +1792,9 @@
                     return -1;
             }
         }
+    }else if(s->progressive){
+        if(mjpeg_decode_scan_progressive(s, nb_components, predictor, ilv, prev_shift, point_transform) < 0)
+            return -1;
     }else{
         if(mjpeg_decode_scan(s) < 0)
             return -1;
@@ -2037,17 +2185,26 @@
                     break;
                 case SOF0:
                     s->lossless=0;
+                    s->progressive=0;
                     if (mjpeg_decode_sof(s) < 0)
                         return -1;
                     break;
+                case SOF2:
+                    s->lossless=0;
+                    s->progressive=1;
+                    if (mjpeg_decode_sof(s) < 0)
+                        return -1;
+                    break;
                 case SOF3:
                     s->lossless=1;
+                    s->progressive=0;
                     if (mjpeg_decode_sof(s) < 0)
                         return -1;
                     break;
                 case SOF48:
                     s->lossless=1;
                     s->ls=1;
+                    s->progressive=0;
                     if (mjpeg_decode_sof(s) < 0)
                         return -1;
                     break;
@@ -2094,7 +2251,6 @@
                     mjpeg_decode_dri(s);
                     break;
                 case SOF1:
-                case SOF2:
                 case SOF5:
                 case SOF6:
                 case SOF7:



More information about the ffmpeg-devel mailing list