Example #1
0
int ff_v4l2_context_init(V4L2Context* ctx)
{
    V4L2m2mContext *s = ctx_to_m2mctx(ctx);
    struct v4l2_requestbuffers req;
    int ret, i;

    if (!v4l2_type_supported(ctx)) {
        av_log(logger(ctx), AV_LOG_ERROR, "type %i not supported\n", ctx->type);
        return AVERROR_PATCHWELCOME;
    }

    ret = ioctl(s->fd, VIDIOC_G_FMT, &ctx->format);
    if (ret)
        av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_G_FMT failed\n", ctx->name);

    memset(&req, 0, sizeof(req));
    req.count = ctx->num_buffers;
    req.memory = V4L2_MEMORY_MMAP;
    req.type = ctx->type;
    ret = ioctl(s->fd, VIDIOC_REQBUFS, &req);
    if (ret < 0)
        return AVERROR(errno);

    ctx->num_buffers = req.count;
    ctx->buffers = av_mallocz(ctx->num_buffers * sizeof(V4L2Buffer));
    if (!ctx->buffers) {
            av_log(logger(ctx), AV_LOG_ERROR, "%s malloc enomem\n", ctx->name);
            return AVERROR(ENOMEM);
    }

    for (i = 0; i < req.count; i++) {
        ctx->buffers[i].context = ctx;
        ret = ff_v4l2_buffer_initialize(&ctx->buffers[i], i);
        if (ret < 0) {
            av_log(logger(ctx), AV_LOG_ERROR, "%s buffer initialization (%s)\n", ctx->name, av_err2str(ret));
            av_free(ctx->buffers);
            return ret;
        }
    }

    av_log(logger(ctx), AV_LOG_DEBUG, "%s: %s %02d buffers initialized: %04ux%04u, sizeimage %08u, bytesperline %08u\n", ctx->name,
        V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? av_fourcc2str(ctx->format.fmt.pix_mp.pixelformat) : av_fourcc2str(ctx->format.fmt.pix.pixelformat),
        req.count,
        v4l2_get_width(&ctx->format),
        v4l2_get_height(&ctx->format),
        V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? ctx->format.fmt.pix_mp.plane_fmt[0].sizeimage : ctx->format.fmt.pix.sizeimage,
        V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? ctx->format.fmt.pix_mp.plane_fmt[0].bytesperline : ctx->format.fmt.pix.bytesperline);

    return 0;
}
Example #2
0
/**
 * __verify_length() - Verify that the bytesused value for each plane fits in
 * the plane length and that the data offset doesn't exceed the bytesused value.
 */
static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b)
{
	unsigned int length;
	unsigned int bytesused;
	unsigned int plane;

	if (!V4L2_TYPE_IS_OUTPUT(b->type))
		return 0;

	if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
		for (plane = 0; plane < vb->num_planes; ++plane) {
			length = (b->memory == VB2_MEMORY_USERPTR ||
				  b->memory == VB2_MEMORY_DMABUF)
			       ? b->m.planes[plane].length
				: vb->planes[plane].length;
			bytesused = b->m.planes[plane].bytesused
				  ? b->m.planes[plane].bytesused : length;

			if (b->m.planes[plane].bytesused > length)
				return -EINVAL;

			if (b->m.planes[plane].data_offset > 0 &&
			    b->m.planes[plane].data_offset >= bytesused)
				return -EINVAL;
		}
	} else {
		length = (b->memory == VB2_MEMORY_USERPTR)
			? b->length : vb->planes[0].length;

		if (b->bytesused > length)
			return -EINVAL;
	}

	return 0;
}
Example #3
0
/**
 * vb2_queue_init() - initialize a videobuf2 queue
 * @q:		videobuf2 queue; this structure should be allocated in driver
 *
 * The vb2_queue structure should be allocated by the driver. The driver is
 * responsible of clearing it's content and setting initial values for some
 * required entries before calling this function.
 * q->ops, q->mem_ops, q->type and q->io_modes are mandatory. Please refer
 * to the struct vb2_queue description in include/media/videobuf2-core.h
 * for more information.
 */
int vb2_queue_init(struct vb2_queue *q)
{
	/*
	 * Sanity check
	 */
	if (WARN_ON(!q)			  ||
	    WARN_ON(q->timestamp_flags &
		    ~(V4L2_BUF_FLAG_TIMESTAMP_MASK |
		      V4L2_BUF_FLAG_TSTAMP_SRC_MASK)))
		return -EINVAL;

	/* Warn that the driver should choose an appropriate timestamp type */
	WARN_ON((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==
		V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN);

	/* Warn that vb2_memory should match with v4l2_memory */
	if (WARN_ON(VB2_MEMORY_MMAP != (int)V4L2_MEMORY_MMAP)
		|| WARN_ON(VB2_MEMORY_USERPTR != (int)V4L2_MEMORY_USERPTR)
		|| WARN_ON(VB2_MEMORY_DMABUF != (int)V4L2_MEMORY_DMABUF))
		return -EINVAL;

	if (q->buf_struct_size == 0)
		q->buf_struct_size = sizeof(struct vb2_v4l2_buffer);

	q->buf_ops = &v4l2_buf_ops;
	q->is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(q->type);
	q->is_output = V4L2_TYPE_IS_OUTPUT(q->type);
	q->copy_timestamp = (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK)
			== V4L2_BUF_FLAG_TIMESTAMP_COPY;

	return vb2_core_queue_init(q);
}
static void
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);
  }
}
Example #5
0
static inline void v4l2_save_to_context(V4L2Context* ctx, struct v4l2_format_update *fmt)
{
    ctx->format.type = ctx->type;

    if (fmt->update_avfmt)
        ctx->av_pix_fmt = fmt->av_fmt;

    if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
        /* update the sizes to handle the reconfiguration of the capture stream at runtime */
        ctx->format.fmt.pix_mp.height = ctx->height;
        ctx->format.fmt.pix_mp.width = ctx->width;
        if (fmt->update_v4l2) {
            ctx->format.fmt.pix_mp.pixelformat = fmt->v4l2_fmt;

            /* s5p-mfc requires the user to specify a buffer size */
            ctx->format.fmt.pix_mp.plane_fmt[0].sizeimage =
                v4l2_get_framesize_compressed(ctx, ctx->width, ctx->height);
        }
    } else {
        ctx->format.fmt.pix.height = ctx->height;
        ctx->format.fmt.pix.width = ctx->width;
        if (fmt->update_v4l2) {
            ctx->format.fmt.pix.pixelformat = fmt->v4l2_fmt;

            /* s5p-mfc requires the user to specify a buffer size */
            ctx->format.fmt.pix.sizeimage =
                v4l2_get_framesize_compressed(ctx, ctx->width, ctx->height);
        }
    }
}
static void
gst_v4l2_allocator_clear_userptr (GstV4l2Allocator * allocator,
    GstV4l2MemoryGroup * group)
{
  GstV4l2Memory *mem;
  gint i;

  g_return_if_fail (allocator->memory == V4L2_MEMORY_USERPTR);

  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);

    mem->mem.maxsize = 0;
    mem->mem.size = 0;
    mem->data = NULL;

    group->planes[i].length = 0;
    group->planes[i].bytesused = 0;
    group->planes[i].m.userptr = 0;
  }

  if (!V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
    group->buffer.bytesused = 0;
    group->buffer.length = 0;
    group->buffer.m.userptr = 0;
  }
}
/**
 * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be
 * returned to userspace
 */
static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
{
	struct vb2_queue *q = vb->vb2_queue;
	int ret = 0;

	/* Copy back data such as timestamp, flags, input, etc. */
	memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m));
	b->input = vb->v4l2_buf.input;
	b->reserved = vb->v4l2_buf.reserved;

	if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) {
		ret = __verify_planes_array(vb, b);
		if (ret)
			return ret;

		/*
		 * Fill in plane-related data if userspace provided an array
		 * for it. The memory and size is verified above.
		 */
		memcpy(b->m.planes, vb->v4l2_planes,
			b->length * sizeof(struct v4l2_plane));
	} else {
		/*
		 * We use length and offset in v4l2_planes array even for
		 * single-planar buffers, but userspace does not.
		 */
		b->length = vb->v4l2_planes[0].length;
		b->bytesused = vb->v4l2_planes[0].bytesused;
		if (q->memory == V4L2_MEMORY_MMAP)
			b->m.offset = vb->v4l2_planes[0].m.mem_offset;
		else if (q->memory == V4L2_MEMORY_USERPTR)
			b->m.userptr = vb->v4l2_planes[0].m.userptr;
	}

	/*
	 * Clear any buffer state related flags.
	 */
	b->flags &= ~V4L2_BUFFER_STATE_FLAGS;

	switch (vb->state) {
	case VB2_BUF_STATE_QUEUED:
	case VB2_BUF_STATE_ACTIVE:
		b->flags |= V4L2_BUF_FLAG_QUEUED;
		break;
	case VB2_BUF_STATE_ERROR:
		b->flags |= V4L2_BUF_FLAG_ERROR;
		/* fall through */
	case VB2_BUF_STATE_DONE:
		b->flags |= V4L2_BUF_FLAG_DONE;
		break;
	case VB2_BUF_STATE_DEQUEUED:
		/* nothing */
		break;
	}

	if (vb->num_planes_mapped == vb->num_planes)
		b->flags |= V4L2_BUF_FLAG_MAPPED;

	return ret;
}
/**
 * __fill_vb2_buffer() - fill a vb2_buffer with information provided in
 * a v4l2_buffer by the userspace
 */
static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b,
				struct v4l2_plane *v4l2_planes)
{
	unsigned int plane;
	int ret;

	if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
		/*
		 * Verify that the userspace gave us a valid array for
		 * plane information.
		 */
		ret = __verify_planes_array(vb, b);
		if (ret)
			return ret;

		/* Fill in driver-provided information for OUTPUT types */
		if (V4L2_TYPE_IS_OUTPUT(b->type)) {
			/*
			 * Will have to go up to b->length when API starts
			 * accepting variable number of planes.
			 */
			for (plane = 0; plane < vb->num_planes; ++plane) {
				v4l2_planes[plane].bytesused =
					b->m.planes[plane].bytesused;
				v4l2_planes[plane].data_offset =
					b->m.planes[plane].data_offset;
			}
		}

