/*
- Copyright (c) 2011-2013, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. The name of the author may not be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+Copyright (c) 2011-2013, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
+John Hurst
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*! \file h__02_Writer.cpp
\version $Id$
//------------------------------------------------------------------------------------------
//
-AS_02::AS02IndexWriter::AS02IndexWriter(const ASDCP::Dictionary*& d) :
- Partition(d), m_CurrentSegment(0), m_BytesPerEditUnit(0), m_Dict(d), m_ECOffset(0), m_Lookup(0)
+AS_02::MXF::AS02IndexWriter::AS02IndexWriter(const ASDCP::Dictionary*& d) :
+ Partition(d), m_CurrentSegment(0), m_BytesPerEditUnit(0), m_Dict(d), m_Lookup(0)
{
BodySID = 0;
IndexSID = 129;
}
-AS_02::AS02IndexWriter::~AS02IndexWriter() {}
+AS_02::MXF::AS02IndexWriter::~AS02IndexWriter() {}
//
Result_t
-AS_02::AS02IndexWriter::WriteToFile(Kumu::FileWriter& Writer)
+AS_02::MXF::AS02IndexWriter::WriteToFile(Kumu::FileWriter& Writer)
{
- // UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
-
assert(m_Dict);
- ASDCP::FrameBuffer FooterBuffer;
- ui32_t footer_size = m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size
- Result_t result = FooterBuffer.Capacity(footer_size);
- ui32_t iseg_count = 0;
+ ASDCP::FrameBuffer index_body_buffer;
+ ui32_t index_body_size = m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size
+ Result_t result = index_body_buffer.Capacity(index_body_size);
+ ui64_t start_position = 0;
if ( m_CurrentSegment != 0 )
{
m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
+ start_position = m_CurrentSegment->IndexStartPosition + m_CurrentSegment->IndexDuration;
m_CurrentSegment = 0;
}
std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
- for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
+ for ( ; pl_i != m_PacketList->m_List.end() && KM_SUCCESS(result); pl_i++ )
{
- if ( (*pl_i)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
- {
- iseg_count++;
- IndexTableSegment* Segment = (IndexTableSegment*)(*pl_i);
-
- if ( m_BytesPerEditUnit != 0 )
- {
- if ( iseg_count != 1 )
- return RESULT_STATE;
-
- /// Segment->IndexDuration = duration;
- }
- }
-
InterchangeObject* object = *pl_i;
object->m_Lookup = m_Lookup;
ASDCP::FrameBuffer WriteWrapper;
- WriteWrapper.SetData(FooterBuffer.Data() + FooterBuffer.Size(),
- FooterBuffer.Capacity() - FooterBuffer.Size());
+ WriteWrapper.SetData(index_body_buffer.Data() + index_body_buffer.Size(),
+ index_body_buffer.Capacity() - index_body_buffer.Size());
result = object->WriteToBuffer(WriteWrapper);
- FooterBuffer.Size(FooterBuffer.Size() + WriteWrapper.Size());
+ index_body_buffer.Size(index_body_buffer.Size() + WriteWrapper.Size());
+ delete *pl_i;
+ *pl_i = 0;
}
- if ( ASDCP_SUCCESS(result) )
+ m_PacketList->m_List.clear();
+
+ if ( KM_SUCCESS(result) )
{
- IndexByteCount = FooterBuffer.Size();
+ IndexByteCount = index_body_buffer.Size();
UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
result = Partition::WriteToFile(Writer, body_ul);
}
- if ( ASDCP_SUCCESS(result) )
+ if ( KM_SUCCESS(result) )
{
ui32_t write_count = 0;
- result = Writer.Write(FooterBuffer.RoData(), FooterBuffer.Size(), &write_count);
- assert(write_count == FooterBuffer.Size());
+ result = Writer.Write(index_body_buffer.RoData(), index_body_buffer.Size(), &write_count);
+ assert(write_count == index_body_buffer.Size());
}
- return result;
-}
-
-//
-void
-AS_02::AS02IndexWriter::ResetCBR(Kumu::fpos_t offset)
-{
- m_ECOffset = offset;
-
- std::list<InterchangeObject*>::iterator i;
-
- for ( i = m_PacketList->m_List.begin(); i != m_PacketList->m_List.end(); ++i )
+ if ( KM_SUCCESS(result) )
{
- delete *i;
+ m_CurrentSegment = new IndexTableSegment(m_Dict);
+ assert(m_CurrentSegment);
+ AddChildObject(m_CurrentSegment);
+ m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
+ m_CurrentSegment->IndexEditRate = m_EditRate;
+ m_CurrentSegment->IndexStartPosition = start_position;
}
- m_PacketList->m_List.clear();
+ return result;
}
//
void
-AS_02::AS02IndexWriter::Dump(FILE* stream)
+AS_02::MXF::AS02IndexWriter::Dump(FILE* stream)
{
if ( stream == 0 )
stream = stderr;
//
ui32_t
-AS_02::AS02IndexWriter::GetDuration() const
+AS_02::MXF::AS02IndexWriter::GetDuration() const
{
ui32_t duration;
std::list<InterchangeObject*>::const_iterator i;
//
void
-AS_02::AS02IndexWriter::SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const ASDCP::Rational& Rate)
+AS_02::MXF::AS02IndexWriter::SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const ASDCP::Rational& Rate)
{
assert(lookup);
m_Lookup = lookup;
//
void
-AS_02::AS02IndexWriter::SetIndexParamsVBR(IPrimerLookup* lookup, const ASDCP::Rational& Rate, Kumu::fpos_t offset)
+AS_02::MXF::AS02IndexWriter::SetIndexParamsVBR(IPrimerLookup* lookup, const ASDCP::Rational& Rate, Kumu::fpos_t offset)
{
assert(lookup);
m_Lookup = lookup;
m_BytesPerEditUnit = 0;
m_EditRate = Rate;
- m_ECOffset = offset;
}
//
void
-AS_02::AS02IndexWriter::PushIndexEntry(const IndexTableSegment::IndexEntry& Entry)
+AS_02::MXF::AS02IndexWriter::PushIndexEntry(const IndexTableSegment::IndexEntry& Entry)
{
if ( m_BytesPerEditUnit != 0 ) // are we CBR? that's bad
{
}
else if ( m_CurrentSegment->IndexEntryArray.size() >= CBRIndexEntriesPerSegment )
{ // no, this one is full, start another
+ DefaultLogSink().Warn("%s, line %d: This has never been tested.\n", __FILE__, __LINE__);
m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
- ui64_t StartPosition = m_CurrentSegment->IndexStartPosition + m_CurrentSegment->IndexDuration;
+ ui64_t start_position = m_CurrentSegment->IndexStartPosition + m_CurrentSegment->IndexDuration;
m_CurrentSegment = new IndexTableSegment(m_Dict);
assert(m_CurrentSegment);
AddChildObject(m_CurrentSegment);
m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
m_CurrentSegment->IndexEditRate = m_EditRate;
- m_CurrentSegment->IndexStartPosition = StartPosition;
+ m_CurrentSegment->IndexStartPosition = start_position;
}
m_CurrentSegment->IndexEntryArray.push_back(Entry);
//
AS_02::h__AS02Writer::h__AS02Writer(const ASDCP::Dictionary& d) : ASDCP::MXF::TrackFileWriter<ASDCP::MXF::OP1aHeader>(d),
- m_IndexWriter(m_Dict), m_PartitionSpace(0),
+ m_ECStart(0), m_ClipStart(0), m_IndexWriter(m_Dict), m_PartitionSpace(0),
m_IndexStrategy(AS_02::IS_FOLLOW) {}
AS_02::h__AS02Writer::~h__AS02Writer() {}
InitHeader();
- AddSourceClip(EditRate, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel);
+ AddSourceClip(EditRate, EditRate/*TODO: for a moment*/, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel);
AddEssenceDescriptor(WrappingUL);
m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // Header partition RIP entry
m_IndexWriter.OperationalPattern = m_HeaderPart.OperationalPattern;
if ( ASDCP_SUCCESS(result) )
{
m_PartitionSpace *= ceil(EditRate.Quotient()); // convert seconds to edit units
- Kumu::fpos_t ECoffset = m_File.Tell();
+ m_ECStart = m_File.Tell();
m_IndexWriter.IndexSID = 129;
if ( BytesPerEditUnit == 0 )
{
- m_IndexWriter.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset);
+ m_IndexWriter.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, m_ECStart);
}
else
{
body_part.BodySID = 1;
body_part.OperationalPattern = m_HeaderPart.OperationalPattern;
body_part.EssenceContainers = m_HeaderPart.EssenceContainers;
- body_part.ThisPartition = m_File.Tell();
+ body_part.ThisPartition = m_ECStart;
result = body_part.WriteToFile(m_File, body_ul);
m_RIP.PairArray.push_back(RIP::Pair(1, body_part.ThisPartition)); // Second RIP Entry
}
Result_t
AS_02::h__AS02Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC)
{
+ ui64_t this_stream_offset = m_StreamOffset; // m_StreamOffset will be changed by the call to Write_EKLV_Packet
+
Result_t result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
m_StreamOffset, FrameBuf, EssenceUL, Ctx, HMAC);
+ if ( KM_SUCCESS(result) )
+ {
+ IndexTableSegment::IndexEntry Entry;
+ Entry.StreamOffset = this_stream_offset;
+ m_IndexWriter.PushIndexEntry(Entry);
+ }
+
if ( m_FramesWritten > 0 && ( m_FramesWritten % m_PartitionSpace ) == 0 )
{
m_IndexWriter.ThisPartition = m_File.Tell();
body_part.OperationalPattern = m_HeaderPart.OperationalPattern;
body_part.EssenceContainers = m_HeaderPart.EssenceContainers;
body_part.ThisPartition = m_File.Tell();
+
+ body_part.BodyOffset = m_StreamOffset;
result = body_part.WriteToFile(m_File, body_ul);
m_RIP.PairArray.push_back(RIP::Pair(1, body_part.ThisPartition));
- m_IndexWriter.ResetCBR(m_File.Tell());
}
return result;
}
-// standard method of writing the header and footer of a completed MXF file
+//
+bool
+AS_02::h__AS02Writer::HasOpenClip() const
+{
+ return m_ClipStart != 0;
+}
+
+//
+Result_t
+AS_02::h__AS02Writer::StartClip(const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC)
+{
+ if ( Ctx != 0 )
+ {
+ DefaultLogSink().Error("Encryption not yet supported for PCM clip-wrap.\n");
+ return RESULT_STATE;
+ }
+
+ if ( m_ClipStart != 0 )
+ {
+ DefaultLogSink().Error("Cannot open clip, clip already open.\n");
+ return RESULT_STATE;
+ }
+
+ m_ClipStart = m_File.Tell();
+ byte_t clip_buffer[24] = {0};
+ memcpy(clip_buffer, EssenceUL, 16);
+ bool check = Kumu::write_BER(clip_buffer+16, 0, 8);
+ assert(check);
+ return m_File.Write(clip_buffer, 24);
+}
+
+//
+Result_t
+AS_02::h__AS02Writer::WriteClipBlock(const ASDCP::FrameBuffer& FrameBuf)
+{
+ if ( m_ClipStart == 0 )
+ {
+ DefaultLogSink().Error("Cannot write clip block, no clip open.\n");
+ return RESULT_STATE;
+ }
+
+ return m_File.Write(FrameBuf.RoData(), FrameBuf.Size());
+}
+
+//
+Result_t
+AS_02::h__AS02Writer::FinalizeClip(ui32_t bytes_per_frame)
+{
+ if ( m_ClipStart == 0 )
+ {
+ DefaultLogSink().Error("Cannot close clip, clip not open.\n");
+ return RESULT_STATE;
+ }
+
+ ui64_t current_position = m_File.Tell();
+ Result_t result = m_File.Seek(m_ClipStart+16);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ byte_t clip_buffer[8] = {0};
+ bool check = Kumu::write_BER(clip_buffer, m_FramesWritten * bytes_per_frame, 8);
+ assert(check);
+ result = m_File.Write(clip_buffer, 8);
+ }
+
+ m_File.Seek(current_position);
+ m_ClipStart = 0;
+ return result;
+}
+
+// standard method of writing the header and footer of a completed AS-02 file
//
Result_t
AS_02::h__AS02Writer::WriteAS02Footer()