2 * American Laser Games MM Video Decoder
3 * Copyright (c) 2006,2008 Peter Ross
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * @file libavcodec/mmvideo.c
24 * American Laser Games MM Video Decoder
25 * by Peter Ross (suxen_drol at hotmail dot com)
27 * The MM format was used by IBM-PC ports of ALG's "arcade shooter" games,
28 * including Mad Dog McCree and Crime Patrol.
30 * Technical details here:
31 * http://wiki.multimedia.cx/index.php?title=American_Laser_Games_MM
34 #include "libavutil/intreadwrite.h"
37 #define MM_PREAMBLE_SIZE 6
39 #define MM_TYPE_INTER 0x5
40 #define MM_TYPE_INTRA 0x8
41 #define MM_TYPE_INTRA_HH 0xc
42 #define MM_TYPE_INTER_HH 0xd
43 #define MM_TYPE_INTRA_HHV 0xe
44 #define MM_TYPE_INTER_HHV 0xf
45 #define MM_TYPE_PALETTE 0x31
47 typedef struct MmContext
{
48 AVCodecContext
*avctx
;
50 int palette
[AVPALETTE_COUNT
];
53 static av_cold
int mm_decode_init(AVCodecContext
*avctx
)
55 MmContext
*s
= avctx
->priv_data
;
59 avctx
->pix_fmt
= PIX_FMT_PAL8
;
61 if (avcodec_check_dimensions(avctx
, avctx
->width
, avctx
->height
))
64 s
->frame
.reference
= 1;
65 if (avctx
->get_buffer(avctx
, &s
->frame
)) {
66 av_log(s
->avctx
, AV_LOG_ERROR
, "mmvideo: get_buffer() failed\n");
73 static void mm_decode_pal(MmContext
*s
, const uint8_t *buf
, const uint8_t *buf_end
)
77 for (i
=0; i
<128 && buf
+2<buf_end
; i
++) {
78 s
->palette
[i
] = AV_RB24(buf
);
79 s
->palette
[i
+128] = s
->palette
[i
]<<2;
84 static void mm_decode_intra(MmContext
* s
, int half_horiz
, int half_vert
, const uint8_t *buf
, int buf_size
)
90 int run_length
, color
;
97 run_length
= (buf
[i
] & 0x7f) + 2;
106 memset(s
->frame
.data
[0] + y
*s
->frame
.linesize
[0] + x
, color
, run_length
);
108 memset(s
->frame
.data
[0] + (y
+1)*s
->frame
.linesize
[0] + x
, color
, run_length
);
112 if (x
>= s
->avctx
->width
) {
114 y
+= half_vert
? 2 : 1;
119 static void mm_decode_inter(MmContext
* s
, int half_horiz
, int half_vert
, const uint8_t *buf
, int buf_size
)
121 const int data_ptr
= 2 + AV_RL16(&buf
[0]);
123 d
= data_ptr
; r
= 2; y
= 0;
125 while(r
< data_ptr
) {
127 int length
= buf
[r
] & 0x7f;
128 int x
= buf
[r
+1] + ((buf
[r
] & 0x80) << 1);
136 for(i
=0; i
<length
; i
++) {
138 int replace
= (buf
[r
+i
] >> (7-j
)) & 1;
141 s
->frame
.data
[0][y
*s
->frame
.linesize
[0] + x
] = color
;
143 s
->frame
.data
[0][y
*s
->frame
.linesize
[0] + x
+ 1] = color
;
145 s
->frame
.data
[0][(y
+1)*s
->frame
.linesize
[0] + x
] = color
;
147 s
->frame
.data
[0][(y
+1)*s
->frame
.linesize
[0] + x
+ 1] = color
;
151 x
+= half_horiz
? 2 : 1;
156 y
+= half_vert
? 2 : 1;
160 static int mm_decode_frame(AVCodecContext
*avctx
,
161 void *data
, int *data_size
,
164 const uint8_t *buf
= avpkt
->data
;
165 int buf_size
= avpkt
->size
;
166 MmContext
*s
= avctx
->priv_data
;
167 const uint8_t *buf_end
= buf
+buf_size
;
170 type
= AV_RL16(&buf
[0]);
171 buf
+= MM_PREAMBLE_SIZE
;
172 buf_size
-= MM_PREAMBLE_SIZE
;
175 case MM_TYPE_PALETTE
: mm_decode_pal(s
, buf
, buf_end
); return buf_size
;
176 case MM_TYPE_INTRA
: mm_decode_intra(s
, 0, 0, buf
, buf_size
); break;
177 case MM_TYPE_INTRA_HH
: mm_decode_intra(s
, 1, 0, buf
, buf_size
); break;
178 case MM_TYPE_INTRA_HHV
: mm_decode_intra(s
, 1, 1, buf
, buf_size
); break;
179 case MM_TYPE_INTER
: mm_decode_inter(s
, 0, 0, buf
, buf_size
); break;
180 case MM_TYPE_INTER_HH
: mm_decode_inter(s
, 1, 0, buf
, buf_size
); break;
181 case MM_TYPE_INTER_HHV
: mm_decode_inter(s
, 1, 1, buf
, buf_size
); break;
186 memcpy(s
->frame
.data
[1], s
->palette
, AVPALETTE_SIZE
);
188 *data_size
= sizeof(AVFrame
);
189 *(AVFrame
*)data
= s
->frame
;
194 static av_cold
int mm_decode_end(AVCodecContext
*avctx
)
196 MmContext
*s
= avctx
->priv_data
;
199 avctx
->release_buffer(avctx
, &s
->frame
);
204 AVCodec mmvideo_decoder
= {
214 .long_name
= NULL_IF_CONFIG_SMALL("American Laser Games MM Video"),