MPEG parser fixes: zero run-in patch, header buffer increase
[asdcplib.git] / src / WavFileWriter.h
index 048a7ec0d034d96f11effbf814ed639f9b11200a..74ffe6ba921e812b7623d7d76cf3535073e7a83a 100755 (executable)
@@ -30,21 +30,61 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include <KM_fileio.h>
+#include <KM_log.h>
 #include <Wav.h>
 #include <list>
 
 #ifndef _WAVFILEWRITER_H_
 #define _WAVFILEWRITER_H_
 
+
+//
+class WavFileElement : public Kumu::FileWriter
+{
+  ASDCP::PCM::FrameBuffer m_Buf;
+  byte_t* m_p;
+
+  WavFileElement();
+  KM_NO_COPY_CONSTRUCT(WavFileElement);
+
+public:
+  WavFileElement(ui32_t s) : m_Buf(s), m_p(0)
+  {
+    m_p = m_Buf.Data();
+  }
+
+  ~WavFileElement() {}
+
+  void WriteSample(const byte_t* sample, ui32_t sample_size)
+  {
+    memcpy(m_p, sample, sample_size);
+    m_p += sample_size;
+  }
+
+  ASDCP::Result_t Flush()
+  {
+    ui32_t write_count = 0;
+
+    if ( m_p == m_Buf.Data() )
+      return ASDCP::RESULT_EMPTY_FB;
+
+    ui32_t write_size = m_p - m_Buf.Data();
+    m_p = m_Buf.Data();
+    return Write(m_Buf.RoData(), write_size, &write_count);
+  }
+};
+
+
 //
 class WavFileWriter
 {
   ASDCP::PCM::AudioDescriptor m_ADesc;
-  std::list<Kumu::FileWriter*> m_OutFile;
+  std::list<WavFileElement*>  m_OutFile;
+  ui32_t                      m_ChannelCount;
   ASDCP_NO_COPY_CONSTRUCT(WavFileWriter);
 
  public:
-  WavFileWriter() {}
+  WavFileWriter() : m_ChannelCount(0) {}
   ~WavFileWriter()
     {
       while ( ! m_OutFile.empty() )
@@ -54,31 +94,60 @@ class WavFileWriter
        }
     }
 
+  //
+  enum SplitType_t {
+    ST_NONE,   // write all channels to a single WAV file
+    ST_MONO,   // write each channel a separate WAV file
+    ST_STEREO  // write channel pairs to separate WAV files
+  };
+
   ASDCP::Result_t
-    OpenWrite(ASDCP::PCM::AudioDescriptor &ADesc, const char* file_root, bool split)
+    OpenWrite(ASDCP::PCM::AudioDescriptor &ADesc, const char* file_root, SplitType_t split = ST_NONE)
     {
       ASDCP_TEST_NULL_STR(file_root);
-      char filename[256];
-      ui32_t file_count = 1;
+      char filename[Kumu::MaxFilePath];
+      ui32_t file_count = 0;
       ASDCP::Result_t result = ASDCP::RESULT_OK;
       m_ADesc = ADesc;
 
-      if ( split )
+      switch ( split )
        {
-         assert ( m_ADesc.ChannelCount % 2 == 0 ); // no support yet for stuffing odd files
+       case ST_NONE:
+         file_count = 1;
+         m_ChannelCount = m_ADesc.ChannelCount;
+         break;
+
+       case ST_MONO:
+         file_count = m_ADesc.ChannelCount;
+         m_ChannelCount = 1;
+         break;
+
+       case ST_STEREO:
+         if ( m_ADesc.ChannelCount % 2 != 0 )
+           {
+             Kumu::DefaultLogSink().Error("Unable to create 2-channel splits with odd number of input channels.\n");
+             return ASDCP::RESULT_PARAM;
+           }
+
          file_count = m_ADesc.ChannelCount / 2;
-         m_ADesc.ChannelCount = 2;
+         m_ChannelCount = 2;
+         break;
        }
+      assert(file_count && m_ChannelCount);
+
+      ui32_t element_size = ASDCP::PCM::CalcFrameBufferSize(m_ADesc) / file_count;
 
       for ( ui32_t i = 0; i < file_count && ASDCP_SUCCESS(result); i++ )
        {
-         snprintf(filename, 256, "%s_%u.wav", file_root, (i + 1));
-         m_OutFile.push_back(new Kumu::FileWriter);
+         snprintf(filename, Kumu::MaxFilePath, "%s_%u.wav", file_root, (i + 1));
+         m_OutFile.push_back(new WavFileElement(element_size));
          result = m_OutFile.back()->OpenWrite(filename);
 
          if ( ASDCP_SUCCESS(result) )
            {
-             ASDCP::Wav::SimpleWaveHeader Wav(m_ADesc);
+             ASDCP::PCM::AudioDescriptor tmpDesc = m_ADesc;
+             tmpDesc.ChannelCount = m_ChannelCount;
+             ASDCP::Wav::SimpleWaveHeader Wav(tmpDesc);
              result = Wav.WriteToFile(*(m_OutFile.back()));
            }
        }
@@ -89,25 +158,34 @@ class WavFileWriter
   ASDCP::Result_t
     WriteFrame(ASDCP::PCM::FrameBuffer& FB)
     {
-      ui32_t write_count;
-      ASDCP::Result_t result = ASDCP::RESULT_OK;
-      std::list<Kumu::FileWriter*>::iterator fi;
-      assert(! m_OutFile.empty());
-
-      ui32_t sample_size = ASDCP::PCM::CalcSampleSize(m_ADesc);
+      if ( m_OutFile.empty() )
+       return ASDCP::RESULT_STATE;
+
+      if ( m_OutFile.size() == 1 ) // no de-interleave needed, just write out the frame
+       return m_OutFile.back()->Write(FB.RoData(), FB.Size(), 0);
+      std::list<WavFileElement*>::iterator fi;
+      ui32_t sample_size = m_ADesc.QuantizationBits / 8;
       const byte_t* p = FB.RoData();
       const byte_t* end_p = p + FB.Size();
 
       while ( p < end_p )
        {
-         for ( fi = m_OutFile.begin(); fi != m_OutFile.end() && ASDCP_SUCCESS(result); fi++ )
+         for ( fi = m_OutFile.begin(); fi != m_OutFile.end(); fi++ )
            {
-             result = (*fi)->Write(p, sample_size, &write_count);
-             assert(write_count == sample_size);
-             p += sample_size;
+             for ( ui32_t c = 0; c < m_ChannelCount; c++ )
+               {
+                 (*fi)->WriteSample(p, sample_size);
+                 p += sample_size;
+               }
            }
        }
 
+      ASDCP::Result_t result = ASDCP::RESULT_OK;
+
+      for ( fi = m_OutFile.begin(); fi != m_OutFile.end() && ASDCP_SUCCESS(result); fi++ )
+       result = (*fi)->Flush();
+
       return result;
     }
 };