一.简介

直到现在,仍然不存在一项旨在网页上显示视频的标准。

今天,大多数视频是通过插件(比如 Flash)来显示的。然而,并非所有浏览器都拥有同样的插件。

HTML5 规定了一种通过 video 元素来包含视频的标准方法。如:

1
2
<video src="movie.ogg" controls="controls">
</video>

二.Canvas+Video

HTML5中引入新的元素canvas,其drawImage 方法允许在 canvas 中插入其他图像( img 和 canvas 元素) 。

drawImage函数有三种函数原型:

drawImage(image, dx, dy) 
drawImage(image, dx, dy, dw, dh) 
drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)

第一个参数image可以用HTMLImageElement,HTMLCanvasElement或者HTMLVideoElement作为参数。

dx和dy是image在canvas中定位的坐标值;dw和dh是image在canvas中即将绘制区域(相对dx和dy坐标的偏移量)的宽度和高度值;

sx和sy是image所要绘制的起始位置,sw和sh是image所要绘制区域(相对image的sx和sy坐标的偏移量)的宽度和高度值。

所以这使酷炫播放体验有了实现的可能。

三.理解canvas.translate和canvas.scale

很多人对于canvas.translate(x,y)的理解有的错误,之前一直以原点(0,0)为基准点,作用就是移动原点,默认的原点(0,0)是在屏幕左上角的,你可以通过translate(x,y)把点(x,y)作为原点,就一直以为这个(x,y)就是新的坐标原点。但看一下API就会知道,这种理解是不对的,

不过API确实容易误导大家:

1
2
3
4
5
6
7
view plain
public void translate (float dx, float dy) 
 Since: API Level 1 
Preconcat the current matrix with the specified translation 
Parameters 
dx  The distance to translate in X 
dy  The distance to translate in Y

其实是原来的原点分别在x轴和y轴偏移多远的距离,然后以偏移后的位置作为坐标原点。也就是说原来在(100,100),然后translate(1,1)新的坐标原点在(101,101)而不是(1,1)

canvas.scale:

canvas.scale提供了放大缩小倒置等功能。比如Y倒置:canvas.scale(1,-1)

四.核心代码

1
2
3
4
5
6
7
canvas.setAttribute('height', Math.floor(video.height));
      canvas.setAttribute('width', Math.floor(video.width));
 
      ctx.translate(0, canvas.height );
      ctx.scale(1, -1);
      ctx.globalAlpha = 0.3;
      ctx.drawImage(video, 0, 0, video.width, video.height, 0, -canvas.height/2, canvas.width, canvas.height);

五.在线演示

 
 00:00 /

六.代码下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<html >
<head>
<meta charset="utf-8" />
<title></title>
 
</head>
<body>
   <div>
   <video  width="640" height="264">
  </video> <br/>
  <canvas style="position:absolute; top:143px;"></canvas>
</div>
<div  style="position:absolute; top:400px;">
  <p>
    <input type="button" id="play" value="play">
    <span id="position">00:00</span> / <span id="duration"></span>
  </p>
  </div>
<script >
 
    var addEvent = (function () {
        if (document.addEventListener) {
            return function (el, type, fn) {
                if (el && el.nodeName || el === window) {
                    el.addEventListener(type, fn, false);
                } else if (el && el.length) {
                    for (var i = 0; i < el.length; i++) {
                        addEvent(el[i], type, fn);
                    }
                }
            };
        } else {
            return function (el, type, fn) {
                if (el && el.nodeName || el === window) {
                    el.attachEvent('on' + type, function () { return fn.call(el, window.event); });
                } else if (el && el.length) {
                    for (var i = 0; i < el.length; i++) {
                        addEvent(el[i], type, fn);
                    }
                }
            };
        }
    })();
    
</script>
<script>
    var video = document.querySelector('video');
    var togglePlay = document.querySelector('#play');
    var position = document.querySelector('#position');
    var canvas = document.querySelector('canvas');
    var ctx = canvas.getContext('2d');
 
    addEvent(togglePlay, 'click', function () {
        video.playbackRate = 0.5;
        if (video.paused) {
            if (video.ended) video.currentTime = 0;
            video.play();
            this.value = "pause";
        } else {
            video.pause();
            this.value = "play";
        }
    });
 
    setInterval(function () {
        position.innerHTML = asTime(video.currentTime);
        ctx.drawImage(video, 0, 0, video.width, video.height, 0, -canvas.height / 2, canvas.width, canvas.height);
    }, 1000 / 15);
 
    addEvent(video, 'ended', function () {
        togglePlay.value = "play";
    });
 
    addEvent(video, 'canplay', function () {
        video.muted = true;
        document.querySelector('#duration').innerHTML = asTime(this.duration);
        startCanvas();
    });
 
 
    function startCanvas() {
        canvas.setAttribute('height', Math.floor(video.height));
        canvas.setAttribute('width', Math.floor(video.width));
 
        ctx.translate(0, canvas.height );
        ctx.scale(1, -1);
        ctx.globalAlpha = 0.3;
        ctx.drawImage(video, 0, 0, video.width, video.height, 0, -canvas.height/2, canvas.width, canvas.height);
 
       
    }
 
    function asTime(t) {
        t = Math.round(t);
        var s = t % 60;
        var m = Math.round(t / 60);
 
        return two(m) + ':' + two(s);
    }
 
    function two(s) {
        s += "";
        if (s.length < 2) s = "0" + s;
        return s;
    }
</script>
</body>
 
</html>

