Added atmos support and new ULs per SMPTE 429-2:2013 - see README for deets.
authormikey <mikey@cinecert.com>
Fri, 12 Apr 2013 23:39:31 +0000 (23:39 +0000)
committermikey <>
Fri, 12 Apr 2013 23:39:31 +0000 (23:39 +0000)
50 files changed:
README
build-aux/config.guess
build-aux/config.sub
build-aux/depcomp
build-aux/install-sh
build-aux/ltmain.sh
build-aux/missing
configure.ac
src/AS_DCP.h
src/AS_DCP_ATMOS.cpp [new file with mode: 0644]
src/AS_DCP_DCData.cpp [new file with mode: 0644]
src/AS_DCP_DCData_internal.h [new file with mode: 0644]
src/AS_DCP_JP2K.cpp
src/AS_DCP_MPEG2.cpp
src/AS_DCP_MXF.cpp
src/AS_DCP_PCM.cpp
src/AS_DCP_TimedText.cpp
src/AS_DCP_internal.h
src/AtmosSyncChannel_Generator.cpp [new file with mode: 0644]
src/AtmosSyncChannel_Generator.h [new file with mode: 0644]
src/AtmosSyncChannel_Mixer.cpp [new file with mode: 0644]
src/AtmosSyncChannel_Mixer.h [new file with mode: 0644]
src/CRC16.c [new file with mode: 0644]
src/CRC16.h [new file with mode: 0644]
src/DCData_ByteStream_Parser.cpp [new file with mode: 0644]
src/DCData_Sequence_Parser.cpp [new file with mode: 0644]
src/Index.cpp
src/MDD.cpp
src/MDD.h
src/MXF.cpp
src/Makefile.am
src/Metadata.cpp
src/Metadata.h
src/PCMDataProviders.cpp [new file with mode: 0644]
src/PCMDataProviders.h [new file with mode: 0644]
src/PCM_Parser.cpp
src/SyncCommon.h [new file with mode: 0644]
src/SyncEncoder.c [new file with mode: 0644]
src/SyncEncoder.h [new file with mode: 0644]
src/UUIDInformation.c [new file with mode: 0644]
src/UUIDInformation.h [new file with mode: 0644]
src/Wav.cpp
src/Wav.h
src/WavFileWriter.h
src/asdcp-info.cpp
src/asdcp-unwrap.cpp
src/asdcp-wrap.cpp
src/blackwave.cpp
src/h__Reader.cpp
win32/Makefile.mak

diff --git a/README b/README
index ccdc4d26eebe15e4e1b753cfbac8fe7098e3a81a..7def63f12d5b3633103dbae3ad408dfbe9e1c35a 100755 (executable)
--- a/README
+++ b/README
@@ -139,6 +139,18 @@ command-line utilities all respond to -h.
 
 Change History
 
+2013-04-12 - Dolby Atmos support and more audio labels 1.11.49
+  o Significant code contribution from Dolby Laboratories to add
+    support for generic data track files as proposed in ST 21DC
+    and also Dolby Atmos track file support as a specialization.
+  o Added Dolby-contributed code to support generating the external
+    sync signal for d-cinema as proposed in ST 21DC.
+  o Added Dolby-contributed code to support RF64 WAVE files.
+  o Fixed UL error in ST 429-5 DM encoding (contributed by Dolby).
+  o Added ULs for ST 428-12 and Amd. 429-2 2013.  Please check!
+
+
+
 2013-02-20 - bug fixes, enhancements 1.10.48
  o Refactored internals of the AS-DCP file readers.  While no
    changes in behavior are intended, users are cautioned to test
index 49ba16f15c66cdf9e12df9cccabfc5aa859e554c..aa04f04bda9641e1dcbf138f6ba7a72b2bc3d1bd 100755 (executable)
@@ -4,7 +4,7 @@
 #   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 #   2011, 2012 Free Software Foundation, Inc.
 
-timestamp='2012-01-01'
+timestamp='2012-06-17'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -17,9 +17,7 @@ timestamp='2012-01-01'
 # General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-# 02110-1301, USA.
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
 #
 # As a special exception to the GNU General Public License, if you
 # distribute this file as part of a program that contains a
@@ -202,6 +200,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
        # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
        echo "${machine}-${os}${release}"
        exit ;;
+    *:Bitrig:*:*)
+       UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+       echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+       exit ;;
     *:OpenBSD:*:*)
        UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
        echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
@@ -863,6 +865,13 @@ EOF
     i*86:Minix:*:*)
        echo ${UNAME_MACHINE}-pc-minix
        exit ;;
+    aarch64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    aarch64_be:Linux:*:*)
+       UNAME_MACHINE=aarch64_be
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
     alpha:Linux:*:*)
        case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
          EV5)   UNAME_MACHINE=alphaev5 ;;
@@ -1251,7 +1260,7 @@ EOF
     NEO-?:NONSTOP_KERNEL:*:*)
        echo neo-tandem-nsk${UNAME_RELEASE}
        exit ;;
-    NSE-?:NONSTOP_KERNEL:*:*)
+    NSE-*:NONSTOP_KERNEL:*:*)
        echo nse-tandem-nsk${UNAME_RELEASE}
        exit ;;
     NSR-?:NONSTOP_KERNEL:*:*)
@@ -1320,6 +1329,9 @@ EOF
     i*86:AROS:*:*)
        echo ${UNAME_MACHINE}-pc-aros
        exit ;;
+    x86_64:VMkernel:*:*)
+       echo ${UNAME_MACHINE}-unknown-esx
+       exit ;;
 esac
 
 #echo '(No uname command or uname output not recognized.)' 1>&2
index d6b6b3c768ff22692f4cb79682672262f89e62df..aa2cf19b81e1b7db93ba04295e7c3998448c86ed 100755 (executable)
@@ -4,7 +4,7 @@
 #   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 #   2011, 2012 Free Software Foundation, Inc.
 
-timestamp='2012-01-01'
+timestamp='2012-06-17'
 
 # This file is (in principle) common to ALL GNU software.
 # The presence of a machine in this file suggests that SOME GNU software
@@ -21,9 +21,7 @@ timestamp='2012-01-01'
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-# 02110-1301, USA.
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
 #
 # As a special exception to the GNU General Public License, if you
 # distribute this file as part of a program that contains a
@@ -132,6 +130,10 @@ case $maybe_os in
     os=-$maybe_os
     basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
     ;;
+  android-linux)
+    os=-linux-android
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+    ;;
   *)
     basic_machine=`echo $1 | sed 's/-[^-]*$//'`
     if [ $basic_machine != $1 ]
@@ -223,6 +225,12 @@ case $os in
        -isc*)
                basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
                ;;
+       -lynx*178)
+               os=-lynxos178
+               ;;
+       -lynx*5)
+               os=-lynxos5
+               ;;
        -lynx*)
                os=-lynxos
                ;;
@@ -247,6 +255,7 @@ case $basic_machine in
        # Some are omitted here because they have special meanings below.
        1750a | 580 \
        | a29k \
+       | aarch64 | aarch64_be \
        | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
        | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
        | am33_2.0 \
@@ -319,7 +328,7 @@ case $basic_machine in
        c6x)
                basic_machine=tic6x-unknown
                ;;
-       m6811 | m68hc11 | m6812 | m68hc12 | picochip)
+       m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
                basic_machine=$basic_machine-unknown
                os=-none
                ;;
@@ -332,7 +341,10 @@ case $basic_machine in
        strongarm | thumb | xscale)
                basic_machine=arm-unknown
                ;;
-
+       xgate)
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
        xscaleeb)
                basic_machine=armeb-unknown
                ;;
@@ -355,6 +367,7 @@ case $basic_machine in
        # Recognize the basic CPU types with company name.
        580-* \
        | a29k-* \
+       | aarch64-* | aarch64_be-* \
        | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
        | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
        | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
@@ -1339,7 +1352,7 @@ case $os in
              | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
              | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
              | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
-             | -openbsd* | -solidbsd* \
+             | -bitrig* | -openbsd* | -solidbsd* \
              | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
              | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
              | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
@@ -1530,6 +1543,9 @@ case $basic_machine in
        c4x-* | tic4x-*)
                os=-coff
                ;;
+       hexagon-*)
+               os=-elf
+               ;;
        tic54x-*)
                os=-coff
                ;;
index bd0ac089584a762069b7e0b3f2937e89b9144cc7..0544c6835139b29baeedf1692eff58602bd14635 100755 (executable)
@@ -1,10 +1,9 @@
 #! /bin/sh
 # depcomp - compile a program generating dependencies as side-effects
 
-scriptversion=2011-12-04.11; # UTC
+scriptversion=2012-07-12.20; # UTC
 
-# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010,
-# 2011 Free Software Foundation, Inc.
+# Copyright (C) 1999-2012 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -28,7 +27,7 @@ scriptversion=2011-12-04.11; # UTC
 
 case $1 in
   '')
-     echo "$0: No command.  Try \`$0 --help' for more information." 1>&2
+     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
      exit 1;
      ;;
   -h | --h*)
@@ -40,8 +39,8 @@ as side-effects.
 
 Environment variables:
   depmode     Dependency tracking mode.
-  source      Source file read by `PROGRAMS ARGS'.
-  object      Object file output by `PROGRAMS ARGS'.
+  source      Source file read by 'PROGRAMS ARGS'.
+  object      Object file output by 'PROGRAMS ARGS'.
   DEPDIR      directory where to store dependencies.
   depfile     Dependency file to output.
   tmpdepfile  Temporary file to use when outputting dependencies.
@@ -57,6 +56,12 @@ EOF
     ;;
 esac
 
+# A tabulation character.
+tab='  '
+# A newline character.
+nl='
+'
+
 if test -z "$depmode" || test -z "$source" || test -z "$object"; then
   echo "depcomp: Variables source, object and depmode must be set" 1>&2
   exit 1
@@ -102,6 +107,12 @@ if test "$depmode" = msvc7msys; then
    depmode=msvc7
 fi
 
+if test "$depmode" = xlc; then
+   # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations.
+   gccflag=-qmakedep=gcc,-MF
+   depmode=gcc
+fi
+
 case "$depmode" in
 gcc3)
 ## gcc 3 implements dependency tracking that does exactly what
@@ -156,15 +167,14 @@ gcc)
 ## The second -e expression handles DOS-style file names with drive letters.
   sed -e 's/^[^:]*: / /' \
       -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
-## This next piece of magic avoids the `deleted header file' problem.
+## This next piece of magic avoids the "deleted header file" problem.
 ## The problem is that when a header file which appears in a .P file
 ## is deleted, the dependency causes make to die (because there is
 ## typically no way to rebuild the header).  We avoid this by adding
 ## dummy dependencies for each header file.  Too bad gcc doesn't do
 ## this for us directly.
-  tr ' ' '
-' < "$tmpdepfile" |
-## Some versions of gcc put a space before the `:'.  On the theory
+  tr ' ' "$nl" < "$tmpdepfile" |
+## Some versions of gcc put a space before the ':'.  On the theory
 ## that the space means something, we add a space to the output as
 ## well.  hp depmode also adds that space, but also prefixes the VPATH
 ## to the object.  Take care to not repeat it in the output.
@@ -203,18 +213,15 @@ sgi)
     # clever and replace this with sed code, as IRIX sed won't handle
     # lines with more than a fixed number of characters (4096 in
     # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
-    # the IRIX cc adds comments like `#:fec' to the end of the
+    # the IRIX cc adds comments like '#:fec' to the end of the
     # dependency line.
-    tr ' ' '
-' < "$tmpdepfile" \
+    tr ' ' "$nl" < "$tmpdepfile" \
     | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
-    tr '
-' ' ' >> "$depfile"
+    tr "$nl" ' ' >> "$depfile"
     echo >> "$depfile"
 
     # The second pass generates a dummy entry for each header file.
-    tr ' ' '
-' < "$tmpdepfile" \
+    tr ' ' "$nl" < "$tmpdepfile" \
    | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
    >> "$depfile"
   else
@@ -226,10 +233,17 @@ sgi)
   rm -f "$tmpdepfile"
   ;;
 
+xlc)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
 aix)
   # The C for AIX Compiler uses -M and outputs the dependencies
   # in a .u file.  In older versions, this file always lives in the
-  # current directory.  Also, the AIX compiler puts `$object:' at the
+  # current directory.  Also, the AIX compiler puts '$object:' at the
   # start of each line; $object doesn't have directory information.
   # Version 6 uses the directory in both cases.
   dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
@@ -259,12 +273,11 @@ aix)
     test -f "$tmpdepfile" && break
   done
   if test -f "$tmpdepfile"; then
-    # Each line is of the form `foo.o: dependent.h'.
+    # Each line is of the form 'foo.o: dependent.h'.
     # Do two passes, one to just change these to
-    # `$object: dependent.h' and one to simply `dependent.h:'.
+    # '$object: dependent.h' and one to simply 'dependent.h:'.
     sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
-    # That's a tab and a space in the [].
-    sed -e 's,^.*\.[a-z]*:[     ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+    sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
   else
     # The sourcefile does not contain any dependencies, so just
     # store a dummy comment line, to avoid errors with the Makefile
@@ -275,23 +288,26 @@ aix)
   ;;
 
 icc)
-  # Intel's C compiler understands `-MD -MF file'.  However on
-  #    icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+  # Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'.
+  # However on
+  #    $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c
   # ICC 7.0 will fill foo.d with something like
   #    foo.o: sub/foo.c
   #    foo.o: sub/foo.h
-  # which is wrong.  We want:
+  # which is wrong.  We want
   #    sub/foo.o: sub/foo.c
   #    sub/foo.o: sub/foo.h
   #    sub/foo.c:
   #    sub/foo.h:
   # ICC 7.1 will output
   #    foo.o: sub/foo.c sub/foo.h
-  # and will wrap long lines using :
+  # and will wrap long lines using '\':
   #    foo.o: sub/foo.c ... \
   #     sub/foo.h ... \
   #     ...
-
+  # tcc 0.9.26 (FIXME still under development at the moment of writing)
+  # will emit a similar output, but also prepend the continuation lines
+  # with horizontal tabulation characters.
   "$@" -MD -MF "$tmpdepfile"
   stat=$?
   if test $stat -eq 0; then :
@@ -300,6 +316,85 @@ icc)
     exit $stat
   fi
   rm -f "$depfile"
+  # Each line is of the form 'foo.o: dependent.h',
+  # or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'.
+  # Do two passes, one to just change these to
+  # '$object: dependent.h' and one to simply 'dependent.h:'.
+  sed -e "s/^[ $tab][ $tab]*/  /" -e "s,^[^:]*:,$object :," \
+    < "$tmpdepfile" > "$depfile"
+  sed '
+    s/[ '"$tab"'][ '"$tab"']*/ /g
+    s/^ *//
+    s/ *\\*$//
+    s/^[^:]*: *//
+    /^$/d
+    /:$/d
+    s/$/ :/
+  ' < "$tmpdepfile" >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+## The order of this option in the case statement is important, since the
+## shell code in configure will try each of these formats in the order
+## listed in this file.  A plain '-MD' option would be understood by many
+## compilers, so we must ensure this comes after the gcc and icc options.
+pgcc)
+  # Portland's C compiler understands '-MD'.
+  # Will always output deps to 'file.d' where file is the root name of the
+  # source file under compilation, even if file resides in a subdirectory.
+  # The object file name does not affect the name of the '.d' file.
+  # pgcc 10.2 will output
+  #    foo.o: sub/foo.c sub/foo.h
+  # and will wrap long lines using '\' :
+  #    foo.o: sub/foo.c ... \
+  #     sub/foo.h ... \
+  #     ...
+  dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+  test "x$dir" = "x$object" && dir=
+  # Use the source, not the object, to determine the base name, since
+  # that's sadly what pgcc will do too.
+  base=`echo "$source" | sed -e 's|^.*/||' -e 's/\.[-_a-zA-Z0-9]*$//'`
+  tmpdepfile="$base.d"
+
+  # For projects that build the same source file twice into different object
+  # files, the pgcc approach of using the *source* file root name can cause
+  # problems in parallel builds.  Use a locking strategy to avoid stomping on
+  # the same $tmpdepfile.
+  lockdir="$base.d-lock"
+  trap "echo '$0: caught signal, cleaning up...' >&2; rm -rf $lockdir" 1 2 13 15
+  numtries=100
+  i=$numtries
+  while test $i -gt 0 ; do
+    # mkdir is a portable test-and-set.
+    if mkdir $lockdir 2>/dev/null; then
+      # This process acquired the lock.
+      "$@" -MD
+      stat=$?
+      # Release the lock.
+      rm -rf $lockdir
+      break
+    else
+      ## the lock is being held by a different process,
+      ## wait until the winning process is done or we timeout
+      while test -d $lockdir && test $i -gt 0; do
+        sleep 1
+        i=`expr $i - 1`
+      done
+    fi
+    i=`expr $i - 1`
+  done
+  trap - 1 2 13 15
+  if test $i -le 0; then
+    echo "$0: failed to acquire lock after $numtries attempts" >&2
+    echo "$0: check lockdir '$lockdir'" >&2
+    exit 1
+  fi
+
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
   # Each line is of the form `foo.o: dependent.h',
   # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
   # Do two passes, one to just change these to
@@ -344,7 +439,7 @@ hp2)
   done
   if test -f "$tmpdepfile"; then
     sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
-    # Add `dependent.h:' lines.
+    # Add 'dependent.h:' lines.
     sed -ne '2,${
               s/^ *//
               s/ \\*$//
@@ -359,9 +454,9 @@ hp2)
 
 tru64)
    # The Tru64 compiler uses -MD to generate dependencies as a side
-   # effect.  `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+   # effect.  'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
    # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
-   # dependencies in `foo.d' instead, so we check for that too.
+   # dependencies in 'foo.d' instead, so we check for that too.
    # Subdirectories are respected.
    dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
    test "x$dir" = "x$object" && dir=
@@ -407,8 +502,7 @@ tru64)
    done
    if test -f "$tmpdepfile"; then
       sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
-      # That's a tab and a space in the [].
-      sed -e 's,^.*\.[a-z]*:[   ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+      sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
    else
       echo "#dummy" > "$depfile"
    fi
@@ -443,11 +537,11 @@ msvc7)
   p
 }' | $cygpath_u | sort -u | sed -n '
 s/ /\\ /g
-s/\(.*\)/      \1 \\/p
+s/\(.*\)/'"$tab"'\1 \\/p
 s/.\(.*\) \\/\1:/
 H
 $ {
-  s/.*/        /
+  s/.*/'"$tab"'/
   G
   p
 }' >> "$depfile"
@@ -478,7 +572,7 @@ dashmstdout)
     shift
   fi
 
-  # Remove `-o $object'.
+  # Remove '-o $object'.
   IFS=" "
   for arg
   do
@@ -498,15 +592,14 @@ dashmstdout)
   done
 
   test -z "$dashmflag" && dashmflag=-M
-  # Require at least two characters before searching for `:'
+  # Require at least two characters before searching for ':'
   # in the target name.  This is to cope with DOS-style filenames:
-  # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+  # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
   "$@" $dashmflag |
-    sed 's:^[  ]*[^: ][^:][^:]*\:[    ]*:'"$object"'\: :' > "$tmpdepfile"
+    sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile"
   rm -f "$depfile"
   cat < "$tmpdepfile" > "$depfile"
-  tr ' ' '
-' < "$tmpdepfile" | \
+  tr ' ' "$nl" < "$tmpdepfile" | \
 ## Some versions of the HPUX 10.20 sed can't process this invocation
 ## correctly.  Breaking it into two sed invocations is a workaround.
     sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
@@ -562,8 +655,7 @@ makedepend)
   # makedepend may prepend the VPATH from the source file name to the object.
   # No need to regex-escape $object, excess matching of '.' is harmless.
   sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
-  sed '1,2d' "$tmpdepfile" | tr ' ' '
-' | \
+  sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \
 ## Some versions of the HPUX 10.20 sed can't process this invocation
 ## correctly.  Breaking it into two sed invocations is a workaround.
     sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
@@ -583,7 +675,7 @@ cpp)
     shift
   fi
 
-  # Remove `-o $object'.
+  # Remove '-o $object'.
   IFS=" "
   for arg
   do
@@ -652,8 +744,8 @@ msvisualcpp)
   sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
   rm -f "$depfile"
   echo "$object : \\" > "$depfile"
-  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::     \1 \\:p' >> "$depfile"
-  echo "       " >> "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+  echo "$tab" >> "$depfile"
   sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
   rm -f "$tmpdepfile"
   ;;
index a9244eb0786534553fdd9eb0050bb4b172bad0a3..377bb8687ffe16bfc79ea25c8667cabf72aaf2c2 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 # install - install a program, script, or datafile
 
-scriptversion=2011-01-19.21; # UTC
+scriptversion=2011-11-20.07; # UTC
 
 # This originates from X11R5 (mit/util/scripts/install.sh), which was
 # later released in X11R6 (xc/config/util/install.sh) with the
@@ -35,7 +35,7 @@ scriptversion=2011-01-19.21; # UTC
 # FSF changes to this file are in the public domain.
 #
 # Calling this script install-sh is preferred over install.sh, to prevent
-# `make' implicit rules from creating a file called install from it
+# 'make' implicit rules from creating a file called install from it
 # when there is no Makefile.
 #
 # This script is compatible with the BSD install script, but was written
@@ -156,7 +156,7 @@ while test $# -ne 0; do
     -s) stripcmd=$stripprog;;
 
     -t) dst_arg=$2
-       # Protect names problematic for `test' and other utilities.
+       # Protect names problematic for 'test' and other utilities.
        case $dst_arg in
          -* | [=\(\)!]) dst_arg=./$dst_arg;;
        esac
@@ -190,7 +190,7 @@ if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
     fi
     shift # arg
     dst_arg=$arg
-    # Protect names problematic for `test' and other utilities.
+    # Protect names problematic for 'test' and other utilities.
     case $dst_arg in
       -* | [=\(\)!]) dst_arg=./$dst_arg;;
     esac
@@ -202,7 +202,7 @@ if test $# -eq 0; then
     echo "$0: no input file specified." >&2
     exit 1
   fi
-  # It's OK to call `install-sh -d' without argument.
+  # It's OK to call 'install-sh -d' without argument.
   # This can happen when creating conditional directories.
   exit 0
 fi
@@ -240,7 +240,7 @@ fi
 
 for src
 do
-  # Protect names problematic for `test' and other utilities.
+  # Protect names problematic for 'test' and other utilities.
   case $src in
     -* | [=\(\)!]) src=./$src;;
   esac
@@ -354,7 +354,7 @@ do
              if test -z "$dir_arg" || {
                   # Check for POSIX incompatibilities with -m.
                   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
-                  # other-writeable bit of parent directory when it shouldn't.
+                  # other-writable bit of parent directory when it shouldn't.
                   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
                   ls_ld_tmpdir=`ls -ld "$tmpdir"`
                   case $ls_ld_tmpdir in
index 63ae69dc6fecaf83c52fba2ad334f4b1369fb1cd..9ae038c248a77a5bc6b732b703093a8cdc62aa74 100644 (file)
@@ -5851,9 +5851,10 @@ func_mode_link ()
       # -tp=*                Portland pgcc target processor selection
       # --sysroot=*          for sysroot support
       # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+      # -stdlib=*            select c++ std lib with clang
       -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
       -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
-      -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
+      -O*|-flto*|-fwhopr*|-fuse-linker-plugin|-stdlib=*)
         func_quote_for_eval "$arg"
        arg="$func_quote_for_eval_result"
         func_append compile_command " $arg"
index 86a8fc31e3c2aa268688a5be47d161c586772e78..9a5564823de4c47d7825a85adea87328123cb6ff 100755 (executable)
@@ -1,10 +1,9 @@
 #! /bin/sh
 # Common stub for a few missing GNU programs while installing.
 
-scriptversion=2012-01-06.13; # UTC
+scriptversion=2012-01-06.18; # UTC
 
-# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
-# 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+# Copyright (C) 1996-2012 Free Software Foundation, Inc.
 # Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
 
 # This program is free software; you can redistribute it and/or modify
@@ -26,7 +25,7 @@ scriptversion=2012-01-06.13; # UTC
 # the same distribution terms that you use for the rest of that program.
 
 if test $# -eq 0; then
-  echo 1>&2 "Try \`$0 --help' for more information"
+  echo 1>&2 "Try '$0 --help' for more information"
   exit 1
 fi
 
@@ -34,7 +33,7 @@ run=:
 sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
 sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
 
-# In the cases where this matters, `missing' is being run in the
+# In the cases where this matters, 'missing' is being run in the
 # srcdir already.
 if test -f configure.ac; then
   configure_ac=configure.ac
@@ -65,7 +64,7 @@ case $1 in
     echo "\
 $0 [OPTION]... PROGRAM [ARGUMENT]...
 
-Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+Handle 'PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
 error status if there is no known handling for PROGRAM.
 
 Options:
@@ -74,20 +73,20 @@ Options:
   --run           try to run the given command, and emulate it if it fails
 
 Supported PROGRAM values:
-  aclocal      touch file \`aclocal.m4'
-  autoconf     touch file \`configure'
-  autoheader   touch file \`config.h.in'
+  aclocal      touch file 'aclocal.m4'
+  autoconf     touch file 'configure'
+  autoheader   touch file 'config.h.in'
   autom4te     touch the output file, or create a stub one
-  automake     touch all \`Makefile.in' files
-  bison        create \`y.tab.[ch]', if possible, from existing .[ch]
-  flex         create \`lex.yy.c', if possible, from existing .c
+  automake     touch all 'Makefile.in' files
+  bison        create 'y.tab.[ch]', if possible, from existing .[ch]
+  flex         create 'lex.yy.c', if possible, from existing .c
   help2man     touch the output file
-  lex          create \`lex.yy.c', if possible, from existing .c
+  lex          create 'lex.yy.c', if possible, from existing .c
   makeinfo     touch the output file
-  yacc         create \`y.tab.[ch]', if possible, from existing .[ch]
+  yacc         create 'y.tab.[ch]', if possible, from existing .[ch]
 
-Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
-\`g' are ignored when checking the name.
+Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
+'g' are ignored when checking the name.
 
 Send bug reports to <bug-automake@gnu.org>."
     exit $?
@@ -99,8 +98,8 @@ Send bug reports to <bug-automake@gnu.org>."
     ;;
 
   -*)
-    echo 1>&2 "$0: Unknown \`$1' option"
-    echo 1>&2 "Try \`$0 --help' for more information"
+    echo 1>&2 "$0: Unknown '$1' option"
+    echo 1>&2 "Try '$0 --help' for more information"
     exit 1
     ;;
 
@@ -127,7 +126,7 @@ case $1 in
        exit 1
     elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
        # Could not run --version or --help.  This is probably someone
-       # running `$TOOL --version' or `$TOOL --help' to check whether
+       # running '$TOOL --version' or '$TOOL --help' to check whether
        # $TOOL exists and not knowing $TOOL uses missing.
        exit 1
     fi
