diff --git a/gstajacommon.cpp b/gstajacommon.cpp index e14219afb6..004981a5e9 100644 --- a/gstajacommon.cpp +++ b/gstajacommon.cpp @@ -589,7 +589,7 @@ static void gst_aja_allocator_finalize(GObject *alloc) { GST_DEBUG_OBJECT(alloc, "Freeing allocator"); - gst_aja_device_unref(aja_alloc->device); + gst_aja_ntv2_device_unref(aja_alloc->device); G_OBJECT_CLASS(gst_aja_allocator_parent_class)->finalize(alloc); } @@ -617,11 +617,11 @@ static void gst_aja_allocator_init(GstAjaAllocator *aja_alloc) { alloc->mem_share = (GstMemoryShareFunction)_aja_memory_share; } -GstAllocator *gst_aja_allocator_new(GstAjaDevice *device) { +GstAllocator *gst_aja_allocator_new(GstAjaNtv2Device *device) { GstAjaAllocator *alloc = (GstAjaAllocator *)g_object_new(GST_TYPE_AJA_ALLOCATOR, NULL); - alloc->device = gst_aja_device_ref(device); + alloc->device = gst_aja_ntv2_device_ref(device); GST_DEBUG_OBJECT(alloc, "Creating allocator for device %d", device->device->GetIndexNumber()); @@ -629,7 +629,7 @@ GstAllocator *gst_aja_allocator_new(GstAjaDevice *device) { return GST_ALLOCATOR(alloc); } -GstAjaDevice *gst_aja_device_obtain(const gchar *device_identifier) { +GstAjaNtv2Device *gst_aja_ntv2_device_obtain(const gchar *device_identifier) { CNTV2Device *device = new CNTV2Device(); if (!CNTV2DeviceScanner::GetFirstDeviceFromArgument(device_identifier, @@ -638,19 +638,19 @@ GstAjaDevice *gst_aja_device_obtain(const gchar *device_identifier) { return NULL; } - GstAjaDevice *dev = g_atomic_rc_box_new0(GstAjaDevice); + GstAjaNtv2Device *dev = g_atomic_rc_box_new0(GstAjaNtv2Device); dev->device = device; return dev; } -GstAjaDevice *gst_aja_device_ref(GstAjaDevice *device) { - return (GstAjaDevice *)g_atomic_rc_box_acquire(device); +GstAjaNtv2Device *gst_aja_ntv2_device_ref(GstAjaNtv2Device *device) { + return (GstAjaNtv2Device *)g_atomic_rc_box_acquire(device); } -void gst_aja_device_unref(GstAjaDevice *device) { +void gst_aja_ntv2_device_unref(GstAjaNtv2Device *device) { g_atomic_rc_box_release_full(device, [](gpointer data) { - GstAjaDevice *dev = (GstAjaDevice *)data; + GstAjaNtv2Device *dev = (GstAjaNtv2Device *)data; delete dev->device; }); diff --git a/gstajacommon.h b/gstajacommon.h index 5f49bb8c16..a976ded5a5 100644 --- a/gstajacommon.h +++ b/gstajacommon.h @@ -56,14 +56,14 @@ GstAjaAudioMeta *gst_buffer_add_aja_audio_meta(GstBuffer *buffer, typedef struct { CNTV2Card *device; -} GstAjaDevice; +} GstAjaNtv2Device; G_GNUC_INTERNAL -GstAjaDevice *gst_aja_device_obtain(const gchar *device_identifier); +GstAjaNtv2Device *gst_aja_ntv2_device_obtain(const gchar *device_identifier); G_GNUC_INTERNAL -GstAjaDevice *gst_aja_device_ref(GstAjaDevice *device); +GstAjaNtv2Device *gst_aja_ntv2_device_ref(GstAjaNtv2Device *device); G_GNUC_INTERNAL -void gst_aja_device_unref(GstAjaDevice *device); +void gst_aja_ntv2_device_unref(GstAjaNtv2Device *device); #define GST_AJA_ALLOCATOR_MEMTYPE "aja" @@ -85,7 +85,7 @@ typedef struct _GstAjaAllocatorClass GstAjaAllocatorClass; struct _GstAjaAllocator { GstAllocator allocator; - GstAjaDevice *device; + GstAjaNtv2Device *device; }; struct _GstAjaAllocatorClass { @@ -95,7 +95,7 @@ struct _GstAjaAllocatorClass { G_GNUC_INTERNAL GType gst_aja_allocator_get_type(void); G_GNUC_INTERNAL -GstAllocator *gst_aja_allocator_new(GstAjaDevice *device); +GstAllocator *gst_aja_allocator_new(GstAjaNtv2Device *device); typedef enum { GST_AJA_AUDIO_SYSTEM_AUTO, diff --git a/gstajadeviceprovider.cpp b/gstajadeviceprovider.cpp new file mode 100644 index 0000000000..361aac8cfe --- /dev/null +++ b/gstajadeviceprovider.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2019 Mathieu Duponchelle + * Copyright (C) 2019,2021 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstajacommon.h" +#include "gstajadeviceprovider.h" + +static GstDevice *gst_aja_device_new(NTV2DeviceInfo &device, gboolean video); + +G_DEFINE_TYPE(GstAjaDeviceProvider, gst_aja_device_provider, + GST_TYPE_DEVICE_PROVIDER); + +static void gst_aja_device_provider_init(GstAjaDeviceProvider *self) {} + +static GList *gst_aja_device_provider_probe(GstDeviceProvider *provider) { + GList *ret = NULL; + + CNTV2DeviceScanner scanner; + + NTV2DeviceInfoList devices = scanner.GetDeviceInfoList(); + for (NTV2DeviceInfoList::iterator it = devices.begin(); it != devices.end(); + it++) { + // Skip non-input / non-output devices + if (it->numVidInputs == 0 && it->numVidOutputs == 0) continue; + + if (it->numVidInputs > 0) + ret = g_list_prepend(ret, gst_aja_device_new(*it, TRUE)); + if (it->numVidOutputs > 0) + ret = g_list_prepend(ret, gst_aja_device_new(*it, FALSE)); + } + + ret = g_list_reverse(ret); + + return ret; +} + +static void gst_aja_device_provider_class_init( + GstAjaDeviceProviderClass *klass) { + GstDeviceProviderClass *dm_class = GST_DEVICE_PROVIDER_CLASS(klass); + + dm_class->probe = GST_DEBUG_FUNCPTR(gst_aja_device_provider_probe); + + gst_device_provider_class_set_static_metadata( + dm_class, "AJA Device Provider", "Source/Audio/Video", + "List and provides AJA capture devices", + "Sebastian Dröge "); +} + +G_DEFINE_TYPE(GstAjaDevice, gst_aja_device, GST_TYPE_DEVICE); + +static void gst_aja_device_init(GstAjaDevice *self) {} + +static GstElement *gst_aja_device_create_element(GstDevice *device, + const gchar *name) { + GstAjaDevice *self = GST_AJA_DEVICE(device); + GstElement *ret = NULL; + + if (self->is_capture) { + ret = gst_element_factory_make("ajasrc", name); + } else { + ret = gst_element_factory_make("ajasink", name); + } + + if (ret) { + gchar *device_identifier = g_strdup_printf("%u", self->device_index); + + g_object_set(ret, "device-identifier", device_identifier, NULL); + g_free(device_identifier); + } + + return ret; +} + +static void gst_aja_device_class_init(GstAjaDeviceClass *klass) { + GstDeviceClass *gst_device_class = GST_DEVICE_CLASS(klass); + + gst_device_class->create_element = + GST_DEBUG_FUNCPTR(gst_aja_device_create_element); +} + +static GstDevice *gst_aja_device_new(NTV2DeviceInfo &device, + gboolean is_capture) { + GstDevice *ret; + gchar *display_name; + const gchar *device_class; + GstCaps *caps = NULL; + GstStructure *properties; + + device_class = is_capture ? "Audio/Video/Source" : "Audio/Video/Sink"; + display_name = g_strdup_printf("AJA %s (%s)", device.deviceIdentifier.c_str(), + is_capture ? "Source" : "Sink"); + + caps = gst_ntv2_supported_caps(device.deviceID); + + properties = gst_structure_new_empty("properties"); + + gst_structure_set( + properties, "device-id", G_TYPE_UINT, device.deviceID, "device-index", + G_TYPE_UINT, device.deviceIndex, "pci-slot", G_TYPE_UINT, device.pciSlot, + "serial-number", G_TYPE_UINT64, device.deviceSerialNumber, + "device-identifier", G_TYPE_STRING, device.deviceIdentifier.c_str(), + "num-audio-streams", G_TYPE_UINT, device.numAudioStreams, + "dual-link-support", G_TYPE_BOOLEAN, device.dualLinkSupport, + "sdi-3g-support", G_TYPE_BOOLEAN, device.sdi3GSupport, "sdi-12g-support", + G_TYPE_BOOLEAN, device.sdi12GSupport, "ip-support", G_TYPE_BOOLEAN, + device.ipSupport, "bi-directional-sdi", G_TYPE_BOOLEAN, + device.biDirectionalSDI, "ltc-in-support", G_TYPE_BOOLEAN, + device.ltcInSupport, "ltc-in-on-ref-port", G_TYPE_BOOLEAN, + device.ltcInOnRefPort, "2k-support", G_TYPE_BOOLEAN, device.has2KSupport, + "4k-support", G_TYPE_BOOLEAN, device.has4KSupport, "8k-support", + G_TYPE_BOOLEAN, device.has8KSupport, "multiformat-support", + G_TYPE_BOOLEAN, device.multiFormat, NULL); + + if (is_capture) { + gst_structure_set( + properties, "num-vid-inputs", G_TYPE_UINT, device.numVidInputs, + "num-anlg-vid-inputs", G_TYPE_UINT, device.numAnlgVidInputs, + "num-hdmi-vid-inputs", G_TYPE_UINT, device.numHDMIVidInputs, + "num-analog-audio-input-channels", G_TYPE_UINT, + device.numAnalogAudioInputChannels, "num-aes-audio-input-channels", + G_TYPE_UINT, device.numAESAudioInputChannels, + "num-embedded-audio-input-channels", G_TYPE_UINT, + device.numEmbeddedAudioInputChannels, "num-hdmi-audio-input-channels", + G_TYPE_UINT, device.numHDMIAudioInputChannels, NULL); + } else { + gst_structure_set( + properties, "num-vid-outputs", G_TYPE_UINT, device.numVidOutputs, + "num-anlg-vid-outputs", G_TYPE_UINT, device.numAnlgVidOutputs, + "num-hdmi-vid-outputs", G_TYPE_UINT, device.numHDMIVidOutputs, + "num-analog-audio-output-channels", G_TYPE_UINT, + device.numAnalogAudioOutputChannels, "num-aes-audio-output-channels", + G_TYPE_UINT, device.numAESAudioOutputChannels, + "num-embedded-audio-output-channels", G_TYPE_UINT, + device.numEmbeddedAudioOutputChannels, "num-hdmi-audio-output-channels", + G_TYPE_UINT, device.numHDMIAudioOutputChannels, NULL); + } + + ret = GST_DEVICE(g_object_new(GST_TYPE_AJA_DEVICE, "display-name", + display_name, "device-class", device_class, + "caps", caps, "properties", properties, NULL)); + + g_free(display_name); + gst_caps_unref(caps); + gst_structure_free(properties); + + GST_AJA_DEVICE(ret)->is_capture = is_capture; + GST_AJA_DEVICE(ret)->device_index = device.deviceIndex; + + return ret; +} diff --git a/gstajadeviceprovider.h b/gstajadeviceprovider.h new file mode 100644 index 0000000000..94829bdcfb --- /dev/null +++ b/gstajadeviceprovider.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 Mathieu Duponchelle + * Copyright (C) 2019,2021 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef _GST_AJA_DEVICE_PROVIDER_H_ +#define _GST_AJA_DEVICE_PROVIDER_H_ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_AJA_DEVICE_PROVIDER gst_aja_device_provider_get_type() +#define GST_AJA_DEVICE_PROVIDER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_AJA_DEVICE_PROVIDER, \ + GstAjaDeviceProvider)) + +typedef struct _GstAjaDeviceProvider GstAjaDeviceProvider; +typedef struct _GstAjaDeviceProviderClass GstAjaDeviceProviderClass; + +struct _GstAjaDeviceProviderClass { + GstDeviceProviderClass parent_class; +}; + +struct _GstAjaDeviceProvider { + GstDeviceProvider parent; +}; + +G_GNUC_INTERNAL +GType gst_aja_device_provider_get_type(void); + +#define GST_TYPE_AJA_DEVICE gst_aja_device_get_type() +#define GST_AJA_DEVICE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_AJA_DEVICE, GstAjaDevice)) + +typedef struct _GstAjaDevice GstAjaDevice; +typedef struct _GstAjaDeviceClass GstAjaDeviceClass; + +struct _GstAjaDeviceClass { + GstDeviceClass parent_class; +}; + +struct _GstAjaDevice { + GstDevice parent; + gboolean is_capture; + guint device_index; +}; + +G_GNUC_INTERNAL +GType gst_aja_device_get_type(void); + +G_END_DECLS + +#endif /* _GST_AJA_DEVICE_PROVIDER_H_ */ diff --git a/gstajasink.cpp b/gstajasink.cpp index d4008a8fb7..5fec1fbab8 100644 --- a/gstajasink.cpp +++ b/gstajasink.cpp @@ -326,14 +326,14 @@ static gboolean gst_aja_sink_open(GstAjaSink *self) { g_assert(self->device == NULL); - self->device = gst_aja_device_obtain(self->device_identifier); + self->device = gst_aja_ntv2_device_obtain(self->device_identifier); if (!self->device) { GST_ERROR_OBJECT(self, "Failed to open device"); return FALSE; } if (!self->device->device->IsDeviceReady(false)) { - g_clear_pointer(&self->device, gst_aja_device_unref); + g_clear_pointer(&self->device, gst_aja_ntv2_device_unref); return FALSE; } @@ -371,7 +371,7 @@ static gboolean gst_aja_sink_open(GstAjaSink *self) { static gboolean gst_aja_sink_close(GstAjaSink *self) { gst_clear_object(&self->allocator); - g_clear_pointer(&self->device, gst_aja_device_unref); + g_clear_pointer(&self->device, gst_aja_ntv2_device_unref); self->device_id = DEVICE_ID_INVALID; GST_DEBUG_OBJECT(self, "Closed device"); diff --git a/gstajasink.h b/gstajasink.h index 1cc8e237b2..054a67e98c 100644 --- a/gstajasink.h +++ b/gstajasink.h @@ -56,7 +56,7 @@ struct _GstAjaSink { GCond drain_cond; gboolean flushing; - GstAjaDevice *device; + GstAjaNtv2Device *device; NTV2DeviceID device_id; GstAllocator *allocator; diff --git a/gstajasrc.cpp b/gstajasrc.cpp index a23757c053..6c97cb5c15 100644 --- a/gstajasrc.cpp +++ b/gstajasrc.cpp @@ -230,7 +230,7 @@ static void gst_aja_src_class_init(GstAjaSrcClass *klass) { gst_caps_unref(templ_caps); gst_element_class_set_static_metadata( - element_class, "AJA audio/video src", "Audio/Video/Src", + element_class, "AJA audio/video src", "Audio/Video/Source", "Captures audio/video frames with AJA devices", "Sebastian Dröge "); @@ -370,14 +370,14 @@ static gboolean gst_aja_src_open(GstAjaSrc *self) { g_assert(self->device == NULL); - self->device = gst_aja_device_obtain(self->device_identifier); + self->device = gst_aja_ntv2_device_obtain(self->device_identifier); if (!self->device) { GST_ERROR_OBJECT(self, "Failed to open device"); return FALSE; } if (!self->device->device->IsDeviceReady(false)) { - g_clear_pointer(&self->device, gst_aja_device_unref); + g_clear_pointer(&self->device, gst_aja_ntv2_device_unref); return FALSE; } @@ -415,7 +415,7 @@ static gboolean gst_aja_src_open(GstAjaSrc *self) { static gboolean gst_aja_src_close(GstAjaSrc *self) { gst_clear_object(&self->allocator); - g_clear_pointer(&self->device, gst_aja_device_unref); + g_clear_pointer(&self->device, gst_aja_ntv2_device_unref); self->device_id = DEVICE_ID_INVALID; GST_DEBUG_OBJECT(self, "Closed device"); @@ -1561,7 +1561,11 @@ static GstFlowReturn gst_aja_src_create(GstPushSrc *psrc, GstBuffer **buffer) { switch (vpid.GetTransferCharacteristics()) { default: case NTV2_VPID_TC_SDR_TV: - // SDR is the default, do nothing here. + if (info.height < 720) { + info.colorimetry.transfer = GST_VIDEO_TRANSFER_BT601; + } else { + info.colorimetry.transfer = GST_VIDEO_TRANSFER_BT709; + } break; case NTV2_VPID_TC_HLG: info.colorimetry.transfer = GST_VIDEO_TRANSFER_ARIB_STD_B67; diff --git a/gstajasrc.h b/gstajasrc.h index 4cbddbac22..f73b4c646d 100644 --- a/gstajasrc.h +++ b/gstajasrc.h @@ -52,7 +52,7 @@ struct _GstAjaSrc { gboolean shutdown; gboolean flushing; - GstAjaDevice *device; + GstAjaNtv2Device *device; NTV2DeviceID device_id; GstAllocator *allocator; GstBufferPool *buffer_pool; diff --git a/meson.build b/meson.build index 66cc7c2858..b46abe89ac 100644 --- a/meson.build +++ b/meson.build @@ -84,6 +84,7 @@ gstaja = library('gstaja', 'gstajasinkcombiner.cpp', 'gstajasrc.cpp', 'gstajasrcdemux.cpp', + 'gstajadeviceprovider.cpp', ], cpp_args : [ aja_includedirs, diff --git a/plugin.cpp b/plugin.cpp index 1423c69c7e..128de52e48 100644 --- a/plugin.cpp +++ b/plugin.cpp @@ -21,6 +21,7 @@ #include #include "gstajacommon.h" +#include "gstajadeviceprovider.h" #include "gstajasink.h" #include "gstajasinkcombiner.h" #include "gstajasrc.h" @@ -38,6 +39,9 @@ static gboolean plugin_init(GstPlugin* plugin) { gst_element_register(plugin, "ajasinkcombiner", GST_RANK_NONE, GST_TYPE_AJA_SINK_COMBINER); + gst_device_provider_register(plugin, "ajadeviceprovider", GST_RANK_PRIMARY, + GST_TYPE_AJA_DEVICE_PROVIDER); + return TRUE; }