Commit c2f60a04 authored by Harald Sitter's avatar Harald Sitter 🏳️‍🌈
Browse files

"fix" subtitle control in dragon player

It actually is more of a patch for the problem as the libphonon design is heavily flawed in that it exposes MediaController specific descriptors to the world also via the backend. Now as the Backend is a singleton but the MC is not, there is a bit of a scope problem... The present solution thus introduces a global overlord master subtitle manager where each MC needs to store its subtitles. Additionally libvlc seems broken as it reports completely bogus SPU ids \o/

The code at hand needs refactoring && bugfixing && cleanup && documentation && *whine*

BUG: 267424
parent 1f5947fe
......@@ -33,14 +33,19 @@ namespace Phonon
namespace VLC
{
template <typename D>
GlobalDescriptionContainer<D>* GlobalDescriptionContainer<D>::self = 0;
MediaController::MediaController()
: m_player(0)
{
GlobalSubtitles::instance()->register_(this);
resetMembers();
}
MediaController::~MediaController()
{
GlobalSubtitles::instance()->unregister_(this);
}
bool MediaController::hasInterface(Interface iface) const
......@@ -73,6 +78,7 @@ bool MediaController::hasInterface(Interface iface) const
QVariant MediaController::interfaceCall(Interface iface, int i_command, const QList<QVariant> & arguments)
{
DEBUG_BLOCK;
switch (iface) {
case AddonInterface::ChapterInterface:
switch (static_cast<AddonInterface::ChapterCommand>(i_command)) {
......@@ -205,7 +211,7 @@ void MediaController::resetMembers()
m_availableAudioChannels.clear();
m_currentSubtitle = Phonon::SubtitleDescription();
m_availableSubtitles.clear();
GlobalSubtitles::instance()->clearListFor(this);
m_currentAngle = 0;
m_availableAngles = 0;
......@@ -234,18 +240,6 @@ void MediaController::audioChannelAdded(int id, const QString &lang)
emit availableAudioChannelsChanged();
}
// Add subtitle
void MediaController::subtitleAdded(int id, const QString &lang, const QString &type)
{
QHash<QByteArray, QVariant> properties;
properties.insert("name", lang);
properties.insert("description", "");
properties.insert("type", type);
m_availableSubtitles << Phonon::SubtitleDescription(id, properties);
emit availableSubtitlesChanged();
}
// Add title
void MediaController::titleAdded(int id, const QString &name)
{
......@@ -307,11 +301,14 @@ void MediaController::refreshAudioChannels()
void MediaController::setCurrentSubtitle(const Phonon::SubtitleDescription &subtitle)
{
DEBUG_BLOCK;
m_currentSubtitle = subtitle;
// int id = current_subtitle.index();
QString type = m_currentSubtitle.property("type").toString();
#warning file stuff is untested and probably causes problems for globalsubtitles
if (type == "file") {
debug() << "file";
QString filename = m_currentSubtitle.property("name").toString();
if (!filename.isEmpty()) {
if (!libvlc_video_set_subtitle_file(m_player,
......@@ -320,11 +317,14 @@ void MediaController::setCurrentSubtitle(const Phonon::SubtitleDescription &subt
}
// There is no subtitle event inside libvlc so let's send our own event...
m_availableSubtitles << m_currentSubtitle;
GlobalSubtitles::instance()->add(this, m_currentSubtitle);
emit availableSubtitlesChanged();
}
} else {
if (libvlc_video_set_spu(m_player, subtitle.index())) {
debug() << "no file";
int localIndex = GlobalSubtitles::instance()->localIdFor(this, subtitle.index());
debug() << localIndex;
if (libvlc_video_set_spu(m_player, localIndex)) {
error() << "libVLC:" << LibVLC::errorMessage();
}
}
......@@ -332,7 +332,7 @@ void MediaController::setCurrentSubtitle(const Phonon::SubtitleDescription &subt
QList<Phonon::SubtitleDescription> MediaController::availableSubtitles() const
{
return m_availableSubtitles;
return GlobalSubtitles::instance()->listFor(this);
}
Phonon::SubtitleDescription MediaController::currentSubtitle() const
......@@ -342,12 +342,31 @@ Phonon::SubtitleDescription MediaController::currentSubtitle() const
void MediaController::refreshSubtitles()
{
DEBUG_BLOCK;
m_currentSubtitle = Phonon::SubtitleDescription();
m_availableSubtitles.clear();
GlobalSubtitles::instance()->clearListFor(this);
int idOffset = 0;
bool idSet = false;
libvlc_track_description_t *p_info = libvlc_video_get_spu_description(m_player);
while (p_info) {
subtitleAdded(p_info->i_id, p_info->psz_name, "");
#ifdef __GNUC__
#warning In the name of Kent Beck! libvlc is the broken...
#endif
int id = -1;
if (p_info->i_id == -1)
id = 0;
if (p_info->i_id > 0 && !idSet) {
idSet = true;
idOffset = p_info->i_id - 1;
debug() << idOffset;
}
if (id == -1)
id = p_info->i_id - idOffset;
GlobalSubtitles::instance()->add(this, id, p_info->psz_name, "");
p_info = p_info->p_next;
}
libvlc_track_description_release(p_info);
......@@ -409,7 +428,7 @@ int MediaController::currentChapter() const
}
// We need to rebuild available chapters when title is changed
void MediaController::refreshChapters(int i_title)
void MediaController::refreshChapters(int title)
{
// m_currentChapter = Phonon::ChapterDescription();
// m_availableChapters.clear();
......@@ -417,8 +436,7 @@ void MediaController::refreshChapters(int i_title)
m_availableChapters = 0;
// Get the description of available chapters for specific title
libvlc_track_description_t *p_info = libvlc_video_get_chapter_description(
m_player, i_title);
libvlc_track_description_t *p_info = libvlc_video_get_chapter_description(m_player, title);
while (p_info) {
chapterAdded(p_info->i_id, p_info->psz_name);
p_info = p_info->p_next;
......
......@@ -27,6 +27,8 @@
#include <phonon/addoninterface.h>
#include <phonon/objectdescription.h>
#include "debug.h"
struct libvlc_media_player_t;
namespace Phonon
......@@ -101,7 +103,7 @@ protected:
void setCurrentChapter(int chapterNumber);
int availableChapters() const;
int currentChapter() const;
void refreshChapters(int i_title);
void refreshChapters(int title);
// Title
// void setCurrentTitle( const Phonon::TitleDescription & title );
......@@ -133,7 +135,6 @@ protected:
QList<Phonon::AudioChannelDescription> m_availableAudioChannels;
Phonon::SubtitleDescription m_currentSubtitle;
QList<Phonon::SubtitleDescription> m_availableSubtitles;
// Phonon::ChapterDescription current_chapter;
// QList<Phonon::ChapterDescription> available_chapters;
......@@ -154,6 +155,170 @@ protected:
libvlc_media_player_t *m_player;
};
template <typename D>
class GlobalDescriptionContainer
{
typedef int global_id_t;
typedef int local_id_t;
typedef QMap<global_id_t, D> GlobalDescriptorMap;
typedef QMapIterator<global_id_t, D> GlobalDescriptorMapIterator;
typedef QMap<global_id_t, local_id_t> LocalIdMap;
typedef QMapIterator<global_id_t, local_id_t> LocaIdMapIterator;
public:
static GlobalDescriptionContainer *self;
static GlobalDescriptionContainer *instance()
{
if (!self)
self = new GlobalDescriptionContainer;
return self;
}
virtual ~GlobalDescriptionContainer() {}
QList<int> globalIndexes()
{
QList<int> list;
GlobalDescriptorMapIterator it(m_globalDescriptors);
while (it.hasNext()) {
it.next();
list << it.key();
}
return list;
}
SubtitleDescription fromIndex(global_id_t key)
{
return m_globalDescriptors.value(key, SubtitleDescription());
}
// ----------- MediaController Specific ----------- //
void register_(MediaController *mediaController)
{
Q_ASSERT(mediaController);
Q_ASSERT(m_localIds.find(mediaController) == m_localIds.end());
m_localIds[mediaController] = LocalIdMap();
}
void unregister_(MediaController *mediaController)
{
Q_ASSERT(mediaController);
Q_ASSERT(m_localIds.find(mediaController) != m_localIds.end());
m_localIds[mediaController] = LocalIdMap();
}
/**
* Clear the internal mapping of global to local id
*/
void clearListFor(MediaController *mediaController)
{
Q_ASSERT(mediaController);
Q_ASSERT(m_localIds.find(mediaController) != m_localIds.end());
m_localIds[mediaController].clear();
}
void add(MediaController *mediaController,
local_id_t index, const QString &name, const QString &type)
{
DEBUG_BLOCK;
Q_ASSERT(mediaController);
Q_ASSERT(m_localIds.find(mediaController) != m_localIds.end());
QHash<QByteArray, QVariant> properties;
properties.insert("name", name);
properties.insert("description", "");
properties.insert("type", type);
// Empty lists will start at 0.
global_id_t id = 0;
{
// Find id, either a descriptor with name and type is already present
// or get the next available index.
GlobalDescriptorMapIterator it(m_globalDescriptors);
while (it.hasNext()) {
it.next();
#ifdef __GNUC__
#warning make properties accessible
#endif
if (it.value().property("name") == name &&
it.value().property("type") == type) {
id = it.value().index();
} else {
id = nextFreeIndex();
}
}
}
debug() << "add: ";
debug() << "id: " << id;
debug() << " local: " << index;
debug() << " name: " << name;
debug() << " type: " << type;
D descriptor = D(id, properties);
m_globalDescriptors.insert(id, descriptor);
m_localIds[mediaController].insert(id, index);
}
void add(MediaController *mediaController,
D descriptor)
{
Q_ASSERT(mediaController);
Q_ASSERT(m_localIds.find(mediaController) != m_localIds.end());
Q_ASSERT(m_globalDescriptors.find(descriptor.index()) == m_globalDescriptors.end());
m_globalDescriptors.insert(descriptor.index(), descriptor);
m_localIds[mediaController].insert(descriptor.index(), descriptor.index());
}
QList<D> listFor(const MediaController *mediaController) const
{
Q_ASSERT(mediaController);
Q_ASSERT(m_localIds.find(mediaController) != m_localIds.end());
QList<D> list;
LocaIdMapIterator it(m_localIds.value(mediaController));
while (it.hasNext()) {
it.next();
Q_ASSERT(m_globalDescriptors.find(it.key()) != m_globalDescriptors.end());
list << m_globalDescriptors[it.key()];
}
return list;
}
int localIdFor(MediaController * mediaController, global_id_t key) const
{
Q_ASSERT(mediaController);
Q_ASSERT(m_localIds.find(mediaController) != m_localIds.end());
#ifdef __GNUC__
#warning localid fail not handled
#endif
return m_localIds[mediaController].value(key, 0);
}
protected:
GlobalDescriptionContainer() : m_peak(0) {}
global_id_t nextFreeIndex()
{
return ++m_peak;
}
// virtual void purifier() = 0;
GlobalDescriptorMap m_globalDescriptors;
QMap<const MediaController *, LocalIdMap> m_localIds;
global_id_t m_peak;
};
typedef GlobalDescriptionContainer<SubtitleDescription> GlobalSubtitles;
}
} // Namespace Phonon::VLC
......
Supports Markdown
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