3 * eXtended BINary text (XBIN) demuxer
4 * Artworx Data Format demuxer
6 * Copyright (c) 2010 Peter Ross <pross@xvid.org>
8 * This file is part of FFmpeg.
10 * FFmpeg is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * FFmpeg is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with FFmpeg; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 * eXtended BINary text (XBIN) demuxer
29 * Artworx Data Format demuxer
30 * iCEDraw File demuxer
33 #include "libavutil/intreadwrite.h"
34 #include "libavutil/opt.h"
35 #include "libavutil/parseutils.h"
39 #include "libavcodec/bintext.h"
43 int chars_per_frame
; /**< characters to send decoder per frame;
44 set by private options as characters per second, and then
45 converted to characters per frame at runtime */
46 int width
, height
; /**< video size (WxH pixels) (private option) */
47 AVRational framerate
; /**< frames per second (private option) */
48 uint64_t fsize
; /**< file size less metadata buffer */
51 static AVStream
* init_stream(AVFormatContext
*s
)
53 BinDemuxContext
*bin
= s
->priv_data
;
54 AVStream
*st
= avformat_new_stream(s
, NULL
);
57 st
->codecpar
->codec_tag
= 0;
58 st
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
61 st
->codecpar
->width
= (80<<3);
62 st
->codecpar
->height
= (25<<4);
65 avpriv_set_pts_info(st
, 60, bin
->framerate
.den
, bin
->framerate
.num
);
67 /* simulate tty display speed */
68 bin
->chars_per_frame
= av_clip(av_q2d(st
->time_base
) * bin
->chars_per_frame
, 1, INT_MAX
);
73 #if CONFIG_BINTEXT_DEMUXER | CONFIG_ADF_DEMUXER | CONFIG_IDF_DEMUXER
75 * Given filesize and width, calculate height (assume font_height of 16)
77 static void calculate_height(AVCodecParameters
*par
, uint64_t fsize
)
79 par
->height
= (fsize
/ ((par
->width
>>3)*2)) << 4;
83 #if CONFIG_BINTEXT_DEMUXER
84 static const uint8_t next_magic
[]={
85 0x1A, 0x1B, '[', '0', ';', '3', '0', ';', '4', '0', 'm', 'N', 'E', 'X', 'T', 0x00
88 static int next_tag_read(AVFormatContext
*avctx
, uint64_t *fsize
)
90 AVIOContext
*pb
= avctx
->pb
;
93 int64_t start_pos
= avio_size(pb
);
96 return AVERROR_INVALIDDATA
;
98 avio_seek(pb
, start_pos
- 256, SEEK_SET
);
99 if (avio_read(pb
, buf
, sizeof(next_magic
)) != sizeof(next_magic
))
101 if (memcmp(buf
, next_magic
, sizeof(next_magic
)))
103 if (avio_r8(pb
) != 0x01)
108 #define GET_EFI2_META(name,size) \
110 if (len < 1 || len > size) \
112 if (avio_read(pb, buf, size) == size && *buf) { \
114 av_dict_set(&avctx->metadata, name, buf, 0); \
117 GET_EFI2_META("filename", 12)
118 GET_EFI2_META("author", 20)
119 GET_EFI2_META("publisher", 20)
120 GET_EFI2_META("title", 35)
125 static void predict_width(AVCodecParameters
*par
, uint64_t fsize
, int got_width
)
127 /** attempt to guess width */
129 par
->width
= fsize
> 4000 ? (160<<3) : (80<<3);
132 static int bin_probe(const AVProbeData
*p
)
134 const uint8_t *d
= p
->buf
;
135 int magic
= 0, sauce
= 0;
139 if (p
->buf_size
> 256)
140 magic
= !memcmp(d
+ p
->buf_size
- 256, next_magic
, sizeof(next_magic
));
141 if (p
->buf_size
> 128)
142 sauce
= !memcmp(d
+ p
->buf_size
- 128, "SAUCE00", 7);
145 return AVPROBE_SCORE_EXTENSION
+ 1;
147 if (av_match_ext(p
->filename
, "bin")) {
148 AVCodecParameters par
;
150 par
.width
= par
.height
= 0;
152 return AVPROBE_SCORE_EXTENSION
+ 1;
154 predict_width(&par
, p
->buf_size
, got_width
);
157 calculate_height(&par
, p
->buf_size
);
161 for (i
= 0; i
< p
->buf_size
- 256; i
+=2) {
162 if ((d
[i
+1] & 15) == (d
[i
+1] >> 4) && d
[i
] && d
[i
] != 0xFF && d
[i
] != ' ') {
167 if (par
.width
* par
.height
* 2 / (8*16) == p
->buf_size
)
168 return AVPROBE_SCORE_MAX
/ 2;
179 static int bintext_read_header(AVFormatContext
*s
)
181 BinDemuxContext
*bin
= s
->priv_data
;
182 AVIOContext
*pb
= s
->pb
;
184 AVStream
*st
= init_stream(s
);
186 return AVERROR(ENOMEM
);
187 st
->codecpar
->codec_id
= AV_CODEC_ID_BINTEXT
;
189 if ((ret
= ff_alloc_extradata(st
->codecpar
, 2)) < 0)
191 st
->codecpar
->extradata
[0] = 16;
192 st
->codecpar
->extradata
[1] = 0;
194 if (pb
->seekable
& AVIO_SEEKABLE_NORMAL
) {
196 bin
->fsize
= avio_size(pb
);
197 if (ff_sauce_read(s
, &bin
->fsize
, &got_width
, 0) < 0)
198 next_tag_read(s
, &bin
->fsize
);
200 predict_width(st
->codecpar
, bin
->fsize
, got_width
);
201 if (st
->codecpar
->width
< 8)
202 return AVERROR_INVALIDDATA
;
203 calculate_height(st
->codecpar
, bin
->fsize
);
205 avio_seek(pb
, 0, SEEK_SET
);
209 #endif /* CONFIG_BINTEXT_DEMUXER */
211 #if CONFIG_XBIN_DEMUXER
212 static int xbin_probe(const AVProbeData
*p
)
214 const uint8_t *d
= p
->buf
;
216 if (AV_RL32(d
) == MKTAG('X','B','I','N') && d
[4] == 0x1A &&
217 AV_RL16(d
+5) > 0 && AV_RL16(d
+5) <= 160 &&
218 d
[9] > 0 && d
[9] <= 32)
219 return AVPROBE_SCORE_MAX
;
223 static int xbin_read_header(AVFormatContext
*s
)
225 BinDemuxContext
*bin
= s
->priv_data
;
226 AVIOContext
*pb
= s
->pb
;
227 char fontheight
, flags
;
229 AVStream
*st
= init_stream(s
);
231 return AVERROR(ENOMEM
);
234 st
->codecpar
->width
= avio_rl16(pb
)<<3;
235 st
->codecpar
->height
= avio_rl16(pb
);
236 fontheight
= avio_r8(pb
);
237 st
->codecpar
->height
*= fontheight
;
240 st
->codecpar
->extradata_size
= 2;
241 if ((flags
& BINTEXT_PALETTE
))
242 st
->codecpar
->extradata_size
+= 48;
243 if ((flags
& BINTEXT_FONT
))
244 st
->codecpar
->extradata_size
+= fontheight
* (flags
& 0x10 ? 512 : 256);
245 st
->codecpar
->codec_id
= flags
& 4 ? AV_CODEC_ID_XBIN
: AV_CODEC_ID_BINTEXT
;
247 ret
= ff_alloc_extradata(st
->codecpar
, st
->codecpar
->extradata_size
);
250 st
->codecpar
->extradata
[0] = fontheight
;
251 st
->codecpar
->extradata
[1] = flags
;
252 if (avio_read(pb
, st
->codecpar
->extradata
+ 2, st
->codecpar
->extradata_size
- 2) < 0)
255 if (pb
->seekable
& AVIO_SEEKABLE_NORMAL
) {
256 int64_t fsize
= avio_size(pb
);
257 if (fsize
< 9 + st
->codecpar
->extradata_size
)
259 bin
->fsize
= fsize
- 9 - st
->codecpar
->extradata_size
;
260 ff_sauce_read(s
, &bin
->fsize
, NULL
, 0);
261 avio_seek(pb
, 9 + st
->codecpar
->extradata_size
, SEEK_SET
);
266 #endif /* CONFIG_XBIN_DEMUXER */
268 #if CONFIG_ADF_DEMUXER
269 static int adf_read_header(AVFormatContext
*s
)
271 BinDemuxContext
*bin
= s
->priv_data
;
272 AVIOContext
*pb
= s
->pb
;
276 if (avio_r8(pb
) != 1)
277 return AVERROR_INVALIDDATA
;
281 return AVERROR(ENOMEM
);
282 st
->codecpar
->codec_id
= AV_CODEC_ID_BINTEXT
;
284 if ((ret
= ff_alloc_extradata(st
->codecpar
, 2 + 48 + 4096)) < 0)
286 st
->codecpar
->extradata
[0] = 16;
287 st
->codecpar
->extradata
[1] = BINTEXT_PALETTE
|BINTEXT_FONT
;
289 if (avio_read(pb
, st
->codecpar
->extradata
+ 2, 24) < 0)
292 if (avio_read(pb
, st
->codecpar
->extradata
+ 2 + 24, 24) < 0)
294 if (avio_read(pb
, st
->codecpar
->extradata
+ 2 + 48, 4096) < 0)
297 if (pb
->seekable
& AVIO_SEEKABLE_NORMAL
) {
299 int64_t fsize
= avio_size(pb
);
300 if (fsize
< 1 + 192 + 4096)
302 bin
->fsize
= fsize
- 1 - 192 - 4096;
303 st
->codecpar
->width
= 80<<3;
304 ff_sauce_read(s
, &bin
->fsize
, &got_width
, 0);
305 if (st
->codecpar
->width
< 8)
306 return AVERROR_INVALIDDATA
;
308 calculate_height(st
->codecpar
, bin
->fsize
);
309 avio_seek(pb
, 1 + 192 + 4096, SEEK_SET
);
313 #endif /* CONFIG_ADF_DEMUXER */
315 #if CONFIG_IDF_DEMUXER
316 static const uint8_t idf_magic
[] = {
317 0x04, 0x31, 0x2e, 0x34, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x15, 0x00
320 static int idf_probe(const AVProbeData
*p
)
322 if (p
->buf_size
< sizeof(idf_magic
))
324 if (!memcmp(p
->buf
, idf_magic
, sizeof(idf_magic
)))
325 return AVPROBE_SCORE_MAX
;
329 static int idf_read_header(AVFormatContext
*s
)
331 BinDemuxContext
*bin
= s
->priv_data
;
332 AVIOContext
*pb
= s
->pb
;
334 int got_width
= 0, ret
;
337 if (!(pb
->seekable
& AVIO_SEEKABLE_NORMAL
))
342 return AVERROR(ENOMEM
);
343 st
->codecpar
->codec_id
= AV_CODEC_ID_IDF
;
345 if ((ret
= ff_alloc_extradata(st
->codecpar
, 2 + 48 + 4096)) < 0)
347 st
->codecpar
->extradata
[0] = 16;
348 st
->codecpar
->extradata
[1] = BINTEXT_PALETTE
|BINTEXT_FONT
;
350 fsize
= avio_size(pb
);
351 if (fsize
< 12 + 4096 + 48)
352 return AVERROR_INVALIDDATA
;
353 bin
->fsize
= fsize
- 12 - 4096 - 48;
355 avio_seek(pb
, bin
->fsize
+ 12, SEEK_SET
);
357 if (avio_read(pb
, st
->codecpar
->extradata
+ 2 + 48, 4096) < 0)
359 if (avio_read(pb
, st
->codecpar
->extradata
+ 2, 48) < 0)
362 ff_sauce_read(s
, &bin
->fsize
, &got_width
, 0);
363 if (st
->codecpar
->width
< 8)
364 return AVERROR_INVALIDDATA
;
366 calculate_height(st
->codecpar
, bin
->fsize
);
367 avio_seek(pb
, 12, SEEK_SET
);
370 #endif /* CONFIG_IDF_DEMUXER */
372 static int read_packet(AVFormatContext
*s
,
375 BinDemuxContext
*bin
= s
->priv_data
;
377 if (bin
->fsize
> 0) {
378 if (av_get_packet(s
->pb
, pkt
, bin
->fsize
) < 0)
380 bin
->fsize
= -1; /* done */
381 } else if (!bin
->fsize
) {
382 if (avio_feof(s
->pb
))
384 if (av_get_packet(s
->pb
, pkt
, bin
->chars_per_frame
) < 0)
390 pkt
->flags
|= AV_PKT_FLAG_KEY
;
394 #define OFFSET(x) offsetof(BinDemuxContext, x)
395 static const AVOption options
[] = {
396 { "linespeed", "set simulated line speed (bytes per second)", OFFSET(chars_per_frame
), AV_OPT_TYPE_INT
, {.i64
= 6000}, 1, INT_MAX
, AV_OPT_FLAG_DECODING_PARAM
},
397 { "video_size", "set video size, such as 640x480 or hd720.", OFFSET(width
), AV_OPT_TYPE_IMAGE_SIZE
, {.str
= NULL
}, 0, 0, AV_OPT_FLAG_DECODING_PARAM
},
398 { "framerate", "set framerate (frames per second)", OFFSET(framerate
), AV_OPT_TYPE_VIDEO_RATE
, {.str
= "25"}, 0, INT_MAX
, AV_OPT_FLAG_DECODING_PARAM
},
402 #define CLASS(name) \
403 (const AVClass[1]){{ \
404 .class_name = name, \
405 .item_name = av_default_item_name, \
407 .version = LIBAVUTIL_VERSION_INT, \
410 #if CONFIG_BINTEXT_DEMUXER
411 AVInputFormat ff_bintext_demuxer
= {
413 .long_name
= NULL_IF_CONFIG_SMALL("Binary text"),
414 .priv_data_size
= sizeof(BinDemuxContext
),
415 .read_probe
= bin_probe
,
416 .read_header
= bintext_read_header
,
417 .read_packet
= read_packet
,
418 .priv_class
= CLASS("Binary text demuxer"),
422 #if CONFIG_XBIN_DEMUXER
423 AVInputFormat ff_xbin_demuxer
= {
425 .long_name
= NULL_IF_CONFIG_SMALL("eXtended BINary text (XBIN)"),
426 .priv_data_size
= sizeof(BinDemuxContext
),
427 .read_probe
= xbin_probe
,
428 .read_header
= xbin_read_header
,
429 .read_packet
= read_packet
,
430 .priv_class
= CLASS("eXtended BINary text (XBIN) demuxer"),
434 #if CONFIG_ADF_DEMUXER
435 AVInputFormat ff_adf_demuxer
= {
437 .long_name
= NULL_IF_CONFIG_SMALL("Artworx Data Format"),
438 .priv_data_size
= sizeof(BinDemuxContext
),
439 .read_header
= adf_read_header
,
440 .read_packet
= read_packet
,
442 .priv_class
= CLASS("Artworx Data Format demuxer"),
446 #if CONFIG_IDF_DEMUXER
447 AVInputFormat ff_idf_demuxer
= {
449 .long_name
= NULL_IF_CONFIG_SMALL("iCE Draw File"),
450 .priv_data_size
= sizeof(BinDemuxContext
),
451 .read_probe
= idf_probe
,
452 .read_header
= idf_read_header
,
453 .read_packet
= read_packet
,
455 .priv_class
= CLASS("iCE Draw File demuxer"),