ffmpeg / libavformat / ffmetadec.c @ f8194672
History | View | Annotate | Download (4.53 KB)
1 |
/*
|
---|---|
2 |
* Metadata demuxer
|
3 |
* Copyright (c) 2010 Anton Khirnov
|
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 |
#include "avformat.h" |
23 |
#include "ffmeta.h" |
24 |
#include "internal.h" |
25 |
|
26 |
static int probe(AVProbeData *p) |
27 |
{ |
28 |
if(!memcmp(p->buf, ID_STRING, strlen(ID_STRING)))
|
29 |
return AVPROBE_SCORE_MAX;
|
30 |
return 0; |
31 |
} |
32 |
|
33 |
static void get_line(ByteIOContext *s, uint8_t *buf, int size) |
34 |
{ |
35 |
do {
|
36 |
uint8_t c; |
37 |
int i = 0; |
38 |
|
39 |
while ((c = get_byte(s))) {
|
40 |
if (c == '\\') { |
41 |
if (i < size - 1) |
42 |
buf[i++] = c; |
43 |
c = get_byte(s); |
44 |
} else if (c == '\n') |
45 |
break;
|
46 |
|
47 |
if (i < size - 1) |
48 |
buf[i++] = c; |
49 |
} |
50 |
buf[i] = 0;
|
51 |
} while (!url_feof(s) && (buf[0] == ';' || buf[0] == '#' || buf[0] == 0)); |
52 |
} |
53 |
|
54 |
static AVChapter *read_chapter(AVFormatContext *s)
|
55 |
{ |
56 |
uint8_t line[256];
|
57 |
int64_t start, end; |
58 |
AVRational tb = {1, 1e9}; |
59 |
|
60 |
get_line(s->pb, line, sizeof(line));
|
61 |
|
62 |
if (sscanf(line, "TIMEBASE=%d/%d", &tb.num, &tb.den)) |
63 |
get_line(s->pb, line, sizeof(line));
|
64 |
if (!sscanf(line, "START=%lld", &start)) { |
65 |
av_log(s, AV_LOG_ERROR, "Expected chapter start timestamp, found %s.\n", line);
|
66 |
start = (s->nb_chapters && s->chapters[s->nb_chapters - 1]->end != AV_NOPTS_VALUE) ?
|
67 |
s->chapters[s->nb_chapters - 1]->end : 0; |
68 |
} else
|
69 |
get_line(s->pb, line, sizeof(line));
|
70 |
|
71 |
if (!sscanf(line, "END=%lld", &end)) { |
72 |
av_log(s, AV_LOG_ERROR, "Expected chapter end timestamp, found %s.\n", line);
|
73 |
end = AV_NOPTS_VALUE; |
74 |
} |
75 |
|
76 |
return ff_new_chapter(s, s->nb_chapters, tb, start, end, NULL); |
77 |
} |
78 |
|
79 |
static uint8_t *unescape(uint8_t *buf, int size) |
80 |
{ |
81 |
uint8_t *ret = av_malloc(size + 1);
|
82 |
uint8_t *p1 = ret, *p2 = buf; |
83 |
|
84 |
if (!ret)
|
85 |
return NULL; |
86 |
|
87 |
while (p2 < buf + size) {
|
88 |
if (*p2 == '\\') |
89 |
p2++; |
90 |
*p1++ = *p2++; |
91 |
} |
92 |
*p1 = 0;
|
93 |
return ret;
|
94 |
} |
95 |
|
96 |
static int read_tag(uint8_t *line, AVMetadata **m) |
97 |
{ |
98 |
uint8_t *key, *value, *p = line; |
99 |
|
100 |
/* find first not escaped '=' */
|
101 |
while (1) { |
102 |
if (*p == '=') |
103 |
break;
|
104 |
else if (*p == '\\') |
105 |
p++; |
106 |
|
107 |
if (*p++)
|
108 |
continue;
|
109 |
|
110 |
return 0; |
111 |
} |
112 |
|
113 |
if (!(key = unescape(line, p - line)))
|
114 |
return AVERROR(ENOMEM);
|
115 |
if (!(value = unescape(p + 1, strlen(p + 1)))) { |
116 |
av_free(key); |
117 |
return AVERROR(ENOMEM);
|
118 |
} |
119 |
|
120 |
av_metadata_set2(m, key, value, AV_METADATA_DONT_STRDUP_KEY | AV_METADATA_DONT_STRDUP_VAL); |
121 |
return 0; |
122 |
} |
123 |
|
124 |
static int read_header(AVFormatContext *s, AVFormatParameters *ap) |
125 |
{ |
126 |
AVMetadata **m = &s->metadata; |
127 |
uint8_t line[1024];
|
128 |
|
129 |
while(!url_feof(s->pb)) {
|
130 |
get_line(s->pb, line, sizeof(line));
|
131 |
|
132 |
if (!memcmp(line, ID_STREAM, strlen(ID_STREAM))) {
|
133 |
AVStream *st = av_new_stream(s, 0);
|
134 |
|
135 |
if (!st)
|
136 |
return -1; |
137 |
|
138 |
st->codec->codec_type = AVMEDIA_TYPE_DATA; |
139 |
st->codec->codec_id = CODEC_ID_FFMETADATA; |
140 |
|
141 |
m = &st->metadata; |
142 |
} else if (!memcmp(line, ID_CHAPTER, strlen(ID_CHAPTER))) { |
143 |
AVChapter *ch = read_chapter(s); |
144 |
|
145 |
if (!ch)
|
146 |
return -1; |
147 |
|
148 |
m = &ch->metadata; |
149 |
} else
|
150 |
read_tag(line, m); |
151 |
} |
152 |
|
153 |
s->start_time = 0;
|
154 |
if (s->nb_chapters)
|
155 |
s->duration = av_rescale_q(s->chapters[s->nb_chapters - 1]->end,
|
156 |
s->chapters[s->nb_chapters - 1]->time_base,
|
157 |
AV_TIME_BASE_Q); |
158 |
|
159 |
return 0; |
160 |
} |
161 |
|
162 |
static int read_packet(AVFormatContext *s, AVPacket *pkt) |
163 |
{ |
164 |
return AVERROR_EOF;
|
165 |
} |
166 |
|
167 |
AVInputFormat ff_ffmetadata_demuxer = { |
168 |
.name = "ffmetadata",
|
169 |
.long_name = NULL_IF_CONFIG_SMALL("FFmpeg metadata in text format"),
|
170 |
.read_probe = probe, |
171 |
.read_header = read_header, |
172 |
.read_packet = read_packet, |
173 |
}; |