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
->codec
->codec_tag
= 0;
58 st
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
61 st
->codec
->width
= (80<<3);
62 st
->codec
->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(AVCodecContext
*avctx
, uint64_t fsize
)
79 avctx
->height
= (fsize
/ ((avctx
->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 uint64_t start_pos
= avio_size(pb
) - 256;
95 avio_seek(pb
, start_pos
, SEEK_SET
);
96 if (avio_read(pb
, buf
, sizeof(next_magic
)) != sizeof(next_magic
))
98 if (memcmp(buf
, next_magic
, sizeof(next_magic
)))
100 if (avio_r8(pb
) != 0x01)
105 #define GET_EFI2_META(name,size) \
107 if (len < 1 || len > size) \
109 if (avio_read(pb, buf, size) == size && *buf) { \
111 av_dict_set(&avctx->metadata, name, buf, 0); \
114 GET_EFI2_META("filename", 12)
115 GET_EFI2_META("author", 20)
116 GET_EFI2_META("publisher", 20)
117 GET_EFI2_META("title", 35)
122 static void predict_width(AVCodecContext
*avctx
, uint64_t fsize
, int got_width
)
124 /** attempt to guess width */
126 avctx
->width
= fsize
> 4000 ? (160<<3) : (80<<3);
129 static int bintext_read_header(AVFormatContext
*s
)
131 BinDemuxContext
*bin
= s
->priv_data
;
132 AVIOContext
*pb
= s
->pb
;
134 AVStream
*st
= init_stream(s
);
136 return AVERROR(ENOMEM
);
137 st
->codec
->codec_id
= AV_CODEC_ID_BINTEXT
;
139 if (ff_alloc_extradata(st
->codec
, 2))
140 return AVERROR(ENOMEM
);
141 st
->codec
->extradata
[0] = 16;
142 st
->codec
->extradata
[1] = 0;
146 bin
->fsize
= avio_size(pb
);
147 if (ff_sauce_read(s
, &bin
->fsize
, &got_width
, 0) < 0)
148 next_tag_read(s
, &bin
->fsize
);
150 predict_width(st
->codec
, bin
->fsize
, got_width
);
151 calculate_height(st
->codec
, bin
->fsize
);
153 avio_seek(pb
, 0, SEEK_SET
);
157 #endif /* CONFIG_BINTEXT_DEMUXER */
159 #if CONFIG_XBIN_DEMUXER
160 static int xbin_probe(AVProbeData
*p
)
162 const uint8_t *d
= p
->buf
;
164 if (AV_RL32(d
) == MKTAG('X','B','I','N') && d
[4] == 0x1A &&
165 AV_RL16(d
+5) > 0 && AV_RL16(d
+5) <= 160 &&
166 d
[9] > 0 && d
[9] <= 32)
167 return AVPROBE_SCORE_MAX
;
171 static int xbin_read_header(AVFormatContext
*s
)
173 BinDemuxContext
*bin
= s
->priv_data
;
174 AVIOContext
*pb
= s
->pb
;
175 char fontheight
, flags
;
177 AVStream
*st
= init_stream(s
);
179 return AVERROR(ENOMEM
);
182 st
->codec
->width
= avio_rl16(pb
)<<3;
183 st
->codec
->height
= avio_rl16(pb
);
184 fontheight
= avio_r8(pb
);
185 st
->codec
->height
*= fontheight
;
188 st
->codec
->extradata_size
= 2;
189 if ((flags
& BINTEXT_PALETTE
))
190 st
->codec
->extradata_size
+= 48;
191 if ((flags
& BINTEXT_FONT
))
192 st
->codec
->extradata_size
+= fontheight
* (flags
& 0x10 ? 512 : 256);
193 st
->codec
->codec_id
= flags
& 4 ? AV_CODEC_ID_XBIN
: AV_CODEC_ID_BINTEXT
;
195 if (ff_alloc_extradata(st
->codec
, st
->codec
->extradata_size
))
196 return AVERROR(ENOMEM
);
197 st
->codec
->extradata
[0] = fontheight
;
198 st
->codec
->extradata
[1] = flags
;
199 if (avio_read(pb
, st
->codec
->extradata
+ 2, st
->codec
->extradata_size
- 2) < 0)
203 bin
->fsize
= avio_size(pb
) - 9 - st
->codec
->extradata_size
;
204 ff_sauce_read(s
, &bin
->fsize
, NULL
, 0);
205 avio_seek(pb
, 9 + st
->codec
->extradata_size
, SEEK_SET
);
210 #endif /* CONFIG_XBIN_DEMUXER */
212 #if CONFIG_ADF_DEMUXER
213 static int adf_read_header(AVFormatContext
*s
)
215 BinDemuxContext
*bin
= s
->priv_data
;
216 AVIOContext
*pb
= s
->pb
;
219 if (avio_r8(pb
) != 1)
220 return AVERROR_INVALIDDATA
;
224 return AVERROR(ENOMEM
);
225 st
->codec
->codec_id
= AV_CODEC_ID_BINTEXT
;
227 if (ff_alloc_extradata(st
->codec
, 2 + 48 + 4096))
228 return AVERROR(ENOMEM
);
229 st
->codec
->extradata
[0] = 16;
230 st
->codec
->extradata
[1] = BINTEXT_PALETTE
|BINTEXT_FONT
;
232 if (avio_read(pb
, st
->codec
->extradata
+ 2, 24) < 0)
235 if (avio_read(pb
, st
->codec
->extradata
+ 2 + 24, 24) < 0)
237 if (avio_read(pb
, st
->codec
->extradata
+ 2 + 48, 4096) < 0)
242 bin
->fsize
= avio_size(pb
) - 1 - 192 - 4096;
243 st
->codec
->width
= 80<<3;
244 ff_sauce_read(s
, &bin
->fsize
, &got_width
, 0);
246 calculate_height(st
->codec
, bin
->fsize
);
247 avio_seek(pb
, 1 + 192 + 4096, SEEK_SET
);
251 #endif /* CONFIG_ADF_DEMUXER */
253 #if CONFIG_IDF_DEMUXER
254 static const uint8_t idf_magic
[] = {
255 0x04, 0x31, 0x2e, 0x34, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x15, 0x00
258 static int idf_probe(AVProbeData
*p
)
260 if (p
->buf_size
< sizeof(idf_magic
))
262 if (!memcmp(p
->buf
, idf_magic
, sizeof(idf_magic
)))
263 return AVPROBE_SCORE_MAX
;
267 static int idf_read_header(AVFormatContext
*s
)
269 BinDemuxContext
*bin
= s
->priv_data
;
270 AVIOContext
*pb
= s
->pb
;
279 return AVERROR(ENOMEM
);
280 st
->codec
->codec_id
= AV_CODEC_ID_IDF
;
282 if (ff_alloc_extradata(st
->codec
, 2 + 48 + 4096))
283 return AVERROR(ENOMEM
);
284 st
->codec
->extradata
[0] = 16;
285 st
->codec
->extradata
[1] = BINTEXT_PALETTE
|BINTEXT_FONT
;
287 avio_seek(pb
, avio_size(pb
) - 4096 - 48, SEEK_SET
);
289 if (avio_read(pb
, st
->codec
->extradata
+ 2 + 48, 4096) < 0)
291 if (avio_read(pb
, st
->codec
->extradata
+ 2, 48) < 0)
294 bin
->fsize
= avio_size(pb
) - 12 - 4096 - 48;
295 ff_sauce_read(s
, &bin
->fsize
, &got_width
, 0);
297 calculate_height(st
->codec
, bin
->fsize
);
298 avio_seek(pb
, 12, SEEK_SET
);
301 #endif /* CONFIG_IDF_DEMUXER */
303 static int read_packet(AVFormatContext
*s
,
306 BinDemuxContext
*bin
= s
->priv_data
;
308 if (bin
->fsize
> 0) {
309 if (av_get_packet(s
->pb
, pkt
, bin
->fsize
) < 0)
311 bin
->fsize
= -1; /* done */
312 } else if (!bin
->fsize
) {
313 if (avio_feof(s
->pb
))
315 if (av_get_packet(s
->pb
, pkt
, bin
->chars_per_frame
) < 0)
321 pkt
->flags
|= AV_PKT_FLAG_KEY
;
325 #define OFFSET(x) offsetof(BinDemuxContext, x)
326 static const AVOption options
[] = {
327 { "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
},
328 { "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
},
329 { "framerate", "set framerate (frames per second)", OFFSET(framerate
), AV_OPT_TYPE_VIDEO_RATE
, {.str
= "25"}, 0, 0, AV_OPT_FLAG_DECODING_PARAM
},
333 #define CLASS(name) \
334 (const AVClass[1]){{ \
335 .class_name = name, \
336 .item_name = av_default_item_name, \
338 .version = LIBAVUTIL_VERSION_INT, \
341 #if CONFIG_BINTEXT_DEMUXER
342 AVInputFormat ff_bintext_demuxer
= {
344 .long_name
= NULL_IF_CONFIG_SMALL("Binary text"),
345 .priv_data_size
= sizeof(BinDemuxContext
),
346 .read_header
= bintext_read_header
,
347 .read_packet
= read_packet
,
349 .priv_class
= CLASS("Binary text demuxer"),
353 #if CONFIG_XBIN_DEMUXER
354 AVInputFormat ff_xbin_demuxer
= {
356 .long_name
= NULL_IF_CONFIG_SMALL("eXtended BINary text (XBIN)"),
357 .priv_data_size
= sizeof(BinDemuxContext
),
358 .read_probe
= xbin_probe
,
359 .read_header
= xbin_read_header
,
360 .read_packet
= read_packet
,
361 .priv_class
= CLASS("eXtended BINary text (XBIN) demuxer"),
365 #if CONFIG_ADF_DEMUXER
366 AVInputFormat ff_adf_demuxer
= {
368 .long_name
= NULL_IF_CONFIG_SMALL("Artworx Data Format"),
369 .priv_data_size
= sizeof(BinDemuxContext
),
370 .read_header
= adf_read_header
,
371 .read_packet
= read_packet
,
373 .priv_class
= CLASS("Artworx Data Format demuxer"),
377 #if CONFIG_IDF_DEMUXER
378 AVInputFormat ff_idf_demuxer
= {
380 .long_name
= NULL_IF_CONFIG_SMALL("iCE Draw File"),
381 .priv_data_size
= sizeof(BinDemuxContext
),
382 .read_probe
= idf_probe
,
383 .read_header
= idf_read_header
,
384 .read_packet
= read_packet
,
386 .priv_class
= CLASS("iCE Draw File demuxer"),