Canvas+Video打造酷炫播放体验的更多相关文章

  1. 使用NestedScrollView+ViewPager+RecyclerView+SmartRefreshLayout打造酷炫下拉视差效果并解决各种滑动冲突

    使用NestedScrollView+ViewPager+RecyclerView+SmartRefreshLayout打造酷炫下拉视差效果并解决各种冲突 如果你还在为处理滑动冲突而发愁,那么你需要静 ...

  2. HTML5 Canvas玩转酷炫大波浪进度图

    如上图所见,本文就是要实现上面那种效果. 由于最近AlloyTouch要写一个下拉刷新的酷炫loading效果.所以首选大波浪进度图. 首先要封装一下大波浪图片进度组件.基本的原理是利用Canvas绘 ...

  3. 三分钟学会用 js + css3 打造酷炫3D相册

    之前发过该文,后来不知怎么回事不见了,现在重新发一下. 中秋主题的3D旋转相册 如图,这是通过Javascript和css3来实现的.整个案例只有不到80行代码,我希望通过这个案例,让正处于迷茫期的j ...

  4. MVC中使用SignalR打造酷炫实用的即时通讯功能附源码

    前言,现在这世道写篇帖子没个前言真不好意思发出来.本贴的主要内容来自于本人在之前项目中所开发的一个小功能,用于OA中的即时通讯.由于当时走的太急,忘记把代码拿出来.想想这已经是大半年前的事情了,时间过 ...

  5. MVC中使用SignalR打造酷炫实用的即时通讯功能(轉載)

    資料來源:http://www.fangsi.net/1144.html 前言,现在这世道写篇帖子没个前言真不好意思发出来.本贴的主要内容来自于本人在之前项目中所开发的一个小功能,用于OA中的即时通讯 ...

  6. 学习websocket-SignalR,MVC中使用SignalR打造酷炫实用的即时通讯

    http://www.cnblogs.com/Leo_wl/p/4793284.html http://www.fangsi.net/archives/1144.html

  7. Android 使用NestedScrollView+ViewPager+RecyclerView+SmartRefreshLayout打造酷炫下拉视差效果并解决各种滑动冲突

    如果你还在为处理滑动冲突而发愁,那么你需要静下心来看看这边文章,如果你能彻底理解这篇文章中使用的技术,那么,一切滑动冲突的问题解决起来就轻而易举了: 先扔一个最终实现的效果图 先分析下效果图中实现的功 ...

  8. [刘阳Java]_酷炫视频播放器制作_界面篇

    今天开始分享一篇酷炫播放器制作,包括界面+JS.整个案例非常类似腾讯视频,优酷视频,爱奇艺视频.我们先看一下效果图,然后这篇文章主要界面篇 是不是效果比较酷炫,那么我接着来给大家说一下这个界面设计思路 ...

  9. 2019基于Hexo快速搭建个人博客,打造一个炫酷博客(1)-奥怪的小栈

    本文转载于:奥怪的小栈 这篇文章告诉你如何在2019快速上手搭建一个像我一样的博客:基于HEXO+Github搭建.并完成SEO优化,打造一个炫酷博客. 本站基于HEXO+Github搭建.所以你需要 ...

随机推荐

  1. 《HelloGitHub》第 17 期

    公告 本月 hellogitub.com 动态 服务器迁移到了国内,国内浏览速度有了质的飞跃. 代码重构 项目 运行更加简单,直接 clone.执行安装依赖命令.运行 上线了"我的收藏&qu ...

  2. 阿里云ECS部署ES

    背景 最近越来越多的公司把业务搬迁到云上,公司也有这个计划,自己抽时间在阿里云和Azure上做了一些小的尝试,现在把阿里云上部署ES和kibana记录下来.为以后做一个参考,也希望对其他人有帮助. 这 ...

  3. JVM内存结构和6大区域

    摘自 http://www.iteye.com/news/30350 对于我们一般理解的计算机内存,它算是CPU与计算机打交道最频繁的区域,所有数据都是先经过硬盘至内存,然后由CPU再从内存中获取数据 ...

  4. [2014-09-18]Entity Framework 6 预热、启动优化

    好久没写博客了,终于憋出了一个大招,现在总结下. 虽然文章题目是针对EF的,但涉及的内容不仅仅是EF. 场景介绍 目前在做的一个项目,行业门户,项目部分站点按域名划分如下: user.xxx.com: ...

  5. 使用 qemu 搭建内核开发环境

    本文主要介绍在 MacOS 上使用 qemu 搭建 Linux Kernel 的开发环境.(在开始之前需要注意的是,本文中的 Linux 开发环境是一个远程服务器,而 qemu 被安装在本地的 Mac ...

  6. 获取ip地址及城市信息

    大家好,今天给大家分享的是一个简单的知识获取登录用户的ip地址及城市信息,lz是一个小白,如果有哪些错误的地方  欢迎大家指出 东西很简单,直接上代码 [HttpPost] public string ...

  7. java内存区域分析及java对象的创建

    java虚拟机在执行java程序的过程中会将它管理的内存区域加分为若干个的不同的数据区域. 主要包括以下几个运行时数据区域,这里就只介绍经常会用到的 1:java虚拟机栈:我们常说的堆栈,栈就是指的j ...

  8. Android学习记录:ViewPager实现欢迎页

    许多APP在第一次启动的时候,都会有welcome page.近日尝试利用ViewPager来实现Welcome Page. d0711 完成记录,跟新下载地址 =================== ...

  9. 入门-什么是webshell?

    webshell是什么? 顾名思义,"web" - 显然需要服务器开放web服务,"shell" - 取得对服务器某种程度上操作权限. webshell常常被称 ...

  10. CentOS7 安装Nginx+MySQL

    首先我们需要安装nginx的yum源 [root@AD ~]# rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-releas ...