整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

经常下载电影的同学,我找到一个提升观影体验的办法!

多好玩好用的软件,欢迎点击右上角关注我~

用过更好的,就再也回不去了。

-- by Tony

差友们对于上面这句话有什么感想吗?托尼的感想就两个字:费钱。

比如要体验 4K 的分辨率,或者 144hz 的刷新率,就必须得换屏( 两者同时体验这种事情就。。不要想了吧。。。)

而换完屏后发现自己显卡推不动。。。就。。。换显卡,换完显卡再回头看自己原来 1080P 60hz 的屏,感觉眼睛都要瞎了。

嗯,怎么看东西这么糊,这块屏该换了。。。

那么有没有不怎么费钱。。。最。。。最好不花钱的办法,可以让暂时没啥钱的年轻人提升一下视频观感体验的?

答案当然是肯定的。今天托尼要给差友们介绍一个补帧软件。

先甩个视频给你们感受一下

传送门:https://v.qq.com/iframe/preview.html?vid=h1346p34ewn&width=500&height=375&auto=0

因为上传的压缩,效果没满血,后面告诉大家感受满血效果的办法。

什么是流畅?

为什么我明明已经特地下了个蓝光资源看起来还是不太得劲儿?是不是该换块屏了?但为什么我游戏过场的 CG 动画看起来又总是比电影要流畅?

决定流畅度好坏的因素主要有两个:帧率,以及动态模糊。

差友们还记得小时候看过的卓别林的默片吗?

早期的默片其实是一张一张画片按照固定的时间间隔在你面前呈现的,再经过人脑神奇的处理给人一种画面在动的感觉。

上面这个动图是由每秒 10 张静态的图片组成的,这个每秒 10 张指的就是帧率,也叫 fps。

fps = frame per second ( 帧每秒 )

而现在的电影多数是 24 fps,游戏的 CG 动画一般是 60 fps。所以单从帧率上来说,CG 动画是要优于电影的。

但是有一点又很神奇的就是,很多游戏玩起来明明连平均帧率都超过30帧,但是观感体验又没有 24 帧的电影来的舒爽顺畅,这又是为什么呢?

这基本上可以说是实时渲染和动态模糊的锅。

实时渲染就是即兴作画。电脑的硬件水平决定了它可以在相同的时间内,画多少张画给你讲同一个故事。

CG 动画就不同了,它是预先通过专业的计算设备渲染好以后导出的一个视频文件,换句话说我画画速度不够快,大不了我花一天的时间画一张画,慢工出细活,最后把画好的画,气定神闲地递给你,你看着感觉就一定很舒服。

而且即兴作画发挥不稳定,可能我之前给你画得挺快,一秒给你画 30 张,但是后来我手酸了,画得慢了,一秒只能给你递 10 张画。这样一会儿快一会儿慢,你看着就很不舒服。

而动态模糊是啥呢?是画的意境,写意画!

游戏里的画,是静物素描,每一张都很清晰。而电影里的画是写意画,有些地方朦胧,有些地方清晰。

画面里的物体是静是动,是快是慢其实都看得出来

(《 死侍 2 》 打斗画面 )

同一画面里面运动速度慢的东西看上去就比较清楚,比如死侍的脸,运动速度快的则是一个模糊的运动轨迹,比如死侍的手和手里的刀。这样的 “ 意境 ” 是方便我们大脑,脑补出一个完整流畅的打斗动作的。

现在的游戏为了游玩体验更好,也会加入一些 “ 意境 ” ,也就是运动模糊。

补帧?

补帧,就类似在你的连环画里面加入更多的画片。

坊间流传着各种各样关于补帧的传闻,甚至是传说。比如我们上面提到的脑补,这还真不是开玩笑的。

本质上所有的电影其实都是一系列静止画片按照一定的时距依次出现在人的眼前,而人脑接受到这些信息之后会产生画面在运动的幻象,这个现象就是似动现象

想象一圈小灯泡围成一个圆圈,灯泡按照顺时针逐个亮起灭掉,是不是会给人一种光球在转圈圈运动的感觉?但事实上是所有的灯泡都只发生了亮灭的变化,并没有发生位移。

但为什么我们会觉得光球在转圈圈呢,这就是脑补。既然叫脑补,自然是费脑子的。咱们假想一个极端的场景,托尼同样用两秒钟给你描述一个 “ 故事 ”。

首先,盯着这张图片看 2 秒。

然后再看这张动图。

( 这是一张两秒的动图,一共 30 张 画。)

哪个故事理解起来更容易?

还有另一种补法叫 “ 眨眼补帧 ” 了,顾名思义,通过眨眼来达到补帧的效果。

这是一种佛系玄学的补帧办法,讲究顺势而为,敌不动我动。比如玩游戏的时候突然卡起来了,看视频的时候帧率不够,玩家就可以通过眨眼来让画面变得流畅。一些修为更高的玩家还可以通过画面帧率具体状况来调整自己眨眼的频率以及每次闭眼的时长来达到流畅的观看体验。

但是 “ 眨眼补帧 ” 有一个致命的缺点就是眼睛容易累,而且有时候眼睛进东西了不得不眨眼会打破原来补好的稳定帧率。

是不是该翻译翻译,什么才叫流畅了?

用 AMD 显卡的差友们可能有听过 AMD Fluid Motion 这项技术,这是用 A 卡的一大好处,它可以为视频补帧,把 24 帧或者 30 帧的视频补齐到 60 帧。不仅仅是视频文件在本地播放的时候可以补,看在线视频的时候也可以补。

( AMD 官网的插帧技术描述 )

这里附上一个用 AMD Fluid Motion 技术补到 60 帧的 “ 愤怒的元首 ” 供大家欣赏一下。

传送门:https://v.qq.com/iframe/preview.html?vid=n13468fxrk0&width=500&height=375&auto=0

( 原 up 主视频效果更明显,视频地址在文末参考资料 )

感兴趣的差友可以去研究研究,托尼就不详细讲了毕竟。。。托尼没有 A 卡。

但是托尼找到了这个叫做 SVP 的软件。

这个软件全称叫做 Smooth Video Project,托尼的叫法叫 “ 丝丝顺滑观影计划 ”。目前在 Windows, Linux 和 Mac 平台都有。

Windows 有一个免费的试用版,Linux完全免费,而 Windows 下的 SVP 4 Pro 和 Mac 下的 SVP 4 Mac 都需要购买。

官网不同版本软件的特性对比

托尼试探性地点进 Mac 的购买链接里瞄了一眼。

稍微有点小贵。。。但是为什么这里还有个中文的 SVP 4 购买链接。

抱着试一试的心态我点进去发现了另一个专门给国人的购买入口。

托尼之前在 Windows 上试用了一下试用版,嘿!还真 TM 管用!

出于国际人道主义精神,这波信仰必须充值!

在电子邮件栏输入邮箱,用支付宝付完钱后,我的邮箱收到了一封通知邮件,里面附上了下载链接,用户名和注册码。

值得一提的是 Windows 和 Mac 都是支持无条件退款的,Windows 15 天,Mac 30 天。

在 Mac 下打开 dmg 文件就可以看到软件,一个安装说明,还有一个终端自运行文件。

跟着说明走把软件拖到 Application 文件夹里以后再运行一下那个自运行文件就基本大功告成了。

软件界面长这样

后面还有一系列设定要调,托尼这里就掠过了,官网和附件里的说明都非常详细,还是留一些小小的未知供差友探索。

虽然无论是 Windows 还是 Mac 上的准备工作都比较复杂,但是复杂的好处就是它不仅支持在线看视频,还支持较多的第三方播放器。

VLC 这个播放器无论是 Mac 还是 Windows 上都有,而且 SVP 也都支持。Mac 上的 SVP 4 就是把 VLC 里的去隔行滤镜替换成了它的 “ 补帧滤镜 ”

托尼拖了个头号玩家进去以后。。。就

炸裂了了了!

托尼把开启补帧和关闭补帧的播放画面录屏了下来,你们对比一下看看吧。

注意 Parzival 的头发

传送门:https://v.qq.com/iframe/preview.html?vid=h1346p34ewn&width=500&height=375&auto=0

Bilibili 支持上传 60 帧的视频,比这里效果更明显( B 站有条件的把分辨率调到 1080p60 最佳 )。

其实 Windows 上的免费版基本已经够用了,但是免费版没法设定目标补齐帧率,所以如果接的是一块 144hz 的显示屏,补帧效果会很不理想。

感兴趣的差友可以下个免费版尝鲜一下,稍微要费点功夫。但是当你随便拖个电影进去的那一刻,你会明白,一切都是值得的。至于冲不充值信仰就很随意了。

反正托尼用这个软件看了三部电影,现在关了软件看啥都像看 PPT 。

参考资料:

1. AMD 官网

https://www.amd.com/zh-hans/technologies/perfect-picture

2. SVP 官网

https://www.svp-team.cn.com/wiki/Main_Page

3. 愤怒的元首视频--Bilibili up主 open4all

https://www.bilibili.com/video/av8778335?from=search&seid=131898783601263129

4. 头号玩家补帧对比视频--Bilibili up主 盒子里面有什么

https://www.bilibili.com/video/av28914137

5. 死侍 2

6. 头号玩家

7. 卓别林-摩登时代

“ 感觉是时候重新温习一下

硬盘里的收藏了 ”

众号【传智播客博学谷】回复关键词:前端 PS Java(100G) Python(80G) 大数据 区块链 测试 PPT JS(40g+300教程) HTML 简历 领取相关学习资料!

一、HTML

1、<image>标签上title属性与alt属性的区别是什么?

alt属性是为了给那些不能看到你文档中图像的浏览者提供文字说明的。且长度必须少于100个英文字符或者用户必须保证替换文字尽可能的短。

这包括那些使用本来就不支持图像显示或者图像显示被关闭的浏览器的用户,视觉障碍的用户和使用屏幕阅读器的用户等。

title属性为设置该属性的元素提供建议性的信息。使用title属性提供非本质的额外信息。参考《alt和title属性的区别及应用》

2、分别写出以下几个HTML标签:文字加粗、下标、居中、字体

加粗:<b>、<strong>

下标:<sub>

居中:<center>

字体:<font>、<basefont>、参考《HTML标签列表》

3、请写出至少5个html5新增的标签,并说明其语义和应用场景

section:定义文档中的一个章节

nav:定义只包含导航链接的章节

header:定义页面或章节的头部。它经常包含 logo、页面标题和导航性的目录。

footer:定义页面或章节的尾部。它经常包含版权信息、法律信息链接和反馈建议用的地址。

aside:定义和页面内容关联度较低的内容——如果被删除,剩下的内容仍然很合理。

参考《HTML5 标签列表》

4、请说说你对标签语义化的理解?

a. 去掉或者丢失样式的时候能够让页面呈现出清晰的结构

b. 有利于SEO:和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息:爬虫依赖于标签来确定上下文和各个关键字的权重;

c. 方便其他设备解析(如屏幕阅读器、盲人阅读器、移动设备)以意义的方式来渲染网页;

d. 便于团队开发和维护,语义化更具可读性,遵循W3C标准的团队都遵循这个标准,可以减少差异化。

5、Doctype作用? 严格模式与混杂模式如何区分?它们有何意义?

声明位于文档中的最前面,处于 标签之前。告知浏览器以何种模式来渲染文档。

严格模式的排版和 JS 运作模式是,以该浏览器支持的最高标准运行。

在混杂模式中,页面以宽松的向后兼容的方式显示。模拟老式浏览器的行为以防止站点无法工作。

DOCTYPE不存在或格式不正确会导致文档以混杂模式呈现。

6、你知道多少种Doctype文档类型?

