3 * Copyright (c) 2007 Benjamin Zores <ben@geexbox.org>
4 * based upon libdemac from Dave Chapman.
6 * This file is part of Libav.
8 * Libav 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.
13 * Libav 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.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with Libav; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "libavutil/intreadwrite.h"
26 #include "libavutil/dict.h"
28 #include "avio_internal.h"
32 #define APE_TAG_VERSION 2000
33 #define APE_TAG_FOOTER_BYTES 32
34 #define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31)
35 #define APE_TAG_FLAG_CONTAINS_FOOTER (1 << 30)
36 #define APE_TAG_FLAG_IS_HEADER (1 << 29)
37 #define APE_TAG_FLAG_IS_BINARY (1 << 1)
39 static int ape_tag_read_field(AVFormatContext
*s
)
41 AVIOContext
*pb
= s
->pb
;
42 uint8_t key
[1024], *value
;
46 size
= avio_rl32(pb
); /* field size */
47 flags
= avio_rl32(pb
); /* field flags */
48 for (i
= 0; i
< sizeof(key
) - 1; i
++) {
50 if (c
< 0x20 || c
> 0x7E)
57 av_log(s
, AV_LOG_WARNING
, "Invalid APE tag key '%s'.\n", key
);
60 if (size
> INT32_MAX
- FF_INPUT_BUFFER_PADDING_SIZE
) {
61 av_log(s
, AV_LOG_ERROR
, "APE tag size too large.\n");
62 return AVERROR_INVALIDDATA
;
64 if (flags
& APE_TAG_FLAG_IS_BINARY
) {
65 uint8_t filename
[1024];
67 AVStream
*st
= avformat_new_stream(s
, NULL
);
69 return AVERROR(ENOMEM
);
71 size
-= avio_get_str(pb
, size
, filename
, sizeof(filename
));
73 av_log(s
, AV_LOG_WARNING
, "Skipping binary tag '%s'.\n", key
);
77 av_dict_set(&st
->metadata
, key
, filename
, 0);
79 if ((id
= ff_guess_image2_codec(filename
)) != AV_CODEC_ID_NONE
) {
83 ret
= av_get_packet(s
->pb
, &pkt
, size
);
85 av_log(s
, AV_LOG_ERROR
, "Error reading cover art.\n");
89 st
->disposition
|= AV_DISPOSITION_ATTACHED_PIC
;
90 st
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
91 st
->codec
->codec_id
= id
;
93 st
->attached_pic
= pkt
;
94 st
->attached_pic
.stream_index
= st
->index
;
95 st
->attached_pic
.flags
|= AV_PKT_FLAG_KEY
;
97 st
->codec
->extradata
= av_malloc(size
+ FF_INPUT_BUFFER_PADDING_SIZE
);
98 if (!st
->codec
->extradata
)
99 return AVERROR(ENOMEM
);
100 if (avio_read(pb
, st
->codec
->extradata
, size
) != size
) {
101 av_freep(&st
->codec
->extradata
);
104 st
->codec
->extradata_size
= size
;
105 st
->codec
->codec_type
= AVMEDIA_TYPE_ATTACHMENT
;
108 value
= av_malloc(size
+1);
110 return AVERROR(ENOMEM
);
111 c
= avio_read(pb
, value
, size
);
117 av_dict_set(&s
->metadata
, key
, value
, AV_DICT_DONT_STRDUP_VAL
);
122 int64_t ff_ape_parse_tag(AVFormatContext
*s
)
124 AVIOContext
*pb
= s
->pb
;
125 int64_t file_size
= avio_size(pb
);
126 uint32_t val
, fields
, tag_bytes
;
131 if (file_size
< APE_TAG_FOOTER_BYTES
)
134 avio_seek(pb
, file_size
- APE_TAG_FOOTER_BYTES
, SEEK_SET
);
136 avio_read(pb
, buf
, 8); /* APETAGEX */
137 if (strncmp(buf
, "APETAGEX", 8)) {
141 val
= avio_rl32(pb
); /* APE tag version */
142 if (val
> APE_TAG_VERSION
) {
143 av_log(s
, AV_LOG_ERROR
, "Unsupported tag version. (>=%d)\n", APE_TAG_VERSION
);
147 tag_bytes
= avio_rl32(pb
); /* tag size */
148 if (tag_bytes
- APE_TAG_FOOTER_BYTES
> (1024 * 1024 * 16)) {
149 av_log(s
, AV_LOG_ERROR
, "Tag size is way too big\n");
153 if (tag_bytes
> file_size
- APE_TAG_FOOTER_BYTES
) {
154 av_log(s
, AV_LOG_ERROR
, "Invalid tag size %"PRIu32
".\n", tag_bytes
);
157 tag_start
= file_size
- tag_bytes
- APE_TAG_FOOTER_BYTES
;
159 fields
= avio_rl32(pb
); /* number of fields */
160 if (fields
> 65536) {
161 av_log(s
, AV_LOG_ERROR
, "Too many tag fields (%"PRIu32
")\n", fields
);
165 val
= avio_rl32(pb
); /* flags */
166 if (val
& APE_TAG_FLAG_IS_HEADER
) {
167 av_log(s
, AV_LOG_ERROR
, "APE Tag is a header\n");
171 avio_seek(pb
, file_size
- tag_bytes
, SEEK_SET
);
173 for (i
=0; i
<fields
; i
++)
174 if (ape_tag_read_field(s
) < 0) break;
179 int ff_ape_write_tag(AVFormatContext
*s
)
181 AVDictionaryEntry
*e
= NULL
;
185 if (!s
->pb
->seekable
)
188 start
= avio_tell(s
->pb
);
191 avio_write(s
->pb
, "APETAGEX", 8); // id
192 avio_wl32 (s
->pb
, APE_TAG_VERSION
); // version
193 avio_wl32(s
->pb
, 0); // reserve space for size
194 avio_wl32(s
->pb
, 0); // reserve space for tag count
197 avio_wl32(s
->pb
, APE_TAG_FLAG_CONTAINS_HEADER
| APE_TAG_FLAG_CONTAINS_FOOTER
|
198 APE_TAG_FLAG_IS_HEADER
);
199 ffio_fill(s
->pb
, 0, 8); // reserved
201 while ((e
= av_dict_get(s
->metadata
, "", e
, AV_DICT_IGNORE_SUFFIX
))) {
202 int val_len
= strlen(e
->value
);
204 avio_wl32(s
->pb
, val_len
); // value length
205 avio_wl32(s
->pb
, 0); // item flags
206 avio_put_str(s
->pb
, e
->key
); // key
207 avio_write(s
->pb
, e
->value
, val_len
); // value
211 size
= avio_tell(s
->pb
) - start
;
214 avio_write(s
->pb
, "APETAGEX", 8); // id
215 avio_wl32 (s
->pb
, APE_TAG_VERSION
); // version
216 avio_wl32(s
->pb
, size
); // size
217 avio_wl32(s
->pb
, count
); // tag count
220 avio_wl32(s
->pb
, APE_TAG_FLAG_CONTAINS_HEADER
| APE_TAG_FLAG_CONTAINS_FOOTER
);
221 ffio_fill(s
->pb
, 0, 8); // reserved
223 // update values in the header
224 end
= avio_tell(s
->pb
);
225 avio_seek(s
->pb
, start
+ 12, SEEK_SET
);
226 avio_wl32(s
->pb
, size
);
227 avio_wl32(s
->pb
, count
);
228 avio_seek(s
->pb
, end
, SEEK_SET
);