萨勒姆的女巫:The Crucible

萨勒姆的女巫

朋友邀请,去北影看了场话剧—-萨勒姆的女巫—-原本对话剧并不了解,最开始了解话剧也才是从《夏洛特烦恼》主演开心麻花,而对于话剧的概念只停留在了电影电视剧的创作中。话剧的表演确实于电影电视剧作品不同,我要刷新一下我的世界观。原来我错过了世界上很多美好的东西,而我却不知道。

剧本介绍

原剧本为,亚瑟 米勒 1953年剧本,四幕剧。该剧于1953年1月22日于百老汇的贝克剧院首次演出。之后成为了话剧经典。

小说原标题为 坩埚 “Crucible”,金属容器,可以将金属或者其他物质放入其中高温加热。剧中每个角色隐喻某种金属,接受着周围环境高温的考验。那些拥有超越死亡的道德人物,例如 约翰 普罗克托 和 瑞贝卡 寓指拒绝融化的物质。

角色

帕里斯 牧师

艾比 帕里斯侄女

蒂图巴 Tituba

约翰 普罗克托 John Proctor 率直正直的农场主,剧本的绝对男主

伊丽莎白 普罗克托 John妻子

黑尔 牧师

托马斯帕特南 想要占领别人的土地

安 帕特南 托马斯的妻子,怀孕8次,流产7次

感想

几个想留住的画面:

  • 开场时全员亮相的时候,开场时虽然有一些恐怖,但开场幽灵似得全员亮相震慑住了我。

  • 第二幕家中的对白,虽平淡,故事也很悲伤,但画面却很美好。

  • 第四幕开场伊丽莎白从台阶上出场,画面太美了。

  • 约翰和伊丽莎白的告别戏,将矛盾与个人命运推向高潮,命运的选择只在一瞬间。

很可惜的是这些画面并没有全部留下成为影像,观看的时候,我更愿意融入剧情而不愿意跳脱出来拿起相机。最后只从朋友那边盗来一些影像,不过我个人更加愿意将这些画面留在脑海。

全体亮相

伊丽莎白出场

伊丽莎白和约翰告别

剧情

在第一幕,最开始以为 帕里斯牧师 是非常正直的人物形象,而到后面几幕中形象大转变,从收受房契,到金子做的烛台,人物形象一落万丈。而同样人物形象转变的还有黑尔牧师,本来善良正直的牧师,到后来只能堕落颓废到劝说人们认罪。同样帕特南无理指控别人想要强行占他人领土地等等。人物形象的转变和刻画推动着剧情的发展。

而从第二幕开始约翰和伊丽莎白的戏开始,我才渐渐的进入剧情的设定,或者说,到第二幕的时候所有的背景故事,背景人物都才有所交代,故事才得以铺展开来。而第二幕过后剧情渐渐走向高潮,第三幕的审判,引入法官,将矛盾凸显,再到第四幕约翰伊丽莎白以及观众感到深深的绝望,将故事推向结局。

剧情中,几乎每个人的形象都刻画的比较生动。反派为各自的私心陷害别人,受到奴隶遭遇的女孩们的反抗,帕特南为夺取地产而进行的无理指控,而身为牧师的帕里斯为个人的私欲利用人们对上帝的信仰收敛钱财。(这里让我想到了那部印度电影《我个神啊》)而正面的角色,约翰虽然诚实正直,却也背叛了妻子,犯有奸淫罪,在为人上略有瑕疵,一直理性的黑尔牧师也在最后一幕变成了说服别人认罪的绝望者,而 伊丽莎白 为了拯救自己的丈夫,无奈得在法庭上作出了谎言。人人都在萨勒姆这样的炼狱中遭受折磨。

在真正的压抑和悲伤中让剧情达到高潮,然后结束整个舞台,才是真正好的剧本。

表演

对于表演真是,没办法说,就像之前一位同学和我说的一样,无论是电影还是话剧等等的剧情和表演中,在第一遍观看的时候总是让人无法集中到演员的表演上。我在看话剧的时候,第一二幕基本将注意力放到了剧情上,记忆剧情中人物的名字和相貌,整理故事中发生主角的关系,了解故事发生的地点和背景。直到第二幕过后才渐渐的融入到故事的本身。哎,真应该在事前就做一下功课的,不然观看太累太累。当然没有做事前功课也带来另外的好处,也就是剧情发展无法预料到,只有真正到黑幕降下才能知道最后的结局。有的时候心中会设定一个剧情,就像最后我会希望那些女孩会为自己的说谎和无理指控而受到惩罚,而约翰和伊丽莎白会被判为无罪,而这其实都是无力的空想,如果剧作真的做了此结局那就落入了俗套。

关于表演,第一幕中的帕里斯牧师和艾比的表演,后几幕中约翰和妻子的表演都让我印象深刻。其实个人最初的时候最喜欢帕里斯牧师的表演,但是在后来剧情的推进中帕里斯牧师渐渐地走向反面,对角色的厌恶消弱了帕里斯的表演。自第二幕起就喜欢上了约翰和伊丽莎白,就个人偏好来说,其实更加喜欢伊丽莎白平铺的对白,没有约翰激动时口喷唾沫,也没有艾比陷害别人时的高声呐喊,伊丽莎白的表演最能让我感受到自然。虽然伊丽莎白在剧中不是唯一女主,剧情扮演上分量适中,但是其诚实正直的基督徒形象让人无法忘却。

或许我们在评价一个角色表演的时候经常带入角色形象,观众永远只会喜欢剧中的正面角色,从而忽略反派角色,而事实上此剧的艾比和蒂图巴 这两个反面的角色表演同样精彩,hen 同样在第三幕出现的审判长,出现再对立面,而我却无法喜欢上他,或许是因为对长官的天然敌意,亦或许是对审判长审判的公平性的质疑,总之无法让我公正地去评价他的形象。

参考


2016-01-02

最棒的gif录屏:byzanz record

类Unix系统下最棒的gif录屏应用—- byzanz record 。可能大部分的人会在需要用到gif时,会先用录屏软件将需要截取的内容录成视频,然后用 ffmpeg 或者其他的应用将视频转成 gif 动画。而这样会产生几个问题:

  1. 麻烦,首先需要有录屏软件,二还得需要 ffmpeg 类似的转码工具
  2. 文件超大,我尝试过用 ffmpeg 转 gif,一般情况下转完之后的 gif 的文件都会比较大,即使是几秒钟的动画,大小可能也超出 gif 能够承受的大小,一般都会接近 10M。即使用 convert 优化,大小依然不乐观。

介绍

而现在要介绍的 byzanz-record 就是一个轻量级的直接录屏产生 gif 的应用。Byzanz 可以直接避免以上两个问题,将录屏这件事情变得非常容易。看Debian package上面的介绍

Byzanz is a desktop recorder and command line tool allowing you to record your current desktop or parts of it to an animated GIF, Ogg Theora, Flash or WebM. This is especially useful for publishing on the web.

Byzanz also allows recording of audio, when the output format supports it.

上面的介绍能够看到 Byzanz 的主要功能,同时说了支持的格式 GIF, Ogg Theora, Flash 和 WebM。同时使用的情况就是想要将内容发布到互联网上的时候。如果输出文件支持音频 Byzanz 也支持。

安装

有维护者将 Debian 的代码移植到 PPA,这样我们可以通过 PPA 来安装使用,打开终端,输入以下内容安装:

sudo add-apt-repository ppa:fossfreedom/byzanz
sudo apt-get update && sudo apt-get install byzanz

如果 Ubuntu 14.04 和以上版本,直接使用:

sudo apt-get install byzanz

使用

安装完毕之后可以在终端使用如下命名来熟悉使用 Byzanz:

byzanz-record --duration=10 --x=100 --y=200 --width=700 --height=400 out.gif

通过参数名字能够非常容易的知道含义,duration 就是时长,xy 就是坐标,截取画面左上角的值,widthheight 就是截取画面的寛和高,也就是画面的大小,最后就是输出文件的名字。

到现在可能有人发现 Byzanz 比较麻烦的地方了,有的时候我不知道要截取的目标的屏幕坐标和大小的时候呢,有的时候只想截取屏幕的某一个部分呢,如果只想录制一个窗口呢?

于是有人写了三个shell脚本文件:

  1. byzanz-record-window 选择一个窗口录制
  2. byzanz-record-region 选择部分窗口录制
  3. 简单GUI录制窗口

下面分别介绍这三个脚本使用,分别将这些脚本保存到本地,赋予执行权限 chmod +x filename,如果想要在终端任何地方使用,加入 $PATH 系统环境变量。

byzanz-record-window

脚本地址

下载脚本,加入 $PATH,使用例子:

  1. 运行 byzanz-record-window 30 -c output.gif
  2. 使用 alt-tab 选择想要抓取的窗口,单击
  3. 等待 10 秒钟(脚本中 $DELAY 变量设置)
  4. 听到 beep 一声,录制开始
  5. 30秒钟之后,beep 一声,录制结束

-c 参数表示byzanz将录制鼠标。

byzanz-record-region

脚本地址

需要依赖: xrectsel link. 使用 make 命令编译获取可执行的二进制。更多的配置参考项目文件。

使用详情参考上一个 section。

Gui version of byzanz-record-window

脚本地址

脚本由MHC提供。修改了以上脚本,做出了一个简单的GUI版本。

Example

长达30s钟的gif,而文件大小只有3.5M,对于Web使用来说这是非常可喜的一个大小。而对于10s左右的动画,几乎1M左右的大小,让我感到非常的震惊。

下面就是30s的gif,画质虽然损失较大,但是完全不影响观感。

byzanz record game

参考


2016-01-01 record , gif

2015年读书记录

年初的时候定下计划2015年一年至少阅读20本书,不管是小说还是专业书,现在离2015结束只有短短几天时间了,就梳理一下看过的书好了,顺带检查一下是否完成了任务。可惜结果很令我伤心。满心以为今年能读20本书,最后满打满算也只算读了16本书。今年欠了4本的债,明年2016年期望自己能够看下24本书吧。

小说

火星救援

看完电影之后还是不过瘾,于是乎补完小说。小说比电影更加精彩,电影因为时长的原因做了很多删减和改编,看小说更能体会到那种绝境的生存下去的力量。

小说摘录

  • 地球土壤中存在着几十种不同类型的细菌,它们对于植物的生长很关键。只有这样,它们才能繁殖得像……嗯,像细菌感染那样。
  • 为了营救我,一定花费了数亿美元。所有这些,就为了救我这个傻不愣登的植物学家,为吗呢? 好吧,我想我知道答案。有部分是因为我代表了进步、科学,还有我们梦想了几个世纪的行星际未来。但说真的,他们这么做的真正原因是:每个人都有一种本能,那就是把同伴救出来,有时候可能看上去不太像,但事实确实如此。
  • 远足的人在深山里迷路了,人们会发动搜救。火车出了事故,人们会排成长队献血。地震毁了一座城市,全世界的人都会捐出紧急物资。这种本能扎根于人类社会,每一种文化都不例外。是的,有些傻逼对此嗤之以鼻,但有多得多的人愿意这么做。正因为这样,才会有几十亿人站在我这边。

蝇王

舍友推荐,舍友因为是英语文学专业,推荐的这本黑色预言式的小说非常的赞,小说对人性的刻画实在是不能让人忘记。这本小说更让我认识了威廉·戈尔丁,英国很著名的小说家。这部小说主要讲述的就是因为战争流失到荒岛的一群小孩,因为利益形成各自集团,之间发生的冲突与矛盾。

摘录

  • 建立在社会理性基础上的民主在专制和暴力面前显得是那么的疲弱无力。
  • 苏格拉底说:“认识你自己”,至今仍是一句天启式的至理名言。在人类发展史上,人类对自身的恶的认识的确是极不清楚的。而人要认识自己,最深刻的莫过于认识自己的人性,如哲学家黎鸣所说:“自知者莫过于知己之人性,自胜者莫过于克服自己人性的弱点、抑制自己人性中潜在的恶念。”
  • 阻碍一个人进步的最大的敌人,往往是这个人自己,同理,阻碍一个文化发展的最大的敌人,往往是这个文化自身。
  • 暴风雨没有留下丝毫痕迹,海滩被冲刷得干干净净,就象被擦得锃亮的刀片。

1984

乔治奥威尔 反乌托邦小说,很早以前就想看不过没有坚持下来,今年总算是看完了。然后摘录一些警句。

  • 控制好人的思想,党就可以控制真理。
  • 人越来越工具化,越来越根据自己的利益和位置来改变事实。
  • 双重思想
  • 在成功的思想控制之下,一个人再也不会有他想法的对立面,而只知道什么才是“真理”的对立面。
  • 真理部
  • 思想罪
  • 谁掌握历史,谁就掌握未来;谁掌握现在,谁就掌握历史。
  • 一方面知道两者之间的矛盾,一方面又两者都相信;利用逻辑来反逻辑;一方面批判道德,一方面又自认为有道德
  • 档案司本身仅是真理部的一个部门而已。真理部的主要工作不是重建过去,而是向大洋国公民提供报纸、电影、课本、电屏节目、比赛、小说——也就是每种可以想象到的信息、指示或娱乐,从雕像到标语,从抒情诗到生物学论文,从小孩子用的拼写书到新话词典。真理部不仅要满足党的各种各样的需求,而且在较低层次上为了服务群众,各种工作也在全力进行着。
  • 你难道看不出新话的唯一目标就是窄化思想范围吗?到了最后,我们将会让思想罪变得完全不可能再犯,因为没有单词可以表达它。每种必要的概念将被一个单词精确地表达出来,这个单词的意义有严格规定,其他次要意义将被消除,然后被忘掉。
  • 如果有希望,它一定是在群众身上,因为只有在那里,在那些被漠视的大批人身上,在占大洋国人口百分之八十五的人身上,才有可能产生将党摧毁的力量。党无法从内部推翻,其敌人——如果有敌人的话——无法走到一起并相互确认。
  • 除非他们觉醒,否则永远不会反抗;但除非他们反抗,否则不会觉醒。
  • 只要他们继续干活、繁衍,他们别的行为就无关紧要。
  • 在党自身内部,没有几个人的观念是革命前就形成的。上一代人的绝大多数都在五六十年代的大清洗中被消灭了,幸存下来的极少数早就吓破了胆,思想上已经完全投降。
  • 只要让他们一直处于工作中,他们的态度便无关紧要
  • 战争是否真正发生着没有关系,而且因为不可能取得决定性胜利,战争进程的顺势逆势也没有关系,需要的只是应当保持战争状态。
  • 党有两个目标,一是征服全世界,二是一劳永逸地消灭独立思考的可能性。因此,党要解决的最主要难题有两个,一是如何在并非本人自愿透露的情况下发现他正在想什么,二是在没有预警的情况下于几秒钟内消灭上亿人口。
  • 二十世纪中叶进行的所谓“消灭私有财产”运动,其实意味着财富集中到了比以前少得多的人手里,不同之处是新的财富拥有者是个集团,而不是许多单独的人。
  • 大众从来不会自发造反,他们也从来不会仅仅因为受到压迫而造反。确实,只要不让他们掌握做比较的标准,他们就根本永远意识不到自己在受压迫。过去周期性发生的经济危机毫无必要,如今也不允许发生,但是其他情形,具有同样大范围的混乱状况能够而且确实会发生,只是不会带来政治性后果,因为不满不可能被表达得清晰有力。
  • 因此,从我们目前统治者的角度来说,唯一的真正危险,是从他们自身阶层分化出一个由能干、未尽其才、渴望权力的人所组成的集团,从而产生出自由主义和怀疑主义精神。
  • 寡头统治的要旨不是父传子、子传孙,而是坚持死者加诸生者的某种世界观和生活方式。只要它能指派自己的后继者,统治集团就永远会是统治集团。党所关心的不是血统上的永存,而是自身的不朽。只要等级化结构永远保持不变,至于是谁掌握权力并非重要。
  • “双重思想”意味着在一个人的脑子里,同时拥有两种相互矛盾的信念,而且两种都接受。
  • 混淆事实方面,也揭示了一种厚颜无耻的行径。和平部负责战争,真理部制造谎言,仁爱部负责拷打,富足部则制造饥饿
  • 此处的“政治”是最广义上的含义。即渴望将世界向某一方向推动,改变人们应该努力实现的那种社会的概念。同样,没有哪本书完全无政治倾向。那种艺术应与政治无关的观点本身即为一种政治态度。

哲学

论自由

约翰密尔,其实是很薄的书,因为当时英语课做presentation查资料找到,所以一直保存在待看列表。

全书要义可以概括为两条基本原则:一、个人的行为只要不涉及他人的利害,个人就有完全的行动自由,不必向社会负责;他人对于这个人的行为不得干涉,至多可以进行忠告、规劝或避而不理。二、只有当个人的行为危害到他人利益时,个人才应当接受社会的或法律的惩罚。社会只有在这个时候,才对个人的行为有裁判权,也才能对个人施加强制力量。  摘录自豆瓣

摘录

  • 公民自由或称社会自由,也就是要探讨社会所能合法施用于个人的权力的性质和限度
  • 自由,是指对于政治统治者的暴虐的防御。
  • 社会作为集体而凌驾于构成它的各别个人时,它的肆虐手段并不限于通过其政治机构而做出的措施。
  • 这两种思想方式各借对方的缺陷现出己方的功用,也在很大程度上各靠对方的反对才把己方保持在理性和健康的限度之内。
  • 真理在很大程度上乃是对立物的协调和结合问题
  • 在人类智力的现有状态下,只有通过意见分歧才能使真理的各个方面得到公平比赛的机会。
  • 似是而非地进行论证、对事实或论据予以压制、把案情的各项因素举陈错误、或者把反对方面的意见表述错误。
  • 在这一类触犯当中论战者所能犯的最坏的一种乃是把持见相反的人诋毁为坏的和不道德的人。
  • 人类应当有自由去形成意见并且无保留地发表意见,这所以成为必要的理由
  • 个人的自由必须约制在这样一个界限上,就是必须不使自己成为他人的妨碍。
  • 这些是他自己的本性经过他自己的教养加以发展和校改的表现——就称为具有一个性格
  • 总之,情事一到对于个人或公众有了确定的损害或者有了确定的损害之虞的时候,它就被提在自由的范围之外而被放进道德或法律的范围之内了。
  • 但积久却变成他们部落的习俗;而习俗在东方就等于宗教。
  • 第一,个人的行动只要不涉及自身以外什么人的利害,个人就不必向社会负责交代。
  • 第二,关于对他人利益有害的行动,个人则应当负责交代,并且还应当承受或是社会的或是法律的惩罚,假如社会的意见认为需要用这种或那种惩罚来保护它自己的话。
  • 总之,凡目标在于使人们不可能得到或难于得到某一货物的干涉都属于这一类。这类干涉可以反对之处,不在它们侵犯了生产者或销售者的自由,而在它们侵犯了购买者的自由。
  • 自由原则不能要求一个人有不要自由的自由。
  • 要知道,由国家强制教育是一回事,由国家亲自指导那个教育是完全不同的另一回事;人们所举的反对国家教育的一切理由,对于前者并不适用,对于后者则是适用的。
  • 不必要地增加政府的权力,会有很大的祸患。
  • 国家的价值,从长远看来,归根结蒂还在组成它的全体个人的价值。一个国家若只图在管理技巧方面或者在事务细节实践上所表现的类似的东西方面稍稍较好一些,而竟把全体个人智力的扩展和提高这一基本利益推迟下来;一个国家若只为——即使是为着有益的目的——使人们成为它手中较易制驭的工具而阻碍他们的发展,那么,它终将看到,小的人不能真正做出大的事;它还将看到,它不惜牺牲一切而求得的机器的完善,由于它为求机器较易使用而宁愿撤去了机器的基本动力,结果将使它一无所用。

快乐学哲学

快乐学哲学 英语课课程材料,通俗易懂的语言介绍西方哲学。推荐看英文原版。

技术

学习bash

学习bash 今年系统的学习一下Linux,但Linux体系太复杂,先从bash看起。

bash cookbook

更加详细一点的bash教程

参考bash 学习笔记.

鸟哥的Linux私房菜 基础学习篇(第二版) (第三版)

很经典,很详细,却也略显啰嗦的Linux入门书

笔记可以参考 linux 学习笔记

Boost程序库完全开发指南

因项目需要C++,Python的结合,看了boost.python部分,后来又自学了boost中的property_tree用来解析json。其他部分未详细看,只大略扫过。

Pro Git

学期中做了个讲座,大略的看了一些知识,Git实在强大,很多特性到现在我也没搞懂。这书要一直备着。

笔记参考git 学习笔记

Python核心编程(第二版)

只学了个大概,因为平时用C++多。

大数据时代

年初的时候读的,似乎已经忘得差不多了,总之“大数据”很玄乎。

其他

剧本结构设计

剧本结构设计 忘记了什么时候200-100的时候买的了,喜欢看电影,而我们总是谈论到剧情设计,于是就买了一本看。

Evernote超效率数字笔记术

一直订阅着这位作者的博客,看完这本书之后就全面使用Evernote中,放弃了OneNote,和Google Keep

摘录

  • 「剪貼」是一種被動而靜態的行爲,而「記錄」才是主動而動態的行動。

大教堂与集市

在观看纪录片《操作系统革命》中提到的这本书的作者,正好实验室有这本书,就拿了看了。这本书主要将软件开发的两大方式,正如书名所述,一种是公司内部集中式的开发,另外一种就是类似 GitHub 上那种分工合作式开发。这两者各有利弊,但作者作为 GNU 的倡导者必然是支持开源的。

别告诉我你会记笔记

别告诉我你会记笔记 学会记笔记是很重要的事情。

摘录

  • 成功的人总是把失败的经验写在笔记本上,然后重新出发
  • 你上谷歌搜索,只能找到别人的经验,唯有自己的笔记本,才是专属于你的资历累积。

