mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-01 03:40:16 +02:00
First version using libvlc instead of phonon - added QIODevice support, less debug, no more segfault
This commit is contained in:
@@ -716,16 +716,14 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString
|
||||
// and Phonon handles the deletion of the
|
||||
// QNR_IODeviceStream object
|
||||
ioToKeep.clear();
|
||||
// TODO d->audioOutput->setAutoDelete( true );
|
||||
d->audioOutput->setAutoDelete( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
tLog() << "CASE 2";
|
||||
/* TODO
|
||||
d->audioOutput->setCurrentSource( io.data() );
|
||||
// We handle the deletion via tracking in d->input
|
||||
d->audioOutput->setAutoDelete( false );
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -758,9 +756,7 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString
|
||||
d->audioOutput->setCurrentSource( QUrl::fromLocalFile( furl ) );
|
||||
}
|
||||
|
||||
/* TODO
|
||||
d->audioOutput->setAutoDelete( true );
|
||||
*/
|
||||
}
|
||||
|
||||
if ( !d->input.isNull() )
|
||||
@@ -1251,6 +1247,8 @@ AudioEngine::currentTrackTotalTime() const
|
||||
{
|
||||
// TODO : This is too hacky. The problem is that I don't know why
|
||||
// libVLC doesn't report total duration for stream data (imem://)
|
||||
// But it's not a real problem for playback, since
|
||||
// EndOfStream is emitted by libVLC itself
|
||||
if ( d_func()->audioOutput->totalTime() == 0 && d_func()->currentTrack && d_func()->currentTrack->track() ) {
|
||||
return d_func()->currentTrack->track()->duration() * 1000 + 1000;
|
||||
}
|
||||
|
@@ -44,16 +44,6 @@ private:
|
||||
Tomahawk::playlistinterface_ptr queue;
|
||||
|
||||
AudioOutput* audioOutput;
|
||||
/*
|
||||
Phonon::MediaObject* mediaObject;
|
||||
Phonon::AudioOutput* audioOutput;
|
||||
|
||||
Phonon::Path audioPath;
|
||||
Phonon::Effect* audioEffect;
|
||||
|
||||
Phonon::AudioDataOutput* audioDataOutput;
|
||||
Phonon::Path audioDataPath;
|
||||
*/
|
||||
|
||||
unsigned int timeElapsed;
|
||||
bool expectStop;
|
||||
|
@@ -54,11 +54,15 @@ AudioOutput::AudioOutput( QObject* parent )
|
||||
: QObject( parent )
|
||||
, currentState( Stopped )
|
||||
, muted( false )
|
||||
, m_autoDelete ( true )
|
||||
, m_volume( 1.0 )
|
||||
, m_currentTime( 0 )
|
||||
, m_totalTime( 0 )
|
||||
, m_aboutToFinish( false )
|
||||
, dspPluginCallback( 0 )
|
||||
, vlcInstance( 0 )
|
||||
, vlcPlayer( 0 )
|
||||
, vlcMedia( 0 )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
|
||||
@@ -126,8 +130,6 @@ AudioOutput::AudioOutput( QObject* parent )
|
||||
libvlc_event_attach( manager, events[ i ], &AudioOutput::vlcEventCallback, this );
|
||||
}
|
||||
|
||||
|
||||
getchar();
|
||||
tDebug() << "AudioOutput::AudioOutput OK !\n";
|
||||
}
|
||||
|
||||
@@ -137,6 +139,13 @@ AudioOutput::~AudioOutput()
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioOutput::setAutoDelete ( bool ad )
|
||||
{
|
||||
m_autoDelete = ad;
|
||||
}
|
||||
|
||||
void
|
||||
AudioOutput::setCurrentSource(MediaStream stream)
|
||||
{
|
||||
@@ -150,6 +159,15 @@ AudioOutput::setCurrentSource(MediaStream* stream)
|
||||
|
||||
setState(Loading);
|
||||
|
||||
if ( vlcMedia != 0 ) {
|
||||
// Ensure playback is stopped, then release media
|
||||
libvlc_media_player_stop( vlcPlayer );
|
||||
libvlc_media_release( vlcMedia );
|
||||
vlcMedia = 0;
|
||||
}
|
||||
if ( m_autoDelete && currentStream != 0 ) {
|
||||
delete currentStream;
|
||||
}
|
||||
currentStream = stream;
|
||||
m_totalTime = 0;
|
||||
m_currentTime = 0;
|
||||
@@ -166,16 +184,18 @@ AudioOutput::setCurrentSource(MediaStream* stream)
|
||||
|
||||
case MediaStream::Url:
|
||||
tDebug() << "MediaStream::Url:" << stream->url();
|
||||
if (stream->url().scheme().isEmpty()) {
|
||||
if ( stream->url().scheme().isEmpty() ) {
|
||||
url = "file:///";
|
||||
if (stream->url().isRelative())
|
||||
url.append(QFile::encodeName(QDir::currentPath()) + '/');
|
||||
if ( stream->url().isRelative() ) {
|
||||
url.append( QFile::encodeName( QDir::currentPath() ) + '/' );
|
||||
}
|
||||
}
|
||||
url += stream->url().toEncoded();
|
||||
break;
|
||||
|
||||
case MediaStream::Stream:
|
||||
url = QByteArray("imem://");
|
||||
case MediaStream::IODevice:
|
||||
url = QByteArray( "imem://" );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -199,19 +219,13 @@ AudioOutput::setCurrentSource(MediaStream* stream)
|
||||
if ( stream->type() == MediaStream::Url ) {
|
||||
m_totalTime = libvlc_media_get_duration( vlcMedia );
|
||||
}
|
||||
else if ( stream->type() == MediaStream::Stream ) {
|
||||
else if ( stream->type() == MediaStream::Stream || stream->type() == MediaStream::IODevice ) {
|
||||
libvlc_media_add_option_flag(vlcMedia, "imem-cat=4", libvlc_media_option_trusted);
|
||||
libvlc_media_add_option_flag(vlcMedia, (QString("imem-data=") + QString::number((quint64)stream)).toUtf8().data(), libvlc_media_option_trusted);
|
||||
libvlc_media_add_option_flag(vlcMedia, (QString("imem-get=") + QString::number((quint64)&MediaStream::readCallback)).toUtf8().data(), libvlc_media_option_trusted);
|
||||
libvlc_media_add_option_flag(vlcMedia, (QString("imem-release=") + QString::number((quint64)&MediaStream::readDoneCallback)).toUtf8().data(), libvlc_media_option_trusted);
|
||||
libvlc_media_add_option_flag(vlcMedia, (QString("imem-seek=") + QString::number((quint64)&MediaStream::seekCallback)).toUtf8().data(), libvlc_media_option_trusted);
|
||||
}
|
||||
libvlc_media_add_option(vlcMedia, "audio-filter=dsp");
|
||||
libvlc_media_add_option(vlcMedia, ":audio-filter=dsp");
|
||||
libvlc_media_add_option(vlcMedia, "--audio-filter=dsp");
|
||||
libvlc_media_add_option(vlcMedia, "audio-filter dsp");
|
||||
libvlc_media_add_option(vlcMedia, ":audio-filter dsp");
|
||||
libvlc_media_add_option(vlcMedia, "--audio-filter dsp");
|
||||
|
||||
m_aboutToFinish = false;
|
||||
setState(Stopped);
|
||||
@@ -246,13 +260,16 @@ AudioOutput::currentTime()
|
||||
void
|
||||
AudioOutput::setCurrentTime( qint64 time )
|
||||
{
|
||||
m_currentTime = time;
|
||||
// TODO : This is a bit hacky, but m_totalTime is only used to determine
|
||||
// if we are about to finish
|
||||
if ( m_totalTime <= 0 ) {
|
||||
m_totalTime = AudioEngine::instance()->currentTrackTotalTime();
|
||||
}
|
||||
|
||||
m_currentTime = time;
|
||||
emit tick( time );
|
||||
|
||||
tDebug() << "Current time : " << m_currentTime << " / " << m_totalTime;
|
||||
// tDebug() << "Current time : " << m_currentTime << " / " << m_totalTime;
|
||||
|
||||
if ( time < m_totalTime - ABOUT_TO_FINISH_TIME ) {
|
||||
m_aboutToFinish = false;
|
||||
@@ -329,27 +346,13 @@ AudioOutput::seek( qint64 milliseconds )
|
||||
case Buffering:
|
||||
break;
|
||||
default:
|
||||
// Seeking while not being in a playingish state is cached for later.
|
||||
// TODO m_seekpoint = milliseconds;
|
||||
return;
|
||||
}
|
||||
|
||||
tDebug() << "AudioOutput:: seeking" << milliseconds << "msec";
|
||||
|
||||
libvlc_media_player_set_time ( vlcPlayer, milliseconds );
|
||||
/*
|
||||
const qint64 time = currentTime();
|
||||
const qint64 total = totalTime();
|
||||
*/
|
||||
/*
|
||||
// Reset last tick marker so we emit time even after seeking
|
||||
if (time < m_lastTick)
|
||||
m_lastTick = time;
|
||||
if (time < total - m_prefinishMark)
|
||||
m_prefinishEmitted = false;
|
||||
if (time < total - ABOUT_TO_FINISH_TIME)
|
||||
m_aboutToFinishEmitted = false;
|
||||
*/
|
||||
setCurrentTime( milliseconds );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -58,6 +58,7 @@ public:
|
||||
qreal volume();
|
||||
qint64 currentTime();
|
||||
qint64 totalTime();
|
||||
void setAutoDelete ( bool ad );
|
||||
|
||||
void setDspCallback( void ( *cb ) ( signed short*, int, int ) );
|
||||
|
||||
@@ -82,6 +83,7 @@ private:
|
||||
AudioState currentState;
|
||||
MediaStream* currentStream;
|
||||
bool muted;
|
||||
bool m_autoDelete;
|
||||
qreal m_volume;
|
||||
qint64 m_currentTime;
|
||||
qint64 m_totalTime;
|
||||
|
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#define BLOCK_SIZE 1048576
|
||||
|
||||
static QString s_aeInfoIdentifier = QString( "MEDIASTREAM" );
|
||||
|
||||
@@ -29,6 +30,7 @@ static QString s_aeInfoIdentifier = QString( "MEDIASTREAM" );
|
||||
MediaStream::MediaStream()
|
||||
: m_type( Unknown )
|
||||
, m_url( QUrl() )
|
||||
, m_ioDevice ( 0 )
|
||||
, m_eos( false )
|
||||
, m_pos( 0 )
|
||||
, m_streamSize( 0 )
|
||||
@@ -46,6 +48,15 @@ MediaStream::MediaStream( const QUrl &url )
|
||||
}
|
||||
|
||||
|
||||
MediaStream::MediaStream( QIODevice* device )
|
||||
: m_type(IODevice)
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
|
||||
m_ioDevice = device;
|
||||
}
|
||||
|
||||
|
||||
MediaStream::~MediaStream()
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
@@ -98,7 +109,7 @@ MediaStream::endOfData()
|
||||
int
|
||||
MediaStream::readCallback ( void* data, const char* cookie, int64_t* dts, int64_t* pts, unsigned* flags, size_t* bufferSize, void** buffer )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
// tDebug() << Q_FUNC_INFO;
|
||||
|
||||
Q_UNUSED(cookie);
|
||||
Q_UNUSED(dts);
|
||||
@@ -111,7 +122,16 @@ MediaStream::readCallback ( void* data, const char* cookie, int64_t* dts, int64_
|
||||
return -1;
|
||||
}
|
||||
|
||||
*bufferSize = that->needData(buffer);
|
||||
if ( that->m_type == Stream ) {
|
||||
*bufferSize = that->needData(buffer);
|
||||
}
|
||||
else if ( that->m_type == IODevice ) {
|
||||
QByteArray data = that->m_ioDevice->read(BLOCK_SIZE);
|
||||
*buffer = new char[data.size()];
|
||||
memcpy(*buffer, data.data(), data.size());
|
||||
*bufferSize = data.size();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -121,12 +141,16 @@ MediaStream::readDoneCallback ( void *data, const char *cookie, size_t bufferSiz
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
|
||||
Q_UNUSED(data);
|
||||
Q_UNUSED(cookie);
|
||||
Q_UNUSED(bufferSize);
|
||||
|
||||
// TODO : causes segfault
|
||||
// delete static_cast<char *>(buffer);
|
||||
MediaStream* that = static_cast < MediaStream * > ( data );
|
||||
|
||||
if ( ( that->m_type == Stream || that->m_type == IODevice ) && buffer != 0 && bufferSize > 0 ) {
|
||||
// TODO : causes segfault
|
||||
tDebug() << "buffer : " << buffer;
|
||||
delete static_cast<char *>(buffer);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -135,14 +159,18 @@ MediaStream::readDoneCallback ( void *data, const char *cookie, size_t bufferSiz
|
||||
int
|
||||
MediaStream::seekCallback ( void *data, const uint64_t pos )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
// tDebug() << Q_FUNC_INFO;
|
||||
|
||||
MediaStream* that = static_cast < MediaStream * > ( data );
|
||||
if ( static_cast < int64_t > ( pos ) > that->streamSize() ) {
|
||||
|
||||
if ( that->m_type == Stream && static_cast < int64_t > ( pos ) > that->streamSize() ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
that->m_pos = pos;
|
||||
if ( that->m_type == IODevice ) {
|
||||
that->m_ioDevice->seek(pos);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -28,15 +28,17 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <QUrl>
|
||||
#include <QIODevice>
|
||||
|
||||
class DLLEXPORT MediaStream
|
||||
{
|
||||
|
||||
public:
|
||||
enum MediaType { Unknown = -1, Empty = 0, Url = 1, Stream = 2 };
|
||||
enum MediaType { Unknown = -1, Empty = 0, Url = 1, Stream = 2, IODevice = 3 };
|
||||
|
||||
MediaStream();
|
||||
MediaStream( const QUrl &url );
|
||||
MediaStream( QIODevice* device );
|
||||
virtual ~MediaStream();
|
||||
|
||||
MediaType type();
|
||||
@@ -57,6 +59,7 @@ protected:
|
||||
|
||||
MediaType m_type;
|
||||
QUrl m_url;
|
||||
QIODevice* m_ioDevice;
|
||||
|
||||
bool m_eos;
|
||||
qint64 m_pos;
|
||||
|
Reference in New Issue
Block a user