decklinkvideosrc: Add automatic mode detection

https://bugzilla.gnome.org/show_bug.cgi?id=739284
This commit is contained in:
Florian Langlois 2015-01-08 16:42:31 +01:00 committed by Sebastian Dröge
parent 9dcf650a17
commit 9480d91ad4
4 changed files with 178 additions and 11 deletions

View file

@ -38,6 +38,8 @@ gst_decklink_mode_get_type (void)
{
static gsize id = 0;
static const GEnumValue modes[] = {
{GST_DECKLINK_MODE_AUTO, "auto", "Automatic detection"},
{GST_DECKLINK_MODE_NTSC, "ntsc", "NTSC SD 60i"},
{GST_DECKLINK_MODE_NTSC2398, "ntsc2398", "NTSC SD 60i (24 fps)"},
{GST_DECKLINK_MODE_PAL, "pal", "PAL SD 50i"},
@ -140,6 +142,8 @@ gst_decklink_audio_connection_get_type (void)
#define HD 1, 1, false, true
static const GstDecklinkMode modes[] = {
{bmdModeNTSC, 720, 486, 30000, 1001, true, NTSC}, // default is ntsc
{bmdModeNTSC, 720, 486, 30000, 1001, true, NTSC},
{bmdModeNTSC2398, 720, 486, 24000, 1001, true, NTSC},
{bmdModePAL, 720, 576, 25, 1, true, PAL},
@ -181,11 +185,113 @@ static const GstDecklinkMode modes[] = {
const GstDecklinkMode *
gst_decklink_get_mode (GstDecklinkModeEnum e)
{
if (e < GST_DECKLINK_MODE_NTSC || e > GST_DECKLINK_MODE_3184p60)
if (e < GST_DECKLINK_MODE_AUTO || e > GST_DECKLINK_MODE_3184p60)
return NULL;
return &modes[e];
}
const GstDecklinkModeEnum
gst_decklink_get_mode_enum_from_bmd (BMDDisplayMode mode)
{
GstDecklinkModeEnum displayMode = GST_DECKLINK_MODE_NTSC;
switch (mode) {
case bmdModeNTSC:
displayMode = GST_DECKLINK_MODE_NTSC;
break;
case bmdModeNTSC2398:
displayMode = GST_DECKLINK_MODE_NTSC2398;
break;
case bmdModePAL:
displayMode = GST_DECKLINK_MODE_PAL;
break;
case bmdModeNTSCp:
displayMode = GST_DECKLINK_MODE_NTSC_P;
break;
case bmdModePALp:
displayMode = GST_DECKLINK_MODE_PAL_P;
break;
case bmdModeHD1080p2398:
displayMode = GST_DECKLINK_MODE_1080p2398;
break;
case bmdModeHD1080p24:
displayMode = GST_DECKLINK_MODE_1080p24;
break;
case bmdModeHD1080p25:
displayMode = GST_DECKLINK_MODE_1080p25;
break;
case bmdModeHD1080p2997:
displayMode = GST_DECKLINK_MODE_1080p2997;
break;
case bmdModeHD1080p30:
displayMode = GST_DECKLINK_MODE_1080p30;
break;
case bmdModeHD1080i50:
displayMode = GST_DECKLINK_MODE_1080i50;
break;
case bmdModeHD1080i5994:
displayMode = GST_DECKLINK_MODE_1080i5994;
break;
case bmdModeHD1080i6000:
displayMode = GST_DECKLINK_MODE_1080i60;
break;
case bmdModeHD1080p50:
displayMode = GST_DECKLINK_MODE_1080p50;
break;
case bmdModeHD1080p5994:
displayMode = GST_DECKLINK_MODE_1080p5994;
break;
case bmdModeHD1080p6000:
displayMode = GST_DECKLINK_MODE_1080p60;
break;
case bmdModeHD720p50:
displayMode = GST_DECKLINK_MODE_720p50;
break;
case bmdModeHD720p5994:
displayMode = GST_DECKLINK_MODE_720p5994;
break;
case bmdModeHD720p60:
displayMode = GST_DECKLINK_MODE_720p60;
break;
case bmdMode2k2398:
displayMode = GST_DECKLINK_MODE_2048p2398;
break;
case bmdMode2k24:
displayMode = GST_DECKLINK_MODE_2048p24;
break;
case bmdMode2k25:
displayMode = GST_DECKLINK_MODE_2048p25;
break;
case bmdMode4K2160p2398:
displayMode = GST_DECKLINK_MODE_3184p2398;
break;
case bmdMode4K2160p24:
displayMode = GST_DECKLINK_MODE_3184p24;
break;
case bmdMode4K2160p25:
displayMode = GST_DECKLINK_MODE_3184p25;
break;
case bmdMode4K2160p2997:
displayMode = GST_DECKLINK_MODE_3184p2997;
break;
case bmdMode4K2160p30:
displayMode = GST_DECKLINK_MODE_3184p30;
break;
case bmdMode4K2160p50:
displayMode = GST_DECKLINK_MODE_3184p50;
break;
case bmdMode4K2160p5994:
displayMode = GST_DECKLINK_MODE_3184p5994;
break;
case bmdMode4K2160p60:
displayMode = GST_DECKLINK_MODE_3184p60;
break;
default:
g_assert_not_reached ();
break;
}
return displayMode;
}
static const BMDVideoConnection connections[] = {
0, /* auto */
bmdVideoConnectionSDI,
@ -346,9 +452,21 @@ public:
virtual HRESULT STDMETHODCALLTYPE
VideoInputFormatChanged (BMDVideoInputFormatChangedEvents,
IDeckLinkDisplayMode *, BMDDetectedVideoInputFormatFlags)
IDeckLinkDisplayMode * mode, BMDDetectedVideoInputFormatFlags)
{
GST_FIXME ("Video input format change not supported yet");
GST_INFO ("Video input format changed");
g_mutex_lock (&m_input->lock);
m_input->input->PauseStreams ();
m_input->input->EnableVideoInput (mode->GetDisplayMode (),
bmdFormat8BitYUV, bmdVideoInputEnableFormatDetection);
m_input->input->FlushStreams ();
m_input->input->StartStreams ();
m_input->mode =
gst_decklink_get_mode (gst_decklink_get_mode_enum_from_bmd
(mode->GetDisplayMode ()));
g_mutex_unlock (&m_input->lock);
return S_OK;
}
@ -362,7 +480,9 @@ public:
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);
m_input->got_video_frame (m_input->videosrc, video_frame,
gst_decklink_get_mode_enum_from_bmd (m_input->mode->mode),
capture_time);
}
if (m_input->got_audio_packet) {
@ -493,6 +613,12 @@ init_devices (gpointer data)
GST_WARNING ("selected device does not have config interface");
}
ret = decklink->QueryInterface (IID_IDeckLinkAttributes,
(void **) &devices[i].input.attributes);
if (ret != S_OK) {
GST_WARNING ("selected device does not have attributes interface");
}
ret = iterator->Next (&decklink);
i++;

View file

@ -44,6 +44,8 @@
#endif /* _MSC_VER */
typedef enum {
GST_DECKLINK_MODE_AUTO,
GST_DECKLINK_MODE_NTSC,
GST_DECKLINK_MODE_NTSC2398,
GST_DECKLINK_MODE_PAL,
@ -122,6 +124,7 @@ struct _GstDecklinkMode {
};
const GstDecklinkMode * gst_decklink_get_mode (GstDecklinkModeEnum e);
const GstDecklinkModeEnum gst_decklink_get_mode_enum_from_bmd (BMDDisplayMode mode);
const BMDVideoConnection gst_decklink_get_connection (GstDecklinkConnectionEnum e);
GstCaps * gst_decklink_mode_get_caps (GstDecklinkModeEnum e);
GstCaps * gst_decklink_mode_get_template_caps (void);
@ -152,13 +155,14 @@ struct _GstDecklinkInput {
IDeckLink *device;
IDeckLinkInput *input;
IDeckLinkConfiguration *config;
IDeckLinkAttributes *attributes;
GstClock *clock;
/* Everything below protected by mutex */
GMutex lock;
/* Set by the video source */
void (*got_video_frame) (GstElement *videosrc, IDeckLinkVideoInputFrame * frame, GstClockTime capture_time);
void (*got_video_frame) (GstElement *videosrc, IDeckLinkVideoInputFrame * frame, GstDecklinkModeEnum mode, GstClockTime capture_time);
/* Configured mode or NULL */
const GstDecklinkMode *mode;

View file

@ -29,7 +29,7 @@
GST_DEBUG_CATEGORY_STATIC (gst_decklink_video_src_debug);
#define GST_CAT_DEFAULT gst_decklink_video_src_debug
#define DEFAULT_MODE (GST_DECKLINK_MODE_NTSC)
#define DEFAULT_MODE (GST_DECKLINK_MODE_AUTO)
#define DEFAULT_CONNECTION (GST_DECKLINK_CONNECTION_AUTO)
#define DEFAULT_BUFFER_SIZE (5)
@ -46,6 +46,7 @@ typedef struct
{
IDeckLinkVideoInputFrame *frame;
GstClockTime capture_time;
GstDecklinkModeEnum mode;
} CaptureFrame;
static void
@ -169,6 +170,7 @@ static void
gst_decklink_video_src_init (GstDecklinkVideoSrc * self)
{
self->mode = DEFAULT_MODE;
self->caps_mode = DEFAULT_MODE;
self->connection = DEFAULT_CONNECTION;
self->device_number = 0;
self->buffer_size = DEFAULT_BUFFER_SIZE;
@ -249,7 +251,7 @@ gst_decklink_video_src_get_caps (GstBaseSrc * bsrc, GstCaps * filter)
GstDecklinkVideoSrc *self = GST_DECKLINK_VIDEO_SRC_CAST (bsrc);
GstCaps *mode_caps, *caps;
mode_caps = gst_decklink_mode_get_caps (self->mode);
mode_caps = gst_decklink_mode_get_caps (self->caps_mode);
if (filter) {
caps =
gst_caps_intersect_full (filter, mode_caps, GST_CAPS_INTERSECT_FIRST);
@ -263,7 +265,8 @@ gst_decklink_video_src_get_caps (GstBaseSrc * bsrc, GstCaps * filter)
static void
gst_decklink_video_src_got_frame (GstElement * element,
IDeckLinkVideoInputFrame * frame, GstClockTime capture_time)
IDeckLinkVideoInputFrame * frame, GstDecklinkModeEnum mode,
GstClockTime capture_time)
{
GstDecklinkVideoSrc *self = GST_DECKLINK_VIDEO_SRC_CAST (element);
@ -284,6 +287,7 @@ gst_decklink_video_src_got_frame (GstElement * element,
f = (CaptureFrame *) g_malloc0 (sizeof (CaptureFrame));
f->frame = frame;
f->capture_time = capture_time;
f->mode = mode;
frame->AddRef ();
g_queue_push_tail (&self->current_frames, f);
g_cond_signal (&self->cond);
@ -301,6 +305,7 @@ gst_decklink_video_src_create (GstPushSrc * bsrc, GstBuffer ** buffer)
VideoFrame *vf;
CaptureFrame *f;
GstClockTime timestamp, duration;
GstCaps *caps;
g_mutex_lock (&self->lock);
while (g_queue_is_empty (&self->current_frames) && !self->flushing) {
@ -316,6 +321,14 @@ gst_decklink_video_src_create (GstPushSrc * bsrc, GstBuffer ** buffer)
return GST_FLOW_FLUSHING;
}
if (self->caps_mode != f->mode) {
self->caps_mode = f->mode;
caps = gst_decklink_mode_get_caps (self->caps_mode);
gst_video_info_from_caps (&self->info, caps);
gst_base_src_set_caps (GST_BASE_SRC_CAST (bsrc), caps);
gst_caps_unref (caps);
}
f->frame->GetBytes ((gpointer *) & data);
data_size = self->info.size;
@ -362,7 +375,7 @@ gst_decklink_video_src_query (GstBaseSrc * bsrc, GstQuery * query)
GstClockTime min, max;
const GstDecklinkMode *mode;
mode = gst_decklink_get_mode (self->mode);
mode = gst_decklink_get_mode (self->caps_mode);
min = gst_util_uint64_scale_ceil (GST_SECOND, mode->fps_d, mode->fps_n);
max = self->buffer_size * min;
@ -414,6 +427,8 @@ static gboolean
gst_decklink_video_src_open (GstDecklinkVideoSrc * self)
{
const GstDecklinkMode *mode;
BMDVideoInputFlags flags;
bool autoDetection;
GstCaps *caps;
HRESULT ret;
@ -446,11 +461,31 @@ gst_decklink_video_src_open (GstDecklinkVideoSrc * self)
}
}
flags = bmdVideoInputFlagDefault;
if (self->mode == GST_DECKLINK_MODE_AUTO) {
if (self->input->attributes) {
ret =
self->input->
attributes->GetFlag (BMDDeckLinkSupportsInputFormatDetection,
&autoDetection);
if (ret != S_OK) {
GST_ERROR_OBJECT (self, "Failed to get attribute (autodetection)");
return FALSE;
}
if (autoDetection)
flags |= bmdVideoInputEnableFormatDetection;
}
if (!autoDetection) {
GST_ERROR_OBJECT (self, "Failed to activate auto-detection");
return FALSE;
}
}
mode = gst_decklink_get_mode (self->mode);
g_assert (mode != NULL);
ret = self->input->input->EnableVideoInput (mode->mode,
bmdFormat8BitYUV, bmdVideoOutputFlagDefault);
bmdFormat8BitYUV, flags);
if (ret != S_OK) {
GST_WARNING_OBJECT (self, "Failed to enable video input");
gst_decklink_release_nth_input (self->device_number,
@ -463,7 +498,8 @@ gst_decklink_video_src_open (GstDecklinkVideoSrc * self)
self->input->got_video_frame = gst_decklink_video_src_got_frame;
g_mutex_unlock (&self->input->lock);
caps = gst_decklink_mode_get_caps (self->mode);
self->caps_mode = gst_decklink_get_mode_enum_from_bmd (mode->mode);
caps = gst_decklink_mode_get_caps (self->caps_mode);
gst_video_info_from_caps (&self->info, caps);
gst_caps_unref (caps);

View file

@ -51,6 +51,7 @@ struct _GstDecklinkVideoSrc
GstPushSrc parent;
GstDecklinkModeEnum mode;
GstDecklinkModeEnum caps_mode;
GstDecklinkConnectionEnum connection;
gint device_number;