Commit 6d931a0c authored by Sebastian Dröge's avatar Sebastian Dröge 🍵

decklink: Add initial version of audio and video sources

parent 57d46fe9
......@@ -26,7 +26,9 @@ libgstdecklink_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
libgstdecklink_la_SOURCES = \
gstdecklink.cpp \
gstdecklinkaudiosink.cpp \
gstdecklinkvideosink.cpp
gstdecklinkvideosink.cpp \
gstdecklinkaudiosrc.cpp \
gstdecklinkvideosrc.cpp
if DECKLINK_OSX
libgstdecklink_la_SOURCES += \
......@@ -40,6 +42,8 @@ noinst_HEADERS = \
gstdecklink.h \
gstdecklinkaudiosink.h \
gstdecklinkvideosink.h \
gstdecklinkaudiosrc.h \
gstdecklinkvideosrc.h \
linux/DeckLinkAPIConfiguration.h \
linux/DeckLinkAPIDeckControl.h \
linux/DeckLinkAPIDiscovery.h \
......
......@@ -26,6 +26,8 @@
#include "gstdecklink.h"
#include "gstdecklinkaudiosink.h"
#include "gstdecklinkvideosink.h"
#include "gstdecklinkaudiosrc.h"
#include "gstdecklinkvideosrc.h"
GST_DEBUG_CATEGORY_STATIC (gst_decklink_debug);
#define GST_CAT_DEFAULT gst_decklink_debug
......@@ -241,6 +243,91 @@ struct _Device
GstDecklinkInput input;
};
class GStreamerDecklinkInputCallback:public IDeckLinkInputCallback
{
private:
GstDecklinkInput * m_input;
GMutex m_mutex;
gint m_refcount;
public:
GStreamerDecklinkInputCallback (GstDecklinkInput * input)
: IDeckLinkInputCallback ()
{
m_input = input;
g_mutex_init (&m_mutex);
}
virtual ~ GStreamerDecklinkInputCallback ()
{
g_mutex_clear (&m_mutex);
}
virtual HRESULT STDMETHODCALLTYPE QueryInterface (REFIID, LPVOID *)
{
return E_NOINTERFACE;
}
virtual ULONG STDMETHODCALLTYPE AddRef (void)
{
ULONG ret;
g_mutex_lock (&m_mutex);
m_refcount++;
ret = m_refcount;
g_mutex_unlock (&m_mutex);
return ret;
}
virtual ULONG STDMETHODCALLTYPE Release (void)
{
ULONG ret;
g_mutex_lock (&m_mutex);
m_refcount--;
ret = m_refcount;
g_mutex_unlock (&m_mutex);
if (ret == 0) {
delete this;
}
return ret;
}
virtual HRESULT STDMETHODCALLTYPE
VideoInputFormatChanged (BMDVideoInputFormatChangedEvents,
IDeckLinkDisplayMode *, BMDDetectedVideoInputFormatFlags)
{
GST_FIXME ("Video input format change not supported yet");
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE
VideoInputFrameArrived (IDeckLinkVideoInputFrame * video_frame,
IDeckLinkAudioInputPacket * audio_packet)
{
GstClockTime clock_time = gst_clock_get_time (m_input->clock);
g_mutex_lock (&m_input->lock);
if (m_input->got_video_frame) {
GstClockTime capture_time = clock_time -
gst_element_get_base_time (m_input->videosrc);
m_input->got_video_frame (m_input->videosrc, video_frame, capture_time);
}
if (m_input->got_audio_packet) {
GstClockTime capture_time = clock_time -
gst_element_get_base_time (m_input->audiosrc);
m_input->got_audio_packet (m_input->audiosrc, audio_packet, capture_time);
}
g_mutex_unlock (&m_input->lock);
return S_OK;
}
};
static GOnce devices_once = G_ONCE_INIT;
static int n_devices;
static Device devices[10];
......@@ -273,6 +360,9 @@ init_devices (gpointer data)
"GstDecklinkInputClock", NULL));
GST_DECKLINK_CLOCK_CAST (devices[i].input.clock)->input =
devices[i].input.input;
devices[i].input.
input->SetCallback (new GStreamerDecklinkInputCallback (&devices[i].
input));
}
ret = decklink->QueryInterface (IID_IDeckLinkOutput,
......@@ -393,6 +483,62 @@ gst_decklink_output_get_audio_clock (GstDecklinkOutput * output)
return ret;
}
GstDecklinkInput *
gst_decklink_acquire_nth_input (gint n, GstElement * src, gboolean is_audio)
{
GstDecklinkInput *input;
g_once (&devices_once, init_devices, NULL);
if (n >= n_devices)
return NULL;
input = &devices[n].input;
if (!input->input) {
GST_ERROR ("Device %d has no input", n);
return NULL;
}
g_mutex_lock (&input->lock);
if (is_audio && !input->audiosrc) {
input->audiosrc = GST_ELEMENT_CAST (gst_object_ref (src));
g_mutex_unlock (&input->lock);
return input;
} else if (!input->videosrc) {
input->videosrc = GST_ELEMENT_CAST (gst_object_ref (src));
g_mutex_unlock (&input->lock);
return input;
}
g_mutex_unlock (&input->lock);
GST_ERROR ("Input device %d (audio: %d) in use already", n, is_audio);
return NULL;
}
void
gst_decklink_release_nth_input (gint n, GstElement * src, gboolean is_audio)
{
GstDecklinkInput *input;
if (n >= n_devices)
return;
input = &devices[n].input;
g_assert (input->input);
g_mutex_lock (&input->lock);
if (is_audio) {
g_assert (input->audiosrc == src);
gst_object_unref (src);
input->audiosrc = NULL;
} else {
g_assert (input->videosrc == src);
gst_object_unref (src);
input->videosrc = NULL;
}
g_mutex_unlock (&input->lock);
}
G_DEFINE_TYPE (GstDecklinkClock, gst_decklink_clock, GST_TYPE_SYSTEM_CLOCK);
static void gst_decklink_clock_class_init (GstDecklinkClockClass * klass);
......@@ -466,6 +612,10 @@ plugin_init (GstPlugin * plugin)
GST_TYPE_DECKLINK_AUDIO_SINK);
gst_element_register (plugin, "decklinkvideosink", GST_RANK_NONE,
GST_TYPE_DECKLINK_VIDEO_SINK);
gst_element_register (plugin, "decklinkaudiosrc", GST_RANK_NONE,
GST_TYPE_DECKLINK_AUDIO_SRC);
gst_element_register (plugin, "decklinkvideosrc", GST_RANK_NONE,
GST_TYPE_DECKLINK_VIDEO_SRC);
return TRUE;
}
......
......@@ -139,8 +139,11 @@ struct _GstDecklinkInput {
/* Everything below protected by mutex */
GMutex lock;
/* Set by the video source */
void (*got_video_frame) (GstElement *videosrc, IDeckLinkVideoInputFrame * frame, GstClockTime capture_time);
/* Set by the audio source */
GstClock *audio_clock;
void (*got_audio_packet) (GstElement *videosrc, IDeckLinkAudioInputPacket * packet, GstClockTime capture_time);
/* <private> */
GstElement *audiosrc;
......@@ -153,4 +156,7 @@ void gst_decklink_release_nth_output (gint n, GstElement * sink,
void gst_decklink_output_set_audio_clock (GstDecklinkOutput * output, GstClock * clock);
GstClock * gst_decklink_output_get_audio_clock (GstDecklinkOutput * output);
GstDecklinkInput * gst_decklink_acquire_nth_input (gint n, GstElement * src, gboolean is_audio);
void gst_decklink_release_nth_input (gint n, GstElement * src, gboolean is_audio);
#endif
......@@ -285,7 +285,6 @@ in_same_pipeline (GstElement * a, GstElement * b)
gst_object_unref (root);
return ret;
}
static gboolean
......@@ -438,7 +437,6 @@ gst_decklink_audio_sink_ringbuffer_close_device (GstAudioRingBuffer * rb)
enum
{
PROP_0,
PROP_MODE,
PROP_DEVICE_NUMBER
};
......
This diff is collapsed.
/* GStreamer
*
* Copyright (C) 2011 David Schleef <ds@schleef.org>
* Copyright (C) 2014 Sebastian Dröge <sebastian@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_DECKLINK_AUDIO_SRC_H__
#define __GST_DECKLINK_AUDIO_SRC_H__
#include <gst/gst.h>
#include <gst/base/base.h>
#include <gst/audio/audio.h>
#include "gstdecklink.h"
G_BEGIN_DECLS
#define GST_TYPE_DECKLINK_AUDIO_SRC \
(gst_decklink_audio_src_get_type())
#define GST_DECKLINK_AUDIO_SRC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_DECKLINK_AUDIO_SRC, GstDecklinkAudioSrc))
#define GST_DECKLINK_AUDIO_SRC_CAST(obj) \
((GstDecklinkAudioSrc*)obj)
#define GST_DECKLINK_AUDIO_SRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_DECKLINK_AUDIO_SRC, GstDecklinkAudioSrcClass))
#define GST_IS_DECKLINK_AUDIO_SRC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_DECKLINK_AUDIO_SRC))
#define GST_IS_DECKLINK_AUDIO_SRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_DECKLINK_AUDIO_SRC))
typedef struct _GstDecklinkAudioSrc GstDecklinkAudioSrc;
typedef struct _GstDecklinkAudioSrcClass GstDecklinkAudioSrcClass;
struct _GstDecklinkAudioSrc
{
GstPushSrc parent;
GstDecklinkModeEnum mode;
gint device_number;
GstAudioInfo info;
GstDecklinkInput *input;
GCond cond;
GMutex lock;
gboolean flushing;
IDeckLinkAudioInputPacket *current_packet;
GstClockTime current_packet_capture_time;
};
struct _GstDecklinkAudioSrcClass
{
GstPushSrcClass parent_class;
};
GType gst_decklink_audio_src_get_type (void);
G_END_DECLS
#endif /* __GST_DECKLINK_AUDIO_SRC_H__ */
This diff is collapsed.
/* GStreamer
*
* Copyright (C) 2011 David Schleef <ds@schleef.org>
* Copyright (C) 2014 Sebastian Dröge <sebastian@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_DECKLINK_VIDEO_SRC_H__
#define __GST_DECKLINK_VIDEO_SRC_H__
#include <gst/gst.h>
#include <gst/base/base.h>
#include <gst/video/video.h>
#include "gstdecklink.h"
G_BEGIN_DECLS
#define GST_TYPE_DECKLINK_VIDEO_SRC \
(gst_decklink_video_src_get_type())
#define GST_DECKLINK_VIDEO_SRC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_DECKLINK_VIDEO_SRC, GstDecklinkVideoSrc))
#define GST_DECKLINK_VIDEO_SRC_CAST(obj) \
((GstDecklinkVideoSrc*)obj)
#define GST_DECKLINK_VIDEO_SRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_DECKLINK_VIDEO_SRC, GstDecklinkVideoSrcClass))
#define GST_IS_DECKLINK_VIDEO_SRC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_DECKLINK_VIDEO_SRC))
#define GST_IS_DECKLINK_VIDEO_SRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_DECKLINK_VIDEO_SRC))
typedef struct _GstDecklinkVideoSrc GstDecklinkVideoSrc;
typedef struct _GstDecklinkVideoSrcClass GstDecklinkVideoSrcClass;
struct _GstDecklinkVideoSrc
{
GstPushSrc parent;
GstDecklinkModeEnum mode;
gint device_number;
GstVideoInfo info;
GstDecklinkInput *input;
GCond cond;
GMutex lock;
gboolean flushing;
IDeckLinkVideoInputFrame *current_frame;
GstClockTime current_frame_capture_time;
};
struct _GstDecklinkVideoSrcClass
{
GstPushSrcClass parent_class;
};
GType gst_decklink_video_src_get_type (void);
G_END_DECLS
#endif /* __GST_DECKLINK_VIDEO_SRC_H__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment