summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/AS_DCP.h2
-rwxr-xr-xsrc/KM_util.cpp24
-rwxr-xr-xsrc/KM_util.h5
-rw-r--r--src/MDD.cpp6
-rwxr-xr-xsrc/MXF.cpp6
-rwxr-xr-xsrc/MXF.h3
-rwxr-xr-xsrc/MXFTypes.cpp3
-rwxr-xr-xsrc/asdcp-test.cpp134
-rw-r--r--src/blackwave.cpp4
-rwxr-xr-xsrc/h__Writer.cpp20
10 files changed, 154 insertions, 53 deletions
diff --git a/src/AS_DCP.h b/src/AS_DCP.h
index 7505666..961dae3 100755
--- a/src/AS_DCP.h
+++ b/src/AS_DCP.h
@@ -144,7 +144,7 @@ namespace ASDCP {
// 1.0.1. If changes were also required in AS_DCP.h, the new version would be 1.1.1.
const ui32_t VERSION_MAJOR = 1;
const ui32_t VERSION_APIMINOR = 1;
- const ui32_t VERSION_IMPMINOR = 10;
+ const ui32_t VERSION_IMPMINOR = 11;
const char* Version();
// UUIDs are passed around as strings of UUIDlen bytes
diff --git a/src/KM_util.cpp b/src/KM_util.cpp
index 7dd6719..339f78b 100755
--- a/src/KM_util.cpp
+++ b/src/KM_util.cpp
@@ -600,6 +600,20 @@ Kumu::Timestamp::operator<(const Timestamp& rhs) const
return ( CompareFileTime(&lft, &rft) == -1 );
}
+//
+bool
+Kumu::Timestamp::operator>(const Timestamp& rhs) const
+{
+ SYSTEMTIME lhst, rhst;
+ FILETIME lft, rft;
+
+ TIMESTAMP_TO_SYSTIME(*this, &lhst);
+ TIMESTAMP_TO_SYSTIME(rhs, &rhst);
+ SystemTimeToFileTime(&lhst, &lft);
+ SystemTimeToFileTime(&rhst, &rft);
+ return ( CompareFileTime(&lft, &rft) == 1 );
+}
+
inline ui64_t
seconds_to_ns100(ui32_t seconds)
{
@@ -686,6 +700,16 @@ Kumu::Timestamp::operator<(const Timestamp& rhs) const
}
//
+bool
+Kumu::Timestamp::operator>(const Timestamp& rhs) const
+{
+ struct tm lhtm, rhtm;
+ TIMESTAMP_TO_TM(*this, &lhtm);
+ TIMESTAMP_TO_TM(rhs, &rhtm);
+ return ( timegm(&lhtm) > timegm(&rhtm) );
+}
+
+//
void
Kumu::Timestamp::AddDays(i32_t days)
{
diff --git a/src/KM_util.h b/src/KM_util.h
index d210bb9..e01cd2b 100755
--- a/src/KM_util.h
+++ b/src/KM_util.h
@@ -276,6 +276,10 @@ namespace Kumu
UUID(const UUID& rhs) : Identifier<UUID_Length>(rhs) {}
virtual ~UUID() {}
+ inline const char* EncodeString(char* buf, ui32_t buf_len) const {
+ return bin2UUIDhex(m_Value, Size(), buf, buf_len);
+ }
+
inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
return bin2UUIDhex(m_Value, Size(), buf, buf_len);
}
@@ -325,6 +329,7 @@ namespace Kumu
const Timestamp& operator=(const Timestamp& rhs);
bool operator<(const Timestamp& rhs) const;
+ bool operator>(const Timestamp& rhs) const;
bool operator==(const Timestamp& rhs) const;
bool operator!=(const Timestamp& rhs) const;
diff --git a/src/MDD.cpp b/src/MDD.cpp
index 29be177..2128257 100644
--- a/src/MDD.cpp
+++ b/src/MDD.cpp
@@ -84,8 +84,10 @@ static const ASDCP::MDDEntry s_MDD_Table[] = {
{ { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01, // 16
0x0d, 0x01, 0x03, 0x01, 0x16, 0x01, 0x01, 0x00 },
{0}, false, "WAVEssence" },
- { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x09, // 17
- 0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x01, 0x01 },
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07,
+ 0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x01, 0x03 },
+ // 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x09, // 17
+ // 0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x01, 0x01 },
{0}, false, "JP2KEssenceCompression" },
{ { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07, // 18
0x02, 0x09, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00 },
diff --git a/src/MXF.cpp b/src/MXF.cpp
index 0913f1b..28b156c 100755
--- a/src/MXF.cpp
+++ b/src/MXF.cpp
@@ -33,6 +33,10 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <KM_log.h>
using Kumu::DefaultLogSink;
+// index segments must be < 64K
+// NOTE: this value may too high if advanced index entry elements are used.
+const ui32_t CBRIndexEntriesPerSegment = 5000;
+
//------------------------------------------------------------------------------------------
//
@@ -1093,7 +1097,7 @@ ASDCP::MXF::OPAtomIndexFooter::PushIndexEntry(const IndexTableSegment::IndexEntr
m_CurrentSegment->IndexEditRate = m_EditRate;
m_CurrentSegment->IndexStartPosition = 0;
}
- else if ( m_CurrentSegment->IndexEntryArray.size() >= 1486 ) // 1486 gets us 16K packets
+ else if ( m_CurrentSegment->IndexEntryArray.size() >= CBRIndexEntriesPerSegment )
{ // no, this one is full, start another
m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
ui64_t StartPosition = m_CurrentSegment->IndexStartPosition + m_CurrentSegment->IndexDuration;
diff --git a/src/MXF.h b/src/MXF.h
index a38b6db..ed7fb0d 100755
--- a/src/MXF.h
+++ b/src/MXF.h
@@ -259,6 +259,9 @@ namespace ASDCP
i8_t KeyFrameOffset;
ui8_t Flags;
ui64_t StreamOffset;
+
+ // if you use these, you will need to change CBRIndexEntriesPerSegment in MXF.cpp
+ // to a more suitable value
// std::list<ui32_t> SliceOffset;
// Array<Rational> PosTable;
diff --git a/src/MXFTypes.cpp b/src/MXFTypes.cpp
index 90d68c1..625a2e2 100755
--- a/src/MXFTypes.cpp
+++ b/src/MXFTypes.cpp
@@ -616,7 +616,8 @@ ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, Kumu::IArchive* Object
ui32_t before = Length();
if ( ! Object->Archive(this) ) return RESULT_KLV_CODING;
- Kumu::i2p<ui16_t>(KM_i16_BE( Length() - before), l_p);
+ if ( (Length() - before) > 0xffffL ) return RESULT_KLV_CODING;
+ Kumu::i2p<ui16_t>(KM_i16_BE(Length() - before), l_p);
}
return result;
diff --git a/src/asdcp-test.cpp b/src/asdcp-test.cpp
index e43569e..cf7a91f 100755
--- a/src/asdcp-test.cpp
+++ b/src/asdcp-test.cpp
@@ -56,6 +56,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <WavFileWriter.h>
#include <MXF.h>
#include <Metadata.h>
+#include <openssl/sha.h>
using namespace ASDCP;
@@ -90,19 +91,6 @@ public:
} s_MyInfo;
-// Macros used to test command option data state.
-
-// True if a major mode has already been selected.
-#define TEST_MAJOR_MODE() ( info_flag||create_flag||extract_flag||genkey_flag||genid_flag||gop_start_flag )
-
-// Causes the caller to return if a major mode has already been selected,
-// otherwise sets the given flag.
-#define TEST_SET_MAJOR_MODE(f) if ( TEST_MAJOR_MODE() ) \
- { \
- fputs("Conflicting major mode, choose one of -(gcixG)).\n", stderr); \
- return; \
- } \
- (f) = true;
// Increment the iterator, test for an additional non-option command line argument.
// Causes the caller to return if there are no remaining arguments or if the next
@@ -143,10 +131,12 @@ USAGE: %s -c <output-file> [-b <buffer-size>] [-d <duration>] [-e|-E]\n\
\n\
%s -G [-v] <input-file>\n\
\n\
+ %s -t <input-file>\n\
+\n\
%s -x <file-prefix> [-b <buffer-size>] [-d <duration>]\n\
[-f <starting-frame>] [-m] [-p <frame-rate>] [-R] [-s <num>] [-S]\n\
[-v] [-W] <input-file>\n\
-\n", PACKAGE, PACKAGE, PACKAGE, PACKAGE, PACKAGE, PACKAGE);
+\n", PACKAGE, PACKAGE, PACKAGE, PACKAGE, PACKAGE, PACKAGE, PACKAGE);
fprintf(stream, "\
Major modes:\n\
@@ -155,6 +145,7 @@ Major modes:\n\
-G - Perform GOP start lookup test on MXF+Interop MPEG file\n\
-h | -help - Show help\n\
-i - Show file info\n\
+ -t - Calculate message digest of input file\n\
-u - Generate a random UUID value to stdout\n\
-V - Show version information\n\
-x <root-name> - Extract essence from AS-DCP file to named file(s)\n\
@@ -204,19 +195,28 @@ Other Options:\n\
}
//
+enum MajorMode_t
+{
+ MMT_NONE,
+ MMT_INFO,
+ MMT_CREATE,
+ MMT_EXTRACT,
+ MMT_GEN_ID,
+ MMT_GEN_KEY,
+ MMT_GOP_START,
+ MMT_DIGEST
+};
+
+
+//
//
class CommandOptions
{
CommandOptions();
public:
+ MajorMode_t mode;
bool error_flag; // true if the given options are in error or not complete
- bool info_flag; // true if the file info mode was selected
- bool create_flag; // true if the file create mode was selected
- bool extract_flag; // true if the file extract mode was selected
- bool genkey_flag; // true if we are to generate a new key value
- bool genid_flag; // true if we are to generate a new UUID value
- bool gop_start_flag; // true if we are to perform a GOP start lookup test
bool key_flag; // true if an encryption key was given
bool key_id_flag; // true if a key ID was given
bool encrypt_header_flag; // true if mpeg headers are to be encrypted
@@ -262,9 +262,7 @@ public:
//
CommandOptions(int argc, const char** argv) :
- error_flag(true), info_flag(false), create_flag(false),
- extract_flag(false), genkey_flag(false), genid_flag(false), gop_start_flag(false),
- key_flag(false), key_id_flag(false), encrypt_header_flag(true),
+ mode(MMT_NONE), error_flag(true), key_flag(false), key_id_flag(false), encrypt_header_flag(true),
write_hmac(true), read_hmac(false), split_wav(false),
verbose_flag(false), fb_dump_size(0), showindex_flag(false), showheader_flag(false),
no_write_flag(false), version_flag(false), help_flag(false), start_frame(0),
@@ -287,8 +285,8 @@ public:
{
switch ( argv[i][1] )
{
- case 'i': TEST_SET_MAJOR_MODE(info_flag); break;
- case 'G': TEST_SET_MAJOR_MODE(gop_start_flag); break;
+ case 'i': mode = MMT_INFO; break;
+ case 'G': mode = MMT_GOP_START; break;
case 'W': no_write_flag = true; break;
case 'n': showindex_flag = true; break;
case 'H': showheader_flag = true; break;
@@ -297,8 +295,8 @@ public:
case 'V': version_flag = true; break;
case 'h': help_flag = true; break;
case 'v': verbose_flag = true; break;
- case 'g': genkey_flag = true; break;
- case 'u': genid_flag = true; break;
+ case 'g': mode = MMT_GEN_KEY; break;
+ case 'u': mode = MMT_GEN_ID; break;
case 'e': encrypt_header_flag = true; break;
case 'E': encrypt_header_flag = false; break;
case 'M': write_hmac = false; break;
@@ -306,14 +304,14 @@ public:
case 'L': use_smpte_labels = true; break;
case 'c':
- TEST_SET_MAJOR_MODE(create_flag);
TEST_EXTRA_ARG(i, 'c');
+ mode = MMT_CREATE;
out_file = argv[i];
break;
case 'x':
- TEST_SET_MAJOR_MODE(extract_flag);
TEST_EXTRA_ARG(i, 'x');
+ mode = MMT_EXTRACT;
file_root = argv[i];
break;
@@ -366,6 +364,8 @@ public:
fb_dump_size = atoi(argv[i]);
break;
+ case 't': mode = MMT_DIGEST; break;
+
case 'b':
TEST_EXTRA_ARG(i, 'b');
fb_size = atoi(argv[i]);
@@ -404,18 +404,19 @@ public:
if ( help_flag || version_flag )
return;
- if ( TEST_MAJOR_MODE() )
+ if ( ( mode == MMT_INFO
+ || mode == MMT_CREATE
+ || mode == MMT_EXTRACT
+ || mode == MMT_GOP_START
+ || mode == MMT_DIGEST ) && file_count == 0 )
{
- if ( ! genkey_flag && ! genid_flag && file_count == 0 )
- {
- fputs("Option requires at least one filename argument.\n", stderr);
- return;
- }
+ fputs("Option requires at least one filename argument.\n", stderr);
+ return;
}
- if ( ! TEST_MAJOR_MODE() && ! help_flag && ! version_flag )
+ if ( mode == MMT_NONE && ! help_flag && ! version_flag )
{
- fputs("No operation selected (use one of -(gcixG) or -h for help).\n", stderr);
+ fputs("No operation selected (use one of -[gGcitux] or -h for help).\n", stderr);
return;
}
@@ -1235,6 +1236,48 @@ show_file_info(CommandOptions& Options)
//
+Result_t
+digest_file(const char* filename)
+{
+ using namespace Kumu;
+
+ ASDCP_TEST_NULL_STR(filename);
+ FileReader Reader;
+ SHA_CTX Ctx;
+ SHA1_Init(&Ctx);
+ ByteString Buf(8192);
+
+ Result_t result = Reader.OpenRead(filename);
+
+ while ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t read_count = 0;
+ result = Reader.Read(Buf.Data(), Buf.Capacity(), &read_count);
+
+ if ( result == RESULT_ENDOFFILE )
+ {
+ result = RESULT_OK;
+ break;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ SHA1_Update(&Ctx, Buf.Data(), read_count);
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ const ui32_t sha_len = 20;
+ byte_t bin_buf[sha_len];
+ char sha_buf[64];
+ SHA1_Final(bin_buf, &Ctx);
+
+ fprintf(stdout, "%s %s\n", base64encode(bin_buf, sha_len, sha_buf, 64), filename);
+ }
+
+ return result;
+}
+
+//
int
main(int argc, const char** argv)
{
@@ -1256,15 +1299,15 @@ main(int argc, const char** argv)
return 3;
}
- if ( Options.info_flag )
+ if ( Options.mode == MMT_INFO )
{
result = show_file_info(Options);
}
- else if ( Options.gop_start_flag )
+ else if ( Options.mode == MMT_GOP_START )
{
result = gop_start_test(Options);
}
- else if ( Options.genkey_flag )
+ else if ( Options.mode == MMT_GEN_KEY )
{
Kumu::FortunaRNG RNG;
byte_t bin_buf[KeyLen];
@@ -1273,14 +1316,19 @@ main(int argc, const char** argv)
RNG.FillRandom(bin_buf, KeyLen);
printf("%s\n", Kumu::bin2hex(bin_buf, KeyLen, str_buf, 40));
}
- else if ( Options.genid_flag )
+ else if ( Options.mode == MMT_GEN_ID )
{
UUID TmpID;
Kumu::GenRandomValue(TmpID);
char str_buf[40];
printf("%s\n", TmpID.EncodeHex(str_buf, 40));
}
- else if ( Options.extract_flag )
+ else if ( Options.mode == MMT_DIGEST )
+ {
+ for ( ui32_t i = 0; i < Options.file_count && ASDCP_SUCCESS(result); i++ )
+ result = digest_file(Options.filenames[i]);
+ }
+ else if ( Options.mode == MMT_EXTRACT )
{
EssenceType_t EssenceType;
result = ASDCP::EssenceType(Options.filenames[0], EssenceType);
@@ -1307,7 +1355,7 @@ main(int argc, const char** argv)
}
}
}
- else if ( Options.create_flag )
+ else if ( Options.mode == MMT_CREATE )
{
if ( Options.do_repeat && ! Options.duration_flag )
{
diff --git a/src/blackwave.cpp b/src/blackwave.cpp
index b704b47..311a0db 100644
--- a/src/blackwave.cpp
+++ b/src/blackwave.cpp
@@ -157,8 +157,8 @@ make_black_wav_file(CommandOptions& Options)
ADesc.Locked = 0;
ADesc.ChannelCount = 1;
ADesc.QuantizationBits = 24;
- ADesc.BlockAlign = 18;
- ADesc.AvgBps = 86400;
+ ADesc.BlockAlign = 3;
+ ADesc.AvgBps = 14400;
ADesc.LinkedTrackID = 1;
ADesc.ContainerDuration = Options.duration;
diff --git a/src/h__Writer.cpp b/src/h__Writer.cpp
index 32568c4..1105e03 100755
--- a/src/h__Writer.cpp
+++ b/src/h__Writer.cpp
@@ -109,7 +109,12 @@ ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& Wrap
// so we tell the world by using OP1a
m_HeaderPart.m_Preface->OperationalPattern = UL(Dict::ul(MDD_OP1a));
m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
- m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // First RIP Entry
+
+ // First RIP Entry
+ if ( m_Info.LabelSetType == LS_MXF_SMPTE )
+ m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // 3-part, no essence in header
+ else
+ m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, 0)); // 2-part, essence in header
//
// Identification
@@ -298,11 +303,16 @@ ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& Wrap
UL BodyUL(Dict::ul(MDD_ClosedCompleteBodyPartition));
result = m_BodyPart.WriteToFile(m_File, BodyUL);
}
+ else
+ {
+ m_HeaderPart.BodySID = 1;
+ }
if ( ASDCP_SUCCESS(result) )
{
// Index setup
Kumu::fpos_t ECoffset = m_File.Tell();
+ m_FooterPart.IndexSID = 129;
if ( BytesPerEditUnit == 0 )
m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset);
@@ -441,7 +451,7 @@ ASDCP::h__Writer::WriteMXFFooter()
m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
Kumu::fpos_t here = m_File.Tell();
- m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Third RIP Entry
+ m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Last RIP Entry
m_HeaderPart.FooterPartition = here;
// re-label the partition
@@ -453,7 +463,11 @@ ASDCP::h__Writer::WriteMXFFooter()
m_HeaderPart.OperationalPattern = OPAtomUL;
m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern;
- m_FooterPart.PreviousPartition = m_BodyPart.ThisPartition;
+ if ( m_Info.LabelSetType == LS_MXF_SMPTE )
+ m_FooterPart.PreviousPartition = m_BodyPart.ThisPartition;
+ else
+ m_FooterPart.PreviousPartition = m_HeaderPart.ThisPartition;
+
m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern;
m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers;
m_FooterPart.FooterPartition = here;