Fix comparisons between signed and unsigned values.
[asdcplib.git] / src / AS_02_PCM.cpp
index 2a63aa3b9243e5cc66277f24097c7cb0d4f8e8a0..de6412254b91a1c6e8647abcc29d837ba3c2e4a0 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2011-2013, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
+Copyright (c) 2011-2015, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
 John Hurst
 
 All rights reserved.
@@ -25,6 +25,8 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
 /*! \file    AS_02_PCM.cpp
   \version $Id$       
   \brief   AS-02 library, PCM essence reader and writer implementation
@@ -47,16 +49,15 @@ static std::string SOUND_DEF_LABEL = "Sound Track";
 
 class AS_02::PCM::MXFReader::h__Reader : public AS_02::h__AS02Reader
 {
-  ui64_t m_ClipEssenceBegin;
-  ui64_t m_SamplesPerFrame;
-  ui32_t m_ContainerDuration;
+  ui64_t m_ClipEssenceBegin, m_ClipSize;
+  ui32_t m_ClipDurationFrames, m_BytesPerFrame;
 
   ASDCP_NO_COPY_CONSTRUCT(h__Reader);
   h__Reader();
 
 public:
-  h__Reader(const Dictionary& d) : AS_02::h__AS02Reader(d), m_ClipEssenceBegin(0),
-                                  m_SamplesPerFrame(0), m_ContainerDuration(0) {}
+  h__Reader(const Dictionary& d) : AS_02::h__AS02Reader(d), m_ClipEssenceBegin(0), m_ClipSize(0),
+                                  m_ClipDurationFrames(0) {}
   virtual ~h__Reader() {}
 
   ASDCP::Result_t    OpenRead(const std::string&, const ASDCP::Rational& edit_rate);
@@ -75,17 +76,20 @@ AS_02::PCM::MXFReader::h__Reader::OpenRead(const std::string& filename, const AS
 
   if( KM_SUCCESS(result) )
     {
-      if ( KM_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor),
-                                                    reinterpret_cast<InterchangeObject**>(&wave_descriptor))) )
+      InterchangeObject* tmp_obj = 0;
+
+      if ( KM_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor), &tmp_obj)) )
        {
-         if ( wave_descriptor == 0 )
-           {
-             DefaultLogSink().Error("WaveAudioDescriptor object not found.\n");
-             return RESULT_AS02_FORMAT;
-           }
+         wave_descriptor = dynamic_cast<ASDCP::MXF::WaveAudioDescriptor*>(tmp_obj);
        }
     }
 
+  if ( wave_descriptor == 0 )
+    {
+      DefaultLogSink().Error("WaveAudioDescriptor object not found.\n");
+      result = RESULT_AS02_FORMAT;
+    }
+
   if ( KM_SUCCESS(result) )
     result = m_IndexAccess.Lookup(0, tmp_entry);
 
@@ -102,7 +106,7 @@ AS_02::PCM::MXFReader::h__Reader::OpenRead(const std::string& filename, const AS
        {
          if ( ! UL(reader.Key()).MatchIgnoreStream(m_Dict->ul(MDD_WAVEssenceClip)) )
            {
-             const MDDEntry *entry = m_Dict->FindUL(reader.Key());
+             const MDDEntry *entry = m_Dict->FindULAnyVersion(reader.Key());
 
              if ( entry == 0 )
                {
@@ -130,9 +134,14 @@ AS_02::PCM::MXFReader::h__Reader::OpenRead(const std::string& filename, const AS
            }
 
          m_ClipEssenceBegin = m_File.Tell();
-         m_SamplesPerFrame = AS_02::MXF::CalcSamplesPerFrame(*wave_descriptor, edit_rate);
-         m_ContainerDuration = static_cast<ui32_t>(8ULL * reader.Length() /
-                                                   (m_SamplesPerFrame * wave_descriptor->ChannelCount * wave_descriptor->QuantizationBits));
+         m_ClipSize = reader.Length();
+         m_BytesPerFrame = AS_02::MXF::CalcFrameBufferSize(*wave_descriptor, edit_rate);
+         m_ClipDurationFrames = m_ClipSize / m_BytesPerFrame;
+
+         if ( m_ClipSize % m_BytesPerFrame > 0 )
+           {
+             ++m_ClipDurationFrames; // there is a partial frame at the end
+           }
        }
     }
 
@@ -142,35 +151,43 @@ AS_02::PCM::MXFReader::h__Reader::OpenRead(const std::string& filename, const AS
 //
 ASDCP::Result_t
 AS_02::PCM::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, ASDCP::PCM::FrameBuffer& FrameBuf,
-                                           ASDCP::AESDecContext* Ctx, ASDCP::HMACContext* HMAC)
+                                           ASDCP::AESDecContext*, ASDCP::HMACContext*)
 {
   if ( ! m_File.IsOpen() )
     {
       return RESULT_INIT;
     }
 
-  if ( FrameNum > m_ContainerDuration )
+  if ( ! ( FrameNum < m_ClipDurationFrames ) )
     {
       return RESULT_RANGE;
     }
 
   assert(m_ClipEssenceBegin);
+  ui64_t offset = FrameNum * m_BytesPerFrame;
+  ui64_t position = m_ClipEssenceBegin + offset;
   Result_t result = RESULT_OK;
-  ui64_t position = m_ClipEssenceBegin + ( FrameNum * m_SamplesPerFrame );
 
-  if ( m_File.Tell() != position )
+  if ( m_File.Tell() != static_cast<Kumu::fpos_t>(position) )
     {
       result = m_File.Seek(position);
     }
 
   if ( KM_SUCCESS(result) )
     {
-      result = m_File.Read(FrameBuf.Data(), m_SamplesPerFrame);
-    }
+      ui64_t remainder = m_ClipSize - offset;
+      ui32_t read_size = ( remainder < m_BytesPerFrame ) ? remainder : m_BytesPerFrame;
+      result = m_File.Read(FrameBuf.Data(), read_size);
 
-  if ( KM_SUCCESS(result) )
-    {
-      FrameBuf.Size(m_SamplesPerFrame);
+      if ( KM_SUCCESS(result) )
+       {
+         FrameBuf.Size(read_size);
+
+         if ( read_size < FrameBuf.Capacity() )
+           {
+             memset(FrameBuf.Data() + FrameBuf.Size(), 0, FrameBuf.Capacity() - FrameBuf.Size());
+           }
+       }
     }
 
   return result;
@@ -238,7 +255,7 @@ AS_02::PCM::MXFReader::RIP()
 // Open the file for reading. The file must exist. Returns error if the
 // operation cannot be completed.
 ASDCP::Result_t
-AS_02::PCM::MXFReader::OpenRead(const std::string& filename, const ASDCP::Rational& edit_rate)
+AS_02::PCM::MXFReader::OpenRead(const std::string& filename, const ASDCP::Rational& edit_rate) const
 {
   return m_Reader->OpenRead(filename, edit_rate);
 }
@@ -290,23 +307,26 @@ void
 AS_02::PCM::MXFReader::DumpHeaderMetadata(FILE* stream) const
 {
   if ( m_Reader && m_Reader->m_File.IsOpen() )
-    m_Reader->m_HeaderPart.Dump(stream);
+    {
+      m_Reader->m_HeaderPart.Dump(stream);
+    }
 }
 
-
 //
 void
 AS_02::PCM::MXFReader::DumpIndex(FILE* stream) const
 {
-  if ( m_Reader->m_File.IsOpen() )
-    m_Reader->m_IndexAccess.Dump(stream);
+  if ( m_Reader && m_Reader->m_File.IsOpen() )
+    {
+      m_Reader->m_IndexAccess.Dump(stream);
+    }
 }
 
 
 //------------------------------------------------------------------------------------------
 
 //
-class AS_02::PCM::MXFWriter::h__Writer : public AS_02::h__AS02Writer
+class AS_02::PCM::MXFWriter::h__Writer : public AS_02::h__AS02WriterClip
 {
   ASDCP_NO_COPY_CONSTRUCT(h__Writer);
   h__Writer();
@@ -314,10 +334,9 @@ class AS_02::PCM::MXFWriter::h__Writer : public AS_02::h__AS02Writer
 public:
   ASDCP::MXF::WaveAudioDescriptor *m_WaveAudioDescriptor;
   byte_t m_EssenceUL[SMPTE_UL_LENGTH];
-  ui32_t m_BytesPerFrame;
-  ui32_t m_SamplesPerFrame;
-
-  h__Writer(const Dictionary& d) : AS_02::h__AS02Writer(d), m_WaveAudioDescriptor(0), m_BytesPerFrame(0), m_SamplesPerFrame(0)
+  ui32_t m_BytesPerSample;
+  
+  h__Writer(const Dictionary& d) : AS_02::h__AS02WriterClip(d), m_WaveAudioDescriptor(0), m_BytesPerSample(0)
   {
     memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
   }
@@ -339,15 +358,15 @@ AS_02::PCM::MXFWriter::h__Writer::OpenWrite(const std::string& filename, ASDCP::
 {
   assert(essence_descriptor);
 
-  if ( essence_descriptor->GetUL() != UL(m_Dict->ul(MDD_WaveAudioDescriptor)) )
+  m_WaveAudioDescriptor = dynamic_cast<ASDCP::MXF::WaveAudioDescriptor*>(essence_descriptor);
+
+  if ( m_WaveAudioDescriptor == 0 )
     {
       DefaultLogSink().Error("Essence descriptor is not a WaveAudioDescriptor.\n");
       essence_descriptor->Dump();
       return RESULT_AS02_FORMAT;
     }
 
-  m_WaveAudioDescriptor = reinterpret_cast<ASDCP::MXF::WaveAudioDescriptor*>(essence_descriptor);
-
   if ( ! m_State.Test_BEGIN() )
     {
       return RESULT_STATE;
@@ -394,8 +413,6 @@ AS_02::PCM::MXFWriter::h__Writer::SetSourceStream(const ASDCP::Rational& edit_ra
       return RESULT_STATE;
     }
 
-  fprintf(stderr, "edit_rate=%d/%d\n", edit_rate.Numerator, edit_rate.Denominator);
-
   memcpy(m_EssenceUL, m_Dict->ul(MDD_WAVEssenceClip), SMPTE_UL_LENGTH);
   m_EssenceUL[15] = 1; // set the stream identifier
   Result_t result = m_State.Goto_READY();
@@ -403,15 +420,16 @@ AS_02::PCM::MXFWriter::h__Writer::SetSourceStream(const ASDCP::Rational& edit_ra
   if ( KM_SUCCESS(result) )
     {
       assert(m_WaveAudioDescriptor);
-      m_BytesPerFrame = AS_02::MXF::CalcFrameBufferSize(*m_WaveAudioDescriptor, edit_rate);
-      m_SamplesPerFrame = AS_02::MXF::CalcSamplesPerFrame(*m_WaveAudioDescriptor, edit_rate);
-      m_WaveAudioDescriptor->ContainerDuration = 0;
-
-      fprintf(stderr, "m_BytesPerFrame=%d, m_SamplesPerFrame=%d\n", m_BytesPerFrame, m_SamplesPerFrame);
-
-      result = WriteAS02Header(PCM_PACKAGE_LABEL, UL(m_Dict->ul(MDD_WAVWrapping)),
+      m_BytesPerSample = AS_02::MXF::CalcSampleSize(*m_WaveAudioDescriptor);
+      result = WriteAS02Header(PCM_PACKAGE_LABEL, UL(m_Dict->ul(MDD_WAVWrappingClip)),
                               SOUND_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_SoundDataDef)),
-                              m_EssenceDescriptor->SampleRate, derive_timecode_rate_from_edit_rate(edit_rate), m_BytesPerFrame);
+                              m_EssenceDescriptor->SampleRate, derive_timecode_rate_from_edit_rate(edit_rate));
+
+      if ( KM_SUCCESS(result) )
+       {
+         this->m_IndexWriter.SetEditRate(m_WaveAudioDescriptor->AudioSamplingRate,
+                                         AS_02::MXF::CalcSampleSize(*m_WaveAudioDescriptor));
+       }
     }
 
   return result;
@@ -430,12 +448,6 @@ AS_02::PCM::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& frame_buf, AESEn
       return RESULT_PARAM;
     }
 
-  if ( frame_buf.Size() % m_BytesPerFrame != 0 )
-    {
-      DefaultLogSink().Error("The frame buffer does not contain an integral number of sample sets.\n");
-      return RESULT_AS02_FORMAT;
-    }
-
   Result_t result = RESULT_OK;
 
   if ( m_State.Test_READY() )
@@ -455,7 +467,7 @@ AS_02::PCM::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& frame_buf, AESEn
 
   if ( KM_SUCCESS(result) )
     {
-      m_FramesWritten++;
+      m_FramesWritten += frame_buf.Size() / m_BytesPerSample;
     }
 
   return result;
@@ -471,12 +483,11 @@ AS_02::PCM::MXFWriter::h__Writer::Finalize()
 
   m_State.Goto_FINAL();
 
-  Result_t result = FinalizeClip(m_BytesPerFrame);
+  Result_t result = FinalizeClip(AS_02::MXF::CalcSampleSize(*m_WaveAudioDescriptor));
 
   if ( KM_SUCCESS(result) )
     {
-      fprintf(stderr, "m_FramesWritten=%d, m_SamplesPerFrame=%d\n", m_FramesWritten, m_SamplesPerFrame);
-      m_FramesWritten = m_FramesWritten * m_SamplesPerFrame;
+      m_WaveAudioDescriptor->ContainerDuration = m_IndexWriter.m_Duration = m_FramesWritten;
       WriteAS02Footer();
     }
 
@@ -527,7 +538,6 @@ AS_02::PCM::MXFWriter::RIP()
   return m_Writer->m_RIP;
 }
 
-
 // Open the file for writing. The file must not exist. Returns error if
 // the operation cannot be completed.
 ASDCP::Result_t