Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/gui/qt/medialibrary/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 16 kB image not shown  

Quelle  mlbookmarkmodel.cpp   Sprache: C

 

/*****************************************************************************
 * 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.
 *****************************************************************************/


#if HAVE_CONFIG_H
# include "config.h"
#endif

#include "mlbookmarkmodel.hpp"
#include "qt.hpp"

#include <vlc_cxx_helpers.hpp>

#include "medialib.hpp"
#include "mlhelper.hpp"

#include "util/shared_input_item.hpp"
#include "util/vlctick.hpp"
#include "player/player_controller.hpp"

MLBookmarkModel::MLBookmarkModel( QObject *parent )
    : QAbstractListModel( parent )
    , m_currentItem( nullptr, &input_item_Release )
    , m_ml_event_handle( nullptr, [this](vlc_ml_event_callback_t* cb ) {
        if (!cb)
            return;
        if ( m_mediaLib )
            m_mediaLib->unregisterEventListener(cb);
    })
{}

MLBookmarkModel::~MLBookmarkModel()
{
    if(m_player && m_listener){
        vlc_player_locker lock{ m_player };
        vlc_player_RemoveListener( m_player, m_listener );
    }
}

QVariant MLBookmarkModel::data( const QModelIndex &index, int role ) const
{
    if ( !index.isValid() || index.row() < 0 || m_player == nullptr ||
         !m_bookmarks || (uint32_t)index.row() >= m_bookmarks->i_nb_items )
        return QVariant{};

    const auto& bookmark = m_bookmarks->p_items[index.row()];

    if (role == Qt::DisplayRole || role == Qt::EditRole)
        role = columnToRole(index.column());

    switch(role){
        case BookmarkRoles::NameRole:
            return QVariant::fromValue( qfu( bookmark.psz_name ) );
        case BookmarkRoles::TimeRole:
            return QVariant::fromValue( VLCDuration::fromMS( bookmark.i_time ).formatHMS() );
        case BookmarkRoles::PositionRole:
        {
            vlc_player_locker lock{ m_player };
            return !vlc_player_GetLength( m_player ) ? QVariant{} :
                    QVariant::fromValue<float> ((float) VLC_TICK_FROM_MS(bookmark.i_time) / vlc_player_GetLength( m_player ));
        }
        case BookmarkRoles::DescriptionRole:
            return QVariant::fromValue( qfu( bookmark.psz_description ) );
        default:
            return QVariant{};
    }
}

bool MLBookmarkModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if ( index.isValid() == false )
        return false;
    if ( role == Qt::EditRole )
        role = columnToRole(index.column());
    if ( role != BookmarkRoles::NameRole && role != BookmarkRoles::DescriptionRole )
        return false;
    if ( value.canConvert<QString>() == false )
        return false;

    size_t row = index.row();
    bool updateName = (index.column() == 0);

    if ( ! m_bookmarks || row >= m_bookmarks->i_nb_items )
        return false;

    auto& b = m_bookmarks->p_items[row];
    auto str = value.toString();

    struct Ctx {
        bool updateSucceed;
    };
    m_mediaLib->runOnMLThread<Ctx>(this,
    //ML thread
    [mediaId = b.i_media_id, bookmarkTime = b.i_time, updateName, str]
    (vlc_medialibrary_t* ml, Ctx& ctx)
    {
        int ret;
        if ( updateName )
            ret = vlc_ml_media_update_bookmark( ml, mediaId, bookmarkTime, qtu( str ), nullptr );
        else
            ret = vlc_ml_media_update_bookmark( ml, mediaId, bookmarkTime, nullptr, qtu( str ) );
        ctx.updateSucceed = (ret == VLC_SUCCESS);
    },
    //UI thread
    [this, updateName, mediaId = m_currentMediaId, row, str]
    (quint64, Ctx& ctx)
    {
        if (!ctx.updateSucceed)
            return;

        if (m_currentMediaId != mediaId)
            return;

        auto& b = m_bookmarks->p_items[row];
        if (updateName)
        {
            free( b.psz_name );
            b.psz_name = strdup( qtu( str ) );
            emit dataChanged(this->index(row, 0), this->index(row, 0),
                             {Qt::DisplayRole, BookmarkRoles::NameRole});
        }
        else
        {
            free( b.psz_description );
            b.psz_description = strdup( qtu( str ) );
            emit dataChanged(this->index(row, 2), this->index(row, 2),
                             {Qt::DisplayRole, BookmarkRoles::DescriptionRole});
        }
    });

    return true;
}

