Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6148 | serge | 1 | /* |
2 | * IFF ACBM/DEEP/ILBM/PBM bitmap decoder |
||
3 | * Copyright (c) 2010 Peter Ross |
||
4 | * Copyright (c) 2010 Sebastian Vater |
||
5 | * |
||
6 | * This file is part of FFmpeg. |
||
7 | * |
||
8 | * FFmpeg is free software; you can redistribute it and/or |
||
9 | * modify it under the terms of the GNU Lesser General Public |
||
10 | * License as published by the Free Software Foundation; either |
||
11 | * version 2.1 of the License, or (at your option) any later version. |
||
12 | * |
||
13 | * FFmpeg is distributed in the hope that it will be useful, |
||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
16 | * Lesser General Public License for more details. |
||
17 | * |
||
18 | * You should have received a copy of the GNU Lesser General Public |
||
19 | * License along with FFmpeg; if not, write to the Free Software |
||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||
21 | */ |
||
22 | |||
23 | /** |
||
24 | * @file |
||
25 | * IFF ACBM/DEEP/ILBM/PBM bitmap decoder |
||
26 | */ |
||
27 | |||
28 | #include "libavutil/imgutils.h" |
||
29 | #include "bytestream.h" |
||
30 | #include "avcodec.h" |
||
31 | #include "get_bits.h" |
||
32 | #include "internal.h" |
||
33 | |||
34 | // TODO: masking bits |
||
35 | typedef enum { |
||
36 | MASK_NONE, |
||
37 | MASK_HAS_MASK, |
||
38 | MASK_HAS_TRANSPARENT_COLOR, |
||
39 | MASK_LASSO |
||
40 | } mask_type; |
||
41 | |||
42 | typedef struct { |
||
43 | AVFrame *frame; |
||
44 | int planesize; |
||
45 | uint8_t * planebuf; |
||
46 | uint8_t * ham_buf; ///< temporary buffer for planar to chunky conversation |
||
47 | uint32_t *ham_palbuf; ///< HAM decode table |
||
48 | uint32_t *mask_buf; ///< temporary buffer for palette indices |
||
49 | uint32_t *mask_palbuf; ///< masking palette table |
||
50 | unsigned compression; ///< delta compression method used |
||
51 | unsigned bpp; ///< bits per plane to decode (differs from bits_per_coded_sample if HAM) |
||
52 | unsigned ham; ///< 0 if non-HAM or number of hold bits (6 for bpp > 6, 4 otherwise) |
||
53 | unsigned flags; ///< 1 for EHB, 0 is no extra half darkening |
||
54 | unsigned transparency; ///< TODO: transparency color index in palette |
||
55 | unsigned masking; ///< TODO: masking method used |
||
56 | int init; // 1 if buffer and palette data already initialized, 0 otherwise |
||
57 | int16_t tvdc[16]; ///< TVDC lookup table |
||
58 | } IffContext; |
||
59 | |||
60 | #define LUT8_PART(plane, v) \ |
||
61 | AV_LE2NE64C(UINT64_C(0x0000000)<<32 | v) << plane, \ |
||
62 | AV_LE2NE64C(UINT64_C(0x1000000)<<32 | v) << plane, \ |
||
63 | AV_LE2NE64C(UINT64_C(0x0010000)<<32 | v) << plane, \ |
||
64 | AV_LE2NE64C(UINT64_C(0x1010000)<<32 | v) << plane, \ |
||
65 | AV_LE2NE64C(UINT64_C(0x0000100)<<32 | v) << plane, \ |
||
66 | AV_LE2NE64C(UINT64_C(0x1000100)<<32 | v) << plane, \ |
||
67 | AV_LE2NE64C(UINT64_C(0x0010100)<<32 | v) << plane, \ |
||
68 | AV_LE2NE64C(UINT64_C(0x1010100)<<32 | v) << plane, \ |
||
69 | AV_LE2NE64C(UINT64_C(0x0000001)<<32 | v) << plane, \ |
||
70 | AV_LE2NE64C(UINT64_C(0x1000001)<<32 | v) << plane, \ |
||
71 | AV_LE2NE64C(UINT64_C(0x0010001)<<32 | v) << plane, \ |
||
72 | AV_LE2NE64C(UINT64_C(0x1010001)<<32 | v) << plane, \ |
||
73 | AV_LE2NE64C(UINT64_C(0x0000101)<<32 | v) << plane, \ |
||
74 | AV_LE2NE64C(UINT64_C(0x1000101)<<32 | v) << plane, \ |
||
75 | AV_LE2NE64C(UINT64_C(0x0010101)<<32 | v) << plane, \ |
||
76 | AV_LE2NE64C(UINT64_C(0x1010101)<<32 | v) << plane |
||
77 | |||
78 | #define LUT8(plane) { \ |
||
79 | LUT8_PART(plane, 0x0000000), \ |
||
80 | LUT8_PART(plane, 0x1000000), \ |
||
81 | LUT8_PART(plane, 0x0010000), \ |
||
82 | LUT8_PART(plane, 0x1010000), \ |
||
83 | LUT8_PART(plane, 0x0000100), \ |
||
84 | LUT8_PART(plane, 0x1000100), \ |
||
85 | LUT8_PART(plane, 0x0010100), \ |
||
86 | LUT8_PART(plane, 0x1010100), \ |
||
87 | LUT8_PART(plane, 0x0000001), \ |
||
88 | LUT8_PART(plane, 0x1000001), \ |
||
89 | LUT8_PART(plane, 0x0010001), \ |
||
90 | LUT8_PART(plane, 0x1010001), \ |
||
91 | LUT8_PART(plane, 0x0000101), \ |
||
92 | LUT8_PART(plane, 0x1000101), \ |
||
93 | LUT8_PART(plane, 0x0010101), \ |
||
94 | LUT8_PART(plane, 0x1010101), \ |
||
95 | } |
||
96 | |||
97 | // 8 planes * 8-bit mask |
||
98 | static const uint64_t plane8_lut[8][256] = { |
||
99 | LUT8(0), LUT8(1), LUT8(2), LUT8(3), |
||
100 | LUT8(4), LUT8(5), LUT8(6), LUT8(7), |
||
101 | }; |
||
102 | |||
103 | #define LUT32(plane) { \ |
||
104 | 0, 0, 0, 0, \ |
||
105 | 0, 0, 0, 1 << plane, \ |
||
106 | 0, 0, 1 << plane, 0, \ |
||
107 | 0, 0, 1 << plane, 1 << plane, \ |
||
108 | 0, 1 << plane, 0, 0, \ |
||
109 | 0, 1 << plane, 0, 1 << plane, \ |
||
110 | 0, 1 << plane, 1 << plane, 0, \ |
||
111 | 0, 1 << plane, 1 << plane, 1 << plane, \ |
||
112 | 1 << plane, 0, 0, 0, \ |
||
113 | 1 << plane, 0, 0, 1 << plane, \ |
||
114 | 1 << plane, 0, 1 << plane, 0, \ |
||
115 | 1 << plane, 0, 1 << plane, 1 << plane, \ |
||
116 | 1 << plane, 1 << plane, 0, 0, \ |
||
117 | 1 << plane, 1 << plane, 0, 1 << plane, \ |
||
118 | 1 << plane, 1 << plane, 1 << plane, 0, \ |
||
119 | 1 << plane, 1 << plane, 1 << plane, 1 << plane, \ |
||
120 | } |
||
121 | |||
122 | // 32 planes * 4-bit mask * 4 lookup tables each |
||
123 | static const uint32_t plane32_lut[32][16*4] = { |
||
124 | LUT32( 0), LUT32( 1), LUT32( 2), LUT32( 3), |
||
125 | LUT32( 4), LUT32( 5), LUT32( 6), LUT32( 7), |
||
126 | LUT32( 8), LUT32( 9), LUT32(10), LUT32(11), |
||
127 | LUT32(12), LUT32(13), LUT32(14), LUT32(15), |
||
128 | LUT32(16), LUT32(17), LUT32(18), LUT32(19), |
||
129 | LUT32(20), LUT32(21), LUT32(22), LUT32(23), |
||
130 | LUT32(24), LUT32(25), LUT32(26), LUT32(27), |
||
131 | LUT32(28), LUT32(29), LUT32(30), LUT32(31), |
||
132 | }; |
||
133 | |||
134 | // Gray to RGB, required for palette table of grayscale images with bpp < 8 |
||
135 | static av_always_inline uint32_t gray2rgb(const uint32_t x) { |
||
136 | return x << 16 | x << 8 | x; |
||
137 | } |
||
138 | |||
139 | /** |
||
140 | * Convert CMAP buffer (stored in extradata) to lavc palette format |
||
141 | */ |
||
142 | static int cmap_read_palette(AVCodecContext *avctx, uint32_t *pal) |
||
143 | { |
||
144 | IffContext *s = avctx->priv_data; |
||
145 | int count, i; |
||
146 | const uint8_t *const palette = avctx->extradata + AV_RB16(avctx->extradata); |
||
147 | int palette_size = avctx->extradata_size - AV_RB16(avctx->extradata); |
||
148 | |||
149 | if (avctx->bits_per_coded_sample > 8) { |
||
150 | av_log(avctx, AV_LOG_ERROR, "bits_per_coded_sample > 8 not supported\n"); |
||
151 | return AVERROR_INVALIDDATA; |
||
152 | } |
||
153 | |||
154 | count = 1 << avctx->bits_per_coded_sample; |
||
155 | // If extradata is smaller than actually needed, fill the remaining with black. |
||
156 | count = FFMIN(palette_size / 3, count); |
||
157 | if (count) { |
||
158 | for (i = 0; i < count; i++) |
||
159 | pal[i] = 0xFF000000 | AV_RB24(palette + i*3); |
||
160 | if (s->flags && count >= 32) { // EHB |
||
161 | for (i = 0; i < 32; i++) |
||
162 | pal[i + 32] = 0xFF000000 | (AV_RB24(palette + i*3) & 0xFEFEFE) >> 1; |
||
163 | count = FFMAX(count, 64); |
||
164 | } |
||
165 | } else { // Create gray-scale color palette for bps < 8 |
||
166 | count = 1 << avctx->bits_per_coded_sample; |
||
167 | |||
168 | for (i = 0; i < count; i++) |
||
169 | pal[i] = 0xFF000000 | gray2rgb((i * 255) >> avctx->bits_per_coded_sample); |
||
170 | } |
||
171 | if (s->masking == MASK_HAS_MASK) { |
||
172 | memcpy(pal + (1 << avctx->bits_per_coded_sample), pal, count * 4); |
||
173 | for (i = 0; i < count; i++) |
||
174 | pal[i] &= 0xFFFFFF; |
||
175 | } else if (s->masking == MASK_HAS_TRANSPARENT_COLOR && |
||
176 | s->transparency < 1 << avctx->bits_per_coded_sample) |
||
177 | pal[s->transparency] &= 0xFFFFFF; |
||
178 | return 0; |
||
179 | } |
||
180 | |||
181 | /** |
||
182 | * Extracts the IFF extra context and updates internal |
||
183 | * decoder structures. |
||
184 | * |
||
185 | * @param avctx the AVCodecContext where to extract extra context to |
||
186 | * @param avpkt the AVPacket to extract extra context from or NULL to use avctx |
||
187 | * @return >= 0 in case of success, a negative error code otherwise |
||
188 | */ |
||
189 | static int extract_header(AVCodecContext *const avctx, |
||
190 | const AVPacket *const avpkt) { |
||
191 | const uint8_t *buf; |
||
192 | unsigned buf_size; |
||
193 | IffContext *s = avctx->priv_data; |
||
194 | int i, palette_size; |
||
195 | |||
196 | if (avctx->extradata_size < 2) { |
||
197 | av_log(avctx, AV_LOG_ERROR, "not enough extradata\n"); |
||
198 | return AVERROR_INVALIDDATA; |
||
199 | } |
||
200 | palette_size = avctx->extradata_size - AV_RB16(avctx->extradata); |
||
201 | |||
202 | if (avpkt) { |
||
203 | int image_size; |
||
204 | if (avpkt->size < 2) |
||
205 | return AVERROR_INVALIDDATA; |
||
206 | image_size = avpkt->size - AV_RB16(avpkt->data); |
||
207 | buf = avpkt->data; |
||
208 | buf_size = bytestream_get_be16(&buf); |
||
209 | if (buf_size <= 1 || image_size <= 1) { |
||
210 | av_log(avctx, AV_LOG_ERROR, |
||
211 | "Invalid image size received: %u -> image data offset: %d\n", |
||
212 | buf_size, image_size); |
||
213 | return AVERROR_INVALIDDATA; |
||
214 | } |
||
215 | } else { |
||
216 | buf = avctx->extradata; |
||
217 | buf_size = bytestream_get_be16(&buf); |
||
218 | if (buf_size <= 1 || palette_size < 0) { |
||
219 | av_log(avctx, AV_LOG_ERROR, |
||
220 | "Invalid palette size received: %u -> palette data offset: %d\n", |
||
221 | buf_size, palette_size); |
||
222 | return AVERROR_INVALIDDATA; |
||
223 | } |
||
224 | } |
||
225 | |||
226 | if (buf_size >= 41) { |
||
227 | s->compression = bytestream_get_byte(&buf); |
||
228 | s->bpp = bytestream_get_byte(&buf); |
||
229 | s->ham = bytestream_get_byte(&buf); |
||
230 | s->flags = bytestream_get_byte(&buf); |
||
231 | s->transparency = bytestream_get_be16(&buf); |
||
232 | s->masking = bytestream_get_byte(&buf); |
||
233 | for (i = 0; i < 16; i++) |
||
234 | s->tvdc[i] = bytestream_get_be16(&buf); |
||
235 | |||
236 | if (s->masking == MASK_HAS_MASK) { |
||
237 | if (s->bpp >= 8 && !s->ham) { |
||
238 | avctx->pix_fmt = AV_PIX_FMT_RGB32; |
||
239 | av_freep(&s->mask_buf); |
||
240 | av_freep(&s->mask_palbuf); |
||
241 | s->mask_buf = av_malloc((s->planesize * 32) + FF_INPUT_BUFFER_PADDING_SIZE); |
||
242 | if (!s->mask_buf) |
||
243 | return AVERROR(ENOMEM); |
||
244 | if (s->bpp > 16) { |
||
245 | av_log(avctx, AV_LOG_ERROR, "bpp %d too large for palette\n", s->bpp); |
||
246 | av_freep(&s->mask_buf); |
||
247 | return AVERROR(ENOMEM); |
||
248 | } |
||
249 | s->mask_palbuf = av_malloc((2 << s->bpp) * sizeof(uint32_t) + FF_INPUT_BUFFER_PADDING_SIZE); |
||
250 | if (!s->mask_palbuf) { |
||
251 | av_freep(&s->mask_buf); |
||
252 | return AVERROR(ENOMEM); |
||
253 | } |
||
254 | } |
||
255 | s->bpp++; |
||
256 | } else if (s->masking != MASK_NONE && s->masking != MASK_HAS_TRANSPARENT_COLOR) { |
||
257 | av_log(avctx, AV_LOG_ERROR, "Masking not supported\n"); |
||
258 | return AVERROR_PATCHWELCOME; |
||
259 | } |
||
260 | if (!s->bpp || s->bpp > 32) { |
||
261 | av_log(avctx, AV_LOG_ERROR, "Invalid number of bitplanes: %u\n", s->bpp); |
||
262 | return AVERROR_INVALIDDATA; |
||
263 | } else if (s->ham >= 8) { |
||
264 | av_log(avctx, AV_LOG_ERROR, "Invalid number of hold bits for HAM: %u\n", s->ham); |
||
265 | return AVERROR_INVALIDDATA; |
||
266 | } |
||
267 | |||
268 | av_freep(&s->ham_buf); |
||
269 | av_freep(&s->ham_palbuf); |
||
270 | |||
271 | if (s->ham) { |
||
272 | int i, count = FFMIN(palette_size / 3, 1 << s->ham); |
||
273 | int ham_count; |
||
274 | const uint8_t *const palette = avctx->extradata + AV_RB16(avctx->extradata); |
||
275 | |||
276 | s->ham_buf = av_malloc((s->planesize * 8) + FF_INPUT_BUFFER_PADDING_SIZE); |
||
277 | if (!s->ham_buf) |
||
278 | return AVERROR(ENOMEM); |
||
279 | |||
280 | ham_count = 8 * (1 << s->ham); |
||
281 | s->ham_palbuf = av_malloc((ham_count << !!(s->masking == MASK_HAS_MASK)) * sizeof (uint32_t) + FF_INPUT_BUFFER_PADDING_SIZE); |
||
282 | if (!s->ham_palbuf) { |
||
283 | av_freep(&s->ham_buf); |
||
284 | return AVERROR(ENOMEM); |
||
285 | } |
||
286 | |||
287 | if (count) { // HAM with color palette attached |
||
288 | // prefill with black and palette and set HAM take direct value mask to zero |
||
289 | memset(s->ham_palbuf, 0, (1 << s->ham) * 2 * sizeof (uint32_t)); |
||
290 | for (i=0; i < count; i++) { |
||
291 | s->ham_palbuf[i*2+1] = 0xFF000000 | AV_RL24(palette + i*3); |
||
292 | } |
||
293 | count = 1 << s->ham; |
||
294 | } else { // HAM with grayscale color palette |
||
295 | count = 1 << s->ham; |
||
296 | for (i=0; i < count; i++) { |
||
297 | s->ham_palbuf[i*2] = 0xFF000000; // take direct color value from palette |
||
298 | s->ham_palbuf[i*2+1] = 0xFF000000 | av_le2ne32(gray2rgb((i * 255) >> s->ham)); |
||
299 | } |
||
300 | } |
||
301 | for (i=0; i < count; i++) { |
||
302 | uint32_t tmp = i << (8 - s->ham); |
||
303 | tmp |= tmp >> s->ham; |
||
304 | s->ham_palbuf[(i+count)*2] = 0xFF00FFFF; // just modify blue color component |
||
305 | s->ham_palbuf[(i+count*2)*2] = 0xFFFFFF00; // just modify red color component |
||
306 | s->ham_palbuf[(i+count*3)*2] = 0xFFFF00FF; // just modify green color component |
||
307 | s->ham_palbuf[(i+count)*2+1] = 0xFF000000 | tmp << 16; |
||
308 | s->ham_palbuf[(i+count*2)*2+1] = 0xFF000000 | tmp; |
||
309 | s->ham_palbuf[(i+count*3)*2+1] = 0xFF000000 | tmp << 8; |
||
310 | } |
||
311 | if (s->masking == MASK_HAS_MASK) { |
||
312 | for (i = 0; i < ham_count; i++) |
||
313 | s->ham_palbuf[(1 << s->bpp) + i] = s->ham_palbuf[i] | 0xFF000000; |
||
314 | } |
||
315 | } |
||
316 | } |
||
317 | |||
318 | return 0; |
||
319 | } |
||
320 | |||
321 | static av_cold int decode_init(AVCodecContext *avctx) |
||
322 | { |
||
323 | IffContext *s = avctx->priv_data; |
||
324 | int err; |
||
325 | |||
326 | if (avctx->bits_per_coded_sample <= 8) { |
||
327 | int palette_size; |
||
328 | |||
329 | if (avctx->extradata_size >= 2) |
||
330 | palette_size = avctx->extradata_size - AV_RB16(avctx->extradata); |
||
331 | else |
||
332 | palette_size = 0; |
||
333 | avctx->pix_fmt = (avctx->bits_per_coded_sample < 8) || |
||
334 | (avctx->extradata_size >= 2 && palette_size) ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_GRAY8; |
||
335 | } else if (avctx->bits_per_coded_sample <= 32) { |
||
336 | if (avctx->codec_tag == MKTAG('R', 'G', 'B', '8')) { |
||
337 | avctx->pix_fmt = AV_PIX_FMT_RGB32; |
||
338 | } else if (avctx->codec_tag == MKTAG('R', 'G', 'B', 'N')) { |
||
339 | avctx->pix_fmt = AV_PIX_FMT_RGB444; |
||
340 | } else if (avctx->codec_tag != MKTAG('D', 'E', 'E', 'P')) { |
||
341 | if (avctx->bits_per_coded_sample == 24) { |
||
342 | avctx->pix_fmt = AV_PIX_FMT_0BGR32; |
||
343 | } else if (avctx->bits_per_coded_sample == 32) { |
||
344 | avctx->pix_fmt = AV_PIX_FMT_BGR32; |
||
345 | } else { |
||
346 | avpriv_request_sample(avctx, "unknown bits_per_coded_sample"); |
||
347 | return AVERROR_PATCHWELCOME; |
||
348 | } |
||
349 | } |
||
350 | } else { |
||
351 | return AVERROR_INVALIDDATA; |
||
352 | } |
||
353 | |||
354 | if ((err = av_image_check_size(avctx->width, avctx->height, 0, avctx))) |
||
355 | return err; |
||
356 | s->planesize = FFALIGN(avctx->width, 16) >> 3; // Align plane size in bits to word-boundary |
||
357 | s->planebuf = av_malloc(s->planesize + FF_INPUT_BUFFER_PADDING_SIZE); |
||
358 | if (!s->planebuf) |
||
359 | return AVERROR(ENOMEM); |
||
360 | |||
361 | s->bpp = avctx->bits_per_coded_sample; |
||
362 | s->frame = av_frame_alloc(); |
||
363 | if (!s->frame) |
||
364 | return AVERROR(ENOMEM); |
||
365 | |||
366 | if ((err = extract_header(avctx, NULL)) < 0) |
||
367 | return err; |
||
368 | |||
369 | return 0; |
||
370 | } |
||
371 | |||
372 | /** |
||
373 | * Decode interleaved plane buffer up to 8bpp |
||
374 | * @param dst Destination buffer |
||
375 | * @param buf Source buffer |
||
376 | * @param buf_size |
||
377 | * @param plane plane number to decode as |
||
378 | */ |
||
379 | static void decodeplane8(uint8_t *dst, const uint8_t *buf, int buf_size, int plane) |
||
380 | { |
||
381 | const uint64_t *lut = plane8_lut[plane]; |
||
382 | if (plane >= 8) { |
||
383 | av_log(NULL, AV_LOG_WARNING, "Ignoring extra planes beyond 8\n"); |
||
384 | return; |
||
385 | } |
||
386 | do { |
||
387 | uint64_t v = AV_RN64A(dst) | lut[*buf++]; |
||
388 | AV_WN64A(dst, v); |
||
389 | dst += 8; |
||
390 | } while (--buf_size); |
||
391 | } |
||
392 | |||
393 | /** |
||
394 | * Decode interleaved plane buffer up to 24bpp |
||
395 | * @param dst Destination buffer |
||
396 | * @param buf Source buffer |
||
397 | * @param buf_size |
||
398 | * @param plane plane number to decode as |
||
399 | */ |
||
400 | static void decodeplane32(uint32_t *dst, const uint8_t *buf, int buf_size, int plane) |
||
401 | { |
||
402 | const uint32_t *lut = plane32_lut[plane]; |
||
403 | do { |
||
404 | unsigned mask = (*buf >> 2) & ~3; |
||
405 | dst[0] |= lut[mask++]; |
||
406 | dst[1] |= lut[mask++]; |
||
407 | dst[2] |= lut[mask++]; |
||
408 | dst[3] |= lut[mask]; |
||
409 | mask = (*buf++ << 2) & 0x3F; |
||
410 | dst[4] |= lut[mask++]; |
||
411 | dst[5] |= lut[mask++]; |
||
412 | dst[6] |= lut[mask++]; |
||
413 | dst[7] |= lut[mask]; |
||
414 | dst += 8; |
||
415 | } while (--buf_size); |
||
416 | } |
||
417 | |||
418 | #define DECODE_HAM_PLANE32(x) \ |
||
419 | first = buf[x] << 1; \ |
||
420 | second = buf[(x)+1] << 1; \ |
||
421 | delta &= pal[first++]; \ |
||
422 | delta |= pal[first]; \ |
||
423 | dst[x] = delta; \ |
||
424 | delta &= pal[second++]; \ |
||
425 | delta |= pal[second]; \ |
||
426 | dst[(x)+1] = delta |
||
427 | |||
428 | /** |
||
429 | * Converts one line of HAM6/8-encoded chunky buffer to 24bpp. |
||
430 | * |
||
431 | * @param dst the destination 24bpp buffer |
||
432 | * @param buf the source 8bpp chunky buffer |
||
433 | * @param pal the HAM decode table |
||
434 | * @param buf_size the plane size in bytes |
||
435 | */ |
||
436 | static void decode_ham_plane32(uint32_t *dst, const uint8_t *buf, |
||
437 | const uint32_t *const pal, unsigned buf_size) |
||
438 | { |
||
439 | uint32_t delta = pal[1]; /* first palette entry */ |
||
440 | do { |
||
441 | uint32_t first, second; |
||
442 | DECODE_HAM_PLANE32(0); |
||
443 | DECODE_HAM_PLANE32(2); |
||
444 | DECODE_HAM_PLANE32(4); |
||
445 | DECODE_HAM_PLANE32(6); |
||
446 | buf += 8; |
||
447 | dst += 8; |
||
448 | } while (--buf_size); |
||
449 | } |
||
450 | |||
451 | static void lookup_pal_indicies(uint32_t *dst, const uint32_t *buf, |
||
452 | const uint32_t *const pal, unsigned width) |
||
453 | { |
||
454 | do { |
||
455 | *dst++ = pal[*buf++]; |
||
456 | } while (--width); |
||
457 | } |
||
458 | |||
459 | /** |
||
460 | * Decode one complete byterun1 encoded line. |
||
461 | * |
||
462 | * @param dst the destination buffer where to store decompressed bitstream |
||
463 | * @param dst_size the destination plane size in bytes |
||
464 | * @param buf the source byterun1 compressed bitstream |
||
465 | * @param buf_end the EOF of source byterun1 compressed bitstream |
||
466 | * @return number of consumed bytes in byterun1 compressed bitstream |
||
467 | */ |
||
468 | static int decode_byterun(uint8_t *dst, int dst_size, |
||
469 | const uint8_t *buf, const uint8_t *const buf_end) |
||
470 | { |
||
471 | const uint8_t *const buf_start = buf; |
||
472 | unsigned x; |
||
473 | for (x = 0; x < dst_size && buf < buf_end;) { |
||
474 | unsigned length; |
||
475 | const int8_t value = *buf++; |
||
476 | if (value >= 0) { |
||
477 | length = value + 1; |
||
478 | memcpy(dst + x, buf, FFMIN3(length, dst_size - x, buf_end - buf)); |
||
479 | buf += length; |
||
480 | } else if (value > -128) { |
||
481 | length = -value + 1; |
||
482 | memset(dst + x, *buf++, FFMIN(length, dst_size - x)); |
||
483 | } else { // noop |
||
484 | continue; |
||
485 | } |
||
486 | x += length; |
||
487 | } |
||
488 | return buf - buf_start; |
||
489 | } |
||
490 | |||
491 | #define DECODE_RGBX_COMMON(type) \ |
||
492 | if (!length) { \ |
||
493 | length = bytestream2_get_byte(gb); \ |
||
494 | if (!length) { \ |
||
495 | length = bytestream2_get_be16(gb); \ |
||
496 | if (!length) \ |
||
497 | return; \ |
||
498 | } \ |
||
499 | } \ |
||
500 | for (i = 0; i < length; i++) { \ |
||
501 | *(type *)(dst + y*linesize + x * sizeof(type)) = pixel; \ |
||
502 | x += 1; \ |
||
503 | if (x >= width) { \ |
||
504 | y += 1; \ |
||
505 | if (y >= height) \ |
||
506 | return; \ |
||
507 | x = 0; \ |
||
508 | } \ |
||
509 | } |
||
510 | |||
511 | /** |
||
512 | * Decode RGB8 buffer |
||
513 | * @param[out] dst Destination buffer |
||
514 | * @param width Width of destination buffer (pixels) |
||
515 | * @param height Height of destination buffer (pixels) |
||
516 | * @param linesize Line size of destination buffer (bytes) |
||
517 | */ |
||
518 | static void decode_rgb8(GetByteContext *gb, uint8_t *dst, int width, int height, int linesize) |
||
519 | { |
||
520 | int x = 0, y = 0, i, length; |
||
521 | while (bytestream2_get_bytes_left(gb) >= 4) { |
||
522 | uint32_t pixel = 0xFF000000 | bytestream2_get_be24(gb); |
||
523 | length = bytestream2_get_byte(gb) & 0x7F; |
||
524 | DECODE_RGBX_COMMON(uint32_t) |
||
525 | } |
||
526 | } |
||
527 | |||
528 | /** |
||
529 | * Decode RGBN buffer |
||
530 | * @param[out] dst Destination buffer |
||
531 | * @param width Width of destination buffer (pixels) |
||
532 | * @param height Height of destination buffer (pixels) |
||
533 | * @param linesize Line size of destination buffer (bytes) |
||
534 | */ |
||
535 | static void decode_rgbn(GetByteContext *gb, uint8_t *dst, int width, int height, int linesize) |
||
536 | { |
||
537 | int x = 0, y = 0, i, length; |
||
538 | while (bytestream2_get_bytes_left(gb) >= 2) { |
||
539 | uint32_t pixel = bytestream2_get_be16u(gb); |
||
540 | length = pixel & 0x7; |
||
541 | pixel >>= 4; |
||
542 | DECODE_RGBX_COMMON(uint16_t) |
||
543 | } |
||
544 | } |
||
545 | |||
546 | /** |
||
547 | * Decode DEEP RLE 32-bit buffer |
||
548 | * @param[out] dst Destination buffer |
||
549 | * @param[in] src Source buffer |
||
550 | * @param src_size Source buffer size (bytes) |
||
551 | * @param width Width of destination buffer (pixels) |
||
552 | * @param height Height of destination buffer (pixels) |
||
553 | * @param linesize Line size of destination buffer (bytes) |
||
554 | */ |
||
555 | static void decode_deep_rle32(uint8_t *dst, const uint8_t *src, int src_size, int width, int height, int linesize) |
||
556 | { |
||
557 | const uint8_t *src_end = src + src_size; |
||
558 | int x = 0, y = 0, i; |
||
559 | while (src + 5 <= src_end) { |
||
560 | int opcode; |
||
561 | opcode = *(int8_t *)src++; |
||
562 | if (opcode >= 0) { |
||
563 | int size = opcode + 1; |
||
564 | for (i = 0; i < size; i++) { |
||
565 | int length = FFMIN(size - i, width); |
||
566 | memcpy(dst + y*linesize + x * 4, src, length * 4); |
||
567 | src += length * 4; |
||
568 | x += length; |
||
569 | i += length; |
||
570 | if (x >= width) { |
||
571 | x = 0; |
||
572 | y += 1; |
||
573 | if (y >= height) |
||
574 | return; |
||
575 | } |
||
576 | } |
||
577 | } else { |
||
578 | int size = -opcode + 1; |
||
579 | uint32_t pixel = AV_RN32(src); |
||
580 | for (i = 0; i < size; i++) { |
||
581 | *(uint32_t *)(dst + y*linesize + x * 4) = pixel; |
||
582 | x += 1; |
||
583 | if (x >= width) { |
||
584 | x = 0; |
||
585 | y += 1; |
||
586 | if (y >= height) |
||
587 | return; |
||
588 | } |
||
589 | } |
||
590 | src += 4; |
||
591 | } |
||
592 | } |
||
593 | } |
||
594 | |||
595 | /** |
||
596 | * Decode DEEP TVDC 32-bit buffer |
||
597 | * @param[out] dst Destination buffer |
||
598 | * @param[in] src Source buffer |
||
599 | * @param src_size Source buffer size (bytes) |
||
600 | * @param width Width of destination buffer (pixels) |
||
601 | * @param height Height of destination buffer (pixels) |
||
602 | * @param linesize Line size of destination buffer (bytes) |
||
603 | * @param[int] tvdc TVDC lookup table |
||
604 | */ |
||
605 | static void decode_deep_tvdc32(uint8_t *dst, const uint8_t *src, int src_size, int width, int height, int linesize, const int16_t *tvdc) |
||
606 | { |
||
607 | int x = 0, y = 0, plane = 0; |
||
608 | int8_t pixel = 0; |
||
609 | int i, j; |
||
610 | |||
611 | for (i = 0; i < src_size * 2;) { |
||
612 | #define GETNIBBLE ((i & 1) ? (src[i>>1] & 0xF) : (src[i>>1] >> 4)) |
||
613 | int d = tvdc[GETNIBBLE]; |
||
614 | i++; |
||
615 | if (d) { |
||
616 | pixel += d; |
||
617 | dst[y * linesize + x*4 + plane] = pixel; |
||
618 | x++; |
||
619 | } else { |
||
620 | if (i >= src_size * 2) |
||
621 | return; |
||
622 | d = GETNIBBLE + 1; |
||
623 | i++; |
||
624 | d = FFMIN(d, width - x); |
||
625 | for (j = 0; j < d; j++) { |
||
626 | dst[y * linesize + x*4 + plane] = pixel; |
||
627 | x++; |
||
628 | } |
||
629 | } |
||
630 | if (x >= width) { |
||
631 | plane++; |
||
632 | if (plane >= 4) { |
||
633 | y++; |
||
634 | if (y >= height) |
||
635 | return; |
||
636 | plane = 0; |
||
637 | } |
||
638 | x = 0; |
||
639 | pixel = 0; |
||
640 | i = (i + 1) & ~1; |
||
641 | } |
||
642 | } |
||
643 | } |
||
644 | |||
645 | static int unsupported(AVCodecContext *avctx) |
||
646 | { |
||
647 | IffContext *s = avctx->priv_data; |
||
648 | avpriv_request_sample(avctx, "bitmap (compression %i, bpp %i, ham %i)", s->compression, s->bpp, s->ham); |
||
649 | return AVERROR_INVALIDDATA; |
||
650 | } |
||
651 | |||
652 | static int decode_frame(AVCodecContext *avctx, |
||
653 | void *data, int *got_frame, |
||
654 | AVPacket *avpkt) |
||
655 | { |
||
656 | IffContext *s = avctx->priv_data; |
||
657 | const uint8_t *buf = avpkt->size >= 2 ? avpkt->data + AV_RB16(avpkt->data) : NULL; |
||
658 | const int buf_size = avpkt->size >= 2 ? avpkt->size - AV_RB16(avpkt->data) : 0; |
||
659 | const uint8_t *buf_end = buf + buf_size; |
||
660 | int y, plane, res; |
||
661 | GetByteContext gb; |
||
662 | |||
663 | if ((res = extract_header(avctx, avpkt)) < 0) |
||
664 | return res; |
||
665 | if ((res = ff_reget_buffer(avctx, s->frame)) < 0) |
||
666 | return res; |
||
667 | if (!s->init && avctx->bits_per_coded_sample <= 8 && |
||
668 | avctx->pix_fmt == AV_PIX_FMT_PAL8) { |
||
669 | if ((res = cmap_read_palette(avctx, (uint32_t *)s->frame->data[1])) < 0) |
||
670 | return res; |
||
671 | } else if (!s->init && avctx->bits_per_coded_sample <= 8 && |
||
672 | avctx->pix_fmt == AV_PIX_FMT_RGB32) { |
||
673 | if ((res = cmap_read_palette(avctx, s->mask_palbuf)) < 0) |
||
674 | return res; |
||
675 | } |
||
676 | s->init = 1; |
||
677 | |||
678 | switch (s->compression) { |
||
679 | case 0: |
||
680 | if (avctx->codec_tag == MKTAG('A', 'C', 'B', 'M')) { |
||
681 | if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { |
||
682 | memset(s->frame->data[0], 0, avctx->height * s->frame->linesize[0]); |
||
683 | for (plane = 0; plane < s->bpp; plane++) { |
||
684 | for (y = 0; y < avctx->height && buf < buf_end; y++) { |
||
685 | uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; |
||
686 | decodeplane8(row, buf, FFMIN(s->planesize, buf_end - buf), plane); |
||
687 | buf += s->planesize; |
||
688 | } |
||
689 | } |
||
690 | } else if (s->ham) { // HAM to AV_PIX_FMT_BGR32 |
||
691 | memset(s->frame->data[0], 0, avctx->height * s->frame->linesize[0]); |
||
692 | for (y = 0; y < avctx->height; y++) { |
||
693 | uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; |
||
694 | memset(s->ham_buf, 0, s->planesize * 8); |
||
695 | for (plane = 0; plane < s->bpp; plane++) { |
||
696 | const uint8_t * start = buf + (plane * avctx->height + y) * s->planesize; |
||
697 | if (start >= buf_end) |
||
698 | break; |
||
699 | decodeplane8(s->ham_buf, start, FFMIN(s->planesize, buf_end - start), plane); |
||
700 | } |
||
701 | decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize); |
||
702 | } |
||
703 | } else |
||
704 | return unsupported(avctx); |
||
705 | } else if (avctx->codec_tag == MKTAG('D', 'E', 'E', 'P')) { |
||
706 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); |
||
707 | int raw_width = avctx->width * (av_get_bits_per_pixel(desc) >> 3); |
||
708 | int x; |
||
709 | for (y = 0; y < avctx->height && buf < buf_end; y++) { |
||
710 | uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; |
||
711 | memcpy(row, buf, FFMIN(raw_width, buf_end - buf)); |
||
712 | buf += raw_width; |
||
713 | if (avctx->pix_fmt == AV_PIX_FMT_BGR32) { |
||
714 | for (x = 0; x < avctx->width; x++) |
||
715 | row[4 * x + 3] = row[4 * x + 3] & 0xF0 | (row[4 * x + 3] >> 4); |
||
716 | } |
||
717 | } |
||
718 | } else if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M')) { // interleaved |
||
719 | if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { |
||
720 | for (y = 0; y < avctx->height; y++) { |
||
721 | uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; |
||
722 | memset(row, 0, avctx->width); |
||
723 | for (plane = 0; plane < s->bpp && buf < buf_end; plane++) { |
||
724 | decodeplane8(row, buf, FFMIN(s->planesize, buf_end - buf), plane); |
||
725 | buf += s->planesize; |
||
726 | } |
||
727 | } |
||
728 | } else if (s->ham) { // HAM to AV_PIX_FMT_BGR32 |
||
729 | for (y = 0; y < avctx->height; y++) { |
||
730 | uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; |
||
731 | memset(s->ham_buf, 0, s->planesize * 8); |
||
732 | for (plane = 0; plane < s->bpp && buf < buf_end; plane++) { |
||
733 | decodeplane8(s->ham_buf, buf, FFMIN(s->planesize, buf_end - buf), plane); |
||
734 | buf += s->planesize; |
||
735 | } |
||
736 | decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize); |
||
737 | } |
||
738 | } else { // AV_PIX_FMT_BGR32 |
||
739 | for (y = 0; y < avctx->height; y++) { |
||
740 | uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; |
||
741 | memset(row, 0, avctx->width << 2); |
||
742 | for (plane = 0; plane < s->bpp && buf < buf_end; plane++) { |
||
743 | decodeplane32((uint32_t *)row, buf, |
||
744 | FFMIN(s->planesize, buf_end - buf), plane); |
||
745 | buf += s->planesize; |
||
746 | } |
||
747 | } |
||
748 | } |
||
749 | } else if (avctx->codec_tag == MKTAG('P', 'B', 'M', ' ')) { // IFF-PBM |
||
750 | if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { |
||
751 | for (y = 0; y < avctx->height && buf_end > buf; y++) { |
||
752 | uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; |
||
753 | memcpy(row, buf, FFMIN(avctx->width, buf_end - buf)); |
||
754 | buf += avctx->width + (avctx->width % 2); // padding if odd |
||
755 | } |
||
756 | } else if (s->ham) { // IFF-PBM: HAM to AV_PIX_FMT_BGR32 |
||
757 | for (y = 0; y < avctx->height && buf_end > buf; y++) { |
||
758 | uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; |
||
759 | memcpy(s->ham_buf, buf, FFMIN(avctx->width, buf_end - buf)); |
||
760 | buf += avctx->width + (avctx->width & 1); // padding if odd |
||
761 | decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize); |
||
762 | } |
||
763 | } else |
||
764 | return unsupported(avctx); |
||
765 | } |
||
766 | break; |
||
767 | case 1: |
||
768 | if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M')) { // interleaved |
||
769 | if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { |
||
770 | for (y = 0; y < avctx->height; y++) { |
||
771 | uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; |
||
772 | memset(row, 0, avctx->width); |
||
773 | for (plane = 0; plane < s->bpp; plane++) { |
||
774 | buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end); |
||
775 | decodeplane8(row, s->planebuf, s->planesize, plane); |
||
776 | } |
||
777 | } |
||
778 | } else if (avctx->bits_per_coded_sample <= 8) { //8-bit (+ mask) to AV_PIX_FMT_BGR32 |
||
779 | for (y = 0; y < avctx->height; y++) { |
||
780 | uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; |
||
781 | memset(s->mask_buf, 0, avctx->width * sizeof(uint32_t)); |
||
782 | for (plane = 0; plane < s->bpp; plane++) { |
||
783 | buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end); |
||
784 | decodeplane32(s->mask_buf, s->planebuf, s->planesize, plane); |
||
785 | } |
||
786 | lookup_pal_indicies((uint32_t *)row, s->mask_buf, s->mask_palbuf, avctx->width); |
||
787 | } |
||
788 | } else if (s->ham) { // HAM to AV_PIX_FMT_BGR32 |
||
789 | for (y = 0; y < avctx->height; y++) { |
||
790 | uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; |
||
791 | memset(s->ham_buf, 0, s->planesize * 8); |
||
792 | for (plane = 0; plane < s->bpp; plane++) { |
||
793 | buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end); |
||
794 | decodeplane8(s->ham_buf, s->planebuf, s->planesize, plane); |
||
795 | } |
||
796 | decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize); |
||
797 | } |
||
798 | } else { // AV_PIX_FMT_BGR32 |
||
799 | for (y = 0; y < avctx->height; y++) { |
||
800 | uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; |
||
801 | memset(row, 0, avctx->width << 2); |
||
802 | for (plane = 0; plane < s->bpp; plane++) { |
||
803 | buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end); |
||
804 | decodeplane32((uint32_t *)row, s->planebuf, s->planesize, plane); |
||
805 | } |
||
806 | } |
||
807 | } |
||
808 | } else if (avctx->codec_tag == MKTAG('P', 'B', 'M', ' ')) { // IFF-PBM |
||
809 | if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { |
||
810 | for (y = 0; y < avctx->height; y++) { |
||
811 | uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; |
||
812 | buf += decode_byterun(row, avctx->width, buf, buf_end); |
||
813 | } |
||
814 | } else if (s->ham) { // IFF-PBM: HAM to AV_PIX_FMT_BGR32 |
||
815 | for (y = 0; y < avctx->height; y++) { |
||
816 | uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]]; |
||
817 | buf += decode_byterun(s->ham_buf, avctx->width, buf, buf_end); |
||
818 | decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize); |
||
819 | } |
||
820 | } else |
||
821 | return unsupported(avctx); |
||
822 | } else if (avctx->codec_tag == MKTAG('D', 'E', 'E', 'P')) { // IFF-DEEP |
||
823 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); |
||
824 | if (av_get_bits_per_pixel(desc) == 32) |
||
825 | decode_deep_rle32(s->frame->data[0], buf, buf_size, avctx->width, avctx->height, s->frame->linesize[0]); |
||
826 | else |
||
827 | return unsupported(avctx); |
||
828 | } |
||
829 | break; |
||
830 | case 4: |
||
831 | bytestream2_init(&gb, buf, buf_size); |
||
832 | if (avctx->codec_tag == MKTAG('R', 'G', 'B', '8')) |
||
833 | decode_rgb8(&gb, s->frame->data[0], avctx->width, avctx->height, s->frame->linesize[0]); |
||
834 | else if (avctx->codec_tag == MKTAG('R', 'G', 'B', 'N')) |
||
835 | decode_rgbn(&gb, s->frame->data[0], avctx->width, avctx->height, s->frame->linesize[0]); |
||
836 | else |
||
837 | return unsupported(avctx); |
||
838 | break; |
||
839 | case 5: |
||
840 | if (avctx->codec_tag == MKTAG('D', 'E', 'E', 'P')) { |
||
841 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); |
||
842 | if (av_get_bits_per_pixel(desc) == 32) |
||
843 | decode_deep_tvdc32(s->frame->data[0], buf, buf_size, avctx->width, avctx->height, s->frame->linesize[0], s->tvdc); |
||
844 | else |
||
845 | return unsupported(avctx); |
||
846 | } else |
||
847 | return unsupported(avctx); |
||
848 | break; |
||
849 | default: |
||
850 | return unsupported(avctx); |
||
851 | } |
||
852 | |||
853 | if ((res = av_frame_ref(data, s->frame)) < 0) |
||
854 | return res; |
||
855 | |||
856 | *got_frame = 1; |
||
857 | |||
858 | return buf_size; |
||
859 | } |
||
860 | |||
861 | static av_cold int decode_end(AVCodecContext *avctx) |
||
862 | { |
||
863 | IffContext *s = avctx->priv_data; |
||
864 | av_frame_free(&s->frame); |
||
865 | av_freep(&s->planebuf); |
||
866 | av_freep(&s->ham_buf); |
||
867 | av_freep(&s->ham_palbuf); |
||
868 | return 0; |
||
869 | } |
||
870 | |||
871 | #if CONFIG_IFF_ILBM_DECODER |
||
872 | AVCodec ff_iff_ilbm_decoder = { |
||
873 | .name = "iff", |
||
874 | .long_name = NULL_IF_CONFIG_SMALL("IFF"), |
||
875 | .type = AVMEDIA_TYPE_VIDEO, |
||
876 | .id = AV_CODEC_ID_IFF_ILBM, |
||
877 | .priv_data_size = sizeof(IffContext), |
||
878 | .init = decode_init, |
||
879 | .close = decode_end, |
||
880 | .decode = decode_frame, |
||
881 | .capabilities = CODEC_CAP_DR1, |
||
882 | }; |
||
883 | #endif |
||
884 | #if CONFIG_IFF_BYTERUN1_DECODER |
||
885 | AVCodec ff_iff_byterun1_decoder = { |
||
886 | .name = "iff", |
||
887 | .long_name = NULL_IF_CONFIG_SMALL("IFF"), |
||
888 | .type = AVMEDIA_TYPE_VIDEO, |
||
889 | .id = AV_CODEC_ID_IFF_BYTERUN1, |
||
890 | .priv_data_size = sizeof(IffContext), |
||
891 | .init = decode_init, |
||
892 | .close = decode_end, |
||
893 | .decode = decode_frame, |
||
894 | .capabilities = CODEC_CAP_DR1, |
||
895 | }; |
||
896 | #endif>>>>><>>>>>>=>>>>>>>><>>>>>>>>>>>>>>>>>=>>=>>>>>>>=>>>>><>><>><>>=>>=>><>>><>><>><>>>><>><>>><>><>><>><>><>>>=>=>=>>>><>>>><>>><>>>>><>><>><>>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>32><32>><>32><32>><>32><32>><>32><32>><>32><32>><>32><32>><>32><32>><>32><32>><>32><32>><>32><32>><>32><32>><>32><32>><>32><32>><>32><32>><>32><32>><>32><32>>>>>>>>>>>> |