Newer
Older
put_pixels_clamped(s->block, ptr, s->linesize[c]);
if (++x == h) {
x = 0;
y++;
}
}
}
}
}
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);
printf("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;
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
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));
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;
}
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
/* 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;
if (state) {
/* get marker */
found:
if (buf_ptr < buf_end) {
val = *buf_ptr++;
state = 0;
} 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 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
}
}
}
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