看到最后一句话其实感触挺大,回想起 Google Reader 关闭,这真是 Google 做出的很差的一件事情。Reader 中的东西都曾经是阅读过,甚至做过笔记的东西,那也就是自己的东西,再怎么使用 Google 搜索,出来的东西也都不是自己的经验。所以现在我也在培养我隔断时间总结上一阶段的习惯,这样自己总结,自己写下来的东西才真正属于自己。

期待2016年美好的开始。


2015-12-29 book , reading

一个中国的缩影

很久没有看到这样反正真实中国的电影了,近两年的国产电影不是被早恋打胎的青春片,就是被各种古怪离奇的古装片,在就是无厘头的喜剧片所霸占。幸而有这样一部电影能够让2015年的国产电影画上一个稍稍圆满的句号。

剧情上,这样一部电影融入了太多真实的新闻,以至于会让人一一和某某事件联系上,人们往往说,电影往往是现实的表现。而这样一部老炮儿正是在真实这件事情上花了太多的功夫。从老北京的腔调到巷口胡同,从酒吧夜宿到马路飙车,从故友借钱到朋友援手,一件一件的小事敲打着人们的心,虽然故事发生在北京,虽然故事的主人公有着特殊的经历,可正是从这样的角度让我们看到了现代人们的人情冷漠,看到了整个中国的一个缩影,城管会不顾形象的殴打底层的百姓,匆匆的行人不会停下匆忙的脚步帮助路边无助的少女,甚至在看到别人跳楼时无情的煽动,更甚至于几十年的友情会在金钱面前变得一文不值。电影中的情节虽是虚构,却真实的让人发抖。电影看至一半就无法忍住打转的眼泪,同情六爷以及他的遭遇,为六爷的仁义感动。我们的社会正迈向黑暗,却少有六爷这样的人出面维护。为何我们会不相信路边求助的少女?为何我们不敢搀扶跌倒的老人?为何我们的眼里只有金钱?是我们少了什么东西吗?是我们被欺骗多次吗?亦或是像电影中说得那样“现在的人们,遇事都躲”。越来越多的人都不讲理,不讲规矩。往小了说就是百姓的日常百态,而往大了说就是三环十二少无法无天,在大就是他爹千万的账单。社会越来越没有理,越来越混乱,而这也仅仅是电影所表现出来的一部分而已。

剧情

在说到剧本设计上面,到现在很少的国产电影能够做到情节上的呼应,很多的时候就是主角想要做什么就凭空能够出现什么,而老炮儿在这方面做的非常的棒。现在能够列举的很多情节在前后发展中都能找打影子,六爷用报纸裹挟遗物扔到理发店呼应话匣子在理发店发现用报纸卷着的房产证,六爷心脏病发作呼应早先话匣子一直说心脏的问题,六爷在路边给建工女孩200元钱呼应片末女孩从远方寄来的挂号信,六爷在片尾穿军大衣用日本军刀独自约架呼应儿子和话匣子对话中对六爷十几年前一人单挑十几人的回忆。这样的剧本设计无意让故事的说服力大大增强。电影虽然有很多未交待的事情,但也正是因为这样才造就一部好电影的剧情。一部好电影就应该是将故事的一个切片展现给人们看,甚至能让人们产生就是电影结束了故事还在继续的错觉。如果真能做到那样,这样的电影离佳片也就不远了。而老炮儿正是这样一部电影,剧情没有交代六爷的妻子,也没有交代六爷故友的生活种种,同样也没有交代三环十二少,但是通过一些侧面的描述,通过电影的叙事交代,电影想要讲述的故事是完整的,那就够了。

表演

不得不说的冯小刚表演,早在电影上映之前就被无数的消息所报道,冯小刚凭借此片获得了金马影帝。一直很想看一看一个导演的表演功力,但是不得不说我被冯小刚的演技震撼到失语。可能原先还有一丝的“嘲讽”,只刚刚开头的城管戏,就让我对冯小刚刮目相看。以至于到最后和三环十二少演对手戏,再到拜访故人借钱救子,一丝一毫的表情动作,刷新了我对冯小刚的认识。片中饰演的六爷有着无比庞大的气场,平时看只是胡同巷子里面普普通通的市井小民,而一旦遇事,六爷凭借自己地位打抱不平,用“规矩”解决所有事情。

六爷的几场戏深深的印在了我的脑海里,一是开场和城管的戏,再就是到修车厂和三环十二少的戏,再到朋友(洋火儿)家借钱,到最后颐和园后野湖。每一个和冯小刚演对手戏的演员,无不给冯小刚的气场所压倒。

而其他的表演也就不想说什么了,这部电影只需要看冯小刚一个人演就够了,而六爷身边的一身肌肉的闷三儿(张涵予),无时不刻不在帮助六爷的话匣子(许晴),还有老实憨厚的灯罩儿,他们都个性十足,表演也到没有太大的瑕疵。尤其是闷三儿在修车厂,还有六爷被打闷三儿带领一帮人砸修车厂的几个镜头让张涵予非常帅气。只是在六爷面前就显得弱很多了。

因此最后在剧本上给7.5分,表演给8分,娱乐性思考性给8分。


2015-12-29 movie , china

2015年最喜欢的十部引进片

观影风向标做了一期引进片的排名,我顺便也简单地回忆了一下。然后根据2015年引进片豆列,找出了10部我非常喜欢的引进片。

就像观影风向标中所说,每个人都有一个自己的排名,没有最终的标准答案,每个人都有自己的喜好,不需要迁就谁,喜欢就好。

王牌特工:特工学院

当之无愧的年度最佳—-王牌特工:特工学院 2015-04-19,记得这部电影上映的时候并不是很了解,只是之后听了节目并看到一些影评觉得非常值得一看,在最后快下线的时候找了很远的一家影院看了。虽然当时同去的朋友对最后脑袋放烟花的镜头颇有微词,但是依然不减这部电影的魅力,我最喜欢的几大类电影中特工片一直靠前。而自从谍影重重马特达蒙不在参演,碟中谍系列,007系列偏离出我的口味稍远之后,很久没有看到一部对胃口的特工片了。不过很遗憾的是国内上映版的阉割。

火星救援

年度最佳科幻—-火星救援 2015-11-25,如果说2014年的星际穿越让我开始重拾起对宇宙的兴趣,那么这一部火星救援让我重拾起了对科幻片的兴趣。演员上有我很喜欢的马特达蒙,还有很多很多熟悉的脸孔,故事情节上有我喜欢的火星宇宙题材,这样一部电影如何能让我忘记。

模仿游戏

模仿游戏 2015-02-19,虽然是一部去年的电影,但是要是放到今年依然是一部非常棒的传记类电影,先不说图灵在计算机界的名声和地位,就卷福的生动表演也能让这部电影出彩。

头脑特工队

最佳动画—-头脑特工队 2015-11-01,天马行空的想象力,虽然说不上什么道理却非常有说服力的情节设定,以及让我找回的那份童真,无疑让这部电影在我这里的得分要高于大白 (●—●),说到超能陆战队,当然也是很不错的一部电影,剧本,情节设计毫无问题,只是我觉得过于好莱坞流水线产品,我在年初的时候就看完了这部片子,那时候这部片子还没有在国内上映,而过了一些时候之后,突然满大街,身边大家都在说着大白,我其实有些疑惑,后来才发现是因为国内上了,然后布天盖地的宣传,其实我不太明白是因为宣传造就了这部电影还是因为其他。

我的个神啊

我的个神啊 PK 2015-05-29,宗教题材的电影,观影风向标中波米总结的很好,这样一部电影有着自己的底线,没有否定宗教,也没有否定信仰,只是否定了打着宗教信仰招摇撞骗的神棍。这样一部电影在我们这样一个无神论的国家里,没有批判什么,但是身边的好多人却都以为这样的一部电影是反宗教的,真是太天真。

前目的地

前目的地 2014-12-04,虽然在14年年末的时候已经看了,看到时候甚至一度以为是一部超级烂的电影,因为剧情设定在前半段时间推进太缓慢,在酒店叙事那一段差点让我睡着,但是之后的剧情发展让我深深的膜拜这部电影。

超能查派

超能查派 2015-05-21,个人很喜欢的电影,一直对机器,人性很感兴趣,导演很聪明,将机器人形容成新生的婴儿,他的成长环境决定了机器人的人格,他的是非判断基于他所学习到的东西,而这不正也是一个人之所以为为一个人的基本常识吗?我们如何做一个判断?无非也就是从生活经历或听,或读,或看到的来下决定。当然这样一部电影,有主题,有思想,有特效,对我来说也就够了。

碟中谍5:神秘国度

碟中谍5:神秘国度 2015-09-13 之前也提到过碟中谍系列的特工片一直是很喜欢的系列,当然这一部也差,只是相较其他传达思考的电影来说,这真是纯粹的爆米花电影了。

速度与激情7

速度与激情7 2015-04-12 话题大片啦,加上保罗沃克的离世,加上片尾的煽情歌曲,这样一部有剧情,有动作,有视效的大片总有其一席之位。

歌曲改变人生

歌曲改变人生 Begin Again 2014-12-01 舍友推荐,虽然去年年末已看过,放到今年这样一部音乐类电影依然给我非常棒的感觉。

其他推荐影片

  • 机械姬 Ex Machina

想看却未看的引进片

  • 极速风流 Rush

    两年前的片子,如果不听节目真的不知道这样一部电影。

  • 思悼

    年末的时候不止一遍的在各种榜单上看过,总之有其上榜的理由吧。

  • 小王子

    准备看小说,然后再补一下好了。


2015-12-28 movie

记一天

早晨 初雪

morning snow

中午 披萨

pizza

中午 火锅

hotpot

饭后

chair

人生如此夫复何求。


2015-12-27 holiday

boost 学习笔记 4:智能指针 smart_ptr

对应书中第三章 内存管理,着重讲 boost 实现的智能指针,和内存池pool 等概念。众所周知,C++没有提供Java中的垃圾回收机制,因此 boost 实现智能指针用来管理内存避免一些问题。C++继承 C 高效灵活地指针,但是同样带了了很多问题:

  • 内存泄露 memory leak
  • 野指针 wild pointer
  • 越界访问 access denied

虽然STL提供了 auto_ptr,但是受限太多(不能放到容器中,因为不支持拷贝构造函数和赋值),因此很少有人使用。

智能指针(smart_ptr)是Boost各组件中,应用最为广泛的一个。使用智能指针需包含以下头文件,如果只使用智能指针 shared_ptr 可以只包含同名头文件。

#include <boost/smart_ptr.hpp>
using namespace boost;

Boost从很早就提供了如下的智能指针,并且功能一直保持稳定:

  • scoped_ptr:不可拷贝与赋值,承载new,只能在 scoped_ptr 声明的作用域内使用。
  • scoped_array:不可拷贝与赋值,承载new []。
  • shared_ptr:可拷贝,承载new。boost 库中重要组成,重点学习。
  • shared_array:可拷贝,承载new []。
  • weak_ptr:弱引用。
  • intrusive_ptr:需要自实现计数功能的,引用计数智能指针。

有其他任何问题,请查阅官方文档: http://www.boost.org/doc/libs/1_60_0/libs/smart_ptr/smart_ptr.htm

scoped_ptr

主要特点

  • scoped_ptr 只限于作用域内使用
  • 指针管理权不可转移,不支持拷贝构造函数与赋值操作。

从名字就可以看出,这种智能指针只限于作用域内使用,无法转移内置指针的管理权(不支持拷贝、=赋值等) 但是作用也很显然,例如:

void test()
{
    int* p = new int(3);
    ...
    delete p;
}

假设定义到delete之中…发生了异常,那么p就无法被delete,造成了内存泄漏。使用scoped_ptr就可以很好解决这个问题,只需要new的时候放到scoped_ptr之中就可以了。

主要用法

scoped_ptr 常用方法:

假设:

scoped_ptr<T> ptr_t(new T); // 假设内置指针为p_t

则:

  • ptr_t->get(),返回内部管理的指针,但禁止在get()出来的指针上执行delete。
  • ptr_t->xxx(),等同于p_t->xxx()
  • ptr_t.reset(),delete内部持有的p_t。
  • 假设T支持直接赋值,*ptr_t = xxx。
  • 再次强调,scoped_ptr不能做拷贝、赋值等转移指针管理权限的事情。因此,class内置域为scoped_ptr<T>是不允许的,除非class也禁止拷贝、赋值

例子:

// scoped_ptr usage
scoped_ptr<string> sp(new string("text"));
cout << *sp << endl;
cout << sp->size() << endl;

// pointer 管理权移交 scoped_ptr
auto_ptr<int> ap(new int(10));
scoped_ptr<int> scoped(ap);
assert(ap.get() == 0);

ap.reset(new int(20));
cout << *ap << ", " << *scoped << endl;

auto_ptr<int> ap2;
ap2 = ap;
assert(ap.get() == 0);			// ap is null-pointer

具体例子如下:

#include <iostream>
#include <boost/smart_ptr.hpp>

class SmallClass
{
    public:
        SmallClass(int x_val)
        {
            x = x_val;
            std::cout << "SmallClass construct " << x << std::endl;
        }

        virtual ~SmallClass()
        {
            std::cout << "SmallClass destory " << x << std::endl;
        }

        int GetX()
        {
            return x;
        }

    private:
        int x;
};

int main()
{
    std::cout << "main start" << std::endl;

    // scoped_ptr on basic
    boost::scoped_ptr<int> int_ptr(new int);
    *int_ptr = 100;
    ++*int_ptr;
    std::cout << *int_ptr << std::endl;

    // scoped_ptr on class
    boost::scoped_ptr<SmallClass> sc_ptr(new SmallClass(0));
    std::cout << sc_ptr->GetX() << std::endl;
    sc_ptr.reset();
    std::cout << "main end" << std::endl;

    return 0;
}

scoped_array

主要特点

同 scoped_ptr 基本一样,只不过可接受数组的new [],多了下标访问操作,其他类似。

  • 构造函数指针必须是 new[] 的结果,而不能是 new 表达式的结果
  • 没有 *, -> 操作符重载,因为 scoped_array 持有的不是一个普通指针
  • 析构函数使用 delete[] 释放资源,而不是 delete
  • 提供 operator[] 操作符重载,可以像普通数组一样用下标访问
  • 没有 begin(), end() 等类似容器迭代器操作函数

主要用法

scoped_array 轻巧方便,没有给程序增加额外负担,但是 scoped_array 功能有限,不能动态增长,也没有迭代器支持,不能搭配 STL 算法,仅有一个纯粹的“裸”数组接口。在需要动态数组的情况下我们应该使用 std::vector 。

例子如下:

#include <iostream>
#include <string>
#include <vector>
#include <boost/smart_ptr.hpp>

using namespace std;
using namespace boost;

int main(int argc, const char * argv[]) {

    scoped_array<int> scopedarr(new int[100]);
    scopedarr[0] = 100;           // 赋值
//    *(scopedarr+1) = 200;       // error

	// fill array with 100 value 2
    fill_n(&scopedarr[0], 100, 2);
    cout << scopedarr[2] << endl;

    scopedarr[3] = scopedarr[0]+scopedarr[1];
    cout << scopedarr[3] << endl;

    cout << scopedarr.get()[3] << endl;

    return 0;
}

shared_ptr

主要特点

最像指针的“智能指针”,是 boost.smart_ptr 库中最有价值,最重要的组成部分。支持拷贝构造函数、支持赋值操作。重载了*和->操作符用来模仿原始指针的行为。目前已成为tr1标准的一部分,发展自原始的auto_ptr,内置引用计数。

  • 支持拷贝构造函数,赋值操作
  • 重载 * 和 -> 操作符模仿原始指针
  • 内置引用计数

使用时候有3点要特别注意:

  1. 禁止get()得到指针地址后,执行delete,这个同scoped_ptr。
  2. 禁止循环引用,否则会出内存泄漏。
  3. 不要将shared_ptr用于函数的临时参数:

    // 下面这个是OK的。 void ok() { shared_ptr p(new int(2)); f(p, g()); }

    // 下面这个就可能内存泄漏! void bad() { f(shared_ptr(new int(2)), g()); }

主要使用

看看基本的使用例子。

#include <iostream>
#include <string>
#include <vector>
#include <random>
#include <boost/smart_ptr.hpp>
#include <boost/make_shared.hpp>

using namespace boost;

void print_count_func(shared_ptr<int> p){
    std::cout << "cout: " << p.use_count() << " value= " << *p << std::endl;
}

class shared {
private:
    shared_ptr<int> p;

public:
    shared(shared_ptr<int> _p):p(_p) {}
    void print(){
        std::cout << "cout: " << p.use_count() << " value= " << *p << std::endl;
    }
};

int main(int argc, const char * argv[]) {

    // 构造函数
    // 无参数构造空指针 shared_ptr
    shared_ptr<int> p0;

    // shared_ptr(Y * p) 获得指向类型 T 的指针 p 的管理权
    shared_ptr<int> p1(new int);
    *p1 = 12;

    // shared_ptr(shared_ptr const & r) 从另外 shared_ptr 获取管理权,两个 shared_ptr 同时共享一个指针管理权
    shared_ptr<int> p2(p1);                 // p1 引用计数加1
    std::cout << "p1 count: " << p1.use_count() << " value: " << *p2 << std::endl;
    *p2 = 13;
    std::cout << "p1 count: " << p1.use_count() << " value: " << *p2 << std::endl;
    p2.reset();
    std::cout << "p1 count: " << p1.use_count() << std::endl;


    // shared_ptr(std::auto_ptr<Y> & r) 从 auto_ptr 获得指针管理权, 同时 auto_ptr 失去管理权
    std::auto_ptr<int> p;
    shared_ptr<int> p3(p);

    // operator= 赋值操作符,从另外一个 shared_ptr 或 auto_ptr 获得指针管理权,等同于构造函数
    shared_ptr<int> p4 = p1;

    // shared_ptr(Y * p, D d) 类似于 shared_ptr(Y * p)
    // 第一个参数是要被管理的指针,第二个删除参数 d 告诉 shared_ptr 在析构时不使用 delete 来操作指针 p,而使用 d 来操作,把 delete p 换成 d(p)


    // usage
    shared_ptr<int> sp(new int(100));
    print_count_func(sp);
    shared shared1(sp), shared2(sp);

    shared1.print();
    shared2.print();

    *sp = 200;

    print_count_func(sp);
    shared1.print();

    // make_shared
    // include <boost/make_shared.hpp>

    shared_ptr<std::string> strp = make_shared<std::string>("make_test");
    shared_ptr<std::vector<int> > vecp = make_shared< std::vector<int> >(10, 3);

    std::cout << *strp << " " << vecp->size() << std::endl;

    // shared_ptr in vector
    // 因为 shared_ptr 实现了拷贝构造、=赋值构造等函数,因此可以完美的放入STL容器中。
    typedef std::vector< shared_ptr<int> > vs;
    vs v(10);

    int i = 0;
    for (vs::iterator pos = v.begin(); pos != v.end(); ++pos) {
        *pos = make_shared<int>(++i);
        std::cout << *(*pos) << ", ";
    }
    std::cout << std::endl;

    shared_ptr<int> ptest = v[9];
    *ptest = 100;
    std::cout << *v[9] << std::endl;


    return 0;
}

然后来讨论类中成员使用shared_ptr的例子,先扯一个稍微远一点的。假设我们类的成员需要new出来,先来看一个错误的例子:

#include <iostream>
#include <string>
#include <vector>
#include <random>
#include <boost/smart_ptr.hpp>
#include <boost/make_shared.hpp>

using namespace boost;

class ClassOne
{
public:
    ClassOne(int data_param):data(NULL)
    {
        init(data_param);
        std::cout << "construct" << std::endl;
    }

    virtual ~ClassOne()
    {
        if(data)
        {
            delete data;
        }
        data = NULL;
    }

    void init(int data_param)
    {
        if(data)
        {
            delete data;
        }
        data = new int(data_param);
    }

private:
    int* data;
};

int main(int argc, const char * argv[]) {
    ClassOne c1(10);
    ClassOne c2(c1);
    ClassOne c3 = c2;

    return 0;
}

上面的ClassOne没有问题,但是会由编译器生成默认的拷贝、赋值构造函数,于是,当c3=c2或者c2(c1)时, 指针data的地址被复制了多份,c1、c2、c3各持有一份,析构的时候就被delete了3次,于是memory error是必须的了。遇到这种情况传统做法就是,c1、c2、c3各保存独立的data区域,即深拷贝:自己写拷贝构造、赋值构造函数。

#include <iostream>
#include <string>
#include <vector>
#include <random>
#include <boost/smart_ptr.hpp>
#include <boost/make_shared.hpp>

using namespace boost;

class ClassOne
{
public:
    ClassOne():data(NULL) {}
    ClassOne(int data_param):data(NULL)
    {
        init(data_param);
        std::cout << "construct" << std::endl;
    }

    virtual ~ClassOne()
    {
        if (data) {
            delete data;
        }
        data = NULL;
    }

    ClassOne(const ClassOne& rhs){
        std::cout<< "copy " <<std::endl;
        data = NULL;
        init(*rhs.data);
    }

    ClassOne& operator = (const ClassOne& rhs){
        std::cout<< "assign " <<std::endl;
        delete data;               // delete your own old data
        data = new int(*rhs.data); // clone the rhs's data
        return *this;
    }

    void init(int data_param)
    {
        delete data;
        data = new int(data_param);
    }

private:
    int* data;
};

int main(int argc, const char * argv[]) {
    ClassOne c1(10);
    ClassOne c2(c1);       // 实际调用的是B(A)拷贝操作 call copy constructor
    ClassOne c3;
    c3 = c1;               // 申明之后进行赋值运算 call assignment function
    return 0;
}

现在我们假设另外一种情况,即data仍然需要从堆上new出来,但可以被若干实例共享。此时可以用 shared_ptr,而且甚至不需要编写拷贝构造、=赋值构造,就可以。如下:

#include <iostream>
#include <string>
#include <vector>
#include <random>
#include <boost/smart_ptr.hpp>
#include <boost/make_shared.hpp>

using namespace boost;

class ClassOne
{
public:
    ClassOne(int data_param):ptr_data(new int)
    {
        init(data_param);
        std::cout << "construct" << std::endl;
    }

    virtual ~ClassOne()
    {

    }

    int get_data() const{
        return *ptr_data;
    }

    long ptr_count() const {
        return ptr_data.use_count();
    }

    void init(int data_param)
    {
        *ptr_data = data_param;
    }

private:
    shared_ptr<int> ptr_data;
};

int main(int argc, const char * argv[]) {
    ClassOne c1(10);
    ClassOne c2(c1);
    ClassOne c3 = c2;

    std::cout << c1.ptr_count() << std::endl;
    std::cout << c2.get_data() << std::endl;

    return 0;
}

实际上,c++编译器自动生成的拷贝、=赋值构造函数完成了ptr_data的赋值拷贝工作,而智能指针赋值拷贝的同时,引用计数也加1了。在默认析构函数也是如此,析构函数执行之后,会调用所有成员(ptr_data)的析构函数,检查引用计数都为0后,会delete掉这个int。 从而完美的完成了无内存泄漏的、无内存出错的、多个实例之间的指针变量共享。

shared_array

同scoped_array类似,shared_array是shared_ptr的数组版本,不再赘述。

weak_ptr

weak_ptr 被设计为与 shared_ptr 共同工作,可以从一个 shared_ptr 或者另一个 weak_ptr 对象构造,获得资源的观测权。但是 weak_ptr 没有共享资源,它的构造不会引起指针引用计数的增加,同时,在析构的时候也不回引起引用计数的减少。

shared_ptr看起来已经很完美了,但有个致命缺陷:不能管理循环引用的对象。 看如下的例子:

#include <string>
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>

class parent;
class children;

typedef boost::shared_ptr<parent> parent_ptr;
typedef boost::shared_ptr<children> children_ptr;

class parent
{
public:
    ~parent() { std::cout <<"destroying parent\n"; }

public:
    children_ptr children;
};

class children
{
public:
    ~children() { std::cout <<"destroying children\n"; }

public:
    parent_ptr parent;
};

void test()
{
    parent_ptr father(new parent());
    children_ptr son(new children);

    father->children = son;
    son->parent = father;
}

void main()
{
    std::cout<<"begin test...\n";
    test();
    std::cout<<"end test.\n";
}

由于parent和child相互引用,他们的计数永远都为1,所以这样使用shared_ptr必然会导致内存泄漏。 boost::weak_ptr必须从一个boost::share_ptr或另一个boost::weak_ptr转换而来,这也说明,进行该对象的内存管理的是那个强引用的boost::share_ptr。boost::weak_ptr只是提供了对管理对象的一个访问手段。 弱引用不更改引用计数,类似普通指针,只要把循环引用的一方使用弱引用,即可解除循环引用。 还有两个常用的功能函数:expired()用于检测所管理的对象是否已经释放;lock()用于获取所管理的对象的强引用指针。

class children
{
public:
    ~children() { std::cout <<"destroying children\n"; }

public:
    boost::weak_ptr<parent> parent;
};

再次强调,weak_ptr必须从shared_ptr而来。

#include <boost/smart_ptr.hpp>
#include <iostream>

int main()
{
    boost::shared_ptr<int> ptr(new int(10));
    std::cout << ptr.use_count() << std::endl;
    boost::weak_ptr<int> ptr_weak(ptr);
    std::cout << ptr.use_count() << std::endl;
    std::cout << ptr_weak.expired() << std::endl;
    return 0;
}

intrusive_ptr

intrusive_ptr是一种“侵入式”的引用计数指针,实际并不提供引用计数功能,而是要求被存储的对象自己实现引用计数功能。可以应用于以下两种情形:

  • 对内存占用要求非常严格,要求必须与原始指针一样;
  • 现存代码已经有了引用计数机制管理的对象。 它提供intrusive_ptr_add_ref和intrusive_ptr_release函数接口供boost::intrusive_ptr调用。

参考


2015-12-24 boost , C++

boost 学习笔记 3: date_time

date_time 日期相关的库,是 boost 中少数需要编译的库,但是实践中,在 Linker 链接器中链接 libboost_date_time.a 即可。也就是在链接时,加上 -l(boost_date_time) 参数。

头文件

使用 date_timer 需要包含以下头文件。 diedaiqi #include <boost/date_time/gregorian/gregorian.hpp> using namespace boost::gregorian;

date基本使用

将时间想象成无线延伸的实数轴,时间点是数轴上的一个点,时间段就是区间,时长是有正负号的标量,两个时间点差,不属于数轴。时间点,时间段,时长之间可以进行运算,有些有实际意义,例如时间点+时长=时间点,时长+时长=时长,时间段交集∩时间段=时间段,时间点属于∈时间段等等,有些无意义等等。

date_time 库支持无限时间和无效时间(NADT, Not Available Date Time)。

日期基于格里高利历,支持从 1400-01-01 到 9999-12-31 之间的日期计算,不支持公元前日期,名字空间 boost::gregorian, 需要包含上文所述头文件。

构造

date 是 date_time 库处理日期的核心类,使用32位整数作为内部存储,以天位单位表示时间点概念,日期的构造方法

date d1;					// 无效日期
date d2(2010,1,1);
date d3(2000, Jan, 1);
date d4(d2);				// 拷贝构造

//you can compare between d1 d2 d3 d4 with == < >

也可以直接使用字符串来构造:

date d0 = from_string("1999-12-31");
date d5 ( from_string("2005/1/1") );
date d6 = from_undelimited_string("20001109");

或者直接从工厂类构造,调用 day_clock 的静态成员函数 local_day() 或者 universal_day() 返回当天的日期对象,分别是本地日期和 UTC 日期。 local_day() 依赖于操作系统时区设置。

// local date and UTC date
cout << day_clock::local_day() << endl;
cout << day_clock::universal_day() << endl;

特殊的日期:

date neg(neg_infin);			//negative infinite time
date pos(pos_infin);			//positive infinite time
date notdate(not_a_date_time);	//not a date time
date maxdate(max_date_time);	//max date
date mindate(min_date_time); 	//min date
cout << neg << endl << pos << endl << maxdate << endl << mindate <<endl;

date访问

date 成员函数 year(), month(), day() 返回年月日; year_month_day() 返回 date::ymd_type 结构,一次性获取年月日信息。

date nowdate = day_clock::local_day();
date::ymd_type ymd = nowdate.year_month_day();
cout << ymd.year << endl << ymd.month << endl << ymd.day << endl;

// day_of_week() return Monday, Tuesday..
// day_of_year() return number of the day in this year, max 366
// end_of_month() return the date of end of month
cout << nowdate.day_of_week() << endl;
cout << nowdate.day_of_year() << endl;
cout << nowdate.end_of_month() << endl;

day_of_week() 返回 date 星期数, 0 表示星期天; day_of_year() 返回 date 是当年第几天,最多366; end_of_month() 返回当月最后一天的 date 对象。

week_number() 返回date所在周是当年的第几个周,范围0到53. 如果年初的几天为去年的周,则周数为53,即第0周。

date 有5个 is_xxx() 函数,用于检验日期是否是一个特殊日期

  • is_infinity() 是否无限日期
  • is_neg_infinity() 是否负无限日期
  • is_pos_infinity() 是否正无限日期
  • is_not_a_date() 是否无效日期
  • is_special() 是否任意一个特殊日期

date输出

date 对象转成字符串输出

date now = day_clock::local_day();
// date output
cout << to_simple_string(now) << endl;			//YYYY-mmm-DD  mmm English
cout << to_iso_string(now) << endl;				//YYYYMMDD
cout << to_iso_extended_string(now) << endl;		//YYYY-MM-DD
cout << now << endl;

支持流输入

date inputdate;
cout << "Input a date: ";						// 2010-Jan-01
cin >> inputdate;								//default using YYYY-mmm-DD English abbr
cout << "\nThe input date is: " << inputdate << endl;

日期长度 date_duration

日期长度类 date_duration , 天为单位,度量时间长度的标量。值为任意整数,可正可负。

成员函数 days() 返回时长天数, is_special() 和 is_negative() 可判断 date_duration 对象是否为特殊值,或者负值, unit() 返回时长最小单位,即1

date_duration 支持全序比较操作 ==, != , <, <= 等等,支持加减法,递增递减,支持除整数,其他乘法,取模,取余不支持。

date_time 库为 date_duration 定义了一个常用的 typedef:days 名字。

days dd1(10);			// ten days
weeks w(2);				// two weeks
months m(5);			// five months
years y(2);				// two years

months m2 = y + m;		// two years and 5 months

日期计算

日期支持简单加减运算

// date compute
date dstart(2000,1,1), dend(2008,8,8);
cout << dend - dstart << endl;			// 3142 days

dstart += days(10);						// 2000-1-11
dstart += months(2);					// 2000-3-11
dstart -= weeks(1);						// 2000-3-4
dstart += years(4);						// 2004-3-4

//something need to be noticed
date endofmonth(2010, 3, 30);
endofmonth -= months(1);				//2010-2-28
endofmonth -= months(1);				//2010-1-31
endofmonth += months(2); 				//2010-3-31

日期区间 date_period

date_period 类来表示日期区间,时间轴上是一个左闭右开区间,端点是两个date对象,左值必须小于右值。

// date period
date_period pd(dstart, dend);			// (date, date)
date_period pd1(dstart, days(10));		// (date, days)

cout << pd << endl;

pd.shift(days(10));						// shift days 平移N天,长度不变
cout << pd << endl;
pd.expand(days(3));						// expand days 像两端扩展三天,长度加2n天
cout << pd << endl;

成员函数 begin() & end() 返回日期区间两个端点, end() 返回 last() 后的第一天。

date_period 可以全序比较运算,依据区间端点,即第一个区间的end() 和第二个区间的 begin(), 判断两个区间在时间轴上的位置大小。如果日期区间相交或者包含,比较操作无意义。

date_period 支持输入输出操作符,默认的输入输出格式是 YYYY-mmm-DD/YYYY-mmm-DD.

date date2014 = from_string("2014-01-01");
date nowdate = day_clock::local_day();
date_period pdl(date2014, nowdate);
date one_day_in_2015 = from_undelimited_string("20150101");
cout << pdl.contains(one_day_in_2015) << endl;

/*
 * date_period
 * is_before(), is_after()
 * contains()
 * intersects()				区间是否存在交集
 * intersections()			返回两个区间的交集
 * is_adjacent()			是否相邻
 * merge()					返回两个区间并集,如果无交集或者不相邻则返回无效区间
 * span()					合并两区间及两者间的间隔
 */

日期迭代器

/*
 * date iterator
 * use only ++iterator, --iterator, don't use iterator++, iterator--
 */
date d(2006,11,26);
day_iterator d_iter(d);
++d_iter;

