Commit 7497299f authored by Hugo Beauzée-Luyssen's avatar Hugo Beauzée-Luyssen

MediaPlayer: Handle event callbacks

parent 9c64fb89
......@@ -54,20 +54,6 @@ protected:
template <typename T>
using DecayPtr = typename std::add_pointer<typename std::decay<T>::type>::type;
template <typename, typename, typename = void>
struct signature_match : std::false_type {};
// Kudos to 3xxO
template <typename Func, typename Ret, typename... Args>
struct signature_match<Func, Ret(Args...),
typename std::enable_if<
std::is_convertible<
decltype(std::declval<Func>()(std::declval<Args>()...)),
Ret
>::value
>::type
> : std::true_type {};
private:
// Polymorphic base to hold a templated implementation
struct EventHandlerBase
......
This diff is collapsed.
......@@ -3,8 +3,8 @@
*****************************************************************************
* Copyright © 2015 libvlcpp authors & VideoLAN
*
* Authors: Alexey Sokolov <alexey@alexeysokolov.co.cc>
* Hugo Beauzée-Luyssen <hugo@beauzee.fr>
* Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
* Jonathan Calmels <exxo@videolabs.io>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
......@@ -25,6 +25,7 @@
#define LIBVLC_CXX_COMMON_H
#include <vlc/vlc.h>
#include <cassert>
#include <memory>
namespace VLC
......@@ -50,6 +51,110 @@ namespace VLC
{
return std::unique_ptr<char, void(*)(void*)>( str, [](void* ptr) { libvlc_free(ptr); } );
}
// Kudos to 3xxO for the signature_match helper
template <typename, typename, typename = void>
struct signature_match : std::false_type {};
template <typename Func, typename Ret, typename... Args>
struct signature_match<Func, Ret(Args...),
typename std::enable_if<
std::is_convertible<
decltype(std::declval<Func>()(std::declval<Args>()...)),
Ret
>::value // true or false
>::type // void or SFINAE
> : std::true_type {};
template <typename Func, typename Ret, typename... Args>
struct signature_match_or_nullptr : std::integral_constant<bool,
signature_match<Func, Ret, Args...>::value ||
std::is_same<Func, std::nullptr_t>::value
>
{
};
struct CallbackHandlerBase
{
virtual ~CallbackHandlerBase() = default;
};
template <typename Func>
struct CallbackHandler : public CallbackHandlerBase
{
CallbackHandler(Func&& f) : func( std::forward<Func>( f ) ) {}
Func func;
};
template <int NbEvent>
struct EventOwner
{
std::array<std::shared_ptr<CallbackHandlerBase>, NbEvent> callbacks;
protected:
EventOwner() = default;
};
template <int Idx, typename Func, typename... Args>
struct CallbackWrapper;
// We assume that any callback will take a void* opaque as its first parameter.
// We intercept this parameter, and use it to fetch the list of user provided
// functions. Once we know what function to call, we forward the rest of the
// parameters.
// Using partial specialization also allows us to get the list of the expected
// callback parameters automatically, rather than having to specify them.
template <int Idx, typename Func, typename Ret, typename... Args>
struct CallbackWrapper<Idx, Func, Ret(*)(void*, Args...)>
{
using Wrapped = Ret(void*, Args...);
template <int NbEvents>
static Wrapped* wrap(EventOwner<NbEvents>* owner, Func&& func)
{
owner->callbacks[Idx] = std::shared_ptr<CallbackHandlerBase>( new CallbackHandler<Func>( std::forward<Func>( func ) ) );
return [](void* opaque, Args... args) -> Ret {
auto self = reinterpret_cast<EventOwner<NbEvents>*>(opaque);
assert(self->callbacks[Idx].get());
auto cbHandler = static_cast<CallbackHandler<Func>*>( self->callbacks[Idx].get() );
return cbHandler->func( std::forward<Args>(args)... );
};
}
};
// Special handling for events with a void** opaque first parameter.
// We fetch it and do our business with it, then forward the parameters
// to the user callback, without this opaque param.
template <int Idx, typename Func, typename Ret, typename... Args>
struct CallbackWrapper<Idx, Func, Ret(*)(void**, Args...)>
{
using Wrapped = Ret(void**, Args...);
template <int NbEvents>
static Wrapped* wrap(EventOwner<NbEvents>* owner, Func&& func)
{
owner->callbacks[Idx] = std::shared_ptr<CallbackHandlerBase>( new CallbackHandler<Func>( std::forward<Func>( func ) ) );
return [](void** opaque, Args... args) -> Ret {
auto self = reinterpret_cast<EventOwner<NbEvents>*>(*opaque);
assert(self->callbacks[Idx].get());
auto cbHandler = static_cast<CallbackHandler<Func>*>( self->callbacks[Idx].get() );
return cbHandler->func( std::forward<Args>(args)... );
};
}
};
// Specialization to handle null callbacks at build time.
// We could try to compare any "Func" against nullptr at runtime, though
// since Func is a template type, which roughly has to satisfy the "Callable" concept,
// it could be an instance of a function object, which doesn't compare nicely against nullptr.
// Using the specialization at build time is easier and performs better.
template <int Idx, typename... Args>
struct CallbackWrapper<Idx, std::nullptr_t, void(*)(void*, Args...)>
{
template <int NbEvents>
static std::nullptr_t wrap(EventOwner<NbEvents>*, std::nullptr_t)
{
return nullptr;
}
};
}
#endif
......@@ -24,6 +24,7 @@
#include <iostream>
#include <thread>
#include <cstring>
int main(int ac, char** av)
{
......@@ -41,10 +42,34 @@ int main(int ac, char** av)
std::cout << media.mrl() << " is playing" << std::endl;
});
auto imgBuffer = malloc(480 * 320 * 4);
mp.setVideoCallbacks([imgBuffer](void** pBuffer) -> void* {
std::cout << "Lock" << std::endl;
*pBuffer = imgBuffer;
return NULL;
}, [](void*, void*const*) {
std::cout << "unlock" << std::endl;
}, nullptr);
mp.setVideoFormatCallbacks([](char* chroma, uint32_t* width, uint32_t* height, uint32_t* pitch, uint32_t* lines) -> int {
memcpy(chroma, "RV32", 4);
*width = 480;
*height = 320;
*pitch = *width * 4;
*lines = 320;
return 1;
}, nullptr);
mp.play();
bool expected = true;
mp.setAudioCallbacks([](const void*, uint32_t count, int64_t pts) {
std::cout << "Playing " << count << " samples at pts " << pts << std::endl;
}, nullptr, nullptr, nullptr, nullptr
);
auto& handler = mp.eventManager().onPositionChanged([&expected](float pos) {
std::cout << "position changed " << pos << std::endl;
assert(expected);
......@@ -111,4 +136,5 @@ int main(int ac, char** av)
{
std::cout << f.name() << std::endl;
}
free(imgBuffer);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment