Created
July 16, 2016 17:37
Star
You must be signed in to star a gist
Generic C++ GObject signal wrapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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