diff options
author | Sebastian Dröge <sebastian@centricular.com> | 2016-11-28 17:17:43 +0200 |
---|---|---|
committer | Sebastian Dröge <sebastian@centricular.com> | 2016-11-28 17:20:40 +0200 |
commit | efb98c922d9c30a9c81a7b4d5e2dca2d703596d8 (patch) | |
tree | 5184c6b17f8f2b37f58ebcefe80cc3050f4e0e66 | |
parent | 481debc252b065678ad8386d9f63ab16991aaa34 (diff) | |
download | gstreamer-plugins-bad-efb98c922d9c30a9c81a7b4d5e2dca2d703596d8.tar.gz |
decklink: Correctly set top-field-first/bottom-field-first
First of all, all the HD and UHD modes should be top-field-first, as
also returned by the Decklink mode iterator API.
Then we should include the caps field "field-order" in the caps of the
source (not the sink due to negotiation problems with optional fields).
And finally we should set the TFF flag on interlaced buffers that are
top-field-first.
-rw-r--r-- | sys/decklink/gstdecklink.cpp | 77 | ||||
-rw-r--r-- | sys/decklink/gstdecklink.h | 8 | ||||
-rw-r--r-- | sys/decklink/gstdecklinkvideosink.cpp | 10 | ||||
-rw-r--r-- | sys/decklink/gstdecklinkvideosrc.cpp | 11 |
4 files changed, 82 insertions, 24 deletions
diff --git a/sys/decklink/gstdecklink.cpp b/sys/decklink/gstdecklink.cpp index 184f124a9..859633777 100644 --- a/sys/decklink/gstdecklink.cpp +++ b/sys/decklink/gstdecklink.cpp @@ -194,8 +194,8 @@ gst_decklink_audio_connection_get_type (void) #define NTSC 10, 11, false, "bt601" #define PAL 12, 11, true, "bt601" -#define HD 1, 1, false, "bt709" -#define UHD 1, 1, false, "bt2020" +#define HD 1, 1, true, "bt709" +#define UHD 1, 1, true, "bt2020" static const GstDecklinkMode modes[] = { {bmdModeNTSC, 720, 486, 30000, 1001, true, NTSC}, // default is ntsc @@ -467,7 +467,7 @@ gst_decklink_caps_get_pixel_format (GstCaps * caps, BMDPixelFormat * format) } static GstStructure * -gst_decklink_mode_get_structure (GstDecklinkModeEnum e, BMDPixelFormat f) +gst_decklink_mode_get_structure (GstDecklinkModeEnum e, BMDPixelFormat f, gboolean input) { const GstDecklinkMode *mode = &modes[e]; GstStructure *s = gst_structure_new ("video/x-raw", @@ -478,6 +478,13 @@ gst_decklink_mode_get_structure (GstDecklinkModeEnum e, BMDPixelFormat f) mode->interlaced ? "interleaved" : "progressive", "framerate", GST_TYPE_FRACTION, mode->fps_n, mode->fps_d, NULL); + if (input && mode->interlaced) { + if (mode->tff) + gst_structure_set (s, "field-order", G_TYPE_STRING, "top-field-first", NULL); + else + gst_structure_set (s, "field-order", G_TYPE_STRING, "bottom-field-first", NULL); + } + switch (f) { case bmdFormat8BitYUV: /* '2vuy' */ gst_structure_set (s, "format", G_TYPE_STRING, "UYVY", @@ -509,19 +516,19 @@ gst_decklink_mode_get_structure (GstDecklinkModeEnum e, BMDPixelFormat f) } GstCaps * -gst_decklink_mode_get_caps (GstDecklinkModeEnum e, BMDPixelFormat f) +gst_decklink_mode_get_caps (GstDecklinkModeEnum e, BMDPixelFormat f, gboolean input) { GstCaps *caps; caps = gst_caps_new_empty (); caps = - gst_caps_merge_structure (caps, gst_decklink_mode_get_structure (e, f)); + gst_caps_merge_structure (caps, gst_decklink_mode_get_structure (e, f, input)); return caps; } GstCaps * -gst_decklink_mode_get_caps_all_formats (GstDecklinkModeEnum e) +gst_decklink_mode_get_caps_all_formats (GstDecklinkModeEnum e, gboolean input) { GstCaps *caps; guint i; @@ -530,13 +537,13 @@ gst_decklink_mode_get_caps_all_formats (GstDecklinkModeEnum e) for (i = 1; i < G_N_ELEMENTS (formats); i++) caps = gst_caps_merge_structure (caps, gst_decklink_mode_get_structure (e, - formats[i].format)); + formats[i].format, input)); return caps; } GstCaps * -gst_decklink_pixel_format_get_caps (BMDPixelFormat f) +gst_decklink_pixel_format_get_caps (BMDPixelFormat f, gboolean input) { int i; GstCaps *caps; @@ -544,7 +551,7 @@ gst_decklink_pixel_format_get_caps (BMDPixelFormat f) caps = gst_caps_new_empty (); for (i = 1; i < (int) G_N_ELEMENTS (modes); i++) { - s = gst_decklink_mode_get_structure ((GstDecklinkModeEnum) i, f); + s = gst_decklink_mode_get_structure ((GstDecklinkModeEnum) i, f, input); caps = gst_caps_merge_structure (caps, s); } @@ -552,7 +559,7 @@ gst_decklink_pixel_format_get_caps (BMDPixelFormat f) } GstCaps * -gst_decklink_mode_get_template_caps (void) +gst_decklink_mode_get_template_caps (gboolean input) { int i; GstCaps *caps; @@ -561,7 +568,7 @@ gst_decklink_mode_get_template_caps (void) for (i = 1; i < (int) G_N_ELEMENTS (modes); i++) caps = gst_caps_merge (caps, - gst_decklink_mode_get_caps_all_formats ((GstDecklinkModeEnum) i)); + gst_decklink_mode_get_caps_all_formats ((GstDecklinkModeEnum) i, input)); return caps; } @@ -578,7 +585,7 @@ gst_decklink_find_mode_and_format_for_caps (GstCaps * caps, return NULL; for (i = 1; i < (int) G_N_ELEMENTS (modes); i++) { - mode_caps = gst_decklink_mode_get_caps ((GstDecklinkModeEnum) i, *format); + mode_caps = gst_decklink_mode_get_caps ((GstDecklinkModeEnum) i, *format, FALSE); if (gst_caps_can_intersect (caps, mode_caps)) { gst_caps_unref (mode_caps); return gst_decklink_get_mode ((GstDecklinkModeEnum) i); @@ -918,6 +925,8 @@ init_devices (gpointer data) GST_WARNING ("selected device does not have input interface: 0x%08x", ret); } else { + IDeckLinkDisplayModeIterator *mode_iter; + devices[i].input.device = decklink; devices[i].input.clock = gst_decklink_clock_new ("GstDecklinkInputClock"); GST_DECKLINK_CLOCK_CAST (devices[i].input.clock)->input = @@ -925,6 +934,27 @@ init_devices (gpointer data) devices[i].input. input->SetCallback (new GStreamerDecklinkInputCallback (&devices[i]. input)); + + if ((ret = + devices[i].input.input->GetDisplayModeIterator (&mode_iter)) == + S_OK) { + IDeckLinkDisplayMode *mode; + + GST_DEBUG ("Input %d supports:", i); + while ((ret = mode_iter->Next (&mode)) == S_OK) { + const char *name; + + mode->GetName (&name); + GST_DEBUG (" %s mode: 0x%08x width: %ld height: %ld" + " fields: 0x%08x flags: 0x%08x", name, + (int) mode->GetDisplayMode (), mode->GetWidth (), + mode->GetHeight (), (int) mode->GetFieldDominance (), + (int) mode->GetFlags ()); + mode->Release (); + } + mode_iter->Release (); + } + ret = S_OK; } ret = decklink->QueryInterface (IID_IDeckLinkOutput, @@ -933,11 +963,34 @@ init_devices (gpointer data) GST_WARNING ("selected device does not have output interface: 0x%08x", ret); } else { + IDeckLinkDisplayModeIterator *mode_iter; + devices[i].output.device = decklink; devices[i].output.clock = gst_decklink_clock_new ("GstDecklinkOutputClock"); GST_DECKLINK_CLOCK_CAST (devices[i].output.clock)->output = &devices[i].output; + + if ((ret = + devices[i].output.output->GetDisplayModeIterator (&mode_iter)) == + S_OK) { + IDeckLinkDisplayMode *mode; + + GST_DEBUG ("Output %d supports:", i); + while ((ret = mode_iter->Next (&mode)) == S_OK) { + const char *name; + + mode->GetName (&name); + GST_DEBUG (" %s mode: 0x%08x width: %ld height: %ld" + " fields: 0x%08x flags: 0x%08x", name, + (int) mode->GetDisplayMode (), mode->GetWidth (), + mode->GetHeight (), (int) mode->GetFieldDominance (), + (int) mode->GetFlags ()); + mode->Release (); + } + mode_iter->Release (); + } + ret = S_OK; } ret = decklink->QueryInterface (IID_IDeckLinkConfiguration, diff --git a/sys/decklink/gstdecklink.h b/sys/decklink/gstdecklink.h index 9f95c56ad..90fda5c25 100644 --- a/sys/decklink/gstdecklink.h +++ b/sys/decklink/gstdecklink.h @@ -160,8 +160,8 @@ 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, BMDPixelFormat f); -GstCaps * gst_decklink_mode_get_template_caps (void); +GstCaps * gst_decklink_mode_get_caps (GstDecklinkModeEnum e, BMDPixelFormat f, gboolean input); +GstCaps * gst_decklink_mode_get_template_caps (gboolean input); typedef struct _GstDecklinkOutput GstDecklinkOutput; struct _GstDecklinkOutput { @@ -231,7 +231,7 @@ void gst_decklink_release_nth_input (gint n, GstElement * src, gb const GstDecklinkMode * gst_decklink_find_mode_for_caps (GstCaps * caps); const GstDecklinkMode * gst_decklink_find_mode_and_format_for_caps (GstCaps * caps, BMDPixelFormat * format); -GstCaps * gst_decklink_mode_get_caps_all_formats (GstDecklinkModeEnum e); -GstCaps * gst_decklink_pixel_format_get_caps (BMDPixelFormat f); +GstCaps * gst_decklink_mode_get_caps_all_formats (GstDecklinkModeEnum e, gboolean input); +GstCaps * gst_decklink_pixel_format_get_caps (BMDPixelFormat f, gboolean input); #endif diff --git a/sys/decklink/gstdecklinkvideosink.cpp b/sys/decklink/gstdecklinkvideosink.cpp index 741d74f69..1612f8be2 100644 --- a/sys/decklink/gstdecklinkvideosink.cpp +++ b/sys/decklink/gstdecklinkvideosink.cpp @@ -227,7 +227,7 @@ gst_decklink_video_sink_class_init (GstDecklinkVideoSinkClass * klass) (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT))); - templ_caps = gst_decklink_mode_get_template_caps (); + templ_caps = gst_decklink_mode_get_template_caps (FALSE); templ_caps = gst_caps_make_writable (templ_caps); /* For output we support any framerate and only really care about timestamps */ gst_caps_map_in_place (templ_caps, reset_framerate, NULL); @@ -405,17 +405,17 @@ gst_decklink_video_sink_get_caps (GstBaseSink * bsink, GstCaps * filter) if (self->mode == GST_DECKLINK_MODE_AUTO && self->video_format == GST_DECKLINK_VIDEO_FORMAT_AUTO) - mode_caps = gst_decklink_mode_get_template_caps (); + mode_caps = gst_decklink_mode_get_template_caps (FALSE); else if (self->video_format == GST_DECKLINK_VIDEO_FORMAT_AUTO) - mode_caps = gst_decklink_mode_get_caps_all_formats (self->mode); + mode_caps = gst_decklink_mode_get_caps_all_formats (self->mode, FALSE); else if (self->mode == GST_DECKLINK_MODE_AUTO) mode_caps = gst_decklink_pixel_format_get_caps (gst_decklink_pixel_format_from_type - (self->video_format)); + (self->video_format), FALSE); else mode_caps = gst_decklink_mode_get_caps (self->mode, - gst_decklink_pixel_format_from_type (self->video_format)); + gst_decklink_pixel_format_from_type (self->video_format), FALSE); mode_caps = gst_caps_make_writable (mode_caps); /* For output we support any framerate and only really care about timestamps */ gst_caps_map_in_place (mode_caps, reset_framerate, NULL); diff --git a/sys/decklink/gstdecklinkvideosrc.cpp b/sys/decklink/gstdecklinkvideosrc.cpp index b8b546130..f5e785c85 100644 --- a/sys/decklink/gstdecklinkvideosrc.cpp +++ b/sys/decklink/gstdecklinkvideosrc.cpp @@ -181,7 +181,7 @@ gst_decklink_video_src_class_init (GstDecklinkVideoSrcClass * klass) (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT))); - templ_caps = gst_decklink_mode_get_template_caps (); + templ_caps = gst_decklink_mode_get_template_caps (TRUE); gst_element_class_add_pad_template (element_class, gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, templ_caps)); gst_caps_unref (templ_caps); @@ -420,7 +420,7 @@ gst_decklink_video_src_get_caps (GstBaseSrc * bsrc, GstCaps * filter) format = self->caps_format; g_mutex_unlock (&self->lock); - mode_caps = gst_decklink_mode_get_caps (mode, format); + mode_caps = gst_decklink_mode_get_caps (mode, format, TRUE); if (filter) { caps = @@ -587,6 +587,7 @@ gst_decklink_video_src_create (GstPushSrc * bsrc, GstBuffer ** buffer) CaptureFrame *f; GstCaps *caps; gboolean caps_changed = FALSE; + const GstDecklinkMode *mode; g_mutex_lock (&self->lock); while (g_queue_is_empty (&self->current_frames) && !self->flushing) { @@ -639,7 +640,7 @@ gst_decklink_video_src_create (GstPushSrc * bsrc, GstBuffer ** buffer) g_mutex_unlock (&self->lock); if (caps_changed) { - caps = gst_decklink_mode_get_caps (f->mode, f->format); + caps = gst_decklink_mode_get_caps (f->mode, f->format, TRUE); gst_video_info_from_caps (&self->info, caps); gst_base_src_set_caps (GST_BASE_SRC_CAST (bsrc), caps); gst_element_post_message (GST_ELEMENT_CAST (self), @@ -667,6 +668,10 @@ gst_decklink_video_src_create (GstPushSrc * bsrc, GstBuffer ** buffer) GST_BUFFER_DURATION (*buffer) = f->capture_duration; gst_buffer_add_video_time_code_meta (*buffer, f->tc); + mode = gst_decklink_get_mode (self->mode); + if (mode->interlaced && mode->tff) + GST_BUFFER_FLAG_SET (*buffer, GST_VIDEO_BUFFER_FLAG_TFF | GST_VIDEO_BUFFER_FLAG_INTERLACED); + GST_DEBUG_OBJECT (self, "Outputting buffer %p with timestamp %" GST_TIME_FORMAT " and duration %" GST_TIME_FORMAT, *buffer, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (*buffer)), |