2009年12月31日星期四

2009年末小感悟

忙忙碌碌,而似乎又无所事事地过了令人兴奋2009年。2009令人兴奋的是因为项目的需要进入了一个对我来说全新的领域--软件工程,它极大地拓宽了我的眼界。需求分析,结构设计,代码开发,测试,重构代码,等等,每一块对我来说都是充满挑战又激动人心。本来想写一个2009年末总结,但是想写的东西太多,思路还没有理清楚,把一些总结先暂存在google doc里。

在2008年我花了一年的时间才了解到“知识积累,独立自主的判断力还有创新的重要性”,才知道“做研究在一定程度上说是一个感受失败的过程,所以必须静下心来要沉得住气。”然而2009年,我又花了一年的时间才大概知道:如何进行知识积累和如何做所谓创新,2009年总是进行着积累-->做项目,积累-->做项目的过程。多读书,多看papers,寻找并补足周边知识,然后思考并进行记录,似乎是对我来说最有效的积累的方法。积累的过程是相对痛苦的,然而,随着积累量的增多,做项目的效率越来越高,在做项目的过程中也感受到了很多的快乐。就像当时学德语一样,学的时候很辛苦,但是现在感受到了学会它的好处,快乐,它已经变成了一种技能,融入自己的体内,如果需要它的时候可以快乐,轻松地使用它。“大道至简”,很惭愧,这个简单的大道理,到了现在了才比较深刻地体会它,这个道理适用生活工作的很多方面,譬如学习编程,学的时候一定不会很轻松,然而当它变成一种自己的技能,但当我们再次使用它的时候,会有一种特别的快乐,那种快乐如同小时候刚学会骑自行车后,骑着车疯狂地在路上狂奔的一般,世界变大了,可以随着车轮的转动去追逐风,最重要的是这时不再是坐在父亲的自行车上,而是自己完全掌控的属于自己的自行车。哈,这就是2009年,我的一点小感悟。

再加两个刚刚闪过脑中的小感想,随手记下:其实R&D的工作常常就是将简单的事情重复做,不停地进行分析学习积累然后实现它,但是一个懂得重复的力量的人会拥有决定性的优势。对于和我一样做R&D的工程师而言,看似简单,无聊的生活之所以具有观赏性,那是拜我们的梦想所赐,我们需要跟极力延伸的心灵触角而让我们的生活具有更多的可能性。延伸心灵的触角吧,兴奋地去感受即将到来的2010吧。

刚刚吃完年末传统龙虾“大餐”,哈,已经可以听见外面的零星的烟花声了,赶紧祝大家,元旦快乐,Happy 0X7DA!

2009年12月29日星期二

读书:保罗·梅耶/迪克·卢赫《知道做到》

圣诞新年假期已经过了一半,愉快的读书时光飘过,这应该是我这个假期读的最后一本书,因为从明天开始对我而言轻松的假期结束了,迫于项目压力,接下来的五天我会比较忙,有一些代码需要重构,软件中有一个功能必须添加,还有两篇论文需要修改。读完一本好书后,写一篇读书笔记总是令人开心的,豆瓣上找到的想读的书已经有上百本了,家中,书架上的书,图书馆借的书,电脑里的电子书,还没有读的也有十几本。在这十几本好书中挑一本来读,也似乎是一个艰难的选择。最后我选择《知道做到》这本探讨提高“学习能力”的一百多页的小书,因为它最薄,呵呵,然后伴随着我喜欢的美国smooth jazz钢琴家Jim Chappell的专辑,泡一杯绿茶,开始本读书之旅。
以下是部分书摘:


#坚持记笔记,24小时之内重读笔记,把自己学到的知识传达给别人(要想开始应用新知识,最好的途径之一就是把它传授给别人。)。(看来我坚持做读书笔记是正确的。:D)
#可如果我们总是在接触新知识,却没有停下来去整合它们,并将其付诸实践,问题就来了。如果继续这样不停地接触新知识,我们的大脑就会堵塞。
#要想掌握一样东西,你必须完全沉浸其中,直到将其完全吸收。你必须慢慢地咀嚼、消化,直到它变成自己的一部分。
#要想真正了解一个领域,你必须透彻地吸收一些重要信息,而不是盲目地接触大量信息。
#人们没能学以致用的原因,1. 信息超载,2. 消极过滤,3. 缺少跟进。
#对于那些只接触过一次的信息,我们通常只能记住其中一小部分。
#我们应该少而精而非多而浅地去学习。
#要想掌握某件事,我们必须首先选择一些关键点,隔段时间就重复一下,让自己完全沉浸其中,并不断提高自己的知识和技能。关键在于间隔性重复。
#一旦真正透彻地掌握了自己的工作,人们就会变得更有创造性,甚至能够创造奇迹。
要想多留住一些自己所学到的东西,关键就在于要带着一种开放、积极的心态去聆听:
#不要带有任何偏见或先入之见;
#带着一种学习的态度,对新的信息感到兴奋;
#带着积极的期待;
#手里拿支笔,准备做记录;
#带着强烈的欲望,不仅要仔细聆听对方的讲话内容,还要努力激发出自己的想象力;
#带着一种“我该如何应用这些”的态度。


一个小时就可以读完的小书,所谈的道理也很简单就是:“知道,就一定要做到。做到,就一定要有结果。”但是还是挺值得花上一个小时去翻翻它。

2009年12月26日星期六

读书:Robert C. Martin《 Clean Code》

第一感觉:很有趣又非常实用的一本书,“Uncle Bob”的文笔相当幽默生动。代码质量与其整洁度成正比,大家都知道,但是如何打磨这些代码让它们变得整洁,这就是Bob大叔这本书所要传授的,在看本书的同时回忆一下自己是平时是如何编程的,会使阅读过程变得更有趣。

这本书前三章谈到了大量的小技巧和规则,例如使用可搜索的名称,分解函数,修改名称,消除重复,函数的第一规则是要短小,第二条规则是还要更短小,函数应该只做一件事,功能集中,有一个好名字(可以使用长而具有描述性的名称),它所带的最理想的参数数量是零。还有,类名和对象名应该是名词或名词短语,而方法名应当是动词或动词短语,减少代码依赖关系,让代码易读,等等。 其实这些小技巧和规则大家都知道,但是如何坚持使用和贯彻,这才是难点。

Chapter 4 Comment(注释),我很喜欢本章的引言“Don’t comment bad code—rewrite it.”—Brian W. Kernighan and P. J. Plaugher。还有一句话也说印象深刻“Keep in mind, however, that the only truly good comment is the comment you found a way not to write.”还有关于Position Markers位置标记的讨论,我个人就常常滥用Position Markers,书中谈到“ So use them very sparingly, and only when the benefit is significant. If you overuse banners, they’ll fall into the background noise and be ignored.” 这章还提到”Few practices are as odious as commenting-out code. Don’t do this!”,看完非常惭愧,我常常注释代码。

Chapter 5 Formatting(格式),这里有关于Vertical,Horizontal Formatting等等的讨论,这里摘抄一段话"It appears to be possible to build significant systems(FitNesse is close to 50,000 lines) out of files that are typically 200 lines long, with an upper limit of 500. Although this should not be a hard and fast rule, it should be consideredvery desirable. Small files are usually easier to understand than large files are."

Chapter 6 Objects and Data Structures (对象和数据结构)个人很喜欢这章,谈到了Data/Object Anti-Symmetry----数据、对象的反对称性,还有一些法则例如Data Transfer Objects(数据传送对象)

chapter 7 Error Handling (错误处理),谈到了使用异常而非返回码还有给出异常发生的环境说明等等。

chapter 8 Boundaries(边界),讨论了使用第三方代码,整洁的边界等等问题。

chapter 9 Unit Tests(单元测试),个人非常喜欢这章,非常实用,这里讨论了Test-Driven Development,The Three Laws of TDD,这里摘书中几句“What makes a clean test? Three things. Readability, readability, and readability. Readability is perhaps even more important in unit tests than it is in production code.” “Tests are as important to the health of a project as the production code is. Perhaps they are even more important, because tests preserve and enhance the flexibility, maintainability, and reusability of the production code. So keep your tests constantly clean.”

Chapter 10 Classes,谈到了类的组织和内聚等等问题,有一句话令人印象深刻,The first rule of classes is that they should be small, the second rule of classes is that they should be smaller than that.哈够深刻吧。

chapter 11 Systems,引言中的话非常精妙,““Complexity kills. It sucks the life out of developers,it makes products difficult to plan, build, and test.”—Ray Ozzie, CTO, Microsoft Corporation”。 其实无论是设计系统或单独的模块,永远要忘记使用可以用的“最简单的东西”。

Chapter 12 Emergence(迭进),谈到了通过迭进设计,以达到整洁目的等等。 

Chapter 13 Concurrency(并发编程),我觉得这章写的非常好,简单生动,如果对Concurrency programming有兴趣,推荐可以直接阅读这章。

chapter 14 Successive Refinement (关于逐步改进),从这章里摘抄一句话“So the solution is to continuously keep your code as clean and simple as it can be. Never let the rot get started.” 

Chapter 15 JUnit Internals(JUnit框架的内幕)和Chapter 16 Refactoring SerialDate,关于(重构SerialDate),跳过,没有阅读。 Chapter 17 Smells and Heuristics,翻阅,没有仔细阅读。

个人一点小感想,如果本书能再出一个“精华简化版”(例如去掉一些例子和说明,去掉第15章,减少第17章 Smells and Heuristics(味道与启发)的篇幅,并把附录的大部分砍掉),缩减到大概200左右就完美了,200页的小册子可以放在身边,作为程序员编程时的童子军规则随时查阅 :D。刚刚发现这本书已经有了中文版,读中文版一定更愉快体会“Uncle Bob”想要告诉我们的简单而又重要的大道理“Writing clean code is what you must do in order to call yourself a professional. There is no reasonable excuse for doing anything less than your best.”。

2009年12月24日星期四

2009平安夜

前几天大概是来到这个德国小城五年来最冷的一天(哦,可能不是最冷,但是一定是体感气温最低的一天,电脑桌面gadget显示最低温有-18度)。现在,平安夜户外大概有1度,户外还有一点前几天的积雪,就算是半个白色圣诞节吧,这也算是这五年来第一个“半个白色圣诞节”,可能是地球气候暖化吧,这五年来圣诞节时根本看不到雪。
平安夜对我来说就是收礼物的日子,不管多大还是很喜欢从身边“Santa Claus”得到礼物的感觉,刚刚拿到了lin给我的礼物:一条zara围巾,朋友寄给我的礼物居然被“粗心或是偷懒”的hermes快递员寄到邻居家(我家前天明明有人),邻居代为签收了,我隔天去拿时,邻居已经回老家过圣诞节,哈,有部分圣诞礼物要变成新年礼物了。
刚刚和lin吃了极度清贫的"圣诞大餐",一菜一汤,中餐:D。今天另一收获是终于有时间可以一口气看完的big bang theory的第一季。
现在正在读一个德国朋友去年给我的圣诞礼物,一本名叫generation doof的德文小书,还挺有趣的,居然放了一年没翻过,哈,不喜欢读德文书的原因是阅读德文的速度大概为我读英文的一半,中文的四分之一,真的实在很慢,很缺乏训练。书架上的这几年通过各种途径“被动”积累的德文“闲书”可能够我看上好几年:D。圣诞假期,有大块时间可以宅在家里读一些闲书,的确是一大快事,作为应景,圣诞夜我听的是Taylor Swift(我个人2009年度最喜欢的歌手)的Sounds of the Season专辑,六首歌从Last Christmas唱到White Christmas,够应景吧。
好了,最后祝大家:Frohe Weihnachten! Merry Christmas!

2009年12月23日星期三

读书:《洛克菲勒留给儿子的38封信》

居然今天才发现这本好书(五星级的好书),还好有豆瓣。书中的观点很贴近真实的人性和现实的世界,十九世纪初的洛克菲勒写给儿子的这38封信,今天看来仍旧可以深切地感受到他所分享的真正的大智慧,还可以深刻体会他对工作的态度,对生命的感悟还有他在商场上成功的秘诀。以下是部分书摘:

 

享有特权而无力量的人是废物,受过教育而无影响的人是一堆一文不值的垃圾。(Men of privilege without power are waste-material. Men of enlightenment without influence ate the poorest kind of rubbish.) 一个真正快乐的人,是能够享受他的创造的人。那些像海绵一样,只取不予的人,只会失去快乐。

如果你视工作为一种乐趣,人生就是天堂;如果你视工作为一种义务,人生就是地狱。         

一个人只有自己依靠自己,他才不会让自己失望,并能增加自己控制命运的机会。聪明人只会去促使事情发生。人生中最令人感到挫折的,莫过于想做的事太多,结果不但没有足够的时间去做,反而想到每件事的步骤繁多,而被做不到的情绪所震慑,以致一事无成。我们必须承认,时间有限,任何人都无法做完所有的事情。聪明人知道,并非所有的行动都会产生好的结果,只有明智的行动才能带来有意义的结果,所以聪明人只会汲取做了以后获得正面效果的工作,做与完成最大目标有关的工作,而且专心致志,所以聪明人总能做出最有价值的贡献,并捞到很多好处。

每个人都有失去自信,怀疑自己能力的时候,尤其是在逆境中的时候。但真正懂得行动艺术艺术的人,却可以用坚强的毅力克服它,会告诉自己每个人都有失败的时候,有失败得很惨的时候,会告诉自己不论事前做了多少准备、思考多久,真正着手做的时候,都有难免会犯错误。然而,被动的人,并不把失败视为学习和成长的机会,却总在告诫自己:或许我真的不行了,以致失去了积极参与未来的行动。

不论是要赢得财富,还是要赢得人生,优秀的人在竞技中想的不是输了我会怎样,而是要成为胜利者我应该做什么。

梦想+失败+挑战=成功之道。

智慧之书的第一章,也是最后一章,是天下没有白吃的午餐。如果人们知道出人头地,要以努力工作为代价,大部分人就会有所成就,同时也将使这个世界变得更美好。而白吃午餐的人,迟早会连本带利付出代价。

知识原本是空的,除非把知识会付诸行动,否则什么事都不会发生。而且,教科书上知识,几乎都是那些皓首穷经的知识匠人在象牙塔里编撰出来的,它难以帮你解决实际问题。世界上只有两种人头脑聪明:一种是活用自己的聪明人,例如艺术艺术家、学者、演员;一种是活用别人的聪明人,例如经营者、领导者。后一种人需要一种特殊的能力——抓住人心的能力。但很多领导者都是聪明的傻瓜,他们以为要抓住人心,就得依据由上而下的指挥方式。在我看来,这非但不能得到领导力,反而会降低很多。要知道,每个人对自己受到轻视都非常敏感,被看矮一截会丧失干劲。这样的领导者只会使部属无能化。 装傻带给你的好处很多很多。装傻的含义,是摆低姿态,变得谦虚,换句话说,就是瞒住你的聪明。越是聪明的人越有装傻的必要,因为就像那句格言所说的——越是成熟的稻子,越垂下稻穗。

一个人越是成功,越不会找借口。百分之九十九的失败都是因为人们惯于代寻借口。我鄙视那些善找借口的人,因为那是懦弱者的行为,我也同情那些善找借口的人,因为借口是制造失败的病源。一旦一个失败者找出一种“好”的借口,他就会抓住不放,然后总是拿这个借口对他自己和他人解释:为什么他无法再做下去,为什么他无法成功。起初,他还能自知他的借口多少是在撒谎,但是在不断重复使用后,他就会越来越相信那完全是真的,相信这个借口就是他无法成功的真正原因,结果他的大脑就开始怠惰、僵化,让努力想方设法要赢的动力化为零。但他们从不愿意承认自己是个爱找借口的人。很多人都迷信所谓的知识就是力量。在我看来这句话只说对了一半。拿才智不足当借口的人,也是错解了这句话的意义。知识只是一种潜在的力量,只有将知识付诸应用,而且是建设性地应用,才会显出它的威力。

我一直视“努力工作定会致富”为谎言,从不把为别人工作当作积累可观财富和上策,相反,我非常笃信为自己工作才能富有。我采取的一切行动都忠于我的伟大梦想和为实现这一梦想而不断达成的各个目标。

在做生意时,你绝对不能想把钱赚得一干二净,要留一点钱给别人赚。

成功不是以一个人的身高、体重、学历或家庭背景来衡量,而是以他思想的“大小”来决定。我们思想的大小决定我们成就的大小。这其中最重要的一条就是我们要看重自己,克服人类最大的弱点——自贬,千万不要廉价出卖自己。你们比你们想像中的还要伟大,所以,要将你们的思想扩大到你们真实的程度,绝不要看轻自己。

世界上有两种人永远不会富有:第一种是及时行乐者,第二种人,喜欢存钱的人。

我厌恶我的手下人说“不可能”。“不可能”是失败的用语,一旦一个人被“那是不可能的”想法所支配,他就能生出一联串的想法证明他想得没错。

我在读书时就记得这样一句话:“最完美的人就是那彻底投身于自己最擅长的活动的人。”后来,经我改造,将其变为我管理上的一个理念:最能创造价值的人就是那彻底投身于自己最喜欢的活动的人。

你是否听到过伐木者的产量会下降,只因为他没有抽出时间来磨利他和斧头?我们花钱,以及很多时间,去修饰头脑的外表,刮胡须、理头发,我们有没有必要花同样的时间和金钱,来化妆头脑的内部呢?当然有,而且可以做到。事实上,精神食粮随处可得,例如书籍。经由伟大的心灵撞击而写成的书籍,没有一本不是洗涤并充实我们心灵的食粮,它们早已一劳永逸地为后人指明了方向,而我们可以其中任意挑选我们想要的。伟大的书籍就伟大的智慧树,伟大的心灵之树,我们将在其中得以重塑。让我们学会既聪明又谦逊,既谦逊又聪明吧。

思考最多、感觉最高贵、行为也最正当的人,生活也过得最充实!           

2009年12月22日星期二

读书:Thomas A.Limoncelli《时间管理》

这本书其实不仅仅是给予系统管理员关于时间管理实战经验的建议,我们这些“IT民工”翻翻这本书也是很有助益的。本书讨论的策略其实也是很简单,也许你和我已经每天都在使用,例如:每天早上花5分钟计划一天。如果是每天要完成的事情,早一点完成它。清理实际办公桌和计算机的桌面。工作不要上网看新闻,信息(这点我总是做不到,改正中),远离即时通软件。每天使用例如google calender以计划好的工作,完成的Tasks以“X”标识(我每天下班时看到所有的Tasks被X掉总是很开心:D。)等等时间管理的方法。

以下是这本书中我最喜欢的观点:

(1)职场生涯的网络,也需要维护,而不是找新工作时候才联系,必须维护与他们的人际关系。

(2)休假是为了维持你的心里健康。拖延休假时间就像是拖延刷牙。现在跳过看起来很方便,但长远看来就不健康了。如果你浪费休假时间而用一天去跑差事,就无法达到减压目的。(深有感触啊,绝对是真理)

(3)例行公事可以节省工作,想一次,做许多事。

(4)浪费时间的事件,就是收益和时间付出的比值太低的活动。不要想用更有效率的方式把这些活动做完,最好的方法是试着将其排除掉。

(5)每件事都应该有某种益处。花五小时电子游戏有娱乐的益处,然而其他有益处的事可能对你更有价值。例如,花同样的时间做些家中维护工作来增加你的生活质量,这比炸掉几百万个古怪的外星人更有长期的益处。有些浪费时间的事件就是很难抗拒。所以,只好“一切适度”。(对于这一点我深有感触,以前我每天花很多时间阅读rss订阅,现在我每星期安排一个小时或几个小时(或者每天几分钟)阅读rss订阅的内容的时间。能看多少就看多少。这样,我每天获得至少一个小时。)


“工作时间 X 工作效率 = 工作的成果”,想获得最好最高的工作成果,我们所要做的就是首先提高时间效率(这是最重要的,很多人自认为投入了不少时间在工作,但是成果很小,这就是因为他投入的是“低效率”的时间),其次是使用一些策略来节约时间。心理学家说,养成一个新习惯需要花21天,21天重复做同样的事情会让你的大脑毫不费力地把这件事情变成习惯。其实关于时间管理的方法大家几乎都知道,也有很多比本书的方法更有效的方法,时间管理也是因人而异,但是如何坚持使用它们,并养成习惯,这才是关键,以下是书中提出的时间管理的方法,特此摘抄出来,与“众IT民工”共勉:


给时间管理的信息一个“数据库”(使用笔记)。将脑力留给最重要的事(节省内存)。(清晰的头脑很重要。胡乱的思路充满分散力,无法让你保持专心。)开发例行公事并持之以恒(程序代码函数库再利用,不要重新发明既有的东西)形成习惯与信念(以预先计算的结果取代运行时的计算)。在“项目期间”保持专心(就像一个核心信号)。以工作生活上的工具管理社交生活(社交生活不是一个可选功能)。