标签可声明三种 DTD 类型,分别表示严格版本、过渡版本以及基于框架的 HTML 文档。

HTML 4.01 规定了三种文档类型:Strict、Transitional 以及 Frameset。

XHTML 1.0 规定了三种 XML 文档类型:Strict、Transitional 以及 Frameset。

Standards (标准)模式(也就是严格呈现模式)用于呈现遵循最新标准的网页,

Quirks(包容)模式(也就是松散呈现模式或者兼容模式)用于呈现为传统浏览器而设计的网页。

7、HTML与XHTML——二者有什么区别

a. XHTML 元素必须被正确地嵌套。

b. XHTML 元素必须被关闭。

c. 标签名必须用小写字母。

d. XHTML 文档必须拥有根元素。

参考《XHTML 与 HTML 之间的差异》

8、html5有哪些新特性、移除了那些元素?

a. HTML5 现在已经不是 SGML 的子集,主要是关于图像,位置,存储,多任务等功能的增加。

b. 拖拽释放(Drag and drop) API

c. 语义化更好的内容标签(header,nav,footer,aside,article,section)

d. 音频、视频API(audio,video)

e. 画布(Canvas) API

f. 地理(Geolocation) API

g. 本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失

h. sessionStorage 的数据在页面会话结束时会被清除

i. 表单控件,calendar、date、time、email、url、search

j. 新的技术webworker, websocket等

移除的元素:

a. 纯表现的元素:basefont,big,center, s,strike,tt,u;

b. 对可用性产生负面影响的元素:frame,frameset,noframes;

9、iframe的优缺点?

优点:

a. 解决加载缓慢的第三方内容如图标和广告等的加载问题

b. iframe无刷新文件上传

c. iframe跨域通信

缺点:

a. iframe会阻塞主页面的Onload事件

b. 无法被一些搜索引擎索引到

c. 页面会增加服务器的http请求

d. 会产生很多页面,不容易管理。

参考《iframe的一些记录》

10、Quirks模式是什么?它和Standards模式有什么区别?

在写程序时我们也会经常遇到这样的问题,如何保证原来的接口不变,又提供更强大的功能,尤其是新功能不兼容旧功能时。IE6以前的页面大家都不会去写DTD,所以IE6就假定 如果写了DTD,就意味着这个页面将采用对CSS支持更好的布局,而如果没有,则采用兼容之前的布局方式。这就是Quirks模式(怪癖模式,诡异模式,怪异模式)。

区别:总体会有布局、样式解析和脚本执行三个方面的区别。

a. 盒模型:在W3C标准中,如果设置一个元素的宽度和高度,指的是元素内容的宽度和高度,而在Quirks 模式下,IE的宽度和高度还包含了padding和border。

b. 设置行内元素的高宽:在Standards模式下,给等行内元素设置wdith和height都不会生效,而在quirks模式下,则会生效。

c. 设置百分比的高度:在standards模式下,一个元素的高度是由其包含的内容来决定的,如果父元素没有设置百分比的高度,子元素设置一个百分比的高度是无效的用

d. 设置水平居中:使用margin:0 auto在standards模式下可以使元素水平居中,但在quirks模式下却会失效。

11、请阐述table的缺点

a. 太深的嵌套,比如table>tr>td>h3,会导致搜索引擎读取困难,而且,最直接的损失就是大大增加了冗余代码量。

b. 灵活性差,比如要将tr设置border等属性,是不行的,得通过td

c. 代码臃肿,当在table中套用table的时候,阅读代码会显得异常混乱

d. 混乱的colspan与rowspan,用来布局时,频繁使用他们会造成整个文档顺序混乱。

e. 不够语义

参考《为什么说table表格布局不好?》

12、简述一下src与href的区别

src用于替换当前元素;href用于在当前文档和引用资源之间确立联系。

src是source的缩写,指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置

href是Hypertext Reference的缩写,指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的链接

公众号【传智播客博学谷】回复关键词:前端 PS Java Python 大数据 区块链 测试 PPT JS HTML 简历 领取相关学习资料!

