mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-27 18:50:48 +00:00
decklink: change device instance lifecycle
The decklink driver eventually crashes after repeated creation/deletion of device, input, output, and configuration objects. Change to create these at the outset and keep them around forever.
This commit is contained in:
parent
dd66252f23
commit
65a1f79bcb
6 changed files with 147 additions and 101 deletions
|
@ -84,59 +84,80 @@ HRESULT
|
|||
videoFrame, IDeckLinkAudioInputPacket * audioFrame)
|
||||
{
|
||||
GstDecklinkSrc *decklinksrc;
|
||||
const char *timecodeString = NULL;
|
||||
|
||||
g_return_val_if_fail (priv != NULL, S_OK);
|
||||
g_return_val_if_fail (GST_IS_DECKLINK_SRC (priv), S_OK);
|
||||
|
||||
decklinksrc = GST_DECKLINK_SRC (priv);
|
||||
|
||||
// Handle Video Frame
|
||||
if (videoFrame) {
|
||||
if (videoFrame->GetFlags () & bmdFrameHasNoInputSource) {
|
||||
GST_DEBUG ("Frame received - No input signal detected");
|
||||
} else {
|
||||
const char *timecodeString = NULL;
|
||||
if (g_timecodeFormat != 0) {
|
||||
IDeckLinkTimecode *timecode;
|
||||
if (videoFrame->GetTimecode (g_timecodeFormat, &timecode) == S_OK) {
|
||||
timecode->GetString (&timecodeString);
|
||||
CONVERT_COM_STRING (timecodeString);
|
||||
}
|
||||
}
|
||||
if (videoFrame == NULL) {
|
||||
GST_WARNING_OBJECT (decklinksrc, "video frame is NULL");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
GST_DEBUG ("Frame received [%s] - %s - Size: %li bytes",
|
||||
timecodeString != NULL ? timecodeString : "No timecode",
|
||||
"Valid Frame", videoFrame->GetRowBytes () * videoFrame->GetHeight ());
|
||||
if (audioFrame == NULL) {
|
||||
GST_WARNING_OBJECT (decklinksrc, "audio frame is NULL");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (timecodeString)
|
||||
FREE_COM_STRING (timecodeString);
|
||||
if (videoFrame->GetFlags () & bmdFrameHasNoInputSource) {
|
||||
GST_DEBUG_OBJECT (decklinksrc, "Frame received - No input signal detected");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
g_mutex_lock (decklinksrc->mutex);
|
||||
if (decklinksrc->video_frame != NULL) {
|
||||
decklinksrc->dropped_frames++;
|
||||
} else {
|
||||
videoFrame->AddRef ();
|
||||
decklinksrc->video_frame = videoFrame;
|
||||
if (audioFrame) {
|
||||
audioFrame->AddRef ();
|
||||
decklinksrc->audio_frame = audioFrame;
|
||||
}
|
||||
}
|
||||
|
||||
/* increment regardless whether frame was dropped or not */
|
||||
decklinksrc->frame_num++;
|
||||
|
||||
g_cond_signal (decklinksrc->cond);
|
||||
g_mutex_unlock (decklinksrc->mutex);
|
||||
if (g_timecodeFormat != 0) {
|
||||
IDeckLinkTimecode *timecode;
|
||||
if (videoFrame->GetTimecode (g_timecodeFormat, &timecode) == S_OK) {
|
||||
timecode->GetString (&timecodeString);
|
||||
CONVERT_COM_STRING (timecodeString);
|
||||
}
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (decklinksrc, "Frame received [%s] - %s - Size: %li bytes",
|
||||
timecodeString != NULL ? timecodeString : "No timecode",
|
||||
"Valid Frame", videoFrame->GetRowBytes () * videoFrame->GetHeight ());
|
||||
|
||||
if (timecodeString)
|
||||
FREE_COM_STRING (timecodeString);
|
||||
|
||||
g_mutex_lock (decklinksrc->mutex);
|
||||
if (decklinksrc->video_frame != NULL) {
|
||||
decklinksrc->dropped_frames++;
|
||||
decklinksrc->video_frame->Release();
|
||||
if (decklinksrc->audio_frame) {
|
||||
decklinksrc->audio_frame->Release();
|
||||
}
|
||||
}
|
||||
videoFrame->AddRef ();
|
||||
decklinksrc->video_frame = videoFrame;
|
||||
if (audioFrame) {
|
||||
audioFrame->AddRef ();
|
||||
decklinksrc->audio_frame = audioFrame;
|
||||
}
|
||||
|
||||
/* increment regardless whether frame was dropped or not */
|
||||
decklinksrc->frame_num++;
|
||||
|
||||
g_cond_signal (decklinksrc->cond);
|
||||
g_mutex_unlock (decklinksrc->mutex);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
DeckLinkCaptureDelegate::VideoInputFormatChanged
|
||||
(BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode * mode,
|
||||
BMDDetectedVideoInputFormatFlags) {
|
||||
GST_ERROR ("moo");
|
||||
DeckLinkCaptureDelegate::VideoInputFormatChanged (
|
||||
BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode * mode,
|
||||
BMDDetectedVideoInputFormatFlags)
|
||||
{
|
||||
GstDecklinkSrc *decklinksrc;
|
||||
|
||||
g_return_val_if_fail (priv != NULL, S_OK);
|
||||
g_return_val_if_fail (GST_IS_DECKLINK_SRC (priv), S_OK);
|
||||
|
||||
decklinksrc = GST_DECKLINK_SRC (priv);
|
||||
|
||||
GST_ERROR_OBJECT (decklinksrc, "unimplemented: video input format changed");
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
@ -190,34 +190,96 @@ gst_decklink_mode_get_template_caps (void)
|
|||
return caps;
|
||||
}
|
||||
|
||||
IDeckLink *
|
||||
gst_decklink_get_nth_device (int n)
|
||||
typedef struct _Device Device;
|
||||
struct _Device {
|
||||
IDeckLink *decklink;
|
||||
IDeckLinkInput *input;
|
||||
IDeckLinkOutput *output;
|
||||
IDeckLinkConfiguration *config;
|
||||
};
|
||||
|
||||
static int n_devices;
|
||||
static Device devices[10];
|
||||
|
||||
static void
|
||||
init_devices (void)
|
||||
{
|
||||
IDeckLinkIterator *iterator;
|
||||
IDeckLink *decklink = NULL;
|
||||
HRESULT ret;
|
||||
int i;
|
||||
static gboolean inited = FALSE;
|
||||
|
||||
if (inited) return;
|
||||
inited = TRUE;
|
||||
|
||||
iterator = CreateDeckLinkIteratorInstance ();
|
||||
if (iterator == NULL) {
|
||||
GST_ERROR ("no driver");
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
ret = iterator->Next (&decklink);
|
||||
if (ret != S_OK) {
|
||||
GST_ERROR ("no card");
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
ret = iterator->Next (&decklink);
|
||||
while (ret == S_OK) {
|
||||
devices[i].decklink = decklink;
|
||||
|
||||
ret = decklink->QueryInterface (IID_IDeckLinkInput,
|
||||
(void **) &devices[i].input);
|
||||
if (ret != S_OK) {
|
||||
GST_ERROR ("no card");
|
||||
return NULL;
|
||||
GST_WARNING ("selected device does not have input interface");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = decklink->QueryInterface (IID_IDeckLinkOutput,
|
||||
(void **) &devices[i].output);
|
||||
if (ret != S_OK) {
|
||||
GST_WARNING ("selected device does not have output interface");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = decklink->QueryInterface (IID_IDeckLinkConfiguration,
|
||||
(void **) &devices[i].config);
|
||||
if (ret != S_OK) {
|
||||
GST_WARNING ("selected device does not have config interface");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = iterator->Next (&decklink);
|
||||
i++;
|
||||
}
|
||||
|
||||
return decklink;
|
||||
n_devices = i;
|
||||
|
||||
iterator->Release();
|
||||
}
|
||||
|
||||
IDeckLink *
|
||||
gst_decklink_get_nth_device (int n)
|
||||
{
|
||||
init_devices ();
|
||||
return devices[n].decklink;
|
||||
}
|
||||
|
||||
IDeckLinkInput *
|
||||
gst_decklink_get_nth_input (int n)
|
||||
{
|
||||
init_devices ();
|
||||
return devices[n].input;
|
||||
}
|
||||
|
||||
IDeckLinkOutput *
|
||||
gst_decklink_get_nth_output (int n)
|
||||
{
|
||||
init_devices ();
|
||||
return devices[n].output;
|
||||
}
|
||||
|
||||
IDeckLinkConfiguration *
|
||||
gst_decklink_get_nth_config (int n)
|
||||
{
|
||||
init_devices ();
|
||||
return devices[n].config;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
|
@ -108,6 +108,8 @@ GstCaps * gst_decklink_mode_get_caps (GstDecklinkModeEnum e);
|
|||
GstCaps * gst_decklink_mode_get_template_caps (void);
|
||||
|
||||
IDeckLink * gst_decklink_get_nth_device (int n);
|
||||
|
||||
IDeckLinkInput * gst_decklink_get_nth_input (int n);
|
||||
IDeckLinkOutput * gst_decklink_get_nth_output (int n);
|
||||
IDeckLinkConfiguration * gst_decklink_get_nth_config (int n);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -469,12 +469,7 @@ gst_decklink_sink_start (GstDecklinkSink * decklinksink)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
ret = decklinksink->decklink->QueryInterface (IID_IDeckLinkOutput,
|
||||
(void **) &decklinksink->output);
|
||||
if (ret != S_OK) {
|
||||
GST_WARNING ("selected device does not have output interface");
|
||||
return FALSE;
|
||||
}
|
||||
decklinksink->output = gst_decklink_get_nth_output (decklinksink->device);
|
||||
|
||||
decklinksink->output->SetAudioCallback (decklinksink->callback);
|
||||
|
||||
|
@ -527,11 +522,6 @@ gst_decklink_sink_stop (GstDecklinkSink * decklinksink)
|
|||
decklinksink->output->DisableAudioOutput ();
|
||||
decklinksink->output->DisableVideoOutput ();
|
||||
|
||||
decklinksink->output->Release ();
|
||||
decklinksink->output = NULL;
|
||||
decklinksink->decklink->Release ();
|
||||
decklinksink->decklink = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -515,8 +515,6 @@ gst_decklink_src_start (GstElement * element)
|
|||
{
|
||||
GstDecklinkSrc *decklinksrc = GST_DECKLINK_SRC (element);
|
||||
DeckLinkCaptureDelegate *delegate;
|
||||
//IDeckLinkDisplayModeIterator *mode_iterator;
|
||||
//IDeckLinkDisplayMode *mode;
|
||||
BMDAudioSampleType sample_depth;
|
||||
int channels;
|
||||
HRESULT ret;
|
||||
|
@ -532,24 +530,19 @@ gst_decklink_src_start (GstElement * element)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
ret = decklinksrc->decklink->QueryInterface (IID_IDeckLinkInput,
|
||||
(void **) &decklinksrc->input);
|
||||
if (ret != S_OK) {
|
||||
GST_ERROR ("selected device does not have input interface");
|
||||
return FALSE;
|
||||
}
|
||||
decklinksrc->input = gst_decklink_get_nth_input (decklinksrc->device);
|
||||
|
||||
delegate = new DeckLinkCaptureDelegate ();
|
||||
delegate->priv = decklinksrc;
|
||||
decklinksrc->input->SetCallback (delegate);
|
||||
|
||||
ret = decklinksrc->decklink->QueryInterface (IID_IDeckLinkConfiguration,
|
||||
(void **) &config);
|
||||
ret = decklinksrc->input->SetCallback (delegate);
|
||||
if (ret != S_OK) {
|
||||
GST_ERROR ("query interface failed");
|
||||
GST_ERROR ("set callback failed (input source)");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
decklinksrc->config = gst_decklink_get_nth_config (decklinksrc->device);
|
||||
config = decklinksrc->config;
|
||||
|
||||
switch (decklinksrc->connection) {
|
||||
default:
|
||||
case GST_DECKLINK_CONNECTION_SDI:
|
||||
|
@ -613,25 +606,6 @@ gst_decklink_src_start (GstElement * element)
|
|||
GST_ERROR ("set configuration (audio input connection)");
|
||||
return FALSE;
|
||||
}
|
||||
#if 0
|
||||
ret = decklinksrc->input->GetDisplayModeIterator (&mode_iterator);
|
||||
if (ret != S_OK) {
|
||||
GST_ERROR ("failed to get display mode iterator");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (mode_iterator->Next (&mode) == S_OK) {
|
||||
const char *mode_name;
|
||||
|
||||
mode->GetName (&mode_name);
|
||||
|
||||
GST_DEBUG ("%d: mode name: %s", i, mode_name);
|
||||
|
||||
mode->Release ();
|
||||
i++;
|
||||
}
|
||||
#endif
|
||||
|
||||
mode = gst_decklink_get_mode (decklinksrc->mode);
|
||||
|
||||
|
@ -667,6 +641,7 @@ static gboolean
|
|||
gst_decklink_src_stop (GstElement * element)
|
||||
{
|
||||
GstDecklinkSrc *decklinksrc = GST_DECKLINK_SRC (element);
|
||||
//int refcount;
|
||||
|
||||
gst_task_stop (decklinksrc->task);
|
||||
|
||||
|
@ -681,12 +656,6 @@ gst_decklink_src_stop (GstElement * element)
|
|||
decklinksrc->input->DisableVideoInput ();
|
||||
decklinksrc->input->DisableAudioInput ();
|
||||
|
||||
decklinksrc->input->Release ();
|
||||
decklinksrc->input = NULL;
|
||||
|
||||
decklinksrc->decklink->Release ();
|
||||
decklinksrc->decklink = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -1456,6 +1425,7 @@ gst_decklinksrc_class_probe_devices (GstElementClass * klass)
|
|||
n_devices++;
|
||||
}
|
||||
}
|
||||
iterator->Release();
|
||||
|
||||
probed = TRUE;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ struct _GstDecklinkSrc
|
|||
|
||||
IDeckLink *decklink;
|
||||
IDeckLinkInput *input;
|
||||
IDeckLinkConfiguration *config;
|
||||
|
||||
GMutex *mutex;
|
||||
GCond *cond;
|
||||
|
|
Loading…
Reference in a new issue