From 528cacb6122b33f73a805fbb47b4ae83a46db418 Mon Sep 17 00:00:00 2001 From: mschroffel Date: Thu, 19 Feb 2015 22:42:18 +0000 Subject: [PATCH] banner updates to 2015 --- README | 41 +++++- configure.ac | 2 +- src/AS_02.h | 14 +- src/AS_02_PCM.cpp | 64 ++++----- src/AS_DCP_MXF.cpp | 12 +- src/AS_DCP_TimedText.cpp | 3 +- src/KM_fileio.cpp | 16 ++- src/KM_util.cpp | 14 +- src/KM_util.h | 5 +- src/KM_xml.cpp | 271 +++++++++++++++++---------------------- src/KM_xml.h | 9 +- src/MXFTypes.cpp | 59 ++++++++- src/MXFTypes.h | 110 +++++++++++++++- src/Metadata.cpp | 2 +- src/Metadata.h | 4 +- src/PCMParserList.cpp | 47 +++++-- src/PCM_Parser.cpp | 47 ++++--- src/as-02-unwrap.cpp | 13 +- src/as-02-wrap.cpp | 14 +- src/asdcp-info.cpp | 2 +- src/asdcp-test.cpp | 2 +- src/asdcp-unwrap.cpp | 2 +- src/asdcp-wrap.cpp | 24 +++- src/phdr-unwrap.cpp | 2 +- src/phdr-wrap.cpp | 2 +- win32/Makefile.mak | 4 +- 26 files changed, 506 insertions(+), 279 deletions(-) diff --git a/README b/README index 2ba249e..b49cf34 100755 --- a/README +++ b/README @@ -150,7 +150,46 @@ command-line utilities all respond to -h. Change History -2015-01-22 - PHDR feature, bug fixes + +2015-02-19 - PHDR feature, bug fixes + o Modified PCMParser and PCMParserList to return partial frame buffers at the + end of a WAV input file. This was needed to allow wrapping all samples into + an AS-02 audio file (which is clip-wrapped) in the case where the input file + has an odd number of samples with respect to the frame buffer size being + used. If there is more than one input file the length of the last buffer + will be determined by PCMParserList to be the shortest of the input files. + Prior to this change, partial samples in an input WAV file have been + abandoned (i.e., not written out to the MXF file). As a result, AS-DCP + applications will have to decide whether to abandon the partial last frame + (usually detected by testing frame_buffer.Size() != frame_buffer.Capacity()) + or write it to the MXF file. Programs written to the old API will write the + partial frame (i.e., new behavior.) This should not be harmful since the + remainder of the buffer is zeroed and the output file will contain one + additional edit unit compared to the previous version. + o asdcp-wrap has been modified to test for the partial buffer and by default + will complain and abandon the buffer (i.e., same behavior but with a warning + message.) A new command line switch (-g) alters this behavior and writes + the buffer to the MXF file (it still warns the user that this condition is + present.) + o as-02-wrap now wraps all samples from the input file to the MXF file. There + is no padding, the clip is exactly the set of samples from the input. + o as-02 unwrap is temporarily restricted to creating wav files that are + aligned with the frame buffer size. This means that the output file will + be longer than the original WAV input in the case where the input file has + an odd number of samples with respect to the frame buffer size being used. + The pad samples are zero (silence). + o Modified CalcFramesFromDurationInSamples() to increment the count by one for + the case where the input file has an odd number of samples with respect to + the frame buffer size being used (previously it truncated the odd samples.) + o Fixed ST 429-5 / ST 2067-5 wrapping to increase header space when ancillary + resources are present (fixes a bug that cause the header to overflow the + allotted space when large numbers of PNG files were present.) + o Refactored GetXMLDocType() to use the XML parser. + o Added ParseFirstFromString() method to Kumu::XMLElement + o Removed Kumu::StringIsXML from the API. + o Added ASDCP::MXF::RGBALayout type + o Added J2CLayout property to JPEG2000PictureSubDescriptor + o Changed km_token_split() to retain empty elements in the output list o Added PHDR wrapping for AS-02. o Added J2CLayout property to the JPEG2000PictureSubDescriptor. This support is preliminary: the Raw data type is being used instead of diff --git a/configure.ac b/configure.ac index 19b4057..35a981d 100644 --- a/configure.ac +++ b/configure.ac @@ -37,7 +37,7 @@ AC_PREREQ([2.59]) # For example, if asdcplib version 1.0.0 were modified to accomodate changes # in file format, and if no changes were made to AS_DCP.h, the new version would be # 1.0.1. If changes were also required in AS_DCP.h, the new version would be 1.1.1. -AC_INIT([asdcplib], [2.3.8], [asdcplib@cinecert.com]) +AC_INIT([asdcplib], [2.4.9], [asdcplib@cinecert.com]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_SRCDIR([src/KM_error.h]) diff --git a/src/AS_02.h b/src/AS_02.h index 02efb9f..78f9229 100644 --- a/src/AS_02.h +++ b/src/AS_02.h @@ -118,12 +118,18 @@ namespace AS_02 } // Returns number of frames for data described by ADesc, given a duration in samples and an edit rate - inline ui32_t CalcFramesFromDurationInSamples(const ui32_t durationInSamples, const ASDCP::MXF::WaveAudioDescriptor& d, + inline ui32_t CalcFramesFromDurationInSamples(const ui32_t duration_samples, const ASDCP::MXF::WaveAudioDescriptor& d, const ASDCP::Rational& edit_rate) { - return static_cast(static_cast(durationInSamples) * - static_cast(d.AudioSamplingRate.Denominator * edit_rate.Numerator) / - static_cast(d.AudioSamplingRate.Numerator * edit_rate.Denominator)); + ui32_t spf = CalcSamplesPerFrame(d, edit_rate); + ui32_t frames = duration_samples / spf; + + if ( duration_samples % spf != 0 ) + { + ++frames; + } + + return frames; } } // namespace MXF diff --git a/src/AS_02_PCM.cpp b/src/AS_02_PCM.cpp index 9a6a98c..f62dcc3 100644 --- a/src/AS_02_PCM.cpp +++ b/src/AS_02_PCM.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2011-2013, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, +Copyright (c) 2011-2015, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst All rights reserved. @@ -47,17 +47,15 @@ static std::string SOUND_DEF_LABEL = "Sound Track"; class AS_02::PCM::MXFReader::h__Reader : public AS_02::h__AS02Reader { - ui64_t m_ClipEssenceBegin; - ui64_t m_SamplesPerFrame; - ui32_t m_BytesPerFrame; - ui32_t m_ContainerDuration; + ui64_t m_ClipEssenceBegin, m_ClipSize; + ui32_t m_ClipDurationFrames, m_BytesPerFrame; ASDCP_NO_COPY_CONSTRUCT(h__Reader); h__Reader(); public: - h__Reader(const Dictionary& d) : AS_02::h__AS02Reader(d), m_ClipEssenceBegin(0), - m_SamplesPerFrame(0), m_BytesPerFrame(0), m_ContainerDuration(0) {} + h__Reader(const Dictionary& d) : AS_02::h__AS02Reader(d), m_ClipEssenceBegin(0), m_ClipSize(0), + m_ClipDurationFrames(0) {} virtual ~h__Reader() {} ASDCP::Result_t OpenRead(const std::string&, const ASDCP::Rational& edit_rate); @@ -134,10 +132,14 @@ AS_02::PCM::MXFReader::h__Reader::OpenRead(const std::string& filename, const AS } m_ClipEssenceBegin = m_File.Tell(); - m_SamplesPerFrame = AS_02::MXF::CalcSamplesPerFrame(*wave_descriptor, edit_rate); + m_ClipSize = reader.Length(); m_BytesPerFrame = AS_02::MXF::CalcFrameBufferSize(*wave_descriptor, edit_rate); - m_ContainerDuration = static_cast(reader.Length() / ( m_SamplesPerFrame * AS_02::MXF::CalcSampleSize(*wave_descriptor))); + m_ClipDurationFrames = m_ClipSize / m_BytesPerFrame; + if ( m_ClipSize % m_BytesPerFrame > 0 ) + { + ++m_ClipDurationFrames; // there is a partial frame at the end + } } } @@ -154,13 +156,14 @@ AS_02::PCM::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, ASDCP::PCM::FrameBu return RESULT_INIT; } - if ( FrameNum > m_ContainerDuration ) + if ( ! ( FrameNum < m_ClipDurationFrames ) ) { return RESULT_RANGE; } assert(m_ClipEssenceBegin); - ui64_t position = m_ClipEssenceBegin + ( FrameNum * m_BytesPerFrame ); + ui64_t offset = FrameNum * m_BytesPerFrame; + ui64_t position = m_ClipEssenceBegin + offset; Result_t result = RESULT_OK; if ( m_File.Tell() != position ) @@ -170,12 +173,19 @@ AS_02::PCM::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, ASDCP::PCM::FrameBu if ( KM_SUCCESS(result) ) { - result = m_File.Read(FrameBuf.Data(), m_BytesPerFrame); - } + ui64_t remainder = m_ClipSize - offset; + ui32_t read_size = ( remainder < m_BytesPerFrame ) ? remainder : m_BytesPerFrame; + result = m_File.Read(FrameBuf.Data(), read_size); - if ( KM_SUCCESS(result) ) - { - FrameBuf.Size(m_BytesPerFrame); + if ( KM_SUCCESS(result) ) + { + FrameBuf.Size(read_size); + + if ( read_size < FrameBuf.Capacity() ) + { + memset(FrameBuf.Data() + FrameBuf.Size(), 0, FrameBuf.Capacity() - FrameBuf.Size()); + } + } } return result; @@ -319,10 +329,9 @@ class AS_02::PCM::MXFWriter::h__Writer : public AS_02::h__AS02WriterClip public: ASDCP::MXF::WaveAudioDescriptor *m_WaveAudioDescriptor; byte_t m_EssenceUL[SMPTE_UL_LENGTH]; - ui32_t m_BytesPerFrame; - ui32_t m_SamplesPerFrame; - - h__Writer(const Dictionary& d) : AS_02::h__AS02WriterClip(d), m_WaveAudioDescriptor(0), m_BytesPerFrame(0), m_SamplesPerFrame(0) + ui32_t m_BytesPerSample; + + h__Writer(const Dictionary& d) : AS_02::h__AS02WriterClip(d), m_WaveAudioDescriptor(0), m_BytesPerSample(0) { memset(m_EssenceUL, 0, SMPTE_UL_LENGTH); } @@ -406,10 +415,7 @@ AS_02::PCM::MXFWriter::h__Writer::SetSourceStream(const ASDCP::Rational& edit_ra if ( KM_SUCCESS(result) ) { assert(m_WaveAudioDescriptor); - m_BytesPerFrame = AS_02::MXF::CalcFrameBufferSize(*m_WaveAudioDescriptor, edit_rate); - m_SamplesPerFrame = AS_02::MXF::CalcSamplesPerFrame(*m_WaveAudioDescriptor, edit_rate); - m_WaveAudioDescriptor->ContainerDuration = 0; - assert(m_BytesPerFrame); + m_BytesPerSample = AS_02::MXF::CalcSampleSize(*m_WaveAudioDescriptor); result = WriteAS02Header(PCM_PACKAGE_LABEL, UL(m_Dict->ul(MDD_WAVWrappingClip)), SOUND_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_SoundDataDef)), m_EssenceDescriptor->SampleRate, derive_timecode_rate_from_edit_rate(edit_rate)); @@ -437,12 +443,6 @@ AS_02::PCM::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& frame_buf, AESEn return RESULT_PARAM; } - if ( frame_buf.Size() % m_BytesPerFrame != 0 ) - { - DefaultLogSink().Error("The frame buffer does not contain an integral number of sample sets.\n"); - return RESULT_AS02_FORMAT; - } - Result_t result = RESULT_OK; if ( m_State.Test_READY() ) @@ -462,7 +462,7 @@ AS_02::PCM::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& frame_buf, AESEn if ( KM_SUCCESS(result) ) { - m_FramesWritten += m_SamplesPerFrame; + m_FramesWritten += frame_buf.Size() / m_BytesPerSample; } return result; @@ -482,7 +482,7 @@ AS_02::PCM::MXFWriter::h__Writer::Finalize() if ( KM_SUCCESS(result) ) { - m_IndexWriter.m_Duration = m_FramesWritten; + m_WaveAudioDescriptor->ContainerDuration = m_IndexWriter.m_Duration = m_FramesWritten; WriteAS02Footer(); } diff --git a/src/AS_DCP_MXF.cpp b/src/AS_DCP_MXF.cpp index 82ec81c..0197275 100755 --- a/src/AS_DCP_MXF.cpp +++ b/src/AS_DCP_MXF.cpp @@ -258,6 +258,16 @@ ASDCP::EssenceType(const std::string& filename, EssenceType_t& type) return result; } +// +static bool +string_is_xml(const ASDCP::FrameBuffer& buffer) +{ + std::string ns_prefix, type_name, namespace_name; + Kumu::AttributeList doc_attr_list; + return GetXMLDocType(buffer.RoData(), buffer.Size(), + ns_prefix, type_name, namespace_name, doc_attr_list); +} + // ASDCP::Result_t ASDCP::RawEssenceType(const std::string& filename, EssenceType_t& type) @@ -324,7 +334,7 @@ ASDCP::RawEssenceType(const std::string& filename, EssenceType_t& type) { type = ESS_PCM_24b_48k; } - else if ( Kumu::StringIsXML((const char*)FB.RoData(), FB.Size()) ) + else if ( string_is_xml(FB) ) { type = ESS_TIMED_TEXT; } diff --git a/src/AS_DCP_TimedText.cpp b/src/AS_DCP_TimedText.cpp index e4619e0..6b52823 100644 --- a/src/AS_DCP_TimedText.cpp +++ b/src/AS_DCP_TimedText.cpp @@ -569,6 +569,7 @@ ASDCP::TimedText::MXFWriter::h__Writer::SetSourceStream(ASDCP::TimedText::TimedT resourceSubdescriptor->EssenceStreamID = m_EssenceStreamID++; m_EssenceSubDescriptorList.push_back((FileDescriptor*)resourceSubdescriptor); m_EssenceDescriptor->SubDescriptors.push_back(resourceSubdescriptor->InstanceUID); + m_HeaderSize += resourceSubdescriptor->MIMEMediaType.ArchiveLength() + 20; // 20 == sizeof uuid + sizeof int32 } m_EssenceStreamID = 10; @@ -585,7 +586,7 @@ ASDCP::TimedText::MXFWriter::h__Writer::SetSourceStream(ASDCP::TimedText::TimedT } else { - DefaultLogSink().Error("Unable to write Interop timed-text MXF file. Use SMOTE DCP options instead.\n"); + DefaultLogSink().Error("Unable to write Interop timed-text MXF file. Use SMPTE DCP options instead.\n"); return RESULT_FORMAT; } diff --git a/src/KM_fileio.cpp b/src/KM_fileio.cpp index a7de3c2..5149d35 100644 --- a/src/KM_fileio.cpp +++ b/src/KM_fileio.cpp @@ -235,12 +235,22 @@ Kumu::PathsAreEquivalent(const std::string& lhs, const std::string& rhs) // Kumu::PathCompList_t& -Kumu::PathToComponents(const std::string& Path, PathCompList_t& CList, char separator) +Kumu::PathToComponents(const std::string& path, PathCompList_t& component_list, char separator) { std::string s; s = separator; - CList = km_token_split(Path, s); - return CList; + PathCompList_t tmp_list = km_token_split(path, std::string(s)); + PathCompList_t::const_iterator i; + + for ( i = tmp_list.begin(); i != tmp_list.end(); ++i ) + { + if ( ! i->empty() ) + { + component_list.push_back(*i); + } + } + + return component_list; } // diff --git a/src/KM_util.cpp b/src/KM_util.cpp index 8f8107f..29c3802 100755 --- a/src/KM_util.cpp +++ b/src/KM_util.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2012, John Hurst +Copyright (c) 2005-2015, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -1178,18 +1178,14 @@ Kumu::km_token_split(const std::string& str, const std::string& 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); - } - + 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 ) + if ( strlen(pstr) >= 0 ) { components.push_back(std::string(pstr)); } diff --git a/src/KM_util.h b/src/KM_util.h index 3e99bbf..2ca1793 100755 --- a/src/KM_util.h +++ b/src/KM_util.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2012, John Hurst +Copyright (c) 2005-2015, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -540,7 +540,8 @@ namespace Kumu 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. + // entire string will be returned as a single-item list. Empty items will be recorded for + // adjacent instances of the separator. E.g., "/foo//bar/" will return ["", "foo", "", "bar", ""]. std::list km_token_split(const std::string& str, const std::string& separator); } // namespace Kumu diff --git a/src/KM_xml.cpp b/src/KM_xml.cpp index dcb35a3..936fcb5 100644 --- a/src/KM_xml.cpp +++ b/src/KM_xml.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2010, John Hurst +Copyright (c) 2005-2015, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -399,6 +399,20 @@ Kumu::XMLElement::ParseString(const std::string& document) return ParseString(document.c_str(), document.size()); } +// +bool +Kumu::XMLElement::ParseFirstFromString(const ByteString& document) +{ + return ParseFirstFromString((const char*)document.RoData(), document.Length()); +} + +// +bool +Kumu::XMLElement::ParseFirstFromString(const std::string& document) +{ + return ParseFirstFromString(document.c_str(), document.size()); +} + //---------------------------------------------------------------------------------------------------- @@ -525,6 +539,11 @@ xph_namespace_start(void* p, const XML_Char* ns_prefix, const XML_Char* ns_name) bool Kumu::XMLElement::ParseString(const char* document, ui32_t doc_len) { + if ( doc_len == 0 ) + { + return false; + } + XML_Parser Parser = XML_ParserCreateNS("UTF-8", '|'); if ( Parser == 0 ) @@ -551,45 +570,33 @@ Kumu::XMLElement::ParseString(const char* document, ui32_t doc_len) XML_ParserFree(Parser); if ( ! Ctx.Namespaces->empty() ) - m_NamespaceOwner = (void*)Ctx.Namespaces; + { + m_NamespaceOwner = (void*)Ctx.Namespaces; + } return true; } -//------------------------------------------------------------------------------------------ - -struct xph_test_wrapper -{ - XML_Parser Parser; - bool Status; - - xph_test_wrapper(XML_Parser p) : Parser(p), Status(false) {} -}; - -// expat wrapper functions, map callbacks to IASAXHandler +// expat wrapper functions // static void -xph_test_start(void* p, const XML_Char* name, const XML_Char** attrs) +xph_start_one_shot(void* p, const XML_Char* name, const XML_Char** attrs) { - assert(p); - xph_test_wrapper* Wrapper = (xph_test_wrapper*)p; - - Wrapper->Status = true; - XML_StopParser(Wrapper->Parser, false); + xph_start(p, name, attrs); + XML_Parser parser = (XML_Parser)p; + XML_StopParser(parser, false); } - // bool -Kumu::StringIsXML(const char* document, ui32_t len) +Kumu::XMLElement::ParseFirstFromString(const char* document, ui32_t doc_len) { - if ( document == 0 ) - return false; - - if ( len == 0 ) - len = strlen(document); + if ( doc_len == 0 ) + { + return false; + } - XML_Parser Parser = XML_ParserCreate("UTF-8"); + XML_Parser Parser = XML_ParserCreateNS("UTF-8", '|'); if ( Parser == 0 ) { @@ -597,15 +604,33 @@ Kumu::StringIsXML(const char* document, ui32_t len) return false; } - xph_test_wrapper Wrapper(Parser); - XML_SetUserData(Parser, (void*)&Wrapper); - XML_SetStartElementHandler(Parser, xph_test_start); + ExpatParseContext Ctx(this); + XML_SetUserData(Parser, (void*)&Ctx); + XML_SetElementHandler(Parser, xph_start_one_shot, xph_end); + XML_SetCharacterDataHandler(Parser, xph_char); + XML_SetStartNamespaceDeclHandler(Parser, xph_namespace_start); + + if ( ! XML_Parse(Parser, document, doc_len, 1) ) + { + DefaultLogSink().Error("XML Parse error on line %d: %s\n", + XML_GetCurrentLineNumber(Parser), + XML_ErrorString(XML_GetErrorCode(Parser))); + XML_ParserFree(Parser); + return false; + } - XML_Parse(Parser, document, len, 1); XML_ParserFree(Parser); - return Wrapper.Status; + + if ( ! Ctx.Namespaces->empty() ) + { + m_NamespaceOwner = (void*)Ctx.Namespaces; + } + + return true; } + + #endif //---------------------------------------------------------------------------------------------------- @@ -905,7 +930,9 @@ bool Kumu::XMLElement::ParseString(const char* document, ui32_t doc_len) { if ( doc_len == 0 ) - return false; + { + return false; + } init_xml_dom(); @@ -958,37 +985,69 @@ Kumu::XMLElement::ParseString(const char* document, ui32_t doc_len) // bool -Kumu::StringIsXML(const char* document, ui32_t len) +Kumu::XMLElement::ParseFirstFromString(const char* document, ui32_t doc_len) { - if ( document == 0 || *document == 0 ) - return false; + if ( doc_len == 0 ) + { + return false; + } init_xml_dom(); - if ( len == 0 ) - len = strlen(document); + int errorCount = 0; + SAXParser* parser = new SAXParser(); - SAXParser parser; + parser->setValidationScheme(SAXParser::Val_Always); + parser->setDoNamespaces(true); // optional + + MyTreeHandler* docHandler = new MyTreeHandler(this); + parser->setDocumentHandler(docHandler); + parser->setErrorHandler(docHandler); XMLPScanToken token; - bool status = false; try { MemBufInputSource xmlSource(reinterpret_cast(document), - static_cast(len), + static_cast(doc_len), "pidc_rules_file"); - if ( parser.parseFirst(xmlSource, token) ) + if ( ! parser->parseFirst(xmlSource, token) ) { - if ( parser.parseNext(token) ) - status = true; + ++errorCount; + } + + if ( ! parser->parseNext(token) ) + { + ++errorCount; } } + catch (const XMLException& e) + { + char* message = XMLString::transcode(e.getMessage()); + DefaultLogSink().Error("Parser error: %s\n", message); + XMLString::release(&message); + errorCount++; + } + catch (const SAXParseException& e) + { + char* message = XMLString::transcode(e.getMessage()); + DefaultLogSink().Error("Parser error: %s at line %d\n", message, e.getLineNumber()); + XMLString::release(&message); + errorCount++; + } catch (...) { + DefaultLogSink().Error("Unexpected XML parser error\n"); + errorCount++; } - return status; + if ( errorCount == 0 ) + m_NamespaceOwner = (void*)docHandler->TakeNamespaceMap(); + + delete parser; + delete docHandler; + + return errorCount > 0 ? false : true; } @@ -1006,9 +1065,8 @@ Kumu::XMLElement::ParseString(const char* document, ui32_t doc_len) return false; } -// bool -Kumu::StringIsXML(const char* document, ui32_t len) +Kumu::XMLElement::ParseFirstFromString(const char* document, ui32_t doc_len) { DefaultLogSink().Error("Kumu compiled without XML parser support.\n"); return false; @@ -1040,124 +1098,27 @@ bool Kumu::GetXMLDocType(const byte_t* buf, ui32_t buf_len, std::string& ns_prefix, std::string& type_name, std::string& namespace_name, AttributeList& doc_attr_list) { - assert(buf); - const byte_t *p1 = buf, *p2; - const byte_t *end_p = buf + buf_len; + XMLElement tmp_element("tmp"); - while ( p1 < end_p && *p1 ) + if ( ! tmp_element.ParseFirstFromString((const char*)buf, buf_len) ) { - if ( *p1 == '<' && isalpha(p1[1]) ) - { - p2 = ++p1; - - // collect element name - while ( p2 < end_p && *p2 && ! ( isspace(*p2) || *p2 == '>' ) ) - ++p2; - - if ( p2 < end_p ) - { - const byte_t* separator = (byte_t*)strchr(reinterpret_cast(p1), ':'); - if ( separator != 0 && separator < p2 ) - { - ns_prefix.assign(reinterpret_cast(p1), separator - p1); - p1 = separator + 1; - } - - type_name.assign(reinterpret_cast(p1), p2 - p1); - break; - } - } - else if ( *p1 == '<' && ( ( p1 + 3 ) < end_p ) && p1[1] == '!' && p1[2] == '-' && p1[3] == '-' ) - { - p1 += 4; - - for (;;) - { - while ( *p1 != '>' && p1 < end_p ) - { - ++p1; - } - - if ( *(p1-2) == '-' && *(p1-1) == '-' && *p1 == '>' ) - { - break; - } - - ++p1; - } - } - else - { - ++p1; - } + return false; } - if ( isspace(*p2) ) - { - const byte_t *p3 = p2+1; - while ( p3 < end_p && *p3 && *p3 != '>' ) - { - ++p3; - } - - if ( *p3 != '>' ) - { - return false; // not well-formed XML - } - - std::string attr_str; - attr_str.assign(reinterpret_cast(p2+1), p3 - p2 - 1); - - // normalize whitespace so the subesquent split works properly - for ( int j = 0; j < attr_str.length(); ++j ) - { - if ( attr_str[j] != ' ' && isspace(attr_str[j]) ) - { - attr_str[j] = ' '; - } - } - - std::list doc_attr_nvpairs = km_token_split(attr_str, " "); - - std::list::iterator i; - std::map ns_map; - - for ( i = doc_attr_nvpairs.begin(); i != doc_attr_nvpairs.end(); ++i ) - { - // trim leading and trailing whitespace an right-most character, i.e., \" - std::string trimmed = i->substr(i->find_first_not_of(" "), i->find_last_not_of(" \r\n\t")); - std::list nv_tokens = km_token_split(trimmed, "=\""); + const XMLNamespace* ns = tmp_element.Namespace(); - if ( nv_tokens.size() != 2 ) - { - continue; - } - - NVPair nv_pair; - nv_pair.name = nv_tokens.front(); - nv_pair.value = nv_tokens.back(); - doc_attr_list.push_back(nv_pair); - ns_map.insert(std::map::value_type(nv_pair.name, nv_pair.value)); - } - - std::string doc_ns_name_selector = ns_prefix.empty() ? "xmlns" : "xmlns:"+ns_prefix; - std::map::iterator j = ns_map.find(doc_ns_name_selector); - - if ( j != ns_map.end() ) - { - namespace_name = j->second; - } + if ( ns != 0 ) + { + ns_prefix = ns->Prefix(); + namespace_name = ns->Name(); } - else if ( *p2 != '>' ) - { - return false; // not well-formed XML - } - return ! type_name.empty(); + type_name = tmp_element.GetName(); + doc_attr_list = tmp_element.GetAttributes(); + return true; } - // // end KM_xml.cpp // diff --git a/src/KM_xml.h b/src/KM_xml.h index 0f8ba3c..0c84e56 100644 --- a/src/KM_xml.h +++ b/src/KM_xml.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2011, John Hurst +Copyright (c) 2005-2015, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -41,9 +41,6 @@ namespace Kumu { class XMLElement; - // Return true if the given string contains an XML document (or the start of one). - bool StringIsXML(const char* document, ui32_t len = 0); - // struct NVPair { @@ -109,6 +106,10 @@ namespace Kumu bool ParseString(const ByteString& document); bool ParseString(const std::string& document); + bool ParseFirstFromString(const char* document, ui32_t doc_len); + bool ParseFirstFromString(const ByteString& document); + bool ParseFirstFromString(const std::string& document); + // building void SetName(const char* name); void SetBody(const std::string& value); diff --git a/src/MXFTypes.cpp b/src/MXFTypes.cpp index c575b96..46ddf61 100755 --- a/src/MXFTypes.cpp +++ b/src/MXFTypes.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2012, John Hurst +Copyright (c) 2005-2015, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -665,6 +665,63 @@ ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value) } +//---------------------------------------------------------------------------------------------------- +// + + +ASDCP::MXF::RGBALayout::RGBALayout() +{ + memset(m_value, 0, RGBAValueLength); +} + +ASDCP::MXF::RGBALayout::RGBALayout(const byte_t* value) +{ + memcpy(m_value, value, RGBAValueLength); +} + +ASDCP::MXF::RGBALayout::~RGBALayout() +{ +} + +static char +get_char_for_code(byte_t c) +{ + for ( int i = 0; ASDCP::MXF::RGBALayoutTable[i].code != 0; ++i ) + { + if ( ASDCP::MXF::RGBALayoutTable[i].code == c ) + { + return ASDCP::MXF::RGBALayoutTable[i].symbol; + } + } + + return '_'; +} + +// +const char* +ASDCP::MXF::RGBALayout::EncodeString(char* buf, ui32_t buf_len) const +{ + std::string tmp_str; + char tmp_buf[64]; + + for ( int i = 0; i < RGBAValueLength && m_value[i] != 0; i += 2 ) + { + snprintf(tmp_buf, 64, "%c(%d)", get_char_for_code(m_value[i]), m_value[i+1]); + + if ( ! tmp_str.empty() ) + { + tmp_str += " "; + } + + tmp_str += tmp_buf; + } + + assert(tmp_str.size() < buf_len); + strncpy(buf, tmp_str.c_str(), tmp_str.size()); + return buf; +} + + //---------------------------------------------------------------------------------------------------- // diff --git a/src/MXFTypes.h b/src/MXFTypes.h index fbf3038..77c0f5f 100755 --- a/src/MXFTypes.h +++ b/src/MXFTypes.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2014, John Hurst +Copyright (c) 2005-2015, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -382,6 +382,114 @@ namespace ASDCP } }; + /* + The RGBALayout type shall be a fixed-size 8 element sequence with a total length + of 16 bytes, where each element shall consist of the RGBAComponent type with the + following fields: + + Code (UInt8): Enumerated value specifying component (i.e., component identifier). + "0" is the layout terminator. + + Depth (UInt8): Integer specifying the number of bits occupied (see also G.2.26) + 1->32 indicates integer depth + 253 = HALF (floating point 16-bit value) + 254 = IEEE floating point 32-bit value + 255 = IEEE floating point 64-bit value + 0 = RGBALayout terminator + + A Fill component indicates unused bits. After the components have been specified, + the remaining Code and Size fields shall be set to zero (0). + + For each component in the Pixel, one of the following Codes or the terminator + shall be specified (explained below): + + Code ASCII + + */ + struct RGBALayoutTableEntry + { + byte_t code; + char symbol; + const char* label; + }; + + struct RGBALayoutTableEntry const RGBALayoutTable[] = { + { 0x52, 'R', "Red component" }, + { 0x47, 'G', "Green component" }, + { 0x42, 'B', "Blue component" }, + { 0x41, 'A', "Alpha component" }, + { 0x72, 'r', "Red component (LSBs)" }, + { 0x67, 'g', "Green component (LSBs)" }, + { 0x62, 'b', "Blue component (LSBs)" }, + { 0x61, 'a', "Alpha component (LSBs)" }, + { 0x46, 'F', "Fill component" }, + { 0x50, 'P', "Palette code" }, + { 0x55, 'U', "Color Difference Sample (e.g. U, Cb, I etc.)" }, + { 0x56, 'V', "Color Difference Sample (e.g. V, Cr, Q etc.)" }, + { 0x57, 'W', "Composite Video" }, + { 0x58, 'X', "Non co-sited luma component" }, + { 0x59, 'Y', "Luma component" }, + { 0x5a, 'Z', "Depth component (SMPTE ST 268 compatible)" }, + { 0x75, 'u', "Color Difference Sample (e.g. U, Cb, I etc.) (LSBs)" }, + { 0x76, 'v', "Color Difference Sample (e.g. V, Cr, Q etc.) (LSBs)" }, + { 0x77, 'w', "Composite Video (LSBs)" }, + { 0x78, 'x', "Non co-sited luma component (LSBs)" }, + { 0x79, 'y', "Luma component (LSBs)" }, + { 0x7a, 'z', "Depth component (LSBs) (SMPTE ST 268 compatible)" }, + { 0xd8, 'X', "The DCDM X color component (see SMPTE ST 428-1 X')" }, + { 0xd9, 'Y', "The DCDM Y color component (see SMPTE ST 428-1 Y')" }, + { 0xda, 'Z', "The DCDM Z color component (see SMPTE ST 428-1 Z')" }, + { 0x00, '_', "Terminator" } + }; + + + size_t const RGBAValueLength = 16; + + byte_t const RGBAValue_RGB_10[RGBAValueLength] = { 'R', 10, 'G', 10, 'B', 10, 0, 0 }; + byte_t const RGBAValue_RGB_8[RGBAValueLength] = { 'R', 8, 'G', 8, 'B', 8, 0, 0 }; + byte_t const RGBAValue_YUV_10[RGBAValueLength] = { 'Y', 10, 'U', 10, 'V', 10, 0, 0 }; + byte_t const RGBAValue_YUV_8[RGBAValueLength] = { 'Y', 8, 'U', 8, 'V', 8, 0, 0 }; + byte_t const RGBAValue_DCDM[RGBAValueLength] = { 0xd8, 10, 0xd9, 10, 0xda, 10, 0, 0 }; + + + class RGBALayout : public Kumu::IArchive + { + byte_t m_value[RGBAValueLength]; + + public: + RGBALayout(); + RGBALayout(const byte_t* value); + ~RGBALayout(); + + RGBALayout(const RGBALayout& rhs) { Set(rhs.m_value); } + const RGBALayout& operator=(const RGBALayout& rhs) { Set(rhs.m_value); return *this; } + + void Set(const byte_t* value) { + memcpy(m_value, value, RGBAValueLength); + } + + const char* EncodeString(char* buf, ui32_t buf_len) const; + + bool HasValue() const { return true; } + ui32_t ArchiveLength() const { return RGBAValueLength; } + + bool Archive(Kumu::MemIOWriter* Writer) const { + return Writer->WriteRaw(m_value, RGBAValueLength); + } + + bool Unarchive(Kumu::MemIOReader* Reader) { + if ( Reader->Remainder() < RGBAValueLength ) + { + return false; + } + + memcpy(m_value, Reader->CurrentData(), RGBAValueLength); + Reader->SkipOffset(RGBAValueLength); + return true; + } + }; + + // class Raw : public Kumu::ByteString { diff --git a/src/Metadata.cpp b/src/Metadata.cpp index 2ab2635..bec2530 100755 --- a/src/Metadata.cpp +++ b/src/Metadata.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2015, John Hurst +Copyright (c) 2005-2012, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/src/Metadata.h b/src/Metadata.h index b8d16dc..d76c477 100755 --- a/src/Metadata.h +++ b/src/Metadata.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2015, John Hurst +Copyright (c) 2005-2012, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -564,7 +564,7 @@ namespace ASDCP optional_property PictureComponentSizing; optional_property CodingStyleDefault; optional_property QuantizationDefault; - optional_property J2CLayout; + optional_property J2CLayout; JPEG2000PictureSubDescriptor(const Dictionary*& d); JPEG2000PictureSubDescriptor(const JPEG2000PictureSubDescriptor& rhs); diff --git a/src/PCMParserList.cpp b/src/PCMParserList.cpp index 4f43c4e..0ae22cc 100755 --- a/src/PCMParserList.cpp +++ b/src/PCMParserList.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2004-2014, John Hurst +Copyright (c) 2004-2015, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -72,11 +72,18 @@ ASDCP::ParserInstance::PutSample(byte_t* p) { ASDCP_TEST_NULL(p); - memcpy(p, m_p, m_SampleSize); - m_p += m_SampleSize; - return RESULT_OK; -} + if ( m_p != 0 ) + { + if ( m_p < ( FB.RoData() + FB.Size() ) ) + { + memcpy(p, m_p, m_SampleSize); + m_p += m_SampleSize; + return RESULT_OK; + } + } + return RESULT_ENDOFFILE; +} // Result_t @@ -247,21 +254,23 @@ ASDCP::PCMParserList::ReadFrame(PCM::FrameBuffer& OutFB) Result_t result = RESULT_OK; if ( size() == 1 ) - return front()->Parser.ReadFrame(OutFB); + { + return front()->Parser.ReadFrame(OutFB); + } PCMParserList::iterator self_i; assert(PCM::CalcFrameBufferSize(m_ADesc) <= OutFB.Capacity()); for ( self_i = begin(); self_i != end() && ASDCP_SUCCESS(result) ; self_i++ ) - result = (*self_i)->ReadFrame(); + { + result = (*self_i)->ReadFrame(); + } if ( ASDCP_SUCCESS(result) ) { - OutFB.Size(PCM::CalcFrameBufferSize(m_ADesc)); - - // ui32_t sample_size = (PCM::CalcSampleSize(m_ADesc)); byte_t* Out_p = OutFB.Data(); - byte_t* End_p = Out_p + OutFB.Size(); + byte_t* End_p = Out_p + OutFB.Capacity(); + ui64_t total_sample_bytes = 0; while ( Out_p < End_p && ASDCP_SUCCESS(result) ) { @@ -270,12 +279,22 @@ ASDCP::PCMParserList::ReadFrame(PCM::FrameBuffer& OutFB) while ( self_i != end() && ASDCP_SUCCESS(result) ) { result = (*self_i)->PutSample(Out_p); - Out_p += (*self_i)->SampleSize(); - self_i++; + + if ( ASDCP_SUCCESS(result) ) + { + Out_p += (*self_i)->SampleSize(); + total_sample_bytes += (*self_i)->SampleSize(); + self_i++; + } } } - assert(Out_p == End_p); + OutFB.Size(total_sample_bytes); + + if ( result == RESULT_ENDOFFILE ) + { + result = RESULT_OK; + } } return result; diff --git a/src/PCM_Parser.cpp b/src/PCM_Parser.cpp index 30e5d28..2700aa4 100755 --- a/src/PCM_Parser.cpp +++ b/src/PCM_Parser.cpp @@ -128,22 +128,22 @@ ASDCP::PCM::WAVParser::h__WAVParser::OpenRead(const std::string& filename, const m_ADesc.ChannelFormat = PCM::CF_NONE; Reset(); } - else - { - SimpleRF64Header RF64Header; - m_FileReader.Seek(0); - result = RF64Header.ReadFromFile(m_FileReader, &m_DataStart); - - if ( ASDCP_SUCCESS(result) ) - { - RF64Header.FillADesc(m_ADesc, PictureRate); - m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc); - m_DataLength = RF64Header.data_len; - m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize; - m_ADesc.ChannelFormat = PCM::CF_NONE; - Reset(); - } - } + else + { + SimpleRF64Header RF64Header; + m_FileReader.Seek(0); + result = RF64Header.ReadFromFile(m_FileReader, &m_DataStart); + + if ( ASDCP_SUCCESS(result) ) + { + RF64Header.FillADesc(m_ADesc, PictureRate); + m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc); + m_DataLength = RF64Header.data_len; + m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize; + m_ADesc.ChannelFormat = PCM::CF_NONE; + Reset(); + } + } } } @@ -156,8 +156,10 @@ ASDCP::PCM::WAVParser::h__WAVParser::ReadFrame(FrameBuffer& FB) { FB.Size(0); - if ( m_EOF || m_ReadCount >= m_DataLength ) - return RESULT_ENDOFFILE; + if ( m_EOF ) + { + return RESULT_ENDOFFILE; + } if ( FB.Capacity() < m_FrameBufferSize ) { @@ -174,7 +176,9 @@ ASDCP::PCM::WAVParser::h__WAVParser::ReadFrame(FrameBuffer& FB) m_EOF = true; if ( read_count > 0 ) - result = RESULT_OK; + { + result = RESULT_OK; + } } if ( ASDCP_SUCCESS(result) ) @@ -182,6 +186,11 @@ ASDCP::PCM::WAVParser::h__WAVParser::ReadFrame(FrameBuffer& FB) m_ReadCount += read_count; FB.Size(read_count); FB.FrameNumber(m_FramesRead++); + + if ( read_count < FB.Capacity() ) + { + memset(FB.Data() + FB.Size(), 0, FB.Capacity() - FB.Size()); + } } return result; diff --git a/src/as-02-unwrap.cpp b/src/as-02-unwrap.cpp index bf69ba3..148946b 100755 --- a/src/as-02-unwrap.cpp +++ b/src/as-02-unwrap.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2011-2014, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, +Copyright (c) 2011-2015, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst All rights reserved. @@ -69,7 +69,7 @@ banner(FILE* stream = stdout) { fprintf(stream, "\n\ %s (asdcplib %s)\n\n\ -Copyright (c) 2011-2014, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst\n\n\ +Copyright (c) 2011-2015, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst\n\n\ asdcplib may be copied only under the terms of the license found at\n\ the top of every file in the asdcplib distribution kit.\n\n\ Specify the -h (help) option for further information about %s\n\n", @@ -550,6 +550,13 @@ read_PCM_file(CommandOptions& Options) FrameBuffer.Dump(stderr, Options.fb_dump_size); } + if ( FrameBuffer.Size() != FrameBuffer.Capacity() ) + { + fprintf(stderr, "Last frame is incomplete, padding with zeros.\n"); + // actually, it has already been zeroed for us, we just need to recognize the appropriate size + FrameBuffer.Size(FrameBuffer.Capacity()); + } + result = OutWave.WriteFrame(FrameBuffer); } } @@ -597,7 +604,7 @@ main(int argc, const char** argv) break; default: - fprintf(stderr, "%s: Unknown file type, not ASDCP essence.\n", Options.input_filename); + fprintf(stderr, "%s: Unknown file type, not AS-02 essence.\n", Options.input_filename); return 5; } } diff --git a/src/as-02-wrap.cpp b/src/as-02-wrap.cpp index 8aac348..0973b91 100755 --- a/src/as-02-wrap.cpp +++ b/src/as-02-wrap.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2011-2014, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, +Copyright (c) 2011-2015, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst All rights reserved. @@ -107,7 +107,7 @@ banner(FILE* stream = stdout) { fprintf(stream, "\n\ %s (asdcplib %s)\n\n\ -Copyright (c) 2011-2014, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst\n\n\ +Copyright (c) 2011-2015, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst\n\n\ asdcplib may be copied only under the terms of the license found at\n\ the top of every file in the asdcplib distribution kit.\n\n\ Specify the -h (help) option for further information about %s\n\n", @@ -173,7 +173,7 @@ decode_rational(const char* str_rat) { assert(str_rat); ui32_t Num = atoi(str_rat); - ui32_t Den = 0; + ui32_t Den = 1; const char* den_str = strrchr(str_rat, '/'); if ( den_str != 0 ) @@ -759,14 +759,6 @@ write_PCM_file(CommandOptions& Options) if ( ASDCP_SUCCESS(result) ) { - if ( FrameBuffer.Size() != FrameBuffer.Capacity() ) - { - fprintf(stderr, "WARNING: Last frame read was short, PCM input is possibly not frame aligned.\n"); - fprintf(stderr, "Expecting %u bytes, got %u.\n", FrameBuffer.Capacity(), FrameBuffer.Size()); - result = RESULT_ENDOFFILE; - continue; - } - if ( Options.verbose_flag ) FrameBuffer.Dump(stderr, Options.fb_dump_size); diff --git a/src/asdcp-info.cpp b/src/asdcp-info.cpp index 448ef42..9b3ea40 100755 --- a/src/asdcp-info.cpp +++ b/src/asdcp-info.cpp @@ -76,7 +76,7 @@ banner(FILE* stream = stdout) { fprintf(stream, "\n\ %s (asdcplib %s)\n\n\ -Copyright (c) 2003-2014 John Hurst\n\n\ +Copyright (c) 2003-2015 John Hurst\n\n\ asdcplib may be copied only under the terms of the license found at\n\ the top of every file in the asdcplib distribution kit.\n\n\ Specify the -h (help) option for further information about %s\n\n", diff --git a/src/asdcp-test.cpp b/src/asdcp-test.cpp index dc50706..c0ccaa1 100755 --- a/src/asdcp-test.cpp +++ b/src/asdcp-test.cpp @@ -103,7 +103,7 @@ banner(FILE* stream = stdout) { fprintf(stream, "\n\ %s (asdcplib %s)\n\n\ -Copyright (c) 2003-2014 John Hurst\n\n\ +Copyright (c) 2003-2015 John Hurst\n\n\ asdcplib may be copied only under the terms of the license found at\n\ the top of every file in the asdcplib distribution kit.\n\n\ Specify the -h (help) option for further information about %s\n\n", diff --git a/src/asdcp-unwrap.cpp b/src/asdcp-unwrap.cpp index e3572f6..1f7e8d2 100755 --- a/src/asdcp-unwrap.cpp +++ b/src/asdcp-unwrap.cpp @@ -61,7 +61,7 @@ banner(FILE* stream = stdout) { fprintf(stream, "\n\ %s (asdcplib %s)\n\n\ -Copyright (c) 2003-2014 John Hurst\n\n\ +Copyright (c) 2003-2015 John Hurst\n\n\ asdcplib may be copied only under the terms of the license found at\n\ the top of every file in the asdcplib distribution kit.\n\n\ Specify the -h (help) option for further information about %s\n\n", diff --git a/src/asdcp-wrap.cpp b/src/asdcp-wrap.cpp index 0a749b0..72dbaea 100755 --- a/src/asdcp-wrap.cpp +++ b/src/asdcp-wrap.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2014, John Hurst +Copyright (c) 2003-2015, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -113,7 +113,7 @@ banner(FILE* stream = stdout) { fprintf(stream, "\n\ %s (asdcplib %s)\n\n\ -Copyright (c) 2003-2014 John Hurst\n\n\ +Copyright (c) 2003-2015 John Hurst\n\n\ asdcplib may be copied only under the terms of the license found at\n\ the top of every file in the asdcplib distribution kit.\n\n\ Specify the -h (help) option for further information about %s\n\n", @@ -221,6 +221,7 @@ public: 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) + bool write_partial_pcm_flag; // if true, write the last frame of PCM input even when it is incomplete 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 @@ -289,7 +290,7 @@ public: encrypt_header_flag(true), write_hmac(true), verbose_flag(false), fb_dump_size(0), no_write_flag(false), version_flag(false), help_flag(false), stereo_image_flag(false), - start_frame(0), + write_partial_pcm_flag(false), start_frame(0), duration(0xffffffff), use_smpte_labels(false), j2c_pedantic(true), fb_size(FRAME_BUFFER_SIZE), channel_fmt(PCM::CF_NONE), @@ -364,6 +365,7 @@ public: start_frame = abs(atoi(argv[i])); break; + case 'g': write_partial_pcm_flag = true; break; case 'h': help_flag = true; break; case 'j': key_id_flag = true; @@ -1059,8 +1061,12 @@ write_PCM_file(CommandOptions& Options) { fprintf(stderr, "WARNING: Last frame read was short, PCM input is possibly not frame aligned.\n"); fprintf(stderr, "Expecting %u bytes, got %u.\n", FrameBuffer.Capacity(), FrameBuffer.Size()); - result = RESULT_ENDOFFILE; - continue; + + if ( Options.write_partial_pcm_flag ) + { + result = RESULT_ENDOFFILE; + continue; + } } if ( Options.verbose_flag ) @@ -1188,8 +1194,12 @@ write_PCM_with_ATMOS_sync_file(CommandOptions& Options) { fprintf(stderr, "WARNING: Last frame read was short, PCM input is possibly not frame aligned.\n"); fprintf(stderr, "Expecting %u bytes, got %u.\n", FrameBuffer.Capacity(), FrameBuffer.Size()); - result = RESULT_ENDOFFILE; - continue; + + if ( Options.write_partial_pcm_flag ) + { + result = RESULT_ENDOFFILE; + continue; + } } if ( Options.verbose_flag ) diff --git a/src/phdr-unwrap.cpp b/src/phdr-unwrap.cpp index a7a3afc..a0ba7c7 100755 --- a/src/phdr-unwrap.cpp +++ b/src/phdr-unwrap.cpp @@ -60,7 +60,7 @@ banner(FILE* stream = stdout) { fprintf(stream, "\n\ %s (asdcplib %s)\n\n\ -Copyright (c) 2011-2014, John Hurst\n\n\ +Copyright (c) 2011-2015, John Hurst\n\n\ asdcplib may be copied only under the terms of the license found at\n\ the top of every file in the asdcplib distribution kit.\n\n\ Specify the -h (help) option for further information about %s\n\n", diff --git a/src/phdr-wrap.cpp b/src/phdr-wrap.cpp index a00d091..b7ef2d2 100755 --- a/src/phdr-wrap.cpp +++ b/src/phdr-wrap.cpp @@ -91,7 +91,7 @@ banner(FILE* stream = stdout) { fprintf(stream, "\n\ %s (asdcplib %s)\n\n\ -Copyright (c) 2011-2014, John Hurst\n\n\ +Copyright (c) 2011-2015, John Hurst\n\n\ asdcplib may be copied only under the terms of the license found at\n\ the top of every file in the asdcplib distribution kit.\n\n\ Specify the -h (help) option for further information about %s\n\n", diff --git a/win32/Makefile.mak b/win32/Makefile.mak index 6640d01..ac7be72 100755 --- a/win32/Makefile.mak +++ b/win32/Makefile.mak @@ -33,11 +33,11 @@ OBJDIR = . !ifdef ENABLE_RANDOM_UUID CXXFLAGS1 = /nologo /W3 /GR /EHsc /DWIN32 /DKM_WIN32 /D_CONSOLE /I. /I$(SRCDIR) /DASDCP_PLATFORM=\"win32\" \ - /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS /DPACKAGE_VERSION=\"2.1.1\" \ + /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS /DPACKAGE_VERSION=\"2.4.9\" \ /I"$(WITH_OPENSSL)"\inc32 /DCONFIG_RANDOM_UUID=1 !else CXXFLAGS1 = /nologo /W3 /GR /EHsc /DWIN32 /DKM_WIN32 /D_CONSOLE /I. /I$(SRCDIR) /DASDCP_PLATFORM=\"win32\" \ - /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS /DPACKAGE_VERSION=\"2.1.1\" \ + /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS /DPACKAGE_VERSION=\"2.4.9\" \ /I"$(WITH_OPENSSL)"\inc32 !endif LIB_EXE = lib.exe -- 2.30.2