v4l2object: scale the encoded sizeimage based on maximum resolution

The default 2MB ENCODED_BUFFER_SIZE can't support some 4K video playback. We now
detect the driver reported maximum resolution and choose an appropriate
default bitstream size accordingly. For 4K video these results in around 4MB
buffer instead of 2MB.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4549>
This commit is contained in:
Shengqi Yu 2023-05-05 17:01:50 +08:00 committed by GStreamer Marge Bot
parent 2bbc2a4c52
commit 25c00b5ba2
2 changed files with 46 additions and 5 deletions

View file

@ -53,7 +53,7 @@ GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
#define DEFAULT_PROP_TV_NORM 0 #define DEFAULT_PROP_TV_NORM 0
#define DEFAULT_PROP_IO_MODE GST_V4L2_IO_AUTO #define DEFAULT_PROP_IO_MODE GST_V4L2_IO_AUTO
#define ENCODED_BUFFER_SIZE (2 * 1024 * 1024) #define ENCODED_BUFFER_MIN_SIZE (256 * 1024)
#define GST_V4L2_DEFAULT_WIDTH 320 #define GST_V4L2_DEFAULT_WIDTH 320
#define GST_V4L2_DEFAULT_HEIGHT 240 #define GST_V4L2_DEFAULT_HEIGHT 240
@ -2994,6 +2994,8 @@ gst_v4l2_object_probe_caps_for_format (GstV4l2Object * v4l2object,
goto enum_framesizes_failed; goto enum_framesizes_failed;
if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
guint32 maxw = 0, maxh = 0;
do { do {
GST_LOG_OBJECT (v4l2object->dbg_obj, "got discrete frame size %dx%d", GST_LOG_OBJECT (v4l2object->dbg_obj, "got discrete frame size %dx%d",
size.discrete.width, size.discrete.height); size.discrete.width, size.discrete.height);
@ -3010,8 +3012,16 @@ gst_v4l2_object_probe_caps_for_format (GstV4l2Object * v4l2object,
results = g_list_prepend (results, tmp); results = g_list_prepend (results, tmp);
} }
if (w > maxw && h > maxh) {
maxw = w;
maxh = h;
}
size.index++; size.index++;
} while (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0); } while (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0);
v4l2object->max_width = maxw;
v4l2object->max_height = maxh;
GST_DEBUG_OBJECT (v4l2object->dbg_obj, GST_DEBUG_OBJECT (v4l2object->dbg_obj,
"done iterating discrete frame sizes"); "done iterating discrete frame sizes");
} else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE) { } else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
@ -3057,6 +3067,9 @@ gst_v4l2_object_probe_caps_for_format (GstV4l2Object * v4l2object,
/* no point using the results list here, since there's only one struct */ /* no point using the results list here, since there's only one struct */
gst_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp); gst_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
v4l2object->max_width = maxw;
v4l2object->max_height = maxh;
} }
} else if (size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { } else if (size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
guint32 maxw, maxh; guint32 maxw, maxh;
@ -3086,6 +3099,9 @@ gst_v4l2_object_probe_caps_for_format (GstV4l2Object * v4l2object,
/* no point using the results list here, since there's only one struct */ /* no point using the results list here, since there's only one struct */
gst_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp); gst_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
v4l2object->max_width = maxw;
v4l2object->max_height = maxh;
} }
} else { } else {
goto unknown_type; goto unknown_type;
@ -3717,6 +3733,19 @@ field_to_str (enum v4l2_field f)
return "unknown"; return "unknown";
} }
static guint
calculate_max_sizeimage (GstV4l2Object * v4l2object, guint pixel_bitdepth)
{
guint max_width, max_height;
guint sizeimage;
max_width = v4l2object->max_width;
max_height = v4l2object->max_height;
sizeimage = max_width * max_height * pixel_bitdepth / 8 / 2;
return MAX (ENCODED_BUFFER_MIN_SIZE, sizeimage);
}
static gboolean static gboolean
gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
gboolean try_only, GstV4l2Error * error) gboolean try_only, GstV4l2Error * error)
@ -3730,6 +3759,7 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
GstVideoInfo info; GstVideoInfo info;
GstVideoAlignment align; GstVideoAlignment align;
gint width, height, fps_n, fps_d; gint width, height, fps_n, fps_d;
guint pixel_bitdepth = 8;
gint n_v4l_planes; gint n_v4l_planes;
gint i = 0; gint i = 0;
gboolean is_mplane; gboolean is_mplane;
@ -3928,6 +3958,14 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
"%" GST_FOURCC_FORMAT " stride: %d", width, height, "%" GST_FOURCC_FORMAT " stride: %d", width, height,
GST_FOURCC_ARGS (pixelformat), GST_VIDEO_INFO_PLANE_STRIDE (&info, 0)); GST_FOURCC_ARGS (pixelformat), GST_VIDEO_INFO_PLANE_STRIDE (&info, 0));
s = gst_caps_get_structure (caps, 0);
if (gst_structure_has_field (s, "bit-depth-chroma")) {
gst_structure_get_uint (s, "bit-depth-chroma", &pixel_bitdepth);
GST_DEBUG_OBJECT (v4l2object->element, "Got pixel bit depth %u from caps",
pixel_bitdepth);
}
memset (&format, 0x00, sizeof (struct v4l2_format)); memset (&format, 0x00, sizeof (struct v4l2_format));
format.type = v4l2object->type; format.type = v4l2object->type;
@ -3952,7 +3990,8 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
} }
if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED) if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED)
format.fmt.pix_mp.plane_fmt[0].sizeimage = ENCODED_BUFFER_SIZE; format.fmt.pix_mp.plane_fmt[0].sizeimage =
calculate_max_sizeimage (v4l2object, pixel_bitdepth);
} else { } else {
gint stride = GST_VIDEO_INFO_PLANE_STRIDE (&info, 0); gint stride = GST_VIDEO_INFO_PLANE_STRIDE (&info, 0);
@ -3971,7 +4010,8 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
format.fmt.pix.bytesperline = stride; format.fmt.pix.bytesperline = stride;
if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED) if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED)
format.fmt.pix.sizeimage = ENCODED_BUFFER_SIZE; format.fmt.pix.sizeimage =
calculate_max_sizeimage (v4l2object, pixel_bitdepth);
} }
GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired format is %dx%d, format " GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Desired format is %dx%d, format "
@ -4164,8 +4204,6 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
goto invalid_planes; goto invalid_planes;
/* used to check colorimetry and interlace mode fields presence */ /* used to check colorimetry and interlace mode fields presence */
s = gst_caps_get_structure (caps, 0);
if (gst_v4l2_object_get_interlace_mode (format.fmt.pix.field, if (gst_v4l2_object_get_interlace_mode (format.fmt.pix.field,
&info.interlace_mode)) { &info.interlace_mode)) {
if (gst_structure_has_field (s, "interlace-mode")) { if (gst_structure_has_field (s, "interlace-mode")) {

View file

@ -228,6 +228,9 @@ struct _GstV4l2Object {
* on slow USB firmwares. When this is set, gst_v4l2_set_format() will modify * on slow USB firmwares. When this is set, gst_v4l2_set_format() will modify
* the caps to reflect what was negotiated during fixation */ * the caps to reflect what was negotiated during fixation */
gboolean skip_try_fmt_probes; gboolean skip_try_fmt_probes;
guint max_width;
guint max_height;
}; };
struct _GstV4l2ObjectClassHelper { struct _GstV4l2ObjectClassHelper {