diff --git a/GstreamerHelper/GstreamerHelper.vcxproj b/GstreamerHelper/GstreamerHelper.vcxproj
index 4ae10323..746f8d6a 100644
--- a/GstreamerHelper/GstreamerHelper.vcxproj
+++ b/GstreamerHelper/GstreamerHelper.vcxproj
@@ -122,7 +122,7 @@
Windows
true
- gstreamer-1.0.lib;gstcontroller-1.0.lib;gobject-2.0.lib;glib-2.0.lib;%(AdditionalDependencies)
+ gstreamer-1.0.lib;gstcontroller-1.0.lib;gobject-2.0.lib;glib-2.0.lib;gstapp-1.0.lib;%(AdditionalDependencies)
diff --git a/GstreamerHelper/GstreamerVideo.cpp b/GstreamerHelper/GstreamerVideo.cpp
index 24881aa5..a8edd0d9 100644
--- a/GstreamerHelper/GstreamerVideo.cpp
+++ b/GstreamerHelper/GstreamerVideo.cpp
@@ -55,9 +55,11 @@ DllExport bool CloseVideo(int Stream)
map::iterator it = VideoStreams.find(Stream);
if(it != VideoStreams.end())
{
- return it->second->CloseVideo();
+ delete it->second;
+ VideoStreams.erase(it);
}
else return false;
+ return true;
}
DllExport int GetVideoNumStreams()
@@ -75,12 +77,12 @@ DllExport float GetVideoLength(int Stream)
else return -1.0;
}
-DllExport UINT8* GetFrame(int Stream, float Time, float &VideoTime)
+DllExport guint8* GetFrame(int Stream, float Time, float &VideoTime, int &Size, int &Width, int &Height)
{
map::iterator it = VideoStreams.find(Stream);
if(it != VideoStreams.end())
{
- return it->second->GetFrame(Time, VideoTime);
+ return it->second->GetFrame(Time, VideoTime, Size, Width, Height);
}
}
@@ -126,7 +128,30 @@ DllExport bool Finished(int Stream)
map::iterator it = VideoStreams.find(Stream);
if(it != VideoStreams.end())
{
- return it->second->Finished();
+ return it->second->IsFinished();
}
else return true;
}
+
+DllExport void UpdateVideo(void)
+{
+ map::iterator p = VideoStreams.begin();
+
+ while(p != VideoStreams.end())
+ {
+ if(p->second->Closed)
+ {
+ delete p->second;
+ VideoStreams.erase(p++);
+ }
+ else {
+ p->second->UpdateVideo();
+ ++p;
+ }
+ }
+}
+
+void LogVideoError(const char* msg)
+{
+ Log(msg);
+}
\ No newline at end of file
diff --git a/GstreamerHelper/GstreamerVideo.h b/GstreamerHelper/GstreamerVideo.h
index 57930064..4b14b4cf 100644
--- a/GstreamerHelper/GstreamerVideo.h
+++ b/GstreamerHelper/GstreamerVideo.h
@@ -20,7 +20,7 @@ using namespace std;
DllExport int GetVideoNumStreams();
DllExport float GetVideoLength(int StreamID);
- DllExport UINT8* GetFrame(int StreamID, float Time, float &VideoTime);
+ DllExport guint8* GetFrame(int StreamID, float Time, float &VideoTime, int &Size, int &Width, int &Height);
DllExport bool Skip(int StreamID, float Start, float Gap);
DllExport void SetVideoLoop(int StreamID, bool Loop);
DllExport void PauseVideo(int StreamID);
@@ -28,5 +28,7 @@ using namespace std;
DllExport bool Finished(int StreamID);
+ DllExport void UpdateVideo();
+
void LogVideoError(const char* msg);
diff --git a/GstreamerHelper/GstreamerVideoStream.cpp b/GstreamerHelper/GstreamerVideoStream.cpp
index c23f90d0..63c954b8 100644
--- a/GstreamerHelper/GstreamerVideoStream.cpp
+++ b/GstreamerHelper/GstreamerVideoStream.cpp
@@ -1,56 +1,190 @@
#include "stdafx.h"
#include "GstreamerVideoStream.h"
+typedef enum {
+ GST_PLAY_FLAG_VIDEO = (1 << 0),
+ GST_PLAY_FLAG_AUDIO = (1 << 1),
+ GST_PLAY_FLAG_TEXT = (1 << 2),
+ GST_PLAY_FLAG_VIS = (1 << 3),
+ GST_PLAY_FLAG_SOFT_VOLUME = (1 << 4),
+ GST_PLAY_FLAG_NATIVE_AUDIO = (1 << 5),
+ GST_PLAY_FLAG_NATIVE_VIDEO = (1 << 6),
+ GST_PLAY_FLAG_DOWNLOAD = (1 << 7),
+ GST_PLAY_FLAG_BUFFERING = (1 << 8),
+ GST_PLAY_FLAG_DEINTERLACE = (1 << 9),
+ GST_PLAY_FLAG_SOFT_COLORBALANCE = (1 << 10)
+} GstPlayFlags;
GstreamerVideoStream::GstreamerVideoStream(int ID)
{
this->ID = ID;
+
+ Loop = false;
+
+ Running = true;
+
+ Paused = false;
+ Finished = false;
+ Closed = false;
+
+ Duration = -1.0;
}
GstreamerVideoStream::~GstreamerVideoStream(void)
{
+ CloseVideo();
}
int GstreamerVideoStream::LoadVideo(const wchar_t* Filename)
{
+ Element = gst_element_factory_make("playbin", "playbin");
+
+
+ Appsink = (GstAppSink*) gst_element_factory_make("appsink", "appsink");
+
+ Bus = gst_element_get_bus(Element);
+ if(!Element)
+ {
+ LogVideoError ("Could not create element!");
+ return -1;
+ }
+ g_object_set(Element, "uri", Filename, NULL);
+ //g_object_set(Element, "video-sink", Appsink, NULL);
+ g_object_set(Element, "flags", GST_PLAY_FLAG_VIDEO, NULL);
+
+ //GstCaps *caps = gst_caps_new_any();
+
+ //gst_caps_set_value(caps, "format", (GValue*)"RGBA");
+ //gst_app_sink_set_caps(Appsink, caps);
+
+ gst_element_set_state(Element, GST_STATE_PLAYING);
+ //gst_bus_timed_pop_filtered(Bus, -1, GST_MESSAGE_ASYNC_DONE);
+ Paused = true;
+ RefreshDuration();
+
return ID;
}
-
bool GstreamerVideoStream::CloseVideo()
{
+ if(Element)
+ gst_element_set_state(Element, GST_STATE_NULL);
+ if(Appsink)
+ gst_object_unref(Appsink);
+ if(Bus)
+ gst_object_unref(Bus);
+ if(Element)
+ gst_object_unref(Element);
return true;
}
float GstreamerVideoStream::GetVideoLength()
{
- return 0.0;
+ if(Duration <= 0)
+ RefreshDuration();
+ return Duration;
}
-UINT8* GstreamerVideoStream::GetFrame(float Time, float &VideoTime)
+guint8* GstreamerVideoStream::GetFrame(float Time, float &VideoTime, int &Size, int &Width, int &Height)
{
+ /*GstSample *sample;
+ GstBuffer *buffer;
+ GstElement *sink;
+
+ sample = gst_app_sink_pull_sample(Appsink);
+ buffer = gst_sample_get_buffer(sample);
+
+ g_object_get(Element, "video-sink", &sink, NULL);
+
+ gst_buffer_map(buffer, &Mapinfo, GST_MAP_READ);
+
+ VideoTime = (float) (buffer->pts / GST_SECOND);
+ Size = Mapinfo.size;
+ return Mapinfo.data; */
return 0;
}
bool GstreamerVideoStream::Skip(float Start, float Gap)
{
- return true;
+ if(!gst_element_seek_simple(Element, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), (Start + Gap) * GST_SECOND))
+ {
+ LogVideoError("Seek failed");
+ return true;
+ }
+ return false;
}
void GstreamerVideoStream::SetVideoLoop(bool Loop)
{
+ this->Loop = Loop;
}
void GstreamerVideoStream::PauseVideo()
{
+ if(Element)
+ gst_element_set_state(Element, GST_STATE_PAUSED);
}
void GstreamerVideoStream::ResumeVideo()
{
+ if(Element)
+ gst_element_set_state(Element, GST_STATE_PLAYING);
}
-bool GstreamerVideoStream::Finished()
+bool GstreamerVideoStream::IsFinished()
{
- return true;
+ return Finished;
}
+
+void GstreamerVideoStream::RefreshDuration()
+{
+ if(Element)
+ {
+ gint64 time;
+ if(!gst_element_query_duration(Element, GST_FORMAT_TIME, &time)) {
+ LogVideoError("Could not query duration");
+ }
+ Duration = (gfloat)((gdouble)(time/GST_SECOND));
+ }
+}
+
+void GstreamerVideoStream::UpdateVideo()
+{
+ if(Running) {
+ 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;
+ LogVideoError(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)
+ Skip(0, 0);
+ else
+ Finished = true;
+ break;
+ default:
+ /* We should not reach here */
+ //LogError ("Unexpected message received.\n");
+ break;
+ }
+ gst_message_unref (Message);
+ }
+ }
+}
\ No newline at end of file
diff --git a/GstreamerHelper/GstreamerVideoStream.h b/GstreamerHelper/GstreamerVideoStream.h
index a355a254..296a8225 100644
--- a/GstreamerHelper/GstreamerVideoStream.h
+++ b/GstreamerHelper/GstreamerVideoStream.h
@@ -1,11 +1,15 @@
#pragma once
#include "gst/gst.h"
+#include "GstreamerVideo.h"
+#include "gst\app\gstappsink.h"
+
using namespace std;
class GstreamerVideoStream
{
public:
int ID;
+ bool Closed;
GstreamerVideoStream(int ID);
~GstreamerVideoStream(void);
@@ -14,12 +18,33 @@ public:
bool CloseVideo();
float GetVideoLength();
- UINT8* GetFrame(float Time, float &VideoTime);
+ guint8* GetFrame(float Time, float &VideoTime, int &Size, int &Width, int &Height);
bool Skip(float Start, float Gap);
void SetVideoLoop(bool Loop);
void PauseVideo();
void ResumeVideo();
- bool Finished();
+ void UpdateVideo();
+
+ bool IsFinished();
+
+private:
+ GstAppSink *Appsink;
+ GstElement *Element;
+ GstBus *Bus;
+ GstMessage *Message;
+ GstMapInfo Mapinfo;
+
+ gboolean Loop;
+
+ gboolean Running;
+
+ gboolean Paused;
+ gboolean Finished;
+
+ gfloat Duration;
+
+ void RefreshDuration();
};
+
diff --git a/Output/x64/gstreamer/GstreamerHelper.dll b/Output/x64/gstreamer/GstreamerHelper.dll
index 22465ffd..92fa8881 100644
Binary files a/Output/x64/gstreamer/GstreamerHelper.dll and b/Output/x64/gstreamer/GstreamerHelper.dll differ
diff --git a/Vocaluxe/Base/CGraphics.cs b/Vocaluxe/Base/CGraphics.cs
index b85b2a9b..6433af02 100644
--- a/Vocaluxe/Base/CGraphics.cs
+++ b/Vocaluxe/Base/CGraphics.cs
@@ -319,6 +319,7 @@ namespace Vocaluxe.Base
Mouse.CopyEvents();
Keys.CopyEvents();
+ CVideo.Update();
CSound.Update();
CBackgroundMusic.Update();
CInput.Update();
diff --git a/Vocaluxe/Base/CVideo.cs b/Vocaluxe/Base/CVideo.cs
index 766e90d2..811b5387 100644
--- a/Vocaluxe/Base/CVideo.cs
+++ b/Vocaluxe/Base/CVideo.cs
@@ -95,6 +95,11 @@ namespace Vocaluxe.Base
return _VideoDecoder.Finished(StreamID);
}
+ public static void Update()
+ {
+ _VideoDecoder.Update();
+ }
+
#endregion Interface
#endregion VideoDecoder
diff --git a/Vocaluxe/Lib/Video/CVideoDecoder.cs b/Vocaluxe/Lib/Video/CVideoDecoder.cs
index da4150db..52197a08 100644
--- a/Vocaluxe/Lib/Video/CVideoDecoder.cs
+++ b/Vocaluxe/Lib/Video/CVideoDecoder.cs
@@ -68,6 +68,10 @@ namespace Vocaluxe.Lib.Video
return false;
}
+ public virtual void Update()
+ {
+ }
+
protected bool AlreadyAdded(int StreamID)
{
foreach (VideoStreams st in _Streams)
diff --git a/Vocaluxe/Lib/Video/CVideoDecoderGstreamer.cs b/Vocaluxe/Lib/Video/CVideoDecoderGstreamer.cs
index 391a0f09..81db3594 100644
--- a/Vocaluxe/Lib/Video/CVideoDecoderGstreamer.cs
+++ b/Vocaluxe/Lib/Video/CVideoDecoderGstreamer.cs
@@ -1,15 +1,31 @@
using System;
using System.Collections.Generic;
using System.Text;
+using Vocaluxe.Base;
using Vocaluxe.Lib.Video.Gstreamer;
+using Vocaluxe.Menu;
namespace Vocaluxe.Lib.Video
{
class CVideoDecoderGstreamer : IVideoDecoder
{
+ #region log
+ public CGstreamerVideoWrapper.LogCallback Log;
+
+ private void LogHandler(string text)
+ {
+ CLog.LogError(text);
+
+ }
+ #endregion log
+
public bool Init()
{
- return CGstreamerVideoWrapper.InitVideo();
+ bool retval = CGstreamerVideoWrapper.InitVideo();
+ Log = new CGstreamerVideoWrapper.LogCallback(LogHandler);
+ GC.SuppressFinalize(Log);
+ CGstreamerVideoWrapper.SetVideoLogCallback(Log);
+ return retval;
}
public void CloseAll()
@@ -19,7 +35,15 @@ namespace Vocaluxe.Lib.Video
public int Load(string VideoFileName)
{
- return CGstreamerVideoWrapper.LoadVideo(VideoFileName);
+ int i = -1;
+ try
+ {
+ Uri u = new Uri(VideoFileName);
+ i = CGstreamerVideoWrapper.LoadVideo(u.AbsoluteUri);
+ return i;
+ }
+ catch (Exception e) { }
+ return i;
}
public bool Close(int StreamID)
@@ -37,9 +61,11 @@ namespace Vocaluxe.Lib.Video
return CGstreamerVideoWrapper.GetVideoLength(StreamID);
}
- public bool GetFrame(int StreamID, ref Menu.STexture Frame, float Time, ref float VideoTime)
+ public bool GetFrame(int StreamID, ref STexture Frame, float Time, ref float VideoTime)
{
- IntPtr buffer = CGstreamerVideoWrapper.GetFrame(StreamID, Time, ref VideoTime);
+ //IntPtr buffer = CGstreamerVideoWrapper.GetFrame(StreamID, Time, ref VideoTime);
+ byte[] data = new byte[4 * 4 * 4];
+ UploadNewFrame(ref Frame, ref data, 4, 4);
return true;
}
@@ -67,5 +93,23 @@ namespace Vocaluxe.Lib.Video
{
return CGstreamerVideoWrapper.Finished(StreamID);
}
+
+ public void Update()
+ {
+ CGstreamerVideoWrapper.UpdateVideo();
+ }
+
+ private void UploadNewFrame(ref STexture frame, ref byte[] Data, int Width, int Height)
+ {
+ if (frame.index == -1 || Width != frame.width || Height != frame.height)
+ {
+ CDraw.RemoveTexture(ref frame);
+ frame = CDraw.AddTexture(Width, Height, ref Data);
+ }
+ else
+ {
+ CDraw.UpdateTexture(ref frame, ref Data);
+ }
+ }
}
}
diff --git a/Vocaluxe/Lib/Video/Gstreamer/CGstreamerVideoWrapper.cs b/Vocaluxe/Lib/Video/Gstreamer/CGstreamerVideoWrapper.cs
index ea9b775e..2a53d404 100644
--- a/Vocaluxe/Lib/Video/Gstreamer/CGstreamerVideoWrapper.cs
+++ b/Vocaluxe/Lib/Video/Gstreamer/CGstreamerVideoWrapper.cs
@@ -43,8 +43,16 @@ namespace Vocaluxe.Lib.Video.Gstreamer
[DllImport(Dll)]
public static extern float GetVideoLength(int StreamID);
- [DllImport(Dll)]
- public static extern IntPtr GetFrame(int StreamID, float Time, ref float VideoTime);
+ [DllImport(Dll, EntryPoint="GetFrame")]
+ public static extern IntPtr GetFrameNative(int StreamID, float Time, ref float VideoTime, ref int Size, ref int Width, ref int Height);
+
+ public static byte[] GetFrame(int StreamID, float Time, ref float VideoTime, ref int Size, ref int Width, ref int Height)
+ {
+ IntPtr buf = GetFrameNative(StreamID, Time, ref VideoTime, ref Size, ref Width, ref Height);
+ byte[] buffer = new byte[Size];
+ Marshal.Copy(buf, buffer, 0, Size);
+ return buffer;
+ }
[DllImport(Dll)]
public static extern bool Skip(int StreamID, float Start, float Gap);
@@ -61,5 +69,8 @@ namespace Vocaluxe.Lib.Video.Gstreamer
[DllImport(Dll)]
public static extern bool Finished(int StreamID);
+ [DllImport(Dll)]
+ public static extern bool UpdateVideo();
+
}
}
diff --git a/Vocaluxe/Lib/Video/IVideoDecoder.cs b/Vocaluxe/Lib/Video/IVideoDecoder.cs
index 2f12f2b3..783e9a84 100644
--- a/Vocaluxe/Lib/Video/IVideoDecoder.cs
+++ b/Vocaluxe/Lib/Video/IVideoDecoder.cs
@@ -36,5 +36,7 @@ namespace Vocaluxe.Lib.Video
void Resume(int StreamID);
bool Finished(int StreamID);
+
+ void Update();
}
}
diff --git a/gstreamerhelper/x64/lib/gstapp-1.0.lib b/gstreamerhelper/x64/lib/gstapp-1.0.lib
new file mode 100644
index 00000000..9d5f770b
Binary files /dev/null and b/gstreamerhelper/x64/lib/gstapp-1.0.lib differ