FFmpeg
Loading...
Searching...
No Matches
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/dict.h"
26#include "libavutil/mem.h"
27#include "avformat.h"
28#include "avio_internal.h"
29#include "apetag.h"
30#include "demux.h"
31#include "internal.h"
32#include "mux.h"
33
34#define APE_TAG_FLAG_CONTAINS_HEADER (1U << 31)
35#define APE_TAG_FLAG_LACKS_FOOTER (1 << 30)
36#define APE_TAG_FLAG_IS_HEADER (1 << 29)
37#define APE_TAG_FLAG_IS_BINARY (1 << 1)
38
40{
41 AVIOContext *pb = s->pb;
42 uint8_t key[1024], *value;
44 int i, c;
45
46 size = avio_rl32(pb); /* field size */
47 flags = avio_rl32(pb); /* field flags */
48 for (i = 0; i < sizeof(key) - 1; i++) {
49 c = avio_r8(pb);
50 if (c < 0x20 || c > 0x7E)
51 break;
52 else
53 key[i] = c;
54 }
55 key[i] = 0;
56 if (c != 0) {
57 av_log(s, AV_LOG_WARNING, "Invalid APE tag key '%s'.\n", key);
58 return -1;
59 }
60 if (size > INT32_MAX - AV_INPUT_BUFFER_PADDING_SIZE) {
61 av_log(s, AV_LOG_ERROR, "APE tag size too large.\n");
63 }
65 uint8_t filename[1024];
66 enum AVCodecID id;
67 int ret;
69 if (!st)
70 return AVERROR(ENOMEM);
71
72 ret = avio_get_str(pb, size, filename, sizeof(filename));
73 if (ret < 0)
74 return ret;
75 if (size <= ret) {
76 av_log(s, AV_LOG_WARNING, "Skipping binary tag '%s'.\n", key);
77 return 0;
78 }
79 size -= ret;
80
81 av_dict_set(&st->metadata, key, filename, 0);
82
83 if ((id = ff_guess_image2_codec(filename)) != AV_CODEC_ID_NONE) {
84 ret = ff_add_attached_pic(s, st, s->pb, NULL, size);
85 if (ret < 0) {
86 av_log(s, AV_LOG_ERROR, "Error reading cover art.\n");
87 return ret;
88 }
89 st->codecpar->codec_id = id;
90 } else {
91 if ((ret = ff_get_extradata(s, st->codecpar, s->pb, size)) < 0)
92 return ret;
94 }
95 } else {
96 value = av_malloc(size+1);
97 if (!value)
98 return AVERROR(ENOMEM);
99 c = avio_read(pb, value, size);
100 if (c < 0) {
101 av_free(value);
102 return c;
103 }
104 value[c] = 0;
106 }
107 return 0;
108}
109
111{
112 AVIOContext *pb = s->pb;
113 int64_t file_size = avio_size(pb);
114 uint32_t val, fields, tag_bytes;
115 uint8_t buf[8];
116 int64_t tag_start;
117 int i;
118
119 if (file_size < APE_TAG_FOOTER_BYTES)
120 return 0;
121
122 avio_seek(pb, file_size - APE_TAG_FOOTER_BYTES, SEEK_SET);
123
124 if(avio_read(pb, buf, 8) != 8) /* APETAGEX */
125 return 0;
126 if (strncmp(buf, APE_TAG_PREAMBLE, 8)) {
127 return 0;
128 }
129
130 val = avio_rl32(pb); /* APE tag version */
131 if (val > APE_TAG_VERSION) {
132 av_log(s, AV_LOG_ERROR, "Unsupported tag version. (>=%d)\n", APE_TAG_VERSION);
133 return 0;
134 }
135
136 tag_bytes = avio_rl32(pb); /* tag size */
137 if (tag_bytes - APE_TAG_FOOTER_BYTES > (1024 * 1024 * 16)) {
138 av_log(s, AV_LOG_ERROR, "Tag size is way too big\n");
139 return 0;
140 }
141
142 if (tag_bytes > file_size - APE_TAG_FOOTER_BYTES) {
143 av_log(s, AV_LOG_ERROR, "Invalid tag size %"PRIu32".\n", tag_bytes);
144 return 0;
145 }
146
147 fields = avio_rl32(pb); /* number of fields */
148 if (fields > 65536) {
149 av_log(s, AV_LOG_ERROR, "Too many tag fields (%"PRIu32")\n", fields);
150 return 0;
151 }
152
153 val = avio_rl32(pb); /* flags */
155 av_log(s, AV_LOG_ERROR, "APE Tag is a header\n");
156 return 0;
157 }
158
159 avio_seek(pb, file_size - tag_bytes, SEEK_SET);
160
162 tag_bytes += APE_TAG_HEADER_BYTES;
163
164 tag_start = file_size - tag_bytes;
165
166 for (i=0; i<fields; i++)
167 if (ape_tag_read_field(s) < 0) break;
168
169 return tag_start;
170}
171
172static int string_is_ascii(const uint8_t *str)
173{
174 while (*str && *str >= 0x20 && *str <= 0x7e ) str++;
175 return !*str;
176}
177
179{
180 const AVDictionaryEntry *e = NULL;
181 int size, ret, count = 0;
182 AVIOContext *dyn_bc;
183 uint8_t *dyn_buf;
184
185 if ((ret = avio_open_dyn_buf(&dyn_bc)) < 0)
186 return ret;
187
189 while ((e = av_dict_iterate(s->metadata, e))) {
190 int val_len;
191
192 if (!string_is_ascii(e->key)) {
193 av_log(s, AV_LOG_WARNING, "Non ASCII keys are not allowed\n");
194 continue;
195 }
196
197 val_len = strlen(e->value);
198 avio_wl32(dyn_bc, val_len); // value length
199 avio_wl32(dyn_bc, 0); // item flags
200 avio_put_str(dyn_bc, e->key); // key
201 avio_write(dyn_bc, e->value, val_len); // value
202 count++;
203 }
204 if (!count)
205 goto end;
206
207 size = avio_get_dyn_buf(dyn_bc, &dyn_buf);
208 if (size <= 0)
209 goto end;
211
212 // header
213 avio_write(s->pb, "APETAGEX", 8); // id
214 avio_wl32(s->pb, APE_TAG_VERSION); // version
215 avio_wl32(s->pb, size);
216 avio_wl32(s->pb, count);
217
218 // flags
220 ffio_fill(s->pb, 0, 8); // reserved
221
222 avio_write(s->pb, dyn_buf, size - APE_TAG_FOOTER_BYTES);
223
224 // footer
225 avio_write(s->pb, "APETAGEX", 8); // id
226 avio_wl32(s->pb, APE_TAG_VERSION); // version
227 avio_wl32(s->pb, size); // size
228 avio_wl32(s->pb, count); // tag count
229
230 // flags
232 ffio_fill(s->pb, 0, 8); // reserved
233
234end:
235 ffio_free_dyn_buf(&dyn_bc);
236
237 return ret;
238}
static double val(void *priv, double ch)
Definition aeval.c:77
static int ape_tag_read_field(AVFormatContext *s)
Definition apetag.c:39
int64_t ff_ape_parse_tag(AVFormatContext *s)
Read and parse an APE tag.
Definition apetag.c:110
#define APE_TAG_FLAG_IS_BINARY
Definition apetag.c:37
int ff_ape_write_tag(AVFormatContext *s)
Write an APE tag into a file.
Definition apetag.c:178
static int string_is_ascii(const uint8_t *str)
Definition apetag.c:172
#define APE_TAG_FLAG_IS_HEADER
Definition apetag.c:36
#define APE_TAG_FLAG_CONTAINS_HEADER
Definition apetag.c:34
#define APE_TAG_VERSION
Definition apetag.h:29
#define APE_TAG_PREAMBLE
Definition apetag.h:28
#define APE_TAG_HEADER_BYTES
Definition apetag.h:31
#define APE_TAG_FOOTER_BYTES
Definition apetag.h:30
Main libavformat public API header.
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition aviobuf.c:236
void avio_wl32(AVIOContext *s, unsigned int val)
Definition aviobuf.c:360
int avio_put_str(AVIOContext *s, const char *str)
Write a NULL-terminated string.
Definition aviobuf.c:376
int64_t avio_size(AVIOContext *s)
Get the filesize.
Definition aviobuf.c:326
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition aviobuf.c:615
unsigned int avio_rl32(AVIOContext *s)
Definition aviobuf.c:733
int avio_get_str(AVIOContext *pb, int maxlen, char *buf, int buflen)
Read a string from pb into buf.
Definition aviobuf.c:869
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition aviobuf.c:206
int avio_open_dyn_buf(AVIOContext **s)
Open a write only memory stream.
Definition aviobuf.c:1365
int avio_r8(AVIOContext *s)
Definition aviobuf.c:606
int avio_get_dyn_buf(AVIOContext *s, uint8_t **pbuffer)
Return the written size and a pointer to the buffer.
Definition aviobuf.c:1377
void ffio_free_dyn_buf(AVIOContext **s)
Free a dynamic buffer.
Definition aviobuf.c:1438
void ffio_fill(AVIOContext *s, int b, int64_t count)
Definition aviobuf.c:192
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
int ff_get_extradata(void *logctx, AVCodecParameters *par, AVIOContext *pb, int size)
Allocate extradata with additional AV_INPUT_BUFFER_PADDING_SIZE at end which is always set to 0 and f...
int ff_add_attached_pic(AVFormatContext *s, AVStream *st, AVIOContext *pb, AVBufferRef **buf, int size)
Add an attached pic to an AVStream.
Public dictionary API.
enum AVCodecID id
Definition dts2pts.c:607
double value
Definition eval.c:102
const char * key
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition codec_id.h:47
@ AV_CODEC_ID_NONE
Definition codec_id.h:48
#define AV_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding.
Definition defs.h:40
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
const AVDictionaryEntry * av_dict_iterate(const AVDictionary *m, const AVDictionaryEntry *prev)
Iterate over a dictionary.
Definition dict.c:42
#define AV_DICT_DONT_STRDUP_VAL
Take ownership of a value that's been allocated with av_malloc() or another memory allocation functio...
Definition dict.h:79
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition dict.c:86
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
@ AVMEDIA_TYPE_ATTACHMENT
Opaque data information usually sparse.
Definition avutil.h:204
enum AVCodecID ff_guess_image2_codec(const char *filename)
Definition img2.c:126
Memory handling functions.
int ff_standardize_creation_time(AVFormatContext *s)
Standardize creation_time metadata in AVFormatContext to an ISO-8601 timestamp string.
Definition mux_utils.c:154
#define av_malloc(s)
Definition ops_static.c:52
enum AVMediaType codec_type
General type of the encoded data.
Definition codec_par.h:53
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition codec_par.h:57
char * key
Definition dict.h:91
char * value
Definition dict.h:92
Format I/O context.
Definition avformat.h:1333
Bytestream IO Context.
Definition avio.h:160
Stream structure.
Definition avformat.h:766
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition avformat.h:789
AVDictionary * metadata
Definition avformat.h:846
#define av_free(p)
#define av_log(a,...)
int size
static double c[64]