Sfoglia il codice sorgente

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js

# Conflicts:
#	gui/src/2D/controls/gridDisplay.ts
David Catuhe 7 anni fa
parent
commit
c73ce9c4a9

File diff suppressed because it is too large
+ 4358 - 4330
Playground/babylon.d.txt


+ 12 - 4
Playground/js/index.js

@@ -558,7 +558,8 @@ function showError(errorMessage, errorEvent) {
                     }
     
                     var scene;
-    
+                    var defaultEngineZip = "new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true })";
+
                     if (code.indexOf("createEngine") !== -1) {
                         createEngineFunction = "createEngine";
                     }
@@ -581,7 +582,7 @@ function showError(errorMessage, errorEvent) {
                         eval("runScript = function(scene, canvas) {" + code + "}");
                         runScript(scene, canvas);
     
-                        zipCode = "var scene = new BABYLON.Scene(engine);\r\n\r\n" + code;
+                        zipCode = "var engine = " + defaultEngineZip + ";\r\nvar scene = new BABYLON.Scene(engine);\r\n\r\n" + code;
                     } else {
                         //execute the code
                         eval(code);
@@ -600,8 +601,15 @@ function showError(errorMessage, errorEvent) {
                             return;
                         }
     
-                        // update the scene code for the zip file
-                        zipCode = code + "\r\n\r\nvar scene = " + createSceneFunction + "()";
+                        var createEngineZip = (createEngineFunction === "createEngine")
+                            ? "createEngine()"
+                            : defaultEngineZip
+
+                        zipCode = 
+                            code + "\r\n\r\n" +
+                            "var engine = " + createEngineZip + ";\r\n" +
+                            "var scene = " + createSceneFunction + "();"
+
                     }
     
                     engine.runRenderLoop(function () {

+ 0 - 1
Playground/zipContent/index.html

@@ -40,7 +40,6 @@
     <canvas id="renderCanvas"></canvas>
     <script>
         var canvas = document.getElementById("renderCanvas");
-        var engine = new BABYLON.Engine(canvas, true);
 
 ####INJECT####
 

+ 11 - 1
Tools/Gulp/config.json

@@ -124,7 +124,8 @@
             "imageProcessing",
             "occlusionQuery",
             "transformFeedback",
-            "noise"
+            "noise",
+            "videoRecorder"
         ],
         "minimal": [
             "meshBuilder",
@@ -1391,7 +1392,16 @@
                 "meshBuilder",
                 "additionalTextures"
             ]
+        },
+        "videoRecorder": {
+            "files": [
+                "../../src/Tools/babylon.videoRecorder.js"
+            ],
+            "dependUpon": [
+                "core"
+            ]
         }
