async function checkEncoderSupport(test, config) { assert_equals("function", typeof VideoEncoder.isConfigSupported); let supported = false; try { const support = await VideoEncoder.isConfigSupported(config); supported = support.supported; } catch (e) {} assert_implements_optional(supported, 'Unsupported config: ' + JSON.stringify(config)); } function fourColorsFrame(ctx, width, height, text) { const kYellow = "#FFFF00"; const kRed = "#FF0000"; const kBlue = "#0000FF"; const kGreen = "#00FF00"; ctx.fillStyle = kYellow; ctx.fillRect(0, 0, width / 2, height / 2); ctx.fillStyle = kRed; ctx.fillRect(width / 2, 0, width / 2, height / 2); ctx.fillStyle = kBlue; ctx.fillRect(0, height / 2, width / 2, height / 2); ctx.fillStyle = kGreen; ctx.fillRect(width / 2, height / 2, width / 2, height / 2); ctx.fillStyle = 'white'; ctx.font = (height / 10) + 'px sans-serif'; ctx.fillText(text, width / 2, height / 2); } // Paints |count| black dots on the |ctx|, so their presence can be validated // later. This is an analog of the most basic bar code. function putBlackDots(ctx, width, height, count) { ctx.fillStyle = 'black'; const dot_size = 20; const step = dot_size * 2; for (let i = 1; i <= count; i++) { let x = i * step; let y = step * (x / width + 1); x %= width; ctx.fillRect(x, y, dot_size, dot_size); } } // Validates that frame has |count| black dots in predefined places. function validateBlackDots(frame, count) { const width = frame.displayWidth; const height = frame.displayHeight; let cnv = new OffscreenCanvas(width, height); var ctx = cnv.getContext('2d', {willReadFrequently: true}); ctx.drawImage(frame, 0, 0); const dot_size = 20; const step = dot_size * 2; for (let i = 1; i <= count; i++) { let x = i * step + dot_size / 2; let y = step * (x / width + 1) + dot_size / 2; x %= width; if (x) x = x -1; if (y) y = y -1; let rgba = ctx.getImageData(x, y, 2, 2).data; const tolerance = 60; if ((rgba[0] > tolerance || rgba[1] > tolerance || rgba[2] > tolerance) && (rgba[4] > tolerance || rgba[5] > tolerance || rgba[6] > tolerance) && (rgba[8] > tolerance || rgba[9] > tolerance || rgba[10] > tolerance) && (rgba[12] > tolerance || rgba[13] > tolerance || rgba[14] > tolerance)) { // The dot is too bright to be a black dot. return false; } } return true; } function createFrame(width, height, ts = 0) { let duration = 33333; // 30fps let text = ts.toString(); let cnv = new OffscreenCanvas(width, height); var ctx = cnv.getContext('2d'); fourColorsFrame(ctx, width, height, text); return new VideoFrame(cnv, { timestamp: ts, duration }); } function createDottedFrame(width, height, dots, ts) { if (ts === undefined) ts = dots; let duration = 33333; // 30fps let text = ts.toString(); let cnv = new OffscreenCanvas(width, height); var ctx = cnv.getContext('2d'); fourColorsFrame(ctx, width, height, text); putBlackDots(ctx, width, height, dots); return new VideoFrame(cnv, { timestamp: ts, duration }); }