diff options
Diffstat (limited to 'src/libffmpeg/libavcodec/msrle.c')
-rw-r--r-- | src/libffmpeg/libavcodec/msrle.c | 168 |
1 files changed, 130 insertions, 38 deletions
diff --git a/src/libffmpeg/libavcodec/msrle.c b/src/libffmpeg/libavcodec/msrle.c index 8943ef3cd..b318faa77 100644 --- a/src/libffmpeg/libavcodec/msrle.c +++ b/src/libffmpeg/libavcodec/msrle.c @@ -26,7 +26,7 @@ * The MS RLE decoder outputs PAL8 colorspace data. * * Note that this decoder expects the palette colors from the end of the - * BITMAPINFO header passed through extradata. + * BITMAPINFO header passed through palctrl. */ #include <stdio.h> @@ -41,22 +41,115 @@ typedef struct MsrleContext { AVCodecContext *avctx; AVFrame frame; - AVFrame prev_frame; unsigned char *buf; int size; - unsigned int palette[256]; } MsrleContext; #define FETCH_NEXT_STREAM_BYTE() \ if (stream_ptr >= s->size) \ { \ - printf(" MS RLE: stream ptr just went out of bounds (1)\n"); \ + av_log(s->avctx, AV_LOG_ERROR, " MS RLE: stream ptr just went out of bounds (1)\n"); \ return; \ } \ stream_byte = s->buf[stream_ptr++]; +static void msrle_decode_pal4(MsrleContext *s) +{ + int stream_ptr = 0; + unsigned char rle_code; + unsigned char extra_byte, odd_pixel; + unsigned char stream_byte; + int pixel_ptr = 0; + int row_dec = s->frame.linesize[0]; + int row_ptr = (s->avctx->height - 1) * row_dec; + int frame_size = row_dec * s->avctx->height; + int i; + + /* make the palette available */ + memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE); + if (s->avctx->palctrl->palette_changed) { + s->frame.palette_has_changed = 1; + s->avctx->palctrl->palette_changed = 0; + } + + while (row_ptr >= 0) { + FETCH_NEXT_STREAM_BYTE(); + rle_code = stream_byte; + if (rle_code == 0) { + /* fetch the next byte to see how to handle escape code */ + FETCH_NEXT_STREAM_BYTE(); + if (stream_byte == 0) { + /* line is done, goto the next one */ + row_ptr -= row_dec; + pixel_ptr = 0; + } else if (stream_byte == 1) { + /* decode is done */ + return; + } else if (stream_byte == 2) { + /* reposition frame decode coordinates */ + FETCH_NEXT_STREAM_BYTE(); + pixel_ptr += stream_byte; + FETCH_NEXT_STREAM_BYTE(); + row_ptr -= stream_byte * row_dec; + } else { + // copy pixels from encoded stream + odd_pixel = stream_byte & 1; + rle_code = (stream_byte + 1) / 2; + extra_byte = rle_code & 0x01; + if ((row_ptr + pixel_ptr + stream_byte > frame_size) || + (row_ptr < 0)) { + av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n"); + return; + } + + for (i = 0; i < rle_code; i++) { + if (pixel_ptr >= s->avctx->width) + break; + FETCH_NEXT_STREAM_BYTE(); + s->frame.data[0][row_ptr + pixel_ptr] = stream_byte >> 4; + pixel_ptr++; + if (i + 1 == rle_code && odd_pixel) + break; + if (pixel_ptr >= s->avctx->width) + break; + s->frame.data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F; + pixel_ptr++; + } + + // if the RLE code is odd, skip a byte in the stream + if (extra_byte) + stream_ptr++; + } + } else { + // decode a run of data + if ((row_ptr + pixel_ptr + stream_byte > frame_size) || + (row_ptr < 0)) { + av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n"); + return; + } + FETCH_NEXT_STREAM_BYTE(); + for (i = 0; i < rle_code; i++) { + if (pixel_ptr >= s->avctx->width) + break; + if ((i & 1) == 0) + s->frame.data[0][row_ptr + pixel_ptr] = stream_byte >> 4; + else + s->frame.data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F; + pixel_ptr++; + } + } + } + + /* one last sanity check on the way out */ + if (stream_ptr < s->size) + av_log(s->avctx, AV_LOG_ERROR, " MS RLE: ended frame decode with bytes left over (%d < %d)\n", + stream_ptr, s->size); +} + + + static void msrle_decode_pal8(MsrleContext *s) { int stream_ptr = 0; @@ -68,6 +161,13 @@ static void msrle_decode_pal8(MsrleContext *s) int row_ptr = (s->avctx->height - 1) * row_dec; int frame_size = row_dec * s->avctx->height; + /* make the palette available */ + memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE); + if (s->avctx->palctrl->palette_changed) { + s->frame.palette_has_changed = 1; + s->avctx->palctrl->palette_changed = 0; + } + while (row_ptr >= 0) { FETCH_NEXT_STREAM_BYTE(); rle_code = stream_byte; @@ -91,14 +191,14 @@ static void msrle_decode_pal8(MsrleContext *s) /* copy pixels from encoded stream */ if ((row_ptr + pixel_ptr + stream_byte > frame_size) || (row_ptr < 0)) { - printf(" MS RLE: frame ptr just went out of bounds (1)\n"); + av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n"); return; } rle_code = stream_byte; extra_byte = stream_byte & 0x01; if (stream_ptr + rle_code + extra_byte > s->size) { - printf(" MS RLE: stream ptr just went out of bounds (2)\n"); + av_log(s->avctx, AV_LOG_ERROR, " MS RLE: stream ptr just went out of bounds (2)\n"); return; } @@ -116,7 +216,7 @@ static void msrle_decode_pal8(MsrleContext *s) /* decode a run of data */ if ((row_ptr + pixel_ptr + stream_byte > frame_size) || (row_ptr < 0)) { - printf(" MS RLE: frame ptr just went out of bounds (2)\n"); + av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (2)\n"); return; } @@ -129,35 +229,21 @@ static void msrle_decode_pal8(MsrleContext *s) } } - /* make the palette available */ - memcpy(s->frame.data[1], s->palette, 256 * 4); - /* one last sanity check on the way out */ if (stream_ptr < s->size) - printf(" MS RLE: ended frame decode with bytes left over (%d < %d)\n", + av_log(s->avctx, AV_LOG_ERROR, " MS RLE: ended frame decode with bytes left over (%d < %d)\n", stream_ptr, s->size); } static int msrle_decode_init(AVCodecContext *avctx) { MsrleContext *s = (MsrleContext *)avctx->priv_data; - int i, j; - unsigned char *palette; s->avctx = avctx; avctx->pix_fmt = PIX_FMT_PAL8; avctx->has_b_frames = 0; - s->frame.data[0] = s->prev_frame.data[0] = NULL; - - /* convert palette */ - palette = (unsigned char *)s->avctx->extradata; - memset (s->palette, 0, 256 * 4); - for (i = 0, j = 0; i < s->avctx->extradata_size / 4; i++, j += 4) - s->palette[i] = - (palette[j + 2] << 16) | - (palette[j + 1] << 8) | - (palette[j + 0] << 0); + s->frame.data[0] = NULL; return 0; } @@ -168,25 +254,31 @@ static int msrle_decode_frame(AVCodecContext *avctx, { MsrleContext *s = (MsrleContext *)avctx->priv_data; + /* no supplementary picture */ + if (buf_size == 0) + return 0; + s->buf = buf; s->size = buf_size; - if (avctx->get_buffer(avctx, &s->frame)) { - printf (" MS RLE: get_buffer() failed\n"); + s->frame.reference = 1; + s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; + if (avctx->reget_buffer(avctx, &s->frame)) { + av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); return -1; } - /* grossly inefficient, but...oh well */ - memcpy(s->frame.data[0], s->prev_frame.data[0], - s->frame.linesize[0] * s->avctx->height); - - msrle_decode_pal8(s); - - if (s->frame.data[0]) - avctx->release_buffer(avctx, &s->frame); - - /* shuffle frames */ - s->prev_frame = s->frame; + switch (avctx->bits_per_sample) { + case 8: + msrle_decode_pal8(s); + break; + case 4: + msrle_decode_pal4(s); + break; + default: + av_log(avctx, AV_LOG_ERROR, "Don't know how to decode depth %u.\n", + avctx->bits_per_sample); + } *data_size = sizeof(AVFrame); *(AVFrame*)data = s->frame; @@ -200,8 +292,8 @@ static int msrle_decode_end(AVCodecContext *avctx) MsrleContext *s = (MsrleContext *)avctx->priv_data; /* release the last frame */ - if (s->prev_frame.data[0]) - avctx->release_buffer(avctx, &s->prev_frame); + if (s->frame.data[0]) + avctx->release_buffer(avctx, &s->frame); return 0; } |