+
     },
     "typescript": [
         "../../src/**/*.ts",

File diff suppressed because it is too large
+ 5557 - 5557
dist/preview release/babylon.d.ts


+ 29 - 0
dist/preview release/gui/babylon.gui.d.ts

@@ -1806,6 +1806,35 @@ declare module BABYLON.GUI {
     }
 }
 declare module BABYLON.GUI {
+    /** Class used to render a grid  */
+    export class DisplayGrid extends Control {
+            name?: string | undefined;
+            /** Gets or sets background color (Black by default) */
+            background: string;
+            /** Gets or sets the width of each cell (20 by default) */
+            cellWidth: number;
+            /** Gets or sets the height of each cell (20 by default) */
+            cellHeight: number;
+            /** Gets or sets the tickness of minor lines (1 by default) */
+            minorLineTickness: number;
+            /** Gets or sets the color of minor lines (DarkGray by default) */
+            minorLineColor: string;
+            /** Gets or sets the tickness of major lines (2 by default) */
+            majorLineTickness: number;
+            /** Gets or sets the color of major lines (White by default) */
+            majorLineColor: string;
+            /** Gets or sets the frequency of major lines (default is 1 every 5 minor lines)*/
+            majorLineFrequency: number;
+            /**
+                * Creates a new GridDisplayRectangle
+                * @param name defines the control name
+                */
+            constructor(name?: string | undefined);
+            _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+            protected _getTypeName(): string;
+    }
+}
+declare module BABYLON.GUI {
     /**
       * Forcing an export so that this code will execute
       * @hidden

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js.map


+ 62 - 0
dist/preview release/gui/babylon.gui.module.d.ts

@@ -43,6 +43,7 @@ declare module 'babylonjs-gui/2D/controls' {
     export * from "babylonjs-gui/2D/controls/virtualKeyboard";
     export * from "babylonjs-gui/2D/controls/slider";
     export * from "babylonjs-gui/2D/controls/rectangle";
+    export * from "babylonjs-gui/2D/controls/displayGrid";
     export * from "babylonjs-gui/2D/controls/statics";
 }
 
@@ -1956,6 +1957,38 @@ declare module 'babylonjs-gui/2D/controls/rectangle' {
     }
 }
 
+declare module 'babylonjs-gui/2D/controls/displayGrid' {
+    import { Control } from "babylonjs-gui/2D/controls";
+    import { Measure } from "babylonjs-gui/2D";
+    /** Class used to render a grid  */
+    export class DisplayGrid extends Control {
+            name?: string | undefined;
+            /** Gets or sets background color (Black by default) */
+            background: string;
+            /** Gets or sets the width of each cell (20 by default) */
+            cellWidth: number;
+            /** Gets or sets the height of each cell (20 by default) */
+            cellHeight: number;
+            /** Gets or sets the tickness of minor lines (1 by default) */
+            minorLineTickness: number;
+            /** Gets or sets the color of minor lines (DarkGray by default) */
+            minorLineColor: string;
+            /** Gets or sets the tickness of major lines (2 by default) */
+            majorLineTickness: number;
+            /** Gets or sets the color of major lines (White by default) */
+            majorLineColor: string;
+            /** Gets or sets the frequency of major lines (default is 1 every 5 minor lines)*/
+            majorLineFrequency: number;
+            /**
+                * Creates a new GridDisplayRectangle
+                * @param name defines the control name
+                */
+            constructor(name?: string | undefined);
+            _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+            protected _getTypeName(): string;
+    }
+}
+
 declare module 'babylonjs-gui/2D/controls/statics' {
     /**
       * Forcing an export so that this code will execute
@@ -4335,6 +4368,35 @@ declare module BABYLON.GUI {
     }
 }
 declare module BABYLON.GUI {
+    /** Class used to render a grid  */
+    export class DisplayGrid extends Control {
+            name?: string | undefined;
+            /** Gets or sets background color (Black by default) */
+            background: string;
+            /** Gets or sets the width of each cell (20 by default) */
+            cellWidth: number;
+            /** Gets or sets the height of each cell (20 by default) */
+            cellHeight: number;
+            /** Gets or sets the tickness of minor lines (1 by default) */
+            minorLineTickness: number;
+            /** Gets or sets the color of minor lines (DarkGray by default) */
+            minorLineColor: string;
+            /** Gets or sets the tickness of major lines (2 by default) */
+            majorLineTickness: number;
+            /** Gets or sets the color of major lines (White by default) */
+            majorLineColor: string;
+            /** Gets or sets the frequency of major lines (default is 1 every 5 minor lines)*/
+            majorLineFrequency: number;
+            /**
+                * Creates a new GridDisplayRectangle
+                * @param name defines the control name
+                */
+            constructor(name?: string | undefined);
+            _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+            protected _getTypeName(): string;
+    }
+}
+declare module BABYLON.GUI {
     /**
       * Forcing an export so that this code will execute
       * @hidden

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js.map


File diff suppressed because it is too large
+ 3 - 3
dist/preview release/viewer/babylon.viewer.js


File diff suppressed because it is too large
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


+ 1 - 0
dist/preview release/what's new.md

@@ -86,6 +86,7 @@
 - Added falloff type per light to prevent material only inconsistencies [Issue 4148](https://github.com/BabylonJS/Babylon.js/issues/4148) ([sebavan](http://www.github.com/sebavan))
 - Added WeightedSound; selects one from many Sounds with random weight for playback. ([najadojo](https://github.com/najadojo))
 - Added HDR support to ReflectionProbe ([Deltakosh](https://github.com/deltakosh))
+- Added Video Recorder [Issue 4708](https://github.com/BabylonJS/Babylon.js/issues/4708) ([sebavan](http://www.github.com/sebavan))
 
 ### glTF Loader
 

+ 189 - 0
gui/src/2D/controls/displayGrid.ts

@@ -0,0 +1,189 @@
+
+import { Control } from ".";
+import { Measure } from "..";
+
+/** Class used to render a grid  */
+export class DisplayGrid extends Control {
+    private _cellWidth = 20;
+    private _cellHeight = 20;
+
+    private _minorLineTickness = 1;
+    private _minorLineColor = "DarkGray";
+
+    private _majorLineTickness = 2;
+    private _majorLineColor = "White";
+
+    private _majorLineFrequency = 5;
+
+    private _background = "Black";
+
+    /** Gets or sets background color (Black by default) */
+    public get background(): string {
+        return this._background;
+    }
+
+    public set background(value: string) {
+        if (this._background === value) {
+            return;
+        }
+
+        this._background = value;
+        this._markAsDirty();
+    }    
+
+    /** Gets or sets the width of each cell (20 by default) */
+    public get cellWidth(): number {
+        return this._cellWidth;
+    }
+
+    public set cellWidth(value: number) {
+        this._cellWidth = value;
+
+        this._markAsDirty();
+    }
+
+    /** Gets or sets the height of each cell (20 by default) */
+    public get cellHeight(): number {
+        return this._cellHeight;
+    }
+
+    public set cellHeight(value: number) {
+        this._cellHeight = value;
+
+        this._markAsDirty();
+    }
+
+    /** Gets or sets the tickness of minor lines (1 by default) */
+    public get minorLineTickness(): number {
+        return this._minorLineTickness;
+    }
+
+    public set minorLineTickness(value: number) {
+        this._minorLineTickness = value;
+
+        this._markAsDirty();
+    }
+
+    /** Gets or sets the color of minor lines (DarkGray by default) */
+    public get minorLineColor(): string {
+        return this._minorLineColor;
+    }
+
+    public set minorLineColor(value: string) {
+        this._minorLineColor = value;
+
+        this._markAsDirty();
+    }    
+
+    /** Gets or sets the tickness of major lines (2 by default) */
+    public get majorLineTickness(): number {
+        return this._majorLineTickness;
+    }
+
+    public set majorLineTickness(value: number) {
+        this._majorLineTickness = value;
+
+        this._markAsDirty();
+    }
+
+    /** Gets or sets the color of major lines (White by default) */
+    public get majorLineColor(): string {
+        return this._majorLineColor;
+    }
+
+    public set majorLineColor(value: string) {
+        this._majorLineColor = value;
+
+        this._markAsDirty();
+    }    
+
+    /** Gets or sets the frequency of major lines (default is 1 every 5 minor lines)*/
+    public get majorLineFrequency(): number {
+        return this._majorLineFrequency;
+    }
+
+    public set majorLineFrequency(value: number) {
+        this._majorLineFrequency = value;
+
+        this._markAsDirty();
+    }
+
+    /**
+     * Creates a new GridDisplayRectangle
+     * @param name defines the control name
+     */
+    constructor(public name?: string) {
+        super(name);
+    }
+
+    public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
+        context.save();
+        
+        this._applyStates(context);
+
+        if (this._processMeasures(parentMeasure, context)) {
+
+            if (this._background) {
+                context.fillStyle = this._background;
+                context.fillRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
+            }
+
+            let cellCountX = this._currentMeasure.width / this._cellWidth;
+            let cellCountY = this._currentMeasure.height / this._cellHeight;
+
+            // Minor lines
+            context.strokeStyle = this._minorLineColor;
+            context.lineWidth = this._minorLineTickness;        
+
+            const left = this._currentMeasure.left + this._currentMeasure.width / 2;
+
+            for (var x = -cellCountX / 2; x < cellCountX / 2; x++) {
+                const cellX = left + x * this.cellWidth;
+
+                context.beginPath();
+                context.moveTo(cellX, this._currentMeasure.top);
+                context.lineTo(cellX, this._currentMeasure.top + this._currentMeasure.height);
+                
+                context.stroke();                
+            }
+
+            const top = this._currentMeasure.top + this._currentMeasure.height / 2;
+
+            for (var y = -cellCountY / 2; y < cellCountY / 2; y++) {
+                const cellY = top + y * this.cellHeight;
+
+                context.beginPath();
+                context.moveTo(this._currentMeasure.left, cellY);
+                context.lineTo(this._currentMeasure.left + this._currentMeasure.width, cellY);
+                context.stroke();
+            }
+
+            // Major lines
+            context.strokeStyle = this._majorLineColor;
+            context.lineWidth = this._majorLineTickness;        
+
+            for (var x = -cellCountX / 2 + this._majorLineFrequency; x < cellCountX / 2; x += this._majorLineFrequency) {
+                let cellX = left + x * this.cellWidth;
+
+                context.beginPath();    
+                context.moveTo(cellX, this._currentMeasure.top);
+                context.lineTo(cellX, this._currentMeasure.top + this._currentMeasure.height);
+                context.stroke();
+            }
+
+            for (var y = -cellCountY / 2 + this._majorLineFrequency; y < cellCountY / 2; y += this._majorLineFrequency) {
+                let cellY = top + y * this.cellHeight;
+                context.moveTo(this._currentMeasure.left, cellY);
+                context.lineTo(this._currentMeasure.left + this._currentMeasure.width, cellY);
+                context.closePath();
+                context.stroke();
+            }
+        }
+
+        context.restore();
+    }
+
+    protected _getTypeName(): string {
+        return "DisplayGrid";
+    }
+}    

+ 0 - 120
gui/src/2D/controls/gridDisplay.ts

@@ -1,120 +0,0 @@
-
-import { Control } from ".";
-import { Measure } from "..";
-
-/** Class used to render a grid  */
-export class GridDisplay extends Control {
-    private _cellWidth = 10;
-    private _cellHeight = 10;
-    private _minorLineTickness = 1;
-    private _minorLineColor = "DarkGray";
-    private _background = "Black";
-
-    /** Gets or sets background color (Black by default) */
-    public get background(): string {
-        return this._background;
-    }
-
-    public set background(value: string) {
-        if (this._background === value) {
-            return;
-        }
-
-        this._background = value;
-        this._markAsDirty();
-    }    
-
-    /** Gets or sets the width of each cell (10 by default) */
-    public get cellWidth(): number {
-        return this._cellWidth;
-    }
-
-    public set cellWidth(value: number) {
-        this._cellWidth = value;
-
-        this._markAsDirty();
-    }
-
-    /** Gets or sets the height of each cell (10 by default) */
-    public get cellHeight(): number {
-        return this._cellHeight;
-    }
-
-    public set cellHeight(value: number) {
-        this._cellHeight = value;
-
-        this._markAsDirty();
-    }
-
-    /** Gets or sets the tickness of minor lines (1 by default) */
-    public get minorLineTickness(): number {
-        return this._minorLineTickness;
-    }
-
-    public set minorLineTickness(value: number) {
-        this._minorLineTickness = value;
-
-        this._markAsDirty();
-    }
-
-    /** Gets or sets the color of minor lines (DarkGray by default) */
-    public get minorLineColor(): string {
-        return this._minorLineColor;
-    }
-
-    public set minorLineColor(value: string) {
-        this._minorLineColor = value;
-
-        this._markAsDirty();
-    }    
-
-    /**
-     * Creates a new GridDisplayRectangle
-     * @param name defines the control name
-     */
-    constructor(public name?: string) {
-        super(name);
-    }
-
-    public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
-        context.save();
-        
-        this._applyStates(context);
-
-        if (this._processMeasures(parentMeasure, context)) {
-
-            context.fillStyle = this._background;
-            context.fillRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
-
-            const cellCountX = this._currentMeasure.width / this._cellWidth;
-            const cellCountY = this._currentMeasure.height / this._cellHeight;
-
-            context.strokeStyle = this._minorLineColor;
-            context.lineWidth = this._minorLineTickness;        
-
-            const left = this._currentMeasure.left + this._currentMeasure.width / 2;
-
-            for (var x = -cellCountX / 2; x < cellCountX / 2; x++) {
-                const cellX = left + x * this.cellWidth;
-                context.moveTo(cellX, this._currentMeasure.top);
-                context.lineTo(cellX, this._currentMeasure.top + this._currentMeasure.height);
-                context.stroke();
-            }
-
-            const top = this._currentMeasure.top + this._currentMeasure.height / 2;
-
-            for (var y = -cellCountY / 2; y < cellCountY / y; x++) {
-                const cellY = top + y * this.cellHeight;
-                context.moveTo(this._currentMeasure.left, cellY);
-                context.lineTo(this._currentMeasure.left + this._currentMeasure.width, cellY);
-                context.stroke();
-            }            
-        }
-
-        context.restore();
-    }
-
-    protected _getTypeName(): string {
-        return "GridDisplay";
-    }
-}    

+ 1 - 1
gui/src/2D/controls/index.ts

@@ -16,6 +16,6 @@ export * from "./textBlock";
 export * from "./virtualKeyboard";
 export * from "./slider";
 export * from "./rectangle";
-export * from "./gridDisplay";
+export * from "./displayGrid";
 
 export * from "./statics";

+ 26 - 1
inspector/src/tabs/ToolsTab.ts

@@ -1,4 +1,4 @@
-import { CubeTexture, Engine, EnvironmentTextureTools, Nullable, Scene, Tools } from "babylonjs";
+import { CubeTexture, Engine, EnvironmentTextureTools, Nullable, Scene, Tools, VideoRecorder } from "babylonjs";
 import { Helpers } from "../helpers/Helpers";
 import { Inspector } from "../Inspector";
 import { Tab } from "./Tab";
@@ -10,6 +10,8 @@ export class ToolsTab extends Tab {
 
     private _scene: Scene;
 
+    private _videoRecorder: Nullable<VideoRecorder> = null;
+
     constructor(tabbar: TabBar, insp: Inspector) {
         super(tabbar, 'Tools');
 
@@ -138,6 +140,29 @@ export class ToolsTab extends Tab {
                 }
             };
             elemValue.appendChild(inputElement);
+
+            if (VideoRecorder.IsSupported(this._scene.getEngine())) {
+                let videoRecorderElement = Inspector.DOCUMENT.createElement('input');
+                videoRecorderElement.value = "Start Recording Video";
+                videoRecorderElement.type = "button";
+                videoRecorderElement.className = "tool-input";
+                videoRecorderElement.onclick = () => {
+                    if (!this._videoRecorder) {
+                        this._videoRecorder = new VideoRecorder(this._scene.getEngine());
+                    }
+
+                    if (this._videoRecorder!.isRecording) {
+                        this._videoRecorder!.stopRecording();
+                    }
+                    else {
+                        videoRecorderElement.value = "Stop Recording Video";
+                        this._videoRecorder!.startRecording().then(() => {
+                            videoRecorderElement.value = "Start Recording Video";
+                        });
+                    }
+                };
+                elemValue.appendChild(videoRecorderElement);
+            }
         }
     }
 

