Advertisement
swestrup

sinker.c

May 2nd, 2014
245
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.83 KB | None | 0 0
  1. //sinker.c -- test program to add and remove sinks to/from a pipeline.
  2.  
  3. #include <stdlib.h>
  4. #include <gst/gst.h>
  5.  
  6. #define DISPLAY ":0"
  7.  
  8. // Returns the short name for an enum's value, or NULL if not found.
  9. static gchar const * enum_nick
  10. ( GType enum_id
  11. , gint value
  12. )
  13. { GEnumClass * gec = G_ENUM_CLASS(g_type_class_ref(enum_id));
  14. GEnumValue * val = gec->values;
  15. gchar const * ret = NULL;
  16. gint i;
  17.  
  18. for(i=0; i < gec->n_values; i++)
  19. if( val[i].value == value )
  20. {
  21. ret = val[i].value_nick;
  22. break;
  23. }
  24. g_type_class_unref(gec);
  25. return ret;
  26. }
  27.  
  28. #define STREAM_STATUS_TYPE_NAME(ss) (enum_nick(GST_TYPE_STREAM_STATUS_TYPE,ss))
  29.  
  30. static gboolean bus_callback
  31. ( GstBus * bus
  32. , GstMessage * msg
  33. , gpointer data
  34. )
  35. { GMainLoop * loop = data;
  36. gboolean quit = FALSE; // do we need to quit the program?
  37. gchar const * src = GST_MESSAGE_SRC_NAME(msg);
  38. gchar * bug = NULL;
  39. GError * err = NULL;
  40.  
  41. switch( GST_MESSAGE_TYPE(msg) )
  42. {
  43. case GST_MESSAGE_EOS:
  44. GST_LOG("End of stream");
  45. quit = TRUE;
  46. break;
  47.  
  48. #if 0
  49. case GST_MESSAGE_STATE_CHANGED:
  50. { GstState old;
  51. GstState new;
  52. GstState pending;
  53.  
  54. gst_message_parse_state_changed(msg,&old,&new,&pending);
  55.  
  56. if( pending != GST_STATE_VOID_PENDING )
  57. g_print
  58. ( "State Change: %-8s: %-8s -> %-8s -> %s\n"
  59. , GST_MESSAGE_SRC_NAME(msg)
  60. , gst_element_state_get_name(old)
  61. , gst_element_state_get_name(new)
  62. , gst_element_state_get_name(pending)
  63. );
  64. else
  65. g_print
  66. ( "State Change: %-8s: %-8s -> %-8s\n"
  67. , GST_MESSAGE_SRC_NAME(msg)
  68. , gst_element_state_get_name(old)
  69. , gst_element_state_get_name(new)
  70. );
  71. break;
  72. }
  73.  
  74. case GST_MESSAGE_STREAM_STATUS:
  75. { GstStreamStatusType sstype;
  76. GstElement * owner;
  77.  
  78. gst_message_parse_stream_status(msg,&sstype,&owner);
  79. g_print
  80. ( "Stream Status: %s : %s\n"
  81. , GST_ELEMENT_NAME(owner)
  82. , STREAM_STATUS_TYPE_NAME(sstype)
  83. );
  84. break;
  85. }
  86. #endif
  87.  
  88. case GST_MESSAGE_CLOCK_LOST:
  89. g_print("Clock Lost!\n");
  90. break;
  91.  
  92. case GST_MESSAGE_NEW_CLOCK:
  93. g_printf("New Clock Chosen!\n");
  94. break;
  95.  
  96. case GST_MESSAGE_ERROR:
  97. gst_message_parse_error(msg,&err,&bug);
  98. GST_ERROR
  99. ( "Error %d.%d: %s (%s)\n"
  100. , err->domain, err->code
  101. , err->message, bug
  102. );
  103. g_error_free(err);
  104. g_free(msg);
  105. quit = TRUE;
  106. break;
  107.  
  108. case GST_MESSAGE_WARNING:
  109. gst_message_parse_warning(msg,&err,&bug);
  110. GST_WARNING("Warning: %s: %s (%s)",src,err->message,bug);
  111. g_error_free(err);
  112. g_free(bug);
  113. break;
  114.  
  115. case GST_MESSAGE_INFO:
  116. gst_message_parse_info(msg,&err,&bug);
  117. GST_INFO("Info: %s: %s (%s)",src, err->message,bug);
  118. g_print("Info: %s: %s\n",src, err->message);
  119. g_error_free(err);
  120. g_free(bug);
  121. break;
  122.  
  123. default:
  124. break;
  125. }
  126. if( quit )
  127. g_main_loop_quit(loop);
  128. return TRUE;
  129. }
  130.  
  131. typedef struct CBData
  132. { GMainLoop * loop; // Loop context
  133. GstBin * pipeline; // Our pipeline
  134. GstElement * tee; // Tee junction in pipeline
  135. GstElement * out; // Output pipeline
  136. GstElement * sink; // Sink at end of output pipeline.
  137. guint count; // Number of add/remove cycles to do
  138. GMutex mutex;
  139. GCond cond;
  140. }
  141. CBData;
  142.  
  143. static GstPadProbeReturn pad_wait_and_destruct_callback
  144. ( GstPad * pad
  145. , GstPadProbeInfo * info
  146. , gpointer data
  147. )
  148. { CBData * cb = data;
  149.  
  150. g_print("Destruct wakes..\n");
  151.  
  152. if(GST_EVENT_TYPE(GST_PAD_PROBE_INFO_DATA(info)) != GST_EVENT_FLUSH_START)
  153. return GST_PAD_PROBE_OK;
  154.  
  155. g_print("Destruction Probe Activated.\n");
  156. gst_pad_remove_probe(pad,GST_PAD_PROBE_INFO_ID(info));
  157.  
  158. gst_element_set_state(cb->out,GST_STATE_NULL);
  159.  
  160. // NOTE: gst_bin_remove unparents the stream, which counts as an
  161. // unref. This is sufficient to free the stream.
  162. gst_bin_remove(cb->pipeline,cb->out);
  163.  
  164. // announce we did it.
  165. g_print("Signaling sink removal\n");
  166. cb->sink = NULL;
  167. cb->out = NULL;
  168. g_cond_signal(&cb->cond);
  169. return GST_PAD_PROBE_OK;
  170. }
  171.  
  172. static GstPadProbeReturn pad_block_and_sever_callback
  173. ( GstPad * pad // source pad of tee element
  174. , GstPadProbeInfo * info
  175. , gpointer data
  176. )
  177. { CBData * cb = data;
  178. GstPad * sinkpad = gst_pad_get_peer(pad);
  179. GstElement * parent = gst_pad_get_parent_element(pad);
  180.  
  181. g_print("Block probe activated\n");
  182.  
  183. // We're a one-shot, so remove us from this pad.
  184. gst_pad_remove_probe(pad, GST_PAD_PROBE_INFO_ID(info));
  185.  
  186. // Unlink the sink from our pad.
  187. gst_pad_unlink(pad,sinkpad);
  188.  
  189. // Ask our parent (TEE element) to remove this request pad
  190. gst_element_release_request_pad(parent,pad);
  191.  
  192. // Note: This is slightly futile in that we are setting a probe
  193. // on a sink pad and then immediately triggering it, because in
  194. // this case 'sinksink' and 'sinkpad' are the same pads, but in the
  195. // case of a longer output pipeline than a single element, this
  196. // becomes a useful operation.
  197.  
  198. GstPad * sinksink = gst_element_get_static_pad(cb->sink,"sink");
  199.  
  200. g_print("Adding destruction probe\n");
  201. gst_pad_add_probe
  202. ( sinksink
  203. , GST_PAD_PROBE_TYPE_EVENT_FLUSH
  204. , pad_wait_and_destruct_callback
  205. , cb
  206. , NULL
  207. );
  208.  
  209. g_print("Activating destruction probe\n");
  210. gst_pad_send_event(sinkpad,gst_event_new_flush_start());
  211.  
  212. // And now we don't need these various references any more...
  213. gst_object_unref(sinksink);
  214. gst_object_unref(sinkpad);
  215. gst_object_unref(parent);
  216. return GST_PAD_PROBE_OK;
  217. }
  218.  
  219. static void pipeline_remove_output
  220. ( CBData * cb
  221. )
  222. {
  223. g_mutex_lock( &cb->mutex );
  224.  
  225. GstPad * sinkpad = gst_element_get_static_pad(cb->out,"sink");
  226. GstPad * srcpad = gst_pad_get_peer(sinkpad);
  227.  
  228. g_print("Adding Block Probe.\n");
  229. gst_pad_add_probe
  230. ( srcpad
  231. , GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM
  232. , pad_block_and_sever_callback
  233. , cb
  234. , NULL
  235. );
  236.  
  237. g_print("Waiting for removal done signal\n");
  238. while( cb->out )
  239. g_cond_wait(&cb->cond,&cb->mutex);
  240. g_print("Received removal done signal\n");
  241.  
  242. g_mutex_unlock( &cb->mutex );
  243. }
  244.  
  245. static void pipeline_add_output
  246. ( CBData * cb
  247. )
  248. {
  249. g_mutex_lock( &cb->mutex );
  250. GstElement * bin = gst_bin_new("outbin");
  251. GstElement * queue = gst_element_factory_make("queue", "outqueue");
  252. GstElement * sink = gst_element_factory_make("xvimagesink", "xsink" );
  253.  
  254. g_object_set(sink,"display",DISPLAY,NULL);
  255.  
  256. gst_bin_add_many(GST_BIN(bin),queue,sink,NULL);
  257. gst_element_link(queue,sink);
  258.  
  259. GstPad *qsink = gst_element_get_static_pad(queue,"sink");
  260. GstPad *gsink = gst_ghost_pad_new("sink",qsink);
  261.  
  262. gst_pad_set_active(gsink,TRUE);
  263. gst_element_add_pad(bin,gsink);
  264. gst_object_unref(qsink);
  265.  
  266. gst_bin_add(cb->pipeline,bin);
  267. if( !gst_element_link(cb->tee,bin) )
  268. { g_print("Failed to link new bin.\n"); exit(-1); }
  269.  
  270. gst_element_sync_state_with_parent(bin);
  271.  
  272. cb->out = bin;
  273. cb->sink = sink;
  274.  
  275. g_mutex_unlock(&cb->mutex);
  276. }
  277.  
  278. static gboolean timed_callback
  279. ( gpointer data
  280. )
  281. { CBData * cb = data;
  282.  
  283. if( cb->count == 0 )
  284. {
  285. g_main_loop_quit(cb->loop);
  286. return FALSE;
  287. }
  288. cb->count--;
  289. if( cb->out )
  290. {
  291. g_print("Removing Output.\n");
  292. pipeline_remove_output(cb);
  293. g_print("Output Removed.\n");
  294. }
  295. else
  296. {
  297. g_print("Adding Output.\n");
  298. pipeline_add_output(cb);
  299. g_print("Output Added.\n");
  300. }
  301. return TRUE;
  302. };
  303.  
  304.  
  305. gint main
  306. ( gint argc
  307. , gchar * argv[]
  308. )
  309. {
  310. /* init GStreamer */
  311. gst_init(&argc, &argv);
  312.  
  313. GMainLoop * loop = g_main_loop_new(NULL, FALSE);
  314.  
  315. /* create a new pipeline to hold the elements */
  316. GstElement * pipeline = gst_pipeline_new("pipe");
  317. GstBus * bus = gst_pipeline_get_bus( GST_PIPELINE(pipeline) );
  318.  
  319. gst_bus_add_watch(bus, bus_callback, loop);
  320. gst_object_unref(bus);
  321.  
  322. /* create basic pipeline elments */
  323. GstElement * vidsrc = gst_element_factory_make("videotestsrc", "source");
  324. GstElement * tee = gst_element_factory_make("tee", "tee" );
  325. GstElement * queue = gst_element_factory_make("queue", "fqueue");
  326. GstElement * fakesink = gst_element_factory_make("fakesink", "fake" );
  327.  
  328. /* initial setup */
  329. gst_bin_add_many(GST_BIN(pipeline), vidsrc, tee, queue, fakesink, NULL);
  330. gst_element_link_many(vidsrc, tee, fakesink, NULL);
  331.  
  332. GstStateChangeReturn sts = gst_element_set_state
  333. ( pipeline
  334. , GST_STATE_PLAYING
  335. );
  336.  
  337. if( sts == GST_STATE_CHANGE_FAILURE )
  338. {
  339. GST_ERROR("Pipeline could not start playing");
  340. exit(-1);
  341. }
  342. else if( sts == GST_STATE_CHANGE_ASYNC )
  343. {
  344. g_print("Waiting for pipeline to change state.\n");
  345. sts = gst_element_get_state(pipeline, NULL, NULL, 5*GST_SECOND);
  346. if( sts == GST_STATE_CHANGE_FAILURE )
  347. {
  348. GST_ERROR("Pipeline Asynchronously failed");
  349. g_print("Pipeline failure!\n");
  350. exit(-1);
  351. }
  352. }
  353. g_print("Pipeline in Run State.\n");
  354.  
  355. CBData cb = {loop, GST_BIN(pipeline), tee, NULL, NULL, 1, FALSE, 0, 0};
  356.  
  357. g_mutex_init(&cb.mutex);
  358. g_cond_init(&cb.cond);
  359.  
  360. g_timeout_add_seconds(2, timed_callback, &cb);
  361.  
  362. g_print("Starting Run Loop\n");
  363. g_main_loop_run(loop);
  364. g_print("Exiting Run Loop\n");
  365.  
  366. /* unset */
  367. gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL);
  368. gst_object_unref(GST_OBJECT(pipeline));
  369. g_cond_clear(&cb.cond);
  370. g_mutex_clear(&cb.mutex);
  371. return 0;
  372. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement