diff options
| author | jhurst <jhurst@cinecert.com> | 2013-12-15 23:34:13 +0000 |
|---|---|---|
| committer | jhurst <> | 2013-12-15 23:34:13 +0000 |
| commit | 7f373b689817ee70fbe5d6a14cb0512b5260f77c (patch) | |
| tree | 0b182f46691f1420e18be08ea1952a818c546f94 /src | |
| parent | 1f41555bcf96369227cda526e36196fe512f464e (diff) | |
o Added preliminary support for timed-text wrapping for AS-02. This
work will require changes in SMPTE ST 429-5 and perhaps other
standards work, so files created with this implementation are
"speculative". Publication of the revised ST 429-5 may not occur
until early 2015.
o Moved LocalFilenameResolver into the AS_DCP public API so that it
can be used by other modules including AS-02.
o Fixed wave wrapping UL in clip-wrapped AS-02 files. Renamed some
UL constants to reflect "clip" or "frame" wrapping.
o Re-factored JP2K_PDesc_to_MD() and MD_to_JP2K_PDesc() to work
with GenericPictureEssenceDescriptor objects.
o Fixed a bug that was suppressing PictureComponentSizing,
CodingStyleDefault and QuantizationDefault when writing the
essence descriptor in a JP2K file (AS-DCP and AS-02).
o Fixed the version byte on the following UL values:
StereoscopicPictureSubDescriptor
GenericPictureEssenceDescriptor_ColorPrimaries
GenericPictureEssenceDescriptor_ActiveHeight
GenericPictureEssenceDescriptor_ActiveWidth
GenericPictureEssenceDescriptor_ActiveXOffset
GenericPictureEssenceDescriptor_ActiveYOffset
o Added some essence descriptor options to as-02-wrap.
o Added TTML timed-text wrapping option to as-02-wrap.
o Changed bit rate display in asdcp-info from mebi-bits/s to
mega-bits/s.
o Added "SMPTE" / "Interop" format type display to asdcp-info.
o Modified asdcp-wrap to assume -L when wrapping timed-text (since
there is no MXF text wrapping for Interop.)
o Fixed missing-index-partion bugs for AS-02 files.
Diffstat (limited to 'src')
| -rw-r--r-- | src/AS_02.h | 146 | ||||
| -rw-r--r-- | src/AS_02_JP2K.cpp | 2 | ||||
| -rw-r--r-- | src/AS_02_PCM.cpp | 5 | ||||
| -rwxr-xr-x | src/AS_DCP.h | 16 | ||||
| -rw-r--r-- | src/AS_DCP_DCData.cpp | 2 | ||||
| -rwxr-xr-x | src/AS_DCP_JP2K.cpp | 232 | ||||
| -rwxr-xr-x | src/AS_DCP_MPEG2.cpp | 2 | ||||
| -rwxr-xr-x | src/AS_DCP_PCM.cpp | 2 | ||||
| -rw-r--r-- | src/AS_DCP_TimedText.cpp | 2 | ||||
| -rwxr-xr-x | src/AS_DCP_internal.h | 16 | ||||
| -rw-r--r-- | src/MDD.cpp | 26 | ||||
| -rwxr-xr-x | src/MDD.h | 11 | ||||
| -rwxr-xr-x | src/MXF.cpp | 27 | ||||
| -rw-r--r-- | src/Makefile.am | 2 | ||||
| -rw-r--r-- | src/TimedText_Parser.cpp | 96 | ||||
| -rwxr-xr-x | src/as-02-wrap.cpp | 191 | ||||
| -rwxr-xr-x | src/asdcp-info.cpp | 7 | ||||
| -rwxr-xr-x | src/asdcp-wrap.cpp | 10 | ||||
| -rw-r--r-- | src/h__02_Reader.cpp | 33 | ||||
| -rw-r--r-- | src/h__02_Writer.cpp | 15 |
20 files changed, 518 insertions, 325 deletions
diff --git a/src/AS_02.h b/src/AS_02.h index e534dd4..3437152 100644 --- a/src/AS_02.h +++ b/src/AS_02.h @@ -314,6 +314,152 @@ namespace AS_02 }; } // namespace PCM + //--------------------------------------------------------------------------------- + // + namespace TimedText + { + using ASDCP::TimedText::TimedTextDescriptor; + using ASDCP::TimedText::TimedTextResourceDescriptor; + using ASDCP::TimedText::ResourceList_t; + + // + class ST2052_TextParser + { + class h__TextParser; + ASDCP::mem_ptr<h__TextParser> m_Parser; + ASDCP_NO_COPY_CONSTRUCT(ST2052_TextParser); + + public: + ST2052_TextParser(); + virtual ~ST2052_TextParser(); + + // Opens an XML file for reading, parses data to provide a complete + // set of stream metadata for the MXFWriter below. + Result_t OpenRead(const std::string& filename) const; + + // Parse an XML string + Result_t OpenRead(const std::string& xml_doc, const std::string& filename) const; + + // Fill a TimedTextDescriptor struct with the values from the file's contents. + // Returns RESULT_INIT if the file is not open. + Result_t FillTimedTextDescriptor(ASDCP::TimedText::TimedTextDescriptor&) const; + + // Reads the complete Timed Text Resource into the given string. + Result_t ReadTimedTextResource(std::string&) const; + + // Reads the Ancillary Resource having the given ID. Fails if the buffer + // is too small or the resource does not exist. The optional Resolver + // argument can be provided which will be used to retrieve the resource + // having a particulat UUID. If a Resolver is not supplied, the default + // internal resolver will return the contents of the file having the UUID + // as the filename. The filename must exist in the same directory as the + // XML file opened with OpenRead(). + Result_t ReadAncillaryResource(const Kumu::UUID&, ASDCP::TimedText::FrameBuffer&, + const ASDCP::TimedText::IResourceResolver* Resolver = 0) const; + }; + + // + class MXFWriter + { + class h__Writer; + ASDCP::mem_ptr<h__Writer> m_Writer; + ASDCP_NO_COPY_CONSTRUCT(MXFWriter); + + public: + MXFWriter(); + virtual ~MXFWriter(); + + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual ASDCP::MXF::OP1aHeader& OP1aHeader(); + virtual ASDCP::MXF::RIP& RIP(); + + // Open the file for writing. The file must not exist. Returns error if + // the operation cannot be completed or if nonsensical data is discovered + // in the essence descriptor. + Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&, + const ASDCP::TimedText::TimedTextDescriptor&, ui32_t HeaderSize = 16384); + + // Writes the Timed-Text Resource to the MXF file. The file must be UTF-8 + // encoded. If the optional AESEncContext argument is present, the essence + // is encrypted prior to writing. Fails if the file is not open, is finalized, + // or an operating system error occurs. + // This method may only be called once, and it must be called before any + // call to WriteAncillaryResource(). RESULT_STATE will be returned if these + // conditions are not met. + Result_t WriteTimedTextResource(const std::string& XMLDoc, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0); + + // Writes an Ancillary Resource to the MXF file. If the optional AESEncContext + // argument is present, the essence is encrypted prior to writing. + // Fails if the file is not open, is finalized, or an operating system + // error occurs. RESULT_STATE will be returned if the method is called before + // WriteTimedTextResource() + Result_t WriteAncillaryResource(const ASDCP::TimedText::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0); + + // Closes the MXF file, writing the index and revised header. + Result_t Finalize(); + }; + + // + class MXFReader + { + class h__Reader; + ASDCP::mem_ptr<h__Reader> m_Reader; + ASDCP_NO_COPY_CONSTRUCT(MXFReader); + + public: + MXFReader(); + virtual ~MXFReader(); + + // Warning: direct manipulation of MXF structures can interfere + // with the normal operation of the wrapper. Caveat emptor! + virtual ASDCP::MXF::OP1aHeader& OP1aHeader(); + virtual AS_02::MXF::AS02IndexReader& AS02IndexReader(); + virtual ASDCP::MXF::RIP& RIP(); + + // Open the file for reading. The file must exist. Returns error if the + // operation cannot be completed. + Result_t OpenRead(const std::string& filename) const; + + // Returns RESULT_INIT if the file is not open. + Result_t Close() const; + + // Fill a TimedTextDescriptor struct with the values from the file's header. + // Returns RESULT_INIT if the file is not open. + Result_t FillTimedTextDescriptor(ASDCP::TimedText::TimedTextDescriptor&) const; + + // Fill a WriterInfo struct with the values from the file's header. + // Returns RESULT_INIT if the file is not open. + Result_t FillWriterInfo(ASDCP::WriterInfo&) const; + + // Reads the complete Timed Text Resource into the given string. Fails if the resource + // is encrypted and AESDecContext is NULL (use the following method to retrieve the + // raw ciphertet block). + Result_t ReadTimedTextResource(std::string&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const; + + // Reads the complete Timed Text Resource from the MXF file. If the optional AESEncContext + // argument is present, the resource is decrypted after reading. If the MXF + // file is encrypted and the AESDecContext argument is NULL, the frame buffer + // will contain the ciphertext frame data. If the HMACContext argument is + // not NULL, the HMAC will be calculated (if the file supports it). + // Returns RESULT_INIT if the file is not open, failure if the frame number is + // out of range, or if optional decrypt or HAMC operations fail. + Result_t ReadTimedTextResource(ASDCP::TimedText::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const; + + // Reads the timed-text resource having the given UUID from the MXF file. If the + // optional AESEncContext argument is present, the resource is decrypted after + // reading. If the MXF file is encrypted and the AESDecContext argument is NULL, + // the frame buffer will contain the ciphertext frame data. If the HMACContext + // argument is not NULL, the HMAC will be calculated (if the file supports it). + // Returns RESULT_INIT if the file is not open, failure if the frame number is + // out of range, or if optional decrypt or HAMC operations fail. + Result_t ReadAncillaryResource(const Kumu::UUID&, ASDCP::TimedText::FrameBuffer&, ASDCP::AESDecContext* = 0, ASDCP::HMACContext* = 0) const; + + // Print debugging information to stream + void DumpHeaderMetadata(FILE* = 0) const; + void DumpIndex(FILE* = 0) const; + }; + } // namespace TimedText } // namespace AS_02 diff --git a/src/AS_02_JP2K.cpp b/src/AS_02_JP2K.cpp index 79ea382..a8eff1a 100644 --- a/src/AS_02_JP2K.cpp +++ b/src/AS_02_JP2K.cpp @@ -331,7 +331,7 @@ AS_02::JP2K::MXFWriter::h__Writer::SetSourceStream(const std::string& label, con if ( KM_SUCCESS(result) ) { - result = WriteAS02Header(label, UL(m_Dict->ul(MDD_JPEG_2000Wrapping)), + result = WriteAS02Header(label, UL(m_Dict->ul(MDD_JPEG_2000WrappingFrame)), PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)), edit_rate, derive_timecode_rate_from_edit_rate(edit_rate)); } diff --git a/src/AS_02_PCM.cpp b/src/AS_02_PCM.cpp index 512bcdb..2ffc45e 100644 --- a/src/AS_02_PCM.cpp +++ b/src/AS_02_PCM.cpp @@ -421,7 +421,7 @@ AS_02::PCM::MXFWriter::h__Writer::SetSourceStream(const ASDCP::Rational& edit_ra m_SamplesPerFrame = AS_02::MXF::CalcSamplesPerFrame(*m_WaveAudioDescriptor, edit_rate); m_WaveAudioDescriptor->ContainerDuration = 0; - result = WriteAS02Header(PCM_PACKAGE_LABEL, UL(m_Dict->ul(MDD_WAVWrapping)), + 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), m_BytesPerFrame); } @@ -488,6 +488,9 @@ AS_02::PCM::MXFWriter::h__Writer::Finalize() if ( KM_SUCCESS(result) ) { m_FramesWritten = m_FramesWritten * m_SamplesPerFrame; + m_IndexWriter.ThisPartition = m_File.Tell(); + m_IndexWriter.WriteToFile(m_File); + m_RIP.PairArray.push_back(RIP::Pair(0, m_IndexWriter.ThisPartition)); WriteAS02Footer(); } diff --git a/src/AS_DCP.h b/src/AS_DCP.h index 7ef83e4..6f99698 100755 --- a/src/AS_DCP.h +++ b/src/AS_DCP.h @@ -1449,6 +1449,8 @@ namespace ASDCP { void Dump(FILE* = 0, ui32_t dump_bytes = 0) const; }; + // An abstract base for a lookup service that returns the resource data + // identified by the given ancillary resource id. // class IResourceResolver { @@ -1457,6 +1459,20 @@ namespace ASDCP { virtual Result_t ResolveRID(const byte_t* uuid, FrameBuffer&) const = 0; // return data for RID }; + // Resolves resource references by testing the named directory for file names containing + // the respective UUID. + // + class LocalFilenameResolver : public ASDCP::TimedText::IResourceResolver + { + std::string m_Dirname; + ASDCP_NO_COPY_CONSTRUCT(LocalFilenameResolver); + + public: + LocalFilenameResolver(); + Result_t OpenRead(const std::string& dirname); + Result_t ResolveRID(const byte_t* uuid, FrameBuffer& FrameBuf) const; + }; + // class DCSubtitleParser { diff --git a/src/AS_DCP_DCData.cpp b/src/AS_DCP_DCData.cpp index faa02a0..a1bb043 100644 --- a/src/AS_DCP_DCData.cpp +++ b/src/AS_DCP_DCData.cpp @@ -414,7 +414,7 @@ ASDCP::DCData::h__Writer::SetSourceStream(DCDataDescriptor const& DDesc, { ui32_t TCFrameRate = m_DDesc.EditRate.Numerator; - result = WriteASDCPHeader(packageLabel, UL(m_Dict->ul(MDD_DCDataWrapping)), + result = WriteASDCPHeader(packageLabel, UL(m_Dict->ul(MDD_DCDataWrappingFrame)), defLabel, UL(m_EssenceUL), UL(m_Dict->ul(MDD_DataDataDef)), m_DDesc.EditRate, TCFrameRate); } diff --git a/src/AS_DCP_JP2K.cpp b/src/AS_DCP_JP2K.cpp index b2f2eaf..1b3bc54 100755 --- a/src/AS_DCP_JP2K.cpp +++ b/src/AS_DCP_JP2K.cpp @@ -208,39 +208,26 @@ static const byte_t s_PixelLayoutXYZ[PixelLayoutSize] = { 0xd8, 0x0c, 0xd9, 0x0c ASDCP::Result_t ASDCP::JP2K_PDesc_to_MD(const JP2K::PictureDescriptor& PDesc, const ASDCP::Dictionary& dict, - ASDCP::MXF::RGBAEssenceDescriptor *EssenceDescriptor, - ASDCP::MXF::JPEG2000PictureSubDescriptor *EssenceSubDescriptor) -{ - if ( EssenceDescriptor == 0 || EssenceSubDescriptor == 0 ) - return RESULT_PTR; - - EssenceDescriptor->ContainerDuration = PDesc.ContainerDuration; - EssenceDescriptor->SampleRate = PDesc.EditRate; - EssenceDescriptor->FrameLayout = 0; - EssenceDescriptor->StoredWidth = PDesc.StoredWidth; - EssenceDescriptor->StoredHeight = PDesc.StoredHeight; - EssenceDescriptor->AspectRatio = PDesc.AspectRatio; - - if ( PDesc.StoredWidth < 2049 ) - { - EssenceDescriptor->PictureEssenceCoding.Set(dict.ul(MDD_JP2KEssenceCompression_2K)); - EssenceSubDescriptor->Rsize = 3; - } - else - { - EssenceDescriptor->PictureEssenceCoding.Set(dict.ul(MDD_JP2KEssenceCompression_4K)); - EssenceSubDescriptor->Rsize = 4; - } - - EssenceSubDescriptor->Xsize = PDesc.Xsize; - EssenceSubDescriptor->Ysize = PDesc.Ysize; - EssenceSubDescriptor->XOsize = PDesc.XOsize; - EssenceSubDescriptor->YOsize = PDesc.YOsize; - EssenceSubDescriptor->XTsize = PDesc.XTsize; - EssenceSubDescriptor->YTsize = PDesc.YTsize; - EssenceSubDescriptor->XTOsize = PDesc.XTOsize; - EssenceSubDescriptor->YTOsize = PDesc.YTOsize; - EssenceSubDescriptor->Csize = PDesc.Csize; + ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor, + ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor) +{ + EssenceDescriptor.ContainerDuration = PDesc.ContainerDuration; + EssenceDescriptor.SampleRate = PDesc.EditRate; + EssenceDescriptor.FrameLayout = 0; + EssenceDescriptor.StoredWidth = PDesc.StoredWidth; + EssenceDescriptor.StoredHeight = PDesc.StoredHeight; + EssenceDescriptor.AspectRatio = PDesc.AspectRatio; + + EssenceSubDescriptor.Rsize = PDesc.Rsize; + EssenceSubDescriptor.Xsize = PDesc.Xsize; + EssenceSubDescriptor.Ysize = PDesc.Ysize; + EssenceSubDescriptor.XOsize = PDesc.XOsize; + EssenceSubDescriptor.YOsize = PDesc.YOsize; + EssenceSubDescriptor.XTsize = PDesc.XTsize; + EssenceSubDescriptor.YTsize = PDesc.YTsize; + EssenceSubDescriptor.XTOsize = PDesc.XTOsize; + EssenceSubDescriptor.YTOsize = PDesc.YTOsize; + EssenceSubDescriptor.Csize = PDesc.Csize; const ui32_t tmp_buffer_len = 1024; byte_t tmp_buffer[tmp_buffer_len]; @@ -249,142 +236,24 @@ ASDCP::JP2K_PDesc_to_MD(const JP2K::PictureDescriptor& PDesc, *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t)); memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents); - const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents); - memcpy(EssenceSubDescriptor->PictureComponentSizing.get().Data(), tmp_buffer, pcomp_size); - EssenceSubDescriptor->PictureComponentSizing.get().Length(pcomp_size); - - ui32_t precinct_set_size = 0, i; - for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ ) - precinct_set_size++; - - ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size; - memcpy(EssenceSubDescriptor->CodingStyleDefault.get().Data(), &PDesc.CodingStyleDefault, csd_size); - EssenceSubDescriptor->CodingStyleDefault.get().Length(csd_size); - - ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1; - memcpy(EssenceSubDescriptor->QuantizationDefault.get().Data(), &PDesc.QuantizationDefault, qdflt_size); - EssenceSubDescriptor->QuantizationDefault.get().Length(qdflt_size); - - return RESULT_OK; -} - - -// -ASDCP::Result_t -ASDCP::MD_to_JP2K_PDesc(const ASDCP::MXF::RGBAEssenceDescriptor& EssenceDescriptor, - const ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor, - const ASDCP::Rational& EditRate, const ASDCP::Rational& SampleRate, - ASDCP::JP2K::PictureDescriptor& PDesc) -{ - memset(&PDesc, 0, sizeof(PDesc)); - - PDesc.EditRate = EditRate; - PDesc.SampleRate = SampleRate; - assert(EssenceDescriptor.ContainerDuration.const_get() <= 0xFFFFFFFFL); - PDesc.ContainerDuration = static_cast<ui32_t>(EssenceDescriptor.ContainerDuration.const_get()); - PDesc.StoredWidth = EssenceDescriptor.StoredWidth; - PDesc.StoredHeight = EssenceDescriptor.StoredHeight; - PDesc.AspectRatio = EssenceDescriptor.AspectRatio; - - PDesc.Rsize = EssenceSubDescriptor.Rsize; - PDesc.Xsize = EssenceSubDescriptor.Xsize; - PDesc.Ysize = EssenceSubDescriptor.Ysize; - PDesc.XOsize = EssenceSubDescriptor.XOsize; - PDesc.YOsize = EssenceSubDescriptor.YOsize; - PDesc.XTsize = EssenceSubDescriptor.XTsize; - PDesc.YTsize = EssenceSubDescriptor.YTsize; - PDesc.XTOsize = EssenceSubDescriptor.XTOsize; - PDesc.YTOsize = EssenceSubDescriptor.YTOsize; - PDesc.Csize = EssenceSubDescriptor.Csize; - - // PictureComponentSizing - ui32_t tmp_size = EssenceSubDescriptor.PictureComponentSizing.const_get().Length(); + const ui32_t pcomp_size = (sizeof(ui32_t) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents); + memcpy(EssenceSubDescriptor.PictureComponentSizing.get().Data(), tmp_buffer, pcomp_size); + EssenceSubDescriptor.PictureComponentSizing.get().Length(pcomp_size); + EssenceSubDescriptor.PictureComponentSizing.set_has_value(); - if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each - { - memcpy(&PDesc.ImageComponents, EssenceSubDescriptor.PictureComponentSizing.const_get().RoData() + 8, tmp_size - 8); - } - else - { - DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size); - } - - // CodingStyleDefault - memset(&PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t)); - memcpy(&PDesc.CodingStyleDefault, - EssenceSubDescriptor.CodingStyleDefault.const_get().RoData(), - EssenceSubDescriptor.CodingStyleDefault.const_get().Length()); - - // QuantizationDefault - memset(&PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t)); - memcpy(&PDesc.QuantizationDefault, - EssenceSubDescriptor.QuantizationDefault.const_get().RoData(), - EssenceSubDescriptor.QuantizationDefault.const_get().Length()); - - PDesc.QuantizationDefault.SPqcdLength = EssenceSubDescriptor.QuantizationDefault.const_get().Length() - 1; - return RESULT_OK; -} - -// -ASDCP::Result_t -ASDCP::JP2K_PDesc_to_MD(const JP2K::PictureDescriptor& PDesc, - const ASDCP::Dictionary& dict, - ASDCP::MXF::CDCIEssenceDescriptor *EssenceDescriptor, - ASDCP::MXF::JPEG2000PictureSubDescriptor *EssenceSubDescriptor) -{ - if ( EssenceDescriptor == 0 || EssenceSubDescriptor == 0 ) - return RESULT_PTR; - - EssenceDescriptor->ContainerDuration = PDesc.ContainerDuration; - EssenceDescriptor->SampleRate = PDesc.EditRate; - EssenceDescriptor->FrameLayout = 0; - EssenceDescriptor->StoredWidth = PDesc.StoredWidth; - EssenceDescriptor->StoredHeight = PDesc.StoredHeight; - EssenceDescriptor->AspectRatio = PDesc.AspectRatio; - - if ( PDesc.StoredWidth < 2049 ) - { - EssenceDescriptor->PictureEssenceCoding.Set(dict.ul(MDD_JP2KEssenceCompression_2K)); - EssenceSubDescriptor->Rsize = 3; - } - else - { - EssenceDescriptor->PictureEssenceCoding.Set(dict.ul(MDD_JP2KEssenceCompression_4K)); - EssenceSubDescriptor->Rsize = 4; - } - - EssenceSubDescriptor->Xsize = PDesc.Xsize; - EssenceSubDescriptor->Ysize = PDesc.Ysize; - EssenceSubDescriptor->XOsize = PDesc.XOsize; - EssenceSubDescriptor->YOsize = PDesc.YOsize; - EssenceSubDescriptor->XTsize = PDesc.XTsize; - EssenceSubDescriptor->YTsize = PDesc.YTsize; - EssenceSubDescriptor->XTOsize = PDesc.XTOsize; - EssenceSubDescriptor->YTOsize = PDesc.YTOsize; - EssenceSubDescriptor->Csize = PDesc.Csize; - - const ui32_t tmp_buffer_len = 1024; - byte_t tmp_buffer[tmp_buffer_len]; - - *(ui32_t*)tmp_buffer = KM_i32_BE(MaxComponents); // three components - *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t)); - memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents); - - const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents); - memcpy(EssenceSubDescriptor->PictureComponentSizing.get().Data(), tmp_buffer, pcomp_size); - EssenceSubDescriptor->PictureComponentSizing.get().Length(pcomp_size); - - ui32_t precinct_set_size = 0, i; - for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ ) + ui32_t precinct_set_size = 0; + for ( ui32_t i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; ++i ) precinct_set_size++; ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size; - memcpy(EssenceSubDescriptor->CodingStyleDefault.get().Data(), &PDesc.CodingStyleDefault, csd_size); - EssenceSubDescriptor->CodingStyleDefault.get().Length(csd_size); + memcpy(EssenceSubDescriptor.CodingStyleDefault.get().Data(), &PDesc.CodingStyleDefault, csd_size); + EssenceSubDescriptor.CodingStyleDefault.get().Length(csd_size); + EssenceSubDescriptor.CodingStyleDefault.set_has_value(); ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1; - memcpy(EssenceSubDescriptor->QuantizationDefault.get().Data(), &PDesc.QuantizationDefault, qdflt_size); - EssenceSubDescriptor->QuantizationDefault.get().Length(qdflt_size); + memcpy(EssenceSubDescriptor.QuantizationDefault.get().Data(), &PDesc.QuantizationDefault, qdflt_size); + EssenceSubDescriptor.QuantizationDefault.get().Length(qdflt_size); + EssenceSubDescriptor.QuantizationDefault.set_has_value(); return RESULT_OK; } @@ -392,7 +261,7 @@ ASDCP::JP2K_PDesc_to_MD(const JP2K::PictureDescriptor& PDesc, // ASDCP::Result_t -ASDCP::MD_to_JP2K_PDesc(const ASDCP::MXF::CDCIEssenceDescriptor& EssenceDescriptor, +ASDCP::MD_to_JP2K_PDesc(const ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor, const ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor, const ASDCP::Rational& EditRate, const ASDCP::Rational& SampleRate, ASDCP::JP2K::PictureDescriptor& PDesc) @@ -446,22 +315,6 @@ ASDCP::MD_to_JP2K_PDesc(const ASDCP::MXF::CDCIEssenceDescriptor& EssenceDescrip return RESULT_OK; } -// Compares the actual floating point value of the rates. -// This allows, for example, {300000,1001} and {2997,100) to be considered equivalent. -// to 29.97. -bool -epsilon_compare(const ASDCP::Rational& left, const ASDCP::Rational& right, double epsilon = 0.001) -{ - bool result = false; - double difference = left.Quotient() - right.Quotient(); - - if (fabs(difference) < epsilon) - result = true; - - return result; -} -// end DOLBY - //------------------------------------------------------------------------------------------ // @@ -1134,12 +987,25 @@ lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& l m_PDesc = PDesc; assert(m_Dict); + assert(m_EssenceDescriptor); + assert(m_EssenceSubDescriptor); Result_t result = JP2K_PDesc_to_MD(m_PDesc, *m_Dict, - (ASDCP::MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor, - m_EssenceSubDescriptor); + *static_cast<ASDCP::MXF::GenericPictureEssenceDescriptor*>(m_EssenceDescriptor), + *m_EssenceSubDescriptor); if ( ASDCP_SUCCESS(result) ) { + if ( PDesc.StoredWidth < 2049 ) + { + static_cast<ASDCP::MXF::RGBAEssenceDescriptor*>(m_EssenceDescriptor)->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_2K)); + m_EssenceSubDescriptor->Rsize = 3; + } + else + { + static_cast<ASDCP::MXF::RGBAEssenceDescriptor*>(m_EssenceDescriptor)->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_4K)); + m_EssenceSubDescriptor->Rsize = 4; + } + memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH); m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container result = m_State.Goto_READY(); @@ -1147,7 +1013,7 @@ lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& l if ( ASDCP_SUCCESS(result) ) { - result = WriteASDCPHeader(label, UL(m_Dict->ul(MDD_JPEG_2000Wrapping)), + result = WriteASDCPHeader(label, UL(m_Dict->ul(MDD_JPEG_2000WrappingFrame)), PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)), LocalEditRate, derive_timecode_rate_from_edit_rate(m_PDesc.EditRate)); } diff --git a/src/AS_DCP_MPEG2.cpp b/src/AS_DCP_MPEG2.cpp index d7cc935..21991bf 100755 --- a/src/AS_DCP_MPEG2.cpp +++ b/src/AS_DCP_MPEG2.cpp @@ -568,7 +568,7 @@ ASDCP::MPEG2::MXFWriter::h__Writer::SetSourceStream(const VideoDescriptor& VDesc if ( ASDCP_SUCCESS(result) ) { - result = WriteASDCPHeader(MPEG_PACKAGE_LABEL, UL(m_Dict->ul(MDD_MPEG2_VESWrapping)), + result = WriteASDCPHeader(MPEG_PACKAGE_LABEL, UL(m_Dict->ul(MDD_MPEG2_VESWrappingFrame)), PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)), m_VDesc.EditRate, derive_timecode_rate_from_edit_rate(m_VDesc.EditRate)); } diff --git a/src/AS_DCP_PCM.cpp b/src/AS_DCP_PCM.cpp index 8cff9cf..8011a55 100755 --- a/src/AS_DCP_PCM.cpp +++ b/src/AS_DCP_PCM.cpp @@ -577,7 +577,7 @@ ASDCP::PCM::MXFWriter::h__Writer::SetSourceStream(const AudioDescriptor& ADesc) if ( ASDCP_SUCCESS(result) ) { - result = WriteASDCPHeader(PCM_PACKAGE_LABEL, UL(m_Dict->ul(MDD_WAVWrapping)), + result = WriteASDCPHeader(PCM_PACKAGE_LABEL, UL(m_Dict->ul(MDD_WAVWrappingFrame)), SOUND_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_SoundDataDef)), m_ADesc.EditRate, derive_timecode_rate_from_edit_rate(m_ADesc.EditRate), calc_CBR_frame_size(m_Info, m_ADesc)); diff --git a/src/AS_DCP_TimedText.cpp b/src/AS_DCP_TimedText.cpp index ac95e24..e5425b4 100644 --- a/src/AS_DCP_TimedText.cpp +++ b/src/AS_DCP_TimedText.cpp @@ -593,7 +593,7 @@ ASDCP::TimedText::MXFWriter::h__Writer::SetSourceStream(ASDCP::TimedText::TimedT AddDMSegment(m_TDesc.EditRate, m_TDesc.EditRate, derive_timecode_rate_from_edit_rate(m_TDesc.EditRate), TIMED_TEXT_DEF_LABEL, UL(m_Dict->ul(MDD_DataDataDef)), TIMED_TEXT_PACKAGE_LABEL); - AddEssenceDescriptor(UL(m_Dict->ul(MDD_TimedTextWrapping))); + AddEssenceDescriptor(UL(m_Dict->ul(MDD_TimedTextWrappingClip))); result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize); diff --git a/src/AS_DCP_internal.h b/src/AS_DCP_internal.h index 8b05dc7..675f96d 100755 --- a/src/AS_DCP_internal.h +++ b/src/AS_DCP_internal.h @@ -134,25 +134,15 @@ namespace ASDCP Result_t EncryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESEncContext*); Result_t DecryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESDecContext*); - Result_t MD_to_JP2K_PDesc(const ASDCP::MXF::RGBAEssenceDescriptor& EssenceDescriptor, + Result_t MD_to_JP2K_PDesc(const ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor, const ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor, const ASDCP::Rational& EditRate, const ASDCP::Rational& SampleRate, ASDCP::JP2K::PictureDescriptor& PDesc); Result_t JP2K_PDesc_to_MD(const JP2K::PictureDescriptor& PDesc, const ASDCP::Dictionary& dict, - ASDCP::MXF::RGBAEssenceDescriptor *EssenceDescriptor, - ASDCP::MXF::JPEG2000PictureSubDescriptor *EssenceSubDescriptor); - - Result_t MD_to_JP2K_PDesc(const ASDCP::MXF::CDCIEssenceDescriptor& EssenceDescriptor, - const ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor, - const ASDCP::Rational& EditRate, const ASDCP::Rational& SampleRate, - ASDCP::JP2K::PictureDescriptor& PDesc); - - Result_t JP2K_PDesc_to_MD(const JP2K::PictureDescriptor& PDesc, - const ASDCP::Dictionary& dict, - ASDCP::MXF::CDCIEssenceDescriptor *EssenceDescriptor, - ASDCP::MXF::JPEG2000PictureSubDescriptor *EssenceSubDescriptor); + ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor, + ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor); Result_t PCM_ADesc_to_MD(PCM::AudioDescriptor& ADesc, ASDCP::MXF::WaveAudioDescriptor* ADescObj); Result_t MD_to_PCM_ADesc(ASDCP::MXF::WaveAudioDescriptor* ADescObj, PCM::AudioDescriptor& ADesc); diff --git a/src/MDD.cpp b/src/MDD.cpp index fa88016..a15956c 100644 --- a/src/MDD.cpp +++ b/src/MDD.cpp @@ -64,13 +64,13 @@ static const ASDCP::MDDEntry s_MDD_Table[] = { {0}, false, "DescriptiveMetaDataDef" }, { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 9 0x0d, 0x01, 0x03, 0x01, 0x02, 0x06, 0x01, 0x00 }, - {0}, false, "WAVWrapping" }, + {0}, false, "WAVWrappingFrame" }, { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x02, // 10 0x0d, 0x01, 0x03, 0x01, 0x02, 0x04, 0x60, 0x00 }, - {0}, false, "MPEG2_VESWrapping" }, + {0}, false, "MPEG2_VESWrappingFrame" }, { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x07, // 11 0x0d, 0x01, 0x03, 0x01, 0x02, 0x0c, 0x01, 0x00 }, - {0}, false, "JPEG_2000Wrapping" }, + {0}, false, "JPEG_2000WrappingFrame" }, { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01, // 12 0x0d, 0x01, 0x03, 0x01, 0x15, 0x01, 0x08, 0x00 }, {0}, false, "JPEG2000Essence" }, @@ -802,7 +802,7 @@ static const ASDCP::MDDEntry s_MDD_Table[] = { {0}, false, "CryptographicContext_CryptographicKeyID" }, { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0a, // 255 0x0d, 0x01, 0x03, 0x01, 0x02, 0x13, 0x01, 0x01 }, - {0}, false, "TimedTextWrapping" }, + {0}, false, "TimedTextWrappingClip" }, { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01, // 256 0x0d, 0x01, 0x03, 0x01, 0x17, 0x01, 0x0b, 0x01 }, {0}, false, "TimedTextEssence" }, @@ -842,7 +842,7 @@ static const ASDCP::MDDEntry s_MDD_Table[] = { { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 268 0x01, 0x07, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00 }, {0x61, 0x02}, false, "DMSegment_TrackIDList" }, - { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x0c, // 269 + { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, // 269 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x63, 0x00 }, {0}, false, "StereoscopicPictureSubDescriptor" }, { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x07, // 270 @@ -919,7 +919,7 @@ static const ASDCP::MDDEntry s_MDD_Table[] = { {0}, false, "SoundfieldGroupLabelSubDescriptor_GroupOfSoundfieldGroupsLinkID" }, { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x05, // 294 0x0e, 0x09, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00 }, - {0}, false, "DCDataWrapping" }, + {0}, false, "DCDataWrappingFrame" }, { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x05, // 295 0x0e, 0x09, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00 }, {0}, false, "DCDataEssence" }, @@ -1091,7 +1091,7 @@ static const ASDCP::MDDEntry s_MDD_Table[] = { { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 351 0x04, 0x01, 0x02, 0x01, 0x01, 0x03, 0x01, 0x00 }, {0}, false, "GenericPictureEssenceDescriptor_CodingEquations" }, - { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x02, // 352 + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, // 352 0x04, 0x01, 0x02, 0x01, 0x01, 0x06, 0x01, 0x00 }, {0}, false, "GenericPictureEssenceDescriptor_ColorPrimaries" }, { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 353 @@ -1124,16 +1124,16 @@ static const ASDCP::MDDEntry s_MDD_Table[] = { { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 362 0x04, 0x01, 0x03, 0x02, 0x0b, 0x00, 0x00, 0x00 }, {0}, false, "GenericPictureEssenceDescriptor_AlternativeCenterCuts" }, - { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 363 + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 363 0x04, 0x01, 0x05, 0x01, 0x13, 0x00, 0x00, 0x00 }, {0x32, 0x05}, true, "GenericPictureEssenceDescriptor_ActiveHeight" }, - { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 364 + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 364 0x04, 0x01, 0x05, 0x01, 0x14, 0x00, 0x00, 0x00 }, {0x32, 0x04}, true, "GenericPictureEssenceDescriptor_ActiveWidth" }, - { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 365 + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 365 0x04, 0x01, 0x05, 0x01, 0x15, 0x00, 0x00, 0x00 }, {0x32, 0x06}, true, "GenericPictureEssenceDescriptor_ActiveXOffset" }, - { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 366 + { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, // 366 0x04, 0x01, 0x05, 0x01, 0x16, 0x00, 0x00, 0x00 }, {0x32, 0x07}, true, "GenericPictureEssenceDescriptor_ActiveYOffset" }, { { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, // 367 @@ -1145,6 +1145,10 @@ static const ASDCP::MDDEntry s_MDD_Table[] = { { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 369 0x04, 0x01, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00 }, {0}, false, "AlternativeCenterCuts_14x9" }, + { { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, // 370 + 0x0d, 0x01, 0x03, 0x01, 0x02, 0x06, 0x02, 0x00 }, + {0}, false, "WAVWrappingClip" }, + { {0}, {0}, false, 0 } }; @@ -44,9 +44,9 @@ namespace ASDCP { MDD_SoundDataDef, // 6 MDD_TimecodeDataDef, // 7 MDD_DescriptiveMetaDataDef, // 8 - MDD_WAVWrapping, // 9 - MDD_MPEG2_VESWrapping, // 10 - MDD_JPEG_2000Wrapping, // 11 + MDD_WAVWrappingFrame, // 9 + MDD_MPEG2_VESWrappingFrame, // 10 + MDD_JPEG_2000WrappingFrame, // 11 MDD_JPEG2000Essence, // 12 MDD_MPEG2Essence, // 13 MDD_MXFInterop_CryptEssence, // 14 @@ -290,7 +290,7 @@ namespace ASDCP { MDD_CryptographicContext_CipherAlgorithm, // 252 MDD_CryptographicContext_MICAlgorithm, // 253 MDD_CryptographicContext_CryptographicKeyID, // 254 - MDD_TimedTextWrapping, // 255 + MDD_TimedTextWrappingClip, // 255 MDD_TimedTextEssence, // 256 MDD_TimedTextDescriptor, // 257 MDD_TimedTextDescriptor_ResourceID, // 258 @@ -329,7 +329,7 @@ namespace ASDCP { MDD_MCALabelSubDescriptor_RFC5646SpokenLanguage, // 291 MDD_AudioChannelLabelSubDescriptor_SoundfieldGroupLinkID, // 292 MDD_SoundfieldGroupLabelSubDescriptor_GroupOfSoundfieldGroupsLinkID, // 293 - MDD_DCDataWrapping, // 294 + MDD_DCDataWrappingFrame, // 294 MDD_DCDataEssence, // 295 MDD_DCDataDescriptor, // 296 MDD_DolbyAtmosSubDescriptor, // 297 @@ -405,6 +405,7 @@ namespace ASDCP { MDD_TimedTextDescriptor_RFC5646LanguageTagList, // 367 MDD_AlternativeCenterCuts_4x3, // 368 MDD_AlternativeCenterCuts_14x9, // 369 + MDD_WAVWrappingClip, // 370 MDD_Max }; // enum MDD_t diff --git a/src/MXF.cpp b/src/MXF.cpp index 15a9ba0..02bf1e9 100755 --- a/src/MXF.cpp +++ b/src/MXF.cpp @@ -1099,17 +1099,17 @@ ASDCP::MXF::OPAtomIndexFooter::WriteToFile(Kumu::FileWriter& Writer, ui64_t dura std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin(); for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ ) { - if ( (*pl_i)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) ) + IndexTableSegment *segment = dynamic_cast<IndexTableSegment*>(*pl_i); + + if ( segment != 0 ) { iseg_count++; - IndexTableSegment* Segment = (IndexTableSegment*)(*pl_i); - if ( m_BytesPerEditUnit != 0 ) { if ( iseg_count != 1 ) return RESULT_STATE; - Segment->IndexDuration = duration; + segment->IndexDuration = duration; } } @@ -1186,28 +1186,29 @@ ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::Index std::list<InterchangeObject*>::iterator li; for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ ) { - if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) ) + IndexTableSegment *segment = dynamic_cast<IndexTableSegment*>(*li); + + if ( segment != 0 ) { - IndexTableSegment* Segment = (IndexTableSegment*)(*li); - ui64_t start_pos = Segment->IndexStartPosition; + ui64_t start_pos = segment->IndexStartPosition; - if ( Segment->EditUnitByteCount > 0 ) + if ( segment->EditUnitByteCount > 0 ) { if ( m_PacketList->m_List.size() > 1 ) DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n"); - if ( ! Segment->IndexEntryArray.empty() ) + if ( ! segment->IndexEntryArray.empty() ) DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n"); - Entry.StreamOffset = (ui64_t)frame_num * Segment->EditUnitByteCount; + Entry.StreamOffset = (ui64_t)frame_num * segment->EditUnitByteCount; return RESULT_OK; } else if ( (ui64_t)frame_num >= start_pos - && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) ) + && (ui64_t)frame_num < (start_pos + segment->IndexDuration) ) { ui64_t tmp = frame_num - start_pos; assert(tmp <= 0xFFFFFFFFL); - Entry = Segment->IndexEntryArray[(ui32_t) tmp]; + Entry = segment->IndexEntryArray[(ui32_t) tmp]; return RESULT_OK; } } @@ -1375,7 +1376,7 @@ ASDCP::MXF::InterchangeObject::Dump(FILE* stream) bool ASDCP::MXF::InterchangeObject::IsA(const byte_t* label) { - if ( m_KLLength == 0 ) + if ( m_KLLength == 0 || m_KeyStart == 0 ) return false; return ( memcmp(label, m_KeyStart, SMPTE_UL_LENGTH) == 0 ); diff --git a/src/Makefile.am b/src/Makefile.am index 0e921ad..c1bcf00 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -128,6 +128,8 @@ libas02_la_SOURCES = \ AS_02_internal.h \ h__02_Reader.cpp \ h__02_Writer.cpp \ + ST2052_TextParser.cpp \ + AS_02_TimedText.cpp \ AS_02_JP2K.cpp \ AS_02_PCM.cpp diff --git a/src/TimedText_Parser.cpp b/src/TimedText_Parser.cpp index a1f3de4..b7b58c5 100644 --- a/src/TimedText_Parser.cpp +++ b/src/TimedText_Parser.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2007-2009, John Hurst +Copyright (c) 2007-2013, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -44,54 +44,61 @@ const char* c_dcst_namespace_name = "http://www.smpte-ra.org/schemas/428-7/2007/ //------------------------------------------------------------------------------------------ +ASDCP::TimedText::LocalFilenameResolver::LocalFilenameResolver() {} -class LocalFilenameResolver : public ASDCP::TimedText::IResourceResolver +// +Result_t +ASDCP::TimedText::LocalFilenameResolver::OpenRead(const std::string& dirname) { - std::string m_Dirname; - - LocalFilenameResolver(); - bool operator==(const LocalFilenameResolver&); - -public: - LocalFilenameResolver(const std::string& dirname) - { - if ( PathIsDirectory(dirname) ) - { - m_Dirname = dirname; - return; - } - - DefaultLogSink().Error("Path '%s' is not a directory, defaulting to '.'\n", dirname.c_str()); - m_Dirname = "."; - } + if ( PathIsDirectory(dirname) ) + { + m_Dirname = dirname; + return RESULT_OK; + } - // - Result_t ResolveRID(const byte_t* uuid, TimedText::FrameBuffer& FrameBuf) const - { - FileReader Reader; - char buf[64]; - UUID RID(uuid); - std::string filename = m_Dirname + "/" + RID.EncodeHex(buf, 64); - DefaultLogSink().Debug("retrieving resource %s from file %s\n", buf, filename.c_str()); + DefaultLogSink().Error("Path '%s' is not a directory, defaulting to '.'\n", dirname.c_str()); + m_Dirname = "."; + return RESULT_FALSE; +} - Result_t result = Reader.OpenRead(filename.c_str()); +// +Result_t +ASDCP::TimedText::LocalFilenameResolver::ResolveRID(const byte_t* uuid, TimedText::FrameBuffer& FrameBuf) const +{ + Result_t result = RESULT_NOT_FOUND; + char buf[64]; + UUID RID(uuid); + PathList_t found_list; - if ( KM_SUCCESS(result) ) - { - ui32_t read_count, read_size = Reader.Size(); + FindInPath(PathMatchRegex(RID.EncodeHex(buf, 64)), m_Dirname, found_list); - result = FrameBuf.Capacity(read_size); + if ( found_list.size() == 1 ) + { + FileReader Reader; + DefaultLogSink().Debug("retrieving resource %s from file %s\n", buf, found_list.front().c_str()); - if ( KM_SUCCESS(result) ) - result = Reader.Read(FrameBuf.Data(), read_size, &read_count); + result = Reader.OpenRead(found_list.front().c_str()); - if ( KM_SUCCESS(result) ) - FrameBuf.Size(read_count); - } + if ( KM_SUCCESS(result) ) + { + ui32_t read_count, read_size = Reader.Size(); + result = FrameBuf.Capacity(read_size); + + if ( KM_SUCCESS(result) ) + result = Reader.Read(FrameBuf.Data(), read_size, &read_count); + + if ( KM_SUCCESS(result) ) + FrameBuf.Size(read_count); + } + } + else if ( ! found_list.empty() ) + { + DefaultLogSink().Error("More than one file in %s matches %s.\n", m_Dirname.c_str(), buf); + result = RESULT_RAW_FORMAT; + } - return result; - } -}; + return result; +} //------------------------------------------------------------------------------------------ @@ -121,8 +128,11 @@ public: TimedText::IResourceResolver* GetDefaultResolver() { if ( m_DefaultResolver.empty() ) - m_DefaultResolver = new LocalFilenameResolver(PathDirname(m_Filename)); - + { + m_DefaultResolver = new LocalFilenameResolver(); + m_DefaultResolver->OpenRead(PathDirname(m_Filename)); + } + return m_DefaultResolver; } @@ -448,5 +458,5 @@ ASDCP::TimedText::DCSubtitleParser::ReadAncillaryResource(const byte_t* uuid, Fr // -// end AS_DCP_timedText.cpp +// end AS_DCP_TimedTextParser.cpp // diff --git a/src/as-02-wrap.cpp b/src/as-02-wrap.cpp index 57515c4..0a31a60 100755 --- a/src/as-02-wrap.cpp +++ b/src/as-02-wrap.cpp @@ -179,6 +179,7 @@ public: ui32_t start_frame; // frame number to begin processing ui32_t duration; // number of frames to be processed bool j2c_pedantic; // passed to JP2K::SequenceParser::OpenRead + bool use_cdci_descriptor; // Rational edit_rate; // edit rate of JP2K sequence ui32_t fb_size; // size of picture frame buffer byte_t key_value[KeyLen]; // value of given encryption key (when key_flag is true) @@ -190,6 +191,10 @@ public: Kumu::PathList_t filenames; // list of filenames to be processed UL channel_assignment; ASDCP::MXF::AS02_MCAConfigParser mca_config; + ui32_t cdci_depth; + ui32_t rgba_MaxRef; + ui32_t rgba_MinRef; + ui32_t mxf_header_size; //new attributes for AS-02 support AS_02::IndexStrategy_t index_strategy; //Shim parameter index_strategy_frame/clip @@ -200,9 +205,10 @@ public: error_flag(true), key_flag(false), key_id_flag(false), asset_id_flag(false), encrypt_header_flag(true), write_hmac(true), verbose_flag(false), fb_dump_size(0), no_write_flag(false), version_flag(false), help_flag(false), start_frame(0), - duration(0xffffffff), j2c_pedantic(true), edit_rate(24,1), fb_size(FRAME_BUFFER_SIZE), + duration(0xffffffff), j2c_pedantic(true), use_cdci_descriptor(false), edit_rate(24,1), fb_size(FRAME_BUFFER_SIZE), show_ul_values_flag(false), index_strategy(AS_02::IS_FOLLOW), partition_space(60), - mca_config(g_dict) + mca_config(g_dict), cdci_depth(0), rgba_MaxRef(1024), rgba_MinRef(0), mxf_header_size(16384) + { memset(key_value, 0, KeyLen); memset(key_id_value, 0, UUIDlen); @@ -367,8 +373,8 @@ public: namespace ASDCP { Result_t JP2K_PDesc_to_MD(const ASDCP::JP2K::PictureDescriptor& PDesc, const ASDCP::Dictionary& dict, - ASDCP::MXF::RGBAEssenceDescriptor *EssenceDescriptor, - ASDCP::MXF::JPEG2000PictureSubDescriptor *EssenceSubDescriptor); + ASDCP::MXF::GenericPictureEssenceDescriptor& GenericPictureEssenceDescriptor, + ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor); Result_t PCM_ADesc_to_MD(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::MXF::WaveAudioDescriptor* ADescObj); } @@ -386,7 +392,7 @@ write_JP2K_file(CommandOptions& Options) JP2K::SequenceParser Parser; byte_t IV_buf[CBC_BLOCK_SIZE]; Kumu::FortunaRNG RNG; - ASDCP::MXF::RGBAEssenceDescriptor *essence_descriptor = 0; + ASDCP::MXF::FileDescriptor *essence_descriptor = 0; ASDCP::MXF::InterchangeObject_list_t essence_sub_descriptors; // set up essence parser @@ -407,17 +413,47 @@ write_JP2K_file(CommandOptions& Options) JP2K::PictureDescriptorDump(PDesc); } - // TODO: optionally set up CDCIEssenceDescriptor - essence_descriptor = new ASDCP::MXF::RGBAEssenceDescriptor(g_dict); - essence_sub_descriptors.push_back(new ASDCP::MXF::JPEG2000PictureSubDescriptor(g_dict)); + if ( Options.use_cdci_descriptor ) + { + ASDCP::MXF::CDCIEssenceDescriptor* tmp_dscr = new ASDCP::MXF::CDCIEssenceDescriptor(g_dict); + essence_sub_descriptors.push_back(new ASDCP::MXF::JPEG2000PictureSubDescriptor(g_dict)); + + result = ASDCP::JP2K_PDesc_to_MD(PDesc, *g_dict, + *static_cast<ASDCP::MXF::GenericPictureEssenceDescriptor*>(tmp_dscr), + *static_cast<ASDCP::MXF::JPEG2000PictureSubDescriptor*>(essence_sub_descriptors.back())); + + if ( ASDCP_SUCCESS(result) ) + { + // TODO, select profile + tmp_dscr->PictureEssenceCoding = UL(g_dict->ul(MDD_JP2KEssenceCompression_BroadcastProfile_1)); + tmp_dscr->ComponentDepth = Options.cdci_depth; + + // more options here - result = ASDCP::JP2K_PDesc_to_MD(PDesc, *g_dict, essence_descriptor, - reinterpret_cast<ASDCP::MXF::JPEG2000PictureSubDescriptor*>(essence_sub_descriptors.back())); + essence_descriptor = static_cast<ASDCP::MXF::FileDescriptor*>(tmp_dscr); + } + } + else + { // use RGB + ASDCP::MXF::RGBAEssenceDescriptor* tmp_dscr = new ASDCP::MXF::RGBAEssenceDescriptor(g_dict); + essence_sub_descriptors.push_back(new ASDCP::MXF::JPEG2000PictureSubDescriptor(g_dict)); + + result = ASDCP::JP2K_PDesc_to_MD(PDesc, *g_dict, + *static_cast<ASDCP::MXF::GenericPictureEssenceDescriptor*>(tmp_dscr), + *static_cast<ASDCP::MXF::JPEG2000PictureSubDescriptor*>(essence_sub_descriptors.back())); + + if ( ASDCP_SUCCESS(result) ) + { + // TODO, select profile + tmp_dscr->PictureEssenceCoding = UL(g_dict->ul(MDD_JP2KEssenceCompression_BroadcastProfile_1)); + tmp_dscr->ComponentMaxRef = Options.rgba_MaxRef; + tmp_dscr->ComponentMinRef = Options.rgba_MinRef; - /// TODO: set with magic or some such thing - essence_descriptor->PictureEssenceCoding = UL(g_dict->ul(MDD_JP2KEssenceCompression_BroadcastProfile_1)); - essence_descriptor->ComponentMaxRef = 4095; - essence_descriptor->ComponentMinRef = 0; + // more options here + + essence_descriptor = static_cast<ASDCP::MXF::FileDescriptor*>(tmp_dscr); + } + } } if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) @@ -457,11 +493,8 @@ write_JP2K_file(CommandOptions& Options) if ( ASDCP_SUCCESS(result) ) { - result = Writer.OpenWrite(Options.out_file, Info, - static_cast<ASDCP::MXF::FileDescriptor*>(essence_descriptor), - essence_sub_descriptors, - Options.edit_rate, 16384, Options.index_strategy, Options.partition_space); - // TODO: make 16384 part of CommandOptions + result = Writer.OpenWrite(Options.out_file, Info, essence_descriptor, essence_sub_descriptors, + Options.edit_rate, Options.mxf_header_size, Options.index_strategy, Options.partition_space); } } @@ -510,8 +543,8 @@ write_JP2K_file(CommandOptions& Options) // PCM essence -// Write one or more plaintext PCM audio streams to a plaintext ASDCP file -// Write one or more plaintext PCM audio streams to a ciphertext ASDCP file +// Write one or more plaintext PCM audio streams to a plaintext AS-02 file +// Write one or more plaintext PCM audio streams to a ciphertext AS-02 file // Result_t write_PCM_file(CommandOptions& Options) @@ -659,6 +692,121 @@ write_PCM_file(CommandOptions& Options) } +//------------------------------------------------------------------------------------------ +// TimedText essence + + +// Write one or more plaintext timed text streams to a plaintext AS-02 file +// Write one or more plaintext timed text streams to a ciphertext AS-02 file +// +Result_t +write_timed_text_file(CommandOptions& Options) +{ + AESEncContext* Context = 0; + HMACContext* HMAC = 0; + AS_02::TimedText::ST2052_TextParser Parser; + AS_02::TimedText::MXFWriter Writer; + TimedText::FrameBuffer FrameBuffer; + TimedText::TimedTextDescriptor TDesc; + byte_t IV_buf[CBC_BLOCK_SIZE]; + Kumu::FortunaRNG RNG; + + // set up essence parser + Result_t result = Parser.OpenRead(Options.filenames.front().c_str()); + + // set up MXF writer + if ( ASDCP_SUCCESS(result) ) + { + Parser.FillTimedTextDescriptor(TDesc); + FrameBuffer.Capacity(Options.fb_size); + + if ( Options.verbose_flag ) + { + fputs("IMF Timed-Text Descriptor:\n", stderr); + TimedText::DescriptorDump(TDesc); + } + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + { + WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here + if ( Options.asset_id_flag ) + memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen); + else + Kumu::GenRandomUUID(Info.AssetUUID); + + // configure encryption + if( Options.key_flag ) + { + Kumu::GenRandomUUID(Info.ContextID); + Info.EncryptedEssence = true; + + if ( Options.key_id_flag ) + memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen); + else + RNG.FillRandom(Info.CryptographicKeyID, UUIDlen); + + Context = new AESEncContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) ) + result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + + if ( ASDCP_SUCCESS(result) && Options.write_hmac ) + { + Info.UsesHMAC = true; + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + } + + if ( ASDCP_SUCCESS(result) ) + result = Writer.OpenWrite(Options.out_file.c_str(), Info, TDesc); + } + + if ( ASDCP_FAILURE(result) ) + return result; + + std::string XMLDoc; + TimedText::ResourceList_t::const_iterator ri; + + result = Parser.ReadTimedTextResource(XMLDoc); + + if ( ASDCP_SUCCESS(result) ) + result = Writer.WriteTimedTextResource(XMLDoc, Context, HMAC); + + for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ ) + { + result = Parser.ReadAncillaryResource((*ri).ResourceID, FrameBuffer); + + if ( ASDCP_SUCCESS(result) ) + { + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + + if ( ! Options.no_write_flag ) + { + result = Writer.WriteAncillaryResource(FrameBuffer, Context, HMAC); + + // The Writer class will forward the last block of ciphertext + // to the encryption context for use as the IV for the next + // frame. If you want to use non-sequitur IV values, un-comment + // the following line of code. + // if ( ASDCP_SUCCESS(result) && Options.key_flag ) + // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE)); + } + } + + if ( result == RESULT_ENDOFFILE ) + result = RESULT_OK; + } + + if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag ) + result = Writer.Finalize(); + + return result; +} + // int main(int argc, const char** argv) @@ -666,6 +814,7 @@ main(int argc, const char** argv) Result_t result = RESULT_OK; char str_buf[64]; g_dict = &ASDCP::DefaultSMPTEDict(); + assert(g_dict); CommandOptions Options(argc, argv); diff --git a/src/asdcp-info.cpp b/src/asdcp-info.cpp index 4a03bde..df69d2b 100755 --- a/src/asdcp-info.cpp +++ b/src/asdcp-info.cpp @@ -93,7 +93,7 @@ USAGE:%s [-h|-help] [-V]\n\ \n\ Options:\n\ -3 - Force stereoscopic interpretation of a JP2K file\n\ - -C - Do not show essence coding UL\n\ + -c - Show essence coding UL\n\ -d - Show essence descriptor info\n\ -h | -help - Show help\n\ -H - Show MXF header metadata\n\ @@ -326,7 +326,8 @@ public: m_Desc.FillDescriptor(m_Reader); m_Reader.FillWriterInfo(m_WriterInfo); - fprintf(stdout, "File essence type is %s, (%d edit unit%s).\n", + fprintf(stdout, "%s file essence type is %s, (%d edit unit%s).\n", + ( m_WriterInfo.LabelSetType == LS_MXF_SMPTE ? "SMPTE 429" : LS_MXF_INTEROP ? "Interop" : "Unknown" ), type_string, m_Desc.ContainerDuration, (m_Desc.ContainerDuration==1?"":"s")); if ( Options.showheader_flag ) @@ -488,7 +489,7 @@ public: } // scale bytes to megabits - static const double mega_const = 1 / ( 1024.0 * 1024.0 / 8.0 ); + static const double mega_const = 1.0 / ( 1000000 / 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 ); diff --git a/src/asdcp-wrap.cpp b/src/asdcp-wrap.cpp index 04608d3..3bad03e 100755 --- a/src/asdcp-wrap.cpp +++ b/src/asdcp-wrap.cpp @@ -222,7 +222,7 @@ public: byte_t asset_id_value[UUIDlen];// value of asset ID (when asset_id_flag is true) PCM::ChannelFormat_t channel_fmt; // audio channel arrangement std::string out_file; // - bool show_ul_values_flag; /// if true, dump the UL table before going tp work. + bool show_ul_values_flag; /// if true, dump the UL table before going to work. Kumu::PathList_t filenames; // list of filenames to be processed UL channel_assignment; UL picture_coding; @@ -1232,11 +1232,9 @@ write_timed_text_file(CommandOptions& Options) else Kumu::GenRandomUUID(Info.AssetUUID); - if ( Options.use_smpte_labels ) - { - Info.LabelSetType = LS_MXF_SMPTE; - fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n"); - } + // 428-7 IN 429-5 always uses SMPTE labels + Info.LabelSetType = LS_MXF_SMPTE; + fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n"); // configure encryption if( Options.key_flag ) diff --git a/src/h__02_Reader.cpp b/src/h__02_Reader.cpp index a433026..1a0de11 100644 --- a/src/h__02_Reader.cpp +++ b/src/h__02_Reader.cpp @@ -200,9 +200,11 @@ AS_02::MXF::AS02IndexReader::InitFromFile(const Kumu::FileReader& reader, const for ( ii = m_PacketList->m_List.begin(); ii != m_PacketList->m_List.end(); ++ii ) { - if ( (*ii)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) ) + IndexTableSegment *segment = dynamic_cast<IndexTableSegment*>(*ii); + + if ( segment != 0 ) { - m_Duration += static_cast<IndexTableSegment*>(*ii)->IndexDuration; + m_Duration += segment->IndexDuration; } } } @@ -263,10 +265,12 @@ AS_02::MXF::AS02IndexReader::InitFromBuffer(const byte_t* p, ui32_t l, const ui6 if ( KM_SUCCESS(result) ) { - if ( object->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) ) + IndexTableSegment *segment = dynamic_cast<IndexTableSegment*>(object); + + if ( segment != 0 ) { - static_cast<IndexTableSegment*>(object)->RtFileOffset = essence_container_offset; - static_cast<IndexTableSegment*>(object)->RtEntryOffset = body_offset; + segment->RtFileOffset = essence_container_offset; + segment->RtEntryOffset = body_offset; m_PacketList->AddPacket(object); // takes ownership } else @@ -340,29 +344,30 @@ AS_02::MXF::AS02IndexReader::Lookup(ui32_t frame_num, ASDCP::MXF::IndexTableSegm std::list<InterchangeObject*>::iterator li; for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ ) { - if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) ) + IndexTableSegment *segment = dynamic_cast<IndexTableSegment*>(*li); + + if ( segment != 0 ) { - IndexTableSegment* Segment = static_cast<IndexTableSegment*>(*li); - ui64_t start_pos = Segment->IndexStartPosition; + ui64_t start_pos = segment->IndexStartPosition; - if ( Segment->EditUnitByteCount > 0 ) + if ( segment->EditUnitByteCount > 0 ) { if ( m_PacketList->m_List.size() > 1 ) DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n"); - if ( ! Segment->IndexEntryArray.empty() ) + if ( ! segment->IndexEntryArray.empty() ) DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n"); - Entry.StreamOffset = ((ui64_t)frame_num * Segment->EditUnitByteCount) + Segment->RtFileOffset; + Entry.StreamOffset = ((ui64_t)frame_num * segment->EditUnitByteCount) + segment->RtFileOffset; return RESULT_OK; } else if ( (ui64_t)frame_num >= start_pos - && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) ) + && (ui64_t)frame_num < (start_pos + segment->IndexDuration) ) { ui64_t tmp = frame_num - start_pos; assert(tmp <= 0xFFFFFFFFL); - Entry = Segment->IndexEntryArray[(ui32_t) tmp]; - Entry.StreamOffset = Entry.StreamOffset - Segment->RtEntryOffset + Segment->RtFileOffset; + Entry = segment->IndexEntryArray[(ui32_t) tmp]; + Entry.StreamOffset = Entry.StreamOffset - segment->RtEntryOffset + segment->RtFileOffset; return RESULT_OK; } } diff --git a/src/h__02_Writer.cpp b/src/h__02_Writer.cpp index a121142..c81da5c 100644 --- a/src/h__02_Writer.cpp +++ b/src/h__02_Writer.cpp @@ -122,23 +122,25 @@ AS_02::MXF::AS02IndexWriter::Dump(FILE* stream) Partition::Dump(stream); std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin(); - for ( ; i != m_PacketList->m_List.end(); i++ ) - (*i)->Dump(stream); + for ( ; i != m_PacketList->m_List.end(); ++i ) + { + (*i)->Dump(stream); + } } // ui32_t AS_02::MXF::AS02IndexWriter::GetDuration() const { - ui32_t duration; + ui32_t duration = 0; std::list<InterchangeObject*>::const_iterator i; for ( i = m_PacketList->m_List.begin(); i != m_PacketList->m_List.end(); ++i ) { - if ( (*i)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) ) + IndexTableSegment* segment = dynamic_cast<IndexTableSegment*>(*i); + if ( segment != 0 ) { - IndexTableSegment& Segment = *(IndexTableSegment*)*i; - duration += Segment.IndexDuration; + duration += segment->IndexEntryArray.size(); } } @@ -380,7 +382,6 @@ AS_02::h__AS02Writer::FinalizeClip(ui32_t bytes_per_frame) Result_t AS_02::h__AS02Writer::WriteAS02Footer() { - if ( m_IndexWriter.GetDuration() > 0 ) { m_IndexWriter.ThisPartition = m_File.Tell(); |
