2 * American Laser Games MM Video Decoder
3 * Copyright (c) 2006 Peter Ross
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * American Laser Games MM Video Decoder
23 * by Peter Ross (suxen_drol at hotmail dot com)
25 * The MM format was used by IBM-PC ports of ALG's "arcade shooter" games,
26 * including Mad Dog McCree and Crime Patrol.
28 * Technical details here:
29 * http://wiki.multimedia.cx/index.php?title=American_Laser_Games_MM
34 #define MM_PREAMBLE_SIZE 6
36 #define MM_TYPE_INTER 0x5
37 #define MM_TYPE_INTRA 0x8
38 #define MM_TYPE_INTRA_HH 0xc
39 #define MM_TYPE_INTER_HH 0xd
40 #define MM_TYPE_INTRA_HHV 0xe
41 #define MM_TYPE_INTER_HHV 0xf
43 typedef struct MmContext
{
44 AVCodecContext
*avctx
;
48 static int mm_decode_init(AVCodecContext
*avctx
)
50 MmContext
*s
= avctx
->priv_data
;
54 if (s
->avctx
->palctrl
== NULL
) {
55 av_log(avctx
, AV_LOG_ERROR
, "mmvideo: palette expected.\n");
59 avctx
->pix_fmt
= PIX_FMT_PAL8
;
60 avctx
->has_b_frames
= 0;
62 if (avcodec_check_dimensions(avctx
, avctx
->width
, avctx
->height
))
65 s
->frame
.reference
= 1;
66 if (avctx
->get_buffer(avctx
, &s
->frame
)) {
67 av_log(s
->avctx
, AV_LOG_ERROR
, "mmvideo: get_buffer() failed\n");
74 static void mm_decode_intra(MmContext
* s
, int half_horiz
, int half_vert
, const uint8_t *buf
, int buf_size
)
80 int run_length
, color
;
87 run_length
= (buf
[i
] & 0x7f) + 2;
96 memset(s
->frame
.data
[0] + y
*s
->frame
.linesize
[0] + x
, color
, run_length
);
98 memset(s
->frame
.data
[0] + (y
+1)*s
->frame
.linesize
[0] + x
, color
, run_length
);
102 if (x
>= s
->avctx
->width
) {
104 y
+= half_vert
? 2 : 1;
109 static void mm_decode_inter(MmContext
* s
, int half_horiz
, int half_vert
, const uint8_t *buf
, int buf_size
)
111 const int data_ptr
= 2 + LE_16(&buf
[0]);
113 d
= data_ptr
; r
= 2; y
= 0;
115 while(r
< data_ptr
) {
117 int length
= buf
[r
] & 0x7f;
118 int x
= buf
[r
+1] + ((buf
[r
] & 0x80) << 1);
126 for(i
=0; i
<length
; i
++) {
128 int replace
= (buf
[r
+i
] >> (7-j
)) & 1;
131 s
->frame
.data
[0][y
*s
->frame
.linesize
[0] + x
] = color
;
133 s
->frame
.data
[0][y
*s
->frame
.linesize
[0] + x
+ 1] = color
;
135 s
->frame
.data
[0][(y
+1)*s
->frame
.linesize
[0] + x
] = color
;
137 s
->frame
.data
[0][(y
+1)*s
->frame
.linesize
[0] + x
+ 1] = color
;
141 x
+= half_horiz
? 2 : 1;
146 y
+= half_vert
? 2 : 1;
150 static int mm_decode_frame(AVCodecContext
*avctx
,
151 void *data
, int *data_size
,
152 uint8_t *buf
, int buf_size
)
154 MmContext
*s
= avctx
->priv_data
;
155 AVPaletteControl
*palette_control
= avctx
->palctrl
;
158 if (palette_control
->palette_changed
) {
159 memcpy(s
->frame
.data
[1], palette_control
->palette
, AVPALETTE_SIZE
);
160 palette_control
->palette_changed
= 0;
163 type
= LE_16(&buf
[0]);
164 buf
+= MM_PREAMBLE_SIZE
;
165 buf_size
-= MM_PREAMBLE_SIZE
;
168 case MM_TYPE_INTRA
: mm_decode_intra(s
, 0, 0, buf
, buf_size
); break;
169 case MM_TYPE_INTRA_HH
: mm_decode_intra(s
, 1, 0, buf
, buf_size
); break;
170 case MM_TYPE_INTRA_HHV
: mm_decode_intra(s
, 1, 1, buf
, buf_size
); break;
171 case MM_TYPE_INTER
: mm_decode_inter(s
, 0, 0, buf
, buf_size
); break;
172 case MM_TYPE_INTER_HH
: mm_decode_inter(s
, 1, 0, buf
, buf_size
); break;
173 case MM_TYPE_INTER_HHV
: mm_decode_inter(s
, 1, 1, buf
, buf_size
); break;
178 *data_size
= sizeof(AVFrame
);
179 *(AVFrame
*)data
= s
->frame
;
184 static int mm_decode_end(AVCodecContext
*avctx
)
186 MmContext
*s
= avctx
->priv_data
;
189 avctx
->release_buffer(avctx
, &s
->frame
);
194 AVCodec mmvideo_decoder
= {