From 47ac344970f1d6ef149c4b8a883b68cdb15112c2 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Mon, 6 May 2013 00:14:05 +0000 Subject: [PATCH] id3v2enc: chapter support Signed-off-by: Paul B Mahol --- libavformat/id3v2enc.c | 82 +++++++++++++++++++++++++++++++++++------- 1 file changed, 69 insertions(+), 13 deletions(-) diff --git a/libavformat/id3v2enc.c b/libavformat/id3v2enc.c index a10d679946..60ddbaaafc 100644 --- a/libavformat/id3v2enc.c +++ b/libavformat/id3v2enc.c @@ -162,33 +162,31 @@ void ff_id3v2_start(ID3v2EncContext *id3, AVIOContext *pb, int id3v2_version, avio_wb32(pb, 0); } -int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3) +static int write_metadata(AVIOContext *pb, AVDictionary **metadata, + ID3v2EncContext *id3, int enc) { AVDictionaryEntry *t = NULL; - int enc = id3->version == 3 ? ID3v2_ENCODING_UTF16BOM : - ID3v2_ENCODING_UTF8; + int ret; - ff_metadata_conv(&s->metadata, ff_id3v2_34_metadata_conv, NULL); + ff_metadata_conv(metadata, ff_id3v2_34_metadata_conv, NULL); if (id3->version == 3) - id3v2_3_metadata_split_date(&s->metadata); + id3v2_3_metadata_split_date(metadata); else if (id3->version == 4) - ff_metadata_conv(&s->metadata, ff_id3v2_4_metadata_conv, NULL); + ff_metadata_conv(metadata, ff_id3v2_4_metadata_conv, NULL); - while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) { - int ret; - - if ((ret = id3v2_check_write_tag(id3, s->pb, t, ff_id3v2_tags, enc)) > 0) { + while ((t = av_dict_get(*metadata, "", t, AV_DICT_IGNORE_SUFFIX))) { + if ((ret = id3v2_check_write_tag(id3, pb, t, ff_id3v2_tags, enc)) > 0) { id3->len += ret; continue; } - if ((ret = id3v2_check_write_tag(id3, s->pb, t, id3->version == 3 ? - ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) { + if ((ret = id3v2_check_write_tag(id3, pb, t, id3->version == 3 ? + ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) { id3->len += ret; continue; } /* unknown tag, write as TXXX frame */ - if ((ret = id3v2_put_ttag(id3, s->pb, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0) + if ((ret = id3v2_put_ttag(id3, pb, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0) return ret; id3->len += ret; } @@ -196,6 +194,64 @@ int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3) return 0; } +static int write_chapter(AVFormatContext *s, ID3v2EncContext *id3, int id, int enc) +{ + const AVRational time_base = {1, 1000}; + AVChapter *ch = s->chapters[id]; + uint8_t *dyn_buf = NULL; + AVIOContext *dyn_bc = NULL; + char name[123]; + int len, start, end, ret; + + if ((ret = avio_open_dyn_buf(&dyn_bc)) < 0) + goto fail; + + start = av_rescale_q(ch->start, ch->time_base, time_base); + end = av_rescale_q(ch->end, ch->time_base, time_base); + + snprintf(name, 122, "ch%d", id); + id3->len += avio_put_str(dyn_bc, name); + avio_wb32(dyn_bc, start); + avio_wb32(dyn_bc, end); + avio_wb32(dyn_bc, 0xFFFFFFFFu); + avio_wb32(dyn_bc, 0xFFFFFFFFu); + + if ((ret = write_metadata(dyn_bc, &ch->metadata, id3, enc)) < 0) + goto fail; + + len = avio_close_dyn_buf(dyn_bc, &dyn_buf); + id3->len += 16 + ID3v2_HEADER_SIZE; + + avio_wb32(s->pb, MKBETAG('C', 'H', 'A', 'P')); + avio_wb32(s->pb, len); + avio_wb16(s->pb, 0); + avio_write(s->pb, dyn_buf, len); + +fail: + if (dyn_bc && !dyn_buf) + avio_close_dyn_buf(dyn_bc, &dyn_buf); + av_freep(&dyn_buf); + + return ret; +} + +int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3) +{ + int enc = id3->version == 3 ? ID3v2_ENCODING_UTF16BOM : + ID3v2_ENCODING_UTF8; + int i, ret; + + if ((ret = write_metadata(s->pb, &s->metadata, id3, enc)) < 0) + return ret; + + for (i = 0; i < s->nb_chapters; i++) { + if ((ret = write_chapter(s, id3, i, enc)) < 0) + return ret; + } + + return 0; +} + int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt) { AVStream *st = s->streams[pkt->stream_index];