@loaders.gl/video
Version:
Framework-independent loaders and writers for video (MP4, WEBM, ...)
1,647 lines (1,641 loc) • 67.2 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// dist/index.js
var dist_exports = {};
__export(dist_exports, {
GIFBuilder: () => GIFBuilder,
VideoLoader: () => VideoLoader
});
module.exports = __toCommonJS(dist_exports);
// dist/lib/parsers/parse-video.js
async function parseVideo(arrayBuffer) {
const blob2 = new Blob([arrayBuffer]);
const video = document.createElement("video");
video.src = URL.createObjectURL(blob2);
return video;
}
// dist/video-loader.js
var VERSION = true ? "4.3.2" : "latest";
var VideoLoader = {
dataType: null,
batchType: null,
name: "Video",
id: "video",
module: "video",
version: VERSION,
extensions: ["mp4"],
mimeTypes: ["video/mp4"],
// tests: arrayBuffer => Boolean(getBinaryImageMetadata(new DataView(arrayBuffer))),
options: {
video: {}
},
parse: parseVideo
};
// dist/lib/utils/assert.js
function assert(condition, message) {
if (!condition) {
throw new Error(message);
}
}
// dist/lib/gifshot/gifshot.js
var document2 = globalThis.document || {};
var utils = {
URL: globalThis.URL || globalThis.webkitURL || globalThis.mozURL || globalThis.msURL,
getUserMedia: function() {
if (!globalThis.navigator)
return globalThis.navigator;
const getUserMedia = globalThis.navigator.getUserMedia || globalThis.navigator.webkitGetUserMedia || globalThis.navigator.mozGetUserMedia || globalThis.navigator.msGetUserMedia;
return getUserMedia ? getUserMedia.bind(globalThis.navigator) : getUserMedia;
}(),
requestAnimFrame: globalThis.requestAnimationFrame || globalThis.webkitRequestAnimationFrame || globalThis.mozRequestAnimationFrame || globalThis.oRequestAnimationFrame || globalThis.msRequestAnimationFrame,
requestTimeout: function requestTimeout(callback, delay) {
callback = callback || utils.noop;
delay = delay || 0;
if (!utils.requestAnimFrame) {
return setTimeout(callback, delay);
}
const start = new Date().getTime();
const handle = new Object();
const requestAnimFrame = utils.requestAnimFrame;
const loop = function loop2() {
const current = new Date().getTime();
const delta = current - start;
delta >= delay ? callback.call() : handle.value = requestAnimFrame(loop2);
};
handle.value = requestAnimFrame(loop);
return handle;
},
Blob: globalThis.Blob || globalThis.BlobBuilder || globalThis.WebKitBlobBuilder || globalThis.MozBlobBuilder || globalThis.MSBlobBuilder,
btoa: function() {
const btoa = globalThis.btoa || function(input) {
let output = "";
let i = 0;
const l = input.length;
const key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
let chr1 = void 0;
let chr2 = void 0;
let chr3 = void 0;
let enc1 = void 0;
let enc2 = void 0;
let enc3 = void 0;
let enc4 = void 0;
while (i < l) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = (chr1 & 3) << 4 | chr2 >> 4;
enc3 = (chr2 & 15) << 2 | chr3 >> 6;
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output + key.charAt(enc1) + key.charAt(enc2) + key.charAt(enc3) + key.charAt(enc4);
}
return output;
};
return btoa ? btoa.bind(globalThis) : utils.noop;
}(),
isObject: function isObject(obj) {
return obj && Object.prototype.toString.call(obj) === "[object Object]";
},
isEmptyObject: function isEmptyObject(obj) {
return utils.isObject(obj) && !Object.keys(obj).length;
},
isArray: function isArray(arr) {
return arr && Array.isArray(arr);
},
isFunction: function isFunction(func) {
return func && typeof func === "function";
},
isElement: function isElement(elem) {
return elem && elem.nodeType === 1;
},
isString: function isString(value) {
return typeof value === "string" || Object.prototype.toString.call(value) === "[object String]";
},
isSupported: {
canvas: function canvas() {
const el = document2.createElement("canvas");
return el && el.getContext && el.getContext("2d");
},
webworkers: function webworkers() {
return globalThis.Worker;
},
blob: function blob() {
return utils.Blob;
},
Uint8Array: function Uint8Array2() {
return globalThis.Uint8Array;
},
Uint32Array: function Uint32Array2() {
return globalThis.Uint32Array;
},
videoCodecs: function() {
const testEl = document2.createElement("video");
const supportObj = {
mp4: false,
h264: false,
ogv: false,
ogg: false,
webm: false
};
try {
if (testEl && testEl.canPlayType) {
supportObj.mp4 = testEl.canPlayType('video/mp4; codecs="mp4v.20.8"') !== "";
supportObj.h264 = (testEl.canPlayType('video/mp4; codecs="avc1.42E01E"') || testEl.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"')) !== "";
supportObj.ogv = testEl.canPlayType('video/ogg; codecs="theora"') !== "";
supportObj.ogg = testEl.canPlayType('video/ogg; codecs="theora"') !== "";
supportObj.webm = testEl.canPlayType('video/webm; codecs="vp8, vorbis"') !== -1;
}
} catch (e) {
}
return supportObj;
}()
},
noop: function noop() {
},
each: function each(collection, callback) {
let x = void 0;
let len = void 0;
if (utils.isArray(collection)) {
x = -1;
len = collection.length;
while (++x < len) {
if (callback(x, collection[x]) === false) {
break;
}
}
} else if (utils.isObject(collection)) {
for (x in collection) {
if (collection.hasOwnProperty(x)) {
if (callback(x, collection[x]) === false) {
break;
}
}
}
}
},
normalizeOptions: function normalizeOptions(defaultOptions2, userOptions) {
if (!utils.isObject(defaultOptions2) || !utils.isObject(userOptions) || !Object.keys) {
return;
}
const newObj = {};
utils.each(defaultOptions2, function(key, val) {
newObj[key] = defaultOptions2[key];
});
utils.each(userOptions, function(key, val) {
const currentUserOption = userOptions[key];
if (!utils.isObject(currentUserOption)) {
newObj[key] = currentUserOption;
} else if (!defaultOptions2[key]) {
newObj[key] = currentUserOption;
} else {
newObj[key] = utils.normalizeOptions(defaultOptions2[key], currentUserOption);
}
});
return newObj;
},
setCSSAttr: function setCSSAttr(elem, attr, val) {
if (!utils.isElement(elem)) {
return;
}
if (utils.isString(attr) && utils.isString(val)) {
elem.style[attr] = val;
} else if (utils.isObject(attr)) {
utils.each(attr, function(key, val2) {
elem.style[key] = val2;
});
}
},
removeElement: function removeElement(node) {
if (!utils.isElement(node)) {
return;
}
if (node.parentNode) {
node.parentNode.removeChild(node);
}
},
createWebWorker: function createWebWorker(content) {
if (!utils.isString(content)) {
return {};
}
try {
const blob2 = new utils.Blob([content], {
type: "text/javascript"
});
const objectUrl = utils.URL.createObjectURL(blob2);
const worker = new Worker(objectUrl);
return {
objectUrl,
worker
};
} catch (e) {
return `${e}`;
}
},
getExtension: function getExtension(src) {
return src.substr(src.lastIndexOf(".") + 1, src.length);
},
getFontSize: function getFontSize() {
const options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
if (!document2.body || options.resizeFont === false) {
return options.fontSize;
}
const text = options.text;
const containerWidth = options.gifWidth;
let fontSize = parseInt(options.fontSize, 10);
const minFontSize = parseInt(options.minFontSize, 10);
const div = document2.createElement("div");
const span = document2.createElement("span");
div.setAttribute("width", containerWidth);
div.appendChild(span);
span.innerHTML = text;
span.style.fontSize = `${fontSize}px`;
span.style.textIndent = "-9999px";
span.style.visibility = "hidden";
document2.body.appendChild(span);
while (span.offsetWidth > containerWidth && fontSize >= minFontSize) {
span.style.fontSize = `${--fontSize}px`;
}
document2.body.removeChild(span);
return `${fontSize}px`;
},
webWorkerError: false
};
var utils$2 = Object.freeze({
default: utils
});
var error = {
validate: function validate(skipObj) {
skipObj = utils.isObject(skipObj) ? skipObj : {};
let errorObj = {};
utils.each(error.validators, function(indece, currentValidator) {
const errorCode = currentValidator.errorCode;
if (!skipObj[errorCode] && !currentValidator.condition) {
errorObj = currentValidator;
errorObj.error = true;
return false;
}
});
delete errorObj.condition;
return errorObj;
},
isValid: function isValid(skipObj) {
const errorObj = error.validate(skipObj);
const isValid2 = errorObj.error !== true;
return isValid2;
},
validators: [
{
condition: utils.isFunction(utils.getUserMedia),
errorCode: "getUserMedia",
errorMsg: "The getUserMedia API is not supported in your browser"
},
{
condition: utils.isSupported.canvas(),
errorCode: "canvas",
errorMsg: "Canvas elements are not supported in your browser"
},
{
condition: utils.isSupported.webworkers(),
errorCode: "webworkers",
errorMsg: "The Web Workers API is not supported in your browser"
},
{
condition: utils.isFunction(utils.URL),
errorCode: "globalThis.URL",
errorMsg: "The globalThis.URL API is not supported in your browser"
},
{
condition: utils.isSupported.blob(),
errorCode: "globalThis.Blob",
errorMsg: "The globalThis.Blob File API is not supported in your browser"
},
{
condition: utils.isSupported.Uint8Array(),
errorCode: "globalThis.Uint8Array",
errorMsg: "The globalThis.Uint8Array function constructor is not supported in your browser"
},
{
condition: utils.isSupported.Uint32Array(),
errorCode: "globalThis.Uint32Array",
errorMsg: "The globalThis.Uint32Array function constructor is not supported in your browser"
}
],
messages: {
videoCodecs: {
errorCode: "videocodec",
errorMsg: "The video codec you are trying to use is not supported in your browser"
}
}
};
var error$2 = Object.freeze({
default: error
});
var noop2 = function noop3() {
};
var defaultOptions = {
sampleInterval: 10,
numWorkers: 2,
filter: "",
gifWidth: 200,
gifHeight: 200,
interval: 0.1,
numFrames: 10,
frameDuration: 1,
keepCameraOn: false,
images: [],
video: null,
webcamVideoElement: null,
cameraStream: null,
text: "",
fontWeight: "normal",
fontSize: "16px",
minFontSize: "10px",
resizeFont: false,
fontFamily: "sans-serif",
fontColor: "#ffffff",
textAlign: "center",
textBaseline: "bottom",
textXCoordinate: null,
textYCoordinate: null,
progressCallback: noop2,
completeCallback: noop2,
saveRenderingContexts: false,
savedRenderingContexts: [],
crossOrigin: "Anonymous"
};
var defaultOptions$2 = Object.freeze({
default: defaultOptions
});
function isSupported() {
return error.isValid();
}
function isWebCamGIFSupported() {
return error.isValid();
}
function isSupported$1() {
const options = {
getUserMedia: true
};
return error.isValid(options);
}
function isExistingVideoGIFSupported(codecs) {
let hasValidCodec = false;
if (utils.isArray(codecs) && codecs.length) {
utils.each(codecs, function(indece, currentCodec) {
if (utils.isSupported.videoCodecs[currentCodec]) {
hasValidCodec = true;
}
});
if (!hasValidCodec) {
return false;
}
} else if (utils.isString(codecs) && codecs.length) {
if (!utils.isSupported.videoCodecs[codecs]) {
return false;
}
}
return error.isValid({
getUserMedia: true
});
}
function NeuQuant() {
const netsize = 256;
const prime1 = 499;
const prime2 = 491;
const prime3 = 487;
const prime4 = 503;
const minpicturebytes = 3 * prime4;
const maxnetpos = netsize - 1;
const netbiasshift = 4;
const ncycles = 100;
const intbiasshift = 16;
const intbias = 1 << intbiasshift;
const gammashift = 10;
const gamma = 1 << gammashift;
const betashift = 10;
const beta = intbias >> betashift;
const betagamma = intbias << gammashift - betashift;
const initrad = netsize >> 3;
const radiusbiasshift = 6;
const radiusbias = 1 << radiusbiasshift;
const initradius = initrad * radiusbias;
const radiusdec = 30;
const alphabiasshift = 10;
const initalpha = 1 << alphabiasshift;
let alphadec;
const radbiasshift = 8;
const radbias = 1 << radbiasshift;
const alpharadbshift = alphabiasshift + radbiasshift;
const alpharadbias = 1 << alpharadbshift;
let thepicture;
let lengthcount;
let samplefac;
let network;
const netindex = [];
const bias = [];
const freq = [];
const radpower = [];
function NeuQuantConstructor(thepic, len, sample) {
let i;
let p;
thepicture = thepic;
lengthcount = len;
samplefac = sample;
network = new Array(netsize);
for (i = 0; i < netsize; i++) {
network[i] = new Array(4);
p = network[i];
p[0] = p[1] = p[2] = (i << netbiasshift + 8) / netsize | 0;
freq[i] = intbias / netsize | 0;
bias[i] = 0;
}
}
function colorMap() {
const map2 = [];
const index = new Array(netsize);
for (let i = 0; i < netsize; i++) {
index[network[i][3]] = i;
}
let k = 0;
for (let l = 0; l < netsize; l++) {
const j = index[l];
map2[k++] = network[j][0];
map2[k++] = network[j][1];
map2[k++] = network[j][2];
}
return map2;
}
function inxbuild() {
let i;
let j;
let smallpos;
let smallval;
let p;
let q;
let previouscol;
let startpos;
previouscol = 0;
startpos = 0;
for (i = 0; i < netsize; i++) {
p = network[i];
smallpos = i;
smallval = p[1];
for (j = i + 1; j < netsize; j++) {
q = network[j];
if (q[1] < smallval) {
smallpos = j;
smallval = q[1];
}
}
q = network[smallpos];
if (i != smallpos) {
j = q[0];
q[0] = p[0];
p[0] = j;
j = q[1];
q[1] = p[1];
p[1] = j;
j = q[2];
q[2] = p[2];
p[2] = j;
j = q[3];
q[3] = p[3];
p[3] = j;
}
if (smallval != previouscol) {
netindex[previouscol] = startpos + i >> 1;
for (j = previouscol + 1; j < smallval; j++) {
netindex[j] = i;
}
previouscol = smallval;
startpos = i;
}
}
netindex[previouscol] = startpos + maxnetpos >> 1;
for (j = previouscol + 1; j < 256; j++) {
netindex[j] = maxnetpos;
}
}
function learn() {
let i;
let j;
let b;
let g;
let r;
let radius;
let rad;
let alpha;
let step;
let delta;
let samplepixels;
let p;
let pix;
let lim;
if (lengthcount < minpicturebytes) {
samplefac = 1;
}
alphadec = 30 + (samplefac - 1) / 3;
p = thepicture;
pix = 0;
lim = lengthcount;
samplepixels = lengthcount / (3 * samplefac);
delta = samplepixels / ncycles | 0;
alpha = initalpha;
radius = initradius;
rad = radius >> radiusbiasshift;
if (rad <= 1) {
rad = 0;
}
for (i = 0; i < rad; i++) {
radpower[i] = alpha * ((rad * rad - i * i) * radbias / (rad * rad));
}
if (lengthcount < minpicturebytes) {
step = 3;
} else if (lengthcount % prime1 !== 0) {
step = 3 * prime1;
} else if (lengthcount % prime2 !== 0) {
step = 3 * prime2;
} else if (lengthcount % prime3 !== 0) {
step = 3 * prime3;
} else {
step = 3 * prime4;
}
i = 0;
while (i < samplepixels) {
b = (p[pix + 0] & 255) << netbiasshift;
g = (p[pix + 1] & 255) << netbiasshift;
r = (p[pix + 2] & 255) << netbiasshift;
j = contest(b, g, r);
altersingle(alpha, j, b, g, r);
if (rad !== 0) {
alterneigh(rad, j, b, g, r);
}
pix += step;
if (pix >= lim) {
pix -= lengthcount;
}
i++;
if (delta === 0) {
delta = 1;
}
if (i % delta === 0) {
alpha -= alpha / alphadec;
radius -= radius / radiusdec;
rad = radius >> radiusbiasshift;
if (rad <= 1) {
rad = 0;
}
for (j = 0; j < rad; j++) {
radpower[j] = alpha * ((rad * rad - j * j) * radbias / (rad * rad));
}
}
}
}
function map(b, g, r) {
let i;
let j;
let dist;
let a;
let bestd;
let p;
let best;
bestd = 1e3;
best = -1;
i = netindex[g];
j = i - 1;
while (i < netsize || j >= 0) {
if (i < netsize) {
p = network[i];
dist = p[1] - g;
if (dist >= bestd) {
i = netsize;
} else {
i++;
if (dist < 0) {
dist = -dist;
}
a = p[0] - b;
if (a < 0) {
a = -a;
}
dist += a;
if (dist < bestd) {
a = p[2] - r;
if (a < 0) {
a = -a;
}
dist += a;
if (dist < bestd) {
bestd = dist;
best = p[3];
}
}
}
}
if (j >= 0) {
p = network[j];
dist = g - p[1];
if (dist >= bestd) {
j = -1;
} else {
j--;
if (dist < 0) {
dist = -dist;
}
a = p[0] - b;
if (a < 0) {
a = -a;
}
dist += a;
if (dist < bestd) {
a = p[2] - r;
if (a < 0) {
a = -a;
}
dist += a;
if (dist < bestd) {
bestd = dist;
best = p[3];
}
}
}
}
}
return best;
}
function process() {
learn();
unbiasnet();
inxbuild();
return colorMap();
}
function unbiasnet() {
let i;
let j;
for (i = 0; i < netsize; i++) {
network[i][0] >>= netbiasshift;
network[i][1] >>= netbiasshift;
network[i][2] >>= netbiasshift;
network[i][3] = i;
}
}
function alterneigh(rad, i, b, g, r) {
let j;
let k;
let lo;
let hi;
let a;
let m;
let p;
lo = i - rad;
if (lo < -1) {
lo = -1;
}
hi = i + rad;
if (hi > netsize) {
hi = netsize;
}
j = i + 1;
k = i - 1;
m = 1;
while (j < hi || k > lo) {
a = radpower[m++];
if (j < hi) {
p = network[j++];
try {
p[0] -= a * (p[0] - b) / alpharadbias | 0;
p[1] -= a * (p[1] - g) / alpharadbias | 0;
p[2] -= a * (p[2] - r) / alpharadbias | 0;
} catch (e) {
}
}
if (k > lo) {
p = network[k--];
try {
p[0] -= a * (p[0] - b) / alpharadbias | 0;
p[1] -= a * (p[1] - g) / alpharadbias | 0;
p[2] -= a * (p[2] - r) / alpharadbias | 0;
} catch (e) {
}
}
}
}
function altersingle(alpha, i, b, g, r) {
const n = network[i];
const alphaMult = alpha / initalpha;
n[0] -= alphaMult * (n[0] - b) | 0;
n[1] -= alphaMult * (n[1] - g) | 0;
n[2] -= alphaMult * (n[2] - r) | 0;
}
function contest(b, g, r) {
let i;
let dist;
let a;
let biasdist;
let betafreq;
let bestpos;
let bestbiaspos;
let bestd;
let bestbiasd;
let n;
bestd = ~(1 << 31);
bestbiasd = bestd;
bestpos = -1;
bestbiaspos = bestpos;
for (i = 0; i < netsize; i++) {
n = network[i];
dist = n[0] - b;
if (dist < 0) {
dist = -dist;
}
a = n[1] - g;
if (a < 0) {
a = -a;
}
dist += a;
a = n[2] - r;
if (a < 0) {
a = -a;
}
dist += a;
if (dist < bestd) {
bestd = dist;
bestpos = i;
}
biasdist = dist - (bias[i] >> intbiasshift - netbiasshift);
if (biasdist < bestbiasd) {
bestbiasd = biasdist;
bestbiaspos = i;
}
betafreq = freq[i] >> betashift;
freq[i] -= betafreq;
bias[i] += betafreq << gammashift;
}
freq[bestpos] += beta;
bias[bestpos] -= betagamma;
return bestbiaspos;
}
NeuQuantConstructor.apply(this, arguments);
const exports = {};
exports.map = map;
exports.process = process;
return exports;
}
function workerCode() {
const self = this;
try {
globalThis.onmessage = function(ev) {
const data = ev.data || {};
let response;
if (data.gifshot) {
response = workerMethods.run(data);
postMessage(response);
}
};
} catch (e) {
}
var workerMethods = {
dataToRGB: function dataToRGB(data, width, height) {
const length = width * height * 4;
let i = 0;
const rgb = [];
while (i < length) {
rgb.push(data[i++]);
rgb.push(data[i++]);
rgb.push(data[i++]);
i++;
}
return rgb;
},
componentizedPaletteToArray: function componentizedPaletteToArray(paletteRGB) {
paletteRGB = paletteRGB || [];
const paletteArray = [];
for (let i = 0; i < paletteRGB.length; i += 3) {
const r = paletteRGB[i];
const g = paletteRGB[i + 1];
const b = paletteRGB[i + 2];
paletteArray.push(r << 16 | g << 8 | b);
}
return paletteArray;
},
// This is the "traditional" Animated_GIF style of going from RGBA to indexed color frames
processFrameWithQuantizer: function processFrameWithQuantizer(imageData, width, height, sampleInterval) {
const rgbComponents = this.dataToRGB(imageData, width, height);
const nq = new NeuQuant(rgbComponents, rgbComponents.length, sampleInterval);
const paletteRGB = nq.process();
const paletteArray = new Uint32Array(this.componentizedPaletteToArray(paletteRGB));
const numberPixels = width * height;
const indexedPixels = new Uint8Array(numberPixels);
let k = 0;
for (let i = 0; i < numberPixels; i++) {
const r = rgbComponents[k++];
const g = rgbComponents[k++];
const b = rgbComponents[k++];
indexedPixels[i] = nq.map(r, g, b);
}
return {
pixels: indexedPixels,
palette: paletteArray
};
},
run: function run(frame) {
frame = frame || {};
const _frame = frame;
const height = _frame.height;
const palette = _frame.palette;
const sampleInterval = _frame.sampleInterval;
const width = _frame.width;
const imageData = frame.data;
return this.processFrameWithQuantizer(imageData, width, height, sampleInterval);
}
};
return workerMethods;
}
function gifWriter(buf, width, height, gopts) {
let p = 0;
gopts = gopts === void 0 ? {} : gopts;
const loop_count = gopts.loop === void 0 ? null : gopts.loop;
const global_palette = gopts.palette === void 0 ? null : gopts.palette;
if (width <= 0 || height <= 0 || width > 65535 || height > 65535)
throw "Width/Height invalid.";
function check_palette_and_num_colors(palette) {
const num_colors = palette.length;
if (num_colors < 2 || num_colors > 256 || num_colors & num_colors - 1)
throw "Invalid code/color length, must be power of 2 and 2 .. 256.";
return num_colors;
}
buf[p++] = 71;
buf[p++] = 73;
buf[p++] = 70;
buf[p++] = 56;
buf[p++] = 57;
buf[p++] = 97;
const gp_num_colors_pow2 = 0;
const background = 0;
buf[p++] = width & 255;
buf[p++] = width >> 8 & 255;
buf[p++] = height & 255;
buf[p++] = height >> 8 & 255;
buf[p++] = (global_palette !== null ? 128 : 0) | // Global Color Table Flag.
gp_num_colors_pow2;
buf[p++] = background;
buf[p++] = 0;
if (loop_count !== null) {
if (loop_count < 0 || loop_count > 65535)
throw "Loop count invalid.";
buf[p++] = 33;
buf[p++] = 255;
buf[p++] = 11;
buf[p++] = 78;
buf[p++] = 69;
buf[p++] = 84;
buf[p++] = 83;
buf[p++] = 67;
buf[p++] = 65;
buf[p++] = 80;
buf[p++] = 69;
buf[p++] = 50;
buf[p++] = 46;
buf[p++] = 48;
buf[p++] = 3;
buf[p++] = 1;
buf[p++] = loop_count & 255;
buf[p++] = loop_count >> 8 & 255;
buf[p++] = 0;
}
let ended = false;
this.addFrame = function(x, y, w, h, indexed_pixels, opts) {
if (ended === true) {
--p;
ended = false;
}
opts = opts === void 0 ? {} : opts;
if (x < 0 || y < 0 || x > 65535 || y > 65535)
throw "x/y invalid.";
if (w <= 0 || h <= 0 || w > 65535 || h > 65535)
throw "Width/Height invalid.";
if (indexed_pixels.length < w * h)
throw "Not enough pixels for the frame size.";
let using_local_palette = true;
let palette = opts.palette;
if (palette === void 0 || palette === null) {
using_local_palette = false;
palette = global_palette;
}
if (palette === void 0 || palette === null)
throw "Must supply either a local or global palette.";
let num_colors = check_palette_and_num_colors(palette);
let min_code_size = 0;
while (num_colors >>= 1) {
++min_code_size;
}
num_colors = 1 << min_code_size;
const delay = opts.delay === void 0 ? 0 : opts.delay;
const disposal = opts.disposal === void 0 ? 0 : opts.disposal;
if (disposal < 0 || disposal > 3)
throw "Disposal out of range.";
let use_transparency = false;
let transparent_index = 0;
if (opts.transparent !== void 0 && opts.transparent !== null) {
use_transparency = true;
transparent_index = opts.transparent;
if (transparent_index < 0 || transparent_index >= num_colors)
throw "Transparent color index.";
}
if (disposal !== 0 || use_transparency || delay !== 0) {
buf[p++] = 33;
buf[p++] = 249;
buf[p++] = 4;
buf[p++] = disposal << 2 | (use_transparency === true ? 1 : 0);
buf[p++] = delay & 255;
buf[p++] = delay >> 8 & 255;
buf[p++] = transparent_index;
buf[p++] = 0;
}
buf[p++] = 44;
buf[p++] = x & 255;
buf[p++] = x >> 8 & 255;
buf[p++] = y & 255;
buf[p++] = y >> 8 & 255;
buf[p++] = w & 255;
buf[p++] = w >> 8 & 255;
buf[p++] = h & 255;
buf[p++] = h >> 8 & 255;
buf[p++] = using_local_palette === true ? 128 | min_code_size - 1 : 0;
if (using_local_palette === true) {
for (let i = 0, il = palette.length; i < il; ++i) {
const rgb = palette[i];
buf[p++] = rgb >> 16 & 255;
buf[p++] = rgb >> 8 & 255;
buf[p++] = rgb & 255;
}
}
p = GifWriterOutputLZWCodeStream(buf, p, min_code_size < 2 ? 2 : min_code_size, indexed_pixels);
};
this.end = function() {
if (ended === false) {
buf[p++] = 59;
ended = true;
}
return p;
};
function GifWriterOutputLZWCodeStream(buf2, p2, min_code_size, index_stream) {
buf2[p2++] = min_code_size;
let cur_subblock = p2++;
const clear_code = 1 << min_code_size;
const code_mask = clear_code - 1;
const eoi_code = clear_code + 1;
let next_code = eoi_code + 1;
let cur_code_size = min_code_size + 1;
let cur_shift = 0;
let cur = 0;
function emit_bytes_to_buffer(bit_block_size) {
while (cur_shift >= bit_block_size) {
buf2[p2++] = cur & 255;
cur >>= 8;
cur_shift -= 8;
if (p2 === cur_subblock + 256) {
buf2[cur_subblock] = 255;
cur_subblock = p2++;
}
}
}
function emit_code(c) {
cur |= c << cur_shift;
cur_shift += cur_code_size;
emit_bytes_to_buffer(8);
}
let ib_code = index_stream[0] & code_mask;
let code_table = {};
emit_code(clear_code);
for (let i = 1, il = index_stream.length; i < il; ++i) {
const k = index_stream[i] & code_mask;
const cur_key = ib_code << 8 | k;
const cur_code = code_table[cur_key];
if (cur_code === void 0) {
cur |= ib_code << cur_shift;
cur_shift += cur_code_size;
while (cur_shift >= 8) {
buf2[p2++] = cur & 255;
cur >>= 8;
cur_shift -= 8;
if (p2 === cur_subblock + 256) {
buf2[cur_subblock] = 255;
cur_subblock = p2++;
}
}
if (next_code === 4096) {
emit_code(clear_code);
next_code = eoi_code + 1;
cur_code_size = min_code_size + 1;
code_table = {};
} else {
if (next_code >= 1 << cur_code_size)
++cur_code_size;
code_table[cur_key] = next_code++;
}
ib_code = k;
} else {
ib_code = cur_code;
}
}
emit_code(ib_code);
emit_code(eoi_code);
emit_bytes_to_buffer(1);
if (cur_subblock + 1 === p2) {
buf2[cur_subblock] = 0;
} else {
buf2[cur_subblock] = p2 - cur_subblock - 1;
buf2[p2++] = 0;
}
return p2;
}
}
var noop$2 = function noop4() {
};
var AnimatedGIF = function AnimatedGIF2(options) {
this.canvas = null;
this.ctx = null;
this.repeat = 0;
this.frames = [];
this.numRenderedFrames = 0;
this.onRenderCompleteCallback = noop$2;
this.onRenderProgressCallback = noop$2;
this.workers = [];
this.availableWorkers = [];
this.generatingGIF = false;
this.options = options;
this.initializeWebWorkers(options);
};
AnimatedGIF.prototype = {
workerMethods: workerCode(),
initializeWebWorkers: function initializeWebWorkers(options) {
const self = this;
const processFrameWorkerCode = `${NeuQuant.toString()}(${workerCode.toString()}());`;
let webWorkerObj = void 0;
let objectUrl = void 0;
let webWorker = void 0;
let numWorkers = void 0;
let x = -1;
let workerError = "";
numWorkers = options.numWorkers;
while (++x < numWorkers) {
webWorkerObj = utils.createWebWorker(processFrameWorkerCode);
if (utils.isObject(webWorkerObj)) {
objectUrl = webWorkerObj.objectUrl;
webWorker = webWorkerObj.worker;
self.workers.push({
worker: webWorker,
objectUrl
});
self.availableWorkers.push(webWorker);
} else {
workerError = webWorkerObj;
utils.webWorkerError = Boolean(webWorkerObj);
}
}
this.workerError = workerError;
this.canvas = document2.createElement("canvas");
this.canvas.width = options.gifWidth;
this.canvas.height = options.gifHeight;
this.ctx = this.canvas.getContext("2d");
this.frames = [];
},
// Return a worker for processing a frame
getWorker: function getWorker() {
return this.availableWorkers.pop();
},
// Restores a worker to the pool
freeWorker: function freeWorker(worker) {
this.availableWorkers.push(worker);
},
byteMap: function() {
const byteMap = [];
for (let i = 0; i < 256; i++) {
byteMap[i] = String.fromCharCode(i);
}
return byteMap;
}(),
bufferToString: function bufferToString(buffer) {
const numberValues = buffer.length;
let str = "";
let x = -1;
while (++x < numberValues) {
str += this.byteMap[buffer[x]];
}
return str;
},
onFrameFinished: function onFrameFinished(progressCallback) {
const self = this;
const frames = self.frames;
const options = self.options;
const hasExistingImages = Boolean((options.images || []).length);
const allDone = frames.every(function(frame) {
return !frame.beingProcessed && frame.done;
});
self.numRenderedFrames++;
if (hasExistingImages) {
progressCallback(self.numRenderedFrames / frames.length);
}
self.onRenderProgressCallback(self.numRenderedFrames * 0.75 / frames.length);
if (allDone) {
if (!self.generatingGIF) {
self.generateGIF(frames, self.onRenderCompleteCallback);
}
} else {
utils.requestTimeout(function() {
self.processNextFrame();
}, 1);
}
},
processFrame: function processFrame(position) {
const AnimatedGifContext = this;
const options = this.options;
const _options = this.options;
const progressCallback = _options.progressCallback;
const sampleInterval = _options.sampleInterval;
const frames = this.frames;
let frame = void 0;
let worker = void 0;
const done = function done2() {
const ev = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
const data = ev.data;
delete frame.data;
frame.pixels = Array.prototype.slice.call(data.pixels);
frame.palette = Array.prototype.slice.call(data.palette);
frame.done = true;
frame.beingProcessed = false;
AnimatedGifContext.freeWorker(worker);
AnimatedGifContext.onFrameFinished(progressCallback);
};
frame = frames[position];
if (frame.beingProcessed || frame.done) {
this.onFrameFinished();
return;
}
frame.sampleInterval = sampleInterval;
frame.beingProcessed = true;
frame.gifshot = true;
worker = this.getWorker();
if (worker) {
worker.onmessage = done;
worker.postMessage(frame);
} else {
done({
data: AnimatedGifContext.workerMethods.run(frame)
});
}
},
startRendering: function startRendering(completeCallback) {
this.onRenderCompleteCallback = completeCallback;
for (let i = 0; i < this.options.numWorkers && i < this.frames.length; i++) {
this.processFrame(i);
}
},
processNextFrame: function processNextFrame() {
let position = -1;
for (let i = 0; i < this.frames.length; i++) {
const frame = this.frames[i];
if (!frame.done && !frame.beingProcessed) {
position = i;
break;
}
}
if (position >= 0) {
this.processFrame(position);
}
},
// Takes the already processed data in frames and feeds it to a new
// GifWriter instance in order to get the binary GIF file
generateGIF: function generateGIF(frames, callback) {
const buffer = [];
const gifOptions = {
loop: this.repeat
};
const options = this.options;
const interval = options.interval;
const frameDuration = options.frameDuration;
const existingImages2 = options.images;
const hasExistingImages = Boolean(existingImages2.length);
const height = options.gifHeight;
const width = options.gifWidth;
const gifWriter$$1 = new gifWriter(buffer, width, height, gifOptions);
const onRenderProgressCallback = this.onRenderProgressCallback;
const delay = hasExistingImages ? interval * 100 : 0;
let bufferToString2 = void 0;
let gif = void 0;
this.generatingGIF = true;
utils.each(frames, function(iterator, frame) {
const framePalette = frame.palette;
onRenderProgressCallback(0.75 + 0.25 * frame.position * 1 / frames.length);
for (let i = 0; i < frameDuration; i++) {
gifWriter$$1.addFrame(0, 0, width, height, frame.pixels, {
palette: framePalette,
delay
});
}
});
gifWriter$$1.end();
onRenderProgressCallback(1);
this.frames = [];
this.generatingGIF = false;
if (utils.isFunction(callback)) {
bufferToString2 = this.bufferToString(buffer);
gif = `data:image/gif;base64,${utils.btoa(bufferToString2)}`;
callback(gif);
}
},
// From GIF: 0 = loop forever, null = not looping, n > 0 = loop n times and stop
setRepeat: function setRepeat(r) {
this.repeat = r;
},
addFrame: function addFrame(element, gifshotOptions) {
gifshotOptions = utils.isObject(gifshotOptions) ? gifshotOptions : {};
const self = this;
const ctx = self.ctx;
const options = self.options;
const width = options.gifWidth;
const height = options.gifHeight;
const fontSize = utils.getFontSize(gifshotOptions);
const _gifshotOptions = gifshotOptions;
const filter = _gifshotOptions.filter;
const fontColor = _gifshotOptions.fontColor;
const fontFamily = _gifshotOptions.fontFamily;
const fontWeight = _gifshotOptions.fontWeight;
const gifHeight = _gifshotOptions.gifHeight;
const gifWidth = _gifshotOptions.gifWidth;
const text = _gifshotOptions.text;
const textAlign = _gifshotOptions.textAlign;
const textBaseline = _gifshotOptions.textBaseline;
const textXCoordinate = gifshotOptions.textXCoordinate ? gifshotOptions.textXCoordinate : textAlign === "left" ? 1 : textAlign === "right" ? width : width / 2;
const textYCoordinate = gifshotOptions.textYCoordinate ? gifshotOptions.textYCoordinate : textBaseline === "top" ? 1 : textBaseline === "center" ? height / 2 : height;
const font = `${fontWeight} ${fontSize} ${fontFamily}`;
let imageData = void 0;
try {
ctx.filter = filter;
ctx.drawImage(element, 0, 0, width, height);
if (text) {
ctx.font = font;
ctx.fillStyle = fontColor;
ctx.textAlign = textAlign;
ctx.textBaseline = textBaseline;
ctx.fillText(text, textXCoordinate, textYCoordinate);
}
imageData = ctx.getImageData(0, 0, width, height);
self.addFrameImageData(imageData);
} catch (e) {
return `${e}`;
}
},
addFrameImageData: function addFrameImageData() {
const imageData = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
const frames = this.frames;
const imageDataArray = imageData.data;
this.frames.push({
data: imageDataArray,
width: imageData.width,
height: imageData.height,
palette: null,
dithering: null,
done: false,
beingProcessed: false,
position: frames.length
});
},
onRenderProgress: function onRenderProgress(callback) {
this.onRenderProgressCallback = callback;
},
isRendering: function isRendering() {
return this.generatingGIF;
},
getBase64GIF: function getBase64GIF(completeCallback) {
const self = this;
const onRenderComplete = function onRenderComplete2(gif) {
self.destroyWorkers();
utils.requestTimeout(function() {
completeCallback(gif);
}, 0);
};
self.startRendering(onRenderComplete);
},
destroyWorkers: function destroyWorkers() {
if (this.workerError) {
return;
}
const workers = this.workers;
utils.each(workers, function(iterator, workerObj) {
const worker = workerObj.worker;
const objectUrl = workerObj.objectUrl;
worker.terminate();
utils.URL.revokeObjectURL(objectUrl);
});
}
};
function getBase64GIF2(animatedGifInstance, callback) {
animatedGifInstance.getBase64GIF(function(image) {
callback({
error: false,
errorCode: "",
errorMsg: "",
image
});
});
}
function existingImages() {
const obj = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
const self = this;
const callback = obj.callback;
const images = obj.images;
const options = obj.options;
let imagesLength = obj.imagesLength;
const skipObj = {
getUserMedia: true,
"globalThis.URL": true
};
const errorObj = error.validate(skipObj);
const loadedImages = [];
let loadedImagesLength = 0;
let tempImage = void 0;
let ag = void 0;
if (errorObj.error) {
return callback(errorObj);
}
ag = new AnimatedGIF(options);
utils.each(images, function(index, image) {
const currentImage = image;
if (utils.isElement(currentImage)) {
if (options.crossOrigin) {
currentImage.crossOrigin = options.crossOrigin;
}
loadedImages[index] = currentImage;
loadedImagesLength += 1;
if (loadedImagesLength === imagesLength) {
addLoadedImagesToGif();
}
} else if (utils.isString(currentImage)) {
tempImage = new Image();
if (options.crossOrigin) {
tempImage.crossOrigin = options.crossOrigin;
}
(function(tempImage2) {
if (image.text) {
tempImage2.text = image.text;
}
tempImage2.onerror = function(e) {
let obj2 = void 0;
--imagesLength;
if (imagesLength === 0) {
obj2 = {};
obj2.error = "None of the requested images was capable of being retrieved";
return callback(obj2);
}
};
tempImage2.onload = function(e) {
if (image.text) {
loadedImages[index] = {
img: tempImage2,
text: tempImage2.text
};
} else {
loadedImages[index] = tempImage2;
}
loadedImagesLength += 1;
if (loadedImagesLength === imagesLength) {
addLoadedImagesToGif();
}
utils.removeElement(tempImage2);
};
tempImage2.src = currentImage;
})(tempImage);
utils.setCSSAttr(tempImage, {
position: "fixed",
opacity: "0"
});
document2.body.appendChild(tempImage);
}
});
function addLoadedImagesToGif() {
utils.each(loadedImages, function(index, loadedImage) {
if (loadedImage) {
if (loadedImage.text) {
ag.addFrame(loadedImage.img, options, loadedImage.text);
} else {
ag.addFrame(loadedImage, options);
}
}
});
getBase64GIF2(ag, callback);
}
}
var noop$3 = function noop5() {
};
var screenShot = {
getGIF: function getGIF() {
const options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
let callback = arguments[1];
callback = utils.isFunction(callback) ? callback : noop$3;
const canvas2 = document2.createElement("canvas");
let context = void 0;
const existingImages2 = options.images;
const hasExistingImages = Boolean(existingImages2.length);
const cameraStream = options.cameraStream;
const crop = options.crop;
const filter = options.filter;
const fontColor = options.fontColor;
const fontFamily = options.fontFamily;
const fontWeight = options.fontWeight;
const keepCameraOn = options.keepCameraOn;
const numWorkers = options.numWorkers;
const progressCallback = options.progressCallback;
const saveRenderingContexts = options.saveRenderingContexts;
const savedRenderingContexts = options.savedRenderingContexts;
const text = options.text;
const textAlign = options.textAlign;
const textBaseline = options.textBaseline;
const videoElement = options.videoElement;
const videoHeight = options.videoHeight;
const videoWidth = options.videoWidth;
const webcamVideoElement = options.webcamVideoElement;
const gifWidth = Number(options.gifWidth);
const gifHeight = Number(options.gifHeight);
let interval = Number(options.interval);
const sampleInterval = Number(options.sampleInterval);
const waitBetweenFrames = hasExistingImages ? 0 : interval * 1e3;
const renderingContextsToSave = [];
let numFrames = savedRenderingContexts.length ? savedRenderingContexts.length : options.numFrames;
let pendingFrames = numFrames;
const ag = new AnimatedGIF(options);
const fontSize = utils.getFontSize(options);
const textXCoordinate = options.textXCoordinate ? options.textXCoordinate : textAlign === "left" ? 1 : textAlign === "right" ? gifWidth : gifWidth / 2;
const textYCoordinate = options.textYCoordinate ? options.textYCoordinate : textBaseline === "top" ? 1 : textBaseline === "center" ? gifHeight / 2 : gifHeight;
const font = `${fontWeight} ${fontSize} ${fontFamily}`;
let sourceX = crop ? Math.floor(crop.scaledWidth / 2) : 0;
let sourceWidth = crop ? videoWidth - crop.scaledWidth : 0;
let sourceY = crop ? Math.floor(crop.scaledHeight / 2) : 0;
let sourceHeight = crop ? videoHeight - crop.scaledHeight : 0;
const captureFrames = function captureSingleFrame() {
const framesLeft = pendingFrames - 1;
if (savedRenderingContexts.length) {
context.putImageData(savedRenderingContexts[numFrames - pendingFrames], 0, 0);
finishCapture();
} else {
drawVideo();
}
function drawVideo() {
try {
if (sourceWidth > videoWidth) {
sourceWidth = videoWidth;
}
if (sourceHeight > videoHeight) {
sourceHeight = videoHeight;
}
if (sourceX < 0) {
sourceX = 0;
}
if (sourceY < 0) {
sourceY = 0;
}
context.filter = filter;
context.drawImage(videoElement, sourceX, sourceY, sourceWidth, sourceHeight, 0, 0, gifWidth, gifHeight);
finishCapture();
} catch (e) {
if (e.name === "NS_ERROR_NOT_AVAILABLE") {
utils.requestTimeout(drawVideo, 100);
} else {
throw e;
}
}
}
function finishCapture() {
let imageData = void 0;
if (saveRenderingContexts) {
renderingContextsToSave.push(context.getImageData(0, 0, gifWidth, gifHeight));
}
if (text) {
context.font = font;
context.fillStyle = fontColor;
context.textAlign = textAlign;
context.textBaseline = textBaseline;
context.fillText(text, textXCoordinate, textYCoordinate);
}
imageData = context.getImageData(0, 0, gifWidth, gifHeight);
ag.addFrameImageData(imageData);
pendingFrames = framesLeft;
progressCallback((numFrames - pendingFrames) / numFrames);
if (framesLeft > 0) {
utils.requestTimeout(captureSingleFrame, waitBetweenFrames);
}
if (!pendingFrames) {
ag.getBase64GIF(function(image) {
callback({
error: false,
errorCode: "",
errorMsg: "",
image,
cameraStream,
videoElement,
webcamVideoElement,
savedRenderingContexts: renderingContextsToSave,
keepCameraOn
});
});
}
}
};
numFrames = numFrames !== void 0 ? numFrames : 10;
interval = interval !== void 0 ? interval : 0.1;
canvas2.width = gifWidth;
canvas2.height = gifHeight;
context = canvas2.getContext("2d");
(function capture() {
if (!savedRenderingContexts.length && videoElement.currentTime === 0) {
utils.requestTimeout(capture, 100);
return;
}
captureFrames();
})();
},
getCropDimensions: function getCropDimensions() {
const obj = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
const width = obj.videoWidth;
const height = obj.videoHeight;
const gifWidth = obj.gifWidth;
const gifHeight = obj.gifHeight;
const result = {
width: 0,
height: 0,
scaledWidth: 0,
scaledHeight: 0
};
if (width > height) {
result.width = Math.round(width * (gifHeight / height)) - gifWidth;
result.scaledWidth = Math.round(result.width * (height / gifHeight));
} else {
result.height = Math.round(height * (gifWidth / width)) - gifHeight;
result.scaledHeight = Math.round(result.height * (width / gifWidth));
}
return result;
}
};
var videoStream = {
loadedData: false,
defaultVideoDimensions: {
width: 640,
height: 480
},
findVideoSize: function findVideoSizeMethod(obj) {
findVideoSizeMethod.attempts = findVideoSizeMethod.attempts || 0;
const cameraStream = obj.cameraStream;
const completedCallback = obj.completedCallback;
const videoElement = obj.videoElement;
if (!videoElement) {
return;
}
if (videoElement.videoWidth > 0 && videoElement.videoHeight > 0) {
videoElement.removeEventListener("loadeddata", videoStream.findVideoSize);
completedCallback({
videoElement,
cameraStream,
videoWidth: videoElement.videoWidth,
videoHeight: videoElement.videoHeight
});
} else if (findVideoSizeMethod.attempts < 10) {
findVideoSizeMethod.attempts += 1;
utils.requestTimeout(function() {
videoStream.findVideoSize(obj);
}, 400);
} else {
completedCallback({
videoElement,
cameraStream,
videoWidth: videoStream.defaultVideoDimensions.width,
videoHeight: videoStream.defaultVideoDimensions.height
});
}
},
onStreamingTimeout: function onStreamingTimeout(callback) {
if (utils.isFunction(callback)) {
callback({
error: true,
errorCode: "getUserMedia",