2 Copyright (c) 2011-2016, 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 = (ui32_t)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 += (ui32_t)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 assert(m_IndexWriter.GetDuration() > 0);
197 FlushIndexPartition();
199 UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
200 Partition body_part(m_Dict);
201 body_part.MajorVersion = m_HeaderPart.MajorVersion;
202 body_part.MinorVersion = m_HeaderPart.MinorVersion;
203 body_part.BodySID = 1;
204 body_part.OperationalPattern = m_HeaderPart.OperationalPattern;
205 body_part.EssenceContainers = m_HeaderPart.EssenceContainers;
206 body_part.ThisPartition = m_File.Tell();
208 body_part.BodyOffset = m_StreamOffset;
209 result = body_part.WriteToFile(m_File, body_ul);
210 m_RIP.PairArray.push_back(RIP::PartitionPair(1, body_part.ThisPartition));
217 //------------------------------------------------------------------------------------------
221 AS_02::MXF::AS02IndexWriterCBR::AS02IndexWriterCBR(const ASDCP::Dictionary*& d) :
222 Partition(d), m_CurrentSegment(0), m_Dict(d), m_Lookup(0), m_Duration(0), m_SampleSize(0)
228 AS_02::MXF::AS02IndexWriterCBR::~AS02IndexWriterCBR() {}
232 AS_02::MXF::AS02IndexWriterCBR::WriteToFile(Kumu::FileWriter& Writer)
235 ASDCP::FrameBuffer index_body_buffer;
236 ui32_t index_body_size = MaxIndexSegmentSize; // segment-count * max-segment-size
237 Result_t result = index_body_buffer.Capacity(index_body_size);
239 m_CurrentSegment = new IndexTableSegment(m_Dict);
240 assert(m_CurrentSegment);
241 m_CurrentSegment->m_Lookup = m_Lookup;
242 m_CurrentSegment->IndexEditRate = m_EditRate;
243 m_CurrentSegment->IndexStartPosition = 0;
244 m_CurrentSegment->IndexDuration = m_Duration;
245 m_CurrentSegment->EditUnitByteCount = m_SampleSize;
246 AddChildObject(m_CurrentSegment);
248 ASDCP::FrameBuffer WriteWrapper;
249 WriteWrapper.SetData(index_body_buffer.Data() + index_body_buffer.Size(),
250 index_body_buffer.Capacity() - index_body_buffer.Size());
252 result = m_CurrentSegment->WriteToBuffer(WriteWrapper);
253 index_body_buffer.Size(index_body_buffer.Size() + WriteWrapper.Size());
254 delete m_CurrentSegment;
255 m_CurrentSegment = 0;
256 m_PacketList->m_List.clear();
258 if ( KM_SUCCESS(result) )
260 IndexByteCount = index_body_buffer.Size();
261 UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
262 result = Partition::WriteToFile(Writer, body_ul);
265 if ( KM_SUCCESS(result) )
267 ui32_t write_count = 0;
268 result = Writer.Write(index_body_buffer.RoData(), index_body_buffer.Size(), &write_count);
269 assert(write_count == index_body_buffer.Size());
277 AS_02::MXF::AS02IndexWriterCBR::GetDuration() const
284 AS_02::MXF::AS02IndexWriterCBR::SetEditRate(const ASDCP::Rational& edit_rate, const ui32_t& sample_size)
286 m_EditRate = edit_rate;
287 m_SampleSize = sample_size;
291 //------------------------------------------------------------------------------------------
295 AS_02::h__AS02WriterClip::h__AS02WriterClip(const ASDCP::Dictionary& d) :
296 h__AS02Writer<AS_02::MXF::AS02IndexWriterCBR>(d),
297 m_ECStart(0), m_ClipStart(0), m_IndexStrategy(AS_02::IS_FOLLOW) {}
299 AS_02::h__AS02WriterClip::~h__AS02WriterClip() {}
303 AS_02::h__AS02WriterClip::HasOpenClip() const
305 return m_ClipStart != 0;
310 AS_02::h__AS02WriterClip::StartClip(const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC)
314 DefaultLogSink().Error("Encryption not yet supported for PCM clip-wrap.\n");
318 if ( m_ClipStart != 0 )
320 DefaultLogSink().Error("Cannot open clip, clip already open.\n");
324 m_ClipStart = m_File.Tell();
325 byte_t clip_buffer[24] = {0};
326 memcpy(clip_buffer, EssenceUL, 16);
327 bool check = Kumu::write_BER(clip_buffer+16, 0, 8);
329 return m_File.Write(clip_buffer, 24);
334 AS_02::h__AS02WriterClip::WriteClipBlock(const ASDCP::FrameBuffer& FrameBuf)
336 if ( m_ClipStart == 0 )
338 DefaultLogSink().Error("Cannot write clip block, no clip open.\n");
342 return m_File.Write(FrameBuf.RoData(), FrameBuf.Size());
347 AS_02::h__AS02WriterClip::FinalizeClip(ui32_t bytes_per_frame)
349 if ( m_ClipStart == 0 )
351 DefaultLogSink().Error("Cannot close clip, clip not open.\n");
355 ui64_t current_position = m_File.Tell();
356 Result_t result = m_File.Seek(m_ClipStart+16);
358 if ( KM_SUCCESS(result) )
360 byte_t clip_buffer[8] = {0};
361 ui64_t size = static_cast<ui64_t>(m_FramesWritten) * bytes_per_frame;
362 bool check = Kumu::write_BER(clip_buffer, size, 8);
364 result = m_File.Write(clip_buffer, 8);
367 if ( KM_SUCCESS(result) )
369 result = m_File.Seek(current_position);
377 // end h__02_Writer.cpp