49

VideoClip

Objective
  • Responder
    • View
      • Clip
        • VideoClip

Move the pointer of the mouse over the clip. Click in the clip or press the space bar to start playing it. Click or press again the space bar to pause it, continue to play it. Use the right and left arrows to move forward or backward by one second, press the Shift key or the Ctrl key at the same time to move forward or backward by ten seconds or a hundred milliseconds. Press the 0 key to come back to the beginning. Press the plus key to play the clip faster, the minus key to play it slower, the asterisk key to play it at the normal speed.

NOTE: A shrink effect programmed on the clip changes the dimensions of the video display over a period of ten seconds.

In the console of the browser, turn the sound off:

clip.muted=true

Try different display options:

clip.options={ hflip: true, sepia: true }

Resize the video:

clip.dimension=[480,270]
  1. function VideoClip() {
  2.     Clip.call(this);
  3.  
  4.     this._drawingarea = new DrawingArea();
  5.  
  6.     this._video = null;
  7.  
  8.     this._animlist = null;
  9.  
  10.     this._timeWidget = null;
  11.  
  12.     this._mutedWidget = null;
  13.  
  14.     this._onmute = null;
  15.  
  16.     this._streamvideo = null;
  17. }
  18.  
  19. VideoClip.prototype = Object.create(Clip.prototype);
  20.  
  21. Object.defineProperty(VideoClip.prototype, 'constructor', { value: VideoClip, enumerable: false, writable: true });
  22.  
  23. Object.defineProperty(VideoClip.prototype, 'dimension', {
  24.     get:    function() {
  25.         return this._drawingarea.size;
  26.     },
  27.     set:    function(d) {
  28.         this._drawingarea.size = d;
  29.     }
  30. });
  31.  
  32. Object.defineProperty(VideoClip.prototype, 'duration', {
  33.     get:    function() {
  34.         return this._video ? Math.floor(this._video.duration * 1000) : 0;
  35.     }
  36. });
  37.  
  38. Object.defineProperty(VideoClip.prototype, 'currentTime', {
  39.     get:    function() {
  40.         return this._video && this._video.currentTime > 0 ? Math.floor(this._video.currentTime * 1000) - 1 : 0;
  41.     }
  42. });
  43.  
  44. Object.defineProperty(VideoClip.prototype, 'playbackRate', {
  45.     get:    function() {
  46.         return this._playbackRate;
  47.     },
  48.     set:    function(r) {
  49.         if (typeof r !== 'number')
  50.             throw new TypeError();
  51.  
  52.         if (r < Clip.minPlaybackRate || r > Clip.maxPlaybackRate)
  53.             throw new RangeError();
  54.  
  55.         this._playbackRate = r;
  56.  
  57.         if (this._video)
  58.             this._video.playbackRate = r;
  59.  
  60.         if (this._animlist)
  61.             for (let e of this._animlist)
  62.                 e.playbackRate = r;
  63.     }
  64. });
  65.  
  66. Object.defineProperty(VideoClip.prototype, 'muted', {
  67.     get:    function() {
  68.         return this._video ? this._video.muted : false;
  69.     },
  70.     set:    function(muted) {
  71.         if (this._video) {
  72.             this._video.muted = muted ? true : false;
  73.  
  74.             if (this._mutedWidget)
  75.                 this._mutedWidget.checked = this._video.muted;
  76.         }
  77.     }
  78. });
  79.  
  80. Object.defineProperty(VideoClip.prototype, 'options', {
  81.     get:    function() {
  82.         return this._drawingarea.getOptions();
  83.     },
  84.     set:    function(options) {
  85.         this._drawingarea.setOptions(options);
  86.     }
  87. });
  88.  
  89. VideoClip.prototype.get = function() {
  90.     return this._drawingarea.getOptions();
  91. };
  92.  
  93. VideoClip.prototype.set = function(options) {
  94.     this._drawingarea.setOptions(options);
  95.  
  96.     return this;
  97. };
  98.  
  99. VideoClip.prototype.setValue = function(prop, val) {
  100.     if (prop == 'size')
  101.         this._drawingarea.size = val;
  102.     else if (prop == 'hflip')
  103.         this._drawingarea.hflip = val;
  104.     else if (prop == 'vflip')
  105.         this._drawingarea.vflip = val;
  106.     else if (prop == 'grayscale')
  107.         this._drawingarea.grayscale = val;
  108.     else if (prop == 'sepia')
  109.         this._drawingarea.sepia = val;
  110.     else if (prop == 'blur')
  111.         this._drawingarea.blur = val;
  112.     else if (prop == 'invert')
  113.         this._drawingarea.invert = val;
  114.     else if (prop == 'contrast')
  115.         this._drawingarea.contrast = val;
  116.     else if (prop == 'saturate')
  117.         this._drawingarea.saturate = val;
  118.     else if (prop == 'brightness')
  119.         this._drawingarea.brightness = val;
  120.     else if (prop == 'opacity')
  121.         this._drawingarea.opacity = val;
  122.  
  123.     return this;
  124. };
  125.  
  126. VideoClip.prototype.animate = function(animations) {
  127.     if (! (Array.isArray(animations) && animations.length > 0))
  128.         throw new TypeError();
  129.  
  130.     if (!this._widget)
  131.         return this;
  132.  
  133.     if (this._animlist)
  134.         for (let e of this._animlist)
  135.             e.cancel();
  136.  
  137.     const animlist = [];
  138.  
  139.     for (let e of animations) {
  140.         if (! (Array.isArray(e) && e.length == 2))
  141.             throw new TypeError();
  142.  
  143.         let [keyframes, options] = e;
  144.  
  145.         let anim = this._widget.animate(keyframes, options);
  146.  
  147.         anim.pause();
  148.  
  149.         animlist.push(anim);
  150.     }
  151.  
  152.     this._animlist = animlist;
  153.  
  154.     return this;
  155. };
  156.  
  157. VideoClip.prototype.seek = function(ms) {
  158.     if (!this._video)
  159.         return this;
  160.  
  161.     this._video.currentTime = (ms + 1) / 1000;  // +1 for Chrome
  162.  
  163.     if (this._animlist) {
  164.         for (let e of this._animlist) {
  165.             e.currentTime = ms;
  166.             if (this._paused)
  167.                 e.pause();
  168.         }
  169.     }
  170.  
  171.     return this;
  172. };
  173.  
  174. VideoClip.prototype.play = function() {
  175.     if (!this._video)
  176.         return this;
  177.  
  178.     if (this._ended)
  179.         this.seek(0);
  180.  
  181.     this._ended = this._paused = false;
  182.  
  183.     this._video.play();
  184.  
  185.     if (this._animlist) {
  186.         for (let e of this._animlist)
  187.             e.play();
  188.     }
  189.  
  190.     return this;
  191. };
  192.  
  193. VideoClip.prototype.pause = function() {
  194.     if (!this._video)
  195.         return this;
  196.  
  197.     this._paused = true;
  198.  
  199.     this._video.pause();
  200.  
  201.     if (this._animlist) {
  202.         for (let e of this._animlist)
  203.             e.pause();
  204.     }
  205.  
  206.     return this;
  207. };
  208.  
  209. VideoClip.prototype.setWidget = function(w) {
  210.     if (w.tagName != 'VIDEO')
  211.         throw new TypeError();
  212.  
  213.     this._drawingarea.setWidget(w);
  214.  
  215.     Clip.prototype.setWidget.call(this, this._drawingarea.widget);
  216.  
  217.     w.style.display = 'none';
  218.  
  219.     w.playbackRate = this._playbackRate;
  220.  
  221.     w.after(this._drawingarea.widget);
  222.  
  223.     this._video = w;
  224.  
  225.     w.onseeked = () => {
  226.         this._drawingarea.setImage(this._video);
  227.  
  228.         if (this._timeWidget)
  229.             this._timeWidget.innerText = VideoClip._toHHMMSS(this._video.currentTime);
  230.  
  231.         this.notify('clipSeeked', this);
  232.     };
  233.  
  234.     w.onended = () => {
  235.         this._ended = this._paused = true;
  236.  
  237.         if (this._animlist) {
  238.             for (let e of this._animlist)
  239.                 e.pause();
  240.         }
  241.  
  242.         this.notify('clipEnded', this);
  243.     };
  244.  
  245.     w.load();
  246.  
  247.     return this;
  248. };
  249.  
  250. VideoClip.prototype.addTimeWidget = function(w) {
  251.     w.innerText = VideoClip._toHHMMSS(this._video.currentTime);
  252.  
  253.     this._timeWidget = w;
  254.  
  255.     return this;
  256. };
  257.  
  258. VideoClip.prototype.removeTimeWidget = function() {
  259.     this._timeWidget = null;
  260.  
  261.     return this;
  262. };
  263.  
  264. VideoClip.prototype.addMutedWidget = function(w) {
  265.     if (this._onmute)
  266.         this.removeEventListener('change', this._onmute);
  267.  
  268.     this._onmute = () => this._video.muted = this._mutedWidget.checked;
  269.  
  270.     w.addEventListener('change', this._onmute);
  271.  
  272.     w.checked = this._video.muted;
  273.  
  274.     this._mutedWidget = w;
  275.  
  276.     return this;
  277. };
  278.  
  279. VideoClip.prototype.removeMutedWidget = function() {
  280.     if (this._onmute)
  281.         this.removeEventListener('change', this._onmute);
  282.  
  283.     this._mutedWidget = null;
  284.  
  285.     return this;
  286. };
  287.  
  288. VideoClip.prototype.enablePlayer = function() {
  289.     if (this.hasPlayer())
  290.         return this;
  291.  
  292.     Clip.prototype.enablePlayer.call(this);
  293.  
  294.     if (this._streamvideo === null) {
  295.         this._streamvideo = () => {
  296.             if (this._video.paused || this._video.ended)
  297.                 return;
  298.  
  299.             this._drawingarea.setImage(this._video);
  300.  
  301.             if (this._timeWidget)
  302.                 this._timeWidget.innerText = VideoClip._toHHMMSS(this._video.currentTime);
  303.  
  304.             requestAnimationFrame(this._streamvideo);
  305.         };
  306.  
  307.         this._video.onplay = this._streamvideo;
  308.     }
  309.  
  310.     return this;
  311. };
  312.  
  313. VideoClip._toHHMMSS = function(nsecs) {
  314.     nsecs = Math.floor(nsecs);
  315.  
  316.     let hh = Math.floor(nsecs / 3600);
  317.     let mm = Math.floor((nsecs - (hh * 3600)) / 60);
  318.     let ss = nsecs - (hh * 3600) - (mm * 60);
  319.  
  320.     hh = (hh < 10 ? '0' : '') + hh;
  321.     mm = (mm < 10 ? '0' : '') + mm;
  322.     ss = (ss < 10 ? '0' : '') + ss;
  323.  
  324.     return `${hh}:${mm}:${ss}`;
  325. };
