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
# 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
# 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
# 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}
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 ;;
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:*:*)
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
# 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
# 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
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 ]
-isc*)
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
+ -lynx*178)
+ os=-lynxos178
+ ;;
+ -lynx*5)
+ os=-lynxos5
+ ;;
-lynx*)
os=-lynxos
;;
# 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 \
c6x)
basic_machine=tic6x-unknown
;;
- m6811 | m68hc11 | m6812 | m68hc12 | picochip)
+ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
basic_machine=$basic_machine-unknown
os=-none
;;
strongarm | thumb | xscale)
basic_machine=arm-unknown
;;
-
+ xgate)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
xscaleeb)
basic_machine=armeb-unknown
;;
# 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-* \
| -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* \
c4x-* | tic4x-*)
os=-coff
;;
+ hexagon-*)
+ os=-elf
+ ;;
tic54x-*)
os=-coff
;;
#! /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
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*)
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.
;;
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
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
## 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.
# 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
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|/[^/]*$|/|'`
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
;;
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 :
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
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/ \\*$//
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=
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
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"
shift
fi
- # Remove `-o $object'.
+ # Remove '-o $object'.
IFS=" "
for arg
do
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"
# 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"
shift
fi
- # Remove `-o $object'.
+ # Remove '-o $object'.
IFS=" "
for arg
do
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"
;;
#!/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
# 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
-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
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
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
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
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
# -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"
#! /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
# 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
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
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:
--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 $?
;;
-*)
- 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
;;
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
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"
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/' |
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"`
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=\${$#}
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=\${$#}
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"`
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"`
*)
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
# 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])
/*
-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
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
#define _AS_DCP_H_
#include <KM_error.h>
+#include <KM_fileio.h>
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
// 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
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;
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);
// 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.
// 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
{
Capacity(size);
}
-
+
virtual ~FrameBuffer() {}
// Sets the MPEG frame type of the picture data in the frame buffer.
// 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.
{
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
};
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;
};
// 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;
ui8_t NumberOfLayers[sizeof(ui16_t)];
ui8_t MultiCompTransform;
} SGcod;
-
+
struct
{
ui8_t DecompositionLevels;
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;
};
// 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;
// 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;
// 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;
SP_LEFT,
SP_RIGHT
};
-
+
struct SFrameBuffer
{
JP2K::FrameBuffer Left;
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;
struct TimedTextResourceDescriptor
{
byte_t ResourceID[UUIDlen];
- MIMEType_t Type;
+ MIMEType_t Type;
TimedTextResourceDescriptor() : Type(MT_BIN) {}
};
struct TimedTextDescriptor
{
- Rational EditRate; //
+ Rational EditRate; //
ui32_t ContainerDuration;
byte_t AssetID[UUIDlen];
std::string NamespaceName;
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(); }
};
} // 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
--- /dev/null
+/*
+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
+//
+
+
--- /dev/null
+/*
+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
+//
--- /dev/null
+/*
+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_
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
ASDCP::JP2K::MXFReader::~MXFReader()
{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ m_Reader->Close();
}
// Warning: direct manipulation of MXF structures can interfere
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.
ASDCP::JP2K::MXFSReader::~MXFSReader()
{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ m_Reader->Close();
}
// Warning: direct manipulation of MXF structures can interfere
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
ASDCP::MPEG2::MXFReader::~MXFReader()
{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ m_Reader->Close();
}
// Warning: direct manipulation of MXF structures can interfere
}
+//
+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,
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;
ASDCP::FrameBuffer FB;
Kumu::FileReader Reader;
ASDCP::Wav::SimpleWaveHeader WavHeader;
+ ASDCP::RF64::SimpleRF64Header RF64Header;
ASDCP::AIFF::SimpleAIFFHeader AIFFHeader;
Kumu::XMLElement TmpElement("Tmp");
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;
{
type = ESS_TIMED_TEXT;
}
+ else if ( ASDCP::ATMOS::IsDolbyAtmos(filename) )
+ {
+ type = ESS_DCDATA_DOLBY_ATMOS;
+ }
}
}
else if ( Kumu::PathIsDirectory(filename) )
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;
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;
}
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,
ADesc.BlockAlign,
ADesc.AvgBps,
ADesc.LinkedTrackID,
- ADesc.ContainerDuration
+ ADesc.ContainerDuration,
+ ADesc.ChannelFormat
);
}
}
else
{
+ DefaultLogSink().Error("PCM EditRate not in expected value range.\n");
// or we just drop the hammer
return RESULT_FORMAT;
}
}
+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
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++ )
{
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)));
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
*/
std::vector<int> result;
const char* pstr = str;
const char* r = strchr(pstr, '.');
-
+
while ( r != 0 )
{
assert(r >= pstr);
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
{
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);
};
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);
}
if ( KM_SUCCESS(result) )
result = m_HeaderPart.InitFromFile(m_File);
-
+ else
+ DefaultLogSink().Error("ASDCP::h__Reader::OpenMXFRead, OpenRead failed\n");
+
return result;
}
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();
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);
+
};
{
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);
};
--- /dev/null
+/*
+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;
+}
+
--- /dev/null
+/*
+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
+//
--- /dev/null
+/*
+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
+//
--- /dev/null
+/*
+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
+//
--- /dev/null
+/*
+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;
+}
--- /dev/null
+/*
+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
--- /dev/null
+/*
+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
+//
+
+
+
--- /dev/null
+/*
+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
+//
+
}
else
{
- fprintf(stream, " IndexEntryArray: %du entries\n", IndexEntryArray.size());
+ fprintf(stream, " IndexEntryArray: %zu entries\n", IndexEntryArray.size());
}
}
/*
-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
{ { 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 }
};
/*
-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
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
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
}
}
}
+ 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;
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() )
{
{
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() )
{
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());
MXFTypes.h \
MXF.h \
Wav.h \
- PCMParserList.h
+ PCMParserList.h \
+ AtmosSyncChannel_Generator.h
nodist_include_HEADERS = TimedText_Transform.h
endif
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
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
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);
}
//------------------------------------------------------------------------------------------
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
//
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
--- /dev/null
+/*
+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;
+}
--- /dev/null
+/*
+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
+//
using namespace ASDCP;
using namespace ASDCP::PCM;
using namespace ASDCP::Wav;
+using namespace ASDCP::RF64;
//------------------------------------------------------------------------------------------
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;
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();
+ }
+ }
}
}
--- /dev/null
+/*
+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
--- /dev/null
+/*
+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;
+}
--- /dev/null
+/*
+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
+
--- /dev/null
+/*
+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]);
+ }
+ }
+}
--- /dev/null
+/*
+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
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;
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
};
} // 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_
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;
}
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.
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
help_flag = true;
continue;
}
-
+
if ( argv[i][0] == '-'
&& ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
&& argv[i][2] == 0 )
if ( help_flag || version_flag )
return;
-
+
if ( filenames.empty() )
{
fputs("At least one filename argument is required.\n", stderr);
}
};
+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>
Result_t result = m_Reader.OPAtomHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_RGBAEssenceDescriptor),
reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
-
+
if ( KM_SUCCESS(result) )
m_PictureEssenceCoding = descriptor->PictureEssenceCoding;
}
Result_t result = m_Reader.OPAtomHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_WaveAudioDescriptor),
reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
-
+
if ( KM_SUCCESS(result) )
{
char buf[64];
{
FileInfoWrapper<ASDCP::JP2K::MXFSReader, MyStereoPictureDescriptor>wrapper;
result = wrapper.file_info(Options, "JPEG 2000 stereoscopic pictures");
-
+
if ( KM_SUCCESS(result) )
{
wrapper.get_PictureEssenceCoding();
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());
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.
-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\
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()
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);
help_flag = true;
continue;
}
-
+
if ( argv[i][0] == '-'
&& ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
&& argv[i][2] == 0 )
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]));
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':
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);
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;
}
{
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 )
{
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;
{
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 )
}
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) )
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 )
if ( ! Options.no_write_flag )
{
- result = OutWave.WriteFrame(FrameBuffer);
- }
+ result = OutWave.WriteFrame(FrameBuffer);
}
}
+ }
return result;
}
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);
}
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;
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
#include <KM_fileio.h>
#include <KM_prng.h>
+#include <AtmosSyncChannel_Mixer.h>
#include <AS_DCP.h>
#include <PCMParserList.h>
#include <Metadata.h>
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";
\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);
-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\
else if ( label_name == "6.1" )
return PCM::CF_CFG_2;
-
+
else if ( label_name == "7.1" )
return PCM::CF_CFG_3;
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()
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);
help_flag = true;
continue;
}
-
+
if ( argv[i][0] == '-'
&& ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
&& argv[i][2] == 0 )
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;
if ( help_flag || version_flag )
return;
-
+
if ( filenames.size() < 2 )
{
fputs("Option requires at least two filename arguments: <input-file> <output-file>\n", stderr);
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 )
{
// 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;
}
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;
{
if ( Options.verbose_flag )
FrameBuffer.Dump(stderr, Options.fb_dump_size);
-
+
if ( Options.encrypt_header_flag )
FrameBuffer.PlaintextOffset(0);
}
{
if ( Options.verbose_flag )
FrameBuffer.Dump(stderr, Options.fb_dump_size);
-
+
if ( Options.encrypt_header_flag )
FrameBuffer.PlaintextOffset(0);
}
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 )
{
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
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
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)
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());
if ( ASDCP_SUCCESS(result) )
{
- Wav::SimpleWaveHeader WavHeader(ADesc);
- result = WavHeader.WriteToFile(OutFile);
+ RF64::SimpleRF64Header WavHeader(ADesc);
+ result = WavHeader.WriteToFile(OutFile);
}
if ( ASDCP_SUCCESS(result) )
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;
}
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);
+}
+
//------------------------------------------------------------------------------------------
//
\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