2 Copyright (c) 2011-2013, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3. The name of the author may not be used to endorse or promote products
16 derived from this software without specific prior written permission.
18 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 /*! \file h__02_Writer.cpp
31 \brief MXF file writer base class
34 #include "AS_02_internal.h"
36 using namespace ASDCP;
37 using namespace ASDCP::MXF;
39 static const ui32_t CBRIndexEntriesPerSegment = 5000;
42 //------------------------------------------------------------------------------------------
45 AS_02::MXF::AS02IndexWriterVBR::AS02IndexWriterVBR(const ASDCP::Dictionary*& d) :
46 Partition(d), m_CurrentSegment(0), m_Dict(d), m_Lookup(0)
52 AS_02::MXF::AS02IndexWriterVBR::~AS02IndexWriterVBR() {}
56 AS_02::MXF::AS02IndexWriterVBR::WriteToFile(Kumu::FileWriter& Writer)
59 ASDCP::FrameBuffer index_body_buffer;
60 ui32_t index_body_size = m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size
61 Result_t result = index_body_buffer.Capacity(index_body_size);
62 ui64_t start_position = 0;
64 if ( m_CurrentSegment != 0 )
66 m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
67 start_position = m_CurrentSegment->IndexStartPosition + m_CurrentSegment->IndexDuration;
71 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
72 for ( ; pl_i != m_PacketList->m_List.end() && KM_SUCCESS(result); pl_i++ )
74 InterchangeObject* object = *pl_i;
75 object->m_Lookup = m_Lookup;
77 ASDCP::FrameBuffer WriteWrapper;
78 WriteWrapper.SetData(index_body_buffer.Data() + index_body_buffer.Size(),
79 index_body_buffer.Capacity() - index_body_buffer.Size());
80 result = object->WriteToBuffer(WriteWrapper);
81 index_body_buffer.Size(index_body_buffer.Size() + WriteWrapper.Size());
86 m_PacketList->m_List.clear();
88 if ( KM_SUCCESS(result) )
90 IndexByteCount = index_body_buffer.Size();
91 UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
92 result = Partition::WriteToFile(Writer, body_ul);
95 if ( KM_SUCCESS(result) )
97 ui32_t write_count = 0;
98 result = Writer.Write(index_body_buffer.RoData(), index_body_buffer.Size(), &write_count);
99 assert(write_count == index_body_buffer.Size());
102 if ( KM_SUCCESS(result) )
104 m_CurrentSegment = new IndexTableSegment(m_Dict);
105 assert(m_CurrentSegment);
106 AddChildObject(m_CurrentSegment);
107 m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
108 m_CurrentSegment->IndexEditRate = m_EditRate;
109 m_CurrentSegment->IndexStartPosition = start_position;
117 AS_02::MXF::AS02IndexWriterVBR::Dump(FILE* stream)
122 Partition::Dump(stream);
124 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
125 for ( ; i != m_PacketList->m_List.end(); ++i )
133 AS_02::MXF::AS02IndexWriterVBR::GetDuration() const
136 std::list<InterchangeObject*>::const_iterator i;
138 for ( i = m_PacketList->m_List.begin(); i != m_PacketList->m_List.end(); ++i )
140 IndexTableSegment* segment = dynamic_cast<IndexTableSegment*>(*i);
143 duration += segment->IndexEntryArray.size();
152 AS_02::MXF::AS02IndexWriterVBR::PushIndexEntry(const IndexTableSegment::IndexEntry& Entry)
154 // do we have an available segment?
155 if ( m_CurrentSegment == 0 )
156 { // no, set up a new segment
157 m_CurrentSegment = new IndexTableSegment(m_Dict);
158 assert(m_CurrentSegment);
159 AddChildObject(m_CurrentSegment);
160 m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
161 m_CurrentSegment->IndexEditRate = m_EditRate;
162 m_CurrentSegment->IndexStartPosition = 0;
165 m_CurrentSegment->IndexEntryArray.push_back(Entry);
169 //------------------------------------------------------------------------------------------
173 AS_02::h__AS02WriterFrame::h__AS02WriterFrame(const ASDCP::Dictionary& d) :
174 h__AS02Writer<AS_02::MXF::AS02IndexWriterVBR>(d), m_IndexStrategy(AS_02::IS_FOLLOW) {}
176 AS_02::h__AS02WriterFrame::~h__AS02WriterFrame() {}
180 AS_02::h__AS02WriterFrame::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC)
182 ui64_t this_stream_offset = m_StreamOffset; // m_StreamOffset will be changed by the call to Write_EKLV_Packet
184 Result_t result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
185 m_StreamOffset, FrameBuf, EssenceUL, Ctx, HMAC);
187 if ( KM_SUCCESS(result) )
189 IndexTableSegment::IndexEntry Entry;
190 Entry.StreamOffset = this_stream_offset;
191 m_IndexWriter.PushIndexEntry(Entry);
194 if ( m_FramesWritten > 1 && ( ( m_FramesWritten + 1 ) % m_PartitionSpace ) == 0 )
196 m_IndexWriter.ThisPartition = m_File.Tell();
197 m_IndexWriter.WriteToFile(m_File);
198 m_RIP.PairArray.push_back(RIP::PartitionPair(0, m_IndexWriter.ThisPartition));
200 UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
201 Partition body_part(m_Dict);
202 body_part.BodySID = 1;
203 body_part.OperationalPattern = m_HeaderPart.OperationalPattern;
204 body_part.EssenceContainers = m_HeaderPart.EssenceContainers;
205 body_part.ThisPartition = m_File.Tell();
207 body_part.BodyOffset = m_StreamOffset;
208 result = body_part.WriteToFile(m_File, body_ul);
209 m_RIP.PairArray.push_back(RIP::PartitionPair(1, body_part.ThisPartition));
216 //------------------------------------------------------------------------------------------
220 AS_02::MXF::AS02IndexWriterCBR::AS02IndexWriterCBR(const ASDCP::Dictionary*& d) :
221 Partition(d), m_CurrentSegment(0), m_Dict(d), m_Lookup(0), m_Duration(0), m_SampleSize(0)
227 AS_02::MXF::AS02IndexWriterCBR::~AS02IndexWriterCBR() {}
231 AS_02::MXF::AS02IndexWriterCBR::WriteToFile(Kumu::FileWriter& Writer)
234 ASDCP::FrameBuffer index_body_buffer;
235 ui32_t index_body_size = MaxIndexSegmentSize; // segment-count * max-segment-size
236 Result_t result = index_body_buffer.Capacity(index_body_size);
238 m_CurrentSegment = new IndexTableSegment(m_Dict);
239 assert(m_CurrentSegment);
240 m_CurrentSegment->m_Lookup = m_Lookup;
241 m_CurrentSegment->IndexEditRate = m_EditRate;
242 m_CurrentSegment->IndexStartPosition = 0;
243 m_CurrentSegment->IndexDuration = m_Duration;
244 m_CurrentSegment->EditUnitByteCount = m_SampleSize;
245 AddChildObject(m_CurrentSegment);
247 ASDCP::FrameBuffer WriteWrapper;
248 WriteWrapper.SetData(index_body_buffer.Data() + index_body_buffer.Size(),
249 index_body_buffer.Capacity() - index_body_buffer.Size());
251 result = m_CurrentSegment->WriteToBuffer(WriteWrapper);
252 index_body_buffer.Size(index_body_buffer.Size() + WriteWrapper.Size());
253 delete m_CurrentSegment;
254 m_CurrentSegment = 0;
255 m_PacketList->m_List.clear();
257 if ( KM_SUCCESS(result) )
259 IndexByteCount = index_body_buffer.Size();
260 UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
261 result = Partition::WriteToFile(Writer, body_ul);
264 if ( KM_SUCCESS(result) )
266 ui32_t write_count = 0;
267 result = Writer.Write(index_body_buffer.RoData(), index_body_buffer.Size(), &write_count);
268 assert(write_count == index_body_buffer.Size());
276 AS_02::MXF::AS02IndexWriterCBR::GetDuration() const
283 AS_02::MXF::AS02IndexWriterCBR::SetEditRate(const ASDCP::Rational& edit_rate, const ui32_t& sample_size)
285 m_EditRate = edit_rate;
286 m_SampleSize = sample_size;
290 //------------------------------------------------------------------------------------------
294 AS_02::h__AS02WriterClip::h__AS02WriterClip(const ASDCP::Dictionary& d) :
295 h__AS02Writer<AS_02::MXF::AS02IndexWriterCBR>(d),
296 m_ECStart(0), m_ClipStart(0), m_IndexStrategy(AS_02::IS_FOLLOW) {}
298 AS_02::h__AS02WriterClip::~h__AS02WriterClip() {}
302 AS_02::h__AS02WriterClip::HasOpenClip() const
304 return m_ClipStart != 0;
309 AS_02::h__AS02WriterClip::StartClip(const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC)
313 DefaultLogSink().Error("Encryption not yet supported for PCM clip-wrap.\n");
317 if ( m_ClipStart != 0 )
319 DefaultLogSink().Error("Cannot open clip, clip already open.\n");
323 m_ClipStart = m_File.Tell();
324 byte_t clip_buffer[24] = {0};
325 memcpy(clip_buffer, EssenceUL, 16);
326 bool check = Kumu::write_BER(clip_buffer+16, 0, 8);
328 return m_File.Write(clip_buffer, 24);
333 AS_02::h__AS02WriterClip::WriteClipBlock(const ASDCP::FrameBuffer& FrameBuf)
335 if ( m_ClipStart == 0 )
337 DefaultLogSink().Error("Cannot write clip block, no clip open.\n");
341 return m_File.Write(FrameBuf.RoData(), FrameBuf.Size());
346 AS_02::h__AS02WriterClip::FinalizeClip(ui32_t bytes_per_frame)
348 if ( m_ClipStart == 0 )
350 DefaultLogSink().Error("Cannot close clip, clip not open.\n");
354 ui64_t current_position = m_File.Tell();
355 Result_t result = m_File.Seek(m_ClipStart+16);
357 if ( KM_SUCCESS(result) )
359 byte_t clip_buffer[8] = {0};
360 ui64_t size = static_cast<ui64_t>(m_FramesWritten) * bytes_per_frame;
361 bool check = Kumu::write_BER(clip_buffer, size, 8);
363 result = m_File.Write(clip_buffer, 8);
366 if ( KM_SUCCESS(result) )
368 result = m_File.Seek(current_position);
378 // end h__02_Writer.cpp