2 * IFF PBM/ILBM bitmap decoder
3 * Copyright (c) 2010 Peter Ross <pross@xvid.org>
4 * Copyright (c) 2010 Sebastian Vater <cdgs.basty@googlemail.com>
6 * This file is part of FFmpeg.
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.
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.
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
25 * IFF PBM/ILBM bitmap decoder
28 #include "libavutil/imgutils.h"
29 #include "bytestream.h"
37 MASK_HAS_TRANSPARENT_COLOR,
45 uint8_t * ham_buf; ///< temporary buffer for planar to chunky conversation
46 uint32_t *ham_palbuf; ///< HAM decode table
47 unsigned compression; ///< delta compression method used
48 unsigned bpp; ///< bits per plane to decode (differs from bits_per_coded_sample if HAM)
49 unsigned ham; ///< 0 if non-HAM or number of hold bits (6 for bpp > 6, 4 otherwise)
50 unsigned flags; ///< 1 for EHB, 0 is no extra half darkening
51 unsigned transparency; ///< TODO: transparency color index in palette
52 unsigned masking; ///< TODO: masking method used
53 int init; // 1 if buffer and palette data already initialized, 0 otherwise
56 #define LUT8_PART(plane, v) \
57 AV_LE2NE64C(UINT64_C(0x0000000)<<32 | v) << plane, \
58 AV_LE2NE64C(UINT64_C(0x1000000)<<32 | v) << plane, \
59 AV_LE2NE64C(UINT64_C(0x0010000)<<32 | v) << plane, \
60 AV_LE2NE64C(UINT64_C(0x1010000)<<32 | v) << plane, \
61 AV_LE2NE64C(UINT64_C(0x0000100)<<32 | v) << plane, \
62 AV_LE2NE64C(UINT64_C(0x1000100)<<32 | v) << plane, \
63 AV_LE2NE64C(UINT64_C(0x0010100)<<32 | v) << plane, \
64 AV_LE2NE64C(UINT64_C(0x1010100)<<32 | v) << plane, \
65 AV_LE2NE64C(UINT64_C(0x0000001)<<32 | v) << plane, \
66 AV_LE2NE64C(UINT64_C(0x1000001)<<32 | v) << plane, \
67 AV_LE2NE64C(UINT64_C(0x0010001)<<32 | v) << plane, \
68 AV_LE2NE64C(UINT64_C(0x1010001)<<32 | v) << plane, \
69 AV_LE2NE64C(UINT64_C(0x0000101)<<32 | v) << plane, \
70 AV_LE2NE64C(UINT64_C(0x1000101)<<32 | v) << plane, \
71 AV_LE2NE64C(UINT64_C(0x0010101)<<32 | v) << plane, \
72 AV_LE2NE64C(UINT64_C(0x1010101)<<32 | v) << plane
74 #define LUT8(plane) { \
75 LUT8_PART(plane, 0x0000000), \
76 LUT8_PART(plane, 0x1000000), \
77 LUT8_PART(plane, 0x0010000), \
78 LUT8_PART(plane, 0x1010000), \
79 LUT8_PART(plane, 0x0000100), \
80 LUT8_PART(plane, 0x1000100), \
81 LUT8_PART(plane, 0x0010100), \
82 LUT8_PART(plane, 0x1010100), \
83 LUT8_PART(plane, 0x0000001), \
84 LUT8_PART(plane, 0x1000001), \
85 LUT8_PART(plane, 0x0010001), \
86 LUT8_PART(plane, 0x1010001), \
87 LUT8_PART(plane, 0x0000101), \
88 LUT8_PART(plane, 0x1000101), \
89 LUT8_PART(plane, 0x0010101), \
90 LUT8_PART(plane, 0x1010101), \
93 // 8 planes * 8-bit mask
94 static const uint64_t plane8_lut[8][256] = {
95 LUT8(0), LUT8(1), LUT8(2), LUT8(3),
96 LUT8(4), LUT8(5), LUT8(6), LUT8(7),
99 #define LUT32(plane) { \
101 0, 0, 0, 1 << plane, \
102 0, 0, 1 << plane, 0, \
103 0, 0, 1 << plane, 1 << plane, \
104 0, 1 << plane, 0, 0, \
105 0, 1 << plane, 0, 1 << plane, \
106 0, 1 << plane, 1 << plane, 0, \
107 0, 1 << plane, 1 << plane, 1 << plane, \
108 1 << plane, 0, 0, 0, \
109 1 << plane, 0, 0, 1 << plane, \
110 1 << plane, 0, 1 << plane, 0, \
111 1 << plane, 0, 1 << plane, 1 << plane, \
112 1 << plane, 1 << plane, 0, 0, \
113 1 << plane, 1 << plane, 0, 1 << plane, \
114 1 << plane, 1 << plane, 1 << plane, 0, \
115 1 << plane, 1 << plane, 1 << plane, 1 << plane, \
118 // 32 planes * 4-bit mask * 4 lookup tables each
119 static const uint32_t plane32_lut[32][16*4] = {
120 LUT32( 0), LUT32( 1), LUT32( 2), LUT32( 3),
121 LUT32( 4), LUT32( 5), LUT32( 6), LUT32( 7),
122 LUT32( 8), LUT32( 9), LUT32(10), LUT32(11),
123 LUT32(12), LUT32(13), LUT32(14), LUT32(15),
124 LUT32(16), LUT32(17), LUT32(18), LUT32(19),
125 LUT32(20), LUT32(21), LUT32(22), LUT32(23),
126 LUT32(24), LUT32(25), LUT32(26), LUT32(27),
127 LUT32(28), LUT32(29), LUT32(30), LUT32(31),
130 // Gray to RGB, required for palette table of grayscale images with bpp < 8
131 static av_always_inline uint32_t gray2rgb(const uint32_t x) {
132 return x << 16 | x << 8 | x;
136 * Convert CMAP buffer (stored in extradata) to lavc palette format
138 static int ff_cmap_read_palette(AVCodecContext *avctx, uint32_t *pal)
141 const uint8_t *const palette = avctx->extradata + AV_RB16(avctx->extradata);
142 int palette_size = avctx->extradata_size - AV_RB16(avctx->extradata);
144 if (avctx->bits_per_coded_sample > 8) {
145 av_log(avctx, AV_LOG_ERROR, "bit_per_coded_sample > 8 not supported\n");
146 return AVERROR_INVALIDDATA;
149 count = 1 << avctx->bits_per_coded_sample;
150 // If extradata is smaller than actually needed, fill the remaining with black.
151 count = FFMIN(palette_size / 3, count);
153 for (i=0; i < count; i++) {
154 pal[i] = 0xFF000000 | AV_RB24(palette + i*3);
156 } else { // Create gray-scale color palette for bps < 8
157 count = 1 << avctx->bits_per_coded_sample;
159 for (i=0; i < count; i++) {
160 pal[i] = 0xFF000000 | gray2rgb((i * 255) >> avctx->bits_per_coded_sample);
167 * Extracts the IFF extra context and updates internal
168 * decoder structures.
170 * @param avctx the AVCodecContext where to extract extra context to
171 * @param avpkt the AVPacket to extract extra context from or NULL to use avctx
172 * @return 0 in case of success, a negative error code otherwise
174 static int extract_header(AVCodecContext *const avctx,
175 const AVPacket *const avpkt) {
178 IffContext *s = avctx->priv_data;
179 int palette_size = avctx->extradata_size - AV_RB16(avctx->extradata);
184 return AVERROR_INVALIDDATA;
185 image_size = avpkt->size - AV_RB16(avpkt->data);
187 buf_size = bytestream_get_be16(&buf);
188 if (buf_size <= 1 || image_size <= 1) {
189 av_log(avctx, AV_LOG_ERROR,
190 "Invalid image size received: %u -> image data offset: %d\n",
191 buf_size, image_size);
192 return AVERROR_INVALIDDATA;
195 if (avctx->extradata_size < 2)
196 return AVERROR_INVALIDDATA;
197 buf = avctx->extradata;
198 buf_size = bytestream_get_be16(&buf);
199 if (buf_size <= 1 || palette_size < 0) {
200 av_log(avctx, AV_LOG_ERROR,
201 "Invalid palette size received: %u -> palette data offset: %d\n",
202 buf_size, palette_size);
203 return AVERROR_INVALIDDATA;
208 s->compression = bytestream_get_byte(&buf);
209 s->bpp = bytestream_get_byte(&buf);
210 s->ham = bytestream_get_byte(&buf);
211 s->flags = bytestream_get_byte(&buf);
212 s->transparency = bytestream_get_be16(&buf);
213 s->masking = bytestream_get_byte(&buf);
214 if (s->masking == MASK_HAS_TRANSPARENT_COLOR) {
215 av_log(avctx, AV_LOG_ERROR, "Transparency not supported\n");
216 return AVERROR_PATCHWELCOME;
217 } else if (s->masking != MASK_NONE) {
218 av_log(avctx, AV_LOG_ERROR, "Masking not supported\n");
219 return AVERROR_PATCHWELCOME;
221 if (!s->bpp || s->bpp > 32) {
222 av_log(avctx, AV_LOG_ERROR, "Invalid number of bitplanes: %u\n", s->bpp);
223 return AVERROR_INVALIDDATA;
224 } else if (s->ham >= 8) {
225 av_log(avctx, AV_LOG_ERROR, "Invalid number of hold bits for HAM: %u\n", s->ham);
226 return AVERROR_INVALIDDATA;
229 av_freep(&s->ham_buf);
230 av_freep(&s->ham_palbuf);
233 int i, count = FFMIN(palette_size / 3, 1 << s->ham);
234 const uint8_t *const palette = avctx->extradata + AV_RB16(avctx->extradata);
235 s->ham_buf = av_malloc((s->planesize * 8) + FF_INPUT_BUFFER_PADDING_SIZE);
237 return AVERROR(ENOMEM);
239 s->ham_palbuf = av_malloc((8 * (1 << s->ham) * sizeof (uint32_t)) + FF_INPUT_BUFFER_PADDING_SIZE);
240 if (!s->ham_palbuf) {
241 av_freep(&s->ham_buf);
242 return AVERROR(ENOMEM);
245 if (count) { // HAM with color palette attached
246 // prefill with black and palette and set HAM take direct value mask to zero
247 memset(s->ham_palbuf, 0, (1 << s->ham) * 2 * sizeof (uint32_t));
248 for (i=0; i < count; i++) {
249 s->ham_palbuf[i*2+1] = AV_RL24(palette + i*3);
252 } else { // HAM with grayscale color palette
254 for (i=0; i < count; i++) {
255 s->ham_palbuf[i*2] = 0; // take direct color value from palette
256 s->ham_palbuf[i*2+1] = av_le2ne32(gray2rgb((i * 255) >> s->ham));
259 for (i=0; i < count; i++) {
260 uint32_t tmp = i << (8 - s->ham);
261 tmp |= tmp >> s->ham;
262 s->ham_palbuf[(i+count)*2] = 0x00FFFF; // just modify blue color component
263 s->ham_palbuf[(i+count*2)*2] = 0xFFFF00; // just modify red color component
264 s->ham_palbuf[(i+count*3)*2] = 0xFF00FF; // just modify green color component
265 s->ham_palbuf[(i+count)*2+1] = tmp << 16;
266 s->ham_palbuf[(i+count*2)*2+1] = tmp;
267 s->ham_palbuf[(i+count*3)*2+1] = tmp << 8;
269 } else if (s->flags & 1) { // EHB (ExtraHalfBrite) color palette
270 av_log(avctx, AV_LOG_ERROR, "ExtraHalfBrite (EHB) mode not supported\n");
271 return AVERROR_PATCHWELCOME;
278 static av_cold int decode_init(AVCodecContext *avctx)
280 IffContext *s = avctx->priv_data;
283 if (avctx->bits_per_coded_sample <= 8) {
284 int palette_size = avctx->extradata_size - AV_RB16(avctx->extradata);
285 avctx->pix_fmt = (avctx->bits_per_coded_sample < 8) ||
286 (avctx->extradata_size >= 2 && palette_size) ? PIX_FMT_PAL8 : PIX_FMT_GRAY8;
287 } else if (avctx->bits_per_coded_sample <= 32) {
288 avctx->pix_fmt = PIX_FMT_BGR32;
290 return AVERROR_INVALIDDATA;
293 if ((err = av_image_check_size(avctx->width, avctx->height, 0, avctx)))
295 s->planesize = FFALIGN(avctx->width, 16) >> 3; // Align plane size in bits to word-boundary
296 s->planebuf = av_malloc(s->planesize + FF_INPUT_BUFFER_PADDING_SIZE);
298 return AVERROR(ENOMEM);
300 s->bpp = avctx->bits_per_coded_sample;
301 avcodec_get_frame_defaults(&s->frame);
303 if ((err = extract_header(avctx, NULL)) < 0)
305 s->frame.reference = 1;
311 * Decode interleaved plane buffer up to 8bpp
312 * @param dst Destination buffer
313 * @param buf Source buffer
315 * @param plane plane number to decode as
317 static void decodeplane8(uint8_t *dst, const uint8_t *buf, int buf_size, int plane)
319 const uint64_t *lut = plane8_lut[plane];
321 uint64_t v = AV_RN64A(dst) | lut[*buf++];
324 } while (--buf_size);
328 * Decode interleaved plane buffer up to 24bpp
329 * @param dst Destination buffer
330 * @param buf Source buffer
332 * @param plane plane number to decode as
334 static void decodeplane32(uint32_t *dst, const uint8_t *buf, int buf_size, int plane)
336 const uint32_t *lut = plane32_lut[plane];
338 unsigned mask = (*buf >> 2) & ~3;
339 dst[0] |= lut[mask++];
340 dst[1] |= lut[mask++];
341 dst[2] |= lut[mask++];
343 mask = (*buf++ << 2) & 0x3F;
344 dst[4] |= lut[mask++];
345 dst[5] |= lut[mask++];
346 dst[6] |= lut[mask++];
349 } while (--buf_size);
352 #define DECODE_HAM_PLANE32(x) \
353 first = buf[x] << 1; \
354 second = buf[(x)+1] << 1; \
355 delta &= pal[first++]; \
356 delta |= pal[first]; \
358 delta &= pal[second++]; \
359 delta |= pal[second]; \
363 * Converts one line of HAM6/8-encoded chunky buffer to 24bpp.
365 * @param dst the destination 24bpp buffer
366 * @param buf the source 8bpp chunky buffer
367 * @param pal the HAM decode table
368 * @param buf_size the plane size in bytes
370 static void decode_ham_plane32(uint32_t *dst, const uint8_t *buf,
371 const uint32_t *const pal, unsigned buf_size)
375 uint32_t first, second;
376 DECODE_HAM_PLANE32(0);
377 DECODE_HAM_PLANE32(2);
378 DECODE_HAM_PLANE32(4);
379 DECODE_HAM_PLANE32(6);
382 } while (--buf_size);
386 * Decode one complete byterun1 encoded line.
388 * @param dst the destination buffer where to store decompressed bitstream
389 * @param dst_size the destination plane size in bytes
390 * @param buf the source byterun1 compressed bitstream
391 * @param buf_end the EOF of source byterun1 compressed bitstream
392 * @return number of consumed bytes in byterun1 compressed bitstream
394 static int decode_byterun(uint8_t *dst, int dst_size,
395 const uint8_t *buf, const uint8_t *const buf_end) {
396 const uint8_t *const buf_start = buf;
398 for (x = 0; x < dst_size && buf < buf_end;) {
400 const int8_t value = *buf++;
403 memcpy(dst + x, buf, FFMIN3(length, dst_size - x, buf_end - buf));
405 } else if (value > -128) {
407 memset(dst + x, *buf++, FFMIN(length, dst_size - x));
413 return buf - buf_start;
416 static int decode_frame_ilbm(AVCodecContext *avctx,
417 void *data, int *data_size,
420 IffContext *s = avctx->priv_data;
421 const uint8_t *buf = avpkt->size >= 2 ? avpkt->data + AV_RB16(avpkt->data) : NULL;
422 const int buf_size = avpkt->size >= 2 ? avpkt->size - AV_RB16(avpkt->data) : 0;
423 const uint8_t *buf_end = buf+buf_size;
426 if ((res = extract_header(avctx, avpkt)) < 0)
430 if ((res = avctx->reget_buffer(avctx, &s->frame)) < 0) {
431 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
434 } else if ((res = avctx->get_buffer(avctx, &s->frame)) < 0) {
435 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
437 } else if (avctx->bits_per_coded_sample <= 8 && avctx->pix_fmt != PIX_FMT_GRAY8) {
438 if ((res = ff_cmap_read_palette(avctx, (uint32_t*)s->frame.data[1])) < 0)
443 if (avctx->codec_tag == MKTAG('I','L','B','M')) { // interleaved
444 if (avctx->pix_fmt == PIX_FMT_PAL8 || avctx->pix_fmt == PIX_FMT_GRAY8) {
445 for(y = 0; y < avctx->height; y++ ) {
446 uint8_t *row = &s->frame.data[0][ y*s->frame.linesize[0] ];
447 memset(row, 0, avctx->width);
448 for (plane = 0; plane < s->bpp && buf < buf_end; plane++) {
449 decodeplane8(row, buf, FFMIN(s->planesize, buf_end - buf), plane);
453 } else if (s->ham) { // HAM to PIX_FMT_BGR32
454 for (y = 0; y < avctx->height; y++) {
455 uint8_t *row = &s->frame.data[0][ y*s->frame.linesize[0] ];
456 memset(s->ham_buf, 0, avctx->width);
457 for (plane = 0; plane < s->bpp && buf < buf_end; plane++) {
458 decodeplane8(s->ham_buf, buf, FFMIN(s->planesize, buf_end - buf), plane);
461 decode_ham_plane32((uint32_t *) row, s->ham_buf, s->ham_palbuf, s->planesize);
463 } else { // PIX_FMT_BGR32
464 for(y = 0; y < avctx->height; y++ ) {
465 uint8_t *row = &s->frame.data[0][y*s->frame.linesize[0]];
466 memset(row, 0, avctx->width << 2);
467 for (plane = 0; plane < s->bpp && buf < buf_end; plane++) {
468 decodeplane32((uint32_t *) row, buf, FFMIN(s->planesize, buf_end - buf), plane);
473 } else if (avctx->pix_fmt == PIX_FMT_PAL8 || avctx->pix_fmt == PIX_FMT_GRAY8) { // IFF-PBM
474 for(y = 0; y < avctx->height; y++ ) {
475 uint8_t *row = &s->frame.data[0][y * s->frame.linesize[0]];
476 memcpy(row, buf, FFMIN(avctx->width, buf_end - buf));
477 buf += avctx->width + (avctx->width % 2); // padding if odd
479 } else { // IFF-PBM: HAM to PIX_FMT_BGR32
480 for (y = 0; y < avctx->height; y++) {
481 uint8_t *row = &s->frame.data[0][ y*s->frame.linesize[0] ];
482 memcpy(s->ham_buf, buf, FFMIN(avctx->width, buf_end - buf));
483 buf += avctx->width + (avctx->width & 1); // padding if odd
484 decode_ham_plane32((uint32_t *) row, s->ham_buf, s->ham_palbuf, avctx->width);
488 *data_size = sizeof(AVFrame);
489 *(AVFrame*)data = s->frame;
493 static int decode_frame_byterun1(AVCodecContext *avctx,
494 void *data, int *data_size,
497 IffContext *s = avctx->priv_data;
498 const uint8_t *buf = avpkt->size >= 2 ? avpkt->data + AV_RB16(avpkt->data) : NULL;
499 const int buf_size = avpkt->size >= 2 ? avpkt->size - AV_RB16(avpkt->data) : 0;
500 const uint8_t *buf_end = buf+buf_size;
503 if ((res = extract_header(avctx, avpkt)) < 0)
506 if ((res = avctx->reget_buffer(avctx, &s->frame)) < 0) {
507 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
510 } else if ((res = avctx->get_buffer(avctx, &s->frame)) < 0) {
511 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
513 } else if (avctx->bits_per_coded_sample <= 8 && avctx->pix_fmt != PIX_FMT_GRAY8) {
514 if ((res = ff_cmap_read_palette(avctx, (uint32_t*)s->frame.data[1])) < 0)
519 if (avctx->codec_tag == MKTAG('I','L','B','M')) { //interleaved
520 if (avctx->pix_fmt == PIX_FMT_PAL8 || avctx->pix_fmt == PIX_FMT_GRAY8) {
521 for(y = 0; y < avctx->height ; y++ ) {
522 uint8_t *row = &s->frame.data[0][ y*s->frame.linesize[0] ];
523 memset(row, 0, avctx->width);
524 for (plane = 0; plane < s->bpp; plane++) {
525 buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end);
526 decodeplane8(row, s->planebuf, s->planesize, plane);
529 } else if (s->ham) { // HAM to PIX_FMT_BGR32
530 for (y = 0; y < avctx->height ; y++) {
531 uint8_t *row = &s->frame.data[0][y*s->frame.linesize[0]];
532 memset(s->ham_buf, 0, avctx->width);
533 for (plane = 0; plane < s->bpp; plane++) {
534 buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end);
535 decodeplane8(s->ham_buf, s->planebuf, s->planesize, plane);
537 decode_ham_plane32((uint32_t *) row, s->ham_buf, s->ham_palbuf, s->planesize);
539 } else { //PIX_FMT_BGR32
540 for(y = 0; y < avctx->height ; y++ ) {
541 uint8_t *row = &s->frame.data[0][y*s->frame.linesize[0]];
542 memset(row, 0, avctx->width << 2);
543 for (plane = 0; plane < s->bpp; plane++) {
544 buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end);
545 decodeplane32((uint32_t *) row, s->planebuf, s->planesize, plane);
549 } else if (avctx->pix_fmt == PIX_FMT_PAL8 || avctx->pix_fmt == PIX_FMT_GRAY8) { // IFF-PBM
550 for(y = 0; y < avctx->height ; y++ ) {
551 uint8_t *row = &s->frame.data[0][y*s->frame.linesize[0]];
552 buf += decode_byterun(row, avctx->width, buf, buf_end);
554 } else { // IFF-PBM: HAM to PIX_FMT_BGR32
555 for (y = 0; y < avctx->height ; y++) {
556 uint8_t *row = &s->frame.data[0][y*s->frame.linesize[0]];
557 buf += decode_byterun(s->ham_buf, avctx->width, buf, buf_end);
558 decode_ham_plane32((uint32_t *) row, s->ham_buf, s->ham_palbuf, avctx->width);
562 *data_size = sizeof(AVFrame);
563 *(AVFrame*)data = s->frame;
567 static av_cold int decode_end(AVCodecContext *avctx)
569 IffContext *s = avctx->priv_data;
570 if (s->frame.data[0])
571 avctx->release_buffer(avctx, &s->frame);
572 av_freep(&s->planebuf);
573 av_freep(&s->ham_buf);
574 av_freep(&s->ham_palbuf);
578 AVCodec ff_iff_ilbm_decoder = {
580 .type = AVMEDIA_TYPE_VIDEO,
581 .id = CODEC_ID_IFF_ILBM,
582 .priv_data_size = sizeof(IffContext),
585 .decode = decode_frame_ilbm,
586 .capabilities = CODEC_CAP_DR1,
587 .long_name = NULL_IF_CONFIG_SMALL("IFF ILBM"),
590 AVCodec ff_iff_byterun1_decoder = {
591 .name = "iff_byterun1",
592 .type = AVMEDIA_TYPE_VIDEO,
593 .id = CODEC_ID_IFF_BYTERUN1,
594 .priv_data_size = sizeof(IffContext),
597 .decode = decode_frame_byterun1,
598 .capabilities = CODEC_CAP_DR1,
599 .long_name = NULL_IF_CONFIG_SMALL("IFF ByteRun1"),