mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	pipewire-v4l2: More improvements
Keep separate map for fd to files so we can implement dup. Filter out duplicates in enumfmt. tryfmt should return the closest match. Use pthread_once to init the global state. Make things mostly work in GStreamer.
This commit is contained in:
		
							parent
							
								
									8175c8276d
								
							
						
					
					
						commit
						3ee852b808
					
				
					 3 changed files with 388 additions and 265 deletions
				
			
		| 
						 | 
					@ -62,11 +62,16 @@ struct file_map {
 | 
				
			||||||
	struct file *file;
 | 
						struct file *file;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct fd_map {
 | 
				
			||||||
 | 
						int fd;
 | 
				
			||||||
 | 
						struct file *file;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct globals {
 | 
					struct globals {
 | 
				
			||||||
	struct fops old_fops;
 | 
						struct fops old_fops;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pthread_mutex_t lock;
 | 
						pthread_mutex_t lock;
 | 
				
			||||||
	struct spa_list files;
 | 
						struct pw_array fd_maps;
 | 
				
			||||||
	struct pw_array file_maps;
 | 
						struct pw_array file_maps;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,7 +91,6 @@ struct buffer {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct file {
 | 
					struct file {
 | 
				
			||||||
	struct spa_list link;
 | 
					 | 
				
			||||||
	int ref;
 | 
						int ref;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_properties *props;
 | 
						struct pw_properties *props;
 | 
				
			||||||
| 
						 | 
					@ -110,7 +114,6 @@ struct file {
 | 
				
			||||||
	struct pw_stream *stream;
 | 
						struct pw_stream *stream;
 | 
				
			||||||
	struct spa_hook stream_listener;
 | 
						struct spa_hook stream_listener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct spa_video_info format;
 | 
					 | 
				
			||||||
	struct v4l2_format v4l2_format;
 | 
						struct v4l2_format v4l2_format;
 | 
				
			||||||
	uint32_t reqbufs;
 | 
						uint32_t reqbufs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -120,6 +123,8 @@ struct file {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_array buffer_maps;
 | 
						struct pw_array buffer_maps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t last_fourcc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int running:1;
 | 
						unsigned int running:1;
 | 
				
			||||||
	int fd;
 | 
						int fd;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -242,39 +247,13 @@ static struct file *make_file(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	file->ref = 1;
 | 
						file->ref = 1;
 | 
				
			||||||
	file->fd = -1;
 | 
						file->fd = -1;
 | 
				
			||||||
	spa_list_init(&file->link);
 | 
					 | 
				
			||||||
	spa_list_init(&file->globals);
 | 
						spa_list_init(&file->globals);
 | 
				
			||||||
	pw_array_init(&file->buffer_maps, sizeof(struct buffer_map) * MAX_BUFFERS);
 | 
						pw_array_init(&file->buffer_maps, sizeof(struct buffer_map) * MAX_BUFFERS);
 | 
				
			||||||
	return file;
 | 
						return file;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void put_file(struct file *file)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	pthread_mutex_lock(&globals.lock);
 | 
					 | 
				
			||||||
	spa_list_append(&globals.files, &file->link);
 | 
					 | 
				
			||||||
	pthread_mutex_unlock(&globals.lock);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct file *find_file(int fd)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct file *f, *res = NULL;
 | 
					 | 
				
			||||||
	pthread_mutex_lock(&globals.lock);
 | 
					 | 
				
			||||||
	spa_list_for_each(f, &globals.files, link)
 | 
					 | 
				
			||||||
		if (f->fd == fd) {
 | 
					 | 
				
			||||||
			res = f;
 | 
					 | 
				
			||||||
			ATOMIC_INC(f->ref);
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	pthread_mutex_unlock(&globals.lock);
 | 
					 | 
				
			||||||
	return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void free_file(struct file *file)
 | 
					static void free_file(struct file *file)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	pthread_mutex_lock(&globals.lock);
 | 
					 | 
				
			||||||
	spa_list_remove(&file->link);
 | 
					 | 
				
			||||||
	pthread_mutex_unlock(&globals.lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (file->loop)
 | 
						if (file->loop)
 | 
				
			||||||
		pw_thread_loop_stop(file->loop);
 | 
							pw_thread_loop_stop(file->loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -307,28 +286,76 @@ static void unref_file(struct file *file)
 | 
				
			||||||
		free_file(file);
 | 
							free_file(file);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int add_file_map(struct file *file, void *addr)
 | 
					static int add_fd_map(int fd, struct file *file)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct fd_map *map;
 | 
				
			||||||
 | 
						pthread_mutex_lock(&globals.lock);
 | 
				
			||||||
 | 
						map = pw_array_add(&globals.fd_maps, sizeof(*map));
 | 
				
			||||||
 | 
						if (map != NULL) {
 | 
				
			||||||
 | 
							map->fd = fd;
 | 
				
			||||||
 | 
							map->file = file;
 | 
				
			||||||
 | 
							file->ref++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&globals.lock);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static struct fd_map *find_fd_map(int fd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct fd_map *map, *res = NULL;
 | 
				
			||||||
 | 
						pthread_mutex_lock(&globals.lock);
 | 
				
			||||||
 | 
						pw_array_for_each(map, &globals.fd_maps) {
 | 
				
			||||||
 | 
							if (map->fd == fd) {
 | 
				
			||||||
 | 
								ATOMIC_INC(map->file->ref);
 | 
				
			||||||
 | 
								res =  map;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&globals.lock);
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct file *find_file(int fd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct fd_map *map = find_fd_map(fd);
 | 
				
			||||||
 | 
						if (map == NULL)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						return map->file;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void remove_fd_map(struct fd_map *map)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct file *file = map->file;
 | 
				
			||||||
 | 
						pthread_mutex_lock(&globals.lock);
 | 
				
			||||||
 | 
						pw_array_remove(&globals.fd_maps, map);
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&globals.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unref_file(file);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int add_file_map(void *addr, struct file *file)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct file_map *map;
 | 
						struct file_map *map;
 | 
				
			||||||
	pthread_mutex_lock(&globals.lock);
 | 
						pthread_mutex_lock(&globals.lock);
 | 
				
			||||||
	map = pw_array_add(&globals.file_maps, sizeof(*map));
 | 
						map = pw_array_add(&globals.file_maps, sizeof(*map));
 | 
				
			||||||
	if (map != NULL) {
 | 
						if (map != NULL) {
 | 
				
			||||||
		map->file = file;
 | 
					 | 
				
			||||||
		map->addr = addr;
 | 
							map->addr = addr;
 | 
				
			||||||
 | 
							map->file = file;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	pthread_mutex_unlock(&globals.lock);
 | 
						pthread_mutex_unlock(&globals.lock);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
static struct file_map *find_file_map(void *addr)
 | 
					static struct file_map *find_file_map(void *addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct file_map *map;
 | 
						struct file_map *map, *res = NULL;
 | 
				
			||||||
	pthread_mutex_lock(&globals.lock);
 | 
						pthread_mutex_lock(&globals.lock);
 | 
				
			||||||
	pw_array_for_each(map, &globals.file_maps) {
 | 
						pw_array_for_each(map, &globals.file_maps) {
 | 
				
			||||||
		if (map->addr == addr)
 | 
							if (map->addr == addr) {
 | 
				
			||||||
			return map;
 | 
								res =  map;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	pthread_mutex_unlock(&globals.lock);
 | 
						pthread_mutex_unlock(&globals.lock);
 | 
				
			||||||
	return NULL;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
static void remove_file_map(struct file_map *map)
 | 
					static void remove_file_map(struct file_map *map)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -431,7 +458,7 @@ static void node_event_info(void *object, const struct pw_node_info *info)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	info = g->info = pw_node_info_merge(g->info, info, g->changed == 0);
 | 
						info = g->info = pw_node_info_merge(g->info, info, g->changed == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_info("update %d %"PRIu64, g->id, info->change_mask);
 | 
						pw_log_debug("update %d %"PRIu64, g->id, info->change_mask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (info->change_mask & PW_NODE_CHANGE_MASK_PROPS && info->props) {
 | 
						if (info->change_mask & PW_NODE_CHANGE_MASK_PROPS && info->props) {
 | 
				
			||||||
		if ((str = spa_dict_lookup(info->props, PW_KEY_DEVICE_ID)))
 | 
							if ((str = spa_dict_lookup(info->props, PW_KEY_DEVICE_ID)))
 | 
				
			||||||
| 
						 | 
					@ -465,7 +492,6 @@ static void node_event_info(void *object, const struct pw_node_info *info)
 | 
				
			||||||
			if (id != SPA_PARAM_EnumFormat)
 | 
								if (id != SPA_PARAM_EnumFormat)
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			add_param(&g->param_list, g->param_seq[id], g->param_seq, id, NULL);
 | 
					 | 
				
			||||||
			if (!(info->params[i].flags & SPA_PARAM_INFO_READ))
 | 
								if (!(info->params[i].flags & SPA_PARAM_INFO_READ))
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -484,7 +510,7 @@ static void node_event_param(void *object, int seq,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct global *g = object;
 | 
						struct global *g = object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_info("update param %d %d", g->id, id);
 | 
						pw_log_debug("update param %d %d %d %d", g->id, id, seq, g->param_seq[id]);
 | 
				
			||||||
	add_param(&g->param_list, seq, g->param_seq, id, param);
 | 
						add_param(&g->param_list, seq, g->param_seq, id, param);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -653,7 +679,7 @@ static int v4l2_openat(int dirfd, const char *path, int oflag, mode_t mode)
 | 
				
			||||||
	pw_log_info("path:%s oflag:%d mode:%d -> %d (%s)", path, oflag, mode,
 | 
						pw_log_info("path:%s oflag:%d mode:%d -> %d (%s)", path, oflag, mode,
 | 
				
			||||||
			res, strerror(res < 0 ? errno : 0));
 | 
								res, strerror(res < 0 ? errno : 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	put_file(file);
 | 
						add_fd_map(res, file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -670,15 +696,16 @@ static int v4l2_dup(int oldfd)
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
	struct file *file;
 | 
						struct file *file;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((file = find_file(oldfd)) == NULL)
 | 
					 | 
				
			||||||
		return globals.old_fops.dup(oldfd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	res = globals.old_fops.dup(oldfd);
 | 
						res = globals.old_fops.dup(oldfd);
 | 
				
			||||||
 | 
						if (res < 0)
 | 
				
			||||||
 | 
							return res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_info("fd:%d -> %d (%s)", oldfd,
 | 
						if ((file = find_file(oldfd)) != NULL) {
 | 
				
			||||||
			res, strerror(res < 0 ? errno : 0));
 | 
							add_fd_map(res, file);
 | 
				
			||||||
	unref_file(file);
 | 
							unref_file(file);
 | 
				
			||||||
 | 
							pw_log_info("fd:%d -> %d (%s)", oldfd,
 | 
				
			||||||
 | 
									res, strerror(res < 0 ? errno : 0));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -686,11 +713,14 @@ static int v4l2_close(int fd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int res = 0;
 | 
						int res = 0;
 | 
				
			||||||
	struct file *file;
 | 
						struct file *file;
 | 
				
			||||||
 | 
						struct fd_map *map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((file = find_file(fd)) == NULL)
 | 
						if ((map = find_fd_map(fd)) == NULL)
 | 
				
			||||||
		return globals.old_fops.close(fd);
 | 
							return globals.old_fops.close(fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free_file(file);
 | 
						file = map->file;
 | 
				
			||||||
 | 
						remove_fd_map(map);
 | 
				
			||||||
 | 
						unref_file(file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_info("fd:%d -> %d (%s)", fd,
 | 
						pw_log_info("fd:%d -> %d (%s)", fd,
 | 
				
			||||||
			res, strerror(res < 0 ? errno : 0));
 | 
								res, strerror(res < 0 ? errno : 0));
 | 
				
			||||||
| 
						 | 
					@ -730,120 +760,119 @@ struct format_info {
 | 
				
			||||||
	uint32_t media_type;
 | 
						uint32_t media_type;
 | 
				
			||||||
	uint32_t media_subtype;
 | 
						uint32_t media_subtype;
 | 
				
			||||||
	uint32_t format;
 | 
						uint32_t format;
 | 
				
			||||||
 | 
						uint32_t bpp;
 | 
				
			||||||
	const char *desc;
 | 
						const char *desc;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAKE_FORMAT(fcc,mt,mst,fmt)	\
 | 
					#define MAKE_FORMAT(fcc,mt,mst,bpp,fmt)	\
 | 
				
			||||||
	{ V4L2_PIX_FMT_ ## fcc, SPA_MEDIA_TYPE_ ## mt, SPA_MEDIA_SUBTYPE_ ## mst, SPA_VIDEO_FORMAT_ ## fmt, #fcc }
 | 
						{ V4L2_PIX_FMT_ ## fcc, SPA_MEDIA_TYPE_ ## mt, SPA_MEDIA_SUBTYPE_ ## mst, SPA_VIDEO_FORMAT_ ## fmt, bpp, #fcc }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct format_info format_info[] = {
 | 
					static const struct format_info format_info[] = {
 | 
				
			||||||
	/* RGB formats */
 | 
						/* RGB formats */
 | 
				
			||||||
	MAKE_FORMAT(RGB332, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(RGB332, video, raw, 4, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(ARGB555, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(ARGB555, video, raw, 4, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(XRGB555, video, raw, RGB15),
 | 
						MAKE_FORMAT(XRGB555, video, raw, 4, RGB15),
 | 
				
			||||||
	MAKE_FORMAT(ARGB555X, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(ARGB555X, video, raw, 4, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(XRGB555X, video, raw, BGR15),
 | 
						MAKE_FORMAT(XRGB555X, video, raw, 4, BGR15),
 | 
				
			||||||
	MAKE_FORMAT(RGB565, video, raw, RGB16),
 | 
						MAKE_FORMAT(RGB565, video, raw, 4, RGB16),
 | 
				
			||||||
	MAKE_FORMAT(RGB565X, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(RGB565X, video, raw, 4, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(BGR666, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(BGR666, video, raw, 4, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(BGR24, video, raw, BGR),
 | 
						MAKE_FORMAT(BGR24, video, raw, 4, BGR),
 | 
				
			||||||
	MAKE_FORMAT(RGB24, video, raw, RGB),
 | 
						MAKE_FORMAT(RGB24, video, raw, 4, RGB),
 | 
				
			||||||
	MAKE_FORMAT(ABGR32, video, raw, BGRA),
 | 
						MAKE_FORMAT(ABGR32, video, raw, 4, BGRA),
 | 
				
			||||||
	MAKE_FORMAT(XBGR32, video, raw, BGRx),
 | 
						MAKE_FORMAT(XBGR32, video, raw, 4, BGRx),
 | 
				
			||||||
	MAKE_FORMAT(ARGB32, video, raw, ARGB),
 | 
						MAKE_FORMAT(ARGB32, video, raw, 4, ARGB),
 | 
				
			||||||
	MAKE_FORMAT(XRGB32, video, raw, xRGB),
 | 
						MAKE_FORMAT(XRGB32, video, raw, 4, xRGB),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Deprecated Packed RGB Image Formats (alpha ambiguity) */
 | 
						/* Deprecated Packed RGB Image Formats (alpha ambiguity) */
 | 
				
			||||||
	MAKE_FORMAT(RGB444, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(RGB444, video, raw, 2, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(RGB555, video, raw, RGB15),
 | 
						MAKE_FORMAT(RGB555, video, raw, 2, RGB15),
 | 
				
			||||||
	MAKE_FORMAT(RGB555X, video, raw, BGR15),
 | 
						MAKE_FORMAT(RGB555X, video, raw, 2, BGR15),
 | 
				
			||||||
	MAKE_FORMAT(BGR32, video, raw, BGRx),
 | 
						MAKE_FORMAT(BGR32, video, raw, 4, BGRx),
 | 
				
			||||||
	MAKE_FORMAT(RGB32, video, raw, xRGB),
 | 
						MAKE_FORMAT(RGB32, video, raw, 4, xRGB),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Grey formats */
 | 
					        /* Grey formats */
 | 
				
			||||||
	MAKE_FORMAT(GREY, video, raw, GRAY8),
 | 
						MAKE_FORMAT(GREY, video, raw, 1, GRAY8),
 | 
				
			||||||
	MAKE_FORMAT(Y4, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(Y4, video, raw, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(Y6, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(Y6, video, raw, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(Y10, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(Y10, video, raw, 2, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(Y12, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(Y12, video, raw, 2, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(Y16, video, raw, GRAY16_LE),
 | 
						MAKE_FORMAT(Y16, video, raw, 2, GRAY16_LE),
 | 
				
			||||||
	MAKE_FORMAT(Y16_BE, video, raw, GRAY16_BE),
 | 
						MAKE_FORMAT(Y16_BE, video, raw, 2, GRAY16_BE),
 | 
				
			||||||
	MAKE_FORMAT(Y10BPACK, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(Y10BPACK, video, raw, 2, UNKNOWN),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Palette formats */
 | 
						/* Palette formats */
 | 
				
			||||||
	MAKE_FORMAT(PAL8, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(PAL8, video, raw, 1, UNKNOWN),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Chrominance formats */
 | 
						/* Chrominance formats */
 | 
				
			||||||
	MAKE_FORMAT(UV8, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(UV8, video, raw, 2, UNKNOWN),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Luminance+Chrominance formats */
 | 
						/* Luminance+Chrominance formats */
 | 
				
			||||||
	MAKE_FORMAT(YUYV, video, raw, YUY2),
 | 
						MAKE_FORMAT(YVU410, video, raw, 1, YVU9),
 | 
				
			||||||
 | 
						MAKE_FORMAT(YVU420, video, raw, 1, YV12),
 | 
				
			||||||
	MAKE_FORMAT(YVU410, video, raw, YVU9),
 | 
						MAKE_FORMAT(YVU420M, video, raw, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(YVU420, video, raw, YV12),
 | 
						MAKE_FORMAT(YUYV, video, raw, 2, YUY2),
 | 
				
			||||||
	MAKE_FORMAT(YVU420M, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(YYUV, video, raw, 2, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(YUYV, video, raw, YUY2),
 | 
						MAKE_FORMAT(YVYU, video, raw, 2, YVYU),
 | 
				
			||||||
	MAKE_FORMAT(YYUV, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(UYVY, video, raw, 2, UYVY),
 | 
				
			||||||
	MAKE_FORMAT(YVYU, video, raw, YVYU),
 | 
						MAKE_FORMAT(VYUY, video, raw, 2, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(UYVY, video, raw, UYVY),
 | 
						MAKE_FORMAT(YUV422P, video, raw, 1, Y42B),
 | 
				
			||||||
	MAKE_FORMAT(VYUY, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(YUV411P, video, raw, 1, Y41B),
 | 
				
			||||||
	MAKE_FORMAT(YUV422P, video, raw, Y42B),
 | 
						MAKE_FORMAT(Y41P, video, raw, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(YUV411P, video, raw, Y41B),
 | 
						MAKE_FORMAT(YUV444, video, raw, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(Y41P, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(YUV555, video, raw, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(YUV444, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(YUV565, video, raw, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(YUV555, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(YUV32, video, raw, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(YUV565, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(YUV410, video, raw, 1, YUV9),
 | 
				
			||||||
	MAKE_FORMAT(YUV32, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(YUV420, video, raw, 1, I420),
 | 
				
			||||||
	MAKE_FORMAT(YUV410, video, raw, YUV9),
 | 
						MAKE_FORMAT(YUV420M, video, raw, 1, I420),
 | 
				
			||||||
	MAKE_FORMAT(YUV420, video, raw, I420),
 | 
						MAKE_FORMAT(HI240, video, raw, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(YUV420M, video, raw, I420),
 | 
						MAKE_FORMAT(HM12, video, raw, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(HI240, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(M420, video, raw, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(HM12, video, raw, UNKNOWN),
 | 
					 | 
				
			||||||
	MAKE_FORMAT(M420, video, raw, UNKNOWN),
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* two planes -- one Y, one Cr + Cb interleaved  */
 | 
						/* two planes -- one Y, one Cr + Cb interleaved  */
 | 
				
			||||||
	MAKE_FORMAT(NV12, video, raw, NV12),
 | 
						MAKE_FORMAT(NV12, video, raw, 1, NV12),
 | 
				
			||||||
	MAKE_FORMAT(NV12M, video, raw, NV12),
 | 
						MAKE_FORMAT(NV12M, video, raw, 1,  NV12),
 | 
				
			||||||
	MAKE_FORMAT(NV12MT, video, raw, NV12_64Z32),
 | 
						MAKE_FORMAT(NV12MT, video, raw, 1,  NV12_64Z32),
 | 
				
			||||||
	MAKE_FORMAT(NV12MT_16X16, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(NV12MT_16X16, video, raw, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(NV21, video, raw, NV21),
 | 
						MAKE_FORMAT(NV21, video, raw, 1, NV21),
 | 
				
			||||||
	MAKE_FORMAT(NV21M, video, raw, NV21),
 | 
						MAKE_FORMAT(NV21M, video, raw, 1, NV21),
 | 
				
			||||||
	MAKE_FORMAT(NV16, video, raw, NV16),
 | 
						MAKE_FORMAT(NV16, video, raw, 1, NV16),
 | 
				
			||||||
	MAKE_FORMAT(NV16M, video, raw, NV16),
 | 
						MAKE_FORMAT(NV16M, video, raw, 1, NV16),
 | 
				
			||||||
	MAKE_FORMAT(NV61, video, raw, NV61),
 | 
						MAKE_FORMAT(NV61, video, raw, 1, NV61),
 | 
				
			||||||
	MAKE_FORMAT(NV61M, video, raw, NV61),
 | 
						MAKE_FORMAT(NV61M, video, raw, 1, NV61),
 | 
				
			||||||
	MAKE_FORMAT(NV24, video, raw, NV24),
 | 
						MAKE_FORMAT(NV24, video, raw, 1, NV24),
 | 
				
			||||||
	MAKE_FORMAT(NV42, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(NV42, video, raw, 1, UNKNOWN),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
 | 
						/* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
 | 
				
			||||||
	MAKE_FORMAT(SBGGR8, video, bayer, UNKNOWN),
 | 
						MAKE_FORMAT(SBGGR8, video, bayer, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(SGBRG8, video, bayer, UNKNOWN),
 | 
						MAKE_FORMAT(SGBRG8, video, bayer, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(SGRBG8, video, bayer, UNKNOWN),
 | 
						MAKE_FORMAT(SGRBG8, video, bayer, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(SRGGB8, video, bayer, UNKNOWN),
 | 
						MAKE_FORMAT(SRGGB8, video, bayer, 1, UNKNOWN),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* compressed formats */
 | 
						/* compressed formats */
 | 
				
			||||||
	MAKE_FORMAT(MJPEG, video, mjpg, ENCODED),
 | 
						MAKE_FORMAT(MJPEG, video, mjpg, 1, ENCODED),
 | 
				
			||||||
	MAKE_FORMAT(JPEG, video, mjpg, ENCODED),
 | 
						MAKE_FORMAT(JPEG, video, mjpg, 1, ENCODED),
 | 
				
			||||||
	MAKE_FORMAT(PJPG, video, mjpg, ENCODED),
 | 
						MAKE_FORMAT(PJPG, video, mjpg, 1, ENCODED),
 | 
				
			||||||
	MAKE_FORMAT(DV, video, dv, ENCODED),
 | 
						MAKE_FORMAT(DV, video, dv, 1, ENCODED),
 | 
				
			||||||
	MAKE_FORMAT(MPEG, video, mpegts, ENCODED),
 | 
						MAKE_FORMAT(MPEG, video, mpegts, 1, ENCODED),
 | 
				
			||||||
	MAKE_FORMAT(H264, video, h264, ENCODED),
 | 
						MAKE_FORMAT(H264, video, h264, 1, ENCODED),
 | 
				
			||||||
	MAKE_FORMAT(H264_NO_SC, video, h264, ENCODED),
 | 
						MAKE_FORMAT(H264_NO_SC, video, h264, 1, ENCODED),
 | 
				
			||||||
	MAKE_FORMAT(H264_MVC, video, h264, ENCODED),
 | 
						MAKE_FORMAT(H264_MVC, video, h264, 1, ENCODED),
 | 
				
			||||||
	MAKE_FORMAT(H263, video, h263, ENCODED),
 | 
						MAKE_FORMAT(H263, video, h263, 1, ENCODED),
 | 
				
			||||||
	MAKE_FORMAT(MPEG1, video, mpeg1, ENCODED),
 | 
						MAKE_FORMAT(MPEG1, video, mpeg1, 1, ENCODED),
 | 
				
			||||||
	MAKE_FORMAT(MPEG2, video, mpeg2, ENCODED),
 | 
						MAKE_FORMAT(MPEG2, video, mpeg2, 1, ENCODED),
 | 
				
			||||||
	MAKE_FORMAT(MPEG4, video, mpeg4, ENCODED),
 | 
						MAKE_FORMAT(MPEG4, video, mpeg4, 1, ENCODED),
 | 
				
			||||||
	MAKE_FORMAT(XVID, video, xvid, ENCODED),
 | 
						MAKE_FORMAT(XVID, video, xvid, 1, ENCODED),
 | 
				
			||||||
	MAKE_FORMAT(VC1_ANNEX_G, video, vc1, ENCODED),
 | 
						MAKE_FORMAT(VC1_ANNEX_G, video, vc1, 1, ENCODED),
 | 
				
			||||||
	MAKE_FORMAT(VC1_ANNEX_L, video, vc1, ENCODED),
 | 
						MAKE_FORMAT(VC1_ANNEX_L, video, vc1, 1, ENCODED),
 | 
				
			||||||
	MAKE_FORMAT(VP8, video, vp8, ENCODED),
 | 
						MAKE_FORMAT(VP8, video, vp8, 1, ENCODED),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*  Vendor-specific formats   */
 | 
						/*  Vendor-specific formats   */
 | 
				
			||||||
	MAKE_FORMAT(WNVA, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(WNVA, video, raw, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(SN9C10X, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(SN9C10X, video, raw, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(PWC1, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(PWC1, video, raw, 1, UNKNOWN),
 | 
				
			||||||
	MAKE_FORMAT(PWC2, video, raw, UNKNOWN),
 | 
						MAKE_FORMAT(PWC2, video, raw, 1, UNKNOWN),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct format_info *format_info_from_media_type(uint32_t type,
 | 
					static const struct format_info *format_info_from_media_type(uint32_t type,
 | 
				
			||||||
| 
						 | 
					@ -869,6 +898,81 @@ static const struct format_info *format_info_from_fourcc(uint32_t fourcc)
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int format_to_info(const struct v4l2_format *arg, struct spa_video_info *info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct format_info *fi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_info("type: %u", arg->type);
 | 
				
			||||||
 | 
						pw_log_info("width: %u", arg->fmt.pix.width);
 | 
				
			||||||
 | 
						pw_log_info("height: %u", arg->fmt.pix.height);
 | 
				
			||||||
 | 
						pw_log_info("fmt: %u", arg->fmt.pix.pixelformat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (arg->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fi = format_info_from_fourcc(arg->fmt.pix.pixelformat);
 | 
				
			||||||
 | 
						if (fi == NULL)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_zero(*info);
 | 
				
			||||||
 | 
						info->media_type = fi->media_type;
 | 
				
			||||||
 | 
						info->media_subtype = fi->media_subtype;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (info->media_subtype) {
 | 
				
			||||||
 | 
						case SPA_MEDIA_SUBTYPE_raw:
 | 
				
			||||||
 | 
							info->info.raw.format = fi->format;
 | 
				
			||||||
 | 
							info->info.raw.size.width = arg->fmt.pix.width;
 | 
				
			||||||
 | 
							info->info.raw.size.height = arg->fmt.pix.height;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SPA_MEDIA_SUBTYPE_h264:
 | 
				
			||||||
 | 
							info->info.h264.size.width = arg->fmt.pix.width;
 | 
				
			||||||
 | 
							info->info.h264.size.height = arg->fmt.pix.height;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SPA_MEDIA_SUBTYPE_mjpg:
 | 
				
			||||||
 | 
						case SPA_MEDIA_SUBTYPE_jpeg:
 | 
				
			||||||
 | 
							info->info.mjpg.size.width = arg->fmt.pix.width;
 | 
				
			||||||
 | 
							info->info.mjpg.size.height = arg->fmt.pix.height;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct spa_pod *info_to_param(struct spa_pod_builder *builder, uint32_t id,
 | 
				
			||||||
 | 
							struct spa_video_info *info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct spa_pod *pod;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (info->media_type != SPA_MEDIA_TYPE_video)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (info->media_subtype) {
 | 
				
			||||||
 | 
						case SPA_MEDIA_SUBTYPE_raw:
 | 
				
			||||||
 | 
							pod = spa_format_video_raw_build(builder, id, &info->info.raw);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SPA_MEDIA_SUBTYPE_mjpg:
 | 
				
			||||||
 | 
						case SPA_MEDIA_SUBTYPE_jpeg:
 | 
				
			||||||
 | 
							pod = spa_format_video_mjpg_build(builder, id, &info->info.mjpg);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SPA_MEDIA_SUBTYPE_h264:
 | 
				
			||||||
 | 
							pod = spa_format_video_h264_build(builder, id, &info->info.h264);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return pod;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct spa_pod *fmt_to_param(struct spa_pod_builder *builder, uint32_t id,
 | 
				
			||||||
 | 
							const struct v4l2_format *fmt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct spa_video_info info;
 | 
				
			||||||
 | 
						if (format_to_info(fmt, &info) < 0)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						return info_to_param(builder, id, &info);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int param_to_info(const struct spa_pod *param, struct spa_video_info *info)
 | 
					static int param_to_info(const struct spa_pod *param, struct spa_video_info *info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
| 
						 | 
					@ -897,6 +1001,71 @@ static int param_to_info(const struct spa_pod *param, struct spa_video_info *inf
 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int info_to_fmt(const struct spa_video_info *info, struct v4l2_format *fmt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct format_info *fi;
 | 
				
			||||||
 | 
						uint32_t format;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (info->media_type != SPA_MEDIA_TYPE_video)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (info->media_subtype == SPA_MEDIA_SUBTYPE_raw) {
 | 
				
			||||||
 | 
							format = info->info.raw.format;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							format = SPA_VIDEO_FORMAT_ENCODED;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fi = format_info_from_media_type(info->media_type, info->media_subtype,
 | 
				
			||||||
 | 
								format);
 | 
				
			||||||
 | 
						if (fi == NULL)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_zero(*fmt);
 | 
				
			||||||
 | 
						fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 | 
				
			||||||
 | 
						fmt->fmt.pix.pixelformat = fi->fourcc;
 | 
				
			||||||
 | 
						fmt->fmt.pix.field = V4L2_FIELD_NONE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (info->media_subtype) {
 | 
				
			||||||
 | 
						case SPA_MEDIA_SUBTYPE_raw:
 | 
				
			||||||
 | 
							fmt->fmt.pix.width = info->info.raw.size.width;
 | 
				
			||||||
 | 
							fmt->fmt.pix.height = info->info.raw.size.height;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SPA_MEDIA_SUBTYPE_mjpg:
 | 
				
			||||||
 | 
						case SPA_MEDIA_SUBTYPE_jpeg:
 | 
				
			||||||
 | 
							fmt->fmt.pix.width = info->info.mjpg.size.width;
 | 
				
			||||||
 | 
							fmt->fmt.pix.height = info->info.mjpg.size.height;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SPA_MEDIA_SUBTYPE_h264:
 | 
				
			||||||
 | 
							fmt->fmt.pix.width = info->info.h264.size.width;
 | 
				
			||||||
 | 
							fmt->fmt.pix.height = info->info.h264.size.height;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fmt->fmt.pix.bytesperline = SPA_ROUND_UP_N(fmt->fmt.pix.width, 4) * fi->bpp;
 | 
				
			||||||
 | 
						fmt->fmt.pix.sizeimage = fmt->fmt.pix.bytesperline *
 | 
				
			||||||
 | 
							SPA_ROUND_UP_N(fmt->fmt.pix.height, 2);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int param_to_fmt(const struct spa_pod *param, struct v4l2_format *fmt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct spa_video_info info;
 | 
				
			||||||
 | 
						struct spa_pod *copy;
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						copy = spa_pod_copy(param);
 | 
				
			||||||
 | 
						spa_pod_fixate(copy);
 | 
				
			||||||
 | 
						res = param_to_info(copy, &info);
 | 
				
			||||||
 | 
						free(copy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (res < 0)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						if (info_to_fmt(&info, fmt) < 0)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void on_stream_param_changed(void *data, uint32_t id, const struct spa_pod *param)
 | 
					static void on_stream_param_changed(void *data, uint32_t id, const struct spa_pod *param)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct file *file = data;
 | 
						struct file *file = data;
 | 
				
			||||||
| 
						 | 
					@ -905,15 +1074,15 @@ static void on_stream_param_changed(void *data, uint32_t id, const struct spa_po
 | 
				
			||||||
	uint8_t buffer[4096];
 | 
						uint8_t buffer[4096];
 | 
				
			||||||
	struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
 | 
						struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
 | 
				
			||||||
	uint32_t buffers, size;
 | 
						uint32_t buffers, size;
 | 
				
			||||||
	struct spa_video_info info;
 | 
						struct v4l2_format fmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (param == NULL || id != SPA_PARAM_Format)
 | 
						if (param == NULL || id != SPA_PARAM_Format)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (param_to_info(param, &info) < 0)
 | 
						if (param_to_fmt(param, &fmt) < 0)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	file->format = info;
 | 
						file->v4l2_format = fmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buffers = file->reqbufs;
 | 
						buffers = file->reqbufs;
 | 
				
			||||||
	size = 0;
 | 
						size = 0;
 | 
				
			||||||
| 
						 | 
					@ -1002,9 +1171,10 @@ static const struct pw_stream_events stream_events = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *arg)
 | 
					static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *arg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint32_t count = 0;
 | 
						uint32_t count = 0, last_fourcc = 0;
 | 
				
			||||||
	struct global *g = file->node;
 | 
						struct global *g = file->node;
 | 
				
			||||||
	struct param *p;
 | 
						struct param *p;
 | 
				
			||||||
 | 
						bool found = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_info("index: %u", arg->index);
 | 
						pw_log_info("index: %u", arg->index);
 | 
				
			||||||
	pw_log_info("type: %u", arg->type);
 | 
						pw_log_info("type: %u", arg->type);
 | 
				
			||||||
| 
						 | 
					@ -1033,20 +1203,26 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *arg)
 | 
				
			||||||
			format = SPA_VIDEO_FORMAT_ENCODED;
 | 
								format = SPA_VIDEO_FORMAT_ENCODED;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pw_log_info("%d %d", count, arg->index);
 | 
					 | 
				
			||||||
		fi = format_info_from_media_type(media_type, media_subtype, format);
 | 
							fi = format_info_from_media_type(media_type, media_subtype, format);
 | 
				
			||||||
		if (fi == NULL)
 | 
							if (fi == NULL)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (fi->fourcc == last_fourcc)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							pw_log_info("count:%d %d %d", count, fi->fourcc, last_fourcc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		arg->flags = fi->format == SPA_VIDEO_FORMAT_ENCODED ? V4L2_FMT_FLAG_COMPRESSED : 0;
 | 
							arg->flags = fi->format == SPA_VIDEO_FORMAT_ENCODED ? V4L2_FMT_FLAG_COMPRESSED : 0;
 | 
				
			||||||
		arg->pixelformat = fi->fourcc;
 | 
							arg->pixelformat = fi->fourcc;
 | 
				
			||||||
		if (count == arg->index)
 | 
							last_fourcc = fi->fourcc;
 | 
				
			||||||
 | 
							if (count == arg->index) {
 | 
				
			||||||
 | 
								found = true;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		count++;
 | 
							count++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	pw_thread_loop_unlock(file->loop);
 | 
						pw_thread_loop_unlock(file->loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (count != arg->index)
 | 
						if (!found)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_info("format: %u", arg->pixelformat);
 | 
						pw_log_info("format: %u", arg->pixelformat);
 | 
				
			||||||
| 
						 | 
					@ -1065,91 +1241,57 @@ static int vidioc_g_fmt(struct file *file, struct v4l2_format *arg)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int format_to_info(struct v4l2_format *arg, struct spa_video_info *info)
 | 
					static int score_diff(struct v4l2_format *fmt, struct v4l2_format *tmp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct format_info *fi;
 | 
						int score = 0;
 | 
				
			||||||
 | 
						if (fmt->fmt.pix.pixelformat != tmp->fmt.pix.pixelformat)
 | 
				
			||||||
	pw_log_info("type: %u", arg->type);
 | 
							score += 20000;
 | 
				
			||||||
	pw_log_info("width: %u", arg->fmt.pix.width);
 | 
						score += SPA_ABS((int)fmt->fmt.pix.width - (int)tmp->fmt.pix.width);
 | 
				
			||||||
	pw_log_info("height: %u", arg->fmt.pix.height);
 | 
						score += SPA_ABS((int)fmt->fmt.pix.height - (int)tmp->fmt.pix.height);
 | 
				
			||||||
	pw_log_info("fmt: %u", arg->fmt.pix.pixelformat);
 | 
						return score;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (arg->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	fi = format_info_from_fourcc(arg->fmt.pix.pixelformat);
 | 
					 | 
				
			||||||
	if (fi == NULL)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	spa_zero(*info);
 | 
					 | 
				
			||||||
	info->media_type = fi->media_type;
 | 
					 | 
				
			||||||
	info->media_subtype = fi->media_subtype;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (info->media_subtype) {
 | 
					 | 
				
			||||||
	case SPA_MEDIA_SUBTYPE_raw:
 | 
					 | 
				
			||||||
		info->info.raw.format = fi->format;
 | 
					 | 
				
			||||||
		info->info.raw.size.width = arg->fmt.pix.width;
 | 
					 | 
				
			||||||
		info->info.raw.size.height = arg->fmt.pix.height;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case SPA_MEDIA_SUBTYPE_h264:
 | 
					 | 
				
			||||||
		info->info.h264.size.width = arg->fmt.pix.width;
 | 
					 | 
				
			||||||
		info->info.h264.size.height = arg->fmt.pix.height;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case SPA_MEDIA_SUBTYPE_mjpg:
 | 
					 | 
				
			||||||
	case SPA_MEDIA_SUBTYPE_jpeg:
 | 
					 | 
				
			||||||
		info->info.mjpg.size.width = arg->fmt.pix.width;
 | 
					 | 
				
			||||||
		info->info.mjpg.size.height = arg->fmt.pix.height;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct spa_pod *info_to_param(struct spa_pod_builder *builder, uint32_t id,
 | 
					static int try_format(struct file *file, struct v4l2_format *fmt)
 | 
				
			||||||
		struct spa_video_info *info)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct spa_pod *pod;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (info->media_type != SPA_MEDIA_TYPE_video)
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (info->media_subtype) {
 | 
					 | 
				
			||||||
	case SPA_MEDIA_SUBTYPE_raw:
 | 
					 | 
				
			||||||
		pod = spa_format_video_raw_build(builder, id, &info->info.raw);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case SPA_MEDIA_SUBTYPE_mjpg:
 | 
					 | 
				
			||||||
	case SPA_MEDIA_SUBTYPE_jpeg:
 | 
					 | 
				
			||||||
		pod = spa_format_video_mjpg_build(builder, id, &info->info.mjpg);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case SPA_MEDIA_SUBTYPE_h264:
 | 
					 | 
				
			||||||
		pod = spa_format_video_h264_build(builder, id, &info->info.h264);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return pod;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int try_format(struct file *file, const struct spa_pod *pod)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct param *p;
 | 
						struct param *p;
 | 
				
			||||||
	struct global *g = file->node;
 | 
						struct global *g = file->node;
 | 
				
			||||||
 | 
						struct v4l2_format best_fmt = *fmt;
 | 
				
			||||||
 | 
						int best = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_info("in: type: %u", fmt->type);
 | 
				
			||||||
 | 
						pw_log_info("in: format: %.4s", (char*)&fmt->fmt.pix.pixelformat);
 | 
				
			||||||
 | 
						pw_log_info("in: width: %u", fmt->fmt.pix.width);
 | 
				
			||||||
 | 
						pw_log_info("in: height: %u", fmt->fmt.pix.height);
 | 
				
			||||||
 | 
						pw_log_info("in: field: %u", fmt->fmt.pix.field);
 | 
				
			||||||
	spa_list_for_each(p, &g->param_list, link) {
 | 
						spa_list_for_each(p, &g->param_list, link) {
 | 
				
			||||||
		char buffer[1024];
 | 
							struct v4l2_format tmp;
 | 
				
			||||||
		struct spa_pod_builder b;
 | 
							int score;
 | 
				
			||||||
		struct spa_pod *res;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (p->id != SPA_PARAM_EnumFormat ||
 | 
							if (p->id != SPA_PARAM_EnumFormat || p->param == NULL)
 | 
				
			||||||
		    p->param == NULL)
 | 
					 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		spa_pod_builder_init(&b, buffer, sizeof(buffer));
 | 
							if (param_to_fmt(p->param, &tmp) < 0)
 | 
				
			||||||
		if (spa_pod_filter(&b, &res, p->param, pod) >= 0)
 | 
								continue;
 | 
				
			||||||
			return 0;
 | 
					
 | 
				
			||||||
 | 
							score = score_diff(fmt, &tmp);
 | 
				
			||||||
 | 
							pw_log_debug("check: type: %u", tmp.type);
 | 
				
			||||||
 | 
							pw_log_debug("check: format: %.4s", (char*)&tmp.fmt.pix.pixelformat);
 | 
				
			||||||
 | 
							pw_log_debug("check: width: %u", tmp.fmt.pix.width);
 | 
				
			||||||
 | 
							pw_log_debug("check: height: %u", tmp.fmt.pix.height);
 | 
				
			||||||
 | 
							pw_log_debug("check: score: %d best:%d", score, best);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (best == -1 || score < best) {
 | 
				
			||||||
 | 
								best = score;
 | 
				
			||||||
 | 
								best_fmt = tmp;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return -EINVAL;
 | 
						*fmt = best_fmt;
 | 
				
			||||||
 | 
						pw_log_info("out: format: %.4s", (char*)&fmt->fmt.pix.pixelformat);
 | 
				
			||||||
 | 
						pw_log_info("out: width: %u", fmt->fmt.pix.width);
 | 
				
			||||||
 | 
						pw_log_info("out: height: %u", fmt->fmt.pix.height);
 | 
				
			||||||
 | 
						pw_log_info("out: field: %u", fmt->fmt.pix.field);
 | 
				
			||||||
 | 
						pw_log_info("out: size: %u", fmt->fmt.pix.sizeimage);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int disconnect_stream(struct file *file)
 | 
					static int disconnect_stream(struct file *file)
 | 
				
			||||||
| 
						 | 
					@ -1174,7 +1316,7 @@ static int connect_stream(struct file *file)
 | 
				
			||||||
	const struct spa_pod *params[1];
 | 
						const struct spa_pod *params[1];
 | 
				
			||||||
	struct pw_properties *props;
 | 
						struct pw_properties *props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	params[0] = info_to_param(&b, SPA_PARAM_EnumFormat, &file->format);
 | 
						params[0] = fmt_to_param(&b, SPA_PARAM_EnumFormat, &file->v4l2_format);
 | 
				
			||||||
	if (params[0] == NULL) {
 | 
						if (params[0] == NULL) {
 | 
				
			||||||
		res = -EINVAL;
 | 
							res = -EINVAL;
 | 
				
			||||||
		goto exit;
 | 
							goto exit;
 | 
				
			||||||
| 
						 | 
					@ -1251,51 +1393,24 @@ exit:
 | 
				
			||||||
static int vidioc_s_fmt(struct file *file, struct v4l2_format *arg)
 | 
					static int vidioc_s_fmt(struct file *file, struct v4l2_format *arg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
	const struct spa_pod *params[1];
 | 
					 | 
				
			||||||
	uint8_t buffer[1024];
 | 
					 | 
				
			||||||
	struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
 | 
					 | 
				
			||||||
	struct spa_video_info info;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((res = format_to_info(arg, &info)) < 0)
 | 
					 | 
				
			||||||
		goto exit;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	params[0] = info_to_param(&b, SPA_PARAM_EnumFormat, &info);
 | 
					 | 
				
			||||||
	if (params[0] == NULL) {
 | 
					 | 
				
			||||||
		res = -EINVAL;
 | 
					 | 
				
			||||||
		goto exit;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_thread_loop_lock(file->loop);
 | 
						pw_thread_loop_lock(file->loop);
 | 
				
			||||||
	if ((res = try_format(file, params[0])) < 0)
 | 
						if ((res = try_format(file, arg)) < 0)
 | 
				
			||||||
		goto exit_unlock;
 | 
							goto exit_unlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	file->format = info;
 | 
					 | 
				
			||||||
	file->v4l2_format = *arg;
 | 
						file->v4l2_format = *arg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exit_unlock:
 | 
					exit_unlock:
 | 
				
			||||||
	pw_thread_loop_unlock(file->loop);
 | 
						pw_thread_loop_unlock(file->loop);
 | 
				
			||||||
exit:
 | 
					 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
static int vidioc_try_fmt(struct file *file, struct v4l2_format *arg)
 | 
					static int vidioc_try_fmt(struct file *file, struct v4l2_format *arg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
	struct spa_video_info info;
 | 
					 | 
				
			||||||
	const struct spa_pod *params[1];
 | 
					 | 
				
			||||||
	uint8_t buffer[1024];
 | 
					 | 
				
			||||||
	struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((res = format_to_info(arg, &info)) < 0)
 | 
					 | 
				
			||||||
		goto exit;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	params[0] = info_to_param(&b, SPA_PARAM_EnumFormat, &info);
 | 
					 | 
				
			||||||
	if (params[0] == NULL)
 | 
					 | 
				
			||||||
		goto exit;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_thread_loop_lock(file->loop);
 | 
						pw_thread_loop_lock(file->loop);
 | 
				
			||||||
	res = try_format(file, params[0]);
 | 
						res = try_format(file, arg);
 | 
				
			||||||
	pw_thread_loop_unlock(file->loop);
 | 
						pw_thread_loop_unlock(file->loop);
 | 
				
			||||||
exit:
 | 
					 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1414,7 +1529,7 @@ static int vidioc_qbuf(struct file *file, struct v4l2_buffer *arg)
 | 
				
			||||||
	arg->flags = buf->v4l2.flags;
 | 
						arg->flags = buf->v4l2.flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_stream_queue_buffer(file->stream, buf->buf);
 | 
						pw_stream_queue_buffer(file->stream, buf->buf);
 | 
				
			||||||
	pw_log_info("file:%p %d -> %d (%s)", file, arg->index, res, spa_strerror(res));
 | 
						pw_log_debug("file:%p %d -> %d (%s)", file, arg->index, res, spa_strerror(res));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exit:
 | 
					exit:
 | 
				
			||||||
	pw_thread_loop_unlock(file->loop);
 | 
						pw_thread_loop_unlock(file->loop);
 | 
				
			||||||
| 
						 | 
					@ -1464,7 +1579,7 @@ static int vidioc_dqbuf(struct file *file, struct v4l2_buffer *arg)
 | 
				
			||||||
exit_unlock:
 | 
					exit_unlock:
 | 
				
			||||||
	pw_thread_loop_unlock(file->loop);
 | 
						pw_thread_loop_unlock(file->loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_info("file:%p %d -> %d (%s)", file, arg->index, res, spa_strerror(res));
 | 
						pw_log_debug("file:%p %d -> %d (%s)", file, arg->index, res, spa_strerror(res));
 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1472,6 +1587,8 @@ static int vidioc_streamon(struct file *file, int *arg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_info("file:%p -> %d", file, *arg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (*arg != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 | 
						if (*arg != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1583,7 +1700,7 @@ done:
 | 
				
			||||||
		errno = -res;
 | 
							errno = -res;
 | 
				
			||||||
		res = -1;
 | 
							res = -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	pw_log_info("fd:%d request:%lx nr:%d arg:%p -> %d (%s)",
 | 
						pw_log_debug("fd:%d request:%lx nr:%d arg:%p -> %d (%s)",
 | 
				
			||||||
			fd, request, (int)_IOC_NR(request), arg,
 | 
								fd, request, (int)_IOC_NR(request), arg,
 | 
				
			||||||
			res, strerror(res < 0 ? errno : 0));
 | 
								res, strerror(res < 0 ? errno : 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1687,8 +1804,7 @@ const struct fops fops = {
 | 
				
			||||||
	.munmap = v4l2_munmap,
 | 
						.munmap = v4l2_munmap,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void reg(void) __attribute__ ((constructor));
 | 
					static void initialize(void)
 | 
				
			||||||
static void reg(void)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	globals.old_fops.openat = dlsym(RTLD_NEXT, "openat64");
 | 
						globals.old_fops.openat = dlsym(RTLD_NEXT, "openat64");
 | 
				
			||||||
	globals.old_fops.dup = dlsym(RTLD_NEXT, "dup");
 | 
						globals.old_fops.dup = dlsym(RTLD_NEXT, "dup");
 | 
				
			||||||
| 
						 | 
					@ -1701,6 +1817,13 @@ static void reg(void)
 | 
				
			||||||
	PW_LOG_TOPIC_INIT(v4l2_log_topic);
 | 
						PW_LOG_TOPIC_INIT(v4l2_log_topic);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pthread_mutex_init(&globals.lock, NULL);
 | 
						pthread_mutex_init(&globals.lock, NULL);
 | 
				
			||||||
	spa_list_init(&globals.files);
 | 
					 | 
				
			||||||
	pw_array_init(&globals.file_maps, 1024);
 | 
						pw_array_init(&globals.file_maps, 1024);
 | 
				
			||||||
 | 
						pw_array_init(&globals.fd_maps, 256);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct fops *get_fops(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static pthread_once_t initialized = PTHREAD_ONCE_INIT;
 | 
				
			||||||
 | 
					        pthread_once(&initialized, initialize);
 | 
				
			||||||
 | 
						return &fops;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,4 +35,4 @@ struct fops {
 | 
				
			||||||
	int (*munmap)(void *addr, size_t length);
 | 
						int (*munmap)(void *addr, size_t length);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern const struct fops fops;
 | 
					const struct fops *get_fops(void);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,7 +48,7 @@ SPA_EXPORT int open(const char *path, int oflag, ...)
 | 
				
			||||||
	if (oflag & O_CREAT || oflag & O_TMPFILE)
 | 
						if (oflag & O_CREAT || oflag & O_TMPFILE)
 | 
				
			||||||
		extract_va_arg(mode_t, mode, oflag);
 | 
							extract_va_arg(mode_t, mode, oflag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return fops.openat(AT_FDCWD, path, oflag, mode);
 | 
						return get_fops()->openat(AT_FDCWD, path, oflag, mode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* _FORTIFY_SOURCE redirects open to __open_2 */
 | 
					/* _FORTIFY_SOURCE redirects open to __open_2 */
 | 
				
			||||||
| 
						 | 
					@ -64,7 +64,7 @@ SPA_EXPORT int open64(const char *path, int oflag, ...)
 | 
				
			||||||
	if (oflag & O_CREAT || oflag & O_TMPFILE)
 | 
						if (oflag & O_CREAT || oflag & O_TMPFILE)
 | 
				
			||||||
		extract_va_arg(mode_t, mode, oflag);
 | 
							extract_va_arg(mode_t, mode, oflag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return fops.openat(AT_FDCWD, path, oflag | O_LARGEFILE, mode);
 | 
						return get_fops()->openat(AT_FDCWD, path, oflag | O_LARGEFILE, mode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SPA_EXPORT int __open64_2(const char *path, int oflag)
 | 
					SPA_EXPORT int __open64_2(const char *path, int oflag)
 | 
				
			||||||
| 
						 | 
					@ -79,7 +79,7 @@ SPA_EXPORT int openat(int dirfd, const char *path, int oflag, ...)
 | 
				
			||||||
	if (oflag & O_CREAT || oflag & O_TMPFILE)
 | 
						if (oflag & O_CREAT || oflag & O_TMPFILE)
 | 
				
			||||||
		extract_va_arg(mode_t, mode, oflag);
 | 
							extract_va_arg(mode_t, mode, oflag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return fops.openat(dirfd, path, oflag, mode);
 | 
						return get_fops()->openat(dirfd, path, oflag, mode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SPA_EXPORT int __openat_2(int dirfd, const char *path, int oflag)
 | 
					SPA_EXPORT int __openat_2(int dirfd, const char *path, int oflag)
 | 
				
			||||||
| 
						 | 
					@ -94,7 +94,7 @@ SPA_EXPORT int openat64(int dirfd, const char *path, int oflag, ...)
 | 
				
			||||||
	if (oflag & O_CREAT || oflag & O_TMPFILE)
 | 
						if (oflag & O_CREAT || oflag & O_TMPFILE)
 | 
				
			||||||
		extract_va_arg(mode_t, mode, oflag);
 | 
							extract_va_arg(mode_t, mode, oflag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return fops.openat(dirfd, path, oflag | O_LARGEFILE, mode);
 | 
						return get_fops()->openat(dirfd, path, oflag | O_LARGEFILE, mode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SPA_EXPORT int __openat64_2(int dirfd, const char *path, int oflag)
 | 
					SPA_EXPORT int __openat64_2(int dirfd, const char *path, int oflag)
 | 
				
			||||||
| 
						 | 
					@ -105,36 +105,36 @@ SPA_EXPORT int __openat64_2(int dirfd, const char *path, int oflag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SPA_EXPORT int dup(int oldfd)
 | 
					SPA_EXPORT int dup(int oldfd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return fops.dup(oldfd);
 | 
						return get_fops()->dup(oldfd);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SPA_EXPORT int close(int fd)
 | 
					SPA_EXPORT int close(int fd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return fops.close(fd);
 | 
						return get_fops()->close(fd);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SPA_EXPORT void *mmap(void *addr, size_t length, int prot, int flags,
 | 
					SPA_EXPORT void *mmap(void *addr, size_t length, int prot, int flags,
 | 
				
			||||||
                            int fd, off_t offset)
 | 
					                            int fd, off_t offset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return fops.mmap(addr, length, prot, flags, fd, offset);
 | 
						return get_fops()->mmap(addr, length, prot, flags, fd, offset);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef mmap64
 | 
					#ifndef mmap64
 | 
				
			||||||
SPA_EXPORT void *mmap64(void *addr, size_t length, int prot, int flags,
 | 
					SPA_EXPORT void *mmap64(void *addr, size_t length, int prot, int flags,
 | 
				
			||||||
                              int fd, off64_t offset)
 | 
					                              int fd, off64_t offset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return fops.mmap(addr, length, prot, flags, fd, offset);
 | 
						return get_fops()->mmap(addr, length, prot, flags, fd, offset);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SPA_EXPORT int munmap(void *addr, size_t length)
 | 
					SPA_EXPORT int munmap(void *addr, size_t length)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return fops.munmap(addr, length);
 | 
						return get_fops()->munmap(addr, length);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SPA_EXPORT int ioctl(int fd, unsigned long int request, ...)
 | 
					SPA_EXPORT int ioctl(int fd, unsigned long int request, ...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void *arg;
 | 
						void *arg;
 | 
				
			||||||
	extract_va_arg(void *, arg, request);
 | 
						extract_va_arg(void *, arg, request);
 | 
				
			||||||
	return fops.ioctl(fd, request, arg);
 | 
						return get_fops()->ioctl(fd, request, arg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue