FFmpeg
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
Examples
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
libavformat
apetag.c
Go to the documentation of this file.
1
/*
2
* APE tag handling
3
* Copyright (c) 2007 Benjamin Zores <ben@geexbox.org>
4
* based upon libdemac from Dave Chapman.
5
*
6
* This file is part of FFmpeg.
7
*
8
* FFmpeg is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public
10
* License as published by the Free Software Foundation; either
11
* version 2.1 of the License, or (at your option) any later version.
12
*
13
* FFmpeg is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
17
*
18
* You should have received a copy of the GNU Lesser General Public
19
* License along with FFmpeg; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
*/
22
23
#include "
libavutil/intreadwrite.h
"
24
#include "
libavutil/dict.h
"
25
#include "
avformat.h
"
26
#include "
avio_internal.h
"
27
#include "
apetag.h
"
28
#include "
internal.h
"
29
30
#define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31)
31
#define APE_TAG_FLAG_CONTAINS_FOOTER (1 << 30)
32
#define APE_TAG_FLAG_IS_HEADER (1 << 29)
33
#define APE_TAG_FLAG_IS_BINARY (1 << 1)
34
35
static
int
ape_tag_read_field
(
AVFormatContext
*
s
)
36
{
37
AVIOContext
*pb = s->
pb
;
38
uint8_t
key[1024], *
value
;
39
uint32_t
size
,
flags
;
40
int
i,
c
;
41
42
size =
avio_rl32
(pb);
/* field size */
43
flags =
avio_rl32
(pb);
/* field flags */
44
for
(i = 0; i <
sizeof
(key) - 1; i++) {
45
c =
avio_r8
(pb);
46
if
(c < 0x20 || c > 0x7E)
47
break
;
48
else
49
key[i] =
c
;
50
}
51
key[i] = 0;
52
if
(c != 0) {
53
av_log
(s,
AV_LOG_WARNING
,
"Invalid APE tag key '%s'.\n"
, key);
54
return
-1;
55
}
56
if
(size >= UINT_MAX)
57
return
-1;
58
if
(flags &
APE_TAG_FLAG_IS_BINARY
) {
59
uint8_t
filename[1024];
60
enum
AVCodecID
id
;
61
AVStream
*st =
avformat_new_stream
(s, NULL);
62
if
(!st)
63
return
AVERROR
(ENOMEM);
64
65
size -=
avio_get_str
(pb, size, filename,
sizeof
(filename));
66
if
(size <= 0) {
67
av_log
(s,
AV_LOG_WARNING
,
"Skipping binary tag '%s'.\n"
, key);
68
return
0;
69
}
70
71
av_dict_set
(&st->
metadata
, key, filename, 0);
72
73
if
((
id
=
ff_guess_image2_codec
(filename)) !=
AV_CODEC_ID_NONE
) {
74
AVPacket
pkt
;
75
int
ret
;
76
77
ret =
av_get_packet
(s->
pb
, &pkt, size);
78
if
(ret < 0) {
79
av_log
(s,
AV_LOG_ERROR
,
"Error reading cover art.\n"
);
80
return
ret
;
81
}
82
83
st->
disposition
|=
AV_DISPOSITION_ATTACHED_PIC
;
84
st->
codec
->
codec_type
=
AVMEDIA_TYPE_VIDEO
;
85
st->
codec
->
codec_id
=
id
;
86
87
st->
attached_pic
=
pkt
;
88
st->
attached_pic
.
stream_index
= st->
index
;
89
st->
attached_pic
.
flags
|=
AV_PKT_FLAG_KEY
;
90
}
else
{
91
if
(
ff_get_extradata
(st->
codec
, s->
pb
, size) < 0)
92
return
AVERROR
(ENOMEM);
93
st->
codec
->
codec_type
=
AVMEDIA_TYPE_ATTACHMENT
;
94
}
95
}
else
{
96
value =
av_malloc
(size+1);
97
if
(!value)
98
return
AVERROR
(ENOMEM);
99
c =
avio_read
(pb, value, size);
100
if
(c < 0) {
101
av_free
(value);
102
return
c
;
103
}
104
value[
c
] = 0;
105
av_dict_set
(&s->
metadata
, key, value,
AV_DICT_DONT_STRDUP_VAL
);
106
}
107
return
0;
108
}
109
110
int64_t
ff_ape_parse_tag
(
AVFormatContext
*
s
)
111
{
112
AVIOContext
*pb = s->
pb
;
113
int64_t file_size =
avio_size
(pb);
114
uint32_t
val
, fields, tag_bytes;
115
uint8_t
buf
[8];
116
int64_t tag_start;
117
int
i;
118
119
if
(file_size <
APE_TAG_FOOTER_BYTES
)
120
return
0;
121
122
avio_seek
(pb, file_size -
APE_TAG_FOOTER_BYTES
, SEEK_SET);
123
124
avio_read
(pb, buf, 8);
/* APETAGEX */
125
if
(strncmp(buf,
APE_TAG_PREAMBLE
, 8)) {
126
return
0;
127
}
128
129
val =
avio_rl32
(pb);
/* APE tag version */
130
if
(val >
APE_TAG_VERSION
) {
131
av_log
(s,
AV_LOG_ERROR
,
"Unsupported tag version. (>=%d)\n"
,
APE_TAG_VERSION
);
132
return
0;
133
}
134
135
tag_bytes =
avio_rl32
(pb);
/* tag size */
136
if
(tag_bytes -
APE_TAG_FOOTER_BYTES
> (1024 * 1024 * 16)) {
137
av_log
(s,
AV_LOG_ERROR
,
"Tag size is way too big\n"
);
138
return
0;
139
}
140
141
if
(tag_bytes > file_size -
APE_TAG_FOOTER_BYTES
) {
142
av_log
(s,
AV_LOG_ERROR
,
"Invalid tag size %u.\n"
, tag_bytes);
143
return
0;
144
}
145
tag_start = file_size - tag_bytes -
APE_TAG_FOOTER_BYTES
;
146
147
fields =
avio_rl32
(pb);
/* number of fields */
148
if
(fields > 65536) {
149
av_log
(s,
AV_LOG_ERROR
,
"Too many tag fields (%d)\n"
, fields);
150
return
0;
151
}
152
153
val =
avio_rl32
(pb);
/* flags */
154
if
(val &
APE_TAG_FLAG_IS_HEADER
) {
155
av_log
(s,
AV_LOG_ERROR
,
"APE Tag is a header\n"
);
156
return
0;
157
}
158
159
avio_seek
(pb, file_size - tag_bytes, SEEK_SET);
160
161
for
(i=0; i<fields; i++)
162
if
(
ape_tag_read_field
(s) < 0)
break
;
163
164
return
tag_start;
165
}
166
167
static
int
string_is_ascii
(
const
uint8_t
*str)
168
{
169
while
(*str && *str >= 0x20 && *str <= 0x7e ) str++;
170
return
!*str;
171
}
172
173
int
ff_ape_write_tag
(
AVFormatContext
*
s
)
174
{
175
AVDictionaryEntry
*e = NULL;
176
int
size
,
ret
,
count
= 0;
177
AVIOContext
*dyn_bc = NULL;
178
uint8_t
*dyn_buf = NULL;
179
180
if
((ret =
avio_open_dyn_buf
(&dyn_bc)) < 0)
181
goto
end
;
182
183
// flags
184
avio_wl32
(dyn_bc,
APE_TAG_FLAG_CONTAINS_HEADER
|
APE_TAG_FLAG_CONTAINS_FOOTER
|
185
APE_TAG_FLAG_IS_HEADER
);
186
ffio_fill
(dyn_bc, 0, 8);
// reserved
187
188
while
((e =
av_dict_get
(s->
metadata
,
""
, e,
AV_DICT_IGNORE_SUFFIX
))) {
189
int
val_len;
190
191
if
(!
string_is_ascii
(e->
key
)) {
192
av_log
(s,
AV_LOG_WARNING
,
"Non ASCII keys are not allowed\n"
);
193
continue
;
194
}
195
196
val_len = strlen(e->
value
);
197
avio_wl32
(dyn_bc, val_len);
// value length
198
avio_wl32
(dyn_bc, 0);
// item flags
199
avio_put_str
(dyn_bc, e->
key
);
// key
200
avio_write
(dyn_bc, e->
value
, val_len);
// value
201
count++;
202
}
203
if
(!count)
204
goto
end
;
205
206
size =
avio_close_dyn_buf
(dyn_bc, &dyn_buf);
207
if
(size <= 0)
208
goto
end
;
209
size += 20;
210
211
// header
212
avio_write
(s->
pb
,
"APETAGEX"
, 8);
// id
213
avio_wl32
(s->
pb
,
APE_TAG_VERSION
);
// version
214
avio_wl32
(s->
pb
, size);
215
avio_wl32
(s->
pb
, count);
216
217
avio_write
(s->
pb
, dyn_buf, size - 20);
218
219
// footer
220
avio_write
(s->
pb
,
"APETAGEX"
, 8);
// id
221
avio_wl32
(s->
pb
,
APE_TAG_VERSION
);
// version
222
avio_wl32
(s->
pb
, size);
// size
223
avio_wl32
(s->
pb
, count);
// tag count
224
225
// flags
226
avio_wl32
(s->
pb
,
APE_TAG_FLAG_CONTAINS_HEADER
|
APE_TAG_FLAG_CONTAINS_FOOTER
);
227
ffio_fill
(s->
pb
, 0, 8);
// reserved
228
229
end
:
230
if
(dyn_bc && !dyn_buf)
231
avio_close_dyn_buf
(dyn_bc, &dyn_buf);
232
av_freep
(&dyn_buf);
233
234
return
ret
;
235
}
Generated on Sun Mar 23 2014 23:50:10 for FFmpeg by
1.8.2