Test
  1. <?php $src='/files/videos/Horloge.webm'; ?>
  2. <?php $type='video/webm'; ?>
  3. <?php $width=854; ?>
  4. <?php $height=480; ?>
  1. <?php $id=uniqid('id'); ?>
  1. .test_display {
  2.     display: inline-flex;
  3.     flex-direction: column;
  4.     align-items: flex-start;
  5.     background: black;
  6. }
  1. <div id="<?php echo $id; ?>" class="noprint">
  2. <div class="test_display">
  3. <video width="<?php echo $width; ?>" height="<?php echo $height; ?>" preload="auto">
  4. <source src="<?php echo $src; ?>" type="<?php echo $type; ?>" />
  5. </video>
  6. </div>
  7. </div>
  1. <?php head('javascript', '/objectivejs/Objective.js'); ?>
  2. <?php head('javascript', '/objectivejs/Responder.js'); ?>
  3. <?php head('javascript', '/objectivejs/View.js'); ?>
  4. <?php head('javascript', '/objectivejs/Clip.js'); ?>
  5. <?php head('javascript', '/objectivejs/VideoClip.js'); ?>
  6. <?php head('javascript', '/objectivejs/DrawingArea.js'); ?>
  1. const clip = new VideoClip();
  2.  
  3. const container = document.querySelector('#<?php echo $id; ?>');
  4.  
  5. clip.setManagedWidget(container.querySelector('video'));
  1. const keyframes = [ {transform: 'scale(1)'}, {transform: 'scale(0.8)'}, {transform: 'scale(1)'}];
  2. const timing = { duration: 10000, iterations: Infinity };
  3.  
  4. clip.animate([[keyframes, timing]]);
  1. clip.dimension = [640, 360];
  1. clip.enablePlayer();
SEE ALSO

Clip, AnimateClip, ProgramClip, DrawingArea, Editing a video clip

Comments

Your comment:
[p] [b] [i] [u] [s] [quote] [pre] [br] [code] [url] [email] strip help 2000

Enter a maximum of 2000 characters.
Improve the presentation of your text with the following formatting tags:
[p]paragraph[/p], [b]bold[/b], [i]italics[/i], [u]underline[/u], [s]strike[/s], [quote]citation[/quote], [pre]as is[/pre], [br]line break,
[url]http://www.izend.org[/url], [url=http://www.izend.org]site[/url], [email]izend@izend.org[/email], [email=izend@izend.org]izend[/email],
[code]command[/code], [code=language]source code in c, java, php, html, javascript, xml, css, sql, bash, dos, make, etc.[/code].