Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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 */
  49. } BinDemuxContext;
  50.  
  51. static AVStream * init_stream(AVFormatContext *s)
  52. {
  53.     BinDemuxContext *bin = s->priv_data;
  54.     AVStream *st = avformat_new_stream(s, NULL);
  55.     if (!st)
  56.         return NULL;
  57.     st->codec->codec_tag   = 0;
  58.     st->codec->codec_type  = AVMEDIA_TYPE_VIDEO;
  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 = av_clip(av_q2d(st->time_base) * bin->chars_per_frame, 1, INT_MAX);
  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);
  137.     st->codec->codec_id    = AV_CODEC_ID_BINTEXT;
  138.  
  139.     if (ff_alloc_extradata(st->codec, 2))
  140.         return AVERROR(ENOMEM);
  141.     st->codec->extradata[0] = 16;
  142.     st->codec->extradata[1] = 0;
  143.  
  144.     if (pb->seekable) {
  145.         int got_width = 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);
  149.         if (!bin->width) {
  150.             predict_width(st->codec, bin->fsize, got_width);
  151.             calculate_height(st->codec, bin->fsize);
  152.         }
  153.         avio_seek(pb, 0, SEEK_SET);
  154.     }
  155.     return 0;
  156. }
  157. #endif /* CONFIG_BINTEXT_DEMUXER */
  158.  
  159. #if CONFIG_XBIN_DEMUXER
  160. static int xbin_probe(AVProbeData *p)
  161. {
  162.     const uint8_t *d = p->buf;
  163.  
  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;
  168.     return 0;
  169. }
  170.  
  171. static int xbin_read_header(AVFormatContext *s)
  172. {
  173.     BinDemuxContext *bin = s->priv_data;
  174.     AVIOContext *pb = s->pb;
  175.     char fontheight, flags;
  176.  
  177.     AVStream *st = init_stream(s);
  178.     if (!st)
  179.         return AVERROR(ENOMEM);
  180.  
  181.     avio_skip(pb, 5);
  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;
  186.     flags              = avio_r8(pb);
  187.  
  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;
  194.  
  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)
  200.         return AVERROR(EIO);
  201.  
  202.     if (pb->seekable) {
  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);
  206.     }
  207.  
  208.     return 0;
  209. }
  210. #endif /* CONFIG_XBIN_DEMUXER */
  211.  
  212. #if CONFIG_ADF_DEMUXER
  213. static int adf_read_header(AVFormatContext *s)
  214. {
  215.     BinDemuxContext *bin = s->priv_data;
  216.     AVIOContext *pb = s->pb;
  217.     AVStream *st;
  218.  
  219.     if (avio_r8(pb) != 1)
  220.         return AVERROR_INVALIDDATA;
  221.  
  222.     st = init_stream(s);
  223.     if (!st)
  224.         return AVERROR(ENOMEM);
  225.     st->codec->codec_id    = AV_CODEC_ID_BINTEXT;
  226.  
  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;
  231.  
  232.     if (avio_read(pb, st->codec->extradata + 2, 24) < 0)
  233.         return AVERROR(EIO);
  234.     avio_skip(pb, 144);
  235.     if (avio_read(pb, st->codec->extradata + 2 + 24, 24) < 0)
  236.         return AVERROR(EIO);
  237.     if (avio_read(pb, st->codec->extradata + 2 + 48, 4096) < 0)
  238.         return AVERROR(EIO);
  239.  
  240.     if (pb->seekable) {
  241.         int got_width = 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);
  245.         if (!bin->width)
  246.             calculate_height(st->codec, bin->fsize);
  247.         avio_seek(pb, 1 + 192 + 4096, SEEK_SET);
  248.     }
  249.     return 0;
  250. }
  251. #endif /* CONFIG_ADF_DEMUXER */
  252.  
  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
  256. };
  257.  
  258. static int idf_probe(AVProbeData *p)
  259. {
  260.     if (p->buf_size < sizeof(idf_magic))
  261.         return 0;
  262.     if (!memcmp(p->buf, idf_magic, sizeof(idf_magic)))
  263.         return AVPROBE_SCORE_MAX;
  264.     return 0;
  265. }
  266.  
  267. static int idf_read_header(AVFormatContext *s)
  268. {
  269.     BinDemuxContext *bin = s->priv_data;
  270.     AVIOContext *pb = s->pb;
  271.     AVStream *st;
  272.     int got_width = 0;
  273.  
  274.     if (!pb->seekable)
  275.         return AVERROR(EIO);
  276.  
  277.     st = init_stream(s);
  278.     if (!st)
  279.         return AVERROR(ENOMEM);
  280.     st->codec->codec_id    = AV_CODEC_ID_IDF;
  281.  
  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;
  286.  
  287.     avio_seek(pb, avio_size(pb) - 4096 - 48, SEEK_SET);
  288.  
  289.     if (avio_read(pb, st->codec->extradata + 2 + 48, 4096) < 0)
  290.         return AVERROR(EIO);
  291.     if (avio_read(pb, st->codec->extradata + 2, 48) < 0)
  292.         return AVERROR(EIO);
  293.  
  294.     bin->fsize = avio_size(pb) - 12 - 4096 - 48;
  295.     ff_sauce_read(s, &bin->fsize, &got_width, 0);
  296.     if (!bin->width)
  297.         calculate_height(st->codec, bin->fsize);
  298.     avio_seek(pb, 12, SEEK_SET);
  299.     return 0;
  300. }
  301. #endif /* CONFIG_IDF_DEMUXER */
  302.  
  303. static int read_packet(AVFormatContext *s,
  304.                            AVPacket *pkt)
  305. {
  306.     BinDemuxContext *bin = s->priv_data;
  307.  
  308.     if (bin->fsize > 0) {
  309.         if (av_get_packet(s->pb, pkt, bin->fsize) < 0)
  310.             return AVERROR(EIO);
  311.         bin->fsize = -1; /* done */
  312.     } else if (!bin->fsize) {
  313.         if (url_feof(s->pb))
  314.             return AVERROR(EIO);
  315.         if (av_get_packet(s->pb, pkt, bin->chars_per_frame) < 0)
  316.             return AVERROR(EIO);
  317.     } else {
  318.         return AVERROR(EIO);
  319.     }
  320.  
  321.     pkt->flags |= AV_PKT_FLAG_KEY;
  322.     return 0;
  323. }
  324.  
  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 },
  330.     { NULL },
  331. };
  332.  
  333. #define CLASS(name) \
  334. (const AVClass[1]){{ \
  335.     .class_name     = name, \
  336.     .item_name      = av_default_item_name, \
  337.     .option         = options, \
  338.     .version        = LIBAVUTIL_VERSION_INT, \
  339. }}
  340.  
  341. #if CONFIG_BINTEXT_DEMUXER
  342. AVInputFormat ff_bintext_demuxer = {
  343.     .name           = "bin",
  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,
  348.     .extensions     = "bin",
  349.     .priv_class     = CLASS("Binary text demuxer"),
  350. };
  351. #endif
  352.  
  353. #if CONFIG_XBIN_DEMUXER
  354. AVInputFormat ff_xbin_demuxer = {
  355.     .name           = "xbin",
  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"),
  362. };
  363. #endif
  364.  
  365. #if CONFIG_ADF_DEMUXER
  366. AVInputFormat ff_adf_demuxer = {
  367.     .name           = "adf",
  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,
  372.     .extensions     = "adf",
  373.     .priv_class     = CLASS("Artworx Data Format demuxer"),
  374. };
  375. #endif
  376.  
  377. #if CONFIG_IDF_DEMUXER
  378. AVInputFormat ff_idf_demuxer = {
  379.     .name           = "idf",
  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,
  385.     .extensions     = "idf",
  386.     .priv_class     = CLASS("iCE Draw File demuxer"),
  387. };
  388. #endif
  389.