/** * gst_v4l2_buffer_pool_new: * @obj: the v4l2 object owning the pool * * Construct a new buffer pool. * * Returns: the new pool, use gst_object_unref() to free resources */ GstBufferPool * gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps) { GstV4l2BufferPool *pool; GstStructure *s; gint fd; fd = v4l2_dup (obj->video_fd); if (fd < 0) goto dup_failed; pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL, NULL); pool->video_fd = fd; pool->obj = obj; s = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); gst_buffer_pool_config_set_params (s, caps, obj->sizeimage, 2, 0); gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), s); return GST_BUFFER_POOL (pool); /* ERRORS */ dup_failed: { GST_DEBUG ("failed to dup fd %d (%s)", errno, g_strerror (errno)); return NULL; } }
int v4l1_dup(int fd) { int index = v4l1_get_index(fd); if (index == -1) return syscall(SYS_dup, fd); devices[index].open_count++; return v4l2_dup(fd); }
GstV4l2Allocator * gst_v4l2_allocator_new (GstObject * parent, gint video_fd, struct v4l2_format *format) { GstV4l2Allocator *allocator; guint32 flags = 0; gchar *name, *parent_name; parent_name = gst_object_get_name (parent); name = g_strconcat (parent_name, ":allocator", NULL); g_free (parent_name); allocator = g_object_new (GST_TYPE_V4L2_ALLOCATOR, "name", name, NULL); gst_object_ref_sink (allocator); g_free (name); /* Save everything */ allocator->video_fd = v4l2_dup (video_fd); allocator->type = format->type; allocator->format = *format; flags |= GST_V4L2_ALLOCATOR_PROBE (allocator, MMAP); flags |= GST_V4L2_ALLOCATOR_PROBE (allocator, USERPTR); flags |= GST_V4L2_ALLOCATOR_PROBE (allocator, DMABUF); if (flags == 0) { /* Drivers not ported from videobuf to videbuf2 don't allow freeing buffers * using REQBUFS(0). This is a workaround to still support these drivers, * which are known to have MMAP support. */ GST_WARNING_OBJECT (allocator, "Could not probe supported memory type, " "assuming MMAP is supported, this is expected for older drivers not " " yet ported to videobuf2 framework"); flags = GST_V4L2_ALLOCATOR_FLAG_MMAP_REQBUFS; } GST_OBJECT_FLAG_SET (allocator, flags); return allocator; }
gboolean gst_v4l2_dup (GstV4l2Object * v4l2object, GstV4l2Object * other) { GST_DEBUG_OBJECT (v4l2object->element, "Trying to dup device %s", other->videodev); GST_V4L2_CHECK_OPEN (other); GST_V4L2_CHECK_NOT_OPEN (v4l2object); GST_V4L2_CHECK_NOT_ACTIVE (other); GST_V4L2_CHECK_NOT_ACTIVE (v4l2object); v4l2object->vcap = other->vcap; gst_v4l2_adjust_buf_type (v4l2object); v4l2object->video_fd = v4l2_dup (other->video_fd); if (!GST_V4L2_IS_OPEN (v4l2object)) goto not_open; g_free (v4l2object->videodev); v4l2object->videodev = g_strdup (other->videodev); GST_INFO_OBJECT (v4l2object->element, "Cloned device '%s' (%s) successfully", v4l2object->vcap.card, v4l2object->videodev); v4l2object->never_interlaced = other->never_interlaced; return TRUE; not_open: { GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ_WRITE, (_("Could not dup device '%s' for reading and writing."), v4l2object->videodev), GST_ERROR_SYSTEM); return FALSE; } }
/** * gst_v4l2_buffer_pool_new: * @v4l2elem: the v4l2 element (src or sink) that owns this pool * @fd: the video device file descriptor * @num_buffers: the requested number of buffers in the pool * @caps: the caps to set on the buffer * @requeuebuf: if %TRUE, and if the pool is still in the running state, a * buffer with no remaining references is immediately passed back to v4l2 * (VIDIOC_QBUF), otherwise it is returned to the pool of available buffers * (which can be accessed via gst_v4l2_buffer_pool_get(). * * Construct a new buffer pool. * * Returns: the new pool, use gst_v4l2_buffer_pool_destroy() to free resources */ GstV4l2BufferPool * gst_v4l2_buffer_pool_new (GstElement * v4l2elem, gint fd, gint num_buffers, GstCaps * caps, gboolean requeuebuf, enum v4l2_buf_type type) { GstV4l2BufferPool *pool; gint n; struct v4l2_requestbuffers breq; pool = (GstV4l2BufferPool *) gst_mini_object_new (GST_TYPE_V4L2_BUFFER_POOL); pool->video_fd = v4l2_dup (fd); if (pool->video_fd < 0) goto dup_failed; /* first, lets request buffers, and see how many we can get: */ GST_DEBUG_OBJECT (v4l2elem, "STREAMING, requesting %d MMAP buffers", num_buffers); memset (&breq, 0, sizeof (struct v4l2_requestbuffers)); breq.type = type; breq.count = num_buffers; breq.memory = V4L2_MEMORY_MMAP; if (v4l2_ioctl (fd, VIDIOC_REQBUFS, &breq) < 0) goto reqbufs_failed; GST_LOG_OBJECT (v4l2elem, " count: %u", breq.count); GST_LOG_OBJECT (v4l2elem, " type: %d", breq.type); GST_LOG_OBJECT (v4l2elem, " memory: %d", breq.memory); if (breq.count < GST_V4L2_MIN_BUFFERS) goto no_buffers; if (num_buffers != breq.count) { GST_WARNING_OBJECT (v4l2elem, "using %u buffers instead", breq.count); num_buffers = breq.count; } pool->v4l2elem = v4l2elem; pool->requeuebuf = requeuebuf; pool->type = type; pool->buffer_count = num_buffers; pool->buffers = g_new0 (GstV4l2Buffer *, num_buffers); pool->avail_buffers = g_async_queue_new (); /* now, map the buffers: */ for (n = 0; n < num_buffers; n++) { pool->buffers[n] = gst_v4l2_buffer_new (pool, n, caps); if (!pool->buffers[n]) goto buffer_new_failed; pool->num_live_buffers++; g_async_queue_push (pool->avail_buffers, pool->buffers[n]); } return pool; /* ERRORS */ dup_failed: { gint errnosave = errno; gst_mini_object_unref (GST_MINI_OBJECT (pool)); errno = errnosave; return NULL; } reqbufs_failed: { GstV4l2Object *v4l2object = get_v4l2_object (v4l2elem); GST_ELEMENT_ERROR (v4l2elem, RESOURCE, READ, (_("Could not get buffers from device '%s'."), v4l2object->videodev), ("error requesting %d buffers: %s", num_buffers, g_strerror (errno))); return NULL; } no_buffers: { GstV4l2Object *v4l2object = get_v4l2_object (v4l2elem); GST_ELEMENT_ERROR (v4l2elem, RESOURCE, READ, (_("Could not get enough buffers from device '%s'."), v4l2object->videodev), ("we received %d from device '%s', we want at least %d", breq.count, v4l2object->videodev, GST_V4L2_MIN_BUFFERS)); return NULL; } buffer_new_failed: { gint errnosave = errno; gst_v4l2_buffer_pool_destroy (pool); errno = errnosave; return NULL; } }
LIBV4L_PUBLIC int dup(int fd) { return v4l2_dup(fd); }
/** * gst_v4l2_buffer_pool_new: * @obj: the v4l2 object owning the pool * * Construct a new buffer pool. * * Returns: the new pool, use gst_object_unref() to free resources */ GstBufferPool * gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps) { GstV4l2BufferPool *pool; GstStructure *config; gchar *name, *parent_name; gint fd; fd = v4l2_dup (obj->video_fd); if (fd < 0) goto dup_failed; /* setting a significant unique name */ parent_name = gst_object_get_name (GST_OBJECT (obj->element)); name = g_strconcat (parent_name, ":", "pool:", V4L2_TYPE_IS_OUTPUT (obj->type) ? "sink" : "src", NULL); g_free (parent_name); pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL, "name", name, NULL); g_free (name); gst_poll_fd_init (&pool->pollfd); pool->pollfd.fd = fd; gst_poll_add_fd (pool->poll, &pool->pollfd); if (V4L2_TYPE_IS_OUTPUT (obj->type)) gst_poll_fd_ctl_write (pool->poll, &pool->pollfd, TRUE); else gst_poll_fd_ctl_read (pool->poll, &pool->pollfd, TRUE); pool->video_fd = fd; pool->obj = obj; pool->can_poll_device = TRUE; pool->vallocator = gst_v4l2_allocator_new (GST_OBJECT (pool), obj->video_fd, &obj->format); if (pool->vallocator == NULL) goto allocator_failed; gst_object_ref (obj->element); config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); gst_buffer_pool_config_set_params (config, caps, obj->info.size, 0, 0); /* This will simply set a default config, but will not configure the pool * because min and max are not valid */ gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), config); return GST_BUFFER_POOL (pool); /* ERRORS */ dup_failed: { GST_ERROR ("failed to dup fd %d (%s)", errno, g_strerror (errno)); return NULL; } allocator_failed: { GST_ERROR_OBJECT (pool, "Failed to create V4L2 allocator"); return NULL; } }