Skip to content
This repository was archived by the owner on May 13, 2024. It is now read-only.

move videoframechecker to separate file and export as module #239

Merged
merged 1 commit into from
Sep 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
16 changes: 16 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -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')
};
1 change: 1 addition & 0 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
<script src="js/call.js"></script>
<script src="js/stats.js"></script>
<script src="js/ssim.js"></script>
<script src="js/videoframechecker.js"></script>
<script src="js/util.js"></script>
<script src="js/testcasename.js"></script>
<script src="js/testsuitename.js"></script>
Expand Down
76 changes: 0 additions & 76 deletions src/js/camresolutionstest.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
};
4 changes: 4 additions & 0 deletions src/js/ssim.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,7 @@ Ssim.prototype = {
return luminance * contrast * structure;
}
};

if (typeof exports === 'object') {
module.exports = Ssim;
}
89 changes: 89 additions & 0 deletions src/js/videoframechecker.js
Original file line number Diff line number Diff line change
@@ -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;
}