2009年12月21日星期一

读书:吉本佳生《在星巴克要买大杯咖啡!》

普及性的经济学入门读物,通过一些简单的例子解释了一些价格与生活经济学常识,很简单但是不够生动,个人感觉上翻译尚不完美,但是还是很受启发。

在前四章谈到了,同物不同价的根本原因在于“交易成本”。物流体系。规模经济的效率(讨论了电视机或数码相机的价格越来越便宜的问题)。时间成本的概念。也谈到了企业的销售策略:例如对不同消费能力层次的顾客采取分而治之的策略。

第五章“在星巴克应该消费哪款杯子的咖啡?”,本书的书名回答了这个问题,要买大杯咖啡,因为节约交易成本能使经营者与消费者共同受益。在这章里还可以了解一些简单成本计算问题。当然了,众所周知IT渠道是节约交易成本的关键环节。

在第六章提到了有些情况下,追加成本(追加制造一个产品时的成本,常常是生产设备未运转时投入生产)决定价格。各种商品都是劳动成本的集合体,并贯穿于产销链的每个环节。这里还提到了“食品生产企业的惯用手法是随行就市,即根据成本的增减调整产品重量以赚取利润。”,难怪薯片的重量常常变化。

个人相当推崇第七章“现实生活中人们之间的经济差距为什么难以消除?”适合比较仔细阅读。作者提出了一些观点,例如,“努力工作以维持高收入的群体,其可以自由支配的时间较少,他们的时间成本相当高。交易成本高,所以可以接受高的价格。然而一部分人其收入较低,但是有充裕的其他财产性收入,他们的交易成本较低,生活很悠闲自得。”“高收入的原因区分为社会地位,工作能力和工作时间。有两类高收入人群:1工作能力强,工作时间长。2工作能让稍逊前者,工作时间短,但有特别的社会地位。”很有道理,看看自己身边的人就明了了。要提高自己的收入,作者提出了“要努力做到正确认清和评价自己,发挥自身具备的比较优势(比较优势和实际利息两个很重要的经济学概念)。并且需要具备基本能力和良好的个性以便能够在工作上获得更多更好的机会。”

薄薄的小书很简单,三个小时左右就可以读完,挺适合在晚上听着音乐轻松阅读。

2009年12月16日星期三

读书:《漫画健康养生手册》

从朋友家发现一本关于上班族健康漫画《漫画健康养生手册》,大喜,立刻就借过来,今天上班的时候慢慢看,呵呵。

看到一章关于健康自测:谈到“健康人的手指甲上都有一个小月牙,而且大拇指的小月牙应该占到指甲的四分之一,除小手指外其他的手指也应占1/5到1/6,这样代表体内的寒热是比较均衡的。如果只有大拇指有小月牙,说明体内寒重,如果全部指甲都没有小月牙说明体内大寒,人的体力会比较差,血少,血稀。反之,就是内热大。”我赶紧看看自己的指甲,哇,体内寒重!!相信你看到这里一定也在看自己的指甲吧,呵呵,你的寒热是否均衡呢?

书中谈到,预防驼背的最佳方法就是“身子坐直双肩向后收,头颈部尽量要向后,每天做几分钟,人永远不会驼背。”我们每天在电脑前n小时,颈椎和背都很容易出现问题,一定要预防驼背,这个方法就简单又实用。

通过这本书还可以了解一些关于穴道的养生保健方法。有一个方法甚是有趣,这里摘抄出来和大家分享,这个方法叫叩齿法:据说能强肾固肾,乌发满头。这个方法实行起来也很的简单就是“没事儿的时候多做叩齿活动,就是嘴唇微闭,上下牙齿有节奏撞击就行了。每次叩齿100到400次(后面的槽牙一定要撞击到)牙齿的经络和肾经是相通的,坚固牙齿就可以对肾起一个反固的作用。能让肾强壮。固肾补肾。”呵呵,在公众场合就不要练了,不然会吓到人的。

书中谈到的“站立环抱养生法”,据说可消除无意识紧张。所谓“站立环抱养生法”就是随意地站立(两脚与肩宽)双手十指自然张开,双臂在胸前做环抱状,全身都放松下来,别耸肩。站十分钟就可以了。我个人认为这个方法不错,自己试了一下还有些效果。

这本书还提到了一些众所周知的养生法,看看也算是温故而知新吧,例如用热水泡脚(全身发热,微微出汗就算泡好,一般三十分钟左右。)据说,这可以可以消怒气,有助睡眠,提高人体免疫力,可降虚火等等好处多多。常常搓手同样好处多多,它能使手指更加灵活自如,对大脑有保健作用,还能促进血液循环,增强体质。对了,不要忘记最好的最廉价的运动--步行!

都市中忙碌打拼的你我,不要忘了健康养生,看完这本书后,马上开始行动吧,此时的我正在边“搓手”边“用热水泡脚”哈。

2009年11月30日星期一

如何将BGR转成YUV420

今天心情非常之好,花了一个下午时间搞定了困扰了我一个月的事情。写了一个程序可以把openCV的BGR图像格式转换成YUV4:2:0,然后通过FFmpeg的API把YUV4:2:0的图像编码压缩,最后利用live555把压缩后的buffer打包成RTP包,最后用Unicast将它们发送出去。简单的说就是 BGR—>YUV4:2:0—>encode to buffer—>RTP—>Unicast这样的过程。

把预想的程序完成真是一大快事,随便记录一部分比较特别的东西,因为openCV没有BGR转YUV420的函数,所以需要自己写一个,我写的这个函数读入一个三通道的图像数据,然后先使用cvCvtColor函数,将BGR转成YCrCb,这个YCrCb是4:4:4也就是全抽样,然后对Cb和Cr分量进行抽样,最后我们可以得到三个数组,分别存Y, U, V三个分量。这个转换不算复杂,就是使用了以下的概念。

YUV4:2:0

 yuv420 4:2:0并不意味着只有Y,Cb而没有Cr分量。它指得是对每行扫描线来说,只有一种色度分量以2:1的抽样率存储。相邻的扫描行存储不同的色度分量,也就是说,如果一行是4:2:0的话,下一行就是4:0:2,再下一行是4:2:0...以此类推。对每个色度分量来说,水平方向和竖直方向的抽样率都是2:1,所以可以说色度的抽样率是4:1。对非压缩的8比特量化的视频来说,每个由2x2个2行2列相邻的像素组成的宏像素需要占用6字节内存。
八个像素为:[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3][Y5 U5 V5] [Y6 U6 V6] [Y7U7 V7] [Y8 U8 V8]
存放的码流为:Y0 U0 Y1 Y2 U2 Y3 Y5 V5 Y6 Y7 V7 Y8
射出的像素点为:[Y0 U0 V5] [Y1 U0 V5] [Y2 U2 V7] [Y3 U2 V7][Y5 U0 V5] [Y6 U0 V5] [Y7U2 V7] [Y8 U2 V7](来自百度百科)我们可以对每八个像素:[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3][Y5 U5 V5] [Y6 U6 V6] [Y7U7 V7] [Y8 U8 V8]进行一次抽样,抽样: Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 给Y分量,U0 U2 给U分量,V5 V7给V分量。

现在提供另一个简单的转换函数:

void convertBGR2YUV420(IplImage *in, unsigned char* out_y, unsigned char* out_u, unsigned char* out_v)  
{  
    // first, convert the input image into YCbCr 
    IplImage *tmp = cvCreateImage(cvSize(in->width, in->height), 8, 3); 
    cvCvtColor(in, tmp, CV_RGB2YCrCb); 
    /*  
    * widthStep = channel number * width  
    * if width%4 == 0  
    * for example, width = 352, width%4 == 0, widthStep = 3 * 352 = 1056  
    */ 
    int idx_in = 0;  
    int idx_out = 0;  
    int idx_out_y = 0;  
    int idx_out_u = 0;  
    int idx_out_v = 0; 
    
    for(int j = 0; j < in->height; j+=1) { 
        idx_in = j * in->widthStep; 
    
        for(int i = 0; i < in->widthStep; i+=12) { 
        // We use the chroma sample here, and put it into the out buffer 
        // take the luminance sample 
        out_y[idx_out_y] = tmp->imageData[idx_in + i + 0]; // Y 
        idx_out_y++; 
        out_y[idx_out_y] = tmp->imageData[idx_in + i + 3]; // Y 
        idx_out_y++; 
        out_y[idx_out_y] = tmp->imageData[idx_in + i + 6]; // Y 
        idx_out_y++; 
        out_y[idx_out_y] = tmp->imageData[idx_in + i + 9]; // Y 
        idx_out_y++; 

        if((j % 2) == 0) { 
              // take the blue-difference and red-difference chroma components sample  
              out_u[idx_out_u++] = tmp->imageData[idx_in + i + 1]; // Cr U  
              out_u[idx_out_u++] = tmp->imageData[idx_in + i + 7]; // Cr U  
              out_v[idx_out_v++] = tmp->imageData[idx_in + i + 2]; // Cb V  
              out_v[idx_out_v++] = tmp->imageData[idx_in + i + 8]; // Cb V 
        }  

        }    
    }  
    cvReleaseImage(&tmp); 
}

杜塞多夫,科隆,波恩两日游

上周五,六,作导游陪国内来的同学逛了逛杜塞多夫,科隆,波恩(今年至少去了5次杜塞,每次去都是阴天下雨,这次也不例外)。还是采用“我的经典旅游路径”:去了杜塞老城,国王大道,莱茵河畔,波恩市政厅,皇宫,贝多芬故居,老城,科隆大教堂,巧克力博物馆。随手照了几张照片。

100_3397 杜塞老城的骑警。

100_3399 在杜塞老城看到的彩虹。

100_3402 波恩的圣诞市场。

100_3415 100_3427科隆的巧克力博物馆展示的巧克力生产线一角。

2009年11月24日星期二

挖概念:RTP timestamp, payload, RTP, RTSP, MPEG ES, TS, PS

阅读别人写的程序绝对是一个很好的提高编程水平的途径,同时也是一个快速获取新知的方式。但是如何从源程序的一点“新的知rtp_timestamp_braindiagram 识点”拓展到一个大的“知识面”,这是一个很有意思的问题,今天我想结合自己的小小的经验来谈谈这个问题。
我采用土法炼钢:“挖概念”法,就是从一个小的概念不停地向外延伸,直到对整个知识架构有一定程度的了解。
举一个我自己的例子,前不久我在看一个视频接收程序的源代码,看到有一行关于timestamp的计算,什么是timestamp这就是一个“新的知识点”。然后我就通过这个点挖出一些我需要的知识,几小时我慢慢地对整个知识架构有一定程度的了解,图示说明了我“挖概念”的过程,以下选载一些我找到的知识点,它们都是围绕着timestamp这个问题展开的。

[1]:


时间戳(Timestamp)-->在RTP中反映RTP数据信息包中第一个字节的采样时刻(时间)。接收端可以利用这个时间戳来去除由网络引起的信息包的抖动,并且在接收端为播放提供同步功能。
时间戳字段是RTP首部中说明数据包时间的同步信息,是数据能以正确的时间顺序恢复的关键。时间戳的值给出了分组中数据的第一个字节的采样时间(Sampling Instant),要求发送方时间戳的时钟是连续、单调增长的,即使在没有数据输入或发送数据时也是如此。在静默时,发送方不必发送数据,保持时间戳的增长,在接收端,由于接收到的数据分组的序号没有丢失,就知道没有发生数据丢失,而且只要比较前后分组的时间戳的差异,就可以确定输出的时间间隔。RTP规定一次会话的初始时间戳必须随机选择,但协议没有规定时间戳的单位,也没有规定该值的精确解释,而是由负载类型来确定时钟的颗粒,这样各种应用类型可以根据需要选择合适的输出计时精度。(来自:百度百科+Wiki)


[2]:


RTP实时传送协议Real-time Transport Protocol由两个紧密链接部分组成: RTP ― 传送具有实时属性的数据;RTP 控制协议(RTCP)。
RTCP的一个关键作用就是能让接收方同步多个RTP流,例如:当音频与视频一起传输的时候,由于编码的不同,RTP使用两个流分别进行传输,这样两个流的时间戳以不同的速率运行,接收方必须同步两个流,以保证声音与影像的一致。为能进行流同步,RTCP要求发送方给每个传送一个唯一的标识数据源的规范名(Canonical Name),尽管由一个数据源发出的不同的流具有不同的同步源标识(SSRC),但具有相同的规范名,这样接收方就知道哪些流是有关联的。而发送方报告报文所包含的信息可被接收方用于协调两个流中的时间戳值。发送方报告中含有一个以网络时间协议NTP(Network Time Protocol)格式表示的绝对时间值,接着RTCP报告中给出一个RTP时间戳值,产生该值的时钟就是产生RTP分组中的TimeStamp字段的那个时钟。由于发送方发出的所有流和发送方报告都使用同一个绝对时钟,接收方就可以比较来自同一数据源的两个流的绝对时间,从而确定如何将一个流中的时间戳值映射为另一个流中的时间戳值。RTSP实时流放协议(Real-Time Streaming Protocol)提供控制多种应用数据传送的功能,提供一种选择传送通道的方法,例如UDP, TCP, IP多目标广播通道,以及提供一种基于RTP协议的递送方法。

RTSP将工作在RTP的上层,用来控制和传送实时的内容。RTSP能够与资源保留协议一起使用,用来设置和管理保留带宽的流式会话或者广播。

(来自:百度百科+Wiki)

[3]:


读了RTP的说明(RFC 2250)后发现RTP with payload type 32 (MPEG1/2 video ES): The RTP timestamp 表示了video frame的PRESENTATION time。
RTP with payload type 33 (MPEG2 TS): The RTP timestamp 表示RTP packet的TRANSMISSION time。(来自:RFC 2250)


[4]:


MPEG一2标准的正式名称为“ISO/IEC13818信息技术——活动图象和相关声音信息的一般编码方法”,是其中的一个编码标准,主要是用于传输声音、图象数据压缩标准,它是MPEG-1的进一步发展,码流在1.5Mb/S到50Mb/s之间。

MPEG-2标准是将视、音频及其他数据基本流(ES)组合成一个或多个适宜于存储或传输的数据流的规范。MPEG-2分为压缩层和系统层:压缩层中,数字视音频数据分别经过编码器,生成连续不分段的基本码流(ES),对于视音频来说,ES就是由一系列编码后的视音频帧的存取单元(AU)组成;在系统层将视音频ES分别通过各自的打包器,加上相应的包头,打包分组为包长度可变的基本流(PES)。系统层主要用来描述视、音频数据复用和同步方式,节目复用器和传输复用器分别将视音频PES加入系统层信息组成相应的节目流(PS)和传输流(TS),多条TS流还可以再次复用成一条多节目TS(MPTS)。

1.数字化的视频、音频和辅助数据,经过压缩后形成各自的基本流(ES)。
2.视频和音频的ES流分别按一定的格式打包,构成具有某种格式的打包的基本信息流(PES:Packetized Elementary Stream),分别称为视频PES和音频PES。这一步骤在打包器内实现,PES的长度可在一定范围内变化。
3.将视频、音频的PES流以及辅助数据按不同的格式再打包,然后进行复用,即分别生成了TS流和PS流.
根据传输媒体的质量不同,MPEG-2中定义了两种复合信息流:传送流(TS:Transport Stream)和节目流(PS:Program Stream)原始的视音频数据流经编码器编码输出压缩后的基本码流 ES, 它含有解码器所必需的、用于恢复原始视音频的信息。 基本码流 ES分解打包成 PES数据包, 每个 PES包在复用的过程中被分成固定长度的传输流包( TS Packet)。TS包的长度是固定的,为188字节。
(来自:张佳,电影频道节目中心传送部,有线电视技术,MPEG-2码流的层次分析,2008,9)

-----------
“挖概念”法,有时候挺好用的,可以在短时间内对一个比较大的知识领域得到一定的理解。

2009年11月23日星期一

浅议SDP(会话描述协议)

因为最近常常使用到SDP(会话描述协议Session Description Protocol)写了一些SDP的文本,在linux里使用例如"ffplay test.sdp"来播放媒体流,今天想简单谈谈SDP,做了一个小小的总结和分析,希望对大家有帮助。

SDP是描述的是流媒体的初始化参数,IETF对其的描述可以在RFC 2327找到,SDP是一个纯文本文档,后缀为.sdp,它的基本内容包括:

# 会话信息:
* 会话名和目的;
* 会话时间;
* 会话使用的带宽;
* 会话的用户信息;
# 媒体信息:
* 媒体类型,例如:视频或音频;
* 传输协议,例如:RTP/UDP/IP;
* 媒体格式,例如:H.263视频或者MPEG视频;
* 多播地址和媒体传输端口(IP多播会话);
* IP单播会话的联系地址和媒体传输端口

举一个例子来进行分析(live555的testMPEG1or2VideoStreamer里附加的SDP文本):

----------------------------------------------------------------------------------------------

v=0

o=- 49451 3 IN IP4 127.0.0.1

s=Test MPEG Video session

i=Parameters for the session streamed by "testMPEG1or2VideoStreamer"

t=0 0

a=tool:testMPEG1or2VideoStreamer

a=type:broadcast

m=video 1234 RTP/AVP 32

c=IN IP4 239.255.42.42/127

----------------------------------------------------------------------------------------------

可以发现SDP会话描述由许多文本行组成,它的格式为“类型=值”。其中v,o,s等等代表了是类型。

第1行v代表了协议版本,例子中为0。
第2行o代表所有者/创建者和会话标识符。

第3行s代表会话名称,例子中为Test MPEG Video session,用户可以自己填写。
第4行t代表会话活动时间。

第5行和第6行a代表会话属性行,可写0个或多个。

第7行m代表代表媒体信息;video代表是视频流;1234代表UDP端口号是1234;RTP/AVP指媒体传输协议使用RTP/AVP;32代表媒体格式使用MPV并且使用90KHz的时钟。关于RTP/AVP可以在RFC 3551 RTP A/V Profile July 2003找到。以下是部分截取:

PT encoding media type clock rate
name (Hz)24 unassigned V
25 CelB V 90,000
26 JPEG V 90,000
27 unassigned V
28 nv V 90,000
29 unassigned V
30 unassigned V
31 H261 V 90,000
32 MPV V 90,000 (这就是例子中的RTP/AVP类型)
33 MP2T AV 90,000
34 H263 V 90,000
35-71 unassigned ?
72-76 reserved N/A N/A
77-95 unassigned ?
96-127 dynamic ?
dyn H263-1998 V 90,000

第8行c代表连接信息。

当然了还可以加上更多的信息描述,例如b=AS:104857,b代表了带宽信息。

2009年11月22日星期日

除了编GUI,Qt还可以做很多事

昨天和学长一起讨论一个旧的项目,他看到我的project里大量使用了Qt的库,说Qt不是做GUI的吗,在编一些非GUI的东西你用它们干嘛(看来这是很多人的既定观点,真的需要改变一下),我说Qt不仅只是可以做GUI还可以完成很多东西,并且很强大,绝对不会比你常用的库弱。整个项目使用Qt的库还可以在一定程度上统一编程风格,并提高代码质量和减少维护开销,Qt库也提供很好的线上资源,很方便查阅。我这里举三个很简单的例子,说明Qt库的一些其他特性。

信号和槽

正如CObject是大多数MFC类的根类或基类,QObject是Qt的基类。先在我们的类继承QObject,并在类声明中使用的Q_OBJECT宏,我们就可以使用QObject信号和槽的强大的机制。
QObject信号和槽即简单又好用,现在举一个简单的例子,在例子中使用QTime和QObject信号和槽,每100微妙对象间自动进行一次接口的数据交换。

/* myclass.h */
#include <QObject> 
#include <QTime> 

class MyClass : public QObject { 
    Q_OBJECT 
public: 
    MyClass(); 
    int data_in; 
    int data_out; 

private slots: 
    void dataExchangePipe(); 

private: 
    AnotherClass anotherclass; 
    QTimer *poller; 
};
 
 
/* myclass.cpp */
MyClass::MyClass() { 
    object = new AnotherClass; 
    poller = new QTimer(this); 
    connect(poller, SIGNAL(timeout()), this, SLOT(dataExchangePipe())); 
    poller->start(100); // the time to poller 
}
 
void MyClass::dataExchangePipe() { 
    data_in = object->data_out; 
    object->data_in = data_out; 
}

容器,迭代器

还在使用STL容器吗,也许Qt也是一个很好的选择,Qt提供了QVector<T>, QLinkedList<T>,QList<T>QMap<K,T> and QHash<K,T>容器。Qt提供对容器的两种风格的迭代:Java风格的迭代器和STL风格迭代器

