mfvideosrc: Add support for DirectShow capture filter

Adding DirecShow video capture filter mode, in addition
to existing MediaFoundation and WinRT(UWP) mode, to support
DirectShow only filters (not KS driver compatible)
such as custom virtual camera filters.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3350>
This commit is contained in:
Seungha Yang 2022-11-06 01:53:46 +09:00
parent a51d492445
commit 4b05736c63
8 changed files with 1542 additions and 6 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,36 @@
/* GStreamer
* Copyright (C) 2022 Seungha Yang <seungha@centricular.com>
*
* 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.
*/
#pragma once
#include <gst/gst.h>
#include "gstmfsourceobject.h"
G_BEGIN_DECLS
#define GST_TYPE_MF_CAPTURE_DSHOW (gst_mf_capture_dshow_get_type())
G_DECLARE_FINAL_TYPE (GstMFCaptureDShow, gst_mf_capture_dshow,
GST, MF_CAPTURE_DSHOW, GstMFSourceObject);
GstMFSourceObject * gst_mf_capture_dshow_new (GstMFSourceType type,
gint device_index,
const gchar * device_name,
const gchar * device_path);
G_END_DECLS

View file

@ -31,6 +31,7 @@
#if GST_MF_WINAPI_DESKTOP #if GST_MF_WINAPI_DESKTOP
#include "gstwin32devicewatcher.h" #include "gstwin32devicewatcher.h"
#include "gstmfcapturedshow.h"
#ifndef INITGUID #ifndef INITGUID
#include <initguid.h> #include <initguid.h>
@ -265,11 +266,11 @@ gst_mf_device_provider_finalize (GObject * object)
G_OBJECT_CLASS (gst_mf_device_provider_parent_class)->finalize (object); G_OBJECT_CLASS (gst_mf_device_provider_parent_class)->finalize (object);
} }
static GList * static void
gst_mf_device_provider_probe (GstDeviceProvider * provider) gst_mf_device_provider_probe_internal (GstDeviceProvider * provider,
gboolean try_dshow, GList ** list)
{ {
GstMFDeviceProvider *self = GST_MF_DEVICE_PROVIDER (provider); GstMFDeviceProvider *self = GST_MF_DEVICE_PROVIDER (provider);
GList *list = nullptr;
gint i; gint i;
for (i = 0;; i++) { for (i = 0;; i++) {
@ -280,8 +281,18 @@ gst_mf_device_provider_probe (GstDeviceProvider * provider)
gchar *device_name = nullptr; gchar *device_name = nullptr;
gchar *device_path = nullptr; gchar *device_path = nullptr;
#if GST_MF_WINAPI_DESKTOP
if (try_dshow) {
obj = gst_mf_capture_dshow_new (GST_MF_SOURCE_TYPE_VIDEO, i,
nullptr, nullptr);
} else {
obj = gst_mf_source_object_new (GST_MF_SOURCE_TYPE_VIDEO, obj = gst_mf_source_object_new (GST_MF_SOURCE_TYPE_VIDEO,
i, nullptr, nullptr, nullptr); i, nullptr, nullptr, nullptr);
}
#else
obj = gst_mf_source_object_new (GST_MF_SOURCE_TYPE_VIDEO,
i, nullptr, nullptr, nullptr);
#endif
if (!obj) if (!obj)
break; break;
@ -314,7 +325,7 @@ gst_mf_device_provider_probe (GstDeviceProvider * provider)
"display-name", device_name, "caps", caps, "display-name", device_name, "caps", caps,
"device-class", "Source/Video", "properties", props, nullptr); "device-class", "Source/Video", "properties", props, nullptr);
list = g_list_append (list, device); *list = g_list_append (*list, device);
next: next:
if (caps) if (caps)
@ -325,6 +336,17 @@ gst_mf_device_provider_probe (GstDeviceProvider * provider)
g_free (device_name); g_free (device_name);
gst_object_unref (obj); gst_object_unref (obj);
} }
}
static GList *
gst_mf_device_provider_probe (GstDeviceProvider * provider)
{
GList *list = nullptr;
gst_mf_device_provider_probe_internal (provider, FALSE, &list);
#if GST_MF_WINAPI_DESKTOP
gst_mf_device_provider_probe_internal (provider, TRUE, &list);
#endif
return list; return list;
} }

View file

@ -232,6 +232,21 @@ gst_mf_source_object_create (GstMFSourceObject * object, GstBuffer ** buffer)
return klass->create (object, buffer); return klass->create (object, buffer);
} }
GstFlowReturn
gst_mf_source_object_get_sample (GstMFSourceObject * object,
GstSample ** sample)
{
GstMFSourceObjectClass *klass;
g_return_val_if_fail (GST_IS_MF_SOURCE_OBJECT (object), GST_FLOW_ERROR);
g_return_val_if_fail (sample != nullptr, GST_FLOW_ERROR);
klass = GST_MF_SOURCE_OBJECT_GET_CLASS (object);
g_assert (klass->get_sample != nullptr);
return klass->get_sample (object, sample);
}
void void
gst_mf_source_object_set_flushing (GstMFSourceObject * object, gst_mf_source_object_set_flushing (GstMFSourceObject * object,
gboolean flushing) gboolean flushing)

View file

