Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * Tele-typewriter demuxer
  3.  * Copyright (c) 2010 Peter Ross <pross@xvid.org>
  4.  *
  5.  * This file is part of FFmpeg.
  6.  *
  7.  * FFmpeg is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * FFmpeg is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with FFmpeg; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20.  */
  21.  
  22. /**
  23.  * @file
  24.  * Tele-typewriter demuxer
  25.  */
  26.  
  27. #include "libavutil/intreadwrite.h"
  28. #include "libavutil/avstring.h"
  29. #include "libavutil/log.h"
  30. #include "libavutil/dict.h"
  31. #include "libavutil/opt.h"
  32. #include "libavutil/parseutils.h"
  33. #include "avformat.h"
  34. #include "internal.h"
  35. #include "sauce.h"
  36.  
  37. typedef struct {
  38.     AVClass *class;
  39.     int chars_per_frame;
  40.     uint64_t fsize;  /**< file size less metadata buffer */
  41.     int width, height; /**< Set by a private option. */
  42.     AVRational framerate; /**< Set by a private option. */
  43. } TtyDemuxContext;
  44.  
  45. /**
  46.  * Parse EFI header
  47.  */
  48. static int efi_read(AVFormatContext *avctx, uint64_t start_pos)
  49. {
  50.     TtyDemuxContext *s = avctx->priv_data;
  51.     AVIOContext *pb = avctx->pb;
  52.     char buf[37];
  53.     int len;
  54.  
  55.     avio_seek(pb, start_pos, SEEK_SET);
  56.     if (avio_r8(pb) != 0x1A)
  57.         return -1;
  58.  
  59. #define GET_EFI_META(name,size) \
  60.     len = avio_r8(pb); \
  61.     if (len < 1 || len > size) \
  62.         return -1; \
  63.     if (avio_read(pb, buf, size) == size) { \
  64.         buf[len] = 0; \
  65.         av_dict_set(&avctx->metadata, name, buf, 0); \
  66.     }
  67.  
  68.     GET_EFI_META("filename", 12)
  69.     GET_EFI_META("title",    36)
  70.  
  71.     s->fsize = start_pos;
  72.     return 0;
  73. }
  74.  
  75. static int read_header(AVFormatContext *avctx)
  76. {
  77.     TtyDemuxContext *s = avctx->priv_data;
  78.     int ret = 0;
  79.     AVStream *st = avformat_new_stream(avctx, NULL);
  80.  
  81.     if (!st) {
  82.         ret = AVERROR(ENOMEM);
  83.         goto fail;
  84.     }
  85.     st->codec->codec_tag   = 0;
  86.     st->codec->codec_type  = AVMEDIA_TYPE_VIDEO;
  87.     st->codec->codec_id    = AV_CODEC_ID_ANSI;
  88.  
  89.     st->codec->width  = s->width;
  90.     st->codec->height = s->height;
  91.     avpriv_set_pts_info(st, 60, s->framerate.den, s->framerate.num);
  92.     st->avg_frame_rate = s->framerate;
  93.  
  94.     /* simulate tty display speed */
  95.     s->chars_per_frame = FFMAX(av_q2d(st->time_base)*s->chars_per_frame, 1);
  96.  
  97.     if (avctx->pb->seekable) {
  98.         s->fsize = avio_size(avctx->pb);
  99.         st->duration = (s->fsize + s->chars_per_frame - 1) / s->chars_per_frame;
  100.  
  101.         if (ff_sauce_read(avctx, &s->fsize, 0, 0) < 0)
  102.             efi_read(avctx, s->fsize - 51);
  103.  
  104.         avio_seek(avctx->pb, 0, SEEK_SET);
  105.     }
  106.  
  107. fail:
  108.     return ret;
  109. }
  110.  
  111. static int read_packet(AVFormatContext *avctx, AVPacket *pkt)
  112. {
  113.     TtyDemuxContext *s = avctx->priv_data;
  114.     int n;
  115.  
  116.     if (url_feof(avctx->pb))
  117.         return AVERROR_EOF;
  118.  
  119.     n = s->chars_per_frame;
  120.     if (s->fsize) {
  121.         // ignore metadata buffer
  122.         uint64_t p = avio_tell(avctx->pb);
  123.         if (p == s->fsize)
  124.             return AVERROR_EOF;
  125.         if (p + s->chars_per_frame > s->fsize)
  126.             n = s->fsize - p;
  127.     }
  128.  
  129.     pkt->size = av_get_packet(avctx->pb, pkt, n);
  130.     if (pkt->size < 0)
  131.         return pkt->size;
  132.     pkt->flags |= AV_PKT_FLAG_KEY;
  133.     return 0;
  134. }
  135.  
  136. #define OFFSET(x) offsetof(TtyDemuxContext, x)
  137. #define DEC AV_OPT_FLAG_DECODING_PARAM
  138. static const AVOption options[] = {
  139.     { "chars_per_frame", "", offsetof(TtyDemuxContext, chars_per_frame), AV_OPT_TYPE_INT, {.i64 = 6000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM},
  140.     { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
  141.     { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, DEC },
  142.     { NULL },
  143. };
  144.  
  145. static const AVClass tty_demuxer_class = {
  146.     .class_name     = "TTY demuxer",
  147.     .item_name      = av_default_item_name,
  148.     .option         = options,
  149.     .version        = LIBAVUTIL_VERSION_INT,
  150. };
  151.  
  152. AVInputFormat ff_tty_demuxer = {
  153.     .name           = "tty",
  154.     .long_name      = NULL_IF_CONFIG_SMALL("Tele-typewriter"),
  155.     .priv_data_size = sizeof(TtyDemuxContext),
  156.     .read_header    = read_header,
  157.     .read_packet    = read_packet,
  158.     .extensions     = "ans,art,asc,diz,ice,nfo,txt,vt",
  159.     .priv_class     = &tty_demuxer_class,
  160. };
  161.