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 "config_components.h"
35 #include "libavutil/intreadwrite.h"
36 #include "libavutil/opt.h"
37 #include "libavutil/parseutils.h"
42 #include "libavcodec/bintext.h"
46 int chars_per_frame
; /**< characters to send decoder per frame;
47 set by private options as characters per second, and then
48 converted to characters per frame at runtime */
49 int width
, height
; /**< video size (WxH pixels) (private option) */
50 AVRational framerate
; /**< frames per second (private option) */
51 uint64_t fsize
; /**< file size less metadata buffer */
54 static AVStream
* init_stream(AVFormatContext
*s
)
56 BinDemuxContext
*bin
= s
->priv_data
;
57 AVStream
*st
= avformat_new_stream(s
, NULL
);
60 st
->codecpar
->codec_tag
= 0;
61 st
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
64 st
->codecpar
->width
= (80<<3);
65 st
->codecpar
->height
= (25<<4);
68 avpriv_set_pts_info(st
, 60, bin
->framerate
.den
, bin
->framerate
.num
);
70 /* simulate tty display speed */
71 bin
->chars_per_frame
= av_clip(av_q2d(st
->time_base
) * bin
->chars_per_frame
, 1, INT_MAX
);
76 #if CONFIG_BINTEXT_DEMUXER | CONFIG_ADF_DEMUXER | CONFIG_IDF_DEMUXER
78 * Given filesize and width, calculate height (assume font_height of 16)
80 static void calculate_height(AVCodecParameters
*par
, uint64_t fsize
)
82 par
->height
= (fsize
/ ((par
->width
>>3)*2)) << 4;
86 #if CONFIG_BINTEXT_DEMUXER
87 static const uint8_t next_magic
[]={
88 0x1A, 0x1B, '[', '0', ';', '3', '0', ';', '4', '0', 'm', 'N', 'E', 'X', 'T', 0x00
91 static int next_tag_read(AVFormatContext
*avctx
, uint64_t *fsize
)
93 AVIOContext
*pb
= avctx
->pb
;
96 int64_t start_pos
= avio_size(pb
);
99 return AVERROR_INVALIDDATA
;
101 avio_seek(pb
, start_pos
- 256, SEEK_SET
);
102 if (avio_read(pb
, buf
, sizeof(next_magic
)) != sizeof(next_magic
))
104 if (memcmp(buf
, next_magic
, sizeof(next_magic
)))
106 if (avio_r8(pb
) != 0x01)
111 #define GET_EFI2_META(name,size) \
113 if (len < 1 || len > size) \
115 if (avio_read(pb, buf, size) == size && *buf) { \
117 av_dict_set(&avctx->metadata, name, buf, 0); \
120 GET_EFI2_META("filename", 12)
121 GET_EFI2_META("author", 20)
122 GET_EFI2_META("publisher", 20)
123 GET_EFI2_META("title", 35)
128 static void predict_width(AVCodecParameters
*par
, uint64_t fsize
, int got_width
)
130 /** attempt to guess width */
132 par
->width
= fsize
> 4000 ? (160<<3) : (80<<3);
135 static int bin_probe(const AVProbeData
*p
)
137 const uint8_t *d
= p
->buf
;
138 int magic
= 0, sauce
= 0;
140 if (p
->buf_size
> 256)
141 magic
= !memcmp(d
+ p
->buf_size
- 256, next_magic
, sizeof(next_magic
));
142 if (p
->buf_size
> 128)
143 sauce
= !memcmp(d
+ p
->buf_size
- 128, "SAUCE00", 7);
146 return AVPROBE_SCORE_EXTENSION
+ 1;
148 if (av_match_ext(p
->filename
, "bin")) {
149 AVCodecParameters par
;
151 par
.width
= par
.height
= 0;
153 return AVPROBE_SCORE_EXTENSION
+ 1;
155 predict_width(&par
, p
->buf_size
, got_width
);
158 calculate_height(&par
, p
->buf_size
);
162 if (par
.width
* par
.height
* 2 / (8*16) == p
->buf_size
)
163 return AVPROBE_SCORE_MAX
/ 2;
174 static int bintext_read_header(AVFormatContext
*s
)
176 BinDemuxContext
*bin
= s
->priv_data
;
177 AVIOContext
*pb
= s
->pb
;
179 AVStream
*st
= init_stream(s
);
181 return AVERROR(ENOMEM
);
182 st
->codecpar
->codec_id
= AV_CODEC_ID_BINTEXT
;
184 if ((ret
= ff_alloc_extradata(st
->codecpar
, 2)) < 0)
186 st
->codecpar
->extradata
[0] = 16;
187 st
->codecpar
->extradata
[1] = 0;
189 if (pb
->seekable
& AVIO_SEEKABLE_NORMAL
) {
191 bin
->fsize
= avio_size(pb
);
192 if (ff_sauce_read(s
, &bin
->fsize
, &got_width
, 0) < 0)
193 next_tag_read(s
, &bin
->fsize
);
195 predict_width(st
->codecpar
, bin
->fsize
, got_width
);
196 if (st
->codecpar
->width
< 8)
197 return AVERROR_INVALIDDATA
;
198 calculate_height(st
->codecpar
, bin
->fsize
);
200 avio_seek(pb
, 0, SEEK_SET
);
204 #endif /* CONFIG_BINTEXT_DEMUXER */
206 #if CONFIG_XBIN_DEMUXER
207 static int xbin_probe(const AVProbeData
*p
)
209 const uint8_t *d
= p
->buf
;
211 if (AV_RL32(d
) == MKTAG('X','B','I','N') && d
[4] == 0x1A &&
212 AV_RL16(d
+5) > 0 && AV_RL16(d
+5) <= 160 &&
213 d
[9] > 0 && d
[9] <= 32)
214 return AVPROBE_SCORE_MAX
;
218 static int xbin_read_header(AVFormatContext
*s
)
220 BinDemuxContext
*bin
= s
->priv_data
;
221 AVIOContext
*pb
= s
->pb
;
222 char fontheight
, flags
;
224 AVStream
*st
= init_stream(s
);
226 return AVERROR(ENOMEM
);
229 st
->codecpar
->width
= avio_rl16(pb
)<<3;
230 st
->codecpar
->height
= avio_rl16(pb
);
231 fontheight
= avio_r8(pb
);
232 st
->codecpar
->height
*= fontheight
;
235 st
->codecpar
->extradata_size
= 2;
236 if ((flags
& BINTEXT_PALETTE
))
237 st
->codecpar
->extradata_size
+= 48;
238 if ((flags
& BINTEXT_FONT
))
239 st
->codecpar
->extradata_size
+= fontheight
* (flags
& 0x10 ? 512 : 256);
240 st
->codecpar
->codec_id
= flags
& 4 ? AV_CODEC_ID_XBIN
: AV_CODEC_ID_BINTEXT
;
242 ret
= ff_alloc_extradata(st
->codecpar
, st
->codecpar
->extradata_size
);
245 st
->codecpar
->extradata
[0] = fontheight
;
246 st
->codecpar
->extradata
[1] = flags
;
247 if (avio_read(pb
, st
->codecpar
->extradata
+ 2, st
->codecpar
->extradata_size
- 2) < 0)
250 if (pb
->seekable
& AVIO_SEEKABLE_NORMAL
) {
251 int64_t fsize
= avio_size(pb
);
252 if (fsize
< 9 + st
->codecpar
->extradata_size
)
254 bin
->fsize
= fsize
- 9 - st
->codecpar
->extradata_size
;
255 ff_sauce_read(s
, &bin
->fsize
, NULL
, 0);
256 avio_seek(pb
, 9 + st
->codecpar
->extradata_size
, SEEK_SET
);
261 #endif /* CONFIG_XBIN_DEMUXER */
263 #if CONFIG_ADF_DEMUXER
264 static int adf_read_header(AVFormatContext
*s
)
266 BinDemuxContext
*bin
= s
->priv_data
;
267 AVIOContext
*pb
= s
->pb
;
271 if (avio_r8(pb
) != 1)
272 return AVERROR_INVALIDDATA
;
276 return AVERROR(ENOMEM
);
277 st
->codecpar
->codec_id
= AV_CODEC_ID_BINTEXT
;
279 if ((ret
= ff_alloc_extradata(st
->codecpar
, 2 + 48 + 4096)) < 0)
281 st
->codecpar
->extradata
[0] = 16;
282 st
->codecpar
->extradata
[1] = BINTEXT_PALETTE
|BINTEXT_FONT
;
284 if (avio_read(pb
, st
->codecpar
->extradata
+ 2, 24) < 0)
287 if (avio_read(pb
, st
->codecpar
->extradata
+ 2 + 24, 24) < 0)
289 if (avio_read(pb
, st
->codecpar
->extradata
+ 2 + 48, 4096) < 0)
292 if (pb
->seekable
& AVIO_SEEKABLE_NORMAL
) {
294 int64_t fsize
= avio_size(pb
);
295 if (fsize
< 1 + 192 + 4096)
297 bin
->fsize
= fsize
- 1 - 192 - 4096;
298 st
->codecpar
->width
= 80<<3;
299 ff_sauce_read(s
, &bin
->fsize
, &got_width
, 0);
300 if (st
->codecpar
->width
< 8)
301 return AVERROR_INVALIDDATA
;
303 calculate_height(st
->codecpar
, bin
->fsize
);
304 avio_seek(pb
, 1 + 192 + 4096, SEEK_SET
);
308 #endif /* CONFIG_ADF_DEMUXER */
310 #if CONFIG_IDF_DEMUXER
311 static const uint8_t idf_magic
[] = {
312 0x04, 0x31, 0x2e, 0x34, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x15, 0x00
315 static int idf_probe(const AVProbeData
*p
)
317 if (p
->buf_size
< sizeof(idf_magic
))
319 if (!memcmp(p
->buf
, idf_magic
, sizeof(idf_magic
)))
320 return AVPROBE_SCORE_MAX
;
324 static int idf_read_header(AVFormatContext
*s
)
326 BinDemuxContext
*bin
= s
->priv_data
;
327 AVIOContext
*pb
= s
->pb
;
329 int got_width
= 0, ret
;
332 if (!(pb
->seekable
& AVIO_SEEKABLE_NORMAL
))
337 return AVERROR(ENOMEM
);
338 st
->codecpar
->codec_id
= AV_CODEC_ID_IDF
;
340 if ((ret
= ff_alloc_extradata(st
->codecpar
, 2 + 48 + 4096)) < 0)
342 st
->codecpar
->extradata
[0] = 16;
343 st
->codecpar
->extradata
[1] = BINTEXT_PALETTE
|BINTEXT_FONT
;
345 fsize
= avio_size(pb
);
346 if (fsize
< 12 + 4096 + 48)
347 return AVERROR_INVALIDDATA
;
348 bin
->fsize
= fsize
- 12 - 4096 - 48;
350 avio_seek(pb
, bin
->fsize
+ 12, SEEK_SET
);
352 if (avio_read(pb
, st
->codecpar
->extradata
+ 2 + 48, 4096) < 0)
354 if (avio_read(pb
, st
->codecpar
->extradata
+ 2, 48) < 0)
357 ff_sauce_read(s
, &bin
->fsize
, &got_width
, 0);
358 if (st
->codecpar
->width
< 8)
359 return AVERROR_INVALIDDATA
;
361 calculate_height(st
->codecpar
, bin
->fsize
);
362 avio_seek(pb
, 12, SEEK_SET
);
365 #endif /* CONFIG_IDF_DEMUXER */
367 static int read_packet(AVFormatContext
*s
,
370 BinDemuxContext
*bin
= s
->priv_data
;
372 if (bin
->fsize
> 0) {
373 if (av_get_packet(s
->pb
, pkt
, bin
->fsize
) < 0)
375 bin
->fsize
= -1; /* done */
376 } else if (!bin
->fsize
) {
377 if (avio_feof(s
->pb
))
379 if (av_get_packet(s
->pb
, pkt
, bin
->chars_per_frame
) < 0)
385 pkt
->flags
|= AV_PKT_FLAG_KEY
;
389 #define OFFSET(x) offsetof(BinDemuxContext, x)
390 static const AVOption options
[] = {
391 { "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
},
392 { "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
},
393 { "framerate", "set framerate (frames per second)", OFFSET(framerate
), AV_OPT_TYPE_VIDEO_RATE
, {.str
= "25"}, 0, INT_MAX
, AV_OPT_FLAG_DECODING_PARAM
},
397 #define CLASS(name) \
398 (const AVClass[1]){{ \
399 .class_name = name, \
400 .item_name = av_default_item_name, \
402 .version = LIBAVUTIL_VERSION_INT, \
405 #if CONFIG_BINTEXT_DEMUXER
406 const FFInputFormat ff_bintext_demuxer
= {
408 .p
.long_name
= NULL_IF_CONFIG_SMALL("Binary text"),
409 .p
.priv_class
= CLASS("Binary text demuxer"),
410 .priv_data_size
= sizeof(BinDemuxContext
),
411 .read_probe
= bin_probe
,
412 .read_header
= bintext_read_header
,
413 .read_packet
= read_packet
,
417 #if CONFIG_XBIN_DEMUXER
418 const FFInputFormat ff_xbin_demuxer
= {
420 .p
.long_name
= NULL_IF_CONFIG_SMALL("eXtended BINary text (XBIN)"),
421 .p
.priv_class
= CLASS("eXtended BINary text (XBIN) demuxer"),
422 .priv_data_size
= sizeof(BinDemuxContext
),
423 .read_probe
= xbin_probe
,
424 .read_header
= xbin_read_header
,
425 .read_packet
= read_packet
,
429 #if CONFIG_ADF_DEMUXER
430 const FFInputFormat ff_adf_demuxer
= {
432 .p
.long_name
= NULL_IF_CONFIG_SMALL("Artworx Data Format"),
433 .p
.extensions
= "adf",
434 .p
.priv_class
= CLASS("Artworx Data Format demuxer"),
435 .priv_data_size
= sizeof(BinDemuxContext
),
436 .read_header
= adf_read_header
,
437 .read_packet
= read_packet
,
441 #if CONFIG_IDF_DEMUXER
442 const FFInputFormat ff_idf_demuxer
= {
444 .p
.long_name
= NULL_IF_CONFIG_SMALL("iCE Draw File"),
445 .p
.extensions
= "idf",
446 .p
.priv_class
= CLASS("iCE Draw File demuxer"),
447 .priv_data_size
= sizeof(BinDemuxContext
),
448 .read_probe
= idf_probe
,
449 .read_header
= idf_read_header
,
450 .read_packet
= read_packet
,