summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/AS_02.h4
-rw-r--r--src/AS_02_JP2K.cpp22
-rw-r--r--src/AS_02_PCM.cpp13
-rw-r--r--src/AS_02_TimedText.cpp4
-rwxr-xr-xsrc/AS_DCP.h3
-rwxr-xr-xsrc/AS_DCP_JP2K.cpp4
-rw-r--r--src/AS_DCP_TimedText.cpp9
-rw-r--r--src/KM_fileio.cpp32
-rw-r--r--src/MDD.cpp18
-rwxr-xr-xsrc/MXF.h12
-rw-r--r--src/Makefile.am10
-rwxr-xr-xsrc/PCMParserList.cpp16
-rwxr-xr-xsrc/PCMParserList.h3
-rwxr-xr-xsrc/PCM_Parser.cpp16
-rw-r--r--src/as-02-info.cpp858
-rwxr-xr-xsrc/as-02-unwrap.cpp14
-rw-r--r--src/h__02_Reader.cpp4
17 files changed, 1008 insertions, 34 deletions
diff --git a/src/AS_02.h b/src/AS_02.h
index 17561fd..874f686 100644
--- a/src/AS_02.h
+++ b/src/AS_02.h
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2011-2014, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
+Copyright (c) 2011-2016, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
John Hurst
All rights reserved.
@@ -301,7 +301,7 @@ namespace AS_02
// Open the file for reading. The file must exist. Returns error if the
// operation cannot be completed.
- Result_t OpenRead(const std::string& filename, const ASDCP::Rational& EditRate);
+ Result_t OpenRead(const std::string& filename, const ASDCP::Rational& EditRate) const;
// Returns RESULT_INIT if the file is not open.
Result_t Close() const;
diff --git a/src/AS_02_JP2K.cpp b/src/AS_02_JP2K.cpp
index a2027d3..b553da3 100644
--- a/src/AS_02_JP2K.cpp
+++ b/src/AS_02_JP2K.cpp
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2011-2013, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
+Copyright (c) 2011-2016, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
John Hurst
All rights reserved.
@@ -223,6 +223,26 @@ AS_02::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
return RESULT_INIT;
}
+//
+void
+AS_02::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ m_Reader->m_HeaderPart.Dump(stream);
+ }
+}
+
+
+//
+void
+AS_02::JP2K::MXFReader::DumpIndex(FILE* stream) const
+{
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ m_Reader->m_IndexAccess.Dump(stream);
+ }
+}
//------------------------------------------------------------------------------------------
diff --git a/src/AS_02_PCM.cpp b/src/AS_02_PCM.cpp
index 183f424..e58690a 100644
--- a/src/AS_02_PCM.cpp
+++ b/src/AS_02_PCM.cpp
@@ -255,7 +255,7 @@ AS_02::PCM::MXFReader::RIP()
// Open the file for reading. The file must exist. Returns error if the
// operation cannot be completed.
ASDCP::Result_t
-AS_02::PCM::MXFReader::OpenRead(const std::string& filename, const ASDCP::Rational& edit_rate)
+AS_02::PCM::MXFReader::OpenRead(const std::string& filename, const ASDCP::Rational& edit_rate) const
{
return m_Reader->OpenRead(filename, edit_rate);
}
@@ -307,16 +307,19 @@ void
AS_02::PCM::MXFReader::DumpHeaderMetadata(FILE* stream) const
{
if ( m_Reader && m_Reader->m_File.IsOpen() )
- m_Reader->m_HeaderPart.Dump(stream);
+ {
+ m_Reader->m_HeaderPart.Dump(stream);
+ }
}
-
//
void
AS_02::PCM::MXFReader::DumpIndex(FILE* stream) const
{
- if ( m_Reader->m_File.IsOpen() )
- m_Reader->m_IndexAccess.Dump(stream);
+ if ( m_Reader && m_Reader->m_File.IsOpen() )
+ {
+ m_Reader->m_IndexAccess.Dump(stream);
+ }
}
diff --git a/src/AS_02_TimedText.cpp b/src/AS_02_TimedText.cpp
index 5361029..c404d9b 100644
--- a/src/AS_02_TimedText.cpp
+++ b/src/AS_02_TimedText.cpp
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2015, John Hurst
+Copyright (c) 2008-2016, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,7 @@ static std::string TIMED_TEXT_DEF_LABEL = "Timed Text Track";
//------------------------------------------------------------------------------------------
-const char*
+static const char*
MIME2str(TimedText::MIMEType_t m)
{
if ( m == TimedText::MT_PNG )
diff --git a/src/AS_DCP.h b/src/AS_DCP.h
index cb78dbc..75ca97f 100755
--- a/src/AS_DCP.h
+++ b/src/AS_DCP.h
@@ -222,6 +222,7 @@ namespace ASDCP {
ESS_AS02_PCM_24b_96k, // the file contains one or more PCM audio pairs, clip wrapped
ESS_AS02_TIMED_TEXT, // the file contains a TTML document and zero or more resources
+ ESS_ACES, // the file contains one ACES codestream
ESS_MAX
};
@@ -946,6 +947,8 @@ namespace ASDCP {
// Reads the next sequential frame in the input file and places it in the
// frame buffer. Fails if the buffer is too small or the stream is empty.
Result_t ReadFrame(FrameBuffer&) const;
+
+ Result_t Seek(ui32_t frame_number) const;
};
diff --git a/src/AS_DCP_JP2K.cpp b/src/AS_DCP_JP2K.cpp
index 35929c6..acb8f4e 100755
--- a/src/AS_DCP_JP2K.cpp
+++ b/src/AS_DCP_JP2K.cpp
@@ -42,7 +42,7 @@ static std::string JP2K_PACKAGE_LABEL = "File Package: SMPTE 429-4 frame wrappin
static std::string JP2K_S_PACKAGE_LABEL = "File Package: SMPTE 429-10 frame wrapping of stereoscopic JPEG 2000 codestreams";
static std::string PICT_DEF_LABEL = "Picture Track";
-int s_exp_lookup[16] = { 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,2048, 4096, 8192, 16384, 32768 };
+static int s_exp_lookup[16] = { 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,2048, 4096, 8192, 16384, 32768 };
//
std::ostream&
@@ -296,7 +296,7 @@ ASDCP::MD_to_JP2K_PDesc(const ASDCP::MXF::GenericPictureEssenceDescriptor& Esse
}
else
{
- DefaultLogSink().Warn("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
+ DefaultLogSink().Warn("Unexpected PictureComponentSizing size: %u, should be 17.\n", tmp_size);
}
// CodingStyleDefault
diff --git a/src/AS_DCP_TimedText.cpp b/src/AS_DCP_TimedText.cpp
index f738a59..e6f3869 100644
--- a/src/AS_DCP_TimedText.cpp
+++ b/src/AS_DCP_TimedText.cpp
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2015, John Hurst
+Copyright (c) 2008-2016, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -43,15 +43,16 @@ static std::string TIMED_TEXT_DEF_LABEL = "Timed Text Track";
//------------------------------------------------------------------------------------------
-const char*
+//
+static const char*
MIME2str(TimedText::MIMEType_t m)
{
if ( m == TimedText::MT_PNG )
return "image/png";
- else if ( m == TimedText::MT_OPENTYPE )
+ else if( m == TimedText::MT_OPENTYPE )
return "application/x-font-opentype";
-
+
return "application/octet-stream";
}
diff --git a/src/KM_fileio.cpp b/src/KM_fileio.cpp
index 0e52cbe..2a217af 100644
--- a/src/KM_fileio.cpp
+++ b/src/KM_fileio.cpp
@@ -670,6 +670,11 @@ Kumu::GetExecutablePath(const std::string& default_path)
size_t size = X_BUFSIZE;
ssize_t rc = readlink("/proc/curproc/file", path, size);
success = ( rc != -1 );
+#elif defined(__sun) && defined(__SVR4)
+ size_t size = X_BUFSIZE;
+ char program[MAXPATHLEN];
+ snprintf(program, MAXPATHLEN, "/proc/%d/path/a.out", getpid());
+ ssize_t rc = readlink(program, path, size);
#else
#error GetExecutablePath --> Create a method for obtaining the executable name
#endif
@@ -1396,6 +1401,33 @@ Kumu::DirScanner::GetNext(char* filename)
}
+//
+Kumu::DirScannerEx::DirScannerEx() : m_Handle(0) {}
+
+//
+Result_t
+Kumu::DirScannerEx::Open(const std::string& dirname)
+{
+ Kumu::DefaultLogSink().Critical("Kumu::DirScannerEx unimplemented for Win32 API.\n");
+ return RESULT_NOTIMPL;
+}
+
+//
+Result_t
+Kumu::DirScannerEx::Close()
+{
+ Kumu::DefaultLogSink().Critical("Kumu::DirScannerEx unimplemented for Win32 API.\n");
+ return RESULT_NOTIMPL;
+}
+
+//
+Result_t
+Kumu::DirScannerEx::GetNext(std::string& next_item_name, DirectoryEntryType_t& next_item_type)
+{
+ Kumu::DefaultLogSink().Critical("Kumu::DirScannerEx unimplemented for Win32 API.\n");
+ return RESULT_NOTIMPL;
+}
+
#else // KM_WIN32
// POSIX directory scanner
diff --git a/src/MDD.cpp b/src/MDD.cpp
index d8e2ee9..7ccbf66 100644
--- a/src/MDD.cpp
+++ b/src/MDD.cpp
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2006-2015, John Hurst
+Copyright (c) 2006-2016, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -665,7 +665,7 @@ static const ASDCP::MDDEntry s_MDD_Table[] = {
{ { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 209
0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x43, 0x00 },
{0}, false, "GenericDataEssenceDescriptor" },
- { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 210
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x03, // 210
0x04, 0x03, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00 },
{0x3e, 0x01}, false, "GenericDataEssenceDescriptor_DataEssenceCoding" },
{ { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 211
@@ -1090,10 +1090,10 @@ static const ASDCP::MDDEntry s_MDD_Table[] = {
{0}, false, "MaterialPackage_PackageMarker" },
{ { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 351
0x04, 0x01, 0x02, 0x01, 0x01, 0x03, 0x01, 0x00 },
- {0}, false, "GenericPictureEssenceDescriptor_CodingEquations" },
+ {0x32, 0x1a}, false, "GenericPictureEssenceDescriptor_CodingEquations" },
{ { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, // 352
0x04, 0x01, 0x02, 0x01, 0x01, 0x06, 0x01, 0x00 },
- {0}, false, "GenericPictureEssenceDescriptor_ColorPrimaries" },
+ {0x32, 0x19}, false, "GenericPictureEssenceDescriptor_ColorPrimaries" },
{ { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 353
0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x01, 0x11 },
{0}, false, "JP2KEssenceCompression_BroadcastProfile_1" },
@@ -1126,16 +1126,16 @@ static const ASDCP::MDDEntry s_MDD_Table[] = {
{0}, false, "GenericPictureEssenceDescriptor_AlternativeCenterCuts" },
{ { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 363
0x04, 0x01, 0x05, 0x01, 0x13, 0x00, 0x00, 0x00 },
- {0x32, 0x05}, true, "GenericPictureEssenceDescriptor_ActiveHeight" },
+ {0}, true, "GenericPictureEssenceDescriptor_ActiveHeight" },
{ { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 364
0x04, 0x01, 0x05, 0x01, 0x14, 0x00, 0x00, 0x00 },
- {0x32, 0x04}, true, "GenericPictureEssenceDescriptor_ActiveWidth" },
+ {0}, true, "GenericPictureEssenceDescriptor_ActiveWidth" },
{ { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 365
0x04, 0x01, 0x05, 0x01, 0x15, 0x00, 0x00, 0x00 },
- {0x32, 0x06}, true, "GenericPictureEssenceDescriptor_ActiveXOffset" },
+ {0}, true, "GenericPictureEssenceDescriptor_ActiveXOffset" },
{ { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 366
0x04, 0x01, 0x05, 0x01, 0x16, 0x00, 0x00, 0x00 },
- {0x32, 0x07}, true, "GenericPictureEssenceDescriptor_ActiveYOffset" },
+ {0}, true, "GenericPictureEssenceDescriptor_ActiveYOffset" },
{ { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 367
0x03, 0x01, 0x01, 0x02, 0x02, 0x16, 0x00, 0x00 },
{0}, false, "TimedTextDescriptor_RFC5646LanguageTagList" },
@@ -1182,11 +1182,9 @@ static const ASDCP::MDDEntry s_MDD_Table[] = {
{ { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, // 379
0x0e, 0x09, 0x06, 0x07, 0x01, 0x01, 0x01, 0x06 },
{0}, false, "PHDRMetadataTrackSubDescriptor_SimplePayloadSID" },
-
{ { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 380
0x04, 0x01, 0x06, 0x03, 0x0e, 0x00, 0x00, 0x00 },
{0}, true, "JPEG2000PictureSubDescriptor_J2CLayout" },
-
{ {0}, {0}, false, 0 }
};
diff --git a/src/MXF.h b/src/MXF.h
index b90ebb7..19ff446 100755
--- a/src/MXF.h
+++ b/src/MXF.h
@@ -185,7 +185,17 @@ namespace ASDCP
LocalTagEntry(const TagValue& tag, ASDCP::UL& ul) : Tag(tag), UL(ul) {}
bool operator<(const LocalTagEntry& rhs) const {
- return ( ( Tag.a < rhs.Tag.a ) || ( Tag.b < rhs.Tag.b ) );
+ if ( Tag.a < rhs.Tag.a )
+ {
+ return true;
+ }
+
+ if ( Tag.a == rhs.Tag.a && Tag.b < rhs.Tag.b )
+ {
+ return true;
+ }
+
+ return false;
}
inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
diff --git a/src/Makefile.am b/src/Makefile.am
index 2f84f6e..306d5ca 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,7 +2,7 @@
#
# $Id$
#
-# Copyright (c) 2007-2013 John Hurst. All rights reserved.
+# Copyright (c) 2007-2016 John Hurst. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -227,7 +227,8 @@ bin_PROGRAMS = \
if USE_AS_02
bin_PROGRAMS += \
as-02-wrap \
- as-02-unwrap
+ as-02-unwrap \
+ as-02-info
endif
if USE_PHDR
@@ -285,6 +286,9 @@ as_02_wrap_LDADD = libas02.la libasdcp.la libkumu.la
as_02_unwrap_SOURCES = as-02-unwrap.cpp
as_02_unwrap_LDADD = libas02.la libasdcp.la libkumu.la
+
+as_02_info_SOURCES = as-02-info.cpp
+as_02_info_LDADD = libas02.la libasdcp.la libkumu.la
endif
if USE_PHDR
@@ -333,7 +337,7 @@ TESTS_ENVIRONMENT = BUILD_DIR="." TEST_FILES=../tests TEST_FILE_PREFIX=DCPd1-M1
JP2K_PREFIX=MM_2k_XYZ_
# files to include in the distribution that automake doesn't automatically include
-EXTRA_DIST = fips-186-test-harness.pl $(TESTS)
+EXTRA_DIST = fips-186-test-harness.pl $(TESTS) ../CMakeLists.txt
if !FREEDIST
if DEV_HEADERS
EXTRA_DIST += $(nodist_libasdcp_la_SOURCES) $(nodist_tt_xform_SOURCES)
diff --git a/src/PCMParserList.cpp b/src/PCMParserList.cpp
index 0ae22cc..c073e3f 100755
--- a/src/PCMParserList.cpp
+++ b/src/PCMParserList.cpp
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2004-2015, John Hurst
+Copyright (c) 2004-2016, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -301,5 +301,19 @@ ASDCP::PCMParserList::ReadFrame(PCM::FrameBuffer& OutFB)
}
//
+ASDCP::Result_t ASDCP::PCMParserList::Seek(ui32_t frame_number)
+{
+ Result_t result = RESULT_OK;
+ PCMParserList::iterator self_i;
+
+ for( self_i = begin(); self_i != end() && ASDCP_SUCCESS(result); self_i++ )
+ {
+ result = (*self_i)->Parser.Seek(frame_number);
+ }
+
+ return result;
+}
+
+//
// end PCMParserList.cpp
//
diff --git a/src/PCMParserList.h b/src/PCMParserList.h
index dbacd68..0af1627 100755
--- a/src/PCMParserList.h
+++ b/src/PCMParserList.h
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2004-2013, John Hurst
+Copyright (c) 2004-2016, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -78,6 +78,7 @@ namespace ASDCP
Result_t FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const;
Result_t Reset();
Result_t ReadFrame(PCM::FrameBuffer& OutFB);
+ Result_t Seek(ui32_t frame_number);
};
}
diff --git a/src/PCM_Parser.cpp b/src/PCM_Parser.cpp
index 2700aa4..072c235 100755
--- a/src/PCM_Parser.cpp
+++ b/src/PCM_Parser.cpp
@@ -73,6 +73,7 @@ public:
void Close();
void Reset();
Result_t ReadFrame(FrameBuffer&);
+ Result_t Seek(ui32_t frame_number);
};
@@ -196,6 +197,14 @@ ASDCP::PCM::WAVParser::h__WAVParser::ReadFrame(FrameBuffer& FB)
return result;
}
+//
+ASDCP::Result_t ASDCP::PCM::WAVParser::h__WAVParser::Seek(ui32_t frame_number)
+{
+ m_FramesRead = frame_number - 1;
+ m_ReadCount = 0;
+ return m_FileReader.Seek(m_DataStart + m_FrameBufferSize * frame_number);
+}
+
//------------------------------------------------------------------------------------------
@@ -254,6 +263,13 @@ ASDCP::PCM::WAVParser::FillAudioDescriptor(AudioDescriptor& ADesc) const
return RESULT_OK;
}
+ASDCP::Result_t ASDCP::PCM::WAVParser::Seek(ui32_t frame_number) const
+{
+ if ( m_Parser.empty() )
+ return RESULT_INIT;
+
+ return m_Parser->Seek(frame_number);;
+}
//
// end PCM_Parser.cpp
diff --git a/src/as-02-info.cpp b/src/as-02-info.cpp
new file mode 100644
index 0000000..7c68c41
--- /dev/null
+++ b/src/as-02-info.cpp
@@ -0,0 +1,858 @@
+/*
+Copyright (c) 2003-2016, John Hurst, Wolfgang Ruppel
+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-02-info.cpp
+ \version $Id$
+ \brief AS-02 file metadata utility
+
+ This program provides metadata information about an AS-02 file.
+
+ For more information about asdcplib, please refer to the header file AS_DCP.h
+*/
+
+#include <KM_fileio.h>
+#include <KM_log.h>
+#include <AS_DCP.h>
+#include <AS_02.h>
+#include <JP2K.h>
+#include <MXF.h>
+#include <Metadata.h>
+#include <cfloat>
+
+using namespace Kumu;
+using namespace ASDCP;
+
+const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte;
+
+//------------------------------------------------------------------------------------------
+//
+// command line option parser class
+
+static const char* PROGRAM_NAME = "as-02-info"; // program name for messages
+
+
+// Increment the iterator, test for an additional non-option command line argument.
+// Causes the caller to return if there are no remaining arguments or if the next
+// argument begins with '-'.
+#define TEST_EXTRA_ARG(i,c) \
+ if ( ++i >= argc || argv[(i)][0] == '-' ) { \
+ fprintf(stderr, "Argument not found for option -%c.\n", (c)); \
+ return; \
+ }
+
+//
+void
+banner(FILE* stream = stdout)
+{
+ fprintf(stream, "\n\
+%s (asdcplib %s)\n\n\
+Copyright (c) 2003-2015 John Hurst\n\n\
+asdcplib may be copied only under the terms of the license found at\n\
+the top of every file in the asdcplib distribution kit.\n\n\
+Specify the -h (help) option for further information about %s\n\n",
+ PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME);
+}
+
+//
+void
+usage(FILE* stream = stdout)
+{
+ fprintf(stream, "\
+USAGE:%s [-h|-help] [-V]\n\
+\n\
+ %s [options] <input-file>+\n\
+\n\
+Options:\n\
+ -c - Show essence coding UL\n\
+ -d - Show essence descriptor info\n\
+ -h | -help - Show help\n\
+ -H - Show MXF header metadata\n\
+ -i - Show identity info\n\
+ -n - Show index\n\
+ -r - Show bit-rate (Mb/s)\n\
+ -t <int> - Set high-bitrate threshold (Mb/s)\n\
+ -V - Show version information\n\
+\n\
+ NOTES: o There is no option grouping, all options must be distinct arguments.\n\
+ o All option arguments must be separated from the option by whitespace.\n\n",
+ PROGRAM_NAME, PROGRAM_NAME);
+
+}
+
+//
+class CommandOptions
+{
+ CommandOptions();
+
+public:
+ bool error_flag; // true if the given options are in error or not complete
+ bool version_flag; // true if the version display option was selected
+ bool help_flag; // true if the help display option was selected
+ bool verbose_flag; // true if the verbose option was selected
+ PathList_t filenames; // list of filenames to be processed
+ bool showindex_flag; // true if index is to be displayed
+ bool showheader_flag; // true if MXF file header is to be displayed
+ 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 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
+
+ //
+ CommandOptions(int argc, const char** argv) :
+ error_flag(true), version_flag(false), help_flag(false), verbose_flag(false),
+ showindex_flag(false), showheader_flag(false),
+ showid_flag(false), showdescriptor_flag(false), showcoding_flag(false),
+ showrate_flag(false), max_bitrate_flag(false), max_bitrate(0.0)
+ {
+ for ( int i = 1; i < argc; ++i )
+ {
+
+ if ( (strcmp( argv[i], "-help") == 0) )
+ {
+ help_flag = true;
+ continue;
+ }
+
+ if ( argv[i][0] == '-'
+ && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
+ && argv[i][2] == 0 )
+ {
+ switch ( argv[i][1] )
+ {
+ case 'c': showcoding_flag = true; break;
+ case 'd': showdescriptor_flag = true; break;
+ case 'H': showheader_flag = true; break;
+ case 'h': help_flag = true; break;
+ case 'i': showid_flag = true; break;
+ case 'n': showindex_flag = true; break;
+ case 'r': showrate_flag = true; break;
+
+ case 't':
+ TEST_EXTRA_ARG(i, 't');
+ max_bitrate = Kumu::xabs(strtol(argv[i], 0, 10));
+ max_bitrate_flag = true;
+ break;
+
+ case 'V': version_flag = true; break;
+ case 'v': verbose_flag = true; break;
+
+ default:
+ fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
+ return;
+ }
+ }
+ else
+ {
+ if ( argv[i][0] != '-' )
+ {
+ filenames.push_back(argv[i]);
+ }
+ else
+ {
+ fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
+ return;
+ }
+ }
+ }
+
+ if ( help_flag || version_flag )
+ return;
+
+ if ( filenames.empty() )
+ {
+ fputs("At least one filename argument is required.\n", stderr);
+ return;
+ }
+
+ error_flag = false;
+ }
+};
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+// These classes wrap the irregular names in the asdcplib API
+// so that I can use a template to simplify the implementation
+// of show_file_info()
+
+static int s_exp_lookup[16] = { 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,2048, 4096, 8192, 16384, 32768 };
+
+using namespace ASDCP::MXF;
+
+template <class ReaderType, class DescriptorType>
+DescriptorType *get_descriptor_by_type(ReaderType& reader, const UL& type_ul)
+{
+ InterchangeObject *obj = 0;
+ reader.OP1aHeader().GetMDObjectByType(type_ul.Value(), &obj);
+ return dynamic_cast<DescriptorType*>(obj);
+}
+
+class MyPictureDescriptor : public JP2K::PictureDescriptor
+{
+ RGBAEssenceDescriptor *m_RGBADescriptor;
+ CDCIEssenceDescriptor *m_CDCIDescriptor;
+ JPEG2000PictureSubDescriptor *m_JP2KSubDescriptor;
+
+ public:
+ MyPictureDescriptor() :
+ m_RGBADescriptor(0),
+ m_CDCIDescriptor(0),
+ m_JP2KSubDescriptor(0) {}
+
+ void FillDescriptor(AS_02::JP2K::MXFReader& Reader)
+ {
+ m_CDCIDescriptor = get_descriptor_by_type<AS_02::JP2K::MXFReader, CDCIEssenceDescriptor>
+ (Reader, DefaultCompositeDict().ul(MDD_CDCIEssenceDescriptor));
+
+ m_RGBADescriptor = get_descriptor_by_type<AS_02::JP2K::MXFReader, RGBAEssenceDescriptor>
+ (Reader, DefaultCompositeDict().ul(MDD_RGBAEssenceDescriptor));
+
+ if ( m_RGBADescriptor != 0 )
+ {
+ SampleRate = m_RGBADescriptor->SampleRate;
+ ContainerDuration = m_RGBADescriptor->ContainerDuration;
+ }
+ else if ( m_CDCIDescriptor != 0 )
+ {
+ SampleRate = m_CDCIDescriptor->SampleRate;
+ ContainerDuration = m_CDCIDescriptor->ContainerDuration;
+ }
+ else
+ {
+ DefaultLogSink().Error("Picture descriptor not found.\n");
+ }
+
+ m_JP2KSubDescriptor = get_descriptor_by_type<AS_02::JP2K::MXFReader, JPEG2000PictureSubDescriptor>
+ (Reader, DefaultCompositeDict().ul(MDD_JPEG2000PictureSubDescriptor));
+
+ if ( m_JP2KSubDescriptor == 0 )
+ {
+ DefaultLogSink().Error("JPEG2000PictureSubDescriptor not found.\n");
+ }
+
+ std::list<InterchangeObject*> ObjectList;
+ Reader.OP1aHeader().GetMDObjectsByType(DefaultCompositeDict().ul(MDD_Track), ObjectList);
+
+ if ( ObjectList.empty() )
+ {
+ DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
+ }
+
+ EditRate = ((Track*)ObjectList.front())->EditRate;
+ }
+
+ void MyDump(FILE* stream) {
+ if ( stream == 0 )
+ {
+ stream = stderr;
+ }
+
+ if ( m_CDCIDescriptor != 0 )
+ {
+ m_CDCIDescriptor->Dump(stream);
+ }
+ else if ( m_RGBADescriptor != 0 )
+ {
+ m_RGBADescriptor->Dump(stream);
+ }
+ else
+ {
+ return;
+ }
+
+ if ( m_JP2KSubDescriptor != 0 )
+ {
+ m_JP2KSubDescriptor->Dump(stream);
+
+ fprintf(stream, " ImageComponents: (max=%d)\n", JP2K::MaxComponents);
+
+ //
+ ui32_t component_sizing = m_JP2KSubDescriptor->PictureComponentSizing.const_get().Length();
+ JP2K::ImageComponent_t image_components[JP2K::MaxComponents];
+
+ if ( component_sizing == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
+ {
+ memcpy(&image_components,
+ m_JP2KSubDescriptor->PictureComponentSizing.const_get().RoData() + 8,
+ component_sizing - 8);
+ }
+ else
+ {
+ DefaultLogSink().Warn("Unexpected PictureComponentSizing size: %u, should be 17.\n", component_sizing);
+ }
+
+ fprintf(stream, " bits h-sep v-sep\n");
+
+ for ( int i = 0; i < m_JP2KSubDescriptor->Csize && i < JP2K::MaxComponents; i++ )
+ {
+ fprintf(stream, " %4d %5d %5d\n",
+ image_components[i].Ssize + 1, // See ISO 15444-1, Table A11, for the origin of '+1'
+ image_components[i].XRsize,
+ image_components[i].YRsize
+ );
+ }
+
+ //
+ JP2K::CodingStyleDefault_t coding_style_default;
+
+ memcpy(&coding_style_default,
+ m_JP2KSubDescriptor->CodingStyleDefault.const_get().RoData(),
+ m_JP2KSubDescriptor->CodingStyleDefault.const_get().Length());
+
+ fprintf(stream, " Scod: %hhu\n", coding_style_default.Scod);
+ fprintf(stream, " ProgressionOrder: %hhu\n", coding_style_default.SGcod.ProgressionOrder);
+ fprintf(stream, " NumberOfLayers: %hd\n",
+ KM_i16_BE(Kumu::cp2i<ui16_t>(coding_style_default.SGcod.NumberOfLayers)));
+
+ fprintf(stream, " MultiCompTransform: %hhu\n", coding_style_default.SGcod.MultiCompTransform);
+ fprintf(stream, "DecompositionLevels: %hhu\n", coding_style_default.SPcod.DecompositionLevels);
+ fprintf(stream, " CodeblockWidth: %hhu\n", coding_style_default.SPcod.CodeblockWidth);
+ fprintf(stream, " CodeblockHeight: %hhu\n", coding_style_default.SPcod.CodeblockHeight);
+ fprintf(stream, " CodeblockStyle: %hhu\n", coding_style_default.SPcod.CodeblockStyle);
+ fprintf(stream, " Transformation: %hhu\n", coding_style_default.SPcod.Transformation);
+
+ ui32_t precinct_set_size = 0;
+
+ for ( int i = 0; coding_style_default.SPcod.PrecinctSize[i] != 0 && i < JP2K::MaxPrecincts; ++i )
+ {
+ ++precinct_set_size;
+ }
+
+ fprintf(stream, " Precincts: %u\n", precinct_set_size);
+ fprintf(stream, "precinct dimensions:\n");
+
+ for ( int i = 0; i < precinct_set_size && i < JP2K::MaxPrecincts; i++ )
+ fprintf(stream, " %d: %d x %d\n", i + 1,
+ s_exp_lookup[coding_style_default.SPcod.PrecinctSize[i]&0x0f],
+ s_exp_lookup[(coding_style_default.SPcod.PrecinctSize[i]>>4)&0x0f]
+ );
+ }
+ }
+};
+
+class MyAudioDescriptor : public PCM::AudioDescriptor
+{
+ WaveAudioDescriptor *m_WaveAudioDescriptor;
+ std::list<MCALabelSubDescriptor*> m_ChannelDescriptorList;
+
+ public:
+ MyAudioDescriptor() : m_WaveAudioDescriptor(0) {}
+ void FillDescriptor(AS_02::PCM::MXFReader& Reader)
+ {
+ m_WaveAudioDescriptor = get_descriptor_by_type<AS_02::PCM::MXFReader, WaveAudioDescriptor>
+ (Reader, DefaultCompositeDict().ul(MDD_WaveAudioDescriptor));
+
+ if ( m_WaveAudioDescriptor != 0 )
+ {
+ AudioSamplingRate = m_WaveAudioDescriptor->SampleRate;
+ }
+ else
+ {
+ DefaultLogSink().Error("Audio descriptor not found.\n");
+ }
+
+ std::list<InterchangeObject*> object_list;
+ Reader.OP1aHeader().GetMDObjectsByType(DefaultCompositeDict().ul(MDD_AudioChannelLabelSubDescriptor), object_list);
+ Reader.OP1aHeader().GetMDObjectsByType(DefaultCompositeDict().ul(MDD_SoundfieldGroupLabelSubDescriptor), object_list);
+ Reader.OP1aHeader().GetMDObjectsByType(DefaultCompositeDict().ul(MDD_GroupOfSoundfieldGroupsLabelSubDescriptor), object_list);
+
+ std::list<InterchangeObject*>::iterator i = object_list.begin();
+ for ( ; i != object_list.end(); ++i )
+ {
+ MCALabelSubDescriptor *p = dynamic_cast<MCALabelSubDescriptor*>(*i);
+
+ if ( p )
+ {
+ m_ChannelDescriptorList.push_back(p);
+ }
+ else
+ {
+ char buf[64];
+ DefaultLogSink().Error("Audio sub-descriptor type error.\n", (**i).InstanceUID.EncodeHex(buf, 64));
+ }
+ }
+
+ object_list.clear();
+ Reader.OP1aHeader().GetMDObjectsByType(DefaultCompositeDict().ul(MDD_Track), object_list);
+
+ if ( object_list.empty() )
+ {
+ DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
+ }
+
+ EditRate = ((Track*)object_list.front())->EditRate;
+ }
+
+ void MyDump(FILE* stream) {
+ if ( stream == 0 )
+ {
+ stream = stderr;
+ }
+
+ if ( m_WaveAudioDescriptor != 0 )
+ {
+ m_WaveAudioDescriptor->Dump(stream);
+ }
+
+ if ( ! m_ChannelDescriptorList.empty() )
+ {
+ fprintf(stream, "Audio Channel Subdescriptors:\n");
+
+ std::list<MCALabelSubDescriptor*>::const_iterator i = m_ChannelDescriptorList.begin();
+ for ( ; i != m_ChannelDescriptorList.end(); ++i )
+ {
+ (**i).Dump(stream);
+ }
+ }
+ }
+};
+
+class MyTextDescriptor : public TimedText::TimedTextDescriptor
+{
+ public:
+ void FillDescriptor(TimedText::MXFReader& Reader) {
+ Reader.FillTimedTextDescriptor(*this);
+ }
+
+ void Dump(FILE* stream) {
+ TimedText::DescriptorDump(*this, stream);
+ }
+};
+
+struct RateInfo
+{
+ UL ul;
+ double bitrate;
+ std::string label;
+
+ RateInfo(const UL& u, const double& b, const std::string& l) {
+ ul = u; bitrate = b; label = l;
+ }
+
+};
+
+static const double dci_max_bitrate = 250.0;
+static const double p_hfr_max_bitrate = 400.0;
+typedef std::map<const UL, const RateInfo> rate_info_map;
+static rate_info_map g_rate_info;
+
+//
+void
+init_rate_info()
+{
+ UL rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_1);
+ g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 200.0, "ISO/IEC 15444-1 Amendment 3 Level 1")));
+
+ rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_2);
+ g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 200.0, "ISO/IEC 15444-1 Amendment 3 Level 2")));
+
+ rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_3);
+ g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 200.0, "ISO/IEC 15444-1 Amendment 3 Level 3")));
+
+ rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_4);
+ g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 400.0, "ISO/IEC 15444-1 Amendment 3 Level 4")));
+
+ rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_5);
+ g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 800.0, "ISO/IEC 15444-1 Amendment 3 Level 5")));
+
+ rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_6);
+ g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 1600.0, "ISO/IEC 15444-1 Amendment 3 Level 6")));
+
+ rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_7);
+ g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, DBL_MAX, "ISO/IEC 15444-1 Amendment 3 Level 7")));
+}
+
+
+//
+//
+template<class ReaderT, class DescriptorT>
+class FileInfoWrapper
+{
+ ReaderT m_Reader;
+ DescriptorT m_Desc;
+ WriterInfo m_WriterInfo;
+ double m_MaxBitrate, m_AvgBitrate;
+ UL m_PictureEssenceCoding;
+
+ KM_NO_COPY_CONSTRUCT(FileInfoWrapper);
+
+ template <class T>
+ Result_t OpenRead(const T& m, const CommandOptions& Options)
+ {
+ return m.OpenRead(Options.filenames.front().c_str());
+ };
+ Result_t OpenRead(const AS_02::PCM::MXFReader& m, const CommandOptions& Options)
+ {
+ return m.OpenRead(Options.filenames.front().c_str(), EditRate_24);
+ //Result_t OpenRead(const std::string& filename, const ASDCP::Rational& EditRate);
+ };
+
+public:
+ FileInfoWrapper() : m_MaxBitrate(0.0), m_AvgBitrate(0.0) {}
+ virtual ~FileInfoWrapper() {}
+
+ Result_t
+ file_info(CommandOptions& Options, const char* type_string, FILE* stream = 0)
+ {
+ assert(type_string);
+ if ( stream == 0 )
+ {
+ stream = stdout;
+ }
+
+ Result_t result = RESULT_OK;
+ result = OpenRead(m_Reader, Options);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ m_Desc.FillDescriptor(m_Reader);
+ m_Reader.FillWriterInfo(m_WriterInfo);
+
+ fprintf(stdout, "%s file essence type is %s, (%d edit unit%s).\n",
+ ( m_WriterInfo.LabelSetType == LS_MXF_SMPTE ? "SMPTE 2067-5" : "Unknown" ),
+ type_string,
+ (m_Desc.ContainerDuration != 0 ? m_Desc.ContainerDuration : m_Reader.AS02IndexReader().GetDuration()),
+ (m_Desc.ContainerDuration == 1 ? "":"s"));
+
+ if ( Options.showheader_flag )
+ {
+ m_Reader.DumpHeaderMetadata(stream);
+ }
+
+ if ( Options.showid_flag )
+ {
+ WriterInfoDump(m_WriterInfo, stream);
+ }
+
+ if ( Options.showdescriptor_flag )
+ {
+ m_Desc.MyDump(stream);
+ }
+
+ if ( Options.showindex_flag )
+ {
+ m_Reader.DumpIndex(stream);
+ }
+ }
+ else if ( result == RESULT_FORMAT && Options.showheader_flag )
+ {
+ m_Reader.DumpHeaderMetadata(stream);
+ }
+
+ return result;
+ }
+
+ //
+ void get_PictureEssenceCoding(FILE* stream = 0)
+ {
+ const Dictionary& Dict = DefaultCompositeDict();
+ MXF::RGBAEssenceDescriptor *rgba_descriptor = 0;
+ MXF::CDCIEssenceDescriptor *cdci_descriptor = 0;
+
+ Result_t result = m_Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_RGBAEssenceDescriptor),
+ reinterpret_cast<MXF::InterchangeObject**>(&rgba_descriptor));
+
+ if ( KM_SUCCESS(result) && rgba_descriptor)
+ m_PictureEssenceCoding = rgba_descriptor->PictureEssenceCoding;
+ else{
+ result = m_Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_CDCIEssenceDescriptor),
+ reinterpret_cast<MXF::InterchangeObject**>(&cdci_descriptor));
+ if ( KM_SUCCESS(result) && cdci_descriptor)
+ m_PictureEssenceCoding = cdci_descriptor->PictureEssenceCoding;
+ }
+ }
+
+
+ //
+ void dump_PictureEssenceCoding(FILE* stream = 0)
+ {
+ char buf[64];
+
+ if ( m_PictureEssenceCoding.HasValue() )
+ {
+ std::string encoding_ul_type = "**UNKNOWN**";
+
+ rate_info_map::const_iterator rate_i = g_rate_info.find(m_PictureEssenceCoding);
+ if ( rate_i == g_rate_info.end() )
+ {
+ fprintf(stderr, "Unknown PictureEssenceCoding UL: %s\n", m_PictureEssenceCoding.EncodeString(buf, 64));
+ }
+ else
+ {
+ encoding_ul_type = rate_i->second.label;
+ }
+
+ fprintf(stream, "PictureEssenceCoding: %s (%s)\n",
+ m_PictureEssenceCoding.EncodeString(buf, 64),
+ encoding_ul_type.c_str());
+ }
+ }
+
+ //
+ Result_t
+ test_rates(CommandOptions& Options, FILE* stream = 0)
+ {
+ double max_bitrate = 0; //Options.max_bitrate_flag ? Options.max_bitrate : dci_max_bitrate;
+ ui32_t errors = 0;
+ char buf[64];
+
+ rate_info_map::const_iterator rate_i = g_rate_info.find(m_PictureEssenceCoding);
+ if ( rate_i == g_rate_info.end() )
+ {
+ fprintf(stderr, "Unknown PictureEssenceCoding UL: %s\n", m_PictureEssenceCoding.EncodeString(buf, 64));
+ }
+ else
+ {
+ max_bitrate = rate_i->second.bitrate;
+ }
+
+ max_bitrate = Options.max_bitrate_flag ? Options.max_bitrate : max_bitrate;
+
+ if ( m_MaxBitrate > max_bitrate )
+ {
+ fprintf(stream, "Bitrate %0.0f Mb/s exceeds maximum %0.0f Mb/s\n", m_MaxBitrate, max_bitrate);
+ ++errors;
+ }
+
+ return errors ? RESULT_FAIL : RESULT_OK;
+ }
+
+ //
+ void
+ calc_Bitrate(FILE* stream = 0)
+ {
+ //MXF::OP1aHeader& footer = m_Reader.OP1aHeader();
+ AS_02::MXF::AS02IndexReader& footer = m_Reader.AS02IndexReader();
+ ui64_t total_frame_bytes = 0, last_stream_offset = 0;
+ ui32_t largest_frame = 0;
+ Result_t result = RESULT_OK;
+ ui64_t duration = 0;
+
+ if ( m_Desc.EditRate.Numerator == 0 || m_Desc.EditRate.Denominator == 0 )
+ {
+ fprintf(stderr, "Broken edit rate, unable to calculate essence bitrate.\n");
+ return;
+ }
+
+ duration = m_Desc.ContainerDuration;
+ if ( duration == 0 )
+ {
+ fprintf(stderr, "ContainerDuration not set in file descriptor, attempting to use index duration.\n");
+ duration = m_Reader.AS02IndexReader().GetDuration();
+ }
+
+ for ( ui32_t i = 0; KM_SUCCESS(result) && i < duration; ++i )
+ {
+ MXF::IndexTableSegment::IndexEntry entry;
+ result = footer.Lookup(i, entry);
+
+ if ( KM_SUCCESS(result) )
+ {
+ if ( last_stream_offset != 0 )
+ {
+ ui64_t this_frame_size = entry.StreamOffset - last_stream_offset - 20; // do not count the bytes that represent the KLV wrapping
+ total_frame_bytes += this_frame_size;
+
+ if ( this_frame_size > largest_frame )
+ largest_frame = this_frame_size;
+ }
+
+ last_stream_offset = entry.StreamOffset;
+ }
+ }
+
+ if ( KM_SUCCESS(result) )
+ {
+ // scale bytes to megabits
+ static const double mega_const = 1.0 / ( 1000000 / 8.0 );
+
+ // we did not accumulate the last, so duration -= 1
+ double avg_bytes_frame = total_frame_bytes / ( duration - 1 );
+
+ m_MaxBitrate = largest_frame * mega_const * m_Desc.EditRate.Quotient();
+ m_AvgBitrate = avg_bytes_frame * mega_const * m_Desc.EditRate.Quotient();
+ }
+ }
+
+ //
+ void
+ dump_Bitrate(FILE* stream = 0)
+ {
+ fprintf(stream, "Max BitRate: %0.2f Mb/s\n", m_MaxBitrate);
+ fprintf(stream, "Average BitRate: %0.2f Mb/s\n", m_AvgBitrate);
+ }
+
+ //
+ void dump_WaveAudioDescriptor(FILE* stream = 0)
+ {
+ const Dictionary& Dict = DefaultCompositeDict();
+ MXF::WaveAudioDescriptor *descriptor = 0;
+
+ Result_t result = m_Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_WaveAudioDescriptor),
+ reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
+
+ if ( KM_SUCCESS(result) )
+ {
+ char buf[64];
+ fprintf(stream, "ChannelAssignment: %s\n", descriptor->ChannelAssignment.const_get().EncodeString(buf, 64));
+ }
+ }
+
+};
+
+
+// Read header metadata from an ASDCP file
+//
+Result_t
+show_file_info(CommandOptions& Options)
+{
+ EssenceType_t EssenceType;
+ Result_t result = ASDCP::EssenceType(Options.filenames.front().c_str(), EssenceType);
+
+ if ( ASDCP_FAILURE(result) )
+ return result;
+
+ if ( EssenceType == ESS_AS02_JPEG_2000 )
+ {
+ FileInfoWrapper<AS_02::JP2K::MXFReader, MyPictureDescriptor> wrapper;
+ result = wrapper.file_info(Options, "JPEG 2000 pictures");
+
+ if ( KM_SUCCESS(result) )
+ {
+ wrapper.get_PictureEssenceCoding();
+ wrapper.calc_Bitrate(stdout);
+
+ if ( Options.showcoding_flag )
+ {
+ wrapper.dump_PictureEssenceCoding(stdout);
+ }
+
+ if ( Options.showrate_flag )
+ {
+ wrapper.dump_Bitrate(stdout);
+ }
+
+ result = wrapper.test_rates(Options, stdout);
+ }
+ }
+
+ else if ( EssenceType == ESS_AS02_PCM_24b_48k || EssenceType == ESS_AS02_PCM_24b_96k )
+ {
+ FileInfoWrapper<AS_02::PCM::MXFReader, MyAudioDescriptor> wrapper;
+ result = wrapper.file_info(Options, "PCM audio");
+
+ if ( ASDCP_SUCCESS(result) && Options.showcoding_flag )
+ wrapper.dump_WaveAudioDescriptor(stdout);
+ }
+ else
+ {
+ fprintf(stderr, "Unknown/unsupported essence type: %s\n", Options.filenames.front().c_str());
+ Kumu::FileReader Reader;
+ const Dictionary* Dict = &DefaultCompositeDict();
+ MXF::OP1aHeader TestHeader(Dict);
+
+ result = Reader.OpenRead(Options.filenames.front().c_str());
+
+ if ( ASDCP_SUCCESS(result) )
+ result = TestHeader.InitFromFile(Reader); // test UL and OP
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ TestHeader.Partition::Dump(stdout);
+
+ if ( MXF::Identification* ID = TestHeader.GetIdentification() )
+ ID->Dump(stdout);
+ else
+ fputs("File contains no Identification object.\n", stdout);
+
+ if ( MXF::SourcePackage* SP = TestHeader.GetSourcePackage() )
+ SP->Dump(stdout);
+ else
+ fputs("File contains no SourcePackage object.\n", stdout);
+ }
+ else
+ {
+ fputs("File is not MXF.\n", stdout);
+ }
+ }
+
+ return result;
+}
+
+//
+int
+main(int argc, const char** argv)
+{
+ Result_t result = RESULT_OK;
+ char str_buf[64];
+ CommandOptions Options(argc, argv);
+
+ if ( Options.version_flag )
+ banner();
+
+ if ( Options.help_flag )
+ usage();
+
+ if ( Options.version_flag || Options.help_flag )
+ return 0;
+
+ if ( Options.error_flag )
+ {
+ fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
+ return 3;
+ }
+
+ init_rate_info();
+
+ while ( ! Options.filenames.empty() && ASDCP_SUCCESS(result) )
+ {
+ result = show_file_info(Options);
+ Options.filenames.pop_front();
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ {
+ fputs("Program stopped on error.\n", stderr);
+
+ if ( result != RESULT_FAIL )
+ {
+ fputs(result, stderr);
+ fputc('\n', stderr);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+//
+// end as-02-info.cpp
+//
diff --git a/src/as-02-unwrap.cpp b/src/as-02-unwrap.cpp
index 688656b..43fe12f 100755
--- a/src/as-02-unwrap.cpp
+++ b/src/as-02-unwrap.cpp
@@ -473,6 +473,20 @@ read_PCM_file(CommandOptions& Options)
if ( last_frame == 0 )
{
+ fprintf(stderr, "ContainerDuration not set in index, attempting to use Duration from SourceClip.\n");
+ result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_SourceClip), &tmp_obj);
+ if ( KM_SUCCESS(result))
+ {
+ ASDCP::MXF::SourceClip *sourceClip = dynamic_cast<ASDCP::MXF::SourceClip*>(tmp_obj);
+ if ( ! sourceClip->Duration.empty() )
+ {
+ last_frame = sourceClip->Duration;
+ }
+ }
+ }
+
+ if ( last_frame == 0 )
+ {
fprintf(stderr, "Unable to determine file duration.\n");
return RESULT_FAIL;
}
diff --git a/src/h__02_Reader.cpp b/src/h__02_Reader.cpp
index a81d1ae..45825f0 100644
--- a/src/h__02_Reader.cpp
+++ b/src/h__02_Reader.cpp
@@ -228,8 +228,8 @@ AS_02::MXF::AS02IndexReader::InitFromFile(const Kumu::FileReader& reader, const
fprintf(stderr, " EditUnitByteCount = %u\n", segment->EditUnitByteCount);
fprintf(stderr, " IndexSID = %u\n", segment->IndexSID);
fprintf(stderr, " BodySID = %u\n", segment->BodySID);
- fprintf(stderr, " SliceCount = %hu\n", segment->SliceCount);
- fprintf(stderr, " PosTableCount = %hu\n", segment->PosTableCount);
+ fprintf(stderr, " SliceCount = %hhu\n", segment->SliceCount);
+ fprintf(stderr, " PosTableCount = %hhu\n", segment->PosTableCount);
fprintf(stderr, " RtFileOffset = %s\n", i64sz(segment->RtFileOffset, identbuf));
fprintf(stderr, " RtEntryOffset = %s\n", i64sz(segment->RtEntryOffset, identbuf));
fprintf(stderr, " IndexEntryArray:\n");