{"id":115,"date":"2010-12-01T12:10:13","date_gmt":"2010-12-01T10:10:13","guid":{"rendered":"http:\/\/blogs.igalia.com\/xrcalvar\/?p=115"},"modified":"2012-04-29T02:22:13","modified_gmt":"2012-04-29T00:22:13","slug":"being-taken-to-azkaban-for-use-of-very-dark-gstreamer-magic","status":"publish","type":"post","link":"https:\/\/blogs.igalia.com\/xrcalvar\/2010\/12\/01\/being-taken-to-azkaban-for-use-of-very-dark-gstreamer-magic\/","title":{"rendered":"Being taken to Azkaban for use of very dark GStreamer magic"},"content":{"rendered":"<p>I was writing some tests for a project at <a href=\"http:\/\/www.igalia.com\">Igalia<\/a> and I need to mock the <i>convert-frame<\/i> <i>playbin2 element action<\/i>. The code to invoke it is something like this:<\/p>\n<pre>\r\nGstElement *pipeline = \/* get pipeline *\/;\r\nGstCaps *caps = \/* create caps to adapt the conversion *\/;\r\nGstBuffer *buffer = NULL;\r\ng_signal_emit_by_name (pipeline, \"convert-frame\", caps, &amp;buffer);\r\n<\/pre>\n<p><\/p>\n<p>When you are writing tests, what you want to do is testing just your code and not to depend on something external, so in this case the idea would be providing a fake implementation for that GStreamer element action.<\/p>\n<p>The way you can do this kind of things is providing the symbol in your code so that the linker when doing its job does not look any further and uses that instead of the one in the external library, so the natural solution coming to your mind would be rewriting <code>g_signal_emit_by_name<\/code>. The problem with this is that though you are not using it in your code, it is too general, so it is not a good idea.<\/p>\n<p>I thought I could replace the <i>convert-frame<\/i> action in the playbin2 class, so I wrote this code:<\/p>\n<pre>\r\ntypedef struct\r\n{\r\n  GstPipelineClass parent_class;\r\n  void (*about_to_finish) (gpointer playbin);\r\n  void (*video_changed) (gpointer playbin);\r\n  void (*audio_changed) (gpointer playbin);\r\n  void (*text_changed) (gpointer playbin);\r\n  void (*video_tags_changed) (gpointer playbin, gint stream);\r\n  void (*audio_tags_changed) (gpointer playbin, gint stream);\r\n  void (*text_tags_changed) (gpointer playbin, gint stream);\r\n  GstTagList *(*get_video_tags) (gpointer playbin, gint stream);\r\n  GstTagList *(*get_audio_tags) (gpointer playbin, gint stream);\r\n  GstTagList *(*get_text_tags) (gpointer playbin, gint stream);\r\n  GstBuffer *(*convert_frame) (gpointer playbin, GstCaps * caps);\r\n  GstPad *(*get_video_pad) (gpointer playbin, gint stream);\r\n  GstPad *(*get_audio_pad) (gpointer playbin, gint stream);\r\n  GstPad *(*get_text_pad) (gpointer playbin, gint stream);\r\n} GstPlayBinClass;\r\n\r\nstatic gpointer\r\ngst_play_bin_convert_frame (G_GNUC_UNUSED gpointer playbin,\r\n                            G_GNUC_UNUSED gpointer caps)\r\n{\r\n    GstBuffer *buffer;\r\n\r\n    \/* Create my own GstBuffer with the data I need *\/\r\n\r\n    return buffer;\r\n}\r\n\r\nvoid\r\nsimulator_gst_reset(GstElement *new_pipeline, GstBus *new_bus)\r\n{\r\n    \/* ... *\/\r\n\r\n    GstPlayBinClass *klass =\r\n        G_TYPE_INSTANCE_GET_CLASS(new_pipeline, GST_PLAY_BIN_TYPE,\r\n                                  GstPlayBinClass);\r\n    klass-&gt;convert_frame = (gpointer) gst_play_bin_convert_frame;\r\n\r\n    \/* ... *\/\r\n}\r\n<\/pre>\n<p>\nFirst I declared the GstPlayBinClass copying it from the GStreamer code. I didn&#8217;t change any parameters order, just replaced some pointers with <i>gpointer<\/i> as we don&#8217;t need them. This way you don&#8217;t break the ABI. Then you can declare your own element action code and finally you get the Class, assign the method and voil\u00e0!.<\/p>\n<p>As I said, the solution is far from being the best, but if you know a better way, drop me a comment.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I was writing some tests for a project at Igalia and I need to mock the convert-frame playbin2 element action. The code to invoke it is something like this: GstElement *pipeline = \/* get pipeline *\/; GstCaps *caps = \/* &hellip; <a href=\"https:\/\/blogs.igalia.com\/xrcalvar\/2010\/12\/01\/being-taken-to-azkaban-for-use-of-very-dark-gstreamer-magic\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":31,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,4,7,8,9,11,6],"tags":[15,17,33],"class_list":["post-115","post","type-post","status-publish","format-standard","hentry","category-gnome","category-igaliacom","category-planet-gnome","category-planet-gpul","category-planet-igalia","category-planeta-gnome-hispano","category-planets","tag-gstreamer","tag-igalia","tag-tests"],"_links":{"self":[{"href":"https:\/\/blogs.igalia.com\/xrcalvar\/wp-json\/wp\/v2\/posts\/115","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.igalia.com\/xrcalvar\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.igalia.com\/xrcalvar\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.igalia.com\/xrcalvar\/wp-json\/wp\/v2\/users\/31"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.igalia.com\/xrcalvar\/wp-json\/wp\/v2\/comments?post=115"}],"version-history":[{"count":1,"href":"https:\/\/blogs.igalia.com\/xrcalvar\/wp-json\/wp\/v2\/posts\/115\/revisions"}],"predecessor-version":[{"id":279,"href":"https:\/\/blogs.igalia.com\/xrcalvar\/wp-json\/wp\/v2\/posts\/115\/revisions\/279"}],"wp:attachment":[{"href":"https:\/\/blogs.igalia.com\/xrcalvar\/wp-json\/wp\/v2\/media?parent=115"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.igalia.com\/xrcalvar\/wp-json\/wp\/v2\/categories?post=115"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.igalia.com\/xrcalvar\/wp-json\/wp\/v2\/tags?post=115"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}