working j2c as-02
[asdcplib.git] / src / h__02_Reader.cpp
1 /*
2   Copyright (c) 2011-2013, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst
3   All rights reserved.
4
5   Redistribution and use in source and binary forms, with or without
6   modification, are permitted provided that the following conditions
7   are met:
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.
15
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.
26 */ 
27 /*! \file    h__02_Reader.cpp
28   \version $Id$
29   \brief   MXF file reader base class
30 */
31
32 #define DEFAULT_MD_DECL
33 #include "AS_02_internal.h"
34
35 using namespace ASDCP;
36 using namespace ASDCP::MXF;
37
38
39 static Kumu::Mutex sg_DefaultMDInitLock;
40 static bool        sg_DefaultMDTypesInit = false;
41 static const ASDCP::Dictionary *sg_dict;
42
43 //
44 void
45 AS_02::default_md_object_init()
46 {
47   if ( ! sg_DefaultMDTypesInit )
48     {
49       Kumu::AutoMutex BlockLock(sg_DefaultMDInitLock);
50
51       if ( ! sg_DefaultMDTypesInit )
52         {
53           sg_dict = &DefaultSMPTEDict();
54           g_AS02IndexReader = new AS_02::MXF::AS02IndexReader(sg_dict);
55           sg_DefaultMDTypesInit = true;
56         }
57     }
58 }
59
60
61 //---------------------------------------------------------------------------------
62 //
63
64     
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() {}
67
68 //    
69 Result_t
70 AS_02::MXF::AS02IndexReader::InitFromFile(const Kumu::FileReader& reader, const ASDCP::MXF::RIP& rip)
71 {
72   ASDCP::MXF::Array<ASDCP::MXF::RIP::Pair>::const_iterator i;
73
74   Result_t result = m_IndexSegmentData.Capacity(128*Kumu::Kilobyte);
75
76   for ( i = rip.PairArray.begin(); KM_SUCCESS(result) && i != rip.PairArray.end(); ++i )
77     {
78       reader.Seek(i->ByteOffset);
79       ASDCP::MXF::Partition plain_part(m_Dict);
80       result = plain_part.InitFromFile(reader);
81
82       if ( KM_SUCCESS(result) && plain_part.IndexByteCount > 0 )
83         {
84           // slurp up the remainder of the footer
85           ui32_t read_count = 0;
86
87           assert (plain_part.IndexByteCount <= 0xFFFFFFFFL);
88           ui32_t bytes_this_partition = (ui32_t)plain_part.IndexByteCount;
89
90           result = m_IndexSegmentData.Capacity(m_IndexSegmentData.Length() + bytes_this_partition);
91
92           if ( ASDCP_SUCCESS(result) )
93             result = reader.Read(m_IndexSegmentData.Data() + m_IndexSegmentData.Length(),
94                                  bytes_this_partition, &read_count);
95
96           if ( ASDCP_SUCCESS(result) && read_count != bytes_this_partition )
97             {
98               DefaultLogSink().Error("Short read of footer partition: got %u, expecting %u\n",
99                                      read_count, bytes_this_partition);
100               return RESULT_FAIL;
101             }
102
103           if ( ASDCP_SUCCESS(result) )
104             {
105               result = InitFromBuffer(m_IndexSegmentData.RoData() + m_IndexSegmentData.Length(), bytes_this_partition);
106               m_IndexSegmentData.Length(m_IndexSegmentData.Length() + bytes_this_partition);
107             }
108         }
109     }
110
111   return result;
112 }
113
114 //
115 ASDCP::Result_t
116 AS_02::MXF::AS02IndexReader::InitFromBuffer(const byte_t* p, ui32_t l)
117 {
118   Result_t result = RESULT_OK;
119   const byte_t* end_p = p + l;
120
121   while ( ASDCP_SUCCESS(result) && p < end_p )
122     {
123       // parse the packets and index them by uid, discard KLVFill items
124       InterchangeObject* object = CreateObject(m_Dict, p);
125       assert(object);
126
127       object->m_Lookup = m_Lookup;
128       result = object->InitFromBuffer(p, end_p - p);
129       p += object->PacketLength();
130
131       if ( ASDCP_SUCCESS(result) )
132         {
133           m_PacketList->AddPacket(object); // takes ownership
134         }
135       else
136         {
137           DefaultLogSink().Error("Error initializing packet\n");
138           delete object;
139         }
140     }
141
142   if ( ASDCP_FAILURE(result) )
143     DefaultLogSink().Error("Failed to initialize AS02IndexReader\n");
144
145   std::list<InterchangeObject*>::const_iterator i;
146   
147   for ( i = m_PacketList->m_List.begin(); i != m_PacketList->m_List.end(); ++i )
148     {
149       if ( (*i)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
150         {
151           m_Duration += static_cast<IndexTableSegment*>(*i)->IndexDuration;
152         }
153     }
154
155   return result;
156 }
157
158 //
159 void
160 AS_02::MXF::AS02IndexReader::Dump(FILE* stream)
161 {
162   if ( stream == 0 )
163     stream = stderr;
164
165   std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
166   for ( ; i != m_PacketList->m_List.end(); ++i )
167     (*i)->Dump(stream);
168 }
169
170 //
171 Result_t
172 AS_02::MXF::AS02IndexReader::GetMDObjectByID(const UUID& object_id, InterchangeObject** Object)
173 {
174   return m_PacketList->GetMDObjectByID(object_id, Object);
175 }
176
177 //
178 Result_t
179 AS_02::MXF::AS02IndexReader::GetMDObjectByType(const byte_t* type_id, InterchangeObject** Object)
180 {
181   InterchangeObject* TmpObject;
182
183   if ( Object == 0 )
184     Object = &TmpObject;
185
186   return m_PacketList->GetMDObjectByType(type_id, Object);
187 }
188
189 //
190 Result_t
191 AS_02::MXF::AS02IndexReader::GetMDObjectsByType(const byte_t* ObjectID, std::list<ASDCP::MXF::InterchangeObject*>& ObjectList)
192 {
193   return m_PacketList->GetMDObjectsByType(ObjectID, ObjectList);
194 }
195
196
197 //
198 ui32_t
199 AS_02::MXF::AS02IndexReader::GetDuration() const
200 {
201   return m_Duration;
202 }
203    
204
205 //
206 Result_t
207 AS_02::MXF::AS02IndexReader::Lookup(ui32_t frame_num, ASDCP::MXF::IndexTableSegment::IndexEntry& Entry) const
208 {
209   std::list<InterchangeObject*>::iterator li;
210   for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ )
211     {
212       if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
213         {
214           IndexTableSegment* Segment = (IndexTableSegment*)(*li);
215           ui64_t start_pos = Segment->IndexStartPosition;
216
217           if ( Segment->EditUnitByteCount > 0 )
218             {
219               if ( m_PacketList->m_List.size() > 1 )
220                 DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n");
221
222               if ( ! Segment->IndexEntryArray.empty() )
223                 DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n");
224
225               Entry.StreamOffset = (ui64_t)frame_num * Segment->EditUnitByteCount;
226               return RESULT_OK;
227             }
228           else if ( (ui64_t)frame_num >= start_pos
229                     && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) )
230             {
231               ui64_t tmp = frame_num - start_pos;
232               assert(tmp <= 0xFFFFFFFFL);
233               Entry = Segment->IndexEntryArray[(ui32_t) tmp];
234               return RESULT_OK;
235             }
236         }
237     }
238
239   return RESULT_FAIL;
240 }
241
242
243 //---------------------------------------------------------------------------------
244 //
245
246
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() {}
249
250
251 // AS-DCP method of opening an MXF file for read
252 Result_t
253 AS_02::h__AS02Reader::OpenMXFRead(const char* filename)
254 {
255   Result_t result = ASDCP::MXF::TrackFileReader<OP1aHeader, AS_02::MXF::AS02IndexReader>::OpenMXFRead(filename);
256
257   if ( KM_SUCCESS(result) )
258     result = ASDCP::MXF::TrackFileReader<OP1aHeader, AS_02::MXF::AS02IndexReader>::InitInfo();
259
260   if( KM_SUCCESS(result) )
261     {
262       //
263       UL OP1a_ul(m_Dict->ul(MDD_OP1a));
264       InterchangeObject* Object;
265       m_Info.LabelSetType = LS_MXF_SMPTE;
266
267       if ( m_HeaderPart.OperationalPattern != OP1a_ul )
268         {
269           char strbuf[IdentBufferLen];
270           const MDDEntry* Entry = m_Dict->FindUL(m_HeaderPart.OperationalPattern.Value());
271
272           if ( Entry == 0 )
273             {
274               DefaultLogSink().Warn("Operational pattern is not OP-1a: %s\n",
275                                     m_HeaderPart.OperationalPattern.EncodeString(strbuf, IdentBufferLen));
276             }
277           else
278             {
279               DefaultLogSink().Warn("Operational pattern is not OP-1a: %s\n", Entry->name);
280             }
281         }
282
283       //
284       if ( m_RIP.PairArray.front().ByteOffset != 0 )
285         {
286           DefaultLogSink().Error("First Partition in RIP is not at offset 0.\n");
287           result = RESULT_FORMAT;
288         }
289     }
290
291   if ( KM_SUCCESS(result) )
292     {
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);
296     }
297
298   m_File.Seek(m_HeaderPart.BodyOffset);
299   return result;
300 }
301
302 // AS-DCP method of reading a plaintext or encrypted frame
303 Result_t
304 AS_02::h__AS02Reader::ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
305                                      const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
306 {
307   return ASDCP::MXF::TrackFileReader<OP1aHeader, AS_02::MXF::AS02IndexReader>::ReadEKLVFrame(m_HeaderPart, FrameNum, FrameBuf,
308                                                                                      EssenceUL, Ctx, HMAC);
309 }
310
311 Result_t
312 AS_02::h__AS02Reader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset,
313                            i8_t& temporalOffset, i8_t& keyFrameOffset)
314 {
315   return ASDCP::MXF::TrackFileReader<OP1aHeader, AS_02::MXF::AS02IndexReader>::LocateFrame(m_HeaderPart, FrameNum,
316                                                                                    streamOffset, temporalOffset, keyFrameOffset);
317 }
318
319
320 //
321 // end h__02_Reader.cpp
322 //