First working gstreamer video output.
Frames are not in sync with the time provided in GetFrame! Need to implement a own GstClock for that first
This commit is contained in:
1 parent
d66e47ff47
commit
a7e528109a
7 files changed
+159
-43
No files matched your search
@@ -77,12 +77,12 @@ DllExport float GetVideoLength(int Stream)
|
|||||||
else return -1.0;
|
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<int,GstreamerVideoStream*>::iterator it = VideoStreams.find(Stream);
|
map<int,GstreamerVideoStream*>::iterator it = VideoStreams.find(Stream);
|
||||||
if(it != VideoStreams.end())
|
if(it != VideoStreams.end())
|
||||||
{
|
{
|
||||||
return it->second->GetFrame(Time, VideoTime, Size, Width, Height);
|
return it->second->GetFrame(Time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,14 @@ using namespace std;
|
|||||||
typedef void (__stdcall * LogCallback)(const char* text);
|
typedef void (__stdcall * LogCallback)(const char* text);
|
||||||
static LogCallback Log;
|
static LogCallback Log;
|
||||||
|
|
||||||
|
struct ApplicationFrame {
|
||||||
|
guint8* buffer;
|
||||||
|
int size;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
float videotime;
|
||||||
|
};
|
||||||
|
|
||||||
DllExport void SetVideoLogCallback(LogCallback Callback);
|
DllExport void SetVideoLogCallback(LogCallback Callback);
|
||||||
|
|
||||||
DllExport bool InitVideo();
|
DllExport bool InitVideo();
|
||||||
@@ -20,7 +28,7 @@ using namespace std;
|
|||||||
DllExport int GetVideoNumStreams();
|
DllExport int GetVideoNumStreams();
|
||||||
|
|
||||||
DllExport float GetVideoLength(int StreamID);
|
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 bool Skip(int StreamID, float Start, float Gap);
|
||||||
DllExport void SetVideoLoop(int StreamID, bool Loop);
|
DllExport void SetVideoLoop(int StreamID, bool Loop);
|
||||||
DllExport void PauseVideo(int StreamID);
|
DllExport void PauseVideo(int StreamID);
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ GstreamerVideoStream::GstreamerVideoStream(int ID)
|
|||||||
{
|
{
|
||||||
this->ID = ID;
|
this->ID = ID;
|
||||||
|
|
||||||
|
g_main_loop_new(Context, false);
|
||||||
|
|
||||||
Loop = false;
|
Loop = false;
|
||||||
|
|
||||||
Running = true;
|
Running = true;
|
||||||
@@ -49,31 +51,98 @@ int GstreamerVideoStream::LoadVideo(const wchar_t* Filename)
|
|||||||
LogVideoError ("Could not create element!");
|
LogVideoError ("Could not create element!");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_app_sink_set_drop(Appsink, true);
|
||||||
g_object_set(Element, "uri", Filename, NULL);
|
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(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_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;
|
Paused = true;
|
||||||
RefreshDuration();
|
RefreshDuration();
|
||||||
|
|
||||||
return ID;
|
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()
|
bool GstreamerVideoStream::CloseVideo()
|
||||||
{
|
{
|
||||||
if(Element)
|
|
||||||
gst_element_set_state(Element, GST_STATE_NULL);
|
|
||||||
if(Appsink)
|
if(Appsink)
|
||||||
gst_object_unref(Appsink);
|
gst_object_unref(Appsink);
|
||||||
if(Bus)
|
if(Bus)
|
||||||
gst_object_unref(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)
|
if(Element)
|
||||||
gst_object_unref(Element);
|
gst_object_unref(Element);
|
||||||
return true;
|
return true;
|
||||||
@@ -86,23 +155,9 @@ float GstreamerVideoStream::GetVideoLength()
|
|||||||
return Duration;
|
return Duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
guint8* GstreamerVideoStream::GetFrame(float Time, float &VideoTime, int &Size, int &Width, int &Height)
|
struct ApplicationFrame GstreamerVideoStream::GetFrame(float Time)
|
||||||
{
|
{
|
||||||
/*GstSample *sample;
|
return Frame;
|
||||||
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)
|
bool GstreamerVideoStream::Skip(float Start, float Gap)
|
||||||
@@ -152,6 +207,7 @@ void GstreamerVideoStream::RefreshDuration()
|
|||||||
void GstreamerVideoStream::UpdateVideo()
|
void GstreamerVideoStream::UpdateVideo()
|
||||||
{
|
{
|
||||||
if(Running) {
|
if(Running) {
|
||||||
|
g_main_context_iteration(Context, false);
|
||||||
Message = gst_bus_pop (Bus);
|
Message = gst_bus_pop (Bus);
|
||||||
|
|
||||||
/* Parse message */
|
/* Parse message */
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <mutex>
|
||||||
#include "gst/gst.h"
|
#include "gst/gst.h"
|
||||||
#include "GstreamerVideo.h"
|
#include "GstreamerVideo.h"
|
||||||
#include "gst\app\gstappsink.h"
|
#include "gst\app\gstappsink.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
class GstreamerVideoStream
|
class GstreamerVideoStream
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -18,7 +20,7 @@ public:
|
|||||||
bool CloseVideo();
|
bool CloseVideo();
|
||||||
|
|
||||||
float GetVideoLength();
|
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);
|
bool Skip(float Start, float Gap);
|
||||||
void SetVideoLoop(bool Loop);
|
void SetVideoLoop(bool Loop);
|
||||||
void PauseVideo();
|
void PauseVideo();
|
||||||
@@ -29,11 +31,22 @@ public:
|
|||||||
bool IsFinished();
|
bool IsFinished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
GMainLoop *MainLoop;
|
||||||
|
GMainContext *Context;
|
||||||
|
|
||||||
GstAppSink *Appsink;
|
GstAppSink *Appsink;
|
||||||
GstElement *Element;
|
GstElement *Element;
|
||||||
GstBus *Bus;
|
GstBus *Bus;
|
||||||
GstMessage *Message;
|
GstMessage *Message;
|
||||||
|
|
||||||
|
ApplicationFrame Frame;
|
||||||
GstMapInfo Mapinfo;
|
GstMapInfo Mapinfo;
|
||||||
|
GstSample *Sample;
|
||||||
|
GstBuffer *Buffer;
|
||||||
|
GstCaps *BufferCaps;
|
||||||
|
GstStructure *BufferStructure;
|
||||||
|
mutex Mutex;
|
||||||
|
|
||||||
gboolean Loop;
|
gboolean Loop;
|
||||||
|
|
||||||
@@ -45,6 +58,9 @@ private:
|
|||||||
gfloat Duration;
|
gfloat Duration;
|
||||||
|
|
||||||
void RefreshDuration();
|
void RefreshDuration();
|
||||||
|
|
||||||
|
GstFlowReturn NewBufferRecieved(GstAppSink *Sink);
|
||||||
|
static GstFlowReturn fake_callback(GstAppSink *sink ,gpointer data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Binary file not shown.
@@ -63,9 +63,10 @@ namespace Vocaluxe.Lib.Video
|
|||||||
|
|
||||||
public bool GetFrame(int StreamID, ref 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);
|
ManagedFrame frame = CGstreamerVideoWrapper.GetFrame(StreamID, Time);
|
||||||
byte[] data = new byte[4 * 4 * 4];
|
VideoTime = frame.Videotime;
|
||||||
UploadNewFrame(ref Frame, ref data, 4, 4);
|
|
||||||
|
UploadNewFrame(ref Frame, ref frame.buffer, frame.Width, frame.Height);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,14 +102,18 @@ namespace Vocaluxe.Lib.Video
|
|||||||
|
|
||||||
private void UploadNewFrame(ref STexture frame, ref byte[] Data, int Width, int Height)
|
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);
|
if (frame.index == -1 || Width != frame.width || Height != frame.height || Data.Length == 0)
|
||||||
frame = CDraw.AddTexture(Width, Height, ref Data);
|
{
|
||||||
}
|
CDraw.RemoveTexture(ref frame);
|
||||||
else
|
frame = CDraw.AddTexture(Width, Height, ref Data);
|
||||||
{
|
}
|
||||||
CDraw.UpdateTexture(ref frame, ref Data);
|
else
|
||||||
|
{
|
||||||
|
CDraw.UpdateTexture(ref frame, ref Data);
|
||||||
|
}
|
||||||
|
Data = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,23 @@ using System.Text;
|
|||||||
|
|
||||||
namespace Vocaluxe.Lib.Video.Gstreamer
|
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
|
public static class CGstreamerVideoWrapper
|
||||||
{
|
{
|
||||||
#region arch
|
#region arch
|
||||||
@@ -44,14 +61,28 @@ namespace Vocaluxe.Lib.Video.Gstreamer
|
|||||||
public static extern float GetVideoLength(int StreamID);
|
public static extern float GetVideoLength(int StreamID);
|
||||||
|
|
||||||
[DllImport(Dll, EntryPoint="GetFrame")]
|
[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);
|
NativeFrame f = GetFrameNative(StreamID, Time);
|
||||||
byte[] buffer = new byte[Size];
|
|
||||||
Marshal.Copy(buf, buffer, 0, Size);
|
byte[] buffer = null;
|
||||||
return buffer;
|
|
||||||
|
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)]
|
[DllImport(Dll)]
|
||||||
|
|||||||
Reference in new issue
Block a user