+ 234 - 0
src/Tools/babylon.videoRecorder.ts

@@ -0,0 +1,234 @@
+interface HTMLCanvasElement {
+    /** Track wether a record is in progress */
+    isRecording: boolean;
+    /** Capture Stream method defined by some browsers */
+    captureStream(fps?: number): MediaStream;
+}
+
+interface MediaRecorder {
+    /** Starts recording */
+    start(timeSlice: number): void;
+    /** Stops recording */
+    stop(): void;
+
+    /** Event raised when an error arised. */
+    onerror: (event: ErrorEvent) => void;
+    /** Event raised when the recording stops. */
+    onstop: (event:Event) => void;
+    /** Event raised when a new chunk  of data is available and should be tracked. */
+    ondataavailable: (event: Event) => void;
+}
+
+interface MediaRecorderOptions {
+    /** The mime type you want to use as the recording container for the new MediaRecorder */
+    mimeType?: string,
+    /** The chosen bitrate for the audio component of the media. */
+    audioBitsPerSecond?: number,
+    /** The chosen bitrate for the video component of the media. */
+    videoBitsPerSecond?: number,
+    /** The chosen bitrate for the audio and video components of the media. This can be specified instead of the above two properties. If this is specified along with one or the other of the above properties, this will be used for the one that isn't specified. */
+    bitsPerSecond?: number,
+}
+
+interface MediaRecorderConstructor {
+    /**
+     * A reference to the prototype.
+     */
+    readonly prototype: MediaRecorder;
+
+    /**
+     * Creates a new MediaRecorder.
+     * @param stream Defines the stream to record.
+     * @param options Defines the options for the recorder available in the type MediaRecorderOptions.
+     */
+    new(stream: MediaStream, options?: MediaRecorderOptions): MediaRecorder;
+}
+
+/**
+ * MediaRecoreder object available in some browsers.
+ */
+declare var MediaRecorder: MediaRecorderConstructor;
+
+module BABYLON {
+    /**
+     * This represents the different options avilable for the video capture.
+     */
+    export interface VideoRecorderOptions {
+        /** Defines the mime type of the video */
+        mimeType: string,
+        /** Defines the video the video should be recorded at */
+        fps: number,
+        /** Defines the chunk size for the recording data */
+        recordChunckSize: number
+    }
+
+    /** 
+     * This can helps recording videos from BabylonJS.
+     * This is based on the available WebRTC functionalities of the browser.
+     * 
+     * @see http://doc.babylonjs.com/how_to/render_scene_on_a_video
+     */
+    export class VideoRecorder {
+
+        private static readonly _defaultOptions = {
+            mimeType: "video/webm",
+            fps: 25,
+            recordChunckSize: 3000
+        };
+
+        /**
+         * Returns wehther or not the VideoRecorder is available in your browser.
+         * @param engine Defines the Babylon Engine to check the support for
+         * @returns true if supported otherwise false
+         */
+        public static IsSupported(engine: Engine): boolean {
+            const canvas = engine.getRenderingCanvas();
+            return (!!canvas && typeof canvas.captureStream === "function");
+        }
+
+        private readonly _options: VideoRecorderOptions;
+        private _canvas: Nullable<HTMLCanvasElement>;
+        private _mediaRecorder: Nullable<MediaRecorder>;
+
+        private _recordedChunks: any[];
+        private _fileName: Nullable<string>;
+        private _resolve: Nullable<(blob: Blob) => void>;
+        private _reject: Nullable<(error: any) => void>;
+
+        /**
+         * True wether a recording is already in progress.
+         */
+        public get isRecording(): boolean {
+            return !!this._canvas && this._canvas.isRecording;
+        }
+
+        /**
+         * Create a new VideoCapture object which can help converting what you see in Babylon to
+         * a video file.
+         * @param engine Defines the BabylonJS Engine you wish to record
+         * @param options Defines options that can be used to customized the capture
+         */
+        constructor(engine: Engine, options: Nullable<VideoRecorderOptions> = null) {
+            if (!VideoRecorder.IsSupported(engine)) {
+                throw "Your browser does not support recording so far.";
+            }
+
+            const canvas = engine.getRenderingCanvas();
+            if (!canvas) {
+                throw "The babylon engine must have a canvas to be recorded";
+            }
+
+            this._canvas = canvas;
+            this._canvas.isRecording = false;
+
+            this._options = {
+                ...VideoRecorder._defaultOptions,
+                ...options
+            }
+
+            const stream = this._canvas.captureStream(this._options.fps);
+            this._mediaRecorder = new MediaRecorder(stream, { mimeType: this._options.mimeType });
+            this._mediaRecorder.ondataavailable = this._handleDataAvailable.bind(this);
+            this._mediaRecorder.onerror = this._handleError.bind(this);
+            this._mediaRecorder.onstop = this._handleStop.bind(this);
+        }
+
+        /**
+         * Stops the current recording before the default capture timeout passed in the startRecording
+         * functions.
+         */
+        public stopRecording(): void {
+            if (!this._canvas || !this._mediaRecorder) {
+                return;
+            }
+
+            if (!this.isRecording) {
+                return;
+            }
+
+            this._canvas.isRecording = false;
+            this._mediaRecorder.stop();
+        }
+
+        /**
+         * Starts recording the canvas for a max duration specified in parameters.
+         * @param fileName Defines the name of the file to be downloaded when the recording stop. If null no automatic download will start and you can rely on the promise to get the data back.
+         * @param maxDuration Defines the maximum recording time in seconds. 
+         * It default to 7 seconds. A value of zero will not stop automatically, you would need to call stopRecording manually.
+         * @return a promise callback at the end of the recording with the video data in Blob.
+         */
+        public startRecording(fileName: Nullable<string> = "babylonjs.webm", maxDuration = 7): Promise<Blob> {
+            if (!this._canvas || !this._mediaRecorder) {
+                throw "Recorder has already been disposed";
+            }
+
+            if (this.isRecording) {
+                throw "Recording already in progress";
+            }
+
+            if (maxDuration > 0) {
+                setTimeout(() => {
+                    this.stopRecording();
+                }, maxDuration * 1000);
+            }
+
+            this._fileName = fileName;
+            this._recordedChunks = [];
+            this._resolve = null;
+            this._reject = null;
+            
+            this._canvas.isRecording = true;
+            this._mediaRecorder.start(this._options.recordChunckSize);
+
+            return new Promise<Blob>((resolve, reject) => {
+                this._resolve = resolve;
+                this._reject = reject;
+            });
+        }
+
+        /**
+         * Releases internal resources used during the recording.
+         */
+        public dispose() {
+            this._canvas = null;
+            this._mediaRecorder = null;
+
+            this._recordedChunks = [];
+            this._fileName = null;
+            this._resolve = null;
+            this._reject = null;
+        }
+
+        private _handleDataAvailable(event: any): void {
+            if (event.data.size > 0) {
+                this._recordedChunks.push(event.data);
+            }
+        }
+
+        private _handleError(event: ErrorEvent): void {
+            this.stopRecording();
+
+            if (this._reject) {
+                this._reject(event.error);
+            }
+            else {
+                throw new event.error;
+            }
+        }
+
+        private _handleStop(): void {
+            this.stopRecording();
+
+            const superBuffer = new Blob(this._recordedChunks);
+            if (this._resolve) {
+                this._resolve(superBuffer);
+            }
+
+            window.URL.createObjectURL(superBuffer);
+
+            if (this._fileName) {
+                Tools.Download(superBuffer, this._fileName);
+            }
+        }
+    }
+}