diff --git a/.eslintrc b/.eslintrc
index 881e9039..3d8418e4 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -66,11 +66,13 @@
"arrayMin": true,
"TURN_URL": true,
"Ssim": true,
+ "VideoFrameChecker": true,
"StatisticsAggregate": true,
"API_KEY": true,
"doGetUserMedia": true,
"Call": true,
"setTimeoutWithProgressBar": true,
"ga": true,
+ "module": true,
}
}
diff --git a/index.js b/index.js
new file mode 100644
index 00000000..669ebbaa
--- /dev/null
+++ b/index.js
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
+ */
+
+/* expose VideoFrameChecker and Ssim as modules without exposing the internal
+ * structure of the source code.
+ */
+'use strict';
+module.exports = {
+ Ssim: require('./src/js/ssim'),
+ VideoFrameChecker: require('./src/js/videoframechecker')
+};
diff --git a/src/index.html b/src/index.html
index 94802339..57aa409e 100644
--- a/src/index.html
+++ b/src/index.html
@@ -51,6 +51,7 @@
+
diff --git a/src/js/camresolutionstest.js b/src/js/camresolutionstest.js
index 6cbe6f62..f6395be9 100644
--- a/src/js/camresolutionstest.js
+++ b/src/js/camresolutionstest.js
@@ -289,79 +289,3 @@ CamResolutionsTest.prototype = {
}
};
-// TODO: Move this to a separate file.
-function VideoFrameChecker(videoElement) {
- this.frameStats = {
- numFrozenFrames: 0,
- numBlackFrames: 0,
- numFrames: 0
- };
-
- this.running_ = true;
-
- this.nonBlackPixelLumaThreshold = 20;
- this.previousFrame_ = [];
- this.identicalFrameSsimThreshold = 0.985;
- this.frameComparator = new Ssim();
-
- this.canvas_ = document.createElement('canvas');
- this.videoElement_ = videoElement;
- this.listener_ = this.checkVideoFrame_.bind(this);
- this.videoElement_.addEventListener('play', this.listener_, false);
-}
-
-VideoFrameChecker.prototype = {
- stop: function() {
- this.videoElement_.removeEventListener('play' , this.listener_);
- this.running_ = false;
- },
-
- getCurrentImageData_: function() {
- this.canvas_.width = this.videoElement_.width;
- this.canvas_.height = this.videoElement_.height;
-
- var context = this.canvas_.getContext('2d');
- context.drawImage(this.videoElement_, 0, 0, this.canvas_.width,
- this.canvas_.height);
- return context.getImageData(0, 0, this.canvas_.width, this.canvas_.height);
- },
-
- checkVideoFrame_: function() {
- if (!this.running_) {
- return;
- }
- if (this.videoElement_.ended) {
- return;
- }
-
- var imageData = this.getCurrentImageData_();
-
- if (this.isBlackFrame_(imageData.data, imageData.data.length)) {
- this.frameStats.numBlackFrames++;
- }
-
- if (this.frameComparator.calculate(this.previousFrame_, imageData.data) >
- this.identicalFrameSsimThreshold) {
- this.frameStats.numFrozenFrames++;
- }
- this.previousFrame_ = imageData.data;
-
- this.frameStats.numFrames++;
- setTimeout(this.checkVideoFrame_.bind(this), 20);
- },
-
- isBlackFrame_: function(data, length) {
- // TODO: Use a statistical, histogram-based detection.
- var thresh = this.nonBlackPixelLumaThreshold;
- var accuLuma = 0;
- for (var i = 4; i < length; i += 4) {
- // Use Luma as in Rec. 709: Y′709 = 0.21R + 0.72G + 0.07B;
- accuLuma += 0.21 * data[i] + 0.72 * data[i + 1] + 0.07 * data[i + 2];
- // Early termination if the average Luma so far is bright enough.
- if (accuLuma > (thresh * i / 4)) {
- return false;
- }
- }
- return true;
- }
-};
diff --git a/src/js/ssim.js b/src/js/ssim.js
index 6ee33d4b..34c1291d 100644
--- a/src/js/ssim.js
+++ b/src/js/ssim.js
@@ -87,3 +87,7 @@ Ssim.prototype = {
return luminance * contrast * structure;
}
};
+
+if (typeof exports === 'object') {
+ module.exports = Ssim;
+}
diff --git a/src/js/videoframechecker.js b/src/js/videoframechecker.js
new file mode 100644
index 00000000..1756e4aa
--- /dev/null
+++ b/src/js/videoframechecker.js
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree.
+ */
+
+/* More information about these options at jshint.com/docs/options */
+'use strict';
+function VideoFrameChecker(videoElement) {
+ this.frameStats = {
+ numFrozenFrames: 0,
+ numBlackFrames: 0,
+ numFrames: 0
+ };
+
+ this.running_ = true;
+
+ this.nonBlackPixelLumaThreshold = 20;
+ this.previousFrame_ = [];
+ this.identicalFrameSsimThreshold = 0.985;
+ this.frameComparator = new Ssim();
+
+ this.canvas_ = document.createElement('canvas');
+ this.videoElement_ = videoElement;
+ this.listener_ = this.checkVideoFrame_.bind(this);
+ this.videoElement_.addEventListener('play', this.listener_, false);
+}
+
+VideoFrameChecker.prototype = {
+ stop: function() {
+ this.videoElement_.removeEventListener('play' , this.listener_);
+ this.running_ = false;
+ },
+
+ getCurrentImageData_: function() {
+ this.canvas_.width = this.videoElement_.width;
+ this.canvas_.height = this.videoElement_.height;
+
+ var context = this.canvas_.getContext('2d');
+ context.drawImage(this.videoElement_, 0, 0, this.canvas_.width,
+ this.canvas_.height);
+ return context.getImageData(0, 0, this.canvas_.width, this.canvas_.height);
+ },
+
+ checkVideoFrame_: function() {
+ if (!this.running_) {
+ return;
+ }
+ if (this.videoElement_.ended) {
+ return;
+ }
+
+ var imageData = this.getCurrentImageData_();
+
+ if (this.isBlackFrame_(imageData.data, imageData.data.length)) {
+ this.frameStats.numBlackFrames++;
+ }
+
+ if (this.frameComparator.calculate(this.previousFrame_, imageData.data) >
+ this.identicalFrameSsimThreshold) {
+ this.frameStats.numFrozenFrames++;
+ }
+ this.previousFrame_ = imageData.data;
+
+ this.frameStats.numFrames++;
+ setTimeout(this.checkVideoFrame_.bind(this), 20);
+ },
+
+ isBlackFrame_: function(data, length) {
+ // TODO: Use a statistical, histogram-based detection.
+ var thresh = this.nonBlackPixelLumaThreshold;
+ var accuLuma = 0;
+ for (var i = 4; i < length; i += 4) {
+ // Use Luma as in Rec. 709: Y′709 = 0.21R + 0.72G + 0.07B;
+ accuLuma += 0.21 * data[i] + 0.72 * data[i + 1] + 0.07 * data[i + 2];
+ // Early termination if the average Luma so far is bright enough.
+ if (accuLuma > (thresh * i / 4)) {
+ return false;
+ }
+ }
+ return true;
+ }
+};
+
+if (typeof exports === 'object') {
+ module.exports = VideoFrameChecker;
+}