Files
youtube-playlist/lib/playlist-controller.hpp
Ruben Garcalia 81d9952fa3 Pues ahora hay doble buffer
Falta el hilo que descargue el video de youtube, que se dice mas pronto que se hace
2026-08-12 01:48:29 +02:00

226 lines
5.9 KiB
C++

#pragma once
#include "logger.hpp"
#include <QAudioOutput>
#include <QMediaPlayer>
#include <QObject>
#include <QUrl>
#include <algorithm>
#include <qcoreapplication.h>
#include <qtmetamacros.h>
#include <qtypes.h>
#include <qurl.h>
#include <string>
#include <vector>
class PlaylistController : public QObject {
Q_OBJECT
Q_PROPERTY(QObject *videoOutputA READ videoOutputA WRITE setVideoOutputA
NOTIFY videoOutputChangedA)
Q_PROPERTY(QObject *audioOutputA READ audioOutputA WRITE setAudioOutputA
NOTIFY audioOutputChangedA)
Q_PROPERTY(QObject *videoOutputB READ videoOutputB WRITE setVideoOutputB
NOTIFY videoOutputChanged)
Q_PROPERTY(QObject *audioOutputB READ audioOutputB WRITE setAudioOutputB
NOTIFY audioOutputChangedB)
Q_PROPERTY(QString playingState READ playingState NOTIFY playingStateChanged)
public:
explicit PlaylistController(QObject *parent = nullptr) : QObject(parent) {
m_playerA = new QMediaPlayer(this);
m_playerB = new QMediaPlayer(this);
m_activePlayer = m_playerA;
m_nextPlayer = m_playerB;
connect(m_playerA, &QMediaPlayer::mediaStatusChanged, this,
[this](QMediaPlayer::MediaStatus status) {
onMediaStatusChanged(m_playerA, status);
});
connect(m_playerB, &QMediaPlayer::mediaStatusChanged, this,
[this](QMediaPlayer::MediaStatus status) {
onMediaStatusChanged(m_playerB, status);
});
}
QObject *videoOutputA() const { return m_videoOutputA; }
QObject *videoOutputB() const { return m_videoOutputB; }
QObject *audioOutputA() const { return m_audioOutputA; }
QObject *audioOutputB() const { return m_audioOutputB; }
QString playingState() const { return m_playingState ? "playing" : "pause"; }
void setVideoOutputA(QObject *output) {
if (m_videoOutputA != output) {
m_videoOutputA = output;
if (m_videoOutputA) {
m_playerA->setVideoOutput(m_videoOutputA);
}
emit videoOutputChangedA();
}
}
void setAudioOutputA(QObject *output) {
if (m_audioOutputA != output) {
m_audioOutputA = output;
if (m_videoOutputA) {
if (auto *audio = qobject_cast<QAudioOutput *>(m_audioOutputA)) {
m_playerA->setAudioOutput(audio);
}
}
emit audioOutputChangedA();
}
}
void setVideoOutputB(QObject *output) {
if (m_videoOutputB != output) {
m_videoOutputB = output;
if (m_videoOutputB) {
m_playerB->setVideoOutput(m_videoOutputB);
}
emit videoOutputChangedB();
}
}
void setAudioOutputB(QObject *output) {
if (m_audioOutputB != output) {
m_audioOutputB = output;
if (m_videoOutputB) {
if (auto *audio = qobject_cast<QAudioOutput *>(m_audioOutputB)) {
m_playerB->setAudioOutput(audio);
}
}
emit audioOutputChangedB();
}
}
Q_INVOKABLE void prepareNext(const QUrl &url) {
// Desplegar hilo que descargue y gestione el mediaplayer
Logger::info(url.toString().toStdString());
m_nextPlayer->setSource(url);
// Para que se quede listo
m_nextPlayer->play();
m_nextPlayer->pause();
m_nextPlayer->setPosition(0);
}
Q_INVOKABLE void swapAndPlay() {
std::swap(m_activePlayer, m_nextPlayer);
m_activePlayer->play();
m_playingState = true;
// m_activePlayer->setPlaybackRate(1);
if (m_queue.size() - 1 > m_queue_index) {
prepareNext(QUrl::fromLocalFile(m_queue.at(m_queue_index + 1)));
}
}
Q_INVOKABLE void setVolume(float volume) {
if (auto *audio = qobject_cast<QAudioOutput *>(m_audioOutputA)) {
audio->setVolume(std::clamp(m_volume + volume, 0.0f, 1.0f));
}
if (auto *audio = qobject_cast<QAudioOutput *>(m_audioOutputB)) {
audio->setVolume(std::clamp(m_volume + volume, 0.0f, 1.0f));
}
}
Q_INVOKABLE void seek(long long time) {
m_activePlayer->setPosition(std::clamp(m_activePlayer->position() + time,
0ll, m_activePlayer->duration()));
}
Q_INVOKABLE void addToQueue(const QString &url) {
int n_ele = m_queue.size();
m_queue.push_back(url);
if (m_nextPlayer->source() == QUrl()) {
prepareNext(m_queue.at(m_queue_index));
}
}
Q_INVOKABLE void togglePause() {
m_playingState = !m_playingState;
if (!m_playingState)
m_activePlayer->pause();
else
m_activePlayer->play();
emit playingStateChanged();
}
signals:
void videoOutputChanged();
void videoOutputChangedA();
void audioOutputChangedA();
void videoOutputChangedB();
void audioOutputChangedB();
void playingStateChanged();
private:
std::vector<QString> m_queue = std::vector<QString>();
bool m_playing = false;
QMediaPlayer *m_playerA{nullptr};
QMediaPlayer *m_playerB{nullptr};
QMediaPlayer *m_activePlayer{nullptr};
QMediaPlayer *m_nextPlayer{nullptr};
QObject *m_videoOutputA{nullptr};
QObject *m_videoOutputB{nullptr};
QObject *m_audioOutputA{nullptr};
QObject *m_audioOutputB{nullptr};
float m_volume = 1;
bool m_playingState = false;
int m_queue_index = 0;
void onMediaStatusChanged(QMediaPlayer *player,
QMediaPlayer::MediaStatus status) {
bool isActive = (player == m_activePlayer);
switch (status) {
case QMediaPlayer::LoadedMedia:
Logger::info(isActive ? "Active media loaded"
: "Next media loaded and ready");
break;
case QMediaPlayer::BufferedMedia:
Logger::info("Media fully buffered");
if (!isActive) {
Logger::info("Next media fully buffered");
}
break;
case QMediaPlayer::EndOfMedia:
if (isActive) {
if (m_queue.size() - 1 > m_queue_index) {
m_queue_index++;
swapAndPlay();
}
}
break;
case QMediaPlayer::InvalidMedia:
Logger::error("Failed to load or play media");
break;
default:
break;
}
}
};