year_iterator y_iter(d,3);		// 增减步长为3年
++y_iter;						// 增加3年
cout << y_iter->year();

综合运用

void print_one_month(){
	date nowdate = day_clock::local_day();
	date month_start(nowdate.year(), nowdate.month(), 1);
	date month_end = nowdate.end_of_month();

	for(day_iterator d_iter(month_start); d_iter != month_end; ++d_iter){
		cout << *d_iter << " " << d_iter->day_of_week() << "\t";
		if(d_iter->day_of_week() == boost::date_time::Sunday){
			cout << endl;
		}
	}
}
/*
 * input your birthday and years after that output the day of
 * future birthday
 */
void birthday_week(){
	date birthday(1992, 06, 05);
	years y30(30);
	date future_birthday = birthday + y30;
	cout << future_birthday.day_of_week() << endl;
}
/*
 * printout the days passed since you were born.
 */
void days_passed(){
	date birthday(1990, 10, 8);
	date nowdate = day_clock::local_day();
	cout << "Since you were born, there were " << nowdate - birthday << " days passed!"<< endl;
}

时间长度 time_duration

度量基本小时、分钟和秒钟,秒以下精确到微秒。

time_duration 有子类,度量不同时间分辨率,分别是: hours,minutes,seconds,millisec/milliseconds,microsec/microseconds和nanosec/nanoseconds。

#include <boost/date_time/posix_time/posix_time.hpp>
using namespace boost::posix_time;

// 2 h 01 m 06.001 s
time_duration td(1, 60, 60, 1000*1000*6 + 1000);

hours h(1);				// one hour
minutes m(10);
seconds s(30);
millisec ms(1);

time_duration td1 = h + m + s + ms;

time_duration td2 = duration_from_string("1:10:30:001");
cout << td2 << endl;			// 01:10:30.001000
cout << to_simple_string(td1) << endl;
cout << to_iso_string(td2) << endl;

时间点 ptime

构造函数中同时指定date和time_duration对象,ptime等于一个日期加上当天的时间偏移,轻量级对象,可以被高效的任意拷贝和赋值,支持全序比较和加减运算。

using namespace boost::gregorian;

ptime p(date(2010,3,5), hours(1));
ptime p1 = time_from_string("2012-09-11 09:09:09");
cout << p1 << endl;
ptime p2 = from_iso_string("20100909T011001");
cout << p2 << endl;

ptime nowtime = second_clock::local_time();			// second accurate
ptime nowtime2 = microsec_clock::universal_time();	// milli second accurate

ptime pnot(not_a_date_time);
ptime pinf(pos_infin);

cout << to_simple_string(nowtime) << endl;
cout << to_iso_string(nowtime) << endl;
cout << to_iso_extended_string(nowtime) << endl;

时间区间 time_period

time_period tp1(nowtime, hours(8));					// start from nowtime, last for eight hours
tp1.shift(hours(2));
tp1.expand(hours(1));

时间迭代器和日期迭代器,时间迭代器需要时间点和时间长度来构造。

ptime p(day_clock::local_day(),hours(10));
for (time_iterator t_iter(p, minutes(10)); t_iter < p+hours(1); ++ t_iter) {
    cout << *t_iter << endl;
}

2015-12-23 boost , C++

boost 学习笔记 2: timer

C++中操作时间的类。timer 是一个很小的库,提供简易的度量时间和进度显示的功能,可用于测试性能计时任务等大多数情况。timer 库包含三个组件, 计时器类 timer, progress_timer 和进度条指示类 progress_display。对应书中第二章内容。

timer

头文件

timer 位于boost命名空间,需要包含头文件 <boost/timer.hpp> 即:

#include <boost/timer.hpp>
using namespace boost;

基本方法

timer变量声明之后即开始计时工作,之后可以调用 elapsed() 方法来测量对象自创建之后所流逝的时间。成员函数 elapsed_max()elapsed_min() 方法返回 timer 能够测量的时间最大值和最小值,输出单位秒。timer类的实现代码很少,可参考源码学习。

/**
	 * timer simple and useful, suitable for short time task.
	 * Do not use it to calculate time for long time.
	 * For long time calculate check date_time lib
	 */
using boost::timer;
timer t;															// declare timer start counting
cout << "max timespan:" << t.elapsed_max() / 3600 << "h" << endl;
cout << "min timespan:" << t.elapsed_min() << "s" << endl;
cout << "now time elapsed:" << t.elapsed() << "s" << endl;

timer 实现源码

使用标准库头文件 中的 std::clock() 函数。

class timer
{
 public:
         timer() { _start_time = std::clock(); } // postcondition: elapsed()==0
//         timer( const timer& src );      // post: elapsed()==src.elapsed()
//        ~timer(){}
//  timer& operator=( const timer& src );  // post: elapsed()==src.elapsed()
  void   restart() { _start_time = std::clock(); } // post: elapsed()==0
  double elapsed() const                  // return elapsed time in seconds
    { return  double(std::clock() - _start_time) / CLOCKS_PER_SEC; }

  double elapsed_max() const   // return estimated maximum value for elapsed()
  // Portability warning: elapsed_max() may return too high a value on systems
  // where std::clock_t overflows or resets at surprising values.
  {
    return (double((std::numeric_limits<std::clock_t>::max)())
       - double(_start_time)) / double(CLOCKS_PER_SEC); 
  }

  double elapsed_min() const            // return minimum value for elapsed()
   { return double(1)/double(CLOCKS_PER_SEC); }

 private:
  std::clock_t _start_time;
}; // timer

使用建议

  • 不适合高精度计时,精度依赖操作系统或编译器
  • 不适合大跨度时间段测量,最大跨度只有几百小时,如需要天、月甚至年做时间单位,可使用 date_time 库

progress_timer

头文件

#include <boost/progress.hpp>
using namespace boost;

基本用法

在定义 progress_timer 之后,析构对象时会自动输出流逝时间。可以使用花括号,来使 progress_timer 实现计时功能。

progress_timer t;
// do some work
cout << t.elapsed() << endl;	//print out elapsed time for the task

progress_timer 精度问题,只能保留到小数点后两位,精确到百分之一秒。

progress_display

头文件

#include <boost/progress.hpp>
using namespace boost;

基本用法

在构造函数中传入总数,然后迭代更新进度条。

vector<string> v(100);
ofstream fs("test.txt");
progress_display pd(v.size());					// 构造函数,传入进度总数

vector<string>::iterator pos;
for (pos = v.begin(); pos != v.end(); ++pos){	// 遍历迭代,处理字符串,写文件
    fs << *pos << endl;
    ++pd;										// 更新进度
}

progress_display 问题

progress_display 向标准输出 cout 输出字符,无法将进度条和输出分离,如果循环中带有输出,则显示会很难看。


2015-12-22 boost , C++

ffmpeg 入门

那天需要将一段视频文件转成gif,偶遇ffmpeg,于是就学习了一下,它真的很强大。在看资料的过程中也是挺有趣的,发现其实kmplayer以及国内的QQ影音,暴风等等,都不同程度的使用了 ffmpeg,可是根据 ffmpeg 的开源许可LGPL,任何使用 ffmpeg 的软件都必须开源,于是乎QQ影音,暴风都上了 ffmpeg 的耻辱柱,如果没接触到 ffmpeg 还真不知道有这一茬,国内的黑心厂商真是拿开源社区的东西都不遵循开源协议。

下面就直接进正题吧:

几个概念

在进入 ffmpeg 入门之前有一些基本概念需要了解,我在查看 ffmpeg 的时候回头查阅了这些资料,觉得先行了解比较好,这些概念都是视频或者音频中的基本概念。

比特率

比特率,英文为 bit rate,描述每秒钟输出多少 KB 的参数,单位是 Kbps,也就是 kbit/s,8Kbit/s = 1KB/s。也就是说800Kbps意思就是每秒视频就要占用100KB磁盘空间。对于音频文件也存在比特率,同理。

压缩同一个视频,视频编码率越大,文件体积越大。视频编码率越大,画质越好,马赛克越少。

MP3一般使用的比特率为 8~320kbps。

帧数

每秒钟播放的图片数,单位 fps(英文:Frames Per Second),每秒的帧数或者帧率表示视频文件或者图形处理器场景时每秒钟能够更新的次数。

高的帧率可以得到更流畅、更逼真的动画。一般来说30fps就是可以接受的,但是将性能提升至60fps则可以明显提升交互感和逼真感,但是一般来说超过75fps一般就不容易察觉到有明显的流畅度提升了。如果帧率超过屏幕刷新率只会浪费图形处理的能力,因为显示器不能以这么快的速度更新,这样超过刷新率的帧率就浪费掉了。

在同一视频,同一码率的情况下,帧数越大,则画质越不好。尤其是运动的画面。因为每张画面会分担每秒有限的文件体积,如果画面越多,那么每张画面所能表现的内容就越有限。

当画面的FPS达到60帧/秒时,已经能满足绝大部分应用需求。一般情况下,如果能够保证游戏画面的平均FPS能够达到30帧/秒,那么画面已经基本流畅;能够达到50帧/秒,就基本可以体会到行云流水的感觉了。一般人很难分辨出60 帧/秒与100帧/秒有什么不同。

分辨率

最好理解的概念了,表示画面的大小,单位是像素 px。

和编码率的关系:越高的分辨率,需要越高的编码率,因为图像的细节多了,需要的文件体积也应该增大,否则还不如画面小一些,你会发现同一码率,画面越大,图像的马赛克程度越明显。

采样率

每秒钟对音频信号的采样次数,采样频率越高声音还原度越高,声音更加自然。单位是赫兹 Hz。音频文件一般使用的采样率是 44100 Hz ,也就是一秒钟采样 44100 次,之所以使用这个数值是因为经过了反复实验,人们发现这个采样精度最合适,低于这个值就会有较明显的损失,而高于这个值人的耳朵已经很难分辨,而且增大了数字音频所占用的空间。我们所使用的CD的采样标准就是44.1k,目前44.1k还是一个最通行的标准。

安装

Debian/Ubuntu/Linux Mint 下安装ffmpeg很简单:

apt-get install ffmpeg

其他操作系统安装方法,参考官网

如果想要手工编译 ffmpeg 可以参考官方 wiki。 Ubuntu/Debian/Mint 系手工编译 ffmpeg 参考 wiki

用法举例

显示视频信息

ffmpeg -i input.avi

将视频拆分多张图片,每一帧图片,保存到 frames 文件夹下,命名 frame001.png这种。可以加上-r 参数以用来限制每秒的帧数,-r 10 就表示每秒10帧。

ffmpeg -i input.mp4 frames/frame%03d.png

将多张图片合成视频

ffmpeg -i frames/frame%3d.png output.mp4

从视频文件中提取音频并保存为 mp3

ffmpeg -i input.mp4 -f mp3 output.mp3

如果需要可以在中间加上 -ar 44100 -ac 2 -ab 192 系数,表示采样率 44100 ,通道2立体声,码率192 kb/s.

将声音合成到视频中

ffmpeg -i input_music.mp3 -i input_video.mp4 output.mp4

格式之间转换 大部分的情况下直接运行一下即可

ffmpeg -i input.mp4 output.avi

将 flv 转码 MP4

ffmpeg -i input.flv -vcodec copy -acodec copy out.mp4

-vcodec copy-acodec copy 表示所使用的视频和音频编码格式,为原样拷贝。

对视频切片操作

比如需要从视频第1分45秒地方,剪10秒画面,-ss 表示开始位置,-t 表示延长时间

ffmpeg -i input.mp4 -ss 00:01:45 -t 10 output.mp4

加速视频

ffmpeg -i input.mp4 -vf “setpts=0.5*PTS” output.mp4

同理减速视频

ffmpeg -i input.mp4 -vf “setpts=2.0*PTS” output.mp4

此操作对音频无影响

视频10秒的地方(-ss 参数)截取一张1920x1080尺寸大小的,格式为jpg的图片 -ss后跟的时间单位为秒

ffmpeg -i input_video.mp4 -y -f image2 -t 0.001 -ss 10 -s 1920x1080 output.jpg

或者

ffmpeg -i input_video.mp4 -ss 00:00:06.000 -vframes 1 output.png 

把视频的前30帧转换成一个Gif

ffmpeg -i input_video.mp4 -vframes 30 -y -f gif output.gif

将视频转成 gif

ffmpeg -ss 00:00:00.000 -i input.mp4 -pix_fmt rgb24 -r 10 -s 320x240 -t 00:00:10.000 output.gif

将输入的文件从(-ss)设定的时间开始以10帧频率,输出到320x240大小的 gif 中,时间长度为-t 设定的参数。通过这样转换出来的 gif 一般都比较大,可以使用 ImageMagick 来优化图片的大小。

 convert -layers Optimize output.gif output_optimized.gif

把frame.[001-100].jpg序列帧和bg.mp3音频文件利用mpeg4编码方式合成分辨率720p的视频文件output.avi:

ffmpeg -i bg.mp3 -i frame.%3d.jpg -s hd720 -vcodec mpeg4 output.avi

要查看你的ffmpeg支持哪些格式,可以用如下命令:

ffmpeg -formats | less

设置输出文件编码率 64 kbit/s, To set the video bitrate of the output file to 64 kbit/s:

 ffmpeg -i input.avi -b:v 64k -bufsize 64k output.avi

设置输出文件帧率为24 fps,To force the frame rate of the output file to 24 fps:

 ffmpeg -i input.avi -r 24 output.avi

强制输入文件以1帧,输出文件24帧 , To force the frame rate of the input file (valid for raw formats only) to 1 fps and the frame rate of the output file to 24 fps:

 ffmpeg -r 1 -i input.mp4 -r 24 output.avi

下面几步分别是,创建frames文件夹,利用 ffmpeg 将视频文件以每秒10帧输出成图像保存到 frames 文件夹中,再利用 ImageMagick 将图片组成 gif。其中 convert 命令来自 ImageMagick。

mkdir frames
ffmpeg -i input.mp4 -r 10 frames/frame%03d.png
convert -delay 5 -loop 0 frames/frame*.png output.gif

Source: http://superuser.com/a/556031

转换文件格式

ffmpeg -y -i input_video.mp4 -bitexact -vcodec h263 -b 128 -r 15 -s 176x144 -acodec aac -ac 2 -ar 22500 -ab 24 -f 3gp test.3gp

ffmpeg -y -i test.wmv -ac 1 -acodec libamr_nb -ar 8000 -ab 12200 -s 176x144 -b 128 -r 15 test.3gp

利用ffmpeg屏幕录制

参考:https://trac.ffmpeg.org/wiki/Capture/Desktop

添加水印

ffmpeg -i input.mp4 -i picture.png -filter_complex overlay="(main_w/2)-(overlay_w/2):(main_h/2)-(overlay_h)/2" output.mp4

picture.png 为水印图片, overlay 为水印位置

ffmpeg使用语法

ffmpeg使用语法:

ffmpeg [global_options] {[input_file_options] -i input_file} ... {[output_file_options] output_file} ...

如果没有输入文件,那么视音频捕捉就会起作用。

作为通用的规则,选项一般用于下一个特定的文件。如果你给 –b 64选项,改选会设置下一个视频速率。对于原始输入文件,格式选项可能是需要的。

缺省情况下,ffmpeg试图尽可能的无损转换,采用与输入同样的音频视频参数来输出。

通用选项

-L license 显示协议
-h 帮助
-formats 显示可用的格式,编解码的,协议的
-decoders 可用解码器
-encoders 可用编码器

主要选项

-i filename 输入文件
-y 覆盖输出文件
-n 不覆盖输出文件,如果输出文件存在则退出
-t duration (input/output)
设置纪录时间 hh:mm:ss[.xxx]格式的记录时间也支持,在 -i 之前使用,则对输入文件限制记录时间;如果对输出文件使用,则是限制输出文件的时长。

-ss position
搜索到指定的时间 [-]hh:mm:ss[.xxx]的格式也支持 ,更多参考

-title string 设置标题
-author string 设置作者
-copyright string 设置版权
-comment string 设置评论
-f fmt 强迫采用格式fmt 输出

-c[:stream_specifier] codec (input/output, per-stream)
-codec[:stream_specifier] codec (input/output, per-stream)
给输入文件指定解码器,给输出文件指定编码器, codec 为编码器名字,如果 codec 值为 copy 则默认为和原视频一致。

-vcodec codec
vcodec 是 -codec:v 的一个别称,强制使用codec编解码方式,未设定时使用与输入流相同的编码器。如果用copy表示原始编解码数据必须被拷贝。

-target type 设置目标文件类型(vcd,svcd,dvd) 所有的格式选项(比特率,编解码以及缓冲区大小)自动设置,只需要输入如下的就可以了:

ffmpeg -i input.avi -target vcd /tmp/vcd.mpg

-hq 激活高质量设置
-itsoffset offset 设置以秒为基准的时间偏移,该选项影响所有后面的输入文件。该偏移被加到输入文件的时戳,定义一个正偏移意味着相应的流被延迟了 offset秒。 [-]hh:mm:ss[.xxx]的格式也支持

视频选项

-vframes number (output)
设置视频输出帧数,是-frames:v的别称。

-b bitrate 设置比特率,缺省200kb/s
-r fps 设置帧率 缺省25
-s size 设置画面的宽高

