Instantly share code, notes, and snippets.

Embed
What would you like to do?
Generic C++ GObject signal wrapper
#include <gstreamermm.h>
#include <glibmm.h>
#include <iostream>
#include <condition_variable>
namespace Glib
{
template <typename T>
static constexpr T wrap (T v, bool=true)
{
return v;
}
template <typename T>
static constexpr T unwrap (T v, bool=true)
{
return v;
}
template<typename T>
using unwrapped_t = decltype(unwrap(*((typename std::remove_reference<T>::type*)nullptr)));
template<typename T>
constexpr T return_helper()
{
typedef unwrapped_t<T> Ret;
return Ret();
}
template<>
constexpr void return_helper()
{
return void();
}
}
template<typename>
class signal_callback;
template<typename Ret, typename ...T>
class signal_callback<Ret(T...)>
{
template<typename ...Args>
static auto callback(void* self, Args ...v)
{
using Glib::wrap;
typedef sigc::slot< void, decltype(wrap(v))... > SlotType;
void* data = std::get<sizeof...(Args)-1>(std::tuple<Args...>(v...));
// Do not try to call a signal on a disassociated wrapper.
if(dynamic_cast<Glib::Object*>(Glib::ObjectBase::_get_current_wrapper((GObject*) self)))
{
try
{
if(sigc::slot_base *const slot = Glib::SignalProxyNormal::data_to_slot(data))
{
(*static_cast<SlotType*>(slot))(wrap(std::forward<Args>(v), true)...);
}
}
catch(...)
{
Glib::exception_handlers_invoke();
}
}
return Glib::return_helper<Ret>();
}
public:
auto operator()(const std::string& signal_name, const Glib::RefPtr<Glib::Object>& obj)
{
using Glib::unwrap;
static std::map<std::pair<GType, std::string>, Glib::SignalProxyInfo> signal_infos;
auto key = std::make_pair(G_TYPE_FROM_INSTANCE (obj->gobj()), signal_name);
if (signal_infos.find(key) == signal_infos.end())
{
signal_infos[key] = {
signal_name.c_str(),
(GCallback) &callback<Glib::unwrapped_t<T>..., void*>,
(GCallback) &callback<Glib::unwrapped_t<T>..., void*>
};
}
return Glib::SignalProxy<Ret, T... >(obj.operator->(), &signal_infos[key]);
}
};
int main(int argc, char** argv)
{
if(argc < 2)
{
std::cout << "Usage: " << argv[0] << " <filename>" << std::endl;
return 1;
}
Gst::init(argc, argv);
auto pipeline = Gst::Pipeline::create();
auto source = Gst::ElementFactory::create_element("filesrc"),
typefind = Gst::ElementFactory::create_element("typefind"),
sink = Gst::ElementFactory::create_element("fakesink");
source->set_property<std::string>("location", argv[1]);
std::mutex m;
std::condition_variable cv;
bool ready = false;
signal_callback<void(guint, const Glib::RefPtr<Gst::Caps>&)> signal_wrapper;
signal_wrapper("have-type", typefind).connect([&ready, &cv] (guint probability, const Glib::RefPtr<Gst::Caps>& caps)
{
std::cout << "have-type: probability=" << probability << std::endl;
if(!caps || !caps->size())
{
std::cerr << "on_typefind_have_type(): caps is null or empty" << std::endl;
return;
}
Gst::Structure structure = caps->get_structure(0);
const Glib::ustring mime_type = structure.get_name();
std::cout << "have-type: mime_type=" << mime_type << std::endl;
structure.foreach([] (const Glib::QueryQuark& id, const Glib::ValueBase& value)
{
const Glib::ustring str_id = id;
gchar* str_value = g_strdup_value_contents(value.gobj());
std::cout << "Structure field: id=" << str_id << ", value=" << str_value << std::endl;
g_free(str_value);
return true;
});
ready = true;
cv.notify_one();
});
try
{
pipeline->add(source)->add(typefind)->add(sink);
source->link(typefind)->link(sink);
}
catch (std::runtime_error& ex)
{
std::cerr << "Exception while adding: " << ex.what() << std::endl;
return 1;
}
pipeline->set_state(Gst::STATE_PLAYING);
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, [&ready]{return ready;});
pipeline->set_state(Gst::STATE_NULL);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment