id3v2enc.c
Go to the documentation of this file.
1 /*
2  * ID3v2 header writer
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <stdint.h>
22 #include <string.h>
23 
24 #include "libavutil/avstring.h"
25 #include "libavutil/dict.h"
26 #include "libavutil/intreadwrite.h"
27 #include "avformat.h"
28 #include "avio.h"
29 #include "id3v2.h"
30 
31 static void id3v2_put_size(AVIOContext *pb, int size)
32 {
33  avio_w8(pb, size >> 21 & 0x7f);
34  avio_w8(pb, size >> 14 & 0x7f);
35  avio_w8(pb, size >> 7 & 0x7f);
36  avio_w8(pb, size & 0x7f);
37 }
38 
39 static int string_is_ascii(const uint8_t *str)
40 {
41  while (*str && *str < 128) str++;
42  return !*str;
43 }
44 
45 static void id3v2_encode_string(AVIOContext *pb, const uint8_t *str,
46  enum ID3v2Encoding enc)
47 {
48  int (*put)(AVIOContext*, const char*);
49 
50  if (enc == ID3v2_ENCODING_UTF16BOM) {
51  avio_wl16(pb, 0xFEFF); /* BOM */
53  } else
54  put = avio_put_str;
55 
56  put(pb, str);
57 }
58 
59 /**
60  * Write a text frame with one (normal frames) or two (TXXX frames) strings
61  * according to encoding (only UTF-8 or UTF-16+BOM supported).
62  * @return number of bytes written or a negative error code.
63  */
64 static int id3v2_put_ttag(ID3v2EncContext *id3, AVIOContext *avioc, const char *str1, const char *str2,
65  uint32_t tag, enum ID3v2Encoding enc)
66 {
67  int len;
68  uint8_t *pb;
69  AVIOContext *dyn_buf;
70  if (avio_open_dyn_buf(&dyn_buf) < 0)
71  return AVERROR(ENOMEM);
72 
73  /* check if the strings are ASCII-only and use UTF16 only if
74  * they're not */
75  if (enc == ID3v2_ENCODING_UTF16BOM && string_is_ascii(str1) &&
76  (!str2 || string_is_ascii(str2)))
78 
79  avio_w8(dyn_buf, enc);
80  id3v2_encode_string(dyn_buf, str1, enc);
81  if (str2)
82  id3v2_encode_string(dyn_buf, str2, enc);
83  len = avio_close_dyn_buf(dyn_buf, &pb);
84 
85  avio_wb32(avioc, tag);
86  /* ID3v2.3 frame size is not synchsafe */
87  if (id3->version == 3)
88  avio_wb32(avioc, len);
89  else
90  id3v2_put_size(avioc, len);
91  avio_wb16(avioc, 0);
92  avio_write(avioc, pb, len);
93 
94  av_freep(&pb);
95  return len + ID3v2_HEADER_SIZE;
96 }
97 
99  const char table[][4], enum ID3v2Encoding enc)
100 {
101  uint32_t tag;
102  int i;
103 
104  if (t->key[0] != 'T' || strlen(t->key) != 4)
105  return -1;
106  tag = AV_RB32(t->key);
107  for (i = 0; *table[i]; i++)
108  if (tag == AV_RB32(table[i]))
109  return id3v2_put_ttag(id3, pb, t->value, NULL, tag, enc);
110  return -1;
111 }
112 
114 {
115  AVDictionaryEntry *mtag = NULL;
116  AVDictionary *dst = NULL;
117  const char *key, *value;
118  char year[5] = {0}, day_month[5] = {0};
119  int i;
120 
121  while ((mtag = av_dict_get(*pm, "", mtag, AV_DICT_IGNORE_SUFFIX))) {
122  key = mtag->key;
123  if (!av_strcasecmp(key, "date")) {
124  /* split date tag using "YYYY-MM-DD" format into year and month/day segments */
125  value = mtag->value;
126  i = 0;
127  while (value[i] >= '0' && value[i] <= '9') i++;
128  if (value[i] == '\0' || value[i] == '-') {
129  av_strlcpy(year, value, sizeof(year));
130  av_dict_set(&dst, "TYER", year, 0);
131 
132  if (value[i] == '-' &&
133  value[i+1] >= '0' && value[i+1] <= '1' &&
134  value[i+2] >= '0' && value[i+2] <= '9' &&
135  value[i+3] == '-' &&
136  value[i+4] >= '0' && value[i+4] <= '3' &&
137  value[i+5] >= '0' && value[i+5] <= '9' &&
138  (value[i+6] == '\0' || value[i+6] == ' ')) {
139  snprintf(day_month, sizeof(day_month), "%.2s%.2s", value + i + 4, value + i + 1);
140  av_dict_set(&dst, "TDAT", day_month, 0);
141  }
142  } else
143  av_dict_set(&dst, key, value, 0);
144  } else
145  av_dict_set(&dst, key, mtag->value, 0);
146  }
147  av_dict_free(pm);
148  *pm = dst;
149 }
150 
151 void ff_id3v2_start(ID3v2EncContext *id3, AVIOContext *pb, int id3v2_version,
152  const char *magic)
153 {
154  id3->version = id3v2_version;
155 
156  avio_wb32(pb, MKBETAG(magic[0], magic[1], magic[2], id3v2_version));
157  avio_w8(pb, 0);
158  avio_w8(pb, 0); /* flags */
159 
160  /* reserve space for size */
161  id3->size_pos = avio_tell(pb);
162  avio_wb32(pb, 0);
163 }
164 
166 {
168  int enc = id3->version == 3 ? ID3v2_ENCODING_UTF16BOM :
170 
172  if (id3->version == 3)
174  else if (id3->version == 4)
176 
177  while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
178  int ret;
179 
180  if ((ret = id3v2_check_write_tag(id3, s->pb, t, ff_id3v2_tags, enc)) > 0) {
181  id3->len += ret;
182  continue;
183  }
184  if ((ret = id3v2_check_write_tag(id3, s->pb, t, id3->version == 3 ?
185  ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) {
186  id3->len += ret;
187  continue;
188  }
189 
190  /* unknown tag, write as TXXX frame */
191  if ((ret = id3v2_put_ttag(id3, s->pb, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0)
192  return ret;
193  id3->len += ret;
194  }
195 
196  return 0;
197 }
198 
200 {
201  AVStream *st = s->streams[pkt->stream_index];
203 
204  AVIOContext *dyn_buf;
205  uint8_t *buf;
206  const CodecMime *mime = ff_id3v2_mime_tags;
207  const char *mimetype = NULL, *desc = "";
208  int enc = id3->version == 3 ? ID3v2_ENCODING_UTF16BOM :
210  int i, len, type = 0;
211 
212  /* get the mimetype*/
213  while (mime->id != AV_CODEC_ID_NONE) {
214  if (mime->id == st->codec->codec_id) {
215  mimetype = mime->str;
216  break;
217  }
218  mime++;
219  }
220  if (!mimetype) {
221  av_log(s, AV_LOG_ERROR, "No mimetype is known for stream %d, cannot "
222  "write an attached picture.\n", st->index);
223  return AVERROR(EINVAL);
224  }
225 
226  /* get the picture type */
227  e = av_dict_get(st->metadata, "comment", NULL, 0);
228  for (i = 0; e && i < FF_ARRAY_ELEMS(ff_id3v2_picture_types); i++) {
229  if (strstr(ff_id3v2_picture_types[i], e->value) == ff_id3v2_picture_types[i]) {
230  type = i;
231  break;
232  }
233  }
234 
235  /* get the description */
236  if ((e = av_dict_get(st->metadata, "title", NULL, 0)))
237  desc = e->value;
238 
239  /* start writing */
240  if (avio_open_dyn_buf(&dyn_buf) < 0)
241  return AVERROR(ENOMEM);
242 
243  avio_w8(dyn_buf, enc);
244  avio_put_str(dyn_buf, mimetype);
245  avio_w8(dyn_buf, type);
246  id3v2_encode_string(dyn_buf, desc, enc);
247  avio_write(dyn_buf, pkt->data, pkt->size);
248  len = avio_close_dyn_buf(dyn_buf, &buf);
249 
250  avio_wb32(s->pb, MKBETAG('A', 'P', 'I', 'C'));
251  if (id3->version == 3)
252  avio_wb32(s->pb, len);
253  else
254  id3v2_put_size(s->pb, len);
255  avio_wb16(s->pb, 0);
256  avio_write(s->pb, buf, len);
257  av_freep(&buf);
258 
259  id3->len += len + ID3v2_HEADER_SIZE;
260 
261  return 0;
262 }
263 
265 {
266  int64_t cur_pos = avio_tell(pb);
267  avio_seek(pb, id3->size_pos, SEEK_SET);
268  id3v2_put_size(pb, id3->len);
269  avio_seek(pb, cur_pos, SEEK_SET);
270 }
271 
272 int ff_id3v2_write_simple(struct AVFormatContext *s, int id3v2_version,
273  const char *magic)
274 {
275  ID3v2EncContext id3 = { 0 };
276  int ret;
277 
278  ff_id3v2_start(&id3, s->pb, id3v2_version, magic);
279  if ((ret = ff_id3v2_write_metadata(s, &id3)) < 0)
280  return ret;
281  ff_id3v2_finish(&id3, s->pb);
282 
283  return 0;
284 }
void avio_wl16(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:367
const char * s
Definition: avisynth_c.h:668
Bytestream IO Context.
Definition: avio.h:68
Buffered I/O operations.
int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer)
Return the written size and a pointer to the buffer.
Definition: aviobuf.c:988
int len
size of the tag written so far
Definition: id3v2.h:52
int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3)
Convert and write all global metadata from s into an ID3v2 tag.
Definition: id3v2enc.c:165
int index
stream index in AVFormatContext
Definition: avformat.h:644
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:199
const char ff_id3v2_4_tags[][4]
ID3v2.4-only text information frames.
Definition: id3v2.c:92
#define FF_ARRAY_ELEMS(a)
AVDictionaryEntry * av_dict_get(AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition: dict.c:39
int avio_open_dyn_buf(AVIOContext **s)
Open a write only memory stream.
Definition: aviobuf.c:976
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
initialize output if(nPeaks >3)%at least 3 peaks in spectrum for trying to find f0 nf0peaks
Format I/O context.
Definition: avformat.h:944
ID3v2Encoding
Definition: id3v2.h:42
Public dictionary API.
void ff_id3v2_start(ID3v2EncContext *id3, AVIOContext *pb, int id3v2_version, const char *magic)
Initialize an ID3v2 tag.
Definition: id3v2enc.c:151
#define ID3v2_HEADER_SIZE
Definition: id3v2.h:30
const AVMetadataConv ff_id3v2_34_metadata_conv[]
Definition: id3v2.c:43
uint8_t
#define AV_RB32
static AVPacket pkt
Definition: demuxing.c:56
#define put(d, s)
Definition: dsputil_align.c:51
AVStream ** streams
Definition: avformat.h:992
uint8_t * data
uint32_t tag
Definition: movenc.c:894
enum AVCodecID id
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:248
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:173
AVDictionary * metadata
Definition: avformat.h:1092
const AVMetadataConv ff_id3v2_4_metadata_conv[]
Definition: id3v2.c:61
static const struct endianess table[]
static int string_is_ascii(const uint8_t *str)
Definition: id3v2enc.c:39
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values. ...
Definition: dict.c:162
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:82
int size
const char * ff_id3v2_picture_types[21]
Definition: id3v2.c:103
AVCodecContext * codec
Codec context associated with this stream.
Definition: avformat.h:662
const CodecMime ff_id3v2_mime_tags[]
Definition: id3v2.c:127
int64_t size_pos
offset of the tag total size
Definition: id3v2.h:51
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition: avstring.c:212
ret
Definition: avfilter.c:821
t
Definition: genspecsines3.m:6
AVDictionary * metadata
Definition: avformat.h:711
int avio_put_str(AVIOContext *s, const char *str)
Write a NULL-terminated string.
Definition: aviobuf.c:307
Stream structure.
Definition: avformat.h:643
const char ff_id3v2_tags[][4]
A list of text information frames allowed in both ID3 v2.3 and v2.4 http://www.id3.org/id3v2.4.0-frames http://www.id3.org/id3v2.4.0-changes.
Definition: id3v2.c:84
NULL
Definition: eval.c:55
enum AVCodecID codec_id
AVIOContext * pb
I/O context.
Definition: avformat.h:977
static int id3v2_check_write_tag(ID3v2EncContext *id3, AVIOContext *pb, AVDictionaryEntry *t, const char table[][4], enum ID3v2Encoding enc)
Definition: id3v2enc.c:98
void avio_w8(AVIOContext *s, int b)
Definition: aviobuf.c:151
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
void * buf
Definition: avisynth_c.h:594
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:62
double value
Definition: eval.c:82
synthesis window for stochastic i
int avio_put_str16le(AVIOContext *s, const char *str)
Convert an UTF-8 string to UTF-16LE and write it.
Definition: aviobuf.c:318
static void id3v2_encode_string(AVIOContext *pb, const uint8_t *str, enum ID3v2Encoding enc)
Definition: id3v2enc.c:45
#define snprintf
Definition: snprintf.h:34
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
#define type
int ff_id3v2_write_simple(struct AVFormatContext *s, int id3v2_version, const char *magic)
Write an ID3v2 tag containing all global metadata from s.
Definition: id3v2enc.c:272
void avio_wb16(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:373
static int id3v2_put_ttag(ID3v2EncContext *id3, AVIOContext *avioc, const char *str1, const char *str2, uint32_t tag, enum ID3v2Encoding enc)
Write a text frame with one (normal frames) or two (TXXX frames) strings according to encoding (only ...
Definition: id3v2enc.c:64
Main libavformat public API header.
static void id3v2_put_size(AVIOContext *pb, int size)
Definition: id3v2enc.c:31
char * key
Definition: dict.h:81
void ff_metadata_conv(AVDictionary **pm, const AVMetadataConv *d_conv, const AVMetadataConv *s_conv)
#define MKBETAG(a, b, c, d)
Definition: common.h:283
const char ff_id3v2_3_tags[][4]
ID3v2.3-only text information frames.
Definition: id3v2.c:98
char * value
Definition: dict.h:82
int len
int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt)
Write an attached picture from pkt into an ID3v2 tag.
Definition: id3v2enc.c:199
else dst[i][x+y *dst_stride[i]]
Definition: vf_mcdeint.c:160
static void id3v2_3_metadata_split_date(AVDictionary **pm)
Definition: id3v2enc.c:113
void avio_wb32(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:299
#define AV_DICT_IGNORE_SUFFIX
Definition: dict.h:68
int version
ID3v2 minor version, either 3 or 4.
Definition: id3v2.h:50
This structure stores compressed data.
void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb)
Finalize an opened ID3v2 tag.
Definition: id3v2enc.c:264