├── .gitignore ├── LICENSE ├── README.md └── src ├── cc └── minos │ └── codec │ ├── Binary.as │ ├── Codec.as │ ├── flv │ ├── FlvCodec.as │ └── Frame.as │ ├── mkv │ ├── Mkv.as │ ├── MkvCodec.as │ ├── MkvFrame.as │ └── elements │ │ ├── AudioTrack.as │ │ ├── Cluster.as │ │ ├── ContentEncoding.as │ │ ├── ContentEncodings.as │ │ ├── CuePoint.as │ │ ├── CuePosition.as │ │ ├── Cues.as │ │ ├── EbmlHeader.as │ │ ├── Element.as │ │ ├── GlobalElement.as │ │ ├── Seek.as │ │ ├── SeekHead.as │ │ ├── Segment.as │ │ ├── SegmentInfo.as │ │ ├── SegmentTracks.as │ │ ├── TrackEntry.as │ │ ├── VarElement.as │ │ └── VideoTrack.as │ ├── mp4 │ ├── Mp4.as │ ├── Mp4Codec.as │ ├── Sample.as │ └── boxs │ │ ├── Box.as │ │ ├── CttsBox.as │ │ ├── FtypBox.as │ │ ├── HdlrBox.as │ │ ├── MdatBox.as │ │ ├── MdhdBox.as │ │ ├── MoovBox.as │ │ ├── MvhdBox.as │ │ ├── StblBox.as │ │ ├── StcoBox.as │ │ ├── StscBox.as │ │ ├── StsdBox.as │ │ ├── StssBox.as │ │ ├── StszBox.as │ │ ├── SttsBox.as │ │ ├── TkhdBox.as │ │ └── TrakBox.as │ └── utils │ ├── Hex.as │ ├── Log.as │ └── SimpleDateFormatter.as └── com └── hurlant ├── math ├── BigInteger.as └── bi_internal.as └── util ├── Hex.as └── Memory.as /.gitignore: -------------------------------------------------------------------------------- 1 | # Build and Release Folders 2 | bin/ 3 | bin-debug/ 4 | bin-release/ 5 | 6 | # Other files and folders 7 | .settings/ 8 | .idea/ 9 | codec-as3.iml 10 | 11 | # Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties` 12 | # should NOT be excluded as they contain compiler settings and other important 13 | # information for Eclipse / Flash Builder. 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 SiuzukZan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Codec-AS3 2 | ========= 3 | 4 | > 这个项目已经不再维护 5 | 6 | ## 说明 7 | 8 | `NetStream.appendBytes()`只支持FLV封裝的格式,在需要播放其他封裝的視頻的話,就必須將其他封裝格式轉成FLV的封裝。 9 | 10 | ## 格式 11 | 12 | - [MP4](http://xhelmboyx.tripod.com/formats/mp4-layout.txt) 13 | - [FLV](http://www.adobe.com/content/dam/Adobe/en/devnet/flv/pdfs/video_file_format_spec_v10.pdf) 14 | - [MKV](http://www.matroska.org/files/matroska.pdf) 15 | 16 | ## 使用 17 | 18 | ``` as3 19 | var mp4:Mp4Codec = new Mp4Codec(); 20 | mp4.decode(mp4bytes); 21 | var bytes:ByteArray = new FlvCodec().encode(mp4); 22 | ns.appendBytes(bytes); 23 | ``` 24 | 25 | ## 许可证 26 | 27 | MIT 28 | -------------------------------------------------------------------------------- /src/cc/minos/codec/Binary.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Created by SiuzukZan on 04/17/2015 16:45 4 | */ 5 | package cc.minos.codec { 6 | 7 | import flash.utils.ByteArray; 8 | 9 | public class Binary extends ByteArray { 10 | 11 | private var _bit:int; 12 | private var _currByte:uint; 13 | 14 | public function Binary(byte:ByteArray) 15 | { 16 | super(); 17 | this.writeBytes(byte); 18 | this.position = 0; 19 | byte.clear(); 20 | byte = null; 21 | _bit = -1; 22 | } 23 | 24 | public function readBit():uint 25 | { 26 | var res:uint; 27 | if (_bit == -1) 28 | { 29 | _currByte = this.readByte(); 30 | _bit = 7; 31 | } 32 | res = _currByte & (1 << _bit) ? 1 : 0; 33 | _bit--; 34 | return res; 35 | } 36 | 37 | public function readBits(nbBits:uint):int 38 | { 39 | var val:int = 0; 40 | for (var i:uint = 0; i < nbBits; ++i) 41 | val = (val << 1) + readBit(); 42 | return val; 43 | } 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/cc/minos/codec/Codec.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/24 10:58 5 | */ 6 | package cc.minos.codec { 7 | 8 | import cc.minos.codec.flv.Frame; 9 | import flash.utils.ByteArray; 10 | 11 | public class Codec extends Object { 12 | 13 | //封装类型 14 | protected var _name:String = ':)' 15 | //拓展 16 | protected var _extensions:String; 17 | //格式 18 | protected var _mimeType:String; 19 | //源數據 20 | protected var _rawData:ByteArray = null; 21 | 22 | //幀列表,包括視頻音頻 23 | protected var _frames:Vector. = new Vector.(); 24 | //關鍵幀列表 25 | protected var _keyframes:Array; 26 | 27 | //視頻 28 | protected var _hasVideo:Boolean = false; //是否有視頻數據 29 | protected var _videoConfig:ByteArray = null; //sps & pps 解析數據 30 | protected var _videoCodec:uint; //編碼類型 31 | protected var _videoWidth:Number = 0.0; //寬 32 | protected var _videoHeight:Number = 0.0; //高 33 | protected var _videoRate:Number; //比特率 34 | 35 | //幀頻fps 36 | protected var _frameRate:Number = 0.0; 37 | 38 | //音頻 39 | protected var _hasAudio:Boolean = false; //是否有音頻 40 | protected var _audioConfig:ByteArray = null; //音頻解析數據 41 | protected var _audioCodec:uint; //編碼類型 42 | protected var _audioType:uint = 10; //音頻類型 43 | protected var _audioRate:Number = 44100; //赫茲 44 | protected var _audioSize:Number = 16; //質量 45 | protected var _audioChannels:uint = 2; //聲道 46 | protected var _audioProperties:uint = 0; //標籤 47 | 48 | //時間 49 | protected var _duration:Number = 0.0; 50 | 51 | public function Codec() 52 | { 53 | } 54 | 55 | /* byte handlers */ 56 | 57 | protected function byte_r8(s:*):int 58 | { 59 | if (s.position < s.length) 60 | return s.readByte(); 61 | return 0; 62 | } 63 | 64 | protected function byte_rb16(s:*):uint 65 | { 66 | var val:uint; 67 | val = byte_r8(s) << 8; 68 | val |= byte_r8(s); 69 | return val; 70 | } 71 | 72 | protected function byte_rb24(s:*):uint 73 | { 74 | var val:uint; 75 | val = byte_rb16(s) << 8; 76 | val |= byte_r8(s); 77 | return val; 78 | } 79 | 80 | protected function byte_rb32(s:*):uint 81 | { 82 | var val:uint; 83 | val = byte_rb16(s) << 16; 84 | val |= byte_rb16(s); 85 | return val; 86 | } 87 | 88 | protected function byte_w8(s:*, b:int):void 89 | { 90 | if (b >= -128 && b <= 255) 91 | s.writeByte(b); 92 | } 93 | 94 | protected function byte_wb16(s:*, b:uint):void 95 | { 96 | byte_w8(s, b >> 8) 97 | byte_w8(s, b & 0xff); 98 | } 99 | 100 | protected function byte_wb24(s:*, b:uint):void 101 | { 102 | byte_wb16(s, b >> 8); 103 | byte_w8(s, b & 0xff); 104 | } 105 | 106 | protected function byte_wb32(s:*, b:uint):void 107 | { 108 | byte_w8(s, b >> 24); 109 | byte_w8(s, b >> 16 & 0xff); 110 | byte_w8(s, b >> 8 & 0xff); 111 | byte_w8(s, b & 0xff); 112 | } 113 | 114 | /* byte handlers end */ 115 | 116 | public function decode(input:ByteArray):Codec 117 | { 118 | return null; 119 | } 120 | 121 | public function encode(input:Codec):ByteArray 122 | { 123 | return null; 124 | } 125 | 126 | public function getDataByFrame(frame:Frame):ByteArray 127 | { 128 | var b:ByteArray = new ByteArray(); 129 | b.writeBytes(_rawData, frame.offset, frame.size); 130 | return b; 131 | } 132 | 133 | public function export():ByteArray 134 | { 135 | return _rawData; 136 | } 137 | 138 | public function exportVideo():ByteArray 139 | { 140 | return null; 141 | } 142 | 143 | public function exportAudio():ByteArray 144 | { 145 | return null; 146 | } 147 | 148 | public function get name():String 149 | { 150 | return _name; 151 | } 152 | 153 | public function get frames():Vector. 154 | { 155 | return _frames; 156 | } 157 | 158 | public function get keyframes():Array 159 | { 160 | return _keyframes; 161 | } 162 | 163 | public function get duration():Number 164 | { 165 | return _duration; 166 | } 167 | 168 | public function get frameRate():Number 169 | { 170 | return _frameRate; 171 | } 172 | 173 | public function get hasVideo():Boolean 174 | { 175 | return _hasVideo; 176 | } 177 | 178 | public function get hasAudio():Boolean 179 | { 180 | return _hasAudio; 181 | } 182 | 183 | public function get videoConfig():ByteArray 184 | { 185 | return _videoConfig; 186 | } 187 | 188 | public function get videoCodec():uint 189 | { 190 | return _videoCodec; 191 | } 192 | 193 | public function get videoWidth():Number 194 | { 195 | return _videoWidth; 196 | } 197 | 198 | public function get videoHeight():Number 199 | { 200 | return _videoHeight; 201 | } 202 | 203 | public function get videoRate():Number 204 | { 205 | return _videoRate; 206 | } 207 | 208 | public function get audioConfig():ByteArray 209 | { 210 | return _audioConfig; 211 | } 212 | 213 | public function get audioCodec():uint 214 | { 215 | return _audioCodec; 216 | } 217 | 218 | public function get audioType():uint 219 | { 220 | return _audioType; 221 | } 222 | 223 | public function get audioRate():Number 224 | { 225 | return _audioRate; 226 | } 227 | 228 | public function get audioSize():Number 229 | { 230 | return _audioSize; 231 | } 232 | 233 | public function get audioChannels():uint 234 | { 235 | return _audioChannels; 236 | } 237 | 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /src/cc/minos/codec/flv/FlvCodec.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Created by SiuzukZan on 03/23/2015 22:58 4 | */ 5 | package cc.minos.codec.flv { 6 | 7 | import cc.minos.codec.Codec; 8 | 9 | import flash.utils.ByteArray; 10 | 11 | /** 12 | * ... 13 | * @link http://www.adobe.com/content/dam/Adobe/en/devnet/flv/pdfs/video_file_format_spec_v10.pdf 14 | */ 15 | public class FlvCodec extends Codec { 16 | 17 | /* video */ 18 | 19 | public static const VIDEO_FRAMETYPE_OFFSET:uint = 4; 20 | //codec id 21 | public static const VIDEO_CODECID_H263:uint = 2; 22 | public static const VIDEO_CODECID_SCREEN:uint = 3; 23 | public static const VIDEO_CODECID_VP6:uint = 4; 24 | public static const VIDEO_CODECID_VP6A:uint = 5; 25 | public static const VIDEO_CODECID_SCREEN2:uint = 6; 26 | public static const VIDEO_CODECID_H264:uint = 7; 27 | public static const VIDEO_CODECID_REALH263:uint = 8; 28 | public static const VIDEO_CODECID_MPEG4:uint = 9; 29 | //frame 30 | public static const VIDEO_FRAME_KEY:uint = 1 << VIDEO_FRAMETYPE_OFFSET; ///< key frame (for AVC, a seekable frame) 31 | public static const VIDEO_FRAME_INTER:uint = 2 << VIDEO_FRAMETYPE_OFFSET; ///< inter frame (for AVC, a non-seekable frame) 32 | public static const VIDEO_FRAME_DISP_INTER:uint = 3 << VIDEO_FRAMETYPE_OFFSET; ///< disposable inter frame (H.263 only) 33 | public static const VIDEO_FRAME_GENERATED_KEY:uint = 4 << VIDEO_FRAMETYPE_OFFSET; ///< generated key frame (reserved for server use only) 34 | public static const VIDEO_FRAME_VIDEO_INFO_CMD:uint = 5 << VIDEO_FRAMETYPE_OFFSET; ///< video info/command frame 35 | 36 | /* audio */ 37 | 38 | public static const AUDIO_SAMPLESSIZE_OFFSET:uint = 1; 39 | public static const AUDIO_SAMPLERATE_OFFSET:uint = 2; 40 | public static const AUDIO_CODECID_OFFSET:uint = 4; 41 | //size 42 | public static const AUDIO_SAMPLESSIZE_8BIT:uint = 0; 43 | public static const AUDIO_SAMPLESSIZE_16BIT:uint = 1 << AUDIO_SAMPLESSIZE_OFFSET; 44 | //rate 45 | public static const AUDIO_SAMPLERATE_SPECIAL:uint = 0; 46 | public static const AUDIO_SAMPLERATE_11025HZ:uint = 1 << AUDIO_SAMPLERATE_OFFSET; 47 | public static const AUDIO_SAMPLERATE_22050HZ:uint = 2 << AUDIO_SAMPLERATE_OFFSET; 48 | public static const AUDIO_SAMPLERATE_44100HZ:uint = 3 << AUDIO_SAMPLERATE_OFFSET; 49 | //channel 50 | public static const AUDIO_CHANNEL_MONO:uint = 0; 51 | public static const AUDIO_CHANNEL_STEREO:uint = 1; 52 | //codec id 53 | public static const AUDIO_CODECID_PCM:uint = 0; 54 | public static const AUDIO_CODECID_ADPCM:uint = 1 << AUDIO_CODECID_OFFSET; 55 | public static const AUDIO_CODECID_MP3:uint = 2 << AUDIO_CODECID_OFFSET; 56 | public static const AUDIO_CODECID_PCM_LE:uint = 3 << AUDIO_CODECID_OFFSET; 57 | public static const AUDIO_CODECID_NELLYMOSER_16KHZ_MONO:uint = 4 << AUDIO_CODECID_OFFSET; 58 | public static const AUDIO_CODECID_NELLYMOSER_8KHZ_MONO:uint = 5 << AUDIO_CODECID_OFFSET; 59 | public static const AUDIO_CODECID_NELLYMOSER:uint = 6 << AUDIO_CODECID_OFFSET; 60 | public static const AUDIO_CODECID_PCM_ALAW:uint = 7 << AUDIO_CODECID_OFFSET; 61 | public static const AUDIO_CODECID_PCM_MULAW:uint = 8 << AUDIO_CODECID_OFFSET; 62 | public static const AUDIO_CODECID_AAC:uint = 10 << AUDIO_CODECID_OFFSET; 63 | public static const AUDIO_CODECID_SPEEX:uint = 11 << AUDIO_CODECID_OFFSET; 64 | 65 | /* TAG TYPE */ 66 | 67 | public static const TAG_TYPE_AUDIO:uint = 0x08; 68 | public static const TAG_TYPE_VIDEO:uint = 0x09; 69 | public static const TAG_TYPE_META:uint = 0x12; 70 | 71 | /* AMF TYPE */ 72 | 73 | public static const AMF_DATA_TYPE_NUMBER:uint = 0x00; 74 | public static const AMF_DATA_TYPE_BOOLEAN:uint = 0x01; 75 | public static const AMF_DATA_TYPE_STRING:uint = 0x02; 76 | public static const AMF_DATA_TYPE_OBJECT:uint = 0x03; 77 | public static const AMF_DATA_TYPE_NULL:uint = 0x05; 78 | public static const AMF_DATA_TYPE_UNDEFINED:uint = 0x06; 79 | public static const AMF_DATA_TYPE_REFERENCE:uint = 0x07; 80 | public static const AMF_DATA_TYPE_MIXEDARRAY:uint = 0x08; 81 | public static const AMF_DATA_TYPE_OBJECT_END:uint = 0x09; 82 | public static const AMF_DATA_TYPE_ARRAY:uint = 0x0a; 83 | public static const AMF_DATA_TYPE_DATE:uint = 0x0b; 84 | public static const AMF_DATA_TYPE_LONG_STRING:uint = 0x0c; 85 | public static const AMF_DATA_TYPE_UNSUPPORTED:uint = 0x0d; 86 | public static const AMF_END_OF_OBJECT:uint = 0x09; 87 | 88 | //记录meta关键帧数据位置 89 | private var filepositionsPos:uint; 90 | private var timesPos:uint; 91 | 92 | public function FlvCodec() 93 | { 94 | _name = "flv"; 95 | _extensions = "flv"; 96 | _mimeType = "video/flv"; 97 | } 98 | 99 | private function byte_string(s:*, str:String):void 100 | { 101 | byte_wb16(s, str.length); 102 | s.writeUTFBytes(str); 103 | } 104 | 105 | private function byte_boolean(s:*, bool:Boolean):void 106 | { 107 | byte_w8(s, AMF_DATA_TYPE_BOOLEAN); 108 | byte_w8(s, int(bool)); 109 | } 110 | 111 | private function byte_number(s:*, num:Number):void 112 | { 113 | byte_w8(s, AMF_DATA_TYPE_NUMBER); 114 | s.writeDouble(num); 115 | } 116 | 117 | /** 118 | * 119 | * @param s 120 | * @param input 121 | */ 122 | private function byte_header(s:*, input:Codec):void 123 | { 124 | var header:ByteArray = new ByteArray(); 125 | //开头固定的3个字节 126 | byte_w8(header, 0x46); //F 127 | byte_w8(header, 0x4C); //L 128 | byte_w8(header, 0x56); //V 129 | byte_w8(header, 1); 130 | var u:uint = 0; 131 | if (input.hasVideo) u += 1; 132 | if (input.hasAudio) u += 4; 133 | byte_w8(header, u); 134 | byte_wb32(header, 9); 135 | byte_wb32(header, 0); 136 | //meta tag 137 | byte_w8(header, TAG_TYPE_META); 138 | //先记录数据大小的位置稍后更新 139 | var metadataSizePos:uint = header.position; 140 | byte_wb24(header, 0); //data size 141 | byte_wb24(header, 0); //ts 142 | byte_w8(header, 0); //ts ext 143 | byte_wb24(header, 0); //stream id 144 | //data 145 | byte_w8(header, AMF_DATA_TYPE_STRING) 146 | byte_string(header, 'onMetaData'); 147 | byte_w8(header, AMF_DATA_TYPE_MIXEDARRAY); 148 | 149 | //先记录参数个数的位置稍后更新 150 | var metadataCountPos:uint = header.position; 151 | var metadataCount:uint = 2; 152 | byte_wb32(header, metadataCount); 153 | 154 | byte_string(header, 'duration'); 155 | byte_number(header, input.duration); 156 | 157 | byte_string(header, 'metadatacreator'); 158 | byte_w8(header, AMF_DATA_TYPE_STRING); 159 | byte_string(header, 'codec-as3 by SiuzukZan'); 160 | 161 | if (input.hasAudio) 162 | { 163 | byte_string(header, 'sterro'); 164 | byte_boolean(header, (input.audioChannels == 2)); 165 | metadataCount += 1; 166 | } 167 | 168 | if (input.hasVideo) 169 | { 170 | byte_string(header, 'width'); 171 | byte_number(header, input.videoWidth); 172 | byte_string(header, 'height'); 173 | byte_number(header, input.videoHeight); 174 | byte_string(header, 'framerate'); 175 | byte_number(header, input.frameRate); 176 | 177 | metadataCount += 3; 178 | 179 | var _hasKey:Boolean = (input.keyframes != null); 180 | if (_hasKey) 181 | { 182 | /** 183 | * 写入关键帧 184 | * 关键帧数据是一个对象,其中包含2个数组(时间,位移) 185 | * 这里都先用0占位,在加入完帧后更新 186 | */ 187 | _keyframes = []; 188 | 189 | byte_string(header, 'hasKeyframes'); 190 | byte_boolean(header, _hasKey); 191 | 192 | var _len:uint = input.keyframes.length + 1; 193 | byte_string(header, 'keyframes'); 194 | byte_w8(header, AMF_DATA_TYPE_OBJECT); 195 | 196 | byte_string(header, 'filepositions'); 197 | byte_w8(header, AMF_DATA_TYPE_ARRAY); 198 | byte_wb32(header, _len); //count 199 | 200 | filepositionsPos = header.position; 201 | for (var i:int = 0; i < _len; i++) 202 | { 203 | byte_number(header, 0.0); 204 | } 205 | 206 | byte_string(header, 'times'); 207 | byte_w8(header, AMF_DATA_TYPE_ARRAY); 208 | byte_wb32(header, _len); //count 209 | 210 | timesPos = header.position; 211 | for (var i:int = 0; i < _len; i++) 212 | { 213 | byte_number(header, 0.0); 214 | } 215 | //object end 216 | byte_wb24(header, AMF_DATA_TYPE_OBJECT_END); 217 | 218 | metadataCount++; 219 | } 220 | } 221 | byte_wb24(header, AMF_END_OF_OBJECT); 222 | 223 | //更新meta的数据 224 | header.position = metadataCountPos; 225 | byte_wb32(header, metadataCount); 226 | header.position = metadataSizePos; 227 | byte_wb24(header, header.length - metadataSizePos - 10); 228 | header.position = header.length; 229 | 230 | s.writeBytes(header); 231 | byte_wb32(s, header.length - 13); 232 | 233 | header.length = 0, header = null; 234 | } 235 | 236 | /** 237 | * 写入视频节点 238 | * @param s : 目标流 239 | * @param data : 数据 240 | * @param timestamp : 时间戳 241 | * @param frameType : 帧类型,占4位(1是关键帧,2则不是) 242 | * @param codecId : 编码类型,占后4位(7则是avc) 243 | * @param naluType : NALU类型,avc的数据开始需要NALU header 0后续都是1 244 | * @param flagsSize : 数据头标签占位 245 | */ 246 | private function byte_video(s:*, data:ByteArray, timestamp:Number, frameType:uint, codecId:uint, naluType:uint = 1, flagsSize:uint = 5):void 247 | { 248 | var tag:ByteArray = new ByteArray(); 249 | byte_w8(tag, FlvCodec.TAG_TYPE_VIDEO); //tag type 250 | byte_wb24(tag, data.length + flagsSize); //data size 251 | byte_wb24(tag, timestamp); //ts 252 | byte_w8(tag, 0); //ts ext 253 | byte_wb24(tag, 0); //stream id 254 | //avc data 255 | byte_w8(tag, (frameType + codecId)); // 256 | if (codecId == FlvCodec.VIDEO_CODECID_H264) 257 | { 258 | byte_w8(tag, naluType); 259 | byte_wb24(tag, 0); //ct 260 | } 261 | tag.writeBytes(data); 262 | //保存關鍵幀的信息 263 | if (frameType == VIDEO_FRAME_KEY && _keyframes) 264 | { 265 | _keyframes.push({'time': parseFloat((timestamp / 1000).toFixed(2)), 'position': s.position}); 266 | } 267 | //add tag and pre tag size 268 | s.writeBytes(tag), byte_wb32(s, tag.length); 269 | 270 | tag.length = 0, tag = null; 271 | } 272 | 273 | /** 274 | * 音频流节点 275 | * @param s : 目标流 276 | * @param data : 数据 277 | * @param timestamp : 时间戳 278 | * @param prop : 音频标识(类型,赫兹,声道等) 279 | * @param packetType: 类型AAC一样需要分header0和body1 280 | * @param flagsSize : 标签头占位 281 | */ 282 | private function byte_audio(s:*, data:ByteArray, timestamp:Number, prop:uint, packetType:uint = 1, flagsSize:uint = 2):void 283 | { 284 | var tag:ByteArray = new ByteArray(); 285 | byte_w8(tag, FlvCodec.TAG_TYPE_AUDIO); 286 | byte_wb24(tag, data.length + flagsSize); 287 | byte_wb24(tag, timestamp); //ts 288 | byte_w8(tag, 0); //ts ext 289 | byte_wb24(tag, 0); //stream 290 | //aac data 291 | byte_w8(tag, prop); 292 | byte_w8(tag, packetType); 293 | tag.writeBytes(data); 294 | 295 | //add tag and pre tag size 296 | s.writeBytes(tag), byte_wb32(s, tag.length); 297 | 298 | tag.length = 0, tag = null; 299 | } 300 | 301 | /** 302 | * 把其他流封裝成flv 303 | * @param input 輸入流 304 | * @return 返回flv封裝的二進制 305 | */ 306 | override public function encode(input:Codec):ByteArray 307 | { 308 | var flv:ByteArray = new ByteArray(); 309 | 310 | //文件头 311 | byte_header(flv, input); 312 | //这里是pps和sps,avc重要的组成部分,在文件的开头meta的后面,一定是关键帧 313 | if (input.videoConfig) 314 | { 315 | byte_video(flv, input.videoConfig, 0, FlvCodec.VIDEO_FRAME_KEY, FlvCodec.VIDEO_CODECID_H264, 0); 316 | } 317 | //音频解析的部分,接着视频的解析数据 318 | var flags:uint = 0; 319 | flags = AUDIO_CODECID_AAC; 320 | flags += AUDIO_SAMPLERATE_44100HZ; 321 | flags += AUDIO_SAMPLESSIZE_16BIT; 322 | flags += AUDIO_CHANNEL_STEREO; 323 | if (input.audioConfig) 324 | { 325 | byte_audio(flv, input.audioConfig, 0, flags, 0); 326 | } 327 | //根据时间添加各个节点 328 | for (var i:int = 0; i < input.frames.length; i++) 329 | { 330 | var f:Frame = input.frames[i]; 331 | if (input.hasVideo && f.dataType == FlvCodec.TAG_TYPE_VIDEO) 332 | byte_video(flv, input.getDataByFrame(f), f.timestamp, f.frameType, FlvCodec.VIDEO_CODECID_H264, 1); 333 | else if (input.hasAudio && f.dataType == FlvCodec.TAG_TYPE_AUDIO) 334 | byte_audio(flv, input.getDataByFrame(f), f.timestamp, flags); 335 | } 336 | 337 | //根据获取到的关键帧数组,更新meta的数据 338 | if (_keyframes && _keyframes.length > 0) 339 | { 340 | flv.position = timesPos; 341 | for (var k:uint = 0; k < _keyframes.length; k++) 342 | { 343 | byte_number(flv, _keyframes[k].time); 344 | } 345 | flv.position = filepositionsPos; 346 | for (k = 0; k < _keyframes.length; k++) 347 | { 348 | byte_number(flv, _keyframes[k].position); 349 | } 350 | } 351 | flv.position = 0; 352 | return flv; 353 | } 354 | 355 | /** 356 | * 解析flv 357 | * @param input 358 | * @return 359 | */ 360 | override public function decode(input:ByteArray):Codec 361 | { 362 | if (!probe(input)) 363 | throw new Error('Not a valid FLV file!'); 364 | 365 | _rawData = input; 366 | _rawData.position = 0; 367 | 368 | _rawData.readUTFBytes(3); // FLV 369 | _rawData.readByte(); //version 370 | var info:uint = _rawData.readByte(); //flags 371 | _hasAudio = (info >> 2 & 0x1); //audio 372 | _hasVideo = (info >> 0 & 0x1); //video 373 | _rawData.position += 8; //data offset 374 | 375 | var offset:int; 376 | var end:int; 377 | var tagLength:int; 378 | var currentTag:int; 379 | var step:int; 380 | var bodyTagHeader:int; 381 | var time:int; 382 | var timestampExtended:int; 383 | var streamID:int; 384 | var frame:Frame; 385 | 386 | _frames = new Vector.(); 387 | while (_rawData.bytesAvailable > 0) 388 | { 389 | offset = _rawData.position; 390 | currentTag = _rawData.readByte(); 391 | step = (_rawData.readUnsignedShort() << 8) | _rawData.readUnsignedByte(); 392 | time = (_rawData.readUnsignedShort() << 8) | _rawData.readUnsignedByte(); 393 | timestampExtended = _rawData.readUnsignedByte(); // 394 | streamID = ((_rawData.readUnsignedShort() << 8) | _rawData.readUnsignedByte()); 395 | bodyTagHeader = _rawData.readUnsignedByte(); 396 | end = _rawData.position + step + 3; 397 | tagLength = end - offset; 398 | 399 | if (currentTag == TAG_TYPE_META || currentTag == TAG_TYPE_AUDIO || currentTag == TAG_TYPE_VIDEO) 400 | { 401 | frame = new Frame('flv'); 402 | frame.dataType = currentTag; 403 | frame.offset = offset; 404 | frame.size = tagLength; 405 | frame.timestamp = time; 406 | if (currentTag == TAG_TYPE_VIDEO) 407 | { 408 | frame.frameType = (bodyTagHeader >> 4); //key or inter ... 409 | frame.codecId = (bodyTagHeader & 0xf);//avc... etc 410 | //if avc -> pps & sps 411 | } 412 | else if (currentTag == TAG_TYPE_AUDIO) 413 | { 414 | frame.frameType = bodyTagHeader; // 415 | frame.codecId = (bodyTagHeader >> 4); //aac... etc 416 | //if aac -> codec specs ... 417 | // (bodyTagHeader >> 4); //sound format 0-15 418 | // (bodyTagHeader >> 2 & 0x03 ); //sound rate 0/1/2/3(5.5/11/22/44-kHz) 419 | // (bodyTagHeader >> 1 & 0x1 ); //sound size 0/1(8b/16b) 420 | // (bodyTagHeader & 0x1 ); //sound type 0/1 421 | } 422 | else if (currentTag == TAG_TYPE_META) 423 | { 424 | //parse meta data -> video params 425 | } 426 | _frames.push(frame); 427 | } 428 | _rawData.position = end; 429 | } 430 | 431 | return this; 432 | } 433 | 434 | /** 435 | * 436 | * @param input 437 | * @return 438 | */ 439 | public static function probe(input:ByteArray):Boolean 440 | { 441 | if (input[0] == 0x46 && input[1] == 0x4C && input[2] == 0x56 && input[3] < 5) 442 | return true; 443 | return false; 444 | } 445 | } 446 | } 447 | -------------------------------------------------------------------------------- /src/cc/minos/codec/flv/Frame.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/23 15:01 5 | */ 6 | package cc.minos.codec.flv { 7 | 8 | public class Frame extends Object { 9 | 10 | public var offset:uint; 11 | public var dataType:uint; 12 | public var frameType:uint; 13 | public var size:uint; 14 | public var timestamp:Number; 15 | public var index:uint; 16 | public var codecId:uint; 17 | public var codecType:String; 18 | 19 | public function Frame(type:String = 'flv') 20 | { 21 | codecType = type; 22 | } 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/Mkv.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/25 18:00 5 | */ 6 | package cc.minos.codec.mkv { 7 | 8 | public class Mkv { 9 | 10 | // 11 | public static const VOID:uint = 0xEC; 12 | public static const CRC_32:uint = 0xBF; 13 | 14 | // 15 | public static const EBML_ID:uint = 0x1A45DFA3; 16 | public static const EBML_VERSION:uint = 0x4286; 17 | public static const EBML_READ_VERSION:uint = 0x42F7; 18 | public static const EBML_MAX_ID_LENGTH:uint = 0x42F2; 19 | public static const EBML_MAX_SIZE_LENGTH:uint = 0x42F3; 20 | public static const EBML_DOC_TYPE:uint = 0x4282; 21 | public static const EBML_DOC_TYPE_VERSION:uint = 0x4287; 22 | public static const EBML_DOC_TYPE_READ_VERSION:uint = 0x4285; 23 | 24 | // 25 | public static const SEGMENT_ID:uint = 0x18538067; 26 | 27 | /** 28 | * segment info contains general information about a segment. 29 | */ 30 | public static const SEGMENT_INFO:uint = 0x1549A966; 31 | public static const SEGMENT_UID:uint = 0x73A4; 32 | public static const SEGMENT_FILE_NAME:uint = 0x7384; 33 | public static const SEGMENT_PREV_UID:uint = 0x3CB923; 34 | public static const SEGMENT_PREV_FILE_NAME:uint = 0x3C83AB; 35 | public static const SEGMENT_NEXT_UID:uint = 0x3EB923; 36 | public static const SEGMENT_NEXT_FILE_NAME:uint = 0x3E83BB; 37 | public static const SEGMENT_TIME_CODE_SCALE:uint = 0x2AD7B1; 38 | public static const SEGMENT_DURATION:uint = 0x4489; 39 | public static const SEGMENT_TITLE:uint = 0x7BA9; 40 | public static const SEGMENT_MUXINGAPP:uint = 0x4D80; 41 | public static const SEGMENT_WRITINGAPP:uint = 0x5741; 42 | public static const SEGMENT_DATEUTC:uint = 0x4461; //2001.1.1 0:00:00 43 | 44 | /** 45 | * a seek head is an index of elements that are children of segment. 46 | */ 47 | public static const SEEK_HEAD:uint = 0x114D9B74; 48 | //one seek element contains an EBML-ID and the position within the segment at which an element with this id can be found. 49 | public static const SEEK:uint = 0x4DBB; 50 | public static const SEEK_ID:uint = 0x53AB; 51 | public static const SEEK_POSITION:uint = 0x53AC; 52 | 53 | /** 54 | * a tracks element contains the description of some or all tracks(preferably all). 55 | */ 56 | public static const TRACKS:uint = 0x1654AE6B; 57 | 58 | public static const TRACK_ENTRY:uint = 0xAE; 59 | public static const TRACK_NUMBER:uint = 0xD7; 60 | public static const TRACK_UID:uint = 0x73C5; 61 | //0x01 > video, 0x02 > audio, 0x03 > complex, 0x10 > logo, 0x11 > subtitle, 0x12 > button, 0x20 > control 62 | public static const TRACK_TYPE:uint = 0x83; 63 | public static const TRACK_FLAG_ENABLED:uint = 0xB9; 64 | public static const TRACK_FLAG_DEFAULT:uint = 0x88; 65 | public static const TRACK_FLAG_FORCED:uint = 0x55AA; 66 | public static const TRACK_FLAG_LACING:uint = 0x9C; 67 | public static const TRACK_MIN_CACHE:uint = 0x6DE7; 68 | public static const TRACK_MAX_CACHE:uint = 0x6DF8; 69 | public static const TRACK_DEFAULT_DURATION:uint = 0x23E383; 70 | public static const TRACK_TIMECODE_SCALE:uint = 0x23314F; 71 | public static const TRACK_NAME:uint = 0x536E; 72 | public static const TRACK_LANGUAGE:uint = 0x22B59C; 73 | public static const TRACK_CODEC_ID:uint = 0x86; 74 | public static const TRACK_CODEC_PRIVATE:uint = 0x63A2; 75 | public static const TRACK_CODEC_NAME:uint = 0x258688; 76 | public static const TRACK_ATTACHMENT_LINK:uint = 0x7446; 77 | //video track 78 | public static const TRACK_VIDEO:uint = 0xE0; 79 | public static const VIDEO_PIXEL_WIDTH:uint = 0xB0; 80 | public static const VIDEO_PIXEL_HEIGHT:uint = 0xBA; 81 | public static const VIDEO_PIXEL_CROP_BOTTOM:uint = 0x54AA; 82 | public static const VIDEO_PIXEL_CROP_TOP:uint = 0x54BB; 83 | public static const VIDEO_PIXEL_CROP_LEFT:uint = 0x54CC; 84 | public static const VIDEO_PIXEL_CROP_RIGHT:uint = 0x54DD; 85 | public static const VIDEO_DISPLAY_WIDTH:uint = 0x54B0; 86 | public static const VIDEO_DISPLAY_HEIGHT:uint = 0x54BA; 87 | public static const VIDEO_DISPLAY_UINT:uint = 0x54B2; 88 | //audio track 89 | public static const TRACK_AUDIO:uint = 0xE1; 90 | public static const AUDIO_SAMPLING_FREQUENCY:uint = 0xB5; 91 | public static const AUDIO_OUTPUT_SAMPLING_FREQUENCY:uint = 0x78B5; 92 | public static const AUDIO_CHANNELS:uint = 0x9F; 93 | public static const AUDIO_BIT_DEPTH:uint = 0x6264; 94 | //information 95 | public static const CONTENT_ENCODINGS:uint = 0x6D80; 96 | public static const CONTENT_ENCODING:uint = 0x6240; 97 | public static const CONTENT_ENCODING_ORDER:uint = 0x5031; 98 | public static const CONTENT_ENCODING_SCOPE:uint = 0x5032; 99 | public static const CONTENT_ENCODING_TYPE:uint = 0x5033; 100 | public static const CONTENT_COMPRESSION:uint = 0x5034; 101 | //value of content comp a lgo zlib: 0, bzlib: 1, lzo1x: 2, header striping: 3 102 | public static const CONTENT_COMPALGO:uint = 0x4254; 103 | public static const CONTENT_COMPSETTINGS:uint = 0x4255; 104 | public static const CONTENT_ENCRYPTION:uint = 0x5035; 105 | 106 | /** 107 | * a cluster contains video, audio and subtitle data. 108 | */ 109 | public static const CLUSTER:uint = 0x1F43B675; 110 | public static const CLUSTER_TIMECODE:uint = 0xE7; 111 | public static const CLUSTER_POSITION:uint = 0xA7; 112 | public static const CLUSTER_PREV_SIZE:uint = 0xAB; 113 | public static const CLUSTER_BLOCK_GROUP:uint = 0xA0; 114 | public static const CLUSTER_SIMPLE_BLOCK:uint = 0xA3; 115 | 116 | public static const BLOCK_GROUP_BLOCK:uint = 0xA1; 117 | public static const GROUP_REFERENCE_BLOCK:uint = 0xFB; 118 | public static const GROUP_BLOCK_DURATION:uint = 0x9B; 119 | 120 | /** 121 | * the cues elements contains a timestamp-wise index to clusters, thus it's helpful for easy and quick seeking. 122 | */ 123 | public static const CUES:uint = 0x1C53BB6B; 124 | public static const CUES_CUE_POINT:uint = 0xBB; 125 | public static const POINT_CUE_TIME:uint = 0xB3; 126 | public static const POINT_CUE_TRACK_POSITIONS:uint = 0xB7; 127 | public static const CUE_TRACK:uint = 0xF7; 128 | public static const CUE_CLUSTER_POSITION:uint = 0xF1; 129 | public static const CUE_BLOCK_NUMBER:uint = 0x5378; 130 | 131 | /** 132 | * the attachments elements contains all files attached to this segment. 133 | */ 134 | public static const ATTACHMENTS:uint = 0x1941A469; 135 | /** 136 | * the chapters elements contains the definition of all chapters and editions of this segment. 137 | */ 138 | public static const CHAPTERS:uint = 0x1043A770; 139 | /** 140 | * the tags elements contains further information about the segment or elements inside the segment that is not ready required for playback. 141 | */ 142 | public static const TAGS:uint = 0x1254C367; 143 | 144 | /** **/ 145 | 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/MkvCodec.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/29 11:05 5 | */ 6 | package cc.minos.codec.mkv { 7 | 8 | import cc.minos.codec.Codec; 9 | import cc.minos.codec.flv.Frame; 10 | import cc.minos.codec.mkv.elements.Cluster; 11 | import cc.minos.codec.mkv.elements.EbmlHeader; 12 | import cc.minos.codec.mkv.elements.Element; 13 | import cc.minos.codec.mkv.elements.Segment; 14 | import cc.minos.codec.mkv.elements.TrackEntry; 15 | 16 | import flash.utils.ByteArray; 17 | 18 | /** 19 | * ... 20 | * @link http://www.matroska.org/ 21 | * @link http://www.matroska.org/files/matroska.pdf 22 | */ 23 | public class MkvCodec extends Codec { 24 | 25 | private var ebml:EbmlHeader; 26 | private var segment:Segment; 27 | 28 | public function MkvCodec() 29 | { 30 | _name = "matroska,webm"; 31 | _extensions = "mkv,webm"; 32 | _mimeType = "video/x-matroska,audio/x-matroska,video/webm,audio/webm"; 33 | } 34 | 35 | override public function decode(input:ByteArray):Codec 36 | { 37 | // 38 | this._rawData = input; 39 | 40 | _rawData.position = 0; 41 | 42 | var id:uint; 43 | var size:uint; 44 | var d:ByteArray; 45 | while (_rawData.bytesAvailable > 0) 46 | { 47 | id = Element.toHex(step()); 48 | d = step(); 49 | size = Element.getSize(d, d.length); 50 | d.length = 0; 51 | d.writeBytes(_rawData, _rawData.position, size); 52 | if (id == Mkv.EBML_ID) 53 | { 54 | ebml = new EbmlHeader(); 55 | ebml.size = d.length; 56 | ebml.parse(d); 57 | } 58 | else if (id == Mkv.SEGMENT_ID) 59 | { 60 | segment = new Segment(); 61 | segment.size = d.length; 62 | segment.parse(d); 63 | } 64 | _rawData.position += size; 65 | } 66 | 67 | if (!ebml || !segment) 68 | { 69 | throw new Error(""); 70 | } 71 | 72 | //frames 73 | var clusters:Vector. = segment.getChildByType(Mkv.CLUSTER); 74 | 75 | if (clusters != null) 76 | { 77 | for (var i:int = 0; i < clusters.length; i++) 78 | { 79 | for (var j:uint = 0; j < Cluster(clusters[i]).frames.length; j++) 80 | { 81 | _frames.push(Cluster(clusters[i]).frames[j]); 82 | } 83 | } 84 | } 85 | 86 | trace('frames: ' + _frames.length); //video & audio frame 87 | 88 | //tracks 89 | var tracks:Vector. = segment.getChildByType(Mkv.TRACK_ENTRY); 90 | if (tracks) 91 | { 92 | for (var j:uint = 0; j < tracks.length; j++) 93 | { 94 | var track:TrackEntry = tracks[j] as TrackEntry; 95 | if (track.trackType == 1) 96 | { 97 | _hasVideo = true; 98 | _videoWidth = track.videoWidth; 99 | _videoHeight = track.videoHeight; 100 | 101 | // _videoConfig = new ByteArray(); 102 | // _videoConfig.writeBytes(frames.shift()['data']); 103 | // trace('videoConfig: ' + _videoConfig.length ); 104 | } 105 | else if (track.trackType == 2) 106 | { 107 | _audioChannels = 2; 108 | // _hasAudio = true; 109 | // _audioConfig = track.configurationData; 110 | } 111 | } 112 | } 113 | 114 | _frameRate = 25; 115 | _duration = segment.info.duration / 1000; 116 | 117 | return this; 118 | } 119 | 120 | override public function getDataByFrame(frame:Frame):ByteArray 121 | { 122 | if (frame is MkvFrame) 123 | return MkvFrame(frame).data; 124 | return null; 125 | } 126 | 127 | private function step():ByteArray 128 | { 129 | var b:ByteArray = null; 130 | var l:uint; 131 | var p:uint; 132 | if (_rawData.bytesAvailable > 0) 133 | { 134 | p = _rawData.position; 135 | l = Element.getLength(_rawData.readUnsignedByte()); 136 | if (_rawData.bytesAvailable > (l - 1)) 137 | { 138 | b = new ByteArray(); 139 | b.writeBytes(_rawData, p, l); 140 | _rawData.position = p + l; 141 | } 142 | } 143 | return b; 144 | } 145 | 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/MkvFrame.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Created by SiuzukZan on 01/12/2015 17:20 4 | */ 5 | package cc.minos.codec.mkv { 6 | 7 | import cc.minos.codec.flv.Frame; 8 | import flash.utils.ByteArray; 9 | 10 | public class MkvFrame extends Frame { 11 | 12 | private var _data:ByteArray; 13 | 14 | public function MkvFrame() 15 | { 16 | super("mkv"); 17 | } 18 | 19 | public function get data():ByteArray 20 | { 21 | return _data; 22 | } 23 | 24 | public function set data(value:ByteArray):void 25 | { 26 | _data = value; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/AudioTrack.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/30 17:13 5 | */ 6 | package cc.minos.codec.mkv.elements { 7 | import cc.minos.codec.mkv.Mkv; 8 | 9 | public class AudioTrack extends Element { 10 | 11 | public function AudioTrack() 12 | { 13 | super(Mkv.TRACK_AUDIO); 14 | } 15 | 16 | override protected function getElement(type:uint):Element 17 | { 18 | switch (type) 19 | { 20 | case Mkv.AUDIO_SAMPLING_FREQUENCY: //Hz 21 | case Mkv.AUDIO_OUTPUT_SAMPLING_FREQUENCY: 22 | case Mkv.AUDIO_CHANNELS: // 23 | case Mkv.AUDIO_BIT_DEPTH: // 24 | return new VarElement(type); 25 | } 26 | return super.getElement(type); 27 | } 28 | 29 | override protected function init():void 30 | { 31 | trace('audio track'); 32 | trace('sampling frequency: ' + getChildByType(Mkv.AUDIO_SAMPLING_FREQUENCY)[0].getNumber() + 'kHz') 33 | trace('channels: ' + getChildByType(Mkv.AUDIO_CHANNELS)[0].getInt()); 34 | trace('bit depth: ' + getChildByType(Mkv.AUDIO_BIT_DEPTH)[0].getInt() + 'bit' ); 35 | trace('childs: ' + children.length); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/Cluster.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/30 17:21 5 | */ 6 | package cc.minos.codec.mkv.elements { 7 | 8 | import cc.minos.codec.flv.Frame; 9 | import cc.minos.codec.mkv.Mkv; 10 | import cc.minos.codec.mkv.MkvFrame; 11 | 12 | import flash.utils.ByteArray; 13 | 14 | public class Cluster extends Element { 15 | 16 | private var _timeCode:uint; 17 | private var _frames:Vector.; 18 | 19 | public function Cluster() 20 | { 21 | super(Mkv.CLUSTER); 22 | } 23 | 24 | override protected function getElement(type:uint):Element 25 | { 26 | switch (type) 27 | { 28 | case Mkv.CLUSTER_TIMECODE: 29 | case Mkv.CLUSTER_POSITION: 30 | case Mkv.CLUSTER_PREV_SIZE: 31 | case Mkv.CLUSTER_BLOCK_GROUP: 32 | case Mkv.CLUSTER_SIMPLE_BLOCK: 33 | return new VarElement(type); 34 | } 35 | return super.getElement(type); 36 | } 37 | 38 | override protected function init():void 39 | { 40 | // trace('cluster: ' + toString() ); 41 | _frames = new Vector.(); 42 | for (var i:int = 0; i < children.length; i++) 43 | { 44 | if (children[i].type == Mkv.CLUSTER_TIMECODE) 45 | { 46 | _timeCode = children[i].getInt(); 47 | } 48 | else if ([children[i].type == Mkv.CLUSTER_SIMPLE_BLOCK]) 49 | { 50 | var f:Frame = parseSimpleBlock(children[i], i); 51 | if(f) 52 | _frames.push(f); 53 | } 54 | } 55 | } 56 | 57 | private function parseSimpleBlock(element:Element, index:uint):Frame 58 | { 59 | var f:MkvFrame = new MkvFrame(); 60 | var d:ByteArray = element.data; 61 | d.position = 0; 62 | 63 | var track_number:uint = d.readByte() & 0xF; 64 | var time_code:uint = d.readShort(); // 65 | 66 | var flags:uint = d.readUnsignedByte(); 67 | 68 | var frame_type:uint = flags >> 7; 69 | var lacing:uint = flags >> 1 & 0x3; 70 | 71 | if (lacing == 0) //no lacing 72 | { 73 | //no lacing 74 | f.timestamp = _timeCode + time_code; // ms 75 | f.index = index; 76 | f.dataType = track_number == 1 ? 0x09 : 0x08; 77 | f.frameType = frame_type == 1 ? (1 << 4) : (2 << 4); 78 | f.codecId = 2; 79 | 80 | if (track_number == 1) 81 | { 82 | var k:uint = d.readByte(); 83 | var key:Boolean = !Boolean(k & ( 1 << 0)); 84 | var show:Boolean = Boolean(k & (1 << 4)); 85 | var part:ByteArray = new ByteArray(); 86 | part.writeBytes(d, 4, 3); 87 | // trace('pl: ' + (InterpretLittleEndian(part, 3) >> 5 )); 88 | f.frameType = key ? (1 << 4) : (2<<4); 89 | if(!show) 90 | return null; 91 | } 92 | var b:ByteArray = new ByteArray(); 93 | b.writeBytes(d, d.position); 94 | f.data = b; 95 | f.size = f.data.length; 96 | // trace('frame: ' + d.bytesAvailable); 97 | } 98 | return f; 99 | } 100 | 101 | private function InterpretLittleEndian(data:ByteArray, i:int):int 102 | { 103 | var tmp:int = 0; 104 | while (i) 105 | { 106 | tmp += data[i - 1] << 8 * (i - 1); 107 | i--; 108 | } 109 | return tmp; 110 | } 111 | 112 | public function get frames():Vector. 113 | { 114 | return _frames; 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/ContentEncoding.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/30 17:18 5 | */ 6 | package cc.minos.codec.mkv.elements { 7 | import cc.minos.codec.mkv.Mkv; 8 | 9 | public class ContentEncoding extends Element { 10 | public function ContentEncoding() 11 | { 12 | super(Mkv.CONTENT_ENCODING); 13 | } 14 | 15 | override protected function getElement(type:uint):Element 16 | { 17 | switch (type) 18 | { 19 | case Mkv.CONTENT_ENCODING_ORDER: 20 | case Mkv.CONTENT_ENCODING_SCOPE: 21 | case Mkv.CONTENT_ENCODING_TYPE: 22 | case Mkv.CONTENT_COMPRESSION: 23 | case Mkv.CONTENT_ENCRYPTION: 24 | return new VarElement(type); 25 | } 26 | return super.getElement(type); 27 | } 28 | 29 | override protected function init():void 30 | { 31 | trace('content encoding <'); 32 | trace('content encoding end. children: ' + children.length ); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/ContentEncodings.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/30 17:15 5 | */ 6 | package cc.minos.codec.mkv.elements { 7 | import cc.minos.codec.mkv.Mkv; 8 | 9 | public class ContentEncodings extends Element { 10 | public function ContentEncodings() 11 | { 12 | super(Mkv.CONTENT_ENCODINGS); 13 | } 14 | 15 | override protected function getElement(type:uint):Element 16 | { 17 | switch (type) 18 | { 19 | case Mkv.CONTENT_ENCODING: 20 | return new ContentEncoding(); 21 | } 22 | return super.getElement(type); 23 | } 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/CuePoint.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/30 17:33 5 | */ 6 | package cc.minos.codec.mkv.elements { 7 | import cc.minos.codec.mkv.Mkv; 8 | 9 | public class CuePoint extends Element { 10 | 11 | public function CuePoint() 12 | { 13 | super(Mkv.CUES_CUE_POINT); 14 | } 15 | 16 | override protected function getElement(type:uint):Element 17 | { 18 | switch (type) 19 | { 20 | case Mkv.POINT_CUE_TIME: 21 | return new VarElement(type); 22 | case Mkv.POINT_CUE_TRACK_POSITIONS: 23 | return new CuePosition(); 24 | } 25 | return super.getElement(type); 26 | } 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/CuePosition.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Created by SiuzukZan on 01/12/2015 14:12 4 | */ 5 | package cc.minos.codec.mkv.elements { 6 | 7 | import cc.minos.codec.mkv.Mkv; 8 | 9 | public class CuePosition extends Element { 10 | public function CuePosition() 11 | { 12 | super(Mkv.POINT_CUE_TRACK_POSITIONS); 13 | } 14 | 15 | override protected function getElement(type:uint):Element 16 | { 17 | switch (type) 18 | { 19 | case Mkv.CUE_TRACK: 20 | case Mkv.CUE_CLUSTER_POSITION: 21 | case Mkv.CUE_BLOCK_NUMBER: 22 | return new VarElement(type); 23 | } 24 | return super.getElement(type); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/Cues.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/30 17:32 5 | */ 6 | package cc.minos.codec.mkv.elements { 7 | import cc.minos.codec.mkv.Mkv; 8 | 9 | public class Cues extends Element { 10 | public function Cues() 11 | { 12 | super(Mkv.CUES); 13 | } 14 | 15 | override protected function getElement(type:uint):Element 16 | { 17 | switch (type) 18 | { 19 | case Mkv.CUES_CUE_POINT: 20 | return new CuePoint(); 21 | } 22 | return super.getElement(type); 23 | } 24 | 25 | override protected function init():void 26 | { 27 | trace('cues: ' + toString() ); 28 | trace('children: ' + children.length ); 29 | // trace((children[0].children[0].getInt())); 30 | // trace(toHex(children[0].children[1].children[0].data)); //track number 31 | // trace((children[0].children[1].children[1].getInt())); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/EbmlHeader.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/29 10:02 5 | */ 6 | package cc.minos.codec.mkv.elements { 7 | import cc.minos.codec.mkv.Mkv; 8 | import cc.minos.codec.mkv.Mkv; 9 | 10 | public class EbmlHeader extends Element { 11 | 12 | public function EbmlHeader() 13 | { 14 | super(Mkv.EBML_ID); 15 | } 16 | 17 | override protected function init():void 18 | { 19 | trace( 'ebml header', type.toString(16), size ); 20 | 21 | //ebml version 22 | //ebml read version 23 | //ebml max id length 24 | //ebml max size length 25 | //doc type 26 | trace('doc type: ' + getChildByType(Mkv.EBML_DOC_TYPE)[0].getString() ); 27 | //doc version 28 | //doc read version 29 | trace('ebml header end. children: ' + children.length); 30 | } 31 | 32 | override protected function getElement(type:uint):Element 33 | { 34 | switch (type) 35 | { 36 | case Mkv.EBML_VERSION: 37 | case Mkv.EBML_READ_VERSION: 38 | case Mkv.EBML_MAX_ID_LENGTH: 39 | case Mkv.EBML_MAX_SIZE_LENGTH: 40 | case Mkv.EBML_DOC_TYPE: 41 | case Mkv.EBML_DOC_TYPE_VERSION: 42 | case Mkv.EBML_DOC_TYPE_READ_VERSION: 43 | return new VarElement(type); 44 | break; 45 | } 46 | return super .getElement(type); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/Element.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/29 09:51 5 | */ 6 | package cc.minos.codec.mkv.elements { 7 | 8 | import cc.minos.codec.mkv.Mkv; 9 | 10 | import com.hurlant.math.BigInteger; 11 | 12 | import flash.utils.ByteArray; 13 | 14 | public class Element extends Object { 15 | 16 | protected var _type:uint = 0x0; 17 | protected var _size:uint = 0; 18 | protected var _position:uint = 0; 19 | protected var _data:ByteArray; 20 | protected var _children:Vector.; 21 | 22 | //mask 23 | private static const SUBTR:Array = [ 24 | new BigInteger('0x7F', 16, true), 25 | new BigInteger('0x3FFF', 16, true), 26 | new BigInteger('0x1FFFFF', 16, true), 27 | new BigInteger('0x0FFFFFFF', 16, true), 28 | new BigInteger('0x07FFFFFFFF', 16, true), 29 | new BigInteger('0x03FFFFFFFFFF', 16, true), 30 | new BigInteger('0x01FFFFFFFFFFFF', 16, true), 31 | new BigInteger('0x00FFFFFFFFFFFFFF', 16, true) ]; 32 | 33 | public function Element(type:uint) 34 | { 35 | this._type = type; 36 | } 37 | 38 | /** 39 | * 40 | * @param bytes 41 | */ 42 | public function parse(bytes:ByteArray):void 43 | { 44 | // 45 | this._data = bytes; 46 | _children = new Vector.(); 47 | 48 | var byte:ByteArray; 49 | var start:uint; 50 | var len:uint; 51 | var size:uint; 52 | var id:uint; 53 | var element:Element; 54 | 55 | _data.position = 0; 56 | while(_data.bytesAvailable > 0) 57 | { 58 | start = _data.position; 59 | len = getLength(_data.readUnsignedByte());// 60 | 61 | if(len > _data.length) break; 62 | 63 | //id 64 | byte = new ByteArray(); 65 | byte.writeBytes(_data, start, len); 66 | id = toHex(byte); 67 | // 68 | element = getElement(id); 69 | if(element) 70 | { 71 | element.position = start; 72 | _data.position = start + len; 73 | start = _data.position; 74 | //size 75 | len = getLength(_data.readUnsignedByte()); 76 | byte.length = 0; 77 | byte.writeBytes(_data, start, len); 78 | size = getSize(byte, len); 79 | 80 | //data 81 | byte.length = 0; 82 | byte.writeBytes(_data, (start + len), size); 83 | element.size = size; 84 | element.parse(byte); 85 | _children.push(element); 86 | _data.position = start + len + size; 87 | } 88 | else 89 | { 90 | trace(id.toString(16), 'not found!'); 91 | break; 92 | } 93 | } 94 | init(); 95 | } 96 | 97 | protected function init():void 98 | { 99 | // 100 | } 101 | 102 | /** 103 | * this element contains others elements. 104 | * default: void and crc32 are global element. 105 | * @param type 106 | * @return 107 | */ 108 | protected function getElement(type:uint):Element 109 | { 110 | switch(type){ 111 | case Mkv.VOID: 112 | case Mkv.CRC_32: 113 | return new GlobalElement(type); 114 | } 115 | return null; 116 | } 117 | 118 | /** 119 | * search all child under this element (same level) 120 | * @param type 121 | * @return 122 | */ 123 | public function getChildByType(type:uint):Vector. 124 | { 125 | var elements:Vector. = new Vector.(); 126 | if( children.length > 0 ) 127 | { 128 | for(var i:int = 0; i < children.length; i++) 129 | { 130 | var e:Element = children[i]; 131 | if(e.type == type) 132 | { 133 | elements.push(e); 134 | }else if( elements.length == 0 && e.children && e.children.length > 0 ) 135 | { 136 | elements = e.getChildByType(type); 137 | if(elements.length > 0) 138 | { 139 | return elements; 140 | } 141 | } 142 | 143 | } 144 | } 145 | return elements; 146 | } 147 | 148 | public function getString():String 149 | { 150 | _data.position = 0; 151 | return _data.readUTFBytes(_data.length); 152 | } 153 | 154 | public function getNumber():Number 155 | { 156 | _data.position = 0; 157 | return _data.readDouble(); 158 | } 159 | 160 | public function getInt():int 161 | { 162 | _data.position = 0; 163 | return toHex(_data); 164 | } 165 | 166 | /** 167 | * print this element's information 168 | * @return 169 | */ 170 | public function toString():String 171 | { 172 | return '[ Element: ' + type.toString(16) + ' at ' + position + ' size ' + size + ']'; 173 | } 174 | 175 | /** 176 | * ByteArray to number 177 | * @param array : ByteArray(EBML-ID) 178 | * @return 179 | */ 180 | public static function toHex(array:ByteArray):uint 181 | { 182 | var s:String = ""; 183 | for(var i:uint = 0; i < array.length; i++) 184 | { 185 | s += ("0" + array[i].toString(16)).substr(-2, 2); 186 | } 187 | return parseInt(s, 16); 188 | } 189 | 190 | /** 191 | * number of heading zero bits. (+1 the first 1's position) 192 | * @param byte 193 | * @return 194 | */ 195 | public static function getLength(byte:uint):uint 196 | { 197 | return (8 - byte.toString(2).length) + 1; 198 | } 199 | 200 | /** 201 | * get data size using big integer. 202 | * @param byte 203 | * @param len 204 | * @return 205 | */ 206 | public static function getSize(byte:ByteArray, len:uint):int 207 | { 208 | var val:int = 0; 209 | byte.position = 0; 210 | var valu:BigInteger = new BigInteger(byte, 0, true); 211 | var mask:BigInteger = SUBTR[len - 1]; 212 | val = valu.and(mask).intValue(); 213 | return val; 214 | } 215 | 216 | // 217 | 218 | public function get type():uint 219 | { 220 | return _type; 221 | } 222 | 223 | public function get size():uint 224 | { 225 | return _size; 226 | } 227 | 228 | public function get position():uint 229 | { 230 | return _position; 231 | } 232 | 233 | public function get data():ByteArray 234 | { 235 | return _data; 236 | } 237 | 238 | public function get children():Vector. 239 | { 240 | return _children; 241 | } 242 | 243 | public function set position(value:uint):void 244 | { 245 | _position = value; 246 | } 247 | 248 | public function set size(value:uint):void 249 | { 250 | _size = value; 251 | } 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/GlobalElement.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/30 11:23 5 | */ 6 | package cc.minos.codec.mkv.elements { 7 | import flash.utils.ByteArray; 8 | 9 | public class GlobalElement extends Element { 10 | 11 | public function GlobalElement(type:uint) 12 | { 13 | super(type); 14 | } 15 | 16 | override public function parse(bytes:ByteArray):void 17 | { 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/Seek.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/31 10:19 5 | */ 6 | package cc.minos.codec.mkv.elements { 7 | import cc.minos.codec.mkv.Mkv; 8 | 9 | public class Seek extends Element { 10 | 11 | private var _seekId:uint; 12 | private var _seekPosition:uint; 13 | 14 | public function Seek() 15 | { 16 | super(Mkv.SEEK); 17 | } 18 | 19 | override protected function getElement(type:uint):Element 20 | { 21 | switch (type) 22 | { 23 | case Mkv.SEEK_ID: 24 | case Mkv.SEEK_POSITION: 25 | return new VarElement(type); 26 | } 27 | return super.getElement(type); 28 | } 29 | 30 | override protected function init():void 31 | { 32 | if(children.length == 2) 33 | { 34 | _seekId = toHex(children[0].data); 35 | _seekPosition = toHex(children[1].data); 36 | } 37 | } 38 | 39 | public function get seekId():uint 40 | { 41 | return _seekId; 42 | } 43 | 44 | public function get seekPosition():uint 45 | { 46 | return _seekPosition; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/SeekHead.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/30 17:05 5 | */ 6 | package cc.minos.codec.mkv.elements { 7 | import cc.minos.codec.mkv.Mkv; 8 | 9 | public class SeekHead extends Element { 10 | 11 | public function SeekHead() 12 | { 13 | super(Mkv.SEEK_HEAD); 14 | } 15 | 16 | override protected function getElement(type:uint):Element 17 | { 18 | switch (type) 19 | { 20 | case Mkv.SEEK: 21 | return new Seek(); 22 | } 23 | return super.getElement(type); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/Segment.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/29 17:48 5 | */ 6 | package cc.minos.codec.mkv.elements { 7 | 8 | import cc.minos.codec.mkv.Mkv; 9 | 10 | public class Segment extends Element { 11 | 12 | private var _info:SegmentInfo; 13 | 14 | public function Segment() 15 | { 16 | super(Mkv.SEGMENT_ID); 17 | } 18 | 19 | override protected function init():void 20 | { 21 | trace('segment', 'id: ' + type.toString(16), 'size: ' + size); 22 | trace('segment end. children: ' + children.length); 23 | } 24 | 25 | override protected function getElement(type:uint):Element 26 | { 27 | switch(type) 28 | { 29 | case Mkv.SEEK_HEAD: 30 | return new SeekHead(); 31 | case Mkv.SEGMENT_INFO: 32 | _info =new SegmentInfo(); 33 | return _info; 34 | case Mkv.TRACKS: 35 | return new SegmentTracks(); 36 | case Mkv.CLUSTER: 37 | return new Cluster(); 38 | case Mkv.CUES: 39 | return new Cues(); 40 | } 41 | return super .getElement(type); 42 | } 43 | 44 | public function get info():SegmentInfo 45 | { 46 | return _info; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/SegmentInfo.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/30 11:42 5 | */ 6 | package cc.minos.codec.mkv.elements { 7 | 8 | import cc.minos.codec.mkv.Mkv; 9 | 10 | public class SegmentInfo extends Element { 11 | 12 | private var _duration:Number; 13 | private var _timeCodeScale:uint; 14 | 15 | public function SegmentInfo() 16 | { 17 | super(Mkv.SEGMENT_INFO); 18 | } 19 | 20 | override protected function init():void 21 | { 22 | trace('segment information: ' + toString() ); 23 | 24 | for(var i:int = 0; i < children.length; i++) 25 | { 26 | var e:Element = children[i]; 27 | if(e.type == Mkv.SEGMENT_DURATION){ 28 | _duration = e.getNumber(); 29 | } 30 | else if(e.type == Mkv.SEGMENT_TIME_CODE_SCALE) 31 | { 32 | _timeCodeScale = e.getInt(); 33 | } 34 | } 35 | 36 | trace('duration: ' + _duration + 'ms' ); 37 | trace('time code scale: ' + _timeCodeScale ); 38 | 39 | trace('information end. children: ' + children.length); 40 | 41 | } 42 | 43 | override protected function getElement(type:uint):Element 44 | { 45 | switch (type) 46 | { 47 | case Mkv.SEGMENT_UID: 48 | case Mkv.SEGMENT_FILE_NAME: 49 | case Mkv.SEGMENT_PREV_UID: 50 | case Mkv.SEGMENT_PREV_FILE_NAME: 51 | case Mkv.SEGMENT_NEXT_UID: 52 | case Mkv.SEGMENT_NEXT_FILE_NAME: 53 | case Mkv.SEGMENT_TIME_CODE_SCALE: 54 | case Mkv.SEGMENT_DURATION: 55 | case Mkv.SEGMENT_TITLE: 56 | case Mkv.SEGMENT_MUXINGAPP: 57 | case Mkv.SEGMENT_WRITINGAPP: 58 | case Mkv.SEGMENT_DATEUTC: 59 | return new VarElement(type); 60 | } 61 | return super.getElement(type); 62 | } 63 | 64 | public function get duration():Number 65 | { 66 | return _duration; 67 | } 68 | 69 | public function get timeCodeScale():uint 70 | { 71 | return _timeCodeScale; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/SegmentTracks.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/30 17:07 5 | */ 6 | package cc.minos.codec.mkv.elements { 7 | import cc.minos.codec.mkv.Mkv; 8 | 9 | public class SegmentTracks extends Element { 10 | public function SegmentTracks() 11 | { 12 | super(Mkv.TRACKS); 13 | } 14 | 15 | override protected function getElement(type:uint):Element 16 | { 17 | switch (type) 18 | { 19 | case Mkv.TRACK_ENTRY: 20 | return new TrackEntry(); 21 | } 22 | return super.getElement(type); 23 | } 24 | 25 | override protected function init():void 26 | { 27 | trace('tracks id: ' + toString() , 'size: ' + size ); 28 | trace('tracks end. children: ' + children.length ); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/TrackEntry.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/30 17:08 5 | */ 6 | package cc.minos.codec.mkv.elements { 7 | import cc.minos.codec.mkv.Mkv; 8 | 9 | import com.hurlant.util.Hex; 10 | 11 | import flash.utils.ByteArray; 12 | 13 | public class TrackEntry extends Element { 14 | 15 | private var _trackType:uint; 16 | private var _configurationData:ByteArray; 17 | 18 | //video 19 | private var _videoWidth:uint; 20 | private var _videoHeight:uint; 21 | private var _videoCodecId:uint; 22 | //audio 23 | private var _audioChannels:uint; 24 | private var _audioSize:uint; 25 | private var _audioRate:Number; 26 | private var _audioCodecId:uint; 27 | 28 | public function TrackEntry() 29 | { 30 | super(Mkv.TRACK_ENTRY); 31 | } 32 | 33 | override protected function getElement(type:uint):Element 34 | { 35 | switch (type) 36 | { 37 | case Mkv.TRACK_NUMBER: 38 | case Mkv.TRACK_TYPE: // 39 | case Mkv.TRACK_UID: 40 | case Mkv.TRACK_FLAG_DEFAULT: 41 | case Mkv.TRACK_FLAG_FORCED: 42 | case Mkv.TRACK_FLAG_ENABLED: 43 | case Mkv.TRACK_FLAG_LACING: 44 | case Mkv.TRACK_MIN_CACHE: 45 | case Mkv.TRACK_MAX_CACHE: 46 | case Mkv.TRACK_DEFAULT_DURATION: 47 | case Mkv.TRACK_TIMECODE_SCALE: 48 | case Mkv.TRACK_NAME: 49 | case Mkv.TRACK_LANGUAGE: 50 | case Mkv.TRACK_CODEC_ID: 51 | case Mkv.TRACK_CODEC_PRIVATE: 52 | case Mkv.TRACK_CODEC_NAME: 53 | case Mkv.TRACK_ATTACHMENT_LINK: 54 | return new VarElement(type); 55 | // video track 56 | case Mkv.TRACK_VIDEO: 57 | return new VideoTrack(); 58 | // audio track 59 | case Mkv.TRACK_AUDIO: 60 | return new AudioTrack(); 61 | // information 62 | case Mkv.CONTENT_ENCODINGS: 63 | return new ContentEncodings(); 64 | } 65 | return super.getElement(type); 66 | } 67 | 68 | override protected function init():void 69 | { 70 | // 71 | trace(' === track entry === ') 72 | for(var i:int = 0; i < children.length; i++) 73 | { 74 | var e:Element = children[i]; 75 | if( e.type == Mkv.TRACK_CODEC_ID ) 76 | { 77 | trace('codec id: ' + e.getString()); // 78 | } 79 | else if( e.type == Mkv.TRACK_TYPE ) 80 | { 81 | trace('type: ' + e.getInt().toString(16)); // 82 | _trackType = e.getInt(); 83 | }else if( e.type == Mkv.TRACK_DEFAULT_DURATION ) 84 | { 85 | trace('timestamp: ' + e.getInt()); 86 | }else if( e.type == Mkv.TRACK_CODEC_PRIVATE ) 87 | { 88 | trace('codec private: ' + e.data.length ); 89 | e.data.position = 0; 90 | trace(e.data.readByte()); 91 | trace(e.data.readByte()); 92 | trace(e.data.readByte()); 93 | _configurationData = new ByteArray(); 94 | _configurationData.writeBytes( e.data, 3, e.data.bytesAvailable ); 95 | } 96 | else if( e.type == Mkv.TRACK_CODEC_NAME ) 97 | { 98 | trace('codec name: ' + e.getString() ); 99 | } 100 | else if( e.type == Mkv.TRACK_VIDEO ) 101 | { 102 | var v:VideoTrack = e as VideoTrack; 103 | _videoWidth = v.width; 104 | _videoHeight = v.height; 105 | } 106 | else if( e.type == Mkv.TRACK_AUDIO ) 107 | { 108 | var a:AudioTrack = e as AudioTrack; 109 | // 110 | } 111 | } 112 | 113 | trace('track end. children: ' + children.length ); 114 | } 115 | 116 | public function get configurationData():ByteArray 117 | { 118 | return _configurationData; 119 | } 120 | 121 | public function get trackType():uint 122 | { 123 | return _trackType; 124 | } 125 | 126 | public function get videoWidth():uint 127 | { 128 | return _videoWidth; 129 | } 130 | 131 | public function get videoHeight():uint 132 | { 133 | return _videoHeight; 134 | } 135 | 136 | public function get audioChannels():uint 137 | { 138 | return _audioChannels; 139 | } 140 | 141 | public function get audioSize():uint 142 | { 143 | return _audioSize; 144 | } 145 | 146 | public function get audioRate():Number 147 | { 148 | return _audioRate; 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/VarElement.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/30 16:30 5 | */ 6 | package cc.minos.codec.mkv.elements { 7 | import flash.utils.ByteArray; 8 | 9 | public class VarElement extends Element { 10 | 11 | public function VarElement(type:uint) 12 | { 13 | super(type); 14 | } 15 | 16 | override public function parse(bytes:ByteArray):void 17 | { 18 | _data = bytes; 19 | _children = new Vector.(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mkv/elements/VideoTrack.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/30 17:12 5 | */ 6 | package cc.minos.codec.mkv.elements { 7 | import cc.minos.codec.mkv.Mkv; 8 | 9 | public class VideoTrack extends Element { 10 | 11 | private var _width:uint; 12 | private var _height:uint; 13 | 14 | public function VideoTrack() 15 | { 16 | super(Mkv.TRACK_VIDEO); 17 | } 18 | 19 | override protected function getElement(type:uint):Element 20 | { 21 | switch(type) 22 | { 23 | case Mkv.VIDEO_PIXEL_WIDTH: 24 | case Mkv.VIDEO_PIXEL_HEIGHT: 25 | case Mkv.VIDEO_PIXEL_CROP_BOTTOM: 26 | case Mkv.VIDEO_PIXEL_CROP_TOP: 27 | case Mkv.VIDEO_PIXEL_CROP_LEFT: 28 | case Mkv.VIDEO_PIXEL_CROP_RIGHT: 29 | case Mkv.VIDEO_DISPLAY_WIDTH: 30 | case Mkv.VIDEO_DISPLAY_HEIGHT: 31 | case Mkv.VIDEO_DISPLAY_UINT: 32 | return new VarElement(type); 33 | } 34 | return super.getElement(type); 35 | } 36 | 37 | override protected function init():void 38 | { 39 | trace('video track'); 40 | _width = getChildByType(Mkv.VIDEO_DISPLAY_WIDTH)[0].getInt(); 41 | _height = getChildByType(Mkv.VIDEO_DISPLAY_HEIGHT)[0].getInt(); 42 | trace('width: ' + _width); 43 | trace('height: ' + _height); 44 | trace('children: ' + children.length); 45 | } 46 | 47 | public function get width():uint 48 | { 49 | return _width; 50 | } 51 | 52 | public function get height():uint 53 | { 54 | return _height; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/Mp4.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/8 16:30 5 | */ 6 | package cc.minos.codec.mp4 { 7 | import cc.minos.codec.mp4.boxs.*; 8 | 9 | public class Mp4 { 10 | 11 | /** audio codec **/ 12 | 13 | public static const CODEC_ID_MOV_TEXT:uint = 0x08; 14 | public static const CODEC_ID_MPEG4:uint = 0x20; 15 | public static const CODEC_ID_H264:uint = 0x21; 16 | public static const CODEC_ID_AAC:uint = 0x40; 17 | public static const CODEC_ID_MP3:uint = 0x69; 18 | public static const CODEC_ID_AC3:uint = 0xA5; 19 | 20 | public static const CODEC_ID_MPEG2_AAC:uint = 0x66; 21 | public static const CODEC_ID_MPEG2_AAC_LOW:uint = 0x67; 22 | public static const CODEC_ID_MPEG2_AAC_SSR:uint = 0x68; 23 | 24 | /** **/ 25 | 26 | public static const FIXED_POINT_16_16:Number = 65536.0; 27 | public static const FIXED_POINT_8_8:Number = 256.0; 28 | 29 | /** trak type **/ 30 | 31 | public static const TRAK_TYPE_VIDE:uint = 0x76696465; 32 | public static const TRAK_TYPE_SOUN:uint = 0x736F756E; 33 | 34 | /** mp4 box type **/ 35 | 36 | //file type 37 | public static const BOX_TYPE_FTYP:uint = 0x66747970; 38 | //metadata container 39 | public static const BOX_TYPE_MOOV:uint = 0x6D6F6F76; 40 | //media data container 41 | public static const BOX_TYPE_MDAT:uint = 0x6D646174; 42 | //movie header 43 | public static const BOX_TYPE_MVHD:uint = 0x6D766864; 44 | public static const BOX_TYPE_IODS:uint = 0x696F6473; 45 | //track or stream container 46 | public static const BOX_TYPE_TRAK:uint = 0x7472616B; 47 | public static const BOX_TYPE_UDTA:uint = 0x75647461; 48 | //track header 49 | public static const BOX_TYPE_TKHD:uint = 0x746B6864; 50 | public static const BOX_TYPE_EDTS:uint = 0x65647473; 51 | public static const BOX_TYPE_ELST:uint = 0x656C7374; 52 | //track media information container 53 | public static const BOX_TYPE_MDIA:uint = 0x6D646961; 54 | //media header 55 | public static const BOX_TYPE_MDHD:uint = 0x6D646864; 56 | //handler 57 | public static const BOX_TYPE_HDLR:uint = 0x68646C72; 58 | //media information container 59 | public static const BOX_TYPE_MINF:uint = 0x6D696E66; 60 | 61 | public static const BOX_TYPE_VMHD:uint = 0x766D6864; 62 | public static const BOX_TYPE_SMHD:uint = 0x736D6864; 63 | public static const BOX_TYPE_DINF:uint = 0x64696E66; 64 | public static const BOX_TYPE_DREF:uint = 0x64726566; 65 | //sample table box 66 | public static const BOX_TYPE_STBL:uint = 0x7374626C; 67 | //sample descriptions 68 | public static const BOX_TYPE_STSD:uint = 0x73747364; 69 | //time to sample 70 | public static const BOX_TYPE_STTS:uint = 0x73747473; 71 | //sample to chunk 72 | public static const BOX_TYPE_STSC:uint = 0x73747363; 73 | //sample size 74 | public static const BOX_TYPE_STSZ:uint = 0x7374737A; 75 | // 76 | public static const BOX_TYPE_CTTS:uint = 0x63747473; 77 | //sync sample table 78 | public static const BOX_TYPE_STSS:uint = 0x73747373; 79 | //chunk offset 80 | public static const BOX_TYPE_STCO:uint = 0x7374636F; 81 | public static const BOX_TYPE_CO64:uint = 0x636F0604; 82 | 83 | public static const BOX_TYPE_MP4A:uint = 0x6D703461; 84 | public static const BOX_TYPE_ESDS:uint = 0x65736473; 85 | 86 | public static const BOX_TYPE_MP4S:uint = 0x6D703473; 87 | 88 | public static const BOX_TYPE_AVC1:uint = 0x61766331; 89 | public static const BOX_TYPE_AVCC:uint = 0x61766343; 90 | public static const BOX_TYPE_BTRT:uint = 0x62747274; 91 | 92 | public static const BOX_TYPE_META:uint = 0x6D657461; 93 | 94 | public static const BOX_TYPE_FREE:uint = 0x66726565; 95 | 96 | 97 | /** 98 | * 99 | * @param type 100 | * @return Box 101 | */ 102 | public static function getBox(type:uint):Box 103 | { 104 | var box:Box = null; 105 | switch(type) 106 | { 107 | case BOX_TYPE_FTYP: 108 | box = new FtypBox(); 109 | break; 110 | case BOX_TYPE_MOOV: 111 | box = new MoovBox(); 112 | break; 113 | case BOX_TYPE_MDAT: 114 | box = new MdatBox(); 115 | break; 116 | // 117 | case BOX_TYPE_MVHD: 118 | box = new MvhdBox(); 119 | break; 120 | case BOX_TYPE_TRAK: 121 | box = new TrakBox(); 122 | break; 123 | case BOX_TYPE_STBL: 124 | box = new StblBox(); 125 | break; 126 | case BOX_TYPE_HDLR: 127 | box = new HdlrBox(); 128 | break; 129 | //sample table 130 | case BOX_TYPE_STSS: 131 | box = new StssBox(); 132 | break; 133 | case BOX_TYPE_CTTS: 134 | box = new CttsBox(); 135 | break; 136 | case BOX_TYPE_STSC: 137 | box = new StscBox(); 138 | break; 139 | case BOX_TYPE_STCO: 140 | box = new StcoBox(); 141 | break; 142 | case BOX_TYPE_STSZ: 143 | box = new StszBox(); 144 | break; 145 | /*case BOX_TYPE_AVCC: 146 | box = new AvccBox(); 147 | break; 148 | case BOX_TYPE_ESDS: 149 | box = new EsdsBox(); 150 | break;*/ 151 | case BOX_TYPE_TKHD: 152 | box = new TkhdBox(); 153 | break; 154 | case BOX_TYPE_STSD: 155 | box = new StsdBox(); 156 | break; 157 | case BOX_TYPE_STTS: 158 | box = new SttsBox(); 159 | break; 160 | case BOX_TYPE_MDHD: 161 | box = new MdhdBox(); 162 | break; 163 | //others 164 | case BOX_TYPE_META: 165 | case BOX_TYPE_MDIA: 166 | case BOX_TYPE_ELST: 167 | case BOX_TYPE_MINF: 168 | case BOX_TYPE_UDTA: 169 | case BOX_TYPE_IODS: 170 | case BOX_TYPE_EDTS: 171 | case BOX_TYPE_VMHD: 172 | case BOX_TYPE_SMHD: 173 | case BOX_TYPE_DINF: 174 | case BOX_TYPE_DREF: 175 | case BOX_TYPE_FREE: 176 | box = new Box(type); 177 | break; 178 | default : 179 | trace('[MP4::getBox] 0x' + type.toString(16) + ' not defined.'); 180 | } 181 | return box; 182 | } 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/Mp4Codec.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/24 15:36 5 | */ 6 | package cc.minos.codec.mp4 { 7 | 8 | import cc.minos.codec.Codec; 9 | import cc.minos.codec.flv.Frame; 10 | import cc.minos.codec.mp4.boxs.*; 11 | import flash.utils.ByteArray; 12 | 13 | /** 14 | * mp4解析 15 | * moov記錄了整個視頻的數據 16 | * stbl記錄幀的數據(位移大小等,獲取的時候需要分析chunk(1個chunk可以有幾個sample)) 17 | * stsd記錄編碼的數據,視頻或音頻的解析需要在這裏取數據 18 | */ 19 | public class Mp4Codec extends Codec { 20 | 21 | //數據信息 22 | protected var moovBox:MoovBox; 23 | //視頻幀列表 24 | protected var _videoSamples:Vector.; 25 | //音頻幀列表 26 | protected var _audioSamples:Vector.; 27 | 28 | public function Mp4Codec() 29 | { 30 | _name = "mp4,f4v"; 31 | _extensions = "mp4,f4v"; 32 | _mimeType = "video/mp4"; 33 | } 34 | 35 | /** 36 | * 排序 37 | * @param a 38 | * @param b 39 | * @param array 40 | * @return 41 | */ 42 | private function sortByIndex(a:Object, b:Object, array:Array = null):int 43 | { 44 | //改用渲染順序來排序 45 | if (a.index < b.index ) 46 | { 47 | return -1; 48 | } 49 | else if(a.index > b.index){ 50 | return 1; 51 | } 52 | if (a.dataType == 0x09) 53 | { 54 | return -1; 55 | } 56 | else if (b.dataType == 0x09) 57 | { 58 | return 1; 59 | } 60 | return 0; 61 | } 62 | 63 | /** 64 | * 解析 65 | * @param input 66 | * @return 67 | */ 68 | override public function decode(input:ByteArray):Codec 69 | { 70 | if (!probe(input)) 71 | throw new Error('Not a valid MP4 file!'); 72 | 73 | this._rawData = input; 74 | //find moov box 75 | //直接搜moov解析 76 | var offset:uint; 77 | var size:uint; 78 | var type:uint; 79 | _rawData.position = 0; 80 | while (_rawData.bytesAvailable > 8) 81 | { 82 | offset = _rawData.position; 83 | size = _rawData.readUnsignedInt(); 84 | type = _rawData.readUnsignedInt(); 85 | if (type == Mp4.BOX_TYPE_MOOV) 86 | { 87 | var d:ByteArray = new ByteArray(); 88 | d.writeBytes(_rawData, offset, size); 89 | moovBox = new MoovBox(); 90 | moovBox.size = size; 91 | moovBox.position = offset; 92 | moovBox.parse(d); 93 | break; 94 | } 95 | _rawData.position = (offset + size); 96 | } 97 | // 98 | _duration = moovBox.mvhdBox.duration; 99 | //獲取解析的數據 100 | for (var i:int = 0; i < moovBox.traks.length; i++) 101 | { 102 | var trak:TrakBox = moovBox.traks[i] as TrakBox; 103 | if (trak.trakType == Mp4.TRAK_TYPE_VIDE) 104 | { 105 | _hasVideo = true; 106 | _videoWidth = trak.stsdBox.videoWidth; 107 | _videoHeight = trak.stsdBox.videoHeight; 108 | _frameRate = trak.framerate; 109 | _videoSamples = trak.samples; 110 | //-- video sps & pps 111 | _videoConfig = trak.stsdBox.configurationData; 112 | _keyframes = trak.keyframes; 113 | } 114 | else if (trak.trakType == Mp4.TRAK_TYPE_SOUN) 115 | { 116 | _hasAudio = true; 117 | _audioChannels = trak.stsdBox.audioChannels; 118 | _audioRate = trak.stsdBox.audioRate; 119 | _audioSize = trak.stsdBox.audioSize; 120 | _audioSamples = trak.samples; 121 | //-- audio spec 122 | _audioConfig = trak.stsdBox.configurationData; 123 | } 124 | } 125 | //根據時間戳排列幀 126 | _frames = new Vector.(); 127 | if (_videoSamples != null) 128 | { 129 | for each(var v:Frame in _videoSamples) 130 | { 131 | _frames.push(v); 132 | } 133 | } 134 | if (_audioSamples != null) 135 | { 136 | for each(var a:Frame in _audioSamples) 137 | { 138 | _frames.push(a); 139 | } 140 | } 141 | _frames.sort(sortByIndex); 142 | 143 | return this; 144 | } 145 | 146 | /** 147 | * 封裝(未完成) 148 | * @param input 149 | * @return 150 | */ 151 | override public function encode(input:Codec):ByteArray 152 | { 153 | return null; 154 | } 155 | 156 | /** 157 | * 判斷 158 | * @param input 159 | * @return 160 | */ 161 | public static function probe(input:ByteArray):Boolean 162 | { 163 | if (input[4] == 0x66 && input[5] == 0x74 && input[6] == 0x79 && input[7] == 0x70) 164 | return true; 165 | return false; 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/Sample.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/10 15:21 5 | */ 6 | package cc.minos.codec.mp4 { 7 | 8 | import cc.minos.codec.*; 9 | import cc.minos.codec.flv.Frame; 10 | 11 | public class Sample extends Frame { 12 | 13 | //index in chunk 14 | public var sampleIndex:uint; 15 | //chunk index 16 | public var chunkIndex:uint; 17 | 18 | public function Sample() 19 | { 20 | super("mp4"); 21 | } 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/boxs/Box.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/8 16:36 5 | */ 6 | package cc.minos.codec.mp4.boxs { 7 | 8 | import cc.minos.codec.mp4.Mp4; 9 | import cc.minos.codec.utils.Hex; 10 | 11 | import flash.utils.ByteArray; 12 | 13 | /** 14 | * base box 15 | */ 16 | public class Box { 17 | 18 | private var _type:uint = 0x0; 19 | private var _size:uint = 0; 20 | private var _position:uint = 0; 21 | private var _data:ByteArray; 22 | private var _children:Vector.; 23 | 24 | public function Box(type:uint) 25 | { 26 | this._type = type; 27 | } 28 | 29 | public function parse(byte:ByteArray):void 30 | { 31 | this.data = byte; 32 | this._children = new Vector.(); 33 | 34 | var size:uint; 35 | var type:uint; 36 | var offset:uint; 37 | var end:uint; 38 | var box:Box; 39 | 40 | data.position = 0; 41 | while (data.bytesAvailable > 8) 42 | { 43 | offset = data.position; 44 | size = data.readUnsignedInt(); 45 | type = data.readUnsignedInt(); 46 | if (type === this.type) 47 | { 48 | this.size = size; 49 | decode(); 50 | continue; 51 | } 52 | end = offset + size; 53 | box = Mp4.getBox(type); 54 | if (box) 55 | { 56 | if (size == 1) 57 | { 58 | size = data.readDouble(); 59 | end = offset + size; 60 | } 61 | box.size = size; 62 | box.position = offset; 63 | var d:ByteArray = new ByteArray(); 64 | d.writeBytes(data, offset, size); 65 | box.parse(d); 66 | _children.push(box); 67 | }else{ 68 | break; 69 | } 70 | data.position = end; 71 | } 72 | init(); 73 | } 74 | 75 | /** **/ 76 | protected function decode():void 77 | { 78 | } 79 | 80 | /** **/ 81 | protected function init():void 82 | { 83 | } 84 | 85 | /** 86 | * 87 | * @param type : uint 88 | * @return Vector. 89 | */ 90 | public function getBox(type:uint):Vector. 91 | { 92 | var boxs:Vector. = new Vector.(); 93 | if (_children.length > 0) 94 | { 95 | for each(var b:Box in _children) 96 | { 97 | if (b.type === type) 98 | boxs.push(b); 99 | else if (boxs.length == 0 && b.children.length > 0) 100 | { 101 | boxs = b.getBox(type); 102 | if (boxs.length > 0) 103 | { 104 | return boxs; 105 | } 106 | } 107 | } 108 | } 109 | return boxs; 110 | } 111 | 112 | public function get size():uint 113 | { 114 | return _size; 115 | } 116 | 117 | public function set size(value:uint):void 118 | { 119 | _size = value; 120 | } 121 | 122 | public function get position():uint 123 | { 124 | return _position; 125 | } 126 | 127 | public function set position(value:uint):void 128 | { 129 | _position = value; 130 | } 131 | 132 | public function get data():ByteArray 133 | { 134 | return _data; 135 | } 136 | 137 | public function set data(value:ByteArray):void 138 | { 139 | _data = value; 140 | } 141 | 142 | public function get type():uint 143 | { 144 | return _type; 145 | } 146 | 147 | public function get children():Vector. 148 | { 149 | return _children; 150 | } 151 | 152 | public function toString():String 153 | { 154 | return '[ ' + Hex.toUTF8String(type.toString(16)) + ' Box, size: ' + size + ' ]'; 155 | } 156 | 157 | /*public static function findBox( data:ByteArray, type:uint ):Box 158 | { 159 | var byte:ByteArray = new ByteArray(); 160 | byte.writeUnsignedInt(type); 161 | var index:int = ByteArrayUtil.byteArrayIndexOf(data, byte); 162 | if(index != -1) 163 | { 164 | byte.clear(); 165 | data.position = index - 4; 166 | var size:int = data.readUnsignedInt(); 167 | byte.writeBytes(data, index - 4, size); 168 | var box:Box = Mp4.getBox(type); 169 | box.parse(byte); 170 | box.position = index - 4; 171 | return box; 172 | } 173 | return null; 174 | }*/ 175 | 176 | } 177 | } -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/boxs/CttsBox.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Created by SiuzukZan on 04/13/2015 19:14 4 | */ 5 | package cc.minos.codec.mp4.boxs { 6 | 7 | import cc.minos.codec.mp4.Mp4; 8 | 9 | public class CttsBox extends Box { 10 | 11 | private var _count:uint; 12 | private var _entries:Array; 13 | 14 | public function CttsBox() 15 | { 16 | super(Mp4.BOX_TYPE_CTTS); 17 | } 18 | 19 | override protected function init():void 20 | { 21 | data.position = 12; 22 | _count = data.readUnsignedInt(); // 23 | _entries = []; 24 | var sampleCount:uint = 0; 25 | var sampleOffset:uint = 0; 26 | for (var i:int = 0; i < _count; i++) 27 | { 28 | sampleCount = data.readUnsignedInt(); 29 | sampleOffset = data.readUnsignedInt(); 30 | for (var j:uint = 0; j < sampleCount; j++) 31 | { 32 | _entries.push(sampleOffset); 33 | } 34 | } 35 | } 36 | 37 | public function get count():uint 38 | { 39 | return _count; 40 | } 41 | 42 | public function get entries():Array 43 | { 44 | return _entries; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/boxs/FtypBox.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/8 16:41 5 | */ 6 | package cc.minos.codec.mp4.boxs { 7 | 8 | import cc.minos.codec.mp4.Mp4; 9 | 10 | CONFIG::LOGGING{ 11 | import cc.minos.codec.utils.Log; 12 | } 13 | 14 | public class FtypBox extends Box { 15 | 16 | private var _majorBrand:String; 17 | private var _minorVersion:uint; 18 | private var _compatibleBrands:Array; 19 | 20 | public function FtypBox() 21 | { 22 | super(Mp4.BOX_TYPE_FTYP); 23 | } 24 | 25 | override protected function init():void 26 | { 27 | data.position = 8; 28 | _majorBrand = data.readUTFBytes(4); 29 | _minorVersion = data.readUnsignedInt(); 30 | _compatibleBrands = []; 31 | while (data.bytesAvailable >= 4) 32 | { 33 | _compatibleBrands.push(data.readUTFBytes(4)); 34 | } 35 | 36 | CONFIG::LOGGING{ 37 | Log.info('[ftyp]'); 38 | Log.info('majorBrand: ' + _majorBrand); 39 | Log.info('minorVersion: ' + _minorVersion); 40 | Log.info('brands: ' + _compatibleBrands); 41 | } 42 | } 43 | 44 | public function get majorBrand():String 45 | { 46 | return _majorBrand; 47 | } 48 | 49 | public function get minorVersion():uint 50 | { 51 | return _minorVersion; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/boxs/HdlrBox.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/10 14:16 5 | */ 6 | package cc.minos.codec.mp4.boxs { 7 | import cc.minos.codec.mp4.Mp4; 8 | 9 | public class HdlrBox extends Box { 10 | 11 | private var _hdType:uint; 12 | 13 | public function HdlrBox() 14 | { 15 | super(Mp4.BOX_TYPE_HDLR); 16 | } 17 | 18 | override protected function init():void 19 | { 20 | data.position = 16; 21 | _hdType = data.readUnsignedInt(); 22 | if( _hdType === Mp4.TRAK_TYPE_VIDE ) 23 | { 24 | } 25 | else if( _hdType === Mp4.TRAK_TYPE_SOUN ) 26 | { 27 | } 28 | } 29 | 30 | public function get hdType():uint 31 | { 32 | return _hdType; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/boxs/MdatBox.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/9 10:10 5 | */ 6 | package cc.minos.codec.mp4.boxs { 7 | import cc.minos.codec.mp4.Mp4; 8 | 9 | public class MdatBox extends Box { 10 | 11 | public function MdatBox() 12 | { 13 | super(Mp4.BOX_TYPE_MDAT); 14 | } 15 | 16 | override protected function init():void 17 | { 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/boxs/MdhdBox.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/18 14:22 5 | */ 6 | package cc.minos.codec.mp4.boxs { 7 | import cc.minos.codec.mp4.Mp4; 8 | 9 | public class MdhdBox extends Box { 10 | 11 | private var _version:uint; 12 | private var _timeScale:uint; 13 | private var _duration:uint; 14 | 15 | public function MdhdBox() 16 | { 17 | super(Mp4.BOX_TYPE_MDHD); 18 | } 19 | 20 | override protected function init():void 21 | { 22 | data.position = 8; 23 | _version = data.readUnsignedByte(); 24 | if(_version == 1) 25 | { 26 | data.position += 17; 27 | _timeScale = data.readUnsignedInt(); 28 | }else 29 | { 30 | data.position += 11; 31 | _timeScale = data.readUnsignedInt(); 32 | _duration = data.readUnsignedInt(); 33 | } 34 | // trace('scale: ' + _timeScale, 'duration: ' + _duration ); 35 | } 36 | 37 | public function get timeScale():uint 38 | { 39 | return _timeScale; 40 | } 41 | 42 | public function get duration():uint 43 | { 44 | return _duration; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/boxs/MoovBox.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/8 17:31 5 | */ 6 | package cc.minos.codec.mp4.boxs { 7 | 8 | import cc.minos.codec.mp4.Mp4; 9 | 10 | CONFIG::LOGGING{ 11 | import cc.minos.codec.utils.Log; 12 | } 13 | 14 | public class MoovBox extends Box { 15 | 16 | private var _mvhdBox:MvhdBox; 17 | private var _traks:Vector.; 18 | 19 | public function MoovBox() 20 | { 21 | super(Mp4.BOX_TYPE_MOOV); 22 | } 23 | 24 | override protected function init():void 25 | { 26 | _mvhdBox = getBox(Mp4.BOX_TYPE_MVHD).shift() as MvhdBox; 27 | _traks = getBox(Mp4.BOX_TYPE_TRAK); 28 | 29 | CONFIG::LOGGING{ 30 | Log.info('traks: ' + traks.length); 31 | } 32 | } 33 | 34 | public function get mvhdBox():MvhdBox 35 | { 36 | return _mvhdBox; 37 | } 38 | 39 | public function get traks():Vector. 40 | { 41 | return _traks; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/boxs/MvhdBox.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/8 17:41 5 | */ 6 | package cc.minos.codec.mp4.boxs { 7 | import cc.minos.codec.mp4.Mp4; 8 | 9 | public class MvhdBox extends Box { 10 | 11 | private var _timescale:uint = 600; 12 | private var _duration:uint = 0; 13 | private var _version:uint = 0; 14 | 15 | public function MvhdBox() 16 | { 17 | super( Mp4.BOX_TYPE_MVHD ); 18 | } 19 | 20 | override protected function init():void 21 | { 22 | data.position = 8; //size, type 23 | _version = data.readUnsignedByte(); //version 24 | data.position += 3; //flags 25 | if( _version == 0 ) 26 | { 27 | //32 28 | data.readUnsignedInt(); //creation time 29 | data.readUnsignedInt(); //modification time 30 | _timescale = data.readUnsignedInt(); 31 | _duration = data.readUnsignedInt(); 32 | } 33 | else if( _version == 1 ) 34 | { 35 | //64 36 | } 37 | } 38 | 39 | /** 40 | * second 41 | */ 42 | public function get duration():Number 43 | { 44 | return parseFloat((_duration / _timescale).toFixed(3)); 45 | } 46 | 47 | /** 48 | * default: 600 49 | */ 50 | public function get timescale():uint 51 | { 52 | return _timescale; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/boxs/StblBox.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/9 11:20 5 | */ 6 | package cc.minos.codec.mp4.boxs { 7 | 8 | import cc.minos.codec.mp4.Sample; 9 | import cc.minos.codec.flv.FlvCodec; 10 | import cc.minos.codec.mp4.Mp4; 11 | 12 | CONFIG::LOGGING{ 13 | import cc.minos.codec.utils.Log; 14 | } 15 | /** 16 | * sample table 17 | */ 18 | public class StblBox extends Box { 19 | 20 | private var _samples:Vector.; 21 | 22 | private var hasKey:Boolean = false; 23 | 24 | private var _stsdBox:StsdBox; 25 | private var _sttsBox:SttsBox; 26 | private var _cttsBox:CttsBox; 27 | private var _stssBox:StssBox; 28 | 29 | public function StblBox() 30 | { 31 | super(Mp4.BOX_TYPE_STBL); 32 | } 33 | 34 | override protected function init():void 35 | { 36 | _stsdBox = getBox(Mp4.BOX_TYPE_STSD).shift() as StsdBox; 37 | 38 | //stts 39 | _sttsBox = getBox(Mp4.BOX_TYPE_STTS).shift() as SttsBox; 40 | var st:Array = _sttsBox.entries; 41 | 42 | //ctts 43 | var ct:Array; 44 | try 45 | { 46 | _cttsBox = getBox(Mp4.BOX_TYPE_CTTS).shift() as CttsBox; 47 | ct = _cttsBox.entries; 48 | } catch (er:Error) 49 | { 50 | CONFIG::LOGGING{ 51 | Log.info("ctts box not found!") 52 | } 53 | } 54 | 55 | //stsz 56 | var sizes:Vector.; 57 | try 58 | { 59 | var stszBox:StszBox = getBox(Mp4.BOX_TYPE_STSZ).shift() as StszBox; 60 | sizes = stszBox.sizes; 61 | } catch (er:Error) 62 | { 63 | CONFIG::LOGGING{ 64 | Log.info("sample size list not found!"); 65 | } 66 | throw new Error("stz2 not parse"); 67 | //stz2 ? 68 | } 69 | //stsc 70 | var entrys:Vector.; 71 | var stscBox:StscBox = getBox(Mp4.BOX_TYPE_STSC).shift() as StscBox; 72 | entrys = stscBox.entrys; 73 | 74 | //stco 75 | var chunksOffset:Vector.; 76 | try 77 | { 78 | var stcoBox:StcoBox = getBox(Mp4.BOX_TYPE_STCO).shift() as StcoBox; 79 | chunksOffset = stcoBox.chunksOffset; 80 | } catch (er:Error) 81 | { 82 | CONFIG::LOGGING{ 83 | Log.info("chunk offset list not found!"); 84 | } 85 | throw new Error("co64 not parse"); 86 | //co64 ? 87 | } 88 | //stss 89 | var keyframes:Array 90 | try 91 | { 92 | _stssBox = getBox(Mp4.BOX_TYPE_STSS).shift() as StssBox; 93 | keyframes = _stssBox.keyframes; 94 | hasKey = true; 95 | } catch (er:Error) 96 | { 97 | CONFIG::LOGGING{ 98 | Log.info('Not found key frames!'); 99 | } 100 | hasKey = false; 101 | } 102 | 103 | //chunk -> sample 104 | var chunk:Vector. = new Vector.(chunksOffset.length); 105 | var lastNum:uint = chunksOffset.length + 1; 106 | for (var ci:int = entrys.length - 1; ci >= 0; --ci) 107 | { 108 | var begin:uint = entrys[ci].first_chk; 109 | for (var ck:uint = begin - 1; ck < lastNum - 1; ++ck) 110 | { 111 | chunk[ck] = { 112 | 'sam_count': entrys[ci].sams_per_chk, //chunk的sample数量 113 | 'sdi': entrys[ci].sdi 114 | }; 115 | } 116 | lastNum = begin; 117 | } 118 | //sample -> chunk 119 | _samples = new Vector.(); 120 | var s:Sample; 121 | var samIndex:uint = 0; 122 | for (ck = 0; ck < chunk.length; ++ck) 123 | { 124 | chunk[ck].first_sam_index = samIndex; 125 | var chkIndex:uint = 0; 126 | var offset:uint = chunksOffset[ck]; 127 | for (var si:int = 0; si < chunk[ck].sam_count; ++si) 128 | { 129 | s = new Sample(); 130 | s.chunkIndex = ck; 131 | s.sampleIndex = chkIndex; 132 | s.offset = offset; 133 | s.index = samIndex; 134 | s.size = sizes[samIndex]; 135 | s.timestamp = st[samIndex]; 136 | if (ct) 137 | { 138 | s.timestamp += ct[samIndex]; 139 | } 140 | if (_stsdBox.videoWidth > 0) 141 | { 142 | s.dataType = FlvCodec.TAG_TYPE_VIDEO; 143 | s.frameType = (keyframes.indexOf(samIndex+1) != -1) ? FlvCodec.VIDEO_FRAME_KEY : FlvCodec.VIDEO_FRAME_INTER; 144 | } 145 | else 146 | { 147 | s.dataType = FlvCodec.TAG_TYPE_AUDIO; 148 | } 149 | _samples.push(s); 150 | offset += sizes[samIndex]; 151 | samIndex++; 152 | chkIndex++; 153 | } 154 | } 155 | 156 | CONFIG::LOGGING{ 157 | Log.info('chunk: ' + chunk.length); 158 | Log.info('samples: ' + samples.length); 159 | } 160 | } 161 | 162 | public function get samples():Vector. 163 | { 164 | return _samples; 165 | } 166 | 167 | public function get stsdBox():StsdBox 168 | { 169 | return _stsdBox; 170 | } 171 | 172 | public function get sttsBox():SttsBox 173 | { 174 | return _sttsBox; 175 | } 176 | 177 | public function get stssBox():StssBox 178 | { 179 | return _stssBox; 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/boxs/StcoBox.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/10 14:59 5 | */ 6 | package cc.minos.codec.mp4.boxs { 7 | import cc.minos.codec.mp4.Mp4; 8 | 9 | /** 10 | * chunk offset 11 | */ 12 | public class StcoBox extends Box { 13 | 14 | private var _count:uint; 15 | private var _chunksOffset:Vector. = new Vector.(); 16 | 17 | public function StcoBox() 18 | { 19 | super(Mp4.BOX_TYPE_STCO); 20 | } 21 | 22 | override protected function init():void 23 | { 24 | data.position = 12; 25 | _count = data.readUnsignedInt(); 26 | for(var i:int =0;i<_count;i++) 27 | { 28 | _chunksOffset.push(data.readUnsignedInt()); 29 | } 30 | } 31 | 32 | public function get chunksOffset():Vector. 33 | { 34 | return _chunksOffset; 35 | } 36 | 37 | public function get count():uint 38 | { 39 | return _count; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/boxs/StscBox.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/10 14:55 5 | */ 6 | package cc.minos.codec.mp4.boxs { 7 | import cc.minos.codec.mp4.Mp4; 8 | 9 | /** 10 | * sample to chunk 11 | */ 12 | public class StscBox extends Box { 13 | 14 | private var _count:uint; 15 | private var _entrys:Vector. = new Vector.(); 16 | 17 | public function StscBox() 18 | { 19 | super(Mp4.BOX_TYPE_STSC); 20 | } 21 | 22 | override protected function init():void 23 | { 24 | data.position = 12; 25 | _count = data.readUnsignedInt(); 26 | for(var i:int = 0; i < _count; i++) 27 | { 28 | _entrys.push({ 29 | 'first_chk': data.readUnsignedInt(), 30 | 'sams_per_chk': data.readUnsignedInt(), 31 | 'sdi': data.readUnsignedInt() 32 | }) 33 | } 34 | } 35 | 36 | public function get entrys():Vector. 37 | { 38 | return _entrys; 39 | } 40 | 41 | public function get count():uint 42 | { 43 | return _count; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/boxs/StsdBox.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/15 10:43 5 | */ 6 | package cc.minos.codec.mp4.boxs { 7 | 8 | import cc.minos.codec.mp4.Mp4; 9 | import cc.minos.codec.utils.Hex; 10 | 11 | import flash.utils.ByteArray; 12 | 13 | CONFIG::LOGGING{ 14 | import cc.minos.codec.utils.Log; 15 | } 16 | 17 | public class StsdBox extends Box { 18 | 19 | //video 20 | private var _videoWidth:uint; 21 | private var _videoHeight:uint; 22 | private var _videoCodecId:uint; 23 | //audio 24 | private var _audioChannels:uint; 25 | private var _audioSize:uint; 26 | private var _audioRate:Number; 27 | private var _audioCodecId:uint; 28 | // 29 | private var _configurationData:ByteArray; 30 | 31 | public function StsdBox() 32 | { 33 | super(Mp4.BOX_TYPE_STSD); 34 | } 35 | 36 | override protected function decode():void 37 | { 38 | CONFIG::LOGGING{ 39 | Log.info('[stsd]'); 40 | } 41 | data.position += 4; //version flags 42 | data.readUnsignedInt(); //count 1 43 | 44 | var codecSize:uint = data.readUnsignedInt(); 45 | var codecType:uint = data.readUnsignedInt(); 46 | _configurationData = new ByteArray(); 47 | var offset:uint; 48 | var len:uint; 49 | if( codecType == Mp4.BOX_TYPE_AVC1 ) 50 | { 51 | //6 reserved 52 | data.position += 6; 53 | //2 data reference index 54 | data.position += 2; 55 | //2 video encoding version 0 56 | trace('encoding version: ' + data.readUnsignedShort()); 57 | //2 video encoding revision level 58 | trace('encoding revision level: ' + data.readUnsignedShort()); 59 | //4 video encoding vendor 60 | trace('encoding vendor: ' + data.readUnsignedInt()); 61 | //4 video temporal quality (0-1024) 62 | trace('temporal quality: ' + data.readUnsignedInt()); 63 | //4 video spatial quality (0-1024) 64 | trace('spatial quality: ' + data.readUnsignedInt()); 65 | //4 video frame pixel size (width + height) 66 | _videoWidth = data.readUnsignedShort(); 67 | _videoHeight = data.readUnsignedShort(); 68 | //8 video resolution (horizontal + vertical) 69 | trace('resolution horizontal: ' + data.readUnsignedInt()); 70 | trace('resolution vertical: ' + data.readUnsignedInt()); 71 | //4 video data size 72 | trace('data size: ' + data.readInt()); 73 | //2 video frame count 74 | trace('frame count: ' + data.readUnsignedShort()); 75 | //1 video encoding name string length 76 | trace('encoding name string length: ' + data.readUnsignedByte()); 77 | //31 video encoder name string 78 | data.position += 31; 79 | //2 video pixel depth 80 | trace('pixel depth: ' + data.readUnsignedShort()); 81 | //2 video color table id 82 | trace('color table id: ' + data.readShort()); 83 | 84 | // ===== AVC ===== 85 | 86 | //size 87 | trace('size: ' + data.readUnsignedInt()); 88 | //type 89 | trace('type: ' + Hex.toUTF8String(data.readUnsignedInt().toString(16))); 90 | offset = data.position; 91 | trace('version: ' + data.readByte()); 92 | trace('profile: ' + data.readUnsignedByte()); 93 | trace('compatible: ' + data.readByte()); 94 | trace('level: ' + data.readUnsignedByte()); 95 | trace('size: ' + (1 + ( data.readByte() & 0x3 ))); 96 | trace('sps num: ' + (data.readByte() & 0x1F )); 97 | var l:uint = data.readUnsignedShort(); 98 | trace('sps length: ' + l); 99 | data.position += l; 100 | trace('pps num: ' + data.readUnsignedByte()); 101 | trace('pps length: ' + data.readUnsignedShort()); 102 | 103 | // 104 | data.position = offset; 105 | _configurationData.writeBytes( data, offset, data.bytesAvailable ); 106 | 107 | CONFIG::LOGGING{ 108 | Log.info('width', _videoWidth); 109 | Log.info('height', _videoHeight); 110 | } 111 | } 112 | else if(codecType == Mp4.BOX_TYPE_MP4A ) 113 | { 114 | //6 reserved 115 | data.position += 6; 116 | //2 data reference index 117 | data.position += 2; 118 | //2 audio encoding version 0 119 | data.readUnsignedShort(); 120 | //2 audio encoding revision level 0 121 | data.readUnsignedShort(); 122 | //4 audio encoding vendor 0 123 | data.readUnsignedInt(); 124 | //2 audio channels (mono = 1 ; stereo = 2) 125 | _audioChannels = data.readUnsignedShort(); 126 | // trace('channels: ' + _audioChannels ); 127 | //2 audio sample size (8 or 16) 128 | _audioSize = data.readUnsignedShort(); 129 | // trace('sample size: ' + _audioSize ); 130 | //2 audio compression id 0 131 | data.readShort(); 132 | //2 audio packet size 0 133 | data.readShort(); 134 | //4 audio sample rate 135 | _audioRate = data.readUnsignedInt() / Mp4.FIXED_POINT_16_16 136 | // trace('rate: ' + _audioRate ); 137 | 138 | CONFIG::LOGGING{ 139 | Log.info('channels: ', _audioChannels); 140 | Log.info('size: ', _audioSize); 141 | Log.info('rate: ', _audioRate); 142 | } 143 | 144 | //========= ESDS | M4DS ========== 145 | var dsSize:uint = data.readUnsignedInt(); 146 | var dsType:uint = data.readUnsignedInt(); 147 | 148 | if(dsType == Mp4.BOX_TYPE_ESDS) 149 | readEsds(); 150 | } 151 | // 152 | data.position = data.length; 153 | } 154 | 155 | private function readEsds():void 156 | { 157 | var offset:uint; 158 | 159 | data.position += 4; //8-bit hex version + 24-bit hex flags 160 | 161 | //ES descriptor 162 | if (data.readUnsignedByte() == 0x03) 163 | { 164 | skipExtended(); // 165 | data.readUnsignedByte(); //length 166 | data.readUnsignedShort(); //ES ID 167 | data.readUnsignedByte(); //stream priority 168 | 169 | //decoder config descriptor 170 | if (data.readUnsignedByte() == 0x04) 171 | { 172 | skipExtended(); // 173 | data.readUnsignedByte(); //length 174 | data.readUnsignedByte(); //object type ID 175 | /* 176 | - type IDs are MPEG-4 video = 32 ; MPEG-4 AVC SPS = 33 177 | - type IDs are MPEG-4 AVC PPS = 34 ; MPEG-4 audio = 64 178 | ... 179 | */ 180 | //6 bits stream type + 1 bit upstream flag + 1 bit reserved flag 181 | //3 bytes buffer size 182 | //4 bytes maximum bit rate 183 | //4 bytes average bit rate 184 | data.position += 12; //skip 185 | //decoder specific descriptor 186 | if (data.readUnsignedByte() == 0x05) 187 | { 188 | skipExtended(); // 189 | var len:uint = data.readUnsignedByte(); //length 190 | _configurationData.writeBytes(data, data.position, len);// 191 | } 192 | //SL config descriptor => 0x06 193 | } 194 | } 195 | } 196 | 197 | private function skipExtended():void 198 | { 199 | while (true) 200 | { 201 | if(data.readUnsignedByte() != 0x80) 202 | break; 203 | } 204 | data.position += -1; 205 | } 206 | 207 | public function get configurationData():ByteArray 208 | { 209 | return _configurationData; 210 | } 211 | 212 | public function get audioRate():Number 213 | { 214 | return _audioRate; 215 | } 216 | 217 | public function get audioSize():uint 218 | { 219 | return _audioSize; 220 | } 221 | 222 | public function get audioChannels():uint 223 | { 224 | return _audioChannels; 225 | } 226 | 227 | public function get videoHeight():uint 228 | { 229 | return _videoHeight; 230 | } 231 | 232 | public function get videoWidth():uint 233 | { 234 | return _videoWidth; 235 | } 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/boxs/StssBox.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/10 15:05 5 | */ 6 | package cc.minos.codec.mp4.boxs { 7 | 8 | import cc.minos.codec.mp4.Mp4; 9 | 10 | /** 11 | * sync sample table (key frames) 12 | */ 13 | public class StssBox extends Box { 14 | 15 | private var _count:uint; 16 | private var _keyframes:Array = []; 17 | 18 | public function StssBox() 19 | { 20 | super(Mp4.BOX_TYPE_STSS); 21 | } 22 | 23 | override protected function init():void 24 | { 25 | data.position = 12; 26 | _count = data.readUnsignedInt(); 27 | for (var i:int = 0; i < _count; i++) 28 | { 29 | _keyframes.push(data.readUnsignedInt()); 30 | } 31 | } 32 | 33 | public function get keyframes():Array 34 | { 35 | return _keyframes; 36 | } 37 | 38 | public function get count():uint 39 | { 40 | return _count; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/boxs/StszBox.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/10 14:50 5 | */ 6 | package cc.minos.codec.mp4.boxs { 7 | import cc.minos.codec.mp4.Mp4; 8 | 9 | /** 10 | * sample size list 11 | */ 12 | public class StszBox extends Box { 13 | 14 | private var _sizes:Vector. = new Vector.(); 15 | private var _constantSize:uint; 16 | private var _count:uint; 17 | 18 | public function StszBox() 19 | { 20 | super(Mp4.BOX_TYPE_STSZ); 21 | } 22 | 23 | override protected function init():void 24 | { 25 | data.position = 12; 26 | _constantSize = data.readUnsignedInt(); 27 | _count = data.readUnsignedInt(); 28 | for(var i:int=0; i<_count; i++ ) 29 | { 30 | _sizes.push(data.readUnsignedInt()); 31 | } 32 | } 33 | 34 | public function get constantSize():uint 35 | { 36 | return _constantSize; 37 | } 38 | 39 | public function get count():uint 40 | { 41 | return _count; 42 | } 43 | 44 | public function get sizes():Vector. 45 | { 46 | return _sizes; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/boxs/SttsBox.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/18 14:17 5 | */ 6 | package cc.minos.codec.mp4.boxs { 7 | 8 | import cc.minos.codec.mp4.Mp4; 9 | 10 | public class SttsBox extends Box { 11 | 12 | private var _count:uint; 13 | private var _entries:Array; 14 | 15 | public function SttsBox() 16 | { 17 | super(Mp4.BOX_TYPE_STTS); 18 | } 19 | 20 | override protected function init():void 21 | { 22 | data.position = 12; 23 | _count = data.readUnsignedInt(); 24 | _entries = []; 25 | var sampleCount:uint = 0; 26 | var sampleOffset:uint = 0; 27 | var sampleStart:uint = 0; 28 | for (var i:int = 0; i < _count; i++) 29 | { 30 | sampleCount = data.readUnsignedInt(); 31 | sampleOffset = data.readUnsignedInt(); 32 | for (var j:uint = 0; j < sampleCount; j++) 33 | { 34 | _entries.push(sampleStart); 35 | sampleStart += sampleOffset; 36 | } 37 | } 38 | } 39 | 40 | public function get entries():Array 41 | { 42 | return _entries; 43 | } 44 | 45 | public function get count():uint 46 | { 47 | return _count; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/boxs/TkhdBox.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/11 16:19 5 | */ 6 | package cc.minos.codec.mp4.boxs { 7 | import cc.minos.codec.mp4.Mp4; 8 | import cc.minos.codec.utils.SimpleDateFormatter; 9 | 10 | public class TkhdBox extends Box { 11 | 12 | private var _version:int; 13 | private var _flags:uint; 14 | 15 | private var _id:uint; 16 | private var _duration:uint; 17 | private var _volume:uint; 18 | private var _width:uint; 19 | private var _height:uint; 20 | 21 | public function TkhdBox() 22 | { 23 | super(Mp4.BOX_TYPE_TKHD); 24 | } 25 | 26 | override protected function init():void 27 | { 28 | data.position = 8; 29 | _version = data.readUnsignedByte(); 30 | _flags = ( (data.readUnsignedShort() << 8) | data.readUnsignedByte() ); 31 | 32 | var creationTime:Date = new Date(Date.UTC(1904, 0, 1)); //from 1904 33 | creationTime.secondsUTC = data.readUnsignedInt(); 34 | // trace('creation time: ' + SimpleDateFormatter.formatDate( creationTime, 'yyyy-MM-dd kk:mm:ss') ); 35 | 36 | var modificationTime = new Date(Date.UTC(1904, 0, 1)); //from 1904 37 | modificationTime.secondsUTC = data.readUnsignedInt(); 38 | // trace('modification time: ' + SimpleDateFormatter.formatDate( modificationTime, 'yyyy-MM-dd kk:mm:ss') ); 39 | 40 | _id = data.readUnsignedInt(); 41 | // trace('id: ' + data.readUnsignedInt()); 42 | // trace('reserved: ' + data.readUnsignedInt() ); 43 | data.readUnsignedInt(); 44 | 45 | _duration = data.readUnsignedInt(); 46 | // trace('duration: ' + _duration ); 47 | 48 | data.position += 12; 49 | 50 | // trace('layer: ' + data.readShort() ); 51 | // trace('group: ' + data.readShort() ); 52 | 53 | _volume = data.readShort() / Mp4.FIXED_POINT_8_8; 54 | // trace('volume: ' + data.readShort() / 256.0 ); 55 | // trace('reserved: ' + data.readShort() ); 56 | 57 | data.position += 38; 58 | 59 | _width = data.readInt() / Mp4.FIXED_POINT_16_16; 60 | _height = data.readInt() / Mp4.FIXED_POINT_16_16; 61 | 62 | // trace('width: ' + _width ); 63 | // trace('height: ' + _height ); 64 | 65 | } 66 | 67 | public function get id():uint 68 | { 69 | return _id; 70 | } 71 | 72 | public function get duration():uint 73 | { 74 | return _duration; 75 | } 76 | 77 | public function get volume():uint 78 | { 79 | return _volume; 80 | } 81 | 82 | public function get width():uint 83 | { 84 | return _width; 85 | } 86 | 87 | public function get height():uint 88 | { 89 | return _height; 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/cc/minos/codec/mp4/boxs/TrakBox.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/8 17:53 5 | */ 6 | package cc.minos.codec.mp4.boxs { 7 | 8 | import cc.minos.codec.mp4.Sample; 9 | import cc.minos.codec.mp4.Mp4; 10 | 11 | /** 12 | * container 13 | */ 14 | public class TrakBox extends Box { 15 | 16 | //mdia -> hdlr 17 | private var _hdlrBox:HdlrBox; 18 | private var _mdhdBox:MdhdBox; 19 | //mdia -> minf -> stbl 20 | private var _stblBox:StblBox; 21 | //tkhd box 22 | private var _tkhdBox:TkhdBox; 23 | private var _framerate:Number; 24 | 25 | public function TrakBox() 26 | { 27 | super(Mp4.BOX_TYPE_TRAK); 28 | } 29 | 30 | override protected function init():void 31 | { 32 | //type 33 | _hdlrBox = getBox(Mp4.BOX_TYPE_HDLR).shift() as HdlrBox; 34 | _mdhdBox = getBox(Mp4.BOX_TYPE_MDHD).shift() as MdhdBox; 35 | _tkhdBox = getBox(Mp4.BOX_TYPE_TKHD).shift() as TkhdBox; 36 | _stblBox = getBox(Mp4.BOX_TYPE_STBL).shift() as StblBox; 37 | 38 | _framerate = parseFloat(( _stblBox.samples.length / ( _mdhdBox.duration / _mdhdBox.timeScale )).toFixed(2)); 39 | 40 | for each(var sample:Sample in _stblBox.samples) 41 | { 42 | sample.timestamp = toMillisecond(sample.timestamp); 43 | } 44 | } 45 | 46 | public function get trakType():uint 47 | { 48 | return _hdlrBox.hdType; 49 | } 50 | 51 | public function get id():uint 52 | { 53 | return _tkhdBox.id; 54 | } 55 | 56 | public function get duration():uint 57 | { 58 | return _tkhdBox.duration; 59 | } 60 | 61 | public function get volume():uint 62 | { 63 | return _tkhdBox.volume; 64 | } 65 | 66 | public function get width():uint 67 | { 68 | return _tkhdBox.width; 69 | } 70 | 71 | public function get height():uint 72 | { 73 | return _tkhdBox.height; 74 | } 75 | 76 | public function get samples():Vector. 77 | { 78 | return _stblBox.samples; 79 | } 80 | 81 | private function toMillisecond(ts:Number):Number 82 | { 83 | return parseFloat(((ts / _mdhdBox.timeScale) * 1000).toFixed(2)); 84 | } 85 | 86 | public function get framerate():Number 87 | { 88 | return _framerate; 89 | } 90 | 91 | public function get stsdBox():StsdBox 92 | { 93 | return _stblBox.stsdBox; 94 | } 95 | 96 | public function get keyframes():Array 97 | { 98 | if (_stblBox.stssBox != null) 99 | return _stblBox.stssBox.keyframes; 100 | return []; 101 | } 102 | 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/cc/minos/codec/utils/Hex.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Author: SiuzukZan 4 | * Date: 14/12/10 16:17 5 | */ 6 | package cc.minos.codec.utils { 7 | 8 | import flash.utils.ByteArray; 9 | 10 | public class Hex { 11 | 12 | 13 | /** 14 | * sunday算法匹配 15 | * @param target : 目标数据 16 | * @param patten : 匹配数据 17 | * @param start : 起始点 18 | * @return int: 成功匹配返回在目标数据的位置,没找到则返回-1 19 | */ 20 | public static function sundaySearch(target:ByteArray, patten:ByteArray, start:uint = 0):int 21 | { 22 | var i:uint = start, j:uint = 0; 23 | var tl:uint = target.length, pl:uint = patten.length; 24 | var pe:uint 25 | 26 | if (tl < pl) 27 | return -1; 28 | //0xFF 29 | var steps:Array = [ 30 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 31 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 32 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 34 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 35 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 36 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 37 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 38 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 39 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 40 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 41 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 43 | ]; 44 | for (var a:int = 0; a < pl; a++) 45 | { 46 | steps[patten[a]] = a; 47 | } 48 | while (i < tl && j < pl) 49 | { 50 | if (target[i] == patten[j]) 51 | { 52 | i++; 53 | j++; 54 | continue; 55 | } 56 | pe = i + pl; 57 | if (pe >= tl) 58 | { 59 | return -1; 60 | } 61 | i += (pl - steps[target[pe]]); 62 | j = 0; 63 | } 64 | return i - pl; 65 | } 66 | 67 | /** 68 | * 69 | * @param array 70 | * @param term 71 | * @return 72 | */ 73 | public static function byteArrayIndexOf(array:ByteArray, term:ByteArray):int 74 | { 75 | var origPosBa:int = array.position; 76 | var origPosSearchTerm:int = term.position; 77 | 78 | var end:int = array.length - term.length 79 | for (var i:int = 0; i <= end; i++) 80 | { 81 | if (byteArrayEqualsAt(array, term, i)) 82 | { 83 | array.position = origPosBa; 84 | term.position = origPosSearchTerm; 85 | return i; 86 | } 87 | } 88 | 89 | array.position = origPosBa; 90 | term.position = origPosSearchTerm; 91 | return -1; 92 | } 93 | 94 | /** 95 | * 96 | * @param array 97 | * @param term 98 | * @param pos 99 | * @return 100 | */ 101 | public static function byteArrayEqualsAt(array:ByteArray, term:ByteArray, pos:int):Boolean 102 | { 103 | if (pos + term.length > array.length) return false; 104 | 105 | array.position = pos; 106 | term.position = 0; 107 | 108 | for (var i:int = 0; i < term.length; i++) 109 | { 110 | var valBa:int = array.readByte(); 111 | var valSearch:int = term.readByte(); 112 | if (valBa != valSearch) return false; 113 | } 114 | 115 | return true; 116 | } 117 | 118 | /** 119 | * 轉utf-8 120 | * @param hex 121 | * @return 122 | */ 123 | public static function toUTF8String(hex:String):String 124 | { 125 | var a:ByteArray = toArray(hex); 126 | return a.readUTFBytes(a.length); 127 | } 128 | 129 | /** 130 | * 字符串(十六進制)轉二進制(ByteArray) 131 | * @param hex 132 | * @return 133 | */ 134 | public static function toArray(hex:String):ByteArray 135 | { 136 | hex = hex.replace(/\s|:/gm, ''); 137 | var a:ByteArray = new ByteArray; 138 | if ((hex.length & 1) == 1) hex = "0" + hex; 139 | for (var i:uint = 0; i < hex.length; i += 2) 140 | { 141 | a[i / 2] = parseInt(hex.substr(i, 2), 16); 142 | } 143 | return a; 144 | } 145 | 146 | /** 147 | * 二進制(ByteArray)轉字符串(十六進制) 148 | * @param array 149 | * @param colons 150 | * @return 151 | */ 152 | public static function fromArray(array:ByteArray, colons:Boolean = false):String 153 | { 154 | var s:String = ""; 155 | var len:uint = array.length; 156 | for (var i:uint = 0; i < len; i++) 157 | { 158 | s += ("0" + array[i].toString(16)).substr(-2, 2); 159 | if (colons) 160 | { 161 | if (i < len - 1) s += ":"; 162 | } 163 | } 164 | return s; 165 | } 166 | 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/cc/minos/codec/utils/Log.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | * Created by SiuzukZan on 04/15/2015 09:03 4 | */ 5 | package cc.minos.codec.utils { 6 | 7 | import flash.external.ExternalInterface; 8 | 9 | public final class Log { 10 | 11 | private static const INFO:String = "[INFO]"; 12 | private static const DEBUG:String = "[DEBUG]"; 13 | private static const WARN:String = "[WARN]"; 14 | private static const ERROR:String = "[ERROR]"; 15 | 16 | public static function info(...rest):void 17 | { 18 | output.apply(null, new Array(INFO).concat(rest)); 19 | } 20 | 21 | public static function debug(...rest):void 22 | { 23 | output.apply(null, new Array(DEBUG).concat(rest)); 24 | } 25 | 26 | public static function warn(...rest):void 27 | { 28 | output.apply(null, new Array(WARN).concat(rest)); 29 | } 30 | 31 | public static function error(...rest):void 32 | { 33 | output.apply(null, new Array(ERROR).concat(rest)); 34 | } 35 | 36 | private static function output(...rest):void 37 | { 38 | // if (ExternalInterface.available) 39 | // ExternalInterface.call.apply(null, new Array('console.log').concat(rest)); 40 | // else 41 | trace.apply(null, rest); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/cc/minos/codec/utils/SimpleDateFormatter.as: -------------------------------------------------------------------------------- 1 | package cc.minos.codec.utils { 2 | 3 | public class SimpleDateFormatter { 4 | /** 5 | * SimpleDateFormatter.as 6 | * 7 | * An Actionscript 2 implementation of the Java SimpleDateFormat class. 8 | * This code was directly adapted from Matt Kruse's Javascript class 9 | * implementation, and is used/distributed with Matt's permission. 10 | * 11 | * Please report all bugs to Daniel Wabyick (dwabyick@fluid.com). 12 | * 13 | * @author Daniel Wabyick (Actionscript 2 port) 14 | * http://www.fluid.com 15 | * @author Matt Kruse ( Javascript implementation) 16 | * http://www.JavascriptToolbox.com 17 | * 18 | * The following notice is maintained from Matt Kruse's 19 | * original Javascript code. 20 | * 21 | * NOTICE: You may use this code for any purpose, commercial or 22 | * private, without any further permission from the author. You may 23 | * remove this notice from your final code if you wish, however it is 24 | * appreciated by the author if at least my web site address is kept. 25 | * 26 | 27 | * HISTORY 28 | * ------------------------------------------------------------------ 29 | * Oct 05, 2005 Wrapped into a static AS2 class - DWABYICK/FLUID 30 | * May 17, 2003: Fixed bug in parseDate() for dates <1970 31 | * March 11, 2003: Added parseDate() function 32 | * March 11, 2003: Added "NNN" formatting option. Doesn't match up 33 | * perfectly with SimpleDateFormat formats, but 34 | * backwards-compatability was required. 35 | * 36 | * USAGE 37 | * ------------------------------------------------------------------ 38 | * These functions use the same 'format' strings as the 39 | * java.text.SimpleDateFormat class, with minor exceptions. 40 | * The format string consists of the following abbreviations: 41 | * 42 | * Field | Full Form | Short Form 43 | * -------------+--------------------+----------------------- 44 | * Year | yyyy (4 digits) | yy (2 digits), y (2 or 4 digits) 45 | * Month | MMM (name or abbr.)| MM (2 digits), M (1 or 2 digits) 46 | * | NNN (abbr.) | 47 | * Day of Month | dd (2 digits) | d (1 or 2 digits) 48 | * Day of Week | EE (name) | E (abbr) 49 | * Hour (1-12) | hh (2 digits) | h (1 or 2 digits) 50 | * Hour (0-23) | HH (2 digits) | H (1 or 2 digits) 51 | * Hour (0-11) | KK (2 digits) | K (1 or 2 digits) 52 | * Hour (1-24) | kk (2 digits) | k (1 or 2 digits) 53 | * Minute | mm (2 digits) | m (1 or 2 digits) 54 | * Second | ss (2 digits) | s (1 or 2 digits) 55 | * AM/PM | a | 56 | * 57 | * NOTE THE DIFFERENCE BETWEEN MM and mm! Month=MM, not mm! 58 | * Examples: 59 | * "MMM d, y" matches: January 01, 2000 60 | * Dec 1, 1900 61 | * Nov 20, 00 62 | * "M/d/yy" matches: 01/20/00 63 | * 9/2/00 64 | * "MMM dd, yyyy hh:mm:ssa" matches: "January 01, 2000 12:30:45AM" 65 | */ 66 | 67 | public static var MONTH_NAMES:Array = new Array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'); 68 | public static var DAY_NAMES:Array = new Array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'); 69 | 70 | public static function LZ(x:Number):String 71 | { 72 | var res:String = x.toString(); 73 | if (x >= 0 && x <= 9) 74 | res = "0" + res; 75 | return res; 76 | } 77 | 78 | /** 79 | * Convert a date object into a string using the given format. 80 | * @param date The date value to convert. 81 | * @param format The format of the date object. (e.g. "yyyy-MM-dd") 82 | * @return The string value of the date. 83 | */ 84 | public static function formatDate(date:Date, format:String):String 85 | { 86 | format = format + ""; 87 | var result:String = ""; 88 | var i_format:int = 0; 89 | var c:String = ""; 90 | var token:String = ""; 91 | var y:Number = date.getFullYear(); 92 | var M:Number = date.getMonth() + 1; 93 | var d:Number = date.getDate(); 94 | var E:Number = date.getDay(); 95 | var H:Number = date.getHours(); 96 | var m:Number = date.getMinutes(); 97 | var s:Number = date.getSeconds(); 98 | // var yyyy,yy,MMM,MM,dd,hh,h,mm,ss,ampm,HH,H,KK,K,kk,k; 99 | // Convert real date parts into formatted versions 100 | var value:Object = new Object(); 101 | if (String(y).length < 4) 102 | { 103 | y = ( y - 0 + 1900 ); 104 | } 105 | value["y"] = "" + y; 106 | value["yyyy"] = y; 107 | value["yy"] = String(y).substring(2, 4); 108 | value["M"] = M; 109 | value["MM"] = LZ(M); 110 | value["MMM"] = MONTH_NAMES[M - 1]; 111 | value["NNN"] = MONTH_NAMES[M + 11]; 112 | value["d"] = d; 113 | value["dd"] = LZ(d); 114 | value["E"] = DAY_NAMES[E + 7]; 115 | value["EE"] = DAY_NAMES[E]; 116 | value["H"] = H; 117 | value["HH"] = LZ(H); 118 | if (H == 0) 119 | { 120 | value["h"] = 12; 121 | } 122 | else if (H > 12) 123 | { 124 | value["h"] = H - 12; 125 | } 126 | else 127 | { 128 | value["h"] = H; 129 | } 130 | value["hh"] = LZ(value["h"]); 131 | if (H > 11) 132 | { 133 | value["K"] = H - 12; 134 | } 135 | else 136 | { 137 | value["K"] = H; 138 | } 139 | value["k"] = H + 1; 140 | value["KK"] = LZ(value["K"]); 141 | value["kk"] = LZ(value["k"]); 142 | if (H > 11) 143 | { 144 | value["a"] = "PM"; 145 | } 146 | else 147 | { 148 | value["a"] = "AM"; 149 | } 150 | value["m"] = m; 151 | value["mm"] = LZ(m); 152 | value["s"] = s; 153 | value["ss"] = LZ(s); 154 | while (i_format < format.length) 155 | { 156 | c = format.charAt(i_format); 157 | token = ""; 158 | while (( format.charAt(i_format) == c ) && ( i_format < format.length )) 159 | { 160 | token += format.charAt(i_format++); 161 | } 162 | if (value[token] != null) 163 | { 164 | result = result + value[token]; 165 | } 166 | else 167 | { 168 | result = result + token; 169 | } 170 | } 171 | return result; 172 | } 173 | 174 | /** 175 | * Determine if the a given string value is a date in the given format. 176 | * @param A string value representing a date. 177 | * @param format The format of this date. (e.g. "yyyy-MM-dd") 178 | * @return true if date string matches format of format string and 179 | * is a valid date. Else returns false. 180 | */ 181 | public static function isDate(val:String, format:String):Boolean 182 | { 183 | var date:Date = getDateFromFormat(val, format); 184 | if (date == null) 185 | { 186 | return false; 187 | } 188 | return true; 189 | } 190 | 191 | /** 192 | * Compare two date strings to see which is greater. 193 | * @param date1 A string representing the first date value. 194 | * @param dateformat1 The format of the first date. (e.g. "yyyy-MM-dd") 195 | * @param date2 A string representing the second date value. 196 | * @param dateformat2 The format of the second date.(e.g. "yyyy-MM-dd") 197 | * @return 1 if date1 >date2; 0 if date2 > date; -1 if either date is an invalid format. 198 | */ 199 | public static function compareDates(date1:String, dateformat1:String, date2:String, dateformat2:String):Number 200 | { 201 | var d1:Date = getDateFromFormat(date1, dateformat1); 202 | var d2:Date = getDateFromFormat(date2, dateformat2); 203 | if (d1 == null || d2 == null) 204 | { 205 | return -1; 206 | } 207 | else if (d1 > d2) 208 | { 209 | return 1; 210 | } 211 | return 0; 212 | } 213 | 214 | /** 215 | * Get a date using the given format. If it does not match, it returns 0. 216 | * @param val The string value to convert to a date 217 | * @param format The format of the date object. 218 | * @return The date in the given format, or null if the value doesn't match the given format. 219 | */ 220 | public static function getDateFromFormat(val:String, format:String):Date 221 | { 222 | val = val + ""; 223 | format = format + ""; 224 | var i_val:int = 0; 225 | var i_format:int = 0; 226 | var c:String = ""; 227 | var token:String = ""; 228 | var token2:String = ""; 229 | var x:int; 230 | var y:int; 231 | var now:Date = new Date(); 232 | var year:Number = now.getFullYear(); 233 | var month:Number = now.getMonth() + 1; 234 | var date:int = 1; 235 | var hh:Number = now.getHours(); 236 | var mm:Number = now.getMinutes(); 237 | var ss:Number = now.getSeconds(); 238 | var ampm:String = ""; 239 | var i:int = 0; 240 | 241 | while (i_format < format.length) 242 | { 243 | // Get next token from format string 244 | c = format.charAt(i_format); 245 | token = ""; 246 | while (( format.charAt(i_format) == c ) && ( i_format < format.length )) 247 | { 248 | token += format.charAt(i_format++); 249 | } 250 | // Extract contents of value based on format token 251 | if (token == "yyyy" || token == "yy" || token == "y") 252 | { 253 | if (token == "yyyy") 254 | { 255 | x = 4; 256 | y = 4; 257 | } 258 | if (token == "yy") 259 | { 260 | x = 2; 261 | y = 2; 262 | } 263 | if (token == "y") 264 | { 265 | x = 2; 266 | y = 4; 267 | } 268 | year = _getInt(val, i_val, x, y); 269 | i_val += String(year).length; 270 | if (String(year).length == 2) 271 | { 272 | if (year > 70) 273 | { 274 | year = 1900 + ( year - 0 ); 275 | } 276 | else 277 | { 278 | year = 2000 + ( year - 0 ); 279 | } 280 | } 281 | } 282 | else if (token == "MMM" || token == "NNN") 283 | { 284 | month = 0; 285 | for (i = 0; i < MONTH_NAMES.length; i++) 286 | { 287 | var month_name:String = MONTH_NAMES[i]; 288 | if (val.substring(i_val, i_val + month_name.length).toLowerCase() == month_name.toLowerCase()) 289 | { 290 | if (token == "MMM" || ( token == "NNN" && i > 11 )) 291 | { 292 | month = i + 1; 293 | if (month > 12) 294 | { 295 | month -= 12; 296 | } 297 | i_val += month_name.length; 298 | break; 299 | } 300 | } 301 | } 302 | if (( month < 1 ) || ( month > 12 )) 303 | { 304 | return null; 305 | } 306 | } 307 | else if (token == "EE" || token == "E") 308 | { 309 | for (i = 0; i < DAY_NAMES.length; i++) 310 | { 311 | var day_name:String = DAY_NAMES[i]; 312 | if (val.substring(i_val, i_val + day_name.length).toLowerCase() == day_name.toLowerCase()) 313 | { 314 | i_val += day_name.length; 315 | break; 316 | } 317 | } 318 | } 319 | else if (token == "MM" || token == "M") 320 | { 321 | month = _getInt(val, i_val, token.length, 2); 322 | if (( month < 1 ) || ( month > 12 )) 323 | { 324 | return null; 325 | } 326 | i_val += token.length; 327 | } 328 | else if (token == "dd" || token == "d") 329 | { 330 | date = _getInt(val, i_val, token.length, 2); 331 | if (( date < 1 ) || ( date > 31 )) 332 | { 333 | return null; 334 | } 335 | i_val += token.length; 336 | } 337 | else if (token == "hh" || token == "h") 338 | { 339 | hh = _getInt(val, i_val, token.length, 2); 340 | if (( hh < 1 ) || ( hh > 12 )) 341 | { 342 | return null; 343 | } 344 | i_val += token.length; 345 | } 346 | else if (token == "HH" || token == "H") 347 | { 348 | hh = _getInt(val, i_val, token.length, 2); 349 | if (( hh < 0 ) || ( hh > 23 )) 350 | { 351 | return null; 352 | } 353 | i_val += token.length; 354 | } 355 | else if (token == "KK" || token == "K") 356 | { 357 | hh = _getInt(val, i_val, token.length, 2); 358 | if (( hh < 0 ) || ( hh > 11 )) 359 | { 360 | return null; 361 | } 362 | i_val += token.length; 363 | } 364 | else if (token == "kk" || token == "k") 365 | { 366 | hh = _getInt(val, i_val, token.length, 2); 367 | if (( hh < 1 ) || ( hh > 24 )) 368 | { 369 | return null; 370 | } 371 | i_val += token.length; 372 | hh--; 373 | } 374 | else if (token == "mm" || token == "m") 375 | { 376 | mm = _getInt(val, i_val, token.length, 2); 377 | if (( mm < 0 ) || ( mm > 59 )) 378 | { 379 | return null; 380 | } 381 | i_val += token.length; 382 | } 383 | else if (token == "ss" || token == "s") 384 | { 385 | ss = _getInt(val, i_val, token.length, 2); 386 | if (( ss < 0 ) || ( ss > 59 )) 387 | { 388 | return null; 389 | } 390 | i_val += token.length; 391 | } 392 | else if (token == "a") 393 | { 394 | if (val.substring(i_val, i_val + 2).toLowerCase() == "am") 395 | { 396 | ampm = "AM"; 397 | } 398 | else if (val.substring(i_val, i_val + 2).toLowerCase() == "pm") 399 | { 400 | ampm = "PM"; 401 | } 402 | else 403 | { 404 | return null; 405 | } 406 | i_val += 2; 407 | } 408 | else 409 | { 410 | if (val.substring(i_val, i_val + token.length) != token) 411 | { 412 | return null; 413 | } 414 | else 415 | { 416 | i_val += token.length; 417 | } 418 | } 419 | } 420 | // If there are any trailing characters left in the value, it doesn't match 421 | if (i_val != val.length) 422 | { 423 | return null; 424 | } 425 | // Is date valid for month? 426 | if (month == 2) 427 | { 428 | // Check for leap year 429 | if ((( year % 4 == 0 ) && ( year % 100 != 0 ) ) || ( year % 400 == 0 )) 430 | { // leap year 431 | if (date > 29) 432 | { 433 | return null; 434 | } 435 | } 436 | else 437 | { 438 | if (date > 28) 439 | { 440 | return null; 441 | } 442 | } 443 | } 444 | if (( month == 4 ) || ( month == 6 ) || ( month == 9 ) || ( month == 11 )) 445 | { 446 | if (date > 30) 447 | { 448 | return null; 449 | } 450 | } 451 | // Correct hours value 452 | if (hh < 12 && ampm == "PM") 453 | { 454 | hh = hh - 0 + 12; 455 | } 456 | else if (hh > 11 && ampm == "AM") 457 | { 458 | hh -= 12; 459 | } 460 | var newdate:Date = new Date(year, month - 1, date, hh, mm, ss); 461 | return newdate; 462 | } 463 | 464 | public static function fromNow(val:String, format:String):String 465 | { 466 | 467 | var d1:Date = getDateFromFormat(val, format); 468 | var d2:Date = new Date(); 469 | 470 | var str:String = ''; 471 | if (d1 > d2) str = 'later'; 472 | else str = 'ago'; 473 | 474 | var year:Number = Math.abs(d2.fullYear - d1.fullYear); 475 | var month:Number = Math.abs(d2.month - d1.month); 476 | var day:Number = Math.abs(d2.date - d1.date); 477 | 478 | if (year == 0 && month == 0) 479 | { 480 | if (day == 0) 481 | { 482 | str = 'Today'; 483 | } 484 | else if (day == 1) 485 | { 486 | if (d1 > d2) 487 | str = "Tomorrow"; 488 | else 489 | str = "Yesterday"; 490 | } 491 | } 492 | else 493 | { 494 | if (year > 0) 495 | { 496 | if (year > 1) 497 | str = year + ' years ' + str; 498 | else 499 | str = year + ' year ' + str; 500 | } 501 | else if (month > 0) 502 | { 503 | if (month > 1) 504 | str = month + ' months ' + str; 505 | else 506 | str = month + ' month ' + str; 507 | } 508 | else if (day > 0) 509 | { 510 | if (day > 1) 511 | str = day + ' days ' + str; 512 | else 513 | str = day + ' day ' + str; 514 | } 515 | } 516 | trace(str) 517 | return str; 518 | } 519 | 520 | /** 521 | * @return True if the value is an integer; false otherwise. 522 | */ 523 | private static function _isInteger(val:String):Boolean 524 | { 525 | var digits:String = "1234567890"; 526 | for (var i:int = 0; i < val.length; i++) 527 | { 528 | if (digits.indexOf(val.charAt(i)) == -1) 529 | { 530 | return false; 531 | } 532 | } 533 | return true; 534 | } 535 | 536 | private static function _getInt(str:String, i:int, minlength:int, maxlength:int):Number 537 | { 538 | for (var x:int = maxlength; x >= minlength; x--) 539 | { 540 | var token:String = str.substring(i, i + x); 541 | if (token.length < minlength) 542 | { 543 | return NaN; 544 | } 545 | if (_isInteger(token)) 546 | { 547 | return Number(token); 548 | } 549 | } 550 | return NaN; 551 | } 552 | } 553 | } 554 | -------------------------------------------------------------------------------- /src/com/hurlant/math/BigInteger.as: -------------------------------------------------------------------------------- 1 | /** 2 | * BigInteger 3 | * 4 | * An ActionScript 3 implementation of BigInteger (light version) 5 | * Copyright (c) 2007 Henri Torgemane 6 | * 7 | * Derived from: 8 | * The jsbn library, Copyright (c) 2003-2005 Tom Wu 9 | * 10 | * See LICENSE.txt for full license information. 11 | */ 12 | package com.hurlant.math 13 | { 14 | 15 | import com.hurlant.util.Hex; 16 | 17 | import flash.utils.ByteArray; 18 | use namespace bi_internal; 19 | 20 | public class BigInteger 21 | { 22 | public static const DB:int = 30; // number of significant bits per chunk 23 | public static const DV:int = (1< 0) { 89 | if (p>p)>0) { 90 | m = true; 91 | r = d.toString(36); 92 | } 93 | while (i >= 0) { 94 | if (p>(p+=DB-k); 97 | } else { 98 | d = (a[i]>>(p-=k))&km; 99 | if (p<=0) { 100 | p += DB; 101 | --i; 102 | } 103 | } 104 | if (d>0) { 105 | m = true; 106 | } 107 | if (m) { 108 | r += d.toString(36); 109 | } 110 | } 111 | } 112 | return m?r:"0"; 113 | } 114 | public function toArray(array:ByteArray):uint { 115 | const k:int = 8; 116 | const km:int = (1<<8)-1; 117 | var d:int = 0; 118 | var i:int = t; 119 | var p:int = DB-(i*DB)%k; 120 | var m:Boolean = false; 121 | var c:int = 0; 122 | if (i-- > 0) { 123 | if (p>p)>0) { 124 | m = true; 125 | array.writeByte(d); 126 | c++; 127 | } 128 | while (i >= 0) { 129 | if (p>(p+=DB-k); 132 | } else { 133 | d = (a[i]>>(p-=k))&km; 134 | if (p<=0) { 135 | p += DB; 136 | --i; 137 | } 138 | } 139 | if (d>0) { 140 | m = true; 141 | } 142 | if (m) { 143 | array.writeByte(d); 144 | c++; 145 | } 146 | } 147 | } 148 | return c; 149 | } 150 | /** 151 | * best-effort attempt to fit into a Number. 152 | * precision can be lost if it just can't fit. 153 | */ 154 | public function valueOf():Number { 155 | if (s==-1) { 156 | return -negate().valueOf(); 157 | } 158 | var coef:Number = 1; 159 | var value:Number = 0; 160 | for (var i:uint=0;i v, - if this < v, 0 if equal 182 | */ 183 | public function compareTo(v:BigInteger):int { 184 | var r:int = s - v.s; 185 | if (r!=0) { 186 | return r; 187 | } 188 | var i:int = t; 189 | r = i-v.t; 190 | if (r!=0) { 191 | return r; 192 | } 193 | while (--i >=0) { 194 | r=a[i]-v.a[i]; 195 | if (r != 0) return r; 196 | } 197 | return 0; 198 | } 199 | /** 200 | * returns bit length of the integer x 201 | */ 202 | bi_internal function nbits(x:int):int { 203 | var r:int = 1; 204 | var t:int; 205 | if ((t=x>>>16) != 0) { x = t; r += 16; } 206 | if ((t=x>>8) != 0) { x = t; r += 8; } 207 | if ((t=x>>4) != 0) { x = t; r += 4; } 208 | if ((t=x>>2) != 0) { x = t; r += 2; } 209 | if ((t=x>>1) != 0) { x = t; r += 1; } 210 | return r; 211 | } 212 | /** 213 | * returns the number of bits in this 214 | */ 215 | public function bitLength():int { 216 | if (t<=0) return 0; 217 | return DB*(t-1)+nbits(a[t-1]^(s&DM)); 218 | } 219 | /** 220 | * 221 | * @param v 222 | * @return this % v 223 | * 224 | */ 225 | public function mod(v:BigInteger):BigInteger { 226 | var r:BigInteger = nbi(); 227 | abs().divRemTo(v,null,r); 228 | if (s<0 && r.compareTo(ZERO)>0) { 229 | v.subTo(r,r); 230 | } 231 | return r; 232 | } 233 | /** 234 | * this^e % m, 0 <= e < 2^32 235 | */ 236 | /*public function modPowInt(e:int, m:BigInteger):BigInteger { 237 | var z:IReduction; 238 | if (e<256 || m.isEven()) { 239 | z = new ClassicReduction(m); 240 | } else { 241 | z = new MontgomeryReduction(m); 242 | } 243 | return exp(e, z); 244 | }*/ 245 | 246 | /** 247 | * copy this to r 248 | */ 249 | bi_internal function copyTo(r:BigInteger):void { 250 | for (var i:int = t-1; i>=0; --i) { 251 | r.a[i] = a[i]; 252 | } 253 | r.t = t; 254 | r.s = s; 255 | } 256 | /** 257 | * set from integer value "value", -DV <= value < DV 258 | */ 259 | bi_internal function fromInt(value:int):void { 260 | t = 1; 261 | s = (value<0)?-1:0; 262 | if (value>0) { 263 | a[0] = value; 264 | } else if (value<-1) { 265 | a[0] = value+DV; 266 | } else { 267 | t = 0; 268 | } 269 | } 270 | /** 271 | * set from ByteArray and length, 272 | * starting a current position 273 | * If length goes beyond the array, pad with zeroes. 274 | */ 275 | bi_internal function fromArray(value:ByteArray, length:int, unsigned:Boolean = false):void { 276 | var p:int = value.position; 277 | var i:int = p+length; 278 | var sh:int = 0; 279 | const k:int = 8; 280 | t = 0; 281 | s = 0; 282 | while (--i >= p) { 283 | var x:int = i DB) { 287 | a[t-1] |= (x&((1<<(DB-sh))-1))<>(DB-sh); 289 | } else { 290 | a[t-1] |= x<= DB) sh -= DB; 294 | } 295 | if (!unsigned && (value[0]&0x80)==0x80) { 296 | s = -1; 297 | if (sh > 0) { 298 | a[t-1] |= ((1<<(DB-sh))-1)<0 && a[t-1]==c) { 310 | --t; 311 | } 312 | } 313 | /** 314 | * r = this << n*DB 315 | */ 316 | bi_internal function dlShiftTo(n:int, r:BigInteger):void { 317 | var i:int; 318 | for (i=t-1; i>=0; --i) { 319 | r.a[i+n] = a[i]; 320 | } 321 | for (i=n-1; i>=0; --i) { 322 | r.a[i] = 0; 323 | } 324 | r.t = t+n; 325 | r.s = s; 326 | } 327 | /** 328 | * r = this >> n*DB 329 | */ 330 | bi_internal function drShiftTo(n:int, r:BigInteger):void { 331 | var i:int; 332 | for (i=n; i=0; --i) { 349 | r.a[i+ds+1] = (a[i]>>cbs)|c; 350 | c = (a[i]&bm)<=0; --i) { 353 | r.a[i] = 0; 354 | } 355 | r.a[ds] = c; 356 | r.t = t+ds+1; 357 | r.s = s; 358 | r.clamp(); 359 | } 360 | /** 361 | * r = this >> n 362 | */ 363 | bi_internal function rShiftTo(n:int, r:BigInteger):void { 364 | r.s = s; 365 | var ds:int = n/DB; 366 | if (ds >= t) { 367 | r.t = 0; 368 | return; 369 | } 370 | var bs:int = n%DB; 371 | var cbs:int = DB-bs; 372 | var bm:int = (1<>bs; 374 | var i:int; 375 | for (i=ds+1; i>bs; 378 | } 379 | if (bs>0) { 380 | r.a[t-ds-1] |= (s&bm)<>= DB; 396 | } 397 | if (v.t < t) { 398 | c -= v.s; 399 | while (i< t) { 400 | c+= a[i]; 401 | r.a[i++] = c&DM; 402 | c >>= DB; 403 | } 404 | c += s; 405 | } else { 406 | c += s; 407 | while (i < v.t) { 408 | c -= v.a[i]; 409 | r.a[i++] = c&DM; 410 | c >>= DB; 411 | } 412 | c -= v.s; 413 | } 414 | r.s = (c<0)?-1:0; 415 | if (c<-1) { 416 | r.a[i++] = DV+c; 417 | } else if (c>0) { 418 | r.a[i++] = c; 419 | } 420 | r.t = i; 421 | r.clamp(); 422 | } 423 | /** 424 | * am: Compute w_j += (x*this_i), propagates carries, 425 | * c is initial carry, returns final carry. 426 | * c < 3*dvalue, x < 2*dvalue, this_i < dvalue 427 | */ 428 | bi_internal function am(i:int,x:int,w:BigInteger,j:int,c:int,n:int):int { 429 | var xl:int = x&0x7fff; 430 | var xh:int = x>>15; 431 | while(--n >= 0) { 432 | var l:int = a[i]&0x7fff; 433 | var h:int = a[i++]>>15; 434 | var m:int = xh*l + h*xl; 435 | l = xl*l + ((m&0x7fff)<<15)+w.a[j]+(c&0x3fffffff); 436 | c = (l>>>30)+(m>>>15)+xh*h+(c>>>30); 437 | w.a[j++] = l&0x3fffffff; 438 | } 439 | return c; 440 | } 441 | /** 442 | * r = this * v, r != this,a (HAC 14.12) 443 | * "this" should be the larger one if appropriate 444 | */ 445 | bi_internal function multiplyTo(v:BigInteger, r:BigInteger):void { 446 | var x:BigInteger = abs(); 447 | var y:BigInteger = v.abs(); 448 | var i:int = x.t; 449 | r.t = i+y.t; 450 | while (--i >= 0) { 451 | r.a[i] = 0; 452 | } 453 | for (i=0; i=0) r.a[i] = 0; 469 | for (i=0; i= DV) { 472 | r.a[i+x.t] -= DV; 473 | r.a[i+x.t+1] = 1; 474 | } 475 | } 476 | if (r.t>0) { 477 | r.a[r.t-1] += x.am(i, x.a[i], r, 2*i, 0, 1); 478 | } 479 | r.s = 0; 480 | r.clamp(); 481 | } 482 | /** 483 | * divide this by m, quotient and remainder to q, r (HAC 14.20) 484 | * r != q, this != m. q or r may be null. 485 | */ 486 | bi_internal function divRemTo(m:BigInteger, q:BigInteger = null, r:BigInteger = null):void { 487 | var pm:BigInteger = m.abs(); 488 | if (pm.t <= 0) return; 489 | var pt:BigInteger = abs(); 490 | if (pt.t < pm.t) { 491 | if (q!=null) q.fromInt(0); 492 | if (r!=null) copyTo(r); 493 | return; 494 | } 495 | if (r==null) r = nbi(); 496 | var y:BigInteger = nbi(); 497 | var ts:int = s; 498 | var ms:int = m.s; 499 | var nsh:int = DB-nbits(pm.a[pm.t-1]); // normalize modulus 500 | if (nsh>0) { 501 | pm.lShiftTo(nsh, y); 502 | pt.lShiftTo(nsh, r); 503 | } else { 504 | pm.copyTo(y); 505 | pt.copyTo(r); 506 | } 507 | var ys:int = y.t; 508 | var y0:int = y.a[ys-1]; 509 | if (y0==0) return; 510 | var yt:Number = y0*(1<1)?y.a[ys-2]>>F2:0); 511 | var d1:Number = FV/yt; 512 | var d2:Number = (1<=0) { 519 | r.a[r.t++] = 1; 520 | r.subTo(t,r); 521 | } 522 | ONE.dlShiftTo(ys,t); 523 | t.subTo(y,y); // "negative" y so we can replace sub with am later. 524 | while(y.t= 0) { 526 | // Estimate quotient digit 527 | var qd:int = (r.a[--i]==y0)?DM:Number(r.a[i])*d1+(Number(r.a[i-1])+e)*d2; 528 | if ((r.a[i]+= y.am(0, qd, r, j, 0, ys))0) { 545 | r.rShiftTo(nsh, r); // Denormalize remainder 546 | } 547 | if (ts<0) { 548 | ZERO.subTo(r,r); 549 | } 550 | } 551 | /** 552 | * return "-1/this % 2^DB"; useful for Mont. reduction 553 | * justification: 554 | * xy == 1 (mod n) 555 | * xy = 1+km 556 | * xy(2-xy) = (1+km)(1-km) 557 | * x[y(2-xy)] = 1-k^2.m^2 558 | * x[y(2-xy)] == 1 (mod m^2) 559 | * if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 560 | * should reduce x and y(2-xy) by m^2 at each step to keep size bounded 561 | * [XXX unit test the living shit out of this.] 562 | */ 563 | bi_internal function invDigit():int { 564 | if (t<1) return 0; 565 | var x:int = a[0]; 566 | if ((x&1)==0) return 0; 567 | var y:int = x&3; // y == 1/x mod 2^2 568 | y = (y*(2-(x&0xf )*y)) &0xf; // y == 1/x mod 2^4 569 | y = (y*(2-(x&0xff)*y)) &0xff; // y == 1/x mod 2^8 570 | y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16 571 | // last step - calculate inverse mod DV directly; 572 | // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints 573 | // XXX 48 bit ints? Whaaaa? is there an implicit float conversion in here? 574 | y = (y*(2-x*y%DV))%DV; // y == 1/x mod 2^dbits 575 | // we really want the negative inverse, and -DV < y < DV 576 | return (y>0)?DV-y:-y; 577 | } 578 | /** 579 | * true iff this is even 580 | */ 581 | bi_internal function isEven():Boolean { 582 | return ((t>0)?(a[0]&1):s) == 0; 583 | } 584 | /** 585 | * this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) 586 | */ 587 | /*bi_internal function exp(e:int, z:IReduction):BigInteger { 588 | if (e > 0xffffffff || e < 1) return ONE; 589 | var r:BigInteger = nbi(); 590 | var r2:BigInteger = nbi(); 591 | var g:BigInteger = z.convert(this); 592 | var i:int = nbits(e)-1; 593 | g.copyTo(r); 594 | while(--i>=0) { 595 | z.sqrTo(r, r2); 596 | if ((e&(1<0) { 597 | z.mulTo(r2,g,r); 598 | } else { 599 | var t:BigInteger = r; 600 | r = r2; 601 | r2 = t; 602 | } 603 | 604 | } 605 | return z.revert(r); 606 | }*/ 607 | bi_internal function intAt(str:String, index:int):int { 608 | return parseInt(str.charAt(index), 36); 609 | } 610 | 611 | 612 | protected function nbi():* { 613 | return new BigInteger; 614 | } 615 | /** 616 | * return bigint initialized to value 617 | */ 618 | public static function nbv(value:int):BigInteger { 619 | var bn:BigInteger = new BigInteger; 620 | bn.fromInt(value); 621 | return bn; 622 | } 623 | 624 | 625 | // Functions above are sufficient for RSA encryption. 626 | // The stuff below is useful for decryption and key generation 627 | 628 | public static const lowprimes:Array = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509]; 629 | public static const lplim:int = (1<<26)/lowprimes[lowprimes.length-1]; 630 | 631 | 632 | public function clone():BigInteger { 633 | var r:BigInteger = new BigInteger; 634 | this.copyTo(r); 635 | return r; 636 | } 637 | 638 | /** 639 | * 640 | * @return value as integer 641 | * 642 | */ 643 | public function intValue():int { 644 | if (s<0) { 645 | if (t==1) { 646 | return a[0]-DV; 647 | } else if (t==0) { 648 | return -1; 649 | } 650 | } else if (t==1) { 651 | return a[0]; 652 | } else if (t==0) { 653 | return 0; 654 | } 655 | // assumes 16 < DB < 32 656 | return ((a[1]&((1<<(32-DB))-1))<>24; 666 | } 667 | 668 | /** 669 | * 670 | * @return value as short (assumes DB>=16) 671 | * 672 | */ 673 | public function shortValue():int { 674 | return (t==0)?s:(a[0]<<16)>>16; 675 | } 676 | 677 | /** 678 | * 679 | * @param r 680 | * @return x s.t. r^x < DV 681 | * 682 | */ 683 | protected function chunkSize(r:Number):int { 684 | return Math.floor(Math.LN2*DB/Math.log(r)); 685 | } 686 | 687 | /** 688 | * 689 | * @return 0 if this ==0, 1 if this >0 690 | * 691 | */ 692 | public function sigNum():int { 693 | if (s<0) { 694 | return -1; 695 | } else if (t<=0 || (t==1 && a[0]<=0)) { 696 | return 0; 697 | } else{ 698 | return 1; 699 | } 700 | } 701 | 702 | /** 703 | * 704 | * @param b: radix to use 705 | * @return a string representing the integer converted to the radix. 706 | * 707 | */ 708 | protected function toRadix(b:uint=10):String { 709 | if (sigNum()==0 || b<2 || b>32) return "0"; 710 | var cs:int = chunkSize(b); 711 | var a:Number = Math.pow(b, cs); 712 | var d:BigInteger = nbv(a); 713 | var y:BigInteger = nbi(); 714 | var z:BigInteger = nbi(); 715 | var r:String = ""; 716 | divRemTo(d, y, z); 717 | while (y.sigNum()>0) { 718 | r = (a+z.intValue()).toString(b).substr(1) + r; 719 | y.divRemTo(d,y,z); 720 | } 721 | return z.intValue().toString(b) + r; 722 | } 723 | 724 | /** 725 | * 726 | * @param s a string to convert from using radix. 727 | * @param b a radix 728 | * 729 | */ 730 | protected function fromRadix(s:String, b:int = 10):void { 731 | fromInt(0); 732 | var cs:int = chunkSize(b); 733 | var d:Number = Math.pow(b, cs); 734 | var mi:Boolean = false; 735 | var j:int = 0; 736 | var w:int = 0; 737 | for (var i:int=0;i= cs) { 747 | dMultiply(d); 748 | dAddOffset(w,0); 749 | j=0; 750 | w=0; 751 | } 752 | } 753 | if (j>0) { 754 | dMultiply(Math.pow(b,j)); 755 | dAddOffset(w,0); 756 | } 757 | if (mi) { 758 | BigInteger.ZERO.subTo(this, this); 759 | } 760 | } 761 | 762 | // XXX function fromNumber not written yet. 763 | 764 | /** 765 | * 766 | * @return a byte array. 767 | * 768 | */ 769 | public function toByteArray():ByteArray { 770 | var i:int = t; 771 | var r:ByteArray = new ByteArray; 772 | r[0] = s; 773 | var p:int = DB-(i*DB)%8; 774 | var d:int; 775 | var k:int=0; 776 | if (i-- > 0) { 777 | if (p>p)!=(s&DM)>>p) { 778 | r[k++] = d|(s<<(DB-p)); 779 | } 780 | while (i>=0) { 781 | if(p<8) { 782 | d = (a[i]&((1<>(p+=DB-8); 784 | } else { 785 | d = (a[i]>>(p-=8))&0xff; 786 | if (p<=0) { 787 | p += DB; 788 | --i; 789 | } 790 | } 791 | if ((d&0x80)!=0) d|=-256; 792 | if (k==0 && (s&0x80)!=(d&0x80)) ++k; 793 | if (k>0 || d!=s) r[k++] = d; 794 | } 795 | } 796 | return r; 797 | } 798 | 799 | public function equals(a:BigInteger):Boolean { 800 | return compareTo(a)==0; 801 | } 802 | public function min(a:BigInteger):BigInteger { 803 | return (compareTo(a)<0)?this:a; 804 | } 805 | public function max(a:BigInteger):BigInteger { 806 | return (compareTo(a)>0)?this:a; 807 | } 808 | 809 | /** 810 | * 811 | * @param a a BigInteger to perform the operation with 812 | * @param op a Function implementing the operation 813 | * @param r a BigInteger to store the result of the operation 814 | * 815 | */ 816 | protected function bitwiseTo(a:BigInteger, op:Function, r:BigInteger):void { 817 | var i:int; 818 | var f:int; 819 | var m:int = Math.min(a.t, t); 820 | for (i=0; i>= 16; r += 16; } 907 | if ((x&0xff) == 0) { x>>= 8; r += 8; } 908 | if ((x&0xf) == 0) { x>>= 4; r += 4; } 909 | if ((x&0x3) == 0) { x>>= 2; r += 2; } 910 | if ((x&0x1) == 0) ++r; 911 | return r; 912 | } 913 | 914 | /** 915 | * 916 | * @return index of lowest 1-bit (or -1 if none) 917 | * 918 | */ 919 | public function getLowestSetBit():int { 920 | for (var i:int=0;i=t) { 962 | return s!=0; 963 | } 964 | return ((a[j]&(1<<(n%DB)))!=0); 965 | } 966 | 967 | /** 968 | * 969 | * @param n 970 | * @param op 971 | * @return this op (1<>=DB; 1018 | } 1019 | if (a.t < t) { 1020 | c += a.s; 1021 | while (i>= DB; 1025 | } 1026 | c += s; 1027 | } else { 1028 | c += s; 1029 | while (i>= DB; 1033 | } 1034 | c += a.s; 1035 | } 1036 | r.s = (c<0)?-1:0; 1037 | if (c>0) { 1038 | r.a[i++] = c; 1039 | } else if (c<-1) { 1040 | r.a[i++] = DV+c; 1041 | } 1042 | r.t = i; 1043 | r.clamp(); 1044 | } 1045 | 1046 | /** 1047 | * 1048 | * @param a 1049 | * @return this + a 1050 | * 1051 | */ 1052 | public function add(a:BigInteger):BigInteger { 1053 | var r:BigInteger = new BigInteger; 1054 | addTo(a,r); 1055 | return r; 1056 | } 1057 | 1058 | /** 1059 | * 1060 | * @param a 1061 | * @return this - a 1062 | * 1063 | */ 1064 | public function subtract(a:BigInteger):BigInteger { 1065 | var r:BigInteger = new BigInteger; 1066 | subTo(a,r); 1067 | return r; 1068 | } 1069 | 1070 | /** 1071 | * 1072 | * @param a 1073 | * @return this * a 1074 | * 1075 | */ 1076 | public function multiply(a:BigInteger):BigInteger { 1077 | var r:BigInteger = new BigInteger; 1078 | multiplyTo(a,r); 1079 | return r; 1080 | } 1081 | 1082 | /** 1083 | * 1084 | * @param a 1085 | * @return this / a 1086 | * 1087 | */ 1088 | public function divide(a:BigInteger):BigInteger { 1089 | var r:BigInteger = new BigInteger; 1090 | divRemTo(a, r, null); 1091 | return r; 1092 | } 1093 | 1094 | public function remainder(a:BigInteger):BigInteger { 1095 | var r:BigInteger = new BigInteger; 1096 | divRemTo(a, null, r); 1097 | return r; 1098 | } 1099 | 1100 | /** 1101 | * 1102 | * @param a 1103 | * @return [this/a, this%a] 1104 | * 1105 | */ 1106 | public function divideAndRemainder(a:BigInteger):Array { 1107 | var q:BigInteger = new BigInteger; 1108 | var r:BigInteger = new BigInteger; 1109 | divRemTo(a, q, r); 1110 | return [q,r]; 1111 | } 1112 | 1113 | /** 1114 | * 1115 | * this *= n, this >=0, 1 < n < DV 1116 | * 1117 | * @param n 1118 | * 1119 | */ 1120 | bi_internal function dMultiply(n:int):void { 1121 | a[t] = am(0, n-1, this, 0, 0, t); 1122 | ++t; 1123 | clamp(); 1124 | } 1125 | 1126 | /** 1127 | * 1128 | * this += n << w words, this >= 0 1129 | * 1130 | * @param n 1131 | * @param w 1132 | * 1133 | */ 1134 | bi_internal function dAddOffset(n:int, w:int):void { 1135 | while (t<=w) { 1136 | a[t++] = 0; 1137 | } 1138 | a[w] += n; 1139 | while (a[w] >= DV) { 1140 | a[w] -= DV; 1141 | if (++w >= t) { 1142 | a[t++] = 0; 1143 | } 1144 | ++a[w]; 1145 | } 1146 | } 1147 | 1148 | /** 1149 | * 1150 | * @param e 1151 | * @return this^e 1152 | * 1153 | */ 1154 | /*public function pow(e:int):BigInteger { 1155 | return exp(e, new NullReduction); 1156 | }*/ 1157 | 1158 | /** 1159 | * 1160 | * @param a 1161 | * @param n 1162 | * @param r = lower n words of "this * a", a.t <= n 1163 | * 1164 | */ 1165 | bi_internal function multiplyLowerTo(a:BigInteger, n:int, r:BigInteger):void { 1166 | var i:int = Math.min(t+a.t, n); 1167 | r.s = 0; // assumes a, this >= 0 1168 | r.t = i; 1169 | while (i>0) { 1170 | r.a[--i]=0; 1171 | } 1172 | var j:int; 1173 | for (j=r.t-t;i 0 1187 | * 1188 | */ 1189 | bi_internal function multiplyUpperTo(a:BigInteger, n:int, r:BigInteger):void { 1190 | --n; 1191 | var i:int = r.t = t+a.t-n; 1192 | r.s = 0; // assumes a,this >= 0 1193 | while (--i>=0) { 1194 | r.a[i] = 0; 1195 | } 1196 | for (i=Math.max(n-t,0);i 1) { 1243 | var g2:BigInteger = new BigInteger; 1244 | z.sqrTo(g[1], g2); 1245 | while (n<=km) { 1246 | g[n] = new BigInteger; 1247 | z.mulTo(g2, g[n-2], g[n]); 1248 | n += 2; 1249 | } 1250 | } 1251 | 1252 | var j:int = e.t-1; 1253 | var w:int; 1254 | var is1:Boolean = true; 1255 | var r2:BigInteger = new BigInteger; 1256 | var t:BigInteger; 1257 | i = nbits(e.a[j])-1; 1258 | while (j>=0) { 1259 | if (i>=k1) { 1260 | w = (e.a[j]>>(i-k1))&km; 1261 | } else { 1262 | w = (e.a[j]&((1<<(i+1))-1))<<(k1-i); 1263 | if (j>0) { 1264 | w |= e.a[j-1]>>(DB+i-k1); 1265 | } 1266 | } 1267 | n = k; 1268 | while ((w&1)==0) { 1269 | w >>= 1; 1270 | --n; 1271 | } 1272 | if ((i -= n) <0) { 1273 | i += DB; 1274 | --j; 1275 | } 1276 | if (is1) { // ret == 1, don't bother squaring or multiplying it 1277 | g[w].copyTo(r); 1278 | is1 = false; 1279 | } else { 1280 | while (n>1) { 1281 | z.sqrTo(r, r2); 1282 | z.sqrTo(r2, r); 1283 | n -= 2; 1284 | } 1285 | if (n>0) { 1286 | z.sqrTo(r, r2); 1287 | } else { 1288 | t = r; 1289 | r = r2; 1290 | r2 = t; 1291 | } 1292 | z.mulTo(r2, g[w], r); 1293 | } 1294 | while (j>=0 && (e.a[j]&(1<0) { 1328 | x.rShiftTo(g, x); 1329 | y.rShiftTo(g, y); 1330 | } 1331 | while (x.sigNum()>0) { 1332 | if ((i = x.getLowestSetBit()) >0) { 1333 | x.rShiftTo(i, x); 1334 | } 1335 | if ((i = y.getLowestSetBit()) >0) { 1336 | y.rShiftTo(i, y); 1337 | } 1338 | if (x.compareTo(y) >= 0) { 1339 | x.subTo(y, x); 1340 | x.rShiftTo(1, x); 1341 | } else { 1342 | y.subTo(x, y); 1343 | y.rShiftTo(1, y); 1344 | } 1345 | } 1346 | if (g>0) { 1347 | y.lShiftTo(g, y); 1348 | } 1349 | return y; 1350 | } 1351 | 1352 | /** 1353 | * 1354 | * @param n 1355 | * @return this % n, n < 2^DB 1356 | * 1357 | */ 1358 | protected function modInt(n:int):int { 1359 | if (n<=0) return 0; 1360 | var d:int = DV%n; 1361 | var r:int = (s<0)?n-1:0; 1362 | if (t>0) { 1363 | if (d==0) { 1364 | r = a[0]%n; 1365 | } else { 1366 | for (var i:int=t-1;i>=0;--i) { 1367 | r = (d*r+a[i])%n; 1368 | } 1369 | } 1370 | } 1371 | return r; 1372 | } 1373 | 1374 | /** 1375 | * 1376 | * @param m 1377 | * @return 1/this %m (HAC 14.61) 1378 | * 1379 | */ 1380 | public function modInverse(m:BigInteger):BigInteger { 1381 | var ac:Boolean = m.isEven(); 1382 | if ((isEven()&&ac) || m.sigNum()==0) { 1383 | return BigInteger.ZERO; 1384 | } 1385 | var u:BigInteger = m.clone(); 1386 | var v:BigInteger = clone(); 1387 | var a:BigInteger = nbv(1); 1388 | var b:BigInteger = nbv(0); 1389 | var c:BigInteger = nbv(0); 1390 | var d:BigInteger = nbv(1); 1391 | while (u.sigNum()!=0) { 1392 | while (u.isEven()) { 1393 | u.rShiftTo(1,u); 1394 | if (ac) { 1395 | if (!a.isEven() || !b.isEven()) { 1396 | a.addTo(this,a); 1397 | b.subTo(m,b); 1398 | } 1399 | a.rShiftTo(1,a); 1400 | } else if (!b.isEven()) { 1401 | b.subTo(m,b); 1402 | } 1403 | b.rShiftTo(1,b); 1404 | } 1405 | while (v.isEven()) { 1406 | v.rShiftTo(1,v); 1407 | if (ac) { 1408 | if (!c.isEven() || !d.isEven()) { 1409 | c.addTo(this,c); 1410 | d.subTo(m,d); 1411 | } 1412 | c.rShiftTo(1,c); 1413 | } else if (!d.isEven()) { 1414 | d.subTo(m,d); 1415 | } 1416 | d.rShiftTo(1,d); 1417 | } 1418 | if (u.compareTo(v)>=0) { 1419 | u.subTo(v,u); 1420 | if (ac) { 1421 | a.subTo(c,a); 1422 | } 1423 | b.subTo(d,b); 1424 | } else { 1425 | v.subTo(u,v); 1426 | if (ac) { 1427 | c.subTo(a,c); 1428 | } 1429 | d.subTo(b,d); 1430 | } 1431 | } 1432 | if (v.compareTo(BigInteger.ONE) != 0) { 1433 | return BigInteger.ZERO; 1434 | } 1435 | if (d.compareTo(m) >= 0) { 1436 | return d.subtract(m); 1437 | } 1438 | if (d.sigNum()<0) { 1439 | d.addTo(m,d); 1440 | } else { 1441 | return d; 1442 | } 1443 | if (d.sigNum()<0) { 1444 | return d.add(m); 1445 | } else { 1446 | return d; 1447 | } 1448 | } 1449 | 1450 | /** 1451 | * 1452 | * @param t 1453 | * @return primality with certainty >= 1-.5^t 1454 | * 1455 | */ 1456 | /*public function isProbablePrime(t:int):Boolean { 1457 | var i:int; 1458 | var x:BigInteger = abs(); 1459 | if (x.t == 1 && x.a[0]<=lowprimes[lowprimes.length-1]) { 1460 | for (i=0;i>1; 1497 | if (t>lowprimes.length) { 1498 | t = lowprimes.length; 1499 | } 1500 | var a:BigInteger = new BigInteger; 1501 | for (var i:int=0;ibits) subTo(BigInteger.ONE.shiftLeft(bits-1),this); 1537 | } 1538 | }*/ 1539 | 1540 | } 1541 | } 1542 | -------------------------------------------------------------------------------- /src/com/hurlant/math/bi_internal.as: -------------------------------------------------------------------------------- 1 | /** 2 | * bi_internal 3 | * 4 | * A namespace. w00t. 5 | * Copyright (c) 2007 Henri Torgemane 6 | * 7 | * See LICENSE.txt for full license information. 8 | */ 9 | package com.hurlant.math { 10 | public namespace bi_internal = "http://crypto.hurlant.com/BigInteger"; 11 | } -------------------------------------------------------------------------------- /src/com/hurlant/util/Hex.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Hex 3 | * 4 | * Utility class to convert Hex strings to ByteArray or String types. 5 | * Copyright (c) 2007 Henri Torgemane 6 | * 7 | * See LICENSE.txt for full license information. 8 | */ 9 | package com.hurlant.util 10 | { 11 | import flash.utils.ByteArray; 12 | 13 | public class Hex 14 | { 15 | /** 16 | * Support straight hex, or colon-laced hex. 17 | * (that means 23:03:0e:f0, but *NOT* 23:3:e:f0) 18 | * Whitespace characters are ignored. 19 | */ 20 | public static function toArray(hex:String):ByteArray { 21 | hex = hex.replace(/\s|:/gm,''); 22 | var a:ByteArray = new ByteArray; 23 | if ((hex.length&1)==1) hex="0"+hex; 24 | for (var i:uint=0;i