00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00027 #include "avformat.h"
00028 #include "internal.h"
00029 #include "subtitles.h"
00030 #include "libavutil/avstring.h"
00031 #include "libavutil/bprint.h"
00032 #include "libavutil/intreadwrite.h"
00033
00034 typedef struct {
00035 FFDemuxSubtitlesQueue q;
00036 } SubViewerContext;
00037
00038 static int subviewer_probe(AVProbeData *p)
00039 {
00040 char c;
00041 const unsigned char *ptr = p->buf;
00042
00043 if (AV_RB24(ptr) == 0xEFBBBF)
00044 ptr += 3;
00045 if (sscanf(ptr, "%*u:%*u:%*u.%*u,%*u:%*u:%*u.%*u%c", &c) == 1)
00046 return AVPROBE_SCORE_MAX/2;
00047 if (!strncmp(ptr, "[INFORMATION]", 13))
00048 return AVPROBE_SCORE_MAX/3;
00049 return 0;
00050 }
00051
00052 static int read_ts(const char *s, int64_t *start, int *duration)
00053 {
00054 int64_t end;
00055 int hh1, mm1, ss1, ms1;
00056 int hh2, mm2, ss2, ms2;
00057
00058 if (sscanf(s, "%u:%u:%u.%u,%u:%u:%u.%u",
00059 &hh1, &mm1, &ss1, &ms1, &hh2, &mm2, &ss2, &ms2) == 8) {
00060 end = (hh2*3600 + mm2*60 + ss2) * 100 + ms2;
00061 *start = (hh1*3600 + mm1*60 + ss1) * 100 + ms1;
00062 *duration = end - *start;
00063 return 0;
00064 }
00065 return -1;
00066 }
00067
00068 static int subviewer_read_header(AVFormatContext *s)
00069 {
00070 SubViewerContext *subviewer = s->priv_data;
00071 AVStream *st = avformat_new_stream(s, NULL);
00072 AVBPrint header;
00073 int res = 0;
00074
00075 if (!st)
00076 return AVERROR(ENOMEM);
00077 avpriv_set_pts_info(st, 64, 1, 100);
00078 st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
00079 st->codec->codec_id = AV_CODEC_ID_SUBVIEWER;
00080
00081 av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED);
00082
00083 while (!url_feof(s->pb)) {
00084 char line[2048];
00085 const int64_t pos = avio_tell(s->pb);
00086 int len = ff_get_line(s->pb, line, sizeof(line));
00087
00088 if (!len)
00089 break;
00090
00091 if (line[0] == '[' && strncmp(line, "[br]", 4)) {
00092
00093
00094 if (strstr(line, "[COLF]") || strstr(line, "[SIZE]") ||
00095 strstr(line, "[FONT]") || strstr(line, "[STYLE]"))
00096 continue;
00097
00098 if (!st->codec->extradata) {
00099 av_bprintf(&header, "%s", line);
00100 if (!strncmp(line, "[END INFORMATION]", 17) || !strncmp(line, "[SUBTITLE]", 10)) {
00101
00102 av_bprint_finalize(&header, (char **)&st->codec->extradata);
00103 if (!st->codec->extradata) {
00104 res = AVERROR(ENOMEM);
00105 goto end;
00106 }
00107 st->codec->extradata_size = header.len + 1;
00108 } else if (strncmp(line, "[INFORMATION]", 13)) {
00109
00110 int i, j = 0;
00111 char key[32], value[128];
00112
00113 for (i = 1; i < sizeof(key) - 1 && line[i] && line[i] != ']'; i++)
00114 key[i - 1] = av_tolower(line[i]);
00115 key[i - 1] = 0;
00116
00117 if (line[i] == ']')
00118 i++;
00119 while (line[i] == ' ')
00120 i++;
00121 while (j < sizeof(value) - 1 && line[i] && !strchr("]\r\n", line[i]))
00122 value[j++] = line[i++];
00123 value[j] = 0;
00124
00125 av_dict_set(&s->metadata, key, value, 0);
00126 }
00127 }
00128 } else {
00129 int64_t pts_start = AV_NOPTS_VALUE;
00130 int duration = -1;
00131 int timed_line = !read_ts(line, &pts_start, &duration);
00132 AVPacket *sub;
00133
00134 sub = ff_subtitles_queue_insert(&subviewer->q, line, len, !timed_line);
00135 if (!sub) {
00136 res = AVERROR(ENOMEM);
00137 goto end;
00138 }
00139 if (timed_line) {
00140 sub->pos = pos;
00141 sub->pts = pts_start;
00142 sub->duration = duration;
00143 }
00144 }
00145 }
00146
00147 ff_subtitles_queue_finalize(&subviewer->q);
00148
00149 end:
00150 av_bprint_finalize(&header, NULL);
00151 return res;
00152 }
00153
00154 static int subviewer_read_packet(AVFormatContext *s, AVPacket *pkt)
00155 {
00156 SubViewerContext *subviewer = s->priv_data;
00157 return ff_subtitles_queue_read_packet(&subviewer->q, pkt);
00158 }
00159
00160 static int subviewer_read_close(AVFormatContext *s)
00161 {
00162 SubViewerContext *subviewer = s->priv_data;
00163 ff_subtitles_queue_clean(&subviewer->q);
00164 return 0;
00165 }
00166
00167 AVInputFormat ff_subviewer_demuxer = {
00168 .name = "subviewer",
00169 .long_name = NULL_IF_CONFIG_SMALL("SubViewer subtitle format"),
00170 .priv_data_size = sizeof(SubViewerContext),
00171 .read_probe = subviewer_probe,
00172 .read_header = subviewer_read_header,
00173 .read_packet = subviewer_read_packet,
00174 .read_close = subviewer_read_close,
00175 .flags = AVFMT_GENERIC_INDEX,
00176 .extensions = "sub",
00177 };