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