2 Copyright (c) 2004-2011, 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 MPEG2_Parser.cpp
29 \brief AS-DCP library, MPEG2 raw essence reader implementation
32 #include <KM_fileio.h>
36 using Kumu::DefaultLogSink;
38 using namespace ASDCP;
39 using namespace ASDCP::MPEG2;
41 // data will be read from a VES file in chunks of this size
42 const ui32_t VESReadSize = 4 * Kumu::Kilobyte;
45 //------------------------------------------------------------------------------------------
58 StringParserState(ParserState_t state)
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";
78 ParserState_t m_State;
79 ASDCP_NO_COPY_CONSTRUCT(h__ParserState);
82 h__ParserState() : m_State(ST_INIT) {}
85 inline bool Test_SLICE() { return m_State == ST_SLICE; }
86 inline void Reset() { m_State = ST_INIT; }
89 inline Result_t Goto_SEQ()
99 DefaultLogSink().Error("SEQ follows %s\n", StringParserState(m_State));
105 inline Result_t Goto_SLICE()
115 DefaultLogSink().Error("Slice follows %s\n", StringParserState(m_State));
121 inline Result_t Goto_PIC()
133 DefaultLogSink().Error("PIC follows %s\n", StringParserState(m_State));
139 inline Result_t Goto_GOP()
149 DefaultLogSink().Error("GOP follows %s\n", StringParserState(m_State));
154 inline Result_t Goto_EXT()
166 DefaultLogSink().Error("EXT follows %s\n", StringParserState(m_State));
171 //------------------------------------------------------------------------------------------
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
177 class StreamParams : public VESParserDelegate
179 h__ParserState m_State;
181 ASDCP_NO_COPY_CONSTRUCT(StreamParams);
184 VideoDescriptor m_VDesc;
188 m_VDesc.ContainerDuration = 0;
189 m_VDesc.ComponentDepth = 8;
195 Result_t Sequence(VESParser*, const byte_t* b, ui32_t s)
197 Result_t result = m_State.Goto_SEQ();
199 if ( ASDCP_FAILURE(result) )
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;
214 Result_t Extension(VESParser*, const byte_t* b, ui32_t s)
216 Result_t result = m_State.Goto_EXT();
218 if ( ASDCP_FAILURE(result) )
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;
229 if ( ( m_VDesc.HorizontalSubsampling == 2 ) && ( m_VDesc.VerticalSubsampling == 2 ) )
230 m_VDesc.ColorSiting = 3; // 4:2:0
232 else if ( ( m_VDesc.HorizontalSubsampling == 2 ) && ( m_VDesc.VerticalSubsampling == 1 ) )
233 m_VDesc.ColorSiting = 4; // 4:2:2
235 else if ( ( m_VDesc.HorizontalSubsampling == 1 ) && ( m_VDesc.VerticalSubsampling == 1 ) )
236 m_VDesc.ColorSiting = 0; // 4:4:4
238 // TODO: get H&V size and bit rate extensions
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; }
250 //------------------------------------------------------------------------------------------
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.
257 class FrameParser : public VESParserDelegate
259 h__ParserState m_State;
260 ASDCP_NO_COPY_CONSTRUCT(FrameParser);
264 bool m_CompletePicture;
268 ui32_t m_PlaintextOffset;
269 FrameType_t m_FrameType;
281 m_HasGOP = m_ClosedGOP = false;
282 m_CompletePicture = false;
284 m_PlaintextOffset = 0;
285 m_FrameType = FRAME_U;
289 Result_t Sequence(VESParser*, const byte_t* b, ui32_t s)
291 if ( m_State.Test_SLICE() )
293 m_CompletePicture = true;
298 return m_State.Goto_SEQ();
301 Result_t Picture(VESParser*, const byte_t* b, ui32_t s)
303 if ( m_State.Test_SLICE() )
305 m_CompletePicture = true;
309 Accessor::Picture pic(b);
310 m_TemporalRef = pic.TemporalRef();
311 m_FrameType = pic.FrameType();
313 return m_State.Goto_PIC();
316 Result_t Slice(VESParser*, byte_t slice_id)
318 if ( slice_id == FIRST_SLICE )
320 m_PlaintextOffset = m_FrameSize;
321 return m_State.Goto_SLICE();
324 return m_State.Test_SLICE() ? RESULT_OK : RESULT_FAIL;
327 Result_t Extension(VESParser*, const byte_t* b, ui32_t s)
330 return m_State.Goto_EXT();
333 Result_t GOP(VESParser*, const byte_t* b, ui32_t s)
335 Accessor::GOP GOP(b);
336 m_ClosedGOP = GOP.Closed();
339 return m_State.Goto_GOP();
342 Result_t Data(VESParser*, const byte_t* b, i32_t s)
349 //------------------------------------------------------------------------------------------
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
358 class ASDCP::MPEG2::Parser::h__Parser
360 StreamParams m_ParamsDelegate;
361 FrameParser m_ParserDelegate;
363 Kumu::FileReader m_FileReader;
364 ui32_t m_FrameNumber;
366 ASDCP::MPEG2::FrameBuffer m_TmpBuffer;
368 ASDCP_NO_COPY_CONSTRUCT(h__Parser);
371 h__Parser() : m_TmpBuffer(VESReadSize*8) {}
372 ~h__Parser() { Close(); }
374 Result_t OpenRead(const std::string& filename);
377 Result_t ReadFrame(FrameBuffer&);
378 Result_t FillVideoDescriptor(VideoDescriptor&);
384 ASDCP::MPEG2::Parser::h__Parser::Reset()
388 m_FileReader.Seek(0);
389 m_ParserDelegate.Reset();
395 ASDCP::MPEG2::Parser::h__Parser::Close()
397 m_FileReader.Close();
402 ASDCP::MPEG2::Parser::h__Parser::OpenRead(const std::string& filename)
404 ui32_t read_count = 0;
406 Result_t result = m_FileReader.OpenRead(filename);
408 if ( ASDCP_SUCCESS(result) )
409 result = m_FileReader.Read(m_TmpBuffer.Data(), m_TmpBuffer.Capacity(), &read_count);
411 if ( ASDCP_SUCCESS(result) )
413 const byte_t* p = m_TmpBuffer.RoData();
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.
420 while ( p[i] == 0 ) i++;
422 if ( i < 2 || p[i] != 1 || ! ( p[i+1] == SEQ_START || p[i+1] == PIC_START ) )
424 DefaultLogSink().Error("Frame buffer does not begin with a PIC or SEQ start code.\n");
425 return RESULT_RAW_FORMAT;
428 if ( ASDCP_SUCCESS(result) )
430 m_Parser.SetDelegate(&m_ParamsDelegate);
431 result = m_Parser.Parse(p, read_count);
435 if ( ASDCP_SUCCESS(result) )
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);
443 if ( ASDCP_FAILURE(result) )
445 DefaultLogSink().Error("Unable to identify a wrapping mode for the essence in file \"%s\"\n", filename.c_str());
446 m_FileReader.Close();
455 ASDCP::MPEG2::Parser::h__Parser::ReadFrame(FrameBuffer& FB)
457 Result_t result = RESULT_OK;
458 ui32_t write_offset = 0;
459 ui32_t read_count = 0;
464 return RESULT_ENDOFFILE;
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
470 m_ParserDelegate.Reset();
473 if ( m_TmpBuffer.Size() > 0 )
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();
481 while ( ! m_ParserDelegate.m_CompletePicture && result == RESULT_OK )
483 if ( FB.Capacity() < ( write_offset + VESReadSize ) )
485 DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %u\n",
486 FB.Capacity(), ( write_offset + VESReadSize ));
487 return RESULT_SMALLBUF;
490 result = m_FileReader.Read(FB.Data() + write_offset, VESReadSize, &read_count);
492 if ( result == RESULT_ENDOFFILE || read_count == 0 )
496 if ( write_offset > 0 )
500 if ( ASDCP_SUCCESS(result) )
502 result = m_Parser.Parse(FB.RoData() + write_offset, read_count);
503 write_offset += read_count;
509 assert(m_ParserDelegate.m_FrameSize <= write_offset);
511 if ( ASDCP_SUCCESS(result)
512 && m_ParserDelegate.m_FrameSize < write_offset )
514 assert(m_TmpBuffer.Size() == 0);
515 ui32_t diff = write_offset - m_ParserDelegate.m_FrameSize;
516 assert(diff <= m_TmpBuffer.Capacity());
518 memcpy(m_TmpBuffer.Data(), FB.RoData() + m_ParserDelegate.m_FrameSize, diff);
519 m_TmpBuffer.Size(diff);
522 if ( ASDCP_SUCCESS(result) )
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 ) )
527 DefaultLogSink().Error("Frame buffer does not begin with a PIC or SEQ start code.\n");
528 return RESULT_RAW_FORMAT;
532 if ( ASDCP_SUCCESS(result) )
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);
547 // Fill a VideoDescriptor struct with the values from the file's header.
549 ASDCP::MPEG2::Parser::h__Parser::FillVideoDescriptor(VideoDescriptor& VDesc)
551 VDesc = m_ParamsDelegate.m_VDesc;
555 //------------------------------------------------------------------------------------------
557 ASDCP::MPEG2::Parser::Parser()
561 ASDCP::MPEG2::Parser::~Parser()
565 // Opens the stream for reading, parses enough data to provide a complete
566 // set of stream metadata for the MXFWriter below.
568 ASDCP::MPEG2::Parser::OpenRead(const std::string& filename) const
570 const_cast<ASDCP::MPEG2::Parser*>(this)->m_Parser = new h__Parser;
572 Result_t result = m_Parser->OpenRead(filename);
574 if ( ASDCP_FAILURE(result) )
575 const_cast<ASDCP::MPEG2::Parser*>(this)->m_Parser.release();
580 // Rewinds the stream to the beginning.
582 ASDCP::MPEG2::Parser::Reset() const
584 if ( m_Parser.empty() )
587 return m_Parser->Reset();
590 // Places a frame of data in the frame buffer. Fails if the buffer is too small
591 // or the stream is empty.
593 ASDCP::MPEG2::Parser::ReadFrame(FrameBuffer& FB) const
595 if ( m_Parser.empty() )
598 return m_Parser->ReadFrame(FB);
602 ASDCP::MPEG2::Parser::FillVideoDescriptor(VideoDescriptor& VDesc) const
604 if ( m_Parser.empty() )
607 return m_Parser->FillVideoDescriptor(VDesc);
611 // end MPEG2_Parser.cpp