The Bare Minimum Code-最小化程序代码

来源:Linuxeden 作者:c-aries
  
"the bare minimum code"

    -- 摘自 file:///usr/share/doc/gstreamer0.10-doc/pwg/html/chapter-building-boiler.html
   
    "the bare minimum code",可译为"最小化程序代码",学习代码的一种技巧。

    这里指,阅读自由软件源代码,通过简化,以最快的速度,最小化代码的形式,获得自己想要的功能

下面通过一个实例,进行感性的认识:

    目标: 将摄像头的影像显示到Gtk界面的一个GtkDrawingArea中
    借鉴的GNU源代码: cheese-2.22.3 (src文件夹,共246.KB)
    为了达到目标,最小化cheese程序的源代码后,得到大小共3.5KB的可用源代码包

主要使用的简化技巧:

1. 用函数结果代替函数本身

将检测摄像头参数的函数

    cheese_webcam_detect_webcam_devices (webcam);

用其检测结果"一个字符串"进行等价替换

    webcam_input="v4l2src name=video_source device=/dev/video0 ! video/x-raw-yuv,width=640,height=480,framerate=30/1 ! identity";

2. 用面向过程思想代替面向对象思想

不使用"struct CheeseWebcamPrivate"等结构体

直接用全局变量代替结构体中的项

GtkWidget *cheese_window,*video_screen;
GstElement *pipeline,*video_display_bin,*webcam_source_bin;
GstElement *video_source;
XF86VidModeGamma normal_gamma;

3. 省略命令行的选项处理,静态地指定你的需求

cheese中的命令选项不多,所以这项技巧简化的代码量不太明显
用spcaview举例,spcaview是一个接收网络摄头像影像的程序,有width,height等命令行参数
在程序中简化过程中,你可以自己指定width,height的大小,从而省略命令行参数的处理

4. 不进行错误检测

  if ((video_scale = gst_element_factory_make ("videoscale", "video_scale")) == NULL)
  {
    cheese_webcam_set_error_element_not_found (error, "videoscale");
  }

简化为

  video_scale=gst_element_factory_make("videoscale","video_scale");

在编译,运行,调试的过程中,错误已被检查出来,所以错误检测代码可以省略
我们不是要写一个通用的软件,只是写一个适合本机的,能以最快速度了解程序结构,以最小的代码实现想要功能的程序,所以有些错误检测省略,是允许的

5. 理解程序代码后,按需求,用自己的方式,更好地更简化地表达

如在函数"cheese_webcam_create_video_display_bin (webcam);"中,使用了gstreamer插件tee。它主要用于将摄像头的影像显示到GtkDrawingArea的同时将数据流用于另存为图片或另存为ogg视频文件。

这里我们只要影像显示的功能,所以去掉tee插件,设计出一个更简单的gstreamer pipeline。

6. 简化Makefile,简化界面

自己重新编写Makefile,不使用autotool
cheese使用GtkBuilder进行界面设计,可视化程序设计,生成xml格式的界面设计文件。(可参见下面的参考资源1)
在理解好xml文件cheese.ui后,笔者在emacs里自己重写了新的ui文件。
只提取出GtkWindow,GtkVBox,GtkDrawingArea这3个Gtk+组件即能满足需求。

详见下面的代码展示

系统环境参数如下:
$ dpkg -l cheese | grep cheese
ii  cheese         2.22.3-3       A tool to take pictures and videos from your
$ cat /etc/debian_version
5.0.3
$    


编写代码,编译,运行如下:
$ ls -F
1.0/  cheese.ui  main.c  Makefile
$ make
gcc `pkg-config --cflags --libs gtk+-2.0 gstreamer-0.10 gstreamer-interfaces-0.10 gdk-x11-2.0 xxf86vm` main.c
$ ls
1.0  Makefile  a.out  cheese.ui  main.c
$ ./a.out


a.out 运行界面如下:
The Bare Minimum Code-最小化程序代码

代码列表:
$ cat Makefile
all:
    gcc `pkg-config --cflags --libs gtk+-2.0 gstreamer-0.10 gstreamer-interfaces-0.10 gdk-x11-2.0 xxf86vm` main.c

clean:
    rm -f *~ a.out
$ cat cheese.ui
<?xml version="1.0"?>
<interface>
  <object class="GtkWindow" id="cheese_window">
    <property name="visible">True</property>
    <property name="default_width">640</property>
    <property name="default_height">480</property>
    <child>
      <object class="GtkVBox" id="video_vbox">
    <property name="visible">True</property>
    <property name="spacing">6</property>
    <child>
      <object class="GtkDrawingArea" id="video_screen">
        <property name="visible">True</property>
        <property name="width_request">320</property>
        <property name="height_request">240</property>
      </object>
    </child>
      </object>
    </child>
  </object>
</interface>
$ cat main.c
#include <gtk/gtk.h>
#include <gst/gst.h>
#include <gst/interfaces/xoverlay.h>
#include <gdk/gdkx.h>
#include <X11/Xlib.h>
#include <X11/extensions/xf86vmode.h>

GtkWidget *cheese_window,*video_screen;
GstElement *pipeline,*video_display_bin,*webcam_source_bin;
GstElement *video_source;
XF86VidModeGamma normal_gamma;

static gboolean
cheese_webcam_create_video_display_bin()
{
  GError *err=NULL;
  gboolean ok;
  GstElement *video_display_queue,*video_scale,*video_sink;
  char *webcam_input;
  video_display_bin=gst_bin_new("video_display_bin");
  webcam_input="v4l2src name=video_source device=/dev/video0 ! video/x-raw-yuv,width=640,height=480,framerate=30/1 ! identity";
  webcam_source_bin=gst_parse_bin_from_description(webcam_input,TRUE,&err);
  if(webcam_source_bin==NULL){
    g_error("webcam_source_bin init error");
  }
  video_source=gst_bin_get_by_name(GST_BIN(webcam_source_bin),"video_source");
  video_display_queue=gst_element_factory_make("queue","video_display_queue");
  video_scale=gst_element_factory_make("videoscale","video_scale");
  g_object_set(video_scale,"method",1,NULL);
  video_sink=gst_element_factory_make("gconfvideosink","video_sink");
  gst_bin_add_many(GST_BIN(video_display_bin),webcam_source_bin,video_display_queue,video_scale,video_sink,NULL);
  ok=gst_element_link_many(webcam_source_bin,video_display_queue,video_scale,video_sink,NULL);
  if(!ok){
    g_error("unable to create video display bin");
  }
  return TRUE;
}

static void
cheese_webcam_set_x_overlay()
{
  GstXOverlay *overlay=GST_X_OVERLAY(gst_bin_get_by_interface(GST_BIN(pipeline),GST_TYPE_X_OVERLAY));
  gst_x_overlay_set_xwindow_id(overlay,GDK_WINDOW_XWINDOW(video_screen->window));
}

static void
window_close(GtkWidget *widget,gpointer data)
{
  gst_element_set_state(pipeline,GST_STATE_NULL);
  gst_object_unref(GST_OBJECT(pipeline));
  gtk_main_quit();
}

int main(int argc,char *argv[])
{
  GtkBuilder *builder;
  GError *error;
  g_thread_init(NULL);
  gdk_threads_init();
  gtk_init(&argc,&argv);
  gst_init(&argc,&argv);
  builder=gtk_builder_new();
  gtk_builder_add_from_file(builder,"cheese.ui",&error);
  cheese_window=GTK_WIDGET(gtk_builder_get_object(builder,"cheese_window"));
  video_screen=GTK_WIDGET(gtk_builder_get_object(builder,"video_screen"));
  g_object_unref(G_OBJECT(builder));
  g_signal_connect(cheese_window,"destroy",G_CALLBACK(window_close),NULL);
  pipeline=gst_pipeline_new("pipeline");
  cheese_webcam_create_video_display_bin();
  gst_bin_add_many(GST_BIN(pipeline),video_display_bin,NULL);
  gdk_threads_enter();
  XF86VidModeGetGamma(GDK_DISPLAY(),0,&normal_gamma);
  gdk_threads_leave();
  gst_element_set_state(pipeline,GST_STATE_PLAYING);
  cheese_webcam_set_x_overlay();
  gtk_widget_show_all(cheese_window);
  gdk_threads_enter();
  gtk_main();
  gdk_threads_leave();
  return 0;
}
$

"the bare minimum code"学习代码的方式,其实际意义在于,理清程序的结构和原理,在短时间内获得自己想要的功能。通过简化,快速获得完成项目的一个组件

还有很多阅读源代码的方法,欢迎大家一起交流经验。

GNU真的很好玩,有这么多代码可以给我们学习 : )

参考资源

1. 使用GtkBuilder设计Gtk+界面

http://www.linuxeden.com/html/develop/20091129/69290.html

时间:2009-12-27 23:05 来源:Linuxeden 作者:c-aries 原文链接

好文,顶一下
(18)
100%
文章真差,踩一下
(0)
0%
------分隔线----------------------------


把开源带在你的身边-精美linux小纪念品
无觅相关文章插件,快速提升流量