00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00027 #include "libavutil/intreadwrite.h"
00028 #include "libavutil/avstring.h"
00029 #include "avformat.h"
00030 #include "sauce.h"
00031
00032 #define LINE_RATE 6000
00033
00034 typedef struct {
00035 int chars_per_frame;
00036 uint64_t fsize;
00037 } TtyDemuxContext;
00038
00042 static int efi_read(AVFormatContext *avctx, uint64_t start_pos)
00043 {
00044 TtyDemuxContext *s = avctx->priv_data;
00045 AVIOContext *pb = avctx->pb;
00046 char buf[37];
00047 int len;
00048
00049 avio_seek(pb, start_pos, SEEK_SET);
00050 if (avio_r8(pb) != 0x1A)
00051 return -1;
00052
00053 #define GET_EFI_META(name,size) \
00054 len = avio_r8(pb); \
00055 if (len < 1 || len > size) \
00056 return -1; \
00057 if (avio_read(pb, buf, size) == size) { \
00058 buf[len] = 0; \
00059 av_metadata_set2(&avctx->metadata, name, buf, 0); \
00060 }
00061
00062 GET_EFI_META("filename", 12)
00063 GET_EFI_META("title", 36)
00064
00065 s->fsize = start_pos;
00066 return 0;
00067 }
00068
00069 static int read_header(AVFormatContext *avctx,
00070 AVFormatParameters *ap)
00071 {
00072 TtyDemuxContext *s = avctx->priv_data;
00073 AVStream *st = av_new_stream(avctx, 0);
00074 if (!st)
00075 return AVERROR(ENOMEM);
00076 st->codec->codec_tag = 0;
00077 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00078 st->codec->codec_id = CODEC_ID_ANSI;
00079 if (ap->width) st->codec->width = ap->width;
00080 if (ap->height) st->codec->height = ap->height;
00081
00082 if (!ap->time_base.num) {
00083 av_set_pts_info(st, 60, 1, 25);
00084 } else {
00085 av_set_pts_info(st, 60, ap->time_base.num, ap->time_base.den);
00086 }
00087
00088
00089 s->chars_per_frame = FFMAX(av_q2d(st->time_base) * (ap->sample_rate ? ap->sample_rate : LINE_RATE), 1);
00090
00091 if (!url_is_streamed(avctx->pb)) {
00092 s->fsize = avio_size(avctx->pb);
00093 st->duration = (s->fsize + s->chars_per_frame - 1) / s->chars_per_frame;
00094
00095 if (ff_sauce_read(avctx, &s->fsize, 0, 0) < 0)
00096 efi_read(avctx, s->fsize - 51);
00097
00098 avio_seek(avctx->pb, 0, SEEK_SET);
00099 }
00100
00101 return 0;
00102 }
00103
00104 static int read_packet(AVFormatContext *avctx, AVPacket *pkt)
00105 {
00106 TtyDemuxContext *s = avctx->priv_data;
00107 int n;
00108
00109 if (url_feof(avctx->pb))
00110 return AVERROR_EOF;
00111
00112 n = s->chars_per_frame;
00113 if (s->fsize) {
00114
00115 uint64_t p = avio_tell(avctx->pb);
00116 if (p + s->chars_per_frame > s->fsize)
00117 n = s->fsize - p;
00118 }
00119
00120 pkt->size = av_get_packet(avctx->pb, pkt, n);
00121 if (pkt->size <= 0)
00122 return AVERROR(EIO);
00123 pkt->flags |= AV_PKT_FLAG_KEY;
00124 return 0;
00125 }
00126
00127 AVInputFormat ff_tty_demuxer = {
00128 .name = "tty",
00129 .long_name = NULL_IF_CONFIG_SMALL("Tele-typewriter"),
00130 .priv_data_size = sizeof(TtyDemuxContext),
00131 .read_header = read_header,
00132 .read_packet = read_packet,
00133 .extensions = "ans,art,asc,diz,ice,nfo,txt,vt",
00134 };