		if (b->memory == V4L2_MEMORY_USERPTR) {
			for (plane = 0; plane < vb->num_planes; ++plane) {
				v4l2_planes[plane].m.userptr =
					b->m.planes[plane].m.userptr;
				v4l2_planes[plane].length =
					b->m.planes[plane].length;
			}
		}
	} else {
		/*
		 * Single-planar buffers do not use planes array,
		 * so fill in relevant v4l2_buffer struct fields instead.
		 * In videobuf we use our internal V4l2_planes struct for
		 * single-planar buffers as well, for simplicity.
		 */
		if (V4L2_TYPE_IS_OUTPUT(b->type))
			v4l2_planes[0].bytesused = b->bytesused;

		if (b->memory == V4L2_MEMORY_USERPTR) {
			v4l2_planes[0].m.userptr = b->m.userptr;
			v4l2_planes[0].length = b->length;
		}
	}

	vb->v4l2_buf.field = b->field;
	vb->v4l2_buf.timestamp = b->timestamp;
	vb->v4l2_buf.input = b->input;
	vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS;

	return 0;
}
Example #9
0
static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory,
			     unsigned int num_buffers, unsigned int num_planes,
			     unsigned long plane_sizes[])
{
	unsigned int buffer;
	struct vb2_buffer *vb;
	int ret;

	for (buffer = 0; buffer < num_buffers; ++buffer) {
		
		vb = kzalloc(q->buf_struct_size, GFP_KERNEL);
		if (!vb) {
			dprintk(1, "Memory alloc for buffer struct failed\n");
			break;
		}

		
		if (V4L2_TYPE_IS_MULTIPLANAR(q->type))
			vb->v4l2_buf.length = num_planes;

		vb->state = VB2_BUF_STATE_DEQUEUED;
		vb->vb2_queue = q;
		vb->num_planes = num_planes;
		vb->v4l2_buf.index = buffer;
		vb->v4l2_buf.type = q->type;
		vb->v4l2_buf.memory = memory;

		
		if (memory == V4L2_MEMORY_MMAP) {
			ret = __vb2_buf_mem_alloc(vb, plane_sizes);
			if (ret) {
				dprintk(1, "Failed allocating memory for "
						"buffer %d\n", buffer);
				kfree(vb);
				break;
			}
			ret = call_qop(q, buf_init, vb);
			if (ret) {
				dprintk(1, "Buffer %d %p initialization"
					" failed\n", buffer, vb);
				__vb2_buf_mem_free(vb);
				kfree(vb);
				break;
			}
		}

		q->bufs[buffer] = vb;
	}

	q->num_buffers = buffer;

	__setup_offsets(q);

	dprintk(1, "Allocated %d buffers, %d plane(s) each\n",
			q->num_buffers, num_planes);

	return buffer;
}
Example #10
0
bool v4l2::s_fmt(v4l2_format &fmt)
{
	if (V4L2_TYPE_IS_MULTIPLANAR(fmt.type)) {
		fmt.fmt.pix_mp.plane_fmt[0].bytesperline = 0;
		fmt.fmt.pix_mp.plane_fmt[1].bytesperline = 0;
	} else {
		fmt.fmt.pix.bytesperline = 0;
	}
	return ioctl("Set Capture Format", VIDIOC_S_FMT, &fmt);
}
Example #11
0
static inline void v4l2_set_timeperframe(V4L2m2mContext *s, unsigned int num, unsigned int den)
{
    struct v4l2_streamparm parm = { 0 };

    parm.type = V4L2_TYPE_IS_MULTIPLANAR(s->output.type) ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : V4L2_BUF_TYPE_VIDEO_OUTPUT;
    parm.parm.output.timeperframe.denominator = den;
    parm.parm.output.timeperframe.numerator = num;

    if (ioctl(s->fd, VIDIOC_S_PARM, &parm) < 0)
        av_log(s->avctx, AV_LOG_WARNING, "Failed to set timeperframe");
}
gboolean
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 (obj->type)) {
    for (i = 0; i < group->n_mem; i++)
      group->planes[i].bytesused =
          gst_memory_get_sizes (group->mem[i], NULL, NULL);
  } else {
    group->buffer.bytesused = gst_memory_get_sizes (group->mem[0], NULL, NULL);
  }

  /* 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,
          "driver pretends buffer is queued even if queue failed");
      UNSET_QUEUED (group->buffer);
    }
    goto done;
  }

  GST_LOG_OBJECT (allocator, "queued buffer %i (flags 0x%X)",
      group->buffer.index, group->buffer.flags);

  if (!IS_QUEUED (group->buffer)) {
    GST_DEBUG_OBJECT (allocator,
        "driver pretends buffer is not queued even if queue succeeded");
    SET_QUEUED (group->buffer);
  }

done:
  return ret;
}
Example #13
0
static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
{
	struct vb2_queue *q = vb->vb2_queue;
	int ret = 0;

	
	memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m));
	b->input = vb->v4l2_buf.input;
	b->reserved = vb->v4l2_buf.reserved;

	if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) {
		ret = __verify_planes_array(vb, b);
		if (ret)
			return ret;

		memcpy(b->m.planes, vb->v4l2_planes,
			b->length * sizeof(struct v4l2_plane));
	} else {
		b->length = vb->v4l2_planes[0].length;
		b->bytesused = vb->v4l2_planes[0].bytesused;
		if (q->memory == V4L2_MEMORY_MMAP)
			b->m.offset = vb->v4l2_planes[0].m.mem_offset;
		else if (q->memory == V4L2_MEMORY_USERPTR)
			b->m.userptr = vb->v4l2_planes[0].m.userptr;
	}

	b->flags &= ~V4L2_BUFFER_STATE_FLAGS;

	switch (vb->state) {
	case VB2_BUF_STATE_QUEUED:
	case VB2_BUF_STATE_ACTIVE:
		b->flags |= V4L2_BUF_FLAG_QUEUED;
		break;
	case VB2_BUF_STATE_ERROR:
		b->flags |= V4L2_BUF_FLAG_ERROR;
		
	case VB2_BUF_STATE_DONE:
		b->flags |= V4L2_BUF_FLAG_DONE;
		break;
	case VB2_BUF_STATE_DEQUEUED:
		
		break;
	}

	if (vb->num_planes_mapped == vb->num_planes)
		b->flags |= V4L2_BUF_FLAG_MAPPED;

	return ret;
}
Example #14
0
static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b,
				struct v4l2_plane *v4l2_planes)
{
	unsigned int plane;
	int ret;

	if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
		ret = __verify_planes_array(vb, b);
		if (ret)
			return ret;

		
		if (V4L2_TYPE_IS_OUTPUT(b->type)) {
			for (plane = 0; plane < vb->num_planes; ++plane) {
				v4l2_planes[plane].bytesused =
					b->m.planes[plane].bytesused;
				v4l2_planes[plane].data_offset =
					b->m.planes[plane].data_offset;
			}
		}

		if (b->memory == V4L2_MEMORY_USERPTR) {
			for (plane = 0; plane < vb->num_planes; ++plane) {
				v4l2_planes[plane].m.userptr =
					b->m.planes[plane].m.userptr;
				v4l2_planes[plane].length =
					b->m.planes[plane].length;
			}
		}
	} else {
		if (V4L2_TYPE_IS_OUTPUT(b->type))
			v4l2_planes[0].bytesused = b->bytesused;

		if (b->memory == V4L2_MEMORY_USERPTR) {
			v4l2_planes[0].m.userptr = b->m.userptr;
			v4l2_planes[0].length = b->length;
		}
	}

	vb->v4l2_buf.field = b->field;
	vb->v4l2_buf.timestamp = b->timestamp;
	vb->v4l2_buf.input = b->input;
	vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS;

	return 0;
}
Example #15
0
static inline unsigned int v4l2_resolution_changed(V4L2Context *ctx, struct v4l2_format *fmt2)
{
    struct v4l2_format *fmt1 = &ctx->format;
    int ret =  V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ?
        fmt1->fmt.pix_mp.width != fmt2->fmt.pix_mp.width ||
        fmt1->fmt.pix_mp.height != fmt2->fmt.pix_mp.height
        :
        fmt1->fmt.pix.width != fmt2->fmt.pix.width ||
        fmt1->fmt.pix.height != fmt2->fmt.pix.height;

    if (ret)
        av_log(logger(ctx), AV_LOG_DEBUG, "%s changed (%dx%d) -> (%dx%d)\n",
            ctx->name,
            v4l2_get_width(fmt1), v4l2_get_height(fmt1),
            v4l2_get_width(fmt2), v4l2_get_height(fmt2));

    return ret;
}
Example #16
0
/**
 * __verify_planes_array() - verify that the planes array passed in struct
 * v4l2_buffer from userspace can be safely used
 */
