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
41
46
47 #define VMD_HEADER_SIZE 0x330
48 #define PALETTE_COUNT 256
49
51
54
55 const unsigned char *
buf;
57
61
64
65 #define QUEUE_SIZE 0x1000
66 #define QUEUE_MASK 0x0FFF
67
69 unsigned char *dest, int dest_len)
70 {
71 unsigned char *d;
72 unsigned char *d_end;
74 unsigned int qpos;
75 unsigned int dataleft;
76 unsigned int chainofs;
77 unsigned int chainlen;
78 unsigned int speclen;
82
84 d = dest;
85 d_end = d + dest_len;
86 dataleft = bytestream2_get_le32(&gb);
90 if (bytestream2_peek_le32(&gb) == 0x56781234) {
92 qpos = 0x111;
93 speclen = 0xF + 3;
94 } else {
95 qpos = 0xFEE;
96 speclen = 100; /* no speclen */
97 }
98
100 tag = bytestream2_get_byteu(&gb);
101 if ((
tag == 0xFF) && (dataleft > 8)) {
104 for (
i = 0;
i < 8;
i++) {
105 queue[qpos++] = *d++ = bytestream2_get_byteu(&gb);
107 }
108 dataleft -= 8;
109 } else {
110 for (
i = 0;
i < 8;
i++) {
111 if (dataleft == 0)
112 break;
116 queue[qpos++] = *d++ = bytestream2_get_byteu(&gb);
118 dataleft--;
119 } else {
120 chainofs = bytestream2_get_byte(&gb);
121 chainofs |= ((bytestream2_peek_byte(&gb) & 0xF0) << 4);
122 chainlen = (bytestream2_get_byte(&gb) & 0x0F) + 3;
123 if (chainlen == speclen) {
124 chainlen = bytestream2_get_byte(&gb) + 0xF + 3;
125 }
126 if (d_end - d < chainlen)
128 for (j = 0; j < chainlen; j++) {
130 queue[qpos++] = *d++;
132 }
133 dataleft -= chainlen;
134 }
136 }
137 }
138 }
139 return d - dest;
140 }
142 int src_count, int src_size, int dest_len)
143 {
144 unsigned char *pd;
146 unsigned char *dest_end = dest + dest_len;
148 uint16_t run_val;
149
151 pd = dest;
152 if (src_count & 1) {
154 return 0;
155 *pd++ = bytestream2_get_byteu(&gb);
156 used++;
157 }
158
159 do {
161 break;
162 l = bytestream2_get_byteu(&gb);
163 if (l & 0x80) {
164 l = (l & 0x7F) * 2;
168 pd += l;
169 } else {
173 for (
i = 0;
i < l;
i++) {
175 pd += 2;
176 }
177 l *= 2;
178 }
179 used += l;
180 } while (used < src_count);
181
183 }
184
186 {
188 unsigned int *palette32;
189 unsigned char r,
g,
b;
190
192
193 unsigned char meth;
194 unsigned char *dp; /* pointer to current frame */
195 unsigned char *pp; /* pointer to previous frame */
197 int ofs;
198
199 int frame_x, frame_y, prev_linesize;
200 int frame_width, frame_height;
201
204 frame_width =
AV_RL16(&
s->buf[10]) - frame_x + 1;
205 frame_height =
AV_RL16(&
s->buf[12]) - frame_y + 1;
206
207 if ((frame_width ==
s->avctx->width && frame_height ==
s->avctx->height) &&
208 (frame_x || frame_y)) {
209
212 }
215
216 if (frame_x < 0 || frame_width < 0 ||
217 frame_x >=
s->avctx->width ||
218 frame_width >
s->avctx->width ||
219 frame_x + frame_width >
s->avctx->width) {
221 "Invalid horizontal range %d-%d\n",
222 frame_x, frame_width);
224 }
225 if (frame_y < 0 || frame_height < 0 ||
226 frame_y >=
s->avctx->height ||
227 frame_height >
s->avctx->height ||
228 frame_y + frame_height >
s->avctx->height) {
230 "Invalid vertical range %d-%d\n",
231 frame_y, frame_height);
233 }
234
235 /* if only a certain region will be updated, copy the entire previous
236 * frame before the decode */
237 if (
s->prev_frame->data[0] &&
238 (frame_x || frame_y || (frame_width !=
s->avctx->width) ||
239 (frame_height !=
s->avctx->height))) {
240
241 memcpy(
frame->data[0],
s->prev_frame->data[0],
242 s->avctx->height *
frame->linesize[0]);
243 }
244
245 /* check if there is a new palette */
247 if (
s->buf[15] & 0x02) {
249 palette32 = (
unsigned int *)
s->palette;
252 r = bytestream2_get_byteu(&gb) * 4;
253 g = bytestream2_get_byteu(&gb) * 4;
254 b = bytestream2_get_byteu(&gb) * 4;
255 palette32[
i] = 0xFF
U << 24 | (
r << 16) | (
g << 8) | (
b);
256 palette32[
i] |= palette32[
i] >> 6 & 0x30303;
257 }
258 } else {
261 }
262 }
263
265 return 0;
266
267 /* originally UnpackFrame in VAG's code */
270 meth = bytestream2_get_byteu(&gb);
271 if (meth & 0x80) {
273 if (!
s->unpack_buffer_size) {
275 "Trying to unpack LZ-compressed frame with no LZ buffer\n");
277 }
279 s->unpack_buffer,
s->unpack_buffer_size);
282 meth &= 0x7F;
284 }
285
286 dp = &
frame->data[0][frame_y *
frame->linesize[0] + frame_x];
287 if (
s->prev_frame->data[0]) {
288 prev_linesize =
s->prev_frame->linesize[0];
289 pp =
s->prev_frame->data[0] + frame_y * prev_linesize + frame_x;
290 } else {
292 prev_linesize = 0;
293 }
294 switch (meth) {
295 case 1:
296 for (
i = 0;
i < frame_height;
i++) {
297 ofs = 0;
298 do {
299 len = bytestream2_get_byte(&gb);
302 if (ofs +
len > frame_width ||
307 } else {
308 /* interframe pixel copy */
309 if (ofs +
len + 1 > frame_width || !pp)
311 memcpy(&dp[ofs], &pp[ofs],
len + 1);
313 }
314 } while (ofs < frame_width);
315 if (ofs > frame_width) {
317 "offset > width (%d > %d)\n",
318 ofs, frame_width);
320 }
321 dp +=
frame->linesize[0];
323 }
324 break;
325
326 case 2:
327 for (
i = 0;
i < frame_height;
i++) {
329 dp +=
frame->linesize[0];
330 }
331 break;
332
333 case 3:
334 for (
i = 0;
i < frame_height;
i++) {
335 ofs = 0;
336 do {
337 len = bytestream2_get_byte(&gb);
340 if (bytestream2_peek_byte(&gb) == 0xFF) {
342 bytestream2_get_byte(&gb);
345 frame_width - ofs);
346 ofs += slen;
348 } else {
349 if (ofs +
len > frame_width ||
354 }
355 } else {
356 /* interframe pixel copy */
357 if (ofs +
len + 1 > frame_width || !pp)
359 memcpy(&dp[ofs], &pp[ofs],
len + 1);
361 }
362 } while (ofs < frame_width);
363 if (ofs > frame_width) {
365 "offset > width (%d > %d)\n",
366 ofs, frame_width);
368 }
369 dp +=
frame->linesize[0];
371 }
372 break;
373 }
374 return 0;
375 }
376
378 {
380
383 s->unpack_buffer_size = 0;
384
385 return 0;
386 }
387
389 {
392 unsigned int *palette32;
393 int palette_index = 0;
394 unsigned char r,
g,
b;
395 unsigned char *vmd_header;
396 unsigned char *raw_palette;
397
400
401 /* make sure the VMD header made it */
406 }
407 vmd_header = (
unsigned char *)avctx->
extradata;
408
409 s->unpack_buffer_size =
AV_RL32(&vmd_header[800]);
410 if (
s->unpack_buffer_size) {
411 s->unpack_buffer =
av_malloc(
s->unpack_buffer_size);
412 if (!
s->unpack_buffer)
414 }
415
416 /* load up the initial palette */
417 raw_palette = &vmd_header[28];
418 palette32 = (
unsigned int *)
s->palette;
420 r = raw_palette[palette_index++] * 4;
421 g = raw_palette[palette_index++] * 4;
422 b = raw_palette[palette_index++] * 4;
423 palette32[
i] = 0xFF
U << 24 | (
r << 16) | (
g << 8) | (
b);
424 palette32[
i] |= palette32[
i] >> 6 & 0x30303;
425 }
426
430
431 return 0;
432 }
433
436 {
437 const uint8_t *buf = avpkt->
data;
438 int buf_size = avpkt->
size;
441
444
445 if (buf_size < 16)
447
450
453
454 /* make the palette available on the way out */
456
457 /* shuffle frames */
460
461 *got_frame = 1;
462
463 /* report that the buffer was completely consumed */
464 return buf_size;
465 }
466
468 .
p.
name =
"vmdvideo",
478 };