[vlc-devel] [RFC 54/82] qt: add medialibrary video model

Pierre Lamot pierre at videolabs.io
Fri Feb 1 14:01:58 CET 2019


---
 modules/gui/qt/Makefile.am                    |   6 +
 .../gui/qt/components/mediacenter/mlvideo.cpp | 148 ++++++++++++++++++
 .../gui/qt/components/mediacenter/mlvideo.hpp |  82 ++++++++++
 .../components/mediacenter/mlvideomodel.cpp   | 136 ++++++++++++++++
 .../components/mediacenter/mlvideomodel.hpp   |  55 +++++++
 5 files changed, 427 insertions(+)
 create mode 100644 modules/gui/qt/components/mediacenter/mlvideo.cpp
 create mode 100644 modules/gui/qt/components/mediacenter/mlvideo.hpp
 create mode 100644 modules/gui/qt/components/mediacenter/mlvideomodel.cpp
 create mode 100644 modules/gui/qt/components/mediacenter/mlvideomodel.hpp

diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index 0169955200..c804e97652 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -140,6 +140,10 @@ libqt_plugin_la_SOURCES = \
 	gui/qt/components/mediacenter/mlgenre.hpp \
 	gui/qt/components/mediacenter/mlgenremodel.cpp \
 	gui/qt/components/mediacenter/mlgenremodel.hpp \
+	gui/qt/components/mediacenter/mlvideo.hpp \
+	gui/qt/components/mediacenter/mlvideo.cpp \
+	gui/qt/components/mediacenter/mlvideomodel.cpp \
+	gui/qt/components/mediacenter/mlvideomodel.hpp \
 	gui/qt/components/playlist/media.hpp \
 	gui/qt/components/playlist/playlist_common.cpp \
 	gui/qt/components/playlist/playlist_common.hpp \
@@ -271,6 +275,8 @@ nodist_libqt_plugin_la_SOURCES = \
 	gui/qt/components/mediacenter/mlartistmodel.moc.cpp \
 	gui/qt/components/mediacenter/mlgenre.moc.cpp \
 	gui/qt/components/mediacenter/mlgenremodel.moc.cpp \
+	gui/qt/components/mediacenter/mlvideo.moc.cpp \
+	gui/qt/components/mediacenter/mlvideomodel.moc.cpp \
 	gui/qt/components/playlist/playlist_common.moc.cpp \
 	gui/qt/components/playlist/playlist_item.moc.cpp \
 	gui/qt/components/playlist/playlist_model.moc.cpp \
