diff --git a/src/input/config_factory.js b/src/input/config_factory.js new file mode 100644 index 0000000..0c49587 --- /dev/null +++ b/src/input/config_factory.js @@ -0,0 +1,138 @@ +import {merge, pick, omitBy, isEmpty} from 'lodash'; + +const isDataURL = {regex: /^\s*data:([a-z]+\/[a-z0-9\-\+]+(;[a-z\-]+\=[a-z0-9\-]+)?)?(;base64)?,[a-z0-9\!\$\&\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i}, // eslint-disable-line max-len + isBlobURL = {regex: /^\s*blob:(.*)$/i}, + isMediaURL = {regex: /^(?:(?:http[s]?|ftp):\/)?\/?(?:(?:[^:\/\s]+)(?:(?:\/\w+)*\/))?([\w\-]+\.([^#?\s]+))(?:.*)?(?:#[\w\-]+)?$/i}, // eslint-disable-line max-len + isImageExt = {regex: /(jpe?g|png|gif|tiff)(?:\s+|$)/i}, + isVideoExt = {regex: /(webm|ogg|mp4|m4v)/i}; + +const MediaStream = "MediaStream" in window ? window.MediaStream : function(){}; + +export function createConfigFromSource(config, sourceConfig, source) { + if (source instanceof MediaStream) { + return createConfigForStream(config, sourceConfig, {srcObject: source}); + } else if (source instanceof HTMLImageElement) { + throw new Error('Source "HTMLImageElement": not yet supported'); + // return createConfigForImage(config, inputConfig, {image: source}); + } else if (source instanceof HTMLVideoElement) { + throw new Error('Source "HTMLVideoElement": not yet supported'); + // return createConfigForVideo(config, inputConfig, {video: source}); + } else if (source instanceof HTMLCanvasElement) { + return createConfigForCanvas(config, sourceConfig, {canvas: source}); + } else if (source instanceof FileList) { + if (source.length > 0) { + return createConfigForFile(config, sourceConfig, source[0]); + } + } else if (source instanceof File) { + return createConfigForFile(config, sourceConfig, source); + } else if (typeof source === 'string') { + return createConfigForString(config, sourceConfig, source); + } else if (typeof source === 'object' + && (typeof source.constraints !== 'undefined' + || typeof source.area !== 'undefined')) { + return createConfigForLiveStream(config, source); + } else { + throw new Error("No source given!"); + } +} + +function createConfigForImage(config, source, inputConfig = {}) { + const staticImageConfig = { + inputStream: merge({ + type: "ImageStream", + sequence: false, + size: 800 + }, source), + numOfWorkers: (ENV.development && config.debug) ? 0 : 1 + }; + return merge( + config, + staticImageConfig, + {numOfWorkers: typeof config.numOfWorkers === 'number' && config.numOfWorkers > 0 ? 1 : 0}, + {inputStream: omitBy(pick(config.inputStream, ['size']), isEmpty)}, + {inputStream: inputConfig}); +} + +function createConfigForMimeType(config, inputConfig, {src, mime}) { + const [, type] = mime.match(/^(video|image)\/(.*)$/i) || []; + if (type === 'video') { + return createConfigForVideo(config, {src}, inputConfig); + } else if (type === 'image') { + return createConfigForImage(config, {src}, inputConfig); + } + throw new Error(`Source with mimetype: "${type}" not supported`); +} + +function createConfigForFile(config, inputConfig, file) { + const src = window.URL.createObjectURL(file); + return createConfigForMimeType(config, inputConfig, { + src, + mime: file.type + }); +} + +function createConfigForString(config, inputConfig = {}, source) { + const [, mime] = source.match(isDataURL.regex) || []; + if (mime) { + return createConfigForMimeType(config, inputConfig, {src: source, mime}); + } + const blobURL = source.match(isBlobURL.regex); + if (blobURL) { + throw new Error(`Source "objectURL": not supported`); + } + const [, , ext] = source.match(isMediaURL.regex) || []; + if (ext) { + return createConfigForMediaExtension(config, inputConfig, {src: source, ext}); + } + throw new Error(`Source "${source}": not recognized`); +} + +function createConfigForMediaExtension(config, inputConfig, {src, ext}) { + if (ext.match(isImageExt.regex)) { + return createConfigForImage(config, {src}, inputConfig); + } else if (ext.match(isVideoExt.regex)) { + return createConfigForVideo(config, {src}, inputConfig); + } + throw new Error(`Source "MediaString": not recognized`); +} + +function createConfigForCanvas (config, {canvas}, inputConfig = {}) { + // TODO: adjust stream & frame-grabber + // once/continous + throw new Error('Source "Canvas": not implemented!'); +} + +function createConfigForVideo (config, source, inputConfig = {}) { + return merge({}, + config, + { + inputStream: merge({ + type: "VideoStream" + }, source) + }, { + inputStream: inputConfig + }); +} + +function createConfigForStream(config, {srcObject}, inputConfig = {}) { + // TODO: attach to