Support writing chapters as 'cue ' and 'adtl' chunks, if no chapter titles are
present, it will create 'Cue #' titles using the chapter number

Signed-off-by: Vladimir Pantelic <[email protected]>
---
 libavformat/wavenc.c | 72 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/libavformat/wavenc.c b/libavformat/wavenc.c
index a515f4e2a2..61a048f641 100644
--- a/libavformat/wavenc.c
+++ b/libavformat/wavenc.c
@@ -88,6 +88,7 @@ typedef struct WAVMuxContext {
     int peak_block_pos;
     int peak_ppv;
     int peak_bps;
+    int write_cue;
 } WAVMuxContext;
 
 #if CONFIG_WAV_MUXER
@@ -299,6 +300,70 @@ static int peak_write_chunk(AVFormatContext *s)
     return 0;
 }
 
+static int wav_write_cue_chunk(AVFormatContext *s, int sample_rate)
+{
+    AVIOContext *dyn_buf;
+    AVIOContext *pb = s->pb;
+    AVRational scale = {1, sample_rate};
+    int ret;
+
+    int64_t start = ff_start_tag(pb, "cue "); /* chunk ID */
+
+    avio_wl32(pb, s->nb_chapters); /* number of cue points */
+
+    /* write cue points */
+    for (int i = 0; i < s->nb_chapters; i++) {
+        AVChapter *c = s->chapters[i];
+        int64_t samples = av_rescale_q(c->start, c->time_base, scale);
+
+        avio_wl32(pb, i + 1);     /* cue point ID */
+        avio_wl32(pb, 0);         /* position, only relevant with PLST chunk */
+        ffio_wfourcc(pb, "data"); /* data chunk ID, only used with WAVL chunk 
*/
+        avio_wl32(pb, 0);         /* chunk start, only used with WAVL chunk */
+        avio_wl32(pb, 0);         /* block start, only used with WAVL chunk*/
+        avio_wl32(pb, samples);   /* sample start (in # of samples) */
+    }
+
+    ff_end_tag(pb, start);
+
+    if ((ret = avio_open_dyn_buf(&dyn_buf)) < 0)
+        return ret;
+
+    start = ff_start_tag(pb, "LIST");
+
+    ffio_wfourcc(pb, "adtl"); /* associated data list chunk */
+
+    /* write cue point names */
+    for (int i = 0; i < s->nb_chapters; i++) {
+        uint8_t *buf;
+        int len;
+        AVChapter *c = s->chapters[i];
+        int64_t label = ff_start_tag(pb, "labl"); /* sub chunk ID */
+        AVDictionaryEntry *t = av_dict_get(c->metadata, "title", NULL, 0);
+        avio_wl32(pb, i + 1);                     /* cue point ID */
+        if(t) {
+            avio_put_str(dyn_buf, t->value);
+        } else {
+            /* no chapter title: use "Cue xyz" */
+            char *title;
+            if((title = av_asprintf("Cue %d", i + 1)) == NULL)
+                return AVERROR(ENOMEM);
+            avio_put_str(dyn_buf, title);
+            av_free(title);
+        }
+        len = avio_get_dyn_buf(dyn_buf, &buf);
+        avio_write(pb, buf, len);                 /* title string data */
+        ffio_reset_dyn_buf(dyn_buf);
+
+        ff_end_tag(pb, label);
+    }
+
+    ff_end_tag(pb, start);
+    ffio_free_dyn_buf(&dyn_buf);
+
+    return 0;
+}
+
 static int wav_write_header(AVFormatContext *s)
 {
     WAVMuxContext *wav = s->priv_data;
@@ -344,6 +409,12 @@ static int wav_write_header(AVFormatContext *s)
     if (wav->write_bext)
         bwf_write_bext_chunk(s);
 
+    if (wav->write_cue) {
+        int ret;
+        if((ret = wav_write_cue_chunk(s, 
s->streams[0]->codecpar->sample_rate)) < 0)
+            return ret;
+    }
+
     if (wav->write_peak) {
         int ret;
         if ((ret = peak_init_writer(s)) < 0)
@@ -494,6 +565,7 @@ static const AVOption options[] = {
     { "peak_block_size", "Number of audio samples used to generate each peak 
frame.",   OFFSET(peak_block_size), AV_OPT_TYPE_INT, { .i64 = 256 }, 0, 65536, 
ENC },
     { "peak_format",     "The format of the peak envelope data (1: uint8, 2: 
uint16).", OFFSET(peak_format), AV_OPT_TYPE_INT,     { .i64 = 
PEAK_FORMAT_UINT16 }, PEAK_FORMAT_UINT8, PEAK_FORMAT_UINT16, ENC },
     { "peak_ppv",        "Number of peak points per peak value (1 or 2).",     
         OFFSET(peak_ppv), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, 2, ENC },
+    { "write_cue",  "Write CUE/ADTL chunk.", OFFSET(write_cue),  
AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC },
     { NULL },
 };
 
-- 
2.51.0


_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to