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:
David Schleef 2012-09-23 13:15:20 -07:00 committed by Tim-Philipp Müller
parent dd66252f23
commit 65a1f79bcb
6 changed files with 147 additions and 101 deletions

View file

@ -84,59 +84,80 @@ HRESULT
videoFrame, IDeckLinkAudioInputPacket * audioFrame) videoFrame, IDeckLinkAudioInputPacket * audioFrame)
{ {
GstDecklinkSrc *decklinksrc; GstDecklinkSrc *decklinksrc;
const char *timecodeString = NULL;
g_return_val_if_fail (priv != NULL, S_OK); g_return_val_if_fail (priv != NULL, S_OK);
g_return_val_if_fail (GST_IS_DECKLINK_SRC (priv), S_OK); g_return_val_if_fail (GST_IS_DECKLINK_SRC (priv), S_OK);
decklinksrc = GST_DECKLINK_SRC (priv); decklinksrc = GST_DECKLINK_SRC (priv);
// Handle Video Frame if (videoFrame == NULL) {
if (videoFrame) { GST_WARNING_OBJECT (decklinksrc, "video frame is NULL");
if (videoFrame->GetFlags () & bmdFrameHasNoInputSource) { return S_OK;
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);
}
}
GST_DEBUG ("Frame received [%s] - %s - Size: %li bytes", if (audioFrame == NULL) {
timecodeString != NULL ? timecodeString : "No timecode", GST_WARNING_OBJECT (decklinksrc, "audio frame is NULL");
"Valid Frame", videoFrame->GetRowBytes () * videoFrame->GetHeight ()); return S_OK;
}
if (timecodeString) if (videoFrame->GetFlags () & bmdFrameHasNoInputSource) {
FREE_COM_STRING (timecodeString); GST_DEBUG_OBJECT (decklinksrc, "Frame received - No input signal detected");
return S_OK;
}
g_mutex_lock (decklinksrc->mutex); if (g_timecodeFormat != 0) {
if (decklinksrc->video_frame != NULL) { IDeckLinkTimecode *timecode;
decklinksrc->dropped_frames++; if (videoFrame->GetTimecode (g_timecodeFormat, &timecode) == S_OK) {
} else { timecode->GetString (&timecodeString);
videoFrame->AddRef (); CONVERT_COM_STRING (timecodeString);
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);
} }
} }
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; return S_OK;
} }
HRESULT HRESULT
DeckLinkCaptureDelegate::VideoInputFormatChanged DeckLinkCaptureDelegate::VideoInputFormatChanged (
(BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode * mode, BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode * mode,
BMDDetectedVideoInputFormatFlags) { BMDDetectedVideoInputFormatFlags)
GST_ERROR ("moo"); {
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; return S_OK;
} }

View file

@ -190,34 +190,96 @@ gst_decklink_mode_get_template_caps (void)
return caps; return caps;
} }
IDeckLink * typedef struct _Device Device;
gst_decklink_get_nth_device (int n) 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; IDeckLinkIterator *iterator;
IDeckLink *decklink = NULL; IDeckLink *decklink = NULL;
HRESULT ret; HRESULT ret;
int i; int i;
static gboolean inited = FALSE;
if (inited) return;
inited = TRUE;
iterator = CreateDeckLinkIteratorInstance (); iterator = CreateDeckLinkIteratorInstance ();
if (iterator == NULL) { if (iterator == NULL) {
GST_ERROR ("no driver"); GST_ERROR ("no driver");
return NULL; return;
} }
i = 0;
ret = iterator->Next (&decklink); ret = iterator->Next (&decklink);
if (ret != S_OK) { while (ret == S_OK) {
GST_ERROR ("no card"); devices[i].decklink = decklink;
return NULL;
} ret = decklink->QueryInterface (IID_IDeckLinkInput,
for (i = 0; i < n; i++) { (void **) &devices[i].input);
ret = iterator->Next (&decklink);
if (ret != S_OK) { if (ret != S_OK) {
GST_ERROR ("no card"); GST_WARNING ("selected device does not have input interface");
return NULL; 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 static gboolean

View file

@ -108,6 +108,8 @@ GstCaps * gst_decklink_mode_get_caps (GstDecklinkModeEnum e);
GstCaps * gst_decklink_mode_get_template_caps (void); GstCaps * gst_decklink_mode_get_template_caps (void);
IDeckLink * gst_decklink_get_nth_device (int n); 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 #endif

View file

@ -469,12 +469,7 @@ gst_decklink_sink_start (GstDecklinkSink * decklinksink)
return FALSE; return FALSE;
} }
ret = decklinksink->decklink->QueryInterface (IID_IDeckLinkOutput, decklinksink->output = gst_decklink_get_nth_output (decklinksink->device);
(void **) &decklinksink->output);
if (ret != S_OK) {
GST_WARNING ("selected device does not have output interface");
return FALSE;
}
decklinksink->output->SetAudioCallback (decklinksink->callback); decklinksink->output->SetAudioCallback (decklinksink->callback);
@ -527,11 +522,6 @@ gst_decklink_sink_stop (GstDecklinkSink * decklinksink)
decklinksink->output->DisableAudioOutput (); decklinksink->output->DisableAudioOutput ();
decklinksink->output->DisableVideoOutput (); decklinksink->output->DisableVideoOutput ();
decklinksink->output->Release ();
decklinksink->output = NULL;
decklinksink->decklink->Release ();
decklinksink->decklink = NULL;
return TRUE; return TRUE;
} }

View file

@ -515,8 +515,6 @@ gst_decklink_src_start (GstElement * element)
{ {
GstDecklinkSrc *decklinksrc = GST_DECKLINK_SRC (element); GstDecklinkSrc *decklinksrc = GST_DECKLINK_SRC (element);
DeckLinkCaptureDelegate *delegate; DeckLinkCaptureDelegate *delegate;
//IDeckLinkDisplayModeIterator *mode_iterator;
//IDeckLinkDisplayMode *mode;
BMDAudioSampleType sample_depth; BMDAudioSampleType sample_depth;
int channels; int channels;
HRESULT ret; HRESULT ret;
@ -532,24 +530,19 @@ gst_decklink_src_start (GstElement * element)
return FALSE; return FALSE;
} }
ret = decklinksrc->decklink->QueryInterface (IID_IDeckLinkInput, decklinksrc->input = gst_decklink_get_nth_input (decklinksrc->device);
(void **) &decklinksrc->input);
if (ret != S_OK) {
GST_ERROR ("selected device does not have input interface");
return FALSE;
}
delegate = new DeckLinkCaptureDelegate (); delegate = new DeckLinkCaptureDelegate ();
delegate->priv = decklinksrc; delegate->priv = decklinksrc;
decklinksrc->input->SetCallback (delegate); ret = decklinksrc->input->SetCallback (delegate);
ret = decklinksrc->decklink->QueryInterface (IID_IDeckLinkConfiguration,
(void **) &config);
if (ret != S_OK) { if (ret != S_OK) {
GST_ERROR ("query interface failed"); GST_ERROR ("set callback failed (input source)");
return FALSE; return FALSE;
} }
decklinksrc->config = gst_decklink_get_nth_config (decklinksrc->device);
config = decklinksrc->config;
switch (decklinksrc->connection) { switch (decklinksrc->connection) {
default: default:
case GST_DECKLINK_CONNECTION_SDI: case GST_DECKLINK_CONNECTION_SDI:
@ -613,25 +606,6 @@ gst_decklink_src_start (GstElement * element)
GST_ERROR ("set configuration (audio input connection)"); GST_ERROR ("set configuration (audio input connection)");
return FALSE; 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); mode = gst_decklink_get_mode (decklinksrc->mode);
@ -667,6 +641,7 @@ static gboolean
gst_decklink_src_stop (GstElement * element) gst_decklink_src_stop (GstElement * element)
{ {
GstDecklinkSrc *decklinksrc = GST_DECKLINK_SRC (element); GstDecklinkSrc *decklinksrc = GST_DECKLINK_SRC (element);
//int refcount;
gst_task_stop (decklinksrc->task); gst_task_stop (decklinksrc->task);
@ -681,12 +656,6 @@ gst_decklink_src_stop (GstElement * element)
decklinksrc->input->DisableVideoInput (); decklinksrc->input->DisableVideoInput ();
decklinksrc->input->DisableAudioInput (); decklinksrc->input->DisableAudioInput ();
decklinksrc->input->Release ();
decklinksrc->input = NULL;
decklinksrc->decklink->Release ();
decklinksrc->decklink = NULL;
return TRUE; return TRUE;
} }
@ -1456,6 +1425,7 @@ gst_decklinksrc_class_probe_devices (GstElementClass * klass)
n_devices++; n_devices++;
} }
} }
iterator->Release();
probed = TRUE; probed = TRUE;
} }

View file

@ -45,6 +45,7 @@ struct _GstDecklinkSrc
IDeckLink *decklink; IDeckLink *decklink;
IDeckLinkInput *input; IDeckLinkInput *input;
IDeckLinkConfiguration *config;
GMutex *mutex; GMutex *mutex;
GCond *cond; GCond *cond;