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)
{
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;
}

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

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