mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 11:41:09 +00:00
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:
parent
a51d492445
commit
4b05736c63
8 changed files with 1542 additions and 6 deletions
File diff suppressed because it is too large
Load diff
|
@ -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
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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++;
|
||||||
|
|
|
@ -20,6 +20,7 @@ mf_sources = [
|
||||||
]
|
]
|
||||||
|
|
||||||
mf_desktop_sources = [
|
mf_desktop_sources = [
|
||||||
|
'gstmfcapturedshow.cpp',
|
||||||
'gstmfsourcereader.cpp',
|
'gstmfsourcereader.cpp',
|
||||||
'gstwin32devicewatcher.cpp',
|
'gstwin32devicewatcher.cpp',
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in a new issue