@ -72,6 +72,9 @@ struct _GstMFSourceObjectClass
GstFlowReturn (*create) (GstMFSourceObject * object, GstFlowReturn (*create) (GstMFSourceObject * object,
GstBuffer ** buffer); GstBuffer ** buffer);
GstFlowReturn (*get_sample) (GstMFSourceObject * object,
GstSample ** sample);
gboolean (*unlock) (GstMFSourceObject * object); gboolean (*unlock) (GstMFSourceObject * object);
gboolean (*unlock_stop) (GstMFSourceObject * object); gboolean (*unlock_stop) (GstMFSourceObject * object);
@ -96,6 +99,10 @@ GstFlowReturn gst_mf_source_object_fill (GstMFSourceObject * object,
GstFlowReturn gst_mf_source_object_create (GstMFSourceObject * object, GstFlowReturn gst_mf_source_object_create (GstMFSourceObject * object,
GstBuffer ** buffer); GstBuffer ** buffer);
/* DirectShow filter */
GstFlowReturn gst_mf_source_object_get_sample (GstMFSourceObject * object,
GstSample ** sample);
void gst_mf_source_object_set_flushing (GstMFSourceObject * object, void gst_mf_source_object_set_flushing (GstMFSourceObject * object,
gboolean flushing); gboolean flushing);

View file

@ -990,7 +990,7 @@ gst_mf_source_reader_new (GstMFSourceType type, gint device_index,
gst_object_ref_sink (self); gst_object_ref_sink (self);
if (!self->opened) { if (!self->opened) {
GST_WARNING_OBJECT (self, "Couldn't open device"); GST_DEBUG_OBJECT (self, "Couldn't open device");
gst_object_unref (self); gst_object_unref (self);
return nullptr; return nullptr;
} }

View file

@ -45,6 +45,10 @@
#include "gstmfsourceobject.h" #include "gstmfsourceobject.h"
#include <string.h> #include <string.h>
#if GST_MF_WINAPI_DESKTOP
#include "gstmfcapturedshow.h"
#endif
GST_DEBUG_CATEGORY (gst_mf_video_src_debug); GST_DEBUG_CATEGORY (gst_mf_video_src_debug);
#define GST_CAT_DEFAULT gst_mf_video_src_debug #define GST_CAT_DEFAULT gst_mf_video_src_debug
@ -76,6 +80,8 @@ struct _GstMFVideoSrc
guint64 n_frames; guint64 n_frames;
GstClockTime latency; GstClockTime latency;
gboolean use_dshow;
/* properties */ /* properties */
gchar *device_path; gchar *device_path;
gchar *device_name; gchar *device_name;
@ -268,6 +274,15 @@ gst_mf_video_src_start (GstBaseSrc * src)
self->n_frames = 0; self->n_frames = 0;
self->latency = 0; self->latency = 0;
self->use_dshow = FALSE;
if (!self->source) {
#if GST_MF_WINAPI_DESKTOP
self->use_dshow = TRUE;
self->source = gst_mf_capture_dshow_new (GST_MF_SOURCE_TYPE_VIDEO,
self->device_index, self->device_name, self->device_path);
#endif
}
if (!self->source) { if (!self->source) {
GST_ERROR_OBJECT (self, "Couldn't create capture object"); GST_ERROR_OBJECT (self, "Couldn't create capture object");
@ -415,6 +430,7 @@ gst_mf_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buffer)
GstMFVideoSrc *self = GST_MF_VIDEO_SRC (pushsrc); GstMFVideoSrc *self = GST_MF_VIDEO_SRC (pushsrc);
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
GstBuffer *buf = nullptr; GstBuffer *buf = nullptr;
GstSample *sample = nullptr;
GstClock *clock; GstClock *clock;
GstClockTime running_time = GST_CLOCK_TIME_NONE; GstClockTime running_time = GST_CLOCK_TIME_NONE;
GstClockTimeDiff diff; GstClockTimeDiff diff;
@ -429,7 +445,9 @@ gst_mf_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buffer)
self->started = TRUE; self->started = TRUE;
} }
if (GST_VIDEO_INFO_FORMAT (&self->info) != GST_VIDEO_FORMAT_ENCODED) { if (self->use_dshow) {
ret = gst_mf_source_object_get_sample (self->source, &sample);
} else if (GST_VIDEO_INFO_FORMAT (&self->info) != GST_VIDEO_FORMAT_ENCODED) {
ret = GST_BASE_SRC_CLASS (parent_class)->alloc (GST_BASE_SRC (self), 0, ret = GST_BASE_SRC_CLASS (parent_class)->alloc (GST_BASE_SRC (self), 0,
GST_VIDEO_INFO_SIZE (&self->info), &buf); GST_VIDEO_INFO_SIZE (&self->info), &buf);
@ -444,6 +462,23 @@ gst_mf_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buffer)
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK)
return ret; return ret;
/* DirectShow capture object will set caps if it's got updated */
if (sample) {
if (gst_sample_get_caps (sample)) {
if (!gst_base_src_negotiate (GST_BASE_SRC (self))) {
GST_ERROR_OBJECT (self, "Failed to negotiate with new caps");
gst_sample_unref (sample);
return GST_FLOW_NOT_NEGOTIATED;
} else {
GST_DEBUG_OBJECT (self, "Renegotiated");
}
}
buf = gst_sample_get_buffer (sample);
gst_buffer_ref (buf);
gst_sample_unref (sample);
}
GST_BUFFER_OFFSET (buf) = self->n_frames; GST_BUFFER_OFFSET (buf) = self->n_frames;
GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET (buf) + 1; GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET (buf) + 1;
self->n_frames++; self->n_frames++;

View file

@ -20,6 +20,7 @@ mf_sources = [
] ]
mf_desktop_sources = [ mf_desktop_sources = [
'gstmfcapturedshow.cpp',
'gstmfsourcereader.cpp', 'gstmfsourcereader.cpp',
'gstwin32devicewatcher.cpp', 'gstwin32devicewatcher.cpp',
] ]