Added initial gstreamer audio playback.
x86 might not work due to misconfiguration because I could not test it since acinerella is broken in x86 currenty. Gstreamer video support is yet to follow. Please report back any bugs you experience. To compile you will need Visual C++, I hope all files are included
This commit is contained in:
1 parent
8a11b0eff0
commit
e653ac87a2
1326 files changed
+154559
-4
No files matched your search
@@ -0,0 +1,320 @@
|
||||
#include "stdafx.h"
|
||||
#include "GstreamerAudioStream.h"
|
||||
#include "GstreamerAudio.h"
|
||||
#include "gst/gst.h"
|
||||
#include <string>
|
||||
|
||||
|
||||
GstreamerAudioStream::GstreamerAudioStream(int id)
|
||||
{
|
||||
ID = id;
|
||||
MaxVolume = 1.0;
|
||||
Volume = 1.0;
|
||||
Duration = -1;
|
||||
Loop = false;
|
||||
Running = true;
|
||||
|
||||
Finished = false;
|
||||
Playing = false;
|
||||
Paused = false;
|
||||
|
||||
//Fading
|
||||
FadeTimer = g_timer_new();
|
||||
FadeTime = 0.0;
|
||||
TargetVolume = 1.0;
|
||||
StartVolume = 1.0;
|
||||
CloseStreamAfterFade = false;
|
||||
PauseStreamAfterFade = false;
|
||||
Fading = false;
|
||||
|
||||
Closed = false;
|
||||
}
|
||||
|
||||
|
||||
GstreamerAudioStream::~GstreamerAudioStream(void)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
int GstreamerAudioStream::Load(const wchar_t* Media)
|
||||
{
|
||||
Element = gst_element_factory_make("playbin", "playbin");
|
||||
|
||||
Convert = gst_element_factory_make("audioconvert", "audioconvert");
|
||||
Audiosink = gst_element_factory_make("directsoundsink", "directsoundsink");
|
||||
SinkBin = gst_bin_new("SinkBin");
|
||||
gst_bin_add_many (GST_BIN (SinkBin), Convert, Audiosink, NULL);
|
||||
gst_element_link_many (Convert, Audiosink, NULL);
|
||||
Pad = gst_element_get_static_pad (Convert, "sink");
|
||||
GhostPad = gst_ghost_pad_new ("sink", Pad);
|
||||
gst_pad_set_active (GhostPad, TRUE);
|
||||
gst_element_add_pad (SinkBin, GhostPad);
|
||||
|
||||
Bus = gst_element_get_bus(Element);
|
||||
if(!Element)
|
||||
{
|
||||
LogError ("Could not create element!");
|
||||
return -1;
|
||||
}
|
||||
Running = true;
|
||||
g_object_set(Element, "uri", Media, NULL);
|
||||
g_object_set(Element, "audio-sink", SinkBin, NULL);
|
||||
|
||||
gst_element_set_state(Element, GST_STATE_PAUSED);
|
||||
gst_bus_timed_pop_filtered(Bus, -1, GST_MESSAGE_ASYNC_DONE);
|
||||
Paused = true;
|
||||
RefreshDuration();
|
||||
|
||||
return ID;
|
||||
}
|
||||
|
||||
int GstreamerAudioStream::Load(const wchar_t* Media, bool Prescan)
|
||||
{
|
||||
Load(Media);
|
||||
return ID;
|
||||
}
|
||||
|
||||
void GstreamerAudioStream::Close(void)
|
||||
{
|
||||
if(Element)
|
||||
gst_element_set_state(Element, GST_STATE_NULL);
|
||||
|
||||
if(Bus)
|
||||
g_object_unref(Bus);
|
||||
if(Element)
|
||||
g_object_unref(Element);
|
||||
if(Convert)
|
||||
g_object_unref(Convert);
|
||||
if(Audiosink)
|
||||
g_object_unref(Audiosink);
|
||||
if(Pad)
|
||||
g_object_unref(Pad);
|
||||
if(GhostPad)
|
||||
g_object_unref(GhostPad);
|
||||
if(SinkBin)
|
||||
g_object_unref(SinkBin);
|
||||
if(FadeTimer)
|
||||
g_timer_destroy (FadeTimer);
|
||||
|
||||
Running = false;
|
||||
Closed = true;
|
||||
}
|
||||
|
||||
void GstreamerAudioStream::Play(void)
|
||||
{
|
||||
if(Element)
|
||||
{
|
||||
PauseStreamAfterFade = false;
|
||||
Running = true;
|
||||
GstStateChangeReturn ret;
|
||||
if(Element)
|
||||
ret = gst_element_set_state(Element, GST_STATE_PLAYING);
|
||||
if(ret == GST_STATE_CHANGE_ASYNC)
|
||||
gst_bus_timed_pop_filtered(Bus, -1, GST_MESSAGE_ASYNC_DONE);
|
||||
SetStreamVolume(Volume * 100.0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GstreamerAudioStream::Play(bool Loop)
|
||||
{
|
||||
Playing = true;
|
||||
Paused = false;
|
||||
this->Loop = Loop;
|
||||
Play();
|
||||
}
|
||||
|
||||
void GstreamerAudioStream::Pause()
|
||||
{
|
||||
Playing = false;
|
||||
Paused = true;
|
||||
Running = true;
|
||||
if(Element)
|
||||
gst_element_set_state(Element, GST_STATE_PAUSED);
|
||||
SetStreamVolume(Volume * 100.0);
|
||||
}
|
||||
|
||||
void GstreamerAudioStream::Stop()
|
||||
{
|
||||
if(Element)
|
||||
{
|
||||
gst_element_set_state(Element, GST_STATE_NULL);
|
||||
gst_element_seek_simple(Element, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, 0);
|
||||
Running = true;
|
||||
Playing = false;
|
||||
}
|
||||
}
|
||||
|
||||
void GstreamerAudioStream::SetStreamVolume(float Volume)
|
||||
{
|
||||
this->Volume = Volume / 100.0;
|
||||
if(Element)
|
||||
{
|
||||
g_object_set(this->Element, "volume", (gdouble)(Volume / 100.0) * MaxVolume, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void GstreamerAudioStream::SetStreamVolumeMax(float MaxVolume)
|
||||
{
|
||||
this->MaxVolume = (gdouble) (MaxVolume / 100.0);
|
||||
if(Element)
|
||||
{
|
||||
g_object_set(this->Element, "volume", Volume * this->MaxVolume, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
float GstreamerAudioStream::GetLength()
|
||||
{
|
||||
if(Duration <= 0)
|
||||
RefreshDuration();
|
||||
return Duration;
|
||||
}
|
||||
|
||||
void GstreamerAudioStream::RefreshDuration()
|
||||
{
|
||||
if(Element)
|
||||
{
|
||||
gint64 time;
|
||||
if(!gst_element_query_duration(Element, GST_FORMAT_TIME, &time)) {
|
||||
LogError("Could not query duration");
|
||||
}
|
||||
Duration = (gfloat)((gdouble)(time/GST_SECOND));
|
||||
}
|
||||
}
|
||||
|
||||
float GstreamerAudioStream::GetPosition()
|
||||
{
|
||||
if(Element)
|
||||
{
|
||||
gint64 time;
|
||||
gst_element_query_position(Element, GST_FORMAT_TIME, &time);
|
||||
return (float)((gdouble)time/GST_SECOND);
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
|
||||
void GstreamerAudioStream::SetPosition(float Position)
|
||||
{
|
||||
if(Element)
|
||||
{
|
||||
//Not sure if we need GST_SEEK_FLAG_ACCURATE
|
||||
if(!gst_element_seek_simple(Element, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), Position * GST_SECOND))
|
||||
LogError("Seek failed");
|
||||
}
|
||||
}
|
||||
|
||||
void GstreamerAudioStream::Fade(float TargetVolume, float Seconds)
|
||||
{
|
||||
Fading = true;
|
||||
g_timer_stop(FadeTimer);
|
||||
StartVolume = Volume;
|
||||
this->TargetVolume = TargetVolume / 100.0;
|
||||
FadeTime = (gdouble)Seconds;
|
||||
g_timer_start(FadeTimer);
|
||||
}
|
||||
|
||||
void GstreamerAudioStream::FadeAndPause(float TargetVolume, float Seconds)
|
||||
{
|
||||
PauseStreamAfterFade = true;
|
||||
|
||||
Fade(TargetVolume, FadeTime);
|
||||
}
|
||||
|
||||
void GstreamerAudioStream::FadeAndStop(float TargetVolume, float Seconds)
|
||||
{
|
||||
CloseStreamAfterFade = true;
|
||||
|
||||
Fade(TargetVolume, FadeTime);
|
||||
}
|
||||
|
||||
bool GstreamerAudioStream::IsPlaying()
|
||||
{
|
||||
GstStateChangeReturn ret;
|
||||
GstState current, pending;
|
||||
|
||||
//This might block!!!
|
||||
ret = gst_element_get_state (Element, ¤t, &pending, GST_CLOCK_TIME_NONE);
|
||||
return current == GST_STATE_PLAYING && !Finished;
|
||||
}
|
||||
|
||||
bool GstreamerAudioStream::IsPaused()
|
||||
{
|
||||
GstStateChangeReturn ret;
|
||||
GstState current, pending;
|
||||
|
||||
//This might block!!!
|
||||
ret = gst_element_get_state (Element, ¤t, &pending, GST_CLOCK_TIME_NONE);
|
||||
return current == GST_STATE_PAUSED && !Finished;
|
||||
}
|
||||
|
||||
bool GstreamerAudioStream::IsFinished()
|
||||
{
|
||||
return Finished;
|
||||
}
|
||||
|
||||
void GstreamerAudioStream::UpdateVolume()
|
||||
{
|
||||
if (Fading)
|
||||
{
|
||||
if (g_timer_elapsed(FadeTimer, NULL) < FadeTime) {
|
||||
gdouble vol = (StartVolume + (TargetVolume - StartVolume) * (g_timer_elapsed(FadeTimer, NULL) / FadeTime));
|
||||
SetStreamVolume(100.0 * vol);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetStreamVolume (TargetVolume * 100.0);
|
||||
g_timer_stop(FadeTimer);
|
||||
Fading = false;
|
||||
|
||||
if (CloseStreamAfterFade)
|
||||
{
|
||||
Closed = true;
|
||||
}
|
||||
|
||||
if (PauseStreamAfterFade)
|
||||
Pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GstreamerAudioStream::Update()
|
||||
{
|
||||
if(Running) {
|
||||
UpdateVolume();
|
||||
Message = gst_bus_pop (Bus);
|
||||
|
||||
/* Parse message */
|
||||
if (Message != NULL) {
|
||||
GError *err;
|
||||
gchar *debug_info;
|
||||
string m;
|
||||
|
||||
switch (GST_MESSAGE_TYPE (Message)) {
|
||||
case GST_MESSAGE_ERROR:
|
||||
gst_message_parse_error (Message, &err, &debug_info);
|
||||
m = err->message;
|
||||
LogError(m.c_str());
|
||||
g_clear_error (&err);
|
||||
g_free (debug_info);
|
||||
break;
|
||||
case GST_MESSAGE_DURATION_CHANGED:
|
||||
RefreshDuration();
|
||||
break;
|
||||
case GST_MESSAGE_STATE_CHANGED:
|
||||
break;
|
||||
case GST_MESSAGE_EOS:
|
||||
if(Loop)
|
||||
SetPosition(0);
|
||||
else
|
||||
Finished = true;
|
||||
break;
|
||||
default:
|
||||
/* We should not reach here */
|
||||
//LogError ("Unexpected message received.\n");
|
||||
break;
|
||||
}
|
||||
gst_message_unref (Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user