Posted on 09-12-2017
Filed Under (技术) by waterlin

Boost 的官网下载一个你需要的版本号,按下面的步骤即可在 Windows 下安装编译 Boost 库:

1. 解压文件夹到指定目录;

2. 选择你想使用的 Visual Studio 版本来编译 Boost,如果机器上有多个 Visual Studio 版本,就从指定 Visual Studio 版本的 command prompt 进入 boost 的解压目录;

3. 运行 Boost 代码目录下的 bootstrap.bat 脚本;

4. 再跑下面的脚本来进行编译:

或是想用更多的参数可以像这样:

注意,上面的 address-model=64 是表示编码64位的,所以,如果要编译32位的,可以用 address-model=32。更多有关 b2 的命令行参数查阅这里

5. 最后编译好的东西,就放在 stage 里,一般来说用静态库就可以了。

6. 如果需要针对多个VS版本来进行编译,可以重新上述步骤,选择不同的平台,就会把库都编到同一个安装目录了。

注意,不管是对 32 位还是 64 位来编译,生成的库文件名,都是相同的,所以需要在编译完 32 位后,拷贝一份数据出来,再重新编译一份。

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

以下示例声明了一个指向 float 的指针:

因为 powerPtr 变量的类型是指向 float 的指针,所以读者可能会将代码写成:

这样写没有问题,编译也会通过,但不是好的代码风格。

C语言允许在一行代码中声明多个变量。例如,要声明变量 x、y和 z,可以将代码写成:

以上三个变量的类型都是 float。

再看下面这段代码,b 和 c 变量分别是什么类型?

答案可能会出乎读者的意料。b 是指向 float 的指针,但 c 的类型却是 float。如果需要将 a 和 b 都声明为指针,就必须在每个变量前都加上*:

在这种情况下,将 * 写在变量名这边,能让声明看上去更清楚。

摘录自《Object-C 编程》122页。

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

最近在使用定时器的时候,被一个小细节坑了,偶尔导致 coredump,费了好大的力气才找到原因,现在整理一下备忘。

我采用了如下方式来生成了定时器:

然后,我就不断地调用上面的代码来生成定时器,并干相应的的事情,比如说视频帧的刷新等操作。但是,我犯了一个错误,在我需要结束定时操作后,我采用了如下的方式来结束定时器:

就是因为最后一个参数的原因,偶尔会出现崩溃:即定时器并没有因为这一行代码而完全销毁,从而导致这个类在销毁后,定时器依然触发了回调信息。

要解决这个问题很简单,只需要把上述代码里的 NULL 参数修改为 INVALID_HANDLE_VALUE 即可:

看看微软官方文档对这两个参数区别的说明:

If this parameter is INVALID_HANDLE_VALUE, the function waits for any running timer callback functions to complete before returning.

If this parameter is NULL, the function marks the timer for deletion and returns immediately. If the timer has already expired, the timer callback function will run to completion. However, there is no notification sent when the timer callback function has completed. Most callers should not use this option, and should wait for running timer callback functions to complete so they can perform any needed cleanup.

即,如果使用 INVALID_HANDLE_VALUE 这个参数,则 DeleteTimerQueueTimer 会等待定时器销毁以及回调函数结束后才返回;如果使用 NULL 则把定时器立即标记为销毁,但是实际上的运行并不受控制,如果有定时器正处在回调函数里并正在执行,有可能导致异常情况。

我的崩溃就是由于这个参数引起的,不容易出现,很不好找原因。

(1) Comment    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 (平面格式)数据:

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

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

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

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

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

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

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

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

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

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

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

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

最近在产品开发中,有用到 QProcess 启动一个进程,并且与之通信。产品开发完了提交给测试组测试,发现产品的内存会不断地增长,但是这个增长速度十分缓慢,大概 12 小时 20M 左右。

怎么看都不像是常规的内存泄漏!

然后是各种找原因,先是把产品中有关视频展示及渲染的部分关掉进行测试,然后逐步把一些其它部分屏蔽掉,最后关得只剩下 socket 这个环节了,可是内存还在缓慢增长。Qt 的 socket 很靠谱啊?找来找去,终于觉得是 QProcess 惹的祸了。仔细地读了读文档,看到下面这一句话:

void QProcess::closeReadChannel ( ProcessChannel channel )
Closes the read channel channel. After calling this function, QProcess will no longer receive data on the channel. Any data that has already been received is still available for reading.
Call this function to save memory, if you are not interested in the output of the process.

其实 QProcess 是会把你启动进程的标准输出重定向到你的程序里来,从而占用你程序的内存。原来我这个缓慢增长就是由于 QProcess 启动进程后的 stdout 输出没有及时清理导致的。

如果不需要 QProcess 启动进程的标准输出,只需要在使用 QProcess 启动进程前调用 closeReadChannel 这个函数关闭输出即可。如果需要 QProcess 导过来的进程输出,则只需要在有输出数据的时候,读取干净即可。

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

最近在 PC 上需要生成一个二维码图片,准备使用 libqrencode 这个 QR 二维码生成库。Windows 下有一个它的移植版本 qrencode-win32,除了有源代码以外,还有一个 Windows 下的应用程序,可以直接用来生成 QR 二维码。

我使用的是 libqrencode 3.4.2 版本,对应于 Windows 下的版本是使用 VC8 来构建工程的,而我本地只有 VC9 的版本,我升级工程后进行编译,提示如下错误:

这是因为在 VC9 CRT 里已经定义了 vsnprintf 这个函数,而在 VC8 里却没有,所以在很多 VC8 或更早的代码里,会添加类似下面的定义:

对于 libqrencode 来说,也是这个问题,只需要把 config.h 里的这一句代码注释掉即可。

如果还需要在 VC8 和 VC9 里使用,则可以使用下面的方式来灵活定制:

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

Visual C++ 2008 SP1 compiler error C1859

有一些工程,在编译好后再重新编译,会提示类似如下错误(Windows7下容易出现):

这个就是 Visual C++ 2008 SP1 compiler error C1859 的问题,解决办法就是安装一个补丁包

除了安装上述安装包以后,还可以使用如下方式来修复该问题:

  • Disable /analyze (if enabled).
  • Invoke a clean build.
  • Reboot your machine.
  • Disable PCH files.

使用 std::copy 时的 C4996 警告

Visual C++ 2008 里如果把警告当成错误处理时进行编译,下面这个警告就会被当成错误,很扎眼,而你,则一定需要解决这个问题。

这是在使用 Visual C++ 自带的标准库时,Visual C++ 的编译器会加强检查,标准库里的一些方法会认为在使用上是不安全的。Visual C++ 对此提出警告、不建议使用这些函数,并且 Windows 提供了一些其它以 _s 结尾的函数用来替代这些方法。std::copy 就是这个现象的重灾区。

如果是你自己的代码碰到这个问题,那很好解决,你只需要把这些函数替换成 Windows 提供的更安全的函数即可。但是,如果是你引用的第三方库的代码问题,而你又在 Visual Studio 里把安全级别设置成不允许有警告,这个时候,就只能通过定义一个 _SCL_SECURE_NO_WARNINGS 宏来解决此问题。

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

平时都是使用 log4cxx 动态链接库,如果需要使用 log4cxx 静态链接库的方式,那还着实需要花一番力气。

  1. 为预编译器定义 LOG4CXX_STATIC 宏。
  2. 静态链接 log4cxx 库,除了正常使用填入如下链接库外:

    还需要添加

    这两个库,否则会有如下出错提示:

  3. 在 Visual Studio 2008 工程里的 object/library modules:下方填入:Mswsock.lib
  4. 如果显示如下错误:

    则添加如下库:aprd.lib。

这样,基本上就可以在你的工程里静态链接 log4cxx 库了。

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

这两天在写 Qt 代码时,用 QPixmap 的 load 或是 loadFromData 方法来从图片文件里导入 Jpeg 图像数据,结果在 debug 版本下可以正确导入图像,可是在 release 版本下却没有办法导入图像。

这个时候,原因多半是 Qt 不支持这个图像格式,可以用下面的代码来检查当前的 Qt 版本支持的图像格式种类,并检查里面是否支持 JPEG 图像格式。

从结果可以看出,当前的 Release 版本的确是不支持 Jpeg 图像格式。是由什么原因造成的这个现象呢?

这里情况比较特殊:并不是 Qt 不支持这个图像格式,而是需要在 release 版本里包括这个解码库。即把 qjpeg4.dll 链接库拷贝成 release 目录下的

文件。你只需要让 Release 版本的可执行文件,可以正确找到该编码库链接库即可。请注意当你打包成安装文件进行安装时,一定要注意把该链接库安装到目录 imageformats 下,否则依然无法正确使用。

类似的问题,同样会存在于字符集编码等其它插件里:当你使用了指定的字符集编码时,则同样需要打包类似的库。例如,对于简体中文来说,需要把 qcncodecs4.dll 打包安装成

文件。

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

通常情况下使用 log4cxx 都是通过一个 log4cxx 配置文件来配置相关参数的,通常描述 log4cxx 的文档1, 2,都会对此作详细的介绍。

但是,如果我能直接在 C/C++ 代码里设置 log4cxx 的属性,这样就可以不使用属性配置文件了。在某些情况下,这样还是更方便一些。从 log4xxx Wiki 获取的示例代码就是起这个作用的,代码如下:

上面的代码仅仅是把日志输出到日志文件,如果我们想同时把日志重定向到终端和文件,我们应该添加一个 log4cxx::ConsoleAppender 类来支持 log4cxx::BasicConfigurator 的初始化。下面是示例代码:

通过上面的代码,在没有 log4cxx 配置文件的情况下,日志也同样可以同时输出到终端和日志文件了。

(0) Comments    Read More