static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b)
{
	if (!V4L2_TYPE_IS_MULTIPLANAR(b->type))
		return 0;

	/* Is memory for copying plane information present? */
	if (b->m.planes == NULL) {
		dprintk(1, "multi-planar buffer passed but planes array not provided\n");
		return -EINVAL;
	}

	if (b->length < vb->num_planes || b->length > VB2_MAX_PLANES) {
		dprintk(1, "incorrect planes array length, expected %d, got %d\n",
			vb->num_planes, b->length);
		return -EINVAL;
	}

	return 0;
}
static void
gst_v4l2_allocator_clear_dmabufin (GstV4l2Allocator * allocator,
    GstV4l2MemoryGroup * group)
{
  GstV4l2Object *obj = allocator->obj;
  GstV4l2Memory *mem;
  gint i;

  g_return_if_fail (allocator->memory == V4L2_MEMORY_DMABUF);

  for (i = 0; i < group->n_mem; 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);

    /* Update memory */
    mem->mem.maxsize = 0;
    mem->mem.offset = 0;
    mem->mem.size = 0;
    mem->dmafd = -1;

    /* Update v4l2 structure */
    group->planes[i].length = 0;
    group->planes[i].bytesused = 0;
    group->planes[i].m.fd = -1;
    group->planes[i].data_offset = 0;
  }

  if (!V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
    group->buffer.bytesused = 0;
    group->buffer.length = 0;
    group->buffer.m.fd = -1;
  }
}
Example #18
0
bool v4l2::qbuf_user(int index, __u32 buftype, void *ptr[], size_t length[])
{
	v4l2_plane planes[VIDEO_MAX_PLANES];
	v4l2_buffer buf;

	memset(&buf, 0, sizeof(buf));
	buf.type = buftype;
	buf.memory = V4L2_MEMORY_USERPTR;
	if (V4L2_TYPE_IS_MULTIPLANAR(buftype)) {
		buf.length = 2;
		buf.m.planes = planes;
		planes[0].length = length[0];
		planes[0].m.userptr = (unsigned long)ptr[0];
		planes[1].length = length[1];
		planes[1].m.userptr = (unsigned long)ptr[1];
	} else {
		buf.m.userptr = (unsigned long)ptr[0];
		buf.length = length[0];
	}
	buf.index = index;
	return qbuf(buf);
}
Example #19
0
/**
 * vb2_queue_init() - initialize a videobuf2 queue
 * @q:		videobuf2 queue; this structure should be allocated in driver
 *
 * The vb2_queue structure should be allocated by the driver. The driver is
 * responsible of clearing it's content and setting initial values for some
 * required entries before calling this function.
 * q->ops, q->mem_ops, q->type and q->io_modes are mandatory. Please refer
 * to the struct vb2_queue description in include/media/videobuf2-core.h
 * for more information.
 */
int vb2_queue_init(struct vb2_queue *q)
{
	/*
	 * Sanity check
	 */
	if (WARN_ON(!q)			  ||
	    WARN_ON(q->timestamp_flags &
		    ~(V4L2_BUF_FLAG_TIMESTAMP_MASK |
		      V4L2_BUF_FLAG_TSTAMP_SRC_MASK)))
		return -EINVAL;

	/* Warn that the driver should choose an appropriate timestamp type */
	WARN_ON((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==
		V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN);

	/* Warn that vb2_memory should match with v4l2_memory */
	if (WARN_ON(VB2_MEMORY_MMAP != (int)V4L2_MEMORY_MMAP)
		|| WARN_ON(VB2_MEMORY_USERPTR != (int)V4L2_MEMORY_USERPTR)
		|| WARN_ON(VB2_MEMORY_DMABUF != (int)V4L2_MEMORY_DMABUF))
		return -EINVAL;

	if (q->buf_struct_size == 0)
		q->buf_struct_size = sizeof(struct vb2_v4l2_buffer);

	q->buf_ops = &v4l2_buf_ops;
	q->is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(q->type);
	q->is_output = V4L2_TYPE_IS_OUTPUT(q->type);
	q->copy_timestamp = (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK)
			== V4L2_BUF_FLAG_TIMESTAMP_COPY;
	/*
	 * For compatibility with vb1: if QBUF hasn't been called yet, then
	 * return POLLERR as well. This only affects capture queues, output
	 * queues will always initialize waiting_for_buffers to false.
	 */
	q->quirk_poll_must_check_waiting_for_buffers = true;

	return vb2_core_queue_init(q);
}
Example #20
0
/**
 * v4l2_m2m_querybuf() - multi-queue-aware QUERYBUF multiplexer
 *
 * See v4l2_m2m_mmap() documentation for details.
 */
int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
		      struct v4l2_buffer *buf)
{
	struct vb2_queue *vq;
	int ret = 0;
	unsigned int i;

	vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
	ret = vb2_querybuf(vq, buf);

	/* Adjust MMAP memory offsets for the CAPTURE queue */
	if (buf->memory == V4L2_MEMORY_MMAP && !V4L2_TYPE_IS_OUTPUT(vq->type)) {
		if (V4L2_TYPE_IS_MULTIPLANAR(vq->type)) {
			for (i = 0; i < buf->length; ++i)
				buf->m.planes[i].m.mem_offset
					+= DST_QUEUE_OFF_BASE;
		} else {
			buf->m.offset += DST_QUEUE_OFF_BASE;
		}
	}

	return ret;
}
Example #21
0
int rot_v4l2_try_fmt_mplane(struct file *file, void *priv,
			    struct v4l2_format *f)
{
	struct rot_ctx *ctx = priv;
	struct rot_fmt *rot_fmt;
	struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
	int i;

	if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) {
		rot_err("not supported format type\n");
		return -EINVAL;
	}

	rot_fmt = rot_find_format(f);
	if (!rot_fmt) {
		rot_err("not supported format values\n");
		return -EINVAL;
	}

	rot_bound_align_image(ctx, rot_fmt, &pixm->width, &pixm->height);

	pixm->num_planes = rot_fmt->num_planes;
	pixm->colorspace = 0;

	for (i = 0; i < pixm->num_planes; ++i) {
		pixm->plane_fmt[i].bytesperline = (pixm->width *
				rot_fmt->bitperpixel[i]) >> 3;
		pixm->plane_fmt[i].sizeimage = pixm->plane_fmt[i].bytesperline
				* pixm->height;

		rot_dbg("[%d] plane: bytesperline %d, sizeimage %d\n", i,
				pixm->plane_fmt[i].bytesperline,
				pixm->plane_fmt[i].sizeimage);
	}

	return 0;
}
/**
 * __vb2_queue_alloc() - allocate videobuf buffer structures and (for MMAP type)
 * video buffer memory for all buffers/planes on the queue and initializes the
 * queue
 *
 * Returns the number of buffers successfully allocated.
 */