是多年以前用传统JQuery(easyUi)做项目时遇到的问题,今天把解决思路发布出来,也许能帮助到还在使用老架构的同学。

在开发类ERP的后台管理系统时,经常会看到这样的布局结构


每打开一个菜单都是单独打开一个Tab页,easyUi打开Tab页有两种方式:

  • 动态增加iframe
  • 在同一个Dom树中增加div 的方式

同一Dom树中存在命名污染的问题,包括样式也会互相影响,新增加页面里的样式很可能影响原有页面的布局

因此我们采用iframe的方式实现:

function addTab(subtitle,url,icon,closable){
	if(!$('#tabs').tabs('exists',subtitle)){
		$('#tabs').tabs('add',{
			title:subtitle,
			content:createFrame(url),
			closable:(closable==null?true:closable),
			icon:icon,
			fit:true
		});
	}else{
		$.messager.confirm('提示',eship.messages.updateTab,function(r){  
			if (r){    
				$('#tabs').tabs('select',subtitle);
				var currTab = $('#tabs').tabs('getSelected');
				$('#tabs').tabs('update',{
					tab:currTab,
					options:{content:createFrame(url)}
				});
			}
		});
	}
	tabClose();
}

function createFrame(url){
	var s = '<iframe scrolling="auto" frameborder="0"  src="'+url+'" style="width:100%;height:99%;"></iframe>';
	return s;
}

我们在使用时iframe Tab页时,页面中经常会有打开对话框的需求。

因为我们采用了iframe的方式,其实打开对话框是在子页面的iframe的dom中打开的,因此会被主页面遮挡,如图所示:


对话框移动过程中会被Tab标签遮挡,并且无法继续向上移动,并且不同iframe传递参数也比较麻烦,不是很方便,因此决定进行封装,基本原理如下:

封装模态对话框插件

  1. 判断是否在最顶层dom中执行,如果不在获取到顶层dom对象
  2. 在最顶层iframe中自动增加一个div,并通过这个div打开模态对话框
  3. 用堆栈记录打开对话框的相关属性options
  4. 关闭时,依次调用堆栈中的对话框,并关闭

优点:

  1. 增加getDialogOption方法,可方便获取当前对话框的option对象,可以方便的通过该对象进行窗口之间的值传递。
  2. 在关闭时,增加回调方法,可以在关闭时方便的调用父窗体的回调方法。
/**
 * jQuery dialog
 * 
 * @author rogerkuo
 * 
 * easy ui 对话框扩展,自动创建DIV,并将DIV放置在最顶层DOM中,避免对话框被iframe覆盖的情况
 */
