Commit a bunch of portability fixes (64- vs. 32-bit types).
[asdcplib.git] / src / AS_DCP_JP2K.cpp
index f5ce3354f9c19d2cc164beb1afa9232f1e8686d0..39dceedd72b4e681f93bdfe39f8108911e0dc62d 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2004-2007, John Hurst
+Copyright (c) 2004-2008, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "AS_DCP_internal.h"
 
 using namespace ASDCP::JP2K;
-
+using Kumu::GenRandomValue;
 
 //------------------------------------------------------------------------------------------
 
@@ -84,7 +84,8 @@ ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
   fprintf(stream, "    ImageComponents:\n");
   fprintf(stream, "  bits  h-sep v-sep\n");
 
-  for ( ui32_t i = 0; i < PDesc.Csize; i++ )
+  ui32_t i;
+  for ( i = 0; i < PDesc.Csize; i++ )
     {
       fprintf(stream, "  %4d  %5d %5d\n",
              PDesc.ImageComponents[i].Ssize + 1, // See ISO 15444-1, Table A11, for the origin of '+1'
@@ -106,7 +107,7 @@ ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
   fprintf(stream, "     Transformation: %hd\n", PDesc.CodingStyleDefault.SPcod.Transformation);
 
 
-  ui32_t precinct_set_size = 0, i;
+  ui32_t precinct_set_size = 0;
 
   for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
     precinct_set_size++;
@@ -159,7 +160,8 @@ lh__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc)
   MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
 
   PDesc.EditRate           = m_EditRate;
-  PDesc.ContainerDuration  = PDescObj->ContainerDuration;
+  assert(PDescObj->ContainerDuration <= 0xFFFFFFFFL);
+  PDesc.ContainerDuration  = (ui32_t) PDescObj->ContainerDuration;
   PDesc.StoredWidth        = PDescObj->StoredWidth;
   PDesc.StoredHeight       = PDescObj->StoredHeight;
   PDesc.AspectRatio        = PDescObj->AspectRatio;
@@ -213,17 +215,19 @@ lh__Reader::OpenRead(const char* filename, EssenceType_t type)
 
   if( ASDCP_SUCCESS(result) )
     {
-      m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor),
-                                    (InterchangeObject**)&m_EssenceDescriptor);
-      m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor),
-                                    (InterchangeObject**)&m_EssenceSubDescriptor);
+      InterchangeObject* tmp_iobj = 0;
+      m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
+      m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj);
+
+      m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
+      m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj);
 
       std::list<InterchangeObject*> ObjectList;
       m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
 
       if ( ObjectList.empty() )
        {
-         DefaultLogSink().Error("MXF Metadata contains no Track Sets\n");
+         DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
          return RESULT_FORMAT;
        }
 
@@ -233,16 +237,23 @@ lh__Reader::OpenRead(const char* filename, EssenceType_t type)
        {
          if ( m_EditRate != m_EssenceDescriptor->SampleRate )
            {
-             DefaultLogSink().Error("EditRate and SampleRate do not match (%.03f, %.03f)\n",
+             DefaultLogSink().Error("EditRate and SampleRate do not match (%.03f, %.03f).\n",
                                     m_EditRate.Quotient(), m_EssenceDescriptor->SampleRate.Quotient());
-             return RESULT_SFORMAT;
+             
+             if ( m_EditRate == EditRate_24 && m_EssenceDescriptor->SampleRate == EditRate_48 )
+               {
+                 DefaultLogSink().Error("File may contain JPEG Interop stereoscopic images.\n");
+                 return RESULT_SFORMAT;
+               }
+
+             return RESULT_FORMAT;
            }
        }
       else if ( type == ASDCP::ESS_JPEG_2000_S )
        {
          if ( ! ( m_EditRate == EditRate_24 && m_EssenceDescriptor->SampleRate == EditRate_48 ) )
            {
-             DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence\n");
+             DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n");
              return RESULT_FORMAT;
            }
        }
@@ -452,7 +463,11 @@ public:
       }
 
     if( ASDCP_SUCCESS(result) )
-      result = ReadEKLVPacket(FrameNum, FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
+      {
+       ui32_t SequenceNum = FrameNum * 2;
+       SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
+       result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
+      }
 
     return result;
   }
@@ -478,6 +493,23 @@ ASDCP::JP2K::MXFSReader::OpenRead(const char* filename) const
   return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
 }
 
+//
+ASDCP::Result_t
+ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const
+{
+  Result_t result = RESULT_INIT;
+
+  if ( m_Reader && m_Reader->m_File.IsOpen() )
+    {
+      result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC);
+
+      if ( ASDCP_SUCCESS(result) )
+       result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC);
+    }
+
+  return result;
+}
+
 //
 ASDCP::Result_t
 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