static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory,
			     unsigned int num_buffers, unsigned int num_planes,
			     unsigned long plane_sizes[])
{
	unsigned int buffer;
	struct vb2_buffer *vb;
	int ret;

	for (buffer = 0; buffer < num_buffers; ++buffer) {
		/* Allocate videobuf buffer structures */
		vb = kzalloc(q->buf_struct_size, GFP_KERNEL);
		if (!vb) {
			dprintk(1, "Memory alloc for buffer struct failed\n");
			break;
		}

		/* Length stores number of planes for multiplanar buffers */
		if (V4L2_TYPE_IS_MULTIPLANAR(q->type))
			vb->v4l2_buf.length = num_planes;

		vb->state = VB2_BUF_STATE_DEQUEUED;
		vb->vb2_queue = q;
		vb->num_planes = num_planes;
		vb->v4l2_buf.index = buffer;
		vb->v4l2_buf.type = q->type;
		vb->v4l2_buf.memory = memory;

		/* Allocate video buffer memory for the MMAP type */
		if (memory == V4L2_MEMORY_MMAP) {
			ret = __vb2_buf_mem_alloc(vb, plane_sizes);
			if (ret) {
				dprintk(1, "Failed allocating memory for "
						"buffer %d\n", buffer);
				kfree(vb);
				break;
			}
			/*
			 * Call the driver-provided buffer initialization
			 * callback, if given. An error in initialization
			 * results in queue setup failure.
			 */
			ret = call_qop(q, buf_init, vb);
			if (ret) {
				dprintk(1, "Buffer %d %p initialization"
					" failed\n", buffer, vb);
				__vb2_buf_mem_free(vb);
				kfree(vb);
				break;
			}
		}

		q->bufs[buffer] = vb;
	}

	q->num_buffers = buffer;

	__setup_offsets(q);

	dprintk(1, "Allocated %d buffers, %d plane(s) each\n",
			q->num_buffers, num_planes);

	return buffer;
}
Example #23
0
static inline unsigned int v4l2_get_height(struct v4l2_format *fmt)
{
    return V4L2_TYPE_IS_MULTIPLANAR(fmt->type) ? fmt->fmt.pix_mp.height : fmt->fmt.pix.height;
}
GstV4l2MemoryGroup *
gst_v4l2_allocator_dqbuf (GstV4l2Allocator * allocator)
{
  struct v4l2_buffer buffer = { 0 };
  struct v4l2_plane planes[VIDEO_MAX_PLANES] = { {0} };
  gint i;

  GstV4l2MemoryGroup *group = NULL;

  g_return_val_if_fail (g_atomic_int_get (&allocator->active), FALSE);

  buffer.type = allocator->type;
  buffer.memory = allocator->memory;

  if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
    buffer.length = allocator->format.fmt.pix_mp.num_planes;
    buffer.m.planes = planes;
  }

  if (v4l2_ioctl (allocator->video_fd, VIDIOC_DQBUF, &buffer) < 0)
    goto error;

  group = allocator->groups[buffer.index];

  if (!IS_QUEUED (group->buffer)) {
    GST_ERROR_OBJECT (allocator,
        "buffer %i was not queued, this indicate a driver bug.", buffer.index);
    return NULL;
  }

  group->buffer = buffer;

  GST_LOG_OBJECT (allocator, "dequeued buffer %i (flags 0x%X)", buffer.index,
      buffer.flags);

  if (IS_QUEUED (group->buffer)) {
    GST_DEBUG_OBJECT (allocator,
        "driver pretends buffer is queued even if dequeue succeeded");
    UNSET_QUEUED (group->buffer);
  }

  if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
    group->buffer.m.planes = group->planes;
    memcpy (group->planes, buffer.m.planes, sizeof (planes));
  } else {
    group->planes[0].bytesused = group->buffer.bytesused;
    group->planes[0].length = group->buffer.length;
    g_assert (sizeof (group->planes[0].m) == sizeof (group->buffer.m));
    memcpy (&group->planes[0].m, &group->buffer.m, sizeof (group->buffer.m));
  }

  /* And update memory size */
  if (V4L2_TYPE_IS_OUTPUT (allocator->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);
    }
  }

  /* Release the memory, possibly making it RW again */
  for (i = 0; i < group->n_mem; i++)
    gst_memory_unref (group->mem[i]);

  return group;

error:
  GST_ERROR_OBJECT (allocator, "failed dequeuing a %s buffer: %s",
      memory_type_to_str (allocator->memory), g_strerror (errno));

  switch (errno) {
    case EAGAIN:
      GST_WARNING_OBJECT (allocator,
          "Non-blocking I/O has been selected using O_NONBLOCK and"
          " no buffer was in the outgoing queue.");
      break;
    case EINVAL:
      GST_ERROR_OBJECT (allocator,
          "The buffer type is not supported, or the index is out of bounds, "
          "or no buffers have been allocated yet, or the userptr "
          "or length are invalid.");
      break;
    case ENOMEM:
      GST_ERROR_OBJECT (allocator,
          "insufficient memory to enqueue a user pointer buffer");
      break;
    case EIO:
      GST_INFO_OBJECT (allocator,
          "VIDIOC_DQBUF failed due to an internal error."
          " Can also indicate temporary problems like signal loss."
          " Note the driver might dequeue an (empty) buffer despite"
          " returning an error, or even stop capturing.");
      /* have we de-queued a buffer ? */
      if (!IS_QUEUED (buffer)) {
        GST_DEBUG_OBJECT (allocator, "reenqueing buffer");
        /* FIXME ... should we do something here? */
      }
      break;
    case EINTR:
      GST_WARNING_OBJECT (allocator, "could not sync on a buffer on device");
      break;
    default:
      GST_WARNING_OBJECT (allocator,
          "Grabbing frame got interrupted unexpectedly. %d: %s.", errno,
          g_strerror (errno));
      break;
  }

  return NULL;
}
static GstV4l2MemoryGroup *
gst_v4l2_memory_group_new (GstV4l2Allocator * allocator, guint32 index)
{
  gint video_fd = allocator->video_fd;
  guint32 memory = allocator->memory;
  struct v4l2_format *format = &allocator->format;
  GstV4l2MemoryGroup *group;
  gsize img_size, buf_size;

  group = g_slice_new0 (GstV4l2MemoryGroup);

  group->buffer.type = format->type;
  group->buffer.index = index;
  group->buffer.memory = memory;

  if (V4L2_TYPE_IS_MULTIPLANAR (format->type)) {
    group->n_mem = group->buffer.length = format->fmt.pix_mp.num_planes;
    group->buffer.m.planes = group->planes;
  } else {
    group->n_mem = 1;
  }

  if (v4l2_ioctl (video_fd, VIDIOC_QUERYBUF, &group->buffer) < 0)
    goto querybuf_failed;

  if (group->buffer.index != index) {
    GST_ERROR_OBJECT (allocator, "Buffer index returned by VIDIOC_QUERYBUF "
        "didn't match, this indicate the presence of a bug in your driver or "
        "libv4l2");
    g_slice_free (GstV4l2MemoryGroup, group);
    return NULL;
  }

  /* 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)) {
    gint i;

    for (i = 0; i < group->n_mem; i++) {
      img_size = allocator->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;
    buf_size = group->buffer.length;
    if (buf_size < img_size)
      goto buffer_too_short;
  }

  /* We save non planar buffer information into the multi-planar plane array
   * to avoid duplicating the code later */
  if (!V4L2_TYPE_IS_MULTIPLANAR (format->type)) {
    group->planes[0].bytesused = group->buffer.bytesused;
    group->planes[0].length = group->buffer.length;
    g_assert (sizeof (group->planes[0].m) == sizeof (group->buffer.m));
    memcpy (&group->planes[0].m, &group->buffer.m, sizeof (group->buffer.m));
  }

  GST_LOG_OBJECT (allocator, "Got %s buffer", memory_type_to_str (memory));
  GST_LOG_OBJECT (allocator, "  index:     %u", group->buffer.index);
  GST_LOG_OBJECT (allocator, "  type:      %d", group->buffer.type);
  GST_LOG_OBJECT (allocator, "  flags:     %08x", group->buffer.flags);
  GST_LOG_OBJECT (allocator, "  field:     %d", group->buffer.field);
  GST_LOG_OBJECT (allocator, "  memory:    %d", group->buffer.memory);
  GST_LOG_OBJECT (allocator, "  planes:    %d", group->n_mem);

#ifndef GST_DISABLE_GST_DEBUG
  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] MMAP offset:  %u", i,
          group->planes[i].m.mem_offset);
    }
  }
