mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	spa: libcamera: source: process requests on data loop
Since `impl::requestComplete()` runs in an internal libcamera thread, extra care
would need to be taken to validate all accesses to common data structures. For
example, the function might call `spa_libcamera_buffer_recycle()`, which accesses
`impl::ctrls`, which would be unsafe because it could read or modified at the same
time on the data thread. So move the processing of requests to the data loop.
(cherry picked from commit 019a5c130f)
			
			
This commit is contained in:
		
							parent
							
								
									3ca1e20b3d
								
							
						
					
					
						commit
						8ed8f21100
					
				
					 1 changed files with 62 additions and 59 deletions
				
			
		| 
						 | 
				
			
			@ -1020,6 +1020,63 @@ void handle_completed_request(struct impl *impl, libcamera::Request *request)
 | 
			
		|||
			impl, request, request_id, static_cast<unsigned int>(request->status()),
 | 
			
		||||
			request->sequence());
 | 
			
		||||
 | 
			
		||||
	if (request->status() == libcamera::Request::Status::RequestCancelled) {
 | 
			
		||||
		spa_log_trace(impl->log, "%p: request %p[%" PRIu64 "] cancelled",
 | 
			
		||||
				impl, request, request_id);
 | 
			
		||||
		request->reuse(libcamera::Request::ReuseFlag::ReuseBuffers);
 | 
			
		||||
		SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUTSTANDING);
 | 
			
		||||
		spa_libcamera_buffer_recycle(impl, port, b->id);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const FrameBuffer *buffer = request->findBuffer(port->streamConfig.stream());
 | 
			
		||||
	if (buffer == nullptr) {
 | 
			
		||||
		spa_log_warn(impl->log, "%p: request %p[%" PRIu64 "] has no buffer for stream %p",
 | 
			
		||||
				impl, request, request_id, port->streamConfig.stream());
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const FrameMetadata &fmd = buffer->metadata();
 | 
			
		||||
 | 
			
		||||
	if (impl->clock) {
 | 
			
		||||
		double target = (double)port->info.rate.num / port->info.rate.denom;
 | 
			
		||||
		double corr;
 | 
			
		||||
 | 
			
		||||
		if (impl->dll.bw == 0.0) {
 | 
			
		||||
			spa_dll_set_bw(&impl->dll, SPA_DLL_BW_MAX, port->info.rate.denom, port->info.rate.denom);
 | 
			
		||||
			impl->clock->next_nsec = fmd.timestamp;
 | 
			
		||||
			corr = 1.0;
 | 
			
		||||
		} else {
 | 
			
		||||
			double diff = ((double)impl->clock->next_nsec - (double)fmd.timestamp) / SPA_NSEC_PER_SEC;
 | 
			
		||||
			double error = port->info.rate.denom * (diff - target);
 | 
			
		||||
			corr = spa_dll_update(&impl->dll, SPA_CLAMPD(error, -128., 128.));
 | 
			
		||||
		}
 | 
			
		||||
		/* FIXME, we should follow the driver clock and target_ values.
 | 
			
		||||
		 * for now we ignore and use our own. */
 | 
			
		||||
		impl->clock->target_rate = port->rate;
 | 
			
		||||
		impl->clock->target_duration = 1;
 | 
			
		||||
 | 
			
		||||
		impl->clock->nsec = fmd.timestamp;
 | 
			
		||||
		impl->clock->rate = port->rate;
 | 
			
		||||
		impl->clock->position = fmd.sequence;
 | 
			
		||||
		impl->clock->duration = 1;
 | 
			
		||||
		impl->clock->delay = 0;
 | 
			
		||||
		impl->clock->rate_diff = corr;
 | 
			
		||||
		impl->clock->next_nsec += (uint64_t) (target * SPA_NSEC_PER_SEC * corr);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (b->h) {
 | 
			
		||||
		b->h->flags = 0;
 | 
			
		||||
		if (fmd.status != libcamera::FrameMetadata::Status::FrameSuccess)
 | 
			
		||||
			b->h->flags |= SPA_META_HEADER_FLAG_CORRUPTED;
 | 
			
		||||
		b->h->offset = 0;
 | 
			
		||||
		b->h->seq = fmd.sequence;
 | 
			
		||||
		b->h->pts = fmd.timestamp;
 | 
			
		||||
		b->h->dts_offset = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	request->reuse(libcamera::Request::ReuseFlag::ReuseBuffers);
 | 
			
		||||
 | 
			
		||||
	spa_list_append(&port->queue, &b->link);
 | 
			
		||||
 | 
			
		||||
	spa_io_buffers *io = port->io;
 | 
			
		||||
| 
						 | 
				
			
			@ -1231,66 +1288,12 @@ spa_libcamera_alloc_buffers(struct impl *impl, struct port *port,
 | 
			
		|||
void impl::requestComplete(libcamera::Request *request)
 | 
			
		||||
{
 | 
			
		||||
	struct impl *impl = this;
 | 
			
		||||
	struct port *port = &impl->out_ports[0];
 | 
			
		||||
	Stream *stream = port->streamConfig.stream();
 | 
			
		||||
	uint32_t index, buffer_id;
 | 
			
		||||
	struct buffer *b;
 | 
			
		||||
	uint32_t index;
 | 
			
		||||
 | 
			
		||||
	spa_log_debug(impl->log, "request complete");
 | 
			
		||||
 | 
			
		||||
	buffer_id = request->cookie();
 | 
			
		||||
	b = &port->buffers[buffer_id];
 | 
			
		||||
 | 
			
		||||
	if ((request->status() == Request::RequestCancelled)) {
 | 
			
		||||
		spa_log_debug(impl->log, "Request was cancelled");
 | 
			
		||||
		request->reuse(libcamera::Request::ReuseFlag::ReuseBuffers);
 | 
			
		||||
		SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUTSTANDING);
 | 
			
		||||
		spa_libcamera_buffer_recycle(impl, port, b->id);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	FrameBuffer *buffer = request->findBuffer(stream);
 | 
			
		||||
	if (buffer == nullptr) {
 | 
			
		||||
		spa_log_warn(impl->log, "unknown buffer");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	const FrameMetadata &fmd = buffer->metadata();
 | 
			
		||||
 | 
			
		||||
	if (impl->clock) {
 | 
			
		||||
		double target = (double)port->info.rate.num / port->info.rate.denom;
 | 
			
		||||
		double corr;
 | 
			
		||||
 | 
			
		||||
		if (impl->dll.bw == 0.0) {
 | 
			
		||||
			spa_dll_set_bw(&impl->dll, SPA_DLL_BW_MAX, port->info.rate.denom, port->info.rate.denom);
 | 
			
		||||
			impl->clock->next_nsec = fmd.timestamp;
 | 
			
		||||
			corr = 1.0;
 | 
			
		||||
		} else {
 | 
			
		||||
			double diff = ((double)impl->clock->next_nsec - (double)fmd.timestamp) / SPA_NSEC_PER_SEC;
 | 
			
		||||
			double error = port->info.rate.denom * (diff - target);
 | 
			
		||||
			corr = spa_dll_update(&impl->dll, SPA_CLAMPD(error, -128., 128.));
 | 
			
		||||
		}
 | 
			
		||||
		/* FIXME, we should follow the driver clock and target_ values.
 | 
			
		||||
		 * for now we ignore and use our own. */
 | 
			
		||||
		impl->clock->target_rate = port->rate;
 | 
			
		||||
		impl->clock->target_duration = 1;
 | 
			
		||||
 | 
			
		||||
		impl->clock->nsec = fmd.timestamp;
 | 
			
		||||
		impl->clock->rate = port->rate;
 | 
			
		||||
		impl->clock->position = fmd.sequence;
 | 
			
		||||
		impl->clock->duration = 1;
 | 
			
		||||
		impl->clock->delay = 0;
 | 
			
		||||
		impl->clock->rate_diff = corr;
 | 
			
		||||
		impl->clock->next_nsec += (uint64_t) (target * SPA_NSEC_PER_SEC * corr);
 | 
			
		||||
	}
 | 
			
		||||
	if (b->h) {
 | 
			
		||||
		b->h->flags = 0;
 | 
			
		||||
		if (fmd.status != FrameMetadata::Status::FrameSuccess)
 | 
			
		||||
			b->h->flags |= SPA_META_HEADER_FLAG_CORRUPTED;
 | 
			
		||||
		b->h->offset = 0;
 | 
			
		||||
		b->h->seq = fmd.sequence;
 | 
			
		||||
		b->h->pts = fmd.timestamp;
 | 
			
		||||
		b->h->dts_offset = 0;
 | 
			
		||||
	}
 | 
			
		||||
	request->reuse(libcamera::Request::ReuseFlag::ReuseBuffers);
 | 
			
		||||
	spa_log_trace(impl->log, "%p: request %p[%" PRIu64 "] completed status:%u seq:%" PRIu32,
 | 
			
		||||
			impl, request, request->cookie(),
 | 
			
		||||
			static_cast<unsigned int>(request->status()),
 | 
			
		||||
			request->sequence());
 | 
			
		||||
 | 
			
		||||
	spa_ringbuffer_get_write_index(&impl->completed_requests_rb, &index);
 | 
			
		||||
	impl->completed_requests[index & MASK_BUFFERS] = request;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue