summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormikey <mikey@cinecert.com>2013-04-12 23:39:31 +0000
committermikey <>2013-04-12 23:39:31 +0000
commit252740d6f7d8924c6af30e55d2da487356a0acdc (patch)
treeba01aa630cf6cd11e7c286a60380aa35be916616 /src
parentc9e20228d6c328a0b446c1417e0082389ff045ff (diff)
Added atmos support and new ULs per SMPTE 429-2:2013 - see README for deets.
Diffstat (limited to 'src')
-rwxr-xr-xsrc/AS_DCP.h393
-rw-r--r--src/AS_DCP_ATMOS.cpp455
-rw-r--r--src/AS_DCP_DCData.cpp554
-rw-r--r--src/AS_DCP_DCData_internal.h94
-rwxr-xr-xsrc/AS_DCP_JP2K.cpp32
-rwxr-xr-xsrc/AS_DCP_MPEG2.cpp9
-rwxr-xr-xsrc/AS_DCP_MXF.cpp37
-rwxr-xr-xsrc/AS_DCP_PCM.cpp42
-rw-r--r--src/AS_DCP_TimedText.cpp4
-rwxr-xr-xsrc/AS_DCP_internal.h43
-rw-r--r--src/AtmosSyncChannel_Generator.cpp149
-rw-r--r--src/AtmosSyncChannel_Generator.h151
-rw-r--r--src/AtmosSyncChannel_Mixer.cpp326
-rw-r--r--src/AtmosSyncChannel_Mixer.h91
-rw-r--r--src/CRC16.c86
-rw-r--r--src/CRC16.h45
-rw-r--r--src/DCData_ByteStream_Parser.cpp121
-rw-r--r--src/DCData_Sequence_Parser.cpp294
-rwxr-xr-xsrc/Index.cpp2
-rw-r--r--src/MDD.cpp81
-rwxr-xr-xsrc/MDD.h106
-rwxr-xr-xsrc/MXF.cpp37
-rw-r--r--src/Makefile.am14
-rwxr-xr-xsrc/Metadata.cpp168
-rwxr-xr-xsrc/Metadata.h49
-rw-r--r--src/PCMDataProviders.cpp210
-rw-r--r--src/PCMDataProviders.h119
-rwxr-xr-xsrc/PCM_Parser.cpp21
-rw-r--r--src/SyncCommon.h80
-rw-r--r--src/SyncEncoder.c346
-rw-r--r--src/SyncEncoder.h86
-rw-r--r--src/UUIDInformation.c119
-rw-r--r--src/UUIDInformation.h58
-rwxr-xr-xsrc/Wav.cpp225
-rwxr-xr-xsrc/Wav.h39
-rwxr-xr-xsrc/WavFileWriter.h46
-rwxr-xr-xsrc/asdcp-info.cpp48
-rwxr-xr-xsrc/asdcp-unwrap.cpp192
-rwxr-xr-xsrc/asdcp-wrap.cpp302
-rw-r--r--src/blackwave.cpp4
-rwxr-xr-xsrc/h__Reader.cpp35
41 files changed, 5110 insertions, 203 deletions
diff --git a/src/AS_DCP.h b/src/AS_DCP.h
index c0556ba..b9aba83 100755
--- a/src/AS_DCP.h
+++ b/src/AS_DCP.h
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2003-2012, John Hurst
+Copyright (c) 2003-2013, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -25,7 +25,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*! \file AS_DCP.h
- \version $Id$
+ \version $Id$
\brief AS-DCP library, public interface
The asdcplib library is a set of file access objects that offer simplified
@@ -87,6 +87,7 @@ This project depends upon the following libraries:
#define _AS_DCP_H_
#include <KM_error.h>
+#include <KM_fileio.h>
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
@@ -203,13 +204,15 @@ namespace ASDCP {
// The file accessors in this library implement a bounded set of essence types.
// This list will be expanded when support for new types is added to the library.
enum EssenceType_t {
- ESS_UNKNOWN, // the file is not a supported AS-DCP essence container
- ESS_MPEG2_VES, // the file contains an MPEG video elementary stream
- ESS_JPEG_2000, // the file contains one or more JPEG 2000 codestreams
- ESS_PCM_24b_48k, // the file contains one or more PCM audio pairs
- ESS_PCM_24b_96k, // the file contains one or more PCM audio pairs
- ESS_TIMED_TEXT, // the file contains an XML timed text document and one or more resources
- ESS_JPEG_2000_S, // the file contains one or more JPEG 2000 codestream pairs (stereoscopic)
+ ESS_UNKNOWN, // the file is not a supported AS-DCP essence container
+ ESS_MPEG2_VES, // the file contains an MPEG video elementary stream
+ ESS_JPEG_2000, // the file contains one or more JPEG 2000 codestreams
+ ESS_PCM_24b_48k, // the file contains one or more PCM audio pairs
+ ESS_PCM_24b_96k, // the file contains one or more PCM audio pairs
+ ESS_TIMED_TEXT, // the file contains an XML timed text document and one or more resources
+ ESS_JPEG_2000_S, // the file contains one or more JPEG 2000 codestream pairs (stereoscopic)
+ ESS_DCDATA_UNKNOWN, // the file contains one or more D-Cinema Data bytestreams
+ ESS_DCDATA_DOLBY_ATMOS, // the file contains one or more DolbyATMOS bytestreams
};
// Determine the type of essence contained in the given MXF file. RESULT_OK
@@ -253,7 +256,7 @@ namespace ASDCP {
if ( Numerator == rhs.Numerator && Denominator < rhs.Denominator ) return true;
return false;
}
-
+
inline bool operator>(const Rational& rhs) {
if ( Numerator > rhs.Numerator ) return true;
if ( Numerator == rhs.Numerator && Denominator > rhs.Denominator ) return true;
@@ -365,7 +368,7 @@ namespace ASDCP {
static byte_t default_ProductUUID_Data[UUIDlen] = {
0x43, 0x05, 0x9a, 0x1d, 0x04, 0x32, 0x41, 0x01,
0xb8, 0x3f, 0x73, 0x68, 0x15, 0xac, 0xf3, 0x1d };
-
+
memcpy(ProductUUID, default_ProductUUID_Data, UUIDlen);
memset(AssetUUID, 0, UUIDlen);
memset(ContextID, 0, UUIDlen);
@@ -407,7 +410,7 @@ namespace ASDCP {
// Initializes Rijndael CBC encryption context.
// Returns error if the key argument is NULL.
Result_t InitKey(const byte_t* key);
-
+
// Initializes 16 byte CBC Initialization Vector. This operation may be performed
// any number of times for a given key.
// Returns error if the i_vec argument is NULL.
@@ -601,22 +604,22 @@ namespace ASDCP {
// MPEG2VideoDescriptor object.
struct VideoDescriptor
{
- Rational EditRate; //
- ui32_t FrameRate; //
- Rational SampleRate; //
- ui8_t FrameLayout; //
- ui32_t StoredWidth; //
- ui32_t StoredHeight; //
- Rational AspectRatio; //
- ui32_t ComponentDepth; //
- ui32_t HorizontalSubsampling; //
- ui32_t VerticalSubsampling; //
- ui8_t ColorSiting; //
- ui8_t CodedContentType; //
- bool LowDelay; //
- ui32_t BitRate; //
- ui8_t ProfileAndLevel; //
- ui32_t ContainerDuration; //
+ Rational EditRate; //
+ ui32_t FrameRate; //
+ Rational SampleRate; //
+ ui8_t FrameLayout; //
+ ui32_t StoredWidth; //
+ ui32_t StoredHeight; //
+ Rational AspectRatio; //
+ ui32_t ComponentDepth; //
+ ui32_t HorizontalSubsampling; //
+ ui32_t VerticalSubsampling; //
+ ui8_t ColorSiting; //
+ ui8_t CodedContentType; //
+ bool LowDelay; //
+ ui32_t BitRate; //
+ ui8_t ProfileAndLevel; //
+ ui32_t ContainerDuration; //
};
// Print VideoDescriptor to std::ostream
@@ -646,7 +649,7 @@ namespace ASDCP {
{
Capacity(size);
}
-
+
virtual ~FrameBuffer() {}
// Sets the MPEG frame type of the picture data in the frame buffer.
@@ -787,6 +790,12 @@ namespace ASDCP {
// out of range, or if optional decrypt or HAMC operations fail.
Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+ // Using the index table read from the footer partition, lookup the frame number
+ // and return the offset into the file at which to read that frame of essence.
+ // Returns RESULT_INIT if the file is not open, and RESULT_RANGE if the frame number is
+ // out of range.
+ Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const;
+
// Calculates the first frame in transport order of the GOP in which the requested
// frame is located. Calls ReadFrame() to fetch the frame at the calculated position.
// Returns RESULT_INIT if the file is not open.
@@ -836,12 +845,12 @@ namespace ASDCP {
{
Rational EditRate; // rate of frame wrapping
Rational AudioSamplingRate; // rate of audio sample
- ui32_t Locked; //
+ ui32_t Locked; //
ui32_t ChannelCount; // number of channels
ui32_t QuantizationBits; // number of bits per single-channel sample
ui32_t BlockAlign; // number of bytes ber sample, all channels
- ui32_t AvgBps; //
- ui32_t LinkedTrackID; //
+ ui32_t AvgBps; //
+ ui32_t LinkedTrackID; //
ui32_t ContainerDuration; // number of frames
ChannelFormat_t ChannelFormat; // audio channel arrangement
};
@@ -877,7 +886,7 @@ namespace ASDCP {
FrameBuffer() {}
FrameBuffer(ui32_t size) { Capacity(size); }
virtual ~FrameBuffer() {}
-
+
// Print debugging information to stream (stderr default)
void Dump(FILE* = 0, ui32_t dump_bytes = 0) const;
};
@@ -986,6 +995,12 @@ namespace ASDCP {
// out of range, or if optional decrypt or HAMC operations fail.
Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+ // Using the index table read from the footer partition, lookup the frame number
+ // and return the offset into the file at which to read that frame of essence.
+ // Returns RESULT_INIT if the file is not open, and RESULT_RANGE if the frame number is
+ // out of range.
+ Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const;
+
// Print debugging information to stream
void DumpHeaderMetadata(FILE* = 0) const;
void DumpIndex(FILE* = 0) const;
@@ -1018,7 +1033,7 @@ namespace ASDCP {
ui8_t NumberOfLayers[sizeof(ui16_t)];
ui8_t MultiCompTransform;
} SGcod;
-
+
struct
{
ui8_t DecompositionLevels;
@@ -1073,7 +1088,7 @@ namespace ASDCP {
FrameBuffer() {}
FrameBuffer(ui32_t size) { Capacity(size); }
virtual ~FrameBuffer() {}
-
+
// Print debugging information to stream (stderr default)
void Dump(FILE* = 0, ui32_t dump_bytes = 0) const;
};
@@ -1125,7 +1140,7 @@ namespace ASDCP {
// alphabetically by filename. The parser will automatically parse enough data
// from the first file to provide a complete set of stream metadata for the
// MXFWriter below. If the "pedantic" parameter is given and is true, the
- // parser will check the metadata for each codestream and fail if a
+ // parser will check the metadata for each codestream and fail if a
// mismatch is detected.
Result_t OpenRead(const char* filename, bool pedantic = false) const;
@@ -1134,7 +1149,7 @@ namespace ASDCP {
// picture. The parser will automatically parse enough data
// from the first file to provide a complete set of stream metadata for the
// MXFWriter below. If the "pedantic" parameter is given and is true, the
- // parser will check the metadata for each codestream and fail if a
+ // parser will check the metadata for each codestream and fail if a
// mismatch is detected.
Result_t OpenRead(const std::list<std::string>& file_list, bool pedantic = false) const;
@@ -1227,6 +1242,12 @@ namespace ASDCP {
// out of range, or if optional decrypt or HAMC operations fail.
Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+ // Using the index table read from the footer partition, lookup the frame number
+ // and return the offset into the file at which to read that frame of essence.
+ // Returns RESULT_INIT if the file is not open, and RESULT_FRAME if the frame number is
+ // out of range.
+ Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const;
+
// Print debugging information to stream
void DumpHeaderMetadata(FILE* = 0) const;
void DumpIndex(FILE* = 0) const;
@@ -1241,7 +1262,7 @@ namespace ASDCP {
SP_LEFT,
SP_RIGHT
};
-
+
struct SFrameBuffer
{
JP2K::FrameBuffer Left;
@@ -1344,6 +1365,12 @@ namespace ASDCP {
Result_t ReadFrame(ui32_t frame_number, StereoscopicPhase_t phase,
FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+ // Using the index table read from the footer partition, lookup the frame number
+ // and return the offset into the file at which to read that frame of essence.
+ // Returns RESULT_INIT if the file is not open, and RESULT_FRAME if the frame number is
+ // out of range.
+ Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const;
+
// Print debugging information to stream
void DumpHeaderMetadata(FILE* = 0) const;
void DumpIndex(FILE* = 0) const;
@@ -1359,7 +1386,7 @@ namespace ASDCP {
struct TimedTextResourceDescriptor
{
byte_t ResourceID[UUIDlen];
- MIMEType_t Type;
+ MIMEType_t Type;
TimedTextResourceDescriptor() : Type(MT_BIN) {}
};
@@ -1368,7 +1395,7 @@ namespace ASDCP {
struct TimedTextDescriptor
{
- Rational EditRate; //
+ Rational EditRate; //
ui32_t ContainerDuration;
byte_t AssetID[UUIDlen];
std::string NamespaceName;
@@ -1396,7 +1423,7 @@ namespace ASDCP {
FrameBuffer() { memset(m_AssetID, 0, UUIDlen); }
FrameBuffer(ui32_t size) { Capacity(size); memset(m_AssetID, 0, UUIDlen); }
virtual ~FrameBuffer() {}
-
+
inline const byte_t* AssetID() const { return m_AssetID; }
inline void AssetID(const byte_t* buf) { memcpy(m_AssetID, buf, UUIDlen); }
inline const char* MIMEType() const { return m_MIMEType.c_str(); }
@@ -1554,6 +1581,290 @@ namespace ASDCP {
};
} // namespace TimedText
+ //---------------------------------------------------------------------------------
+ //
+ namespace DCData
+ {
+ struct DCDataDescriptor
+ {
+ Rational EditRate; // Sample rate
+ ui32_t ContainerDuration; // number of frames
+ byte_t AssetID[UUIDlen]; // The UUID for the DCData track
+ byte_t DataEssenceCoding[UUIDlen]; // The coding for the data carried
+ };
+
+ // Print DCDataDescriptor to std::ostream
+ std::ostream& operator << (std::ostream& strm, const DCDataDescriptor& ddesc);
+ // Print debugging information to stream (stderr default)
+ void DCDataDescriptorDump(const DCDataDescriptor&, FILE* = 0);
+
+ //
+ class FrameBuffer : public ASDCP::FrameBuffer
+ {
+ public:
+ FrameBuffer() {}
+ FrameBuffer(ui32_t size) { Capacity(size); }
+ virtual ~FrameBuffer() {}
+
+ // Print debugging information to stream (stderr default)
+ void Dump(FILE* = 0, ui32_t dump_bytes = 0) const;
+ };
+
+ // An object which opens and reads a DC Data file. The file is expected
+ // to contain exactly one complete frame of DC data essence as an unwrapped (raw)
+ // byte stream.
+ class BytestreamParser
+ {
+ class h__BytestreamParser;
+ mem_ptr<h__BytestreamParser> m_Parser;
+ ASDCP_NO_COPY_CONSTRUCT(BytestreamParser);
+
+ public:
+ BytestreamParser();
+ virtual ~BytestreamParser();
+
+ // Opens a file for reading, parses enough data to provide a complete
+ // set of stream metadata for the MXFWriter below.
+ // The frame buffer's PlaintextOffset parameter will be set to the first
+ // byte of the data segment. Set this value to zero if you want
+ // encrypted headers.
+ Result_t OpenReadFrame(const char* filename, FrameBuffer&) const;
+
+ // Fill a DCDataDescriptor struct with the values from the file's bytestream.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillDCDataDescriptor(DCDataDescriptor&) const;
+ };
+
+ // An object which reads a sequence of files containing DC Data.
+ class SequenceParser
+ {
+ class h__SequenceParser;
+ mem_ptr<h__SequenceParser> m_Parser;
+ ASDCP_NO_COPY_CONSTRUCT(SequenceParser);
+
+ public:
+ SequenceParser();
+ virtual ~SequenceParser();
+
+ // Opens a directory for reading. The directory is expected to contain one or
+ // more files, each containing the bytestream for exactly one frame. The files
+ // must be named such that the frames are in temporal order when sorted
+ // alphabetically by filename.
+ Result_t OpenRead(const char* filename) const;
+
+ // Opens a file sequence for reading. The sequence is expected to contain one or
+ // more filenames, each naming a file containing the bytestream for exactly one
+ // frame.
+ Result_t OpenRead(const std::list<std::string>& file_list) const;
+
+ // Fill a DCDataDescriptor struct with default values.
+ // Returns RESULT_INIT if the directory is not open.
+ Result_t FillDCDataDescriptor(DCDataDescriptor&) const;
+
+ // Rewind the directory to the beginning.
+ Result_t Reset() const;
+
+ // Reads the next sequential frame in the directory and places it in the
+ // frame buffer. Fails if the buffer is too small or the direcdtory
+ // contains no more files.
+ // The frame buffer's PlaintextOffset parameter will be set to the first
+ // byte of the data segment. Set this value to zero if you want
+ // encrypted headers.
+ Result_t ReadFrame(FrameBuffer&) const;
+ };
+
+ //
+ class MXFWriter
+ {
+ class h__Writer;
+ mem_ptr<h__Writer> m_Writer;
+ ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
+
+ public:
+ MXFWriter();
+ virtual ~MXFWriter();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for writing. The file must not exist. Returns error if
+ // the operation cannot be completed or if nonsensical data is discovered
+ // in the essence descriptor.
+ Result_t OpenWrite(const char* filename, const WriterInfo&,
+ const DCDataDescriptor&, ui32_t HeaderSize = 16384);
+
+ // 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.
+ Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+
+ // Closes the MXF file, writing the index and revised header.
+ Result_t Finalize();
+ };
+
+ //
+ class MXFReader
+ {
+ class h__Reader;
+ mem_ptr<h__Reader> m_Reader;
+ ASDCP_NO_COPY_CONSTRUCT(MXFReader);
+
+ public:
+ MXFReader();
+ virtual ~MXFReader();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for reading. The file must exist. Returns error if the
+ // operation cannot be completed.
+ Result_t OpenRead(const char* filename) const;
+
+ // Returns RESULT_INIT if the file is not open.
+ Result_t Close() const;
+
+ // Fill a DCDataDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillDCDataDescriptor(DCDataDescriptor&) const;
+
+ // Fill a WriterInfo struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillWriterInfo(WriterInfo&) const;
+
+ // Reads a frame of essence from the MXF file. If the optional AESEncContext
+ // argument is present, the essence is decrypted after reading. If the MXF
+ // file is encrypted and the AESDecContext argument is NULL, the frame buffer
+ // will contain the ciphertext frame data. If the HMACContext argument is
+ // not NULL, the HMAC will be calculated (if the file supports it).
+ // Returns RESULT_INIT if the file is not open, failure if the frame number is
+ // out of range, or if optional decrypt or HAMC operations fail.
+ Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Using the index table read from the footer partition, lookup the frame number
+ // and return the offset into the file at which to read that frame of essence.
+ // Returns RESULT_INIT if the file is not open, and RESULT_RANGE if the frame number is
+ // out of range.
+ Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const;
+
+ // Print debugging information to stream
+ void DumpHeaderMetadata(FILE* = 0) const;
+ void DumpIndex(FILE* = 0) const;
+ };
+
+ } // namespace DCData
+
+ //---------------------------------------------------------------------------------
+ //
+ namespace ATMOS
+ {
+ struct AtmosDescriptor : public DCData::DCDataDescriptor
+ {
+ ui32_t FirstFrame; // Frame number of the frame to align with the FFOA of the picture track
+ ui16_t MaxChannelCount; // Max number of channels in bitstream
+ ui16_t MaxObjectCount; // Max number of objects in bitstream
+ byte_t AtmosID[UUIDlen]; // UUID of Atmos Project
+ ui8_t AtmosVersion; // ATMOS Coder Version used to create bitstream
+ };
+
+ // Print AtmosDescriptor to std::ostream
+ std::ostream& operator << (std::ostream& strm, const AtmosDescriptor& adesc);
+ // Print debugging information to stream (stderr default)
+ void AtmosDescriptorDump(const AtmosDescriptor&, FILE* = 0);
+ // Determine if a file is a raw atmos file
+ bool IsDolbyAtmos(const char* filename);
+
+ //
+ class MXFWriter
+ {
+
+ class h__Writer;
+ mem_ptr<h__Writer> m_Writer;
+ ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
+
+ public:
+ MXFWriter();
+ virtual ~MXFWriter();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for writing. The file must not exist. Returns error if
+ // the operation cannot be completed or if nonsensical data is discovered
+ // in the essence descriptor.
+ Result_t OpenWrite(const char* filename, const WriterInfo&,
+ const AtmosDescriptor&, ui32_t HeaderSize = 16384);
+
+ // 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.
+ Result_t WriteFrame(const DCData::FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+
+ // Closes the MXF file, writing the index and revised header.
+ Result_t Finalize();
+ };
+
+ //
+ class MXFReader
+ {
+ class h__Reader;
+ mem_ptr<h__Reader> m_Reader;
+ ASDCP_NO_COPY_CONSTRUCT(MXFReader);
+
+ public:
+ MXFReader();
+ virtual ~MXFReader();
+
+ // Warning: direct manipulation of MXF structures can interfere
+ // with the normal operation of the wrapper. Caveat emptor!
+ virtual MXF::OPAtomHeader& OPAtomHeader();
+ virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+ // Open the file for reading. The file must exist. Returns error if the
+ // operation cannot be completed.
+ Result_t OpenRead(const char* filename) const;
+
+ // Returns RESULT_INIT if the file is not open.
+ Result_t Close() const;
+
+ // Fill an AtmosDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillAtmosDescriptor(AtmosDescriptor&) const;
+
+ // Fill a WriterInfo struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillWriterInfo(WriterInfo&) const;
+
+ // Reads a frame of essence from the MXF file. If the optional AESEncContext
+ // argument is present, the essence is decrypted after reading. If the MXF
+ // file is encrypted and the AESDecContext argument is NULL, the frame buffer
+ // will contain the ciphertext frame data. If the HMACContext argument is
+ // not NULL, the HMAC will be calculated (if the file supports it).
+ // Returns RESULT_INIT if the file is not open, failure if the frame number is
+ // out of range, or if optional decrypt or HAMC operations fail.
+ Result_t ReadFrame(ui32_t frame_number, DCData::FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Using the index table read from the footer partition, lookup the frame number
+ // and return the offset into the file at which to read that frame of essence.
+ // Returns RESULT_INIT if the file is not open, and RESULT_RANGE if the frame number is
+ // out of range.
+ Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const;
+
+ // Print debugging information to stream
+ void DumpHeaderMetadata(FILE* = 0) const;
+ void DumpIndex(FILE* = 0) const;
+ };
+
+ } // namespace ATMOS
+
+
} // namespace ASDCP
diff --git a/src/AS_DCP_ATMOS.cpp b/src/AS_DCP_ATMOS.cpp
new file mode 100644
index 0000000..da23a0a
--- /dev/null
+++ b/src/AS_DCP_ATMOS.cpp
@@ -0,0 +1,455 @@
+/*
+Copyright (c) 2004-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AS_DCP_ATMOS.cpp
+ \version $Id$
+ \brief AS-DCP library, Dolby Atmos essence reader and writer implementation
+*/
+
+
+#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_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 };
+} // namespace ATMOS
+} // namespace ASDCP
+
+//
+std::ostream&
+ASDCP::ATMOS::operator << (std::ostream& strm, const AtmosDescriptor& ADesc)
+{
+ char str_buf[40];
+ strm << " EditRate: " << ADesc.EditRate.Numerator << "/" << ADesc.EditRate.Denominator << std::endl;
+ strm << " ContainerDuration: " << (unsigned) ADesc.ContainerDuration << std::endl;
+ strm << " DataEssenceCoding: " << UL(ADesc.DataEssenceCoding).EncodeString(str_buf, 40) << std::endl;
+ strm << " AtmosVersion: " << (unsigned) ADesc.AtmosVersion << std::endl;
+ strm << " MaxChannelCount: " << (unsigned) ADesc.MaxChannelCount << std::endl;
+ strm << " MaxObjectCount: " << (unsigned) ADesc.MaxObjectCount << std::endl;
+ strm << " AtmosID: " << UUID(ADesc.AtmosID).EncodeString(str_buf, 40) << std::endl;
+ strm << " FirstFrame: " << (unsigned) ADesc.FirstFrame << std::endl;
+ return strm;
+}
+
+//
+void
+ASDCP::ATMOS::AtmosDescriptorDump(const AtmosDescriptor& ADesc, FILE* stream)
+{
+ char str_buf[40];
+ char atmosID_buf[40];
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "\
+ EditRate: %d/%d\n\
+ ContainerDuration: %u\n\
+ DataEssenceCoding: %s\n\
+ AtmosVersion: %u\n\
+ MaxChannelCount: %u\n\
+ MaxObjectCount: %u\n\
+ AtmosID: %s\n\
+ FirsFrame: %u\n",
+ ADesc.EditRate.Numerator, ADesc.EditRate.Denominator,
+ ADesc.ContainerDuration,
+ UL(ADesc.DataEssenceCoding).EncodeString(str_buf, 40),
+ ADesc.AtmosVersion,
+ ADesc.MaxChannelCount,
+ ADesc.MaxObjectCount,
+ UUID(ADesc.AtmosID).EncodeString(atmosID_buf, 40),
+ ADesc.FirstFrame);
+}
+
+//
+bool
+ASDCP::ATMOS::IsDolbyAtmos(const char* filename)
+{
+ // TODO
+ // For now use an atmos extension
+ bool result = (0 == (std::string("atmos").compare(Kumu::PathGetExtension(std::string(filename)))));
+ return result;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+
+class ASDCP::ATMOS::MXFReader::h__Reader : public ASDCP::DCData::h__Reader
+{
+ MXF::DolbyAtmosSubDescriptor* m_EssenceSubDescriptor;
+
+ ASDCP_NO_COPY_CONSTRUCT(h__Reader);
+ h__Reader();
+
+ public:
+ AtmosDescriptor m_ADesc;
+
+ h__Reader(const Dictionary& d) : DCData::h__Reader(d), m_EssenceSubDescriptor(NULL),
+ m_ADesc() {}
+ ~h__Reader() {}
+ Result_t OpenRead(const char*);
+ Result_t MD_to_Atmos_ADesc(ATMOS::AtmosDescriptor& ADesc);
+};
+
+ASDCP::Result_t
+ASDCP::ATMOS::MXFReader::h__Reader::MD_to_Atmos_ADesc(ATMOS::AtmosDescriptor& ADesc)
+{
+ ASDCP_TEST_NULL(m_EssenceSubDescriptor);
+ Result_t result = MD_to_DCData_DDesc(ADesc);
+ if( ASDCP_SUCCESS(result) )
+ {
+ MXF::DolbyAtmosSubDescriptor* ADescObj = m_EssenceSubDescriptor;
+ ADesc.MaxChannelCount = ADescObj->MaxChannelCount;
+ ADesc.MaxObjectCount = ADescObj->MaxObjectCount;
+ ::memcpy(ADesc.AtmosID, ADescObj->AtmosID.Value(), UUIDlen);
+ ADesc.AtmosVersion = ADescObj->AtmosVersion;
+ ADesc.FirstFrame = ADescObj->FirstFrame;
+ }
+ return result;
+}
+
+//
+//
+ASDCP::Result_t
+ASDCP::ATMOS::MXFReader::h__Reader::OpenRead(const char* filename)
+{
+ Result_t result = DCData::h__Reader::OpenRead(filename);
+
+ 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 ( ASDCP_SUCCESS(result) )
+ {
+ result = MD_to_Atmos_ADesc(m_ADesc);
+ }
+ }
+
+ return result;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::ATMOS::MXFReader::MXFReader()
+{
+ m_Reader = new h__Reader(DefaultSMPTEDict());
+}
+
+
+ASDCP::ATMOS::MXFReader::~MXFReader()
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ m_Reader->Close();
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::ATMOS::MXFReader::OPAtomHeader()
+{
+ if ( m_Reader.empty() )
+ {
+ assert(g_OPAtomHeader);
+ return *g_OPAtomHeader;
+ }
+
+ return m_Reader->m_HeaderPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomIndexFooter&
+ASDCP::ATMOS::MXFReader::OPAtomIndexFooter()
+{
+ if ( m_Reader.empty() )
+ {
+ assert(g_OPAtomIndexFooter);
+ return *g_OPAtomIndexFooter;
+ }
+
+ return m_Reader->m_FooterPart;
+}
+
+// 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
+{
+ return m_Reader->OpenRead(filename);
+}
+
+//
+ASDCP::Result_t
+ASDCP::ATMOS::MXFReader::ReadFrame(ui32_t FrameNum, DCData::FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
+
+ return RESULT_INIT;
+}
+
+ASDCP::Result_t
+ASDCP::ATMOS::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
+{
+ return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
+}
+
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::ATMOS::MXFReader::FillAtmosDescriptor(AtmosDescriptor& ADesc) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ ADesc = m_Reader->m_ADesc;
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::ATMOS::MXFReader::FillWriterInfo(WriterInfo& Info) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ Info = m_Reader->m_Info;
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+//
+void
+ASDCP::ATMOS::MXFReader::DumpHeaderMetadata(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_HeaderPart.Dump(stream);
+}
+
+//
+void
+ASDCP::ATMOS::MXFReader::DumpIndex(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_FooterPart.Dump(stream);
+}
+
+//
+ASDCP::Result_t
+ASDCP::ATMOS::MXFReader::Close() const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ m_Reader->Close();
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+//
+class ASDCP::ATMOS::MXFWriter::h__Writer : public DCData::h__Writer
+{
+ MXF::DolbyAtmosSubDescriptor* m_EssenceSubDescriptor;
+
+ ASDCP_NO_COPY_CONSTRUCT(h__Writer);
+ h__Writer();
+
+ public:
+ AtmosDescriptor m_ADesc;
+
+ h__Writer(const Dictionary& d) : DCData::h__Writer(d),
+ m_EssenceSubDescriptor(NULL), m_ADesc() {}
+
+ ~h__Writer(){}
+
+ Result_t OpenWrite(const char*, ui32_t HeaderSize, const AtmosDescriptor& ADesc);
+ Result_t Atmos_ADesc_to_MD(const AtmosDescriptor& ADesc);
+};
+
+//
+ASDCP::Result_t
+ASDCP::ATMOS::MXFWriter::h__Writer::Atmos_ADesc_to_MD(const AtmosDescriptor& ADesc)
+{
+ ASDCP_TEST_NULL(m_EssenceDescriptor);
+ ASDCP_TEST_NULL(m_EssenceSubDescriptor);
+ MXF::DolbyAtmosSubDescriptor * ADescObj = m_EssenceSubDescriptor;
+ ADescObj->MaxChannelCount = ADesc.MaxChannelCount;
+ ADescObj->MaxObjectCount = ADesc.MaxObjectCount;
+ ADescObj->AtmosID.Set(ADesc.AtmosID);
+ ADescObj->AtmosVersion = ADesc.AtmosVersion;
+ ADescObj->FirstFrame = ADesc.FirstFrame;
+ return RESULT_OK;
+}
+
+//
+ASDCP::Result_t
+ASDCP::ATMOS::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize, const AtmosDescriptor& ADesc)
+{
+
+ 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;
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_ADesc = ADesc;
+ memcpy(m_ADesc.DataEssenceCoding, ATMOS_ESSENCE_CODING, SMPTE_UL_LENGTH);
+ result = Atmos_ADesc_to_MD(m_ADesc);
+ }
+
+ return result;
+}
+
+
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::ATMOS::MXFWriter::MXFWriter()
+{
+}
+
+ASDCP::ATMOS::MXFWriter::~MXFWriter()
+{
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::ATMOS::MXFWriter::OPAtomHeader()
+{
+ if ( m_Writer.empty() )
+ {
+ assert(g_OPAtomHeader);
+ return *g_OPAtomHeader;
+ }
+
+ 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::ATMOS::MXFWriter::OPAtomIndexFooter()
+{
+ if ( m_Writer.empty() )
+ {
+ assert(g_OPAtomIndexFooter);
+ return *g_OPAtomIndexFooter;
+ }
+
+ return m_Writer->m_FooterPart;
+}
+
+// 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,
+ const AtmosDescriptor& ADesc, ui32_t HeaderSize)
+{
+ if ( Info.LabelSetType != LS_MXF_SMPTE )
+ {
+ DefaultLogSink().Error("Atmos support requires LS_MXF_SMPTE\n");
+ return RESULT_FORMAT;
+ }
+
+ m_Writer = new h__Writer(DefaultSMPTEDict());
+ 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();
+
+ 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::ATMOS::MXFWriter::WriteFrame(const DCData::FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
+}
+
+// Closes the MXF file, writing the index and other closing information.
+ASDCP::Result_t
+ASDCP::ATMOS::MXFWriter::Finalize()
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->Finalize();
+}
+
+
+//
+// end AS_DCP_ATMOS.cpp
+//
+
+
diff --git a/src/AS_DCP_DCData.cpp b/src/AS_DCP_DCData.cpp
new file mode 100644
index 0000000..53e4497
--- /dev/null
+++ b/src/AS_DCP_DCData.cpp
@@ -0,0 +1,554 @@
+/*
+Copyright (c) 2004-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AS_DCP_DCData.cpp
+ \version $Id$
+ \brief AS-DCP library, Dcinema generic data essence reader and writer implementation
+*/
+
+#include <iostream>
+
+#include "AS_DCP.h"
+#include "AS_DCP_DCData_internal.h"
+#include "AS_DCP_internal.h"
+
+namespace ASDCP
+{
+namespace DCData
+{
+ static std::string DC_DATA_PACKAGE_LABEL = "File Package: SMPTE 382M frame wrapping of D-Cinema Generic data";
+ static std::string DC_DATA_DEF_LABEL = "D-Cinema Generic Data Track";
+} // namespace DCData
+} // namespace ASDCP
+
+//
+std::ostream&
+ASDCP::DCData::operator << (std::ostream& strm, const DCDataDescriptor& DDesc)
+{
+ char str_buf[40];
+ strm << " EditRate: " << DDesc.EditRate.Numerator << "/" << DDesc.EditRate.Denominator << std::endl;
+ strm << " ContainerDuration: " << (unsigned) DDesc.ContainerDuration << std::endl;
+ strm << " DataEssenceCoding: " << UL(DDesc.DataEssenceCoding).EncodeString(str_buf, 40) << std::endl;
+ return strm;
+}
+
+//
+void
+ASDCP::DCData::DCDataDescriptorDump(const DCDataDescriptor& DDesc, FILE* stream)
+{
+ char str_buf[40];
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "\
+ EditRate: %d/%d\n\
+ ContainerDuration: %u\n\
+ DataEssenceCoding: %s\n",
+ DDesc.EditRate.Numerator, DDesc.EditRate.Denominator,
+ DDesc.ContainerDuration,
+ UL(DDesc.DataEssenceCoding).EncodeString(str_buf, 40));
+}
+
+
+//------------------------------------------------------------------------------------------
+
+
+ASDCP::Result_t
+ASDCP::DCData::h__Reader::MD_to_DCData_DDesc(DCData::DCDataDescriptor& DDesc)
+{
+ ASDCP_TEST_NULL(m_EssenceDescriptor);
+ MXF::DCDataDescriptor* 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::DCData::h__Reader::OpenRead(const char* filename)
+{
+ Result_t result = OpenMXFRead(filename);
+
+ if( ASDCP_SUCCESS(result) )
+ {
+ if (NULL == m_EssenceDescriptor)
+ {
+ InterchangeObject* iObj = NULL;
+ result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(DCDataDescriptor), &iObj);
+ m_EssenceDescriptor = static_cast<MXF::DCDataDescriptor*>(iObj);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ 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 )
+ {
+ 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) )
+ result = InitMXFIndex();
+
+ if( ASDCP_SUCCESS(result) )
+ result = InitInfo();
+
+ return result;
+}
+
+//
+//
+ASDCP::Result_t
+ASDCP::DCData::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_DCDataEssence), Ctx, HMAC);
+}
+
+
+//
+//------------------------------------------------------------------------------------------
+
+class ASDCP::DCData::MXFReader::h__Reader : public DCData::h__Reader
+{
+ ASDCP_NO_COPY_CONSTRUCT(h__Reader);
+ h__Reader();
+
+ public:
+ h__Reader(const Dictionary& d) : DCData::h__Reader(d) {}
+};
+
+
+//------------------------------------------------------------------------------------------
+
+
+//
+void
+ASDCP::DCData::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "Frame: %06u, %7u bytes\n", m_FrameNumber, m_Size);
+
+ if ( dump_len > 0 )
+ Kumu::hexdump(m_Data, dump_len, stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::DCData::MXFReader::MXFReader()
+{
+ m_Reader = new h__Reader(DefaultSMPTEDict());
+}
+
+
+ASDCP::DCData::MXFReader::~MXFReader()
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ m_Reader->Close();
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::DCData::MXFReader::OPAtomHeader()
+{
+ if ( m_Reader.empty() )
+ {
+ assert(g_OPAtomHeader);
+ return *g_OPAtomHeader;
+ }
+
+ return m_Reader->m_HeaderPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomIndexFooter&
+ASDCP::DCData::MXFReader::OPAtomIndexFooter()
+{
+ if ( m_Reader.empty() )
+ {
+ assert(g_OPAtomIndexFooter);
+ return *g_OPAtomIndexFooter;
+ }
+
+ return m_Reader->m_FooterPart;
+}
+
+// Open the file for reading. The file must exist. Returns error if the
+// operation cannot be completed.
+ASDCP::Result_t
+ASDCP::DCData::MXFReader::OpenRead(const char* filename) const
+{
+ return m_Reader->OpenRead(filename);
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
+
+ return RESULT_INIT;
+}
+
+ASDCP::Result_t
+ASDCP::DCData::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
+{
+ return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
+}
+
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::DCData::MXFReader::FillDCDataDescriptor(DCDataDescriptor& DDesc) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ DDesc = m_Reader->m_DDesc;
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::DCData::MXFReader::FillWriterInfo(WriterInfo& Info) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ Info = m_Reader->m_Info;
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+//
+void
+ASDCP::DCData::MXFReader::DumpHeaderMetadata(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_HeaderPart.Dump(stream);
+}
+
+
+//
+void
+ASDCP::DCData::MXFReader::DumpIndex(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_FooterPart.Dump(stream);
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::MXFReader::Close() const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ m_Reader->Close();
+ return RESULT_OK;
+ }
+
+ return RESULT_INIT;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+
+//
+ASDCP::Result_t
+ASDCP::DCData::h__Writer::DCData_DDesc_to_MD(DCData::DCDataDescriptor& DDesc)
+{
+ ASDCP_TEST_NULL(m_EssenceDescriptor);
+ MXF::DCDataDescriptor* DDescObj = static_cast<MXF::DCDataDescriptor *>(m_EssenceDescriptor);
+
+ DDescObj->SampleRate = DDesc.EditRate;
+ DDescObj->ContainerDuration = DDesc.ContainerDuration;
+ DDescObj->DataEssenceCoding.Set(DDesc.DataEssenceCoding);
+
+ return RESULT_OK;
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::h__Writer::OpenWrite(char const* filename, ui32_t HeaderSize,
+ const SubDescriptorList_t& subDescriptors)
+{
+ 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::DCDataDescriptor(m_Dict);
+ 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();
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::h__Writer::SetSourceStream(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 )
+ {
+ 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_DCDataEssence), 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 = WriteMXFHeader(packageLabel, UL(m_Dict->ul(MDD_DCDataWrapping)),
+ defLabel, UL(m_EssenceUL), UL(m_Dict->ul(MDD_DataDataDef)),
+ m_DDesc.EditRate, TCFrameRate);
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::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, 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::DCData::h__Writer::Finalize()
+{
+ if ( ! m_State.Test_RUNNING() )
+ return RESULT_STATE;
+
+ m_State.Goto_FINAL();
+
+ return WriteMXFFooter();
+}
+
+
+//
+//------------------------------------------------------------------------------------------
+
+
+class ASDCP::DCData::MXFWriter::h__Writer : public DCData::h__Writer
+{
+ ASDCP_NO_COPY_CONSTRUCT(h__Writer);
+ h__Writer();
+
+ public:
+ h__Writer(const Dictionary& d) : DCData::h__Writer(d) {}
+};
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::DCData::MXFWriter::MXFWriter()
+{
+}
+
+ASDCP::DCData::MXFWriter::~MXFWriter()
+{
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper. Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::DCData::MXFWriter::OPAtomHeader()
+{
+ if ( m_Writer.empty() )
+ {
+ assert(g_OPAtomHeader);
+ return *g_OPAtomHeader;
+ }
+
+ 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::DCData::MXFWriter::OPAtomIndexFooter()
+{
+ if ( m_Writer.empty() )
+ {
+ assert(g_OPAtomIndexFooter);
+ return *g_OPAtomIndexFooter;
+ }
+
+ return m_Writer->m_FooterPart;
+}
+
+// Open the file for writing. The file must not exist. Returns error if
+// the operation cannot be completed.
+ASDCP::Result_t
+ASDCP::DCData::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
+ const DCDataDescriptor& DDesc, ui32_t HeaderSize)
+{
+ if ( Info.LabelSetType != LS_MXF_SMPTE )
+ {
+ DefaultLogSink().Error("DC Data support requires LS_MXF_SMPTE\n");
+ return RESULT_FORMAT;
+ }
+
+ m_Writer = new h__Writer(DefaultSMPTEDict());
+ m_Writer->m_Info = Info;
+
+ Result_t result = m_Writer->OpenWrite(filename, HeaderSize, SubDescriptorList_t());
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_Writer->SetSourceStream(DDesc, NULL, DC_DATA_PACKAGE_LABEL, DC_DATA_DEF_LABEL);
+
+ if ( ASDCP_FAILURE(result) )
+ m_Writer.release();
+
+ 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::DCData::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
+}
+
+// Closes the MXF file, writing the index and other closing information.
+ASDCP::Result_t
+ASDCP::DCData::MXFWriter::Finalize()
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->Finalize();
+}
+
+
+//
+// end AS_DCP_DCData.cpp
+//
diff --git a/src/AS_DCP_DCData_internal.h b/src/AS_DCP_DCData_internal.h
new file mode 100644
index 0000000..65d6c41
--- /dev/null
+++ b/src/AS_DCP_DCData_internal.h
@@ -0,0 +1,94 @@
+/*
+Copyright (c) 2004-2012, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AS_DCP_DCData_internal.h
+ \version $Id$
+ \brief AS-DCP library, non-public common DCData reader and writer implementation
+*/
+
+#ifndef _AS_DCP_DCDATA_INTERNAL_H_
+#define _AS_DCP_DCDATA_INTERNAL_H_
+
+#include <list>
+
+#include "AS_DCP_internal.h"
+
+namespace ASDCP
+{
+
+namespace MXF
+{
+ class InterchangeObject;
+}
+
+namespace DCData
+{
+ typedef std::list<MXF::InterchangeObject*> SubDescriptorList_t;
+
+ class h__Reader : public ASDCP::h__ASDCPReader
+ {
+ MXF::DCDataDescriptor* m_EssenceDescriptor;
+ ASDCP_NO_COPY_CONSTRUCT(h__Reader);
+ h__Reader();
+
+ public:
+ DCDataDescriptor m_DDesc;
+
+ h__Reader(const Dictionary& d) : ASDCP::h__ASDCPReader(d), m_EssenceDescriptor(0),
+ m_DDesc() {}
+ ~h__Reader() {}
+ Result_t OpenRead(const char*);
+ Result_t ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
+ Result_t MD_to_DCData_DDesc(DCData::DCDataDescriptor& DDesc);
+ };
+
+ class h__Writer : public ASDCP::h__Writer
+ {
+ ASDCP_NO_COPY_CONSTRUCT(h__Writer);
+ h__Writer();
+
+ public:
+ DCDataDescriptor m_DDesc;
+ byte_t m_EssenceUL[SMPTE_UL_LENGTH];
+
+ h__Writer(const Dictionary& d) : ASDCP::h__Writer(d) {
+ memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
+ }
+
+ ~h__Writer(){}
+
+ Result_t OpenWrite(const char*, ui32_t HeaderSize, const SubDescriptorList_t& subDescriptors);
+ Result_t SetSourceStream(const 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(DCData::DCDataDescriptor& DDesc);
+};
+
+
+} // namespace DCData
+} // namespace ASDCP
+
+#endif // _AS_DCP_DCDATA_INTERNAL_H_
diff --git a/src/AS_DCP_JP2K.cpp b/src/AS_DCP_JP2K.cpp
index 33d5b93..300a6a2 100755
--- a/src/AS_DCP_JP2K.cpp
+++ b/src/AS_DCP_JP2K.cpp
@@ -280,6 +280,22 @@ lh__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc)
return RESULT_OK;
}
+// Compares the actual floating point value of the rates.
+// This allows, for example, {300000,1001} and {2997,100) to be considered equivalent.
+// to 29.97.
+bool
+epsilon_compare(const ASDCP::Rational& left, const ASDCP::Rational& right, double epsilon = 0.001)
+{
+ bool result = false;
+ double difference = left.Quotient() - right.Quotient();
+
+ if (fabs(difference) < epsilon)
+ result = true;
+
+ return result;
+}
+// end DOLBY
+
//
//
ASDCP::Result_t
@@ -459,6 +475,8 @@ ASDCP::JP2K::MXFReader::MXFReader()
ASDCP::JP2K::MXFReader::~MXFReader()
{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ m_Reader->Close();
}
// Warning: direct manipulation of MXF structures can interfere
@@ -510,6 +528,12 @@ ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
return RESULT_INIT;
}
+ASDCP::Result_t
+ASDCP::JP2K::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
+{
+ return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
+}
+
// Fill the struct with the values from the file's header.
// Returns RESULT_INIT if the file is not open.
@@ -663,6 +687,8 @@ ASDCP::JP2K::MXFSReader::MXFSReader()
ASDCP::JP2K::MXFSReader::~MXFSReader()
{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ m_Reader->Close();
}
// Warning: direct manipulation of MXF structures can interfere
@@ -731,6 +757,12 @@ ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, F
return RESULT_INIT;
}
+ASDCP::Result_t
+ASDCP::JP2K::MXFSReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
+{
+ return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
+}
+
// Fill the struct with the values from the file's header.
// Returns RESULT_INIT if the file is not open.
ASDCP::Result_t
diff --git a/src/AS_DCP_MPEG2.cpp b/src/AS_DCP_MPEG2.cpp
index 2081630..61ab7b7 100755
--- a/src/AS_DCP_MPEG2.cpp
+++ b/src/AS_DCP_MPEG2.cpp
@@ -333,6 +333,8 @@ ASDCP::MPEG2::MXFReader::MXFReader()
ASDCP::MPEG2::MXFReader::~MXFReader()
{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ m_Reader->Close();
}
// Warning: direct manipulation of MXF structures can interfere
@@ -387,6 +389,13 @@ ASDCP::MPEG2::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
//
ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
+{
+ return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
+}
+
+//
+ASDCP::Result_t
ASDCP::MPEG2::MXFReader::ReadFrameGOPStart(ui32_t FrameNum, FrameBuffer& FrameBuf,
AESDecContext* Ctx, HMACContext* HMAC) const
{
diff --git a/src/AS_DCP_MXF.cpp b/src/AS_DCP_MXF.cpp
index 96fc959..4d039f0 100755
--- a/src/AS_DCP_MXF.cpp
+++ b/src/AS_DCP_MXF.cpp
@@ -191,6 +191,13 @@ ASDCP::EssenceType(const char* filename, EssenceType_t& type)
type = ESS_MPEG2_VES;
else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(TimedTextDescriptor))) )
type = ESS_TIMED_TEXT;
+ else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(DCDataDescriptor))) )
+ {
+ if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(DolbyAtmosSubDescriptor))) )
+ type = ESS_DCDATA_DOLBY_ATMOS;
+ else
+ type = ESS_DCDATA_UNKNOWN;
+ }
}
return result;
@@ -205,6 +212,7 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type)
ASDCP::FrameBuffer FB;
Kumu::FileReader Reader;
ASDCP::Wav::SimpleWaveHeader WavHeader;
+ ASDCP::RF64::SimpleRF64Header RF64Header;
ASDCP::AIFF::SimpleAIFFHeader AIFFHeader;
Kumu::XMLElement TmpElement("Tmp");
@@ -248,6 +256,16 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type)
return RESULT_FORMAT;
}
}
+ else if ( ASDCP_SUCCESS(RF64Header.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
+ {
+ switch ( RF64Header.samplespersec )
+ {
+ case 48000: type = ESS_PCM_24b_48k; break;
+ case 96000: type = ESS_PCM_24b_96k; break;
+ default:
+ return RESULT_FORMAT;
+ }
+ }
else if ( ASDCP_SUCCESS(AIFFHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
{
type = ESS_PCM_24b_48k;
@@ -256,6 +274,10 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type)
{
type = ESS_TIMED_TEXT;
}
+ else if ( ASDCP::ATMOS::IsDolbyAtmos(filename) )
+ {
+ type = ESS_DCDATA_DOLBY_ATMOS;
+ }
}
}
else if ( Kumu::PathIsDirectory(filename) )
@@ -298,6 +320,21 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type)
return RESULT_FORMAT;
}
}
+ else if ( ASDCP_SUCCESS(RF64Header.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
+ {
+ switch ( RF64Header.samplespersec )
+ {
+ case 48000: type = ESS_PCM_24b_48k; break;
+ case 96000: type = ESS_PCM_24b_96k; break;
+ default:
+ return RESULT_FORMAT;
+ }
+ }
+ else if ( ASDCP::ATMOS::IsDolbyAtmos(Str.c_str()) )
+ {
+ type = ESS_DCDATA_DOLBY_ATMOS;
+ }
+
}
break;
diff --git a/src/AS_DCP_PCM.cpp b/src/AS_DCP_PCM.cpp
index 606a6f5..e52b27f 100755
--- a/src/AS_DCP_PCM.cpp
+++ b/src/AS_DCP_PCM.cpp
@@ -134,6 +134,35 @@ ASDCP::PCM::operator << (std::ostream& strm, const AudioDescriptor& ADesc)
strm << " AvgBps: " << (unsigned) ADesc.AvgBps << std::endl;
strm << " LinkedTrackID: " << (unsigned) ADesc.LinkedTrackID << std::endl;
strm << " ContainerDuration: " << (unsigned) ADesc.ContainerDuration << std::endl;
+ strm << " ChannelFormat: ";
+ switch (ADesc.ChannelFormat)
+ {
+ case CF_NONE:
+ default:
+ strm << "No Channel Format";
+ break;
+
+ case CF_CFG_1:
+ strm << "Config 1 (5.1 with optional HI/VI)";
+ break;
+
+ case CF_CFG_2:
+ strm << "Config 2 (5.1 + center surround with optional HI/VI)";
+ break;
+
+ case CF_CFG_3:
+ strm << "Config 3 (7.1 with optional HI/VI)";
+ break;
+
+ case CF_CFG_4:
+ strm << "Config 4";
+ break;
+
+ case CF_CFG_5:
+ strm << "Config 5 (7.1 DS with optional HI/VI)";
+ break;
+ }
+ strm << std::endl;
return strm;
}
@@ -154,7 +183,8 @@ ASDCP::PCM::AudioDescriptorDump(const AudioDescriptor& ADesc, FILE* stream)
BlockAlign: %u\n\
AvgBps: %u\n\
LinkedTrackID: %u\n\
- ContainerDuration: %u\n",
+ ContainerDuration: %u\n\
+ ChannelFormat: %u\n",
ADesc.EditRate.Numerator, ADesc.EditRate.Denominator,
ADesc.AudioSamplingRate.Numerator, ADesc.AudioSamplingRate.Denominator,
ADesc.Locked,
@@ -163,7 +193,8 @@ ASDCP::PCM::AudioDescriptorDump(const AudioDescriptor& ADesc, FILE* stream)
ADesc.BlockAlign,
ADesc.AvgBps,
ADesc.LinkedTrackID,
- ADesc.ContainerDuration
+ ADesc.ContainerDuration,
+ ADesc.ChannelFormat
);
}
@@ -256,6 +287,7 @@ ASDCP::PCM::MXFReader::h__Reader::OpenRead(const char* filename)
}
else
{
+ DefaultLogSink().Error("PCM EditRate not in expected value range.\n");
// or we just drop the hammer
return RESULT_FORMAT;
}
@@ -370,6 +402,12 @@ ASDCP::PCM::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
}
+ASDCP::Result_t
+ASDCP::PCM::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
+{
+ return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
+}
+
// Fill the struct with the values from the file's header.
// Returns RESULT_INIT if the file is not open.
ASDCP::Result_t
diff --git a/src/AS_DCP_TimedText.cpp b/src/AS_DCP_TimedText.cpp
index 971fe08..694676d 100644
--- a/src/AS_DCP_TimedText.cpp
+++ b/src/AS_DCP_TimedText.cpp
@@ -92,7 +92,7 @@ ASDCP::TimedText::DescriptorDump(ASDCP::TimedText::TimedTextDescriptor const& TD
fprintf(stream, "ContainerDuration: %u\n", TDesc.ContainerDuration);
fprintf(stream, " AssetID: %s\n", TmpID.EncodeHex(buf, 64));
fprintf(stream, " NamespaceName: %s\n", TDesc.NamespaceName.c_str());
- fprintf(stream, " ResourceCount: %d\n", TDesc.ResourceList.size());
+ fprintf(stream, " ResourceCount: %zu\n", TDesc.ResourceList.size());
TimedText::ResourceList_t::const_iterator ri;
for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end(); ri++ )
@@ -567,7 +567,7 @@ ASDCP::TimedText::MXFWriter::h__Writer::SetSourceStream(ASDCP::TimedText::TimedT
{
InitHeader();
AddDMSegment(m_TDesc.EditRate, 24, TIMED_TEXT_DEF_LABEL,
- UL(m_Dict->ul(MDD_PictureDataDef)), TIMED_TEXT_PACKAGE_LABEL);
+ UL(m_Dict->ul(MDD_DataDataDef)), TIMED_TEXT_PACKAGE_LABEL);
AddEssenceDescriptor(UL(m_Dict->ul(MDD_TimedTextWrapping)));
diff --git a/src/AS_DCP_internal.h b/src/AS_DCP_internal.h
index af6b553..5310100 100755
--- a/src/AS_DCP_internal.h
+++ b/src/AS_DCP_internal.h
@@ -25,7 +25,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*! \file AS_DCP_internal.h
- \version $Id$
+ \version $Id$
\brief AS-DCP library, non-public common elements
*/
@@ -62,7 +62,7 @@ namespace ASDCP
std::vector<int> result;
const char* pstr = str;
const char* r = strchr(pstr, '.');
-
+
while ( r != 0 )
{
assert(r >= pstr);
@@ -132,7 +132,7 @@ namespace ASDCP
const ASDCP::WriterInfo& Info, Kumu::fpos_t& LastPosition, ASDCP::FrameBuffer& CtFrameBuf,
ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
-
+
//
class KLReader : public ASDCP::KLVPacket
{
@@ -146,7 +146,7 @@ namespace ASDCP
inline const byte_t* Key() { return m_KeyBuf; }
inline const ui64_t Length() { return m_ValueLength; }
inline const ui64_t KLLength() { return m_KLLength; }
-
+
Result_t ReadKLFromFile(Kumu::FileReader& Reader);
};
@@ -207,7 +207,7 @@ namespace ASDCP
if ( KM_SUCCESS(result) )
{
Result_t cr_result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CryptographicContext), &Object);
-
+
if ( KM_SUCCESS(cr_result) )
MD_to_CryptoInfo((CryptographicContext*)Object, m_Info, *m_Dict);
}
@@ -223,7 +223,9 @@ namespace ASDCP
if ( KM_SUCCESS(result) )
result = m_HeaderPart.InitFromFile(m_File);
-
+ else
+ DefaultLogSink().Error("ASDCP::h__Reader::OpenMXFRead, OpenRead failed\n");
+
return result;
}
@@ -266,6 +268,28 @@ namespace ASDCP
FrameNum, SequenceNum, FrameBuf, EssenceUL, Ctx, HMAC);
}
+ // Get the position of a frame from a track file
+ Result_t LocateFrame(const ASDCP::MXF::Partition& CurrentPartition,
+ ui32_t FrameNum, Kumu::fpos_t& streamOffset,
+ i8_t& temporalOffset, i8_t& keyFrameOffset)
+ {
+ // look up frame index node
+ IndexTableSegment::IndexEntry TmpEntry;
+
+ if ( KM_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
+ {
+ DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
+ return RESULT_RANGE;
+ }
+
+ // get frame position, temporal offset, and key frame ofset
+ streamOffset = CurrentPartition.BodyOffset + TmpEntry.StreamOffset;
+ temporalOffset = TmpEntry.TemporalOffset;
+ keyFrameOffset = TmpEntry.KeyFrameOffset;
+
+ return RESULT_OK;
+ }
+
//
void Close() {
m_File.Close();
@@ -291,6 +315,9 @@ namespace ASDCP
Result_t InitMXFIndex();
Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
+ Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset,
+ i8_t& temporalOffset, i8_t& keyFrameOffset);
+
};
@@ -392,13 +419,13 @@ namespace ASDCP
{
public:
byte_t Data[klv_intpack_size];
-
+
IntegrityPack() {
memset(Data, 0, klv_intpack_size);
}
~IntegrityPack() {}
-
+
Result_t CalcValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
Result_t TestValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
};
diff --git a/src/AtmosSyncChannel_Generator.cpp b/src/AtmosSyncChannel_Generator.cpp
new file mode 100644
index 0000000..b9b8c44
--- /dev/null
+++ b/src/AtmosSyncChannel_Generator.cpp
@@ -0,0 +1,149 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AtmosSyncChannel_Generator.cpp
+ \version $Id$
+ \brief Dolby Atmos sync channel generator implementation
+*/
+
+#include <AtmosSyncChannel_Generator.h>
+
+#include <AS_DCP.h>
+
+using namespace ASDCP;
+
+//
+ASDCP::PCM::AtmosSyncChannelGenerator::AtmosSyncChannelGenerator(ui16_t bitsPerSample, ui32_t sampleRate,
+ const ASDCP::Rational& editRate, const byte_t* uuid)
+ : m_syncEncoder(),
+ m_audioTrackUUID(),
+ m_ADesc(),
+ m_syncSignalBuffer(NULL),
+ m_numSamplesPerFrame(0),
+ m_currentFrameNumber(0),
+ m_numBytesPerFrame(0),
+ m_isSyncEncoderInitialized(false)
+{
+
+ m_ADesc.EditRate = editRate;
+ m_ADesc.ChannelCount = 1;
+ m_ADesc.QuantizationBits = bitsPerSample;
+ m_ADesc.AudioSamplingRate = Rational(sampleRate, 1);
+ m_ADesc.BlockAlign = ((bitsPerSample + 7) / 8);
+ m_ADesc.AvgBps = (sampleRate * m_ADesc.BlockAlign);
+
+ memcpy(&m_audioTrackUUID.abyUUIDBytes[0], uuid, UUIDlen);
+ m_numSamplesPerFrame = (editRate.Denominator * sampleRate) / editRate.Numerator;
+ m_numBytesPerFrame = m_numSamplesPerFrame * m_ADesc.BlockAlign;
+
+ if (bitsPerSample == 24)
+ {
+ ui32_t frameRate = editRate.Numerator/editRate.Denominator; // intentionally allowing for imprecise cast to int
+ m_isSyncEncoderInitialized = (SyncEncoderInit(&m_syncEncoder, sampleRate, frameRate, &m_audioTrackUUID) == SYNC_ENCODER_ERROR_NONE);
+ m_syncSignalBuffer = new float[m_numSamplesPerFrame];
+ }
+ else
+ {
+ m_isSyncEncoderInitialized = false;
+ }
+}
+
+ASDCP::PCM::AtmosSyncChannelGenerator::~AtmosSyncChannelGenerator()
+{
+ delete [] m_syncSignalBuffer;
+}
+
+ASDCP::Result_t
+ASDCP::PCM::AtmosSyncChannelGenerator::ReadFrame(FrameBuffer& OutFB)
+{
+ if (OutFB.Capacity() < m_numBytesPerFrame)
+ {
+ return RESULT_SMALLBUF;
+ }
+
+ /**
+ * Update frame number and size.
+ */
+ OutFB.FrameNumber(m_currentFrameNumber);
+ OutFB.Size(m_numBytesPerFrame);
+
+ /**
+ * Get pointer to frame essence.
+ */
+ byte_t* frameEssence = OutFB.Data();
+
+ if (m_isSyncEncoderInitialized)
+ {
+ /**
+ * Generate sync signal frame.
+ */
+ int ret = EncodeSync(&m_syncEncoder, m_numSamplesPerFrame, m_syncSignalBuffer, m_currentFrameNumber);
+ if (ret == SYNC_ENCODER_ERROR_NONE)
+ {
+ for (unsigned int i = 0; i < m_numSamplesPerFrame; ++i)
+ {
+ /**
+ * Convert each encoded float sample to a signed 24 bit integer and
+ * copy into the essence buffer.
+ */
+ i32_t sample = convertSampleFloatToInt24(m_syncSignalBuffer[i]);
+ memcpy(frameEssence, ((byte_t*)(&sample))+1, NUM_BYTES_PER_INT24);
+ frameEssence += NUM_BYTES_PER_INT24;
+ }
+ }
+ else
+ {
+ /**
+ * Encoding error, zero out the frame.
+ */
+ memset(frameEssence, 0, m_numBytesPerFrame);
+ }
+ }
+ else
+ {
+ /**
+ * Sync encoder not initialize, zero out the frame.
+ */
+ memset(frameEssence, 0, m_numBytesPerFrame);
+ }
+ ++m_currentFrameNumber;
+ return RESULT_OK;
+}
+
+ASDCP::Result_t
+ASDCP::PCM::AtmosSyncChannelGenerator::Reset()
+{
+ m_currentFrameNumber = 0;
+ return RESULT_OK;
+}
+
+Result_t
+ASDCP::PCM::AtmosSyncChannelGenerator::FillAudioDescriptor(AudioDescriptor& ADesc) const
+{
+ ADesc = m_ADesc;
+ return RESULT_OK;
+}
+
diff --git a/src/AtmosSyncChannel_Generator.h b/src/AtmosSyncChannel_Generator.h
new file mode 100644
index 0000000..d7f4219
--- /dev/null
+++ b/src/AtmosSyncChannel_Generator.h
@@ -0,0 +1,151 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AtmosSyncChannel_Generator.h
+ \version $Id$
+ \brief Dolby Atmos sync channel generator
+*/
+
+#ifndef _ATMOSSYNCCHANNEL_GENERATOR_H_
+#define _ATMOSSYNCCHANNEL_GENERATOR_H_
+
+#include <AS_DCP.h>
+#include "SyncEncoder.h"
+#include "UUIDInformation.h"
+
+#define INT24_MAX 8388607.0
+#define INT24_MIN -8388608.0
+
+namespace ASDCP
+{
+ namespace ATMOS
+ {
+ static const ui32_t SYNC_CHANNEL = 14;
+ }
+
+ namespace PCM
+ {
+
+ static const ui16_t NUM_BYTES_PER_INT24 = 3;
+
+ class AtmosSyncChannelGenerator
+ {
+ SYNCENCODER m_syncEncoder;
+ UUIDINFORMATION m_audioTrackUUID;
+ AudioDescriptor m_ADesc;
+ float *m_syncSignalBuffer;
+ ui32_t m_numSamplesPerFrame;
+ ui32_t m_currentFrameNumber;
+ ui32_t m_numBytesPerFrame;
+ bool m_isSyncEncoderInitialized;
+
+ ASDCP_NO_COPY_CONSTRUCT(AtmosSyncChannelGenerator);
+
+ public:
+ /**
+ * Constructor
+ *
+ * @param bitsPerSample the number of bits in each sample of pcm data
+ * @param sampleRate the sampling rate
+ * @param editRate the edit rate of the associated picture track.
+ * @param atmosUUID the UUID of the associated ATMOS track file.
+ *
+ */
+ AtmosSyncChannelGenerator(ui16_t bitsPerSample, ui32_t sampleRate,
+ const ASDCP::Rational& editRate, const byte_t* uuid);
+ ~AtmosSyncChannelGenerator();
+
+ /**
+ * Set the frame number when seeking
+ * Use override the default starting frame number for a new track or
+ * to set the frame number when doing random access.
+ *
+ * @param frameNumber
+ *
+ */
+ void setFrameNumber(ui32_t frameNumber) { m_currentFrameNumber = frameNumber; };
+
+ /**
+ * Get the number of bytes per frame.
+ *
+ * @return Number of bytes per frame
+ *
+ */
+ ui32_t getBytesPerFrame() { return m_numBytesPerFrame; }
+
+ /**
+ * Generates the next frame of sync data.
+ * Generates the next frame of sync data and places it
+ * the frame buffer. Fails if the buffer is too small.
+ * **Automatically increments the frame number.**
+ *
+ * @param buf the buffer that the generated frame data will be written to.
+ *
+ * @return Kumu::RESULT_OK if the buffer is succesfully filled with sync
+ * data for the next frame.
+ */
+ Result_t ReadFrame(FrameBuffer& buf);
+
+ /**
+ * Reset the frame count.
+ *
+ * @return Kumu::RESULT_OK
+ */
+ Result_t Reset();
+
+ /**
+ * Fill the AudioDescriptor with the relevant information.
+ *
+ * @return Kumu::RESULT_OK
+ */
+ Result_t FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const;
+
+ /**
+ * Converts a sample float into
+ * 24-bit PCM data.
+ *
+ */
+ static inline i32_t convertSampleFloatToInt24(float sample)
+ {
+ if (sample >= 0.0)
+ {
+ return (static_cast<i32_t>(sample * INT24_MAX) << 8);
+ }
+ else
+ {
+ return (static_cast<i32_t>(-sample * INT24_MIN) << 8);
+ }
+ }
+ };
+
+ } // namespace PCM
+} // namespace ASDCP
+
+#endif // _ATMOSSYNCCHANNEL_GENERATOR_H_
+
+//
+// end AtmosSyncChannel_Generator.h
+//
diff --git a/src/AtmosSyncChannel_Mixer.cpp b/src/AtmosSyncChannel_Mixer.cpp
new file mode 100644
index 0000000..70cfbfd
--- /dev/null
+++ b/src/AtmosSyncChannel_Mixer.cpp
@@ -0,0 +1,326 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AtmosSyncChannel_Mixer.cpp
+ \version $Id$
+ \brief Read WAV files(s), multiplex multiple PCM frame buffers including Atmos Sync into one
+*/
+
+#include <AtmosSyncChannel_Mixer.h>
+
+#include <algorithm>
+
+#include <AS_DCP.h>
+#include <KM_log.h>
+#include <PCMDataProviders.h>
+
+using namespace ASDCP;
+using namespace Kumu;
+
+//
+ASDCP::AtmosSyncChannelMixer::AtmosSyncChannelMixer(const byte_t * trackUUID)
+ : m_inputs(), m_outputs(), m_trackUUID(), m_ADesc(), m_ChannelCount(0), m_FramesRead(0)
+{
+ ::memcpy(m_trackUUID, trackUUID, UUIDlen);
+}
+
+ASDCP::AtmosSyncChannelMixer::~AtmosSyncChannelMixer()
+{
+ clear();
+}
+
+void
+ASDCP::AtmosSyncChannelMixer::clear()
+{
+ m_outputs.clear();
+ std::for_each(m_inputs.begin(), m_inputs.end(), delete_input());
+ m_inputs.clear();
+}
+
+//
+Result_t
+ASDCP::AtmosSyncChannelMixer::OpenRead(ui32_t argc, const char** argv, const Rational& PictureRate)
+{
+ ASDCP_TEST_NULL_STR(argv);
+ PathList_t TmpFileList;
+
+ for ( ui32_t i = 0; i < argc; ++i )
+ TmpFileList.push_back(argv[i]);
+
+ return OpenRead(TmpFileList, PictureRate);
+}
+
+//
+Result_t
+ASDCP::AtmosSyncChannelMixer::OpenRead(const Kumu::PathList_t& argv, const Rational& PictureRate)
+{
+ Result_t result = RESULT_OK;
+ PathList_t::iterator fi;
+ Kumu::PathList_t file_list;
+ PCM::AudioDescriptor tmpDesc;
+
+ if ( argv.size() == 1 && PathIsDirectory(argv.front()) )
+ {
+ DirScanner Dir;
+ char name_buf[MaxFilePath];
+ result = Dir.Open(argv.front().c_str());
+
+ if ( KM_SUCCESS(result) )
+ result = Dir.GetNext(name_buf);
+
+ while ( KM_SUCCESS(result) )
+ {
+ if ( name_buf[0] != '.' ) // no hidden files
+ {
+ std::string tmp_path = argv.front() + "/" + name_buf;
+ file_list.push_back(tmp_path);
+ }
+
+ result = Dir.GetNext(name_buf);
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ {
+ result = RESULT_OK;
+ file_list.sort();
+ }
+ }
+ else
+ {
+ file_list = argv;
+ }
+
+ for ( fi = file_list.begin(); KM_SUCCESS(result) && fi != file_list.end(); ++fi )
+ {
+ result = OpenRead(*fi, PictureRate);
+ }
+
+ if ( ASDCP_SUCCESS(result) && (m_ChannelCount < ATMOS::SYNC_CHANNEL))
+ {
+ // atmos sync channel has not been added
+ result = MixInSilenceChannels();
+ if ( ASDCP_SUCCESS(result) )
+ result = MixInAtmosSyncChannel();
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_ADesc.ChannelCount = m_ChannelCount;
+ m_ADesc.AvgBps = (ui32_t)(ceil(m_ADesc.AudioSamplingRate.Quotient()) * m_ADesc.BlockAlign);
+ }
+ else
+ {
+ clear();
+ }
+
+ return result;
+}
+
+//
+Result_t
+ASDCP::AtmosSyncChannelMixer::OpenRead(const std::string& file, const Rational& PictureRate)
+{
+ Result_t result = RESULT_OK;
+ PCM::AudioDescriptor tmpDesc;
+ ui32_t numChannels = 0;
+ mem_ptr<WAVDataProvider> I = new WAVDataProvider;
+ result = I->OpenRead(file.c_str(), PictureRate);
+
+ if ( ASDCP_SUCCESS(result))
+ {
+ result = I->FillAudioDescriptor(tmpDesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+
+ if ( m_ChannelCount == 0 )
+ {
+ m_ADesc = tmpDesc;
+ }
+ else
+ {
+
+ if ( tmpDesc.AudioSamplingRate != m_ADesc.AudioSamplingRate )
+ {
+ DefaultLogSink().Error("AudioSamplingRate mismatch in PCM parser list.");
+ return RESULT_FORMAT;
+ }
+
+ if ( tmpDesc.QuantizationBits != m_ADesc.QuantizationBits )
+ {
+ DefaultLogSink().Error("QuantizationBits mismatch in PCM parser list.");
+ return RESULT_FORMAT;
+ }
+
+ if ( tmpDesc.ContainerDuration < m_ADesc.ContainerDuration )
+ m_ADesc.ContainerDuration = tmpDesc.ContainerDuration;
+
+ m_ADesc.BlockAlign += tmpDesc.BlockAlign;
+ }
+ }
+
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ numChannels = tmpDesc.ChannelCount; // default to all channels
+ if ((m_ChannelCount < ATMOS::SYNC_CHANNEL) && (m_ChannelCount + numChannels) > (ATMOS::SYNC_CHANNEL - 1))
+ {
+ // need to insert an atmos channel between the channels of this file.
+ numChannels = ATMOS::SYNC_CHANNEL - m_ChannelCount - 1;
+ m_outputs.push_back(std::make_pair(numChannels, I.get()));
+ m_ChannelCount += numChannels;
+ MixInAtmosSyncChannel();
+ numChannels = tmpDesc.ChannelCount - numChannels;
+ }
+ m_outputs.push_back(std::make_pair(numChannels, I.get()));
+ m_inputs.push_back(I);
+ I.release();
+ m_ChannelCount += numChannels;
+ }
+ return result;
+}
+
+Result_t
+ASDCP::AtmosSyncChannelMixer::MixInSilenceChannels()
+{
+ Result_t result = RESULT_OK;
+ PCM::AudioDescriptor tmpDesc;
+ ui32_t numSilenceChannels = ATMOS::SYNC_CHANNEL - m_ChannelCount - 1;
+ if (numSilenceChannels > 0)
+ {
+ mem_ptr<SilenceDataProvider> I = new SilenceDataProvider(numSilenceChannels,
+ m_ADesc.QuantizationBits,
+ m_ADesc.AudioSamplingRate.Numerator,
+ m_ADesc.EditRate);
+ result = I->FillAudioDescriptor(tmpDesc);
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_ADesc.BlockAlign += tmpDesc.BlockAlign;
+ m_ChannelCount += tmpDesc.ChannelCount;
+ m_outputs.push_back(std::make_pair(numSilenceChannels, I.get()));
+ m_inputs.push_back(I);
+ I.release();
+ assert(m_ChannelCount == (ATMOS::SYNC_CHANNEL - 1));
+ }
+ }
+ return result;
+}
+
+//
+Result_t
+ASDCP::AtmosSyncChannelMixer::MixInAtmosSyncChannel()
+{
+ Result_t result = RESULT_OK;
+ PCM::AudioDescriptor tmpDesc;
+ mem_ptr<AtmosSyncDataProvider> I = new AtmosSyncDataProvider(m_ADesc.QuantizationBits,
+ m_ADesc.AudioSamplingRate.Numerator,
+ m_ADesc.EditRate, m_trackUUID);
+ result = I->FillAudioDescriptor(tmpDesc);
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_ADesc.BlockAlign += tmpDesc.BlockAlign;
+ m_ChannelCount += tmpDesc.ChannelCount;
+ m_outputs.push_back(std::make_pair(tmpDesc.ChannelCount, I.get()));
+ m_inputs.push_back(I);
+ I.release();
+ assert(m_ChannelCount == ATMOS::SYNC_CHANNEL);
+ }
+ return result;
+}
+
+//
+Result_t
+ASDCP::AtmosSyncChannelMixer::FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const
+{
+ ADesc = m_ADesc;
+ return RESULT_OK;
+}
+
+//
+Result_t
+ASDCP::AtmosSyncChannelMixer::Reset()
+{
+ Result_t result = RESULT_OK;
+ SourceList::iterator it;
+ SourceList::iterator lastInput = m_inputs.end();
+
+ for ( it = m_inputs.begin(); it != lastInput && ASDCP_SUCCESS(result) ; ++it )
+ result = (*it)->Reset();
+
+ return result;
+}
+
+
+//2
+Result_t
+ASDCP::AtmosSyncChannelMixer::ReadFrame(PCM::FrameBuffer& OutFB)
+{
+
+
+ Result_t result = RESULT_OK;
+ SourceList::iterator iter;
+ SourceList::iterator lastInput = m_inputs.end();
+ ui32_t bufSize = PCM::CalcFrameBufferSize(m_ADesc);
+ assert( bufSize <= OutFB.Capacity());
+
+ for ( iter = m_inputs.begin(); iter != lastInput && ASDCP_SUCCESS(result) ; ++iter )
+ result = (*iter)->ReadFrame();
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ OutFB.Size(bufSize);
+ byte_t* Out_p = OutFB.Data();
+ byte_t* End_p = Out_p + OutFB.Size();
+ ui32_t bytesWritten = 0;
+ OutputList::iterator iter;
+ OutputList::iterator lastOutput = m_outputs.end();
+
+ while ( Out_p < End_p && ASDCP_SUCCESS(result) )
+ {
+ iter = m_outputs.begin();
+ while ( iter != lastOutput && ASDCP_SUCCESS(result) )
+ {
+ result = ((*iter).second)->PutSample((*iter).first, Out_p, &bytesWritten);
+ Out_p += bytesWritten;
+ ++iter;
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ assert(Out_p == End_p);
+ OutFB.FrameNumber(m_FramesRead++);
+ }
+ }
+
+ return result;
+}
+
+
+//
+// end AtmosSyncChannel_Mixer.cpp
+//
diff --git a/src/AtmosSyncChannel_Mixer.h b/src/AtmosSyncChannel_Mixer.h
new file mode 100644
index 0000000..c6a27a3
--- /dev/null
+++ b/src/AtmosSyncChannel_Mixer.h
@@ -0,0 +1,91 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AtmosSyncChannel_Mixer.h
+ \version $Id$
+ \brief Read WAV files(s), multiplex multiple PCM frame buffers including Atmos Sync into one
+*/
+
+#ifndef _ATMOSSYNCCHANNEL_MIXER_H_
+#define _ATMOSSYNCCHANNEL_MIXER_H_
+
+#include <AS_DCP.h>
+#include <KM_error.h>
+#include <PCMDataProviders.h>
+#include <vector>
+
+namespace ASDCP
+{
+
+ //
+ class AtmosSyncChannelMixer
+ {
+ typedef std::pair<ui32_t, PCMDataProviderInterface*> InputBus;
+ typedef std::vector<InputBus> OutputList;
+ typedef std::vector<PCMDataProviderInterface*> SourceList;
+
+ SourceList m_inputs;
+ OutputList m_outputs;
+ byte_t m_trackUUID[ASDCP::UUIDlen];
+
+ Result_t OpenRead(const std::string& file, const Rational& PictureRate);
+ Result_t MixInSilenceChannels();
+ Result_t MixInAtmosSyncChannel();
+ void clear();
+
+ // functor for deleting
+ struct delete_input
+ {
+ void operator()(PCMDataProviderInterface* i)
+ {
+ delete i;
+ }
+ };
+
+ ASDCP_NO_COPY_CONSTRUCT(AtmosSyncChannelMixer);
+
+ protected:
+ PCM::AudioDescriptor m_ADesc;
+ ui32_t m_ChannelCount;
+ ui32_t m_FramesRead;
+
+ public:
+ AtmosSyncChannelMixer(const byte_t * trackUUID);
+ virtual ~AtmosSyncChannelMixer();
+
+ Result_t OpenRead(ui32_t argc, const char** argv, const Rational& PictureRate);
+ Result_t OpenRead(const Kumu::PathList_t& argv, const Rational& PictureRate);
+ Result_t FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const;
+ Result_t Reset();
+ Result_t ReadFrame(PCM::FrameBuffer& OutFB);
+ };
+} // namespace ASDCP
+
+#endif // _ATMOSSYNCCHANNEL_MIXER_H_
+
+//
+// end AtmosSyncChannel_Mixer.h
+//
diff --git a/src/CRC16.c b/src/CRC16.c
new file mode 100644
index 0000000..3e2f09e
--- /dev/null
+++ b/src/CRC16.c
@@ -0,0 +1,86 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file CRC16.c
+ \version $Id$
+ \brief Implementation of a CRC function
+*/
+
+#include "CRC16.h"
+
+static const unsigned short g_aushCRC16tab[256]= {
+ 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
+ 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
+ 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
+ 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
+ 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
+ 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
+ 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
+ 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
+ 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
+ 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
+ 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
+ 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
+ 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
+ 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
+ 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
+ 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
+ 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
+ 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
+ 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
+ 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
+ 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
+ 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
+ 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
+ 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
+ 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
+ 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
+ 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
+ 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
+ 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
+ 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
+ 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
+ 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
+};
+
+unsigned short CRC16(const void *pData, int ilength)
+{
+ int n;
+ unsigned short ushCRC;
+ unsigned char *puchData;
+
+
+ puchData = (unsigned char*)pData;
+
+ ushCRC = 0;
+ for(n = 0; n < ilength; n ++){
+
+ ushCRC = (ushCRC << 8) ^ g_aushCRC16tab[((ushCRC>>8) ^ *puchData) & 0x00FF];
+ puchData ++;
+ }
+
+ return ushCRC;
+}
diff --git a/src/CRC16.h b/src/CRC16.h
new file mode 100644
index 0000000..6d3beb3
--- /dev/null
+++ b/src/CRC16.h
@@ -0,0 +1,45 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file CRC16.h
+ \version $Id$
+ \brief Declaration of a CRC function
+*/
+
+#ifndef _CRC_16_H_
+#define _CRC_16_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+unsigned short CRC16(const void *pData, int ilength);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/src/DCData_ByteStream_Parser.cpp b/src/DCData_ByteStream_Parser.cpp
new file mode 100644
index 0000000..73565d4
--- /dev/null
+++ b/src/DCData_ByteStream_Parser.cpp
@@ -0,0 +1,121 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AtmosSyncChannel_Mixer.h
+ \version $Id$
+ \brief AS-DCP library, Digital Cinema Data bytestream essence reader
+*/
+
+#include "AS_DCP.h"
+#include "KM_fileio.h"
+#include "KM_log.h"
+using Kumu::DefaultLogSink;
+
+//------------------------------------------------------------------------------------------
+
+class ASDCP::DCData::BytestreamParser::h__BytestreamParser
+{
+ ASDCP_NO_COPY_CONSTRUCT(h__BytestreamParser);
+
+public:
+ DCDataDescriptor m_DDesc;
+ Kumu::FileReader m_File;
+
+ h__BytestreamParser()
+ {
+ memset(&m_DDesc, 0, sizeof(m_DDesc));
+ m_DDesc.EditRate = Rational(24,1);
+ }
+
+ ~h__BytestreamParser() {}
+
+ Result_t OpenReadFrame(const char* filename, FrameBuffer& FB)
+ {
+ ASDCP_TEST_NULL_STR(filename);
+ m_File.Close();
+ Result_t result = m_File.OpenRead(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Kumu::fsize_t file_size = m_File.Size();
+
+ if ( FB.Capacity() < file_size )
+ {
+ DefaultLogSink().Error("FrameBuf.Capacity: %u frame length: %u\n", FB.Capacity(), (ui32_t)file_size);
+ return RESULT_SMALLBUF;
+ }
+ }
+
+ ui32_t read_count;
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_File.Read(FB.Data(), FB.Capacity(), &read_count);
+
+ if ( ASDCP_SUCCESS(result) )
+ FB.Size(read_count);
+
+ return result;
+ }
+};
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::DCData::BytestreamParser::BytestreamParser()
+{
+}
+
+ASDCP::DCData::BytestreamParser::~BytestreamParser()
+{
+}
+
+// Opens the stream for reading, parses enough data to provide a complete
+// set of stream metadata for the MXFWriter below.
+ASDCP::Result_t
+ASDCP::DCData::BytestreamParser::OpenReadFrame(const char* filename, FrameBuffer& FB) const
+{
+ const_cast<ASDCP::DCData::BytestreamParser*>(this)->m_Parser = new h__BytestreamParser;
+ return m_Parser->OpenReadFrame(filename, FB);
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::BytestreamParser::FillDCDataDescriptor(DCDataDescriptor& DDesc) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ DDesc = m_Parser->m_DDesc;
+ return RESULT_OK;
+}
+
+
+//
+// end DCData_Bytestream_Parser.cpp
+//
+
+
+
diff --git a/src/DCData_Sequence_Parser.cpp b/src/DCData_Sequence_Parser.cpp
new file mode 100644
index 0000000..45594c5
--- /dev/null
+++ b/src/DCData_Sequence_Parser.cpp
@@ -0,0 +1,294 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file AtmosSyncChannel_Mixer.h
+ \version $Id$
+ \brief AS-DCP library, DCinema data seqence reader implementation
+*/
+
+#include "AS_DCP.h"
+
+#include <algorithm>
+#include <list>
+#include <string>
+
+#include "KM_fileio.h"
+#include "KM_log.h"
+
+using ASDCP::Result_t;
+
+//------------------------------------------------------------------------------------------
+namespace ASDCP
+{
+namespace DCData
+{
+class FileList;
+} // namespace DCData
+} // namespace ASDCP
+
+
+class ASDCP::DCData::FileList : public std::list<std::string>
+{
+ std::string m_DirName;
+
+ public:
+ FileList() {}
+ ~FileList() {}
+
+ const FileList& operator=(const std::list<std::string>& pathlist) {
+ std::list<std::string>::const_iterator i;
+ for ( i = pathlist.begin(); i != pathlist.end(); i++ )
+ push_back(*i);
+ return *this;
+ }
+
+ //
+ Result_t InitFromDirectory(const char* path)
+ {
+ char next_file[Kumu::MaxFilePath];
+ Kumu::DirScanner Scanner;
+
+ Result_t result = Scanner.Open(path);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_DirName = path;
+
+ while ( ASDCP_SUCCESS(Scanner.GetNext(next_file)) )
+ {
+ if ( next_file[0] == '.' ) // no hidden files or internal links
+ continue;
+
+ std::string Str(m_DirName);
+ Str += "/";
+ Str += next_file;
+
+ if ( ! Kumu::PathIsDirectory(Str) )
+ push_back(Str);
+ }
+
+ sort();
+ }
+
+ return result;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+
+class ASDCP::DCData::SequenceParser::h__SequenceParser
+{
+ ui32_t m_FramesRead;
+ Rational m_PictureRate;
+ FileList m_FileList;
+ FileList::iterator m_CurrentFile;
+ BytestreamParser m_Parser;
+
+ Result_t OpenRead();
+
+ ASDCP_NO_COPY_CONSTRUCT(h__SequenceParser);
+
+ public:
+ DCDataDescriptor m_DDesc;
+
+ h__SequenceParser() : m_FramesRead(0)
+ {
+ memset(&m_DDesc, 0, sizeof(m_DDesc));
+ m_DDesc.EditRate = Rational(24,1);
+ }
+
+ ~h__SequenceParser()
+ {
+ Close();
+ }
+
+ Result_t OpenRead(const char* filename);
+ Result_t OpenRead(const std::list<std::string>& file_list);
+ void Close() {}
+
+ Result_t Reset()
+ {
+ m_FramesRead = 0;
+ m_CurrentFile = m_FileList.begin();
+ return RESULT_OK;
+ }
+
+ Result_t ReadFrame(FrameBuffer&);
+};
+
+
+//
+ASDCP::Result_t
+ASDCP::DCData::SequenceParser::h__SequenceParser::OpenRead()
+{
+ if ( m_FileList.empty() )
+ return RESULT_ENDOFFILE;
+
+ m_CurrentFile = m_FileList.begin();
+ BytestreamParser Parser;
+ FrameBuffer TmpBuffer;
+
+ Kumu::fsize_t file_size = Kumu::FileSize((*m_CurrentFile).c_str());
+
+ if ( file_size == 0 )
+ return RESULT_NOT_FOUND;
+
+ assert(file_size <= 0xFFFFFFFFL);
+ Result_t result = TmpBuffer.Capacity((ui32_t) file_size);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Parser.OpenReadFrame((*m_CurrentFile).c_str(), TmpBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Parser.FillDCDataDescriptor(m_DDesc);
+
+ // how big is it?
+ if ( ASDCP_SUCCESS(result) )
+ m_DDesc.ContainerDuration = m_FileList.size();
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::SequenceParser::h__SequenceParser::OpenRead(const char* filename)
+{
+ ASDCP_TEST_NULL_STR(filename);
+
+ Result_t result = m_FileList.InitFromDirectory(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = OpenRead();
+
+ return result;
+}
+
+
+//
+ASDCP::Result_t
+ASDCP::DCData::SequenceParser::h__SequenceParser::OpenRead(const std::list<std::string>& file_list)
+{
+ m_FileList = file_list;
+ return OpenRead();
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::SequenceParser::h__SequenceParser::ReadFrame(FrameBuffer& FB)
+{
+ if ( m_CurrentFile == m_FileList.end() )
+ return RESULT_ENDOFFILE;
+
+ // open the file
+ Result_t result = m_Parser.OpenReadFrame((*m_CurrentFile).c_str(), FB);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ FB.FrameNumber(m_FramesRead++);
+ m_CurrentFile++;
+ }
+
+ return result;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::DCData::SequenceParser::SequenceParser()
+{
+}
+
+ASDCP::DCData::SequenceParser::~SequenceParser()
+{
+}
+
+// Opens the stream for reading, parses enough data to provide a complete
+// set of stream metadata for the MXFWriter below.
+ASDCP::Result_t
+ASDCP::DCData::SequenceParser::OpenRead(const char* filename) const
+{
+ const_cast<ASDCP::DCData::SequenceParser*>(this)->m_Parser = new h__SequenceParser;
+
+ Result_t result = m_Parser->OpenRead(filename);
+
+ if ( ASDCP_FAILURE(result) )
+ const_cast<ASDCP::DCData::SequenceParser*>(this)->m_Parser.release();
+
+ return result;
+}
+
+//
+Result_t
+ASDCP::DCData::SequenceParser::OpenRead(const std::list<std::string>& file_list) const
+{
+ const_cast<ASDCP::DCData::SequenceParser*>(this)->m_Parser = new h__SequenceParser;
+
+ Result_t result = m_Parser->OpenRead(file_list);
+
+ if ( ASDCP_FAILURE(result) )
+ const_cast<ASDCP::DCData::SequenceParser*>(this)->m_Parser.release();
+
+ return result;
+}
+
+
+// Rewinds the stream to the beginning.
+ASDCP::Result_t
+ASDCP::DCData::SequenceParser::Reset() const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ return m_Parser->Reset();
+}
+
+// Places a frame of data in the frame buffer. Fails if the buffer is too small
+// or the stream is empty.
+ASDCP::Result_t
+ASDCP::DCData::SequenceParser::ReadFrame(FrameBuffer& FB) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ return m_Parser->ReadFrame(FB);
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::SequenceParser::FillDCDataDescriptor(DCDataDescriptor& DDesc) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ DDesc = m_Parser->m_DDesc;
+ return RESULT_OK;
+}
+
+
+//
+// end DCData_Sequence_Parser.cpp
+//
+
diff --git a/src/Index.cpp b/src/Index.cpp
index 449d5bf..f377585 100755
--- a/src/Index.cpp
+++ b/src/Index.cpp
@@ -143,7 +143,7 @@ ASDCP::MXF::IndexTableSegment::Dump(FILE* stream)
}
else
{
- fprintf(stream, " IndexEntryArray: %du entries\n", IndexEntryArray.size());
+ fprintf(stream, " IndexEntryArray: %zu entries\n", IndexEntryArray.size());
}
}
diff --git a/src/MDD.cpp b/src/MDD.cpp
index 5627624..5afb75e 100644
--- a/src/MDD.cpp
+++ b/src/MDD.cpp
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2006-2012, John Hurst
+Copyright (c) 2006-2013, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -917,6 +917,85 @@ static const ASDCP::MDDEntry s_MDD_Table[] = {
{ { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 293
0x01, 0x03, 0x07, 0x01, 0x04, 0x00, 0x00, 0x00 },
{0}, false, "SoundfieldGroupLabelSubDescriptor_GroupOfSoundfieldGroupsLinkID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x05, // 294
+ 0x0e, 0x09, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCDataWrapping" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x05, // 295
+ 0x0e, 0x09, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCDataEssence" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x05, // 296
+ 0x0e, 0x09, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCDataDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x05, // 297
+ 0x0e, 0x09, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DolbyAtmosSubDescriptor" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 298
+ 0x0e, 0x09, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00 },
+ {0}, true, "DolbyAtmosSubDescriptor_AtmosVersion" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 299
+ 0x0e, 0x09, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00 },
+ {0}, true, "DolbyAtmosSubDescriptor_MaxChannelCount" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 300
+ 0x0e, 0x09, 0x05, 0x08, 0x00, 0x00, 0x00, 0x00 },
+ {0}, true, "DolbyAtmosSubDescriptor_MaxObjectCount" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 301
+ 0x0e, 0x09, 0x05, 0x09, 0x00, 0x00, 0x00, 0x00 },
+ {0}, true, "DolbyAtmosSubDescriptor_AtmosID" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 302
+ 0x0e, 0x09, 0x05, 0x0A, 0x00, 0x00, 0x00, 0x00 },
+ {0}, true, "DolbyAtmosSubDescriptor_FirstFrame" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 303
+ 0x01, 0x03, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00 },
+ {0}, false, "DataDataDef" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 304
+ 0x04, 0x02, 0x02, 0x10, 0x03, 0x02, 0x00, 0x00 },
+ {0}, false, "DCAudioChannelCfg_MCA" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 305
+ 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCAudioChannel_L" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 306
+ 0x03, 0x02, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCAudioChannel_R" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 307
+ 0x03, 0x02, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCAudioChannel_C" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 308
+ 0x03, 0x02, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCAudioChannel_LFE" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 309
+ 0x03, 0x02, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCAudioChannel_Ls" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 310
+ 0x03, 0x02, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCAudioChannel_Rs" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 311
+ 0x03, 0x02, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCAudioChannel_Lss" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 312
+ 0x03, 0x02, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCAudioChannel_Rss" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 313
+ 0x03, 0x02, 0x01, 0x09, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCAudioChannel_Lrs" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 314
+ 0x03, 0x02, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCAudioChannel_Rrs" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 315
+ 0x03, 0x02, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCAudioChannel_Lc" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 316
+ 0x03, 0x02, 0x01, 0x0c, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCAudioChannel_Rc" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 317
+ 0x03, 0x02, 0x01, 0x0d, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCAudioChannel_Cs" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 318
+ 0x03, 0x02, 0x01, 0x0e, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCAudioChannel_HI" },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 319
+ 0x03, 0x02, 0x01, 0x0f, 0x00, 0x00, 0x00, 0x00 },
+ {0}, false, "DCAudioChannel_VIN" },
+
{ {0}, {0}, false, 0 }
};
diff --git a/src/MDD.h b/src/MDD.h
index 358b874..ab8482f 100755
--- a/src/MDD.h
+++ b/src/MDD.h
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2006-2012, John Hurst
+Copyright (c) 2006-2013, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -290,46 +290,72 @@ namespace ASDCP {
MDD_CryptographicContext_CipherAlgorithm, // 252
MDD_CryptographicContext_MICAlgorithm, // 253
MDD_CryptographicContext_CryptographicKeyID, // 254
- MDD_TimedTextWrapping, // 255
- MDD_TimedTextEssence, // 256
- MDD_TimedTextDescriptor, // 257
- MDD_TimedTextDescriptor_ResourceID, // 258
- MDD_TimedTextDescriptor_UCSEncoding, // 259
- MDD_TimedTextDescriptor_NamespaceURI, // 260
- MDD_TimedTextResourceSubDescriptor, // 261
- MDD_TimedTextResourceSubDescriptor_AncillaryResourceID, // 262
- MDD_TimedTextResourceSubDescriptor_MIMEMediaType, // 263
- MDD_TimedTextResourceSubDescriptor_EssenceStreamID_DEPRECATED, // 264
- MDD_GenericStreamPartition, // 265
- MDD_DMSegment_DataDefinition_DEPRECATED, // 266
- MDD_DMSegment_Duration_DEPRECATED, // 267
- MDD_DMSegment_TrackIDList, // 268
- MDD_StereoscopicPictureSubDescriptor, // 269
+ MDD_TimedTextWrapping, // 255
+ MDD_TimedTextEssence, // 256
+ MDD_TimedTextDescriptor, // 257
+ MDD_TimedTextDescriptor_ResourceID, // 258
+ MDD_TimedTextDescriptor_UCSEncoding, // 259
+ MDD_TimedTextDescriptor_NamespaceURI, // 260
+ MDD_TimedTextResourceSubDescriptor, // 261
+ MDD_TimedTextResourceSubDescriptor_AncillaryResourceID, // 262
+ MDD_TimedTextResourceSubDescriptor_MIMEMediaType, // 263
+ MDD_TimedTextResourceSubDescriptor_EssenceStreamID_DEPRECATED, // 264
+ MDD_GenericStreamPartition, // 265
+ MDD_DMSegment_DataDefinition_DEPRECATED, // 266
+ MDD_DMSegment_Duration_DEPRECATED, // 267
+ MDD_DMSegment_TrackIDList, // 268
+ MDD_StereoscopicPictureSubDescriptor, // 269
MDD_WaveAudioDescriptor_ChannelAssignment, // 270
- MDD_GenericStream_DataElement, // 271
+ MDD_GenericStream_DataElement, // 271
MDD_MXFInterop_GenericDescriptor_SubDescriptors, // 272
- MDD_Core_BodySID, // 273
- MDD_Core_IndexSID, // 274
- MDD_Core_OperationalPattern, // 275
- MDD_Core_EssenceContainers, // 276
- MDD_DCAudioChannelCfg_1_5p1, // 277
- MDD_DCAudioChannelCfg_2_6p1, // 278
- MDD_DCAudioChannelCfg_3_7p1, // 279
- MDD_DCAudioChannelCfg_4_WTF, // 280
- MDD_DCAudioChannelCfg_5_7p1_DS, // 281
- MDD_MCALabelSubDescriptor, // 282
- MDD_AudioChannelLabelSubDescriptor, // 283
- MDD_SoundfieldGroupLabelSubDescriptor, // 284
- MDD_GroupOfSoundfieldGroupsLabelSubDescriptor, // 285
- MDD_MCALabelSubDescriptor_MCALabelDictionaryID, // 286
- MDD_MCALabelSubDescriptor_MCALinkID, // 287
- MDD_MCALabelSubDescriptor_MCATagSymbol, // 288
- MDD_MCALabelSubDescriptor_MCATagName, // 289
- MDD_MCALabelSubDescriptor_MCAChannelID, // 290
- MDD_MCALabelSubDescriptor_RFC5646SpokenLanguage, // 291
- MDD_AudioChannelLabelSubDescriptor_SoundfieldGroupLinkID, // 292
- MDD_SoundfieldGroupLabelSubDescriptor_GroupOfSoundfieldGroupsLinkID, // 293
- MDD_Max
+ MDD_Core_BodySID, // 273
+ MDD_Core_IndexSID, // 274
+ MDD_Core_OperationalPattern, // 275
+ MDD_Core_EssenceContainers, // 276
+ MDD_DCAudioChannelCfg_1_5p1, // 277
+ MDD_DCAudioChannelCfg_2_6p1, // 278
+ MDD_DCAudioChannelCfg_3_7p1, // 279
+ MDD_DCAudioChannelCfg_4_WTF, // 280
+ MDD_DCAudioChannelCfg_5_7p1_DS, // 281
+ MDD_MCALabelSubDescriptor, // 282
+ MDD_AudioChannelLabelSubDescriptor, // 283
+ MDD_SoundfieldGroupLabelSubDescriptor, // 284
+ MDD_GroupOfSoundfieldGroupsLabelSubDescriptor, // 285
+ MDD_MCALabelSubDescriptor_MCALabelDictionaryID, // 286
+ MDD_MCALabelSubDescriptor_MCALinkID, // 287
+ MDD_MCALabelSubDescriptor_MCATagSymbol, // 288
+ MDD_MCALabelSubDescriptor_MCATagName, // 289
+ MDD_MCALabelSubDescriptor_MCAChannelID, // 290
+ MDD_MCALabelSubDescriptor_RFC5646SpokenLanguage, // 291
+ MDD_AudioChannelLabelSubDescriptor_SoundfieldGroupLinkID, // 292
+ MDD_SoundfieldGroupLabelSubDescriptor_GroupOfSoundfieldGroupsLinkID, // 293
+ MDD_DCDataWrapping, // 294
+ MDD_DCDataEssence, // 295
+ MDD_DCDataDescriptor, // 296
+ MDD_DolbyAtmosSubDescriptor, // 297
+ MDD_DolbyAtmosSubDescriptor_AtmosVersion, // 298
+ MDD_DolbyAtmosSubDescriptor_MaxChannelCount, // 299
+ MDD_DolbyAtmosSubDescriptor_MaxObjectCount, // 300
+ MDD_DolbyAtmosSubDescriptor_AtmosID, // 301
+ MDD_DolbyAtmosSubDescriptor_FirstFrame, // 302
+ MDD_DataDataDef, // 303
+ MDD_DCAudioChannelCfg_MCA, // 304
+ MDD_DCAudioChannel_L, // 305
+ MDD_DCAudioChannel_R, // 306
+ MDD_DCAudioChannel_C, // 307
+ MDD_DCAudioChannel_LFE, // 308
+ MDD_DCAudioChannel_Ls, // 309
+ MDD_DCAudioChannel_Rs, // 310
+ MDD_DCAudioChannel_Lss, // 311
+ MDD_DCAudioChannel_Rss, // 312
+ MDD_DCAudioChannel_Lrs, // 313
+ MDD_DCAudioChannel_Rrs, // 314
+ MDD_DCAudioChannel_Lc, // 315
+ MDD_DCAudioChannel_Rc, // 316
+ MDD_DCAudioChannel_Cs, // 317
+ MDD_DCAudioChannel_HI, // 318
+ MDD_DCAudioChannel_VIN, // 319
+ MDD_Max
}; // enum MDD_t
@@ -342,7 +368,7 @@ namespace ASDCP {
const MDD_t MDD_Preface_EssenceContainers = MDD_Core_EssenceContainers;
const MDD_t MDD_Preface_OperationalPattern = MDD_Core_OperationalPattern;
const MDD_t MDD_TimedTextResourceSubDescriptor_EssenceStreamID = MDD_Core_BodySID;
-
+
} // namespaceASDCP
diff --git a/src/MXF.cpp b/src/MXF.cpp
index 7f042ee..1b9e558 100755
--- a/src/MXF.cpp
+++ b/src/MXF.cpp
@@ -725,12 +725,20 @@ ASDCP::MXF::OPAtomHeader::InitFromFile(const Kumu::FileReader& Reader)
}
}
}
+ else
+ {
+ DefaultLogSink().Error("OPAtomHeader::InitFromFile, SeekToRIP failed\n");
+ }
if ( ASDCP_SUCCESS(result) )
result = Reader.Seek(0);
+ else
+ DefaultLogSink().Error("OPAtomHeader::InitFromFile, Seek failed\n");
if ( ASDCP_SUCCESS(result) )
result = Partition::InitFromFile(Reader); // test UL and OP
+ else
+ DefaultLogSink().Error("OPAtomHeader::InitFromFile, Partition::InitFromFile failed\n");
if ( ASDCP_FAILURE(result) )
return result;
@@ -774,7 +782,10 @@ ASDCP::MXF::OPAtomHeader::InitFromFile(const Kumu::FileReader& Reader)
result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
if ( ASDCP_FAILURE(result) )
- return result;
+ {
+ DefaultLogSink().Error("OPAtomHeader::InitFromFile, Read failed\n");
+ return result;
+ }
if ( read_count != m_Buffer.Capacity() )
{
@@ -1038,17 +1049,21 @@ ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const Kumu::FileReader& Reader)
{
Result_t result = Partition::InitFromFile(Reader); // test UL and OP
- // slurp up the remainder of the footer
- ui32_t read_count;
+ // slurp up the remainder of the footer
+ ui32_t read_count = 0;
- if ( ASDCP_SUCCESS(result) )
+ if ( ASDCP_SUCCESS(result) )
{
- assert (IndexByteCount <= 0xFFFFFFFFL);
- result = m_Buffer.Capacity((ui32_t) IndexByteCount);
+ assert (IndexByteCount <= 0xFFFFFFFFL);
+ // At this point, m_Buffer may not have been initialized
+ // so it's capacity is zero and data pointer is NULL
+ // However, if IndexByteCount is zero then the capacity
+ // doesn't change and the data pointer is not set.
+ result = m_Buffer.Capacity((ui32_t) IndexByteCount);
}
- if ( ASDCP_SUCCESS(result) )
- result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
+ if ( ASDCP_SUCCESS(result) && m_Buffer.Data() )
+ result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
{
@@ -1056,6 +1071,12 @@ ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const Kumu::FileReader& Reader)
read_count, m_Buffer.Capacity());
return RESULT_FAIL;
}
+ else if( ASDCP_SUCCESS(result) && !m_Buffer.Data() )
+ {
+ DefaultLogSink().Error( "Buffer for footer partition not created: IndexByteCount = %u\n",
+ IndexByteCount );
+ return RESULT_FAIL;
+ }
if ( ASDCP_SUCCESS(result) )
result = InitFromBuffer(m_Buffer.RoData(), m_Buffer.Capacity());
diff --git a/src/Makefile.am b/src/Makefile.am
index 6cd2da3..fdbf3c4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -61,7 +61,8 @@ include_HEADERS += \
MXFTypes.h \
MXF.h \
Wav.h \
- PCMParserList.h
+ PCMParserList.h \
+ AtmosSyncChannel_Generator.h
nodist_include_HEADERS = TimedText_Transform.h
endif
@@ -89,7 +90,16 @@ libasdcp_la_SOURCES = MPEG2_Parser.cpp MPEG.cpp JP2K_Codestream_Parser.cpp \
AS_DCP_PCM.cpp AS_DCP_TimedText.cpp PCMParserList.cpp \
Wav.h WavFileWriter.h MXF.h Metadata.h \
JP2K.h AS_DCP.h AS_DCP_internal.h KLV.h MPEG.h MXFTypes.h MDD.h \
- PCMParserList.h S12MTimecode.h MDD.cpp
+ PCMParserList.h S12MTimecode.h MDD.cpp \
+ AS_DCP_ATMOS.cpp AS_DCP_DCData.cpp AS_DCP_DCData_internal.h \
+ DCData_ByteStream_Parser.cpp DCData_Sequence_Parser.cpp \
+ AtmosSyncChannel_Generator.cpp AtmosSyncChannel_Generator.h \
+ AtmosSyncChannel_Mixer.cpp AtmosSyncChannel_Mixer.h \
+ PCMDataProviders.cpp PCMDataProviders.h \
+ SyncEncoder.c SyncEncoder.h SyncCommon.h CRC16.c CRC16.h \
+ UUIDInformation.c UUIDInformation.h
+
+
if DEV_HEADERS
nodist_libasdcp_la_SOURCES += TimedText_Transform.h TimedText_Transform.cpp
endif
diff --git a/src/Metadata.cpp b/src/Metadata.cpp
index ac1db76..3507ba0 100755
--- a/src/Metadata.cpp
+++ b/src/Metadata.cpp
@@ -73,6 +73,8 @@ static InterchangeObject* MCALabelSubDescriptor_Factory(const Dictionary*& Dict)
static InterchangeObject* AudioChannelLabelSubDescriptor_Factory(const Dictionary*& Dict) { return new AudioChannelLabelSubDescriptor(Dict); }
static InterchangeObject* SoundfieldGroupLabelSubDescriptor_Factory(const Dictionary*& Dict) { return new SoundfieldGroupLabelSubDescriptor(Dict); }
static InterchangeObject* GroupOfSoundfieldGroupsLabelSubDescriptor_Factory(const Dictionary*& Dict) { return new GroupOfSoundfieldGroupsLabelSubDescriptor(Dict); }
+static InterchangeObject* DCDataDescriptor_Factory(const Dictionary*& Dict) { return new DCDataDescriptor(Dict); }
+static InterchangeObject* DolbyAtmosSubDescriptor_Factory(const Dictionary*& Dict) { return new DolbyAtmosSubDescriptor(Dict); }
void
@@ -112,6 +114,8 @@ ASDCP::MXF::Metadata_InitTypes(const Dictionary*& Dict)
SetObjectFactory(Dict->ul(MDD_AudioChannelLabelSubDescriptor), AudioChannelLabelSubDescriptor_Factory);
SetObjectFactory(Dict->ul(MDD_SoundfieldGroupLabelSubDescriptor), SoundfieldGroupLabelSubDescriptor_Factory);
SetObjectFactory(Dict->ul(MDD_GroupOfSoundfieldGroupsLabelSubDescriptor), GroupOfSoundfieldGroupsLabelSubDescriptor_Factory);
+ SetObjectFactory(Dict->ul(MDD_DCDataDescriptor), DCDataDescriptor_Factory);
+ SetObjectFactory(Dict->ul(MDD_DolbyAtmosSubDescriptor), DolbyAtmosSubDescriptor_Factory);
}
//------------------------------------------------------------------------------------------
@@ -2888,6 +2892,170 @@ GroupOfSoundfieldGroupsLabelSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buf
return InterchangeObject::WriteToBuffer(Buffer);
}
+//------------------------------------------------------------------------------------------
+// DCDataDescriptor
+
+//
+
+DCDataDescriptor::DCDataDescriptor(const Dictionary*& d) : GenericDataEssenceDescriptor(d), m_Dict(d)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_DCDataDescriptor);
+}
+
+DCDataDescriptor::DCDataDescriptor(const DCDataDescriptor& rhs) : GenericDataEssenceDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_DCDataDescriptor);
+ Copy(rhs);
+}
+
+//
+ASDCP::Result_t
+DCDataDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ // NOTE (this function can be removed if no attributes are defined for this descriptor)
+ assert(m_Dict);
+ Result_t result = GenericDataEssenceDescriptor::InitFromTLVSet(TLVSet);
+ return result;
+}
+
+//
+ASDCP::Result_t
+DCDataDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ // NOTE (this function can be removed if no attributes are defined for this descriptor)
+ assert(m_Dict);
+ Result_t result = GenericDataEssenceDescriptor::WriteToTLVSet(TLVSet);
+ return result;
+}
+
+//
+void
+DCDataDescriptor::Copy(const DCDataDescriptor& rhs)
+{
+ GenericDataEssenceDescriptor::Copy(rhs);
+}
+
+//
+void
+DCDataDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ GenericDataEssenceDescriptor::Dump(stream);
+}
+
+//
+ASDCP::Result_t
+DCDataDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+DCDataDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// DolbyAtmosSubDescriptor
+
+//
+
+DolbyAtmosSubDescriptor::DolbyAtmosSubDescriptor(const Dictionary*& d) : InterchangeObject(d), m_Dict(d), FirstFrame(0), MaxChannelCount(0), MaxObjectCount(0), AtmosVersion(0)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_DolbyAtmosSubDescriptor);
+}
+
+DolbyAtmosSubDescriptor::DolbyAtmosSubDescriptor(const DolbyAtmosSubDescriptor& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+ assert(m_Dict);
+ m_UL = m_Dict->ul(MDD_DolbyAtmosSubDescriptor);
+ Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+DolbyAtmosSubDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(DolbyAtmosSubDescriptor, AtmosID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(DolbyAtmosSubDescriptor, FirstFrame));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(DolbyAtmosSubDescriptor, MaxChannelCount));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(DolbyAtmosSubDescriptor, MaxObjectCount));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(DolbyAtmosSubDescriptor, AtmosVersion));
+ return result;
+}
+
+//
+ASDCP::Result_t
+DolbyAtmosSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+ assert(m_Dict);
+ Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(DolbyAtmosSubDescriptor, AtmosID));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(DolbyAtmosSubDescriptor, FirstFrame));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(DolbyAtmosSubDescriptor, MaxChannelCount));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(DolbyAtmosSubDescriptor, MaxObjectCount));
+ if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(DolbyAtmosSubDescriptor, AtmosVersion));
+ return result;
+}
+
+//
+void
+DolbyAtmosSubDescriptor::Copy(const DolbyAtmosSubDescriptor& rhs)
+{
+ InterchangeObject::Copy(rhs);
+ AtmosID = rhs.AtmosID;
+ FirstFrame = rhs.FirstFrame;
+ MaxChannelCount = rhs.MaxChannelCount;
+ MaxObjectCount = rhs.MaxObjectCount;
+ AtmosVersion = rhs.AtmosVersion;
+}
+
+//
+void
+DolbyAtmosSubDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ *identbuf = 0;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ InterchangeObject::Dump(stream);
+ fprintf(stream, " %22s = %s\n", "AtmosID", AtmosID.EncodeString(identbuf, IdentBufferLen));
+ fprintf(stream, " %22s = %d\n", "FirstFrame", FirstFrame);
+ fprintf(stream, " %22s = %d\n", "MaxChannelCount", MaxChannelCount);
+ fprintf(stream, " %22s = %d\n", "MaxObjectCount", MaxObjectCount);
+ fprintf(stream, " %22s = %d\n", "AtmosVersion", AtmosVersion);
+}
+
+//
+ASDCP::Result_t
+DolbyAtmosSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+DolbyAtmosSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+
//
// end Metadata.cpp
//
diff --git a/src/Metadata.h b/src/Metadata.h
index 507a151..6b9a50c 100755
--- a/src/Metadata.h
+++ b/src/Metadata.h
@@ -889,6 +889,55 @@ namespace ASDCP
virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
};
+ //
+ class DCDataDescriptor : public GenericDataEssenceDescriptor
+ {
+ DCDataDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+
+ DCDataDescriptor(const Dictionary*& d);
+ DCDataDescriptor(const DCDataDescriptor& rhs);
+ virtual ~DCDataDescriptor() {}
+
+ const DCDataDescriptor& operator=(const DCDataDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const DCDataDescriptor& rhs);
+ virtual const char* HasName() { return "DCDataDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
+ //
+ class DolbyAtmosSubDescriptor : public InterchangeObject
+ {
+ DolbyAtmosSubDescriptor();
+
+ public:
+ const Dictionary*& m_Dict;
+ UUID AtmosID;
+ ui32_t FirstFrame;
+ ui16_t MaxChannelCount;
+ ui16_t MaxObjectCount;
+ ui8_t AtmosVersion;
+
+ DolbyAtmosSubDescriptor(const Dictionary*& d);
+ DolbyAtmosSubDescriptor(const DolbyAtmosSubDescriptor& rhs);
+ virtual ~DolbyAtmosSubDescriptor() {}
+
+ const DolbyAtmosSubDescriptor& operator=(const DolbyAtmosSubDescriptor& rhs) { Copy(rhs); return *this; }
+ virtual void Copy(const DolbyAtmosSubDescriptor& rhs);
+ virtual const char* HasName() { return "DolbyAtmosSubDescriptor"; }
+ virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+ virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ };
+
} // namespace MXF
} // namespace ASDCP
diff --git a/src/PCMDataProviders.cpp b/src/PCMDataProviders.cpp
new file mode 100644
index 0000000..7d2c152
--- /dev/null
+++ b/src/PCMDataProviders.cpp
@@ -0,0 +1,210 @@
+/*
+Copyright (c) 20013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file PCMDataProviders.cpp
+ \version $Id$
+ \brief Implementation of PCM sample data providers for WAV, AtmosSync and Silence.
+*/
+
+#include <PCMDataProviders.h>
+
+#include <KM_log.h>
+
+using namespace ASDCP;
+using namespace Kumu;
+
+ASDCP::PCMDataProviderInterface::~PCMDataProviderInterface() {}
+
+//
+ASDCP::WAVDataProvider::WAVDataProvider()
+ : m_Parser(), m_FB(), m_ADesc(), m_SampleSize(0), m_ptr(NULL)
+{}
+
+ASDCP::WAVDataProvider::~WAVDataProvider()
+{}
+
+Result_t
+ASDCP::WAVDataProvider::PutSample(const ui32_t numChannels, byte_t* buf, ui32_t* bytesWritten)
+{
+ ASDCP_TEST_NULL(buf);
+ ASDCP_TEST_NULL(m_ptr);
+ if ( numChannels > m_ADesc.ChannelCount)
+ {
+ DefaultLogSink().Error("Requested %u channels from a wav file with %u channel.", numChannels,
+ m_ADesc.ChannelCount);
+ return RESULT_FAIL;
+ }
+ *bytesWritten = m_SampleSize * numChannels;
+ ::memcpy(buf, m_ptr, *bytesWritten);
+ m_ptr += *bytesWritten;
+ return RESULT_OK;
+}
+
+Result_t
+ASDCP::WAVDataProvider::ReadFrame()
+{
+ Result_t result = m_Parser.ReadFrame(m_FB);
+ m_ptr = ASDCP_SUCCESS(result) ? m_FB.RoData() : NULL;
+ return result;
+}
+
+Result_t
+ASDCP::WAVDataProvider::FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const
+{
+ ADesc = m_ADesc;
+ return RESULT_OK;
+}
+
+Result_t
+ASDCP::WAVDataProvider::Reset()
+{
+ return m_Parser.Reset();
+}
+
+Result_t
+ASDCP::WAVDataProvider::OpenRead(const char* filename, const Rational& PictureRate)
+{
+ ASDCP_TEST_NULL_STR(filename);
+
+ Result_t result = m_Parser.OpenRead(filename, PictureRate);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_Parser.FillAudioDescriptor(m_ADesc);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_ADesc.EditRate = PictureRate;
+ m_SampleSize = ((m_ADesc.QuantizationBits + 7) / 8);
+ result = m_FB.Capacity(PCM::CalcFrameBufferSize(m_ADesc));
+ }
+
+ return result;
+}
+
+//
+ASDCP::AtmosSyncDataProvider::AtmosSyncDataProvider(const ui16_t bitsPerSample, const ui32_t sampleRate,
+ const ASDCP::Rational& editRate, const byte_t* uuid)
+ : m_Generator(bitsPerSample, sampleRate, editRate, uuid), m_FB(), m_ADesc(), m_SampleSize()
+{
+ m_Generator.FillAudioDescriptor(m_ADesc);
+ m_SampleSize = PCM::CalcSampleSize(m_ADesc);
+ m_FB.Capacity(PCM::CalcFrameBufferSize(m_ADesc));
+}
+
+ASDCP::AtmosSyncDataProvider::~AtmosSyncDataProvider()
+{}
+
+Result_t
+ASDCP::AtmosSyncDataProvider::PutSample(const ui32_t numChannels, byte_t* buf, ui32_t* bytesWritten)
+{
+ ASDCP_TEST_NULL(buf);
+ ASDCP_TEST_NULL(m_ptr);
+ if ( numChannels > m_ADesc.ChannelCount)
+ {
+ DefaultLogSink().Error("Requested %u channels from a wav file with %u channel.", numChannels,
+ m_ADesc.ChannelCount);
+ return RESULT_FAIL;
+ }
+
+ (*bytesWritten) = m_SampleSize;
+ ::memcpy(buf, m_ptr, m_SampleSize);
+ m_ptr += m_SampleSize;
+ return RESULT_OK;
+}
+
+Result_t
+ASDCP::AtmosSyncDataProvider::ReadFrame()
+{
+ Result_t result = m_Generator.ReadFrame(m_FB);
+ m_ptr = ASDCP_SUCCESS(result) ? m_FB.RoData() : NULL;
+ return result;
+}
+
+Result_t
+ASDCP::AtmosSyncDataProvider::FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const
+{
+ ADesc = m_ADesc;
+ return RESULT_OK;
+}
+
+Result_t
+ASDCP::AtmosSyncDataProvider::Reset()
+{
+ return m_Generator.Reset();
+}
+
+//
+ASDCP::SilenceDataProvider::SilenceDataProvider(const ui16_t numChannels, const ui16_t bitsPerSample,
+ const ui32_t sampleRate, const ASDCP::Rational& editRate)
+ : m_ADesc(), m_SampleSize(0)
+{
+ m_SampleSize = ((bitsPerSample + 7) / 8);
+ m_ADesc.EditRate = editRate;
+ m_ADesc.AudioSamplingRate = Rational(sampleRate, 1);
+ m_ADesc.ChannelCount = numChannels;
+ m_ADesc.QuantizationBits = bitsPerSample;
+ m_ADesc.BlockAlign = numChannels * m_SampleSize;
+ m_ADesc.AvgBps = sampleRate * m_ADesc.BlockAlign;
+}
+
+ASDCP::SilenceDataProvider::~SilenceDataProvider()
+{}
+
+Result_t
+ASDCP::SilenceDataProvider::PutSample(const ui32_t numChannels, byte_t* buf, ui32_t* bytesWritten)
+{
+ ASDCP_TEST_NULL(buf);
+ if ( numChannels > m_ADesc.ChannelCount)
+ {
+ DefaultLogSink().Error("Requested %u channels from a wav file with %u channel.", numChannels,
+ m_ADesc.ChannelCount);
+ return RESULT_FAIL;
+ }
+ (*bytesWritten) = m_SampleSize * numChannels;
+ ::memset(buf, 0, (*bytesWritten));
+ return RESULT_OK;
+}
+
+Result_t
+ASDCP::SilenceDataProvider::ReadFrame()
+{
+ // no op
+ return RESULT_OK;
+}
+
+Result_t
+ASDCP::SilenceDataProvider::FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const
+{
+ ADesc = m_ADesc;
+ return RESULT_OK;
+}
+
+Result_t
+ASDCP::SilenceDataProvider::Reset()
+{
+ //no op
+ return RESULT_OK;
+}
diff --git a/src/PCMDataProviders.h b/src/PCMDataProviders.h
new file mode 100644
index 0000000..9241fd3
--- /dev/null
+++ b/src/PCMDataProviders.h
@@ -0,0 +1,119 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file PCMDataProviders.h
+ \version $Id$
+ \brief PCM sample data providers for WAV, AtmosSync and Silence.
+*/
+
+#ifndef _PCMDATAPROVIDERS_H_
+#define _PCMDATAPROVIDERS_H_
+
+#include <AS_DCP.h>
+#include <AtmosSyncChannel_Generator.h>
+
+namespace ASDCP
+{
+
+ // PCM Data Provider Interface
+ class PCMDataProviderInterface
+ {
+ ASDCP_NO_COPY_CONSTRUCT(PCMDataProviderInterface);
+
+ public:
+ PCMDataProviderInterface() {};
+ virtual ~PCMDataProviderInterface() = 0;
+ virtual Result_t PutSample(const ui32_t numChannels, byte_t* buf, ui32_t* bytesWritten) = 0;
+ virtual Result_t ReadFrame() = 0;
+ virtual Result_t FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const = 0;
+ virtual Result_t Reset() = 0;
+ };
+
+ // WAV file implementation of the PCM Data Provider Interface
+ class WAVDataProvider : public PCMDataProviderInterface
+ {
+ ASDCP_NO_COPY_CONSTRUCT(WAVDataProvider);
+ PCM::WAVParser m_Parser;
+ PCM::FrameBuffer m_FB;
+ PCM::AudioDescriptor m_ADesc;
+ const byte_t* m_ptr;
+ ui32_t m_SampleSize;
+
+ public:
+ WAVDataProvider();
+ virtual ~WAVDataProvider();
+ virtual Result_t PutSample(const ui32_t numChannels, byte_t* buf, ui32_t* bytesWritten);
+ virtual Result_t ReadFrame();
+ virtual Result_t FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const;
+ virtual Result_t Reset();
+ Result_t OpenRead(const char* filename, const Rational& PictureRate);
+
+ };
+
+ // Atmos Sync Channel implementation of the PCM Data Provider Interface
+ class AtmosSyncDataProvider : public PCMDataProviderInterface
+ {
+ ASDCP_NO_COPY_CONSTRUCT(AtmosSyncDataProvider);
+ PCM::AtmosSyncChannelGenerator m_Generator;
+ PCM::FrameBuffer m_FB;
+ PCM::AudioDescriptor m_ADesc;
+ const byte_t* m_ptr;
+ ui32_t m_SampleSize;
+
+ public:
+ AtmosSyncDataProvider(const ui16_t bitsPerSample, const ui32_t sampleRate,
+ const ASDCP::Rational& PictureRate, const byte_t* uuid);
+ virtual ~AtmosSyncDataProvider();
+ virtual Result_t PutSample(const ui32_t numChannels, byte_t* buf, ui32_t* bytesWritten);
+ virtual Result_t ReadFrame();
+ virtual Result_t FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const;
+ virtual Result_t Reset();
+ };
+
+ // Silence Channel(s) implementation of the PCM Data Provider Interface
+ class SilenceDataProvider : public PCMDataProviderInterface
+ {
+ ASDCP_NO_COPY_CONSTRUCT(SilenceDataProvider);
+ PCM::AudioDescriptor m_ADesc;
+ ui32_t m_SampleSize;
+
+ public:
+ SilenceDataProvider(const ui16_t numChannels, const ui16_t bitsPerSample,
+ const ui32_t sampleRate, const ASDCP::Rational& editRate);
+ virtual ~SilenceDataProvider();
+ virtual Result_t PutSample(const ui32_t numChannels, byte_t* buf, ui32_t* bytesWritten);
+ virtual Result_t ReadFrame();
+ virtual Result_t FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const;
+ virtual Result_t Reset();
+ };
+
+} // namespace ASDCP
+
+#endif // _PCMDATAPROVIDERS_H_
+
+//
+// end PCMDataProviders.h
+//
diff --git a/src/PCM_Parser.cpp b/src/PCM_Parser.cpp
index 3fa6d7d..e3b693d 100755
--- a/src/PCM_Parser.cpp
+++ b/src/PCM_Parser.cpp
@@ -37,6 +37,7 @@ using Kumu::DefaultLogSink;
using namespace ASDCP;
using namespace ASDCP::PCM;
using namespace ASDCP::Wav;
+using namespace ASDCP::RF64;
//------------------------------------------------------------------------------------------
@@ -47,8 +48,8 @@ class ASDCP::PCM::WAVParser::h__WAVParser
Kumu::FileReader m_FileReader;
bool m_EOF;
ui32_t m_DataStart;
- ui32_t m_DataLength;
- ui32_t m_ReadCount;
+ ui64_t m_DataLength;
+ ui64_t m_ReadCount;
ui32_t m_FrameBufferSize;
ui32_t m_FramesRead;
Rational m_PictureRate;
@@ -129,6 +130,22 @@ ASDCP::PCM::WAVParser::h__WAVParser::OpenRead(const char* filename, const Ration
m_ADesc.ChannelFormat = PCM::CF_NONE;
Reset();
}
+ else
+ {
+ SimpleRF64Header RF64Header;
+ m_FileReader.Seek(0);
+ result = RF64Header.ReadFromFile(m_FileReader, &m_DataStart);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ RF64Header.FillADesc(m_ADesc, PictureRate);
+ m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc);
+ m_DataLength = RF64Header.data_len;
+ m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize;
+ m_ADesc.ChannelFormat = PCM::CF_NONE;
+ Reset();
+ }
+ }
}
}
diff --git a/src/SyncCommon.h b/src/SyncCommon.h
new file mode 100644
index 0000000..bc5d498
--- /dev/null
+++ b/src/SyncCommon.h
@@ -0,0 +1,80 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file SyncCommon.h
+ \version $Id$
+ \brief Common elements for ATMOS Sync Channel generation
+*/
+
+#ifndef _SYNC_COMMON_H_
+#define _SYNC_COMMON_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef BYTE
+typedef unsigned char BYTE;
+#endif
+
+#ifndef USHORT
+typedef unsigned short USHORT;
+#endif
+
+#ifndef INT
+typedef int INT;
+#endif
+
+#ifndef FLOAT
+typedef float FLOAT;
+#endif
+
+#define SYMBOL_RATE (12000)
+
+#define SYMBOL_LENGTH_48 (4)
+#define SYMBOL_LENGTH_96 (8)
+
+#define SYNC_HEADER (0x4D56)
+#define SYNC_HEADER1 (0x4D)
+#define SYNC_HEADER2 (0x56)
+
+#define SYNC_HEADER_BITS (16)
+#define FRAME_RATE_BITS (4)
+#define RESERVE_BITS (2)
+#define UUID_SUB_INDEX_BITS (2)
+#define UUID_SUB_BITS (32)
+#define FRAME_INDEX_BITS (24)
+#define CRC_BITS (16)
+#define MESSAGE_TOTAL_BITS (96)
+#define MESSAGE_TOTAL_BYTES (12)
+
+#define MAX_PACKET (32)
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/src/SyncEncoder.c b/src/SyncEncoder.c
new file mode 100644
index 0000000..c553509
--- /dev/null
+++ b/src/SyncEncoder.c
@@ -0,0 +1,346 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file SyncEncoder.c
+ \version $Id$
+ \brief Implementation of Atmos Sync Frame Encoder
+*/
+
+#include "SyncEncoder.h"
+#include "CRC16.h"
+
+#include <memory.h>
+
+void ConstructFrame(LPSYNCENCODER pSyncEncoder,
+ INT iFrameIndex);
+
+FLOAT SEWriteBits( INT iSampleRate, /* In: Sample rate of signal */
+ FLOAT *pfAudioBuffer, /* Out: Audio buffer containing signal */
+ INT iBits, /* In: Number of bits to write */
+ BYTE *pbyData, /* In: Data to write */
+ FLOAT fSymbolPhase); /* In: Symbol phase */
+
+
+
+INT SyncEncoderInit(LPSYNCENCODER pSyncEncoder, /* Out: SYNCENCODER structure to be initialized */
+ INT iSampleRate, /* In: Signal sample rate */
+ INT iFrameRate, /* In: frame rate */
+ LPUUIDINFORMATION pUUID) /* In: UUID */
+{
+ pSyncEncoder->iError = SYNC_ENCODER_ERROR_NONE;
+
+ /* Check and set sample rate */
+ pSyncEncoder->iSymbolLength = 1;
+ switch(iSampleRate){
+ case 48000:
+ pSyncEncoder->iSampleRate = iSampleRate;
+ pSyncEncoder->iSymbolLength = SYMBOL_LENGTH_48;
+ break;
+ case 96000:
+ pSyncEncoder->iSampleRate = iSampleRate;
+ pSyncEncoder->iSymbolLength = SYMBOL_LENGTH_96;
+ break;
+ default:
+ pSyncEncoder->iError = SYNC_ENCODER_ERROR_INVALID_SR;
+ };
+
+ if(pSyncEncoder->iError != SYNC_ENCODER_ERROR_NONE){
+ return pSyncEncoder->iError;
+ }
+
+ /* check and set frame rate */
+ switch(iFrameRate){
+ case 24:
+ pSyncEncoder->iFrameRate = iFrameRate;
+ pSyncEncoder->iFrameRateCode = 0;
+ pSyncEncoder->iPacketsPerFrame = 4;
+ break;
+ case 25:
+ pSyncEncoder->iFrameRate = iFrameRate;
+ pSyncEncoder->iFrameRateCode = 1;
+ pSyncEncoder->iPacketsPerFrame = 4;
+ break;
+ case 30:
+ pSyncEncoder->iFrameRate = iFrameRate;
+ pSyncEncoder->iFrameRateCode = 2;
+ pSyncEncoder->iPacketsPerFrame = 4;
+ break;
+ case 48:
+ pSyncEncoder->iFrameRate = iFrameRate;
+ pSyncEncoder->iFrameRateCode = 3;
+ pSyncEncoder->iPacketsPerFrame = 2;
+ break;
+ case 50:
+ pSyncEncoder->iFrameRate = iFrameRate;
+ pSyncEncoder->iFrameRateCode = 4;
+ pSyncEncoder->iPacketsPerFrame = 2;
+ break;
+ case 60:
+ pSyncEncoder->iFrameRate = iFrameRate;
+ pSyncEncoder->iFrameRateCode = 5;
+ pSyncEncoder->iPacketsPerFrame = 2;
+ break;
+ case 96:
+ pSyncEncoder->iFrameRate = iFrameRate;
+ pSyncEncoder->iFrameRateCode = 6;
+ pSyncEncoder->iPacketsPerFrame = 1;
+ break;
+ case 100:
+ pSyncEncoder->iFrameRate = iFrameRate;
+ pSyncEncoder->iFrameRateCode = 7;
+ pSyncEncoder->iPacketsPerFrame = 1;
+ break;
+ case 120:
+ pSyncEncoder->iFrameRate = iFrameRate;
+ pSyncEncoder->iFrameRateCode = 8;
+ pSyncEncoder->iPacketsPerFrame = 1;
+ break;
+ default:
+ pSyncEncoder->iError = SYNC_ENCODER_ERROR_INVALID_FR;
+ };
+
+ if(pSyncEncoder->iError != SYNC_ENCODER_ERROR_NONE){
+ return pSyncEncoder->iError;
+ }
+
+ /* calculate required buffer length */
+ pSyncEncoder->iAudioBufferLength = pSyncEncoder->iSampleRate / pSyncEncoder->iFrameRate;
+
+ /* Calculate total packet bits including wash bits */
+ pSyncEncoder->iPacketBits = pSyncEncoder->iAudioBufferLength / (pSyncEncoder->iSymbolLength * pSyncEncoder->iPacketsPerFrame);
+
+ /* Initialize symbol phase */
+ pSyncEncoder->fSymbolPhase = 1.0f;
+
+ /* Initialize UUD information */
+ pSyncEncoder->iUUIDSubIndex = 0;
+ memcpy(&pSyncEncoder->UUID,pUUID,sizeof(UUIDINFORMATION));
+
+ return pSyncEncoder->iError;
+}
+
+INT GetSyncEncoderAudioBufferLength(LPSYNCENCODER pSyncEncoder) /* In: Sync encoder structure */
+{
+ if(pSyncEncoder->iError != SYNC_ENCODER_ERROR_NONE){
+ return pSyncEncoder->iError;
+ }
+
+ return pSyncEncoder->iAudioBufferLength;
+}
+
+
+
+INT EncodeSync( LPSYNCENCODER pSyncEncoder, /* In: Sync encoder structure */
+ INT iBufferLength, /* In: Length of audio buffer */
+ FLOAT *pfAudioBuffer, /* Out: Audio buffer with signal */
+ INT iFrameIndex) /* In: Frame Index */
+{
+ INT n;
+ INT iBufferIndex;
+
+
+ if(pSyncEncoder->iError != SYNC_ENCODER_ERROR_NONE){
+ return pSyncEncoder->iError;
+ }
+ if(iBufferLength != pSyncEncoder->iAudioBufferLength){
+ return SYNC_ENCODER_ERROR_INVALID_BL;
+ }
+
+ iBufferIndex = 0;
+ for(n = 0; n < pSyncEncoder->iPacketsPerFrame; n ++){
+ /* Construct message */
+ ConstructFrame(pSyncEncoder,iFrameIndex);
+
+ /* Write Message */
+ pSyncEncoder->fSymbolPhase = SEWriteBits(pSyncEncoder->iSampleRate,
+ &pfAudioBuffer[iBufferIndex],
+ pSyncEncoder->iPacketBits,
+ pSyncEncoder->abyPacket,
+ pSyncEncoder->fSymbolPhase);
+
+ iBufferIndex += (pSyncEncoder->iPacketBits * pSyncEncoder->iSymbolLength);
+
+ }
+
+ return pSyncEncoder->iError;
+}
+
+void ConstructFrame(LPSYNCENCODER pSyncEncoder,
+ INT iFrameIndex)
+{
+ USHORT ushCRC;
+ BYTE byByte;
+ INT iUUIDIndex;
+
+ /* Flush the packet buffer */
+ memset(pSyncEncoder->abyPacket,0,MAX_PACKET);
+
+ /* Sync Header */
+ pSyncEncoder->abyPacket[0] = SYNC_HEADER1;
+ pSyncEncoder->abyPacket[1] = SYNC_HEADER2;
+
+ /* Frame Rate code */
+ byByte = 0;
+ byByte = (unsigned char)(pSyncEncoder->iFrameRateCode << 4);
+
+ /* UUID sub index */
+ byByte |= (unsigned char)(pSyncEncoder->iUUIDSubIndex & 0x3);
+
+ pSyncEncoder->abyPacket[2] = byByte;
+
+ /* UUID Sub */
+ iUUIDIndex = pSyncEncoder->iUUIDSubIndex << 2;
+ pSyncEncoder->abyPacket[3] = pSyncEncoder->UUID.abyUUIDBytes[iUUIDIndex];
+ pSyncEncoder->abyPacket[4] = pSyncEncoder->UUID.abyUUIDBytes[iUUIDIndex + 1];
+ pSyncEncoder->abyPacket[5] = pSyncEncoder->UUID.abyUUIDBytes[iUUIDIndex + 2];
+ pSyncEncoder->abyPacket[6] = pSyncEncoder->UUID.abyUUIDBytes[iUUIDIndex + 3];
+
+ /* Update UUID sub index */
+ pSyncEncoder->iUUIDSubIndex ++;
+ pSyncEncoder->iUUIDSubIndex &= 0x3;
+
+ /* Frame Index */
+ byByte = (unsigned char)((iFrameIndex >> 16) & 0XFF);
+ pSyncEncoder->abyPacket[7] = byByte;
+ byByte = (unsigned char)((iFrameIndex >> 8) & 0XFF);
+ pSyncEncoder->abyPacket[8] = byByte;
+ byByte = (unsigned char)(iFrameIndex & 0XFF);
+ pSyncEncoder->abyPacket[9] = byByte;
+
+ /* calculate CRC */
+ ushCRC = CRC16(&pSyncEncoder->abyPacket[2],MESSAGE_TOTAL_BYTES - 4);
+
+ /* Insert CRC */
+ byByte = (unsigned char)((ushCRC >> 8) & 0XFF);
+ pSyncEncoder->abyPacket[10] = byByte;
+ byByte = (unsigned char)(ushCRC & 0XFF);
+ pSyncEncoder->abyPacket[11] = byByte;
+
+}
+
+static FLOAT g_afSymbol0_48[SYMBOL_LENGTH_48] = {
+ 0.3827f,
+ 0.9239f,
+ 0.9239f,
+ 0.3827f,
+};
+
+static FLOAT g_afSymbol1_48[SYMBOL_LENGTH_48] = {
+ 0.7071f,
+ 0.7071f,
+ -0.7071f,
+ -0.7071f,
+};
+
+static FLOAT g_afSymbol0_96[SYMBOL_LENGTH_96] = {
+ 0.1951f,
+ 0.5556f,
+ 0.8315f,
+ 0.9808f,
+ 0.9808f,
+ 0.8315f,
+ 0.5556f,
+ 0.1951f,
+};
+
+static FLOAT g_afSymbol1_96[SYMBOL_LENGTH_96] = {
+ 0.3827f,
+ 0.9239f,
+ 0.9239f,
+ 0.3827f,
+ -0.3827f,
+ -0.9239f,
+ -0.9239f,
+ -0.3827f,
+};
+
+/* Symbol gain */
+static FLOAT g_fGain = 0.1f;
+
+FLOAT SEWriteBits( INT iSampleRate, /* In: Sample rate of signal */
+ FLOAT *pfAudioBuffer, /* Out: Audio buffer containing signal */
+ INT iBits, /* In: Number of bits to write */
+ BYTE *pbyData, /* In: Data to write */
+ FLOAT fSymbolPhase) /* In: Symbol phase */
+{
+ INT n;
+ INT i;
+ INT iSymbolLength;
+ FLOAT *pfSymbol0;
+ FLOAT *pfSymbol1;
+ BYTE byByte;
+
+ /* Select the correct symbol length and symbol signal based on sample rate */
+ switch (iSampleRate){
+ case 96000:
+ iSymbolLength = SYMBOL_LENGTH_96;
+ pfSymbol0 = g_afSymbol0_96;
+ pfSymbol1 = g_afSymbol1_96;
+ break;
+ case 48000:
+ iSymbolLength = SYMBOL_LENGTH_48;
+ pfSymbol0 = g_afSymbol0_48;
+ pfSymbol1 = g_afSymbol1_48;
+ break;
+ default:
+ iSymbolLength = 0;
+ pfSymbol0 = g_afSymbol0_96;
+ pfSymbol1 = g_afSymbol1_96;
+ };
+
+ /* Write bits */
+ n = 0;
+ i = 0;
+ while(n < iBits){
+ INT k;
+ FLOAT *pfSymbol;
+
+ /* Grab next byte of data */
+ if(i == 0){
+ byByte = *pbyData;
+ pbyData ++;
+ }
+
+ pfSymbol = (byByte & 0x80) ? pfSymbol1 : pfSymbol0;
+
+ for(k = 0; k < iSymbolLength; k ++){
+ *pfAudioBuffer = *pfSymbol * fSymbolPhase * g_fGain;
+ pfAudioBuffer ++;
+ pfSymbol ++;
+ }
+
+ fSymbolPhase *= (byByte & 0x80) ? 1.0f : -1.0f;
+
+ byByte <<= 1;
+
+ n ++;
+
+ i ++;
+ i &= 0x7;
+ }
+
+ return fSymbolPhase;
+}
diff --git a/src/SyncEncoder.h b/src/SyncEncoder.h
new file mode 100644
index 0000000..4b97f5a
--- /dev/null
+++ b/src/SyncEncoder.h
@@ -0,0 +1,86 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file SyncEncoder.h
+ \version $Id$
+ \brief Declaration of Atmos Sync Frame Encoder
+*/
+
+#ifndef _SYNC_ENCODER_H_
+#define _SYNC_ENCODER_H_
+
+#include "SyncCommon.h"
+#include "UUIDInformation.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct SyncEncoder{
+ INT iSampleRate; /* Signal sample rate */
+ INT iSymbolLength; /* Symbol Length */
+ INT iFrameRate; /* Frame rate */
+ INT iFrameRateCode; /* Frame rate code */
+ INT iAudioBufferLength; /* Length of audio buffer */
+ INT iPacketBits; /* Bits in each packet includes wash bits */
+ INT iPacketsPerFrame; /* Number of packets per frame */
+ FLOAT fSymbolPhase; /* Symbol phase */
+
+ INT iUUIDSubIndex; /* UUID transmission sub index */
+ UUIDINFORMATION UUID; /* UUID */
+
+ BYTE abyPacket[MAX_PACKET];
+
+ INT iError; /* Error state */
+}SYNCENCODER,*LPSYNCENCODER;
+
+enum{
+ SYNC_ENCODER_ERROR_NONE = 0, /* No error */
+ SYNC_ENCODER_ERROR_INVALID_SR = -1, /* Invalid sample rate */
+ SYNC_ENCODER_ERROR_INVALID_FR = -2, /* Invalid frame rate */
+ SYNC_ENCODER_ERROR_INVALID_BL = -10, /* Buffer length is incorrect */
+ SYNC_ENCODER_ERROR_UNKNOWN = -100, /* Unknown */
+};
+
+
+INT SyncEncoderInit(LPSYNCENCODER pSyncEncoder, /* Out: SYNCENCODER structure to be initialized */
+ INT iSampleRate, /* In: Signal sample rate */
+ INT iFrameRate, /* In: frame rate */
+ LPUUIDINFORMATION pUUID); /* In: UUID */
+
+INT GetSyncEncoderAudioBufferLength(LPSYNCENCODER pSyncEncoder);
+
+INT EncodeSync( LPSYNCENCODER pSyncEncoder, /* In: Sync encoder structure */
+ INT iBufferLength, /* In: Length of audio buffer */
+ FLOAT *pfAudioBuffer, /* Out: Audio buffer with signal */
+ INT iFrameIndex); /* In: Frame Index */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
+
diff --git a/src/UUIDInformation.c b/src/UUIDInformation.c
new file mode 100644
index 0000000..4c5eec9
--- /dev/null
+++ b/src/UUIDInformation.c
@@ -0,0 +1,119 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file SyncEncoder.h
+ \version $Id$
+ \brief Implementation of Atmos Sync UUID
+*/
+
+#include "UUIDInformation.h"
+#include <stdlib.h>
+
+
+void UUIDSynthesize(LPUUIDINFORMATION pUUID)
+{
+ INT n;
+
+ for(n = 0; n < 16; n ++){
+ pUUID->abyUUIDBytes[n] = (BYTE)(rand() & 0xFF);
+ }
+
+ pUUID->abyUUIDBytes[6] &= 0x0F;
+ pUUID->abyUUIDBytes[6] |= 0x40;
+
+ pUUID->abyUUIDBytes[8] &= 0x0F;
+ pUUID->abyUUIDBytes[8] |= 0xA0;
+}
+
+void UUIDPrint( FILE *pFilePtr,
+ LPUUIDINFORMATION pUUID)
+{
+ if(pFilePtr != NULL){
+ INT n;
+
+ for(n = 0; n < 16; n ++){
+ fprintf(pFilePtr,"%02x",pUUID->abyUUIDBytes[n]);
+ }
+ }
+ else{
+ INT n;
+
+ for(n = 0; n < 16; n ++){
+ fprintf(stdout,"%02x",pUUID->abyUUIDBytes[n]);
+ }
+ }
+}
+
+void UUIDPrintFormated( FILE *pFilePtr,
+ LPUUIDINFORMATION pUUID)
+{
+ if(pFilePtr != NULL){
+ INT n;
+
+ for(n = 0; n < 4; n ++){
+ fprintf(pFilePtr,"%02x",pUUID->abyUUIDBytes[n]);
+ }
+ fprintf(pFilePtr,"-");
+ for(n = 4; n < 6; n ++){
+ fprintf(pFilePtr,"%02x",pUUID->abyUUIDBytes[n]);
+ }
+ fprintf(pFilePtr,"-");
+ for(n = 6; n < 8; n ++){
+ fprintf(pFilePtr,"%02x",pUUID->abyUUIDBytes[n]);
+ }
+ fprintf(pFilePtr,"-");
+ for(n = 8; n < 10; n ++){
+ fprintf(pFilePtr,"%02x",pUUID->abyUUIDBytes[n]);
+ }
+ fprintf(pFilePtr,"-");
+ for(n = 10; n < 16; n ++){
+ fprintf(pFilePtr,"%02x",pUUID->abyUUIDBytes[n]);
+ }
+ }
+ else{
+ INT n;
+
+ for(n = 0; n < 4; n ++){
+ fprintf(stdout,"%02x",pUUID->abyUUIDBytes[n]);
+ }
+ fprintf(stdout,"-");
+ for(n = 4; n < 6; n ++){
+ fprintf(stdout,"%02x",pUUID->abyUUIDBytes[n]);
+ }
+ fprintf(stdout,"-");
+ for(n = 6; n < 8; n ++){
+ fprintf(stdout,"%02x",pUUID->abyUUIDBytes[n]);
+ }
+ fprintf(stdout,"-");
+ for(n = 8; n < 10; n ++){
+ fprintf(stdout,"%02x",pUUID->abyUUIDBytes[n]);
+ }
+ fprintf(stdout,"-");
+ for(n = 10; n < 16; n ++){
+ fprintf(stdout,"%02x",pUUID->abyUUIDBytes[n]);
+ }
+ }
+}
diff --git a/src/UUIDInformation.h b/src/UUIDInformation.h
new file mode 100644
index 0000000..4bd0ff4
--- /dev/null
+++ b/src/UUIDInformation.h
@@ -0,0 +1,58 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file SyncEncoder.h
+ \version $Id$
+ \brief Declaration of Atmos Sync UUID
+*/
+
+#ifndef _UUID_INFORMATION_H_
+#define _UUID_INFORMATION_H_
+
+#include "SyncCommon.h"
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct UUIInformation{
+ BYTE abyUUIDBytes[16];
+} UUIDINFORMATION,*LPUUIDINFORMATION;
+
+void UUIDSynthesize(LPUUIDINFORMATION pUUID);
+
+void UUIDPrint( FILE *pFilePtr,
+ LPUUIDINFORMATION pUUID);
+
+void UUIDPrintFormated( FILE *pFilePtr,
+ LPUUIDINFORMATION pUUID);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/src/Wav.cpp b/src/Wav.cpp
index 7275ab9..0f14850 100755
--- a/src/Wav.cpp
+++ b/src/Wav.cpp
@@ -44,7 +44,7 @@ ASDCP::Wav::SimpleWaveHeader::SimpleWaveHeader(ASDCP::PCM::AudioDescriptor& ADes
nchannels = ADesc.ChannelCount;
bitspersample = ADesc.QuantizationBits;
samplespersec = (ui32_t)ceil(ADesc.AudioSamplingRate.Quotient());
- blockalign = nchannels * (bitspersample / 8);
+ blockalign = nchannels * ((bitspersample + 7) / 8);
avgbps = samplespersec * blockalign;
cbsize = 0;
data_len = ASDCP::PCM::CalcFrameBufferSize(ADesc) * ADesc.ContainerDuration;
@@ -363,7 +363,230 @@ ASDCP::AIFF::SimpleAIFFHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len,
return RESULT_OK;
}
+ASDCP::RF64::SimpleRF64Header::SimpleRF64Header(ASDCP::PCM::AudioDescriptor& ADesc)
+{
+ format = 1;
+ nchannels = ADesc.ChannelCount;
+ bitspersample = ADesc.QuantizationBits;
+ samplespersec = (ui32_t)ceil(ADesc.AudioSamplingRate.Quotient());
+ blockalign = nchannels * ((bitspersample + 7) / 8);
+ avgbps = samplespersec * blockalign;
+ data_len = ASDCP::PCM::CalcFrameBufferSize(ADesc) * ADesc.ContainerDuration;
+}
+
+//
+void
+ASDCP::RF64::SimpleRF64Header::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const
+{
+ ADesc.EditRate = PictureRate;
+
+ ADesc.LinkedTrackID = 0;
+ ADesc.Locked = 0;
+ ADesc.ChannelCount = nchannels;
+ ADesc.AudioSamplingRate = Rational(samplespersec, 1);
+ ADesc.AvgBps = avgbps;
+ ADesc.BlockAlign = blockalign;
+ ADesc.QuantizationBits = bitspersample;
+ ui32_t FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(ADesc);
+ ADesc.ContainerDuration = data_len / FrameBufferSize;
+ ADesc.ChannelFormat = PCM::CF_NONE;
+}
+
+//
+ASDCP::Result_t
+ASDCP::RF64::SimpleRF64Header::WriteToFile(Kumu::FileWriter& OutFile) const
+{
+ static ui32_t fmt_len =
+ sizeof(format)
+ + sizeof(nchannels)
+ + sizeof(samplespersec)
+ + sizeof(avgbps)
+ + sizeof(blockalign)
+ + sizeof(bitspersample);
+
+ ui32_t write_count = 0;
+ ui64_t RIFF_len = data_len + SimpleWavHeaderLength - 8;
+ DefaultLogSink().Debug("RIFF_len is %llu.\n", RIFF_len);
+ byte_t* tmp_header = NULL;
+ ui32_t header_len = 0;
+
+ if (RIFF_len > MAX_RIFF_LEN)
+ {
+ DefaultLogSink().Debug("Will write out an RF64 wave file.\n");
+ ui32_t data32_len = ((data_len < MAX_RIFF_LEN) ? data_len : MAX_RIFF_LEN);
+ ui64_t data64_len = ((data_len < MAX_RIFF_LEN) ? 0 : data_len);
+ static ui32_t ds64_len =
+ sizeof(RIFF_len)
+ + sizeof(data64_len)
+ + sizeof(SAMPLE_COUNT)
+ + sizeof(TABLE_LEN);
+
+ header_len = SIMPLE_RF64_HEADER_LEN;
+ tmp_header = new byte_t[header_len];
+ byte_t* p = tmp_header;
+ memcpy(p, &FCC_RF64, sizeof(fourcc)); p += 4;
+ *((ui32_t*)p) = KM_i32_LE(MAX_RIFF_LEN); p += 4;
+ memcpy(p, &Wav::FCC_WAVE, sizeof(fourcc)); p += 4;
+ memcpy(p, &FCC_ds64, sizeof(fourcc)); p += 4;
+ *((ui32_t*)p) = KM_i32_LE(ds64_len); p += 4;
+ *((ui64_t*)p) = KM_i64_LE(RIFF_len); p += 8;
+ *((ui64_t*)p) = KM_i64_LE(data64_len); p += 8;
+ *((ui64_t*)p) = KM_i64_LE(SAMPLE_COUNT); p += 8;
+ *((ui32_t*)p) = KM_i32_LE(TABLE_LEN); p += 4;
+ memcpy(p, &Wav::FCC_fmt_, sizeof(fourcc)); p += 4;
+ *((ui32_t*)p) = KM_i32_LE(fmt_len); p += 4;
+ *((ui16_t*)p) = KM_i16_LE(format); p += 2;
+ *((ui16_t*)p) = KM_i16_LE(nchannels); p += 2;
+ *((ui32_t*)p) = KM_i32_LE(samplespersec); p += 4;
+ *((ui32_t*)p) = KM_i32_LE(avgbps); p += 4;
+ *((ui16_t*)p) = KM_i16_LE(blockalign); p += 2;
+ *((ui16_t*)p) = KM_i16_LE(bitspersample); p += 2;
+ memcpy(p, &Wav::FCC_data, sizeof(fourcc)); p += 4;
+ *((ui32_t*)p) = KM_i32_LE(data32_len); p += 4;
+ write_count = (p - tmp_header);
+ }
+ else
+ {
+ DefaultLogSink().Debug("Will write out a regular wave file.\n");
+ header_len = SimpleWavHeaderLength;
+ tmp_header = new byte_t[header_len];
+ byte_t* p = tmp_header;
+ memcpy(p, &Wav::FCC_RIFF, sizeof(fourcc)); p += 4;
+ *((ui32_t*)p) = KM_i32_LE(RIFF_len); p += 4;
+ memcpy(p, &Wav::FCC_WAVE, sizeof(fourcc)); p += 4;
+ memcpy(p, &Wav::FCC_fmt_, sizeof(fourcc)); p += 4;
+ *((ui32_t*)p) = KM_i32_LE(fmt_len); p += 4;
+ *((ui16_t*)p) = KM_i16_LE(format); p += 2;
+ *((ui16_t*)p) = KM_i16_LE(nchannels); p += 2;
+ *((ui32_t*)p) = KM_i32_LE(samplespersec); p += 4;
+ *((ui32_t*)p) = KM_i32_LE(avgbps); p += 4;
+ *((ui16_t*)p) = KM_i16_LE(blockalign); p += 2;
+ *((ui16_t*)p) = KM_i16_LE(bitspersample); p += 2;
+ memcpy(p, &Wav::FCC_data, sizeof(fourcc)); p += 4;
+ *((ui32_t*)p) = KM_i32_LE(data_len); p += 4;
+ write_count = (p - tmp_header);
+ }
+ if (header_len != write_count)
+ {
+ DefaultLogSink().Warn("Expected to write %u bytes but wrote %u bytes for header.\n",
+ header_len, write_count);
+ }
+ write_count = 0;
+ ASDCP::Result_t r = OutFile.Write(tmp_header, header_len, &write_count);
+ delete [] tmp_header;
+ return r;
+}
+
+//
+ASDCP::Result_t
+ASDCP::RF64::SimpleRF64Header::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start)
+{
+ ui32_t read_count = 0;
+ ui32_t local_data_start = 0;
+ ASDCP::PCM::FrameBuffer TmpBuffer(Wav::MaxWavHeader);
+ if ( data_start == 0 )
+ data_start = &local_data_start;
+
+ Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start);
+ else
+ DefaultLogSink().Error("Failed to read %d bytes from file\n", Wav::MaxWavHeader);
+
+ return result;
+}
+
+ASDCP::Result_t
+ASDCP::RF64::SimpleRF64Header::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start)
+{
+ if ( buf_len < SIMPLE_RF64_HEADER_LEN )
+ return RESULT_SMALLBUF;
+
+ *data_start = 0;
+ const byte_t* p = buf;
+ const byte_t* end_p = p + buf_len;
+
+ fourcc test_RF64(p); p += 4;
+ if ( test_RF64 != FCC_RF64 )
+ {
+ DefaultLogSink().Debug("File does not begin with RF64 header\n");
+ return RESULT_RAW_FORMAT;
+ }
+
+ ui32_t tmp_len = KM_i32_LE(*(ui32_t*)p); p += 4;
+
+ fourcc test_WAVE(p); p += 4;
+ if ( test_WAVE != Wav::FCC_WAVE )
+ {
+ DefaultLogSink().Debug("File does not contain a WAVE header\n");
+ return RESULT_RAW_FORMAT;
+ }
+
+ fourcc test_ds64(p); p += 4;
+ if ( test_ds64 != FCC_ds64 )
+ {
+ DefaultLogSink().Debug("File does not contain a ds64 chunk\n");
+ return RESULT_RAW_FORMAT;
+ }
+ ui32_t ds64_len = KM_i32_LE(*(ui32_t*)p); p += 4;
+ ui64_t RIFF_len = ((tmp_len == MAX_RIFF_LEN) ? KM_i64_LE(*(ui64_t*)p) : tmp_len); p += 8;
+ data_len = KM_i64_LE(*(ui64_t*)p); p += 8;
+ p += (ds64_len - 16); // skip rest of ds64 chunk
+
+ fourcc test_fcc;
+
+ while ( p < end_p )
+ {
+ test_fcc = fourcc(p); p += 4;
+ ui32_t chunk_size = KM_i32_LE(*(ui32_t*)p); p += 4;
+
+ if ( test_fcc == Wav::FCC_data )
+ {
+ if ( chunk_size > RIFF_len )
+ {
+ DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len);
+ return RESULT_RAW_FORMAT;
+ }
+
+ if (chunk_size != MAX_RIFF_LEN)
+ data_len = chunk_size;
+ *data_start = p - buf;
+ break;
+ }
+
+ if ( test_fcc == Wav::FCC_fmt_ )
+ {
+ ui16_t format = KM_i16_LE(*(ui16_t*)p); p += 2;
+
+ if ( format != Wav::WAVE_FORMAT_PCM && format != Wav::WAVE_FORMAT_EXTENSIBLE )
+ {
+ DefaultLogSink().Error("Expecting uncompressed PCM data, got format type %hd\n", format);
+ return RESULT_RAW_FORMAT;
+ }
+
+ nchannels = KM_i16_LE(*(ui16_t*)p); p += 2;
+ samplespersec = KM_i32_LE(*(ui32_t*)p); p += 4;
+ avgbps = KM_i32_LE(*(ui32_t*)p); p += 4;
+ blockalign = KM_i16_LE(*(ui16_t*)p); p += 2;
+ bitspersample = KM_i16_LE(*(ui16_t*)p); p += 2;
+ p += chunk_size - 16; // 16 is the number of bytes read in this block
+ }
+ else
+ {
+ p += chunk_size;
+ }
+ }
+
+ if ( *data_start == 0 ) // can't have no data!
+ {
+ DefaultLogSink().Error("No data chunk found, file contains no essence\n");
+ return RESULT_RAW_FORMAT;
+ }
+
+ return RESULT_OK;
+}
//
// end Wav.cpp
diff --git a/src/Wav.h b/src/Wav.h
index ef9c4e2..d2a9789 100755
--- a/src/Wav.h
+++ b/src/Wav.h
@@ -118,6 +118,45 @@ namespace ASDCP
};
} // namespace Wav
+
+ namespace RF64
+ {
+ const fourcc FCC_RF64("RF64");
+ const fourcc FCC_ds64("ds64");
+
+
+ static const ui32_t MAX_RIFF_LEN = 0xFFFFFFFF;
+ static const ui32_t DS64_HEADER_LEN = 28;
+ static const ui32_t SIMPLE_RF64_HEADER_LEN = 80;
+ //
+ class SimpleRF64Header
+ {
+ public:
+ ui16_t format;
+ ui16_t nchannels;
+ ui32_t samplespersec;
+ ui32_t avgbps;
+ ui16_t blockalign;
+ ui16_t bitspersample;
+ ui64_t data_len;
+
+ SimpleRF64Header() :
+ format(0), nchannels(0), samplespersec(0), avgbps(0),
+ blockalign(0), bitspersample(0), data_len(0) {}
+
+ SimpleRF64Header(ASDCP::PCM::AudioDescriptor& ADesc);
+
+ Result_t ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start);
+ Result_t ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start);
+ Result_t WriteToFile(Kumu::FileWriter& OutFile) const;
+ void FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, Rational PictureRate) const;
+
+ private:
+ static const ui64_t SAMPLE_COUNT = 0;
+ static const ui32_t TABLE_LEN = 0;
+ };
+
+ } // namespace RF64
} // namespace ASDCP
#endif // _WAV_H_
diff --git a/src/WavFileWriter.h b/src/WavFileWriter.h
index 3febc23..9611adc 100755
--- a/src/WavFileWriter.h
+++ b/src/WavFileWriter.h
@@ -136,22 +136,36 @@ class WavFileWriter
assert(file_count && m_ChannelCount);
ui32_t element_size = ASDCP::PCM::CalcFrameBufferSize(m_ADesc) / file_count;
-
- for ( ui32_t i = 0; i < file_count && ASDCP_SUCCESS(result); i++ )
- {
- snprintf(filename, Kumu::MaxFilePath, "%s_%u.wav", file_root, (i + 1));
- m_OutFile.push_back(new WavFileElement(element_size));
- result = m_OutFile.back()->OpenWrite(filename);
-
- if ( ASDCP_SUCCESS(result) )
- {
- ASDCP::PCM::AudioDescriptor tmpDesc = m_ADesc;
- tmpDesc.ChannelCount = m_ChannelCount;
- ASDCP::Wav::SimpleWaveHeader Wav(tmpDesc);
- result = Wav.WriteToFile(*(m_OutFile.back()));
- }
- }
-
+ if (split == ST_NONE)
+ {
+ snprintf(filename, Kumu::MaxFilePath, "%s", file_root);
+ m_OutFile.push_back(new WavFileElement(element_size));
+ result = m_OutFile.back()->OpenWrite(filename);
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ASDCP::PCM::AudioDescriptor tmpDesc = m_ADesc;
+ tmpDesc.ChannelCount = m_ChannelCount;
+ ASDCP::RF64::SimpleRF64Header Wav(tmpDesc);
+ result = Wav.WriteToFile(*(m_OutFile.back()));
+ }
+ }
+ else
+ {
+ for ( ui32_t i = 0; i < file_count && ASDCP_SUCCESS(result); i++ )
+ {
+ snprintf(filename, Kumu::MaxFilePath, "%s_%u.wav", file_root, (i + 1));
+ m_OutFile.push_back(new WavFileElement(element_size));
+ result = m_OutFile.back()->OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ASDCP::PCM::AudioDescriptor tmpDesc = m_ADesc;
+ tmpDesc.ChannelCount = m_ChannelCount;
+ ASDCP::RF64::SimpleRF64Header Wav(tmpDesc);
+ result = Wav.WriteToFile(*(m_OutFile.back()));
+ }
+ }
+ }
return result;
}
diff --git a/src/asdcp-info.cpp b/src/asdcp-info.cpp
index 05e2c79..cbc4381 100755
--- a/src/asdcp-info.cpp
+++ b/src/asdcp-info.cpp
@@ -25,7 +25,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*! \file asdcp-info.cpp
- \version $Id$
+ \version $Id$
\brief AS-DCP file metadata utility
This program provides metadata information about an AS-DCP file.
@@ -125,7 +125,7 @@ public:
bool stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first)
bool showid_flag; // if true, show file identity info (the WriterInfo struct)
bool showdescriptor_flag; // if true, show the essence descriptor
- bool showcoding_flag; // if true, show the coding UL
+ bool showcoding_flag; // if true, show the coding UL
bool showrate_flag; // if true and is image file, show bit rate
bool max_bitrate_flag; // true if -t option given
double max_bitrate; // if true and is image file, max bit rate for rate test
@@ -145,7 +145,7 @@ public:
help_flag = true;
continue;
}
-
+
if ( argv[i][0] == '-'
&& ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
&& argv[i][2] == 0 )
@@ -191,7 +191,7 @@ public:
if ( help_flag || version_flag )
return;
-
+
if ( filenames.empty() )
{
fputs("At least one filename argument is required.\n", stderr);
@@ -270,6 +270,30 @@ class MyTextDescriptor : public TimedText::TimedTextDescriptor
}
};
+class MyDCDataDescriptor : public DCData::DCDataDescriptor
+{
+ public:
+ void FillDescriptor(DCData::MXFReader& Reader) {
+ Reader.FillDCDataDescriptor(*this);
+ }
+
+ void Dump(FILE* stream) {
+ DCData::DCDataDescriptorDump(*this, stream);
+ }
+};
+
+class MyAtmosDescriptor : public ATMOS::AtmosDescriptor
+{
+ public:
+ void FillDescriptor(ATMOS::MXFReader& Reader) {
+ Reader.FillAtmosDescriptor(*this);
+ }
+
+ void Dump(FILE* stream) {
+ ATMOS::AtmosDescriptorDump(*this, stream);
+ }
+};
+
//
//
template<class ReaderT, class DescriptorT>
@@ -333,7 +357,7 @@ public:
Result_t result = m_Reader.OPAtomHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_RGBAEssenceDescriptor),
reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
-
+
if ( KM_SUCCESS(result) )
m_PictureEssenceCoding = descriptor->PictureEssenceCoding;
}
@@ -489,7 +513,7 @@ public:
Result_t result = m_Reader.OPAtomHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_WaveAudioDescriptor),
reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
-
+
if ( KM_SUCCESS(result) )
{
char buf[64];
@@ -572,7 +596,7 @@ show_file_info(CommandOptions& Options)
{
FileInfoWrapper<ASDCP::JP2K::MXFSReader, MyStereoPictureDescriptor>wrapper;
result = wrapper.file_info(Options, "JPEG 2000 stereoscopic pictures");
-
+
if ( KM_SUCCESS(result) )
{
wrapper.get_PictureEssenceCoding();
@@ -592,6 +616,16 @@ show_file_info(CommandOptions& Options)
FileInfoWrapper<ASDCP::TimedText::MXFReader, MyTextDescriptor>wrapper;
result = wrapper.file_info(Options, "Timed Text");
}
+ else if ( EssenceType == ESS_DCDATA_UNKNOWN )
+ {
+ FileInfoWrapper<ASDCP::DCData::MXFReader, MyDCDataDescriptor> wrapper;
+ result = wrapper.file_info(Options, "D-Cinema Generic Data");
+ }
+ else if ( EssenceType == ESS_DCDATA_DOLBY_ATMOS )
+ {
+ FileInfoWrapper<ASDCP::ATMOS::MXFReader, MyAtmosDescriptor> wrapper;
+ result = wrapper.file_info(Options, "Dolby ATMOS");
+ }
else
{
fprintf(stderr, "File is not AS-DCP: %s\n", Options.filenames.front().c_str());
diff --git a/src/asdcp-unwrap.cpp b/src/asdcp-unwrap.cpp
index e9b9fee..7b8654b 100755
--- a/src/asdcp-unwrap.cpp
+++ b/src/asdcp-unwrap.cpp
@@ -25,7 +25,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*! \file asdcp-unwrap.cpp
- \version $Id$
+ \version $Id$
\brief AS-DCP file manipulation utility
This program extracts picture, sound and text essence from AS-DCP files.
@@ -92,7 +92,8 @@ Options:\n\
-b <buffer-size> - Specify size in bytes of picture frame buffer\n\
Defaults to 4,194,304 (4MB)\n\
-d <duration> - Number of frames to process, default all\n\
- -f <start-frame> - Starting frame number, default 0\n\
+ -e <extension> - Extension to use for Unknown D-Cinema Data files. default dcdata\n\
+ -f <start-frame> - Starting frame number, default 0\n \
-G - Perform GOP start lookup test on MXF+Interop MPEG file\n\
-h | -help - Show help\n\
-k <key-string> - Use key for ciphertext operations\n\
@@ -153,6 +154,7 @@ public:
PCM::ChannelFormat_t channel_fmt; // audio channel arrangement
const char* input_filename;
std::string prefix_buffer;
+ const char* extension; // file extension to use for unknown D-Cinema Data track files.
//
Rational PictureRate()
@@ -181,7 +183,7 @@ public:
version_flag(false), help_flag(false), stereo_image_flag(false), number_width(6),
start_frame(0), duration(0xffffffff), duration_flag(false), j2c_pedantic(true),
picture_rate(24), fb_size(FRAME_BUFFER_SIZE), file_prefix(0),
- channel_fmt(PCM::CF_NONE), input_filename(0)
+ channel_fmt(PCM::CF_NONE), input_filename(0), extension("dcdata")
{
memset(key_value, 0, KeyLen);
memset(key_id_value, 0, UUIDlen);
@@ -194,7 +196,7 @@ public:
help_flag = true;
continue;
}
-
+
if ( argv[i][0] == '-'
&& ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
&& argv[i][2] == 0 )
@@ -216,6 +218,11 @@ public:
duration = abs(atoi(argv[i]));
break;
+ case 'e':
+ TEST_EXTRA_ARG(i, 'e');
+ extension = argv[i];
+ break;
+
case 'f':
TEST_EXTRA_ARG(i, 'f');
start_frame = abs(atoi(argv[i]));
@@ -224,6 +231,20 @@ public:
case 'G': mode = MMT_GOP_START; break;
case 'h': help_flag = true; break;
+ case 'k': key_flag = true;
+ TEST_EXTRA_ARG(i, 'k');
+ {
+ ui32_t length;
+ Kumu::hex2bin(argv[i], key_value, KeyLen, &length);
+
+ if ( length != KeyLen )
+ {
+ fprintf(stderr, "Unexpected key length: %u, expecting %u characters.\n", length, KeyLen);
+ return;
+ }
+ }
+ break;
+
case 'm': read_hmac = true; break;
case 'p':
@@ -276,7 +297,7 @@ public:
if ( help_flag || version_flag )
return;
-
+
if ( ( mode == MMT_EXTRACT || mode == MMT_GOP_START ) && input_filename == 0 )
{
fputs("Option requires at least one filename argument.\n", stderr);
@@ -369,11 +390,11 @@ read_MPEG2_file(CommandOptions& Options)
if ( ! Options.no_write_flag )
{
- ui32_t write_count = 0;
- result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
- }
+ ui32_t write_count = 0;
+ result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
}
}
+ }
return result;
}
@@ -499,13 +520,13 @@ read_JP2K_S_file(CommandOptions& Options)
{
if ( ! Options.no_write_flag )
{
- Kumu::FileWriter OutFile;
- ui32_t write_count;
- snprintf(filename, filename_max, left_format, Options.file_prefix, i);
- result = OutFile.OpenWrite(filename);
+ Kumu::FileWriter OutFile;
+ ui32_t write_count;
+ snprintf(filename, filename_max, left_format, Options.file_prefix, i);
+ result = OutFile.OpenWrite(filename);
- if ( ASDCP_SUCCESS(result) )
- result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+ if ( ASDCP_SUCCESS(result) )
+ result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
}
if ( Options.verbose_flag )
@@ -519,18 +540,18 @@ read_JP2K_S_file(CommandOptions& Options)
{
if ( ! Options.no_write_flag )
{
- Kumu::FileWriter OutFile;
- ui32_t write_count;
- snprintf(filename, filename_max, right_format, Options.file_prefix, i);
- result = OutFile.OpenWrite(filename);
+ Kumu::FileWriter OutFile;
+ ui32_t write_count;
+ snprintf(filename, filename_max, right_format, Options.file_prefix, i);
+ result = OutFile.OpenWrite(filename);
- if ( ASDCP_SUCCESS(result) )
- result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
- }
+ if ( ASDCP_SUCCESS(result) )
+ result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+ }
if ( Options.verbose_flag )
FrameBuffer.Dump(stderr, Options.fb_dump_size);
- }
+ }
}
return result;
@@ -602,14 +623,14 @@ read_JP2K_file(CommandOptions& Options)
{
if ( ! Options.no_write_flag )
{
- Kumu::FileWriter OutFile;
- char filename[256];
- ui32_t write_count;
- snprintf(filename, 256, name_format, Options.file_prefix, i);
- result = OutFile.OpenWrite(filename);
-
- if ( ASDCP_SUCCESS(result) )
- result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+ Kumu::FileWriter OutFile;
+ char filename[256];
+ ui32_t write_count;
+ snprintf(filename, 256, name_format, Options.file_prefix, i);
+ result = OutFile.OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
}
if ( Options.verbose_flag )
@@ -659,14 +680,14 @@ read_PCM_file(CommandOptions& Options)
}
else
{
- FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
+ FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
}
if ( Options.verbose_flag )
{
fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
- PCM::AudioDescriptorDump(ADesc);
- }
+ PCM::AudioDescriptorDump(ADesc);
+ }
}
if ( ASDCP_SUCCESS(result) )
@@ -691,10 +712,10 @@ read_PCM_file(CommandOptions& Options)
if ( ! Options.no_write_flag )
{
- OutWave.OpenWrite(ADesc, Options.file_prefix,
- ( Options.split_wav ? WavFileWriter::ST_STEREO :
- ( Options.mono_wav ? WavFileWriter::ST_MONO : WavFileWriter::ST_NONE ) ));
- }
+ OutWave.OpenWrite(ADesc, Options.file_prefix,
+ ( Options.split_wav ? WavFileWriter::ST_STEREO :
+ ( Options.mono_wav ? WavFileWriter::ST_MONO : WavFileWriter::ST_NONE ) ));
+ }
}
if ( ASDCP_SUCCESS(result) && Options.key_flag )
@@ -730,10 +751,10 @@ read_PCM_file(CommandOptions& Options)
if ( ! Options.no_write_flag )
{
- result = OutWave.WriteFrame(FrameBuffer);
- }
+ result = OutWave.WriteFrame(FrameBuffer);
}
}
+ }
return result;
}
@@ -820,6 +841,90 @@ read_timed_text_file(CommandOptions& Options)
if ( ASDCP_SUCCESS(result) )
result = Writer.Write(FrameBuffer.RoData(), FrameBuffer.Size(), &write_count);
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+ }
+ }
+
+ return result;
+}
+
+// Read one or more plaintext DCData bytestreams from a plaintext ASDCP file
+// Read one or more plaintext DCData bytestreams from a ciphertext ASDCP file
+// Read one or more ciphertext DCData byestreams from a ciphertext ASDCP file
+//
+Result_t
+read_DCData_file(CommandOptions& Options)
+{
+ AESDecContext* Context = 0;
+ HMACContext* HMAC = 0;
+ DCData::MXFReader Reader;
+ DCData::FrameBuffer FrameBuffer(Options.fb_size);
+ ui32_t frame_count = 0;
+
+ Result_t result = Reader.OpenRead(Options.input_filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ DCData::DCDataDescriptor DDesc;
+ Reader.FillDCDataDescriptor(DDesc);
+
+ frame_count = DDesc.ContainerDuration;
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ DCData::DCDataDescriptorDump(DDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ {
+ Context = new AESDecContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) && Options.read_hmac )
+ {
+ WriterInfo Info;
+ Reader.FillWriterInfo(Info);
+
+ if ( Info.UsesHMAC )
+ {
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ else
+ {
+ fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
+ }
+ }
+ }
+
+ ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
+ if ( last_frame > frame_count )
+ last_frame = frame_count;
+
+ char name_format[64];
+ snprintf(name_format, 64, "%%s%%0%du.%s", Options.number_width, Options.extension);
+
+ for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
+ {
+ result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( ! Options.no_write_flag )
+ {
+ Kumu::FileWriter OutFile;
+ char filename[256];
+ ui32_t write_count;
+ snprintf(filename, 256, name_format, Options.file_prefix, i);
+ result = OutFile.OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+ }
+
if ( Options.verbose_flag )
FrameBuffer.Dump(stderr, Options.fb_dump_size);
}
@@ -888,6 +993,15 @@ main(int argc, const char** argv)
result = read_timed_text_file(Options);
break;
+ case ESS_DCDATA_UNKNOWN:
+ result = read_DCData_file(Options);
+ break;
+
+ case ESS_DCDATA_DOLBY_ATMOS:
+ Options.extension = "atmos";
+ result = read_DCData_file(Options);
+ break;
+
default:
fprintf(stderr, "%s: Unknown file type, not ASDCP essence.\n", Options.input_filename);
return 5;
diff --git a/src/asdcp-wrap.cpp b/src/asdcp-wrap.cpp
index bbff82a..12435ce 100755
--- a/src/asdcp-wrap.cpp
+++ b/src/asdcp-wrap.cpp
@@ -25,7 +25,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*! \file asdcp-wrap.cpp
- \version $Id$
+ \version $Id$
\brief AS-DCP file manipulation utility
This program wraps d-cinema essence (picture, sound or text) into an AS-DCP
@@ -48,6 +48,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <KM_fileio.h>
#include <KM_prng.h>
+#include <AtmosSyncChannel_Mixer.h>
#include <AS_DCP.h>
#include <PCMParserList.h>
#include <Metadata.h>
@@ -76,7 +77,7 @@ public:
static byte_t default_ProductUUID_Data[UUIDlen] =
{ 0x7d, 0x83, 0x6e, 0x16, 0x37, 0xc7, 0x4c, 0x22,
0xb2, 0xe0, 0x46, 0xa7, 0x17, 0xe8, 0x4f, 0x42 };
-
+
memcpy(ProductUUID, default_ProductUUID_Data, UUIDlen);
CompanyName = "WidgetCo";
ProductName = "asdcp-wrap";
@@ -117,7 +118,7 @@ USAGE: %s [-h|-help] [-V]\n\
\n\
%s [-3] [-a <uuid>] [-b <buffer-size>] [-C <UL>] [-d <duration>]\n\
[-e|-E] [-f <start-frame>] [-j <key-id-string>] [-k <key-string>]\n\
- [-l <label>] [-L] [-M] [-p <frame-rate>] [-s <num>] [-v] [-W]\n\
+ [-l <label>] [-L] [-M] [-p <frame-rate>] [-s] [-v] [-W]\n\
[-z|-Z] <input-file>+ <output-file>\n\n",
PROGRAM_NAME, PROGRAM_NAME);
@@ -147,6 +148,10 @@ Options:\n\
-P <UL> - Set PictureEssenceCoding UL value in a JP2K file\n\
-p <rate> - fps of picture when wrapping PCM or JP2K:\n\
Use one of [23|24|25|30|48|50|60], 24 is default\n\
+ -s - Insert a Dolby Atmos synchronization channel when\n\
+ wrapping PCM. This implies a -L option(SMPTE ULs) and \n\
+ will overide -C and -l options with Configuration 4 \n\
+ Channel Assigment and no format label respectively. \n\
-v - Verbose, prints informative messages to stderr\n\
-W - Read input file only, do not write source file\n\
-z - Fail if j2c inputs have unequal parameters (default)\n\
@@ -168,7 +173,7 @@ decode_channel_fmt(const std::string& label_name)
else if ( label_name == "6.1" )
return PCM::CF_CFG_2;
-
+
else if ( label_name == "7.1" )
return PCM::CF_CFG_3;
@@ -217,6 +222,11 @@ public:
Kumu::PathList_t filenames; // list of filenames to be processed
UL channel_assignment;
UL picture_coding;
+ bool dolby_atmos_sync_flag; // if true, insert a Dolby Atmos Synchronization channel.
+ ui32_t ffoa; /// first frame of action for atmos wrapping
+ ui32_t max_channel_count; /// max channel count for atmos wrapping
+ ui32_t max_object_count; /// max object count for atmos wrapping
+
//
Rational PictureRate()
@@ -268,6 +278,8 @@ public:
duration(0xffffffff), use_smpte_labels(false), j2c_pedantic(true),
fb_size(FRAME_BUFFER_SIZE),
channel_fmt(PCM::CF_NONE),
+ ffoa(0), max_channel_count(10), max_object_count(118), // hard-coded sample atmos properties
+ dolby_atmos_sync_flag(false),
show_ul_values(false)
{
memset(key_value, 0, KeyLen);
@@ -281,7 +293,7 @@ public:
help_flag = true;
continue;
}
-
+
if ( argv[i][0] == '-'
&& ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
&& argv[i][2] == 0 )
@@ -387,7 +399,7 @@ public:
TEST_EXTRA_ARG(i, 'p');
picture_rate = abs(atoi(argv[i]));
break;
-
+ case 's': dolby_atmos_sync_flag = true; break;
case 'V': version_flag = true; break;
case 'v': verbose_flag = true; break;
case 'W': no_write_flag = true; break;
@@ -416,7 +428,7 @@ public:
if ( help_flag || version_flag )
return;
-
+
if ( filenames.size() < 2 )
{
fputs("Option requires at least two filename arguments: <input-file> <output-file>\n", stderr);
@@ -515,19 +527,16 @@ write_MPEG2_file(CommandOptions& Options)
while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
{
- if ( duration == 1 )
- {
result = Parser.ReadFrame(FrameBuffer);
if ( ASDCP_SUCCESS(result) )
{
if ( Options.verbose_flag )
FrameBuffer.Dump(stderr, Options.fb_dump_size);
-
+
if ( Options.encrypt_header_flag )
FrameBuffer.PlaintextOffset(0);
}
- }
if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
{
@@ -578,7 +587,7 @@ check_phfr_params(CommandOptions& Options, JP2K::PictureDescriptor& PDesc)
// do not set the label if the user has already done so
if ( ! Options.picture_coding.HasValue() )
Options.picture_coding = UL(P_HFR_UL_2K);
-
+
return true;
}
@@ -673,7 +682,7 @@ write_JP2K_S_file(CommandOptions& Options)
if ( ASDCP_SUCCESS(result) )
result = Writer.OpenWrite(Options.out_file.c_str(), Info, PDesc);
-
+
if ( ASDCP_SUCCESS(result) && Options.picture_coding.HasValue() )
{
MXF::RGBAEssenceDescriptor *descriptor = 0;
@@ -697,7 +706,7 @@ write_JP2K_S_file(CommandOptions& Options)
{
if ( Options.verbose_flag )
FrameBuffer.Dump(stderr, Options.fb_dump_size);
-
+
if ( Options.encrypt_header_flag )
FrameBuffer.PlaintextOffset(0);
}
@@ -712,7 +721,7 @@ write_JP2K_S_file(CommandOptions& Options)
{
if ( Options.verbose_flag )
FrameBuffer.Dump(stderr, Options.fb_dump_size);
-
+
if ( Options.encrypt_header_flag )
FrameBuffer.PlaintextOffset(0);
}
@@ -825,19 +834,16 @@ write_JP2K_file(CommandOptions& Options)
while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
{
- if ( duration == 1 )
- {
result = Parser.ReadFrame(FrameBuffer);
if ( ASDCP_SUCCESS(result) )
{
if ( Options.verbose_flag )
FrameBuffer.Dump(stderr, Options.fb_dump_size);
-
+
if ( Options.encrypt_header_flag )
FrameBuffer.PlaintextOffset(0);
}
- }
if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
{
@@ -1007,6 +1013,131 @@ write_PCM_file(CommandOptions& Options)
return result;
}
+// Mix one or more plaintext PCM audio streams with a Dolby Atmos Synchronization channel and write them to a plaintext ASDCP file
+// Mix one or more plaintext PCM audio streams with a Dolby Atmos Synchronization channel and write them to a ciphertext ASDCP file
+//
+Result_t
+write_PCM_with_ATMOS_sync_file(CommandOptions& Options)
+{
+ AESEncContext* Context = 0;
+ HMACContext* HMAC = 0;
+ PCM::MXFWriter Writer;
+ PCM::FrameBuffer FrameBuffer;
+ PCM::AudioDescriptor ADesc;
+ Rational PictureRate = Options.PictureRate();
+ byte_t IV_buf[CBC_BLOCK_SIZE];
+ Kumu::FortunaRNG RNG;
+
+ WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
+ if ( Options.asset_id_flag )
+ memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
+ else
+ Kumu::GenRandomUUID(Info.AssetUUID);
+ AtmosSyncChannelMixer Mixer(Info.AssetUUID);
+
+ // set up essence parser
+ Result_t result = Mixer.OpenRead(Options.filenames, PictureRate);
+
+ // set up MXF writer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Mixer.FillAudioDescriptor(ADesc);
+
+ ADesc.EditRate = PictureRate;
+ FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
+ ADesc.ChannelFormat = PCM::CF_CFG_4;
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "%.1fkHz PCM Audio, %s fps (%u spf)\n",
+ ADesc.AudioSamplingRate.Quotient() / 1000.0,
+ Options.szPictureRate(),
+ PCM::CalcSamplesPerFrame(ADesc));
+ fputs("AudioDescriptor:\n", stderr);
+ PCM::AudioDescriptorDump(ADesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ Info.LabelSetType = LS_MXF_SMPTE;
+ fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
+
+ // configure encryption
+ if( Options.key_flag )
+ {
+ Kumu::GenRandomUUID(Info.ContextID);
+ Info.EncryptedEssence = true;
+
+ if ( Options.key_id_flag )
+ memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
+ else
+ RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
+
+ Context = new AESEncContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+
+ if ( ASDCP_SUCCESS(result) && Options.write_hmac )
+ {
+ Info.UsesHMAC = true;
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.OpenWrite(Options.out_file.c_str(), Info, ADesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = Mixer.Reset();
+ ui32_t duration = 0;
+
+ while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
+ {
+ result = Mixer.ReadFrame(FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( FrameBuffer.Size() != FrameBuffer.Capacity() )
+ {
+ fprintf(stderr, "WARNING: Last frame read was short, PCM input is possibly not frame aligned.\n");
+ fprintf(stderr, "Expecting %u bytes, got %u.\n", FrameBuffer.Capacity(), FrameBuffer.Size());
+ result = RESULT_ENDOFFILE;
+ continue;
+ }
+
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( ! Options.no_write_flag )
+ {
+ result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
+
+ // The Writer class will forward the last block of ciphertext
+ // to the encryption context for use as the IV for the next
+ // frame. If you want to use non-sequitur IV values, un-comment
+ // the following line of code.
+ // if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+ }
+ }
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.Finalize();
+
+ return result;
+}
+
//------------------------------------------------------------------------------------------
// TimedText essence
@@ -1109,7 +1240,7 @@ write_timed_text_file(CommandOptions& Options)
if ( ! Options.no_write_flag )
{
result = Writer.WriteAncillaryResource(FrameBuffer, Context, HMAC);
-
+
// The Writer class will forward the last block of ciphertext
// to the encryption context for use as the IV for the next
// frame. If you want to use non-sequitur IV values, un-comment
@@ -1129,6 +1260,124 @@ write_timed_text_file(CommandOptions& Options)
return result;
}
+// Write one or more plaintext Dolby ATMOS bytestreams to a plaintext ASDCP file
+// Write one or more plaintext Dolby ATMOS bytestreams to a ciphertext ASDCP file
+//
+Result_t
+write_dolby_atmos_file(CommandOptions& Options)
+{
+ AESEncContext* Context = 0;
+ HMACContext* HMAC = 0;
+ ATMOS::MXFWriter Writer;
+ DCData::FrameBuffer FrameBuffer(Options.fb_size);
+ ATMOS::AtmosDescriptor ADesc;
+ DCData::SequenceParser Parser;
+ byte_t IV_buf[CBC_BLOCK_SIZE];
+ Kumu::FortunaRNG RNG;
+
+ // set up essence parser
+ Result_t result = Parser.OpenRead(Options.filenames.front().c_str());
+
+ // set up MXF writer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Parser.FillDCDataDescriptor(ADesc);
+ ADesc.EditRate = Options.PictureRate();
+ // TODO: fill AtmosDescriptor
+ ADesc.FirstFrame = Options.ffoa;
+ ADesc.MaxChannelCount = Options.max_channel_count;
+ ADesc.MaxObjectCount = Options.max_object_count;
+ Kumu::GenRandomUUID(ADesc.AtmosID);
+ ADesc.AtmosVersion = 1;
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "Dolby ATMOS Data\n");
+ fputs("AtmosDescriptor:\n", stderr);
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ ATMOS::AtmosDescriptorDump(ADesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
+ if ( Options.asset_id_flag )
+ memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
+ else
+ Kumu::GenRandomUUID(Info.AssetUUID);
+
+ Info.LabelSetType = LS_MXF_SMPTE;
+
+ // configure encryption
+ if( Options.key_flag )
+ {
+ Kumu::GenRandomUUID(Info.ContextID);
+ Info.EncryptedEssence = true;
+
+ if ( Options.key_id_flag )
+ memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
+ else
+ RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
+
+ Context = new AESEncContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+
+ if ( ASDCP_SUCCESS(result) && Options.write_hmac )
+ {
+ Info.UsesHMAC = true;
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.OpenWrite(Options.out_file.c_str(), Info, ADesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t duration = 0;
+ result = Parser.Reset();
+
+ while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
+ {
+ result = Parser.ReadFrame(FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( Options.encrypt_header_flag )
+ FrameBuffer.PlaintextOffset(0);
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
+
+ // The Writer class will forward the last block of ciphertext
+ // to the encryption context for use as the IV for the next
+ // frame. If you want to use non-sequitur IV values, un-comment
+ // the following line of code.
+ // if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+ }
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.Finalize();
+
+ return result;
+}
+
//
int
main(int argc, const char** argv)
@@ -1184,13 +1433,24 @@ main(int argc, const char** argv)
case ESS_PCM_24b_48k:
case ESS_PCM_24b_96k:
- result = write_PCM_file(Options);
+ if ( Options.dolby_atmos_sync_flag )
+ {
+ result = write_PCM_with_ATMOS_sync_file(Options);
+ }
+ else
+ {
+ result = write_PCM_file(Options);
+ }
break;
case ESS_TIMED_TEXT:
result = write_timed_text_file(Options);
break;
+ case ESS_DCDATA_DOLBY_ATMOS:
+ result = write_dolby_atmos_file(Options);
+ break;
+
default:
fprintf(stderr, "%s: Unknown file type, not ASDCP-compatible essence.\n",
Options.filenames.front().c_str());
diff --git a/src/blackwave.cpp b/src/blackwave.cpp
index 35e5e77..36d3235 100644
--- a/src/blackwave.cpp
+++ b/src/blackwave.cpp
@@ -187,8 +187,8 @@ make_black_wav_file(CommandOptions& Options)
if ( ASDCP_SUCCESS(result) )
{
- Wav::SimpleWaveHeader WavHeader(ADesc);
- result = WavHeader.WriteToFile(OutFile);
+ RF64::SimpleRF64Header WavHeader(ADesc);
+ result = WavHeader.WriteToFile(OutFile);
}
if ( ASDCP_SUCCESS(result) )
diff --git a/src/h__Reader.cpp b/src/h__Reader.cpp
index da2aca2..77d732f 100755
--- a/src/h__Reader.cpp
+++ b/src/h__Reader.cpp
@@ -75,19 +75,26 @@ ASDCP::h__ASDCPReader::OpenMXFRead(const char* filename)
if ( KM_SUCCESS(result) )
{
- // if this is a three partition file, go to the body
- // partition and read the partition pack
- if ( m_HeaderPart.m_RIP.PairArray.size() > 2 )
- {
- Array<RIP::Pair>::iterator r_i = m_HeaderPart.m_RIP.PairArray.begin();
- r_i++;
- m_File.Seek((*r_i).ByteOffset);
- result = m_BodyPart.InitFromFile(m_File);
- }
+ // if this is a three partition file, go to the body
+ // partition and read the partition pack
+ if ( m_HeaderPart.m_RIP.PairArray.size() > 2 )
+ {
+ Array<RIP::Pair>::iterator r_i = m_HeaderPart.m_RIP.PairArray.begin();
+ r_i++;
+ m_File.Seek((*r_i).ByteOffset);
+ result = m_BodyPart.InitFromFile(m_File);
+ if( !ASDCP_SUCCESS(result) )
+ {
+ DefaultLogSink().Error("ASDCP::h__Reader::OpenMXFRead, m_BodyPart.InitFromFile failed\n");
+ }
+ }
}
+ else
+ DefaultLogSink().Error("ASDCP::h__Reader::OpenMXFRead, TrackFileReader::OpenMXFRead failed\n");
+
if ( KM_SUCCESS(result) )
- m_HeaderPart.BodyOffset = m_File.Tell();
+ m_HeaderPart.BodyOffset = m_File.Tell();
return result;
}
@@ -148,6 +155,14 @@ ASDCP::h__ASDCPReader::ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameB
EssenceUL, Ctx, HMAC);
}
+Result_t
+ASDCP::h__ASDCPReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset,
+ i8_t& temporalOffset, i8_t& keyFrameOffset)
+{
+ return ASDCP::MXF::TrackFileReader<OPAtomHeader, OPAtomIndexFooter>::LocateFrame(m_HeaderPart, FrameNum,
+ streamOffset, temporalOffset, keyFrameOffset);
+}
+
//------------------------------------------------------------------------------------------
//