diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2003-06-15 00:15:57 +0000 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2003-06-15 00:15:57 +0000 |
commit | e4d2b1f39a44498d5a56de5dc08a8f11051365c9 (patch) | |
tree | 989b9fa229df1438fc5f89ad47155b838117d4a9 | |
parent | 31319a8ccddca74b178a411232865d78c5f4e985 (diff) | |
download | ffmpeg-e4d2b1f39a44498d5a56de5dc08a8f11051365c9.tar.gz |
lossless jpeg decoding support
Originally committed as revision 1959 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r-- | libavcodec/mjpeg.c | 220 |
1 files changed, 200 insertions, 20 deletions
diff --git a/libavcodec/mjpeg.c b/libavcodec/mjpeg.c index 83be2c875c..f6f735d371 100644 --- a/libavcodec/mjpeg.c +++ b/libavcodec/mjpeg.c @@ -27,6 +27,8 @@ */ //#define DEBUG +#include <assert.h> + #include "avcodec.h" #include "dsputil.h" #include "mpegvideo.h" @@ -279,6 +281,20 @@ void mjpeg_close(MpegEncContext *s) av_free(s->mjpeg_ctx); } +static inline int predict(uint8_t *ptr, int stride, int predictor, int size){ + switch(predictor){ + case 0: return ptr[0]; + case 1: return ptr[-size]; + case 2: return ptr[-stride]; + case 3: return ptr[-stride-size]; + case 4: return ptr[-size] + ptr[-stride] - ptr[-stride-size]; + case 5: return ptr[-size] + ((ptr[-stride] - ptr[-stride-size])>>1); + case 6: return ptr[-stride] + ((ptr[-size] - ptr[-stride-size])>>1); + case 7: return (ptr[-size] + ptr[-stride])>>1; + default: return 0xFFFF; + } +} + static inline void put_marker(PutBitContext *p, int code) { put_bits(p, 8, 0xff); @@ -653,6 +669,8 @@ typedef struct MJpegDecodeContext { int first_picture; /* true if decoding first picture */ int interlaced; /* true if interlaced */ int bottom_field; /* true if bottom field */ + int lossless; + int rgb; int width, height; int nb_components; @@ -810,15 +828,16 @@ static int mjpeg_decode_dht(MJpegDecodeContext *s) return 0; } -static int mjpeg_decode_sof0(MJpegDecodeContext *s) +static int mjpeg_decode_sof(MJpegDecodeContext *s) { int len, nb_components, i, width, height; /* XXX: verify len field validity */ len = get_bits(&s->gb, 16); - /* only 8 bits/component accepted */ - if (get_bits(&s->gb, 8) != 8) + if (get_bits(&s->gb, 8) != 8){ + printf("only 8 bits/component accepted\n"); return -1; + } height = get_bits(&s->gb, 16); width = get_bits(&s->gb, 16); dprintf("sof0: picture: %dx%d\n", width, height); @@ -863,7 +882,18 @@ static int mjpeg_decode_sof0(MJpegDecodeContext *s) s->bottom_field = 0; } - for(i=0;i<nb_components;i++) { + assert(s->rgb==0 || (s->h_max==1 && s->v_max==1)); + if(s->rgb){ + int w, h; + w = s->width; + h = s->height; + if (s->interlaced) + w *= 2; + s->linesize[0] = 4*w; + s->current_picture[0] = av_mallocz(4*w * h); + s->current_picture[1] = s->current_picture[2] = NULL; + }else{ + for(i=0;i<nb_components;i++) { int w, h; w = (s->width + 8 * s->h_max - 1) / (8 * s->h_max); h = (s->height + 8 * s->v_max - 1) / (8 * s->v_max); @@ -878,6 +908,7 @@ static int mjpeg_decode_sof0(MJpegDecodeContext *s) dprintf("error: no picture buffers allocated\n"); return -1; } + } } s->first_picture = 0; } @@ -957,9 +988,12 @@ static int decode_block(MJpegDecodeContext *s, DCTELEM *block, return 0; } +static void decode_lossless(MJpegDecodeContext *s, int point_transform, int predictor){ +} + static int mjpeg_decode_sos(MJpegDecodeContext *s) { - int len, nb_components, i, j, n, h, v, ret; + int len, nb_components, i, j, n, h, v, ret, point_transform, predictor; int mb_width, mb_height, mb_x, mb_y, vmax, hmax, index, id; int comp_index[4]; int dc_index[4]; @@ -967,7 +1001,8 @@ static int mjpeg_decode_sos(MJpegDecodeContext *s) int nb_blocks[4]; int h_count[4]; int v_count[4]; - + const int block_size= s->lossless ? 1 : 8; + /* XXX: verify len field validity */ len = get_bits(&s->gb, 16); nb_components = get_bits(&s->gb, 8); @@ -1025,29 +1060,165 @@ static int mjpeg_decode_sos(MJpegDecodeContext *s) break; } } - skip_bits(&s->gb, 8); /* Ss */ + predictor= get_bits(&s->gb, 8); /* lossless predictor or start of spectral (Ss) */ skip_bits(&s->gb, 8); /* Se */ - skip_bits(&s->gb, 8); /* Ah and Al (each are 4 bits) */ + skip_bits(&s->gb, 4); /* Ah */ + point_transform= get_bits(&s->gb, 4); /* Al */ for(i=0;i<nb_components;i++) s->last_dc[i] = 1024; if (nb_components > 1) { /* interleaved stream */ - mb_width = (s->width + s->h_max * 8 - 1) / (s->h_max * 8); - mb_height = (s->height + s->v_max * 8 - 1) / (s->v_max * 8); + mb_width = (s->width + s->h_max * block_size - 1) / (s->h_max * block_size); + mb_height = (s->height + s->v_max * block_size - 1) / (s->v_max * block_size); } else { h = s->h_max / s->h_count[comp_index[0]]; v = s->v_max / s->v_count[comp_index[0]]; - mb_width = (s->width + h * 8 - 1) / (h * 8); - mb_height = (s->height + v * 8 - 1) / (v * 8); + mb_width = (s->width + h * block_size - 1) / (h * block_size); + mb_height = (s->height + v * block_size - 1) / (v * block_size); nb_blocks[0] = 1; h_count[0] = 1; v_count[0] = 1; } - - for(mb_y = 0; mb_y < mb_height; mb_y++) { + + if(s->lossless){ + if(s->rgb){ //FIXME cleanup + const int linesize= s->linesize[0]; + for(mb_y = 0; mb_y < mb_height; mb_y++) { + for(mb_x = 0; mb_x < mb_width; mb_x++) { + if (s->restart_interval && !s->restart_count) + s->restart_count = s->restart_interval; + + if(mb_x==0 || mb_y==0 || s->interlaced || 1){ + for(i=0;i<3;i++) { + uint8_t *ptr; + int c, pred; + c = comp_index[i]; + + ptr = s->current_picture[0] + (linesize * mb_y) + 4*mb_x + c; //FIXME optimize this crap + if(mb_y==0){ + if(mb_x==0){ + pred= 128 << point_transform; + }else{ + pred= ptr[-4]; + } + }else{ + if(mb_x==0){ + pred= ptr[-linesize]; + }else{ + pred= predict(ptr, linesize, predictor, 4); + } + } + if (s->interlaced && s->bottom_field) + ptr += linesize >> 1; + *ptr= pred + (mjpeg_decode_dc(s, dc_index[i]) << point_transform); + } + }else{ + for(i=0;i<3;i++) { + uint8_t *ptr; + int c, pred; + c = comp_index[i]; + + ptr = s->current_picture[0] + (linesize * mb_y) + 4*mb_x + c; //FIXME optimize this crap + pred= predict(ptr, linesize, predictor, 4); + *ptr= pred + (mjpeg_decode_dc(s, dc_index[i]) << point_transform); + } + } + /* (< 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 */ + } + } + } + }else{ + for(mb_y = 0; mb_y < mb_height; mb_y++) { + for(mb_x = 0; mb_x < mb_width; mb_x++) { + if (s->restart_interval && !s->restart_count) + s->restart_count = s->restart_interval; + + if(mb_x==0 || mb_y==0 || s->interlaced || 1){ + for(i=0;i<nb_components;i++) { + uint8_t *ptr; + int x, y, c, linesize; + n = nb_blocks[i]; + c = comp_index[i]; + h = h_count[i]; + v = v_count[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{ + pred= predict(ptr, linesize, predictor, 1); + } + } + + if (s->interlaced && s->bottom_field) + ptr += linesize >> 1; + *ptr= pred + (mjpeg_decode_dc(s, dc_index[i]) << point_transform); + + if (++x == h) { + x = 0; + y++; + } + } + } + }else{ + for(i=0;i<nb_components;i++) { + uint8_t *ptr; + int x, y, c, linesize; + n = nb_blocks[i]; + c = comp_index[i]; + h = h_count[i]; + v = v_count[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 + pred= predict(ptr, linesize, predictor, 1); + *ptr= pred + (mjpeg_decode_dc(s, dc_index[i]) << point_transform); + 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 */ + } + } + } + } + }else{ + for(mb_y = 0; mb_y < mb_height; mb_y++) { for(mb_x = 0; mb_x < 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 x, y, c; @@ -1057,8 +1228,6 @@ static int mjpeg_decode_sos(MJpegDecodeContext *s) v = v_count[i]; x = 0; y = 0; - if (s->restart_interval && !s->restart_count) - s->restart_count = s->restart_interval; for(j=0;j<n;j++) { memset(s->block, 0, sizeof(s->block)); if (decode_block(s, s->block, i, @@ -1091,6 +1260,7 @@ static int mjpeg_decode_sos(MJpegDecodeContext *s) } } } + } ret = 0; the_end: emms_c(); @@ -1418,7 +1588,15 @@ static int mjpeg_decode_frame(AVCodecContext *avctx, mjpeg_decode_dht(s); break; case SOF0: - if (mjpeg_decode_sof0(s) < 0) + s->lossless=0; + s->rgb=0; + if (mjpeg_decode_sof(s) < 0) + return -1; + break; + case SOF3: + s->lossless=1; + s->rgb=1; //FIXME + if (mjpeg_decode_sof(s) < 0) return -1; break; case EOI: @@ -1443,7 +1621,10 @@ eoi_parser: /* XXX: not complete test ! */ switch((s->h_count[0] << 4) | s->v_count[0]) { case 0x11: - avctx->pix_fmt = PIX_FMT_YUV444P; + if(s->rgb){ + avctx->pix_fmt = PIX_FMT_RGBA32; + }else + avctx->pix_fmt = PIX_FMT_YUV444P; break; case 0x21: avctx->pix_fmt = PIX_FMT_YUV422P; @@ -1471,7 +1652,6 @@ eoi_parser: break; case SOF1: case SOF2: - case SOF3: case SOF5: case SOF6: case SOF7: @@ -1570,7 +1750,7 @@ read_header: { init_get_bits(&s->gb, buf+sof_offs, (buf_end - (buf+sof_offs))*8); s->start_code = SOF0; - if (mjpeg_decode_sof0(s) < 0) + if (mjpeg_decode_sof(s) < 0) return -1; } |