A quick translation of h264-stream
Map over H264Stream from action script and get it passing JSLint. There are still plenty of pieces which are definitely busted. Stub ExpGolomb out for now.
Showing
2 changed files
with
562 additions
and
2 deletions
src/exp-golomb.js
0 → 100644
1 | (function() { | ||
2 | |||
3 | window.videojs.hls.ExpGolomb = function() {}; | ||
4 | |||
5 | /* | ||
6 | public class ExpGolomb | ||
7 | { | ||
8 | private var workingData:ByteArray; | ||
9 | private var workingWord:uint; | ||
10 | private var workingbBitsAvailable:uint; | ||
11 | |||
12 | public function ExpGolomb(pData:ByteArray) | ||
13 | { | ||
14 | workingData = pData; | ||
15 | workingData.position = 0; | ||
16 | loadWord(); | ||
17 | } | ||
18 | |||
19 | public function length():uint | ||
20 | { | ||
21 | return ( 8 * workingData.length ); | ||
22 | } | ||
23 | |||
24 | public function bitsAvailable():uint | ||
25 | { | ||
26 | return ( 8 * workingData.bytesAvailable ) + workingbBitsAvailable; | ||
27 | } | ||
28 | |||
29 | private function loadWord():void | ||
30 | { | ||
31 | workingWord = 0; workingbBitsAvailable = 0; | ||
32 | switch( workingData.bytesAvailable ) | ||
33 | { | ||
34 | case 0: workingbBitsAvailable = 0; break; | ||
35 | default: // not 0, but greater than 4 | ||
36 | case 4: workingWord = workingData.readUnsignedByte(); workingbBitsAvailable = 8; | ||
37 | case 3: workingWord = ( workingWord << 8 ) | workingData.readUnsignedByte(); workingbBitsAvailable += 8; | ||
38 | case 2: workingWord = ( workingWord << 8 ) | workingData.readUnsignedByte(); workingbBitsAvailable += 8; | ||
39 | case 1: workingWord = ( workingWord << 8 ) | workingData.readUnsignedByte(); workingbBitsAvailable += 8; | ||
40 | } | ||
41 | |||
42 | workingWord <<= (32 - workingbBitsAvailable); | ||
43 | } | ||
44 | |||
45 | public function skipBits(size:int):void | ||
46 | { | ||
47 | if ( workingbBitsAvailable > size ) | ||
48 | { | ||
49 | workingWord <<= size; | ||
50 | workingbBitsAvailable -= size; | ||
51 | } | ||
52 | else | ||
53 | { | ||
54 | size -= workingbBitsAvailable; | ||
55 | var skipBytes:int = size / 8; | ||
56 | |||
57 | size -= ( skipBytes * 8 ); | ||
58 | workingData.position += skipBytes; | ||
59 | |||
60 | loadWord(); | ||
61 | |||
62 | workingWord <<= size; | ||
63 | workingbBitsAvailable -= size; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | public function readBits(size:int):uint | ||
68 | { | ||
69 | // if ( 32 < size ) | ||
70 | // throw new Error("Can not read more than 32 bits at a time"); | ||
71 | |||
72 | var bits:uint = ( workingbBitsAvailable < size ? workingbBitsAvailable : size); | ||
73 | var valu:uint = workingWord >>> (32 - bits); | ||
74 | |||
75 | workingbBitsAvailable -= bits; | ||
76 | if ( 0 < workingbBitsAvailable ) | ||
77 | workingWord <<= bits; | ||
78 | else | ||
79 | loadWord(); | ||
80 | |||
81 | bits = size - bits; | ||
82 | if ( 0 < bits ) | ||
83 | return valu << bits | readBits( bits ); | ||
84 | else | ||
85 | return valu; | ||
86 | } | ||
87 | |||
88 | private function skipLeadingZeros():uint | ||
89 | { | ||
90 | for( var clz:uint = 0 ; clz < workingbBitsAvailable ; ++clz ) | ||
91 | { | ||
92 | if( 0 != ( workingWord & ( 0x80000000 >>> clz ) ) ) | ||
93 | { | ||
94 | workingWord <<= clz; | ||
95 | workingbBitsAvailable -= clz; | ||
96 | return clz; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | loadWord(); // we exhausted workingWord and still have not found a 1 | ||
101 | return clz + skipLeadingZeros(); | ||
102 | } | ||
103 | |||
104 | public function skipUnsignedExpGolomb():void | ||
105 | { | ||
106 | skipBits(1 + skipLeadingZeros() ); | ||
107 | } | ||
108 | |||
109 | public function skipExpGolomb():void | ||
110 | { | ||
111 | skipBits(1 + skipLeadingZeros() ); | ||
112 | } | ||
113 | |||
114 | public function readUnsignedExpGolomb():uint | ||
115 | { | ||
116 | var clz:uint = skipLeadingZeros(); | ||
117 | return readBits(clz+1) - 1; | ||
118 | } | ||
119 | |||
120 | public function readExpGolomb():int | ||
121 | { | ||
122 | var valu:int = readUnsignedExpGolomb(); | ||
123 | if ( 0x01 & valu ) // the number is odd if the low order bit is set | ||
124 | return (1 + valu) >>> 1; // add 1 to make it even, and devide by 2 | ||
125 | else | ||
126 | return -1 * (valu >>> 1); // devide by two then make it negative | ||
127 | } | ||
128 | |||
129 | // Some convenience functions | ||
130 | public function readBoolean():Boolean | ||
131 | { | ||
132 | return 1 == readBits(1); | ||
133 | } | ||
134 | |||
135 | public function readUnsignedByte():int | ||
136 | { | ||
137 | return readBits(8); | ||
138 | } | ||
139 | } | ||
140 | */ | ||
141 | })(); |
... | @@ -7,9 +7,428 @@ | ... | @@ -7,9 +7,428 @@ |
7 | */ | 7 | */ |
8 | 8 | ||
9 | (function(window) { | 9 | (function(window) { |
10 | var | ||
11 | ExpGolomb = window.videojs.hls.ExpGolomb, | ||
12 | FlvTag = window.videojs.hls.FlvTag, | ||
13 | H264ExtraData = function() { | ||
14 | var | ||
15 | sps = [], // :Array | ||
16 | pps = []; // :Array | ||
17 | |||
18 | this.addSPS = function() { // :ByteArray | ||
19 | var tmp = new Uint8Array(); // :ByteArray | ||
20 | sps.push(tmp); | ||
21 | return tmp; | ||
22 | }; | ||
23 | |||
24 | this.addPPS = function() { // :ByteArray | ||
25 | var tmp = new Uint8Array(); // :ByteArray | ||
26 | pps.push(tmp); | ||
27 | return tmp; | ||
28 | }; | ||
29 | |||
30 | this.extraDataExists = function() { // :Boolean | ||
31 | return 0 < sps.length; | ||
32 | }; | ||
33 | |||
34 | // (sizeOfScalingList:int, expGolomb:ExpGolomb):void | ||
35 | this.scaling_list = function(sizeOfScalingList, expGolomb) { | ||
36 | var | ||
37 | lastScale = 8, // :int | ||
38 | nextScale = 8, // :int | ||
39 | j, | ||
40 | delta_scale; // :int | ||
41 | |||
42 | for (j = 0; j < sizeOfScalingList; ++j) { | ||
43 | if (0 !== nextScale) { | ||
44 | delta_scale = expGolomb.readExpGolomb(); | ||
45 | nextScale = (lastScale + delta_scale + 256) % 256; | ||
46 | //useDefaultScalingMatrixFlag = ( j = = 0 && nextScale = = 0 ) | ||
47 | } | ||
48 | |||
49 | lastScale = (nextScale === 0) ? lastScale : nextScale; | ||
50 | // scalingList[ j ] = ( nextScale == 0 ) ? lastScale : nextScale; | ||
51 | // lastScale = scalingList[ j ] | ||
52 | } | ||
53 | }; | ||
54 | |||
55 | this.getSps0Rbsp = function() { // :ByteArray | ||
56 | // remove emulation bytes. Is this nesessary? is there ever emulation bytes in the SPS? | ||
57 | var | ||
58 | sps0 = sps[0],// :ByteArray = sps[0]; | ||
59 | s, // :uint | ||
60 | e, // :uint | ||
61 | rbsp, // :ByteArray | ||
62 | o; // :uint | ||
63 | |||
64 | sps0.position = 1; | ||
65 | s = sps0.position; | ||
66 | e = sps0.bytesAvailable - 2; | ||
67 | rbsp = new Uint8Array(); // new ByteArray(); | ||
68 | |||
69 | for (o = s ; o < e ;) { | ||
70 | if (3 !== sps0[o + 2]) { | ||
71 | o += 3; | ||
72 | } else if (0 !== sps0[o + 1]) { | ||
73 | o += 2; | ||
74 | } else if (0 !== sps0[o + 0]) { | ||
75 | o += 1; | ||
76 | } else { // found emulation bytess | ||
77 | rbsp.writeShort(0x0000); | ||
78 | |||
79 | if ( o > s ) { | ||
80 | // If there are bytes to write, write them | ||
81 | sps0.readBytes( rbsp, rbsp.length, o-s ); | ||
82 | } | ||
83 | |||
84 | // skip the emulation bytes | ||
85 | sps0.position += 3; | ||
86 | o = s = sps0.position; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | // copy any remaining bytes | ||
91 | sps0.readBytes(rbsp, rbsp.length); | ||
92 | sps0.position = 0; | ||
93 | return rbsp; | ||
94 | }; | ||
95 | |||
96 | //(pts:uint):FlvTag | ||
97 | this.metaDataTag = function(pts) { | ||
98 | var | ||
99 | tag = new FlvTag(FlvTag.METADATA_TAG), // :FlvTag | ||
100 | expGolomb, // :ExpGolomb | ||
101 | profile_idc, // :int | ||
102 | chroma_format_idc, // :int | ||
103 | imax, // :int | ||
104 | i, // :int | ||
105 | |||
106 | pic_order_cnt_type, // :int | ||
107 | num_ref_frames_in_pic_order_cnt_cycle, // :uint | ||
108 | |||
109 | pic_width_in_mbs_minus1, // :int | ||
110 | pic_height_in_map_units_minus1, // :int | ||
111 | |||
112 | frame_mbs_only_flag, // :int | ||
113 | frame_cropping_flag, // :Boolean | ||
114 | |||
115 | frame_crop_left_offset, // :int | ||
116 | frame_crop_right_offset, // :int | ||
117 | frame_crop_top_offset, // :int | ||
118 | frame_crop_bottom_offset, // :int | ||
119 | |||
120 | width, | ||
121 | height; | ||
122 | |||
123 | tag.dts = pts; | ||
124 | tag.pts = pts; | ||
125 | expGolomb = new ExpGolomb(this.getSps0Rbsp()); | ||
126 | |||
127 | profile_idc = expGolomb.readUnsignedByte(); // :int = expGolomb.readUnsignedByte(); // profile_idc u(8) | ||
128 | expGolomb.skipBits(16);// constraint_set[0-5]_flag, u(1), reserved_zero_2bits u(2), level_idc u(8) | ||
129 | expGolomb.skipUnsignedExpGolomb(); // seq_parameter_set_id | ||
130 | |||
131 | if (profile_idc === 100 || | ||
132 | profile_idc === 110 || | ||
133 | profile_idc === 122 || | ||
134 | profile_idc === 244 || | ||
135 | profile_idc === 44 || | ||
136 | profile_idc === 83 || | ||
137 | profile_idc === 86 || | ||
138 | profile_idc === 118 || | ||
139 | profile_idc === 128) { | ||
140 | chroma_format_idc = expGolomb.readUnsignedExpGolomb(); | ||
141 | if (3 === chroma_format_idc) { | ||
142 | expGolomb.skipBits(1); // separate_colour_plane_flag | ||
143 | } | ||
144 | expGolomb.skipUnsignedExpGolomb(); // bit_depth_luma_minus8 | ||
145 | expGolomb.skipUnsignedExpGolomb(); // bit_depth_chroma_minus8 | ||
146 | expGolomb.skipBits(1); // qpprime_y_zero_transform_bypass_flag | ||
147 | if ( expGolomb.readBoolean() ) { // seq_scaling_matrix_present_flag | ||
148 | imax = (chroma_format_idc !== 3) ? 8 : 12; | ||
149 | for (i = 0 ; i < imax ; ++i) { | ||
150 | if (expGolomb.readBoolean()) { // seq_scaling_list_present_flag[ i ] | ||
151 | if (i < 6) { | ||
152 | this.scaling_list(16, expGolomb); | ||
153 | } else { | ||
154 | this.scaling_list(64, expGolomb); | ||
155 | } | ||
156 | } | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | |||
161 | expGolomb.skipUnsignedExpGolomb(); // log2_max_frame_num_minus4 | ||
162 | pic_order_cnt_type = expGolomb.readUnsignedExpGolomb(); | ||
163 | |||
164 | if ( 0 === pic_order_cnt_type ) { | ||
165 | expGolomb.readUnsignedExpGolomb(); //log2_max_pic_order_cnt_lsb_minus4 | ||
166 | } else if ( 1 === pic_order_cnt_type ) { | ||
167 | expGolomb.skipBits(1); // delta_pic_order_always_zero_flag | ||
168 | expGolomb.skipExpGolomb(); // offset_for_non_ref_pic | ||
169 | expGolomb.skipExpGolomb(); // offset_for_top_to_bottom_field | ||
170 | num_ref_frames_in_pic_order_cnt_cycle = expGolomb.readUnsignedExpGolomb(); | ||
171 | for(i = 0 ; i < num_ref_frames_in_pic_order_cnt_cycle ; ++i) { | ||
172 | expGolomb.skipExpGolomb(); // offset_for_ref_frame[ i ] | ||
173 | } | ||
174 | } | ||
175 | |||
176 | expGolomb.skipUnsignedExpGolomb(); // max_num_ref_frames | ||
177 | expGolomb.skipBits(1); // gaps_in_frame_num_value_allowed_flag | ||
178 | pic_width_in_mbs_minus1 = expGolomb.readUnsignedExpGolomb(); | ||
179 | pic_height_in_map_units_minus1 = expGolomb.readUnsignedExpGolomb(); | ||
180 | |||
181 | frame_mbs_only_flag = expGolomb.readBits(1); | ||
182 | if (0 === frame_mbs_only_flag) { | ||
183 | expGolomb.skipBits(1); // mb_adaptive_frame_field_flag | ||
184 | } | ||
185 | |||
186 | expGolomb.skipBits(1); // direct_8x8_inference_flag | ||
187 | frame_cropping_flag = expGolomb.readBoolean(); | ||
188 | if (frame_cropping_flag) { | ||
189 | frame_crop_left_offset = expGolomb.readUnsignedExpGolomb(); | ||
190 | frame_crop_right_offset = expGolomb.readUnsignedExpGolomb(); | ||
191 | frame_crop_top_offset = expGolomb.readUnsignedExpGolomb(); | ||
192 | frame_crop_bottom_offset = expGolomb.readUnsignedExpGolomb(); | ||
193 | } | ||
194 | |||
195 | width = ((pic_width_in_mbs_minus1 +1)*16) - frame_crop_left_offset*2 - frame_crop_right_offset*2; | ||
196 | height = ((2 - frame_mbs_only_flag)* (pic_height_in_map_units_minus1 +1) * 16) - (frame_crop_top_offset * 2) - (frame_crop_bottom_offset * 2); | ||
197 | |||
198 | tag.writeMetaDataDouble("videocodecid", 7); | ||
199 | tag.writeMetaDataDouble("width", width); | ||
200 | tag.writeMetaDataDouble("height", height); | ||
201 | // tag.writeMetaDataDouble("videodatarate", 0 ); | ||
202 | // tag.writeMetaDataDouble("framerate", 0); | ||
203 | |||
204 | return tag; | ||
205 | }; | ||
206 | |||
207 | // (pts:uint):FlvTag | ||
208 | this.extraDataTag = function(pts) { | ||
209 | var | ||
210 | i, | ||
211 | tag = new FlvTag(FlvTag.VIDEO_TAG,true); | ||
212 | |||
213 | tag.dts = pts; | ||
214 | tag.pts = pts; | ||
215 | |||
216 | tag.writeByte(0x01);// version | ||
217 | tag.writeByte(sps[0][1]);// profile | ||
218 | tag.writeByte(sps[0][2]);// compatibility | ||
219 | tag.writeByte(sps[0][3]);// level | ||
220 | tag.writeByte(0xFC | 0x03); // reserved (6 bits), NULA length size - 1 (2 bits) | ||
221 | tag.writeByte(0xE0 | 0x01 ); // reserved (3 bits), num of SPS (5 bits) | ||
222 | tag.writeShort( sps[0].length ); // data of SPS | ||
223 | tag.writeBytes( sps[0] ); // SPS | ||
224 | |||
225 | tag.writeByte( pps.length ); // num of PPS (will there ever be more that 1 PPS?) | ||
226 | for (i = 0 ; i < pps.length ; ++i) { | ||
227 | tag.writeShort(pps[i].length); // 2 bytes for length of PPS | ||
228 | tag.writeBytes(pps[i]); // data of PPS | ||
229 | } | ||
230 | |||
231 | return tag; | ||
232 | }; | ||
233 | }; | ||
234 | |||
235 | window.videojs.hls.H264Stream = function() { | ||
236 | var | ||
237 | tags = [], | ||
238 | |||
239 | next_pts, // :uint; | ||
240 | next_dts, // :uint; | ||
241 | pts_delta = -1, // :int | ||
242 | |||
243 | h264Frame, // :FlvTag | ||
244 | |||
245 | oldExtraData = new H264ExtraData(), // :H264ExtraData | ||
246 | newExtraData = new H264ExtraData(), // :H264ExtraData | ||
247 | |||
248 | nalUnitType = -1, // :int | ||
249 | |||
250 | state; // :uint; | ||
10 | 251 | ||
11 | window.videojs.hls.H264Stream = function(){ | ||
12 | this.tags = []; | 252 | this.tags = []; |
13 | }; | ||
14 | 253 | ||
254 | //(pts:uint, dts:uint, dataAligned:Boolean):void | ||
255 | this.setNextTimeStamp = function(pts, dts, dataAligned) { | ||
256 | if (0>pts_delta) { | ||
257 | // We assume the very first pts is less than 0x8FFFFFFF (max signed | ||
258 | // int32) | ||
259 | pts_delta = pts; | ||
260 | } | ||
261 | |||
262 | // We could end up with a DTS less than 0 here. We need to deal with that! | ||
263 | next_pts = pts - pts_delta; | ||
264 | next_dts = dts - pts_delta; | ||
265 | |||
266 | // If data is aligned, flush all internal buffers | ||
267 | if (dataAligned) { | ||
268 | this.finishFrame(); | ||
269 | } | ||
270 | }; | ||
271 | |||
272 | this.finishFrame = function() { | ||
273 | if (null !== h264Frame) { | ||
274 | // Push SPS before EVERY IDR frame fo seeking | ||
275 | if (newExtraData.extraDataExists()) { | ||
276 | oldExtraData = newExtraData; | ||
277 | newExtraData = new H264ExtraData(); | ||
278 | } | ||
279 | |||
280 | if(true === h264Frame.keyFrame) { | ||
281 | // Push extra data on every IDR frame in case we did a stream change + seek | ||
282 | tags.push( oldExtraData.metaDataTag (h264Frame.pts) ); | ||
283 | tags.push( oldExtraData.extraDataTag(h264Frame.pts) ); | ||
284 | } | ||
285 | |||
286 | h264Frame.endNalUnit(); | ||
287 | tags.push(h264Frame); | ||
288 | } | ||
289 | |||
290 | h264Frame = null; | ||
291 | nalUnitType = -1; | ||
292 | state = 0; | ||
293 | }; | ||
294 | |||
295 | // (pData:ByteArray, o:int, l:int):void | ||
296 | this.writeBytes = function(pData, o, l) { | ||
297 | var | ||
298 | nalUnitSize, // :uint | ||
299 | s, // :uint | ||
300 | e, // :uint | ||
301 | t; // :int | ||
302 | |||
303 | if (0 >= l) { | ||
304 | return; | ||
305 | } | ||
306 | switch (state) { | ||
307 | default: | ||
308 | state = 1; | ||
309 | break; | ||
310 | case 0: | ||
311 | state = 1; | ||
312 | break; | ||
313 | /*--------------------------------------------------------------------------------------------------------------------*/ | ||
314 | case 1: // We are looking for overlaping start codes | ||
315 | if (1 >= pData[o]) { | ||
316 | nalUnitSize = (null === h264Frame) ? 0 : h264Frame.nalUnitSize(); | ||
317 | if (1 <= nalUnitSize && 0 === h264Frame.negIndex(1)) { | ||
318 | // ?? ?? 00 | O[01] ?? ?? | ||
319 | if (1 === pData[o] && 2 <= nalUnitSize && 0 === h264Frame.negIndex(2) ) { | ||
320 | // ?? 00 00 : 01 | ||
321 | if (3 <= nalUnitSize && 0 === h264Frame.negIndex(3)) { | ||
322 | h264Frame.length -= 3; // 00 00 00 : 01 | ||
323 | } else { | ||
324 | h264Frame.length -= 2; // 00 00 : 01 | ||
325 | } | ||
326 | |||
327 | state = 3; | ||
328 | return this.writeBytes(pData, o + 1, l - 1); | ||
329 | } | ||
330 | |||
331 | if (1 < l && 0 === pData[o] && 1 === pData[o + 1]) { | ||
332 | // ?? 00 | 00 01 | ||
333 | if (2 <= nalUnitSize && 0 === h264Frame.negIndex(2)) { | ||
334 | h264Frame.length -= 2; // 00 00 : 00 01 | ||
335 | } else { | ||
336 | h264Frame.length -= 1; // 00 : 00 01 | ||
337 | } | ||
338 | |||
339 | state = 3; | ||
340 | return this.writeBytes(pData, o + 2, l - 2); | ||
341 | } | ||
342 | |||
343 | if (2 < l && 0 === pData[o] && 0 === pData[o + 1] && 1 === pData[o + 2]) { | ||
344 | // 00 | 00 00 01 | ||
345 | h264Frame.length -= 1; | ||
346 | state = 3; | ||
347 | return this.writeBytes(pData, o + 3, l - 3); | ||
348 | } | ||
349 | } | ||
350 | } | ||
351 | // allow fall through if the above fails, we may end up checking a few | ||
352 | // bytes a second time. But that case will be VERY rare | ||
353 | state = 2; | ||
354 | break; | ||
355 | case 2: // Look for start codes in pData | ||
356 | s = o; // s = Start | ||
357 | e = s + l; // e = End | ||
358 | for (t = e - 3 ; o < t ;) { | ||
359 | if (1 < pData[o + 2]) { | ||
360 | o += 3; // if pData[o+2] is greater than 1, there is no way a start code can begin before o+3 | ||
361 | } else if (0 !== pData[o + 1]) { | ||
362 | o += 2; | ||
363 | } else if (0 !== pData[o]) { | ||
364 | o += 1; | ||
365 | } else { | ||
366 | // If we get here we have 00 00 00 or 00 00 01 | ||
367 | if (1 === pData[o + 2]) { | ||
368 | if (o > s) { | ||
369 | h264Frame.writeBytes(pData, s, o - s); | ||
370 | } | ||
371 | state = 3; o += 3; | ||
372 | return this.writeBytes(pData, o, e - o); | ||
373 | } | ||
374 | |||
375 | if (4 <= e-o && 0 === pData[o + 2] && 1 === pData[o + 3]) { | ||
376 | if (o > s) { | ||
377 | h264Frame.writeBytes(pData, s, o - s); | ||
378 | } | ||
379 | state = 3; | ||
380 | o += 4; | ||
381 | return this.writeBytes(pData, o, e - o); | ||
382 | } | ||
383 | |||
384 | // We are at the end of the buffer, or we have 3 NULLS followed by something that is not a 1, eaither way we can step forward by at least 3 | ||
385 | o += 3; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | // We did not find any start codes. Try again next packet | ||
390 | state = 1; | ||
391 | h264Frame.writeBytes( pData, s, l ); | ||
392 | return; | ||
393 | /*--------------------------------------------------------------------------------------------------------------------*/ | ||
394 | case 3: // The next byte is the first byte of a NAL Unit | ||
395 | if (null !== h264Frame) { | ||
396 | switch (nalUnitType) { | ||
397 | // We are still operating on the previous NAL Unit | ||
398 | case 7: | ||
399 | h264Frame.endNalUnit(newExtraData.addSPS()); | ||
400 | break; | ||
401 | case 8: | ||
402 | h264Frame.endNalUnit(newExtraData.addPPS()); | ||
403 | break; | ||
404 | case 5: | ||
405 | h264Frame.keyFrame = true; | ||
406 | h264Frame.endNalUnit(); | ||
407 | break; | ||
408 | default: | ||
409 | h264Frame.endNalUnit(); | ||
410 | break; | ||
411 | } | ||
412 | } | ||
413 | |||
414 | nalUnitType = pData[o] & 0x1F; | ||
415 | if ( null != h264Frame && 9 === nalUnitType ) { | ||
416 | this.finishFrame(); // We are starting a new access unit. Flush the previous one | ||
417 | } | ||
418 | |||
419 | // finishFrame may render h264Frame null, so we must test again | ||
420 | if ( null === h264Frame ) | ||
421 | { | ||
422 | h264Frame = new FlvTag(FlvTag.VIDEO_TAG); | ||
423 | h264Frame.pts = next_pts; | ||
424 | h264Frame.dts = next_dts; | ||
425 | } | ||
426 | |||
427 | h264Frame.startNalUnit(); | ||
428 | state = 2; // We know there will not be an overlapping start code, so we can skip that test | ||
429 | return this.writeBytes(pData, o, l); | ||
430 | /*--------------------------------------------------------------------------------------------------------------------*/ | ||
431 | } // switch | ||
432 | }; | ||
433 | }; | ||
15 | })(this); | 434 | })(this); | ... | ... |
-
Please register or sign in to post a comment