diff options
Diffstat (limited to 'src')
| -rwxr-xr-x | src/AS_DCP.h | 2 | ||||
| -rwxr-xr-x | src/KM_util.cpp | 24 | ||||
| -rwxr-xr-x | src/KM_util.h | 5 | ||||
| -rw-r--r-- | src/MDD.cpp | 6 | ||||
| -rwxr-xr-x | src/MXF.cpp | 6 | ||||
| -rwxr-xr-x | src/MXF.h | 3 | ||||
| -rwxr-xr-x | src/MXFTypes.cpp | 3 | ||||
| -rwxr-xr-x | src/asdcp-test.cpp | 134 | ||||
| -rw-r--r-- | src/blackwave.cpp | 4 | ||||
| -rwxr-xr-x | src/h__Writer.cpp | 20 |
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; @@ -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; |
