UNPKG

2.54 kBJavaScriptView Raw
1/*
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree.
7 */
8'use strict';
9
10/* eslint-env node */
11/* eslint-env browser */
12var Ssim = require('./ssim');
13
14function VideoFrameChecker(videoElement) {
15 this.frameStats = {
16 numFrozenFrames: 0,
17 numBlackFrames: 0,
18 numFrames: 0
19 };
20
21 this.running_ = true;
22
23 this.nonBlackPixelLumaThreshold = 20;
24 this.previousFrame_ = [];
25 this.identicalFrameSsimThreshold = 0.985;
26 this.frameComparator = new Ssim();
27
28 this.canvas_ = document.createElement('canvas');
29 this.videoElement_ = videoElement;
30 this.listener_ = this.checkVideoFrame_.bind(this);
31 this.videoElement_.addEventListener('play', this.listener_, false);
32}
33
34VideoFrameChecker.prototype = {
35 stop: function() {
36 this.videoElement_.removeEventListener('play' , this.listener_);
37 this.running_ = false;
38 },
39
40 getCurrentImageData_: function() {
41 this.canvas_.width = this.videoElement_.width;
42 this.canvas_.height = this.videoElement_.height;
43
44 var context = this.canvas_.getContext('2d');
45 context.drawImage(this.videoElement_, 0, 0, this.canvas_.width,
46 this.canvas_.height);
47 return context.getImageData(0, 0, this.canvas_.width, this.canvas_.height);
48 },
49
50 checkVideoFrame_: function() {
51 if (!this.running_) {
52 return;
53 }
54 if (this.videoElement_.ended) {
55 return;
56 }
57
58 var imageData = this.getCurrentImageData_();
59
60 if (this.isBlackFrame_(imageData.data, imageData.data.length)) {
61 this.frameStats.numBlackFrames++;
62 }
63
64 if (this.frameComparator.calculate(this.previousFrame_, imageData.data) >
65 this.identicalFrameSsimThreshold) {
66 this.frameStats.numFrozenFrames++;
67 }
68 this.previousFrame_ = imageData.data;
69
70 this.frameStats.numFrames++;
71 setTimeout(this.checkVideoFrame_.bind(this), 20);
72 },
73
74 isBlackFrame_: function(data, length) {
75 // TODO: Use a statistical, histogram-based detection.
76 var thresh = this.nonBlackPixelLumaThreshold;
77 var accuLuma = 0;
78 for (var i = 4; i < length; i += 4) {
79 // Use Luma as in Rec. 709: Y′709 = 0.21R + 0.72G + 0.07B;
80 accuLuma += 0.21 * data[i] + 0.72 * data[i + 1] + 0.07 * data[i + 2];
81 // Early termination if the average Luma so far is bright enough.
82 if (accuLuma > (thresh * i / 4)) {
83 return false;
84 }
85 }
86 return true;
87 }
88};
89
90module.exports = VideoFrameChecker;