Changeset 1484
- Timestamp:
- 12/09/10 09:31:59 (2 years ago)
- Location:
- providers/adaptive
- Files:
-
- 4 added
- 1 deleted
- 6 edited
- 1 moved
-
adaptive.swf (modified) (previous)
-
doc/index.rst (modified) (1 diff)
-
src/com/longtailvideo/jwplayer/media/AdaptiveProvider.as (modified) (2 diffs)
-
src/com/longtailvideo/jwplayer/muxing (moved) (moved from providers/adaptive/src/com/longtailvideo/jwplayer/demux)
-
src/com/longtailvideo/jwplayer/muxing/AAC.as (added)
-
src/com/longtailvideo/jwplayer/muxing/FLV.as (modified) (4 diffs)
-
src/com/longtailvideo/jwplayer/muxing/FLVTag.as (added)
-
src/com/longtailvideo/jwplayer/muxing/H264.as (added)
-
src/com/longtailvideo/jwplayer/muxing/ISMV.as (added)
-
src/com/longtailvideo/jwplayer/muxing/MP4.as (deleted)
-
src/com/longtailvideo/jwplayer/muxing/PES.as (modified) (4 diffs)
-
src/com/longtailvideo/jwplayer/muxing/TS.as (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
providers/adaptive/doc/index.rst
r1449 r1484 1 HTTP Live Streamingprovider2 ================= ===========1 Adaptive provider 2 ================= 3 3 4 This custom media provider leverages the HTTP Live Streaming protocol:4 This custom media provider intends to add suppport to: 5 5 6 * Parsing of M3U8 manifests 7 * Demuxing of MPPEG-TS streams 6 * Apple HTTP Live Streaming (by parsing M3U8 files and transmuxing MPEG TS files) 7 * Microsoft Smooth Streaming (by parsing ISMC files and transmuxing ISMV files) 8 9 Flash player 10.1 is required for the transmuxed data to play back. 10 11 Only Smooth streams using H264 video can be supported. VC-1 streams cannot be decoded in Flash. 12 13 http://learn.iis.net/page.aspx/792/adaptive-streaming-comparison/ 14 15 16 References 17 ========== 18 19 MPEG TS 20 ------- 21 22 TS, PAT, PMT and PES: 23 24 http://en.wikipedia.org/wiki/MPEG_transport_stream 25 26 27 28 H264 29 ---- 30 31 H264, NAL, SPS/PPS and avcC: 32 33 http://en.wikipedia.org/wiki/H.264/MPEG-4_AVC 34 http://en.wikipedia.org/wiki/Network_Abstraction_Layer 35 http://www.javvin.com/protocolH264.html 36 http://wiki.multimedia.cx/index.php?title=H.264 37 38 AAC 39 --- 40 41 AAC, ADTS and ADIF: 42 43 http://en.wikipedia.org/wiki/Advanced_Audio_Coding 44 http://wiki.multimedia.cx/index.php?title=ADTS 45 http://wiki.multimedia.cx/index.php?title=MPEG-4_Audio 46 47 48 M3U8 49 ---- 50 51 M3U8 manifests: 52 53 http://tools.ietf.org/html/draft-pantos-http-live-streaming-04 8 54 9 55 10 56 11 57 12 MPEG-TS Parsing Tree 13 ---- ----------------58 ISMV 59 ---- 14 60 15 Excerpt from the draft:61 ISMC manifests and ISMV MP4 fragments: 16 62 17 Each media file URI in a Playlist file MUST identify a media file 18 which is a segment of the overall presentation. Each media file MUST 19 be formatted as an MPEG-2 Transport Stream or an MPEG-2 audio 20 elementary stream [ISO_13818]. 21 22 Transport Stream files MUST contain a single MPEG-2 Program. There 23 SHOULD be a Program Association Table and a Program Map Table at the 24 start of each file. A file that contains video SHOULD have at least 25 one key frame and enough information to completely initialize a video 26 decoder. 63 http://wiki.multimedia.cx/index.php?title=MP4 64 http://learn.iis.net/page.aspx/626/smooth-streaming-technical-overview/ 27 65 28 66 29 F ormat specs30 --- ---------67 FLV 68 --- 31 69 32 http://en.wikipedia.org/wiki/MPEG_transport_stream 33 34 http://tools.ietf.org/html/draft-pantos-http-live-streaming-04 70 FLV files, FLV tags and loading into actionscript: 35 71 36 72 http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf 37 38 http://help.adobe.com/en_US/FlashPlatform/beta/reference/actionscript/3/flash/net/NetStream.html -
providers/adaptive/src/com/longtailvideo/jwplayer/media/AdaptiveProvider.as
r1476 r1484 2 2 3 3 4 import com.longtailvideo.jwplayer.demux.*;5 4 import com.longtailvideo.jwplayer.events.MediaEvent; 6 5 import com.longtailvideo.jwplayer.media.MediaProvider; … … 8 7 import com.longtailvideo.jwplayer.model.PlaylistItem; 9 8 import com.longtailvideo.jwplayer.player.PlayerState; 9 import com.longtailvideo.jwplayer.muxing.*; 10 10 import com.longtailvideo.jwplayer.utils.*; 11 11 -
providers/adaptive/src/com/longtailvideo/jwplayer/muxing/FLV.as
r1476 r1484 1 package com.longtailvideo.jwplayer. demux{1 package com.longtailvideo.jwplayer.muxing { 2 2 3 3 4 4 import com.longtailvideo.jwplayer.utils.Logger; 5 import com.longtailvideo.jwplayer. demux.*;5 import com.longtailvideo.jwplayer.muxing.*; 6 6 import flash.utils.ByteArray; 7 7 … … 25 25 var flv:ByteArray = new ByteArray(); 26 26 _writeHeader(flv); 27 // Sort the tags by timestamp .27 // Sort the tags by timestamp; private data first. 28 28 _tags.sortOn( 29 [' isPrivate','timestamp','isAudio'],30 [Array.NUMERIC | Array.DESCENDING, Array.NUMERIC, Array.NUMERIC]29 ['timestamp','isPrivate'], 30 [Array.NUMERIC, Array.NUMERIC | Array.DESCENDING] 31 31 ); 32 //var stt:Number = _tags[0].timestamp;32 var stt:Number = _tags[0].timestamp; 33 33 // Append all tags 34 34 var pos:Number = flv.position; 35 35 for(var i:Number=0; i<_tags.length; i++) { 36 36 // Set the timestamps zero-indexed. 37 //_tags[i].timestamp -= stt;37 _tags[i].timestamp -= stt; 38 38 // The Tag itself. 39 39 flv.writeBytes(_tags[i].data); … … 49 49 50 50 /** Push an FLV tag into the FLV file. **/ 51 public function push(tag: Tag):void {51 public function push(tag:FLVTag):void { 52 52 _tags.push(tag); 53 53 }; … … 56 56 /** Write end-of-sequence FLV tag. **/ 57 57 private function _writeEOSTag(tag:ByteArray):void { 58 var tsp:Number = _tags[_tags.length-1].timestamp;59 tag.writeByte(9);60 58 // Size of the tag in bytes after StreamID. 61 tag.writeByte(5 >> 16); 62 tag.writeByte(5 >> 8); 63 tag.writeByte(5); 59 tag.writeUnsignedInt(0x09000005); 64 60 // Timestamp (lower 24 plus upper 8) 61 var tsp:Number = _tags[_tags.length-1].timestamp + 1; 65 62 tag.writeByte(tsp >> 16); 66 63 tag.writeByte(tsp >> 8); 67 64 tag.writeByte(tsp); 68 65 tag.writeByte(tsp >> 24); 69 // StreamID (3 empty bytes) 70 tag.writeByte(0); 71 tag.writeByte(0); 72 tag.writeByte(0); 73 // Keyframe + AVC 74 tag.writeByte(0x17); 75 //Sequence end 76 tag.writeByte(0x02); 77 // Composition time. 78 tag.writeByte(0); 79 tag.writeByte(0); 80 tag.writeByte(0); 66 // StreamID (3 empty bytes), Keyframe, AVC. 67 tag.writeUnsignedInt(0x00000017); 68 //Sequence end, composition time 69 tag.writeUnsignedInt(0x02000000); 81 70 // PreviousTagSize 82 tag.writeUnsignedInt( 16);71 tag.writeUnsignedInt(0x00000016); 83 72 }; 84 73 -
providers/adaptive/src/com/longtailvideo/jwplayer/muxing/PES.as
r1476 r1484 1 package com.longtailvideo.jwplayer. demux{1 package com.longtailvideo.jwplayer.muxing { 2 2 3 3 4 import com.longtailvideo.jwplayer. demux.*;4 import com.longtailvideo.jwplayer.muxing.*; 5 5 import com.longtailvideo.jwplayer.utils.Logger; 6 6 import flash.utils.ByteArray; … … 43 43 _flv = flv; 44 44 _data.position = 0; 45 _parseHeader();46 };47 48 49 /** Parse the ADTS header and store FLV tag. **/50 private function _parseADTS():void {51 var dat:ByteArray = new ByteArray();52 // Syncword, ID, Layer and PA should be 0xFFF1.53 if(_data.readUnsignedShort() == 65521) {54 // ADIF zero index is null; ADTS not.55 var profile:uint = (_data.readByte() >> 6) + 1;56 _data.position--;57 var samplerate:uint = (_data.readByte() & 0x3C) >> 2;58 _data.position--;59 var channels:uint = (_data.readShort() & 0x01C0) >> 6;60 _data.position -= 4;61 // 5 bits profile + 4 bits samplerate + 4 bits channels.62 dat.writeByte((profile << 3) + (samplerate >> 1));63 dat.writeByte((samplerate << 7) + (channels << 3));64 _flv.push(new Tag(dat,Math.round(_pts/90), true, true));65 } else {66 throw new Error("ADTS data not found in PES.");67 }68 };69 70 71 /** Filter out ADTS headers and store FLV tag. **/72 private function _parseAudio():void {73 var pos:Number = 0;74 var dat:ByteArray;75 while(_data.bytesAvailable > 1) {76 // ADTS header: Syncword, ID, Layer and PA should be 0xFFF1.77 if(_data.readUnsignedShort() == 65521) {78 // Write raw AAC preceding this header into FLVTag.79 if(pos) {80 dat = new ByteArray();81 dat.writeBytes(_data, pos , _data.position - pos - 1);82 // Saving raw AAC in one tag by just slicing ADTS caused speed-ups.83 _flv.push(new Tag(dat, Math.round(_pts/90), true));84 }85 // ADTS header is 7 bytes.86 _data.position += 5;87 pos = _data.position;88 } else {89 _data.position--;90 }91 }92 // Write raw AAC after last header.93 dat = new ByteArray();94 dat.writeBytes(_data, pos);95 _flv.push(new Tag(dat, Math.round(_pts/90), true));96 };97 98 99 /** Parse the header of a PES. **/100 private function _parseHeader():void {101 45 // Start code prefix and packet ID. 102 46 if((_isAudio && _data.readUnsignedInt() != 448) || … … 130 74 _data.position += len; 131 75 if(_isAudio) { 132 if(_isFirst) {133 _parseADTS();134 }135 76 _parseAudio(); 136 77 } else { … … 140 81 141 82 142 /** Step through AVC to extract NAL units. **/ 143 private function _parseVideo():void { 144 var units:Array = new Array(); 145 var window:uint = 0; 146 var started:Number = 0; 147 148 // Loop through data to find NAL startcode. 149 while(_data.bytesAvailable > 3) { 150 window = _data.readUnsignedInt(); 151 // Find startcodes 152 if((window & 0xFFFFFF00) == 0x100) { 153 _data.position -= 5; 154 var four:uint = _data.readByte(); 155 _data.position += 3; 156 var head:uint = _data.readByte(); 157 // Now we know the length of the previous NAL 158 if(started) { 159 var size:Number = _data.position - started - 4; 160 if(!four) { size--; } 161 units.push(new ByteArray()); 162 units[units.length-1].writeBytes(_data,started,size); 163 units[units.length-1].position = 0; 164 } 165 started = _data.position - 1; 166 } 167 _data.position -= 3; 168 } 169 170 // Save the last NAL to the array. 171 if(started) { 172 units.push(new ByteArray()); 173 units[units.length-1].writeBytes(_data, started); 174 units[units.length-1].position = 0; 175 } else { 176 return; 177 throw new Error('No NAL units found.'); 178 } 179 180 // Separate the SPS/PPS and add size headers to other NALs 181 var nalu:ByteArray = new ByteArray(); 182 var sps:ByteArray = new ByteArray(); 183 var pps:ByteArray = new ByteArray(); 184 for(var i:Number = 0; i < units.length; i++) { 185 units[i].position = 0; 186 var type:Number = units[i].readByte() & 0x1F; 187 if(type == 7) { 188 sps.writeBytes(units[i],0); 189 } else if (type == 8) { 190 pps.writeBytes(units[i],0); 191 } else { 192 // Instead of a startcode, NAL units need a 4-byte length prefix. 193 nalu.writeUnsignedInt(units[i].length); 194 nalu.writeBytes(units[i],0); 195 } 196 } 197 198 // Finally, write the tags 83 /** Parse ADTS streams for audio tags. **/ 84 private function _parseAudio():void { 85 // Get ADIF header if this is the first audio stream. 199 86 if(_isFirst) { 200 if(sps.length && pps.length) { 201 _parseSpsPps(sps,pps); 202 } 203 _flv.push(new Tag( 204 nalu, 205 Math.round(_pts/90), 206 false, 207 false, 87 _flv.push(new FLVTag( 88 AAC.getADIF(_data), 89 Math.round(_pts/90), 90 true, 208 91 true 209 92 )); 210 } else {211 _flv.push(new Tag(212 nalu,213 Math.round(_pts/90),214 false,215 false,216 false217 ));93 } 94 // Get AAC frames. 95 var samplerate:uint = AAC.getSamplerate(_data); 96 var frames:Array = AAC.getFrames(_data); 97 for(var i:Number = 0; i<frames.length; i++) { 98 // Increment the timestamp of subsequent frames. 99 var tsp:uint = Math.round(_pts/90 + i*1024*1000/samplerate); 100 _flv.push(new FLVTag(frames[i], Math.round(_pts/90), true)); 218 101 } 219 102 }; 220 103 221 104 222 /** Parse the SPS and PPS data into avcC. **/ 223 private function _parseSpsPps(sps:ByteArray,pps:ByteArray):void { 224 var dat:ByteArray = new ByteArray(); 225 // avcC version. 226 dat.writeByte(0x01); 227 // profile, compatibility and level. 228 dat.writeBytes(sps, 1, 3); 229 // 111111 + 2 bit NAL size - 11 230 dat.writeByte(0xFF); 231 // Number of SPS. 232 dat.writeByte(0xE1); 233 // SPS bytesize (UI16) 234 dat.writeByte(sps.length >> 8); 235 dat.writeByte(sps.length); 236 // SPS data block. 237 dat.writeBytes(sps,0); 238 // Number of PPS 239 dat.writeByte(0x01); 240 // PPS bytesize 241 dat.writeByte(pps.length >> 8); 242 dat.writeByte(pps.length); 243 // PPS data block. 244 dat.writeBytes(pps,0); 245 _flv.push(new Tag( 246 dat, 247 Math.round(_pts/90), 248 false, 249 true, 250 true 105 /** Step through AVC to extract NAL units. **/ 106 private function _parseVideo():void { 107 // Get AVCC header if this is the first video stream. 108 if(_isFirst) { 109 _flv.push(new FLVTag( 110 H264.getAVCC(_data), 111 Math.round(_pts/90), 112 false, 113 true, 114 true, 115 Math.round((_pts-_dts)/90) 116 )); 117 } 118 // Get raw NALU data. 119 var nalu:ByteArray = new ByteArray(); 120 var units:Array = H264.getNALU(_data); 121 var unit_type:Number; 122 var is_keyframe:Boolean; 123 // Only push NAL units 1 to 6 into stream (5 is keyframe). 124 for(var i:Number = 0; i < units.length; i++) { 125 unit_type = units[i].readByte() & 0x1F; 126 if (unit_type < 6) { 127 // NAL's are separated by a 4 byte NAL length header. 128 nalu.writeUnsignedInt(units[i].length); 129 nalu.writeBytes(units[i]); 130 if(unit_type == 5) { 131 is_keyframe = true; 132 } 133 } 134 } 135 _flv.push(new FLVTag( 136 nalu, 137 Math.round(_pts/90), 138 false, 139 false, 140 is_keyframe, 141 Math.round((_pts-_dts)/90) 251 142 )); 252 143 }; 253 254 144 255 145 -
providers/adaptive/src/com/longtailvideo/jwplayer/muxing/TS.as
r1476 r1484 1 package com.longtailvideo.jwplayer. demux{1 package com.longtailvideo.jwplayer.muxing { 2 2 3 3 4 4 import com.longtailvideo.jwplayer.utils.Logger; 5 import com.longtailvideo.jwplayer. demux.*;5 import com.longtailvideo.jwplayer.muxing.*; 6 6 import flash.utils.ByteArray; 7 7 … … 9 9 /** Representation of an MPEG transport stream. **/ 10 10 public class TS { 11 12 13 /** TS Sync byte. **/ 14 public static const SYNC_BYTE:uint = 0x47; 15 16 17 /** TS Packet size in byte. **/ 18 public static const PACKET_SIZE:uint = 188; 11 19 12 20 … … 50 58 private function _readPacket(dat:ByteArray):void { 51 59 // Each packet is 188 bytes. 52 var todo:uint = 188;60 var todo:uint = TS.PACKET_SIZE; 53 61 // Sync byte. 54 if(dat.readByte() != 0x47) {62 if(dat.readByte() != TS.SYNC_BYTE) { 55 63 throw new Error("Could not parse TS file: sync byte not found."); 56 64 } … … 65 73 var atf:uint = (dat.readByte() & 48) >> 4; 66 74 todo --; 67 68 75 // Read adaptation field if available. 69 76 if(atf > 1) { … … 76 83 todo -= len; 77 84 // Return if there's only adaptation field. 78 if(atf == 2) { 85 if(atf == 2) { 79 86 dat.position += todo; 80 return; 81 } 87 return; 88 } 82 89 } 83 90 … … 111 118 if(_lastAvc == -1) { 112 119 _pesArray.push(new PES(pes,false,true)); 113 } else { 114 _pesArray.push(new PES(pes,false ,Boolean(rai)));120 } else { 121 _pesArray.push(new PES(pes,false)); 115 122 } 116 123 _lastAvc = _pesArray.length-1; … … 123 130 break; 124 131 } 125 126 132 // Jump to the next packet. 127 133 dat.position += todo; … … 143 149 144 150 145 /** Read the Program Map Table. **/ 146 private function _readPMT(dat:ByteArray):Number { 151 /** Read the Program Map Table. **/ 152 private function _readPMT(dat:ByteArray):Number { 147 153 // Check the section length for a single PMT. 148 154 dat.position += 3; 149 var len:uint = dat.read UnsignedByte();155 var len:uint = dat.readByte(); 150 156 dat.position += 9; 151 157 // Loop through the streams in the PMT. 152 for(var i:Number = 0; i < (len - 13) / 5; i++) {153 var typ:uint = dat.read UnsignedByte();154 if(typ == 0x0F) { 158 for(var i:Number=0; i<2; i++) { 159 var typ:uint = dat.readByte(); 160 if(typ == 0x0F) { 155 161 _aacId = dat.readUnsignedShort() & 8191; 156 } else if (typ == 0x1B) { 162 } else if (typ == 0x1B) { 157 163 _avcId = dat.readUnsignedShort() & 8191; 158 164 } else { 159 165 throw new Error("Only AAC audio and AVC video are supported."); 160 166 } 161 dat.position += 2; 167 dat.position ++; 168 // Possible section length. 169 var sel:uint = dat.readByte(); 170 dat.position += sel; 162 171 } 163 172 return len;
Note: See TracChangeset
for help on using the changeset viewer.