Java风格(非常简单,Qt官网上的一个例子)

QList<QString> list; 
list << "A" << "B" << "C" << "D"; 
QListIterator<QString> i(list); 
while (i.hasNext()) 
    qDebug() << i.next();


STL风格(比较powerful,每一个sequential container class C<T>都有两个 STL-style 迭代器类型: C<T>::iterator 和 C<T>::const_iterator,以下是Qt官网上的例子)

QList<QString> list;  
list << "A" << "B" << "C" << "D";  
QList<QString>::iterator i = list.end(); 
while (i != list.begin()) { 
    --i;
    *i = (*i).toLower(); 
}

多线程

Qt的QThread很类似C++Boost线程库。使用起来也非常容易,例如:

建thread:

#include <QThread> 
class MyThread : public QThread { 
  public: void run();  
}; 

void MyThread::run() { 
... 
... 
}

使用thread,很简单:

先声明对象,MyThread *mythread = new MyThread;

启动: mythread->start();

终止: mythread->terminate();

对线程的同步,Qt也提供了QMutex;我们可以声明QMutex mutex;然后使用mutex.lock();和mutex.unlock();进行线程同步。

更多有用的特性请查阅:http://doc.trolltech.com/4.5/index.html

2009年11月16日星期一

源代码行数计算器

刚刚完成了一个项目的重构。使用源代码计算器一查,代码少了30%,系统的结构也更清晰了。总结经验,因为,抛弃了很多原型代码。改变以前自上而下的设计方法,使用了自下而上的设计方法,并把一些绝对要做的模块做了,然后再把它们搭起来。 还加入了一些Facade降低了一些模块间的耦合。重写了一些utility classes(工具类),然后就可以让大量的类使用某个给定的类,达到了《代码大全》所谓的high fan-in(高扇入)。《代码大全》中提到了应该让每个类都应该少或适中使用其他的类(不要超过7个)这就是所谓的低扇出,low fan-out,在我重构的时候也努力的遵守这个原则,这大大减低了类的复杂度。

呵,做这个项目走了不少弯路,看来还是要多读书,并结合一些编程经验带着问题读,多思考。这样会提高编程的质量,并提高效率。

line counter

想计算所编软件源代码共有几行,网上搜到了n种计算器,随便找了一种,使用了line counter,还不错,该软件下载地址:http://sourceforge.net/projects/lcounter/

2009年11月5日星期四

电影:圣诞颂歌-Eine Weihnachtsgeschichte

3D 版的“人物动作捕捉”技术的动画片圣诞颂歌(A Christmas Carol,德语:Eine Weihnachtsgeschichte)在德国上映的第一天就跑到电影院尝鲜,第一次看“人物动作捕捉”动画片的3D版,个人感受相当不错,某些场景还挺震撼的。

disney-s-eine-weihnachtsgeschichte-2008-imagemovers 值得一提的是金·凯瑞(Jim Carrey)一人分饰多角,在影片中饰演守财奴艾柏纳泽·斯克鲁奇(Ebenezer Scrooge)从儿童到老年的四个时期的角色,还有圣诞三精灵。

如果想回忆一下的查尔斯·狄更斯的原著内容:在http://publicliterature.org/可以找到A Christmas Carol的有声书和原著的pdf。http://publicliterature.org/books/christmas_carol/xaa.php

enjoy!

2009年10月30日星期五

读书:风云《游戏之旅-我的编程感悟》

对于一本技术图书的好坏我有两个最简单的评断标准,一是是否能吸引人,这本书就像一个好游戏一样让人沈浸其中,不能自拔,上个一个周末分“两口气”把它仔细读完了。第二个标准就是我是否做很多笔记,在读这本书的过程中我在我的Google docs做了非常多的笔记。以我的标准来说这本书绝对是五星级的好书。虽然我不是游戏程序员,但是我也得到了非常多的收获,我不仅从风云的亲切自然的文笔中了解他的一些成长经历,而且还“似乎”进入了一个陌生但是令人兴奋的游戏设计领域。通过阅读这本书还有一个收获,就是进行了一些关于游戏开发的方法,游戏引擎,游戏引擎中的优化等等知识的“扫盲”。
s2198972 “第二章算法,程序的灵魂”是我最喜欢的章节。如何进行算法层面的优化,本书也谈到了几点,看完深有体会,以下是部分书摘。

1 数学方法的改进

2 预运算来节省时间(空间换时间来避免重复运算)或是重复运算来节省时间。

3. 简化算法求得近似解来取代精确解(或最优解)

4. 改进数据组织方式,用更少的操作处理更多的数据,甚至避免冗余数据的处理

我也非常喜欢“第九章C和C++”和“第十章 调试”,强烈推荐仔细阅读。我们使用C和C++,但是有没有在不同的层面去*思考*一下它们而不是仅仅使用它们,书中关于C和C++的一些精彩诠释也令我得到很多启发,以下是部分书摘:

“C++和C一样,都是最贴近计算机固有模型的,C++的每一行代码,都和C一样有明确的目的,没有去干多余的事情。”

“C语言是对汇编语言的一种抽象,正如汇编语言是对机器底层指令的一个最小幅度的抽象一样,是为了人类能更方便地控制机器。但是,人在使用C语言控制机器时,并没有比汇编语言有观念上的不同,也就是说,程序员依旧是按机器模型来思考问题。在面对问题时,问题的描述往往并不符合机器思考的模型,程序员的工作也就是在两者之间搭上一座桥梁,让问题的描述可以用机器的思维来解决。”

“C++则采用了另一套方法来减轻程序员解决问题的复杂度,那就是面向对象。它是一种通用的方法,面对问题,我们把问题中的事物都表示为对象,对象有自己的行为,对自己遇到的问题提出符合机器模型的解决方案,或把自己划分为更小的对象集合。这样,程序员就可以在对象的级别用对象本身的术语描述问题,而这些术语最终都会被直接对应到机器模型上。”

八卦一下,书中有一些关于一些编程语言的有趣观点:

“JAVA更像一个实验室研究出来,有着浓厚的学术气味,外观优美超过它本来应该具有的人们所期望的实用性。”

“而C#则是工程师的结晶,外加了许多商业味道,被微软强烈地推广。”

“脚本语言如Python会像C++这样的主体开发语言的一种有益的补充。”

风云来自实践的这本书,是我读过最有趣生动,亲切的本土技术图书,同时也是一本极好的教材。

在这本书中,我最有感触并最喜欢的一句话是“多年的编程经历让我明白了一个道理:绝大多数情况下,没有解决不了的问题,只有因为平时缺少练习而惧怕问题的复杂度,畏惧的心理让我们选择避让,采取并不那么好的方案去解决问题。”一句很平实的大实话。真正的“高手”之路,无论什么领域,其实就是多思考,多动手,知难而进吧。

2009年10月25日星期日

读书:梁肇新《编程高手箴言》

s2301239上个星期读了超级解霸的作者梁肇新的这本书。这本书行文亲切自然,国人写的书显然比国外的图书的中文版更具有“亲和性”。当然了,也许也会有很多人对文中的一些观点有不同的意见,但是不同的人一定会得到不同的启发,绝对值得一读。带着自己的思考和结合自身编程的实践经验去阅读这本书也许可以得到更多的收获。这里谈谈我从中得到的一点启发。
曾经参与一个项目开发经过多次失败,最后才发现对于实际应用软件项目,最适合的方法就是类似“实现核心-->增强功能-->测试”这样一个过程。强烈赞同书中的观点:
“我们不可能一开始就把所有的细节都考虑清楚,通常,开始只需要一个基本的框架,也就是核心的核心。如果这个核心都实现不了,即使再进行下去,整个项目也都是多余的,只是浪费时间而已。所以,一开始就要解决最核心的问题。当最核心的问题解决之后,就可以进行第二阶段。我们把软件开发分为设计规划阶段,功能设计阶段,测试阶段。所有的产品都可以划分为这三个阶段。事实上,如果最核心部分实现了,那么依赖于此核心,再实现增强一点功能就是第二阶段。第二阶段完成后,就可以进行第三阶段。”
还有例如书中谈到的关于界面和接口的“箴言”:
“界面是界面部分,接口是独立的一块。接口部分就是程序的实现内核,通常先用Console方法直接地实现程序,这样更便于分离界面和内核。如果开始就用Windows的界面去实现内核部分,这样就可能会把界面和内核混在一起,无法分开。所以,一开始做程序时,就不要考虑界面是什么样子。”
“接口的目的就是把外部条件和内部条件分离开来。外部条件由别的程序提供,别人可以用。做接口最好的方法,就是直接用Console程序先实现程序的主体,然后从中提炼出接口来。这样做提炼会简单明了。如果用可视界面先实现了程序的功能后再去提炼,就会比较困难,因为这样就会把界面和功能实现混在一起,很难区分。”
看完后深有体会,我在做一些应用软件项目时总是把界面和功能实现混在一起,的确会造成维护,修改,甚至是阅读的很大困难,程序结构也会不够简单明了。
我总是太过局限于“软件工程的思维框架”中,常常在抽象化的时候,总是想要把所有的事情都想全了,常常做一个巨大无比的对象,这本书对此也提出一些让人有所反思的观点,例如:
“做对象化时还有一条准则,既对不同的应用去设计程序,而不是针对一种所谓的虚拟模型去设计一个对象。所谓的抽象化,就是想着将来有可能会用的某个功能。这样设计出的软件又庞大又耗时,运行也很慢。这就是杀鸡取卵(教科书会教你这种方法)。”
“杀鸡取卵就是指设计的软件提供了很多的功能,其实用到的功能只是那么一丁点。可能做了一个巨大无比的对象,但是只用到对象的很小的一些功能而已。因为做抽象化的时候,要把所有的事情都想全了,但是这是不现实的,实际上也是没有必要的,且是浪费的。如果凡是思考问题都是为了将来的大而全,这样出错的可能性也会成倍的提高。一般来说,代码越大,出错的地方也就越大,如果代码越小,出错的地方也就越小。将功能模块做成API函数与做出对象就不一样,做成一个对象时,该模块出错的机会就多一些,因为对象还有一个动态的过程,但做成一个函数时,调用函数就可以了,模块出错的机会就会比较小。所以,程序越简单,越不容易出错。”
书中的“程序主干和分支”的概念,也令人很有启发:
“核心就是整个系统中最重要,最基础,最简单的部分。首先要把程序的核心提炼出来,在给它添加附加的部分,它就能成为一个完整的软件。主干是最核心的核心,其后在添加的其他的部分就是枝叶了。”
“编程就是要保证核心的核心不出错,那剩下的枝叶都是一层一层地构建出来的。”
读《编程高手箴言》,也是自己编程思想,习惯等等的一个“自审”的过程。你一定可以找到适合自己需要的“箴言”,用它去提高自己吧。

