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