@@ -139,27 +138,27 @@ esac
 case $program in
   aclocal*)
     echo 1>&2 "\
-WARNING: \`$1' is $msg.  You should only need it if
-         you modified \`acinclude.m4' or \`${configure_ac}'.  You might want
-         to install the \`Automake' and \`Perl' packages.  Grab them from
+WARNING: '$1' is $msg.  You should only need it if
+         you modified 'acinclude.m4' or '${configure_ac}'.  You might want
+         to install the Automake and Perl packages.  Grab them from
          any GNU archive site."
     touch aclocal.m4
     ;;
 
   autoconf*)
     echo 1>&2 "\
-WARNING: \`$1' is $msg.  You should only need it if
-         you modified \`${configure_ac}'.  You might want to install the
-         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
+WARNING: '$1' is $msg.  You should only need it if
+         you modified '${configure_ac}'.  You might want to install the
+         Autoconf and GNU m4 packages.  Grab them from any GNU
          archive site."
     touch configure
     ;;
 
   autoheader*)
     echo 1>&2 "\
-WARNING: \`$1' is $msg.  You should only need it if
-         you modified \`acconfig.h' or \`${configure_ac}'.  You might want
-         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
+WARNING: '$1' is $msg.  You should only need it if
+         you modified 'acconfig.h' or '${configure_ac}'.  You might want
+         to install the Autoconf and GNU m4 packages.  Grab them
          from any GNU archive site."
     files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
     test -z "$files" && files="config.h"
@@ -176,9 +175,9 @@ WARNING: \`$1' is $msg.  You should only need it if
 
   automake*)
     echo 1>&2 "\
-WARNING: \`$1' is $msg.  You should only need it if
-         you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
-         You might want to install the \`Automake' and \`Perl' packages.
+WARNING: '$1' is $msg.  You should only need it if
+         you modified 'Makefile.am', 'acinclude.m4' or '${configure_ac}'.
+         You might want to install the Automake and Perl packages.
          Grab them from any GNU archive site."
     find . -type f -name Makefile.am -print |
           sed 's/\.am$/.in/' |
@@ -187,10 +186,10 @@ WARNING: \`$1' is $msg.  You should only need it if
 
   autom4te*)
     echo 1>&2 "\
-WARNING: \`$1' is needed, but is $msg.
+WARNING: '$1' is needed, but is $msg.
          You might have modified some files without having the
          proper tools for further handling them.
-         You can get \`$1' as part of \`Autoconf' from any GNU
+         You can get '$1' as part of Autoconf from any GNU
          archive site."
 
     file=`echo "$*" | sed -n "$sed_output"`
@@ -210,10 +209,10 @@ WARNING: \`$1' is needed, but is $msg.
 
   bison*|yacc*)
     echo 1>&2 "\
-WARNING: \`$1' $msg.  You should only need it if
-         you modified a \`.y' file.  You may need the \`Bison' package
+WARNING: '$1' $msg.  You should only need it if
+         you modified a '.y' file.  You may need the Bison package
          in order for those modifications to take effect.  You can get
-         \`Bison' from any GNU archive site."
+         Bison from any GNU archive site."
     rm -f y.tab.c y.tab.h
     if test $# -ne 1; then
         eval LASTARG=\${$#}
@@ -240,10 +239,10 @@ WARNING: \`$1' $msg.  You should only need it if
 
   lex*|flex*)
     echo 1>&2 "\
-WARNING: \`$1' is $msg.  You should only need it if
-         you modified a \`.l' file.  You may need the \`Flex' package
+WARNING: '$1' is $msg.  You should only need it if
+         you modified a '.l' file.  You may need the Flex package
          in order for those modifications to take effect.  You can get
-         \`Flex' from any GNU archive site."
+         Flex from any GNU archive site."
     rm -f lex.yy.c
     if test $# -ne 1; then
         eval LASTARG=\${$#}
@@ -263,10 +262,10 @@ WARNING: \`$1' is $msg.  You should only need it if
 
   help2man*)
     echo 1>&2 "\
-WARNING: \`$1' is $msg.  You should only need it if
+WARNING: '$1' is $msg.  You should only need it if
         you modified a dependency of a manual page.  You may need the
-        \`Help2man' package in order for those modifications to take
-        effect.  You can get \`Help2man' from any GNU archive site."
+        Help2man package in order for those modifications to take
+        effect.  You can get Help2man from any GNU archive site."
 
     file=`echo "$*" | sed -n "$sed_output"`
     test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
@@ -281,12 +280,12 @@ WARNING: \`$1' is $msg.  You should only need it if
 
   makeinfo*)
     echo 1>&2 "\
-WARNING: \`$1' is $msg.  You should only need it if
-         you modified a \`.texi' or \`.texinfo' file, or any other file
+WARNING: '$1' is $msg.  You should only need it if
+         you modified a '.texi' or '.texinfo' file, or any other file
          indirectly affecting the aspect of the manual.  The spurious
-         call might also be the consequence of using a buggy \`make' (AIX,
-         DU, IRIX).  You might want to install the \`Texinfo' package or
-         the \`GNU make' package.  Grab either from any GNU archive site."
+         call might also be the consequence of using a buggy 'make' (AIX,
+         DU, IRIX).  You might want to install the Texinfo package or
+         the GNU make package.  Grab either from any GNU archive site."
     # The file to touch is that specified with -o ...
     file=`echo "$*" | sed -n "$sed_output"`
     test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
@@ -310,12 +309,12 @@ WARNING: \`$1' is $msg.  You should only need it if
 
   *)
     echo 1>&2 "\
-WARNING: \`$1' is needed, and is $msg.
+WARNING: '$1' is needed, and is $msg.
          You might have modified some files without having the
-         proper tools for further handling them.  Check the \`README' file,
+         proper tools for further handling them.  Check the 'README' file,
          it often tells you about the needed prerequisites for installing
          this package.  You may also peek at any GNU archive site, in case
-         some other package would contain this missing \`$1' program."
+         some other package would contain this missing '$1' program."
     exit 1
     ;;
 esac
index 0c9af7f2c374c0ee477fb685fa86135a763b5a00..59d982fbf06b50690e338605fddf6620317ce955 100644 (file)
@@ -37,7 +37,7 @@ AC_PREREQ([2.59])
 # 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.
-AC_INIT([asdcplib], [1.10.48], [asdcplib@cinecert.com])
+AC_INIT([asdcplib], [1.11.49], [asdcplib@cinecert.com])
 
 AC_CONFIG_AUX_DIR([build-aux])
 AC_CONFIG_SRCDIR([src/KM_error.h])
index c0556ba7d71c9c91fed2baa45098b072bc7bc484..b9aba837651a94f69b47f5238f3727a562056fe6 100755 (executable)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2003-2012, John Hurst
+Copyright (c) 2003-2013, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -25,7 +25,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 /*! \file    AS_DCP.h
-    \version $Id$       
+    \version $Id$
     \brief   AS-DCP library, public interface
 
 The asdcplib library is a set of file access objects that offer simplified
@@ -87,6 +87,7 @@ This project depends upon the following libraries:
 #define _AS_DCP_H_
 
 #include <KM_error.h>
+#include <KM_fileio.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <math.h>
@@ -203,13 +204,15 @@ namespace ASDCP {
   // The file accessors in this library implement a bounded set of essence types.
   // This list will be expanded when support for new types is added to the library.
   enum EssenceType_t {
-    ESS_UNKNOWN,     // the file is not a supported AS-DCP essence container
-    ESS_MPEG2_VES,   // the file contains an MPEG video elementary stream
-    ESS_JPEG_2000,   // the file contains one or more JPEG 2000 codestreams
-    ESS_PCM_24b_48k, // the file contains one or more PCM audio pairs
-    ESS_PCM_24b_96k, // the file contains one or more PCM audio pairs
-    ESS_TIMED_TEXT,  // the file contains an XML timed text document and one or more resources
-    ESS_JPEG_2000_S, // the file contains one or more JPEG 2000 codestream pairs (stereoscopic)
+    ESS_UNKNOWN,              // the file is not a supported AS-DCP essence container
+    ESS_MPEG2_VES,            // the file contains an MPEG video elementary stream
+    ESS_JPEG_2000,            // the file contains one or more JPEG 2000 codestreams
+    ESS_PCM_24b_48k,          // the file contains one or more PCM audio pairs
+    ESS_PCM_24b_96k,          // the file contains one or more PCM audio pairs
+    ESS_TIMED_TEXT,           // the file contains an XML timed text document and one or more resources
+    ESS_JPEG_2000_S,          // the file contains one or more JPEG 2000 codestream pairs (stereoscopic)
+    ESS_DCDATA_UNKNOWN,       // the file contains one or more D-Cinema Data bytestreams
+    ESS_DCDATA_DOLBY_ATMOS,   // the file contains one or more DolbyATMOS bytestreams
   };
 
   // Determine the type of essence contained in the given MXF file. RESULT_OK
@@ -253,7 +256,7 @@ namespace ASDCP {
       if ( Numerator == rhs.Numerator && Denominator < rhs.Denominator )    return true;
       return false;
     }
+
     inline bool operator>(const Rational& rhs) {
       if ( Numerator > rhs.Numerator )     return true;
       if ( Numerator == rhs.Numerator && Denominator > rhs.Denominator )     return true;
@@ -365,7 +368,7 @@ namespace ASDCP {
       static byte_t default_ProductUUID_Data[UUIDlen] = {
        0x43, 0x05, 0x9a, 0x1d, 0x04, 0x32, 0x41, 0x01,
        0xb8, 0x3f, 0x73, 0x68, 0x15, 0xac, 0xf3, 0x1d };
-      
+
       memcpy(ProductUUID, default_ProductUUID_Data, UUIDlen);
       memset(AssetUUID, 0, UUIDlen);
       memset(ContextID, 0, UUIDlen);
@@ -407,7 +410,7 @@ namespace ASDCP {
       // Initializes Rijndael CBC encryption context.
       // Returns error if the key argument is NULL.
       Result_t InitKey(const byte_t* key);
-      
+
       // Initializes 16 byte CBC Initialization Vector. This operation may be performed
       // any number of times for a given key.
       // Returns error if the i_vec argument is NULL.
@@ -601,22 +604,22 @@ namespace ASDCP {
       // MPEG2VideoDescriptor object.
       struct VideoDescriptor
        {
-         Rational EditRate;                // 
-         ui32_t   FrameRate;               // 
-         Rational SampleRate;              // 
-         ui8_t    FrameLayout;             // 
-         ui32_t   StoredWidth;             // 
-         ui32_t   StoredHeight;            // 
-         Rational AspectRatio;             // 
-         ui32_t   ComponentDepth;          // 
-         ui32_t   HorizontalSubsampling;   // 
-         ui32_t   VerticalSubsampling;     // 
-         ui8_t    ColorSiting;             // 
-         ui8_t    CodedContentType;        // 
-         bool     LowDelay;                // 
-         ui32_t   BitRate;                 // 
-         ui8_t    ProfileAndLevel;         // 
-         ui32_t   ContainerDuration;       // 
+         Rational EditRate;                //
+         ui32_t   FrameRate;               //
+         Rational SampleRate;              //
+         ui8_t    FrameLayout;             //
+         ui32_t   StoredWidth;             //
+         ui32_t   StoredHeight;            //
+         Rational AspectRatio;             //
+         ui32_t   ComponentDepth;          //
+         ui32_t   HorizontalSubsampling;   //
+         ui32_t   VerticalSubsampling;     //
+         ui8_t    ColorSiting;             //
+         ui8_t    CodedContentType;        //
+         bool     LowDelay;                //
+         ui32_t   BitRate;                 //
+         ui8_t    ProfileAndLevel;         //
+         ui32_t   ContainerDuration;       //
       };
 
       // Print VideoDescriptor to std::ostream
@@ -646,7 +649,7 @@ namespace ASDCP {
            {
              Capacity(size);
            }
-           
+
          virtual ~FrameBuffer() {}
 
          // Sets the MPEG frame type of the picture data in the frame buffer.
@@ -787,6 +790,12 @@ namespace ASDCP {
          // out of range, or if optional decrypt or HAMC operations fail.
          Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
 
+         // Using the index table read from the footer partition, lookup the frame number
+         // and return the offset into the file at which to read that frame of essence.
+         // Returns RESULT_INIT if the file is not open, and RESULT_RANGE if the frame number is
+         // out of range.
+         Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const;
+
          // Calculates the first frame in transport order of the GOP in which the requested
          // frame is located.  Calls ReadFrame() to fetch the frame at the calculated position.
          // Returns RESULT_INIT if the file is not open.
@@ -836,12 +845,12 @@ namespace ASDCP {
        {
          Rational EditRate;         // rate of frame wrapping
          Rational AudioSamplingRate;  // rate of audio sample
-         ui32_t   Locked;             // 
+         ui32_t   Locked;             //
          ui32_t   ChannelCount;       // number of channels
          ui32_t   QuantizationBits;   // number of bits per single-channel sample
          ui32_t   BlockAlign;         // number of bytes ber sample, all channels
-         ui32_t   AvgBps;             // 
-         ui32_t   LinkedTrackID;      // 
+         ui32_t   AvgBps;             //
+         ui32_t   LinkedTrackID;      //
          ui32_t   ContainerDuration;  // number of frames
          ChannelFormat_t ChannelFormat; // audio channel arrangement
       };
@@ -877,7 +886,7 @@ namespace ASDCP {
          FrameBuffer() {}
          FrameBuffer(ui32_t size) { Capacity(size); }
          virtual ~FrameBuffer() {}
-       
+
          // Print debugging information to stream (stderr default)
          void Dump(FILE* = 0, ui32_t dump_bytes = 0) const;
        };
@@ -986,6 +995,12 @@ namespace ASDCP {
          // out of range, or if optional decrypt or HAMC operations fail.
          Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
 
+         // Using the index table read from the footer partition, lookup the frame number
+         // and return the offset into the file at which to read that frame of essence.
+         // Returns RESULT_INIT if the file is not open, and RESULT_RANGE if the frame number is
+         // out of range.
+         Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const;
+
          // Print debugging information to stream
          void     DumpHeaderMetadata(FILE* = 0) const;
          void     DumpIndex(FILE* = 0) const;
@@ -1018,7 +1033,7 @@ namespace ASDCP {
          ui8_t  NumberOfLayers[sizeof(ui16_t)];
          ui8_t  MultiCompTransform;
        } SGcod;
-       
+
        struct
        {
          ui8_t  DecompositionLevels;
@@ -1073,7 +1088,7 @@ namespace ASDCP {
          FrameBuffer() {}
          FrameBuffer(ui32_t size) { Capacity(size); }
          virtual ~FrameBuffer() {}
-       
+
          // Print debugging information to stream (stderr default)
          void Dump(FILE* = 0, ui32_t dump_bytes = 0) const;
        };
@@ -1125,7 +1140,7 @@ namespace ASDCP {
          // alphabetically by filename. The parser will automatically parse enough data
          // from the first file to provide a complete set of stream metadata for the
          // MXFWriter below.  If the "pedantic" parameter is given and is true, the
-         // parser will check the metadata for each codestream and fail if a 
+         // parser will check the metadata for each codestream and fail if a
          // mismatch is detected.
          Result_t OpenRead(const char* filename, bool pedantic = false) const;
 
@@ -1134,7 +1149,7 @@ namespace ASDCP {
          // picture. The parser will automatically parse enough data
          // from the first file to provide a complete set of stream metadata for the
          // MXFWriter below.  If the "pedantic" parameter is given and is true, the
-         // parser will check the metadata for each codestream and fail if a 
+         // parser will check the metadata for each codestream and fail if a
          // mismatch is detected.
          Result_t OpenRead(const std::list<std::string>& file_list, bool pedantic = false) const;
 
@@ -1227,6 +1242,12 @@ namespace ASDCP {
          // out of range, or if optional decrypt or HAMC operations fail.
          Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
 
+         // Using the index table read from the footer partition, lookup the frame number
+         // and return the offset into the file at which to read that frame of essence.
+         // Returns RESULT_INIT if the file is not open, and RESULT_FRAME if the frame number is
+         // out of range.
+         Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const;
+
          // Print debugging information to stream
          void     DumpHeaderMetadata(FILE* = 0) const;
          void     DumpIndex(FILE* = 0) const;
@@ -1241,7 +1262,7 @@ namespace ASDCP {
        SP_LEFT,
        SP_RIGHT
       };
-      
+
       struct SFrameBuffer
       {
        JP2K::FrameBuffer Left;
@@ -1344,6 +1365,12 @@ namespace ASDCP {
          Result_t ReadFrame(ui32_t frame_number, StereoscopicPhase_t phase,
                             FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
 
+         // Using the index table read from the footer partition, lookup the frame number
+         // and return the offset into the file at which to read that frame of essence.
+         // Returns RESULT_INIT if the file is not open, and RESULT_FRAME if the frame number is
+         // out of range.
+         Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const;
+
          // Print debugging information to stream
          void     DumpHeaderMetadata(FILE* = 0) const;
          void     DumpIndex(FILE* = 0) const;
@@ -1359,7 +1386,7 @@ namespace ASDCP {
       struct TimedTextResourceDescriptor
       {
        byte_t      ResourceID[UUIDlen];
-       MIMEType_t  Type;
+          MIMEType_t  Type;
 
         TimedTextResourceDescriptor() : Type(MT_BIN) {}
       };
@@ -1368,7 +1395,7 @@ namespace ASDCP {
 
       struct TimedTextDescriptor
       {
-       Rational       EditRate;                // 
+       Rational       EditRate;                //
        ui32_t         ContainerDuration;
        byte_t         AssetID[UUIDlen];
        std::string    NamespaceName;
@@ -1396,7 +1423,7 @@ namespace ASDCP {
        FrameBuffer() { memset(m_AssetID, 0, UUIDlen); }
        FrameBuffer(ui32_t size) { Capacity(size); memset(m_AssetID, 0, UUIDlen); }
        virtual ~FrameBuffer() {}
-        
+
        inline const byte_t* AssetID() const { return m_AssetID; }
        inline void          AssetID(const byte_t* buf) { memcpy(m_AssetID, buf, UUIDlen); }
        inline const char*   MIMEType() const { return m_MIMEType.c_str(); }
@@ -1554,6 +1581,290 @@ namespace ASDCP {
        };
     } // namespace TimedText
 
+  //---------------------------------------------------------------------------------
+  //
+  namespace DCData
+  {
+    struct DCDataDescriptor
+    {
+      Rational EditRate;                 // Sample rate
+      ui32_t   ContainerDuration;          // number of frames
+      byte_t   AssetID[UUIDlen];           // The UUID for the DCData track
+      byte_t   DataEssenceCoding[UUIDlen]; // The coding for the data carried
+    };
+
+    // Print DCDataDescriptor to std::ostream
+    std::ostream& operator << (std::ostream& strm, const DCDataDescriptor& ddesc);
+    // Print debugging information to stream (stderr default)
+    void DCDataDescriptorDump(const DCDataDescriptor&, FILE* = 0);
+
+    //
+    class FrameBuffer : public ASDCP::FrameBuffer
+       {
+     public:
+         FrameBuffer() {}
+         FrameBuffer(ui32_t size) { Capacity(size); }
+         virtual ~FrameBuffer() {}
+
+         // Print debugging information to stream (stderr default)
+         void Dump(FILE* = 0, ui32_t dump_bytes = 0) const;
+       };
+
+    // An object which opens and reads a DC Data file.  The file is expected
+    // to contain exactly one complete frame of DC data essence as an unwrapped (raw)
+    // byte stream.
+    class BytestreamParser
+       {
+         class h__BytestreamParser;
+         mem_ptr<h__BytestreamParser> m_Parser;
+         ASDCP_NO_COPY_CONSTRUCT(BytestreamParser);
+
+     public:
+         BytestreamParser();
+         virtual ~BytestreamParser();
+
+         // Opens a file for reading, parses enough data to provide a complete
+      // set of stream metadata for the MXFWriter below.
+         // The frame buffer's PlaintextOffset parameter will be set to the first
+         // byte of the data segment. Set this value to zero if you want
+         // encrypted headers.
+         Result_t OpenReadFrame(const char* filename, FrameBuffer&) const;
+
+         // Fill a DCDataDescriptor struct with the values from the file's bytestream.
+         // Returns RESULT_INIT if the file is not open.
+         Result_t FillDCDataDescriptor(DCDataDescriptor&) const;
+       };
+
+    // An object which reads a sequence of files containing DC Data.
+    class SequenceParser
+       {
+         class h__SequenceParser;
+         mem_ptr<h__SequenceParser> m_Parser;
+         ASDCP_NO_COPY_CONSTRUCT(SequenceParser);
+
+     public:
+         SequenceParser();
+         virtual ~SequenceParser();
+
+         // Opens a directory for reading.  The directory is expected to contain one or
+         // more files, each containing the bytestream for exactly one frame. The files
+      // must be named such that the frames are in temporal order when sorted
+         // alphabetically by filename.
+         Result_t OpenRead(const char* filename) const;
+
+         // Opens a file sequence for reading.  The sequence is expected to contain one or
+         // more filenames, each naming a file containing the bytestream for exactly one
+         // frame.
+         Result_t OpenRead(const std::list<std::string>& file_list) const;
+
+         // Fill a DCDataDescriptor struct with default values.
+         // Returns RESULT_INIT if the directory is not open.
+         Result_t FillDCDataDescriptor(DCDataDescriptor&) const;
+
+         // Rewind the directory to the beginning.
+         Result_t Reset() const;
+
+         // Reads the next sequential frame in the directory and places it in the
+         // frame buffer. Fails if the buffer is too small or the direcdtory
+         // contains no more files.
+         // The frame buffer's PlaintextOffset parameter will be set to the first
+         // byte of the data segment. Set this value to zero if you want
+         // encrypted headers.
+         Result_t ReadFrame(FrameBuffer&) const;
+       };
+
+    //
+    class MXFWriter
+       {
+         class h__Writer;
+         mem_ptr<h__Writer> m_Writer;
+         ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
+
+     public:
+         MXFWriter();
+         virtual ~MXFWriter();
+
+         // Warning: direct manipulation of MXF structures can interfere
+         // with the normal operation of the wrapper.  Caveat emptor!
+         virtual MXF::OPAtomHeader& OPAtomHeader();
+         virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+         // Open the file for writing. The file must not exist. Returns error if
+         // the operation cannot be completed or if nonsensical data is discovered
+         // in the essence descriptor.
+         Result_t OpenWrite(const char* filename, const WriterInfo&,
+                            const DCDataDescriptor&, ui32_t HeaderSize = 16384);
+
+         // Writes a frame of essence to the MXF file. If the optional AESEncContext
+         // argument is present, the essence is encrypted prior to writing.
+         // Fails if the file is not open, is finalized, or an operating system
+         // error occurs.
+         Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+
+         // Closes the MXF file, writing the index and revised header.
+         Result_t Finalize();
+       };
+
+    //
+    class MXFReader
+       {
+         class h__Reader;
+         mem_ptr<h__Reader> m_Reader;
+         ASDCP_NO_COPY_CONSTRUCT(MXFReader);
+
+     public:
+         MXFReader();
+         virtual ~MXFReader();
+
+         // Warning: direct manipulation of MXF structures can interfere
+         // with the normal operation of the wrapper.  Caveat emptor!
+         virtual MXF::OPAtomHeader& OPAtomHeader();
+         virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+         // Open the file for reading. The file must exist. Returns error if the
+         // operation cannot be completed.
+         Result_t OpenRead(const char* filename) const;
+
+         // Returns RESULT_INIT if the file is not open.
+         Result_t Close() const;
+
+         // Fill a DCDataDescriptor struct with the values from the file's header.
+         // Returns RESULT_INIT if the file is not open.
+         Result_t FillDCDataDescriptor(DCDataDescriptor&) const;
+
+         // Fill a WriterInfo struct with the values from the file's header.
+         // Returns RESULT_INIT if the file is not open.
+         Result_t FillWriterInfo(WriterInfo&) const;
+
+         // Reads a frame of essence from the MXF file. If the optional AESEncContext
+         // argument is present, the essence is decrypted after reading. If the MXF
+         // file is encrypted and the AESDecContext argument is NULL, the frame buffer
+         // will contain the ciphertext frame data. If the HMACContext argument is
+         // not NULL, the HMAC will be calculated (if the file supports it).
+         // Returns RESULT_INIT if the file is not open, failure if the frame number is
+         // out of range, or if optional decrypt or HAMC operations fail.
+         Result_t ReadFrame(ui32_t frame_number, FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+         // Using the index table read from the footer partition, lookup the frame number
+         // and return the offset into the file at which to read that frame of essence.
+         // Returns RESULT_INIT if the file is not open, and RESULT_RANGE if the frame number is
+         // out of range.
+         Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const;
+
+         // Print debugging information to stream
+         void     DumpHeaderMetadata(FILE* = 0) const;
+         void     DumpIndex(FILE* = 0) const;
+       };
+
+  } // namespace DCData
+
+  //---------------------------------------------------------------------------------
+  //
+  namespace ATMOS
+  {
+    struct AtmosDescriptor : public DCData::DCDataDescriptor
+    {
+      ui32_t FirstFrame;       // Frame number of the frame to align with the FFOA of the picture track
+      ui16_t MaxChannelCount;  // Max number of channels in bitstream
+      ui16_t MaxObjectCount;   // Max number of objects in bitstream
+      byte_t AtmosID[UUIDlen]; // UUID of Atmos Project
+      ui8_t  AtmosVersion;     // ATMOS Coder Version used to create bitstream
+    };
+
+    // Print AtmosDescriptor to std::ostream
+    std::ostream& operator << (std::ostream& strm, const AtmosDescriptor& adesc);
+    // Print debugging information to stream (stderr default)
+    void AtmosDescriptorDump(const AtmosDescriptor&, FILE* = 0);
+    // Determine if a file is a raw atmos file
+    bool IsDolbyAtmos(const char* filename);
+
+    //
+    class MXFWriter
+       {
+
+      class h__Writer;
+         mem_ptr<h__Writer> m_Writer;
+         ASDCP_NO_COPY_CONSTRUCT(MXFWriter);
+
+     public:
+         MXFWriter();
+         virtual ~MXFWriter();
+
+         // Warning: direct manipulation of MXF structures can interfere
+         // with the normal operation of the wrapper.  Caveat emptor!
+         virtual MXF::OPAtomHeader& OPAtomHeader();
+         virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+         // Open the file for writing. The file must not exist. Returns error if
+         // the operation cannot be completed or if nonsensical data is discovered
+         // in the essence descriptor.
+         Result_t OpenWrite(const char* filename, const WriterInfo&,
+                            const AtmosDescriptor&, ui32_t HeaderSize = 16384);
+
+         // Writes a frame of essence to the MXF file. If the optional AESEncContext
+         // argument is present, the essence is encrypted prior to writing.
+         // Fails if the file is not open, is finalized, or an operating system
+         // error occurs.
+      Result_t WriteFrame(const DCData::FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+
+         // Closes the MXF file, writing the index and revised header.
+         Result_t Finalize();
+       };
+
+    //
+    class MXFReader
+       {
+      class h__Reader;
+         mem_ptr<h__Reader> m_Reader;
+         ASDCP_NO_COPY_CONSTRUCT(MXFReader);
+
+     public:
+         MXFReader();
+         virtual ~MXFReader();
+
+         // Warning: direct manipulation of MXF structures can interfere
+         // with the normal operation of the wrapper.  Caveat emptor!
+         virtual MXF::OPAtomHeader& OPAtomHeader();
+         virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter();
+
+         // Open the file for reading. The file must exist. Returns error if the
+         // operation cannot be completed.
+         Result_t OpenRead(const char* filename) const;
+
+         // Returns RESULT_INIT if the file is not open.
+         Result_t Close() const;
+
+         // Fill an AtmosDescriptor struct with the values from the file's header.
+         // Returns RESULT_INIT if the file is not open.
+         Result_t FillAtmosDescriptor(AtmosDescriptor&) const;
+
+         // Fill a WriterInfo struct with the values from the file's header.
+         // Returns RESULT_INIT if the file is not open.
+         Result_t FillWriterInfo(WriterInfo&) const;
+
+         // Reads a frame of essence from the MXF file. If the optional AESEncContext
+         // argument is present, the essence is decrypted after reading. If the MXF
+         // file is encrypted and the AESDecContext argument is NULL, the frame buffer
+         // will contain the ciphertext frame data. If the HMACContext argument is
+         // not NULL, the HMAC will be calculated (if the file supports it).
+         // Returns RESULT_INIT if the file is not open, failure if the frame number is
+         // out of range, or if optional decrypt or HAMC operations fail.
+         Result_t ReadFrame(ui32_t frame_number, DCData::FrameBuffer&, AESDecContext* = 0, HMACContext* = 0) const;
+
+         // Using the index table read from the footer partition, lookup the frame number
+         // and return the offset into the file at which to read that frame of essence.
+         // Returns RESULT_INIT if the file is not open, and RESULT_RANGE if the frame number is
+         // out of range.
+         Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const;
+
+         // Print debugging information to stream
+         void     DumpHeaderMetadata(FILE* = 0) const;
+         void     DumpIndex(FILE* = 0) const;
+       };
+
+  } // namespace ATMOS
+
+
 
 } // namespace ASDCP
 
diff --git a/src/AS_DCP_ATMOS.cpp b/src/AS_DCP_ATMOS.cpp
new file mode 100644 (file)
index 0000000..da23a0a
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+Copyright (c) 2004-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    AS_DCP_ATMOS.cpp
+    \version $Id$
+    \brief   AS-DCP library, Dolby Atmos essence reader and writer implementation
+*/
+
+
+#include <iostream>
+
+#include "AS_DCP.h"
+#include "AS_DCP_DCData_internal.h"
+#include "AS_DCP_internal.h"
+
+namespace ASDCP
+{
+namespace ATMOS
+{
+  static std::string ATMOS_PACKAGE_LABEL = "File Package: SMPTE 382M frame wrapping of Dolby ATMOS data";
+  static std::string ATMOS_DEF_LABEL = "Dolby ATMOS Data Track";
+  static byte_t ATMOS_ESSENCE_CODING[SMPTE_UL_LENGTH] = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x05,
+                                                          0x0e, 0x09, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00 };
+} // namespace ATMOS
+} // namespace ASDCP
+
+//
+std::ostream&
+ASDCP::ATMOS::operator << (std::ostream& strm, const AtmosDescriptor& ADesc)
+{
+  char str_buf[40];
+  strm << "        EditRate: " << ADesc.EditRate.Numerator << "/" << ADesc.EditRate.Denominator << std::endl;
+  strm << " ContainerDuration: " << (unsigned) ADesc.ContainerDuration << std::endl;
+  strm << " DataEssenceCoding: " << UL(ADesc.DataEssenceCoding).EncodeString(str_buf, 40) << std::endl;
+  strm << "      AtmosVersion: " << (unsigned) ADesc.AtmosVersion << std::endl;
+  strm << "   MaxChannelCount: " << (unsigned) ADesc.MaxChannelCount << std::endl;
+  strm << "    MaxObjectCount: " << (unsigned) ADesc.MaxObjectCount << std::endl;
+  strm << "           AtmosID: " << UUID(ADesc.AtmosID).EncodeString(str_buf, 40) << std::endl;
+  strm << "        FirstFrame: " << (unsigned) ADesc.FirstFrame << std::endl;
+  return strm;
+}
+
+//
+void
+ASDCP::ATMOS::AtmosDescriptorDump(const AtmosDescriptor& ADesc, FILE* stream)
+{
+  char str_buf[40];
+  char atmosID_buf[40];
+  if ( stream == 0 )
+    stream = stderr;
+
+  fprintf(stream, "\
+          EditRate: %d/%d\n\
+   ContainerDuration: %u\n\
+   DataEssenceCoding: %s\n\
+        AtmosVersion: %u\n\
+     MaxChannelCount: %u\n\
+      MaxObjectCount: %u\n\
+             AtmosID: %s\n\
+           FirsFrame: %u\n",
+          ADesc.EditRate.Numerator, ADesc.EditRate.Denominator,
+          ADesc.ContainerDuration,
+          UL(ADesc.DataEssenceCoding).EncodeString(str_buf, 40),
+          ADesc.AtmosVersion,
+          ADesc.MaxChannelCount,
+          ADesc.MaxObjectCount,
+          UUID(ADesc.AtmosID).EncodeString(atmosID_buf, 40),
+          ADesc.FirstFrame);
+}
+
+//
+bool
+ASDCP::ATMOS::IsDolbyAtmos(const char* filename)
+{
+    // TODO
+    // For now use an atmos extension
+    bool result = (0 == (std::string("atmos").compare(Kumu::PathGetExtension(std::string(filename)))));
+    return result;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+
+class ASDCP::ATMOS::MXFReader::h__Reader : public ASDCP::DCData::h__Reader
+{
+  MXF::DolbyAtmosSubDescriptor* m_EssenceSubDescriptor;
+
+  ASDCP_NO_COPY_CONSTRUCT(h__Reader);
+  h__Reader();
+
+ public:
+  AtmosDescriptor m_ADesc;
+
+  h__Reader(const Dictionary& d) : DCData::h__Reader(d),  m_EssenceSubDescriptor(NULL),
+                                   m_ADesc() {}
+  ~h__Reader() {}
+  Result_t    OpenRead(const char*);
+  Result_t    MD_to_Atmos_ADesc(ATMOS::AtmosDescriptor& ADesc);
+};
+
+ASDCP::Result_t
+ASDCP::ATMOS::MXFReader::h__Reader::MD_to_Atmos_ADesc(ATMOS::AtmosDescriptor& ADesc)
+{
+  ASDCP_TEST_NULL(m_EssenceSubDescriptor);
+  Result_t result = MD_to_DCData_DDesc(ADesc);
+  if( ASDCP_SUCCESS(result) )
+  {
+    MXF::DolbyAtmosSubDescriptor* ADescObj = m_EssenceSubDescriptor;
+    ADesc.MaxChannelCount = ADescObj->MaxChannelCount;
+    ADesc.MaxObjectCount = ADescObj->MaxObjectCount;
+    ::memcpy(ADesc.AtmosID, ADescObj->AtmosID.Value(), UUIDlen);
+    ADesc.AtmosVersion = ADescObj->AtmosVersion;
+    ADesc.FirstFrame = ADescObj->FirstFrame;
+  }
+  return result;
+}
+
+//
+//
+ASDCP::Result_t
+ASDCP::ATMOS::MXFReader::h__Reader::OpenRead(const char* filename)
+{
+  Result_t result = DCData::h__Reader::OpenRead(filename);
+
+  if( ASDCP_SUCCESS(result) )
+  {
+
+    if (NULL == m_EssenceSubDescriptor)
+    {
+      InterchangeObject* iObj = NULL;
+      result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(DolbyAtmosSubDescriptor), &iObj);
+      m_EssenceSubDescriptor = static_cast<MXF::DolbyAtmosSubDescriptor*>(iObj);
+    }
+
+    if ( ASDCP_SUCCESS(result) )
+    {
+      result = MD_to_Atmos_ADesc(m_ADesc);
+    }
+  }
+
+  return result;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::ATMOS::MXFReader::MXFReader()
+{
+  m_Reader = new h__Reader(DefaultSMPTEDict());
+}
+
+
+ASDCP::ATMOS::MXFReader::~MXFReader()
+{
+  if ( m_Reader && m_Reader->m_File.IsOpen() )
+    m_Reader->Close();
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper.  Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::ATMOS::MXFReader::OPAtomHeader()
+{
+  if ( m_Reader.empty() )
+  {
+    assert(g_OPAtomHeader);
+    return *g_OPAtomHeader;
+  }
+
+  return m_Reader->m_HeaderPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper.  Caveat emptor!
+//
+ASDCP::MXF::OPAtomIndexFooter&
+ASDCP::ATMOS::MXFReader::OPAtomIndexFooter()
+{
+  if ( m_Reader.empty() )
+  {
+    assert(g_OPAtomIndexFooter);
+    return *g_OPAtomIndexFooter;
+  }
+
+  return m_Reader->m_FooterPart;
+}
+
+// Open the file for reading. The file must exist. Returns error if the
+// operation cannot be completed.
+ASDCP::Result_t
+ASDCP::ATMOS::MXFReader::OpenRead(const char* filename) const
+{
+  return m_Reader->OpenRead(filename);
+}
+
+//
+ASDCP::Result_t
+ASDCP::ATMOS::MXFReader::ReadFrame(ui32_t FrameNum, DCData::FrameBuffer& FrameBuf,
+                                    AESDecContext* Ctx, HMACContext* HMAC) const
+{
+  if ( m_Reader && m_Reader->m_File.IsOpen() )
+    return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
+
+  return RESULT_INIT;
+}
+
+ASDCP::Result_t
+ASDCP::ATMOS::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
+{
+    return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
+}
+
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::ATMOS::MXFReader::FillAtmosDescriptor(AtmosDescriptor& ADesc) const
+{
+  if ( m_Reader && m_Reader->m_File.IsOpen() )
+  {
+    ADesc = m_Reader->m_ADesc;
+    return RESULT_OK;
+  }
+
+  return RESULT_INIT;
+}
+
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::ATMOS::MXFReader::FillWriterInfo(WriterInfo& Info) const
+{
+  if ( m_Reader && m_Reader->m_File.IsOpen() )
+  {
+    Info = m_Reader->m_Info;
+    return RESULT_OK;
+  }
+
+  return RESULT_INIT;
+}
+
+//
+void
+ASDCP::ATMOS::MXFReader::DumpHeaderMetadata(FILE* stream) const
+{
+  if ( m_Reader->m_File.IsOpen() )
+    m_Reader->m_HeaderPart.Dump(stream);
+}
+
+//
+void
+ASDCP::ATMOS::MXFReader::DumpIndex(FILE* stream) const
+{
+  if ( m_Reader->m_File.IsOpen() )
+    m_Reader->m_FooterPart.Dump(stream);
+}
+
+//
+ASDCP::Result_t
+ASDCP::ATMOS::MXFReader::Close() const
+{
+  if ( m_Reader && m_Reader->m_File.IsOpen() )
+    {
+      m_Reader->Close();
+      return RESULT_OK;
+    }
+
+  return RESULT_INIT;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+//
+class ASDCP::ATMOS::MXFWriter::h__Writer : public DCData::h__Writer
+{
+  MXF::DolbyAtmosSubDescriptor* m_EssenceSubDescriptor;
+
+  ASDCP_NO_COPY_CONSTRUCT(h__Writer);
+  h__Writer();
+
+ public:
+  AtmosDescriptor m_ADesc;
+
+  h__Writer(const Dictionary& d) : DCData::h__Writer(d),
+      m_EssenceSubDescriptor(NULL), m_ADesc() {}
+
+  ~h__Writer(){}
+
+  Result_t OpenWrite(const char*, ui32_t HeaderSize, const AtmosDescriptor& ADesc);
+  Result_t Atmos_ADesc_to_MD(const AtmosDescriptor& ADesc);
+};
+
+//
+ASDCP::Result_t
+ASDCP::ATMOS::MXFWriter::h__Writer::Atmos_ADesc_to_MD(const AtmosDescriptor& ADesc)
+{
+  ASDCP_TEST_NULL(m_EssenceDescriptor);
+  ASDCP_TEST_NULL(m_EssenceSubDescriptor);
+  MXF::DolbyAtmosSubDescriptor * ADescObj = m_EssenceSubDescriptor;
+  ADescObj->MaxChannelCount = ADesc.MaxChannelCount;
+  ADescObj->MaxObjectCount = ADesc.MaxObjectCount;
+  ADescObj->AtmosID.Set(ADesc.AtmosID);
+  ADescObj->AtmosVersion = ADesc.AtmosVersion;
+  ADescObj->FirstFrame = ADesc.FirstFrame;
+  return RESULT_OK;
+}
+
+//
+ASDCP::Result_t
+ASDCP::ATMOS::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize, const AtmosDescriptor& ADesc)
+{
+
+  m_EssenceSubDescriptor = new DolbyAtmosSubDescriptor(m_Dict);
+  DCData::SubDescriptorList_t subDescriptors;
+  subDescriptors.push_back(m_EssenceSubDescriptor);
+  Result_t result = DCData::h__Writer::OpenWrite(filename, HeaderSize, subDescriptors);
+  if ( ASDCP_FAILURE(result) )
+    delete m_EssenceSubDescriptor;
+
+  if ( ASDCP_SUCCESS(result) )
+  {
+      m_ADesc = ADesc;
+      memcpy(m_ADesc.DataEssenceCoding, ATMOS_ESSENCE_CODING, SMPTE_UL_LENGTH);
+      result = Atmos_ADesc_to_MD(m_ADesc);
+  }
+
+  return result;
+}
+
+
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::ATMOS::MXFWriter::MXFWriter()
+{
+}
+
+ASDCP::ATMOS::MXFWriter::~MXFWriter()
+{
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper.  Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::ATMOS::MXFWriter::OPAtomHeader()
+{
+  if ( m_Writer.empty() )
+  {
+    assert(g_OPAtomHeader);
+    return *g_OPAtomHeader;
+    }
+
+  return m_Writer->m_HeaderPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper.  Caveat emptor!
+//
+ASDCP::MXF::OPAtomIndexFooter&
+ASDCP::ATMOS::MXFWriter::OPAtomIndexFooter()
+{
+  if ( m_Writer.empty() )
+  {
+    assert(g_OPAtomIndexFooter);
+    return *g_OPAtomIndexFooter;
+  }
+
+  return m_Writer->m_FooterPart;
+}
+
+// Open the file for writing. The file must not exist. Returns error if
+// the operation cannot be completed.
+ASDCP::Result_t
+ASDCP::ATMOS::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
+                                      const AtmosDescriptor& ADesc, ui32_t HeaderSize)
+{
+  if ( Info.LabelSetType != LS_MXF_SMPTE )
+  {
+    DefaultLogSink().Error("Atmos support requires LS_MXF_SMPTE\n");
+    return RESULT_FORMAT;
+  }
+
+  m_Writer = new h__Writer(DefaultSMPTEDict());
+  m_Writer->m_Info = Info;
+
+  Result_t result = m_Writer->OpenWrite(filename, HeaderSize, ADesc);
+
+  if ( ASDCP_SUCCESS(result) )
+      result = m_Writer->SetSourceStream(ADesc, ATMOS_ESSENCE_CODING, ATMOS_PACKAGE_LABEL,
+                                         ATMOS_DEF_LABEL);
+
+  if ( ASDCP_FAILURE(result) )
+    m_Writer.release();
+
+  return result;
+}
+
+// Writes a frame of essence to the MXF file. If the optional AESEncContext
+// argument is present, the essence is encrypted prior to writing.
+// Fails if the file is not open, is finalized, or an operating system
+// error occurs.
+ASDCP::Result_t
+ASDCP::ATMOS::MXFWriter::WriteFrame(const DCData::FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
+{
+  if ( m_Writer.empty() )
+    return RESULT_INIT;
+
+  return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
+}
+
+// Closes the MXF file, writing the index and other closing information.
+ASDCP::Result_t
+ASDCP::ATMOS::MXFWriter::Finalize()
+{
+  if ( m_Writer.empty() )
+    return RESULT_INIT;
+
+  return m_Writer->Finalize();
+}
+
+
+//
+// end AS_DCP_ATMOS.cpp
+//
+
+
diff --git a/src/AS_DCP_DCData.cpp b/src/AS_DCP_DCData.cpp
new file mode 100644 (file)
index 0000000..53e4497
--- /dev/null
@@ -0,0 +1,554 @@
+/*
+Copyright (c) 2004-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    AS_DCP_DCData.cpp
+    \version $Id$
+    \brief   AS-DCP library, Dcinema generic data essence reader and writer implementation
+*/
+
+#include <iostream>
+
+#include "AS_DCP.h"
+#include "AS_DCP_DCData_internal.h"
+#include "AS_DCP_internal.h"
+
+namespace ASDCP
+{
+namespace DCData
+{
+  static std::string DC_DATA_PACKAGE_LABEL = "File Package: SMPTE 382M frame wrapping of D-Cinema Generic data";
+  static std::string DC_DATA_DEF_LABEL = "D-Cinema Generic Data Track";
+} // namespace DCData
+} // namespace ASDCP
+
+//
+std::ostream&
+ASDCP::DCData::operator << (std::ostream& strm, const DCDataDescriptor& DDesc)
+{
+  char str_buf[40];
+  strm << "          EditRate: " << DDesc.EditRate.Numerator << "/" << DDesc.EditRate.Denominator << std::endl;
+  strm << " ContainerDuration: " << (unsigned) DDesc.ContainerDuration << std::endl;
+  strm << " DataEssenceCoding: " << UL(DDesc.DataEssenceCoding).EncodeString(str_buf, 40) << std::endl;
+  return strm;
+}
+
+//
+void
+ASDCP::DCData::DCDataDescriptorDump(const DCDataDescriptor& DDesc, FILE* stream)
+{
+  char str_buf[40];
+  if ( stream == 0 )
+    stream = stderr;
+
+  fprintf(stream, "\
+            EditRate: %d/%d\n\
+   ContainerDuration: %u\n\
+   DataEssenceCoding: %s\n",
+          DDesc.EditRate.Numerator, DDesc.EditRate.Denominator,
+          DDesc.ContainerDuration,
+          UL(DDesc.DataEssenceCoding).EncodeString(str_buf, 40));
+}
+
+
+//------------------------------------------------------------------------------------------
+
+
+ASDCP::Result_t
+ASDCP::DCData::h__Reader::MD_to_DCData_DDesc(DCData::DCDataDescriptor& DDesc)
+{
+  ASDCP_TEST_NULL(m_EssenceDescriptor);
+  MXF::DCDataDescriptor* DDescObj = m_EssenceDescriptor;
+  DDesc.EditRate = DDescObj->SampleRate;
+  assert(DDescObj->ContainerDuration <= 0xFFFFFFFFL);
+  DDesc.ContainerDuration = static_cast<ui32_t>(DDescObj->ContainerDuration);
+  memcpy(DDesc.DataEssenceCoding, DDescObj->DataEssenceCoding.Value(), SMPTE_UL_LENGTH);
+  return RESULT_OK;
+}
+
+//
+//
+ASDCP::Result_t
+ASDCP::DCData::h__Reader::OpenRead(const char* filename)
+{
+  Result_t result = OpenMXFRead(filename);
+
+  if( ASDCP_SUCCESS(result) )
+  {
+    if (NULL == m_EssenceDescriptor)
+    {
+      InterchangeObject* iObj = NULL;
+      result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(DCDataDescriptor), &iObj);
+      m_EssenceDescriptor = static_cast<MXF::DCDataDescriptor*>(iObj);
+    }
+
+    if ( ASDCP_SUCCESS(result) )
+    {
+      result = MD_to_DCData_DDesc(m_DDesc);
+    }
+  }
+
+  // check for sample/frame rate sanity
+  if ( ASDCP_SUCCESS(result)
+                && m_DDesc.EditRate != EditRate_24
+                && m_DDesc.EditRate != EditRate_25
+                && m_DDesc.EditRate != EditRate_30
+                && m_DDesc.EditRate != EditRate_48
+                && m_DDesc.EditRate != EditRate_50
+                && m_DDesc.EditRate != EditRate_60
+                && m_DDesc.EditRate != EditRate_96
+                && m_DDesc.EditRate != EditRate_100
+       && m_DDesc.EditRate != EditRate_120 )
+  {
+    DefaultLogSink().Error("DC Data file EditRate is not a supported value: %d/%d\n", // lu
+                           m_DDesc.EditRate.Numerator, m_DDesc.EditRate.Denominator);
+
+    return RESULT_FORMAT;
+  }
+
+  if( ASDCP_SUCCESS(result) )
+    result = InitMXFIndex();
+
+  if( ASDCP_SUCCESS(result) )
+    result = InitInfo();
+
+  return result;
+}
+
+//
+//
+ASDCP::Result_t
+ASDCP::DCData::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
+                     AESDecContext* Ctx, HMACContext* HMAC)
+{
+  if ( ! m_File.IsOpen() )
+    return RESULT_INIT;
+
+  assert(m_Dict);
+  return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_DCDataEssence), Ctx, HMAC);
+}
+
+
+//
+//------------------------------------------------------------------------------------------
+
+class ASDCP::DCData::MXFReader::h__Reader : public DCData::h__Reader
+{
+  ASDCP_NO_COPY_CONSTRUCT(h__Reader);
+  h__Reader();
+
+  public:
+    h__Reader(const Dictionary& d) : DCData::h__Reader(d) {}
+};
+
+
+//------------------------------------------------------------------------------------------
+
+
+//
+void
+ASDCP::DCData::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
+{
+  if ( stream == 0 )
+    stream = stderr;
+
+  fprintf(stream, "Frame: %06u, %7u bytes\n", m_FrameNumber, m_Size);
+
+  if ( dump_len > 0 )
+    Kumu::hexdump(m_Data, dump_len, stream);
+}
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::DCData::MXFReader::MXFReader()
+{
+  m_Reader = new h__Reader(DefaultSMPTEDict());
+}
+
+
+ASDCP::DCData::MXFReader::~MXFReader()
+{
+  if ( m_Reader && m_Reader->m_File.IsOpen() )
+    m_Reader->Close();
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper.  Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::DCData::MXFReader::OPAtomHeader()
+{
+  if ( m_Reader.empty() )
+    {
+      assert(g_OPAtomHeader);
+      return *g_OPAtomHeader;
+    }
+
+  return m_Reader->m_HeaderPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper.  Caveat emptor!
+//
+ASDCP::MXF::OPAtomIndexFooter&
+ASDCP::DCData::MXFReader::OPAtomIndexFooter()
+{
+  if ( m_Reader.empty() )
+    {
+      assert(g_OPAtomIndexFooter);
+      return *g_OPAtomIndexFooter;
+    }
+
+  return m_Reader->m_FooterPart;
+}
+
+// Open the file for reading. The file must exist. Returns error if the
+// operation cannot be completed.
+ASDCP::Result_t
+ASDCP::DCData::MXFReader::OpenRead(const char* filename) const
+{
+  return m_Reader->OpenRead(filename);
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
+                                    AESDecContext* Ctx, HMACContext* HMAC) const
+{
+  if ( m_Reader && m_Reader->m_File.IsOpen() )
+    return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
+
+  return RESULT_INIT;
+}
+
+ASDCP::Result_t
+ASDCP::DCData::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
+{
+    return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
+}
+
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::DCData::MXFReader::FillDCDataDescriptor(DCDataDescriptor& DDesc) const
+{
+  if ( m_Reader && m_Reader->m_File.IsOpen() )
+    {
+      DDesc = m_Reader->m_DDesc;
+      return RESULT_OK;
+    }
+
+  return RESULT_INIT;
+}
+
+
+// Fill the struct with the values from the file's header.
+// Returns RESULT_INIT if the file is not open.
+ASDCP::Result_t
+ASDCP::DCData::MXFReader::FillWriterInfo(WriterInfo& Info) const
+{
+  if ( m_Reader && m_Reader->m_File.IsOpen() )
+    {
+      Info = m_Reader->m_Info;
+      return RESULT_OK;
+    }
+
+  return RESULT_INIT;
+}
+
+//
+void
+ASDCP::DCData::MXFReader::DumpHeaderMetadata(FILE* stream) const
+{
+  if ( m_Reader->m_File.IsOpen() )
+    m_Reader->m_HeaderPart.Dump(stream);
+}
+
+
+//
+void
+ASDCP::DCData::MXFReader::DumpIndex(FILE* stream) const
+{
+  if ( m_Reader->m_File.IsOpen() )
+    m_Reader->m_FooterPart.Dump(stream);
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::MXFReader::Close() const
+{
+  if ( m_Reader && m_Reader->m_File.IsOpen() )
+    {
+      m_Reader->Close();
+      return RESULT_OK;
+    }
+
+  return RESULT_INIT;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+
+//
+ASDCP::Result_t
+ASDCP::DCData::h__Writer::DCData_DDesc_to_MD(DCData::DCDataDescriptor& DDesc)
+{
+  ASDCP_TEST_NULL(m_EssenceDescriptor);
+  MXF::DCDataDescriptor* DDescObj = static_cast<MXF::DCDataDescriptor *>(m_EssenceDescriptor);
+
+  DDescObj->SampleRate = DDesc.EditRate;
+  DDescObj->ContainerDuration = DDesc.ContainerDuration;
+  DDescObj->DataEssenceCoding.Set(DDesc.DataEssenceCoding);
+
+  return RESULT_OK;
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::h__Writer::OpenWrite(char const* filename, ui32_t HeaderSize,
+                                    const SubDescriptorList_t& subDescriptors)
+{
+  if ( ! m_State.Test_BEGIN() )
+    return RESULT_STATE;
+
+  Result_t result = m_File.OpenWrite(filename);
+
+  if ( ASDCP_SUCCESS(result) )
+    {
+      m_HeaderSize = HeaderSize;
+      m_EssenceDescriptor = new MXF::DCDataDescriptor(m_Dict);
+      SubDescriptorList_t::const_iterator sDObj;
+      SubDescriptorList_t::const_iterator lastDescriptor = subDescriptors.end();
+      for (sDObj = subDescriptors.begin(); sDObj != lastDescriptor; ++sDObj)
+      {
+          m_EssenceSubDescriptorList.push_back(*sDObj);
+          GenRandomValue((*sDObj)->InstanceUID);
+          m_EssenceDescriptor->SubDescriptors.push_back((*sDObj)->InstanceUID);
+      }
+      result = m_State.Goto_INIT();
+    }
+
+  return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::h__Writer::SetSourceStream(DCDataDescriptor const& DDesc,
+                                          const byte_t * essenceCoding,
+                                          const std::string& packageLabel,
+                                          const std::string& defLabel)
+{
+  if ( ! m_State.Test_INIT() )
+    return RESULT_STATE;
+
+  if ( DDesc.EditRate != EditRate_24
+       && DDesc.EditRate != EditRate_25
+       && DDesc.EditRate != EditRate_30
+       && DDesc.EditRate != EditRate_48
+       && DDesc.EditRate != EditRate_50
+       && DDesc.EditRate != EditRate_60
+       && DDesc.EditRate != EditRate_96
+       && DDesc.EditRate != EditRate_100
+       && DDesc.EditRate != EditRate_120 )
+  {
+    DefaultLogSink().Error("DCDataDescriptor.EditRate is not a supported value: %d/%d\n",
+                           DDesc.EditRate.Numerator, DDesc.EditRate.Denominator);
+    return RESULT_RAW_FORMAT;
+  }
+
+  assert(m_Dict);
+  m_DDesc = DDesc;
+  if (NULL != essenceCoding)
+      memcpy(m_DDesc.DataEssenceCoding, essenceCoding, SMPTE_UL_LENGTH);
+  Result_t result = DCData_DDesc_to_MD(m_DDesc);
+
+  if ( ASDCP_SUCCESS(result) )
+  {
+    memcpy(m_EssenceUL, m_Dict->ul(MDD_DCDataEssence), SMPTE_UL_LENGTH);
+    m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
+    result = m_State.Goto_READY();
+  }
+
+  if ( ASDCP_SUCCESS(result) )
+  {
+    ui32_t TCFrameRate = m_DDesc.EditRate.Numerator;
+
+    result = WriteMXFHeader(packageLabel, UL(m_Dict->ul(MDD_DCDataWrapping)),
+                            defLabel, UL(m_EssenceUL), UL(m_Dict->ul(MDD_DataDataDef)),
+                            m_DDesc.EditRate, TCFrameRate);
+  }
+
+  return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::h__Writer::WriteFrame(const FrameBuffer& FrameBuf,
+                                                ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
+{
+  Result_t result = RESULT_OK;
+
+  if ( m_State.Test_READY() )
+    result = m_State.Goto_RUNNING(); // first time through
+
+  ui64_t StreamOffset = m_StreamOffset;
+
+  if ( ASDCP_SUCCESS(result) )
+    result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
+
+  if ( ASDCP_SUCCESS(result) )
+  {
+    IndexTableSegment::IndexEntry Entry;
+    Entry.StreamOffset = StreamOffset;
+    m_FooterPart.PushIndexEntry(Entry);
+    m_FramesWritten++;
+  }
+  return result;
+}
+
+// Closes the MXF file, writing the index and other closing information.
+//
+ASDCP::Result_t
+ASDCP::DCData::h__Writer::Finalize()
+{
+  if ( ! m_State.Test_RUNNING() )
+    return RESULT_STATE;
+
+  m_State.Goto_FINAL();
+
+  return WriteMXFFooter();
+}
+
+
+//
+//------------------------------------------------------------------------------------------
+
+
+class ASDCP::DCData::MXFWriter::h__Writer : public DCData::h__Writer
+{
+  ASDCP_NO_COPY_CONSTRUCT(h__Writer);
+  h__Writer();
+
+  public:
+    h__Writer(const Dictionary& d) : DCData::h__Writer(d) {}
+};
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::DCData::MXFWriter::MXFWriter()
+{
+}
+
+ASDCP::DCData::MXFWriter::~MXFWriter()
+{
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper.  Caveat emptor!
+//
+ASDCP::MXF::OPAtomHeader&
+ASDCP::DCData::MXFWriter::OPAtomHeader()
+{
+  if ( m_Writer.empty() )
+    {
+      assert(g_OPAtomHeader);
+      return *g_OPAtomHeader;
+    }
+
+  return m_Writer->m_HeaderPart;
+}
+
+// Warning: direct manipulation of MXF structures can interfere
+// with the normal operation of the wrapper.  Caveat emptor!
+//
+ASDCP::MXF::OPAtomIndexFooter&
+ASDCP::DCData::MXFWriter::OPAtomIndexFooter()
+{
+  if ( m_Writer.empty() )
+    {
+      assert(g_OPAtomIndexFooter);
+      return *g_OPAtomIndexFooter;
+    }
+
+  return m_Writer->m_FooterPart;
+}
+
+// Open the file for writing. The file must not exist. Returns error if
+// the operation cannot be completed.
+ASDCP::Result_t
+ASDCP::DCData::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
+                                      const DCDataDescriptor& DDesc, ui32_t HeaderSize)
+{
+  if ( Info.LabelSetType != LS_MXF_SMPTE )
+  {
+    DefaultLogSink().Error("DC Data support requires LS_MXF_SMPTE\n");
+    return RESULT_FORMAT;
+  }
+
+  m_Writer = new h__Writer(DefaultSMPTEDict());
+  m_Writer->m_Info = Info;
+
+  Result_t result = m_Writer->OpenWrite(filename, HeaderSize, SubDescriptorList_t());
+
+  if ( ASDCP_SUCCESS(result) )
+      result = m_Writer->SetSourceStream(DDesc, NULL, DC_DATA_PACKAGE_LABEL, DC_DATA_DEF_LABEL);
+
+  if ( ASDCP_FAILURE(result) )
+    m_Writer.release();
+
+  return result;
+}
+
+// Writes a frame of essence to the MXF file. If the optional AESEncContext
+// argument is present, the essence is encrypted prior to writing.
+// Fails if the file is not open, is finalized, or an operating system
+// error occurs.
+ASDCP::Result_t
+ASDCP::DCData::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
+{
+  if ( m_Writer.empty() )
+    return RESULT_INIT;
+
+  return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
+}
+
+// Closes the MXF file, writing the index and other closing information.
+ASDCP::Result_t
+ASDCP::DCData::MXFWriter::Finalize()
+{
+  if ( m_Writer.empty() )
+    return RESULT_INIT;
+
+  return m_Writer->Finalize();
+}
+
+
+//
+// end AS_DCP_DCData.cpp
+//
diff --git a/src/AS_DCP_DCData_internal.h b/src/AS_DCP_DCData_internal.h
new file mode 100644 (file)
index 0000000..65d6c41
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+Copyright (c) 2004-2012, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    AS_DCP_DCData_internal.h
+    \version $Id$
+    \brief   AS-DCP library, non-public common DCData reader and writer implementation
+*/
+
+#ifndef _AS_DCP_DCDATA_INTERNAL_H_
+#define _AS_DCP_DCDATA_INTERNAL_H_
+
+#include <list>
+
+#include "AS_DCP_internal.h"
+
+namespace ASDCP
+{
+
+namespace MXF
+{
+  class InterchangeObject;
+}
+
+namespace DCData
+{
+  typedef std::list<MXF::InterchangeObject*> SubDescriptorList_t;
+
+  class h__Reader : public ASDCP::h__ASDCPReader
+  {
+    MXF::DCDataDescriptor* m_EssenceDescriptor;
+    ASDCP_NO_COPY_CONSTRUCT(h__Reader);
+    h__Reader();
+
+   public:
+    DCDataDescriptor m_DDesc;
+
+    h__Reader(const Dictionary& d) : ASDCP::h__ASDCPReader(d), m_EssenceDescriptor(0),
+                                     m_DDesc() {}
+    ~h__Reader() {}
+    Result_t    OpenRead(const char*);
+    Result_t    ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
+    Result_t    MD_to_DCData_DDesc(DCData::DCDataDescriptor& DDesc);
+  };
+
+  class h__Writer : public ASDCP::h__Writer
+  {
+    ASDCP_NO_COPY_CONSTRUCT(h__Writer);
+    h__Writer();
+
+   public:
+    DCDataDescriptor m_DDesc;
+    byte_t           m_EssenceUL[SMPTE_UL_LENGTH];
+
+    h__Writer(const Dictionary& d) : ASDCP::h__Writer(d) {
+      memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
+    }
+
+    ~h__Writer(){}
+
+    Result_t OpenWrite(const char*, ui32_t HeaderSize, const SubDescriptorList_t& subDescriptors);
+    Result_t SetSourceStream(const DCDataDescriptor&, const byte_t*, const std::string&, const std::string&);
+    Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
+    Result_t Finalize();
+    Result_t DCData_DDesc_to_MD(DCData::DCDataDescriptor& DDesc);
+};
+
+
+} // namespace DCData
+} // namespace ASDCP
+
+#endif // _AS_DCP_DCDATA_INTERNAL_H_
index 33d5b9355618acd5b25cc8a6335588fcc6f9a7ef..300a6a284118e673696e3f1493019ed41abae8f6 100755 (executable)
@@ -280,6 +280,22 @@ lh__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc)
   return RESULT_OK;
 }
 
+// Compares the actual floating point value of the rates.
+// This allows, for example, {300000,1001} and {2997,100) to be considered equivalent.
+// to 29.97.
+bool 
+epsilon_compare(const ASDCP::Rational& left, const ASDCP::Rational& right, double epsilon = 0.001)
+{
+  bool result = false;
+  double difference = left.Quotient() - right.Quotient();
+
+  if (fabs(difference) < epsilon)
+    result = true;
+
+  return result;
+}
+// end DOLBY
+
 //
 //
 ASDCP::Result_t
@@ -459,6 +475,8 @@ ASDCP::JP2K::MXFReader::MXFReader()
 
 ASDCP::JP2K::MXFReader::~MXFReader()
 {
+  if ( m_Reader && m_Reader->m_File.IsOpen() )
+    m_Reader->Close();
 }
 
 // Warning: direct manipulation of MXF structures can interfere
@@ -510,6 +528,12 @@ ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
   return RESULT_INIT;
 }
 
+ASDCP::Result_t
+ASDCP::JP2K::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
+{
+    return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
+}
+
 
 // Fill the struct with the values from the file's header.
 // Returns RESULT_INIT if the file is not open.
@@ -663,6 +687,8 @@ ASDCP::JP2K::MXFSReader::MXFSReader()
 
 ASDCP::JP2K::MXFSReader::~MXFSReader()
 {
+  if ( m_Reader && m_Reader->m_File.IsOpen() )
+    m_Reader->Close();
 }
 
 // Warning: direct manipulation of MXF structures can interfere
@@ -731,6 +757,12 @@ ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, F
   return RESULT_INIT;
 }
 
+ASDCP::Result_t
+ASDCP::JP2K::MXFSReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
+{
+    return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
+}
+
 // Fill the struct with the values from the file's header.
 // Returns RESULT_INIT if the file is not open.
 ASDCP::Result_t
index 208163066a0f002aaa1ff4b758b53115c47009fe..61ab7b7d83cd10239a796957f28a4c71483f4325 100755 (executable)
@@ -333,6 +333,8 @@ ASDCP::MPEG2::MXFReader::MXFReader()
 
 ASDCP::MPEG2::MXFReader::~MXFReader()
 {
+  if ( m_Reader && m_Reader->m_File.IsOpen() )
+    m_Reader->Close();
 }
 
 // Warning: direct manipulation of MXF structures can interfere
@@ -385,6 +387,13 @@ ASDCP::MPEG2::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
 }
 
 
+//
+ASDCP::Result_t
+ASDCP::MPEG2::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
+{
+    return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
+}
+
 //
 ASDCP::Result_t
 ASDCP::MPEG2::MXFReader::ReadFrameGOPStart(ui32_t FrameNum, FrameBuffer& FrameBuf,
index 96fc95930e2ec3f48db0a81e1da454894306a8fc..4d039f00f83a0148e1c51fe6518749fae21b7e36 100755 (executable)
@@ -191,6 +191,13 @@ ASDCP::EssenceType(const char* filename, EssenceType_t& type)
        type = ESS_MPEG2_VES;
       else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(TimedTextDescriptor))) )
        type = ESS_TIMED_TEXT;
+      else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(DCDataDescriptor))) )
+      {
+        if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(DolbyAtmosSubDescriptor))) )
+          type = ESS_DCDATA_DOLBY_ATMOS;
+        else
+          type = ESS_DCDATA_UNKNOWN;
+      }
     }
 
   return result;
@@ -205,6 +212,7 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type)
   ASDCP::FrameBuffer FB;
   Kumu::FileReader Reader;
   ASDCP::Wav::SimpleWaveHeader WavHeader;
+  ASDCP::RF64::SimpleRF64Header RF64Header;
   ASDCP::AIFF::SimpleAIFFHeader AIFFHeader;
   Kumu::XMLElement TmpElement("Tmp");
 
@@ -248,6 +256,16 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type)
                  return RESULT_FORMAT;
                }
            }
+         else if ( ASDCP_SUCCESS(RF64Header.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
+           {
+             switch ( RF64Header.samplespersec )
+               {
+               case 48000: type = ESS_PCM_24b_48k; break;
+               case 96000: type = ESS_PCM_24b_96k; break;
+               default:
+                 return RESULT_FORMAT;
+               }
+           }
          else if ( ASDCP_SUCCESS(AIFFHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
            {
              type = ESS_PCM_24b_48k;
@@ -256,6 +274,10 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type)
            {
              type = ESS_TIMED_TEXT;
            }
+      else if ( ASDCP::ATMOS::IsDolbyAtmos(filename) )
+      {
+        type = ESS_DCDATA_DOLBY_ATMOS;
+      }
        }
     }
   else if ( Kumu::PathIsDirectory(filename) )
@@ -298,6 +320,21 @@ ASDCP::RawEssenceType(const char* filename, EssenceType_t& type)
                          return RESULT_FORMAT;
                        }
                    }
+             else if ( ASDCP_SUCCESS(RF64Header.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
+            {
+              switch ( RF64Header.samplespersec )
+            {
+            case 48000: type = ESS_PCM_24b_48k; break;
+            case 96000: type = ESS_PCM_24b_96k; break;
+            default:
+              return RESULT_FORMAT;
+            }
+               }
+          else if ( ASDCP::ATMOS::IsDolbyAtmos(Str.c_str()) )
+          {
+            type = ESS_DCDATA_DOLBY_ATMOS;
+          }
+
                }
 
              break;
index 606a6f5d4356fe7a04a90a3762680744c54b7849..e52b27f3b1106353206454c55c617897d430698b 100755 (executable)
@@ -134,6 +134,35 @@ ASDCP::PCM::operator << (std::ostream& strm, const AudioDescriptor& ADesc)
   strm << "            AvgBps: " << (unsigned) ADesc.AvgBps << std::endl;
   strm << "     LinkedTrackID: " << (unsigned) ADesc.LinkedTrackID << std::endl;
   strm << " ContainerDuration: " << (unsigned) ADesc.ContainerDuration << std::endl;
+  strm << "     ChannelFormat: ";
+  switch (ADesc.ChannelFormat)
+  {
+    case CF_NONE:
+    default:
+      strm << "No Channel Format";
+      break;
+
+    case CF_CFG_1:
+      strm << "Config 1 (5.1 with optional HI/VI)";
+      break;
+
+    case CF_CFG_2:
+      strm << "Config 2 (5.1 + center surround with optional HI/VI)";
+      break;
+
+    case CF_CFG_3:
+      strm << "Config 3 (7.1 with optional HI/VI)";
+      break;
+
+    case CF_CFG_4:
+      strm << "Config 4";
+      break;
+
+    case CF_CFG_5:
+      strm << "Config 5 (7.1 DS with optional HI/VI)";
+      break;
+  }
+  strm << std::endl;
 
   return strm;
 }
@@ -154,7 +183,8 @@ ASDCP::PCM::AudioDescriptorDump(const AudioDescriptor& ADesc, FILE* stream)
         BlockAlign: %u\n\
             AvgBps: %u\n\
      LinkedTrackID: %u\n\
- ContainerDuration: %u\n",
+ ContainerDuration: %u\n\
+     ChannelFormat: %u\n",
          ADesc.EditRate.Numerator, ADesc.EditRate.Denominator,
          ADesc.AudioSamplingRate.Numerator, ADesc.AudioSamplingRate.Denominator,
          ADesc.Locked,
@@ -163,7 +193,8 @@ ASDCP::PCM::AudioDescriptorDump(const AudioDescriptor& ADesc, FILE* stream)
          ADesc.BlockAlign,
          ADesc.AvgBps,
          ADesc.LinkedTrackID,
-         ADesc.ContainerDuration
+         ADesc.ContainerDuration,
+          ADesc.ChannelFormat
          );
 }
 
@@ -256,6 +287,7 @@ ASDCP::PCM::MXFReader::h__Reader::OpenRead(const char* filename)
        }
       else
        {
+      DefaultLogSink().Error("PCM EditRate not in expected value range.\n");
          // or we just drop the hammer
          return RESULT_FORMAT;
        }
@@ -370,6 +402,12 @@ ASDCP::PCM::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
 }
 
 
+ASDCP::Result_t
+ASDCP::PCM::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
+{
+    return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
+}
+
 // Fill the struct with the values from the file's header.
 // Returns RESULT_INIT if the file is not open.
 ASDCP::Result_t
index 971fe08bf164f1fa2700f6676af93815438afe66..694676d7327180bc30ea87ecdc3dcce2d513530f 100644 (file)
@@ -92,7 +92,7 @@ ASDCP::TimedText::DescriptorDump(ASDCP::TimedText::TimedTextDescriptor const& TD
   fprintf(stream, "ContainerDuration: %u\n",    TDesc.ContainerDuration);
   fprintf(stream, "          AssetID: %s\n",    TmpID.EncodeHex(buf, 64));
   fprintf(stream, "    NamespaceName: %s\n",    TDesc.NamespaceName.c_str());
-  fprintf(stream, "    ResourceCount: %d\n",   TDesc.ResourceList.size());
+  fprintf(stream, "    ResourceCount: %zu\n",   TDesc.ResourceList.size());
 
   TimedText::ResourceList_t::const_iterator ri;
   for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end(); ri++ )
@@ -567,7 +567,7 @@ ASDCP::TimedText::MXFWriter::h__Writer::SetSourceStream(ASDCP::TimedText::TimedT
     {
       InitHeader();
       AddDMSegment(m_TDesc.EditRate, 24, TIMED_TEXT_DEF_LABEL,
-                  UL(m_Dict->ul(MDD_PictureDataDef)), TIMED_TEXT_PACKAGE_LABEL);
+                  UL(m_Dict->ul(MDD_DataDataDef)), TIMED_TEXT_PACKAGE_LABEL);
 
       AddEssenceDescriptor(UL(m_Dict->ul(MDD_TimedTextWrapping)));
 
index af6b55317be1f58b922ad9a3f960e748674fa481..53101001335238af49abab6d632aee8797103ede 100755 (executable)
@@ -25,7 +25,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 /*! \file    AS_DCP_internal.h
-    \version $Id$       
+    \version $Id$
     \brief   AS-DCP library, non-public common elements
 */
 
@@ -62,7 +62,7 @@ namespace ASDCP
     std::vector<int> result;
     const char* pstr = str;
     const char* r = strchr(pstr, '.');
-    
+
     while ( r != 0 )
       {
        assert(r >= pstr);
@@ -132,7 +132,7 @@ namespace ASDCP
                            const ASDCP::WriterInfo& Info, Kumu::fpos_t& LastPosition, ASDCP::FrameBuffer& CtFrameBuf,
                            ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
                            const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
-  
+
   //
  class KLReader : public ASDCP::KLVPacket
     {
@@ -146,7 +146,7 @@ namespace ASDCP
       inline const byte_t* Key() { return m_KeyBuf; }
       inline const ui64_t  Length() { return m_ValueLength; }
       inline const ui64_t  KLLength() { return m_KLLength; }
-      
+
       Result_t ReadKLFromFile(Kumu::FileReader& Reader);
     };
 
@@ -207,7 +207,7 @@ namespace ASDCP
          if ( KM_SUCCESS(result) )
            {
              Result_t cr_result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CryptographicContext), &Object);
-             
+
              if ( KM_SUCCESS(cr_result) )
                MD_to_CryptoInfo((CryptographicContext*)Object, m_Info, *m_Dict);
            }
@@ -223,7 +223,9 @@ namespace ASDCP
 
          if ( KM_SUCCESS(result) )
            result = m_HeaderPart.InitFromFile(m_File);
-         
+      else
+        DefaultLogSink().Error("ASDCP::h__Reader::OpenMXFRead, OpenRead failed\n");
+
          return result;
        }
 
@@ -266,6 +268,28 @@ namespace ASDCP
                                  FrameNum, SequenceNum, FrameBuf, EssenceUL, Ctx, HMAC);
        }
 
+    // Get the position of a frame from a track file
+    Result_t LocateFrame(const ASDCP::MXF::Partition& CurrentPartition,
+                         ui32_t FrameNum, Kumu::fpos_t& streamOffset,
+                         i8_t& temporalOffset, i8_t& keyFrameOffset)
+    {
+      // look up frame index node
+      IndexTableSegment::IndexEntry TmpEntry;
+
+      if ( KM_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
+      {
+        DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
+        return RESULT_RANGE;
+      }
+
+      // get frame position, temporal offset, and key frame ofset
+      streamOffset = CurrentPartition.BodyOffset + TmpEntry.StreamOffset;
+      temporalOffset = TmpEntry.TemporalOffset;
+      keyFrameOffset = TmpEntry.KeyFrameOffset;
+
+      return RESULT_OK;
+    }
+
        //
        void     Close() {
          m_File.Close();
@@ -291,6 +315,9 @@ namespace ASDCP
       Result_t InitMXFIndex();
       Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
                             const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
+      Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset,
+                           i8_t& temporalOffset, i8_t& keyFrameOffset);
+
     };
 
 
@@ -392,13 +419,13 @@ namespace ASDCP
     {
     public:
       byte_t Data[klv_intpack_size];
-  
+
       IntegrityPack() {
        memset(Data, 0, klv_intpack_size);
       }
 
       ~IntegrityPack() {}
-  
+
       Result_t CalcValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
       Result_t TestValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
     };
diff --git a/src/AtmosSyncChannel_Generator.cpp b/src/AtmosSyncChannel_Generator.cpp
new file mode 100644 (file)
index 0000000..b9b8c44
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    AtmosSyncChannel_Generator.cpp
+    \version $Id$
+    \brief   Dolby Atmos sync channel generator implementation
+*/
+
+#include <AtmosSyncChannel_Generator.h>
+
+#include <AS_DCP.h>
+
+using namespace ASDCP;
+
+//
+ASDCP::PCM::AtmosSyncChannelGenerator::AtmosSyncChannelGenerator(ui16_t bitsPerSample, ui32_t sampleRate,
+                                                                 const ASDCP::Rational& editRate, const byte_t* uuid)
+    : m_syncEncoder(),
+      m_audioTrackUUID(),
+      m_ADesc(),
+      m_syncSignalBuffer(NULL),
+      m_numSamplesPerFrame(0),
+      m_currentFrameNumber(0),
+      m_numBytesPerFrame(0),
+      m_isSyncEncoderInitialized(false)
+{
+
+    m_ADesc.EditRate = editRate;
+    m_ADesc.ChannelCount = 1;
+    m_ADesc.QuantizationBits = bitsPerSample;
+    m_ADesc.AudioSamplingRate = Rational(sampleRate, 1);
+    m_ADesc.BlockAlign = ((bitsPerSample + 7) / 8);
+    m_ADesc.AvgBps = (sampleRate * m_ADesc.BlockAlign);
+
+    memcpy(&m_audioTrackUUID.abyUUIDBytes[0], uuid, UUIDlen);
+    m_numSamplesPerFrame = (editRate.Denominator * sampleRate) / editRate.Numerator;
+    m_numBytesPerFrame = m_numSamplesPerFrame * m_ADesc.BlockAlign;
+
+    if (bitsPerSample == 24)
+    {
+        ui32_t frameRate = editRate.Numerator/editRate.Denominator; // intentionally allowing for imprecise cast to int
+        m_isSyncEncoderInitialized = (SyncEncoderInit(&m_syncEncoder, sampleRate, frameRate, &m_audioTrackUUID) == SYNC_ENCODER_ERROR_NONE);
+        m_syncSignalBuffer = new float[m_numSamplesPerFrame];
+    }
+    else
+    {
+        m_isSyncEncoderInitialized = false;
+    }
+}
+
+ASDCP::PCM::AtmosSyncChannelGenerator::~AtmosSyncChannelGenerator()
+{
+    delete [] m_syncSignalBuffer;
+}
+
+ASDCP::Result_t
+ASDCP::PCM::AtmosSyncChannelGenerator::ReadFrame(FrameBuffer& OutFB)
+{
+    if (OutFB.Capacity() < m_numBytesPerFrame)
+    {
+        return RESULT_SMALLBUF;
+    }
+
+    /**
+     * Update frame number and size.
+     */
+    OutFB.FrameNumber(m_currentFrameNumber);
+    OutFB.Size(m_numBytesPerFrame);
+
+    /**
+     * Get pointer to frame essence.
+     */
+    byte_t* frameEssence = OutFB.Data();
+
+    if (m_isSyncEncoderInitialized)
+    {
+        /**
+         * Generate sync signal frame.
+         */
+        int ret = EncodeSync(&m_syncEncoder, m_numSamplesPerFrame, m_syncSignalBuffer, m_currentFrameNumber);
+        if (ret == SYNC_ENCODER_ERROR_NONE)
+        {
+            for (unsigned int i = 0; i < m_numSamplesPerFrame; ++i)
+            {
+                /**
+                 * Convert each encoded float sample to a signed 24 bit integer and
+                 * copy into the essence buffer.
+                 */
+                i32_t sample = convertSampleFloatToInt24(m_syncSignalBuffer[i]);
+                memcpy(frameEssence, ((byte_t*)(&sample))+1, NUM_BYTES_PER_INT24);
+                frameEssence += NUM_BYTES_PER_INT24;
+            }
+        }
+        else
+        {
+            /**
+             * Encoding error, zero out the frame.
+             */
+            memset(frameEssence, 0, m_numBytesPerFrame);
+        }
+    }
+    else
+    {
+        /**
+         * Sync encoder not initialize, zero out the frame.
+         */
+        memset(frameEssence, 0, m_numBytesPerFrame);
+    }
+    ++m_currentFrameNumber;
+    return RESULT_OK;
+}
+
+ASDCP::Result_t
+ASDCP::PCM::AtmosSyncChannelGenerator::Reset()
+{
+  m_currentFrameNumber = 0;
+  return RESULT_OK;
+}
+
+Result_t
+ASDCP::PCM::AtmosSyncChannelGenerator::FillAudioDescriptor(AudioDescriptor& ADesc) const
+{
+  ADesc = m_ADesc;
+  return RESULT_OK;
+}
+
diff --git a/src/AtmosSyncChannel_Generator.h b/src/AtmosSyncChannel_Generator.h
new file mode 100644 (file)
index 0000000..d7f4219
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    AtmosSyncChannel_Generator.h
+    \version $Id$
+    \brief   Dolby Atmos sync channel generator
+*/
+
+#ifndef _ATMOSSYNCCHANNEL_GENERATOR_H_
+#define _ATMOSSYNCCHANNEL_GENERATOR_H_
+
+#include <AS_DCP.h>
+#include "SyncEncoder.h"
+#include "UUIDInformation.h"
+
+#define INT24_MAX 8388607.0
+#define INT24_MIN -8388608.0
+
+namespace ASDCP
+{
+    namespace ATMOS
+    {
+        static const ui32_t SYNC_CHANNEL = 14;
+    }
+
+    namespace PCM
+    {
+
+        static const ui16_t NUM_BYTES_PER_INT24 = 3;
+
+        class AtmosSyncChannelGenerator
+        {
+            SYNCENCODER  m_syncEncoder;
+            UUIDINFORMATION m_audioTrackUUID;
+            AudioDescriptor m_ADesc;
+            float *m_syncSignalBuffer;
+            ui32_t m_numSamplesPerFrame;
+            ui32_t m_currentFrameNumber;
+            ui32_t m_numBytesPerFrame;
+            bool m_isSyncEncoderInitialized;
+
+            ASDCP_NO_COPY_CONSTRUCT(AtmosSyncChannelGenerator);
+
+        public:
+            /**
+             * Constructor
+             *
+             * @param bitsPerSample the number of bits in each sample of pcm data
+             * @param sampleRate the sampling rate
+             * @param editRate the edit rate of the associated picture track.
+             * @param atmosUUID the UUID of the associated ATMOS track file.
+             *
+             */
+            AtmosSyncChannelGenerator(ui16_t bitsPerSample, ui32_t sampleRate,
+                               const ASDCP::Rational& editRate, const byte_t* uuid);
+            ~AtmosSyncChannelGenerator();
+
+            /**
+             * Set the frame number when seeking
+             * Use override the default starting frame number for a new track or
+             * to set the frame number when doing random access.
+             *
+             * @param frameNumber
+             *
+             */
+            void setFrameNumber(ui32_t frameNumber) { m_currentFrameNumber = frameNumber; };
+
+            /**
+             * Get the number of bytes per frame.
+             *
+             * @return Number of bytes per frame
+             *
+             */
+            ui32_t getBytesPerFrame() { return m_numBytesPerFrame; }
+
+            /**
+             * Generates the next frame of sync data.
+             * Generates the next frame of sync data and places it
+             * the frame buffer. Fails if the buffer is too small.
+             * **Automatically increments the frame number.**
+             *
+             * @param buf the buffer that the generated frame data will be written to.
+             *
+             * @return Kumu::RESULT_OK if the buffer is succesfully filled with sync
+             *  data for the next frame.
+             */
+            Result_t ReadFrame(FrameBuffer& buf);
+
+            /**
+             * Reset the frame count.
+             *
+             * @return Kumu::RESULT_OK
+             */
+            Result_t Reset();
+
+            /**
+             * Fill the AudioDescriptor with the relevant information.
+             *
+             * @return Kumu::RESULT_OK
+             */
+            Result_t FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const;
+
+            /**
+             * Converts a sample float into
+             * 24-bit PCM data.
+             *
+             */
+            static inline i32_t convertSampleFloatToInt24(float sample)
+            {
+                if (sample >= 0.0)
+                {
+                    return (static_cast<i32_t>(sample * INT24_MAX) << 8);
+                }
+                else
+                {
+                    return (static_cast<i32_t>(-sample * INT24_MIN) << 8);
+                }
+            }
+        };
+
+    } // namespace PCM
+} // namespace ASDCP
+
+#endif // _ATMOSSYNCCHANNEL_GENERATOR_H_
+
+//
+// end AtmosSyncChannel_Generator.h
+//
diff --git a/src/AtmosSyncChannel_Mixer.cpp b/src/AtmosSyncChannel_Mixer.cpp
new file mode 100644 (file)
index 0000000..70cfbfd
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    AtmosSyncChannel_Mixer.cpp
+    \version $Id$
+    \brief   Read WAV files(s), multiplex multiple PCM frame buffers including Atmos Sync into one
+*/
+
+#include <AtmosSyncChannel_Mixer.h>
+
+#include <algorithm>
+
+#include <AS_DCP.h>
+#include <KM_log.h>
+#include <PCMDataProviders.h>
+
+using namespace ASDCP;
+using namespace Kumu;
+
+//
+ASDCP::AtmosSyncChannelMixer::AtmosSyncChannelMixer(const byte_t * trackUUID)
+    : m_inputs(), m_outputs(), m_trackUUID(), m_ADesc(), m_ChannelCount(0), m_FramesRead(0)
+{
+  ::memcpy(m_trackUUID, trackUUID, UUIDlen);
+}
+
+ASDCP::AtmosSyncChannelMixer::~AtmosSyncChannelMixer()
+{
+  clear();
+}
+
+void
+ASDCP::AtmosSyncChannelMixer::clear()
+{
+  m_outputs.clear();
+  std::for_each(m_inputs.begin(), m_inputs.end(), delete_input());
+  m_inputs.clear();
+}
+
+//
+Result_t
+ASDCP::AtmosSyncChannelMixer::OpenRead(ui32_t argc, const char** argv, const Rational& PictureRate)
+{
+  ASDCP_TEST_NULL_STR(argv);
+  PathList_t TmpFileList;
+
+  for ( ui32_t i = 0; i < argc; ++i )
+    TmpFileList.push_back(argv[i]);
+
+  return OpenRead(TmpFileList, PictureRate);
+}
+
+//
+Result_t
+ASDCP::AtmosSyncChannelMixer::OpenRead(const Kumu::PathList_t& argv, const Rational& PictureRate)
+{
+  Result_t result = RESULT_OK;
+  PathList_t::iterator fi;
+  Kumu::PathList_t file_list;
+  PCM::AudioDescriptor tmpDesc;
+
+  if ( argv.size() == 1 && PathIsDirectory(argv.front()) )
+  {
+    DirScanner Dir;
+    char name_buf[MaxFilePath];
+    result = Dir.Open(argv.front().c_str());
+
+    if ( KM_SUCCESS(result) )
+      result = Dir.GetNext(name_buf);
+
+    while ( KM_SUCCESS(result) )
+       {
+         if ( name_buf[0] != '.' ) // no hidden files
+      {
+        std::string tmp_path = argv.front() + "/" + name_buf;
+        file_list.push_back(tmp_path);
+      }
+
+         result = Dir.GetNext(name_buf);
+       }
+
+    if ( result == RESULT_ENDOFFILE )
+       {
+         result = RESULT_OK;
+         file_list.sort();
+       }
+  }
+  else
+  {
+    file_list = argv;
+  }
+
+  for ( fi = file_list.begin(); KM_SUCCESS(result) && fi != file_list.end(); ++fi )
+  {
+    result = OpenRead(*fi, PictureRate);
+  }
+
+  if ( ASDCP_SUCCESS(result) && (m_ChannelCount < ATMOS::SYNC_CHANNEL))
+  {
+    // atmos sync channel has not been added
+    result = MixInSilenceChannels();
+    if ( ASDCP_SUCCESS(result) )
+      result = MixInAtmosSyncChannel();
+  }
+
+  if ( ASDCP_SUCCESS(result) )
+  {
+    m_ADesc.ChannelCount = m_ChannelCount;
+    m_ADesc.AvgBps = (ui32_t)(ceil(m_ADesc.AudioSamplingRate.Quotient()) * m_ADesc.BlockAlign);
+  }
+  else
+  {
+    clear();
+  }
+
+  return result;
+}
+
+//
+Result_t
+ASDCP::AtmosSyncChannelMixer::OpenRead(const std::string& file, const Rational& PictureRate)
+{
+  Result_t result = RESULT_OK;
+  PCM::AudioDescriptor tmpDesc;
+  ui32_t numChannels = 0;
+  mem_ptr<WAVDataProvider> I = new WAVDataProvider;
+  result = I->OpenRead(file.c_str(), PictureRate);
+
+  if ( ASDCP_SUCCESS(result))
+  {
+    result = I->FillAudioDescriptor(tmpDesc);
+  }
+
+  if ( ASDCP_SUCCESS(result) )
+  {
+
+    if ( m_ChannelCount == 0 )
+    {
+      m_ADesc = tmpDesc;
+    }
+    else
+    {
+
+      if ( tmpDesc.AudioSamplingRate != m_ADesc.AudioSamplingRate )
+      {
+        DefaultLogSink().Error("AudioSamplingRate mismatch in PCM parser list.");
+        return RESULT_FORMAT;
+      }
+
+      if ( tmpDesc.QuantizationBits  != m_ADesc.QuantizationBits )
+      {
+        DefaultLogSink().Error("QuantizationBits mismatch in PCM parser list.");
+        return RESULT_FORMAT;
+      }
+
+      if ( tmpDesc.ContainerDuration < m_ADesc.ContainerDuration )
+        m_ADesc.ContainerDuration = tmpDesc.ContainerDuration;
+
+      m_ADesc.BlockAlign += tmpDesc.BlockAlign;
+    }
+  }
+
+
+  if ( ASDCP_SUCCESS(result) )
+  {
+    numChannels = tmpDesc.ChannelCount; // default to all channels
+    if ((m_ChannelCount < ATMOS::SYNC_CHANNEL) && (m_ChannelCount + numChannels) > (ATMOS::SYNC_CHANNEL - 1))
+    {
+      // need to insert an atmos channel between the channels of this file.
+      numChannels = ATMOS::SYNC_CHANNEL - m_ChannelCount - 1;
+      m_outputs.push_back(std::make_pair(numChannels, I.get()));
+      m_ChannelCount += numChannels;
+      MixInAtmosSyncChannel();
+      numChannels = tmpDesc.ChannelCount - numChannels;
+    }
+    m_outputs.push_back(std::make_pair(numChannels, I.get()));
+    m_inputs.push_back(I);
+    I.release();
+    m_ChannelCount += numChannels;
+  }
+  return result;
+}
+
+Result_t
+ASDCP::AtmosSyncChannelMixer::MixInSilenceChannels()
+{
+  Result_t result = RESULT_OK;
+  PCM::AudioDescriptor tmpDesc;
+  ui32_t numSilenceChannels = ATMOS::SYNC_CHANNEL - m_ChannelCount - 1;
+  if (numSilenceChannels > 0)
+  {
+    mem_ptr<SilenceDataProvider> I = new SilenceDataProvider(numSilenceChannels,
+                                                             m_ADesc.QuantizationBits,
+                                                             m_ADesc.AudioSamplingRate.Numerator,
+                                                             m_ADesc.EditRate);
+    result = I->FillAudioDescriptor(tmpDesc);
+    if ( ASDCP_SUCCESS(result) )
+    {
+      m_ADesc.BlockAlign += tmpDesc.BlockAlign;
+      m_ChannelCount += tmpDesc.ChannelCount;
+      m_outputs.push_back(std::make_pair(numSilenceChannels, I.get()));
+      m_inputs.push_back(I);
+      I.release();
+      assert(m_ChannelCount == (ATMOS::SYNC_CHANNEL - 1));
+    }
+  }
+  return result;
+}
+
+//
+Result_t
+ASDCP::AtmosSyncChannelMixer::MixInAtmosSyncChannel()
+{
+  Result_t result = RESULT_OK;
+  PCM::AudioDescriptor tmpDesc;
+  mem_ptr<AtmosSyncDataProvider> I = new AtmosSyncDataProvider(m_ADesc.QuantizationBits,
+                                                               m_ADesc.AudioSamplingRate.Numerator,
+                                                               m_ADesc.EditRate, m_trackUUID);
+  result = I->FillAudioDescriptor(tmpDesc);
+  if ( ASDCP_SUCCESS(result) )
+  {
+    m_ADesc.BlockAlign += tmpDesc.BlockAlign;
+    m_ChannelCount += tmpDesc.ChannelCount;
+    m_outputs.push_back(std::make_pair(tmpDesc.ChannelCount, I.get()));
+    m_inputs.push_back(I);
+    I.release();
+    assert(m_ChannelCount == ATMOS::SYNC_CHANNEL);
+  }
+  return result;
+}
+
+//
+Result_t
+ASDCP::AtmosSyncChannelMixer::FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const
+{
+  ADesc = m_ADesc;
+  return RESULT_OK;
+}
+
+//
+Result_t
+ASDCP::AtmosSyncChannelMixer::Reset()
+{
+  Result_t result = RESULT_OK;
+  SourceList::iterator it;
+  SourceList::iterator lastInput = m_inputs.end();
+
+  for ( it = m_inputs.begin(); it != lastInput && ASDCP_SUCCESS(result) ; ++it )
+    result = (*it)->Reset();
+
+  return result;
+}
+
+
+//2
+Result_t
+ASDCP::AtmosSyncChannelMixer::ReadFrame(PCM::FrameBuffer& OutFB)
+{
+
+
+  Result_t result = RESULT_OK;
+  SourceList::iterator iter;
+  SourceList::iterator lastInput = m_inputs.end();
+  ui32_t bufSize = PCM::CalcFrameBufferSize(m_ADesc);
+  assert( bufSize <= OutFB.Capacity());
+
+  for ( iter = m_inputs.begin(); iter != lastInput && ASDCP_SUCCESS(result) ; ++iter )
+    result = (*iter)->ReadFrame();
+
+  if ( ASDCP_SUCCESS(result) )
+  {
+    OutFB.Size(bufSize);
+    byte_t* Out_p = OutFB.Data();
+    byte_t* End_p = Out_p + OutFB.Size();
+    ui32_t bytesWritten = 0;
+    OutputList::iterator iter;
+    OutputList::iterator lastOutput = m_outputs.end();
+
+    while ( Out_p < End_p && ASDCP_SUCCESS(result) )
+       {
+        iter = m_outputs.begin();
+        while ( iter != lastOutput && ASDCP_SUCCESS(result) )
+        {
+            result = ((*iter).second)->PutSample((*iter).first, Out_p, &bytesWritten);
+            Out_p += bytesWritten;
+            ++iter;
+        }
+    }
+
+    if ( ASDCP_SUCCESS(result) )
+    {
+      assert(Out_p == End_p);
+      OutFB.FrameNumber(m_FramesRead++);
+    }
+  }
+
+  return result;
+}
+
+
+//
+// end AtmosSyncChannel_Mixer.cpp
+//
diff --git a/src/AtmosSyncChannel_Mixer.h b/src/AtmosSyncChannel_Mixer.h
new file mode 100644 (file)
index 0000000..c6a27a3
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    AtmosSyncChannel_Mixer.h
+    \version $Id$
+    \brief   Read WAV files(s), multiplex multiple PCM frame buffers including Atmos Sync into one
+*/
+
+#ifndef _ATMOSSYNCCHANNEL_MIXER_H_
+#define _ATMOSSYNCCHANNEL_MIXER_H_
+
+#include <AS_DCP.h>
+#include <KM_error.h>
+#include <PCMDataProviders.h>
+#include <vector>
+
+namespace ASDCP
+{
+
+  //
+  class AtmosSyncChannelMixer
+  {
+    typedef std::pair<ui32_t, PCMDataProviderInterface*> InputBus;
+    typedef std::vector<InputBus> OutputList;
+    typedef std::vector<PCMDataProviderInterface*> SourceList;
+
+    SourceList m_inputs;
+    OutputList m_outputs;
+    byte_t m_trackUUID[ASDCP::UUIDlen];
+
+    Result_t OpenRead(const std::string& file, const Rational& PictureRate);
+    Result_t MixInSilenceChannels();
+    Result_t MixInAtmosSyncChannel();
+    void clear();
+
+    // functor for deleting
+    struct delete_input
+    {
+        void operator()(PCMDataProviderInterface* i)
+        {
+            delete i;
+        }
+    };
+
+    ASDCP_NO_COPY_CONSTRUCT(AtmosSyncChannelMixer);
+
+    protected:
+      PCM::AudioDescriptor m_ADesc;
+      ui32_t m_ChannelCount;
+      ui32_t m_FramesRead;
+
+    public:
+      AtmosSyncChannelMixer(const byte_t * trackUUID);
+      virtual ~AtmosSyncChannelMixer();
+
+      Result_t OpenRead(ui32_t argc, const char** argv, const Rational& PictureRate);
+      Result_t OpenRead(const Kumu::PathList_t& argv, const Rational& PictureRate);
+      Result_t FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const;
+      Result_t Reset();
+      Result_t ReadFrame(PCM::FrameBuffer& OutFB);
+    };
+} // namespace ASDCP
+
+#endif // _ATMOSSYNCCHANNEL_MIXER_H_
+
+//
+// end AtmosSyncChannel_Mixer.h
+//
diff --git a/src/CRC16.c b/src/CRC16.c
new file mode 100644 (file)
index 0000000..3e2f09e
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    CRC16.c
+    \version $Id$
+    \brief   Implementation of a CRC function
+*/
+
+#include "CRC16.h"
+
+static const unsigned short g_aushCRC16tab[256]= {
+       0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
+       0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
+       0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
+       0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
+       0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
+       0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
+       0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
+       0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
+       0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
+       0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
+       0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
+       0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
+       0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
+       0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
+       0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
+       0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
+       0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
+       0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
+       0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
+       0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
+       0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
+       0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
+       0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
+       0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
+       0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
+       0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
+       0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
+       0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
+       0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
+       0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
+       0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
+       0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
+};
+
+unsigned short CRC16(const void *pData, int ilength)
+{
+       int n;
+       unsigned short ushCRC;
+       unsigned char *puchData;
+
+
+       puchData = (unsigned char*)pData;
+
+       ushCRC = 0;
+       for(n = 0; n < ilength; n ++){
+
+               ushCRC = (ushCRC << 8) ^ g_aushCRC16tab[((ushCRC>>8) ^ *puchData) & 0x00FF];
+               puchData ++;
+       }
+
+       return ushCRC;
+}
diff --git a/src/CRC16.h b/src/CRC16.h
new file mode 100644 (file)
index 0000000..6d3beb3
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    CRC16.h
+    \version $Id$
+    \brief   Declaration of a CRC function
+*/
+
+#ifndef _CRC_16_H_
+#define _CRC_16_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+unsigned short CRC16(const void *pData, int ilength);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/src/DCData_ByteStream_Parser.cpp b/src/DCData_ByteStream_Parser.cpp
new file mode 100644 (file)
index 0000000..73565d4
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    AtmosSyncChannel_Mixer.h
+    \version $Id$
+    \brief   AS-DCP library, Digital Cinema Data bytestream essence reader
+*/
+
+#include "AS_DCP.h"
+#include "KM_fileio.h"
+#include "KM_log.h"
+using Kumu::DefaultLogSink;
+
+//------------------------------------------------------------------------------------------
+
+class ASDCP::DCData::BytestreamParser::h__BytestreamParser
+{
+  ASDCP_NO_COPY_CONSTRUCT(h__BytestreamParser);
+
+public:
+  DCDataDescriptor  m_DDesc;
+  Kumu::FileReader   m_File;
+
+  h__BytestreamParser()
+  {
+    memset(&m_DDesc, 0, sizeof(m_DDesc));
+    m_DDesc.EditRate = Rational(24,1);
+  }
+
+  ~h__BytestreamParser() {}
+
+  Result_t OpenReadFrame(const char* filename, FrameBuffer& FB)
+  {
+    ASDCP_TEST_NULL_STR(filename);
+    m_File.Close();
+    Result_t result = m_File.OpenRead(filename);
+
+    if ( ASDCP_SUCCESS(result) )
+    {
+        Kumu::fsize_t file_size = m_File.Size();
+
+        if ( FB.Capacity() < file_size )
+        {
+            DefaultLogSink().Error("FrameBuf.Capacity: %u frame length: %u\n", FB.Capacity(), (ui32_t)file_size);
+            return RESULT_SMALLBUF;
+        }
+    }
+
+    ui32_t read_count;
+
+    if ( ASDCP_SUCCESS(result) )
+        result = m_File.Read(FB.Data(), FB.Capacity(), &read_count);
+
+    if ( ASDCP_SUCCESS(result) )
+        FB.Size(read_count);
+
+    return result;
+  }
+};
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::DCData::BytestreamParser::BytestreamParser()
+{
+}
+
+ASDCP::DCData::BytestreamParser::~BytestreamParser()
+{
+}
+
+// Opens the stream for reading, parses enough data to provide a complete
+// set of stream metadata for the MXFWriter below.
+ASDCP::Result_t
+ASDCP::DCData::BytestreamParser::OpenReadFrame(const char* filename, FrameBuffer& FB) const
+{
+  const_cast<ASDCP::DCData::BytestreamParser*>(this)->m_Parser = new h__BytestreamParser;
+  return m_Parser->OpenReadFrame(filename, FB);
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::BytestreamParser::FillDCDataDescriptor(DCDataDescriptor& DDesc) const
+{
+  if ( m_Parser.empty() )
+    return RESULT_INIT;
+
+  DDesc = m_Parser->m_DDesc;
+  return RESULT_OK;
+}
+
+
+//
+// end DCData_Bytestream_Parser.cpp
+//
+
+
+
diff --git a/src/DCData_Sequence_Parser.cpp b/src/DCData_Sequence_Parser.cpp
new file mode 100644 (file)
index 0000000..45594c5
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    AtmosSyncChannel_Mixer.h
+    \version $Id$
+    \brief   AS-DCP library, DCinema data seqence reader implementation
+*/
+
+#include "AS_DCP.h"
+
+#include <algorithm>
+#include <list>
+#include <string>
+
+#include "KM_fileio.h"
+#include "KM_log.h"
+
+using ASDCP::Result_t;
+
+//------------------------------------------------------------------------------------------
+namespace ASDCP
+{
+namespace DCData
+{
+class FileList;
+} // namespace DCData
+} // namespace ASDCP
+
+
+class ASDCP::DCData::FileList : public std::list<std::string>
+{
+    std::string m_DirName;
+
+  public:
+    FileList() {}
+    ~FileList() {}
+
+    const FileList& operator=(const std::list<std::string>& pathlist) {
+        std::list<std::string>::const_iterator i;
+        for ( i = pathlist.begin(); i != pathlist.end(); i++ )
+            push_back(*i);
+        return *this;
+    }
+
+    //
+    Result_t InitFromDirectory(const char* path)
+    {
+        char next_file[Kumu::MaxFilePath];
+        Kumu::DirScanner Scanner;
+
+        Result_t result = Scanner.Open(path);
+
+        if ( ASDCP_SUCCESS(result) )
+        {
+            m_DirName = path;
+
+            while ( ASDCP_SUCCESS(Scanner.GetNext(next_file)) )
+            {
+                if ( next_file[0] == '.' ) // no hidden files or internal links
+                    continue;
+
+                std::string Str(m_DirName);
+                Str += "/";
+                Str += next_file;
+
+                if ( ! Kumu::PathIsDirectory(Str) )
+                    push_back(Str);
+            }
+
+            sort();
+        }
+
+        return result;
+    }
+};
+
+//------------------------------------------------------------------------------------------
+
+class ASDCP::DCData::SequenceParser::h__SequenceParser
+{
+  ui32_t             m_FramesRead;
+  Rational           m_PictureRate;
+  FileList           m_FileList;
+  FileList::iterator m_CurrentFile;
+  BytestreamParser   m_Parser;
+
+  Result_t OpenRead();
+
+  ASDCP_NO_COPY_CONSTRUCT(h__SequenceParser);
+
+ public:
+  DCDataDescriptor  m_DDesc;
+
+  h__SequenceParser() : m_FramesRead(0)
+  {
+    memset(&m_DDesc, 0, sizeof(m_DDesc));
+    m_DDesc.EditRate = Rational(24,1);
+  }
+
+  ~h__SequenceParser()
+  {
+    Close();
+  }
+
+  Result_t OpenRead(const char* filename);
+  Result_t OpenRead(const std::list<std::string>& file_list);
+  void     Close() {}
+
+  Result_t Reset()
+  {
+    m_FramesRead = 0;
+    m_CurrentFile = m_FileList.begin();
+    return RESULT_OK;
+  }
+
+  Result_t ReadFrame(FrameBuffer&);
+};
+
+
+//
+ASDCP::Result_t
+ASDCP::DCData::SequenceParser::h__SequenceParser::OpenRead()
+{
+  if ( m_FileList.empty() )
+    return RESULT_ENDOFFILE;
+
+  m_CurrentFile = m_FileList.begin();
+  BytestreamParser Parser;
+  FrameBuffer TmpBuffer;
+
+  Kumu::fsize_t file_size = Kumu::FileSize((*m_CurrentFile).c_str());
+
+  if ( file_size == 0 )
+    return RESULT_NOT_FOUND;
+
+  assert(file_size <= 0xFFFFFFFFL);
+  Result_t result = TmpBuffer.Capacity((ui32_t) file_size);
+
+  if ( ASDCP_SUCCESS(result) )
+    result = Parser.OpenReadFrame((*m_CurrentFile).c_str(), TmpBuffer);
+
+  if ( ASDCP_SUCCESS(result) )
+    result = Parser.FillDCDataDescriptor(m_DDesc);
+
+  // how big is it?
+  if ( ASDCP_SUCCESS(result) )
+    m_DDesc.ContainerDuration = m_FileList.size();
+
+  return result;
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::SequenceParser::h__SequenceParser::OpenRead(const char* filename)
+{
+  ASDCP_TEST_NULL_STR(filename);
+
+  Result_t result = m_FileList.InitFromDirectory(filename);
+
+  if ( ASDCP_SUCCESS(result) )
+    result = OpenRead();
+
+  return result;
+}
+
+
+//
+ASDCP::Result_t
+ASDCP::DCData::SequenceParser::h__SequenceParser::OpenRead(const std::list<std::string>& file_list)
+{
+  m_FileList = file_list;
+  return OpenRead();
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::SequenceParser::h__SequenceParser::ReadFrame(FrameBuffer& FB)
+{
+  if ( m_CurrentFile == m_FileList.end() )
+    return RESULT_ENDOFFILE;
+
+  // open the file
+  Result_t result = m_Parser.OpenReadFrame((*m_CurrentFile).c_str(), FB);
+
+  if ( ASDCP_SUCCESS(result) )
+  {
+      FB.FrameNumber(m_FramesRead++);
+      m_CurrentFile++;
+  }
+
+  return result;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+ASDCP::DCData::SequenceParser::SequenceParser()
+{
+}
+
+ASDCP::DCData::SequenceParser::~SequenceParser()
+{
+}
+
+// Opens the stream for reading, parses enough data to provide a complete
+// set of stream metadata for the MXFWriter below.
+ASDCP::Result_t
+ASDCP::DCData::SequenceParser::OpenRead(const char* filename) const
+{
+  const_cast<ASDCP::DCData::SequenceParser*>(this)->m_Parser = new h__SequenceParser;
+
+  Result_t result = m_Parser->OpenRead(filename);
+
+  if ( ASDCP_FAILURE(result) )
+    const_cast<ASDCP::DCData::SequenceParser*>(this)->m_Parser.release();
+
+  return result;
+}
+
+//
+Result_t
+ASDCP::DCData::SequenceParser::OpenRead(const std::list<std::string>& file_list) const
+{
+  const_cast<ASDCP::DCData::SequenceParser*>(this)->m_Parser = new h__SequenceParser;
+
+  Result_t result = m_Parser->OpenRead(file_list);
+
+  if ( ASDCP_FAILURE(result) )
+    const_cast<ASDCP::DCData::SequenceParser*>(this)->m_Parser.release();
+
+  return result;
+}
+
+
+// Rewinds the stream to the beginning.
+ASDCP::Result_t
+ASDCP::DCData::SequenceParser::Reset() const
+{
+  if ( m_Parser.empty() )
+    return RESULT_INIT;
+
+  return m_Parser->Reset();
+}
+
+// Places a frame of data in the frame buffer. Fails if the buffer is too small
+// or the stream is empty.
+ASDCP::Result_t
+ASDCP::DCData::SequenceParser::ReadFrame(FrameBuffer& FB) const
+{
+  if ( m_Parser.empty() )
+    return RESULT_INIT;
+
+  return m_Parser->ReadFrame(FB);
+}
+
+//
+ASDCP::Result_t
+ASDCP::DCData::SequenceParser::FillDCDataDescriptor(DCDataDescriptor& DDesc) const
+{
+  if ( m_Parser.empty() )
+    return RESULT_INIT;
+
+  DDesc = m_Parser->m_DDesc;
+  return RESULT_OK;
+}
+
+
+//
+// end DCData_Sequence_Parser.cpp
+//
+
index 449d5bf91e0105b84061648b053e9fc623580d3d..f37758516411b9969060999217ee04546735bebd 100755 (executable)
@@ -143,7 +143,7 @@ ASDCP::MXF::IndexTableSegment::Dump(FILE* stream)
     }
   else
     {
-      fprintf(stream, "  IndexEntryArray: %du entries\n", IndexEntryArray.size());
+      fprintf(stream, "  IndexEntryArray: %zu entries\n", IndexEntryArray.size());
     }
 }
 
index 56276245f6d96b7f579f3ed51e02b68f06e9657c..5afb75edc2216ddb707af064911613ee5bc6e463 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2006-2012, John Hurst
+Copyright (c) 2006-2013, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -917,6 +917,85 @@ static const ASDCP::MDDEntry s_MDD_Table[] = {
   { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0d, // 293
       0x01, 0x03, 0x07, 0x01, 0x04, 0x00, 0x00, 0x00 },
     {0}, false, "SoundfieldGroupLabelSubDescriptor_GroupOfSoundfieldGroupsLinkID" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x05, // 294
+      0x0e, 0x09, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00 },
+    {0}, false, "DCDataWrapping" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x05, // 295
+      0x0e, 0x09, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00 },
+    {0}, false, "DCDataEssence" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x05, // 296
+      0x0e, 0x09, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00 },
+    {0}, false, "DCDataDescriptor" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x05, // 297
+      0x0e, 0x09, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00 },
+    {0}, false, "DolbyAtmosSubDescriptor" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 298
+      0x0e, 0x09, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00 },
+    {0}, true, "DolbyAtmosSubDescriptor_AtmosVersion" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 299
+      0x0e, 0x09, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00 },
+    {0}, true, "DolbyAtmosSubDescriptor_MaxChannelCount" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 300
+      0x0e, 0x09, 0x05, 0x08, 0x00, 0x00, 0x00, 0x00 },
+    {0}, true, "DolbyAtmosSubDescriptor_MaxObjectCount" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 301
+      0x0e, 0x09, 0x05, 0x09, 0x00, 0x00, 0x00, 0x00 },
+    {0}, true, "DolbyAtmosSubDescriptor_AtmosID" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 302
+      0x0e, 0x09, 0x05, 0x0A, 0x00, 0x00, 0x00, 0x00 },
+    {0}, true, "DolbyAtmosSubDescriptor_FirstFrame" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 303
+      0x01, 0x03, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00 },
+      {0}, false, "DataDataDef" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 304
+      0x04, 0x02, 0x02, 0x10, 0x03, 0x02, 0x00, 0x00 },
+    {0}, false, "DCAudioChannelCfg_MCA" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 305
+      0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
+      {0}, false, "DCAudioChannel_L" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 306
+      0x03, 0x02, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00 },
+      {0}, false, "DCAudioChannel_R" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 307
+      0x03, 0x02, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00 },
+      {0}, false, "DCAudioChannel_C" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 308
+      0x03, 0x02, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00 },
+      {0}, false, "DCAudioChannel_LFE" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 309
+      0x03, 0x02, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00 },
+      {0}, false, "DCAudioChannel_Ls" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 310
+      0x03, 0x02, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00 },
+      {0}, false, "DCAudioChannel_Rs" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 311
+      0x03, 0x02, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 },
+      {0}, false, "DCAudioChannel_Lss" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 312
+      0x03, 0x02, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00 },
+      {0}, false, "DCAudioChannel_Rss" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 313
+      0x03, 0x02, 0x01, 0x09, 0x00, 0x00, 0x00, 0x00 },
+      {0}, false, "DCAudioChannel_Lrs" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 314
+      0x03, 0x02, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00 },
+      {0}, false, "DCAudioChannel_Rrs" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 315
+      0x03, 0x02, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x00 },
+      {0}, false, "DCAudioChannel_Lc" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 316
+      0x03, 0x02, 0x01, 0x0c, 0x00, 0x00, 0x00, 0x00 },
+      {0}, false, "DCAudioChannel_Rc" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 317
+      0x03, 0x02, 0x01, 0x0d, 0x00, 0x00, 0x00, 0x00 },
+      {0}, false, "DCAudioChannel_Cs" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 318
+      0x03, 0x02, 0x01, 0x0e, 0x00, 0x00, 0x00, 0x00 },
+      {0}, false, "DCAudioChannel_HI" },
+  { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 319
+      0x03, 0x02, 0x01, 0x0f, 0x00, 0x00, 0x00, 0x00 },
+      {0}, false, "DCAudioChannel_VIN" },
+
   { {0}, {0}, false, 0 }
 };
 
index 358b874869f1d24d4cc37ca9b002e1c153f22092..ab8482f2775cead3bd92357fe3005d0ccbeb0be0 100755 (executable)
--- a/src/MDD.h
+++ b/src/MDD.h
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2006-2012, John Hurst
+Copyright (c) 2006-2013, John Hurst
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -290,46 +290,72 @@ namespace ASDCP {
         MDD_CryptographicContext_CipherAlgorithm,  // 252
         MDD_CryptographicContext_MICAlgorithm,  // 253
         MDD_CryptographicContext_CryptographicKeyID,  // 254
-       MDD_TimedTextWrapping, // 255
-       MDD_TimedTextEssence, // 256
-       MDD_TimedTextDescriptor, // 257
-       MDD_TimedTextDescriptor_ResourceID, // 258
-       MDD_TimedTextDescriptor_UCSEncoding, // 259
-       MDD_TimedTextDescriptor_NamespaceURI, // 260
-       MDD_TimedTextResourceSubDescriptor, // 261
-       MDD_TimedTextResourceSubDescriptor_AncillaryResourceID, // 262
-       MDD_TimedTextResourceSubDescriptor_MIMEMediaType, // 263
-       MDD_TimedTextResourceSubDescriptor_EssenceStreamID_DEPRECATED, // 264
-       MDD_GenericStreamPartition, // 265
-       MDD_DMSegment_DataDefinition_DEPRECATED, // 266
-       MDD_DMSegment_Duration_DEPRECATED, // 267
-       MDD_DMSegment_TrackIDList, // 268
-       MDD_StereoscopicPictureSubDescriptor, // 269
+        MDD_TimedTextWrapping, // 255
+        MDD_TimedTextEssence, // 256
+        MDD_TimedTextDescriptor, // 257
+        MDD_TimedTextDescriptor_ResourceID, // 258
+        MDD_TimedTextDescriptor_UCSEncoding, // 259
+        MDD_TimedTextDescriptor_NamespaceURI, // 260
+        MDD_TimedTextResourceSubDescriptor, // 261
+        MDD_TimedTextResourceSubDescriptor_AncillaryResourceID, // 262
+        MDD_TimedTextResourceSubDescriptor_MIMEMediaType, // 263
+        MDD_TimedTextResourceSubDescriptor_EssenceStreamID_DEPRECATED, // 264
+        MDD_GenericStreamPartition, // 265
+        MDD_DMSegment_DataDefinition_DEPRECATED, // 266
+        MDD_DMSegment_Duration_DEPRECATED, // 267
+        MDD_DMSegment_TrackIDList, // 268
+        MDD_StereoscopicPictureSubDescriptor, // 269
         MDD_WaveAudioDescriptor_ChannelAssignment,  // 270
-       MDD_GenericStream_DataElement, // 271
+        MDD_GenericStream_DataElement, // 271
         MDD_MXFInterop_GenericDescriptor_SubDescriptors,  // 272
-       MDD_Core_BodySID, // 273
-       MDD_Core_IndexSID, // 274
-       MDD_Core_OperationalPattern, // 275
-       MDD_Core_EssenceContainers, // 276
-       MDD_DCAudioChannelCfg_1_5p1, // 277
-       MDD_DCAudioChannelCfg_2_6p1, // 278
-       MDD_DCAudioChannelCfg_3_7p1, // 279
-       MDD_DCAudioChannelCfg_4_WTF, // 280
-       MDD_DCAudioChannelCfg_5_7p1_DS, // 281
-       MDD_MCALabelSubDescriptor, // 282
-       MDD_AudioChannelLabelSubDescriptor, // 283
-       MDD_SoundfieldGroupLabelSubDescriptor, // 284
-       MDD_GroupOfSoundfieldGroupsLabelSubDescriptor, // 285
-       MDD_MCALabelSubDescriptor_MCALabelDictionaryID, // 286
-       MDD_MCALabelSubDescriptor_MCALinkID, // 287
-       MDD_MCALabelSubDescriptor_MCATagSymbol, // 288
-       MDD_MCALabelSubDescriptor_MCATagName, // 289
-       MDD_MCALabelSubDescriptor_MCAChannelID, // 290
-       MDD_MCALabelSubDescriptor_RFC5646SpokenLanguage, // 291
-       MDD_AudioChannelLabelSubDescriptor_SoundfieldGroupLinkID, // 292
-       MDD_SoundfieldGroupLabelSubDescriptor_GroupOfSoundfieldGroupsLinkID, // 293
-       MDD_Max
+        MDD_Core_BodySID, // 273
+        MDD_Core_IndexSID, // 274
+        MDD_Core_OperationalPattern, // 275
+        MDD_Core_EssenceContainers, // 276
+        MDD_DCAudioChannelCfg_1_5p1, // 277
+        MDD_DCAudioChannelCfg_2_6p1, // 278
+        MDD_DCAudioChannelCfg_3_7p1, // 279
+        MDD_DCAudioChannelCfg_4_WTF, // 280
+        MDD_DCAudioChannelCfg_5_7p1_DS, // 281
+        MDD_MCALabelSubDescriptor, // 282
+        MDD_AudioChannelLabelSubDescriptor, // 283
+        MDD_SoundfieldGroupLabelSubDescriptor, // 284
+        MDD_GroupOfSoundfieldGroupsLabelSubDescriptor, // 285
+        MDD_MCALabelSubDescriptor_MCALabelDictionaryID, // 286
+        MDD_MCALabelSubDescriptor_MCALinkID, // 287
+        MDD_MCALabelSubDescriptor_MCATagSymbol, // 288
+        MDD_MCALabelSubDescriptor_MCATagName, // 289
+        MDD_MCALabelSubDescriptor_MCAChannelID, // 290
+        MDD_MCALabelSubDescriptor_RFC5646SpokenLanguage, // 291
+        MDD_AudioChannelLabelSubDescriptor_SoundfieldGroupLinkID, // 292
+        MDD_SoundfieldGroupLabelSubDescriptor_GroupOfSoundfieldGroupsLinkID, // 293
+        MDD_DCDataWrapping, // 294
+        MDD_DCDataEssence, // 295
+        MDD_DCDataDescriptor, // 296
+        MDD_DolbyAtmosSubDescriptor, // 297
+        MDD_DolbyAtmosSubDescriptor_AtmosVersion, // 298
+        MDD_DolbyAtmosSubDescriptor_MaxChannelCount, // 299
+        MDD_DolbyAtmosSubDescriptor_MaxObjectCount, // 300
+        MDD_DolbyAtmosSubDescriptor_AtmosID, // 301
+        MDD_DolbyAtmosSubDescriptor_FirstFrame, // 302
+        MDD_DataDataDef, // 303
+       MDD_DCAudioChannelCfg_MCA, // 304
+       MDD_DCAudioChannel_L, // 305
+       MDD_DCAudioChannel_R, // 306
+       MDD_DCAudioChannel_C, // 307
+       MDD_DCAudioChannel_LFE, // 308
+       MDD_DCAudioChannel_Ls, // 309
+       MDD_DCAudioChannel_Rs, // 310
+       MDD_DCAudioChannel_Lss, // 311
+       MDD_DCAudioChannel_Rss, // 312
+       MDD_DCAudioChannel_Lrs, // 313
+       MDD_DCAudioChannel_Rrs, // 314
+       MDD_DCAudioChannel_Lc, // 315
+       MDD_DCAudioChannel_Rc, // 316
+       MDD_DCAudioChannel_Cs, // 317
+       MDD_DCAudioChannel_HI, // 318
+       MDD_DCAudioChannel_VIN, // 319
+        MDD_Max
 
     }; // enum MDD_t
 
@@ -342,7 +368,7 @@ namespace ASDCP {
     const MDD_t MDD_Preface_EssenceContainers = MDD_Core_EssenceContainers;
     const MDD_t MDD_Preface_OperationalPattern = MDD_Core_OperationalPattern;
     const MDD_t MDD_TimedTextResourceSubDescriptor_EssenceStreamID = MDD_Core_BodySID;
-    
+
 } // namespaceASDCP
 
 
index 7f042eebfee95fc298578589af04eb0f6db79390..1b9e558592688d4ea842c6fa52b6ce7f43529bbc 100755 (executable)
@@ -725,12 +725,20 @@ ASDCP::MXF::OPAtomHeader::InitFromFile(const Kumu::FileReader& Reader)
            }
        }
     }
+  else
+  {
+    DefaultLogSink().Error("OPAtomHeader::InitFromFile, SeekToRIP failed\n");
+  }
 
   if ( ASDCP_SUCCESS(result) )
     result = Reader.Seek(0);
+  else
+    DefaultLogSink().Error("OPAtomHeader::InitFromFile, Seek failed\n");
 
   if ( ASDCP_SUCCESS(result) )
     result = Partition::InitFromFile(Reader); // test UL and OP
+  else
+    DefaultLogSink().Error("OPAtomHeader::InitFromFile, Partition::InitFromFile failed\n");
 
   if ( ASDCP_FAILURE(result) )
     return result;
@@ -774,7 +782,10 @@ ASDCP::MXF::OPAtomHeader::InitFromFile(const Kumu::FileReader& Reader)
       result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
 
       if ( ASDCP_FAILURE(result) )
-       return result;
+        {
+         DefaultLogSink().Error("OPAtomHeader::InitFromFile, Read failed\n");
+         return result;
+        }
 
       if ( read_count != m_Buffer.Capacity() )
        {
@@ -1038,17 +1049,21 @@ ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const Kumu::FileReader& Reader)
 {
   Result_t result = Partition::InitFromFile(Reader); // test UL and OP
 
-  // slurp up the remainder of the footer
-  ui32_t read_count;
+       // slurp up the remainder of the footer
+       ui32_t read_count = 0;
 
-  if ( ASDCP_SUCCESS(result) )
+       if ( ASDCP_SUCCESS(result) )
     {
-      assert (IndexByteCount <= 0xFFFFFFFFL);
-      result = m_Buffer.Capacity((ui32_t) IndexByteCount);
+               assert (IndexByteCount <= 0xFFFFFFFFL);
+               // At this point, m_Buffer may not have been initialized
+               // so it's capacity is zero and data pointer is NULL
+               // However, if IndexByteCount is zero then the capacity
+               // doesn't change and the data pointer is not set.
+               result = m_Buffer.Capacity((ui32_t) IndexByteCount);
     }
 
-  if ( ASDCP_SUCCESS(result) )
-    result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
+       if ( ASDCP_SUCCESS(result) && m_Buffer.Data() )
+               result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
 
   if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
     {
@@ -1056,6 +1071,12 @@ ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const Kumu::FileReader& Reader)
                             read_count, m_Buffer.Capacity());
       return RESULT_FAIL;
     }
+       else if( ASDCP_SUCCESS(result) && !m_Buffer.Data() )
+       {
+               DefaultLogSink().Error( "Buffer for footer partition not created: IndexByteCount = %u\n",
+                                                               IndexByteCount );
+               return RESULT_FAIL;
+       }
 
   if ( ASDCP_SUCCESS(result) )
     result = InitFromBuffer(m_Buffer.RoData(), m_Buffer.Capacity());
index 6cd2da3465cac768cd3e16153f4751680495ff47..fdbf3c481f9825a0d9a83219d15cf8eafc4a51d1 100644 (file)
@@ -61,7 +61,8 @@ include_HEADERS += \
        MXFTypes.h \
        MXF.h \
        Wav.h \
-       PCMParserList.h
+       PCMParserList.h \
+       AtmosSyncChannel_Generator.h
 nodist_include_HEADERS = TimedText_Transform.h
 endif
 
@@ -89,7 +90,16 @@ libasdcp_la_SOURCES = MPEG2_Parser.cpp MPEG.cpp JP2K_Codestream_Parser.cpp \
                AS_DCP_PCM.cpp AS_DCP_TimedText.cpp PCMParserList.cpp \
                Wav.h WavFileWriter.h MXF.h Metadata.h \
                JP2K.h AS_DCP.h AS_DCP_internal.h KLV.h MPEG.h MXFTypes.h MDD.h \
-               PCMParserList.h S12MTimecode.h MDD.cpp
+               PCMParserList.h S12MTimecode.h MDD.cpp \
+               AS_DCP_ATMOS.cpp  AS_DCP_DCData.cpp AS_DCP_DCData_internal.h \
+               DCData_ByteStream_Parser.cpp DCData_Sequence_Parser.cpp \
+               AtmosSyncChannel_Generator.cpp AtmosSyncChannel_Generator.h \
+               AtmosSyncChannel_Mixer.cpp AtmosSyncChannel_Mixer.h \
+               PCMDataProviders.cpp PCMDataProviders.h \
+               SyncEncoder.c SyncEncoder.h SyncCommon.h CRC16.c CRC16.h \
+               UUIDInformation.c UUIDInformation.h
+
+
 if DEV_HEADERS
 nodist_libasdcp_la_SOURCES += TimedText_Transform.h TimedText_Transform.cpp
 endif
index ac1db76aba2dcecf7c5ad60e7b1f574896ae0ab3..3507ba00f89ce08dbd128d81b64795ff21a42182 100755 (executable)
@@ -73,6 +73,8 @@ static InterchangeObject* MCALabelSubDescriptor_Factory(const Dictionary*& Dict)
 static InterchangeObject* AudioChannelLabelSubDescriptor_Factory(const Dictionary*& Dict) { return new AudioChannelLabelSubDescriptor(Dict); }
 static InterchangeObject* SoundfieldGroupLabelSubDescriptor_Factory(const Dictionary*& Dict) { return new SoundfieldGroupLabelSubDescriptor(Dict); }
 static InterchangeObject* GroupOfSoundfieldGroupsLabelSubDescriptor_Factory(const Dictionary*& Dict) { return new GroupOfSoundfieldGroupsLabelSubDescriptor(Dict); }
+static InterchangeObject* DCDataDescriptor_Factory(const Dictionary*& Dict) { return new DCDataDescriptor(Dict); }
+static InterchangeObject* DolbyAtmosSubDescriptor_Factory(const Dictionary*& Dict) { return new DolbyAtmosSubDescriptor(Dict); }
 
 
 void
@@ -112,6 +114,8 @@ ASDCP::MXF::Metadata_InitTypes(const Dictionary*& Dict)
   SetObjectFactory(Dict->ul(MDD_AudioChannelLabelSubDescriptor), AudioChannelLabelSubDescriptor_Factory);
   SetObjectFactory(Dict->ul(MDD_SoundfieldGroupLabelSubDescriptor), SoundfieldGroupLabelSubDescriptor_Factory);
   SetObjectFactory(Dict->ul(MDD_GroupOfSoundfieldGroupsLabelSubDescriptor), GroupOfSoundfieldGroupsLabelSubDescriptor_Factory);
+  SetObjectFactory(Dict->ul(MDD_DCDataDescriptor), DCDataDescriptor_Factory);
+  SetObjectFactory(Dict->ul(MDD_DolbyAtmosSubDescriptor), DolbyAtmosSubDescriptor_Factory);
 }
 
 //------------------------------------------------------------------------------------------
@@ -2888,6 +2892,170 @@ GroupOfSoundfieldGroupsLabelSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buf
   return InterchangeObject::WriteToBuffer(Buffer);
 }
 
+//------------------------------------------------------------------------------------------
+// DCDataDescriptor
+
+//
+
+DCDataDescriptor::DCDataDescriptor(const Dictionary*& d) : GenericDataEssenceDescriptor(d), m_Dict(d)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_DCDataDescriptor);
+}
+
+DCDataDescriptor::DCDataDescriptor(const DCDataDescriptor& rhs) : GenericDataEssenceDescriptor(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_DCDataDescriptor);
+  Copy(rhs);
+}
+
+//
+ASDCP::Result_t
+DCDataDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+    // NOTE (this function can be removed if no attributes are defined for this descriptor)
+    assert(m_Dict);
+    Result_t result = GenericDataEssenceDescriptor::InitFromTLVSet(TLVSet);
+    return result;
+}
+
+//
+ASDCP::Result_t
+DCDataDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+  // NOTE (this function can be removed if no attributes are defined for this descriptor)
+  assert(m_Dict);
+  Result_t result = GenericDataEssenceDescriptor::WriteToTLVSet(TLVSet);
+  return result;
+}
+
+//
+void
+DCDataDescriptor::Copy(const DCDataDescriptor& rhs)
+{
+  GenericDataEssenceDescriptor::Copy(rhs);
+}
+
+//
+void
+DCDataDescriptor::Dump(FILE* stream)
+{
+  char identbuf[IdentBufferLen];
+  *identbuf = 0;
+
+  if ( stream == 0 )
+    stream = stderr;
+
+  GenericDataEssenceDescriptor::Dump(stream);
+}
+
+//
+ASDCP::Result_t
+DCDataDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+  return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+DCDataDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+  return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+//------------------------------------------------------------------------------------------
+// DolbyAtmosSubDescriptor
+
+//
+
+DolbyAtmosSubDescriptor::DolbyAtmosSubDescriptor(const Dictionary*& d) : InterchangeObject(d), m_Dict(d), FirstFrame(0), MaxChannelCount(0), MaxObjectCount(0), AtmosVersion(0)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_DolbyAtmosSubDescriptor);
+}
+
+DolbyAtmosSubDescriptor::DolbyAtmosSubDescriptor(const DolbyAtmosSubDescriptor& rhs) : InterchangeObject(rhs.m_Dict), m_Dict(rhs.m_Dict)
+{
+  assert(m_Dict);
+  m_UL = m_Dict->ul(MDD_DolbyAtmosSubDescriptor);
+  Copy(rhs);
+}
+
+
+//
+ASDCP::Result_t
+DolbyAtmosSubDescriptor::InitFromTLVSet(TLVReader& TLVSet)
+{
+  assert(m_Dict);
+  Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(DolbyAtmosSubDescriptor, AtmosID));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(DolbyAtmosSubDescriptor, FirstFrame));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(DolbyAtmosSubDescriptor, MaxChannelCount));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(DolbyAtmosSubDescriptor, MaxObjectCount));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi8(OBJ_READ_ARGS(DolbyAtmosSubDescriptor, AtmosVersion));
+  return result;
+}
+
+//
+ASDCP::Result_t
+DolbyAtmosSubDescriptor::WriteToTLVSet(TLVWriter& TLVSet)
+{
+  assert(m_Dict);
+  Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(DolbyAtmosSubDescriptor, AtmosID));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(DolbyAtmosSubDescriptor, FirstFrame));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(DolbyAtmosSubDescriptor, MaxChannelCount));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(DolbyAtmosSubDescriptor, MaxObjectCount));
+  if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi8(OBJ_WRITE_ARGS(DolbyAtmosSubDescriptor, AtmosVersion));
+  return result;
+}
+
+//
+void
+DolbyAtmosSubDescriptor::Copy(const DolbyAtmosSubDescriptor& rhs)
+{
+  InterchangeObject::Copy(rhs);
+  AtmosID = rhs.AtmosID;
+  FirstFrame = rhs.FirstFrame;
+  MaxChannelCount = rhs.MaxChannelCount;
+  MaxObjectCount = rhs.MaxObjectCount;
+  AtmosVersion = rhs.AtmosVersion;
+}
+
+//
+void
+DolbyAtmosSubDescriptor::Dump(FILE* stream)
+{
+  char identbuf[IdentBufferLen];
+  *identbuf = 0;
+
+  if ( stream == 0 )
+    stream = stderr;
+
+  InterchangeObject::Dump(stream);
+  fprintf(stream, "  %22s = %s\n",  "AtmosID", AtmosID.EncodeString(identbuf, IdentBufferLen));
+  fprintf(stream, "  %22s = %d\n",  "FirstFrame", FirstFrame);
+  fprintf(stream, "  %22s = %d\n",  "MaxChannelCount", MaxChannelCount);
+  fprintf(stream, "  %22s = %d\n",  "MaxObjectCount", MaxObjectCount);
+  fprintf(stream, "  %22s = %d\n",  "AtmosVersion", AtmosVersion);
+}
+
+//
+ASDCP::Result_t
+DolbyAtmosSubDescriptor::InitFromBuffer(const byte_t* p, ui32_t l)
+{
+  return InterchangeObject::InitFromBuffer(p, l);
+}
+
+//
+ASDCP::Result_t
+DolbyAtmosSubDescriptor::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
+{
+  return InterchangeObject::WriteToBuffer(Buffer);
+}
+
+
 //
 // end Metadata.cpp
 //
index 507a151b8718ab0d6fd78f7ac7644f47646a417d..6b9a50c8266fa8101ae1b14f01b9bc0a8195f383 100755 (executable)
@@ -889,6 +889,55 @@ namespace ASDCP
       virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
        };
 
+      //
+     class DCDataDescriptor : public GenericDataEssenceDescriptor
+       {
+         DCDataDescriptor();
+
+       public:
+         const Dictionary*& m_Dict;
+
+      DCDataDescriptor(const Dictionary*& d);
+      DCDataDescriptor(const DCDataDescriptor& rhs);
+      virtual ~DCDataDescriptor() {}
+
+      const DCDataDescriptor& operator=(const DCDataDescriptor& rhs) { Copy(rhs); return *this; }
+      virtual void Copy(const DCDataDescriptor& rhs);
+      virtual const char* HasName() { return "DCDataDescriptor"; }
+      virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+      virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+      virtual void     Dump(FILE* = 0);
+      virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+      virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+       };
+
+      //
+      class DolbyAtmosSubDescriptor : public InterchangeObject
+       {
+         DolbyAtmosSubDescriptor();
+
+       public:
+         const Dictionary*& m_Dict;
+        UUID AtmosID;
+        ui32_t FirstFrame;
+        ui16_t MaxChannelCount;
+        ui16_t MaxObjectCount;
+        ui8_t AtmosVersion;
+
+      DolbyAtmosSubDescriptor(const Dictionary*& d);
+      DolbyAtmosSubDescriptor(const DolbyAtmosSubDescriptor& rhs);
+      virtual ~DolbyAtmosSubDescriptor() {}
+
+      const DolbyAtmosSubDescriptor& operator=(const DolbyAtmosSubDescriptor& rhs) { Copy(rhs); return *this; }
+      virtual void Copy(const DolbyAtmosSubDescriptor& rhs);
+      virtual const char* HasName() { return "DolbyAtmosSubDescriptor"; }
+      virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
+      virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
+      virtual void     Dump(FILE* = 0);
+      virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
+      virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
+       };
+
     } // namespace MXF
 } // namespace ASDCP
 
diff --git a/src/PCMDataProviders.cpp b/src/PCMDataProviders.cpp
new file mode 100644 (file)
index 0000000..7d2c152
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+Copyright (c) 20013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    PCMDataProviders.cpp
+    \version $Id$
+    \brief   Implementation of PCM sample data providers for WAV, AtmosSync and Silence.
+*/
+
+#include <PCMDataProviders.h>
+
+#include <KM_log.h>
+
+using namespace ASDCP;
+using namespace Kumu;
+
+ASDCP::PCMDataProviderInterface::~PCMDataProviderInterface() {}
+
+//
+ASDCP::WAVDataProvider::WAVDataProvider()
+    : m_Parser(), m_FB(), m_ADesc(), m_SampleSize(0), m_ptr(NULL)
+{}
+
+ASDCP::WAVDataProvider::~WAVDataProvider()
+{}
+
+Result_t
+ASDCP::WAVDataProvider::PutSample(const ui32_t numChannels, byte_t* buf, ui32_t* bytesWritten)
+{
+  ASDCP_TEST_NULL(buf);
+  ASDCP_TEST_NULL(m_ptr);
+  if ( numChannels > m_ADesc.ChannelCount)
+  {
+    DefaultLogSink().Error("Requested %u channels from a wav file with %u channel.", numChannels,
+                           m_ADesc.ChannelCount);
+    return RESULT_FAIL;
+  }
+  *bytesWritten = m_SampleSize * numChannels;
+  ::memcpy(buf, m_ptr, *bytesWritten);
+  m_ptr += *bytesWritten;
+  return RESULT_OK;
+}
+
+Result_t
+ASDCP::WAVDataProvider::ReadFrame()
+{
+  Result_t result = m_Parser.ReadFrame(m_FB);
+  m_ptr = ASDCP_SUCCESS(result) ? m_FB.RoData() : NULL;
+  return result;
+}
+
+Result_t
+ASDCP::WAVDataProvider::FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const
+{
+  ADesc = m_ADesc;
+  return RESULT_OK;
+}
+
+Result_t
+ASDCP::WAVDataProvider::Reset()
+{
+    return m_Parser.Reset();
+}
+
+Result_t
+ASDCP::WAVDataProvider::OpenRead(const char* filename, const Rational& PictureRate)
+{
+  ASDCP_TEST_NULL_STR(filename);
+
+  Result_t result = m_Parser.OpenRead(filename, PictureRate);
+
+  if ( ASDCP_SUCCESS(result) )
+    result = m_Parser.FillAudioDescriptor(m_ADesc);
+
+  if ( ASDCP_SUCCESS(result) )
+  {
+    m_ADesc.EditRate = PictureRate;
+    m_SampleSize = ((m_ADesc.QuantizationBits + 7) / 8);
+    result = m_FB.Capacity(PCM::CalcFrameBufferSize(m_ADesc));
+  }
+
+  return result;
+}
+
+//
+ASDCP::AtmosSyncDataProvider::AtmosSyncDataProvider(const ui16_t bitsPerSample, const ui32_t sampleRate,
+                                                    const ASDCP::Rational& editRate, const byte_t* uuid)
+    : m_Generator(bitsPerSample, sampleRate, editRate, uuid), m_FB(), m_ADesc(), m_SampleSize()
+{
+    m_Generator.FillAudioDescriptor(m_ADesc);
+    m_SampleSize = PCM::CalcSampleSize(m_ADesc);
+    m_FB.Capacity(PCM::CalcFrameBufferSize(m_ADesc));
+}
+
+ASDCP::AtmosSyncDataProvider::~AtmosSyncDataProvider()
+{}
+
+Result_t
+ASDCP::AtmosSyncDataProvider::PutSample(const ui32_t numChannels, byte_t* buf, ui32_t* bytesWritten)
+{
+  ASDCP_TEST_NULL(buf);
+  ASDCP_TEST_NULL(m_ptr);
+  if ( numChannels > m_ADesc.ChannelCount)
+  {
+    DefaultLogSink().Error("Requested %u channels from a wav file with %u channel.", numChannels,
+                           m_ADesc.ChannelCount);
+    return RESULT_FAIL;
+  }
+
+  (*bytesWritten) = m_SampleSize;
+  ::memcpy(buf, m_ptr, m_SampleSize);
+  m_ptr += m_SampleSize;
+  return RESULT_OK;
+}
+
+Result_t
+ASDCP::AtmosSyncDataProvider::ReadFrame()
+{
+  Result_t result = m_Generator.ReadFrame(m_FB);
+  m_ptr = ASDCP_SUCCESS(result) ? m_FB.RoData() : NULL;
+  return result;
+}
+
+Result_t
+ASDCP::AtmosSyncDataProvider::FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const
+{
+  ADesc = m_ADesc;
+  return RESULT_OK;
+}
+
+Result_t
+ASDCP::AtmosSyncDataProvider::Reset()
+{
+    return m_Generator.Reset();
+}
+
+//
+ASDCP::SilenceDataProvider::SilenceDataProvider(const ui16_t numChannels, const ui16_t bitsPerSample,
+                                                const ui32_t sampleRate, const ASDCP::Rational& editRate)
+    : m_ADesc(), m_SampleSize(0)
+{
+    m_SampleSize = ((bitsPerSample + 7) / 8);
+    m_ADesc.EditRate = editRate;
+    m_ADesc.AudioSamplingRate = Rational(sampleRate, 1);
+    m_ADesc.ChannelCount = numChannels;
+    m_ADesc.QuantizationBits = bitsPerSample;
+    m_ADesc.BlockAlign = numChannels * m_SampleSize;
+    m_ADesc.AvgBps = sampleRate * m_ADesc.BlockAlign;
+}
+
+ASDCP::SilenceDataProvider::~SilenceDataProvider()
+{}
+
+Result_t
+ASDCP::SilenceDataProvider::PutSample(const ui32_t numChannels, byte_t* buf, ui32_t* bytesWritten)
+{
+  ASDCP_TEST_NULL(buf);
+  if ( numChannels > m_ADesc.ChannelCount)
+  {
+    DefaultLogSink().Error("Requested %u channels from a wav file with %u channel.", numChannels,
+                           m_ADesc.ChannelCount);
+    return RESULT_FAIL;
+  }
+  (*bytesWritten) = m_SampleSize * numChannels;
+  ::memset(buf, 0, (*bytesWritten));
+  return RESULT_OK;
+}
+
+Result_t
+ASDCP::SilenceDataProvider::ReadFrame()
+{
+    // no op
+    return RESULT_OK;
+}
+
+Result_t
+ASDCP::SilenceDataProvider::FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const
+{
+  ADesc = m_ADesc;
+  return RESULT_OK;
+}
+
+Result_t
+ASDCP::SilenceDataProvider::Reset()
+{
+    //no op
+    return RESULT_OK;
+}
diff --git a/src/PCMDataProviders.h b/src/PCMDataProviders.h
new file mode 100644 (file)
index 0000000..9241fd3
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    PCMDataProviders.h
+    \version $Id$
+    \brief   PCM sample data providers for WAV, AtmosSync and Silence.
+*/
+
+#ifndef _PCMDATAPROVIDERS_H_
+#define _PCMDATAPROVIDERS_H_
+
+#include <AS_DCP.h>
+#include <AtmosSyncChannel_Generator.h>
+
+namespace ASDCP
+{
+
+  // PCM Data Provider Interface
+  class PCMDataProviderInterface
+  {
+      ASDCP_NO_COPY_CONSTRUCT(PCMDataProviderInterface);
+
+  public:
+      PCMDataProviderInterface() {};
+      virtual ~PCMDataProviderInterface() = 0;
+      virtual Result_t PutSample(const ui32_t numChannels, byte_t* buf, ui32_t* bytesWritten) = 0;
+      virtual Result_t ReadFrame() = 0;
+      virtual Result_t FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const = 0;
+      virtual Result_t Reset() = 0;
+  };
+
+  // WAV file implementation of the PCM Data Provider Interface
+  class WAVDataProvider : public PCMDataProviderInterface
+  {
+      ASDCP_NO_COPY_CONSTRUCT(WAVDataProvider);
+      PCM::WAVParser       m_Parser;
+      PCM::FrameBuffer     m_FB;
+      PCM::AudioDescriptor m_ADesc;
+      const byte_t*        m_ptr;
+      ui32_t               m_SampleSize;
+
+  public:
+      WAVDataProvider();
+      virtual ~WAVDataProvider();
+      virtual Result_t PutSample(const ui32_t numChannels, byte_t* buf, ui32_t* bytesWritten);
+      virtual Result_t ReadFrame();
+      virtual Result_t FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const;
+      virtual Result_t Reset();
+      Result_t OpenRead(const char* filename, const Rational& PictureRate);
+
+  };
+
+  // Atmos Sync Channel implementation of the PCM Data Provider Interface
+  class AtmosSyncDataProvider : public PCMDataProviderInterface
+  {
+      ASDCP_NO_COPY_CONSTRUCT(AtmosSyncDataProvider);
+      PCM::AtmosSyncChannelGenerator m_Generator;
+      PCM::FrameBuffer                m_FB;
+      PCM::AudioDescriptor            m_ADesc;
+      const byte_t*                   m_ptr;
+      ui32_t                          m_SampleSize;
+
+  public:
+      AtmosSyncDataProvider(const ui16_t bitsPerSample, const ui32_t sampleRate,
+                            const ASDCP::Rational& PictureRate, const byte_t* uuid);
+      virtual ~AtmosSyncDataProvider();
+      virtual Result_t PutSample(const ui32_t numChannels, byte_t* buf, ui32_t* bytesWritten);
+      virtual Result_t ReadFrame();
+      virtual Result_t FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const;
+      virtual Result_t Reset();
+  };
+
+  // Silence Channel(s) implementation of the PCM Data Provider Interface
+  class SilenceDataProvider : public PCMDataProviderInterface
+  {
+      ASDCP_NO_COPY_CONSTRUCT(SilenceDataProvider);
+      PCM::AudioDescriptor  m_ADesc;
+      ui32_t                m_SampleSize;
+
+  public:
+      SilenceDataProvider(const ui16_t numChannels, const ui16_t bitsPerSample,
+                          const ui32_t sampleRate, const ASDCP::Rational& editRate);
+      virtual ~SilenceDataProvider();
+      virtual Result_t PutSample(const ui32_t numChannels, byte_t* buf, ui32_t* bytesWritten);
+      virtual Result_t ReadFrame();
+      virtual Result_t FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const;
+      virtual Result_t Reset();
+  };
+
+} // namespace ASDCP
+
+#endif // _PCMDATAPROVIDERS_H_
+
+//
+// end PCMDataProviders.h
+//
index 3fa6d7d44c5b2ed3b10c6815182f568d790a9ae3..e3b693d6bcf01928b88fc21362e0eeb7483ef1fc 100755 (executable)
@@ -37,6 +37,7 @@ using Kumu::DefaultLogSink;
 using namespace ASDCP;
 using namespace ASDCP::PCM;
 using namespace ASDCP::Wav;
+using namespace ASDCP::RF64;
 
 
 //------------------------------------------------------------------------------------------
@@ -47,8 +48,8 @@ class ASDCP::PCM::WAVParser::h__WAVParser
   Kumu::FileReader m_FileReader;
   bool             m_EOF;
   ui32_t           m_DataStart;
-  ui32_t           m_DataLength;
-  ui32_t           m_ReadCount;
+  ui64_t           m_DataLength;
+  ui64_t           m_ReadCount;
   ui32_t           m_FrameBufferSize;
   ui32_t           m_FramesRead;
   Rational         m_PictureRate;
@@ -129,6 +130,22 @@ ASDCP::PCM::WAVParser::h__WAVParser::OpenRead(const char* filename, const Ration
              m_ADesc.ChannelFormat = PCM::CF_NONE;
              Reset();
            }
+      else
+        {
+          SimpleRF64Header RF64Header;
+          m_FileReader.Seek(0);
+          result = RF64Header.ReadFromFile(m_FileReader, &m_DataStart);
+
+          if ( ASDCP_SUCCESS(result) )
+            {
+                RF64Header.FillADesc(m_ADesc, PictureRate);
+                m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc);
+                m_DataLength = RF64Header.data_len;
+                m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize;
+                m_ADesc.ChannelFormat = PCM::CF_NONE;
+                Reset();
+            }
+        }
        }
     }
 
diff --git a/src/SyncCommon.h b/src/SyncCommon.h
new file mode 100644 (file)
index 0000000..bc5d498
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    SyncCommon.h
+    \version $Id$
+    \brief   Common elements for ATMOS Sync Channel generation
+*/
+
+#ifndef _SYNC_COMMON_H_
+#define _SYNC_COMMON_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef BYTE
+typedef unsigned char BYTE;
+#endif
+
+#ifndef USHORT
+typedef unsigned short USHORT;
+#endif
+
+#ifndef INT
+typedef int INT;
+#endif
+
+#ifndef FLOAT
+typedef float FLOAT;
+#endif
+
+#define SYMBOL_RATE                    (12000)
+
+#define SYMBOL_LENGTH_48       (4)
+#define SYMBOL_LENGTH_96       (8)
+
+#define SYNC_HEADER                    (0x4D56)
+#define SYNC_HEADER1           (0x4D)
+#define SYNC_HEADER2           (0x56)
+
+#define SYNC_HEADER_BITS       (16)
+#define FRAME_RATE_BITS                (4)
+#define RESERVE_BITS           (2)
+#define UUID_SUB_INDEX_BITS    (2)
+#define UUID_SUB_BITS          (32)
+#define FRAME_INDEX_BITS       (24)
+#define CRC_BITS                       (16)
+#define MESSAGE_TOTAL_BITS     (96)
+#define MESSAGE_TOTAL_BYTES (12)
+
+#define MAX_PACKET                     (32)
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/src/SyncEncoder.c b/src/SyncEncoder.c
new file mode 100644 (file)
index 0000000..c553509
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    SyncEncoder.c
+    \version $Id$
+    \brief   Implementation of Atmos Sync Frame Encoder
+*/
+
+#include "SyncEncoder.h"
+#include "CRC16.h"
+
+#include <memory.h>
+
+void ConstructFrame(LPSYNCENCODER      pSyncEncoder,
+                                       INT                             iFrameIndex);
+
+FLOAT SEWriteBits(     INT                     iSampleRate,            /* In:  Sample rate of signal */
+                                       FLOAT           *pfAudioBuffer,         /* Out: Audio buffer containing signal */
+                                       INT                     iBits,                          /* In:  Number of bits to write */
+                                       BYTE            *pbyData,                       /* In:  Data to write */
+                                       FLOAT           fSymbolPhase);          /* In:  Symbol phase */
+
+
+
+INT SyncEncoderInit(LPSYNCENCODER              pSyncEncoder,   /* Out: SYNCENCODER structure to be initialized */
+                                       INT                                     iSampleRate,    /* In:  Signal sample rate */
+                                       INT                                     iFrameRate,             /* In:  frame rate */
+                                       LPUUIDINFORMATION       pUUID)                  /* In:  UUID */
+{
+       pSyncEncoder->iError = SYNC_ENCODER_ERROR_NONE;
+
+       /* Check and set sample rate */
+       pSyncEncoder->iSymbolLength = 1;
+       switch(iSampleRate){
+               case 48000:
+                       pSyncEncoder->iSampleRate = iSampleRate;
+                       pSyncEncoder->iSymbolLength = SYMBOL_LENGTH_48;
+               break;
+               case 96000:
+                       pSyncEncoder->iSampleRate = iSampleRate;
+                       pSyncEncoder->iSymbolLength = SYMBOL_LENGTH_96;
+               break;
+               default:
+                       pSyncEncoder->iError = SYNC_ENCODER_ERROR_INVALID_SR;
+       };
+
+       if(pSyncEncoder->iError != SYNC_ENCODER_ERROR_NONE){
+               return pSyncEncoder->iError;
+       }
+
+       /* check and set frame rate */
+       switch(iFrameRate){
+               case 24:
+                       pSyncEncoder->iFrameRate = iFrameRate;
+                       pSyncEncoder->iFrameRateCode = 0;
+                       pSyncEncoder->iPacketsPerFrame = 4;
+               break;
+               case 25:
+                       pSyncEncoder->iFrameRate = iFrameRate;
+                       pSyncEncoder->iFrameRateCode = 1;
+                       pSyncEncoder->iPacketsPerFrame = 4;
+               break;
+               case 30:
+                       pSyncEncoder->iFrameRate = iFrameRate;
+                       pSyncEncoder->iFrameRateCode = 2;
+                       pSyncEncoder->iPacketsPerFrame = 4;
+               break;
+               case 48:
+                       pSyncEncoder->iFrameRate = iFrameRate;
+                       pSyncEncoder->iFrameRateCode = 3;
+                       pSyncEncoder->iPacketsPerFrame = 2;
+               break;
+               case 50:
+                       pSyncEncoder->iFrameRate = iFrameRate;
+                       pSyncEncoder->iFrameRateCode = 4;
+                       pSyncEncoder->iPacketsPerFrame = 2;
+               break;
+               case 60:
+                       pSyncEncoder->iFrameRate = iFrameRate;
+                       pSyncEncoder->iFrameRateCode = 5;
+                       pSyncEncoder->iPacketsPerFrame = 2;
+               break;
+               case 96:
+                       pSyncEncoder->iFrameRate = iFrameRate;
+                       pSyncEncoder->iFrameRateCode = 6;
+                       pSyncEncoder->iPacketsPerFrame = 1;
+               break;
+               case 100:
+                       pSyncEncoder->iFrameRate = iFrameRate;
+                       pSyncEncoder->iFrameRateCode = 7;
+                       pSyncEncoder->iPacketsPerFrame = 1;
+               break;
+               case 120:
+                       pSyncEncoder->iFrameRate = iFrameRate;
+                       pSyncEncoder->iFrameRateCode = 8;
+                       pSyncEncoder->iPacketsPerFrame = 1;
+               break;
+               default:
+                       pSyncEncoder->iError = SYNC_ENCODER_ERROR_INVALID_FR;
+       };
+
+       if(pSyncEncoder->iError != SYNC_ENCODER_ERROR_NONE){
+               return pSyncEncoder->iError;
+       }
+
+       /* calculate required buffer length */
+       pSyncEncoder->iAudioBufferLength = pSyncEncoder->iSampleRate / pSyncEncoder->iFrameRate;
+
+       /* Calculate total packet bits including wash bits */
+       pSyncEncoder->iPacketBits = pSyncEncoder->iAudioBufferLength / (pSyncEncoder->iSymbolLength * pSyncEncoder->iPacketsPerFrame);
+
+       /* Initialize symbol phase */
+       pSyncEncoder->fSymbolPhase = 1.0f;
+
+       /* Initialize UUD information */
+       pSyncEncoder->iUUIDSubIndex = 0;
+       memcpy(&pSyncEncoder->UUID,pUUID,sizeof(UUIDINFORMATION));
+
+       return pSyncEncoder->iError;
+}
+
+INT GetSyncEncoderAudioBufferLength(LPSYNCENCODER pSyncEncoder)        /* In: Sync encoder structure */
+{
+       if(pSyncEncoder->iError != SYNC_ENCODER_ERROR_NONE){
+               return pSyncEncoder->iError;
+       }
+
+       return pSyncEncoder->iAudioBufferLength;
+}
+
+
+
+INT EncodeSync(        LPSYNCENCODER   pSyncEncoder,   /* In:  Sync encoder structure */
+                               INT                             iBufferLength,  /* In:  Length of audio buffer */
+                               FLOAT                   *pfAudioBuffer, /* Out: Audio buffer with signal */
+                               INT                             iFrameIndex)    /* In:  Frame Index */
+{
+       INT             n;
+       INT             iBufferIndex;
+
+
+       if(pSyncEncoder->iError != SYNC_ENCODER_ERROR_NONE){
+               return pSyncEncoder->iError;
+       }
+       if(iBufferLength != pSyncEncoder->iAudioBufferLength){
+               return SYNC_ENCODER_ERROR_INVALID_BL;
+       }
+
+       iBufferIndex = 0;
+       for(n = 0; n < pSyncEncoder->iPacketsPerFrame; n ++){
+               /* Construct message */
+               ConstructFrame(pSyncEncoder,iFrameIndex);
+
+               /* Write Message */
+               pSyncEncoder->fSymbolPhase = SEWriteBits(pSyncEncoder->iSampleRate,
+                                                                                               &pfAudioBuffer[iBufferIndex],
+                                                                                               pSyncEncoder->iPacketBits,
+                                                                                               pSyncEncoder->abyPacket,
+                                                                                               pSyncEncoder->fSymbolPhase);
+
+               iBufferIndex += (pSyncEncoder->iPacketBits * pSyncEncoder->iSymbolLength);
+
+       }
+
+       return pSyncEncoder->iError;
+}
+
+void ConstructFrame(LPSYNCENCODER      pSyncEncoder,
+                                       INT                             iFrameIndex)
+{
+       USHORT  ushCRC;
+       BYTE    byByte;
+       INT             iUUIDIndex;
+
+       /* Flush the packet buffer */
+       memset(pSyncEncoder->abyPacket,0,MAX_PACKET);
+
+       /* Sync Header */
+       pSyncEncoder->abyPacket[0] = SYNC_HEADER1;
+       pSyncEncoder->abyPacket[1] = SYNC_HEADER2;
+
+       /* Frame Rate code */
+       byByte = 0;
+       byByte = (unsigned char)(pSyncEncoder->iFrameRateCode << 4);
+
+       /* UUID sub index */
+       byByte |= (unsigned char)(pSyncEncoder->iUUIDSubIndex & 0x3);
+
+       pSyncEncoder->abyPacket[2] = byByte;
+
+       /* UUID Sub */
+       iUUIDIndex = pSyncEncoder->iUUIDSubIndex << 2;
+       pSyncEncoder->abyPacket[3] = pSyncEncoder->UUID.abyUUIDBytes[iUUIDIndex];
+       pSyncEncoder->abyPacket[4] = pSyncEncoder->UUID.abyUUIDBytes[iUUIDIndex + 1];
+       pSyncEncoder->abyPacket[5] = pSyncEncoder->UUID.abyUUIDBytes[iUUIDIndex + 2];
+       pSyncEncoder->abyPacket[6] = pSyncEncoder->UUID.abyUUIDBytes[iUUIDIndex + 3];
+
+       /* Update UUID sub index */
+       pSyncEncoder->iUUIDSubIndex ++;
+       pSyncEncoder->iUUIDSubIndex &= 0x3;
+
+       /* Frame Index */
+       byByte = (unsigned char)((iFrameIndex >> 16) & 0XFF);
+       pSyncEncoder->abyPacket[7] = byByte;
+       byByte = (unsigned char)((iFrameIndex >> 8) & 0XFF);
+       pSyncEncoder->abyPacket[8] = byByte;
+       byByte = (unsigned char)(iFrameIndex & 0XFF);
+       pSyncEncoder->abyPacket[9] = byByte;
+
+       /* calculate CRC */
+       ushCRC = CRC16(&pSyncEncoder->abyPacket[2],MESSAGE_TOTAL_BYTES - 4);
+
+       /* Insert CRC */
+       byByte = (unsigned char)((ushCRC >> 8) & 0XFF);
+       pSyncEncoder->abyPacket[10] = byByte;
+       byByte = (unsigned char)(ushCRC & 0XFF);
+       pSyncEncoder->abyPacket[11] = byByte;
+
+}
+
+static FLOAT g_afSymbol0_48[SYMBOL_LENGTH_48] = {
+       0.3827f,
+    0.9239f,
+    0.9239f,
+    0.3827f,
+};
+
+static FLOAT g_afSymbol1_48[SYMBOL_LENGTH_48] = {
+       0.7071f,
+    0.7071f,
+   -0.7071f,
+   -0.7071f,
+};
+
+static FLOAT g_afSymbol0_96[SYMBOL_LENGTH_96] = {
+       0.1951f,
+    0.5556f,
+    0.8315f,
+    0.9808f,
+    0.9808f,
+    0.8315f,
+    0.5556f,
+    0.1951f,
+};
+
+static FLOAT g_afSymbol1_96[SYMBOL_LENGTH_96] = {
+       0.3827f,
+    0.9239f,
+    0.9239f,
+    0.3827f,
+   -0.3827f,
+   -0.9239f,
+   -0.9239f,
+   -0.3827f,
+};
+
+/* Symbol gain */
+static FLOAT g_fGain = 0.1f;
+
+FLOAT SEWriteBits(     INT                     iSampleRate,            /* In:  Sample rate of signal */
+                                       FLOAT           *pfAudioBuffer,         /* Out: Audio buffer containing signal */
+                                       INT                     iBits,                          /* In:  Number of bits to write */
+                                       BYTE            *pbyData,                       /* In:  Data to write */
+                                       FLOAT           fSymbolPhase)           /* In:  Symbol phase */
+{
+       INT             n;
+       INT             i;
+       INT             iSymbolLength;
+       FLOAT   *pfSymbol0;
+       FLOAT   *pfSymbol1;
+       BYTE    byByte;
+
+       /* Select the correct symbol length and symbol signal based on sample rate */
+       switch (iSampleRate){
+               case 96000:
+                       iSymbolLength = SYMBOL_LENGTH_96;
+                       pfSymbol0 = g_afSymbol0_96;
+                       pfSymbol1 = g_afSymbol1_96;
+               break;
+               case 48000:
+                       iSymbolLength = SYMBOL_LENGTH_48;
+                       pfSymbol0 = g_afSymbol0_48;
+                       pfSymbol1 = g_afSymbol1_48;
+               break;
+               default:
+                       iSymbolLength = 0;
+                       pfSymbol0 = g_afSymbol0_96;
+                       pfSymbol1 = g_afSymbol1_96;
+       };
+
+       /* Write bits */
+       n = 0;
+       i = 0;
+       while(n < iBits){
+               INT             k;
+               FLOAT   *pfSymbol;
+
+               /* Grab next byte of data */
+               if(i == 0){
+                       byByte = *pbyData;
+                       pbyData ++;
+               }
+
+               pfSymbol = (byByte & 0x80) ? pfSymbol1 : pfSymbol0;
+
+               for(k = 0; k < iSymbolLength; k ++){
+                       *pfAudioBuffer =  *pfSymbol * fSymbolPhase * g_fGain;
+                       pfAudioBuffer ++;
+                       pfSymbol ++;
+               }
+
+               fSymbolPhase *= (byByte & 0x80) ? 1.0f : -1.0f;
+
+               byByte <<= 1;
+
+               n ++;
+
+               i ++;
+               i &= 0x7;
+       }
+
+       return fSymbolPhase;
+}
diff --git a/src/SyncEncoder.h b/src/SyncEncoder.h
new file mode 100644 (file)
index 0000000..4b97f5a
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    SyncEncoder.h
+    \version $Id$
+    \brief   Declaration of Atmos Sync Frame Encoder
+*/
+
+#ifndef _SYNC_ENCODER_H_
+#define _SYNC_ENCODER_H_
+
+#include "SyncCommon.h"
+#include "UUIDInformation.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct SyncEncoder{
+       INT                             iSampleRate;                    /* Signal sample rate */
+       INT                             iSymbolLength;                  /* Symbol Length */
+       INT                             iFrameRate;                             /* Frame rate */
+       INT                             iFrameRateCode;                 /* Frame rate code */
+       INT                             iAudioBufferLength;             /* Length of audio buffer */
+       INT                             iPacketBits;                    /* Bits in each packet includes wash bits */
+       INT                             iPacketsPerFrame;               /* Number of packets per frame */
+       FLOAT                   fSymbolPhase;                   /* Symbol phase */
+
+       INT                             iUUIDSubIndex;                  /* UUID transmission sub index */
+       UUIDINFORMATION UUID;                                   /* UUID */
+
+       BYTE                    abyPacket[MAX_PACKET];
+
+       INT                             iError;                                 /* Error state */
+}SYNCENCODER,*LPSYNCENCODER;
+
+enum{
+       SYNC_ENCODER_ERROR_NONE = 0,                    /* No error */
+       SYNC_ENCODER_ERROR_INVALID_SR = -1,             /* Invalid sample rate */
+       SYNC_ENCODER_ERROR_INVALID_FR = -2,             /* Invalid frame rate */
+       SYNC_ENCODER_ERROR_INVALID_BL = -10,    /* Buffer length is incorrect */
+       SYNC_ENCODER_ERROR_UNKNOWN = -100,              /* Unknown */
+};
+
+
+INT SyncEncoderInit(LPSYNCENCODER              pSyncEncoder,   /* Out: SYNCENCODER structure to be initialized */
+                                       INT                                     iSampleRate,    /* In:  Signal sample rate */
+                                       INT                                     iFrameRate,             /* In:  frame rate */
+                                       LPUUIDINFORMATION       pUUID);                 /* In:  UUID */
+
+INT GetSyncEncoderAudioBufferLength(LPSYNCENCODER pSyncEncoder);
+
+INT EncodeSync(        LPSYNCENCODER   pSyncEncoder,   /* In:  Sync encoder structure */
+                               INT                             iBufferLength,  /* In:  Length of audio buffer */
+                               FLOAT                   *pfAudioBuffer, /* Out: Audio buffer with signal */
+                               INT                             iFrameIndex);   /* In:  Frame Index */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
+
diff --git a/src/UUIDInformation.c b/src/UUIDInformation.c
new file mode 100644 (file)
index 0000000..4c5eec9
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    SyncEncoder.h
+    \version $Id$
+    \brief   Implementation of Atmos Sync UUID
+*/
+
+#include "UUIDInformation.h"
+#include <stdlib.h>
+
+
+void UUIDSynthesize(LPUUIDINFORMATION pUUID)
+{
+       INT n;
+
+       for(n = 0; n < 16; n ++){
+               pUUID->abyUUIDBytes[n] = (BYTE)(rand() & 0xFF);
+       }
+
+       pUUID->abyUUIDBytes[6] &= 0x0F;
+       pUUID->abyUUIDBytes[6] |= 0x40;
+
+       pUUID->abyUUIDBytes[8] &= 0x0F;
+       pUUID->abyUUIDBytes[8] |= 0xA0;
+}
+
+void UUIDPrint(        FILE                            *pFilePtr,
+                               LPUUIDINFORMATION       pUUID)
+{
+       if(pFilePtr != NULL){
+               INT n;
+
+               for(n = 0; n < 16; n ++){
+                       fprintf(pFilePtr,"%02x",pUUID->abyUUIDBytes[n]);
+               }
+       }
+       else{
+               INT n;
+
+               for(n = 0; n < 16; n ++){
+                       fprintf(stdout,"%02x",pUUID->abyUUIDBytes[n]);
+               }
+       }
+}
+
+void UUIDPrintFormated(        FILE                            *pFilePtr,
+                                               LPUUIDINFORMATION       pUUID)
+{
+       if(pFilePtr != NULL){
+               INT n;
+
+               for(n = 0; n < 4; n ++){
+                       fprintf(pFilePtr,"%02x",pUUID->abyUUIDBytes[n]);
+               }
+               fprintf(pFilePtr,"-");
+               for(n = 4; n < 6; n ++){
+                       fprintf(pFilePtr,"%02x",pUUID->abyUUIDBytes[n]);
+               }
+               fprintf(pFilePtr,"-");
+               for(n = 6; n < 8; n ++){
+                       fprintf(pFilePtr,"%02x",pUUID->abyUUIDBytes[n]);
+               }
+               fprintf(pFilePtr,"-");
+               for(n = 8; n < 10; n ++){
+                       fprintf(pFilePtr,"%02x",pUUID->abyUUIDBytes[n]);
+               }
+               fprintf(pFilePtr,"-");
+               for(n = 10; n < 16; n ++){
+                       fprintf(pFilePtr,"%02x",pUUID->abyUUIDBytes[n]);
+               }
+       }
+       else{
+               INT n;
+
+               for(n = 0; n < 4; n ++){
+                       fprintf(stdout,"%02x",pUUID->abyUUIDBytes[n]);
+               }
+               fprintf(stdout,"-");
+               for(n = 4; n < 6; n ++){
+                       fprintf(stdout,"%02x",pUUID->abyUUIDBytes[n]);
+               }
+               fprintf(stdout,"-");
+               for(n = 6; n < 8; n ++){
+                       fprintf(stdout,"%02x",pUUID->abyUUIDBytes[n]);
+               }
+               fprintf(stdout,"-");
+               for(n = 8; n < 10; n ++){
+                       fprintf(stdout,"%02x",pUUID->abyUUIDBytes[n]);
+               }
+               fprintf(stdout,"-");
+               for(n = 10; n < 16; n ++){
+                       fprintf(stdout,"%02x",pUUID->abyUUIDBytes[n]);
+               }
+       }
+}
diff --git a/src/UUIDInformation.h b/src/UUIDInformation.h
new file mode 100644 (file)
index 0000000..4bd0ff4
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+Copyright (c) 2013-2013, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file    SyncEncoder.h
+    \version $Id$
+    \brief   Declaration of Atmos Sync UUID
+*/
+
+#ifndef _UUID_INFORMATION_H_
+#define _UUID_INFORMATION_H_
+
+#include "SyncCommon.h"
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct UUIInformation{
+       BYTE abyUUIDBytes[16];
+} UUIDINFORMATION,*LPUUIDINFORMATION;
+
+void UUIDSynthesize(LPUUIDINFORMATION pUUID);
+
+void UUIDPrint(        FILE                            *pFilePtr,
+                               LPUUIDINFORMATION       pUUID);
+
+void UUIDPrintFormated(        FILE                            *pFilePtr,
+                                               LPUUIDINFORMATION       pUUID);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
index 7275ab95cfa186f1870cd06e1c54637792b0e128..0f148500d7759bbf37f8f884b0c1ba462a574406 100755 (executable)
@@ -44,7 +44,7 @@ ASDCP::Wav::SimpleWaveHeader::SimpleWaveHeader(ASDCP::PCM::AudioDescriptor& ADes
   nchannels = ADesc.ChannelCount;
   bitspersample = ADesc.QuantizationBits;
   samplespersec = (ui32_t)ceil(ADesc.AudioSamplingRate.Quotient());
-  blockalign = nchannels * (bitspersample / 8);
+  blockalign = nchannels * ((bitspersample + 7) / 8);
   avgbps = samplespersec * blockalign;
   cbsize = 0;    
   data_len = ASDCP::PCM::CalcFrameBufferSize(ADesc) * ADesc.ContainerDuration;
@@ -363,7 +363,230 @@ ASDCP::AIFF::SimpleAIFFHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len,
   return RESULT_OK;
 }
 
+ASDCP::RF64::SimpleRF64Header::SimpleRF64Header(ASDCP::PCM::AudioDescriptor& ADesc)
+{
+  format = 1;
+  nchannels = ADesc.ChannelCount;
+  bitspersample = ADesc.QuantizationBits;
+  samplespersec = (ui32_t)ceil(ADesc.AudioSamplingRate.Quotient());
+  blockalign = nchannels * ((bitspersample + 7) / 8);
+  avgbps = samplespersec * blockalign;
+  data_len = ASDCP::PCM::CalcFrameBufferSize(ADesc) * ADesc.ContainerDuration;
+}
+
+//
+void
+ASDCP::RF64::SimpleRF64Header::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const
+{
+  ADesc.EditRate = PictureRate;
+
+  ADesc.LinkedTrackID = 0;
+  ADesc.Locked = 0;
+  ADesc.ChannelCount = nchannels;
+  ADesc.AudioSamplingRate = Rational(samplespersec, 1);
+  ADesc.AvgBps = avgbps;
+  ADesc.BlockAlign = blockalign;
+  ADesc.QuantizationBits = bitspersample;
+  ui32_t FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(ADesc);
+  ADesc.ContainerDuration = data_len / FrameBufferSize;
+  ADesc.ChannelFormat = PCM::CF_NONE;
+}
+
+//
+ASDCP::Result_t
+ASDCP::RF64::SimpleRF64Header::WriteToFile(Kumu::FileWriter& OutFile) const
+{
+  static ui32_t fmt_len =
+    sizeof(format)
+    + sizeof(nchannels)
+    + sizeof(samplespersec)
+    + sizeof(avgbps)
+    + sizeof(blockalign)
+    + sizeof(bitspersample);
+
+  ui32_t write_count = 0;
+  ui64_t RIFF_len = data_len + SimpleWavHeaderLength - 8;
+  DefaultLogSink().Debug("RIFF_len is %llu.\n", RIFF_len);
+  byte_t* tmp_header = NULL;
+  ui32_t header_len = 0;
+
+  if (RIFF_len > MAX_RIFF_LEN)
+  {
+    DefaultLogSink().Debug("Will write out an RF64 wave file.\n");
+    ui32_t data32_len = ((data_len < MAX_RIFF_LEN) ? data_len : MAX_RIFF_LEN);
+    ui64_t data64_len = ((data_len < MAX_RIFF_LEN) ? 0 : data_len);
+    static ui32_t ds64_len =
+            sizeof(RIFF_len)
+            + sizeof(data64_len)
+            + sizeof(SAMPLE_COUNT)
+            + sizeof(TABLE_LEN);
+
+    header_len = SIMPLE_RF64_HEADER_LEN;
+    tmp_header = new byte_t[header_len];
+    byte_t* p = tmp_header;
+    memcpy(p, &FCC_RF64, sizeof(fourcc)); p += 4;
+    *((ui32_t*)p) = KM_i32_LE(MAX_RIFF_LEN); p += 4;
+    memcpy(p, &Wav::FCC_WAVE, sizeof(fourcc)); p += 4;
+    memcpy(p, &FCC_ds64, sizeof(fourcc)); p += 4;
+    *((ui32_t*)p) = KM_i32_LE(ds64_len); p += 4;
+    *((ui64_t*)p) = KM_i64_LE(RIFF_len); p += 8;
+    *((ui64_t*)p) = KM_i64_LE(data64_len); p += 8;
+    *((ui64_t*)p) = KM_i64_LE(SAMPLE_COUNT); p += 8;
+    *((ui32_t*)p) = KM_i32_LE(TABLE_LEN); p += 4;
+    memcpy(p, &Wav::FCC_fmt_, sizeof(fourcc)); p += 4;
+    *((ui32_t*)p) = KM_i32_LE(fmt_len); p += 4;
+    *((ui16_t*)p) = KM_i16_LE(format); p += 2;
+    *((ui16_t*)p) = KM_i16_LE(nchannels); p += 2;
+    *((ui32_t*)p) = KM_i32_LE(samplespersec); p += 4;
+    *((ui32_t*)p) = KM_i32_LE(avgbps); p += 4;
+    *((ui16_t*)p) = KM_i16_LE(blockalign); p += 2;
+    *((ui16_t*)p) = KM_i16_LE(bitspersample); p += 2;
+    memcpy(p, &Wav::FCC_data, sizeof(fourcc)); p += 4;
+    *((ui32_t*)p) = KM_i32_LE(data32_len); p += 4;
+    write_count = (p - tmp_header);
+  }
+  else
+  {
+    DefaultLogSink().Debug("Will write out a regular wave file.\n");
+    header_len = SimpleWavHeaderLength;
+    tmp_header = new byte_t[header_len];
+    byte_t* p = tmp_header;
+    memcpy(p, &Wav::FCC_RIFF, sizeof(fourcc)); p += 4;
+    *((ui32_t*)p) = KM_i32_LE(RIFF_len); p += 4;
+    memcpy(p, &Wav::FCC_WAVE, sizeof(fourcc)); p += 4;
+    memcpy(p, &Wav::FCC_fmt_, sizeof(fourcc)); p += 4;
+    *((ui32_t*)p) = KM_i32_LE(fmt_len); p += 4;
+    *((ui16_t*)p) = KM_i16_LE(format); p += 2;
+    *((ui16_t*)p) = KM_i16_LE(nchannels); p += 2;
+    *((ui32_t*)p) = KM_i32_LE(samplespersec); p += 4;
+    *((ui32_t*)p) = KM_i32_LE(avgbps); p += 4;
+    *((ui16_t*)p) = KM_i16_LE(blockalign); p += 2;
+    *((ui16_t*)p) = KM_i16_LE(bitspersample); p += 2;
+    memcpy(p, &Wav::FCC_data, sizeof(fourcc)); p += 4;
+    *((ui32_t*)p) = KM_i32_LE(data_len); p += 4;
+    write_count = (p - tmp_header);
+  }
+  if (header_len != write_count)
+  {
+      DefaultLogSink().Warn("Expected to write %u bytes but wrote %u bytes for header.\n",
+                            header_len, write_count);
+  }
+  write_count = 0;
+  ASDCP::Result_t r = OutFile.Write(tmp_header, header_len, &write_count);
+  delete [] tmp_header;
+  return r;
+}
+
+//
+ASDCP::Result_t
+ASDCP::RF64::SimpleRF64Header::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start)
+{
+  ui32_t read_count = 0;
+  ui32_t local_data_start = 0;
+  ASDCP::PCM::FrameBuffer TmpBuffer(Wav::MaxWavHeader);
 
+  if ( data_start == 0 )
+    data_start = &local_data_start;
+
+  Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count);
+
+  if ( ASDCP_SUCCESS(result) )
+    result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start);
+  else
+    DefaultLogSink().Error("Failed to read %d bytes from file\n", Wav::MaxWavHeader);
+
+    return result;
+}
+
+ASDCP::Result_t
+ASDCP::RF64::SimpleRF64Header::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start)
+{
+    if ( buf_len < SIMPLE_RF64_HEADER_LEN )
+        return RESULT_SMALLBUF;
+
+    *data_start = 0;
+    const byte_t* p = buf;
+    const byte_t* end_p = p + buf_len;
+
+    fourcc test_RF64(p); p += 4;
+    if ( test_RF64 != FCC_RF64 )
+    {
+        DefaultLogSink().Debug("File does not begin with RF64 header\n");
+        return RESULT_RAW_FORMAT;
+    }
+
+    ui32_t tmp_len = KM_i32_LE(*(ui32_t*)p); p += 4;
+
+    fourcc test_WAVE(p); p += 4;
+    if ( test_WAVE != Wav::FCC_WAVE )
+    {
+        DefaultLogSink().Debug("File does not contain a WAVE header\n");
+        return RESULT_RAW_FORMAT;
+    }
+
+    fourcc test_ds64(p); p += 4;
+    if ( test_ds64 != FCC_ds64 )
+    {
+        DefaultLogSink().Debug("File does not contain a ds64 chunk\n");
+        return RESULT_RAW_FORMAT;
+    }
+    ui32_t ds64_len = KM_i32_LE(*(ui32_t*)p); p += 4;
+    ui64_t RIFF_len = ((tmp_len == MAX_RIFF_LEN) ? KM_i64_LE(*(ui64_t*)p) : tmp_len); p += 8;
+    data_len = KM_i64_LE(*(ui64_t*)p); p += 8;
+    p += (ds64_len - 16); // skip rest of ds64 chunk
+
+    fourcc test_fcc;
+
+    while ( p < end_p )
+    {
+        test_fcc = fourcc(p); p += 4;
+        ui32_t chunk_size = KM_i32_LE(*(ui32_t*)p); p += 4;
+
+        if ( test_fcc == Wav::FCC_data )
+        {
+            if ( chunk_size > RIFF_len )
+            {
+                DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len);
+                return RESULT_RAW_FORMAT;
+            }
+
+            if (chunk_size != MAX_RIFF_LEN)
+                data_len = chunk_size;
+            *data_start = p - buf;
+            break;
+        }
+
+        if ( test_fcc == Wav::FCC_fmt_ )
+        {
+            ui16_t format = KM_i16_LE(*(ui16_t*)p); p += 2;
+
+            if ( format != Wav::WAVE_FORMAT_PCM && format != Wav::WAVE_FORMAT_EXTENSIBLE )
+            {
+                DefaultLogSink().Error("Expecting uncompressed PCM data, got format type %hd\n", format);
+                return RESULT_RAW_FORMAT;
+            }
+
+            nchannels = KM_i16_LE(*(ui16_t*)p); p += 2;
+            samplespersec = KM_i32_LE(*(ui32_t*)p); p += 4;
+            avgbps = KM_i32_LE(*(ui32_t*)p); p += 4;
+            blockalign = KM_i16_LE(*(ui16_t*)p); p += 2;
+            bitspersample = KM_i16_LE(*(ui16_t*)p); p += 2;
+            p += chunk_size - 16; // 16 is the number of bytes read in this block
+        }
+        else
+        {
+            p += chunk_size;
+        }
+    }
+
+    if ( *data_start == 0 ) // can't have no data!
+    {
+        DefaultLogSink().Error("No data chunk found, file contains no essence\n");
+        return RESULT_RAW_FORMAT;
+    }
+
+  return RESULT_OK;
+}
 
 //
 // end Wav.cpp
index ef9c4e20870786a6e508ae45012e2598356e00ce..d2a97895e7380885450a0cb856d819173ae215d6 100755 (executable)
--- a/src/Wav.h
+++ b/src/Wav.h
@@ -118,6 +118,45 @@ namespace ASDCP
        };
 
     } // namespace Wav
+
+  namespace RF64
+    {
+      const fourcc FCC_RF64("RF64");
+      const fourcc FCC_ds64("ds64");
+
+
+      static const ui32_t MAX_RIFF_LEN = 0xFFFFFFFF;
+      static const ui32_t DS64_HEADER_LEN = 28;
+      static const ui32_t SIMPLE_RF64_HEADER_LEN = 80;
+      //
+      class SimpleRF64Header
+       {
+       public:
+         ui16_t        format;
+         ui16_t        nchannels;
+         ui32_t        samplespersec;
+         ui32_t        avgbps;
+         ui16_t        blockalign;
+         ui16_t        bitspersample;
+         ui64_t        data_len;
+
+         SimpleRF64Header() :
+           format(0), nchannels(0), samplespersec(0), avgbps(0),
+           blockalign(0), bitspersample(0), data_len(0) {}
+
+         SimpleRF64Header(ASDCP::PCM::AudioDescriptor& ADesc);
+
+         Result_t  ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start);
+         Result_t  ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start);
+         Result_t  WriteToFile(Kumu::FileWriter& OutFile) const;
+         void      FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, Rational PictureRate) const;
+
+    private:
+      static const ui64_t SAMPLE_COUNT = 0;
+      static const ui32_t TABLE_LEN = 0;
+       };
+
+    } // namespace RF64
 } // namespace ASDCP
 
 #endif // _WAV_H_
index 3febc2325afee15ee5ad2cdfd7188ff555180c28..9611adc05adb6c53a6341df6d242d110d606c02d 100755 (executable)
@@ -136,22 +136,36 @@ class WavFileWriter
       assert(file_count && m_ChannelCount);
 
       ui32_t element_size = ASDCP::PCM::CalcFrameBufferSize(m_ADesc) / file_count;
-
-      for ( ui32_t i = 0; i < file_count && ASDCP_SUCCESS(result); i++ )
-       {
-         snprintf(filename, Kumu::MaxFilePath, "%s_%u.wav", file_root, (i + 1));
-         m_OutFile.push_back(new WavFileElement(element_size));
-         result = m_OutFile.back()->OpenWrite(filename);
-
-         if ( ASDCP_SUCCESS(result) )
-           {
-             ASDCP::PCM::AudioDescriptor tmpDesc = m_ADesc;
-             tmpDesc.ChannelCount = m_ChannelCount;
-             ASDCP::Wav::SimpleWaveHeader Wav(tmpDesc);
-             result = Wav.WriteToFile(*(m_OutFile.back()));
-           }
-       }
-      
+      if (split == ST_NONE)
+      {
+          snprintf(filename, Kumu::MaxFilePath, "%s", file_root);
+          m_OutFile.push_back(new WavFileElement(element_size));
+          result = m_OutFile.back()->OpenWrite(filename);
+          if ( ASDCP_SUCCESS(result) )
+          {
+              ASDCP::PCM::AudioDescriptor tmpDesc = m_ADesc;
+              tmpDesc.ChannelCount = m_ChannelCount;
+              ASDCP::RF64::SimpleRF64Header Wav(tmpDesc);
+              result = Wav.WriteToFile(*(m_OutFile.back()));
+          }
+      }
+      else
+      {
+          for ( ui32_t i = 0; i < file_count && ASDCP_SUCCESS(result); i++ )
+          {
+              snprintf(filename, Kumu::MaxFilePath, "%s_%u.wav", file_root, (i + 1));
+              m_OutFile.push_back(new WavFileElement(element_size));
+              result = m_OutFile.back()->OpenWrite(filename);
+
+              if ( ASDCP_SUCCESS(result) )
+              {
+                  ASDCP::PCM::AudioDescriptor tmpDesc = m_ADesc;
+                  tmpDesc.ChannelCount = m_ChannelCount;
+                  ASDCP::RF64::SimpleRF64Header Wav(tmpDesc);
+                  result = Wav.WriteToFile(*(m_OutFile.back()));
+              }
+          }
+      }
       return result;
     }
 
index 05e2c79a353a93c9928bf764256cf6ccd7d1dc01..cbc43811b4234b797d3b20d6f19d13184f304603 100755 (executable)
@@ -25,7 +25,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 /*! \file    asdcp-info.cpp
-    \version $Id$       
+    \version $Id$
     \brief   AS-DCP file metadata utility
 
   This program provides metadata information about an AS-DCP file.
@@ -125,7 +125,7 @@ public:
   bool   stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first)
   bool   showid_flag;          // if true, show file identity info (the WriterInfo struct)
   bool   showdescriptor_flag;  // if true, show the essence descriptor
-  bool   showcoding_flag;      // if true, show the coding UL 
+  bool   showcoding_flag;      // if true, show the coding UL
   bool   showrate_flag;        // if true and is image file, show bit rate
   bool   max_bitrate_flag;     // true if -t option given
   double max_bitrate;          // if true and is image file, max bit rate for rate test
@@ -145,7 +145,7 @@ public:
            help_flag = true;
            continue;
          }
-         
+
        if ( argv[i][0] == '-'
             && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
             && argv[i][2] == 0 )
@@ -191,7 +191,7 @@ public:
 
     if ( help_flag || version_flag )
       return;
-    
+
     if ( filenames.empty() )
       {
        fputs("At least one filename argument is required.\n", stderr);
@@ -270,6 +270,30 @@ class MyTextDescriptor : public TimedText::TimedTextDescriptor
   }
 };
 
+class MyDCDataDescriptor : public DCData::DCDataDescriptor
+{
+ public:
+  void FillDescriptor(DCData::MXFReader& Reader) {
+    Reader.FillDCDataDescriptor(*this);
+  }
+
+  void Dump(FILE* stream) {
+      DCData::DCDataDescriptorDump(*this, stream);
+  }
+};
+
+class MyAtmosDescriptor : public ATMOS::AtmosDescriptor
+{
+ public:
+  void FillDescriptor(ATMOS::MXFReader& Reader) {
+    Reader.FillAtmosDescriptor(*this);
+  }
+
+  void Dump(FILE* stream) {
+      ATMOS::AtmosDescriptorDump(*this, stream);
+  }
+};
+
 //
 //
 template<class ReaderT, class DescriptorT>
@@ -333,7 +357,7 @@ public:
 
     Result_t result = m_Reader.OPAtomHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_RGBAEssenceDescriptor),
                                                                reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
-    
+
     if ( KM_SUCCESS(result) )
       m_PictureEssenceCoding = descriptor->PictureEssenceCoding;
   }
@@ -489,7 +513,7 @@ public:
 
     Result_t result = m_Reader.OPAtomHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_WaveAudioDescriptor),
                                                                reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
-    
+
     if ( KM_SUCCESS(result) )
       {
        char buf[64];
@@ -572,7 +596,7 @@ show_file_info(CommandOptions& Options)
     {
       FileInfoWrapper<ASDCP::JP2K::MXFSReader, MyStereoPictureDescriptor>wrapper;
       result = wrapper.file_info(Options, "JPEG 2000 stereoscopic pictures");
-      
+
       if ( KM_SUCCESS(result) )
        {
          wrapper.get_PictureEssenceCoding();
@@ -592,6 +616,16 @@ show_file_info(CommandOptions& Options)
       FileInfoWrapper<ASDCP::TimedText::MXFReader, MyTextDescriptor>wrapper;
       result = wrapper.file_info(Options, "Timed Text");
     }
+  else if ( EssenceType == ESS_DCDATA_UNKNOWN )
+    {
+      FileInfoWrapper<ASDCP::DCData::MXFReader, MyDCDataDescriptor> wrapper;
+      result = wrapper.file_info(Options, "D-Cinema Generic Data");
+    }
+  else if ( EssenceType == ESS_DCDATA_DOLBY_ATMOS )
+    {
+      FileInfoWrapper<ASDCP::ATMOS::MXFReader, MyAtmosDescriptor> wrapper;
+      result = wrapper.file_info(Options, "Dolby ATMOS");
+    }
   else
     {
       fprintf(stderr, "File is not AS-DCP: %s\n", Options.filenames.front().c_str());
index e9b9feeada1f6869bf9ef3fddeb6df237241fdd1..7b8654bbda68c7ff4b6c9cdb8ea29d90578e80a2 100755 (executable)
@@ -25,7 +25,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 /*! \file    asdcp-unwrap.cpp
-    \version $Id$       
+    \version $Id$
     \brief   AS-DCP file manipulation utility
 
   This program extracts picture, sound and text essence from AS-DCP files.
@@ -92,7 +92,8 @@ Options:\n\
   -b <buffer-size>  - Specify size in bytes of picture frame buffer\n\
                       Defaults to 4,194,304 (4MB)\n\
   -d <duration>     - Number of frames to process, default all\n\
-  -f <start-frame>  - Starting frame number, default 0\n\
+  -e <extension>    - Extension to use for Unknown D-Cinema Data files. default dcdata\n\
+  -f <start-frame>  - Starting frame number, default 0\n                \
   -G                - Perform GOP start lookup test on MXF+Interop MPEG file\n\
   -h | -help        - Show help\n\
   -k <key-string>   - Use key for ciphertext operations\n\
@@ -153,6 +154,7 @@ public:
   PCM::ChannelFormat_t channel_fmt; // audio channel arrangement
   const char* input_filename;
   std::string prefix_buffer;
+  const char* extension; // file extension to use for unknown D-Cinema Data track files.
 
   //
   Rational PictureRate()
@@ -181,7 +183,7 @@ public:
     version_flag(false), help_flag(false), stereo_image_flag(false), number_width(6),
     start_frame(0), duration(0xffffffff), duration_flag(false), j2c_pedantic(true),
     picture_rate(24), fb_size(FRAME_BUFFER_SIZE), file_prefix(0),
-    channel_fmt(PCM::CF_NONE), input_filename(0)
+    channel_fmt(PCM::CF_NONE), input_filename(0), extension("dcdata")
   {
     memset(key_value, 0, KeyLen);
     memset(key_id_value, 0, UUIDlen);
@@ -194,7 +196,7 @@ public:
            help_flag = true;
            continue;
          }
-         
+
        if ( argv[i][0] == '-'
             && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
             && argv[i][2] == 0 )
@@ -216,6 +218,11 @@ public:
                duration = abs(atoi(argv[i]));
                break;
 
+          case 'e':
+            TEST_EXTRA_ARG(i, 'e');
+            extension = argv[i];
+            break;
+
              case 'f':
                TEST_EXTRA_ARG(i, 'f');
                start_frame = abs(atoi(argv[i]));
@@ -224,6 +231,20 @@ public:
              case 'G': mode = MMT_GOP_START; break;
              case 'h': help_flag = true; break;
 
+             case 'k': key_flag = true;
+               TEST_EXTRA_ARG(i, 'k');
+               {
+                 ui32_t length;
+                 Kumu::hex2bin(argv[i], key_value, KeyLen, &length);
+
+                 if ( length != KeyLen )
+                   {
+                     fprintf(stderr, "Unexpected key length: %u, expecting %u characters.\n", length, KeyLen);
+                     return;
+                   }
+               }
+               break;
+
              case 'm': read_hmac = true; break;
 
              case 'p':
@@ -276,7 +297,7 @@ public:
 
     if ( help_flag || version_flag )
       return;
-    
+
     if ( (  mode == MMT_EXTRACT || mode == MMT_GOP_START ) && input_filename == 0 )
       {
        fputs("Option requires at least one filename argument.\n", stderr);
@@ -369,11 +390,11 @@ read_MPEG2_file(CommandOptions& Options)
 
          if ( ! Options.no_write_flag )
            {
-             ui32_t write_count = 0;
-             result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
-           }
+         ui32_t write_count = 0;
+         result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
        }
     }
+    }
 
   return result;
 }
@@ -499,13 +520,13 @@ read_JP2K_S_file(CommandOptions& Options)
        {
          if ( ! Options.no_write_flag )
            {
-             Kumu::FileWriter OutFile;
-             ui32_t write_count;
-             snprintf(filename, filename_max, left_format, Options.file_prefix, i);
-             result = OutFile.OpenWrite(filename);
+         Kumu::FileWriter OutFile;
+         ui32_t write_count;
+         snprintf(filename, filename_max, left_format, Options.file_prefix, i);
+         result = OutFile.OpenWrite(filename);
 
-             if ( ASDCP_SUCCESS(result) )
-               result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+         if ( ASDCP_SUCCESS(result) )
+           result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
            }
 
          if ( Options.verbose_flag )
@@ -519,18 +540,18 @@ read_JP2K_S_file(CommandOptions& Options)
        {
          if ( ! Options.no_write_flag )
            {
-             Kumu::FileWriter OutFile;
-             ui32_t write_count;
-             snprintf(filename, filename_max, right_format, Options.file_prefix, i);
-             result = OutFile.OpenWrite(filename);
+         Kumu::FileWriter OutFile;
+         ui32_t write_count;
+         snprintf(filename, filename_max, right_format, Options.file_prefix, i);
+         result = OutFile.OpenWrite(filename);
 
-             if ( ASDCP_SUCCESS(result) )
-               result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
-           }
+         if ( ASDCP_SUCCESS(result) )
+           result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+       }
 
          if ( Options.verbose_flag )
            FrameBuffer.Dump(stderr, Options.fb_dump_size);
-       }
+    }
     }
 
   return result;
@@ -602,14 +623,14 @@ read_JP2K_file(CommandOptions& Options)
        {
          if ( ! Options.no_write_flag )
            {
-             Kumu::FileWriter OutFile;
-             char filename[256];
-             ui32_t write_count;
-             snprintf(filename, 256, name_format, Options.file_prefix, i);
-             result = OutFile.OpenWrite(filename);
-
-             if ( ASDCP_SUCCESS(result) )
-               result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+         Kumu::FileWriter OutFile;
+         char filename[256];
+         ui32_t write_count;
+         snprintf(filename, 256, name_format, Options.file_prefix, i);
+         result = OutFile.OpenWrite(filename);
+
+         if ( ASDCP_SUCCESS(result) )
+           result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
            }
 
          if ( Options.verbose_flag )
@@ -659,14 +680,14 @@ read_PCM_file(CommandOptions& Options)
        }
       else
        {
-         FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
+      FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
        }
 
       if ( Options.verbose_flag )
        {
          fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
-         PCM::AudioDescriptorDump(ADesc);
-       }
+       PCM::AudioDescriptorDump(ADesc);
+    }
     }
 
   if ( ASDCP_SUCCESS(result) )
@@ -691,10 +712,10 @@ read_PCM_file(CommandOptions& Options)
 
       if ( ! Options.no_write_flag )
        {
-         OutWave.OpenWrite(ADesc, Options.file_prefix,
-                           ( Options.split_wav ? WavFileWriter::ST_STEREO : 
-                             ( Options.mono_wav ? WavFileWriter::ST_MONO : WavFileWriter::ST_NONE ) ));
-       }
+      OutWave.OpenWrite(ADesc, Options.file_prefix,
+                       ( Options.split_wav ? WavFileWriter::ST_STEREO :
+                         ( Options.mono_wav ? WavFileWriter::ST_MONO : WavFileWriter::ST_NONE ) ));
+    }
     }
 
   if ( ASDCP_SUCCESS(result) && Options.key_flag )
@@ -730,10 +751,10 @@ read_PCM_file(CommandOptions& Options)
 
          if ( ! Options.no_write_flag )
            {
-             result = OutWave.WriteFrame(FrameBuffer);
-           }
+         result = OutWave.WriteFrame(FrameBuffer);
        }
     }
+    }
 
   return result;
 }
@@ -820,6 +841,90 @@ read_timed_text_file(CommandOptions& Options)
          if ( ASDCP_SUCCESS(result) )
            result = Writer.Write(FrameBuffer.RoData(), FrameBuffer.Size(), &write_count);
 
+             if ( Options.verbose_flag )
+               FrameBuffer.Dump(stderr, Options.fb_dump_size);
+       }
+    }
+
+  return result;
+}
+
+// Read one or more plaintext DCData bytestreams from a plaintext ASDCP file
+// Read one or more plaintext DCData bytestreams from a ciphertext ASDCP file
+// Read one or more ciphertext DCData byestreams from a ciphertext ASDCP file
+//
+Result_t
+read_DCData_file(CommandOptions& Options)
+{
+  AESDecContext*     Context = 0;
+  HMACContext*       HMAC = 0;
+  DCData::MXFReader    Reader;
+  DCData::FrameBuffer  FrameBuffer(Options.fb_size);
+  ui32_t             frame_count = 0;
+
+  Result_t result = Reader.OpenRead(Options.input_filename);
+
+  if ( ASDCP_SUCCESS(result) )
+    {
+      DCData::DCDataDescriptor DDesc;
+      Reader.FillDCDataDescriptor(DDesc);
+
+      frame_count = DDesc.ContainerDuration;
+
+      if ( Options.verbose_flag )
+       {
+         fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+         DCData::DCDataDescriptorDump(DDesc);
+       }
+    }
+
+  if ( ASDCP_SUCCESS(result) && Options.key_flag )
+    {
+      Context = new AESDecContext;
+      result = Context->InitKey(Options.key_value);
+
+      if ( ASDCP_SUCCESS(result) && Options.read_hmac )
+       {
+         WriterInfo Info;
+         Reader.FillWriterInfo(Info);
+
+         if ( Info.UsesHMAC )
+           {
+             HMAC = new HMACContext;
+             result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+           }
+         else
+           {
+             fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
+           }
+       }
+    }
+
+  ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
+  if ( last_frame > frame_count )
+    last_frame = frame_count;
+
+  char name_format[64];
+  snprintf(name_format,  64, "%%s%%0%du.%s", Options.number_width, Options.extension);
+
+  for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
+    {
+      result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
+
+      if ( ASDCP_SUCCESS(result) )
+       {
+         if ( ! Options.no_write_flag )
+           {
+         Kumu::FileWriter OutFile;
+         char filename[256];
+         ui32_t write_count;
+         snprintf(filename, 256, name_format, Options.file_prefix, i);
+         result = OutFile.OpenWrite(filename);
+
+         if ( ASDCP_SUCCESS(result) )
+           result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
+        }
+
          if ( Options.verbose_flag )
            FrameBuffer.Dump(stderr, Options.fb_dump_size);
        }
@@ -888,6 +993,15 @@ main(int argc, const char** argv)
              result = read_timed_text_file(Options);
              break;
 
+        case ESS_DCDATA_UNKNOWN:
+          result = read_DCData_file(Options);
+          break;
+
+        case ESS_DCDATA_DOLBY_ATMOS:
+          Options.extension = "atmos";
+          result = read_DCData_file(Options);
+          break;
+
            default:
              fprintf(stderr, "%s: Unknown file type, not ASDCP essence.\n", Options.input_filename);
              return 5;
index bbff82a6c6eaae1e962d818f146d39b9f43f6a5d..12435ce341062abd91adb4b881ac4efb66dc5b03 100755 (executable)
@@ -25,7 +25,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 /*! \file    asdcp-wrap.cpp
-    \version $Id$       
+    \version $Id$
     \brief   AS-DCP file manipulation utility
 
   This program wraps d-cinema essence (picture, sound or text) into an AS-DCP
@@ -48,6 +48,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <KM_fileio.h>
 #include <KM_prng.h>
+#include <AtmosSyncChannel_Mixer.h>
 #include <AS_DCP.h>
 #include <PCMParserList.h>
 #include <Metadata.h>
@@ -76,7 +77,7 @@ public:
       static byte_t default_ProductUUID_Data[UUIDlen] =
       { 0x7d, 0x83, 0x6e, 0x16, 0x37, 0xc7, 0x4c, 0x22,
        0xb2, 0xe0, 0x46, 0xa7, 0x17, 0xe8, 0x4f, 0x42 };
-      
+
       memcpy(ProductUUID, default_ProductUUID_Data, UUIDlen);
       CompanyName = "WidgetCo";
       ProductName = "asdcp-wrap";
@@ -117,7 +118,7 @@ USAGE: %s [-h|-help] [-V]\n\
 \n\
        %s [-3] [-a <uuid>] [-b <buffer-size>] [-C <UL>] [-d <duration>]\n\
           [-e|-E] [-f <start-frame>] [-j <key-id-string>] [-k <key-string>]\n\
-          [-l <label>] [-L] [-M] [-p <frame-rate>] [-s <num>] [-v] [-W]\n\
+          [-l <label>] [-L] [-M] [-p <frame-rate>] [-s] [-v] [-W]\n\
           [-z|-Z] <input-file>+ <output-file>\n\n",
          PROGRAM_NAME, PROGRAM_NAME);
 
@@ -147,6 +148,10 @@ Options:\n\
   -P <UL>           - Set PictureEssenceCoding UL value in a JP2K file\n\
   -p <rate>         - fps of picture when wrapping PCM or JP2K:\n\
                       Use one of [23|24|25|30|48|50|60], 24 is default\n\
+  -s                - Insert a Dolby Atmos synchronization channel when\n\
+                      wrapping PCM. This implies a -L option(SMPTE ULs) and \n\
+                      will overide -C and -l options with Configuration 4 \n\
+                      Channel Assigment and no format label respectively. \n\
   -v                - Verbose, prints informative messages to stderr\n\
   -W                - Read input file only, do not write source file\n\
   -z                - Fail if j2c inputs have unequal parameters (default)\n\
@@ -168,7 +173,7 @@ decode_channel_fmt(const std::string& label_name)
 
   else if ( label_name == "6.1" )
     return PCM::CF_CFG_2;
-  
+
   else if ( label_name == "7.1" )
     return PCM::CF_CFG_3;
 
@@ -217,6 +222,11 @@ public:
   Kumu::PathList_t filenames;  // list of filenames to be processed
   UL channel_assignment;
   UL picture_coding;
+  bool dolby_atmos_sync_flag;  // if true, insert a Dolby Atmos Synchronization channel.
+  ui32_t ffoa;  /// first frame of action for atmos wrapping
+  ui32_t max_channel_count; /// max channel count for atmos wrapping
+  ui32_t max_object_count; /// max object count for atmos wrapping
+
 
   //
   Rational PictureRate()
@@ -268,6 +278,8 @@ public:
     duration(0xffffffff), use_smpte_labels(false), j2c_pedantic(true),
     fb_size(FRAME_BUFFER_SIZE),
     channel_fmt(PCM::CF_NONE),
+    ffoa(0), max_channel_count(10), max_object_count(118), // hard-coded sample atmos properties
+    dolby_atmos_sync_flag(false),
     show_ul_values(false)
   {
     memset(key_value, 0, KeyLen);
@@ -281,7 +293,7 @@ public:
            help_flag = true;
            continue;
          }
-         
+
        if ( argv[i][0] == '-'
             && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
             && argv[i][2] == 0 )
@@ -387,7 +399,7 @@ public:
                TEST_EXTRA_ARG(i, 'p');
                picture_rate = abs(atoi(argv[i]));
                break;
-
+          case 's': dolby_atmos_sync_flag = true; break;
              case 'V': version_flag = true; break;
              case 'v': verbose_flag = true; break;
              case 'W': no_write_flag = true; break;
@@ -416,7 +428,7 @@ public:
 
     if ( help_flag || version_flag )
       return;
-    
+
     if ( filenames.size() < 2 )
       {
        fputs("Option requires at least two filename arguments: <input-file> <output-file>\n", stderr);
@@ -515,19 +527,16 @@ write_MPEG2_file(CommandOptions& Options)
 
       while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
        {
-         if ( duration == 1 )
-           {
              result = Parser.ReadFrame(FrameBuffer);
 
              if ( ASDCP_SUCCESS(result) )
                {
                  if ( Options.verbose_flag )
                    FrameBuffer.Dump(stderr, Options.fb_dump_size);
-                 
+
                  if ( Options.encrypt_header_flag )
                    FrameBuffer.PlaintextOffset(0);
                }
-           }
 
          if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
            {
@@ -578,7 +587,7 @@ check_phfr_params(CommandOptions& Options, JP2K::PictureDescriptor& PDesc)
   // do not set the label if the user has already done so
   if ( ! Options.picture_coding.HasValue() )
     Options.picture_coding = UL(P_HFR_UL_2K);
-  
+
   return true;
 }
 
@@ -673,7 +682,7 @@ write_JP2K_S_file(CommandOptions& Options)
 
       if ( ASDCP_SUCCESS(result) )
        result = Writer.OpenWrite(Options.out_file.c_str(), Info, PDesc);
-      
+
       if ( ASDCP_SUCCESS(result) && Options.picture_coding.HasValue() )
        {
          MXF::RGBAEssenceDescriptor *descriptor = 0;
@@ -697,7 +706,7 @@ write_JP2K_S_file(CommandOptions& Options)
            {
              if ( Options.verbose_flag )
                FrameBuffer.Dump(stderr, Options.fb_dump_size);
-                 
+
              if ( Options.encrypt_header_flag )
                FrameBuffer.PlaintextOffset(0);
            }
@@ -712,7 +721,7 @@ write_JP2K_S_file(CommandOptions& Options)
            {
              if ( Options.verbose_flag )
                FrameBuffer.Dump(stderr, Options.fb_dump_size);
-                 
+
              if ( Options.encrypt_header_flag )
                FrameBuffer.PlaintextOffset(0);
            }
@@ -825,19 +834,16 @@ write_JP2K_file(CommandOptions& Options)
 
       while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
        {
-         if ( duration == 1 )
-           {
              result = Parser.ReadFrame(FrameBuffer);
 
              if ( ASDCP_SUCCESS(result) )
                {
                  if ( Options.verbose_flag )
                    FrameBuffer.Dump(stderr, Options.fb_dump_size);
-                 
+
                  if ( Options.encrypt_header_flag )
                    FrameBuffer.PlaintextOffset(0);
                }
-           }
 
          if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
            {
@@ -1007,6 +1013,131 @@ write_PCM_file(CommandOptions& Options)
   return result;
 }
 
+// Mix one or more plaintext PCM audio streams with a Dolby Atmos Synchronization channel and write them to a plaintext ASDCP file
+// Mix one or more plaintext PCM audio streams with a Dolby Atmos Synchronization channel and write them to a ciphertext ASDCP file
+//
+Result_t
+write_PCM_with_ATMOS_sync_file(CommandOptions& Options)
+{
+  AESEncContext*        Context = 0;
+  HMACContext*          HMAC = 0;
+  PCM::MXFWriter        Writer;
+  PCM::FrameBuffer      FrameBuffer;
+  PCM::AudioDescriptor  ADesc;
+  Rational              PictureRate = Options.PictureRate();
+  byte_t                IV_buf[CBC_BLOCK_SIZE];
+  Kumu::FortunaRNG      RNG;
+
+  WriterInfo Info = s_MyInfo;  // fill in your favorite identifiers here
+  if ( Options.asset_id_flag )
+       memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
+  else
+       Kumu::GenRandomUUID(Info.AssetUUID);
+  AtmosSyncChannelMixer Mixer(Info.AssetUUID);
+
+  // set up essence parser
+  Result_t result = Mixer.OpenRead(Options.filenames, PictureRate);
+
+  // set up MXF writer
+  if ( ASDCP_SUCCESS(result) )
+  {
+    Mixer.FillAudioDescriptor(ADesc);
+
+    ADesc.EditRate = PictureRate;
+    FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
+    ADesc.ChannelFormat = PCM::CF_CFG_4;
+
+    if ( Options.verbose_flag )
+       {
+         fprintf(stderr, "%.1fkHz PCM Audio, %s fps (%u spf)\n",
+              ADesc.AudioSamplingRate.Quotient() / 1000.0,
+              Options.szPictureRate(),
+              PCM::CalcSamplesPerFrame(ADesc));
+         fputs("AudioDescriptor:\n", stderr);
+         PCM::AudioDescriptorDump(ADesc);
+       }
+  }
+
+  if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+  {
+    Info.LabelSetType = LS_MXF_SMPTE;
+    fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
+
+    // configure encryption
+    if( Options.key_flag )
+       {
+         Kumu::GenRandomUUID(Info.ContextID);
+         Info.EncryptedEssence = true;
+
+         if ( Options.key_id_flag )
+           memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
+         else
+           RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
+
+         Context = new AESEncContext;
+         result = Context->InitKey(Options.key_value);
+
+         if ( ASDCP_SUCCESS(result) )
+           result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+
+         if ( ASDCP_SUCCESS(result) && Options.write_hmac )
+      {
+        Info.UsesHMAC = true;
+        HMAC = new HMACContext;
+        result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+      }
+       }
+
+    if ( ASDCP_SUCCESS(result) )
+      result = Writer.OpenWrite(Options.out_file.c_str(), Info, ADesc);
+  }
+
+  if ( ASDCP_SUCCESS(result) )
+  {
+    result = Mixer.Reset();
+    ui32_t duration = 0;
+
+    while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
+       {
+         result = Mixer.ReadFrame(FrameBuffer);
+
+         if ( ASDCP_SUCCESS(result) )
+      {
+        if ( FrameBuffer.Size() != FrameBuffer.Capacity() )
+               {
+                 fprintf(stderr, "WARNING: Last frame read was short, PCM input is possibly not frame aligned.\n");
+                 fprintf(stderr, "Expecting %u bytes, got %u.\n", FrameBuffer.Capacity(), FrameBuffer.Size());
+                 result = RESULT_ENDOFFILE;
+                 continue;
+               }
+
+        if ( Options.verbose_flag )
+          FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+        if ( ! Options.no_write_flag )
+               {
+                 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
+
+                 // The Writer class will forward the last block of ciphertext
+                 // to the encryption context for use as the IV for the next
+                 // frame. If you want to use non-sequitur IV values, un-comment
+                 // the following  line of code.
+                 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
+                 //   Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+               }
+      }
+       }
+
+    if ( result == RESULT_ENDOFFILE )
+      result = RESULT_OK;
+  }
+
+  if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+    result = Writer.Finalize();
+
+  return result;
+}
+
 
 //------------------------------------------------------------------------------------------
 // TimedText essence
@@ -1109,7 +1240,7 @@ write_timed_text_file(CommandOptions& Options)
          if ( ! Options.no_write_flag )
            {
              result = Writer.WriteAncillaryResource(FrameBuffer, Context, HMAC);
-             
+
              // The Writer class will forward the last block of ciphertext
              // to the encryption context for use as the IV for the next
              // frame. If you want to use non-sequitur IV values, un-comment
@@ -1129,6 +1260,124 @@ write_timed_text_file(CommandOptions& Options)
   return result;
 }
 
+// Write one or more plaintext Dolby ATMOS bytestreams to a plaintext ASDCP file
+// Write one or more plaintext Dolby ATMOS bytestreams to a ciphertext ASDCP file
+//
+Result_t
+write_dolby_atmos_file(CommandOptions& Options)
+{
+  AESEncContext*          Context = 0;
+  HMACContext*            HMAC = 0;
+  ATMOS::MXFWriter         Writer;
+  DCData::FrameBuffer       FrameBuffer(Options.fb_size);
+  ATMOS::AtmosDescriptor ADesc;
+  DCData::SequenceParser    Parser;
+  byte_t                  IV_buf[CBC_BLOCK_SIZE];
+  Kumu::FortunaRNG        RNG;
+
+  // set up essence parser
+  Result_t result = Parser.OpenRead(Options.filenames.front().c_str());
+
+  // set up MXF writer
+  if ( ASDCP_SUCCESS(result) )
+  {
+    Parser.FillDCDataDescriptor(ADesc);
+    ADesc.EditRate = Options.PictureRate();
+    // TODO: fill AtmosDescriptor
+    ADesc.FirstFrame = Options.ffoa;
+    ADesc.MaxChannelCount = Options.max_channel_count;
+    ADesc.MaxObjectCount = Options.max_object_count;
+    Kumu::GenRandomUUID(ADesc.AtmosID);
+    ADesc.AtmosVersion = 1;
+    if ( Options.verbose_flag )
+       {
+         fprintf(stderr, "Dolby ATMOS Data\n");
+         fputs("AtmosDescriptor:\n", stderr);
+      fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+      ATMOS::AtmosDescriptorDump(ADesc);
+       }
+  }
+
+  if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+  {
+    WriterInfo Info = s_MyInfo;  // fill in your favorite identifiers here
+    if ( Options.asset_id_flag )
+      memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
+    else
+      Kumu::GenRandomUUID(Info.AssetUUID);
+
+    Info.LabelSetType = LS_MXF_SMPTE;
+
+      // configure encryption
+    if( Options.key_flag )
+       {
+         Kumu::GenRandomUUID(Info.ContextID);
+         Info.EncryptedEssence = true;
+
+         if ( Options.key_id_flag )
+           memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
+         else
+           RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
+
+         Context = new AESEncContext;
+         result = Context->InitKey(Options.key_value);
+
+         if ( ASDCP_SUCCESS(result) )
+           result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+
+         if ( ASDCP_SUCCESS(result) && Options.write_hmac )
+      {
+        Info.UsesHMAC = true;
+        HMAC = new HMACContext;
+        result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+      }
+       }
+
+    if ( ASDCP_SUCCESS(result) )
+      result = Writer.OpenWrite(Options.out_file.c_str(), Info, ADesc);
+  }
+
+  if ( ASDCP_SUCCESS(result) )
+  {
+    ui32_t duration = 0;
+    result = Parser.Reset();
+
+    while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
+       {
+      result = Parser.ReadFrame(FrameBuffer);
+
+      if ( ASDCP_SUCCESS(result) )
+      {
+        if ( Options.verbose_flag )
+          FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+        if ( Options.encrypt_header_flag )
+          FrameBuffer.PlaintextOffset(0);
+      }
+
+      if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+      {
+        result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
+
+        // The Writer class will forward the last block of ciphertext
+        // to the encryption context for use as the IV for the next
+        // frame. If you want to use non-sequitur IV values, un-comment
+        // the following  line of code.
+        // if ( ASDCP_SUCCESS(result) && Options.key_flag )
+        //   Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+      }
+       }
+
+    if ( result == RESULT_ENDOFFILE )
+      result = RESULT_OK;
+  }
+
+  if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+    result = Writer.Finalize();
+
+  return result;
+}
+
 //
 int
 main(int argc, const char** argv)
@@ -1184,13 +1433,24 @@ main(int argc, const char** argv)
 
        case ESS_PCM_24b_48k:
        case ESS_PCM_24b_96k:
-         result = write_PCM_file(Options);
+      if ( Options.dolby_atmos_sync_flag )
+      {
+        result = write_PCM_with_ATMOS_sync_file(Options);
+      }
+      else
+      {
+        result = write_PCM_file(Options);
+      }
          break;
 
        case ESS_TIMED_TEXT:
          result = write_timed_text_file(Options);
          break;
 
+       case ESS_DCDATA_DOLBY_ATMOS:
+         result = write_dolby_atmos_file(Options);
+         break;
+
        default:
          fprintf(stderr, "%s: Unknown file type, not ASDCP-compatible essence.\n",
                  Options.filenames.front().c_str());
index 35e5e776eb097e3bd069cb7ff33cc85508c33003..36d3235d050b4d68cf44640a32be64964438faf1 100644 (file)
@@ -187,8 +187,8 @@ make_black_wav_file(CommandOptions& Options)
 
   if ( ASDCP_SUCCESS(result) )
     {
-      Wav::SimpleWaveHeader WavHeader(ADesc);
-      result = WavHeader.WriteToFile(OutFile);
+       RF64::SimpleRF64Header WavHeader(ADesc);
+       result = WavHeader.WriteToFile(OutFile);
     }
 
   if ( ASDCP_SUCCESS(result) )
index da2aca231019172eb08d2da2c962a4b28eb2270f..77d732f9f2aaae9536691767f8163fd5d7d65c18 100755 (executable)
@@ -75,19 +75,26 @@ ASDCP::h__ASDCPReader::OpenMXFRead(const char* filename)
 
   if ( KM_SUCCESS(result) )
     {
-      // if this is a three partition file, go to the body
-      // partition and read the partition pack
-      if ( m_HeaderPart.m_RIP.PairArray.size() > 2 )
-       {
-         Array<RIP::Pair>::iterator r_i = m_HeaderPart.m_RIP.PairArray.begin();
-         r_i++;
-         m_File.Seek((*r_i).ByteOffset);
-         result = m_BodyPart.InitFromFile(m_File);
-       }
+        // if this is a three partition file, go to the body
+        // partition and read the partition pack
+        if ( m_HeaderPart.m_RIP.PairArray.size() > 2 )
+        {
+            Array<RIP::Pair>::iterator r_i = m_HeaderPart.m_RIP.PairArray.begin();
+            r_i++;
+            m_File.Seek((*r_i).ByteOffset);
+            result = m_BodyPart.InitFromFile(m_File);
+            if( !ASDCP_SUCCESS(result) )
+            {
+                DefaultLogSink().Error("ASDCP::h__Reader::OpenMXFRead, m_BodyPart.InitFromFile failed\n");
+            }
+        }
     }
+    else
+      DefaultLogSink().Error("ASDCP::h__Reader::OpenMXFRead, TrackFileReader::OpenMXFRead failed\n");
+
 
   if ( KM_SUCCESS(result) )
-    m_HeaderPart.BodyOffset = m_File.Tell();
+      m_HeaderPart.BodyOffset = m_File.Tell();
 
   return result;
 }
@@ -148,6 +155,14 @@ ASDCP::h__ASDCPReader::ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameB
                                                                                     EssenceUL, Ctx, HMAC);
 }
 
+Result_t
+ASDCP::h__ASDCPReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset,
+                           i8_t& temporalOffset, i8_t& keyFrameOffset)
+{
+  return ASDCP::MXF::TrackFileReader<OPAtomHeader, OPAtomIndexFooter>::LocateFrame(m_HeaderPart, FrameNum,
+                                                                                   streamOffset, temporalOffset, keyFrameOffset);
+}
+
 
 //------------------------------------------------------------------------------------------
 //
index 1a7b9b8531dc4e4018003b27ba665b23b2ca67d9..26103c7f8c933048a0699a3128a0f408eff1e110 100755 (executable)
@@ -33,11 +33,11 @@ OBJDIR = .
 \r
 !ifdef ENABLE_RANDOM_UUID\r
 CXXFLAGS1 = /nologo /W3 /GR /EHsc /DWIN32 /DKM_WIN32 /D_CONSOLE /I. /I$(SRCDIR) /DASDCP_PLATFORM=\"win32\" \\r
-       /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS /DPACKAGE_VERSION=\"1.10.48\" \\r
+       /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS /DPACKAGE_VERSION=\"1.11.49\" \\r
        /I"$(WITH_OPENSSL)"\inc32 /DCONFIG_RANDOM_UUID=1\r
 !else\r
 CXXFLAGS1 = /nologo /W3 /GR /EHsc /DWIN32 /DKM_WIN32 /D_CONSOLE /I. /I$(SRCDIR) /DASDCP_PLATFORM=\"win32\" \\r
-       /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS /DPACKAGE_VERSION=\"1.10.48\" \\r
+       /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS /DPACKAGE_VERSION=\"1.11.49\" \\r
        /I"$(WITH_OPENSSL)"\inc32\r
 !endif\r
 LIB_EXE = lib.exe\r