/*
-Copyright (c) 2004-2013, John Hurst
+Copyright (c) 2004-2016, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
#include <iostream>
#include "AS_DCP.h"
-#include "AS_DCP_DCData_internal.h"
#include "AS_DCP_internal.h"
namespace ASDCP
{
namespace ATMOS
{
- static std::string ATMOS_PACKAGE_LABEL = "File Package: SMPTE 382M frame wrapping of Dolby ATMOS data";
+ static std::string ATMOS_PACKAGE_LABEL = "File Package: SMPTE-GC frame wrapping of Dolby ATMOS data";
static std::string ATMOS_DEF_LABEL = "Dolby ATMOS Data Track";
static byte_t ATMOS_ESSENCE_CODING[SMPTE_UL_LENGTH] = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x05,
0x0e, 0x09, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00 };
//
bool
-ASDCP::ATMOS::IsDolbyAtmos(const char* filename)
+ASDCP::ATMOS::IsDolbyAtmos(const std::string& filename)
{
// TODO
// For now use an atmos extension
- bool result = (0 == (std::string("atmos").compare(Kumu::PathGetExtension(std::string(filename)))));
+ bool result = ( 0 == (std::string("atmos").compare(Kumu::PathGetExtension(filename))) );
return result;
}
//------------------------------------------------------------------------------------------
+typedef std::list<MXF::InterchangeObject*> SubDescriptorList_t;
-class ASDCP::ATMOS::MXFReader::h__Reader : public ASDCP::DCData::h__Reader
+class ASDCP::ATMOS::MXFReader::h__Reader : public ASDCP::h__ASDCPReader
{
+ MXF::PrivateDCDataDescriptor* m_EssenceDescriptor;
MXF::DolbyAtmosSubDescriptor* m_EssenceSubDescriptor;
- ASDCP_NO_COPY_CONSTRUCT(h__Reader);
+ KM_NO_COPY_CONSTRUCT(h__Reader);
h__Reader();
public:
+ ASDCP::DCData::DCDataDescriptor m_DDesc;
AtmosDescriptor m_ADesc;
- h__Reader(const Dictionary& d) : DCData::h__Reader(d), m_EssenceSubDescriptor(NULL),
- m_ADesc() {}
- ~h__Reader() {}
- Result_t OpenRead(const char*);
+ h__Reader(const Dictionary& d) :
+ ASDCP::h__ASDCPReader(d), m_EssenceDescriptor(0), m_EssenceSubDescriptor(0) {}
+ virtual ~h__Reader() {}
+ Result_t OpenRead(const std::string&);
+ Result_t ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
+ Result_t MD_to_DCData_DDesc(ASDCP::DCData::DCDataDescriptor& DDesc);
Result_t MD_to_Atmos_ADesc(ATMOS::AtmosDescriptor& ADesc);
};
+ASDCP::Result_t
+ASDCP::ATMOS::MXFReader::h__Reader::MD_to_DCData_DDesc(ASDCP::DCData::DCDataDescriptor& DDesc)
+{
+ ASDCP_TEST_NULL(m_EssenceDescriptor);
+ MXF::PrivateDCDataDescriptor* DDescObj = m_EssenceDescriptor;
+ DDesc.EditRate = DDescObj->SampleRate;
+ assert(DDescObj->ContainerDuration <= 0xFFFFFFFFL);
+ DDesc.ContainerDuration = static_cast<ui32_t>(DDescObj->ContainerDuration);
+ memcpy(DDesc.DataEssenceCoding, DDescObj->DataEssenceCoding.Value(), SMPTE_UL_LENGTH);
+ return RESULT_OK;
+}
+
ASDCP::Result_t
ASDCP::ATMOS::MXFReader::h__Reader::MD_to_Atmos_ADesc(ATMOS::AtmosDescriptor& ADesc)
{
//
//
ASDCP::Result_t
-ASDCP::ATMOS::MXFReader::h__Reader::OpenRead(const char* filename)
+ASDCP::ATMOS::MXFReader::h__Reader::OpenRead(const std::string& filename)
{
- Result_t result = DCData::h__Reader::OpenRead(filename);
+ Result_t result = OpenMXFRead(filename);
+ m_EssenceDescriptor = 0;
- if( ASDCP_SUCCESS(result) )
- {
+ if ( KM_SUCCESS(result) )
+ {
+ InterchangeObject* iObj = 0;
+ result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(PrivateDCDataDescriptor), &iObj);
+
+ if ( KM_SUCCESS(result) )
+ {
+ m_EssenceDescriptor = static_cast<MXF::PrivateDCDataDescriptor*>(iObj);
+ }
+ }
- if (NULL == m_EssenceSubDescriptor)
+ if ( m_EssenceDescriptor == 0 )
{
- InterchangeObject* iObj = NULL;
- result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(DolbyAtmosSubDescriptor), &iObj);
- m_EssenceSubDescriptor = static_cast<MXF::DolbyAtmosSubDescriptor*>(iObj);
+ DefaultLogSink().Error("DCDataDescriptor object not found in Atmos file.\n");
+ result = RESULT_FORMAT;
}
- if ( ASDCP_SUCCESS(result) )
+ if ( KM_SUCCESS(result) )
{
- result = MD_to_Atmos_ADesc(m_ADesc);
+ result = MD_to_DCData_DDesc(m_DDesc);
}
+
+ // check for sample/frame rate sanity
+ if ( ASDCP_SUCCESS(result)
+ && m_DDesc.EditRate != EditRate_24
+ && m_DDesc.EditRate != EditRate_25
+ && m_DDesc.EditRate != EditRate_30
+ && m_DDesc.EditRate != EditRate_48
+ && m_DDesc.EditRate != EditRate_50
+ && m_DDesc.EditRate != EditRate_60
+ && m_DDesc.EditRate != EditRate_96
+ && m_DDesc.EditRate != EditRate_100
+ && m_DDesc.EditRate != EditRate_120
+ && m_DDesc.EditRate != EditRate_192
+ && m_DDesc.EditRate != EditRate_200
+ && m_DDesc.EditRate != EditRate_240 )
+ {
+ DefaultLogSink().Error("DC Data file EditRate is not a supported value: %d/%d\n", // lu
+ m_DDesc.EditRate.Numerator, m_DDesc.EditRate.Denominator);
+
+ return RESULT_FORMAT;
}
+ if( ASDCP_SUCCESS(result) )
+ {
+
+ if (NULL == m_EssenceSubDescriptor)
+ {
+ InterchangeObject* iObj = NULL;
+ result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(DolbyAtmosSubDescriptor), &iObj);
+ m_EssenceSubDescriptor = static_cast<MXF::DolbyAtmosSubDescriptor*>(iObj);
+
+ if ( iObj == 0 )
+ {
+ DefaultLogSink().Error("DolbyAtmosSubDescriptor object not found.\n");
+ return RESULT_FORMAT;
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = MD_to_Atmos_ADesc(m_ADesc);
+ }
+ }
+
return result;
}
+//
+ASDCP::Result_t
+ASDCP::ATMOS::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC)
+{
+ if ( ! m_File.IsOpen() )
+ return RESULT_INIT;
+
+ assert(m_Dict);
+ return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_PrivateDCDataEssence), Ctx, HMAC);
+}
+
//------------------------------------------------------------------------------------------
ASDCP::ATMOS::MXFReader::MXFReader()
{
- m_Reader = new h__Reader(DefaultSMPTEDict());
+ m_Reader = new h__Reader(AtmosSMPTEDict());
}
// Warning: direct manipulation of MXF structures can interfere
// with the normal operation of the wrapper. Caveat emptor!
//
-ASDCP::MXF::OPAtomHeader&
-ASDCP::ATMOS::MXFReader::OPAtomHeader()
+ASDCP::MXF::OP1aHeader&
+ASDCP::ATMOS::MXFReader::OP1aHeader()
{
if ( m_Reader.empty() )
{
- assert(g_OPAtomHeader);
- return *g_OPAtomHeader;
+ assert(g_OP1aHeader);
+ return *g_OP1aHeader;
}
return m_Reader->m_HeaderPart;
return *g_OPAtomIndexFooter;
}
- return m_Reader->m_FooterPart;
+ return m_Reader->m_IndexAccess;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::RIP&
+ASDCP::ATMOS::MXFReader::RIP()
+{
+ if ( m_Reader.empty() )
+ {
+ assert(g_RIP);
+ return *g_RIP;
+ }
+
+ return m_Reader->m_RIP;
}
// Open the file for reading. The file must exist. Returns error if the
// operation cannot be completed.
ASDCP::Result_t
-ASDCP::ATMOS::MXFReader::OpenRead(const char* filename) const
+ASDCP::ATMOS::MXFReader::OpenRead(const std::string& filename) const
{
return m_Reader->OpenRead(filename);
}
ASDCP::ATMOS::MXFReader::DumpIndex(FILE* stream) const
{
if ( m_Reader->m_File.IsOpen() )
- m_Reader->m_FooterPart.Dump(stream);
+ m_Reader->m_IndexAccess.Dump(stream);
}
//
//------------------------------------------------------------------------------------------
//
-class ASDCP::ATMOS::MXFWriter::h__Writer : public DCData::h__Writer
+class ASDCP::ATMOS::MXFWriter::h__Writer : public ASDCP::h__ASDCPWriter
{
+ ASDCP::DCData::DCDataDescriptor m_DDesc;
+ byte_t m_EssenceUL[SMPTE_UL_LENGTH];
MXF::DolbyAtmosSubDescriptor* m_EssenceSubDescriptor;
ASDCP_NO_COPY_CONSTRUCT(h__Writer);
public:
AtmosDescriptor m_ADesc;
- h__Writer(const Dictionary& d) : DCData::h__Writer(d),
- m_EssenceSubDescriptor(NULL), m_ADesc() {}
+ h__Writer(const Dictionary& d) : ASDCP::h__ASDCPWriter(d),
+ m_EssenceSubDescriptor(0), m_ADesc() {
+ memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
+ }
- ~h__Writer(){}
+ virtual ~h__Writer(){}
- Result_t OpenWrite(const char*, ui32_t HeaderSize, const AtmosDescriptor& ADesc);
+ Result_t OpenWrite(const std::string&, ui32_t HeaderSize, const AtmosDescriptor& ADesc);
+ Result_t SetSourceStream(const DCData::DCDataDescriptor&, const byte_t*, const std::string&, const std::string&);
+ Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+ Result_t Finalize();
+ Result_t DCData_DDesc_to_MD(ASDCP::DCData::DCDataDescriptor& DDesc);
Result_t Atmos_ADesc_to_MD(const AtmosDescriptor& ADesc);
};
+//
+ASDCP::Result_t
+ASDCP::ATMOS::MXFWriter::h__Writer::DCData_DDesc_to_MD(ASDCP::DCData::DCDataDescriptor& DDesc)
+{
+ ASDCP_TEST_NULL(m_EssenceDescriptor);
+ MXF::PrivateDCDataDescriptor* DDescObj = static_cast<MXF::PrivateDCDataDescriptor *>(m_EssenceDescriptor);
+
+ DDescObj->SampleRate = DDesc.EditRate;
+ DDescObj->ContainerDuration = DDesc.ContainerDuration;
+ DDescObj->DataEssenceCoding.Set(DDesc.DataEssenceCoding);
+ return RESULT_OK;
+}
+
//
ASDCP::Result_t
ASDCP::ATMOS::MXFWriter::h__Writer::Atmos_ADesc_to_MD(const AtmosDescriptor& ADesc)
//
ASDCP::Result_t
-ASDCP::ATMOS::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize, const AtmosDescriptor& ADesc)
+ASDCP::ATMOS::MXFWriter::h__Writer::OpenWrite(const std::string& filename, ui32_t HeaderSize, const AtmosDescriptor& ADesc)
{
+ if ( ! m_State.Test_BEGIN() )
+ return RESULT_STATE;
+
+ Result_t result = m_File.OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_HeaderSize = HeaderSize;
+ m_EssenceDescriptor = new MXF::PrivateDCDataDescriptor(m_Dict);
+ m_EssenceSubDescriptor = new DolbyAtmosSubDescriptor(m_Dict);
+ SubDescriptorList_t subDescriptors;
+ subDescriptors.push_back(m_EssenceSubDescriptor);
+
+ SubDescriptorList_t::const_iterator sDObj;
+ SubDescriptorList_t::const_iterator lastDescriptor = subDescriptors.end();
+ for (sDObj = subDescriptors.begin(); sDObj != lastDescriptor; ++sDObj)
+ {
+ m_EssenceSubDescriptorList.push_back(*sDObj);
+ GenRandomValue((*sDObj)->InstanceUID);
+ m_EssenceDescriptor->SubDescriptors.push_back((*sDObj)->InstanceUID);
+ }
+ result = m_State.Goto_INIT();
+ }
- m_EssenceSubDescriptor = new DolbyAtmosSubDescriptor(m_Dict);
- DCData::SubDescriptorList_t subDescriptors;
- subDescriptors.push_back(m_EssenceSubDescriptor);
- Result_t result = DCData::h__Writer::OpenWrite(filename, HeaderSize, subDescriptors);
if ( ASDCP_FAILURE(result) )
delete m_EssenceSubDescriptor;
return result;
}
+//
+ASDCP::Result_t
+ASDCP::ATMOS::MXFWriter::h__Writer::SetSourceStream(ASDCP::DCData::DCDataDescriptor const& DDesc,
+ const byte_t * essenceCoding,
+ const std::string& packageLabel,
+ const std::string& defLabel)
+{
+ if ( ! m_State.Test_INIT() )
+ return RESULT_STATE;
+
+ if ( DDesc.EditRate != EditRate_24
+ && DDesc.EditRate != EditRate_25
+ && DDesc.EditRate != EditRate_30
+ && DDesc.EditRate != EditRate_48
+ && DDesc.EditRate != EditRate_50
+ && DDesc.EditRate != EditRate_60
+ && DDesc.EditRate != EditRate_96
+ && DDesc.EditRate != EditRate_100
+ && DDesc.EditRate != EditRate_120
+ && DDesc.EditRate != EditRate_192
+ && DDesc.EditRate != EditRate_200
+ && DDesc.EditRate != EditRate_240 )
+ {
+ DefaultLogSink().Error("DCDataDescriptor.EditRate is not a supported value: %d/%d\n",
+ DDesc.EditRate.Numerator, DDesc.EditRate.Denominator);
+ return RESULT_RAW_FORMAT;
+ }
+
+ assert(m_Dict);
+ m_DDesc = DDesc;
+ if (NULL != essenceCoding)
+ memcpy(m_DDesc.DataEssenceCoding, essenceCoding, SMPTE_UL_LENGTH);
+ Result_t result = DCData_DDesc_to_MD(m_DDesc);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ memcpy(m_EssenceUL, m_Dict->ul(MDD_PrivateDCDataEssence), SMPTE_UL_LENGTH);
+ m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
+ result = m_State.Goto_READY();
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t TCFrameRate = m_DDesc.EditRate.Numerator;
+
+ result = WriteASDCPHeader(packageLabel, UL(m_Dict->ul(MDD_PrivateDCDataWrappingFrame)),
+ defLabel, UL(m_EssenceUL), UL(m_Dict->ul(MDD_DataDataDef)),
+ m_DDesc.EditRate, TCFrameRate);
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::ATMOS::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf,
+ ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
+{
+ Result_t result = RESULT_OK;
+
+ if ( m_State.Test_READY() )
+ result = m_State.Goto_RUNNING(); // first time through
+
+ ui64_t StreamOffset = m_StreamOffset;
+
+ if ( ASDCP_SUCCESS(result) )
+ result = WriteEKLVPacket(FrameBuf, m_EssenceUL, MXF_BER_LENGTH, Ctx, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ IndexTableSegment::IndexEntry Entry;
+ Entry.StreamOffset = StreamOffset;
+ m_FooterPart.PushIndexEntry(Entry);
+ m_FramesWritten++;
+ }
+ return result;
+}
+
+// Closes the MXF file, writing the index and other closing information.
+//
+ASDCP::Result_t
+ASDCP::ATMOS::MXFWriter::h__Writer::Finalize()
+{
+ if ( ! m_State.Test_RUNNING() )
+ return RESULT_STATE;
+
+ m_State.Goto_FINAL();
+
+ return WriteASDCPFooter();
+}
// Warning: direct manipulation of MXF structures can interfere
// with the normal operation of the wrapper. Caveat emptor!
//
-ASDCP::MXF::OPAtomHeader&
-ASDCP::ATMOS::MXFWriter::OPAtomHeader()
+ASDCP::MXF::OP1aHeader&
+ASDCP::ATMOS::MXFWriter::OP1aHeader()
{
if ( m_Writer.empty() )
{
- assert(g_OPAtomHeader);
- return *g_OPAtomHeader;
+ assert(g_OP1aHeader);
+ return *g_OP1aHeader;
}
return m_Writer->m_HeaderPart;
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::ATMOS::MXFWriter::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::ATMOS::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
+ASDCP::ATMOS::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
const AtmosDescriptor& ADesc, ui32_t HeaderSize)
{
if ( Info.LabelSetType != LS_MXF_SMPTE )
return RESULT_FORMAT;
}
- m_Writer = new h__Writer(DefaultSMPTEDict());
+ m_Writer = new h__Writer(AtmosSMPTEDict());
m_Writer->m_Info = Info;
Result_t result = m_Writer->OpenWrite(filename, HeaderSize, ADesc);
if ( ASDCP_SUCCESS(result) )
result = m_Writer->SetSourceStream(ADesc, ATMOS_ESSENCE_CODING, ATMOS_PACKAGE_LABEL,
ATMOS_DEF_LABEL);
-
+
if ( ASDCP_FAILURE(result) )
m_Writer.release();