• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * VorbisComment writer
3  * Copyright (c) 2009 James Darnley
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 "avio.h"
23 #include "avformat.h"
24 #include "metadata.h"
25 #include "vorbiscomment.h"
26 #include "libavutil/dict.h"
27 
28 /**
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
32  */
33 const AVMetadataConv ff_vorbiscomment_metadata_conv[] = {
34     { "ALBUMARTIST", "album_artist"},
35     { "TRACKNUMBER", "track"  },
36     { "DISCNUMBER",  "disc"   },
37     { "DESCRIPTION", "comment" },
38     { 0 }
39 };
40 
ff_vorbiscomment_length(const AVDictionary * m,const char * vendor_string,AVChapter ** chapters,unsigned int nb_chapters)41 int64_t ff_vorbiscomment_length(const AVDictionary *m, const char *vendor_string,
42                                 AVChapter **chapters, unsigned int nb_chapters)
43 {
44     int64_t len = 8;
45     len += strlen(vendor_string);
46     if (chapters && nb_chapters) {
47         for (int i = 0; i < nb_chapters; i++) {
48             AVDictionaryEntry *tag = NULL;
49             len += 4 + 12 + 1 + 10;
50             while ((tag = av_dict_get(chapters[i]->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
51                 int64_t len1 = !strcmp(tag->key, "title") ? 4 : strlen(tag->key);
52                 len += 4 + 10 + len1 + 1 + strlen(tag->value);
53             }
54         }
55     }
56     if (m) {
57         AVDictionaryEntry *tag = NULL;
58         while ((tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) {
59             len += 4 +strlen(tag->key) + 1 + strlen(tag->value);
60         }
61     }
62     return len;
63 }
64 
ff_vorbiscomment_write(AVIOContext * pb,const AVDictionary * m,const char * vendor_string,AVChapter ** chapters,unsigned int nb_chapters)65 int ff_vorbiscomment_write(AVIOContext *pb, const AVDictionary *m,
66                            const char *vendor_string,
67                            AVChapter **chapters, unsigned int nb_chapters)
68 {
69     size_t vendor_string_length = strlen(vendor_string);
70     int cm_count = 0;
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;
76         }
77     }
78     if (m) {
79         int count = av_dict_count(m) + cm_count;
80         AVDictionaryEntry *tag = NULL;
81         avio_wl32(pb, count);
82         while ((tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) {
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);
89             avio_w8(pb, '=');
90             avio_write(pb, tag->value, len2);
91         }
92         for (int i = 0; i < nb_chapters; i++) {
93             AVChapter *chp = chapters[i];
94             char chapter_time[13];
95             char chapter_number[4];
96             int h, m, s, ms;
97 
98             s  = av_rescale(chp->start, chp->time_base.num, chp->time_base.den);
99             h  = s / 3600;
100             m  = (s / 60) % 60;
101             ms = av_rescale_q(chp->start, chp->time_base, av_make_q(   1, 1000)) % 1000;
102             s  = s % 60;
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);
108             avio_w8(pb, '=');
109             avio_write(pb, chapter_time, 12);
110 
111             tag = NULL;
112             while ((tag = av_dict_get(chapters[i]->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
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);
122                 else
123                     avio_write(pb, tag->key, len1);
124                 avio_w8(pb, '=');
125                 avio_write(pb, tag->value, len2);
126             }
127         }
128     } else
129         avio_wl32(pb, 0);
130     return 0;
131 }
132