2 Copyright (c) 2011-2015, 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
29 \version $Id: AS_02_PHDR.cpp,v 1.7 2015/10/09 23:41:11 jhurst Exp $
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");
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.OperationalPattern = m_HeaderPart.OperationalPattern;
504 body_part.EssenceContainers = m_HeaderPart.EssenceContainers;
505 body_part.ThisPartition = m_ECStart;
506 result = body_part.WriteToFile(m_File, body_ul);
507 m_RIP.PairArray.push_back(RIP::PartitionPair(1, body_part.ThisPartition)); // Second RIP Entry
513 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
515 AS_02::PHDR::MXFWriter::h__Writer::SetSourceStream(const std::string& label, const ASDCP::Rational& edit_rate)
518 if ( ! m_State.Test_INIT() )
523 memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
524 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first track of the essence container
526 memcpy(m_MetadataUL, m_Dict->ul(MDD_PHDRImageMetadataItem), SMPTE_UL_LENGTH);
527 m_MetadataUL[SMPTE_UL_LENGTH-1] = 3; // third track of the essence container
529 Result_t result = m_State.Goto_READY();
531 if ( KM_SUCCESS(result) )
533 result = WritePHDRHeader(label, UL(m_Dict->ul(MDD_JPEG_2000WrappingFrame)),
534 PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
535 edit_rate, derive_timecode_rate_from_edit_rate(edit_rate));
537 if ( KM_SUCCESS(result) )
539 this->m_IndexWriter.SetPrimerLookup(&this->m_HeaderPart.m_Primer);
546 // Writes a frame of essence to the MXF file. If the optional AESEncContext
547 // argument is present, the essence is encrypted prior to writing.
548 // Fails if the file is not open, is finalized, or an operating system
552 AS_02::PHDR::MXFWriter::h__Writer::WriteFrame(const AS_02::PHDR::FrameBuffer& FrameBuf,
553 AESEncContext* Ctx, HMACContext* HMAC)
555 if ( FrameBuf.Size() == 0 )
557 DefaultLogSink().Error("The frame buffer size is zero.\n");
561 Result_t result = RESULT_OK;
563 if ( m_State.Test_READY() )
565 result = m_State.Goto_RUNNING(); // first time through
568 if ( KM_SUCCESS(result) )
570 ui64_t this_stream_offset = m_StreamOffset; // m_StreamOffset will be changed by the call to Write_EKLV_Packet
572 result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
573 m_StreamOffset, FrameBuf, m_EssenceUL, Ctx, HMAC);
575 if ( KM_SUCCESS(result) )
577 ASDCP::FrameBuffer metadata_buffer_wrapper;
578 metadata_buffer_wrapper.SetData((byte_t*)(FrameBuf.OpaqueMetadata.c_str()), FrameBuf.OpaqueMetadata.size());
579 metadata_buffer_wrapper.Size(FrameBuf.OpaqueMetadata.size());
582 result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
583 m_StreamOffset, metadata_buffer_wrapper, m_MetadataUL, Ctx, HMAC);
586 if ( KM_SUCCESS(result) )
588 IndexTableSegment::IndexEntry Entry;
589 Entry.StreamOffset = this_stream_offset;
590 m_IndexWriter.PushIndexEntry(Entry);
593 if ( m_FramesWritten > 1 && ( ( m_FramesWritten + 1 ) % m_PartitionSpace ) == 0 )
595 m_IndexWriter.ThisPartition = m_File.Tell();
596 m_IndexWriter.WriteToFile(m_File);
597 m_RIP.PairArray.push_back(RIP::PartitionPair(0, m_IndexWriter.ThisPartition));
599 UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
600 Partition body_part(m_Dict);
601 body_part.BodySID = 1;
602 body_part.OperationalPattern = m_HeaderPart.OperationalPattern;
603 body_part.EssenceContainers = m_HeaderPart.EssenceContainers;
604 body_part.ThisPartition = m_File.Tell();
606 body_part.BodyOffset = m_StreamOffset;
607 result = body_part.WriteToFile(m_File, body_ul);
608 m_RIP.PairArray.push_back(RIP::PartitionPair(1, body_part.ThisPartition));
612 if ( KM_SUCCESS(result) )
620 // Closes the MXF file, writing the index and other closing information.
623 AS_02::PHDR::MXFWriter::h__Writer::Finalize(const std::string& PHDR_master_metadata)
625 if ( ! m_State.Test_RUNNING() )
628 Result_t result = m_State.Goto_FINAL();
630 if ( KM_SUCCESS(result) )
632 if ( m_IndexWriter.GetDuration() > 0 )
634 m_IndexWriter.ThisPartition = this->m_File.Tell();
635 m_IndexWriter.WriteToFile(this->m_File);
636 m_RIP.PairArray.push_back(RIP::PartitionPair(0, this->m_IndexWriter.ThisPartition));
639 if ( ! PHDR_master_metadata.empty() )
641 // write PHDRSimplePayload
642 Kumu::fpos_t here = m_File.Tell();
644 // create generic stream partition header
645 static UL GenericStream_DataElement(m_Dict->ul(MDD_GenericStream_DataElement));
646 ASDCP::MXF::Partition GSPart(m_Dict);
648 GSPart.ThisPartition = here;
649 GSPart.PreviousPartition = m_RIP.PairArray.back().ByteOffset;
650 GSPart.OperationalPattern = m_HeaderPart.OperationalPattern;
652 m_MetadataTrackSubDescriptor->SimplePayloadSID = 2;
654 m_RIP.PairArray.push_back(RIP::PartitionPair(2, here));
655 GSPart.EssenceContainers = m_HeaderPart.EssenceContainers;
657 static UL gs_part_ul(m_Dict->ul(MDD_GenericStreamPartition));
658 Result_t result = GSPart.WriteToFile(m_File, gs_part_ul);
660 if ( KM_SUCCESS(result) )
662 ASDCP::FrameBuffer tmp_buf;
663 tmp_buf.SetData((byte_t*)PHDR_master_metadata.c_str(), PHDR_master_metadata.size());
664 tmp_buf.Size(PHDR_master_metadata.size());
666 result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
667 m_StreamOffset, tmp_buf, GenericStream_DataElement.Value(), 0, 0);
671 result = WriteAS02Footer();
678 //------------------------------------------------------------------------------------------
682 AS_02::PHDR::MXFWriter::MXFWriter()
686 AS_02::PHDR::MXFWriter::~MXFWriter()
690 // Warning: direct manipulation of MXF structures can interfere
691 // with the normal operation of the wrapper. Caveat emptor!
693 ASDCP::MXF::OP1aHeader&
694 AS_02::PHDR::MXFWriter::OP1aHeader()
696 if ( m_Writer.empty() )
698 assert(g_OP1aHeader);
699 return *g_OP1aHeader;
702 return m_Writer->m_HeaderPart;
705 // Warning: direct manipulation of MXF structures can interfere
706 // with the normal operation of the wrapper. Caveat emptor!
709 AS_02::PHDR::MXFWriter::RIP()
711 if ( m_Writer.empty() )
717 return m_Writer->m_RIP;
720 // Open the file for writing. The file must not exist. Returns error if
721 // the operation cannot be completed.
723 AS_02::PHDR::MXFWriter::OpenWrite(const std::string& filename, const ASDCP::WriterInfo& Info,
724 ASDCP::MXF::FileDescriptor* essence_descriptor,
725 ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
726 const ASDCP::Rational& edit_rate, const ui32_t& header_size,
727 const IndexStrategy_t& strategy, const ui32_t& partition_space)
729 if ( essence_descriptor == 0 )
731 DefaultLogSink().Error("Essence descriptor object required.\n");
735 m_Writer = new AS_02::PHDR::MXFWriter::h__Writer(DefaultSMPTEDict());
736 m_Writer->m_Info = Info;
738 Result_t result = m_Writer->OpenWrite(filename, essence_descriptor, essence_sub_descriptor_list,
739 strategy, partition_space, header_size);
741 if ( KM_SUCCESS(result) )
742 result = m_Writer->SetSourceStream(JP2K_PACKAGE_LABEL, edit_rate);
744 if ( KM_FAILURE(result) )
750 // Writes a frame of essence to the MXF file. If the optional AESEncContext
751 // argument is present, the essence is encrypted prior to writing.
752 // Fails if the file is not open, is finalized, or an operating system
755 AS_02::PHDR::MXFWriter::WriteFrame(const AS_02::PHDR::FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
757 if ( m_Writer.empty() )
760 return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
763 // Closes the MXF file, writing the index and other closing information.
765 AS_02::PHDR::MXFWriter::Finalize(const std::string& PHDR_master_metadata)
767 if ( m_Writer.empty() )
770 return m_Writer->Finalize(PHDR_master_metadata);
775 // end AS_02_PHDR.cpp