#endif

  return group;

querybuf_failed:
  {
    GST_ERROR ("error querying buffer %d: %s", index, g_strerror (errno));
    goto failed;
  }
buffer_too_short:
  {
    GST_ERROR ("buffer size %" G_GSIZE_FORMAT
        " is smaller then negotiated size %" G_GSIZE_FORMAT
        ", this is usually the result of a bug in the v4l2 driver or libv4l.",
        buf_size, img_size);
    goto failed;
  }
failed:
  gst_v4l2_memory_group_free (group);
  return NULL;
}
gboolean
gst_v4l2_allocator_import_userptr (GstV4l2Allocator * allocator,
    GstV4l2MemoryGroup * group, gsize img_size, int n_planes,
    gpointer * data, gsize * size)
{
  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)
    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;
    }

    g_assert (psize <= img_size);

    GST_LOG_OBJECT (allocator, "imported USERPTR %p plane %d size %"
        G_GSIZE_FORMAT, data[i], i, psize);

    mem = (GstV4l2Memory *) group->mem[i];

    mem->mem.maxsize = maxsize;
    mem->mem.size = psize;
    mem->data = data[i];

    group->planes[i].length = maxsize;
    group->planes[i].bytesused = psize;
    group->planes[i].m.userptr = (unsigned long) data[i];
    group->planes[i].data_offset = 0;
  }

  /* Copy into buffer structure if not using planes */
  if (!V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
    group->buffer.bytesused = group->planes[0].bytesused;
    group->buffer.length = group->planes[0].length;
    group->buffer.m.userptr = group->planes[0].m.userptr;
  } else {
    group->buffer.length = group->n_mem;
  }

  return TRUE;

n_mem_missmatch:
  {
    GST_ERROR_OBJECT (allocator, "Got %i userptr plane while driver need %i",
        n_planes, group->n_mem);
    return FALSE;
  }
}
gboolean
gst_v4l2_allocator_import_dmabuf (GstV4l2Allocator * allocator,
    GstV4l2MemoryGroup * group, gint n_mem, GstMemory ** dma_mem)
{
  GstV4l2Memory *mem;
  gint i;

  g_return_val_if_fail (allocator->memory == V4L2_MEMORY_DMABUF, FALSE);

  if (group->n_mem != n_mem)
    goto n_mem_missmatch;

  for (i = 0; i < group->n_mem; i++) {
    gint dmafd;
    gsize size, offset, maxsize;

    if (!gst_is_dmabuf_memory (dma_mem[i]))
      goto not_dmabuf;

    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;

    GST_LOG_OBJECT (allocator, "imported DMABUF as fd %i plane %d", dmafd, i);

    mem = (GstV4l2Memory *) group->mem[i];

    /* Update memory */
    mem->mem.maxsize = maxsize;
    mem->mem.offset = offset;
    mem->mem.size = size;
    mem->dmafd = dmafd;

    /* Update v4l2 structure */
    group->planes[i].length = maxsize;
    group->planes[i].bytesused = size;
    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)) {
    group->buffer.bytesused = group->planes[0].bytesused;
    group->buffer.length = group->planes[0].length;
    group->buffer.m.fd = group->planes[0].m.userptr;
  } else {
    group->buffer.length = group->n_mem;
  }

  return TRUE;

n_mem_missmatch:
  {
    GST_ERROR_OBJECT (allocator, "Got %i dmabuf but needed %i", n_mem,
        group->n_mem);
    return FALSE;
  }
not_dmabuf:
  {
    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;
  }
}
int fimc_is_video_s_ctrl(struct file *file,
	struct fimc_is_video_ctx *vctx,
	struct v4l2_control *ctrl)
{
	int ret = 0;
	/* hack for 64bit addr */
	ulong value_to_addr = 0;
	struct fimc_is_video *video;
	struct fimc_is_device_ischain *device;
	struct fimc_is_resourcemgr *resourcemgr;

	BUG_ON(!vctx);
	BUG_ON(!GET_DEVICE(vctx));
	BUG_ON(!GET_VIDEO(vctx));
	BUG_ON(!ctrl);

	device = GET_DEVICE(vctx);
	video = GET_VIDEO(vctx);
	resourcemgr = device->resourcemgr;

