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
st->
codec
->
extradata
=
av_malloc
(size +
FF_INPUT_BUFFER_PADDING_SIZE
);
92
if
(!st->
codec
->
extradata
)
93
return
AVERROR
(ENOMEM);
94
if
(
avio_read
(pb, st->
codec
->
extradata
, size) != size) {
95
av_freep
(&st->
codec
->
extradata
);
96
return
AVERROR
(EIO);
97
}
98
st->
codec
->
extradata_size
=
size
;
99
st->
codec
->
codec_type
=
AVMEDIA_TYPE_ATTACHMENT
;
100
}
101
}
else
{
102
value =
av_malloc
(size+1);
103
if
(!value)
104
return
AVERROR
(ENOMEM);
105
c =
avio_read
(pb, value, size);
106
if
(c < 0) {
107
av_free
(value);
108
return
c
;
109
}
110
value[
c
] = 0;
111
av_dict_set
(&s->
metadata
, key, value,
AV_DICT_DONT_STRDUP_VAL
);
112
}
113
return
0;
114
}
115
116
int64_t
ff_ape_parse_tag
(
AVFormatContext
*
s
)
117
{
118
AVIOContext
*pb = s->
pb
;
119
int64_t file_size =
avio_size
(pb);
120
uint32_t
val
, fields, tag_bytes;
121
uint8_t
buf
[8];
122
int64_t tag_start;
123
int
i;
124
125
if
(file_size <
APE_TAG_FOOTER_BYTES
)
126
return
0;
127
128
avio_seek
(pb, file_size -
APE_TAG_FOOTER_BYTES
, SEEK_SET);
129
130
avio_read
(pb, buf, 8);
/* APETAGEX */
131
if
(strncmp(buf,
APE_TAG_PREAMBLE
, 8)) {
132
return
0;
133
}
134
135
val =
avio_rl32
(pb);
/* APE tag version */
136
if
(val >
APE_TAG_VERSION
) {
137
av_log
(s,
AV_LOG_ERROR
,
"Unsupported tag version. (>=%d)\n"
,
APE_TAG_VERSION
);
138
return
0;
139
}
140
141
tag_bytes =
avio_rl32
(pb);
/* tag size */
142
if
(tag_bytes -
APE_TAG_FOOTER_BYTES
> (1024 * 1024 * 16)) {
143
av_log
(s,
AV_LOG_ERROR
,
"Tag size is way too big\n"
);
144
return
0;
145
}
146
147
if
(tag_bytes > file_size -
APE_TAG_FOOTER_BYTES
) {
148
av_log
(s,
AV_LOG_ERROR
,
"Invalid tag size %u.\n"
, tag_bytes);
149
return
0;
150
}
151
tag_start = file_size - tag_bytes -
APE_TAG_FOOTER_BYTES
;
152
153
fields =
avio_rl32
(pb);
/* number of fields */
154
if
(fields > 65536) {
155
av_log
(s,
AV_LOG_ERROR
,
"Too many tag fields (%d)\n"
, fields);
156
return
0;
157
}
158
159
val =
avio_rl32
(pb);
/* flags */
160
if
(val &
APE_TAG_FLAG_IS_HEADER
) {
161
av_log
(s,
AV_LOG_ERROR
,
"APE Tag is a header\n"
);
162
return
0;
163
}
164
165
avio_seek
(pb, file_size - tag_bytes, SEEK_SET);
166
167
for
(i=0; i<fields; i++)
168
if
(
ape_tag_read_field
(s) < 0)
break
;
169
170
return
tag_start;
171
}
172
173
static
int
string_is_ascii
(
const
uint8_t
*str)
174
{
175
while
(*str && *str >= 0x20 && *str <= 0x7e ) str++;
176
return
!*str;
177
}
178
179
int
ff_ape_write_tag
(
AVFormatContext
*
s
)
180
{
181
AVDictionaryEntry
*e = NULL;
182
int
size
,
ret
,
count
= 0;
183
AVIOContext
*dyn_bc = NULL;
184
uint8_t
*dyn_buf = NULL;
185
186
if
((ret =
avio_open_dyn_buf
(&dyn_bc)) < 0)
187
goto
end
;
188
189
// flags
190
avio_wl32
(dyn_bc,
APE_TAG_FLAG_CONTAINS_HEADER
|
APE_TAG_FLAG_CONTAINS_FOOTER
|
191
APE_TAG_FLAG_IS_HEADER
);
192
ffio_fill
(dyn_bc, 0, 8);
// reserved
193
194
while
((e =
av_dict_get
(s->
metadata
,
""
, e,
AV_DICT_IGNORE_SUFFIX
))) {
195
int
val_len;
196
197
if
(!
string_is_ascii
(e->
key
)) {
198
av_log
(s,
AV_LOG_WARNING
,
"Non ASCII keys are not allowed\n"
);
199
continue
;
200
}
201
202
val_len = strlen(e->
value
);
203
avio_wl32
(dyn_bc, val_len);
// value length
204
avio_wl32
(dyn_bc, 0);
// item flags
205
avio_put_str
(dyn_bc, e->
key
);
// key
206
avio_write
(dyn_bc, e->
value
, val_len);
// value
207
count++;
208
}
209
if
(!count)
210
goto
end
;
211
212
size =
avio_close_dyn_buf
(dyn_bc, &dyn_buf);
213
if
(size <= 0)
214
goto
end
;
215
size += 20;
216
217
// header
218
avio_write
(s->
pb
,
"APETAGEX"
, 8);
// id
219
avio_wl32
(s->
pb
,
APE_TAG_VERSION
);
// version
220
avio_wl32
(s->
pb
, size);
221
avio_wl32
(s->
pb
, count);
222
223
avio_write
(s->
pb
, dyn_buf, size - 20);
224
225
// footer
226
avio_write
(s->
pb
,
"APETAGEX"
, 8);
// id
227
avio_wl32
(s->
pb
,
APE_TAG_VERSION
);
// version
228
avio_wl32
(s->
pb
, size);
// size
229
avio_wl32
(s->
pb
, count);
// tag count
230
231
// flags
232
avio_wl32
(s->
pb
,
APE_TAG_FLAG_CONTAINS_HEADER
|
APE_TAG_FLAG_CONTAINS_FOOTER
);
233
ffio_fill
(s->
pb
, 0, 8);
// reserved
234
235
end
:
236
if
(dyn_bc && !dyn_buf)
237
avio_close_dyn_buf
(dyn_bc, &dyn_buf);
238
av_freep
(&dyn_buf);
239
240
return
ret
;
241
}
Generated on Wed Jul 10 2013 23:48:11 for FFmpeg by
1.8.2