2 Copyright (c) 2011-2018, 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)
53 AS_02::MXF::AS02IndexWriterVBR::~AS02IndexWriterVBR() {}
57 AS_02::MXF::AS02IndexWriterVBR::WriteToFile(Kumu::FileWriter& Writer)
60 ASDCP::FrameBuffer index_body_buffer;
61 ui32_t index_body_size = (ui32_t)m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size
62 Result_t result = index_body_buffer.Capacity(index_body_size);
63 ui64_t start_position = 0;
65 if ( m_CurrentSegment != 0 )
67 m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
68 start_position = m_CurrentSegment->IndexStartPosition + m_CurrentSegment->IndexDuration;
72 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
73 for ( ; pl_i != m_PacketList->m_List.end() && KM_SUCCESS(result); pl_i++ )
75 InterchangeObject* object = *pl_i;
76 object->m_Lookup = m_Lookup;
78 ASDCP::FrameBuffer WriteWrapper;
79 WriteWrapper.SetData(index_body_buffer.Data() + index_body_buffer.Size(),
80 index_body_buffer.Capacity() - index_body_buffer.Size());
81 result = object->WriteToBuffer(WriteWrapper);
82 index_body_buffer.Size(index_body_buffer.Size() + WriteWrapper.Size());
87 m_PacketList->m_List.clear();
89 if ( KM_SUCCESS(result) )
91 IndexByteCount = index_body_buffer.Size();
92 UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
93 result = Partition::WriteToFile(Writer, body_ul);
96 if ( KM_SUCCESS(result) )
98 ui32_t write_count = 0;
99 result = Writer.Write(index_body_buffer.RoData(), index_body_buffer.Size(), &write_count);
100 assert(write_count == index_body_buffer.Size());
103 if ( KM_SUCCESS(result) )
105 m_CurrentSegment = new IndexTableSegment(m_Dict);
106 assert(m_CurrentSegment);
107 AddChildObject(m_CurrentSegment);
108 m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
109 m_CurrentSegment->IndexEditRate = m_EditRate;
110 m_CurrentSegment->IndexStartPosition = start_position;
118 AS_02::MXF::AS02IndexWriterVBR::Dump(FILE* stream)
123 Partition::Dump(stream);
125 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
126 for ( ; i != m_PacketList->m_List.end(); ++i )
134 AS_02::MXF::AS02IndexWriterVBR::GetDuration() const
137 std::list<InterchangeObject*>::const_iterator i;
139 for ( i = m_PacketList->m_List.begin(); i != m_PacketList->m_List.end(); ++i )
141 IndexTableSegment* segment = dynamic_cast<IndexTableSegment*>(*i);
144 duration += (ui32_t)segment->IndexEntryArray.size();
153 AS_02::MXF::AS02IndexWriterVBR::PushIndexEntry(const IndexTableSegment::IndexEntry& Entry)
155 // do we have an available segment?
156 if ( m_CurrentSegment == 0 )
157 { // no, set up a new segment
158 m_CurrentSegment = new IndexTableSegment(m_Dict);
159 assert(m_CurrentSegment);
160 AddChildObject(m_CurrentSegment);
161 m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
162 m_CurrentSegment->IndexEditRate = m_EditRate;
163 m_CurrentSegment->IndexStartPosition = 0;
166 m_CurrentSegment->IndexEntryArray.push_back(Entry);
170 AS_02::MXF::AS02IndexWriterVBR::SetEditRate(const ASDCP::Rational& edit_rate)
172 m_EditRate = edit_rate;
175 //------------------------------------------------------------------------------------------
179 AS_02::h__AS02WriterFrame::h__AS02WriterFrame(const ASDCP::Dictionary& d) :
180 h__AS02Writer<AS_02::MXF::AS02IndexWriterVBR>(d), m_IndexStrategy(AS_02::IS_FOLLOW) {}
182 AS_02::h__AS02WriterFrame::~h__AS02WriterFrame() {}
186 AS_02::h__AS02WriterFrame::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
187 const ui32_t& MinEssenceElementBerLength,
188 AESEncContext* Ctx, HMACContext* HMAC)
190 ui64_t this_stream_offset = m_StreamOffset; // m_StreamOffset will be changed by the call to Write_EKLV_Packet
192 Result_t result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
193 m_StreamOffset, FrameBuf, EssenceUL, MinEssenceElementBerLength, Ctx, HMAC);
195 if ( KM_SUCCESS(result) )
197 IndexTableSegment::IndexEntry Entry;
198 Entry.StreamOffset = this_stream_offset;
199 m_IndexWriter.PushIndexEntry(Entry);
202 if ( m_FramesWritten > 1 && ( ( m_FramesWritten + 1 ) % m_PartitionSpace ) == 0 )
204 assert(m_IndexWriter.GetDuration() > 0);
205 FlushIndexPartition();
207 UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
208 Partition body_part(m_Dict);
209 body_part.MajorVersion = m_HeaderPart.MajorVersion;
210 body_part.MinorVersion = m_HeaderPart.MinorVersion;
211 body_part.BodySID = 1;
212 body_part.OperationalPattern = m_HeaderPart.OperationalPattern;
213 body_part.EssenceContainers = m_HeaderPart.EssenceContainers;
214 body_part.ThisPartition = m_File.Tell();
216 body_part.BodyOffset = m_StreamOffset;
217 result = body_part.WriteToFile(m_File, body_ul);
218 m_RIP.PairArray.push_back(RIP::PartitionPair(1, body_part.ThisPartition));
225 //------------------------------------------------------------------------------------------
229 AS_02::MXF::AS02IndexWriterCBR::AS02IndexWriterCBR(const ASDCP::Dictionary*& d) :
230 Partition(d), m_CurrentSegment(0), m_Dict(d), m_Lookup(0), m_Duration(0), m_SampleSize(0)
237 AS_02::MXF::AS02IndexWriterCBR::~AS02IndexWriterCBR() {}
241 AS_02::MXF::AS02IndexWriterCBR::WriteToFile(Kumu::FileWriter& Writer)
244 ASDCP::FrameBuffer index_body_buffer;
245 ui32_t index_body_size = MaxIndexSegmentSize; // segment-count * max-segment-size
246 Result_t result = index_body_buffer.Capacity(index_body_size);
248 m_CurrentSegment = new IndexTableSegment(m_Dict);
249 assert(m_CurrentSegment);
250 m_CurrentSegment->m_Lookup = m_Lookup;
251 m_CurrentSegment->IndexEditRate = m_EditRate;
252 m_CurrentSegment->IndexStartPosition = 0;
253 m_CurrentSegment->IndexDuration = m_Duration;
254 m_CurrentSegment->EditUnitByteCount = m_SampleSize;
255 AddChildObject(m_CurrentSegment);
257 ASDCP::FrameBuffer WriteWrapper;
258 WriteWrapper.SetData(index_body_buffer.Data() + index_body_buffer.Size(),
259 index_body_buffer.Capacity() - index_body_buffer.Size());
261 result = m_CurrentSegment->WriteToBuffer(WriteWrapper);
262 index_body_buffer.Size(index_body_buffer.Size() + WriteWrapper.Size());
263 delete m_CurrentSegment;
264 m_CurrentSegment = 0;
265 m_PacketList->m_List.clear();
267 if ( KM_SUCCESS(result) )
269 IndexByteCount = index_body_buffer.Size();
270 UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
271 result = Partition::WriteToFile(Writer, body_ul);
274 if ( KM_SUCCESS(result) )
276 ui32_t write_count = 0;
277 result = Writer.Write(index_body_buffer.RoData(), index_body_buffer.Size(), &write_count);
278 assert(write_count == index_body_buffer.Size());
286 AS_02::MXF::AS02IndexWriterCBR::GetDuration() const
293 AS_02::MXF::AS02IndexWriterCBR::SetEditRate(const ASDCP::Rational& edit_rate, const ui32_t& sample_size)
295 m_EditRate = edit_rate;
296 m_SampleSize = sample_size;
300 //------------------------------------------------------------------------------------------
304 AS_02::h__AS02WriterClip::h__AS02WriterClip(const ASDCP::Dictionary& d) :
305 h__AS02Writer<AS_02::MXF::AS02IndexWriterCBR>(d),
306 m_ECStart(0), m_ClipStart(0), m_IndexStrategy(AS_02::IS_FOLLOW) {}
308 AS_02::h__AS02WriterClip::~h__AS02WriterClip() {}
312 AS_02::h__AS02WriterClip::HasOpenClip() const
314 return m_ClipStart != 0;
319 AS_02::h__AS02WriterClip::StartClip(const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC)
323 DefaultLogSink().Error("Encryption not yet supported for PCM clip-wrap.\n");
327 if ( m_ClipStart != 0 )
329 DefaultLogSink().Error("Cannot open clip, clip already open.\n");
333 m_ClipStart = m_File.Tell();
334 byte_t clip_buffer[24] = {0};
335 memcpy(clip_buffer, EssenceUL, 16);
336 bool check = Kumu::write_BER(clip_buffer+16, 0, 8);
338 return m_File.Write(clip_buffer, 24);
343 AS_02::h__AS02WriterClip::WriteClipBlock(const ASDCP::FrameBuffer& FrameBuf)
345 if ( m_ClipStart == 0 )
347 DefaultLogSink().Error("Cannot write clip block, no clip open.\n");
351 return m_File.Write(FrameBuf.RoData(), FrameBuf.Size());
356 AS_02::h__AS02WriterClip::FinalizeClip(ui32_t bytes_per_frame)
358 if ( m_ClipStart == 0 )
360 DefaultLogSink().Error("Cannot close clip, clip not open.\n");
364 ui64_t current_position = m_File.Tell();
365 Result_t result = m_File.Seek(m_ClipStart+16);
367 if ( KM_SUCCESS(result) )
369 byte_t clip_buffer[8] = {0};
370 ui64_t size = static_cast<ui64_t>(m_FramesWritten) * bytes_per_frame;
371 bool check = Kumu::write_BER(clip_buffer, size, 8);
373 result = m_File.Write(clip_buffer, 8);
376 if ( KM_SUCCESS(result) )
378 result = m_File.Seek(current_position);
386 // end h__02_Writer.cpp