From: APTX Date: Sun, 20 Feb 2022 04:27:43 +0000 (+0900) Subject: Introduce mpvhelper.h, possible future replacement of qthelper.hpp X-Git-Url: https://gitweb.aptx.org/?a=commitdiff_plain;h=1038a83610beb2ed105e5f2d5ea2bb7d39a8feec;p=aniplayer.git Introduce mpvhelper.h, possible future replacement of qthelper.hpp Use of "max-volume" property was removed as that property doesn't exist. --- diff --git a/backendplugins/backend_mpv/CMakeLists.txt b/backendplugins/backend_mpv/CMakeLists.txt index 81d5519..c848299 100644 --- a/backendplugins/backend_mpv/CMakeLists.txt +++ b/backendplugins/backend_mpv/CMakeLists.txt @@ -22,6 +22,7 @@ set(backend_mpv_SOURCES set(backend_mpv_HEADERS backendmpv.h + mpvhelper.h qthelper.hpp backend_mpv_global.h ) @@ -35,7 +36,7 @@ add_library(backend_mpv MODULE ${backend_mpv_HEADERS} ) -set_property(TARGET backend_mpv PROPERTY CXX_STANDARD 14) +set_property(TARGET backend_mpv PROPERTY CXX_STANDARD 17) set_property(TARGET backend_mpv PROPERTY OUTPUT_NAME "backend_mpv") target_link_libraries(backend_mpv ${backend_mpv_LIBS}) diff --git a/backendplugins/backend_mpv/backendmpv.cpp b/backendplugins/backend_mpv/backendmpv.cpp index c110179..0e11985 100644 --- a/backendplugins/backend_mpv/backendmpv.cpp +++ b/backendplugins/backend_mpv/backendmpv.cpp @@ -5,6 +5,7 @@ #include #include +#include "mpvhelper.h" #include "qthelper.hpp" #include @@ -105,8 +106,6 @@ MpvInstance::MpvInstance(PlayerPluginInterface *playerInterface, } { double maxVolume = 130.0; - mpv_set_property(m_handle, "max-volume", MPV_FORMAT_DOUBLE, &maxVolume); - mpv_get_property(m_handle, "max-volume", MPV_FORMAT_DOUBLE, &maxVolume); maxVolume /= 100.0; m_player->playbackMaxVolumeChanged(maxVolume); } @@ -136,26 +135,24 @@ bool MpvInstance::open(const QUrl &source) { void MpvInstance::play() { qCDebug(mpvBackend) << "Play"; - int f = 0; - mpv_set_property(m_handle, "pause", MPV_FORMAT_FLAG, &f); + mpv::SetProperty(m_handle, mpv::property::Pause, false); } void MpvInstance::pause() { qCDebug(mpvBackend) << "Pause"; - int f = 1; - mpv_set_property(m_handle, "pause", MPV_FORMAT_FLAG, &f); + mpv::SetProperty(m_handle, mpv::property::Pause, true); } void MpvInstance::stop() { qCDebug(mpvBackend) << "Stop"; } void MpvInstance::seek(TimeStamp pos) { - mpv_set_property(m_handle, "playback-time", MPV_FORMAT_DOUBLE, &pos); + mpv::SetProperty(m_handle, mpv::property::PlaybackTime, pos); } void MpvInstance::setVolume(Volume volume) { double percantageVolume = volume * 100; int error = - mpv_set_property(m_handle, VOLUME, MPV_FORMAT_DOUBLE, &percantageVolume); + mpv::SetProperty(m_handle, mpv::property::Volume, percantageVolume); if (error) { qCDebug(mpvBackend) << "Audio output not yet ready, setting volume at a later time"; @@ -168,27 +165,27 @@ void MpvInstance::setVolume(Volume volume) { } void MpvInstance::setCurrentVideoStream(TrackIndex track) { - qint64 tmp = track; - if (track < 0) - mpv_set_property_string(m_handle, "vid", "no"); - else - mpv_set_property(m_handle, "vid", MPV_FORMAT_INT64, &tmp); + if (track < 0) { + mpv::SetProperty(m_handle, mpv::property::Vid, "no"); + } else { + mpv::SetProperty(m_handle, mpv::property::Vid, mpv::format::Int64, track); + } } void MpvInstance::setCurrentAudioStream(TrackIndex track) { - qint64 tmp = track; - if (track < 0) - mpv_set_property_string(m_handle, "aid", "no"); - else - mpv_set_property(m_handle, "aid", MPV_FORMAT_INT64, &tmp); + if (track < 0) { + mpv::SetProperty(m_handle, mpv::property::Aid, "no"); + } else { + mpv::SetProperty(m_handle, mpv::property::Aid, mpv::format::Int64, track); + } } void MpvInstance::setCurrentSubtitleStream(TrackIndex track) { - qint64 tmp = track; - if (track < 0) - mpv_set_property_string(m_handle, "sid", "no"); - else - mpv_set_property(m_handle, "sid", MPV_FORMAT_INT64, &tmp); + if (track < 0) { + mpv::SetProperty(m_handle, mpv::property::Sid, "no"); + } else { + mpv::SetProperty(m_handle, mpv::property::Sid, mpv::format::Int64, track); + } } template struct MpvProperty; @@ -296,7 +293,7 @@ void MpvInstance::processMpvEvents() { void MpvInstance::onPropertyChange(mpv_event_property *property) { qCDebug(mpvVerboseBackend) << "Property" << property->name << "changed"; if (property->format == MPV_FORMAT_NONE) { - qCDebug(mpvBackend) << "No data in event"; + qCDebug(mpvBackend) << "No data in event for property: " << property->name; return; } if (strcmp(property->name, "pause") == 0) { @@ -397,8 +394,7 @@ void MpvInstance::onLogMessage(mpv_event_log_message *log) { } void MpvInstance::onFileLoaded() { - int paused = 0; - mpv_get_property(m_handle, "paused", MPV_FORMAT_FLAG, &paused); + bool paused = *mpv::GetProperty(m_handle, mpv::property::Paused); qCDebug(mpvBackend) << "file-loaded event!" << paused; m_loadedFile = true; auto state = paused ? PlayerPluginInterface::PlayState::Paused diff --git a/backendplugins/backend_mpv/mpvhelper.h b/backendplugins/backend_mpv/mpvhelper.h new file mode 100644 index 0000000..0d5208c --- /dev/null +++ b/backendplugins/backend_mpv/mpvhelper.h @@ -0,0 +1,237 @@ +#ifndef MPVHELPER_H +#define MPVHELPER_H + +#include + +#include +#include + +#include + +#include + +Q_LOGGING_CATEGORY(mpvHelper, "mpv.helper") + +namespace mpv { + +using Handle = mpv_handle *; + +struct Error +{ + using ErrorType = int; + ErrorType error; +}; + +template +class Outcome { + Error::ErrorType m_error = MPV_ERROR_SUCCESS; + T m_value; + +public: + Outcome(T value) : m_value{std::move(value)} {} + Outcome(Error error) : m_error{error.error} {} + + bool HasError() const { return m_error != MPV_ERROR_SUCCESS; } + bool ok() const { return !HasError(); } + explicit operator bool() const { return ok(); } + const T &value() const { + assert(!HasError()); + return m_value; + } + const T &operator*() const { return value(); } + Error::ErrorType error() const { + assert(HasError()); + return m_error; + } +}; + +template +struct Event +{ + using type = DataType; + const mpv_event_id id; + constexpr explicit Event(mpv_event_id id) : id{id} {} +}; + +namespace event { +// TODO add all events? +constexpr Event PropertyChange{MPV_EVENT_PROPERTY_CHANGE}; +constexpr Event LogMessage{MPV_EVENT_LOG_MESSAGE}; +constexpr Event<> FileLoaded{MPV_EVENT_FILE_LOADED}; +constexpr Event EndFile{MPV_EVENT_END_FILE}; +constexpr Event<> AudioReconfig{MPV_EVENT_AUDIO_RECONFIG}; +} // namespace event + +template +struct Format +{ + static_assert(!std::is_same_v, + "MpvInternalType can not be bool"); + // The type returned/provided from C++ + using type = CppType; + // The type used internally by mpc + using MpvInternalType = MpvInternalTypeName; + static constexpr mpv_format format = FormatValue; + static constexpr bool readOnly = ReadOnly; +}; + +namespace format { +constexpr Format None; +constexpr Format String; +constexpr Format OsdString; +constexpr Format Flag; +constexpr Format Int64; +constexpr Format Double; +constexpr Format Node; +// TODO should these be defined +constexpr Format NodeArray; +constexpr Format NodeMap; +// TODO figure out correct type +constexpr Format ByteArray; + +} // namespace format + +template +struct Property +{ + static_assert(!(Format::readOnly == true && ReadOnly == false), + "Property with ReadOnly == false can not have a Format with " + "ReadOnly == true"); + const Format format; + static constexpr bool readOnly = ReadOnly; + const char *name; + constexpr explicit Property(Format format, const char *name) + : format{format}, name{name} {} +}; + +template +constexpr auto MakeProperty(Format, const char *name) { + return Property(Format{}, name); +} + +namespace property { +constexpr Property Pause = MakeProperty(format::Flag, "pause"); +constexpr Property Paused = MakeProperty(format::Flag, "paused"); +constexpr Property Duration = MakeProperty(format::Double, "duration"); +constexpr Property PlaybackTime = MakeProperty(format::Double, "playback-time"); +constexpr Property Volume = MakeProperty(format::Double, "volume"); +constexpr Property TrackList = MakeProperty(format::Node, "track-list"); +constexpr Property Vid = MakeProperty(format::String, "vid"); +constexpr Property Aid = MakeProperty(format::String, "aid"); +constexpr Property Sid = MakeProperty(format::String, "sid"); +constexpr Property ChapterList = MakeProperty(format::Node, "sid"); +constexpr Property IdleActive = MakeProperty(format::Flag, "idle-active"); +constexpr Property MaxVolume = MakeProperty(format::Double, "max-volume"); +} // namespace property + +namespace detail { +template +struct TypeConversion +{ + static_assert(std::is_convertible_v, + "Default type conversion not possible, new TypeConversion " + "specialization required"); + static To convert(const From &from) { return To{from}; } +}; + +template +struct TypeConversion +{ + static const T &convert(const T &from) { return from; } +}; + +template<> +struct TypeConversion +{ + static const char *convert(const QString &from) { + return qUtf8Printable(from); + } +}; + +template<> +struct TypeConversion +{ + static QString convert(const char *from) { return QString::fromUtf8(from); } +}; + +// Avoids narrwoing conversion warnings +template<> +struct TypeConversion +{ + static bool convert(const int &from) { return from != 0; } +}; + +template +auto ReadFormat(const Handle &handle, Format format, const char *name) + -> Outcome { + typename Format::MpvInternalType data; + int error = mpv_get_property(handle, name, format.format, &data); + qCDebug(mpvHelper()).nospace() + << "ReadFormat, property: " << name << ", error: " << error + << ", original value: " << data; + if (error != MPV_ERROR_SUCCESS) { + return Error{error}; + } + return TypeConversion::convert(data); +} + +template +int WriteFormat(const Handle &handle, Format format, const char *name, + const typename Format::type &value) { + const auto &data = + TypeConversion::convert(value); + int error = + mpv_set_property(handle, name, format.format, + const_cast(&data)); + qCDebug(mpvHelper()).nospace() + << "WriteFormat, property: " << name << ", error: " << error + << ", original value: " << value << ", converted value: " << data; + return error; +} + +} // namespace detail + +template +auto GetProperty(const Handle &handle, const Property &property) + -> Outcome { + static_assert(decltype(Property::format)::format != MPV_FORMAT_NONE, + "Can not read property with format None"); + return detail::ReadFormat(handle, property.format, property.name); +} + +// Read property, using specific format rather than the properties format +template +auto GetProperty(const Handle &handle, const Property &property, + const Format &format) -> Outcome { + static_assert(Format::format != MPV_FORMAT_NONE, + "Can not read property with format None"); + return detail::ReadFormat(handle, format, property.name); +} + +template +int SetProperty(const Handle &handle, const Property &property, + const typename decltype(Property::format)::type &value) { + static_assert(decltype(Property::format)::format != MPV_FORMAT_NONE, + "Can not write property with format None"); + static_assert(!decltype(Property::format)::readOnly, + "Can not write a readOnly property"); + + return detail::WriteFormat(handle, property.format, property.name, value); +} + +template +int SetProperty(const Handle &handle, const Property &property, + const Format &format, const typename Format::type &value) { + static_assert(Format::format != MPV_FORMAT_NONE, + "Can not write property with format None"); + static_assert(!Format::readOnly, "Can not write a readOnly property"); + + return detail::WriteFormat(handle, format, property.name, value); +} + +} // namespace mpv + +#endif // MPVHELPER_H