metadata reformed...
[asdcplib.git] / src / MPEG.h
1 /*
2 Copyright (c) 2005, 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    MPEG.h
28     \version $Id$
29     \brief   MPEG2 VES parser interface
30 */
31
32 #ifndef _ASDCP_MPEG_H_
33 #define _ASDCP_MPEG_H_
34
35 #include <AS_DCP_system.h>
36 #include <stdio.h>
37 #include <assert.h>
38
39
40 namespace ASDCP
41 {
42   namespace MPEG2
43     {
44       //
45       enum StartCode_t {
46         PIC_START   = 0x00,
47         SEQ_START   = 0xb3,
48         EXT_START   = 0xb5,
49         GOP_START   = 0xb8,
50         FIRST_SLICE = 0x01,
51         INVALID     = 0xff
52       };
53
54       //
55       enum RateCode_t {
56         RATE_23_976 = 0x01,
57         RATE_24     = 0x02,
58         RATE_25     = 0x03,
59         RATE_29_97  = 0x04,
60         RATE_30     = 0x05
61       };
62
63       //
64       enum ExtCode_t {
65         EXT_SEQ = 0x01
66       };
67
68       //------------------------------------------------------------------------------------------
69       // VES Parser
70
71       // find the location in the buffer of the next VES packet, returns RESULT_FAIL
72       // if no start code is found
73       Result_t FindVESStartCode(const byte_t* buf, ui32_t buf_len, StartCode_t* sc, const byte_t** new_pos);
74
75       // return the extension code of an extension header
76       inline ExtCode_t ParseExtensionCode(const byte_t* buf)
77         {
78           assert(buf);
79           return (ExtCode_t)(buf[4] >> 4);
80         }
81
82       //
83       class VESParserDelegate; // the delegate is declared later
84       const ui32_t VESHeaderBufSize = 1024; // should be larger than any expected header
85
86       // MPEG VES parser class - call Parse() as many times as you want with buffers
87       // of any size. State is maintained between calls. When complete headers are
88       // available for examination, the respective delegate method will be called.
89       // All other data is given to the delegate's Data() method.
90       class VESParser
91         {
92           class h__StreamState;
93           mem_ptr<h__StreamState> m_State;
94           VESParserDelegate*      m_Delegate;
95
96           ui32_t         m_HBufLen; // temp space for partial header contents
97           byte_t         m_HBuf[VESHeaderBufSize];
98           ui32_t         m_ZeroCount;
99           bool           m_Partial;
100
101           ASDCP_NO_COPY_CONSTRUCT(VESParser);
102
103         public:
104           VESParser();
105           ~VESParser();
106
107           void     SetDelegate(VESParserDelegate*); // you must call this before Parse()
108           Result_t Parse(const byte_t*, ui32_t);  // call repeatedly
109           void     Reset(); // resets the internal state machine and counters
110         };
111
112       // Parser Event Delegate Interface
113       //
114       // Create a concrete subclass and give it to the parser by calling SetDelegate().
115       // The respective method will be called when a header of the named type is found.
116       // Handler methods should return RESULT_OK to continue processing or RESULT_FALSE
117       // to stop without error.
118       //
119       class VESParserDelegate
120         {
121         public:
122           virtual ~VESParserDelegate() {}
123
124           // header handlers
125           virtual Result_t Picture(VESParser*, const byte_t*, ui32_t) = 0;
126           virtual Result_t Extension(VESParser*, const byte_t*, ui32_t) = 0;
127           virtual Result_t Sequence(VESParser*, const byte_t*, ui32_t) = 0;
128           virtual Result_t GOP(VESParser*, const byte_t*, ui32_t) = 0;
129
130           // this is not a header handler, it is a signal that actual picture data
131           // has started. All Slice data is reported via the Data() method.
132           virtual Result_t Slice(VESParser*) = 0;
133
134           // Any data not given to the header handlers above is reported here
135           virtual Result_t Data(VESParser*, const byte_t*, ui32_t) = 0;
136         };
137
138
139       //------------------------------------------------------------------------------------------
140       // VES header accessor objects
141       //
142       // For use within parser delegate methods. The constructor expects a pointer to a buffer
143       // containing two zero bytes, a one byte, a start code and some number of header bytes.
144       // They are not documented further as they should be self-explanatory.
145       namespace Accessor
146         {
147           // decoding tables
148           static i16_t FrameRateLUT[] = { 0, 24, 24, 25, 30, 30, 50, 60, 60};
149           static bool  PulldownLUT[]  = { false,  true,  false,  false,  true,  false,  false,  true,  false};
150
151           //
152           class Sequence
153             {
154               const byte_t* m_p;
155               ASDCP_NO_COPY_CONSTRUCT(Sequence);
156
157             public:
158               Sequence(const byte_t* p) { assert(p); m_p = p + 4; }
159               inline ui16_t      HorizontalSize() { return (ui16_t)( ( m_p[0] << 4 ) | ( m_p[1] >> 4 ) ); }
160               inline ui16_t      VerticalSize()   { return (ui16_t)( ( ( m_p[1] & 0x0f ) << 8 ) | m_p[2] ); }
161               inline RateCode_t  RateCode()       { return (RateCode_t)( m_p[3] & 0x0f ); }
162               inline ui16_t      FrameRate()      { return FrameRateLUT[RateCode()]; }
163               inline bool        Pulldown()       { return PulldownLUT[RateCode()] != 0; }
164               inline i32_t       BitRate() {
165                 return ( ( (i32_t)m_p[4] << 10 ) + ( (i32_t)m_p[5] << 2 ) + ( m_p[6] >> 6 ) ) * 400;
166               }
167
168               Rational   AspectRatio();
169             };
170
171           //
172           class SequenceEx
173             {
174               const byte_t* m_p;
175               ASDCP_NO_COPY_CONSTRUCT(SequenceEx);
176
177             public:
178               SequenceEx(const byte_t* p)
179                 {
180                   assert(p);
181                   assert(ParseExtensionCode(p) == EXT_SEQ);
182                   m_p = p + 4;
183                 }
184
185               inline ui16_t      ProfileAndLevel()   { return ( m_p[0] << 4) | ( m_p[1] >> 4 ); }
186               inline ui8_t       ChromaFormat()      { return ( m_p[1] >> 1 ) & 0x03; }
187               inline bool        Progressive()       { return ( ( m_p[1] >> 3 ) & 0x01 ) > 0; }
188               inline ui32_t      HorizontalSizeExt() {
189                 return ( ( m_p[1] & 0x01 ) << 13 ) | ( ( m_p[2] & 0x80 ) << 5 );
190               }
191               inline ui32_t      VerticalSizeExt()   { return ( m_p[2] & 0x60 ) << 7; }
192               inline ui32_t      BitRateExt()        {
193                 return ( ( m_p[2] & 0x1f ) << 25 ) | ( ( m_p[3] & 0xfe ) << 17 );
194               }
195
196               inline bool        LowDelay()          { return ( m_p[5] & 0x80 ) > 0; }
197             };
198
199           //
200           class GOP
201             {
202               const byte_t* m_p;
203               ASDCP_NO_COPY_CONSTRUCT(GOP);
204
205             public:
206               GOP(const byte_t* p) { assert(p); m_p = p + 4; }
207               inline bool        Closed() { return ( ( m_p[3] ) >> 6 ) & 0x01; }
208             };
209
210           //
211           class Picture
212             {
213               const byte_t*  m_p;
214               ASDCP_NO_COPY_CONSTRUCT(Picture);
215               
216             public:
217               Picture(const byte_t* p) { assert(p); m_p = p + 4; }
218               inline i16_t       TemporalRef() {
219                 return ( (i16_t)( m_p[0] << 2 ) ) | ( ( (i16_t)m_p[1] & 0x00c0 ) >> 6 );
220               }
221
222               inline FrameType_t FrameType()   {
223                 return (FrameType_t)( ( m_p[1] & 0x38 ) >> 3 );
224               }
225             };
226           
227         } // namespace Accessor
228
229     } // namespace MPEG2
230
231 } // namespace ASDCP
232
233 #endif // ASDCP_MPEG_H_
234
235 //
236 // end MPEG.h
237 //