Forráskód Böngészése

feat(master): add precache for video

yonghaohu 5 éve
szülő
commit
23bb47b393
5 módosított fájl, 372 hozzáadás és 274 törlés
  1. 2 0
      web/README.md
  2. 200 154
      web/dist/vap.js
  3. 0 0
      web/dist/vap.min.js
  4. 1 1
      web/package-lock.json
  5. 169 119
      web/src/video.js

+ 2 - 0
web/README.md

@@ -37,6 +37,8 @@ config | 配置json对象(详情见下文)
 width | 宽度
 height | 高度
 fps | 动画播放帧数(可用:15、20、30、60)
+mute | 是否对视频静音
+precache | 是否预加载视频资源(默认关闭,即边下边播)
 ext(无固定名) | 融合参数(和json配置文件中保持一致)
 
 ### 二、素材

+ 200 - 154
web/dist/vap.js

@@ -333,165 +333,211 @@
    * limitations under the License.
    */
   var VapVideo = function () {
-      function VapVideo(options) {
-          classCallCheck(this, VapVideo);
+    function VapVideo(options) {
+      classCallCheck(this, VapVideo);
 
-          if (!options.container || !options.src) {
-              return console.warn('[Alpha video]: options container and src cannot be empty!');
-          }
-          this.options = Object.assign({
-              // 视频url
-              src: '',
-              // 循环播放
-              loop: false,
-              fps: 20,
-              // 视频宽度
-              width: 375,
-              // 视频高度
-              height: 375,
-              // 容器
-              container: null,
-              config: ''
-          }, options);
-          this.fps = 20;
-          this.requestAnim = this.requestAnimFunc(this.fps);
-          this.container = this.options.container;
-          if (!this.options.src || !this.options.config || !this.options.container) {
-              console.error('参数出错:src(视频地址)、config(配置文件地址)、container(dom容器)');
-          } else {
-              // 创建video
-              this.initVideo();
-          }
+      if (!options.container || !options.src) {
+        return console.warn('[Alpha video]: options container and src cannot be empty!');
       }
+      this.options = Object.assign({
+        // 视频url
+        src: '',
+        // 循环播放
+        loop: false,
+        fps: 20,
+        // 视频宽度
+        width: 375,
+        // 视频高度
+        height: 375,
+        // 容器
+        container: null,
+        config: ''
+      }, options);
+      this.fps = 20;
+      this.requestAnim = this.requestAnimFunc(this.fps);
+      this.container = this.options.container;
+      if (!this.options.src || !this.options.config || !this.options.container) {
+        console.error('参数出错:src(视频地址)、config(配置文件地址)、container(dom容器)');
+      } else {
+        // 创建video
+        this.initVideo();
+      }
+    }
 
-      createClass(VapVideo, [{
-          key: 'initVideo',
-          value: function initVideo() {
-              var _this = this;
-
-              var options = this.options;
-              // 创建video
-              var video = this.video = document.createElement('video');
-              video.crossOrigin = 'anonymous';
-              video.autoplay = false;
-              video.preload = 'auto';
-              video.autoload = true;
-              // video.muted = true
-              // video.volume = 0
-              video.style.display = 'none';
-              video.src = options.src;
-              video.loop = !!options.loop;
-              // 这里要插在body上,避免container移动带来无法播放的问题
-              document.body.appendChild(this.video);
-              // 绑定事件
-              this.events = {};['playing', 'pause', 'ended', 'error'].forEach(function (item) {
-                  _this.on(item, _this['on' + item].bind(_this));
-              });
-              video.load();
-          }
-      }, {
-          key: 'drawFrame',
-          value: function drawFrame() {
-              this._drawFrame = this._drawFrame || this.drawFrame.bind(this);
-              this.animId = this.requestAnim(this._drawFrame);
-          }
-      }, {
-          key: 'play',
-          value: function play() {
-              var _this2 = this;
-
-              var prom = this.video && this.video.play();
-
-              if (prom && prom.then) {
-                  prom.catch(function (e) {
-                      if (!_this2.video) {
-                          return;
-                      }
-                      _this2.video.muted = true;
-                      _this2.video.volume = 0;
-                      _this2.video.play().catch(function (e) {
-  (_this2.events.error || []).forEach(function (item) {
-                              item(e);
-                          });
-                      });
-                  });
-              }
-          }
-      }, {
-          key: 'requestAnimFunc',
-          value: function requestAnimFunc() {
-              var me = this;
-              if (window.requestAnimationFrame) {
-                  var index = -1;
-                  return function (cb) {
-                      index++;
-                      return requestAnimationFrame(function () {
-                          if (!(index % (60 / me.fps))) {
-                              return cb();
-                          }
-                          me.animId = me.requestAnim(cb);
-                      });
-                  };
-              }
-              return function (cb) {
-                  return setTimeout(cb, 1000 / me.fps);
-              };
-          }
-      }, {
-          key: 'cancelRequestAnimation',
-          value: function cancelRequestAnimation() {
-              if (window.cancelAnimationFrame) {
-                  cancelAnimationFrame(this.animId);
-              }
-              clearTimeout(this.animId);
-          }
-      }, {
-          key: 'destroy',
-          value: function destroy() {
-              if (this.video) {
-                  this.video.parentNode && this.video.parentNode.removeChild(this.video);
-                  this.video = null;
+    createClass(VapVideo, [{
+      key: 'precacheSource',
+      value: function precacheSource(source) {
+        var URL = window.webkitURL || window.URL;
+        return new Promise(function (resolve, reject) {
+          var xhr = new XMLHttpRequest();
+          xhr.open("GET", source, true);
+          xhr.responseType = "blob";
+          xhr.onload = function () {
+            if (xhr.status === 200 || xhr.status === 304) {
+              var res = xhr.response;
+              if (/iphone|ipad|ipod/i.test(navigator.userAgent)) {
+                var fileReader = new FileReader();
+                fileReader.onloadend = function () {
+                  var raw = atob(fileReader.result.slice(fileReader.result.indexOf(",") + 1));
+                  var buf = Array(raw.length);
+                  for (var d = 0; d < raw.length; d++) {
+                    buf[d] = raw.charCodeAt(d);
+                  }
+                  var arr = new Uint8Array(buf);
+                  var blob = new Blob([arr], { type: "video/mp4" });
+                  resolve(URL.createObjectURL(blob));
+                };
+                fileReader.readAsDataURL(xhr.response);
+              } else {
+                resolve(URL.createObjectURL(res));
               }
-              this.cancelRequestAnimation(this.animId);
-          }
-      }, {
-          key: 'clear',
-          value: function clear() {
-              this.destroy();
-          }
-      }, {
-          key: 'on',
-          value: function on(event, callback) {
-              var cbs = this.events[event] || [];
-              cbs.push(callback);
-              this.events[event] = cbs;
-              this.video.addEventListener(event, callback);
-              return this;
-          }
-      }, {
-          key: 'onplaying',
-          value: function onplaying() {
-              if (!this.firstPlaying) {
-                  this.firstPlaying = true;
-                  this.drawFrame();
+            } else {
+              reject(new Error("http response invalid" + xhr.status));
+            }
+          };
+          xhr.send();
+        });
+      }
+    }, {
+      key: 'initVideo',
+      value: function initVideo() {
+        var _this = this;
+
+        var options = this.options;
+        // 创建video
+        var video = this.video = document.createElement('video');
+        video.crossOrigin = 'anonymous';
+        video.autoplay = false;
+        video.preload = 'auto';
+        video.autoload = true;
+        if (options.mute) {
+          video.muted = true;
+          video.volume = 0;
+        }
+        video.style.display = 'none';
+        video.loop = !!options.loop;
+        if (options.precache) {
+          this.precacheSource(options.src).then(function (blob) {
+            console.log("sample precached.");
+            video.src = blob;
+            document.body.appendChild(video);
+          }).catch(function (e) {
+            console.error(e);
+          });
+        } else {
+          video.src = options.src;
+          // 这里要插在body上,避免container移动带来无法播放的问题
+          document.body.appendChild(this.video);
+          video.load();
+        }
+        // 绑定事件
+        this.events = {};['playing', 'pause', 'ended', 'error'].forEach(function (item) {
+          _this.on(item, _this['on' + item].bind(_this));
+        });
+      }
+    }, {
+      key: 'drawFrame',
+      value: function drawFrame() {
+        this._drawFrame = this._drawFrame || this.drawFrame.bind(this);
+        this.animId = this.requestAnim(this._drawFrame);
+      }
+    }, {
+      key: 'play',
+      value: function play() {
+        var _this2 = this;
+
+        var prom = this.video && this.video.play();
+
+        if (prom && prom.then) {
+          prom.catch(function (e) {
+            if (!_this2.video) {
+              return;
+            }
+            _this2.video.muted = true;
+            _this2.video.volume = 0;
+            _this2.video.play().catch(function (e) {
+  (_this2.events.error || []).forEach(function (item) {
+                item(e);
+              });
+            });
+          });
+        }
+      }
+    }, {
+      key: 'requestAnimFunc',
+      value: function requestAnimFunc() {
+        var me = this;
+        if (window.requestAnimationFrame) {
+          var index = -1;
+          return function (cb) {
+            index++;
+            return requestAnimationFrame(function () {
+              if (!(index % (60 / me.fps))) {
+                return cb();
               }
-          }
-      }, {
-          key: 'onpause',
-          value: function onpause() {}
-      }, {
-          key: 'onended',
-          value: function onended() {
-              this.destroy();
-          }
-      }, {
-          key: 'onerror',
-          value: function onerror(err) {
-              console.error('[Alpha video]: play error: ', err);
-              this.destroy();
-          }
-      }]);
-      return VapVideo;
+              me.animId = me.requestAnim(cb);
+            });
+          };
+        }
+        return function (cb) {
+          return setTimeout(cb, 1000 / me.fps);
+        };
+      }
+    }, {
+      key: 'cancelRequestAnimation',
+      value: function cancelRequestAnimation() {
+        if (window.cancelAnimationFrame) {
+          cancelAnimationFrame(this.animId);
+        }
+        clearTimeout(this.animId);
+      }
+    }, {
+      key: 'destroy',
+      value: function destroy() {
+        if (this.video) {
+          this.video.parentNode && this.video.parentNode.removeChild(this.video);
+          this.video = null;
+        }
+        this.cancelRequestAnimation(this.animId);
+      }
+    }, {
+      key: 'clear',
+      value: function clear() {
+        this.destroy();
+      }
+    }, {
+      key: 'on',
+      value: function on(event, callback) {
+        var cbs = this.events[event] || [];
+        cbs.push(callback);
+        this.events[event] = cbs;
+        this.video.addEventListener(event, callback);
+        return this;
+      }
+    }, {
+      key: 'onplaying',
+      value: function onplaying() {
+        if (!this.firstPlaying) {
+          this.firstPlaying = true;
+          this.drawFrame();
+        }
+      }
+    }, {
+      key: 'onpause',
+      value: function onpause() {}
+    }, {
+      key: 'onended',
+      value: function onended() {
+        this.destroy();
+      }
+    }, {
+      key: 'onerror',
+      value: function onerror(err) {
+        console.error('[Alpha video]: play error: ', err);
+        this.destroy();
+      }
+    }]);
+    return VapVideo;
   }();
 
   /*

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
web/dist/vap.min.js


+ 1 - 1
web/package-lock.json

@@ -1,6 +1,6 @@
 {
   "name": "video-animation-player",
-  "version": "0.1.0",
+  "version": "0.1.2",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {

+ 169 - 119
web/src/video.js

@@ -14,145 +14,195 @@
  * limitations under the License.
  */
 export default class VapVideo {
-    constructor(options) {
-        if (!options.container || !options.src) {
-            return console.warn('[Alpha video]: options container and src cannot be empty!')
-        }
-        this.options = Object.assign(
-            {
-                // 视频url
-                src: '',
-                // 循环播放
-                loop: false,
-                fps: 20,
-                // 视频宽度
-                width: 375,
-                // 视频高度
-                height: 375,
-                // 容器
-                container: null,
-                config: ''
-            },
-            options
-        )
-        this.fps = 20
-        this.requestAnim = this.requestAnimFunc(this.fps)
-        this.container = this.options.container
-        if (!this.options.src || !this.options.config || !this.options.container) {
-            console.error('参数出错:src(视频地址)、config(配置文件地址)、container(dom容器)')
+  constructor(options) {
+    if (!options.container || !options.src) {
+      return console.warn('[Alpha video]: options container and src cannot be empty!')
+    }
+    this.options = Object.assign(
+      {
+        // 视频url
+        src: '',
+        // 循环播放
+        loop: false,
+        fps: 20,
+        // 视频宽度
+        width: 375,
+        // 视频高度
+        height: 375,
+        // 容器
+        container: null,
+        config: ''
+      },
+      options
+    )
+    this.fps = 20
+    this.requestAnim = this.requestAnimFunc(this.fps)
+    this.container = this.options.container
+    if (!this.options.src || !this.options.config || !this.options.container) {
+      console.error('参数出错:src(视频地址)、config(配置文件地址)、container(dom容器)')
+    } else {
+      // 创建video
+      this.initVideo()
+    }
+  }
+
+  precacheSource(source) {
+    const URL = window.webkitURL || window.URL;
+    return new Promise((resolve, reject) => {
+      const xhr = new XMLHttpRequest();
+      xhr.open("GET", source, true);
+      xhr.responseType = "blob";
+      xhr.onload = function() {
+        if (xhr.status === 200 || xhr.status === 304) {
+          const res = xhr.response;
+          if (/iphone|ipad|ipod/i.test(navigator.userAgent)) {
+            const fileReader = new FileReader();
+            fileReader.onloadend = function() {
+              const raw = atob(
+                fileReader.result.slice(fileReader.result.indexOf(",") + 1)
+              );
+              const buf = Array(raw.length);
+              for (let d = 0; d < raw.length; d++) {
+                buf[d] = raw.charCodeAt(d);
+              }
+              const arr = new Uint8Array(buf);
+              const blob = new Blob([arr], { type: "video/mp4" });
+              resolve(URL.createObjectURL(blob));
+            };
+            fileReader.readAsDataURL(xhr.response);
+          } else {
+            resolve(URL.createObjectURL(res));
+          }
         } else {
-            // 创建video
-            this.initVideo()
+          reject(new Error("http response invalid" + xhr.status));
         }
-    }
+      };
+      xhr.send();
+    });
+  }
 
-    initVideo() {
-        const options = this.options
-        // 创建video
-        const video = (this.video = document.createElement('video'))
-        video.crossOrigin = 'anonymous'
-        video.autoplay = false
-        video.preload = 'auto'
-        video.autoload = true
-        // video.muted = true
-        // video.volume = 0
-        video.style.display = 'none'
-        video.src = options.src
-        video.loop = !!options.loop
-        // 这里要插在body上,避免container移动带来无法播放的问题
-        document.body.appendChild(this.video)
-        // 绑定事件
-        this.events = {}
-        ;['playing', 'pause', 'ended', 'error'].forEach(item => {
-            this.on(item, this['on' + item].bind(this))
-        })
-        video.load()
+
+  initVideo() {
+    const options = this.options
+    // 创建video
+    const video = (this.video = document.createElement('video'))
+    video.crossOrigin = 'anonymous'
+    video.autoplay = false
+    video.preload = 'auto'
+    video.autoload = true
+    if(options.mute){
+      video.muted = true
+      video.volume = 0
     }
-    drawFrame() {
-        this._drawFrame = this._drawFrame || this.drawFrame.bind(this)
-        this.animId = this.requestAnim(this._drawFrame)
+    video.style.display = 'none'
+    video.loop = !!options.loop
+    if(options.precache) {
+      this.precacheSource(options.src)
+        .then(blob => {
+          console.log("sample precached.");
+          video.src = blob;
+          document.body.appendChild(video);
+        })
+        .catch(e=>{
+          console.error(e);
+        });
+    }else{
+      video.src = options.src;
+      // 这里要插在body上,避免container移动带来无法播放的问题
+      document.body.appendChild(this.video);
+      video.load();
     }
+    // 绑定事件
+    this.events = {}
+    ;['playing', 'pause', 'ended', 'error'].forEach(item => {
+      this.on(item, this['on' + item].bind(this))
+    })
+  }
+  drawFrame() {
+    this._drawFrame = this._drawFrame || this.drawFrame.bind(this)
+    this.animId = this.requestAnim(this._drawFrame)
+  }
 
-    play() {
-        const prom = this.video && this.video.play()
+  play() {
+    const prom = this.video && this.video.play()
 
-        if (prom && prom.then) {
-            prom.catch(e => {
-                if (!this.video) {
-                    return
-                }
-                this.video.muted = true
-                this.video.volume = 0
-                this.video.play().catch(e => {
-                    ;(this.events.error || []).forEach(item => {
-                        item(e)
-                    })
-                })
-            })
+    if (prom && prom.then) {
+      prom.catch(e => {
+        if (!this.video) {
+          return
         }
+        this.video.muted = true
+        this.video.volume = 0
+        this.video.play().catch(e => {
+          ;(this.events.error || []).forEach(item => {
+            item(e)
+          })
+        })
+      })
     }
+  }
 
-    requestAnimFunc() {
-        const me = this
-        if (window.requestAnimationFrame) {
-            let index = -1
-            return function(cb) {
-                index++
-                return requestAnimationFrame(() => {
-                    if (!(index % (60 / me.fps))) {
-                        return cb()
-                    }
-                    me.animId = me.requestAnim(cb)
-                })
-            }
-        }
-        return function(cb) {
-            return setTimeout(cb, 1000 / me.fps)
-        }
+  requestAnimFunc() {
+    const me = this
+    if (window.requestAnimationFrame) {
+      let index = -1
+      return function(cb) {
+        index++
+        return requestAnimationFrame(() => {
+          if (!(index % (60 / me.fps))) {
+            return cb()
+          }
+          me.animId = me.requestAnim(cb)
+        })
+      }
     }
-
-    cancelRequestAnimation() {
-        if (window.cancelAnimationFrame) {
-            cancelAnimationFrame(this.animId)
-        }
-        clearTimeout(this.animId)
+    return function(cb) {
+      return setTimeout(cb, 1000 / me.fps)
     }
+  }
 
-    destroy() {
-        if (this.video) {
-            this.video.parentNode && this.video.parentNode.removeChild(this.video)
-            this.video = null
-        }
-        this.cancelRequestAnimation(this.animId)
+  cancelRequestAnimation() {
+    if (window.cancelAnimationFrame) {
+      cancelAnimationFrame(this.animId)
     }
+    clearTimeout(this.animId)
+  }
 
-    clear() {
-        this.destroy()
+  destroy() {
+    if (this.video) {
+      this.video.parentNode && this.video.parentNode.removeChild(this.video)
+      this.video = null
     }
+    this.cancelRequestAnimation(this.animId)
+  }
 
-    on(event, callback) {
-        const cbs = this.events[event] || []
-        cbs.push(callback)
-        this.events[event] = cbs
-        this.video.addEventListener(event, callback)
-        return this
-    }
+  clear() {
+    this.destroy()
+  }
 
-    onplaying() {
-        if (!this.firstPlaying) {
-            this.firstPlaying = true
-            this.drawFrame()
-        }
+  on(event, callback) {
+    const cbs = this.events[event] || []
+    cbs.push(callback)
+    this.events[event] = cbs
+    this.video.addEventListener(event, callback)
+    return this
+  }
+
+  onplaying() {
+    if (!this.firstPlaying) {
+      this.firstPlaying = true
+      this.drawFrame()
     }
+  }
 
-    onpause() {}
+  onpause() {}
 
-    onended() {
-        this.destroy()
-    }
+  onended() {
+    this.destroy()
+  }
 
-    onerror(err) {
-        console.error('[Alpha video]: play error: ', err)
-        this.destroy()
-    }
+  onerror(err) {
+    console.error('[Alpha video]: play error: ', err)
+    this.destroy()
+  }
 }

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott