Add stream discoverer to gstreamer pipeline and continuous updating of bitrate

This commit is contained in:
Jonas Kvinge
2019-09-07 23:34:13 +02:00
parent 8962644ba8
commit e45a0bf24b
33 changed files with 281 additions and 176 deletions

View File

@@ -59,11 +59,11 @@ Engine::Base::Base()
Engine::Base::~Base() {}
bool Engine::Base::Load(const QUrl &media_url, const QUrl &original_url, TrackChangeFlags, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
bool Engine::Base::Load(const QUrl &stream_url, const QUrl &original_url, TrackChangeFlags, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
Q_UNUSED(force_stop_at_end);
media_url_ = media_url;
stream_url_ = stream_url;
original_url_ = original_url;
beginning_nanosec_ = beginning_nanosec;
end_nanosec_ = end_nanosec;
@@ -73,9 +73,9 @@ bool Engine::Base::Load(const QUrl &media_url, const QUrl &original_url, TrackCh
}
bool Engine::Base::Play(const QUrl &media_url, const QUrl &original_url, TrackChangeFlags flags, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
bool Engine::Base::Play(const QUrl &stream_url, const QUrl &original_url, TrackChangeFlags flags, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
if (!Load(media_url, original_url, flags, force_stop_at_end, beginning_nanosec, end_nanosec))
if (!Load(stream_url, original_url, flags, force_stop_at_end, beginning_nanosec, end_nanosec))
return false;
return Play(0);

View File

@@ -69,8 +69,8 @@ public:
virtual bool Init() = 0;
virtual State state() const = 0;
virtual void StartPreloading(const QUrl &media_url, const QUrl &original_url, bool, qint64, qint64) {}
virtual bool Load(const QUrl &media_url, const QUrl &original_url, TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
virtual void StartPreloading(const QUrl &stream_url, const QUrl &original_url, bool, qint64, qint64) {}
virtual bool Load(const QUrl &stream_url, const QUrl &original_url, TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
virtual bool Play(quint64 offset_nanosec) = 0;
virtual void Stop(bool stop_after = false) = 0;
virtual void Pause() = 0;
@@ -98,7 +98,7 @@ public:
// Plays a media stream represented with the URL 'u' from the given 'beginning' to the given 'end' (usually from 0 to a song's length).
// Both markers should be passed in nanoseconds. 'end' can be negative, indicating that the real length of 'u' stream is unknown.
bool Play(const QUrl &media_url, const QUrl &original_url, TrackChangeFlags c, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
bool Play(const QUrl &stream_url, const QUrl &original_url, TrackChangeFlags c, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
void SetVolume(uint value);
static uint MakeVolumeLogarithmic(uint volume);
@@ -168,7 +168,7 @@ signals:
uint volume_;
quint64 beginning_nanosec_;
qint64 end_nanosec_;
QUrl media_url_;
QUrl stream_url_;
QUrl original_url_;
Scope scope_;
bool buffering_;
@@ -206,8 +206,10 @@ private:
};
struct SimpleMetaBundle {
SimpleMetaBundle() : length(-1), year(-1), track(-1), samplerate(-1), bitdepth(-1) {}
SimpleMetaBundle() : minor(true), length(-1), year(-1), track(-1), samplerate(-1), bitdepth(-1) {}
QUrl url;
QUrl stream_url;
bool minor;
QString title;
QString artist;
QString album;

View File

@@ -114,7 +114,7 @@ bool GstEngine::Init() {
Engine::State GstEngine::state() const {
if (!current_pipeline_) return media_url_.isEmpty() ? Engine::Empty : Engine::Idle;
if (!current_pipeline_) return stream_url_.isEmpty() ? Engine::Empty : Engine::Idle;
switch (current_pipeline_->state()) {
case GST_STATE_NULL:
@@ -131,11 +131,11 @@ Engine::State GstEngine::state() const {
}
void GstEngine::StartPreloading(const QUrl &media_url, const QUrl &original_url, bool force_stop_at_end, qint64 beginning_nanosec, qint64 end_nanosec) {
void GstEngine::StartPreloading(const QUrl &stream_url, const QUrl &original_url, bool force_stop_at_end, qint64 beginning_nanosec, qint64 end_nanosec) {
EnsureInitialised();
QByteArray gst_url = FixupUrl(media_url);
QByteArray gst_url = FixupUrl(stream_url);
// No crossfading, so we can just queue the new URL in the existing pipeline and get gapless playback (hopefully)
if (current_pipeline_)
@@ -143,20 +143,20 @@ void GstEngine::StartPreloading(const QUrl &media_url, const QUrl &original_url,
}
bool GstEngine::Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
bool GstEngine::Load(const QUrl &stream_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
EnsureInitialised();
Engine::Base::Load(media_url, original_url, change, force_stop_at_end, beginning_nanosec, end_nanosec);
Engine::Base::Load(stream_url, original_url, change, force_stop_at_end, beginning_nanosec, end_nanosec);
QByteArray gst_url = FixupUrl(media_url);
QByteArray gst_url = FixupUrl(stream_url);
bool crossfade = current_pipeline_ && ((crossfade_enabled_ && change & Engine::Manual) || (autocrossfade_enabled_ && change & Engine::Auto) || ((crossfade_enabled_ || autocrossfade_enabled_) && change & Engine::Intro));
if (change & Engine::Auto && change & Engine::SameAlbum && !crossfade_same_album_)
crossfade = false;
if (!crossfade && current_pipeline_ && current_pipeline_->media_url() == gst_url && change & Engine::Auto) {
if (!crossfade && current_pipeline_ && current_pipeline_->stream_url() == gst_url && change & Engine::Auto) {
// We're not crossfading, and the pipeline is already playing the URI we want, so just do nothing.
return true;
}
@@ -202,7 +202,7 @@ void GstEngine::Stop(bool stop_after) {
StopTimers();
media_url_ = QUrl(); // To ensure we return Empty from state()
stream_url_ = QUrl(); // To ensure we return Empty from state()
original_url_ = QUrl();
beginning_nanosec_ = end_nanosec_ = 0;
@@ -503,7 +503,7 @@ void GstEngine::HandlePipelineError(int pipeline_id, const QString &message, int
emit StateChanged(Engine::Error);
if (domain == GST_RESOURCE_ERROR && (error_code == GST_RESOURCE_ERROR_NOT_FOUND || error_code == GST_RESOURCE_ERROR_NOT_AUTHORIZED)) {
emit InvalidSongRequested(media_url_);
emit InvalidSongRequested(stream_url_);
}
else {
emit FatalError();
@@ -515,10 +515,9 @@ void GstEngine::HandlePipelineError(int pipeline_id, const QString &message, int
void GstEngine::NewMetaData(int pipeline_id, const Engine::SimpleMetaBundle &bundle) {
if (!current_pipeline_.get() || current_pipeline_->id() != pipeline_id)
return;
if (!current_pipeline_.get() || current_pipeline_->id() != pipeline_id) return;
emit MetaData(bundle);
}
void GstEngine::AddBufferToScope(GstBuffer *buf, int pipeline_id) {
@@ -581,7 +580,7 @@ void GstEngine::PlayDone(QFuture<GstStateChangeReturn> future, const quint64 off
if (ret == GST_STATE_CHANGE_FAILURE) {
// Failure, but we got a redirection URL - try loading that instead
QByteArray redirect_url = current_pipeline_->redirect_url();
if (!redirect_url.isEmpty() && redirect_url != current_pipeline_->media_url()) {
if (!redirect_url.isEmpty() && redirect_url != current_pipeline_->stream_url()) {
qLog(Info) << "Redirecting to" << redirect_url;
current_pipeline_ = CreatePipeline(redirect_url, current_pipeline_->original_url(), end_nanosec_);
Play(offset_nanosec);
@@ -604,7 +603,7 @@ void GstEngine::PlayDone(QFuture<GstStateChangeReturn> future, const quint64 off
emit StateChanged(Engine::Playing);
// We've successfully started playing a media stream with this url
emit ValidSongRequested(media_url_);
emit ValidSongRequested(stream_url_);
}

View File

@@ -69,8 +69,8 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
bool Init();
Engine::State state() const;
void StartPreloading(const QUrl &media_url, const QUrl &original_url, bool force_stop_at_end, qint64 beginning_nanosec, qint64 end_nanosec);
bool Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
void StartPreloading(const QUrl &stream_url, const QUrl &original_url, bool force_stop_at_end, qint64 beginning_nanosec, qint64 end_nanosec);
bool Load(const QUrl &stream_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
bool Play(quint64 offset_nanosec);
void Stop(bool stop_after = false);
void Pause();

View File

@@ -25,6 +25,7 @@
#include <glib.h>
#include <glib-object.h>
#include <gst/gst.h>
#include <gst/pbutils/pbutils.h>
#include <QtGlobal>
#include <QObject>
@@ -51,6 +52,7 @@
const int GstEnginePipeline::kGstStateTimeoutNanosecs = 10000000;
const int GstEnginePipeline::kFaderFudgeMsec = 2000;
const int GstEnginePipeline::kDiscoveryTimeoutS = 10;
const int GstEnginePipeline::kEqBandCount = 10;
const int GstEnginePipeline::kEqBandFrequencies[] = { 60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000 };
@@ -102,7 +104,8 @@ GstEnginePipeline::GstEnginePipeline(GstEngine *engine)
equalizer_preamp_(nullptr),
equalizer_(nullptr),
rgvolume_(nullptr),
rglimiter_(nullptr)
rglimiter_(nullptr),
discoverer_(nullptr)
{
if (!sElementDeleter) {
@@ -122,6 +125,11 @@ GstEnginePipeline::~GstEnginePipeline() {
gst_object_unref(GST_OBJECT(pipeline_));
}
if (discoverer_) {
gst_discoverer_stop(discoverer_);
g_object_unref(discoverer_);
}
}
void GstEnginePipeline::set_output_device(const QString &output, const QVariant &device) {
@@ -403,6 +411,11 @@ bool GstEnginePipeline::InitAudioBin() {
bus_cb_id_ = gst_bus_add_watch(bus, BusCallback, this);
gst_object_unref(bus);
// Add request to discover the stream
if (!gst_discoverer_discover_uri_async(discoverer_, stream_url_.toStdString().c_str())) {
qLog(Error) << "Failed to start stream discovery for" << stream_url_;
}
return true;
}
@@ -415,22 +428,29 @@ bool GstEnginePipeline::InitFromString(const QString &pipeline) {
}
bool GstEnginePipeline::InitFromUrl(const QByteArray &media_url, const QUrl original_url, qint64 end_nanosec) {
bool GstEnginePipeline::InitFromUrl(const QByteArray &stream_url, const QUrl original_url, qint64 end_nanosec) {
media_url_ = media_url;
stream_url_ = stream_url;
original_url_ = original_url;
end_offset_nanosec_ = end_nanosec;
pipeline_ = engine_->CreateElement("playbin");
if (!pipeline_) return false;
g_object_set(G_OBJECT(pipeline_), "uri", media_url.constData(), nullptr);
g_object_set(G_OBJECT(pipeline_), "uri", stream_url.constData(), nullptr);
CHECKED_GCONNECT(G_OBJECT(pipeline_), "about-to-finish", &AboutToFinishCallback, this);
CHECKED_GCONNECT(G_OBJECT(pipeline_), "pad-added", &NewPadCallback, this);
CHECKED_GCONNECT(G_OBJECT(pipeline_), "notify::source", &SourceSetupCallback, this);
// Setting up a discoverer
discoverer_ = gst_discoverer_new(kDiscoveryTimeoutS * GST_SECOND, NULL);
if (!discoverer_) return false;
CHECKED_GCONNECT(G_OBJECT(discoverer_), "discovered", &StreamDiscovered, this);
CHECKED_GCONNECT(G_OBJECT(discoverer_), "finished", &StreamDiscoveryFinished, this);
gst_discoverer_start(discoverer_);
if (!InitAudioBin()) return false;
// Set playbin's sink to be our costum audio-sink.
@@ -536,10 +556,10 @@ void GstEnginePipeline::StreamStartMessageReceived() {
if (next_uri_set_) {
next_uri_set_ = false;
media_url_ = next_media_url_;
stream_url_ = next_stream_url_;
original_url_ = next_original_url_;
end_offset_nanosec_ = next_end_offset_nanosec_;
next_media_url_ = QByteArray();
next_stream_url_ = QByteArray();
next_original_url_ = QUrl();
next_beginning_offset_nanosec_ = 0;
next_end_offset_nanosec_ = 0;
@@ -613,6 +633,8 @@ void GstEnginePipeline::ErrorMessageReceived(GstMessage *msg) {
void GstEnginePipeline::TagMessageReceived(GstMessage *msg) {
if (ignore_tags_) return;
GstTagList *taglist = nullptr;
gst_message_parse_tag(msg, &taglist);
@@ -633,10 +655,7 @@ void GstEnginePipeline::TagMessageReceived(GstMessage *msg) {
gst_tag_list_free(taglist);
if (ignore_tags_) return;
if (!bundle.title.isEmpty() || !bundle.artist.isEmpty() || !bundle.comment.isEmpty() || !bundle.album.isEmpty())
emit MetadataFound(id(), bundle);
emit MetadataFound(id(), bundle);
}
@@ -688,7 +707,7 @@ void GstEnginePipeline::StateChangedMessageReceived(GstMessage *msg) {
if (next_uri_set_ && new_state == GST_STATE_READY) {
// Revert uri and go back to PLAY state again
next_uri_set_ = false;
g_object_set(G_OBJECT(pipeline_), "uri", media_url_.constData(), nullptr);
g_object_set(G_OBJECT(pipeline_), "uri", stream_url_.constData(), nullptr);
SetState(GST_STATE_PLAYING);
}
}
@@ -816,10 +835,10 @@ GstPadProbeReturn GstEnginePipeline::HandoffCallback(GstPad*, GstPadProbeInfo *i
quint64 end_time = start_time + duration;
if (end_time > instance->end_offset_nanosec_) {
if (instance->has_next_valid_url() && instance->next_media_url_ == instance->media_url_ && instance->next_beginning_offset_nanosec_ == instance->end_offset_nanosec_) {
if (instance->has_next_valid_url() && instance->next_stream_url_ == instance->stream_url_ && instance->next_beginning_offset_nanosec_ == instance->end_offset_nanosec_) {
// The "next" song is actually the next segment of this file - so cheat and keep on playing, but just tell the Engine we've moved on.
instance->end_offset_nanosec_ = instance->next_end_offset_nanosec_;
instance->next_media_url_ = QByteArray();
instance->next_stream_url_ = QByteArray();
instance->next_original_url_ = QUrl();
instance->next_beginning_offset_nanosec_ = 0;
instance->next_end_offset_nanosec_ = 0;
@@ -867,13 +886,13 @@ GstPadProbeReturn GstEnginePipeline::EventHandoffCallback(GstPad*, GstPadProbeIn
void GstEnginePipeline::AboutToFinishCallback(GstPlayBin *bin, gpointer self) {
GstEnginePipeline* instance = reinterpret_cast<GstEnginePipeline*>(self);
GstEnginePipeline *instance = reinterpret_cast<GstEnginePipeline*>(self);
if (instance->has_next_valid_url() && !instance->next_uri_set_) {
// Set the next uri. When the current song ends it will be played automatically and a STREAM_START message is send to the bus.
// When the next uri is not playable an error message is send when the pipeline goes to PLAY (or PAUSE) state or immediately if it is currently in PLAY state.
instance->next_uri_set_ = true;
g_object_set(G_OBJECT(instance->pipeline_), "uri", instance->next_media_url_.constData(), nullptr);
g_object_set(G_OBJECT(instance->pipeline_), "uri", instance->next_stream_url_.constData(), nullptr);
}
}
@@ -1123,11 +1142,79 @@ void GstEnginePipeline::RemoveAllBufferConsumers() {
buffer_consumers_.clear();
}
void GstEnginePipeline::SetNextUrl(const QByteArray &media_url, const QUrl &original_url, qint64 beginning_nanosec, qint64 end_nanosec) {
void GstEnginePipeline::SetNextUrl(const QByteArray &stream_url, const QUrl &original_url, qint64 beginning_nanosec, qint64 end_nanosec) {
next_media_url_ = media_url;
next_stream_url_ = stream_url;
next_original_url_ = original_url;
next_beginning_offset_nanosec_ = beginning_nanosec;
next_end_offset_nanosec_ = end_nanosec;
}
void GstEnginePipeline::StreamDiscovered(GstDiscoverer *discoverer, GstDiscovererInfo *info, GError *err, gpointer self) {
GstEnginePipeline *instance = reinterpret_cast<GstEnginePipeline*>(self);
if (!instance) return;
QString discovered_url(gst_discoverer_info_get_uri(info));
GstDiscovererResult result = gst_discoverer_info_get_result(info);
if (result != GST_DISCOVERER_OK) {
QString error_message = GSTdiscovererErrorMessage(result);
qLog(Error) << QString("Stream discovery for %1 failed: %2").arg(discovered_url).arg(error_message);
return;
}
GList *audio_streams = gst_discoverer_info_get_audio_streams(info);
if (audio_streams) {
GstDiscovererStreamInfo *stream_info = (GstDiscovererStreamInfo*) g_list_first(audio_streams)->data;
Engine::SimpleMetaBundle bundle;
bundle.minor = true;
bundle.url = instance->original_url();
bundle.stream_url = QUrl(discovered_url);
bundle.samplerate = gst_discoverer_audio_info_get_sample_rate(GST_DISCOVERER_AUDIO_INFO(stream_info));
bundle.bitdepth = gst_discoverer_audio_info_get_depth(GST_DISCOVERER_AUDIO_INFO(stream_info));
bundle.bitrate = gst_discoverer_audio_info_get_bitrate(GST_DISCOVERER_AUDIO_INFO(stream_info));
GstCaps *stream_caps = gst_discoverer_stream_info_get_caps(stream_info);
gchar *decoder_description = gst_pb_utils_get_codec_description(stream_caps);
QString filetype_description = (decoder_description ? QString(decoder_description) : QString("Unknown"));
gst_caps_unref(stream_caps);
g_free(decoder_description);
gst_discoverer_stream_info_list_free(audio_streams);
qLog(Info) << QString("Got stream info for %1: %2").arg(discovered_url).arg(filetype_description);
emit instance->MetadataFound(instance->id(), bundle);
}
else {
qLog(Error) << QString("Could not detect an audio stream in %1").arg(discovered_url);
}
}
void GstEnginePipeline::StreamDiscoveryFinished(GstDiscoverer *discoverer, gpointer self) {
//GstEnginePipeline *instance = reinterpret_cast<GstEnginePipeline*>(self);
}
QString GstEnginePipeline::GSTdiscovererErrorMessage(GstDiscovererResult result) {
switch (result) {
case (GST_DISCOVERER_URI_INVALID):
return tr("Invalid URL");
case (GST_DISCOVERER_TIMEOUT):
return tr("Connection timed out");
case (GST_DISCOVERER_BUSY):
return tr("The discoverer is busy");
case (GST_DISCOVERER_MISSING_PLUGINS):
return tr("Missing plugins");
case (GST_DISCOVERER_ERROR):
default:
return tr("Could not get details");
}
}

View File

@@ -30,6 +30,7 @@
#include <glib-object.h>
#include <glib/gtypes.h>
#include <gst/gst.h>
#include <gst/pbutils/pbutils.h>
#include <QtGlobal>
#include <QObject>
@@ -74,7 +75,7 @@ class GstEnginePipeline : public QObject {
void set_buffer_min_fill(int percent);
// Creates the pipeline, returns false on error
bool InitFromUrl(const QByteArray &media_url, const QUrl original_url, qint64 end_nanosec);
bool InitFromUrl(const QByteArray &stream_url, const QUrl original_url, qint64 end_nanosec);
bool InitFromString(const QString &pipeline);
// GstBufferConsumers get fed audio data. Thread-safe.
@@ -92,13 +93,13 @@ class GstEnginePipeline : public QObject {
void StartFader(qint64 duration_nanosec, QTimeLine::Direction direction = QTimeLine::Forward, QTimeLine::CurveShape shape = QTimeLine::LinearCurve, bool use_fudge_timer = true);
// If this is set then it will be loaded automatically when playback finishes for gapless playback
void SetNextUrl(const QByteArray &media_url, const QUrl &original_url, qint64 beginning_nanosec, qint64 end_nanosec);
bool has_next_valid_url() const { return !next_media_url_.isNull() && !next_media_url_.isEmpty(); }
void SetNextUrl(const QByteArray &stream_url, const QUrl &original_url, qint64 beginning_nanosec, qint64 end_nanosec);
bool has_next_valid_url() const { return !next_stream_url_.isNull() && !next_stream_url_.isEmpty(); }
void SetSourceDevice(QString device) { source_device_ = device; }
// Get information about the music playback
QByteArray media_url() const { return media_url_; }
QByteArray stream_url() const { return stream_url_; }
QUrl original_url() const { return original_url_; }
bool is_valid() const { return valid_; }
// Please note that this method (unlike GstEngine's.position()) is multiple-section media unaware.
@@ -165,12 +166,17 @@ signals:
void UpdateEqualizer();
void UpdateStereoBalance();
static void StreamDiscovered(GstDiscoverer *discoverer, GstDiscovererInfo *info, GError *err, gpointer instance);
static void StreamDiscoveryFinished(GstDiscoverer *discoverer, gpointer instance);
static QString GSTdiscovererErrorMessage(GstDiscovererResult result);
private slots:
void FaderTimelineFinished();
private:
static const int kGstStateTimeoutNanosecs;
static const int kFaderFudgeMsec;
static const int kDiscoveryTimeoutS;
static const int kEqBandCount;
static const int kEqBandFrequencies[];
@@ -217,9 +223,9 @@ signals:
bool segment_start_received_;
// The URL that is currently playing, and the URL that is to be preloaded when the current track is close to finishing.
QByteArray media_url_;
QByteArray stream_url_;
QUrl original_url_;
QByteArray next_media_url_;
QByteArray next_stream_url_;
QUrl next_original_url_;
// If this is > 0 then the pipeline will be forced to stop when playback goes past this position.
@@ -278,6 +284,7 @@ signals:
GstElement *equalizer_;
GstElement *rgvolume_;
GstElement *rglimiter_;
GstDiscoverer *discoverer_;
uint bus_cb_id_;

View File

@@ -20,6 +20,7 @@
#include "config.h"
#include <gst/gst.h>
#include <gst/pbutils/pbutils.h>
#include <QtGlobal>
#include <QObject>
@@ -51,6 +52,7 @@ void GstStartup::InitialiseGStreamer() {
SetEnvironment();
gst_init(nullptr, nullptr);
gst_pb_utils_init();
#ifdef HAVE_MOODBAR
gstfastspectrum_register_static();

View File

@@ -65,8 +65,8 @@ bool PhononEngine::CanDecode(const QUrl &url) {
return true;
}
bool PhononEngine::Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
media_object_->setCurrentSource(Phonon::MediaSource(media_url));
bool PhononEngine::Load(const QUrl &stream_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
media_object_->setCurrentSource(Phonon::MediaSource(stream_url));
return true;
}

View File

@@ -49,7 +49,7 @@ class PhononEngine : public Engine::Base {
bool CanDecode(const QUrl &url);
bool Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
bool Load(const QUrl &stream_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
bool Play(quint64 offset_nanosec);
void Stop(bool stop_after = false);
void Pause();

View File

@@ -98,12 +98,12 @@ bool VLCEngine::Init() {
}
bool VLCEngine::Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
bool VLCEngine::Load(const QUrl &stream_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
if (!Initialised()) return false;
// Create the media object
VlcScopedRef<libvlc_media_t> media(libvlc_media_new_location(instance_, media_url.toEncoded().constData()));
VlcScopedRef<libvlc_media_t> media(libvlc_media_new_location(instance_, stream_url.toEncoded().constData()));
libvlc_media_player_set_media(player_, media);

View File

@@ -48,7 +48,7 @@ class VLCEngine : public Engine::Base {
bool Init();
Engine::State state() const { return state_; }
bool Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
bool Load(const QUrl &stream_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
bool Play(quint64 offset_nanosec);
void Stop(bool stop_after = false);
void Pause();

View File

@@ -301,22 +301,22 @@ Engine::State XineEngine::state() const {
return Engine::Empty;
case XINE_STATUS_STOP:
default:
return media_url_.isEmpty() ? Engine::Empty : Engine::Idle;
return stream_url_.isEmpty() ? Engine::Empty : Engine::Idle;
}
}
bool XineEngine::Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
bool XineEngine::Load(const QUrl &stream_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
if (!EnsureStream()) return false;
have_metadata_ = false;
Engine::Base::Load(media_url, original_url, change, force_stop_at_end, beginning_nanosec, end_nanosec);
Engine::Base::Load(stream_url, original_url, change, force_stop_at_end, beginning_nanosec, end_nanosec);
xine_close(stream_);
int result = xine_open(stream_, media_url.toString().toUtf8());
int result = xine_open(stream_, stream_url.toString().toUtf8());
if (result) {
#if !defined(XINE_SAFE_MODE) && defined(XINE_ANALYZER)
@@ -502,7 +502,7 @@ uint XineEngine::length() const {
// Xine often delivers nonsense values for VBR files and such, so we only use the length for remote files
if (media_url_.isLocalFile()) return 0;
if (stream_url_.isLocalFile()) return 0;
else {
int pos = 0, time = 0, length = 0;
@@ -695,7 +695,7 @@ void XineEngine::XineEventListener(void *p, const xine_event_t *event) {
message += QString::fromUtf8((char*)data + data->parameters);
}
emit engine->StateChanged(Engine::Error);
emit engine->InvalidSongRequested(engine->media_url_);
emit engine->InvalidSongRequested(engine->stream_url_);
break;
case XINE_MSG_UNKNOWN_HOST:
message = "The host is unknown.";
@@ -704,7 +704,7 @@ void XineEngine::XineEventListener(void *p, const xine_event_t *event) {
message += QString::fromUtf8((char*)data + data->parameters);
}
emit engine->StateChanged(Engine::Error);
emit engine->InvalidSongRequested(engine->media_url_);
emit engine->InvalidSongRequested(engine->stream_url_);
break;
case XINE_MSG_UNKNOWN_DEVICE:
message = "The device name you specified seems invalid.";
@@ -713,7 +713,7 @@ void XineEngine::XineEventListener(void *p, const xine_event_t *event) {
message += QString::fromUtf8((char*)data + data->parameters);
}
emit engine->StateChanged(Engine::Error);
emit engine->InvalidSongRequested(engine->media_url_);
emit engine->InvalidSongRequested(engine->stream_url_);
break;
case XINE_MSG_NETWORK_UNREACHABLE:
message = "The network appears unreachable.";
@@ -722,7 +722,7 @@ void XineEngine::XineEventListener(void *p, const xine_event_t *event) {
message += QString::fromUtf8((char*)data + data->parameters);
}
emit engine->StateChanged(Engine::Error);
emit engine->InvalidSongRequested(engine->media_url_);
emit engine->InvalidSongRequested(engine->stream_url_);
break;
case XINE_MSG_AUDIO_OUT_UNAVAILABLE:
message = "Audio output unavailable; the device is busy.";
@@ -740,7 +740,7 @@ void XineEngine::XineEventListener(void *p, const xine_event_t *event) {
message += QString::fromUtf8((char*)data + data->parameters);
}
emit engine->StateChanged(Engine::Error);
emit engine->InvalidSongRequested(engine->media_url_);
emit engine->InvalidSongRequested(engine->stream_url_);
break;
case XINE_MSG_FILE_NOT_FOUND:
message = "File not found.";
@@ -749,7 +749,7 @@ void XineEngine::XineEventListener(void *p, const xine_event_t *event) {
message += QString::fromUtf8((char*)data + data->parameters);
}
emit engine->StateChanged(Engine::Error);
emit engine->InvalidSongRequested(engine->media_url_);
emit engine->InvalidSongRequested(engine->stream_url_);
break;
case XINE_MSG_PERMISSION_ERROR:
message = "Access denied.";
@@ -758,7 +758,7 @@ void XineEngine::XineEventListener(void *p, const xine_event_t *event) {
message += QString::fromUtf8((char*)data + data->parameters);
}
emit engine->StateChanged(Engine::Error);
emit engine->InvalidSongRequested(engine->media_url_);
emit engine->InvalidSongRequested(engine->stream_url_);
break;
case XINE_MSG_READ_ERROR:
message = "Read error.";
@@ -767,7 +767,7 @@ void XineEngine::XineEventListener(void *p, const xine_event_t *event) {
message += QString::fromUtf8((char*)data + data->parameters);
}
emit engine->StateChanged(Engine::Error);
emit engine->InvalidSongRequested(engine->media_url_);
emit engine->InvalidSongRequested(engine->stream_url_);
break;
case XINE_MSG_LIBRARY_LOAD_ERROR:
message = "A problem occurred while loading a library or decoder.";
@@ -885,7 +885,7 @@ void XineEngine::DetermineAndShowErrorMessage() {
// xine can read the plugin but it didn't find any codec
// THUS xine=daft for telling us it could handle the format in canDecode!
message = "There is no available decoder.";
QString const ext = QFileInfo(media_url_.path()).completeSuffix();
QString const ext = QFileInfo(stream_url_.path()).completeSuffix();
break;
}
result = xine_get_stream_info(stream_, XINE_STREAM_INFO_HAS_AUDIO);

View File

@@ -54,7 +54,7 @@ class XineEngine : public Engine::Base {
bool Init();
Engine::State state() const;
bool Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
bool Load(const QUrl &stream_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
bool Play(quint64 offset_nanosec);
void Stop(bool stop_after = false);
void Pause();
@@ -103,7 +103,7 @@ class XineEngine : public Engine::Base {
#endif
float preamp_;
QUrl media_url_;
QUrl stream_url_;
QUrl original_url_;
bool have_metadata_;