#endif
#include "ext/videodev2.h"
+
+#include "gstv4l2object.h"
#include "gstv4l2allocator.h"
-#include "v4l2_calls.h"
#include <gst/allocators/gstdmabuf.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
+#include <unistd.h>
+#ifdef TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER
+#include <tbm_surface.h>
+#include <tbm_surface_internal.h>
+#endif /* TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER */
#define GST_V4L2_MEMORY_TYPE "V4l2Memory"
if (mem)
gst_memory_unref (mem);
}
+#ifdef TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER
+ if (group->surface) {
+ GST_INFO ("unref surface[%p]", group->surface);
+ tbm_surface_destroy (group->surface);
+ group->surface = NULL;
+ }
+#endif /* TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER */
g_slice_free (GstV4l2MemoryGroup, group);
}
static GstV4l2MemoryGroup *
gst_v4l2_memory_group_new (GstV4l2Allocator * allocator, guint32 index)
{
- gint video_fd = allocator->video_fd;
+ GstV4l2Object *obj = allocator->obj;
guint32 memory = allocator->memory;
- struct v4l2_format *format = &allocator->format;
+ struct v4l2_format *format = &obj->format;
GstV4l2MemoryGroup *group;
gsize img_size, buf_size;
group->n_mem = 1;
}
- if (v4l2_ioctl (video_fd, VIDIOC_QUERYBUF, &group->buffer) < 0)
+ if (obj->ioctl (obj->video_fd, VIDIOC_QUERYBUF, &group->buffer) < 0)
goto querybuf_failed;
if (group->buffer.index != index) {
/* Check that provided size matches the format we have negotiation. Failing
* there usually means a driver of libv4l bug. */
- if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
+ if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
gint i;
for (i = 0; i < group->n_mem; i++) {
- img_size = allocator->format.fmt.pix_mp.plane_fmt[i].sizeimage;
+ img_size = obj->format.fmt.pix_mp.plane_fmt[i].sizeimage;
buf_size = group->planes[i].length;
if (buf_size < img_size)
goto buffer_too_short;
}
} else {
- img_size = allocator->format.fmt.pix.sizeimage;
+ img_size = obj->format.fmt.pix.sizeimage;
buf_size = group->buffer.length;
if (buf_size < img_size)
goto buffer_too_short;
if (!V4L2_TYPE_IS_MULTIPLANAR (format->type)) {
group->planes[0].bytesused = group->buffer.bytesused;
group->planes[0].length = group->buffer.length;
+ group->planes[0].data_offset = 0;
g_assert (sizeof (group->planes[0].m) == sizeof (group->buffer.m));
memcpy (&group->planes[0].m, &group->buffer.m, sizeof (group->buffer.m));
}
if (memory == V4L2_MEMORY_MMAP) {
gint i;
for (i = 0; i < group->n_mem; i++) {
- GST_LOG_OBJECT (allocator, " [%u] bytesused: %u, length: %u", i,
- group->planes[i].bytesused, group->planes[i].length);
+ GST_LOG_OBJECT (allocator,
+ " [%u] bytesused: %u, length: %u, offset: %u", i,
+ group->planes[i].bytesused, group->planes[i].length,
+ group->planes[i].data_offset);
GST_LOG_OBJECT (allocator, " [%u] MMAP offset: %u", i,
group->planes[i].m.mem_offset);
}
gst_v4l2_allocator_free (GstAllocator * gallocator, GstMemory * gmem)
{
GstV4l2Allocator *allocator = (GstV4l2Allocator *) gallocator;
+ GstV4l2Object *obj = allocator->obj;
GstV4l2Memory *mem = (GstV4l2Memory *) gmem;
GstV4l2MemoryGroup *group = mem->group;
if (allocator->memory == V4L2_MEMORY_MMAP) {
if (mem->data)
- v4l2_munmap (mem->data, group->planes[mem->plane].length);
+ obj->munmap (mem->data, group->planes[mem->plane].length);
}
/* This apply for both mmap with expbuf, and dmabuf imported memory */
GstV4l2Allocator *allocator = (GstV4l2Allocator *) obj;
GST_LOG_OBJECT (obj, "called");
+#ifdef TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER
+ if (allocator->bufmgr) {
+ GST_INFO_OBJECT (obj, "deinit tbm bufmgr %p", allocator->bufmgr);
+ tbm_bufmgr_deinit (allocator->bufmgr);
+ allocator->bufmgr = NULL;
+ }
+#endif /* TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER */
- v4l2_close (allocator->video_fd);
gst_atomic_queue_unref (allocator->free_queue);
+ gst_object_unref (allocator->obj->element);
G_OBJECT_CLASS (parent_class)->finalize (obj);
}
gst_v4l2_allocator_probe (GstV4l2Allocator * allocator, guint32 memory,
guint32 breq_flag, guint32 bcreate_flag)
{
+ GstV4l2Object *obj = allocator->obj;
struct v4l2_requestbuffers breq = { 0 };
guint32 flags = 0;
- breq.type = allocator->type;
+ breq.type = obj->type;
breq.count = 0;
breq.memory = memory;
- if (v4l2_ioctl (allocator->video_fd, VIDIOC_REQBUFS, &breq) == 0) {
+ if (obj->ioctl (obj->video_fd, VIDIOC_REQBUFS, &breq) == 0) {
struct v4l2_create_buffers bcreate = { 0 };
flags |= breq_flag;
- bcreate.memory = allocator->type;
- bcreate.format = allocator->format;
+ bcreate.memory = memory;
+ bcreate.format = obj->format;
- if ((v4l2_ioctl (allocator->video_fd, VIDIOC_CREATE_BUFS, &bcreate) == 0))
+ if ((obj->ioctl (obj->video_fd, VIDIOC_CREATE_BUFS, &bcreate) == 0))
flags |= bcreate_flag;
}
+ if (breq.capabilities & V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS)
+ flags |= GST_V4L2_ALLOCATOR_FLAG_SUPPORTS_ORPHANED_BUFS;
+
return flags;
}
static GstV4l2MemoryGroup *
gst_v4l2_allocator_create_buf (GstV4l2Allocator * allocator)
{
+ GstV4l2Object *obj = allocator->obj;
struct v4l2_create_buffers bcreate = { 0 };
GstV4l2MemoryGroup *group = NULL;
if (!g_atomic_int_get (&allocator->active))
goto done;
+ if (GST_V4L2_ALLOCATOR_IS_ORPHANED (allocator))
+ goto orphaned_bug;
+
bcreate.memory = allocator->memory;
- bcreate.format = allocator->format;
+ bcreate.format = obj->format;
bcreate.count = 1;
if (!allocator->can_allocate)
goto done;
- if (v4l2_ioctl (allocator->video_fd, VIDIOC_CREATE_BUFS, &bcreate) < 0)
+ if (obj->ioctl (obj->video_fd, VIDIOC_CREATE_BUFS, &bcreate) < 0)
goto create_bufs_failed;
if (allocator->groups[bcreate.index] != NULL)
GST_OBJECT_UNLOCK (allocator);
return group;
+orphaned_bug:
+ {
+ GST_ERROR_OBJECT (allocator, "allocator was orphaned, "
+ "not creating new buffers");
+ goto done;
+ }
create_bufs_failed:
{
GST_WARNING_OBJECT (allocator, "error creating a new buffer: %s",
gst_v4l2_allocator_reset_size (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup * group)
{
- gsize size;
- gboolean imported = FALSE;
-
- switch (allocator->memory) {
- case V4L2_MEMORY_USERPTR:
- case V4L2_MEMORY_DMABUF:
- imported = TRUE;
- break;
- }
-
- if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
- gint i;
-
- for (i = 0; i < group->n_mem; i++) {
- size = allocator->format.fmt.pix_mp.plane_fmt[i].sizeimage;
-
- if (imported)
- group->mem[i]->maxsize = size;
-
- gst_memory_resize (group->mem[i], 0, size);
- }
-
- } else {
- size = allocator->format.fmt.pix.sizeimage;
-
- if (imported)
- group->mem[0]->maxsize = size;
-
- gst_memory_resize (group->mem[0], 0, size);
+ gint i;
+ for (i = 0; i < group->n_mem; i++) {
+ group->mem[i]->maxsize = group->planes[i].length;
+ group->mem[i]->offset = 0;
+ group->mem[i]->size = group->planes[i].length;
}
}
}
}
-
+#ifdef TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER
+static tbm_format __get_tbm_format (GstVideoFormat gst_format)
+{
+ switch (gst_format) {
+ case GST_VIDEO_FORMAT_NV12:
+ case GST_VIDEO_FORMAT_SN12:
+ return TBM_FORMAT_NV12;
+ case GST_VIDEO_FORMAT_I420:
+ case GST_VIDEO_FORMAT_S420:
+ default:
+ return TBM_FORMAT_YUV420;
+ }
+}
+#endif /* TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER */
GstV4l2Allocator *
-gst_v4l2_allocator_new (GstObject * parent, gint video_fd,
- struct v4l2_format *format)
+gst_v4l2_allocator_new (GstObject * parent, GstV4l2Object * v4l2object)
{
GstV4l2Allocator *allocator;
guint32 flags = 0;
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;
+ allocator->obj = v4l2object;
+
+ /* Keep a ref on the elemnt so obj does not disapear */
+ gst_object_ref (allocator->obj->element);
flags |= GST_V4L2_ALLOCATOR_PROBE (allocator, MMAP);
flags |= GST_V4L2_ALLOCATOR_PROBE (allocator, USERPTR);
GST_OBJECT_FLAG_SET (allocator, flags);
+#ifdef TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER
+ if (!V4L2_TYPE_IS_OUTPUT (v4l2object->type) &&
+ v4l2object->mode == GST_V4L2_IO_DMABUF) {
+ tbm_surface_h tmp_surface = NULL;
+ int width = GST_VIDEO_INFO_WIDTH (&v4l2object->info);
+ int height = GST_VIDEO_INFO_HEIGHT (&v4l2object->info);
+
+ tmp_surface = tbm_surface_create (width, height,
+ __get_tbm_format (GST_VIDEO_INFO_FORMAT (&v4l2object->info)));
+ if (tmp_surface) {
+ tbm_surface_get_info (tmp_surface, &allocator->s_info);
+ GST_INFO_OBJECT (allocator, "[%dx%d] -> tbm surface info[%dx%d]",
+ width, height, allocator->s_info.width, allocator->s_info.height);
+ tbm_surface_destroy (tmp_surface);
+ } else {
+ GST_ERROR_OBJECT (allocator, "[%dx%d] surface failed", width, height);
+ }
+
+ allocator->bufmgr = tbm_bufmgr_init (-1);
+ if (!allocator->bufmgr) {
+ GST_ERROR_OBJECT (allocator, "tbm bufmgr failed");
+ gst_object_unref (allocator);
+ return NULL;
+ }
+ }
+#endif /* TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER */
return allocator;
}
gst_v4l2_allocator_start (GstV4l2Allocator * allocator, guint32 count,
guint32 memory)
{
- struct v4l2_requestbuffers breq = { count, allocator->type, memory };
+ GstV4l2Object *obj = allocator->obj;
+ struct v4l2_requestbuffers breq = { count, obj->type, memory };
gboolean can_allocate;
gint i;
if (g_atomic_int_get (&allocator->active))
goto already_active;
- if (v4l2_ioctl (allocator->video_fd, VIDIOC_REQBUFS, &breq) < 0)
+ if (GST_V4L2_ALLOCATOR_IS_ORPHANED (allocator))
+ goto orphaned;
+
+ if (obj->ioctl (obj->video_fd, VIDIOC_REQBUFS, &breq) < 0)
goto reqbufs_failed;
if (breq.count < 1)
GST_ERROR_OBJECT (allocator, "allocator already active");
goto error;
}
+orphaned:
+ {
+ GST_ERROR_OBJECT (allocator, "allocator was orphaned");
+ goto error;
+ }
reqbufs_failed:
{
GST_ERROR_OBJECT (allocator,
GstV4l2Return
gst_v4l2_allocator_stop (GstV4l2Allocator * allocator)
{
- struct v4l2_requestbuffers breq = { 0, allocator->type, allocator->memory };
+ GstV4l2Object *obj = allocator->obj;
+ struct v4l2_requestbuffers breq = { 0, obj->type, allocator->memory };
gint i = 0;
GstV4l2Return ret = GST_V4L2_OK;
gst_v4l2_memory_group_free (group);
}
- /* Not all drivers support rebufs(0), so warn only */
- if (v4l2_ioctl (allocator->video_fd, VIDIOC_REQBUFS, &breq) < 0)
- GST_WARNING_OBJECT (allocator,
- "error releasing buffers buffers: %s", g_strerror (errno));
+ if (!GST_V4L2_ALLOCATOR_IS_ORPHANED (allocator)) {
+ /* Not all drivers support rebufs(0), so warn only */
+ if (obj->ioctl (obj->video_fd, VIDIOC_REQBUFS, &breq) < 0)
+ GST_WARNING_OBJECT (allocator,
+ "error releasing buffers buffers: %s", g_strerror (errno));
+ }
allocator->count = 0;
return ret;
}
+gboolean
+gst_v4l2_allocator_orphan (GstV4l2Allocator * allocator)
+{
+ GstV4l2Object *obj = allocator->obj;
+ struct v4l2_requestbuffers breq = { 0, obj->type, allocator->memory };
+
+ if (!GST_V4L2_ALLOCATOR_CAN_ORPHAN_BUFS (allocator))
+ return FALSE;
+
+ GST_OBJECT_FLAG_SET (allocator, GST_V4L2_ALLOCATOR_FLAG_ORPHANED);
+
+ if (obj->ioctl (obj->video_fd, VIDIOC_REQBUFS, &breq) < 0) {
+ GST_ERROR_OBJECT (allocator,
+ "error orphaning buffers buffers: %s", g_strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
GstV4l2MemoryGroup *
gst_v4l2_allocator_alloc_mmap (GstV4l2Allocator * allocator)
{
+ GstV4l2Object *obj = allocator->obj;
GstV4l2MemoryGroup *group;
gint i;
for (i = 0; i < group->n_mem; i++) {
if (group->mem[i] == NULL) {
gpointer data;
- data = v4l2_mmap (NULL, group->planes[i].length, PROT_READ | PROT_WRITE,
- MAP_SHARED, allocator->video_fd, group->planes[i].m.mem_offset);
+ data = obj->mmap (NULL, group->planes[i].length, PROT_READ | PROT_WRITE,
+ MAP_SHARED, obj->video_fd, group->planes[i].m.mem_offset);
if (data == MAP_FAILED)
goto mmap_failed;
group->planes[i].length, group->planes[i].data_offset, i);
group->mem[i] = (GstMemory *) _v4l2mem_new (0, GST_ALLOCATOR (allocator),
- NULL, group->planes[i].length, 0, 0, group->planes[i].length, i,
- data, -1, group);
+ NULL, group->planes[i].length, 0, 0, group->planes[i].length, i, data,
+ -1, group);
} else {
/* Take back the allocator reference */
gst_object_ref (allocator);
gst_v4l2_allocator_alloc_dmabuf (GstV4l2Allocator * allocator,
GstAllocator * dmabuf_allocator)
{
+ GstV4l2Object *obj = allocator->obj;
GstV4l2MemoryGroup *group;
gint i;
+#ifdef TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER
+ tbm_bo bos[VIDEO_MAX_PLANES] = {NULL, };
+#endif /* TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER */
g_return_val_if_fail (allocator->memory == V4L2_MEMORY_MMAP, NULL);
for (i = 0; i < group->n_mem; i++) {
GstV4l2Memory *mem;
GstMemory *dma_mem;
- gint dmafd;
if (group->mem[i] == NULL) {
struct v4l2_exportbuffer expbuf = { 0 };
- expbuf.type = allocator->type;
+ expbuf.type = obj->type;
expbuf.index = group->buffer.index;
expbuf.plane = i;
expbuf.flags = O_CLOEXEC | O_RDWR;
- if (v4l2_ioctl (allocator->video_fd, VIDIOC_EXPBUF, &expbuf) < 0)
+ if (obj->ioctl (obj->video_fd, VIDIOC_EXPBUF, &expbuf) < 0)
goto expbuf_failed;
GST_LOG_OBJECT (allocator, "exported DMABUF as fd %i plane %d",
expbuf.fd, i);
group->mem[i] = (GstMemory *) _v4l2mem_new (0, GST_ALLOCATOR (allocator),
- NULL, group->planes[i].length, 0, 0, group->planes[i].length, i,
- NULL, expbuf.fd, group);
+ NULL, group->planes[i].length, 0, group->planes[i].data_offset,
+ group->planes[i].length - group->planes[i].data_offset, i, NULL,
+ expbuf.fd, group);
+#ifdef TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER
+ bos[i] = tbm_bo_import_fd (allocator->bufmgr, expbuf.fd);
+ GST_INFO_OBJECT (allocator, "obj[%p,i:%d]: fd[%d] -> bo[%p]",
+ obj, expbuf.index, expbuf.fd, bos[i]);
+#endif /* TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER */
} else {
/* Take back the allocator reference */
gst_object_ref (allocator);
}
+ group->mems_allocated++;
+
g_assert (gst_is_v4l2_memory (group->mem[i]));
mem = (GstV4l2Memory *) group->mem[i];
- if ((dmafd = dup (mem->dmafd)) < 0)
- goto dup_failed;
-
- dma_mem = gst_dmabuf_allocator_alloc (dmabuf_allocator, dmafd,
- mem->mem.maxsize);
+ dma_mem = gst_fd_allocator_alloc (dmabuf_allocator, mem->dmafd,
+ group->planes[i].length, GST_FD_MEMORY_FLAG_DONT_CLOSE);
+ gst_memory_resize (dma_mem, group->planes[i].data_offset,
+ group->planes[i].length - group->planes[i].data_offset);
gst_mini_object_set_qdata (GST_MINI_OBJECT (dma_mem),
GST_V4L2_MEMORY_QUARK, mem, (GDestroyNotify) gst_memory_unref);
group->mem[i] = dma_mem;
- group->mems_allocated++;
}
+#ifdef TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER
+ if (!group->surface) {
+ group->surface = tbm_surface_internal_create_with_bos (&allocator->s_info, bos, group->n_mem);
+ GST_INFO_OBJECT (allocator, "new surface[%p] in memory group[%p]", group->surface, group);
+ }
+ /* release bos - they will be kept in surface. */
+ for (i = 0 ; i < VIDEO_MAX_PLANES && bos[i] ; i++)
+ tbm_bo_unref (bos[i]);
+#endif /* TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER */
+
gst_v4l2_allocator_reset_size (allocator, group);
return group;
g_strerror (errno));
goto cleanup;
}
-dup_failed:
- {
- GST_ERROR_OBJECT (allocator, "Failed to dup DMABUF descriptor: %s",
- g_strerror (errno));
- goto cleanup;
- }
cleanup:
{
_cleanup_failed_alloc (allocator, group);
gst_v4l2_allocator_clear_dmabufin (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup * group)
{
+ GstV4l2Object *obj = allocator->obj;
GstV4l2Memory *mem;
gint i;
mem = (GstV4l2Memory *) group->mem[i];
- GST_LOG_OBJECT (allocator, "clearing DMABUF import, fd %i plane %d",
- mem->dmafd, i);
-
- if (mem->dmafd >= 0)
- close (mem->dmafd);
+ GST_LOG_OBJECT (allocator, "[%i] clearing DMABUF import, fd %i plane %d",
+ group->buffer.index, mem->dmafd, i);
/* Update memory */
mem->mem.maxsize = 0;
group->planes[i].data_offset = 0;
}
- if (!V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
+ if (!V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
group->buffer.bytesused = 0;
group->buffer.length = 0;
group->buffer.m.fd = -1;
gst_v4l2_allocator_clear_userptr (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup * group)
{
+ GstV4l2Object *obj = allocator->obj;
GstV4l2Memory *mem;
gint i;
for (i = 0; i < group->n_mem; i++) {
mem = (GstV4l2Memory *) group->mem[i];
- GST_LOG_OBJECT (allocator, "clearing USERPTR %p plane %d size %"
- G_GSIZE_FORMAT, mem->data, i, mem->mem.size);
+ GST_LOG_OBJECT (allocator, "[%i] clearing USERPTR %p plane %d size %"
+ G_GSIZE_FORMAT, group->buffer.index, mem->data, i, mem->mem.size);
mem->mem.maxsize = 0;
mem->mem.size = 0;
group->planes[i].m.userptr = 0;
}
- if (!V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
+ if (!V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
group->buffer.bytesused = 0;
group->buffer.length = 0;
group->buffer.m.userptr = 0;
gst_v4l2_allocator_import_dmabuf (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup * group, gint n_mem, GstMemory ** dma_mem)
{
+ GstV4l2Object *obj = allocator->obj;
GstV4l2Memory *mem;
gint i;
size = gst_memory_get_sizes (dma_mem[i], &offset, &maxsize);
- if ((dmafd = dup (gst_dmabuf_memory_get_fd (dma_mem[i]))) < 0)
- goto dup_failed;
+ dmafd = gst_dmabuf_memory_get_fd (dma_mem[i]);
- GST_LOG_OBJECT (allocator, "imported DMABUF as fd %i plane %d", dmafd, i);
+ GST_LOG_OBJECT (allocator, "[%i] imported DMABUF as fd %i plane %d",
+ group->buffer.index, dmafd, i);
mem = (GstV4l2Memory *) group->mem[i];
/* Update v4l2 structure */
group->planes[i].length = maxsize;
- group->planes[i].bytesused = size;
+ group->planes[i].bytesused = size + offset;
group->planes[i].m.fd = dmafd;
group->planes[i].data_offset = offset;
}
/* Copy into buffer structure if not using planes */
- if (!V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
+ if (!V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
group->buffer.bytesused = group->planes[0].bytesused;
group->buffer.length = group->planes[0].length;
group->buffer.m.fd = group->planes[0].m.userptr;
+
+ /* FIXME Check if data_offset > 0 and fail for non-multi-planar */
+ g_assert (group->planes[0].data_offset == 0);
} else {
group->buffer.length = group->n_mem;
}
GST_ERROR_OBJECT (allocator, "Memory %i is not of DMABUF", i);
return FALSE;
}
-dup_failed:
- {
- GST_ERROR_OBJECT (allocator, "Failed to dup DMABUF descriptor: %s",
- g_strerror (errno));
- return FALSE;
- }
}
gboolean
GstV4l2MemoryGroup * group, gsize img_size, int n_planes,
gpointer * data, gsize * size)
{
+ GstV4l2Object *obj = allocator->obj;
GstV4l2Memory *mem;
gint i;
g_return_val_if_fail (allocator->memory == V4L2_MEMORY_USERPTR, FALSE);
/* TODO Support passing N plane from 1 memory to MPLANE v4l2 format */
- if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type) && n_planes != group->n_mem)
+ if (V4L2_TYPE_IS_MULTIPLANAR (obj->type) && n_planes != group->n_mem)
goto n_mem_missmatch;
for (i = 0; i < group->n_mem; i++) {
gsize maxsize, psize;
- if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
- struct v4l2_pix_format_mplane *pix = &allocator->format.fmt.pix_mp;
- maxsize = pix->plane_fmt[i].sizeimage;
- psize = size[i];
- } else {
- maxsize = allocator->format.fmt.pix.sizeimage;
- psize = img_size;
- }
+ /* TODO request used size and maxsize seperatly */
+ if (V4L2_TYPE_IS_MULTIPLANAR (obj->type))
+ maxsize = psize = size[i];
+ else
+ maxsize = psize = img_size;
g_assert (psize <= img_size);
- GST_LOG_OBJECT (allocator, "imported USERPTR %p plane %d size %"
- G_GSIZE_FORMAT, data[i], i, psize);
+ GST_LOG_OBJECT (allocator, "[%i] imported USERPTR %p plane %d size %"
+ G_GSIZE_FORMAT, group->buffer.index, data[i], i, psize);
mem = (GstV4l2Memory *) group->mem[i];
}
/* Copy into buffer structure if not using planes */
- if (!V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
+ if (!V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
group->buffer.bytesused = group->planes[0].bytesused;
group->buffer.length = group->planes[0].length;
group->buffer.m.userptr = group->planes[0].m.userptr;
gst_v4l2_allocator_qbuf (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup * group)
{
+ GstV4l2Object *obj = allocator->obj;
gboolean ret = TRUE;
gint i;
g_return_val_if_fail (g_atomic_int_get (&allocator->active), FALSE);
/* update sizes */
- if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
+ if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
for (i = 0; i < group->n_mem; i++)
group->planes[i].bytesused =
gst_memory_get_sizes (group->mem[i], NULL, NULL);
group->buffer.bytesused = gst_memory_get_sizes (group->mem[0], NULL, NULL);
}
- if (v4l2_ioctl (allocator->video_fd, VIDIOC_QBUF, &group->buffer) < 0) {
+ /* Ensure the memory will stay around and is RO */
+ for (i = 0; i < group->n_mem; i++)
+ gst_memory_ref (group->mem[i]);
+
+ if (obj->ioctl (obj->video_fd, VIDIOC_QBUF, &group->buffer) < 0) {
GST_ERROR_OBJECT (allocator, "failed queueing buffer %i: %s",
group->buffer.index, g_strerror (errno));
+
+ /* Release the memory, possibly making it RW again */
+ for (i = 0; i < group->n_mem; i++)
+ gst_memory_unref (group->mem[i]);
+
ret = FALSE;
if (IS_QUEUED (group->buffer)) {
GST_DEBUG_OBJECT (allocator,
SET_QUEUED (group->buffer);
}
- /* Ensure the memory will stay around and is RO */
- for (i = 0; i < group->n_mem; i++)
- gst_memory_ref (group->mem[i]);
-
done:
return ret;
}
gst_v4l2_allocator_dqbuf (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup ** group_out)
{
+ GstV4l2Object *obj = allocator->obj;
struct v4l2_buffer buffer = { 0 };
struct v4l2_plane planes[VIDEO_MAX_PLANES] = { {0} };
gint i;
g_return_val_if_fail (g_atomic_int_get (&allocator->active), GST_FLOW_ERROR);
- buffer.type = allocator->type;
+ buffer.type = obj->type;
buffer.memory = allocator->memory;
- if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
- buffer.length = allocator->format.fmt.pix_mp.num_planes;
+ if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
+ buffer.length = obj->format.fmt.pix_mp.num_planes;
buffer.m.planes = planes;
}
- if (v4l2_ioctl (allocator->video_fd, VIDIOC_DQBUF, &buffer) < 0)
+ if (obj->ioctl (obj->video_fd, VIDIOC_DQBUF, &buffer) < 0)
goto error;
group = allocator->groups[buffer.index];
UNSET_QUEUED (group->buffer);
}
- if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
+ if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
group->buffer.m.planes = group->planes;
memcpy (group->planes, buffer.m.planes, sizeof (planes));
} else {
}
/* And update memory size */
- if (V4L2_TYPE_IS_OUTPUT (allocator->type)) {
+ if (V4L2_TYPE_IS_OUTPUT (obj->type)) {
gst_v4l2_allocator_reset_size (allocator, group);
} else {
/* for capture, simply read the size */
for (i = 0; i < group->n_mem; i++) {
- gst_memory_resize (group->mem[i], 0, group->planes[i].bytesused);
+ gsize size, offset;
+
+ GST_LOG_OBJECT (allocator,
+ "Dequeued capture buffer, length: %u bytesused: %u data_offset: %u",
+ group->planes[i].length, group->planes[i].bytesused,
+ group->planes[i].data_offset);
+
+ offset = group->planes[i].data_offset;
+
+ if (group->planes[i].bytesused > group->planes[i].data_offset) {
+ size = group->planes[i].bytesused - group->planes[i].data_offset;
+ } else {
+ GST_WARNING_OBJECT (allocator, "V4L2 provided buffer has bytesused %"
+ G_GUINT32_FORMAT " which is too small to include data_offset %"
+ G_GUINT32_FORMAT, group->planes[i].bytesused,
+ group->planes[i].data_offset);
+ size = group->planes[i].bytesused;
+ }
+
+ if (G_LIKELY (size + offset <= group->mem[i]->maxsize))
+ gst_memory_resize (group->mem[i], offset, size);
+ else {
+ GST_WARNING_OBJECT (allocator,
+ "v4l2 provided buffer that is too big for the memory it was "
+ "writing into. v4l2 claims %" G_GSIZE_FORMAT " bytes used but "
+ "memory is only %" G_GSIZE_FORMAT "B. This is probably a driver "
+ "bug.", size, group->mem[i]->maxsize);
+ gst_memory_resize (group->mem[i], 0, group->mem[i]->maxsize);
+ }
}
}