reworked decode_frame marker searching, fixes many non-working samples
authorAlex Beregszaszi <alex@rtfs.hu>
Sun, 27 Oct 2002 17:59:35 +0000 (17:59 +0000)
committerAlex Beregszaszi <alex@rtfs.hu>
Sun, 27 Oct 2002 17:59:35 +0000 (17:59 +0000)
Originally committed as revision 1079 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavcodec/mjpeg.c

index 0be897c..baaf8ad 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  * Support for external huffman table, various fixes (AVID workaround),
- * aspecting and various markers support
+ * aspecting and new decode_frame mechanism
  *                                  by Alex Beregszaszi <alex@naxine.org>
  */
-//#define DEBUG
+#define DEBUG
 #include "avcodec.h"
 #include "dsputil.h"
 #include "mpegvideo.h"
@@ -29,7 +29,7 @@
 #include "fastmemcpy.h"
 #endif
 
-/* use two quantizer table (one for luminance and one for chrominance) */
+/* use two quantizer tables (one for luminance and one for chrominance) */
 /* not yet working */
 #undef TWOMATRIXES
 
@@ -590,11 +590,12 @@ void mjpeg_encode_mb(MpegEncContext *s,
 typedef struct MJpegDecodeContext {
     AVCodecContext *avctx;
     GetBitContext gb;
-    UINT32 header_state;
+    int mpeg_enc_ctx_allocated; /* true if decoding context allocated */
+
     int start_code; /* current start code */
-    UINT8 *buf_ptr;
     int buffer_size;
-    int mpeg_enc_ctx_allocated; /* true if decoding context allocated */
+    UINT8 *buffer;
+
     INT16 quant_matrixes[4][64];
     VLC vlcs[2][4];
 
@@ -614,7 +615,6 @@ typedef struct MJpegDecodeContext {
     UINT8 *current_picture[MAX_COMPONENTS]; /* picture structure */
     int linesize[MAX_COMPONENTS];
     DCTELEM block[64] __align8;
-    UINT8 buffer[PICTURE_BUFFER_SIZE]; 
 
     int buggy_avid;
     int restart_interval;
@@ -624,13 +624,7 @@ typedef struct MJpegDecodeContext {
     void (*idct_put)(UINT8 *dest/*align 8*/, int line_size, DCTELEM *block/*align 16*/);
 } MJpegDecodeContext;
 
-#define SKIP_REMAINING(gb, len) { \
-    dprintf("reamining %d bytes in marker\n", len); \
-    if (len) while (--len) \
-       skip_bits(gb, 8); \
-}
-
-static int mjpeg_decode_dht(MJpegDecodeContext *s, UINT8 *buf, int buf_size);
+static int mjpeg_decode_dht(MJpegDecodeContext *s);
 
 static void build_vlc(VLC *vlc, const UINT8 *bits_table, const UINT8 *val_table, 
                       int nb_codes)
@@ -664,12 +658,11 @@ static int mjpeg_decode_init(AVCodecContext *avctx)
     s->idct_put= s2.idct_put;
     MPV_common_end(&s2);
 
-    s->header_state = 0;
     s->mpeg_enc_ctx_allocated = 0;
     s->buffer_size = PICTURE_BUFFER_SIZE - 1; /* minus 1 to take into
                                                  account FF 00 case */
+    s->buffer = av_malloc(s->buffer_size);
     s->start_code = -1;
-    s->buf_ptr = s->buffer;
     s->first_picture = 1;
     s->org_width = avctx->width;
     s->org_height = avctx->height;
@@ -678,22 +671,22 @@ static int mjpeg_decode_init(AVCodecContext *avctx)
     build_vlc(&s->vlcs[0][1], bits_dc_chrominance, val_dc_chrominance, 12);
     build_vlc(&s->vlcs[1][0], bits_ac_luminance, val_ac_luminance, 251);
     build_vlc(&s->vlcs[1][1], bits_ac_chrominance, val_ac_chrominance, 251);
-    
+
     if (avctx->flags & CODEC_FLAG_EXTERN_HUFF)
     {
        printf("mjpeg: using external huffman table\n");
-       mjpeg_decode_dht(s, avctx->extradata, avctx->extradata_size);
+       init_get_bits(&s->gb, avctx->extradata, avctx->extradata_size);
+       mjpeg_decode_dht(s);
        /* should check for error - but dunno */
     }
+
     return 0;
 }
 
 /* quantize tables */
-static int mjpeg_decode_dqt(MJpegDecodeContext *s,
-                            UINT8 *buf, int buf_size)
+static int mjpeg_decode_dqt(MJpegDecodeContext *s)
 {
     int len, index, i, j;
-    init_get_bits(&s->gb, buf, buf_size);
     
     len = get_bits(&s->gb, 16) - 2;
 
@@ -716,23 +709,17 @@ static int mjpeg_decode_dqt(MJpegDecodeContext *s,
         len -= 65;
     }
     
-    SKIP_REMAINING(&s->gb, len);
-
     return 0;
 }
 
 /* decode huffman tables and build VLC decoders */
-static int mjpeg_decode_dht(MJpegDecodeContext *s,
-                            UINT8 *buf, int buf_size)
+static int mjpeg_decode_dht(MJpegDecodeContext *s)
 {
     int len, index, i, class, n, v, code_max;
     UINT8 bits_table[17];
     UINT8 val_table[256];
     
-    init_get_bits(&s->gb, buf, buf_size);
-
-    len = get_bits(&s->gb, 16);
-    len -= 2;
+    len = get_bits(&s->gb, 16) - 2;
 
     while (len > 0) {
         if (len < 17)
@@ -770,13 +757,10 @@ static int mjpeg_decode_dht(MJpegDecodeContext *s,
     return 0;
 }
 
-static int mjpeg_decode_sof0(MJpegDecodeContext *s,
-                             UINT8 *buf, int buf_size)
+static int mjpeg_decode_sof0(MJpegDecodeContext *s)
 {
     int len, nb_components, i, width, height;
 
-    init_get_bits(&s->gb, buf, buf_size);
-
     /* XXX: verify len field validity */
     len = get_bits(&s->gb, 16);
     /* only 8 bits/component accepted */
@@ -851,8 +835,12 @@ static int mjpeg_decode_sof0(MJpegDecodeContext *s,
 static inline int mjpeg_decode_dc(MJpegDecodeContext *s, int dc_index)
 {
     int code, diff;
-
+#if 0
+    code = get_vlc2(&s->gb, s->vlc[0][dc_index].table,
+       s->vlc[0][dc_index].bits, 1);
+#else
     code = get_vlc(&s->gb, &s->vlcs[0][dc_index]);
+#endif
     if (code < 0)
     {
        dprintf("mjpeg_decode_dc: bad vlc: %d:%d (%p)\n", 0, dc_index,
@@ -892,7 +880,12 @@ static int decode_block(MJpegDecodeContext *s, DCTELEM *block,
     ac_vlc = &s->vlcs[1][ac_index];
     i = 1;
     for(;;) {
+#if 0
+       code = get_vlc2(&s->gb, s->vlcs[1][ac_index].table,
+           s->vlcs[1][ac_index].bits, 2);
+#else
         code = get_vlc(&s->gb, ac_vlc);
+#endif
         if (code < 0) {
             dprintf("error ac\n");
             return -1;
@@ -923,8 +916,7 @@ static int decode_block(MJpegDecodeContext *s, DCTELEM *block,
     return 0;
 }
 
-static int mjpeg_decode_sos(MJpegDecodeContext *s,
-                            UINT8 *buf, int buf_size)
+static int mjpeg_decode_sos(MJpegDecodeContext *s)
 {
     int len, nb_components, i, j, n, h, v, ret;
     int mb_width, mb_height, mb_x, mb_y, vmax, hmax, index, id;
@@ -935,10 +927,14 @@ static int mjpeg_decode_sos(MJpegDecodeContext *s,
     int h_count[4];
     int v_count[4];
     
-    init_get_bits(&s->gb, buf, buf_size);
     /* XXX: verify len field validity */
     len = get_bits(&s->gb, 16);
     nb_components = get_bits(&s->gb, 8);
+    if (len != 6+2*nb_components)
+    {
+       dprintf("decode_sos: invalid len (%d)\n", len);
+       return -1;
+    }
     /* XXX: only interleaved scan accepted */
     if (nb_components != 3)
     {
@@ -1061,11 +1057,8 @@ static int mjpeg_decode_sos(MJpegDecodeContext *s,
     return -1;
 }
 
-static int mjpeg_decode_dri(MJpegDecodeContext *s,
-                             UINT8 *buf, int buf_size)
+static int mjpeg_decode_dri(MJpegDecodeContext *s)
 {
-    init_get_bits(&s->gb, buf, buf_size);
-
     if (get_bits(&s->gb, 16) != 4)
        return -1;
     s->restart_interval = get_bits(&s->gb, 16);
@@ -1075,13 +1068,10 @@ static int mjpeg_decode_dri(MJpegDecodeContext *s,
 }
 
 #define FOURCC(a,b,c,d) ((a << 24) | (b << 16) | (c << 8) | d)
-static int mjpeg_decode_app(MJpegDecodeContext *s,
-                             UINT8 *buf, int buf_size, int start_code)
+static int mjpeg_decode_app(MJpegDecodeContext *s, int start_code)
 {
     int len, id;
 
-    init_get_bits(&s->gb, buf, buf_size);
-
     /* XXX: verify len field validity */
     len = get_bits(&s->gb, 16);
     if (len < 5)
@@ -1164,20 +1154,16 @@ static int mjpeg_decode_app(MJpegDecodeContext *s,
 
 out:
     /* should check for further values.. */
-    SKIP_REMAINING(&s->gb, len);
 
     return 0;
 }
 #undef FOURCC
 
-static int mjpeg_decode_com(MJpegDecodeContext *s,
-                             UINT8 *buf, int buf_size)
+static int mjpeg_decode_com(MJpegDecodeContext *s)
 {
     int len, i;
     UINT8 *cbuf;
 
-    init_get_bits(&s->gb, buf, buf_size);
-
     /* XXX: verify len field validity */
     len = get_bits(&s->gb, 16)-2;
     cbuf = av_malloc(len+1);
@@ -1195,8 +1181,8 @@ static int mjpeg_decode_com(MJpegDecodeContext *s,
     if (!strcmp(cbuf, "AVID"))
     {
        s->buggy_avid = 1;
-       if (s->first_picture)
-           printf("mjpeg: workarounding buggy AVID\n");
+//     if (s->first_picture)
+//         printf("mjpeg: workarounding buggy AVID\n");
     }
     
     av_free(cbuf);
@@ -1204,41 +1190,58 @@ static int mjpeg_decode_com(MJpegDecodeContext *s,
     return 0;
 }
 
+#if 0
+static int valid_marker_list[] =
+{
+        /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */
+/* 0 */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 1 */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 2 */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 3 */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 4 */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 5 */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 6 */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 7 */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 8 */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 9 */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* a */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* b */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* c */    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* d */    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* e */    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* f */    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
+}
+#endif
+
 /* return the 8 bit start code value and update the search
    state. Return -1 if no start code found */
-static int find_marker(UINT8 **pbuf_ptr, UINT8 *buf_end, 
-                       UINT32 *header_state)
+static int find_marker(UINT8 **pbuf_ptr, UINT8 *buf_end)
 {
     UINT8 *buf_ptr;
-    unsigned int state, v;
+    unsigned int v, v2;
     int val;
+#ifdef DEBUG
+    int skipped=0;
+#endif
 
-    state = *header_state;
     buf_ptr = *pbuf_ptr;
-retry:
-    if (state) {
-        /* get marker */
-    found:
-        if (buf_ptr < buf_end) {
-            val = *buf_ptr++;
-            state = 0;
-            if ((val >= RST0) && (val <= RST7))
-                goto retry;
-        } else {
-            val = -1;
-        }
-    } else {
-        while (buf_ptr < buf_end) {
-            v = *buf_ptr++;
-            if (v == 0xff) {
-                state = 1;
-                goto found;
-            }
+    while (buf_ptr < buf_end) {
+        v = *buf_ptr++;
+       v2 = *buf_ptr;
+        if ((v == 0xff) && (v2 >= 0xc0) && (v2 <= 0xfe)) {
+           val = *buf_ptr++;
+           goto found;
         }
-        val = -1;
+#ifdef DEBUG
+       skipped++;
+#endif
     }
+    val = -1;
+found:
+#ifdef DEBUG
+    dprintf("find_marker skipped %d bytes\n", skipped);
+#endif
     *pbuf_ptr = buf_ptr;
-    *header_state = state;
     return val;
 }
 
@@ -1247,10 +1250,9 @@ static int mjpeg_decode_frame(AVCodecContext *avctx,
                               UINT8 *buf, int buf_size)
 {
     MJpegDecodeContext *s = avctx->priv_data;
-    UINT8 *buf_end, *buf_ptr, *buf_start;
-    int len, code, input_size, i;
+    UINT8 *buf_end, *buf_ptr;
+    int i, start_code;
     AVPicture *picture = data;
-    unsigned int start_code;
 
     *data_size = 0;
 
@@ -1261,49 +1263,78 @@ static int mjpeg_decode_frame(AVCodecContext *avctx,
     buf_ptr = buf;
     buf_end = buf + buf_size;
     while (buf_ptr < buf_end) {
-        buf_start = buf_ptr;
         /* find start next marker */
-        code = find_marker(&buf_ptr, buf_end, &s->header_state);
-        /* copy to buffer */
-        len = buf_ptr - buf_start;
-        if (len + (s->buf_ptr - s->buffer) > s->buffer_size) {
-            /* data too big : flush */
-            s->buf_ptr = s->buffer;
-            if (code > 0)
-                s->start_code = code;
-        } else {
-            memcpy(s->buf_ptr, buf_start, len);
-            s->buf_ptr += len;
-            if (code < 0) {
-                /* nothing to do: wait next marker */
-            } else if (code == 0 || code == 0xff) {
-                /* if we got FF 00, we copy FF to the stream to unescape FF 00 */
-                /* valid marker code is between 00 and ff - alex */
-                s->buf_ptr--;
+        start_code = find_marker(&buf_ptr, buf_end);
+       {
+           /* EOF */
+            if (start_code < 0) {
+               goto the_end;
             } else {
-                /* prepare data for next start code */
-                input_size = s->buf_ptr - s->buffer;
-                start_code = s->start_code;
-                s->buf_ptr = s->buffer;
-                s->start_code = code;
-                dprintf("marker=%x\n", start_code);
+                dprintf("marker=%x avail_size_in_buf=%d\n", start_code, buf_end - buf_ptr);
+               
+               if ((buf_end - buf_ptr) > s->buffer_size)
+               {
+                   av_free(s->buffer);
+                   s->buffer_size = buf_end-buf_ptr;
+                   s->buffer = av_malloc(s->buffer_size);
+               }
+               
+               /* unescape buffer of SOS */
+               if (start_code == SOS)
+               {
+                   UINT8 *src = buf_ptr;
+                   UINT8 *dst = s->buffer;
+
+                   while (src<buf_end)
+                   {
+                       unsigned char *x = *(src++);
+                       
+                       *(dst++) = x;
+                       if (x == 0xff)
+                       {
+                           x = *(src++);
+                           if (x >= 0xd0 && x <= 0xd7)
+                               *(dst++) = x;
+                           else if (x)
+                               break;
+                       }
+                   }
+               }
+               else
+                   memcpy(s->buffer, buf_ptr, buf_end - buf_ptr);
+               init_get_bits(&s->gb, s->buffer, s->buffer_size);
+               
+               s->start_code = start_code;
+
+               /* process markers */
+               if (start_code >= 0xd0 && start_code <= 0xd7) {
+                   dprintf("restart marker: %d\n", start_code&0x0f);
+               } else if (s->first_picture) {
+                   /* APP fields */
+                   if (start_code >= 0xe0 && start_code <= 0xef)
+                       mjpeg_decode_app(s, start_code);
+                   /* Comment */
+                   else if (start_code == COM)
+                       mjpeg_decode_com(s);
+               }
+
                 switch(start_code) {
                 case SOI:
                    s->restart_interval = 0;
                     /* nothing to do on SOI */
                     break;
                 case DQT:
-                    mjpeg_decode_dqt(s, s->buffer, input_size);
+                    mjpeg_decode_dqt(s);
                     break;
                 case DHT:
-                    mjpeg_decode_dht(s, s->buffer, input_size);
+                    mjpeg_decode_dht(s);
                     break;
                 case SOF0:
-                    mjpeg_decode_sof0(s, s->buffer, input_size);
+                    mjpeg_decode_sof0(s);
                     break;
-                case SOS:
-                    mjpeg_decode_sos(s, s->buffer, input_size);
-                    if (s->start_code == EOI || s->buggy_avid || s->restart_interval) {
+               case EOI:
+eoi_parser:
+                   {
                         int l;
                         if (s->interlaced) {
                             s->bottom_field ^= 1;
@@ -1313,10 +1344,15 @@ static int mjpeg_decode_frame(AVCodecContext *avctx,
                         }
                         for(i=0;i<3;i++) {
                             picture->data[i] = s->current_picture[i];
+#if 1
                             l = s->linesize[i];
                             if (s->interlaced)
                                 l >>= 1;
                             picture->linesize[i] = l;
+#else
+                           picture->linesize[i] = (s->interlaced) ?
+                               s->linesize[i] >> 1 : s->linesize[i];
+#endif
                         }
                         *data_size = sizeof(AVPicture);
                         avctx->height = s->height;
@@ -1341,9 +1377,16 @@ static int mjpeg_decode_frame(AVCodecContext *avctx,
                        avctx->quality = 3; 
                         goto the_end;
                     }
+                   break;
+                case SOS:
+                    mjpeg_decode_sos(s);
+                   /* buggy avid puts EOI every 10-20th frame */
+                   /* if restart period is over process EOI */
+                   if ((s->buggy_avid && !s->interlaced) || s->restart_interval)
+                       goto eoi_parser;
                     break;
                case DRI:
-                   mjpeg_decode_dri(s, s->buffer, input_size);
+                   mjpeg_decode_dri(s);
                    break;
                case SOF1:
                case SOF2:
@@ -1359,26 +1402,24 @@ static int mjpeg_decode_frame(AVCodecContext *avctx,
                case SOF15:
                case JPG:
                    printf("mjpeg: unsupported coding type (%x)\n", start_code);
-                   return -1;
+                   break;
+//             default:
+//                 printf("mjpeg: unsupported marker (%x)\n", start_code);
+//                 break;
                 }
-#if 1
-               if (start_code >= 0xd0 && start_code <= 0xd7) {
-                   dprintf("restart marker: %d\n", start_code&0x0f);
-               } else if (s->first_picture) {
-                   /* APP fields */
-                   if (start_code >= 0xe0 && start_code <= 0xef)
-                       mjpeg_decode_app(s, s->buffer, input_size, start_code);
-                   /* Comment */
-                   else if (start_code == COM)
-                       mjpeg_decode_com(s, s->buffer, input_size);
-               }
-#endif
+
+not_the_end:
+               /* eof process start code */
+               buf_ptr += (get_bits_count(&s->gb)+7)/8;
+               dprintf("marker parser used %d bytes (%d bits)\n",
+                   (get_bits_count(&s->gb)+7)/8, get_bits_count(&s->gb));
             }
         }
- not_the_end:
-       ;
     }
- the_end:
+the_end:
+
+    dprintf("mjpeg decode frame unused %d bytes\n", buf_end - buf_ptr);
+//    return buf_end - buf_ptr;
     return buf_ptr - buf;
 }
 
@@ -1387,6 +1428,7 @@ static int mjpeg_decode_end(AVCodecContext *avctx)
     MJpegDecodeContext *s = avctx->priv_data;
     int i, j;
 
+    av_free(s->buffer);
     for(i=0;i<MAX_COMPONENTS;i++)
         av_free(s->current_picture[i]);
     for(i=0;i<2;i++) {