FFmpeg
Main Page
Related Pages
Modules
Data Structures
Files
Examples
File List
Globals
All
Data Structures
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 "
apetag.h
"
27
#include "
internal.h
"
28
29
#define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31)
30
#define APE_TAG_FLAG_IS_HEADER (1 << 29)
31
#define APE_TAG_FLAG_IS_BINARY (1 << 1)
32
33
static
int
ape_tag_read_field
(
AVFormatContext
*s)
34
{
35
AVIOContext
*pb = s->
pb
;
36
uint8_t
key[1024], *
value
;
37
uint32_t
size
,
flags
;
38
int
i,
c
;
39
40
size =
avio_rl32
(pb);
/* field size */
41
flags =
avio_rl32
(pb);
/* field flags */
42
for
(i = 0; i <
sizeof
(key) - 1; i++) {
43
c =
avio_r8
(pb);
44
if
(c < 0x20 || c > 0x7E)
45
break
;
46
else
47
key[i] =
c
;
48
}
49
key[i] = 0;
50
if
(c != 0) {
51
av_log
(s,
AV_LOG_WARNING
,
"Invalid APE tag key '%s'.\n"
, key);
52
return
-1;
53
}
54
if
(size >= UINT_MAX)
55
return
-1;
56
if
(flags &
APE_TAG_FLAG_IS_BINARY
) {
57
uint8_t
filename[1024];
58
enum
AVCodecID
id
;
59
AVStream
*st =
avformat_new_stream
(s,
NULL
);
60
if
(!st)
61
return
AVERROR
(ENOMEM);
62
63
size -=
avio_get_str
(pb, size, filename,
sizeof
(filename));
64
if
(size <= 0) {
65
av_log
(s,
AV_LOG_WARNING
,
"Skipping binary tag '%s'.\n"
, key);
66
return
0;
67
}
68
69
av_dict_set
(&st->
metadata
, key, filename, 0);
70
71
if
((
id
=
ff_guess_image2_codec
(filename)) !=
AV_CODEC_ID_NONE
) {
72
AVPacket
pkt
;
73
int
ret;
74
75
ret =
av_get_packet
(s->
pb
, &pkt, size);
76
if
(ret < 0) {
77
av_log
(s,
AV_LOG_ERROR
,
"Error reading cover art.\n"
);
78
return
ret;
79
}
80
81
st->
disposition
|=
AV_DISPOSITION_ATTACHED_PIC
;
82
st->
codec
->
codec_type
=
AVMEDIA_TYPE_VIDEO
;
83
st->
codec
->
codec_id
=
id
;
84
85
st->
attached_pic
=
pkt
;
86
st->
attached_pic
.
stream_index
= st->
index
;
87
st->
attached_pic
.
flags
|=
AV_PKT_FLAG_KEY
;
88
}
else
{
89
st->
codec
->
extradata
=
av_malloc
(size +
FF_INPUT_BUFFER_PADDING_SIZE
);
90
if
(!st->
codec
->
extradata
)
91
return
AVERROR
(ENOMEM);
92
if
(
avio_read
(pb, st->
codec
->
extradata
, size) != size) {
93
av_freep
(&st->
codec
->
extradata
);
94
return
AVERROR
(EIO);
95
}
96
st->
codec
->
extradata_size
=
size
;
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
int
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 %u.\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 (%d)\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
}
Generated on Sat May 25 2013 04:01:16 for FFmpeg by
1.8.2