/*
-Copyright (c) 2004-2013, John Hurst
+Copyright (c) 2004-2018, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
ui32_t
ASDCP::derive_timecode_rate_from_edit_rate(const ASDCP::Rational& edit_rate)
{
- double edit_rate_real = edit_rate.Quotient();
- if ( ceil(edit_rate_real) == floor(edit_rate_real) )
- {
- return ceil(edit_rate_real);
- }
-
- return ( edit_rate_real - floor(edit_rate_real) < 0.5 ) ? floor(edit_rate_real) : ceil(edit_rate_real);
+ return (ui32_t)floor(0.5 + edit_rate.Quotient());
}
//
// add DMS CryptographicFramework entry to source package
void
-ASDCP::AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
+ASDCP::AddDmsCrypt(Partition& HeaderPart, SourcePackage& Package,
WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict)
{
assert(Dict);
HeaderPart.AddChildObject(Segment);
Seq->StructuralComponents.push_back(Segment->InstanceUID);
Segment->EventComment = "AS-DCP KLV Encryption";
-
+ Segment->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef));
+
CryptographicFramework* CFW = new CryptographicFramework(Dict);
HeaderPart.AddChildObject(CFW);
Segment->DMFramework = CFW->InstanceUID;
Context->CryptographicKeyID.Set(Descr.CryptographicKeyID);
}
+static std::string const rp2057_static_track_label = "SMPTE RP 2057 Generic Stream Text-Based Set";
+//
+static bool
+id_batch_contains(const Array<Kumu::UUID>& batch, const Kumu::UUID& value)
+{
+ Array<Kumu::UUID>::const_iterator i;
+ for ( i = batch.begin(); i != batch.end(); ++i )
+ {
+ if ( *i == value )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+//
+Result_t
+ASDCP::AddDmsTrackGenericPartUtf8Text(Kumu::FileWriter& file_writer, MXF::OP1aHeader& header_part,
+ SourcePackage& source_package, MXF::RIP& rip, const Dictionary*& Dict)
+{
+ Sequence* Sequence_obj = 0;
+ InterchangeObject* tmp_iobj = 0;
+ std::list<InterchangeObject*> object_list;
+
+ // get the SourcePackage else die
+ header_part.GetMDObjectByType(Dict->ul(MDD_SourcePackage), &tmp_iobj);
+ SourcePackage *SourcePackage_obj = dynamic_cast<SourcePackage*>(tmp_iobj);
+ if ( SourcePackage_obj == 0 )
+ {
+ DefaultLogSink().Error("MXF Metadata contains no SourcePackage Set.\n");
+ return RESULT_FORMAT;
+ }
+
+ // find the first StaticTrack object, having the right label, that is ref'd by the source package
+ StaticTrack *StaticTrack_obj = 0;
+ header_part.GetMDObjectsByType(Dict->ul(MDD_StaticTrack), object_list);
+ std::list<InterchangeObject*>::iterator j;
+ for ( j = object_list.begin(); j != object_list.end(); ++j )
+ {
+ StaticTrack_obj = dynamic_cast<StaticTrack*>(*j);
+ assert(StaticTrack_obj);
+ if ( id_batch_contains(SourcePackage_obj->Tracks, StaticTrack_obj->InstanceUID)
+ && StaticTrack_obj->TrackName.get() == rp2057_static_track_label )
+ {
+ break;
+ }
+ StaticTrack_obj = 0;
+ }
+
+ // find the Sequence associated with this Track
+ if ( StaticTrack_obj )
+ {
+ object_list.clear();
+ header_part.GetMDObjectsByType(Dict->ul(MDD_Sequence), object_list);
+ for ( j = object_list.begin(); j != object_list.end(); ++j )
+ {
+ Sequence_obj = dynamic_cast<Sequence*>(*j);
+ assert(Sequence_obj);
+ if ( Sequence_obj->InstanceUID == StaticTrack_obj->Sequence )
+ {
+ break;
+ }
+ Sequence_obj = 0;
+ }
+ }
+
+ if ( Sequence_obj == 0 )
+ {
+ // this is the first insertion, create the static track
+ assert(Dict);
+ StaticTrack* static_track = new StaticTrack(Dict);
+ header_part.AddChildObject(static_track);
+ source_package.Tracks.push_back(static_track->InstanceUID);
+ static_track->TrackName = "Descriptive Track";
+ static_track->TrackID = 4;
+
+ Sequence_obj = new Sequence(Dict);
+ header_part.AddChildObject(Sequence_obj);
+ static_track->Sequence = Sequence_obj->InstanceUID;
+ Sequence_obj->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef));
+ header_part.m_Preface->DMSchemes.push_back(UL(Dict->ul(MDD_MXFTextBasedFramework)));
+ }
+
+ assert(Sequence_obj);
+ // Create the DM segment and framework packs
+ DMSegment* Segment = new DMSegment(Dict);
+ header_part.AddChildObject(Segment);
+ Sequence_obj->StructuralComponents.push_back(Segment->InstanceUID);
+ Segment->EventComment = rp2057_static_track_label;
+ Segment->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef));
+
+ //
+ TextBasedDMFramework *dmf_obj = new TextBasedDMFramework(Dict);
+ assert(dmf_obj);
+ header_part.AddChildObject(dmf_obj);
+ Segment->DMFramework = dmf_obj->InstanceUID;
+ GenRandomValue(dmf_obj->ObjectRef);
+
+ // Create a new SID on the RIP, located at the current file position
+ ui32_t max_sid = 0;
+ ASDCP::MXF::RIP::pair_iterator i;
+ for ( i = rip.PairArray.begin(); i != rip.PairArray.end(); ++i )
+ {
+ if ( max_sid < i->BodySID )
+ {
+ max_sid = i->BodySID;
+ }
+ }
+
+ if ( max_sid == 0 )
+ {
+ DefaultLogSink().Error("Unable to add a GS Partition before the essence container has been established.\n");
+ return RESULT_FORMAT;
+ }
+
+ rip.PairArray.push_back(RIP::PartitionPair(max_sid + 1, file_writer.Tell()));
+
+ // Add new GSTBS linked to DMF
+ GenericStreamTextBasedSet *gst_obj = new GenericStreamTextBasedSet(Dict);
+ header_part.AddChildObject(gst_obj);
+ gst_obj->InstanceUID = dmf_obj->ObjectRef;
+ gst_obj->GenericStreamSID = max_sid + 1;
+ gst_obj->PayloadSchemeID = UL(Dict->ul(MDD_MXFTextBasedFramework));
+
+ return RESULT_OK;
+}
//
ASDCP::h__ASDCPWriter::h__ASDCPWriter(const Dictionary& d) :
m_BodyPart.BodySID = 1;
UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
m_BodyPart.OperationalPattern = OPAtomUL;
- m_RIP.PairArray.push_back(RIP::Pair(1, m_BodyPart.ThisPartition)); // Second RIP Entry
+ m_RIP.PairArray.push_back(RIP::PartitionPair(1, m_BodyPart.ThisPartition)); // Second RIP Entry
UL BodyUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
result = m_BodyPart.WriteToFile(m_File, BodyUL);
const std::string& TrackName, const UL& EssenceUL, const UL& DataDefinition,
const MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
{
- InitHeader();
+ InitHeader(MXFVersion_2004);
// First RIP Entry
if ( m_Info.LabelSetType == LS_MXF_SMPTE ) // ERK
{
- m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // 3-part, no essence in header
+ m_RIP.PairArray.push_back(RIP::PartitionPair(0, 0)); // 3-part, no essence in header
}
else
{
- m_RIP.PairArray.push_back(RIP::Pair(1, 0)); // 2-part, essence in header
+ m_RIP.PairArray.push_back(RIP::PartitionPair(1, 0)); // 2-part, essence in header
}
// timecode rate and essence rate are the same
AddSourceClip(EditRate, EditRate, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel);
AddEssenceDescriptor(WrappingUL);
+#ifdef ASDCP_GCMULTI_PATCH
+ UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
+ m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
+#endif
+
Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
if ( KM_SUCCESS(result) )
//
Result_t
ASDCP::h__ASDCPWriter::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
+ const ui32_t& MinEssenceElementBerLength,
AESEncContext* Ctx, HMACContext* HMAC)
{
return Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
- m_StreamOffset, FrameBuf, EssenceUL, Ctx, HMAC);
+ m_StreamOffset, FrameBuf, EssenceUL, MinEssenceElementBerLength,
+ Ctx, HMAC);
}
// standard method of writing the header and footer of a completed MXF file
m_FooterPart.PreviousPartition = m_RIP.PairArray.back().ByteOffset;
Kumu::fpos_t here = m_File.Tell();
- m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Last RIP Entry
+ m_RIP.PairArray.push_back(RIP::PartitionPair(0, here)); // Last RIP Entry
m_HeaderPart.FooterPartition = here;
assert(m_Dict);
ASDCP::Write_EKLV_Packet(Kumu::FileWriter& File, const ASDCP::Dictionary& Dict, const MXF::OP1aHeader& HeaderPart,
const ASDCP::WriterInfo& Info, ASDCP::FrameBuffer& CtFrameBuf, ui32_t& FramesWritten,
ui64_t & StreamOffset, const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
+ const ui32_t& MinEssenceElementBerLength,
AESEncContext* Ctx, HMACContext* HMAC)
{
Result_t result = RESULT_OK;
// construct encrypted triplet header
ui32_t ETLength = klv_cryptinfo_size + CtFrameBuf.Size();
- ui32_t BER_length = MXF_BER_LENGTH;
+ ui32_t essence_element_BER_length = MinEssenceElementBerLength;
if ( Info.UsesHMAC )
ETLength += klv_intpack_size;
if ( ETLength > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
{
- BER_length = Kumu::get_BER_length_for_value(ETLength);
+ essence_element_BER_length = Kumu::get_BER_length_for_value(ETLength);
// the packet is longer by the difference in expected vs. actual BER length
- ETLength += BER_length - MXF_BER_LENGTH;
+ ETLength += essence_element_BER_length - MXF_BER_LENGTH;
- if ( BER_length == 0 )
+ if ( essence_element_BER_length == 0 )
result = RESULT_KLV_CODING;
}
if ( ASDCP_SUCCESS(result) )
{
- if ( ! ( Overhead.WriteBER(ETLength, BER_length) // write encrypted triplet length
+ if ( ! ( Overhead.WriteBER(ETLength, essence_element_BER_length) // write encrypted triplet length
&& Overhead.WriteBER(UUIDlen, MXF_BER_LENGTH) // write ContextID length
&& Overhead.WriteRaw(Info.ContextID, UUIDlen) // write ContextID
&& Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH) // write PlaintextOffset length
&& Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH) // write the essence UL
&& Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH) // write SourceLength length
&& Overhead.WriteUi64BE(FrameBuf.Size()) // write SourceLength
- && Overhead.WriteBER(CtFrameBuf.Size(), BER_length) ) ) // write ESV length
+ && Overhead.WriteBER(CtFrameBuf.Size(), essence_element_BER_length) ) ) // write ESV length
{
result = RESULT_KLV_CODING;
}
}
else
{
- ui32_t BER_length = MXF_BER_LENGTH;
+ ui32_t essence_element_BER_length = MinEssenceElementBerLength;
if ( FrameBuf.Size() > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
{
- BER_length = Kumu::get_BER_length_for_value(FrameBuf.Size());
+ essence_element_BER_length = Kumu::get_BER_length_for_value(FrameBuf.Size());
- if ( BER_length == 0 )
+ if ( essence_element_BER_length == 0 )
result = RESULT_KLV_CODING;
}
Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH);
- Overhead.WriteBER(FrameBuf.Size(), BER_length);
+ Overhead.WriteBER(FrameBuf.Size(), essence_element_BER_length);
if ( ASDCP_SUCCESS(result) )
result = File.Writev(Overhead.Data(), Overhead.Length());