00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00033 #include "libavutil/intreadwrite.h"
00034 #include "libavutil/opt.h"
00035 #include "libavutil/parseutils.h"
00036 #include "avformat.h"
00037 #include "internal.h"
00038 #include "sauce.h"
00039 #include "libavcodec/bintext.h"
00040
00041 typedef struct {
00042 const AVClass *class;
00043 int chars_per_frame;
00046 char *video_size;
00047 char *framerate;
00048 uint64_t fsize;
00049 } BinDemuxContext;
00050
00051 static AVStream * init_stream(AVFormatContext *s)
00052 {
00053 BinDemuxContext *bin = s->priv_data;
00054 AVStream *st = avformat_new_stream(s, NULL);
00055 if (!st)
00056 return NULL;
00057 st->codec->codec_tag = 0;
00058 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00059
00060 if (bin->video_size) {
00061 if (av_parse_video_size(&st->codec->width, &st->codec->height, bin->video_size) < 0) {
00062 av_log(s, AV_LOG_ERROR, "Could not parse video size: '%s'\n", bin->video_size);
00063 return NULL;
00064 }
00065 } else {
00066 st->codec->width = (80<<3);
00067 st->codec->height = (25<<4);
00068 }
00069
00070 if (bin->framerate) {
00071 AVRational framerate;
00072 if (av_parse_video_rate(&framerate, bin->framerate) < 0) {
00073 av_log(s, AV_LOG_ERROR, "Could not parse framerate: '%s'\n", bin->framerate);
00074 return NULL;
00075 }
00076 avpriv_set_pts_info(st, 60, framerate.den, framerate.num);
00077 } else {
00078 avpriv_set_pts_info(st, 60, 1, 25);
00079 }
00080
00081
00082 bin->chars_per_frame = FFMAX(av_q2d(st->time_base) * bin->chars_per_frame, 1);
00083
00084 return st;
00085 }
00086
00087 #if CONFIG_BINTEXT_DEMUXER | CONFIG_ADF_DEMUXER | CONFIG_IDF_DEMUXER
00088
00091 static void calculate_height(AVCodecContext *avctx, uint64_t fsize)
00092 {
00093 avctx->height = (fsize / ((avctx->width>>3)*2)) << 4;
00094 }
00095 #endif
00096
00097 #if CONFIG_BINTEXT_DEMUXER
00098 static const uint8_t next_magic[]={
00099 0x1A, 0x1B, '[', '0', ';', '3', '0', ';', '4', '0', 'm', 'N', 'E', 'X', 'T', 0x00
00100 };
00101
00102 static int next_tag_read(AVFormatContext *avctx, uint64_t *fsize)
00103 {
00104 AVIOContext *pb = avctx->pb;
00105 char buf[36];
00106 int len;
00107 uint64_t start_pos = avio_size(pb) - 256;
00108
00109 avio_seek(pb, start_pos, SEEK_SET);
00110 if (avio_read(pb, buf, sizeof(next_magic)) != sizeof(next_magic))
00111 return -1;
00112 if (memcmp(buf, next_magic, sizeof(next_magic)))
00113 return -1;
00114 if (avio_r8(pb) != 0x01)
00115 return -1;
00116
00117 *fsize -= 256;
00118
00119 #define GET_EFI2_META(name,size) \
00120 len = avio_r8(pb); \
00121 if (len < 1 || len > size) \
00122 return -1; \
00123 if (avio_read(pb, buf, size) == size && *buf) { \
00124 buf[len] = 0; \
00125 av_dict_set(&avctx->metadata, name, buf, 0); \
00126 }
00127
00128 GET_EFI2_META("filename", 12)
00129 GET_EFI2_META("author", 20)
00130 GET_EFI2_META("publisher", 20)
00131 GET_EFI2_META("title", 35)
00132
00133 return 0;
00134 }
00135
00136 static void predict_width(AVCodecContext *avctx, uint64_t fsize, int got_width)
00137 {
00139 if (!got_width)
00140 avctx->width = fsize > 4000 ? (160<<3) : (80<<3);
00141 }
00142
00143 static int bintext_read_header(AVFormatContext *s)
00144 {
00145 BinDemuxContext *bin = s->priv_data;
00146 AVIOContext *pb = s->pb;
00147
00148 AVStream *st = init_stream(s);
00149 if (!st)
00150 return AVERROR(ENOMEM);
00151 st->codec->codec_id = AV_CODEC_ID_BINTEXT;
00152
00153 st->codec->extradata_size = 2;
00154 st->codec->extradata = av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
00155 if (!st->codec->extradata)
00156 return AVERROR(ENOMEM);
00157 st->codec->extradata[0] = 16;
00158 st->codec->extradata[1] = 0;
00159
00160 if (pb->seekable) {
00161 int got_width = 0;
00162 bin->fsize = avio_size(pb);
00163 if (ff_sauce_read(s, &bin->fsize, &got_width, 0) < 0)
00164 next_tag_read(s, &bin->fsize);
00165 if (!bin->video_size) {
00166 predict_width(st->codec, bin->fsize, got_width);
00167 calculate_height(st->codec, bin->fsize);
00168 }
00169 avio_seek(pb, 0, SEEK_SET);
00170 }
00171 return 0;
00172 }
00173 #endif
00174
00175 #if CONFIG_XBIN_DEMUXER
00176 static int xbin_probe(AVProbeData *p)
00177 {
00178 const uint8_t *d = p->buf;
00179
00180 if (AV_RL32(d) == MKTAG('X','B','I','N') && d[4] == 0x1A &&
00181 AV_RL16(d+5) > 0 && AV_RL16(d+5) <= 160 &&
00182 d[9] > 0 && d[9] <= 32)
00183 return AVPROBE_SCORE_MAX;
00184 return 0;
00185 }
00186
00187 static int xbin_read_header(AVFormatContext *s)
00188 {
00189 BinDemuxContext *bin = s->priv_data;
00190 AVIOContext *pb = s->pb;
00191 char fontheight, flags;
00192
00193 AVStream *st = init_stream(s);
00194 if (!st)
00195 return AVERROR(ENOMEM);
00196
00197 avio_skip(pb, 5);
00198 st->codec->width = avio_rl16(pb)<<3;
00199 st->codec->height = avio_rl16(pb);
00200 fontheight = avio_r8(pb);
00201 st->codec->height *= fontheight;
00202 flags = avio_r8(pb);
00203
00204 st->codec->extradata_size = 2;
00205 if ((flags & BINTEXT_PALETTE))
00206 st->codec->extradata_size += 48;
00207 if ((flags & BINTEXT_FONT))
00208 st->codec->extradata_size += fontheight * (flags & 0x10 ? 512 : 256);
00209 st->codec->codec_id = flags & 4 ? AV_CODEC_ID_XBIN : AV_CODEC_ID_BINTEXT;
00210
00211 st->codec->extradata = av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
00212 if (!st->codec->extradata)
00213 return AVERROR(ENOMEM);
00214 st->codec->extradata[0] = fontheight;
00215 st->codec->extradata[1] = flags;
00216 if (avio_read(pb, st->codec->extradata + 2, st->codec->extradata_size - 2) < 0)
00217 return AVERROR(EIO);
00218
00219 if (pb->seekable) {
00220 bin->fsize = avio_size(pb) - 9 - st->codec->extradata_size;
00221 ff_sauce_read(s, &bin->fsize, NULL, 0);
00222 avio_seek(pb, 9 + st->codec->extradata_size, SEEK_SET);
00223 }
00224
00225 return 0;
00226 }
00227 #endif
00228
00229 #if CONFIG_ADF_DEMUXER
00230 static int adf_read_header(AVFormatContext *s)
00231 {
00232 BinDemuxContext *bin = s->priv_data;
00233 AVIOContext *pb = s->pb;
00234 AVStream *st;
00235
00236 if (avio_r8(pb) != 1)
00237 return AVERROR_INVALIDDATA;
00238
00239 st = init_stream(s);
00240 if (!st)
00241 return AVERROR(ENOMEM);
00242 st->codec->codec_id = AV_CODEC_ID_BINTEXT;
00243
00244 st->codec->extradata_size = 2 + 48 + 4096;
00245 st->codec->extradata = av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
00246 if (!st->codec->extradata)
00247 return AVERROR(ENOMEM);
00248 st->codec->extradata[0] = 16;
00249 st->codec->extradata[1] = BINTEXT_PALETTE|BINTEXT_FONT;
00250
00251 if (avio_read(pb, st->codec->extradata + 2, 24) < 0)
00252 return AVERROR(EIO);
00253 avio_skip(pb, 144);
00254 if (avio_read(pb, st->codec->extradata + 2 + 24, 24) < 0)
00255 return AVERROR(EIO);
00256 if (avio_read(pb, st->codec->extradata + 2 + 48, 4096) < 0)
00257 return AVERROR(EIO);
00258
00259 if (pb->seekable) {
00260 int got_width = 0;
00261 bin->fsize = avio_size(pb) - 1 - 192 - 4096;
00262 st->codec->width = 80<<3;
00263 ff_sauce_read(s, &bin->fsize, &got_width, 0);
00264 if (!bin->video_size)
00265 calculate_height(st->codec, bin->fsize);
00266 avio_seek(pb, 1 + 192 + 4096, SEEK_SET);
00267 }
00268 return 0;
00269 }
00270 #endif
00271
00272 #if CONFIG_IDF_DEMUXER
00273 static const uint8_t idf_magic[] = {
00274 0x04, 0x31, 0x2e, 0x34, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x15, 0x00
00275 };
00276
00277 static int idf_probe(AVProbeData *p)
00278 {
00279 if (p->buf_size < sizeof(idf_magic))
00280 return 0;
00281 if (!memcmp(p->buf, idf_magic, sizeof(idf_magic)))
00282 return AVPROBE_SCORE_MAX;
00283 return 0;
00284 }
00285
00286 static int idf_read_header(AVFormatContext *s)
00287 {
00288 BinDemuxContext *bin = s->priv_data;
00289 AVIOContext *pb = s->pb;
00290 AVStream *st;
00291 int got_width = 0;
00292
00293 if (!pb->seekable)
00294 return AVERROR(EIO);
00295
00296 st = init_stream(s);
00297 if (!st)
00298 return AVERROR(ENOMEM);
00299 st->codec->codec_id = AV_CODEC_ID_IDF;
00300
00301 st->codec->extradata_size = 2 + 48 + 4096;
00302 st->codec->extradata = av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
00303 if (!st->codec->extradata)
00304 return AVERROR(ENOMEM);
00305 st->codec->extradata[0] = 16;
00306 st->codec->extradata[1] = BINTEXT_PALETTE|BINTEXT_FONT;
00307
00308 avio_seek(pb, avio_size(pb) - 4096 - 48, SEEK_SET);
00309
00310 if (avio_read(pb, st->codec->extradata + 2 + 48, 4096) < 0)
00311 return AVERROR(EIO);
00312 if (avio_read(pb, st->codec->extradata + 2, 48) < 0)
00313 return AVERROR(EIO);
00314
00315 bin->fsize = avio_size(pb) - 12 - 4096 - 48;
00316 ff_sauce_read(s, &bin->fsize, &got_width, 0);
00317 if (!bin->video_size)
00318 calculate_height(st->codec, bin->fsize);
00319 avio_seek(pb, 12, SEEK_SET);
00320 return 0;
00321 }
00322 #endif
00323
00324 static int read_packet(AVFormatContext *s,
00325 AVPacket *pkt)
00326 {
00327 BinDemuxContext *bin = s->priv_data;
00328
00329 if (bin->fsize > 0) {
00330 if (av_get_packet(s->pb, pkt, bin->fsize) < 0)
00331 return AVERROR(EIO);
00332 bin->fsize = -1;
00333 } else if (!bin->fsize) {
00334 if (url_feof(s->pb))
00335 return AVERROR(EIO);
00336 if (av_get_packet(s->pb, pkt, bin->chars_per_frame) < 0)
00337 return AVERROR(EIO);
00338 } else {
00339 return AVERROR(EIO);
00340 }
00341
00342 pkt->flags |= AV_PKT_FLAG_KEY;
00343 return 0;
00344 }
00345
00346 #define OFFSET(x) offsetof(BinDemuxContext, x)
00347 static const AVOption options[] = {
00348 { "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},
00349 { "video_size", "set video size, such as 640x480 or hd720.", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
00350 { "framerate", "set framerate (frames per second)", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
00351 { NULL },
00352 };
00353
00354 #define CLASS(name) \
00355 (const AVClass[1]){{ \
00356 .class_name = name, \
00357 .item_name = av_default_item_name, \
00358 .option = options, \
00359 .version = LIBAVUTIL_VERSION_INT, \
00360 }}
00361
00362 #if CONFIG_BINTEXT_DEMUXER
00363 AVInputFormat ff_bintext_demuxer = {
00364 .name = "bin",
00365 .long_name = NULL_IF_CONFIG_SMALL("Binary text"),
00366 .priv_data_size = sizeof(BinDemuxContext),
00367 .read_header = bintext_read_header,
00368 .read_packet = read_packet,
00369 .extensions = "bin",
00370 .priv_class = CLASS("Binary text demuxer"),
00371 };
00372 #endif
00373
00374 #if CONFIG_XBIN_DEMUXER
00375 AVInputFormat ff_xbin_demuxer = {
00376 .name = "xbin",
00377 .long_name = NULL_IF_CONFIG_SMALL("eXtended BINary text (XBIN)"),
00378 .priv_data_size = sizeof(BinDemuxContext),
00379 .read_probe = xbin_probe,
00380 .read_header = xbin_read_header,
00381 .read_packet = read_packet,
00382 .priv_class = CLASS("eXtended BINary text (XBIN) demuxer"),
00383 };
00384 #endif
00385
00386 #if CONFIG_ADF_DEMUXER
00387 AVInputFormat ff_adf_demuxer = {
00388 .name = "adf",
00389 .long_name = NULL_IF_CONFIG_SMALL("Artworx Data Format"),
00390 .priv_data_size = sizeof(BinDemuxContext),
00391 .read_header = adf_read_header,
00392 .read_packet = read_packet,
00393 .extensions = "adf",
00394 .priv_class = CLASS("Artworx Data Format demuxer"),
00395 };
00396 #endif
00397
00398 #if CONFIG_IDF_DEMUXER
00399 AVInputFormat ff_idf_demuxer = {
00400 .name = "idf",
00401 .long_name = NULL_IF_CONFIG_SMALL("iCE Draw File"),
00402 .priv_data_size = sizeof(BinDemuxContext),
00403 .read_probe = idf_probe,
00404 .read_header = idf_read_header,
00405 .read_packet = read_packet,
00406 .extensions = "idf",
00407 .priv_class = CLASS("iCE Draw File demuxer"),
00408 };
00409 #endif