Newer
Older
n = nb_blocks[i];
c = comp_index[i];
h = h_count[i];
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,
dc_index[i], ac_index[i],
s->quant_index[c]) < 0) {
dprintf("error y=%d x=%d\n", mb_y, mb_x);
Fabrice Bellard
committed
ret = -1;
goto the_end;
Arpi
committed
// dprintf("mb: %d %d processed\n", mb_y, mb_x);
ptr = s->current_picture[c] +
(s->linesize[c] * (v * mb_y + y) * 8) +
(h * mb_x + x) * 8;
if (s->interlaced && s->bottom_field)
ptr += s->linesize[c] >> 1;
if (++x == h) {
x = 0;
y++;
}
}
}
Leon van Stuivenberg
committed
if (s->restart_interval && !--s->restart_count) {
align_get_bits(&s->gb);
skip_bits(&s->gb, 16); /* skip RSTn */
for (j=0; j<nb_components; j++) /* reset dc */
s->last_dc[j] = 1024;
}
Fabrice Bellard
committed
ret = 0;
the_end:
emms_c();
Fabrice Bellard
committed
return ret;
Arpi
committed
out_of_range:
dprintf("decode_sos: ac/dc index out of range\n");
return -1;
static int mjpeg_decode_dri(MJpegDecodeContext *s,
UINT8 *buf, int buf_size)
{
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);
dprintf("restart interval: %d\n", s->restart_interval);
return 0;
}
#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)
{
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)
return -1;
id = (get_bits(&s->gb, 16) << 16) | get_bits(&s->gb, 16);
len -= 6;
/* buggy AVID, it puts EOI only at every 10th frame */
/* also this fourcc is used by non-avid files too, it means
interleaving, but it's always present in AVID files */
if (id == FOURCC('A','V','I','1'))
{
/* structure:
4bytes AVI1
1bytes polarity
1bytes always zero
4bytes field_size
4bytes field_size_less_padding
*/
s->buggy_avid = 1;
if (s->first_picture)
printf("mjpeg: workarounding buggy AVID\n");
s->interleaved_rows = get_bits(&s->gb, 8);
#if 0
skip_bits(&s->gb, 8);
skip_bits(&s->gb, 32);
skip_bits(&s->gb, 32);
len -= 10;
#endif
if (s->interleaved_rows)
printf("mjpeg: interleaved rows: %d\n", s->interleaved_rows);
goto out;
len -= 2;
if (id == FOURCC('J','F','I','F'))
{
skip_bits(&s->gb, 8); /* the trailing zero-byte */
printf("mjpeg: JFIF header found (version: %x.%x)\n",
get_bits(&s->gb, 8), get_bits(&s->gb, 8));
if (get_bits(&s->gb, 8) == 0)
{
s->avctx->aspect_ratio_info = FF_ASPECT_EXTENDED;
s->avctx->aspected_width = get_bits(&s->gb, 16);
s->avctx->aspected_height = get_bits(&s->gb, 16);
}
else
{
skip_bits(&s->gb, 16);
skip_bits(&s->gb, 16);
}
skip_bits(&s->gb, 8);
skip_bits(&s->gb, 8);
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
goto out;
}
/* Apple MJPEG-A */
if ((start_code == APP1) && (len > (0x28 - 8)))
{
id = (get_bits(&s->gb, 16) << 16) | get_bits(&s->gb, 16);
len -= 4;
if (id == FOURCC('m','j','p','g')) /* Apple MJPEG-A */
{
#if 0
skip_bits(&s->gb, 32); /* field size */
skip_bits(&s->gb, 32); /* pad field size */
skip_bits(&s->gb, 32); /* next off */
skip_bits(&s->gb, 32); /* quant off */
skip_bits(&s->gb, 32); /* huff off */
skip_bits(&s->gb, 32); /* image off */
skip_bits(&s->gb, 32); /* scan off */
skip_bits(&s->gb, 32); /* data off */
#endif
if (s->first_picture)
printf("mjpeg: Apple MJPEG-A header found\n");
}
}
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)
{
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);
for (i = 0; i < len; i++)
cbuf[i] = get_bits(&s->gb, 8);
if (cbuf[i-1] == '\n')
cbuf[i-1] = 0;
else
cbuf[i] = 0;
printf("mjpeg comment: '%s'\n", cbuf);
/* buggy avid, it puts EOI only at every 10th frame */
if (!strcmp(cbuf, "AVID"))
{
s->buggy_avid = 1;
if (s->first_picture)
printf("mjpeg: workarounding buggy AVID\n");
}
av_free(cbuf);
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 **pbuf_ptr, UINT8 *buf_end,
UINT32 *header_state)
{
UINT8 *buf_ptr;
unsigned int state, v;
int val;
state = *header_state;
buf_ptr = *pbuf_ptr;
Leon van Stuivenberg
committed
retry:
if (state) {
/* get marker */
found:
if (buf_ptr < buf_end) {
val = *buf_ptr++;
state = 0;
Leon van Stuivenberg
committed
if ((val >= RST0) && (val <= RST7))
goto retry;
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
} else {
val = -1;
}
} else {
while (buf_ptr < buf_end) {
v = *buf_ptr++;
if (v == 0xff) {
state = 1;
goto found;
}
}
val = -1;
}
*pbuf_ptr = buf_ptr;
*header_state = state;
return val;
}
static int mjpeg_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
UINT8 *buf, int buf_size)
{
MJpegDecodeContext *s = avctx->priv_data;
UINT8 *buf_end, *buf_ptr, *buf_start;
Arpi
committed
int len, code, input_size, i;
AVPicture *picture = data;
Arpi
committed
unsigned int start_code;
/* no supplementary picture */
return 0;
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 */
/* 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);
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);
break;
case DHT:
mjpeg_decode_dht(s, s->buffer, input_size);
break;
case SOF0:
mjpeg_decode_sof0(s, s->buffer, input_size);
break;
case SOS:
mjpeg_decode_sos(s, s->buffer, input_size);
if (s->start_code == EOI || s->buggy_avid || s->restart_interval) {
int l;
if (s->interlaced) {
s->bottom_field ^= 1;
/* if not bottom field, do not output image yet */
if (s->bottom_field)
goto not_the_end;
for(i=0;i<3;i++) {
picture->data[i] = s->current_picture[i];
l = s->linesize[i];
if (s->interlaced)
l >>= 1;
picture->linesize[i] = l;
}
*data_size = sizeof(AVPicture);
avctx->height = s->height;
if (s->interlaced)
avctx->height *= 2;
avctx->width = s->width;
/* XXX: not complete test ! */
switch((s->h_count[0] << 4) | s->v_count[0]) {
case 0x11:
avctx->pix_fmt = PIX_FMT_YUV444P;
break;
case 0x21:
avctx->pix_fmt = PIX_FMT_YUV422P;
break;
default:
case 0x22:
avctx->pix_fmt = PIX_FMT_YUV420P;
break;
}
Fabrice Bellard
committed
/* dummy quality */
/* XXX: infer it with matrix */
avctx->quality = 3;
goto the_end;
}
break;
case DRI:
mjpeg_decode_dri(s, s->buffer, input_size);
break;
case SOF1:
case SOF2:
case SOF3:
case SOF5:
case SOF6:
case SOF7:
case SOF9:
case SOF10:
case SOF11:
case SOF13:
case SOF14:
case SOF15:
case JPG:
printf("mjpeg: unsupported coding type (%x)\n", start_code);
return -1;
#if 1
if (start_code >= 0xd0 && start_code <= 0xd7) {
dprintf("restart marker: %d\n", start_code&0x0f);
/* 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:
}
the_end:
return buf_ptr - buf;
}
static int mjpeg_decode_end(AVCodecContext *avctx)
{
MJpegDecodeContext *s = avctx->priv_data;
int i, j;
for(i=0;i<MAX_COMPONENTS;i++)
av_free(s->current_picture[i]);
for(i=0;i<2;i++) {
for(j=0;j<4;j++)
free_vlc(&s->vlcs[i][j]);
}
return 0;
}
AVCodec mjpeg_decoder = {
"mjpeg",
CODEC_TYPE_VIDEO,
CODEC_ID_MJPEG,
sizeof(MJpegDecodeContext),
mjpeg_decode_init,
NULL,
mjpeg_decode_end,
mjpeg_decode_frame,
0,
NULL