diff --git a/GstreamerHelper/GstreamerVideo.cpp b/GstreamerHelper/GstreamerVideo.cpp index a8edd0d9..8d0dc29c 100644 --- a/GstreamerHelper/GstreamerVideo.cpp +++ b/GstreamerHelper/GstreamerVideo.cpp @@ -77,12 +77,12 @@ DllExport float GetVideoLength(int Stream) else return -1.0; } -DllExport guint8* GetFrame(int Stream, float Time, float &VideoTime, int &Size, int &Width, int &Height) +DllExport struct ApplicationFrame GetFrame(int Stream, float Time) { map::iterator it = VideoStreams.find(Stream); if(it != VideoStreams.end()) { - return it->second->GetFrame(Time, VideoTime, Size, Width, Height); + return it->second->GetFrame(Time); } } diff --git a/GstreamerHelper/GstreamerVideo.h b/GstreamerHelper/GstreamerVideo.h index 4b14b4cf..e8020648 100644 --- a/GstreamerHelper/GstreamerVideo.h +++ b/GstreamerHelper/GstreamerVideo.h @@ -10,6 +10,14 @@ using namespace std; typedef void (__stdcall * LogCallback)(const char* text); static LogCallback Log; + struct ApplicationFrame { + guint8* buffer; + int size; + int width; + int height; + float videotime; + }; + DllExport void SetVideoLogCallback(LogCallback Callback); DllExport bool InitVideo(); @@ -20,7 +28,7 @@ using namespace std; DllExport int GetVideoNumStreams(); DllExport float GetVideoLength(int StreamID); - DllExport guint8* GetFrame(int StreamID, float Time, float &VideoTime, int &Size, int &Width, int &Height); + DllExport struct ApplicationFrame GetFrame(int StreamID, float Time); DllExport bool Skip(int StreamID, float Start, float Gap); DllExport void SetVideoLoop(int StreamID, bool Loop); DllExport void PauseVideo(int StreamID); diff --git a/GstreamerHelper/GstreamerVideoStream.cpp b/GstreamerHelper/GstreamerVideoStream.cpp index 63c954b8..1b19240a 100644 --- a/GstreamerHelper/GstreamerVideoStream.cpp +++ b/GstreamerHelper/GstreamerVideoStream.cpp @@ -19,6 +19,8 @@ GstreamerVideoStream::GstreamerVideoStream(int ID) { this->ID = ID; + g_main_loop_new(Context, false); + Loop = false; Running = true; @@ -49,31 +51,98 @@ int GstreamerVideoStream::LoadVideo(const wchar_t* Filename) LogVideoError ("Could not create element!"); return -1; } + + gst_app_sink_set_drop(Appsink, true); g_object_set(Element, "uri", Filename, NULL); - //g_object_set(Element, "video-sink", Appsink, NULL); + g_object_set(Element, "video-sink", Appsink, NULL); g_object_set(Element, "flags", GST_PLAY_FLAG_VIDEO, NULL); + g_object_set (Appsink, "emit-signals", TRUE, "sync", TRUE, NULL); + g_signal_connect(Appsink,"new-sample", G_CALLBACK(fake_callback),(gpointer)this); - //GstCaps *caps = gst_caps_new_any(); + GstCaps *caps; + caps = gst_caps_new_simple ("video/x-raw", + "format", G_TYPE_STRING, "BGRA", //We should use RGB for better performance here! Implement later + NULL); - //gst_caps_set_value(caps, "format", (GValue*)"RGBA"); - //gst_app_sink_set_caps(Appsink, caps); + gst_app_sink_set_caps(Appsink, caps); + gst_app_sink_set_max_buffers(Appsink, 1); gst_element_set_state(Element, GST_STATE_PLAYING); - //gst_bus_timed_pop_filtered(Bus, -1, GST_MESSAGE_ASYNC_DONE); + gst_element_set_state((GstElement*)Appsink, GST_STATE_PLAYING); + gst_bus_timed_pop_filtered(Bus, -1, GST_MESSAGE_ASYNC_DONE); + Paused = true; RefreshDuration(); return ID; } +GstFlowReturn GstreamerVideoStream::fake_callback(GstAppSink *sink,gpointer data) { + + GstreamerVideoStream* instance = (GstreamerVideoStream*)data; + return instance->NewBufferRecieved(sink); +} + +GstFlowReturn GstreamerVideoStream::NewBufferRecieved(GstAppSink *sink) +{ + float VideoTime = 0.0; + int Width = 0; + int Height = 0; + int Size = -1; + + Sample = gst_app_sink_pull_sample(Appsink); + if(Sample) { + BufferCaps = gst_sample_get_caps (Sample); + BufferStructure = gst_caps_get_structure (BufferCaps, 0); + + Buffer = gst_sample_get_buffer(Sample); + gst_buffer_map(Buffer, &Mapinfo, GST_MAP_READ); + + Size = Mapinfo.size; + gst_structure_get_int (BufferStructure, "width", &Width); + gst_structure_get_int (BufferStructure, "height", &Height); + VideoTime = (float) (Buffer->pts / GST_SECOND); + + if(Buffer && &Mapinfo) + { + gst_buffer_unmap(Buffer, &Mapinfo); + gst_buffer_unref(Buffer); + } + if(BufferCaps) + gst_caps_unref(BufferCaps); + + if(BufferStructure) + gst_object_unref(BufferStructure); + } + + Frame.buffer = Mapinfo.data; + Frame.height = Height; + Frame.width = Width; + Frame.size = Size; + Frame.videotime = VideoTime; + + return GST_FLOW_OK; +} + 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(Buffer && &Mapinfo) + //gst_buffer_unmap(Buffer, &Mapinfo); + if(Buffer) + gst_buffer_unref(Buffer); + if(BufferCaps) + gst_caps_unref(BufferCaps); + + if(BufferStructure) + gst_object_unref(BufferStructure); + + if(Element) + gst_element_set_state(Element, GST_STATE_NULL); if(Element) gst_object_unref(Element); return true; @@ -86,23 +155,9 @@ float GstreamerVideoStream::GetVideoLength() return Duration; } -guint8* GstreamerVideoStream::GetFrame(float Time, float &VideoTime, int &Size, int &Width, int &Height) +struct ApplicationFrame GstreamerVideoStream::GetFrame(float Time) { - /*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; + return Frame; } bool GstreamerVideoStream::Skip(float Start, float Gap) @@ -152,6 +207,7 @@ void GstreamerVideoStream::RefreshDuration() void GstreamerVideoStream::UpdateVideo() { if(Running) { + g_main_context_iteration(Context, false); Message = gst_bus_pop (Bus); /* Parse message */ diff --git a/GstreamerHelper/GstreamerVideoStream.h b/GstreamerHelper/GstreamerVideoStream.h index 296a8225..421a7ded 100644 --- a/GstreamerHelper/GstreamerVideoStream.h +++ b/GstreamerHelper/GstreamerVideoStream.h @@ -1,9 +1,11 @@ #pragma once +#include #include "gst/gst.h" #include "GstreamerVideo.h" #include "gst\app\gstappsink.h" using namespace std; + class GstreamerVideoStream { @@ -18,7 +20,7 @@ public: bool CloseVideo(); float GetVideoLength(); - guint8* GetFrame(float Time, float &VideoTime, int &Size, int &Width, int &Height); + struct ApplicationFrame GetFrame(float Time); bool Skip(float Start, float Gap); void SetVideoLoop(bool Loop); void PauseVideo(); @@ -29,11 +31,22 @@ public: bool IsFinished(); private: + + GMainLoop *MainLoop; + GMainContext *Context; + GstAppSink *Appsink; GstElement *Element; GstBus *Bus; GstMessage *Message; + + ApplicationFrame Frame; GstMapInfo Mapinfo; + GstSample *Sample; + GstBuffer *Buffer; + GstCaps *BufferCaps; + GstStructure *BufferStructure; + mutex Mutex; gboolean Loop; @@ -45,6 +58,9 @@ private: gfloat Duration; void RefreshDuration(); + + GstFlowReturn NewBufferRecieved(GstAppSink *Sink); + static GstFlowReturn fake_callback(GstAppSink *sink ,gpointer data); }; diff --git a/Output/x64/gstreamer/GstreamerHelper.dll b/Output/x64/gstreamer/GstreamerHelper.dll index 92fa8881..a8cae009 100644 Binary files a/Output/x64/gstreamer/GstreamerHelper.dll and b/Output/x64/gstreamer/GstreamerHelper.dll differ diff --git a/Vocaluxe/Lib/Video/CVideoDecoderGstreamer.cs b/Vocaluxe/Lib/Video/CVideoDecoderGstreamer.cs index 81db3594..72c59faf 100644 --- a/Vocaluxe/Lib/Video/CVideoDecoderGstreamer.cs +++ b/Vocaluxe/Lib/Video/CVideoDecoderGstreamer.cs @@ -63,9 +63,10 @@ namespace Vocaluxe.Lib.Video public bool GetFrame(int StreamID, ref STexture Frame, float Time, ref float VideoTime) { - //IntPtr buffer = CGstreamerVideoWrapper.GetFrame(StreamID, Time, ref VideoTime); - byte[] data = new byte[4 * 4 * 4]; - UploadNewFrame(ref Frame, ref data, 4, 4); + ManagedFrame frame = CGstreamerVideoWrapper.GetFrame(StreamID, Time); + VideoTime = frame.Videotime; + + UploadNewFrame(ref Frame, ref frame.buffer, frame.Width, frame.Height); return true; } @@ -101,14 +102,18 @@ namespace Vocaluxe.Lib.Video private void UploadNewFrame(ref STexture frame, ref byte[] Data, int Width, int Height) { - if (frame.index == -1 || Width != frame.width || Height != frame.height) + if (Data != null) { - CDraw.RemoveTexture(ref frame); - frame = CDraw.AddTexture(Width, Height, ref Data); - } - else - { - CDraw.UpdateTexture(ref frame, ref Data); + if (frame.index == -1 || Width != frame.width || Height != frame.height || Data.Length == 0) + { + CDraw.RemoveTexture(ref frame); + frame = CDraw.AddTexture(Width, Height, ref Data); + } + else + { + CDraw.UpdateTexture(ref frame, ref Data); + } + Data = null; } } } diff --git a/Vocaluxe/Lib/Video/Gstreamer/CGstreamerVideoWrapper.cs b/Vocaluxe/Lib/Video/Gstreamer/CGstreamerVideoWrapper.cs index 2a53d404..17368cf5 100644 --- a/Vocaluxe/Lib/Video/Gstreamer/CGstreamerVideoWrapper.cs +++ b/Vocaluxe/Lib/Video/Gstreamer/CGstreamerVideoWrapper.cs @@ -5,6 +5,23 @@ using System.Text; namespace Vocaluxe.Lib.Video.Gstreamer { + public struct NativeFrame { + public IntPtr buffer; + public int Size; + public int Width; + public int Height; + public float Videotime; + } + + public struct ManagedFrame + { + public byte[] buffer; + public int Size; + public int Width; + public int Height; + public float Videotime; + } + public static class CGstreamerVideoWrapper { #region arch @@ -44,14 +61,28 @@ namespace Vocaluxe.Lib.Video.Gstreamer public static extern float GetVideoLength(int StreamID); [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 extern NativeFrame GetFrameNative(int StreamID, float Time); - public static byte[] GetFrame(int StreamID, float Time, ref float VideoTime, ref int Size, ref int Width, ref int Height) + public static ManagedFrame GetFrame(int StreamID, float Time) { - 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; + NativeFrame f = GetFrameNative(StreamID, Time); + + byte[] buffer = null; + + if (f.Size > 0) + { + buffer = new byte[f.Size]; + Marshal.Copy(f.buffer, buffer, 0, f.Size); + } + + ManagedFrame m; + m.buffer = buffer; + m.Height = f.Height; + m.Size = f.Size; + m.Videotime = f.Videotime; + m.Width = f.Width; + return m; + } [DllImport(Dll)]