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