Browse Source

qt: introduce DeviceSourcesProvider

helper class to get list of media sources
pull/162/head
Prince Gupta 2 years ago
committed by Jean-Baptiste Kempf
parent
commit
c5dc278f1f
  1. 3
      modules/gui/qt/Makefile.am
  2. 3
      modules/gui/qt/meson.build
  3. 228
      modules/gui/qt/network/devicesourceprovider.cpp
  4. 123
      modules/gui/qt/network/devicesourceprovider.hpp

3
modules/gui/qt/Makefile.am

@ -237,6 +237,8 @@ libqt_plugin_la_SOURCES = \
menus/menus.cpp menus/menus.hpp \
network/mediatreelistener.cpp \
network/mediatreelistener.hpp \
network/devicesourceprovider.cpp \
network/devicesourceprovider.hpp \
network/networkdevicemodel.cpp \
network/networkdevicemodel.hpp \
network/networksourcesmodel.cpp \
@ -422,6 +424,7 @@ nodist_libqt_plugin_la_SOURCES = \
menus/custom_menus.moc.cpp \
menus/qml_menu_wrapper.moc.cpp \
menus/menus.moc.cpp \
network/devicesourceprovider.moc.cpp \
network/networkdevicemodel.moc.cpp \
network/networksourcesmodel.moc.cpp \
network/networkmediamodel.moc.cpp \

3
modules/gui/qt/meson.build

@ -102,6 +102,7 @@ moc_headers = files(
'menus/custom_menus.hpp',
'menus/qml_menu_wrapper.hpp',
'menus/menus.hpp',
'network/devicesourceprovider.hpp',
'network/networkdevicemodel.hpp',
'network/networksourcesmodel.hpp',
'network/networkmediamodel.hpp',
@ -363,6 +364,8 @@ some_sources = files(
'menus/menus.hpp',
'network/mediatreelistener.cpp',
'network/mediatreelistener.hpp',
'network/devicesourceprovider.cpp',
'network/devicesourceprovider.hpp',
'network/networkdevicemodel.cpp',
'network/networkdevicemodel.hpp',
'network/networksourcesmodel.cpp',

228
modules/gui/qt/network/devicesourceprovider.cpp

@ -0,0 +1,228 @@
/*****************************************************************************
* Copyright (C) 2024 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 "devicesourceprovider.hpp"
#include "networkmediamodel.hpp"
//handle discovery events from the media source provider
struct DeviceSourceProvider::ListenerCb : public MediaTreeListener::MediaTreeListenerCb {
ListenerCb(DeviceSourceProvider* provider, NetworkDeviceModel::MediaSourcePtr mediaSource)
: provider(provider)
, mediaSource(std::move(mediaSource))
{}
inline void onItemPreparseEnded( MediaTreePtr, input_item_node_t *, enum input_item_preparse_status ) override final {}
void onItemCleared( MediaTreePtr tree, input_item_node_t* node ) override
{
if (node != &tree->root)
return;
refresh( node->pp_children, node->i_children, true);
}
void onItemAdded( MediaTreePtr tree, input_item_node_t* parent, input_item_node_t *const children[], size_t count ) override
{
if (parent != &tree->root)
return;
refresh( children, count, false );
}
void onItemRemoved( MediaTreePtr tree, input_item_node_t * node, input_item_node_t *const children[], size_t count ) override
{
if (node != &tree->root)
return;
std::vector<SharedInputItem> itemList;
itemList.reserve( count );
for ( auto i = 0u; i < count; ++i )
itemList.emplace_back( children[i]->p_item );
QMetaObject::invokeMethod(provider, [provider = this->provider,
itemList = std::move(itemList),
mediaSource = this->mediaSource]()
{
provider->removeItems(itemList, mediaSource);
});
}
void refresh(input_item_node_t * const children[], size_t count,
bool clear)
{
std::vector<SharedInputItem> itemList;
itemList.reserve(count);
for (size_t i = 0; i < count; i++)
itemList.emplace_back(children[i]->p_item);
QMetaObject::invokeMethod(provider, [provider = this->provider,
itemList = std::move(itemList),
mediaSource = this->mediaSource, clear]()
{
provider->addItems(itemList, mediaSource, clear);
});
}
DeviceSourceProvider *provider;
MediaSourcePtr mediaSource;
};
DeviceSourceProvider::DeviceSourceProvider(NetworkDeviceModel::SDCatType sdSource
, const QString &sourceName, QObject *parent)
: QObject(parent)
, m_sdSource {sdSource}
, m_sourceName {sourceName}
{
}
void DeviceSourceProvider::init(qt_intf_t *intf)
{
using SourceMetaPtr = std::unique_ptr<vlc_media_source_meta_list_t,
decltype( &vlc_media_source_meta_list_Delete )>;
auto libvlc = vlc_object_instance(intf);
auto provider = vlc_media_source_provider_Get( libvlc );
SourceMetaPtr providerList( vlc_media_source_provider_List(
provider,
static_cast<services_discovery_category_e>(m_sdSource) ),
&vlc_media_source_meta_list_Delete );
if (!providerList)
{
emit failed();
return;
}
size_t nbProviders = vlc_media_source_meta_list_Count( providerList.get() );
for ( auto i = 0u; i < nbProviders; ++i )
{
auto meta = vlc_media_source_meta_list_Get( providerList.get(), i );
const QString sourceName = qfu( meta->name );
if ( m_sourceName != '*' && m_sourceName != sourceName )
continue;
m_name += m_name.isEmpty() ? qfu( meta->longname ) : ", " + qfu( meta->longname );
MediaSourcePtr mediaSource(
vlc_media_source_provider_GetMediaSource(provider, meta->name)
, false );
if ( mediaSource == nullptr )
continue;
std::unique_ptr<MediaTreeListener> l{ new MediaTreeListener(
MediaTreePtr{ mediaSource->tree },
std::make_unique<DeviceSourceProvider::ListenerCb>(this, mediaSource) ) };
if ( l->listener == nullptr )
break;
m_mediaSources.push_back( std::move( mediaSource ) );
m_listeners.push_back( std::move( l ) );
}
if ( !m_name.isEmpty() )
emit nameUpdated( m_name );
if ( !m_listeners.empty() )
emit itemsUpdated( m_items );
else
emit failed();
}
void DeviceSourceProvider::addItems(const std::vector<SharedInputItem> &inputList,
const MediaSourcePtr &mediaSource, const bool clear)
{
bool dataChanged = false;
if (clear)
{
const qsizetype removed = m_items.removeIf([&mediaSource](const NetworkDeviceItemPtr &item)
{
return item->mediaSource == mediaSource;
});
if (removed > 0)
dataChanged = true;
}
for (const SharedInputItem & inputItem : inputList)
{
auto newItem = std::make_shared<NetworkDeviceItem>(inputItem, mediaSource);
auto it = m_items.find(newItem);
if (it != m_items.end())
{
(*it)->mrls.push_back(std::make_pair(newItem->mainMrl, mediaSource));
}
else
{
m_items.insert(std::move(newItem));
dataChanged = true;
}
}
if (dataChanged)
{
emit itemsUpdated(m_items);
}
}
void DeviceSourceProvider::removeItems(const std::vector<SharedInputItem> &inputList,
const MediaSourcePtr &mediaSource)
{
bool dataChanged = false;
for (const SharedInputItem& p_item : inputList)
{
auto oldItem = std::make_shared<NetworkDeviceItem>(p_item, mediaSource);
NetworkDeviceItemSet::iterator it = m_items.find(oldItem);
if (it != m_items.end())
{
bool found = false;
const NetworkDeviceItemPtr& item = *it;
if (item->mrls.size() > 1)
{
auto mrlIt = std::find_if(
item->mrls.begin(), item->mrls.end(),
[&oldItem]( const std::pair<QUrl, MediaSourcePtr>& mrl ) {
return mrl.first.matches(oldItem->mainMrl, QUrl::StripTrailingSlash)
&& mrl.second == oldItem->mediaSource;
});
if ( mrlIt != item->mrls.end() )
{
found = true;
item->mrls.erase( mrlIt );
}
}
if (!found)
{
m_items.erase(it);
dataChanged = true;
}
}
}
if (dataChanged)
emit itemsUpdated(m_items);
}

123
modules/gui/qt/network/devicesourceprovider.hpp

@ -0,0 +1,123 @@
/*****************************************************************************
* Copyright (C) 2024 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.
*****************************************************************************/
#pragma once
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "qt.hpp"
#include <QString>
#include <QSet>
#include <vector>
#include "networkdevicemodel.hpp"
#include "mediatreelistener.hpp"
//represents an entry of the model
struct NetworkDeviceItem
{
NetworkDeviceItem(const SharedInputItem& item, const NetworkDeviceModel::MediaSourcePtr& mediaSource)
: name(qfu(item->psz_name))
, mainMrl(QUrl::fromEncoded(item->psz_uri))
, protocol(mainMrl.scheme())
, type( static_cast<NetworkDeviceModel::ItemType>(item->i_type))
, mediaSource(mediaSource)
, inputItem(item)
{
id = qHash(name) ^ qHash(protocol);
mrls.push_back(std::make_pair(mainMrl, mediaSource));
char* artworkUrl = input_item_GetArtworkURL(inputItem.get());
if (artworkUrl)
{
artwork = QString::fromUtf8(artworkUrl);
free(artworkUrl);
}
}
uint id;
QString name;
QUrl mainMrl;
std::vector<std::pair<QUrl, NetworkDeviceModel::MediaSourcePtr>> mrls;
QString protocol;
NetworkDeviceModel::ItemType type;
NetworkDeviceModel::MediaSourcePtr mediaSource;
SharedInputItem inputItem;
QString artwork;
};
using NetworkDeviceItemPtr =std::shared_ptr<NetworkDeviceItem>;
static inline bool operator == (const NetworkDeviceItemPtr& a, const NetworkDeviceItemPtr& b) noexcept
{
return a->id == b->id
&& QString::compare(a->name, b->name, Qt::CaseInsensitive) == 0
&& QString::compare(a->protocol, b->protocol, Qt::CaseInsensitive) == 0;
}
static inline std::size_t qHash(const NetworkDeviceItemPtr& s, size_t = 0) noexcept
{
return s->id;
}
using NetworkDeviceItemSet = QSet<NetworkDeviceItemPtr>;
class DeviceSourceProvider : public QObject
{
Q_OBJECT
public:
using MediaSourcePtr = NetworkDeviceModel::MediaSourcePtr;
DeviceSourceProvider(NetworkDeviceModel::SDCatType sdSource,
const QString &sourceName,
QObject *parent = nullptr);
void init(qt_intf_t *intf);
signals:
void failed();
void nameUpdated( QString name );
void itemsUpdated( NetworkDeviceItemSet items );
private:
struct ListenerCb;
void addItems(const std::vector<SharedInputItem>& inputList,
const MediaSourcePtr& mediaSource,
bool clear);
void removeItems(const std::vector<SharedInputItem>& inputList,
const MediaSourcePtr& mediaSource);
NetworkDeviceModel::SDCatType m_sdSource;
QString m_sourceName; // '*' -> all sources
QString m_name; // source long name
NetworkDeviceItemSet m_items;
// destruction of listeners may cause destruction of source 'MediaSource'
// maintain a seperate reference of MediaSources to fix cyclic free
std::vector<MediaSourcePtr> m_mediaSources;
std::vector<std::unique_ptr<MediaTreeListener>> m_listeners;
};
Loading…
Cancel
Save