yading@10
|
1 /*
|
yading@10
|
2 * Interplay MVE Video Decoder
|
yading@10
|
3 * Copyright (C) 2003 the ffmpeg project
|
yading@10
|
4 *
|
yading@10
|
5 * This file is part of FFmpeg.
|
yading@10
|
6 *
|
yading@10
|
7 * FFmpeg is free software; you can redistribute it and/or
|
yading@10
|
8 * modify it under the terms of the GNU Lesser General Public
|
yading@10
|
9 * License as published by the Free Software Foundation; either
|
yading@10
|
10 * version 2.1 of the License, or (at your option) any later version.
|
yading@10
|
11 *
|
yading@10
|
12 * FFmpeg is distributed in the hope that it will be useful,
|
yading@10
|
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
yading@10
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
yading@10
|
15 * Lesser General Public License for more details.
|
yading@10
|
16 *
|
yading@10
|
17 * You should have received a copy of the GNU Lesser General Public
|
yading@10
|
18 * License along with FFmpeg; if not, write to the Free Software
|
yading@10
|
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
yading@10
|
20 */
|
yading@10
|
21
|
yading@10
|
22 /**
|
yading@10
|
23 * @file
|
yading@10
|
24 * Interplay MVE Video Decoder by Mike Melanson (melanson@pcisys.net)
|
yading@10
|
25 * For more information about the Interplay MVE format, visit:
|
yading@10
|
26 * http://www.pcisys.net/~melanson/codecs/interplay-mve.txt
|
yading@10
|
27 * This code is written in such a way that the identifiers match up
|
yading@10
|
28 * with the encoding descriptions in the document.
|
yading@10
|
29 *
|
yading@10
|
30 * This decoder presently only supports a PAL8 output colorspace.
|
yading@10
|
31 *
|
yading@10
|
32 * An Interplay video frame consists of 2 parts: The decoding map and
|
yading@10
|
33 * the video data. A demuxer must load these 2 parts together in a single
|
yading@10
|
34 * buffer before sending it through the stream to this decoder.
|
yading@10
|
35 */
|
yading@10
|
36
|
yading@10
|
37 #include <stdio.h>
|
yading@10
|
38 #include <stdlib.h>
|
yading@10
|
39 #include <string.h>
|
yading@10
|
40
|
yading@10
|
41 #include "avcodec.h"
|
yading@10
|
42 #include "bytestream.h"
|
yading@10
|
43 #include "hpeldsp.h"
|
yading@10
|
44 #define BITSTREAM_READER_LE
|
yading@10
|
45 #include "get_bits.h"
|
yading@10
|
46 #include "internal.h"
|
yading@10
|
47
|
yading@10
|
48 #define PALETTE_COUNT 256
|
yading@10
|
49
|
yading@10
|
50 typedef struct IpvideoContext {
|
yading@10
|
51
|
yading@10
|
52 AVCodecContext *avctx;
|
yading@10
|
53 HpelDSPContext hdsp;
|
yading@10
|
54 AVFrame *second_last_frame;
|
yading@10
|
55 AVFrame *last_frame;
|
yading@10
|
56 const unsigned char *decoding_map;
|
yading@10
|
57 int decoding_map_size;
|
yading@10
|
58
|
yading@10
|
59 int is_16bpp;
|
yading@10
|
60 GetByteContext stream_ptr, mv_ptr;
|
yading@10
|
61 unsigned char *pixel_ptr;
|
yading@10
|
62 int line_inc;
|
yading@10
|
63 int stride;
|
yading@10
|
64 int upper_motion_limit_offset;
|
yading@10
|
65
|
yading@10
|
66 uint32_t pal[256];
|
yading@10
|
67 } IpvideoContext;
|
yading@10
|
68
|
yading@10
|
69 static int copy_from(IpvideoContext *s, AVFrame *src, AVFrame *dst, int delta_x, int delta_y)
|
yading@10
|
70 {
|
yading@10
|
71 int current_offset = s->pixel_ptr - dst->data[0];
|
yading@10
|
72 int motion_offset = current_offset + delta_y * dst->linesize[0]
|
yading@10
|
73 + delta_x * (1 + s->is_16bpp);
|
yading@10
|
74 if (motion_offset < 0) {
|
yading@10
|
75 av_log(s->avctx, AV_LOG_ERROR, "motion offset < 0 (%d)\n", motion_offset);
|
yading@10
|
76 return AVERROR_INVALIDDATA;
|
yading@10
|
77 } else if (motion_offset > s->upper_motion_limit_offset) {
|
yading@10
|
78 av_log(s->avctx, AV_LOG_ERROR, "motion offset above limit (%d >= %d)\n",
|
yading@10
|
79 motion_offset, s->upper_motion_limit_offset);
|
yading@10
|
80 return AVERROR_INVALIDDATA;
|
yading@10
|
81 }
|
yading@10
|
82 if (src->data[0] == NULL) {
|
yading@10
|
83 av_log(s->avctx, AV_LOG_ERROR, "Invalid decode type, corrupted header?\n");
|
yading@10
|
84 return AVERROR(EINVAL);
|
yading@10
|
85 }
|
yading@10
|
86 s->hdsp.put_pixels_tab[!s->is_16bpp][0](s->pixel_ptr, src->data[0] + motion_offset,
|
yading@10
|
87 dst->linesize[0], 8);
|
yading@10
|
88 return 0;
|
yading@10
|
89 }
|
yading@10
|
90
|
yading@10
|
91 static int ipvideo_decode_block_opcode_0x0(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
92 {
|
yading@10
|
93 return copy_from(s, s->last_frame, frame, 0, 0);
|
yading@10
|
94 }
|
yading@10
|
95
|
yading@10
|
96 static int ipvideo_decode_block_opcode_0x1(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
97 {
|
yading@10
|
98 return copy_from(s, s->second_last_frame, frame, 0, 0);
|
yading@10
|
99 }
|
yading@10
|
100
|
yading@10
|
101 static int ipvideo_decode_block_opcode_0x2(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
102 {
|
yading@10
|
103 unsigned char B;
|
yading@10
|
104 int x, y;
|
yading@10
|
105
|
yading@10
|
106 /* copy block from 2 frames ago using a motion vector; need 1 more byte */
|
yading@10
|
107 if (!s->is_16bpp) {
|
yading@10
|
108 B = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
109 } else {
|
yading@10
|
110 B = bytestream2_get_byte(&s->mv_ptr);
|
yading@10
|
111 }
|
yading@10
|
112
|
yading@10
|
113 if (B < 56) {
|
yading@10
|
114 x = 8 + (B % 7);
|
yading@10
|
115 y = B / 7;
|
yading@10
|
116 } else {
|
yading@10
|
117 x = -14 + ((B - 56) % 29);
|
yading@10
|
118 y = 8 + ((B - 56) / 29);
|
yading@10
|
119 }
|
yading@10
|
120
|
yading@10
|
121 av_dlog(s->avctx, "motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
|
yading@10
|
122 return copy_from(s, s->second_last_frame, frame, x, y);
|
yading@10
|
123 }
|
yading@10
|
124
|
yading@10
|
125 static int ipvideo_decode_block_opcode_0x3(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
126 {
|
yading@10
|
127 unsigned char B;
|
yading@10
|
128 int x, y;
|
yading@10
|
129
|
yading@10
|
130 /* copy 8x8 block from current frame from an up/left block */
|
yading@10
|
131
|
yading@10
|
132 /* need 1 more byte for motion */
|
yading@10
|
133 if (!s->is_16bpp) {
|
yading@10
|
134 B = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
135 } else {
|
yading@10
|
136 B = bytestream2_get_byte(&s->mv_ptr);
|
yading@10
|
137 }
|
yading@10
|
138
|
yading@10
|
139 if (B < 56) {
|
yading@10
|
140 x = -(8 + (B % 7));
|
yading@10
|
141 y = -(B / 7);
|
yading@10
|
142 } else {
|
yading@10
|
143 x = -(-14 + ((B - 56) % 29));
|
yading@10
|
144 y = -( 8 + ((B - 56) / 29));
|
yading@10
|
145 }
|
yading@10
|
146
|
yading@10
|
147 av_dlog(s->avctx, "motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
|
yading@10
|
148 return copy_from(s, frame, frame, x, y);
|
yading@10
|
149 }
|
yading@10
|
150
|
yading@10
|
151 static int ipvideo_decode_block_opcode_0x4(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
152 {
|
yading@10
|
153 int x, y;
|
yading@10
|
154 unsigned char B, BL, BH;
|
yading@10
|
155
|
yading@10
|
156 /* copy a block from the previous frame; need 1 more byte */
|
yading@10
|
157 if (!s->is_16bpp) {
|
yading@10
|
158 B = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
159 } else {
|
yading@10
|
160 B = bytestream2_get_byte(&s->mv_ptr);
|
yading@10
|
161 }
|
yading@10
|
162
|
yading@10
|
163 BL = B & 0x0F;
|
yading@10
|
164 BH = (B >> 4) & 0x0F;
|
yading@10
|
165 x = -8 + BL;
|
yading@10
|
166 y = -8 + BH;
|
yading@10
|
167
|
yading@10
|
168 av_dlog(s->avctx, "motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
|
yading@10
|
169 return copy_from(s, s->last_frame, frame, x, y);
|
yading@10
|
170 }
|
yading@10
|
171
|
yading@10
|
172 static int ipvideo_decode_block_opcode_0x5(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
173 {
|
yading@10
|
174 signed char x, y;
|
yading@10
|
175
|
yading@10
|
176 /* copy a block from the previous frame using an expanded range;
|
yading@10
|
177 * need 2 more bytes */
|
yading@10
|
178 x = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
179 y = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
180
|
yading@10
|
181 av_dlog(s->avctx, "motion bytes = %d, %d\n", x, y);
|
yading@10
|
182 return copy_from(s, s->last_frame, frame, x, y);
|
yading@10
|
183 }
|
yading@10
|
184
|
yading@10
|
185 static int ipvideo_decode_block_opcode_0x6(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
186 {
|
yading@10
|
187 /* mystery opcode? skip multiple blocks? */
|
yading@10
|
188 av_log(s->avctx, AV_LOG_ERROR, "Help! Mystery opcode 0x6 seen\n");
|
yading@10
|
189
|
yading@10
|
190 /* report success */
|
yading@10
|
191 return 0;
|
yading@10
|
192 }
|
yading@10
|
193
|
yading@10
|
194 static int ipvideo_decode_block_opcode_0x7(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
195 {
|
yading@10
|
196 int x, y;
|
yading@10
|
197 unsigned char P[2];
|
yading@10
|
198 unsigned int flags;
|
yading@10
|
199
|
yading@10
|
200 /* 2-color encoding */
|
yading@10
|
201 P[0] = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
202 P[1] = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
203
|
yading@10
|
204 if (P[0] <= P[1]) {
|
yading@10
|
205
|
yading@10
|
206 /* need 8 more bytes from the stream */
|
yading@10
|
207 for (y = 0; y < 8; y++) {
|
yading@10
|
208 flags = bytestream2_get_byte(&s->stream_ptr) | 0x100;
|
yading@10
|
209 for (; flags != 1; flags >>= 1)
|
yading@10
|
210 *s->pixel_ptr++ = P[flags & 1];
|
yading@10
|
211 s->pixel_ptr += s->line_inc;
|
yading@10
|
212 }
|
yading@10
|
213
|
yading@10
|
214 } else {
|
yading@10
|
215
|
yading@10
|
216 /* need 2 more bytes from the stream */
|
yading@10
|
217 flags = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
218 for (y = 0; y < 8; y += 2) {
|
yading@10
|
219 for (x = 0; x < 8; x += 2, flags >>= 1) {
|
yading@10
|
220 s->pixel_ptr[x ] =
|
yading@10
|
221 s->pixel_ptr[x + 1 ] =
|
yading@10
|
222 s->pixel_ptr[x + s->stride] =
|
yading@10
|
223 s->pixel_ptr[x + 1 + s->stride] = P[flags & 1];
|
yading@10
|
224 }
|
yading@10
|
225 s->pixel_ptr += s->stride * 2;
|
yading@10
|
226 }
|
yading@10
|
227 }
|
yading@10
|
228
|
yading@10
|
229 /* report success */
|
yading@10
|
230 return 0;
|
yading@10
|
231 }
|
yading@10
|
232
|
yading@10
|
233 static int ipvideo_decode_block_opcode_0x8(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
234 {
|
yading@10
|
235 int x, y;
|
yading@10
|
236 unsigned char P[4];
|
yading@10
|
237 unsigned int flags = 0;
|
yading@10
|
238
|
yading@10
|
239 /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
|
yading@10
|
240 * either top and bottom or left and right halves */
|
yading@10
|
241 P[0] = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
242 P[1] = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
243
|
yading@10
|
244 if (P[0] <= P[1]) {
|
yading@10
|
245 for (y = 0; y < 16; y++) {
|
yading@10
|
246 // new values for each 4x4 block
|
yading@10
|
247 if (!(y & 3)) {
|
yading@10
|
248 if (y) {
|
yading@10
|
249 P[0] = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
250 P[1] = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
251 }
|
yading@10
|
252 flags = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
253 }
|
yading@10
|
254
|
yading@10
|
255 for (x = 0; x < 4; x++, flags >>= 1)
|
yading@10
|
256 *s->pixel_ptr++ = P[flags & 1];
|
yading@10
|
257 s->pixel_ptr += s->stride - 4;
|
yading@10
|
258 // switch to right half
|
yading@10
|
259 if (y == 7) s->pixel_ptr -= 8 * s->stride - 4;
|
yading@10
|
260 }
|
yading@10
|
261
|
yading@10
|
262 } else {
|
yading@10
|
263 flags = bytestream2_get_le32(&s->stream_ptr);
|
yading@10
|
264 P[2] = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
265 P[3] = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
266
|
yading@10
|
267 if (P[2] <= P[3]) {
|
yading@10
|
268
|
yading@10
|
269 /* vertical split; left & right halves are 2-color encoded */
|
yading@10
|
270
|
yading@10
|
271 for (y = 0; y < 16; y++) {
|
yading@10
|
272 for (x = 0; x < 4; x++, flags >>= 1)
|
yading@10
|
273 *s->pixel_ptr++ = P[flags & 1];
|
yading@10
|
274 s->pixel_ptr += s->stride - 4;
|
yading@10
|
275 // switch to right half
|
yading@10
|
276 if (y == 7) {
|
yading@10
|
277 s->pixel_ptr -= 8 * s->stride - 4;
|
yading@10
|
278 P[0] = P[2];
|
yading@10
|
279 P[1] = P[3];
|
yading@10
|
280 flags = bytestream2_get_le32(&s->stream_ptr);
|
yading@10
|
281 }
|
yading@10
|
282 }
|
yading@10
|
283
|
yading@10
|
284 } else {
|
yading@10
|
285
|
yading@10
|
286 /* horizontal split; top & bottom halves are 2-color encoded */
|
yading@10
|
287
|
yading@10
|
288 for (y = 0; y < 8; y++) {
|
yading@10
|
289 if (y == 4) {
|
yading@10
|
290 P[0] = P[2];
|
yading@10
|
291 P[1] = P[3];
|
yading@10
|
292 flags = bytestream2_get_le32(&s->stream_ptr);
|
yading@10
|
293 }
|
yading@10
|
294
|
yading@10
|
295 for (x = 0; x < 8; x++, flags >>= 1)
|
yading@10
|
296 *s->pixel_ptr++ = P[flags & 1];
|
yading@10
|
297 s->pixel_ptr += s->line_inc;
|
yading@10
|
298 }
|
yading@10
|
299 }
|
yading@10
|
300 }
|
yading@10
|
301
|
yading@10
|
302 /* report success */
|
yading@10
|
303 return 0;
|
yading@10
|
304 }
|
yading@10
|
305
|
yading@10
|
306 static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
307 {
|
yading@10
|
308 int x, y;
|
yading@10
|
309 unsigned char P[4];
|
yading@10
|
310
|
yading@10
|
311 /* 4-color encoding */
|
yading@10
|
312 bytestream2_get_buffer(&s->stream_ptr, P, 4);
|
yading@10
|
313
|
yading@10
|
314 if (P[0] <= P[1]) {
|
yading@10
|
315 if (P[2] <= P[3]) {
|
yading@10
|
316
|
yading@10
|
317 /* 1 of 4 colors for each pixel, need 16 more bytes */
|
yading@10
|
318 for (y = 0; y < 8; y++) {
|
yading@10
|
319 /* get the next set of 8 2-bit flags */
|
yading@10
|
320 int flags = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
321 for (x = 0; x < 8; x++, flags >>= 2)
|
yading@10
|
322 *s->pixel_ptr++ = P[flags & 0x03];
|
yading@10
|
323 s->pixel_ptr += s->line_inc;
|
yading@10
|
324 }
|
yading@10
|
325
|
yading@10
|
326 } else {
|
yading@10
|
327 uint32_t flags;
|
yading@10
|
328
|
yading@10
|
329 /* 1 of 4 colors for each 2x2 block, need 4 more bytes */
|
yading@10
|
330 flags = bytestream2_get_le32(&s->stream_ptr);
|
yading@10
|
331
|
yading@10
|
332 for (y = 0; y < 8; y += 2) {
|
yading@10
|
333 for (x = 0; x < 8; x += 2, flags >>= 2) {
|
yading@10
|
334 s->pixel_ptr[x ] =
|
yading@10
|
335 s->pixel_ptr[x + 1 ] =
|
yading@10
|
336 s->pixel_ptr[x + s->stride] =
|
yading@10
|
337 s->pixel_ptr[x + 1 + s->stride] = P[flags & 0x03];
|
yading@10
|
338 }
|
yading@10
|
339 s->pixel_ptr += s->stride * 2;
|
yading@10
|
340 }
|
yading@10
|
341
|
yading@10
|
342 }
|
yading@10
|
343 } else {
|
yading@10
|
344 uint64_t flags;
|
yading@10
|
345
|
yading@10
|
346 /* 1 of 4 colors for each 2x1 or 1x2 block, need 8 more bytes */
|
yading@10
|
347 flags = bytestream2_get_le64(&s->stream_ptr);
|
yading@10
|
348 if (P[2] <= P[3]) {
|
yading@10
|
349 for (y = 0; y < 8; y++) {
|
yading@10
|
350 for (x = 0; x < 8; x += 2, flags >>= 2) {
|
yading@10
|
351 s->pixel_ptr[x ] =
|
yading@10
|
352 s->pixel_ptr[x + 1] = P[flags & 0x03];
|
yading@10
|
353 }
|
yading@10
|
354 s->pixel_ptr += s->stride;
|
yading@10
|
355 }
|
yading@10
|
356 } else {
|
yading@10
|
357 for (y = 0; y < 8; y += 2) {
|
yading@10
|
358 for (x = 0; x < 8; x++, flags >>= 2) {
|
yading@10
|
359 s->pixel_ptr[x ] =
|
yading@10
|
360 s->pixel_ptr[x + s->stride] = P[flags & 0x03];
|
yading@10
|
361 }
|
yading@10
|
362 s->pixel_ptr += s->stride * 2;
|
yading@10
|
363 }
|
yading@10
|
364 }
|
yading@10
|
365 }
|
yading@10
|
366
|
yading@10
|
367 /* report success */
|
yading@10
|
368 return 0;
|
yading@10
|
369 }
|
yading@10
|
370
|
yading@10
|
371 static int ipvideo_decode_block_opcode_0xA(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
372 {
|
yading@10
|
373 int x, y;
|
yading@10
|
374 unsigned char P[8];
|
yading@10
|
375 int flags = 0;
|
yading@10
|
376
|
yading@10
|
377 bytestream2_get_buffer(&s->stream_ptr, P, 4);
|
yading@10
|
378
|
yading@10
|
379 /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
|
yading@10
|
380 * either top and bottom or left and right halves */
|
yading@10
|
381 if (P[0] <= P[1]) {
|
yading@10
|
382
|
yading@10
|
383 /* 4-color encoding for each quadrant; need 32 bytes */
|
yading@10
|
384 for (y = 0; y < 16; y++) {
|
yading@10
|
385 // new values for each 4x4 block
|
yading@10
|
386 if (!(y & 3)) {
|
yading@10
|
387 if (y) bytestream2_get_buffer(&s->stream_ptr, P, 4);
|
yading@10
|
388 flags = bytestream2_get_le32(&s->stream_ptr);
|
yading@10
|
389 }
|
yading@10
|
390
|
yading@10
|
391 for (x = 0; x < 4; x++, flags >>= 2)
|
yading@10
|
392 *s->pixel_ptr++ = P[flags & 0x03];
|
yading@10
|
393
|
yading@10
|
394 s->pixel_ptr += s->stride - 4;
|
yading@10
|
395 // switch to right half
|
yading@10
|
396 if (y == 7) s->pixel_ptr -= 8 * s->stride - 4;
|
yading@10
|
397 }
|
yading@10
|
398
|
yading@10
|
399 } else {
|
yading@10
|
400 // vertical split?
|
yading@10
|
401 int vert;
|
yading@10
|
402 uint64_t flags = bytestream2_get_le64(&s->stream_ptr);
|
yading@10
|
403
|
yading@10
|
404 bytestream2_get_buffer(&s->stream_ptr, P + 4, 4);
|
yading@10
|
405 vert = P[4] <= P[5];
|
yading@10
|
406
|
yading@10
|
407 /* 4-color encoding for either left and right or top and bottom
|
yading@10
|
408 * halves */
|
yading@10
|
409
|
yading@10
|
410 for (y = 0; y < 16; y++) {
|
yading@10
|
411 for (x = 0; x < 4; x++, flags >>= 2)
|
yading@10
|
412 *s->pixel_ptr++ = P[flags & 0x03];
|
yading@10
|
413
|
yading@10
|
414 if (vert) {
|
yading@10
|
415 s->pixel_ptr += s->stride - 4;
|
yading@10
|
416 // switch to right half
|
yading@10
|
417 if (y == 7) s->pixel_ptr -= 8 * s->stride - 4;
|
yading@10
|
418 } else if (y & 1) s->pixel_ptr += s->line_inc;
|
yading@10
|
419
|
yading@10
|
420 // load values for second half
|
yading@10
|
421 if (y == 7) {
|
yading@10
|
422 memcpy(P, P + 4, 4);
|
yading@10
|
423 flags = bytestream2_get_le64(&s->stream_ptr);
|
yading@10
|
424 }
|
yading@10
|
425 }
|
yading@10
|
426 }
|
yading@10
|
427
|
yading@10
|
428 /* report success */
|
yading@10
|
429 return 0;
|
yading@10
|
430 }
|
yading@10
|
431
|
yading@10
|
432 static int ipvideo_decode_block_opcode_0xB(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
433 {
|
yading@10
|
434 int y;
|
yading@10
|
435
|
yading@10
|
436 /* 64-color encoding (each pixel in block is a different color) */
|
yading@10
|
437 for (y = 0; y < 8; y++) {
|
yading@10
|
438 bytestream2_get_buffer(&s->stream_ptr, s->pixel_ptr, 8);
|
yading@10
|
439 s->pixel_ptr += s->stride;
|
yading@10
|
440 }
|
yading@10
|
441
|
yading@10
|
442 /* report success */
|
yading@10
|
443 return 0;
|
yading@10
|
444 }
|
yading@10
|
445
|
yading@10
|
446 static int ipvideo_decode_block_opcode_0xC(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
447 {
|
yading@10
|
448 int x, y;
|
yading@10
|
449
|
yading@10
|
450 /* 16-color block encoding: each 2x2 block is a different color */
|
yading@10
|
451 for (y = 0; y < 8; y += 2) {
|
yading@10
|
452 for (x = 0; x < 8; x += 2) {
|
yading@10
|
453 s->pixel_ptr[x ] =
|
yading@10
|
454 s->pixel_ptr[x + 1 ] =
|
yading@10
|
455 s->pixel_ptr[x + s->stride] =
|
yading@10
|
456 s->pixel_ptr[x + 1 + s->stride] = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
457 }
|
yading@10
|
458 s->pixel_ptr += s->stride * 2;
|
yading@10
|
459 }
|
yading@10
|
460
|
yading@10
|
461 /* report success */
|
yading@10
|
462 return 0;
|
yading@10
|
463 }
|
yading@10
|
464
|
yading@10
|
465 static int ipvideo_decode_block_opcode_0xD(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
466 {
|
yading@10
|
467 int y;
|
yading@10
|
468 unsigned char P[2];
|
yading@10
|
469
|
yading@10
|
470 /* 4-color block encoding: each 4x4 block is a different color */
|
yading@10
|
471 for (y = 0; y < 8; y++) {
|
yading@10
|
472 if (!(y & 3)) {
|
yading@10
|
473 P[0] = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
474 P[1] = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
475 }
|
yading@10
|
476 memset(s->pixel_ptr, P[0], 4);
|
yading@10
|
477 memset(s->pixel_ptr + 4, P[1], 4);
|
yading@10
|
478 s->pixel_ptr += s->stride;
|
yading@10
|
479 }
|
yading@10
|
480
|
yading@10
|
481 /* report success */
|
yading@10
|
482 return 0;
|
yading@10
|
483 }
|
yading@10
|
484
|
yading@10
|
485 static int ipvideo_decode_block_opcode_0xE(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
486 {
|
yading@10
|
487 int y;
|
yading@10
|
488 unsigned char pix;
|
yading@10
|
489
|
yading@10
|
490 /* 1-color encoding: the whole block is 1 solid color */
|
yading@10
|
491 pix = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
492
|
yading@10
|
493 for (y = 0; y < 8; y++) {
|
yading@10
|
494 memset(s->pixel_ptr, pix, 8);
|
yading@10
|
495 s->pixel_ptr += s->stride;
|
yading@10
|
496 }
|
yading@10
|
497
|
yading@10
|
498 /* report success */
|
yading@10
|
499 return 0;
|
yading@10
|
500 }
|
yading@10
|
501
|
yading@10
|
502 static int ipvideo_decode_block_opcode_0xF(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
503 {
|
yading@10
|
504 int x, y;
|
yading@10
|
505 unsigned char sample[2];
|
yading@10
|
506
|
yading@10
|
507 /* dithered encoding */
|
yading@10
|
508 sample[0] = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
509 sample[1] = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
510
|
yading@10
|
511 for (y = 0; y < 8; y++) {
|
yading@10
|
512 for (x = 0; x < 8; x += 2) {
|
yading@10
|
513 *s->pixel_ptr++ = sample[ y & 1 ];
|
yading@10
|
514 *s->pixel_ptr++ = sample[!(y & 1)];
|
yading@10
|
515 }
|
yading@10
|
516 s->pixel_ptr += s->line_inc;
|
yading@10
|
517 }
|
yading@10
|
518
|
yading@10
|
519 /* report success */
|
yading@10
|
520 return 0;
|
yading@10
|
521 }
|
yading@10
|
522
|
yading@10
|
523 static int ipvideo_decode_block_opcode_0x6_16(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
524 {
|
yading@10
|
525 signed char x, y;
|
yading@10
|
526
|
yading@10
|
527 /* copy a block from the second last frame using an expanded range */
|
yading@10
|
528 x = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
529 y = bytestream2_get_byte(&s->stream_ptr);
|
yading@10
|
530
|
yading@10
|
531 av_dlog(s->avctx, "motion bytes = %d, %d\n", x, y);
|
yading@10
|
532 return copy_from(s, s->second_last_frame, frame, x, y);
|
yading@10
|
533 }
|
yading@10
|
534
|
yading@10
|
535 static int ipvideo_decode_block_opcode_0x7_16(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
536 {
|
yading@10
|
537 int x, y;
|
yading@10
|
538 uint16_t P[2];
|
yading@10
|
539 unsigned int flags;
|
yading@10
|
540 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
|
yading@10
|
541
|
yading@10
|
542 /* 2-color encoding */
|
yading@10
|
543 P[0] = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
544 P[1] = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
545
|
yading@10
|
546 if (!(P[0] & 0x8000)) {
|
yading@10
|
547
|
yading@10
|
548 for (y = 0; y < 8; y++) {
|
yading@10
|
549 flags = bytestream2_get_byte(&s->stream_ptr) | 0x100;
|
yading@10
|
550 for (; flags != 1; flags >>= 1)
|
yading@10
|
551 *pixel_ptr++ = P[flags & 1];
|
yading@10
|
552 pixel_ptr += s->line_inc;
|
yading@10
|
553 }
|
yading@10
|
554
|
yading@10
|
555 } else {
|
yading@10
|
556
|
yading@10
|
557 flags = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
558 for (y = 0; y < 8; y += 2) {
|
yading@10
|
559 for (x = 0; x < 8; x += 2, flags >>= 1) {
|
yading@10
|
560 pixel_ptr[x ] =
|
yading@10
|
561 pixel_ptr[x + 1 ] =
|
yading@10
|
562 pixel_ptr[x + s->stride] =
|
yading@10
|
563 pixel_ptr[x + 1 + s->stride] = P[flags & 1];
|
yading@10
|
564 }
|
yading@10
|
565 pixel_ptr += s->stride * 2;
|
yading@10
|
566 }
|
yading@10
|
567 }
|
yading@10
|
568
|
yading@10
|
569 return 0;
|
yading@10
|
570 }
|
yading@10
|
571
|
yading@10
|
572 static int ipvideo_decode_block_opcode_0x8_16(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
573 {
|
yading@10
|
574 int x, y;
|
yading@10
|
575 uint16_t P[4];
|
yading@10
|
576 unsigned int flags = 0;
|
yading@10
|
577 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
|
yading@10
|
578
|
yading@10
|
579 /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
|
yading@10
|
580 * either top and bottom or left and right halves */
|
yading@10
|
581 P[0] = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
582 P[1] = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
583
|
yading@10
|
584 if (!(P[0] & 0x8000)) {
|
yading@10
|
585
|
yading@10
|
586 for (y = 0; y < 16; y++) {
|
yading@10
|
587 // new values for each 4x4 block
|
yading@10
|
588 if (!(y & 3)) {
|
yading@10
|
589 if (y) {
|
yading@10
|
590 P[0] = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
591 P[1] = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
592 }
|
yading@10
|
593 flags = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
594 }
|
yading@10
|
595
|
yading@10
|
596 for (x = 0; x < 4; x++, flags >>= 1)
|
yading@10
|
597 *pixel_ptr++ = P[flags & 1];
|
yading@10
|
598 pixel_ptr += s->stride - 4;
|
yading@10
|
599 // switch to right half
|
yading@10
|
600 if (y == 7) pixel_ptr -= 8 * s->stride - 4;
|
yading@10
|
601 }
|
yading@10
|
602
|
yading@10
|
603 } else {
|
yading@10
|
604
|
yading@10
|
605 flags = bytestream2_get_le32(&s->stream_ptr);
|
yading@10
|
606 P[2] = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
607 P[3] = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
608
|
yading@10
|
609 if (!(P[2] & 0x8000)) {
|
yading@10
|
610
|
yading@10
|
611 /* vertical split; left & right halves are 2-color encoded */
|
yading@10
|
612
|
yading@10
|
613 for (y = 0; y < 16; y++) {
|
yading@10
|
614 for (x = 0; x < 4; x++, flags >>= 1)
|
yading@10
|
615 *pixel_ptr++ = P[flags & 1];
|
yading@10
|
616 pixel_ptr += s->stride - 4;
|
yading@10
|
617 // switch to right half
|
yading@10
|
618 if (y == 7) {
|
yading@10
|
619 pixel_ptr -= 8 * s->stride - 4;
|
yading@10
|
620 P[0] = P[2];
|
yading@10
|
621 P[1] = P[3];
|
yading@10
|
622 flags = bytestream2_get_le32(&s->stream_ptr);
|
yading@10
|
623 }
|
yading@10
|
624 }
|
yading@10
|
625
|
yading@10
|
626 } else {
|
yading@10
|
627
|
yading@10
|
628 /* horizontal split; top & bottom halves are 2-color encoded */
|
yading@10
|
629
|
yading@10
|
630 for (y = 0; y < 8; y++) {
|
yading@10
|
631 if (y == 4) {
|
yading@10
|
632 P[0] = P[2];
|
yading@10
|
633 P[1] = P[3];
|
yading@10
|
634 flags = bytestream2_get_le32(&s->stream_ptr);
|
yading@10
|
635 }
|
yading@10
|
636
|
yading@10
|
637 for (x = 0; x < 8; x++, flags >>= 1)
|
yading@10
|
638 *pixel_ptr++ = P[flags & 1];
|
yading@10
|
639 pixel_ptr += s->line_inc;
|
yading@10
|
640 }
|
yading@10
|
641 }
|
yading@10
|
642 }
|
yading@10
|
643
|
yading@10
|
644 /* report success */
|
yading@10
|
645 return 0;
|
yading@10
|
646 }
|
yading@10
|
647
|
yading@10
|
648 static int ipvideo_decode_block_opcode_0x9_16(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
649 {
|
yading@10
|
650 int x, y;
|
yading@10
|
651 uint16_t P[4];
|
yading@10
|
652 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
|
yading@10
|
653
|
yading@10
|
654 /* 4-color encoding */
|
yading@10
|
655 for (x = 0; x < 4; x++)
|
yading@10
|
656 P[x] = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
657
|
yading@10
|
658 if (!(P[0] & 0x8000)) {
|
yading@10
|
659 if (!(P[2] & 0x8000)) {
|
yading@10
|
660
|
yading@10
|
661 /* 1 of 4 colors for each pixel */
|
yading@10
|
662 for (y = 0; y < 8; y++) {
|
yading@10
|
663 /* get the next set of 8 2-bit flags */
|
yading@10
|
664 int flags = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
665 for (x = 0; x < 8; x++, flags >>= 2)
|
yading@10
|
666 *pixel_ptr++ = P[flags & 0x03];
|
yading@10
|
667 pixel_ptr += s->line_inc;
|
yading@10
|
668 }
|
yading@10
|
669
|
yading@10
|
670 } else {
|
yading@10
|
671 uint32_t flags;
|
yading@10
|
672
|
yading@10
|
673 /* 1 of 4 colors for each 2x2 block */
|
yading@10
|
674 flags = bytestream2_get_le32(&s->stream_ptr);
|
yading@10
|
675
|
yading@10
|
676 for (y = 0; y < 8; y += 2) {
|
yading@10
|
677 for (x = 0; x < 8; x += 2, flags >>= 2) {
|
yading@10
|
678 pixel_ptr[x ] =
|
yading@10
|
679 pixel_ptr[x + 1 ] =
|
yading@10
|
680 pixel_ptr[x + s->stride] =
|
yading@10
|
681 pixel_ptr[x + 1 + s->stride] = P[flags & 0x03];
|
yading@10
|
682 }
|
yading@10
|
683 pixel_ptr += s->stride * 2;
|
yading@10
|
684 }
|
yading@10
|
685
|
yading@10
|
686 }
|
yading@10
|
687 } else {
|
yading@10
|
688 uint64_t flags;
|
yading@10
|
689
|
yading@10
|
690 /* 1 of 4 colors for each 2x1 or 1x2 block */
|
yading@10
|
691 flags = bytestream2_get_le64(&s->stream_ptr);
|
yading@10
|
692 if (!(P[2] & 0x8000)) {
|
yading@10
|
693 for (y = 0; y < 8; y++) {
|
yading@10
|
694 for (x = 0; x < 8; x += 2, flags >>= 2) {
|
yading@10
|
695 pixel_ptr[x ] =
|
yading@10
|
696 pixel_ptr[x + 1] = P[flags & 0x03];
|
yading@10
|
697 }
|
yading@10
|
698 pixel_ptr += s->stride;
|
yading@10
|
699 }
|
yading@10
|
700 } else {
|
yading@10
|
701 for (y = 0; y < 8; y += 2) {
|
yading@10
|
702 for (x = 0; x < 8; x++, flags >>= 2) {
|
yading@10
|
703 pixel_ptr[x ] =
|
yading@10
|
704 pixel_ptr[x + s->stride] = P[flags & 0x03];
|
yading@10
|
705 }
|
yading@10
|
706 pixel_ptr += s->stride * 2;
|
yading@10
|
707 }
|
yading@10
|
708 }
|
yading@10
|
709 }
|
yading@10
|
710
|
yading@10
|
711 /* report success */
|
yading@10
|
712 return 0;
|
yading@10
|
713 }
|
yading@10
|
714
|
yading@10
|
715 static int ipvideo_decode_block_opcode_0xA_16(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
716 {
|
yading@10
|
717 int x, y;
|
yading@10
|
718 uint16_t P[8];
|
yading@10
|
719 int flags = 0;
|
yading@10
|
720 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
|
yading@10
|
721
|
yading@10
|
722 for (x = 0; x < 4; x++)
|
yading@10
|
723 P[x] = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
724
|
yading@10
|
725 /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
|
yading@10
|
726 * either top and bottom or left and right halves */
|
yading@10
|
727 if (!(P[0] & 0x8000)) {
|
yading@10
|
728
|
yading@10
|
729 /* 4-color encoding for each quadrant */
|
yading@10
|
730 for (y = 0; y < 16; y++) {
|
yading@10
|
731 // new values for each 4x4 block
|
yading@10
|
732 if (!(y & 3)) {
|
yading@10
|
733 if (y)
|
yading@10
|
734 for (x = 0; x < 4; x++)
|
yading@10
|
735 P[x] = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
736 flags = bytestream2_get_le32(&s->stream_ptr);
|
yading@10
|
737 }
|
yading@10
|
738
|
yading@10
|
739 for (x = 0; x < 4; x++, flags >>= 2)
|
yading@10
|
740 *pixel_ptr++ = P[flags & 0x03];
|
yading@10
|
741
|
yading@10
|
742 pixel_ptr += s->stride - 4;
|
yading@10
|
743 // switch to right half
|
yading@10
|
744 if (y == 7) pixel_ptr -= 8 * s->stride - 4;
|
yading@10
|
745 }
|
yading@10
|
746
|
yading@10
|
747 } else {
|
yading@10
|
748 // vertical split?
|
yading@10
|
749 int vert;
|
yading@10
|
750 uint64_t flags = bytestream2_get_le64(&s->stream_ptr);
|
yading@10
|
751
|
yading@10
|
752 for (x = 4; x < 8; x++)
|
yading@10
|
753 P[x] = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
754 vert = !(P[4] & 0x8000);
|
yading@10
|
755
|
yading@10
|
756 /* 4-color encoding for either left and right or top and bottom
|
yading@10
|
757 * halves */
|
yading@10
|
758
|
yading@10
|
759 for (y = 0; y < 16; y++) {
|
yading@10
|
760 for (x = 0; x < 4; x++, flags >>= 2)
|
yading@10
|
761 *pixel_ptr++ = P[flags & 0x03];
|
yading@10
|
762
|
yading@10
|
763 if (vert) {
|
yading@10
|
764 pixel_ptr += s->stride - 4;
|
yading@10
|
765 // switch to right half
|
yading@10
|
766 if (y == 7) pixel_ptr -= 8 * s->stride - 4;
|
yading@10
|
767 } else if (y & 1) pixel_ptr += s->line_inc;
|
yading@10
|
768
|
yading@10
|
769 // load values for second half
|
yading@10
|
770 if (y == 7) {
|
yading@10
|
771 memcpy(P, P + 4, 8);
|
yading@10
|
772 flags = bytestream2_get_le64(&s->stream_ptr);
|
yading@10
|
773 }
|
yading@10
|
774 }
|
yading@10
|
775 }
|
yading@10
|
776
|
yading@10
|
777 /* report success */
|
yading@10
|
778 return 0;
|
yading@10
|
779 }
|
yading@10
|
780
|
yading@10
|
781 static int ipvideo_decode_block_opcode_0xB_16(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
782 {
|
yading@10
|
783 int x, y;
|
yading@10
|
784 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
|
yading@10
|
785
|
yading@10
|
786 /* 64-color encoding (each pixel in block is a different color) */
|
yading@10
|
787 for (y = 0; y < 8; y++) {
|
yading@10
|
788 for (x = 0; x < 8; x++)
|
yading@10
|
789 pixel_ptr[x] = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
790 pixel_ptr += s->stride;
|
yading@10
|
791 }
|
yading@10
|
792
|
yading@10
|
793 /* report success */
|
yading@10
|
794 return 0;
|
yading@10
|
795 }
|
yading@10
|
796
|
yading@10
|
797 static int ipvideo_decode_block_opcode_0xC_16(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
798 {
|
yading@10
|
799 int x, y;
|
yading@10
|
800 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
|
yading@10
|
801
|
yading@10
|
802 /* 16-color block encoding: each 2x2 block is a different color */
|
yading@10
|
803 for (y = 0; y < 8; y += 2) {
|
yading@10
|
804 for (x = 0; x < 8; x += 2) {
|
yading@10
|
805 pixel_ptr[x ] =
|
yading@10
|
806 pixel_ptr[x + 1 ] =
|
yading@10
|
807 pixel_ptr[x + s->stride] =
|
yading@10
|
808 pixel_ptr[x + 1 + s->stride] = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
809 }
|
yading@10
|
810 pixel_ptr += s->stride * 2;
|
yading@10
|
811 }
|
yading@10
|
812
|
yading@10
|
813 /* report success */
|
yading@10
|
814 return 0;
|
yading@10
|
815 }
|
yading@10
|
816
|
yading@10
|
817 static int ipvideo_decode_block_opcode_0xD_16(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
818 {
|
yading@10
|
819 int x, y;
|
yading@10
|
820 uint16_t P[2];
|
yading@10
|
821 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
|
yading@10
|
822
|
yading@10
|
823 /* 4-color block encoding: each 4x4 block is a different color */
|
yading@10
|
824 for (y = 0; y < 8; y++) {
|
yading@10
|
825 if (!(y & 3)) {
|
yading@10
|
826 P[0] = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
827 P[1] = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
828 }
|
yading@10
|
829 for (x = 0; x < 8; x++)
|
yading@10
|
830 pixel_ptr[x] = P[x >> 2];
|
yading@10
|
831 pixel_ptr += s->stride;
|
yading@10
|
832 }
|
yading@10
|
833
|
yading@10
|
834 /* report success */
|
yading@10
|
835 return 0;
|
yading@10
|
836 }
|
yading@10
|
837
|
yading@10
|
838 static int ipvideo_decode_block_opcode_0xE_16(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
839 {
|
yading@10
|
840 int x, y;
|
yading@10
|
841 uint16_t pix;
|
yading@10
|
842 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
|
yading@10
|
843
|
yading@10
|
844 /* 1-color encoding: the whole block is 1 solid color */
|
yading@10
|
845 pix = bytestream2_get_le16(&s->stream_ptr);
|
yading@10
|
846
|
yading@10
|
847 for (y = 0; y < 8; y++) {
|
yading@10
|
848 for (x = 0; x < 8; x++)
|
yading@10
|
849 pixel_ptr[x] = pix;
|
yading@10
|
850 pixel_ptr += s->stride;
|
yading@10
|
851 }
|
yading@10
|
852
|
yading@10
|
853 /* report success */
|
yading@10
|
854 return 0;
|
yading@10
|
855 }
|
yading@10
|
856
|
yading@10
|
857 static int (* const ipvideo_decode_block[])(IpvideoContext *s, AVFrame *frame) = {
|
yading@10
|
858 ipvideo_decode_block_opcode_0x0, ipvideo_decode_block_opcode_0x1,
|
yading@10
|
859 ipvideo_decode_block_opcode_0x2, ipvideo_decode_block_opcode_0x3,
|
yading@10
|
860 ipvideo_decode_block_opcode_0x4, ipvideo_decode_block_opcode_0x5,
|
yading@10
|
861 ipvideo_decode_block_opcode_0x6, ipvideo_decode_block_opcode_0x7,
|
yading@10
|
862 ipvideo_decode_block_opcode_0x8, ipvideo_decode_block_opcode_0x9,
|
yading@10
|
863 ipvideo_decode_block_opcode_0xA, ipvideo_decode_block_opcode_0xB,
|
yading@10
|
864 ipvideo_decode_block_opcode_0xC, ipvideo_decode_block_opcode_0xD,
|
yading@10
|
865 ipvideo_decode_block_opcode_0xE, ipvideo_decode_block_opcode_0xF,
|
yading@10
|
866 };
|
yading@10
|
867
|
yading@10
|
868 static int (* const ipvideo_decode_block16[])(IpvideoContext *s, AVFrame *frame) = {
|
yading@10
|
869 ipvideo_decode_block_opcode_0x0, ipvideo_decode_block_opcode_0x1,
|
yading@10
|
870 ipvideo_decode_block_opcode_0x2, ipvideo_decode_block_opcode_0x3,
|
yading@10
|
871 ipvideo_decode_block_opcode_0x4, ipvideo_decode_block_opcode_0x5,
|
yading@10
|
872 ipvideo_decode_block_opcode_0x6_16, ipvideo_decode_block_opcode_0x7_16,
|
yading@10
|
873 ipvideo_decode_block_opcode_0x8_16, ipvideo_decode_block_opcode_0x9_16,
|
yading@10
|
874 ipvideo_decode_block_opcode_0xA_16, ipvideo_decode_block_opcode_0xB_16,
|
yading@10
|
875 ipvideo_decode_block_opcode_0xC_16, ipvideo_decode_block_opcode_0xD_16,
|
yading@10
|
876 ipvideo_decode_block_opcode_0xE_16, ipvideo_decode_block_opcode_0x1,
|
yading@10
|
877 };
|
yading@10
|
878
|
yading@10
|
879 static void ipvideo_decode_opcodes(IpvideoContext *s, AVFrame *frame)
|
yading@10
|
880 {
|
yading@10
|
881 int x, y;
|
yading@10
|
882 unsigned char opcode;
|
yading@10
|
883 int ret;
|
yading@10
|
884 GetBitContext gb;
|
yading@10
|
885
|
yading@10
|
886 bytestream2_skip(&s->stream_ptr, 14); /* data starts 14 bytes in */
|
yading@10
|
887 if (!s->is_16bpp) {
|
yading@10
|
888 /* this is PAL8, so make the palette available */
|
yading@10
|
889 memcpy(frame->data[1], s->pal, AVPALETTE_SIZE);
|
yading@10
|
890
|
yading@10
|
891 s->stride = frame->linesize[0];
|
yading@10
|
892 } else {
|
yading@10
|
893 s->stride = frame->linesize[0] >> 1;
|
yading@10
|
894 s->mv_ptr = s->stream_ptr;
|
yading@10
|
895 bytestream2_skip(&s->mv_ptr, bytestream2_get_le16(&s->stream_ptr));
|
yading@10
|
896 }
|
yading@10
|
897 s->line_inc = s->stride - 8;
|
yading@10
|
898 s->upper_motion_limit_offset = (s->avctx->height - 8) * frame->linesize[0]
|
yading@10
|
899 + (s->avctx->width - 8) * (1 + s->is_16bpp);
|
yading@10
|
900
|
yading@10
|
901 init_get_bits(&gb, s->decoding_map, s->decoding_map_size * 8);
|
yading@10
|
902 for (y = 0; y < s->avctx->height; y += 8) {
|
yading@10
|
903 for (x = 0; x < s->avctx->width; x += 8) {
|
yading@10
|
904 opcode = get_bits(&gb, 4);
|
yading@10
|
905
|
yading@10
|
906 av_dlog(s->avctx,
|
yading@10
|
907 " block @ (%3d, %3d): encoding 0x%X, data ptr offset %d\n",
|
yading@10
|
908 x, y, opcode, bytestream2_tell(&s->stream_ptr));
|
yading@10
|
909
|
yading@10
|
910 if (!s->is_16bpp) {
|
yading@10
|
911 s->pixel_ptr = frame->data[0] + x
|
yading@10
|
912 + y*frame->linesize[0];
|
yading@10
|
913 ret = ipvideo_decode_block[opcode](s, frame);
|
yading@10
|
914 } else {
|
yading@10
|
915 s->pixel_ptr = frame->data[0] + x*2
|
yading@10
|
916 + y*frame->linesize[0];
|
yading@10
|
917 ret = ipvideo_decode_block16[opcode](s, frame);
|
yading@10
|
918 }
|
yading@10
|
919 if (ret != 0) {
|
yading@10
|
920 av_log(s->avctx, AV_LOG_ERROR, "decode problem on frame %d, @ block (%d, %d)\n",
|
yading@10
|
921 s->avctx->frame_number, x, y);
|
yading@10
|
922 return;
|
yading@10
|
923 }
|
yading@10
|
924 }
|
yading@10
|
925 }
|
yading@10
|
926 if (bytestream2_get_bytes_left(&s->stream_ptr) > 1) {
|
yading@10
|
927 av_log(s->avctx, AV_LOG_ERROR,
|
yading@10
|
928 "decode finished with %d bytes left over\n",
|
yading@10
|
929 bytestream2_get_bytes_left(&s->stream_ptr));
|
yading@10
|
930 }
|
yading@10
|
931 }
|
yading@10
|
932
|
yading@10
|
933 static av_cold int ipvideo_decode_init(AVCodecContext *avctx)
|
yading@10
|
934 {
|
yading@10
|
935 IpvideoContext *s = avctx->priv_data;
|
yading@10
|
936
|
yading@10
|
937 s->avctx = avctx;
|
yading@10
|
938
|
yading@10
|
939 s->is_16bpp = avctx->bits_per_coded_sample == 16;
|
yading@10
|
940 avctx->pix_fmt = s->is_16bpp ? AV_PIX_FMT_RGB555 : AV_PIX_FMT_PAL8;
|
yading@10
|
941
|
yading@10
|
942 ff_hpeldsp_init(&s->hdsp, avctx->flags);
|
yading@10
|
943
|
yading@10
|
944 s->last_frame = av_frame_alloc();
|
yading@10
|
945 s->second_last_frame = av_frame_alloc();
|
yading@10
|
946 if (!s->last_frame || !s->second_last_frame) {
|
yading@10
|
947 av_frame_free(&s->last_frame);
|
yading@10
|
948 av_frame_free(&s->second_last_frame);
|
yading@10
|
949 return AVERROR(ENOMEM);
|
yading@10
|
950 }
|
yading@10
|
951
|
yading@10
|
952 return 0;
|
yading@10
|
953 }
|
yading@10
|
954
|
yading@10
|
955 static int ipvideo_decode_frame(AVCodecContext *avctx,
|
yading@10
|
956 void *data, int *got_frame,
|
yading@10
|
957 AVPacket *avpkt)
|
yading@10
|
958 {
|
yading@10
|
959 const uint8_t *buf = avpkt->data;
|
yading@10
|
960 int buf_size = avpkt->size;
|
yading@10
|
961 IpvideoContext *s = avctx->priv_data;
|
yading@10
|
962 AVFrame *frame = data;
|
yading@10
|
963 int ret;
|
yading@10
|
964
|
yading@10
|
965 /* decoding map contains 4 bits of information per 8x8 block */
|
yading@10
|
966 s->decoding_map_size = avctx->width * avctx->height / (8 * 8 * 2);
|
yading@10
|
967
|
yading@10
|
968 /* compressed buffer needs to be large enough to at least hold an entire
|
yading@10
|
969 * decoding map */
|
yading@10
|
970 if (buf_size < s->decoding_map_size)
|
yading@10
|
971 return buf_size;
|
yading@10
|
972
|
yading@10
|
973 if (av_packet_get_side_data(avpkt, AV_PKT_DATA_PARAM_CHANGE, NULL)) {
|
yading@10
|
974 av_frame_unref(s->last_frame);
|
yading@10
|
975 av_frame_unref(s->second_last_frame);
|
yading@10
|
976 }
|
yading@10
|
977
|
yading@10
|
978 s->decoding_map = buf;
|
yading@10
|
979 bytestream2_init(&s->stream_ptr, buf + s->decoding_map_size,
|
yading@10
|
980 buf_size - s->decoding_map_size);
|
yading@10
|
981
|
yading@10
|
982 if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
|
yading@10
|
983 return ret;
|
yading@10
|
984
|
yading@10
|
985 if (!s->is_16bpp) {
|
yading@10
|
986 const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL);
|
yading@10
|
987 if (pal) {
|
yading@10
|
988 frame->palette_has_changed = 1;
|
yading@10
|
989 memcpy(s->pal, pal, AVPALETTE_SIZE);
|
yading@10
|
990 }
|
yading@10
|
991 }
|
yading@10
|
992
|
yading@10
|
993 ipvideo_decode_opcodes(s, frame);
|
yading@10
|
994
|
yading@10
|
995 *got_frame = 1;
|
yading@10
|
996
|
yading@10
|
997 /* shuffle frames */
|
yading@10
|
998 av_frame_unref(s->second_last_frame);
|
yading@10
|
999 FFSWAP(AVFrame*, s->second_last_frame, s->last_frame);
|
yading@10
|
1000 if ((ret = av_frame_ref(s->last_frame, frame)) < 0)
|
yading@10
|
1001 return ret;
|
yading@10
|
1002
|
yading@10
|
1003 /* report that the buffer was completely consumed */
|
yading@10
|
1004 return buf_size;
|
yading@10
|
1005 }
|
yading@10
|
1006
|
yading@10
|
1007 static av_cold int ipvideo_decode_end(AVCodecContext *avctx)
|
yading@10
|
1008 {
|
yading@10
|
1009 IpvideoContext *s = avctx->priv_data;
|
yading@10
|
1010
|
yading@10
|
1011 av_frame_free(&s->last_frame);
|
yading@10
|
1012 av_frame_free(&s->second_last_frame);
|
yading@10
|
1013
|
yading@10
|
1014 return 0;
|
yading@10
|
1015 }
|
yading@10
|
1016
|
yading@10
|
1017 AVCodec ff_interplay_video_decoder = {
|
yading@10
|
1018 .name = "interplayvideo",
|
yading@10
|
1019 .type = AVMEDIA_TYPE_VIDEO,
|
yading@10
|
1020 .id = AV_CODEC_ID_INTERPLAY_VIDEO,
|
yading@10
|
1021 .priv_data_size = sizeof(IpvideoContext),
|
yading@10
|
1022 .init = ipvideo_decode_init,
|
yading@10
|
1023 .close = ipvideo_decode_end,
|
yading@10
|
1024 .decode = ipvideo_decode_frame,
|
yading@10
|
1025 .capabilities = CODEC_CAP_DR1 | CODEC_CAP_PARAM_CHANGE,
|
yading@10
|
1026 .long_name = NULL_IF_CONFIG_SMALL("Interplay MVE video"),
|
yading@10
|
1027 };
|