* Copyright (c) 2003 Alex Beregszaszi
* Copyright (c) 2003-2004 Michael Niedermayer
*
+ * Support for external huffman table, various fixes (AVID workaround),
+ * aspecting, new decode_frame mechanism and apple mjpeg-b support
+ * by Alex Beregszaszi
+ *
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Support for external huffman table, various fixes (AVID workaround),
- * aspecting, new decode_frame mechanism and apple mjpeg-b support
- * by Alex Beregszaszi
*/
/**
#include "jpeglsdec.h"
-static int mjpeg_decode_dht(MJpegDecodeContext *s);
-
static int build_vlc(VLC *vlc, const uint8_t *bits_table, const uint8_t *val_table,
int nb_codes, int use_static, int is_ac)
{
return init_vlc(vlc, 9, nb_codes, huff_size, 1, 1, huff_code, 2, 2, use_static);
}
-int ff_mjpeg_decode_init(AVCodecContext *avctx)
+static void build_basic_mjpeg_vlc(MJpegDecodeContext * s) {
+ build_vlc(&s->vlcs[0][0], ff_mjpeg_bits_dc_luminance,
+ ff_mjpeg_val_dc, 12, 0, 0);
+ build_vlc(&s->vlcs[0][1], ff_mjpeg_bits_dc_chrominance,
+ ff_mjpeg_val_dc, 12, 0, 0);
+ build_vlc(&s->vlcs[1][0], ff_mjpeg_bits_ac_luminance,
+ ff_mjpeg_val_ac_luminance, 251, 0, 1);
+ build_vlc(&s->vlcs[1][1], ff_mjpeg_bits_ac_chrominance,
+ ff_mjpeg_val_ac_chrominance, 251, 0, 1);
+}
+
+av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx)
{
MJpegDecodeContext *s = avctx->priv_data;
s->first_picture = 1;
s->org_height = avctx->coded_height;
- build_vlc(&s->vlcs[0][0], ff_mjpeg_bits_dc_luminance,
- ff_mjpeg_val_dc_luminance, 12, 0, 0);
- build_vlc(&s->vlcs[0][1], ff_mjpeg_bits_dc_chrominance,
- ff_mjpeg_val_dc_chrominance, 12, 0, 0);
- build_vlc(&s->vlcs[1][0], ff_mjpeg_bits_ac_luminance,
- ff_mjpeg_val_ac_luminance, 251, 0, 1);
- build_vlc(&s->vlcs[1][1], ff_mjpeg_bits_ac_chrominance,
- ff_mjpeg_val_ac_chrominance, 251, 0, 1);
+ build_basic_mjpeg_vlc(s);
if (avctx->flags & CODEC_FLAG_EXTERN_HUFF)
{
av_log(avctx, AV_LOG_INFO, "mjpeg: using external huffman table\n");
init_get_bits(&s->gb, avctx->extradata, avctx->extradata_size*8);
- mjpeg_decode_dht(s);
- /* should check for error - but dunno */
+ if (ff_mjpeg_decode_dht(s)) {
+ av_log(avctx, AV_LOG_ERROR, "mjpeg: error using external huffman table, switching back to internal\n");
+ build_basic_mjpeg_vlc(s);
+ }
}
if (avctx->extradata_size > 9 &&
AV_RL32(avctx->extradata + 4) == MKTAG('f','i','e','l')) {
/* quantize tables */
-static int mjpeg_decode_dqt(MJpegDecodeContext *s)
+int ff_mjpeg_decode_dqt(MJpegDecodeContext *s)
{
int len, index, i, j;
}
/* decode huffman tables and build VLC decoders */
-static int mjpeg_decode_dht(MJpegDecodeContext *s)
+int ff_mjpeg_decode_dht(MJpegDecodeContext *s)
{
int len, index, i, class, n, v, code_max;
uint8_t bits_table[17];
return 0;
}
-static int mjpeg_decode_sof(MJpegDecodeContext *s)
+int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
{
int len, nb_components, i, width, height, pix_fmt_id;
return 0;
/* XXX: not complete test ! */
- pix_fmt_id = (s->h_count[0] << 20) | (s->v_count[0] << 16) |
- (s->h_count[1] << 12) | (s->v_count[1] << 8) |
- (s->h_count[2] << 4) | s->v_count[2];
+ pix_fmt_id = (s->h_count[0] << 28) | (s->v_count[0] << 24) |
+ (s->h_count[1] << 20) | (s->v_count[1] << 16) |
+ (s->h_count[2] << 12) | (s->v_count[2] << 8) |
+ (s->h_count[3] << 4) | s->v_count[3];
av_log(s->avctx, AV_LOG_DEBUG, "pix fmt id %x\n", pix_fmt_id);
+ if(!(pix_fmt_id & 0x10101010))
+ pix_fmt_id-= (pix_fmt_id & 0xF0F0F0F0)>>1;
+ if(!(pix_fmt_id & 0x01010101))
+ pix_fmt_id-= (pix_fmt_id & 0x0F0F0F0F)>>1;
+
switch(pix_fmt_id){
- case 0x222222:
- case 0x111111:
+ case 0x11111100:
if(s->rgb){
s->avctx->pix_fmt = PIX_FMT_RGB32;
- }else if(s->nb_components==3)
+ }else
s->avctx->pix_fmt = s->cs_itu601 ? PIX_FMT_YUV444P : PIX_FMT_YUVJ444P;
- else
- s->avctx->pix_fmt = PIX_FMT_GRAY8;
+ assert(s->nb_components==3);
+ break;
+ case 0x11000000:
+ s->avctx->pix_fmt = PIX_FMT_GRAY8;
break;
- case 0x211111:
- case 0x221212:
+ case 0x12111100:
+ s->avctx->pix_fmt = s->cs_itu601 ? PIX_FMT_YUV440P : PIX_FMT_YUVJ440P;
+ break;
+ case 0x21111100:
s->avctx->pix_fmt = s->cs_itu601 ? PIX_FMT_YUV422P : PIX_FMT_YUVJ422P;
break;
- default:
- case 0x221111:
+ case 0x22111100:
s->avctx->pix_fmt = s->cs_itu601 ? PIX_FMT_YUV420P : PIX_FMT_YUVJ420P;
break;
+ default:
+ av_log(s->avctx, AV_LOG_ERROR, "Unhandled pixel format 0x%x\n", pix_fmt_id);
+ return -1;
}
if(s->ls){
if(s->nb_components > 1)
av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return -1;
}
- s->picture.pict_type= I_TYPE;
+ s->picture.pict_type= FF_I_TYPE;
s->picture.key_frame= 1;
for(i=0; i<3; i++){
/* 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]));
+ int bw = (width + s->h_max*8-1) / (s->h_max*8);
+ int bh = (height + s->v_max*8-1) / (s->v_max*8);
+ for(i=0; i<s->nb_components; i++) {
+ int size = bw * bh * s->h_count[i] * s->v_count[i];
+ av_freep(&s->blocks[i]);
+ av_freep(&s->last_nnz[i]);
+ s->blocks[i] = av_malloc(size * sizeof(**s->blocks));
+ s->last_nnz[i] = av_mallocz(size * sizeof(**s->last_nnz));
+ s->block_stride[i] = bw * s->h_count[i];
+ }
+ memset(s->coefs_finished, 0, sizeof(s->coefs_finished));
}
return 0;
}
return 0;
}
+static int decode_dc_progressive(MJpegDecodeContext *s, DCTELEM *block, int component,
+ int dc_index, int16_t *quant_matrix, int Al)
+{
+ int val;
+ s->dsp.clear_block(block);
+ val = mjpeg_decode_dc(s, dc_index);
+ if (val == 0xffff) {
+ av_log(s->avctx, AV_LOG_ERROR, "error dc\n");
+ return -1;
+ }
+ val = (val * quant_matrix[0] << Al) + s->last_dc[component];
+ s->last_dc[component] = val;
+ block[0] = val;
+ 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)
+static int decode_block_progressive(MJpegDecodeContext *s, DCTELEM *block, uint8_t *last_nnz,
+ int ac_index, int16_t *quant_matrix,
+ int ss, int se, int Al, int *EOBRUN)
{
int code, i, j, level, val, run;
- /* DC coef */
- if(!ss){
- val = mjpeg_decode_dc(s, dc_index);
- if (val == 0xffff) {
- av_log(s->avctx, AV_LOG_ERROR, "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;
}
}
CLOSE_READER(re, &s->gb)}
+ if(i > *last_nnz)
+ *last_nnz = i;
+ return 0;
+}
+
+#define REFINE_BIT(j) {\
+ UPDATE_CACHE(re, &s->gb);\
+ sign = block[j]>>15;\
+ block[j] += SHOW_UBITS(re, &s->gb, 1) * ((quant_matrix[j]^sign)-sign) << Al;\
+ LAST_SKIP_BITS(re, &s->gb, 1);\
+}
+
+#define ZERO_RUN \
+for(;;i++) {\
+ if(i > last) {\
+ i += run;\
+ if(i > se) {\
+ av_log(s->avctx, AV_LOG_ERROR, "error count: %d\n", i);\
+ return -1;\
+ }\
+ break;\
+ }\
+ j = s->scantable.permutated[i];\
+ if(block[j])\
+ REFINE_BIT(j)\
+ else if(run-- == 0)\
+ break;\
+}
+
+/* decode block and dequantize - progressive JPEG refinement pass */
+static int decode_block_refinement(MJpegDecodeContext *s, DCTELEM *block, uint8_t *last_nnz,
+ int ac_index, int16_t *quant_matrix,
+ int ss, int se, int Al, int *EOBRUN)
+{
+ int code, i=ss, j, sign, val, run;
+ int last = FFMIN(se, *last_nnz);
+
+ OPEN_READER(re, &s->gb);
+ if(*EOBRUN)
+ (*EOBRUN)--;
+ else {
+ for(;;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) {
+ run = ((unsigned) code) >> 4;
+ UPDATE_CACHE(re, &s->gb);
+ val = SHOW_UBITS(re, &s->gb, 1);
+ LAST_SKIP_BITS(re, &s->gb, 1);
+ ZERO_RUN;
+ j = s->scantable.permutated[i];
+ val--;
+ block[j] = ((quant_matrix[j]^val)-val) << Al;
+ if(i == se) {
+ if(i > *last_nnz)
+ *last_nnz = i;
+ CLOSE_READER(re, &s->gb)
+ return 0;
+ }
+ }else{
+ run = ((unsigned) code) >> 4;
+ if(run == 0xF){
+ ZERO_RUN;
+ }else{
+ val = run;
+ run = (1 << run);
+ if(val) {
+ UPDATE_CACHE(re, &s->gb);
+ run += SHOW_UBITS(re, &s->gb, val);
+ LAST_SKIP_BITS(re, &s->gb, val);
+ }
+ *EOBRUN = run - 1;
+ break;
+ }
+ }
+ }
+
+ if(i > *last_nnz)
+ *last_nnz = i;
+ }
+
+ for(;i<=last;i++) {
+ j = s->scantable.permutated[i];
+ if(block[j])
+ REFINE_BIT(j)
+ }
+ CLOSE_READER(re, &s->gb);
return 0;
}
+#undef REFINE_BIT
+#undef ZERO_RUN
static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s, int predictor, int point_transform){
int i, mb_x, mb_y;
return 0;
}
-static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int ss, int se, int Ah, int Al){
+static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah, int Al){
int i, mb_x, mb_y;
- int EOBRUN = 0;
+ uint8_t* data[MAX_COMPONENTS];
+ int linesize[MAX_COMPONENTS];
+
+ for(i=0; i < nb_components; i++) {
+ int c = s->comp_index[i];
+ data[c] = s->picture.data[c];
+ linesize[c]=s->linesize[c];
+ s->coefs_finished[c] |= 1;
+ if(s->avctx->codec->id==CODEC_ID_AMV) {
+ //picture should be flipped upside-down for this codec
+ assert(!(s->avctx->flags & CODEC_FLAG_EMU_EDGE));
+ data[c] += (linesize[c] * (s->v_scount[i] * (8 * s->mb_height -((s->height/s->v_max)&7)) - 1 ));
+ linesize[c] *= -1;
+ }
+ }
- if(Ah) return 0; /* TODO decode refinement planes too */
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)
x = 0;
y = 0;
for(j=0;j<n;j++) {
- memset(s->block, 0, sizeof(s->block));
- if (!s->progressive && decode_block(s, s->block, i,
+ ptr = data[c] +
+ (((linesize[c] * (v * mb_y + y) * 8) +
+ (h * mb_x + x) * 8) >> s->avctx->lowres);
+ if(s->interlaced && s->bottom_field)
+ ptr += linesize[c] >> 1;
+ if(!s->progressive) {
+ s->dsp.clear_block(s->block);
+ if(decode_block(s, s->block, i,
s->dc_index[i], s->ac_index[i],
s->quant_matrixes[ s->quant_index[c] ]) < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "error y=%d x=%d\n", mb_y, mb_x);
- return -1;
- }
- if (s->progressive && 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) {
- av_log(s->avctx, AV_LOG_ERROR, "error y=%d x=%d\n", mb_y, mb_x);
- return -1;
+ av_log(s->avctx, AV_LOG_ERROR, "error y=%d x=%d\n", mb_y, mb_x);
+ return -1;
+ }
+ s->dsp.idct_put(ptr, linesize[c], s->block);
+ } else {
+ int block_idx = s->block_stride[c] * (v * mb_y + y) + (h * mb_x + x);
+ DCTELEM *block = s->blocks[c][block_idx];
+ if(Ah)
+ block[0] += get_bits1(&s->gb) * s->quant_matrixes[ s->quant_index[c] ][0] << Al;
+ else if(decode_dc_progressive(s, block, i, s->dc_index[i], s->quant_matrixes[ s->quant_index[c] ], Al) < 0) {
+ av_log(s->avctx, AV_LOG_ERROR, "error y=%d x=%d\n", mb_y, mb_x);
+ return -1;
+ }
}
// av_log(s->avctx, AV_LOG_DEBUG, "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);
- if(!s->progressive)
- s->dsp.idct_put(ptr, s->linesize[c], s->block);
- else
- s->dsp.idct_add(ptr, s->linesize[c], s->block);
if (++x == h) {
x = 0;
y++;
return 0;
}
-static int mjpeg_decode_sos(MJpegDecodeContext *s)
+static int mjpeg_decode_scan_progressive_ac(MJpegDecodeContext *s, int ss, int se, int Ah, int Al){
+ int mb_x, mb_y;
+ int EOBRUN = 0;
+ int c = s->comp_index[0];
+ uint8_t* data = s->picture.data[c];
+ int linesize = s->linesize[c];
+ int last_scan = 0;
+ int16_t *quant_matrix = s->quant_matrixes[ s->quant_index[c] ];
+
+ if(!Al) {
+ s->coefs_finished[c] |= (1LL<<(se+1))-(1LL<<ss);
+ last_scan = !~s->coefs_finished[c];
+ }
+
+ if(s->interlaced && s->bottom_field)
+ data += linesize >> 1;
+
+ for(mb_y = 0; mb_y < s->mb_height; mb_y++) {
+ uint8_t *ptr = data + (mb_y*linesize*8 >> s->avctx->lowres);
+ int block_idx = mb_y * s->block_stride[c];
+ DCTELEM (*block)[64] = &s->blocks[c][block_idx];
+ uint8_t *last_nnz = &s->last_nnz[c][block_idx];
+ for(mb_x = 0; mb_x < s->mb_width; mb_x++, block++, last_nnz++) {
+ int ret;
+ if(Ah)
+ ret = decode_block_refinement(s, *block, last_nnz, s->ac_index[0],
+ quant_matrix, ss, se, Al, &EOBRUN);
+ else
+ ret = decode_block_progressive(s, *block, last_nnz, s->ac_index[0],
+ quant_matrix, ss, se, Al, &EOBRUN);
+ if(ret < 0) {
+ av_log(s->avctx, AV_LOG_ERROR, "error y=%d x=%d\n", mb_y, mb_x);
+ return -1;
+ }
+ if(last_scan) {
+ s->dsp.idct_put(ptr, linesize, *block);
+ ptr += 8 >> s->avctx->lowres;
+ }
+ }
+ }
+ return 0;
+}
+
+int ff_mjpeg_decode_sos(MJpegDecodeContext *s)
{
int len, nb_components, i, h, v, predictor, point_transform;
int vmax, hmax, index, id;
// for(){
// reset_ls_coding_parameters(s, 0);
- ff_jpegls_decode_picture(s, predictor, point_transform, ilv);
+ if(ff_jpegls_decode_picture(s, predictor, point_transform, ilv) < 0)
+ return -1;
}else{
if(s->rgb){
if(ljpeg_decode_rgb_scan(s, predictor, point_transform) < 0)
}
}
}else{
- if(mjpeg_decode_scan(s, nb_components, predictor, ilv, prev_shift, point_transform) < 0)
- return -1;
+ if(s->progressive && predictor) {
+ if(mjpeg_decode_scan_progressive_ac(s, predictor, ilv, prev_shift, point_transform) < 0)
+ return -1;
+ } else {
+ if(mjpeg_decode_scan(s, nb_components, prev_shift, point_transform) < 0)
+ return -1;
+ }
}
emms_c();
return 0;
/* return the 8 bit start code value and update the search
state. Return -1 if no start code found */
-static int find_marker(uint8_t **pbuf_ptr, uint8_t *buf_end)
+static int find_marker(const uint8_t **pbuf_ptr, const uint8_t *buf_end)
{
- uint8_t *buf_ptr;
+ const uint8_t *buf_ptr;
unsigned int v, v2;
int val;
#ifdef DEBUG
int ff_mjpeg_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
- uint8_t *buf, int buf_size)
+ const uint8_t *buf, int buf_size)
{
MJpegDecodeContext *s = avctx->priv_data;
- uint8_t *buf_end, *buf_ptr;
+ const uint8_t *buf_end, *buf_ptr;
int start_code;
AVFrame *picture = data;
if (start_code < 0) {
goto the_end;
} else {
- av_log(avctx, AV_LOG_DEBUG, "marker=%x avail_size_in_buf=%d\n", start_code, buf_end - buf_ptr);
+ av_log(avctx, AV_LOG_DEBUG, "marker=%x avail_size_in_buf=%td\n", start_code, buf_end - buf_ptr);
if ((buf_end - buf_ptr) > s->buffer_size)
{
/* unescape buffer of SOS, use special treatment for JPEG-LS */
if (start_code == SOS && !s->ls)
{
- uint8_t *src = buf_ptr;
+ const uint8_t *src = buf_ptr;
uint8_t *dst = s->buffer;
while (src<buf_end)
}
init_get_bits(&s->gb, s->buffer, (dst - s->buffer)*8);
- av_log(avctx, AV_LOG_DEBUG, "escaping removed %d bytes\n",
+ av_log(avctx, AV_LOG_DEBUG, "escaping removed %td bytes\n",
(buf_end - buf_ptr) - (dst - s->buffer));
}
else if(start_code == SOS && s->ls){
- uint8_t *src = buf_ptr;
+ const uint8_t *src = buf_ptr;
uint8_t *dst = s->buffer;
int bit_count = 0;
int t = 0, b = 0;
/* nothing to do on SOI */
break;
case DQT:
- mjpeg_decode_dqt(s);
+ ff_mjpeg_decode_dqt(s);
break;
case DHT:
- if(mjpeg_decode_dht(s) < 0){
+ if(ff_mjpeg_decode_dht(s) < 0){
av_log(avctx, AV_LOG_ERROR, "huffman table decode error\n");
return -1;
}
s->lossless=0;
s->ls=0;
s->progressive=0;
- if (mjpeg_decode_sof(s) < 0)
+ if (ff_mjpeg_decode_sof(s) < 0)
return -1;
break;
case SOF2:
s->lossless=0;
s->ls=0;
s->progressive=1;
- if (mjpeg_decode_sof(s) < 0)
+ if (ff_mjpeg_decode_sof(s) < 0)
return -1;
break;
case SOF3:
s->lossless=1;
s->ls=0;
s->progressive=0;
- if (mjpeg_decode_sof(s) < 0)
+ if (ff_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)
+ if (ff_mjpeg_decode_sof(s) < 0)
return -1;
break;
case LSE:
*data_size = sizeof(AVFrame);
if(!s->lossless){
- picture->quality= FFMAX(FFMAX(s->qscale[0], s->qscale[1]), s->qscale[2]);
+ picture->quality= FFMAX3(s->qscale[0], s->qscale[1], s->qscale[2]);
picture->qstride= 0;
picture->qscale_table= s->qscale_table;
memset(picture->qscale_table, picture->quality, (s->width+15)/16);
}
break;
case SOS:
- mjpeg_decode_sos(s);
+ ff_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)
}
}
the_end:
- av_log(avctx, AV_LOG_DEBUG, "mjpeg decode frame unused %d bytes\n", buf_end - buf_ptr);
+ av_log(avctx, AV_LOG_DEBUG, "mjpeg decode frame unused %td bytes\n", buf_end - buf_ptr);
// return buf_end - buf_ptr;
return buf_ptr - buf;
}
-static int mjpegb_decode_frame(AVCodecContext *avctx,
- void *data, int *data_size,
- uint8_t *buf, int buf_size)
-{
- MJpegDecodeContext *s = avctx->priv_data;
- uint8_t *buf_end, *buf_ptr;
- AVFrame *picture = data;
- GetBitContext hgb; /* for the header */
- uint32_t dqt_offs, dht_offs, sof_offs, sos_offs, second_field_offs;
- uint32_t field_size, sod_offs;
-
- buf_ptr = buf;
- buf_end = buf + buf_size;
-
-read_header:
- /* reset on every SOI */
- s->restart_interval = 0;
- s->restart_count = 0;
- s->mjpb_skiptosod = 0;
-
- init_get_bits(&hgb, buf_ptr, /*buf_size*/(buf_end - buf_ptr)*8);
-
- skip_bits(&hgb, 32); /* reserved zeros */
-
- if (get_bits_long(&hgb, 32) != MKBETAG('m','j','p','g'))
- {
- av_log(avctx, AV_LOG_WARNING, "not mjpeg-b (bad fourcc)\n");
- return 0;
- }
-
- field_size = get_bits_long(&hgb, 32); /* field size */
- av_log(avctx, AV_LOG_DEBUG, "field size: 0x%x\n", field_size);
- skip_bits(&hgb, 32); /* padded field size */
- second_field_offs = get_bits_long(&hgb, 32);
- av_log(avctx, AV_LOG_DEBUG, "second field offs: 0x%x\n", second_field_offs);
-
- dqt_offs = get_bits_long(&hgb, 32);
- av_log(avctx, AV_LOG_DEBUG, "dqt offs: 0x%x\n", dqt_offs);
- if (dqt_offs)
- {
- init_get_bits(&s->gb, buf+dqt_offs, (buf_end - (buf+dqt_offs))*8);
- s->start_code = DQT;
- mjpeg_decode_dqt(s);
- }
-
- dht_offs = get_bits_long(&hgb, 32);
- av_log(avctx, AV_LOG_DEBUG, "dht offs: 0x%x\n", dht_offs);
- if (dht_offs)
- {
- init_get_bits(&s->gb, buf+dht_offs, (buf_end - (buf+dht_offs))*8);
- s->start_code = DHT;
- mjpeg_decode_dht(s);
- }
-
- sof_offs = get_bits_long(&hgb, 32);
- av_log(avctx, AV_LOG_DEBUG, "sof offs: 0x%x\n", sof_offs);
- if (sof_offs)
- {
- init_get_bits(&s->gb, buf+sof_offs, (buf_end - (buf+sof_offs))*8);
- s->start_code = SOF0;
- if (mjpeg_decode_sof(s) < 0)
- return -1;
- }
-
- sos_offs = get_bits_long(&hgb, 32);
- av_log(avctx, AV_LOG_DEBUG, "sos offs: 0x%x\n", sos_offs);
- sod_offs = get_bits_long(&hgb, 32);
- av_log(avctx, AV_LOG_DEBUG, "sod offs: 0x%x\n", sod_offs);
- if (sos_offs)
- {
-// init_get_bits(&s->gb, buf+sos_offs, (buf_end - (buf+sos_offs))*8);
- init_get_bits(&s->gb, buf+sos_offs, field_size*8);
- s->mjpb_skiptosod = (sod_offs - sos_offs - show_bits(&s->gb, 16));
- s->start_code = SOS;
- mjpeg_decode_sos(s);
- }
-
- if (s->interlaced) {
- s->bottom_field ^= 1;
- /* if not bottom field, do not output image yet */
- if (s->bottom_field && second_field_offs)
- {
- buf_ptr = buf + second_field_offs;
- second_field_offs = 0;
- goto read_header;
- }
- }
-
- //XXX FIXME factorize, this looks very similar to the EOI code
-
- *picture= s->picture;
- *data_size = sizeof(AVFrame);
-
- if(!s->lossless){
- picture->quality= FFMAX(FFMAX(s->qscale[0], s->qscale[1]), s->qscale[2]);
- picture->qstride= 0;
- picture->qscale_table= s->qscale_table;
- memset(picture->qscale_table, picture->quality, (s->width+15)/16);
- if(avctx->debug & FF_DEBUG_QP)
- av_log(avctx, AV_LOG_DEBUG, "QP: %d\n", picture->quality);
- picture->quality*= FF_QP2LAMBDA;
- }
-
- return buf_ptr - buf;
-}
-
-#include "sp5x.h"
-
-static int sp5x_decode_frame(AVCodecContext *avctx,
- void *data, int *data_size,
- uint8_t *buf, int buf_size)
-{
-#if 0
- MJpegDecodeContext *s = avctx->priv_data;
-#endif
- const int qscale = 5;
- uint8_t *buf_ptr, *buf_end, *recoded;
- int i = 0, j = 0;
-
- if (!avctx->width || !avctx->height)
- return -1;
-
- buf_ptr = buf;
- buf_end = buf + buf_size;
-
-#if 1
- recoded = av_mallocz(buf_size + 1024);
- if (!recoded)
- return -1;
-
- /* SOI */
- recoded[j++] = 0xFF;
- recoded[j++] = 0xD8;
-
- memcpy(recoded+j, &sp5x_data_dqt[0], sizeof(sp5x_data_dqt));
- memcpy(recoded+j+5, &sp5x_quant_table[qscale * 2], 64);
- memcpy(recoded+j+70, &sp5x_quant_table[(qscale * 2) + 1], 64);
- j += sizeof(sp5x_data_dqt);
-
- memcpy(recoded+j, &sp5x_data_dht[0], sizeof(sp5x_data_dht));
- j += sizeof(sp5x_data_dht);
-
- memcpy(recoded+j, &sp5x_data_sof[0], sizeof(sp5x_data_sof));
- recoded[j+5] = (avctx->coded_height >> 8) & 0xFF;
- recoded[j+6] = avctx->coded_height & 0xFF;
- recoded[j+7] = (avctx->coded_width >> 8) & 0xFF;
- recoded[j+8] = avctx->coded_width & 0xFF;
- j += sizeof(sp5x_data_sof);
-
- memcpy(recoded+j, &sp5x_data_sos[0], sizeof(sp5x_data_sos));
- j += sizeof(sp5x_data_sos);
-
- for (i = 14; i < buf_size && j < buf_size+1024-2; i++)
- {
- recoded[j++] = buf[i];
- if (buf[i] == 0xff)
- recoded[j++] = 0;
- }
-
- /* EOI */
- recoded[j++] = 0xFF;
- recoded[j++] = 0xD9;
-
- i = ff_mjpeg_decode_frame(avctx, data, data_size, recoded, j);
-
- av_free(recoded);
-
-#else
- /* SOF */
- s->bits = 8;
- s->width = avctx->coded_width;
- s->height = avctx->coded_height;
- s->nb_components = 3;
- s->component_id[0] = 0;
- s->h_count[0] = 2;
- s->v_count[0] = 2;
- s->quant_index[0] = 0;
- s->component_id[1] = 1;
- s->h_count[1] = 1;
- s->v_count[1] = 1;
- s->quant_index[1] = 1;
- s->component_id[2] = 2;
- s->h_count[2] = 1;
- s->v_count[2] = 1;
- s->quant_index[2] = 1;
- s->h_max = 2;
- s->v_max = 2;
-
- s->qscale_table = av_mallocz((s->width+15)/16);
- avctx->pix_fmt = s->cs_itu601 ? PIX_FMT_YUV420P : PIX_FMT_YUVJ420;
- s->interlaced = 0;
-
- s->picture.reference = 0;
- if (avctx->get_buffer(avctx, &s->picture) < 0)
- {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return -1;
- }
-
- s->picture.pict_type = I_TYPE;
- s->picture.key_frame = 1;
-
- for (i = 0; i < 3; i++)
- s->linesize[i] = s->picture.linesize[i] << s->interlaced;
-
- /* DQT */
- for (i = 0; i < 64; i++)
- {
- j = s->scantable.permutated[i];
- s->quant_matrixes[0][j] = sp5x_quant_table[(qscale * 2) + i];
- }
- s->qscale[0] = FFMAX(
- s->quant_matrixes[0][s->scantable.permutated[1]],
- s->quant_matrixes[0][s->scantable.permutated[8]]) >> 1;
-
- for (i = 0; i < 64; i++)
- {
- j = s->scantable.permutated[i];
- s->quant_matrixes[1][j] = sp5x_quant_table[(qscale * 2) + 1 + i];
- }
- s->qscale[1] = FFMAX(
- s->quant_matrixes[1][s->scantable.permutated[1]],
- s->quant_matrixes[1][s->scantable.permutated[8]]) >> 1;
-
- /* DHT */
-
- /* SOS */
- s->comp_index[0] = 0;
- s->nb_blocks[0] = s->h_count[0] * s->v_count[0];
- s->h_scount[0] = s->h_count[0];
- s->v_scount[0] = s->v_count[0];
- s->dc_index[0] = 0;
- s->ac_index[0] = 0;
-
- s->comp_index[1] = 1;
- s->nb_blocks[1] = s->h_count[1] * s->v_count[1];
- s->h_scount[1] = s->h_count[1];
- s->v_scount[1] = s->v_count[1];
- s->dc_index[1] = 1;
- s->ac_index[1] = 1;
-
- s->comp_index[2] = 2;
- s->nb_blocks[2] = s->h_count[2] * s->v_count[2];
- s->h_scount[2] = s->h_count[2];
- s->v_scount[2] = s->v_count[2];
- s->dc_index[2] = 1;
- s->ac_index[2] = 1;
-
- for (i = 0; i < 3; i++)
- s->last_dc[i] = 1024;
-
- s->mb_width = (s->width * s->h_max * 8 -1) / (s->h_max * 8);
- s->mb_height = (s->height * s->v_max * 8 -1) / (s->v_max * 8);
-
- init_get_bits(&s->gb, buf+14, (buf_size-14)*8);
-
- return mjpeg_decode_scan(s);
-#endif
-
- return i;
-}
-
-int ff_mjpeg_decode_end(AVCodecContext *avctx)
+av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx)
{
MJpegDecodeContext *s = avctx->priv_data;
int i, j;
for(j=0;j<4;j++)
free_vlc(&s->vlcs[i][j]);
}
+ for(i=0; i<MAX_COMPONENTS; i++) {
+ av_freep(&s->blocks[i]);
+ av_freep(&s->last_nnz[i]);
+ }
return 0;
}
ff_mjpeg_decode_end,
ff_mjpeg_decode_frame,
CODEC_CAP_DR1,
- NULL
+ NULL,
+ .long_name = NULL_IF_CONFIG_SMALL("MJPEG (Motion JPEG)"),
};
AVCodec thp_decoder = {
ff_mjpeg_decode_end,
ff_mjpeg_decode_frame,
CODEC_CAP_DR1,
- NULL
-};
-
-AVCodec mjpegb_decoder = {
- "mjpegb",
- CODEC_TYPE_VIDEO,
- CODEC_ID_MJPEGB,
- sizeof(MJpegDecodeContext),
- ff_mjpeg_decode_init,
- NULL,
- ff_mjpeg_decode_end,
- mjpegb_decode_frame,
- CODEC_CAP_DR1,
- NULL
-};
-
-AVCodec sp5x_decoder = {
- "sp5x",
- CODEC_TYPE_VIDEO,
- CODEC_ID_SP5X,
- sizeof(MJpegDecodeContext),
- ff_mjpeg_decode_init,
NULL,
- ff_mjpeg_decode_end,
- sp5x_decode_frame,
- CODEC_CAP_DR1,
- NULL
+ .long_name = NULL_IF_CONFIG_SMALL("Nintendo Gamecube THP video"),
};