2 Copyright (c) 2011-2013, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 /*! \file h__02_Reader.cpp
29 \brief MXF file reader base class
32 #define DEFAULT_MD_DECL
33 #include "AS_02_internal.h"
35 using namespace ASDCP;
36 using namespace ASDCP::MXF;
39 static Kumu::Mutex sg_DefaultMDInitLock;
40 static bool sg_DefaultMDTypesInit = false;
41 static const ASDCP::Dictionary *sg_dict;
45 AS_02::default_md_object_init()
47 if ( ! sg_DefaultMDTypesInit )
49 Kumu::AutoMutex BlockLock(sg_DefaultMDInitLock);
51 if ( ! sg_DefaultMDTypesInit )
53 sg_dict = &DefaultSMPTEDict();
54 g_AS02IndexReader = new AS_02::MXF::AS02IndexReader(sg_dict);
55 sg_DefaultMDTypesInit = true;
61 //---------------------------------------------------------------------------------
65 AS_02::MXF::AS02IndexReader::AS02IndexReader(const ASDCP::Dictionary*& d) : m_Duration(0), ASDCP::MXF::Partition(m_Dict), m_Dict(d) {}
66 AS_02::MXF::AS02IndexReader::~AS02IndexReader() {}
70 AS_02::MXF::AS02IndexReader::InitFromFile(const Kumu::FileReader& reader, const ASDCP::MXF::RIP& rip)
72 ASDCP::MXF::Array<ASDCP::MXF::RIP::Pair>::const_iterator i;
74 Result_t result = m_IndexSegmentData.Capacity(128*Kumu::Kilobyte);
76 for ( i = rip.PairArray.begin(); KM_SUCCESS(result) && i != rip.PairArray.end(); ++i )
78 reader.Seek(i->ByteOffset);
79 ASDCP::MXF::Partition plain_part(m_Dict);
80 result = plain_part.InitFromFile(reader);
82 if ( KM_SUCCESS(result) && plain_part.IndexByteCount > 0 )
84 // slurp up the remainder of the footer
85 ui32_t read_count = 0;
87 assert (plain_part.IndexByteCount <= 0xFFFFFFFFL);
88 ui32_t bytes_this_partition = (ui32_t)plain_part.IndexByteCount;
90 result = m_IndexSegmentData.Capacity(m_IndexSegmentData.Length() + bytes_this_partition);
92 if ( ASDCP_SUCCESS(result) )
93 result = reader.Read(m_IndexSegmentData.Data() + m_IndexSegmentData.Length(),
94 bytes_this_partition, &read_count);
96 if ( ASDCP_SUCCESS(result) && read_count != bytes_this_partition )
98 DefaultLogSink().Error("Short read of footer partition: got %u, expecting %u\n",
99 read_count, bytes_this_partition);
103 if ( ASDCP_SUCCESS(result) )
105 result = InitFromBuffer(m_IndexSegmentData.RoData() + m_IndexSegmentData.Length(), bytes_this_partition);
106 m_IndexSegmentData.Length(m_IndexSegmentData.Length() + bytes_this_partition);
116 AS_02::MXF::AS02IndexReader::InitFromBuffer(const byte_t* p, ui32_t l)
118 Result_t result = RESULT_OK;
119 const byte_t* end_p = p + l;
121 while ( ASDCP_SUCCESS(result) && p < end_p )
123 // parse the packets and index them by uid, discard KLVFill items
124 InterchangeObject* object = CreateObject(m_Dict, p);
127 object->m_Lookup = m_Lookup;
128 result = object->InitFromBuffer(p, end_p - p);
129 p += object->PacketLength();
131 if ( ASDCP_SUCCESS(result) )
133 m_PacketList->AddPacket(object); // takes ownership
137 DefaultLogSink().Error("Error initializing packet\n");
142 if ( ASDCP_FAILURE(result) )
143 DefaultLogSink().Error("Failed to initialize AS02IndexReader\n");
145 std::list<InterchangeObject*>::const_iterator i;
147 for ( i = m_PacketList->m_List.begin(); i != m_PacketList->m_List.end(); ++i )
149 if ( (*i)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
151 m_Duration += static_cast<IndexTableSegment*>(*i)->IndexDuration;
160 AS_02::MXF::AS02IndexReader::Dump(FILE* stream)
165 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
166 for ( ; i != m_PacketList->m_List.end(); ++i )
172 AS_02::MXF::AS02IndexReader::GetMDObjectByID(const UUID& object_id, InterchangeObject** Object)
174 return m_PacketList->GetMDObjectByID(object_id, Object);
179 AS_02::MXF::AS02IndexReader::GetMDObjectByType(const byte_t* type_id, InterchangeObject** Object)
181 InterchangeObject* TmpObject;
186 return m_PacketList->GetMDObjectByType(type_id, Object);
191 AS_02::MXF::AS02IndexReader::GetMDObjectsByType(const byte_t* ObjectID, std::list<ASDCP::MXF::InterchangeObject*>& ObjectList)
193 return m_PacketList->GetMDObjectsByType(ObjectID, ObjectList);
199 AS_02::MXF::AS02IndexReader::GetDuration() const
207 AS_02::MXF::AS02IndexReader::Lookup(ui32_t frame_num, ASDCP::MXF::IndexTableSegment::IndexEntry& Entry) const
209 std::list<InterchangeObject*>::iterator li;
210 for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ )
212 if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
214 IndexTableSegment* Segment = (IndexTableSegment*)(*li);
215 ui64_t start_pos = Segment->IndexStartPosition;
217 if ( Segment->EditUnitByteCount > 0 )
219 if ( m_PacketList->m_List.size() > 1 )
220 DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n");
222 if ( ! Segment->IndexEntryArray.empty() )
223 DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n");
225 Entry.StreamOffset = (ui64_t)frame_num * Segment->EditUnitByteCount;
228 else if ( (ui64_t)frame_num >= start_pos
229 && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) )
231 ui64_t tmp = frame_num - start_pos;
232 assert(tmp <= 0xFFFFFFFFL);
233 Entry = Segment->IndexEntryArray[(ui32_t) tmp];
243 //---------------------------------------------------------------------------------
247 AS_02::h__AS02Reader::h__AS02Reader(const ASDCP::Dictionary& d) : ASDCP::MXF::TrackFileReader<ASDCP::MXF::OP1aHeader, AS_02::MXF::AS02IndexReader>(d) {}
248 AS_02::h__AS02Reader::~h__AS02Reader() {}
251 // AS-DCP method of opening an MXF file for read
253 AS_02::h__AS02Reader::OpenMXFRead(const char* filename)
255 Result_t result = ASDCP::MXF::TrackFileReader<OP1aHeader, AS_02::MXF::AS02IndexReader>::OpenMXFRead(filename);
257 if ( KM_SUCCESS(result) )
258 result = ASDCP::MXF::TrackFileReader<OP1aHeader, AS_02::MXF::AS02IndexReader>::InitInfo();
260 if( KM_SUCCESS(result) )
263 UL OP1a_ul(m_Dict->ul(MDD_OP1a));
264 InterchangeObject* Object;
265 m_Info.LabelSetType = LS_MXF_SMPTE;
267 if ( m_HeaderPart.OperationalPattern != OP1a_ul )
269 char strbuf[IdentBufferLen];
270 const MDDEntry* Entry = m_Dict->FindUL(m_HeaderPart.OperationalPattern.Value());
274 DefaultLogSink().Warn("Operational pattern is not OP-1a: %s\n",
275 m_HeaderPart.OperationalPattern.EncodeString(strbuf, IdentBufferLen));
279 DefaultLogSink().Warn("Operational pattern is not OP-1a: %s\n", Entry->name);
284 if ( m_RIP.PairArray.front().ByteOffset != 0 )
286 DefaultLogSink().Error("First Partition in RIP is not at offset 0.\n");
287 result = RESULT_FORMAT;
291 if ( KM_SUCCESS(result) )
293 m_HeaderPart.BodyOffset = m_File.Tell();
294 m_IndexAccess.m_Lookup = &m_HeaderPart.m_Primer;
295 result = m_IndexAccess.InitFromFile(m_File, m_RIP);
298 m_File.Seek(m_HeaderPart.BodyOffset);
302 // AS-DCP method of reading a plaintext or encrypted frame
304 AS_02::h__AS02Reader::ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
305 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
307 return ASDCP::MXF::TrackFileReader<OP1aHeader, AS_02::MXF::AS02IndexReader>::ReadEKLVFrame(m_HeaderPart, FrameNum, FrameBuf,
308 EssenceUL, Ctx, HMAC);
312 AS_02::h__AS02Reader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset,
313 i8_t& temporalOffset, i8_t& keyFrameOffset)
315 return ASDCP::MXF::TrackFileReader<OP1aHeader, AS_02::MXF::AS02IndexReader>::LocateFrame(m_HeaderPart, FrameNum,
316 streamOffset, temporalOffset, keyFrameOffset);
321 // end h__02_Reader.cpp