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
40
45
46 #define VMD_HEADER_SIZE 0x330
47 #define PALETTE_COUNT 256
48
50
53
54 const unsigned char *
buf;
56
60
63
64 #define QUEUE_SIZE 0x1000
65 #define QUEUE_MASK 0x0FFF
66
68 unsigned char *dest, int dest_len)
69 {
71 unsigned char *d_end;
73 unsigned int qpos;
74 unsigned int dataleft;
75 unsigned int chainofs;
76 unsigned int chainlen;
77 unsigned int speclen;
81
85 dataleft = bytestream2_get_le32(&gb);
89 if (bytestream2_peek_le32(&gb) == 0x56781234) {
91 qpos = 0x111;
92 speclen = 0xF + 3;
93 } else {
94 qpos = 0xFEE;
95 speclen = 100; /* no speclen */
96 }
97
99 tag = bytestream2_get_byteu(&gb);
100 if ((
tag == 0xFF) && (dataleft > 8)) {
103 for (
i = 0;
i < 8;
i++) {
104 queue[qpos++] = *
d++ = bytestream2_get_byteu(&gb);
106 }
107 dataleft -= 8;
108 } else {
109 for (
i = 0;
i < 8;
i++) {
110 if (dataleft == 0)
111 break;
115 queue[qpos++] = *
d++ = bytestream2_get_byteu(&gb);
117 dataleft--;
118 } else {
119 chainofs = bytestream2_get_byte(&gb);
120 chainofs |= ((bytestream2_peek_byte(&gb) & 0xF0) << 4);
121 chainlen = (bytestream2_get_byte(&gb) & 0x0F) + 3;
122 if (chainlen == speclen) {
123 chainlen = bytestream2_get_byte(&gb) + 0xF + 3;
124 }
125 if (d_end -
d < chainlen)
127 for (j = 0; j < chainlen; j++) {
129 queue[qpos++] = *
d++;
131 }
132 dataleft -= chainlen;
133 }
135 }
136 }
137 }
139 }
141 int src_count, int src_size, int dest_len)
142 {
143 unsigned char *pd;
145 unsigned char *dest_end = dest + dest_len;
147 uint16_t run_val;
148
150 pd = dest;
151 if (src_count & 1) {
153 return 0;
154 *pd++ = bytestream2_get_byteu(&gb);
155 used++;
156 }
157
158 do {
160 break;
161 l = bytestream2_get_byteu(&gb);
162 if (l & 0x80) {
163 l = (l & 0x7F) * 2;
167 pd += l;
168 } else {
172 for (
i = 0;
i < l;
i++) {
174 pd += 2;
175 }
176 l *= 2;
177 }
178 used += l;
179 } while (used < src_count);
180
182 }
183
185 {
187 unsigned int *palette32;
188 unsigned char r,
g,
b;
189
191
192 unsigned char meth;
193 unsigned char *dp; /* pointer to current frame */
194 unsigned char *pp; /* pointer to previous frame */
196 int ofs;
197
198 int frame_x, frame_y, prev_linesize;
199 int frame_width, frame_height;
200
203 frame_width =
AV_RL16(&
s->buf[10]) - frame_x + 1;
204 frame_height =
AV_RL16(&
s->buf[12]) - frame_y + 1;
205
206 if ((frame_width ==
s->avctx->width && frame_height ==
s->avctx->height) &&
207 (frame_x || frame_y)) {
208
211 }
214
215 if (frame_x < 0 || frame_width < 0 ||
216 frame_x >=
s->avctx->width ||
217 frame_width >
s->avctx->width ||
218 frame_x + frame_width >
s->avctx->width) {
220 "Invalid horizontal range %d-%d\n",
221 frame_x, frame_width);
223 }
224 if (frame_y < 0 || frame_height < 0 ||
225 frame_y >=
s->avctx->height ||
226 frame_height >
s->avctx->height ||
227 frame_y + frame_height >
s->avctx->height) {
229 "Invalid vertical range %d-%d\n",
230 frame_y, frame_height);
232 }
233
234 /* if only a certain region will be updated, copy the entire previous
235 * frame before the decode */
236 if (
s->prev_frame->data[0] &&
237 (frame_x || frame_y || (frame_width !=
s->avctx->width) ||
238 (frame_height !=
s->avctx->height))) {
239
240 memcpy(
frame->data[0],
s->prev_frame->data[0],
241 s->avctx->height *
frame->linesize[0]);
242 }
243
244 /* check if there is a new palette */
246 if (
s->buf[15] & 0x02) {
248 palette32 = (
unsigned int *)
s->palette;
251 r = bytestream2_get_byteu(&gb) * 4;
252 g = bytestream2_get_byteu(&gb) * 4;
253 b = bytestream2_get_byteu(&gb) * 4;
254 palette32[
i] = 0xFF
U << 24 | (
r << 16) | (
g << 8) | (
b);
255 palette32[
i] |= palette32[
i] >> 6 & 0x30303;
256 }
257 } else {
260 }
261 }
262
264 return 0;
265
266 /* originally UnpackFrame in VAG's code */
269 meth = bytestream2_get_byteu(&gb);
270 if (meth & 0x80) {
272 if (!
s->unpack_buffer_size) {
274 "Trying to unpack LZ-compressed frame with no LZ buffer\n");
276 }
278 s->unpack_buffer,
s->unpack_buffer_size);
281 meth &= 0x7F;
283 }
284
285 dp = &
frame->data[0][frame_y *
frame->linesize[0] + frame_x];
286 if (
s->prev_frame->data[0]) {
287 prev_linesize =
s->prev_frame->linesize[0];
288 pp =
s->prev_frame->data[0] + frame_y * prev_linesize + frame_x;
289 } else {
291 prev_linesize = 0;
292 }
293 switch (meth) {
294 case 1:
295 for (
i = 0;
i < frame_height;
i++) {
296 ofs = 0;
297 do {
298 len = bytestream2_get_byte(&gb);
301 if (ofs +
len > frame_width ||
306 } else {
307 /* interframe pixel copy */
308 if (ofs +
len + 1 > frame_width || !pp)
310 memcpy(&dp[ofs], &pp[ofs],
len + 1);
312 }
313 } while (ofs < frame_width);
314 if (ofs > frame_width) {
316 "offset > width (%d > %d)\n",
317 ofs, frame_width);
319 }
320 dp +=
frame->linesize[0];
322 }
323 break;
324
325 case 2:
326 for (
i = 0;
i < frame_height;
i++) {
328 dp +=
frame->linesize[0];
329 }
330 break;
331
332 case 3:
333 for (
i = 0;
i < frame_height;
i++) {
334 ofs = 0;
335 do {
336 len = bytestream2_get_byte(&gb);
339 if (bytestream2_peek_byte(&gb) == 0xFF) {
341 bytestream2_get_byte(&gb);
344 frame_width - ofs);
345 ofs += slen;
347 } else {
348 if (ofs +
len > frame_width ||
353 }
354 } else {
355 /* interframe pixel copy */
356 if (ofs +
len + 1 > frame_width || !pp)
358 memcpy(&dp[ofs], &pp[ofs],
len + 1);
360 }
361 } while (ofs < frame_width);
362 if (ofs > frame_width) {
364 "offset > width (%d > %d)\n",
365 ofs, frame_width);
367 }
368 dp +=
frame->linesize[0];
370 }
371 break;
372 }
373 return 0;
374 }
375
377 {
379
382 s->unpack_buffer_size = 0;
383
384 return 0;
385 }
386
388 {
391 unsigned int *palette32;
392 int palette_index = 0;
393 unsigned char r,
g,
b;
394 unsigned char *vmd_header;
395 unsigned char *raw_palette;
396
399
400 /* make sure the VMD header made it */
405 }
406 vmd_header = (
unsigned char *)avctx->
extradata;
407
408 s->unpack_buffer_size =
AV_RL32(&vmd_header[800]);
409 if (
s->unpack_buffer_size) {
410 s->unpack_buffer =
av_malloc(
s->unpack_buffer_size);
411 if (!
s->unpack_buffer)
413 }
414
415 /* load up the initial palette */
416 raw_palette = &vmd_header[28];
417 palette32 = (
unsigned int *)
s->palette;
419 r = raw_palette[palette_index++] * 4;
420 g = raw_palette[palette_index++] * 4;
421 b = raw_palette[palette_index++] * 4;
422 palette32[
i] = 0xFF
U << 24 | (
r << 16) | (
g << 8) | (
b);
423 palette32[
i] |= palette32[
i] >> 6 & 0x30303;
424 }
425
429
430 return 0;
431 }
432
435 {
436 const uint8_t *buf = avpkt->
data;
437 int buf_size = avpkt->
size;
440
443
444 if (buf_size < 16)
446
449
452
453 /* make the palette available on the way out */
455
456 /* 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 };