Allow incremental writing of picture MXFs.
authorCarl Hetherington <cth@carlh.net>
Fri, 18 Jan 2013 20:25:02 +0000 (20:25 +0000)
committerCarl Hetherington <cth@carlh.net>
Fri, 18 Jan 2013 20:25:02 +0000 (20:25 +0000)
asdcplib/src/AS_DCP.h
asdcplib/src/JP2K_Codestream_Parser.cpp
src/asset.h
src/mxf_asset.cc
src/mxf_asset.h
src/picture_asset.cc
src/picture_asset.h
src/sound_asset.cc

index b227c0637997cbfabfd5bd7c723fa2302f06daab..3d679413f912c30945168ddb3c56c8ce912289d7 100755 (executable)
@@ -1090,6 +1090,8 @@ namespace ASDCP {
          // encrypted headers.
          Result_t OpenReadFrame(const char* filename, FrameBuffer&) const;
 
+         Result_t OpenReadFrame(const unsigned char * data, unsigned int size, FrameBuffer&) const;
+
          // Fill a PictureDescriptor struct with the values from the file's codestream.
          // Returns RESULT_INIT if the file is not open.
          Result_t FillPictureDescriptor(PictureDescriptor&) const;
index c78912318b245f6bca0ab4783c80c10690a1f670..5ab7a3221a80f1ec6c82db1bf77622d32285dd48 100755 (executable)
@@ -91,6 +91,26 @@ public:
 
     return result;
   }
+
+  Result_t OpenReadFrame(const unsigned char * data, unsigned int size, FrameBuffer& FB)
+  {
+    if ( FB.Capacity() < size )
+      {
+        DefaultLogSink().Error("FrameBuf.Capacity: %u frame length: %u\n", FB.Capacity(), (ui32_t) size);
+        return RESULT_SMALLBUF;
+      }
+
+    memcpy (FB.Data(), data, size);
+    FB.Size(size);
+
+    byte_t start_of_data = 0; // out param
+    const Result_t result = ParseMetadataIntoDesc(FB, m_PDesc, &start_of_data);
+
+    if ( ASDCP_SUCCESS(result) )
+      FB.PlaintextOffset(start_of_data);
+
+    return result;
+  }    
 };
 
 ASDCP::Result_t
@@ -224,6 +244,15 @@ ASDCP::JP2K::CodestreamParser::OpenReadFrame(const char* filename, FrameBuffer&
   return m_Parser->OpenReadFrame(filename, FB);
 }
 
+// Opens the stream for reading, parses enough data to provide a complete
+// set of stream metadata for the MXFWriter below.
+ASDCP::Result_t
+ASDCP::JP2K::CodestreamParser::OpenReadFrame(const unsigned char* data, unsigned int size, FrameBuffer& FB) const
+{
+  const_cast<ASDCP::JP2K::CodestreamParser*>(this)->m_Parser = new h__CodestreamParser;
+  return m_Parser->OpenReadFrame(data, size, FB);
+}
+
 //
 ASDCP::Result_t
 ASDCP::JP2K::CodestreamParser::FillPictureDescriptor(PictureDescriptor& PDesc) const
index cc6fbcb7c374f7ec06ed98afd004fc2b3e875d1b..3ba0a0cf49930baebcff6bc95ceb19d7c4e1aecf 100644 (file)
@@ -70,14 +70,13 @@ public:
                return _uuid;
        }
 
+       boost::filesystem::path path () const;
+       
        virtual bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, std::list<std::string>& notes) const = 0;
 
 protected:
-       friend class PictureAsset;
-       friend class SoundAsset;
        
        std::string digest () const;
-       boost::filesystem::path path () const;
 
        /** Directory that our MXF or XML file is in */
        std::string _directory;
index 77e4b098910d65395242bb54fdea4db7eea103e9..af3c74dc79c7b53e522ecb41849ecd49241184f0 100644 (file)
@@ -60,7 +60,7 @@ MXFAsset::set_duration (int d)
 }
 
 void
-MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info) const
+MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info, string uuid)
 {
        writer_info->ProductVersion = Metadata::instance()->product_version;
        writer_info->CompanyName = Metadata::instance()->company_name;
@@ -68,7 +68,7 @@ MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info) const
 
        writer_info->LabelSetType = ASDCP::LS_MXF_SMPTE;
        unsigned int c;
