00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "avformat.h"
00023 #include "ffmeta.h"
00024
00025 static int probe(AVProbeData *p)
00026 {
00027 if(!memcmp(p->buf, ID_STRING, strlen(ID_STRING)))
00028 return AVPROBE_SCORE_MAX;
00029 return 0;
00030 }
00031
00032 static void get_line(ByteIOContext *s, uint8_t *buf, int size)
00033 {
00034 do {
00035 uint8_t c;
00036 int i = 0;
00037
00038 while ((c = get_byte(s))) {
00039 if (c == '\\') {
00040 if (i < size - 1)
00041 buf[i++] = c;
00042 c = get_byte(s);
00043 } else if (c == '\n')
00044 break;
00045
00046 if (i < size - 1)
00047 buf[i++] = c;
00048 }
00049 buf[i] = 0;
00050 } while (!url_feof(s) && (buf[0] == ';' || buf[0] == '#' || buf[0] == 0));
00051 }
00052
00053 static AVChapter *read_chapter(AVFormatContext *s)
00054 {
00055 uint8_t line[256];
00056 int64_t start, end;
00057 AVRational tb = {1, 1e9};
00058
00059 get_line(s->pb, line, sizeof(line));
00060
00061 if (sscanf(line, "TIMEBASE=%d/%d", &tb.num, &tb.den))
00062 get_line(s->pb, line, sizeof(line));
00063 if (!sscanf(line, "START=%lld", &start)) {
00064 av_log(s, AV_LOG_ERROR, "Expected chapter start timestamp, found %s.\n", line);
00065 start = (s->nb_chapters && s->chapters[s->nb_chapters - 1]->end != AV_NOPTS_VALUE) ?
00066 s->chapters[s->nb_chapters - 1]->end : 0;
00067 } else
00068 get_line(s->pb, line, sizeof(line));
00069
00070 if (!sscanf(line, "END=%lld", &end)) {
00071 av_log(s, AV_LOG_ERROR, "Expected chapter end timestamp, found %s.\n", line);
00072 end = AV_NOPTS_VALUE;
00073 }
00074
00075 return ff_new_chapter(s, s->nb_chapters, tb, start, end, NULL);
00076 }
00077
00078 static uint8_t *unescape(uint8_t *buf, int size)
00079 {
00080 uint8_t *ret = av_malloc(size + 1);
00081 uint8_t *p1 = ret, *p2 = buf;
00082
00083 if (!ret)
00084 return NULL;
00085
00086 while (p2 < buf + size) {
00087 if (*p2 == '\\')
00088 p2++;
00089 *p1++ = *p2++;
00090 }
00091 *p1 = 0;
00092 return ret;
00093 }
00094
00095 static int read_tag(uint8_t *line, AVMetadata **m)
00096 {
00097 uint8_t *key, *value, *p = line;
00098
00099
00100 while (1) {
00101 if (*p == '=')
00102 break;
00103 else if (*p == '\\')
00104 p++;
00105
00106 if (*p++)
00107 continue;
00108
00109 return 0;
00110 }
00111
00112 if (!(key = unescape(line, p - line)))
00113 return AVERROR(ENOMEM);
00114 if (!(value = unescape(p + 1, strlen(p + 1)))) {
00115 av_free(key);
00116 return AVERROR(ENOMEM);
00117 }
00118
00119 av_metadata_set2(m, key, value, AV_METADATA_DONT_STRDUP_KEY | AV_METADATA_DONT_STRDUP_VAL);
00120 return 0;
00121 }
00122
00123 static int read_header(AVFormatContext *s, AVFormatParameters *ap)
00124 {
00125 AVMetadata **m = &s->metadata;
00126 uint8_t line[1024];
00127
00128 while(!url_feof(s->pb)) {
00129 get_line(s->pb, line, sizeof(line));
00130
00131 if (!memcmp(line, ID_STREAM, strlen(ID_STREAM))) {
00132 AVStream *st = av_new_stream(s, 0);
00133
00134 if (!st)
00135 return -1;
00136
00137 st->codec->codec_type = AVMEDIA_TYPE_DATA;
00138 st->codec->codec_id = CODEC_ID_FFMETADATA;
00139
00140 m = &st->metadata;
00141 } else if (!memcmp(line, ID_CHAPTER, strlen(ID_CHAPTER))) {
00142 AVChapter *ch = read_chapter(s);
00143
00144 if (!ch)
00145 return -1;
00146
00147 m = &ch->metadata;
00148 } else
00149 read_tag(line, m);
00150 }
00151
00152 s->start_time = 0;
00153 if (s->nb_chapters)
00154 s->duration = av_rescale_q(s->chapters[s->nb_chapters - 1]->end,
00155 s->chapters[s->nb_chapters - 1]->time_base,
00156 AV_TIME_BASE_Q);
00157
00158 return 0;
00159 }
00160
00161 static int read_packet(AVFormatContext *s, AVPacket *pkt)
00162 {
00163 return AVERROR_EOF;
00164 }
00165
00166 AVInputFormat ffmetadata_demuxer = {
00167 .name = "ffmetadata",
00168 .long_name = NULL_IF_CONFIG_SMALL("FFmpeg metadata in text format"),
00169 .read_probe = probe,
00170 .read_header = read_header,
00171 .read_packet = read_packet,
00172 };