summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjhurst <jhurst@cinecert.com>2005-12-20 01:55:40 +0000
committerjhurst <>2005-12-20 01:55:40 +0000
commit8095eaa320551b6795d0368c0ad0c227a3167caa (patch)
treee522d5137671fffbc8fcc084831b5d8806ef44f2 /src
wheee!
Diffstat (limited to 'src')
-rwxr-xr-xsrc/AS_DCP.cpp509
-rwxr-xr-xsrc/AS_DCP.h1088
-rwxr-xr-xsrc/AS_DCP_AES.cpp462
-rwxr-xr-xsrc/AS_DCP_JP2K.cpp594
-rwxr-xr-xsrc/AS_DCP_MPEG2.cpp529
-rwxr-xr-xsrc/AS_DCP_MXF.cpp598
-rwxr-xr-xsrc/AS_DCP_PCM.cpp475
-rwxr-xr-xsrc/AS_DCP_internal.h299
-rwxr-xr-xsrc/Index.cpp203
-rwxr-xr-xsrc/JP2K.cpp222
-rwxr-xr-xsrc/JP2K.h163
-rwxr-xr-xsrc/JP2K_Codestream_Parser.cpp193
-rwxr-xr-xsrc/JP2K_Sequence_Parser.cpp244
-rwxr-xr-xsrc/KLV.cpp270
-rwxr-xr-xsrc/KLV.h151
-rwxr-xr-xsrc/MDD.h1249
-rwxr-xr-xsrc/MPEG.cpp267
-rwxr-xr-xsrc/MPEG.h237
-rwxr-xr-xsrc/MPEG2_Parser.cpp581
-rwxr-xr-xsrc/MXF.cpp1020
-rwxr-xr-xsrc/MXF.h307
-rwxr-xr-xsrc/MXFTypes.cpp284
-rwxr-xr-xsrc/MXFTypes.h285
-rwxr-xr-xsrc/Metadata.cpp781
-rwxr-xr-xsrc/Metadata.h389
-rwxr-xr-xsrc/PCMParserList.cpp213
-rwxr-xr-xsrc/PCMParserList.h86
-rwxr-xr-xsrc/PCM_Parser.cpp214
-rwxr-xr-xsrc/Wav.cpp207
-rwxr-xr-xsrc/Wav.h95
-rwxr-xr-xsrc/WavFileWriter.h120
-rwxr-xr-xsrc/asdcp-mem-test.cpp152
-rwxr-xr-xsrc/asdcp-test.cpp1366
-rwxr-xr-xsrc/asdcp-version.cpp46
-rwxr-xr-xsrc/h__Reader.cpp346
-rwxr-xr-xsrc/h__Writer.cpp458
-rwxr-xr-xsrc/j2c-test.cpp74
-rwxr-xr-xsrc/klvwalk.cpp161
38 files changed, 14938 insertions, 0 deletions
diff --git a/src/AS_DCP.cpp b/src/AS_DCP.cpp
new file mode 100755
index 0000000..4b5acd6
--- /dev/null
+++ b/src/AS_DCP.cpp
@@ -0,0 +1,509 @@
+/*
+Copyright (c) 2004-2005, 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.cpp
+ \version $Id$
+ \brief AS-DCP library, misc classes and subroutines
+*/
+
+#include <AS_DCP_system.h>
+#include "hex_utils.h"
+#include <assert.h>
+
+
+static const ui32_t s_MessageCount = 27;
+static const char* s_ErrorMessages[] =
+{
+ "An undefined error was detected.",
+ "An unexpected NULL pointer was given.",
+ "An unexpected empty string was given.",
+ "The given frame buffer is too small.",
+ "The object is not yet initialized.",
+
+ "The requested file does not exist on the system.",
+ "Insufficient privilege exists to perform the operation.",
+ "File open error.",
+ "The file contains errors or is not OP-Atom/AS-DCP.",
+ "An invalid file location was requested.",
+
+ "File read error.",
+ "File write error.",
+ "Unknown raw essence file type.",
+ "Raw essence format invalid.",
+ "Object state error.",
+
+ "Attempt to read past end of file.",
+ "Invalid configuration option detected.",
+ "Frame number out of range.",
+ "AESEncContext required when writing to encrypted file",
+ "Plaintext offset exceeds frame buffer size",
+
+ "Error allocating memory",
+ "Cannot resize externally allocated memory",
+ "The check value did not decrypt correctly",
+ "HMAC authentication failure",
+ "HMAC context required",
+
+ "Error initializing block cipher context",
+ "Attempted to write an empty frame buffer"
+};
+
+
+//------------------------------------------------------------------------------------------
+
+//
+class StderrLogSink : public ASDCP::ILogSink
+{
+public:
+ bool show_info;
+ bool show_debug;
+
+ StderrLogSink() : show_info(false), show_debug(false) {}
+ ~StderrLogSink() {}
+
+ void Error(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ vLogf(LOG_ERROR, fmt, &args);
+ va_end(args);
+ }
+
+ void Warn(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ vLogf(LOG_WARN, fmt, &args);
+ va_end(args);
+ }
+
+ void Info(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ vLogf(LOG_INFO, fmt, &args);
+ va_end(args);
+ }
+
+ void Debug(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ vLogf(LOG_DEBUG, fmt, &args);
+ va_end(args);
+ }
+
+ void Logf(ASDCP::ILogSink::LogType_t type, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ vLogf(type, fmt, &args);
+ va_end(args);
+ }
+
+ void vLogf(ASDCP::ILogSink::LogType_t type, const char* fmt, va_list* list) {
+ FILE* stream = stderr;
+
+ switch ( type )
+ {
+ case LOG_ERROR: fputs("Error: ", stream); break;
+ case LOG_WARN: fputs("Warning: ", stream); break;
+ case LOG_INFO:
+ if ( ! show_info ) return;
+ fputs("Info: ", stream);
+ break;
+ case LOG_DEBUG:
+ if ( ! show_debug ) return;
+ fputs("Debug: ", stream);
+ break;
+ }
+
+ vfprintf(stream, fmt, *list);
+ }
+
+} s_StderrLogSink;
+
+//
+static ASDCP::ILogSink* s_DefaultLogSink = 0;
+
+//
+void
+ASDCP::SetDefaultLogSink(ILogSink* Sink)
+{
+ s_DefaultLogSink = Sink;
+}
+
+// bootleg entry for debug enthusiasts
+void
+set_debug_mode(bool info_mode, bool debug_mode)
+{
+ s_StderrLogSink.show_info = info_mode;
+ s_StderrLogSink.show_debug = debug_mode;
+}
+
+// Returns the internal default sink.
+ASDCP::ILogSink&
+ASDCP::DefaultLogSink()
+{
+ if ( s_DefaultLogSink == 0 )
+ s_DefaultLogSink = &s_StderrLogSink;
+
+ return *s_DefaultLogSink;
+}
+
+const char*
+ASDCP::Version()
+{
+ static char ver[16];
+ sprintf(ver, "%lu.%lu.%lu", VERSION_MAJOR, VERSION_APIMINOR, VERSION_IMPMINOR);
+ return ver;
+}
+
+
+// Returns a pointer to an English language string describing the given result code.
+// If the result code is not a valid member of the Result_t enum, the string
+// "**UNKNOWN**" will be returned.
+const char*
+ASDCP::GetResultString(Result_t result)
+{
+ if ( result >= 0 )
+ return "No error.";
+
+ ui32_t idx = (- result);
+
+ if ( idx > s_MessageCount )
+ return "**UNKNOWN**";
+
+ return s_ErrorMessages[--idx];
+}
+
+
+// convert utf-8 hext string to bin
+i32_t
+ASDCP::hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* conv_size)
+{
+ ASDCP_TEST_NULL(str);
+ ASDCP_TEST_NULL(buf);
+ ASDCP_TEST_NULL(conv_size);
+
+ *conv_size = 0;
+
+ if ( str[0] == 0 ) // nothing to convert
+ return 0;
+
+ for ( int j = 0; str[j]; j++ )
+ {
+ if ( isxdigit(str[j]) )
+ (*conv_size)++;
+ }
+
+ if ( *conv_size & 0x01 ) (*conv_size)++;
+ *conv_size /= 2;
+
+ if ( *conv_size > buf_len )// maximum possible data size
+ return -1;
+
+ *conv_size = 0;
+
+ int phase = 0; // track high/low nybble
+
+ // for each character, fill in the high nybble then the low
+ for ( int i = 0; str[i]; i++ )
+ {
+ if ( ! isxdigit(str[i]) )
+ continue;
+
+ byte_t val = str[i] - ( isdigit(str[i]) ? 0x30 : ( isupper(str[i]) ? 0x37 : 0x57 ) );
+
+ if ( phase == 0 )
+ {
+ buf[*conv_size] = val << 4;
+ phase++;
+ }
+ else
+ {
+ buf[*conv_size] |= val;
+ phase = 0;
+ (*conv_size)++;
+ }
+ }
+
+ return 0;
+}
+
+
+// convert a memory region to a NULL-terminated hexadecimal string
+//
+const char*
+ASDCP::bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len)
+{
+ if ( bin_buf == 0
+ || str_buf == 0
+ || ((bin_len * 2) + 1) > str_len )
+ return 0;
+
+ char* p = str_buf;
+
+ for ( ui32_t i = 0; i < bin_len; i++ )
+ {
+ *p = (bin_buf[i] >> 4) & 0x0f;
+ *p += *p < 10 ? 0x30 : 0x61 - 10;
+ p++;
+
+ *p = bin_buf[i] & 0x0f;
+ *p += *p < 10 ? 0x30 : 0x61 - 10;
+ p++;
+ }
+
+ *p = '\0';
+ return str_buf;
+}
+
+
+// spew a range of bin data as hex
+void
+ASDCP::hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream)
+{
+ if ( buf == 0 )
+ return;
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ static ui32_t row_len = 16;
+ const byte_t* p = buf;
+ const byte_t* end_p = p + dump_len;
+
+ for ( ui32_t line = 0; p < end_p; line++ )
+ {
+ fprintf(stream, " %06x: ", line);
+ ui32_t i;
+ const byte_t* pp;
+
+ for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
+ fprintf(stream, "%02x ", *pp);
+
+ while ( i++ < row_len )
+ fputs(" ", stream);
+
+ for ( pp = p, i = 0; i < row_len && pp < end_p; i++, pp++ )
+ fputc((isprint(*pp) ? *pp : '.'), stream);
+
+ fputc('\n', stream);
+ p += row_len;
+ }
+}
+
+//------------------------------------------------------------------------------------------
+
+// read a ber value from the buffer and compare with test value.
+// Advances buffer to first character after BER value.
+//
+bool
+ASDCP::read_test_BER(byte_t **buf, ui64_t test_value)
+{
+ if ( buf == 0 )
+ return false;
+
+ if ( ( **buf & 0x80 ) == 0 )
+ return false;
+
+ ui64_t val = 0;
+ ui8_t ber_size = ( **buf & 0x0f ) + 1;
+
+ if ( ber_size > 9 )
+ return false;
+
+ for ( ui8_t i = 1; i < ber_size; i++ )
+ {
+ if ( (*buf)[i] > 0 )
+ val |= (ui64_t)((*buf)[i]) << ( ( ( ber_size - 1 ) - i ) * 8 );
+ }
+
+ *buf += ber_size;
+ return ( val == test_value );
+}
+
+
+//
+bool
+ASDCP::read_BER(const byte_t* buf, ui64_t* val)
+{
+ ui8_t ber_size, i;
+
+ if ( buf == 0 || val == 0 )
+ return false;
+
+ if ( ( *buf & 0x80 ) == 0 )
+ return false;
+
+ *val = 0;
+ ber_size = ( *buf & 0x0f ) + 1;
+
+ if ( ber_size > 9 )
+ return false;
+
+ for ( i = 1; i < ber_size; i++ )
+ {
+ if ( buf[i] > 0 )
+ *val |= (ui64_t)buf[i] << ( ( ( ber_size - 1 ) - i ) * 8 );
+ }
+
+ return true;
+}
+
+
+static const ui64_t ber_masks[9] =
+ { ui64_C(0xffffffffffffffff), ui64_C(0xffffffffffffff00),
+ ui64_C(0xffffffffffff0000), ui64_C(0xffffffffff000000),
+ ui64_C(0xffffffff00000000), ui64_C(0xffffff0000000000),
+ ui64_C(0xffff000000000000), ui64_C(0xff00000000000000),
+ 0
+ };
+
+
+//
+bool
+ASDCP::write_BER(byte_t* buf, ui64_t val, ui32_t ber_len)
+{
+ if ( buf == 0 )
+ return false;
+
+ if ( ber_len == 0 )
+ { // calculate default length
+ if ( val < 0x01000000L )
+ ber_len = 4;
+ else if ( val < ui64_C(0x0100000000000000) )
+ ber_len = 8;
+ else
+ ber_len = 9;
+ }
+ else
+ { // sanity check BER length
+ if ( ber_len > 9 )
+ {
+ DefaultLogSink().Error("BER size %lu exceeds maximum size of 9\n", ber_len);
+ return false;
+ }
+
+ if ( val & ber_masks[ber_len - 1] )
+ {
+ char intbuf[IntBufferLen];
+ DefaultLogSink().Error("BER size %lu too small for value %s\n",
+ ber_len, ui64sz(val, intbuf));
+ return false;
+ }
+ }
+
+ buf[0] = 0x80 + ( ber_len - 1 );
+
+ for ( ui32_t i = ber_len - 1; i > 0; i-- )
+ {
+ buf[i] = (ui8_t)(val & 0xff);
+ val >>= 8;
+ }
+
+ return true;
+}
+
+//------------------------------------------------------------------------------------------
+//
+// frame buffer base class implementation
+
+ASDCP::FrameBuffer::FrameBuffer() :
+ m_Data(0), m_Capacity(0), m_OwnMem(false), m_Size(0),
+ m_FrameNumber(0), m_SourceLength(0), m_PlaintextOffset(0)
+{
+}
+
+ASDCP::FrameBuffer::~FrameBuffer()
+{
+ if ( m_OwnMem && m_Data != 0 )
+ free(m_Data);
+}
+
+// Instructs the object to use an externally allocated buffer. The external
+// buffer will not be cleaned up by the frame buffer when it is destroyed.
+// Call with (0,0) to revert to internally allocated buffer.
+// Returns error if the buf_addr argument is NULL and either buf_size is
+// non-zero or internally allocated memory is in use.
+ASDCP::Result_t
+ASDCP::FrameBuffer::SetData(byte_t* buf_addr, ui32_t buf_size)
+{
+ // if buf_addr is null and we have an external memory reference,
+ // drop the reference and place the object in the initialized-
+ // but-no-buffer-allocated state
+ if ( buf_addr == 0 )
+ {
+ if ( buf_size > 0 || m_OwnMem )
+ return RESULT_PTR;
+
+ m_OwnMem = false;
+ m_Capacity = m_Size = 0;
+ m_Data = 0;
+ return RESULT_OK;
+ }
+
+ if ( m_OwnMem && m_Data != 0 )
+ free(m_Data);
+
+ m_OwnMem = false;
+ m_Capacity = buf_size;
+ m_Data = buf_addr;
+ m_Size = 0;
+
+ return RESULT_OK;
+}
+
+// Sets the size of the internally allocate buffer. Returns RESULT_CAPEXTMEM
+// if the object is using an externally allocated buffer via SetData();
+// Resets content size to zero.
+ASDCP::Result_t
+ASDCP::FrameBuffer::Capacity(ui32_t cap_size)
+{
+ if ( ! m_OwnMem && m_Data != 0 )
+ return RESULT_CAPEXTMEM; // cannot resize external memory
+
+ if ( m_Capacity < cap_size )
+ {
+ if ( m_Data != 0 )
+ {
+ assert(m_OwnMem);
+ free(m_Data);
+ }
+
+ m_Data = (byte_t*)malloc(cap_size);
+
+ if ( m_Data == 0 )
+ return RESULT_ALLOC;
+
+ m_Capacity = cap_size;
+ m_OwnMem = true;
+ m_Size = 0;
+ }
+
+ return RESULT_OK;
+}
+
+
+//
+// end AS_DCP.cpp
+//
diff --git a/src/AS_DCP.h b/src/AS_DCP.h
new file mode 100755
index 0000000..06ff8b9
--- /dev/null
+++ b/src/AS_DCP.h
@@ -0,0 +1,1088 @@
+/*
+Copyright (c) 2003-2005, 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.h
+ \version $Id$
+ \brief AS-DCP library, public interface
+
+The asdcplib library is a set of wrapper objects that offer simplified
+access to files conforming to the file formats proposed by the SMPTE
+D-Cinema packaging working group DC28.20. The file format, labeled
+AS-DCP, is described in series of separate documents which include but
+may not be limited to:
+
+ o AS-DCP Track File Specification
+ o AS-DCP Track File Essence Encryption Specification
+ o AS-DCP Operational Constraints Specification
+ o SMPTE 330M - UMID
+ o SMPTE 336M - KLV
+ o SMPTE 377M - MXF
+ o SMPTE 390M - OP-Atom
+ o SMPTE 379M - Generic Container
+ o SMPTE 381M - MPEG2 picture
+ o SMPTE XXXM - JPEG 2000 picture
+ o SMPTE 382M - WAV/PCM sound
+ o IETF RFC 2104 - HMAC/SHA1
+ o NIST FIPS 197 - AES (Rijndael)
+
+The following use cases are supported by the library:
+
+ o Write a plaintext MPEG2 Video Elementary Stream to a plaintext ASDCP file
+ o Write a plaintext MPEG2 Video Elementary Stream to a ciphertext ASDCP file
+ o Read a plaintext MPEG2 Video Elementary Stream from a plaintext ASDCP file
+ o Read a plaintext MPEG2 Video Elementary Stream from a ciphertext ASDCP file
+ o Read a ciphertext MPEG2 Video Elementary Stream from a ciphertext ASDCP file
+ o Write one or more plaintext JPEG 2000 codestreams to a plaintext ASDCP file
+ o Write one or more plaintext JPEG 2000 codestreams to a ciphertext ASDCP file
+ o Read one or more plaintext JPEG 2000 codestreams from a plaintext ASDCP file
+ o Read one or more plaintext JPEG 2000 codestreams from a ciphertext ASDCP file
+ o Read one or more ciphertext JPEG 2000 codestreams from a ciphertext ASDCP file
+ o Write one or more plaintext PCM audio streams to a plaintext ASDCP file
+ o Write one or more plaintext PCM audio streams to a ciphertext ASDCP file
+ o Read one or more plaintext PCM audio streams from a plaintext ASDCP file
+ o Read one or more plaintext PCM audio streams from a ciphertext ASDCP file
+ o Read one or more ciphertext PCM audio streams from a ciphertext ASDCP file
+ o Read header metadata from an ASDCP file
+
+This project depends upon the following library:
+ - OpenSSL http://www.openssl.org/
+
+*/
+
+#ifndef _AS_DCP_H__
+#define _AS_DCP_H__
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <iostream>
+#include <math.h>
+
+//--------------------------------------------------------------------------------
+// common integer types
+// supply your own by defining ASDCP_NO_BASE_TYPES
+
+#ifndef ASDCP_NO_BASE_TYPES
+typedef unsigned char byte_t;
+typedef char i8_t;
+typedef unsigned char ui8_t;
+typedef short i16_t;
+typedef unsigned short ui16_t;
+typedef int i32_t;
+typedef unsigned int ui32_t;
+#endif
+
+
+//--------------------------------------------------------------------------------
+// convenience macros
+
+// Convenience macros for managing return values in predicates
+#define ASDCP_SUCCESS(v) (((v) < 0) ? 0 : 1)
+#define ASDCP_FAILURE(v) (((v) < 0) ? 1 : 0)
+
+
+// Returns RESULT_PTR if the given argument is NULL.
+// See Result_t below for an explanation of RESULT_* symbols.
+#define ASDCP_TEST_NULL(p) \
+ if ( (p) == 0 ) { \
+ return ASDCP::RESULT_PTR; \
+ }
+
+// Returns RESULT_PTR if the given argument is NULL. See Result_t
+// below for an explanation of RESULT_* symbols. It then assumes
+// that the argument is a pointer to a string and returns
+// RESULT_NULL_STR if the first character is '\0'.
+//
+#define ASDCP_TEST_NULL_STR(p) \
+ ASDCP_TEST_NULL(p); \
+ if ( (p)[0] == '\0' ) { \
+ return ASDCP::RESULT_NULL_STR; \
+ }
+
+// Produces copy constructor boilerplate. Allows convenient private
+// declatarion of copy constructors to prevent the compiler from
+// silently manufacturing default methods.
+#define ASDCP_NO_COPY_CONSTRUCT(T) \
+ T(const T&); \
+ T& operator=(const T&)
+
+
+//--------------------------------------------------------------------------------
+// All library components are defined in the namespace ASDCP
+//
+namespace ASDCP {
+ // The version number consists of three segments: major, API minor, and
+ // implementation minor. Whenever a change is made to AS_DCP.h, the API minor
+ // version will increment. Changes made to the internal implementation will
+ // result in the incrementing of the implementation minor version.
+
+ // For example, if asdcplib version 1.0.0 were modified to accomodate changes
+ // in file format, and if no changes were made to AS_DCP.h, the new version would be
+ // 1.0.1. If changes were also required in AS_DCP.h, the new version would be 1.1.1.
+ const ui32_t VERSION_MAJOR = 1;
+ const ui32_t VERSION_APIMINOR = 0;
+ const ui32_t VERSION_IMPMINOR = 3;
+ const char* Version();
+
+ // UUIDs are passed around as strings of UUIDlen bytes
+ const ui32_t UUIDlen = 16;
+
+ // Encryption keys are passed around as strings of KeyLen bytes
+ const ui32_t KeyLen = 16;
+
+ // Encryption key IDs are passed around as strings of KeyIDlen bytes
+ const ui32_t KeyIDlen = 16;
+
+
+ //---------------------------------------------------------------------------------
+ // message logging
+
+ // Error and debug messages will be delivered to an object having this interface.
+ // The default implementation sends only LOG_ERROR and LOG_WARN messages to stderr.
+ // To receive LOG_INFO or LOG_DEBUG messages, or to send messages somewhere other
+ // than stderr, implement this interface and register an instance of your new class
+ // by calling SetDefaultLogSink().
+ class ILogSink
+ {
+ public:
+ enum LogType_t { LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG };
+
+ virtual ~ILogSink() {}
+ virtual void Error(const char*, ...) = 0; // receives error messges
+ virtual void Warn(const char*, ...) = 0; // receives warning messges
+ virtual void Info(const char*, ...) = 0; // receives info messages
+ virtual void Debug(const char*, ...) = 0; // receives debug messages
+ virtual void Logf(LogType_t, const char*, ...) = 0; // log a formatted string with positional parameters
+ virtual void vLogf(LogType_t, const char*, va_list*) = 0; // log a formatted string with a va_list struct
+ };
+
+ // Sets the internal default sink to the given receiver. If the given value
+ // is zero, sets the default sink to the internally allocated stderr sink.
+ void SetDefaultLogSink(ILogSink* = 0);
+
+ // Returns the internal default sink.
+ ILogSink& DefaultLogSink();
+
+ //---------------------------------------------------------------------------------
+ // return values
+
+ // Each method or subroutine in this library that is not void or does not directly
+ // return a value will instead return a result code from this enumeration.
+ enum Result_t {
+ RESULT_FALSE = 1, // successful but negative
+ RESULT_OK = 0, // No errors detected
+ RESULT_FAIL = -1, // An undefined error was detected
+ RESULT_PTR = -2, // An unexpected NULL pointer was given
+ RESULT_NULL_STR = -3, // An unexpected empty string was given
+ RESULT_SMALLBUF = -4, // The given frame buffer is too small
+ RESULT_INIT = -5, // The object is not yet initialized
+ RESULT_NOT_FOUND = -6, // The requested file does not exist on the system
+ RESULT_NO_PERM = -7, // Insufficient privilege exists to perform the operation
+ RESULT_FILEOPEN = -8, // Failure opening file
+ RESULT_FORMAT = -9, // The file format is not proper OP-Atom/AS-DCP
+ RESULT_BADSEEK = -10, // An invalid file location was requested
+ RESULT_READFAIL = -11, // File read error
+ RESULT_WRITEFAIL = -12, // File write error
+ RESULT_RAW_ESS = -13, // Unknown raw essence file type
+ RESULT_RAW_FORMAT = -14, // Raw essence format invalid
+ RESULT_STATE = -15, // Object state error
+ RESULT_ENDOFFILE = -16, // Attempt to read past end of file
+ RESULT_CONFIG = -17, // Invalid configuration option detected
+ RESULT_RANGE = -18, // Frame number out of range
+ RESULT_CRYPT_CTX = -19, // AESEncContext required when writing to encrypted file
+ RESULT_LARGE_PTO = -20, // Plaintext offset exceeds frame buffer size
+ RESULT_ALLOC = -21, // Error allocating memory
+ RESULT_CAPEXTMEM = -22, // Cannot resize externally allocated memory
+ RESULT_CHECKFAIL = -23, // The check value did not decrypt correctly
+ RESULT_HMACFAIL = -24, // HMAC authentication failure
+ RESULT_HMAC_CTX = -25, // HMAC context required
+ RESULT_CRYPT_INIT = -26, // Error initializing block cipher context
+ RESULT_EMPTY_FB = -27, // Attempted to write an empty frame buffer
+ };
+
+ // Returns a pointer to an English language string describing the given result code.
+ // If the result code is not a valid member of the Result_t enum, the string
+ // "**UNKNOWN**" will be returned.
+ const char* GetResultString(Result_t);
+
+ //---------------------------------------------------------------------------------
+ // file identification
+
+ // 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
+ };
+
+
+ // Determine the type of essence contained in the given MXF file. RESULT_OK
+ // is returned if the file is successfully opened and contains a valid MXF
+ // stream. If there is an error, the result code will indicate the reason.
+ Result_t EssenceType(const char* filename, EssenceType_t& type);
+
+ // Determine the type of essence contained in the given raw file. RESULT_OK
+ // is returned if the file is successfully opened and contains a known
+ // stream type. If there is an error, the result code will indicate the reason.
+ Result_t RawEssenceType(const char* filename, EssenceType_t& type);
+
+ // Locate the named object in the file header and dump it to the given stream.
+ // The default dump stream is stderr.
+ Result_t FindObject(const char* filename, const char* objname, FILE* = 0);
+
+
+ // A simple container for rational numbers.
+ struct Rational
+ {
+ i32_t Numerator;
+ i32_t Denominator;
+
+ Rational() : Numerator(0), Denominator(0) {}
+ Rational(i32_t n, i32_t d) : Numerator(n), Denominator(d) {}
+
+ inline double Quotient() const {
+ return (double)Numerator / (double)Denominator;
+ }
+
+ inline bool operator==(const Rational& rhs) const {
+ return ( rhs.Numerator == Numerator && rhs.Denominator == Denominator );
+ }
+
+ inline bool operator!=(const Rational& rhs) const {
+ return ( rhs.Numerator != Numerator || rhs.Denominator != Denominator );
+ }
+ };
+
+ // common edit rates, use these instead of hard coded constants
+ const Rational EditRate_24(24,1);
+ const Rational EditRate_23_98(24000,1001);
+ const Rational EditRate_48(48,1);
+ const Rational SampleRate_48k(48000,1);
+
+ // Non-reference counting container for internal member objects.
+ // Please do not use this class for any other purpose.
+ template <class T>
+ class mem_ptr
+ {
+ T* m_p; // the thing we point to
+ mem_ptr(T&);
+
+ public:
+ mem_ptr() : m_p(0) {}
+ mem_ptr(T* p) : m_p(p) {}
+ ~mem_ptr() { delete m_p; }
+
+ inline T& operator*() const { return *m_p; }
+ inline T* operator->() const { return m_p; }
+ inline operator T*()const { return m_p; }
+ inline const mem_ptr<T>& operator=(T* p) { set(p); return *this; }
+ inline T* set(T* p) { delete m_p; m_p = p; return m_p; }
+ inline T* get() const { return m_p; }
+ inline void release() { m_p = 0; }
+ inline bool empty() const { return m_p == 0; }
+ };
+
+ //---------------------------------------------------------------------------------
+ // cryptographic support
+
+ // The following classes define interfaces to Rijndael contexts having the following properties:
+ // o 16 byte key
+ // o CBC mode with 16 byte block size
+ const ui32_t CBC_KEY_SIZE = 16;
+ const ui32_t CBC_BLOCK_SIZE = 16;
+ const ui32_t HMAC_SIZE = 20;
+
+ //
+ class AESEncContext
+ {
+ class h__AESContext;
+ mem_ptr<h__AESContext> m_Context;
+ ASDCP_NO_COPY_CONSTRUCT(AESEncContext);
+
+ public:
+ AESEncContext();
+ ~AESEncContext();
+
+ // 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.
+ Result_t SetIVec(const byte_t* i_vec);
+ Result_t GetIVec(byte_t* i_vec) const;
+
+ // Encrypt a block of data. The block size must be a multiple of CBC_BLOCK_SIZE.
+ // Returns error if either argument is NULL.
+ Result_t EncryptBlock(const byte_t* pt_buf, byte_t* ct_buf, ui32_t block_size);
+ };
+
+ //
+ class AESDecContext
+ {
+ class h__AESContext;
+ mem_ptr<h__AESContext> m_Context;
+ ASDCP_NO_COPY_CONSTRUCT(AESDecContext);
+
+ public:
+ AESDecContext();
+ ~AESDecContext();
+
+ // Initializes Rijndael CBC decryption 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.
+ Result_t SetIVec(const byte_t* i_vec);
+
+ // Decrypt a block of data. The block size must be a multiple of CBC_BLOCK_SIZE.
+ // Returns error if either argument is NULL.
+ Result_t DecryptBlock(const byte_t* ct_buf, byte_t* pt_buf, ui32_t block_size);
+ };
+
+ //
+ class HMACContext
+ {
+ class h__HMACContext;
+ mem_ptr<h__HMACContext> m_Context;
+ ASDCP_NO_COPY_CONSTRUCT(HMACContext);
+
+ public:
+ HMACContext();
+ ~HMACContext();
+
+ // Initializes HMAC context. The key argument must point to a binary
+ // key that is CBC_KEY_SIZE bytes in length. Returns error if the key
+ // argument is NULL.
+ Result_t InitKey(const byte_t* key);
+
+ // Reset internal state, allows repeated cycles of Update -> Finalize
+ void Reset();
+
+ // Add data to the digest. Returns error if the key argument is NULL or
+ // if the digest has been finalized.
+ Result_t Update(const byte_t* buf, ui32_t buf_len);
+
+ // Finalize digest. Returns error if the digest has already been finalized.
+ Result_t Finalize();
+
+ // Writes HMAC value to given buffer. buf must point to a writable area of
+ // memory that is at least HMAC_SIZE bytes in length. Returns error if the
+ // buf argument is NULL or if the digest has not been finalized.
+ Result_t GetHMACValue(byte_t* buf) const;
+
+ // Tests the given value against the finalized value in the object. buf must
+ // point to a readable area of memory that is at least HMAC_SIZE bytes in length.
+ // Returns error if the buf argument is NULL or if the values do ot match.
+ Result_t TestHMACValue(const byte_t* buf) const;
+ };
+
+ //---------------------------------------------------------------------------------
+ // WriterInfo class - encapsulates writer identification details used for
+ // OpenWrite() calls. Replace these values at runtime to identify your product.
+ //
+ struct WriterInfo
+ {
+ byte_t ProductUUID[UUIDlen];
+ byte_t AssetUUID[UUIDlen];
+ byte_t ContextID[UUIDlen];
+ byte_t CryptographicKeyID[KeyIDlen];
+ bool EncryptedEssence; // true if essence data is (or is to be) encrypted
+ bool UsesHMAC; // true if HMAC exists or is to be calculated
+ std::string ProductVersion;
+ std::string CompanyName;
+ std::string ProductName;
+
+ WriterInfo() : EncryptedEssence(false), UsesHMAC(false) {
+ 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);
+ memset(CryptographicKeyID, 0, KeyIDlen);
+
+ ProductVersion = "Unreleased ";
+ ProductVersion += Version();
+ CompanyName = "DCI";
+ ProductName = "asdcplib";
+ }
+ };
+
+ // Print WriterInfo to stream, stderr by default.
+ void WriterInfoDump(const WriterInfo&, FILE* = 0);
+
+ //---------------------------------------------------------------------------------
+ // frame buffer base class
+ //
+ // The supported essence types are stored using per-frame KLV packetization. The
+ // following class implements essence-neutral functionality for managing a buffer
+ // containing a frame of essence.
+
+ class FrameBuffer
+ {
+ ASDCP_NO_COPY_CONSTRUCT(FrameBuffer);
+
+ protected:
+ byte_t* m_Data; // pointer to memory area containing frame data
+ ui32_t m_Capacity; // size of memory area pointed to by m_Data
+ bool m_OwnMem; // if false, m_Data points to externally allocated memory
+ ui32_t m_Size; // size of frame data in memory area pointed to by m_Data
+ ui32_t m_FrameNumber; // delivery-order frame number
+
+ // It is possible to read raw ciphertext from an encrypted AS-DCP file.
+ // After reading an encrypted AS-DCP file in raw mode, the frame buffer will
+ // contain the encrypted source value portion of the Encrypted Triplet, followed
+ // by the integrity pack, if it exists.
+ // The buffer will begin with the IV and CheckValue, followed by encrypted essence
+ // and optional integrity pack
+ // The SourceLength and PlaintextOffset values from the packet will be held in the
+ // following variables:
+ ui32_t m_SourceLength; // plaintext length (delivered plaintext+decrypted ciphertext)
+ ui32_t m_PlaintextOffset; // offset to first byte of ciphertext
+
+ public:
+ FrameBuffer();
+ virtual ~FrameBuffer();
+
+ // Instructs the object to use an externally allocated buffer. The external
+ // buffer will not be cleaned up by the frame buffer when it exits.
+ // Call with (0,0) to revert to internally allocated buffer.
+ // Returns error if the buf_addr argument is NULL and buf_size is non-zero.
+ Result_t SetData(byte_t* buf_addr, ui32_t buf_size);
+
+ // Sets the size of the internally allocate buffer. Returns RESULT_CAPEXTMEM
+ // if the object is using an externally allocated buffer via SetData();
+ // Resets content size to zero.
+ Result_t Capacity(ui32_t cap);
+
+ // returns the size of the buffer
+ inline ui32_t Capacity() const { return m_Capacity; }
+
+ // returns a const pointer to the essence data
+ inline const byte_t* RoData() const { return m_Data; }
+
+ // returns a non-const pointer to the essence data
+ inline byte_t* Data() { return m_Data; }
+
+ // set the size of the buffer's contents
+ inline ui32_t Size(ui32_t size) { return m_Size = size; }
+
+ // returns the size of the buffer's contents
+ inline ui32_t Size() const { return m_Size; }
+
+ // Sets the absolute frame number of this frame in the file in delivery order.
+ inline void FrameNumber(ui32_t num) { m_FrameNumber = num; }
+
+ // Returns the absolute frame number of this frame in the file in delivery order.
+ inline ui32_t FrameNumber() const { return m_FrameNumber; }
+
+ // Sets the length of the plaintext essence data
+ inline void SourceLength(ui32_t len) { m_SourceLength = len; }
+
+ // When this value is 0 (zero), the buffer contains only plaintext. When it is
+ // non-zero, the buffer contains raw ciphertext and the return value is the length
+ // of the original plaintext.
+ inline ui32_t SourceLength() const { return m_SourceLength; }
+
+ // Sets the offset into the buffer at which encrypted data begins
+ inline void PlaintextOffset(ui32_t ofst) { m_PlaintextOffset = ofst; }
+
+ // Returns offset into buffer of first byte of ciphertext.
+ inline ui32_t PlaintextOffset() const { return m_PlaintextOffset; }
+ };
+
+
+ //---------------------------------------------------------------------------------
+ // MPEG2 video elementary stream support
+
+ //
+ namespace MPEG2
+ {
+ // MPEG picture coding type
+ enum FrameType_t {
+ FRAME_U = 0x00, // Unknown
+ FRAME_I = 0x01, // I-Frame
+ FRAME_P = 0x02, // P-Frame
+ FRAME_B = 0x03 // B-Frame
+ };
+
+ // convert FrameType_t to char
+ inline char FrameTypeChar(FrameType_t type)
+ {
+ switch ( type )
+ {
+ case FRAME_I: return 'I';
+ case FRAME_B: return 'B';
+ case FRAME_P: return 'P';
+ default: return 'U';
+ }
+ }
+
+ // Structure represents the metadata elements in the file header's
+ // 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; //
+ };
+
+ // Print VideoDescriptor to stream, stderr by default.
+ void VideoDescriptorDump(const VideoDescriptor&, FILE* = 0);
+
+ // A container for MPEG frame data.
+ class FrameBuffer : public ASDCP::FrameBuffer
+ {
+ ASDCP_NO_COPY_CONSTRUCT(FrameBuffer); // TODO: should have copy construct
+
+ protected:
+ FrameType_t m_FrameType;
+ ui8_t m_TemporalOffset;
+ bool m_ClosedGOP;
+ bool m_GOPStart;
+
+ public:
+ FrameBuffer() :
+ m_FrameType(FRAME_U), m_TemporalOffset(0),
+ m_ClosedGOP(false), m_GOPStart(false) {}
+
+ FrameBuffer(ui32_t size) :
+ m_FrameType(FRAME_U), m_TemporalOffset(0),
+ m_ClosedGOP(false), m_GOPStart(false)
+ {
+ Capacity(size);
+ }
+
+ virtual ~FrameBuffer() {}
+
+ // Sets the MPEG frame type of the picture data in the frame buffer.
+ inline void FrameType(FrameType_t type) { m_FrameType = type; }
+
+ // Returns the MPEG frame type of the picture data in the frame buffer.
+ inline FrameType_t FrameType() const { return m_FrameType; }
+
+ // Sets the MPEG temporal offset of the picture data in the frame buffer.
+ inline void TemporalOffset(ui8_t offset) { m_TemporalOffset = offset; }
+
+ // Returns the MPEG temporal offset of the picture data in the frame buffer.
+ inline ui8_t TemporalOffset() const { return m_TemporalOffset; }
+
+ // Sets the MPEG GOP 'start' attribute for the frame buffer.
+ inline void GOPStart(bool start) { m_GOPStart = start; }
+
+ // True if the frame in the buffer is the first in the GOP (in transport order)
+ inline bool GOPStart() const { return m_GOPStart; }
+
+ // Sets the MPEG GOP 'closed' attribute for the frame buffer.
+ inline void ClosedGOP(bool closed) { m_ClosedGOP = closed; }
+
+ // Returns true if the frame in the buffer is from a closed GOP, false if
+ // the frame is from an open GOP. Always returns false unless GOPStart()
+ // returns true.
+ inline bool ClosedGOP() const { return m_ClosedGOP; }
+
+ // Print object state to stream, include n bytes of frame data if indicated.
+ // Default stream is stderr.
+ void Dump(FILE* = 0, ui32_t dump_len = 0) const;
+ };
+
+
+ // An object which opens and reads an MPEG2 Video Elementary Stream file. The call to
+ // OpenRead() reads metadata from the file and populates an internal VideoDescriptor object.
+ // Each subsequent call to ReadFrame() reads exactly one frame from the stream into the
+ // given FrameBuffer object.
+ class Parser
+ {
+ class h__Parser;
+ mem_ptr<h__Parser> m_Parser;
+ ASDCP_NO_COPY_CONSTRUCT(Parser);
+
+ public:
+ Parser();
+ virtual ~Parser();
+
+ // Opens the stream for reading, parses enough data to provide a complete
+ // set of stream metadata for the MXFWriter below.
+ Result_t OpenRead(const char* filename) const;
+
+ // Fill a VideoDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillVideoDescriptor(VideoDescriptor&) const;
+
+ // Rewind the stream to the beginning.
+ Result_t Reset() const;
+
+ // Reads the next sequential frame in the input file and places it in the
+ // frame buffer. Fails if the buffer is too small or the stream is empty.
+ // The frame buffer's PlaintextOffset parameter will be set to the first
+ // data byte of the first slice. Set this value to zero if you want
+ // encrypted headers.
+ Result_t ReadFrame(FrameBuffer&) const;
+ };
+
+ // A class which creates and writes MPEG frame data to an AS-DCP format MXF file.
+ // Not yet implemented
+ class MXFWriter
+ {
+ class h__Writer;
+ mem_ptr<h__Writer> m_Writer;
+ ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
+
+ public:
+ MXFWriter();
+ virtual ~MXFWriter();
+
+ // 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 VideoDescriptor&, 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();
+ };
+
+ // A class which reads MPEG frame data from an AS-DCP format MXF file.
+ class MXFReader
+ {
+ class h__Reader;
+ mem_ptr<h__Reader> m_Reader;
+ ASDCP_NO_COPY_CONSTRUCT(MXFReader);
+
+ public:
+ MXFReader();
+ virtual ~MXFReader();
+
+ // 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 VideoDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillVideoDescriptor(VideoDescriptor&) 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;
+
+ // 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.
+ Result_t ReadFrameGOPStart(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+ // Calculates the first frame in transport order of the GOP in which the requested
+ // frame is located. Sets key_frame_number to the number of the frame at the calculated position.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FindFrameGOPStart(ui32_t frame_number, ui32_t& key_frame_number) const;
+
+ // Returns the type of the frame at the given position.
+ // Returns RESULT_INIT if the file is not open or RESULT_RANGE if the index is out of range.
+ Result_t FrameType(ui32_t frame_number, FrameType_t&) const;
+
+ // Print debugging information to stream
+ void DumpHeaderMetadata(FILE* = 0) const;
+ void DumpIndex(FILE* = 0) const;
+ };
+ } // namespace MPEG2
+
+ //
+ namespace PCM
+ {
+ struct AudioDescriptor
+ {
+ Rational SampleRate; // rate of frame wrapping
+ Rational AudioSamplingRate; // rate of audio sample
+ 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 ContainerDuration; // number of frames
+ };
+
+ // Print debugging information to stream (stderr default)
+ void AudioDescriptorDump(const AudioDescriptor&, FILE* = 0);
+
+ // Returns size in bytes of a single sample of data described by ADesc
+ inline ui32_t CalcSampleSize(const AudioDescriptor& ADesc)
+ {
+ return (ADesc.QuantizationBits / 8) * ADesc.ChannelCount;
+ }
+
+ // Returns number of samples per frame of data described by ADesc
+ inline ui32_t CalcSamplesPerFrame(const AudioDescriptor& ADesc)
+ {
+ double tmpd = ADesc.AudioSamplingRate.Quotient() / ADesc.SampleRate.Quotient();
+ return (ui32_t)ceil(tmpd);
+ }
+
+ // Returns the size in bytes of a frame of data described by ADesc
+ inline ui32_t CalcFrameBufferSize(const AudioDescriptor& ADesc)
+ {
+ return CalcSampleSize(ADesc) * CalcSamplesPerFrame(ADesc);
+ }
+
+ //
+ 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 WAV file. The call to OpenRead() reads metadata from
+ // the file and populates an internal AudioDescriptor object. Each subsequent call to
+ // ReadFrame() reads exactly one frame from the stream into the given FrameBuffer object.
+ // A "frame" is either 2000 or 2002 samples, depending upon the value of PictureRate.
+ class WAVParser
+ {
+ class h__WAVParser;
+ mem_ptr<h__WAVParser> m_Parser;
+ ASDCP_NO_COPY_CONSTRUCT(WAVParser);
+
+ public:
+ WAVParser();
+ virtual ~WAVParser();
+
+ // Opens the stream for reading, parses enough data to provide a complete
+ // set of stream metadata for the MXFWriter below. PictureRate controls
+ // ther frame rate for the MXF frame wrapping option.
+ Result_t OpenRead(const char* filename, const Rational& PictureRate) const;
+
+ // Fill an AudioDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillAudioDescriptor(AudioDescriptor&) const;
+
+ // Rewind the stream to the beginning.
+ Result_t Reset() const;
+
+ // Reads the next sequential frame in the input file and places it in the
+ // frame buffer. Fails if the buffer is too small or the stream is empty.
+ 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();
+
+ // 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 AudioDescriptor&, 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();
+
+ // 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 AudioDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillAudioDescriptor(AudioDescriptor&) 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;
+
+ // Print debugging information to stream
+ void DumpHeaderMetadata(FILE* = 0) const;
+ void DumpIndex(FILE* = 0) const;
+ };
+ } // namespace PCM
+
+ //
+ namespace JP2K
+ {
+ const ui32_t MaxComponents = 3;
+ const ui32_t DefaultCodingDataLength = 64;
+
+ struct ImageComponent
+ {
+ byte_t Ssize;
+ byte_t XRsize;
+ byte_t YRsize;
+ };
+
+ struct PictureDescriptor
+ {
+ Rational EditRate;
+ ui32_t ContainerDuration;
+ Rational SampleRate;
+ ui32_t StoredWidth;
+ ui32_t StoredHeight;
+ Rational AspectRatio;
+ ui16_t Rsize;
+ ui32_t Xsize;
+ ui32_t Ysize;
+ ui32_t XOsize;
+ ui32_t YOsize;
+ ui32_t XTsize;
+ ui32_t YTsize;
+ ui32_t XTOsize;
+ ui32_t YTOsize;
+ ui16_t Csize;
+ ImageComponent ImageComponents[MaxComponents];
+ byte_t CodingStyle[DefaultCodingDataLength];
+ ui32_t CodingStyleLength;
+ byte_t QuantDefault[DefaultCodingDataLength];
+ ui32_t QuantDefaultLength;
+ };
+
+ // Print debugging information to stream (stderr default)
+ void PictureDescriptorDump(const PictureDescriptor&, 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 JPEG 2000 codestream file. The file is expected
+ // to contain exactly one complete frame of picture essence as an unwrapped (raw)
+ // ISO/IEC 15444 codestream.
+ class CodestreamParser
+ {
+ class h__CodestreamParser;
+ mem_ptr<h__CodestreamParser> m_Parser;
+ ASDCP_NO_COPY_CONSTRUCT(CodestreamParser);
+
+ public:
+ CodestreamParser();
+ virtual ~CodestreamParser();
+
+ // 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 PictureDescriptor struct with the values from the file's codestream.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillPictureDescriptor(PictureDescriptor&) const;
+ };
+
+ // An object which reads a sequence of files containing JPEG 2000 pictures.
+ 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 codestream for exactly one picture. The
+ // files must be named such that the frames are in temporal order when sorted
+ // 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
+ // mismatch is detected.
+ Result_t OpenRead(const char* filename, bool pedantic = false) const;
+
+ // Fill a PictureDescriptor struct with the values from the first file's codestream.
+ // Returns RESULT_INIT if the directory is not open.
+ Result_t FillPictureDescriptor(PictureDescriptor&) 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();
+
+ // 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 PictureDescriptor&, 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();
+
+ // 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 AudioDescriptor struct with the values from the file's header.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillPictureDescriptor(PictureDescriptor&) 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;
+
+ // Print debugging information to stream
+ void DumpHeaderMetadata(FILE* = 0) const;
+ void DumpIndex(FILE* = 0) const;
+ };
+ } // namespace JP2K
+} // namespace ASDCP
+
+
+#endif // _AS_DCP_H__
+
+//
+// end AS_DCP.h
+//
diff --git a/src/AS_DCP_AES.cpp b/src/AS_DCP_AES.cpp
new file mode 100755
index 0000000..3d36566
--- /dev/null
+++ b/src/AS_DCP_AES.cpp
@@ -0,0 +1,462 @@
+/*
+Copyright (c) 2004, 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_AES.h
+ \version $Id$
+ \brief AS-DCP library, AES wrapper
+*/
+
+
+#include <assert.h>
+#include <AS_DCP.h>
+
+using namespace ASDCP;
+const int KEY_SIZE_BITS = 128;
+
+
+#ifndef ASDCP_WITHOUT_OPENSSL
+#include <openssl/aes.h>
+#include <openssl/sha.h>
+#include <openssl/err.h>
+
+void
+print_ssl_error()
+{
+ char err_buf[256];
+ unsigned long errval = ERR_get_error();
+ DefaultLogSink().Error("OpenSSL: %s\n", ERR_error_string(errval, err_buf));
+}
+
+#endif
+
+
+//------------------------------------------------------------------------------------------
+
+#ifdef ASDCP_WITHOUT_OPENSSL
+class ASDCP::AESEncContext::h__AESContext
+#else
+class ASDCP::AESEncContext::h__AESContext : public AES_KEY
+#endif
+{
+public:
+ byte_t m_IVec[CBC_BLOCK_SIZE];
+};
+
+
+ASDCP::AESEncContext::AESEncContext() {}
+ASDCP::AESEncContext::~AESEncContext() {}
+
+// Initializes Rijndael CBC encryption context.
+// Returns error if the key argument is NULL.
+ASDCP::Result_t
+ASDCP::AESEncContext::InitKey(const byte_t* key)
+{
+ ASDCP_TEST_NULL(key);
+
+ if ( m_Context )
+ return RESULT_INIT;
+
+#ifndef ASDCP_WITHOUT_OPENSSL
+ m_Context = new h__AESContext;
+
+ if ( AES_set_encrypt_key(key, KEY_SIZE_BITS, m_Context) )
+ {
+ print_ssl_error();
+ return RESULT_CRYPT_INIT;
+ }
+
+ return RESULT_OK;
+#else // ASDCP_WITHOUT_OPENSSL
+ return RESULT_FAIL;
+#endif // ASDCP_WITHOUT_OPENSSL
+}
+
+
+// Set the value of the 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.
+ASDCP::Result_t
+ASDCP::AESEncContext::SetIVec(const byte_t* i_vec)
+{
+ ASDCP_TEST_NULL(i_vec);
+
+ if ( ! m_Context )
+ return RESULT_INIT;
+
+#ifndef ASDCP_WITHOUT_OPENSSL
+ memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE);
+ return RESULT_OK;
+#else // ASDCP_WITHOUT_OPENSSL
+ return RESULT_FAIL;
+#endif // ASDCP_WITHOUT_OPENSSL
+}
+
+
+// Retrieve the value of the 16 byte CBC Initialization Vector.
+// Returns error if the i_vec argument is NULL.
+ASDCP::Result_t
+ASDCP::AESEncContext::GetIVec(byte_t* i_vec) const
+{
+ ASDCP_TEST_NULL(i_vec);
+
+ if ( ! m_Context )
+ return RESULT_INIT;
+
+#ifndef ASDCP_WITHOUT_OPENSSL
+ memcpy(i_vec, m_Context->m_IVec, CBC_BLOCK_SIZE);
+ return RESULT_OK;
+#else // ASDCP_WITHOUT_OPENSSL
+ return RESULT_FAIL;
+#endif // ASDCP_WITHOUT_OPENSSL
+}
+
+
+// Encrypt a 16 byte block of data.
+// Returns error if either argument is NULL.
+ASDCP::Result_t
+ASDCP::AESEncContext::EncryptBlock(const byte_t* pt_buf, byte_t* ct_buf, ui32_t block_size)
+{
+ ASDCP_TEST_NULL(pt_buf);
+ ASDCP_TEST_NULL(ct_buf);
+ assert(block_size > 0);
+ assert( block_size % CBC_BLOCK_SIZE == 0 );
+
+ if ( m_Context.empty() )
+ return RESULT_INIT;
+
+#ifndef ASDCP_WITHOUT_OPENSSL
+ h__AESContext* Ctx = m_Context;
+ byte_t tmp_buf[CBC_BLOCK_SIZE];
+ const byte_t* in_p = pt_buf;
+ byte_t* out_p = ct_buf;
+
+ while ( block_size )
+ {
+ // xor with the previous block
+ for ( ui32_t i = 0; i < CBC_BLOCK_SIZE; i++ )
+ tmp_buf[i] = in_p[i] ^ Ctx->m_IVec[i];
+
+ AES_encrypt(tmp_buf, Ctx->m_IVec, Ctx);
+ memcpy(out_p, Ctx->m_IVec, CBC_BLOCK_SIZE);
+
+ in_p += CBC_BLOCK_SIZE;
+ out_p += CBC_BLOCK_SIZE;
+ block_size -= CBC_BLOCK_SIZE;
+ }
+
+ return RESULT_OK;
+#else // ASDCP_WITHOUT_OPENSSL
+ return RESULT_FAIL;
+#endif // ASDCP_WITHOUT_OPENSSL
+}
+
+
+//------------------------------------------------------------------------------------------
+
+#ifdef ASDCP_WITHOUT_OPENSSL
+class ASDCP::AESDecContext::h__AESContext
+#else
+class ASDCP::AESDecContext::h__AESContext : public AES_KEY
+#endif
+{
+public:
+ byte_t m_IVec[CBC_BLOCK_SIZE];
+};
+
+ASDCP::AESDecContext::AESDecContext() {}
+ASDCP::AESDecContext::~AESDecContext() {}
+
+
+// Initializes Rijndael CBC decryption context.
+// Returns error if the key argument is NULL.
+ASDCP::Result_t
+ASDCP::AESDecContext::InitKey(const byte_t* key)
+{
+ ASDCP_TEST_NULL(key);
+
+ if ( m_Context )
+ return RESULT_INIT;
+
+#ifndef ASDCP_WITHOUT_OPENSSL
+ m_Context = new h__AESContext;
+
+ if ( AES_set_decrypt_key(key, KEY_SIZE_BITS, m_Context) )
+ {
+ print_ssl_error();
+ return RESULT_CRYPT_INIT;
+ }
+
+ return RESULT_OK;
+#else // ASDCP_WITHOUT_OPENSSL
+ return RESULT_FAIL;
+#endif // ASDCP_WITHOUT_OPENSSL
+}
+
+// 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.
+ASDCP::Result_t
+ASDCP::AESDecContext::SetIVec(const byte_t* i_vec)
+{
+ ASDCP_TEST_NULL(i_vec);
+
+ if ( ! m_Context )
+ return RESULT_INIT;
+
+#ifndef ASDCP_WITHOUT_OPENSSL
+ memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE);
+ return RESULT_OK;
+#else // ASDCP_WITHOUT_OPENSSL
+ return RESULT_FAIL;
+#endif // ASDCP_WITHOUT_OPENSSL
+}
+
+// Decrypt a 16 byte block of data.
+// Returns error if either argument is NULL.
+ASDCP::Result_t
+ASDCP::AESDecContext::DecryptBlock(const byte_t* ct_buf, byte_t* pt_buf, ui32_t block_size)
+{
+ ASDCP_TEST_NULL(ct_buf);
+ ASDCP_TEST_NULL(pt_buf);
+ assert(block_size > 0);
+ assert( block_size % CBC_BLOCK_SIZE == 0 );
+
+ if ( m_Context.empty() )
+ return RESULT_INIT;
+
+#ifndef ASDCP_WITHOUT_OPENSSL
+ register h__AESContext* Ctx = m_Context;
+
+ const byte_t* in_p = ct_buf;
+ byte_t* out_p = pt_buf;
+
+ while ( block_size )
+ {
+ AES_decrypt(in_p, out_p, Ctx);
+
+ for ( ui32_t i = 0; i < CBC_BLOCK_SIZE; i++ )
+ out_p[i] ^= Ctx->m_IVec[i];
+
+ memcpy(Ctx->m_IVec, in_p, CBC_BLOCK_SIZE);
+
+ in_p += CBC_BLOCK_SIZE;
+ out_p += CBC_BLOCK_SIZE;
+ block_size -= CBC_BLOCK_SIZE;
+ }
+
+ return RESULT_OK;
+#else // ASDCP_WITHOUT_OPENSSL
+ return RESULT_FAIL;
+#endif // ASDCP_WITHOUT_OPENSSL
+}
+
+//------------------------------------------------------------------------------------------
+
+
+static byte_t ipad[KeyLen] = { 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 };
+
+static byte_t opad[KeyLen] = { 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c };
+
+class HMACContext::h__HMACContext
+{
+#ifndef ASDCP_WITHOUT_OPENSSL
+ SHA_CTX m_SHA;
+#endif // ASDCP_WITHOUT_OPENSSL
+ byte_t m_key[KeyLen];
+ ASDCP_NO_COPY_CONSTRUCT(h__HMACContext);
+
+public:
+ byte_t sha_value[HMAC_SIZE];
+ bool m_Final;
+
+ h__HMACContext() : m_Final(false) {}
+ ~h__HMACContext() {}
+
+ //
+ void SetKey(const byte_t* key)
+ {
+ static byte_t key_nonce[KeyLen] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
+#ifndef ASDCP_WITHOUT_OPENSSL
+ byte_t sha_buf[SHA_DIGEST_LENGTH];
+
+ // 7.10: MICKey = trunc( SHA1 ( key, key_nonce ) )
+ SHA_CTX SHA;
+ SHA1_Init(&SHA);
+ SHA1_Update(&SHA, key, KeyLen);
+ SHA1_Update(&SHA, key_nonce, KeyLen);
+ SHA1_Final(sha_buf, &SHA);
+ memcpy(m_key, sha_buf, KeyLen);
+
+ Reset();
+#endif // ASDCP_WITHOUT_OPENSSL
+ }
+
+ void
+ Reset()
+ {
+#ifndef ASDCP_WITHOUT_OPENSSL
+ byte_t xor_buf[KeyLen];
+ memset(sha_value, 0, HMAC_SIZE);
+ m_Final = false;
+ SHA1_Init(&m_SHA);
+
+ // H(K XOR opad, H(K XOR ipad, text))
+ // ^^^^^^^^^^
+ for ( ui32_t i = 0; i < KeyLen; i++ )
+ xor_buf[i] = m_key[i] ^ ipad[i];
+
+ SHA1_Update(&m_SHA, xor_buf, KeyLen);
+#endif // ASDCP_WITHOUT_OPENSSL
+ }
+
+ //
+ void
+ Update(const byte_t* buf, ui32_t buf_len)
+ {
+#ifndef ASDCP_WITHOUT_OPENSSL
+ // H(K XOR opad, H(K XOR ipad, text))
+ // ^^^^
+ SHA1_Update(&m_SHA, buf, buf_len);
+#endif // ASDCP_WITHOUT_OPENSSL
+ }
+
+ //
+ void
+ Finalize()
+ {
+#ifndef ASDCP_WITHOUT_OPENSSL
+ // H(K XOR opad, H(K XOR ipad, text))
+ // ^^^^^^^^^^^^^^^
+ SHA1_Final(sha_value, &m_SHA);
+
+ SHA_CTX SHA;
+ SHA1_Init(&SHA);
+
+ byte_t xor_buf[KeyLen];
+
+ for ( ui32_t i = 0; i < KeyLen; i++ )
+ xor_buf[i] = m_key[i] ^ opad[i];
+
+ SHA1_Update(&SHA, xor_buf, KeyLen);
+ SHA1_Update(&SHA, sha_value, HMAC_SIZE);
+
+ SHA1_Final(sha_value, &SHA);
+ m_Final = true;
+#endif // ASDCP_WITHOUT_OPENSSL
+ }
+};
+
+
+HMACContext::HMACContext()
+{
+}
+
+HMACContext::~HMACContext()
+{
+}
+
+
+//
+Result_t
+HMACContext::InitKey(const byte_t* key)
+{
+ ASDCP_TEST_NULL(key);
+
+ m_Context = new h__HMACContext;
+ m_Context->SetKey(key);
+ return RESULT_OK;
+}
+
+
+//
+void
+HMACContext::Reset()
+{
+ if ( ! m_Context.empty() )
+ m_Context->Reset();
+}
+
+
+//
+Result_t
+HMACContext::Update(const byte_t* buf, ui32_t buf_len)
+{
+ ASDCP_TEST_NULL(buf);
+
+ if ( m_Context.empty() || m_Context->m_Final )
+ return RESULT_INIT;
+
+ m_Context->Update(buf, buf_len);
+ return RESULT_OK;
+}
+
+
+//
+Result_t
+HMACContext::Finalize()
+{
+ if ( m_Context.empty() || m_Context->m_Final )
+ return RESULT_INIT;
+
+ m_Context->Finalize();
+ return RESULT_OK;
+}
+
+
+//
+Result_t
+HMACContext::GetHMACValue(byte_t* buf) const
+{
+ ASDCP_TEST_NULL(buf);
+
+ if ( m_Context.empty() || ! m_Context->m_Final )
+ return RESULT_INIT;
+
+ memcpy(buf, m_Context->sha_value, HMAC_SIZE);
+ return RESULT_OK;
+}
+
+
+//
+Result_t
+HMACContext::TestHMACValue(const byte_t* buf) const
+{
+ ASDCP_TEST_NULL(buf);
+
+ if ( m_Context.empty() || ! m_Context->m_Final )
+ return RESULT_INIT;
+
+ return ( memcmp(buf, m_Context->sha_value, HMAC_SIZE) == 0 ) ? RESULT_OK : RESULT_HMACFAIL;
+}
+
+
+
+//
+// end AS_DCP_AES.cpp
+//
diff --git a/src/AS_DCP_JP2K.cpp b/src/AS_DCP_JP2K.cpp
new file mode 100755
index 0000000..4262edf
--- /dev/null
+++ b/src/AS_DCP_JP2K.cpp
@@ -0,0 +1,594 @@
+/*
+Copyright (c) 2004-2006, 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_JP2k.cpp
+ \version $Id$
+ \brief AS-DCP library, JPEG 2000 essence reader and writer implementation
+*/
+
+#include "AS_DCP_internal.h"
+#include "MDD.h"
+#include <assert.h>
+
+
+//------------------------------------------------------------------------------------------
+
+//
+const byte_t JP2KEssenceCompressionLabel[klv_key_size] =
+{
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x09,
+ 0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x01, 0x01 };
+#if 0
+//
+ASDCP::Result_t
+ASDCP::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc, MDObject& PDescObj)
+{
+ char text_buf[32];
+
+ PDescObj.SetValue("Codec", DataChunk(klv_key_size, JP2KEssenceCompressionLabel));
+
+ sprintf(text_buf, "%ld/%ld", PDesc.EditRate.Numerator, PDesc.EditRate.Denominator);
+ PDescObj.SetString("SampleRate", text_buf);
+
+ sprintf(text_buf, "%ld/%ld", PDesc.AspectRatio.Numerator, PDesc.AspectRatio.Denominator);
+ PDescObj.SetString("AspectRatio", text_buf);
+
+ PDescObj.SetUint("FrameLayout", 0);
+ PDescObj.SetUint("StoredWidth", PDesc.StoredWidth);
+ PDescObj.SetUint("StoredHeight", PDesc.StoredHeight);
+ PDescObj.SetUint("ContainerDuration", PDesc.ContainerDuration);
+
+ MDObject* PSubDescObj = GetMDObjectByType(PDescObj, "JPEG2000PictureSubDescriptor");
+
+ if ( PSubDescObj == 0 )
+ {
+ DefaultLogSink().Error("Unable to locate JPEG2000PictureSubDescriptor");
+ return RESULT_FALSE;
+ }
+
+ PSubDescObj->SetUint("Rsize", PDesc.Rsize);
+ PSubDescObj->SetUint("Xsize", PDesc.Xsize);
+ PSubDescObj->SetUint("Ysize", PDesc.Ysize);
+ PSubDescObj->SetUint("XOsize", PDesc.XOsize);
+ PSubDescObj->SetUint("YOsize", PDesc.YOsize);
+ PSubDescObj->SetUint("XTsize", PDesc.XTsize);
+ PSubDescObj->SetUint("YTsize", PDesc.YTsize);
+ PSubDescObj->SetUint("XTOsize", PDesc.XTOsize);
+ PSubDescObj->SetUint("YTOsize", PDesc.YTOsize);
+ PSubDescObj->SetUint("Csize", PDesc.Csize);
+
+ const ui32_t tmp_buffer_len = 64;
+ byte_t tmp_buffer[tmp_buffer_len];
+
+ *(ui32_t*)tmp_buffer = ASDCP_i32_BE(3L); // three components
+ *(ui32_t*)(tmp_buffer+4) = ASDCP_i32_BE(3L);
+ memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent) * 3L);
+
+ PSubDescObj->SetValue("PictureComponentSizing", DataChunk(17, tmp_buffer));
+ PSubDescObj->SetValue("CodingStyleDefault", DataChunk(PDesc.CodingStyleLength, PDesc.CodingStyle));
+ PSubDescObj->SetValue("QuantizationDefault", DataChunk(PDesc.QuantDefaultLength, PDesc.QuantDefault));
+
+ return RESULT_OK;
+}
+#endif
+
+//
+ASDCP::Result_t
+ASDCP::MD_to_JP2K_PDesc(MXF::RGBAEssenceDescriptor* PDescObj, JP2K::PictureDescriptor& PDesc)
+{
+ ASDCP_TEST_NULL(PDescObj);
+ PDesc.CodingStyleLength = PDesc.QuantDefaultLength = 0;
+
+#if 0
+ PDesc.StoredWidth = PDescObj.GetUint("StoredWidth");
+ PDesc.StoredHeight = PDescObj.GetUint("StoredHeight");
+ PDesc.ContainerDuration = PDescObj.GetUint("ContainerDuration");
+
+ //
+ MDObject* Ptr = PDescObj["SampleRate"]; // should be EditRate
+
+ if ( Ptr )
+ {
+ PDesc.EditRate.Numerator = Ptr->GetInt("Numerator");
+ PDesc.EditRate.Denominator = Ptr->GetInt("Denominator");
+ }
+
+ //
+ Ptr = PDescObj["AspectRatio"];
+
+ if ( Ptr )
+ {
+ PDesc.AspectRatio.Numerator = Ptr->GetInt("Numerator");
+ PDesc.AspectRatio.Denominator = Ptr->GetInt("Denominator");
+ }
+
+ MDObject* PSubDescObj = GetMDObjectByType(PDescObj, "JPEG2000PictureSubDescriptor");
+
+ if ( PSubDescObj == 0 )
+ {
+ DefaultLogSink().Error("Unable to locate JPEG2000PictureSubDescriptor");
+ return RESULT_FALSE;
+ }
+
+ PDesc.Rsize = PSubDescObj->GetUint("Rsize");
+ PDesc.Xsize = PSubDescObj->GetUint("Xsize");
+ PDesc.Ysize = PSubDescObj->GetUint("Ysize");
+ PDesc.XOsize = PSubDescObj->GetUint("XOsize");
+ PDesc.YOsize = PSubDescObj->GetUint("YOsize");
+ PDesc.XTsize = PSubDescObj->GetUint("XTsize");
+ PDesc.YTsize = PSubDescObj->GetUint("YTsize");
+ PDesc.XTOsize = PSubDescObj->GetUint("XTOsize");
+ PDesc.YTOsize = PSubDescObj->GetUint("YTOsize");
+ PDesc.Csize = PSubDescObj->GetUint("Csize");
+
+ //
+ Ptr = (*PSubDescObj)["PictureComponentSizing"];
+
+ if ( Ptr )
+ {
+ DataChunk DC3 = Ptr->GetData();
+
+ if ( DC3.Size == 17 ) // ( 2* sizeof(ui32_t) ) + 3 components * 3 byte each
+ {
+ memcpy(&PDesc.ImageComponents, DC3.Data + 8, DC3.Size - 8);
+ }
+ else
+ {
+ DefaultLogSink().Error("Unexpected PictureComponentSizing size: %lu, should be 17\n", DC3.Size);
+ }
+ }
+
+ //
+ Ptr = (*PSubDescObj)["CodingStyleDefault"];
+
+ if ( Ptr )
+ {
+ DataChunk DC1 = Ptr->GetData();
+ PDesc.CodingStyleLength = DC1.Size;
+ memcpy(PDesc.CodingStyle, DC1.Data, DC1.Size);
+ }
+
+ //
+ Ptr = (*PSubDescObj)["QuantizationDefault"];
+
+ if ( Ptr )
+ {
+ DataChunk DC2 = Ptr->GetData();
+ PDesc.QuantDefaultLength = DC2.Size;
+ memcpy(PDesc.QuantDefault, DC2.Data, DC2.Size);
+ }
+#endif
+ return RESULT_OK;
+}
+
+
+void
+ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "\
+ AspectRatio: %lu/%lu\n\
+ EditRate: %lu/%lu\n\
+ StoredWidth: %lu\n\
+ StoredHeight: %lu\n\
+ Rsize: %lu\n\
+ Xsize: %lu\n\
+ Ysize: %lu\n\
+ XOsize: %lu\n\
+ YOsize: %lu\n\
+ XTsize: %lu\n\
+ YTsize: %lu\n\
+ XTOsize: %lu\n\
+ YTOsize: %lu\n\
+ContainerDuration: %lu\n",
+ PDesc.AspectRatio.Numerator ,PDesc.AspectRatio.Denominator,
+ PDesc.EditRate.Numerator ,PDesc.EditRate.Denominator,
+ PDesc.StoredWidth,
+ PDesc.StoredHeight,
+ PDesc.Rsize,
+ PDesc.Xsize,
+ PDesc.Ysize,
+ PDesc.XOsize,
+ PDesc.YOsize,
+ PDesc.XTsize,
+ PDesc.YTsize,
+ PDesc.XTOsize,
+ PDesc.YTOsize,
+ PDesc.ContainerDuration
+ );
+
+ fprintf(stream, "Color Components:\n");
+
+ for ( ui32_t i = 0; i < PDesc.Csize; i++ )
+ {
+ fprintf(stream, " %lu.%lu.%lu\n",
+ PDesc.ImageComponents[i].Ssize,
+ PDesc.ImageComponents[i].XRsize,
+ PDesc.ImageComponents[i].YRsize
+ );
+ }
+
+ const ui32_t tmp_buf_len = 256;
+ char tmp_buf[tmp_buf_len];
+
+ if ( PDesc.CodingStyleLength )
+ fprintf(stream, "Default Coding (%lu): %s\n",
+ PDesc.CodingStyleLength,
+ bin2hex(PDesc.CodingStyle, PDesc.CodingStyleLength,
+ tmp_buf, tmp_buf_len)
+ );
+
+ if ( PDesc.QuantDefaultLength )
+ fprintf(stream, "Default Coding (%lu): %s\n",
+ PDesc.QuantDefaultLength,
+ bin2hex(PDesc.QuantDefault, PDesc.QuantDefaultLength,
+ tmp_buf, tmp_buf_len)
+ );
+}
+
+//------------------------------------------------------------------------------------------
+//
+// hidden, internal implementation of JPEG 2000 reader
+
+class ASDCP::JP2K::MXFReader::h__Reader : public ASDCP::h__Reader
+{
+ ASDCP_NO_COPY_CONSTRUCT(h__Reader);
+
+public:
+ PictureDescriptor m_PDesc; // codestream parameter list
+
+ h__Reader() {}
+ Result_t OpenRead(const char*);
+ Result_t ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
+ Result_t ReadFrameGOPStart(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
+};
+
+
+//
+//
+ASDCP::Result_t
+ASDCP::JP2K::MXFReader::h__Reader::OpenRead(const char* filename)
+{
+ Result_t result = OpenMXFRead(filename);
+
+ if( ASDCP_SUCCESS(result) )
+ {
+ InterchangeObject* Object;
+ if ( ASDCP_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &Object)) )
+ {
+ assert(Object);
+ result = MD_to_JP2K_PDesc((MXF::RGBAEssenceDescriptor*)Object, m_PDesc);
+ }
+ }
+
+ if( ASDCP_SUCCESS(result) )
+ result = InitMXFIndex();
+
+ if( ASDCP_SUCCESS(result) )
+ result = InitInfo(m_Info);
+
+ return result;
+}
+
+//
+//
+ASDCP::Result_t
+ASDCP::JP2K::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC)
+{
+ if ( ! m_File.IsOpen() )
+ return RESULT_INIT;
+
+ return ReadEKLVPacket(FrameNum, FrameBuf, JP2KEssenceUL_Data, Ctx, HMAC);
+}
+
+//------------------------------------------------------------------------------------------
+
+
+//
+void
+ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "Frame: %06lu, %7lu bytes", m_FrameNumber, m_Size);
+
+ fputc('\n', stream);
+
+ if ( dump_len > 0 )
+ hexdump(m_Data, dump_len, stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::JP2K::MXFReader::MXFReader()
+{
+ m_Reader = new h__Reader;
+}
+
+
+ASDCP::JP2K::MXFReader::~MXFReader()
+{
+}
+
+// Open the file for reading. The file must exist. Returns error if the
+// operation cannot be completed.
+ASDCP::Result_t
+ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
+{
+ return m_Reader->OpenRead(filename);
+}
+
+//
+ASDCP::Result_t
+ASDCP::JP2K::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;
+}
+
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ PDesc = m_Reader->m_PDesc;
+ 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::JP2K::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::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_HeaderPart.Dump(stream);
+}
+
+
+//
+void
+ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_FooterPart.Dump(stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+
+
+#if 0
+//
+class ASDCP::JP2K::MXFWriter::h__Writer : public ASDCP::h__Writer
+{
+public:
+ PictureDescriptor m_PDesc;
+ ui32_t m_GOPOffset;
+
+ ASDCP_NO_COPY_CONSTRUCT(h__Writer);
+
+ h__Writer() : m_GOPOffset(0) {}
+ ~h__Writer(){}
+
+ Result_t OpenWrite(const char*, ui32_t HeaderSize);
+ Result_t SetSourceStream(const PictureDescriptor&);
+ Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+ Result_t Finalize();
+};
+
+
+// Open the file for writing. The file must not exist. Returns error if
+// the operation cannot be completed.
+ASDCP::Result_t
+ASDCP::JP2K::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize)
+{
+ if ( ! m_State.Test_BEGIN() )
+ return RESULT_STATE;
+
+ m_File = new MXFFile;
+
+ Result_t result = m_File.OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_EssenceDescriptor = new MDObject("RGBAEssenceDescriptor");
+ MDObject* jp2kDesc = new MDObject("JPEG2000PictureSubDescriptor");
+ MDObject* md01 = m_EssenceDescriptor->AddChild("SubDescriptors");
+
+ if ( md01 == 0 )
+ {
+ DefaultLogSink().Error("Unable to locate JPEG2000PictureSubDescriptor, incomplete dictionary?\n");
+ return RESULT_FAIL;
+ }
+
+ MDObject* md02 = md01->AddChild("SubDescriptor");
+ assert(md02);
+ md02->MakeLink(*jp2kDesc);
+
+ result = m_State.Goto_INIT();
+ }
+
+ return result;
+}
+
+// Automatically sets the MXF file's metadata from the first jpeg codestream stream.
+ASDCP::Result_t
+ASDCP::JP2K::MXFWriter::h__Writer::SetSourceStream(const PictureDescriptor& PDesc)
+{
+ if ( ! m_State.Test_INIT() )
+ return RESULT_STATE;
+
+ m_PDesc = PDesc;
+ Result_t result = JP2K_PDesc_to_MD(m_PDesc, *m_EssenceDescriptor);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = WriteMXFHeader(ESS_JPEG_2000, m_PDesc.EditRate, 24 /* TCFrameRate */);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_State.Goto_READY();
+
+ 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::JP2K::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx,
+ HMACContext* HMAC)
+{
+ Result_t result = RESULT_OK;
+
+ if ( m_State.Test_READY() )
+ result = m_State.Goto_RUNNING(); // first time through
+
+ ui64_t ThisOffset = m_StreamOffset;
+
+ if ( ASDCP_SUCCESS(result) )
+ result = WriteEKLVPacket(FrameBuf, JP2KEssenceUL_Data, Ctx, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_IndexMan->OfferEditUnit(0, m_FramesWritten, 0, 1);
+ m_IndexMan->OfferOffset(0, m_FramesWritten, ThisOffset);
+ m_FramesWritten++;
+ }
+
+ return result;
+}
+
+
+// Closes the MXF file, writing the index and other closing information.
+//
+ASDCP::Result_t
+ASDCP::JP2K::MXFWriter::h__Writer::Finalize()
+{
+ if ( ! m_State.Test_RUNNING() )
+ return RESULT_STATE;
+
+ if ( ! m_File )
+ return RESULT_INIT;
+
+ m_State.Goto_FINAL();
+
+ return WriteMXFFooter(ESS_JPEG_2000);
+}
+
+
+//------------------------------------------------------------------------------------------
+
+
+
+ASDCP::JP2K::MXFWriter::MXFWriter()
+{
+}
+
+ASDCP::JP2K::MXFWriter::~MXFWriter()
+{
+}
+
+
+// Open the file for writing. The file must not exist. Returns error if
+// the operation cannot be completed.
+ASDCP::Result_t
+ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
+ const PictureDescriptor& PDesc, ui32_t HeaderSize)
+{
+ m_Writer = new h__Writer;
+
+ Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_Writer->m_Info = Info;
+ result = m_Writer->SetSourceStream(PDesc);
+ }
+
+ 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::JP2K::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::JP2K::MXFWriter::Finalize()
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->Finalize();
+}
+
+#endif
+
+//
+// end AS_DCP_JP2K.cpp
+//
diff --git a/src/AS_DCP_MPEG2.cpp b/src/AS_DCP_MPEG2.cpp
new file mode 100755
index 0000000..a126583
--- /dev/null
+++ b/src/AS_DCP_MPEG2.cpp
@@ -0,0 +1,529 @@
+/*
+Copyright (c) 2004-2006, 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_MPEG2.cpp
+ \version $Id$
+ \brief AS-DCP library, MPEG2 essence reader and writer implementation
+*/
+
+#include "AS_DCP_internal.h"
+#include "MDD.h"
+
+
+//------------------------------------------------------------------------------------------
+
+//
+ASDCP::Result_t
+ASDCP::MD_to_MPEG2_VDesc(MXF::MPEG2VideoDescriptor* VDescObj, MPEG2::VideoDescriptor& VDesc)
+{
+ ASDCP_TEST_NULL(VDescObj);
+ VDesc = *((MPEG2::VideoDescriptor*)VDescObj);
+ VDesc.FrameRate = 0;
+ return RESULT_OK;
+}
+
+
+//
+void
+ASDCP::MPEG2::VideoDescriptorDump(const VideoDescriptor& VDesc, FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "\
+ SampleRate: %lu/%lu\n\
+ FrameLayout: %lu\n\
+ StoredWidth: %lu\n\
+ StoredHeight: %lu\n\
+ AspectRatio: %lu/%lu\n\
+ ComponentDepth: %lu\n\
+HorizontalSubsampling: %lu\n\
+ VerticalSubsampling: %lu\n\
+ ColorSiting: %lu\n\
+ CodedContentType: %lu\n\
+ LowDelay: %lu\n\
+ BitRate: %lu\n\
+ ProfileAndLevel: %lu\n\
+ ContainerDuration: %lu\n",
+ VDesc.SampleRate.Numerator ,VDesc.SampleRate.Denominator,
+ VDesc.FrameLayout,
+ VDesc.StoredWidth,
+ VDesc.StoredHeight,
+ VDesc.AspectRatio.Numerator ,VDesc.AspectRatio.Denominator,
+ VDesc.ComponentDepth,
+ VDesc.HorizontalSubsampling,
+ VDesc.VerticalSubsampling,
+ VDesc.ColorSiting,
+ VDesc.CodedContentType,
+ VDesc.LowDelay,
+ VDesc.BitRate,
+ VDesc.ProfileAndLevel,
+ VDesc.ContainerDuration
+ );
+}
+
+//------------------------------------------------------------------------------------------
+//
+// hidden, internal implementation of MPEG2 reader
+
+class ASDCP::MPEG2::MXFReader::h__Reader : public ASDCP::h__Reader
+{
+ ASDCP_NO_COPY_CONSTRUCT(h__Reader);
+
+public:
+ VideoDescriptor m_VDesc; // video parameter list
+
+ h__Reader() {}
+ ~h__Reader() {}
+ Result_t OpenRead(const char*);
+ Result_t ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
+ Result_t ReadFrameGOPStart(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
+ Result_t FindFrameGOPStart(ui32_t, ui32_t&);
+};
+
+
+//
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::h__Reader::OpenRead(const char* filename)
+{
+ Result_t result = OpenMXFRead(filename);
+
+ if( ASDCP_SUCCESS(result) )
+ {
+ InterchangeObject* Object;
+ if ( ASDCP_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(MPEG2VideoDescriptor), &Object)) )
+ {
+ assert(Object);
+ result = MD_to_MPEG2_VDesc((MXF::MPEG2VideoDescriptor*)Object, m_VDesc);
+ }
+ }
+
+ if( ASDCP_SUCCESS(result) )
+ result = InitMXFIndex();
+
+ if( ASDCP_SUCCESS(result) )
+ result = InitInfo(m_Info);
+
+ return result;
+}
+
+
+//
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::h__Reader::ReadFrameGOPStart(ui32_t FrameNum, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC)
+{
+ ui32_t KeyFrameNum;
+
+ Result_t result = FindFrameGOPStart(FrameNum, KeyFrameNum);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = ReadFrame(KeyFrameNum, FrameBuf, Ctx, HMAC);
+
+ return result;
+}
+
+
+//
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::h__Reader::FindFrameGOPStart(ui32_t FrameNum, ui32_t& KeyFrameNum)
+{
+ KeyFrameNum = 0;
+
+ if ( ! m_File.IsOpen() )
+ return RESULT_INIT;
+
+ // look up frame index node
+ IndexTableSegment::IndexEntry TmpEntry;
+
+ if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
+ {
+ DefaultLogSink().Error("Frame value out of range: %lu\n", FrameNum);
+ return RESULT_RANGE;
+ }
+
+ KeyFrameNum = FrameNum - TmpEntry.KeyFrameOffset;
+
+ return RESULT_OK;
+}
+
+
+//
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC)
+{
+ if ( ! m_File.IsOpen() )
+ return RESULT_INIT;
+
+ Result_t result = ReadEKLVPacket(FrameNum, FrameBuf, MPEGEssenceUL_Data, Ctx, HMAC);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ IndexTableSegment::IndexEntry TmpEntry;
+ m_FooterPart.Lookup(FrameNum, TmpEntry);
+
+ switch ( ( TmpEntry.Flags >> 4 ) & 0x03 )
+ {
+ case 0: FrameBuf.FrameType(FRAME_I); break;
+ case 2: FrameBuf.FrameType(FRAME_P); break;
+ case 3: FrameBuf.FrameType(FRAME_B); break;
+ default: FrameBuf.FrameType(FRAME_U);
+ }
+
+ FrameBuf.TemporalOffset(TmpEntry.TemporalOffset);
+ FrameBuf.GOPStart(TmpEntry.Flags & 0x40 ? true : false);
+ FrameBuf.ClosedGOP(TmpEntry.Flags & 0x80 ? true : false);
+
+ return RESULT_OK;
+}
+
+//------------------------------------------------------------------------------------------
+
+
+//
+void
+ASDCP::MPEG2::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "Frame: %06lu, %c%-2hu, %7lu bytes",
+ m_FrameNumber, FrameTypeChar(m_FrameType), m_TemporalOffset, m_Size);
+
+ if ( m_GOPStart )
+ fprintf(stream, " (start %s GOP)", ( m_ClosedGOP ? "closed" : "open"));
+
+ fputc('\n', stream);
+
+ if ( dump_len > 0 )
+ hexdump(m_Data, dump_len, stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::MPEG2::MXFReader::MXFReader()
+{
+ m_Reader = new h__Reader;
+}
+
+
+ASDCP::MPEG2::MXFReader::~MXFReader()
+{
+}
+
+// Open the file for reading. The file must exist. Returns error if the
+// operation cannot be completed.
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::OpenRead(const char* filename) const
+{
+ return m_Reader->OpenRead(filename);
+}
+
+//
+ASDCP::Result_t
+ASDCP::MPEG2::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::MPEG2::MXFReader::ReadFrameGOPStart(ui32_t FrameNum, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ return m_Reader->ReadFrameGOPStart(FrameNum, FrameBuf, Ctx, HMAC);
+
+ return RESULT_INIT;
+}
+
+
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::FindFrameGOPStart(ui32_t FrameNum, ui32_t& KeyFrameNum) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ return m_Reader->FindFrameGOPStart(FrameNum, KeyFrameNum);
+
+ 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::MPEG2::MXFReader::FillVideoDescriptor(VideoDescriptor& VDesc) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ VDesc = m_Reader->m_VDesc;
+ 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::MPEG2::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::MPEG2::MXFReader::DumpHeaderMetadata(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_HeaderPart.Dump(stream);
+}
+
+
+//
+void
+ASDCP::MPEG2::MXFReader::DumpIndex(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_FooterPart.Dump(stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+#if 0
+
+
+//
+class ASDCP::MPEG2::MXFWriter::h__Writer : public ASDCP::h__Writer
+{
+public:
+ VideoDescriptor m_VDesc;
+ ui32_t m_GOPOffset;
+
+ ASDCP_NO_COPY_CONSTRUCT(h__Writer);
+
+ h__Writer() : m_GOPOffset(0) {}
+ ~h__Writer(){}
+
+ Result_t OpenWrite(const char*, ui32_t HeaderSize);
+ Result_t SetSourceStream(const VideoDescriptor&);
+ Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+ Result_t Finalize();
+};
+
+
+// Open the file for writing. The file must not exist. Returns error if
+// the operation cannot be completed.
+ASDCP::Result_t
+ASDCP::MPEG2::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize)
+{
+ if ( ! m_State.Test_BEGIN() )
+ return RESULT_STATE;
+
+ m_File = new MXFFile;
+
+ Result_t result = m_File->OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_EssenceDescriptor = new MDObject("MPEG2VideoDescriptor");
+ result = m_State.Goto_INIT();
+ }
+
+ return result;
+}
+
+// Automatically sets the MXF file's metadata from the MPEG stream.
+ASDCP::Result_t
+ASDCP::MPEG2::MXFWriter::h__Writer::SetSourceStream(const VideoDescriptor& VDesc)
+{
+ if ( ! m_State.Test_INIT() )
+ return RESULT_STATE;
+
+ m_VDesc = VDesc;
+ Result_t result = MPEG2_VDesc_to_MD(m_VDesc, *m_EssenceDescriptor);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = WriteMXFHeader(ESS_MPEG2_VES, m_VDesc.EditRate, 24 /* TCFrameRate */);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_State.Goto_READY();
+
+ 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::MPEG2::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx,
+ HMACContext* HMAC)
+{
+ Result_t result = RESULT_OK;
+
+ if ( m_State.Test_READY() )
+ result = m_State.Goto_RUNNING(); // first time through, get the body location
+
+ ui64_t ThisOffset = m_StreamOffset;
+
+ if ( ASDCP_SUCCESS(result) )
+ result = WriteEKLVPacket(FrameBuf, MPEGEssenceUL_Data, Ctx, HMAC);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ // create mxflib flags
+ int Flags = 0;
+
+ switch ( FrameBuf.FrameType() )
+ {
+ case FRAME_I: Flags = 0x00; break;
+ case FRAME_P: Flags = 0x22; break;
+ case FRAME_B: Flags = 0x33; break;
+ }
+
+ if ( FrameBuf.GOPStart() )
+ {
+ m_GOPOffset = 0;
+ Flags |= 0x40;
+
+ if ( FrameBuf.ClosedGOP() )
+ Flags |= 0x80;
+ }
+
+ // update the index manager
+ m_IndexMan->OfferEditUnit(0, m_FramesWritten, m_GOPOffset, Flags);
+ m_IndexMan->OfferTemporalOffset(m_FramesWritten, m_GOPOffset - FrameBuf.TemporalOffset());
+ m_IndexMan->OfferOffset(0, m_FramesWritten, ThisOffset);
+
+ m_FramesWritten++;
+ m_GOPOffset++;
+
+ return RESULT_OK;
+}
+
+
+// Closes the MXF file, writing the index and other closing information.
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFWriter::h__Writer::Finalize()
+{
+ if ( ! m_State.Test_RUNNING() )
+ return RESULT_STATE;
+
+ if ( ! m_File )
+ return RESULT_INIT;
+
+ m_State.Goto_FINAL();
+
+ return WriteMXFFooter(ESS_MPEG2_VES);
+}
+
+
+//------------------------------------------------------------------------------------------
+
+
+
+ASDCP::MPEG2::MXFWriter::MXFWriter()
+{
+}
+
+ASDCP::MPEG2::MXFWriter::~MXFWriter()
+{
+}
+
+
+// Open the file for writing. The file must not exist. Returns error if
+// the operation cannot be completed.
+ASDCP::Result_t
+ASDCP::MPEG2::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
+ const VideoDescriptor& VDesc, ui32_t HeaderSize)
+{
+ m_Writer = new h__Writer;
+
+ Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_Writer->m_Info = Info;
+ result = m_Writer->SetSourceStream(VDesc);
+ }
+
+ 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::MPEG2::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::MPEG2::MXFWriter::Finalize()
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->Finalize();
+}
+#endif
+
+//
+// end AS_DCP_MPEG2.cpp
+//
diff --git a/src/AS_DCP_MXF.cpp b/src/AS_DCP_MXF.cpp
new file mode 100755
index 0000000..a7cb1e3
--- /dev/null
+++ b/src/AS_DCP_MXF.cpp
@@ -0,0 +1,598 @@
+/*
+Copyright (c) 2004-2005, 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_MXF.cpp
+ \version $Id$
+ \brief AS-DCP library, misc classes and subroutines
+*/
+
+#include "AS_DCP_internal.h"
+#include "FileIO.h"
+#include "DirScanner.h"
+#include "JP2K.h"
+#include "Wav.h"
+#include "MDD.h"
+
+
+//------------------------------------------------------------------------------------------
+// misc subroutines
+
+
+// helper class for XXX below
+//
+class PathSplitter
+{
+public:
+ char* Root;
+ char* SubPath;
+
+ PathSplitter(const std::string Str)
+ {
+ Root = strdup(Str.c_str());
+ assert(Root);
+
+ // sub-path exists?
+ SubPath = strchr(Root, OBJECT_PATH_SEPARATOR);
+
+ if ( SubPath )
+ {
+ while ( SubPath[1] == OBJECT_PATH_SEPARATOR )
+ SubPath++;
+
+ *SubPath++ = 0;
+
+ if ( *SubPath == 0 )
+ SubPath = 0;
+ }
+ }
+
+ ~PathSplitter() {
+ free(Root);
+ }
+};
+
+//
+void
+ASDCP::WriterInfoDump(const WriterInfo& Info, FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ char str_buf[40];
+
+ fprintf(stream," ProductUUID: %s\n", bin2hex(Info.ProductUUID, 16, str_buf, 40));
+ fprintf(stream,"\
+ ProductVersion: %s\n\
+ CompanyName: %s\n\
+ ProductName: %s\n\
+ EncryptedEssence: %s\n",
+ Info.ProductVersion.c_str(),
+ Info.CompanyName.c_str(),
+ Info.ProductName.c_str(),
+ ( Info.EncryptedEssence ? "Yes" : "No" )
+ );
+
+ if ( Info.EncryptedEssence )
+ {
+ fprintf(stream, " HMAC: %s\n", ( Info.UsesHMAC ? "Yes" : "No"));
+ fprintf(stream, " ContextID: %s\n", bin2hex(Info.ContextID, 16, str_buf, 40));
+ fprintf(stream, "CryptographicKeyID: %s\n", bin2hex(Info.CryptographicKeyID, 16, str_buf, 40));
+ }
+
+ fprintf(stream," AssetUUID: %s\n", bin2hex(Info.AssetUUID, 16, str_buf, 40));
+}
+
+//
+Result_t
+ASDCP::MD_to_WriterInfo(Identification* InfoObj, WriterInfo& Info)
+{
+ ASDCP_TEST_NULL(InfoObj);
+ char tmp_str[IdentBufferLen];
+
+ Info.ProductName = "Unknown Product";
+ Info.ProductVersion = "Unknown Version";
+ Info.CompanyName = "Unknown Company";
+ memset(Info.ProductUUID, 0, UUIDlen);
+
+ InfoObj->ProductName.ToString(tmp_str);
+ if ( *tmp_str ) Info.ProductName = tmp_str;
+
+ InfoObj->VersionString.ToString(tmp_str);
+ if ( *tmp_str ) Info.ProductVersion = tmp_str;
+
+ InfoObj->CompanyName.ToString(tmp_str);
+ if ( *tmp_str ) Info.CompanyName = tmp_str;
+
+ memcpy(Info.ProductUUID, InfoObj->ProductUID.Data(), UUIDlen);
+
+ return RESULT_OK;
+}
+
+
+//
+Result_t
+ASDCP::MD_to_CryptoInfo(CryptographicContext* InfoObj, WriterInfo& Info)
+{
+ ASDCP_TEST_NULL(InfoObj);
+
+ Info.EncryptedEssence = true;
+ memcpy(Info.ContextID, InfoObj->ContextID.Data(), UUIDlen);
+ memcpy(Info.CryptographicKeyID, InfoObj->CryptographicKeyID.Data(), UUIDlen);
+
+ UL MIC_SHA1(MICAlgorithm_HMAC_SHA1);
+ UL MIC_NONE(MICAlgorithm_NONE);
+
+ if ( InfoObj->MICAlgorithm == MIC_SHA1 )
+ Info.UsesHMAC = true;
+
+ else if ( InfoObj->MICAlgorithm == MIC_NONE )
+ Info.UsesHMAC = false;
+
+ else
+ {
+ DefaultLogSink().Error("Unexpected MICAlgorithm UL.\n");
+ return RESULT_FORMAT;
+ }
+
+ return RESULT_OK;
+}
+
+#if 0
+
+
+//
+// add DMS CryptographicFramework entry to source package
+void
+ASDCP::AddDMScrypt(PackagePtr SourcePackage, WriterInfo& Descr, const byte_t* SourceEssenceContainerLabel)
+{
+ assert(SourceEssenceContainerLabel);
+
+ TrackPtr MPDMTrack = SourcePackage->AddDMTrack(); // zero parameters = static
+ DMSegmentPtr MPDMSegment = MPDMTrack->AddDMSegment();
+
+ MDObject* Crypto_DMS_Ptr = new MDObject("CryptographicFramework");
+ MPDMSegment->AddChild("DMFramework")->MakeLink(*Crypto_DMS_Ptr);
+
+ MDObject* Crypto_DMS_BasicPtr = new MDObject("CryptographicContext");
+ Crypto_DMS_Ptr->AddChild("ContextSR")->MakeLink(*Crypto_DMS_BasicPtr);
+
+ UUID ContextID(Descr.ContextID);
+ Crypto_DMS_BasicPtr->SetValue("ContextID", DataChunk(UUIDlen, ContextID.GetValue())); // UUID
+ Crypto_DMS_BasicPtr->SetValue("SourceEssenceContainer",
+ DataChunk(klv_key_size, SourceEssenceContainerLabel)); // Label
+ Crypto_DMS_BasicPtr->SetValue("CipherAlgorithm", DataChunk(klv_key_size, CipherAlgorithm_AES)); // UL Key
+
+ Crypto_DMS_BasicPtr->SetValue("MICAlgorithm",
+ DataChunk(KeyLen,
+ (Descr.UsesHMAC ?
+ MICAlgorithm_HMAC_SHA1
+ : MICAlgorithm_NONE))); // UL Key
+
+ UUID CryptographicKeyID(Descr.CryptographicKeyID);
+
+ Crypto_DMS_BasicPtr->SetValue("CryptographicKeyID", DataChunk(UUIDlen, CryptographicKeyID.GetValue())); // UUID
+}
+
+
+//
+//
+ASDCP::Result_t
+ASDCP::FindObject(const char* filename, const char* objname, FILE* stream)
+{
+ ASDCP_TEST_NULL_STR(filename);
+ ASDCP_TEST_NULL_STR(objname);
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ ASDCP::h__Reader Reader;
+ Result_t result = Reader.OpenMXFRead(filename);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ MDObject* DescObj = Reader.GetMDObjectByType(objname);
+
+ if ( DescObj )
+ {
+ DumpMDObject(*DescObj, " ", stream);
+ return RESULT_OK;
+ }
+
+ return RESULT_FAIL;
+}
+#endif
+
+//
+//
+ASDCP::Result_t
+ASDCP::EssenceType(const char* filename, EssenceType_t& type)
+{
+ ASDCP_TEST_NULL_STR(filename);
+ FileReader Reader;
+ OPAtomHeader TestHeader;
+
+ Result_t result = Reader.OpenRead(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = TestHeader.InitFromFile(Reader); // test UL and OP
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ type = ESS_UNKNOWN;
+ if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor))) )
+ type = ESS_JPEG_2000;
+ else
+ {
+ if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor))) )
+ type = ESS_PCM_24b_48k;
+ else
+ {
+ if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(MPEG2VideoDescriptor))) )
+ type = ESS_MPEG2_VES;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+//
+ASDCP::Result_t
+ASDCP::RawEssenceType(const char* filename, EssenceType_t& type)
+{
+ ASDCP_TEST_NULL_STR(filename);
+ type = ESS_UNKNOWN;
+ ASDCP::FrameBuffer FB;
+ FileReader Reader;
+ ui32_t read_count;
+ Result_t result = FB.Capacity(Wav::MaxWavHeader); // using Wav max because everything else is much smaller
+
+ if ( ASDCP::PathIsFile(filename) )
+ {
+ result = Reader.OpenRead(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = Reader.Read(FB.Data(), FB.Capacity(), &read_count);
+ Reader.Close();
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ASDCP::Wav::SimpleWaveHeader WavHeader;
+ ui32_t data_offset;
+ const byte_t* p = FB.RoData();
+
+ if ( p[0] == 0 && p[1] == 0 && p[2] == 1 && (p[3] == 0xb3 || p[3] == 0) )
+ type = ESS_MPEG2_VES;
+
+ else if ( ASDCP_SUCCESS(WavHeader.ReadFromBuffer(p, read_count, &data_offset)) )
+ type = ESS_PCM_24b_48k;
+ }
+ }
+ else if ( ASDCP::PathIsDirectory(filename) )
+ {
+ char next_file[ASDCP_MAX_PATH];
+ DirScanner Scanner;
+ Result_t result = Scanner.Open(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ while ( ASDCP_SUCCESS(Scanner.GetNext(next_file)) )
+ {
+ if ( next_file[0] == '.' ) // no hidden files or internal links
+ continue;
+
+ std::string Str(filename);
+ Str += "/";
+ Str += next_file;
+ result = Reader.OpenRead(Str.c_str());
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = Reader.Read(FB.Data(), FB.Capacity(), &read_count);
+ Reader.Close();
+ }
+
+ if ( ASDCP_SUCCESS(result)
+ && ( memcmp(FB.RoData(), ASDCP::JP2K::Magic, sizeof(ASDCP::JP2K::Magic)) == 0 ) )
+ type = ESS_JPEG_2000;
+
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+//
+Result_t
+ASDCP::EncryptFrameBuffer(const ASDCP::FrameBuffer& FBin, ASDCP::FrameBuffer& FBout, AESEncContext* Ctx)
+{
+ ASDCP_TEST_NULL(Ctx);
+ FBout.Size(0);
+
+ // size the buffer
+ Result_t result = FBout.Capacity(calc_esv_length(FBin.Size(), FBin.PlaintextOffset()));
+
+ // write the IV
+ byte_t* p = FBout.Data();
+
+ // write the IV to the frame buffer
+ Ctx->GetIVec(p);
+ p += CBC_BLOCK_SIZE;
+
+
+ // encrypt the check value to the frame buffer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = Ctx->EncryptBlock(ESV_CheckValue, p, CBC_BLOCK_SIZE);
+ p += CBC_BLOCK_SIZE;
+ }
+
+ // write optional plaintext region
+ if ( FBin.PlaintextOffset() > 0 )
+ {
+ assert(FBin.PlaintextOffset() <= FBin.Size());
+ memcpy(p, FBin.RoData(), FBin.PlaintextOffset());
+ p += FBin.PlaintextOffset();
+ }
+
+ ui32_t ct_size = FBin.Size() - FBin.PlaintextOffset();
+ ui32_t diff = ct_size % CBC_BLOCK_SIZE;
+ ui32_t block_size = ct_size - diff;
+ assert((block_size % CBC_BLOCK_SIZE) == 0);
+
+ // encrypt the ciphertext region essence data
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = Ctx->EncryptBlock(FBin.RoData() + FBin.PlaintextOffset(), p, block_size);
+ p += block_size;
+ }
+
+ // construct and encrypt the padding
+ if ( ASDCP_SUCCESS(result) )
+ {
+ byte_t the_last_block[CBC_BLOCK_SIZE];
+
+ if ( diff > 0 )
+ memcpy(the_last_block, FBin.RoData() + FBin.PlaintextOffset() + block_size, diff);
+
+ for (ui32_t i = 0; diff < CBC_BLOCK_SIZE; diff++, i++ )
+ the_last_block[diff] = i;
+
+ result = Ctx->EncryptBlock(the_last_block, p, CBC_BLOCK_SIZE);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ FBout.Size(calc_esv_length(FBin.Size(), FBin.PlaintextOffset()));
+
+ return result;
+}
+
+//
+Result_t
+ASDCP::DecryptFrameBuffer(const ASDCP::FrameBuffer& FBin, ASDCP::FrameBuffer& FBout, AESDecContext* Ctx)
+{
+ ASDCP_TEST_NULL(Ctx);
+ assert(FBout.Capacity() >= FBin.SourceLength());
+
+ ui32_t ct_size = FBin.SourceLength() - FBin.PlaintextOffset();
+ ui32_t diff = ct_size % CBC_BLOCK_SIZE;
+ ui32_t block_size = ct_size - diff;
+ assert(block_size);
+ assert((block_size % CBC_BLOCK_SIZE) == 0);
+
+ const byte_t* buf = FBin.RoData();
+
+ // get ivec
+ Ctx->SetIVec(buf);
+ buf += CBC_BLOCK_SIZE;
+
+ // decrypt and test check value
+ byte_t CheckValue[CBC_BLOCK_SIZE];
+ Result_t result = Ctx->DecryptBlock(buf, CheckValue, CBC_BLOCK_SIZE);
+ buf += CBC_BLOCK_SIZE;
+
+ if ( memcmp(CheckValue, ESV_CheckValue, CBC_BLOCK_SIZE) != 0 )
+ return RESULT_CHECKFAIL;
+
+ // copy plaintext region
+ if ( FBin.PlaintextOffset() > 0 )
+ {
+ memcpy(FBout.Data(), buf, FBin.PlaintextOffset());
+ buf += FBin.PlaintextOffset();
+ }
+
+ // decrypt all but last block
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = Ctx->DecryptBlock(buf, FBout.Data() + FBin.PlaintextOffset(), block_size);
+ buf += block_size;
+ }
+
+ // decrypt last block
+ if ( ASDCP_SUCCESS(result) )
+ {
+ byte_t the_last_block[CBC_BLOCK_SIZE];
+ result = Ctx->DecryptBlock(buf, the_last_block, CBC_BLOCK_SIZE);
+
+ if ( the_last_block[diff] != 0 )
+ {
+ DefaultLogSink().Error("Unexpected non-zero padding value.\n");
+ return RESULT_FORMAT;
+ }
+
+ if ( diff > 0 )
+ memcpy(FBout.Data() + FBin.PlaintextOffset() + block_size, the_last_block, diff);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ FBout.Size(FBin.SourceLength());
+
+ return result;
+}
+
+
+//
+Result_t
+ASDCP::IntegrityPack::CalcValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID,
+ ui32_t sequence, HMACContext* HMAC)
+{
+ ASDCP_TEST_NULL(AssetID);
+ ASDCP_TEST_NULL(HMAC);
+ byte_t* p = Data;
+ HMAC->Reset();
+
+ static byte_t ber_4[klv_length_size] = {0x83, 0};
+
+ // update HMAC with essence data
+ HMAC->Update(FB.RoData(), FB.Size());
+
+ // track file ID length
+ memcpy(p, ber_4, klv_length_size);
+ *(p+3) = UUIDlen;;
+ p += klv_length_size;
+
+ // track file ID
+ memcpy(p, AssetID, UUIDlen);
+ p += UUIDlen;
+
+ // sequence length
+ memcpy(p, ber_4, klv_length_size);
+ *(p+3) = sizeof(ui64_t);
+ p += klv_length_size;
+
+ // sequence number
+ i2p<ui64_t>(ASDCP_i64_BE(sequence), p);
+ p += sizeof(ui64_t);
+
+ // HMAC length
+ memcpy(p, ber_4, klv_length_size);
+ *(p+3) = HMAC_SIZE;
+ p += klv_length_size;
+
+ // update HMAC with intpack values
+ HMAC->Update(Data, klv_intpack_size - HMAC_SIZE);
+
+ // finish & write HMAC
+ HMAC->Finalize();
+ HMAC->GetHMACValue(p);
+
+ assert(p + HMAC_SIZE == Data + klv_intpack_size);
+
+ return RESULT_OK;
+}
+
+
+Result_t
+ASDCP::IntegrityPack::TestValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID,
+ ui32_t sequence, HMACContext* HMAC)
+{
+ ASDCP_TEST_NULL(AssetID);
+ ASDCP_TEST_NULL(HMAC);
+
+ // find the start of the intpack
+ byte_t* p = (byte_t*)FB.RoData() + ( FB.Size() - klv_intpack_size );
+
+ // test the AssetID length
+ if ( ! read_test_BER(&p, UUIDlen) )
+ return RESULT_HMACFAIL;
+
+ // test the AssetID
+ if ( memcmp(p, AssetID, UUIDlen) != 0 )
+ {
+ DefaultLogSink().Error("IntegrityPack failure: AssetID mismatch.\n");
+ return RESULT_HMACFAIL;
+ }
+ p += UUIDlen;
+
+ // test the sequence length
+ if ( ! read_test_BER(&p, sizeof(ui64_t)) )
+ return RESULT_HMACFAIL;
+
+ ui32_t test_sequence = (ui32_t)ASDCP_i64_BE(cp2i<ui64_t>(p));
+
+ // test the sequence value
+ if ( test_sequence != sequence )
+ {
+ DefaultLogSink().Error("IntegrityPack failure: sequence is %lu, expecting %lu.\n", test_sequence, sequence);
+ return RESULT_HMACFAIL;
+ }
+
+ p += sizeof(ui64_t);
+
+ // test the HMAC length
+ if ( ! read_test_BER(&p, HMAC_SIZE) )
+ return RESULT_HMACFAIL;
+
+ // test the HMAC
+ HMAC->Reset();
+ HMAC->Update(FB.RoData(), FB.Size() - HMAC_SIZE);
+ HMAC->Finalize();
+
+ return HMAC->TestHMACValue(p);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+
+//
+ASDCP::Result_t
+ASDCP::KLVReader::ReadKLFromFile(ASDCP::FileReader& Reader)
+{
+ ui32_t read_count;
+ m_HeaderLength = klv_key_size + klv_length_size;
+ Result_t result = Reader.Read(m_Key, m_HeaderLength, &read_count);
+ assert(read_count == m_HeaderLength);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_BERLength = BER_length(m_Key + klv_key_size);
+
+ if ( m_BERLength != klv_length_size )
+ {
+ ASDCP::DefaultLogSink().Error("Found packet with BER length %lu; being less efficient...\n",
+ m_BERLength);
+ // TODO: recover the correct BER value
+ // and reposition the file pointer
+ assert(0);
+ }
+
+ if ( ! read_BER(m_Key + klv_key_size, &m_Length) )
+ return RESULT_FAIL;
+ }
+
+ return result;
+}
+
+//
+// end AS_DCP_MXF.cpp
+//
diff --git a/src/AS_DCP_PCM.cpp b/src/AS_DCP_PCM.cpp
new file mode 100755
index 0000000..3f019c1
--- /dev/null
+++ b/src/AS_DCP_PCM.cpp
@@ -0,0 +1,475 @@
+/*
+Copyright (c) 2004-2005, 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_PCM.cpp
+ \version $Id$
+ \brief AS-DCP library, PCM essence reader and writer implementation
+*/
+
+#include "AS_DCP_internal.h"
+#include "MDD.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <map>
+
+//------------------------------------------------------------------------------------------
+
+//
+ASDCP::Result_t
+ASDCP::MD_to_PCM_ADesc(MXF::WaveAudioDescriptor* ADescObj, PCM::AudioDescriptor& ADesc)
+{
+ ASDCP_TEST_NULL(ADescObj);
+ ADesc.SampleRate = ADescObj->SampleRate;
+ ADesc.AudioSamplingRate = ADescObj->AudioSamplingRate;
+ ADesc.Locked = ADescObj->Locked;
+ ADesc.ChannelCount = ADescObj->ChannelCount;
+ ADesc.QuantizationBits = ADescObj->QuantizationBits;
+ ADesc.BlockAlign = ADescObj->BlockAlign;
+ ADesc.AvgBps = ADescObj->AvgBps;
+ ADesc.LinkedTrackID = ADescObj->LinkedTrackID;
+ ADesc.ContainerDuration = ADescObj->ContainerDuration;
+ return RESULT_OK;
+}
+
+void
+ASDCP::PCM::AudioDescriptorDump(const AudioDescriptor& ADesc, FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "\
+ SampleRate: %lu/%lu\n\
+ AudioSamplingRate: %lu/%lu\n\
+ Locked: %lu\n\
+ ChannelCount: %lu\n\
+ QuantizationBits: %lu\n\
+ BlockAlign: %lu\n\
+ AvgBps: %lu\n\
+ LinkedTrackID: %lu\n\
+ ContainerDuration: %lu\n",
+ ADesc.SampleRate.Numerator ,ADesc.SampleRate.Denominator,
+ ADesc.AudioSamplingRate.Numerator ,ADesc.AudioSamplingRate.Denominator,
+ ADesc.Locked,
+ ADesc.ChannelCount,
+ ADesc.QuantizationBits,
+ ADesc.BlockAlign,
+ ADesc.AvgBps,
+ ADesc.LinkedTrackID,
+ ADesc.ContainerDuration
+ );
+}
+
+
+//
+//
+static ui32_t
+calc_CBR_frame_size(ASDCP::WriterInfo& Info, const ASDCP::PCM::AudioDescriptor& ADesc)
+{
+ ui32_t CBR_frame_size = 0;
+
+ if ( Info.EncryptedEssence )
+ {
+ CBR_frame_size =
+ klv_key_size
+ + klv_length_size
+ + klv_cryptinfo_size
+ + calc_esv_length(ASDCP::PCM::CalcFrameBufferSize(ADesc), 0)
+ + ( Info.UsesHMAC ? klv_intpack_size : (klv_length_size * 3) );
+ }
+ else
+ {
+ CBR_frame_size = ASDCP::PCM::CalcFrameBufferSize(ADesc) + klv_key_size + klv_length_size;
+ }
+
+ return CBR_frame_size;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+
+class ASDCP::PCM::MXFReader::h__Reader : public ASDCP::h__Reader
+{
+ ASDCP_NO_COPY_CONSTRUCT(h__Reader);
+
+public:
+ AudioDescriptor m_ADesc;
+
+ h__Reader() {}
+ ~h__Reader() {}
+ Result_t OpenRead(const char*);
+ Result_t ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
+};
+
+
+//
+//
+ASDCP::Result_t
+ASDCP::PCM::MXFReader::h__Reader::OpenRead(const char* filename)
+{
+ Result_t result = OpenMXFRead(filename);
+
+ if( ASDCP_SUCCESS(result) )
+ {
+ InterchangeObject* Object;
+ if ( ASDCP_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor), &Object)) )
+ {
+ assert(Object);
+ result = MD_to_PCM_ADesc((MXF::WaveAudioDescriptor*)Object, m_ADesc);
+ }
+ }
+
+ // check for sample/frame rate sanity
+ if ( m_ADesc.SampleRate != EditRate_24
+ && m_ADesc.SampleRate != EditRate_48
+ && m_ADesc.SampleRate != EditRate_23_98 )
+ {
+ DefaultLogSink().Error("PCM file SampleRate is not 24/1, 48/1 or 24000/1001: %08x/%08x\n", // lu
+ m_ADesc.SampleRate.Numerator, m_ADesc.SampleRate.Denominator);
+
+ // oh, they gave us the audio sampling rate instead, assume 24/1
+ if ( m_ADesc.SampleRate == SampleRate_48k )
+ {
+ DefaultLogSink().Warn("adjusting SampleRate to 24/1\n");
+ m_ADesc.SampleRate.Numerator = 24;
+ m_ADesc.SampleRate.Denominator = 1;
+ }
+ else
+ {
+ // or we just drop the hammer
+ return RESULT_FORMAT;
+ }
+ }
+
+ if( ASDCP_SUCCESS(result) )
+ result = InitMXFIndex();
+
+ if( ASDCP_SUCCESS(result) )
+ result = InitInfo(m_Info);
+
+ // TODO: test file for sane CBR index BytesPerEditUnit
+
+ return result;
+}
+
+
+//
+//
+ASDCP::Result_t
+ASDCP::PCM::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
+ AESDecContext* Ctx, HMACContext* HMAC)
+{
+ if ( ! m_File.IsOpen() )
+ return RESULT_INIT;
+
+ return ReadEKLVPacket(FrameNum, FrameBuf, WAVEssenceUL_Data, Ctx, HMAC);
+}
+
+//------------------------------------------------------------------------------------------
+
+
+//
+void
+ASDCP::PCM::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "Frame: %06lu, %7lu bytes\n",
+ m_FrameNumber, m_Size);
+
+ if ( dump_len )
+ hexdump(m_Data, dump_len, stream);
+}
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::PCM::MXFReader::MXFReader()
+{
+ m_Reader = new h__Reader;
+}
+
+
+ASDCP::PCM::MXFReader::~MXFReader()
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ m_Reader->Close();
+}
+
+// Open the file for reading. The file must exist. Returns error if the
+// operation cannot be completed.
+ASDCP::Result_t
+ASDCP::PCM::MXFReader::OpenRead(const char* filename) const
+{
+ return m_Reader->OpenRead(filename);
+}
+
+// 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.
+ASDCP::Result_t
+ASDCP::PCM::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;
+}
+
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::PCM::MXFReader::FillAudioDescriptor(AudioDescriptor& 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::PCM::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::PCM::MXFReader::DumpHeaderMetadata(FILE* stream) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ m_Reader->m_HeaderPart.Dump(stream);
+}
+
+
+//
+void
+ASDCP::PCM::MXFReader::DumpIndex(FILE* stream) const
+{
+ if ( m_Reader->m_File.IsOpen() )
+ m_Reader->m_FooterPart.Dump(stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+#if 0
+
+//
+class ASDCP::PCM::MXFWriter::h__Writer : public ASDCP::h__Writer
+{
+public:
+ AudioDescriptor m_ADesc;
+
+ ASDCP_NO_COPY_CONSTRUCT(h__Writer);
+
+ h__Writer(){}
+ ~h__Writer(){}
+
+ Result_t OpenWrite(const char*, ui32_t HeaderSize);
+ Result_t SetSourceStream(const AudioDescriptor&);
+ Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+ Result_t Finalize();
+};
+
+
+
+// Open the file for writing. The file must not exist. Returns error if
+// the operation cannot be completed.
+ASDCP::Result_t
+ASDCP::PCM::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize)
+{
+ if ( ! m_State.Test_BEGIN() )
+ return RESULT_STATE;
+
+ m_File = new MXFFile;
+
+ Result_t result = m_File.OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_EssenceDescriptor = new MDObject("WaveAudioDescriptor");
+ result = m_State.Goto_INIT();
+ }
+
+ return result;
+}
+
+
+// Automatically sets the MXF file's metadata from the WAV parser info.
+ASDCP::Result_t
+ASDCP::PCM::MXFWriter::h__Writer::SetSourceStream(const AudioDescriptor& ADesc)
+{
+ if ( ! m_State.Test_INIT() )
+ return RESULT_STATE;
+
+ if ( ADesc.SampleRate != EditRate_24
+ && ADesc.SampleRate != EditRate_48
+ && ADesc.SampleRate != EditRate_23_98 )
+ {
+ DefaultLogSink().Error("AudioDescriptor.SampleRate is not 24/1, 48/1 or 24000/1001: %lu/%lu\n",
+ ADesc.SampleRate.Numerator, ADesc.SampleRate.Denominator);
+ return RESULT_RAW_FORMAT;
+ }
+
+ if ( ADesc.AudioSamplingRate != SampleRate_48k )
+ {
+ DefaultLogSink().Error("AudioDescriptor.AudioSamplingRate is not 48000/1: %lu/%lu\n",
+ ADesc.AudioSamplingRate.Numerator, ADesc.AudioSamplingRate.Denominator);
+ return RESULT_RAW_FORMAT;
+ }
+
+ m_ADesc = ADesc;
+ Result_t result = PCM_ADesc_to_MD(m_ADesc, *m_EssenceDescriptor);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = WriteMXFHeader(ESS_PCM_24b_48k, m_ADesc.SampleRate,
+ 24 /* TCFrameRate */, calc_CBR_frame_size(m_Info, m_ADesc));
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_State.Goto_READY();
+
+ return result;
+}
+
+
+//
+//
+ASDCP::Result_t
+ASDCP::PCM::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx,
+ HMACContext* HMAC)
+{
+ Result_t result = RESULT_OK;
+
+ if ( m_State.Test_READY() )
+ result = m_State.Goto_RUNNING(); // first time through
+
+ if ( ASDCP_SUCCESS(result) )
+ result = WriteEKLVPacket(FrameBuf, WAVEssenceUL_Data, Ctx, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ m_FramesWritten++;
+
+ return result;
+}
+
+// Closes the MXF file, writing the index and other closing information.
+//
+ASDCP::Result_t
+ASDCP::PCM::MXFWriter::h__Writer::Finalize()
+{
+ if ( ! m_State.Test_RUNNING() )
+ return RESULT_STATE;
+
+ if ( ! m_File )
+ return RESULT_INIT;
+
+ m_State.Goto_FINAL();
+
+ return WriteMXFFooter(ESS_PCM_24b_48k);
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+
+
+ASDCP::PCM::MXFWriter::MXFWriter()
+{
+}
+
+ASDCP::PCM::MXFWriter::~MXFWriter()
+{
+}
+
+
+// Open the file for writing. The file must not exist. Returns error if
+// the operation cannot be completed.
+ASDCP::Result_t
+ASDCP::PCM::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
+ const AudioDescriptor& ADesc, ui32_t HeaderSize)
+{
+ m_Writer = new h__Writer;
+
+ Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_Writer->m_Info = Info;
+ result = m_Writer->SetSourceStream(ADesc);
+ }
+
+ 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::PCM::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::PCM::MXFWriter::Finalize()
+{
+ if ( m_Writer.empty() )
+ return RESULT_INIT;
+
+ return m_Writer->Finalize();
+}
+
+#endif
+
+//
+// end AS_DCP_PCM.cpp
+//
+
diff --git a/src/AS_DCP_internal.h b/src/AS_DCP_internal.h
new file mode 100755
index 0000000..473a4ab
--- /dev/null
+++ b/src/AS_DCP_internal.h
@@ -0,0 +1,299 @@
+/*
+Copyright (c) 2004-2005, 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_internal.h
+ \version $Id$
+ \brief AS-DCP library, non-public common elements
+*/
+
+#ifndef _AS_DCP_INTERNAL_H__
+#define _AS_DCP_INTERNAL_H__
+
+#include "AS_DCP_system.h"
+#include "Metadata.h"
+#include "hex_utils.h"
+
+using namespace std;
+using namespace ASDCP;
+using namespace ASDCP::MXF;
+
+
+
+namespace ASDCP
+{
+ // constant values used to calculate KLV and EKLV packet sizes
+ static const ui32_t klv_key_size = 16;
+ static const ui32_t klv_length_size = 4;
+
+ static const ui32_t klv_cryptinfo_size =
+ klv_length_size
+ + UUIDlen /* ContextID */
+ + klv_length_size
+ + sizeof(ui64_t) /* PlaintextOffset */
+ + klv_length_size
+ + klv_key_size /* SourceKey */
+ + klv_length_size
+ + sizeof(ui64_t) /* SourceLength */
+ + klv_length_size /* ESV length */ ;
+
+ static const ui32_t klv_intpack_size =
+ klv_length_size
+ + UUIDlen /* TrackFileID */
+ + klv_length_size
+ + sizeof(ui64_t) /* SequenceNumber */
+ + klv_length_size
+ + 20; /* HMAC length*/
+
+ // why this value? i dunno. it was peeled from mxflib.
+ static const ui32_t HeaderPadding = 16384;
+
+ const byte_t GCMulti_Data[16] =
+ { 0x06, 0x0E, 0x2B, 0x34, 0x04, 0x01, 0x01, 0x03,
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x7F, 0x01, 0x00 };
+
+ static const byte_t CipherAlgorithm_AES[klv_key_size] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07,
+ 0x02, 0x09, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00 };
+
+ static const byte_t MICAlgorithm_NONE[klv_key_size] = {0};
+ static const byte_t MICAlgorithm_HMAC_SHA1[klv_key_size] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07,
+ 0x02, 0x09, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00 };
+
+#ifdef SMPTE_LABELS
+ static byte_t OPAtom_Data[klv_key_size] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x02,
+ 0x0d, 0x01, 0x02, 0x01, 0x10, 0x00, 0x00, 0x00 };
+ static UL OPAtomUL(OPAtom_Data);
+#else
+ static byte_t OPAtom_Data[klv_key_size] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x10, 0x00, 0x00, 0x00 };
+ static UL OPAtomUL(OPAtom_Data);
+#endif
+
+ static const byte_t OP1a_Data[klv_key_size] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00 };
+ static UL OP1aUL(OP1a_Data);
+
+ // Essence element labels
+ static const byte_t WAVEssenceUL_Data[klv_key_size] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01,
+ 0x0d, 0x01, 0x03, 0x01, 0x16, 0x01, 0x01, 0x00 };
+
+ static const byte_t MPEGEssenceUL_Data[klv_key_size] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01,
+ 0x0d, 0x01, 0x03, 0x01, 0x15, 0x01, 0x05, 0x00 };
+
+ static const byte_t JP2KEssenceUL_Data[klv_key_size] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01,
+ 0x0d, 0x01, 0x03, 0x01, 0x15, 0x01, 0x08, 0x01 };
+
+#ifdef SMPTE_LABELS
+ static const byte_t CryptEssenceUL_Data[klv_key_size] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x04, 0x01, 0x01,
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x7e, 0x01, 0x00 };
+#else
+ static const byte_t CryptEssenceUL_Data[klv_key_size] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x04, 0x01, 0x07,
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x7e, 0x01, 0x00 };
+#endif
+
+ // Essence Container Labels
+ static const byte_t WrappingUL_Data_PCM_24b_48k[klv_key_size] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01,
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x06, 0x01, 0x00 };
+
+ static const byte_t WrappingUL_Data_MPEG2_VES[klv_key_size] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x02,
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x04, 0x60, 0x01 };
+
+ static const byte_t WrappingUL_Data_JPEG_2000[klv_key_size] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07,
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x0c, 0x01, 0x00 };
+
+ static const byte_t WrappingUL_Data_Crypt[klv_key_size] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07,
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x0b, 0x01, 0x00 };
+
+
+ // the label for the Cryptographic Framework DM scheme
+ static const byte_t CryptoFrameworkUL_Data[klv_key_size] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07,
+ 0x0d, 0x01, 0x04, 0x01, 0x02, 0x01, 0x01, 0x00 };
+
+ // the check value for EKLV packets
+ // CHUKCHUKCHUKCHUK
+ static const byte_t ESV_CheckValue[CBC_BLOCK_SIZE] =
+ { 0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b,
+ 0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b };
+
+ // labels used for FilePackages
+ static std::string MPEG_PACKAGE_LABEL = "File Package: SMPTE 381M frame wrapping of MPEG2 video elementary stream";
+ static std::string JP2K_PACKAGE_LABEL = "File Package: SMPTE XXXM frame wrapping of JPEG 2000 codestreams";
+ static std::string PCM_PACKAGE_LABEL = "File Package: SMPTE 382M frame wrapping of wave audio";
+
+ // GetMDObjectByPath() allows searching for metadata object by pathname
+ // This character separates the path elements.
+ static const char OBJECT_PATH_SEPARATOR = '.';
+
+ //------------------------------------------------------------------------------------------
+ //
+
+ // MDObject* GetMDObjectByPath(MDObject&, const std::string);
+ // MDObject* GetMDObjectByType(MDObject&, const std::string);
+ // void DumpMDObject(MDObject&, std::string = " ", FILE* = 0);
+ // void DumpHeader(Partition&, FILE* = 0);
+ // void DumpIndexTable(IndexTablePtr, ui64_t = 0, FILE* = 0);
+ // Result_t init_mxf_types();
+ Result_t MD_to_MPEG2_VDesc(MXF::MPEG2VideoDescriptor*, MPEG2::VideoDescriptor&);
+ Result_t MD_to_JP2K_PDesc(MXF::RGBAEssenceDescriptor*, JP2K::PictureDescriptor&);
+ Result_t MD_to_PCM_ADesc(MXF::WaveAudioDescriptor*, PCM::AudioDescriptor&);
+ Result_t MD_to_WriterInfo(MXF::Identification*, WriterInfo&);
+ Result_t MD_to_CryptoInfo(MXF::CryptographicContext*, WriterInfo&);
+
+#if 0
+ Result_t MPEG2_VDesc_to_MD(MPEG2::VideoDescriptor&, MDObject&);
+ Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor&, MDObject&);
+ Result_t PCM_ADesc_to_MD(PCM::AudioDescriptor&, MDObject&);
+ void AddDMScrypt(PackagePtr, WriterInfo&, const byte_t*);
+#endif
+
+ Result_t EncryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESEncContext*);
+ Result_t DecryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESDecContext*);
+
+ // calculate size of encrypted essence with IV, CheckValue, and padding
+ inline ui32_t
+ calc_esv_length(ui32_t source_length, ui32_t plaintext_offset)
+ {
+ ui32_t ct_size = source_length - plaintext_offset;
+ ui32_t diff = ct_size % CBC_BLOCK_SIZE;
+ ui32_t block_size = ct_size - diff;
+ return plaintext_offset + block_size + (CBC_BLOCK_SIZE * 3);
+ }
+
+ //
+ class h__Reader
+ {
+ ASDCP_NO_COPY_CONSTRUCT(h__Reader);
+
+ public:
+ FileReader m_File;
+ OPAtomHeader m_HeaderPart;
+ Partition m_BodyPart;
+ OPAtomIndexFooter m_FooterPart;
+ ui64_t m_EssenceStart;
+ WriterInfo m_Info;
+ ASDCP::FrameBuffer m_CtFrameBuf;
+
+ h__Reader();
+ virtual ~h__Reader();
+ //
+ // MDObject* GetMDObjectByType(const std::string ObjName);
+ // MDObject* GetMDObjectByPath(const std::string ObjPath);
+ Result_t InitInfo(WriterInfo& Info);
+ Result_t OpenMXFRead(const char* filename);
+ Result_t InitMXFIndex();
+ Result_t ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
+ const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
+ void Close();
+ };
+
+ // helper class for calculating Integrity Packs, used by WriteEKLVPacket() below.
+ //
+ class IntegrityPack
+ {
+ public:
+ byte_t Data[klv_intpack_size];
+
+ IntegrityPack() {
+ memset(Data, 0, klv_intpack_size);
+ }
+
+ ~IntegrityPack() {}
+
+ Result_t CalcValues(const ASDCP::FrameBuffer&, byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
+ Result_t TestValues(const ASDCP::FrameBuffer&, byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
+ };
+
+ //
+ class KLVReader
+ {
+ byte_t m_Key[32];
+ ui64_t m_Length;
+ ui32_t m_BERLength;
+ ui32_t m_HeaderLength;
+
+ ASDCP_NO_COPY_CONSTRUCT(KLVReader);
+
+ public:
+ KLVReader() : m_Length(0), m_BERLength(0), m_HeaderLength(0) {}
+ ~KLVReader() {}
+
+ inline const byte_t* Key() { return m_Key; }
+ inline const ui64_t Length() { return m_Length; }
+ inline const ui64_t KLLength() { return m_BERLength + klv_key_size; }
+ Result_t ReadKLFromFile(ASDCP::FileReader& Reader);
+#if 0
+ //
+ {
+ ui32_t read_count;
+ m_HeaderLength = klv_key_size + klv_length_size;
+ Result_t result = Reader.Read(m_Key, m_HeaderLength, &read_count);
+ assert(read_count == m_HeaderLength);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_BERLength = BER_length(m_Key + klv_key_size);
+
+ if ( m_BERLength != klv_length_size )
+ {
+ ASDCP::DefaultLogSink().Error("Found packet with BER length %lu; being less efficient...\n",
+ m_BERLength);
+ // TODO: recover the correct BER value
+ // and reposition the file pointer
+ assert(0);
+ }
+
+ if ( ! read_BER(m_Key + klv_key_size, &m_Length) )
+ return RESULT_FAIL;
+ }
+
+ return result;
+ }
+#endif
+
+ };
+
+} // namespace ASDCP
+
+#endif // _AS_DCP_INTERNAL_H__
+
+
+//
+// end AS_DCP_internal.h
+//
diff --git a/src/Index.cpp b/src/Index.cpp
new file mode 100755
index 0000000..9d1791a
--- /dev/null
+++ b/src/Index.cpp
@@ -0,0 +1,203 @@
+//
+// Index.cpp
+//
+
+#include "MDD.h"
+#include "MXF.h"
+
+//
+ASDCP::MXF::IndexTableSegment::IndexTableSegment() :
+ IndexStartPosition(0), IndexDuration(0), EditUnitByteCount(0),
+ IndexSID(0), BodySID(0), SliceCount(0), PosTableCount(0)
+{
+}
+
+//
+ASDCP::MXF::IndexTableSegment::~IndexTableSegment()
+{
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::IndexTableSegment::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ ASDCP_TEST_NULL(p);
+
+ Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_IndexTableSegment].ul);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
+
+ result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(IndexTableSegmentBase, IndexEditRate));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64(OBJ_READ_ARGS(IndexTableSegmentBase, IndexStartPosition));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64(OBJ_READ_ARGS(IndexTableSegmentBase, IndexDuration));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(IndexTableSegmentBase, EditUnitByteCount));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(IndexTableSegmentBase, IndexSID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(IndexTableSegmentBase, BodySID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi8(OBJ_READ_ARGS(IndexTableSegmentBase, SliceCount));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi8(OBJ_READ_ARGS(IndexTableSegmentBase, PosTableCount));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(IndexTableSegment, DeltaEntryArray));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(IndexTableSegment, IndexEntryArray));
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Batch<IndexEntry>::iterator i;
+ ui32_t offset = 0;
+ for ( i = IndexEntryArray.begin(); i != IndexEntryArray.end(); i++ )
+ {
+ if ( (*i).Flags == 0x40 )
+ offset = 0;
+
+ (*i).KeyFrameOffset = offset++;
+ }
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::IndexTableSegment::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_IndexTableSegment].ul, 0);
+#if 0
+ Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_IndexTableSegment].ul);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TLVWriter MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
+
+ result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(IndexTableSegmentBase, IndexEditRate));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64(OBJ_READ_ARGS(IndexTableSegmentBase, IndexStartPosition));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64(OBJ_READ_ARGS(IndexTableSegmentBase, IndexDuration));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(IndexTableSegmentBase, EditUnitByteCount));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(IndexTableSegmentBase, IndexSID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(IndexTableSegmentBase, BodySID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi8(OBJ_READ_ARGS(IndexTableSegmentBase, SliceCount));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi8(OBJ_READ_ARGS(IndexTableSegmentBase, PosTableCount));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(IndexTableSegment, DeltaEntryArray));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(IndexTableSegment, IndexEntryArray));
+ }
+
+ return result;
+#endif
+}
+
+//
+void
+ASDCP::MXF::IndexTableSegment::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVPacket::Dump(stream, false);
+ fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
+ fprintf(stream, " IndexEditRate = %s\n", IndexEditRate.ToString(identbuf));
+ fprintf(stream, " IndexStartPosition = %s\n", i64sz(IndexStartPosition, identbuf));
+ fprintf(stream, " IndexDuration = %s\n", i64sz(IndexDuration, identbuf));
+ fprintf(stream, " EditUnitByteCount = %lu\n", EditUnitByteCount);
+ fprintf(stream, " IndexSID = %lu\n", IndexSID);
+ fprintf(stream, " BodySID = %lu\n", BodySID);
+ fprintf(stream, " SliceCount = %hu\n", SliceCount);
+ fprintf(stream, " PosTableCount = %hu\n", PosTableCount);
+
+ fprintf(stream, " DeltaEntryArray:\n"); DeltaEntryArray.Dump(stream);
+ fprintf(stream, " IndexEntryArray:\n"); IndexEntryArray.Dump(stream);
+
+ fputs("==========================================================================\n", stream);
+}
+
+//
+const char*
+ASDCP::MXF::IndexTableSegment::DeltaEntry::ToString(char* str_buf) const
+{
+ sprintf(str_buf, "%3i %-3hu %-3lu", PosTableIndex, Slice, ElementData);
+ return str_buf;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::IndexTableSegment::DeltaEntry::ReadFrom(ASDCP::MemIOReader& Reader)
+{
+ Result_t result = Reader.ReadUi8((ui8_t*)&PosTableIndex);
+ if ( ASDCP_SUCCESS(result) ) result = Reader.ReadUi8(&Slice);
+ if ( ASDCP_SUCCESS(result) ) result = Reader.ReadUi32BE(&ElementData);
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::IndexTableSegment::DeltaEntry::WriteTo(ASDCP::MemIOWriter& Writer)
+{
+ Result_t result = Writer.WriteUi8((ui8_t)PosTableIndex);
+ if ( ASDCP_SUCCESS(result) ) result = Writer.WriteUi8(Slice);
+ if ( ASDCP_SUCCESS(result) ) result = Writer.WriteUi32BE(ElementData);
+ return result;
+}
+
+// Flags:
+// Bit 7: Random Access
+// Bit 6: Sequence Header
+// Bit 5: forward prediction flag
+// Bit 4: backward prediction flag
+// e.g.
+// 00== I frame (no prediction)
+// 10== P frame(forward prediction from previous frame)
+// 01== B frame (backward prediction from future frame)
+// 11== B frame (forward & backward prediction)
+// Bits 0-3: reserved [RP210 Flags to indicate coding of elements in this edit unit]
+
+//
+const char*
+ASDCP::MXF::IndexTableSegment::IndexEntry::ToString(char* str_buf) const
+{
+ char intbuf[IntBufferLen];
+ char txt_flags[6];
+ txt_flags[5] = 0;
+
+ txt_flags[0] = ( (Flags & 0x80) != 0 ) ? 'r' : ' ';
+ txt_flags[1] = ( (Flags & 0x40) != 0 ) ? 's' : ' ';
+ txt_flags[2] = ( (Flags & 0x20) != 0 ) ? 'f' : ' ';
+ txt_flags[3] = ( (Flags & 0x10) != 0 ) ? 'b' : ' ';
+ txt_flags[4] = ( (Flags & 0x0f) == 3 ) ? 'B' : ( (Flags & 0x0f) == 2 ) ? 'P' : 'I';
+
+ sprintf(str_buf, "%3i %-3hu %s %s",
+ TemporalOffset, KeyFrameOffset, txt_flags,
+ i64sz(StreamOffset, intbuf));
+
+ return str_buf;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::IndexTableSegment::IndexEntry::ReadFrom(ASDCP::MemIOReader& Reader)
+{
+ Result_t result = Reader.ReadUi8((ui8_t*)&TemporalOffset);
+ if ( ASDCP_SUCCESS(result) ) result = Reader.ReadUi8((ui8_t*)&KeyFrameOffset);
+ if ( ASDCP_SUCCESS(result) ) result = Reader.ReadUi8(&Flags);
+ if ( ASDCP_SUCCESS(result) ) result = Reader.ReadUi64BE(&StreamOffset);
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::IndexTableSegment::IndexEntry::WriteTo(ASDCP::MemIOWriter& Writer)
+{
+ Result_t result = Writer.WriteUi8((ui8_t)TemporalOffset);
+ if ( ASDCP_SUCCESS(result) ) result = Writer.WriteUi8((ui8_t)KeyFrameOffset);
+ if ( ASDCP_SUCCESS(result) ) result = Writer.WriteUi8(Flags);
+ if ( ASDCP_SUCCESS(result) ) result = Writer.WriteUi64BE(StreamOffset);
+ return result;
+}
+
+
+//
+// end Index.cpp
+//
+
diff --git a/src/JP2K.cpp b/src/JP2K.cpp
new file mode 100755
index 0000000..20ec891
--- /dev/null
+++ b/src/JP2K.cpp
@@ -0,0 +1,222 @@
+/*
+Copyright (c) 2005, 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 JP2K.cpp
+ \version $Id$
+ \brief JPEG 2000 parser implementation
+
+ This is not a complete implementation of all things JP2K. There is just enough here to
+ support parsing picture metadata from a codestream header.
+*/
+
+#include <JP2K.h>
+#include <hex_utils.h>
+
+
+// when indexed with the second byte of a marker code, this table will procuce one of
+// two values:
+// 0 - the marker is a standalone marker
+// 1 - the marker designates a marker segment
+//
+const byte_t MarkerSegmentMap[] =
+ {
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
+ /* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
+ /* 2 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
+ /* 3 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
+ /* 4 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
+ /* 5 */ 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, // 5
+ /* 6 */ 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
+ /* 7 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
+ /* 9 */ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
+ /* a */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // a
+ /* b */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // b
+ /* c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // c
+ /* d */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // d
+ /* e */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // e
+ /* f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // f
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ };
+
+
+//
+ASDCP::Result_t
+ASDCP::JP2K::GetNextMarker(const byte_t** buf, JP2K::Marker& Marker)
+{
+ assert((buf != 0) && (*buf != 0 ));
+
+ if ( **buf != 0xff )
+ return ASDCP::RESULT_FAIL;
+
+ Marker.m_IsSegment = (MarkerSegmentMap[*(++(*buf))] == 1);
+ Marker.m_Type = (Marker_t)(0xff00 | *(*buf)++);
+
+ if ( Marker.m_IsSegment )
+ {
+ Marker.m_DataSize = *(*buf)++ << 8;
+ Marker.m_DataSize |= *(*buf)++;
+ Marker.m_DataSize -= 2;
+ Marker.m_Data = *buf;
+ *buf += Marker.m_DataSize;
+ }
+
+
+ if ( Marker.m_DataSize != 0 && Marker.m_DataSize < 3 )
+ {
+ DefaultLogSink().Error("Illegal data size: %lu\n", Marker.m_DataSize);
+ return ASDCP::RESULT_FAIL;
+ }
+
+ return ASDCP::RESULT_OK;
+}
+
+
+//-------------------------------------------------------------------------------------------------------
+//
+
+//
+void
+ASDCP::JP2K::Accessor::SIZ::ReadComponent(ui32_t index, ASDCP::JP2K::ImageComponent& IC)
+{
+ assert ( index < Csize() );
+ const byte_t* p = m_MarkerData + 36 + (index * 3);
+ IC.Ssize = *p++;
+ IC.XRsize = *p++;
+ IC.YRsize = *p;
+}
+
+//
+void
+ASDCP::JP2K::Accessor::SIZ::Dump(FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "SIZ: \n");
+ fprintf(stream, " Rsize: %hu\n", Rsize());
+ fprintf(stream, " Xsize: %lu\n", Xsize());
+ fprintf(stream, " Ysize: %lu\n", Xsize());
+ fprintf(stream, " XOsize: %lu\n", XOsize());
+ fprintf(stream, " YOsize: %lu\n", XOsize());
+ fprintf(stream, " XTsize: %lu\n", XTsize());
+ fprintf(stream, " YTsize: %lu\n", XTsize());
+ fprintf(stream, "XTOsize: %lu\n", XTOsize());
+ fprintf(stream, "YTOsize: %lu\n", YTOsize());
+ fprintf(stream, " Csize: %lu\n", Csize());
+
+ if ( Csize() > 0 )
+ {
+ fprintf(stream, "Components\n");
+
+ for ( ui32_t i = 0; i < Csize(); i++ )
+ {
+ ImageComponent TmpComp;
+ ReadComponent(i, TmpComp);
+ fprintf(stream, "%lu: ", i);
+ fprintf(stream, "%lu, %lu, %lu\n", TmpComp.Ssize, TmpComp.XRsize, TmpComp.YRsize);
+ }
+ }
+}
+
+//
+void
+ASDCP::JP2K::Accessor::COM::Dump(FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ if ( IsText() )
+ {
+ char* t_str = (char*)malloc(CommentSize() + 1);
+ assert( t_str != 0 );
+ ui32_t cs = CommentSize();
+ memcpy(t_str, CommentData(), cs);
+ t_str[cs] = 0;
+ fprintf(stream, "COM:%s\n", t_str);
+ }
+ else
+ {
+ hexdump(CommentData(), CommentSize(), stream);
+ }
+}
+
+
+//-------------------------------------------------------------------------------------------------------
+//
+
+
+//
+void
+ASDCP::JP2K::Marker::Dump(FILE* stream) const
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "Marker%s 0x%04x: %s", (m_IsSegment ? " segment" : ""), m_Type, GetMarkerString(m_Type));
+
+ if ( m_IsSegment )
+ fprintf(stream, ", 0x%0x bytes", m_DataSize);
+
+ fputc('\n', stream);
+}
+
+//
+const char*
+ASDCP::JP2K::GetMarkerString(Marker_t m)
+{
+ switch ( m )
+ {
+ case MRK_NIL: return "NIL"; break;
+ case MRK_SOC: return "SOC: Start of codestream"; break;
+ case MRK_SOT: return "SOT: Start of tile-part"; break;
+ case MRK_SOD: return "SOD: Start of data"; break;
+ case MRK_EOC: return "EOC: End of codestream"; break;
+ case MRK_SIZ: return "SIZ: Image and tile size"; break;
+ case MRK_COD: return "COD: Coding style default"; break;
+ case MRK_COC: return "COC: Coding style component"; break;
+ case MRK_RGN: return "RGN: Region of interest"; break;
+ case MRK_QCD: return "QCD: Quantization default"; break;
+ case MRK_QCC: return "QCC: Quantization component"; break;
+ case MRK_POC: return "POC: Progression order change"; break;
+ case MRK_TLM: return "TLM: Tile-part lengths"; break;
+ case MRK_PLM: return "PLM: Packet length, main header"; break;
+ case MRK_PLT: return "PLT: Packet length, tile-part header"; break;
+ case MRK_PPM: return "PPM: Packed packet headers, main header"; break;
+ case MRK_PPT: return "PPT: Packed packet headers, tile-part header"; break;
+ case MRK_SOP: return "SOP: Start of packet"; break;
+ case MRK_EPH: return "EPH: End of packet header"; break;
+ case MRK_CRG: return "CRG: Component registration"; break;
+ case MRK_COM: return "COM: Comment"; break;
+ }
+
+ return "Unknown marker code";
+}
+
+//
+// end
+//
diff --git a/src/JP2K.h b/src/JP2K.h
new file mode 100755
index 0000000..cff77b2
--- /dev/null
+++ b/src/JP2K.h
@@ -0,0 +1,163 @@
+/*
+Copyright (c) 2005, 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 JP2K.h
+ \version $Id$
+ \brief JPEG 2000 constants and data structures
+
+ This is not a complete enumeration of all things JP2K. There is just enough here to
+ support parsing picture metadata from a codestream header.
+*/
+
+#ifndef _JP2K_H_
+#define _JP2K_H_
+
+// AS_DCP.h is included only for it's base type definitions.
+#include <AS_DCP_system.h>
+#include <hex_utils.h>
+#include <assert.h>
+
+namespace ASDCP
+{
+namespace JP2K
+{
+ const byte_t Magic[] = {0xff, 0x4f, 0xff};
+
+ enum Marker_t
+ {
+ MRK_NIL = 0,
+ MRK_SOC = 0xff4f, // Start of codestream
+ MRK_SOT = 0xff90, // Start of tile-part
+ MRK_SOD = 0xff93, // Start of data
+ MRK_EOC = 0xffd9, // End of codestream
+ MRK_SIZ = 0xff51, // Image and tile size
+ MRK_COD = 0xff52, // Coding style default
+ MRK_COC = 0xff53, // Coding style component
+ MRK_RGN = 0xff5e, // Region of interest
+ MRK_QCD = 0xff5c, // Quantization default
+ MRK_QCC = 0xff5d, // Quantization component
+ MRK_POC = 0xff5f, // Progression order change
+ MRK_TLM = 0xff55, // Tile-part lengths
+ MRK_PLM = 0xff57, // Packet length, main header
+ MRK_PLT = 0xff58, // Packet length, tile-part header
+ MRK_PPM = 0xff60, // Packed packet headers, main header
+ MRK_PPT = 0xff61, // Packed packet headers, tile-part header
+ MRK_SOP = 0xff91, // Start of packet
+ MRK_EPH = 0xff92, // End of packet header
+ MRK_CRG = 0xff63, // Component registration
+ MRK_COM = 0xff64, // Comment
+ };
+
+ const char* GetMarkerString(Marker_t m);
+
+ //
+ class Marker
+ {
+ ASDCP_NO_COPY_CONSTRUCT(Marker);
+
+ public:
+ Marker_t m_Type;
+ bool m_IsSegment;
+ ui32_t m_DataSize;
+ const byte_t* m_Data;
+
+ Marker() : m_Type(MRK_NIL), m_IsSegment(false), m_DataSize(0), m_Data(0) {}
+ ~Marker() {}
+
+ void Dump(FILE* stream = 0) const;
+ };
+
+ //
+ ASDCP::Result_t GetNextMarker(const byte_t**, Marker&);
+
+ // accessor objects for marker segments
+ namespace Accessor
+ {
+ // image size
+ class SIZ
+ {
+ const byte_t* m_MarkerData;
+ ASDCP_NO_COPY_CONSTRUCT(SIZ);
+ SIZ();
+
+ public:
+ SIZ(const Marker& M)
+ {
+ assert(M.m_Type == MRK_SIZ);
+ m_MarkerData = M.m_Data;
+ }
+
+ ~SIZ() {}
+
+ inline ui16_t Rsize() { return ASDCP_i16_BE(*(ui16_t*)m_MarkerData); }
+ inline ui32_t Xsize() { return ASDCP_i32_BE(*(ui32_t*)(m_MarkerData + 2)); }
+ inline ui32_t Ysize() { return ASDCP_i32_BE(*(ui32_t*)(m_MarkerData + 6)); }
+ inline ui32_t XOsize() { return ASDCP_i32_BE(*(ui32_t*)(m_MarkerData + 10)); }
+ inline ui32_t YOsize() { return ASDCP_i32_BE(*(ui32_t*)(m_MarkerData + 14)); }
+ inline ui32_t XTsize() { return ASDCP_i32_BE(*(ui32_t*)(m_MarkerData + 18)); }
+ inline ui32_t YTsize() { return ASDCP_i32_BE(*(ui32_t*)(m_MarkerData + 22)); }
+ inline ui32_t XTOsize() { return ASDCP_i32_BE(*(ui32_t*)(m_MarkerData + 26)); }
+ inline ui32_t YTOsize() { return ASDCP_i32_BE(*(ui32_t*)(m_MarkerData + 30)); }
+ inline ui16_t Csize() { return ASDCP_i16_BE(*(ui16_t*)(m_MarkerData + 34)); }
+ void ReadComponent(ui32_t index, ImageComponent& IC);
+ void Dump(FILE* stream = 0);
+ };
+
+ // a comment
+ class COM
+ {
+ bool m_IsText;
+ const byte_t* m_MarkerData;
+ ui32_t m_DataSize;
+
+ ASDCP_NO_COPY_CONSTRUCT(COM);
+ COM();
+
+ public:
+ COM(const Marker& M)
+ {
+ assert(M.m_Type == MRK_COM);
+ m_IsText = M.m_Data[1] == 1;
+ m_MarkerData = M.m_Data + 2;
+ m_DataSize = M.m_DataSize - 2;
+ }
+
+ ~COM() {}
+
+ inline bool IsText() { return m_IsText; }
+ inline const byte_t* CommentData() { return m_MarkerData; }
+ inline ui32_t CommentSize() { return m_DataSize; }
+ void Dump(FILE* stream = 0);
+ };
+ } // namespace Accessor
+} // namespace JP2K
+} // namespace ASDCP
+
+#endif // _JP2K_H_
+
+//
+// end JP2K.h
+//
diff --git a/src/JP2K_Codestream_Parser.cpp b/src/JP2K_Codestream_Parser.cpp
new file mode 100755
index 0000000..216827b
--- /dev/null
+++ b/src/JP2K_Codestream_Parser.cpp
@@ -0,0 +1,193 @@
+/*
+Copyright (c) 2004, 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 Codestream_Parser.cpp
+ \version $Id$
+ \brief AS-DCP library, JPEG 2000 codestream essence reader implementation
+*/
+
+#include <AS_DCP.h>
+#include <FileIO.h>
+#include <JP2K.h>
+#include <assert.h>
+
+//------------------------------------------------------------------------------------------
+
+class ASDCP::JP2K::CodestreamParser::h__CodestreamParser
+{
+ ASDCP_NO_COPY_CONSTRUCT(h__CodestreamParser);
+
+public:
+ PictureDescriptor m_PDesc;
+ FileReader m_File;
+
+ h__CodestreamParser()
+ {
+ memset(&m_PDesc, 0, sizeof(m_PDesc));
+ m_PDesc.EditRate = Rational(24,1);
+ m_PDesc.SampleRate = m_PDesc.EditRate;
+ }
+
+ ~h__CodestreamParser() {}
+
+ 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) )
+ {
+ fsize_t file_size = m_File.Size();
+
+ if ( FB.Capacity() < file_size )
+ {
+ DefaultLogSink().Error("FrameBuf.Capacity: %lu frame length: %lu\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);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Marker NextMarker;
+ ui32_t i;
+ const byte_t* p = FB.RoData();
+ const byte_t* end_p = p + FB.Size();
+
+ while ( p < end_p && ASDCP_SUCCESS(result) )
+ {
+ result = GetNextMarker(&p, NextMarker);
+#if 0
+ fprintf(stderr, "%s Length: %lu\n",
+ GetMarkerString(NextMarker.m_Type), NextMarker.m_DataSize);
+#endif
+
+ switch ( NextMarker.m_Type )
+ {
+ case MRK_SOD:
+ FB.PlaintextOffset(p - FB.RoData());
+ p = end_p;
+ break;
+
+ case MRK_SIZ:
+ {
+ Accessor::SIZ SIZ_(NextMarker);
+ m_PDesc.StoredWidth = SIZ_.Xsize();
+ m_PDesc.StoredHeight = SIZ_.Ysize();
+ m_PDesc.AspectRatio = Rational(SIZ_.Xsize(), SIZ_.Ysize());
+ m_PDesc.Rsize = SIZ_.Rsize();
+ m_PDesc.Xsize = SIZ_.Xsize();
+ m_PDesc.Ysize = SIZ_.Ysize();
+ m_PDesc.XOsize = SIZ_.XOsize();
+ m_PDesc.YOsize = SIZ_.YOsize();
+ m_PDesc.XTsize = SIZ_.XTsize();
+ m_PDesc.YTsize = SIZ_.YTsize();
+ m_PDesc.XTOsize = SIZ_.XTOsize();
+ m_PDesc.YTOsize = SIZ_.YTOsize();
+ m_PDesc.Csize = SIZ_.Csize();
+
+ if ( m_PDesc.Csize != 3 )
+ {
+ DefaultLogSink().Error("Unexpected number of components: %lu\n", m_PDesc.Csize);
+ return RESULT_RAW_FORMAT;
+ }
+
+ for ( i = 0; i < m_PDesc.Csize; i++ )
+ SIZ_.ReadComponent(i, m_PDesc.ImageComponents[i]);
+ }
+ break;
+
+ case MRK_COD:
+ if ( NextMarker.m_DataSize > DefaultCodingDataLength )
+ {
+ DefaultLogSink().Error("Unexpectedly large CodingStyle data: %lu\n", NextMarker.m_DataSize);
+ return RESULT_RAW_FORMAT;
+ }
+
+ m_PDesc.CodingStyleLength = NextMarker.m_DataSize;
+ memcpy(m_PDesc.CodingStyle, NextMarker.m_Data, m_PDesc.CodingStyleLength);
+ break;
+
+ case MRK_QCD:
+ if ( NextMarker.m_DataSize > DefaultCodingDataLength )
+ {
+ DefaultLogSink().Error("Unexpectedly large QuantDefault data: %lu\n", NextMarker.m_DataSize);
+ return RESULT_RAW_FORMAT;
+ }
+
+ m_PDesc.QuantDefaultLength = NextMarker.m_DataSize;
+ memcpy(m_PDesc.QuantDefault, NextMarker.m_Data, m_PDesc.QuantDefaultLength);
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::JP2K::CodestreamParser::CodestreamParser()
+{
+}
+
+ASDCP::JP2K::CodestreamParser::~CodestreamParser()
+{
+}
+
+// Opens the stream for reading, parses enough data to provide a complete
+// set of stream metadata for the MXFWriter below.
+ASDCP::Result_t
+ASDCP::JP2K::CodestreamParser::OpenReadFrame(const char* filename, FrameBuffer& FB) const
+{
+ const_cast<ASDCP::JP2K::CodestreamParser*>(this)->m_Parser = new h__CodestreamParser;
+ return m_Parser->OpenReadFrame(filename, FB);
+}
+
+//
+ASDCP::Result_t
+ASDCP::JP2K::CodestreamParser::FillPictureDescriptor(PictureDescriptor& PDesc) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ PDesc = m_Parser->m_PDesc;
+ return RESULT_OK;
+}
+
+
+//
+// end Codestream_Parser.cpp
+//
diff --git a/src/JP2K_Sequence_Parser.cpp b/src/JP2K_Sequence_Parser.cpp
new file mode 100755
index 0000000..8d1b63c
--- /dev/null
+++ b/src/JP2K_Sequence_Parser.cpp
@@ -0,0 +1,244 @@
+/*
+Copyright (c) 2004-2005, 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 JP2K_Sequence_Parser.cpp
+ \version $Id$
+ \brief AS-DCP library, JPEG 2000 codestream essence reader implementation
+*/
+
+#include <AS_DCP.h>
+#include <FileIO.h>
+#include <DirScanner.h>
+#include <list>
+#include <string>
+#include <algorithm>
+#include <string.h>
+#include <assert.h>
+
+using namespace ASDCP;
+
+
+//------------------------------------------------------------------------------------------
+
+class FileList : public std::list<std::string>
+{
+ std::string m_DirName;
+
+public:
+ FileList() {}
+ ~FileList() {}
+
+ //
+ Result_t InitFromDirectory(const char* path)
+ {
+ char next_file[ASDCP_MAX_PATH];
+ 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;
+ push_back(Str);
+ }
+
+ sort();
+ }
+
+ return result;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+
+class ASDCP::JP2K::SequenceParser::h__SequenceParser
+{
+ ui32_t m_FramesRead;
+ Rational m_PictureRate;
+ FileList m_FileList;
+ FileList::iterator m_CurrentFile;
+ CodestreamParser m_Parser;
+
+ ASDCP_NO_COPY_CONSTRUCT(h__SequenceParser);
+
+public:
+ PictureDescriptor m_PDesc;
+
+ h__SequenceParser() : m_FramesRead(0)
+ {
+ memset(&m_PDesc, 0, sizeof(m_PDesc));
+ m_PDesc.EditRate = Rational(24,1);
+ }
+
+ ~h__SequenceParser()
+ {
+ Close();
+ }
+
+ Result_t OpenRead(const char* filename);
+ void Close() {}
+
+ Result_t Reset()
+ {
+ m_FramesRead = 0;
+ m_CurrentFile = m_FileList.begin();
+ return RESULT_OK;
+ }
+
+ Result_t ReadFrame(FrameBuffer&);
+};
+
+
+//
+ASDCP::Result_t
+ASDCP::JP2K::SequenceParser::h__SequenceParser::OpenRead(const char* filename)
+{
+ ASDCP_TEST_NULL_STR(filename);
+
+ Result_t result = m_FileList.InitFromDirectory(filename);
+
+ if ( m_FileList.empty() )
+ return RESULT_ENDOFFILE;
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_CurrentFile = m_FileList.begin();
+
+ CodestreamParser Parser;
+ FrameBuffer TmpBuffer;
+
+ fsize_t file_size = FileSize((*m_CurrentFile).c_str());
+
+ if ( file_size == 0 )
+ result = RESULT_NOT_FOUND;
+
+ if ( ASDCP_SUCCESS(result) )
+ result = TmpBuffer.Capacity(file_size);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Parser.OpenReadFrame((*m_CurrentFile).c_str(), TmpBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Parser.FillPictureDescriptor(m_PDesc);
+
+ // how big is it?
+ if ( ASDCP_SUCCESS(result) )
+ m_PDesc.ContainerDuration = m_FileList.size();
+ }
+
+ return result;
+}
+
+//
+//
+ASDCP::Result_t
+ASDCP::JP2K::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::JP2K::SequenceParser::SequenceParser()
+{
+}
+
+ASDCP::JP2K::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::JP2K::SequenceParser::OpenRead(const char* filename, bool pedantic) const
+{
+ const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser = new h__SequenceParser;
+
+ Result_t result = m_Parser->OpenRead(filename);
+
+ if ( ASDCP_FAILURE(result) )
+ const_cast<ASDCP::JP2K::SequenceParser*>(this)->m_Parser.release();
+
+ return result;
+}
+
+// Rewinds the stream to the beginning.
+ASDCP::Result_t
+ASDCP::JP2K::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::JP2K::SequenceParser::ReadFrame(FrameBuffer& FB) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ return m_Parser->ReadFrame(FB);
+}
+
+ASDCP::Result_t
+ASDCP::JP2K::SequenceParser::FillPictureDescriptor(PictureDescriptor& PDesc) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ PDesc = m_Parser->m_PDesc;
+ return RESULT_OK;
+}
+
+
+//
+// end JP2K_Sequence_Parser.cpp
+//
diff --git a/src/KLV.cpp b/src/KLV.cpp
new file mode 100755
index 0000000..b57e805
--- /dev/null
+++ b/src/KLV.cpp
@@ -0,0 +1,270 @@
+/*
+Copyright (c) 2005, 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.
+*/
+
+//
+// KLV.cpp
+//
+
+#include "KLV.h"
+#include <hex_utils.h>
+
+
+// This is how much we read when we're reading from a file and we don't know
+// how long the packet is. This gives us the K (16 bytes) and L (4-9 bytes)
+// and the remaining bytes for an even read (tmp_read_size % 16 == 0)
+const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH;
+const ui32_t tmp_read_size = 32;
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::KLVPacket::InitFromBuffer(const byte_t* buf, ui32_t buf_len, const byte_t* label)
+{
+ Result_t result = KLVPacket::InitFromBuffer(buf, buf_len);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = ( memcmp(m_KeyStart, label, SMPTE_UL_LENGTH) == 0 ) ?
+ RESULT_OK : RESULT_FAIL;
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::KLVPacket::InitFromBuffer(const byte_t* buf, ui32_t buf_len)
+{
+ m_KeyStart = m_ValueStart = 0;
+ m_KLLength = m_ValueLength = 0;
+
+ if ( memcmp(buf, SMPTE_UL_START, 4) != 0 )
+ {
+ DefaultLogSink().Error("Unexpected UL preamble: %02x.%02x.%02x.%02x\n",
+ buf[0], buf[1], buf[2], buf[3]);
+ return RESULT_FAIL;
+ }
+
+ ui64_t tmp_size;
+ if ( ! read_BER(buf + SMPTE_UL_LENGTH, &tmp_size) )
+ return RESULT_FAIL;
+
+ m_ValueLength = tmp_size;
+ m_KLLength = SMPTE_UL_LENGTH + BER_length(buf + SMPTE_UL_LENGTH);
+ m_KeyStart = buf;
+ m_ValueStart = buf + m_KLLength;
+ return RESULT_OK;
+}
+
+//
+bool
+ASDCP::KLVPacket::HasUL(const byte_t* ul)
+{
+ if ( m_KeyStart == 0 )
+ return false;
+
+ return ( memcmp(ul, m_KeyStart, SMPTE_UL_LENGTH) == 0 ) ? true : false;
+}
+
+//
+ASDCP::Result_t
+ASDCP::KLVPacket::WriteKLToBuffer(ASDCP::FrameBuffer& Buffer, const byte_t* label, ui32_t length)
+{
+ if ( Buffer.Size() + kl_length > Buffer.Capacity() )
+ {
+ DefaultLogSink().Error("Small write buffer\n");
+ return RESULT_FAIL;
+ }
+
+ memcpy(Buffer.Data() + Buffer.Size(), label, SMPTE_UL_LENGTH);
+
+ if ( ! write_BER(Buffer.Data() + Buffer.Size() + SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) )
+ return RESULT_FAIL;
+
+ Buffer.Size(Buffer.Size() + kl_length);
+ return RESULT_OK;
+}
+
+//
+void
+ASDCP::KLVPacket::Dump(FILE* stream, bool show_hex)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ if ( m_KeyStart != 0 )
+ {
+ assert(m_ValueStart);
+
+ for ( ui32_t i = 0; i < SMPTE_UL_LENGTH; i++ )
+ fprintf(stream, "%02x.", m_KeyStart[i]);
+
+ const MDDEntry* Entry = GetMDDEntry(m_KeyStart);
+ fprintf(stream, "\b len: %7lu (%s)\n", m_ValueLength, (Entry ? Entry->name : "Unknown"));
+
+ if ( show_hex && m_ValueLength < 1000 )
+ hexdump(m_ValueStart, ASDCP::xmin(m_ValueLength, (ui32_t)64), stream);
+ }
+ else
+ {
+ fprintf(stream, "*** Malformed packet ***\n");
+ }
+}
+
+//
+ASDCP::Result_t
+ASDCP::KLVFilePacket::InitFromFile(const FileReader& Reader, const byte_t* label)
+{
+ Result_t result = KLVFilePacket::InitFromFile(Reader);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = ( memcmp(m_KeyStart, label, SMPTE_UL_LENGTH) == 0 ) ?
+ RESULT_OK : RESULT_FAIL;
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::KLVFilePacket::InitFromFile(const FileReader& Reader)
+{
+ ui32_t read_count;
+ byte_t tmp_data[tmp_read_size];
+ ui64_t tmp_size;
+ m_KeyStart = m_ValueStart = 0;
+ m_KLLength = m_ValueLength = 0;
+ m_Buffer.Size(0);
+
+ Result_t result = Reader.Read(tmp_data, tmp_read_size, &read_count);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ if ( read_count < (SMPTE_UL_LENGTH + 1) )
+ {
+ DefaultLogSink().Error("Short read of Key and Length got %lu\n", read_count);
+ return RESULT_READFAIL;
+ }
+
+ if ( memcmp(tmp_data, SMPTE_UL_START, 4) != 0 )
+ {
+ DefaultLogSink().Error("Unexpected UL preamble: %02x.%02x.%02x.%02x\n",
+ tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]);
+ return RESULT_FAIL;
+ }
+
+ if ( ! read_BER(tmp_data + SMPTE_UL_LENGTH, &tmp_size) )
+ {
+ DefaultLogSink().Error("BER Length decoding error\n");
+ return RESULT_FAIL;
+ }
+
+ if ( tmp_size > MAX_KLV_PACKET_LENGTH )
+ {
+ char intbuf[IntBufferLen];
+ DefaultLogSink().Error("Packet length %s exceeds internal limit\n",
+ ui64sz(tmp_size, intbuf));
+ return RESULT_FAIL;
+ }
+
+ ui32_t remainder = 0;
+ ui32_t ber_len = BER_length(tmp_data + SMPTE_UL_LENGTH);
+ m_KLLength = SMPTE_UL_LENGTH + ber_len;
+ m_ValueLength = tmp_size;
+ ui32_t packet_length = m_ValueLength + m_KLLength;
+
+ result = m_Buffer.Capacity(packet_length);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ m_KeyStart = m_Buffer.Data();
+ m_ValueStart = m_Buffer.Data() + m_KLLength;
+ m_Buffer.Size(packet_length);
+
+ // is the whole packet in the tmp buf?
+ if ( packet_length <= tmp_read_size )
+ {
+ assert(packet_length <= read_count);
+ memcpy(m_Buffer.Data(), tmp_data, packet_length);
+
+ if ( (remainder = read_count - packet_length) != 0 )
+ {
+ DefaultLogSink().Warn("Repositioning pointer for short packet\n");
+ ASDCP::fpos_t pos = Reader.Tell();
+ assert(pos > remainder);
+ result = Reader.Seek(pos - remainder);
+ }
+ }
+ else
+ {
+ if ( read_count < tmp_read_size )
+ {
+ DefaultLogSink().Error("Short read of packet body, expecting %lu, got %lu\n",
+ m_Buffer.Size(), read_count);
+ return RESULT_READFAIL;
+ }
+
+ memcpy(m_Buffer.Data(), tmp_data, tmp_read_size);
+ remainder = m_Buffer.Size() - tmp_read_size;
+
+ if ( remainder > 0 )
+ {
+ result = Reader.Read(m_Buffer.Data() + tmp_read_size, remainder, &read_count);
+
+ if ( read_count != remainder )
+ {
+ DefaultLogSink().Error("Short read of packet body, expecting %lu, got %lu\n",
+ remainder+tmp_read_size, read_count+tmp_read_size);
+ result = RESULT_READFAIL;
+ }
+ }
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::KLVFilePacket::WriteKLToFile(FileWriter& Writer, const byte_t* label, ui32_t length)
+{
+ byte_t buffer[kl_length];
+ memcpy(buffer, label, SMPTE_UL_LENGTH);
+
+ if ( ! write_BER(buffer+SMPTE_UL_LENGTH, length, MXF_BER_LENGTH) )
+ return RESULT_FAIL;
+
+ ui32_t write_count;
+ Writer.Write(buffer, kl_length, &write_count);
+ assert(write_count == kl_length);
+ return RESULT_OK;
+}
+
+
+//
+// end KLV.cpp
+//
diff --git a/src/KLV.h b/src/KLV.h
new file mode 100755
index 0000000..587bbe8
--- /dev/null
+++ b/src/KLV.h
@@ -0,0 +1,151 @@
+/*
+Copyright (c) 2005, 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.
+*/
+
+
+#ifndef _KLV_H_
+#define _KLV_H_
+
+#include <FileIO.h>
+#include <MemIO.h>
+
+namespace ASDCP
+{
+ const ui32_t MXF_BER_LENGTH = 4;
+ const ui32_t MXF_TAG_LENGTH = 2;
+ const ui32_t SMPTE_UL_LENGTH = 16;
+ const ui32_t SMPTE_UMID_LENGTH = 32;
+ const byte_t SMPTE_UL_START[4] = { 0x06, 0x0e, 0x2b, 0x34 };
+ const ui32_t MAX_KLV_PACKET_LENGTH = 1024*1024*64;
+
+ const ui32_t IdentBufferLen = 128;
+
+ struct TagValue
+ {
+ byte_t a;
+ byte_t b;
+
+ inline bool operator<(const TagValue& rhs) const {
+ if ( a < rhs.a ) return true;
+ if ( a == rhs.a && b < rhs.b ) return true;
+ return false;
+ }
+
+ inline bool operator==(const TagValue& rhs) const {
+ if ( a != rhs.a ) return false;
+ if ( b != rhs.b ) return false;
+ return true;
+ }
+ };
+
+ //
+ class IArchive
+ {
+ public:
+ virtual ~IArchive() {}
+ virtual Result_t ReadFrom(ASDCP::MemIOReader& Reader) = 0;
+ virtual Result_t WriteTo(ASDCP::MemIOWriter& Writer) = 0;
+ };
+} // namespace ASDCP
+
+#include "Identifier.h"
+
+namespace ASDCP
+{
+ //
+ class IPrimerLookup
+ {
+ public:
+ virtual ~IPrimerLookup() {}
+ virtual void ClearTagList() = 0;
+ virtual Result_t InsertTag(const ASDCP::UL& Key, ASDCP::TagValue& Tag) = 0;
+ virtual Result_t TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag) = 0;
+ };
+
+ //
+ struct MDDEntry
+ {
+ byte_t ul[SMPTE_UL_LENGTH];
+ TagValue tag;
+ bool optional;
+ const char* name;
+ const char* detail;
+ };
+
+ //
+ const MDDEntry* GetMDDEntry(const byte_t*);
+
+ //
+ class KLVPacket
+ {
+ ASDCP_NO_COPY_CONSTRUCT(KLVPacket);
+
+ protected:
+ const byte_t* m_KeyStart;
+ ui32_t m_KLLength;
+ const byte_t* m_ValueStart;
+ ui32_t m_ValueLength;
+
+ public:
+ KLVPacket() : m_KeyStart(0), m_KLLength(0), m_ValueStart(0), m_ValueLength(0) {}
+ virtual ~KLVPacket() {}
+
+ ui32_t PacketLength() {
+ return m_KLLength + m_ValueLength;
+ }
+
+ virtual bool HasUL(const byte_t*);
+ virtual Result_t InitFromBuffer(const byte_t*, ui32_t);
+ virtual Result_t InitFromBuffer(const byte_t*, ui32_t, const byte_t* label);
+ virtual Result_t WriteKLToBuffer(ASDCP::FrameBuffer&, const byte_t* label, ui32_t length);
+ virtual void Dump(FILE*, bool);
+ };
+
+ //
+ class KLVFilePacket : public KLVPacket
+ {
+ ASDCP_NO_COPY_CONSTRUCT(KLVFilePacket);
+
+ protected:
+ ASDCP::FrameBuffer m_Buffer;
+
+ public:
+ KLVFilePacket() {}
+ virtual ~KLVFilePacket() {}
+
+ virtual Result_t InitFromFile(const FileReader&);
+ virtual Result_t InitFromFile(const FileReader&, const byte_t* label);
+ virtual Result_t WriteKLToFile(FileWriter& Writer, const byte_t* label, ui32_t length);
+ };
+
+} // namespace ASDCP
+
+#endif // _KLV_H_
+
+
+//
+// end KLV.h
+//
diff --git a/src/MDD.h b/src/MDD.h
new file mode 100755
index 0000000..493e30d
--- /dev/null
+++ b/src/MDD.h
@@ -0,0 +1,1249 @@
+//
+// MDD.h
+//
+
+#ifndef _MDD_H_
+#define _MDD_H_
+#include <KLV.h>
+
+const ASDCP::MDDEntry s_MDD_Table[] = {
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01,
+ 0x0d, 0x01, 0x03, 0x01, 0x15, 0x01, 0x08, 0x01 }, {0}, true, "JPEG2000Essence", // 0
+ "JPEG 2000 Compressed Picture Essence Descriptor" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01,
+ 0x0d, 0x01, 0x03, 0x01, 0x15, 0x01, 0x05, 0x00 }, {0}, true, "MPEG2Essence", // 1
+ "MPEG-2 Compressed Picture Essence Descriptor" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01,
+ 0x0d, 0x01, 0x03, 0x01, 0x16, 0x01, 0x01, 0x00 }, {0}, true, "WAVEssence", // 2
+ "PCM Audio Essence Descriptor" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x04, 0x01, 0x07,
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x7e, 0x01, 0x00 }, {0}, true, "EKLVPacket", // 3
+ "Encrypted Essence Container Descriptor" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x03, 0x01, 0x02, 0x10, 0x01, 0x00, 0x00, 0x00 }, {0}, false, "KLVFill", // 4
+ "KLV Filler packet" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x03, 0x01, 0x02, 0x01, 0x06, 0x00, 0x00, 0x00 }, {0}, false, "PartitionMetadata_MajorVersion", // 5
+ "Major Version number of MXF byte-level format (non-backwards compatible version number)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x03, 0x01, 0x02, 0x01, 0x07, 0x00, 0x00, 0x00 }, {0}, false, "PartitionMetadata_MinorVersion", // 6
+ "Minor Version number of MXF byte-level format (backwards compatible version number)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x03, 0x01, 0x02, 0x01, 0x09, 0x00, 0x00, 0x00 }, {0}, false, "PartitionMetadata_KAGSize", // 7
+ "Size of the KLV Alignment Grid (KAG) for this partition, in bytes" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x06, 0x10, 0x10, 0x03, 0x01, 0x00, 0x00, 0x00 }, {0}, false, "PartitionMetadata_ThisPartition", // 8
+ "Byte offset of the start of This Partition, relative to the start of the Header Partition" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x06, 0x10, 0x10, 0x02, 0x01, 0x00, 0x00, 0x00 }, {0}, false, "PartitionMetadata_PreviousPartition", // 9
+ "Byte offset of the start of the Previous Partition, relative to the start of the Header Partition" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x06, 0x10, 0x10, 0x05, 0x01, 0x00, 0x00, 0x00 }, {0}, false, "PartitionMetadata_FooterPartition", // 10
+ "Byte offset of the start of the Footer Partition, relative to the start of the Header Partition" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x06, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00 }, {0}, false, "PartitionMetadata_HeaderByteCount", // 11
+ "Count of Bytes used for Header Metadata. This starts at the byte following the Partition pack and includes any trailing filler which is part of the Header Metadata." },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x06, 0x09, 0x02, 0x00, 0x00, 0x00, 0x00 }, {0}, false, "PartitionMetadata_IndexByteCount", // 12
+ "Count of Bytes used for Index Table Segments. This starts at the byte following the Header Metadata and includes any trailing filler which is part of the Index Table." },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x01, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00 }, {0}, false, "PartitionMetadata_IndexSID", // 13
+ "Index Table Segment Identifier in this partition. The value 0 defines that there are no Index Table segments in this partition." },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x06, 0x08, 0x01, 0x02, 0x01, 0x03, 0x00, 0x00 }, {0}, false, "PartitionMetadata_BodyOffset", // 14
+ "Byte offset of the first byte in the following Essence Container data relative to the start of the Essence Container identified by this BodySID" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 }, {0}, false, "PartitionMetadata_BodySID", // 15
+ "Identifier of the Essence Container data found in this partition. The value 0 indicates there is no Essence Container data in this partition." },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x01, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00 }, {0}, false, "PartitionMetadata_OperationalPattern", // 16
+ "Universal Label of the Operational Pattern to which this file complies" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x01, 0x02, 0x02, 0x10, 0x02, 0x01, 0x00, 0x00 }, {0}, false, "PartitionMetadata_EssenceContainers", // 17
+ "The unordered batch of Universal Labels of Essence Containers used in or referenced by this file" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x00 }, {0}, false, "OpenHeader", // 18
+ "Open Header Partition Pack" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x02, 0x03, 0x00 }, {0}, false, "OpenCompleteHeader", // 19
+ "Open Complete Header Partition Pack" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x00 }, {0}, false, "ClosedHeader", // 20
+ "Closed Header Partition Pack" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, 0x00 }, {0}, false, "ClosedCompleteHeader", // 21
+ "Closed Complete Header Partition Pack" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x03, 0x01, 0x00 }, {0}, false, "OpenBodyPartition", // 22
+ "Open Body Partition Pack" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x03, 0x03, 0x00 }, {0}, false, "OpenCompleteBodyPartition", // 23
+ "Open Complete Body Partition Pack" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x03, 0x02, 0x00 }, {0}, false, "ClosedBodyPartition", // 24
+ "Closed Body Partition Pack" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x03, 0x04, 0x00 }, {0}, false, "ClosedCompleteBodyPartition", // 25
+ "Closed Complete Body Partition Pack" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x00 }, {0}, false, "Footer", // 26
+ "Footer Partition Pack" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x04, 0x04, 0x00 }, {0}, false, "CompleteFooter", // 27
+ "Complete Footer Partition Pack" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x05, 0x01, 0x00 }, {0}, false, "Primer", // 28
+ "Primer Pack" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x06, 0x01, 0x01, 0x07, 0x15, 0x00, 0x00, 0x00 }, {0}, false, "Primer_LocalTagEntryBatch", // 29
+ "Local Tag Entry Batch" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x01, 0x03, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00 }, {0}, false, "LocalTagEntryBatch_Primer_LocalTag", // 30
+ "The value of the Local Tag" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x01, 0x03, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00 }, {0}, false, "LocalTagEntryBatch_Primer_UID", // 31
+ "The UID of which the local tag is an alias" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x15, 0x02, 0x00, 0x00, 0x00, 0x00 }, {0x3c, 0x0a}, false, "InterchangeObject_InstanceUID", // 32
+ "Unique ID of this instance" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x07, 0x01, 0x08, 0x00, 0x00, 0x00 }, {0x01, 0x02}, true, "GenerationInterchangeObject_GenerationUID", // 33
+ "Generation Instance" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, {0}, false, "DefaultObject", // 34
+ "" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x05, 0x30, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00 }, {0x3f, 0x0b}, false, "IndexTableSegmentBase_IndexEditRate", // 35
+ "Edit Rate copied from the tracks of the Essence Container" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x07, 0x02, 0x01, 0x03, 0x01, 0x0a, 0x00, 0x00 }, {0x3f, 0x0c}, false, "IndexTableSegmentBase_IndexStartPosition", // 36
+ "The first editable unit indexed by this Index Table segment measured in File Package Edit Units" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x07, 0x02, 0x02, 0x01, 0x01, 0x02, 0x00, 0x00 }, {0x3f, 0x0d}, false, "IndexTableSegmentBase_IndexDuration", // 37
+ "Time duration of this table segment measured in Edit Unitsof the referenceg package" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x06, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00 }, {0x3f, 0x05}, false, "IndexTableSegmentBase_EditUnitByteCount", // 38
+ "Byte count of each and every Edit Unit. A value of 0 defines the byte count of Edit Units is only given in the Index Entry Array" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x01, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00 }, {0x3f, 0x06}, false, "IndexTableSegmentBase_IndexSID", // 39
+ "Stream Identifier (SID) of Index Stream" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 }, {0x3f, 0x07}, false, "IndexTableSegmentBase_BodySID", // 40
+ "Stream Identifier (SID) of Essence Container Stream" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x04, 0x04, 0x01, 0x01, 0x00, 0x00, 0x00 }, {0x3f, 0x08}, false, "IndexTableSegmentBase_SliceCount", // 41
+ "Number of slices minus 1 (NSL)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x04, 0x04, 0x01, 0x07, 0x00, 0x00, 0x00 }, {0x3f, 0x0e}, true, "IndexTableSegmentBase_PosTableCount", // 42
+ "Number of PosTable Entries minus 1 (NPE)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x10, 0x01, 0x00 }, {0}, false, "IndexTableSegment", // 43
+ "A segment of an Index Table" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x04, 0x04, 0x01, 0x06, 0x00, 0x00, 0x00 }, {0x3f, 0x09}, true, "IndexTableSegment_DeltaEntryArray", // 44
+ "Map Elements onto Slices" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x04, 0x04, 0x01, 0x04, 0x00, 0x00, 0x00 }, {0}, false, "DeltaEntryArray_IndexTableSegment_PosTableIndex", // 45
+ "Index into PosTable (or Apply Temporta Reordering if -1)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x04, 0x04, 0x01, 0x02, 0x00, 0x00, 0x00 }, {0}, false, "DeltaEntryArray_IndexTableSegment_Slice", // 46
+ "Slice number in IndexEntry" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x04, 0x04, 0x01, 0x03, 0x00, 0x00, 0x00 }, {0}, false, "DeltaEntryArray_IndexTableSegment_ElementDelta", // 47
+ "Delta from start of slice to this Element" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x04, 0x04, 0x02, 0x05, 0x00, 0x00, 0x00 }, {0x3f, 0x0a}, false, "IndexTableSegment_IndexEntryArray", // 48
+ "Index from Edit Unit number to stream offset" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x04, 0x04, 0x02, 0x03, 0x00, 0x00, 0x00 }, {0}, false, "IndexEntryArray_IndexTableSegment_TemporalOffset", // 49
+ "Offset in edit units from Display Order to Coded Order" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x04, 0x04, 0x02, 0x04, 0x00, 0x00, 0x00 }, {0}, false, "IndexEntryArray_IndexTableSegment_AnchorOffset", // 50
+ "Offset in edit units to previous Anchor Frame. The value is zero if this is an anchor frame." },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00 }, {0}, false, "IndexEntryArray_IndexTableSegment_Flags", // 51
+ "Flags for this Edit Unit" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00 }, {0}, false, "IndexEntryArray_IndexTableSegment_StreamOffset", // 52
+ "Offset in bytes from the first KLV element in this Edit Unit within the Essence Container" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x04, 0x04, 0x01, 0x05, 0x00, 0x00, 0x00 }, {0}, false, "IndexEntryArray_IndexTableSegment_SliceOffsetArray", // 53
+ "Array of offsets in bytes from the Stream Offset to the start of each slice." },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x04, 0x04, 0x01, 0x08, 0x00, 0x00, 0x00 }, {0}, false, "IndexEntryArray_IndexTableSegment_PosTableArray", // 54
+ "Array of fractional position offsets from the start of the content package to the synchronized sample in the Content Package" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01,
+ 0x0d, 0x01, 0x02, 0x01, 0x01, 0x11, 0x01, 0x00 }, {0}, false, "RandomIndexMetadata", // 55
+ "Random Index Pack" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 }, {0}, false, "PartitionArray_RandomIndexMetadata_BodySID", // 56
+ "Stream ID of the Body in this partition" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x06, 0x09, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00 }, {0}, false, "PartitionArray_RandomIndexMetadata_ByteOffset", // 57
+ "Byte offset from file start (1st byte of the file which is numbered 0) to the 1st byte of the Partition Pack Key" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x06, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00 }, {0}, false, "RandomIndexMetadata_Length", // 58
+ "Overall Length of this Pack including the Set Key and BER Length fields" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2f, 0x00 }, {0}, false, "Preface", // 59
+ "Preface Set" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x01, 0x10, 0x02, 0x04, 0x00, 0x00 }, {0x3b, 0x02}, false, "Preface_LastModifiedDate", // 60
+ "Date &amp; time of the last modification of the file" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x03, 0x01, 0x02, 0x01, 0x05, 0x00, 0x00, 0x00 }, {0x3b, 0x05}, false, "Preface_Version", // 61
+ "The value shall be 258 (i.e. v1.2)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x03, 0x01, 0x02, 0x01, 0x04, 0x00, 0x00, 0x00 }, {0x3b, 0x07}, true, "Preface_ObjectModelVersion", // 62
+ "Simple integer version number of Object Model" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x06, 0x01, 0x01, 0x04, 0x01, 0x08, 0x00, 0x00 }, {0x3b, 0x08}, true, "Preface_PrimaryPackage", // 63
+ "The primary Package in this file" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x04, 0x00, 0x00 }, {0x3b, 0x06}, false, "Preface_Identifications", // 64
+ "Ordered array of strong references to Identification sets recording all modifications to the file" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x02, 0x01, 0x00, 0x00 }, {0x3b, 0x03}, false, "Preface_ContentStorage", // 65
+ "Strong reference to Content Storage object" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x01, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00 }, {0x3b, 0x09}, false, "Preface_OperationalPattern", // 66
+ "Universal Label of the Operational Pattern which this file complies to (repeat of Partition Pack value)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x01, 0x02, 0x02, 0x10, 0x02, 0x01, 0x00, 0x00 }, {0x3b, 0x0a}, false, "Preface_EssenceContainers", // 67
+ "Unordered batch of ULs of Essence Containers used in or referenced by this file (repeat of Partition Pack value)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x01, 0x02, 0x02, 0x10, 0x02, 0x02, 0x00, 0x00 }, {0x3b, 0x0b}, false, "Preface_DMSchemes", // 68
+ "An unordered batch of Universal Labels of all the Descriptive Metadata schemes used in this file" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x00 }, {0}, false, "Identification", // 69
+ "Identification set" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00 }, {0x3c, 0x09}, false, "Identification_ThisGenerationUID", // 70
+ "This Generation Identifier" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x07, 0x01, 0x02, 0x01, 0x00, 0x00 }, {0x3c, 0x01}, false, "Identification_CompanyName", // 71
+ "Manufacturer of the equipment or application that created or modified the file" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x07, 0x01, 0x03, 0x01, 0x00, 0x00 }, {0x3c, 0x02}, false, "Identification_ProductName", // 72
+ "Name of the application which created or modified this file" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x07, 0x01, 0x04, 0x00, 0x00, 0x00 }, {0x3c, 0x03}, true, "Identification_ProductVersion", // 73
+ "Maj.min.tweak.build.rel version number of this application" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x07, 0x01, 0x05, 0x01, 0x00, 0x00 }, {0x3c, 0x04}, false, "Identification_VersionString", // 74
+ "Human readable name of the application version" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x07, 0x01, 0x07, 0x00, 0x00, 0x00 }, {0x3c, 0x05}, false, "Identification_ProductUID", // 75
+ "A unique identification for the product which created this file (defined by the manufacturer)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x01, 0x10, 0x02, 0x03, 0x00, 0x00 }, {0x3c, 0x06}, false, "Identification_ModificationDate", // 76
+ "Time &amp; date an application created or modified this file and created this Identification set" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x07, 0x01, 0x0a, 0x00, 0x00, 0x00 }, {0x3c, 0x07}, true, "Identification_ToolkitVersion", // 77
+ "Maj.min.tweak.build.rel version of software or hardware codec used" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x07, 0x01, 0x06, 0x01, 0x00, 0x00 }, {0x3c, 0x08}, true, "Identification_Platform", // 78
+ "Human readable name of the operating system used." },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, 0x00 }, {0}, false, "ContentStorage", // 79
+ "Content Storage set" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x05, 0x01, 0x00, 0x00 }, {0x19, 0x01}, false, "ContentStorage_Packages", // 80
+ "Unordered batch of all packages used in this file" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x05, 0x02, 0x00, 0x00 }, {0x19, 0x02}, true, "ContentStorage_EssenceContainerData", // 81
+ "Unordered batch of strong references to Essence Container Data sets used in this file" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x23, 0x00 }, {0}, false, "EssenceContainerData", // 82
+ "Essence Container Data set" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00 }, {0x27, 0x01}, false, "EssenceContainerData_LinkedPackageUID", // 83
+ "Identifier of the Package to which this set is linked as a UMID" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x01, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00 }, {0x3f, 0x06}, true, "EssenceContainerData_IndexSID", // 84
+ "ID of the Index Table for the Essence Container to which this set is linked" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x01, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 }, {0x3f, 0x07}, false, "EssenceContainerData_BodySID", // 85
+ "ID of the Essence Container to which this set is linked" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x15, 0x10, 0x00, 0x00, 0x00, 0x00 }, {0x44, 0x01}, false, "GenericPackage_PackageUID", // 86
+ "Unique Package Identifier as a UMID" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x03, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00 }, {0x44, 0x02}, true, "GenericPackage_Name", // 87
+ "Human readable package name" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x01, 0x10, 0x01, 0x03, 0x00, 0x00 }, {0x44, 0x05}, false, "GenericPackage_PackageCreationDate", // 88
+ "The date &amp; time of creation of this package" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x01, 0x10, 0x02, 0x05, 0x00, 0x00 }, {0x44, 0x04}, false, "GenericPackage_PackageModifiedDate", // 89
+ "The date &amp; time of last modification of this package" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x05, 0x00, 0x00 }, {0x44, 0x03}, false, "GenericPackage_Tracks", // 90
+ "Array of Unique IDs of Tracks" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x32, 0x00 }, {0}, false, "NetworkLocator", // 91
+ "Network Locator set for location with a URL" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00 }, {0x40, 0x01}, false, "NetworkLocator_URLString", // 92
+ "A URL indicating where the essence may be found." },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x33, 0x00 }, {0}, false, "TextLocator", // 93
+ "Text Locator set for location with a human-readable text string" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x01, 0x04, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00 }, {0x41, 0x01}, false, "TextLocator_LocatorName", // 94
+ "Value of a human-readable locator text string for manual location of essence" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x01, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }, {0x48, 0x01}, false, "GenericTrack_TrackID", // 95
+ "ID of the track in this package (for linking to a SourceTrackID in a segment)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x01, 0x04, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00 }, {0x48, 0x04}, false, "GenericTrack_TrackNumber", // 96
+ "Number used to link to the track in the Essence Container if it exists" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x01, 0x07, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00 }, {0x48, 0x02}, true, "GenericTrack_TrackName", // 97
+ "Human readable name of the track type" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x02, 0x04, 0x00, 0x00 }, {0x48, 0x03}, false, "GenericTrack_Sequence", // 98
+ "Strong Reference to Sequence Set" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x3a, 0x00 }, {0}, false, "StaticTrack", // 99
+ "" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x3b, 0x00 }, {0}, false, "Track", // 100
+ "Track" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x30, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00 }, {0x4b, 0x01}, false, "Track_EditRate", // 101
+ "Edit Rate of Track" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x00 }, {0x4b, 0x02}, false, "Track_Origin", // 102
+ "An Offset used to resolved timeline references to this track. The start of the track has this timeline value measured in Edit Units." },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x39, 0x00 }, {0}, false, "EventTrack", // 103
+ "Event Track" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x30, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00 }, {0x49, 0x01}, false, "EventTrack_EventEditRate", // 104
+ "Edit Rate of Event Track" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x07, 0x02, 0x01, 0x03, 0x01, 0x0b, 0x00, 0x00 }, {0x49, 0x02}, true, "EventTrack_EventOrigin", // 105
+ "An Offset used to resolved timeline references to this event track. The start of the event track has this timeline value measured in Edit Units." },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }, {0x02, 0x01}, false, "StructuralComponent_DataDefinition", // 106
+ "Data Definition - kind of data or metadata this structure refers to" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x02, 0x01, 0x01, 0x03, 0x00, 0x00 }, {0x02, 0x02}, false, "StructuralComponent_Duration", // 107
+ "Duration (in units of edit rate)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0f, 0x00 }, {0}, false, "Sequence", // 108
+ "Sequence" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x09, 0x00, 0x00 }, {0x10, 0x01}, false, "Sequence_StructuralComponents", // 109
+ "Ordered array of strong references to Structural Components" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x14, 0x00 }, {0}, false, "TimecodeComponent", // 110
+ "Timecode Component" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x04, 0x01, 0x01, 0x02, 0x06, 0x00, 0x00 }, {0x15, 0x02}, false, "TimecodeComponent_RoundedTimecodeBase", // 111
+ "Integer frames per second" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x01, 0x03, 0x01, 0x05, 0x00, 0x00 }, {0x15, 0x01}, false, "TimecodeComponent_StartTimecode", // 112
+ "Starting timecode" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x04, 0x01, 0x01, 0x05, 0x00, 0x00, 0x00 }, {0x15, 0x03}, false, "TimecodeComponent_DropFrame", // 113
+ "Drop frame flag" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x00 }, {0}, false, "SourceClip", // 114
+ "Source Clip" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x01, 0x03, 0x01, 0x04, 0x00, 0x00 }, {0x12, 0x01}, false, "SourceClip_StartPosition", // 115
+ "Offset into Essence measured in edit units of the track containing this segment" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00 }, {0x11, 0x01}, false, "SourceClip_SourcePackageID", // 116
+ "ID of referenced Package as a UMID" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x03, 0x02, 0x00, 0x00, 0x00 }, {0x11, 0x02}, false, "SourceClip_SourceTrackID", // 117
+ "Track ID of the referenced Track within the referenced Package" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x41, 0x00 }, {0}, false, "DMSegment", // 118
+ "Descriptive Metadata Segment" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x07, 0x02, 0x01, 0x03, 0x03, 0x03, 0x00, 0x00 }, {0x06, 0x01}, false, "DMSegment_EventStartPosition", // 119
+ "Offset into the descriptive metadata track in edit units" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x30, 0x04, 0x04, 0x01, 0x00, 0x00, 0x00 }, {0x06, 0x02}, true, "DMSegment_EventComment", // 120
+ "Description of the Descriptive Metadata Framework" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x01, 0x07, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00 }, {0x61, 0x02}, false, "DMSegment_TrackIDs", // 121
+ "An unordered list of track ID values that identify the tracks in this Package to which this DM Framework refers (if omitted, refers to all essence tracks)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x06, 0x01, 0x01, 0x04, 0x02, 0x0c, 0x00, 0x00 }, {0x61, 0x01}, false, "DMSegment_DMFramework", // 122
+ "Strong Reference to the Descriptive Metadata Framework" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x45, 0x00 }, {0}, false, "DMSourceClip", // 123
+ "Descriptive Metadata SourceClip" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x01, 0x07, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00 }, {0x61, 0x03}, true, "DMSourceClip_DMSourceClipTrackIDs", // 124
+ "An unordered list of track ID values that identify the tracks in this Package to which the referenced Descriptive Metadata refers (if omitted, refers to all essence tracks)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x36, 0x00 }, {0}, false, "MaterialPackage", // 125
+ "Material Package set" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x37, 0x00 }, {0}, false, "SourcePackage", // 126
+ "File Package set" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x02, 0x03, 0x00, 0x00 }, {0x47, 0x01}, false, "SourcePackage_Descriptor", // 127
+ "Strong Reference to the Descriptor" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x03, 0x00, 0x00 }, {0x2f, 0x01}, true, "GenericDescriptor_Locators", // 128
+ "Ordered array of strong references to Locator sets" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x10, 0x00, 0x00 }, {0}, true, "GenericDescriptor_SubDescriptors", // 129
+ "Ordered array of strong references to sub descriptor sets" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x25, 0x00 }, {0}, false, "FileDescriptor", // 130
+ "File Descriptor" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x06, 0x01, 0x01, 0x03, 0x05, 0x00, 0x00, 0x00 }, {0x30, 0x06}, true, "FileDescriptor_LinkedTrackID", // 131
+ "Link to (i.e. value of) the Track ID of the Track in this Package to which the Descriptor applies" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x06, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }, {0x30, 0x01}, false, "FileDescriptor_SampleRate", // 132
+ "The field or frame rate of the Essence Container (not the essence sampling clock rate)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x06, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00 }, {0x30, 0x02}, true, "FileDescriptor_ContainerDuration", // 133
+ "Duration of Essence Container (measured in Edit Units)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x01, 0x02, 0x00, 0x00 }, {0x30, 0x04}, false, "FileDescriptor_EssenceContainer", // 134
+ "The UL identifying the Essence Container described by this Descriptor" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x06, 0x01, 0x01, 0x04, 0x01, 0x03, 0x00, 0x00 }, {0x30, 0x05}, true, "FileDescriptor_Codec", // 135
+ "UL to identify a codec compatible with this Essence Container" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x27, 0x00 }, {0}, false, "GenericPictureEssenceDescriptor", // 136
+ "Defines the Picture Essence Descriptor set" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x05, 0x01, 0x13, 0x00, 0x00, 0x00, 0x00 }, {0x32, 0x15}, true, "GenericPictureEssenceDescriptor_SignalStandard", // 137
+ "Underlying signal standard" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x03, 0x01, 0x04, 0x00, 0x00, 0x00 }, {0x32, 0x0c}, false, "GenericPictureEssenceDescriptor_FrameLayout", // 138
+ "Interlace or Progressive layout" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00 }, {0x32, 0x03}, false, "GenericPictureEssenceDescriptor_StoredWidth", // 139
+ "Horizontal Size of active picture" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x02, 0x01, 0x00, 0x00, 0x00 }, {0x32, 0x02}, false, "GenericPictureEssenceDescriptor_StoredHeight", // 140
+ "Vertical Field Size of active picture" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x03, 0x02, 0x08, 0x00, 0x00, 0x00 }, {0x32, 0x16}, true, "GenericPictureEssenceDescriptor_StoredF2Offset", // 141
+ "Topness Adjustment for stored picture" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x08, 0x00, 0x00, 0x00 }, {0x32, 0x05}, true, "GenericPictureEssenceDescriptor_SampledWidth", // 142
+ "Sampled width supplied to codec" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x07, 0x00, 0x00, 0x00 }, {0x32, 0x04}, true, "GenericPictureEssenceDescriptor_SampledHeight", // 143
+ "Sampled height supplied to codec" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x09, 0x00, 0x00, 0x00 }, {0x32, 0x06}, true, "GenericPictureEssenceDescriptor_SampledXOffset", // 144
+ "Offset from sampled to stored width" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x0a, 0x00, 0x00, 0x00 }, {0x32, 0x07}, true, "GenericPictureEssenceDescriptor_SampledYOffset", // 145
+ "Offset from sampled to stored" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x0b, 0x00, 0x00, 0x00 }, {0x32, 0x08}, true, "GenericPictureEssenceDescriptor_DisplayHeight", // 146
+ "Displayed Height placed in Production Aperture" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x0c, 0x00, 0x00, 0x00 }, {0x32, 0x09}, true, "GenericPictureEssenceDescriptor_DisplayWidth", // 147
+ "Displayed Width placed in Production Aperture" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x0d, 0x00, 0x00, 0x00 }, {0x32, 0x0a}, true, "GenericPictureEssenceDescriptor_DisplayXOffset", // 148
+ "The horizontal offset from the (in pixels) of the picture as displayed" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x0e, 0x00, 0x00, 0x00 }, {0x32, 0x0b}, true, "GenericPictureEssenceDescriptor_DisplayYOffset", // 149
+ "The vertical offset (in pixels) of the picture as displayed" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x03, 0x02, 0x07, 0x00, 0x00, 0x00 }, {0x32, 0x17}, true, "GenericPictureEssenceDescriptor_DisplayF2Offset", // 150
+ "Topness Adjustment for Displayed Picture" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00 }, {0x32, 0x0e}, false, "GenericPictureEssenceDescriptor_AspectRatio", // 151
+ "Specifies the horizontal to vertical aspect ratio of the whole image as it is to be presented to avoid geometric distortion (and hence including any black edges)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x03, 0x02, 0x09, 0x00, 0x00, 0x00 }, {0x32, 0x18}, true, "GenericPictureEssenceDescriptor_ActiveFormatDescriptor", // 152
+ "Specifies the intended framing of the content within the displayed image" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x03, 0x02, 0x05, 0x00, 0x00, 0x00 }, {0x32, 0x0d}, false, "GenericPictureEssenceDescriptor_VideoLineMap", // 153
+ "First active line in each field" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x05, 0x20, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00 }, {0x32, 0x0f}, true, "GenericPictureEssenceDescriptor_AlphaTransparency", // 154
+ "Is Alpha Inverted" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x00 }, {0x32, 0x10}, true, "GenericPictureEssenceDescriptor_Gamma", // 155
+ "Registered UL of known Gamma" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }, {0x32, 0x11}, true, "GenericPictureEssenceDescriptor_ImageAlignmentOffset", // 156
+ "Byte Boundary alignment required for Low Level Essence Storage" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x18, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00 }, {0x32, 0x13}, true, "GenericPictureEssenceDescriptor_ImageStartOffset", // 157
+ "Unused bytes before start of stored data" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x18, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00 }, {0x32, 0x14}, true, "GenericPictureEssenceDescriptor_ImageEndOffset", // 158
+ "Unused bytes before start of stored data" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x03, 0x01, 0x06, 0x00, 0x00, 0x00 }, {0x32, 0x12}, true, "GenericPictureEssenceDescriptor_FieldDominance", // 159
+ "The number of the field which is considered temporally to come first" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00 }, {0x32, 0x01}, false, "GenericPictureEssenceDescriptor_PictureEssenceCoding", // 160
+ "UL identifying the Picture Compression Scheme" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x28, 0x00 }, {0}, false, "CDCIEssenceDescriptor", // 161
+ "Defines the CDCI Picture Essence Descriptor set" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x05, 0x03, 0x0a, 0x00, 0x00, 0x00 }, {0x33, 0x01}, false, "CDCIEssenceDescriptor_ComponentDepth", // 162
+ "Number of active bits per sample (e.g. 8, 10, 16)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x05, 0x00, 0x00, 0x00 }, {0x33, 0x02}, false, "CDCIEssenceDescriptor_HorizontalSubsampling", // 163
+ "Specifies the H colour subsampling" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x05, 0x01, 0x10, 0x00, 0x00, 0x00 }, {0x33, 0x08}, true, "CDCIEssenceDescriptor_VerticalSubsampling", // 164
+ "Specifies the V colour subsampling" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x01, 0x06, 0x00, 0x00, 0x00 }, {0x33, 0x03}, true, "CDCIEssenceDescriptor_ColorSiting", // 165
+ "Enumerated value describing the color siting" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x03, 0x01, 0x02, 0x01, 0x0a, 0x00, 0x00, 0x00 }, {0x33, 0x0b}, true, "CDCIEssenceDescriptor_ReversedByteOrder", // 166
+ "a FALSE value denotes Chroma followed by Luma pexels according to ITU Rec. 601" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x18, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00 }, {0x33, 0x07}, true, "CDCIEssenceDescriptor_PaddingBits", // 167
+ "Bits to round up each pixel to stored size" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x05, 0x03, 0x07, 0x00, 0x00, 0x00 }, {0x33, 0x09}, true, "CDCIEssenceDescriptor_AlphaSampleDepth", // 168
+ "Number of bits per alpha sample" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x03, 0x03, 0x00, 0x00, 0x00 }, {0x33, 0x04}, true, "CDCIEssenceDescriptor_BlackRefLevel", // 169
+ "Black refernece level e.g. 16 or 64 (8 or 10-bits)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x05, 0x03, 0x04, 0x00, 0x00, 0x00 }, {0x33, 0x05}, true, "CDCIEssenceDescriptor_WhiteReflevel", // 170
+ "White reference level e.g. 235 or 943 (8 or 10 bits)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x05, 0x03, 0x05, 0x00, 0x00, 0x00 }, {0x33, 0x06}, true, "CDCIEssenceDescriptor_ColorRange", // 171
+ "Color range e.g. 225 or 897 (8 or 10 bits)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x29, 0x00 }, {0}, false, "RGBAEssenceDescriptor", // 172
+ "Defines the RGBA Picture Essence Descriptor set" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x05, 0x03, 0x0b, 0x00, 0x00, 0x00 }, {0x34, 0x06}, true, "RGBAEssenceDescriptor_ComponentMaxRef", // 173
+ "Maximum value for RGB components, e.g. 235 or 940 (8 or 10 bits)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x05, 0x03, 0x0c, 0x00, 0x00, 0x00 }, {0x34, 0x07}, true, "RGBAEssenceDescriptor_ComponentMinRef", // 174
+ "Minimum value for RGB components, e.g. 16 or 64 (8 or 10 bits)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x05, 0x03, 0x0d, 0x00, 0x00, 0x00 }, {0x34, 0x08}, true, "RGBAEssenceDescriptor_AlphaMaxRef", // 175
+ "Maximum value for alpha component, e.g. 235 or 940 (8 or 10 bits)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x05, 0x03, 0x0e, 0x00, 0x00, 0x00 }, {0x34, 0x09}, true, "RGBAEssenceDescriptor_AlphaMinRef", // 176
+ "Minimum value for alpha component, e.g. 16 or 64 (8 or 10 bits)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x04, 0x04, 0x01, 0x00, 0x00, 0x00 }, {0x34, 0x05}, true, "RGBAEssenceDescriptor_ScanningDirection", // 177
+ "Enumerated Scanning Direction" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x05, 0x03, 0x06, 0x00, 0x00, 0x00 }, {0x34, 0x01}, false, "RGBAEssenceDescriptor_PixelLayout", // 178
+ "Pixel Layout" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x05, 0x03, 0x08, 0x00, 0x00, 0x00 }, {0x34, 0x03}, true, "RGBAEssenceDescriptor_Palette", // 179
+ "Palette" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x01, 0x05, 0x03, 0x09, 0x00, 0x00, 0x00 }, {0x34, 0x04}, true, "RGBAEssenceDescriptor_PaletteLayout", // 180
+ "Palette Layout" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x42, 0x00 }, {0}, false, "GenericSoundEssenceDescriptor", // 181
+ "Defines the Sound Essence Descriptor set" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00 }, {0x3d, 0x03}, false, "GenericSoundEssenceDescriptor_AudioSamplingRate", // 182
+ "Sampling rate of the audio essence" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x02, 0x03, 0x01, 0x04, 0x00, 0x00, 0x00 }, {0x3d, 0x02}, false, "GenericSoundEssenceDescriptor_Locked", // 183
+ "Boolean indicating that the Number of samples per frame is locked or unlocked (non-0 = locked)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x02, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00 }, {0x3d, 0x04}, true, "GenericSoundEssenceDescriptor_AudioRefLevel", // 184
+ "Audio reference level which gives the number of dBm for 0VU" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00 }, {0x3d, 0x05}, true, "GenericSoundEssenceDescriptor_ElectroSpatialFormulation", // 185
+ "E.g. mono, dual mono, stereo, A,B etc (enum)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x01, 0x01, 0x04, 0x00, 0x00, 0x00 }, {0x3d, 0x07}, false, "GenericSoundEssenceDescriptor_ChannelCount", // 186
+ "Number of Sound Channels" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x04, 0x02, 0x03, 0x03, 0x04, 0x00, 0x00, 0x00 }, {0x3d, 0x01}, false, "GenericSoundEssenceDescriptor_QuantizationBits", // 187
+ "Number of quantization bits" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00 }, {0x3d, 0x0c}, true, "GenericSoundEssenceDescriptor_DialNorm", // 188
+ "Gain to be applied to normalise perceived loudness of the clip, defined by ATSC A/53 (1dB per step)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02,
+ 0x04, 0x02, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00 }, {0x3d, 0x06}, false, "GenericSoundEssenceDescriptor_SoundEssenceCompression", // 189
+ "UL identifying the Sound Compression Scheme" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x43, 0x00 }, {0}, false, "GenericDataEssenceDescriptor", // 190
+ "Defines the Data Essence Descriptor set" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x03, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00 }, {0x3e, 0x01}, false, "GenericDataEssenceDescriptor_DataEssenceCoding", // 191
+ "Specifies the data essence coding type" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x44, 0x00 }, {0}, false, "MultipleDescriptor", // 192
+ "Defines the Multiple Descriptor set" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04,
+ 0x06, 0x01, 0x01, 0x04, 0x06, 0x0b, 0x00, 0x00 }, {0x3f, 0x01}, false, "MultipleDescriptor_SubDescriptorUIDs", // 193
+ "Unordered array of strong references to File Descriptor sets (1 per interleaved item within the Essence Container)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x51, 0x00 }, {0}, false, "MPEG2VideoDescriptor", // 194
+ "Defines the MPEG2 Picture Essence Descriptor set" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x02, 0x00, 0x00 }, {0}, true, "MPEG2VideoDescriptor_SingleSequence", // 195
+ "TRUE if the essence consists of a single MPEG sequence. False if there are a number of sequences. This flag implies that the sequence header information is not varying in the essence stream." },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x03, 0x00, 0x00 }, {0}, true, "MPEG2VideoDescriptor_ConstantBFrames", // 196
+ "TRUE if the number of B frames is always constant" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x04, 0x00, 0x00 }, {0}, true, "MPEG2VideoDescriptor_CodedContentType", // 197
+ "0= &quot;Unknown&quot;,1= &quot;Progressive&quot;, 2= &quot;Interlaced&quot;, 3= &quot;Mixed&quot;: an enumerated value which tells if the underlying content which was MPEG coded was of a known type" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x05, 0x00, 0x00 }, {0}, true, "MPEG2VideoDescriptor_LowDelay", // 198
+ "TRUE if low delay mode was used in the sequence" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x06, 0x00, 0x00 }, {0}, true, "MPEG2VideoDescriptor_ClosedGOP", // 199
+ "TRUE if closed_gop is set in all GOP Headers, per 13818-1 IBP descriptor" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x07, 0x00, 0x00 }, {0}, true, "MPEG2VideoDescriptor_IdenticalGOP", // 200
+ "TRUE if every GOP in the sequence is constructed the same, per 13818-1 IBP descriptor" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x08, 0x00, 0x00 }, {0}, true, "MPEG2VideoDescriptor_MaxGOP", // 201
+ "Specifies the maximum occurring spacing between I frames, per 13818-1 IBP descriptor. A value of 0 or the absence of this property implies no limit to the maximum GOP" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x09, 0x00, 0x00 }, {0}, true, "MPEG2VideoDescriptor_BPictureCount", // 202
+ "Specifies the maximum number of B pictures between P or I frames, equivalent to 13818-2 annex D (M-1)" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x0b, 0x00, 0x00 }, {0}, true, "MPEG2VideoDescriptor_BitRate", // 203
+ "Maximum bit rate of MPEG video elementary stream in bit/s as defined in ISO-13818-2 bit_rate property" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x01, 0x06, 0x02, 0x01, 0x0a, 0x00, 0x00 }, {0}, true, "MPEG2VideoDescriptor_ProfileAndLevel", // 204
+ "Specifies the MPEG-2 video profile and level. The value is taken directly from the profile_and_level_indication in the MPEG-2 sequence header extension. For main profile @ main level, the value is 0x48. For 4:2:2 profile @ main level, the value is 0x85" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x48, 0x00 }, {0}, false, "WaveAudioDescriptor", // 205
+ "Defines the Wave Audio Essence Descriptor Set" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00 }, {0x3d, 0x0a}, false, "WaveAudioDescriptor_BlockAlign", // 206
+ "Sample Block alignment" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x03, 0x02, 0x02, 0x00, 0x00, 0x00 }, {0x3d, 0x0b}, true, "WaveAudioDescriptor_SequenceOffset", // 207
+ "Zero-based ordinal frame number of first essence data within five-frame sequence" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x03, 0x03, 0x05, 0x00, 0x00, 0x00 }, {0x3d, 0x09}, false, "WaveAudioDescriptor_AvgBps", // 208
+ "Average Bytes per second" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05,
+ 0x04, 0x02, 0x03, 0x01, 0x0e, 0x00, 0x00, 0x00 }, {0x3d, 0x0e}, true, "WaveAudioDescriptor_PeakEnvelope", // 209
+ "Peak Envelope from &lt;LEVL> Chunk" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x5a, 0x00 }, {0}, false, "JPEG2000PictureSubDescriptor", // 210
+ "JPEG 2000 Picture Sub Descriptor" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a,
+ 0x04, 0x01, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00 }, {0}, false, "JPEG2000PictureSubDescriptor_Rsize", // 211
+ "An enumerated value that defines the decoder capabilities" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a,
+ 0x04, 0x01, 0x06, 0x03, 0x02, 0x00, 0x00, 0x00 }, {0}, false, "JPEG2000PictureSubDescriptor_Xsize", // 212
+ "Width of the reference grid" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a,
+ 0x04, 0x01, 0x06, 0x03, 0x03, 0x00, 0x00, 0x00 }, {0}, false, "JPEG2000PictureSubDescriptor_Ysize", // 213
+ "Height of the reference grid" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a,
+ 0x04, 0x01, 0x06, 0x03, 0x04, 0x00, 0x00, 0x00 }, {0}, false, "JPEG2000PictureSubDescriptor_XOsize", // 214
+ "Horizontal offset from the origin of the reference grid to the left side of the image area" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a,
+ 0x04, 0x01, 0x06, 0x03, 0x05, 0x00, 0x00, 0x00 }, {0}, false, "JPEG2000PictureSubDescriptor_YOsize", // 215
+ "Vertical offset from the origin of the reference grid to the top side of the image area" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a,
+ 0x04, 0x01, 0x06, 0x03, 0x06, 0x00, 0x00, 0x00 }, {0}, false, "JPEG2000PictureSubDescriptor_XTsize", // 216
+ "Width of one reference tile with respect to the reference grid" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a,
+ 0x04, 0x01, 0x06, 0x03, 0x07, 0x00, 0x00, 0x00 }, {0}, false, "JPEG2000PictureSubDescriptor_YTsize", // 217
+ "Height of one reference tile with respect to the reference grid" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a,
+ 0x04, 0x01, 0x06, 0x03, 0x08, 0x00, 0x00, 0x00 }, {0}, false, "JPEG2000PictureSubDescriptor_XTOsize", // 218
+ "Horizontal offset from the origin of the reference grid to the left side of the first tile" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a,
+ 0x04, 0x01, 0x06, 0x03, 0x09, 0x00, 0x00, 0x00 }, {0}, false, "JPEG2000PictureSubDescriptor_YTOsize", // 219
+ "Vertical offset from the origin of the reference grid to the top side of the first tile" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a,
+ 0x04, 0x01, 0x06, 0x03, 0x0a, 0x00, 0x00, 0x00 }, {0}, false, "JPEG2000PictureSubDescriptor_Csize", // 220
+ "The number of components in the picture" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a,
+ 0x04, 0x01, 0x06, 0x03, 0x0b, 0x00, 0x00, 0x00 }, {0}, false, "JPEG2000PictureSubDescriptor_PictureComponentSizing", // 221
+ "Array of picture components" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a,
+ 0x04, 0x01, 0x06, 0x03, 0x0c, 0x00, 0x00, 0x00 }, {0}, true, "JPEG2000PictureSubDescriptor_CodingStyleDefault", // 222
+ "Default coding style for all components. Use this value only if static for all pictures in the Essence Container" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0a,
+ 0x04, 0x01, 0x06, 0x03, 0x0d, 0x00, 0x00, 0x00 }, {0}, true, "JPEG2000PictureSubDescriptor_QuantizationDefault", // 223
+ "Default quantization style for all components. Use this value only if static for all pictures in the Essence Container" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00 }, {0}, false, "DM_Framework", // 224
+ "Superclass for all concrete DM Frameworks" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }, {0}, false, "DM_Set", // 225
+ "Superclass for all concrete DM Frameworks" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07,
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x0b, 0x01, 0x00 }, {0}, false, "EncryptedContainerLabel", // 226
+ "DCP-Crypto Encrypted Essence Container, frame-wrapped" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07,
+ 0x0d, 0x01, 0x04, 0x01, 0x02, 0x01, 0x01, 0x00 }, {0}, false, "CryptographicFrameworkLabel", // 227
+ "DCP-Crypto Framework" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x04, 0x01, 0x02, 0x01, 0x00, 0x00 }, {0}, false, "CryptographicFramework", // 228
+ "DCP-Encryption Cryptographic Framework" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09,
+ 0x06, 0x01, 0x01, 0x04, 0x02, 0x0d, 0x00, 0x00 }, {0}, false, "CryptographicFramework_ContextSR", // 229
+ "Strong Reference to the associated Cryptographic Context" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
+ 0x0d, 0x01, 0x04, 0x01, 0x02, 0x02, 0x00, 0x00 }, {0}, false, "CryptographicContext", // 230
+ "cryptographic information that applies to encrypted essence tracks as a whole" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09,
+ 0x01, 0x01, 0x15, 0x11, 0x00, 0x00, 0x00, 0x00 }, {0}, false, "CryptographicContext_ContextID", // 231
+ "Persistent Unique identifier for the context" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09,
+ 0x06, 0x01, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00 }, {0}, false, "CryptographicContext_SourceEssenceContainer", // 232
+ "Essence Container Label for the source essence, prior to encryption" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09,
+ 0x02, 0x09, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00 }, {0}, false, "CryptographicContext_CipherAlgorithm", // 233
+ "Algorithm used for Triplet encryption, if any" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09,
+ 0x02, 0x09, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00 }, {0}, false, "CryptographicContext_MICAlgorithm", // 234
+ "Algorithm used for Triplet integrity, if any" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09,
+ 0x02, 0x09, 0x03, 0x01, 0x02, 0x00, 0x00, 0x00 }, {0}, false, "CryptographicContext_CryptographicKeyID", // 235
+ "Unique identifier for the cryptographic key" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x04, 0x01, 0x07,
+ 0x0d, 0x01, 0x03, 0x01, 0x02, 0x7e, 0x01, 0x00 }, {0}, false, "EncryptedTriplet", // 236
+ "encrypted data and cryptographic information specific to the Triplet" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09,
+ 0x06, 0x01, 0x01, 0x06, 0x03, 0x00, 0x00, 0x00 }, {0}, false, "EncryptedTriplet_ContextIDLink", // 237
+ "Persistent Unique identifier for the context.associated with this Triplet" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09,
+ 0x06, 0x09, 0x02, 0x01, 0x03, 0x00, 0x00, 0x00 }, {0}, false, "EncryptedTriplet_PlaintextOffset", // 238
+ "Offset within the source at which encryption starts" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09,
+ 0x06, 0x01, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00 }, {0}, false, "EncryptedTriplet_SourceKey", // 239
+ "Key of the source Triplet" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09,
+ 0x04, 0x06, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00 }, {0}, false, "EncryptedTriplet_SourceLength", // 240
+ "Length of the value of the source Triplet" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09,
+ 0x02, 0x09, 0x03, 0x01, 0x03, 0x00, 0x00, 0x00 }, {0}, false, "EncryptedTriplet_EncryptedSourceValue", // 241
+ "Encrypted Source value starting at Plaintext Offset" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09,
+ 0x06, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x00 }, {0}, true, "EncryptedTriplet_TrackFileID", // 242
+ "The identifier of the AS-DCP Track File containing this Triplet" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09,
+ 0x06, 0x10, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 }, {0}, true, "EncryptedTriplet_SequenceNumber", // 243
+ "Sequence number of this Triplet within the Track File" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09,
+ 0x02, 0x09, 0x03, 0x02, 0x02, 0x00, 0x00, 0x00 }, {0}, true, "EncryptedTriplet_MIC", // 244
+ "Keyed HMAC" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07,
+ 0x02, 0x09, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00 }, {0}, false, "CipherAlgorithmAES128CBC", // 245
+ "Identifes the use of AES128 CBC mode cipher algorithm" },
+
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07,
+ 0x02, 0x09, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00 }, {0}, false, "HMACAlgorithmSHA1128", // 246
+ "Identifes the use of SHA1 128 bit HMAC algorithm" },
+
+ { 0, 0, 0 }
+};
+
+const ui32_t MDDindex_KLVFill = 4;
+const ui32_t MDDindex_PartitionMetadata_MajorVersion = 5;
+const ui32_t MDDindex_PartitionMetadata_MinorVersion = 6;
+const ui32_t MDDindex_PartitionMetadata_KAGSize = 7;
+const ui32_t MDDindex_PartitionMetadata_ThisPartition = 8;
+const ui32_t MDDindex_PartitionMetadata_PreviousPartition = 9;
+const ui32_t MDDindex_PartitionMetadata_FooterPartition = 10;
+const ui32_t MDDindex_PartitionMetadata_HeaderByteCount = 11;
+const ui32_t MDDindex_PartitionMetadata_IndexByteCount = 12;
+const ui32_t MDDindex_PartitionMetadata_IndexSID = 13;
+const ui32_t MDDindex_PartitionMetadata_BodyOffset = 14;
+const ui32_t MDDindex_PartitionMetadata_BodySID = 15;
+const ui32_t MDDindex_PartitionMetadata_OperationalPattern = 16;
+const ui32_t MDDindex_PartitionMetadata_EssenceContainers = 17;
+const ui32_t MDDindex_OpenHeader = 18;
+const ui32_t MDDindex_OpenCompleteHeader = 19;
+const ui32_t MDDindex_ClosedHeader = 20;
+const ui32_t MDDindex_ClosedCompleteHeader = 21;
+const ui32_t MDDindex_OpenBodyPartition = 22;
+const ui32_t MDDindex_OpenCompleteBodyPartition = 23;
+const ui32_t MDDindex_ClosedBodyPartition = 24;
+const ui32_t MDDindex_ClosedCompleteBodyPartition = 25;
+const ui32_t MDDindex_Footer = 26;
+const ui32_t MDDindex_CompleteFooter = 27;
+const ui32_t MDDindex_Primer = 28;
+const ui32_t MDDindex_Primer_LocalTagEntryBatch = 29;
+const ui32_t MDDindex_LocalTagEntryBatch_Primer_LocalTag = 30;
+const ui32_t MDDindex_LocalTagEntryBatch_Primer_UID = 31;
+const ui32_t MDDindex_InterchangeObject_InstanceUID = 32;
+const ui32_t MDDindex_GenerationInterchangeObject_GenerationUID = 33;
+const ui32_t MDDindex_DefaultObject = 34;
+const ui32_t MDDindex_IndexTableSegmentBase_IndexEditRate = 35;
+const ui32_t MDDindex_IndexTableSegmentBase_IndexStartPosition = 36;
+const ui32_t MDDindex_IndexTableSegmentBase_IndexDuration = 37;
+const ui32_t MDDindex_IndexTableSegmentBase_EditUnitByteCount = 38;
+const ui32_t MDDindex_IndexTableSegmentBase_IndexSID = 39;
+const ui32_t MDDindex_IndexTableSegmentBase_BodySID = 40;
+const ui32_t MDDindex_IndexTableSegmentBase_SliceCount = 41;
+const ui32_t MDDindex_IndexTableSegmentBase_PosTableCount = 42;
+const ui32_t MDDindex_IndexTableSegment = 43;
+const ui32_t MDDindex_IndexTableSegment_DeltaEntryArray = 44;
+const ui32_t MDDindex_DeltaEntryArray_IndexTableSegment_PosTableIndex = 45;
+const ui32_t MDDindex_DeltaEntryArray_IndexTableSegment_Slice = 46;
+const ui32_t MDDindex_DeltaEntryArray_IndexTableSegment_ElementDelta = 47;
+const ui32_t MDDindex_IndexTableSegment_IndexEntryArray = 48;
+const ui32_t MDDindex_IndexEntryArray_IndexTableSegment_TemporalOffset = 49;
+const ui32_t MDDindex_IndexEntryArray_IndexTableSegment_AnchorOffset = 50;
+const ui32_t MDDindex_IndexEntryArray_IndexTableSegment_Flags = 51;
+const ui32_t MDDindex_IndexEntryArray_IndexTableSegment_StreamOffset = 52;
+const ui32_t MDDindex_IndexEntryArray_IndexTableSegment_SliceOffsetArray = 53;
+const ui32_t MDDindex_IndexEntryArray_IndexTableSegment_PosTableArray = 54;
+const ui32_t MDDindex_RandomIndexMetadata = 55;
+const ui32_t MDDindex_PartitionArray_RandomIndexMetadata_BodySID = 56;
+const ui32_t MDDindex_PartitionArray_RandomIndexMetadata_ByteOffset = 57;
+const ui32_t MDDindex_RandomIndexMetadata_Length = 58;
+const ui32_t MDDindex_Preface = 59;
+const ui32_t MDDindex_Preface_LastModifiedDate = 60;
+const ui32_t MDDindex_Preface_Version = 61;
+const ui32_t MDDindex_Preface_ObjectModelVersion = 62;
+const ui32_t MDDindex_Preface_PrimaryPackage = 63;
+const ui32_t MDDindex_Preface_Identifications = 64;
+const ui32_t MDDindex_Preface_ContentStorage = 65;
+const ui32_t MDDindex_Preface_OperationalPattern = 66;
+const ui32_t MDDindex_Preface_EssenceContainers = 67;
+const ui32_t MDDindex_Preface_DMSchemes = 68;
+const ui32_t MDDindex_Identification = 69;
+const ui32_t MDDindex_Identification_ThisGenerationUID = 70;
+const ui32_t MDDindex_Identification_CompanyName = 71;
+const ui32_t MDDindex_Identification_ProductName = 72;
+const ui32_t MDDindex_Identification_ProductVersion = 73;
+const ui32_t MDDindex_Identification_VersionString = 74;
+const ui32_t MDDindex_Identification_ProductUID = 75;
+const ui32_t MDDindex_Identification_ModificationDate = 76;
+const ui32_t MDDindex_Identification_ToolkitVersion = 77;
+const ui32_t MDDindex_Identification_Platform = 78;
+const ui32_t MDDindex_ContentStorage = 79;
+const ui32_t MDDindex_ContentStorage_Packages = 80;
+const ui32_t MDDindex_ContentStorage_EssenceContainerData = 81;
+const ui32_t MDDindex_EssenceContainerData = 82;
+const ui32_t MDDindex_EssenceContainerData_LinkedPackageUID = 83;
+const ui32_t MDDindex_EssenceContainerData_IndexSID = 84;
+const ui32_t MDDindex_EssenceContainerData_BodySID = 85;
+const ui32_t MDDindex_GenericPackage_PackageUID = 86;
+const ui32_t MDDindex_GenericPackage_Name = 87;
+const ui32_t MDDindex_GenericPackage_PackageCreationDate = 88;
+const ui32_t MDDindex_GenericPackage_PackageModifiedDate = 89;
+const ui32_t MDDindex_GenericPackage_Tracks = 90;
+const ui32_t MDDindex_NetworkLocator = 91;
+const ui32_t MDDindex_NetworkLocator_URLString = 92;
+const ui32_t MDDindex_TextLocator = 93;
+const ui32_t MDDindex_TextLocator_LocatorName = 94;
+const ui32_t MDDindex_GenericTrack_TrackID = 95;
+const ui32_t MDDindex_GenericTrack_TrackNumber = 96;
+const ui32_t MDDindex_GenericTrack_TrackName = 97;
+const ui32_t MDDindex_GenericTrack_Sequence = 98;
+const ui32_t MDDindex_StaticTrack = 99;
+const ui32_t MDDindex_Track = 100;
+const ui32_t MDDindex_Track_EditRate = 101;
+const ui32_t MDDindex_Track_Origin = 102;
+const ui32_t MDDindex_EventTrack = 103;
+const ui32_t MDDindex_EventTrack_EventEditRate = 104;
+const ui32_t MDDindex_EventTrack_EventOrigin = 105;
+const ui32_t MDDindex_StructuralComponent_DataDefinition = 106;
+const ui32_t MDDindex_StructuralComponent_Duration = 107;
+const ui32_t MDDindex_Sequence = 108;
+const ui32_t MDDindex_Sequence_StructuralComponents = 109;
+const ui32_t MDDindex_TimecodeComponent = 110;
+const ui32_t MDDindex_TimecodeComponent_RoundedTimecodeBase = 111;
+const ui32_t MDDindex_TimecodeComponent_StartTimecode = 112;
+const ui32_t MDDindex_TimecodeComponent_DropFrame = 113;
+const ui32_t MDDindex_SourceClip = 114;
+const ui32_t MDDindex_SourceClip_StartPosition = 115;
+const ui32_t MDDindex_SourceClip_SourcePackageID = 116;
+const ui32_t MDDindex_SourceClip_SourceTrackID = 117;
+const ui32_t MDDindex_DMSegment = 118;
+const ui32_t MDDindex_DMSegment_EventStartPosition = 119;
+const ui32_t MDDindex_DMSegment_EventComment = 120;
+const ui32_t MDDindex_DMSegment_TrackIDs = 121;
+const ui32_t MDDindex_DMSegment_DMFramework = 122;
+const ui32_t MDDindex_DMSourceClip = 123;
+const ui32_t MDDindex_DMSourceClip_DMSourceClipTrackIDs = 124;
+const ui32_t MDDindex_MaterialPackage = 125;
+const ui32_t MDDindex_SourcePackage = 126;
+const ui32_t MDDindex_SourcePackage_Descriptor = 127;
+const ui32_t MDDindex_GenericDescriptor_Locators = 128;
+const ui32_t MDDindex_GenericDescriptor_SubDescriptors = 129;
+const ui32_t MDDindex_FileDescriptor = 130;
+const ui32_t MDDindex_FileDescriptor_LinkedTrackID = 131;
+const ui32_t MDDindex_FileDescriptor_SampleRate = 132;
+const ui32_t MDDindex_FileDescriptor_ContainerDuration = 133;
+const ui32_t MDDindex_FileDescriptor_EssenceContainer = 134;
+const ui32_t MDDindex_FileDescriptor_Codec = 135;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor = 136;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_SignalStandard = 137;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_FrameLayout = 138;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_StoredWidth = 139;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_StoredHeight = 140;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_StoredF2Offset = 141;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_SampledWidth = 142;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_SampledHeight = 143;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_SampledXOffset = 144;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_SampledYOffset = 145;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_DisplayHeight = 146;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_DisplayWidth = 147;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_DisplayXOffset = 148;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_DisplayYOffset = 149;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_DisplayF2Offset = 150;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_AspectRatio = 151;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_ActiveFormatDescriptor = 152;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_VideoLineMap = 153;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_AlphaTransparency = 154;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_Gamma = 155;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_ImageAlignmentOffset = 156;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_ImageStartOffset = 157;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_ImageEndOffset = 158;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_FieldDominance = 159;
+const ui32_t MDDindex_GenericPictureEssenceDescriptor_PictureEssenceCoding = 160;
+const ui32_t MDDindex_CDCIEssenceDescriptor = 161;
+const ui32_t MDDindex_CDCIEssenceDescriptor_ComponentDepth = 162;
+const ui32_t MDDindex_CDCIEssenceDescriptor_HorizontalSubsampling = 163;
+const ui32_t MDDindex_CDCIEssenceDescriptor_VerticalSubsampling = 164;
+const ui32_t MDDindex_CDCIEssenceDescriptor_ColorSiting = 165;
+const ui32_t MDDindex_CDCIEssenceDescriptor_ReversedByteOrder = 166;
+const ui32_t MDDindex_CDCIEssenceDescriptor_PaddingBits = 167;
+const ui32_t MDDindex_CDCIEssenceDescriptor_AlphaSampleDepth = 168;
+const ui32_t MDDindex_CDCIEssenceDescriptor_BlackRefLevel = 169;
+const ui32_t MDDindex_CDCIEssenceDescriptor_WhiteReflevel = 170;
+const ui32_t MDDindex_CDCIEssenceDescriptor_ColorRange = 171;
+const ui32_t MDDindex_RGBAEssenceDescriptor = 172;
+const ui32_t MDDindex_RGBAEssenceDescriptor_ComponentMaxRef = 173;
+const ui32_t MDDindex_RGBAEssenceDescriptor_ComponentMinRef = 174;
+const ui32_t MDDindex_RGBAEssenceDescriptor_AlphaMaxRef = 175;
+const ui32_t MDDindex_RGBAEssenceDescriptor_AlphaMinRef = 176;
+const ui32_t MDDindex_RGBAEssenceDescriptor_ScanningDirection = 177;
+const ui32_t MDDindex_RGBAEssenceDescriptor_PixelLayout = 178;
+const ui32_t MDDindex_RGBAEssenceDescriptor_Palette = 179;
+const ui32_t MDDindex_RGBAEssenceDescriptor_PaletteLayout = 180;
+const ui32_t MDDindex_GenericSoundEssenceDescriptor = 181;
+const ui32_t MDDindex_GenericSoundEssenceDescriptor_AudioSamplingRate = 182;
+const ui32_t MDDindex_GenericSoundEssenceDescriptor_Locked = 183;
+const ui32_t MDDindex_GenericSoundEssenceDescriptor_AudioRefLevel = 184;
+const ui32_t MDDindex_GenericSoundEssenceDescriptor_ElectroSpatialFormulation = 185;
+const ui32_t MDDindex_GenericSoundEssenceDescriptor_ChannelCount = 186;
+const ui32_t MDDindex_GenericSoundEssenceDescriptor_QuantizationBits = 187;
+const ui32_t MDDindex_GenericSoundEssenceDescriptor_DialNorm = 188;
+const ui32_t MDDindex_GenericSoundEssenceDescriptor_SoundEssenceCompression = 189;
+const ui32_t MDDindex_GenericDataEssenceDescriptor = 190;
+const ui32_t MDDindex_GenericDataEssenceDescriptor_DataEssenceCoding = 191;
+const ui32_t MDDindex_MultipleDescriptor = 192;
+const ui32_t MDDindex_MultipleDescriptor_SubDescriptorUIDs = 193;
+const ui32_t MDDindex_MPEG2VideoDescriptor = 194;
+const ui32_t MDDindex_MPEG2VideoDescriptor_SingleSequence = 195;
+const ui32_t MDDindex_MPEG2VideoDescriptor_ConstantBFrames = 196;
+const ui32_t MDDindex_MPEG2VideoDescriptor_CodedContentType = 197;
+const ui32_t MDDindex_MPEG2VideoDescriptor_LowDelay = 198;
+const ui32_t MDDindex_MPEG2VideoDescriptor_ClosedGOP = 199;
+const ui32_t MDDindex_MPEG2VideoDescriptor_IdenticalGOP = 200;
+const ui32_t MDDindex_MPEG2VideoDescriptor_MaxGOP = 201;
+const ui32_t MDDindex_MPEG2VideoDescriptor_BPictureCount = 202;
+const ui32_t MDDindex_MPEG2VideoDescriptor_BitRate = 203;
+const ui32_t MDDindex_MPEG2VideoDescriptor_ProfileAndLevel = 204;
+const ui32_t MDDindex_WaveAudioDescriptor = 205;
+const ui32_t MDDindex_WaveAudioDescriptor_BlockAlign = 206;
+const ui32_t MDDindex_WaveAudioDescriptor_SequenceOffset = 207;
+const ui32_t MDDindex_WaveAudioDescriptor_AvgBps = 208;
+const ui32_t MDDindex_WaveAudioDescriptor_PeakEnvelope = 209;
+const ui32_t MDDindex_JPEG2000PictureSubDescriptor = 210;
+const ui32_t MDDindex_JPEG2000PictureSubDescriptor_Rsize = 211;
+const ui32_t MDDindex_JPEG2000PictureSubDescriptor_Xsize = 212;
+const ui32_t MDDindex_JPEG2000PictureSubDescriptor_Ysize = 213;
+const ui32_t MDDindex_JPEG2000PictureSubDescriptor_XOsize = 214;
+const ui32_t MDDindex_JPEG2000PictureSubDescriptor_YOsize = 215;
+const ui32_t MDDindex_JPEG2000PictureSubDescriptor_XTsize = 216;
+const ui32_t MDDindex_JPEG2000PictureSubDescriptor_YTsize = 217;
+const ui32_t MDDindex_JPEG2000PictureSubDescriptor_XTOsize = 218;
+const ui32_t MDDindex_JPEG2000PictureSubDescriptor_YTOsize = 219;
+const ui32_t MDDindex_JPEG2000PictureSubDescriptor_Csize = 220;
+const ui32_t MDDindex_JPEG2000PictureSubDescriptor_PictureComponentSizing = 221;
+const ui32_t MDDindex_JPEG2000PictureSubDescriptor_CodingStyleDefault = 222;
+const ui32_t MDDindex_JPEG2000PictureSubDescriptor_QuantizationDefault = 223;
+const ui32_t MDDindex_DM_Framework = 224;
+const ui32_t MDDindex_DM_Set = 225;
+const ui32_t MDDindex_EncryptedContainerLabel = 226;
+const ui32_t MDDindex_CryptographicFrameworkLabel = 227;
+const ui32_t MDDindex_CryptographicFramework = 228;
+const ui32_t MDDindex_CryptographicFramework_ContextSR = 229;
+const ui32_t MDDindex_CryptographicContext = 230;
+const ui32_t MDDindex_CryptographicContext_ContextID = 231;
+const ui32_t MDDindex_CryptographicContext_SourceEssenceContainer = 232;
+const ui32_t MDDindex_CryptographicContext_CipherAlgorithm = 233;
+const ui32_t MDDindex_CryptographicContext_MICAlgorithm = 234;
+const ui32_t MDDindex_CryptographicContext_CryptographicKeyID = 235;
+const ui32_t MDDindex_EncryptedTriplet = 236;
+const ui32_t MDDindex_EncryptedTriplet_ContextIDLink = 237;
+const ui32_t MDDindex_EncryptedTriplet_PlaintextOffset = 238;
+const ui32_t MDDindex_EncryptedTriplet_SourceKey = 239;
+const ui32_t MDDindex_EncryptedTriplet_SourceLength = 240;
+const ui32_t MDDindex_EncryptedTriplet_EncryptedSourceValue = 241;
+const ui32_t MDDindex_EncryptedTriplet_TrackFileID = 242;
+const ui32_t MDDindex_EncryptedTriplet_SequenceNumber = 243;
+const ui32_t MDDindex_EncryptedTriplet_MIC = 244;
+const ui32_t MDDindex_CipherAlgorithmAES128CBC = 245;
+const ui32_t MDDindex_HMACAlgorithmSHA1128 = 246;
+
+#endif // _MDD_H_
+
+//
+// end MDD.h
+//
diff --git a/src/MPEG.cpp b/src/MPEG.cpp
new file mode 100755
index 0000000..0f60a8f
--- /dev/null
+++ b/src/MPEG.cpp
@@ -0,0 +1,267 @@
+/*
+Copyright (c) 2005, 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 MPEG.cpp
+ \version $Id$
+ \brief MPEG2 VES parser
+*/
+
+#include <MPEG.h>
+
+// walk a buffer stopping at the end of the buffer or the end of a VES
+// start code '00 00 01'. If successful, returns address of first byte
+// of start code
+ASDCP::Result_t
+ASDCP::MPEG2::FindVESStartCode(const byte_t* buf, ui32_t buf_len, StartCode_t* sc, const byte_t** new_pos)
+{
+ ASDCP_TEST_NULL(buf);
+ ASDCP_TEST_NULL(new_pos);
+
+ ui32_t zero_i = 0;
+ const byte_t* p = buf;
+ const byte_t* end_p = buf + buf_len;
+
+ for ( ; p < end_p; p++ )
+ {
+ if ( *p == 0 )
+ zero_i++;
+
+ else if ( *p == 1 && zero_i > 1 )
+ {
+ // 2 or more 0 bytes followed by a 1, start code is next
+ if ( ++p == end_p )
+ return RESULT_FAIL;
+
+ *new_pos = p - 3;
+ *sc = (StartCode_t)*p;
+ return RESULT_OK;
+ }
+ else
+ zero_i = 0;
+ }
+
+ *new_pos = buf + buf_len;
+ return RESULT_FAIL;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+//
+ASDCP::Rational
+ASDCP::MPEG2::Accessor::Sequence::AspectRatio()
+{
+ switch ( m_p[3] & 0xf0 )
+ {
+ case 0x10: return Rational(1,1);
+ case 0x20: return Rational(4,3);
+ case 0x30: return Rational(16,9);
+ case 0x40: return Rational(221,100);
+ }
+
+ DefaultLogSink().Error("Unknown AspectRatio value: %02x\n", m_p[3]);
+ return Rational(0,0);
+}
+
+//------------------------------------------------------------------------------------------
+
+enum State_t {
+ ST_IDLE,
+ ST_START_HEADER,
+ ST_IN_HEADER,
+};
+
+
+//
+class ASDCP::MPEG2::VESParser::h__StreamState
+{
+public:
+ State_t m_State;
+ h__StreamState() : m_State(ST_IDLE) {}
+ ~h__StreamState() {}
+
+ void Goto_START_HEADER() { m_State = ST_START_HEADER; }
+ void Goto_IN_HEADER() { m_State = ST_IN_HEADER; }
+ void Goto_IDLE() { m_State = ST_IDLE; }
+ bool Test_IDLE() { return m_State == ST_IDLE; }
+ bool Test_START_HEADER() { return m_State == ST_START_HEADER; }
+ bool Test_IN_HEADER() { return m_State == ST_IN_HEADER; }
+};
+
+//------------------------------------------------------------------------------------------
+
+
+ASDCP::MPEG2::VESParser::VESParser() :
+ m_Delegate(0), m_HBufLen(0), m_ZeroCount(0), m_Partial(false)
+{
+ m_State = new h__StreamState;
+}
+
+ASDCP::MPEG2::VESParser::~VESParser()
+{
+}
+
+
+//
+void
+ASDCP::MPEG2::VESParser::SetDelegate(VESParserDelegate* Delegate)
+{
+ m_Delegate = Delegate;
+}
+
+//
+void
+ASDCP::MPEG2::VESParser::Reset()
+{
+ m_State->Goto_IDLE();
+ m_HBufLen = 0;
+ m_ZeroCount = 0;
+ m_Partial = false;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MPEG2::VESParser::Parse(const byte_t* buf, ui32_t buf_len)
+{
+ ASDCP_TEST_NULL(buf);
+ ASDCP_TEST_NULL(m_Delegate);
+
+ Result_t result;
+ const byte_t* end_p = buf + buf_len;
+ const byte_t* run_pos = buf; // track runs of uninteresting data as a position and count
+ ui32_t run_len = 0;
+
+ // search for MPEG2 headers
+ // copy interesting data to a buffer and pass to delegate for processing
+ for ( const byte_t* p = buf; p < end_p; p++ )
+ {
+ if ( m_State->Test_IN_HEADER() )
+ {
+ m_HBuf[m_HBufLen++] = *p;
+ assert(m_HBufLen < VESHeaderBufSize);
+ }
+ else
+ {
+ run_len++;
+ }
+
+ if ( m_State->Test_START_HEADER() ) // *p is a start code
+ {
+ // Do we already have a header? We need to flush it...
+ if ( m_HBufLen > 0)
+ {
+ m_HBufLen -= 3; // remove the current partial start code
+
+ // let the delegate handle the header
+ switch( m_HBuf[3] )
+ {
+ case PIC_START: result = m_Delegate->Picture(this, m_HBuf, m_HBufLen); break;
+ case EXT_START: result = m_Delegate->Extension(this, m_HBuf, m_HBufLen); break;
+ case SEQ_START: result = m_Delegate->Sequence(this, m_HBuf, m_HBufLen); break;
+ case GOP_START: result = m_Delegate->GOP(this, m_HBuf, m_HBufLen); break;
+
+ default:
+ DefaultLogSink().Error("Unexpected start code: %02x at byte %lu\n",
+ m_HBuf[3], (ui32_t)(p - buf));
+ result = RESULT_RAW_FORMAT;
+ }
+
+ // the next run starts with the start code that got us here
+ run_len = 4;
+ run_pos = p-3;
+ m_HBufLen = 0;
+
+ // Parser handlers return RESULT_FALSE to teriminate without error
+ if ( result != RESULT_OK )
+ {
+ m_State->Goto_IDLE();
+ return result;
+ }
+ }
+
+ // all headers start with this same start code: 00 00 01 xx
+ m_HBuf[0] = m_HBuf[1] = 0; m_HBuf[2] = 1; m_HBuf[3] = *p;
+
+ // is this a header we want?
+ if ( *p == PIC_START || *p == SEQ_START || *p == EXT_START || *p == GOP_START )
+ {
+ // we're starting a new header, flush the current run
+ if ( run_len > 4 )
+ {
+ m_Delegate->Data(this, run_pos, run_len - 4);
+ run_len = 0;
+ }
+
+ m_Partial = false;
+ m_HBufLen = 4;
+ m_State->Goto_IN_HEADER();
+ }
+ else
+ {
+ if ( *p == FIRST_SLICE )
+ result = m_Delegate->Slice(this);
+
+ if ( m_Partial )
+ {
+ m_Partial = false;
+ m_Delegate->Data(this, m_HBuf, 3);
+ }
+
+ m_State->Goto_IDLE();
+ }
+ }
+ else if ( *p == 0 )
+ {
+ m_ZeroCount++;
+ }
+ else
+ {
+ if ( *p == 1 && m_ZeroCount > 1 )
+ m_State->Goto_START_HEADER();
+
+ m_ZeroCount = 0;
+ }
+ }
+
+ if ( run_len > 0 )
+ {
+ if ( m_State->Test_START_HEADER() )
+ {
+ m_Partial = true; // 'partial' means we have a partial header in progress
+ run_len -= 3;
+ }
+
+ // flush the current run
+ m_Delegate->Data(this, run_pos, run_len);
+ }
+
+ return RESULT_OK;
+}
+
+
+//
+// end MPEG.cpp
+//
diff --git a/src/MPEG.h b/src/MPEG.h
new file mode 100755
index 0000000..c4de827
--- /dev/null
+++ b/src/MPEG.h
@@ -0,0 +1,237 @@
+/*
+Copyright (c) 2005, 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 MPEG.h
+ \version $Id$
+ \brief MPEG2 VES parser interface
+*/
+
+#ifndef _ASDCP_MPEG_H_
+#define _ASDCP_MPEG_H_
+
+#include <AS_DCP_system.h>
+#include <stdio.h>
+#include <assert.h>
+
+
+namespace ASDCP
+{
+ namespace MPEG2
+ {
+ //
+ enum StartCode_t {
+ PIC_START = 0x00,
+ SEQ_START = 0xb3,
+ EXT_START = 0xb5,
+ GOP_START = 0xb8,
+ FIRST_SLICE = 0x01,
+ INVALID = 0xff
+ };
+
+ //
+ enum RateCode_t {
+ RATE_23_976 = 0x01,
+ RATE_24 = 0x02,
+ RATE_25 = 0x03,
+ RATE_29_97 = 0x04,
+ RATE_30 = 0x05
+ };
+
+ //
+ enum ExtCode_t {
+ EXT_SEQ = 0x01
+ };
+
+ //------------------------------------------------------------------------------------------
+ // VES Parser
+
+ // find the location in the buffer of the next VES packet, returns RESULT_FAIL
+ // if no start code is found
+ Result_t FindVESStartCode(const byte_t* buf, ui32_t buf_len, StartCode_t* sc, const byte_t** new_pos);
+
+ // return the extension code of an extension header
+ inline ExtCode_t ParseExtensionCode(const byte_t* buf)
+ {
+ assert(buf);
+ return (ExtCode_t)(buf[4] >> 4);
+ }
+
+ //
+ class VESParserDelegate; // the delegate is declared later
+ const ui32_t VESHeaderBufSize = 1024; // should be larger than any expected header
+
+ // MPEG VES parser class - call Parse() as many times as you want with buffers
+ // of any size. State is maintained between calls. When complete headers are
+ // available for examination, the respective delegate method will be called.
+ // All other data is given to the delegate's Data() method.
+ class VESParser
+ {
+ class h__StreamState;
+ mem_ptr<h__StreamState> m_State;
+ VESParserDelegate* m_Delegate;
+
+ ui32_t m_HBufLen; // temp space for partial header contents
+ byte_t m_HBuf[VESHeaderBufSize];
+ ui32_t m_ZeroCount;
+ bool m_Partial;
+
+ ASDCP_NO_COPY_CONSTRUCT(VESParser);
+
+ public:
+ VESParser();
+ ~VESParser();
+
+ void SetDelegate(VESParserDelegate*); // you must call this before Parse()
+ Result_t Parse(const byte_t*, ui32_t); // call repeatedly
+ void Reset(); // resets the internal state machine and counters
+ };
+
+ // Parser Event Delegate Interface
+ //
+ // Create a concrete subclass and give it to the parser by calling SetDelegate().
+ // The respective method will be called when a header of the named type is found.
+ // Handler methods should return RESULT_OK to continue processing or RESULT_FALSE
+ // to stop without error.
+ //
+ class VESParserDelegate
+ {
+ public:
+ virtual ~VESParserDelegate() {}
+
+ // header handlers
+ virtual Result_t Picture(VESParser*, const byte_t*, ui32_t) = 0;
+ virtual Result_t Extension(VESParser*, const byte_t*, ui32_t) = 0;
+ virtual Result_t Sequence(VESParser*, const byte_t*, ui32_t) = 0;
+ virtual Result_t GOP(VESParser*, const byte_t*, ui32_t) = 0;
+
+ // this is not a header handler, it is a signal that actual picture data
+ // has started. All Slice data is reported via the Data() method.
+ virtual Result_t Slice(VESParser*) = 0;
+
+ // Any data not given to the header handlers above is reported here
+ virtual Result_t Data(VESParser*, const byte_t*, ui32_t) = 0;
+ };
+
+
+ //------------------------------------------------------------------------------------------
+ // VES header accessor objects
+ //
+ // For use within parser delegate methods. The constructor expects a pointer to a buffer
+ // containing two zero bytes, a one byte, a start code and some number of header bytes.
+ // They are not documented further as they should be self-explanatory.
+ namespace Accessor
+ {
+ // decoding tables
+ static i16_t FrameRateLUT[] = { 0, 24, 24, 25, 30, 30, 50, 60, 60};
+ static bool PulldownLUT[] = { false, true, false, false, true, false, false, true, false};
+
+ //
+ class Sequence
+ {
+ const byte_t* m_p;
+ ASDCP_NO_COPY_CONSTRUCT(Sequence);
+
+ public:
+ Sequence(const byte_t* p) { assert(p); m_p = p + 4; }
+ inline ui16_t HorizontalSize() { return (ui16_t)( ( m_p[0] << 4 ) | ( m_p[1] >> 4 ) ); }
+ inline ui16_t VerticalSize() { return (ui16_t)( ( ( m_p[1] & 0x0f ) << 8 ) | m_p[2] ); }
+ inline RateCode_t RateCode() { return (RateCode_t)( m_p[3] & 0x0f ); }
+ inline ui16_t FrameRate() { return FrameRateLUT[RateCode()]; }
+ inline bool Pulldown() { return PulldownLUT[RateCode()] != 0; }
+ inline i32_t BitRate() {
+ return ( ( (i32_t)m_p[4] << 10 ) + ( (i32_t)m_p[5] << 2 ) + ( m_p[6] >> 6 ) ) * 400;
+ }
+
+ Rational AspectRatio();
+ };
+
+ //
+ class SequenceEx
+ {
+ const byte_t* m_p;
+ ASDCP_NO_COPY_CONSTRUCT(SequenceEx);
+
+ public:
+ SequenceEx(const byte_t* p)
+ {
+ assert(p);
+ assert(ParseExtensionCode(p) == EXT_SEQ);
+ m_p = p + 4;
+ }
+
+ inline ui16_t ProfileAndLevel() { return ( m_p[0] << 4) | ( m_p[1] >> 4 ); }
+ inline ui8_t ChromaFormat() { return ( m_p[1] >> 1 ) & 0x03; }
+ inline bool Progressive() { return ( ( m_p[1] >> 3 ) & 0x01 ) > 0; }
+ inline ui32_t HorizontalSizeExt() {
+ return ( ( m_p[1] & 0x01 ) << 13 ) | ( ( m_p[2] & 0x80 ) << 5 );
+ }
+ inline ui32_t VerticalSizeExt() { return ( m_p[2] & 0x60 ) << 7; }
+ inline ui32_t BitRateExt() {
+ return ( ( m_p[2] & 0x1f ) << 25 ) | ( ( m_p[3] & 0xfe ) << 17 );
+ }
+
+ inline bool LowDelay() { return ( m_p[5] & 0x80 ) > 0; }
+ };
+
+ //
+ class GOP
+ {
+ const byte_t* m_p;
+ ASDCP_NO_COPY_CONSTRUCT(GOP);
+
+ public:
+ GOP(const byte_t* p) { assert(p); m_p = p + 4; }
+ inline bool Closed() { return ( ( m_p[3] ) >> 6 ) & 0x01; }
+ };
+
+ //
+ class Picture
+ {
+ const byte_t* m_p;
+ ASDCP_NO_COPY_CONSTRUCT(Picture);
+
+ public:
+ Picture(const byte_t* p) { assert(p); m_p = p + 4; }
+ inline i16_t TemporalRef() {
+ return ( (i16_t)( m_p[0] << 2 ) ) | ( ( (i16_t)m_p[1] & 0x00c0 ) >> 6 );
+ }
+
+ inline FrameType_t FrameType() {
+ return (FrameType_t)( ( m_p[1] & 0x38 ) >> 3 );
+ }
+ };
+
+ } // namespace Accessor
+
+ } // namespace MPEG2
+
+} // namespace ASDCP
+
+#endif // ASDCP_MPEG_H_
+
+//
+// end MPEG.h
+//
diff --git a/src/MPEG2_Parser.cpp b/src/MPEG2_Parser.cpp
new file mode 100755
index 0000000..9e72b0f
--- /dev/null
+++ b/src/MPEG2_Parser.cpp
@@ -0,0 +1,581 @@
+/*
+Copyright (c) 2004, 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 MPEG2_Parser.cpp
+ \version $Id$
+ \brief AS-DCP library, MPEG2 raw essence reader implementation
+*/
+
+#include <FileIO.h>
+#include <MPEG.h>
+
+using namespace ASDCP;
+using namespace ASDCP::MPEG2;
+
+// data will be read from a VES file in chunks of this size
+const ui32_t VESReadSize = 4096;
+
+
+//------------------------------------------------------------------------------------------
+
+//
+enum ParserState_t {
+ ST_INIT,
+ ST_SEQ,
+ ST_PIC,
+ ST_GOP,
+ ST_EXT,
+ ST_SLICE,
+};
+
+
+//
+class h__ParserState
+{
+ ParserState_t m_State;
+ ASDCP_NO_COPY_CONSTRUCT(h__ParserState);
+
+ public:
+ h__ParserState() : m_State(::ST_INIT) {}
+ ~h__ParserState() {}
+
+ bool Test_SLICE() { return m_State == ST_SLICE; }
+ void Reset() { m_State = ST_INIT; }
+
+ //
+ inline Result_t Goto_SEQ()
+ {
+ switch ( m_State )
+ {
+ case ST_INIT:
+ m_State = ST_SEQ;
+ return RESULT_OK;
+ }
+
+ return RESULT_STATE;
+ }
+
+
+ //
+ inline Result_t Goto_SLICE()
+ {
+ switch ( m_State )
+ {
+ case ST_PIC:
+ case ST_EXT:
+ m_State = ST_SLICE;
+ return RESULT_OK;
+ }
+
+ return RESULT_STATE;
+ }
+
+
+ //
+ inline Result_t Goto_PIC()
+ {
+ switch ( m_State )
+ {
+ case ST_INIT:
+ case ST_SEQ:
+ case ST_GOP:
+ case ST_EXT:
+ m_State = ST_PIC;
+ return RESULT_OK;
+ }
+
+ return RESULT_STATE;
+ }
+
+
+ //
+ inline Result_t Goto_GOP()
+ {
+ switch ( m_State )
+ {
+ case ST_EXT:
+ case ST_SEQ:
+ m_State = ST_GOP;
+ return RESULT_OK;
+ }
+
+ return RESULT_STATE;
+ }
+
+ //
+ inline Result_t Goto_EXT()
+ {
+ switch ( m_State )
+ {
+ case ST_PIC:
+ case ST_EXT:
+ case ST_SEQ:
+ case ST_GOP:
+ m_State = ST_EXT;
+ return RESULT_OK;
+ }
+
+ return RESULT_STATE;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+
+// This is a parser delagate that reads the stream params from a
+// sequence header and sequence extension header. The parser is
+// commanded to return after processing the sequence extension
+// header.
+class StreamParams : public VESParserDelegate
+{
+ h__ParserState m_State;
+
+ ASDCP_NO_COPY_CONSTRUCT(StreamParams);
+
+public:
+ VideoDescriptor m_VDesc;
+
+ StreamParams()
+ {
+ m_VDesc.ContainerDuration = 0;
+ m_VDesc.ComponentDepth = 8;
+ }
+
+ ~StreamParams() {}
+
+ //
+ Result_t Sequence(VESParser*, const byte_t* b, ui32_t s)
+ {
+ Result_t result = m_State.Goto_SEQ();
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ Accessor::Sequence SEQ(b);
+ m_VDesc.AspectRatio = SEQ.AspectRatio();
+ m_VDesc.FrameRate = SEQ.FrameRate();
+ m_VDesc.StoredWidth = SEQ.HorizontalSize();
+ m_VDesc.StoredHeight = SEQ.VerticalSize();
+ m_VDesc.BitRate = SEQ.BitRate();
+ m_VDesc.EditRate = SEQ.Pulldown() ? Rational(SEQ.FrameRate() * 1000, 1001) : Rational(SEQ.FrameRate(), 1);
+ m_VDesc.SampleRate = m_VDesc.EditRate;
+ return RESULT_OK;
+ }
+
+ //
+ Result_t Extension(VESParser*, const byte_t* b, ui32_t s)
+ {
+ Result_t result = m_State.Goto_EXT();
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ Accessor::SequenceEx SEQX(b);
+ m_VDesc.ProfileAndLevel = SEQX.ProfileAndLevel();
+ m_VDesc.FrameLayout = SEQX.Progressive() ? 0 : 1;
+ m_VDesc.CodedContentType = SEQX.Progressive() ? 1 : 2;
+ m_VDesc.LowDelay = SEQX.LowDelay();
+ m_VDesc.HorizontalSubsampling = SEQX.ChromaFormat() == 3 ? 1 : 2;
+ m_VDesc.VerticalSubsampling = SEQX.ChromaFormat() >= 3 ? 1 : 2;
+
+ if ( ( m_VDesc.HorizontalSubsampling == 2 ) && ( m_VDesc.VerticalSubsampling == 2 ) )
+ m_VDesc.ColorSiting = 3; // 4:2:0
+
+ else if ( ( m_VDesc.HorizontalSubsampling == 2 ) && ( m_VDesc.VerticalSubsampling == 1 ) )
+ m_VDesc.ColorSiting = 4; // 4:2:2
+
+ else if ( ( m_VDesc.HorizontalSubsampling == 1 ) && ( m_VDesc.VerticalSubsampling == 1 ) )
+ m_VDesc.ColorSiting = 0; // 4:4:4
+
+ // TODO: get H&V size and bit rate extensions
+
+ return RESULT_FALSE;
+ }
+
+ Result_t GOP(VESParser*, const byte_t*, ui32_t) { return RESULT_FALSE; }
+ Result_t Picture(VESParser*, const byte_t*, ui32_t) { return RESULT_FALSE; }
+ Result_t Slice(VESParser*) { return RESULT_FALSE; }
+ Result_t Data(VESParser*, const byte_t*, ui32_t) { return RESULT_OK; }
+};
+
+
+//------------------------------------------------------------------------------------------
+
+// This is a parser delagate that reads a VES stream and sets public
+// instance variables to indicate state. It is used below to read an
+// entire frame into a buffer. The delegate retains metadata about the
+// frame for later access.
+//
+class FrameParser : public VESParserDelegate
+{
+ h__ParserState m_State;
+ ASDCP_NO_COPY_CONSTRUCT(FrameParser);
+
+public:
+ ui32_t m_FrameSize;
+ bool m_CompletePicture;
+ bool m_HasGOP;
+ bool m_ClosedGOP;
+ ui8_t m_TemporalRef;
+ ui32_t m_PlaintextOffset;
+ FrameType_t m_FrameType;
+
+ FrameParser()
+ {
+ Reset();
+ }
+
+ ~FrameParser() {}
+
+ void Reset()
+ {
+ m_FrameSize = 0;
+ m_HasGOP = m_ClosedGOP = false;
+ m_CompletePicture = false;
+ m_TemporalRef = 0;
+ m_PlaintextOffset = 0;
+ m_FrameType = FRAME_U;
+ m_State.Reset();
+ }
+
+ Result_t Sequence(VESParser*, const byte_t* b, ui32_t s)
+ {
+ if ( m_State.Test_SLICE() )
+ {
+ m_CompletePicture = true;
+ return RESULT_FALSE;
+ }
+
+ m_FrameSize += s;
+ return m_State.Goto_SEQ();
+ }
+
+ Result_t Picture(VESParser*, const byte_t* b, ui32_t s)
+ {
+ if ( m_State.Test_SLICE() )
+ {
+ m_CompletePicture = true;
+ return RESULT_FALSE;
+ }
+
+ Accessor::Picture PIC(b);
+ m_TemporalRef = PIC.TemporalRef();
+ m_FrameType = PIC.FrameType();
+ m_FrameSize += s;
+ return m_State.Goto_PIC();
+ }
+
+ Result_t Slice(VESParser*)
+ {
+ m_PlaintextOffset = m_FrameSize;
+ return m_State.Goto_SLICE();
+ }
+
+ Result_t Extension(VESParser*, const byte_t* b, ui32_t s)
+ {
+ m_FrameSize += s;
+ return m_State.Goto_EXT();
+ }
+
+ Result_t GOP(VESParser*, const byte_t* b, ui32_t s)
+ {
+ Accessor::GOP GOP(b);
+ m_ClosedGOP = GOP.Closed();
+ m_HasGOP = true;
+ m_FrameSize += s;
+ return m_State.Goto_GOP();
+ }
+
+ Result_t Data(VESParser*, const byte_t* b, ui32_t s)
+ {
+ m_FrameSize += s;
+ return RESULT_OK;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+
+// The following code assumes the following things:
+// - each frame will begin with a picture header or a sequence header
+// - any frame that begins with a sequence header is an I frame and is
+// assumed to contain a GOP header, a picture header and complete picture data
+// - any frame that begins with a picture header is either an I, B or P frame
+// and is assumed to contain a complete picture header and picture data
+
+
+class ASDCP::MPEG2::Parser::h__Parser
+{
+ StreamParams m_ParamsDelegate;
+ FrameParser m_ParserDelegate;
+ VESParser m_Parser;
+ FileReader m_FileReader;
+ ui32_t m_FrameNumber;
+ bool m_EOF;
+ ASDCP::MPEG2::FrameBuffer m_TmpBuffer;
+
+ ASDCP_NO_COPY_CONSTRUCT(h__Parser);
+
+public:
+ h__Parser() : m_TmpBuffer(VESReadSize*2) {}
+ ~h__Parser() { Close(); }
+
+ Result_t OpenRead(const char* filename);
+ void Close();
+ Result_t Reset();
+ Result_t ReadFrame(FrameBuffer&);
+ Result_t FillVideoDescriptor(VideoDescriptor&);
+};
+
+
+//
+Result_t
+ASDCP::MPEG2::Parser::h__Parser::Reset()
+{
+ m_FrameNumber = 0;
+ m_EOF = false;
+ m_FileReader.Seek(0);
+ m_ParserDelegate.Reset();
+ return RESULT_OK;
+}
+
+//
+void
+ASDCP::MPEG2::Parser::h__Parser::Close()
+{
+ m_FileReader.Close();
+}
+
+//
+ASDCP::Result_t
+ASDCP::MPEG2::Parser::h__Parser::OpenRead(const char* filename)
+{
+ ASDCP_TEST_NULL_STR(filename)
+ ui32_t read_count = 0;
+
+ Result_t result = m_FileReader.OpenRead(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_FileReader.Read(m_TmpBuffer.Data(), m_TmpBuffer.Capacity(), &read_count);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ const byte_t* p = m_TmpBuffer.RoData();
+
+ // the mxflib parser demanded the file start with a sequence header.
+ // Since no one complained and that's the easiest thing to implement,
+ // I have left it that way. Let me know if you want to be able to
+ // locate the first GOP in the stream.
+ if ( p[0] != 0 || p[1] != 0 || p[2] != 1 )
+ {
+ DefaultLogSink().Error("Frame buffer does not begin with a start code.\n");
+ return RESULT_RAW_FORMAT;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_Parser.SetDelegate(&m_ParamsDelegate);
+ result = m_Parser.Parse(p, read_count);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_Parser.SetDelegate(&m_ParserDelegate);
+ m_FileReader.Seek(0);
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ {
+ DefaultLogSink().Error("Unable to identify a wrapping mode for the essence in file \"%s\"\n", filename);
+ m_FileReader.Close();
+ }
+
+ return result;
+}
+
+//
+//
+ASDCP::Result_t
+ASDCP::MPEG2::Parser::h__Parser::ReadFrame(FrameBuffer& FB)
+{
+ Result_t result = RESULT_OK;
+ ui32_t write_offset = 0;
+ ui32_t read_count = 0;
+
+ FB.Size(0);
+
+ if ( m_EOF )
+ return RESULT_ENDOFFILE;
+
+ // Data is read in VESReadSize chunks. Each chunk is parsed, and the
+ // process is stopped when a Sequence or Picture header is found or when
+ // the input file is exhausted. The partial next frame is cached for the
+ // next call.
+ m_ParserDelegate.Reset();
+
+ if ( m_TmpBuffer.Size() > 0 )
+ {
+ memcpy(FB.Data(), m_TmpBuffer.RoData(), m_TmpBuffer.Size());
+ result = m_Parser.Parse(FB.RoData(), m_TmpBuffer.Size());
+ write_offset = m_TmpBuffer.Size();
+ m_TmpBuffer.Size(0);
+ }
+
+ while ( ! m_ParserDelegate.m_CompletePicture && ASDCP_SUCCESS(result) )
+ {
+ if ( FB.Capacity() < ( write_offset + VESReadSize ) )
+ {
+ DefaultLogSink().Error("FrameBuf.Capacity: %lu FrameLength: %lu\n",
+ FB.Capacity(), ( write_offset + VESReadSize ));
+ return RESULT_SMALLBUF;
+ }
+
+ result = m_FileReader.Read(FB.Data() + write_offset, VESReadSize, &read_count);
+
+ if ( result == RESULT_ENDOFFILE )
+ {
+ m_EOF = true;
+
+ if ( write_offset > 0 )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = m_Parser.Parse(FB.RoData() + write_offset, read_count);
+ write_offset += read_count;
+ }
+
+ if ( m_EOF )
+ break;
+ }
+
+ if ( ASDCP_SUCCESS(result)
+ && m_ParserDelegate.m_FrameSize < write_offset )
+ {
+ assert(m_TmpBuffer.Size() == 0);
+ ui32_t diff = write_offset - m_ParserDelegate.m_FrameSize;
+ assert(diff <= m_TmpBuffer.Capacity());
+ memcpy(m_TmpBuffer.Data(), FB.RoData() + m_ParserDelegate.m_FrameSize, diff);
+ m_TmpBuffer.Size(diff);
+ }
+
+#ifndef NDEBUG
+ if ( ASDCP_SUCCESS(result) )
+ {
+ const byte_t* p = FB.RoData();
+ if ( p[0] != 0 || p[1] != 0 || p[2] != 1 )
+ {
+ DefaultLogSink().Error("Parsed frame buffer does not begin with a start code.\n");
+ return RESULT_RAW_FORMAT;
+ }
+ }
+#endif
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ FB.Size(m_ParserDelegate.m_FrameSize);
+ FB.TemporalOffset(m_ParserDelegate.m_TemporalRef);
+ FB.FrameType(m_ParserDelegate.m_FrameType);
+ FB.PlaintextOffset(m_ParserDelegate.m_PlaintextOffset);
+ FB.FrameNumber(m_FrameNumber++);
+
+ if ( m_ParserDelegate.m_HasGOP )
+ {
+ FB.GOPStart(m_ParserDelegate.m_HasGOP);
+ FB.ClosedGOP(m_ParserDelegate.m_ClosedGOP);
+ }
+ }
+
+ return result;
+}
+
+
+// Fill a VideoDescriptor struct with the values from the file's header.
+ASDCP::Result_t
+ASDCP::MPEG2::Parser::h__Parser::FillVideoDescriptor(VideoDescriptor& VDesc)
+{
+ VDesc = m_ParamsDelegate.m_VDesc;
+ return RESULT_OK;
+}
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::MPEG2::Parser::Parser()
+{
+}
+
+ASDCP::MPEG2::Parser::~Parser()
+{
+}
+
+// Opens the stream for reading, parses enough data to provide a complete
+// set of stream metadata for the MXFWriter below.
+ASDCP::Result_t
+ASDCP::MPEG2::Parser::OpenRead(const char* filename) const
+{
+ const_cast<ASDCP::MPEG2::Parser*>(this)->m_Parser = new h__Parser;
+
+ Result_t result = m_Parser->OpenRead(filename);
+
+ if ( ASDCP_FAILURE(result) )
+ const_cast<ASDCP::MPEG2::Parser*>(this)->m_Parser.release();
+
+ return result;
+}
+
+// Rewinds the stream to the beginning.
+ASDCP::Result_t
+ASDCP::MPEG2::Parser::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::MPEG2::Parser::ReadFrame(FrameBuffer& FB) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ return m_Parser->ReadFrame(FB);
+}
+
+ASDCP::Result_t
+ASDCP::MPEG2::Parser::FillVideoDescriptor(VideoDescriptor& VDesc) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ return m_Parser->FillVideoDescriptor(VDesc);
+}
+
+//
+// end AS_DCP_MPEG2_Parser.cpp
+//
diff --git a/src/MXF.cpp b/src/MXF.cpp
new file mode 100755
index 0000000..bacf069
--- /dev/null
+++ b/src/MXF.cpp
@@ -0,0 +1,1020 @@
+//
+//
+//
+
+
+#define ASDCP_DECLARE_MDD
+#include "MDD.h"
+
+#include "MXF.h"
+#include "Metadata.h"
+#include <hex_utils.h>
+
+//------------------------------------------------------------------------------------------
+//
+
+const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH;
+
+const byte_t mdd_key[] = { 0x06, 0x0e, 0x2b, 0x34 };
+
+//
+const ASDCP::MDDEntry*
+ASDCP::GetMDDEntry(const byte_t* ul_buf)
+{
+ ui32_t t_idx = 0;
+ ui32_t k_idx = 8;
+
+ // must be a pointer to a SMPTE UL
+ if ( ul_buf == 0 || memcmp(mdd_key, ul_buf, 4) != 0 )
+ return 0;
+
+ // advance to first matching element
+ // TODO: optimize using binary search
+ while ( s_MDD_Table[t_idx].ul != 0
+ && s_MDD_Table[t_idx].ul[k_idx] != ul_buf[k_idx] )
+ t_idx++;
+
+ if ( s_MDD_Table[t_idx].ul == 0 )
+ return 0;
+
+ // match successive elements
+ while ( s_MDD_Table[t_idx].ul != 0
+ && k_idx < SMPTE_UL_LENGTH - 1
+ && s_MDD_Table[t_idx].ul[k_idx] == ul_buf[k_idx] )
+ {
+ if ( s_MDD_Table[t_idx].ul[k_idx+1] == ul_buf[k_idx+1] )
+ {
+ k_idx++;
+ }
+ else
+ {
+ while ( s_MDD_Table[t_idx].ul != 0
+ && s_MDD_Table[t_idx].ul[k_idx] == ul_buf[k_idx]
+ && s_MDD_Table[t_idx].ul[k_idx+1] != ul_buf[k_idx+1] )
+ t_idx++;
+
+ while ( s_MDD_Table[t_idx].ul[k_idx] != ul_buf[k_idx] )
+ k_idx--;
+ }
+ }
+
+ return (s_MDD_Table[t_idx].ul == 0 ? 0 : &s_MDD_Table[t_idx]);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::SeekToRIP(const ASDCP::FileReader& Reader)
+{
+ ASDCP::fpos_t end_pos;
+
+ // go to the end - 4 bytes
+ Result_t result = Reader.Seek(0, ASDCP::SP_END);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.Tell(&end_pos);
+
+ if ( ASDCP_SUCCESS(result)
+ && end_pos < (SMPTE_UL_LENGTH+MXF_BER_LENGTH) )
+ result = RESULT_FAIL; // File is smaller than an empty packet!
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.Seek(end_pos - 4);
+
+ // get the ui32_t RIP length
+ ui32_t read_count;
+ byte_t intbuf[MXF_BER_LENGTH];
+ ui32_t rip_size = 0;
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = Reader.Read(intbuf, MXF_BER_LENGTH, &read_count);
+
+ if ( ASDCP_SUCCESS(result) && read_count != 4 )
+ result = RESULT_FAIL;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ rip_size = ASDCP_i32_BE(cp2i<ui32_t>(intbuf));
+
+ if ( rip_size > end_pos ) // RIP can't be bigger than the file
+ return RESULT_FAIL;
+ }
+
+ // reposition to start of RIP
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.Seek(end_pos - rip_size);
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::RIP::InitFromFile(const ASDCP::FileReader& Reader)
+{
+ Result_t result = KLVFilePacket::InitFromFile(Reader, s_MDD_Table[MDDindex_RandomIndexMetadata].ul);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ MemIOReader MemRDR(m_ValueStart, m_ValueLength - 4);
+ result = PairArray.ReadFrom(MemRDR);
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ DefaultLogSink().Error("Failed to initialize RIP\n");
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::RIP::WriteToFile(ASDCP::FileWriter& Writer)
+{
+ Result_t result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_RandomIndexMetadata].ul, 0);
+ return result;
+}
+
+//
+void
+ASDCP::MXF::RIP::Dump(FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVFilePacket::Dump(stream, false);
+ PairArray.Dump(stream, false);
+
+ fputs("==========================================================================\n", stream);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Partition::InitFromFile(const ASDCP::FileReader& Reader)
+{
+ Result_t result = KLVFilePacket::InitFromFile(Reader);
+ // test the UL
+ // could be one of several values
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ MemIOReader MemRDR(m_ValueStart, m_ValueLength);
+ result = MemRDR.ReadUi16BE(&MajorVersion);
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi16BE(&MinorVersion);
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&KAGSize);
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&ThisPartition);
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&PreviousPartition);
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&FooterPartition);
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&HeaderByteCount);
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&IndexByteCount);
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&IndexSID);
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&BodyOffset);
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&BodySID);
+ if ( ASDCP_SUCCESS(result) ) result = OperationalPattern.ReadFrom(MemRDR);
+ if ( ASDCP_SUCCESS(result) ) result = EssenceContainers.ReadFrom(MemRDR);
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ DefaultLogSink().Error("Failed to initialize Partition\n");
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Partition::WriteToFile(ASDCP::FileWriter& Writer)
+{
+ Result_t result = m_Buffer.Capacity(1024);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ MemIOWriter MemWRT(m_Buffer.Data(), m_Buffer.Capacity());
+ result = MemWRT.WriteUi16BE(MajorVersion);
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi16BE(MinorVersion);
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(KAGSize);
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(ThisPartition);
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(PreviousPartition);
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(FooterPartition);
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(HeaderByteCount);
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(IndexByteCount);
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(IndexSID);
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(BodyOffset);
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(BodySID);
+ if ( ASDCP_SUCCESS(result) ) result = OperationalPattern.WriteTo(MemWRT);
+ if ( ASDCP_SUCCESS(result) ) result = EssenceContainers.WriteTo(MemWRT);
+ if ( ASDCP_SUCCESS(result) ) m_Buffer.Size(MemWRT.Size());
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t write_count; // this is subclassed, so the UL is only right some of the time
+ result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_ClosedCompleteHeader].ul, m_Buffer.Size());
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.Write(m_Buffer.RoData(), m_Buffer.Size(), &write_count);
+ }
+
+ return result;
+}
+
+//
+void
+ASDCP::MXF::Partition::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+ char intbuf[IntBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVFilePacket::Dump(stream, false);
+ fprintf(stream, " MajorVersion = %hu\n", MajorVersion);
+ fprintf(stream, " MinorVersion = %hu\n", MinorVersion);
+ fprintf(stream, " KAGSize = %lu\n", KAGSize);
+ fprintf(stream, " ThisPartition = %s\n", ui64sz(ThisPartition, intbuf));
+ fprintf(stream, " PreviousPartition = %s\n", ui64sz(PreviousPartition, intbuf));
+ fprintf(stream, " FooterPartition = %s\n", ui64sz(FooterPartition, intbuf));
+ fprintf(stream, " HeaderByteCount = %s\n", ui64sz(HeaderByteCount, intbuf));
+ fprintf(stream, " IndexByteCount = %s\n", ui64sz(IndexByteCount, intbuf));
+ fprintf(stream, " IndexSID = %lu\n", IndexSID);
+ fprintf(stream, " BodyOffset = %s\n", ui64sz(BodyOffset, intbuf));
+ fprintf(stream, " BodySID = %lu\n", BodySID);
+ fprintf(stream, " OperationalPattern = %s\n", OperationalPattern.ToString(identbuf));
+ fputs("Essence Containers:\n", stream); EssenceContainers.Dump(stream, false);
+
+ fputs("==========================================================================\n", stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+class ASDCP::MXF::Primer::h__PrimerLookup : public std::map<UL, TagValue>
+{
+public:
+ void InitWithBatch(ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>& Batch)
+ {
+ ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>::iterator i = Batch.begin();
+
+ for ( ; i != Batch.end(); i++ )
+ insert(std::map<UL, TagValue>::value_type((*i).UL, (*i).Tag));
+ }
+};
+
+
+//
+ASDCP::MXF::Primer::Primer() {}
+
+//
+ASDCP::MXF::Primer::~Primer() {}
+
+//
+void
+ASDCP::MXF::Primer::ClearTagList()
+{
+ LocalTagEntryBatch.clear();
+ m_Lookup = new h__PrimerLookup;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Primer::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_Primer].ul);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ MemIOReader MemRDR(m_ValueStart, m_ValueLength);
+ result = LocalTagEntryBatch.ReadFrom(MemRDR);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_Lookup = new h__PrimerLookup;
+ m_Lookup->InitWithBatch(LocalTagEntryBatch);
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ DefaultLogSink().Error("Failed to initialize Primer\n");
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Primer::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ MemIOWriter MemWRT(Buffer.Data(), Buffer.Capacity());
+ Result_t result = LocalTagEntryBatch.WriteTo(MemWRT);
+ Buffer.Size(MemWRT.Size());
+#if 0
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t write_count;
+ result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_Primer].ul, Buffer.Size());
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.Write(Buffer.RoData(), Buffer.Size(), &write_count);
+ }
+#endif
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Primer::InsertTag(const ASDCP::UL& Key, ASDCP::TagValue& Tag)
+{
+ assert(m_Lookup);
+
+ std::map<UL, TagValue>::iterator i = m_Lookup->find(Key);
+
+ if ( i == m_Lookup->end() )
+ {
+ const MDDEntry* mdde = GetMDDEntry(Key.Data());
+ assert(mdde);
+
+ LocalTagEntry TmpEntry;
+ TmpEntry.UL = Key;
+ TmpEntry.Tag = mdde->tag;
+
+ LocalTagEntryBatch.push_back(TmpEntry);
+ m_Lookup->insert(std::map<UL, TagValue>::value_type(TmpEntry.UL, TmpEntry.Tag));
+ }
+
+ return RESULT_OK;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Primer::TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag)
+{
+ assert(m_Lookup);
+ if ( m_Lookup.empty() )
+ {
+ DefaultLogSink().Error("Primer lookup is empty\n");
+ return RESULT_FAIL;
+ }
+
+ std::map<UL, TagValue>::iterator i = m_Lookup->find(Key);
+
+ if ( i == m_Lookup->end() )
+ return RESULT_FALSE;
+
+ Tag = (*i).second;
+ return RESULT_OK;
+}
+
+//
+void
+ASDCP::MXF::Primer::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVPacket::Dump(stream, false);
+ fprintf(stream, "Primer: %lu %s\n",
+ LocalTagEntryBatch.ItemCount,
+ ( LocalTagEntryBatch.ItemCount == 1 ? "entry" : "entries" ));
+
+ Batch<LocalTagEntry>::iterator i = LocalTagEntryBatch.begin();
+ for ( ; i != LocalTagEntryBatch.end(); i++ )
+ {
+ const MDDEntry* Entry = GetMDDEntry((*i).UL.Data());
+ fprintf(stream, " %s %s\n", (*i).ToString(identbuf), (Entry ? Entry->name : "Unknown"));
+ }
+
+ fputs("==========================================================================\n", stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Preface::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ ASDCP_TEST_NULL(p);
+
+ Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_Preface].ul);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
+
+ result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, LastModifiedDate));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi16(OBJ_READ_ARGS(Preface, Version));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(Preface, ObjectModelVersion));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, PrimaryPackage));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, Identifications));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, ContentStorage));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, OperationalPattern));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, EssenceContainers));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, DMSchemes));
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ DefaultLogSink().Error("Failed to initialize Preface\n");
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Preface::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ TLVWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length, m_Lookup);
+ Result_t result = MemWRT.WriteObject(OBJ_WRITE_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(GenerationInterchangeObject, GenerationUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, LastModifiedDate));
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi16(OBJ_WRITE_ARGS(Preface, Version));
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32(OBJ_WRITE_ARGS(Preface, ObjectModelVersion));
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, PrimaryPackage));
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, Identifications));
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, ContentStorage));
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, OperationalPattern));
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, EssenceContainers));
+ if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, DMSchemes));
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t packet_length = MemWRT.Size();
+ result = WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_Preface].ul, packet_length);
+
+ if ( ASDCP_SUCCESS(result) )
+ Buffer.Size(Buffer.Size() + packet_length);
+ }
+
+ return result;
+}
+
+//
+void
+ASDCP::MXF::Preface::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVPacket::Dump(stream, false);
+ fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
+ fprintf(stream, " GenerationUID = %s\n", GenerationUID.ToString(identbuf));
+ fprintf(stream, " LastModifiedDate = %s\n", LastModifiedDate.ToString(identbuf));
+ fprintf(stream, " Version = %hu\n", Version);
+ fprintf(stream, " ObjectModelVersion = %lu\n", ObjectModelVersion);
+ fprintf(stream, " PrimaryPackage = %s\n", PrimaryPackage.ToString(identbuf));
+ fprintf(stream, " Identifications:\n"); Identifications.Dump(stream);
+ fprintf(stream, " ContentStorage = %s\n", ContentStorage.ToString(identbuf));
+ fprintf(stream, " OperationalPattern = %s\n", OperationalPattern.ToString(identbuf));
+ fprintf(stream, " EssenceContainers:\n"); EssenceContainers.Dump(stream);
+ fprintf(stream, " DMSchemes:\n"); DMSchemes.Dump(stream);
+
+ fputs("==========================================================================\n", stream);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+class ASDCP::MXF::h__PacketList
+{
+public:
+ std::list<InterchangeObject*> m_List;
+ std::map<UL, InterchangeObject*> m_Map;
+
+ ~h__PacketList() {
+ while ( ! m_List.empty() )
+ {
+ delete m_List.back();
+ m_List.pop_back();
+ }
+ }
+
+ //
+ void AddPacket(InterchangeObject* ThePacket)
+ {
+ assert(ThePacket);
+ m_Map.insert(std::map<UID, InterchangeObject*>::value_type(ThePacket->InstanceUID, ThePacket));
+ m_List.push_back(ThePacket);
+ }
+
+ //
+ Result_t GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
+ {
+ ASDCP_TEST_NULL(ObjectID);
+ ASDCP_TEST_NULL(Object);
+ std::list<InterchangeObject*>::iterator li;
+ *Object = 0;
+
+ for ( li = m_List.begin(); li != m_List.end(); li++ )
+ {
+ if ( (*li)->HasUL(ObjectID) )
+ {
+ *Object = *li;
+ return RESULT_OK;
+ }
+ }
+
+ return RESULT_FAIL;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+//
+
+ASDCP::MXF::OPAtomHeader::OPAtomHeader() : m_Preface(0), m_HasRIP(false)
+{
+ m_PacketList = new h__PacketList;
+}
+
+
+ASDCP::MXF::OPAtomHeader::~OPAtomHeader()
+{
+}
+
+
+ASDCP::Result_t
+ASDCP::MXF::OPAtomHeader::InitFromFile(const ASDCP::FileReader& Reader)
+{
+ m_HasRIP = false;
+ Result_t result = SeekToRIP(Reader);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = m_RIP.InitFromFile(Reader);
+
+ if ( ASDCP_FAILURE(result) )
+ {
+ DefaultLogSink().Error("File contains no RIP\n");
+ result = RESULT_OK;
+ }
+ else
+ {
+ m_HasRIP = true;
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.Seek(0);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Partition::InitFromFile(Reader); // test UL and OP
+
+ // slurp up the remainder of the header
+ ui32_t read_count;
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui64_t here = Reader.Tell();
+ ui32_t buf_len = HeaderByteCount;
+ result = m_Buffer.Capacity(buf_len);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
+
+ if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
+ {
+ DefaultLogSink().Error("Short read of OP-Atom header metadata; wanted %lu, got %lu\n",
+ m_Buffer.Capacity(), read_count);
+ return RESULT_FAIL;
+ }
+
+ const byte_t* p = m_Buffer.RoData();
+ const byte_t* end_p = p + m_Buffer.Capacity();
+
+ while ( ASDCP_SUCCESS(result) && p < end_p )
+ {
+ // parse the packets and index them by uid, discard KLVFill items
+ InterchangeObject* object = CreateObject(p);
+ assert(object);
+
+ object->m_Lookup = &m_Primer;
+ result = object->InitFromBuffer(p, end_p - p);
+ const byte_t* redo_p = p;
+ p += object->PacketLength();
+ // hexdump(p, object->PacketLength());
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( object->IsA(s_MDD_Table[MDDindex_KLVFill].ul) )
+ {
+ delete object;
+ }
+ else if ( object->IsA(s_MDD_Table[MDDindex_Primer].ul) )
+ {
+ delete object;
+ result = m_Primer.InitFromBuffer(redo_p, end_p - redo_p);
+ }
+ else if ( object->IsA(s_MDD_Table[MDDindex_Preface].ul) )
+ {
+ m_Preface = object;
+ }
+ else
+ {
+ m_PacketList->AddPacket(object);
+ }
+ }
+ else
+ {
+ DefaultLogSink().Error("Error initializing packet\n");
+ delete object;
+ }
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::OPAtomHeader::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
+{
+ InterchangeObject* TmpObject;
+
+ if ( Object == 0 )
+ Object = &TmpObject;
+
+ return m_PacketList->GetMDObjectByType(ObjectID, Object);
+}
+
+ASDCP::MXF::Identification*
+ASDCP::MXF::OPAtomHeader::GetIdentification()
+{
+ InterchangeObject* Object;
+
+ if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object)) )
+ return (Identification*)Object;
+
+ return 0;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::OPAtomHeader::WriteToFile(ASDCP::FileWriter& Writer, ui32_t HeaderSize)
+{
+ if ( HeaderSize < 4096 )
+ {
+ DefaultLogSink().Error("HeaderSize %lu is too small. Must be >= 4096\n");
+ return RESULT_FAIL;
+ }
+
+ ASDCP::FrameBuffer HeaderBuffer;
+
+ Result_t result = HeaderBuffer.Capacity(HeaderSize);
+ HeaderByteCount = HeaderSize;
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ assert(m_Preface);
+ m_Preface->m_Lookup = &m_Primer;
+ result = m_Preface->WriteToBuffer(HeaderBuffer);
+ }
+#if 0
+ std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
+ for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
+ {
+ InterchangeObject* object = *pl_i;
+ object->m_Lookup = &m_Primer;
+ result = object->WriteToBuffer(HeaderBuffer);
+ }
+#endif
+ if ( ASDCP_SUCCESS(result) )
+ result = Partition::WriteToFile(Writer);
+
+ // if ( ASDCP_SUCCESS(result) )
+ // result = m_Primer.WriteToFile(Writer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t write_count;
+ Writer.Write(HeaderBuffer.RoData(), HeaderBuffer.Size(), &write_count);
+ assert(write_count == HeaderBuffer.Size());
+ }
+
+ // KLV Fill
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ASDCP::fpos_t pos = Writer.Tell();
+
+ if ( pos > HeaderSize )
+ {
+ char intbuf[IntBufferLen];
+ DefaultLogSink().Error("Header size %s exceeds specified value %lu\n",
+ ui64sz(pos, intbuf),
+ HeaderSize);
+ return RESULT_FAIL;
+ }
+
+ ASDCP::FrameBuffer NilBuf;
+ ui32_t klv_fill_length = HeaderSize - (ui32_t)pos;
+
+ if ( klv_fill_length < kl_length )
+ {
+ DefaultLogSink().Error("Remaining region too small for KLV Fill header\n");
+ return RESULT_FAIL;
+ }
+
+ klv_fill_length -= kl_length;
+ result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_KLVFill].ul, klv_fill_length);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = NilBuf.Capacity(klv_fill_length);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ memset(NilBuf.Data(), 0, klv_fill_length);
+ ui32_t write_count;
+ Writer.Write(NilBuf.RoData(), klv_fill_length, &write_count);
+ assert(write_count == klv_fill_length);
+ }
+ }
+
+ return result;
+}
+
+//
+void
+ASDCP::MXF::OPAtomHeader::Dump(FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ if ( m_HasRIP )
+ m_RIP.Dump(stream);
+
+ Partition::Dump(stream);
+ m_Primer.Dump(stream);
+ assert(m_Preface);
+ m_Preface->Dump(stream);
+
+ std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
+ for ( ; i != m_PacketList->m_List.end(); i++ )
+ (*i)->Dump(stream);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+ASDCP::MXF::OPAtomIndexFooter::OPAtomIndexFooter() : m_Lookup(0)
+{
+ m_PacketList = new h__PacketList;
+}
+
+
+ASDCP::MXF::OPAtomIndexFooter::~OPAtomIndexFooter()
+{
+}
+
+
+ASDCP::Result_t
+ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const ASDCP::FileReader& Reader)
+{
+ Result_t result = Partition::InitFromFile(Reader); // test UL and OP
+
+ // slurp up the remainder of the footer
+ ui32_t read_count;
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_Buffer.Capacity(IndexByteCount);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
+
+ if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
+ {
+ DefaultLogSink().Error("Short read of footer partition: got %lu, expecting %lu\n",
+ read_count, m_Buffer.Capacity());
+ return RESULT_FAIL;
+ }
+
+ const byte_t* p = m_Buffer.RoData();
+ const byte_t* end_p = p + m_Buffer.Capacity();
+
+ while ( ASDCP_SUCCESS(result) && p < end_p )
+ {
+ // parse the packets and index them by uid, discard KLVFill items
+ InterchangeObject* object = CreateObject(p);
+ assert(object);
+
+ object->m_Lookup = m_Lookup;
+ result = object->InitFromBuffer(p, end_p - p);
+ p += object->PacketLength();
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_PacketList->AddPacket(object);
+ }
+ else
+ {
+ DefaultLogSink().Error("Error initializing packet\n");
+ delete object;
+ }
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ DefaultLogSink().Error("Failed to initialize OPAtomIndexFooter\n");
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::OPAtomIndexFooter::WriteToFile(ASDCP::FileWriter& Writer)
+{
+ Result_t result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_CompleteFooter].ul, 0);
+ return result;
+}
+
+//
+void
+ASDCP::MXF::OPAtomIndexFooter::Dump(FILE* stream)
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ Partition::Dump(stream);
+
+ std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
+ for ( ; i != m_PacketList->m_List.end(); i++ )
+ (*i)->Dump(stream);
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry& Entry)
+{
+ std::list<InterchangeObject*>::iterator li;
+ for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ )
+ {
+ if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
+ {
+ IndexTableSegment* Segment = (IndexTableSegment*)(*li);
+ ui64_t start_pos = Segment->IndexStartPosition;
+
+ if ( Segment->EditUnitByteCount > 0 )
+ {
+ if ( m_PacketList->m_List.size() > 1 )
+ DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n");
+
+ if ( ! Segment->IndexEntryArray.empty() )
+ DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n");
+
+ Entry.StreamOffset = (ui64_t)frame_num * Segment->EditUnitByteCount;
+ return RESULT_OK;
+ }
+ else if ( (ui64_t)frame_num >= start_pos
+ && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) )
+ {
+ Entry = Segment->IndexEntryArray[frame_num];
+ return RESULT_OK;
+ }
+ }
+ }
+
+ return RESULT_FAIL;
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::InterchangeObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ if ( Buffer.Capacity() < (Buffer.Size() + m_KLLength + m_ValueLength) )
+ {
+ DefaultLogSink().Error("InterchangeObject::WriteToBuffer: Buffer too small\n");
+ Dump();
+ return RESULT_READFAIL;
+ }
+
+ Result_t result = WriteKLToBuffer(Buffer, m_KeyStart, m_ValueLength);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ memcpy(Buffer.Data() + Buffer.Size(), m_ValueStart, m_ValueLength);
+ Buffer.Size(Buffer.Size() + m_ValueLength);
+ }
+
+ return result;
+}
+
+//
+bool
+ASDCP::MXF::InterchangeObject::IsA(const byte_t* label)
+{
+ if ( m_KLLength == 0 )
+ return false;
+
+ return ( memcmp(label, m_KeyStart, SMPTE_UL_LENGTH) == 0 );
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+enum FLT_t
+ {
+ FLT_Preface,
+ FLT_Identification,
+ FLT_ContentStorage,
+ FLT_MaterialPackage,
+ FLT_SourcePackage,
+ FLT_Track,
+ FLT_Sequence,
+ FLT_SourceClip,
+ FLT_TimecodeComponent,
+ FLT_FileDescriptor,
+ FLT_WaveAudioDescriptor,
+ FLT_GenericPictureEssenceDescriptor,
+ FLT_MPEG2VideoDescriptor,
+ FLT_RGBAEssenceDescriptor,
+ FLT_JPEG2000PictureSubDescriptor,
+ FLT_IndexTableSegment,
+ FLT_CryptographicFramework,
+ FLT_CryptographicContext
+ };
+
+//
+typedef std::map<ASDCP::UL, FLT_t> FactoryList;
+#define SETUP_IDX(t) const ui32_t FLT_##t = v;
+
+static FactoryList s_FactoryList;
+#define SETUP_FACTORY(t) s_FactoryList.insert(FactoryList::value_type(s_MDD_Table[MDDindex_##t].ul, FLT_##t));
+#define CASE_FACTORY(t) case FLT_##t: return new t
+
+//
+ASDCP::MXF::InterchangeObject*
+ASDCP::MXF::CreateObject(const byte_t* label)
+{
+ if ( label == 0 )
+ return 0;
+
+ if ( s_FactoryList.empty() )
+ {
+ SETUP_FACTORY(Preface);
+ SETUP_FACTORY(Identification);
+ SETUP_FACTORY(ContentStorage);
+ SETUP_FACTORY(MaterialPackage);
+ SETUP_FACTORY(SourcePackage);
+ SETUP_FACTORY(Track);
+ SETUP_FACTORY(Sequence);
+ SETUP_FACTORY(SourceClip);
+ SETUP_FACTORY(TimecodeComponent);
+ SETUP_FACTORY(FileDescriptor);
+ SETUP_FACTORY(WaveAudioDescriptor);
+ SETUP_FACTORY(GenericPictureEssenceDescriptor);
+ SETUP_FACTORY(MPEG2VideoDescriptor);
+ SETUP_FACTORY(RGBAEssenceDescriptor);
+ SETUP_FACTORY(JPEG2000PictureSubDescriptor);
+ SETUP_FACTORY(IndexTableSegment);
+ SETUP_FACTORY(CryptographicFramework);
+ SETUP_FACTORY(CryptographicContext);
+ }
+
+ FactoryList::iterator i = s_FactoryList.find(label);
+
+ if ( i == s_FactoryList.end() )
+ return new InterchangeObject;
+
+ switch ( i->second )
+ {
+ CASE_FACTORY(Preface);
+ CASE_FACTORY(Identification);
+ CASE_FACTORY(ContentStorage);
+ CASE_FACTORY(MaterialPackage);
+ CASE_FACTORY(SourcePackage);
+ CASE_FACTORY(Track);
+ CASE_FACTORY(Sequence);
+ CASE_FACTORY(SourceClip);
+ CASE_FACTORY(TimecodeComponent);
+ CASE_FACTORY(FileDescriptor);
+ CASE_FACTORY(WaveAudioDescriptor);
+ CASE_FACTORY(GenericPictureEssenceDescriptor);
+ CASE_FACTORY(MPEG2VideoDescriptor);
+ CASE_FACTORY(RGBAEssenceDescriptor);
+ CASE_FACTORY(JPEG2000PictureSubDescriptor);
+ CASE_FACTORY(IndexTableSegment);
+ CASE_FACTORY(CryptographicFramework);
+ CASE_FACTORY(CryptographicContext);
+ }
+
+ return new InterchangeObject;
+}
+
+//
+// end MXF.cpp
+//
diff --git a/src/MXF.h b/src/MXF.h
new file mode 100755
index 0000000..fc0d996
--- /dev/null
+++ b/src/MXF.h
@@ -0,0 +1,307 @@
+//
+//
+//
+
+#ifndef _MXF_H_
+#define _MXF_H_
+
+#include "MXFTypes.h"
+
+namespace ASDCP
+{
+ namespace MXF
+ {
+ // seek an open file handle to the start of the RIP KLV packet
+ Result_t SeekToRIP(const FileReader&);
+
+ //
+ class RIP : public ASDCP::KLVFilePacket
+ {
+ ASDCP_NO_COPY_CONSTRUCT(RIP);
+
+ public:
+ //
+ class Pair {
+ public:
+ ui32_t BodySID;
+ ui64_t ByteOffset;
+
+ ui32_t Size() { return sizeof(ui32_t) + sizeof(ui64_t); }
+
+ inline const char* ToString(char* str_buf) const {
+ char intbuf[IntBufferLen];
+ sprintf(str_buf, "%-6lu: %s", BodySID, ui64sz(ByteOffset, intbuf));
+ return str_buf;
+ }
+
+ inline Result_t ReadFrom(ASDCP::MemIOReader& Reader) {
+ Result_t result = Reader.ReadUi32BE(&BodySID);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.ReadUi64BE(&ByteOffset);
+
+ return result;
+ }
+
+ inline Result_t WriteTo(ASDCP::MemIOWriter& Writer) {
+ Result_t result = Writer.WriteUi32BE(BodySID);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.WriteUi64BE(ByteOffset);
+
+ return result;
+ }
+ };
+
+ Array<Pair> PairArray;
+
+ RIP() {}
+ virtual ~RIP() {}
+ virtual Result_t InitFromFile(const ASDCP::FileReader& Reader);
+ virtual Result_t WriteToFile(ASDCP::FileWriter& Writer);
+ virtual void Dump(FILE* = 0);
+ };
+
+
+ //
+ class Partition : public ASDCP::KLVFilePacket
+ {
+ ASDCP_NO_COPY_CONSTRUCT(Partition);
+
+ public:
+ ui16_t MajorVersion;
+ ui16_t MinorVersion;
+ ui32_t KAGSize;
+ ui64_t ThisPartition;
+ ui64_t PreviousPartition;
+ ui64_t FooterPartition;
+ ui64_t HeaderByteCount;
+ ui64_t IndexByteCount;
+ ui32_t IndexSID;
+ ui64_t BodyOffset;
+ ui32_t BodySID;
+ UL OperationalPattern;
+ Batch<UL> EssenceContainers;
+
+ Partition() {}
+ virtual ~Partition() {}
+ virtual Result_t InitFromFile(const ASDCP::FileReader& Reader);
+ virtual Result_t WriteToFile(ASDCP::FileWriter& Writer);
+ virtual void Dump(FILE* = 0);
+ };
+
+
+ //
+ class Primer : public ASDCP::KLVPacket, public ASDCP::IPrimerLookup
+ {
+ class h__PrimerLookup;
+ mem_ptr<h__PrimerLookup> m_Lookup;
+ ASDCP_NO_COPY_CONSTRUCT(Primer);
+
+ public:
+ //
+ class LocalTagEntry
+ {
+ public:
+ TagValue Tag;
+ ASDCP::UL UL;
+
+ inline const char* ToString(char* str_buf) const {
+ sprintf(str_buf, "%02x %02x: ", Tag.a, Tag.b);
+ UL.ToString(str_buf + strlen(str_buf));
+ return str_buf;
+ }
+
+ inline Result_t ReadFrom(ASDCP::MemIOReader& Reader) {
+ Result_t result = Reader.ReadUi8(&Tag.a);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.ReadUi8(&Tag.b);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = UL.ReadFrom(Reader);
+
+ return result;
+ }
+
+ inline Result_t WriteTo(ASDCP::MemIOWriter& Writer) {
+ Result_t result = Writer.WriteUi8(Tag.a);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.WriteUi8(Tag.b);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = UL.WriteTo(Writer);
+
+ return result;
+ }
+ };
+
+ Batch<LocalTagEntry> LocalTagEntryBatch;
+
+ Primer();
+ virtual ~Primer();
+
+ virtual void ClearTagList();
+ virtual Result_t InsertTag(const ASDCP::UL& Key, ASDCP::TagValue& Tag);
+ virtual Result_t TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag);
+
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual void Dump(FILE* = 0);
+ };
+
+
+ //
+ class InterchangeObject : public ASDCP::KLVPacket
+ {
+ public:
+ IPrimerLookup* m_Lookup;
+ UID InstanceUID;
+
+ InterchangeObject() : m_Lookup(0) {}
+ virtual ~InterchangeObject() {}
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual bool IsA(const byte_t* label);
+
+ virtual void Dump(FILE* stream = 0) {
+ KLVPacket::Dump(stream, true);
+ }
+ };
+
+ //
+ InterchangeObject* CreateObject(const byte_t* label);
+
+
+ //
+ class Preface : public InterchangeObject
+ {
+ ASDCP_NO_COPY_CONSTRUCT(Preface);
+
+ public:
+ UUID GenerationUID;
+ Timestamp LastModifiedDate;
+ ui16_t Version;
+ ui32_t ObjectModelVersion;
+ UID PrimaryPackage;
+ Batch<UID> Identifications;
+ UID ContentStorage;
+ UL OperationalPattern;
+ Batch<UL> EssenceContainers;
+ Batch<UL> DMSchemes;
+
+ Preface() {}
+ virtual ~Preface() {}
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer& Buffer);
+ virtual void Dump(FILE* = 0);
+ };
+
+ //
+ class IndexTableSegment : public InterchangeObject
+ {
+ ASDCP_NO_COPY_CONSTRUCT(IndexTableSegment);
+
+ public:
+ //
+ class DeltaEntry
+ {
+ public:
+ i8_t PosTableIndex;
+ ui8_t Slice;
+ ui32_t ElementData;
+
+ Result_t ReadFrom(ASDCP::MemIOReader& Reader);
+ Result_t WriteTo(ASDCP::MemIOWriter& Writer);
+ inline const char* ToString(char* str_buf) const;
+ };
+
+ //
+ class IndexEntry
+ {
+ public:
+ i8_t TemporalOffset;
+ i8_t KeyFrameOffset;
+ ui8_t Flags;
+ ui64_t StreamOffset;
+ std::list<ui32_t> SliceOffset;
+ Array<Rational> PosTable;
+
+ Result_t ReadFrom(ASDCP::MemIOReader& Reader);
+ Result_t WriteTo(ASDCP::MemIOWriter& Writer);
+ inline const char* ToString(char* str_buf) const;
+ };
+
+ Rational IndexEditRate;
+ ui64_t IndexStartPosition;
+ ui64_t IndexDuration;
+ ui32_t EditUnitByteCount;
+ ui32_t IndexSID;
+ ui32_t BodySID;
+ ui8_t SliceCount;
+ ui8_t PosTableCount;
+ Batch<DeltaEntry> DeltaEntryArray;
+ Batch<IndexEntry> IndexEntryArray;
+
+ IndexTableSegment();
+ virtual ~IndexTableSegment();
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer& Buffer);
+ virtual void Dump(FILE* = 0);
+ };
+
+ //---------------------------------------------------------------------------------
+ //
+ class h__PacketList; // See MXF.cpp
+ class Identification;
+
+ //
+ class OPAtomHeader : public Partition
+ {
+ mem_ptr<h__PacketList> m_PacketList;
+ ASDCP_NO_COPY_CONSTRUCT(OPAtomHeader);
+
+ public:
+ ASDCP::MXF::RIP m_RIP;
+ ASDCP::MXF::Primer m_Primer;
+ InterchangeObject* m_Preface;
+ ASDCP::FrameBuffer m_Buffer;
+ bool m_HasRIP;
+
+ OPAtomHeader();
+ virtual ~OPAtomHeader();
+ virtual Result_t InitFromFile(const ASDCP::FileReader& Reader);
+ virtual Result_t WriteToFile(ASDCP::FileWriter& Writer, ui32_t HeaderLength = 16384);
+ virtual void Dump(FILE* = 0);
+ virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
+ Identification* GetIdentification();
+ };
+
+ //
+ class OPAtomIndexFooter : public Partition
+ {
+ mem_ptr<h__PacketList> m_PacketList;
+ ASDCP::FrameBuffer m_Buffer;
+ ASDCP_NO_COPY_CONSTRUCT(OPAtomIndexFooter);
+
+ public:
+ IPrimerLookup* m_Lookup;
+
+ OPAtomIndexFooter();
+ virtual ~OPAtomIndexFooter();
+ virtual Result_t InitFromFile(const ASDCP::FileReader& Reader);
+ virtual Result_t WriteToFile(ASDCP::FileWriter& Writer);
+ virtual void Dump(FILE* = 0);
+
+ virtual Result_t Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry&);
+ };
+
+ } // namespace MXF
+} // namespace ASDCP
+
+
+#endif // _MXF_H_
+
+//
+// end MXF.h
+//
diff --git a/src/MXFTypes.cpp b/src/MXFTypes.cpp
new file mode 100755
index 0000000..ca65bdf
--- /dev/null
+++ b/src/MXFTypes.cpp
@@ -0,0 +1,284 @@
+
+#include "MXFTypes.h"
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::UTF16String::ReadFrom(ASDCP::MemIOReader& Reader)
+{
+ const byte_t* p = Reader.Data() + Reader.Offset();
+ /// cheating - for all use cases, we know the previous two bytes are the length
+ m_length = ASDCP_i16_BE(cp2i<ui16_t>(p-2));
+ assert(m_length % 2 == 0);
+ m_length /= 2;
+ assert(IdentBufferLen >= m_length);
+ ui32_t i = 0;
+
+ for ( i = 0; i < m_length; i++ )
+ m_buffer[i] = p[(i*2)+1];
+
+ m_buffer[i] = 0;
+
+ Reader.SkipOffset(m_length*2);
+ return RESULT_OK;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::UTF16String::WriteTo(ASDCP::MemIOWriter& Writer)
+{
+ byte_t* p = Writer.Data() + Writer.Size();
+ ui32_t i = 0;
+ m_length = strlen(m_buffer);
+ memset(p, 0, m_length*2);
+
+ for ( i = 0; i < m_length; i++ )
+ p[(i*2)+1] = m_buffer[i];
+
+ m_buffer[i] = 0;
+
+ Writer.AddOffset(m_length*2);
+ return RESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
+ MemIOReader(p, c), m_Lookup(PrimerLookup)
+{
+ Result_t result = RESULT_OK;
+
+ while ( Remainder() > 0 && ASDCP_SUCCESS(result) )
+ {
+ TagValue Tag;
+ ui16_t pkt_len = 0;
+
+ result = MemIOReader::ReadUi8(&Tag.a);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = MemIOReader::ReadUi8(&Tag.b);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = MemIOReader::ReadUi16BE(&pkt_len);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len)));
+ result = SkipOffset(pkt_len);
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ {
+ DefaultLogSink().Error("Malformed Set\n");
+ m_ElementMap.clear();
+ break;
+ }
+ }
+}
+
+//
+bool
+ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry)
+{
+ if ( m_Lookup == 0 )
+ {
+ fprintf(stderr, "No Lookup service\n");
+ return false;
+ }
+
+ TagValue TmpTag;
+
+ if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK )
+ {
+ if ( Entry.tag.a == 0 )
+ {
+ DefaultLogSink().Error("No such UL in this TL list: %s (%02x %02x)\n",
+ Entry.name, Entry.tag.a, Entry.tag.b);
+ return false;
+ }
+
+ TmpTag = Entry.tag;
+ }
+
+ TagMap::iterator e_i = m_ElementMap.find(TmpTag);
+
+ if ( e_i != m_ElementMap.end() )
+ {
+ m_size = (*e_i).second.first;
+ m_capacity = m_size + (*e_i).second.second;
+ return true;
+ }
+
+ // DefaultLogSink().Warn("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name);
+ return false;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, IArchive* Object)
+{
+ ASDCP_TEST_NULL(Object);
+
+ if ( FindTL(Entry) )
+ return Object->ReadFrom(*this);
+
+ return RESULT_FALSE;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value)
+{
+ ASDCP_TEST_NULL(value);
+
+ if ( FindTL(Entry) )
+ return MemIOReader::ReadUi8(value);
+
+ return RESULT_FALSE;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value)
+{
+ ASDCP_TEST_NULL(value);
+
+ if ( FindTL(Entry) )
+ return MemIOReader::ReadUi16BE(value);
+
+ return RESULT_FALSE;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value)
+{
+ ASDCP_TEST_NULL(value);
+
+ if ( FindTL(Entry) )
+ return MemIOReader::ReadUi32BE(value);
+
+ return RESULT_FALSE;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value)
+{
+ ASDCP_TEST_NULL(value);
+
+ if ( FindTL(Entry) )
+ return MemIOReader::ReadUi64BE(value);
+
+ return RESULT_FALSE;
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+ASDCP::MXF::TLVWriter::TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
+ MemIOWriter(p, c), m_Lookup(PrimerLookup)
+{
+ assert(c > 3);
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
+{
+ TagValue TmpTag;
+
+ if ( m_Lookup == 0 )
+ {
+ DefaultLogSink().Error("No Primer object available\n");
+ return RESULT_FAIL;
+ }
+
+ if ( m_Lookup->InsertTag(Entry.ul, TmpTag) != RESULT_OK )
+ {
+ DefaultLogSink().Error("No tag for entry %s\n", Entry.name);
+ return RESULT_FAIL;
+ }
+
+ Result_t result = MemIOWriter::WriteUi8(TmpTag.a);
+ if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi8(TmpTag.b);
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, IArchive* Object)
+{
+ ASDCP_TEST_NULL(Object);
+ Result_t result = WriteTag(Entry);
+
+ // write a temp length
+ byte_t* l_p = CurrentData();
+
+ if ( ASDCP_SUCCESS(result) )
+ MemIOWriter::WriteUi16BE(0);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t before = Size();
+ result = Object->WriteTo(*this);
+
+ if ( ASDCP_SUCCESS(result) )
+ i2p<ui16_t>(ASDCP_i16_BE( Size() - before), l_p);
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
+{
+ ASDCP_TEST_NULL(value);
+ Result_t result = WriteTag(Entry);
+ if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui8_t));
+ if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi8(*value);
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
+{
+ ASDCP_TEST_NULL(value);
+ Result_t result = WriteTag(Entry);
+ if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui16_t));
+ if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi8(*value);
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
+{
+ ASDCP_TEST_NULL(value);
+ Result_t result = WriteTag(Entry);
+ if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui32_t));
+ if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi8(*value);
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
+{
+ ASDCP_TEST_NULL(value);
+ Result_t result = WriteTag(Entry);
+ if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui64_t));
+ if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi8(*value);
+ return result;
+}
+
+//
+// end
+//
diff --git a/src/MXFTypes.h b/src/MXFTypes.h
new file mode 100755
index 0000000..02efbb1
--- /dev/null
+++ b/src/MXFTypes.h
@@ -0,0 +1,285 @@
+//
+// MXFTypes.h
+//
+
+#ifndef _MXFTYPES_H_
+#define _MXFTYPES_H_
+
+
+
+#endif //_MXFTYPES_H_
+
+#include "KLV.h"
+#include <list>
+#include <vector>
+#include <map>
+#include <wchar.h>
+
+// used with TLVReader::Read*
+//
+// these are used below to manufacture arguments
+#define OBJ_READ_ARGS(s,l) s_MDD_Table[MDDindex_##s##_##l], &l
+#define OBJ_READ_ARGS_R(s,l,r) s_MDD_Table[MDDindex_##s##_##l], &r
+
+#define OBJ_WRITE_ARGS(s,l) s_MDD_Table[MDDindex_##s##_##l], &l
+
+#define OBJ_TYPE_ARGS(t) s_MDD_Table[MDDindex_##t].ul
+
+
+namespace ASDCP
+{
+ namespace MXF
+ {
+ typedef std::pair<ui32_t, ui32_t> ItemInfo;
+ typedef std::map<TagValue, ItemInfo> TagMap;
+
+ //
+ class TLVReader : public ASDCP::MemIOReader
+ {
+
+ TagMap m_ElementMap;
+ IPrimerLookup* m_Lookup;
+
+ TLVReader();
+ ASDCP_NO_COPY_CONSTRUCT(TLVReader);
+ bool FindTL(const MDDEntry&);
+
+ public:
+ TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* = 0);
+ Result_t ReadObject(const MDDEntry&, IArchive*);
+ Result_t ReadUi8(const MDDEntry&, ui8_t*);
+ Result_t ReadUi16(const MDDEntry&, ui16_t*);
+ Result_t ReadUi32(const MDDEntry&, ui32_t*);
+ Result_t ReadUi64(const MDDEntry&, ui64_t*);
+ };
+
+ //
+ class TLVWriter : public ASDCP::MemIOWriter
+ {
+
+ TagMap m_ElementMap;
+ IPrimerLookup* m_Lookup;
+
+ TLVWriter();
+ ASDCP_NO_COPY_CONSTRUCT(TLVWriter);
+ Result_t WriteTag(const MDDEntry&);
+
+ public:
+ TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* = 0);
+ Result_t WriteObject(const MDDEntry&, IArchive*);
+ Result_t WriteUi8(const MDDEntry&, ui8_t*);
+ Result_t WriteUi16(const MDDEntry&, ui16_t*);
+ Result_t WriteUi32(const MDDEntry&, ui32_t*);
+ Result_t WriteUi64(const MDDEntry&, ui64_t*);
+ };
+
+ //
+ template <class T>
+ class Batch : public std::vector<T>, public IArchive
+ {
+ public:
+ ui32_t ItemCount;
+ ui32_t ItemSize;
+
+ Batch() : ItemCount(0), ItemSize(0) { ItemSize = sizeof(T); }
+ ~Batch() {}
+
+ //
+ Result_t ReadFrom(ASDCP::MemIOReader& Reader) {
+ Result_t result = Reader.ReadUi32BE(&ItemCount);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.ReadUi32BE(&ItemSize);
+
+ if ( ( ItemCount > 65536 ) || ( ItemSize > 1024 ) )
+ return RESULT_FAIL;
+
+ for ( ui32_t i = 0; i < ItemCount && ASDCP_SUCCESS(result); i++ )
+ {
+ T Tmp;
+ result = Tmp.ReadFrom(Reader);
+
+ if ( ASDCP_SUCCESS(result) )
+ push_back(Tmp);
+ }
+
+ return result;
+ }
+
+ //
+ Result_t WriteTo(ASDCP::MemIOWriter& Writer) {
+ Result_t result = Writer.WriteUi32BE(size());
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.WriteUi32BE(ItemSize);
+
+ typename std::vector<T>::iterator l_i = begin();
+ for ( ; l_i != end() && ASDCP_SUCCESS(result); l_i++ )
+ result = (*l_i).WriteTo(Writer);
+
+ return result;
+ }
+
+ //
+ void Dump(FILE* stream = 0, ui32_t depth = 0)
+ {
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ typename std::vector<T>::iterator i = this->begin();
+ for ( ; i != this->end(); i++ )
+ fprintf(stream, " %s\n", (*i).ToString(identbuf));
+ }
+ };
+
+ //
+ template <class T>
+ class Array : public std::list<T>, public IArchive
+ {
+ public:
+ Array() {}
+ ~Array() {}
+
+ //
+ Result_t ReadFrom(ASDCP::MemIOReader& Reader)
+ {
+ while ( Reader.Remainder() > 0 )
+ {
+ T Tmp;
+ Tmp.ReadFrom(Reader);
+ push_back(Tmp);
+ }
+
+ return RESULT_OK;
+ }
+
+ //
+ Result_t WriteTo(ASDCP::MemIOWriter& Writer) {
+ Result_t result = RESULT_OK;
+ typename std::list<T>::iterator l_i = begin();
+
+ for ( ; l_i != end() && ASDCP_SUCCESS(result); l_i++ )
+ result = (*l_i).WriteTo(Writer);
+
+ return result;
+ }
+
+ //
+ void Dump(FILE* stream = 0, ui32_t depth = 0)
+ {
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ typename std::list<T>::iterator i = this->begin();
+ for ( ; i != this->end(); i++ )
+ fprintf(stream, " %s\n", (*i).ToString(identbuf));
+ }
+ };
+
+ //
+ class Timestamp : public IArchive
+ {
+ public:
+ ui16_t Year;
+ ui8_t Month;
+ ui8_t Day;
+ ui8_t Hour;
+ ui8_t Minute;
+ ui8_t Second;
+ ui8_t mSec_4;
+
+ Timestamp() :
+ Year(0), Month(0), Day(0),
+ Hour(0), Minute(0), Second(0), mSec_4(0) {}
+
+ //
+ inline const char* ToString(char* str_buf) const {
+ sprintf(str_buf, "%04hu-%02hu-%02hu %02hu:%02hu:%02hu.%03hu",
+ Year, Month, Day, Hour, Minute, Second, mSec_4);
+ return str_buf;
+ }
+
+ //
+ inline Result_t ReadFrom(ASDCP::MemIOReader& Reader) {
+ Result_t result = Reader.ReadUi16BE(&Year);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.ReadRaw(&Month, 6);
+
+ return result;
+ }
+
+ //
+ inline Result_t WriteTo(ASDCP::MemIOWriter& Writer) {
+ Result_t result = Writer.WriteUi16BE(Year);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.WriteRaw(&Month, 6);
+
+ return result;
+ }
+ };
+
+ //
+ class UTF16String : public IArchive
+ {
+ ui16_t m_length;
+ char m_buffer[IdentBufferLen];
+
+ public:
+ UTF16String() : m_length(0) { *m_buffer = 0; }
+ ~UTF16String() {}
+
+ //
+ const char* ToString(char* str_buf) const {
+ strncpy(str_buf, m_buffer, m_length+1);
+ return str_buf;
+ }
+
+ Result_t ReadFrom(ASDCP::MemIOReader& Reader);
+ Result_t WriteTo(ASDCP::MemIOWriter& Writer);
+ };
+
+ //
+ class Rational : public ASDCP::Rational, public IArchive
+ {
+ public:
+ Rational() {}
+ ~Rational() {}
+
+ //
+ const char* ToString(char* str_buf) const {
+ sprintf(str_buf, "%lu/%lu", Numerator, Denominator);
+ return str_buf;
+ }
+
+ Result_t ReadFrom(ASDCP::MemIOReader& Reader) {
+ Result_t result = Reader.ReadUi32BE((ui32_t*)&Numerator);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.ReadUi32BE((ui32_t*)&Denominator);
+
+ return result;
+ }
+
+ Result_t WriteTo(ASDCP::MemIOWriter& Writer) {
+ Result_t result = Writer.WriteUi32BE((ui32_t)Numerator);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.WriteUi32BE((ui32_t)Denominator);
+
+ return result;
+ }
+ };
+
+ } // namespace MXF
+} // namespace ASDCP
+
+
+//
+// end MXFTypes.h
+//
diff --git a/src/Metadata.cpp b/src/Metadata.cpp
new file mode 100755
index 0000000..1335803
--- /dev/null
+++ b/src/Metadata.cpp
@@ -0,0 +1,781 @@
+/*
+Copyright (c) 2005-2006, 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 Metadata.cpp
+ \version $Id$
+ \brief AS-DCP library, MXF Metadata Sets implementation
+*/
+
+
+#include "Metadata.h"
+#include "MDD.h"
+#include <hex_utils.h>
+
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Identification::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ ASDCP_TEST_NULL(p);
+
+ Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_Identification].ul);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
+
+ result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Identification, ThisGenerationUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Identification, CompanyName));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Identification, ProductName));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi16(OBJ_READ_ARGS(Identification, ProductVersion));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Identification, VersionString));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Identification, ProductUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Identification, ModificationDate));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi16(OBJ_READ_ARGS(Identification, ToolkitVersion));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Identification, Platform));
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Identification::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_Identification].ul, 0);
+}
+
+
+//
+void
+ASDCP::MXF::Identification::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVPacket::Dump(stream, false);
+ fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
+ fprintf(stream, " ThisGenerationUID = %s\n", ThisGenerationUID.ToString(identbuf));
+ fprintf(stream, " CompanyName = %s\n", CompanyName.ToString(identbuf));
+ fprintf(stream, " ProductName = %s\n", ProductName.ToString(identbuf));
+ fprintf(stream, " ProductVersion = %hu\n", ProductVersion);
+ fprintf(stream, " VersionString = %s\n", VersionString.ToString(identbuf));
+ fprintf(stream, " ProductUID = %s\n", ProductUID.ToString(identbuf));
+ fprintf(stream, " ModificationDate = %s\n", ModificationDate.ToString(identbuf));
+ fprintf(stream, " ToolkitVersion = %hu\n", ToolkitVersion);
+ fprintf(stream, " Platform = %s\n", Platform.ToString(identbuf));
+
+ fputs("==========================================================================\n", stream);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::ContentStorage::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_ContentStorage].ul);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
+
+ result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(ContentStorage, Packages));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(ContentStorage, EssenceContainerData));
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::ContentStorage::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_ContentStorage].ul, 0);
+}
+
+//
+void
+ASDCP::MXF::ContentStorage::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVPacket::Dump(stream, false);
+ fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
+ fprintf(stream, " GenerationUID = %s\n", GenerationUID.ToString(identbuf));
+ fprintf(stream, " Packages:\n"); Packages.Dump(stream);
+ fprintf(stream, " EssenceContainerData:\n"); EssenceContainerData.Dump(stream);
+
+ fputs("==========================================================================\n", stream);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::GenericPackage::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
+
+ Result_t result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
+ // result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenericPackage, PackageUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenericPackage, Name));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenericPackage, PackageCreationDate));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenericPackage, PackageModifiedDate));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenericPackage, Tracks));
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::GenericPackage::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_DefaultObject].ul, 0);
+}
+
+//
+void
+ASDCP::MXF::GenericPackage::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVPacket::Dump(stream, false);
+ fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
+ fprintf(stream, " GenerationUID = %s\n", GenerationUID.ToString(identbuf));
+ fprintf(stream, " PackageUID = %s\n", PackageUID.ToString(identbuf));
+ fprintf(stream, " Name = %s\n", Name.ToString(identbuf));
+ fprintf(stream, " PackageCreationDate= %s\n", PackageCreationDate.ToString(identbuf));
+ fprintf(stream, " PackageModifiedDate= %s\n", PackageModifiedDate.ToString(identbuf));
+ fprintf(stream, " Tracks:\n"); Tracks.Dump(stream);
+
+ fputs("==========================================================================\n", stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::MaterialPackage::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_MaterialPackage].ul);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ return GenericPackage::InitFromBuffer(p, l);
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::MaterialPackage::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_MaterialPackage].ul, 0);
+}
+
+//
+void
+ASDCP::MXF::MaterialPackage::Dump(FILE* stream)
+{
+ GenericPackage::Dump(stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::SourcePackage::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_SourcePackage].ul);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ return GenericPackage::InitFromBuffer(p, l);
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::SourcePackage::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_SourcePackage].ul, 0);
+}
+
+//
+void
+ASDCP::MXF::SourcePackage::Dump(FILE* stream)
+{
+ GenericPackage::Dump(stream);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Track::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ ASDCP_TEST_NULL(p);
+
+ Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_Track].ul);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
+
+ result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(GenericTrack, TrackID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(GenericTrack, TrackNumber));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenericTrack, TrackName));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenericTrack, Sequence));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Track, EditRate));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64(OBJ_READ_ARGS(Track, Origin));
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Track::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_Track].ul, 0);
+}
+
+//
+void
+ASDCP::MXF::Track::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVPacket::Dump(stream, false);
+ fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
+ fprintf(stream, " GenerationUID = %s\n", GenerationUID.ToString(identbuf));
+ fprintf(stream, " TrackID = %lu\n", TrackID);
+ fprintf(stream, " TrackNumber = %lu\n", TrackNumber);
+ fprintf(stream, " TrackName = %s\n", TrackName.ToString(identbuf));
+ fprintf(stream, " Sequence = %s\n", Sequence.ToString(identbuf));
+ fprintf(stream, " EditRate = %s\n", EditRate.ToString(identbuf));
+ fprintf(stream, " Origin = %s\n", i64sz(Origin, identbuf));
+
+ fputs("==========================================================================\n", stream);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Sequence::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ ASDCP_TEST_NULL(p);
+
+ Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_Sequence].ul);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
+
+ result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(StructuralComponent, DataDefinition));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64(OBJ_READ_ARGS(StructuralComponent, Duration));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Sequence, StructuralComponents));
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::Sequence::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_Sequence].ul, 0);
+}
+
+//
+void
+ASDCP::MXF::Sequence::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ const MDDEntry* Entry = GetMDDEntry(DataDefinition.Data());
+
+ KLVPacket::Dump(stream, false);
+ fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
+ fprintf(stream, " DataDefinition = %s (%s)\n", DataDefinition.ToString(identbuf), (Entry ? Entry->name : "Unknown"));
+ fprintf(stream, " Duration = %s\n", ui64sz(Duration, identbuf));
+ fprintf(stream, " StructuralComponents:\n"); StructuralComponents.Dump(stream);
+
+ fputs("==========================================================================\n", stream);
+}
+
+
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::SourceClip::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ ASDCP_TEST_NULL(p);
+
+ Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_SourceClip].ul);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
+
+ result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(StructuralComponent, DataDefinition));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64(OBJ_READ_ARGS(SourceClip, StartPosition));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64(OBJ_READ_ARGS(StructuralComponent, Duration));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(SourceClip, SourcePackageID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(SourceClip, SourceTrackID));
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::SourceClip::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_SourceClip].ul, 0);
+}
+
+//
+void
+ASDCP::MXF::SourceClip::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVPacket::Dump(stream, false);
+ fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
+ fprintf(stream, " DataDefinition = %s\n", DataDefinition.ToString(identbuf));
+ fprintf(stream, " StartPosition = %s\n", ui64sz(StartPosition, identbuf));
+ fprintf(stream, " SourcePackageID = %s\n", SourcePackageID.ToString(identbuf));
+ fprintf(stream, " SourcePackageID = %u\n", SourceTrackID);
+
+ fputs("==========================================================================\n", stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TimecodeComponent::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ ASDCP_TEST_NULL(p);
+
+ Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_TimecodeComponent].ul);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
+
+ result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(StructuralComponent, DataDefinition));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64(OBJ_READ_ARGS(StructuralComponent, Duration));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi16(OBJ_READ_ARGS(TimecodeComponent, RoundedTimecodeBase));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64(OBJ_READ_ARGS(TimecodeComponent, StartTimecode));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi8(OBJ_READ_ARGS(TimecodeComponent, DropFrame));
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::TimecodeComponent::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_TimecodeComponent].ul, 0);
+}
+
+//
+void
+ASDCP::MXF::TimecodeComponent::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVPacket::Dump(stream, false);
+ fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
+ fprintf(stream, " DataDefinition = %s\n", DataDefinition.ToString(identbuf));
+ fprintf(stream, " Duration = %s\n", ui64sz(Duration, identbuf));
+ fprintf(stream, " RoundedTimecodeBase= %u\n", RoundedTimecodeBase);
+ fprintf(stream, " StartTimecode = %s\n", ui64sz(StartTimecode, identbuf));
+ fprintf(stream, " DropFrame = %d\n", DropFrame);
+
+ fputs("==========================================================================\n", stream);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::WaveAudioDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ ASDCP_TEST_NULL(p);
+
+ Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_WaveAudioDescriptor].ul);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
+ MXF::Rational TmpRat;
+
+ //InterchangeObject_InstanceUID
+ result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(FileDescriptor, SampleRate));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64(OBJ_READ_ARGS(FileDescriptor, ContainerDuration));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(FileDescriptor, LinkedTrackID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(FileDescriptor, EssenceContainer));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenericSoundEssenceDescriptor, AudioSamplingRate));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi8(OBJ_READ_ARGS(GenericSoundEssenceDescriptor, Locked));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(GenericSoundEssenceDescriptor, ChannelCount));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(GenericSoundEssenceDescriptor, QuantizationBits));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi16(OBJ_READ_ARGS(WaveAudioDescriptor, BlockAlign));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(WaveAudioDescriptor, AvgBps));
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::WaveAudioDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_WaveAudioDescriptor].ul, 0);
+}
+
+//
+void
+ASDCP::MXF::WaveAudioDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVPacket::Dump(stream, false);
+ fprintf(stream, " InstanceUID: %s\n", InstanceUID.ToString(identbuf));
+ fprintf(stream, " LinkedTrackID: %lu\n", LinkedTrackID);
+ fprintf(stream, " EssenceContainer: %s\n", EssenceContainer.ToString(identbuf));
+ fprintf(stream, "...\n");
+
+ fputs("==========================================================================\n", stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::MPEG2VideoDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ ASDCP_TEST_NULL(p);
+
+ Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_MPEG2VideoDescriptor].ul);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
+ MXF::Rational TmpRat;
+ ui8_t tmp_delay;
+
+ //InterchangeObject_InstanceUID
+ result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS_R(FileDescriptor, SampleRate, TmpRat));
+ SampleRate = TmpRat;
+ ui64_t tmpDuration = 0;
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64(OBJ_READ_ARGS_R(FileDescriptor, ContainerDuration, tmpDuration));
+ ContainerDuration = tmpDuration;
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(FileDescriptor, LinkedTrackID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(FileDescriptor, EssenceContainer));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS_R(GenericPictureEssenceDescriptor, AspectRatio, TmpRat));
+ AspectRatio = TmpRat;
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi8(OBJ_READ_ARGS(GenericPictureEssenceDescriptor, FrameLayout));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(GenericPictureEssenceDescriptor, StoredWidth));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(GenericPictureEssenceDescriptor, StoredHeight));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(CDCIEssenceDescriptor, ComponentDepth));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(CDCIEssenceDescriptor, HorizontalSubsampling));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(CDCIEssenceDescriptor, VerticalSubsampling));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi8(OBJ_READ_ARGS(CDCIEssenceDescriptor, ColorSiting));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi8(OBJ_READ_ARGS(MPEG2VideoDescriptor, CodedContentType));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(MPEG2VideoDescriptor, BitRate));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi8(OBJ_READ_ARGS(MPEG2VideoDescriptor, ProfileAndLevel));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi8(OBJ_READ_ARGS_R(MPEG2VideoDescriptor, LowDelay, tmp_delay));
+ LowDelay = (tmp_delay > 0);
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::MPEG2VideoDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_MPEG2VideoDescriptor].ul, 0);
+}
+
+//
+void
+ASDCP::MXF::MPEG2VideoDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVPacket::Dump(stream, false);
+ fprintf(stream, " InstanceUID: %s\n", InstanceUID.ToString(identbuf));
+ fprintf(stream, " LinkedTrackID: %lu\n", LinkedTrackID);
+ fprintf(stream, " EssenceContainer: %s\n", EssenceContainer.ToString(identbuf));
+ ASDCP::MPEG2::VideoDescriptorDump(*this, stream);
+
+ fputs("==========================================================================\n", stream);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::FileDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ ASDCP_TEST_NULL(p);
+
+ Result_t result = KLVPacket::InitFromBuffer(p, l); // any of a variety of ULs, really
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
+
+ result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenericDescriptor, Locators));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenericDescriptor, SubDescriptors));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(FileDescriptor, LinkedTrackID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(FileDescriptor, SampleRate));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64(OBJ_READ_ARGS(FileDescriptor, ContainerDuration));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(FileDescriptor, EssenceContainer));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(FileDescriptor, Codec));
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::MXF::FileDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_FileDescriptor].ul, 0);
+}
+
+//
+void
+ASDCP::MXF::FileDescriptor::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVPacket::Dump(stream, false);
+ fprintf(stream, " InstanceUID: %s\n", InstanceUID.ToString(identbuf));
+ fprintf(stream, " GenerationUID: %lu\n", GenerationUID.ToString(identbuf));
+ fprintf(stream, " LinkedTrackID: %lu\n", LinkedTrackID);
+ fprintf(stream, " EssenceContainer: %s\n", EssenceContainer.ToString(identbuf));
+ fprintf(stream, "...\n");
+
+ fputs("==========================================================================\n", stream);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::GenericPictureEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_GenericPictureEssenceDescriptor].ul, 0);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::RGBAEssenceDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_RGBAEssenceDescriptor].ul, 0);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::JPEG2000PictureSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+ return WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_JPEG2000PictureSubDescriptor].ul, 0);
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::CryptographicFramework::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ ASDCP_TEST_NULL(p);
+
+ Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_CryptographicFramework].ul);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
+
+ result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(CryptographicFramework, ContextSR));
+ }
+
+ return result;
+}
+
+//
+void
+ASDCP::MXF::CryptographicFramework::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVPacket::Dump(stream, false);
+ fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
+ fprintf(stream, " ContextSR = %s\n", ContextSR.ToString(identbuf));
+
+ fputs("==========================================================================\n", stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+ASDCP::Result_t
+ASDCP::MXF::CryptographicContext::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+ ASDCP_TEST_NULL(p);
+
+ Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_CryptographicContext].ul);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
+
+ result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(CryptographicContext, ContextID));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(CryptographicContext, SourceEssenceContainer));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(CryptographicContext, CipherAlgorithm));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(CryptographicContext, MICAlgorithm));
+ if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(CryptographicContext, CryptographicKeyID));
+ }
+
+ return result;
+}
+
+//
+void
+ASDCP::MXF::CryptographicContext::Dump(FILE* stream)
+{
+ char identbuf[IdentBufferLen];
+
+ if ( stream == 0 )
+ stream = stderr;
+
+ KLVPacket::Dump(stream, false);
+ fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
+ fprintf(stream, " ContextID = %s\n", ContextID.ToString(identbuf));
+ fprintf(stream, " SourceEssenceCnt = %s\n", SourceEssenceContainer.ToString(identbuf));
+ fprintf(stream, " CipherAlgorithm = %s\n", CipherAlgorithm.ToString(identbuf));
+ fprintf(stream, " MICAlgorithm = %s\n", MICAlgorithm.ToString(identbuf));
+ fprintf(stream, " CryptographicKeyID = %s\n", CryptographicKeyID.ToString(identbuf));
+
+ fputs("==========================================================================\n", stream);
+}
+
+//
+// end MXF.cpp
+//
diff --git a/src/Metadata.h b/src/Metadata.h
new file mode 100755
index 0000000..0a04790
--- /dev/null
+++ b/src/Metadata.h
@@ -0,0 +1,389 @@
+//
+//
+// TODO: constructor initializers for all member variables
+//
+
+#ifndef _METADATA_H_
+#define _METADATA_H_
+
+#include "MXF.h"
+
+namespace ASDCP
+{
+ namespace MXF
+ {
+ //
+ class Identification : public InterchangeObject
+ {
+ ASDCP_NO_COPY_CONSTRUCT(Identification);
+
+ public:
+ UUID ThisGenerationUID;
+ UTF16String CompanyName;
+ UTF16String ProductName;
+ ui16_t ProductVersion;
+ UTF16String VersionString;
+ UUID ProductUID;
+ Timestamp ModificationDate;
+ ui16_t ToolkitVersion;
+ UTF16String Platform;
+
+ Identification() {}
+ virtual ~Identification() {}
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual void Dump(FILE* = 0);
+ };
+
+
+ //
+ class ContentStorage : public InterchangeObject
+ {
+ ASDCP_NO_COPY_CONSTRUCT(ContentStorage);
+
+ public:
+ UUID GenerationUID;
+ Batch<UUID> Packages;
+ Batch<UUID> EssenceContainerData;
+
+ ContentStorage() {}
+ virtual ~ContentStorage() {}
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual void Dump(FILE* = 0);
+ };
+
+ //
+ class GenericPackage : public InterchangeObject
+ {
+ ASDCP_NO_COPY_CONSTRUCT(GenericPackage);
+
+ public:
+ UMID PackageUID;
+ UUID GenerationUID;
+ UTF16String Name;
+ Timestamp PackageCreationDate;
+ Timestamp PackageModifiedDate;
+ Batch<UID> Tracks;
+
+ GenericPackage() {}
+ virtual ~GenericPackage() {}
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l) = 0;
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual void Dump(FILE* = 0) = 0;
+ };
+
+
+ //
+ class MaterialPackage : public GenericPackage
+ {
+ ASDCP_NO_COPY_CONSTRUCT(MaterialPackage);
+
+ public:
+ MaterialPackage() {}
+ virtual ~MaterialPackage() {}
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual void Dump(FILE* = 0);
+ };
+
+
+ //
+ class SourcePackage : public GenericPackage
+ {
+ ASDCP_NO_COPY_CONSTRUCT(SourcePackage);
+
+ public:
+ SourcePackage() {}
+ virtual ~SourcePackage() {}
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual void Dump(FILE* = 0);
+ };
+
+ //
+ class Track : public InterchangeObject
+ {
+ ASDCP_NO_COPY_CONSTRUCT(Track);
+
+ public:
+ UUID GenerationUID;
+ ui32_t TrackID;
+ ui32_t TrackNumber;
+ UTF16String TrackName;
+ UUID Sequence;
+ Rational EditRate;
+ ui64_t Origin;
+
+ Track() {}
+ virtual ~Track() {}
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual void Dump(FILE* = 0);
+ };
+
+ //
+ class Sequence : public InterchangeObject
+ {
+ ASDCP_NO_COPY_CONSTRUCT(Sequence);
+
+ public:
+ UUID GenerationUID;
+ UL DataDefinition;
+ ui64_t Duration;
+ Batch<UID> StructuralComponents;
+
+ Sequence() {}
+ virtual ~Sequence() {}
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual void Dump(FILE* = 0);
+ };
+
+ //
+ class SourceClip : public InterchangeObject
+ {
+ ASDCP_NO_COPY_CONSTRUCT(SourceClip);
+
+ public:
+ UUID GenerationUID;
+ UL DataDefinition;
+ ui64_t StartPosition;
+ ui64_t Duration;
+ UMID SourcePackageID;
+ ui32_t SourceTrackID;
+
+ SourceClip() {}
+ virtual ~SourceClip() {}
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual void Dump(FILE* = 0);
+ };
+
+ //
+ class TimecodeComponent : public InterchangeObject
+ {
+ ASDCP_NO_COPY_CONSTRUCT(TimecodeComponent);
+
+ public:
+ UUID GenerationUID;
+ UL DataDefinition;
+ ui64_t Duration;
+ ui16_t RoundedTimecodeBase;
+ ui64_t StartTimecode;
+ ui8_t DropFrame;
+
+ TimecodeComponent() {}
+ virtual ~TimecodeComponent() {}
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual void Dump(FILE* = 0);
+ };
+
+ //
+ class MPEG2VideoDescriptor : public ASDCP::MPEG2::VideoDescriptor, public InterchangeObject
+ {
+ ASDCP_NO_COPY_CONSTRUCT(MPEG2VideoDescriptor);
+
+ public:
+ ui32_t LinkedTrackID;
+ UL EssenceContainer;
+
+ MPEG2VideoDescriptor() : LinkedTrackID(0) {}
+ ~MPEG2VideoDescriptor() {}
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual void Dump(FILE* = 0);
+ };
+
+ //
+ class FileDescriptor : public InterchangeObject
+ {
+ ASDCP_NO_COPY_CONSTRUCT(FileDescriptor);
+
+ public:
+ UUID GenerationUID;
+ Batch<UUID> Locators;
+ Batch<UUID> SubDescriptors;
+ ui32_t LinkedTrackID;
+ Rational SampleRate;
+ ui64_t ContainerDuration;
+ UL EssenceContainer;
+ UL Codec;
+
+ FileDescriptor() : LinkedTrackID(0), ContainerDuration(0) {}
+ ~FileDescriptor() {}
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual void Dump(FILE* = 0);
+ };
+
+ //
+ class WaveAudioDescriptor : public FileDescriptor
+ {
+ ASDCP_NO_COPY_CONSTRUCT(WaveAudioDescriptor);
+
+ public:
+ Rational AudioSamplingRate;
+ ui8_t Locked;
+ i8_t AudioRefLevel;
+ ui8_t ElectroSpatialFormulation;
+ ui32_t ChannelCount;
+ ui32_t QuantizationBits;
+ i8_t DialNorm;
+ UL SoundEssenceCompression;
+ ui16_t BlockAlign;
+ ui8_t SequenceOffset;
+ ui32_t AvgBps;
+ // Stream PeakEnvelope;
+
+ WaveAudioDescriptor() :
+ Locked(false), AudioRefLevel(0), ElectroSpatialFormulation(0),
+ ChannelCount(0), QuantizationBits(0), DialNorm(0), BlockAlign(0),
+ SequenceOffset(0), AvgBps(0) {}
+
+ ~WaveAudioDescriptor() {}
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual void Dump(FILE* = 0);
+ };
+
+ //
+ class GenericPictureEssenceDescriptor : public FileDescriptor
+ {
+ ASDCP_NO_COPY_CONSTRUCT(GenericPictureEssenceDescriptor);
+
+ public:
+ ui8_t FrameLayout;
+ ui32_t StoredWidth;
+ ui32_t StoredHeight;
+ ui32_t DisplayWidth;
+ ui32_t DisplayHeight;
+ Rational AspectRatio;
+ ui32_t ComponentMaxRef;
+ ui32_t ComponentMinRef;
+ UL Gamma;
+ UL PictureEssenceCoding;
+
+ GenericPictureEssenceDescriptor() :
+ FrameLayout(0), StoredWidth(0), StoredHeight(0), DisplayWidth(0),
+ DisplayHeight(0), ComponentMaxRef(0), ComponentMinRef(0) {}
+
+ ~GenericPictureEssenceDescriptor() {}
+ // virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ // virtual void Dump(FILE* = 0);
+ };
+
+ //
+ class RGBAEssenceDescriptor : public GenericPictureEssenceDescriptor
+ {
+ ASDCP_NO_COPY_CONSTRUCT(RGBAEssenceDescriptor);
+
+ public:
+ class RGBLayout
+ {
+ public:
+ struct element {
+ ui8_t Code;
+ ui8_t Depth;
+ } PictureElement[8];
+ RGBLayout() { memset(PictureElement, 0, sizeof(PictureElement)); }
+ };
+
+ RGBLayout PixelLayout;
+
+ RGBAEssenceDescriptor() {}
+ ~RGBAEssenceDescriptor() {}
+ // virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ // virtual void Dump(FILE* = 0);
+ };
+
+ class Raw
+ {
+ ASDCP_NO_COPY_CONSTRUCT(Raw);
+
+ public:
+ byte_t* data;
+ Raw() {}
+ ~Raw() {}
+
+ };
+
+ //
+ class JPEG2000PictureSubDescriptor : public InterchangeObject
+ {
+ ASDCP_NO_COPY_CONSTRUCT(JPEG2000PictureSubDescriptor);
+
+ public:
+ ui16_t Rsize;
+ ui32_t Xsize;
+ ui32_t Ysize;
+ ui32_t XOsize;
+ ui32_t YOsize;
+ ui32_t XTsize;
+ ui32_t YTsize;
+ ui32_t XTOsize;
+ ui32_t YTOsize;
+ ui16_t Csize;
+ Raw PictureComponentSizing;
+ Raw CodingStyleDefault;
+ Raw QuantizationDefault;
+
+ JPEG2000PictureSubDescriptor() :
+ Rsize(0), Xsize(0), Ysize(0),
+ XOsize(0), YOsize(0), XTsize(0),
+ YTsize(0), XTOsize(0), YTOsize(0),
+ Csize(0) {}
+
+ ~JPEG2000PictureSubDescriptor() {}
+ // virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ // virtual void Dump(FILE* = 0);
+ };
+
+
+ //
+ class CryptographicFramework : public InterchangeObject
+ {
+ ASDCP_NO_COPY_CONSTRUCT(CryptographicFramework);
+
+ public:
+ UUID ContextSR;
+
+ CryptographicFramework() {}
+ ~CryptographicFramework() {}
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ // virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual void Dump(FILE* = 0);
+ };
+
+ //
+ class CryptographicContext : public InterchangeObject
+ {
+ ASDCP_NO_COPY_CONSTRUCT(CryptographicContext);
+
+ public:
+ UUID ContextID;
+ UL SourceEssenceContainer;
+ UL CipherAlgorithm;
+ UL MICAlgorithm;
+ UUID CryptographicKeyID;
+
+ CryptographicContext() {}
+ ~CryptographicContext() {}
+ virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+ // virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+ virtual void Dump(FILE* = 0);
+ };
+
+ } // namespace MXF
+} // namespace ASDCP
+
+
+#endif // _METADATA_H_
+
+//
+// end Metadata.h
+//
diff --git a/src/PCMParserList.cpp b/src/PCMParserList.cpp
new file mode 100755
index 0000000..2679162
--- /dev/null
+++ b/src/PCMParserList.cpp
@@ -0,0 +1,213 @@
+/*
+Copyright (c) 2004, 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 PCMParserList.cpp
+ \version $Id$
+ \brief Read WAV file(s), multiplex multiple PCM frame buffers into one
+*/
+
+#include <PCMParserList.h>
+#include <assert.h>
+
+using namespace ASDCP;
+
+
+ASDCP::ParserInstance::ParserInstance() : m_p(0), m_SampleSize(0)
+{
+}
+
+ASDCP::ParserInstance::~ParserInstance()
+{
+}
+
+// PCM::CalcSampleSize(ADesc);
+Result_t
+ASDCP::ParserInstance::OpenRead(const char* filename, Rational& PictureRate)
+{
+ ASDCP_TEST_NULL_STR(filename);
+
+ Result_t result = Parser.OpenRead(filename, PictureRate);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Parser.FillAudioDescriptor(ADesc);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ADesc.SampleRate = PictureRate;
+ m_SampleSize = PCM::CalcSampleSize(ADesc);
+ result = FB.Capacity(PCM::CalcFrameBufferSize(ADesc));
+ }
+
+ return result;
+}
+
+
+// deposit the next available sample into the given framebuffer
+Result_t
+ASDCP::ParserInstance::PutSample(byte_t* p)
+{
+ ASDCP_TEST_NULL(p);
+
+ memcpy(p, m_p, m_SampleSize);
+ m_p += m_SampleSize;
+ return RESULT_OK;
+}
+
+
+//
+Result_t
+ASDCP::ParserInstance::ReadFrame()
+{
+ Result_t result = Parser.ReadFrame(FB);
+ m_p = ASDCP_SUCCESS(result) ? FB.RoData() : 0;
+ return result;
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+
+//
+ASDCP::PCMParserList::PCMParserList() : m_ChannelCount(0)
+{
+}
+
+ASDCP::PCMParserList::~PCMParserList()
+{
+ while ( ! empty() )
+ {
+ delete back();
+ pop_back();
+ }
+}
+
+
+//
+Result_t
+ASDCP::PCMParserList::OpenRead(ui32_t argc, const char** argv, Rational& PictureRate)
+{
+ ASDCP_TEST_NULL_STR(argv);
+ Result_t result = RESULT_OK;
+
+ for ( ui32_t i = 0; i < argc && ASDCP_SUCCESS(result); i++ )
+ {
+ ParserInstance* I = new ParserInstance;
+ result = I->OpenRead(argv[i], PictureRate);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( i == 0 )
+ m_ADesc = I->ADesc;
+
+ else
+ m_ADesc.BlockAlign += I->ADesc.BlockAlign;
+ // result = I->CmpADesc(m_ADesc);
+
+ m_ChannelCount += I->ADesc.ChannelCount;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = I->FB.Capacity(PCM::CalcFrameBufferSize(m_ADesc));
+
+ if ( ASDCP_SUCCESS(result) )
+ push_back(I);
+ }
+
+ m_ADesc.ChannelCount = m_ChannelCount;
+
+ if ( ASDCP_FAILURE(result) )
+ clear();
+
+ return result;
+}
+
+//
+Result_t
+ASDCP::PCMParserList::FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const
+{
+ ADesc = m_ADesc;
+ return RESULT_OK;
+}
+
+//
+Result_t
+ASDCP::PCMParserList::Reset()
+{
+ Result_t result = RESULT_OK;
+ PCMParserList::iterator self_i;
+
+ for ( self_i = begin(); self_i != end() && ASDCP_SUCCESS(result) ; self_i++ )
+ result = (*self_i)->Parser.Reset();
+
+ return result;
+}
+
+
+//
+Result_t
+ASDCP::PCMParserList::ReadFrame(PCM::FrameBuffer& OutFB)
+{
+ Result_t result = RESULT_OK;
+
+ if ( size() == 1 )
+ return front()->Parser.ReadFrame(OutFB);
+
+ PCMParserList::iterator self_i;
+ assert(PCM::CalcFrameBufferSize(m_ADesc) <= OutFB.Capacity());
+
+ for ( self_i = begin(); self_i != end() && ASDCP_SUCCESS(result) ; self_i++ )
+ result = (*self_i)->ReadFrame();
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ OutFB.Size(PCM::CalcFrameBufferSize(m_ADesc));
+
+ // ui32_t sample_size = (PCM::CalcSampleSize(m_ADesc));
+ byte_t* Out_p = OutFB.Data();
+ byte_t* End_p = Out_p + OutFB.Size();
+
+ while ( Out_p < End_p && ASDCP_SUCCESS(result) )
+ {
+ self_i = begin();
+
+ while ( self_i != end() && ASDCP_SUCCESS(result) )
+ {
+ result = (*self_i)->PutSample(Out_p);
+ Out_p += (*self_i)->SampleSize();
+ self_i++;
+ }
+ }
+
+ assert(Out_p == End_p);
+ }
+
+ return result;
+}
+
+//
+// end PCMParserList.cpp
+//
diff --git a/src/PCMParserList.h b/src/PCMParserList.h
new file mode 100755
index 0000000..e6bf20b
--- /dev/null
+++ b/src/PCMParserList.h
@@ -0,0 +1,86 @@
+/*
+Copyright (c) 2004, 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 PCMParserList.h
+ \version $Id$
+ \brief Read WAV file(s), multiplex multiple PCM frame buffers into one
+*/
+
+#ifndef _PCMPARSERLIST_H_
+#define _PCMPARSERLIST_H_
+
+#include <AS_DCP.h>
+#include <vector>
+
+namespace ASDCP
+{
+ //
+ class ParserInstance
+ {
+ const byte_t* m_p;
+ ui32_t m_SampleSize;
+
+ ASDCP_NO_COPY_CONSTRUCT(ParserInstance);
+
+ public:
+ PCM::WAVParser Parser;
+ PCM::FrameBuffer FB;
+ PCM::AudioDescriptor ADesc;
+
+ ParserInstance();
+ virtual ~ParserInstance();
+
+ Result_t OpenRead(const char* filename, Rational& PictureRate);
+ Result_t PutSample(byte_t* p);
+ Result_t ReadFrame();
+ inline ui32_t SampleSize() { return m_SampleSize; }
+ };
+
+ //
+ class PCMParserList : public std::vector<ParserInstance*>
+ {
+ PCM::AudioDescriptor m_ADesc;
+ ui32_t m_ChannelCount;
+
+ ASDCP_NO_COPY_CONSTRUCT(PCMParserList);
+
+ public:
+ PCMParserList();
+ virtual ~PCMParserList();
+
+ Result_t OpenRead(ui32_t argc, const char** argv, Rational& PictureRate);
+ Result_t FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const;
+ Result_t Reset();
+ Result_t ReadFrame(PCM::FrameBuffer& OutFB);
+ };
+}
+
+
+#endif // _PCMPARSERLIST_H_
+
+//
+// end PCMParserList.h
+//
diff --git a/src/PCM_Parser.cpp b/src/PCM_Parser.cpp
new file mode 100755
index 0000000..70cc277
--- /dev/null
+++ b/src/PCM_Parser.cpp
@@ -0,0 +1,214 @@
+/*
+Copyright (c) 2004, 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 PCM_Parser.cpp
+ \version $Id$
+ \brief AS-DCP library, PCM raw essence reader implementation
+*/
+
+#include <Wav.h>
+#include <assert.h>
+
+using namespace ASDCP;
+using namespace ASDCP::PCM;
+using namespace ASDCP::Wav;
+
+
+//------------------------------------------------------------------------------------------
+
+//
+class ASDCP::PCM::WAVParser::h__WAVParser
+{
+ FileReader m_FileReader;
+ bool m_EOF;
+ ui32_t m_DataStart;
+ ui32_t m_DataLength;
+ ui32_t m_ReadCount;
+ ui32_t m_FrameBufferSize;
+ ui32_t m_FramesRead;
+ Rational m_PictureRate;
+
+ ASDCP_NO_COPY_CONSTRUCT(h__WAVParser);
+
+public:
+ AudioDescriptor m_ADesc;
+
+
+ h__WAVParser() :
+ m_EOF(false), m_DataStart(0), m_DataLength(0), m_ReadCount(0),
+ m_FrameBufferSize(0), m_FramesRead(0) {}
+
+ ~h__WAVParser()
+ {
+ Close();
+ }
+
+ Result_t OpenRead(const char* filename, const Rational& PictureRate);
+ void Close();
+ void Reset();
+ Result_t ReadFrame(FrameBuffer&);
+};
+
+
+//
+void
+ASDCP::PCM::WAVParser::h__WAVParser::Close()
+{
+ m_FileReader.Close();
+}
+
+//
+void
+ASDCP::PCM::WAVParser::h__WAVParser::Reset()
+{
+ m_FileReader.Seek(m_DataStart);
+ m_FramesRead = 0;
+ m_ReadCount = 0;
+}
+
+//
+ASDCP::Result_t
+ASDCP::PCM::WAVParser::h__WAVParser::OpenRead(const char* filename, const Rational& PictureRate)
+{
+ ASDCP_TEST_NULL_STR(filename);
+ SimpleWaveHeader WavHeader;
+
+ Result_t result = m_FileReader.OpenRead(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = WavHeader.ReadFromFile(m_FileReader, &m_DataStart);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ WavHeader.FillADesc(m_ADesc, PictureRate);
+ m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc);
+ m_DataLength = WavHeader.data_len;
+ m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize;
+ Reset();
+ }
+
+ return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::PCM::WAVParser::h__WAVParser::ReadFrame(FrameBuffer& FB)
+{
+ FB.Size(0);
+
+ if ( m_EOF || m_ReadCount >= m_DataLength )
+ return RESULT_ENDOFFILE;
+
+ if ( FB.Capacity() < m_FrameBufferSize )
+ {
+ DefaultLogSink().Error("FrameBuf.Capacity: %lu FrameLength: %lu\n",
+ FB.Capacity(), m_FrameBufferSize);
+ return RESULT_SMALLBUF;
+ }
+
+ ui32_t read_count = 0;
+ Result_t result = m_FileReader.Read(FB.Data(), m_FrameBufferSize, &read_count);
+
+ if ( result == RESULT_ENDOFFILE )
+ {
+ m_EOF = true;
+
+ if ( read_count > 0 )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_ReadCount += read_count;
+ FB.Size(read_count);
+ FB.FrameNumber(m_FramesRead++);
+ }
+
+ return result;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::PCM::WAVParser::WAVParser()
+{
+}
+
+ASDCP::PCM::WAVParser::~WAVParser()
+{
+}
+
+// Opens the stream for reading, parses enough data to provide a complete
+// set of stream metadata for the MXFWriter below.
+ASDCP::Result_t
+ASDCP::PCM::WAVParser::OpenRead(const char* filename, const Rational& PictureRate) const
+{
+ const_cast<ASDCP::PCM::WAVParser*>(this)->m_Parser = new h__WAVParser;
+
+ Result_t result = m_Parser->OpenRead(filename, PictureRate);
+
+ if ( ASDCP_FAILURE(result) )
+ const_cast<ASDCP::PCM::WAVParser*>(this)->m_Parser.release();
+
+ return result;
+}
+
+// Rewinds the stream to the beginning.
+ASDCP::Result_t
+ASDCP::PCM::WAVParser::Reset() const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ m_Parser->Reset();
+ return RESULT_OK;
+}
+
+// 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::PCM::WAVParser::ReadFrame(FrameBuffer& FB) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ return m_Parser->ReadFrame(FB);
+}
+
+ASDCP::Result_t
+ASDCP::PCM::WAVParser::FillAudioDescriptor(AudioDescriptor& ADesc) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ ADesc = m_Parser->m_ADesc;
+ return RESULT_OK;
+}
+
+
+//
+// end PCM_Parser.cpp
+//
diff --git a/src/Wav.cpp b/src/Wav.cpp
new file mode 100755
index 0000000..42e0d21
--- /dev/null
+++ b/src/Wav.cpp
@@ -0,0 +1,207 @@
+/*
+Copyright (c) 2005, 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 Wav.cpp
+ \version $Id$
+ \brief Wave file common elements
+*/
+
+#include <Wav.h>
+#include <assert.h>
+
+
+const ui32_t SimpleHeaderLength = 46;
+
+//
+ASDCP::Wav::SimpleWaveHeader::SimpleWaveHeader(ASDCP::PCM::AudioDescriptor& ADesc)
+{
+ format = 1;
+ nchannels = ADesc.ChannelCount;
+ bitspersample = ADesc.QuantizationBits;
+ samplespersec = (ui32_t)ceil(ADesc.AudioSamplingRate.Quotient());
+ avgbps = samplespersec * nchannels * ((bitspersample + 7) / 8);
+ blockalign = nchannels * ((bitspersample + 7) / 8);
+ cbsize = 0;
+ data_len = ASDCP::PCM::CalcFrameBufferSize(ADesc) * ADesc.ContainerDuration;
+}
+
+//
+void
+ASDCP::Wav::SimpleWaveHeader::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const
+{
+ ADesc.SampleRate = 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;
+}
+
+
+//
+ASDCP::Result_t
+ASDCP::Wav::SimpleWaveHeader::WriteToFile(ASDCP::FileWriter& OutFile) const
+{
+ ui32_t write_count;
+ byte_t tmp_header[SimpleHeaderLength];
+ byte_t* p = tmp_header;
+
+ static ui32_t fmt_len =
+ sizeof(format)
+ + sizeof(nchannels)
+ + sizeof(samplespersec)
+ + sizeof(avgbps)
+ + sizeof(blockalign)
+ + sizeof(bitspersample)
+ + sizeof(cbsize);
+
+ ui32_t RIFF_len = data_len + SimpleHeaderLength - 8;
+
+ memcpy(p, &FCC_RIFF, sizeof(fourcc)); p += 4;
+ *((ui32_t*)p) = ASDCP_i32_LE(RIFF_len); p += 4;
+ memcpy(p, &FCC_WAVE, sizeof(fourcc)); p += 4;
+ memcpy(p, &FCC_fmt_, sizeof(fourcc)); p += 4;
+ *((ui32_t*)p) = ASDCP_i32_LE(fmt_len); p += 4;
+ *((ui16_t*)p) = ASDCP_i16_LE(format); p += 2;
+ *((ui16_t*)p) = ASDCP_i16_LE(nchannels); p += 2;
+ *((ui32_t*)p) = ASDCP_i32_LE(samplespersec); p += 4;
+ *((ui32_t*)p) = ASDCP_i32_LE(avgbps); p += 4;
+ *((ui16_t*)p) = ASDCP_i16_LE(blockalign); p += 2;
+ *((ui16_t*)p) = ASDCP_i16_LE(bitspersample); p += 2;
+ *((ui16_t*)p) = ASDCP_i16_LE(cbsize); p += 2;
+ memcpy(p, &FCC_data, sizeof(fourcc)); p += 4;
+ *((ui32_t*)p) = ASDCP_i32_LE(data_len); p += 4;
+
+ return OutFile.Write(tmp_header, SimpleHeaderLength, &write_count);
+}
+
+//
+ASDCP::Result_t
+ASDCP::Wav::SimpleWaveHeader::ReadFromFile(const ASDCP::FileReader& InFile, ui32_t* data_start)
+{
+ ui32_t read_count = 0;
+ ui32_t local_data_start = 0;
+ ASDCP::PCM::FrameBuffer TmpBuffer(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);
+
+ return result;
+}
+
+ASDCP::Result_t
+ASDCP::Wav::SimpleWaveHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start)
+{
+ if ( buf_len < SimpleHeaderLength )
+ return RESULT_SMALLBUF;
+
+ *data_start = 0;
+ const byte_t* p = buf;
+ const byte_t* end_p = p + buf_len;
+
+ fourcc test_RIFF(p); p += 4;
+ if ( test_RIFF != FCC_RIFF )
+ {
+ DefaultLogSink().Error("Files does not begin with RIFF header\n");
+ return RESULT_RAW_FORMAT;
+ }
+
+ ui32_t RIFF_len = ASDCP_i32_LE(*(ui32_t*)p); p += 4;
+
+ fourcc test_WAVE(p); p += 4;
+ if ( test_WAVE != FCC_WAVE )
+ {
+ DefaultLogSink().Error("Files does not begin with WAVE header\n");
+ return RESULT_RAW_FORMAT;
+ }
+
+ fourcc test_fcc;
+
+ while ( p < end_p )
+ {
+ test_fcc = fourcc(p); p += 4;
+ ui32_t chunk_size = ASDCP_i32_LE(*(ui32_t*)p); p += 4;
+
+ if ( test_fcc == FCC_data )
+ {
+ if ( chunk_size > RIFF_len )
+ {
+ DefaultLogSink().Error("Chunk size %lu larger than file: %lu\n", chunk_size, RIFF_len);
+ return RESULT_RAW_FORMAT;
+ }
+
+ data_len = chunk_size;
+ *data_start = p - buf;
+ break;
+ }
+
+ if ( test_fcc == FCC_fmt_ )
+ {
+ ui16_t format = ASDCP_i16_LE(*(ui16_t*)p); p += 2;
+
+ if ( format != 1 )
+ {
+ DefaultLogSink().Error("Expecting uncompressed essence, got format type %hu\n", format);
+ return RESULT_RAW_FORMAT;
+ }
+
+ nchannels = ASDCP_i16_LE(*(ui16_t*)p); p += 2;
+ samplespersec = ASDCP_i32_LE(*(ui32_t*)p); p += 4;
+ avgbps = ASDCP_i32_LE(*(ui32_t*)p); p += 4;
+ blockalign = ASDCP_i16_LE(*(ui16_t*)p); p += 2;
+ bitspersample = ASDCP_i16_LE(*(ui16_t*)p); p += 2;
+ p += chunk_size - 16;
+ }
+ 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
new file mode 100755
index 0000000..a04c92f
--- /dev/null
+++ b/src/Wav.h
@@ -0,0 +1,95 @@
+/*
+Copyright (c) 2005, 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 Wav.h
+ \version $Id$
+ \brief Wave file common elements
+*/
+
+#ifndef _WAV_H_
+#define _WAV_H_
+
+#include <FileIO.h>
+
+namespace ASDCP
+{
+namespace Wav
+{
+ const ui32_t MaxWavHeader = 1024*32; // must find "data" within this space or no happy
+
+ //
+ class fourcc
+ {
+ private:
+ byte_t data[4];
+
+ public:
+ inline fourcc() { memset( data, 0, 4 ); }
+ inline fourcc( const char* v ) { memcpy( this->data, v, 4 ); }
+ inline fourcc( const byte_t* v ) { memcpy( this->data, v, 4 ); }
+ inline fourcc& operator=(const fourcc & s) { memcpy( this->data, s.data, 4); return *this; }
+ inline bool operator==(const fourcc &rhs) { return memcmp(data, rhs.data, 4) == 0 ? true : false; }
+ inline bool operator!=(const fourcc &rhs) { return memcmp(data, rhs.data, 4) != 0 ? true : false; }
+ };
+
+ const fourcc FCC_RIFF("RIFF");
+ const fourcc FCC_WAVE("WAVE");
+ const fourcc FCC_fmt_("fmt ");
+ const fourcc FCC_data("data");
+
+ //
+ class SimpleWaveHeader
+ {
+ public:
+ ui16_t format;
+ ui16_t nchannels;
+ ui32_t samplespersec;
+ ui32_t avgbps;
+ ui16_t blockalign;
+ ui16_t bitspersample;
+ ui16_t cbsize;
+ ui32_t data_len;
+
+ SimpleWaveHeader() :
+ format(0), nchannels(0), samplespersec(0), avgbps(0),
+ blockalign(0), bitspersample(0), cbsize(0), data_len(0) {}
+
+ SimpleWaveHeader(ASDCP::PCM::AudioDescriptor& ADesc);
+
+ Result_t ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start);
+ Result_t ReadFromFile(const ASDCP::FileReader& InFile, ui32_t* data_start);
+ Result_t WriteToFile(ASDCP::FileWriter& OutFile) const;
+ void FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, Rational PictureRate) const;
+ };
+
+} // namespace Wav
+} // namespace ASDCP
+
+#endif // _WAV_H_
+
+//
+// end Wav.h
+//
diff --git a/src/WavFileWriter.h b/src/WavFileWriter.h
new file mode 100755
index 0000000..250cc20
--- /dev/null
+++ b/src/WavFileWriter.h
@@ -0,0 +1,120 @@
+/*
+Copyright (c) 2005, 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 WavFileWriter.h
+ \version $Id$
+ \brief demux and write PCM data to WAV file(s)
+*/
+
+#include <FileIO.h>
+#include <Wav.h>
+#include <list>
+
+#ifndef _WAVFILEWRITER_H_
+#define _WAVFILEWRITER_H_
+
+//
+class WavFileWriter
+{
+ ASDCP::PCM::AudioDescriptor m_ADesc;
+ std::list<ASDCP::FileWriter*> m_OutFile;
+ ASDCP_NO_COPY_CONSTRUCT(WavFileWriter);
+
+ public:
+ WavFileWriter() {}
+ ~WavFileWriter()
+ {
+ while ( ! m_OutFile.empty() )
+ {
+ delete m_OutFile.back();
+ m_OutFile.pop_back();
+ }
+ }
+
+ ASDCP::Result_t
+ OpenWrite(ASDCP::PCM::AudioDescriptor &ADesc, const char* file_root, bool split)
+ {
+ ASDCP_TEST_NULL_STR(file_root);
+ char filename[256];
+ ui32_t file_count = 1;
+ ASDCP::Result_t result = ASDCP::RESULT_OK;
+ m_ADesc = ADesc;
+
+ if ( split )
+ {
+ assert ( m_ADesc.ChannelCount % 2 == 0 ); // no support yet for stuffing odd files
+ file_count = m_ADesc.ChannelCount / 2;
+ m_ADesc.ChannelCount = 2;
+ }
+
+ for ( ui32_t i = 0; i < file_count && ASDCP_SUCCESS(result); i++ )
+ {
+ sprintf(filename, "%s_%lu.wav", file_root, (i + 1));
+ m_OutFile.push_back(new ASDCP::FileWriter);
+ result = m_OutFile.back()->OpenWrite(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ASDCP::Wav::SimpleWaveHeader Wav(m_ADesc);
+ result = Wav.WriteToFile(*(m_OutFile.back()));
+ }
+ }
+
+ return result;
+ }
+
+ ASDCP::Result_t
+ WriteFrame(ASDCP::PCM::FrameBuffer& FB)
+ {
+ ui32_t write_count;
+ ASDCP::Result_t result = ASDCP::RESULT_OK;
+ std::list<ASDCP::FileWriter*>::iterator fi;
+ assert(! m_OutFile.empty());
+
+ ui32_t sample_size = ASDCP::PCM::CalcSampleSize(m_ADesc);
+ const byte_t* p = FB.RoData();
+ const byte_t* end_p = p + FB.Size();
+
+ while ( p < end_p )
+ {
+ for ( fi = m_OutFile.begin(); fi != m_OutFile.end() && ASDCP_SUCCESS(result); fi++ )
+ {
+ result = (*fi)->Write(p, sample_size, &write_count);
+ assert(write_count == sample_size);
+ p += sample_size;
+ }
+ }
+
+ return result;
+ }
+};
+
+
+#endif // _WAVFILEWRITER_H_
+
+//
+// end WavFileWriter.h
+//
diff --git a/src/asdcp-mem-test.cpp b/src/asdcp-mem-test.cpp
new file mode 100755
index 0000000..b199abe
--- /dev/null
+++ b/src/asdcp-mem-test.cpp
@@ -0,0 +1,152 @@
+/*
+Copyright (c) 2004, 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 asdcp-mem-test.cpp
+ \version $Id$
+ \brief AS-DCP frame buffer allocation test
+*/
+
+
+#include <AS_DCP_internal.h>
+#include <FortunaRNG.h>
+
+#include <iostream>
+#include <assert.h>
+
+using namespace ASDCP;
+
+const ui32_t buf_size = 1024;
+FortunaRNG RNG;
+
+//
+int a()
+{
+ FrameBuffer FB;
+ FB.Capacity(buf_size);
+ assert(FB.Capacity() == buf_size);
+ RNG.FillRandom(FB.Data(), FB.Capacity());
+
+ return 0;
+}
+
+//
+int b()
+{
+ byte_t* buf = (byte_t*)malloc(buf_size);
+ assert(buf);
+ RNG.FillRandom(buf, buf_size);
+
+ {
+ FrameBuffer FB;
+ FB.SetData(buf, buf_size);
+ assert(FB.Data() == buf);
+ assert(FB.Capacity() == buf_size);
+ // ~FB() is called...
+ }
+
+ free(buf);
+ return 0;
+}
+
+//
+int c()
+{
+ byte_t* buf = (byte_t*)malloc(buf_size);
+ assert(buf);
+ RNG.FillRandom(buf, buf_size);
+
+ {
+ FrameBuffer FB;
+ FB.SetData(buf, buf_size);
+ assert(FB.Data() == buf);
+ assert(FB.Capacity() == buf_size);
+
+ FB.SetData(0,0);
+ assert(FB.Data() == 0);
+ assert(FB.Capacity() == 0);
+
+ FB.Capacity(buf_size);
+ assert(FB.Capacity() == buf_size);
+ RNG.FillRandom(FB.Data(), FB.Capacity());
+ // ~FB() is called...
+ }
+
+ free(buf);
+ return 0;
+}
+
+//
+int d()
+{
+ mem_ptr<DataChunk> Chunk(new DataChunk(1024));
+
+
+#if 0
+
+ // MPEG2::Parser mPFile;
+ MPEG2::MXFReader mRFile;
+ Result_t result = mRFile.OpenRead("../test/write_test_mpeg.mxf");
+ assert(ASDCP_SUCCESS(result));
+
+ // MPEG2::MXFWriter mWFile;
+ JP2K::CodestreamParser jPCFile;
+ JP2K::SequenceParser jPSFile;
+ JP2K::MXFReader jRFile;
+ JP2K::MXFWriter jWFile;
+
+ PCM::WAVParser pPFile;
+ PCM::MXFReader pRFile;
+ PCM::MXFWriter pWFile;
+#endif
+ return 0;
+}
+
+//
+int
+main( int argc, char **argv )
+{
+ ui32_t i = 0x00010000;
+ fputs("Watch your process monitor, memory usage should not change after startup.\n", stderr);
+
+ while ( i-- )
+ {
+ a();
+ b();
+ c();
+ d();
+
+ if ( i && ( i % 1000 ) == 0 )
+ fputc('.', stderr);
+ }
+
+ fputc('\n', stderr);
+ return 0;
+}
+
+
+//
+// end asdcp-mem-test.cpp
+//
diff --git a/src/asdcp-test.cpp b/src/asdcp-test.cpp
new file mode 100755
index 0000000..c034626
--- /dev/null
+++ b/src/asdcp-test.cpp
@@ -0,0 +1,1366 @@
+/*
+Copyright (c) 2003-2005, 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 asdcp-test.cpp
+ \version $Id$
+ \brief AS-DCP file manipulation utility
+
+ This program provides command line access to the major features of the asdcplib
+ library, and serves as a library unit test which provides the functionality of
+ the supported use cases.
+
+ For more information about asdcplib, please refer to the header file AS_DCP.h
+
+ WARNING: While the asdcplib library attempts to provide a complete and secure
+ implementation of the cryptographic features of the AS-DCP file formats, this
+ unit test program is NOT secure and is therefore NOT SUITABLE FOR USE in a
+ production environment without some modification.
+
+ In particular, this program uses weak IV generation and externally generated
+ plaintext keys. These shortcomings exist because cryptographic-quality
+ random number generation and key management are outside the scope of the
+ asdcplib library. Developers using asdcplib for commercial implementations
+ claiming SMPTE conformance are expected to provide proper implementations of
+ these features.
+*/
+
+#include <iostream>
+#include <assert.h>
+
+#include <FileIO.h>
+#include <PCMParserList.h>
+#include <WavFileWriter.h>
+#include <hex_utils.h>
+#include <AS_DCP_UUID.h>
+#include <MXF.h>
+#include <Metadata.h>
+
+using namespace ASDCP;
+
+const ui32_t FRAME_BUFFER_SIZE = 4*1024*1024;
+
+//------------------------------------------------------------------------------------------
+//
+// command line option parser class
+
+static const char* PACKAGE = "asdcp-test"; // program name for messages
+const ui32_t MAX_IN_FILES = 16; // maximum number of input files handled by
+ // the command option parser
+
+// local program identification info written to file headers
+class MyInfo : public WriterInfo
+{
+public:
+ MyInfo()
+ {
+ 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-test";
+
+ char s_buf[128];
+ sprintf(s_buf, "%lu.%lu.%lu", VERSION_MAJOR, VERSION_APIMINOR, VERSION_IMPMINOR);
+ ProductVersion = s_buf;
+ }
+} s_MyInfo;
+
+
+// Macros used to test command option data state.
+
+// True if a major mode has already been selected.
+#define TEST_MAJOR_MODE() ( info_flag||create_flag||extract_flag||genkey_flag||genid_flag||gop_start_flag )
+
+// Causes the caller to return if a major mode has already been selected,
+// otherwise sets the given flag.
+#define TEST_SET_MAJOR_MODE(f) if ( TEST_MAJOR_MODE() ) \
+ { \
+ fputs("Conflicting major mode, choose one of -(gcixG)).\n", stderr); \
+ return; \
+ } \
+ (f) = true;
+
+// Increment the iterator, test for an additional non-option command line argument.
+// Causes the caller to return if there are no remaining arguments or if the next
+// argument begins with '-'.
+#define TEST_EXTRA_ARG(i,c) if ( ++i >= argc || argv[(i)][0] == '-' ) \
+ { \
+ fprintf(stderr, "Argument not found for option %c.\n", (c)); \
+ return; \
+ }
+//
+void
+banner(FILE* stream = stderr)
+{
+ fprintf(stream, "\n\
+%s (asdcplib %s)\n\n\
+Copyright (c) 2003-2005 John Hurst\n\n\
+asdcplib may be copied only under the terms of the license found at\n\
+the top of every file in the asdcplib distribution kit.\n\n\
+Specify the -h (help) option for further information about %s\n\n",
+ PACKAGE, ASDCP::Version(), PACKAGE);
+}
+
+//
+void
+usage(FILE* stream = stderr)
+{
+ fprintf(stream, "\
+USAGE: %s [-i [-H, -n]|-c <filename> [-p <rate>, -e, -M, -R]|-x <root-name> [-m][-S]|-g|-u|-G|-V|-h]\n\
+ [-k <key-string>] [-j <key-id-string>] [-f <start-frame-num>] [-d <duration>]\n\
+ [-b <buf-size>] [-W] [-v [-s]] [<filename>, ...]\n\
+\n", PACKAGE);
+
+ fprintf(stream, "\
+Major modes:\n\
+ -i - show file info\n\
+ -c <filename> - create AS-DCP file from input(s)\n\
+ -x <root-name> - extract essence from AS-DCP file to named file(s)\n\
+ -g - generate a random 16 byte value to stdout\n\
+ -u - generate a random UUID value to stdout\n\
+ -G - Perform GOP start lookup test on MPEG file\n\
+ -V - show version\n\
+ -h - show help\n\
+\n");
+
+ fprintf(stream, "\
+Security Options:\n\
+ -j <key-id-str> - write key ID instead of creating a random value\n\
+ -k <key-string> - use key for ciphertext operations\n\
+ -e - encrypt MPEG or JP2K headers (default)\n\
+ -E - do not encrypt MPEG or JP2K headers\n\
+ -M - do not create HMAC values when writing\n\
+ -m - verify HMAC values when reading\n\
+\n");
+
+ fprintf(stream, "\
+Read/Write Options:\n\
+ -b <buf-size> - Size (in bytes) of the picture frame buffer, default: 2097152 (2MB)\n\
+ -f <frame-num> - starting frame number, default 0\n\
+ -d <duration> - number of frames to process, default all\n\
+ -p <rate> - fps of picture when wrapping PCM or JP2K:, use one of [23|24|48], 24 is default\n\
+ -R - Repeat the first frame over the entire file (picture essence only, requires -c, -d)\n\
+ -S - Split Wave essence to stereo WAV files during extract (default = multichannel WAV)\n\
+ -W - read input file only, do not write source file\n\
+\n");
+
+ fprintf(stream, "\
+Info Options:\n\
+ -H - show MXF header metadata, used with option -i\n\
+ -n - show index, used with option -i\n\
+\n\
+Other Options:\n\
+ -s <number> - number of bytes of frame buffer to be dumped as hex to stderr (use with -v)\n\
+ -v - verbose, show extra detail during run\n\
+\n\
+ NOTES: o There is no option grouping, all options must be distinct arguments.\n\
+ o All option arguments must be separated from the option by whitespace.\n\
+ o An argument of \"23\" to the -p option will be interpreted as 23000/1001 fps.\n\
+\n");
+}
+
+//
+//
+class CommandOptions
+{
+ CommandOptions();
+
+public:
+ bool error_flag; // true if the given options are in error or not complete
+ bool info_flag; // true if the file info mode was selected
+ bool create_flag; // true if the file create mode was selected
+ bool extract_flag; // true if the file extract mode was selected
+ bool genkey_flag; // true if we are to generate a new key value
+ bool genid_flag; // true if we are to generate a new UUID value
+ bool gop_start_flag; // true if we are to perform a GOP start lookup test
+ bool key_flag; // true if an encryption key was given
+ bool key_id_flag; // true if a key ID was given
+ bool encrypt_header_flag; // true if mpeg headers are to be encrypted
+ bool write_hmac; // true if HMAC values are to be generated and written
+ bool read_hmac; // true if HMAC values are to be validated
+ bool split_wav; // true if PCM is to be extracted to stereo WAV files
+ bool verbose_flag; // true if the verbose option was selected
+ ui32_t fb_dump_size; // number of bytes of frame buffer to dump
+ bool showindex_flag; // true if index is to be displayed
+ bool showheader_flag; // true if MXF file header is to be displayed
+ bool no_write_flag; // true if no output files are to be written
+ bool version_flag; // true if the version display option was selected
+ bool help_flag; // true if the help display option was selected
+ ui32_t start_frame; // frame number to begin processing
+ ui32_t duration; // number of frames to be processed
+ bool duration_flag; // true if duration argument given
+ bool do_repeat; // if true and -c -d, repeat first input frame
+ ui32_t picture_rate; // fps of picture when wrapping PCM
+ ui32_t fb_size; // size of picture frame buffer
+ ui32_t file_count; // number of elements in filenames[]
+ const char* file_root; // filename pre for files written by the extract mode
+ const char* out_file; // name of mxf file created by create mode
+ byte_t key_value[KeyLen]; // value of given encryption key (when key_flag is true)
+ byte_t key_id_value[KeyIDlen];// value of given key ID (when key_id_flag is true)
+ const char* filenames[MAX_IN_FILES]; // list of filenames to be processed
+
+ //
+ Rational PictureRate()
+ {
+ if ( picture_rate == 23 ) return EditRate_23_98;
+ if ( picture_rate == 48 ) return EditRate_48;
+ return EditRate_24;
+ }
+
+ //
+ const char* szPictureRate()
+ {
+ if ( picture_rate == 23 ) return "23.976";
+ if ( picture_rate == 48 ) return "48";
+ return "24";
+ }
+
+ //
+ CommandOptions(int argc, const char** argv) :
+ error_flag(true), info_flag(false), create_flag(false),
+ extract_flag(false), genkey_flag(false), genid_flag(false), gop_start_flag(false),
+ key_flag(false), encrypt_header_flag(true), write_hmac(true), read_hmac(false), split_wav(false),
+ verbose_flag(false), fb_dump_size(0), showindex_flag(false), showheader_flag(false),
+ no_write_flag(false), version_flag(false), help_flag(false), start_frame(0),
+ duration(0xffffffff), duration_flag(false), do_repeat(false), picture_rate(24),
+ fb_size(FRAME_BUFFER_SIZE), file_count(0), file_root(0), out_file(0)
+ {
+ memset(key_value, 0, KeyLen);
+ memset(key_id_value, 0, KeyIDlen);
+
+ for ( int i = 1; i < argc; i++ )
+ {
+ if ( argv[i][0] == '-' && isalpha(argv[i][1]) && argv[i][2] == 0 )
+ {
+ switch ( argv[i][1] )
+ {
+ case 'i': TEST_SET_MAJOR_MODE(info_flag); break;
+ case 'G': TEST_SET_MAJOR_MODE(gop_start_flag); break;
+ case 'W': no_write_flag = true; break;
+ case 'n': showindex_flag = true; break;
+ case 'H': showheader_flag = true; break;
+ case 'R': do_repeat = true; break;
+ case 'S': split_wav = true; break;
+ case 'V': version_flag = true; break;
+ case 'h': help_flag = true; break;
+ case 'v': verbose_flag = true; break;
+ case 'g':
+#ifdef ASDCP_WITHOUT_OPENSSL
+ fputs("Program compiled without encryption support.\n", stderr);
+ return;
+#else
+ genkey_flag = true;
+#endif
+ break;
+
+ case 'u':
+#ifdef ASDCP_WITHOUT_OPENSSL
+ fputs("Program compiled without encryption support.\n", stderr);
+ return;
+#else
+ genid_flag = true;
+#endif
+ break;
+
+ case 'e': encrypt_header_flag = true; break;
+ case 'E': encrypt_header_flag = false; break;
+ case 'M': write_hmac = false; break;
+ case 'm': read_hmac = true; break;
+
+ case 'c':
+ TEST_SET_MAJOR_MODE(create_flag);
+ TEST_EXTRA_ARG(i, 'c');
+ out_file = argv[i];
+ break;
+
+ case 'x':
+ TEST_SET_MAJOR_MODE(extract_flag);
+ TEST_EXTRA_ARG(i, 'x');
+ file_root = argv[i];
+ break;
+
+ case 'k': key_flag = true;
+#ifdef ASDCP_WITHOUT_OPENSSL
+ fputs("Program compiled without encryption support.\n", stderr);
+ return;
+#else
+ TEST_EXTRA_ARG(i, 'k');
+ {
+ ui32_t length;
+ hex2bin(argv[i], key_value, KeyLen, &length);
+
+ if ( length != KeyLen )
+ {
+ fprintf(stderr, "Unexpected key length: %lu, expecting %lu characters.\n", KeyLen, length);
+ return;
+ }
+ }
+#endif
+ break;
+
+ case 'j': key_id_flag = true;
+#ifdef ASDCP_WITHOUT_OPENSSL
+ fputs("Program compiled without encryption support.\n", stderr);
+ return;
+#else
+ TEST_EXTRA_ARG(i, 'j');
+ {
+ ui32_t length;
+ hex2bin(argv[i], key_id_value, KeyIDlen, &length);
+
+ if ( length != KeyIDlen )
+ {
+ fprintf(stderr, "Unexpected key ID length: %lu, expecting %lu characters.\n", KeyIDlen, length);
+ return;
+ }
+ }
+#endif
+ break;
+
+ case 'f':
+ TEST_EXTRA_ARG(i, 'f');
+ start_frame = atoi(argv[i]); // TODO: test for negative value, should use strtol()
+ break;
+
+ case 'd':
+ TEST_EXTRA_ARG(i, 'd');
+ duration_flag = true;
+ duration = atoi(argv[i]); // TODO: test for negative value, should use strtol()
+ break;
+
+ case 'p':
+ TEST_EXTRA_ARG(i, 'p');
+ picture_rate = atoi(argv[i]);
+ break;
+
+ case 's':
+ TEST_EXTRA_ARG(i, 's');
+ fb_dump_size = atoi(argv[i]);
+ break;
+
+ case 'b':
+ TEST_EXTRA_ARG(i, 'b');
+ fb_size = atoi(argv[i]);
+
+ if ( verbose_flag )
+ fprintf(stderr, "Frame Buffer size: %lu bytes.\n", fb_size);
+
+ break;
+
+ default:
+ fprintf(stderr, "Unrecognized option: %c\n", argv[i][1]);
+ return;
+ }
+ }
+ else
+ {
+ filenames[file_count++] = argv[i];
+
+ if ( file_count >= MAX_IN_FILES )
+ {
+ fprintf(stderr, "Filename lists exceeds maximum list size: %lu\n", MAX_IN_FILES);
+ return;
+ }
+ }
+ }
+
+ if ( TEST_MAJOR_MODE() )
+ {
+ if ( ! genkey_flag && ! genid_flag && file_count == 0 )
+ {
+ fputs("Option requires at least one filename argument.\n", stderr);
+ return;
+ }
+ }
+
+ if ( ! TEST_MAJOR_MODE() && ! help_flag && ! version_flag )
+ {
+ fputs("No operation selected (use one of -(gcixG) or -h for help).\n", stderr);
+ return;
+ }
+
+ error_flag = false;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+// MPEG2 essence
+#if 0
+// Write a plaintext MPEG2 Video Elementary Stream to a plaintext ASDCP file
+// Write a plaintext MPEG2 Video Elementary Stream to a ciphertext ASDCP file
+//
+Result_t
+write_MPEG2_file(CommandOptions& Options)
+{
+ AESEncContext* Context = 0;
+ HMACContext* HMAC = 0;
+ MPEG2::FrameBuffer FrameBuffer(Options.fb_size);
+ MPEG2::Parser Parser;
+ MPEG2::MXFWriter Writer;
+ MPEG2::VideoDescriptor VDesc;
+
+#ifndef ASDCP_WITHOUT_OPENSSL
+ byte_t IV_buf[CBC_BLOCK_SIZE];
+ FortunaRNG RNG;
+#endif
+
+ // set up essence parser
+ Result_t result = Parser.OpenRead(Options.filenames[0]);
+
+ // set up MXF writer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Parser.FillVideoDescriptor(VDesc);
+
+ if ( Options.verbose_flag )
+ {
+ fputs("MPEG-2 Pictures\n", stderr);
+ fputs("VideoDescriptor:\n", stderr);
+ fprintf(stderr, "Frame Buffer size: %lu\n", Options.fb_size);
+ MPEG2::VideoDescriptorDump(VDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
+#ifndef ASDCP_WITHOUT_OPENSSL
+ GenRandomUUID(RNG, Info.AssetUUID);
+
+ // configure encryption
+ if( Options.key_flag )
+ {
+ GenRandomUUID(RNG, Info.ContextID);
+ Info.EncryptedEssence = true;
+
+ if ( Options.key_id_flag )
+ memcpy(Info.CryptographicKeyID, Options.key_id_value, KeyIDlen);
+ else
+ RNG.FillRandom(Info.CryptographicKeyID, KeyIDlen);
+
+ 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);
+ }
+ }
+#endif // ASDCP_WITHOUT_OPENSSL
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.OpenWrite(Options.out_file, Info, VDesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ // loop through the frames
+ {
+ result = Parser.Reset();
+ ui32_t duration = 0;
+
+ while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
+ {
+ if ( ! Options.do_repeat || 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 )
+ {
+ result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
+
+#ifndef ASDCP_WITHOUT_OPENSSL
+ // 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));
+#endif
+ }
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.Finalize();
+
+ return result;
+}
+#endif
+
+// Read a plaintext MPEG2 Video Elementary Stream from a plaintext ASDCP file
+// Read a plaintext MPEG2 Video Elementary Stream from a ciphertext ASDCP file
+// Read a ciphertext MPEG2 Video Elementary Stream from a ciphertext ASDCP file
+//
+Result_t
+read_MPEG2_file(CommandOptions& Options)
+{
+ AESDecContext* Context = 0;
+ HMACContext* HMAC = 0;
+ MPEG2::MXFReader Reader;
+ MPEG2::FrameBuffer FrameBuffer(Options.fb_size);
+ FileWriter OutFile;
+ ui32_t frame_count = 0;
+
+ Result_t result = Reader.OpenRead(Options.filenames[0]);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ MPEG2::VideoDescriptor VDesc;
+ Reader.FillVideoDescriptor(VDesc);
+ frame_count = VDesc.ContainerDuration;
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "Frame Buffer size: %lu\n", Options.fb_size);
+ MPEG2::VideoDescriptorDump(VDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ char filename[256];
+ sprintf(filename, "%s.ves", Options.file_root);
+ result = OutFile.OpenWrite(filename);
+ }
+
+ 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);
+ }
+ 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;
+
+ 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.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ ui32_t write_count = 0;
+ result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+ }
+ }
+
+ return result;
+}
+
+
+//
+Result_t
+gop_start_test(CommandOptions& Options)
+{
+ using namespace ASDCP::MPEG2;
+
+ MXFReader Reader;
+ MPEG2::FrameBuffer FrameBuffer(Options.fb_size);
+ ui32_t frame_count = 0;
+
+ Result_t result = Reader.OpenRead(Options.filenames[0]);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ MPEG2::VideoDescriptor VDesc;
+ Reader.FillVideoDescriptor(VDesc);
+ frame_count = VDesc.ContainerDuration;
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "Frame Buffer size: %lu\n", Options.fb_size);
+ MPEG2::VideoDescriptorDump(VDesc);
+ }
+ }
+
+ ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
+ if ( last_frame > frame_count )
+ last_frame = frame_count;
+
+ for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
+ {
+ result = Reader.ReadFrameGOPStart(i, FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( FrameBuffer.FrameType() != FRAME_I )
+ fprintf(stderr, "Expecting an I frame, got %c\n", FrameTypeChar(FrameBuffer.FrameType()));
+
+ fprintf(stderr, "Requested frame %lu, got %lu\n", i, FrameBuffer.FrameNumber());
+ }
+ }
+
+ return result;
+}
+
+#if 0
+//------------------------------------------------------------------------------------------
+// JPEG 2000 essence
+
+// Write one or more plaintext JPEG 2000 codestreams to a plaintext ASDCP file
+// Write one or more plaintext JPEG 2000 codestreams to a ciphertext ASDCP file
+//
+Result_t
+write_JP2K_file(CommandOptions& Options)
+{
+ AESEncContext* Context = 0;
+ HMACContext* HMAC = 0;
+ JP2K::MXFWriter Writer;
+ JP2K::FrameBuffer FrameBuffer(Options.fb_size);
+ JP2K::PictureDescriptor PDesc;
+ JP2K::SequenceParser Parser;
+
+#ifndef ASDCP_WITHOUT_OPENSSL
+ byte_t IV_buf[CBC_BLOCK_SIZE];
+ FortunaRNG RNG;
+#endif
+
+ // set up essence parser
+ Result_t result = Parser.OpenRead(Options.filenames[0]);
+
+ // set up MXF writer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Parser.FillPictureDescriptor(PDesc);
+ PDesc.EditRate = Options.PictureRate();
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "JPEG 2000 pictures\n");
+ fputs("PictureDescriptor:\n", stderr);
+ fprintf(stderr, "Frame Buffer size: %lu\n", Options.fb_size);
+ JP2K::PictureDescriptorDump(PDesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
+#ifndef ASDCP_WITHOUT_OPENSSL
+ GenRandomUUID(RNG, Info.AssetUUID);
+
+ // configure encryption
+ if( Options.key_flag )
+ {
+ GenRandomUUID(RNG, Info.ContextID);
+ Info.EncryptedEssence = true;
+
+ if ( Options.key_id_flag )
+ memcpy(Info.CryptographicKeyID, Options.key_id_value, KeyIDlen);
+ else
+ RNG.FillRandom(Info.CryptographicKeyID, KeyIDlen);
+
+ 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);
+ }
+ }
+#endif // ASDCP_WITHOUT_OPENSSL
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.OpenWrite(Options.out_file, Info, PDesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t duration = 0;
+ result = Parser.Reset();
+
+ while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
+ {
+ if ( ! Options.do_repeat || 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 )
+ {
+ result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
+#ifndef ASDCP_WITHOUT_OPENSSL
+ // 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));
+#endif
+ }
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.Finalize();
+
+ return result;
+}
+#endif
+
+// Read one or more plaintext JPEG 2000 codestreams from a plaintext ASDCP file
+// Read one or more plaintext JPEG 2000 codestreams from a ciphertext ASDCP file
+// Read one or more ciphertext JPEG 2000 codestreams from a ciphertext ASDCP file
+//
+Result_t
+read_JP2K_file(CommandOptions& Options)
+{
+ AESDecContext* Context = 0;
+ HMACContext* HMAC = 0;
+ JP2K::MXFReader Reader;
+ JP2K::FrameBuffer FrameBuffer(Options.fb_size);
+ ui32_t frame_count = 0;
+
+ Result_t result = Reader.OpenRead(Options.filenames[0]);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ JP2K::PictureDescriptor PDesc;
+ Reader.FillPictureDescriptor(PDesc);
+
+ frame_count = PDesc.ContainerDuration;
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "Frame Buffer size: %lu\n", Options.fb_size);
+ JP2K::PictureDescriptorDump(PDesc);
+ }
+ }
+
+ 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);
+ }
+ 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;
+
+ 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) )
+ {
+ FileWriter OutFile;
+ char filename[256];
+ ui32_t write_count;
+ sprintf(filename, "%s%06lu.j2c", Options.file_root, 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);
+ }
+ }
+
+ return result;
+}
+
+#if 0
+//------------------------------------------------------------------------------------------
+// PCM essence
+
+
+// Write one or more plaintext PCM audio streams to a plaintext ASDCP file
+// Write one or more plaintext PCM audio streams to a ciphertext ASDCP file
+//
+Result_t
+write_PCM_file(CommandOptions& Options)
+{
+ AESEncContext* Context = 0;
+ HMACContext* HMAC = 0;
+ PCMParserList Parser;
+ PCM::MXFWriter Writer;
+ PCM::FrameBuffer FrameBuffer;
+ PCM::AudioDescriptor ADesc;
+ Rational PictureRate = Options.PictureRate();
+
+#ifndef ASDCP_WITHOUT_OPENSSL
+ byte_t IV_buf[CBC_BLOCK_SIZE];
+ FortunaRNG RNG;
+#endif
+
+ // set up essence parser
+ Result_t result = Parser.OpenRead(Options.file_count, Options.filenames, PictureRate);
+
+ // set up MXF writer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Parser.FillAudioDescriptor(ADesc);
+
+ ADesc.SampleRate = PictureRate;
+ FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "48Khz PCM Audio, %s fps (%lu spf)\n",
+ Options.szPictureRate(),
+ PCM::CalcSamplesPerFrame(ADesc));
+ fputs("AudioDescriptor:\n", stderr);
+ PCM::AudioDescriptorDump(ADesc);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
+#ifndef ASDCP_WITHOUT_OPENSSL
+ GenRandomUUID(RNG, Info.AssetUUID);
+
+ // configure encryption
+ if( Options.key_flag )
+ {
+ GenRandomUUID(RNG, Info.ContextID);
+ Info.EncryptedEssence = true;
+
+ if ( Options.key_id_flag )
+ memcpy(Info.CryptographicKeyID, Options.key_id_value, KeyIDlen);
+ else
+ RNG.FillRandom(Info.CryptographicKeyID, KeyIDlen);
+
+ 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);
+ }
+ }
+#endif // ASDCP_WITHOUT_OPENSSL
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.OpenWrite(Options.out_file, Info, ADesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = Parser.Reset();
+ ui32_t duration = 0;
+
+ while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
+ {
+ result = Parser.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 %lu bytes, got %lu.\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);
+
+#ifndef ASDCP_WITHOUT_OPENSSL
+ // 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));
+#endif
+ }
+ }
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.Finalize();
+
+ return result;
+}
+#endif
+
+// Read one or more plaintext PCM audio streams from a plaintext ASDCP file
+// Read one or more plaintext PCM audio streams from a ciphertext ASDCP file
+// Read one or more ciphertext PCM audio streams from a ciphertext ASDCP file
+//
+Result_t
+read_PCM_file(CommandOptions& Options)
+{
+ AESDecContext* Context = 0;
+ HMACContext* HMAC = 0;
+ PCM::MXFReader Reader;
+ PCM::FrameBuffer FrameBuffer;
+ WavFileWriter OutWave;
+ PCM::AudioDescriptor ADesc;
+ ui32_t last_frame = 0;
+
+ Result_t result = Reader.OpenRead(Options.filenames[0]);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Reader.FillAudioDescriptor(ADesc);
+
+ if ( ADesc.SampleRate != EditRate_23_98
+ && ADesc.SampleRate != EditRate_24
+ && ADesc.SampleRate != EditRate_48 )
+ ADesc.SampleRate = Options.PictureRate();
+
+ FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
+
+ if ( Options.verbose_flag )
+ PCM::AudioDescriptorDump(ADesc);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ last_frame = ADesc.ContainerDuration;
+
+ if ( Options.duration > 0 && Options.duration < last_frame )
+ last_frame = Options.duration;
+
+ if ( Options.start_frame > 0 )
+ {
+ if ( Options.start_frame > ADesc.ContainerDuration )
+ {
+ fprintf(stderr, "Start value greater than file duration.\n");
+ return RESULT_FAIL;
+ }
+
+ last_frame = xmin(Options.start_frame + last_frame, ADesc.ContainerDuration);
+ }
+
+ ADesc.ContainerDuration = last_frame - Options.start_frame;
+ OutWave.OpenWrite(ADesc, Options.file_root, Options.split_wav);
+ }
+
+ 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);
+ }
+ else
+ {
+ fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
+ }
+ }
+ }
+
+ 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.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ result = OutWave.WriteFrame(FrameBuffer);
+ }
+ }
+
+ return result;
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+// These classes wrap the irregular names in the asdcplib API
+// so that I can use a template to simplify the implementation
+// of show_file_info()
+
+class MyVideoDescriptor : public MPEG2::VideoDescriptor
+{
+ public:
+ void FillDescriptor(MPEG2::MXFReader& Reader) {
+ Reader.FillVideoDescriptor(*this);
+ }
+
+ void Dump(FILE* stream) {
+ MPEG2::VideoDescriptorDump(*this, stream);
+ }
+};
+#if 0
+class MyPictureDescriptor : public JP2K::PictureDescriptor
+{
+ public:
+ void FillDescriptor(JP2K::MXFReader& Reader) {
+ Reader.FillPictureDescriptor(*this);
+ }
+
+ void Dump(FILE* stream) {
+ JP2K::PictureDescriptorDump(*this, stream);
+ }
+};
+
+class MyAudioDescriptor : public PCM::AudioDescriptor
+{
+ public:
+ void FillDescriptor(PCM::MXFReader& Reader) {
+ Reader.FillAudioDescriptor(*this);
+ }
+
+ void Dump(FILE* stream) {
+ PCM::AudioDescriptorDump(*this, stream);
+ }
+};
+#endif
+
+// MSVC didn't like the function template, so now it's a static class method
+template<class ReaderT, class DescriptorT>
+class FileInfoWrapper
+{
+public:
+ static void file_info(CommandOptions& Options, FILE* stream = 0)
+ {
+ if ( stream == 0 )
+ stream = stdout;
+
+ if ( Options.verbose_flag || Options.showheader_flag )
+ {
+ ReaderT Reader;
+ Result_t result = Reader.OpenRead(Options.filenames[0]);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.showheader_flag )
+ Reader.DumpHeaderMetadata(stream);
+
+ WriterInfo WI;
+ Reader.FillWriterInfo(WI);
+ WriterInfoDump(WI, stream);
+
+ DescriptorT Desc;
+ Desc.FillDescriptor(Reader);
+ Desc.Dump(stream);
+
+ if ( Options.showindex_flag )
+ Reader.DumpIndex(stream);
+ }
+ else if ( result == RESULT_FORMAT && Options.showheader_flag )
+ {
+ Reader.DumpHeaderMetadata(stream);
+ }
+ }
+ }
+};
+
+// Read header metadata from an ASDCP file
+//
+Result_t
+show_file_info(CommandOptions& Options)
+{
+ EssenceType_t EssenceType;
+ Result_t result = ASDCP::EssenceType(Options.filenames[0], EssenceType);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ if ( EssenceType == ESS_MPEG2_VES )
+ {
+ fputs("File essence type is MPEG2 video.\n", stdout);
+ FileInfoWrapper<ASDCP::MPEG2::MXFReader, MyVideoDescriptor>::file_info(Options);
+ }
+#if 0
+ else if ( EssenceType == ESS_PCM_24b_48k )
+ {
+ fputs("File essence type is PCM audio.\n", stdout);
+ FileInfoWrapper<ASDCP::PCM::MXFReader, MyAudioDescriptor>::file_info(Options);
+ }
+ else if ( EssenceType == ESS_JPEG_2000 )
+ {
+ fputs("File essence type is JPEG 2000 pictures.\n", stdout);
+ FileInfoWrapper<ASDCP::JP2K::MXFReader, MyPictureDescriptor>::file_info(Options);
+ }
+#endif
+ else
+ {
+ fprintf(stderr, "File is not AS-DCP: %s\n", Options.filenames[0]);
+ FileReader Reader;
+ MXF::OPAtomHeader TestHeader;
+
+ result = Reader.OpenRead(Options.filenames[0]);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = TestHeader.InitFromFile(Reader); // test UL and OP
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( MXF::Identification* ID = TestHeader.GetIdentification() )
+ {
+ TestHeader.Dump();
+ ID->Dump();
+ // show OP
+ // show
+ }
+ else
+ {
+ fputs("File contains no Identification object.\n", stdout);
+ }
+ }
+ else
+ {
+ fputs("File is not MXF.\n", stdout);
+ }
+ }
+
+ return result;
+}
+
+
+//
+int
+main(int argc, const char** argv)
+{
+ Result_t result = RESULT_OK;
+ CommandOptions Options(argc, argv);
+
+ if ( Options.help_flag )
+ {
+ usage();
+ return 0;
+ }
+
+ if ( Options.error_flag )
+ return 3;
+
+ if ( Options.version_flag )
+ banner();
+
+ if ( Options.info_flag )
+ {
+ result = show_file_info(Options);
+ }
+ else if ( Options.gop_start_flag )
+ {
+ result = gop_start_test(Options);
+ }
+#ifndef ASDCP_WITHOUT_OPENSSL
+ else if ( Options.genkey_flag )
+ {
+ FortunaRNG RNG;
+ byte_t bin_buf[KeyLen];
+ char str_buf[40];
+
+ RNG.FillRandom(bin_buf, KeyLen);
+ printf("%s\n", bin2hex(bin_buf, KeyLen, str_buf, 40));
+ }
+ else if ( Options.genid_flag )
+ {
+ FortunaRNG RNG;
+ byte_t bin_buf[KeyLen];
+ char str_buf[40];
+
+ GenRandomUUID(RNG, bin_buf);
+ bin2hex(bin_buf, KeyLen, str_buf, 40);
+ printf("%s\n", hyphenate_UUID(str_buf, 40));
+ }
+#endif // ASDCP_WITHOUT_OPENSSL
+ else if ( Options.extract_flag )
+ {
+ EssenceType_t EssenceType;
+ result = ASDCP::EssenceType(Options.filenames[0], EssenceType);
+#ifdef SMPTE_LABELS
+ fprintf(stderr, "ATTENTION! Expecting SMPTE Universal Labels\n");
+#endif
+ if ( ASDCP_SUCCESS(result) )
+ {
+ switch ( EssenceType )
+ {
+ case ESS_MPEG2_VES:
+ result = read_MPEG2_file(Options);
+ break;
+
+ case ESS_JPEG_2000:
+ result = read_JP2K_file(Options);
+ break;
+
+ case ESS_PCM_24b_48k:
+ result = read_PCM_file(Options);
+ break;
+
+ default:
+ fprintf(stderr, "%s: Unknown file type, not ASDCP essence.\n", Options.filenames[0]);
+ return 5;
+ }
+ }
+ }
+ else if ( Options.create_flag )
+ {
+ if ( Options.do_repeat && ! Options.duration_flag )
+ {
+ fputs("Option -R requires -d <duration>\n", stderr);
+ return RESULT_FAIL;
+ }
+
+ EssenceType_t EssenceType;
+ result = ASDCP::RawEssenceType(Options.filenames[0], EssenceType);
+#ifdef SMPTE_LABELS
+ fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
+#endif
+#if 0
+ if ( ASDCP_SUCCESS(result) )
+ {
+ switch ( EssenceType )
+ {
+ case ESS_MPEG2_VES:
+ result = write_MPEG2_file(Options);
+ break;
+
+ case ESS_JPEG_2000:
+ result = write_JP2K_file(Options);
+ break;
+
+ case ESS_PCM_24b_48k:
+ result = write_PCM_file(Options);
+ break;
+
+ default:
+ fprintf(stderr, "%s: Unknown file type, not ASDCP-compatible essence.\n",
+ Options.filenames[0]);
+ return 5;
+ }
+ }
+#endif
+ }
+
+ if ( result != RESULT_OK )
+ {
+ fputs("Program stopped on error.\n", stderr);
+
+ if ( result != RESULT_FAIL )
+ {
+ fputs(GetResultString(result), stderr);
+ fputc('\n', stderr);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+//
+// end asdcp-test.cpp
+//
diff --git a/src/asdcp-version.cpp b/src/asdcp-version.cpp
new file mode 100755
index 0000000..148f69d
--- /dev/null
+++ b/src/asdcp-version.cpp
@@ -0,0 +1,46 @@
+/*
+Copyright (c) 2004, 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 asdcp-version.cpp
+ \version $Id$
+ \brief AS-DCP library version annunciator
+*/
+
+#include <AS_DCP.h>
+using namespace ASDCP;
+
+//
+int
+main()
+{
+ printf("%lu.%lu.%lu", VERSION_MAJOR, VERSION_APIMINOR, VERSION_IMPMINOR);
+ return 0;
+}
+
+
+//
+// end asdcp-version.cpp
+//
diff --git a/src/h__Reader.cpp b/src/h__Reader.cpp
new file mode 100755
index 0000000..1503102
--- /dev/null
+++ b/src/h__Reader.cpp
@@ -0,0 +1,346 @@
+/*
+Copyright (c) 2004-2005, 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 h__Reader.cpp
+ \version $Id$
+ \brief MXF file reader base class
+*/
+
+#include "AS_DCP_internal.h"
+#include "KLV.h"
+#include "MDD.h"
+#include <assert.h>
+
+using namespace ASDCP;
+using namespace ASDCP::MXF;
+
+
+// GetMDObjectByPath() path to file's Identification metadata object
+static const char* INFO_OBJECT_PATH = "Preface.Identifications.Identification.Identification";
+static const char* ASSET_ID_OBJECT_PATH = "Preface.ContentStorage.ContentStorage.Packages.Package.SourcePackage.PackageUID";
+
+
+ASDCP::h__Reader::h__Reader() : m_EssenceStart(0)
+{
+}
+
+ASDCP::h__Reader::~h__Reader()
+{
+ Close();
+}
+
+void
+ASDCP::h__Reader::Close()
+{
+ m_File.Close();
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+Result_t
+ASDCP::h__Reader::InitInfo(WriterInfo& Info)
+{
+ InterchangeObject* Object;
+
+ // Identification
+ Result_t result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object);
+
+ if( ASDCP_SUCCESS(result) )
+ MD_to_WriterInfo((Identification*)Object, m_Info);
+
+ // SourcePackage
+ if( ASDCP_SUCCESS(result) )
+ result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object);
+
+ if( ASDCP_SUCCESS(result) )
+ {
+ SourcePackage* SP = (SourcePackage*)Object;
+ memcpy(Info.AssetUUID, SP->PackageUID.Data() + 16, UUIDlen);
+ }
+
+ // optional CryptographicContext
+ if( ASDCP_SUCCESS(result) )
+ {
+ Result_t cr_result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CryptographicContext), &Object);
+
+ if( ASDCP_SUCCESS(cr_result) )
+ MD_to_CryptoInfo((CryptographicContext*)Object, m_Info);
+ }
+
+ return result;
+}
+
+
+// standard method of opening an MXF file for read
+Result_t
+ASDCP::h__Reader::OpenMXFRead(const char* filename)
+{
+ Result_t result = m_File.OpenRead(filename);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_HeaderPart.InitFromFile(m_File);
+
+ // OP-Atom states that there will be either two or three partitions,
+ // one closed header and one closed footer with an optional body
+ ui32_t test_s = m_HeaderPart.m_RIP.PairArray.size();
+
+ if ( test_s < 2 || test_s > 3 )
+ {
+ DefaultLogSink().Error("RIP count is not 2 or 3: %lu\n", test_s);
+ return RESULT_FORMAT;
+ }
+
+ // it really OP-Atom?
+ // MDObject* OpPattern = GetMDObjectByType("OperationalPattern");
+ // TODO: check the label
+
+ // if this is a three partition file, go to the body
+ // partition and read off the partition pack
+ if ( test_s == 3 )
+ {
+ DefaultLogSink().Error("RIP count is 3: must write code...\n");
+ return RESULT_FORMAT;
+ }
+ // TODO: check the partition pack to make sure it is
+ // really a body with a single essence container
+
+ m_EssenceStart = m_File.Tell();
+
+ return RESULT_OK;
+}
+
+
+// standard method of populating the in-memory index
+Result_t
+ASDCP::h__Reader::InitMXFIndex()
+{
+ if ( ! m_File.IsOpen() )
+ return RESULT_INIT;
+
+ Result_t result = m_File.Seek(m_HeaderPart.FooterPartition);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_FooterPart.m_Lookup = &m_HeaderPart.m_Primer;
+ result = m_FooterPart.InitFromFile(m_File);
+ }
+
+ return result;
+}
+
+
+// standard method of reading a plaintext or encrypted frame
+Result_t
+ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
+ const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
+{
+ // look up frame index node
+ IndexTableSegment::IndexEntry TmpEntry;
+
+ if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
+ {
+ DefaultLogSink().Error("Frame value out of range: %lu\n", FrameNum);
+ return RESULT_RANGE;
+ }
+
+ // get frame position and go read the frame's key and length
+ ASDCP::KLVReader Reader;
+ ASDCP::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset;
+
+ Result_t result = m_File.Seek(FilePosition);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.ReadKLFromFile(m_File);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ UL Key(Reader.Key());
+ UL InteropRef(CryptEssenceUL_Data);
+ UL SMPTERef(CryptEssenceUL_Data);
+ ui64_t PacketLength = Reader.Length();
+
+ if ( Key == InteropRef || Key == SMPTERef )
+ {
+ if ( ! m_Info.EncryptedEssence )
+ {
+ DefaultLogSink().Error("EKLV packet found, no Cryptographic Context in header.\n");
+ return RESULT_FORMAT;
+ }
+
+ // read encrypted triplet value into internal buffer
+ m_CtFrameBuf.Capacity(PacketLength);
+ ui32_t read_count;
+ result = m_File.Read(m_CtFrameBuf.Data(), PacketLength, &read_count);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ if ( read_count != PacketLength )
+ {
+ DefaultLogSink().Error("read length is smaller than EKLV packet length.\n");
+ return RESULT_FORMAT;
+ }
+
+ m_CtFrameBuf.Size(PacketLength);
+
+ // should be const but mxflib::ReadBER is not
+ byte_t* ess_p = m_CtFrameBuf.Data();
+
+ // read context ID length
+ if ( ! read_test_BER(&ess_p, UUIDlen) )
+ return RESULT_FORMAT;
+
+ // test the context ID
+ if ( memcmp(ess_p, m_Info.ContextID, UUIDlen) != 0 )
+ {
+ DefaultLogSink().Error("Packet's Cryptographic Context ID does not match the header.\n");
+ return RESULT_FORMAT;
+ }
+ ess_p += UUIDlen;
+
+ // read PlaintextOffset length
+ if ( ! read_test_BER(&ess_p, sizeof(ui64_t)) )
+ return RESULT_FORMAT;
+
+ ui32_t PlaintextOffset = (ui32_t)ASDCP_i64_BE(cp2i<ui64_t>(ess_p));
+ ess_p += sizeof(ui64_t);
+
+ // read essence UL length
+ if ( ! read_test_BER(&ess_p, klv_key_size) )
+ return RESULT_FORMAT;
+
+ // TODO: test essence UL
+ ess_p += klv_key_size;
+
+ // read SourceLength length
+ if ( ! read_test_BER(&ess_p, sizeof(ui64_t)) )
+ return RESULT_FORMAT;
+
+ ui32_t SourceLength = (ui32_t)ASDCP_i64_BE(cp2i<ui64_t>(ess_p));
+ ess_p += sizeof(ui64_t);
+ assert(SourceLength);
+
+ if ( FrameBuf.Capacity() < SourceLength )
+ {
+ DefaultLogSink().Error("FrameBuf.Capacity: %lu SourceLength: %lu\n", FrameBuf.Capacity(), SourceLength);
+ return RESULT_SMALLBUF;
+ }
+
+ ui32_t esv_length = calc_esv_length(SourceLength, PlaintextOffset);
+
+ // read ESV length
+ if ( ! read_test_BER(&ess_p, esv_length) )
+ {
+ DefaultLogSink().Error("read_test_BER did not return %lu\n", esv_length);
+ return RESULT_FORMAT;
+ }
+
+ ui32_t tmp_len = esv_length + (m_Info.UsesHMAC ? klv_intpack_size : 0);
+
+ if ( PacketLength < tmp_len )
+ {
+ DefaultLogSink().Error("Frame length is larger than EKLV packet length.\n");
+ return RESULT_FORMAT;
+ }
+
+ if ( Ctx )
+ {
+ // wrap the pointer and length as a FrameBuffer for use by
+ // DecryptFrameBuffer() and TestValues()
+ FrameBuffer TmpWrapper;
+ TmpWrapper.SetData(ess_p, tmp_len);
+ TmpWrapper.Size(tmp_len);
+ TmpWrapper.SourceLength(SourceLength);
+ TmpWrapper.PlaintextOffset(PlaintextOffset);
+
+ result = DecryptFrameBuffer(TmpWrapper, FrameBuf, Ctx);
+ FrameBuf.FrameNumber(FrameNum);
+
+ // detect and test integrity pack
+ if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC && HMAC )
+ {
+ IntegrityPack IntPack;
+ result = IntPack.TestValues(TmpWrapper, m_Info.AssetUUID, FrameNum + 1, HMAC);
+ }
+ }
+ else // return ciphertext to caller
+ {
+ if ( FrameBuf.Capacity() < tmp_len )
+ return RESULT_SMALLBUF;
+
+ memcpy(FrameBuf.Data(), ess_p, tmp_len);
+ FrameBuf.Size(tmp_len);
+ FrameBuf.SourceLength(SourceLength);
+ FrameBuf.PlaintextOffset(PlaintextOffset);
+ }
+ }
+ else if ( Key == EssenceUL )
+ { // read plaintext frame
+ if ( FrameBuf.Capacity() < PacketLength )
+ {
+ char intbuf[IntBufferLen];
+ DefaultLogSink().Error("FrameBuf.Capacity: %lu FrameLength: %s\n",
+ FrameBuf.Capacity(), ui64sz(PacketLength, intbuf));
+ return RESULT_SMALLBUF;
+ }
+
+ // read the data into the supplied buffer
+ ui32_t read_count;
+ result = m_File.Read(FrameBuf.Data(), PacketLength, &read_count);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ if ( read_count != PacketLength )
+ {
+ char intbuf1[IntBufferLen];
+ char intbuf2[IntBufferLen];
+ DefaultLogSink().Error("read_count: %s != FrameLength: %s\n",
+ ui64sz(read_count, intbuf1),
+ ui64sz(PacketLength, intbuf2) );
+
+ return RESULT_READFAIL;
+ }
+
+ FrameBuf.FrameNumber(FrameNum);
+ FrameBuf.Size(read_count);
+ }
+ else
+ {
+ DefaultLogSink().Error("Unexpected UL found.\n");
+ return RESULT_FORMAT;
+ }
+
+ return result;
+}
+
+
+//
+// end h__Reader.cpp
+//
diff --git a/src/h__Writer.cpp b/src/h__Writer.cpp
new file mode 100755
index 0000000..411f63e
--- /dev/null
+++ b/src/h__Writer.cpp
@@ -0,0 +1,458 @@
+/*
+Copyright (c) 2004-2005, 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 h__Writer.cpp
+ \version $Id$
+ \brief MXF file writer base class
+*/
+
+#include "AS_DCP_internal.h"
+#include "MemIO.h"
+#include "Timecode.h"
+#include <assert.h>
+
+using namespace mxflib;
+using namespace ASDCP;
+
+
+ASDCP::h__Writer::h__Writer() : m_FramesWritten(0), m_StreamOffset(0)
+{
+ init_mxf_types();
+}
+
+ASDCP::h__Writer::~h__Writer()
+{
+}
+
+// standard method of writing the header of a new MXF file
+Result_t
+ASDCP::h__Writer::WriteMXFHeader(EssenceType_t EssenceType, ASDCP::Rational& EditRate,
+ ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
+{
+ // write the stream metadata
+ m_Metadata = new Metadata();
+ assert(m_Metadata);
+ assert(m_Metadata->m_Object);
+
+ if ( m_Info.EncryptedEssence )
+ {
+ UL DMSUL(CryptoFrameworkUL_Data);
+ m_Metadata->AddDMScheme(DMSUL);
+ }
+
+ // Set the OP label
+ // If we are writing OP-Atom we write the header as OP1a initially as another process
+ // may try to read the file before it is complete and then it will NOT be a valid OP-Atom file
+ m_Metadata->SetOP(OP1aUL);
+
+ // Build the Material Package
+ // DRAGONS: We should really try and determine the UMID type rather than cop-out!
+ UMID PackageUMID;
+ PackageUMID.MakeUMID(0x0d); // mixed type
+
+#if ASDCP_USE_MXFLIB
+ mxflib::Rational EditRate_;
+ EditRate_.Numerator = EditRate.Numerator;
+ EditRate_.Denominator = EditRate.Denominator;
+#else
+#define EditRate_ EditRate
+#endif
+
+ m_MaterialPackage = m_Metadata->AddMaterialPackage("AS-DCP Material Package", PackageUMID);
+ m_Metadata->SetPrimaryPackage(m_MaterialPackage); // This will be overwritten for OP-Atom
+
+ TrackPtr MPTimecodeTrack = m_MaterialPackage->AddTimecodeTrack(EditRate_);
+ m_MPTimecode = MPTimecodeTrack->AddTimecodeComponent(TCFrameRate, 0, 0);
+
+ TrackPtr FPTimecodeTrack = 0;
+ mxflib::UUID assetUUID(m_Info.AssetUUID);
+
+ UMID EssenceUMID;
+
+ switch ( EssenceType )
+ {
+ case ESS_MPEG2_VES:
+ PackageUMID.MakeUMID(0x0f, assetUUID);
+ m_FilePackage = m_Metadata->AddFilePackage(1, MPEG_PACKAGE_LABEL, PackageUMID);
+ m_MPTrack = m_MaterialPackage->AddPictureTrack(EditRate_);
+ m_FPTrack = m_FilePackage->AddPictureTrack(0, EditRate_);
+ break;
+
+ case ESS_JPEG_2000:
+ PackageUMID.MakeUMID(0x0f, assetUUID);
+ m_FilePackage = m_Metadata->AddFilePackage(1, JP2K_PACKAGE_LABEL, PackageUMID);
+ m_MPTrack = m_MaterialPackage->AddPictureTrack(EditRate_);
+ m_FPTrack = m_FilePackage->AddPictureTrack(0, EditRate_);
+ break;
+
+ case ESS_PCM_24b_48k:
+ PackageUMID.MakeUMID(0x0f, assetUUID);
+ m_FilePackage = m_Metadata->AddFilePackage(1, PCM_PACKAGE_LABEL, PackageUMID);
+ m_MPTrack = m_MaterialPackage->AddSoundTrack(EditRate_);
+ m_FPTrack = m_FilePackage->AddSoundTrack(0, EditRate_);
+ break;
+
+ default: return RESULT_RAW_ESS;
+ }
+
+ // Add an essence element
+ FPTimecodeTrack = m_FilePackage->AddTimecodeTrack(EditRate_);
+ m_FPTimecode = FPTimecodeTrack->AddTimecodeComponent(TCFrameRate, 0/* NDF */,
+ tc_to_frames(TCFrameRate, 1, 0, 0, 0) );
+
+ // Add a single Component to this Track of the Material Package
+ m_MPClip = m_MPTrack->AddSourceClip();
+
+ // Add a single Component to this Track of the File Package
+ m_FPClip = m_FPTrack->AddSourceClip();
+ const byte_t* SourceEssenceContainerLabel = 0;
+
+ // Frame wrapping
+ if ( m_Info.EncryptedEssence )
+ {
+ switch ( EssenceType )
+ {
+ case ESS_MPEG2_VES:
+ SourceEssenceContainerLabel = WrappingUL_Data_MPEG2_VES;
+ break;
+
+ case ESS_JPEG_2000:
+ SourceEssenceContainerLabel = WrappingUL_Data_JPEG_2000;
+ break;
+
+ case ESS_PCM_24b_48k:
+ SourceEssenceContainerLabel = WrappingUL_Data_PCM_24b_48k;
+ break;
+
+ default:
+ return RESULT_RAW_ESS;
+ }
+ }
+
+ mem_ptr<UL> WrappingUL;
+ switch ( EssenceType )
+ {
+ case ESS_MPEG2_VES:
+ WrappingUL = new UL(WrappingUL_Data_MPEG2_VES); // memchk TESTED
+ break;
+
+ case ESS_JPEG_2000:
+ WrappingUL = new UL(WrappingUL_Data_JPEG_2000); // memchk TESTED
+ break;
+
+ case ESS_PCM_24b_48k:
+ WrappingUL = new UL(WrappingUL_Data_PCM_24b_48k); // memchk TESTED
+ break;
+
+ default:
+ return RESULT_RAW_ESS;
+ }
+ assert(!WrappingUL.empty());
+ m_EssenceDescriptor->SetValue("EssenceContainer", DataChunk(klv_key_size, WrappingUL->GetValue()));
+
+ // Write a File Descriptor only on the internally ref'ed Track
+ m_EssenceDescriptor->SetUint("LinkedTrackID", m_FPTrack->GetUint("TrackID"));
+ m_FilePackage->AddChild("Descriptor")->MakeLink(*m_EssenceDescriptor);
+
+ UL CryptEssenceUL(WrappingUL_Data_Crypt);
+
+ if ( m_Info.EncryptedEssence )
+ {
+ m_Metadata->AddEssenceType(CryptEssenceUL);
+ }
+ else
+ {
+ UL GCUL(GCMulti_Data);
+ m_Metadata->AddEssenceType(GCUL);
+ m_Metadata->AddEssenceType(*WrappingUL);
+ }
+
+ // Link the MP to the FP
+ m_MPClip->MakeLink(m_FPTrack, 0);
+
+ //
+ // ** Write out the header **
+ //
+
+ m_HeaderPart = new Partition("OpenHeader");
+ assert(m_HeaderPart);
+ m_HeaderPart->SetKAG(1); // Everything else can stay at default
+ m_HeaderPart->SetUint("BodySID", 1);
+
+ m_HeaderPart->AddMetadata(m_Metadata);
+
+ // Build an Ident set describing us and link into the metadata
+ MDObject* Ident = new MDObject("Identification");
+ assert(Ident);
+ Ident->SetString("CompanyName", m_Info.CompanyName);
+ Ident->SetString("ProductName", m_Info.ProductName);
+ Ident->SetString("VersionString", m_Info.ProductVersion);
+ UUID ProductUID(m_Info.ProductUUID);
+ Ident->SetValue("ProductUID", DataChunk(UUIDlen, ProductUID.GetValue()));
+
+ // TODO: get Oliver to show me how this works
+ // Ident->SetString("ToolkitVersion", ?);
+
+ m_Metadata->UpdateGenerations(*Ident);
+
+ if ( m_Info.EncryptedEssence )
+ AddDMScrypt(m_FilePackage, m_Info, SourceEssenceContainerLabel);
+
+ // Write the header partition
+ m_File->WritePartition(*m_HeaderPart, HeaderPadding);
+
+ // set up the index
+ switch ( EssenceType )
+ {
+ case ESS_MPEG2_VES:
+ case ESS_JPEG_2000:
+ m_IndexMan = new IndexManager(0, 0);
+ m_IndexMan->SetPosTableIndex(0, -1);
+ break;
+
+ case ESS_PCM_24b_48k:
+ m_IndexMan = new IndexManager(0, BytesPerEditUnit);
+ break;
+
+ case ESS_UNKNOWN:
+ return RESULT_INIT;
+ }
+
+ m_IndexMan->SetBodySID(1);
+ m_IndexMan->SetIndexSID(129);
+ m_IndexMan->SetEditRate(EditRate_);
+
+ return RESULT_OK;
+}
+
+// standard method of writing a plaintext or encrypted frame
+Result_t
+ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
+ AESEncContext* Ctx, HMACContext* HMAC)
+{
+ Result_t result;
+ IntegrityPack IntPack;
+
+ byte_t overhead[128];
+ MemIOWriter Overhead(overhead, 128);
+
+ if ( FrameBuf.Size() == 0 )
+ {
+ DefaultLogSink().Error("Cannot write empty frame buffer\n");
+ return RESULT_EMPTY_FB;
+ }
+
+ if ( m_Info.EncryptedEssence )
+ {
+ if ( ! Ctx )
+ return RESULT_CRYPT_CTX;
+
+ if ( m_Info.UsesHMAC && ! HMAC )
+ return RESULT_HMAC_CTX;
+
+ if ( FrameBuf.PlaintextOffset() > FrameBuf.Size() )
+ return RESULT_LARGE_PTO;
+
+ // encrypt the essence data (create encrypted source value)
+ result = EncryptFrameBuffer(FrameBuf, m_CtFrameBuf, Ctx);
+
+ // create HMAC
+ if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC )
+ result = IntPack.CalcValues(m_CtFrameBuf, m_Info.AssetUUID, m_FramesWritten + 1, HMAC);
+
+ if ( ASDCP_SUCCESS(result) )
+ { // write UL
+ Overhead.WriteRaw((byte_t*)CryptEssenceUL_Data, klv_key_size);
+
+ // construct encrypted triplet header
+ ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size();
+
+ if ( m_Info.UsesHMAC )
+ ETLength += klv_intpack_size;
+ else
+ ETLength += (klv_length_size * 3); // for empty intpack
+
+ Overhead.WriteBER(ETLength, klv_length_size); // write encrypted triplet length
+ Overhead.WriteBER(UUIDlen, klv_length_size); // write ContextID length
+ Overhead.WriteRaw(m_Info.ContextID, UUIDlen); // write ContextID
+ Overhead.WriteBER(sizeof(ui64_t), klv_length_size); // write PlaintextOffset length
+ Overhead.WriteUi64BE(FrameBuf.PlaintextOffset()); // write PlaintextOffset
+ Overhead.WriteBER(klv_key_size, klv_length_size); // write essence UL length
+ Overhead.WriteRaw((byte_t*)EssenceUL, klv_key_size); // write the essence UL
+ Overhead.WriteBER(sizeof(ui64_t), klv_length_size); // write SourceLength length
+ Overhead.WriteUi64BE(FrameBuf.Size()); // write SourceLength
+ Overhead.WriteBER(m_CtFrameBuf.Size(), klv_length_size); // write ESV length
+
+ result = m_File->Writev(Overhead.Data(), Overhead.Size());
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_StreamOffset += Overhead.Size();
+ // write encrypted source value
+ result = m_File->Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size());
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_StreamOffset += m_CtFrameBuf.Size();
+
+ byte_t hmoverhead[512];
+ MemIOWriter HMACOverhead(hmoverhead, 512);
+
+ // write the HMAC
+ if ( m_Info.UsesHMAC )
+ {
+ HMACOverhead.WriteRaw(IntPack.Data, klv_intpack_size);
+ }
+ else
+ { // we still need the var-pack length values if the intpack is empty
+ for ( ui32_t i = 0; i < 3 ; i++ )
+ HMACOverhead.WriteBER(0, klv_length_size);
+ }
+
+ // write HMAC
+ result = m_File->Writev(HMACOverhead.Data(), HMACOverhead.Size());
+ m_StreamOffset += HMACOverhead.Size();
+ }
+ }
+ else
+ {
+ Overhead.WriteRaw((byte_t*)EssenceUL, klv_key_size);
+ Overhead.WriteBER(FrameBuf.Size(), klv_length_size);
+ result = m_File->Writev(Overhead.Data(), Overhead.Size());
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_File->Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size());
+
+ if ( ASDCP_SUCCESS(result) )
+ m_StreamOffset += Overhead.Size() + FrameBuf.Size();
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ result = m_File->Writev();
+
+ return result;
+}
+
+
+// standard method of writing the header and footer of a completed MXF file
+//
+Result_t
+ASDCP::h__Writer::WriteMXFFooter(EssenceType_t EssenceType)
+{
+ // write the index
+ DataChunk IndexChunk;
+ ui32_t IndexSID = 0;
+
+ // Find all essence container data sets so we can update "IndexSID"
+ MDObjectListPtr ECDataSets = 0;
+ MDObject* Ptr = (*m_Metadata)["ContentStorage"];
+ if ( Ptr )
+ Ptr = Ptr->GetLink();
+ if ( Ptr )
+ Ptr = (*Ptr)["EssenceContainerData"];
+ if ( Ptr )
+ ECDataSets = Ptr->ChildList("EssenceContainer");
+
+ // ** Handle full index tables next **
+ // ***********************************
+
+ // Make an index table containing all available entries
+ IndexTablePtr Index = m_IndexMan->MakeIndex();
+ m_IndexMan->AddEntriesToIndex(Index);
+
+ // Write the index table
+ Index->WriteIndex(IndexChunk);
+
+ // Record the IndexSID for when the index is written
+ IndexSID = Index->IndexSID;
+
+ // Update IndexSID in essence container data set
+ MDObjectList::iterator ECD_it = ECDataSets->begin();
+ while(ECD_it != ECDataSets->end())
+ {
+ if((*ECD_it)->GetLink())
+ {
+ if((*ECD_it)->GetLink()->GetUint("BodySID") == m_IndexMan->GetBodySID())
+ {
+ (*ECD_it)->GetLink()->SetUint("IndexSID", m_IndexMan->GetIndexSID());
+ break;
+ }
+ }
+
+ ECD_it++;
+ }
+
+ // If we are writing OP-Atom this is the first place we can claim it
+ m_Metadata->SetOP(OPAtomUL);
+
+ // Set top-level file package correctly for OP-Atom
+ m_Metadata->SetPrimaryPackage(m_FilePackage);
+
+ m_Metadata->SetTime();
+ m_MPTimecode->SetDuration(m_FramesWritten);
+
+ m_MPClip->SetDuration(m_FramesWritten);
+ m_FPTimecode->SetDuration(m_FramesWritten);
+ m_FPClip->SetDuration(m_FramesWritten);
+ m_EssenceDescriptor->SetInt64("ContainerDuration", m_FramesWritten);
+
+ // Turn the header or body partition into a footer
+ m_HeaderPart->ChangeType("CompleteFooter");
+ m_HeaderPart->SetUint("IndexSID", IndexSID);
+
+ // Make sure any new sets are linked in
+ m_HeaderPart->UpdateMetadata(m_Metadata);
+
+ // Actually write the footer
+ m_File->WritePartitionWithIndex(*m_HeaderPart, &IndexChunk, false);
+
+ // Add a RIP
+ m_File->WriteRIP();
+
+ //
+ // ** Update the header **
+ //
+ // For generalized OPs update the value of "FooterPartition" in the header pack
+ // For OP-Atom re-write the entire header
+ //
+ ASDCP::fpos_t FooterPos = m_HeaderPart->GetUint64("FooterPartition");
+ m_File->Seek(0);
+
+ m_HeaderPart->ChangeType("ClosedCompleteHeader");
+ m_HeaderPart->SetUint64("FooterPartition", FooterPos);
+ m_HeaderPart->SetUint64("BodySID", 1);
+
+ m_File->ReWritePartition(*m_HeaderPart);
+ m_File->Close();
+
+ return RESULT_OK;
+}
+
+//
+// end h__Writer.cpp
+//
diff --git a/src/j2c-test.cpp b/src/j2c-test.cpp
new file mode 100755
index 0000000..98c7cf4
--- /dev/null
+++ b/src/j2c-test.cpp
@@ -0,0 +1,74 @@
+
+#include <AS_DCP.h>
+#include <FileIO.h>
+#include <JP2K.h>
+using namespace ASDCP;
+using namespace ASDCP::JP2K;
+
+//
+int
+main(int argc, const char** argv)
+{
+ ASDCP::JP2K::FrameBuffer FB;
+ Marker MyMarker;
+
+ if ( argc < 2 )
+ return 1;
+
+ FB.Capacity(1024*1024*2);
+ CodestreamParser Parser;
+
+ Result_t result = Parser.OpenReadFrame(argv[1], FB);
+
+ if ( result != RESULT_OK )
+ {
+ fputs("Program stopped on error.\n", stderr);
+
+ if ( result != RESULT_FAIL )
+ {
+ fputs(GetResultString(result), stderr);
+ fputc('\n', stderr);
+ }
+
+ return 1;
+ }
+
+ const byte_t* p = FB.RoData();
+ const byte_t* end_p = p + FB.Size();
+
+ hexdump(p, 256, stderr);
+
+ while ( p < end_p && ASDCP_SUCCESS(GetNextMarker(&p, MyMarker)) )
+ {
+ MyMarker.Dump();
+
+ switch ( MyMarker.m_Type )
+ {
+ case MRK_SOD:
+ p = end_p;
+ break;
+
+ case MRK_SIZ:
+ {
+ Accessor::SIZ SIZ_(MyMarker);
+ hexdump(MyMarker.m_Data - 2, MyMarker.m_DataSize + 2, stderr);
+ SIZ_.Dump();
+ }
+ break;
+
+ case MRK_COM:
+ {
+ Accessor::COM COM_(MyMarker);
+ COM_.Dump();
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+//
+// end jp2k-test.cpp
+//
diff --git a/src/klvwalk.cpp b/src/klvwalk.cpp
new file mode 100755
index 0000000..3704f10
--- /dev/null
+++ b/src/klvwalk.cpp
@@ -0,0 +1,161 @@
+//
+// klvwalk.cpp
+//
+
+#include <AS_DCP.h>
+#include <MXF.h>
+#include <hex_utils.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+using namespace ASDCP;
+
+
+//------------------------------------------------------------------------------------------
+//
+
+// There is no header file thet defines this function.
+// You just have to know it's there...
+void set_debug_mode(bool info_mode, bool debug_mode);
+
+
+int
+main(int argc, char** argv)
+{
+ Result_t result = RESULT_OK;
+ bool read_mxf = false;
+ bool rewrite_mxf = false;
+ int arg_i = 1;
+ set_debug_mode(true, true);
+
+ if ( strcmp(argv[1], "-r") == 0 )
+ {
+ read_mxf = true;
+ arg_i++;
+ }
+ else if ( strcmp(argv[1], "-w") == 0 )
+ {
+ rewrite_mxf = true;
+ arg_i++;
+ assert(argc - arg_i == 2);
+ }
+
+ fprintf(stderr, "Opening file %s\n", argv[arg_i]);
+
+ if ( read_mxf )
+ {
+ ASDCP::FileReader Reader;
+ ASDCP::MXF::OPAtomHeader Header;
+
+ result = Reader.OpenRead(argv[arg_i]);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Header.InitFromFile(Reader);
+
+ // if ( ASDCP_SUCCESS(result) )
+ Header.Dump();
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ASDCP::MXF::OPAtomIndexFooter Index;
+ result = Reader.Seek(Header.FooterPartition);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ Index.m_Lookup = &Header.m_Primer;
+ result = Index.InitFromFile(Reader);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ Index.Dump();
+ }
+ }
+ else if ( rewrite_mxf )
+ {
+ ASDCP::FileReader Reader;
+ ASDCP::FileWriter Writer;
+ ASDCP::MXF::OPAtomHeader Header;
+ ASDCP::MXF::OPAtomIndexFooter Index;
+
+ result = Reader.OpenRead(argv[arg_i++]);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Header.InitFromFile(Reader);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Reader.Seek(Header.FooterPartition);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Index.InitFromFile(Reader);
+
+ Header.m_Primer.ClearTagList();
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Writer.OpenWrite(argv[arg_i]);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Header.WriteToFile(Writer);
+
+// if ( ASDCP_SUCCESS(result) )
+// result = Index.WriteToFile(Writer);
+
+ // essence packets
+
+ // index
+
+ // RIP
+ }
+ else // dump klv
+ {
+ ASDCP::FileReader Reader;
+ KLVFilePacket KP;
+
+ result = Reader.OpenRead(argv[arg_i]);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = KP.InitFromFile(Reader);
+
+ while ( ASDCP_SUCCESS(result) )
+ {
+ KP.Dump(stderr, true);
+ result = KP.InitFromFile(Reader);
+ }
+
+ if( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+ if ( result != RESULT_OK )
+ {
+ fputs("Program stopped on error.\n", stderr);
+
+ if ( result != RESULT_FAIL )
+ {
+ fputs(GetResultString(result), stderr);
+ fputc('\n', stderr);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+//
+// end klvwalk.cpp
+//
+
+
+
+
+
+
+
+
+
+