mfvideosrc: Expose sorted caps

Sort the list of supported caps for downstream to be able to select
the best image in terms of quality (resolution and framerate) by default.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1452>
This commit is contained in:
Seungha Yang 2020-07-21 16:52:33 +09:00
parent c3ecea0aa4
commit 6c52008413
4 changed files with 109 additions and 20 deletions

View file

@ -27,6 +27,7 @@
#include "mediacapturewrapper.h"
#include <memorybuffer.h>
#include <memory>
#include <algorithm>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
@ -161,6 +162,13 @@ gst_mf_capture_winrt_main_loop_running_cb (GstMFCaptureWinRT * self)
return G_SOURCE_REMOVE;
}
static bool
winrt_compare_caps_func (const GstWinRTMediaDescription & a,
const GstWinRTMediaDescription & b)
{
return gst_mf_source_object_caps_compare (a.caps_, b.caps_) < 0;
}
static gpointer
gst_mf_capture_winrt_thread_func (GstMFCaptureWinRT * self)
{
@ -232,30 +240,33 @@ gst_mf_capture_winrt_thread_func (GstMFCaptureWinRT * self)
goto run_loop;
}
if (target_group->source_list_.empty ()) {
GST_WARNING_OBJECT (self, "No available source list");
goto run_loop;
}
self->capture->SetSourceGroup(*target_group);
for (auto iter: target_group->source_list_) {
if (!self->supported_caps)
self->supported_caps = gst_caps_ref (iter.caps_);
else
self->supported_caps =
gst_caps_merge (self->supported_caps, gst_caps_ref (iter.caps_));
}
std::sort (target_group->source_list_.begin (),
target_group->source_list_.end (), winrt_compare_caps_func);
self->supported_caps = gst_caps_new_empty ();
for (auto iter: target_group->source_list_)
gst_caps_append (self->supported_caps, gst_caps_copy (iter.caps_));
GST_DEBUG_OBJECT (self, "Available output caps %" GST_PTR_FORMAT,
self->supported_caps);
source->opened = !!self->supported_caps;
source->opened = TRUE;
if (source->opened) {
g_free (source->device_path);
source->device_path = g_strdup (target_group->id_.c_str());
g_free (source->device_path);
source->device_path = g_strdup (target_group->id_.c_str());
g_free (source->device_name);
source->device_name = g_strdup (target_group->display_name_.c_str());
g_free (source->device_name);
source->device_name = g_strdup (target_group->display_name_.c_str());
source->device_index = index;
}
source->device_index = index;
run_loop:
GST_DEBUG_OBJECT (self, "Starting main loop");

View file

@ -338,3 +338,64 @@ gst_mf_source_object_new (GstMFSourceType type, gint device_index,
return NULL;
}
gint
gst_mf_source_object_caps_compare (GstCaps * caps1, GstCaps * caps2)
{
GstStructure *s1, *s2;
const gchar *n1, *n2;
gboolean m1_is_raw, m2_is_raw;
gint w1 = 0, h1 = 0, w2 = 0, h2 = 0;
gint r1, r2;
gint num1 = 0, den1 = 1, num2 = 0, den2 = 1;
gint fraction_cmp;
/* sorting priority
* - raw video > comprssed
* - raw video format
* - higher resolution
* - higher framerate
*/
s1 = gst_caps_get_structure (caps1, 0);
n1 = gst_structure_get_name (s1);
s2 = gst_caps_get_structure (caps2, 0);
n2 = gst_structure_get_name (s2);
m1_is_raw = g_strcmp0 (n1, "video/x-raw") == 0;
m2_is_raw = g_strcmp0 (n2, "video/x-raw") == 0;
if (m1_is_raw && !m2_is_raw)
return -1;
else if (!m1_is_raw && m2_is_raw)
return 1;
/* if both are raw formats */
if (m1_is_raw) {
gint format_cmp = g_strcmp0 (gst_structure_get_string (s1, "format"),
gst_structure_get_string (s2, "format"));
if (format_cmp)
return format_cmp;
}
/* resolution */
gst_structure_get_int (s1, "width", &w1);
gst_structure_get_int (s1, "height", &h1);
gst_structure_get_int (s2, "width", &w2);
gst_structure_get_int (s2, "height", &h2);
r1 = w1 * h1;
r2 = w2 * h2;
/* higher resolution first */
if (r1 != r2)
return r2 - r1;
gst_structure_get_fraction (s1, "framerate", &num1, &den1);
gst_structure_get_fraction (s2, "framerate", &num2, &den2);
fraction_cmp = gst_util_fraction_compare (num1, den1, num2, den2);
/* higher framerate first */
return fraction_cmp * -1;
}

View file

@ -108,6 +108,10 @@ GstMFSourceObject * gst_mf_source_object_new (GstMFSourceType type,
const gchar * device_name,
const gchar * device_path);
/* Utility methods */
gint gst_mf_source_object_caps_compare (GstCaps * caps1,
GstCaps * caps2);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstMFSourceObject, gst_object_unref)
G_END_DECLS

View file

@ -244,6 +244,17 @@ gst_mf_stream_media_type_free (GstMFStreamMediaType * media_type)
g_free (media_type);
}
static gint
compare_caps_func (gconstpointer a, gconstpointer b)
{
GstMFStreamMediaType *m1, *m2;
m1 = (GstMFStreamMediaType *) a;
m2 = (GstMFStreamMediaType *) b;
return gst_mf_source_object_caps_compare (m1->caps, m2->caps);
}
static gboolean
gst_mf_source_reader_open (GstMFSourceReader * self, IMFActivate * activate)
{
@ -280,13 +291,15 @@ gst_mf_source_reader_open (GstMFSourceReader * self, IMFActivate * activate)
self->source = source.Detach ();
self->reader = reader.Detach ();
self->media_types = g_list_sort (self->media_types,
(GCompareFunc) compare_caps_func);
self->supported_caps = gst_caps_new_empty ();
for (iter = self->media_types; iter; iter = g_list_next (iter)) {
GstMFStreamMediaType *mtype = (GstMFStreamMediaType *) iter->data;
if (!self->supported_caps)
self->supported_caps = gst_caps_ref (mtype->caps);
else
self->supported_caps =
gst_caps_merge (self->supported_caps, gst_caps_ref (mtype->caps));
gst_caps_append (self->supported_caps, gst_caps_copy (mtype->caps));
}
GST_DEBUG_OBJECT (self, "Available output caps %" GST_PTR_FORMAT,