1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
/*
Copyright (c) 2005-2011, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*! \file MPEG.h
\version $Id$
\brief MPEG2 VES parser interface
*/
#ifndef _MPEG_H_
#define _MPEG_H_
#include <KM_platform.h>
#include "AS_DCP.h"
#include <stdio.h>
#include <assert.h>
namespace ASDCP
{
namespace MPEG2
{
//
enum StartCode_t {
PIC_START = 0x00,
SEQ_START = 0xb3,
EXT_START = 0xb5,
GOP_START = 0xb8,
FIRST_SLICE = 0x01,
LAST_SLICE = 0xaf,
INVALID = 0xff
};
//
enum RateCode_t {
RATE_23_976 = 0x01,
RATE_24 = 0x02,
RATE_25 = 0x03,
RATE_29_97 = 0x04,
RATE_30 = 0x05
};
//
enum ExtCode_t {
EXT_SEQ = 0x01
};
//------------------------------------------------------------------------------------------
// VES Parser
// find the location in the buffer of the next VES packet, returns RESULT_FAIL
// if no start code is found
Result_t FindVESStartCode(const byte_t* buf, ui32_t buf_len, StartCode_t* sc, const byte_t** new_pos);
// return the extension code of an extension header
inline ExtCode_t ParseExtensionCode(const byte_t* buf)
{
assert(buf);
return (ExtCode_t)(buf[4] >> 4);
}
//
class VESParserDelegate; // the delegate is declared later
const ui32_t VESHeaderBufSize = 1024*32; // should be larger than any expected header
// MPEG VES parser class - call Parse() as many times as you want with buffers
// of any size. State is maintained between calls. When complete headers are
// available for examination, the respective delegate method will be called.
// All other data is given to the delegate's Data() method.
class VESParser
{
class h__StreamState;
Kumu::mem_ptr<h__StreamState> m_State;
VESParserDelegate* m_Delegate;
ui32_t m_HBufLen; // temp space for partial header contents
byte_t m_HBuf[VESHeaderBufSize];
ui32_t m_ZeroCount;
bool m_Partial;
ASDCP_NO_COPY_CONSTRUCT(VESParser);
public:
VESParser();
~VESParser();
void SetDelegate(VESParserDelegate*); // you must call this before Parse()
Result_t Parse(const byte_t*, ui32_t); // call repeatedly
void Reset(); // resets the internal state machine and counters, return to the top of the file
};
// Parser Event Delegate Interface
//
// Create a concrete subclass and give it to the parser by calling SetDelegate().
// The respective method will be called when a header of the named type is found.
// Handler methods should return RESULT_OK to continue processing or RESULT_FALSE
// to terminate parsing without signaling an error.
//
class VESParserDelegate
{
public:
virtual ~VESParserDelegate() {}
// header handlers
virtual Result_t Picture(VESParser* Caller, const byte_t* header_buf, ui32_t header_len) = 0;
virtual Result_t Extension(VESParser*, const byte_t*, ui32_t) = 0;
virtual Result_t Sequence(VESParser*, const byte_t*, ui32_t) = 0;
virtual Result_t GOP(VESParser*, const byte_t*, ui32_t) = 0;
// this is not a header handler, it is a signal that actual picture data
// has started. All Slice data is reported via the Data() method.
virtual Result_t Slice(VESParser*, byte_t slice_id) = 0;
// Any data not given to the header handlers above is reported here
// This method may be called with a value of -1 or -2. This will happen
// when processing a start code that has one or two leading zeros
// in the preceding buffer
virtual Result_t Data(VESParser*, const byte_t*, i32_t) = 0;
};
//------------------------------------------------------------------------------------------
// VES header accessor objects
//
// For use within parser delegate methods. The constructor expects a pointer to a buffer
// containing two zero bytes, a one byte, a start code and some number of header bytes.
// They are not documented further as it is hoped that they are self-explanatory.
//
namespace Accessor
{
// decoding tables
static i16_t FrameRateLUT[] = { 0, 24, 24, 25, 30, 30, 50, 60, 60};
static bool PulldownLUT[] = { false, true, false, false, true, false, false, true, false};
//
class Sequence
{
const byte_t* m_p;
ASDCP_NO_COPY_CONSTRUCT(Sequence);
public:
Sequence(const byte_t* p) { assert(p); m_p = p + 4; }
inline ui16_t HorizontalSize() { return (ui16_t)( ( m_p[0] << 4 ) | ( m_p[1] >> 4 ) ); }
inline ui16_t VerticalSize() { return (ui16_t)( ( ( m_p[1] & 0x0f ) << 8 ) | m_p[2] ); }
inline RateCode_t RateCode() { return (RateCode_t)( m_p[3] & 0x0f ); }
inline ui16_t FrameRate() { return FrameRateLUT[RateCode()]; }
inline bool Pulldown() { return PulldownLUT[RateCode()] != 0; }
inline i32_t BitRate() {
return ( ( (i32_t)m_p[4] << 10 ) + ( (i32_t)m_p[5] << 2 ) + ( m_p[6] >> 6 ) ) * 400;
}
Rational AspectRatio();
};
//
class SequenceEx // tension
{
const byte_t* m_p;
ASDCP_NO_COPY_CONSTRUCT(SequenceEx);
public:
SequenceEx(const byte_t* p)
{
assert(p);
assert(ParseExtensionCode(p) == EXT_SEQ);
m_p = p + 4;
}
inline ui16_t ProfileAndLevel() { return ( m_p[0] << 4) | ( m_p[1] >> 4 ); }
inline ui8_t ChromaFormat() { return ( m_p[1] >> 1 ) & 0x03; }
inline bool Progressive() { return ( ( m_p[1] >> 3 ) & 0x01 ) > 0; }
inline ui32_t HorizontalSizeExt() {
return ( ( m_p[1] & 0x01 ) << 13 ) | ( ( m_p[2] & 0x80 ) << 5 );
}
inline ui32_t VerticalSizeExt() { return ( m_p[2] & 0x60 ) << 7; }
inline ui32_t BitRateExt() {
return ( ( m_p[2] & 0x1f ) << 25 ) | ( ( m_p[3] & 0xfe ) << 17 );
}
inline bool LowDelay() { return ( m_p[5] & 0x80 ) > 0; }
};
//
class GOP
{
const byte_t* m_p;
ASDCP_NO_COPY_CONSTRUCT(GOP);
public:
GOP(const byte_t* p) { assert(p); m_p = p + 4; }
inline bool Closed() { return ( ( m_p[3] ) >> 6 ) & 0x01; }
};
//
class Picture
{
const byte_t* m_p;
ASDCP_NO_COPY_CONSTRUCT(Picture);
public:
Picture(const byte_t* p) { assert(p); m_p = p + 4; }
inline i16_t TemporalRef() {
return ( (i16_t)( m_p[0] << 2 ) ) | ( ( (i16_t)m_p[1] & 0x00c0 ) >> 6 );
}
inline FrameType_t FrameType() {
return (FrameType_t)( ( m_p[1] & 0x38 ) >> 3 );
}
};
} // namespace Accessor
} // namespace MPEG2
} // namespace ASDCP
#endif // _MPEG_H_
//
// end MPEG.h
//
|