babylon.videoTexture.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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. if (this._texture === undefined){
  45. this._createTexture();
  46. }
  47. });
  48. urls.forEach(url => {
  49. var source = document.createElement("source");
  50. source.src = url;
  51. this.video.appendChild(source);
  52. });
  53. } else {
  54. this._createTexture();
  55. }
  56. this._lastUpdate = Tools.Now;
  57. }
  58. private __setTextureReady(): void {
  59. if (this._texture) {
  60. this._texture.isReady = true;
  61. }
  62. }
  63. private _createTexture(): void {
  64. this._texture = this._engine.createDynamicTexture(this.video.videoWidth, this.video.videoHeight, this._generateMipMaps, this._samplingMode);
  65. if (this._autoLaunch) {
  66. this._autoLaunch = false;
  67. this.video.play();
  68. }
  69. this._setTextureReady = this.__setTextureReady.bind(this);
  70. this.video.addEventListener("playing", this._setTextureReady);
  71. }
  72. public _rebuild(): void {
  73. this.update();
  74. }
  75. public update(): boolean {
  76. var now = Tools.Now;
  77. if (now - this._lastUpdate < 15 || this.video.readyState !== this.video.HAVE_ENOUGH_DATA) {
  78. return false;
  79. }
  80. this._lastUpdate = now;
  81. this._engine.updateVideoTexture(this._texture, this.video, this._invertY);
  82. return true;
  83. }
  84. public dispose(): void {
  85. super.dispose();
  86. this.video.removeEventListener("playing", this._setTextureReady);
  87. }
  88. public static CreateFromWebCam(scene: Scene, onReady: (videoTexture: VideoTexture) => void, constraints: {
  89. minWidth: number,
  90. maxWidth: number,
  91. minHeight: number,
  92. maxHeight: number,
  93. deviceId: string
  94. }): void {
  95. var video = document.createElement("video");
  96. var constraintsDeviceId;
  97. if (constraints && constraints.deviceId) {
  98. constraintsDeviceId = {
  99. exact: constraints.deviceId
  100. }
  101. }
  102. navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
  103. window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
  104. if (navigator.getUserMedia) {
  105. navigator.getUserMedia({
  106. video: {
  107. deviceId: constraintsDeviceId,
  108. width: {
  109. min: (constraints && constraints.minWidth) || 256,
  110. max: (constraints && constraints.maxWidth) || 640
  111. },
  112. height: {
  113. min: (constraints && constraints.minHeight) || 256,
  114. max: (constraints && constraints.maxHeight) || 480
  115. }
  116. }
  117. }, (stream: any) => {
  118. if (video.mozSrcObject !== undefined) { // hack for Firefox < 19
  119. video.mozSrcObject = stream;
  120. } else {
  121. video.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
  122. }
  123. video.play();
  124. if (onReady) {
  125. onReady(new VideoTexture("video", video, scene, true, true));
  126. }
  127. }, function (e: DOMException) {
  128. Tools.Error(e.name);
  129. });
  130. }
  131. }
  132. }
  133. }