• build your own custom HTML5 video player All In One


    build your own custom HTML5 video player All In One

    npm

    https://www.npmjs.com/package/custome-html5-video-player

    1. 自定义 Video Player UI
    2. 实现 Video API 事件
    3. PIP (picture in picture / 画中画),Fullscreen API
    4. custom feature ..., blob 下载,
    // Select elements here
    const video = document.getElementById('video');
    const videoControls = document.getElementById('video-controls');
    const playButton = document.getElementById('play');
    const playbackIcons = document.querySelectorAll('.playback-icons use');
    const timeElapsed = document.getElementById('time-elapsed');
    const duration = document.getElementById('duration');
    const progressBar = document.getElementById('progress-bar');
    const seek = document.getElementById('seek');
    const seekTooltip = document.getElementById('seek-tooltip');
    const volumeButton = document.getElementById('volume-button');
    const volumeIcons = document.querySelectorAll('.volume-button use');
    const volumeMute = document.querySelector('use[href="#volume-mute"]');
    const volumeLow = document.querySelector('use[href="#volume-low"]');
    const volumeHigh = document.querySelector('use[href="#volume-high"]');
    const volume = document.getElementById('volume');
    const playbackAnimation = document.getElementById('playback-animation');
    const fullscreenButton = document.getElementById('fullscreen-button');
    const videoContainer = document.getElementById('video-container');
    const fullscreenIcons = fullscreenButton.querySelectorAll('use');
    const pipButton = document.getElementById('pip-button');
    
    const videoWorks = !!document.createElement('video').canPlayType;
    if (videoWorks) {
      video.controls = false;
      videoControls.classList.remove('hidden');
    }
    
    // Add functions here
    
    // togglePlay toggles the playback state of the video.
    // If the video playback is paused or ended, the video is played
    // otherwise, the video is paused
    function togglePlay() {
      if (video.paused || video.ended) {
        video.play();
      } else {
        video.pause();
      }
    }
    
    // updatePlayButton updates the playback icon and tooltip
    // depending on the playback state
    function updatePlayButton() {
      playbackIcons.forEach((icon) => icon.classList.toggle('hidden'));
    
      if (video.paused) {
        playButton.setAttribute('data-title', 'Play (k)');
      } else {
        playButton.setAttribute('data-title', 'Pause (k)');
      }
    }
    
    // formatTime takes a time length in seconds and returns the time in
    // minutes and seconds
    function formatTime(timeInSeconds) {
      const result = new Date(timeInSeconds * 1000).toISOString().substr(11, 8);
    
      return {
        minutes: result.substr(3, 2),
        seconds: result.substr(6, 2),
      };
    }
    
    // initializeVideo sets the video duration, and maximum value of the
    // progressBar
    function initializeVideo() {
      const videoDuration = Math.round(video.duration);
      seek.setAttribute('max', videoDuration);
      progressBar.setAttribute('max', videoDuration);
      const time = formatTime(videoDuration);
      duration.innerText = `${time.minutes}:${time.seconds}`;
      duration.setAttribute('datetime', `${time.minutes}m ${time.seconds}s`);
    }
    
    // updateTimeElapsed indicates how far through the video
    // the current playback is by updating the timeElapsed element
    function updateTimeElapsed() {
      const time = formatTime(Math.round(video.currentTime));
      timeElapsed.innerText = `${time.minutes}:${time.seconds}`;
      timeElapsed.setAttribute('datetime', `${time.minutes}m ${time.seconds}s`);
    }
    
    // updateProgress indicates how far through the video
    // the current playback is by updating the progress bar
    function updateProgress() {
      seek.value = Math.floor(video.currentTime);
      progressBar.value = Math.floor(video.currentTime);
    }
    
    // updateSeekTooltip uses the position of the mouse on the progress bar to
    // roughly work out what point in the video the user will skip to if
    // the progress bar is clicked at that point
    function updateSeekTooltip(event) {
      const skipTo = Math.round(
        (event.offsetX / event.target.clientWidth) *
          parseInt(event.target.getAttribute('max'), 10)
      );
      seek.setAttribute('data-seek', skipTo);
      const t = formatTime(skipTo);
      seekTooltip.textContent = `${t.minutes}:${t.seconds}`;
      const rect = video.getBoundingClientRect();
      seekTooltip.style.left = `${event.pageX - rect.left}px`;
    }
    
    // skipAhead jumps to a different point in the video when the progress bar
    // is clicked
    function skipAhead(event) {
      const skipTo = event.target.dataset.seek
        ? event.target.dataset.seek
        : event.target.value;
      video.currentTime = skipTo;
      progressBar.value = skipTo;
      seek.value = skipTo;
    }
    
    // updateVolume updates the video's volume
    // and disables the muted state if active
    function updateVolume() {
      if (video.muted) {
        video.muted = false;
      }
    
      video.volume = volume.value;
    }
    
    // updateVolumeIcon updates the volume icon so that it correctly reflects
    // the volume of the video
    function updateVolumeIcon() {
      volumeIcons.forEach((icon) => {
        icon.classList.add('hidden');
      });
    
      volumeButton.setAttribute('data-title', 'Mute (m)');
    
      if (video.muted || video.volume === 0) {
        volumeMute.classList.remove('hidden');
        volumeButton.setAttribute('data-title', 'Unmute (m)');
      } else if (video.volume > 0 && video.volume <= 0.5) {
        volumeLow.classList.remove('hidden');
      } else {
        volumeHigh.classList.remove('hidden');
      }
    }
    
    // toggleMute mutes or unmutes the video when executed
    // When the video is unmuted, the volume is returned to the value
    // it was set to before the video was muted
    function toggleMute() {
      video.muted = !video.muted;
    
      if (video.muted) {
        volume.setAttribute('data-volume', volume.value);
        volume.value = 0;
      } else {
        volume.value = volume.dataset.volume;
      }
    }
    
    // animatePlayback displays an animation when
    // the video is played or paused
    function animatePlayback() {
      playbackAnimation.animate(
        [
          {
            opacity: 1,
            transform: 'scale(1)',
          },
          {
            opacity: 0,
            transform: 'scale(1.3)',
          },
        ],
        {
          duration: 500,
        }
      );
    }
    
    // toggleFullScreen toggles the full screen state of the video
    // If the browser is currently in fullscreen mode,
    // then it should exit and vice versa.
    function toggleFullScreen() {
      if (document.fullscreenElement) {
        document.exitFullscreen();
      } else if (document.webkitFullscreenElement) {
        // Need this to support Safari
        document.webkitExitFullscreen();
      } else if (videoContainer.webkitRequestFullscreen) {
        // Need this to support Safari
        videoContainer.webkitRequestFullscreen();
      } else {
        videoContainer.requestFullscreen();
      }
    }
    
    // updateFullscreenButton changes the icon of the full screen button
    // and tooltip to reflect the current full screen state of the video
    function updateFullscreenButton() {
      fullscreenIcons.forEach((icon) => icon.classList.toggle('hidden'));
    
      if (document.fullscreenElement) {
        fullscreenButton.setAttribute('data-title', 'Exit full screen (f)');
      } else {
        fullscreenButton.setAttribute('data-title', 'Full screen (f)');
      }
    }
    
    // togglePip toggles Picture-in-Picture mode on the video
    async function togglePip() {
      try {
        if (video !== document.pictureInPictureElement) {
          pipButton.disabled = true;
          await video.requestPictureInPicture();
        } else {
          await document.exitPictureInPicture();
        }
      } catch (error) {
        console.error(error);
      } finally {
        pipButton.disabled = false;
      }
    }
    
    // hideControls hides the video controls when not in use
    // if the video is paused, the controls must remain visible
    function hideControls() {
      if (video.paused) {
        return;
      }
    
      videoControls.classList.add('hide');
    }
    
    // showControls displays the video controls
    function showControls() {
      videoControls.classList.remove('hide');
    }
    
    // keyboardShortcuts executes the relevant functions for
    // each supported shortcut key
    function keyboardShortcuts(event) {
      const { key } = event;
      switch (key) {
        case 'k':
          togglePlay();
          animatePlayback();
          if (video.paused) {
            showControls();
          } else {
            setTimeout(() => {
              hideControls();
            }, 2000);
          }
          break;
        case 'm':
          toggleMute();
          break;
        case 'f':
          toggleFullScreen();
          break;
        case 'p':
          togglePip();
          break;
      }
    }
    
    // Add eventlisteners here
    playButton.addEventListener('click', togglePlay);
    video.addEventListener('play', updatePlayButton);
    video.addEventListener('pause', updatePlayButton);
    video.addEventListener('loadedmetadata', initializeVideo);
    video.addEventListener('timeupdate', updateTimeElapsed);
    video.addEventListener('timeupdate', updateProgress);
    video.addEventListener('volumechange', updateVolumeIcon);
    video.addEventListener('click', togglePlay);
    video.addEventListener('click', animatePlayback);
    video.addEventListener('mouseenter', showControls);
    video.addEventListener('mouseleave', hideControls);
    videoControls.addEventListener('mouseenter', showControls);
    videoControls.addEventListener('mouseleave', hideControls);
    seek.addEventListener('mousemove', updateSeekTooltip);
    seek.addEventListener('input', skipAhead);
    volume.addEventListener('input', updateVolume);
    volumeButton.addEventListener('click', toggleMute);
    fullscreenButton.addEventListener('click', toggleFullScreen);
    videoContainer.addEventListener('fullscreenchange', updateFullscreenButton);
    pipButton.addEventListener('click', togglePip);
    
    document.addEventListener('DOMContentLoaded', () => {
      if (!('pictureInPictureEnabled' in document)) {
        pipButton.classList.add('hidden');
      }
    });
    document.addEventListener('keyup', keyboardShortcuts);
    

    Video & Audio

    
    <video controls>
      <source src="https://mdn.github.io/learning-area/html/multimedia-and-embedding/video-and-audio-content/rabbit320.mp4" type="video/mp4">
      <source src="https://mdn.github.io/learning-area/html/multimedia-and-embedding/video-and-audio-content/rabbit320.webm" type="video/webm">
      <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p>
    </video>
    
    

    https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs

    Media/Formats

    // codecs
    
    

    https://developer.mozilla.org/en-US/docs/Web/Media/Formats#Browser_compatibility

    https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Video_codecs

    Web video codec guide

    网络视频编解码器指南

    https://developer.mozilla.org/en-US/docs/Glossary/Codec

    https://en.wikipedia.org/wiki/Codec

    HTMLMediaElement API

    // custom video player API
    
    

    https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement

    HLS

    HTTPS Live Streaming

    video.js

    https://videojs.com/

    https://github.com/videojs/video.js

    Big Buck Bunny

    https://en.wikipedia.org/wiki/Big_Buck_Bunny

    https://peach.blender.org/

    https://www.youtube.com/watch?v=aqz-KE-bpKQ

    http://bbb3d.renderfarming.net/download.html

    refs

    https://freshman.tech/custom-html5-video/



    ©xgqfrms 2012-2020

    www.cnblogs.com/xgqfrms 发布文章使用:只允许注册用户才可以访问!

    原创文章,版权所有©️xgqfrms, 禁止转载 ️,侵权必究⚠️!


  • 相关阅读:
    这两年
    Ubuntu 14.04 更新 setuptools 至 19.2 版本
    leetcode 编译问题:Line x: member access within null pointer of type 'struct TreeNode'
    C++ 将 std::string 转换为 char*
    LeetCode in action
    Ubuntu下 fatal error: Python.h: No such file or directory 解决方法
    Mac OS X 清除DNS缓存
    Mac OS X 避免产生临时文件 .DS_Store
    Mac OS X 显示和隐藏文件
    解决 ln -s 软链接产生的Too many levels of symbolic links错误
  • 原文地址:https://www.cnblogs.com/xgqfrms/p/16228744.html
Copyright © 2020-2023  润新知