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