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