[libcamera-devel] [PATCH] gstreamer: Fix usage of default size for fixation

Kieran Bingham kieran.bingham at ideasonboard.com
Thu Aug 26 15:48:30 CEST 2021


One more catch ...

On 26/08/2021 14:44, Kieran Bingham wrote:
> On 25/08/2021 16:07, Nicolas Dufresne wrote:
>> From: Nicolas Dufresne <nicolas.dufresne at collabora.com>
>>
>> Even thought this is not formaly documented, all pipeline managers sets a
> 
> s/thought/though/
> 
> s/formaly/formally/
> 
>> default value to StreamConfiguration::size. The original fixation code was
> 
> This is documented at by the function Camera::generateConfiguration()
> 
> https://libcamera.org/api-html/classlibcamera_1_1Camera.html#a25c80eb7fc9b1cf32692ce0c7f09991d
> 
> I suspect the real issue (of documentation) is that - we have lots of
> documentation, but it's hard to find the parts that are needed at the
> time they are needed.
> 
> 
>> attempting to use it, but as it was truncating the caps to its first structure
>> it would never actually find a best match.
>>
>> In this patch, instead of truncating, we weight various matches using the
>> product of the width and height delta. We also split delta from ranges
>> appart and prefer fixed size over them as ranges are not reliable.
> 
> s/appart/apart/
> 
> 
>> This patch also removes the related todo, as it seems that libcamera core won't
>> go further then providing this default value and won't be sorting the format and
>> size lists.
> 
> The formats and sizes might be sorted numerically ... but there's no
> indication of preference there indeed. They don't even really mean that
> the frame size is supported by the device (though the pixel format is a
> bit more indicative).
> 
> 
> Maybe the Sizes and Formats shouldn't be used at all by gstreamer, it
> might be that they are providing information which is seen as more
> expressive than it really is, and gstreamer should do it's own
> try/validate negotiation phase to determine the possibilities.
> 
> 
> 
>> Signed-off-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
>> ---
>>  src/gstreamer/gstlibcamera-utils.cpp | 51 +++++++++++++++++++++++++---
>>  src/gstreamer/gstlibcamerasrc.cpp    |  4 ---
>>  2 files changed, 47 insertions(+), 8 deletions(-)
>>
>> diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp
>> index 61370d5f..007d6a64 100644
>> --- a/src/gstreamer/gstlibcamera-utils.cpp
>> +++ b/src/gstreamer/gstlibcamera-utils.cpp
>> @@ -136,14 +136,57 @@ gst_libcamera_configure_stream_from_caps(StreamConfiguration &stream_cfg,
>>  					 GstCaps *caps)
>>  {
>>  	GstVideoFormat gst_format = pixel_format_to_gst_format(stream_cfg.pixelFormat);
>> +	guint i;
>> +	gint best_fixed = -1, best_in_range = -1;
>> +	GstStructure *s;
>> +
>> +	/*
>> +	 * These are delta weight computed from:
>> +	 *   ABS(width - stream_cfg.size.width) * ABS(height - stream_cfg.size.height)
>> +	 */
>> +	guint best_fixed_delta = G_MAXUINT;
>> +	guint best_in_range_delta = G_MAXUINT;
>>  
>>  	/* First fixate the caps using default configuration value. */
>>  	g_assert(gst_caps_is_writable(caps));
>> -	caps = gst_caps_truncate(caps);
>> -	GstStructure *s = gst_caps_get_structure(caps, 0);
>>  
>> -	gst_structure_fixate_field_nearest_int(s, "width", stream_cfg.size.width);
>> -	gst_structure_fixate_field_nearest_int(s, "height", stream_cfg.size.height);
>> +	/* Lookup the structure for a close match to the stream_cfg.size */
> 
> I'm worried that this is placing too much weight on the caps which have
> been generated from the StreamFormats.
> 
> https://libcamera.org/api-html/classlibcamera_1_1StreamFormats.html
> states:
> 
>> All sizes retrieved from StreamFormats shall be treated as advisory
>> and no size shall be considered to be supported until it has been 
>> verified using CameraConfiguration::validate().
> 
> If a role has been passed to the generateConfiguration() [0], then the
> Streams (and therefore their StreamConfiguration) are provided as
> suggested default configurations (which should have already been run
> through validation).
> 
> 
> [0]
> https://libcamera.org/api-html/classlibcamera_1_1Camera.html#a25c80eb7fc9b1cf32692ce0c7f09991d
> 
> 
> However, having discussed this with you last night, I think the code
> here is correct, as it matches against the caps of the whole pipeline,
> but we might want to have a validation phase either during
> gst_libcamera_stream_formats_to_caps() or after it to further
> filter/restrict what is actually added as supported formats.
> 
> I've already seen that this is reporting formats to the caps, that are
> not actually available on the IPU3, and so its' failing to correctly
> configure the pipeline as expected.
> 
> But I think that's a separate issue on top... Or I wonder if we could
> handle that better at the libcamera layer ...
> 
> 
>> +	for (i = 0; i < gst_caps_get_size(caps); i++) {
>> +		s = gst_caps_get_structure(caps, i);
>> +		gint width, height;
>> +		guint delta;
>> +
>> +		if (gst_structure_has_field_typed(s, "width", G_TYPE_INT) &&
>> +		    gst_structure_has_field_typed(s, "height", G_TYPE_INT)) {
>> +			gst_structure_get_int(s, "width", &width);
>> +			gst_structure_get_int(s, "width", &height);
> 
> s/width/height/ here, looks like your setting width * width.
> 
> In fact, that might explain one of the bugs I hit with this...
> 
> The IPU3 was ending up using an odd default size which was possible
> based on the best match of 720x720 now I see this ...
> 
> (I'll test again later).
> 
> 
> Anyway, with s/width/height/ fixed above here:
> 
> Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
> 
> 
> 
>> +
>> +			delta = ABS(width - (gint)stream_cfg.size.width) * ABS(height - (gint)stream_cfg.size.height);
>> +
>> +			if (delta < best_fixed_delta) {
>> +				best_fixed_delta = delta;
>> +				best_fixed = i;
>> +			}
>> +		} else {
>> +			gst_structure_fixate_field_nearest_int(s, "width", stream_cfg.size.width);
>> +			gst_structure_fixate_field_nearest_int(s, "height", stream_cfg.size.height);
>> +			gst_structure_get_int(s, "width", &width);
>> +			gst_structure_get_int(s, "width", &height);
>> +

And s/width/height/ here also.


With those two fixed, I now get:


gst-launch-1.0 libcamerasrc ! queue ! glimagesink
...
 INFO Camera camera.cpp:937 configuring streams: (0) 1280x720-NV12

on the IPU3.
and

gst-launch-1.0 libcamerasrc ! queue ! glimagesink
...
 INFO Camera camera.cpp:937 configuring streams: (0) 1920x1080-NV12

on my Brio.

Tested-by: Kieran Bingham <kieran.bingham at ideasonboard.com>



>> +			delta = ABS(width - (gint)stream_cfg.size.width) * ABS(height - (gint)stream_cfg.size.height);
>> +
>> +			if (delta < best_in_range_delta) {
>> +				best_in_range_delta = delta;
>> +				best_in_range = i;
>> +			}
>> +		}
>> +	}
>> +
>> +	/* Prefer reliable fixed value over ranges */
>> +	if (best_fixed >= 0)
>> +		s = gst_caps_get_structure(caps, best_fixed);
>> +	else
>> +		s = gst_caps_get_structure(caps, best_in_range);
>>  
>>  	if (gst_structure_has_name(s, "video/x-raw")) {
>>  		const gchar *format = gst_video_format_to_string(gst_format);
>> diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp
>> index b243aeb3..4c7b36ae 100644
>> --- a/src/gstreamer/gstlibcamerasrc.cpp
>> +++ b/src/gstreamer/gstlibcamerasrc.cpp
>> @@ -25,10 +25,6 @@
>>   *  - Add timestamp support
>>   *  - Use unique names to select the camera devices
>>   *  - Add GstVideoMeta support (strides and offsets)
>> - *
>> - * \todo libcamera UVC drivers picks the lowest possible resolution first, this
>> - * should be fixed so that we get a decent resolution and framerate for the
>> - * role by default.
>>   */
>>  
>>  #include "gstlibcamerasrc.h"
>>

-- 
Regards
--
Kieran


More information about the libcamera-devel mailing list