Remove old transmuxing infrastructure
All the transmuxing code has moved into mux.js so we can get rid of the remnants in this project.
Showing
35 changed files
with
0 additions
and
3092 deletions
src/aac-stream.js
deleted
100644 → 0
1 | (function(window) { | ||
2 | var | ||
3 | FlvTag = window.videojs.Hls.FlvTag, | ||
4 | adtsSampleingRates = [ | ||
5 | 96000, 88200, | ||
6 | 64000, 48000, | ||
7 | 44100, 32000, | ||
8 | 24000, 22050, | ||
9 | 16000, 12000 | ||
10 | ]; | ||
11 | |||
12 | window.videojs.Hls.AacStream = function() { | ||
13 | var | ||
14 | next_pts, // :uint | ||
15 | state, // :uint | ||
16 | pes_length, // :int | ||
17 | lastMetaPts, | ||
18 | |||
19 | adtsProtectionAbsent, // :Boolean | ||
20 | adtsObjectType, // :int | ||
21 | adtsSampleingIndex, // :int | ||
22 | adtsChanelConfig, // :int | ||
23 | adtsFrameSize, // :int | ||
24 | adtsSampleCount, // :int | ||
25 | adtsDuration, // :int | ||
26 | |||
27 | aacFrame, // :FlvTag = null; | ||
28 | extraData; // :uint; | ||
29 | |||
30 | this.tags = []; | ||
31 | |||
32 | // (pts:uint):void | ||
33 | this.setTimeStampOffset = function(pts) { | ||
34 | |||
35 | // keep track of the last time a metadata tag was written out | ||
36 | // set the initial value so metadata will be generated before any | ||
37 | // payload data | ||
38 | lastMetaPts = pts - 1000; | ||
39 | }; | ||
40 | |||
41 | // (pts:uint, pes_size:int, dataAligned:Boolean):void | ||
42 | this.setNextTimeStamp = function(pts, pes_size, dataAligned) { | ||
43 | next_pts = pts; | ||
44 | pes_length = pes_size; | ||
45 | |||
46 | // If data is aligned, flush all internal buffers | ||
47 | if (dataAligned) { | ||
48 | state = 0; | ||
49 | } | ||
50 | }; | ||
51 | |||
52 | // (data:ByteArray, o:int = 0, l:int = 0):void | ||
53 | this.writeBytes = function(data, offset, length) { | ||
54 | var | ||
55 | end, // :int | ||
56 | newExtraData, // :uint | ||
57 | bytesToCopy; // :int | ||
58 | |||
59 | // default arguments | ||
60 | offset = offset || 0; | ||
61 | length = length || 0; | ||
62 | |||
63 | // Do not allow more than 'pes_length' bytes to be written | ||
64 | length = (pes_length < length ? pes_length : length); | ||
65 | pes_length -= length; | ||
66 | end = offset + length; | ||
67 | while (offset < end) { | ||
68 | switch (state) { | ||
69 | default: | ||
70 | state = 0; | ||
71 | break; | ||
72 | case 0: | ||
73 | if (offset >= end) { | ||
74 | return; | ||
75 | } | ||
76 | if (0xFF !== data[offset]) { | ||
77 | console.assert(false, 'Error no ATDS header found'); | ||
78 | offset += 1; | ||
79 | state = 0; | ||
80 | return; | ||
81 | } | ||
82 | |||
83 | offset += 1; | ||
84 | state = 1; | ||
85 | break; | ||
86 | case 1: | ||
87 | if (offset >= end) { | ||
88 | return; | ||
89 | } | ||
90 | if (0xF0 !== (data[offset] & 0xF0)) { | ||
91 | console.assert(false, 'Error no ATDS header found'); | ||
92 | offset +=1; | ||
93 | state = 0; | ||
94 | return; | ||
95 | } | ||
96 | |||
97 | adtsProtectionAbsent = !!(data[offset] & 0x01); | ||
98 | |||
99 | offset += 1; | ||
100 | state = 2; | ||
101 | break; | ||
102 | case 2: | ||
103 | if (offset >= end) { | ||
104 | return; | ||
105 | } | ||
106 | adtsObjectType = ((data[offset] & 0xC0) >>> 6) + 1; | ||
107 | adtsSampleingIndex = ((data[offset] & 0x3C) >>> 2); | ||
108 | adtsChanelConfig = ((data[offset] & 0x01) << 2); | ||
109 | |||
110 | offset += 1; | ||
111 | state = 3; | ||
112 | break; | ||
113 | case 3: | ||
114 | if (offset >= end) { | ||
115 | return; | ||
116 | } | ||
117 | adtsChanelConfig |= ((data[offset] & 0xC0) >>> 6); | ||
118 | adtsFrameSize = ((data[offset] & 0x03) << 11); | ||
119 | |||
120 | offset += 1; | ||
121 | state = 4; | ||
122 | break; | ||
123 | case 4: | ||
124 | if (offset >= end) { | ||
125 | return; | ||
126 | } | ||
127 | adtsFrameSize |= (data[offset] << 3); | ||
128 | |||
129 | offset += 1; | ||
130 | state = 5; | ||
131 | break; | ||
132 | case 5: | ||
133 | if(offset >= end) { | ||
134 | return; | ||
135 | } | ||
136 | adtsFrameSize |= ((data[offset] & 0xE0) >>> 5); | ||
137 | adtsFrameSize -= (adtsProtectionAbsent ? 7 : 9); | ||
138 | |||
139 | offset += 1; | ||
140 | state = 6; | ||
141 | break; | ||
142 | case 6: | ||
143 | if (offset >= end) { | ||
144 | return; | ||
145 | } | ||
146 | adtsSampleCount = ((data[offset] & 0x03) + 1) * 1024; | ||
147 | adtsDuration = (adtsSampleCount * 1000) / adtsSampleingRates[adtsSampleingIndex]; | ||
148 | |||
149 | newExtraData = (adtsObjectType << 11) | | ||
150 | (adtsSampleingIndex << 7) | | ||
151 | (adtsChanelConfig << 3); | ||
152 | |||
153 | // write out metadata tags every 1 second so that the decoder | ||
154 | // is re-initialized quickly after seeking into a different | ||
155 | // audio configuration | ||
156 | if (newExtraData !== extraData || next_pts - lastMetaPts >= 1000) { | ||
157 | aacFrame = new FlvTag(FlvTag.METADATA_TAG); | ||
158 | aacFrame.pts = next_pts; | ||
159 | aacFrame.dts = next_pts; | ||
160 | |||
161 | // AAC is always 10 | ||
162 | aacFrame.writeMetaDataDouble("audiocodecid", 10); | ||
163 | aacFrame.writeMetaDataBoolean("stereo", 2 === adtsChanelConfig); | ||
164 | aacFrame.writeMetaDataDouble ("audiosamplerate", adtsSampleingRates[adtsSampleingIndex]); | ||
165 | // Is AAC always 16 bit? | ||
166 | aacFrame.writeMetaDataDouble ("audiosamplesize", 16); | ||
167 | |||
168 | this.tags.push(aacFrame); | ||
169 | |||
170 | extraData = newExtraData; | ||
171 | aacFrame = new FlvTag(FlvTag.AUDIO_TAG, true); | ||
172 | // For audio, DTS is always the same as PTS. We want to set the DTS | ||
173 | // however so we can compare with video DTS to determine approximate | ||
174 | // packet order | ||
175 | aacFrame.pts = next_pts; | ||
176 | aacFrame.dts = aacFrame.pts; | ||
177 | |||
178 | aacFrame.view.setUint16(aacFrame.position, newExtraData); | ||
179 | aacFrame.position += 2; | ||
180 | aacFrame.length = Math.max(aacFrame.length, aacFrame.position); | ||
181 | |||
182 | this.tags.push(aacFrame); | ||
183 | |||
184 | lastMetaPts = next_pts; | ||
185 | } | ||
186 | |||
187 | // Skip the checksum if there is one | ||
188 | offset += 1; | ||
189 | state = 7; | ||
190 | break; | ||
191 | case 7: | ||
192 | if (!adtsProtectionAbsent) { | ||
193 | if (2 > (end - offset)) { | ||
194 | return; | ||
195 | } else { | ||
196 | offset += 2; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | aacFrame = new FlvTag(FlvTag.AUDIO_TAG); | ||
201 | aacFrame.pts = next_pts; | ||
202 | aacFrame.dts = next_pts; | ||
203 | state = 8; | ||
204 | break; | ||
205 | case 8: | ||
206 | while (adtsFrameSize) { | ||
207 | if (offset >= end) { | ||
208 | return; | ||
209 | } | ||
210 | bytesToCopy = (end - offset) < adtsFrameSize ? (end - offset) : adtsFrameSize; | ||
211 | aacFrame.writeBytes(data, offset, bytesToCopy); | ||
212 | offset += bytesToCopy; | ||
213 | adtsFrameSize -= bytesToCopy; | ||
214 | } | ||
215 | |||
216 | this.tags.push(aacFrame); | ||
217 | |||
218 | // finished with this frame | ||
219 | state = 0; | ||
220 | next_pts += adtsDuration; | ||
221 | } | ||
222 | } | ||
223 | }; | ||
224 | }; | ||
225 | |||
226 | })(this); |
src/exp-golomb.js
deleted
100644 → 0
1 | (function(window) { | ||
2 | |||
3 | /** | ||
4 | * Parser for exponential Golomb codes, a variable-bitwidth number encoding | ||
5 | * scheme used by h264. | ||
6 | */ | ||
7 | window.videojs.Hls.ExpGolomb = function(workingData) { | ||
8 | var | ||
9 | // the number of bytes left to examine in workingData | ||
10 | workingBytesAvailable = workingData.byteLength, | ||
11 | |||
12 | // the current word being examined | ||
13 | workingWord = 0, // :uint | ||
14 | |||
15 | // the number of bits left to examine in the current word | ||
16 | workingBitsAvailable = 0; // :uint; | ||
17 | |||
18 | // ():uint | ||
19 | this.length = function() { | ||
20 | return (8 * workingBytesAvailable); | ||
21 | }; | ||
22 | |||
23 | // ():uint | ||
24 | this.bitsAvailable = function() { | ||
25 | return (8 * workingBytesAvailable) + workingBitsAvailable; | ||
26 | }; | ||
27 | |||
28 | // ():void | ||
29 | this.loadWord = function() { | ||
30 | var | ||
31 | position = workingData.byteLength - workingBytesAvailable, | ||
32 | workingBytes = new Uint8Array(4), | ||
33 | availableBytes = Math.min(4, workingBytesAvailable); | ||
34 | |||
35 | if (availableBytes === 0) { | ||
36 | throw new Error('no bytes available'); | ||
37 | } | ||
38 | |||
39 | workingBytes.set(workingData.subarray(position, | ||
40 | position + availableBytes)); | ||
41 | workingWord = new DataView(workingBytes.buffer).getUint32(0); | ||
42 | |||
43 | // track the amount of workingData that has been processed | ||
44 | workingBitsAvailable = availableBytes * 8; | ||
45 | workingBytesAvailable -= availableBytes; | ||
46 | }; | ||
47 | |||
48 | // (count:int):void | ||
49 | this.skipBits = function(count) { | ||
50 | var skipBytes; // :int | ||
51 | if (workingBitsAvailable > count) { | ||
52 | workingWord <<= count; | ||
53 | workingBitsAvailable -= count; | ||
54 | } else { | ||
55 | count -= workingBitsAvailable; | ||
56 | skipBytes = count / 8; | ||
57 | |||
58 | count -= (skipBytes * 8); | ||
59 | workingBytesAvailable -= skipBytes; | ||
60 | |||
61 | this.loadWord(); | ||
62 | |||
63 | workingWord <<= count; | ||
64 | workingBitsAvailable -= count; | ||
65 | } | ||
66 | }; | ||
67 | |||
68 | // (size:int):uint | ||
69 | this.readBits = function(size) { | ||
70 | var | ||
71 | bits = Math.min(workingBitsAvailable, size), // :uint | ||
72 | valu = workingWord >>> (32 - bits); // :uint | ||
73 | |||
74 | console.assert(size < 32, 'Cannot read more than 32 bits at a time'); | ||
75 | |||
76 | workingBitsAvailable -= bits; | ||
77 | if (workingBitsAvailable > 0) { | ||
78 | workingWord <<= bits; | ||
79 | } else if (workingBytesAvailable > 0) { | ||
80 | this.loadWord(); | ||
81 | } | ||
82 | |||
83 | bits = size - bits; | ||
84 | if (bits > 0) { | ||
85 | return valu << bits | this.readBits(bits); | ||
86 | } else { | ||
87 | return valu; | ||
88 | } | ||
89 | }; | ||
90 | |||
91 | // ():uint | ||
92 | this.skipLeadingZeros = function() { | ||
93 | var leadingZeroCount; // :uint | ||
94 | for (leadingZeroCount = 0 ; leadingZeroCount < workingBitsAvailable ; ++leadingZeroCount) { | ||
95 | if (0 !== (workingWord & (0x80000000 >>> leadingZeroCount))) { | ||
96 | // the first bit of working word is 1 | ||
97 | workingWord <<= leadingZeroCount; | ||
98 | workingBitsAvailable -= leadingZeroCount; | ||
99 | return leadingZeroCount; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | // we exhausted workingWord and still have not found a 1 | ||
104 | this.loadWord(); | ||
105 | return leadingZeroCount + this.skipLeadingZeros(); | ||
106 | }; | ||
107 | |||
108 | // ():void | ||
109 | this.skipUnsignedExpGolomb = function() { | ||
110 | this.skipBits(1 + this.skipLeadingZeros()); | ||
111 | }; | ||
112 | |||
113 | // ():void | ||
114 | this.skipExpGolomb = function() { | ||
115 | this.skipBits(1 + this.skipLeadingZeros()); | ||
116 | }; | ||
117 | |||
118 | // ():uint | ||
119 | this.readUnsignedExpGolomb = function() { | ||
120 | var clz = this.skipLeadingZeros(); // :uint | ||
121 | return this.readBits(clz + 1) - 1; | ||
122 | }; | ||
123 | |||
124 | // ():int | ||
125 | this.readExpGolomb = function() { | ||
126 | var valu = this.readUnsignedExpGolomb(); // :int | ||
127 | if (0x01 & valu) { | ||
128 | // the number is odd if the low order bit is set | ||
129 | return (1 + valu) >>> 1; // add 1 to make it even, and divide by 2 | ||
130 | } else { | ||
131 | return -1 * (valu >>> 1); // divide by two then make it negative | ||
132 | } | ||
133 | }; | ||
134 | |||
135 | // Some convenience functions | ||
136 | // :Boolean | ||
137 | this.readBoolean = function() { | ||
138 | return 1 === this.readBits(1); | ||
139 | }; | ||
140 | |||
141 | // ():int | ||
142 | this.readUnsignedByte = function() { | ||
143 | return this.readBits(8); | ||
144 | }; | ||
145 | |||
146 | this.loadWord(); | ||
147 | |||
148 | }; | ||
149 | })(this); |
src/flv-tag.js
deleted
100644 → 0
This diff is collapsed.
Click to expand it.
src/h264-extradata.js
deleted
100644 → 0
1 | (function() { | ||
2 | var | ||
3 | H264ExtraData, | ||
4 | ExpGolomb = window.videojs.Hls.ExpGolomb, | ||
5 | FlvTag = window.videojs.Hls.FlvTag; | ||
6 | |||
7 | window.videojs.Hls.H264ExtraData = H264ExtraData = function() { | ||
8 | this.sps = []; // :Array | ||
9 | this.pps = []; // :Array | ||
10 | }; | ||
11 | |||
12 | H264ExtraData.prototype.extraDataExists = function() { // :Boolean | ||
13 | return this.sps.length > 0; | ||
14 | }; | ||
15 | |||
16 | // (sizeOfScalingList:int, expGolomb:ExpGolomb):void | ||
17 | H264ExtraData.prototype.scaling_list = function(sizeOfScalingList, expGolomb) { | ||
18 | var | ||
19 | lastScale = 8, // :int | ||
20 | nextScale = 8, // :int | ||
21 | j, | ||
22 | delta_scale; // :int | ||
23 | |||
24 | for (j = 0; j < sizeOfScalingList; ++j) { | ||
25 | if (0 !== nextScale) { | ||
26 | delta_scale = expGolomb.readExpGolomb(); | ||
27 | nextScale = (lastScale + delta_scale + 256) % 256; | ||
28 | //useDefaultScalingMatrixFlag = ( j = = 0 && nextScale = = 0 ) | ||
29 | } | ||
30 | |||
31 | lastScale = (nextScale === 0) ? lastScale : nextScale; | ||
32 | // scalingList[ j ] = ( nextScale == 0 ) ? lastScale : nextScale; | ||
33 | // lastScale = scalingList[ j ] | ||
34 | } | ||
35 | }; | ||
36 | |||
37 | /** | ||
38 | * RBSP: raw bit-stream payload. The actual encoded video data. | ||
39 | * | ||
40 | * SPS: sequence parameter set. Part of the RBSP. Metadata to be applied | ||
41 | * to a complete video sequence, like width and height. | ||
42 | */ | ||
43 | H264ExtraData.prototype.getSps0Rbsp = function() { // :ByteArray | ||
44 | var | ||
45 | sps = this.sps[0], | ||
46 | offset = 1, | ||
47 | start = 1, | ||
48 | written = 0, | ||
49 | end = sps.byteLength - 2, | ||
50 | result = new Uint8Array(sps.byteLength); | ||
51 | |||
52 | // In order to prevent 0x0000 01 from being interpreted as a | ||
53 | // NAL start code, occurences of that byte sequence in the | ||
54 | // RBSP are escaped with an "emulation byte". That turns | ||
55 | // sequences of 0x0000 01 into 0x0000 0301. When interpreting | ||
56 | // a NAL payload, they must be filtered back out. | ||
57 | while (offset < end) { | ||
58 | if (sps[offset] === 0x00 && | ||
59 | sps[offset + 1] === 0x00 && | ||
60 | sps[offset + 2] === 0x03) { | ||
61 | result.set(sps.subarray(start, offset + 1), written); | ||
62 | written += offset + 1 - start; | ||
63 | start = offset + 3; | ||
64 | } | ||
65 | offset++; | ||
66 | } | ||
67 | result.set(sps.subarray(start), written); | ||
68 | return result.subarray(0, written + (sps.byteLength - start)); | ||
69 | }; | ||
70 | |||
71 | // (pts:uint):FlvTag | ||
72 | H264ExtraData.prototype.metaDataTag = function(pts) { | ||
73 | var | ||
74 | tag = new FlvTag(FlvTag.METADATA_TAG), // :FlvTag | ||
75 | expGolomb, // :ExpGolomb | ||
76 | profile_idc, // :int | ||
77 | chroma_format_idc, // :int | ||
78 | imax, // :int | ||
79 | i, // :int | ||
80 | |||
81 | pic_order_cnt_type, // :int | ||
82 | num_ref_frames_in_pic_order_cnt_cycle, // :uint | ||
83 | |||
84 | pic_width_in_mbs_minus1, // :int | ||
85 | pic_height_in_map_units_minus1, // :int | ||
86 | |||
87 | frame_mbs_only_flag, // :int | ||
88 | frame_cropping_flag, // :Boolean | ||
89 | |||
90 | frame_crop_left_offset = 0, // :int | ||
91 | frame_crop_right_offset = 0, // :int | ||
92 | frame_crop_top_offset = 0, // :int | ||
93 | frame_crop_bottom_offset = 0, // :int | ||
94 | |||
95 | width, | ||
96 | height; | ||
97 | |||
98 | tag.dts = pts; | ||
99 | tag.pts = pts; | ||
100 | expGolomb = new ExpGolomb(this.getSps0Rbsp()); | ||
101 | |||
102 | // :int = expGolomb.readUnsignedByte(); // profile_idc u(8) | ||
103 | profile_idc = expGolomb.readUnsignedByte(); | ||
104 | |||
105 | // constraint_set[0-5]_flag, u(1), reserved_zero_2bits u(2), level_idc u(8) | ||
106 | expGolomb.skipBits(16); | ||
107 | |||
108 | // seq_parameter_set_id | ||
109 | expGolomb.skipUnsignedExpGolomb(); | ||
110 | |||
111 | if (profile_idc === 100 || | ||
112 | profile_idc === 110 || | ||
113 | profile_idc === 122 || | ||
114 | profile_idc === 244 || | ||
115 | profile_idc === 44 || | ||
116 | profile_idc === 83 || | ||
117 | profile_idc === 86 || | ||
118 | profile_idc === 118 || | ||
119 | profile_idc === 128) { | ||
120 | chroma_format_idc = expGolomb.readUnsignedExpGolomb(); | ||
121 | if (3 === chroma_format_idc) { | ||
122 | expGolomb.skipBits(1); // separate_colour_plane_flag | ||
123 | } | ||
124 | expGolomb.skipUnsignedExpGolomb(); // bit_depth_luma_minus8 | ||
125 | expGolomb.skipUnsignedExpGolomb(); // bit_depth_chroma_minus8 | ||
126 | expGolomb.skipBits(1); // qpprime_y_zero_transform_bypass_flag | ||
127 | if (expGolomb.readBoolean()) { // seq_scaling_matrix_present_flag | ||
128 | imax = (chroma_format_idc !== 3) ? 8 : 12; | ||
129 | for (i = 0 ; i < imax ; ++i) { | ||
130 | if (expGolomb.readBoolean()) { // seq_scaling_list_present_flag[ i ] | ||
131 | if (i < 6) { | ||
132 | this.scaling_list(16, expGolomb); | ||
133 | } else { | ||
134 | this.scaling_list(64, expGolomb); | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | |||
141 | expGolomb.skipUnsignedExpGolomb(); // log2_max_frame_num_minus4 | ||
142 | pic_order_cnt_type = expGolomb.readUnsignedExpGolomb(); | ||
143 | |||
144 | if ( 0 === pic_order_cnt_type ) { | ||
145 | expGolomb.readUnsignedExpGolomb(); //log2_max_pic_order_cnt_lsb_minus4 | ||
146 | } else if ( 1 === pic_order_cnt_type ) { | ||
147 | expGolomb.skipBits(1); // delta_pic_order_always_zero_flag | ||
148 | expGolomb.skipExpGolomb(); // offset_for_non_ref_pic | ||
149 | expGolomb.skipExpGolomb(); // offset_for_top_to_bottom_field | ||
150 | num_ref_frames_in_pic_order_cnt_cycle = expGolomb.readUnsignedExpGolomb(); | ||
151 | for(i = 0 ; i < num_ref_frames_in_pic_order_cnt_cycle ; ++i) { | ||
152 | expGolomb.skipExpGolomb(); // offset_for_ref_frame[ i ] | ||
153 | } | ||
154 | } | ||
155 | |||
156 | expGolomb.skipUnsignedExpGolomb(); // max_num_ref_frames | ||
157 | expGolomb.skipBits(1); // gaps_in_frame_num_value_allowed_flag | ||
158 | pic_width_in_mbs_minus1 = expGolomb.readUnsignedExpGolomb(); | ||
159 | pic_height_in_map_units_minus1 = expGolomb.readUnsignedExpGolomb(); | ||
160 | |||
161 | frame_mbs_only_flag = expGolomb.readBits(1); | ||
162 | if (0 === frame_mbs_only_flag) { | ||
163 | expGolomb.skipBits(1); // mb_adaptive_frame_field_flag | ||
164 | } | ||
165 | |||
166 | expGolomb.skipBits(1); // direct_8x8_inference_flag | ||
167 | frame_cropping_flag = expGolomb.readBoolean(); | ||
168 | if (frame_cropping_flag) { | ||
169 | frame_crop_left_offset = expGolomb.readUnsignedExpGolomb(); | ||
170 | frame_crop_right_offset = expGolomb.readUnsignedExpGolomb(); | ||
171 | frame_crop_top_offset = expGolomb.readUnsignedExpGolomb(); | ||
172 | frame_crop_bottom_offset = expGolomb.readUnsignedExpGolomb(); | ||
173 | } | ||
174 | |||
175 | width = ((pic_width_in_mbs_minus1 + 1) * 16) - frame_crop_left_offset * 2 - frame_crop_right_offset * 2; | ||
176 | height = ((2 - frame_mbs_only_flag) * (pic_height_in_map_units_minus1 + 1) * 16) - (frame_crop_top_offset * 2) - (frame_crop_bottom_offset * 2); | ||
177 | |||
178 | tag.writeMetaDataDouble("videocodecid", 7); | ||
179 | tag.writeMetaDataDouble("width", width); | ||
180 | tag.writeMetaDataDouble("height", height); | ||
181 | // tag.writeMetaDataDouble("videodatarate", 0 ); | ||
182 | // tag.writeMetaDataDouble("framerate", 0); | ||
183 | |||
184 | return tag; | ||
185 | }; | ||
186 | |||
187 | // (pts:uint):FlvTag | ||
188 | H264ExtraData.prototype.extraDataTag = function(pts) { | ||
189 | var | ||
190 | i, | ||
191 | tag = new FlvTag(FlvTag.VIDEO_TAG, true); | ||
192 | |||
193 | tag.dts = pts; | ||
194 | tag.pts = pts; | ||
195 | |||
196 | tag.writeByte(0x01);// version | ||
197 | tag.writeByte(this.sps[0][1]);// profile | ||
198 | tag.writeByte(this.sps[0][2]);// compatibility | ||
199 | tag.writeByte(this.sps[0][3]);// level | ||
200 | tag.writeByte(0xFC | 0x03); // reserved (6 bits), NULA length size - 1 (2 bits) | ||
201 | tag.writeByte(0xE0 | 0x01 ); // reserved (3 bits), num of SPS (5 bits) | ||
202 | tag.writeShort( this.sps[0].length ); // data of SPS | ||
203 | tag.writeBytes( this.sps[0] ); // SPS | ||
204 | |||
205 | tag.writeByte( this.pps.length ); // num of PPS (will there ever be more that 1 PPS?) | ||
206 | for (i = 0 ; i < this.pps.length ; ++i) { | ||
207 | tag.writeShort(this.pps[i].length); // 2 bytes for length of PPS | ||
208 | tag.writeBytes(this.pps[i]); // data of PPS | ||
209 | } | ||
210 | |||
211 | return tag; | ||
212 | }; | ||
213 | })(); |
src/h264-stream.js
deleted
100644 → 0
1 | (function(window) { | ||
2 | var | ||
3 | FlvTag = window.videojs.Hls.FlvTag, | ||
4 | H264ExtraData = window.videojs.Hls.H264ExtraData, | ||
5 | H264Stream, | ||
6 | NALUnitType; | ||
7 | |||
8 | /** | ||
9 | * Network Abstraction Layer (NAL) units are the packets of an H264 | ||
10 | * stream. NAL units are divided into types based on their payload | ||
11 | * data. Each type has a unique numeric identifier. | ||
12 | * | ||
13 | * NAL unit | ||
14 | * |- NAL header -|------ RBSP ------| | ||
15 | * | ||
16 | * NAL unit: Network abstraction layer unit. The combination of a NAL | ||
17 | * header and an RBSP. | ||
18 | * NAL header: the encapsulation unit for transport-specific metadata in | ||
19 | * an h264 stream. Exactly one byte. | ||
20 | */ | ||
21 | // incomplete, see Table 7.1 of ITU-T H.264 for 12-32 | ||
22 | window.videojs.Hls.NALUnitType = NALUnitType = { | ||
23 | unspecified: 0, | ||
24 | slice_layer_without_partitioning_rbsp_non_idr: 1, | ||
25 | slice_data_partition_a_layer_rbsp: 2, | ||
26 | slice_data_partition_b_layer_rbsp: 3, | ||
27 | slice_data_partition_c_layer_rbsp: 4, | ||
28 | slice_layer_without_partitioning_rbsp_idr: 5, | ||
29 | sei_rbsp: 6, | ||
30 | seq_parameter_set_rbsp: 7, | ||
31 | pic_parameter_set_rbsp: 8, | ||
32 | access_unit_delimiter_rbsp: 9, | ||
33 | end_of_seq_rbsp: 10, | ||
34 | end_of_stream_rbsp: 11 | ||
35 | }; | ||
36 | |||
37 | window.videojs.Hls.H264Stream = H264Stream = function() { | ||
38 | this._next_pts = 0; // :uint; | ||
39 | this._next_dts = 0; // :uint; | ||
40 | |||
41 | this._h264Frame = null; // :FlvTag | ||
42 | |||
43 | this._oldExtraData = new H264ExtraData(); // :H264ExtraData | ||
44 | this._newExtraData = new H264ExtraData(); // :H264ExtraData | ||
45 | |||
46 | this._nalUnitType = -1; // :int | ||
47 | |||
48 | this._state = 0; // :uint; | ||
49 | |||
50 | this.tags = []; | ||
51 | }; | ||
52 | |||
53 | //(pts:uint):void | ||
54 | H264Stream.prototype.setTimeStampOffset = function() {}; | ||
55 | |||
56 | //(pts:uint, dts:uint, dataAligned:Boolean):void | ||
57 | H264Stream.prototype.setNextTimeStamp = function(pts, dts, dataAligned) { | ||
58 | // We could end up with a DTS less than 0 here. We need to deal with that! | ||
59 | this._next_pts = pts; | ||
60 | this._next_dts = dts; | ||
61 | |||
62 | // If data is aligned, flush all internal buffers | ||
63 | if (dataAligned) { | ||
64 | this.finishFrame(); | ||
65 | } | ||
66 | }; | ||
67 | |||
68 | H264Stream.prototype.finishFrame = function() { | ||
69 | if (this._h264Frame) { | ||
70 | // Push SPS before EVERY IDR frame for seeking | ||
71 | if (this._newExtraData.extraDataExists()) { | ||
72 | this._oldExtraData = this._newExtraData; | ||
73 | this._newExtraData = new H264ExtraData(); | ||
74 | } | ||
75 | |||
76 | // Check if keyframe and the length of tags. | ||
77 | // This makes sure we write metadata on the first frame of a segment. | ||
78 | if (this._oldExtraData.extraDataExists() && | ||
79 | (this._h264Frame.keyFrame || this.tags.length === 0)) { | ||
80 | // Push extra data on every IDR frame in case we did a stream change + seek | ||
81 | this.tags.push(this._oldExtraData.metaDataTag(this._h264Frame.pts)); | ||
82 | this.tags.push(this._oldExtraData.extraDataTag(this._h264Frame.pts)); | ||
83 | } | ||
84 | |||
85 | this._h264Frame.endNalUnit(); | ||
86 | this.tags.push(this._h264Frame); | ||
87 | |||
88 | } | ||
89 | |||
90 | this._h264Frame = null; | ||
91 | this._nalUnitType = -1; | ||
92 | this._state = 0; | ||
93 | }; | ||
94 | |||
95 | // (data:ByteArray, o:int, l:int):void | ||
96 | H264Stream.prototype.writeBytes = function(data, offset, length) { | ||
97 | var | ||
98 | nalUnitSize, // :uint | ||
99 | start, // :uint | ||
100 | end, // :uint | ||
101 | t; // :int | ||
102 | |||
103 | // default argument values | ||
104 | offset = offset || 0; | ||
105 | length = length || 0; | ||
106 | |||
107 | if (length <= 0) { | ||
108 | // data is empty so there's nothing to write | ||
109 | return; | ||
110 | } | ||
111 | |||
112 | // scan through the bytes until we find the start code (0x000001) for a | ||
113 | // NAL unit and then begin writing it out | ||
114 | // strip NAL start codes as we go | ||
115 | switch (this._state) { | ||
116 | default: | ||
117 | /* falls through */ | ||
118 | case 0: | ||
119 | this._state = 1; | ||
120 | /* falls through */ | ||
121 | case 1: | ||
122 | // A NAL unit may be split across two TS packets. Look back a bit to | ||
123 | // make sure the prefix of the start code wasn't already written out. | ||
124 | if (data[offset] <= 1) { | ||
125 | nalUnitSize = this._h264Frame ? this._h264Frame.nalUnitSize() : 0; | ||
126 | if (nalUnitSize >= 1 && this._h264Frame.negIndex(1) === 0) { | ||
127 | // ?? ?? 00 | O[01] ?? ?? | ||
128 | if (data[offset] === 1 && | ||
129 | nalUnitSize >= 2 && | ||
130 | this._h264Frame.negIndex(2) === 0) { | ||
131 | // ?? 00 00 : 01 | ||
132 | if (3 <= nalUnitSize && 0 === this._h264Frame.negIndex(3)) { | ||
133 | this._h264Frame.length -= 3; // 00 00 00 : 01 | ||
134 | } else { | ||
135 | this._h264Frame.length -= 2; // 00 00 : 01 | ||
136 | } | ||
137 | |||
138 | this._state = 3; | ||
139 | return this.writeBytes(data, offset + 1, length - 1); | ||
140 | } | ||
141 | |||
142 | if (length > 1 && data[offset] === 0 && data[offset + 1] === 1) { | ||
143 | // ?? 00 | 00 01 | ||
144 | if (nalUnitSize >= 2 && this._h264Frame.negIndex(2) === 0) { | ||
145 | this._h264Frame.length -= 2; // 00 00 : 00 01 | ||
146 | } else { | ||
147 | this._h264Frame.length -= 1; // 00 : 00 01 | ||
148 | } | ||
149 | |||
150 | this._state = 3; | ||
151 | return this.writeBytes(data, offset + 2, length - 2); | ||
152 | } | ||
153 | |||
154 | if (length > 2 && | ||
155 | data[offset] === 0 && | ||
156 | data[offset + 1] === 0 && | ||
157 | data[offset + 2] === 1) { | ||
158 | // 00 : 00 00 01 | ||
159 | // this._h264Frame.length -= 1; | ||
160 | this._state = 3; | ||
161 | return this.writeBytes(data, offset + 3, length - 3); | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | // allow fall through if the above fails, we may end up checking a few | ||
166 | // bytes a second time. But that case will be VERY rare | ||
167 | this._state = 2; | ||
168 | /* falls through */ | ||
169 | case 2: | ||
170 | // Look for start codes in the data from the current offset forward | ||
171 | start = offset; | ||
172 | end = start + length; | ||
173 | for (t = end - 3; offset < t;) { | ||
174 | if (data[offset + 2] > 1) { | ||
175 | // if data[offset + 2] is greater than 1, there is no way a start | ||
176 | // code can begin before offset + 3 | ||
177 | offset += 3; | ||
178 | } else if (data[offset + 1] !== 0) { | ||
179 | offset += 2; | ||
180 | } else if (data[offset] !== 0) { | ||
181 | offset += 1; | ||
182 | } else { | ||
183 | // If we get here we have 00 00 00 or 00 00 01 | ||
184 | if (data[offset + 2] === 1) { | ||
185 | if (offset > start) { | ||
186 | this._h264Frame.writeBytes(data, start, offset - start); | ||
187 | } | ||
188 | this._state = 3; | ||
189 | offset += 3; | ||
190 | return this.writeBytes(data, offset, end - offset); | ||
191 | } | ||
192 | |||
193 | if (end - offset >= 4 && | ||
194 | data[offset + 2] === 0 && | ||
195 | data[offset + 3] === 1) { | ||
196 | if (offset > start) { | ||
197 | this._h264Frame.writeBytes(data, start, offset - start); | ||
198 | } | ||
199 | this._state = 3; | ||
200 | offset += 4; | ||
201 | return this.writeBytes(data, offset, end - offset); | ||
202 | } | ||
203 | |||
204 | // We are at the end of the buffer, or we have 3 NULLS followed by | ||
205 | // something that is not a 1, either way we can step forward by at | ||
206 | // least 3 | ||
207 | offset += 3; | ||
208 | } | ||
209 | } | ||
210 | |||
211 | // We did not find any start codes. Try again next packet | ||
212 | this._state = 1; | ||
213 | if (this._h264Frame) { | ||
214 | this._h264Frame.writeBytes(data, start, length); | ||
215 | } | ||
216 | return; | ||
217 | case 3: | ||
218 | // The next byte is the first byte of a NAL Unit | ||
219 | |||
220 | if (this._h264Frame) { | ||
221 | // we've come to a new NAL unit so finish up the one we've been | ||
222 | // working on | ||
223 | |||
224 | switch (this._nalUnitType) { | ||
225 | case NALUnitType.seq_parameter_set_rbsp: | ||
226 | this._h264Frame.endNalUnit(this._newExtraData.sps); | ||
227 | break; | ||
228 | case NALUnitType.pic_parameter_set_rbsp: | ||
229 | this._h264Frame.endNalUnit(this._newExtraData.pps); | ||
230 | break; | ||
231 | case NALUnitType.slice_layer_without_partitioning_rbsp_idr: | ||
232 | this._h264Frame.endNalUnit(); | ||
233 | break; | ||
234 | default: | ||
235 | this._h264Frame.endNalUnit(); | ||
236 | break; | ||
237 | } | ||
238 | } | ||
239 | |||
240 | // setup to begin processing the new NAL unit | ||
241 | this._nalUnitType = data[offset] & 0x1F; | ||
242 | if (this._h264Frame) { | ||
243 | if (this._nalUnitType === NALUnitType.access_unit_delimiter_rbsp) { | ||
244 | // starting a new access unit, flush the previous one | ||
245 | this.finishFrame(); | ||
246 | } else if (this._nalUnitType === NALUnitType.slice_layer_without_partitioning_rbsp_idr) { | ||
247 | this._h264Frame.keyFrame = true; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | // finishFrame may render this._h264Frame null, so we must test again | ||
252 | if (!this._h264Frame) { | ||
253 | this._h264Frame = new FlvTag(FlvTag.VIDEO_TAG); | ||
254 | this._h264Frame.pts = this._next_pts; | ||
255 | this._h264Frame.dts = this._next_dts; | ||
256 | } | ||
257 | |||
258 | this._h264Frame.startNalUnit(); | ||
259 | // We know there will not be an overlapping start code, so we can skip | ||
260 | // that test | ||
261 | this._state = 2; | ||
262 | return this.writeBytes(data, offset, length); | ||
263 | } // switch | ||
264 | }; | ||
265 | })(this); |
src/metadata-stream.js
deleted
100644 → 0
1 | /** | ||
2 | * Accepts program elementary stream (PES) data events and parses out | ||
3 | * ID3 metadata from them, if present. | ||
4 | * @see http://id3.org/id3v2.3.0 | ||
5 | */ | ||
6 | (function(window, videojs, undefined) { | ||
7 | 'use strict'; | ||
8 | var | ||
9 | // return a percent-encoded representation of the specified byte range | ||
10 | // @see http://en.wikipedia.org/wiki/Percent-encoding | ||
11 | percentEncode = function(bytes, start, end) { | ||
12 | var i, result = ''; | ||
13 | for (i = start; i < end; i++) { | ||
14 | result += '%' + ('00' + bytes[i].toString(16)).slice(-2); | ||
15 | } | ||
16 | return result; | ||
17 | }, | ||
18 | // return the string representation of the specified byte range, | ||
19 | // interpreted as UTf-8. | ||
20 | parseUtf8 = function(bytes, start, end) { | ||
21 | return window.decodeURIComponent(percentEncode(bytes, start, end)); | ||
22 | }, | ||
23 | // return the string representation of the specified byte range, | ||
24 | // interpreted as ISO-8859-1. | ||
25 | parseIso88591 = function(bytes, start, end) { | ||
26 | return window.unescape(percentEncode(bytes, start, end)); | ||
27 | }, | ||
28 | tagParsers = { | ||
29 | 'TXXX': function(tag) { | ||
30 | var i; | ||
31 | if (tag.data[0] !== 3) { | ||
32 | // ignore frames with unrecognized character encodings | ||
33 | return; | ||
34 | } | ||
35 | |||
36 | for (i = 1; i < tag.data.length; i++) { | ||
37 | if (tag.data[i] === 0) { | ||
38 | // parse the text fields | ||
39 | tag.description = parseUtf8(tag.data, 1, i); | ||
40 | // do not include the null terminator in the tag value | ||
41 | tag.value = parseUtf8(tag.data, i + 1, tag.data.length - 1); | ||
42 | break; | ||
43 | } | ||
44 | } | ||
45 | }, | ||
46 | 'WXXX': function(tag) { | ||
47 | var i; | ||
48 | if (tag.data[0] !== 3) { | ||
49 | // ignore frames with unrecognized character encodings | ||
50 | return; | ||
51 | } | ||
52 | |||
53 | for (i = 1; i < tag.data.length; i++) { | ||
54 | if (tag.data[i] === 0) { | ||
55 | // parse the description and URL fields | ||
56 | tag.description = parseUtf8(tag.data, 1, i); | ||
57 | tag.url = parseUtf8(tag.data, i + 1, tag.data.length); | ||
58 | break; | ||
59 | } | ||
60 | } | ||
61 | }, | ||
62 | 'PRIV': function(tag) { | ||
63 | var i; | ||
64 | |||
65 | for (i = 0; i < tag.data.length; i++) { | ||
66 | if (tag.data[i] === 0) { | ||
67 | // parse the description and URL fields | ||
68 | tag.owner = parseIso88591(tag.data, 0, i); | ||
69 | break; | ||
70 | } | ||
71 | } | ||
72 | tag.privateData = tag.data.subarray(i + 1); | ||
73 | } | ||
74 | }, | ||
75 | MetadataStream; | ||
76 | |||
77 | MetadataStream = function(options) { | ||
78 | var | ||
79 | settings = { | ||
80 | debug: !!(options && options.debug), | ||
81 | |||
82 | // the bytes of the program-level descriptor field in MP2T | ||
83 | // see ISO/IEC 13818-1:2013 (E), section 2.6 "Program and | ||
84 | // program element descriptors" | ||
85 | descriptor: options && options.descriptor | ||
86 | }, | ||
87 | // the total size in bytes of the ID3 tag being parsed | ||
88 | tagSize = 0, | ||
89 | // tag data that is not complete enough to be parsed | ||
90 | buffer = [], | ||
91 | // the total number of bytes currently in the buffer | ||
92 | bufferSize = 0, | ||
93 | i; | ||
94 | |||
95 | MetadataStream.prototype.init.call(this); | ||
96 | |||
97 | // calculate the text track in-band metadata track dispatch type | ||
98 | // https://html.spec.whatwg.org/multipage/embedded-content.html#steps-to-expose-a-media-resource-specific-text-track | ||
99 | this.dispatchType = videojs.Hls.SegmentParser.STREAM_TYPES.metadata.toString(16); | ||
100 | if (settings.descriptor) { | ||
101 | for (i = 0; i < settings.descriptor.length; i++) { | ||
102 | this.dispatchType += ('00' + settings.descriptor[i].toString(16)).slice(-2); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | this.push = function(chunk) { | ||
107 | var tag, frameStart, frameSize, frame, i; | ||
108 | |||
109 | // ignore events that don't look like ID3 data | ||
110 | if (buffer.length === 0 && | ||
111 | (chunk.data.length < 10 || | ||
112 | chunk.data[0] !== 'I'.charCodeAt(0) || | ||
113 | chunk.data[1] !== 'D'.charCodeAt(0) || | ||
114 | chunk.data[2] !== '3'.charCodeAt(0))) { | ||
115 | if (settings.debug) { | ||
116 | videojs.log('Skipping unrecognized metadata packet'); | ||
117 | } | ||
118 | return; | ||
119 | } | ||
120 | |||
121 | // add this chunk to the data we've collected so far | ||
122 | buffer.push(chunk); | ||
123 | bufferSize += chunk.data.byteLength; | ||
124 | |||
125 | // grab the size of the entire frame from the ID3 header | ||
126 | if (buffer.length === 1) { | ||
127 | // the frame size is transmitted as a 28-bit integer in the | ||
128 | // last four bytes of the ID3 header. | ||
129 | // The most significant bit of each byte is dropped and the | ||
130 | // results concatenated to recover the actual value. | ||
131 | tagSize = (chunk.data[6] << 21) | | ||
132 | (chunk.data[7] << 14) | | ||
133 | (chunk.data[8] << 7) | | ||
134 | (chunk.data[9]); | ||
135 | |||
136 | // ID3 reports the tag size excluding the header but it's more | ||
137 | // convenient for our comparisons to include it | ||
138 | tagSize += 10; | ||
139 | } | ||
140 | |||
141 | // if the entire frame has not arrived, wait for more data | ||
142 | if (bufferSize < tagSize) { | ||
143 | return; | ||
144 | } | ||
145 | |||
146 | // collect the entire frame so it can be parsed | ||
147 | tag = { | ||
148 | data: new Uint8Array(tagSize), | ||
149 | frames: [], | ||
150 | pts: buffer[0].pts, | ||
151 | dts: buffer[0].dts | ||
152 | }; | ||
153 | for (i = 0; i < tagSize;) { | ||
154 | tag.data.set(buffer[0].data, i); | ||
155 | i += buffer[0].data.byteLength; | ||
156 | bufferSize -= buffer[0].data.byteLength; | ||
157 | buffer.shift(); | ||
158 | } | ||
159 | |||
160 | // find the start of the first frame and the end of the tag | ||
161 | frameStart = 10; | ||
162 | if (tag.data[5] & 0x40) { | ||
163 | // advance the frame start past the extended header | ||
164 | frameStart += 4; // header size field | ||
165 | frameStart += (tag.data[10] << 24) | | ||
166 | (tag.data[11] << 16) | | ||
167 | (tag.data[12] << 8) | | ||
168 | (tag.data[13]); | ||
169 | |||
170 | // clip any padding off the end | ||
171 | tagSize -= (tag.data[16] << 24) | | ||
172 | (tag.data[17] << 16) | | ||
173 | (tag.data[18] << 8) | | ||
174 | (tag.data[19]); | ||
175 | } | ||
176 | |||
177 | // parse one or more ID3 frames | ||
178 | // http://id3.org/id3v2.3.0#ID3v2_frame_overview | ||
179 | do { | ||
180 | // determine the number of bytes in this frame | ||
181 | frameSize = (tag.data[frameStart + 4] << 24) | | ||
182 | (tag.data[frameStart + 5] << 16) | | ||
183 | (tag.data[frameStart + 6] << 8) | | ||
184 | (tag.data[frameStart + 7]); | ||
185 | if (frameSize < 1) { | ||
186 | return videojs.log('Malformed ID3 frame encountered. Skipping metadata parsing.'); | ||
187 | } | ||
188 | |||
189 | frame = { | ||
190 | id: String.fromCharCode(tag.data[frameStart], | ||
191 | tag.data[frameStart + 1], | ||
192 | tag.data[frameStart + 2], | ||
193 | tag.data[frameStart + 3]), | ||
194 | data: tag.data.subarray(frameStart + 10, frameStart + frameSize + 10) | ||
195 | }; | ||
196 | if (tagParsers[frame.id]) { | ||
197 | tagParsers[frame.id](frame); | ||
198 | } | ||
199 | tag.frames.push(frame); | ||
200 | |||
201 | frameStart += 10; // advance past the frame header | ||
202 | frameStart += frameSize; // advance past the frame body | ||
203 | } while (frameStart < tagSize); | ||
204 | this.trigger('data', tag); | ||
205 | }; | ||
206 | }; | ||
207 | MetadataStream.prototype = new videojs.Hls.Stream(); | ||
208 | |||
209 | videojs.Hls.MetadataStream = MetadataStream; | ||
210 | })(window, window.videojs); |
src/mp4-generator.js
deleted
100644 → 0
This diff is collapsed.
Click to expand it.
src/segment-parser.js
deleted
100644 → 0
This diff is collapsed.
Click to expand it.
src/transmuxer.js
deleted
100644 → 0
This diff is collapsed.
Click to expand it.
test/exp-golomb_test.js
deleted
100644 → 0
1 | (function(window) { | ||
2 | /* | ||
3 | ======== A Handy Little QUnit Reference ======== | ||
4 | http://api.qunitjs.com/ | ||
5 | |||
6 | Test methods: | ||
7 | module(name, {[setup][ ,teardown]}) | ||
8 | test(name, callback) | ||
9 | expect(numberOfAssertions) | ||
10 | stop(increment) | ||
11 | start(decrement) | ||
12 | Test assertions: | ||
13 | ok(value, [message]) | ||
14 | equal(actual, expected, [message]) | ||
15 | notEqual(actual, expected, [message]) | ||
16 | deepEqual(actual, expected, [message]) | ||
17 | notDeepEqual(actual, expected, [message]) | ||
18 | strictEqual(actual, expected, [message]) | ||
19 | notStrictEqual(actual, expected, [message]) | ||
20 | throws(block, [expected], [message]) | ||
21 | */ | ||
22 | var | ||
23 | buffer, | ||
24 | ExpGolomb = window.videojs.Hls.ExpGolomb, | ||
25 | expGolomb; | ||
26 | |||
27 | module('Exponential Golomb coding'); | ||
28 | |||
29 | test('small numbers are coded correctly', function() { | ||
30 | var | ||
31 | expected = [ | ||
32 | [0xF8, 0], | ||
33 | [0x5F, 1], | ||
34 | [0x7F, 2], | ||
35 | [0x27, 3], | ||
36 | [0x2F, 4], | ||
37 | [0x37, 5], | ||
38 | [0x3F, 6], | ||
39 | [0x11, 7], | ||
40 | [0x13, 8], | ||
41 | [0x15, 9] | ||
42 | ], | ||
43 | i = expected.length, | ||
44 | result; | ||
45 | |||
46 | while (i--) { | ||
47 | buffer = new Uint8Array([expected[i][0]]); | ||
48 | expGolomb = new ExpGolomb(buffer); | ||
49 | result = expGolomb.readUnsignedExpGolomb(); | ||
50 | equal(expected[i][1], result, expected[i][0] + ' is decoded to ' + expected[i][1]); | ||
51 | } | ||
52 | }); | ||
53 | |||
54 | test('drops working data as it is parsed', function() { | ||
55 | var expGolomb = new ExpGolomb(new Uint8Array([0x00, 0xFF])); | ||
56 | expGolomb.skipBits(8); | ||
57 | equal(8, expGolomb.bitsAvailable(), '8 bits remain'); | ||
58 | equal(0xFF, expGolomb.readBits(8), 'the second byte is read'); | ||
59 | }); | ||
60 | |||
61 | test('drops working data when skipping leading zeros', function() { | ||
62 | var expGolomb = new ExpGolomb(new Uint8Array([0x00, 0x00, 0x00, 0x00, 0xFF])); | ||
63 | equal(32, expGolomb.skipLeadingZeros(), '32 leading zeros are dropped'); | ||
64 | equal(8, expGolomb.bitsAvailable(), '8 bits remain'); | ||
65 | equal(0xFF, expGolomb.readBits(8), 'the second byte is read'); | ||
66 | }); | ||
67 | |||
68 | test('drops working data when skipping leading zeros', function() { | ||
69 | var expGolomb = new ExpGolomb(new Uint8Array([0x15, 0xab, 0x40, 0xc8, 0xFF])); | ||
70 | equal(3, expGolomb.skipLeadingZeros(), '3 leading zeros are dropped'); | ||
71 | equal((8 * 4) + 5, expGolomb.bitsAvailable(), '37 bits remain'); | ||
72 | expGolomb.skipBits(1); | ||
73 | equal(0x5a, expGolomb.readBits(8), 'the next bits are read'); | ||
74 | }); | ||
75 | |||
76 | test('parses a sequence parameter set', function() { | ||
77 | var | ||
78 | sps = new Uint8Array([ | ||
79 | 0x27, 0x42, 0xe0, 0x0b, | ||
80 | 0xa9, 0x18, 0x60, 0x9d, | ||
81 | 0x80, 0x35, 0x06, 0x01, | ||
82 | 0x06, 0xb6, 0xc2, 0xb5, | ||
83 | 0xef, 0x7c, 0x04 | ||
84 | ]), | ||
85 | expGolomb = new ExpGolomb(sps); | ||
86 | |||
87 | strictEqual(expGolomb.readBits(8), 0x27, 'the NAL type specifies an SPS'); | ||
88 | strictEqual(expGolomb.readBits(8), 66, 'profile_idc is 66'); | ||
89 | strictEqual(expGolomb.readBits(4), 0x0E, 'constraints 0-3 are correct'); | ||
90 | |||
91 | expGolomb.skipBits(4); | ||
92 | strictEqual(expGolomb.readBits(8), 11, 'level_idc is 11'); | ||
93 | strictEqual(expGolomb.readUnsignedExpGolomb(), 0, 'seq_parameter_set_id is 0'); | ||
94 | strictEqual(expGolomb.readUnsignedExpGolomb(), 1, 'log2_max_frame_num_minus4 is 1'); | ||
95 | strictEqual(expGolomb.readUnsignedExpGolomb(), 0, 'pic_order_cnt_type is 0'); | ||
96 | strictEqual(expGolomb.readUnsignedExpGolomb(), 3, 'log2_max_pic_order_cnt_lsb_minus4 is 3'); | ||
97 | strictEqual(expGolomb.readUnsignedExpGolomb(), 2, 'max_num_ref_frames is 2'); | ||
98 | strictEqual(expGolomb.readBits(1), 0, 'gaps_in_frame_num_value_allowed_flag is false'); | ||
99 | strictEqual(expGolomb.readUnsignedExpGolomb(), 11, 'pic_width_in_mbs_minus1 is 11'); | ||
100 | strictEqual(expGolomb.readUnsignedExpGolomb(), 8, 'pic_height_in_map_units_minus1 is 8'); | ||
101 | strictEqual(expGolomb.readBits(1), 1, 'frame_mbs_only_flag is true'); | ||
102 | strictEqual(expGolomb.readBits(1), 1, 'direct_8x8_inference_flag is true'); | ||
103 | strictEqual(expGolomb.readBits(1), 0, 'frame_cropping_flag is false'); | ||
104 | }); | ||
105 | |||
106 | })(this); |
test/flv-tag_test.js
deleted
100644 → 0
1 | (function(window) { | ||
2 | /* | ||
3 | ======== A Handy Little QUnit Reference ======== | ||
4 | http://api.qunitjs.com/ | ||
5 | |||
6 | Test methods: | ||
7 | module(name, {[setup][ ,teardown]}) | ||
8 | test(name, callback) | ||
9 | expect(numberOfAssertions) | ||
10 | stop(increment) | ||
11 | start(decrement) | ||
12 | Test assertions: | ||
13 | ok(value, [message]) | ||
14 | equal(actual, expected, [message]) | ||
15 | notEqual(actual, expected, [message]) | ||
16 | deepEqual(actual, expected, [message]) | ||
17 | notDeepEqual(actual, expected, [message]) | ||
18 | strictEqual(actual, expected, [message]) | ||
19 | notStrictEqual(actual, expected, [message]) | ||
20 | throws(block, [expected], [message]) | ||
21 | */ | ||
22 | var FlvTag = window.videojs.Hls.FlvTag; | ||
23 | |||
24 | module('FLV tag'); | ||
25 | |||
26 | test('writeBytes with zero length writes the entire array', function() { | ||
27 | var | ||
28 | tag = new FlvTag(FlvTag.VIDEO_TAG), | ||
29 | headerLength = tag.length; | ||
30 | tag.writeBytes(new Uint8Array([0x1, 0x2, 0x3])); | ||
31 | |||
32 | equal(3 + headerLength, tag.length, '3 payload bytes are written'); | ||
33 | }); | ||
34 | |||
35 | test('writeShort writes a two byte sequence', function() { | ||
36 | var | ||
37 | tag = new FlvTag(FlvTag.VIDEO_TAG), | ||
38 | headerLength = tag.length; | ||
39 | tag.writeShort(0x0102); | ||
40 | |||
41 | equal(2 + headerLength, tag.length, '2 bytes are written'); | ||
42 | equal(0x0102, | ||
43 | new DataView(tag.bytes.buffer).getUint16(tag.length - 2), | ||
44 | 'the value is written'); | ||
45 | }); | ||
46 | |||
47 | test('writeBytes grows the internal byte array dynamically', function() { | ||
48 | var | ||
49 | tag = new FlvTag(FlvTag.VIDEO_TAG), | ||
50 | tooManyBytes = new Uint8Array(tag.bytes.byteLength + 1); | ||
51 | |||
52 | try { | ||
53 | tag.writeBytes(tooManyBytes); | ||
54 | ok(true, 'the buffer grew to fit the data'); | ||
55 | } catch(e) { | ||
56 | ok(!e, 'the buffer should grow'); | ||
57 | } | ||
58 | }); | ||
59 | |||
60 | })(this); |
test/h264-stream_test.js
deleted
100644 → 0
1 | (function(videojs) { | ||
2 | module('H264 Stream'); | ||
3 | |||
4 | var | ||
5 | nalUnitTypes = window.videojs.Hls.NALUnitType, | ||
6 | FlvTag = window.videojs.Hls.FlvTag, | ||
7 | |||
8 | accessUnitDelimiter = new Uint8Array([ | ||
9 | 0x00, | ||
10 | 0x00, | ||
11 | 0x01, | ||
12 | nalUnitTypes.access_unit_delimiter_rbsp | ||
13 | ]), | ||
14 | seqParamSet = new Uint8Array([ | ||
15 | 0x00, | ||
16 | 0x00, | ||
17 | 0x01, | ||
18 | 0x60 | nalUnitTypes.seq_parameter_set_rbsp, | ||
19 | 0x00, // profile_idc | ||
20 | 0x00, // constraint_set flags | ||
21 | 0x00, // level_idc | ||
22 | // seq_parameter_set_id ue(v) 0 => 1 | ||
23 | // log2_max_frame_num_minus4 ue(v) 1 => 010 | ||
24 | // pic_order_cnt_type ue(v) 0 => 1 | ||
25 | // log2_max_pic_order_cnt_lsb_minus4 ue(v) 1 => 010 | ||
26 | // max_num_ref_frames ue(v) 1 => 010 | ||
27 | // gaps_in_frame_num_value_allowed u(1) 0 | ||
28 | // pic_width_in_mbs_minus1 ue(v) 0 => 1 | ||
29 | // pic_height_in_map_units_minus1 ue(v) 0 => 1 | ||
30 | // frame_mbs_only_flag u(1) 1 | ||
31 | // direct_8x8_inference_flag u(1) 0 | ||
32 | // frame_cropping_flag u(1) 0 | ||
33 | // vui_parameters_present_flag u(1) 0 | ||
34 | // 1010 1010 0100 1110 00(00 0000) | ||
35 | 0xAA, | ||
36 | 0x4E, | ||
37 | 0x00 | ||
38 | ]); | ||
39 | |||
40 | test('metadata is generated for IDRs after a full NAL unit is written', function() { | ||
41 | var | ||
42 | h264Stream = new videojs.Hls.H264Stream(), | ||
43 | idr = new Uint8Array([ | ||
44 | 0x00, | ||
45 | 0x00, | ||
46 | 0x01, | ||
47 | nalUnitTypes.slice_layer_without_partitioning_rbsp_idr | ||
48 | ]); | ||
49 | |||
50 | h264Stream.setNextTimeStamp(0, 0, true); | ||
51 | h264Stream.writeBytes(accessUnitDelimiter, 0, accessUnitDelimiter.byteLength); | ||
52 | h264Stream.writeBytes(seqParamSet, 0, seqParamSet.byteLength); | ||
53 | h264Stream.writeBytes(idr, 0, idr.byteLength); | ||
54 | h264Stream.setNextTimeStamp(1, 1, true); | ||
55 | |||
56 | strictEqual(h264Stream.tags.length, 3, 'three tags are written'); | ||
57 | ok(FlvTag.isMetaData(h264Stream.tags[0].bytes), | ||
58 | 'metadata is written'); | ||
59 | ok(FlvTag.isVideoFrame(h264Stream.tags[1].bytes), | ||
60 | 'picture parameter set is written'); | ||
61 | ok(h264Stream.tags[2].keyFrame, 'key frame is written'); | ||
62 | }); | ||
63 | |||
64 | test('make sure we add metadata and extra data at the beginning of a stream', function() { | ||
65 | var | ||
66 | H264ExtraData = videojs.Hls.H264ExtraData, | ||
67 | oldExtraData = H264ExtraData.prototype.extraDataTag, | ||
68 | oldMetadata = H264ExtraData.prototype.metaDataTag, | ||
69 | h264Stream; | ||
70 | |||
71 | H264ExtraData.prototype.extraDataTag = function() { | ||
72 | return 'extraDataTag'; | ||
73 | }; | ||
74 | H264ExtraData.prototype.metaDataTag = function() { | ||
75 | return 'metaDataTag'; | ||
76 | }; | ||
77 | |||
78 | h264Stream = new videojs.Hls.H264Stream(); | ||
79 | |||
80 | h264Stream.setTimeStampOffset(0); | ||
81 | h264Stream.setNextTimeStamp(0, 0, true); | ||
82 | // the sps provides the metadata for the stream | ||
83 | h264Stream.writeBytes(seqParamSet, 0, seqParamSet.byteLength); | ||
84 | h264Stream.writeBytes(accessUnitDelimiter, 0, accessUnitDelimiter.byteLength); | ||
85 | |||
86 | // make sure that keyFrame is set to false but that we don't have any tags currently written out | ||
87 | h264Stream._h264Frame.keyFrame = false; | ||
88 | h264Stream.tags = []; | ||
89 | |||
90 | h264Stream.setNextTimeStamp(5, 5, true); | ||
91 | h264Stream.writeBytes(accessUnitDelimiter, 0, accessUnitDelimiter.byteLength); | ||
92 | // flush out the last tag | ||
93 | h264Stream.writeBytes(accessUnitDelimiter, 0, accessUnitDelimiter.byteLength); | ||
94 | |||
95 | strictEqual(h264Stream.tags.length, 4, 'three tags are ready'); | ||
96 | strictEqual(h264Stream.tags[0], 'metaDataTag', 'the first tag is the metaDataTag'); | ||
97 | strictEqual(h264Stream.tags[1], 'extraDataTag', 'the second tag is the extraDataTag'); | ||
98 | |||
99 | H264ExtraData.prototype.extraDataTag = oldExtraData; | ||
100 | H264ExtraData.prototype.metaDataTag = oldMetadata; | ||
101 | }); | ||
102 | |||
103 | })(window.videojs); |
... | @@ -77,25 +77,15 @@ module.exports = function(config) { | ... | @@ -77,25 +77,15 @@ module.exports = function(config) { |
77 | '../test/karma-qunit-shim.js', | 77 | '../test/karma-qunit-shim.js', |
78 | '../src/videojs-hls.js', | 78 | '../src/videojs-hls.js', |
79 | '../src/stream.js', | 79 | '../src/stream.js', |
80 | '../src/flv-tag.js', | ||
81 | '../src/exp-golomb.js', | ||
82 | '../src/h264-extradata.js', | ||
83 | '../src/h264-stream.js', | ||
84 | '../src/aac-stream.js', | ||
85 | '../src/metadata-stream.js', | ||
86 | '../src/segment-parser.js', | ||
87 | '../src/m3u8/m3u8-parser.js', | 80 | '../src/m3u8/m3u8-parser.js', |
88 | '../src/xhr.js', | 81 | '../src/xhr.js', |
89 | '../src/playlist.js', | 82 | '../src/playlist.js', |
90 | '../src/playlist-loader.js', | 83 | '../src/playlist-loader.js', |
91 | '../src/decrypter.js', | 84 | '../src/decrypter.js', |
92 | '../src/mp4-generator.js', | ||
93 | '../src/transmuxer.js', | ||
94 | '../tmp/manifests.js', | 85 | '../tmp/manifests.js', |
95 | '../tmp/expected.js', | 86 | '../tmp/expected.js', |
96 | 'tsSegment-bc.js', | 87 | 'tsSegment-bc.js', |
97 | '../src/bin-utils.js', | 88 | '../src/bin-utils.js', |
98 | '../test/muxer/js/mp4-inspector.js', | ||
99 | '../test/*.js', | 89 | '../test/*.js', |
100 | ], | 90 | ], |
101 | 91 | ... | ... |
... | @@ -42,25 +42,15 @@ module.exports = function(config) { | ... | @@ -42,25 +42,15 @@ module.exports = function(config) { |
42 | '../test/karma-qunit-shim.js', | 42 | '../test/karma-qunit-shim.js', |
43 | '../src/videojs-hls.js', | 43 | '../src/videojs-hls.js', |
44 | '../src/stream.js', | 44 | '../src/stream.js', |
45 | '../src/flv-tag.js', | ||
46 | '../src/exp-golomb.js', | ||
47 | '../src/h264-extradata.js', | ||
48 | '../src/h264-stream.js', | ||
49 | '../src/aac-stream.js', | ||
50 | '../src/metadata-stream.js', | ||
51 | '../src/segment-parser.js', | ||
52 | '../src/m3u8/m3u8-parser.js', | 45 | '../src/m3u8/m3u8-parser.js', |
53 | '../src/xhr.js', | 46 | '../src/xhr.js', |
54 | '../src/playlist.js', | 47 | '../src/playlist.js', |
55 | '../src/playlist-loader.js', | 48 | '../src/playlist-loader.js', |
56 | '../src/decrypter.js', | 49 | '../src/decrypter.js', |
57 | '../src/mp4-generator.js', | ||
58 | '../src/transmuxer.js', | ||
59 | '../tmp/manifests.js', | 50 | '../tmp/manifests.js', |
60 | '../tmp/expected.js', | 51 | '../tmp/expected.js', |
61 | 'tsSegment-bc.js', | 52 | 'tsSegment-bc.js', |
62 | '../src/bin-utils.js', | 53 | '../src/bin-utils.js', |
63 | '../test/muxer/js/mp4-inspector.js', | ||
64 | '../test/*.js', | 54 | '../test/*.js', |
65 | ], | 55 | ], |
66 | 56 | ... | ... |
test/metadata-stream_test.js
deleted
100644 → 0
This diff is collapsed.
Click to expand it.
test/mp4-generator_test.js
deleted
100644 → 0
This diff is collapsed.
Click to expand it.
test/mp4-inspector_test.js
deleted
100644 → 0
This diff is collapsed.
Click to expand it.
test/muxer/css/main.css
deleted
100644 → 0
1 | /* ========================================================================== | ||
2 | HTML5 Boilerplate styles - h5bp.com (generated via initializr.com) | ||
3 | ========================================================================== */ | ||
4 | |||
5 | html, | ||
6 | button, | ||
7 | input, | ||
8 | select, | ||
9 | textarea { | ||
10 | color: #222; | ||
11 | } | ||
12 | |||
13 | body { | ||
14 | font-size: 1em; | ||
15 | line-height: 1.4; | ||
16 | } | ||
17 | |||
18 | ::-moz-selection { | ||
19 | background: #b3d4fc; | ||
20 | text-shadow: none; | ||
21 | } | ||
22 | |||
23 | ::selection { | ||
24 | background: #b3d4fc; | ||
25 | text-shadow: none; | ||
26 | } | ||
27 | |||
28 | hr { | ||
29 | display: block; | ||
30 | height: 1px; | ||
31 | border: 0; | ||
32 | border-top: 1px solid #ccc; | ||
33 | margin: 1em 0; | ||
34 | padding: 0; | ||
35 | } | ||
36 | |||
37 | img { | ||
38 | vertical-align: middle; | ||
39 | } | ||
40 | |||
41 | fieldset { | ||
42 | border: 0; | ||
43 | margin: 0; | ||
44 | padding: 0; | ||
45 | } | ||
46 | |||
47 | textarea { | ||
48 | resize: vertical; | ||
49 | } | ||
50 | |||
51 | .chromeframe { | ||
52 | margin: 0.2em 0; | ||
53 | background: #ccc; | ||
54 | color: #000; | ||
55 | padding: 0.2em 0; | ||
56 | } | ||
57 | |||
58 | |||
59 | /* ===== Initializr Styles ================================================== | ||
60 | Author: Jonathan Verrecchia - verekia.com/initializr/responsive-template | ||
61 | ========================================================================== */ | ||
62 | |||
63 | body { | ||
64 | font: 16px/26px Helvetica, Helvetica Neue, Arial; | ||
65 | } | ||
66 | |||
67 | .wrapper { | ||
68 | width: 90%; | ||
69 | margin: 0 5%; | ||
70 | } | ||
71 | |||
72 | /* =================== | ||
73 | ALL: Orange Theme | ||
74 | =================== */ | ||
75 | |||
76 | .header-container { | ||
77 | border-bottom: 20px solid #e44d26; | ||
78 | } | ||
79 | |||
80 | .footer-container, | ||
81 | .main aside { | ||
82 | border-top: 20px solid #e44d26; | ||
83 | } | ||
84 | |||
85 | .header-container, | ||
86 | .footer-container, | ||
87 | .main aside { | ||
88 | background: #f16529; | ||
89 | } | ||
90 | |||
91 | .title { | ||
92 | color: white; | ||
93 | } | ||
94 | |||
95 | /* ============== | ||
96 | MOBILE: Menu | ||
97 | ============== */ | ||
98 | |||
99 | nav ul { | ||
100 | margin: 0; | ||
101 | padding: 0; | ||
102 | } | ||
103 | |||
104 | nav a { | ||
105 | display: block; | ||
106 | margin-bottom: 10px; | ||
107 | padding: 15px 0; | ||
108 | |||
109 | text-align: center; | ||
110 | text-decoration: none; | ||
111 | font-weight: bold; | ||
112 | |||
113 | color: white; | ||
114 | background: #e44d26; | ||
115 | } | ||
116 | |||
117 | nav a:hover, | ||
118 | nav a:visited { | ||
119 | color: white; | ||
120 | } | ||
121 | |||
122 | nav a:hover { | ||
123 | text-decoration: underline; | ||
124 | } | ||
125 | |||
126 | /* ============== | ||
127 | MOBILE: Main | ||
128 | ============== */ | ||
129 | |||
130 | .main { | ||
131 | padding: 30px 0; | ||
132 | } | ||
133 | |||
134 | .main article h1 { | ||
135 | font-size: 2em; | ||
136 | } | ||
137 | |||
138 | .main aside { | ||
139 | color: white; | ||
140 | padding: 0px 5% 10px; | ||
141 | } | ||
142 | |||
143 | .footer-container footer { | ||
144 | color: white; | ||
145 | padding: 20px 0; | ||
146 | } | ||
147 | |||
148 | /* =============== | ||
149 | ALL: IE Fixes | ||
150 | =============== */ | ||
151 | |||
152 | .ie7 .title { | ||
153 | padding-top: 20px; | ||
154 | } | ||
155 | |||
156 | /* ========================================================================== | ||
157 | Author's custom styles | ||
158 | ========================================================================== */ | ||
159 | |||
160 | section { | ||
161 | clear: both; | ||
162 | } | ||
163 | |||
164 | form label { | ||
165 | display: block; | ||
166 | } | ||
167 | |||
168 | .result-wrapper { | ||
169 | float: left; | ||
170 | margin: 10px 0; | ||
171 | min-width: 422px; | ||
172 | width: 50%; | ||
173 | } | ||
174 | |||
175 | .result { | ||
176 | border: thin solid #aaa; | ||
177 | border-radius: 5px; | ||
178 | font-size: 10px; | ||
179 | line-height: 15px; | ||
180 | margin: 0 5px; | ||
181 | padding: 0 10px; | ||
182 | } | ||
183 | |||
184 | /* ========================================================================== | ||
185 | Media Queries | ||
186 | ========================================================================== */ | ||
187 | |||
188 | @media only screen and (min-width: 480px) { | ||
189 | |||
190 | /* ==================== | ||
191 | INTERMEDIATE: Menu | ||
192 | ==================== */ | ||
193 | |||
194 | nav a { | ||
195 | float: left; | ||
196 | width: 27%; | ||
197 | margin: 0 1.7%; | ||
198 | padding: 25px 2%; | ||
199 | margin-bottom: 0; | ||
200 | } | ||
201 | |||
202 | nav li:first-child a { | ||
203 | margin-left: 0; | ||
204 | } | ||
205 | |||
206 | nav li:last-child a { | ||
207 | margin-right: 0; | ||
208 | } | ||
209 | |||
210 | /* ======================== | ||
211 | INTERMEDIATE: IE Fixes | ||
212 | ======================== */ | ||
213 | |||
214 | nav ul li { | ||
215 | display: inline; | ||
216 | } | ||
217 | |||
218 | .oldie nav a { | ||
219 | margin: 0 0.7%; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | @media only screen and (min-width: 768px) { | ||
224 | |||
225 | /* ==================== | ||
226 | WIDE: CSS3 Effects | ||
227 | ==================== */ | ||
228 | |||
229 | .header-container, | ||
230 | .main aside { | ||
231 | -webkit-box-shadow: 0 5px 10px #aaa; | ||
232 | -moz-box-shadow: 0 5px 10px #aaa; | ||
233 | box-shadow: 0 5px 10px #aaa; | ||
234 | } | ||
235 | |||
236 | /* ============ | ||
237 | WIDE: Menu | ||
238 | ============ */ | ||
239 | |||
240 | .title { | ||
241 | float: left; | ||
242 | } | ||
243 | |||
244 | nav { | ||
245 | float: right; | ||
246 | width: 38%; | ||
247 | } | ||
248 | |||
249 | /* ============ | ||
250 | WIDE: Main | ||
251 | ============ */ | ||
252 | |||
253 | .main article { | ||
254 | float: left; | ||
255 | width: 100%; | ||
256 | } | ||
257 | } | ||
258 | |||
259 | @media only screen and (min-width: 1140px) { | ||
260 | |||
261 | /* =============== | ||
262 | Maximal Width | ||
263 | =============== */ | ||
264 | |||
265 | .wrapper { | ||
266 | width: 1026px; /* 1140px - 10% for margins */ | ||
267 | margin: 0 auto; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | /* ========================================================================== | ||
272 | Helper classes | ||
273 | ========================================================================== */ | ||
274 | |||
275 | .ir { | ||
276 | background-color: transparent; | ||
277 | border: 0; | ||
278 | overflow: hidden; | ||
279 | *text-indent: -9999px; | ||
280 | } | ||
281 | |||
282 | .ir:before { | ||
283 | content: ""; | ||
284 | display: block; | ||
285 | width: 0; | ||
286 | height: 150%; | ||
287 | } | ||
288 | |||
289 | .hidden { | ||
290 | display: none !important; | ||
291 | visibility: hidden; | ||
292 | } | ||
293 | |||
294 | .visuallyhidden { | ||
295 | border: 0; | ||
296 | clip: rect(0 0 0 0); | ||
297 | height: 1px; | ||
298 | margin: -1px; | ||
299 | overflow: hidden; | ||
300 | padding: 0; | ||
301 | position: absolute; | ||
302 | width: 1px; | ||
303 | } | ||
304 | |||
305 | .visuallyhidden.focusable:active, | ||
306 | .visuallyhidden.focusable:focus { | ||
307 | clip: auto; | ||
308 | height: auto; | ||
309 | margin: 0; | ||
310 | overflow: visible; | ||
311 | position: static; | ||
312 | width: auto; | ||
313 | } | ||
314 | |||
315 | .invisible { | ||
316 | visibility: hidden; | ||
317 | } | ||
318 | |||
319 | .clearfix:before, | ||
320 | .clearfix:after { | ||
321 | content: " "; | ||
322 | display: table; | ||
323 | } | ||
324 | |||
325 | .clearfix:after { | ||
326 | clear: both; | ||
327 | } | ||
328 | |||
329 | .clearfix { | ||
330 | *zoom: 1; | ||
331 | } | ||
332 | |||
333 | /* ========================================================================== | ||
334 | Print styles | ||
335 | ========================================================================== */ | ||
336 | |||
337 | @media print { | ||
338 | * { | ||
339 | background: transparent !important; | ||
340 | color: #000 !important; /* Black prints faster: h5bp.com/s */ | ||
341 | box-shadow: none !important; | ||
342 | text-shadow: none !important; | ||
343 | } | ||
344 | |||
345 | a, | ||
346 | a:visited { | ||
347 | text-decoration: underline; | ||
348 | } | ||
349 | |||
350 | a[href]:after { | ||
351 | content: " (" attr(href) ")"; | ||
352 | } | ||
353 | |||
354 | abbr[title]:after { | ||
355 | content: " (" attr(title) ")"; | ||
356 | } | ||
357 | |||
358 | /* | ||
359 | * Don't show links for images, or javascript/internal links | ||
360 | */ | ||
361 | |||
362 | .ir a:after, | ||
363 | a[href^="javascript:"]:after, | ||
364 | a[href^="#"]:after { | ||
365 | content: ""; | ||
366 | } | ||
367 | |||
368 | pre, | ||
369 | blockquote { | ||
370 | border: 1px solid #999; | ||
371 | page-break-inside: avoid; | ||
372 | } | ||
373 | |||
374 | thead { | ||
375 | display: table-header-group; /* h5bp.com/t */ | ||
376 | } | ||
377 | |||
378 | tr, | ||
379 | img { | ||
380 | page-break-inside: avoid; | ||
381 | } | ||
382 | |||
383 | img { | ||
384 | max-width: 100% !important; | ||
385 | } | ||
386 | |||
387 | @page { | ||
388 | margin: 0.5cm; | ||
389 | } | ||
390 | |||
391 | p, | ||
392 | h2, | ||
393 | h3 { | ||
394 | orphans: 3; | ||
395 | widows: 3; | ||
396 | } | ||
397 | |||
398 | h2, | ||
399 | h3 { | ||
400 | page-break-after: avoid; | ||
401 | } | ||
402 | } | ||
403 | |||
404 | /** | ||
405 | * Diff styling | ||
406 | */ | ||
407 | #comparison p { | ||
408 | white-space: normal; | ||
409 | } | ||
410 | #comparison pre { | ||
411 | font-size: 90%; | ||
412 | } | ||
413 | ins, del { | ||
414 | text-decoration: none; | ||
415 | } | ||
416 | ins { | ||
417 | background-color: #C6E746; | ||
418 | } | ||
419 | |||
420 | del { | ||
421 | background-color: #EE5757 | ||
422 | } | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
test/muxer/css/normalize.css
deleted
100644 → 0
1 | /*! normalize.css v1.1.2 | MIT License | git.io/normalize */ | ||
2 | |||
3 | /* ========================================================================== | ||
4 | HTML5 display definitions | ||
5 | ========================================================================== */ | ||
6 | |||
7 | /** | ||
8 | * Correct `block` display not defined in IE 6/7/8/9 and Firefox 3. | ||
9 | */ | ||
10 | |||
11 | article, | ||
12 | aside, | ||
13 | details, | ||
14 | figcaption, | ||
15 | figure, | ||
16 | footer, | ||
17 | header, | ||
18 | hgroup, | ||
19 | main, | ||
20 | nav, | ||
21 | section, | ||
22 | summary { | ||
23 | display: block; | ||
24 | } | ||
25 | |||
26 | /** | ||
27 | * Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3. | ||
28 | */ | ||
29 | |||
30 | audio, | ||
31 | canvas, | ||
32 | video { | ||
33 | display: inline-block; | ||
34 | *display: inline; | ||
35 | *zoom: 1; | ||
36 | } | ||
37 | |||
38 | /** | ||
39 | * Prevent modern browsers from displaying `audio` without controls. | ||
40 | * Remove excess height in iOS 5 devices. | ||
41 | */ | ||
42 | |||
43 | audio:not([controls]) { | ||
44 | display: none; | ||
45 | height: 0; | ||
46 | } | ||
47 | |||
48 | /** | ||
49 | * Address styling not present in IE 7/8/9, Firefox 3, and Safari 4. | ||
50 | * Known issue: no IE 6 support. | ||
51 | */ | ||
52 | |||
53 | [hidden] { | ||
54 | display: none; | ||
55 | } | ||
56 | |||
57 | /* ========================================================================== | ||
58 | Base | ||
59 | ========================================================================== */ | ||
60 | |||
61 | /** | ||
62 | * 1. Correct text resizing oddly in IE 6/7 when body `font-size` is set using | ||
63 | * `em` units. | ||
64 | * 2. Prevent iOS text size adjust after orientation change, without disabling | ||
65 | * user zoom. | ||
66 | */ | ||
67 | |||
68 | html { | ||
69 | font-size: 100%; /* 1 */ | ||
70 | -ms-text-size-adjust: 100%; /* 2 */ | ||
71 | -webkit-text-size-adjust: 100%; /* 2 */ | ||
72 | } | ||
73 | |||
74 | /** | ||
75 | * Address `font-family` inconsistency between `textarea` and other form | ||
76 | * elements. | ||
77 | */ | ||
78 | |||
79 | html, | ||
80 | button, | ||
81 | input, | ||
82 | select, | ||
83 | textarea { | ||
84 | font-family: sans-serif; | ||
85 | } | ||
86 | |||
87 | /** | ||
88 | * Address margins handled incorrectly in IE 6/7. | ||
89 | */ | ||
90 | |||
91 | body { | ||
92 | margin: 0; | ||
93 | } | ||
94 | |||
95 | /* ========================================================================== | ||
96 | Links | ||
97 | ========================================================================== */ | ||
98 | |||
99 | /** | ||
100 | * Address `outline` inconsistency between Chrome and other browsers. | ||
101 | */ | ||
102 | |||
103 | a:focus { | ||
104 | outline: thin dotted; | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * Improve readability when focused and also mouse hovered in all browsers. | ||
109 | */ | ||
110 | |||
111 | a:active, | ||
112 | a:hover { | ||
113 | outline: 0; | ||
114 | } | ||
115 | |||
116 | /* ========================================================================== | ||
117 | Typography | ||
118 | ========================================================================== */ | ||
119 | |||
120 | /** | ||
121 | * Address font sizes and margins set differently in IE 6/7. | ||
122 | * Address font sizes within `section` and `article` in Firefox 4+, Safari 5, | ||
123 | * and Chrome. | ||
124 | */ | ||
125 | |||
126 | h1 { | ||
127 | font-size: 2em; | ||
128 | margin: 0.67em 0; | ||
129 | } | ||
130 | |||
131 | h2 { | ||
132 | font-size: 1.5em; | ||
133 | margin: 0.83em 0; | ||
134 | } | ||
135 | |||
136 | h3 { | ||
137 | font-size: 1.17em; | ||
138 | margin: 1em 0; | ||
139 | } | ||
140 | |||
141 | h4 { | ||
142 | font-size: 1em; | ||
143 | margin: 1.33em 0; | ||
144 | } | ||
145 | |||
146 | h5 { | ||
147 | font-size: 0.83em; | ||
148 | margin: 1.67em 0; | ||
149 | } | ||
150 | |||
151 | h6 { | ||
152 | font-size: 0.67em; | ||
153 | margin: 2.33em 0; | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * Address styling not present in IE 7/8/9, Safari 5, and Chrome. | ||
158 | */ | ||
159 | |||
160 | abbr[title] { | ||
161 | border-bottom: 1px dotted; | ||
162 | } | ||
163 | |||
164 | /** | ||
165 | * Address style set to `bolder` in Firefox 3+, Safari 4/5, and Chrome. | ||
166 | */ | ||
167 | |||
168 | b, | ||
169 | strong { | ||
170 | font-weight: bold; | ||
171 | } | ||
172 | |||
173 | blockquote { | ||
174 | margin: 1em 40px; | ||
175 | } | ||
176 | |||
177 | /** | ||
178 | * Address styling not present in Safari 5 and Chrome. | ||
179 | */ | ||
180 | |||
181 | dfn { | ||
182 | font-style: italic; | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * Address differences between Firefox and other browsers. | ||
187 | * Known issue: no IE 6/7 normalization. | ||
188 | */ | ||
189 | |||
190 | hr { | ||
191 | -moz-box-sizing: content-box; | ||
192 | box-sizing: content-box; | ||
193 | height: 0; | ||
194 | } | ||
195 | |||
196 | /** | ||
197 | * Address styling not present in IE 6/7/8/9. | ||
198 | */ | ||
199 | |||
200 | mark { | ||
201 | background: #ff0; | ||
202 | color: #000; | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * Address margins set differently in IE 6/7. | ||
207 | */ | ||
208 | |||
209 | p, | ||
210 | pre { | ||
211 | margin: 1em 0; | ||
212 | } | ||
213 | |||
214 | /** | ||
215 | * Correct font family set oddly in IE 6, Safari 4/5, and Chrome. | ||
216 | */ | ||
217 | |||
218 | code, | ||
219 | kbd, | ||
220 | pre, | ||
221 | samp { | ||
222 | font-family: monospace, serif; | ||
223 | _font-family: 'courier new', monospace; | ||
224 | font-size: 1em; | ||
225 | } | ||
226 | |||
227 | /** | ||
228 | * Improve readability of pre-formatted text in all browsers. | ||
229 | */ | ||
230 | |||
231 | pre { | ||
232 | white-space: pre; | ||
233 | white-space: pre-wrap; | ||
234 | word-wrap: break-word; | ||
235 | } | ||
236 | |||
237 | /** | ||
238 | * Address CSS quotes not supported in IE 6/7. | ||
239 | */ | ||
240 | |||
241 | q { | ||
242 | quotes: none; | ||
243 | } | ||
244 | |||
245 | /** | ||
246 | * Address `quotes` property not supported in Safari 4. | ||
247 | */ | ||
248 | |||
249 | q:before, | ||
250 | q:after { | ||
251 | content: ''; | ||
252 | content: none; | ||
253 | } | ||
254 | |||
255 | /** | ||
256 | * Address inconsistent and variable font size in all browsers. | ||
257 | */ | ||
258 | |||
259 | small { | ||
260 | font-size: 80%; | ||
261 | } | ||
262 | |||
263 | /** | ||
264 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. | ||
265 | */ | ||
266 | |||
267 | sub, | ||
268 | sup { | ||
269 | font-size: 75%; | ||
270 | line-height: 0; | ||
271 | position: relative; | ||
272 | vertical-align: baseline; | ||
273 | } | ||
274 | |||
275 | sup { | ||
276 | top: -0.5em; | ||
277 | } | ||
278 | |||
279 | sub { | ||
280 | bottom: -0.25em; | ||
281 | } | ||
282 | |||
283 | /* ========================================================================== | ||
284 | Lists | ||
285 | ========================================================================== */ | ||
286 | |||
287 | /** | ||
288 | * Address margins set differently in IE 6/7. | ||
289 | */ | ||
290 | |||
291 | dl, | ||
292 | menu, | ||
293 | ol, | ||
294 | ul { | ||
295 | margin: 1em 0; | ||
296 | } | ||
297 | |||
298 | dd { | ||
299 | margin: 0 0 0 40px; | ||
300 | } | ||
301 | |||
302 | /** | ||
303 | * Address paddings set differently in IE 6/7. | ||
304 | */ | ||
305 | |||
306 | menu, | ||
307 | ol, | ||
308 | ul { | ||
309 | padding: 0 0 0 40px; | ||
310 | } | ||
311 | |||
312 | /** | ||
313 | * Correct list images handled incorrectly in IE 7. | ||
314 | */ | ||
315 | |||
316 | nav ul, | ||
317 | nav ol { | ||
318 | list-style: none; | ||
319 | list-style-image: none; | ||
320 | } | ||
321 | |||
322 | /* ========================================================================== | ||
323 | Embedded content | ||
324 | ========================================================================== */ | ||
325 | |||
326 | /** | ||
327 | * 1. Remove border when inside `a` element in IE 6/7/8/9 and Firefox 3. | ||
328 | * 2. Improve image quality when scaled in IE 7. | ||
329 | */ | ||
330 | |||
331 | img { | ||
332 | border: 0; /* 1 */ | ||
333 | -ms-interpolation-mode: bicubic; /* 2 */ | ||
334 | } | ||
335 | |||
336 | /** | ||
337 | * Correct overflow displayed oddly in IE 9. | ||
338 | */ | ||
339 | |||
340 | svg:not(:root) { | ||
341 | overflow: hidden; | ||
342 | } | ||
343 | |||
344 | /* ========================================================================== | ||
345 | Figures | ||
346 | ========================================================================== */ | ||
347 | |||
348 | /** | ||
349 | * Address margin not present in IE 6/7/8/9, Safari 5, and Opera 11. | ||
350 | */ | ||
351 | |||
352 | figure { | ||
353 | margin: 0; | ||
354 | } | ||
355 | |||
356 | /* ========================================================================== | ||
357 | Forms | ||
358 | ========================================================================== */ | ||
359 | |||
360 | /** | ||
361 | * Correct margin displayed oddly in IE 6/7. | ||
362 | */ | ||
363 | |||
364 | form { | ||
365 | margin: 0; | ||
366 | } | ||
367 | |||
368 | /** | ||
369 | * Define consistent border, margin, and padding. | ||
370 | */ | ||
371 | |||
372 | fieldset { | ||
373 | border: 1px solid #c0c0c0; | ||
374 | margin: 0 2px; | ||
375 | padding: 0.35em 0.625em 0.75em; | ||
376 | } | ||
377 | |||
378 | /** | ||
379 | * 1. Correct color not being inherited in IE 6/7/8/9. | ||
380 | * 2. Correct text not wrapping in Firefox 3. | ||
381 | * 3. Correct alignment displayed oddly in IE 6/7. | ||
382 | */ | ||
383 | |||
384 | legend { | ||
385 | border: 0; /* 1 */ | ||
386 | padding: 0; | ||
387 | white-space: normal; /* 2 */ | ||
388 | *margin-left: -7px; /* 3 */ | ||
389 | } | ||
390 | |||
391 | /** | ||
392 | * 1. Correct font size not being inherited in all browsers. | ||
393 | * 2. Address margins set differently in IE 6/7, Firefox 3+, Safari 5, | ||
394 | * and Chrome. | ||
395 | * 3. Improve appearance and consistency in all browsers. | ||
396 | */ | ||
397 | |||
398 | button, | ||
399 | input, | ||
400 | select, | ||
401 | textarea { | ||
402 | font-size: 100%; /* 1 */ | ||
403 | margin: 0; /* 2 */ | ||
404 | vertical-align: baseline; /* 3 */ | ||
405 | *vertical-align: middle; /* 3 */ | ||
406 | } | ||
407 | |||
408 | /** | ||
409 | * Address Firefox 3+ setting `line-height` on `input` using `!important` in | ||
410 | * the UA stylesheet. | ||
411 | */ | ||
412 | |||
413 | button, | ||
414 | input { | ||
415 | line-height: normal; | ||
416 | } | ||
417 | |||
418 | /** | ||
419 | * Address inconsistent `text-transform` inheritance for `button` and `select`. | ||
420 | * All other form control elements do not inherit `text-transform` values. | ||
421 | * Correct `button` style inheritance in Chrome, Safari 5+, and IE 6+. | ||
422 | * Correct `select` style inheritance in Firefox 4+ and Opera. | ||
423 | */ | ||
424 | |||
425 | button, | ||
426 | select { | ||
427 | text-transform: none; | ||
428 | } | ||
429 | |||
430 | /** | ||
431 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` | ||
432 | * and `video` controls. | ||
433 | * 2. Correct inability to style clickable `input` types in iOS. | ||
434 | * 3. Improve usability and consistency of cursor style between image-type | ||
435 | * `input` and others. | ||
436 | * 4. Remove inner spacing in IE 7 without affecting normal text inputs. | ||
437 | * Known issue: inner spacing remains in IE 6. | ||
438 | */ | ||
439 | |||
440 | button, | ||
441 | html input[type="button"], /* 1 */ | ||
442 | input[type="reset"], | ||
443 | input[type="submit"] { | ||
444 | -webkit-appearance: button; /* 2 */ | ||
445 | cursor: pointer; /* 3 */ | ||
446 | *overflow: visible; /* 4 */ | ||
447 | } | ||
448 | |||
449 | /** | ||
450 | * Re-set default cursor for disabled elements. | ||
451 | */ | ||
452 | |||
453 | button[disabled], | ||
454 | html input[disabled] { | ||
455 | cursor: default; | ||
456 | } | ||
457 | |||
458 | /** | ||
459 | * 1. Address box sizing set to content-box in IE 8/9. | ||
460 | * 2. Remove excess padding in IE 8/9. | ||
461 | * 3. Remove excess padding in IE 7. | ||
462 | * Known issue: excess padding remains in IE 6. | ||
463 | */ | ||
464 | |||
465 | input[type="checkbox"], | ||
466 | input[type="radio"] { | ||
467 | box-sizing: border-box; /* 1 */ | ||
468 | padding: 0; /* 2 */ | ||
469 | *height: 13px; /* 3 */ | ||
470 | *width: 13px; /* 3 */ | ||
471 | } | ||
472 | |||
473 | /** | ||
474 | * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. | ||
475 | * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome | ||
476 | * (include `-moz` to future-proof). | ||
477 | */ | ||
478 | |||
479 | input[type="search"] { | ||
480 | -webkit-appearance: textfield; /* 1 */ | ||
481 | -moz-box-sizing: content-box; | ||
482 | -webkit-box-sizing: content-box; /* 2 */ | ||
483 | box-sizing: content-box; | ||
484 | } | ||
485 | |||
486 | /** | ||
487 | * Remove inner padding and search cancel button in Safari 5 and Chrome | ||
488 | * on OS X. | ||
489 | */ | ||
490 | |||
491 | input[type="search"]::-webkit-search-cancel-button, | ||
492 | input[type="search"]::-webkit-search-decoration { | ||
493 | -webkit-appearance: none; | ||
494 | } | ||
495 | |||
496 | /** | ||
497 | * Remove inner padding and border in Firefox 3+. | ||
498 | */ | ||
499 | |||
500 | button::-moz-focus-inner, | ||
501 | input::-moz-focus-inner { | ||
502 | border: 0; | ||
503 | padding: 0; | ||
504 | } | ||
505 | |||
506 | /** | ||
507 | * 1. Remove default vertical scrollbar in IE 6/7/8/9. | ||
508 | * 2. Improve readability and alignment in all browsers. | ||
509 | */ | ||
510 | |||
511 | textarea { | ||
512 | overflow: auto; /* 1 */ | ||
513 | vertical-align: top; /* 2 */ | ||
514 | } | ||
515 | |||
516 | /* ========================================================================== | ||
517 | Tables | ||
518 | ========================================================================== */ | ||
519 | |||
520 | /** | ||
521 | * Remove most spacing between table cells. | ||
522 | */ | ||
523 | |||
524 | table { | ||
525 | border-collapse: collapse; | ||
526 | border-spacing: 0; | ||
527 | } |
test/muxer/css/normalize.min.css
deleted
100644 → 0
1 | /*! normalize.css v1.1.2 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-size:100%;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}html,button,input,select,textarea{font-family:sans-serif}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{font-size:2em;margin:.67em 0}h2{font-size:1.5em;margin:.83em 0}h3{font-size:1.17em;margin:1em 0}h4{font-size:1em;margin:1.33em 0}h5{font-size:.83em;margin:1.67em 0}h6{font-size:.67em;margin:2.33em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:1em 40px}dfn{font-style:italic}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}p,pre{margin:1em 0}code,kbd,pre,samp{font-family:monospace,serif;_font-family:'courier new',monospace;font-size:1em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}q{quotes:none}q:before,q:after{content:'';content:none}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}dl,menu,ol,ul{margin:1em 0}dd{margin:0 0 0 40px}menu,ol,ul{padding:0 0 0 40px}nav ul,nav ol{list-style:none;list-style-image:none}img{border:0;-ms-interpolation-mode:bicubic}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0;white-space:normal;*margin-left:-7px}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;*overflow:visible}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*height:13px;*width:13px}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
test/muxer/index.html
deleted
100644 → 0
1 | <!DOCTYPE html> | ||
2 | <!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]--> | ||
3 | <!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]--> | ||
4 | <!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]--> | ||
5 | <!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]--> | ||
6 | <head> | ||
7 | <meta charset="utf-8"> | ||
8 | <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | ||
9 | <title></title> | ||
10 | <meta name="description" content=""> | ||
11 | <meta name="viewport" content="width=device-width"> | ||
12 | |||
13 | <link rel="stylesheet" href="css/normalize.min.css"> | ||
14 | <link rel="stylesheet" href="css/main.css"> | ||
15 | |||
16 | <script src="js/vendor/modernizr-2.6.2.min.js"></script> | ||
17 | </head> | ||
18 | <body> | ||
19 | <!--[if lt IE 7]> | ||
20 | <p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> or <a href="http://www.google.com/chromeframe/?redirect=true">activate Google Chrome Frame</a> to improve your experience.</p> | ||
21 | <![endif]--> | ||
22 | |||
23 | <div class="header-container"> | ||
24 | <header class="wrapper clearfix"> | ||
25 | <h1 class="title">Transmux Analyzer</h1> | ||
26 | </header> | ||
27 | </div> | ||
28 | |||
29 | <div class="main-container"> | ||
30 | <div class="main wrapper clearfix"> | ||
31 | |||
32 | <article> | ||
33 | <header> | ||
34 | <p> | ||
35 | This page can help you compare the results of the | ||
36 | transmuxing performed by videojs-contrib-hls with a known, | ||
37 | working file produced by another tool. You could use | ||
38 | ffmpeg to transform an MPEG-2 transport stream into an FLV | ||
39 | with a command like this: | ||
40 | <pre>ffmpeg -i input.ts -acodec copy -vcodec copy output.flv</pre> | ||
41 | </p> | ||
42 | <p> | ||
43 | This page only compares FLVs files. There is | ||
44 | a <a href="mp4.html">similar utility</a> for testing the mp4 | ||
45 | conversion. | ||
46 | </p> | ||
47 | </header> | ||
48 | <section> | ||
49 | <h2>Inputs</h2> | ||
50 | <form id="inputs"> | ||
51 | <fieldset> | ||
52 | <label> | ||
53 | Your original MP2T segment: | ||
54 | <input type="file" id="original"> | ||
55 | </label> | ||
56 | <label> | ||
57 | Key (optional): | ||
58 | <input type="text" id="key"> | ||
59 | </label> | ||
60 | <label> | ||
61 | IV (optional): | ||
62 | <input type="text" id="iv"> | ||
63 | </label> | ||
64 | </fieldset> | ||
65 | <label> | ||
66 | A working, FLV version of the underlying stream | ||
67 | produced by another tool: | ||
68 | <input type="file" id="working"> | ||
69 | </label> | ||
70 | </form> | ||
71 | </section> | ||
72 | <section> | ||
73 | <h2>Tag Comparison</h2> | ||
74 | <div class="result-wrapper"> | ||
75 | <h3>videojs-contrib-hls</h3> | ||
76 | <ol class="vjs-tags"> | ||
77 | </ol> | ||
78 | </div> | ||
79 | <div class="result-wrapper"> | ||
80 | <h3>Working</h3> | ||
81 | <ol class="working-tags"> | ||
82 | </ol> | ||
83 | </div> | ||
84 | </section> | ||
85 | <section> | ||
86 | <h2>Results</h2> | ||
87 | <div class="result-wrapper"> | ||
88 | <h3>videojs-contrib-hls</h3> | ||
89 | <div class="vjs-hls-output result"> | ||
90 | <p> | ||
91 | The results of transmuxing your input file with | ||
92 | videojs-contrib-hls will show up here. | ||
93 | </p> | ||
94 | </div> | ||
95 | </div> | ||
96 | <div class="result-wrapper"> | ||
97 | <h3>Working</h3> | ||
98 | <div class="working-output result"> | ||
99 | <p> | ||
100 | The "good" version of the file will show up here. | ||
101 | </p> | ||
102 | </div> | ||
103 | </div> | ||
104 | </section> | ||
105 | </article> | ||
106 | |||
107 | </div> <!-- #main --> | ||
108 | </div> <!-- #main-container --> | ||
109 | |||
110 | <div class="footer-container"> | ||
111 | <footer class="wrapper"> | ||
112 | <h3>footer</h3> | ||
113 | </footer> | ||
114 | </div> | ||
115 | |||
116 | |||
117 | <script> | ||
118 | window.videojs = { | ||
119 | Hls: {} | ||
120 | }; | ||
121 | </script> | ||
122 | <!-- transmuxing --> | ||
123 | <script src="../../src/stream.js"></script> | ||
124 | <script src="../../src/flv-tag.js"></script> | ||
125 | <script src="../../src/exp-golomb.js"></script> | ||
126 | <script src="../../src/h264-stream.js"></script> | ||
127 | <script src="../../src/aac-stream.js"></script> | ||
128 | <script src="../../src/metadata-stream.js"></script> | ||
129 | <script src="../../src/segment-parser.js"></script> | ||
130 | <script src="../../node_modules/pkcs7/dist/pkcs7.unpad.js"></script> | ||
131 | <script src="../../src/decrypter.js"></script> | ||
132 | |||
133 | <script src="../../src/bin-utils.js"></script> | ||
134 | <script> | ||
135 | var inputs = document.getElementById('inputs'), | ||
136 | original = document.getElementById('original'), | ||
137 | key = document.getElementById('key'), | ||
138 | iv = document.getElementById('iv'), | ||
139 | working = document.getElementById('working'), | ||
140 | |||
141 | vjsTags = document.querySelector('.vjs-tags'), | ||
142 | workingTags = document.querySelector('.working-tags'), | ||
143 | |||
144 | vjsOutput = document.querySelector('.vjs-hls-output'), | ||
145 | workingOutput = document.querySelector('.working-output'), | ||
146 | |||
147 | tagTypes = { | ||
148 | 0x08: 'audio', | ||
149 | 0x09: 'video', | ||
150 | 0x12: 'metadata' | ||
151 | }; | ||
152 | |||
153 | videojs.log = console.log.bind(console); | ||
154 | |||
155 | original.addEventListener('change', function() { | ||
156 | var reader = new FileReader(); | ||
157 | reader.addEventListener('loadend', function() { | ||
158 | var parser = new videojs.Hls.SegmentParser(), | ||
159 | tags = [parser.getFlvHeader()], | ||
160 | tag, | ||
161 | bytes, | ||
162 | hex, | ||
163 | li, | ||
164 | byteLength = 0, | ||
165 | data, | ||
166 | i, | ||
167 | pos; | ||
168 | |||
169 | // clear old tag info | ||
170 | vjsTags.innerHTML = ''; | ||
171 | |||
172 | // optionally, decrypt the segment | ||
173 | if (key.value && iv.value) { | ||
174 | bytes = videojs.Hls.decrypt(new Uint8Array(reader.result), | ||
175 | key.value.match(/([0-9a-f]{8})/gi).map(function(e) { | ||
176 | return parseInt(e, 16); | ||
177 | }), | ||
178 | iv.value.match(/([0-9a-f]{8})/gi).map(function(e) { | ||
179 | return parseInt(e, 16); | ||
180 | })); | ||
181 | } else { | ||
182 | bytes = new Uint8Array(reader.result); | ||
183 | } | ||
184 | |||
185 | parser.parseSegmentBinaryData(bytes); | ||
186 | |||
187 | // collect all the tags | ||
188 | while (parser.tagsAvailable()) { | ||
189 | tag = parser.getNextTag(); | ||
190 | tags.push(tag.bytes); | ||
191 | li = document.createElement('li'); | ||
192 | li.innerHTML = tagTypes[tag.bytes[0]] + ': ' + tag.bytes.byteLength + 'B'; | ||
193 | vjsTags.appendChild(li); | ||
194 | } | ||
195 | // create a uint8array for the entire segment and copy everything over | ||
196 | i = tags.length; | ||
197 | while (i--) { | ||
198 | byteLength += tags[i].byteLength; | ||
199 | } | ||
200 | data = new Uint8Array(byteLength); | ||
201 | i = tags.length; | ||
202 | pos = byteLength; | ||
203 | while (i--) { | ||
204 | pos -= tags[i].byteLength; | ||
205 | data.set(tags[i], pos); | ||
206 | } | ||
207 | |||
208 | hex = '<pre>' | ||
209 | hex += videojs.Hls.utils.hexDump(data); | ||
210 | hex += '</pre>' | ||
211 | |||
212 | vjsOutput.innerHTML = hex; | ||
213 | }); | ||
214 | reader.readAsArrayBuffer(this.files[0]); | ||
215 | }, false); | ||
216 | |||
217 | working.addEventListener('change', function() { | ||
218 | var reader = new FileReader(); | ||
219 | reader.addEventListener('loadend', function() { | ||
220 | var hex = '<pre>', | ||
221 | bytes = new Uint8Array(reader.result), | ||
222 | i = 9, // header | ||
223 | dataSize, | ||
224 | li; | ||
225 | |||
226 | // clear old tag info | ||
227 | workingTags.innerHTML = ''; | ||
228 | |||
229 | // traverse the tags | ||
230 | i += 4; // previous tag size | ||
231 | while (i < bytes.byteLength) { | ||
232 | dataSize = bytes[i + 1] << 16; | ||
233 | dataSize |= bytes[i + 2] << 8; | ||
234 | dataSize |= bytes[i + 3]; | ||
235 | dataSize += 11; | ||
236 | |||
237 | li = document.createElement('li'); | ||
238 | li.innerHTML = tagTypes[bytes[i]] + ': ' + dataSize + 'B'; | ||
239 | workingTags.appendChild(li); | ||
240 | |||
241 | i += dataSize; // tag size | ||
242 | i += 4; // previous tag size | ||
243 | } | ||
244 | |||
245 | // output the hex dump | ||
246 | hex += videojs.Hls.utils.hexDump(bytes); | ||
247 | hex += '</pre>'; | ||
248 | workingOutput.innerHTML = hex; | ||
249 | }); | ||
250 | reader.readAsArrayBuffer(this.files[0]); | ||
251 | }, false); | ||
252 | </script> | ||
253 | <script type="text/plain"> | ||
254 | // map nal_unit_types to friendly names | ||
255 | console.log([ | ||
256 | 'unspecified', | ||
257 | 'slice_layer_without_partitioning', | ||
258 | 'slice_data_partition_a_layer', | ||
259 | 'slice_data_partition_b_layer', | ||
260 | 'slice_data_partition_c_layer', | ||
261 | 'slice_layer_without_partitioning_idr', | ||
262 | 'sei', | ||
263 | 'seq_parameter_set', | ||
264 | 'pic_parameter_set', | ||
265 | 'access_unit_delimiter', | ||
266 | 'end_of_seq', | ||
267 | 'end_of_stream', | ||
268 | 'filler', | ||
269 | 'seq_parameter_set_ext', | ||
270 | 'prefix_nal_unit', | ||
271 | 'subset_seq_parameter_set', | ||
272 | 'reserved', | ||
273 | 'reserved', | ||
274 | 'reserved' | ||
275 | ][nalUnitType]); | ||
276 | </script> | ||
277 | </body> | ||
278 | </html> |
test/muxer/js/main.js
deleted
100644 → 0
test/muxer/js/mdat.js
deleted
100644 → 0
This diff is collapsed.
Click to expand it.
test/muxer/js/mp4-inspector.js
deleted
100644 → 0
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
test/muxer/min-m4s.js
deleted
100644 → 0
This diff is collapsed.
Click to expand it.
test/muxer/mp4.html
deleted
100644 → 0
This diff is collapsed.
Click to expand it.
test/muxer/mse-demo.html
deleted
100644 → 0
1 | <!DOCTYPE html> | ||
2 | <!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]--> | ||
3 | <!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]--> | ||
4 | <!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]--> | ||
5 | <!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]--> | ||
6 | <head> | ||
7 | <meta charset="utf-8"> | ||
8 | <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | ||
9 | <title>HLS Media Sources Demo</title> | ||
10 | <meta name="description" content=""> | ||
11 | <meta name="viewport" content="width=device-width"> | ||
12 | |||
13 | <link rel="stylesheet" href="css/normalize.min.css"> | ||
14 | <link rel="stylesheet" href="css/main.css"> | ||
15 | |||
16 | <script src="js/vendor/modernizr-2.6.2.min.js"></script> | ||
17 | </head> | ||
18 | <body> | ||
19 | <!--[if lt IE 7]> | ||
20 | <p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> or <a href="http://www.google.com/chromeframe/?redirect=true">activate Google Chrome Frame</a> to improve your experience.</p> | ||
21 | <![endif]--> | ||
22 | |||
23 | <div class="header-container"> | ||
24 | <header class="wrapper clearfix"> | ||
25 | <h1 class="title">Media Sources Demo</h1> | ||
26 | </header> | ||
27 | </div> | ||
28 | |||
29 | <div class="main-container"> | ||
30 | <div class="main wrapper clearfix"> | ||
31 | |||
32 | <article> | ||
33 | <header> | ||
34 | <p> | ||
35 | videojs-contrib-hls can convert MPEG transport streams | ||
36 | into Media Source Extension-compatible media segments on | ||
37 | the fly. Check out the demo below in Chrome! | ||
38 | </p> | ||
39 | </header> | ||
40 | <section> | ||
41 | <video id=demo width=640 height=360 controls> | ||
42 | <p> | ||
43 | Your browser is too old to view this demo. How about | ||
44 | upgrading? | ||
45 | </p> | ||
46 | </video> | ||
47 | </section> | ||
48 | </article> | ||
49 | |||
50 | </div> <!-- #main --> | ||
51 | </div> <!-- #main-container --> | ||
52 | |||
53 | <div class="footer-container"> | ||
54 | <footer class="wrapper"> | ||
55 | </footer> | ||
56 | </div> | ||
57 | |||
58 | |||
59 | <script src="zencoder-haze-1.js"></script> | ||
60 | <!-- transmuxing --> | ||
61 | <script> | ||
62 | window.videojs = window.videojs || { | ||
63 | Hls: {} | ||
64 | }; | ||
65 | </script> | ||
66 | <script src="../../src/stream.js"></script> | ||
67 | <script src="../../src/mp4-generator.js"></script> | ||
68 | <script src="../../src/transmuxer.js"></script> | ||
69 | <script src="../../src/exp-golomb.js"></script> | ||
70 | <script src="js/mp4-inspector.js"></script> | ||
71 | |||
72 | <script src="../../src/bin-utils.js"></script> | ||
73 | <script> | ||
74 | var mediaSource = new MediaSource(), | ||
75 | demo = document.getElementById('demo'); | ||
76 | |||
77 | // setup the media source | ||
78 | mediaSource.addEventListener('sourceopen', function() { | ||
79 | var videoBuffer = mediaSource.addSourceBuffer('video/mp4;codecs=avc1.4d400d'), | ||
80 | audioBuffer = mediaSource.addSourceBuffer('audio/mp4;codecs=mp4a.40.2'), | ||
81 | transmuxer = new videojs.mp2t.Transmuxer(), | ||
82 | videoSegments = [], | ||
83 | audioSegments = []; | ||
84 | |||
85 | // expose the machinery for debugging | ||
86 | window.vjsMediaSource = mediaSource; | ||
87 | window.vjsSourceBuffer = videoBuffer; | ||
88 | window.vjsVideo = demo; | ||
89 | |||
90 | // transmux the MPEG-TS data to BMFF segments | ||
91 | transmuxer.on('data', function(segment) { | ||
92 | if (segment.type === 'video') { | ||
93 | videoSegments.push(segment); | ||
94 | } else { | ||
95 | audioSegments.push(segment); | ||
96 | } | ||
97 | }); | ||
98 | transmuxer.push(hazeVideo); | ||
99 | transmuxer.end(); | ||
100 | |||
101 | // buffer up the video data | ||
102 | videoBuffer.appendBuffer(videoSegments.shift().data); | ||
103 | videoBuffer.addEventListener('updateend', function() { | ||
104 | if (videoSegments.length) { | ||
105 | videoBuffer.appendBuffer(videoSegments.shift().data); | ||
106 | } | ||
107 | }); | ||
108 | |||
109 | // buffer up the audio data | ||
110 | audioBuffer.appendBuffer(audioSegments.shift().data); | ||
111 | audioBuffer.addEventListener('updateend', function() { | ||
112 | if (audioSegments.length) { | ||
113 | audioBuffer.appendBuffer(audioSegments.shift().data); | ||
114 | } | ||
115 | }); | ||
116 | }); | ||
117 | demo.src = URL.createObjectURL(mediaSource); | ||
118 | demo.addEventListener('error', console.log.bind(console)); | ||
119 | </script> | ||
120 | </body> | ||
121 | </html> |
test/muxer/parts.html
deleted
100644 → 0
1 | <!DOCTYPE html> | ||
2 | <!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]--> | ||
3 | <!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]--> | ||
4 | <!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]--> | ||
5 | <!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]--> | ||
6 | <head> | ||
7 | <meta charset="utf-8"> | ||
8 | <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | ||
9 | <title></title> | ||
10 | <meta name="description" content=""> | ||
11 | <meta name="viewport" content="width=device-width"> | ||
12 | |||
13 | <link rel="stylesheet" href="css/normalize.min.css"> | ||
14 | <link rel="stylesheet" href="css/main.css"> | ||
15 | |||
16 | <script src="js/vendor/modernizr-2.6.2.min.js"></script> | ||
17 | |||
18 | <script> | ||
19 | window.videojs = window.videojs || { | ||
20 | Hls: {} | ||
21 | }; | ||
22 | </script> | ||
23 | <!--<script src="min-m4s.js"></script>--> | ||
24 | <script src="./js/mdat.js"></script> | ||
25 | <script src="../../src/mp4-generator.js"></script> | ||
26 | </head> | ||
27 | <body> | ||
28 | <!--[if lt IE 7]> | ||
29 | <p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> or <a href="http://www.google.com/chromeframe/?redirect=true">activate Google Chrome Frame</a> to improve your experience.</p> | ||
30 | <![endif]--> | ||
31 | |||
32 | <div class="header-container"> | ||
33 | <header class="wrapper clearfix"> | ||
34 | <h1 class="title">Transmux Analyzer</h1> | ||
35 | </header> | ||
36 | </div> | ||
37 | |||
38 | <div class="main-container"> | ||
39 | <div class="main wrapper clearfix"> | ||
40 | |||
41 | <article> | ||
42 | <header> | ||
43 | <p> | ||
44 | This page will show a video player that loads a header of an mp4 followed by an mp4 segment. | ||
45 | </p> | ||
46 | </header> | ||
47 | <section> | ||
48 | <video controls autoplay width="320" height="240"></video> | ||
49 | </section> | ||
50 | </article> | ||
51 | |||
52 | </div> <!-- #main --> | ||
53 | </div> <!-- #main-container --> | ||
54 | |||
55 | <div class="footer-container"> | ||
56 | <footer class="wrapper"> | ||
57 | <h3></h3> | ||
58 | </footer> | ||
59 | </div> | ||
60 | |||
61 | |||
62 | |||
63 | |||
64 | |||
65 | <script> | ||
66 | var ms, | ||
67 | sourceBuffer, | ||
68 | video; | ||
69 | |||
70 | function closed() { | ||
71 | console.log("MediaSource Closed."); | ||
72 | } | ||
73 | |||
74 | var done = false; | ||
75 | function loadFragment() { | ||
76 | if (done) { | ||
77 | return; | ||
78 | } | ||
79 | |||
80 | console.log("LOAD FRAGMENT"); | ||
81 | |||
82 | var moov = videojs.mp4.moov(100, 600, 300, "video"); | ||
83 | var moof = videojs.mp4.moof([{trackId: 1}]); | ||
84 | var frag = Array.prototype.slice.call(moov); | ||
85 | frag = frag.concat(Array.prototype.slice.call(moof)); | ||
86 | frag = frag.concat(Array.prototype.slice.call(mdat)); | ||
87 | |||
88 | |||
89 | |||
90 | sourceBuffer.appendBuffer( new Uint8Array( frag ) ); | ||
91 | |||
92 | done = true; | ||
93 | |||
94 | } | ||
95 | |||
96 | function loadMdat(){ | ||
97 | console.log('mdat', mdat); | ||
98 | setTimeout( function(){ | ||
99 | sourceBuffer.appendBuffer(new Uint8Amdat); | ||
100 | },0); | ||
101 | |||
102 | } | ||
103 | |||
104 | function loadInit() { | ||
105 | console.log("LOAD INIT"); | ||
106 | var req = new XMLHttpRequest(); | ||
107 | req.responseType = "arraybuffer"; | ||
108 | req.open("GET", "./ts2/Header.m4s", true); | ||
109 | |||
110 | req.onload = function() { | ||
111 | console.log("INIT DONE LOADING"); | ||
112 | sourceBuffer.appendBuffer(new Uint8Array(req.response)); | ||
113 | sourceBuffer.addEventListener('update', loadFragment); | ||
114 | }; | ||
115 | |||
116 | req.onerror = function () { | ||
117 | window.alert("Could not load init."); | ||
118 | }; | ||
119 | |||
120 | req.send(); | ||
121 | |||
122 | } | ||
123 | |||
124 | function opened() { | ||
125 | |||
126 | console.log("OPENED"); | ||
127 | sourceBuffer = ms.addSourceBuffer('video/mp4;codecs="avc1.42c00d"'); | ||
128 | |||
129 | sourceBuffer.addEventListener('updateend', console.log.bind(console)); | ||
130 | sourceBuffer.addEventListener('updatestart', console.log.bind(console)); | ||
131 | sourceBuffer.addEventListener('update', console.log.bind(console)); | ||
132 | loadInit(); | ||
133 | } | ||
134 | |||
135 | function load() { | ||
136 | console.log("START"); | ||
137 | window.MediaSource = window.MediaSource || window.WebKitMediaSource; | ||
138 | |||
139 | ms = new window.MediaSource(); | ||
140 | |||
141 | video = document.querySelector('video'); | ||
142 | video.src = window.URL.createObjectURL(ms); | ||
143 | |||
144 | ms.addEventListener('webkitsourceopen', opened, false); | ||
145 | ms.addEventListener('webkitsourceclose', closed, false); | ||
146 | |||
147 | ms.addEventListener('sourceopen', opened, false); | ||
148 | ms.addEventListener('sourceclose', closed, false); | ||
149 | |||
150 | ms.addEventListener('update', console.log.bind(console)); | ||
151 | ms.addEventListener('updateend', console.log.bind(console)); | ||
152 | } | ||
153 | load(); | ||
154 | </script> | ||
155 | </body> | ||
156 | </html> |
test/muxer/player.html
deleted
100644 → 0
1 | <!DOCTYPE html> | ||
2 | <!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]--> | ||
3 | <!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]--> | ||
4 | <!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]--> | ||
5 | <!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]--> | ||
6 | <head> | ||
7 | <meta charset="utf-8"> | ||
8 | <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | ||
9 | <title></title> | ||
10 | <meta name="description" content=""> | ||
11 | <meta name="viewport" content="width=device-width"> | ||
12 | |||
13 | <link rel="stylesheet" href="css/normalize.min.css"> | ||
14 | <link rel="stylesheet" href="css/main.css"> | ||
15 | |||
16 | <script src="js/vendor/modernizr-2.6.2.min.js"></script> | ||
17 | </head> | ||
18 | <body> | ||
19 | <!--[if lt IE 7]> | ||
20 | <p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> or <a href="http://www.google.com/chromeframe/?redirect=true">activate Google Chrome Frame</a> to improve your experience.</p> | ||
21 | <![endif]--> | ||
22 | |||
23 | <div class="header-container"> | ||
24 | <header class="wrapper clearfix"> | ||
25 | <h1 class="title">MP4 Media Sources API Test</h1> | ||
26 | </header> | ||
27 | </div> | ||
28 | |||
29 | <div class="main-container"> | ||
30 | <div class="main wrapper clearfix"> | ||
31 | |||
32 | <article> | ||
33 | <header> | ||
34 | <p> | ||
35 | This page is used to demo the playing of an mp4 file via the mediaSources API | ||
36 | </p> | ||
37 | </header> | ||
38 | <section> | ||
39 | <h2>Inputs</h2> | ||
40 | <form id="inputs"> | ||
41 | <label> | ||
42 | Your original MP2T segment: | ||
43 | <input type="file" id="original"> | ||
44 | </label> | ||
45 | <label> | ||
46 | A working, MP4 version of the underlying stream | ||
47 | produced by another tool: | ||
48 | <input type="file" id="working"> | ||
49 | </label> | ||
50 | </form> | ||
51 | </section> | ||
52 | <section> | ||
53 | |||
54 | <video controls width="320" height="240">> | ||
55 | <source src="sintel_trailer-480p.mp4" type="video/mp4"> | ||
56 | Your browser does not support the <code>video</code> element. | ||
57 | </video> | ||
58 | </section> | ||
59 | </article> | ||
60 | |||
61 | </div> <!-- #main --> | ||
62 | </div> <!-- #main-container --> | ||
63 | |||
64 | <div class="footer-container"> | ||
65 | <footer class="wrapper"> | ||
66 | <h3></h3> | ||
67 | </footer> | ||
68 | </div> | ||
69 | |||
70 | <script> | ||
71 | var inputs = document.getElementById('inputs'), | ||
72 | original = document.getElementById('original'), | ||
73 | working = document.getElementById('working'), | ||
74 | |||
75 | video = document.createElement('video'); | ||
76 | |||
77 | |||
78 | working.addEventListener('change', function() { | ||
79 | console.log('File Selectd'); | ||
80 | var reader = new FileReader(); | ||
81 | reader.addEventListener('loadend', function() { | ||
82 | console.log('File has been loaded'); | ||
83 | var bytes = new Uint8Array(reader.result), | ||
84 | ms = new window.MediaSource(), | ||
85 | video = document.querySelector('video'); | ||
86 | |||
87 | video.addEventListener("error", function onError(err) { | ||
88 | console.dir("error", err, video.error); | ||
89 | }); | ||
90 | |||
91 | video.pause(); | ||
92 | video.src = window.URL.createObjectURL(ms); | ||
93 | |||
94 | var onMediaSourceOpen = function() { | ||
95 | console.log('on media open'); | ||
96 | ms.removeEventListener('sourceopen', onMediaSourceOpen); | ||
97 | var videoBuffer = ms.addSourceBuffer('video/mp4;codecs="avc1.4D400D"'); | ||
98 | videoBuffer.appendBuffer(bytes); | ||
99 | |||
100 | var audioBuffer = ms.addSourceBuffer('audio/mp4;codecs=mp4a.40.2'); | ||
101 | }; | ||
102 | |||
103 | ms.addEventListener('sourceopen', onMediaSourceOpen); | ||
104 | |||
105 | console.log('appended bytes', bytes); | ||
106 | }); | ||
107 | reader.readAsArrayBuffer(this.files[0]); | ||
108 | }); | ||
109 | |||
110 | </script> | ||
111 | |||
112 | </body> | ||
113 | </html> |
test/muxer/ts2/Header_boxes.json
deleted
100644 → 0
1 | [ | ||
2 | { | ||
3 | "type": "ftyp" | ||
4 | }, | ||
5 | { | ||
6 | "type": "free" | ||
7 | }, | ||
8 | { | ||
9 | "boxes": [ | ||
10 | { | ||
11 | "type": "mvhd" | ||
12 | }, | ||
13 | { | ||
14 | "boxes": [ | ||
15 | { | ||
16 | "type": "mehd" | ||
17 | }, | ||
18 | { | ||
19 | "type": "trex" | ||
20 | } | ||
21 | ], | ||
22 | "type": "mvex" | ||
23 | }, | ||
24 | { | ||
25 | "boxes": [ | ||
26 | { | ||
27 | "type": "tkhd" | ||
28 | }, | ||
29 | { | ||
30 | "boxes": [ | ||
31 | { | ||
32 | "type": "mdhd" | ||
33 | }, | ||
34 | { | ||
35 | |||
36 | "type": "hdlr" | ||
37 | }, | ||
38 | { | ||
39 | "boxes": [ | ||
40 | { | ||
41 | "type": "vmhd" | ||
42 | }, | ||
43 | { | ||
44 | "boxes": [ | ||
45 | { | ||
46 | "dataReferences": [ | ||
47 | { | ||
48 | "type": "url " | ||
49 | } | ||
50 | ], | ||
51 | "type": "dref" | ||
52 | } | ||
53 | ], | ||
54 | "type": "dinf" | ||
55 | }, | ||
56 | { | ||
57 | "boxes": [ | ||
58 | { | ||
59 | "sampleDescriptions": [ | ||
60 | { | ||
61 | "config": [ | ||
62 | { | ||
63 | "type": "avcC" | ||
64 | }, | ||
65 | { | ||
66 | "type": "btrt" | ||
67 | } | ||
68 | ], | ||
69 | "type": "avc1" | ||
70 | } | ||
71 | ], | ||
72 | "type": "stsd" | ||
73 | }, | ||
74 | { | ||
75 | "type": "stts" | ||
76 | }, | ||
77 | { | ||
78 | "type": "stsc" | ||
79 | }, | ||
80 | { | ||
81 | "type": "stsz" | ||
82 | }, | ||
83 | { | ||
84 | "type": "stco" | ||
85 | } | ||
86 | ], | ||
87 | "type": "stbl" | ||
88 | } | ||
89 | ], | ||
90 | "type": "minf" | ||
91 | } | ||
92 | ], | ||
93 | "type": "mdia" | ||
94 | } | ||
95 | ], | ||
96 | "type": "trak" | ||
97 | } | ||
98 | ], | ||
99 | "type": "moov" | ||
100 | } | ||
101 | ] | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
test/muxer/zencoder-haze-1.js
deleted
100644 → 0
This diff could not be displayed because it is too large.
test/segment-parser.js
deleted
100644 → 0
This diff is collapsed.
Click to expand it.
test/transmuxer_test.js
deleted
100644 → 0
This diff is collapsed.
Click to expand it.
... | @@ -19,13 +19,6 @@ | ... | @@ -19,13 +19,6 @@ |
19 | <script src="../src/videojs-hls.js"></script> | 19 | <script src="../src/videojs-hls.js"></script> |
20 | <script src="../src/xhr.js"></script> | 20 | <script src="../src/xhr.js"></script> |
21 | <script src="../src/stream.js"></script> | 21 | <script src="../src/stream.js"></script> |
22 | <script src="../src/flv-tag.js"></script> | ||
23 | <script src="../src/exp-golomb.js"></script> | ||
24 | <script src="../src/h264-extradata.js"></script> | ||
25 | <script src="../src/h264-stream.js"></script> | ||
26 | <script src="../src/aac-stream.js"></script> | ||
27 | <script src="../src/metadata-stream.js"></script> | ||
28 | <script src="../src/segment-parser.js"></script> | ||
29 | 22 | ||
30 | <!-- M3U8 --> | 23 | <!-- M3U8 --> |
31 | <script src="../src/m3u8/m3u8-parser.js"></script> | 24 | <script src="../src/m3u8/m3u8-parser.js"></script> |
... | @@ -42,11 +35,6 @@ | ... | @@ -42,11 +35,6 @@ |
42 | <script src="tsSegment-bc.js"></script> | 35 | <script src="tsSegment-bc.js"></script> |
43 | <script src="../src/bin-utils.js"></script> | 36 | <script src="../src/bin-utils.js"></script> |
44 | 37 | ||
45 | <!-- mp4 utilities --> | ||
46 | <script src="../src/mp4-generator.js"></script> | ||
47 | <script src="../src/transmuxer.js"></script> | ||
48 | <script src="muxer/js/mp4-inspector.js"></script> | ||
49 | |||
50 | <!-- Test cases --> | 38 | <!-- Test cases --> |
51 | <script> | 39 | <script> |
52 | module('environment'); | 40 | module('environment'); |
... | @@ -56,18 +44,10 @@ | ... | @@ -56,18 +44,10 @@ |
56 | }); | 44 | }); |
57 | </script> | 45 | </script> |
58 | <script src="videojs-hls_test.js"></script> | 46 | <script src="videojs-hls_test.js"></script> |
59 | <script src="segment-parser.js"></script> | ||
60 | <script src="h264-stream_test.js"></script> | ||
61 | <script src="exp-golomb_test.js"></script> | ||
62 | <script src="flv-tag_test.js"></script> | ||
63 | <script src="metadata-stream_test.js"></script> | ||
64 | <script src="m3u8_test.js"></script> | 47 | <script src="m3u8_test.js"></script> |
65 | <script src="playlist_test.js"></script> | 48 | <script src="playlist_test.js"></script> |
66 | <script src="playlist-loader_test.js"></script> | 49 | <script src="playlist-loader_test.js"></script> |
67 | <script src="decrypter_test.js"></script> | 50 | <script src="decrypter_test.js"></script> |
68 | <script src="transmuxer_test.js"></script> | ||
69 | <script src="mp4-inspector_test.js"></script> | ||
70 | <script src="mp4-generator_test.js"></script> | ||
71 | </head> | 51 | </head> |
72 | <body> | 52 | <body> |
73 | <div id="qunit"></div> | 53 | <div id="qunit"></div> | ... | ... |
-
Please register or sign in to post a comment