	switch (ctrl->id) {
	case V4L2_CID_IS_END_OF_STREAM:
		ret = fimc_is_ischain_open_wrap(device, true);
		if (ret) {
			merr("fimc_is_ischain_open_wrap is fail(%d)", device, ret);
			goto p_err;
		}
		break;
	case V4L2_CID_IS_SET_SETFILE:
		if (test_bit(FIMC_IS_ISCHAIN_START, &device->state)) {
			merr("device is already started, setfile applying is fail", device);
			ret = -EINVAL;
			goto p_err;
		}

		device->setfile = ctrl->value;
		break;
	case V4L2_CID_IS_HAL_VERSION:
		if (ctrl->value < 0 || ctrl->value >= IS_HAL_VER_MAX) {
			merr("hal version(%d) is invalid", device, ctrl->value);
			ret = -EINVAL;
			goto p_err;
		}
		resourcemgr->hal_version = ctrl->value;
		break;
	case V4L2_CID_IS_DEBUG_DUMP:
		info("Print fimc-is info dump by HAL");
		fimc_is_hw_logdump(device->interface);
		fimc_is_hw_regdump(device->interface);
		CALL_POPS(device, print_clk);

		if (ctrl->value)
			panic("intentional panic from camera HAL");
		break;
	case V4L2_CID_IS_DVFS_CLUSTER0:
	case V4L2_CID_IS_DVFS_CLUSTER1:
		fimc_is_resource_ioctl(resourcemgr, ctrl);
		break;
	case V4L2_CID_IS_DEBUG_SYNC_LOG:
		fimc_is_logsync(device->interface, ctrl->value, IS_MSG_TEST_SYNC_LOG);
		break;
	case V4L2_CID_IS_MAP_BUFFER:
		{
			struct fimc_is_queue *queue;
			struct fimc_is_framemgr *framemgr;
			struct fimc_is_frame *frame;
			struct dma_buf *dmabuf;
			struct dma_buf_attachment *attachment;
			dma_addr_t dva;
			struct v4l2_buffer *buf;
			struct v4l2_plane *planes;
			size_t size;
			u32 plane, group_id;

			size = sizeof(struct v4l2_buffer);
			buf = kmalloc(size, GFP_KERNEL);
			if (!buf) {
				mverr("kmalloc is fail(%p)", device, video, buf);
				ret = -EINVAL;
				goto p_err;
			}
			/* hack for 64bit addr */
			value_to_addr = ctrl->value;

			ret = copy_from_user(buf, (void __user *)value_to_addr, size);
			if (ret) {
				mverr("copy_from_user is fail(%d)", device, video, ret);
				kfree(buf);
				ret = -EINVAL;
				goto p_err;
			}

			if (!V4L2_TYPE_IS_OUTPUT(buf->type)) {
				mverr("capture video type is not supported", device, video);
				kfree(buf);
				ret = -EINVAL;
				goto p_err;
			}

			if (!V4L2_TYPE_IS_MULTIPLANAR(buf->type)) {
				mverr("single plane is not supported", device, video);
				kfree(buf);
				ret = -EINVAL;
				goto p_err;
			}

			if (buf->index >= FRAMEMGR_MAX_REQUEST) {
				mverr("buffer index is invalid(%d)", device, video, buf->index);
				kfree(buf);
				ret = -EINVAL;
				goto p_err;
			}

			if (buf->length > VIDEO_MAX_PLANES) {
				mverr("planes[%d] is invalid", device, video, buf->length);
				kfree(buf);
				ret = -EINVAL;
				goto p_err;
			}

			queue = GET_QUEUE(vctx);
			if (queue->vbq->memory != V4L2_MEMORY_DMABUF) {
				mverr("memory type(%d) is not supported", device, video, queue->vbq->memory);
				kfree(buf);
				ret = -EINVAL;
				goto p_err;
			}

			size = sizeof(struct v4l2_plane) * buf->length;
			planes = kmalloc(size, GFP_KERNEL);
			if (!planes) {
				mverr("kmalloc is fail(%p)", device, video, planes);
				kfree(buf);
				ret = -EINVAL;
				goto p_err;
			}

			ret = copy_from_user(planes, (void __user *)buf->m.planes, size);
			if (ret) {
				mverr("copy_from_user is fail(%d)", device, video, ret);
				kfree(planes);
				kfree(buf);
				ret = -EINVAL;
				goto p_err;
			}

			framemgr = &queue->framemgr;
			frame = &framemgr->frame[buf->index];
			if (test_bit(FRAME_MAP_MEM, &frame->memory)) {
				mverr("this buffer(%d) is already mapped", device, video, buf->index);
				kfree(planes);
				kfree(buf);
				ret = -EINVAL;
				goto p_err;
			}

			/* only last buffer need to map */
			if (buf->length <= 1) {
				mverr("this buffer(%d) have no meta plane", device, video, buf->length);
				kfree(planes);
				kfree(buf);
				ret = -EINVAL;
				goto p_err;
			}

			plane = buf->length - 1;
			dmabuf = dma_buf_get(planes[plane].m.fd);
			if (IS_ERR(dmabuf)) {
				mverr("dma_buf_get is fail(%p)", device, video, dmabuf);
				kfree(planes);
				kfree(buf);
				ret = -EINVAL;
				goto p_err;
			}

			attachment = dma_buf_attach(dmabuf, &device->pdev->dev);
			if (IS_ERR(attachment)) {
				mverr("dma_buf_attach is fail(%p)", device, video, attachment);
				kfree(planes);
				kfree(buf);
				dma_buf_put(dmabuf);
				ret = -EINVAL;
				goto p_err;
			}

			/* only support output(read) video node */
			dva = ion_iovmm_map(attachment, 0, dmabuf->size, 0, plane);
			if (IS_ERR_VALUE(dva)) {
				mverr("ion_iovmm_map is fail(%pa)", device, video, &dva);
				kfree(planes);
				kfree(buf);
				dma_buf_detach(dmabuf, attachment);
				dma_buf_put(dmabuf);
				ret = -EINVAL;
				goto p_err;
			}

			group_id = GROUP_ID(device->group_3aa.id);
			ret = fimc_is_itf_map(device, group_id, dva, dmabuf->size);
			if (ret) {
				mverr("fimc_is_itf_map is fail(%d)", device, video, ret);
				kfree(planes);
				kfree(buf);
				dma_buf_detach(dmabuf, attachment);
				dma_buf_put(dmabuf);
				goto p_err;
			}

			mvinfo(" B%d.P%d MAP\n", device, video, buf->index, plane);
			set_bit(FRAME_MAP_MEM, &frame->memory);
			dma_buf_detach(dmabuf, attachment);
			dma_buf_put(dmabuf);
			kfree(planes);
			kfree(buf);
		}
		break;
	default:
		err("unsupported ioctl(0x%X)", ctrl->id);
		ret = -EINVAL;
		break;
	}

p_err:
	return ret;
}
Example #29
0
/**
 * __fill_vb2_buffer() - fill a vb2_buffer with information provided in a
 * v4l2_buffer by the userspace. It also verifies that struct
 * v4l2_buffer has a valid number of planes.
 */
static int __fill_vb2_buffer(struct vb2_buffer *vb,
		const void *pb, struct vb2_plane *planes)
{
	struct vb2_queue *q = vb->vb2_queue;
	const struct v4l2_buffer *b = pb;
	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
	unsigned int plane;
	int ret;

	ret = __verify_length(vb, b);
	if (ret < 0) {
		dprintk(1, "plane parameters verification failed: %d\n", ret);
		return ret;
	}
	if (b->field == V4L2_FIELD_ALTERNATE && q->is_output) {
		/*
		 * If the format's field is ALTERNATE, then the buffer's field
		 * should be either TOP or BOTTOM, not ALTERNATE since that
		 * makes no sense. The driver has to know whether the
		 * buffer represents a top or a bottom field in order to
		 * program any DMA correctly. Using ALTERNATE is wrong, since
		 * that just says that it is either a top or a bottom field,
		 * but not which of the two it is.
		 */
		dprintk(1, "the field is incorrectly set to ALTERNATE "
					"for an output buffer\n");
		return -EINVAL;
	}
	vb->timestamp = 0;
	vbuf->sequence = 0;

	if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
		if (b->memory == VB2_MEMORY_USERPTR) {
			for (plane = 0; plane < vb->num_planes; ++plane) {
				planes[plane].m.userptr =
					b->m.planes[plane].m.userptr;
				planes[plane].length =
					b->m.planes[plane].length;
			}
		}
		if (b->memory == VB2_MEMORY_DMABUF) {
			for (plane = 0; plane < vb->num_planes; ++plane) {
				planes[plane].m.fd =
					b->m.planes[plane].m.fd;
				planes[plane].length =
					b->m.planes[plane].length;
			}
		}

		/* Fill in driver-provided information for OUTPUT types */
		if (V4L2_TYPE_IS_OUTPUT(b->type)) {
			/*
			 * Will have to go up to b->length when API starts
			 * accepting variable number of planes.
			 *
			 * If bytesused == 0 for the output buffer, then fall
			 * back to the full buffer size. In that case
			 * userspace clearly never bothered to set it and
			 * it's a safe assumption that they really meant to
			 * use the full plane sizes.
			 *
			 * Some drivers, e.g. old codec drivers, use bytesused == 0
			 * as a way to indicate that streaming is finished.
			 * In that case, the driver should use the
			 * allow_zero_bytesused flag to keep old userspace
			 * applications working.
			 */
			for (plane = 0; plane < vb->num_planes; ++plane) {
				struct vb2_plane *pdst = &planes[plane];
				struct v4l2_plane *psrc = &b->m.planes[plane];

				if (psrc->bytesused == 0)
					vb2_warn_zero_bytesused(vb);

				if (vb->vb2_queue->allow_zero_bytesused)
					pdst->bytesused = psrc->bytesused;
				else
					pdst->bytesused = psrc->bytesused ?
						psrc->bytesused : pdst->length;
				pdst->data_offset = psrc->data_offset;
			}
		}
	} else {
		/*
		 * Single-planar buffers do not use planes array,
		 * so fill in relevant v4l2_buffer struct fields instead.
		 * In videobuf we use our internal V4l2_planes struct for
		 * single-planar buffers as well, for simplicity.
		 *
		 * If bytesused == 0 for the output buffer, then fall back
		 * to the full buffer size as that's a sensible default.
		 *
		 * Some drivers, e.g. old codec drivers, use bytesused == 0 as
		 * a way to indicate that streaming is finished. In that case,
		 * the driver should use the allow_zero_bytesused flag to keep
		 * old userspace applications working.
		 */
		if (b->memory == VB2_MEMORY_USERPTR) {
			planes[0].m.userptr = b->m.userptr;
			planes[0].length = b->length;
		}

		if (b->memory == VB2_MEMORY_DMABUF) {
			planes[0].m.fd = b->m.fd;
			planes[0].length = b->length;
		}

		if (V4L2_TYPE_IS_OUTPUT(b->type)) {
			if (b->bytesused == 0)
				vb2_warn_zero_bytesused(vb);

			if (vb->vb2_queue->allow_zero_bytesused)
				planes[0].bytesused = b->bytesused;
			else
				planes[0].bytesused = b->bytesused ?
					b->bytesused : planes[0].length;
		} else
			planes[0].bytesused = 0;

	}

	/* Zero flags that the vb2 core handles */
	vbuf->flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS;
	if (!vb->vb2_queue->copy_timestamp || !V4L2_TYPE_IS_OUTPUT(b->type)) {
		/*
		 * Non-COPY timestamps and non-OUTPUT queues will get
		 * their timestamp and timestamp source flags from the
		 * queue.
		 */
		vbuf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
	}

	if (V4L2_TYPE_IS_OUTPUT(b->type)) {
		/*
		 * For output buffers mask out the timecode flag:
		 * this will be handled later in vb2_internal_qbuf().
		 * The 'field' is valid metadata for this output buffer
		 * and so that needs to be copied here.
		 */
		vbuf->flags &= ~V4L2_BUF_FLAG_TIMECODE;
		vbuf->field = b->field;
	} else {
		/* Zero any output buffer flags as this is a capture buffer */
		vbuf->flags &= ~V4L2_BUFFER_OUT_FLAGS;
	}

	return 0;
}
GstFlowReturn
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;

  GstV4l2MemoryGroup *group = NULL;

  g_return_val_if_fail (g_atomic_int_get (&allocator->active), GST_FLOW_ERROR);

  buffer.type = obj->type;
  buffer.memory = allocator->memory;

  if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
    buffer.length = obj->format.fmt.pix_mp.num_planes;
    buffer.m.planes = planes;
  }

  if (obj->ioctl (obj->video_fd, VIDIOC_DQBUF, &buffer) < 0)
    goto error;

  group = allocator->groups[buffer.index];

  if (!IS_QUEUED (group->buffer)) {
    GST_ERROR_OBJECT (allocator,
        "buffer %i was not queued, this indicate a driver bug.", buffer.index);
    return GST_FLOW_ERROR;
  }

  group->buffer = buffer;

  GST_LOG_OBJECT (allocator, "dequeued buffer %i (flags 0x%X)", buffer.index,
      buffer.flags);

  if (IS_QUEUED (group->buffer)) {
    GST_DEBUG_OBJECT (allocator,
        "driver pretends buffer is queued even if dequeue succeeded");
    UNSET_QUEUED (group->buffer);
  }

  if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
    group->buffer.m.planes = group->planes;
    memcpy (group->planes, buffer.m.planes, sizeof (planes));
  } else {
    group->planes[0].bytesused = group->buffer.bytesused;
    group->planes[0].length = group->buffer.length;
    g_assert (sizeof (group->planes[0].m) == sizeof (group->buffer.m));
    memcpy (&group->planes[0].m, &group->buffer.m, sizeof (group->buffer.m));
  }

  /* And update memory size */
  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++) {
      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);
      }
    }
  }

  /* Release the memory, possibly making it RW again */
  for (i = 0; i < group->n_mem; i++)
    gst_memory_unref (group->mem[i]);

  *group_out = group;
  return GST_FLOW_OK;

error:
  if (errno == EPIPE) {
    GST_DEBUG_OBJECT (allocator, "broken pipe signals last buffer");
    return GST_FLOW_EOS;
  }

  GST_ERROR_OBJECT (allocator, "failed dequeuing a %s buffer: %s",
      memory_type_to_str (allocator->memory), g_strerror (errno));

  switch (errno) {
    case EAGAIN:
      GST_WARNING_OBJECT (allocator,
          "Non-blocking I/O has been selected using O_NONBLOCK and"
          " no buffer was in the outgoing queue.");
      break;
    case EINVAL:
      GST_ERROR_OBJECT (allocator,
          "The buffer type is not supported, or the index is out of bounds, "
          "or no buffers have been allocated yet, or the userptr "
          "or length are invalid.");
      break;
    case ENOMEM:
      GST_ERROR_OBJECT (allocator,
          "insufficient memory to enqueue a user pointer buffer");
      break;
    case EIO:
      GST_INFO_OBJECT (allocator,
          "VIDIOC_DQBUF failed due to an internal error."
          " Can also indicate temporary problems like signal loss."
          " Note the driver might dequeue an (empty) buffer despite"
          " returning an error, or even stop capturing.");
      /* have we de-queued a buffer ? */
      if (!IS_QUEUED (buffer)) {
        GST_DEBUG_OBJECT (allocator, "reenqueueing buffer");
        /* FIXME ... should we do something here? */
      }
      break;
    case EINTR:
      GST_WARNING_OBJECT (allocator, "could not sync on a buffer on device");
      break;
    default:
      GST_WARNING_OBJECT (allocator,
          "Grabbing frame got interrupted unexpectedly. %d: %s.", errno,
          g_strerror (errno));
      break;
  }

  return GST_FLOW_ERROR;
}