2 Copyright (c) 2005, 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.
29 \brief MPEG2 VES parser
34 // walk a buffer stopping at the end of the buffer or the end of a VES
35 // start code '00 00 01'. If successful, returns address of first byte
38 ASDCP::MPEG2::FindVESStartCode(const byte_t* buf, ui32_t buf_len, StartCode_t* sc, const byte_t** new_pos)
41 ASDCP_TEST_NULL(new_pos);
44 const byte_t* p = buf;
45 const byte_t* end_p = buf + buf_len;
47 for ( ; p < end_p; p++ )
52 else if ( *p == 1 && zero_i > 1 )
54 // 2 or more 0 bytes followed by a 1, start code is next
59 *sc = (StartCode_t)*p;
66 *new_pos = buf + buf_len;
71 //------------------------------------------------------------------------------------------
75 ASDCP::MPEG2::Accessor::Sequence::AspectRatio()
77 switch ( m_p[3] & 0xf0 )
79 case 0x10: return Rational(1,1);
80 case 0x20: return Rational(4,3);
81 case 0x30: return Rational(16,9);
82 case 0x40: return Rational(221,100);
85 DefaultLogSink().Error("Unknown AspectRatio value: %02x\n", m_p[3]);
89 //------------------------------------------------------------------------------------------
99 class ASDCP::MPEG2::VESParser::h__StreamState
103 h__StreamState() : m_State(ST_IDLE) {}
106 void Goto_START_HEADER() { m_State = ST_START_HEADER; }
107 void Goto_IN_HEADER() { m_State = ST_IN_HEADER; }
108 void Goto_IDLE() { m_State = ST_IDLE; }
109 bool Test_IDLE() { return m_State == ST_IDLE; }
110 bool Test_START_HEADER() { return m_State == ST_START_HEADER; }
111 bool Test_IN_HEADER() { return m_State == ST_IN_HEADER; }
114 //------------------------------------------------------------------------------------------
117 ASDCP::MPEG2::VESParser::VESParser() :
118 m_Delegate(0), m_HBufLen(0), m_ZeroCount(0), m_Partial(false)
120 m_State = new h__StreamState;
123 ASDCP::MPEG2::VESParser::~VESParser()
130 ASDCP::MPEG2::VESParser::SetDelegate(VESParserDelegate* Delegate)
132 m_Delegate = Delegate;
137 ASDCP::MPEG2::VESParser::Reset()
139 m_State->Goto_IDLE();
147 ASDCP::MPEG2::VESParser::Parse(const byte_t* buf, ui32_t buf_len)
149 ASDCP_TEST_NULL(buf);
150 ASDCP_TEST_NULL(m_Delegate);
153 const byte_t* end_p = buf + buf_len;
154 const byte_t* run_pos = buf; // track runs of uninteresting data as a position and count
157 // search for MPEG2 headers
158 // copy interesting data to a buffer and pass to delegate for processing
159 for ( const byte_t* p = buf; p < end_p; p++ )
161 if ( m_State->Test_IN_HEADER() )
163 m_HBuf[m_HBufLen++] = *p;
164 assert(m_HBufLen < VESHeaderBufSize);
171 if ( m_State->Test_START_HEADER() ) // *p is a start code
173 // Do we already have a header? We need to flush it...
176 m_HBufLen -= 3; // remove the current partial start code
178 // let the delegate handle the header
181 case PIC_START: result = m_Delegate->Picture(this, m_HBuf, m_HBufLen); break;
182 case EXT_START: result = m_Delegate->Extension(this, m_HBuf, m_HBufLen); break;
183 case SEQ_START: result = m_Delegate->Sequence(this, m_HBuf, m_HBufLen); break;
184 case GOP_START: result = m_Delegate->GOP(this, m_HBuf, m_HBufLen); break;
187 DefaultLogSink().Error("Unexpected start code: %02x at byte %lu\n",
188 m_HBuf[3], (ui32_t)(p - buf));
189 result = RESULT_RAW_FORMAT;
192 // the next run starts with the start code that got us here
197 // Parser handlers return RESULT_FALSE to teriminate without error
198 if ( result != RESULT_OK )
200 m_State->Goto_IDLE();
205 // all headers start with this same start code: 00 00 01 xx
206 m_HBuf[0] = m_HBuf[1] = 0; m_HBuf[2] = 1; m_HBuf[3] = *p;
208 // is this a header we want?
209 if ( *p == PIC_START || *p == SEQ_START || *p == EXT_START || *p == GOP_START )
211 // we're starting a new header, flush the current run
214 m_Delegate->Data(this, run_pos, run_len - 4);
220 m_State->Goto_IN_HEADER();
224 if ( *p == FIRST_SLICE )
225 result = m_Delegate->Slice(this);
230 m_Delegate->Data(this, m_HBuf, 3);
233 m_State->Goto_IDLE();
242 if ( *p == 1 && m_ZeroCount > 1 )
243 m_State->Goto_START_HEADER();
251 if ( m_State->Test_START_HEADER() )
253 m_Partial = true; // 'partial' means we have a partial header in progress
257 // flush the current run
258 m_Delegate->Data(this, run_pos, run_len);