[FFmpeg-devel] [RFC/PATCH] WAV muxer: add RF64 support

Daniel Verkamp daniel at drv.nu
Wed Jan 23 09:59:09 CET 2013


---
 libavformat/wavenc.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 59 insertions(+), 6 deletions(-)

diff --git a/libavformat/wavenc.c b/libavformat/wavenc.c
index 2e80a75..9a208cb 100644
--- a/libavformat/wavenc.c
+++ b/libavformat/wavenc.c
@@ -40,10 +40,13 @@ typedef struct WAVMuxContext {
     const AVClass *class;
     int64_t data;
     int64_t fact_pos;
+    int64_t ds64;
     int64_t minpts;
     int64_t maxpts;
     int last_duration;
     int write_bext;
+    int allow_rf64;
+    int force_rf64;
 } WAVMuxContext;
 
 #if CONFIG_WAV_MUXER
@@ -107,10 +110,24 @@ static int wav_write_header(AVFormatContext *s)
     AVIOContext *pb = s->pb;
     int64_t fmt;
 
+    if (wav->force_rf64) {
+        ffio_wfourcc(pb, "RF64");
+        avio_wl32(pb, -1); /* RF64 chunk size: use size in ds64 */
+    } else {
     ffio_wfourcc(pb, "RIFF");
     avio_wl32(pb, 0); /* file length */
+    }
+
     ffio_wfourcc(pb, "WAVE");
 
+    if (wav->force_rf64 || wav->allow_rf64) {
+        /* write empty ds64 chunk or JUNK chunk to reserve space for ds64 */
+        ffio_wfourcc(pb, wav->force_rf64 ? "ds64" : "JUNK");
+        avio_wl32(pb, 28); /* chunk size */
+        wav->ds64 = avio_tell(pb);
+        ffio_fill(pb, 0, 28);
+    }
+
     /* format header */
     fmt = ff_start_tag(pb, "fmt ");
     if (ff_put_wav_header(pb, s->streams[0]->codec) < 0) {
@@ -163,32 +180,66 @@ static int wav_write_trailer(AVFormatContext *s)
 {
     AVIOContext *pb  = s->pb;
     WAVMuxContext    *wav = s->priv_data;
-    int64_t file_size;
+    int64_t file_size, data_size;
+    int64_t number_of_samples = 0;
+    int rf64 = 0;
 
     avio_flush(pb);
 
     if (s->pb->seekable) {
-        ff_end_tag(pb, wav->data);
-
         /* update file size */
         file_size = avio_tell(pb);
+        data_size = file_size - wav->data;
+        if (wav->force_rf64 || (wav->allow_rf64 && file_size - 8 > UINT32_MAX)) {
+            rf64 = 1;
+        } else {
         avio_seek(pb, 4, SEEK_SET);
         avio_wl32(pb, (uint32_t)(file_size - 8));
         avio_seek(pb, file_size, SEEK_SET);
 
+                ff_end_tag(pb, wav->data);
         avio_flush(pb);
+        }
 
-        if(s->streams[0]->codec->codec_tag != 0x01) {
-            /* Update num_samps in fact chunk */
-            int number_of_samples;
             number_of_samples = av_rescale(wav->maxpts - wav->minpts + wav->last_duration,
                                            s->streams[0]->codec->sample_rate * (int64_t)s->streams[0]->time_base.num,
                                            s->streams[0]->time_base.den);
+
+        if(s->streams[0]->codec->codec_tag != 0x01) {
+            /* Update num_samps in fact chunk */
             avio_seek(pb, wav->fact_pos, SEEK_SET);
+            if (rf64 || (wav->allow_rf64 && number_of_samples > UINT32_MAX)) {
+                rf64 = 1;
+                avio_wl32(pb, -1);
+            } else {
             avio_wl32(pb, number_of_samples);
             avio_seek(pb, file_size, SEEK_SET);
             avio_flush(pb);
+            }
+        }
+
+        if (rf64) {
+            /* overwrite RIFF with RF64 */
+            avio_seek(pb, 0, SEEK_SET);
+            ffio_wfourcc(pb, "RF64");
+            avio_wl32(pb, -1);
+
+            /* write ds64 chunk (overwrite JUNK if allow_rf64) */
+            avio_seek(pb, wav->ds64 - 8, SEEK_SET);
+            ffio_wfourcc(pb, "ds64");
+            avio_wl32(pb, 28);                  /* ds64 chunk size */
+            avio_wl64(pb, file_size - 8);       /* RF64 chunk size */
+            avio_wl64(pb, data_size);           /* data chunk size */
+            avio_wl64(pb, number_of_samples);   /* fact chunk number of samples */
+            avio_wl32(pb, 0);                   /* number of table entries for non-'data' chunks */
+
+            /* write -1 in data chunk size */
+            avio_seek(pb, wav->data - 4, SEEK_SET);
+            avio_wl32(pb, -1);
         }
+
+        avio_seek(pb, file_size, SEEK_SET);
+        avio_flush(pb);
     }
     return 0;
 }
@@ -197,6 +248,8 @@ static int wav_write_trailer(AVFormatContext *s)
 #define ENC AV_OPT_FLAG_ENCODING_PARAM
 static const AVOption options[] = {
     { "write_bext", "Write BEXT chunk.", OFFSET(write_bext), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC },
+    { "allow_rf64", "Write RF64 header instead of standard RIFF header if file grows large enough.", OFFSET(allow_rf64), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC },
+    { "force_rf64", "Always write RF64 header instead of standard RIFF header regardless of file size.", OFFSET(force_rf64), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC },
     { NULL },
 };
 
-- 
1.8.0



More information about the ffmpeg-devel mailing list