-       Kumu::hex2bin (_uuid.c_str(), writer_info->AssetUUID, Kumu::UUID_Length, &c);
+       Kumu::hex2bin (uuid.c_str(), writer_info->AssetUUID, Kumu::UUID_Length, &c);
        assert (c == Kumu::UUID_Length);
 }
 
index 9526135382d6adad966e745603fe8dcc5e0a77b5..fd786cc683190e3867777bf24c94582cea978fbb 100644 (file)
@@ -45,12 +45,21 @@ public:
        virtual bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, std::list<std::string>& notes) const;
        
        int intrinsic_duration () const;
+       int frames_per_second () const {
+               return _fps;
+       }
+
+       void set_intrinsic_duration (int d) {
+               _intrinsic_duration = d;
+       }
 
-protected:
        /** Fill in a ADSCP::WriteInfo struct.
         *  @param w struct to fill in.
+        *  @param uuid uuid to use.
         */
-       void fill_writer_info (ASDCP::WriterInfo* w) const;
+       static void fill_writer_info (ASDCP::WriterInfo* w, std::string uuid);
+
+protected:
 
        /** Signal to emit to report progress */
        boost::signals2::signal<void (float)>* _progress;
index 3058c13d67bf77bfacc0a8c10af4fb72ef0bbb5d..f3d523963abec33620447b14e51aa1b5b93dcae3 100644 (file)
@@ -46,8 +46,9 @@ using boost::dynamic_pointer_cast;
 using boost::lexical_cast;
 using namespace libdcp;
 
-PictureAsset::PictureAsset (string directory, string mxf_name, boost::signals2::signal<void (float)>* progress, int fps, int intrinsic_duration)
+PictureAsset::PictureAsset (string directory, string mxf_name, boost::signals2::signal<void (float)>* progress, int fps, int intrinsic_duration, Size size)
        : MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration)
+       , _size (size)
 {
 
 }
@@ -136,9 +137,8 @@ MonoPictureAsset::MonoPictureAsset (
        int fps,
        int intrinsic_duration,
        Size size)
-       : PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration)
+       : PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration, size)
 {
-       _size = size;
        construct (get_path);
 }
 
@@ -150,14 +150,19 @@ MonoPictureAsset::MonoPictureAsset (
        int fps,
        int intrinsic_duration,
        Size size)
-       : PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration)
+       : PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration, size)
 {
-       _size = size;
        construct (boost::bind (&MonoPictureAsset::path_from_list, this, _1, files));
 }
 
+MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name, int fps, Size size)
+       : PictureAsset (directory, mxf_name, 0, fps, 0, size)
+{
+
+}
+
 MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name, int fps, int intrinsic_duration)
