diff --git a/Plugin/VS/GStreamerUnityPlugin.vcxproj b/Plugin/VS/GStreamerUnityPlugin.vcxproj index 095bc27e..71a3c63b 100644 --- a/Plugin/VS/GStreamerUnityPlugin.vcxproj +++ b/Plugin/VS/GStreamerUnityPlugin.vcxproj @@ -28,26 +28,26 @@ DynamicLibrary true - v142 + v143 Unicode DynamicLibrary true - v142 + v143 MultiByte DynamicLibrary false - v142 + v143 true Unicode DynamicLibrary false - v142 + v143 true MultiByte @@ -129,7 +129,7 @@ Level3 Disabled - USE_UNITY_GRABBER;USE_UNITY_NETWORK;WIN32;_DEBUG;_WINDOWS;_USRDLL;GSTREAMERUNITYPLUGIN_EXPORTS;%(PreprocessorDefinitions) + USE_UNITY_GRABBER;WIN32;_DEBUG;_WINDOWS;_USRDLL;GSTREAMERUNITYPLUGIN_EXPORTS;%(PreprocessorDefinitions) ./;../includes;../includes/Win32;../sources;%(AdditionalIncludeDirectories) @@ -163,7 +163,7 @@ MaxSpeed - USE_UNITY_GRABBER;__USE_UNITY_NETWORK;WIN32;NDEBUG;_WINDOWS;_USRDLL;GSTREAMERUNITYPLUGIN_EXPORTS;%(PreprocessorDefinitions) + USE_UNITY_GRABBER;WIN32;NDEBUG;_WINDOWS;_USRDLL;GSTREAMERUNITYPLUGIN_EXPORTS;%(PreprocessorDefinitions) ./;../includes;../includes/Win32;../sources;%(AdditionalIncludeDirectories) @@ -225,12 +225,27 @@ true - - - + + false + false + + + true + true + + + true + true + - - + + true + true + + + true + true + @@ -239,7 +254,10 @@ - + + true + true + @@ -280,14 +298,29 @@ - - - + + false + false + + + true + true + + + true + true + Disabled - - + + true + true + + + true + true + Disabled @@ -309,7 +342,10 @@ Disabled - + + true + true + diff --git a/Plugin/sources/GstCustomVideoStreamer.cpp b/Plugin/sources/GstCustomVideoStreamer.cpp index 6f039846..8691ef1f 100644 --- a/Plugin/sources/GstCustomVideoStreamer.cpp +++ b/Plugin/sources/GstCustomVideoStreamer.cpp @@ -23,6 +23,8 @@ class GstCustomVideoStreamerImpl : public GstPipelineHandler, std::string m_pipeLineString; std::string m_srcPipeLineString; + ConnectionStatusCallback m_connectionStatusCallback = nullptr; + int m_fps; Vector2d m_frameSize; @@ -60,6 +62,11 @@ class GstCustomVideoStreamerImpl : public GstPipelineHandler, m_fps = fps; } + void SetConnectionStatusCallback(ConnectionStatusCallback cb) + { + m_connectionStatusCallback = cb; + } + std::string GetFormatStr(EPixelFormat fmt) { std::string format = "RGB"; switch (fmt) { @@ -313,6 +320,38 @@ class GstCustomVideoStreamerImpl : public GstPipelineHandler, virtual void OnPipelineStopped(GstPipelineHandler* p) { m_owner->__FIRE_OnStreamerStopped(m_owner); } + virtual void OnPipelineError(GstPipelineHandler* p, const std::string& elementName) + { + if (m_connectionStatusCallback && elementName.find("rtspclientsink") != std::string::npos) + { + m_connectionStatusCallback(false); + } + } + virtual void OnPipelineProgress(GstPipelineHandler* p, int progressType, const std::string& code, const std::string& info) override + { + if(!m_connectionStatusCallback) + { + return; + } + + switch (progressType) + { + case 2: // GST_PROGRESS_TYPE_COMPLETE + if (code.find("open") != std::string::npos) + { + m_connectionStatusCallback(true); + } + break; + case 4: // GST_PROGRESS_TYPE_ERROR + if (code.find("open") != std::string::npos) + { + m_connectionStatusCallback(false); + } + break; + default: + break; + } + } }; GstCustomVideoStreamer::GstCustomVideoStreamer() { @@ -336,6 +375,11 @@ void GstCustomVideoStreamer::SetResolution(int width, int height, int fps) { m_impl->SetResolution(width, height, fps); } +void GstCustomVideoStreamer::SetConnectionStatusCallback(ConnectionStatusCallback cb) +{ + m_impl->SetConnectionStatusCallback(cb); +} + void GstCustomVideoStreamer::SetVideoGrabber(IVideoGrabber* grabber0) { m_impl->SetVideoGrabber(grabber0); } diff --git a/Plugin/sources/GstCustomVideoStreamer.h b/Plugin/sources/GstCustomVideoStreamer.h index a870cc0f..f8829679 100644 --- a/Plugin/sources/GstCustomVideoStreamer.h +++ b/Plugin/sources/GstCustomVideoStreamer.h @@ -20,6 +20,7 @@ author: MHD Yamen Saraiji #define GstCustomVideoStreamer_h__ #include "IGStreamerStreamer.h" +#include "Unity/IUnityInterface.h" #include namespace mray @@ -30,6 +31,12 @@ namespace video class GstCustomVideoStreamerImpl; class IVideoGrabber; +// Uggly fix to expose the ConnectionStatusCallback signature where relevant. +extern "C" +{ + typedef void(UNITY_INTERFACE_API* ConnectionStatusCallback)(bool); +} + class GstCustomVideoStreamer :public IGStreamerStreamer { protected: @@ -50,7 +57,8 @@ class GstCustomVideoStreamer :public IGStreamerStreamer virtual void Close(); void SetVideoGrabber(IVideoGrabber* grabber0); - void SetResolution(int width, int height, int fps); + void SetResolution(int width, int height, int fps); + void SetConnectionStatusCallback(ConnectionStatusCallback cb); virtual void SetPaused(bool paused); virtual bool IsPaused(); diff --git a/Plugin/sources/GstPipelineHandler.cpp b/Plugin/sources/GstPipelineHandler.cpp index 8125e711..527959a1 100644 --- a/Plugin/sources/GstPipelineHandler.cpp +++ b/Plugin/sources/GstPipelineHandler.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "GStreamerCore.h" #include "IThreadManager.h" @@ -368,9 +369,16 @@ long GstPipelineHandler::GetDuration() { } bool GstPipelineHandler::IsResettingEOS() { return m_data->_restartingEOS; } void GstPipelineHandler::SetPaused(bool p) { + if (m_data->gstPipeline == NULL && m_data->busWatchID == 0) + { + m_data->paused = true; + m_data->Loaded = false; + m_data->playing = false; + return; + } std::lock_guard lock(GetMutex()); m_data->paused = p; - if (m_data->Loaded || true) { + if (m_data->Loaded) { if (m_data->playing) { GstState state; if (m_data->paused) { @@ -405,9 +413,18 @@ void GstPipelineHandler::SetPaused(bool p) { } } void GstPipelineHandler::Stop() { + if (m_data->gstPipeline == NULL && m_data->busWatchID == 0) + { + m_data->paused = true; + m_data->Loaded = false; + m_data->playing = false; + return; + } + LogMessage(m_data->_name + ": GstPipelineHandler::Stop ", ELL_INFO); if (!m_data->Loaded) return; std::lock_guard lock(GetMutex()); + if (m_data->paused == true && m_data->playing == false) return; GstState state; m_data->_seekPos = GST_CLOCK_TIME_NONE; // gst_element_send_event(m_data->gstPipeline, gst_event_new_eos()); @@ -444,11 +461,16 @@ bool GstPipelineHandler::QueryLatency(bool &isLive, ulong &minLatency, return ok; } void GstPipelineHandler::Close() { + if (m_data->gstPipeline == NULL && m_data->busWatchID == 0) + { + m_data->Loaded = false; + return; + } LogMessage(m_data->_name + ": GstPipelineHandler::Close ", ELL_INFO); std::lock_guard lock(GetMutex()); Stop(); - if (true || m_data->Loaded) { + if (m_data->Loaded) { if (m_data->busWatchID != 0) g_source_remove(m_data->busWatchID); m_data->busWatchID = 0; @@ -607,27 +629,30 @@ bool GstPipelineHandler::HandleMessage(GstBus *bus, GstMessage *msg) { case GST_MESSAGE_PROGRESS: { GstProgressType type; gchar *code, *text; - bool in_progress = false; gst_message_parse_progress(msg, &type, &code, &text); switch (type) { case GST_PROGRESS_TYPE_START: case GST_PROGRESS_TYPE_CONTINUE: - in_progress = TRUE; - break; case GST_PROGRESS_TYPE_COMPLETE: case GST_PROGRESS_TYPE_CANCELED: case GST_PROGRESS_TYPE_ERROR: - in_progress = FALSE; + { + const std::string progressCode(code); + const std::string progressInfo(text); + FIRE_LISTENR_METHOD(OnPipelineProgress, (this, type, progressCode, progressInfo)); + } break; default: break; } - LogMessage("Progress: (" + std::string(code) + ") " + std::string(text), - ELL_INFO); + LogMessage("Progress: (" + std::to_string(type) + ") (" + + std::string(code) + ") " + std::string(text), + ELL_INFO); g_free(code); g_free(text); - } break; + } + break; case GST_MESSAGE_WARNING: { GError *err; @@ -668,15 +693,16 @@ bool GstPipelineHandler::HandleMessage(GstBus *bus, GstMessage *msg) { std::string(" - ") + debug, ELL_WARNING); + + const std::string gstElementName(name); + if (m_data) { + FIRE_LISTENR_METHOD(OnPipelineError, (this, gstElementName)); + } + g_free(name); g_error_free(err); g_free(debug); - if (m_data) { - FIRE_LISTENR_METHOD(OnPipelineError, (this)); - // gst_element_set_state(GST_ELEMENT(m_data->gstPipeline), - // GST_STATE_NULL); - } } break; default: diff --git a/Plugin/sources/GstPipelineHandler.h b/Plugin/sources/GstPipelineHandler.h index cad5ff78..765e1fa8 100644 --- a/Plugin/sources/GstPipelineHandler.h +++ b/Plugin/sources/GstPipelineHandler.h @@ -25,7 +25,7 @@ class IPipelineListener { virtual void OnPipelineStopped(GstPipelineHandler* p) {} virtual void OnPipelineClosed(GstPipelineHandler* p) {} virtual void OnPipelineWarning(GstPipelineHandler* p) {} - virtual void OnPipelineError(GstPipelineHandler* p) {} + virtual void OnPipelineError(GstPipelineHandler* p, const std::string& elementName) {} virtual void OnPipelineEOS(GstPipelineHandler* p) {} virtual void OnPipelineBuffering(GstPipelineHandler* p, int percent) {} @@ -34,6 +34,7 @@ class IPipelineListener { virtual void OnPreSeek(GstPipelineHandler* p, long pos) {} virtual void OnPostSeek(GstPipelineHandler* p) {} + virtual void OnPipelineProgress(GstPipelineHandler* p, int progressType, const std::string& code, const std::string& info) {} }; class GstPipelineHandler : public ListenerContainer { @@ -48,7 +49,7 @@ class GstPipelineHandler : public ListenerContainer { DECLARE_FIRE_METHOD(OnPipelineStopped, (GstPipelineHandler * p), (p)); DECLARE_FIRE_METHOD(OnPipelineClosed, (GstPipelineHandler * p), (p)); DECLARE_FIRE_METHOD(OnPipelineWarning, (GstPipelineHandler * p), (p)); - DECLARE_FIRE_METHOD(OnPipelineError, (GstPipelineHandler * p), (p)); + DECLARE_FIRE_METHOD(OnPipelineError, (GstPipelineHandler * p, const std::string& elementName), (p, elementName)); DECLARE_FIRE_METHOD(OnPipelineEOS, (GstPipelineHandler * p), (p)); DECLARE_FIRE_METHOD(OnPreSeek, (GstPipelineHandler * p, long pos), (p, pos)); DECLARE_FIRE_METHOD(OnPostSeek, (GstPipelineHandler * p), (p)); @@ -58,6 +59,7 @@ class GstPipelineHandler : public ListenerContainer { (p, prevState, newState, pendState)); DECLARE_FIRE_METHOD(OnPipelineBuffering, (GstPipelineHandler * p, int percent), (p, percent)); + DECLARE_FIRE_METHOD(OnPipelineProgress, (GstPipelineHandler* p, int progressType, const std::string& code, const std::string& info), (p, progressType, code, info)); public: GstPipelineHandler(const char* name = ""); diff --git a/Plugin/sources/StreamersAPI.cpp b/Plugin/sources/StreamersAPI.cpp index ff6e264d..58da9207 100644 --- a/Plugin/sources/StreamersAPI.cpp +++ b/Plugin/sources/StreamersAPI.cpp @@ -149,6 +149,17 @@ extern "C" UNITY_INTERFACE_EXPORT void mray_gst_customImageStreamerSetResolution } } +extern "C" +{ + UNITY_INTERFACE_EXPORT void mray_gst_customImageStreamerSetConnectionStatusCallback(GstCustomVideoStreamer* p, ConnectionStatusCallback cb) + { + if (p) + { + p->SetConnectionStatusCallback(cb); + } + } +} + #ifdef USE_UNITY_NETWORK extern "C" UNITY_INTERFACE_EXPORT void *mray_gst_createNetworkStreamer() diff --git a/Unity/UnityTests/Assets/GStreamerUnity/Scripts/GstCustomVideoStreamer.cs b/Unity/UnityTests/Assets/GStreamerUnity/Scripts/GstCustomVideoStreamer.cs index 1936ce50..cd634341 100644 --- a/Unity/UnityTests/Assets/GStreamerUnity/Scripts/GstCustomVideoStreamer.cs +++ b/Unity/UnityTests/Assets/GStreamerUnity/Scripts/GstCustomVideoStreamer.cs @@ -2,6 +2,8 @@ using System.Collections; using System.Runtime.InteropServices; +namespace GStreamerUnity{ + public class GstCustomVideoStreamer:IGstStreamer { @@ -17,6 +19,15 @@ public class GstCustomVideoStreamer:IGstStreamer { [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] extern static private int mray_gst_customImageStreamerSetResolution(System.IntPtr p,int width, int height, int fps); + + public delegate void ConnectionStatusCallback(bool isConnected); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + extern static internal void + mray_gst_customImageStreamerSetConnectionStatusCallback( + System.IntPtr p, + [MarshalAs(UnmanagedType.FunctionPtr)] ConnectionStatusCallback callbackPointer); + GstUnityImageGrabber _grabber; public GstCustomVideoStreamer() @@ -44,4 +55,11 @@ public void SetResolution(int w,int h,int fps) { mray_gst_customImageStreamerSetResolution (m_Instance, w,h,fps); } + + public void SetCallback(ConnectionStatusCallback cb) + { + mray_gst_customImageStreamerSetConnectionStatusCallback(m_Instance, cb); + } +} + } diff --git a/Unity/UnityTests/Assets/GStreamerUnity/Scripts/GstUnityImageGrabber.cs b/Unity/UnityTests/Assets/GStreamerUnity/Scripts/GstUnityImageGrabber.cs index 810f9874..2bfd4d31 100644 --- a/Unity/UnityTests/Assets/GStreamerUnity/Scripts/GstUnityImageGrabber.cs +++ b/Unity/UnityTests/Assets/GStreamerUnity/Scripts/GstUnityImageGrabber.cs @@ -3,6 +3,8 @@ using System.Runtime.InteropServices; using System; +namespace GStreamerUnity{ + public class GstUnityImageGrabber { enum EPixelFormat @@ -141,3 +143,5 @@ public void Update() mray_gst_UnityImageGrabberSetData (m_Instance, m_lastArrayPtr, m_width,m_height, (int)m_format); } } + +} \ No newline at end of file diff --git a/Unity/UnityTests/Assets/GStreamerUnity/Scripts/IGstStreamer.cs b/Unity/UnityTests/Assets/GStreamerUnity/Scripts/IGstStreamer.cs index fb1cf6e5..6335448c 100644 --- a/Unity/UnityTests/Assets/GStreamerUnity/Scripts/IGstStreamer.cs +++ b/Unity/UnityTests/Assets/GStreamerUnity/Scripts/IGstStreamer.cs @@ -2,6 +2,9 @@ using System.Collections; using System.Runtime.InteropServices; + +namespace GStreamerUnity{ + public class IGstStreamer : MonoBehaviour { internal const string DllName = "GStreamerUnityPlugin"; @@ -81,3 +84,5 @@ public void Close() mray_gst_StreamerClose (m_Instance); } } + +} \ No newline at end of file