id3v2enc: split ff_id3v2_write().
This will allow writing the tag in several steps, needed for writing attached pictures.
This commit is contained in:
parent
c199817748
commit
411225aabc
@ -46,6 +46,12 @@ enum ID3v2Encoding {
|
|||||||
ID3v2_ENCODING_UTF8 = 3,
|
ID3v2_ENCODING_UTF8 = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct ID3v2EncContext {
|
||||||
|
int version; ///< ID3v2 minor version, either 3 or 4
|
||||||
|
int64_t size_pos; ///< offset of the tag total size
|
||||||
|
int len; ///< size of the tag written so far
|
||||||
|
} ID3v2EncContext;
|
||||||
|
|
||||||
typedef struct ID3v2ExtraMeta {
|
typedef struct ID3v2ExtraMeta {
|
||||||
const char *tag;
|
const char *tag;
|
||||||
void *data;
|
void *data;
|
||||||
@ -91,12 +97,28 @@ int ff_id3v2_tag_len(const uint8_t *buf);
|
|||||||
void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta);
|
void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write an ID3v2 tag.
|
* Initialize an ID3v2 tag.
|
||||||
|
*/
|
||||||
|
void ff_id3v2_start(ID3v2EncContext *id3, AVIOContext *pb, int id3v2_version,
|
||||||
|
const char *magic);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert and write all global metadata from s into an ID3v2 tag.
|
||||||
|
*/
|
||||||
|
int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalize an opened ID3v2 tag.
|
||||||
|
*/
|
||||||
|
void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write an ID3v2 tag containing all global metadata from s.
|
||||||
* @param id3v2_version Subversion of ID3v2; supported values are 3 and 4
|
* @param id3v2_version Subversion of ID3v2; supported values are 3 and 4
|
||||||
* @param magic magic bytes to identify the header
|
* @param magic magic bytes to identify the header
|
||||||
* If in doubt, use ID3v2_DEFAULT_MAGIC.
|
* If in doubt, use ID3v2_DEFAULT_MAGIC.
|
||||||
*/
|
*/
|
||||||
int ff_id3v2_write(struct AVFormatContext *s, int id3v2_version, const char *magic);
|
int ff_id3v2_write_simple(struct AVFormatContext *s, int id3v2_version, const char *magic);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free memory allocated parsing special (non-text) metadata.
|
* Free memory allocated parsing special (non-text) metadata.
|
||||||
|
@ -97,50 +97,70 @@ static int id3v2_check_write_tag(AVFormatContext *s, AVDictionaryEntry *t, const
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ff_id3v2_write(struct AVFormatContext *s, int id3v2_version,
|
void ff_id3v2_start(ID3v2EncContext *id3, AVIOContext *pb, int id3v2_version,
|
||||||
const char *magic)
|
const char *magic)
|
||||||
{
|
{
|
||||||
int64_t size_pos, cur_pos;
|
id3->version = id3v2_version;
|
||||||
AVDictionaryEntry *t = NULL;
|
|
||||||
|
|
||||||
int totlen = 0, enc = id3v2_version == 3 ? ID3v2_ENCODING_UTF16BOM :
|
avio_wb32(pb, MKBETAG(magic[0], magic[1], magic[2], id3v2_version));
|
||||||
ID3v2_ENCODING_UTF8;
|
avio_w8(pb, 0);
|
||||||
|
avio_w8(pb, 0); /* flags */
|
||||||
|
|
||||||
avio_wb32(s->pb, MKBETAG(magic[0], magic[1], magic[2], id3v2_version));
|
|
||||||
avio_w8(s->pb, 0);
|
|
||||||
avio_w8(s->pb, 0); /* flags */
|
|
||||||
|
|
||||||
/* reserve space for size */
|
/* reserve space for size */
|
||||||
size_pos = avio_tell(s->pb);
|
id3->size_pos = avio_tell(pb);
|
||||||
avio_wb32(s->pb, 0);
|
avio_wb32(pb, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3)
|
||||||
|
{
|
||||||
|
AVDictionaryEntry *t = NULL;
|
||||||
|
int enc = id3->version == 3 ? ID3v2_ENCODING_UTF16BOM :
|
||||||
|
ID3v2_ENCODING_UTF8;
|
||||||
|
|
||||||
ff_metadata_conv(&s->metadata, ff_id3v2_34_metadata_conv, NULL);
|
ff_metadata_conv(&s->metadata, ff_id3v2_34_metadata_conv, NULL);
|
||||||
if (id3v2_version == 4)
|
if (id3->version == 4)
|
||||||
ff_metadata_conv(&s->metadata, ff_id3v2_4_metadata_conv, NULL);
|
ff_metadata_conv(&s->metadata, ff_id3v2_4_metadata_conv, NULL);
|
||||||
|
|
||||||
while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
|
while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if ((ret = id3v2_check_write_tag(s, t, ff_id3v2_tags, enc)) > 0) {
|
if ((ret = id3v2_check_write_tag(s, t, ff_id3v2_tags, enc)) > 0) {
|
||||||
totlen += ret;
|
id3->len += ret;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((ret = id3v2_check_write_tag(s, t, id3v2_version == 3 ?
|
if ((ret = id3v2_check_write_tag(s, t, id3->version == 3 ?
|
||||||
ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) {
|
ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) {
|
||||||
totlen += ret;
|
id3->len += ret;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unknown tag, write as TXXX frame */
|
/* unknown tag, write as TXXX frame */
|
||||||
if ((ret = id3v2_put_ttag(s, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0)
|
if ((ret = id3v2_put_ttag(s, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0)
|
||||||
return ret;
|
return ret;
|
||||||
totlen += ret;
|
id3->len += ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_pos = avio_tell(s->pb);
|
return 0;
|
||||||
avio_seek(s->pb, size_pos, SEEK_SET);
|
}
|
||||||
id3v2_put_size(s->pb, totlen);
|
|
||||||
avio_seek(s->pb, cur_pos, SEEK_SET);
|
void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb)
|
||||||
|
{
|
||||||
|
int64_t cur_pos = avio_tell(pb);
|
||||||
|
avio_seek(pb, id3->size_pos, SEEK_SET);
|
||||||
|
id3v2_put_size(pb, id3->len);
|
||||||
|
avio_seek(pb, cur_pos, SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ff_id3v2_write_simple(struct AVFormatContext *s, int id3v2_version,
|
||||||
|
const char *magic)
|
||||||
|
{
|
||||||
|
ID3v2EncContext id3 = { 0 };
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ff_id3v2_start(&id3, s->pb, id3v2_version, magic);
|
||||||
|
if ((ret = ff_id3v2_write_metadata(s, &id3)) < 0)
|
||||||
|
return ret;
|
||||||
|
ff_id3v2_finish(&id3, s->pb);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -187,7 +187,7 @@ static int mp3_write_header(struct AVFormatContext *s)
|
|||||||
MP3Context *mp3 = s->priv_data;
|
MP3Context *mp3 = s->priv_data;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = ff_id3v2_write(s, mp3->id3v2_version, ID3v2_DEFAULT_MAGIC);
|
ret = ff_id3v2_write_simple(s, mp3->id3v2_version, ID3v2_DEFAULT_MAGIC);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ static av_cold int oma_write_header(AVFormatContext *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Metadata; OpenMG does not support ID3v2.4 */
|
/* Metadata; OpenMG does not support ID3v2.4 */
|
||||||
ff_id3v2_write(s, 3, ID3v2_EA3_MAGIC);
|
ff_id3v2_write_simple(s, 3, ID3v2_EA3_MAGIC);
|
||||||
|
|
||||||
ffio_wfourcc(s->pb, "EA3\0");
|
ffio_wfourcc(s->pb, "EA3\0");
|
||||||
avio_w8(s->pb, EA3_HEADER_SIZE >> 7);
|
avio_w8(s->pb, EA3_HEADER_SIZE >> 7);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user