예제 #1
0
int v4lconvert_convert(struct v4lconvert_data *data,
  const struct v4l2_format *src_fmt,  /* in */
  const struct v4l2_format *dest_fmt, /* in */
  unsigned char *src, int src_size, unsigned char *dest, int dest_size)
{
  int res, dest_needed, temp_needed, convert = 0, rotate = 0, crop = 0;
  unsigned char *convert_dest = dest, *rotate_src = src, *rotate_dest = dest;
  unsigned char *crop_src = src;
  struct v4l2_format my_src_fmt = *src_fmt;
  struct v4l2_format my_dest_fmt = *dest_fmt;

  /* Special case when no conversion is needed */
  if (!v4lconvert_needs_conversion(data, src_fmt, dest_fmt)) {
    int to_copy = MIN(dest_size, src_size);
    memcpy(dest, src, to_copy);
    return to_copy;
  }

  /* When field is V4L2_FIELD_ALTERNATE, each buffer only contains half the
     lines */
  if (my_src_fmt.fmt.pix.field == V4L2_FIELD_ALTERNATE) {
    my_src_fmt.fmt.pix.height /= 2;
    my_dest_fmt.fmt.pix.height /= 2;
  }

  /* sanity check, is the dest buffer large enough? */
  switch (my_dest_fmt.fmt.pix.pixelformat) {
    case V4L2_PIX_FMT_RGB24:
    case V4L2_PIX_FMT_BGR24:
      dest_needed = my_dest_fmt.fmt.pix.width * my_dest_fmt.fmt.pix.height * 3;
      temp_needed = my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3;
      break;
    case V4L2_PIX_FMT_YUV420:
    case V4L2_PIX_FMT_YVU420:
      dest_needed =
	my_dest_fmt.fmt.pix.width * my_dest_fmt.fmt.pix.height * 3 / 2;
      temp_needed =
	my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3 / 2;
      break;
    default:
      V4LCONVERT_ERR("Unknown dest format in conversion\n");
      errno = EINVAL;
      return -1;
  }

  if (dest_size < dest_needed) {
    V4LCONVERT_ERR("destination buffer too small\n");
    errno = EFAULT;
    return -1;
  }

  if (my_dest_fmt.fmt.pix.pixelformat != my_src_fmt.fmt.pix.pixelformat)
    convert = 1;

  if (data->flags & V4LCONVERT_ROTATE_90)
    rotate += 90;
  if (data->flags & V4LCONVERT_ROTATE_180)
    rotate += 180;

  if (my_dest_fmt.fmt.pix.width != my_src_fmt.fmt.pix.width ||
      my_dest_fmt.fmt.pix.height != my_src_fmt.fmt.pix.height)
    crop = 1;

  /* convert_pixfmt -> rotate -> crop, all steps are optional */
  if (convert && (rotate || crop)) {
    convert_dest = v4lconvert_alloc_buffer(data, temp_needed,
		     &data->convert_buf, &data->convert_buf_size);
    if (!convert_dest)
      return -1;

    rotate_src = crop_src = convert_dest;
  }

  if (rotate && crop) {
    rotate_dest = v4lconvert_alloc_buffer(data, temp_needed,
		    &data->rotate_buf, &data->rotate_buf_size);
    if (!rotate_dest)
      return -1;

    crop_src = rotate_dest;
  }

  if (convert) {
    res = v4lconvert_convert_pixfmt(data, src, src_size, convert_dest,
				    &my_src_fmt,
				    my_dest_fmt.fmt.pix.pixelformat);
    if (res)
      return res;

    my_src_fmt.fmt.pix.pixelformat = my_dest_fmt.fmt.pix.pixelformat;
    v4lconvert_fixup_fmt(&my_src_fmt);
  }

  if (rotate)
    v4lconvert_rotate(rotate_src, rotate_dest,
		      my_src_fmt.fmt.pix.width, my_src_fmt.fmt.pix.height,
		      my_src_fmt.fmt.pix.pixelformat, rotate);

  if (crop)
    v4lconvert_crop(crop_src, dest, &my_src_fmt, &my_dest_fmt);

  return dest_needed;
}
예제 #2
0
int v4lconvert_convert(struct v4lconvert_data *data,
		const struct v4l2_format *src_fmt,  /* in */
		const struct v4l2_format *dest_fmt, /* in */
		unsigned char *src, int src_size, unsigned char *dest, int dest_size)
{
	int res, dest_needed, temp_needed, processing, convert = 0;
	int rotate90, vflip, hflip, crop;
	unsigned char *convert1_dest = dest;
	int convert1_dest_size = dest_size;
	unsigned char *convert2_src = src, *convert2_dest = dest;
	int convert2_dest_size = dest_size;
	unsigned char *rotate90_src = src, *rotate90_dest = dest;
	unsigned char *flip_src = src, *flip_dest = dest;
	unsigned char *crop_src = src;
	struct v4l2_format my_src_fmt = *src_fmt;
	struct v4l2_format my_dest_fmt = *dest_fmt;

	processing = v4lprocessing_pre_processing(data->processing);
	rotate90 = data->control_flags & V4LCONTROL_ROTATED_90_JPEG;
	hflip = v4lcontrol_get_ctrl(data->control, V4LCONTROL_HFLIP);
	vflip = v4lcontrol_get_ctrl(data->control, V4LCONTROL_VFLIP);
	crop = my_dest_fmt.fmt.pix.width != my_src_fmt.fmt.pix.width ||
		my_dest_fmt.fmt.pix.height != my_src_fmt.fmt.pix.height;

	if (/* If no conversion/processing is needed */
			(src_fmt->fmt.pix.pixelformat == dest_fmt->fmt.pix.pixelformat &&
			 !processing && !rotate90 && !hflip && !vflip && !crop) ||
			/* or if we should do processing/rotating/flipping but the app tries to
			   use the native cam format, we just return an unprocessed frame copy */
			!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)) {
		int to_copy = MIN(dest_size, src_size);
		memcpy(dest, src, to_copy);
		return to_copy;
	}

	/* When field is V4L2_FIELD_ALTERNATE, each buffer only contains half the
	   lines */
	if (my_src_fmt.fmt.pix.field == V4L2_FIELD_ALTERNATE) {
		my_src_fmt.fmt.pix.height /= 2;
		my_dest_fmt.fmt.pix.height /= 2;
	}

	/* sanity check, is the dest buffer large enough? */
	switch (my_dest_fmt.fmt.pix.pixelformat) {
	case V4L2_PIX_FMT_RGB24:
	case V4L2_PIX_FMT_BGR24:
		dest_needed = my_dest_fmt.fmt.pix.width * my_dest_fmt.fmt.pix.height * 3;
		temp_needed = my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3;
		break;
	case V4L2_PIX_FMT_YUV420:
	case V4L2_PIX_FMT_YVU420:
		dest_needed =
			my_dest_fmt.fmt.pix.width * my_dest_fmt.fmt.pix.height * 3 / 2;
		temp_needed =
			my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3 / 2;
		break;
	default:
		V4LCONVERT_ERR("Unknown dest format in conversion\n");
		errno = EINVAL;
		return -1;
	}

	if (dest_size < dest_needed) {
		V4LCONVERT_ERR("destination buffer too small (%d < %d)\n",
				dest_size, dest_needed);
		errno = EFAULT;
		return -1;
	}


	/* Sometimes we need foo -> rgb -> bar as video processing (whitebalance,
	   etc.) can only be done on rgb data */
	if (processing && v4lconvert_processing_needs_double_conversion(
				my_src_fmt.fmt.pix.pixelformat,
				my_dest_fmt.fmt.pix.pixelformat))
		convert = 2;
	else if (my_dest_fmt.fmt.pix.pixelformat !=
			my_src_fmt.fmt.pix.pixelformat ||
		 /* Special case if we do not need to do conversion, but we
		    are not doing any other step involving copying either,
		    force going through convert_pixfmt to copy the data from
		    source to dest */
		 (!rotate90 && !hflip && !vflip && !crop))
		convert = 1;

	/* convert_pixfmt (only if convert == 2) -> processing -> convert_pixfmt ->
	   rotate -> flip -> crop, all steps are optional */
	if (convert == 2) {
		convert1_dest = v4lconvert_alloc_buffer(
				my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3,
				&data->convert1_buf, &data->convert1_buf_size);
		if (!convert1_dest)
			return v4lconvert_oom_error(data);

		convert1_dest_size =
			my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3;
		convert2_src = convert1_dest;
	}

	if (convert && (rotate90 || hflip || vflip || crop)) {
		convert2_dest = v4lconvert_alloc_buffer(temp_needed,
				&data->convert2_buf, &data->convert2_buf_size);
		if (!convert2_dest)
			return v4lconvert_oom_error(data);

		convert2_dest_size = temp_needed;
		rotate90_src = flip_src = crop_src = convert2_dest;
	}

	if (rotate90 && (hflip || vflip || crop)) {
		rotate90_dest = v4lconvert_alloc_buffer(temp_needed,
				&data->rotate90_buf, &data->rotate90_buf_size);
		if (!rotate90_dest)
			return v4lconvert_oom_error(data);

		flip_src = crop_src = rotate90_dest;
	}

	if ((vflip || hflip) && crop) {
		flip_dest = v4lconvert_alloc_buffer(temp_needed, &data->flip_buf,
				&data->flip_buf_size);
		if (!flip_dest)
			return v4lconvert_oom_error(data);

		crop_src = flip_dest;
	}

	/* Done setting sources / dest and allocating intermediate buffers,
	   real conversion / processing / ... starts here. */
	if (convert == 2) {
		res = v4lconvert_convert_pixfmt(data, src, src_size,
				convert1_dest, convert1_dest_size,
				&my_src_fmt,
				V4L2_PIX_FMT_RGB24);
		if (res)
			return res;

		src_size = my_src_fmt.fmt.pix.sizeimage;
	}

	if (processing)
		v4lprocessing_processing(data->processing, convert2_src, &my_src_fmt);

	if (convert) {
		res = v4lconvert_convert_pixfmt(data, convert2_src, src_size,
				convert2_dest, convert2_dest_size,
				&my_src_fmt,
				my_dest_fmt.fmt.pix.pixelformat);
		if (res)
			return res;

		src_size = my_src_fmt.fmt.pix.sizeimage;

		/* We call processing here again in case the source format was not
		   rgb, but the dest is. v4lprocessing checks it self it only actually
		   does the processing once per frame. */
		if (processing)
			v4lprocessing_processing(data->processing, convert2_dest, &my_src_fmt);
	}

	if (rotate90)
		v4lconvert_rotate90(rotate90_src, rotate90_dest, &my_src_fmt);

	if (hflip || vflip)
		v4lconvert_flip(flip_src, flip_dest, &my_src_fmt, hflip, vflip);

	if (crop)
		v4lconvert_crop(crop_src, dest, &my_src_fmt, &my_dest_fmt);

	return dest_needed;
}