3 * Copyright (c) 2009 James Darnley
5 * This file is part of FFmpeg.
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.
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.
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
25 #include "vorbiscomment.h"
26 #include "libavutil/dict.h"
29 * VorbisComment metadata conversion mapping.
30 * from Ogg Vorbis I format specification: comment field and header specification
31 * http://xiph.org/vorbis/doc/v-comment.html
33 const AVMetadataConv ff_vorbiscomment_metadata_conv
[] = {
34 { "ALBUMARTIST", "album_artist"},
35 { "TRACKNUMBER", "track" },
36 { "DISCNUMBER", "disc" },
37 { "DESCRIPTION", "comment" },
41 int64_t ff_vorbiscomment_length(const AVDictionary
*m
, const char *vendor_string
,
42 AVChapter
**chapters
, unsigned int nb_chapters
)
45 len
+= strlen(vendor_string
);
46 if (chapters
&& nb_chapters
) {
47 for (int i
= 0; i
< nb_chapters
; i
++) {
48 const AVDictionaryEntry
*tag
= NULL
;
49 len
+= 4 + 12 + 1 + 10;
50 while ((tag
= av_dict_iterate(chapters
[i
]->metadata
, tag
))) {
51 int64_t len1
= !strcmp(tag
->key
, "title") ? 4 : strlen(tag
->key
);
52 len
+= 4 + 10 + len1
+ 1 + strlen(tag
->value
);
57 const AVDictionaryEntry
*tag
= NULL
;
58 while ((tag
= av_dict_iterate(m
, tag
))) {
59 len
+= 4 +strlen(tag
->key
) + 1 + strlen(tag
->value
);
65 int ff_vorbiscomment_write(AVIOContext
*pb
, const AVDictionary
*m
,
66 const char *vendor_string
,
67 AVChapter
**chapters
, unsigned int nb_chapters
)
69 size_t vendor_string_length
= strlen(vendor_string
);
71 avio_wl32(pb
, vendor_string_length
);
72 avio_write(pb
, vendor_string
, vendor_string_length
);
73 if (chapters
&& nb_chapters
) {
74 for (int i
= 0; i
< nb_chapters
; i
++) {
75 cm_count
+= av_dict_count(chapters
[i
]->metadata
) + 1;
79 int count
= av_dict_count(m
) + cm_count
;
80 const AVDictionaryEntry
*tag
= NULL
;
82 while ((tag
= av_dict_iterate(m
, tag
))) {
83 int64_t len1
= strlen(tag
->key
);
84 int64_t len2
= strlen(tag
->value
);
85 if (len1
+1+len2
> UINT32_MAX
)
86 return AVERROR(EINVAL
);
87 avio_wl32(pb
, len1
+ 1 + len2
);
88 avio_write(pb
, tag
->key
, len1
);
90 avio_write(pb
, tag
->value
, len2
);
92 for (int i
= 0; i
< nb_chapters
; i
++) {
93 AVChapter
*chp
= chapters
[i
];
94 char chapter_time
[13];
95 char chapter_number
[4];
98 s
= av_rescale(chp
->start
, chp
->time_base
.num
, chp
->time_base
.den
);
101 ms
= av_rescale_q(chp
->start
, chp
->time_base
, av_make_q( 1, 1000)) % 1000;
103 snprintf(chapter_number
, sizeof(chapter_number
), "%03d", i
);
104 snprintf(chapter_time
, sizeof(chapter_time
), "%02d:%02d:%02d.%03d", h
, m
, s
, ms
);
105 avio_wl32(pb
, 10 + 1 + 12);
106 avio_write(pb
, "CHAPTER", 7);
107 avio_write(pb
, chapter_number
, 3);
109 avio_write(pb
, chapter_time
, 12);
112 while ((tag
= av_dict_iterate(chapters
[i
]->metadata
, tag
))) {
113 int64_t len1
= !strcmp(tag
->key
, "title") ? 4 : strlen(tag
->key
);
114 int64_t len2
= strlen(tag
->value
);
115 if (len1
+1+len2
+10 > UINT32_MAX
)
116 return AVERROR(EINVAL
);
117 avio_wl32(pb
, 10 + len1
+ 1 + len2
);
118 avio_write(pb
, "CHAPTER", 7);
119 avio_write(pb
, chapter_number
, 3);
120 if (!strcmp(tag
->key
, "title"))
121 avio_write(pb
, "NAME", 4);
123 avio_write(pb
, tag
->key
, len1
);
125 avio_write(pb
, tag
->value
, len2
);