mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 16:50:47 +00:00
dshowvideosrc: can use other video sizes and framerates than the defaults
Even if the device could capture several video sizes at several framerates, without this commit, it was only possible to use one video size and one framerate: the default directshow values.
This commit is contained in:
parent
4aea6354e0
commit
0a7c30f6c1
2 changed files with 172 additions and 25 deletions
|
@ -1,5 +1,6 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net>
|
||||
* Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
|
||||
*
|
||||
* gstdshowvideosrc.c:
|
||||
*
|
||||
|
@ -104,6 +105,7 @@ static gboolean gst_dshowvideosrc_unlock (GstBaseSrc * bsrc);
|
|||
static gboolean gst_dshowvideosrc_unlock_stop (GstBaseSrc * bsrc);
|
||||
static gboolean gst_dshowvideosrc_set_caps (GstBaseSrc * bsrc, GstCaps * caps);
|
||||
static GstCaps *gst_dshowvideosrc_get_caps (GstBaseSrc * bsrc);
|
||||
static void gst_dshowvideosrc_src_fixate (GstBaseSrc * bsrc, GstCaps * caps);
|
||||
static GstFlowReturn gst_dshowvideosrc_create (GstPushSrc * psrc,
|
||||
GstBuffer ** buf);
|
||||
|
||||
|
@ -170,6 +172,7 @@ gst_dshowvideosrc_class_init (GstDshowVideoSrcClass * klass)
|
|||
|
||||
gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_dshowvideosrc_get_caps);
|
||||
gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_dshowvideosrc_set_caps);
|
||||
gstbasesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_dshowvideosrc_src_fixate);
|
||||
gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_dshowvideosrc_start);
|
||||
gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_dshowvideosrc_stop);
|
||||
gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_dshowvideosrc_unlock);
|
||||
|
@ -205,6 +208,7 @@ gst_dshowvideosrc_init (GstDshowVideoSrc * src, GstDshowVideoSrcClass * klass)
|
|||
src->media_filter = NULL;
|
||||
src->filter_graph = NULL;
|
||||
src->caps = NULL;
|
||||
src->video_defaults = NULL;
|
||||
src->pins_mediatypes = NULL;
|
||||
src->is_rgb = FALSE;
|
||||
|
||||
|
@ -218,6 +222,36 @@ gst_dshowvideosrc_init (GstDshowVideoSrc * src, GstDshowVideoSrcClass * klass)
|
|||
gst_base_src_set_live (GST_BASE_SRC (src), TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_dshowvideosrc_src_fixate (GstBaseSrc * bsrc, GstCaps * caps)
|
||||
{
|
||||
/* If there is no desired video size, set default video size to device preffered video size */
|
||||
|
||||
GstDshowVideoSrc *src = GST_DSHOWVIDEOSRC (bsrc);
|
||||
GstStructure *structure = gst_caps_get_structure (caps, 0);
|
||||
guint i = 0;
|
||||
gint res = -1;
|
||||
|
||||
for (; i < gst_caps_get_size (src->caps) && res == -1; i++) {
|
||||
GstCaps *capstmp = gst_caps_copy_nth (src->caps, i);
|
||||
|
||||
if (gst_caps_is_subset (caps, capstmp)) {
|
||||
res = i;
|
||||
}
|
||||
gst_caps_unref (capstmp);
|
||||
}
|
||||
|
||||
if (res != -1) {
|
||||
GList *type_video_default = g_list_nth (src->video_defaults, res);
|
||||
if (type_video_default) {
|
||||
GstCaptureVideoDefault *video_default = (GstCaptureVideoDefault *) type_video_default->data;
|
||||
gst_structure_fixate_field_nearest_int (structure, "width", video_default->defaultWidth);
|
||||
gst_structure_fixate_field_nearest_int (structure, "height", video_default->defaultHeight);
|
||||
gst_structure_fixate_field_nearest_fraction (structure, "framerate", video_default->defaultFPS, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_dshowvideosrc_dispose (GObject * gobject)
|
||||
{
|
||||
|
@ -238,6 +272,11 @@ gst_dshowvideosrc_dispose (GObject * gobject)
|
|||
src->caps = NULL;
|
||||
}
|
||||
|
||||
if (src->video_defaults) {
|
||||
g_list_free (src->video_defaults);
|
||||
src->video_defaults = NULL;
|
||||
}
|
||||
|
||||
if (src->pins_mediatypes) {
|
||||
gst_dshow_free_pins_mediatypes (src->pins_mediatypes);
|
||||
src->pins_mediatypes = NULL;
|
||||
|
@ -292,7 +331,6 @@ gst_dshowvideosrc_probe_probe_property (GstPropertyProbe * probe,
|
|||
|
||||
switch (prop_id) {
|
||||
case PROP_DEVICE_NAME:
|
||||
//gst_v4l_class_probe_devices (klass, FALSE);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
|
||||
|
@ -556,7 +594,6 @@ static GstStateChangeReturn
|
|||
gst_dshowvideosrc_change_state (GstElement * element, GstStateChange transition)
|
||||
{
|
||||
HRESULT hres = S_FALSE;
|
||||
IAMVfwCaptureDialogs *dialog = NULL;
|
||||
GstDshowVideoSrc *src = GST_DSHOWVIDEOSRC (element);
|
||||
|
||||
switch (transition) {
|
||||
|
@ -675,13 +712,51 @@ gst_dshowvideosrc_set_caps (GstBaseSrc * bsrc, GstCaps * caps)
|
|||
|
||||
if (res != -1 && src->pins_mediatypes) {
|
||||
/* get the corresponding media type and build the dshow graph */
|
||||
GstCapturePinMediaType *pin_mediatype = NULL;
|
||||
gchar *caps_string = NULL;
|
||||
GList *type = g_list_nth (src->pins_mediatypes, res);
|
||||
|
||||
if (type) {
|
||||
//will be removed when GST_TYPE_INT_RANGE_STEP exits
|
||||
GList *type_video_default = g_list_nth (src->video_defaults, res);
|
||||
|
||||
if (type && type_video_default) {
|
||||
//will be removed when GST_TYPE_INT_RANGE_STEP exits
|
||||
GstCaptureVideoDefault *video_default = (GstCaptureVideoDefault *) type_video_default->data;
|
||||
GstCapturePinMediaType *pin_mediatype = NULL;
|
||||
gchar *caps_string = NULL;
|
||||
gchar *src_caps_string = NULL;
|
||||
|
||||
/* retrieve the desired video size */
|
||||
VIDEOINFOHEADER *video_info = NULL;
|
||||
gint width = 0;
|
||||
gint height = 0;
|
||||
gint numerator = 0;
|
||||
gint denominator = 0;
|
||||
gst_structure_get_int (s, "width", &width);
|
||||
gst_structure_get_int (s, "height", &height);
|
||||
gst_structure_get_fraction (s, "framerate", &numerator, &denominator);
|
||||
|
||||
/* check if the desired video size is valid about granularity */
|
||||
/* This check will be removed when GST_TYPE_INT_RANGE_STEP exits */
|
||||
/* See remarks in gst_dshowvideosrc_getcaps_from_streamcaps function */
|
||||
if (video_default->granularityWidth != 0 && width % video_default->granularityWidth != 0)
|
||||
g_warning ("your desired video size is not valid : %d mod %d !=0\n", width, video_default->granularityWidth) ;
|
||||
if (video_default->granularityHeight !=0 && height % video_default->granularityHeight != 0)
|
||||
g_warning ("your desired video size is not valid : %d mod %d !=0\n", height, video_default->granularityHeight) ;
|
||||
|
||||
/* display all capabilities when using --gst-debug-level=3 */
|
||||
src_caps_string = gst_caps_to_string (src->caps);
|
||||
GST_CAT_LEVEL_LOG (dshowvideosrc_debug, GST_LEVEL_INFO, src, src_caps_string);
|
||||
g_free (src_caps_string);
|
||||
|
||||
pin_mediatype = (GstCapturePinMediaType *) type->data;
|
||||
|
||||
/* update mediatype */
|
||||
video_info = (VIDEOINFOHEADER *) pin_mediatype->mediatype->pbFormat;
|
||||
video_info->bmiHeader.biWidth = width;
|
||||
video_info->bmiHeader.biHeight = height;
|
||||
video_info->AvgTimePerFrame = (LONGLONG) (10000000 * denominator / (double)numerator);
|
||||
video_info->bmiHeader.biSizeImage = DIBSIZE(video_info->bmiHeader);
|
||||
pin_mediatype->mediatype->lSampleSize = DIBSIZE(video_info->bmiHeader);
|
||||
|
||||
src->dshow_fakesink->gst_set_media_type (pin_mediatype->mediatype);
|
||||
src->dshow_fakesink->gst_set_buffer_callback(
|
||||
(push_buffer_func) gst_dshowvideosrc_push_buffer, src);
|
||||
|
@ -695,7 +770,7 @@ gst_dshowvideosrc_set_caps (GstBaseSrc * bsrc, GstCaps * caps)
|
|||
}
|
||||
|
||||
hres = src->filter_graph->ConnectDirect(pin_mediatype->capture_pin,
|
||||
input_pin, NULL);
|
||||
input_pin, pin_mediatype->mediatype);
|
||||
input_pin->Release();
|
||||
|
||||
if (hres != S_OK) {
|
||||
|
@ -845,6 +920,7 @@ gst_dshowvideosrc_getcaps_from_streamcaps (GstDshowVideoSrc * src, IPin * pin,
|
|||
|
||||
for (; i < icount; i++) {
|
||||
GstCapturePinMediaType *pin_mediatype = g_new0 (GstCapturePinMediaType, 1);
|
||||
GstCaptureVideoDefault *video_default = g_new0 (GstCaptureVideoDefault, 1);
|
||||
|
||||
pin->AddRef();
|
||||
pin_mediatype->capture_pin = pin;
|
||||
|
@ -857,6 +933,17 @@ gst_dshowvideosrc_getcaps_from_streamcaps (GstDshowVideoSrc * src, IPin * pin,
|
|||
if (!caps)
|
||||
caps = gst_caps_new_empty ();
|
||||
|
||||
/* some remarks: */
|
||||
/* Hope GST_TYPE_INT_RANGE_STEP will exits in future gstreamer releases */
|
||||
/* because we could use : */
|
||||
/* "width", GST_TYPE_INT_RANGE_STEP, video_default->minWidth, video_default->maxWidth, video_default->granularityWidth */
|
||||
/* instead of : */
|
||||
/* "width", GST_TYPE_INT_RANGE, video_default->minWidth, video_default->maxWidth */
|
||||
|
||||
/* For framerate we do not need a step (granularity) because */
|
||||
/* "The IAMStreamConfig::SetFormat method will set the frame rate to the closest */
|
||||
/* value that the filter supports" as it said in the VIDEO_STREAM_CONFIG_CAPS dshwo doc */
|
||||
|
||||
/* I420 */
|
||||
if ((UuidCompare (&pin_mediatype->mediatype->subtype, (UUID *) &MEDIASUBTYPE_I420,
|
||||
&rpcstatus) == 0 && rpcstatus == RPC_S_OK)
|
||||
|
@ -865,19 +952,29 @@ gst_dshowvideosrc_getcaps_from_streamcaps (GstDshowVideoSrc * src, IPin * pin,
|
|||
&& rpcstatus == RPC_S_OK)) {
|
||||
video_info = (VIDEOINFOHEADER *) pin_mediatype->mediatype->pbFormat;
|
||||
|
||||
video_default->defaultWidth = video_info->bmiHeader.biWidth;
|
||||
video_default->defaultHeight = video_info->bmiHeader.biHeight;
|
||||
video_default->defaultFPS = (int) (10000000 / video_info->AvgTimePerFrame);
|
||||
video_default->granularityWidth = vscc.OutputGranularityX;
|
||||
video_default->granularityHeight = vscc.OutputGranularityY;
|
||||
|
||||
mediacaps = gst_caps_new_simple ("video/x-raw-yuv",
|
||||
"width", G_TYPE_INT, video_info->bmiHeader.biWidth,
|
||||
"height", G_TYPE_INT, video_info->bmiHeader.biHeight,
|
||||
"framerate", GST_TYPE_FRACTION,
|
||||
(int) (10000000 / video_info->AvgTimePerFrame), 1, "format",
|
||||
GST_TYPE_FOURCC, MAKEFOURCC ('I', '4', '2', '0'), NULL);
|
||||
"width", GST_TYPE_INT_RANGE, vscc.MinOutputSize.cx, vscc.MaxOutputSize.cx,
|
||||
"height", GST_TYPE_INT_RANGE, vscc.MinOutputSize.cy, vscc.MaxOutputSize.cy,
|
||||
"framerate", GST_TYPE_FRACTION_RANGE,
|
||||
(int) (10000000 / vscc.MaxFrameInterval), 1,
|
||||
(int) (10000000 / vscc.MinFrameInterval), 1,
|
||||
"format", GST_TYPE_FOURCC, MAKEFOURCC ('I', '4', '2', '0'), NULL);
|
||||
|
||||
if (mediacaps) {
|
||||
src->pins_mediatypes =
|
||||
g_list_append (src->pins_mediatypes, pin_mediatype);
|
||||
src->video_defaults =
|
||||
g_list_append (src->video_defaults, video_default);
|
||||
gst_caps_append (caps, mediacaps);
|
||||
} else {
|
||||
gst_dshow_free_pin_mediatype (pin_mediatype);
|
||||
g_free (video_default);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -890,23 +987,35 @@ gst_dshowvideosrc_getcaps_from_streamcaps (GstDshowVideoSrc * src, IPin * pin,
|
|||
&& rpcstatus == RPC_S_OK)) {
|
||||
video_info = (VIDEOINFOHEADER *) pin_mediatype->mediatype->pbFormat;
|
||||
|
||||
video_default->defaultWidth = video_info->bmiHeader.biWidth;
|
||||
video_default->defaultHeight = video_info->bmiHeader.biHeight;
|
||||
video_default->defaultFPS = (int) (10000000 / video_info->AvgTimePerFrame);
|
||||
video_default->granularityWidth = vscc.OutputGranularityX;
|
||||
video_default->granularityHeight = vscc.OutputGranularityY;
|
||||
|
||||
/* ffmpegcolorspace handles RGB24 in BIG_ENDIAN */
|
||||
mediacaps = gst_caps_new_simple ("video/x-raw-rgb",
|
||||
"bpp", G_TYPE_INT, 24,
|
||||
"depth", G_TYPE_INT, 24,
|
||||
"width", G_TYPE_INT, video_info->bmiHeader.biWidth,
|
||||
"height", G_TYPE_INT, video_info->bmiHeader.biHeight,
|
||||
"framerate", GST_TYPE_FRACTION,
|
||||
(int) (10000000 / video_info->AvgTimePerFrame), 1, "endianness",
|
||||
G_TYPE_INT, G_BIG_ENDIAN, "red_mask", G_TYPE_INT, 255, "green_mask",
|
||||
G_TYPE_INT, 65280, "blue_mask", G_TYPE_INT, 16711680, NULL);
|
||||
"bpp", G_TYPE_INT, 24,
|
||||
"depth", G_TYPE_INT, 24,
|
||||
"width", GST_TYPE_INT_RANGE, vscc.MinOutputSize.cx, vscc.MaxOutputSize.cx,
|
||||
"height", GST_TYPE_INT_RANGE, vscc.MinOutputSize.cy, vscc.MaxOutputSize.cy,
|
||||
"framerate", GST_TYPE_FRACTION_RANGE,
|
||||
(int) (10000000 / vscc.MaxFrameInterval), 1,
|
||||
(int) (10000000 / vscc.MinFrameInterval), 1,
|
||||
"endianness", G_TYPE_INT, G_BIG_ENDIAN,
|
||||
"red_mask", G_TYPE_INT, 255,
|
||||
"green_mask", G_TYPE_INT, 65280,
|
||||
"blue_mask", G_TYPE_INT, 16711680, NULL);
|
||||
|
||||
if (mediacaps) {
|
||||
src->pins_mediatypes =
|
||||
g_list_append (src->pins_mediatypes, pin_mediatype);
|
||||
src->video_defaults =
|
||||
g_list_append (src->video_defaults, video_default);
|
||||
gst_caps_append (caps, mediacaps);
|
||||
} else {
|
||||
gst_dshow_free_pin_mediatype (pin_mediatype);
|
||||
g_free (video_default);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -919,20 +1028,30 @@ gst_dshowvideosrc_getcaps_from_streamcaps (GstDshowVideoSrc * src, IPin * pin,
|
|||
&& rpcstatus == RPC_S_OK)) {
|
||||
video_info = (VIDEOINFOHEADER *) pin_mediatype->mediatype->pbFormat;
|
||||
|
||||
video_default->defaultWidth = video_info->bmiHeader.biWidth;
|
||||
video_default->defaultHeight = video_info->bmiHeader.biHeight;
|
||||
video_default->defaultFPS = (int) (10000000 / video_info->AvgTimePerFrame);
|
||||
video_default->granularityWidth = vscc.OutputGranularityX;
|
||||
video_default->granularityHeight = vscc.OutputGranularityY;
|
||||
|
||||
mediacaps = gst_caps_new_simple ("video/x-dv",
|
||||
"systemstream", G_TYPE_BOOLEAN, FALSE,
|
||||
"format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('d', 'v', 's', 'd'),
|
||||
"framerate", GST_TYPE_FRACTION,
|
||||
(int) (10000000 / video_info->AvgTimePerFrame), 1, "width",
|
||||
G_TYPE_INT, video_info->bmiHeader.biWidth, "height", G_TYPE_INT,
|
||||
video_info->bmiHeader.biHeight, NULL);
|
||||
"systemstream", G_TYPE_BOOLEAN, FALSE,
|
||||
"format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('d', 'v', 's', 'd'),
|
||||
"framerate", GST_TYPE_FRACTION_RANGE,
|
||||
(int) (10000000 / vscc.MaxFrameInterval), 1,
|
||||
(int) (10000000 / vscc.MinFrameInterval), 1,
|
||||
"width", GST_TYPE_INT_RANGE, vscc.MinOutputSize.cx, vscc.MaxOutputSize.cx,
|
||||
"height", GST_TYPE_INT_RANGE, vscc.MinOutputSize.cy, vscc.MaxOutputSize.cy, NULL);
|
||||
|
||||
if (mediacaps) {
|
||||
src->pins_mediatypes =
|
||||
g_list_append (src->pins_mediatypes, pin_mediatype);
|
||||
src->video_defaults =
|
||||
g_list_append (src->video_defaults, video_default);
|
||||
gst_caps_append (caps, mediacaps);
|
||||
} else {
|
||||
gst_dshow_free_pin_mediatype (pin_mediatype);
|
||||
g_free (video_default);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -943,20 +1062,33 @@ gst_dshowvideosrc_getcaps_from_streamcaps (GstDshowVideoSrc * src, IPin * pin,
|
|||
&& (UuidCompare (&pin_mediatype->mediatype->formattype,
|
||||
(UUID *) &FORMAT_DvInfo, &rpcstatus) == 0 && rpcstatus == RPC_S_OK)) {
|
||||
|
||||
video_info = (VIDEOINFOHEADER *) pin_mediatype->mediatype->pbFormat;
|
||||
|
||||
//No video size in caps when stream ? I do know if the following fields exist
|
||||
video_default->defaultWidth = video_info->bmiHeader.biWidth;
|
||||
video_default->defaultHeight = video_info->bmiHeader.biHeight;
|
||||
video_default->defaultFPS = (int) (10000000 / video_info->AvgTimePerFrame);
|
||||
video_default->granularityWidth = vscc.OutputGranularityX;
|
||||
video_default->granularityHeight = vscc.OutputGranularityY;
|
||||
|
||||
mediacaps = gst_caps_new_simple ("video/x-dv",
|
||||
"systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
|
||||
|
||||
if (mediacaps) {
|
||||
src->pins_mediatypes =
|
||||
g_list_append (src->pins_mediatypes, pin_mediatype);
|
||||
src->video_defaults =
|
||||
g_list_append (src->video_defaults, video_default);
|
||||
gst_caps_append (caps, mediacaps);
|
||||
} else {
|
||||
gst_dshow_free_pin_mediatype (pin_mediatype);
|
||||
g_free (video_default);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
gst_dshow_free_pin_mediatype (pin_mediatype);
|
||||
g_free (video_default);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,18 @@ G_BEGIN_DECLS
|
|||
typedef struct _GstDshowVideoSrc GstDshowVideoSrc;
|
||||
typedef struct _GstDshowVideoSrcClass GstDshowVideoSrcClass;
|
||||
|
||||
/* video default properties associated to a video format (YUY2, I420, RGB24 ...) */
|
||||
typedef struct _GstCaptureVideoDefault
|
||||
{
|
||||
gint defaultWidth;
|
||||
gint defaultHeight;
|
||||
gint defaultFPS;
|
||||
|
||||
gint granularityWidth; //will be removed when GST_TYPE_INT_RANGE_STEP exits
|
||||
gint granularityHeight; //will be removed when GST_TYPE_INT_RANGE_STEP exits
|
||||
|
||||
} GstCaptureVideoDefault;
|
||||
|
||||
struct _GstDshowVideoSrc
|
||||
{
|
||||
GstPushSrc src;
|
||||
|
@ -55,6 +67,9 @@ struct _GstDshowVideoSrc
|
|||
/* list of caps created from the list of supported media types of the dshow capture filter */
|
||||
GstCaps *caps;
|
||||
|
||||
/* list of dshow default video properties from filter's capture pins */
|
||||
GList *video_defaults;
|
||||
|
||||
/* list of dshow media types from the filter's capture pins */
|
||||
GList *pins_mediatypes;
|
||||
|
||||
|
|
Loading…
Reference in a new issue