Posted on 06-11-2015
Filed Under (技术) by waterlin

本文摘自《费马大定理:一个困惑了世间智者358年的谜》“第三章数学史上暗淡的一页”中的部分内容,主要是介绍一下密钥和公钥的数学原理,摘录于下,备查。

虽然质数的无穷性使早期证明费马大定理的希望破灭,但质数的这种性质的确在诸如谍报活动和昆虫进化等别的领域具有比较积极的意义。在回到寻求费马大定理的证明之前,稍微研究一下质数的正常使用和滥用是值得的。

质数理论是纯粹数学中已经在现实世界中找到直接应用的少数领域之一,它在密码学中有直接应用。密码学涉及将需要保密的信息打乱,使得只有接收者才能整理出它们,而别的任何可能截获它们的人都无法做到这一点。这种打乱的过程需要使用密钥,而整理这些信息按惯例只需要接收者反过来使用密钥就行了。在这个程序中,密钥是保密环节中最薄弱的一环。首先,接收者和发送者必须约定密钥的详细内容,而这种信息的交流是一个有泄密风险的过程。如果敌方能截获正在交流的密钥,那么他们就能译出此后所有的信息。其次,为了保持安全性,密钥必须定期更改,而每一次更改时,都有新的密钥被截获的危险。

密钥的问题围绕着下面的事实展开:它的使用,一次是打乱信息,另一次是反过来整理出信息,而整理信息几乎与打乱信息同样容易。然而,经验告诉我们:在许多情况中整理要比打乱困难得多——打碎一个鸡蛋是相对容易的,而重新拼好它则困难得多。

在20世纪70年代,惠特菲尔德·迪菲(Whitfield Diffie)和马丁·海尔曼(Martin Hellman)提出了这样的思想:寻找一种按一个方向很容易进行,而按相反方向进行则不可思议地困难的数学程序。这种程序将会提供十分完美的密钥。举例来说,我可以有自己用的、由两部分组成的密钥,并且在公用指南中公开它的用于打乱信息的那部分。

于是,任何人都可以向我发送打乱过的信息,但是只有我知道密钥中用于整理信息的那一半。虽然人人都了解密钥中关于打乱信息的那部分,但是它和密钥中用来整理信息的那部分毫无联系。

在1977年,麻省理工学院一群数学家和计算机专家罗纳德·里维斯特(Ronald Rivest)、艾迪·沙米(Adi Shamir)和伦纳德·阿德里曼(Leonard Adleman)认识到质数可能是易打乱、难整理过程的理想的基础。为了制成我自己的私人密钥,我会取两个大质数,每一个多达80个数字,然后将它们乘起来得到一个大得多的非质数。为了打乱信息所需要的一切,就是知道这个大的非质数,然而要整理信息则需要知道已经被乘在一起的原来的两个质数,它们称为质因数。现在我可以公开大的非质数,也即密钥中打乱信息的那一半,而自己保存那两个质因数,即密钥中整理信息的那一半。重要的是,即使人人都知道这个大的非质数,他们要判断出那两个质因数却仍然非常困难。

举一个简单的例子,我可以交出非质数589,这可能会使每个人都能代我打乱信息。然而,我将保守589的两个质因数的秘密,结果只有我能够整理信息。如果别的人能判断出这两个质因数,那么他们也能整理我的信息,但是即使是对这个不大的数,两个质因数是什么也不是显而易见的。在589这个情形中,在台式电脑上只要花几分钟就可算出两个质因数实际上是31和19(31×19=589),所以我的密钥的秘密不会持久。

然而,实际上我公布的非质数将会有100位以上的数字,这就使找出它的质因数的任务变得几乎是不可能的。即使用世界上最快的计算机来将这个巨大的非质数(打乱信息的密钥)分解成它的两个质因数(整理信息的密钥),也要花几年时间才能得到答案。于是,为挫败外国间谍,我仅仅需要每年一次更改我的密钥。每年一次我宣布我的巨大的非质数,任何人要想尝试整理我的信息,就必须从头开始设法算出这两个质因数。

除了在谍报活动中发现应用外,质数也出现在自然界中。在昆虫中十七年蝉的生命周期是最长的。它们独有的生命周期开始于地下,蝉蛹在地下耐心地吮吸树根中的汁水。然后,经过17年的等待,成年的蝉钻出地面,无数的蝉密集在一起,一时间掩盖了一切景色。在几个星期中,它们交配,产卵,然后死去。

除了在谍报活动中发现应用外,质数也出现在自然界中。在昆虫中十七年蝉的生命周期是最长的。它们独有的生命周期开始于地下,蝉蛹在地下耐心地吮吸树根中的汁水。然后,经过17年的等待,成年的蝉钻出地面,无数的蝉密集在一起,一时间掩盖了一切景色。在几个星期中,它们交配,产卵,然后死去。

有一种理论假设蝉有一种生命周期也较长的寄生物,蝉要设法避开这种寄生物。如果这种寄生物的生命周期比方说是2年,那么蝉就要避开能被2整除的生命周期,否则寄生物和蝉就会定期相遇。类似地,如果寄生物的生命周期是3年,那么蝉要避开能被3整除的生命周期,否则寄生物和蝉又会定期相遇。所以最终为了避免遇到它的寄生物,蝉的最佳策略是使它的生命周期的年数延长为一个质数。由于没有数能整除17,十七年蝉将很难得遇上它的寄生物。如果寄生物的生命周期为2年,那么它们每隔34年才遇上一次;倘若寄生物的生命周期更长一些,比方说16年,那么它们每隔272(16×17)年才遇上一次。

为了回击,寄生物只有选择两种生命周期可以增加相遇的频率——1年期的生命周期以及与蝉同样的17年期的生命周期。然而,寄生物不可能活着接连重新出现达17年之久,因为在前16次出现时没有蝉供它们寄生。另一方面,为了达到为期17年的生命周期,一代代的寄生物在16年的生命周期中首先必须得到进化,这意味着在进化的某个阶段,寄生物和蝉会有272年之久不相遇!无论哪一种情形,蝉的漫长的、年数为质数的生命周期都保护了它。

这或许解释了为什么这种假设的寄生物从未被发现!在为了跟上蝉而进行的赛跑中,寄生物很可能不断延长它的生命周期直至到达16年这个难关。然后它将有272年的时间遇不到蝉,而在此之前,由于无法与蝉相遇它已被赶上了绝路。剩下的是生命周期为17年的蝉,其实它已不再需要这么长的生命周期了,因为它的寄生物已不复存在。

(0) Comments    Read More   
Posted on 29-04-2015
Filed Under (技术) by waterlin

一、先介绍一个基本的移动端采集音频模块

OpenSL ES :嵌入式音频加速标准

OpenSL ES™ 是无授权费、跨平台、针对嵌入式系统精心优化的硬件音频加速API。它为嵌入式移动多媒体设备上的本地应用程序开发者提供标准化、高性能、低响应时间的音频功能实现方法,并实现软/硬件音频性能的直接跨平台部署,降低执行难度,促进高级音频市场的发展。

二、再介绍一些常用的音频格式

SILK: Skype 里使用的一种音频格式。这个格式的 SDK 可以从网上下载,不过有版权保护,只允许用来做测试与研究,如果需要在产品里使用,估计还是得取得授权。这个基本上是基于语音对话来设计的质量,对讲话的录音效果还可以,但是对于音乐等来说,效果不太好。

Speex: 已经不再维护,官方建议使用 Opus 来代替。

Opus: 基本上可以说是为网络而生的音频格式,支持网络电话、视频会议以及游戏里的音频对讲等场景。Opus 是由 SILK 发展而来。

AMRWB: Adaptive Multi-Rate Wideband, Nokia 和 VoiceAge 联合开发的一个音频格式,最开始是在 3GPP 里使用。

AAC:这个不用多介绍了吧,几乎是现在最常用的音频格式了,当初主要是用在 Mp4 里的。

HE-AAC:又叫 EAAC+,是 AAC 的改进版本,基本上是现在效果最好的库了。

(0) Comments    Read More   
Posted on 22-04-2015
Filed Under (技术) by waterlin
  1. Maven 会把你依赖的库下载到 ~/.m2 文件夹里,在硬盘里仔细找找。
  2. 如果 Maven 拿不到相关的依赖文件,仔细检查一下 ~/.m2/settings.xml 文件,看究竟有没有错误。
  3. 如果你的代码都写好了,想测试一下相关依赖库等是否正常、能否正常编译,可以使用下面的命令来进行编译:
    mvn package -Pdev
    

    如果你们团队有构建服务器,则上述命令的运行应该和服务器上的构建是等价的,在服务器上构建之前,可以使用这个命令来进行构建测试。

  4. Maven 的基本用法及概念参看这里
  5. 配置好了 pom.xml 文件后,以后需要引用第三方库,直接在 pom 文件里配置即可。还有一种情况,如果别人临时编译了一个版本给你要测试,怎么办?这时可以直接把库文件放到本地相应的 libs 目录里,有一些编辑器如 Android Studio 会优先采用本地的库文件。
  6. 如果用 Maven 来构建 Android 工程,可以参看 Android Example Maven Project 这个例子来构建工程。不过现在好像都推荐使用 Gradle 来构建 Android 工程了。
(0) Comments    Read More   
Posted on 09-04-2015
Filed Under (技术) by waterlin

Spydroid 是一个可以让 Android 手机变成音视频采集终端的 App,其中核心功能由 libstreaming 库提供。

技术上的主要实现原理:

  1. 使用 Android 的 MediaRecorder API 来录制音视频为 mp4 文件,然后通过这个 mp4 文件来生成 rtsp 流。这样做,只能做到图像与声音大致同步,尤其是人说话的时候音画同步的问题会特别明显;这种方式对于网络抖动的处理也不是特别好。
  2. 通过 MediaCodec API 来获取视频流的未压缩数据,然后通过自己的编码器,来生成视频流。这个和传统的多媒体视频流思路一样,比较容易控制,但是对 Android 系统的版本有要求,系统版本最低最好不要低于 4.0。

这个库的使用方式主要有两种:

  1. 把 libstreaming 当作 rtsp 客户端来使用,并且植入 Wowza Media Server,这样就可以从手机上获取实时视频流,并让 Wowza Media Server 分发出去,从而实现在网页上观看手机采集的音视频流功能。
  2. 把 libstreaming 当作一个 rtsp 服务器,这样通过 VLC 或是其它 rtsp 流播放器,可以观看当前手机摄像头的音视频流媒体内容。
(0) Comments    Read More   
Posted on 25-03-2015
Filed Under (技术) by waterlin

最近琢磨了一下 WebM 的远程传输技术,小结一下。

  1. 通过 RTSP 的流媒体方式来传输 WebM,IETF 草案里有涉及到使用 RTP 来传输 VP-8 编码数据的细节,经测试,这个方案和用 RTP 来传输 H.264 数据一样靠谱。
  2. 直接通过 HTML5 的方式使用浏览器播放服务器的 WebM 视频

    WebM 如果需要在浏览器里使用的话,可以使用 HTML5 的技术来实现,Firefox 和 Chrome 原生支持播放 WebM 视频,对于 IE 来说,虽然原生不支持 WebM 视频,但是却可以通过安装插件来完成,安装了该插件后,则 IE9 以上版本可完美支持 WebM 的播放。有关 IE 支持 WebM 的技术细节可以查看 HTML5 Video Update—WebM for IE9 一文。

题外话:HTML5 还是好东西,起码对于视频点播来说是一个进步,原来的 HTML 一般来说都需要通过插件(比如说 flash)来完成对视频的点播技术,而现在 HTML5 原生就支持视频点播技术了,希望标准进一步细化,实现各个浏览器的统一。

(0) Comments    Read More   
Posted on 23-03-2015
Filed Under (技术) by waterlin

不管手机内置存储有多大,按照现在这种多媒体、照片及视频的拍摄方法,很快就满了。在我的 htc one 上,16G 的存储就面临着这样一个问题。在我拍了大量的相片与视频后,我的机身存储终于快要爆了,于是我想办法给手机减负,但是里面的相片实在无法可删,我也不想把照片拷到电脑上放着,因为我想随时拿出来看一看。今天琢磨了一个整理手机相册的办法,能保证 Android 系统速度的同时,也能保证存储最大数量的照片。

  1. 设置手机的摄像头拍照存储空间为机器本身,这样可以保证最大的拍摄速度与存储速度。事实上,不单单针对摄像头的数据,对于其它应用的数据(比如说记事本、阅读器等),能把存储位置设置到机身上也尽量设置在机身上。
  2. 在 SD 卡的根目录下,新建一个比较特殊的名称,用来存放相片。取一个比较特殊的名称,主要是怕一些应用会取相同名称的文件夹。
  3. 当机身的存储空间快要满的时候,把机身存储里的照片整理好,把需要保存起来的照片拷贝出来,放到第 2 步里建立的专门用来存放照片的文件夹里,为了方便管理,你可以在第 2 步建立的文件夹下面,继续以日期、地点、主题等方式建立子文件夹,方便回忆照片内容。
  4. 第 3 步完成后,你从摄像头界面查看相册,应该会看不到旧的照片了。不过没关系,这时再安装一个第三方相册软件(比如说快图浏览,英文名叫QuickPic),专门用来查看手机里的相册。这样就解决了相片移动了位置而原生相册无法查看的问题。
  5. 定期重复第 3 步,把照片从机身存储移动到 SD 卡里。这样就能保证机身有足够的存储空间,而手机里也能常保存旧照片。

