├── .gitignore
├── .jshintrc
├── .npmignore
├── CHANGELOG.md
├── Gruntfile.js
├── README.md
├── buildPlayer.py
├── debug
└── BufferDisplay.js
├── demo
├── dash.all.debug.js
└── example_dash.html
├── package.json
└── src
├── as3
└── com
│ ├── dash
│ ├── boxes
│ │ ├── Box.as
│ │ ├── FLVTag.as
│ │ ├── FullBox.as
│ │ ├── HandlerReferenceBox.as
│ │ ├── MediaBox.as
│ │ ├── MediaHeaderBox.as
│ │ ├── MediaInformationBox.as
│ │ ├── MovieBox.as
│ │ ├── MovieExtendsBox.as
│ │ ├── MovieFragmentBox.as
│ │ ├── Muxer.as
│ │ ├── NalUnit.as
│ │ ├── SampleDescriptionBox.as
│ │ ├── SampleEntry.as
│ │ ├── SampleTableBox.as
│ │ ├── TrackBox.as
│ │ ├── TrackExtendsBox.as
│ │ ├── TrackFragmentBox.as
│ │ ├── TrackFragmentHeaderBox.as
│ │ ├── TrackFragmentRunBox.as
│ │ └── TrackHeaderBox.as
│ ├── events
│ │ └── MessageEvent.as
│ ├── handlers
│ │ ├── AudioSegmentHandler.as
│ │ ├── IndexSegmentHandler.as
│ │ ├── InitializationAudioSegmentHandler.as
│ │ ├── InitializationSegmentHandler.as
│ │ ├── InitializationVideoSegmentHandler.as
│ │ ├── MediaSegmentHandler.as
│ │ ├── SegmentHandler.as
│ │ └── VideoSegmentHandler.as
│ ├── loaders
│ │ └── FragmentLoader.as
│ └── utils
│ │ ├── BandwidthMonitor.as
│ │ ├── Base64.as
│ │ ├── Bytes.as
│ │ ├── Console.as
│ │ ├── Manifest.as
│ │ └── SmoothMonitor.as
│ └── streamroot
│ ├── MSEPolyfill.as
│ ├── Main.as
│ ├── NetStreamWrapper.as
│ ├── Skin.as
│ ├── buffer
│ ├── Segment.as
│ ├── SourceBuffer.as
│ ├── StreamBuffer.as
│ └── StreamBufferController.as
│ ├── events
│ └── PlaybackEvent.as
│ ├── transcoder
│ ├── TranscodeWorker.as
│ └── Transcoder.as
│ └── util
│ ├── Conf.as
│ └── TrackTypeHelper.as
└── js
├── Main.js
├── lib
├── B64Encoder.js
├── B64MainThread.js
├── B64Worker.js
├── MediaSourceFlash.js
├── SegmentAppender.js
├── SourceBuffer.js
├── VideoExtension.js
└── utils
│ └── CustomTimeRange.js
└── test
└── utils.customTimeRange.js
/.gitignore:
--------------------------------------------------------------------------------
1 | **/*.swf
2 | **/*.swc
3 | node_modules/
4 | npm-debug.log
5 | build/
6 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "undef": true,
3 | "unused": true,
4 | "curly": true,
5 | "indent": 4,
6 | "camelcase":false,
7 | "forin":false,
8 | "newcap":true,
9 | "quotmark":false,
10 | "typed":true,
11 | "worker":true,
12 | "browser":true,
13 | "browserify":true,
14 | "mocha":true,
15 | "devel":true,
16 | "predef": [],
17 | "esnext": true
18 | }
19 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | com/streamroot/TranscodeWorker.swf
2 | node_modules/
3 | /grunt-aws.json
4 | /dist/
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file.
3 | This project adheres to [Semantic Versioning](http://semver.org/).
4 | This changelog's template come from [keepachangelog.com](http://keepachangelog.com/). When editing this document, please follow the convention specified there.
5 |
6 |
7 | ## [Unreleased]
8 | ### Changed
9 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 | require("matchdep").filterDev("grunt-*").forEach(grunt.loadNpmTasks);
3 |
4 | grunt.registerTask('default', ['browserify']);
5 |
6 | grunt.initConfig({
7 | pkg: grunt.file.readJSON('package.json'),
8 | browserify: {
9 | main: {
10 | src: 'src/js/Main.js',
11 | dest: 'build/fMSE.js',
12 | options: {
13 | transform: ['babelify'],
14 | browserifyOptions: {
15 | standalone: 'fMSE.init',
16 | debug: true
17 | },
18 | watch: true,
19 | keepAlive: true
20 | }
21 | },
22 | debug: {
23 | src: 'debug/BufferDisplay.js',
24 | dest: 'debug/build/BufferDisplay.js',
25 | options: {
26 | transform: ['babelify'],
27 | browserifyOptions: {
28 | standalone: 'fMSE.debug.bufferDisplay',
29 | debug: true
30 | },
31 | watch: true,
32 | keepAlive: true
33 | }
34 | },
35 | }
36 | });
37 | };
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### :warning: This repository is not maintained and has critical known issues (see issues section).
2 |
3 | # Flash Media Source Extensions polyfill
4 |
5 | fMSE is a library that emulates MSE in browsers that do not support it.
6 |
7 | It allows transparent fallback for players supporting modern video formats such as MPEG-DASH or HLS when MSE is not available.
8 |
9 | Adobe Flash is used to do the actual playback, and communicates with a small JS polyfill that implements the MSE API.
10 |
11 | ## Building
12 |
13 | This is a two steps process:
14 |
15 | ### Building JavaScript
16 |
17 | Quite simple:
18 | ```
19 | $ npm install
20 | $ grunt
21 | ```
22 |
23 | This will create `fMSE.js` in the `build` directory.
24 |
25 | ### Building ActionScript files
26 |
27 | If you don't have Flex SDK:
28 |
29 | 1. Download [Apache Flex SDK Installer](http://flex.apache.org/installer.html)
30 | 1. Install the latest Flex SDK.
31 |
32 | Edit `buildPlayer.py` and specify path to your Flex SDK directory and run the script:
33 |
34 | ```
35 | $ python buildPlayer.py
36 | ```
37 |
38 | You can provide additional options to customize the build. Use
39 |
40 | ```
41 | $ python buildPlayer.py -h
42 | ```
43 |
44 | to get list of supported options. Successful build will create `fMSE.swf` in the `build` directory.
45 |
46 | ##### NOTE:
47 |
48 | We're targeting flash versions 11.4+, so you should make sure you have playerglobal.swc v11.4 at `$FLEX_PATH/frameworks/libs/player/11.4/playerglobal.swc`
49 |
50 | ## Example
51 |
52 | Here is an example of MPEG-DASH playback using [dash.js v2.0](https://github.com/Dash-Industry-Forum/dash.js) and fMSE
53 |
54 | ```html
55 |
56 |
57 |
58 | fMSE Polyfill - dash.js test page
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
98 |
99 |
100 | ```
101 |
102 | This demo page is here `demo/example_dash.html`. You can go to `demo` directory and run simple HTTP server (like Python's) to test it in a browser.
103 |
104 | ## Integration
105 |
106 | 1. Include fSME.js in your page
107 |
108 | ```html
109 |
110 |
111 |
112 | ...
113 |
114 | ```
115 |
116 | 1. Initialize fMSE
117 |
118 | ```html
119 |
120 | ...
121 |
138 |
139 | ```
140 |
141 | ## Requirements & Compatibilities
142 |
143 | This library requires Adobe Flash Player 11.4 or higher installed.
144 | This library also needs [Web workers support](http://caniuse.com/webworkers), so it might not be working correctly on Safari and Edge.
145 |
146 | fMSE has been tested with the following media libraries:
147 | - [dash.js](https://github.com/Dash-Industry-Forum/dash.js)
148 |
149 | Media engines to we want to provide support with:
150 | - [shakapayer](https://github.com/google/shaka-player)
151 | - [hls.js](https://github.com/dailymotion/hls.js)
152 |
153 | ## Known issues (PRs appreciated!)
154 |
155 | - seek not working yet
156 | - Muxed streams not supported
157 | - EME is not supported (planning to provide EME support with Flash Access DRM)
158 |
159 | For more details see our [issues tracker](https://github.com/streamroot/fmse/issues).
160 |
161 | ## Contributing
162 |
163 | fMSE is a free and open source library. It's a work in progress and we appreciate any help you're willing to give. Don't hesitate add and comment issues on Github, or contact us directly at contact@streamroot.io.
164 |
165 | ## License
166 |
167 | This project is licensed under [MPL 2.0](https://www.mozilla.org/en-US/MPL/2.0/)
168 | If you need a special type of license for this project, you can contact us at contact@streamroot.io.
169 |
170 | ## Credits
171 |
172 | The project uses [dash.as](https://github.com/castlabs/dashas) for MP4 to FLV transmuxing.
173 |
--------------------------------------------------------------------------------
/buildPlayer.py:
--------------------------------------------------------------------------------
1 | import os
2 | import shutil
3 | import sys
4 | import subprocess
5 | import time
6 |
7 | if (os.path.exists("/opt/flex")):
8 | flex = "/opt/flex"
9 | exe = ""
10 | elif (os.path.exists(os.path.normpath("C:/flex_sdk_4.6"))):
11 | flex = ("C:/flex_sdk_4.6")
12 | exe = ".exe"
13 | elif (os.path.exists(os.path.expanduser("~/SDKs/Flex/4.14"))):
14 | flex = os.path.expanduser("~/SDKs/Flex/4.14")
15 | exe = ""
16 |
17 | SOURCE_PATH = "./src/as3/"
18 | TRANSCODER_MAIN_CLASS = SOURCE_PATH + "com/streamroot/transcoder/TranscodeWorker.as"
19 | TRANSCODER_OUTPUT = SOURCE_PATH + "com/streamroot/transcoder/TranscodeWorker.swf"
20 | POLYFILL_MAIN_CLASS = SOURCE_PATH + "com/streamroot/Main.as"
21 | POLYFILL_OUTPUT = "build/fMSE.swf"
22 |
23 | debug = "false"
24 | log_debug = "false"
25 | log_error = "false"
26 | verbose = False
27 | swfversion = "17"
28 | targetPlayer = "11.4.0"
29 | color = True
30 |
31 | startTime = time.time()
32 |
33 | def helpParam():
34 | print "\npython buildPlayer.py [options]"
35 | print "options:"
36 | print "\t--debug : set debug flag to true"
37 | print "\t--log-debug : enables debug messages logging to browser console"
38 | print "\t--log-error : enables error messages logging to browser console"
39 | print "\t--no-color : disable color"
40 | print "\t-v : verbose mode"
41 | print "\t-h : display this menu"
42 | print ""
43 | sys.exit(0)
44 |
45 | def printRed(text):
46 | if color:
47 | print "\033[31m" + text + "\033[0m"
48 | else:
49 | print text
50 |
51 | def printPurple(text):
52 | if color:
53 | print "\033[35m" + text + "\033[0m"
54 | else:
55 | print text
56 |
57 | def printGreen(text):
58 | if color:
59 | print "\033[32m" + text + "\033[0m"
60 | else:
61 | print text
62 |
63 | def printYellow(text):
64 | if color:
65 | print "\033[33m" + text + "\033[0m"
66 | else:
67 | print text
68 |
69 | if (len(sys.argv)>1):
70 | for i in range(1, len(sys.argv)):
71 | if sys.argv[i] == "--debug":
72 | debug = "true"
73 | elif sys.argv[i] == "--log-debug":
74 | log_debug = "true"
75 | elif sys.argv[i] == "--log-error":
76 | log_error = "true"
77 | elif sys.argv[i] == "-v":
78 | verbose = True
79 | elif sys.argv[i] in ["--help","-h"]:
80 | helpParam()
81 | elif sys.argv[i] == "--no-color":
82 | color = False
83 | else:
84 | print "incorrect argument"
85 | helpParam()
86 | if verbose:
87 | print "Debug flag = " + debug
88 | print "-swf-version="+swfversion
89 | print "-target-player="+targetPlayer
90 |
91 | def popenPrint(result):
92 | result.wait()
93 | if verbose:
94 | for line in result.stdout:
95 | print(line)
96 |
97 | for line in result.stderr:
98 | while line.endswith("\n"):
99 | line = line[:-1]
100 | if not line == "":
101 | if color:
102 | line = line.replace("Error:", "\n\033[31mError\033[0m:");
103 | line = line.replace("Erreur:", "\n\033[31mErreur\033[0m:");
104 | line = line.replace("Warning:", "\n\033[33mWarning\033[0m:");
105 | line = line.replace("Avertissement:", "\n\033[33mAvertissement\033[0m:");
106 | else:
107 | line = line.replace("Error:", "Error:");
108 | line = line.replace("Erreur:", "Erreur:");
109 | line = line.replace("Warning:", "Warning:");
110 | line = line.replace("Avertissement:", "Avertissement:");
111 | if line.startswith('\n'):
112 | line = line[1:]
113 | print(line)
114 |
115 | #Compile worker
116 | if os.path.exists(TRANSCODER_OUTPUT):
117 | os.remove(os.path.normpath(TRANSCODER_OUTPUT))
118 | workerResult = subprocess.Popen([os.path.normpath(flex + "/bin/mxmlc" + exe),
119 | os.path.normpath(TRANSCODER_MAIN_CLASS),
120 | os.path.normpath("-output=" + TRANSCODER_OUTPUT),
121 | "-static-link-runtime-shared-libraries=true",
122 | "-compiler.source-path=" + SOURCE_PATH,
123 | "-target-player="+targetPlayer+"",
124 | "-swf-version="+swfversion+"",
125 | "-debug="+debug+"",
126 | "-define+=CONFIG::LOG_DEBUG," + log_debug,
127 | "-define+=CONFIG::LOG_ERROR," + log_error],
128 | stdout=subprocess.PIPE, stderr=subprocess.PIPE)
129 |
130 | popenPrint(workerResult)
131 | if not os.path.exists(TRANSCODER_OUTPUT):
132 | printRed("Transcoder build failed")
133 | sys.exit(0)
134 | else:
135 | printPurple(">> " + TRANSCODER_OUTPUT + " has been generated, build successful")
136 |
137 | #compiling polyfill
138 | if os.path.exists(POLYFILL_OUTPUT):
139 | os.remove(os.path.normpath(POLYFILL_OUTPUT))
140 | polyfillResult = subprocess.Popen([os.path.normpath(flex +"/bin/mxmlc" + exe),
141 | os.path.normpath(POLYFILL_MAIN_CLASS),
142 | os.path.normpath("-output=" + POLYFILL_OUTPUT),
143 | "-compiler.source-path=" + SOURCE_PATH,
144 | "-target-player="+targetPlayer+"",
145 | "-swf-version="+swfversion+"",
146 | "-debug="+debug+"",
147 | "-static-link-runtime-shared-libraries=true",
148 | "-use-network=false",
149 | "-compiler.optimize=true",
150 | "-default-background-color=0x000000",
151 | "-default-frame-rate=30",
152 | "-define+=CONFIG::LOG_DEBUG," + log_debug,
153 | "-define+=CONFIG::LOG_ERROR," + log_error], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
154 | popenPrint(polyfillResult)
155 | if not os.path.exists(POLYFILL_OUTPUT):
156 | printRed("Polyfill build failed")
157 | sys.exit(0)
158 | else:
159 | printPurple(">> " + POLYFILL_OUTPUT + " has been generated, build successful")
160 |
161 | printGreen("Build successful")
162 | time = time.time() - startTime
163 | print "Time elapsed : " + str(time) + "s"
164 |
--------------------------------------------------------------------------------
/debug/BufferDisplay.js:
--------------------------------------------------------------------------------
1 | const CACHE_HEIGHT = 40;
2 | const BUFFER_HEIGHT = 25;
3 | const TRACK_TOP_MARGIN = 3;
4 | const BUFFERED_COLOR = "#0c1b2e";
5 | const PENDING_COLOR = "#07659f";
6 | const CURRENT_TIME_COLOR = "#bf0101";
7 | const CANVAS_WIDTH = 700;
8 | const TRACK_TYPE_WIDTH = 60;
9 | const FONT_STYLE = "12px Arial";
10 | const TRACK_TYPE_COLOR = "#000824";
11 |
12 |
13 | class BufferDisplay {
14 | constructor(){
15 | this._sourceBuffers = [];
16 | }
17 |
18 | attachVideo(video) {
19 | this._video = video;
20 | this._startIfReady();
21 | }
22 |
23 | attachSourceBuffer(sourceBuffer) {
24 | this._sourceBuffers.push(sourceBuffer);
25 | this._startIfReady();
26 | }
27 |
28 | _startIfReady() {
29 | if (this._sourceBuffers.length && this._video && !this._started) {
30 | this._started = true;
31 | this._canvas = document.createElement('canvas');
32 |
33 | this._canvas.width = CANVAS_WIDTH;
34 | let div = document.getElementById("bufferDisplay");
35 | if(!div){
36 | div = document.createElement('div');
37 | document.body.appendChild(div);
38 | }
39 | div.appendChild(this._canvas);
40 |
41 | let render = this._render.bind(this);
42 | setInterval(render, 30);
43 | }
44 | }
45 |
46 | _render(){
47 | let { currentTime } = this._video;
48 | let context2D = this._canvas.getContext('2d');
49 |
50 | this._canvas.height = (CACHE_HEIGHT + TRACK_TOP_MARGIN)*this._sourceBuffers.length;
51 |
52 | // calculate the scale of the chart
53 | let min = Infinity, max = 0;
54 | for (let sourceBuffer of this._sourceBuffers) {
55 | let buffered = sourceBuffer.debugBuffered || sourceBuffer.buffered;
56 | if(buffered.length){
57 | let bufferedMin = buffered.start(0);
58 | let bufferedMax = buffered.end(buffered.length-1);
59 |
60 | if( bufferedMin < min ){
61 | min = bufferedMin;
62 | }
63 | if(bufferedMax > max){
64 | max = bufferedMax;
65 | }
66 | }
67 | }
68 |
69 | let scale = {min, max, canvasWidth: this._canvas.width};
70 |
71 | //for each SourceBuffer, draw TimeRanges.
72 | for (let i=0, sourceBuffer; sourceBuffer = this._sourceBuffers[i]; i++) {
73 | let buffered = sourceBuffer.debugBuffered || sourceBuffer.buffered;
74 | let debug = !!sourceBuffer.debugBuffered;
75 |
76 | let yPosition = (CACHE_HEIGHT + TRACK_TOP_MARGIN)*i;
77 | let opt = {
78 | scale,
79 | height: BUFFER_HEIGHT,
80 | yPosition: yPosition+(CACHE_HEIGHT - BUFFER_HEIGHT),
81 | color: BUFFERED_COLOR,
82 | debug
83 | };
84 | this._drawTimeRanges(context2D, opt, buffered, currentTime);
85 | if (debug) {
86 | let captionYPosition = yPosition + (CACHE_HEIGHT * 1 / 4);
87 | this._writeTrackType(context2D, sourceBuffer.type, captionYPosition);
88 | }
89 | }
90 | let currentTimeLineOptions = {
91 | height:this._canvas.height,
92 | color: CURRENT_TIME_COLOR,
93 | scale
94 | };
95 | this._drawCurrentTimeLine(context2D, currentTimeLineOptions, currentTime);
96 | }
97 |
98 | //The actual canvas drawing functions
99 | _drawTimeRanges(context2D, options, timeRanges, currentTime){
100 | let {scale, height, yPosition, color, debug} = options;
101 |
102 | if (debug && timeRanges.length > 2) {
103 | throw new Error("Expected debug buffered attribute with a buffered time interval and a pending time interval. Got more than 2 time intervals");
104 | }
105 |
106 | for (let j = 0; j < timeRanges.length; j++) {
107 |
108 | if (debug && j===1) {
109 | color = PENDING_COLOR;
110 | }
111 |
112 |
113 | let start = timeRanges.start(j);
114 | let end = timeRanges.end(j);
115 |
116 | let startX = this._convertTimeToPixel(scale, start);
117 | let endX = this._convertTimeToPixel(scale, end);
118 | let length = endX - startX > 1 ? endX - startX : 1;
119 | context2D.fillStyle = color;
120 | context2D.fillRect(startX, yPosition, length, height);
121 |
122 | if (start <= currentTime && currentTime <= end) {
123 | context2D.fillStyle = "#868686";
124 | context2D.font = "11px Arial";
125 | context2D.fillText(start.toFixed(3), startX + 2, yPosition + 10);
126 | context2D.fillText(end.toFixed(3), endX - 38, yPosition + height - 2);
127 | }
128 | }
129 | }
130 |
131 |
132 | _drawCurrentTimeLine(context2D, options, time){
133 | let {color, scale, height} = options;
134 | let position = this._convertTimeToPixel(scale,time);
135 | context2D.fillStyle = color;
136 | context2D.fillRect(position, 0, 1, height);
137 | context2D.fillStyle = color;
138 | context2D.font = FONT_STYLE;
139 | context2D.fillText(time.toFixed(3), 0, height);
140 | }
141 |
142 |
143 | _convertTimeToPixel(scale, time) {
144 | let {min, max, canvasWidth} = scale;
145 | let effectiveCanvasWidth = canvasWidth - TRACK_TYPE_WIDTH;
146 | let divider = Math.max(max - min, 3*60); //trick so we can see the progression of the buffer during the 3 first minutes of a stream.
147 | return TRACK_TYPE_WIDTH + ((time - min) * effectiveCanvasWidth / divider);
148 | }
149 |
150 | _writeTrackType(context2D, trackType, yPosition){
151 | context2D.fillStyle = TRACK_TYPE_COLOR;
152 | context2D.font = FONT_STYLE;
153 | context2D.fillText(trackType, 0, yPosition);
154 | }
155 |
156 | }
157 |
158 | export default new BufferDisplay();
159 |
--------------------------------------------------------------------------------
/demo/example_dash.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | fMSE Polyfill - dash.js test page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fMSE",
3 | "version": "0.1.0",
4 | "homepage": "www.streamroot.io",
5 | "scripts": {
6 | "test": "mocha src/js/videomock/test/"
7 | },
8 | "author": {
9 | "name": "StreamRoot",
10 | "email": "contact@streamroot.io"
11 | },
12 | "devDependencies": {
13 | "should": "4.0.4",
14 | "grunt": "^0.4.5",
15 | "grunt-browserify": "4.0.1",
16 | "babelify": "^6.1.0",
17 | "matchdep": "0.3.0"
18 | },
19 | "dependencies": {
20 | "eventemitter3": "^1.1.1"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/Box.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 | import flash.errors.IllegalOperationError;
11 | import flash.utils.ByteArray;
12 |
13 | internal class Box {
14 | protected const SIZE_AND_TYPE:uint = 8;
15 |
16 | private var _end:uint;
17 |
18 | public function Box(offset:uint, size:uint) {
19 | _end = offset + size;
20 | }
21 |
22 | public function get end():uint {
23 | return _end;
24 | }
25 |
26 | public function parse(ba:ByteArray):void {
27 | while (ba.bytesAvailable) {
28 | var offset:uint = ba.position;
29 | var size:uint = ba.readUnsignedInt();
30 | var type:String = ba.readUTFBytes(4);
31 |
32 | var parsed:Object = parseChildBox(type, offset, size, ba);
33 |
34 | if (parsed == false) {
35 | if (ba.position < _end) { // skip
36 | ba.position += size - SIZE_AND_TYPE;
37 | } else { // quit
38 | ba.position = _end;
39 | return;
40 | }
41 | }
42 | }
43 | }
44 |
45 | protected function parseChildBox(type:String, offset:uint, size:uint, ba:ByteArray):Boolean {
46 | throw new IllegalOperationError("Method not implemented");
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/FLVTag.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 | import flash.utils.ByteArray;
11 |
12 | public class FLVTag {
13 | public static const I_FRAME:uint = 1;
14 | public static const P_FRAME:uint = 2;
15 | public static const B_FRAME:uint = 3;
16 | public static const UNKNOWN:uint = 4;
17 |
18 | private static const VIDEO_TYPE:uint = 9;
19 | private static const AUDIO_TYPE:uint = 8;
20 |
21 | public var length:uint;
22 | public var timestamp:uint;
23 | public var frameType:uint;
24 | public var compositionTimestamp:int;
25 | public var dataOffset:uint;
26 | public var data:ByteArray;
27 | public var setup:Boolean = false;
28 |
29 | public var duration:uint;
30 |
31 | private var _type:uint;
32 |
33 | public function FLVTag() {
34 | }
35 |
36 | public function get type():uint {
37 | return _type;
38 | }
39 |
40 | public function isVideo():Boolean {
41 | return _type == VIDEO_TYPE;
42 | }
43 |
44 | public function isAudio():Boolean {
45 | return _type == AUDIO_TYPE;
46 | }
47 |
48 | public function markAsVideo():void {
49 | _type = VIDEO_TYPE;
50 | }
51 |
52 | public function markAsAudio():void {
53 | _type = AUDIO_TYPE;
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/FullBox.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 | import flash.errors.IllegalOperationError;
11 | import flash.utils.ByteArray;
12 |
13 | public class FullBox extends Box {
14 | private var _version:uint;
15 | private var _flags:uint;
16 |
17 | public function FullBox(offset:uint, size:uint) {
18 | super(offset, size);
19 | }
20 |
21 | public function get version():uint {
22 | return _version;
23 | }
24 |
25 | public function get flags():uint {
26 | return _flags;
27 | }
28 |
29 | public override function parse(ba:ByteArray):void {
30 | parseVersion(ba);
31 | parseFlags(ba);
32 |
33 | parseBox(ba);
34 |
35 | ba.position = end;
36 | }
37 |
38 | protected function parseBox(ba:ByteArray):void {
39 | throw new IllegalOperationError("Method not implemented");
40 | }
41 |
42 | private function parseVersion(ba:ByteArray):void {
43 | _version = ba.readUnsignedByte();
44 | }
45 |
46 | private function parseFlags(ba:ByteArray):void {
47 | _flags = 0;
48 |
49 | for (var i:uint = 0; i < 3; i++) {
50 | _flags = _flags << 8;
51 | _flags += ba.readUnsignedByte();
52 | }
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/HandlerReferenceBox.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 | import flash.utils.ByteArray;
11 |
12 | public class HandlerReferenceBox extends FullBox {
13 |
14 | // 'vide', 'soun' or other values
15 | private var _type:String;
16 |
17 | public function HandlerReferenceBox(offset:uint, size:uint) {
18 | super(offset, size);
19 | }
20 |
21 | public function get type():String {
22 | return _type;
23 | }
24 |
25 | override protected function parseBox(ba:ByteArray):void {
26 |
27 | // skip QUICKTIME type
28 | ba.position += 4;
29 |
30 | _type = ba.readUTFBytes(4);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/MediaBox.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 |
11 | import flash.utils.ByteArray;
12 |
13 | public class MediaBox extends Box {
14 | private var _mdhd:MediaHeaderBox;
15 | private var _hdlr:HandlerReferenceBox;
16 | private var _minf:MediaInformationBox;
17 |
18 | public function MediaBox(offset:uint, size:uint) {
19 | super(offset, size);
20 | }
21 |
22 | public function get mdhd():MediaHeaderBox {
23 | return _mdhd;
24 | }
25 |
26 | public function get hdlr():HandlerReferenceBox {
27 | return _hdlr;
28 | }
29 |
30 | public function get minf():MediaInformationBox {
31 | return _minf;
32 | }
33 |
34 | override protected function parseChildBox(type:String, offset:uint, size:uint, ba:ByteArray):Boolean {
35 | if (type == "mdhd") {
36 | parseMediaHeaderBox(offset, size, ba);
37 | return true;
38 | }
39 |
40 | if (type == "hdlr") {
41 | parseHandlerReferenceBox(offset, size, ba);
42 | return true;
43 | }
44 |
45 | if (type == "minf") {
46 | parseMediaInformationBox(offset, size, ba);
47 | return true;
48 | }
49 |
50 | return false;
51 | }
52 |
53 | private function parseMediaInformationBox(offset:uint, size:uint, ba:ByteArray):void {
54 | _minf = new MediaInformationBox(offset, size);
55 | _minf.parse(ba);
56 | }
57 |
58 | private function parseHandlerReferenceBox(offset:uint, size:uint, ba:ByteArray):void {
59 | _hdlr = new HandlerReferenceBox(offset, size);
60 | _hdlr.parse(ba);
61 | }
62 |
63 | private function parseMediaHeaderBox(offset:uint, size:uint, ba:ByteArray):void {
64 | _mdhd = new MediaHeaderBox(offset, size);
65 | _mdhd.parse(ba);
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/MediaHeaderBox.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 | import flash.utils.ByteArray;
11 |
12 | public class MediaHeaderBox extends FullBox {
13 | private var _timescale:uint;
14 |
15 | public function MediaHeaderBox(offset:uint, size:uint) {
16 | super(offset, size);
17 | }
18 |
19 | public function get timescale():uint {
20 | return _timescale;
21 | }
22 |
23 | override protected function parseBox(ba:ByteArray):void {
24 | if (version == 1) {
25 | parseVersion1(ba);
26 | }
27 |
28 | if (version == 0) {
29 | parseVersion2(ba);
30 | }
31 | }
32 |
33 | private function parseVersion1(ba:ByteArray):void {
34 |
35 | // // creation time MSB
36 | // ba.readUnsignedInt(); // 4 bytes
37 | // // creation time LSB
38 | // ba.readUnsignedInt(); // 4 bytes
39 | // // modification time MSB
40 | // ba.readUnsignedInt(); // 4 bytes
41 | // // modification time LSB
42 | // ba.readUnsignedInt(); // 4 bytes
43 |
44 | // skip
45 | ba.position += 16;
46 |
47 | // timescale
48 | _timescale = ba.readUnsignedInt(); // 4 bytes
49 | }
50 |
51 | private function parseVersion2(ba:ByteArray):void {
52 |
53 | // // creation time LSB
54 | // ba.readUnsignedInt(); // 4 bytes
55 | // // modification time LSB
56 | // ba.readUnsignedInt(); // 4 bytes
57 |
58 | // skip
59 | ba.position += 8;
60 |
61 | // timescale
62 | _timescale = ba.readUnsignedInt();
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/MediaInformationBox.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 | import flash.utils.ByteArray;
11 |
12 | public class MediaInformationBox extends Box {
13 | private var _stbl:SampleTableBox;
14 |
15 | public function MediaInformationBox(offset:uint, size:uint) {
16 | super(offset, size);
17 | }
18 |
19 | public function get stbl():SampleTableBox {
20 | return _stbl;
21 | }
22 |
23 | override protected function parseChildBox(type:String, offset:uint, size:uint, ba:ByteArray):Boolean {
24 | if (type == "stbl") {
25 | parseSampleTableBox(offset, size, ba);
26 | return true;
27 | }
28 |
29 | return false;
30 | }
31 |
32 | private function parseSampleTableBox(offset:uint, size:uint, ba:ByteArray):void {
33 | _stbl = new SampleTableBox(offset, size);
34 | _stbl.parse(ba);
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/MovieBox.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 |
11 | import flash.utils.ByteArray;
12 |
13 | public class MovieBox extends Box {
14 | private var _traks:Vector. = new Vector.();
15 | private var _mvex:MovieExtendsBox;
16 |
17 | public function MovieBox(offset:uint, size:uint) {
18 | super(offset, size);
19 | }
20 |
21 | public function get traks():Vector. {
22 | return _traks;
23 | }
24 |
25 | public function get mvex():MovieExtendsBox {
26 | return _mvex;
27 | }
28 |
29 | override protected function parseChildBox(type:String, offset:uint, size:uint, ba:ByteArray):Boolean {
30 | if (type == "trak") {
31 | parseTrackBox(offset, size, ba);
32 | return true;
33 | }
34 |
35 | if (type == "mvex") {
36 | parseMovieExtendsBox(offset, size, ba);
37 | return true;
38 | }
39 |
40 | return false;
41 | }
42 |
43 | private function parseMovieExtendsBox(offset:uint, size:uint, ba:ByteArray):void {
44 | _mvex = new MovieExtendsBox(offset, size);
45 | _mvex.parse(ba);
46 | }
47 |
48 | private function parseTrackBox(offset:uint, size:uint, ba:ByteArray):void {
49 | var trak:TrackBox = new TrackBox(offset, size);
50 | trak.parse(ba);
51 | _traks.push(trak);
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/MovieExtendsBox.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 |
11 | import flash.utils.ByteArray;
12 |
13 | public class MovieExtendsBox extends Box {
14 | private var _trexs:Vector. = new Vector.();
15 |
16 | public function MovieExtendsBox(offset:uint, size:uint) {
17 | super(offset, size);
18 | }
19 |
20 | public function get trexs():Vector. {
21 | return _trexs;
22 | }
23 |
24 | override protected function parseChildBox(type:String, offset:uint, size:uint, ba:ByteArray):Boolean {
25 | if (type == "trex") {
26 | parseTrackExtendsBox(offset, size, ba);
27 | return true;
28 | }
29 |
30 | return false;
31 | }
32 |
33 | private function parseTrackExtendsBox(offset:uint, size:uint, ba:ByteArray):void {
34 | var trex:TrackExtendsBox = new TrackExtendsBox(offset, size);
35 | trex.parse(ba);
36 | _trexs.push(trex);
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/MovieFragmentBox.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 |
11 | import flash.utils.ByteArray;
12 |
13 | public class MovieFragmentBox extends Box {
14 | private var _trafs:Vector. = new Vector.();
15 | private var _offset:uint;
16 |
17 | public function MovieFragmentBox(offset:uint, size:uint) {
18 | super(offset, size);
19 | _offset = offset;
20 | }
21 |
22 | public function get trafs():Vector. {
23 | return _trafs;
24 | }
25 |
26 | public function get offset():uint {
27 | return _offset;
28 | }
29 |
30 | override protected function parseChildBox(type:String, offset:uint, size:uint, ba:ByteArray):Boolean {
31 | if (type == "traf") {
32 | parseTrackFragmentBox(offset, size, ba);
33 | return true;
34 | }
35 |
36 | return false;
37 | }
38 |
39 | private function parseTrackFragmentBox(offset:uint, size:uint, ba:ByteArray):void {
40 | var traf:TrackFragmentBox = new TrackFragmentBox(offset, size);
41 | traf.parse(ba);
42 | _trafs.push(traf);
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/Muxer.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 |
11 | import flash.utils.ByteArray;
12 |
13 | public class Muxer {
14 | private var _duration:uint;
15 |
16 | public function Muxer() {
17 | }
18 | public function get duration():uint {
19 | return _duration;
20 | }
21 |
22 | public function mux(messages:Vector.):ByteArray {
23 | var ba:ByteArray = new ByteArray();
24 | _duration = 0;
25 | while (messages.length > 0) {
26 | var message:FLVTag = messages.shift();
27 | writeMsg(message, ba);
28 | _duration += message.duration;
29 | }
30 |
31 | return ba;
32 | }
33 |
34 | private function writeMsg(message:FLVTag, ba:ByteArray):void {
35 | var messageSize:uint = calculateSize(message);
36 |
37 | writeType(message, ba);
38 | writeSize(messageSize, ba);
39 | writeTimestamp(message, ba);
40 | writeStreamId(message, ba);
41 | writeHeader(message, ba);
42 | writeData(message, ba);
43 |
44 | // write previous tag size
45 | ba.writeUnsignedInt(messageSize + 11); // 4 bytes
46 | }
47 |
48 | private function calculateSize(message:FLVTag):uint {
49 | var size:uint = message.length;
50 |
51 | if (message.isVideo()) {
52 | size += 5;
53 | } else if (message.isAudio()) {
54 | size += 2;
55 | }
56 |
57 | return size;
58 | }
59 |
60 | private function writeType(message:FLVTag, ba:ByteArray):void {
61 | ba.writeByte(message.type);
62 | }
63 |
64 | private function writeData(message:FLVTag, ba:ByteArray):void {
65 | if (message.data != null) {
66 | ba.writeBytes(message.data);
67 | }
68 | }
69 |
70 | private function writeHeader(message:FLVTag, ba:ByteArray):void {
71 | if (message.isVideo()) {
72 | writeVideoHeader(message, ba);
73 | writeCompositionTimestamp(message, ba);
74 | }
75 |
76 | if (message.isAudio()) {
77 | writeAudioHeader(message, ba);
78 | }
79 | }
80 |
81 | private function writeStreamId(message:FLVTag, ba:ByteArray):void {
82 | writeNumber(0, ba); // always the same ID
83 | }
84 |
85 | private function writeTimestamp(message:FLVTag, ba:ByteArray):void {
86 | var timestamp:Number = Math.round(message.timestamp);
87 | writeNumber(timestamp, ba);
88 | ba.writeByte(0);
89 | }
90 |
91 | private function writeSize(messageSize:uint, ba:ByteArray):void {
92 | writeNumber(messageSize, ba);
93 | }
94 |
95 | private function writeAudioHeader(message:FLVTag, ba:ByteArray):void {
96 | var sampleSize:uint;
97 | if (SampleEntry.sampleSize == 16) { // 16 bit
98 | sampleSize = 1;
99 | } else {
100 | sampleSize = 0;
101 | }
102 |
103 | var channelCount:uint;
104 | if (SampleEntry.channelCount == 2) { // stereo
105 | channelCount = 1;
106 | } else {
107 | channelCount = 0;
108 | }
109 |
110 | ba.writeByte((10 << 4) + (3 << 2) + (sampleSize << 1) + channelCount);
111 |
112 | if (message.setup) {
113 | ba.writeByte(0);
114 | } else {
115 | ba.writeByte(1);
116 | }
117 | }
118 |
119 | private function writeVideoHeader(message:FLVTag, ba:ByteArray):void {
120 | switch (message.frameType) {
121 | case FLVTag.I_FRAME:
122 | ba.writeByte(0x17);
123 | ba.writeByte(1);
124 | break;
125 | case FLVTag.P_FRAME:
126 | ba.writeByte(0x27);
127 | ba.writeByte(1);
128 | break;
129 | case FLVTag.B_FRAME:
130 | ba.writeByte(0x37);
131 | ba.writeByte(1);
132 | break;
133 | default:
134 | ba.writeByte(0x17);
135 | ba.writeByte(0);
136 | }
137 | }
138 |
139 | private function writeCompositionTimestamp(message:FLVTag, ba:ByteArray):void {
140 | writeNumber(message.compositionTimestamp, ba);
141 | }
142 |
143 | private function writeNumber(number:int, ba:ByteArray):void {
144 | ba.writeByte(number >> 16);
145 | ba.writeByte(number >> 8);
146 | ba.writeByte(number);
147 | }
148 | }
149 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/NalUnit.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 | import flash.utils.ByteArray;
11 |
12 | public class NalUnit {
13 | private static const HEADER:uint = 1;
14 |
15 | public function NalUnit() {
16 | }
17 |
18 | public function parse(ba:ByteArray):uint {
19 | ba.position = 0;
20 |
21 | var pPresent:Boolean = false;
22 | var bPresent:Boolean = false;
23 | var iPresent:Boolean = false;
24 |
25 | while (ba.bytesAvailable) {
26 | var nalUnitLength:uint = ba.readUnsignedInt();
27 | var nalUnitHeader:uint = ba.readUnsignedByte();
28 | var nalUnitType:uint = nalUnitHeader & 0x1f;
29 |
30 | if ((nalUnitHeader & 0x80) != 0x0) {
31 | return FLVTag.UNKNOWN;
32 | }
33 |
34 | if (nalUnitType == 0x5) {
35 | return FLVTag.I_FRAME;
36 | }
37 |
38 | if (nalUnitType == 0x1) {
39 | var bits:BitArray = new BitArray(ba);
40 |
41 | // firstMbInSlice
42 | readUnsignedIntegerFromGolombCode(bits);
43 |
44 | var sliceType:uint = readUnsignedIntegerFromGolombCode(bits);
45 |
46 | switch (sliceType) {
47 | case 0:
48 | pPresent = true;
49 | break;
50 | case 1:
51 | bPresent = true;
52 | break;
53 | case 2:
54 | iPresent = true;
55 | break;
56 | case 5:
57 | return FLVTag.P_FRAME;
58 | case 6:
59 | return FLVTag.B_FRAME;
60 | case 7:
61 | return FLVTag.I_FRAME;
62 | case 8:
63 | return FLVTag.UNKNOWN;
64 | case 9:
65 | return FLVTag.UNKNOWN;
66 | }
67 | }
68 |
69 | ba.position += nalUnitLength - HEADER;
70 | }
71 |
72 | if (bPresent) {
73 | return FLVTag.B_FRAME;
74 | }
75 |
76 | if (pPresent) {
77 | return FLVTag.P_FRAME;
78 | }
79 |
80 | if (iPresent) {
81 | return FLVTag.I_FRAME;
82 | }
83 |
84 | return FLVTag.UNKNOWN;
85 | }
86 |
87 | private function readUnsignedIntegerFromGolombCode(ba:BitArray):uint {
88 | var leadingZeroBits:uint = 0;
89 |
90 | // count number of zeros
91 | while (ba.readBit() == 0) {
92 | leadingZeroBits++;
93 | }
94 |
95 | // code = 2^(leadingZeroBits) – 1
96 | var code:uint = (1 << leadingZeroBits) - 1;
97 |
98 | // code += read_bits(leadingZeroBits)
99 | for (var i:int = (leadingZeroBits - 1); i >= 0; i--) {
100 | code += ba.readBit() << i;
101 | }
102 |
103 | return code;
104 | }
105 | }
106 | }
107 |
108 | import flash.utils.ByteArray;
109 |
110 | class BitArray {
111 | private var _ba:ByteArray;
112 | private var _offset:uint;
113 |
114 | public function BitArray(ba:ByteArray) {
115 | _ba = ba;
116 | _offset = ba.position * 8;
117 | }
118 |
119 | public function readBit():uint {
120 | var byte:uint = _ba[(_offset >> 0x3)];
121 | var byteOffset:uint = 0x7 - (_offset & 0x7);
122 |
123 | _offset++;
124 |
125 | return (byte >> byteOffset) & 0x1;
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/SampleDescriptionBox.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 |
11 | import flash.utils.ByteArray;
12 |
13 | public class SampleDescriptionBox extends FullBox {
14 | private var _sampleEntries:Vector. = new Vector.();
15 |
16 | public function SampleDescriptionBox(offset:uint, size:uint) {
17 | super(offset, size);
18 | }
19 |
20 | public function get sampleEntries():Vector. {
21 | return _sampleEntries;
22 | }
23 |
24 | override protected function parseBox(ba:ByteArray):void {
25 | var sampleEntriesLength:uint = ba.readUnsignedInt();
26 |
27 | for (var i:uint = 0; i < sampleEntriesLength; i++) {
28 | var offset:uint = ba.position;
29 | var size:uint = ba.readUnsignedInt();
30 | var type:String = ba.readUTFBytes(4);
31 |
32 | parseSampleEntry(offset, size, type, ba);
33 | }
34 | }
35 |
36 | private function parseSampleEntry(offset:uint, size:uint, type:String, ba:ByteArray):void {
37 | var sampleEntry:SampleEntry = new SampleEntry(offset, size, type);
38 | sampleEntry.parse(ba);
39 | _sampleEntries.push(sampleEntry);
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/SampleEntry.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 |
11 | import com.dash.utils.Console;
12 |
13 | import flash.utils.ByteArray;
14 |
15 | public class SampleEntry extends Box {
16 | public static var channelCount:uint;
17 | public static var sampleSize:uint;
18 |
19 | private var _data:ByteArray;
20 | private var _type:String;
21 |
22 | public function SampleEntry(offset:uint, size:uint, type:String) {
23 | super(offset, size);
24 | _type = type;
25 | }
26 |
27 | public function get data():ByteArray {
28 | return _data;
29 | }
30 |
31 | public override function parse(ba:ByteArray):void {
32 | if (_type == "avc1") {
33 | parseAvc1(ba);
34 | }
35 |
36 | if (_type == "mp4a") {
37 | parseMp4a(ba);
38 | }
39 |
40 | ba.position = end;
41 | }
42 |
43 | private function parseAvc1(ba:ByteArray):void {
44 |
45 | // skip
46 | ba.position += 78;
47 |
48 | parseAvc1Data(ba);
49 | }
50 |
51 | private function parseMp4a(ba:ByteArray):void {
52 |
53 | // skip
54 | ba.position += 16;
55 |
56 | channelCount = ba.readUnsignedShort();
57 | sampleSize = ba.readUnsignedShort();
58 |
59 | // skip
60 | ba.position += 8;
61 |
62 | _data = parseMp4aData(ba);
63 | }
64 |
65 | private function parseAvc1Data(ba:ByteArray):void {
66 | ba.position = goToBox("avcC", ba);
67 |
68 | var size:Number = ba.readUnsignedInt();
69 |
70 | // skip: type("avcC")
71 | ba.position += 4;
72 |
73 | _data = new ByteArray();
74 | ba.readBytes(_data, 0, size - SIZE_AND_TYPE);
75 | }
76 |
77 | private function goToBox(type:String, ba:ByteArray):uint {
78 | var typeBegin:String = type.slice(0, 1);
79 | var typeOther:String = type.slice(1);
80 |
81 | while (ba.bytesAvailable) {
82 | if (ba.readUTFBytes(typeBegin.length) != typeBegin) {
83 | continue;
84 | }
85 |
86 | if (ba.readUTFBytes(typeOther.length) == typeOther) {
87 | return ba.position - SIZE_AND_TYPE;
88 | }
89 | }
90 |
91 | throw Console.getInstance().logError(new Error("Couldn't find any '" + type + "' box"));
92 | }
93 |
94 | private function parseMp4aData(ba:ByteArray):ByteArray {
95 |
96 | // // 4-bytes size
97 | // ba.position += 4;
98 | // // 4-bytes type
99 | // ba.position += 4;
100 | // // 4-bytes version/flags
101 | // ba.position += 4;
102 | // // 1-byte type (0x03)
103 | // ba.position += 1;
104 |
105 | ba.position += 13;
106 |
107 | // 3-bytes header (optional) and 1-byte size
108 | getDescriptorSize(ba);
109 |
110 | // // 2-bytes ID
111 | // ba.position += 2;
112 | // // 1-byte priority
113 | // ba.position += 1;
114 | // // 1-byte type (0x04)
115 | // ba.position += 1;
116 |
117 | ba.position += 4;
118 |
119 | // 3-bytes header (optional) and 1-byte size
120 | getDescriptorSize(ba);
121 |
122 | // // 1-byte ID
123 | // ba.position += 1;
124 | // // 1-byte type/flags
125 | // ba.position += 1;
126 | // // 3-bytes buffer size
127 | // ba.position += 3;
128 | // // 4-bytes maximum bit rate
129 | // ba.position += 4;
130 | // // 4-bytes average bit rate
131 | // ba.position += 4;
132 | // // 1-byte type (0x05)
133 | // ba.position += 1;
134 |
135 | ba.position += 14;
136 |
137 | var sdf:ByteArray = new ByteArray();
138 | ba.readBytes(sdf, 0, getDescriptorSize(ba));
139 |
140 | return sdf;
141 | }
142 |
143 | private function getDescriptorSize(ba:ByteArray):uint {
144 | var headerOrSize:uint = ba.readUnsignedByte();
145 |
146 | if (headerOrSize == 0x80) {
147 |
148 | // 2-bytes header
149 | ba.position += 2;
150 |
151 | // size
152 | return ba.readUnsignedByte();
153 | }
154 |
155 | // size
156 | return headerOrSize;
157 | }
158 | }
159 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/SampleTableBox.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 | import flash.utils.ByteArray;
11 |
12 | public class SampleTableBox extends Box {
13 | private var _stsd:SampleDescriptionBox;
14 |
15 | public function SampleTableBox(offset:uint, size:uint) {
16 | super(offset, size);
17 | }
18 |
19 | public function get stsd():SampleDescriptionBox {
20 | return _stsd;
21 | }
22 |
23 | override protected function parseChildBox(type:String, offset:uint, size:uint, ba:ByteArray):Boolean {
24 | if (type == "stsd") {
25 | parseSampleDescriptionBox(offset, size, ba);
26 | return true;
27 | }
28 |
29 | return false;
30 | }
31 |
32 | private function parseSampleDescriptionBox(offset:uint, size:uint, ba:ByteArray):void {
33 | _stsd = new SampleDescriptionBox(offset, size);
34 | _stsd.parse(ba);
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/TrackBox.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 |
11 | import flash.utils.ByteArray;
12 |
13 | public class TrackBox extends Box {
14 | private var _tkhd:TrackHeaderBox;
15 | private var _mdia:MediaBox;
16 |
17 | public function TrackBox(offset:uint, size:uint) {
18 | super(offset, size);
19 | }
20 |
21 | public function get tkhd():TrackHeaderBox {
22 | return _tkhd;
23 | }
24 |
25 | public function get mdia():MediaBox {
26 | return _mdia;
27 | }
28 |
29 | override protected function parseChildBox(type:String, offset:uint, size:uint, ba:ByteArray):Boolean {
30 | if (type == "tkhd") {
31 | parseTrackHeaderBox(offset, size, ba);
32 | return true;
33 | }
34 |
35 | if (type == "mdia") {
36 | parseMediaBox(offset, size, ba);
37 | return true;
38 | }
39 |
40 | return false;
41 | }
42 |
43 | private function parseTrackHeaderBox(offset:uint, size:uint, ba:ByteArray):void {
44 | _tkhd = new TrackHeaderBox(offset, size);
45 | _tkhd.parse(ba);
46 | }
47 |
48 | private function parseMediaBox(offset:uint, size:uint, ba:ByteArray):void {
49 | _mdia = new MediaBox(offset, size);
50 | _mdia.parse(ba);
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/TrackExtendsBox.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 | import flash.utils.ByteArray;
11 |
12 | public class TrackExtendsBox extends FullBox {
13 | private var _trackId:uint;
14 | private var _defaultSampleDuration:uint;
15 |
16 | public function TrackExtendsBox(offset:uint, size:uint) {
17 | super(offset, size);
18 | }
19 |
20 | public function get trackId():uint {
21 | return _trackId;
22 | }
23 |
24 | public function get defaultSampleDuration():uint {
25 | return _defaultSampleDuration;
26 | }
27 |
28 | override protected function parseBox(ba:ByteArray):void {
29 |
30 | // track ID
31 | _trackId = ba.readUnsignedInt();
32 |
33 | // // default sample description index
34 | // ba.readUnsignedInt(); // 4 bytes
35 |
36 | // skip
37 | ba.position += 4;
38 |
39 | _defaultSampleDuration = ba.readUnsignedInt();
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/TrackFragmentBox.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 |
11 | import flash.utils.ByteArray;
12 |
13 | public class TrackFragmentBox extends Box {
14 | private var _truns:Vector. = new Vector.();
15 | private var _tfhd:TrackFragmentHeaderBox;
16 |
17 | public function TrackFragmentBox(offset:uint, size:uint) {
18 | super(offset, size);
19 | }
20 |
21 | public function get truns():Vector. {
22 | return _truns;
23 | }
24 |
25 | public function get tfhd():TrackFragmentHeaderBox {
26 | return _tfhd;
27 | }
28 |
29 | override protected function parseChildBox(type:String, offset:uint, size:uint, ba:ByteArray):Boolean {
30 | if (type == "tfhd") {
31 | parseTrackFragmentHeaderBox(offset, size, ba);
32 | return true;
33 | }
34 |
35 | if (type == "trun") {
36 | parseTrackFragmentRunBox(offset, size, ba);
37 | return true;
38 | }
39 |
40 | return false;
41 | }
42 |
43 | private function parseTrackFragmentRunBox(offset:uint, size:uint, ba:ByteArray):void {
44 | var trun:TrackFragmentRunBox = new TrackFragmentRunBox(offset, size);
45 | trun.parse(ba);
46 | _truns.push(trun);
47 | }
48 |
49 | private function parseTrackFragmentHeaderBox(offset:uint, size:uint, ba:ByteArray):void {
50 | _tfhd = new TrackFragmentHeaderBox(offset, size);
51 | _tfhd.parse(ba);
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/TrackFragmentHeaderBox.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 |
11 | import com.dash.utils.Bytes;
12 |
13 | import flash.utils.ByteArray;
14 |
15 | public class TrackFragmentHeaderBox extends FullBox {
16 | private var _baseDataOffsetPresent:Boolean = false;
17 | private var _baseDataOffset:Number;
18 | private var _defaultSampleDurationPresent:Boolean = false;
19 | private var _defaultSampleDuration:uint;
20 |
21 | public function TrackFragmentHeaderBox(offset:uint, size:uint) {
22 | super(offset, size);
23 | }
24 |
25 | public function get defaultSampleDurationPresent():Boolean {
26 | return _defaultSampleDurationPresent;
27 | }
28 |
29 | public function get baseDataOffsetPresent():Boolean {
30 | return _baseDataOffsetPresent;
31 | }
32 |
33 | public function get defaultSampleDuration():uint {
34 | return _defaultSampleDuration;
35 | }
36 |
37 | public function get baseDataOffset():Number {
38 | return _baseDataOffset;
39 | }
40 |
41 | override protected function parseBox(ba:ByteArray):void {
42 | if ((flags & 0x1) == 0x1) {
43 | _baseDataOffsetPresent = true;
44 | }
45 |
46 | var sampleDescriptionIndexPresent:Boolean = false;
47 | if ((flags & 0x2) == 0x2) {
48 | sampleDescriptionIndexPresent = true;
49 | }
50 |
51 | if ((flags & 0x8) == 0x8) {
52 | _defaultSampleDurationPresent = true;
53 | }
54 |
55 | // trafId
56 | Bytes.readNumber(ba);
57 |
58 | if (_baseDataOffsetPresent) {
59 | _baseDataOffset = Bytes.readNumber(ba, 8);
60 | }
61 |
62 | Bytes.skipNumberIfNeeded(sampleDescriptionIndexPresent, ba);
63 |
64 | if (_defaultSampleDurationPresent) {
65 | _defaultSampleDuration = Bytes.readNumber(ba);
66 | }
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/TrackFragmentRunBox.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 | import com.dash.utils.Bytes;
11 |
12 | import flash.utils.ByteArray;
13 |
14 | public class TrackFragmentRunBox extends FullBox {
15 | private var _sampleDurationPresent:Boolean = false;
16 | private var _sampleDuration:Vector. = new Vector.();
17 | private var _sampleDependsOn:Vector. = new Vector.();
18 | private var _sampleIsDependedOn:Vector. = new Vector.();
19 | private var _sampleSize:Vector. = new Vector.();
20 | private var _sampleCompositionTimeOffset:Vector. = new Vector.();
21 | private var _dataOffset:int;
22 |
23 | public function TrackFragmentRunBox(offset:uint, size:uint) {
24 | super(offset, size);
25 | }
26 |
27 | public function get dataOffset():int {
28 | return _dataOffset;
29 | }
30 |
31 | public function get sampleDurationPresent():Boolean {
32 | return _sampleDurationPresent;
33 | }
34 |
35 | public function get sampleCompositionTimeOffset():Vector. {
36 | return _sampleCompositionTimeOffset;
37 | }
38 |
39 | public function get sampleSize():Vector. {
40 | return _sampleSize;
41 | }
42 |
43 | public function get sampleDuration():Vector. {
44 | return _sampleDuration;
45 | }
46 |
47 | public function get sampleDependsOn():Vector. {
48 | return _sampleDependsOn;
49 | }
50 |
51 | public function get sampleIsDependedOn():Vector. {
52 | return _sampleIsDependedOn;
53 | }
54 |
55 | override protected function parseBox(ba:ByteArray):void {
56 | var dataOffsetPresent:Boolean = false;
57 | if ((flags & 0x1) == 0x1) {
58 | dataOffsetPresent = true;
59 | }
60 |
61 | var firstSampleFlagsPresent:Boolean = false;
62 | if ((flags & 0x4) == 0x4) {
63 | firstSampleFlagsPresent = true;
64 | }
65 |
66 | if ((flags & 0x100) == 0x100) {
67 | _sampleDurationPresent = true;
68 | }
69 |
70 | var sampleSizePresent:Boolean = false;
71 | if ((flags & 0x200) == 0x200) {
72 | sampleSizePresent = true;
73 | }
74 |
75 | var secondSampleFlagsPresent:Boolean = false;
76 | if ((flags & 0x400) == 0x400) {
77 | secondSampleFlagsPresent = true;
78 | }
79 |
80 | var sampleCompositionTimeOffsetsPresent:Boolean = false;
81 | if ((flags & 0x800) == 0x800) {
82 | sampleCompositionTimeOffsetsPresent = true;
83 | }
84 |
85 | var sampleCount:uint = Bytes.readNumber(ba);
86 |
87 | parseDataOffsetIfNeeded(dataOffsetPresent, ba);
88 | Bytes.skipNumberIfNeeded(firstSampleFlagsPresent, ba);
89 |
90 | for (var i:uint = 0; i < sampleCount; i++) {
91 | parseSampleDurationIfNeeded(i, ba);
92 | parseSampleSizeIfNeeded(sampleSizePresent, i, ba);
93 | parseSampleFlagsIfNeeded(secondSampleFlagsPresent, i, ba);
94 | parseSampleCompositionTimeOffsetsIfNeeded(sampleCompositionTimeOffsetsPresent, i, ba);
95 | }
96 | }
97 |
98 | private function parseDataOffsetIfNeeded(present:Boolean, ba:ByteArray):void {
99 | if (present) {
100 | _dataOffset = Bytes.readNumber(ba);
101 | }
102 | }
103 |
104 | private function parseSampleCompositionTimeOffsetsIfNeeded(present:Boolean, i:uint, ba:ByteArray):void {
105 | if (present) {
106 | if (version == 0) {
107 | parseSampleCompositionTimeOffsetsVersion0(i, ba);
108 | }
109 |
110 | if (version == 1) {
111 | parseSampleCompositionTimeOffsetsVersion1(i, ba);
112 | }
113 | }
114 | }
115 |
116 | private function parseSampleCompositionTimeOffsetsVersion1(i:uint, ba:ByteArray):void {
117 | var cts:uint = Bytes.readNumber(ba);
118 |
119 | if (((cts >> 31) & 0x1) == 1) {
120 | _sampleCompositionTimeOffset[i] = cts - 0xffffffff;
121 | } else {
122 | _sampleCompositionTimeOffset[i] = cts;
123 | }
124 | }
125 |
126 | private function parseSampleCompositionTimeOffsetsVersion0(i:uint, ba:ByteArray):void {
127 | _sampleCompositionTimeOffset[i] = Bytes.readNumber(ba);
128 | }
129 |
130 | private function parseSampleSizeIfNeeded(present:Boolean, i:uint, ba:ByteArray):void {
131 | if (present) {
132 | _sampleSize[i] = Bytes.readNumber(ba);
133 | }
134 | }
135 |
136 | private function parseSampleDurationIfNeeded(i:uint, ba:ByteArray):void {
137 | if (_sampleDurationPresent) {
138 | _sampleDuration[i] = Bytes.readNumber(ba);
139 | }
140 | }
141 |
142 | private function parseSampleFlagsIfNeeded(present:Boolean, i:uint, ba:ByteArray):void {
143 | if (present) {
144 | var sampleFlags:uint = ba.readUnsignedInt();
145 | _sampleDependsOn[i] = (sampleFlags >> 24) & 0x03;
146 | _sampleIsDependedOn[i] = (sampleFlags >> 22) & 0x03;
147 | }
148 | }
149 | }
150 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/boxes/TrackHeaderBox.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.boxes {
10 | import com.dash.utils.Console;
11 |
12 | import flash.utils.ByteArray;
13 |
14 | public class TrackHeaderBox extends FullBox {
15 | private var _id:uint;
16 |
17 | public function TrackHeaderBox(offset:uint, size:uint) {
18 | super(offset, size);
19 | }
20 |
21 | public function get id():uint {
22 | return _id;
23 | }
24 |
25 | override protected function parseBox(ba:ByteArray):void {
26 | if (version == 0) {
27 |
28 | // // created mac UTC date
29 | // ba.position += 4;
30 | // // modified mac UTC date
31 | // ba.position += 4;
32 |
33 | ba.position += 8;
34 | } else if (version == 1) {
35 |
36 | // // created mac UTC date
37 | // ba.position += 8;
38 | // // modified mac UTC date
39 | // ba.position += 8;
40 |
41 | ba.position += 16;
42 | } else {
43 | throw Console.getInstance().logError(new Error("Unknown TrackHeaderBox version"));
44 | }
45 |
46 | _id = ba.readUnsignedInt();
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/as3/com/dash/events/MessageEvent.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.events {
10 |
11 | import flash.events.Event;
12 |
13 | public class MessageEvent extends Event {
14 | public static const ADDED:String = "messageAdded";
15 |
16 | private var _message:String;
17 |
18 | public function MessageEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false,
19 | message:String='') {
20 | super(type, bubbles, cancelable);
21 |
22 | _message = message;
23 | }
24 |
25 | public function get message():String {
26 | return _message;
27 | }
28 |
29 | }
30 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/handlers/AudioSegmentHandler.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.handlers {
10 | import com.dash.boxes.FLVTag;
11 | import com.dash.boxes.Muxer;
12 |
13 | import flash.utils.ByteArray;
14 |
15 | public class AudioSegmentHandler extends MediaSegmentHandler {
16 | public function AudioSegmentHandler(segment:ByteArray, messages:Vector.,
17 | defaultSampleDuration:uint, timescale:uint, timestamp:Number, mixer:Muxer) {
18 | super(segment, messages, defaultSampleDuration, timescale, timestamp, mixer);
19 | }
20 |
21 | protected override function buildMessage(sampleDuration:uint, sampleSize:uint, sampleDependsOn:uint,
22 | sampleIsDependedOn:uint, compositionTimeOffset:Number,
23 | dataOffset:uint, ba:ByteArray):FLVTag {
24 | var message:FLVTag = new FLVTag();
25 |
26 | message.markAsAudio();
27 |
28 | message.timestamp = _timestamp;
29 | _timestamp = message.timestamp + sampleDuration * 1000 / _timescale;
30 |
31 | message.duration = sampleDuration * 1000 * 1000 / _timescale; //sampleDuration / _timescale;// * 1000
32 |
33 | message.length = sampleSize;
34 |
35 | message.dataOffset = dataOffset;
36 |
37 | message.data = new ByteArray();
38 | ba.position = message.dataOffset;
39 | ba.readBytes(message.data, 0, sampleSize);
40 |
41 | return message;
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/src/as3/com/dash/handlers/IndexSegmentHandler.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 castLabs GmbH
3 | *
4 | * This Source Code Form is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | */
8 |
9 | package com.dash.handlers {
10 |
11 | import com.dash.utils.Bytes;
12 | import com.dash.utils.Console;
13 |
14 | import flash.utils.ByteArray;
15 |
16 | public class IndexSegmentHandler {
17 | public static const SEGMENT_INDEX_BOX_TYPE:String = "sidx";
18 |
19 | private var _references:Vector.