diff options
| author | jhurst <jhurst@cinecert.com> | 2013-02-08 19:11:58 +0000 |
|---|---|---|
| committer | jhurst <> | 2013-02-08 19:11:58 +0000 |
| commit | 9998b893b47f111f41c4f0fcf1067efe5b7a62f3 (patch) | |
| tree | ef455067287c17ebb9f82ecf3d27d134823c1edb /src | |
| parent | b3fa00a9f37ecc7c2bef6276aae0ea67d1ddbeb3 (diff) | |
big change rollup
Diffstat (limited to 'src')
| -rwxr-xr-x | src/AS_DCP.h | 9 | ||||
| -rwxr-xr-x | src/AS_DCP_JP2K.cpp | 6 | ||||
| -rwxr-xr-x | src/AS_DCP_MPEG2.cpp | 4 | ||||
| -rwxr-xr-x | src/AS_DCP_MXF.cpp | 4 | ||||
| -rwxr-xr-x | src/AS_DCP_PCM.cpp | 21 | ||||
| -rw-r--r-- | src/AS_DCP_TimedText.cpp | 4 | ||||
| -rwxr-xr-x | src/AS_DCP_internal.h | 162 | ||||
| -rw-r--r-- | src/KM_fileio.cpp | 179 | ||||
| -rwxr-xr-x | src/KM_fileio.h | 2 | ||||
| -rwxr-xr-x | src/KM_util.cpp | 58 | ||||
| -rwxr-xr-x | src/KM_util.h | 8 | ||||
| -rw-r--r-- | src/Makefile.am | 46 | ||||
| -rwxr-xr-x | src/asdcp-info.cpp | 225 | ||||
| -rwxr-xr-x | src/asdcp-test.cpp | 8 | ||||
| -rwxr-xr-x | src/asdcp-unwrap.cpp | 110 | ||||
| -rwxr-xr-x | src/asdcp-wrap.cpp | 87 | ||||
| -rw-r--r-- | src/blackwave.cpp | 22 | ||||
| -rwxr-xr-x | src/h__Reader.cpp | 200 | ||||
| -rw-r--r-- | src/path-test.cpp | 11 |
19 files changed, 805 insertions, 361 deletions
diff --git a/src/AS_DCP.h b/src/AS_DCP.h index 72d5261..c0556ba 100755 --- a/src/AS_DCP.h +++ b/src/AS_DCP.h @@ -279,6 +279,15 @@ namespace ASDCP { const Rational EditRate_100 = Rational(100,1); const Rational EditRate_120 = Rational(120,1); + // Archival frame rates, see ST 428-21 + // These rates are new and not supported by all systems. Do not assume that + // a package made using one of these rates will work just anywhere! + const Rational EditRate_16 = Rational(16,1); + const Rational EditRate_18 = Rational(200,11); // 18.182 + const Rational EditRate_20 = Rational(20,1); + const Rational EditRate_22 = Rational(240,11); // 21.818 + + // Non-reference counting container for internal member objects. // Please do not use this class for any other purpose. template <class T> diff --git a/src/AS_DCP_JP2K.cpp b/src/AS_DCP_JP2K.cpp index 076ba5c..33d5b93 100755 --- a/src/AS_DCP_JP2K.cpp +++ b/src/AS_DCP_JP2K.cpp @@ -205,7 +205,7 @@ ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream) // hidden, internal implementation of JPEG 2000 reader -class lh__Reader : public ASDCP::h__Reader +class lh__Reader : public ASDCP::h__ASDCPReader { RGBAEssenceDescriptor* m_EssenceDescriptor; JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor; @@ -219,7 +219,7 @@ public: PictureDescriptor m_PDesc; // codestream parameter list lh__Reader(const Dictionary& d) : - ASDCP::h__Reader(d), m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {} + ASDCP::h__ASDCPReader(d), m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {} Result_t OpenRead(const char*, EssenceType_t); Result_t ReadFrame(ui32_t, JP2K::FrameBuffer&, AESDecContext*, HMACContext*); Result_t MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc); @@ -595,7 +595,7 @@ public: } // get frame position - Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset; + Kumu::fpos_t FilePosition = m_HeaderPart.BodyOffset + TmpEntry.StreamOffset; Result_t result = RESULT_OK; if ( phase == SP_LEFT ) diff --git a/src/AS_DCP_MPEG2.cpp b/src/AS_DCP_MPEG2.cpp index 18102d4..2081630 100755 --- a/src/AS_DCP_MPEG2.cpp +++ b/src/AS_DCP_MPEG2.cpp @@ -160,7 +160,7 @@ ASDCP::MPEG2::VideoDescriptorDump(const VideoDescriptor& VDesc, FILE* stream) // // hidden, internal implementation of MPEG2 reader -class ASDCP::MPEG2::MXFReader::h__Reader : public ASDCP::h__Reader +class ASDCP::MPEG2::MXFReader::h__Reader : public ASDCP::h__ASDCPReader { ASDCP_NO_COPY_CONSTRUCT(h__Reader); h__Reader(); @@ -168,7 +168,7 @@ class ASDCP::MPEG2::MXFReader::h__Reader : public ASDCP::h__Reader public: VideoDescriptor m_VDesc; // video parameter list - h__Reader(const Dictionary& d) : ASDCP::h__Reader(d) {} + h__Reader(const Dictionary& d) : ASDCP::h__ASDCPReader(d) {} ~h__Reader() {} Result_t OpenRead(const char*); Result_t ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*); diff --git a/src/AS_DCP_MXF.cpp b/src/AS_DCP_MXF.cpp index 95e219e..96fc959 100755 --- a/src/AS_DCP_MXF.cpp +++ b/src/AS_DCP_MXF.cpp @@ -439,7 +439,7 @@ ASDCP::DecryptFrameBuffer(const ASDCP::FrameBuffer& FBin, ASDCP::FrameBuffer& FB // Result_t -ASDCP::IntegrityPack::CalcValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID, +ASDCP::IntegrityPack::CalcValues(const ASDCP::FrameBuffer& FB, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC) { ASDCP_TEST_NULL(AssetID); @@ -489,7 +489,7 @@ ASDCP::IntegrityPack::CalcValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID, Result_t -ASDCP::IntegrityPack::TestValues(const ASDCP::FrameBuffer& FB, byte_t* AssetID, +ASDCP::IntegrityPack::TestValues(const ASDCP::FrameBuffer& FB, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC) { ASDCP_TEST_NULL(AssetID); diff --git a/src/AS_DCP_PCM.cpp b/src/AS_DCP_PCM.cpp index 06a47b4..606a6f5 100755 --- a/src/AS_DCP_PCM.cpp +++ b/src/AS_DCP_PCM.cpp @@ -196,7 +196,7 @@ calc_CBR_frame_size(ASDCP::WriterInfo& Info, const ASDCP::PCM::AudioDescriptor& //------------------------------------------------------------------------------------------ -class ASDCP::PCM::MXFReader::h__Reader : public ASDCP::h__Reader +class ASDCP::PCM::MXFReader::h__Reader : public ASDCP::h__ASDCPReader { ASDCP_NO_COPY_CONSTRUCT(h__Reader); h__Reader(); @@ -204,7 +204,7 @@ class ASDCP::PCM::MXFReader::h__Reader : public ASDCP::h__Reader public: AudioDescriptor m_ADesc; - h__Reader(const Dictionary& d) : ASDCP::h__Reader(d) {} + h__Reader(const Dictionary& d) : ASDCP::h__ASDCPReader(d) {} ~h__Reader() {} Result_t OpenRead(const char*); Result_t ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*); @@ -239,6 +239,10 @@ ASDCP::PCM::MXFReader::h__Reader::OpenRead(const char* filename) && m_ADesc.EditRate != EditRate_96 && m_ADesc.EditRate != EditRate_100 && m_ADesc.EditRate != EditRate_120 + && m_ADesc.EditRate != EditRate_16 + && m_ADesc.EditRate != EditRate_18 + && m_ADesc.EditRate != EditRate_20 + && m_ADesc.EditRate != EditRate_22 && m_ADesc.EditRate != EditRate_23_98 ) { DefaultLogSink().Error("PCM file EditRate is not a supported value: %d/%d\n", // lu @@ -488,6 +492,10 @@ ASDCP::PCM::MXFWriter::h__Writer::SetSourceStream(const AudioDescriptor& ADesc) && ADesc.EditRate != EditRate_96 && ADesc.EditRate != EditRate_100 && ADesc.EditRate != EditRate_120 + && ADesc.EditRate != EditRate_16 + && ADesc.EditRate != EditRate_18 + && ADesc.EditRate != EditRate_20 + && ADesc.EditRate != EditRate_22 && ADesc.EditRate != EditRate_23_98 ) { DefaultLogSink().Error("AudioDescriptor.EditRate is not a supported value: %d/%d\n", @@ -516,7 +524,14 @@ ASDCP::PCM::MXFWriter::h__Writer::SetSourceStream(const AudioDescriptor& ADesc) if ( ASDCP_SUCCESS(result) ) { - ui32_t TCFrameRate = ( m_ADesc.EditRate == EditRate_23_98 ) ? 24 : m_ADesc.EditRate.Numerator; + ui32_t TCFrameRate = m_ADesc.EditRate.Numerator; + + if ( m_ADesc.EditRate == EditRate_23_98 ) + TCFrameRate = 24; + else if ( m_ADesc.EditRate == EditRate_18 ) + TCFrameRate = 18; + else if ( m_ADesc.EditRate == EditRate_22 ) + TCFrameRate = 22; result = WriteMXFHeader(PCM_PACKAGE_LABEL, UL(m_Dict->ul(MDD_WAVWrapping)), SOUND_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_SoundDataDef)), diff --git a/src/AS_DCP_TimedText.cpp b/src/AS_DCP_TimedText.cpp index 1199554..971fe08 100644 --- a/src/AS_DCP_TimedText.cpp +++ b/src/AS_DCP_TimedText.cpp @@ -123,7 +123,7 @@ ASDCP::TimedText::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const typedef std::map<UUID, UUID> ResourceMap_t; -class ASDCP::TimedText::MXFReader::h__Reader : public ASDCP::h__Reader +class ASDCP::TimedText::MXFReader::h__Reader : public ASDCP::h__ASDCPReader { MXF::TimedTextDescriptor* m_EssenceDescriptor; ResourceMap_t m_ResourceMap; @@ -133,7 +133,7 @@ class ASDCP::TimedText::MXFReader::h__Reader : public ASDCP::h__Reader public: TimedTextDescriptor m_TDesc; - h__Reader(const Dictionary& d) : ASDCP::h__Reader(d), m_EssenceDescriptor(0) { + h__Reader(const Dictionary& d) : ASDCP::h__ASDCPReader(d), m_EssenceDescriptor(0) { memset(&m_TDesc.AssetID, 0, UUIDlen); } diff --git a/src/AS_DCP_internal.h b/src/AS_DCP_internal.h index 082cd83..af6b553 100755 --- a/src/AS_DCP_internal.h +++ b/src/AS_DCP_internal.h @@ -128,6 +128,11 @@ namespace ASDCP void AddDMScrypt(Partition& HeaderPart, SourcePackage& Package, WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict); + Result_t Read_EKLV_Packet(Kumu::FileReader& File, const ASDCP::Dictionary& Dict, const MXF::OPAtomHeader& HeaderPart, + 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 { @@ -145,38 +150,147 @@ namespace ASDCP Result_t ReadKLFromFile(Kumu::FileReader& Reader); }; + namespace MXF + { + //--------------------------------------------------------------------------------- + // + + /// void default_md_object_init(); + + template <class HeaderType, class FooterType> + class TrackFileReader + { + KM_NO_COPY_CONSTRUCT(TrackFileReader); + TrackFileReader(); + + public: + const Dictionary* m_Dict; + Kumu::FileReader m_File; + HeaderType m_HeaderPart; + FooterType m_FooterPart; + WriterInfo m_Info; + ASDCP::FrameBuffer m_CtFrameBuf; + Kumu::fpos_t m_LastPosition; + + TrackFileReader(const Dictionary& d) : + m_HeaderPart(m_Dict), m_FooterPart(m_Dict), m_Dict(&d) + { + default_md_object_init(); + } + + virtual ~TrackFileReader() { + Close(); + } + + Result_t InitInfo() + { + assert(m_Dict); + InterchangeObject* Object; + + // Identification + Result_t result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object); + + // Writer Info and SourcePackage + if ( KM_SUCCESS(result) ) + { + MD_to_WriterInfo((Identification*)Object, m_Info); + result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object); + } + + if ( KM_SUCCESS(result) ) + { + SourcePackage* SP = (SourcePackage*)Object; + memcpy(m_Info.AssetUUID, SP->PackageUID.Value() + 16, UUIDlen); + } + + // optional CryptographicContext + 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); + } + + return result; + } + + // + Result_t OpenMXFRead(const char* filename) + { + m_LastPosition = 0; + Result_t result = m_File.OpenRead(filename); + + if ( KM_SUCCESS(result) ) + result = m_HeaderPart.InitFromFile(m_File); + + return result; + } + + // positions file before reading + Result_t ReadEKLVFrame(const ASDCP::MXF::Partition& CurrentPartition, + ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf, + const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC) + { + // 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 and go read the frame's key and length + Kumu::fpos_t FilePosition = CurrentPartition.BodyOffset + TmpEntry.StreamOffset; + Result_t result = RESULT_OK; + + if ( FilePosition != m_LastPosition ) + { + m_LastPosition = FilePosition; + result = m_File.Seek(FilePosition); + } + + if( KM_SUCCESS(result) ) + result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC); + + return result; + } + + // reads from current position + Result_t ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf, + const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC) + { + assert(m_Dict); + return Read_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_LastPosition, m_CtFrameBuf, + FrameNum, SequenceNum, FrameBuf, EssenceUL, Ctx, HMAC); + } + + // + void Close() { + m_File.Close(); + } + }; + + }/// namespace MXF + // - class h__Reader + class h__ASDCPReader : public MXF::TrackFileReader<OPAtomHeader, OPAtomIndexFooter> { - ASDCP_NO_COPY_CONSTRUCT(h__Reader); - h__Reader(); + ASDCP_NO_COPY_CONSTRUCT(h__ASDCPReader); + h__ASDCPReader(); public: - const Dictionary* m_Dict; - Kumu::FileReader m_File; - OPAtomHeader m_HeaderPart; - Partition m_BodyPart; - OPAtomIndexFooter m_FooterPart; - ui64_t m_EssenceStart; - WriterInfo m_Info; - ASDCP::FrameBuffer m_CtFrameBuf; - Kumu::fpos_t m_LastPosition; + Partition m_BodyPart; - h__Reader(const Dictionary&); - virtual ~h__Reader(); + h__ASDCPReader(const Dictionary&); + virtual ~h__ASDCPReader(); - Result_t InitInfo(); Result_t OpenMXFRead(const char* filename); + Result_t InitInfo(); Result_t InitMXFIndex(); - - // positions file before reading Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC); - - // reads from current position - Result_t ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf, - const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC); - void Close(); }; @@ -285,8 +399,8 @@ namespace ASDCP ~IntegrityPack() {} - Result_t CalcValues(const ASDCP::FrameBuffer&, byte_t* AssetID, ui32_t sequence, HMACContext* HMAC); - Result_t TestValues(const ASDCP::FrameBuffer&, byte_t* AssetID, ui32_t sequence, HMACContext* HMAC); + Result_t CalcValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC); + Result_t TestValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC); }; diff --git a/src/KM_fileio.cpp b/src/KM_fileio.cpp index 5d728cc..fdd4719 100644 --- a/src/KM_fileio.cpp +++ b/src/KM_fileio.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2004-2011, John Hurst +Copyright (c) 2004-2012, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -70,31 +70,6 @@ struct iovec { typedef struct stat fstat_t; #endif -// -static void -split(const std::string& str, char separator, std::list<std::string>& components) -{ - const char* pstr = str.c_str(); - const char* r = strchr(pstr, separator); - - while ( r != 0 ) - { - assert(r >= pstr); - if ( r > pstr ) - { - std::string tmp_str; - tmp_str.assign(pstr, (r - pstr)); - components.push_back(tmp_str); - } - - pstr = r + 1; - r = strchr(pstr, separator); - } - - if( strlen(pstr) > 0 ) - components.push_back(std::string(pstr)); -} - // static Kumu::Result_t @@ -216,61 +191,55 @@ Kumu::FileSize(const std::string& pathname) } // -static PathCompList_t& -s_PathMakeCanonical(PathCompList_t& CList, bool is_absolute) +static void +make_canonical_list(const PathCompList_t& in_list, PathCompList_t& out_list) { - PathCompList_t::iterator ci, ri; // component and removal iterators - - for ( ci = CList.begin(); ci != CList.end(); ci++ ) + PathCompList_t::const_iterator i; + for ( i = in_list.begin(); i != in_list.end(); ++i ) { - if ( *ci == "." && ( CList.size() > 1 || is_absolute ) ) - { - ri = ci++; - CList.erase(ri); - } - else if ( *ci == ".." && ci != CList.begin() ) + if ( *i == ".." ) { - ri = ci; - ri--; - - if ( *ri != ".." ) + if ( ! out_list.empty() ) { - CList.erase(ri); - ri = ci++; - CList.erase(ri); - } - } + out_list.pop_back(); + } + } + else if ( *i != "." ) + { + out_list.push_back(*i); + } } - - return CList; } // std::string Kumu::PathMakeCanonical(const std::string& Path, char separator) { - PathCompList_t CList; + PathCompList_t in_list, out_list; bool is_absolute = PathIsAbsolute(Path, separator); - s_PathMakeCanonical(PathToComponents(Path, CList, separator), is_absolute); + PathToComponents(Path, in_list, separator); + make_canonical_list(in_list, out_list); if ( is_absolute ) - return ComponentsToAbsolutePath(CList, separator); + return ComponentsToAbsolutePath(out_list, separator); - return ComponentsToPath(CList, separator); + return ComponentsToPath(out_list, separator); } // bool Kumu::PathsAreEquivalent(const std::string& lhs, const std::string& rhs) { - return PathMakeCanonical(lhs) == PathMakeCanonical(rhs); + return PathMakeAbsolute(lhs) == PathMakeAbsolute(rhs); } // Kumu::PathCompList_t& Kumu::PathToComponents(const std::string& Path, PathCompList_t& CList, char separator) { - split(Path, separator, CList); + std::string s; + s = separator; + CList = km_token_split(Path, s); return CList; } @@ -334,18 +303,8 @@ Kumu::PathIsAbsolute(const std::string& Path, char separator) // std::string -Kumu::PathMakeAbsolute(const std::string& Path, char separator) +Kumu::PathCwd() { - if ( Path.empty() ) - { - std::string out_path; - out_path = separator; - return out_path; - } - - if ( PathIsAbsolute(Path, separator) ) - return Path; - char cwd_buf [MaxFilePath]; if ( _getcwd(cwd_buf, MaxFilePath) == 0 ) { @@ -353,11 +312,28 @@ Kumu::PathMakeAbsolute(const std::string& Path, char separator) return ""; } - PathCompList_t CList; - PathToComponents(cwd_buf, CList); - CList.push_back(Path); + return cwd_buf; +} - return ComponentsToAbsolutePath(s_PathMakeCanonical(CList, true), separator); +// +std::string +Kumu::PathMakeAbsolute(const std::string& Path, char separator) +{ + if ( Path.empty() ) + { + std::string tmpstr; + tmpstr = separator; + return tmpstr; + } + + if ( PathIsAbsolute(Path, separator) ) + return PathMakeCanonical(Path); + + PathCompList_t in_list, out_list; + PathToComponents(PathJoin(PathCwd(), Path), in_list); + make_canonical_list(in_list, out_list); + + return ComponentsToAbsolutePath(out_list); } // @@ -455,6 +431,69 @@ Kumu::PathJoin(const std::string& Path1, const std::string& Path2, return Path1 + separator + Path2 + separator + Path3 + separator + Path4; } +#ifndef KM_WIN32 +// returns false if link cannot be read +// +bool +Kumu::PathResolveLinks(const std::string& link_path, std::string& resolved_path, char separator) +{ + PathCompList_t in_list, out_list; + PathToComponents(PathMakeCanonical(link_path), in_list, separator); + PathCompList_t::iterator i; + char link_buf[MaxFilePath]; + + for ( i = in_list.begin(); i != in_list.end(); ++i ) + { + assert ( *i != ".." && *i != "." ); + out_list.push_back(*i); + + for (;;) + { + std::string next_link = ComponentsToAbsolutePath(out_list, separator); + ssize_t link_size = readlink(next_link.c_str(), link_buf, MaxFilePath); + + if ( link_size == -1 ) + { + if ( errno == EINVAL ) + break; + + DefaultLogSink().Error("%s: readlink: %s\n", next_link.c_str(), strerror(errno)); + return false; + } + + assert(link_size < MaxFilePath); + link_buf[link_size] = 0; + std::string tmp_path; + out_list.clear(); + + if ( PathIsAbsolute(link_buf) ) + { + tmp_path = link_buf; + } + else + { + tmp_path = PathJoin(PathDirname(next_link), link_buf); + } + + PathToComponents(PathMakeCanonical(tmp_path), out_list, separator); + } + } + + resolved_path = ComponentsToAbsolutePath(out_list, separator); + return true; +} + +#else // KM_WIN32 +// TODO: is there a reasonable equivalent to be written for win32? +// +bool +Kumu::PathResolveLinks(const std::string& link_path, std::string& resolved_path, char separator) +{ + resolved_path = link_path; + return true; +} +#endif + // Kumu::PathList_t& Kumu::FindInPaths(const IPathMatch& Pattern, const Kumu::PathList_t& SearchPaths, @@ -1520,7 +1559,7 @@ h__DeletePath(const std::string& pathname) Result_t Kumu::DeletePath(const std::string& pathname) { - std::string c_pathname = PathMakeAbsolute(PathMakeCanonical(pathname)); + std::string c_pathname = PathMakeCanonical(PathMakeAbsolute(pathname)); DefaultLogSink().Debug("DeletePath (%s) c(%s)\n", pathname.c_str(), c_pathname.c_str()); return h__DeletePath(c_pathname); } diff --git a/src/KM_fileio.h b/src/KM_fileio.h index 0eb921b..a051e8e 100755 --- a/src/KM_fileio.h +++ b/src/KM_fileio.h @@ -133,6 +133,7 @@ namespace Kumu bool PathIsFile(const std::string& Path); // true if the path exists in the filesystem and is a file bool PathIsDirectory(const std::string& Path); // true if the path exists in the filesystem and is a directory fsize_t FileSize(const std::string& Path); // returns the size of a regular file, 0 for a directory or device + std::string PathCwd(); bool PathsAreEquivalent(const std::string& lhs, const std::string& rhs); // true if paths point to the same filesystem entry // Returns free space and total space available for the given path @@ -148,6 +149,7 @@ namespace Kumu std::string PathMakeAbsolute(const std::string& Path, char separator = '/'); // compute position of relative path using getcwd() std::string PathMakeLocal(const std::string& Path, const std::string& Parent); // remove Parent from front of Path, if it exists std::string PathMakeCanonical(const std::string& Path, char separator = '/'); // remove '.' and '..' + bool PathResolveLinks(const std::string& link_path, std::string& resolved_path, char separator = '/'); // common operations std::string PathBasename(const std::string& Path, char separator = '/'); // returns right-most path element (list back()) diff --git a/src/KM_util.cpp b/src/KM_util.cpp index 803b0ed..333b00a 100755 --- a/src/KM_util.cpp +++ b/src/KM_util.cpp @@ -1129,6 +1129,64 @@ Kumu::ByteString::Append(const byte_t* buf, ui32_t buf_len) return result; } +//------------------------------------------------------------------------------------------ + +// +const char* +Kumu::km_strnstr(const char *s, const char *find, size_t slen) +{ + char c, sc; + size_t len; + + if ( ( c = *find++ ) != '\0' ) + { + len = strlen(find); + do + { + do + { + if ( slen-- < 1 || ( sc = *s++ ) == '\0' ) + return 0; + } + while ( sc != c ); + + if ( len > slen ) + return 0; + } + while ( strncmp(s, find, len) != 0 ); + --s; + } + + return s; +} + +// +std::list<std::string> +Kumu::km_token_split(const std::string& str, const std::string& separator) +{ + std::list<std::string> components; + const char* pstr = str.c_str(); + const char* r = strstr(pstr, separator.c_str()); + + while ( r != 0 ) + { + assert(r >= pstr); + if ( r > pstr ) + { + std::string tmp_str; + tmp_str.assign(pstr, r - pstr); + components.push_back(tmp_str); + } + + pstr = r + separator.size(); + r = strstr(pstr, separator.c_str()); + } + + if( strlen(pstr) > 0 ) + components.push_back(std::string(pstr)); + + return components; +} // // end KM_util.cpp diff --git a/src/KM_util.h b/src/KM_util.h index f4de54e..a7667fc 100755 --- a/src/KM_util.h +++ b/src/KM_util.h @@ -534,6 +534,14 @@ namespace Kumu hexdump(buf.RoData(), buf.Length()); } + // Locates the first occurrence of the null-terminated string s2 in the string s1, where not more + // than n characters are searched. Characters that appear after a `\0' character are not searched. + // Reproduced here from BSD for portability. + const char *km_strnstr(const char *s1, const char *s2, size_t n); + + // Split the input string into tokens using the given separator. If the separator is not found the + // entire string will be returned as a single-item list. + std::list<std::string> km_token_split(const std::string& str, const std::string& separator); } // namespace Kumu diff --git a/src/Makefile.am b/src/Makefile.am index 81f1eeb..6cd2da3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -39,17 +39,34 @@ AM_CPPFLAGS += -DCONFIG_RANDOM_UUID endif # list of all the header files that should be installed -include_HEADERS = KM_error.h KM_fileio.h KM_log.h KM_memio.h KM_mutex.h \ - KM_platform.h KM_prng.h KM_util.h KM_tai.h KM_xml.h AS_DCP.h AS_02.h +include_HEADERS = \ + KM_error.h \ + KM_fileio.h \ + KM_log.h \ + KM_memio.h \ + KM_mutex.h \ + KM_platform.h \ + KM_prng.h \ + KM_util.h \ + KM_tai.h \ + KM_xml.h \ + AS_DCP.h + if DEV_HEADERS -include_HEADERS += S12MTimecode.h MDD.h Metadata.h KLV.h MXFTypes.h MXF.h Wav.h \ - PCMParserList.h +include_HEADERS += \ + S12MTimecode.h \ + MDD.h \ + Metadata.h \ + KLV.h \ + MXFTypes.h \ + MXF.h \ + Wav.h \ + PCMParserList.h nodist_include_HEADERS = TimedText_Transform.h endif - # list of the libraries to build and install -lib_LTLIBRARIES = libkumu.la libasdcp.la libas02.la +lib_LTLIBRARIES = libkumu.la libasdcp.la # sources for kumu library libkumu_la_SOURCES = KM_error.h KM_fileio.cpp KM_fileio.h KM_log.cpp KM_log.h \ @@ -76,20 +93,12 @@ libasdcp_la_SOURCES = MPEG2_Parser.cpp MPEG.cpp JP2K_Codestream_Parser.cpp \ if DEV_HEADERS nodist_libasdcp_la_SOURCES += TimedText_Transform.h TimedText_Transform.cpp endif + libasdcp_la_LDFLAGS = -release @VERSION@ # additional libraries to link against for a library libasdcp_la_LIBADD = libkumu.la libasdcp_la_CPPFLAGS = -DASDCP_PLATFORM=\"@host@\" - -# sources for as-02 library -libas02_la_SOURCES = \ - AS_02.h AS_02_MXF.cpp AS_02_JP2K.cpp AS_02_PCM.cpp h__02_Reader.cpp h__02_Writer.cpp AS_02_internal.h -libas02_la_LDFLAGS = -release @VERSION@ -libas02_la_LIBADD = libasdcp.la libkumu.la -libas02_la_CPPFLAGS = -DASDCP_PLATFORM=\"@host@\" - - # Python extension if PYTHON_USE lib_LTLIBRARIES += libpyasdcp.la @@ -132,7 +141,6 @@ endif # list of programs to be built and installed bin_PROGRAMS = \ asdcp-wrap asdcp-unwrap asdcp-util asdcp-info asdcp-test \ - as-02-wrap as-02-unwrap \ j2c-test blackwave klvwalk wavesplit \ kmfilegen kmrandgen kmuuidgen @@ -140,12 +148,6 @@ bin_PROGRAMS = \ asdcp_test_SOURCES = asdcp-test.cpp asdcp_test_LDADD = libasdcp.la -as_02_wrap_SOURCES = as-02-wrap.cpp -as_02_wrap_LDADD = libas02.la - -as_02_unwrap_SOURCES = as-02-unwrap.cpp -as_02_unwrap_LDADD = libas02.la - asdcp_wrap_SOURCES = asdcp-wrap.cpp asdcp_wrap_LDADD = libasdcp.la diff --git a/src/asdcp-info.cpp b/src/asdcp-info.cpp index 4cd755a..05e2c79 100755 --- a/src/asdcp-info.cpp +++ b/src/asdcp-info.cpp @@ -92,15 +92,16 @@ USAGE:%s [-h|-help] [-V]\n\ %s [options] <input-file>+\n\ \n\ Options:\n\ - -3 - Force stereoscopic interpretation of a JP2K file\n\ - -C - Do not 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 - Do not show bit-rate (Mb/s)\n\ - -V - Show version information\n\ + -3 - Force stereoscopic interpretation of a JP2K file\n\ + -C - Do not 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", @@ -122,17 +123,19 @@ public: bool showindex_flag; // true if index is to be displayed bool showheader_flag; // true if MXF file header is to be displayed bool stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first) - bool showid_flag; - bool showdescriptor_flag; - bool showcoding_flag; - bool showrate_flag; + 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(), showheader_flag(), stereo_image_flag(false), - showid_flag(false), showdescriptor_flag(false), showcoding_flag(true), - showrate_flag(true) + 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 ) { @@ -150,13 +153,20 @@ public: switch ( argv[i][1] ) { case '3': stereo_image_flag = true; break; - case 'C': showcoding_flag = false; break; + 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 = false; break; + case 'r': showrate_flag = true; break; + + case 't': + TEST_EXTRA_ARG(i, 't'); + max_bitrate = abs(atoi(argv[i])); + max_bitrate_flag = true; + break; + case 'V': version_flag = true; break; case 'v': verbose_flag = true; break; @@ -260,16 +270,21 @@ class MyTextDescriptor : public TimedText::TimedTextDescriptor } }; -// MSVC didn't like the function template, so now it's a static class method +// +// 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); public: - FileInfoWrapper() {} + FileInfoWrapper() : m_MaxBitrate(0.0), m_AvgBitrate(0.0) {} virtual ~FileInfoWrapper() {} Result_t @@ -285,19 +300,16 @@ public: if ( ASDCP_SUCCESS(result) ) { m_Desc.FillDescriptor(m_Reader); + m_Reader.FillWriterInfo(m_WriterInfo); - fprintf(stdout, "File essence type is %s, (%d frame%s).\n", + fprintf(stdout, "File essence type is %s, (%d edit unit%s).\n", type_string, m_Desc.ContainerDuration, (m_Desc.ContainerDuration==1?"":"s")); if ( Options.showheader_flag ) m_Reader.DumpHeaderMetadata(stream); if ( Options.showid_flag ) - { - WriterInfo WI; - m_Reader.FillWriterInfo(WI); - WriterInfoDump(WI, stream); - } + WriterInfoDump(m_WriterInfo, stream); if ( Options.showdescriptor_flag ) m_Desc.Dump(stream); @@ -314,7 +326,7 @@ public: } // - void dump_PictureEssenceCoding(FILE* stream = 0) + void get_PictureEssenceCoding(FILE* stream = 0) { const Dictionary& Dict = DefaultCompositeDict(); MXF::RGBAEssenceDescriptor *descriptor = 0; @@ -323,26 +335,108 @@ public: reinterpret_cast<MXF::InterchangeObject**>(&descriptor)); if ( KM_SUCCESS(result) ) + m_PictureEssenceCoding = descriptor->PictureEssenceCoding; + } + + + // + void dump_PictureEssenceCoding(FILE* stream = 0) + { + char buf[64]; + + if ( m_PictureEssenceCoding.HasValue() ) { const char *encoding_ul_type = "**UNKNOWN**"; - if ( descriptor->PictureEssenceCoding == UL(P_HFR_UL_2K) ) + if ( m_PictureEssenceCoding == UL(P_HFR_UL_2K) ) encoding_ul_type = "P-HFR-2K"; - else if ( descriptor->PictureEssenceCoding == UL(P_HFR_UL_4K) ) + else if ( m_PictureEssenceCoding == UL(P_HFR_UL_4K) ) encoding_ul_type = "**P-HFR-4K**"; - else if ( descriptor->PictureEssenceCoding == DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_2K) ) + else if ( m_PictureEssenceCoding == DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_2K) ) encoding_ul_type = "ST-429-4-2K"; - else if ( descriptor->PictureEssenceCoding == DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_4K) ) + else if ( m_PictureEssenceCoding == DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_4K) ) encoding_ul_type = "ST-429-4-4K"; - char buf[64]; - fprintf(stream, "PictureEssenceCoding: %s (%s)\n", descriptor->PictureEssenceCoding.EncodeString(buf, 64), encoding_ul_type); + fprintf(stream, "PictureEssenceCoding: %s (%s)\n", m_PictureEssenceCoding.EncodeString(buf, 64), encoding_ul_type); } } // + Result_t + test_rates(CommandOptions& Options, FILE* stream = 0) + { + static const double dci_max_bitrate = 250.0; + static const double p_hfr_max_bitrate = 400.0; + + double max_bitrate = Options.max_bitrate_flag ? Options.max_bitrate : dci_max_bitrate; + ui32_t errors = 0; + + if ( m_PictureEssenceCoding == UL(P_HFR_UL_2K) ) + { + if ( m_Desc.StoredWidth > 2048 ) // 4k + { + fprintf(stream, "4k images marked as 2k HFR.\n"); + ++errors; + } + + if ( m_Desc.SampleRate < ASDCP::EditRate_96 ) + { + fprintf(stream, "HFR UL used for fps < 96.\n"); + ++errors; + } + + if ( ! Options.max_bitrate_flag ) + max_bitrate = p_hfr_max_bitrate; + } + else if ( m_PictureEssenceCoding == UL(P_HFR_UL_4K) ) + { + fprintf(stream, "4k HFR support undefined.\n"); + ++errors; + + if ( m_Desc.StoredWidth <= 2048 ) // 2k + { + fprintf(stream, "2k images marked as 4k HFR.\n"); + ++errors; + } + } + else if ( m_PictureEssenceCoding != DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_2K) + && m_PictureEssenceCoding != DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_4K) ) + { + fprintf(stream, "Unknown PictureEssenceCoding UL value.\n"); + ++errors; + } + else + { + if ( m_PictureEssenceCoding == DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_2K) ) + { + if ( m_Desc.StoredWidth > 2048 ) // 4k + { + fprintf(stream, "4k images marked as 2k ST 429-4.\n"); + ++errors; + } + } + else if ( m_PictureEssenceCoding == DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_4K) ) + { + if ( m_Desc.StoredWidth <= 2048 ) // 2k + { + fprintf(stream, "2k images marked as 4k ST 429-4.\n"); + ++errors; + } + } + } + + if ( m_MaxBitrate > max_bitrate ) + { + fprintf(stream, "Bitrate %0.0f exceeds maximum %0.0f (see option -r).\n", m_MaxBitrate, max_bitrate); + ++errors; + } + + return errors ? RESULT_FAIL : RESULT_OK; + } + + // void - dump_Bitrate(FILE* stream = 0) + calc_Bitrate(FILE* stream = 0) { MXF::OPAtomIndexFooter& footer = m_Reader.OPAtomIndexFooter(); ui64_t total_frame_bytes = 0, last_stream_offset = 0; @@ -369,13 +463,22 @@ public: } } - // we did not test the first or last frame; scale to return bits when the input is bytes + // scale bytes to megabits static const double mega_const = 1 / ( 1024.0 * 1024.0 / 8.0 ); + + // we did not accumulate the first or last frame, so duration -= 2 double avg_bytes_frame = total_frame_bytes / ( m_Desc.ContainerDuration - 2 ); - double avg_mbits_second = avg_bytes_frame * mega_const * m_Desc.EditRate.Quotient(); - fprintf(stream, "Max BitRate: %0.2f Mb/s\n", largest_frame * mega_const * m_Desc.EditRate.Quotient()); - fprintf(stream, "Average BitRate: %0.2f Mb/s\n", avg_bytes_frame * mega_const * m_Desc.EditRate.Quotient()); + 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); } // @@ -431,22 +534,38 @@ show_file_info(CommandOptions& Options) FileInfoWrapper<ASDCP::JP2K::MXFSReader, MyStereoPictureDescriptor> wrapper; result = wrapper.file_info(Options, "JPEG 2000 stereoscopic pictures"); - if ( ASDCP_SUCCESS(result) && Options.showcoding_flag ) - wrapper.dump_PictureEssenceCoding(stdout); + if ( KM_SUCCESS(result) ) + { + wrapper.get_PictureEssenceCoding(); + wrapper.calc_Bitrate(); - if ( ASDCP_SUCCESS(result) && Options.showrate_flag ) - wrapper.dump_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 { FileInfoWrapper<ASDCP::JP2K::MXFReader, MyPictureDescriptor>wrapper; result = wrapper.file_info(Options, "JPEG 2000 pictures"); - if ( ASDCP_SUCCESS(result) && Options.showcoding_flag ) - wrapper.dump_PictureEssenceCoding(stdout); + if ( KM_SUCCESS(result) ) + { + wrapper.get_PictureEssenceCoding(); + wrapper.calc_Bitrate(); - if ( ASDCP_SUCCESS(result) && Options.showrate_flag ) - wrapper.dump_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_JPEG_2000_S ) @@ -454,11 +573,19 @@ show_file_info(CommandOptions& Options) FileInfoWrapper<ASDCP::JP2K::MXFSReader, MyStereoPictureDescriptor>wrapper; result = wrapper.file_info(Options, "JPEG 2000 stereoscopic pictures"); - if ( ASDCP_SUCCESS(result) && Options.showcoding_flag ) - wrapper.dump_PictureEssenceCoding(stdout); + if ( KM_SUCCESS(result) ) + { + wrapper.get_PictureEssenceCoding(); + wrapper.calc_Bitrate(); - if ( ASDCP_SUCCESS(result) && Options.showrate_flag ) - wrapper.dump_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_TIMED_TEXT ) { diff --git a/src/asdcp-test.cpp b/src/asdcp-test.cpp index 384324d..56bc5ab 100755 --- a/src/asdcp-test.cpp +++ b/src/asdcp-test.cpp @@ -292,6 +292,10 @@ public: // Rational PictureRate() { + if ( picture_rate == 16 ) return EditRate_16; + if ( picture_rate == 18 ) return EditRate_18; + if ( picture_rate == 20 ) return EditRate_20; + if ( picture_rate == 22 ) return EditRate_22; if ( picture_rate == 23 ) return EditRate_23_98; if ( picture_rate == 24 ) return EditRate_24; if ( picture_rate == 25 ) return EditRate_25; @@ -308,6 +312,10 @@ public: // const char* szPictureRate() { + if ( picture_rate == 16 ) return "16"; + if ( picture_rate == 18 ) return "18.182"; + if ( picture_rate == 20 ) return "20"; + if ( picture_rate == 22 ) return "21.818"; if ( picture_rate == 23 ) return "23.976"; if ( picture_rate == 24 ) return "24"; if ( picture_rate == 25 ) return "25"; diff --git a/src/asdcp-unwrap.cpp b/src/asdcp-unwrap.cpp index ebe483c..e9b9fee 100755 --- a/src/asdcp-unwrap.cpp +++ b/src/asdcp-unwrap.cpp @@ -157,6 +157,10 @@ public: // Rational PictureRate() { + if ( picture_rate == 16 ) return EditRate_16; + if ( picture_rate == 18 ) return EditRate_18; + if ( picture_rate == 20 ) return EditRate_20; + if ( picture_rate == 22 ) return EditRate_22; if ( picture_rate == 23 ) return EditRate_23_98; if ( picture_rate == 24 ) return EditRate_24; if ( picture_rate == 25 ) return EditRate_25; @@ -204,10 +208,6 @@ public: case 'b': TEST_EXTRA_ARG(i, 'b'); fb_size = abs(atoi(argv[i])); - - if ( verbose_flag ) - fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size); - break; case 'd': @@ -325,7 +325,7 @@ read_MPEG2_file(CommandOptions& Options) } } - if ( ASDCP_SUCCESS(result) ) + if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) ) { char filename[256]; snprintf(filename, 256, "%s.ves", Options.file_prefix); @@ -367,8 +367,11 @@ read_MPEG2_file(CommandOptions& Options) if ( Options.verbose_flag ) FrameBuffer.Dump(stderr, Options.fb_dump_size); - ui32_t write_count = 0; - result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); + if ( ! Options.no_write_flag ) + { + ui32_t write_count = 0; + result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); + } } } @@ -494,13 +497,16 @@ read_JP2K_S_file(CommandOptions& Options) if ( ASDCP_SUCCESS(result) ) { - Kumu::FileWriter OutFile; - ui32_t write_count; - snprintf(filename, filename_max, left_format, Options.file_prefix, i); - result = OutFile.OpenWrite(filename); + 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); - 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); @@ -511,13 +517,19 @@ read_JP2K_S_file(CommandOptions& Options) if ( ASDCP_SUCCESS(result) ) { - Kumu::FileWriter OutFile; - ui32_t write_count; - snprintf(filename, filename_max, right_format, Options.file_prefix, i); - result = OutFile.OpenWrite(filename); + 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); - 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); } } @@ -588,14 +600,17 @@ read_JP2K_file(CommandOptions& Options) if ( ASDCP_SUCCESS(result) ) { - 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.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); @@ -638,10 +653,20 @@ read_PCM_file(CommandOptions& Options) && ADesc.EditRate != EditRate_60 ) ADesc.EditRate = Options.PictureRate(); - FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc)); + if ( Options.fb_size != FRAME_BUFFER_SIZE ) + { + FrameBuffer.Capacity(Options.fb_size); + } + else + { + FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc)); + } if ( Options.verbose_flag ) - PCM::AudioDescriptorDump(ADesc); + { + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + PCM::AudioDescriptorDump(ADesc); + } } if ( ASDCP_SUCCESS(result) ) @@ -663,9 +688,13 @@ read_PCM_file(CommandOptions& Options) } ADesc.ContainerDuration = last_frame - Options.start_frame; - OutWave.OpenWrite(ADesc, Options.file_prefix, - ( Options.split_wav ? WavFileWriter::ST_STEREO : - ( Options.mono_wav ? WavFileWriter::ST_MONO : WavFileWriter::ST_NONE ) )); + + 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 ) )); + } } if ( ASDCP_SUCCESS(result) && Options.key_flag ) @@ -699,7 +728,10 @@ read_PCM_file(CommandOptions& Options) if ( Options.verbose_flag ) FrameBuffer.Dump(stderr, Options.fb_dump_size); - result = OutWave.WriteFrame(FrameBuffer); + if ( ! Options.no_write_flag ) + { + result = OutWave.WriteFrame(FrameBuffer); + } } } @@ -767,7 +799,7 @@ read_timed_text_file(CommandOptions& Options) result = Reader.ReadTimedTextResource(XMLDoc, Context, HMAC); - if ( ASDCP_SUCCESS(result) ) + if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) ) { Kumu::FileWriter Writer; result = Writer.OpenWrite(Options.file_prefix); @@ -780,18 +812,16 @@ read_timed_text_file(CommandOptions& Options) { result = Reader.ReadAncillaryResource(ri->ResourceID, FrameBuffer, Context, HMAC); - if ( ASDCP_SUCCESS(result) ) + if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) ) { Kumu::FileWriter Writer; result = Writer.OpenWrite(Kumu::PathJoin(out_path, Kumu::UUID(ri->ResourceID).EncodeHex(buf, 64)).c_str()); if ( ASDCP_SUCCESS(result) ) - { - if ( Options.verbose_flag ) - FrameBuffer.Dump(stderr, Options.fb_dump_size); + result = Writer.Write(FrameBuffer.RoData(), FrameBuffer.Size(), &write_count); - result = Writer.Write(FrameBuffer.RoData(), FrameBuffer.Size(), &write_count); - } + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); } } diff --git a/src/asdcp-wrap.cpp b/src/asdcp-wrap.cpp index b6880ac..bbff82a 100755 --- a/src/asdcp-wrap.cpp +++ b/src/asdcp-wrap.cpp @@ -56,6 +56,11 @@ using namespace ASDCP; const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte; +const byte_t P_HFR_UL_2K[16] = { + 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, + 0x0e, 0x16, 0x02, 0x02, 0x03, 0x01, 0x01, 0x03 +}; + //------------------------------------------------------------------------------------------ // // command line option parser class @@ -120,8 +125,8 @@ USAGE: %s [-h|-help] [-V]\n\ Options:\n\ -3 - Create a stereoscopic image file. Expects two\n\ directories of JP2K codestreams (directories must have\n\ - an equal number of frames; left eye is first).\n\ - -C <UL> - Set ChannelAssignment UL value\n\ + an equal number of frames; the left eye is first)\n\ + -C <UL> - Set ChannelAssignment UL value in a PCM file\n\ -h | -help - Show help\n\ -V - Show version information\n\ -e - Encrypt MPEG or JP2K headers (default)\n\ @@ -139,6 +144,7 @@ Options:\n\ '7.1DS', 'WTF'\n\ Default is no label (valid for Interop only).\n\ -L - Write SMPTE UL values instead of MXF Interop\n\ + -P <UL> - Set PictureEssenceCoding UL value in a JP2K file\n\ -p <rate> - fps of picture when wrapping PCM or JP2K:\n\ Use one of [23|24|25|30|48|50|60], 24 is default\n\ -v - Verbose, prints informative messages to stderr\n\ @@ -189,18 +195,12 @@ public: bool asset_id_flag; // true if an asset ID was given bool encrypt_header_flag; // true if mpeg headers are to be encrypted bool write_hmac; // true if HMAC values are to be generated and written - /// bool read_hmac; // true if HMAC values are to be validated - /// bool split_wav; // true if PCM is to be extracted to stereo WAV files - /// bool mono_wav; // true if PCM is to be extracted to mono WAV files bool verbose_flag; // true if the verbose option was selected ui32_t fb_dump_size; // number of bytes of frame buffer to dump - /// bool showindex_flag; // true if index is to be displayed - /// bool showheader_flag; // true if MXF file header is to be displayed bool no_write_flag; // true if no output files are to be written bool version_flag; // true if the version display option was selected bool help_flag; // true if the help display option was selected bool stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first) - /// ui32_t number_width; // number of digits in a serialized filename (for JPEG extract) ui32_t start_frame; // frame number to begin processing ui32_t duration; // number of frames to be processed bool use_smpte_labels; // if true, SMPTE UL values will be written instead of MXF Interop values @@ -216,10 +216,15 @@ public: bool show_ul_values; /// if true, dump the UL table before going tp work. Kumu::PathList_t filenames; // list of filenames to be processed UL channel_assignment; + UL picture_coding; // Rational PictureRate() { + if ( picture_rate == 16 ) return EditRate_16; + if ( picture_rate == 18 ) return EditRate_18; + if ( picture_rate == 20 ) return EditRate_20; + if ( picture_rate == 22 ) return EditRate_22; if ( picture_rate == 23 ) return EditRate_23_98; if ( picture_rate == 24 ) return EditRate_24; if ( picture_rate == 25 ) return EditRate_25; @@ -236,6 +241,10 @@ public: // const char* szPictureRate() { + if ( picture_rate == 16 ) return "16"; + if ( picture_rate == 18 ) return "18.182"; + if ( picture_rate == 20 ) return "20"; + if ( picture_rate == 22 ) return "21.818"; if ( picture_rate == 23 ) return "23.976"; if ( picture_rate == 24 ) return "24"; if ( picture_rate == 25 ) return "25"; @@ -306,7 +315,7 @@ public: break; case 'C': - TEST_EXTRA_ARG(i, 'U'); + TEST_EXTRA_ARG(i, 'C'); if ( ! channel_assignment.DecodeHex(argv[i]) ) { fprintf(stderr, "Error decoding UL value: %s\n", argv[i]); @@ -365,6 +374,15 @@ public: case 'L': use_smpte_labels = true; break; case 'M': write_hmac = false; break; + case 'P': + TEST_EXTRA_ARG(i, 'P'); + if ( ! picture_coding.DecodeHex(argv[i]) ) + { + fprintf(stderr, "Error decoding UL value: %s\n", argv[i]); + return; + } + break; + case 'p': TEST_EXTRA_ARG(i, 'p'); picture_rate = abs(atoi(argv[i])); @@ -536,6 +554,35 @@ write_MPEG2_file(CommandOptions& Options) //------------------------------------------------------------------------------------------ + +// return false if an error is discovered +bool +check_phfr_params(CommandOptions& Options, JP2K::PictureDescriptor& PDesc) +{ + Rational rate = Options.PictureRate(); + if ( rate != EditRate_96 && rate != EditRate_100 && rate != EditRate_120 ) + return true; + + if ( PDesc.StoredWidth > 2048 ) + { + fprintf(stderr, "P-HFR files currently limited to 2K.\n"); + return false; + } + + if ( ! Options.use_smpte_labels ) + { + fprintf(stderr, "P-HFR files must be written using SMPTE labels. Use option '-L'.\n"); + return false; + } + + // 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; +} + +//------------------------------------------------------------------------------------------ // JPEG 2000 essence // Write one or more plaintext JPEG 2000 stereoscopic codestream pairs to a plaintext ASDCP file @@ -582,6 +629,9 @@ write_JP2K_S_file(CommandOptions& Options) } } + if ( ! check_phfr_params(Options, PDesc) ) + return RESULT_FAIL; + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) { WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here @@ -623,6 +673,14 @@ write_JP2K_S_file(CommandOptions& Options) if ( ASDCP_SUCCESS(result) ) result = Writer.OpenWrite(Options.out_file.c_str(), Info, PDesc); + + if ( ASDCP_SUCCESS(result) && Options.picture_coding.HasValue() ) + { + MXF::RGBAEssenceDescriptor *descriptor = 0; + Writer.OPAtomHeader().GetMDObjectByType(DefaultSMPTEDict().ul(MDD_RGBAEssenceDescriptor), + reinterpret_cast<MXF::InterchangeObject**>(&descriptor)); + descriptor->PictureEssenceCoding = Options.picture_coding; + } } if ( ASDCP_SUCCESS(result) ) @@ -706,6 +764,9 @@ write_JP2K_file(CommandOptions& Options) } } + if ( ! check_phfr_params(Options, PDesc) ) + return RESULT_FAIL; + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) { WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here @@ -747,6 +808,14 @@ write_JP2K_file(CommandOptions& Options) if ( ASDCP_SUCCESS(result) ) result = Writer.OpenWrite(Options.out_file.c_str(), Info, PDesc); + + if ( ASDCP_SUCCESS(result) && Options.picture_coding.HasValue() ) + { + MXF::RGBAEssenceDescriptor *descriptor = 0; + Writer.OPAtomHeader().GetMDObjectByType(DefaultSMPTEDict().ul(MDD_RGBAEssenceDescriptor), + reinterpret_cast<MXF::InterchangeObject**>(&descriptor)); + descriptor->PictureEssenceCoding = Options.picture_coding; + } } if ( ASDCP_SUCCESS(result) ) diff --git a/src/blackwave.cpp b/src/blackwave.cpp index 3e75c3e..35e5e77 100644 --- a/src/blackwave.cpp +++ b/src/blackwave.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2009, John Hurst +Copyright (c) 2005-2012, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -56,7 +56,7 @@ banner(FILE* stream = stderr) { fprintf(stream, "\n\ %s (asdcplib %s)\n\n\ -Copyright (c) 2005-2009 John Hurst\n\n\ +Copyright (c) 2005-2012 John Hurst\n\n\ %s is part of asdcplib.\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\ @@ -73,7 +73,8 @@ USAGE: %s [-v|-h[-d]] <filename>\n\ \n\ -V - Show version\n\ -h - Show help\n\ - -d <duration> - Number of 2k-sample frames to process, default 1440\n\ + -d <duration> - Number of edit units to process, default 1440\n\ + -9 - Make a 96 kHz file (default 48 kHz)\n\ \n\ Other Options:\n\ -v - Verbose, show extra detail during run\n\ @@ -94,6 +95,7 @@ public: bool verbose_flag; // true if the verbose option was selected bool version_flag; // true if the version display option was selected bool help_flag; // true if the help display option was selected + bool s96_flag; // true if the samples should be at 96 kHz ui32_t duration; // number of frames to be processed const char* filename; // filename prefix for files written by the extract mode @@ -103,7 +105,7 @@ public: { for ( int i = 1; i < argc; i++ ) { - if ( argv[i][0] == '-' && isalpha(argv[i][1]) && argv[i][2] == 0 ) + if ( argv[i][0] == '-' && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) ) && argv[i][2] == 0 ) { switch ( argv[i][1] ) { @@ -116,6 +118,10 @@ public: duration = atoi(argv[i]); // TODO: test for negative value, should use strtol() break; + case '9': + s96_flag = true; + break; + default: fprintf(stderr, "Unrecognized option: %c\n", argv[i][1]); return; @@ -153,12 +159,12 @@ make_black_wav_file(CommandOptions& Options) PCM::AudioDescriptor ADesc; ADesc.EditRate = Rational(24,1); - ADesc.AudioSamplingRate = ASDCP::SampleRate_48k; + ADesc.AudioSamplingRate = Options.s96_flag ? ASDCP::SampleRate_96k : ASDCP::SampleRate_48k; ADesc.Locked = 0; ADesc.ChannelCount = 1; ADesc.QuantizationBits = 24; ADesc.BlockAlign = 3; - ADesc.AvgBps = 14400; + ADesc.AvgBps = ADesc.BlockAlign * ADesc.AudioSamplingRate.Quotient(); ADesc.LinkedTrackID = 1; ADesc.ContainerDuration = Options.duration; @@ -169,8 +175,8 @@ make_black_wav_file(CommandOptions& Options) if ( Options.verbose_flag ) { - fprintf(stderr, "48Khz PCM Audio, %s fps (%u spf)\n", "24", - PCM::CalcSamplesPerFrame(ADesc)); + fprintf(stderr, "%s kHz PCM Audio, %s fps (%u spf)\n", "24", + (Options.s96_flag?"96":"48"), PCM::CalcSamplesPerFrame(ADesc)); fputs("AudioDescriptor:\n", stderr); PCM::AudioDescriptorDump(ADesc); } diff --git a/src/h__Reader.cpp b/src/h__Reader.cpp index 23b1e1a..da2aca2 100755 --- a/src/h__Reader.cpp +++ b/src/h__Reader.cpp @@ -59,81 +59,21 @@ ASDCP::default_md_object_init() } -// -ASDCP::h__Reader::h__Reader(const Dictionary& d) : - m_HeaderPart(m_Dict), m_BodyPart(m_Dict), m_FooterPart(m_Dict), m_Dict(&d), m_EssenceStart(0) -{ - default_md_object_init(); -} - -ASDCP::h__Reader::~h__Reader() -{ - Close(); -} - -void -ASDCP::h__Reader::Close() -{ - m_File.Close(); -} - //------------------------------------------------------------------------------------------ // // -Result_t -ASDCP::h__Reader::InitInfo() -{ - assert(m_Dict); - InterchangeObject* Object; - - m_Info.LabelSetType = LS_MXF_UNKNOWN; - - if ( m_HeaderPart.OperationalPattern.ExactMatch(MXFInterop_OPAtom_Entry().ul) ) - m_Info.LabelSetType = LS_MXF_INTEROP; - else if ( m_HeaderPart.OperationalPattern.ExactMatch(SMPTE_390_OPAtom_Entry().ul) ) - m_Info.LabelSetType = LS_MXF_SMPTE; - - // Identification - Result_t result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object); - - if( ASDCP_SUCCESS(result) ) - MD_to_WriterInfo((Identification*)Object, m_Info); - - // SourcePackage - if( ASDCP_SUCCESS(result) ) - result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object); - - if( ASDCP_SUCCESS(result) ) - { - SourcePackage* SP = (SourcePackage*)Object; - memcpy(m_Info.AssetUUID, SP->PackageUID.Value() + 16, UUIDlen); - } - - // optional CryptographicContext - if( ASDCP_SUCCESS(result) ) - { - Result_t cr_result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CryptographicContext), &Object); - - if( ASDCP_SUCCESS(cr_result) ) - MD_to_CryptoInfo((CryptographicContext*)Object, m_Info, *m_Dict); - } +ASDCP::h__ASDCPReader::h__ASDCPReader(const Dictionary& d) : MXF::TrackFileReader<OPAtomHeader, OPAtomIndexFooter>(d), m_BodyPart(m_Dict) {} +ASDCP::h__ASDCPReader::~h__ASDCPReader() {} - return result; -} - -// standard method of opening an MXF file for read +// AS-DCP method of opening an MXF file for read Result_t -ASDCP::h__Reader::OpenMXFRead(const char* filename) +ASDCP::h__ASDCPReader::OpenMXFRead(const char* filename) { - m_LastPosition = 0; - Result_t result = m_File.OpenRead(filename); + Result_t result = ASDCP::MXF::TrackFileReader<OPAtomHeader, OPAtomIndexFooter>::OpenMXFRead(filename); - if ( ASDCP_SUCCESS(result) ) - result = m_HeaderPart.InitFromFile(m_File); - - 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 @@ -142,20 +82,44 @@ ASDCP::h__Reader::OpenMXFRead(const char* filename) 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); } - - m_EssenceStart = m_File.Tell(); } + if ( KM_SUCCESS(result) ) + m_HeaderPart.BodyOffset = m_File.Tell(); + return result; } +// +Result_t +ASDCP::h__ASDCPReader::InitInfo() +{ + Result_t result = ASDCP::MXF::TrackFileReader<OPAtomHeader, OPAtomIndexFooter>::InitInfo(); + + if( KM_SUCCESS(result) ) + { + InterchangeObject* Object; + + m_Info.LabelSetType = LS_MXF_UNKNOWN; + + if ( m_HeaderPart.OperationalPattern.ExactMatch(MXFInterop_OPAtom_Entry().ul) ) + { + m_Info.LabelSetType = LS_MXF_INTEROP; + } + else if ( m_HeaderPart.OperationalPattern.ExactMatch(SMPTE_390_OPAtom_Entry().ul) ) + { + m_Info.LabelSetType = LS_MXF_SMPTE; + } + } -// standard method of populating the in-memory index + return result; +} + +// AS-DCP method of populating the in-memory index Result_t -ASDCP::h__Reader::InitMXFIndex() +ASDCP::h__ASDCPReader::InitMXFIndex() { if ( ! m_File.IsOpen() ) return RESULT_INIT; @@ -169,11 +133,26 @@ ASDCP::h__Reader::InitMXFIndex() } if ( ASDCP_SUCCESS(result) ) - m_File.Seek(m_EssenceStart); + m_File.Seek(m_HeaderPart.BodyOffset); return result; } + +// AS-DCP method of reading a plaintext or encrypted frame +Result_t +ASDCP::h__ASDCPReader::ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf, + const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC) +{ + return ASDCP::MXF::TrackFileReader<OPAtomHeader, OPAtomIndexFooter>::ReadEKLVFrame(m_HeaderPart, FrameNum, FrameBuf, + EssenceUL, Ctx, HMAC); +} + + +//------------------------------------------------------------------------------------------ +// + + // Result_t ASDCP::KLReader::ReadKLFromFile(Kumu::FileReader& Reader) @@ -229,55 +208,26 @@ ASDCP::KLReader::ReadKLFromFile(Kumu::FileReader& Reader) return InitFromBuffer(m_KeyBuf, header_length); } -// standard method of reading a plaintext or encrypted frame +// base subroutine for reading a KLV packet, assumes file position is at the first byte of the packet Result_t -ASDCP::h__Reader::ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf, - const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC) -{ - // look up frame index node - IndexTableSegment::IndexEntry TmpEntry; - - if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) ) - { - DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum); - return RESULT_RANGE; - } - - // get frame position and go read the frame's key and length - Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset; - Result_t result = RESULT_OK; - - if ( FilePosition != m_LastPosition ) - { - m_LastPosition = FilePosition; - result = m_File.Seek(FilePosition); - } - - if( ASDCP_SUCCESS(result) ) - result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC); - - return result; -} - - -Result_t -ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf, - const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC) +ASDCP::Read_EKLV_Packet(Kumu::FileReader& File, const ASDCP::Dictionary& Dict, const MXF::OPAtomHeader& HeaderPart, + 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) { KLReader Reader; - Result_t result = Reader.ReadKLFromFile(m_File); + Result_t result = Reader.ReadKLFromFile(File); - if ( ASDCP_FAILURE(result) ) + if ( KM_FAILURE(result) ) return result; UL Key(Reader.Key()); ui64_t PacketLength = Reader.Length(); - m_LastPosition = m_LastPosition + Reader.KLLength() + PacketLength; - assert(m_Dict); + LastPosition = LastPosition + Reader.KLLength() + PacketLength; - if ( Key.MatchIgnoreStream(m_Dict->ul(MDD_CryptEssence)) ) // ignore the stream numbers + if ( Key.MatchIgnoreStream(Dict.ul(MDD_CryptEssence)) ) // ignore the stream numbers { - if ( ! m_Info.EncryptedEssence ) + if ( ! Info.EncryptedEssence ) { DefaultLogSink().Error("EKLV packet found, no Cryptographic Context in header.\n"); return RESULT_FORMAT; @@ -285,10 +235,9 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::Fra // read encrypted triplet value into internal buffer assert(PacketLength <= 0xFFFFFFFFL); - m_CtFrameBuf.Capacity((ui32_t) PacketLength); + CtFrameBuf.Capacity((ui32_t) PacketLength); ui32_t read_count; - result = m_File.Read(m_CtFrameBuf.Data(), (ui32_t) PacketLength, - &read_count); + result = File.Read(CtFrameBuf.Data(), (ui32_t) PacketLength, &read_count); if ( ASDCP_FAILURE(result) ) return result; @@ -299,17 +248,17 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::Fra return RESULT_FORMAT; } - m_CtFrameBuf.Size((ui32_t) PacketLength); + CtFrameBuf.Size((ui32_t) PacketLength); // should be const but mxflib::ReadBER is not - byte_t* ess_p = m_CtFrameBuf.Data(); + byte_t* ess_p = CtFrameBuf.Data(); // read context ID length if ( ! Kumu::read_test_BER(&ess_p, UUIDlen) ) return RESULT_FORMAT; // test the context ID - if ( memcmp(ess_p, m_Info.ContextID, UUIDlen) != 0 ) + if ( memcmp(ess_p, Info.ContextID, UUIDlen) != 0 ) { DefaultLogSink().Error("Packet's Cryptographic Context ID does not match the header.\n"); return RESULT_FORMAT; @@ -331,11 +280,11 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::Fra if ( ! UL(ess_p).MatchIgnoreStream(EssenceUL) ) // ignore the stream number { char strbuf[IntBufferLen]; - const MDDEntry* Entry = m_Dict->FindUL(Key.Value()); + const MDDEntry* Entry = Dict.FindUL(Key.Value()); if ( Entry == 0 ) - DefaultLogSink().Warn("Unexpected Encrypted Essence UL found: %s.\n", Key.EncodeString(strbuf, IntBufferLen)); + DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Key.EncodeString(strbuf, IntBufferLen)); else - DefaultLogSink().Warn("Unexpected Encrypted Essence UL found: %s.\n", Entry->name); + DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Entry->name); return RESULT_FORMAT; } ess_p += SMPTE_UL_LENGTH; @@ -363,7 +312,7 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::Fra return RESULT_FORMAT; } - ui32_t tmp_len = esv_length + (m_Info.UsesHMAC ? klv_intpack_size : 0); + ui32_t tmp_len = esv_length + (Info.UsesHMAC ? klv_intpack_size : 0); if ( PacketLength < tmp_len ) { @@ -385,10 +334,10 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::Fra FrameBuf.FrameNumber(FrameNum); // detect and test integrity pack - if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC && HMAC ) + if ( ASDCP_SUCCESS(result) && Info.UsesHMAC && HMAC ) { IntegrityPack IntPack; - result = IntPack.TestValues(TmpWrapper, m_Info.AssetUUID, SequenceNum, HMAC); + result = IntPack.TestValues(TmpWrapper, Info.AssetUUID, SequenceNum, HMAC); } } else // return ciphertext to caller @@ -421,7 +370,7 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::Fra // read the data into the supplied buffer ui32_t read_count; assert(PacketLength <= 0xFFFFFFFFL); - result = m_File.Read(FrameBuf.Data(), (ui32_t) PacketLength, &read_count); + result = File.Read(FrameBuf.Data(), (ui32_t) PacketLength, &read_count); if ( ASDCP_FAILURE(result) ) return result; @@ -443,11 +392,12 @@ ASDCP::h__Reader::ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::Fra else { char strbuf[IntBufferLen]; - const MDDEntry* Entry = m_Dict->FindUL(Key.Value()); + const MDDEntry* Entry = Dict.FindUL(Key.Value()); if ( Entry == 0 ) DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Key.EncodeString(strbuf, IntBufferLen)); else DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Entry->name); + return RESULT_FORMAT; } diff --git a/src/path-test.cpp b/src/path-test.cpp index ce81b8f..30a5e09 100644 --- a/src/path-test.cpp +++ b/src/path-test.cpp @@ -111,8 +111,15 @@ main(int argc, const char** argv) FindInPaths(PathMatchAny(), InList, OutList); PathList_t::iterator pi; - for ( pi = OutList.begin(); pi != OutList.end(); pi++ ) - cerr << *pi << endl; + if ( false ) + { + for ( pi = OutList.begin(); pi != OutList.end(); pi++ ) + cerr << *pi << endl; + } + else + { + cerr << OutList.size() << ( ( OutList.size() == 1 ) ? " file" : " files" ) << endl; + } cerr << "----------------------------------" << endl; OutList.clear(); |
