00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00034 #include "libavutil/intreadwrite.h"
00035 #include "avcodec.h"
00036 #include "bytestream.h"
00037
00038 #define MM_PREAMBLE_SIZE 6
00039
00040 #define MM_TYPE_INTER 0x5
00041 #define MM_TYPE_INTRA 0x8
00042 #define MM_TYPE_INTRA_HH 0xc
00043 #define MM_TYPE_INTER_HH 0xd
00044 #define MM_TYPE_INTRA_HHV 0xe
00045 #define MM_TYPE_INTER_HHV 0xf
00046 #define MM_TYPE_PALETTE 0x31
00047
00048 typedef struct MmContext {
00049 AVCodecContext *avctx;
00050 AVFrame frame;
00051 int palette[AVPALETTE_COUNT];
00052 GetByteContext gb;
00053 } MmContext;
00054
00055 static av_cold int mm_decode_init(AVCodecContext *avctx)
00056 {
00057 MmContext *s = avctx->priv_data;
00058
00059 s->avctx = avctx;
00060
00061 avctx->pix_fmt = PIX_FMT_PAL8;
00062
00063 avcodec_get_frame_defaults(&s->frame);
00064 s->frame.reference = 3;
00065
00066 return 0;
00067 }
00068
00069 static int mm_decode_pal(MmContext *s)
00070 {
00071 int i;
00072
00073 bytestream2_skip(&s->gb, 4);
00074 for (i = 0; i < 128; i++) {
00075 s->palette[i] = 0xFF << 24 | bytestream2_get_be24(&s->gb);
00076 s->palette[i+128] = s->palette[i]<<2;
00077 }
00078
00079 return 0;
00080 }
00081
00086 static int mm_decode_intra(MmContext * s, int half_horiz, int half_vert)
00087 {
00088 int x = 0, y = 0;
00089
00090 while (bytestream2_get_bytes_left(&s->gb) > 0) {
00091 int run_length, color;
00092
00093 if (y >= s->avctx->height)
00094 return 0;
00095
00096 color = bytestream2_get_byte(&s->gb);
00097 if (color & 0x80) {
00098 run_length = 1;
00099 }else{
00100 run_length = (color & 0x7f) + 2;
00101 color = bytestream2_get_byte(&s->gb);
00102 }
00103
00104 if (half_horiz)
00105 run_length *=2;
00106
00107 if (color) {
00108 memset(s->frame.data[0] + y*s->frame.linesize[0] + x, color, run_length);
00109 if (half_vert)
00110 memset(s->frame.data[0] + (y+1)*s->frame.linesize[0] + x, color, run_length);
00111 }
00112 x+= run_length;
00113
00114 if (x >= s->avctx->width) {
00115 x=0;
00116 y += 1 + half_vert;
00117 }
00118 }
00119
00120 return 0;
00121 }
00122
00123
00124
00125
00126
00127 static int mm_decode_inter(MmContext * s, int half_horiz, int half_vert)
00128 {
00129 int data_off = bytestream2_get_le16(&s->gb), y = 0;
00130 GetByteContext data_ptr;
00131
00132 if (bytestream2_get_bytes_left(&s->gb) < data_off)
00133 return AVERROR_INVALIDDATA;
00134
00135 bytestream2_init(&data_ptr, s->gb.buffer + data_off, bytestream2_get_bytes_left(&s->gb) - data_off);
00136 while (s->gb.buffer < data_ptr.buffer_start) {
00137 int i, j;
00138 int length = bytestream2_get_byte(&s->gb);
00139 int x = bytestream2_get_byte(&s->gb) + ((length & 0x80) << 1);
00140 length &= 0x7F;
00141
00142 if (length==0) {
00143 y += x;
00144 continue;
00145 }
00146
00147 if (y + half_vert >= s->avctx->height)
00148 return 0;
00149
00150 for(i=0; i<length; i++) {
00151 int replace_array = bytestream2_get_byte(&s->gb);
00152 for(j=0; j<8; j++) {
00153 int replace = (replace_array >> (7-j)) & 1;
00154 if (replace) {
00155 int color = bytestream2_get_byte(&data_ptr);
00156 s->frame.data[0][y*s->frame.linesize[0] + x] = color;
00157 if (half_horiz)
00158 s->frame.data[0][y*s->frame.linesize[0] + x + 1] = color;
00159 if (half_vert) {
00160 s->frame.data[0][(y+1)*s->frame.linesize[0] + x] = color;
00161 if (half_horiz)
00162 s->frame.data[0][(y+1)*s->frame.linesize[0] + x + 1] = color;
00163 }
00164 }
00165 x += 1 + half_horiz;
00166 }
00167 }
00168
00169 y += 1 + half_vert;
00170 }
00171
00172 return 0;
00173 }
00174
00175 static int mm_decode_frame(AVCodecContext *avctx,
00176 void *data, int *data_size,
00177 AVPacket *avpkt)
00178 {
00179 const uint8_t *buf = avpkt->data;
00180 int buf_size = avpkt->size;
00181 MmContext *s = avctx->priv_data;
00182 int type, res;
00183
00184 if (buf_size < MM_PREAMBLE_SIZE)
00185 return AVERROR_INVALIDDATA;
00186 type = AV_RL16(&buf[0]);
00187 buf += MM_PREAMBLE_SIZE;
00188 buf_size -= MM_PREAMBLE_SIZE;
00189 bytestream2_init(&s->gb, buf, buf_size);
00190
00191 if (avctx->reget_buffer(avctx, &s->frame) < 0) {
00192 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
00193 return -1;
00194 }
00195
00196 switch(type) {
00197 case MM_TYPE_PALETTE : res = mm_decode_pal(s); return buf_size;
00198 case MM_TYPE_INTRA : res = mm_decode_intra(s, 0, 0); break;
00199 case MM_TYPE_INTRA_HH : res = mm_decode_intra(s, 1, 0); break;
00200 case MM_TYPE_INTRA_HHV : res = mm_decode_intra(s, 1, 1); break;
00201 case MM_TYPE_INTER : res = mm_decode_inter(s, 0, 0); break;
00202 case MM_TYPE_INTER_HH : res = mm_decode_inter(s, 1, 0); break;
00203 case MM_TYPE_INTER_HHV : res = mm_decode_inter(s, 1, 1); break;
00204 default:
00205 res = AVERROR_INVALIDDATA;
00206 break;
00207 }
00208 if (res < 0)
00209 return res;
00210
00211 memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE);
00212
00213 *data_size = sizeof(AVFrame);
00214 *(AVFrame*)data = s->frame;
00215
00216 return buf_size;
00217 }
00218
00219 static av_cold int mm_decode_end(AVCodecContext *avctx)
00220 {
00221 MmContext *s = avctx->priv_data;
00222
00223 if(s->frame.data[0])
00224 avctx->release_buffer(avctx, &s->frame);
00225
00226 return 0;
00227 }
00228
00229 AVCodec ff_mmvideo_decoder = {
00230 .name = "mmvideo",
00231 .type = AVMEDIA_TYPE_VIDEO,
00232 .id = CODEC_ID_MMVIDEO,
00233 .priv_data_size = sizeof(MmContext),
00234 .init = mm_decode_init,
00235 .close = mm_decode_end,
00236 .decode = mm_decode_frame,
00237 .capabilities = CODEC_CAP_DR1,
00238 .long_name = NULL_IF_CONFIG_SMALL("American Laser Games MM Video"),
00239 };