Chinaunix首页 | 论坛 | 博客
  • 博客访问: 57985
  • 博文数量: 9
  • 博客积分: 226
  • 博客等级: 二等列兵
  • 技术积分: 131
  • 用 户 组: 普通用户
  • 注册时间: 2012-08-22 22:43
文章分类

全部博文(9)

文章存档

2013年(2)

2012年(7)

我的朋友

分类: 嵌入式

2012-08-29 13:43:17

                   使用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,欢迎拍砖!


  1. /*
  2. * Function_Testes.c
  3. *
  4. * Created on: 2012-8-7
  5. * Author: caoping
  6. */

  7. #include
  8. #include
  9. #include
  10. #include
  11. #include

  12. #include

  13. /*
  14. * test cmd
  15. * check the clock mechinism
  16. * playbin2 uri=file:///hom/project/gstreamer/bitstream/MPEG4_V_ONLY.AVI
  17. * check multi-audio
  18. * playbin uri=file:///home/project/gstreamer/bitstream/multiaudio.divx
  19. *
  20. */

  21. static GstElement *pipeline;


  22. static GstBusSyncReply
  23. sync_bus_handler (GstBus * bus, GstMessage * message, GstElement * bin)
  24. {
  25. switch (GST_MESSAGE_TYPE (message))
  26. {
  27. case GST_MESSAGE_STREAM_STATUS:
  28. {
  29. GstStreamStatusType type;
  30. GstElement *owner;
  31. const GValue *val;
  32. gchar *path;
  33. GstTask *task = NULL;

  34. g_message ("received STREAM_STATUS");
  35. gst_message_parse_stream_status (message, &type, &owner);

  36. val = gst_message_get_stream_status_object (message);

  37. g_message ("type: %d", type);
  38. path = gst_object_get_path_string (GST_MESSAGE_SRC (message));
  39. g_message ("source: %s", path);
  40. g_free (path);
  41. path = gst_object_get_path_string (GST_OBJECT (owner));
  42. g_message ("owner: %s", path);
  43. g_free (path);
  44. g_message ("object: type %s, value %p", G_VALUE_TYPE_NAME (val),
  45. g_value_get_object (val));

  46. /* see if we know how to deal with this object */
  47. if (G_VALUE_TYPE (val) == GST_TYPE_TASK) {
  48. task = g_value_get_object (val);
  49. }

  50. switch (type) {
  51. case GST_STREAM_STATUS_TYPE_CREATE:
  52. g_message ("created task %p", task);
  53. break;
  54. case GST_STREAM_STATUS_TYPE_ENTER:
  55. if (task) {
  56. g_message ("raising task priority for %p", task);
  57. gst_task_set_priority (task, G_THREAD_PRIORITY_HIGH);
  58. }
  59. break;
  60. case GST_STREAM_STATUS_TYPE_LEAVE:
  61. break;
  62. default:
  63. break;
  64. }
  65. break;
  66. }
  67. default:
  68. break;
  69. }
  70. /* pass all messages on the async queue */
  71. return GST_BUS_PASS;
  72. }

  73. /* event_loop return codes */
  74. typedef enum _EventLoopResult
  75. {
  76. ELR_NO_ERROR = 0,
  77. ELR_ERROR,
  78. ELR_INTERRUPT
  79. } EventLoopResult;

  80. static EventLoopResult
  81. event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
  82. {

  83. GstBus *bus;
  84. GstMessage *message = NULL;
  85. EventLoopResult res = ELR_NO_ERROR;
  86. gboolean buffering = FALSE;

  87. bus = gst_element_get_bus (GST_ELEMENT (pipeline));



  88. while (TRUE)
  89. {
  90. message = gst_bus_poll (bus, GST_MESSAGE_ANY, blocking ? -1 : 0);

  91. /* if the poll timed out, only when !blocking */
  92. if (message == NULL)
  93. goto exit;

  94. /* check if we need to dump messages to the console */
  95. if (message)
  96. {
  97. GstObject *src_obj;
  98. const GstStructure *s;
  99. guint32 seqnum;

  100. seqnum = gst_message_get_seqnum (message);

  101. s = gst_message_get_structure (message);

  102. src_obj = GST_MESSAGE_SRC (message);

  103. if (GST_IS_ELEMENT (src_obj))
  104. {
  105. g_message ("Got message #%u from element \"%s\" (%s): ",
  106. (guint) seqnum, GST_ELEMENT_NAME (src_obj),
  107. GST_MESSAGE_TYPE_NAME (message));
  108. }
  109. else if (GST_IS_PAD (src_obj))
  110. {
  111. g_message ("Got message #%u from pad \"%s:%s\" (%s): ",
  112. (guint) seqnum, GST_DEBUG_PAD_NAME (src_obj),
  113. GST_MESSAGE_TYPE_NAME (message));
  114. }
  115. else if (GST_IS_OBJECT (src_obj))
  116. {
  117. g_message ("Got message #%u from object \"%s\" (%s): ",
  118. (guint) seqnum, GST_OBJECT_NAME (src_obj),
  119. GST_MESSAGE_TYPE_NAME (message));
  120. }
  121. else
  122. {
  123. g_message ("Got message #%u (%s): ", (guint) seqnum,
  124. GST_MESSAGE_TYPE_NAME (message));
  125. }

  126. if (s)
  127. {
  128. gchar *sstr;

  129. sstr = gst_structure_to_string (s);
  130. g_message ("%s\n", sstr);
  131. g_free (sstr);
  132. }
  133. else
  134. {
  135. g_message ("no message details\n");
  136. }
  137. }

  138. switch (GST_MESSAGE_TYPE (message))
  139. {
  140. case GST_MESSAGE_NEW_CLOCK:
  141. {
  142. GstClock *clock;

  143. gst_message_parse_new_clock (message, &clock);

  144. g_message ("New clock: %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
  145. break;
  146. }
  147. case GST_MESSAGE_CLOCK_LOST:
  148. g_message ("Clock lost, selecting a new one\n");
  149. gst_element_set_state (pipeline, GST_STATE_PAUSED);
  150. gst_element_set_state (pipeline, GST_STATE_PLAYING);
  151. break;
  152. case GST_MESSAGE_EOS:
  153. {
  154. g_message("got eos\n");
  155. goto exit;
  156. }
  157. case GST_MESSAGE_WARNING:
  158. {
  159. GError *gerror;
  160. gchar *debug;
  161. gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message));

  162. /* dump graph on warning */
  163. GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
  164. GST_DEBUG_GRAPH_SHOW_ALL, "gst-launch.warning");

  165. gst_message_parse_warning (message, &gerror, &debug);
  166. g_message ("WARNING: from element %s: %s\n", name, gerror->message);
  167. if (debug) {
  168. g_message ("Additional debug info:\n%s\n", debug);
  169. }
  170. g_error_free (gerror);
  171. g_free (debug);
  172. g_free (name);
  173. break;
  174. }
  175. case GST_MESSAGE_ERROR:{
  176. /* dump graph on error */
  177. GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
  178. GST_DEBUG_GRAPH_SHOW_ALL, "gst-launch.error");

  179. /* we have an error */
  180. res = ELR_ERROR;
  181. goto exit;
  182. }
  183. case GST_MESSAGE_STATE_CHANGED:
  184. {
  185. GstState old, new, pending;

  186. /* we only care about pipeline state change messages */
  187. if (GST_MESSAGE_SRC (message) != GST_OBJECT_CAST (pipeline))
  188. break;

  189. /* ignore when we are buffering since then we mess with the states
  190. * ourselves. */
  191. if (buffering) {
  192. g_message ("Prerolled, waiting for buffering to finish...\n");
  193. break;
  194. }

  195. gst_message_parse_state_changed (message, &old, &new, &pending);

  196. /* if we reached the final target state, exit */
  197. if (target_state == GST_STATE_PAUSED && new == target_state)
  198. goto exit;

  199. /* else not an interesting message */
  200. break;
  201. }
  202. case GST_MESSAGE_BUFFERING:
  203. {
  204. gint percent;

  205. gst_message_parse_buffering (message, &percent);
  206. g_message ("%d buffering...", percent);

  207. if (percent == 100)
  208. {
  209. /* a 100% message means buffering is done */
  210. buffering = FALSE;
  211. /* if the desired state is playing, go back */
  212. if (target_state == GST_STATE_PLAYING)
  213. {
  214. g_message ("Done buffering, setting pipeline to PLAYING ...\n");
  215. gst_element_set_state (pipeline, GST_STATE_PLAYING);
  216. } else
  217. goto exit;
  218. } else {
  219. /* buffering busy */
  220. if (buffering == FALSE && target_state == GST_STATE_PLAYING) {
  221. /* we were not buffering but PLAYING, PAUSE the pipeline. */
  222. g_message ("Buffering, setting pipeline to PAUSED ...\n");
  223. gst_element_set_state (pipeline, GST_STATE_PAUSED);
  224. }
  225. buffering = TRUE;
  226. }
  227. break;
  228. }
  229. case GST_MESSAGE_LATENCY:
  230. {
  231. g_message("Redistribute latency...\n");
  232. gst_bin_recalculate_latency (GST_BIN (pipeline));
  233. break;
  234. }
  235. case GST_MESSAGE_REQUEST_STATE:
  236. {
  237. GstState state;
  238. gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message));

  239. gst_message_parse_request_state (message, &state);

  240. g_message ("Setting state to %s as requested by %s...\n",
  241. gst_element_state_get_name (state), name);

  242. gst_element_set_state (pipeline, state);

  243. g_free (name);
  244. break;
  245. }
  246. case GST_MESSAGE_APPLICATION:{
  247. const GstStructure *s;

  248. s = gst_message_get_structure (message);

  249. if (gst_structure_has_name (s, "GstLaunchInterrupt")) {
  250. /* this application message is posted when we caught an interrupt and
  251. * we need to stop the pipeline. */
  252. g_message ("Interrupt: Stopping pipeline ...\n");
  253. res = ELR_INTERRUPT;
  254. goto exit;
  255. }
  256. break;
  257. }
  258. case GST_MESSAGE_ELEMENT:
  259. {

  260. }
  261. break;
  262. default:
  263. /* just be quiet by default */
  264. break;
  265. }
  266. if (message)
  267. gst_message_unref (message);
  268. }
  269. g_assert_not_reached ();

  270. exit:
  271. {
  272. if (message)
  273. gst_message_unref (message);
  274. gst_object_unref (bus);
  275. return res;
  276. }
  277. }

  278. int main(int argc, char *argv[])
  279. {
  280. GError *error = NULL;
  281. EventLoopResult caught_error ;

  282. gst_init(&argc, &argv);

  283. pipeline = (GstElement *) gst_parse_launchv((const gchar **) &argv[1],
  284. &error);

  285. if (!pipeline)
  286. {
  287. if (error)
  288. {
  289. g_printerr("ERROR: pipeline could not be constructed: %s.\n",
  290. GST_STR_NULL (error->message));
  291. g_error_free(error);
  292. }
  293. else
  294. {
  295. g_printerr("ERROR: pipeline could not be constructed.\n");
  296. }

  297. return 1;
  298. }
  299. else if (error)
  300. {
  301. g_printerr("WARNING: erroneous pipeline: %s\n",
  302. GST_STR_NULL (error->message));
  303. g_error_free(error);
  304. return 1;
  305. }

  306. GstState state, pending;
  307. GstStateChangeReturn ret;
  308. GstBus *bus;


  309. /* If the top-level object is not a pipeline, place it in a pipeline. */
  310. if (!GST_IS_PIPELINE (pipeline))
  311. {
  312. GstElement *real_pipeline = gst_element_factory_make("pipeline", NULL);

  313. if (real_pipeline == NULL)
  314. {
  315. g_printerr("ERROR: the 'pipeline' element wasn't found.\n");
  316. return 1;
  317. }
  318. gst_bin_add(GST_BIN (real_pipeline), pipeline);
  319. pipeline = real_pipeline;
  320. }

  321. bus = gst_element_get_bus(pipeline);
  322. gst_bus_set_sync_handler(bus, (GstBusSyncHandler)sync_bus_handler, (gpointer) pipeline);
  323. gst_object_unref(bus);

  324. g_message("Setting pipeline to PAUSED ...\n");
  325. ret = gst_element_set_state(pipeline, GST_STATE_PAUSED);

  326. switch (ret)
  327. {
  328. case GST_STATE_CHANGE_FAILURE:
  329. g_printerr("ERROR: Pipeline doesn't want to pause.\n");
  330. event_loop(pipeline, FALSE, GST_STATE_VOID_PENDING);
  331. goto end;
  332. case GST_STATE_CHANGE_NO_PREROLL:
  333. break;
  334. case GST_STATE_CHANGE_ASYNC:
  335. caught_error = event_loop(pipeline, TRUE, GST_STATE_PAUSED);
  336. if (caught_error)
  337. {
  338. g_printerr("ERROR: pipeline doesn't want to preroll.\n");
  339. goto end;
  340. }
  341. state = GST_STATE_PAUSED;
  342. case GST_STATE_CHANGE_SUCCESS:
  343. break;
  344. }

  345. caught_error = event_loop(pipeline, FALSE, GST_STATE_PLAYING);

  346. if (caught_error)
  347. {
  348. g_printerr("ERROR: pipeline doesn't want to preroll.\n");
  349. }
  350. else
  351. {
  352. GstClockTime tfthen, tfnow;
  353. GstClockTimeDiff diff;

  354. if (gst_element_set_state(pipeline, GST_STATE_PLAYING)
  355. == GST_STATE_CHANGE_FAILURE)
  356. {
  357. GstMessage *err_msg;
  358. GstBus *bus;

  359. g_printerr("ERROR: pipeline doesn't want to play.\n");
  360. bus = gst_element_get_bus(pipeline);
  361. if ((err_msg = gst_bus_poll(bus, GST_MESSAGE_ERROR, 0)))
  362. {
  363. gst_message_unref(err_msg);
  364. }
  365. gst_object_unref(bus);
  366. goto end;
  367. }

  368. tfthen = gst_util_get_timestamp();
  369. caught_error = event_loop(pipeline, TRUE, GST_STATE_PLAYING);
  370. if (caught_error == ELR_INTERRUPT)
  371. {
  372. gst_element_send_event(pipeline, gst_event_new_eos());
  373. caught_error = event_loop(pipeline, TRUE, GST_STATE_PLAYING);

  374. if (caught_error == ELR_NO_ERROR)
  375. {

  376. }
  377. else if (caught_error == ELR_ERROR)
  378. {

  379. }
  380. }
  381. tfnow = gst_util_get_timestamp();

  382. diff = GST_CLOCK_DIFF (tfthen, tfnow);

  383. }


  384. gst_element_set_state(pipeline, GST_STATE_PAUSED);
  385. if (caught_error == ELR_NO_ERROR)
  386. gst_element_get_state(pipeline, &state, &pending, GST_CLOCK_TIME_NONE);

  387. /* iterate mainloop to process pending stuff */
  388. while (g_main_context_iteration(NULL, FALSE));

  389. gst_element_set_state(pipeline, GST_STATE_READY);
  390. gst_element_get_state(pipeline, &state, &pending, GST_CLOCK_TIME_NONE);

  391. end:
  392. gst_element_set_state(pipeline, GST_STATE_NULL);
  393. gst_element_get_state(pipeline, &state, &pending, GST_CLOCK_TIME_NONE);


  394. gst_object_unref(pipeline);

  395. gst_deinit();

  396. return 0;
  397. }


至此,已经成功的搭建了eclipse debug gstreamer环境,如果还有问题,欢迎留言!


   
   
阅读(8902) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~