大家在平时观看视频的视频网站中,比如优酷,爱奇艺,腾讯视频等,鼠标移动至播放条区域的时候,大家可以看到会弹出小的视频预览图片,这样子就可以给用户很好体验,至少可以知道前后播放的内容。最近公司业务需要,就不得不研究了。
本文将从三个方面进行总结
一、设计与逻辑(最重要)
二、优化拓展
三、代码
特别说明:本设计针对flowplayer版本为6.0版本,低于6.0版本在本设计中不适用,后面会简单说到在flowplayer的5.0版本如何设计的问题,整个设计会复杂很多。
一、设计与逻辑
首先有三个问题
(1)鼠标移到flowplayer的播放条上如何获取对应的时间。
(2)在对应的时间又如何获取到该时间点上的视频的缩略图。
(3)如何显示的样式问题,像爱奇艺的缩略图显示一排在播放器区域内显示。
第一个问题
在flowplayer6.0的版本中,flowplayer.min.js其实已经实现获取时间的功能,在官网的demo中,只要鼠标把移至播放的时间轴上,就会出现一个时间。下图是我在官网上的截图。
图一
从图上可以看到,鼠标移至00:02时,出现一个div,显示时间,可以在firebug的调试中找到该<div>,其实是,可以针对该div入手。首先,我们可以<div class="fp-timeline-tooltip fp-tooltip">在里面再创建两个<div>。创建之后形式如下
- <div class="fp-timeline-tooltip fp-tooltip">
- <div class="fp-thumbnails"></div>
- <div class="fp-seektime" id="fp-seektime"></div>
- </div>
其中,
<div class="fp-thumbnails"></div>
用于显示缩略图,
<div class="fp-seektime" id="fp-seektime"></div>
用于显示时间,最终要实现的形式如图下
图二
这样,我们又产生一个问题了,如何创建这些元素呢?这就需要我们能够去看flowplayer.js的内部代码了,因为在加载这个flowplayer.js的时候,会内部创建<div class="fp-timeline-tooltip fp-tooltip"></div>,并将时间显示在这个div。既然这样,那可以在flowplayer.js的文件中再重新定义一个函数,这个函数循环对象为<div class="fp-timeline-tooltip fp-tooltip"></div>,创建需要的两个div
- <div class="fp-thumbnails"></div>
- <div class="fp-seektime" id="fp-seektime"></div>
在flowplayer.js中的html的函数之后创建,如图所示
图三
同时更改当鼠标移动时的促发的函数,原来是html函数的,现在要改为tpl函数。
图四
这样,可以解决了第一个问题了。当鼠标放在播放的进度条时,如果设置一下<div class="fp-thumbnails">的宽度width和高度height就可以出现图二的效果啦,因为还没有获取到缩略图,所以没有缩列图显示,时间可以显示。
第二个问题
要获取缩略图,肯定要图片,这个单纯用JavaScript是不可能从视频中获取对应时间的图片的,下面会用到专注于多媒体处理的ffmpeg来将这个视频的关键帧分解出来。
ffmpeg所用的命令
- ffmpeg -i my.mp4 -filter:v framerate=1/1,scale=-1:100 -q:v 5 myvideo%d.jpg
这个命令可以将一个视频的关键帧图片全部分解出来,其中的参数可以自己查询资料。图片的命名是myvideo1.jpg,myvideo2.jpg......
其中这个framerate的值代表帧率,即相隔多少秒,截一张图,这里设置等于1,说明myvideo1.jpg就是0秒的图,myvideo2.jpg就是代表1秒的图。。。。这样子的话,就非常好办了,鼠标移到00:02时,可以取对应的myvideo3的图片,就相当于在这一秒的画面。将这个图作为<div class="fp-thumbnails"></div>的背景,也就是显示了这一张图了。
那么,问题又来了,如何获取鼠标放在进度条上的时间呢?方法也很简单哦哦!有很多种!
最简单一种是直接获取创建的<div class="fp-seektime" id="fp-seektime"></div>的值,因为这里面显示的就是时间,格式是00:00:00,需要自己重新将格式转为时间秒数,比如格式00:00:20的秒数为second=20,那么可以动态的设置
<div class="fp-thumbnails"></div>的背景为url了,例如url(./myvideo20.jpg),那么很容易就可以将对应的视频的缩略图显示出来了。
另外一种是flowplayer的原生方法,通过鼠标距离左侧的位置
var x = ev.pageX || ev.clientX,
delta = x - common.offset(timeline).left,
percentage = delta / common.width(timeline),
seconds = Math.round(percentage * api.video.duration);
具体要自己了解flowplayer.js
如果显示多个缩略图又怎么办呢,显示的原理是一样的,只不过又要动态地创建多个<div>,这就涉及到样式问题,要以主缩略图为中心(即是刚才创建的那个缩略图),动态创建<div>。再可以设置一个步调step,获取每张相隔step秒的图片显示在主缩略图的左右两侧。比如鼠标移至时间是00:00:50,即现在在50秒显示的是主缩略图,则左侧可以显示的图分别是在10,20,30,40秒处的视频图,右边则是60,70,80,,,,,所以整个很重要。
其实说到这里,基本整个设计与逻辑就已经完了,剩下的是css和js的逻辑问题了,在这里我就不多说了。
第三个问题
直接看代码,主要是样式问题,如何更好地显示一排出来。
二、优化拓展
(1)尽量写成js插件形式
(2)样式外观
(3)点击缩略图,播放跳至对应时间播放
这几个是很有必要优化的
三、代码
这是一个插件的形式来的,用的时候,要在这个文件之前引入需要引入jQuery文件
- /*!
- Thumbnail image plugin for Flowplayer HTML5
- Copyright (c) 2015-2016, Flowplayer Oy
- Released under the MIT License:
- http://www.opensource.org/licenses/mit-license.php
- requires:
- - Flowplayer HTML5 version 6.x or greater
- revision: $GIT_ID$
- */
- (function (flowplayer,$) {
- "use strict";
- flowplayer(function (api, root) {
- var common = flowplayer.common,
- bean = flowplayer.bean,
- support = flowplayer.support,
- timeline = common.find('.fp-timeline', root)[0],
- timelineTooltip = common.find('.fp-timeline-tooltip', root)[0];
-
- if (support.touch || !support.inlineVideo) {
- return;
- }
-
- api.on('ready', function (ev, a, video) {
- // cleanup
- bean.off(root, '.thumbnails');
-
- common.css(timelineTooltip, {
- 'border': '1px solid #333',
- 'color':'#fff',
- 'background-color':'#000',
-
- });
- var c = flowplayer.extend({}, api.conf.thumbnails, video.thumbnails);
-
- if (!c.template) {
- return;
- }
-
- var height = c.height || 80,
- interval = c.interval || 1,
- template = c.template,
- ratio = video.height / video.width,
- preloadImages = function (tmpl, max, start) {
- max = Math.floor(max / interval);
- if (start === undefined) {
- start = 1;
- }
- function load() {
- if (start > max) {
- return;
- }
- var img = new Image();
- img.src = tmpl.replace('{time}', start);
- img.onload = function () {
- start += 1;
- load();
- };
- }
- load();
- };
-
- if (c.preload !== false) {
- preloadImages(template, video.duration);
- }
-
- // 鼠标移动至播放条,可以显示出预览图
- bean.on(root, 'mousemove.thumbnails', '.fp-timeline', function (ev) {
-
- $('div.fp-pre,div.fp-next').remove();
-
- var x = ev.pageX || ev.clientX,
- delta = x - common.offset(timeline).left,
- percentage = delta / common.width(timeline),
- seconds = Math.round(percentage * api.video.duration);
-
- // 2nd condition safeguards at out of range retrieval attempts
- if (seconds < 0 || seconds > Math.round(api.video.duration)) {
- return;
- }
- // enables greater interval than one second between thumbnails
- seconds = Math.floor(seconds / interval);
-
- var fpthumbnails = $(timelineTooltip).find('.fp-thumbnails'),
- // 主缩略图的时间位置div
- fpseektime = $(timelineTooltip).find('#fp-seektime'),
- // 控制面板的宽度,视频宽度
- width = $(root).find('.fp-controls').width(),
- // 主缩略图距离视频左侧位置
- left = $(timelineTooltip).position().left,
- // 主缩略图距离视频右侧位置
- right = width - left - (height / ratio)-2,
- // 左右侧缩略图的宽度
- thumbwidth = c.thumbwidth || 150,
- // 步调,即每张缩略图显示的时间隔间
- step=c.step || 10;
-
- // 主缩略图的样式以及背景图片
- fpthumbnails.css({
- width: (height / ratio) + 'px',
- height: height + 'px',
- // {time} template expected to start at 1, video time/first frame starts at 0
- 'background-image': "url('" + template.replace('{time}', seconds + 1) + "')",
- 'background-repeat': 'no-repeat',
- 'background-size':'100% 100%',
- '-moz-background-size':'100% 100%', /* 老版本的 Firefox */
- 'border': '1px solid #333'
- });
- // 主缩略图的时间样式
- fpseektime.css({
- height:20 + 'px',
- 'text-align':'center',
- 'text-shadow': '1px 1px #000'
- });
- // 左侧缩略图,创建div
- if(left>0) {
- var leftnum = Math.ceil(left/thumbwidth);
- for(var i=0;i<leftnum;i++) {
- $(timelineTooltip).parent('.fp-controls').append('<div class="fp-pre"></div>');
- }
- }
- // 右侧缩略图,创建div
- if(right>0) {
- var rightnum = Math.ceil(right/thumbwidth);
- for(var i=0;i<rightnum;i++) {
- $(timelineTooltip).parent('.fp-controls').append('<div class="fp-next"></div>');
- }
- }
-
- //左侧只能显示一个缩略图位置时
- if(leftnum==1){
- $('.fp-pre').css({
- 'width':(left-2)+'px',
- 'height':height + 'px',
- 'position':'absolute',
- 'bottom':'30px',
- 'border-top': '1px solid #333',
- 'border-right': '1px solid #333',
- 'border-bottom': '1px solid #333',
- 'color':'#fff',
- 'background-color':'#000',
- 'overflow':'hidden',
- 'left':'1px',
- 'background-image':"url('" + template.replace('{time}', seconds + 1-step) + "')"
- });
- }else {
- // 出来最后一个元素的其他元素的样式设置
- $('.fp-pre').not(':last').each(function(i,value){
- $(this).css({
- 'width':thumbwidth + 'px',
- 'height':height + 'px',
- 'position':'absolute',
- 'bottom':'30px',
- 'border': '1px solid #333',
- 'color':'#fff',
- 'background-color':'#000',
- 'left':(left - (i+1)*(thumbwidth+2)) + 'px',
- 'background-image':"url('" + template.replace('{time}', seconds + 1-(i+1)*step) + "')",/*步调*/
- 'background-repeat': 'no-repeat',
- 'background-size':'100% 100%',
- '-moz-background-size':'100% 100%', /* 老版本的 Firefox */
- });
- });
- // 设置最后一个的样式
- $('.fp-pre').last().css({
- 'width':(left-(leftnum-1)*(thumbwidth+2)-1)+'px',
- 'height':height + 'px',
- 'position':'absolute',
- 'bottom':'30px',
- 'border-top': '1px solid #333',
- 'border-right': '1px solid #333',
- 'border-bottom': '1px solid #333',
- 'color':'#fff',
- 'color':'#fff',
- 'background-color':'#000',
- 'overflow':'hidden',
- 'left':'1px',
- 'background-image':"url('" + template.replace('{time}', seconds + 1-(leftnum-1)*step) + "')"
- });
- }
- // 右侧只有一个div时的样式
- if(rightnum==1){
- $('.fp-next').css({
- 'width':(width-(left+(height / ratio)+2)-2)+'px',
- 'height':height + 'px',
- 'position':'absolute',
- 'bottom':'30px',
- 'border-top': '1px solid #333',
- 'border-left': '1px solid #333',
- 'border-bottom': '1px solid #333',
- 'color':'#fff',
- 'color':'#fff',
- 'background-color':'#000',
- 'left':(left + (height / ratio)+2) + 'px',
- 'overflow':'hidden',
- 'background-image':"url('" + template.replace('{time}', seconds + 1+step) + "')"
-
- });
- }else {
- // 除了最后一个的其他样式
- $('.fp-next').not(':last').each(function(i,value){
- $(this).css({
- 'width':thumbwidth + 'px',
- 'height':height + 'px',
- 'position':'absolute',
- 'bottom':'30px',
- 'border': '1px solid #333',
- 'color':'#fff',
- 'background-color':'#000',
- 'left':(left + (height / ratio)+2 + i*(thumbwidth+2))+ 'px',
- 'background-image':"url('" + template.replace('{time}', seconds + 1+(i+1)*step) + "')",
- 'background-repeat': 'no-repeat',
- 'background-size':'100% 100%',
- '-moz-background-size':'100% 100%', /* 老版本的 Firefox */
-
- });
- });
- // 右侧最后一个div样式
- $('.fp-next').last().css({
- 'width':(right - (rightnum-1)*(thumbwidth+2)-1)+'px',
- 'height':height + 'px',
- 'position':'absolute',
- 'bottom':'30px',
- 'border-top': '1px solid #333',
- 'border-left': '1px solid #333',
- 'border-bottom': '1px solid #333',
- 'color':'#fff',
- 'background-color':'#000',
- 'left':(left + (height / ratio)+2 + ((rightnum-1)*(thumbwidth+2))) + 'px',
- 'overflow':'hidden',
- 'background-image':"url('" + template.replace('{time}', seconds + 1 +(rightnum-1)*step) + "')"
-
- });
- }
-
- });
-
-
- $('.fp-timeline').on('mouseout',function(){
- $('div.fp-pre,div.fp-next').remove();
- });
-
- });
-
- });
-
- })((typeof module === "object" && module.exports)
- ? require('flowplayer')
- : window.flowplayer,jQuery);
在html页面中的用法
- <div class="player1 no-toggle play-button">
-
- </div>
- <div style="overflow:hidden;width:200px;height:161px;background-image:url('thumbnails/myvideo8.jpg')">
- <!-- <img src="thumbnails/myvideo8.jpg"> -->
- </div>
- </div>
- <link rel="stylesheet" type="text/css" href="./flowplayer.quality-selector.css">
- <script type="text/javascript" src="./jquery-1.11.0.min.js"></script>
- <script type="text/javascript" src="./flowplayer6.js"></script>
- <script type="text/javascript" src="./thumbnails.js"></script>
- <script type="text/javascript" src="./flowplayer.quality-selector.js"></script>
- <script>
-
- $('.player1').flowplayer({
- adaptiveRatio:true,
- debug:true,
- autoplay:true,
- embed:false,
- clip: {
- title: 'Bauhausfffff',
- <span style="color:#FF0000;"> //这里配置
- thumbnails: {
- template: 'thumbnails/myvideo{time}.jpg',
- height: 100,
- thumbwidth: 150,
- step: 5
-
- },</span>
-
- sources: [
- {
- type: "video/mp4",
- src: "http:/host/Video/201503/20150320105047342.mp4"
- }
-
- ]
- },
-
- brand:{
- text: "MyBrand",
- showOnOrigin:false
- }
- });
- </script>
直接上几个大图
转自http://blog.csdn.net/u012979009/article/details/50623460