+var SampleData = function() {
+ "use strict";
+ this.maximumSampleSize = 0;
+ this.maxScenes = 0;
+ this.syncSampleSizes = [];
+ this.decisions = [];
+ this.thresholds = [];
+ this.syncSampleTimes = [];
+ this.sceneSamples = [];
+};
+
+SampleData.prototype.decision = function(data, k, n, count) {
+ "use strict";
+ var n_m_1 = (n - 1 >= 0 ? n - 1 : 0);
+ var n_m_2 = (n - 2 >= 0 ? n - 2 : 0);
+ var n_p_1 = (n + 1 < count ? n + 1 : count - 1);
+
+ if (
+ ((
+ (data[n_m_1] - data[n_m_2] > 0) &&
+ (data[n] - data[n_m_1] > 0) &&
+ (data[n_p_1] - data[n] > 0) &&
+ (data[n_p_1] - data[n] >= data[n] - data[n - 1])
+ )
+ ||
+ (
+ (data[n_m_1] - data[n_m_2] < 0) &&
+ (data[n] - data[n_m_1] < 0) &&
+ (data[n_p_1] - data[n] < 0) &&
+ (data[n_p_1] - data[n] <= data[n] - data[n - 1])
+ )))
+ return 0;
+
+ var directionSet = new Array(4);
+ directionSet[0] = Math.abs(data[n] - data[n_m_1]);
+ directionSet[1] = Math.abs(data[n] - data[n_m_2]);
+ directionSet[2] = Math.abs(data[n_p_1] - data[n_m_1]);
+ directionSet[3] = Math.abs(data[n_p_1] - data[n_m_2]);
+
+ return directionSet.sort()[0];
+};
+
+SampleData.prototype.threshold = function(data, distances, k, n, count) {
+ "use strict";
+ var mean = 0;
+ var S = 0;
+ var min, max, min_n1, max_n1;
+ var directionSet = new Array(4);
+
+ min = min_n1 = data[k];
+ max = max_n1 = data[k];
+
+ var n_m_1 = (n >= 1 ? n - 1 : 0);
+ var n_m_2 = (n >= 2 ? n - 2 : 0);
+ var n_p_1 = (n + 1 < count ? n + 1 : count - 1);
+ directionSet[0] = data[n] - data[n_m_1];
+ directionSet[1] = data[n] - data[n_m_2];
+ directionSet[2] = data[n_p_1] - data[n_m_1];
+ directionSet[3] = data[n_p_1] - data[n_m_2];
+
+ // Knuth Variance Algorithm with Min/Max
+ // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Algorithm_III
+ for (var i = k, count = 1; i <= n; ++i, ++count) {
+ var x = data[i];
+ var delta = x - mean;
+ mean += delta / count;
+ S += delta * (x - mean);
+
+ // Caculate min/max and min/max excluding the last entry.
+ if (x > max) max = x;
+ if (x < min) min = x;
+ if (i != n) {
+ if (x > max_n1) max_n1 = x;
+ if (x < max_n1) min_n1 = x;
+ }
+ }
+
+ var distance = Math.sqrt(1 / Math.log(distances[n] - distances[k]));
+ var variance = S / ((n - k) - 1);
+ var stddev = Math.sqrt(variance);
+ var weightedDev = stddev / (max - min);
+ var eta = 0;
+
+ var k_m_1 = (k >= 1 ? k - 1 : 0);
+
+ if (directionSet.sort()[0] > 0) {
+ eta = Math.abs(data[k] - data[k_m_1]);
+ if (max_n1 > data[k]) eta += Math.abs(max_n1 - data[k]);
+ } else {
+ eta = Math.abs(data[k] - data[k_m_1]);
+ if (min_n1 < data[k]) eta += Math.abs(min_n1 - data[k]);
+ }
+
+ return distance * weightedDev * eta;
+};
+
+SampleData.prototype.load = function(file, completion) {
+ "use strict";
+ this.reader = new FileReader();
+ this.file = file;
+ this.completion = completion;
+ this.checkForMoovAtom(0);
+};
+
+SampleData.prototype.checkForMoovAtom = function(offset) {
+ "use strict";
+ this.reader.onload = (function(e) {
+ var result = e.target.result;
+ var basicAtom = new Atom();
+ basicAtom.parse(result);
+
+ if (basicAtom.type == 'moov')
+ this.readMoovAtom(offset, basicAtom.size);
+ else
+ this.checkForMoovAtom(offset + basicAtom.size);
+ }).bind(this);
+ var subset = this.file.slice(offset, offset + 16);
+ this.reader.readAsArrayBuffer(subset);
+};
+
+SampleData.prototype.readMoovAtom = function(offset, length) {
+ "use strict";
+ this.reader.onload = (function(e) {
+ var moovAtom = Atom.create(e.target.result);
+ var mediaAtoms = moovAtom.getAtomsByType('mdia');
+ var mediaAtom = mediaAtoms.find(function(atom){
+ return atom.getAtomByType('hdlr').handlerType == 'vide';
+ });
+ var syncSampleAtom = mediaAtom.getAtomByType('stss');
+ var sampleSizeAtom = syncSampleAtom.parent.getAtomByType('stsz');
+ var mediaHeaderAtom = syncSampleAtom.parent.parent.parent.getAtomByType('mdhd');
+ this.timeScale = mediaHeaderAtom.timeScale;
+ for (var i = 0; i < syncSampleAtom.syncSamples.length; ++i) {
+ var sampleNumber = syncSampleAtom.syncSamples[i];
+ var sampleSize = sampleSizeAtom.sampleSizes[sampleNumber];
+ this.syncSampleSizes.push(sampleSize);
+ if (this.maximumSampleSize < sampleSize)
+ this.maximumSampleSize = sampleSize;
+
+ var sampleTimeAtom = syncSampleAtom.parent.getAtomByType('stts');
+ var sampleSum = 0;
+
+
+ this.syncSampleTimes.push(timeSum);
+ }
+
+ this.sceneSamples.push([0, 0]);
+ for (var i = 1; i < this.syncSampleTimes.length; ++i) {
+ var k = this.sceneSamples[this.sceneSamples.length-1][1];
+ var n = i;
+ var T = this.threshold(this.syncSampleSizes, this.syncSampleTimes, k, n, this.syncSampleSizes.length);
+ var D = this.decision(this.syncSampleSizes, k, n, this.syncSampleSizes.length);
+ this.thresholds.push(isFinite(T) ? T : 0);
+ this.decisions.push(D);
+
+ if (D > T && k + 1 < n) {
+ this.sceneSamples.push([D - T, i]);
+ }
+ }
+
+ this.sceneSamples.sort(function(a, b) {
+ if (a[0] == b[0])
+ return a[1] - b[1]
+ return a[0] - b[0];
+ });
+
+ this.completion();
+
+ }).bind(this);
+ var subset = this.file.slice(offset, offset + length);
+ this.reader.readAsArrayBuffer(subset);
+};