id3v2enc: chapter support
authorPaul B Mahol <onemda@gmail.com>
Mon, 6 May 2013 00:14:05 +0000 (00:14 +0000)
committerPaul B Mahol <onemda@gmail.com>
Fri, 17 May 2013 16:52:55 +0000 (16:52 +0000)
Signed-off-by: Paul B Mahol <onemda@gmail.com>
libavformat/id3v2enc.c

index a10d679..60ddbaa 100644 (file)
@@ -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);
-
-    while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
-        int ret;
+        ff_metadata_conv(metadata, ff_id3v2_4_metadata_conv, NULL);
 
-        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];