# HG changeset patch # User al3x # Date 1035741575 0 # Node ID e96776e1d2aee2b4b9a6faaf627ab1fcf5c0f845 # Parent baa66649df35322a8263b08320bc60fd40ae2c2d reworked decode_frame marker searching, fixes many non-working samples diff -r baa66649df35 -r e96776e1d2ae mjpeg.c --- a/mjpeg.c Sun Oct 27 12:20:58 2002 +0000 +++ b/mjpeg.c Sun Oct 27 17:59:35 2002 +0000 @@ -17,10 +17,10 @@ * 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 */ -//#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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } #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 @@ 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 @@ 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 @@ 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; + while (buf_ptr < buf_end) { + v = *buf_ptr++; + v2 = *buf_ptr; + if ((v == 0xff) && (v2 >= 0xc0) && (v2 <= 0xfe)) { + val = *buf_ptr++; + goto found; } - } else { - while (buf_ptr < buf_end) { - v = *buf_ptr++; - if (v == 0xff) { - state = 1; - 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 @@ 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 @@ 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= 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 @@ } 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 @@ 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 @@ 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 @@ MJpegDecodeContext *s = avctx->priv_data; int i, j; + av_free(s->buffer); for(i=0;icurrent_picture[i]); for(i=0;i<2;i++) {