libavcodec/bmv.c
Go to the documentation of this file.
1 /*
2  * Discworld II BMV video and audio decoder
3  * Copyright (c) 2011 Konstantin Shishkov
4  *
5  * This file is part of Libav.
6  *
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.
11  *
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.
16  *
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
20  */
21 
22 #include "libavutil/avassert.h"
24 #include "avcodec.h"
25 #include "bytestream.h"
26 #include "internal.h"
27 
28 enum BMVFlags{
29  BMV_NOP = 0,
33 
34  BMV_SCROLL = 0x04,
35  BMV_PALETTE = 0x08,
36  BMV_COMMAND = 0x10,
37  BMV_AUDIO = 0x20,
38  BMV_EXT = 0x40,
39  BMV_PRINT = 0x80
40 };
41 
42 #define SCREEN_WIDE 640
43 #define SCREEN_HIGH 429
44 
45 typedef struct BMVDecContext {
47 
49  uint32_t pal[256];
50  const uint8_t *stream;
52 
53 #define NEXT_BYTE(v) v = forward ? v + 1 : v - 1;
54 
55 static int decode_bmv_frame(const uint8_t *source, int src_len, uint8_t *frame, int frame_off)
56 {
57  unsigned val, saved_val = 0;
58  int tmplen = src_len;
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;
62  int len, mask;
63  int forward = (frame_off <= -SCREEN_WIDE) || (frame_off >= 0);
64  int read_two_nibbles, flag;
65  int advance_mode;
66  int mode = 0;
67  int i;
68 
69  if (src_len <= 0)
70  return AVERROR_INVALIDDATA;
71 
72  if (forward) {
73  src = source;
74  dst = frame;
75  dst_end = frame_end;
76  } else {
77  src = source + src_len - 1;
78  dst = frame_end - 1;
79  dst_end = frame - 1;
80  }
81  for (;;) {
82  int shift = 0;
83  flag = 0;
84 
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.
91  */
92  if (!mode || (tmplen == 4)) {
93  if (src < source || src >= source_end)
94  return AVERROR_INVALIDDATA;
95  val = *src;
96  read_two_nibbles = 1;
97  } else {
98  val = saved_val;
99  read_two_nibbles = 0;
100  }
101  if (!(val & 0xC)) {
102  for (;;) {
103  if(shift>22)
104  return -1;
105  if (!read_two_nibbles) {
106  if (src < source || src >= source_end)
107  return AVERROR_INVALIDDATA;
108  shift += 2;
109  val |= *src << shift;
110  if (*src & 0xC)
111  break;
112  }
113  // two upper bits of the nibble is zero,
114  // so shift top nibble value down into their place
115  read_two_nibbles = 0;
116  shift += 2;
117  mask = (1 << shift) - 1;
118  val = ((val >> 2) & ~mask) | (val & mask);
119  NEXT_BYTE(src);
120  if ((val & (0xC << shift))) {
121  flag = 1;
122  break;
123  }
124  }
125  } else if (mode) {
126  flag = tmplen != 4;
127  }
128  if (flag) {
129  tmplen = 4;
130  } else {
131  saved_val = val >> (4 + shift);
132  tmplen = 0;
133  val &= (1 << (shift + 4)) - 1;
134  NEXT_BYTE(src);
135  }
136  advance_mode = val & 1;
137  len = (val >> 1) - 1;
138  av_assert0(len>0);
139  mode += 1 + advance_mode;
140  if (mode >= 4)
141  mode -= 3;
142  if (len <= 0 || FFABS(dst_end - dst) < len)
143  return AVERROR_INVALIDDATA;
144  switch (mode) {
145  case 1:
146  if (forward) {
147  if (dst - frame + SCREEN_WIDE < frame_off ||
148  dst - frame + SCREEN_WIDE + frame_off < 0 ||
149  frame_end - dst < frame_off + len ||
150  frame_end - dst < len)
151  return AVERROR_INVALIDDATA;
152  for (i = 0; i < len; i++)
153  dst[i] = dst[frame_off + i];
154  dst += len;
155  } else {
156  dst -= len;
157  if (dst - frame + SCREEN_WIDE < frame_off ||
158  dst - frame + SCREEN_WIDE + frame_off < 0 ||
159  frame_end - dst < frame_off + len ||
160  frame_end - dst < len)
161  return AVERROR_INVALIDDATA;
162  for (i = len - 1; i >= 0; i--)
163  dst[i] = dst[frame_off + i];
164  }
165  break;
166  case 2:
167  if (forward) {
168  if (source + src_len - src < len)
169  return AVERROR_INVALIDDATA;
170  memcpy(dst, src, len);
171  dst += len;
172  src += len;
173  } else {
174  if (src - source < len)
175  return AVERROR_INVALIDDATA;
176  dst -= len;
177  src -= len;
178  memcpy(dst, src, len);
179  }
180  break;
181  case 3:
182  val = forward ? dst[-1] : dst[1];
183  if (forward) {
184  memset(dst, val, len);
185  dst += len;
186  } else {
187  dst -= len;
188  memset(dst, val, len);
189  }
190  break;
191  }
192  if (dst == dst_end)
193  return 0;
194  }
195  return 0;
196 }
197 
198 static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
199  AVPacket *pkt)
200 {
201  BMVDecContext * const c = avctx->priv_data;
202  AVFrame *frame = data;
203  int type, scr_off;
204  int i, ret;
205  uint8_t *srcptr, *outptr;
206 
207  c->stream = pkt->data;
208  type = bytestream_get_byte(&c->stream);
209  if (type & BMV_AUDIO) {
210  int blobs = bytestream_get_byte(&c->stream);
211  if (pkt->size < blobs * 65 + 2) {
212  av_log(avctx, AV_LOG_ERROR, "Audio data doesn't fit in frame\n");
213  return AVERROR_INVALIDDATA;
214  }
215  c->stream += blobs * 65;
216  }
217  if (type & BMV_COMMAND) {
218  int command_size = (type & BMV_PRINT) ? 8 : 10;
219  if (c->stream - pkt->data + command_size > pkt->size) {
220  av_log(avctx, AV_LOG_ERROR, "Command data doesn't fit in frame\n");
221  return AVERROR_INVALIDDATA;
222  }
223  c->stream += command_size;
224  }
225  if (type & BMV_PALETTE) {
226  if (c->stream - pkt->data > pkt->size - 768) {
227  av_log(avctx, AV_LOG_ERROR, "Palette data doesn't fit in frame\n");
228  return AVERROR_INVALIDDATA;
229  }
230  for (i = 0; i < 256; i++)
231  c->pal[i] = 0xFFU << 24 | bytestream_get_be24(&c->stream);
232  }
233  if (type & BMV_SCROLL) {
234  if (c->stream - pkt->data > pkt->size - 2) {
235  av_log(avctx, AV_LOG_ERROR, "Screen offset data doesn't fit in frame\n");
236  return AVERROR_INVALIDDATA;
237  }
238  scr_off = (int16_t)bytestream_get_le16(&c->stream);
239  } else if ((type & BMV_INTRA) == BMV_INTRA) {
240  scr_off = -640;
241  } else {
242  scr_off = 0;
243  }
244 
245  if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
246  return ret;
247 
248  if (decode_bmv_frame(c->stream, pkt->size - (c->stream - pkt->data), c->frame, scr_off)) {
249  av_log(avctx, AV_LOG_ERROR, "Error decoding frame data\n");
250  return AVERROR_INVALIDDATA;
251  }
252 
253  memcpy(frame->data[1], c->pal, AVPALETTE_SIZE);
254  frame->palette_has_changed = type & BMV_PALETTE;
255 
256  outptr = frame->data[0];
257  srcptr = c->frame;
258 
259  for (i = 0; i < avctx->height; i++) {
260  memcpy(outptr, srcptr, avctx->width);
261  srcptr += avctx->width;
262  outptr += frame->linesize[0];
263  }
264 
265  *got_frame = 1;
266 
267  /* always report that the buffer was completely consumed */
268  return pkt->size;
269 }
270 
272 {
273  BMVDecContext * const c = avctx->priv_data;
274 
275  c->avctx = avctx;
276  avctx->pix_fmt = AV_PIX_FMT_PAL8;
277 
278  if (avctx->width != SCREEN_WIDE || avctx->height != SCREEN_HIGH) {
279  av_log(avctx, AV_LOG_ERROR, "Invalid dimension %dx%d\n", avctx->width, avctx->height);
280  return AVERROR_INVALIDDATA;
281  }
282 
283  c->frame = c->frame_base + 640;
284 
285  return 0;
286 }
287 
288 static const int bmv_aud_mults[16] = {
289  16512, 8256, 4128, 2064, 1032, 516, 258, 192, 129, 88, 64, 56, 48, 40, 36, 32
290 };
291 
293 {
294  avctx->channels = 2;
296  avctx->sample_fmt = AV_SAMPLE_FMT_S16;
297 
298  return 0;
299 }
300 
302  int *got_frame_ptr, AVPacket *avpkt)
303 {
304  AVFrame *frame = data;
305  const uint8_t *buf = avpkt->data;
306  int buf_size = avpkt->size;
307  int blocks = 0, total_blocks, i;
308  int ret;
309  int16_t *output_samples;
310  int scale[2];
311 
312  total_blocks = *buf++;
313  if (buf_size < total_blocks * 65 + 1) {
314  av_log(avctx, AV_LOG_ERROR, "expected %d bytes, got %d\n",
315  total_blocks * 65 + 1, buf_size);
316  return AVERROR_INVALIDDATA;
317  }
318 
319  /* get output buffer */
320  frame->nb_samples = total_blocks * 32;
321  if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
322  return ret;
323  output_samples = (int16_t *)frame->data[0];
324 
325  for (blocks = 0; blocks < total_blocks; blocks++) {
326  uint8_t code = *buf++;
327  code = (code >> 1) | (code << 7);
328  scale[0] = bmv_aud_mults[code & 0xF];
329  scale[1] = bmv_aud_mults[code >> 4];
330  for (i = 0; i < 32; i++) {
331  *output_samples++ = av_clip_int16((scale[0] * (int8_t)*buf++) >> 5);
332  *output_samples++ = av_clip_int16((scale[1] * (int8_t)*buf++) >> 5);
333  }
334  }
335 
336  *got_frame_ptr = 1;
337 
338  return buf_size;
339 }
340 
342  .name = "bmv_video",
343  .type = AVMEDIA_TYPE_VIDEO,
344  .id = AV_CODEC_ID_BMV_VIDEO,
345  .priv_data_size = sizeof(BMVDecContext),
346  .init = decode_init,
347  .decode = decode_frame,
348  .capabilities = CODEC_CAP_DR1,
349  .long_name = NULL_IF_CONFIG_SMALL("Discworld II BMV video"),
350 };
351 
353  .name = "bmv_audio",
354  .type = AVMEDIA_TYPE_AUDIO,
355  .id = AV_CODEC_ID_BMV_AUDIO,
356  .init = bmv_aud_decode_init,
357  .decode = bmv_aud_decode_frame,
358  .capabilities = CODEC_CAP_DR1,
359  .long_name = NULL_IF_CONFIG_SMALL("Discworld II BMV audio"),
360 };
static int bmv_aud_decode_frame(AVCodecContext *avctx, void *data, int *got_frame_ptr, AVPacket *avpkt)
AVCodec ff_bmv_video_decoder
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
static int shift(int a, int b)
Definition: sonic.c:86
This structure describes decoded (raw) audio or video data.
Definition: frame.h:76
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
AVCodec ff_bmv_audio_decoder
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
const uint8_t * stream
#define AV_CH_LAYOUT_STEREO
signed 16 bits
Definition: samplefmt.h:52
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *pkt)
AVCodecContext * avctx
struct BMVDecContext BMVDecContext
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
enum AVSampleFormat sample_fmt
audio sample format
uint8_t
#define av_cold
Definition: attributes.h:78
8 bit with PIX_FMT_RGB32 palette
Definition: pixfmt.h:79
mode
Definition: f_perms.c:27
#define AVPALETTE_SIZE
Definition: pixfmt.h:33
static AVPacket pkt
Definition: demuxing.c:56
#define CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
uint8_t * data
static int decode_bmv_frame(const uint8_t *source, int src_len, uint8_t *frame, int frame_off)
static const uint16_t mask[17]
Definition: lzw.c:37
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Spectrum Plot time data
simple assert() macros that are a bit more flexible than ISO C assert().
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
const char * name
Name of the codec implementation.
#define NEXT_BYTE(v)
#define SCREEN_HIGH
external API header
uint64_t channel_layout
Audio channel layout.
audio channel layout utility functions
ret
Definition: avfilter.c:821
int width
picture width / height.
static av_cold int decode_init(AVCodecContext *avctx)
static const int bmv_aud_mults[16]
#define FFABS(a)
Definition: common.h:53
#define SCREEN_WIDE
or the Software in violation of any applicable export control laws in any jurisdiction Except as provided by mandatorily applicable UPF has no obligation to provide you with source code to the Software In the event Software contains any source code
AVS_Value src
Definition: avisynth_c.h:523
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:101
main external API structure.
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
uint32_t pal[256]
void * buf
Definition: avisynth_c.h:594
synthesis window for stochastic i
int palette_has_changed
Tell user application that palette has changed from previous frame.
Definition: frame.h:280
BMVFlags
#define type
uint8_t * frame
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:87
common internal api header.
static double c[64]
Same thing on a dB scale
int len
int channels
number of audio channels
else dst[i][x+y *dst_stride[i]]
Definition: vf_mcdeint.c:160
static int decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: crystalhd.c:868
static av_cold int bmv_aud_decode_init(AVCodecContext *avctx)
uint8_t frame_base[SCREEN_WIDE *(SCREEN_HIGH+1)]
This structure stores compressed data.
int nb_samples
number of audio samples (per channel) described by this frame
Definition: frame.h:127
for(j=16;j >0;--j)