@@ -489,7 +521,6 @@ ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, F
   return RESULT_INIT;
 }
 
-
 // Fill the struct with the values from the file's header.
 // Returns RESULT_INIT if the file is not open.
 ASDCP::Result_t
@@ -564,6 +595,9 @@ public:
   Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
 };
 
+const int VideoLineMapSize = 16; // See SMPTE 377M D.2.1
+const int PixelLayoutSize = 8*2; // See SMPTE 377M D.2.3
+static const byte_t s_PixelLayoutXYZ[PixelLayoutSize] = { 0xd8, 0x0c, 0xd9, 0x0c, 0xda, 0x0c, 0x00 };
 
 //
 ASDCP::Result_t
@@ -573,21 +607,31 @@ lh__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
   assert(m_EssenceSubDescriptor);
   MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
 
-  PDescObj->SampleRate = PDesc.EditRate;
   PDescObj->ContainerDuration = PDesc.ContainerDuration;
+  PDescObj->SampleRate = PDesc.EditRate;
+  PDescObj->FrameLayout = 0;
   PDescObj->StoredWidth = PDesc.StoredWidth;
   PDescObj->StoredHeight = PDesc.StoredHeight;
   PDescObj->AspectRatio = PDesc.AspectRatio;
-  PDescObj->FrameLayout = 0;
+
+  //  if ( m_Info.LabelSetType == LS_MXF_SMPTE )
+  //    {
+  // PictureEssenceCoding UL = 
+  // Video Line Map       ui32_t[VideoLineMapSize] = { 2, 4, 0, 0 }
+  // CaptureGamma         UL = 
+  // ComponentMaxRef      ui32_t = 4095
+  // ComponentMinRef      ui32_t = 0
+  // PixelLayout          byte_t[PixelLayoutSize] = s_PixelLayoutXYZ
+  //    }
 
   if ( PDesc.StoredWidth < 2049 )
     {
-      PDescObj->Codec.Set(Dict::ul(MDD_JP2KEssenceCompression_2K));
+      PDescObj->PictureEssenceCoding.Set(Dict::ul(MDD_JP2KEssenceCompression_2K));
       m_EssenceSubDescriptor->Rsize = 3;
     }
   else
     {
-      PDescObj->Codec.Set(Dict::ul(MDD_JP2KEssenceCompression_4K));
+      PDescObj->PictureEssenceCoding.Set(Dict::ul(MDD_JP2KEssenceCompression_4K));
       m_EssenceSubDescriptor->Rsize = 4;
     }
 
@@ -718,9 +762,9 @@ lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
       IndexTableSegment::IndexEntry Entry;
       Entry.StreamOffset = StreamOffset;
       m_FooterPart.PushIndexEntry(Entry);
-      m_FramesWritten++;
     }
 
+  m_FramesWritten++;
   return result;
 }
 
@@ -765,14 +809,12 @@ ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
                                  const PictureDescriptor& PDesc, ui32_t HeaderSize)
 {
   m_Writer = new h__Writer;
-  
+  m_Writer->m_Info = Info;
+
   Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
 
   if ( ASDCP_SUCCESS(result) )
-    {
-      m_Writer->m_Info = Info;
-      result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
-    }
+    result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
 
   if ( ASDCP_FAILURE(result) )
     m_Writer.release();
@@ -839,6 +881,8 @@ public:
     if ( m_NextPhase != SP_LEFT )
       return RESULT_SPHASE;
 
+    assert( m_FramesWritten % 2 == 0 );
+    m_FramesWritten /= 2;
     return lh__Writer::Finalize();
   }
 };
@@ -868,11 +912,15 @@ ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
       return RESULT_FORMAT;
     }
 
+  if ( PDesc.StoredWidth > 2048 )
+    DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
+
+  m_Writer->m_Info = Info;
+
   Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
 
   if ( ASDCP_SUCCESS(result) )
     {
-      m_Writer->m_Info = Info;
       PictureDescriptor TmpPDesc = PDesc;
       TmpPDesc.EditRate = ASDCP::EditRate_48;
 
@@ -885,6 +933,19 @@ ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
   return result;
 }
 
+ASDCP::Result_t
+ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
+{
+  if ( m_Writer.empty() )
+    return RESULT_INIT;
+
+  Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
+
+  if ( ASDCP_SUCCESS(result) )
+    result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
+
+  return result;
+}
 
 // Writes a frame of essence to the MXF file. If the optional AESEncContext
 // argument is present, the essence is encrypted prior to writing.