Some cleanup in Gstreamer Audio, should be finished 100% now! Please test
Frames are now pulled in a thread for better performance. We still need to grab the right frame from the Framebuffer and we might need to switch Gstreamer's Frame stepping API. refs #1
This commit is contained in:
1 parent
ea4a8abd87
commit
b60169d2a6
9 files changed
+134
-100
No files matched your search
@@ -1,11 +1,5 @@
|
|||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "GstreamerAudio.h"
|
#include "GstreamerAudio.h"
|
||||||
#include "GstreamerAudioStream.h"
|
|
||||||
#include "gst\gst.h"
|
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
|
||||||
#include <map>
|
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
#define DllExport extern "C" __declspec(dllexport)
|
#define DllExport extern "C" __declspec(dllexport)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <queue>
|
||||||
#include "gst/gst.h"
|
#include "gst/gst.h"
|
||||||
|
#include "GstreamerAudioStream.h"
|
||||||
|
#include "gst\gst.h"
|
||||||
|
|
||||||
#define DllExport extern "C" __declspec(dllexport)
|
#define DllExport extern "C" __declspec(dllexport)
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "GstreamerAudioStream.h"
|
#include "GstreamerAudioStream.h"
|
||||||
#include "GstreamerAudio.h"
|
|
||||||
#include "gst/gst.h"
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GST_PLAY_FLAG_VIDEO = (1 << 0),
|
GST_PLAY_FLAG_VIDEO = (1 << 0),
|
||||||
@@ -28,8 +26,6 @@ GstreamerAudioStream::GstreamerAudioStream(int id)
|
|||||||
Running = true;
|
Running = true;
|
||||||
|
|
||||||
Finished = false;
|
Finished = false;
|
||||||
Playing = false;
|
|
||||||
Paused = false;
|
|
||||||
|
|
||||||
//Fading
|
//Fading
|
||||||
FadeTimer = g_timer_new();
|
FadeTimer = g_timer_new();
|
||||||
@@ -76,7 +72,6 @@ int GstreamerAudioStream::Load(const wchar_t* Media)
|
|||||||
|
|
||||||
gst_element_set_state(Element, GST_STATE_PAUSED);
|
gst_element_set_state(Element, GST_STATE_PAUSED);
|
||||||
gst_bus_timed_pop_filtered(Bus, -1, GST_MESSAGE_ASYNC_DONE);
|
gst_bus_timed_pop_filtered(Bus, -1, GST_MESSAGE_ASYNC_DONE);
|
||||||
Paused = true;
|
|
||||||
RefreshDuration();
|
RefreshDuration();
|
||||||
|
|
||||||
return ID;
|
return ID;
|
||||||
@@ -132,16 +127,12 @@ void GstreamerAudioStream::Play(void)
|
|||||||
|
|
||||||
void GstreamerAudioStream::Play(bool Loop)
|
void GstreamerAudioStream::Play(bool Loop)
|
||||||
{
|
{
|
||||||
Playing = true;
|
|
||||||
Paused = false;
|
|
||||||
this->Loop = Loop;
|
this->Loop = Loop;
|
||||||
Play();
|
Play();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GstreamerAudioStream::Pause()
|
void GstreamerAudioStream::Pause()
|
||||||
{
|
{
|
||||||
Playing = false;
|
|
||||||
Paused = true;
|
|
||||||
Running = true;
|
Running = true;
|
||||||
if(Element)
|
if(Element)
|
||||||
gst_element_set_state(Element, GST_STATE_PAUSED);
|
gst_element_set_state(Element, GST_STATE_PAUSED);
|
||||||
@@ -154,8 +145,6 @@ void GstreamerAudioStream::Stop()
|
|||||||
{
|
{
|
||||||
gst_element_set_state(Element, GST_STATE_NULL);
|
gst_element_set_state(Element, GST_STATE_NULL);
|
||||||
gst_element_seek_simple(Element, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, 0);
|
gst_element_seek_simple(Element, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, 0);
|
||||||
Running = true;
|
|
||||||
Playing = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
#pragma warning(disable: 4244) // possible loss of data
|
#pragma warning(disable: 4244) // possible loss of data
|
||||||
#pragma warning(disable: 4267) // possible loss of data
|
#pragma warning(disable: 4267) // possible loss of data
|
||||||
#pragma warning(disable: 4800)
|
#pragma warning(disable: 4800)
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "gst/gst.h"
|
#include "gst/gst.h"
|
||||||
|
#include "GstreamerAudio.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@@ -49,8 +51,6 @@ private:
|
|||||||
gboolean Running;
|
gboolean Running;
|
||||||
gboolean Loop;
|
gboolean Loop;
|
||||||
|
|
||||||
gboolean Playing;
|
|
||||||
gboolean Paused;
|
|
||||||
gboolean Finished;
|
gboolean Finished;
|
||||||
|
|
||||||
gdouble MaxVolume;
|
gdouble MaxVolume;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ DllExport bool InitVideo()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
gst_init(NULL, NULL);
|
gst_init(NULL, NULL);
|
||||||
|
|
||||||
GstRegistry* registry = gst_registry_get();
|
GstRegistry* registry = gst_registry_get();
|
||||||
|
|
||||||
#if _WIN64
|
#if _WIN64
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ using namespace std;
|
|||||||
static LogCallback Log;
|
static LogCallback Log;
|
||||||
|
|
||||||
struct ApplicationFrame {
|
struct ApplicationFrame {
|
||||||
guint8* buffer;
|
guint8* data;
|
||||||
int size;
|
int size;
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
|
|||||||
@@ -19,9 +19,6 @@ GstreamerVideoStream::GstreamerVideoStream(int ID)
|
|||||||
{
|
{
|
||||||
this->ID = ID;
|
this->ID = ID;
|
||||||
|
|
||||||
g_main_loop_new(Context, false);
|
|
||||||
Clock = vocaluxe_clock_new("external");
|
|
||||||
|
|
||||||
Loop = false;
|
Loop = false;
|
||||||
|
|
||||||
Running = true;
|
Running = true;
|
||||||
@@ -29,6 +26,15 @@ GstreamerVideoStream::GstreamerVideoStream(int ID)
|
|||||||
Paused = false;
|
Paused = false;
|
||||||
Finished = false;
|
Finished = false;
|
||||||
Closed = false;
|
Closed = false;
|
||||||
|
Copying = true;
|
||||||
|
|
||||||
|
BufferFull = false;
|
||||||
|
for(int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
FrameBuffer[i].Sample = NULL;
|
||||||
|
FrameBuffer[i].Buffer = NULL;
|
||||||
|
FrameBuffer[i].Displayed = true;
|
||||||
|
}
|
||||||
|
|
||||||
Duration = -1.0;
|
Duration = -1.0;
|
||||||
}
|
}
|
||||||
@@ -42,12 +48,10 @@ GstreamerVideoStream::~GstreamerVideoStream(void)
|
|||||||
int GstreamerVideoStream::LoadVideo(const wchar_t* Filename)
|
int GstreamerVideoStream::LoadVideo(const wchar_t* Filename)
|
||||||
{
|
{
|
||||||
Element = gst_element_factory_make("playbin", "playbin");
|
Element = gst_element_factory_make("playbin", "playbin");
|
||||||
|
|
||||||
|
|
||||||
Appsink = (GstAppSink*) gst_element_factory_make("appsink", "appsink");
|
Appsink = (GstAppSink*) gst_element_factory_make("appsink", "appsink");
|
||||||
|
|
||||||
Bus = gst_element_get_bus(Element);
|
Bus = gst_element_get_bus(Element);
|
||||||
if(!Element)
|
if(!Element || !Appsink)
|
||||||
{
|
{
|
||||||
LogVideoError ("Could not create element!");
|
LogVideoError ("Could not create element!");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -56,8 +60,7 @@ int GstreamerVideoStream::LoadVideo(const wchar_t* Filename)
|
|||||||
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_object_set (Appsink, "emit-signals", FALSE, "sync", FALSE, NULL);
|
||||||
g_signal_connect(Appsink,"new-sample", G_CALLBACK(fake_callback),(gpointer)this);
|
|
||||||
|
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
caps = gst_caps_new_simple ("video/x-raw",
|
caps = gst_caps_new_simple ("video/x-raw",
|
||||||
@@ -67,70 +70,74 @@ int GstreamerVideoStream::LoadVideo(const wchar_t* Filename)
|
|||||||
gst_app_sink_set_caps(Appsink, caps);
|
gst_app_sink_set_caps(Appsink, caps);
|
||||||
|
|
||||||
gst_app_sink_set_drop(Appsink, false);
|
gst_app_sink_set_drop(Appsink, false);
|
||||||
gst_app_sink_set_max_buffers(Appsink, 1);
|
gst_app_sink_set_max_buffers(Appsink, 5);
|
||||||
|
|
||||||
gst_pipeline_use_clock((GstPipeline *)Element, (GstClock*) Clock);
|
|
||||||
gst_element_set_state(Element, GST_STATE_PLAYING);
|
gst_element_set_state(Element, GST_STATE_PLAYING);
|
||||||
gst_element_set_state((GstElement*)Appsink, GST_STATE_PLAYING);
|
//gst_element_set_state(GST_ELEMENT (Appsink), GST_STATE_PLAYING);
|
||||||
gst_bus_timed_pop_filtered(Bus, -1, GST_MESSAGE_ASYNC_DONE);
|
gst_bus_timed_pop_filtered(Bus, -1, GST_MESSAGE_ASYNC_DONE);
|
||||||
|
CopyThread = thread (&GstreamerVideoStream::Copy, this);
|
||||||
|
|
||||||
Paused = true;
|
|
||||||
RefreshDuration();
|
RefreshDuration();
|
||||||
|
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
GstFlowReturn GstreamerVideoStream::fake_callback(GstAppSink *sink,gpointer data) {
|
void GstreamerVideoStream::Copy()
|
||||||
|
|
||||||
GstreamerVideoStream* instance = (GstreamerVideoStream*)data;
|
|
||||||
return instance->NewBufferRecieved(sink);
|
|
||||||
}
|
|
||||||
|
|
||||||
GstFlowReturn GstreamerVideoStream::NewBufferRecieved(GstAppSink *sink)
|
|
||||||
{
|
{
|
||||||
float VideoTime = 0.0;
|
while(Copying)
|
||||||
int Width = 0;
|
{
|
||||||
int Height = 0;
|
int num = -1;
|
||||||
int Size = -1;
|
for (int i = 0; i < 5; i++)
|
||||||
|
|
||||||
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);
|
if(FrameBuffer[i].Displayed)
|
||||||
gst_buffer_unref(Buffer);
|
{
|
||||||
|
|
||||||
|
num = i;
|
||||||
|
GstSample *sample;
|
||||||
|
sample = gst_app_sink_pull_sample(Appsink);
|
||||||
|
Mutex.lock();
|
||||||
|
if(FrameBuffer[i].Buffer)
|
||||||
|
{
|
||||||
|
if(FrameBuffer[i].Memory.data)
|
||||||
|
gst_buffer_unmap(FrameBuffer[i].Buffer, &FrameBuffer[i].Memory);
|
||||||
|
gst_buffer_unref(FrameBuffer[i].Buffer);
|
||||||
|
}
|
||||||
|
//if(FrameBuffer[i].Sample)
|
||||||
|
//gst_sample_unref(FrameBuffer[i].Sample);
|
||||||
|
|
||||||
|
|
||||||
|
FrameBuffer[i].Displayed = false;
|
||||||
|
FrameBuffer[i].Sample = sample;
|
||||||
|
Mutex.unlock();
|
||||||
|
|
||||||
|
//gst_element_send_event (Element, gst_event_new_step (GST_FORMAT_BUFFERS, 1, 1.0, TRUE, FALSE));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(BufferCaps)
|
if(num == -1)
|
||||||
gst_caps_unref(BufferCaps);
|
BufferFull = true;
|
||||||
|
|
||||||
if(BufferStructure)
|
|
||||||
gst_object_unref(BufferStructure);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Mutex.lock();
|
|
||||||
Frame.buffer = Mapinfo.data;
|
|
||||||
Frame.height = Height;
|
|
||||||
Frame.width = Width;
|
|
||||||
Frame.size = Size;
|
|
||||||
Frame.videotime = VideoTime;
|
|
||||||
Mutex.unlock();
|
|
||||||
|
|
||||||
return GST_FLOW_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GstreamerVideoStream::CloseVideo()
|
bool GstreamerVideoStream::CloseVideo()
|
||||||
{
|
{
|
||||||
|
Copying = false;
|
||||||
|
CopyThread.join();
|
||||||
|
|
||||||
|
for(int i= 0; i< 5; i++)
|
||||||
|
{
|
||||||
|
if(FrameBuffer[i].Buffer)
|
||||||
|
{
|
||||||
|
if(FrameBuffer[i].Memory.data)
|
||||||
|
gst_buffer_unmap(FrameBuffer[i].Buffer, &FrameBuffer[i].Memory);
|
||||||
|
gst_buffer_unref(FrameBuffer[i].Buffer);
|
||||||
|
}
|
||||||
|
//if(FrameBuffer[i].Sample)
|
||||||
|
//gst_sample_unref(FrameBuffer[i].Sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Element)
|
||||||
|
gst_element_set_state(Element, GST_STATE_NULL);
|
||||||
|
|
||||||
if(Appsink)
|
if(Appsink)
|
||||||
gst_object_unref(Appsink);
|
gst_object_unref(Appsink);
|
||||||
@@ -138,16 +145,8 @@ bool GstreamerVideoStream::CloseVideo()
|
|||||||
gst_object_unref(Bus);
|
gst_object_unref(Bus);
|
||||||
//if(Buffer && &Mapinfo)
|
//if(Buffer && &Mapinfo)
|
||||||
//gst_buffer_unmap(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;
|
||||||
@@ -162,8 +161,51 @@ float GstreamerVideoStream::GetVideoLength()
|
|||||||
|
|
||||||
struct ApplicationFrame GstreamerVideoStream::GetFrame(float Time)
|
struct ApplicationFrame GstreamerVideoStream::GetFrame(float Time)
|
||||||
{
|
{
|
||||||
vocaluxe_clock_set_time(Clock, Time);
|
float VideoTime = 0.0;
|
||||||
return Frame;
|
int Width = 0;
|
||||||
|
int Height = 0;
|
||||||
|
int Size = -1;
|
||||||
|
|
||||||
|
Mutex.lock();
|
||||||
|
for(int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
if(!FrameBuffer[i].Displayed)
|
||||||
|
{
|
||||||
|
if(FrameBuffer[i].Sample) {
|
||||||
|
GstBuffer *Buffer = gst_sample_get_buffer(FrameBuffer[i].Sample);
|
||||||
|
GstMapInfo Mapinfo;
|
||||||
|
|
||||||
|
GstCaps *BufferCaps = gst_sample_get_caps (FrameBuffer[i].Sample);
|
||||||
|
GstStructure *BufferStructure = gst_caps_get_structure (BufferCaps, 0);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
ReturnFrame.data = Mapinfo.data;
|
||||||
|
ReturnFrame.height = Height;
|
||||||
|
ReturnFrame.width = Width;
|
||||||
|
ReturnFrame.size = Size;
|
||||||
|
ReturnFrame.videotime = VideoTime;
|
||||||
|
|
||||||
|
FrameBuffer[i].Memory = Mapinfo;
|
||||||
|
FrameBuffer[i].Buffer = Buffer;
|
||||||
|
|
||||||
|
if(BufferCaps)
|
||||||
|
gst_caps_unref(BufferCaps);
|
||||||
|
|
||||||
|
if(BufferStructure)
|
||||||
|
gst_object_unref(BufferStructure);
|
||||||
|
}
|
||||||
|
FrameBuffer[i].Displayed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Mutex.unlock();
|
||||||
|
return ReturnFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GstreamerVideoStream::Skip(float Start, float Gap)
|
bool GstreamerVideoStream::Skip(float Start, float Gap)
|
||||||
@@ -179,9 +221,9 @@ bool GstreamerVideoStream::Skip(float Start, float Gap)
|
|||||||
void GstreamerVideoStream::SetVideoLoop(bool Loop)
|
void GstreamerVideoStream::SetVideoLoop(bool Loop)
|
||||||
{
|
{
|
||||||
if(Loop)
|
if(Loop)
|
||||||
gst_pipeline_auto_clock((GstPipeline *)Element);
|
g_object_set(Element, "sync", TRUE, NULL);
|
||||||
else
|
else
|
||||||
gst_pipeline_use_clock((GstPipeline *)Element, (GstClock*) Clock);
|
g_object_set(Element, "sync", FALSE, NULL);
|
||||||
this->Loop = Loop;
|
this->Loop = Loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,7 +259,6 @@ 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,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
#include "gst/gst.h"
|
#include "gst/gst.h"
|
||||||
#include "GstreamerVideo.h"
|
#include "GstreamerVideo.h"
|
||||||
#include "gst\app\gstappsink.h"
|
#include "gst\app\gstappsink.h"
|
||||||
@@ -32,36 +33,39 @@ public:
|
|||||||
bool IsFinished();
|
bool IsFinished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GMainLoop *MainLoop;
|
struct BufferFrame {
|
||||||
GMainContext *Context;
|
GstSample *Sample;
|
||||||
VocaluxeClock *Clock;
|
GstBuffer *Buffer;
|
||||||
|
GstMapInfo Memory;
|
||||||
|
gboolean Displayed;
|
||||||
|
};
|
||||||
|
|
||||||
|
thread CopyThread;
|
||||||
|
|
||||||
GstAppSink *Appsink;
|
GstAppSink *Appsink;
|
||||||
GstElement *Element;
|
GstElement *Element;
|
||||||
GstBus *Bus;
|
GstBus *Bus;
|
||||||
GstMessage *Message;
|
GstMessage *Message;
|
||||||
|
|
||||||
ApplicationFrame Frame;
|
BufferFrame FrameBuffer[5];
|
||||||
GstMapInfo Mapinfo;
|
gboolean BufferFull;
|
||||||
GstSample *Sample;
|
|
||||||
GstBuffer *Buffer;
|
|
||||||
GstCaps *BufferCaps;
|
|
||||||
GstStructure *BufferStructure;
|
|
||||||
mutex Mutex;
|
mutex Mutex;
|
||||||
|
|
||||||
gboolean Loop;
|
gboolean Loop;
|
||||||
|
|
||||||
gboolean Running;
|
gboolean Running;
|
||||||
|
volatile gboolean Copying;
|
||||||
|
|
||||||
gboolean Paused;
|
gboolean Paused;
|
||||||
gboolean Finished;
|
gboolean Finished;
|
||||||
|
|
||||||
gfloat Duration;
|
gfloat Duration;
|
||||||
|
|
||||||
|
ApplicationFrame ReturnFrame;
|
||||||
|
|
||||||
void RefreshDuration();
|
void RefreshDuration();
|
||||||
|
|
||||||
GstFlowReturn NewBufferRecieved(GstAppSink *Sink);
|
void Copy();
|
||||||
static GstFlowReturn fake_callback(GstAppSink *sink ,gpointer data);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Binary file not shown.
Reference in new issue
Block a user