#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);
}
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);
}
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 */
gst_atomic_queue_unref (allocator->free_queue);
gst_object_unref (allocator->obj->element);
flags |= bcreate_flag;
}
+ if (breq.capabilities & V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS)
+ flags |= GST_V4L2_ALLOCATOR_FLAG_SUPPORTS_ORPHANED_BUFS;
+
return flags;
}
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 = obj->format;
bcreate.count = 1;
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)
{
- GstV4l2Object *obj = allocator->obj;
- gsize size;
- gboolean imported = FALSE;
-
- switch (allocator->memory) {
- case V4L2_MEMORY_USERPTR:
- case V4L2_MEMORY_DMABUF:
- imported = TRUE;
- break;
- }
-
- if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
- gint i;
-
- for (i = 0; i < group->n_mem; i++) {
- size = obj->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 = obj->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, GstV4l2Object * v4l2object)
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;
}
if (g_atomic_int_get (&allocator->active))
goto already_active;
+ if (GST_V4L2_ALLOCATOR_IS_ORPHANED (allocator))
+ goto orphaned;
+
if (obj->ioctl (obj->video_fd, VIDIOC_REQBUFS, &breq) < 0)
goto reqbufs_failed;
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,
gst_v4l2_memory_group_free (group);
}
- /* 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));
+ 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)
{
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);
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.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);
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;
}
+#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);
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;
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;
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;
}
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
for (i = 0; i < group->n_mem; i++) {
gsize maxsize, psize;
- if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
- struct v4l2_pix_format_mplane *pix = &obj->format.fmt.pix_mp;
- maxsize = pix->plane_fmt[i].sizeimage;
- psize = size[i];
- } else {
- maxsize = obj->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];
} else {
/* for capture, simply read the size */
for (i = 0; i < group->n_mem; i++) {
- if (G_LIKELY (group->planes[i].bytesused <= group->mem[i]->maxsize))
- 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_GUINT32_FORMAT " bytes used but "
+ "writing into. v4l2 claims %" G_GSIZE_FORMAT " bytes used but "
"memory is only %" G_GSIZE_FORMAT "B. This is probably a driver "
- "bug.", group->planes[i].bytesused, group->mem[i]->maxsize);
+ "bug.", size, group->mem[i]->maxsize);
gst_memory_resize (group->mem[i], 0, group->mem[i]->maxsize);
}
}