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