设置帧大小,分辨率, 格式为wxh 缺省为原视频大小。下面的简写也可以直接使用:
ntsc 720x480
snits 640x480
hd720 1280x720
hd1080 1920x1080
更多[参考](https://ffmpeg.org/ffmpeg-utils.html#toc-Video-size)

-aspect aspect 设置画面比例 4:3 16:9 或 1.3333 1.7777
-croptop size 设置顶部切除带大小 像素单位
-cropbottom size –cropleft size –cropright size
-padtop size 设置顶部补齐的大小 像素单位

-padbottom size –padleft size –padright size –padcolor color 设置补齐条颜色(hex,6个16进制的数,红:绿:兰排列,比如 000000代表黑色)

-vn 不做视频记录,输出无视频内容
-bt tolerance 设置视频码率容忍度kbit/s
-maxrate bitrate设置最大视频码率容忍度
-minrate bitreate 设置最小视频码率容忍度

-bufsize size 设置码率控制缓冲区大小

-sameq 使用同样视频质量作为源(VBR)

-pass n 选择处理遍数(1或者2)。两遍编码非常有用。第一遍生成统计信息,第二遍生成精确的请求的码率

-passlogfile file 选择两遍的纪录文件名为file

高级视频选项

-g gop_size 设置图像组大小

-intra 仅适用帧内编码

-qscale q 使用固定的视频量化标度(VBR)

-qmin q 最小视频量化标度(VBR)

-qmax q 最大视频量化标度(VBR)

-qdiff q 量化标度间最大偏差 (VBR)

-qblur blur 视频量化标度柔化(VBR)

-qcomp compression 视频量化标度压缩(VBR)

-rc_init_cplx complexity 一遍编码的初始复杂度

-b_qfactor factor 在p和b帧间的qp因子

-i_qfactor factor 在p和i帧间的qp因子

-b_qoffset offset 在p和b帧间的qp偏差

-i_qoffset offset 在p和i帧间的qp偏差

-rc_eq equation 设置码率控制方程 默认tex^qComp

-rc_override override 特定间隔下的速率控制重载

-me method 设置运动估计的方法 可用方法有 zero phods log x1 epzs(缺省) full

-dct_algo algo 设置dct的算法 可用的有 0 FF_DCT_AUTO 缺省的DCT 1 FF_DCT_FASTINT 2 FF_DCT_INT 3 FF_DCT_MMX 4 FF_DCT_MLIB 5 FF_DCT_ALTIVEC

-idct_algo algo 设置idct算法。可用的有 0 FF_IDCT_AUTO 缺省的IDCT 1 FF_IDCT_INT 2 FF_IDCT_SIMPLE 3 FF_IDCT_SIMPLEMMX 4 FF_IDCT_LIBMPEG2MMX 5 FF_IDCT_PS2 6 FF_IDCT_MLIB 7 FF_IDCT_ARM 8 FF_IDCT_ALTIVEC 9 FF_IDCT_SH4 10 FF_IDCT_SIMPLEARM

-er n 设置错误残留为n 1 FF_ER_CAREFULL 缺省 2 FF_ER_COMPLIANT 3 FF_ER_AGGRESSIVE 4 FF_ER_VERY_AGGRESSIVE

-ec bit_mask 设置错误掩蔽为bit_mask,该值为如下值的位掩码 1 FF_EC_GUESS_MVS (default=enabled) 2 FF_EC_DEBLOCK (default=enabled)

-bf frames 使用frames B 帧,支持mpeg1,mpeg2,mpeg4

-mbd mode 宏块决策 0 FF_MB_DECISION_SIMPLE 使用mb_cmp 1 FF_MB_DECISION_BITS 2 FF_MB_DECISION_RD

-4mv 使用4个运动矢量 仅用于mpeg4

-part 使用数据划分 仅用于mpeg4

-bug param 绕过没有被自动监测到编码器的问题

-strict strictness 跟标准的严格性

-aic 使能高级帧内编码 h263+

-umv 使能无限运动矢量 h263+

-deinterlace 不采用交织方法

-interlace 强迫交织法编码仅对mpeg2和mpeg4有效。当你的输入是交织的并且你想要保持交织以最小图像损失的时候采用该选项。可选的方法是不交织,但是损失更大

-psnr 计算压缩帧的psnr

-vstats 输出视频编码统计到vstats_hhmmss.log

-vhook module 插入视频处理模块 module 包括了模块名和参数,用空格分开

音频选项

-aframes number (output)
设置输出文件音频帧数,是-frames:a 的别名

-ab bitrate
设置音频码率,声音比特率,-ac 设为立体声时要以一半比特率来设置,比如192kbps 的就设置成96,高品质音乐建议160kbps(80) 一上

-ar freq
设置音频采样率,一般设置44100

-ac channels
设置通道,声道数, 缺省为1, 1为单声道,2为立体声

-an 不使用音频纪录

-acodec codec 使用codec编解码,是-codec:a的别名

音频/视频捕获选项

-vd device 设置视频捕获设备。比如/dev/video0

-vc channel 设置视频捕获通道 DV1394专用

-tvstd standard 设置电视标准 NTSC PAL(SECAM)

-dv1394 设置DV1394捕获

-av device 设置音频设备 比如/dev/dsp

高级选项

-map file:stream 设置输入流映射

-debug 打印特定调试信息

-benchmark 为基准测试加入时间

-hex 倾倒每一个输入包

-bitexact 仅使用位精确算法 用于编解码测试

-ps size 设置包大小,以bits为单位

-re 以本地帧频读数据,主要用于模拟捕获设备

-loop 循环输入流。只工作于图像流,用于ffserver测试

附录1:ffmpeg 简略帮助

Hyper fast Audio and Video encoder
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...

Getting help:
    -h      -- print basic options
    -h long -- print more options
    -h full -- print all options (including all format and codec specific options, very long)
    -h type=name -- print all options for the named decoder/encoder/demuxer/muxer/filter
    See man ffmpeg for detailed description of the options.

Print help / information / capabilities:
-L                  show license
-h topic            show help
-? topic            show help
-help topic         show help
--help topic        show help
-version            show version
-buildconf          show build configuration
-formats            show available formats
-devices            show available devices
-codecs             show available codecs
-decoders           show available decoders
-encoders           show available encoders
-bsfs               show available bit stream filters
-protocols          show available protocols
-filters            show available filters
-pix_fmts           show available pixel formats
-layouts            show standard channel layouts
-sample_fmts        show available audio sample formats
-colors             show available color names
-sources device     list sources of the input device
-sinks device       list sinks of the output device
-hwaccels           show available HW acceleration methods

Global options (affect whole program instead of just one file:
-loglevel loglevel  set logging level
-v loglevel         set logging level
-report             generate a report
-max_alloc bytes    set maximum size of a single allocated block
-y                  overwrite output files
-n                  never overwrite output files
-ignore_unknown     Ignore unknown stream types
-stats              print progress report during encoding
-max_error_rate ratio of errors (0.0: no errors, 1.0: 100% error  maximum error rate
-bits_per_raw_sample number  set the number of bits per raw sample
-vol volume         change audio volume (256=normal)

Per-file main options:
-f fmt              force format
-c codec            codec name
-codec codec        codec name
-pre preset         preset name
-map_metadata outfile[,metadata]:infile[,metadata]  set metadata information of outfile from infile
-t duration         record or transcode "duration" seconds of audio/video
-to time_stop       record or transcode stop time
-fs limit_size      set the limit file size in bytes
-ss time_off        set the start time offset
-sseof time_off     set the start time offset relative to EOF
-seek_timestamp     enable/disable seeking by timestamp with -ss
-timestamp time     set the recording timestamp ('now' to set the current time)
-metadata string=string  add metadata
-program title=string:st=number...  add program with specified streams
-target type        specify target file type ("vcd", "svcd", "dvd", "dv" or "dv50" with optional prefixes "pal-", "ntsc-" or "film-")
-apad               audio pad
-frames number      set the number of frames to output
-filter filter_graph  set stream filtergraph
-filter_script filename  read stream filtergraph description from a file
-reinit_filter      reinit filtergraph on input parameter changes
-discard            discard
-disposition        disposition

Video options:
-vframes number     set the number of video frames to output
-r rate             set frame rate (Hz value, fraction or abbreviation)
-s size             set frame size (WxH or abbreviation)
-aspect aspect      set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)
-bits_per_raw_sample number  set the number of bits per raw sample
-vn                 disable video
-vcodec codec       force video codec ('copy' to copy stream)
-timecode hh:mm:ss[:;.]ff  set initial TimeCode value.
-pass n             select the pass number (1 to 3)
-vf filter_graph    set video filters
-ab bitrate         audio bitrate (please use -b:a)
-b bitrate          video bitrate (please use -b:v)
-dn                 disable data

Audio options:
-aframes number     set the number of audio frames to output
-aq quality         set audio quality (codec-specific)
-ar rate            set audio sampling rate (in Hz)
-ac channels        set number of audio channels
-an                 disable audio
-acodec codec       force audio codec ('copy' to copy stream)
-vol volume         change audio volume (256=normal)
-af filter_graph    set audio filters

Subtitle options:
-s size             set frame size (WxH or abbreviation)
-sn                 disable subtitle
-scodec codec       force subtitle codec ('copy' to copy stream)
-stag fourcc/tag    force subtitle tag/fourcc
-fix_sub_duration   fix subtitles duration
-canvas_size size   set canvas size (WxH or abbreviation)
-spre preset        set the subtitle options to the indicated preset

附录2: 常用视频文件格式详解

常见的视频格式:

1.AVI格式   它的英文全称为Audio Video Interleaved,即音频视频交错格式。它于1992年被Microsoft公司推出,随Windows3.1一起被人们所认识和熟知。所谓“音频视频交错”,就是可以将视频和音频交织在一起进行同步播放。这种视频格式的优点是图像质量好,可以跨多个平台使用,但是其缺点是体积过于庞大,而且更加糟糕的是压缩标准不统一,因此经常会遇到高版本Windows媒体播放器播放不了采用早期编码编辑的AVI格式视频,而低版本Windows媒体播放器又播放不了采用最新编码编辑的AVI格式视频。其实解决的方法也非常简单,我们将在后面的视频转换、视频修复部分中给出解决的方案。

2.DV-AVI格式   DV的英文全称是Digital Video Format,是由索尼、松下、JVC等多家厂商联合提出的一种家用数字视频格式。目前非常流行的数码摄像机就是使用这种格式记录视频数据的。它可以通过电脑的IEEE 1394端口传输视频数据到电脑,也可以将电脑中编辑好的的视频数据回录到数码摄像机中。这种视频格式的文件扩展名一般也是.avi,所以我们习惯地叫它为DV-AVI格式。

3.MPEG格式   它的英文全称为Moving Picture Expert Group,即运动图像专家组格式,家里常看的VCD、SVCD、DVD就是这种格式。MPEG文件格式是运动图像压缩算法的国际标准,它采用了有损压缩方法从而减少运动图像中的冗余信息。MPEG的压缩方法说的更加深入一点就是保留相邻两幅画面绝大多数相同的部分,而把后续图像中和前面图像有冗余的部分去除,从而达到压缩的目的。目前MPEG格式有三个压缩标准,分别是MPEG-1、MPEG-2、和MPEG-4,另外,MPEG-7与MPEG-21仍处在研发阶段。   MPEG-1:制定于1992年,它是针对1.5Mbps以下数据传输率的数字存储媒体运动图像及其伴音编码而设计的国际标准。也就是我们通常所见到的VCD制作格式。这种视频格式的文件扩展名包括.mpg、.mlv、.mpe、.mpeg及VCD光盘中的.dat文件等。   MPEG-2:制定于1994年,设计目标为高级工业标准的图像质量以及更高的传输率。这种格式主要应用在DVD/SVCD的制作(压缩)方面,同时在一些HDTV(高清晰电视广播)和一些高要求视频编辑、处理上面也有相当的应用。这种视频格式的文件扩展名包括.mpg、.mpe、.mpeg、.m2v及DVD光盘上的.vob文件等。   MPEG-4:制定于1998年,MPEG-4是为了播放流式媒体的高质量视频而专门设计的,它可利用很窄的带度,通过帧重建技术,压缩和传输数据,以求使用最少的数据获得最佳的图像质量。MPEG-4最有吸引力的地方在于它能够保存接近于DVD画质的小体积视频文件。这种视频格式的文件扩展名包括.asf、.mov和DivX 、AVI等。

4.DivX格式   这是由MPEG-4衍生出的另一种视频编码(压缩)标准,也即我们通常所说的DVDrip格式,它采用了MPEG4的压缩算法同时又综合了MPEG-4与MP3各方面的技术,说白了就是使用DivX压缩技术对DVD盘片的视频图像进行高质量压缩,同时用MP3或AC3对音频进行压缩,然后再将视频与音频合成并加上相应的外挂字幕文件而形成的视频格式。其画质直逼DVD并且体积只有DVD的数分之一。

5.MOV格式   美国Apple公司开发的一种视频格式,默认的播放器是苹果的QuickTimePlayer。具有较高的压缩比率和较完美的视频清晰度等特点,但是其最大的特点还是跨平台性,即不仅能支持MacOS,同样也能支持Windows系列。

6.ASF格式   它的英文全称为Advanced Streaming format,它是微软为了和现在的Real Player竞争而推出的一种视频格式,用户可以直接使用Windows自带的Windows Media Player对其进行播放。由于它使用了MPEG-4的压缩算法,所以压缩率和图像的质量都很不错。

7.WMF格式   它的英文全称为Windows Media Video,也是微软推出的一种采用独立编码方式并且可以直接在网上实时观看视频节目的文件压缩格式。WMV格式的主要优点包括:本地或网络回放、可扩充的媒体类型、可伸缩的媒体类型、多语言支持、环境独立性、丰富的流间关系以及扩展性等。

8.RM格式   Networks公司所制定的音频视频压缩规范称之为Real Media,用户可以使用RealPlayer或RealOne Player对符合RealMedia技术规范的网络音频/视频资源进行实况转播,并且RealMedia还可以根据不同的网络传输速率制定出不同的压缩比率,从而实现在低速率的网络上进行影像数据实时传送和播放。这种格式的另一个特点是用户使用RealPlayer或RealOne Player播放器可以在不下载音频/视频内容的条件下实现在线播放。

9.RMVB格式   这是一种由RM视频格式升级延伸出的新视频格式,它的先进之处在于RMVB视频格式打破了原先RM格式那种平均压缩采样的方式,在保证平均压缩比的基础上合理利用比特率资源,就是说静止和动作场面少的画面场景采用较低的编码速率,这样可以留出更多的带宽空间,而这些带宽会在出现快速运动的画面场景时被利用。这样在保证了静止画面质量的前提下,大幅地提高了运动图像的画面质量,从而图像质量和文件大小之间就达到了微妙的平衡。

参考


2015-12-21 ffmpeg , linux

Google+

最近文章

  • vim presentation 大纲
  • Vim 寄存器 Vim 的寄存器可以看成 Vim 中额外用来存储信息的区域,虽然看不见,但是如果使用 x, s, y, p 等等命令的时候都无意识的使用到了 Vim 的寄存器(register).
  • vim normal 命令 替换::%s/^/#/g visual block:ggI# 注释第一行后用.重复执行每一行 我们可以在第三种方法之上用normal命令实现上述需求,步骤:
  • Vim 中的宏命令 Vim 的设计哲学中有这样一句话:”if you write a thing once, it is okay. However if you’re writing it twice or more times, then you should find a better way to do it”.
  • headless chrome puppeteer Headless 最早的时候在 PhantomJS 听说过这个概念,后来在 GitHub 各种项目中总有人不断提起这个概念,而最新看到的新闻便是 Chrome 开始支持 Headless,也正激起了我了解的欲望。