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 <inttypes.h>
24
25
#include "
libavutil/intreadwrite.h
"
26
#include "
libavutil/dict.h
"
27
#include "
avformat.h
"
28
#include "
avio_internal.h
"
29
#include "
apetag.h
"
30
#include "
internal.h
"
31
32
#define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31)
33
#define APE_TAG_FLAG_CONTAINS_FOOTER (1 << 30)
34
#define APE_TAG_FLAG_IS_HEADER (1 << 29)
35
#define APE_TAG_FLAG_IS_BINARY (1 << 1)
36
37
static
int
ape_tag_read_field
(
AVFormatContext
*
s
)
38
{
39
AVIOContext
*pb = s->
pb
;
40
uint8_t
key[1024], *
value
;
41
uint32_t
size
,
flags
;
42
int
i,
c
;
43
44
size =
avio_rl32
(pb);
/* field size */
45
flags =
avio_rl32
(pb);
/* field flags */
46
for
(i = 0; i <
sizeof
(key) - 1; i++) {
47
c =
avio_r8
(pb);
48
if
(c < 0x20 || c > 0x7E)
49
break
;
50
else
51
key[i] =
c
;
52
}
53
key[i] = 0;
54
if
(c != 0) {
55
av_log
(s,
AV_LOG_WARNING
,
"Invalid APE tag key '%s'.\n"
, key);
56
return
-1;
57
}
58
if
(size >= UINT_MAX)
59
return
-1;
60
if
(flags &
APE_TAG_FLAG_IS_BINARY
) {
61
uint8_t
filename[1024];
62
enum
AVCodecID
id
;
63
AVStream
*st =
avformat_new_stream
(s, NULL);
64
if
(!st)
65
return
AVERROR
(ENOMEM);
66
67
size -=
avio_get_str
(pb, size, filename,
sizeof
(filename));
68
if
(size <= 0) {
69
av_log
(s,
AV_LOG_WARNING
,
"Skipping binary tag '%s'.\n"
, key);
70
return
0;
71
}
72
73
av_dict_set
(&st->
metadata
, key, filename, 0);
74
75
if
((
id
=
ff_guess_image2_codec
(filename)) !=
AV_CODEC_ID_NONE
) {
76
AVPacket
pkt
;
77
int
ret
;
78
79
ret =
av_get_packet
(s->
pb
, &pkt, size);
80
if
(ret < 0) {
81
av_log
(s,
AV_LOG_ERROR
,
"Error reading cover art.\n"
);
82
return
ret
;
83
}
84
85
st->
disposition
|=
AV_DISPOSITION_ATTACHED_PIC
;
86
st->
codec
->
codec_type
=
AVMEDIA_TYPE_VIDEO
;
87
st->
codec
->
codec_id
=
id
;
88
89
st->
attached_pic
=
pkt
;
90
st->
attached_pic
.
stream_index
= st->
index
;
91
st->
attached_pic
.
flags
|=
AV_PKT_FLAG_KEY
;
92
}
else
{
93
if
(
ff_get_extradata
(st->
codec
, s->
pb
, size) < 0)
94
return
AVERROR
(ENOMEM);
95
st->
codec
->
codec_type
=
AVMEDIA_TYPE_ATTACHMENT
;
96
}
97
}
else
{
98
value =
av_malloc
(size+1);
99
if
(!value)
100
return
AVERROR
(ENOMEM);
101
c =
avio_read
(pb, value, size);
102
if
(c < 0) {
103
av_free
(value);
104
return
c
;
105
}
106
value[
c
] = 0;
107
av_dict_set
(&s->
metadata
, key, value,
AV_DICT_DONT_STRDUP_VAL
);
108
}
109
return
0;
110
}
111
112
int64_t
ff_ape_parse_tag
(
AVFormatContext
*
s
)
113
{
114
AVIOContext
*pb = s->
pb
;
115
int64_t file_size =
avio_size
(pb);
116
uint32_t
val
, fields, tag_bytes;
117
uint8_t
buf
[8];
118
int64_t tag_start;
119
int
i;
120
121
if
(file_size <
APE_TAG_FOOTER_BYTES
)
122
return
0;
123
124
avio_seek
(pb, file_size -
APE_TAG_FOOTER_BYTES
, SEEK_SET);
125
126
avio_read
(pb, buf, 8);
/* APETAGEX */
127
if
(strncmp(buf,
APE_TAG_PREAMBLE
, 8)) {
128
return
0;
129
}
130
131
val =
avio_rl32
(pb);
/* APE tag version */
132
if
(val >
APE_TAG_VERSION
) {
133
av_log
(s,
AV_LOG_ERROR
,
"Unsupported tag version. (>=%d)\n"
,
APE_TAG_VERSION
);
134
return
0;
135
}
136
137
tag_bytes =
avio_rl32
(pb);
/* tag size */
138
if
(tag_bytes -
APE_TAG_FOOTER_BYTES
> (1024 * 1024 * 16)) {
139
av_log
(s,
AV_LOG_ERROR
,
"Tag size is way too big\n"
);
140
return
0;
141
}
142
143
if
(tag_bytes > file_size -
APE_TAG_FOOTER_BYTES
) {
144
av_log
(s,
AV_LOG_ERROR
,
"Invalid tag size %"
PRIu32
".\n"
, tag_bytes);
145
return
0;
146
}
147
tag_start = file_size - tag_bytes -
APE_TAG_FOOTER_BYTES
;
148
149
fields =
avio_rl32
(pb);
/* number of fields */
150
if
(fields > 65536) {
151
av_log
(s,
AV_LOG_ERROR
,
"Too many tag fields (%"
PRIu32
")\n"
, fields);
152
return
0;
153
}
154
155
val =
avio_rl32
(pb);
/* flags */
156
if
(val &
APE_TAG_FLAG_IS_HEADER
) {
157
av_log
(s,
AV_LOG_ERROR
,
"APE Tag is a header\n"
);
158
return
0;
159
}
160
161
avio_seek
(pb, file_size - tag_bytes, SEEK_SET);
162
163
for
(i=0; i<fields; i++)
164
if
(
ape_tag_read_field
(s) < 0)
break
;
165
166
return
tag_start;
167
}
168
169
static
int
string_is_ascii
(
const
uint8_t
*str)
170
{
171
while
(*str && *str >= 0x20 && *str <= 0x7e ) str++;
172
return
!*str;
173
}
174
175
int
ff_ape_write_tag
(
AVFormatContext
*
s
)
176
{
177
AVDictionaryEntry
*e = NULL;
178
int
size
,
ret
,
count
= 0;
179
AVIOContext
*dyn_bc = NULL;
180
uint8_t
*dyn_buf = NULL;
181
182
if
((ret =
avio_open_dyn_buf
(&dyn_bc)) < 0)
183
goto
end
;
184
185
// flags
186
avio_wl32
(dyn_bc,
APE_TAG_FLAG_CONTAINS_HEADER
|
APE_TAG_FLAG_CONTAINS_FOOTER
|
187
APE_TAG_FLAG_IS_HEADER
);
188
ffio_fill
(dyn_bc, 0, 8);
// reserved
189
190
while
((e =
av_dict_get
(s->
metadata
,
""
, e,
AV_DICT_IGNORE_SUFFIX
))) {
191
int
val_len;
192
193
if
(!
string_is_ascii
(e->
key
)) {
194
av_log
(s,
AV_LOG_WARNING
,
"Non ASCII keys are not allowed\n"
);
195
continue
;
196
}
197
198
val_len = strlen(e->
value
);
199
avio_wl32
(dyn_bc, val_len);
// value length
200
avio_wl32
(dyn_bc, 0);
// item flags
201
avio_put_str
(dyn_bc, e->
key
);
// key
202
avio_write
(dyn_bc, e->
value
, val_len);
// value
203
count++;
204
}
205
if
(!count)
206
goto
end
;
207
208
size =
avio_close_dyn_buf
(dyn_bc, &dyn_buf);
209
if
(size <= 0)
210
goto
end
;
211
size += 20;
212
213
// header
214
avio_write
(s->
pb
,
"APETAGEX"
, 8);
// id
215
avio_wl32
(s->
pb
,
APE_TAG_VERSION
);
// version
216
avio_wl32
(s->
pb
, size);
217
avio_wl32
(s->
pb
, count);
218
219
avio_write
(s->
pb
, dyn_buf, size - 20);
220
221
// footer
222
avio_write
(s->
pb
,
"APETAGEX"
, 8);
// id
223
avio_wl32
(s->
pb
,
APE_TAG_VERSION
);
// version
224
avio_wl32
(s->
pb
, size);
// size
225
avio_wl32
(s->
pb
, count);
// tag count
226
227
// flags
228
avio_wl32
(s->
pb
,
APE_TAG_FLAG_CONTAINS_HEADER
|
APE_TAG_FLAG_CONTAINS_FOOTER
);
229
ffio_fill
(s->
pb
, 0, 8);
// reserved
230
231
end
:
232
if
(dyn_bc && !dyn_buf)
233
avio_close_dyn_buf
(dyn_bc, &dyn_buf);
234
av_freep
(&dyn_buf);
235
236
return
ret
;
237
}
Generated on Sun Jul 20 2014 23:06:02 for FFmpeg by
1.8.2