分享

Linux 的魅力: 访问 Nokia N800 摄像机

 waston 2011-09-26

Linux 的魅力: 访问 Nokia N800 摄像机

构建应用程序以访问 Webcam

Peter Seebach (developerworks@seebs.plethora.net), 自由作家, Wind River Systems
Author photo
Peter Seebach 已经使用计算机很多年了,也正在逐渐适应计算机的特性。不过他仍然不清楚为什么鼠标要如此频繁地进行清洁。

简介:  Linux 的魅力 的 3 期文章用实际例子演示了如何构建应用程序:使用摄像机功能创建 Webcam。在这期文章中,讨论如何使用 gstreamer 开始构建摄像机应用程序,以访问 Nokia N800 设备的 Webcam(需要做的工作也许比您想象的更少,尤其是在我们借鉴现有的应用程序之后)。

在这个分三部分的系列的 第 1 期 中,演示了 Nokia N800 Linux® 的内部结构,列出了它的 技术规范和物理参数,并阐述了如何设置和测试构建环境。

前提条件

本文从 网站上描述的一个摄像机应用程序开始讨论。此处只是提供这篇 maemo 文章的链接并建议您熟悉其中包含的信息,而不会重复其内容并加以解释:“ How to use the Camera API”。

关于开发 Nokia N770 和 N800 的其他 developerWorks 文章

尽管不需要 shell 访问也能在 N800 上运行摄像机应用程序,但是在 N800 上加载一个终端程序将非常有用。我还安装了一个 ssh 服务器,以便在测试时可以使用实际的键盘。提示一下:如果在 N800 上安装 ssh 服务器(和之前的 770 一样),系统将允许通过 ssh 进行根登录(密码为 “rootme”)。毫无疑问应该修改这个设置,但是人们总会单击附件来查看其行为,因此建议更改 root 密码。

认识 GStreamer

GStreamer 是一种开源的多媒体框架 — 这个时髦词的具体含义就是提供了连接各种媒体流(比如音频或视频)的胶合代码。如果仅此而已也没多大用处,最大的优势在于它包含了对大量任务的支持。默认 情况下 N800 上安装了 GStreamer 库,但这并不是命令行工具。如果有一个根 shell,则可以弥补这个缺陷,并能执行更多命令(参阅 获取更多软件 侧栏)。只需从 maemo 存储库安装 gstreamer-tools 包,就能够获得命令行前端。

如果按照以上步骤进行了操作,就可以打开摄像机了;否则,应该禁用视频聊天应用程序的 “start when camera opened” 功能(查看 Tools 菜单)。

gstreamer 的重要用途是设置管道。和 UNIX® shell 中使用管道将小部件汇编成完整的应用程序一样,gstreamer 管道将各种部件组合在一起。我将简单展示一个使用 gstreamer 库的 C 程序,也可以使用一个名为 gst-launch 的命令行工具。这个工具在 gstreamer-tools 包中,可以使用 apt-get 工具安装该包,但是不能使用 Application Manager 安装,因为它只显示经过过滤的部分可用项目(还需要向 apt-get 配置添加一些存储库,参阅 获取更多软件 侧栏)。


清单 1. 安装 gstreamer-tools
                
# apt-get install gstreamer-tools
Reading package lists... Done
Building dependency tree... Done
The following extra packages will be installed:
gstreamer0.10-tools
The following NEW packages will be installed:
gstreamer-tools gstreamer0.10-tools
0 upgraded, 2 newly installed, 0 to remove and 9 not upgraded.
Need to get 41.1kB of archives.
After unpacking 164kB of additional disk space will be used.
Do you want to continue [Y/n]?
WARNING: The following packages cannot be authenticated!
gstreamer0.10-tools gstreamer-tools
Install these packages without verification [y/N]? y
[...]
Setting up gstreamer0.10-tools (0.10.9-osso11) ...
Setting up gstreamer-tools (0.10.9-osso11) ...

注意这些包没有经过 “验证”,在此处并无关系。下面是一个简单的命令行调用:

$ gst-launch v4l2src ! xvimagesink

请记住命令中使用的是一个感叹号,而不是一个 pipe(|)符号。如果执行了该命令,屏幕上将会出现来自摄像机的实况视频。这个方法很容易掌握。

gst-launch 程序是一个简单的封装程序,它打开指定的插件并将它们连接在一起(在 gstreamer 中,能够进行连接的任何部件称为一个插件;插件通过名称识别并在运行时动态载入)。感叹号的用法与 shell 命令中的 pipe(|)一样。在本文中,每个插件称为一个元素

要了解 gstreamer 的主要工作,请注意:

在本文中,v4l2src 插件是 video4linux2 源;其默认行为是查找内核能够识别的第一个支持的视频设备及其生成的流视频。xvimagesink 插件在物理显示器上显示视频流。

一些元素既可以是源也可以是接收器。每个插件可以定义 pad 或连接器;一个给定的 pad 可以是源也可以是接收器。许多插件都支持其中的一种,并对输入进行转换以生成输出。

还存在许多特殊元素。例如,有一个名为 fakesink 的特殊元素,它只能消耗输出。为什么需要这样的元素呢?因为如果元素带有断开的输出,那么它将会等待其他元素消耗其输出。

一些元素在使用过程中可以获得附加的 pad。 其中一个显著特点是,tee pad 允许将一个以上的接收器与其连接,将一个流分解并提供多个副本。如果想在流上执行两个操作,每个操作需要不同且不兼容的过滤器,那么这个功能很有用。

可以通过很多方式使用 gstreamer 设计 Webcam 应用程序。基本思想是将一个视频源连接到一个图像接收器(比如屏幕)和其他地方,然后获取图像的一个副本并编码成一个 JPEG 文件。默认情况下,来自摄像机的视频不是 RGB 格式的。这正是 gstreamer 框架发挥作用的地方;其自动导航能力使其不需要执行显式转换就可以请求特定格式的数据或进行伸缩。


改善性能

首先快速回顾一下现有的资源。我们是从 maemo 站点的示例摄像机应用程序开始讨论的(参考资料)。此程序可以开箱即用,尽管其速度较慢。基本设计思想是,从 video4linux 源开始,将其过滤为 RGB,然后将它的一个副本发送到屏幕,另一个发送到可以临时保存 JPEG 文件的图像接收器。

实际上,颜色空间转换将占用大量资源,并且如果不需要保存实际的 JPEG 文件,没有必要进行转换。标准 xvimagesink 元素显示用摄像机的 YUV 格式编码的帧。

需要更改的第一步是将 colorspace 过滤器移动到进行 JPEG 转换的路径中。原始代码将过滤器的输出提供给一个 tee 元素,然后传送到一个图像接收器(用来在需要时保存 JPEG 文件)和屏幕上。这需要对每帧图像都进行转换。

对于 tee 元素,colorspace 过滤器将一直运行所有帧,但是现在这一情况可能被改变。gstreamer 库包含一些 探测器(probe) 函数,可用来修改元素的行为。对到达给定 pad 的帧调用探测器函数。如果探测器函数返回 TRUE,该帧被传递给流,如果返回 FALSE,该帧将被丢弃。只要用户按下按钮,示例代码注册特定的 save as JPEG 探测器函数。探测器函数然后保存帧并注销自身的注册。

但是,还有另一个选择:注册一个探测器(通常返回 FALSE)并在颜色空间转换之前连接它。然后,可以设置为如果用户单击 “take photo” 按钮,探测器就返回 TRUE。这意味着在其余时间里,colorspace 过滤器处理的流中没有数据。

现在,对管道设置的更改就再简单不过了:只需一次调用,将探测器添加到 tee 过滤器的一个输出 pad 中。探测器又叫做缓冲区探测器 — 它只在实际的数据块上被调用,比如视频帧。不会影响到无关的信息。

下面是用于添加回调的代码:


清单 2. 探测数据流
                
pad = gst_element_get_static_pad(queue, "src");
if (pad) {
gst_pad_add_buffer_probe(pad, G_CALLBACK(only_when_saving), appdata);
} else {
fprintf(stderr, "couldn't get sink.\n");
}

only_when_saving 函数是一个标准的探测器回调。在我们的例子中,它非常简单,因为它只需检查一个布尔值。


清单 3. 保留还是丢弃帧?
                
/* This callback indicates whether or not we want a picture */
static gboolean only_when_saving(
GstElement *element,
GstBuffer *buffer, AppData *appdata)
{
if (appdata->save_next_frame) {
appdata->save_next_frame = FALSE;
return TRUE;
} else {
return FALSE;
}
}

如果设置了 save_next_frame 值,此函数清除该值并返回 TRUE,从而通过其余管道传送此帧。否则,此函数返回 FALSE,从而丢弃此帧。

这应该能显著改善性能,但是在我的系统中性能仍不太好。最初的例子为流使用队列对象。从屏幕流删除队列对象可以消除对性能 的影响,但保存图像时例外。通过确保 JPEG 转换在与主显示器独立的线程中进行,其他流中的队列能够显著提升可感知的性能。这也允许从 save-as-JPEG 探测器删除更复杂的注册/注销代码、按钮 press callback,通过简单地编写 save_next_frame 布尔值来取代它们(对于此实现,不用担心竞态条件)。


保存 JPEG 文件

我最初使用 gstreamer 的 jpegenc 插件。从插件元素的名称就可以知道它的用途:将图像帧转换为 JPEG。不幸的是,它没有包含在 N800 的基本版本中。更糟的是,本应该在 gstreamer 的 plugins-good 版本中的包被分为多个部分发布。

可以使用一种简单的手动方法进行测试;下载 scratchbox 上的插件,配置并运行,将该插件的共享库复制到 N800。还有许多工作要做。example_camera 程序附带了 gdk_pixbuf;非常容易安装(已经安装上了)。

然而,gdk_pixbuf 似乎有点大材小用,而且我一直喜欢标准 libjpeg 库,该库也包含在 N800 中。附带这个库有一个很重要的原因,将在下一篇文章中说明。现在,我将演示用 libjpeg 来压缩文件的简单代码:


清单 4. 创建 JPEG 文件
                
/* Creates a jpeg file from the buffer's raw image data */
static gboolean create_jpeg(unsigned char *data)
{
FILE *out;
struct jpeg_compress_struct comp;
struct jpeg_error_mgr error;

out = fopen("test.jpg", "wb");

comp.err = jpeg_std_error(&error);
jpeg_create_compress(&comp);
jpeg_stdio_dest(&comp, out);
comp.image_width = 640;
comp.image_height = 480;
comp.input_components = 3;
comp.in_color_space = JCS_RGB;
jpeg_set_defaults(&comp);
jpeg_set_quality(&comp, 90, TRUE);
jpeg_start_compress(&comp, TRUE);
for (int i = 0; i < 480; ++i) {
jpeg_write_scanlines(&comp, &data, 1);
data += (640 * 3);
}
jpeg_finish_compress(&comp);
fflush(out);
fclose(out);
jpeg_destroy_compress(&comp);

return TRUE;
}

我们的文件保存为 test.jpg。


下一步

现在摄像机应用程序能够正常工作了 — 捕捉单个视频帧并将其转换为流行的格式 — 下一步是将其和系统的其他部分结合并上传这些文件。在 N800 系列的第 3 期(最后一期)将讨论如何操作。


参考资料

学习

获得产品和技术

  • GStreamer 是一个库,允许构造媒体处理组件图,包括简单 Ogg/Vorbis 回放和复杂音频(混合)和视频(非线性编辑)处理。

  • 订购 SEK for Linux,共包含两张 DVD,其中有用于 Linux 的最新 IBM 试用软件,包括 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere®。

  • 使用 IBM 试用软件 构建您的下一个 LInux 开发项目,这些软件可直接从 developerWorks 下载。

讨论

关于作者

Author photo

Peter Seebach 已经使用计算机很多年了,也正在逐渐适应计算机的特性。不过他仍然不清楚为什么鼠标要如此频繁地进行清洁。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多