diff --git a/modules/gui/qt/components/mediacenter/mlvideo.cpp b/modules/gui/qt/components/mediacenter/mlvideo.cpp
new file mode 100644
index 0000000000..8b73a90581
--- /dev/null
+++ b/modules/gui/qt/components/mediacenter/mlvideo.cpp
@@ -0,0 +1,148 @@
+/*****************************************************************************
+ * Copyright (C) 2019 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * ( at your option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include "mlvideo.hpp"
+
+#include <cassert>
+
+#include <vlc_thumbnailer.h>
+
+MLVideo::MLVideo(vlc_medialibrary_t* ml, const vlc_ml_media_t* data, QObject* parent)
+    : QObject( parent )
+    , m_ml( ml )
+    , m_id( data->i_id, VLC_ML_PARENT_UNKNOWN )
+    , m_title( QString::fromUtf8( data->psz_title ) )
+    , m_thumbnail( QString::fromUtf8( data->psz_artwork_mrl ) )
+    , m_playCount( data->i_playcount )
+    , m_thumbnailGenerated( data->b_artwork_generated )
+    , m_ml_event_handle( nullptr, [this](vlc_ml_event_callback_t* cb ) {
+        assert( m_ml != nullptr );
+        vlc_ml_event_unregister_callback( m_ml, cb );
+    })
+{
+    assert( data->i_type == VLC_ML_MEDIA_TYPE_VIDEO );
+
+    int t_sec = data->i_duration / 1000000;
+    int sec = t_sec % 60;
+    int min = (t_sec / 60) % 60;
+    int hour = t_sec / 3600;
+    if (hour == 0)
+        m_duration = QString("%1:%2")
+                .arg(min, 2, 10, QChar('0'))
+                .arg(sec, 2, 10, QChar('0'));
+    else
+        m_duration = QString("%1:%2:%3")
+                .arg(hour, 2, 10, QChar('0'))
+                .arg(min, 2, 10, QChar('0'))
+                .arg(sec, 2, 10, QChar('0'));
+
+    for( const vlc_ml_file_t& file: ml_range_iterate<vlc_ml_file_t>( data->p_files ) )
+        if( file.i_type == VLC_ML_FILE_TYPE_MAIN )
+        {
+            //FIXME should we store every mrl
+            m_mrl = QString::fromUtf8(file.psz_mrl);
+            break;
+        }
+    char *psz_progress;
+    if ( vlc_ml_media_get_playback_pref( ml, data->i_id, VLC_ML_PLAYBACK_PREF_PROGRESS,
+                                    &psz_progress ) == VLC_SUCCESS && psz_progress != NULL )
+    {
+        m_progress = atoi( psz_progress );
+        free( psz_progress );
+    }
+}
+
+MLVideo::MLVideo(const MLVideo& video, QObject* parent)
+    : QObject( parent )
+    , m_ml( video.m_ml )
+    , m_id( video.m_id )
+    , m_title( video.m_title )
+    , m_thumbnail( video.m_thumbnail )
+    , m_duration( video.m_duration )
+    , m_mrl( video.m_mrl )
+    , m_progress( video.m_progress )
+    , m_playCount( video.m_playCount )
+{
+}
+
+void MLVideo::onMlEvent( void* data, const vlc_ml_event_t* event )
+{
+    auto self = static_cast<MLVideo*>(data);
+    self->onMlEvent(event);
+}
+
+void MLVideo::onMlEvent( const vlc_ml_event_t* event )
+{
+    if ( event->i_type != VLC_ML_EVENT_MEDIA_THUMBNAIL_GENERATED )
+        return;
+    m_thumbnailGenerated = true;
+    if ( event->media_thumbnail_generated.p_media->i_id != m_id.id )
+        return;
+    if ( event->media_thumbnail_generated.b_success == false )
+        return;
+    auto thumbnailMrl = event->media_thumbnail_generated.p_media->psz_artwork_mrl;
+    m_thumbnail = QString::fromUtf8( thumbnailMrl );
+    vlc_ml_event_unregister_from_callback( m_ml, m_ml_event_handle.release() );
+    emit onThumbnailChanged( m_thumbnail );
+}
+
+MLParentId MLVideo::getId() const
+{
+    return m_id;
+}
+
+QString MLVideo::getTitle() const
+{
+    return m_title;
+}
+
+QString MLVideo::getThumbnail()
+{
+    if ( m_thumbnailGenerated == false )
+    {
+        m_ml_event_handle.reset( vlc_ml_event_register_callback( m_ml, onMlEvent, this ) );
+        vlc_ml_media_generate_thumbnail( m_ml, m_id.id );
+    }
+
+    return m_thumbnail;
+}
+
+QString MLVideo::getDuration() const
+{
+    return m_duration;
+}
+
+QString MLVideo::getMRL() const
+{
+    return m_mrl;
+}
+
+unsigned int MLVideo::getProgress() const
+{
+    return m_progress;
+}
+
+unsigned int MLVideo::getPlayCount() const
+{
+    return m_playCount;
+}
+
+MLVideo*MLVideo::clone(QObject* parent) const
+{
+    return new MLVideo(*this, parent);
+}
diff --git a/modules/gui/qt/components/mediacenter/mlvideo.hpp b/modules/gui/qt/components/mediacenter/mlvideo.hpp
new file mode 100644
index 0000000000..f8f204878a
--- /dev/null
+++ b/modules/gui/qt/components/mediacenter/mlvideo.hpp
@@ -0,0 +1,82 @@
+/*****************************************************************************
+ * Copyright (C) 2019 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * ( at your option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef MLVIDEO_H
+#define MLVIDEO_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <QObject>
+#include <vlc_media_library.h>
+#include "mlhelper.hpp"
+#include "mlqmltypes.hpp"
+
+#include <functional>
+
+class MLVideo : public QObject
+{
+    Q_OBJECT
+
+    Q_PROPERTY(MLParentId id READ getId CONSTANT);
+    Q_PROPERTY(QString title READ getTitle CONSTANT);
+    Q_PROPERTY(QString thumbnail READ getThumbnail NOTIFY onThumbnailChanged);
+    Q_PROPERTY(QString duration READ getDuration CONSTANT);
+    Q_PROPERTY(QString mrl READ getMRL CONSTANT);
+    Q_PROPERTY(unsigned int progress READ getProgress CONSTANT);
+    Q_PROPERTY(unsigned int playCount READ getPlayCount CONSTANT);
+
+public:
+    MLVideo(vlc_medialibrary_t *ml, const vlc_ml_media_t *data, QObject *parent = nullptr);
+
+    MLParentId getId() const;
+    QString getTitle() const;
+    QString getThumbnail();
+    QString getDuration() const;
+    QString getMRL() const;
+    unsigned int getProgress() const;
+    unsigned int getPlayCount() const;
+
+    MLVideo* clone(QObject* parent = nullptr) const;
+
+signals:
+    void onThumbnailChanged( QString );
+
+private:
+    MLVideo(const MLVideo& video, QObject* parent = nullptr);
+
+    static void onMlEvent( void* data, const vlc_ml_event_t* event );
+    void onMlEvent( const vlc_ml_event_t* event );
+
+
+    vlc_medialibrary_t* m_ml;
+    MLParentId m_id;
+    QString m_title;
+    QString m_thumbnail;
+    QString m_duration;
+    QString m_mrl;
+    unsigned int m_progress;
+    unsigned int m_playCount;
+    bool m_thumbnailGenerated;
+
+    std::unique_ptr<vlc_ml_event_callback_t,
+                    std::function<void(vlc_ml_event_callback_t*)>> m_ml_event_handle;
+};
+
+#endif // MLVIDEO_H
diff --git a/modules/gui/qt/components/mediacenter/mlvideomodel.cpp b/modules/gui/qt/components/mediacenter/mlvideomodel.cpp
new file mode 100644
index 0000000000..9c2b436874
--- /dev/null
+++ b/modules/gui/qt/components/mediacenter/mlvideomodel.cpp
@@ -0,0 +1,136 @@
+/*****************************************************************************
+ * Copyright (C) 2019 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * ( at your option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include "mlvideomodel.hpp"
+
+namespace {
+
+enum Role {
+    VIDEO_ID = Qt::UserRole + 1,
+    VIDEO_TITLE,
+    VIDEO_THUMBNAIL,
+    VIDEO_DURATION,
+    VIDEO_PROGRESS,
+    VIDEO_PLAYCOUNT,
+};
+
+}
+
+QHash<QByteArray, vlc_ml_sorting_criteria_t> MLVideoModel::M_names_to_criteria = {
+    {"id", VLC_ML_SORTING_DEFAULT},
+    {"title", VLC_ML_SORTING_ALPHA},
+    {"duration", VLC_ML_SORTING_DURATION},
+    {"playcount", VLC_ML_SORTING_PLAYCOUNT},
+};
+
+MLVideoModel::MLVideoModel(QObject* parent)
+    : MLSlidingWindowModel<MLVideo>(parent)
+{
+}
+
+QVariant MLVideoModel::data(const QModelIndex& index, int role) const
+{
+    const auto video = item(static_cast<unsigned int>(index.row()));
+    if ( video == nullptr )
+        return {};
+    switch (role)
+    {
+        case VIDEO_ID:
+            return QVariant::fromValue( video->getId() );
+        case VIDEO_TITLE:
+            return QVariant::fromValue( video->getTitle() );
+        case VIDEO_THUMBNAIL:
+            return QVariant::fromValue( video->getThumbnail() );
+        case VIDEO_DURATION:
+            return QVariant::fromValue( video->getDuration() );
+        case VIDEO_PROGRESS:
+            return QVariant::fromValue( video->getProgress() );
+        case VIDEO_PLAYCOUNT:
+            return QVariant::fromValue( video->getPlayCount() );
+        default:
+            return {};
+    }
+}
+
+QHash<int, QByteArray> MLVideoModel::roleNames() const
+{
+    return {
+        { VIDEO_ID, "id" },
+        { VIDEO_TITLE, "title" },
+        { VIDEO_THUMBNAIL, "thumbnail" },
+        { VIDEO_DURATION, "duration" },
+        { VIDEO_PROGRESS, "progress" },
+        { VIDEO_PLAYCOUNT, "playcount" },
+    };
+}
+
+std::vector<std::unique_ptr<MLVideo> > MLVideoModel::fetch()
+{
+    ml_unique_ptr<vlc_ml_media_list_t> media{ vlc_ml_list_video_media(
+                m_ml, &m_query_param ) };
+    if ( media == nullptr )
+        return {};
+    std::vector<std::unique_ptr<MLVideo>> res;
+    for( const vlc_ml_media_t& media: ml_range_iterate<vlc_ml_media_t>(media) )
+        res.emplace_back( std::unique_ptr<MLVideo>{ new MLVideo(m_ml, &media) } );
+    return res;
+}
+
+size_t MLVideoModel::countTotalElements() const
+{
+    vlc_ml_query_params_t params{};
+    return vlc_ml_count_video_media(m_ml, &params);
+}
+
+vlc_ml_sorting_criteria_t MLVideoModel::roleToCriteria(int role) const
+{
+    switch(role)
+    {
+        case VIDEO_TITLE:
+            return VLC_ML_SORTING_ALPHA;
+        case VIDEO_DURATION:
+            return VLC_ML_SORTING_DURATION;
+        case VIDEO_PLAYCOUNT:
+            return VLC_ML_SORTING_PLAYCOUNT;
+        default:
+            return VLC_ML_SORTING_DEFAULT;
+    }
+}
+
+vlc_ml_sorting_criteria_t MLVideoModel::nameToCriteria(QByteArray name) const
+{
+    return M_names_to_criteria.value(name, VLC_ML_SORTING_DEFAULT);
+}
+
+void MLVideoModel::onVlcMlEvent(const vlc_ml_event_t* event)
+{
+    switch (event->i_type)
+    {
+        case VLC_ML_EVENT_MEDIA_ADDED:
+        case VLC_ML_EVENT_MEDIA_UPDATED:
+            if ( event->modification.p_media->i_type == VLC_ML_MEDIA_TYPE_VIDEO )
+                m_need_reset = true;
+            break;
+        case VLC_ML_EVENT_MEDIA_DELETED:
+            m_need_reset = true;
+            break;
+        default:
+            break;
+    }
+    MLBaseModel::onVlcMlEvent( event );
+}
diff --git a/modules/gui/qt/components/mediacenter/mlvideomodel.hpp b/modules/gui/qt/components/mediacenter/mlvideomodel.hpp
new file mode 100644
index 0000000000..91e2d62fe1
--- /dev/null
+++ b/modules/gui/qt/components/mediacenter/mlvideomodel.hpp
@@ -0,0 +1,55 @@
+/*****************************************************************************
+ * Copyright (C) 2019 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * ( at your option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef MCVIDEOMODEL_H
+#define MCVIDEOMODEL_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_media_library.h>
+
+#include "mlbasemodel.hpp"
+#include "mlvideo.hpp"
+
+#include <QObject>
+
+class MLVideoModel : public MLSlidingWindowModel<MLVideo>
+{
+    Q_OBJECT
+
+public:
+    explicit MLVideoModel(QObject* parent = nullptr);
+    virtual ~MLVideoModel() = default;
+
+    QVariant data(const QModelIndex& index, int role) const override;
+    QHash<int, QByteArray> roleNames() const override;
+
+private:
+    std::vector<std::unique_ptr<MLVideo>> fetch() override;
+    size_t countTotalElements() const override;
+    vlc_ml_sorting_criteria_t roleToCriteria(int role) const override;
+    vlc_ml_sorting_criteria_t nameToCriteria(QByteArray name) const override;
+    virtual void onVlcMlEvent( const vlc_ml_event_t* event ) override;
+
+    static QHash<QByteArray, vlc_ml_sorting_criteria_t> M_names_to_criteria;
+};
+
+#endif // MCVIDEOMODEL_H
-- 
2.19.1



More information about the vlc-devel mailing list