Implemented J2K desc to/from MD
[asdcplib.git] / src / MPEG2_Parser.cpp
1 /*
2 Copyright (c) 2004-2011, 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    MPEG2_Parser.cpp
28     \version $Id$
29     \brief   AS-DCP library, MPEG2 raw essence reader implementation
30 */
31
32 #include <KM_fileio.h>
33 #include <MPEG.h>
34
35 #include <KM_log.h>
36 using Kumu::DefaultLogSink;
37
38 using namespace ASDCP;
39 using namespace ASDCP::MPEG2;
40
41 // data will be read from a VES file in chunks of this size
42 const ui32_t VESReadSize = 4 * Kumu::Kilobyte;
43
44
45 //------------------------------------------------------------------------------------------
46
47 //
48 enum ParserState_t {
49     ST_INIT,
50     ST_SEQ,
51     ST_PIC,
52     ST_GOP,
53     ST_EXT,
54     ST_SLICE,
55 };
56
57 const char*
58 StringParserState(ParserState_t state)
59 {
60   switch ( state )
61     {
62     case ST_INIT:  return "INIT";
63     case ST_SEQ:   return "SEQ";
64     case ST_PIC:   return "PIC";
65     case ST_GOP:   return "GOP";
66     case ST_EXT:   return "EXT";
67     case ST_SLICE: return "SLICE";
68     }
69
70   return "*UNKNOWN*";
71 }
72
73
74
75 //
76 class h__ParserState
77 {
78   ParserState_t m_State;
79   ASDCP_NO_COPY_CONSTRUCT(h__ParserState);
80
81  public:
82   h__ParserState() : m_State(ST_INIT) {}
83   ~h__ParserState() {}
84
85   inline bool Test_SLICE() { return m_State == ST_SLICE; }
86   inline void Reset() { m_State = ST_INIT; }
87
88   //
89   inline Result_t Goto_SEQ()
90     {
91       switch ( m_State )
92         {
93         case ST_INIT:
94         case ST_EXT:
95           m_State = ST_SEQ;
96           return RESULT_OK;
97         }
98       
99       DefaultLogSink().Error("SEQ follows %s\n", StringParserState(m_State));
100       return RESULT_STATE;
101     }
102
103
104   //
105   inline Result_t Goto_SLICE()
106     {
107       switch ( m_State )
108         {
109         case ST_PIC:
110         case ST_EXT:
111           m_State = ST_SLICE;
112           return RESULT_OK;
113         }
114       
115       DefaultLogSink().Error("Slice follows %s\n", StringParserState(m_State));
116       return RESULT_STATE;
117     }
118
119
120   //
121   inline Result_t Goto_PIC()
122     {
123       switch ( m_State )
124         {
125         case ST_INIT:
126         case ST_SEQ:
127         case ST_GOP:
128         case ST_EXT:
129           m_State = ST_PIC;
130           return RESULT_OK;
131         }
132       
133       DefaultLogSink().Error("PIC follows %s\n", StringParserState(m_State));
134       return RESULT_STATE;
135     }
136
137
138   //
139   inline Result_t Goto_GOP()
140   {
141     switch ( m_State )
142       {
143       case ST_EXT:
144       case ST_SEQ:
145         m_State = ST_GOP;
146         return RESULT_OK;
147       }
148     
149     DefaultLogSink().Error("GOP follows %s\n", StringParserState(m_State));
150     return RESULT_STATE;
151   }
152
153   //
154   inline Result_t Goto_EXT()
155   {
156     switch ( m_State )
157       {
158         case ST_PIC:
159         case ST_EXT:
160         case ST_SEQ:
161         case ST_GOP:
162           m_State = ST_EXT;
163           return RESULT_OK;
164       }
165
166     DefaultLogSink().Error("EXT follows %s\n", StringParserState(m_State));
167     return RESULT_STATE;
168   }
169 };
170
171 //------------------------------------------------------------------------------------------
172
173 // This is a parser delagate that reads the stream params from a
174 // sequence header and sequence extension header. The parser is
175 // commanded to return after processing the sequence extension
176 // header.
177 class StreamParams : public VESParserDelegate
178 {
179   h__ParserState m_State;
180
181   ASDCP_NO_COPY_CONSTRUCT(StreamParams);
182
183 public:
184   VideoDescriptor  m_VDesc;
185
186   StreamParams()
187   {
188     m_VDesc.ContainerDuration = 0;
189     m_VDesc.ComponentDepth = 8;
190   }
191
192   ~StreamParams() {}
193
194   //
195   Result_t Sequence(VESParser*, const byte_t* b, ui32_t s)
196   {
197     Result_t result = m_State.Goto_SEQ();
198
199     if ( ASDCP_FAILURE(result) )
200       return result;
201
202     Accessor::Sequence SEQ(b);
203     m_VDesc.AspectRatio = SEQ.AspectRatio();
204     m_VDesc.FrameRate = SEQ.FrameRate();
205     m_VDesc.StoredWidth = SEQ.HorizontalSize();
206     m_VDesc.StoredHeight = SEQ.VerticalSize();
207     m_VDesc.BitRate = SEQ.BitRate();
208     m_VDesc.EditRate = SEQ.Pulldown() ? Rational(SEQ.FrameRate() * 1000, 1001) : Rational(SEQ.FrameRate(), 1);
209     m_VDesc.SampleRate = m_VDesc.EditRate;
210     return RESULT_OK;
211   }
212
213   //
214   Result_t Extension(VESParser*, const byte_t* b, ui32_t s)
215   {
216     Result_t result = m_State.Goto_EXT();
217
218     if ( ASDCP_FAILURE(result) )
219       return result;
220
221     Accessor::SequenceEx SEQX(b);
222     m_VDesc.ProfileAndLevel = SEQX.ProfileAndLevel();
223     m_VDesc.FrameLayout = SEQX.Progressive() ? 0 : 1;
224     m_VDesc.CodedContentType = SEQX.Progressive() ? 1 : 2;
225     m_VDesc.LowDelay = SEQX.LowDelay();
226     m_VDesc.HorizontalSubsampling = SEQX.ChromaFormat() == 3 ? 1 : 2;
227     m_VDesc.VerticalSubsampling = SEQX.ChromaFormat() >= 3 ? 1 : 2;
228
229     if ( ( m_VDesc.HorizontalSubsampling == 2 ) && ( m_VDesc.VerticalSubsampling == 2 ) )
230       m_VDesc.ColorSiting = 3;  // 4:2:0
231
232     else if ( ( m_VDesc.HorizontalSubsampling == 2 ) && ( m_VDesc.VerticalSubsampling == 1 ) )
233       m_VDesc.ColorSiting = 4;  // 4:2:2
234
235     else if ( ( m_VDesc.HorizontalSubsampling == 1 ) && ( m_VDesc.VerticalSubsampling == 1 ) )
236       m_VDesc.ColorSiting = 0;  // 4:4:4
237
238     // TODO: get H&V size and bit rate extensions
239
240     return RESULT_FALSE;
241   }
242
243   Result_t GOP(VESParser*, const byte_t*, ui32_t)     { return RESULT_FALSE; }
244   Result_t Picture(VESParser*, const byte_t*, ui32_t) { return RESULT_FALSE; }
245   Result_t Slice(VESParser*, byte_t)                  { return RESULT_FALSE; }
246   Result_t Data(VESParser*, const byte_t*, i32_t)     { return RESULT_OK; }
247 };
248
249
250 //------------------------------------------------------------------------------------------
251
252 // This is a parser delagate that reads a VES stream and sets public
253 // instance variables to indicate state. It is used below to read an
254 // entire frame into a buffer. The delegate retains metadata about the
255 // frame for later access.
256 //
257 class FrameParser : public VESParserDelegate
258 {
259   h__ParserState             m_State;
260   ASDCP_NO_COPY_CONSTRUCT(FrameParser);
261
262 public:
263   ui32_t       m_FrameSize;
264   bool         m_CompletePicture;
265   bool         m_HasGOP;
266   bool         m_ClosedGOP;
267   ui8_t        m_TemporalRef;
268   ui32_t       m_PlaintextOffset;
269   FrameType_t  m_FrameType;
270
271   FrameParser()
272   {
273     Reset();
274   }
275
276   ~FrameParser() {}
277   
278   void Reset()
279   {
280     m_FrameSize = 0;
281     m_HasGOP = m_ClosedGOP = false;
282     m_CompletePicture = false;
283     m_TemporalRef = 0;
284     m_PlaintextOffset = 0;
285     m_FrameType = FRAME_U;
286     m_State.Reset();
287  }
288
289   Result_t Sequence(VESParser*, const byte_t* b, ui32_t s)
290   {
291     if ( m_State.Test_SLICE() )
292       {
293         m_CompletePicture = true;
294         return RESULT_FALSE;
295       }
296
297     m_FrameSize += s;
298     return m_State.Goto_SEQ();
299   }
300
301   Result_t Picture(VESParser*, const byte_t* b, ui32_t s)
302   {
303     if ( m_State.Test_SLICE() )
304       {
305         m_CompletePicture = true;
306         return RESULT_FALSE;
307       }
308
309     Accessor::Picture pic(b);
310     m_TemporalRef = pic.TemporalRef();
311     m_FrameType = pic.FrameType();
312     m_FrameSize += s;
313     return m_State.Goto_PIC();
314   }
315
316   Result_t Slice(VESParser*, byte_t slice_id)
317   {
318     if ( slice_id == FIRST_SLICE )
319       {
320         m_PlaintextOffset = m_FrameSize;
321         return m_State.Goto_SLICE();
322       }
323
324     return m_State.Test_SLICE() ? RESULT_OK : RESULT_FAIL;
325   }
326
327   Result_t Extension(VESParser*, const byte_t* b, ui32_t s)
328   {
329     m_FrameSize += s;
330     return m_State.Goto_EXT();
331   }
332
333   Result_t GOP(VESParser*, const byte_t* b, ui32_t s)
334   {
335     Accessor::GOP GOP(b);
336     m_ClosedGOP = GOP.Closed();
337     m_HasGOP = true;
338     m_FrameSize += s;
339     return m_State.Goto_GOP();
340   }
341
342   Result_t Data(VESParser*, const byte_t* b, i32_t s)
343   {
344     m_FrameSize += s;
345     return RESULT_OK;
346   }
347 };
348
349 //------------------------------------------------------------------------------------------
350
351 // The following code assumes the following things:
352 // - each frame will begin with a picture header or a sequence header
353 // - any frame that begins with a sequence header is an I frame and is
354 //   assumed to contain a GOP header, a picture header and complete picture data
355 // - any frame that begins with a picture header is either an I, B or P frame
356 //   and is assumed to contain a complete picture header and picture data
357
358 class ASDCP::MPEG2::Parser::h__Parser
359 {
360   StreamParams     m_ParamsDelegate;
361   FrameParser      m_ParserDelegate;
362   VESParser        m_Parser;
363   Kumu::FileReader m_FileReader;
364   ui32_t           m_FrameNumber;
365   bool             m_EOF;
366   ASDCP::MPEG2::FrameBuffer  m_TmpBuffer;
367
368   ASDCP_NO_COPY_CONSTRUCT(h__Parser);
369
370 public:
371   h__Parser() : m_TmpBuffer(VESReadSize*8) {}
372   ~h__Parser() { Close(); }
373
374   Result_t OpenRead(const std::string& filename);
375   void     Close();
376   Result_t Reset();
377   Result_t ReadFrame(FrameBuffer&);
378   Result_t FillVideoDescriptor(VideoDescriptor&);
379 };
380
381
382 //
383 Result_t
384 ASDCP::MPEG2::Parser::h__Parser::Reset()
385 {
386   m_FrameNumber = 0;
387   m_EOF = false;
388   m_FileReader.Seek(0);
389   m_ParserDelegate.Reset();
390   return RESULT_OK;
391 }
392
393 //
394 void
395 ASDCP::MPEG2::Parser::h__Parser::Close()
396 {
397   m_FileReader.Close();
398 }
399
400 //
401 ASDCP::Result_t
402 ASDCP::MPEG2::Parser::h__Parser::OpenRead(const std::string& filename)
403 {
404   ui32_t read_count = 0;
405
406   Result_t result = m_FileReader.OpenRead(filename);
407   
408   if ( ASDCP_SUCCESS(result) )
409     result = m_FileReader.Read(m_TmpBuffer.Data(), m_TmpBuffer.Capacity(), &read_count);
410   
411   if ( ASDCP_SUCCESS(result) )
412     {
413       const byte_t* p = m_TmpBuffer.RoData();
414
415       // the mxflib parser demanded the file start with a sequence header.
416       // Since no one complained and that's the easiest thing to implement,
417       // I have left it that way. Let me know if you want to be able to
418       // locate the first GOP in the stream.
419       ui32_t i = 0;
420       while ( p[i] == 0 ) i++;
421
422       if ( i < 2 || p[i] != 1 || ! ( p[i+1] == SEQ_START || p[i+1] == PIC_START ) )
423         {
424           DefaultLogSink().Error("Frame buffer does not begin with a PIC or SEQ start code.\n");
425           return RESULT_RAW_FORMAT;
426         }
427
428       if ( ASDCP_SUCCESS(result) )
429         {
430           m_Parser.SetDelegate(&m_ParamsDelegate);
431           result = m_Parser.Parse(p, read_count);
432         }
433     }
434
435   if ( ASDCP_SUCCESS(result) )
436     {
437       ui64_t tmp = m_FileReader.Size() / 65536; // a gross approximation
438       m_ParamsDelegate.m_VDesc.ContainerDuration = (ui32_t) tmp;
439       m_Parser.SetDelegate(&m_ParserDelegate);
440       m_FileReader.Seek(0);
441     }
442
443   if ( ASDCP_FAILURE(result) )
444     {
445       DefaultLogSink().Error("Unable to identify a wrapping mode for the essence in file \"%s\"\n", filename.c_str());
446       m_FileReader.Close();
447     }
448
449   return result;}
450
451
452 //
453 //
454 ASDCP::Result_t
455 ASDCP::MPEG2::Parser::h__Parser::ReadFrame(FrameBuffer& FB)
456 {
457   Result_t result = RESULT_OK;
458   ui32_t write_offset = 0;
459   ui32_t read_count = 0;
460
461   FB.Size(0);
462
463   if ( m_EOF )
464     return RESULT_ENDOFFILE;
465
466   // Data is read in VESReadSize chunks. Each chunk is parsed, and the
467   // process is stopped when a Sequence or Picture header is found or when
468   // the input file is exhausted. The partial next frame is cached for the
469   // next call.
470   m_ParserDelegate.Reset();
471   m_Parser.Reset();
472
473   if ( m_TmpBuffer.Size() > 0 )
474     {
475       memcpy(FB.Data(), m_TmpBuffer.RoData(), m_TmpBuffer.Size());
476       result = m_Parser.Parse(FB.RoData(), m_TmpBuffer.Size());
477       write_offset = m_TmpBuffer.Size();
478       m_TmpBuffer.Size(0);
479     }
480
481   while ( ! m_ParserDelegate.m_CompletePicture && result == RESULT_OK )
482     {
483       if ( FB.Capacity() < ( write_offset + VESReadSize ) )
484         {
485           DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %u\n",
486                                  FB.Capacity(), ( write_offset + VESReadSize ));
487           return RESULT_SMALLBUF;
488         }
489
490       result = m_FileReader.Read(FB.Data() + write_offset, VESReadSize, &read_count);
491
492       if ( result == RESULT_ENDOFFILE || read_count == 0 )
493         {
494           m_EOF = true;
495
496           if ( write_offset > 0 )
497             result = RESULT_OK;
498         }
499
500       if ( ASDCP_SUCCESS(result) )
501         {
502           result = m_Parser.Parse(FB.RoData() + write_offset, read_count);
503           write_offset += read_count;
504         }
505
506       if ( m_EOF )
507         break;
508     }
509   assert(m_ParserDelegate.m_FrameSize <= write_offset);
510
511   if ( ASDCP_SUCCESS(result)
512        && m_ParserDelegate.m_FrameSize < write_offset )
513     {
514       assert(m_TmpBuffer.Size() == 0);
515       ui32_t diff = write_offset - m_ParserDelegate.m_FrameSize;
516       assert(diff <= m_TmpBuffer.Capacity());
517
518       memcpy(m_TmpBuffer.Data(), FB.RoData() + m_ParserDelegate.m_FrameSize, diff);
519       m_TmpBuffer.Size(diff);
520     }
521
522   if ( ASDCP_SUCCESS(result) )
523     {
524       const byte_t* p = FB.RoData();
525       if ( p[0] != 0 || p[1] != 0 || p[2] != 1 || ! ( p[3] == SEQ_START || p[3] == PIC_START ) )
526         {
527           DefaultLogSink().Error("Frame buffer does not begin with a PIC or SEQ start code.\n");
528           return RESULT_RAW_FORMAT;
529         }
530     }
531
532   if ( ASDCP_SUCCESS(result) )
533     {
534       FB.Size(m_ParserDelegate.m_FrameSize);
535       FB.TemporalOffset(m_ParserDelegate.m_TemporalRef);
536       FB.FrameType(m_ParserDelegate.m_FrameType);
537       FB.PlaintextOffset(m_ParserDelegate.m_PlaintextOffset);
538       FB.FrameNumber(m_FrameNumber++);
539       FB.GOPStart(m_ParserDelegate.m_HasGOP);
540       FB.ClosedGOP(m_ParserDelegate.m_ClosedGOP);
541     }
542
543   return result;
544 }
545
546
547 // Fill a VideoDescriptor struct with the values from the file's header.
548 ASDCP::Result_t
549 ASDCP::MPEG2::Parser::h__Parser::FillVideoDescriptor(VideoDescriptor& VDesc)
550 {
551   VDesc = m_ParamsDelegate.m_VDesc;
552   return RESULT_OK;
553 }
554
555 //------------------------------------------------------------------------------------------
556
557 ASDCP::MPEG2::Parser::Parser()
558 {
559 }
560
561 ASDCP::MPEG2::Parser::~Parser()
562 {
563 }
564
565 // Opens the stream for reading, parses enough data to provide a complete
566 // set of stream metadata for the MXFWriter below.
567 ASDCP::Result_t
568 ASDCP::MPEG2::Parser::OpenRead(const std::string& filename) const
569 {
570   const_cast<ASDCP::MPEG2::Parser*>(this)->m_Parser = new h__Parser;
571
572   Result_t result = m_Parser->OpenRead(filename);
573
574   if ( ASDCP_FAILURE(result) )
575     const_cast<ASDCP::MPEG2::Parser*>(this)->m_Parser.release();
576
577   return result;
578 }
579
580 // Rewinds the stream to the beginning.
581 ASDCP::Result_t
582 ASDCP::MPEG2::Parser::Reset() const
583 {
584   if ( m_Parser.empty() )
585     return RESULT_INIT;
586
587   return m_Parser->Reset();
588 }
589
590 // Places a frame of data in the frame buffer. Fails if the buffer is too small
591 // or the stream is empty.
592 ASDCP::Result_t
593 ASDCP::MPEG2::Parser::ReadFrame(FrameBuffer& FB) const
594 {
595   if ( m_Parser.empty() )
596     return RESULT_INIT;
597
598   return m_Parser->ReadFrame(FB);
599 }
600
601 ASDCP::Result_t
602 ASDCP::MPEG2::Parser::FillVideoDescriptor(VideoDescriptor& VDesc) const
603 {
604   if ( m_Parser.empty() )
605     return RESULT_INIT;
606
607   return m_Parser->FillVideoDescriptor(VDesc);
608 }
609
610 //
611 // end MPEG2_Parser.cpp
612 //