babylon.videoTexture.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. module BABYLON {
  2. export class VideoTexture extends Texture {
  3. public video: HTMLVideoElement;
  4. private _autoLaunch = true;
  5. private _lastUpdate: number;
  6. private _generateMipMaps: boolean
  7. private _setTextureReady: () => void;
  8. private _engine: Engine;
  9. /**
  10. * Creates a video texture.
  11. * Sample : https://doc.babylonjs.com/tutorials/01._Advanced_Texturing
  12. * @param {Array} urlsOrVideo can be used to provide an array of urls or an already setup HTML video element.
  13. * @param {BABYLON.Scene} scene is obviously the current scene.
  14. * @param {boolean} generateMipMaps can be used to turn on mipmaps (Can be expensive for videoTextures because they are often updated).
  15. * @param {boolean} invertY is false by default but can be used to invert video on Y axis
  16. * @param {number} samplingMode controls the sampling method and is set to TRILINEAR_SAMPLINGMODE by default
  17. */
  18. constructor(name: string, urlsOrVideo: string[] | HTMLVideoElement, scene: Scene, generateMipMaps = false, invertY = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
  19. super(null, scene, !generateMipMaps, invertY);
  20. var urls: Nullable<string[]> = null;
  21. this.name = name;
  22. if (urlsOrVideo instanceof HTMLVideoElement) {
  23. this.video = <any>urlsOrVideo;
  24. } else {
  25. urls = urlsOrVideo;
  26. this.video = document.createElement("video");
  27. this.video.autoplay = false;
  28. this.video.loop = true;
  29. Tools.SetCorsBehavior(urls, this.video);
  30. }
  31. this._engine = (<Scene>this.getScene()).getEngine();
  32. this._generateMipMaps = generateMipMaps;
  33. this._samplingMode = samplingMode;
  34. if (!this._engine.needPOTTextures ||(Tools.IsExponentOfTwo(this.video.videoWidth) && Tools.IsExponentOfTwo(this.video.videoHeight))) {
  35. this.wrapU = Texture.WRAP_ADDRESSMODE;
  36. this.wrapV = Texture.WRAP_ADDRESSMODE;
  37. } else {
  38. this.wrapU = Texture.CLAMP_ADDRESSMODE;
  39. this.wrapV = Texture.CLAMP_ADDRESSMODE;
  40. this._generateMipMaps = false;
  41. }
  42. if (urls) {
  43. this.video.addEventListener("canplay", () => {
  44. this._createTexture();
  45. });
  46. urls.forEach(url => {
  47. var source = document.createElement("source");
  48. source.src = url;
  49. this.video.appendChild(source);
  50. });
  51. } else {
  52. this._createTexture();
  53. }
  54. this._lastUpdate = Tools.Now;
  55. }
  56. private __setTextureReady(): void {
  57. if (this._texture) {
  58. this._texture.isReady = true;
  59. }
  60. }
  61. private _createTexture(): void {
  62. this._texture = this._engine.createDynamicTexture(this.video.videoWidth, this.video.videoHeight, this._generateMipMaps, this._samplingMode);
  63. if (this._autoLaunch) {
  64. this._autoLaunch = false;
  65. this.video.play();
  66. }
  67. this._setTextureReady = this.__setTextureReady.bind(this);
  68. this.video.addEventListener("playing", this._setTextureReady);
  69. }
  70. public _rebuild(): void {
  71. this.update();
  72. }
  73. public update(): boolean {
  74. var now = Tools.Now;
  75. if (now - this._lastUpdate < 15 || this.video.readyState !== this.video.HAVE_ENOUGH_DATA) {
  76. return false;
  77. }
  78. this._lastUpdate = now;
  79. this._engine.updateVideoTexture(this._texture, this.video, this._invertY);
  80. return true;
  81. }
  82. public dispose(): void {
  83. super.dispose();
  84. this.video.removeEventListener("playing", this._setTextureReady);
  85. }
  86. public static CreateFromWebCam(scene: Scene, onReady: (videoTexture: VideoTexture) => void, constraints: {
  87. minWidth: number,
  88. maxWidth: number,
  89. minHeight: number,
  90. maxHeight: number,
  91. deviceId: string
  92. }): void {
  93. var video = document.createElement("video");
  94. var constraintsDeviceId;
  95. if (constraints && constraints.deviceId){
  96. constraintsDeviceId = {
  97. exact: constraints.deviceId
  98. }
  99. }
  100. navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
  101. window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
  102. if (navigator.getUserMedia) {
  103. navigator.getUserMedia({
  104. video: {
  105. deviceId: constraintsDeviceId,
  106. width: {
  107. min: (constraints && constraints.minWidth) || 256,
  108. max: (constraints && constraints.maxWidth) || 640
  109. },
  110. height: {
  111. min: (constraints && constraints.minHeight) || 256,
  112. max: (constraints && constraints.maxHeight) || 480
  113. }
  114. }
  115. }, (stream: any) => {
  116. if (video.mozSrcObject !== undefined) { // hack for Firefox < 19
  117. video.mozSrcObject = stream;
  118. } else {
  119. video.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
  120. }
  121. video.play();
  122. if (onReady) {
  123. onReady(new BABYLON.VideoTexture("video", video, scene, true, true));
  124. }
  125. }, function (e: DOMException) {
  126. Tools.Error(e.name);
  127. });
  128. }
  129. }
  130. }
  131. }