2009年10月24日星期六

读书: 成寒《躺着学英语:听力从零到满分》

最近因工作时发现自己的英语口语水平还是停留在n年前水平,阔别多年后又开始自学英语了,偶得这本英语励志书,n年就前看过一些英语励志书,其实内容光看这本书的书名和简介,就可以猜到十之八九。但是,正如书中所说的“如果一个人没有纪律,没有办法自动自发学习,一定要人用鞭子打才肯用功的话,再多的英语励志书,也不过是一帖安慰剂罢了。”

s2212962 “学英语,用什么方法都可以。只要这个方法能够挑起学习的乐趣,就一定会有成果。”作者推荐大家用一种轻松快乐的心态去学英文,这本书的行文也很清新流畅,不像一般的英语励志书教导式的文笔,而是让你感觉到作者就在身边和你聊聊她的经验,在短短的几小时就可以很轻松的一口气读完。

我非常认可书中的一些观点例如“自修英语,最大的好处是可以随心所欲。尽量找好听的,自己感兴趣的教材”。至于如何选择适合自己的教材这本书谈到“每页的生词不超过十个,也不低于五个,便是合乎自己程度的教程”。

顺带一提,通过阅读这本书我还纠正了一个长期以来的错误认知,原来晶圆厂例如FAB1是Fabrication(精密制造)的缩写,而不是Factory,象征着晶圆厂与传统工厂的层次有别。

2009年10月5日星期一

电子工程师乱弹编程-跳出迷思

和我一样电子专业毕业的学生,若投身到软件编程时,常常会有一些“迷思”,也许你和我一样也问过自己这些问题:
# 我是否一定需要使用模式
# 我是否应该使用“尝试错误法”
# 我应该为我的低生产力而担忧吗

# 我是否一定需要使用模式
什么是模式?《Head First 设计模式》里是这样定义的:“是在某情景(context)下,针对某问题的某种解决方案。”我认为:我们在设计软件时需要使用模式,但是应该先使用最简单的方式解决问题,在经验和知识增长后,我们在编程时就会知道在何时何处应该使用何种模式,然而这需要一定的时间积累。谈谈我的经验,我刚开始编程时,接触到一些比较大的项目,读了以前开发人员写的代码,里面包含了很多模式,除了一头雾水更多的还是担忧,我总是认为“如果没有使用模式在我的代码中,就说明我是个菜鸟程序员。”开始时我努力地看了很多关于模式的书,并在我的代码中加入了外观模式,工厂方法模式,命令模式......尽可能地使用模式,一段时间后,师兄看了我的代码后对我说“你不是在使用模式,而是用模式去装饰你的代码”。在得到得到师兄的一些指教,并随着自己编程经验的提高,才真正体会到了《C++编程规范》一书的一段话“我们设计的软件正确,简单和清晰第一,软件简单为美(Keep It Simple Software,KISS)正确优于速度。简单优于复杂。清晰优于技巧。安全优于不安全。”的真正内涵。我们使用模式只是为了让我们设计简单并且有弹性。正如《Head First 设计模式》所言“如果你能保持简单的设计,那么你将会得到其他开发人员的欣赏和尊敬。”

# 我是否应该使用“尝试错误法”
我认为:应该尽可能地减少使用“尝试错误法”。Trial and error-尝试错误法是一种用来解决问题、获取知识。因为我们这些外行人对一些编程的基础知识的缺陷和经验的不足,所以我们常常喜欢使用Trial and error来解决问题。尝试错误法常常就是靠巧合编程,使用着最低限度的知识去解决问题,这里产生的代码绝对是比较低质量的,不是最佳的。通过“尝试错误法”解决问题,其实只能带来一时之快,然而之后也许会带来“无限的痛苦”(我们很有可能要为这个低质量的解决方案付出大量的额外时间),因为没有深思熟虑,没有了解问题的实质,并掌握解决问题的根本知识。我很喜欢《程序员修炼之道》里的一句话 “Don't Program by Coincidence. 不要靠巧合编程。深思熟虑地编程。”我们应该常常问自己,是否有深思熟虑地编程。

# 我应该为我的低生产力而担忧吗
我认为:不应该担心。“程序员之间生产力比差10:1”,这句话在很多书提到了,很多大牛也是这样说。我刚开始编程的时候,和我的生产力和我的师兄不止差10倍,我认为甚至是20倍以上。因为同在一个项目组,当时每天我都很担心,也很痛苦。虽然现在我和我的师兄还是差距很大,但是我一点也不担心“低生产力”的问题,这不是一个问题,而是一个事实,只需要直面它,并通过不断的自我提升来减少差距。提高生产力,以下我粗浅地谈一下我认为比较重要的几点,自学,提高自己的工作效率和多实践多思考。

自学,常常积累知识
网络真是自学的天堂,而且我认为程序员行业是几乎就是最适合自学的行业。好记性不如烂笔头,自学时也许需要通过记事本或google doc记录一下,常常回顾一下,可能在一定的经验积累后看看以前的记录会对一些知识会有了更高一层的理解,以前的一些似懂非懂的部分也会豁然开朗。用纯文本保存知识绝对会是一个很重要的经验。

提高自己的工作效率,也许可以考虑一下两点:
# 提高自己的E-因子(E-因子=不被打扰的时间/体力出勤的时间)。
# 延长自己的flow的状态的时间(在一心一意动脑筋工作的时候,人们在意识上处于一种心理学家称为顺流flow的状态,顺流是一种陷入沉思的状态。)

多实践,多思考
提高编程水平决对是一个“蹲马步”的过程,我们要做的其实也很简单,就是专心致志的实践,多编程。多试着思考解决问题的方法也是提升自己的一个很重要方法,请常常反思。我认为,随着经验的积累和思考水平的提升,我们必然会从“低手”成为“中手”,最后一定能成为具有超高生产力的“高手”。

2009年10月3日星期六

在MinGW中安装并使用GCC4.4.0

一直懒得升级MinGW的GCC,因为嫌麻烦,这真是一个很不好的习惯,其实我们应该要常常提醒自己是否“是否在使用最好最新的工具?”,一直到前几天在我的一个小程序使用FFmpeg的avcodec_encode_video()函数发生崩溃(Crash)后才决定升级GCC。avcodec_encode_video()函数发生崩溃是因为堆栈定向问题(stack alignment issue),有兴趣的可以看这个网页里的讨论:
http://ffmpeg.arrozcru.org/forum/viewtopic.php?f=1&t=549如果使用gcc >= 4.2版本就可以解决问题。

MinGW在2009年6月份已经释出了GCC 4.4.0请到以下的站点:http://sourceforge.net/projects/mingw/files/下载如下的文件(假设你只是要使用gcc,c++编译器,如果要使用java,objc,请下载其他相关的文档)
gcc-ada-4.4.0-mingw32-dll
gcc-core-4.4.0-mingw32-bin
gcc-core-4.4.0-mingw32-dll
gcc-c++-4.4.0-mingw32-bin
gcc-c++-4.4.0-mingw32-dll
gmp-4.2.4-mingw32-dll
mpfr-2.4.1-mingw32-dll
下完后,请直接解压到MinGW的目录中去,例如C:\MinGW里。

然后重新安装msys,很简单以前的文章就提过了,不要忘了下载coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2并且解压到msys的目录中去,因为在默认状态下msys并没有完全安装coreutils的所有组件。为什么要安装完整的coreutils组件呢,这是因为有些make文件里的指令需要coreutils的一些组件才能正确识别。coreutils的最新版可以http://ftp.gnu.org/pub/gnu/coreutils/里找到。

现在有了MinGW5.16+GCC4.4.0+msys,我对我常用的几个库进行了重新编译(理论上不需要对所有所使用的库重新编译,因为高版本的GCC应该向下兼容低版本的GCC所编译的库):

Qt4.5.1已经用了挺长的一段时间,9月30日我下载了了Qt4.5.2然后编译了它,没想到10月1日Qt释出了4.5.3。哈,不想再编译一遍了,因为即使使用配置了Core i7的机器,编译Qt也需要很长的时间。编译的方法如下:先将C:\MinGW\bin和C:\Qt\4.5.2\bin加入环境变量的path里。然后进入Qt by Nokia v4.5.2 --> Qt 4.5.2 Command Prompt并输入configure(当然了,可以进行configure调整,具体请输入configure --help看说明),最后输入mingw32-make,就开始编译了。

LIVE555也于28-Sep-2009已经释出了新版本,可到以下站点下载。http://live555.com/liveMedia/public/然后重新编译,很简单,解压下载完的原文档,然后通过msys进入它的目录,先输入./genMakefiles mingw然后输入make,就搞定了。如果遇到问题可能要对config.mingw进行一些微调,例如将第三行C_COMPILER =           $(CC)的改成C_COMPILER =           $ gcc

对FFmpeg编译可以按照以前介绍过的方法,但是编译好我的项目并正确连接编译好的ffmpeg动态库后,运行我的程序会出现这样的错误:"The application failed to initialize properly - 0xc0000005" 很无奈,我的解决方法比较愚蠢,重新编译FFmpeg生成静态链接库(.a),然后在项目设定中使用静态链接库代替动态库(.dll),结果程序可以正常运行,只是我的主程序增肥了不少,这是暂时的解决方法。

还编译了一些库,使用gcc4.4.0编译和使用几乎没有问题,这里就不多谈了。在网上找了一下我使用过的一些库,很多开源库都陆续释出新的版本,我使用的版本真的很旧了,使用开源库要常常注意它们的更新,还是那句话要常常“提醒自己是否在使用的最新最好的库”,很多库的新版本已经解决了一些我以前遇到的问题,我下载了一些库的二进制版(bin),然后可以直接使用它里面的dll就可以了,连编译都不用了。

2009年9月28日星期一

读书:《长尾理论》

上一篇书评提到了“长尾理论”,今天想聊聊这本书。 这部书提供我们一些新的视角来理解我们所处的世代。分析长尾的奥妙的章节写得很妙。以下是长尾的奥妙:
s1935122 1. 生产力普及: 工具制造者,生产者 - 数字摄像机,博客工具
2. 传播普及:集合器    - 亚马逊,ebay
3. 供需相连:过滤器    - Google,博客,畅销榜
为什么Google这么强大,本书对这个问题也通过长尾理论的角度进行了回答:“搜索引擎之所以成为硅谷的一大经济力量,这是因为我们认识到来衡量和分析大众行为的价值。在一个无限选择的时代,统治一切的不是内容,而是寻找内容的方式。”
这本书最让我感兴趣的是其中关于亚马逊和Salesforce.com的分析。它们的例子可以让人感到一些的“思维颠覆”,看来这些例子的同时似乎也呼吸到了新经济模式中的精妙,颠覆的味道,其中“亚马逊即需及印的概念。在理想化的情况下,一本书在出售以前一直只是数字文件而已。”而Salesforce.com,“第三方开发商们可以编写某个指定的小应用程序,这个程序 会在Salesforce的服务器上运行,于Salesforce的其他软件合为一体。Salesforce希望成百上千的小开发商能够满足顾客们的各种特殊的需求,这样的话,Salesforce就可以把精力集中在更常见的需求上。”Salesforce.com的模式,也许是未来软件行业发展的一个重要的方向,它结合了云计算技术,体现了“软件即服务 saas”的思想,同时也抓住了长尾理论的精髓,这个案例也许很值得计算机行业的从业人员分析和学习。
这里摘录一些我最喜欢的观点:
“集合器可以瞄准特定的细分市场。”
“纯数字模式下,每一种产品都只是数据库中的一个条目而已,实际上没有任何存储存储成本。传输成本只是带宽字节,这种东西可以大批量购买,价格也正在迅速降低,而仅在产品被订购的情况下才需使用。”
”当我们的文化碎裂成千千万万的小文化碎片,小名人们也随之崛起了。“
“大城市之所以存在,是因为秘籍聚居的文化和经济优势完全可以弥补城市的成本。颇有讽刺意味的是,其中一个优势是无奇不有的细分市场。”
“对零售商店来说,可获得性和便捷性就等于更高的销量。消费者在选择更多的情况下更容易消费。”
”不存在大众,只存在把人们看作大众的方法。现在是百花齐放的小众文化时代。“
“博客可以专注于某些特殊的主题,这样的专业化程度,媒体企业的记者们没几个能做到。”
本书还谈到一个可以自我出书的网站:http://www.lulu.com/index.php, 哈,很有趣吧。
在一个无聊的午后或晚上,阅读《长尾理论》,了解一些关于“这个一个无限选择的时代,百花齐放的小众文化时代,网络时代……”的商业道理的同时,你一定还会感受一些新思维的冲击,这就是本书的过人之处。

2009年9月26日星期六

读书:《C++编程规范:101条规则、准则与最佳实践》

我很喜欢看书,也看了不少书,各种各样五花八门。在“一个无限选择的时代”,就像《长尾理论》说的我们的一些评论可以起到“过滤器”的作用,提供他人一些参考。我很乐意写一些书评关于某些我感兴趣的书,并将它们放在这里和豆瓣上,希望能对“同好”在选择书的时候有所帮助。

今天谈的书为《C++编程规范:101条规则、准则与最佳实践》,这本书相当适合和象我一样有一定C++编程经验的初级,中级程序员阅读。这本书讨论了101个规则,每个规则都按照,固定的格式(包括条款标题,摘要,讨论,示例等部分)进行说明。这样的编排方式即清晰又符合我们理解接受的渐进过程。C  编程规范
也许可以边看书边试着做一些回忆,想想自己是否在编程时候使用或注意到这些规范。还可以问自己一些问题,例如在我们的设计风格中是否注意了,”对一个函数之赋予一种职责“,”正确,简单和清晰第一,软件简单为美(Keep It Simple Software, KISS)“,”优先使用线性算法或者尽可能快的算法:例如O(N)“,”尽量减少全局和共享数据(会增加耦合度,从而降低可维护性,通常还会降低性能)“等等。
我们也可以考虑一下我们的编程风格,并问自己: 我们有没有做到避免使用宏, 尽可能局部声明变量, 总是初始化变量,避免函数过长,避免嵌套过深,是否做到确保所编写的每个头文件都能够独自进行编译。
C++之父Bjarne Stroustrup说过“软件开发最重要的一个方面就是弄清楚自己要构建的是什么”,对于类的设计与继承这一部分也相当值得一读,例如以下条款“用小类代替巨类”,“ 用组合代替继承”,“避免从并非要设计成基类的类中继承”,“优先提供抽象接口”,“共用继承即可替换性。继承,不是为了重用,而是为了被重用,Liskov替换原则: Liskov Substitution Principle,共用继承所建模的必须总是“是一个is a”,更精确的“其行为象一个 works like a ”关系:所有基类约定必须满足这一点。”等等,也许我们对这些规则都了然于胸,但是我们是否时时刻刻注意到这些规则呢,这本书就提供了这样一个“小声音”,提醒我们,在经过一段时间的编程后,我们也许常常会被一些“坏习惯”占据,这个“小声音”,也许就是摒除这些“坏习惯”的利器,
也许你和我一样在编写C++的时候会不自觉地使用了一些不先进的C的方式,例如使用数组,匈牙利标法,switch等等,看了这本书后绝对会大有启发,例如以下的部分书摘:
”匈牙利记法:将类型信息并入变量名的记法,是混用了类型不安全语言(特别是C)中的设施,这在面向对象语言中是可以存在的,但是有害无益,在泛型编程则更不不行。所以,任何C++编程规范都不应该要求使用匈牙利记法,而在规范中选择禁用该记法则是合理的。“
”通过类型分支(type switching)来定制行为既不牢固,容易出错,又不安全,而且是企图用C++编写C代码的明显标志。这是一种很不灵活的技术,要添加新特性时必须回过头对现有代码进行修改。它还不安全,因为添加新类型时,如果忘记修改所有分支,编译器也不会告知。“
“不要使用C语言风格的数组,指针运算和内存管理原语操作实现数组抽象。使用vector或者string不仅更轻松,而且还有助于编写更安全,伸缩性更好的软件。毋庸置疑,在当今软件中缓冲区溢出和安全缺陷是罪魁祸首。固定长度的数组所带来的愚蠢限制,即使仍在正确界限内,也是软件开发人员的一大困扰。”
”不要使用C风格的强制转换。“
初级,中级程序员看了本书后一定会大有收获,掌握这些规范,也许是成长为优秀程序员的重要的坚实一步。

2009年9月20日星期日

电子工程师乱弹编程-使用开源代码技巧

还记得我们学语言的时候,就是从模仿开始的。对我们这些外行人,第一件事不是试着”说话“,而是应该学习如何做到“牙牙学语”。今天我想乱弹的问题是如何阅读别人写的代码,并使用它。通过读别人的代码来学习技术即实际也很有效率。现在很容易就可以搜索到很多优质的开源代码,读懂别人的代码然后加以修改加入我们的项目,外行人或技术落后者也可以做出和专业人士一样高质量的软件。这里我想到一件事,中国最早的第二代坦克80式有:德国730匹柴油发动机+英国的双向稳定火炮控制系统+奥地利的105毫米线膛炮。通过引进吸收十几年过去了,中国的99式,第三代主战坦克,已经是世界上最先进的主战坦克之一,所有的配件完全国产,并掌握所有相关技术。以下我想结合这个坦克制造这个例子谈谈阅读使用开源代码的技巧。

技巧:

整合资源阶段:若想在我们的坦克中加入德国730匹柴油发动机,那么首先应了解这个发动机的性能参数,搞定一切我们所需要的资源,使用开源代码也是一样。


# 下载源码文档。
# 找到源码文档的网页(例如通过文档生成器的doxygen写的文档),我们可以轻松地通过这个网页阅读程序,这种方式的阅读效率也是很高的。
# 找到自己感兴趣的部分,通过这个部分可以"解决我们需要的一个特定的问题"。
# 了解命名规则(或惯例)。
# 试着在网上找一下“专业人士”对该代码的分析,这样会对我们理解整个系统代码概括达到事半功倍的效果。例如,我们想要使用FFmpeg的源码,我可以找到很多关于源码分析的文章,我们可以很轻松的理解FFmpeg的数据结构,理解它们的关系,例如“AVFormatContext派生出AVStream派生出AVCCodecContext派生出AVCodec”。通过网上的文件我们可以快速地理解FFmpeg的初始化函数和编码函数的使用方式,有些数据结构和函数比较生涩难懂,但是如果有了这些文章的帮助,我们可以迅速上手。
# 保存归纳搜索到的资源。
# 背景知识的准备,也许有时需要一些背景知识,还是FFmpeg这个例子,例如有些概念需要理解mux, demux, encode, decode, codec, yuv, 容器格式,视频格式等等。这对于真正理解源代码也很重要。如果只是停留在代码的层级上理解,其实并不是真正读懂了这个代码。也许这是我们学电子学生的优势,也许我们的抽象力不如学计算机学生,但我们可能会更容易地从现实层面知识背景层面理解代码的内涵。如果我们彻底了掌握了我们的坦克中要加入德国730匹柴油发动机的技术,那么离我们自主创新也不远了。

修改拆解,编译,调试阶段:如何将英国的双向稳定火炮控制系统放入我们坦克系统中,让它发挥出效能,是这部分我们要谈谈的内容。


# 拆解代码,然后将拆解的代码加入我们的项目中。
# 编译调试代码,在编译的过程中一定会有很多问题,一定要有耐心,细致。(也许有时先注释掉一些代码,然后再编译也是一个方法。),也许有时编译不通过 是因为没有完整加入所需要的全部元素。
# 编译成功后,试着让它能正确运行。
# 反复调试,如果可以,这时加入单元测试。

优化,提炼,系统整合阶段:继续开篇的例子,坦克系统相当复杂,如何优化,提炼,系统整合这些新加入的配件,绝对是成败的关键。


# 统一编程风格。我们整合的原代码的编码风格肯定和我们自己的风格不一样,先统一风格。
# 改善代码的结构。
# 优化代码,整合系统,考虑系统效能
# 除去一些不必要的代码,提高系统效能。

总结:整合资源,修改拆解,编译,调试,优化,提炼,系统整合并试着锻练自己的阅读技巧。

预告:下一篇文章我想结合我的一些经验和教训,谈谈电子工程师编程时的“坏习惯”和(群体成员背景和价值观的相似性产生的)“团体迷思”,文章选题比较泛将分篇释出。

2009年9月18日星期五

电子工程师乱弹编程-谈谈工具

使用源码控制软件,在软件开发中非常重要,使用SVN吧,我以前谈过,比CVS强大很多。

