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