mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	v4l2: Improve format and control enumeration
Use dynamic pod builder so that we can also build complex formats. Make sure we zero the format before we parse it or else we end up with potentially uninitialized values. When ENUM_FRAMESIZES or VIDIOC_ENUM_FRAMEINTERVALS return EINVAL for the first index, make a dummy result and continue with that. This will trigger an intersect withe filter so that we end up with something valid instead of nothing. Handle 0 framerates without crashing. See #4063
This commit is contained in:
		
							parent
							
								
									bc9eb76a6e
								
							
						
					
					
						commit
						7114e9a31a
					
				
					 2 changed files with 100 additions and 57 deletions
				
			
		| 
						 | 
				
			
			@ -236,7 +236,8 @@ static int impl_node_enum_params(void *object, int seq,
 | 
			
		|||
{
 | 
			
		||||
	struct impl *this = object;
 | 
			
		||||
	struct spa_pod *param;
 | 
			
		||||
	struct spa_pod_builder b = { 0 };
 | 
			
		||||
	spa_auto(spa_pod_dynamic_builder) b = { 0 };
 | 
			
		||||
	struct spa_pod_builder_state state;
 | 
			
		||||
	uint8_t buffer[1024];
 | 
			
		||||
	struct spa_result_node_params result;
 | 
			
		||||
	uint32_t count = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -245,12 +246,15 @@ static int impl_node_enum_params(void *object, int seq,
 | 
			
		|||
	spa_return_val_if_fail(this != NULL, -EINVAL);
 | 
			
		||||
	spa_return_val_if_fail(num != 0, -EINVAL);
 | 
			
		||||
 | 
			
		||||
	spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
 | 
			
		||||
	spa_pod_builder_get_state(&b.b, &state);
 | 
			
		||||
 | 
			
		||||
	result.id = id;
 | 
			
		||||
	result.next = start;
 | 
			
		||||
      next:
 | 
			
		||||
	result.index = result.next++;
 | 
			
		||||
 | 
			
		||||
	spa_pod_builder_init(&b, buffer, sizeof(buffer));
 | 
			
		||||
	spa_pod_builder_reset(&b.b, &state);
 | 
			
		||||
 | 
			
		||||
	switch (id) {
 | 
			
		||||
	case SPA_PARAM_PropInfo:
 | 
			
		||||
| 
						 | 
				
			
			@ -259,21 +263,21 @@ static int impl_node_enum_params(void *object, int seq,
 | 
			
		|||
 | 
			
		||||
		switch (result.index) {
 | 
			
		||||
		case 0:
 | 
			
		||||
			param = spa_pod_builder_add_object(&b,
 | 
			
		||||
			param = spa_pod_builder_add_object(&b.b,
 | 
			
		||||
				SPA_TYPE_OBJECT_PropInfo, id,
 | 
			
		||||
				SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_device),
 | 
			
		||||
				SPA_PROP_INFO_description, SPA_POD_String("The V4L2 device"),
 | 
			
		||||
				SPA_PROP_INFO_type, SPA_POD_String(p->device));
 | 
			
		||||
			break;
 | 
			
		||||
		case 1:
 | 
			
		||||
			param = spa_pod_builder_add_object(&b,
 | 
			
		||||
			param = spa_pod_builder_add_object(&b.b,
 | 
			
		||||
				SPA_TYPE_OBJECT_PropInfo, id,
 | 
			
		||||
				SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_deviceName),
 | 
			
		||||
				SPA_PROP_INFO_description, SPA_POD_String("The V4L2 device name"),
 | 
			
		||||
				SPA_PROP_INFO_type, SPA_POD_String(p->device_name));
 | 
			
		||||
			break;
 | 
			
		||||
		case 2:
 | 
			
		||||
			param = spa_pod_builder_add_object(&b,
 | 
			
		||||
			param = spa_pod_builder_add_object(&b.b,
 | 
			
		||||
				SPA_TYPE_OBJECT_PropInfo, id,
 | 
			
		||||
				SPA_PROP_INFO_id,   SPA_POD_Id(SPA_PROP_deviceFd),
 | 
			
		||||
				SPA_PROP_INFO_description, SPA_POD_String("The V4L2 fd"),
 | 
			
		||||
| 
						 | 
				
			
			@ -298,8 +302,8 @@ static int impl_node_enum_params(void *object, int seq,
 | 
			
		|||
 | 
			
		||||
		switch (result.index) {
 | 
			
		||||
		case 0:
 | 
			
		||||
			spa_pod_builder_push_object(&b, &f, SPA_TYPE_OBJECT_Props, id);
 | 
			
		||||
			spa_pod_builder_add(&b,
 | 
			
		||||
			spa_pod_builder_push_object(&b.b, &f, SPA_TYPE_OBJECT_Props, id);
 | 
			
		||||
			spa_pod_builder_add(&b.b,
 | 
			
		||||
				SPA_PROP_device,     SPA_POD_String(p->device),
 | 
			
		||||
				SPA_PROP_deviceName, SPA_POD_String(p->device_name),
 | 
			
		||||
				SPA_PROP_deviceFd,   SPA_POD_Int(p->device_fd),
 | 
			
		||||
| 
						 | 
				
			
			@ -307,20 +311,20 @@ static int impl_node_enum_params(void *object, int seq,
 | 
			
		|||
			for (i = 0; i < port->n_controls; i++) {
 | 
			
		||||
				struct control *c = &port->controls[i];
 | 
			
		||||
 | 
			
		||||
				spa_pod_builder_prop(&b, c->id, 0);
 | 
			
		||||
				spa_pod_builder_prop(&b.b, c->id, 0);
 | 
			
		||||
				switch (c->type) {
 | 
			
		||||
				case SPA_TYPE_Int:
 | 
			
		||||
					spa_pod_builder_int(&b, c->value);
 | 
			
		||||
					spa_pod_builder_int(&b.b, c->value);
 | 
			
		||||
					break;
 | 
			
		||||
				case SPA_TYPE_Bool:
 | 
			
		||||
					spa_pod_builder_bool(&b, c->value);
 | 
			
		||||
					spa_pod_builder_bool(&b.b, c->value);
 | 
			
		||||
					break;
 | 
			
		||||
				default:
 | 
			
		||||
					spa_pod_builder_int(&b, c->value);
 | 
			
		||||
					spa_pod_builder_int(&b.b, c->value);
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			param = spa_pod_builder_pop(&b, &f);
 | 
			
		||||
			param = spa_pod_builder_pop(&b.b, &f);
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -331,14 +335,14 @@ static int impl_node_enum_params(void *object, int seq,
 | 
			
		|||
		return spa_v4l2_enum_format(this, seq, start, num, filter);
 | 
			
		||||
	case SPA_PARAM_Format:
 | 
			
		||||
		if((res = port_get_format(GET_OUT_PORT(this, 0),
 | 
			
		||||
						result.index, filter, ¶m, &b)) <= 0)
 | 
			
		||||
						result.index, filter, ¶m, &b.b)) <= 0)
 | 
			
		||||
			return res;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return -ENOENT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (spa_pod_filter(&b, &result.param, param, filter) < 0)
 | 
			
		||||
	if (spa_pod_filter(&b.b, &result.param, param, filter) < 0)
 | 
			
		||||
		goto next;
 | 
			
		||||
 | 
			
		||||
	spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
 | 
			
		||||
| 
						 | 
				
			
			@ -528,7 +532,8 @@ static int impl_node_port_enum_params(void *object, int seq,
 | 
			
		|||
	struct impl *this = object;
 | 
			
		||||
	struct port *port;
 | 
			
		||||
	struct spa_pod *param;
 | 
			
		||||
	struct spa_pod_builder b = { 0 };
 | 
			
		||||
	spa_auto(spa_pod_dynamic_builder) b = { 0 };
 | 
			
		||||
	struct spa_pod_builder_state state;
 | 
			
		||||
	uint8_t buffer[1024];
 | 
			
		||||
	struct spa_result_node_params result;
 | 
			
		||||
	uint32_t count = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -538,6 +543,9 @@ static int impl_node_port_enum_params(void *object, int seq,
 | 
			
		|||
	spa_return_val_if_fail(num != 0, -EINVAL);
 | 
			
		||||
	spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
 | 
			
		||||
 | 
			
		||||
	spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
 | 
			
		||||
	spa_pod_builder_get_state(&b.b, &state);
 | 
			
		||||
 | 
			
		||||
	port = GET_PORT(this, direction, port_id);
 | 
			
		||||
 | 
			
		||||
	result.id = id;
 | 
			
		||||
| 
						 | 
				
			
			@ -545,7 +553,7 @@ static int impl_node_port_enum_params(void *object, int seq,
 | 
			
		|||
     next:
 | 
			
		||||
	result.index = result.next++;
 | 
			
		||||
 | 
			
		||||
	spa_pod_builder_init(&b, buffer, sizeof(buffer));
 | 
			
		||||
	spa_pod_builder_reset(&b.b, &state);
 | 
			
		||||
 | 
			
		||||
	switch (id) {
 | 
			
		||||
	case SPA_PARAM_PropInfo:
 | 
			
		||||
| 
						 | 
				
			
			@ -555,7 +563,7 @@ static int impl_node_port_enum_params(void *object, int seq,
 | 
			
		|||
		return spa_v4l2_enum_format(this, seq, start, num, filter);
 | 
			
		||||
 | 
			
		||||
	case SPA_PARAM_Format:
 | 
			
		||||
		if((res = port_get_format(port, result.index, filter, ¶m, &b)) <= 0)
 | 
			
		||||
		if((res = port_get_format(port, result.index, filter, ¶m, &b.b)) <= 0)
 | 
			
		||||
			return res;
 | 
			
		||||
		break;
 | 
			
		||||
	case SPA_PARAM_Buffers:
 | 
			
		||||
| 
						 | 
				
			
			@ -564,7 +572,7 @@ static int impl_node_port_enum_params(void *object, int seq,
 | 
			
		|||
		if (result.index > 0)
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
		param = spa_pod_builder_add_object(&b,
 | 
			
		||||
		param = spa_pod_builder_add_object(&b.b,
 | 
			
		||||
			SPA_TYPE_OBJECT_ParamBuffers, id,
 | 
			
		||||
			SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(4, 1, MAX_BUFFERS),
 | 
			
		||||
			SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(1),
 | 
			
		||||
| 
						 | 
				
			
			@ -575,7 +583,7 @@ static int impl_node_port_enum_params(void *object, int seq,
 | 
			
		|||
	case SPA_PARAM_Meta:
 | 
			
		||||
		switch (result.index) {
 | 
			
		||||
		case 0:
 | 
			
		||||
			param = spa_pod_builder_add_object(&b,
 | 
			
		||||
			param = spa_pod_builder_add_object(&b.b,
 | 
			
		||||
				SPA_TYPE_OBJECT_ParamMeta, id,
 | 
			
		||||
				SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header),
 | 
			
		||||
				SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header)));
 | 
			
		||||
| 
						 | 
				
			
			@ -587,19 +595,19 @@ static int impl_node_port_enum_params(void *object, int seq,
 | 
			
		|||
	case SPA_PARAM_IO:
 | 
			
		||||
		switch (result.index) {
 | 
			
		||||
		case 0:
 | 
			
		||||
			param = spa_pod_builder_add_object(&b,
 | 
			
		||||
			param = spa_pod_builder_add_object(&b.b,
 | 
			
		||||
				SPA_TYPE_OBJECT_ParamIO, id,
 | 
			
		||||
				SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_Buffers),
 | 
			
		||||
				SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_buffers)));
 | 
			
		||||
			break;
 | 
			
		||||
		case 1:
 | 
			
		||||
			param = spa_pod_builder_add_object(&b,
 | 
			
		||||
			param = spa_pod_builder_add_object(&b.b,
 | 
			
		||||
				SPA_TYPE_OBJECT_ParamIO, id,
 | 
			
		||||
				SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_Clock),
 | 
			
		||||
				SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_clock)));
 | 
			
		||||
			break;
 | 
			
		||||
		case 2:
 | 
			
		||||
			param = spa_pod_builder_add_object(&b,
 | 
			
		||||
			param = spa_pod_builder_add_object(&b.b,
 | 
			
		||||
				SPA_TYPE_OBJECT_ParamIO, id,
 | 
			
		||||
				SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_Control),
 | 
			
		||||
				SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_sequence)));
 | 
			
		||||
| 
						 | 
				
			
			@ -611,7 +619,7 @@ static int impl_node_port_enum_params(void *object, int seq,
 | 
			
		|||
	case SPA_PARAM_Latency:
 | 
			
		||||
		switch (result.index) {
 | 
			
		||||
		case 0: case 1:
 | 
			
		||||
			param = spa_latency_build(&b, id, &this->latency[result.index]);
 | 
			
		||||
			param = spa_latency_build(&b.b, id, &this->latency[result.index]);
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -621,7 +629,7 @@ static int impl_node_port_enum_params(void *object, int seq,
 | 
			
		|||
		return -ENOENT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (spa_pod_filter(&b, &result.param, param, filter) < 0)
 | 
			
		||||
	if (spa_pod_filter(&b.b, &result.param, param, filter) < 0)
 | 
			
		||||
		goto next;
 | 
			
		||||
 | 
			
		||||
	spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
 | 
			
		||||
| 
						 | 
				
			
			@ -639,6 +647,8 @@ static int port_set_format(struct impl *this, struct port *port,
 | 
			
		|||
	struct spa_video_info info;
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
	spa_zero(info);
 | 
			
		||||
 | 
			
		||||
	if (port->have_format) {
 | 
			
		||||
		spa_v4l2_stream_off(this);
 | 
			
		||||
		spa_v4l2_clear_buffers(this);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue