[gstreamermm] Gst::BaseSrc: fix refs of {get_caps, fixate}() return values



commit 65dc5d8c76dc2d8e91d1e665eec5b0ab39e81de3
Author: Michał Wróbel <michal wrobel flytronic pl>
Date:   Sat Jun 27 23:52:24 2015 +0200

    Gst::BaseSrc: fix refs of {get_caps,fixate}() return values
    
    This is https://bugzilla.gnome.org/show_bug.cgi?id=751601 in progress.
    
        * gstreamer/src/basesrc.ccg: initialize pointer.
        * gstreamer/src/basesrc.hg: fix virtual methods: get_caps and fixate.
        * tests/Makefile.am: add appsrc test to a build.
        * tests/plugins/derivedfromappsrc.h:
        * tests/plugins/test-plugin-appsrc.cc:
        * tests/plugins/test-plugin-derivedfromappsrc.cc: add a few appsrc
          tests.
    
    The patch includes unit tests which should fail if the fixes done in
    gstreamer/src/basesrc.{ccg,hg} are not applied.

 gstreamer/src/basesrc.ccg                      |    2 +-
 gstreamer/src/basesrc.hg                       |    7 +-
 tests/Makefile.am                              |    2 +
 tests/plugins/derivedfromappsrc.h              |   30 ++++++
 tests/plugins/test-plugin-appsrc.cc            |   80 ++++++++++++----
 tests/plugins/test-plugin-derivedfromappsrc.cc |  119 ++++++++++++++++++++++++
 6 files changed, 215 insertions(+), 25 deletions(-)
---
diff --git a/gstreamer/src/basesrc.ccg b/gstreamer/src/basesrc.ccg
index 9d81a9f..37dfa00 100644
--- a/gstreamer/src/basesrc.ccg
+++ b/gstreamer/src/basesrc.ccg
@@ -192,7 +192,7 @@ FlowReturn Gst::BaseSrc::create_vfunc(guint64 offset, guint size, Glib::RefPtr<G
 
   if(base && base->create)
   {
-    GstBuffer* gst_buffer;
+    GstBuffer* gst_buffer = NULL;
     Gst::FlowReturn const result =
       static_cast<FlowReturn>((*base->create)(gobj(),offset, size,&gst_buffer));
     buffer = Glib::wrap(gst_buffer, false); // Don't take copy because callback returns a newly created copy.
diff --git a/gstreamer/src/basesrc.hg b/gstreamer/src/basesrc.hg
index 8ad7cf4..6ab8741 100644
--- a/gstreamer/src/basesrc.hg
+++ b/gstreamer/src/basesrc.hg
@@ -179,11 +179,12 @@ public:
   _WRAP_PROPERTY("typefind", bool)
 
 #m4 _CONVERSION(`Glib::RefPtr<Gst::Caps>', `GstCaps*', `Glib::unwrap($3)')
+#m4 _CONVERSION(`GstCaps*', `const Glib::RefPtr<Gst::Caps>&', `Glib::wrap($3, true)')
+
   /** Called to get the caps to report.
    */
-  _WRAP_VFUNC(Glib::RefPtr<Gst::Caps> get_caps(Glib::RefPtr<Gst::Caps> caps) const, "get_caps")
+  _WRAP_VFUNC(Glib::RefPtr<Gst::Caps> get_caps(const Glib::RefPtr<Gst::Caps>& caps) const, "get_caps", 
refreturn_ctype)
 
-#m4 _CONVERSION(`GstCaps*', `const Glib::RefPtr<Gst::Caps>&', `Glib::wrap($3, true)')
   /** Notify subclass of changed output caps.
    */
   _WRAP_VFUNC(bool set_caps(const Glib::RefPtr<Gst::Caps>& caps), "set_caps")
@@ -242,7 +243,7 @@ public:
   /** Called during negotiation if caps need fixating. Implement instead of
    * setting a fixate function on the source pad.
    */
-  _WRAP_VFUNC(Glib::RefPtr<Gst::Caps> fixate(const Glib::RefPtr<Gst::Caps>& caps), "fixate")
+  _WRAP_VFUNC(Glib::RefPtr<Gst::Caps> fixate(const Glib::RefPtr<Gst::Caps>& caps), "fixate", refreturn_ctype)
 
   /** Clear the previous unlock request. Subclasses should clear any state they
    * set during unlock_vfunc(), such as clearing command queues.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index aff11d3..52f5d1e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -43,6 +43,7 @@ check_PROGRAMS =                                \
                                                 \
         test-plugin-appsink                     \
         test-plugin-appsrc                      \
+        test-plugin-derivedfromappsrc           \
         test-plugin-derivedfrombasetransform    \
         test-plugin-pushsrc                     \
         test-plugin-register                    \
@@ -80,6 +81,7 @@ test_urihandler_SOURCES                         = test-urihandler.cc
 
 test_plugin_appsink_SOURCES                     = plugins/test-plugin-appsink.cc                     
$(TEST_MAIN_SOURCE)
 test_plugin_appsrc_SOURCES                      = plugins/test-plugin-appsrc.cc                      
$(TEST_MAIN_SOURCE)
+test_plugin_derivedfromappsrc_SOURCES           = plugins/test-plugin-derivedfromappsrc.cc           
$(TEST_MAIN_SOURCE)
 test_plugin_derivedfrombasetransform_SOURCES    = plugins/test-plugin-derivedfrombasetransform.cc    
$(TEST_MAIN_SOURCE)
 test_plugin_pushsrc_SOURCES                     = plugins/test-plugin-pushsrc.cc                     
$(TEST_MAIN_SOURCE)
 test_plugin_register_SOURCES                    = plugins/test-plugin-register.cc                    
$(TEST_MAIN_SOURCE)
diff --git a/tests/plugins/derivedfromappsrc.h b/tests/plugins/derivedfromappsrc.h
new file mode 100644
index 0000000..aca87ad
--- /dev/null
+++ b/tests/plugins/derivedfromappsrc.h
@@ -0,0 +1,30 @@
+#ifndef TESTS_PLUGINS_DERIVEDFROMAPPSRC_H_
+#define TESTS_PLUGINS_DERIVEDFROMAPPSRC_H_
+
+#include <gst/app/gstappsrc.h>
+#include <gstreamermm.h>
+#include <gstreamermm/private/appsrc_p.h>
+#include <assert.h>
+
+class DerivedFromAppSrc : public Gst::AppSrc
+{
+public:
+    static void base_init(Gst::ElementClass<DerivedFromAppSrc> *klass)
+    {
+        klass->set_metadata("derivedfromappsrc_longname",
+                "derivedfromappsrc_classification", "derivedfromappsrc_detail_description", 
"derivedfromappsrc_detail_author");
+    }
+
+    explicit DerivedFromAppSrc(GstAppSrc *gobj)
+        : Glib::ObjectBase(typeid (DerivedFromAppSrc)), // type must be registered before use
+          Gst::AppSrc(gobj)
+    {
+    }
+
+    static bool register_element(Glib::RefPtr<Gst::Plugin> plugin)
+    {
+        return Gst::ElementFactory::register_element(plugin, "derivedfromappsrc", 10, 
Gst::register_mm_type<DerivedFromAppSrc>("derivedfromappsrc"));
+    }
+};
+
+#endif /* TESTS_PLUGINS_DERIVEDFROMAPPSRC_H_ */
diff --git a/tests/plugins/test-plugin-appsrc.cc b/tests/plugins/test-plugin-appsrc.cc
index 324c80b..b12e3e7 100644
--- a/tests/plugins/test-plugin-appsrc.cc
+++ b/tests/plugins/test-plugin-appsrc.cc
@@ -15,21 +15,22 @@ using Glib::RefPtr;
 class AppSrcPluginTest : public ::testing::Test
 {
 protected:
-    RefPtr<Element> source_element;
+    RefPtr<Element> source;
+    RefPtr<Element> sink;
     RefPtr<Pipeline> pipeline;
 
     void CreatePipelineWithElements()
     {
         pipeline = Gst::Pipeline::create();
 
-        RefPtr<Element> sink = Gst::ElementFactory::create_element("fakesink", "sink");
-        source_element = ElementFactory::create_element("appsrc", "source");
+        sink = ElementFactory::create_element("fakesink", "sink");
+        source = ElementFactory::create_element("appsrc", "source");
 
         ASSERT_TRUE(sink);
-        ASSERT_TRUE(source_element);
+        ASSERT_TRUE(source);
 
-        ASSERT_NO_THROW(pipeline->add(source_element)->add(sink));
-        ASSERT_NO_THROW(source_element->link(sink));
+        ASSERT_NO_THROW(pipeline->add(source)->add(sink));
+        ASSERT_NO_THROW(source->link(sink));
     }
 };
 
@@ -38,7 +39,7 @@ TEST_F(AppSrcPluginTest, CorrectCreatedAppSrcElement)
     RefPtr<AppSrc> source = AppSrc::create("source");
     ASSERT_TRUE(source);
 
-    source_element = ElementFactory::create_element("appsrc", "source");
+    RefPtr<Element> source_element = ElementFactory::create_element("appsrc", "source");
     ASSERT_TRUE(source_element);
 
     source = source.cast_dynamic(source_element);
@@ -50,33 +51,70 @@ TEST_F(AppSrcPluginTest, CreatePipelineWithAppSrcElement)
     CreatePipelineWithElements();
 }
 
-TEST_F(AppSrcPluginTest, SimpleDataFlowInPipelineWitAppSrcElement)
+TEST_F(AppSrcPluginTest, SrcPadQueryCapsShouldReturnProperCapsObjects)
 {
     CreatePipelineWithElements();
 
-    pipeline->set_state(Gst::STATE_PLAYING);
+    RefPtr<BaseSrc> basesrc;
+    basesrc = basesrc.cast_dynamic(source);
+    ASSERT_TRUE(basesrc);
+
+    RefPtr<Pad> src_pad = basesrc->get_src_pad();
+    ASSERT_TRUE(src_pad);
+    ASSERT_TRUE(GST_IS_PAD(src_pad->gobj()));
+    RefPtr<Caps> caps = src_pad->query_caps(Caps::create_any());
+    ASSERT_TRUE(caps);
+    ASSERT_TRUE(caps->gobj());
+    ASSERT_TRUE(GST_IS_CAPS(caps->gobj()));
+    RefPtr<Caps> template_caps = Glib::wrap(gst_pad_get_pad_template_caps(src_pad->gobj()), false);
+
+    src_pad.reset();
+    basesrc.reset();
+    sink.reset();
+    pipeline.reset();
+
+    // query_caps may return just another ref to template_caps
+    if (caps == template_caps)
+    {
+        // ...but template_caps might be just another ref to static caps with some higher unknown refcount
+        //EXPECT_EQ(2, caps->get_refcount());
+    }
+    else
+    {
+        EXPECT_EQ(1, caps->get_refcount());
+    }
+}
+
+TEST_F(AppSrcPluginTest, SimpleDataFlowInPipelineWithAppSrcElement)
+{
+    CreatePipelineWithElements();
+
+    EXPECT_EQ(STATE_CHANGE_ASYNC, pipeline->set_state(STATE_PLAYING));
 
     std::string data = "hello world";
     RefPtr<Buffer> buf = Buffer::create(data.length() + 1);
-    RefPtr<MapInfo> mapinfo(new Gst::MapInfo());
-    buf->map(mapinfo, MAP_WRITE);
+    ASSERT_TRUE(buf);
+    RefPtr<MapInfo> mapinfo(new MapInfo());
+    ASSERT_TRUE(buf->map(mapinfo, MAP_WRITE));
     strcpy((char *)mapinfo->get_data(), data.c_str());
 
     RefPtr<AppSrc> appsrc;
-    appsrc = appsrc.cast_dynamic(source_element);
-    appsrc->push_buffer(buf);
+    appsrc = appsrc.cast_dynamic(source);
+    ASSERT_TRUE(appsrc);
+
+    EXPECT_EQ(FLOW_OK, appsrc->push_buffer(buf));
 
     {
-        State state;
-        StateChangeReturn ret=pipeline->get_state(state, state, 1*SECOND);
-        ASSERT_EQ(ret, STATE_CHANGE_SUCCESS);
+        State state, pending;
+        StateChangeReturn ret = pipeline->get_state(state, pending, 1*SECOND);
+        EXPECT_EQ(STATE_CHANGE_SUCCESS, ret);
+        EXPECT_EQ(STATE_PLAYING, state);
     }
 
-    appsrc->end_of_stream();
+    EXPECT_EQ(FLOW_OK, appsrc->end_of_stream());
 
-    RefPtr<Gst::Message> msg = pipeline->get_bus()->poll((Gst::MessageType)(Gst::MESSAGE_EOS | 
Gst::MESSAGE_ERROR) , 1*Gst::SECOND);
+    RefPtr<Message> msg = pipeline->get_bus()->poll((MessageType)(MESSAGE_EOS | MESSAGE_ERROR) , 1*SECOND);
     ASSERT_TRUE(msg);
-    ASSERT_EQ(msg->get_message_type(), Gst::MESSAGE_EOS);
-    pipeline->set_state(Gst::STATE_NULL);
+    EXPECT_EQ(MESSAGE_EOS, msg->get_message_type());
+    EXPECT_EQ(STATE_CHANGE_SUCCESS, pipeline->set_state(STATE_NULL));
 }
-
diff --git a/tests/plugins/test-plugin-derivedfromappsrc.cc b/tests/plugins/test-plugin-derivedfromappsrc.cc
new file mode 100644
index 0000000..8b7ab4b
--- /dev/null
+++ b/tests/plugins/test-plugin-derivedfromappsrc.cc
@@ -0,0 +1,119 @@
+#include <gtest/gtest.h>
+#include <gstreamermm.h>
+#include <gstreamermm/appsrc.h>
+
+#include "derivedfromappsrc.h"
+
+using namespace Gst;
+using Glib::RefPtr;
+
+class DerivedFromAppSrcPluginTest : public ::testing::Test
+{
+protected:
+    RefPtr<Element> source;
+    RefPtr<Element> sink;
+    RefPtr<Pipeline> pipeline;
+
+    void CreatePipelineWithElements()
+    {
+        pipeline = Pipeline::create();
+
+        sink = ElementFactory::create_element("fakesink", "sink");
+        source = ElementFactory::create_element("derivedfromappsrc", "source");
+
+        ASSERT_TRUE(sink);
+        ASSERT_TRUE(source);
+
+        ASSERT_NO_THROW(pipeline->add(source)->add(sink));
+        ASSERT_NO_THROW(source->link(sink));
+    }
+
+    virtual void SetUp()
+    {
+        Plugin::register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR, "derivedfromappsrc",
+            "derivedfromappsrc is an example of C++ element derived from Gst::AppSrc",
+            sigc::ptr_fun(&DerivedFromAppSrc::register_element), "0.123",
+            "LGPL", "source?", "package?", "http://example.com";);
+    }
+};
+
+TEST_F(DerivedFromAppSrcPluginTest, CreateRegisteredElement)
+{
+    RefPtr<Element> source_element = ElementFactory::create_element("derivedfromappsrc", "source");
+
+    ASSERT_TRUE(source_element);
+}
+
+TEST_F(DerivedFromAppSrcPluginTest, CreatePipelineWithRegisteredElement)
+{
+    CreatePipelineWithElements();
+}
+
+TEST_F(DerivedFromAppSrcPluginTest, SrcPadQueryCapsShouldReturnProperCapsObjects)
+{
+    CreatePipelineWithElements();
+
+    RefPtr<BaseSrc> basesrc;
+    basesrc = basesrc.cast_dynamic(source);
+    ASSERT_TRUE(basesrc);
+
+    RefPtr<Pad> src_pad = basesrc->get_src_pad();
+    ASSERT_TRUE(src_pad);
+    ASSERT_TRUE(GST_IS_PAD(src_pad->gobj()));
+    RefPtr<Caps> caps = src_pad->query_caps(Caps::create_any());
+    ASSERT_TRUE(caps);
+    ASSERT_TRUE(caps->gobj());
+    ASSERT_TRUE(GST_IS_CAPS(caps->gobj()));
+    RefPtr<Caps> template_caps = Glib::wrap(gst_pad_get_pad_template_caps(src_pad->gobj()), false);
+
+    src_pad.reset();
+    basesrc.reset();
+    sink.reset();
+    pipeline.reset();
+
+    // query_caps may return just another ref to template_caps
+    if (caps == template_caps)
+    {
+        // ...but template_caps might be just another ref to static caps with some higher unknown refcount
+        //EXPECT_EQ(2, caps->get_refcount());
+    }
+    else
+    {
+        EXPECT_EQ(1, caps->get_refcount());
+    }
+}
+
+TEST_F(DerivedFromAppSrcPluginTest, SimpleDataFlowInPipelineWithAppSrcElement)
+{
+    CreatePipelineWithElements();
+
+    EXPECT_EQ(STATE_CHANGE_ASYNC, pipeline->set_state(STATE_PLAYING));
+
+    std::string data = "hello world";
+    RefPtr<Buffer> buf = Buffer::create(data.length() + 1);
+    ASSERT_TRUE(buf);
+    RefPtr<MapInfo> mapinfo(new MapInfo());
+    ASSERT_TRUE(buf->map(mapinfo, MAP_WRITE));
+    strcpy((char *)mapinfo->get_data(), data.c_str());
+
+    RefPtr<AppSrc> appsrc;
+    appsrc = appsrc.cast_dynamic(source);
+    ASSERT_TRUE(appsrc);
+
+    EXPECT_EQ(FLOW_OK, appsrc->push_buffer(buf));
+
+    {
+        State state, pending;
+        StateChangeReturn ret = pipeline->get_state(state, pending, 1*SECOND);
+        EXPECT_EQ(STATE_CHANGE_SUCCESS, ret);
+        EXPECT_EQ(STATE_PLAYING, state);
+    }
+
+    EXPECT_EQ(FLOW_OK, appsrc->end_of_stream());
+
+    RefPtr<Message> msg = pipeline->get_bus()->poll((MessageType)(MESSAGE_EOS | MESSAGE_ERROR) , 1*SECOND);
+    ASSERT_TRUE(msg);
+    EXPECT_EQ(MESSAGE_EOS, msg->get_message_type());
+    EXPECT_EQ(STATE_CHANGE_SUCCESS, pipeline->set_state(STATE_NULL));
+}
+


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]