这样把照片都备份到 SD 卡上,有一个好处:在你换手机时,只需要把 SD 卡也插到新手机上,原来的照片一张都不少;就算是你要换 SD 卡,也一样只需要备份你重要文件夹里的数据而再也不用担心有数据不知道放在哪里了,这样方便了吧?

另外说一下,对于多媒体的东西,手机上再多的存储空间也是不够用的、也是不安全的。唯一保证数据安全可靠的办法,就是勤整理照片,多备份手机上的数据到电脑上、移动硬盘上,保证数据的安全性以及减少冗余性。

(0) Comments    Read More   
Posted on 29-01-2015
Filed Under (技术) by waterlin

一直以来对 HTTP 方式观看视频的技术不是太了解,最近恶补了一些知识,整理一下笔记,备忘一下。本篇主要谈谈使用 Adobe Flash Media Server 4.5 来配置一个基本的网页视频服务站点的概念及步骤。

一些基础的知识

与 Flash 有关的一些名词概念

FMS: Flash Media Server,Flash多媒体服务器,用来对音频和视频进行流媒体服务的服务器软件。

SWF: small web format,就是 flash 动画文件。

FLV: Flash Video,用来通过 Flash 播放视频的文件格式,可以包含在 SWF 中。在互联网上,这个是事实上的基于 Web 的视频服务的传输标准,例如 Youtube 之类的厂商都是用这个格式来进行基于 Web 的在线视频点播。FLV 文件里对视频和音频内容的编码方法和 SWF 是一样的。从 Adobe Flash Player version 6 开始支持 FLV 格式。

F4V: 与 FLV 相平行的一种格式,为了封装 H.264 和 AAC 的音视频内容,从 Flash Player 9 update 3 开始支持这种格式。

备注:在 Windows 上可以通过 Flash Player 来播放 FLV 和 F4V 格式的视频,在 Web 浏览器里通过安装 Flash Player 插件来实现对这类视频的播放。

FLA: SWF 的源代码文件,可以使用编辑器打开这个文件进行修改,再导出新的 SWF 文件。

f4m: 清单文件,在使用 Web 浏览器来进行视频浏览时,需要有一个清单文件来适配码率以便选择合适的文件,就是通过这个清单来做的。

Flash Professional: 用来制作 SWF 的专业工具。

VOD: Video on Demond,请求视频服务。在 FMS 安装目录下的 vod 目录,有如下的使用特例:

The VOD service enables you to stream video and audio files through the server without writing any application code or configuring the server. You can simply point the Flash FLVPlayback component or a Flash video object to a file in this folder and the file will play—as long as it is an MP4, F4V, FLV, or MP3 file.

Flash 视频服务的基本类型

总体来说,Flash 视频的使用方式有两种,一种是客户端的模式,通过使用 RTMP 协议;另一种方式是使用 HTTP 的方式,通过网页来观看视频。在这两种方式中,SWF 都是客户端,FMS 都是服务器。

使用 RTMP 的方式来观看视频

最基本的配置步骤:

  1. 正常安装 FMS 4.5;
  2. 打开安装文件夹的这个路径:
    D:\Program Files\Adobe\Flash Media Server 4.5\applications\vod\media
    

    把示例的 flv 文件扔进去,或者直接使用该目录下面已有的测试文件。

  3. 直接打开 VLC 播放器,使用如下的地址来进行播放了:
    rtmp://127.0.0.1/vod/sample
    

    或是

    rtmp://127.0.0.1/vod/Legend
    

对于以 flv 为后缀的文件,可以不使用后缀。但是这样播放有一个问题,没有办法快进与快退。