编程的时候请给自己找一个安静的工作环境,现在笔记本非常普及大可以很轻松地找到一个安静舒适的环境,在桌上准备一根笔和一张纸,很多抽象并不是简单的通过纯思考就可以构建出来,在具体解决问题的时候,有时你也可以在纸上画一个脑图,以理清思路。

使用最好,最适合自己的工具,很多工具非常好但是并不是最适合自己的,IDE和编辑器几乎是你手的延伸。

IDE没什么好说了,具体使用Eclipse或Visual Studio因情况条件而异,但是熟悉这个IDE的所有特性是非常重要的。这里想谈谈编辑器,精通一种编辑器就如同你装了一个机器手一样顿时生产力有了质的飞跃,你甚至不需要用鼠标,必须的操作甚至只是一种条件反射。编辑器的选择因人而异,例如编辑器Emacs很强大,很多高级的特性对于我们这种外行人来说并不是很适合,因此我选择轻量级的notepad++,但是它基本的拓展性,可配置性一点也不差,使用notepad++的最简单技巧我在以前的文章也提过了。

说到工具,不得不提到计算机硬件,我以前的一台古董笔记本陪我很多年,但是因为有了远程登入的这个功能,古董的笔记本也可以有第二春,远程登入一台性能强大的台式机,你可以获得强大的计算力,笔记本这时候就是一个客户端只需要能上网即可,我和我的导师共同远程使用一台配置了Ci7 CPU的计算机,这台高性能的计算机就如同云端,提供类云计算的服务,强大的硬件也可以在另一方面提高工作效率,我刚刚装了一台新的台式机,但是我还是远程登入学校的计算机来编程,我完全不需要在本地安装编程或工作需要的各种软件,这样不仅节约了配置软件的时间,同时云端上的计算机的数据的安全性也远高于本地数据。

总结:源码控制软件, IDE, 编辑器,安静的环境,较好的计算机硬件。

电子工程师乱弹编程系列-开篇

作为一个电子系的学生,我以前和很多同学一样对编程有些排斥,总是认为编程这种事是程序员干的,作为电子工程师应该是“做电子工程师该做的事“,其实在内心对编程有些害怕,所以才会产生抗拒感。去年,我被导师“推入”一个比较大的软件项目的开发,因为这是我们电子系的一个项目,这个项目既有软件也有硬件开发部分,因为一时找不到学计算机的学生来做软件,只好死马当活马医,学电子的上。一开始和大家一样很排斥编程,痛苦不已,而且还是使用我几乎毫无基础的C++。还好有7*24小时的解答,终年无休Google老师,和它无数次的”交流”后,一段时间静下心一步步的痛苦编程后,现在项目快做完了,但是我早已经喜欢上编程,其实编程非常有趣,和很多人说的一样它是一种工艺,或艺术。看了一些大牛写的书,计算机的书真是相当的多,看完后真是获益匪浅,很多书谈的不仅仅是编程,更深层的是告诉我们一些思考问题的方法,看世界的观点,我们电子的教材相较之下逊色很多,还有一点很有感触,很多计算机的大牛不仅在他的领域很强,他们的文笔非常漂亮,行文相当生动,譬如Joel Spolsky的书。学电子的会软件编程,可以让我们对于事物的抽象能力得到很大的锻炼,逻辑思维能力也会得到一定的拓展,可谓是相当有益,并且以后再很多工作场合可以“软硬兼施”,大展身手呢。

很早就想写这个系列文章,我不写什么教程(想写也写不出,呵呵),而是每篇文章聊一个小问题,这些问题的探讨将基于我有限的经验,如果文章中有错误,请读者大方指出,我将要讨论的问题天马行空,并不仅仅局限于编程,并且对这些问题的讨论一般不会很深入,文章也会比较短,希望对和我一样的学电子出身的你有所帮助。当然了,这不仅写给学电子学生,本系列文章的目标读者为和我一样“半路出家”对编程没什么基础的同学。

2009年9月17日星期四

ffmpeg的使用,及发送媒体流的一些简单介绍

在以前的文章谈过对ffmpeg的编译。这里谈谈ffmpeg的最简单的使用。

ffmpeg使用语法:

ffmpeg [[options][`-i' input_file]]... {[options] output_file}...

最简单的使用:ffmpeg –i test_mp4.mp4 test_mpg.mpg (将输入的mp4容器格式的文件转换成mpg格式文件)

我在做一些机器人控制实验时常常会得到很多的jpg格式的文件,将这些文件改成连续的名称,例如test_jpg00001, test_jpg00002等等,然后可以通过ffmpeg生成一个视频文件,这会很方便演示,例如:
  ffmpeg -r 15 -b 1800 -i test_jpg00%03d.jpg test_mp4.mp4 (这里,-r 代表fps 设置帧频;–b 代表bitrate 设置比特率; test_jpg00%03d.jpg中%03d代表最后三位数字)

做实验时,直接通过摄像头可以得到raw picture(也就是YUV或RGB文件),这时也可以通过ffmpeg将它们转换成mpg或任意容器格式。例如:ffmpeg -s 320*240 -i test_yuv.yuv test_mpg.mpg (这里请注意在写入输入文件之前,必须给ffmpeg传入帧大小,也就是通过 –s 来设置帧大小)。当然了,你也可以将例如mpg格式的文件转换成YUV文件,即,ffmpeg -i test_mpg.mpg test_yuv.yuv。
 

除了转换格式ffmpeg还可以做更多的事,例如发送媒体流,通过rtp协议,可以输入以下的命令:

ffmpeg -fflags +genpts -re -i test.mpg -vcodec copy -an -f rtp rtp://127.0.0.1:10000 -vn -acodec copy -f rtp rtp://127.0.0.1:20000 -newaudio

其中,-re 代表本地帧频读数据;-an 代表不使能音频纪录;127.0.0.1也就是本地回环地址,我们常常使用它来测试本机的网络配置,通过PING127.0.0.1来检测本机的网卡和IP协议;当然我们还可以使用它来代替SERVER的IP地址,这样程序就可以在同一台机器上运行,所有的SERVER的资源就可以装在本机,我们程序就可以运行。

使用ffmpeg发送了媒体流后,我们可以在写字板里写一个SDP文件(附注:文件的后缀也是.sdp),例如:

v=0
  o=- 0 0 IN IPV4 127.0.0.1
  t=0 0
  s=No Name 
  a=tool:libavformat 52.23.1
  m=video 10000 RTP/AVP 32
  c=IN IP4 127.0.0.1
  b=AS:104857
  m=audio 20000 RTP/AVP 14
  c=IN IP4 127.0.0.1
  b=AS:64

然后通过vlc就打开这个sdp文件,就可以播放我们发送的媒体流了。

#####    #####

谈到了媒体流的发送,我想继续延伸聊聊:我们也可以使用以前介绍过的LIVE555.COM提供的LIVE555 Media Server,来发送媒体流,很简单:可以直接下载live555MediaServer.exe,然后输入: “live555MediaServer 你的文件”,例如live555MediaServer D:\test.mpg。媒体流就发送了。然后可以使用vlc来播放,vlc rtsp://本机IP/文件名(附注:在Window里通过ipconfig可以看本机IP), 例如 vlc rtsp://131.***.**.101/D:\test.mpg。

结语:播放媒体流使用vlc或一些其他的工具就在GUI里可以简单的执行了,这篇文章最后一部分是希望给读者提供一些思路,例如使用ffmpeg,LIVE555发送,并使用不同的发送方式和接受方式。

2009年9月2日星期三

最常用的Notepad++的快捷键

如果Notepad++是程序员的一个生产工具,那么快捷键的使用就可以提高生产效率,记住一些快捷键是挺有用的:-)。

http://notepad-plus.sourceforge.net/uk/shortcuts.php这上面有完整的快捷键表格,但是很多都记不住,因为很少用。除了Ctrl-C,Ctrl-X,Ctrl-V,Ctrl-Y,Ctrl-A,Ctrl-F,Ctrl-S,Ctrl-O,Ctrl-N,Ctrl-W,Ctrl-Tab,Ctrl-P,Alt-F4这些基本的,也许有些简单的比较有用的快捷键,你可能有兴趣知道。

Ctrl-H 打开Find / Replace 对话框
Ctrl-D 复制当前行
Ctrl-L 删除当前行
Ctrl-T 上下行交换
F3 找下一个
Shift-F3 找上一个
Ctrl-Shift-F 在文件中找
Ctrl-F2 触发书签
F2 到前一个书签
Shift-F2 到下一个书签
F5 打开run对话框
Ctrl-Space 打开CallTip列表框
Tab (selection of several lines) 加入Space
Shift-Tab (selection of several lines) 移除Space
F11 全屏
Alt-0 折叠全部
Alt-Shift-0 展开全部
Ctrl-U 变为小写
Ctrl-Shift-U 变为大写
Ctrl-Q 块注释/消除注释

使用ModelSim做simulation一些小问题的简单解决方法

使用ModelSim做模拟常常会遇到一些小问题,常常没有很在意但是常常又发生:-),这里谈谈遇到以下几个小问题的解决方法。

1.遇到类似以下的问题:

# ** Error: /homes/ethernet/eth_spram_256x32.v(151): Module 'RAMB4_S8' is not defined.
  # **Error: /homes/ethernet/xilinx_dist_ram_16x32.v(20): Module 'RAM16X1D' is not defined.

解决方法:进入Simulation Properties: Libraries --> 在Search Libraries中加入unisim(如果是要做 UNISIM-based RTL simulation)
如下图所示:

SearchLibraries_Modelsim

2.遇到类似以下的问题:

# ** Fatal: (vsim-3693) The minimum time resolution limit (10ps) in the Verilog source is smaller than the one chosen for SystemC or VHDL units in the design. Use the vsim -t option to specify the desired resolution.
#    Time: 0 ns  Iteration: 0  Instance: /sample_tb File: /homes/sample_tb.vhd Line: UNKNOWN
# FATAL ERROR while loading design

解决方法:改变Simulation Properties: Libraries --> 在Search Libraries中加入unisim(如果是要做 UNISIM-based RTL simulation)
如下图所示:也是进入Simulation Properties,然后如下图所示,改变Resolution。

Simulation_Properties_ModelSim

3.遇到类似以下的问题:

# ** Error: (vsim-3601) Iteration limit reached at time 0 ps.

# ** Note: (vsim-3602) Delays were truncated during elaboration of the design.

解决方法:进入Simulation -> Runtime Options,然后改变Iteration Limit,将它改成例如5000。如下图所示:

RuntimeOptions_Modelsim