FFmpeg
vmdvideo.c
Go to the documentation of this file.
1 /*
2  * Sierra VMD video decoder
3  * Copyright (c) 2004 The FFmpeg Project
4  *
5  * This file is part of FFmpeg.
6  *
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.
11  *
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.
16  *
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
20  */
21 
22 /**
23  * @file
24  * Sierra VMD video decoder
25  * by Vladimir "VAG" Gneushev (vagsoft at mail.ru)
26  * for more information on the Sierra VMD format, visit:
27  * http://www.pcisys.net/~melanson/codecs/
28  *
29  * The video decoder outputs PAL8 colorspace data. The decoder expects
30  * a 0x330-byte VMD file header to be transmitted via extradata during
31  * codec initialization. Each encoded frame that is sent to this decoder
32  * is expected to be prepended with the appropriate 16-byte frame
33  * information record from the VMD file.
34  */
35 
36 #include <string.h>
37 
38 #include "libavutil/common.h"
39 #include "libavutil/intreadwrite.h"
40 
41 #include "avcodec.h"
42 #include "internal.h"
43 #include "bytestream.h"
44 
45 #define VMD_HEADER_SIZE 0x330
46 #define PALETTE_COUNT 256
47 
48 typedef struct VmdVideoContext {
49 
52 
53  const unsigned char *buf;
54  int size;
55 
56  unsigned char palette[PALETTE_COUNT * 4];
57  unsigned char *unpack_buffer;
59 
60  int x_off, y_off;
62 
63 #define QUEUE_SIZE 0x1000
64 #define QUEUE_MASK 0x0FFF
65 
66 static int lz_unpack(const unsigned char *src, int src_len,
67  unsigned char *dest, int dest_len)
68 {
69  unsigned char *d;
70  unsigned char *d_end;
71  unsigned char queue[QUEUE_SIZE];
72  unsigned int qpos;
73  unsigned int dataleft;
74  unsigned int chainofs;
75  unsigned int chainlen;
76  unsigned int speclen;
77  unsigned char tag;
78  unsigned int i, j;
79  GetByteContext gb;
80 
81  bytestream2_init(&gb, src, src_len);
82  d = dest;
83  d_end = d + dest_len;
84  dataleft = bytestream2_get_le32(&gb);
85  memset(queue, 0x20, QUEUE_SIZE);
86  if (bytestream2_get_bytes_left(&gb) < 4)
87  return AVERROR_INVALIDDATA;
88  if (bytestream2_peek_le32(&gb) == 0x56781234) {
89  bytestream2_skipu(&gb, 4);
90  qpos = 0x111;
91  speclen = 0xF + 3;
92  } else {
93  qpos = 0xFEE;
94  speclen = 100; /* no speclen */
95  }
96 
97  while (dataleft > 0 && bytestream2_get_bytes_left(&gb) > 0) {
98  tag = bytestream2_get_byteu(&gb);
99  if ((tag == 0xFF) && (dataleft > 8)) {
100  if (d_end - d < 8 || bytestream2_get_bytes_left(&gb) < 8)
101  return AVERROR_INVALIDDATA;
102  for (i = 0; i < 8; i++) {
103  queue[qpos++] = *d++ = bytestream2_get_byteu(&gb);
104  qpos &= QUEUE_MASK;
105  }
106  dataleft -= 8;
107  } else {
108  for (i = 0; i < 8; i++) {
109  if (dataleft == 0)
110  break;
111  if (tag & 0x01) {
112  if (d_end - d < 1 || bytestream2_get_bytes_left(&gb) < 1)
113  return AVERROR_INVALIDDATA;
114  queue[qpos++] = *d++ = bytestream2_get_byteu(&gb);
115  qpos &= QUEUE_MASK;
116  dataleft--;
117  } else {
118  chainofs = bytestream2_get_byte(&gb);
119  chainofs |= ((bytestream2_peek_byte(&gb) & 0xF0) << 4);
120  chainlen = (bytestream2_get_byte(&gb) & 0x0F) + 3;
121  if (chainlen == speclen) {
122  chainlen = bytestream2_get_byte(&gb) + 0xF + 3;
123  }
124  if (d_end - d < chainlen)
125  return AVERROR_INVALIDDATA;
126  for (j = 0; j < chainlen; j++) {
127  *d = queue[chainofs++ & QUEUE_MASK];
128  queue[qpos++] = *d++;
129  qpos &= QUEUE_MASK;
130  }
131  dataleft -= chainlen;
132  }
133  tag >>= 1;
134  }
135  }
136  }
137  return d - dest;
138 }
139 static int rle_unpack(const unsigned char *src, unsigned char *dest,
140  int src_count, int src_size, int dest_len)
141 {
142  unsigned char *pd;
143  int i, l, used = 0;
144  unsigned char *dest_end = dest + dest_len;
145  GetByteContext gb;
146  uint16_t run_val;
147 
148  bytestream2_init(&gb, src, src_size);
149  pd = dest;
150  if (src_count & 1) {
151  if (bytestream2_get_bytes_left(&gb) < 1)
152  return 0;
153  *pd++ = bytestream2_get_byteu(&gb);
154  used++;
155  }
156 
157  do {
158  if (bytestream2_get_bytes_left(&gb) < 1)
159  break;
160  l = bytestream2_get_byteu(&gb);
161  if (l & 0x80) {
162  l = (l & 0x7F) * 2;
163  if (dest_end - pd < l || bytestream2_get_bytes_left(&gb) < l)
164  return bytestream2_tell(&gb);
165  bytestream2_get_bufferu(&gb, pd, l);
166  pd += l;
167  } else {
168  if (dest_end - pd < 2*l || bytestream2_get_bytes_left(&gb) < 2)
169  return bytestream2_tell(&gb);
170  run_val = bytestream2_get_ne16(&gb);
171  for (i = 0; i < l; i++) {
172  AV_WN16(pd, run_val);
173  pd += 2;
174  }
175  l *= 2;
176  }
177  used += l;
178  } while (used < src_count);
179 
180  return bytestream2_tell(&gb);
181 }
182 
184 {
185  int i;
186  unsigned int *palette32;
187  unsigned char r, g, b;
188 
189  GetByteContext gb;
190 
191  unsigned char meth;
192  unsigned char *dp; /* pointer to current frame */
193  unsigned char *pp; /* pointer to previous frame */
194  unsigned char len;
195  int ofs;
196 
197  int frame_x, frame_y;
198  int frame_width, frame_height;
199 
200  frame_x = AV_RL16(&s->buf[6]);
201  frame_y = AV_RL16(&s->buf[8]);
202  frame_width = AV_RL16(&s->buf[10]) - frame_x + 1;
203  frame_height = AV_RL16(&s->buf[12]) - frame_y + 1;
204 
205  if ((frame_width == s->avctx->width && frame_height == s->avctx->height) &&
206  (frame_x || frame_y)) {
207 
208  s->x_off = frame_x;
209  s->y_off = frame_y;
210  }
211  frame_x -= s->x_off;
212  frame_y -= s->y_off;
213 
214  if (frame_x < 0 || frame_width < 0 ||
215  frame_x >= s->avctx->width ||
216  frame_width > s->avctx->width ||
217  frame_x + frame_width > s->avctx->width) {
219  "Invalid horizontal range %d-%d\n",
220  frame_x, frame_width);
221  return AVERROR_INVALIDDATA;
222  }
223  if (frame_y < 0 || frame_height < 0 ||
224  frame_y >= s->avctx->height ||
225  frame_height > s->avctx->height ||
226  frame_y + frame_height > s->avctx->height) {
228  "Invalid vertical range %d-%d\n",
229  frame_x, frame_width);
230  return AVERROR_INVALIDDATA;
231  }
232 
233  /* if only a certain region will be updated, copy the entire previous
234  * frame before the decode */
235  if (s->prev_frame->data[0] &&
236  (frame_x || frame_y || (frame_width != s->avctx->width) ||
237  (frame_height != s->avctx->height))) {
238 
239  memcpy(frame->data[0], s->prev_frame->data[0],
240  s->avctx->height * frame->linesize[0]);
241  }
242 
243  /* check if there is a new palette */
244  bytestream2_init(&gb, s->buf + 16, s->size - 16);
245  if (s->buf[15] & 0x02) {
246  bytestream2_skip(&gb, 2);
247  palette32 = (unsigned int *)s->palette;
249  for (i = 0; i < PALETTE_COUNT; i++) {
250  r = bytestream2_get_byteu(&gb) * 4;
251  g = bytestream2_get_byteu(&gb) * 4;
252  b = bytestream2_get_byteu(&gb) * 4;
253  palette32[i] = 0xFFU << 24 | (r << 16) | (g << 8) | (b);
254  palette32[i] |= palette32[i] >> 6 & 0x30303;
255  }
256  } else {
257  av_log(s->avctx, AV_LOG_ERROR, "Incomplete palette\n");
258  return AVERROR_INVALIDDATA;
259  }
260  }
261 
262  if (!s->size)
263  return 0;
264 
265  /* originally UnpackFrame in VAG's code */
266  if (bytestream2_get_bytes_left(&gb) < 1)
267  return AVERROR_INVALIDDATA;
268  meth = bytestream2_get_byteu(&gb);
269  if (meth & 0x80) {
270  int size;
271  if (!s->unpack_buffer_size) {
273  "Trying to unpack LZ-compressed frame with no LZ buffer\n");
274  return AVERROR_INVALIDDATA;
275  }
278  if (size < 0)
279  return size;
280  meth &= 0x7F;
281  bytestream2_init(&gb, s->unpack_buffer, size);
282  }
283 
284  dp = &frame->data[0][frame_y * frame->linesize[0] + frame_x];
285  pp = &s->prev_frame->data[0][frame_y * s->prev_frame->linesize[0] + frame_x];
286  switch (meth) {
287  case 1:
288  for (i = 0; i < frame_height; i++) {
289  ofs = 0;
290  do {
291  len = bytestream2_get_byte(&gb);
292  if (len & 0x80) {
293  len = (len & 0x7F) + 1;
294  if (ofs + len > frame_width ||
296  return AVERROR_INVALIDDATA;
297  bytestream2_get_bufferu(&gb, &dp[ofs], len);
298  ofs += len;
299  } else {
300  /* interframe pixel copy */
301  if (ofs + len + 1 > frame_width || !s->prev_frame->data[0])
302  return AVERROR_INVALIDDATA;
303  memcpy(&dp[ofs], &pp[ofs], len + 1);
304  ofs += len + 1;
305  }
306  } while (ofs < frame_width);
307  if (ofs > frame_width) {
309  "offset > width (%d > %d)\n",
310  ofs, frame_width);
311  return AVERROR_INVALIDDATA;
312  }
313  dp += frame->linesize[0];
314  pp += s->prev_frame->linesize[0];
315  }
316  break;
317 
318  case 2:
319  for (i = 0; i < frame_height; i++) {
320  bytestream2_get_buffer(&gb, dp, frame_width);
321  dp += frame->linesize[0];
322  pp += s->prev_frame->linesize[0];
323  }
324  break;
325 
326  case 3:
327  for (i = 0; i < frame_height; i++) {
328  ofs = 0;
329  do {
330  len = bytestream2_get_byte(&gb);
331  if (len & 0x80) {
332  len = (len & 0x7F) + 1;
333  if (bytestream2_peek_byte(&gb) == 0xFF) {
334  int slen = len;
335  bytestream2_get_byte(&gb);
336  len = rle_unpack(gb.buffer, &dp[ofs],
337  len, bytestream2_get_bytes_left(&gb),
338  frame_width - ofs);
339  ofs += slen;
340  bytestream2_skip(&gb, len);
341  } else {
342  if (ofs + len > frame_width ||
343  bytestream2_get_bytes_left(&gb) < len)
344  return AVERROR_INVALIDDATA;
345  bytestream2_get_buffer(&gb, &dp[ofs], len);
346  ofs += len;
347  }
348  } else {
349  /* interframe pixel copy */
350  if (ofs + len + 1 > frame_width || !s->prev_frame->data[0])
351  return AVERROR_INVALIDDATA;
352  memcpy(&dp[ofs], &pp[ofs], len + 1);
353  ofs += len + 1;
354  }
355  } while (ofs < frame_width);
356  if (ofs > frame_width) {
358  "offset > width (%d > %d)\n",
359  ofs, frame_width);
360  return AVERROR_INVALIDDATA;
361  }
362  dp += frame->linesize[0];
363  pp += s->prev_frame->linesize[0];
364  }
365  break;
366  }
367  return 0;
368 }
369 
371 {
372  VmdVideoContext *s = avctx->priv_data;
373 
375  av_freep(&s->unpack_buffer);
376  s->unpack_buffer_size = 0;
377 
378  return 0;
379 }
380 
382 {
383  VmdVideoContext *s = avctx->priv_data;
384  int i;
385  unsigned int *palette32;
386  int palette_index = 0;
387  unsigned char r, g, b;
388  unsigned char *vmd_header;
389  unsigned char *raw_palette;
390 
391  s->avctx = avctx;
392  avctx->pix_fmt = AV_PIX_FMT_PAL8;
393 
394  /* make sure the VMD header made it */
395  if (s->avctx->extradata_size != VMD_HEADER_SIZE) {
396  av_log(s->avctx, AV_LOG_ERROR, "expected extradata size of %d\n",
398  return AVERROR_INVALIDDATA;
399  }
400  vmd_header = (unsigned char *)avctx->extradata;
401 
402  s->unpack_buffer_size = AV_RL32(&vmd_header[800]);
403  if (s->unpack_buffer_size) {
405  if (!s->unpack_buffer)
406  return AVERROR(ENOMEM);
407  }
408 
409  /* load up the initial palette */
410  raw_palette = &vmd_header[28];
411  palette32 = (unsigned int *)s->palette;
412  for (i = 0; i < PALETTE_COUNT; i++) {
413  r = raw_palette[palette_index++] * 4;
414  g = raw_palette[palette_index++] * 4;
415  b = raw_palette[palette_index++] * 4;
416  palette32[i] = 0xFFU << 24 | (r << 16) | (g << 8) | (b);
417  palette32[i] |= palette32[i] >> 6 & 0x30303;
418  }
419 
420  s->prev_frame = av_frame_alloc();
421  if (!s->prev_frame) {
422  vmdvideo_decode_end(avctx);
423  return AVERROR(ENOMEM);
424  }
425 
426  return 0;
427 }
428 
430  void *data, int *got_frame,
431  AVPacket *avpkt)
432 {
433  const uint8_t *buf = avpkt->data;
434  int buf_size = avpkt->size;
435  VmdVideoContext *s = avctx->priv_data;
436  AVFrame *frame = data;
437  int ret;
438 
439  s->buf = buf;
440  s->size = buf_size;
441 
442  if (buf_size < 16)
443  return AVERROR_INVALIDDATA;
444 
445  if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
446  return ret;
447 
448  if ((ret = vmd_decode(s, frame)) < 0)
449  return ret;
450 
451  /* make the palette available on the way out */
452  memcpy(frame->data[1], s->palette, PALETTE_COUNT * 4);
453 
454  /* shuffle frames */
456  if ((ret = av_frame_ref(s->prev_frame, frame)) < 0)
457  return ret;
458 
459  *got_frame = 1;
460 
461  /* report that the buffer was completely consumed */
462  return buf_size;
463 }
464 
466  .name = "vmdvideo",
467  .long_name = NULL_IF_CONFIG_SMALL("Sierra VMD video"),
468  .type = AVMEDIA_TYPE_VIDEO,
469  .id = AV_CODEC_ID_VMDVIDEO,
470  .priv_data_size = sizeof(VmdVideoContext),
472  .close = vmdvideo_decode_end,
474  .capabilities = AV_CODEC_CAP_DR1,
475 };
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
This structure describes decoded (raw) audio or video data.
Definition: frame.h:268
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
AVFrame * prev_frame
Definition: vmdvideo.c:51
const char * g
Definition: vf_curves.c:115
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
int size
Definition: avcodec.h:1478
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1775
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:133
#define src
Definition: vp8dsp.c:254
AVCodec.
Definition: avcodec.h:3477
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_RL16
Definition: bytestream.h:87
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, FILE *outfile)
Definition: decode_audio.c:42
static av_always_inline unsigned int bytestream2_get_bufferu(GetByteContext *g, uint8_t *dst, unsigned int size)
Definition: bytestream.h:273
AVCodecContext * avctx
Definition: vmdvideo.c:50
uint8_t
#define av_cold
Definition: attributes.h:82
#define av_malloc(s)
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:189
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:77
int av_frame_ref(AVFrame *dst, const AVFrame *src)
Set up a new reference to the data described by the source frame.
Definition: frame.c:443
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:1666
AVCodec ff_vmdvideo_decoder
Definition: vmdvideo.c:465
uint8_t * data
Definition: avcodec.h:1477
const uint8_t * buffer
Definition: bytestream.h:34
unsigned char * unpack_buffer
Definition: vmdvideo.c:57
uint32_t tag
Definition: movenc.c:1496
static av_always_inline void bytestream2_skipu(GetByteContext *g, unsigned int size)
Definition: bytestream.h:170
static int vmdvideo_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: vmdvideo.c:429
unsigned char palette[PALETTE_COUNT *4]
Definition: vmdvideo.c:56
#define av_log(a,...)
static av_cold int vmdvideo_decode_end(AVCodecContext *avctx)
Definition: vmdvideo.c:370
#define U(x)
Definition: vp56_arith.h:37
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:260
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:164
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:202
#define bytestream2_get_ne16
Definition: bytestream.h:115
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
const char * r
Definition: vf_curves.c:114
static av_always_inline unsigned int bytestream2_get_buffer(GetByteContext *g, uint8_t *dst, unsigned int size)
Definition: bytestream.h:263
int unpack_buffer_size
Definition: vmdvideo.c:58
static av_always_inline unsigned int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:154
const unsigned char * buf
Definition: vmdvideo.c:53
const char * name
Name of the codec implementation.
Definition: avcodec.h:3484
static int vmd_decode(VmdVideoContext *s, AVFrame *frame)
Definition: vmdvideo.c:183
static av_cold int vmdvideo_decode_init(AVCodecContext *avctx)
Definition: vmdvideo.c:381
#define b
Definition: input.c:41
#define PALETTE_COUNT
Definition: vmdvideo.c:46
int width
picture width / height.
Definition: avcodec.h:1738
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
#define s(width, name)
Definition: cbs_vp9.c:257
#define QUEUE_MASK
Definition: vmdvideo.c:64
if(ret)
static av_always_inline int bytestream2_tell(GetByteContext *g)
Definition: bytestream.h:188
Libavcodec external API header.
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:299
main external API structure.
Definition: avcodec.h:1565
#define QUEUE_SIZE
Definition: vmdvideo.c:63
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1964
int extradata_size
Definition: avcodec.h:1667
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:553
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:282
common internal api header.
common internal and external API header
void * priv_data
Definition: avcodec.h:1592
int len
#define av_freep(p)
#define AV_WN16(p, v)
Definition: intreadwrite.h:372
static int rle_unpack(const unsigned char *src, unsigned char *dest, int src_count, int src_size, int dest_len)
Definition: vmdvideo.c:139
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_RL32
Definition: bytestream.h:87
This structure stores compressed data.
Definition: avcodec.h:1454
#define AV_GET_BUFFER_FLAG_REF
The decoder will keep a reference to the frame and may reuse it later.
Definition: avcodec.h:1176
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:981
static int lz_unpack(const unsigned char *src, int src_len, unsigned char *dest, int dest_len)
Definition: vmdvideo.c:66
for(j=16;j >0;--j)
#define VMD_HEADER_SIZE
Definition: vmdvideo.c:45