2 Copyright (c) 2011-2018, John Hurst
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 3. The name of the author may not be used to endorse or promote products
15 derived from this software without specific prior written permission.
17 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 /*! \file AS_02_PHDR.cpp
30 \brief AS-02 library, JPEG 2000 P-HDR essence reader and writer implementation
33 #include "AS_02_internal.h"
34 #include "AS_02_PHDR.h"
39 using namespace ASDCP;
40 using namespace ASDCP::JP2K;
41 using Kumu::GenRandomValue;
43 //------------------------------------------------------------------------------------------
45 static std::string JP2K_PACKAGE_LABEL = "File Package: PROTOTYPE SMPTE ST 422 / ST 2067-5 frame wrapping of JPEG 2000 codestreams with HDR metadata";
46 static std::string PICT_DEF_LABEL = "PHDR Image Track";
47 static std::string MD_DEF_LABEL = "PHDR Metadata Track";
51 //------------------------------------------------------------------------------------------
55 AS_02::PHDR::FrameBuffer::Dump(FILE* stream, ui32_t dump_bytes) const
60 fprintf(stream, "Frame %d, %d bytes (metadata: %zd bytes)\n", FrameNumber(), Size(), OpaqueMetadata.size());
64 Kumu::hexdump(RoData(), Kumu::xmin(dump_bytes, Size()), stream);
69 //------------------------------------------------------------------------------------------
71 // hidden, internal implementation of JPEG 2000 reader
74 class AS_02::PHDR::MXFReader::h__Reader : public AS_02::h__AS02Reader
76 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
79 h__Reader(const Dictionary& d) :
80 AS_02::h__AS02Reader(d) {}
82 virtual ~h__Reader() {}
84 Result_t OpenRead(const std::string& filename, std::string& PHDR_master_metadata);
85 Result_t ReadFrame(ui32_t, AS_02::PHDR::FrameBuffer&, AESDecContext*, HMACContext*);
90 AS_02::PHDR::MXFReader::h__Reader::OpenRead(const std::string& filename, std::string& PHDR_master_metadata)
92 Result_t result = OpenMXFRead(filename.c_str());
93 ui32_t SimplePayloadSID = 0;
95 if( KM_SUCCESS(result) )
97 InterchangeObject* tmp_iobj = 0;
99 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CDCIEssenceDescriptor), &tmp_iobj);
103 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
108 DefaultLogSink().Error("RGBAEssenceDescriptor nor CDCIEssenceDescriptor found.\n");
109 return RESULT_AS02_FORMAT;
112 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
116 DefaultLogSink().Error("JPEG2000PictureSubDescriptor not found.\n");
117 return RESULT_AS02_FORMAT;
120 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(PHDRMetadataTrackSubDescriptor), &tmp_iobj);
124 DefaultLogSink().Error("PHDRMetadataTrackSubDescriptor not found.\n");
125 return RESULT_AS02_FORMAT;
129 PHDRMetadataTrackSubDescriptor *tmp_desc = dynamic_cast<PHDRMetadataTrackSubDescriptor*>(tmp_iobj);
131 SimplePayloadSID = tmp_desc->SimplePayloadSID;
134 std::list<InterchangeObject*> ObjectList;
135 m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
137 if ( ObjectList.empty() )
139 DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
140 return RESULT_AS02_FORMAT;
144 // if PHDRSimplePayload exists, go get it
145 if ( KM_SUCCESS(result) && SimplePayloadSID )
147 RIP::const_pair_iterator pi;
148 RIP::PartitionPair TmpPair;
150 // Look up the partition start in the RIP using the SID.
151 for ( pi = m_RIP.PairArray.begin(); pi != m_RIP.PairArray.end(); ++pi )
153 if ( (*pi).BodySID == SimplePayloadSID )
160 if ( TmpPair.ByteOffset == 0 )
162 DefaultLogSink().Error("Body SID not found in RIP set: %d\n", SimplePayloadSID);
163 return RESULT_AS02_FORMAT;
166 // seek to the start of the partition
167 if ( (Kumu::fpos_t)TmpPair.ByteOffset != m_LastPosition )
169 m_LastPosition = TmpPair.ByteOffset;
170 result = m_File.Seek(TmpPair.ByteOffset);
173 // read the partition header
174 ASDCP::MXF::Partition GSPart(m_Dict);
175 result = GSPart.InitFromFile(m_File);
177 if ( KM_SUCCESS(result) )
179 // read the generic stream packet
180 if ( KM_SUCCESS(result) )
182 ASDCP::FrameBuffer tmp_buf;
183 tmp_buf.Capacity(Kumu::Megabyte);
185 result = Read_EKLV_Packet(m_File, *m_Dict, m_Info, m_LastPosition, m_CtFrameBuf,
186 0, 0, tmp_buf, m_Dict->ul(MDD_GenericStream_DataElement), 0, 0);
188 if ( KM_SUCCESS(result) )
190 PHDR_master_metadata.assign((const char*)tmp_buf.RoData(), tmp_buf.Size());
202 AS_02::PHDR::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, AS_02::PHDR::FrameBuffer& FrameBuf,
203 ASDCP::AESDecContext* Ctx, ASDCP::HMACContext* HMAC)
205 if ( ! m_File.IsOpen() )
209 Result_t result = ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
211 if ( KM_SUCCESS(result) )
213 ASDCP::FrameBuffer tmp_metadata_buffer;
214 tmp_metadata_buffer.Capacity(8192);
216 result = Read_EKLV_Packet(m_File, *m_Dict, m_Info, m_LastPosition, m_CtFrameBuf,
217 FrameNum, FrameNum + 1, tmp_metadata_buffer, m_Dict->ul(MDD_PHDRImageMetadataItem), Ctx, HMAC);
219 if ( KM_SUCCESS(result) )
221 FrameBuf.OpaqueMetadata.assign((const char*)tmp_metadata_buffer.RoData(), tmp_metadata_buffer.Size());
225 DefaultLogSink().Error("Metadata packet not found at frame %d.\n", FrameNum);
233 //------------------------------------------------------------------------------------------
236 AS_02::PHDR::MXFReader::MXFReader()
238 m_Reader = new h__Reader(DefaultCompositeDict());
242 AS_02::PHDR::MXFReader::~MXFReader()
246 // Warning: direct manipulation of MXF structures can interfere
247 // with the normal operation of the wrapper. Caveat emptor!
249 ASDCP::MXF::OP1aHeader&
250 AS_02::PHDR::MXFReader::OP1aHeader()
252 if ( m_Reader.empty() )
254 assert(g_OP1aHeader);
255 return *g_OP1aHeader;
258 return m_Reader->m_HeaderPart;
261 // Warning: direct manipulation of MXF structures can interfere
262 // with the normal operation of the wrapper. Caveat emptor!
264 AS_02::MXF::AS02IndexReader&
265 AS_02::PHDR::MXFReader::AS02IndexReader()
267 if ( m_Reader.empty() )
269 assert(g_AS02IndexReader);
270 return *g_AS02IndexReader;
273 return m_Reader->m_IndexAccess;
276 // Warning: direct manipulation of MXF structures can interfere
277 // with the normal operation of the wrapper. Caveat emptor!
280 AS_02::PHDR::MXFReader::RIP()
282 if ( m_Reader.empty() )
288 return m_Reader->m_RIP;
291 // Open the file for reading. The file must exist. Returns error if the
292 // operation cannot be completed.
294 AS_02::PHDR::MXFReader::OpenRead(const std::string& filename, std::string& PHDR_master_metadata) const
296 return m_Reader->OpenRead(filename, PHDR_master_metadata);
301 AS_02::PHDR::MXFReader::Close() const
303 if ( m_Reader && m_Reader->m_File.IsOpen() )
314 AS_02::PHDR::MXFReader::ReadFrame(ui32_t FrameNum, AS_02::PHDR::FrameBuffer& FrameBuf,
315 ASDCP::AESDecContext* Ctx, ASDCP::HMACContext* HMAC) const
317 if ( m_Reader && m_Reader->m_File.IsOpen() )
318 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
323 // Fill the struct with the values from the file's header.
324 // Returns RESULT_INIT if the file is not open.
326 AS_02::PHDR::MXFReader::FillWriterInfo(WriterInfo& Info) const
328 if ( m_Reader && m_Reader->m_File.IsOpen() )
330 Info = m_Reader->m_Info;
338 //------------------------------------------------------------------------------------------
341 class AS_02::PHDR::MXFWriter::h__Writer : public AS_02::h__AS02WriterFrame
343 PHDRMetadataTrackSubDescriptor *m_MetadataTrackSubDescriptor;
345 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
348 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
350 Result_t WritePHDRHeader(const std::string& PackageLabel, const ASDCP::UL& WrappingUL,
351 const std::string& TrackName, const ASDCP::UL& EssenceUL,
352 const ASDCP::UL& DataDefinition, const ASDCP::Rational& EditRate,
353 const ui32_t& TCFrameRate);
356 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
357 byte_t m_MetadataUL[SMPTE_UL_LENGTH];
359 h__Writer(const Dictionary& d) : h__AS02WriterFrame(d), m_EssenceSubDescriptor(0), m_MetadataTrackSubDescriptor(0) {
360 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
361 memset(m_MetadataUL, 0, SMPTE_UL_LENGTH);
364 virtual ~h__Writer(){}
366 Result_t OpenWrite(const std::string&, ASDCP::MXF::FileDescriptor* essence_descriptor,
367 ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
368 const AS_02::IndexStrategy_t& IndexStrategy,
369 const ui32_t& PartitionSpace, const ui32_t& HeaderSize);
370 Result_t SetSourceStream(const std::string& label, const ASDCP::Rational& edit_rate);
371 Result_t WriteFrame(const AS_02::PHDR::FrameBuffer&, ASDCP::AESEncContext*, ASDCP::HMACContext*);
372 Result_t Finalize(const std::string& PHDR_master_metadata);
376 // Open the file for writing. The file must not exist. Returns error if
377 // the operation cannot be completed.
379 AS_02::PHDR::MXFWriter::h__Writer::OpenWrite(const std::string& filename,
380 ASDCP::MXF::FileDescriptor* essence_descriptor,
381 ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
382 const AS_02::IndexStrategy_t& IndexStrategy,
383 const ui32_t& PartitionSpace_sec, const ui32_t& HeaderSize)
385 if ( ! m_State.Test_BEGIN() )
390 if ( m_IndexStrategy != AS_02::IS_FOLLOW )
392 DefaultLogSink().Error("Only strategy IS_FOLLOW is supported at this time.\n");
393 return Kumu::RESULT_NOTIMPL;
396 Result_t result = m_File.OpenWrite(filename);
398 if ( KM_SUCCESS(result) )
400 m_IndexStrategy = IndexStrategy;
401 m_PartitionSpace = PartitionSpace_sec; // later converted to edit units by WritePHDRHeader()
402 m_HeaderSize = HeaderSize;
404 if ( essence_descriptor->GetUL() != UL(m_Dict->ul(MDD_RGBAEssenceDescriptor))
405 && essence_descriptor->GetUL() != UL(m_Dict->ul(MDD_CDCIEssenceDescriptor)) )
407 DefaultLogSink().Error("Essence descriptor is not a RGBAEssenceDescriptor or CDCIEssenceDescriptor.\n");
408 essence_descriptor->Dump();
409 return RESULT_AS02_FORMAT;
412 m_EssenceDescriptor = essence_descriptor;
414 ASDCP::MXF::InterchangeObject_list_t::iterator i;
415 for ( i = essence_sub_descriptor_list.begin(); i != essence_sub_descriptor_list.end(); ++i )
417 if ( (*i)->GetUL() != UL(m_Dict->ul(MDD_JPEG2000PictureSubDescriptor)) )
419 DefaultLogSink().Error("Essence sub-descriptor is not a JPEG2000PictureSubDescriptor.\n");
423 m_EssenceSubDescriptorList.push_back(*i);
424 GenRandomValue((*i)->InstanceUID);
425 m_EssenceDescriptor->SubDescriptors.push_back((*i)->InstanceUID);
426 *i = 0; // parent will only free the ones we don't keep
429 result = m_State.Goto_INIT();
435 // all the above for a single source clip
437 AS_02::PHDR::MXFWriter::h__Writer::WritePHDRHeader(const std::string& PackageLabel, const ASDCP::UL& WrappingUL,
438 const std::string& TrackName, const ASDCP::UL& EssenceUL,
439 const ASDCP::UL& DataDefinition, const ASDCP::Rational& EditRate,
440 const ui32_t& TCFrameRate)
442 if ( EditRate.Numerator == 0 || EditRate.Denominator == 0 )
444 DefaultLogSink().Error("Non-zero edit-rate reqired.\n");
448 InitHeader(MXFVersion_2011);
450 AddSourceClip(EditRate, EditRate/*TODO: for a moment*/, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel);
452 // add metadata track
453 TrackSet<SourceClip> metdata_track =
454 CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
455 MD_DEF_LABEL, EditRate,
456 UL(m_Dict->ul(MDD_PHDRImageMetadataItem)),
457 3 /* track id */, m_Dict);
459 metdata_track.Sequence->Duration.set_has_value();
460 m_DurationUpdateList.push_back(&(metdata_track.Sequence->Duration.get()));
461 // Consult ST 379:2004 Sec. 6.3, "Element to track relationship" to see where "12" comes from.
462 metdata_track.Track->TrackNumber = KM_i32_BE(Kumu::cp2i<ui32_t>((UL(m_MetadataUL).Value() + 12)));
464 metdata_track.Clip = new SourceClip(m_Dict);
465 m_HeaderPart.AddChildObject(metdata_track.Clip);
466 metdata_track.Sequence->StructuralComponents.push_back(metdata_track.Clip->InstanceUID);
467 metdata_track.Clip->DataDefinition = UL(m_Dict->ul(MDD_PHDRImageMetadataWrappingFrame));
469 // for now we do not allow setting this value, so all files will be 'original'
470 metdata_track.Clip->SourceTrackID = 0;
471 metdata_track.Clip->SourcePackageID = NilUMID;
473 metdata_track.Clip->Duration.set_has_value();
474 m_DurationUpdateList.push_back(&(metdata_track.Clip->Duration.get()));
476 // add PHDR subdescriptor
477 m_MetadataTrackSubDescriptor = new PHDRMetadataTrackSubDescriptor(m_Dict);
478 m_EssenceSubDescriptorList.push_back(m_MetadataTrackSubDescriptor);
479 GenRandomValue(m_MetadataTrackSubDescriptor->InstanceUID);
480 m_EssenceDescriptor->SubDescriptors.push_back(m_MetadataTrackSubDescriptor->InstanceUID);
481 m_MetadataTrackSubDescriptor->DataDefinition = UL(m_Dict->ul(MDD_PHDRImageMetadataWrappingFrame));
482 m_MetadataTrackSubDescriptor->SourceTrackID = 3;
483 m_MetadataTrackSubDescriptor->SimplePayloadSID = 0;
485 AddEssenceDescriptor(WrappingUL);
487 m_IndexWriter.SetPrimerLookup(&m_HeaderPart.m_Primer);
488 m_RIP.PairArray.push_back(RIP::PartitionPair(0, 0)); // Header partition RIP entry
489 m_IndexWriter.OperationalPattern = m_HeaderPart.OperationalPattern;
490 m_IndexWriter.EssenceContainers = m_HeaderPart.EssenceContainers;
492 Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
494 if ( KM_SUCCESS(result) )
496 m_PartitionSpace *= floor( EditRate.Quotient() + 0.5 ); // convert seconds to edit units
497 m_ECStart = m_File.Tell();
498 m_IndexWriter.IndexSID = 129;
500 UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
501 Partition body_part(m_Dict);
502 body_part.BodySID = 1;
503 body_part.MajorVersion = m_HeaderPart.MajorVersion;
504 body_part.MinorVersion = m_HeaderPart.MinorVersion;
505 body_part.OperationalPattern = m_HeaderPart.OperationalPattern;
506 body_part.EssenceContainers = m_HeaderPart.EssenceContainers;
507 body_part.ThisPartition = m_ECStart;
508 result = body_part.WriteToFile(m_File, body_ul);
509 m_RIP.PairArray.push_back(RIP::PartitionPair(1, body_part.ThisPartition)); // Second RIP Entry
515 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
517 AS_02::PHDR::MXFWriter::h__Writer::SetSourceStream(const std::string& label, const ASDCP::Rational& edit_rate)
520 if ( ! m_State.Test_INIT() )
525 memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
526 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first track of the essence container
528 memcpy(m_MetadataUL, m_Dict->ul(MDD_PHDRImageMetadataItem), SMPTE_UL_LENGTH);
529 m_MetadataUL[SMPTE_UL_LENGTH-1] = 3; // third track of the essence container
531 Result_t result = m_State.Goto_READY();
533 if ( KM_SUCCESS(result) )
535 result = WritePHDRHeader(label, UL(m_Dict->ul(MDD_MXFGCFUFrameWrappedPictureElement)),
536 PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
537 edit_rate, derive_timecode_rate_from_edit_rate(edit_rate));
539 if ( KM_SUCCESS(result) )
541 this->m_IndexWriter.SetPrimerLookup(&this->m_HeaderPart.m_Primer);
548 // Writes a frame of essence to the MXF file. If the optional AESEncContext
549 // argument is present, the essence is encrypted prior to writing.
550 // Fails if the file is not open, is finalized, or an operating system
554 AS_02::PHDR::MXFWriter::h__Writer::WriteFrame(const AS_02::PHDR::FrameBuffer& FrameBuf,
555 AESEncContext* Ctx, HMACContext* HMAC)
557 if ( FrameBuf.Size() == 0 )
559 DefaultLogSink().Error("The frame buffer size is zero.\n");
563 Result_t result = RESULT_OK;
565 if ( m_State.Test_READY() )
567 result = m_State.Goto_RUNNING(); // first time through
570 if ( KM_SUCCESS(result) )
572 ui64_t this_stream_offset = m_StreamOffset; // m_StreamOffset will be changed by the call to Write_EKLV_Packet
574 result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
575 m_StreamOffset, FrameBuf, m_EssenceUL, MXF_BER_LENGTH, Ctx, HMAC);
577 if ( KM_SUCCESS(result) )
579 ASDCP::FrameBuffer metadata_buffer_wrapper;
580 metadata_buffer_wrapper.SetData((byte_t*)(FrameBuf.OpaqueMetadata.c_str()), FrameBuf.OpaqueMetadata.size());
581 metadata_buffer_wrapper.Size(FrameBuf.OpaqueMetadata.size());
584 result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
585 m_StreamOffset, metadata_buffer_wrapper, m_MetadataUL,
586 MXF_BER_LENGTH, Ctx, HMAC);
589 if ( KM_SUCCESS(result) )
591 IndexTableSegment::IndexEntry Entry;
592 Entry.StreamOffset = this_stream_offset;
593 m_IndexWriter.PushIndexEntry(Entry);
596 if ( m_FramesWritten > 1 && ( ( m_FramesWritten + 1 ) % m_PartitionSpace ) == 0 )
598 assert(m_IndexWriter.GetDuration() > 0);
599 FlushIndexPartition();
601 UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
602 Partition body_part(m_Dict);
603 body_part.BodySID = 1;
604 body_part.MajorVersion = m_HeaderPart.MajorVersion;
605 body_part.MinorVersion = m_HeaderPart.MinorVersion;
606 body_part.OperationalPattern = m_HeaderPart.OperationalPattern;
607 body_part.EssenceContainers = m_HeaderPart.EssenceContainers;
608 body_part.ThisPartition = m_File.Tell();
610 body_part.BodyOffset = m_StreamOffset;
611 result = body_part.WriteToFile(m_File, body_ul);
612 m_RIP.PairArray.push_back(RIP::PartitionPair(1, body_part.ThisPartition));
616 if ( KM_SUCCESS(result) )
624 // Closes the MXF file, writing the index and other closing information.
627 AS_02::PHDR::MXFWriter::h__Writer::Finalize(const std::string& PHDR_master_metadata)
629 if ( ! m_State.Test_RUNNING() )
631 KM_RESULT_STATE_HERE();
635 Result_t result = m_State.Goto_FINAL();
637 if ( KM_SUCCESS(result) )
639 FlushIndexPartition();
641 if ( ! PHDR_master_metadata.empty() )
643 // write PHDRSimplePayload
644 Kumu::fpos_t here = m_File.Tell();
646 // create generic stream partition header
647 static UL GenericStream_DataElement(m_Dict->ul(MDD_GenericStream_DataElement));
648 ASDCP::MXF::Partition GSPart(m_Dict);
650 GSPart.MajorVersion = m_HeaderPart.MajorVersion;
651 GSPart.MinorVersion = m_HeaderPart.MinorVersion;
652 GSPart.ThisPartition = here;
653 GSPart.PreviousPartition = m_RIP.PairArray.back().ByteOffset;
654 GSPart.OperationalPattern = m_HeaderPart.OperationalPattern;
656 m_MetadataTrackSubDescriptor->SimplePayloadSID = 2;
658 m_RIP.PairArray.push_back(RIP::PartitionPair(2, here));
659 GSPart.EssenceContainers = m_HeaderPart.EssenceContainers;
661 static UL gs_part_ul(m_Dict->ul(MDD_GenericStreamPartition));
662 Result_t result = GSPart.WriteToFile(m_File, gs_part_ul);
664 if ( KM_SUCCESS(result) )
666 ASDCP::FrameBuffer tmp_buf;
667 tmp_buf.SetData((byte_t*)PHDR_master_metadata.c_str(), PHDR_master_metadata.size());
668 tmp_buf.Size(PHDR_master_metadata.size());
670 result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
671 m_StreamOffset, tmp_buf, GenericStream_DataElement.Value(),
672 MXF_BER_LENGTH, 0, 0);
676 result = WriteAS02Footer();
683 //------------------------------------------------------------------------------------------
687 AS_02::PHDR::MXFWriter::MXFWriter()
691 AS_02::PHDR::MXFWriter::~MXFWriter()
695 // Warning: direct manipulation of MXF structures can interfere
696 // with the normal operation of the wrapper. Caveat emptor!
698 ASDCP::MXF::OP1aHeader&
699 AS_02::PHDR::MXFWriter::OP1aHeader()
701 if ( m_Writer.empty() )
703 assert(g_OP1aHeader);
704 return *g_OP1aHeader;
707 return m_Writer->m_HeaderPart;
710 // Warning: direct manipulation of MXF structures can interfere
711 // with the normal operation of the wrapper. Caveat emptor!
714 AS_02::PHDR::MXFWriter::RIP()
716 if ( m_Writer.empty() )
722 return m_Writer->m_RIP;
725 // Open the file for writing. The file must not exist. Returns error if
726 // the operation cannot be completed.
728 AS_02::PHDR::MXFWriter::OpenWrite(const std::string& filename, const ASDCP::WriterInfo& Info,
729 ASDCP::MXF::FileDescriptor* essence_descriptor,
730 ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
731 const ASDCP::Rational& edit_rate, const ui32_t& header_size,
732 const IndexStrategy_t& strategy, const ui32_t& partition_space)
734 if ( essence_descriptor == 0 )
736 DefaultLogSink().Error("Essence descriptor object required.\n");
740 m_Writer = new AS_02::PHDR::MXFWriter::h__Writer(DefaultSMPTEDict());
741 m_Writer->m_Info = Info;
743 Result_t result = m_Writer->OpenWrite(filename, essence_descriptor, essence_sub_descriptor_list,
744 strategy, partition_space, header_size);
746 if ( KM_SUCCESS(result) )
747 result = m_Writer->SetSourceStream(JP2K_PACKAGE_LABEL, edit_rate);
749 if ( KM_FAILURE(result) )
755 // Writes a frame of essence to the MXF file. If the optional AESEncContext
756 // argument is present, the essence is encrypted prior to writing.
757 // Fails if the file is not open, is finalized, or an operating system
760 AS_02::PHDR::MXFWriter::WriteFrame(const AS_02::PHDR::FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
762 if ( m_Writer.empty() )
765 return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
768 // Closes the MXF file, writing the index and other closing information.
770 AS_02::PHDR::MXFWriter::Finalize(const std::string& PHDR_master_metadata)
772 if ( m_Writer.empty() )
775 return m_Writer->Finalize(PHDR_master_metadata);
780 // end AS_02_PHDR.cpp