[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