Пример #1
0
EFI_STATUS 
print_memory_map(void)
{
    EFI_MEMORY_DESCRIPTOR *buf;
    UINTN desc_size;
    UINT32 desc_version;
    UINTN size, map_key, mapping_size;
    EFI_MEMORY_DESCRIPTOR *desc;
    EFI_STATUS err = EFI_SUCCESS;
    int i = 0;

    err = memory_map(&buf, &size, &map_key, &desc_size, &desc_version);
    if (err != EFI_SUCCESS)
        return err;

    Print(L"Memory Map Size: %d\n", size);
    Print(L"Map Key: %d\n", map_key);
    Print(L"Descriptor Version: %d\n", desc_version);
    Print(L"Descriptor Size: %d\n\n", desc_size);

    desc = buf;
    while ((void *)desc < (void *)buf + size) {
        mapping_size = desc->NumberOfPages * PAGE_SIZE;

        Print(L"[#%02d] Type: %s  Attr: 0x%x\n", i, memory_type_to_str(desc->Type), desc->Attribute);
        Print(L"      Phys: %016llx-%016llx\n", desc->PhysicalStart, desc->PhysicalStart + mapping_size);
        Print(L"      Virt: %016llx-%016llx\n\n", desc->VirtualStart, desc->VirtualStart + mapping_size);

        desc = (void *)desc + desc_size;
        i++;
    }

    uefi_call_wrapper(BS->FreePool, 1, buf);
    return err;
}
Пример #2
0
static EFI_STATUS print_memory_map(void)
{
	EFI_MEMORY_DESCRIPTOR *buf;
	UINTN desc_size;
	UINT32 desc_version;
	UINTN size, map_key;
	EFI_MEMORY_DESCRIPTOR *desc;
	EFI_STATUS err;
	int i;

	err = memory_map(&buf, &size, &map_key,
			 &desc_size, &desc_version);
	if (err != EFI_SUCCESS)
		return err;

	Print(L"System Memory Map\n");
	Print(L"System Memory Map Size: %d\n", size);
	Print(L"Descriptor Version: %d\n", desc_version);
	Print(L"Descriptor Size: %d\n", desc_size);

	desc = buf;
	i = 0;

	while ((void *)desc < (void *)buf + size) {
		UINTN mapping_size;

		mapping_size = desc->NumberOfPages * PAGE_SIZE;

		Print(L"[#%.2d] Type: %s\n", i,
		      memory_type_to_str(desc->Type));

		Print(L"      Attr: 0x%016llx\n", desc->Attribute);

		Print(L"      Phys: [0x%016llx - 0x%016llx]\n",
		      desc->PhysicalStart,
		      desc->PhysicalStart + mapping_size);

		Print(L"      Virt: [0x%016llx - 0x%016llx]",
		      desc->VirtualStart,
		      desc->VirtualStart + mapping_size);

		Print(L"\n");
		desc = (void *)desc + desc_size;
		i++;
	}

	free_pool(buf);
	return err;
}
guint
gst_v4l2_allocator_start (GstV4l2Allocator * allocator, guint32 count,
    guint32 memory)
{
  struct v4l2_requestbuffers breq = { count, allocator->type, memory };
  gboolean can_allocate;
  gint i;

  g_return_val_if_fail (count != 0, 0);

  GST_OBJECT_LOCK (allocator);

  if (g_atomic_int_get (&allocator->active))
    goto already_active;

  if (v4l2_ioctl (allocator->video_fd, VIDIOC_REQBUFS, &breq) < 0)
    goto reqbufs_failed;

  if (breq.count < 1)
    goto out_of_memory;

  switch (memory) {
    case V4L2_MEMORY_MMAP:
      can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (allocator, MMAP);
      break;
    case V4L2_MEMORY_USERPTR:
      can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (allocator, USERPTR);
      break;
    case V4L2_MEMORY_DMABUF:
      can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (allocator, DMABUF);
      break;
    default:
      can_allocate = FALSE;
      break;
  }

  GST_DEBUG_OBJECT (allocator, "allocated %u %s buffers out of %u requested",
      breq.count, memory_type_to_str (memory), count);

  allocator->can_allocate = can_allocate;
  allocator->count = breq.count;
  allocator->memory = memory;

  /* Create memory groups */
  for (i = 0; i < allocator->count; i++) {
    allocator->groups[i] = gst_v4l2_memory_group_new (allocator, i);
    if (allocator->groups[i] == NULL)
      goto error;

    gst_atomic_queue_push (allocator->free_queue, allocator->groups[i]);
  }

  g_atomic_int_set (&allocator->active, TRUE);

done:
  GST_OBJECT_UNLOCK (allocator);
  return breq.count;

already_active:
  {
    GST_ERROR_OBJECT (allocator, "allocator already active");
    goto error;
  }
reqbufs_failed:
  {
    GST_ERROR_OBJECT (allocator,
        "error requesting %d buffers: %s", count, g_strerror (errno));
    goto error;
  }
out_of_memory:
  {
    GST_ERROR_OBJECT (allocator, "Not enough memory to allocate buffers");
    goto error;
  }
error:
  {
    breq.count = 0;
    goto done;
  }
}
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;
}
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;
}
Пример #6
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;
}