QHash<int, QByteArray> MLBookmarkModel::roleNames() const{
    return QHash<int, QByteArray>{
        {BookmarkRoles::NameRole, QByteArrayLiteral("name")},
        {BookmarkRoles::TimeRole, QByteArrayLiteral("time")},
        {BookmarkRoles::PositionRole, QByteArrayLiteral("position")},
        {BookmarkRoles::DescriptionRole, QByteArrayLiteral("description")}
    };
}

int MLBookmarkModel::columnToRole(int column) const{
    switch (column)
    {
      case 0:
         return BookmarkRoles::NameRole;
      case 1:
         return BookmarkRoles::TimeRole;
      case 2:
        return BookmarkRoles::DescriptionRole;
      default:
         return -1;
    }
}

Qt::ItemFlags MLBookmarkModel::flags( const QModelIndex& index ) const
{
    auto f = QAbstractItemModel::flags( index );
    if ( index.column() != 1 )
        f |= Qt::ItemIsEditable;
    return f;
}

int MLBookmarkModel::rowCount(const QModelIndex &) const
{
    if ( m_bookmarks == nullptr )
        return 0;
    return m_bookmarks->i_nb_items;
}

int MLBookmarkModel::columnCount(const QModelIndex &) const
{
    return 3;
}

QModelIndex MLBookmarkModel::index( int row, int column, const QModelIndex& ) const
{
    return createIndex( row, column, nullptr );
}

QModelIndex MLBookmarkModel::parent(const QModelIndex &) const
{
    return createIndex( -1, -1, nullptr );
}

QVariant MLBookmarkModel::headerData( int section, Qt::Orientation orientation,
                                      int role ) const
{
    if (role != Qt::DisplayRole || orientation == Qt::Vertical)
        return QVariant{};

    switch ( section )
    {
        case 0:
            return QVariant::fromValue( qtr( "Name" ) );
        case 1:
            return QVariant::fromValue( qtr( "Time" ) );
        case 2:
            return QVariant::fromValue( qtr( "Description" ) );
        default:
            return QVariant{};
    }
}

void MLBookmarkModel::sort( int column, Qt::SortOrder order )
{
    switch ( column )
    {
        case 0:
            m_sort = VLC_ML_SORTING_ALPHA;
            break;
        case 1:
            // For bookmarks, default sort order is their time in the media
            m_sort = VLC_ML_SORTING_DEFAULT;
            break;
        case 2:
            // We don't support ordering by description, just ignore it
            return;
        default:
            // In all other cases, just list the items as they are inserted
            m_sort = VLC_ML_SORTING_INSERTIONDATE;
            break;
    }
    m_desc = order == Qt::DescendingOrder ? true : false;
    refresh( MLBOOKMARKMODEL_REFRESH );
}

void MLBookmarkModel::add()
{
    vlc_tick_t currentTime;
    {
        vlc_player_locker lock{ m_player };
        currentTime = vlc_player_GetTime( m_player );
    }

    if (m_currentMediaId == 0)
        return;

    m_mediaLib->runOnMLThread(this,
    //ML thread
    [mediaId = m_currentMediaId, currentTime, count = rowCount()](vlc_medialibrary_t* ml)
    {
        int64_t time = MS_FROM_VLC_TICK(currentTime);

        vlc_ml_media_add_bookmark(ml, mediaId, time);

        ml_unique_ptr<vlc_ml_media_t> media { vlc_ml_get_media(ml, mediaId) };

        if (media)
        {
            QString name = qtr("Bookmark at %1").arg(VLCDuration::fromMS( time ).formatHMS());

            vlc_ml_media_update_bookmark(ml, mediaId, time, qtu(name), nullptr);
        }
    },
    //UI thread
    [this](){
        refresh( MLBOOKMARKMODEL_REFRESH );
    });
}

void MLBookmarkModel::remove( const QModelIndexList &indexes )
{
    if (m_currentMediaId == 0)
        return;

    std::vector<int64_t> bookmarkTimeList;
    for ( const auto& i : indexes )
    {
        if ( i.isValid() == false || (size_t)i.row() >= m_bookmarks->i_nb_items )
            continue;
        auto& b = m_bookmarks->p_items[i.row()];
        bookmarkTimeList.push_back(b.i_time);
    }

    m_mediaLib->runOnMLThread(this,
    //ML thread
    [mediaId = m_currentMediaId, bookmarkTimeList]
    (vlc_medialibrary_t* ml)
    {
        for (int64_t bookmarkTime : bookmarkTimeList)
            vlc_ml_media_remove_bookmark(ml, mediaId, bookmarkTime);
    },
    //UI thread
    [this](){
        refresh( MLBOOKMARKMODEL_REFRESH );
    });
}

void MLBookmarkModel::clear()
{
    if (m_currentMediaId == 0)
        return;

    m_mediaLib->runOnMLThread(this,
    //ML thread
    [mediaId = m_currentMediaId](vlc_medialibrary_t* ml)
    {
        vlc_ml_media_remove_all_bookmarks( ml, mediaId );
    },
    //UI thread
    [this, mediaId = m_currentMediaId]()
    {
        if (mediaId == m_currentMediaId)
        {
            beginResetModel();
            m_bookmarks.reset();
            endResetModel();
        }
    });
}

void MLBookmarkModel::select(const QModelIndex &index)
{
    if ( index.isValid() == false )
        return;
    const auto& b = m_bookmarks->p_items[index.row()];
    vlc_player_locker lock{ m_player };
    vlc_player_SetTime( m_player, VLC_TICK_FROM_MS( b.i_time ) );
}

void MLBookmarkModel::onCurrentMediaChanged( vlc_player_t*, input_item_t* media,
                                             void *data )
{
    //Player thread
    auto self = static_cast<MLBookmarkModel*>( data );
    SharedInputItem item(media, true);
    QString mediaUri;
    uint64_t revision;
    {
        vlc::threads::mutex_locker lock{ self->m_mutex };
        self->m_currentItem.reset( media ? input_item_Hold( media ) : nullptr );
        revision = ++self->m_revision;
        if (media)
            mediaUri = media->psz_uri;
    }

    //UI Thread
    QMetaObject::invokeMethod(self,
    [self, revision, mediaUri]()
    {
        {
            vlc::threads::mutex_locker lock{ self->m_mutex };
            //did we start playing a new media in between
            if (self->m_revision != revision)
                return;
        }
        self->updateMediaId(revision, mediaUri);
    });
}

void MLBookmarkModel::onPlaybackStateChanged( vlc_player_t *, vlc_player_state state,
                                              void *data )
{
    auto self = static_cast<MLBookmarkModel*>( data );

    if(self->m_currentMediaId == 0)
        return;

    QMetaObject::invokeMethod(self, [self, state](){
        if ( state == VLC_PLAYER_STATE_STARTED )
            self->refresh( MLBOOKMARKMODEL_REFRESH );
        else if ( state == VLC_PLAYER_STATE_STOPPING )
            self->refresh( MLBOOKMARKMODEL_CLEAR );
    });
}


void MLBookmarkModel::updateMediaId(uint64_t revision, const QString &mediaUri)
{
    if (mediaUri.isEmpty())
    {
        refresh(MLBOOKMARKMODEL_CLEAR);
        return;
    }

    //retrieve the media id in the medialib
    struct Ctx{
        uint64_t newMLid = 0;
        BookmarkListPtr newBookmarks;
    };
    m_mediaLib->runOnMLThread<Ctx>(this,
    //ML thread
    [mediaUri, sort = m_sort, desc = m_desc](vlc_medialibrary_t* ml, Ctx& ctx){

        auto mlMedia = vlc_ml_get_media_by_mrl( ml, qtu(mediaUri) );
        if ( mlMedia != nullptr )
        {
            ctx.newMLid = mlMedia->i_id;
            vlc_ml_release( mlMedia );
        }
        vlc_ml_query_params_t params = vlc_ml_query_params_create();
        params.i_sort = sort;
        params.b_desc = desc;
        ctx.newBookmarks.reset( vlc_ml_list_media_bookmarks( ml, ¶ms, ctx.newMLid ) );
    },
    //UI thread
    [this, revision](quint64, Ctx& ctx) {
        bool valid;
        {
            vlc::threads::mutex_locker lock{ m_mutex };
            //did we start playing a new media in between
            valid = (m_revision == revision);
        }
        if (valid)
        {
            beginResetModel();
            m_bookmarks = std::move(ctx.newBookmarks);
            m_currentMediaId = ctx.newMLid;
            refresh(MLBOOKMARKMODEL_REFRESH);
            endResetModel();
        }
    });
}

void MLBookmarkModel::refresh(MLBookmarkModel::RefreshOperation forceClear )
{
    if (m_currentMediaId == 0 || forceClear == MLBOOKMARKMODEL_CLEAR)
    {
        beginResetModel();
        m_bookmarks.reset();
        endResetModel();
    }
    else
    {
        uint64_t mediaId = m_currentMediaId;
        struct Ctx
        {
            BookmarkListPtr newBookmarks;
        };
        m_mediaLib->runOnMLThread<Ctx>(this,
        //ML thread
        [mediaId, sort = m_sort, desc = m_desc]
        (vlc_medialibrary_t* ml, Ctx& ctx) {
            vlc_ml_query_params_t params = vlc_ml_query_params_create();
            params.i_sort = sort;
            params.b_desc = desc;
            ctx.newBookmarks.reset( vlc_ml_list_media_bookmarks( ml, ¶ms, mediaId ) );
        },
        //UI thread
        [this, mediaId](quint64, Ctx& ctx)
        {
            beginResetModel();
            if (m_currentMediaId == mediaId)
                m_bookmarks = std::move(ctx.newBookmarks);
            else
                m_bookmarks.reset();
            endResetModel();
        });
    }
}

vlc_player_t * MLBookmarkModel::player() const
{
    return m_player;
}

void MLBookmarkModel::setPlayer(vlc_player_t * player)
{
    if (m_player == player) return;

    if(m_player && m_listener){
        vlc_player_locker lock{ m_player };
        vlc_player_RemoveListener( m_player, m_listener );
    }

    m_player = player;

    if (m_player && m_mediaLib)
        initModel();
}


PlayerController * MLBookmarkModel::playerController() const
{
    return m_player_controller;
}

void MLBookmarkModel::setPlayer(PlayerController * player)
{
    if (m_player_controller == player) return;

    if (m_player_controller)
        disconnect(m_player_controller, nullptr, this, nullptr);

    m_player_controller = player;

    connect(m_player_controller, &PlayerController::lengthChanged, this, &MLBookmarkModel::playerLengthChanged);

    setPlayer(player->getPlayer());
}

MediaLib* MLBookmarkModel::ml() const
{
    return m_mediaLib;
}

void MLBookmarkModel::playerLengthChanged()
{
    refresh(MLBOOKMARKMODEL_REFRESH);
}

void MLBookmarkModel::setMl(MediaLib* medialib)
{
    if(m_mediaLib == medialib) return;

    if(m_mediaLib)
        m_ml_event_handle.reset(nullptr);

    m_mediaLib = medialib;

    if (m_player && m_mediaLib)
        initModel();
}

void MLBookmarkModel::initModel()
{
    static const vlc_player_cbs cbs = []{
        vlc_player_cbs cbs {};
        cbs.on_current_media_changed = &onCurrentMediaChanged;
        cbs.on_state_changed = &onPlaybackStateChanged;
        return cbs;
    }();
    QString uri;
    {
        vlc_player_locker lock{ m_player };
        vlc::threads::mutex_locker selflock{ m_mutex };
        m_listener = vlc_player_AddListener( m_player, &cbs, this );
        if ( m_listener == nullptr )
            throw std::bad_alloc{};
        auto currentItem = vlc_player_GetCurrentMedia( m_player );
        m_currentItem = vlc::wrap_cptr( currentItem ? input_item_Hold( currentItem ) : nullptr,
                                        &input_item_Release );
        if (m_currentItem)
        {
            uri = m_currentItem->psz_uri;
        }
    }
    updateMediaId(0, uri);

    if (m_ml_event_handle == nullptr)
        m_ml_event_handle.reset(m_mediaLib->registerEventListener(onVlcMlEvent, this));
}

void MLBookmarkModel::onVlcMlEvent(void* data, const vlc_ml_event_t* event)
{
    auto self = static_cast<MLBookmarkModel*>(data);
    auto  mlEvent = std::make_shared<MLEvent>(event);
    QMetaObject::invokeMethod(self, [self, mlEvent] () mutable {
        self->onVlcMlEvent(*mlEvent);
    });
}

void MLBookmarkModel::onVlcMlEvent(const MLEvent &event){
    switch (event.i_type)
    {
        case VLC_ML_EVENT_BOOKMARKS_ADDED:
        case VLC_ML_EVENT_BOOKMARKS_DELETED:
        case VLC_ML_EVENT_BOOKMARKS_UPDATED:
            refresh(MLBOOKMARKMODEL_REFRESH);
        break;
        default:
            break;
    }
}

Messung
CHZG
851009392

¤ Dauer der Verarbeitung: 0.9 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.