Improve contextview and engine code
This commit is contained in:
@@ -60,11 +60,12 @@ Engine::Base::Base()
|
||||
|
||||
Engine::Base::~Base() {}
|
||||
|
||||
bool Engine::Base::Load(const QUrl &url, TrackChangeFlags, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
||||
bool Engine::Base::Load(const QUrl &media_url, const QUrl &original_url, TrackChangeFlags, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
||||
|
||||
Q_UNUSED(force_stop_at_end);
|
||||
|
||||
url_ = url;
|
||||
media_url_ = media_url;
|
||||
original_url_ = original_url;
|
||||
beginning_nanosec_ = beginning_nanosec;
|
||||
end_nanosec_ = end_nanosec;
|
||||
|
||||
@@ -73,12 +74,13 @@ bool Engine::Base::Load(const QUrl &url, TrackChangeFlags, bool force_stop_at_en
|
||||
|
||||
}
|
||||
|
||||
bool Engine::Base::Play(const QUrl &url, TrackChangeFlags flags, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
||||
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) {
|
||||
|
||||
if (!Load(url, flags, force_stop_at_end, beginning_nanosec, end_nanosec))
|
||||
if (!Load(media_url, original_url, flags, force_stop_at_end, beginning_nanosec, end_nanosec))
|
||||
return false;
|
||||
|
||||
return Play(0);
|
||||
|
||||
}
|
||||
|
||||
void Engine::Base::SetVolume(uint value) {
|
||||
|
||||
@@ -68,8 +68,8 @@ public:
|
||||
|
||||
virtual bool Init() = 0;
|
||||
virtual State state() const = 0;
|
||||
virtual void StartPreloading(const QUrl&, bool, qint64, qint64) {}
|
||||
virtual bool Load(const QUrl &url, TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
|
||||
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 bool Play(quint64 offset_nanosec) = 0;
|
||||
virtual void Stop(bool stop_after = false) = 0;
|
||||
virtual void Pause() = 0;
|
||||
@@ -97,7 +97,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 &u, TrackChangeFlags c, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
|
||||
bool Play(const QUrl &media_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);
|
||||
|
||||
@@ -164,7 +164,8 @@ protected:
|
||||
uint volume_;
|
||||
quint64 beginning_nanosec_;
|
||||
qint64 end_nanosec_;
|
||||
QUrl url_;
|
||||
QUrl media_url_;
|
||||
QUrl original_url_;
|
||||
Scope scope_;
|
||||
bool buffering_;
|
||||
bool equalizer_enabled_;
|
||||
@@ -209,12 +210,13 @@ struct SimpleMetaBundle {
|
||||
QString album;
|
||||
QString comment;
|
||||
QString genre;
|
||||
QString bitrate;
|
||||
QString samplerate;
|
||||
QString bitdepth;
|
||||
QString length;
|
||||
QString year;
|
||||
QString tracknr;
|
||||
qlonglong length;
|
||||
int year;
|
||||
int tracknr;
|
||||
int samplerate;
|
||||
int bitdepth;
|
||||
qlonglong bitrate;
|
||||
QString lyrics;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -137,7 +137,7 @@ bool GstEngine::Init() {
|
||||
|
||||
Engine::State GstEngine::state() const {
|
||||
|
||||
if (!current_pipeline_) return url_.isEmpty() ? Engine::Empty : Engine::Idle;
|
||||
if (!current_pipeline_) return media_url_.isEmpty() ? Engine::Empty : Engine::Idle;
|
||||
|
||||
switch (current_pipeline_->state()) {
|
||||
case GST_STATE_NULL:
|
||||
@@ -154,32 +154,32 @@ Engine::State GstEngine::state() const {
|
||||
|
||||
}
|
||||
|
||||
void GstEngine::StartPreloading(const QUrl &url, bool force_stop_at_end, qint64 beginning_nanosec, qint64 end_nanosec) {
|
||||
void GstEngine::StartPreloading(const QUrl &media_url, const QUrl &original_url, bool force_stop_at_end, qint64 beginning_nanosec, qint64 end_nanosec) {
|
||||
|
||||
EnsureInitialised();
|
||||
|
||||
QByteArray gst_url = FixupUrl(url);
|
||||
QByteArray gst_url = FixupUrl(media_url);
|
||||
|
||||
// No crossfading, so we can just queue the new URL in the existing pipeline and get gapless playback (hopefully)
|
||||
if (current_pipeline_)
|
||||
current_pipeline_->SetNextUrl(gst_url, beginning_nanosec, force_stop_at_end ? end_nanosec : 0);
|
||||
current_pipeline_->SetNextUrl(gst_url, original_url, beginning_nanosec, force_stop_at_end ? end_nanosec : 0);
|
||||
|
||||
}
|
||||
|
||||
bool GstEngine::Load(const QUrl &url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
||||
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) {
|
||||
|
||||
EnsureInitialised();
|
||||
|
||||
Engine::Base::Load(url, change, force_stop_at_end, beginning_nanosec, end_nanosec);
|
||||
Engine::Base::Load(media_url, original_url, change, force_stop_at_end, beginning_nanosec, end_nanosec);
|
||||
|
||||
QByteArray gst_url = FixupUrl(url);
|
||||
QByteArray gst_url = FixupUrl(media_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_->url() == gst_url && change & Engine::Auto) {
|
||||
if (!crossfade && current_pipeline_ && current_pipeline_->media_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;
|
||||
}
|
||||
@@ -188,7 +188,7 @@ bool GstEngine::Load(const QUrl &url, Engine::TrackChangeFlags change, bool forc
|
||||
//SetEqualizerParameters(equalizer_preamp_, equalizer_gains_);
|
||||
//SetStereoBalance(stereo_balance_);
|
||||
|
||||
shared_ptr<GstEnginePipeline> pipeline = CreatePipeline(gst_url, force_stop_at_end ? end_nanosec : 0);
|
||||
shared_ptr<GstEnginePipeline> pipeline = CreatePipeline(gst_url, original_url, force_stop_at_end ? end_nanosec : 0);
|
||||
if (!pipeline) return false;
|
||||
|
||||
if (crossfade) StartFadeout();
|
||||
@@ -229,7 +229,8 @@ void GstEngine::Stop(bool stop_after) {
|
||||
|
||||
StopTimers();
|
||||
|
||||
url_ = QUrl(); // To ensure we return Empty from state()
|
||||
media_url_ = QUrl(); // To ensure we return Empty from state()
|
||||
original_url_ = QUrl();
|
||||
beginning_nanosec_ = end_nanosec_ = 0;
|
||||
|
||||
// Check if we started a fade out. If it isn't finished yet and the user pressed stop, we cancel the fader and just stop the playback.
|
||||
@@ -575,7 +576,7 @@ void GstEngine::HandlePipelineError(int pipeline_id, const QString &message, int
|
||||
BufferingFinished();
|
||||
emit StateChanged(Engine::Error);
|
||||
// unable to play media stream with this url
|
||||
emit InvalidSongRequested(url_);
|
||||
emit InvalidSongRequested(media_url_);
|
||||
|
||||
emit Error(message);
|
||||
|
||||
@@ -649,9 +650,9 @@ 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_->url()) {
|
||||
if (!redirect_url.isEmpty() && redirect_url != current_pipeline_->media_url()) {
|
||||
qLog(Info) << "Redirecting to" << redirect_url;
|
||||
current_pipeline_ = CreatePipeline(redirect_url, end_nanosec_);
|
||||
current_pipeline_ = CreatePipeline(redirect_url, current_pipeline_->original_url(), end_nanosec_);
|
||||
Play(offset_nanosec);
|
||||
return;
|
||||
}
|
||||
@@ -665,14 +666,14 @@ void GstEngine::PlayDone(QFuture<GstStateChangeReturn> future, const quint64 off
|
||||
|
||||
StartTimers();
|
||||
|
||||
// initial offset
|
||||
// Initial offset
|
||||
if (offset_nanosec != 0 || beginning_nanosec_ != 0) {
|
||||
Seek(offset_nanosec);
|
||||
}
|
||||
|
||||
emit StateChanged(Engine::Playing);
|
||||
// we've successfully started playing a media stream with this url
|
||||
emit ValidSongRequested(url_);
|
||||
// We've successfully started playing a media stream with this url
|
||||
emit ValidSongRequested(media_url_);
|
||||
|
||||
}
|
||||
|
||||
@@ -823,25 +824,14 @@ shared_ptr<GstEnginePipeline> GstEngine::CreatePipeline() {
|
||||
connect(ret.get(), SIGNAL(BufferingProgress(int)), SLOT(BufferingProgress(int)));
|
||||
connect(ret.get(), SIGNAL(BufferingFinished()), SLOT(BufferingFinished()));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
shared_ptr<GstEnginePipeline> GstEngine::CreatePipeline(const QUrl &url, qint64 end_nanosec) {
|
||||
|
||||
shared_ptr<GstEnginePipeline> ret = CreatePipeline();
|
||||
|
||||
if (!ret->InitFromUrl(url.toEncoded(), end_nanosec)) ret.reset();
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
shared_ptr<GstEnginePipeline> GstEngine::CreatePipeline(const QByteArray &url, qint64 end_nanosec) {
|
||||
shared_ptr<GstEnginePipeline> GstEngine::CreatePipeline(const QByteArray &gst_url, const QUrl &original_url, qint64 end_nanosec) {
|
||||
|
||||
shared_ptr<GstEnginePipeline> ret = CreatePipeline();
|
||||
|
||||
if (!ret->InitFromUrl(url, end_nanosec)) ret.reset();
|
||||
|
||||
if (!ret->InitFromUrl(gst_url, original_url, end_nanosec)) ret.reset();
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
@@ -68,8 +68,8 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
|
||||
|
||||
bool Init();
|
||||
Engine::State state() const;
|
||||
void StartPreloading(const QUrl &url, bool force_stop_at_end, qint64 beginning_nanosec, qint64 end_nanosec);
|
||||
bool Load(const QUrl &, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
|
||||
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);
|
||||
bool Play(quint64 offset_nanosec);
|
||||
void Stop(bool stop_after = false);
|
||||
void Pause();
|
||||
@@ -157,8 +157,7 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
|
||||
void StopTimers();
|
||||
|
||||
std::shared_ptr<GstEnginePipeline> CreatePipeline();
|
||||
std::shared_ptr<GstEnginePipeline> CreatePipeline(const QUrl &url, qint64 end_nanosec);
|
||||
std::shared_ptr<GstEnginePipeline> CreatePipeline(const QByteArray &url, qint64 end_nanosec);
|
||||
std::shared_ptr<GstEnginePipeline> CreatePipeline(const QByteArray &gst_url, const QUrl &original_url, qint64 end_nanosec);
|
||||
|
||||
void UpdateScope(int chunk_length);
|
||||
|
||||
|
||||
@@ -371,15 +371,16 @@ bool GstEnginePipeline::InitFromString(const QString &pipeline) {
|
||||
|
||||
}
|
||||
|
||||
bool GstEnginePipeline::InitFromUrl(const QByteArray &url, qint64 end_nanosec) {
|
||||
bool GstEnginePipeline::InitFromUrl(const QByteArray &media_url, const QUrl original_url, qint64 end_nanosec) {
|
||||
|
||||
url_ = url;
|
||||
media_url_ = media_url;
|
||||
original_url_ = original_url;
|
||||
end_offset_nanosec_ = end_nanosec;
|
||||
|
||||
pipeline_ = engine_->CreateElement("playbin");
|
||||
if (pipeline_ == nullptr) return false;
|
||||
|
||||
g_object_set(G_OBJECT(pipeline_), "uri", url.constData(), nullptr);
|
||||
g_object_set(G_OBJECT(pipeline_), "uri", media_url.constData(), nullptr);
|
||||
CHECKED_GCONNECT(G_OBJECT(pipeline_), "about-to-finish", &AboutToFinishCallback, this);
|
||||
|
||||
CHECKED_GCONNECT(G_OBJECT(pipeline_), "pad-added", &NewPadCallback, this);
|
||||
@@ -501,9 +502,11 @@ void GstEnginePipeline::StreamStartMessageReceived() {
|
||||
if (next_uri_set_) {
|
||||
next_uri_set_ = false;
|
||||
|
||||
url_ = next_url_;
|
||||
media_url_ = next_media_url_;
|
||||
original_url_ = next_original_url_;
|
||||
end_offset_nanosec_ = next_end_offset_nanosec_;
|
||||
next_url_ = QByteArray();
|
||||
next_media_url_ = QByteArray();
|
||||
next_original_url_ = QUrl();
|
||||
next_beginning_offset_nanosec_ = 0;
|
||||
next_end_offset_nanosec_ = 0;
|
||||
|
||||
@@ -580,11 +583,18 @@ void GstEnginePipeline::TagMessageReceived(GstMessage *msg) {
|
||||
gst_message_parse_tag(msg, &taglist);
|
||||
|
||||
Engine::SimpleMetaBundle bundle;
|
||||
bundle.url = QUrl(QString(url_));
|
||||
bundle.title = ParseTag(taglist, GST_TAG_TITLE);
|
||||
bundle.artist = ParseTag(taglist, GST_TAG_ARTIST);
|
||||
bundle.comment = ParseTag(taglist, GST_TAG_COMMENT);
|
||||
bundle.album = ParseTag(taglist, GST_TAG_ALBUM);
|
||||
bundle.url = original_url_;
|
||||
bundle.title = ParseStrTag(taglist, GST_TAG_TITLE);
|
||||
bundle.artist = ParseStrTag(taglist, GST_TAG_ARTIST);
|
||||
bundle.comment = ParseStrTag(taglist, GST_TAG_COMMENT);
|
||||
bundle.album = ParseStrTag(taglist, GST_TAG_ALBUM);
|
||||
bundle.length = 0;
|
||||
bundle.year = 0;
|
||||
bundle.tracknr = 0;
|
||||
bundle.samplerate = 0;
|
||||
bundle.bitdepth = 0;
|
||||
bundle.bitrate = ParseUIntTag(taglist, GST_TAG_BITRATE) / 1000;
|
||||
bundle.lyrics = ParseStrTag(taglist, GST_TAG_LYRICS);
|
||||
|
||||
gst_tag_list_free(taglist);
|
||||
|
||||
@@ -595,7 +605,7 @@ void GstEnginePipeline::TagMessageReceived(GstMessage *msg) {
|
||||
|
||||
}
|
||||
|
||||
QString GstEnginePipeline::ParseTag(GstTagList *list, const char *tag) const {
|
||||
QString GstEnginePipeline::ParseStrTag(GstTagList *list, const char *tag) const {
|
||||
|
||||
gchar *data = nullptr;
|
||||
bool success = gst_tag_list_get_string(list, tag, &data);
|
||||
@@ -609,6 +619,17 @@ QString GstEnginePipeline::ParseTag(GstTagList *list, const char *tag) const {
|
||||
|
||||
}
|
||||
|
||||
guint GstEnginePipeline::ParseUIntTag(GstTagList *list, const char *tag) const {
|
||||
|
||||
guint data;
|
||||
bool success = gst_tag_list_get_uint(list, tag, &data);
|
||||
|
||||
guint ret = 0;
|
||||
if (success && data) ret = data;
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void GstEnginePipeline::StateChangedMessageReceived(GstMessage *msg) {
|
||||
|
||||
if (msg->src != GST_OBJECT(pipeline_)) {
|
||||
@@ -632,7 +653,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", url_.constData(), nullptr);
|
||||
g_object_set(G_OBJECT(pipeline_), "uri", media_url_.constData(), nullptr);
|
||||
SetState(GST_STATE_PLAYING);
|
||||
}
|
||||
}
|
||||
@@ -760,10 +781,11 @@ 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_url_ == instance->url_ && instance->next_beginning_offset_nanosec_ == 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_) {
|
||||
// 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_url_ = QByteArray();
|
||||
instance->next_media_url_ = QByteArray();
|
||||
instance->next_original_url_ = QUrl();
|
||||
instance->next_beginning_offset_nanosec_ = 0;
|
||||
instance->next_end_offset_nanosec_ = 0;
|
||||
|
||||
@@ -816,7 +838,7 @@ void GstEnginePipeline::AboutToFinishCallback(GstPlayBin *bin, gpointer self) {
|
||||
// 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_url_.constData(), nullptr);
|
||||
g_object_set(G_OBJECT(instance->pipeline_), "uri", instance->next_media_url_.constData(), nullptr);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1059,9 +1081,10 @@ void GstEnginePipeline::RemoveAllBufferConsumers() {
|
||||
buffer_consumers_.clear();
|
||||
}
|
||||
|
||||
void GstEnginePipeline::SetNextUrl(const QByteArray &url, qint64 beginning_nanosec, qint64 end_nanosec) {
|
||||
void GstEnginePipeline::SetNextUrl(const QByteArray &media_url, const QUrl &original_url, qint64 beginning_nanosec, qint64 end_nanosec) {
|
||||
|
||||
next_url_ = url;
|
||||
next_media_url_ = media_url;
|
||||
next_original_url_ = original_url;
|
||||
next_beginning_offset_nanosec_ = beginning_nanosec;
|
||||
next_end_offset_nanosec_ = end_nanosec;
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ class GstEnginePipeline : public QObject {
|
||||
void set_mono_playback(bool enabled);
|
||||
|
||||
// Creates the pipeline, returns false on error
|
||||
bool InitFromUrl(const QByteArray &url, qint64 end_nanosec);
|
||||
bool InitFromUrl(const QByteArray &media_url, const QUrl original_url, qint64 end_nanosec);
|
||||
bool InitFromString(const QString &pipeline);
|
||||
|
||||
// GstBufferConsumers get fed audio data. Thread-safe.
|
||||
@@ -89,13 +89,14 @@ 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 &url, qint64 beginning_nanosec, qint64 end_nanosec);
|
||||
bool has_next_valid_url() const { return !next_url_.isNull() && !next_url_.isEmpty(); }
|
||||
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 SetSourceDevice(QString device) { source_device_ = device; }
|
||||
|
||||
// Get information about the music playback
|
||||
QByteArray url() const { return url_; }
|
||||
QByteArray media_url() const { return media_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.
|
||||
qint64 position() const;
|
||||
@@ -150,7 +151,8 @@ signals:
|
||||
void StreamStatusMessageReceived(GstMessage*);
|
||||
void StreamStartMessageReceived();
|
||||
|
||||
QString ParseTag(GstTagList *list, const char *tag) const;
|
||||
QString ParseStrTag(GstTagList *list, const char *tag) const;
|
||||
guint ParseUIntTag(GstTagList *list, const char *tag) const;
|
||||
|
||||
bool InitDecodeBin(GstElement* new_bin);
|
||||
bool InitAudioBin();
|
||||
@@ -213,8 +215,10 @@ 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 url_;
|
||||
QByteArray next_url_;
|
||||
QByteArray media_url_;
|
||||
QUrl original_url_;
|
||||
QByteArray next_media_url_;
|
||||
QUrl next_original_url_;
|
||||
|
||||
// If this is > 0 then the pipeline will be forced to stop when playback goes past this position.
|
||||
qint64 end_offset_nanosec_;
|
||||
|
||||
@@ -64,8 +64,8 @@ bool PhononEngine::CanDecode(const QUrl &url) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PhononEngine::Load(const QUrl &url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
||||
media_object_->setCurrentSource(Phonon::MediaSource(url));
|
||||
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));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class PhononEngine : public Engine::Base {
|
||||
|
||||
bool CanDecode(const QUrl &url);
|
||||
|
||||
bool Load(const QUrl &, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 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);
|
||||
bool Play(quint64 offset_nanosec);
|
||||
void Stop(bool stop_after = false);
|
||||
void Pause();
|
||||
|
||||
@@ -100,12 +100,12 @@ bool VLCEngine::Initialised() const {
|
||||
|
||||
}
|
||||
|
||||
bool VLCEngine::Load(const QUrl &url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
||||
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) {
|
||||
|
||||
if (!Initialised()) return false;
|
||||
|
||||
// Create the media object
|
||||
VlcScopedRef<libvlc_media_t> media(libvlc_media_new_location(instance_, url.toEncoded().constData()));
|
||||
VlcScopedRef<libvlc_media_t> media(libvlc_media_new_location(instance_, media_url.toEncoded().constData()));
|
||||
|
||||
libvlc_media_player_set_media(player_, media);
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class VLCEngine : public Engine::Base {
|
||||
|
||||
bool Init();
|
||||
Engine::State state() const { return state_; }
|
||||
bool Load(const QUrl &url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 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);
|
||||
bool Play(quint64 offset_nanosec);
|
||||
void Stop(bool stop_after = false);
|
||||
void Pause();
|
||||
|
||||
@@ -180,20 +180,20 @@ Engine::State XineEngine::state() const {
|
||||
return Engine::Empty;
|
||||
case XINE_STATUS_STOP:
|
||||
default:
|
||||
return url_.isEmpty() ? Engine::Empty : Engine::Idle;
|
||||
return media_url_.isEmpty() ? Engine::Empty : Engine::Idle;
|
||||
}
|
||||
}
|
||||
|
||||
bool XineEngine::Load(const QUrl &url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
||||
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) {
|
||||
|
||||
if (!EnsureStream()) return false;
|
||||
|
||||
Engine::Base::Load(url, change, force_stop_at_end, beginning_nanosec, end_nanosec);
|
||||
Engine::Base::Load(media_url_, original_url_, change, force_stop_at_end, beginning_nanosec, end_nanosec);
|
||||
|
||||
xine_close(stream_);
|
||||
|
||||
//int result = xine_open(stream_, url.path().toUtf8());
|
||||
int result = xine_open(stream_, url.toString().toUtf8());
|
||||
int result = xine_open(stream_, media_url.toString().toUtf8());
|
||||
if (result) {
|
||||
|
||||
#ifndef XINE_SAFE_MODE
|
||||
@@ -375,7 +375,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 (url_.scheme().toLower() == "file") return 0;
|
||||
if (media_url_.scheme().toLower() == "file") return 0;
|
||||
else {
|
||||
int pos = 0, time = 0, length = 0;
|
||||
|
||||
@@ -477,10 +477,9 @@ bool XineEngine::MetaDataForUrl(const QUrl &url, Engine::SimpleMetaBundle &b) {
|
||||
b.artist = QString::fromUtf8(xine_get_meta_info(tmpstream, XINE_META_INFO_ARTIST));
|
||||
b.album = QString::fromUtf8(xine_get_meta_info(tmpstream, XINE_META_INFO_ALBUM));
|
||||
b.genre = QString::fromUtf8(xine_get_meta_info(tmpstream, XINE_META_INFO_GENRE));
|
||||
b.year = QString::fromUtf8(xine_get_meta_info(tmpstream, XINE_META_INFO_YEAR));
|
||||
b.tracknr = QString::fromUtf8(xine_get_meta_info(tmpstream, XINE_META_INFO_TRACK_NUMBER));
|
||||
if (b.tracknr.isEmpty())
|
||||
b.tracknr = QFileInfo(url.path()).fileName();
|
||||
b.year = atoi(xine_get_meta_info(tmpstream, XINE_META_INFO_YEAR));
|
||||
b.tracknr = atoi(xine_get_meta_info(tmpstream, XINE_META_INFO_TRACK_NUMBER));
|
||||
//if (b.tracknr <= 0) b.tracknr = QFileInfo(url.path()).fileName();
|
||||
}
|
||||
else {
|
||||
b.title = QString("Track %1").arg(QFileInfo(url.path()).fileName());
|
||||
@@ -490,18 +489,19 @@ bool XineEngine::MetaDataForUrl(const QUrl &url, Engine::SimpleMetaBundle &b) {
|
||||
|
||||
if (audioCodec == "CDDA" || audioCodec == "WAV") {
|
||||
result = true;
|
||||
b.url = url;
|
||||
int samplerate = xine_get_stream_info(tmpstream, XINE_STREAM_INFO_AUDIO_SAMPLERATE);
|
||||
|
||||
int bitdepth = xine_get_stream_info(tmpstream, XINE_STREAM_INFO_AUDIO_BITS);
|
||||
int channels = xine_get_stream_info(tmpstream, XINE_STREAM_INFO_AUDIO_CHANNELS);
|
||||
// Xine would provide a XINE_STREAM_INFO_AUDIO_BITRATE, but unfortunately not for CDDA or WAV so we calculate the bitrate by our own
|
||||
int bitsPerSample = xine_get_stream_info(tmpstream, XINE_STREAM_INFO_AUDIO_BITS);
|
||||
int nbrChannels = xine_get_stream_info(tmpstream, XINE_STREAM_INFO_AUDIO_CHANNELS);
|
||||
int bitrate = (samplerate * bitsPerSample * nbrChannels) / 1000;
|
||||
int bitrate = (samplerate * bitdepth * channels) / 1000;
|
||||
|
||||
b.bitrate = QString::number(bitrate);
|
||||
b.samplerate = QString::number(samplerate);
|
||||
b.samplerate = samplerate;
|
||||
b.bitdepth = bitdepth;
|
||||
b.bitrate = bitrate;
|
||||
int pos, time, length = 0;
|
||||
xine_get_pos_length(tmpstream, &pos, &time, &length);
|
||||
b.length = QString::number(length / 1000);
|
||||
b.length = length / 1000;
|
||||
}
|
||||
xine_close(tmpstream);
|
||||
}
|
||||
@@ -750,7 +750,7 @@ bool XineEngine::event(QEvent *e) {
|
||||
return true;
|
||||
|
||||
case XineEvent::InfoMessage:
|
||||
emit InfoMessage((*message).arg(url_.toString()));
|
||||
emit InfoMessage((*message).arg(media_url_.toString()));
|
||||
delete message;
|
||||
return true;
|
||||
|
||||
@@ -771,7 +771,7 @@ bool XineEngine::event(QEvent *e) {
|
||||
|
||||
case XineEvent::Redirecting:
|
||||
emit StatusText(QString("Redirecting to: ").arg(*message));
|
||||
Load(QUrl(*message), Engine::Auto, false, 0, 0);
|
||||
Load(QUrl(*message), original_url_, Engine::Auto, false, 0, 0);
|
||||
Play(0);
|
||||
delete message;
|
||||
return true;
|
||||
@@ -787,15 +787,18 @@ bool XineEngine::event(QEvent *e) {
|
||||
Engine::SimpleMetaBundle XineEngine::fetchMetaData() const {
|
||||
|
||||
Engine::SimpleMetaBundle bundle;
|
||||
bundle.url = original_url;
|
||||
bundle.title = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_TITLE));
|
||||
bundle.artist = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_ARTIST));
|
||||
bundle.album = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_ALBUM));
|
||||
bundle.comment = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_COMMENT));
|
||||
bundle.genre = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_GENRE));
|
||||
bundle.bitrate = QString::number(xine_get_stream_info(stream_, XINE_STREAM_INFO_AUDIO_BITRATE) / 1000);
|
||||
bundle.samplerate = QString::number(xine_get_stream_info(stream_, XINE_STREAM_INFO_AUDIO_SAMPLERATE));
|
||||
bundle.year = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_YEAR));
|
||||
bundle.tracknr = QString::fromUtf8(xine_get_meta_info(stream_, XINE_META_INFO_TRACK_NUMBER));
|
||||
bundle.length = 0;
|
||||
bundle.year = atoi(xine_get_meta_info(stream_, XINE_META_INFO_YEAR));
|
||||
bundle.tracknr = atoi(xine_get_meta_info(stream_, XINE_META_INFO_TRACK_NUMBER));
|
||||
bundle.samplerate = xine_get_stream_info(stream_, XINE_STREAM_INFO_AUDIO_SAMPLERATE);
|
||||
bundle.bitdepth = xine_get_stream_info(stream_, XINE_STREAM_INFO_AUDIO_BITS);
|
||||
bundle.bitrate = xine_get_stream_info(stream_, XINE_STREAM_INFO_AUDIO_BITRATE) / 1000;
|
||||
|
||||
return bundle;
|
||||
|
||||
@@ -899,7 +902,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!
|
||||
body = "There is no available decoder.";
|
||||
QString const ext = QFileInfo(url_.path()).completeSuffix();
|
||||
QString const ext = QFileInfo(media_url_.path()).completeSuffix();
|
||||
// TODO:
|
||||
// if (ext == "mp3" && EngineController::installDistroCodec("xine-engine"))
|
||||
// return;
|
||||
|
||||
@@ -70,7 +70,7 @@ class XineEngine : public Engine::Base {
|
||||
|
||||
bool Init();
|
||||
Engine::State state() const;
|
||||
bool Load(const QUrl &url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 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);
|
||||
bool Play(quint64 offset_nanosec);
|
||||
void Stop(bool stop_after = false);
|
||||
void Pause();
|
||||
@@ -116,7 +116,8 @@ class XineEngine : public Engine::Base {
|
||||
float preamp_;
|
||||
std::unique_ptr<PruneScopeThread> prune_;
|
||||
|
||||
QUrl url_;
|
||||
QUrl media_url_;
|
||||
QUrl original_url_;
|
||||
|
||||
static int last_error_;
|
||||
static time_t last_error_time_;
|
||||
|
||||
Reference in New Issue
Block a user