4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "libavutil/avstring.h"
25 #include "libavutil/dict.h"
26 #include "libavutil/intreadwrite.h"
29 #include "avio_internal.h"
33 static void id3v2_put_size(AVIOContext
*pb
, int size
)
35 avio_w8(pb
, size
>> 21 & 0x7f);
36 avio_w8(pb
, size
>> 14 & 0x7f);
37 avio_w8(pb
, size
>> 7 & 0x7f);
38 avio_w8(pb
, size
& 0x7f);
41 static int string_is_ascii(const uint8_t *str
)
43 while (*str
&& *str
< 128) str
++;
47 static void id3v2_encode_string(AVIOContext
*pb
, const uint8_t *str
,
48 enum ID3v2Encoding enc
)
50 int (*put
)(AVIOContext
*, const char*);
52 if (enc
== ID3v2_ENCODING_UTF16BOM
) {
53 avio_wl16(pb
, 0xFEFF); /* BOM */
54 put
= avio_put_str16le
;
62 * Write a text frame with one (normal frames) or two (TXXX frames) strings
63 * according to encoding (only UTF-8 or UTF-16+BOM supported).
64 * @return number of bytes written or a negative error code.
66 static int id3v2_put_ttag(ID3v2EncContext
*id3
, AVIOContext
*avioc
, const char *str1
, const char *str2
,
67 uint32_t tag
, enum ID3v2Encoding enc
)
72 if ((ret
= avio_open_dyn_buf(&dyn_buf
)) < 0)
75 /* check if the strings are ASCII-only and use UTF16 only if
77 if (enc
== ID3v2_ENCODING_UTF16BOM
&& string_is_ascii(str1
) &&
78 (!str2
|| string_is_ascii(str2
)))
79 enc
= ID3v2_ENCODING_ISO8859
;
81 avio_w8(dyn_buf
, enc
);
82 id3v2_encode_string(dyn_buf
, str1
, enc
);
84 id3v2_encode_string(dyn_buf
, str2
, enc
);
85 len
= avio_get_dyn_buf(dyn_buf
, &pb
);
87 avio_wb32(avioc
, tag
);
88 /* ID3v2.3 frame size is not sync-safe */
89 if (id3
->version
== 3)
90 avio_wb32(avioc
, len
);
92 id3v2_put_size(avioc
, len
);
94 avio_write(avioc
, pb
, len
);
96 ffio_free_dyn_buf(&dyn_buf
);
97 return len
+ ID3v2_HEADER_SIZE
;
101 * Write a priv frame with owner and data. 'key' is the owner prepended with
102 * ID3v2_PRIV_METADATA_PREFIX. 'data' is provided as a string. Any \xXX
103 * (where 'X' is a valid hex digit) will be unescaped to the byte value.
105 static int id3v2_put_priv(ID3v2EncContext
*id3
, AVIOContext
*avioc
, const char *key
, const char *data
)
109 AVIOContext
*dyn_buf
;
111 if (!av_strstart(key
, ID3v2_PRIV_METADATA_PREFIX
, &key
)) {
115 if ((ret
= avio_open_dyn_buf(&dyn_buf
)) < 0)
118 // owner + null byte.
119 avio_write(dyn_buf
, key
, strlen(key
) + 1);
122 if (av_strstart(data
, "\\x", &data
)) {
123 if (data
[0] && data
[1] && av_isxdigit(data
[0]) && av_isxdigit(data
[1])) {
124 char digits
[] = {data
[0], data
[1], 0};
125 avio_w8(dyn_buf
, strtol(digits
, NULL
, 16));
128 ffio_free_dyn_buf(&dyn_buf
);
129 av_log(avioc
, AV_LOG_ERROR
, "Invalid escape '\\x%.2s' in metadata tag '"
130 ID3v2_PRIV_METADATA_PREFIX
"%s'.\n", data
, key
);
131 return AVERROR(EINVAL
);
134 avio_write(dyn_buf
, data
++, 1);
138 len
= avio_get_dyn_buf(dyn_buf
, &pb
);
140 avio_wb32(avioc
, MKBETAG('P', 'R', 'I', 'V'));
141 if (id3
->version
== 3)
142 avio_wb32(avioc
, len
);
144 id3v2_put_size(avioc
, len
);
146 avio_write(avioc
, pb
, len
);
148 ffio_free_dyn_buf(&dyn_buf
);
150 return len
+ ID3v2_HEADER_SIZE
;
153 static int id3v2_check_write_tag(ID3v2EncContext
*id3
, AVIOContext
*pb
, const AVDictionaryEntry
*t
,
154 const char table
[][4], enum ID3v2Encoding enc
)
159 if (t
->key
[0] != 'T' || strlen(t
->key
) != 4)
161 tag
= AV_RB32(t
->key
);
162 for (i
= 0; *table
[i
]; i
++)
163 if (tag
== AV_RB32(table
[i
]))
164 return id3v2_put_ttag(id3
, pb
, t
->value
, NULL
, tag
, enc
);
168 static void id3v2_3_metadata_split_date(AVDictionary
**pm
)
170 const AVDictionaryEntry
*mtag
= NULL
;
171 AVDictionary
*dst
= NULL
;
172 const char *key
, *value
;
173 char year
[5] = {0}, day_month
[5] = {0};
176 while ((mtag
= av_dict_iterate(*pm
, mtag
))) {
178 if (!av_strcasecmp(key
, "date")) {
179 /* split date tag using "YYYY-MM-DD" format into year and month/day segments */
182 while (value
[i
] >= '0' && value
[i
] <= '9') i
++;
183 if (value
[i
] == '\0' || value
[i
] == '-') {
184 av_strlcpy(year
, value
, sizeof(year
));
185 av_dict_set(&dst
, "TYER", year
, 0);
187 if (value
[i
] == '-' &&
188 value
[i
+1] >= '0' && value
[i
+1] <= '1' &&
189 value
[i
+2] >= '0' && value
[i
+2] <= '9' &&
191 value
[i
+4] >= '0' && value
[i
+4] <= '3' &&
192 value
[i
+5] >= '0' && value
[i
+5] <= '9' &&
193 (value
[i
+6] == '\0' || value
[i
+6] == ' ')) {
194 snprintf(day_month
, sizeof(day_month
), "%.2s%.2s", value
+ i
+ 4, value
+ i
+ 1);
195 av_dict_set(&dst
, "TDAT", day_month
, 0);
198 av_dict_set(&dst
, key
, value
, 0);
200 av_dict_set(&dst
, key
, mtag
->value
, 0);
206 void ff_id3v2_start(ID3v2EncContext
*id3
, AVIOContext
*pb
, int id3v2_version
,
209 id3
->version
= id3v2_version
;
211 avio_wb32(pb
, MKBETAG(magic
[0], magic
[1], magic
[2], id3v2_version
));
213 avio_w8(pb
, 0); /* flags */
215 /* reserve space for size */
216 id3
->size_pos
= avio_tell(pb
);
220 static int write_metadata(AVIOContext
*pb
, AVDictionary
**metadata
,
221 ID3v2EncContext
*id3
, int enc
)
223 const AVDictionaryEntry
*t
= NULL
;
226 ff_metadata_conv(metadata
, ff_id3v2_34_metadata_conv
, NULL
);
227 if (id3
->version
== 3)
228 id3v2_3_metadata_split_date(metadata
);
229 else if (id3
->version
== 4)
230 ff_metadata_conv(metadata
, ff_id3v2_4_metadata_conv
, NULL
);
232 while ((t
= av_dict_iterate(*metadata
, t
))) {
233 if ((ret
= id3v2_check_write_tag(id3
, pb
, t
, ff_id3v2_tags
, enc
)) > 0) {
237 if ((ret
= id3v2_check_write_tag(id3
, pb
, t
, id3
->version
== 3 ?
238 ff_id3v2_3_tags
: ff_id3v2_4_tags
, enc
)) > 0) {
243 if ((ret
= id3v2_put_priv(id3
, pb
, t
->key
, t
->value
)) > 0) {
246 } else if (ret
< 0) {
250 /* unknown tag, write as TXXX frame */
251 if ((ret
= id3v2_put_ttag(id3
, pb
, t
->key
, t
->value
, MKBETAG('T', 'X', 'X', 'X'), enc
)) < 0)
259 static int write_ctoc(AVFormatContext
*s
, ID3v2EncContext
*id3
, int enc
)
266 if (s
->nb_chapters
== 0)
269 if ((ret
= avio_open_dyn_buf(&dyn_bc
)) < 0)
272 avio_put_str(dyn_bc
, "toc");
273 avio_w8(dyn_bc
, 0x03);
274 avio_w8(dyn_bc
, s
->nb_chapters
);
275 for (int i
= 0; i
< s
->nb_chapters
; i
++) {
276 snprintf(name
, 122, "ch%d", i
);
277 avio_put_str(dyn_bc
, name
);
279 len
= avio_get_dyn_buf(dyn_bc
, &dyn_buf
);
280 id3
->len
+= len
+ ID3v2_HEADER_SIZE
;
282 avio_wb32(s
->pb
, MKBETAG('C', 'T', 'O', 'C'));
283 avio_wb32(s
->pb
, len
);
285 avio_write(s
->pb
, dyn_buf
, len
);
287 ffio_free_dyn_buf(&dyn_bc
);
292 static int write_chapter(AVFormatContext
*s
, ID3v2EncContext
*id3
, int id
, int enc
)
294 const AVRational time_base
= {1, 1000};
295 AVChapter
*ch
= s
->chapters
[id
];
299 int len
, start
, end
, ret
;
301 if ((ret
= avio_open_dyn_buf(&dyn_bc
)) < 0)
304 start
= av_rescale_q(ch
->start
, ch
->time_base
, time_base
);
305 end
= av_rescale_q(ch
->end
, ch
->time_base
, time_base
);
307 snprintf(name
, 122, "ch%d", id
);
308 id3
->len
+= avio_put_str(dyn_bc
, name
);
309 avio_wb32(dyn_bc
, start
);
310 avio_wb32(dyn_bc
, end
);
311 avio_wb32(dyn_bc
, 0xFFFFFFFFu
);
312 avio_wb32(dyn_bc
, 0xFFFFFFFFu
);
314 if ((ret
= write_metadata(dyn_bc
, &ch
->metadata
, id3
, enc
)) < 0)
317 len
= avio_get_dyn_buf(dyn_bc
, &dyn_buf
);
318 id3
->len
+= 16 + ID3v2_HEADER_SIZE
;
320 avio_wb32(s
->pb
, MKBETAG('C', 'H', 'A', 'P'));
321 avio_wb32(s
->pb
, len
);
323 avio_write(s
->pb
, dyn_buf
, len
);
326 ffio_free_dyn_buf(&dyn_bc
);
331 int ff_id3v2_write_metadata(AVFormatContext
*s
, ID3v2EncContext
*id3
)
333 int enc
= id3
->version
== 3 ? ID3v2_ENCODING_UTF16BOM
:
337 ff_standardize_creation_time(s
);
338 if ((ret
= write_metadata(s
->pb
, &s
->metadata
, id3
, enc
)) < 0)
341 if ((ret
= write_ctoc(s
, id3
, enc
)) < 0)
344 for (i
= 0; i
< s
->nb_chapters
; i
++) {
345 if ((ret
= write_chapter(s
, id3
, i
, enc
)) < 0)
352 int ff_id3v2_write_apic(AVFormatContext
*s
, ID3v2EncContext
*id3
, AVPacket
*pkt
)
354 AVStream
*st
= s
->streams
[pkt
->stream_index
];
355 AVDictionaryEntry
*e
;
357 AVIOContext
*dyn_buf
;
359 const CodecMime
*mime
= ff_id3v2_mime_tags
;
360 const char *mimetype
= NULL
, *desc
= "";
361 int enc
= id3
->version
== 3 ? ID3v2_ENCODING_UTF16BOM
:
363 int i
, len
, type
= 0, ret
;
365 /* get the mimetype*/
366 while (mime
->id
!= AV_CODEC_ID_NONE
) {
367 if (mime
->id
== st
->codecpar
->codec_id
) {
368 mimetype
= mime
->str
;
374 av_log(s
, AV_LOG_ERROR
, "No mimetype is known for stream %d, cannot "
375 "write an attached picture.\n", st
->index
);
376 return AVERROR(EINVAL
);
379 /* get the picture type */
380 e
= av_dict_get(st
->metadata
, "comment", NULL
, 0);
381 for (i
= 0; e
&& i
< FF_ARRAY_ELEMS(ff_id3v2_picture_types
); i
++) {
382 if (!av_strcasecmp(e
->value
, ff_id3v2_picture_types
[i
])) {
388 /* get the description */
389 if ((e
= av_dict_get(st
->metadata
, "title", NULL
, 0)))
392 /* use UTF16 only for non-ASCII strings */
393 if (enc
== ID3v2_ENCODING_UTF16BOM
&& string_is_ascii(desc
))
394 enc
= ID3v2_ENCODING_ISO8859
;
397 if ((ret
= avio_open_dyn_buf(&dyn_buf
)) < 0)
400 avio_w8(dyn_buf
, enc
);
401 avio_put_str(dyn_buf
, mimetype
);
402 avio_w8(dyn_buf
, type
);
403 id3v2_encode_string(dyn_buf
, desc
, enc
);
404 avio_write(dyn_buf
, pkt
->data
, pkt
->size
);
405 len
= avio_get_dyn_buf(dyn_buf
, &buf
);
407 avio_wb32(s
->pb
, MKBETAG('A', 'P', 'I', 'C'));
408 if (id3
->version
== 3)
409 avio_wb32(s
->pb
, len
);
411 id3v2_put_size(s
->pb
, len
);
413 avio_write(s
->pb
, buf
, len
);
414 ffio_free_dyn_buf(&dyn_buf
);
416 id3
->len
+= len
+ ID3v2_HEADER_SIZE
;
421 void ff_id3v2_finish(ID3v2EncContext
*id3
, AVIOContext
*pb
,
426 if (padding_bytes
< 0)
429 /* The ID3v2.3 specification states that 28 bits are used to represent the
430 * size of the whole tag. Therefore the current size of the tag needs to be
431 * subtracted from the upper limit of 2^28-1 to clip the value correctly. */
432 /* The minimum of 10 is an arbitrary amount of padding at the end of the tag
433 * to fix cover art display with some software such as iTunes, Traktor,
435 padding_bytes
= av_clip(padding_bytes
, 10, 268435455 - id3
->len
);
436 ffio_fill(pb
, 0, padding_bytes
);
437 id3
->len
+= padding_bytes
;
439 cur_pos
= avio_tell(pb
);
440 avio_seek(pb
, id3
->size_pos
, SEEK_SET
);
441 id3v2_put_size(pb
, id3
->len
);
442 avio_seek(pb
, cur_pos
, SEEK_SET
);
445 int ff_id3v2_write_simple(struct AVFormatContext
*s
, int id3v2_version
,
448 ID3v2EncContext id3
= { 0 };
451 ff_id3v2_start(&id3
, s
->pb
, id3v2_version
, magic
);
452 if ((ret
= ff_id3v2_write_metadata(s
, &id3
)) < 0)
454 ff_id3v2_finish(&id3
, s
->pb
, s
->metadata_header_padding
);