使用这种方式来播放,可以简单地测试一下服务器是否正常。

另外,使用 Flash Media Server,还可以直接直播摄像头的视频。大体上是三个步骤:

  1. 使用 Flash Media Live Encoder 对摄像头的数据进行压缩;
  2. 使用 Flash Media Server 创建一个直播流;
  3. 使用视频播放器来打开这个地址。

使用 HTTP 的方式来观看视频

如果使用 HTTP 的方式来传输视频,最基本的原理在这里讲得很清楚了,引用里面比较经典的一段话:

HDS和Pete的想法又有什么关联呢?HDS可能就是由你伴随Flash Media Server (FMS)一同安装的Apache模块而来的。在这种情况下,FMS扮演着打包机的角色,制造内容片断,由Apache通过HTTP传输到Flash兼容的视频播放器。为了解决Sam所提出的反对意见,与F4M扩展一起,另外的一个清单文件也是通过同样的一个过程创建出来的。从根本上说,所需视频文件首先使用F4F扩展软件切割成若干片段,作为片段文件。清单文件中包含了视频的一些基本信息,包括每一个片段文件的位置以及其中最为重要的信息——这些片段传输到用户设备上的顺序。

对于具体的协议来说,可以使用 PD, HLS, HDS 这三种中的一个,这三种协议的基本含义:

PD: HTTP progressive download,在终端用户上缓存多媒体文件从而实现边下载边播放的流媒体技术,这是很多视频流媒体服务使用方法的统称。

HLS: HTTP Live Streaming,苹果公司的基于 Web 的流媒体服务协议,先把视频切成若干个小片,然后使用 HTTP 协议下载后进行播放,从而实现基于 Web 的视频播放技术。这个协议最大的优势是只使用了 HTTP 协议,所以一般来讲,只要能正常上网的地方就可以使用该协议进行视频观看服务。

HDS: HTTP Dynamic Streaming

对于 FMS 的配置来讲,如果需要跑起基本的视频服务,还是比较简单的,根据上面的教程来配置即可。这几者之间的优缺点下次再作详细的介绍。

(0) Comments    Read More   
Posted on 17-11-2014
Filed Under (技术) by waterlin

今天碰到一个比较有意思的问题,在我本地编译的 release 版本没有任何问题,但是如果我提交到版本库并且从构建系统里构建,则会提示说 protobuf 的头文件有一些未使用的变量,从而生成警告信息。由于我们的构建系统设置是会把警告当成错误来对待,从而抛出一个 4996 的警告,从而构建系统把这个警告当作错误信息,导致版本构建失败。

实在找不出是什么原因导致的这个警告消息,我只把强行用 #pragma 把这个警告消息去掉:

#pragma warning(disable:4996)
#include "protocol.pb.h"
#pragma warning(default:4996)

对于代码里的这种莫名其妙的问题,还是使用类似于 #pragma 的方法来处理吧。

(0) Comments    Read More   
Posted on 05-11-2014
Filed Under (技术) by waterlin

今天在使用 FFMpeg 解码 iPad 过来的视频流时,有一个非常奇怪的现象,即对于分辨率为 406*720 和 450*720 的图像来说,解码一切正常,但是把 YUV420 的数据转为 RGBA 显示出来时,图像的最右边会有一条几个像素的黑竖条,如下图所示:

./images/ffmpeg-black-bar2.jpg

碰到这个问题,通常的解决思路如下。

第一,检查一下解码是否有错误,这个好办,只要解码不返回错误码就是正常。

第二,如果解码没有问题的话,仔细查看各步的图片格式转化操作是否有问题。

1. 先看看解码出来的 yuv 数据是否就有这条黑边。可以直接把 yuv 保存成二进制文件,然后用 yuvplayer 播放。

如果是使用 FFMpeg 解码,则可以使用如下的代码来保存 yuv (平面格式)数据:

//保存yuv数据
static int fcount = 0;
char yuvdumpName[255];

sprintf(yuvdumpName, "E:/temp/yuv/%d.yuv", fcount);
FILE *fp = fopen(yuvdumpName, "ab");
if (fp) {

    char* yuv = (char*)src_frame->data[0];
    int stride = src_frame->linesize[0];

    for(int y=0; y<720; y++) {
        fwrite(yuv+stride*y, 1, 540, fp);
    }

    char* udata = (char*)src_frame->data[1];
    int ustride = src_frame->linesize[1];

    for(int u=0; u<720/2; u++) {
        fwrite(udata+u*ustride, 1, 540/2, fp);
    }

    char* vdata = (char*)src_frame->data[2];
    int vstride = src_frame->linesize[2];
    for(int v=0; v<720/2; v++) {
        fwrite(vdata+v*vstride, 1, 540/2, fp);
    }

    fclose(fp);
    fcount++;
}

在我这里有一个特别奇怪的现象,分辨是 540*720,但是解码后得到的 YUV 的 stridesize 是: 576, 288, 288。经过查找资料,原来为了方便各种格式转换及效率,通常是把分辨率的宽度进行了 16 倍整数化,方便硬件加速。

在我查看了 yuv 图片后,还是一切正常,真是怪事,只能继续找原因了。

2. 既然 yuv 数据没有黑边,则把 sws_scale 转成 BGRA 数据后的图片保存成位图,看是否有黑边。

可以使用如下的代码来保存 BGRA 的数据:

void saveBmpFile(uint8_t *src,int srcW,int srcH,int srcStride)
{
    static int fileIndex = 0;

    char filename[256];
    sprintf(filename,"e:\\temp\\yuv\\bmp\\%d.bmp", fileIndex++);
    BITMAPINFOHEADER bih; 
    BITMAPFILEHEADER bhh;  
    int widthStep = srcStride; //(((src->m_width * 24) + 31) & (~31)) / 8 ;  
    bih.biSize=40;       // header size  
    bih.biWidth= srcW;
    bih.biHeight= abs(srcH);
    bih.biPlanes=1;  
    bih.biBitCount=32;     // RGB encoded, 24 bit  
    bih.biCompression=BI_RGB;   // no compression
    bih.biSizeImage=srcStride*abs(srcH);
    bih.biXPelsPerMeter=0;  
    bih.biYPelsPerMeter=0;  
    bih.biClrUsed=0;  
    bih.biClrImportant=0;   
    bhh.bfType = ((WORD) ('M' << 8) | 'B');  //'BM'  
    bhh.bfSize = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + widthStep * abs(srcH);
    bhh.bfReserved1 = 0;  
    bhh.bfReserved2 = 0;  
    bhh.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);

    FILE *fp = fopen(filename, "wb");
    if( fp ) {
        src = src + (abs(srcH)-1)*srcStride;
        fwrite(&bhh,1,sizeof(bhh),fp);
        fwrite(&bih,1,sizeof(bih),fp);
        for(int y=0; y<abs(srcH); y++) {
            fwrite(src,1,srcW*4,fp);
            src -= srcStride;
        }
        fclose(fp);
    }
}

如果使用了 Qt 库,也可以直接这样保存图片:

AVFrame *pFrameRGB = avcodec_alloc_frame();

//some decode operation

static int index = 0;
QImage image( pFrameRGB->data[0], codec->width, codec->height, QImage::Format_RGB32 );
image = image.copy();
image.save(QString("E:/temp/yuv/jpg/%1.jpg").arg(index));
index++;

在我这里,恰恰是第2步使用 sws_scale 转换图片格式后出现的黑边。我原来 sws_scale 的使用方法如下:

SwsContext *img_convert_ctx_temp;
img_convert_ctx_temp = sws_getContext(
                                    codec->width, codec->height,
                                    codec->pix_fmt,
                                    dst_w, dst_h, (PixelFormat)dst_fmt,
                                    SWS_BICUBIC, NULL, NULL, NULL);

sws_scale(img_convert_ctx_temp,
          src_frame->data, src_frame->linesize, 0, codec->height,
          pFrameRGB->data,
          pFrameRGB->linesize);

事实上问题就出在这里,是 sws_getContext 这个函数的参数需要带上 SWS_ACCURATE_RND,即修改成如下方式:

SwsContext *img_convert_ctx_temp;
img_convert_ctx_temp = sws_getContext(
                                    codec->width, codec->height,
                                    codec->pix_fmt,
                                    dst_w, dst_h, (PixelFormat)dst_fmt,
                                    SWS_BICUBIC | SWS_ACCURATE_RND, NULL, NULL, NULL);

但是加了这个参数后,运算速度就变得巨慢了。

有一个更好的解决办法,就是在解码后把图片的 yuv 格式转成 BGRA 格式之前,先考虑一下设置 RGBA 格式的图像的宽度是 16 的倍数:

PixelFormat dst_fmt = PIX_FMT_BGRA;
int dst_w = (codec->width/16)*16;
int dst_h = codec->height;

这样在你以后用 sws_scale 时就可以直接使用 dst_w 这样的16的倍数来进行操作。这样,黑边的问题就解决了,黑边得到了裁剪,并且并不会耗费大量的计算时间,不过缺点是图像的分辨率也变小了。*最佳的解决办法,是在压缩流的输出端就保证分辨率的宽度值是 16 的整数倍*。

PS:我这里碰到这个问题,有可能是因为使用的 FFMpeg 库被修改过,用 SSE4 加速了 rgb 到 yuv420 的转换操作。原版的 FFMpeg 在这些奇怪的分辨率下是否会是如此,我没有验证。

(0) Comments    Read More   
Posted on 06-08-2014
Filed Under (技术) by waterlin

protobuf 可以很方便地在各个语言里制定数据交换协议,通过绑定不同的语言进行编译,可生成相应的代码文件。针对 C++ 和 Java 语言的编译,非常简单,好像默认就能搞定(不知道是不是因为我本地 C++ 和 Java 的环境很完善有关),而针对 Go 语言进行编译,则有点麻烦,折腾了好一会,写个笔记备忘一下。

基本的配置步骤

  1. 安装 Go 语言,这个简单,直接安装就可以了。安装好后,记得把 bin 目录添加到系统的 PATH 变量里,这样就可以执行 go 命令了。
  2. 安装 hg 源代码管理工具,Go 下载扩展包的时候要用到的命令。
  3. 安装 goprotobuf 扩展包,先在环境变量里新建一个变量 GOPATH,指向一个你准备用来放置 Go 扩展包的路径,注意,GOPATH 所指向的路径需要与 GOROOT 不一样。
  4. 在 GOPATH 目录下,新建 src 和 pkg 目录。
  5. 安装 goprotobuf,使用如下命令即可安装
    go get code.google.com/p/goprotobuf/{proto,protoc-gen-go}
    

    如果前面配置正确的话,这一步应该不会提示什么错误。

  6. 上述命令安装成功后,即可在目录 $GOPATH/bin 里找到编译好的 protoc-gen-go.exe 程序,并且把 $GOPATH/bin 添加到系统的 PATH 里,这样从命令行执行的话,可以找到该命令。
  7. 在 protobuf 的编译脚本里,加上下面这一行,就可以在编译的时候,编译出针对 go 语言的代码文件。
    #!bin/sh
    
    outDir=./out
    
    #create folder or do something else
    
    goSucceed=true
    protoc --go_out=$outDir/go live.proto
    if [ $? = 0 ]; then 
            echo "build go protocol succeed"
    else 
            goSucceed=false
            echo  "build go protocol failed"
    fi
    

碰到的一些基础问题

如果出现如下错误:

C:\Users\Administrator>go get -u code.google.com/p/goprotobuf/{proto,protoc-gen-
go}
package code.google.com/p/goprotobuf/{proto,protoc-gen-go}: invalid code.google.
com/ import path "code.google.com/p/goprotobuf/{proto,protoc-gen-go}"

我感觉多半是没设 GOPATH 环境变量,这个我没准确验证。

如果提示如下错误

Administrator@DBXXT-20131216M /cygdrive/d/OpenSource/go-packages/src/goprotobuf
$ go get code.google.com/p/goprotobuf/{proto,protoc-gen-go}
go: missing Mercurial command. See http://golang.org/s/gogetcmd
package code.google.com/p/goprotobuf/proto: exec: "hg": executable file not found in %PATH%
package code.google.com/p/goprotobuf/protoc-gen-go
        imports code.google.com/p/goprotobuf/protoc-gen-go
        imports code.google.com/p/goprotobuf/protoc-gen-go: cannot find package "code.google.com/p/goprotobuf/protoc-gen-go" in any of:
        D:\Go\src\pkg\code.google.com\p\goprotobuf\protoc-gen-go (from $GOROOT)
        D:\OpenSource\go-packages\src\code.google.com\p\goprotobuf\protoc-gen-go (from $GOPATH)

的话,就是没有安装 hg 源代码管理工具。

(0) Comments    Read More