function TransparentVideo (video, options) {
		var initialStyles = {};
		var divisor = options.mask ? 1 : 2; //static alpha data will not cut the image dimensions
		var dimensions = { // calculate dimensions
			width: parseInt(options.width, 10),
			height: parseInt(options.height, 10)
		};
		var bufferCanvas = document.createElement('canvas');
		var buffer = bufferCanvas.getContext('2d');
		var displayCanvas = document.createElement('canvas');
		var display = displayCanvas.getContext('2d');
		var posterframe;
		var interval;
		var requestAnimationFrame = window.requestAnimationFrame || getRequestAnimationFrame();
		var cancelAnimationFrame = window.cancelAnimationFrame || getCancelAnimationFrame();
		var lastDrawnFrameTime = null;
		var drawFrame = function (recurse) {
			var image, alphaData, i, len, currentFrameTime = video.currentTime;

			if (lastDrawnFrameTime !== currentFrameTime && video.readyState > 1) {
				lastDrawnFrameTime = currentFrameTime;

				buffer.drawImage(video, 0, 0, dimensions.width, dimensions.height * divisor); //scales if <video>-dimensions are not matching
				image = buffer.getImageData(0, 0, dimensions.width, dimensions.height);
				alphaData = buffer.getImageData(0, dimensions.height, dimensions.width, dimensions.height).data; //grab from video;

				if (options.unmult) unmultiply(image, alphaData);

				//calculate luminance from buffer part, no weighting needed when alpha mask is used
				for (i = 3, len = image.data.length; i < len; i = i + 4) {
					image.data[i] = options.alphaMask ? alphaData[i - 1] : Math.max(alphaData[i - 1], alphaData[i - 2], alphaData[i - 3]);
				}

				display.putImageData(image, 0, 0, 0, 0, dimensions.width, dimensions.height);
			}

			if (recurse) {
				interval = requestAnimationFrame(function () {
					drawFrame(true);
				});
			}
		};

		var drawStaticMask = function (node) {
			if (node.tagName !== 'IMG') throw new Error('Cannot use non-image element as mask!');

			node.width = dimensions.width;
			node.height = dimensions.height; //adjust image dimensions to video dimensions

			if (options.alphaMask) { //alpha channel has to be converted into RGB
				buffer.putImageData(convertAlphaMask(node, dimensions), 0, dimensions.height);
			} else { //no conversion needed, draw image into buffer
				buffer.drawImage(node, 0, dimensions.height, dimensions.width, dimensions.height);
			}

			node.style.display = 'none';
		};


		/**
		* @method startRendering
		* kick off the animation loop
		* @returns self
		* @API public
		*/
		this.startRendering = function () {
			drawFrame(true);
			return this;
		};

		/**
		* @method stopRendering
		* ends the animation loop
		* @returns self
		* @API public
		*/
		this.stopRendering = function () {
			cancelAnimationFrame(interval);
			return this;
		};

		/**
		* @method stopRendering
		* ends the animation loop, removes the canvas elements and unhides the video
		* @returns self
		* @API public
		*/
		this.teardown = function () {
			cancelAnimationFrame(interval);
			video.parentNode.removeChild(video.nextSibling);
			video.parentNode.removeChild(video.nextSibling);
			for (var key in initialStyles) {
				if (Object.prototype.hasOwnProperty.call(initialStyles, key)) {
					video.style[key] = initialStyles[key];
				}
			}
			return this;
		};

		/**
		* @method updateMask
		* draws a new image onto the alpha portion of the buffer
		* @param {DOMElement} node
		* @returns self
		* @API public
		*/
		this.updateMask = function (node) {
			drawStaticMask(node);
			return this;
		};

		/**
		* @method getCanvas
		* gets the visible canvas element that is used for display
		* @returns {DOMElement}
		* @API public
		*/
		this.getCanvas = function () {
			return displayCanvas;
		};

		/**
		* @method getPoster
		* gets the posterframe element
		* @returns {DOMElement}
		* @API public
		*/
		this.getPoster = function () {
			return posterframe;
		};

		var elementDimensions = video.getBoundingClientRect();

		if (!dimensions.height || !dimensions.width) { //we need to find out at least one dimension parameter as it is not explicitly set
			if (!video.width && !video.height) { //<video> has no width- or height-attribute -> source dimensions from video source meta
				dimensions.width = dimensions.width || video.videoWidth;
				dimensions.height = dimensions.height || video.videoHeight / divisor;
			} else if (!video.height) { //<video> has no height-attribute -> source dimensions from video source meta
				dimensions.width = dimensions.width || elementDimensions.width;
				dimensions.height = dimensions.height || elementDimensions.width / (video.videoWidth / Math.floor(video.videoHeight / divisor));
			} else if (!video.width) { //<video> has no height-attribute -> source dimensions from video source meta
				dimensions.width = dimensions.width || elementDimensions.height * (video.videoWidth / Math.floor(video.videoHeight / divisor));
				dimensions.height = dimensions.height || elementDimensions.height;
			} else { //get values from height and width attributes of <video>
				dimensions.width = dimensions.width || elementDimensions.width;
				dimensions.height = dimensions.height || elementDimensions.height / divisor;
			}
		}

		bufferCanvas.width = dimensions.width;
		bufferCanvas.height = dimensions.height * 2;
		bufferCanvas.style.display = 'none';
		bufferCanvas.className = options.namespace + '-buffer';

		displayCanvas.width = dimensions.width;
		displayCanvas.height = dimensions.height;
		displayCanvas.className = options.namespace + '-display';

		insertAfter(bufferCanvas, video);
		insertAfter(displayCanvas, video);

		// draw static mask if needed
		if (options.mask) {
			drawStaticMask(getNode(options.mask));
		}

		// append "posterframe" if option is set and attribute is present on the video
		if (options.poster && video.poster) {
			posterframe = document.createElement('div');
			posterframe.className = 'seeThru-poster';
			posterframe.style.cssText = cssObjectToString({
				width: dimensions.width + 'px',
				height: dimensions.height + 'px',
				position: 'absolute',
				top: 0,
				left: 0,
				'background-size': 'cover',
				'background-position': 'center',
				'background-image': 'url("' + video.poster + '")'
			});
			insertAfter(posterframe, video);
		}

		for (var key in options.videoStyles) {
			if (Object.prototype.hasOwnProperty.call(options.videoStyles, key)) {
				initialStyles[key] = window.getComputedStyle(video)[key];
				video.style[key] = options.videoStyles[key];
			}
		}
	}
@constructor TransparentVideo
handles the transformation of a video into the canvas elements and keeps track
of intervals and animation loop logic
@param {DOMElement} video
@param {Object options}