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