使用eclipse 调试gstreamer 框架
在学习新框架的时候我比较喜欢找一个Sample,然后搭建一套debug环境,自己用调试器跟进去,看看框架是如何工作的,所以我将如何搭建debug环境放在了第一篇,包括:使用eclipse编译和调试Gstreamer应用程序。
准备工作:
1, 安装Eclipse CDT,我装的是GALIEO版本;
2, 编译和安装debug版本的Gstreamer和Glib库,假设你编译的debug版本库安装在
/home/XXX/project/gstreamer/0.10.36/目录下。
一,使用Eclipse编译和调试Gstreamer应用程序;
1, 新建一个C工程,例如:gstsample,如下图所示,
2, 将gstsample.c文件添加到该工程中,
3, 按如下方式添加头文件路径,
右键单击gstsample项目,选择"Properties"标签;
在弹出窗口中选择"C/C++ Build"--->"Settings", 再选择"GCC C Compiler"菜单下的
"Directories"选项,然后点击右侧的"+"按钮,如下图所示,
在"Add directory path"窗口中单击"file system"按钮添加自己需要的头文件即可。
主要需要添加以下几个目录:
/home/XXX/project/gstreamer/0.10.36/include/gstreamer-0.10
/home/XXX/project/gstreamer/0.10.36/include/glib-2.0
/home/XXX/project/gstreamer/0.10.36/lib/glib-2.0/include
/usr/include/libxml2/ (如果没有该文件,sudo apt-get install libxml2-dev就有了)
/home/XXX/project/gstreamer/0.10.36目录是你自己安装的gstreamer库的目录。
此时如果Build Project 会提示类似于下面的错误,
Invoking: GCC C Linker
gcc -o"gstsample" ./Function_Testes.o
./Function_Testes.o: In function `gst_message_unref':
/home/XXX/project/gstreamer/0.10.36/include/gstreamer-0.10/gst/gstmessage.h:347:
undefined reference to `gst_mini_object_unref'
一看错误就知道编译过了,连接器找不到符号,添加lib库目录就好了。
4, 添加lib库目录
步骤跟3类似,需要添加依赖的动态库的名称和目录,我们至少需要添加gstreamer0.10和glib-2.0这两个动态库,在后续的的开发中,你可能还有添加其他的依赖库。如下图所示,
注: 给eclipse添加动态库名称,只要除头除尾即可,例如:libgstreamer-0.10.so,eclipse对应的动态库名称是:gstreamer-0.10。
5, 开始运行
如果上述步骤都做完了,并且gstreamer库正确的安装了,只需要添加命令行参数即可,因为这个例子是从gst-laucn精简得到的,因此提供跟gst-launch一样的命令行参数就好了。单击主菜单的"run"按钮,选择run configurerations菜单,如下图所示,
其中左侧的 "C/C++Application"列出了当前workspace中所有的可执行程序,我们选择gst-sample,在右侧的Arguments标签中填入类似于gst-launch的命令的命令行参数即可。
至此使用eclipse编译和运行gstreamer应用程序全部讲完,下面将如何配置debug菜单
6,为了方便跟踪gstreamer core以及plugin的内部运行流程,需要再新建一个C project,如:0.10.36,在该project中添加gstreamer 动态库的source code,目的是方便下断点,看code,以及建立索引,这个Project不需要编译和运行,我通过link的方式将source code添加进工程,步骤如下:
右键单击0.10.36 project, 选择"Properties"标签;
在弹出窗口中选择"C/C++ General"--->"Paths and Symbols", 单击"Source Location"标签;如下图所示,
单击"link folder"按钮,在"new folder"对话框中,选中"Link to floder in the file system",单击"Browse..."按钮,添加gstreamr source code 路径即可。如下图所示,
7,添加Project references
右键单击0.10.36 project, 选择"Properties"
标签;
在弹出窗口中选择"Project References"标签,在右侧的复选框中沟中"gstsample"项目,如下图所示,这样这两个项目就关联起来了,gstsample 项目就可以找到各种gstreamer库函数的定义。
8, 开始调试
在项目0.10.36中打开文件gst.c在函数gst_init 入口处打一个断点,单击gstsample 项目,然后按F11启动调试,按F8运行到下一个断点,这个时候应该停在gst_init函数中,如下入所示:
注意事项:
1,一般来说按照上面的步骤就可以搭建好debug环境,为了验证自己搭建的环境是否OK,一定要找一个100%能执行到的gstreamer库函数做试验,之前我的同事就出现断点无法起作用,查了半天发现那段code根本执行不到。
2,如果出现断点起作用,但是单步跟踪的时候不是按序执行,那估计是编译的DEBUG版本库不对,另外Gstreamer 提供的 --enable-debug 的configure参数感觉有点问题,因此我都是手动加一个CFLAGS="-g",你可以在你的使用下面的脚本来编译configure你的gstreamer库。
PKG_CONFIG_PATH=/home/XXX/project/gstreamer/0.10.36/lib/pkgconfig ./configure CFLAGS="-g" --prefix=/home/XXX/project/gstreamer/0.10.36/ --enable-shared --disable-s tatic --enable-debug
3,如果发现下的断点还是无法起作用,在选择菜单"run"-->"Debug configurerations",在该对话框中配置GDB,这个配置非常简单,自己尝试一下。
4, 因为无法上传附件,我只好将source code全部贴出来了,这个code跟gst-launch命令的功能是一样的,大家可以基于这个进行学习和测试,code是2个小时改出来的,后续有时间我会完善这份CODE,欢迎拍砖!
- /*
- * Function_Testes.c
- *
- * Created on: 2012-8-7
- * Author: caoping
- */
- #include
- #include
- #include
- #include
- #include
- #include
- /*
- * test cmd
- * check the clock mechinism
- * playbin2 uri=file:///hom/project/gstreamer/bitstream/MPEG4_V_ONLY.AVI
- * check multi-audio
- * playbin uri=file:///home/project/gstreamer/bitstream/multiaudio.divx
- *
- */
- static GstElement *pipeline;
- static GstBusSyncReply
- sync_bus_handler (GstBus * bus, GstMessage * message, GstElement * bin)
- {
- switch (GST_MESSAGE_TYPE (message))
- {
- case GST_MESSAGE_STREAM_STATUS:
- {
- GstStreamStatusType type;
- GstElement *owner;
- const GValue *val;
- gchar *path;
- GstTask *task = NULL;
- g_message ("received STREAM_STATUS");
- gst_message_parse_stream_status (message, &type, &owner);
- val = gst_message_get_stream_status_object (message);
- g_message ("type: %d", type);
- path = gst_object_get_path_string (GST_MESSAGE_SRC (message));
- g_message ("source: %s", path);
- g_free (path);
- path = gst_object_get_path_string (GST_OBJECT (owner));
- g_message ("owner: %s", path);
- g_free (path);
- g_message ("object: type %s, value %p", G_VALUE_TYPE_NAME (val),
- g_value_get_object (val));
- /* see if we know how to deal with this object */
- if (G_VALUE_TYPE (val) == GST_TYPE_TASK) {
- task = g_value_get_object (val);
- }
- switch (type) {
- case GST_STREAM_STATUS_TYPE_CREATE:
- g_message ("created task %p", task);
- break;
- case GST_STREAM_STATUS_TYPE_ENTER:
- if (task) {
- g_message ("raising task priority for %p", task);
- gst_task_set_priority (task, G_THREAD_PRIORITY_HIGH);
- }
- break;
- case GST_STREAM_STATUS_TYPE_LEAVE:
- break;
- default:
- break;
- }
- break;
- }
- default:
- break;
- }
- /* pass all messages on the async queue */
- return GST_BUS_PASS;
- }
- /* event_loop return codes */
- typedef enum _EventLoopResult
- {
- ELR_NO_ERROR = 0,
- ELR_ERROR,
- ELR_INTERRUPT
- } EventLoopResult;
- static EventLoopResult
- event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
- {
- GstBus *bus;
- GstMessage *message = NULL;
- EventLoopResult res = ELR_NO_ERROR;
- gboolean buffering = FALSE;
- bus = gst_element_get_bus (GST_ELEMENT (pipeline));
- while (TRUE)
- {
- message = gst_bus_poll (bus, GST_MESSAGE_ANY, blocking ? -1 : 0);
- /* if the poll timed out, only when !blocking */
- if (message == NULL)
- goto exit;
- /* check if we need to dump messages to the console */
- if (message)
- {
- GstObject *src_obj;
- const GstStructure *s;
- guint32 seqnum;
- seqnum = gst_message_get_seqnum (message);
- s = gst_message_get_structure (message);
- src_obj = GST_MESSAGE_SRC (message);
- if (GST_IS_ELEMENT (src_obj))
- {
- g_message ("Got message #%u from element \"%s\" (%s): ",
- (guint) seqnum, GST_ELEMENT_NAME (src_obj),
- GST_MESSAGE_TYPE_NAME (message));
- }
- else if (GST_IS_PAD (src_obj))
- {
- g_message ("Got message #%u from pad \"%s:%s\" (%s): ",
- (guint) seqnum, GST_DEBUG_PAD_NAME (src_obj),
- GST_MESSAGE_TYPE_NAME (message));
- }
- else if (GST_IS_OBJECT (src_obj))
- {
- g_message ("Got message #%u from object \"%s\" (%s): ",
- (guint) seqnum, GST_OBJECT_NAME (src_obj),
- GST_MESSAGE_TYPE_NAME (message));
- }
- else
- {
- g_message ("Got message #%u (%s): ", (guint) seqnum,
- GST_MESSAGE_TYPE_NAME (message));
- }
- if (s)
- {
- gchar *sstr;
- sstr = gst_structure_to_string (s);
- g_message ("%s\n", sstr);
- g_free (sstr);
- }
- else
- {
- g_message ("no message details\n");
- }
- }
- switch (GST_MESSAGE_TYPE (message))
- {
- case GST_MESSAGE_NEW_CLOCK:
- {
- GstClock *clock;
- gst_message_parse_new_clock (message, &clock);
- g_message ("New clock: %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
- break;
- }
- case GST_MESSAGE_CLOCK_LOST:
- g_message ("Clock lost, selecting a new one\n");
- gst_element_set_state (pipeline, GST_STATE_PAUSED);
- gst_element_set_state (pipeline, GST_STATE_PLAYING);
- break;
- case GST_MESSAGE_EOS:
- {
- g_message("got eos\n");
- goto exit;
- }
- case GST_MESSAGE_WARNING:
- {
- GError *gerror;
- gchar *debug;
- gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message));
- /* dump graph on warning */
- GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
- GST_DEBUG_GRAPH_SHOW_ALL, "gst-launch.warning");
- gst_message_parse_warning (message, &gerror, &debug);
- g_message ("WARNING: from element %s: %s\n", name, gerror->message);
- if (debug) {
- g_message ("Additional debug info:\n%s\n", debug);
- }
- g_error_free (gerror);
- g_free (debug);
- g_free (name);
- break;
- }
- case GST_MESSAGE_ERROR:{
- /* dump graph on error */
- GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
- GST_DEBUG_GRAPH_SHOW_ALL, "gst-launch.error");
- /* we have an error */
- res = ELR_ERROR;
- goto exit;
- }
- case GST_MESSAGE_STATE_CHANGED:
- {
- GstState old, new, pending;
- /* we only care about pipeline state change messages */
- if (GST_MESSAGE_SRC (message) != GST_OBJECT_CAST (pipeline))
- break;
- /* ignore when we are buffering since then we mess with the states
- * ourselves. */
- if (buffering) {
- g_message ("Prerolled, waiting for buffering to finish...\n");
- break;
- }
- gst_message_parse_state_changed (message, &old, &new, &pending);
- /* if we reached the final target state, exit */
- if (target_state == GST_STATE_PAUSED && new == target_state)
- goto exit;
- /* else not an interesting message */
- break;
- }
- case GST_MESSAGE_BUFFERING:
- {
- gint percent;
- gst_message_parse_buffering (message, &percent);
- g_message ("%d buffering...", percent);
- if (percent == 100)
- {
- /* a 100% message means buffering is done */
- buffering = FALSE;
- /* if the desired state is playing, go back */
- if (target_state == GST_STATE_PLAYING)
- {
- g_message ("Done buffering, setting pipeline to PLAYING ...\n");
- gst_element_set_state (pipeline, GST_STATE_PLAYING);
- } else
- goto exit;
- } else {
- /* buffering busy */
- if (buffering == FALSE && target_state == GST_STATE_PLAYING) {
- /* we were not buffering but PLAYING, PAUSE the pipeline. */
- g_message ("Buffering, setting pipeline to PAUSED ...\n");
- gst_element_set_state (pipeline, GST_STATE_PAUSED);
- }
- buffering = TRUE;
- }
- break;
- }
- case GST_MESSAGE_LATENCY:
- {
- g_message("Redistribute latency...\n");
- gst_bin_recalculate_latency (GST_BIN (pipeline));
- break;
- }
- case GST_MESSAGE_REQUEST_STATE:
- {
- GstState state;
- gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message));
- gst_message_parse_request_state (message, &state);
- g_message ("Setting state to %s as requested by %s...\n",
- gst_element_state_get_name (state), name);
- gst_element_set_state (pipeline, state);
- g_free (name);
- break;
- }
- case GST_MESSAGE_APPLICATION:{
- const GstStructure *s;
- s = gst_message_get_structure (message);
- if (gst_structure_has_name (s, "GstLaunchInterrupt")) {
- /* this application message is posted when we caught an interrupt and
- * we need to stop the pipeline. */
- g_message ("Interrupt: Stopping pipeline ...\n");
- res = ELR_INTERRUPT;
- goto exit;
- }
- break;
- }
- case GST_MESSAGE_ELEMENT:
- {
- }
- break;
- default:
- /* just be quiet by default */
- break;
- }
- if (message)
- gst_message_unref (message);
- }
- g_assert_not_reached ();
- exit:
- {
- if (message)
- gst_message_unref (message);
- gst_object_unref (bus);
- return res;
- }
- }
- int main(int argc, char *argv[])
- {
- GError *error = NULL;
- EventLoopResult caught_error ;
- gst_init(&argc, &argv);
- pipeline = (GstElement *) gst_parse_launchv((const gchar **) &argv[1],
- &error);
- if (!pipeline)
- {
- if (error)
- {
- g_printerr("ERROR: pipeline could not be constructed: %s.\n",
- GST_STR_NULL (error->message));
- g_error_free(error);
- }
- else
- {
- g_printerr("ERROR: pipeline could not be constructed.\n");
- }
- return 1;
- }
- else if (error)
- {
- g_printerr("WARNING: erroneous pipeline: %s\n",
- GST_STR_NULL (error->message));
- g_error_free(error);
- return 1;
- }
- GstState state, pending;
- GstStateChangeReturn ret;
- GstBus *bus;
- /* If the top-level object is not a pipeline, place it in a pipeline. */
- if (!GST_IS_PIPELINE (pipeline))
- {
- GstElement *real_pipeline = gst_element_factory_make("pipeline", NULL);
- if (real_pipeline == NULL)
- {
- g_printerr("ERROR: the 'pipeline' element wasn't found.\n");
- return 1;
- }
- gst_bin_add(GST_BIN (real_pipeline), pipeline);
- pipeline = real_pipeline;
- }
- bus = gst_element_get_bus(pipeline);
- gst_bus_set_sync_handler(bus, (GstBusSyncHandler)sync_bus_handler, (gpointer) pipeline);
- gst_object_unref(bus);
- g_message("Setting pipeline to PAUSED ...\n");
- ret = gst_element_set_state(pipeline, GST_STATE_PAUSED);
- switch (ret)
- {
- case GST_STATE_CHANGE_FAILURE:
- g_printerr("ERROR: Pipeline doesn't want to pause.\n");
- event_loop(pipeline, FALSE, GST_STATE_VOID_PENDING);
- goto end;
- case GST_STATE_CHANGE_NO_PREROLL:
- break;
- case GST_STATE_CHANGE_ASYNC:
- caught_error = event_loop(pipeline, TRUE, GST_STATE_PAUSED);
- if (caught_error)
- {
- g_printerr("ERROR: pipeline doesn't want to preroll.\n");
- goto end;
- }
- state = GST_STATE_PAUSED;
- case GST_STATE_CHANGE_SUCCESS:
- break;
- }
- caught_error = event_loop(pipeline, FALSE, GST_STATE_PLAYING);
- if (caught_error)
- {
- g_printerr("ERROR: pipeline doesn't want to preroll.\n");
- }
- else
- {
- GstClockTime tfthen, tfnow;
- GstClockTimeDiff diff;
- if (gst_element_set_state(pipeline, GST_STATE_PLAYING)
- == GST_STATE_CHANGE_FAILURE)
- {
- GstMessage *err_msg;
- GstBus *bus;
- g_printerr("ERROR: pipeline doesn't want to play.\n");
- bus = gst_element_get_bus(pipeline);
- if ((err_msg = gst_bus_poll(bus, GST_MESSAGE_ERROR, 0)))
- {
- gst_message_unref(err_msg);
- }
- gst_object_unref(bus);
- goto end;
- }
- tfthen = gst_util_get_timestamp();
- caught_error = event_loop(pipeline, TRUE, GST_STATE_PLAYING);
- if (caught_error == ELR_INTERRUPT)
- {
- gst_element_send_event(pipeline, gst_event_new_eos());
- caught_error = event_loop(pipeline, TRUE, GST_STATE_PLAYING);
- if (caught_error == ELR_NO_ERROR)
- {
- }
- else if (caught_error == ELR_ERROR)
- {
- }
- }
- tfnow = gst_util_get_timestamp();
- diff = GST_CLOCK_DIFF (tfthen, tfnow);
- }
- gst_element_set_state(pipeline, GST_STATE_PAUSED);
- if (caught_error == ELR_NO_ERROR)
- gst_element_get_state(pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
- /* iterate mainloop to process pending stuff */
- while (g_main_context_iteration(NULL, FALSE));
- gst_element_set_state(pipeline, GST_STATE_READY);
- gst_element_get_state(pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
- end:
- gst_element_set_state(pipeline, GST_STATE_NULL);
- gst_element_get_state(pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
- gst_object_unref(pipeline);
- gst_deinit();
- return 0;
- }
至此,已经成功的搭建了eclipse debug gstreamer环境,如果还有问题,欢迎留言!
阅读(8902) | 评论(0) | 转发(0) |