7 background-color: black;
11 <body onload=
"main()">
12 <div id=
"buttons"></div>
16 <td id=
"video_header"></td>
17 <td>Absolute Diff
</td>
18 <td>Different Pixels
</td>
21 <td><img src=
"blackwhite.png"></div>
22 <td><video autoplay
></video></div>
23 <td><canvas id=
"diff"></canvas></td>
24 <td><canvas id=
"mask"></canvas></td>
32 document
.getElementById('result').textContent
= str
;
36 function loadVideo(name
) {
37 var videoElem
= document
.querySelector('video');
38 videoElem
.src
= 'blackwhite_' + name
;
40 document
.getElementById('video_header').textContent
= name
;
41 videoElem
.addEventListener('ended', onVideoEnded
);
44 function onVideoEnded(e
) {
45 document
.title
= verifyVideo() ? 'ENDED' : 'FAILED';
48 function onVideoError(e
) {
49 document
.title
= 'ERROR';
50 document
.getElementById('diff').style
.visibility
= 'hidden';
51 document
.getElementById('mask').style
.visibility
= 'hidden';
52 log('Error playing video: ' + e
.target
.error
.code
+ '.');
56 // Programatically create buttons for each clip for manual testing.
57 var buttonsElem
= document
.getElementById('buttons');
59 function createButton(name
) {
60 var buttonElem
= document
.createElement('button');
61 buttonElem
.textContent
= name
;
62 buttonElem
.addEventListener('click', function() {
65 buttonsElem
.appendChild(buttonElem
);
81 for (var i
= 0; i
< VIDEOS
.length
; ++i
) {
82 createButton(VIDEOS
[i
]);
85 // Video event handlers.
86 var videoElem
= document
.querySelector('video');
87 videoElem
.addEventListener('error', onVideoError
);
89 // Check if a query parameter was provided for automated tests.
90 if (window
.location
.search
.length
> 1) {
91 loadVideo(window
.location
.search
.substr(1));
93 // If we're not an automated test, compute some pretty diffs.
94 document
.querySelector('video').addEventListener('ended',
99 function getCanvasPixels(canvas
) {
101 return canvas
.getContext('2d')
102 .getImageData(0, 0, canvas
.width
, canvas
.height
)
105 var message
= 'ERROR: ' + e
;
106 if (e
.name
== 'SecurityError') {
107 message
+= ' Couldn\'t get image pixels, try running with ' +
108 '--allow-file-access-from-files.';
114 function verifyVideo() {
115 var videoElem
= document
.querySelector('video');
116 var offscreen
= document
.createElement('canvas');
117 offscreen
.width
= videoElem
.videoWidth
;
118 offscreen
.height
= videoElem
.videoHeight
;
119 offscreen
.getContext('2d')
120 .drawImage(videoElem
, 0, 0, offscreen
.width
, offscreen
.height
);
122 videoData
= getCanvasPixels(offscreen
);
126 // Check the color of a givel pixel |x,y| in |imgData| against an
127 // expected value, |expected|, with up to |allowedError| difference.
128 function checkColor(imgData
, x
, y
, stride
, expected
, allowedError
) {
129 for (var i
= 0; i
< 3; ++i
) {
130 if (Math
.abs(imgData
[(x
+ y
* stride
) * 4 + i
] - expected
) >
138 // Check one pixel in each quadrant (in the upper left, away from
139 // boundaries and the text, to avoid compression artifacts).
140 // Also allow a small error, for the same reason.
142 // TODO(mtomasz): Once code.google.com/p/libyuv/issues/detail?id=324 is
143 // fixed, the allowedError should be decreased to 1.
144 var allowedError
= 2;
146 return checkColor(videoData
, 30, 30, videoElem
.videoWidth
, 0xff,
148 checkColor(videoData
, 150, 30, videoElem
.videoWidth
, 0x00,
150 checkColor(videoData
, 30, 150, videoElem
.videoWidth
, 0x10,
152 checkColor(videoData
, 150, 150, videoElem
.videoWidth
, 0xef,
156 // Compute a standard diff image, plus a high-contrast mask that shows
157 // each differing pixel more visibly.
158 function computeDiffs() {
159 var diffElem
= document
.getElementById('diff');
160 var maskElem
= document
.getElementById('mask');
161 var videoElem
= document
.querySelector('video');
162 var imgElem
= document
.querySelector('img');
164 var width
= imgElem
.width
;
165 var height
= imgElem
.height
;
167 if (videoElem
.videoWidth
!= width
|| videoElem
.videoHeight
!= height
) {
168 log('ERROR: video dimensions don\'t match reference image ' +
173 // Make an offscreen canvas to dump reference image pixels into.
174 var offscreen
= document
.createElement('canvas');
175 offscreen
.width
= width
;
176 offscreen
.height
= height
;
178 offscreen
.getContext('2d').drawImage(imgElem
, 0, 0, width
, height
);
179 imgData
= getCanvasPixels(offscreen
);
183 // Scale and clear diff canvases.
184 diffElem
.width
= maskElem
.width
= width
;
185 diffElem
.height
= maskElem
.height
= height
;
186 var diffCtx
= diffElem
.getContext('2d');
187 var maskCtx
= maskElem
.getContext('2d');
188 maskCtx
.clearRect(0, 0, width
, height
);
189 diffCtx
.clearRect(0, 0, width
, height
);
191 // Copy video pixels into diff.
192 diffCtx
.drawImage(videoElem
, 0, 0, width
, height
);
194 var diffIData
= diffCtx
.getImageData(0, 0, width
, height
);
195 var diffData
= diffIData
.data
;
196 var maskIData
= maskCtx
.getImageData(0, 0, width
, height
);
197 var maskData
= maskIData
.data
;
199 // Make diffs and collect stats.
200 var meanSquaredError
= 0;
201 for (var i
= 0; i
< imgData
.length
; i
+= 4) {
203 for (var j
= 0; j
< 3; ++j
) {
204 diffData
[i
+ j
] = Math
.abs(diffData
[i
+ j
] - imgData
[i
+ j
]);
205 meanSquaredError
+= diffData
[i
+ j
] * diffData
[i
+ j
];
206 if (diffData
[i
+ j
] != 0) {
207 difference
+= diffData
[i
+ j
];
210 if (difference
> 0) {
211 if (difference
<= 3) {
212 // If we're only off by a bit per channel or so, use darker red.
215 // Bright red to indicate a different pixel.
222 meanSquaredError
/= width
* height
;
223 log('Mean squared error: ' + meanSquaredError
);
224 diffCtx
.putImageData(diffIData
, 0, 0);
225 maskCtx
.putImageData(maskIData
, 0, 0);
226 document
.getElementById('diff').style
.visibility
= 'visible';
227 document
.getElementById('mask').style
.visibility
= 'visible';