Main Page
Related Pages
Modules
Data Structures
Files
Examples
File List
Globals
libavformat
id3v2enc.c
Go to the documentation of this file.
1
/*
2
* ID3v2 header writer
3
*
4
* This file is part of Libav.
5
*
6
* Libav 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.
10
*
11
* Libav 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.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with Libav; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
*/
20
21
#include <stdint.h>
22
23
#include "
libavutil/dict.h
"
24
#include "
libavutil/intreadwrite.h
"
25
#include "
avformat.h
"
26
#include "
avio.h
"
27
#include "
id3v2.h
"
28
29
static
void
id3v2_put_size
(
AVFormatContext
*s,
int
size
)
30
{
31
avio_w8
(s->
pb
, size >> 21 & 0x7f);
32
avio_w8
(s->
pb
, size >> 14 & 0x7f);
33
avio_w8
(s->
pb
, size >> 7 & 0x7f);
34
avio_w8
(s->
pb
, size & 0x7f);
35
}
36
37
static
int
string_is_ascii
(
const
uint8_t *str)
38
{
39
while
(*str && *str < 128) str++;
40
return
!*str;
41
}
42
48
static
int
id3v2_put_ttag
(
AVFormatContext
*s,
const
char
*str1,
const
char
*str2,
49
uint32_t
tag
,
enum
ID3v2Encoding
enc)
50
{
51
int
len
;
52
uint8_t *pb;
53
int (*
put
)(
AVIOContext
*,
const
char
*);
54
AVIOContext
*dyn_buf;
55
if
(
avio_open_dyn_buf
(&dyn_buf) < 0)
56
return
AVERROR
(ENOMEM);
57
58
/* check if the strings are ASCII-only and use UTF16 only if
59
* they're not */
60
if
(enc ==
ID3v2_ENCODING_UTF16BOM
&&
string_is_ascii
(str1) &&
61
(!str2 ||
string_is_ascii
(str2)))
62
enc =
ID3v2_ENCODING_ISO8859
;
63
64
avio_w8
(dyn_buf, enc);
65
if
(enc ==
ID3v2_ENCODING_UTF16BOM
) {
66
avio_wl16
(dyn_buf, 0xFEFF);
/* BOM */
67
put
=
avio_put_str16le
;
68
}
else
69
put
=
avio_put_str
;
70
71
put
(dyn_buf, str1);
72
if
(str2)
73
put
(dyn_buf, str2);
74
len =
avio_close_dyn_buf
(dyn_buf, &pb);
75
76
avio_wb32
(s->
pb
, tag);
77
id3v2_put_size
(s, len);
78
avio_wb16
(s->
pb
, 0);
79
avio_write
(s->
pb
, pb, len);
80
81
av_freep
(&pb);
82
return
len +
ID3v2_HEADER_SIZE
;
83
}
84
85
static
int
id3v2_check_write_tag
(
AVFormatContext
*s,
AVDictionaryEntry
*
t
,
const
char
table[][4],
86
enum
ID3v2Encoding
enc)
87
{
88
uint32_t
tag
;
89
int
i;
90
91
if
(t->
key
[0] !=
'T'
|| strlen(t->
key
) != 4)
92
return
-1;
93
tag =
AV_RB32
(t->
key
);
94
for
(i = 0; *table[i]; i++)
95
if
(tag ==
AV_RB32
(table[i]))
96
return
id3v2_put_ttag
(s, t->
value
,
NULL
, tag, enc);
97
return
-1;
98
}
99
100
int
ff_id3v2_write
(
struct
AVFormatContext
*s,
int
id3v2_version,
101
const
char
*magic)
102
{
103
int64_t size_pos, cur_pos;
104
AVDictionaryEntry
*
t
=
NULL
;
105
106
int
totlen = 0, enc = id3v2_version == 3 ?
ID3v2_ENCODING_UTF16BOM
:
107
ID3v2_ENCODING_UTF8
;
108
109
110
avio_wb32
(s->
pb
,
MKBETAG
(magic[0], magic[1], magic[2], id3v2_version));
111
avio_w8
(s->
pb
, 0);
112
avio_w8
(s->
pb
, 0);
/* flags */
113
114
/* reserve space for size */
115
size_pos =
avio_tell
(s->
pb
);
116
avio_wb32
(s->
pb
, 0);
117
118
ff_metadata_conv
(&s->
metadata
,
ff_id3v2_34_metadata_conv
,
NULL
);
119
if
(id3v2_version == 4)
120
ff_metadata_conv
(&s->
metadata
,
ff_id3v2_4_metadata_conv
,
NULL
);
121
122
while
((t =
av_dict_get
(s->
metadata
,
""
, t,
AV_DICT_IGNORE_SUFFIX
))) {
123
int
ret;
124
125
if
((ret =
id3v2_check_write_tag
(s, t,
ff_id3v2_tags
, enc)) > 0) {
126
totlen += ret;
127
continue
;
128
}
129
if
((ret =
id3v2_check_write_tag
(s, t, id3v2_version == 3 ?
130
ff_id3v2_3_tags
:
ff_id3v2_4_tags
, enc)) > 0) {
131
totlen += ret;
132
continue
;
133
}
134
135
/* unknown tag, write as TXXX frame */
136
if
((ret =
id3v2_put_ttag
(s, t->
key
, t->
value
,
MKBETAG
(
'T'
,
'X'
,
'X'
,
'X'
), enc)) < 0)
137
return
ret;
138
totlen += ret;
139
}
140
141
cur_pos =
avio_tell
(s->
pb
);
142
avio_seek
(s->
pb
, size_pos, SEEK_SET);
143
id3v2_put_size
(s, totlen);
144
avio_seek
(s->
pb
, cur_pos, SEEK_SET);
145
return
0;
146
}