3 * Copyright (c) 2010 Anton Khirnov
5 * This file is part of Libav.
7 * Libav 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.
12 * Libav 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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "libavutil/mathematics.h"
26 #include "libavutil/dict.h"
28 static int probe(AVProbeData
*p
)
30 if(!memcmp(p
->buf
, ID_STRING
, strlen(ID_STRING
)))
31 return AVPROBE_SCORE_MAX
;
35 static void get_line(AVIOContext
*s
, uint8_t *buf
, int size
)
41 while ((c
= avio_r8(s
))) {
53 } while (!s
->eof_reached
&& (buf
[0] == ';' || buf
[0] == '#' || buf
[0] == 0));
56 static AVChapter
*read_chapter(AVFormatContext
*s
)
60 AVRational tb
= {1, 1e9
};
62 get_line(s
->pb
, line
, sizeof(line
));
64 if (sscanf(line
, "TIMEBASE=%d/%d", &tb
.num
, &tb
.den
))
65 get_line(s
->pb
, line
, sizeof(line
));
66 if (!sscanf(line
, "START=%"SCNd64
, &start
)) {
67 av_log(s
, AV_LOG_ERROR
, "Expected chapter start timestamp, found %s.\n", line
);
68 start
= (s
->nb_chapters
&& s
->chapters
[s
->nb_chapters
- 1]->end
!= AV_NOPTS_VALUE
) ?
69 s
->chapters
[s
->nb_chapters
- 1]->end
: 0;
71 get_line(s
->pb
, line
, sizeof(line
));
73 if (!sscanf(line
, "END=%"SCNd64
, &end
)) {
74 av_log(s
, AV_LOG_ERROR
, "Expected chapter end timestamp, found %s.\n", line
);
78 return avpriv_new_chapter(s
, s
->nb_chapters
, tb
, start
, end
, NULL
);
81 static uint8_t *unescape(uint8_t *buf
, int size
)
83 uint8_t *ret
= av_malloc(size
+ 1);
84 uint8_t *p1
= ret
, *p2
= buf
;
89 while (p2
< buf
+ size
) {
98 static int read_tag(uint8_t *line
, AVDictionary
**m
)
100 uint8_t *key
, *value
, *p
= line
;
102 /* find first not escaped '=' */
115 if (!(key
= unescape(line
, p
- line
)))
116 return AVERROR(ENOMEM
);
117 if (!(value
= unescape(p
+ 1, strlen(p
+ 1)))) {
119 return AVERROR(ENOMEM
);
122 av_dict_set(m
, key
, value
, AV_DICT_DONT_STRDUP_KEY
| AV_DICT_DONT_STRDUP_VAL
);
126 static int read_header(AVFormatContext
*s
)
128 AVDictionary
**m
= &s
->metadata
;
131 while(!s
->pb
->eof_reached
) {
132 get_line(s
->pb
, line
, sizeof(line
));
134 if (!memcmp(line
, ID_STREAM
, strlen(ID_STREAM
))) {
135 AVStream
*st
= avformat_new_stream(s
, NULL
);
140 st
->codec
->codec_type
= AVMEDIA_TYPE_DATA
;
141 st
->codec
->codec_id
= AV_CODEC_ID_FFMETADATA
;
144 } else if (!memcmp(line
, ID_CHAPTER
, strlen(ID_CHAPTER
))) {
145 AVChapter
*ch
= read_chapter(s
);
157 s
->duration
= av_rescale_q(s
->chapters
[s
->nb_chapters
- 1]->end
,
158 s
->chapters
[s
->nb_chapters
- 1]->time_base
,
164 static int read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
169 AVInputFormat ff_ffmetadata_demuxer
= {
170 .name
= "ffmetadata",
171 .long_name
= NULL_IF_CONFIG_SMALL("FFmpeg metadata in text"),
173 .read_header
= read_header
,
174 .read_packet
= read_packet
,