(function($) {
	$.joyplus = function(){};
	$.joyplus.messager = function(){};
	
	//私有方法,用来负责创建对话框
	function _joy_show(options) {
		var defaults = {
			width : 800,
			height : 500,
			title : 'My Dialog',
			modal : true,
			onLoad : function(){
				var topDiaOptions = $.joyplus.getDialogOption();
				if( topDiaOptions.dialogId != undefined){//如果需要处理对话框连续弹出问题时,对焦点进行处理
					var topBody = _joy_get_top_body();
					var ele = $(topBody).find("#" + $.joyplus.getModelDialogId());
					var inputs = $(ele).find("input");
					if( inputs.length > 0 ){
						inputs[0].focus();
					}
				}
			}
			//dialogId : ""用来判断是否同一窗体,避免同一个业务多次弹出一个对话框,造成对话框堆叠,如果没有,不作处理
		};

		var isString = (typeof options == "string");
		if (isString) {
			options = {};
		}
		
		var d = {};
		
		$.extend(d , options);
		
		var topDiaOptions = $.joyplus.getDialogOption();
		
		if( topDiaOptions != undefined && topDiaOptions.dialogId != undefined &&  topDiaOptions.dialogId == d.dialogId ){

			return;
		}
		
		var isDataFunction = false;
		//新增dialog传值基础功能,可调用父窗体的方法,获取附加数据
		if( jQuery.type(d.extdata) == "function"){
			isDataFunction = true;
			d.extdata = d.extdata.call(this);
		}
		//新增dialog传值grid功能
		if( jQuery.type(d.grid) == "function"){
			isDataFunction = true;
			d.grid = d.grid.call(this);
		}
		if(!isDataFunction){
			d = $.extend(d , options);
		}
		

		_joy_get_options_cache().push(d);

		var opt = $.extend(defaults, options);

		opt.onClose = $.joyplus.closeModelDialog;

		var id = _joy_create_div();
		var top = _joy_get_top_body();

		var element = $(top).find("#" + id);
		$(element).dialog(opt);
		
	};

	//获取最上层的dialog对象
	function _joy_get_top_dialog() {
		var stack = _joy_get_dialog_stack();
		return stack.pop();
	};

	//获取对话框堆栈,因为用户可以在对话框上继续点开对话框,因次要记录对话框堆栈
	//先进后出
	function _joy_get_dialog_stack() {
		var top = _joy_get_cahce();
		return top;
	};

	//自动创建div,在dom的最顶层创建
	function _joy_create_div() {

		var new_id = _joy_get_new_id();
		var stack = _joy_get_dialog_stack();
		stack.push(new_id);
		$(_joy_get_top_body()).last().append("<div id='" + new_id + "'></div>");
		return new_id;
	};

	function _joy_get_top_body() {
		var top = window.parent.document.body;
		return $(top)
	};

	function _joy_get_cahce() {
		var a = window.top.$.fn._cache;
		return a;
	};

	function _joy_get_options_cache() {
		return window.top.$.fn._options_cache;
	};

	function _joy_get_new_id() {
		var date = new Date();
		return date.getTime().toString();
	};

	$.joyplus.showModelDialog = function(options , ifr) {
		if( ifr ){
			_joy_show(options);
		}
		else{
			//如果是最顶层的iframe
			if (window.top == window) {
				_joy_show(options);
			} else {//如果不是最顶层的iframe,则执行最顶层的showModelDialog方法
				options.curDom = window;
				window.top.$.joyplus.showModelDialog(options);
			}
		}
	};
	
	//获取当前对话框的options
	$.joyplus.getDialogOption = function(){
		var options = _joy_get_options_cache();
		return options[options.length-1];
	};
  
	//延时关闭
	$.joyplus.delayedClose = function(millisecond){
		var dialogId = $.joyplus.getModelDialogId();
		if(dialogId){
			$('#'+dialogId).dialog('minimize');
		}
		setTimeout($.joyplus.closeModelDialog,millisecond);
	};
  
	$.joyplus.closeModelDialog = function() {
		
		if (window.top == window) {
			var options = _joy_get_options_cache().pop();
      
      //父窗体可以实现onClose方法,在对话框关闭时,会调用该方法
			if (options.onClose != undefined && $.isFunction(options.onClose)) {
				options.onClose();
			}
     
      //提供父窗体回调函数
			if (options.callBack != undefined && $.isFunction(options.callBack)) {
				options.callBack();
			}
      
			if (options.validObj != undefined) {
				options.validObj.validatebox("validate");
			}
      //获取当前对话框id
			var id = _joy_get_top_dialog();
			var top = _joy_get_top_body();

      //释放自动创建的div
			var element = $(top).find("#" + id);
			$(element).dialog("destroy");
		} else {
			window.top.$.joyplus.closeModelDialog();
		}
	};
	
	$.joyplus.messager.alert = function(title, msg, icon, fn){
		if( eship.messages[msg] != undefined ){
			msg = eship.messages[msg];
		}
		$.messager.alert(title, msg, icon, fn);
	};
	
	//获取dialog对象ID
	$.joyplus.getModelDialogId = function() {
		var c =  _joy_get_cahce();	
		return c[c.length - 1];
	};

	$.fn._cache = new Array();
	$.fn._options_cache = new Array();

})(jQuery);

这样在使用时,只需调用简单方法即可