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