-       : PictureAsset (directory, mxf_name, 0, fps, intrinsic_duration)
+       : PictureAsset (directory, mxf_name, 0, fps, intrinsic_duration, Size (0, 0))
 {
        ASDCP::JP2K::MXFReader reader;
        if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) {
@@ -187,7 +192,7 @@ MonoPictureAsset::construct (boost::function<string (int)> get_path)
        picture_desc.EditRate = ASDCP::Rational (_fps, 1);
        
        ASDCP::WriterInfo writer_info;
-       fill_writer_info (&writer_info);
+       fill_writer_info (&writer_info, _uuid);
        
        ASDCP::JP2K::MXFWriter mxf_writer;
        if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, picture_desc))) {
@@ -357,7 +362,7 @@ PictureAsset::frame_buffer_equals (
 
 
 StereoPictureAsset::StereoPictureAsset (string directory, string mxf_name, int fps, int intrinsic_duration)
-       : PictureAsset (directory, mxf_name, 0, fps, intrinsic_duration)
+       : PictureAsset (directory, mxf_name, 0, fps, intrinsic_duration, Size (0, 0))
 {
        ASDCP::JP2K::MXFSReader reader;
        if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) {
@@ -378,3 +383,60 @@ StereoPictureAsset::get_frame (int n) const
 {
        return shared_ptr<const StereoPictureFrame> (new StereoPictureFrame (path().string(), n + _entry_point));
 }
+
+shared_ptr<MonoPictureAssetWriter>
+MonoPictureAsset::start_write ()
+{
+       /* XXX: can't we use a shared_ptr here? */
+       return shared_ptr<MonoPictureAssetWriter> (new MonoPictureAssetWriter (this));
+}
+
+MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* a)
+       : _frame_buffer (4 * Kumu::Megabyte)
+       , _asset (a)
+       , _frames_written (0)
+       , _finalized (false)
+{
+
+}
+
+void
+MonoPictureAssetWriter::write (uint8_t* data, int size)
+{
+       if (ASDCP_FAILURE (_j2k_parser.OpenReadFrame (data, size, _frame_buffer))) {
+               throw MiscError ("could not parse J2K frame");
+       }
+
+       if (_frames_written == 0) {
+               _j2k_parser.FillPictureDescriptor (_picture_descriptor);
+               _picture_descriptor.EditRate = ASDCP::Rational (_asset->frames_per_second(), 1);
+       
+               MXFAsset::fill_writer_info (&_writer_info, _asset->uuid());
+               
+               if (ASDCP_FAILURE (_mxf_writer.OpenWrite (_asset->path().c_str(), _writer_info, _picture_descriptor))) {
+                       throw MXFFileError ("could not open MXF file for writing", _asset->path().string());
+               }
+       }
+
+       if (ASDCP_FAILURE (_mxf_writer.WriteFrame (_frame_buffer, 0, 0))) {
+               throw MiscError ("error in writing video MXF");
+       }
+
+       _frames_written++;
+}
+
+void
+MonoPictureAssetWriter::finalize ()
+{
+       if (ASDCP_FAILURE (_mxf_writer.Finalize())) {
+               throw MiscError ("error in finalizing video MXF");
+       }
+
+       _finalized = true;
+       _asset->set_intrinsic_duration (_frames_written);
+}
+
+MonoPictureAssetWriter::~MonoPictureAssetWriter ()
+{
+       assert (_finalized);
+}
index d2c6f656a546662a5c3b2bd26eea4ab8c492c46c..059e5926b8788c4964e1a89db900655229053165 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <openjpeg.h>
+#include "AS_DCP.h"
 #include "mxf_asset.h"
 #include "util.h"
 
@@ -35,7 +36,7 @@ class StereoPictureFrame;
 class PictureAsset : public MXFAsset
 {
 public:
-       PictureAsset (std::string directory, std::string mxf_name, boost::signals2::signal<void (float)>* progress, int fps, int intrinsic_duration);
+       PictureAsset (std::string directory, std::string mxf_name, boost::signals2::signal<void (float)>* progress, int fps, int intrinsic_duration, Size size);
        
        /** Write details of this asset to a CPL stream.
         *  @param s Stream.
@@ -59,6 +60,31 @@ protected:
        Size _size;
 };
 
+class MonoPictureAsset;
+
+class MonoPictureAssetWriter
+{
+public:
+       ~MonoPictureAssetWriter ();
+
+       void write (uint8_t* data, int size);
+       void finalize ();
+
+private:
+       friend class MonoPictureAsset;
+       
+       MonoPictureAssetWriter (MonoPictureAsset *);
+
+       ASDCP::JP2K::CodestreamParser _j2k_parser;
+       ASDCP::JP2K::FrameBuffer _frame_buffer;
+       ASDCP::JP2K::MXFWriter _mxf_writer;
+       ASDCP::WriterInfo _writer_info;
+       ASDCP::JP2K::PictureDescriptor _picture_descriptor;
+       MonoPictureAsset* _asset;
+       int _frames_written;
+       bool _finalized;
+};
+
 /** A 2D (monoscopic) picture asset */
 class MonoPictureAsset : public PictureAsset
 {
@@ -103,6 +129,15 @@ public:
                Size size
                );
 
+       MonoPictureAsset (
+               std::string directory,
+               std::string mxf_name,
+               int fps,
+               Size size
+               );
+
+       boost::shared_ptr<MonoPictureAssetWriter> start_write ();
+
        MonoPictureAsset (std::string directory, std::string mxf_name, int fps, int intrinsic_duration);
        
        boost::shared_ptr<const MonoPictureFrame> get_frame (int n) const;
index be77739adb590e7bb62f86dcb3371dfc257bfb00..04ca88da3a7a22cf2a6c36598d7a9066d2e340f6 100644 (file)
@@ -157,7 +157,7 @@ SoundAsset::construct (boost::function<string (Channel)> get_path)
        frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (audio_desc));
 
        ASDCP::WriterInfo writer_info;
-       fill_writer_info (&writer_info);
+       fill_writer_info (&writer_info, _uuid);
 
        ASDCP::PCM::MXFWriter mxf_writer;
        if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, audio_desc))) {