Add waveformat-extensible support in the wav muxer.
[ffmpeg.git] / libavformat / riff.c
index 8dda623..014c762 100644 (file)
@@ -22,6 +22,7 @@
 #include "libavcodec/avcodec.h"
 #include "avformat.h"
 #include "riff.h"
+#include "libavcodec/bytestream.h"
 
 /* Note: when encoding, the first matching tag is used, so order is
    important if multiple tags possible for a given codec. */
@@ -284,11 +285,20 @@ int put_wav_header(ByteIOContext *pb, AVCodecContext *enc)
 {
     int bps, blkalign, bytespersec;
     int hdrsize = 18;
+    int waveformatextensible;
+    uint8_t temp[256];
+    uint8_t *riff_extradata= temp;
+    uint8_t *riff_extradata_start= temp;
 
     if(!enc->codec_tag || enc->codec_tag > 0xffff)
         return -1;
+    waveformatextensible = enc->channels > 2 && enc->channel_layout;
 
+    if (waveformatextensible) {
+        put_le16(pb, 0xfffe);
+    } else {
     put_le16(pb, enc->codec_tag);
+    }
     put_le16(pb, enc->channels);
     put_le32(pb, enc->sample_rate);
     if (enc->codec_id == CODEC_ID_MP2 || enc->codec_id == CODEC_ID_MP3 || enc->codec_id == CODEC_ID_GSM_MS) {
@@ -326,43 +336,52 @@ int put_wav_header(ByteIOContext *pb, AVCodecContext *enc)
     put_le16(pb, blkalign); /* block align */
     put_le16(pb, bps); /* bits per sample */
     if (enc->codec_id == CODEC_ID_MP3) {
-        put_le16(pb, 12); /* wav_extra_size */
         hdrsize += 12;
-        put_le16(pb, 1); /* wID */
-        put_le32(pb, 2); /* fdwFlags */
-        put_le16(pb, 1152); /* nBlockSize */
-        put_le16(pb, 1); /* nFramesPerBlock */
-        put_le16(pb, 1393); /* nCodecDelay */
+        bytestream_put_le16(&riff_extradata, 1);    /* wID */
+        bytestream_put_le32(&riff_extradata, 2);    /* fdwFlags */
+        bytestream_put_le16(&riff_extradata, 1152); /* nBlockSize */
+        bytestream_put_le16(&riff_extradata, 1);    /* nFramesPerBlock */
+        bytestream_put_le16(&riff_extradata, 1393); /* nCodecDelay */
     } else if (enc->codec_id == CODEC_ID_MP2) {
-        put_le16(pb, 22); /* wav_extra_size */
         hdrsize += 22;
-        put_le16(pb, 2);  /* fwHeadLayer */
-        put_le32(pb, enc->bit_rate); /* dwHeadBitrate */
-        put_le16(pb, enc->channels == 2 ? 1 : 8); /* fwHeadMode */
-        put_le16(pb, 0);  /* fwHeadModeExt */
-        put_le16(pb, 1);  /* wHeadEmphasis */
-        put_le16(pb, 16); /* fwHeadFlags */
-        put_le32(pb, 0);  /* dwPTSLow */
-        put_le32(pb, 0);  /* dwPTSHigh */
+        bytestream_put_le16(&riff_extradata, 2);                          /* fwHeadLayer */
+        bytestream_put_le32(&riff_extradata, enc->bit_rate);              /* dwHeadBitrate */
+        bytestream_put_le16(&riff_extradata, enc->channels == 2 ? 1 : 8); /* fwHeadMode */
+        bytestream_put_le16(&riff_extradata, 0);                          /* fwHeadModeExt */
+        bytestream_put_le16(&riff_extradata, 1);                          /* wHeadEmphasis */
+        bytestream_put_le16(&riff_extradata, 16);                         /* fwHeadFlags */
+        bytestream_put_le32(&riff_extradata, 0);                          /* dwPTSLow */
+        bytestream_put_le32(&riff_extradata, 0);                          /* dwPTSHigh */
     } else if (enc->codec_id == CODEC_ID_GSM_MS) {
-        put_le16(pb, 2); /* wav_extra_size */
         hdrsize += 2;
-        put_le16(pb, enc->frame_size); /* wSamplesPerBlock */
+        bytestream_put_le16(&riff_extradata, enc->frame_size); /* wSamplesPerBlock */
     } else if (enc->codec_id == CODEC_ID_ADPCM_IMA_WAV) {
-        put_le16(pb, 2); /* wav_extra_size */
         hdrsize += 2;
-        put_le16(pb, enc->frame_size); /* wSamplesPerBlock */
+        bytestream_put_le16(&riff_extradata, enc->frame_size); /* wSamplesPerBlock */
     } else if(enc->extradata_size){
-        put_le16(pb, enc->extradata_size);
-        put_buffer(pb, enc->extradata, enc->extradata_size);
+        riff_extradata_start= enc->extradata;
+        riff_extradata= enc->extradata + enc->extradata_size;
         hdrsize += enc->extradata_size;
+    } else if (!waveformatextensible){
+        hdrsize -= 2;
+    }
+    if(waveformatextensible) {                                    /* write WAVEFORMATEXTENSIBLE extensions */
+        hdrsize += 22;
+        put_le16(pb, riff_extradata - riff_extradata_start + 22); /* 22 is WAVEFORMATEXTENSIBLE size */
+        put_le16(pb, enc->bits_per_coded_sample);                 /* ValidBitsPerSample || SamplesPerBlock || Reserved */
+        put_le32(pb, enc->channel_layout);                        /* dwChannelMask */
+        put_le32(pb, enc->codec_tag);                             /* GUID + next 3 */
+        put_le32(pb, 0x00100000);
+        put_le32(pb, 0xAA000080);
+        put_le32(pb, 0x719B3800);
+    } else if(riff_extradata - riff_extradata_start) {
+        put_le16(pb, riff_extradata - riff_extradata_start);
+    }
+    put_buffer(pb, riff_extradata_start, riff_extradata - riff_extradata_start);
         if(hdrsize&1){
             hdrsize++;
             put_byte(pb, 0);
         }
-    } else {
-        hdrsize -= 2;
-    }
 
     return hdrsize;
 }