Support planar sample formats in audio mixdown
authorSergey Sharybin <sergey.vfx@gmail.com>
Fri, 28 Feb 2014 09:15:04 +0000 (15:15 +0600)
committerSergey Sharybin <sergey.vfx@gmail.com>
Fri, 28 Feb 2014 09:16:30 +0000 (15:16 +0600)
Now libav-10 should work for output of ac3 container.

intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp
intern/audaspace/ffmpeg/AUD_FFMPEGWriter.h

index dcacf71a2d323ab767d9e337bd2e172c8d66e9f9..d30835da4e5ff65072ea591b4ef93cc168192a89 100644 (file)
@@ -169,6 +169,19 @@ AUD_FFMPEGWriter::AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs,
                        if(!codec)
                                AUD_THROW(AUD_ERROR_FFMPEG, codec_error);
 
+                       if(codec->sample_fmts) {
+                               // Check if the prefered sample format for this codec is supported.
+                               const enum AVSampleFormat *p = codec->sample_fmts;
+                               for(; *p != -1; p++) {
+                                       if(*p == m_stream->codec->sample_fmt)
+                                               break;
+                               }
+                               if(*p == -1) {
+                                       // Sample format incompatible with codec. Defaulting to a format known to work.
+                                       m_stream->codec->sample_fmt = codec->sample_fmts[0];
+                               }
+                       }
+
                        if(avcodec_open2(m_codecCtx, codec, NULL))
                                AUD_THROW(AUD_ERROR_FFMPEG, codec_error);
 
@@ -199,8 +212,11 @@ AUD_FFMPEGWriter::AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs,
 #  ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
                        m_frame->channel_layout = m_codecCtx->channel_layout;
 #  endif
-                       m_audio_sample_size = av_get_bytes_per_sample(m_codecCtx->sample_fmt);
+                       m_sample_size = av_get_bytes_per_sample(m_codecCtx->sample_fmt);
                        m_frame_pts = 0;
+                       m_deinterleave = av_sample_fmt_is_planar(m_codecCtx->sample_fmt);
+                       if(m_deinterleave)
+                               m_deinterleave_buffer.resize(m_input_size * m_codecCtx->channels * m_sample_size);
 #endif
 
                        try
@@ -284,6 +300,17 @@ void AUD_FFMPEGWriter::encode(sample_t* data)
        m_frame->channel_layout = m_codecCtx->channel_layout;
 #endif
 
+       if(m_deinterleave) {
+               for(int channel = 0; channel < m_codecCtx->channels; channel++) {
+                       for(int i = 0; i < m_frame->nb_samples; i++) {
+                               memcpy(reinterpret_cast<uint8_t*>(m_deinterleave_buffer.getBuffer()) + (i + channel * m_frame->nb_samples) * m_sample_size,
+                                          reinterpret_cast<uint8_t*>(data) + (m_codecCtx->channels * i + channel) * m_sample_size, m_sample_size);
+                       }
+               }
+
+               data = m_deinterleave_buffer.getBuffer();
+       }
+
        avcodec_fill_audio_frame(m_frame, m_codecCtx->channels, m_codecCtx->sample_fmt, reinterpret_cast<uint8_t*>(data),
                                 m_frame->nb_samples * av_get_bytes_per_sample(m_codecCtx->sample_fmt) * m_codecCtx->channels, 1);
 
index 743d885fca8c837a5418f31ff7ffd88870e0b14f..492aa35ff12e791705579e28d20849d1233aa322 100644 (file)
@@ -90,7 +90,14 @@ private:
        /**
         * Number of bytes per sample.
         */
-       int m_audio_sample_size;
+       int m_sample_size;
+
+       /**
+        * Need to de-interleave audio for planar sample formats.
+        */
+       bool m_deinterleave;
+
+       AUD_Buffer m_deinterleave_buffer;
 
        /**
         * The input buffer for the format converted data before encoding.