libavformat/bintext.c
Go to the documentation of this file.
1 /*
2  * Binary text demuxer
3  * eXtended BINary text (XBIN) demuxer
4  * Artworx Data Format demuxer
5  * iCEDraw File demuxer
6  * Copyright (c) 2010 Peter Ross <pross@xvid.org>
7  *
8  * This file is part of FFmpeg.
9  *
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.
14  *
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.
19  *
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
23  */
24 
25 /**
26  * @file
27  * Binary text demuxer
28  * eXtended BINary text (XBIN) demuxer
29  * Artworx Data Format demuxer
30  * iCEDraw File demuxer
31  */
32 
33 #include "libavutil/intreadwrite.h"
34 #include "libavutil/opt.h"
35 #include "libavutil/parseutils.h"
36 #include "avformat.h"
37 #include "internal.h"
38 #include "sauce.h"
39 #include "libavcodec/bintext.h"
40 
41 typedef struct {
42  const AVClass *class;
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 */
50 
52 {
53  BinDemuxContext *bin = s->priv_data;
55  if (!st)
56  return NULL;
57  st->codec->codec_tag = 0;
59 
60  if (!bin->width) {
61  st->codec->width = (80<<3);
62  st->codec->height = (25<<4);
63  }
64 
65  avpriv_set_pts_info(st, 60, bin->framerate.den, bin->framerate.num);
66 
67  /* simulate tty display speed */
68  bin->chars_per_frame = FFMAX(av_q2d(st->time_base) * bin->chars_per_frame, 1);
69 
70  return st;
71 }
72 
73 #if CONFIG_BINTEXT_DEMUXER | CONFIG_ADF_DEMUXER | CONFIG_IDF_DEMUXER
74 /**
75  * Given filesize and width, calculate height (assume font_height of 16)
76  */
77 static void calculate_height(AVCodecContext *avctx, uint64_t fsize)
78 {
79  avctx->height = (fsize / ((avctx->width>>3)*2)) << 4;
80 }
81 #endif
82 
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
86 };
87 
88 static int next_tag_read(AVFormatContext *avctx, uint64_t *fsize)
89 {
90  AVIOContext *pb = avctx->pb;
91  char buf[36];
92  int len;
93  uint64_t start_pos = avio_size(pb) - 256;
94 
95  avio_seek(pb, start_pos, SEEK_SET);
96  if (avio_read(pb, buf, sizeof(next_magic)) != sizeof(next_magic))
97  return -1;
98  if (memcmp(buf, next_magic, sizeof(next_magic)))
99  return -1;
100  if (avio_r8(pb) != 0x01)
101  return -1;
102 
103  *fsize -= 256;
104 
105 #define GET_EFI2_META(name,size) \
106  len = avio_r8(pb); \
107  if (len < 1 || len > size) \
108  return -1; \
109  if (avio_read(pb, buf, size) == size && *buf) { \
110  buf[len] = 0; \
111  av_dict_set(&avctx->metadata, name, buf, 0); \
112  }
113 
114  GET_EFI2_META("filename", 12)
115  GET_EFI2_META("author", 20)
116  GET_EFI2_META("publisher", 20)
117  GET_EFI2_META("title", 35)
118 
119  return 0;
120 }
121 
122 static void predict_width(AVCodecContext *avctx, uint64_t fsize, int got_width)
123 {
124  /** attempt to guess width */
125  if (!got_width)
126  avctx->width = fsize > 4000 ? (160<<3) : (80<<3);
127 }
128 
129 static int bintext_read_header(AVFormatContext *s)
130 {
131  BinDemuxContext *bin = s->priv_data;
132  AVIOContext *pb = s->pb;
133 
134  AVStream *st = init_stream(s);
135  if (!st)
136  return AVERROR(ENOMEM);
138 
139  st->codec->extradata_size = 2;
141  if (!st->codec->extradata)
142  return AVERROR(ENOMEM);
143  st->codec->extradata[0] = 16;
144  st->codec->extradata[1] = 0;
145 
146  if (pb->seekable) {
147  int got_width = 0;
148  bin->fsize = avio_size(pb);
149  if (ff_sauce_read(s, &bin->fsize, &got_width, 0) < 0)
150  next_tag_read(s, &bin->fsize);
151  if (!bin->width) {
152  predict_width(st->codec, bin->fsize, got_width);
153  calculate_height(st->codec, bin->fsize);
154  }
155  avio_seek(pb, 0, SEEK_SET);
156  }
157  return 0;
158 }
159 #endif /* CONFIG_BINTEXT_DEMUXER */
160 
161 #if CONFIG_XBIN_DEMUXER
162 static int xbin_probe(AVProbeData *p)
163 {
164  const uint8_t *d = p->buf;
165 
166  if (AV_RL32(d) == MKTAG('X','B','I','N') && d[4] == 0x1A &&
167  AV_RL16(d+5) > 0 && AV_RL16(d+5) <= 160 &&
168  d[9] > 0 && d[9] <= 32)
169  return AVPROBE_SCORE_MAX;
170  return 0;
171 }
172 
173 static int xbin_read_header(AVFormatContext *s)
174 {
175  BinDemuxContext *bin = s->priv_data;
176  AVIOContext *pb = s->pb;
177  char fontheight, flags;
178 
179  AVStream *st = init_stream(s);
180  if (!st)
181  return AVERROR(ENOMEM);
182 
183  avio_skip(pb, 5);
184  st->codec->width = avio_rl16(pb)<<3;
185  st->codec->height = avio_rl16(pb);
186  fontheight = avio_r8(pb);
187  st->codec->height *= fontheight;
188  flags = avio_r8(pb);
189 
190  st->codec->extradata_size = 2;
191  if ((flags & BINTEXT_PALETTE))
192  st->codec->extradata_size += 48;
193  if ((flags & BINTEXT_FONT))
194  st->codec->extradata_size += fontheight * (flags & 0x10 ? 512 : 256);
195  st->codec->codec_id = flags & 4 ? AV_CODEC_ID_XBIN : AV_CODEC_ID_BINTEXT;
196 
198  if (!st->codec->extradata)
199  return AVERROR(ENOMEM);
200  st->codec->extradata[0] = fontheight;
201  st->codec->extradata[1] = flags;
202  if (avio_read(pb, st->codec->extradata + 2, st->codec->extradata_size - 2) < 0)
203  return AVERROR(EIO);
204 
205  if (pb->seekable) {
206  bin->fsize = avio_size(pb) - 9 - st->codec->extradata_size;
207  ff_sauce_read(s, &bin->fsize, NULL, 0);
208  avio_seek(pb, 9 + st->codec->extradata_size, SEEK_SET);
209  }
210 
211  return 0;
212 }
213 #endif /* CONFIG_XBIN_DEMUXER */
214 
215 #if CONFIG_ADF_DEMUXER
216 static int adf_read_header(AVFormatContext *s)
217 {
218  BinDemuxContext *bin = s->priv_data;
219  AVIOContext *pb = s->pb;
220  AVStream *st;
221 
222  if (avio_r8(pb) != 1)
223  return AVERROR_INVALIDDATA;
224 
225  st = init_stream(s);
226  if (!st)
227  return AVERROR(ENOMEM);
229 
230  st->codec->extradata_size = 2 + 48 + 4096;
232  if (!st->codec->extradata)
233  return AVERROR(ENOMEM);
234  st->codec->extradata[0] = 16;
236 
237  if (avio_read(pb, st->codec->extradata + 2, 24) < 0)
238  return AVERROR(EIO);
239  avio_skip(pb, 144);
240  if (avio_read(pb, st->codec->extradata + 2 + 24, 24) < 0)
241  return AVERROR(EIO);
242  if (avio_read(pb, st->codec->extradata + 2 + 48, 4096) < 0)
243  return AVERROR(EIO);
244 
245  if (pb->seekable) {
246  int got_width = 0;
247  bin->fsize = avio_size(pb) - 1 - 192 - 4096;
248  st->codec->width = 80<<3;
249  ff_sauce_read(s, &bin->fsize, &got_width, 0);
250  if (!bin->width)
251  calculate_height(st->codec, bin->fsize);
252  avio_seek(pb, 1 + 192 + 4096, SEEK_SET);
253  }
254  return 0;
255 }
256 #endif /* CONFIG_ADF_DEMUXER */
257 
258 #if CONFIG_IDF_DEMUXER
259 static const uint8_t idf_magic[] = {
260  0x04, 0x31, 0x2e, 0x34, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x15, 0x00
261 };
262 
263 static int idf_probe(AVProbeData *p)
264 {
265  if (p->buf_size < sizeof(idf_magic))
266  return 0;
267  if (!memcmp(p->buf, idf_magic, sizeof(idf_magic)))
268  return AVPROBE_SCORE_MAX;
269  return 0;
270 }
271 
272 static int idf_read_header(AVFormatContext *s)
273 {
274  BinDemuxContext *bin = s->priv_data;
275  AVIOContext *pb = s->pb;
276  AVStream *st;
277  int got_width = 0;
278 
279  if (!pb->seekable)
280  return AVERROR(EIO);
281 
282  st = init_stream(s);
283  if (!st)
284  return AVERROR(ENOMEM);
286 
287  st->codec->extradata_size = 2 + 48 + 4096;
289  if (!st->codec->extradata)
290  return AVERROR(ENOMEM);
291  st->codec->extradata[0] = 16;
293 
294  avio_seek(pb, avio_size(pb) - 4096 - 48, SEEK_SET);
295 
296  if (avio_read(pb, st->codec->extradata + 2 + 48, 4096) < 0)
297  return AVERROR(EIO);
298  if (avio_read(pb, st->codec->extradata + 2, 48) < 0)
299  return AVERROR(EIO);
300 
301  bin->fsize = avio_size(pb) - 12 - 4096 - 48;
302  ff_sauce_read(s, &bin->fsize, &got_width, 0);
303  if (!bin->width)
304  calculate_height(st->codec, bin->fsize);
305  avio_seek(pb, 12, SEEK_SET);
306  return 0;
307 }
308 #endif /* CONFIG_IDF_DEMUXER */
309 
311  AVPacket *pkt)
312 {
313  BinDemuxContext *bin = s->priv_data;
314 
315  if (bin->fsize > 0) {
316  if (av_get_packet(s->pb, pkt, bin->fsize) < 0)
317  return AVERROR(EIO);
318  bin->fsize = -1; /* done */
319  } else if (!bin->fsize) {
320  if (url_feof(s->pb))
321  return AVERROR(EIO);
322  if (av_get_packet(s->pb, pkt, bin->chars_per_frame) < 0)
323  return AVERROR(EIO);
324  } else {
325  return AVERROR(EIO);
326  }
327 
328  pkt->flags |= AV_PKT_FLAG_KEY;
329  return 0;
330 }
331 
332 #define OFFSET(x) offsetof(BinDemuxContext, x)
333 static const AVOption options[] = {
334  { "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},
335  { "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 },
336  { "framerate", "set framerate (frames per second)", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
337  { NULL },
338 };
339 
340 #define CLASS(name) \
341 (const AVClass[1]){{ \
342  .class_name = name, \
343  .item_name = av_default_item_name, \
344  .option = options, \
345  .version = LIBAVUTIL_VERSION_INT, \
346 }}
347 
348 #if CONFIG_BINTEXT_DEMUXER
349 AVInputFormat ff_bintext_demuxer = {
350  .name = "bin",
351  .long_name = NULL_IF_CONFIG_SMALL("Binary text"),
352  .priv_data_size = sizeof(BinDemuxContext),
353  .read_header = bintext_read_header,
355  .extensions = "bin",
356  .priv_class = CLASS("Binary text demuxer"),
357 };
358 #endif
359 
360 #if CONFIG_XBIN_DEMUXER
361 AVInputFormat ff_xbin_demuxer = {
362  .name = "xbin",
363  .long_name = NULL_IF_CONFIG_SMALL("eXtended BINary text (XBIN)"),
364  .priv_data_size = sizeof(BinDemuxContext),
365  .read_probe = xbin_probe,
366  .read_header = xbin_read_header,
368  .priv_class = CLASS("eXtended BINary text (XBIN) demuxer"),
369 };
370 #endif
371 
372 #if CONFIG_ADF_DEMUXER
373 AVInputFormat ff_adf_demuxer = {
374  .name = "adf",
375  .long_name = NULL_IF_CONFIG_SMALL("Artworx Data Format"),
376  .priv_data_size = sizeof(BinDemuxContext),
377  .read_header = adf_read_header,
379  .extensions = "adf",
380  .priv_class = CLASS("Artworx Data Format demuxer"),
381 };
382 #endif
383 
384 #if CONFIG_IDF_DEMUXER
385 AVInputFormat ff_idf_demuxer = {
386  .name = "idf",
387  .long_name = NULL_IF_CONFIG_SMALL("iCE Draw File"),
388  .priv_data_size = sizeof(BinDemuxContext),
389  .read_probe = idf_probe,
390  .read_header = idf_read_header,
392  .extensions = "idf",
393  .priv_class = CLASS("iCE Draw File demuxer"),
394 };
395 #endif
Binary text decoder.
#define OFFSET(x)
const char * s
Definition: avisynth_c.h:668
Bytestream IO Context.
Definition: avio.h:68
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
int64_t avio_size(AVIOContext *s)
Get the filesize.
Definition: aviobuf.c:261
AVOption.
Definition: opt.h:251
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
int num
numerator
Definition: rational.h:44
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:199
#define AV_RL16
int64_t avio_skip(AVIOContext *s, int64_t offset)
Skip given number of bytes forward.
Definition: aviobuf.c:256
int chars_per_frame
characters to send decoder per frame; set by private options as characters per second, and then converted to characters per frame at runtime
set threshold d
Format I/O context.
Definition: avformat.h:944
uint8_t
AVOptions.
static AVPacket pkt
Definition: demuxing.c:56
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
static double av_q2d(AVRational a)
Convert rational to double.
Definition: rational.h:69
static const AVOption options[]
int av_get_packet(AVIOContext *s, AVPacket *pkt, int size)
Allocate and read the payload of a packet and initialize its fields with default values.
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:478
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
#define BINTEXT_PALETTE
Definition: bintext.h:34
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
int ff_sauce_read(AVFormatContext *avctx, uint64_t *fsize, int *got_width, int get_height)
Definition: sauce.c:32
#define FFMAX(a, b)
Definition: common.h:56
int flags
A combination of AV_PKT_FLAG values.
int avio_r8(AVIOContext *s)
Definition: aviobuf.c:469
AVCodecContext * codec
Codec context associated with this stream.
Definition: avformat.h:662
int buf_size
Size of buf except extra allocated bytes.
Definition: avformat.h:337
unsigned char * buf
Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero.
Definition: avformat.h:336
#define FF_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding...
int seekable
A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
Definition: avio.h:117
static int read_probe(AVProbeData *pd)
int width
picture width / height.
#define AV_RL32
uint64_t fsize
file size less metadata buffer
int url_feof(AVIOContext *s)
feof() equivalent for AVIOContext.
Definition: aviobuf.c:280
static int read_header(FFV1Context *f)
Definition: ffv1dec.c:517
Stream structure.
Definition: avformat.h:643
NULL
Definition: eval.c:55
static int width
Definition: tests/utils.c:158
enum AVMediaType codec_type
enum AVCodecID codec_id
AVRational framerate
frames per second (private option)
AVIOContext * pb
I/O context.
Definition: avformat.h:977
main external API structure.
unsigned int codec_tag
fourcc (LSB first, so "ABCD" -> (&#39;D&#39;<<24) + (&#39;C&#39;<<16) + (&#39;B&#39;<<8) + &#39;A&#39;).
void * buf
Definition: avisynth_c.h:594
BYTE int const BYTE int int int height
Definition: avisynth_c.h:713
void * av_malloc(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:73
Describe the class of an AVClass context structure.
Definition: log.h:50
rational number numerator/denominator
Definition: rational.h:43
#define AV_OPT_FLAG_DECODING_PARAM
a generic parameter which can be set by the user for demuxing or decoding
Definition: opt.h:282
offset must point to AVRational
Definition: opt.h:233
static int read_packet(AVFormatContext *s, AVPacket *pkt)
offset must point to two consecutive integers
Definition: opt.h:230
This structure contains the data a format has to probe a file.
Definition: avformat.h:334
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
misc parsing utilities
SAUCE header parser.
static AVStream * init_stream(AVFormatContext *s)
static int flags
Definition: cpu.c:23
#define AVPROBE_SCORE_MAX
maximum score, half of that is used for file-extension-based detection
Definition: avformat.h:340
unsigned int avio_rl16(AVIOContext *s)
Definition: aviobuf.c:563
Main libavformat public API header.
int den
denominator
Definition: rational.h:45
int len
void * priv_data
Format private data.
Definition: avformat.h:964
#define CLASS(name)
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:461
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
Definition: avformat.h:679
#define MKTAG(a, b, c, d)
Definition: common.h:282
#define BINTEXT_FONT
Definition: bintext.h:35
This structure stores compressed data.