2 * Discworld II BMV video and audio decoder
3 * Copyright (c) 2011 Konstantin Shishkov
5 * This file is part of Libav.
7 * Libav 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 * Libav 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 Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "libavutil/channel_layout.h"
24 #include "bytestream.h"
41 #define SCREEN_WIDE 640
42 #define SCREEN_HIGH 429
44 typedef struct BMVDecContext
{
45 AVCodecContext
*avctx
;
48 uint8_t *frame
, frame_base
[SCREEN_WIDE
* (SCREEN_HIGH
+ 1)];
50 const uint8_t *stream
;
53 #define NEXT_BYTE(v) v = forward ? v + 1 : v - 1;
55 static int decode_bmv_frame(const uint8_t *source
, int src_len
, uint8_t *frame
, int frame_off
)
57 unsigned val
, saved_val
= 0;
59 const uint8_t *src
, *source_end
= source
+ src_len
;
60 uint8_t *frame_end
= frame
+ SCREEN_WIDE
* SCREEN_HIGH
;
61 uint8_t *dst
, *dst_end
;
63 int forward
= (frame_off
<= -SCREEN_WIDE
) || (frame_off
>= 0);
64 int read_two_nibbles
, flag
;
70 return AVERROR_INVALIDDATA
;
77 src
= source
+ src_len
- 1;
85 /* The mode/len decoding is a bit strange:
86 * values are coded as variable-length codes with nibble units,
87 * code end is signalled by two top bits in the nibble being nonzero.
88 * And since data is bytepacked and we read two nibbles at a time,
89 * we may get a nibble belonging to the next code.
90 * Hence this convoluted loop.
92 if (!mode
|| (tmplen
== 4)) {
93 if (src
< source
|| src
>= source_end
)
94 return AVERROR_INVALIDDATA
;
103 if (!read_two_nibbles
) {
104 if (src
< source
|| src
>= source_end
)
105 return AVERROR_INVALIDDATA
;
107 val
|= *src
<< shift
;
111 // two upper bits of the nibble is zero,
112 // so shift top nibble value down into their place
113 read_two_nibbles
= 0;
115 mask
= (1 << shift
) - 1;
116 val
= ((val
>> 2) & ~mask
) | (val
& mask
);
118 if ((val
& (0xC << shift
))) {
129 saved_val
= val
>> (4 + shift
);
131 val
&= (1 << (shift
+ 4)) - 1;
134 advance_mode
= val
& 1;
135 len
= (val
>> 1) - 1;
136 mode
+= 1 + advance_mode
;
139 if (FFABS(dst_end
- dst
) < len
)
140 return AVERROR_INVALIDDATA
;
144 if (dst
- frame
+ SCREEN_WIDE
< frame_off
||
145 dst
- frame
+ SCREEN_WIDE
+ frame_off
< 0 ||
146 frame_end
- dst
< frame_off
+ len
||
147 frame_end
- dst
< len
)
148 return AVERROR_INVALIDDATA
;
149 for (i
= 0; i
< len
; i
++)
150 dst
[i
] = dst
[frame_off
+ i
];
154 if (dst
- frame
+ SCREEN_WIDE
< frame_off
||
155 dst
- frame
+ SCREEN_WIDE
+ frame_off
< 0 ||
156 frame_end
- dst
< frame_off
+ len
||
157 frame_end
- dst
< len
)
158 return AVERROR_INVALIDDATA
;
159 for (i
= len
- 1; i
>= 0; i
--)
160 dst
[i
] = dst
[frame_off
+ i
];
165 if (source
+ src_len
- src
< len
)
166 return AVERROR_INVALIDDATA
;
167 memcpy(dst
, src
, len
);
171 if (src
- source
< len
)
172 return AVERROR_INVALIDDATA
;
175 memcpy(dst
, src
, len
);
179 val
= forward
? dst
[-1] : dst
[1];
181 memset(dst
, val
, len
);
185 memset(dst
, val
, len
);
197 static int decode_frame(AVCodecContext
*avctx
, void *data
, int *got_frame
,
200 BMVDecContext
* const c
= avctx
->priv_data
;
203 uint8_t *srcptr
, *outptr
;
205 c
->stream
= pkt
->data
;
206 type
= bytestream_get_byte(&c
->stream
);
207 if (type
& BMV_AUDIO
) {
208 int blobs
= bytestream_get_byte(&c
->stream
);
209 if (pkt
->size
< blobs
* 65 + 2) {
210 av_log(avctx
, AV_LOG_ERROR
, "Audio data doesn't fit in frame\n");
211 return AVERROR_INVALIDDATA
;
213 c
->stream
+= blobs
* 65;
215 if (type
& BMV_COMMAND
) {
216 int command_size
= (type
& BMV_PRINT
) ? 8 : 10;
217 if (c
->stream
- pkt
->data
+ command_size
> pkt
->size
) {
218 av_log(avctx
, AV_LOG_ERROR
, "Command data doesn't fit in frame\n");
219 return AVERROR_INVALIDDATA
;
221 c
->stream
+= command_size
;
223 if (type
& BMV_PALETTE
) {
224 if (c
->stream
- pkt
->data
> pkt
->size
- 768) {
225 av_log(avctx
, AV_LOG_ERROR
, "Palette data doesn't fit in frame\n");
226 return AVERROR_INVALIDDATA
;
228 for (i
= 0; i
< 256; i
++)
229 c
->pal
[i
] = bytestream_get_be24(&c
->stream
);
231 if (type
& BMV_SCROLL
) {
232 if (c
->stream
- pkt
->data
> pkt
->size
- 2) {
233 av_log(avctx
, AV_LOG_ERROR
, "Screen offset data doesn't fit in frame\n");
234 return AVERROR_INVALIDDATA
;
236 scr_off
= (int16_t)bytestream_get_le16(&c
->stream
);
237 } else if ((type
& BMV_INTRA
) == BMV_INTRA
) {
244 avctx
->release_buffer(avctx
, &c
->pic
);
246 c
->pic
.reference
= 3;
247 if ((ret
= ff_get_buffer(avctx
, &c
->pic
)) < 0) {
248 av_log(avctx
, AV_LOG_ERROR
, "get_buffer() failed\n");
252 if (decode_bmv_frame(c
->stream
, pkt
->size
- (c
->stream
- pkt
->data
), c
->frame
, scr_off
)) {
253 av_log(avctx
, AV_LOG_ERROR
, "Error decoding frame data\n");
254 return AVERROR_INVALIDDATA
;
257 memcpy(c
->pic
.data
[1], c
->pal
, AVPALETTE_SIZE
);
258 c
->pic
.palette_has_changed
= type
& BMV_PALETTE
;
260 outptr
= c
->pic
.data
[0];
263 for (i
= 0; i
< avctx
->height
; i
++) {
264 memcpy(outptr
, srcptr
, avctx
->width
);
265 srcptr
+= avctx
->width
;
266 outptr
+= c
->pic
.linesize
[0];
270 *(AVFrame
*)data
= c
->pic
;
272 /* always report that the buffer was completely consumed */
276 static av_cold
int decode_init(AVCodecContext
*avctx
)
278 BMVDecContext
* const c
= avctx
->priv_data
;
281 avctx
->pix_fmt
= AV_PIX_FMT_PAL8
;
283 c
->frame
= c
->frame_base
+ 640;
288 static av_cold
int decode_end(AVCodecContext
*avctx
)
290 BMVDecContext
*c
= avctx
->priv_data
;
293 avctx
->release_buffer(avctx
, &c
->pic
);
298 static const int bmv_aud_mults
[16] = {
299 16512, 8256, 4128, 2064, 1032, 516, 258, 192, 129, 88, 64, 56, 48, 40, 36, 32
302 static av_cold
int bmv_aud_decode_init(AVCodecContext
*avctx
)
305 avctx
->channel_layout
= AV_CH_LAYOUT_STEREO
;
306 avctx
->sample_fmt
= AV_SAMPLE_FMT_S16
;
311 static int bmv_aud_decode_frame(AVCodecContext
*avctx
, void *data
,
312 int *got_frame_ptr
, AVPacket
*avpkt
)
314 AVFrame
*frame
= data
;
315 const uint8_t *buf
= avpkt
->data
;
316 int buf_size
= avpkt
->size
;
317 int blocks
= 0, total_blocks
, i
;
319 int16_t *output_samples
;
322 total_blocks
= *buf
++;
323 if (buf_size
< total_blocks
* 65 + 1) {
324 av_log(avctx
, AV_LOG_ERROR
, "expected %d bytes, got %d\n",
325 total_blocks
* 65 + 1, buf_size
);
326 return AVERROR_INVALIDDATA
;
329 /* get output buffer */
330 frame
->nb_samples
= total_blocks
* 32;
331 if ((ret
= ff_get_buffer(avctx
, frame
)) < 0) {
332 av_log(avctx
, AV_LOG_ERROR
, "get_buffer() failed\n");
335 output_samples
= (int16_t *)frame
->data
[0];
337 for (blocks
= 0; blocks
< total_blocks
; blocks
++) {
338 uint8_t code
= *buf
++;
339 code
= (code
>> 1) | (code
<< 7);
340 scale
[0] = bmv_aud_mults
[code
& 0xF];
341 scale
[1] = bmv_aud_mults
[code
>> 4];
342 for (i
= 0; i
< 32; i
++) {
343 *output_samples
++ = av_clip_int16((scale
[0] * (int8_t)*buf
++) >> 5);
344 *output_samples
++ = av_clip_int16((scale
[1] * (int8_t)*buf
++) >> 5);
353 AVCodec ff_bmv_video_decoder
= {
355 .type
= AVMEDIA_TYPE_VIDEO
,
356 .id
= AV_CODEC_ID_BMV_VIDEO
,
357 .priv_data_size
= sizeof(BMVDecContext
),
360 .decode
= decode_frame
,
361 .capabilities
= CODEC_CAP_DR1
,
362 .long_name
= NULL_IF_CONFIG_SMALL("Discworld II BMV video"),
365 AVCodec ff_bmv_audio_decoder
= {
367 .type
= AVMEDIA_TYPE_AUDIO
,
368 .id
= AV_CODEC_ID_BMV_AUDIO
,
369 .init
= bmv_aud_decode_init
,
370 .decode
= bmv_aud_decode_frame
,
371 .capabilities
= CODEC_CAP_DR1
,
372 .long_name
= NULL_IF_CONFIG_SMALL("Discworld II BMV audio"),