+//------------------------------------------------------------------------------------------
+//
+
+//
+class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
+{
+ ASDCP_NO_COPY_CONSTRUCT(h__SWriter);
+ h__SWriter();
+ StereoscopicPhase_t m_NextPhase;
+
+public:
+ h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {}
+
+ //
+ Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
+ AESEncContext* Ctx, HMACContext* HMAC)
+ {
+ if ( m_NextPhase != phase )
+ return RESULT_SPHASE;
+
+ if ( phase == SP_LEFT )
+ {
+ m_NextPhase = SP_RIGHT;
+ return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
+ }
+
+ m_NextPhase = SP_LEFT;
+ return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
+ }
+
+ //
+ Result_t Finalize()
+ {
+ if ( m_NextPhase != SP_LEFT )
+ return RESULT_SPHASE;
+
+ assert( m_FramesWritten % 2 == 0 );
+ m_FramesWritten /= 2;
+ return lh__Writer::Finalize();
+ }
+};
+
+
+//
+ASDCP::JP2K::MXFSWriter::MXFSWriter()
+{
+}
+
+ASDCP::JP2K::MXFSWriter::~MXFSWriter()
+{
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OP1aHeader&
+ASDCP::JP2K::MXFSWriter::OP1aHeader()
+{
+ if ( m_Writer.empty() )
+ {
+ assert(g_OP1aHeader);
+ return *g_OP1aHeader;
+ }
+
+ return m_Writer->m_HeaderPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomIndexFooter&
+ASDCP::JP2K::MXFSWriter::OPAtomIndexFooter()
+{
+ if ( m_Writer.empty() )
+ {
+ assert(g_OPAtomIndexFooter);
+ return *g_OPAtomIndexFooter;
+ }
+
+ return m_Writer->m_FooterPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::RIP&
+ASDCP::JP2K::MXFSWriter::RIP()
+{
+ if ( m_Writer.empty() )
+ {
+ assert(g_RIP);
+ return *g_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
+ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
+ const PictureDescriptor& PDesc, ui32_t HeaderSize)
+{
+ if ( Info.LabelSetType == LS_MXF_SMPTE )
+ m_Writer = new h__SWriter(DefaultSMPTEDict());
+ else
+ m_Writer = new h__SWriter(DefaultInteropDict());
+
+ if ( PDesc.EditRate != ASDCP::EditRate_24
+ && PDesc.EditRate != ASDCP::EditRate_25
+ && PDesc.EditRate != ASDCP::EditRate_30
+ && PDesc.EditRate != ASDCP::EditRate_48
+ && PDesc.EditRate != ASDCP::EditRate_50
+ && PDesc.EditRate != ASDCP::EditRate_60 )
+ {
+ DefaultLogSink().Error("Stereoscopic wrapping requires 24, 25, 30, 48, 50 or 60 fps input streams.\n");
+ 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) )
+ {
+ PictureDescriptor TmpPDesc = PDesc;
+
+ if ( PDesc.EditRate == ASDCP::EditRate_24 )
+ TmpPDesc.EditRate = ASDCP::EditRate_48;
+
+ else if ( PDesc.EditRate == ASDCP::EditRate_25 )
+ TmpPDesc.EditRate = ASDCP::EditRate_50;
+
+ else if ( PDesc.EditRate == ASDCP::EditRate_30 )
+ TmpPDesc.EditRate = ASDCP::EditRate_60;
+
+ else if ( PDesc.EditRate == ASDCP::EditRate_48 )
+ TmpPDesc.EditRate = ASDCP::EditRate_96;
+
+ else if ( PDesc.EditRate == ASDCP::EditRate_50 )
+ TmpPDesc.EditRate = ASDCP::EditRate_100;
+
+ else if ( PDesc.EditRate == ASDCP::EditRate_60 )
+ TmpPDesc.EditRate = ASDCP::EditRate_120;
+
+ result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate);
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ m_Writer.release();
+
+ 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.
+// Fails if the file is not open, is finalized, or an operating system
+// error occurs.
+ASDCP::Result_t
+ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
+ AESEncContext* Ctx, HMACContext* HMAC)
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
+}
+
+// Closes the MXF file, writing the index and other closing information.
+ASDCP::Result_t
+ASDCP::JP2K::MXFSWriter::Finalize()
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->Finalize();
+}
+