static gboolean gst_wl_shm_validate_video_info (const GstVideoInfo * vinfo) { gint height = GST_VIDEO_INFO_HEIGHT (vinfo); gint base_stride = GST_VIDEO_INFO_PLANE_STRIDE (vinfo, 0); gsize base_offs = GST_VIDEO_INFO_PLANE_OFFSET (vinfo, 0); gint i; gsize offs = 0; for (i = 0; i < GST_VIDEO_INFO_N_PLANES (vinfo); i++) { guint32 estride; /* Overwrite the video info's stride and offset using the pitch calculcated * by the kms driver. */ estride = gst_wl_shm_extrapolate_stride (vinfo->finfo, i, base_stride); if (estride != GST_VIDEO_INFO_PLANE_STRIDE (vinfo, i)) return FALSE; if (GST_VIDEO_INFO_PLANE_OFFSET (vinfo, i) - base_offs != offs) return FALSE; /* Note that we cannot negotiate special padding betweem each planes, * hence using the display height here. */ offs += estride * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vinfo->finfo, i, height); } if (vinfo->size < offs) return FALSE; return TRUE; }
static gboolean ensure_data (GstVdpVideoMemory * vmem) { VdpStatus vdp_stat; GstVideoInfo *info = vmem->info; #ifndef GST_DISABLE_GST_DEBUG GstClockTime before, after; #endif if (g_atomic_int_add (&vmem->refcount, 1) > 1) return TRUE; /* Allocate enough room to store data */ vmem->cache = g_malloc (GST_VIDEO_INFO_SIZE (info)); vmem->cached_data[0] = vmem->cache; vmem->cached_data[1] = vmem->cache + GST_VIDEO_INFO_PLANE_OFFSET (info, 1); vmem->cached_data[2] = vmem->cache + GST_VIDEO_INFO_PLANE_OFFSET (info, 2); vmem->destination_pitches[0] = GST_VIDEO_INFO_PLANE_STRIDE (info, 0); vmem->destination_pitches[1] = GST_VIDEO_INFO_PLANE_STRIDE (info, 1); vmem->destination_pitches[2] = GST_VIDEO_INFO_PLANE_STRIDE (info, 2); GST_DEBUG ("cached_data %p %p %p", vmem->cached_data[0], vmem->cached_data[1], vmem->cached_data[2]); GST_DEBUG ("pitches %d %d %d", vmem->destination_pitches[0], vmem->destination_pitches[1], vmem->destination_pitches[2]); #ifndef GST_DISABLE_GST_DEBUG before = gst_util_get_timestamp (); #endif vdp_stat = vmem->device->vdp_video_surface_get_bits_ycbcr (vmem->surface, vmem->ycbcr_format, vmem->cached_data, vmem->destination_pitches); #ifndef GST_DISABLE_GST_DEBUG after = gst_util_get_timestamp (); #endif GST_CAT_WARNING (GST_CAT_PERFORMANCE, "Downloading took %" GST_TIME_FORMAT, GST_TIME_ARGS (after - before)); if (vdp_stat != VDP_STATUS_OK) { GST_ERROR ("Failed to get bits : %s", vmem->device->vdp_get_error_string (vdp_stat)); g_free (vmem->cache); vmem->cache = NULL; return FALSE; } return TRUE; }
struct wl_buffer * gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display, const GstVideoInfo * info) { GstWlShmMemory *shm_mem = (GstWlShmMemory *) mem; gint width, height, stride; gsize size; enum wl_shm_format format; struct wl_shm_pool *wl_pool; struct wl_buffer *wbuffer; width = GST_VIDEO_INFO_WIDTH (info); height = GST_VIDEO_INFO_HEIGHT (info); stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0); size = GST_VIDEO_INFO_SIZE (info); format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (info)); g_return_val_if_fail (gst_is_wl_shm_memory (mem), NULL); g_return_val_if_fail (size <= mem->size, NULL); g_return_val_if_fail (shm_mem->fd != -1, NULL); GST_DEBUG_OBJECT (mem->allocator, "Creating wl_buffer of size %" G_GSSIZE_FORMAT " (%d x %d, stride %d), format %s", size, width, height, stride, gst_wl_shm_format_to_string (format)); wl_pool = wl_shm_create_pool (display->shm, shm_mem->fd, mem->size); wbuffer = wl_shm_pool_create_buffer (wl_pool, 0, width, height, stride, format); close (shm_mem->fd); shm_mem->fd = -1; wl_shm_pool_destroy (wl_pool); return wbuffer; }
static void gst_raw_video_parse_init_config (GstRawVideoParseConfig * config) { int i; config->ready = FALSE; config->width = DEFAULT_WIDTH; config->height = DEFAULT_HEIGHT; config->format = DEFAULT_FORMAT; config->pixel_aspect_ratio_n = DEFAULT_PIXEL_ASPECT_RATIO_N; config->pixel_aspect_ratio_d = DEFAULT_PIXEL_ASPECT_RATIO_D; config->framerate_n = DEFAULT_FRAMERATE_N; config->framerate_d = DEFAULT_FRAMERATE_D; config->interlaced = DEFAULT_INTERLACED; config->top_field_first = DEFAULT_TOP_FIELD_FIRST; config->frame_stride = DEFAULT_FRAME_STRIDE; gst_video_info_set_format (&(config->info), DEFAULT_FORMAT, DEFAULT_WIDTH, DEFAULT_HEIGHT); for (i = 0; i < GST_VIDEO_MAX_PLANES; ++i) { config->plane_offsets[i] = GST_VIDEO_INFO_PLANE_OFFSET (&(config->info), i); config->plane_strides[i] = GST_VIDEO_INFO_PLANE_STRIDE (&(config->info), i); } }
bool getVideoSizeAndFormatFromCaps(GstCaps* caps, WebCore::IntSize& size, GstVideoFormat& format, int& pixelAspectRatioNumerator, int& pixelAspectRatioDenominator, int& stride) { #ifdef GST_API_VERSION_1 GstVideoInfo info; if (!gst_video_info_from_caps(&info, caps)) return false; format = GST_VIDEO_INFO_FORMAT(&info); size.setWidth(GST_VIDEO_INFO_WIDTH(&info)); size.setHeight(GST_VIDEO_INFO_HEIGHT(&info)); pixelAspectRatioNumerator = GST_VIDEO_INFO_PAR_N(&info); pixelAspectRatioDenominator = GST_VIDEO_INFO_PAR_D(&info); stride = GST_VIDEO_INFO_PLANE_STRIDE(&info, 0); #else gint width, height; if (!GST_IS_CAPS(caps) || !gst_caps_is_fixed(caps) || !gst_video_format_parse_caps(caps, &format, &width, &height) || !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator, &pixelAspectRatioDenominator)) return false; size.setWidth(width); size.setHeight(height); stride = size.width() * 4; #endif return true; }
static gboolean plugin_update_sinkpad_info_from_buffer (GstVaapiPluginBase * plugin, GstBuffer * buf) { GstVideoInfo *const vip = &plugin->sinkpad_info; GstVideoMeta *vmeta; guint i; vmeta = gst_buffer_get_video_meta (buf); if (!vmeta) return TRUE; if (GST_VIDEO_INFO_FORMAT (vip) != vmeta->format || GST_VIDEO_INFO_WIDTH (vip) != vmeta->width || GST_VIDEO_INFO_HEIGHT (vip) != vmeta->height || GST_VIDEO_INFO_N_PLANES (vip) != vmeta->n_planes) return FALSE; for (i = 0; i < GST_VIDEO_INFO_N_PLANES (vip); ++i) { GST_VIDEO_INFO_PLANE_OFFSET (vip, i) = vmeta->offset[i]; GST_VIDEO_INFO_PLANE_STRIDE (vip, i) = vmeta->stride[i]; } GST_VIDEO_INFO_SIZE (vip) = gst_buffer_get_size (buf); return TRUE; }
static GstFlowReturn gst_wayland_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer, GstBufferPoolAcquireParams * params) { GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL_CAST (pool); gint width, height, stride; gsize size; enum wl_shm_format format; gint offset; void *data; GstWlMeta *meta; width = GST_VIDEO_INFO_WIDTH (&self->info); height = GST_VIDEO_INFO_HEIGHT (&self->info); stride = GST_VIDEO_INFO_PLANE_STRIDE (&self->info, 0); size = GST_VIDEO_INFO_SIZE (&self->info); format = gst_video_format_to_wayland_format (GST_VIDEO_INFO_FORMAT (&self->info)); GST_DEBUG_OBJECT (self, "Allocating buffer of size %" G_GSSIZE_FORMAT " (%d x %d, stride %d), format %s", size, width, height, stride, gst_wayland_format_to_string (format)); /* try to reserve another memory block from the shm pool */ if (self->used + size > self->size) goto no_buffer; offset = self->used; self->used += size; data = ((gchar *) self->data) + offset; /* create buffer and its metadata object */ *buffer = gst_buffer_new (); meta = (GstWlMeta *) gst_buffer_add_meta (*buffer, GST_WL_META_INFO, NULL); meta->pool = self; meta->wbuffer = wl_shm_pool_create_buffer (self->wl_pool, offset, width, height, stride, format); meta->used_by_compositor = FALSE; /* configure listening to wl_buffer.release */ g_mutex_lock (&self->buffers_map_mutex); g_hash_table_insert (self->buffers_map, meta->wbuffer, *buffer); g_mutex_unlock (&self->buffers_map_mutex); wl_buffer_add_listener (meta->wbuffer, &buffer_listener, self); /* add the allocated memory on the GstBuffer */ gst_buffer_append_memory (*buffer, gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, data, size, 0, size, NULL, NULL)); return GST_FLOW_OK; /* ERROR */ no_buffer: { GST_WARNING_OBJECT (pool, "can't create buffer"); return GST_FLOW_ERROR; } }
static void gst_imx_ipu_blitter_init_dummy_black_buffer(GstImxIpuBlitter *ipu_blitter) { GstVideoInfo video_info; gst_video_info_init(&video_info); gst_video_info_set_format(&video_info, GST_VIDEO_FORMAT_RGBx, 64, 64); ipu_blitter->dummy_black_buffer = gst_buffer_new_allocate(ipu_blitter->allocator, GST_VIDEO_INFO_SIZE(&video_info), NULL); gst_buffer_memset(ipu_blitter->dummy_black_buffer, 0, 0, GST_VIDEO_INFO_SIZE(&video_info)); gst_buffer_add_video_meta_full( ipu_blitter->dummy_black_buffer, GST_VIDEO_FRAME_FLAG_NONE, GST_VIDEO_INFO_FORMAT(&video_info), GST_VIDEO_INFO_WIDTH(&video_info), GST_VIDEO_INFO_HEIGHT(&video_info), GST_VIDEO_INFO_N_PLANES(&video_info), &(GST_VIDEO_INFO_PLANE_OFFSET(&video_info, 0)), &(GST_VIDEO_INFO_PLANE_STRIDE(&video_info, 0)) ); { GstImxPhysMemory *imx_phys_mem_mem = (GstImxPhysMemory *)gst_buffer_peek_memory(ipu_blitter->dummy_black_buffer, 0); GstImxPhysMemMeta *phys_mem_meta = (GstImxPhysMemMeta *)GST_IMX_PHYS_MEM_META_ADD(ipu_blitter->dummy_black_buffer); phys_mem_meta->phys_addr = imx_phys_mem_mem->phys_addr; } }
GstEGLImage * gst_egl_image_from_dmabuf (GstGLContext * context, gint dmabuf, GstVideoInfo * in_info, gint plane, gsize offset) { GstGLContextEGL *ctx_egl = GST_GL_CONTEXT_EGL (context); gint fourcc; gint atti = 0; EGLint attribs[13]; EGLImageKHR img = EGL_NO_IMAGE_KHR; GstVideoGLTextureType type; fourcc = _drm_fourcc_from_info (in_info, plane); type = gst_gl_texture_type_from_format (context, GST_VIDEO_INFO_FORMAT (in_info), plane); GST_DEBUG ("fourcc %.4s (%d) plane %d (%dx%d)", (char *) &fourcc, fourcc, plane, GST_VIDEO_INFO_COMP_WIDTH (in_info, plane), GST_VIDEO_INFO_COMP_HEIGHT (in_info, plane)); attribs[atti++] = EGL_WIDTH; attribs[atti++] = GST_VIDEO_INFO_COMP_WIDTH (in_info, plane); attribs[atti++] = EGL_HEIGHT; attribs[atti++] = GST_VIDEO_INFO_COMP_HEIGHT (in_info, plane); attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT; attribs[atti++] = fourcc; attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT; attribs[atti++] = dmabuf; attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; attribs[atti++] = offset; attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; attribs[atti++] = GST_VIDEO_INFO_PLANE_STRIDE (in_info, plane); attribs[atti] = EGL_NONE; for (int i = 0; i < atti; i++) GST_LOG ("attr %i: %08X", i, attribs[i]); g_assert (atti == 12); img = ctx_egl->eglCreateImage (ctx_egl->egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attribs); if (!img) { GST_WARNING ("eglCreateImage failed: %s", gst_gl_context_egl_get_error_string (eglGetError ())); return NULL; } return gst_egl_image_new_wrapped (context, img, type, GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL, (GstEGLImageDestroyNotify) _destroy_egl_image, NULL); }
GstMemory * gst_egl_image_memory_from_dmabuf (GstGLContext * context, gint dmabuf, GstVideoInfo * in_info, gint plane, gsize offset) { GstGLContextEGL *ctx_egl = GST_GL_CONTEXT_EGL (context); GstEGLImageAllocator *allocator; gint fourcc; gint atti = 0; EGLint attribs[13]; EGLImageKHR img = EGL_NO_IMAGE_KHR; allocator = gst_egl_image_allocator_obtain (); fourcc = _drm_fourcc_from_info (in_info, plane); GST_DEBUG ("fourcc %.4s (%d) plane %d (%dx%d)", (char *) &fourcc, fourcc, plane, GST_VIDEO_INFO_COMP_WIDTH (in_info, plane), GST_VIDEO_INFO_COMP_HEIGHT (in_info, plane)); attribs[atti++] = EGL_WIDTH; attribs[atti++] = GST_VIDEO_INFO_COMP_WIDTH (in_info, plane); attribs[atti++] = EGL_HEIGHT; attribs[atti++] = GST_VIDEO_INFO_COMP_HEIGHT (in_info, plane); attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT; attribs[atti++] = fourcc; attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT; attribs[atti++] = dmabuf; attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; attribs[atti++] = offset; attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; attribs[atti++] = GST_VIDEO_INFO_PLANE_STRIDE (in_info, plane); attribs[atti] = EGL_NONE; for (int i = 0; i < atti; i++) GST_LOG ("attr %i: %08X", i, attribs[i]); g_assert (atti == 12); img = ctx_egl->eglCreateImage (ctx_egl->egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attribs); if (!img) { GST_WARNING_OBJECT (allocator, "eglCreateImage failed: %s", gst_gl_context_egl_get_error_string ()); return NULL; } return gst_egl_image_allocator_wrap (allocator, ctx_egl, img, 0, 0, in_info->size, NULL, NULL); }
static void fill_video_alignment (GstVaapiVideoBufferPool * pool, GstVideoAlignment * align) { GstVideoInfo *const vip = &pool->priv->vmeta_vinfo; guint i; gst_video_alignment_reset (align); for (i = 0; i < GST_VIDEO_INFO_N_PLANES (vip); i++) align->stride_align[i] = (1U << g_bit_nth_lsf (GST_VIDEO_INFO_PLANE_STRIDE (vip, i), 0)) - 1; }
static void fill_video_info (GstVideoInfo * vip, GstVideoFormat format, guint width, guint height, gsize offset[GST_VIDEO_MAX_PLANES], gint stride[GST_VIDEO_MAX_PLANES]) { guint i; gst_video_info_set_format (vip, format, width, height); for (i = 0; i < GST_VIDEO_INFO_N_PLANES (vip); i++) { GST_VIDEO_INFO_PLANE_OFFSET (vip, i) = offset[i]; GST_VIDEO_INFO_PLANE_STRIDE (vip, i) = stride[i]; } }
bool getVideoSizeAndFormatFromCaps(GstCaps* caps, WebCore::IntSize& size, GstVideoFormat& format, int& pixelAspectRatioNumerator, int& pixelAspectRatioDenominator, int& stride) { GstVideoInfo info; if (!gst_caps_is_fixed(caps) || !gst_video_info_from_caps(&info, caps)) return false; format = GST_VIDEO_INFO_FORMAT(&info); size.setWidth(GST_VIDEO_INFO_WIDTH(&info)); size.setHeight(GST_VIDEO_INFO_HEIGHT(&info)); pixelAspectRatioNumerator = GST_VIDEO_INFO_PAR_N(&info); pixelAspectRatioDenominator = GST_VIDEO_INFO_PAR_D(&info); stride = GST_VIDEO_INFO_PLANE_STRIDE(&info, 0); return true; }
static gboolean gst_imx_blitter_video_sink_select_fb_page(GstImxBlitterVideoSink *blitter_video_sink, guint page) { GstImxPhysMemMeta *phys_mem_meta = GST_IMX_PHYS_MEM_META_GET(blitter_video_sink->framebuffer); guint height = GST_VIDEO_INFO_HEIGHT(&(blitter_video_sink->output_video_info)); guint page_size = GST_VIDEO_INFO_PLANE_STRIDE(&(blitter_video_sink->output_video_info), 0) * height; if (blitter_video_sink->framebuffer_fd == -1) return FALSE; GST_LOG_OBJECT(blitter_video_sink, "switching to page %u", page); phys_mem_meta->phys_addr = (gst_imx_phys_addr_t)(blitter_video_sink->fb_fix.smem_start) + page_size * page; blitter_video_sink->fb_var.yoffset = height * page; return gst_imx_blitter_set_output_frame(blitter_video_sink->blitter, blitter_video_sink->framebuffer); }
/** * gst_gl_get_plane_data_size: * @info: a #GstVideoInfo * @align: a #GstVideoAlignment or %NULL * @plane: plane number in @info to retrieve the data size of * * Retrieve the size in bytes of a video plane of data with a certain alignment */ gsize gst_gl_get_plane_data_size (GstVideoInfo * info, GstVideoAlignment * align, guint plane) { gint padded_height; gsize plane_size; padded_height = info->height; if (align) padded_height += align->padding_top + align->padding_bottom; padded_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info->finfo, plane, padded_height); plane_size = GST_VIDEO_INFO_PLANE_STRIDE (info, plane) * padded_height; return plane_size; }
struct wl_buffer * gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display, const GstVideoInfo * info) { gint width, height, stride; gsize offset, size, memsize, maxsize; enum wl_shm_format format; struct wl_shm_pool *wl_pool; struct wl_buffer *wbuffer; if (!gst_wl_shm_validate_video_info (info)) { GST_DEBUG_OBJECT (display, "Unsupported strides and offsets."); return NULL; } width = GST_VIDEO_INFO_WIDTH (info); height = GST_VIDEO_INFO_HEIGHT (info); stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0); size = GST_VIDEO_INFO_SIZE (info); format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (info)); memsize = gst_memory_get_sizes (mem, &offset, &maxsize); offset += GST_VIDEO_INFO_PLANE_OFFSET (info, 0); g_return_val_if_fail (gst_is_fd_memory (mem), NULL); g_return_val_if_fail (size <= memsize, NULL); g_return_val_if_fail (gst_wl_display_check_format_for_shm (display, GST_VIDEO_INFO_FORMAT (info)), NULL); GST_DEBUG_OBJECT (display, "Creating wl_buffer from SHM of size %" G_GSSIZE_FORMAT " (%d x %d, stride %d), format %s", size, width, height, stride, gst_wl_shm_format_to_string (format)); wl_pool = wl_shm_create_pool (display->shm, gst_fd_memory_get_fd (mem), memsize); wbuffer = wl_shm_pool_create_buffer (wl_pool, offset, width, height, stride, format); wl_shm_pool_destroy (wl_pool); return wbuffer; }
static gboolean gst_video_info_update_from_image (GstVideoInfo * vip, GstVaapiImage * image) { GstVideoFormat format; const guchar *data; guint i, num_planes, data_size, width, height; /* Reset format from image */ format = gst_vaapi_image_get_format (image); gst_vaapi_image_get_size (image, &width, &height); gst_video_info_set_format (vip, format, width, height); num_planes = gst_vaapi_image_get_plane_count (image); g_return_val_if_fail (num_planes == GST_VIDEO_INFO_N_PLANES (vip), FALSE); /* Determine the base data pointer */ data = get_image_data (image); g_return_val_if_fail (data != NULL, FALSE); data_size = gst_vaapi_image_get_data_size (image); /* Check that we don't have disjoint planes */ for (i = 0; i < num_planes; i++) { const guchar *const plane = gst_vaapi_image_get_plane (image, i); if (plane - data > data_size) return FALSE; } /* Update GstVideoInfo structure */ for (i = 0; i < num_planes; i++) { const guchar *const plane = gst_vaapi_image_get_plane (image, i); GST_VIDEO_INFO_PLANE_OFFSET (vip, i) = plane - data; GST_VIDEO_INFO_PLANE_STRIDE (vip, i) = gst_vaapi_image_get_pitch (image, i); } GST_VIDEO_INFO_SIZE (vip) = data_size; return TRUE; }
static gboolean ensure_data (GstMsdkSystemMemory * mem) { gsize size; void *data; GstVideoInfo *info; GstAllocator *allocator; GstMsdkSystemAllocator *msdk_allocator; allocator = GST_MEMORY_CAST (mem)->allocator; msdk_allocator = GST_MSDK_SYSTEM_ALLOCATOR_CAST (allocator); info = &msdk_allocator->image_info; size = GST_VIDEO_INFO_SIZE (info); if (mem->cache) return TRUE; if (posix_memalign (&data, 32, size) != 0) { GST_ERROR ("Memory allocation failed"); return FALSE; } mem->cache = data; mem->cached_data[0] = mem->cache; mem->cached_data[1] = mem->cache + GST_VIDEO_INFO_PLANE_OFFSET (info, 1); mem->cached_data[2] = mem->cache + GST_VIDEO_INFO_PLANE_OFFSET (info, 2); mem->destination_pitches[0] = GST_VIDEO_INFO_PLANE_STRIDE (info, 0); mem->destination_pitches[1] = GST_VIDEO_INFO_PLANE_STRIDE (info, 1); mem->destination_pitches[2] = GST_VIDEO_INFO_PLANE_STRIDE (info, 2); switch (GST_VIDEO_INFO_FORMAT (info)) { case GST_VIDEO_FORMAT_NV12: mem->surface->Data.Y = mem->cached_data[0]; mem->surface->Data.UV = mem->cached_data[1]; mem->surface->Data.Pitch = mem->destination_pitches[0]; break; case GST_VIDEO_FORMAT_YV12: mem->surface->Data.Y = mem->cached_data[0]; mem->surface->Data.U = mem->cached_data[2]; mem->surface->Data.V = mem->cached_data[1]; mem->surface->Data.Pitch = mem->destination_pitches[0]; break; case GST_VIDEO_FORMAT_I420: mem->surface->Data.Y = mem->cached_data[0]; mem->surface->Data.U = mem->cached_data[1]; mem->surface->Data.V = mem->cached_data[2]; mem->surface->Data.Pitch = mem->destination_pitches[0]; break; case GST_VIDEO_FORMAT_YUY2: mem->surface->Data.Y = mem->cached_data[0]; mem->surface->Data.U = mem->surface->Data.Y + 1; mem->surface->Data.V = mem->surface->Data.Y + 3; mem->surface->Data.Pitch = mem->destination_pitches[0]; break; case GST_VIDEO_FORMAT_UYVY: mem->surface->Data.Y = mem->cached_data[0]; mem->surface->Data.U = mem->surface->Data.Y; mem->surface->Data.V = mem->surface->Data.U + 2; mem->surface->Data.Pitch = mem->destination_pitches[0]; break; case GST_VIDEO_FORMAT_BGRA: mem->surface->Data.R = mem->cached_data[0]; mem->surface->Data.G = mem->surface->Data.R + 1; mem->surface->Data.B = mem->surface->Data.R + 2; mem->surface->Data.Pitch = mem->destination_pitches[0]; break; default: g_assert_not_reached (); break; } return TRUE; }
static gboolean gst_v4l2_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config) { GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool); GstV4l2Object *obj = pool->obj; GstCaps *caps; guint size, min_buffers, max_buffers, num_buffers, copy_threshold; GstAllocator *allocator; GstAllocationParams params; struct v4l2_requestbuffers breq; GST_DEBUG_OBJECT (pool, "set config"); pool->add_videometa = gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); if (!pool->add_videometa) { gint stride; /* we don't have video metadata, see if the strides are compatible */ stride = GST_VIDEO_INFO_PLANE_STRIDE (&obj->info, 0); GST_DEBUG_OBJECT (pool, "no videometadata, checking strides %d and %u", stride, obj->bytesperline); if (stride != obj->bytesperline) goto missing_video_api; } /* parse the config and keep around */ if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers, &max_buffers)) goto wrong_config; if (!gst_buffer_pool_config_get_allocator (config, &allocator, ¶ms)) goto wrong_config; GST_DEBUG_OBJECT (pool, "config %" GST_PTR_FORMAT, config); switch (obj->mode) { case GST_V4L2_IO_RW: /* we preallocate 1 buffer, this value also instructs the latency * calculation to have 1 frame latency max */ num_buffers = 1; copy_threshold = 0; break; case GST_V4L2_IO_MMAP: { /* request a reasonable number of buffers when no max specified. We will * copy when we run out of buffers */ if (max_buffers == 0) num_buffers = 4; else num_buffers = max_buffers; /* first, lets request buffers, and see how many we can get: */ GST_DEBUG_OBJECT (pool, "starting, requesting %d MMAP buffers", num_buffers); memset (&breq, 0, sizeof (struct v4l2_requestbuffers)); breq.type = obj->type; breq.count = num_buffers; breq.memory = V4L2_MEMORY_MMAP; if (v4l2_ioctl (pool->video_fd, VIDIOC_REQBUFS, &breq) < 0) goto reqbufs_failed; GST_LOG_OBJECT (pool, " count: %u", breq.count); GST_LOG_OBJECT (pool, " type: %d", breq.type); GST_LOG_OBJECT (pool, " memory: %d", breq.memory); if (breq.count < GST_V4L2_MIN_BUFFERS) goto no_buffers; if (num_buffers != breq.count) { GST_WARNING_OBJECT (pool, "using %u buffers instead", breq.count); num_buffers = breq.count; } /* update min buffers with the amount of buffers we just reserved. We need * to configure this value in the bufferpool so that the default start * implementation calls our allocate function */ min_buffers = breq.count; if (max_buffers == 0 || num_buffers < max_buffers) { /* if we are asked to provide more buffers than we have allocated, start * copying buffers when we only have 2 buffers left in the pool */ copy_threshold = 2; } else { /* we are certain that we have enough buffers so we don't need to * copy */ copy_threshold = 0; } break; } case GST_V4L2_IO_USERPTR: default: num_buffers = 0; copy_threshold = 0; g_assert_not_reached (); break; } pool->size = size; pool->num_buffers = num_buffers; pool->copy_threshold = copy_threshold; if (pool->allocator) gst_allocator_unref (pool->allocator); if ((pool->allocator = allocator)) gst_allocator_ref (allocator); pool->params = params; gst_buffer_pool_config_set_params (config, caps, size, min_buffers, max_buffers); return GST_BUFFER_POOL_CLASS (parent_class)->set_config (bpool, config); /* ERRORS */ missing_video_api: { GST_ERROR_OBJECT (pool, "missing GstMetaVideo API in config, " "default stride: %d, wanted stride %u", GST_VIDEO_INFO_PLANE_STRIDE (&obj->info, 0), obj->bytesperline); return FALSE; } wrong_config: { GST_ERROR_OBJECT (pool, "invalid config %" GST_PTR_FORMAT, config); return FALSE; } reqbufs_failed: { GST_ERROR_OBJECT (pool, "error requesting %d buffers: %s", num_buffers, g_strerror (errno)); return FALSE; } no_buffers: { GST_ERROR_OBJECT (pool, "we received %d from device '%s', we want at least %d", breq.count, obj->videodev, GST_V4L2_MIN_BUFFERS); return FALSE; } }
static gboolean ensure_srcpad_allocator (GstVaapiPluginBase * plugin, GstVideoInfo * vinfo, GstCaps * caps) { gboolean different_caps; GstVideoInfo vi; GstVaapiImageUsageFlags usage_flag = GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS; /* the received caps are the "allocation caps" which may be * different from the "negotiation caps". In this case, we should * indicate the allocator to store the negotiation caps since they * are the one should be used for frame mapping with GstVideoMeta */ different_caps = GST_IS_VIDEO_DECODER (plugin) && plugin->srcpad_caps && !gst_caps_is_strictly_equal (plugin->srcpad_caps, caps); if (different_caps) { vi = plugin->srcpad_info; } else { vi = *vinfo; } if (!reset_allocator (plugin->srcpad_allocator, &vi)) return TRUE; plugin->srcpad_allocator = NULL; if (caps && gst_caps_is_video_raw (caps)) { if (plugin->srcpad_can_dmabuf) { if (GST_IS_VIDEO_DECODER (plugin) || GST_IS_BASE_TRANSFORM (plugin)) { plugin->srcpad_allocator = gst_vaapi_dmabuf_allocator_new (plugin->display, vinfo, get_dmabuf_surface_allocation_flags (), GST_PAD_SRC); } } else if (plugin->enable_direct_rendering) { usage_flag = GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER; GST_INFO_OBJECT (plugin, "enabling direct rendering in source allocator"); } } if (!plugin->srcpad_allocator) { plugin->srcpad_allocator = gst_vaapi_video_allocator_new (plugin->display, vinfo, 0, usage_flag); } if (!plugin->srcpad_allocator) goto error_create_allocator; if (different_caps) { guint i, flags = 0; const GstVideoInfo *alloc_vi = gst_allocator_get_vaapi_video_info (plugin->srcpad_allocator, &flags); /* update the planes and the size with the allocator image info, * but not the resolution */ if (alloc_vi) { for (i = 0; i < GST_VIDEO_INFO_N_PLANES (alloc_vi); i++) { GST_VIDEO_INFO_PLANE_OFFSET (&vi, i) = GST_VIDEO_INFO_PLANE_OFFSET (alloc_vi, i); GST_VIDEO_INFO_PLANE_STRIDE (&vi, i) = GST_VIDEO_INFO_PLANE_STRIDE (alloc_vi, i); } GST_VIDEO_INFO_SIZE (&vi) = GST_VIDEO_INFO_SIZE (alloc_vi); gst_allocator_set_vaapi_video_info (plugin->srcpad_allocator, &vi, flags); } } return TRUE; /* ERRORS */ error_create_allocator: { GST_ERROR_OBJECT (plugin, "failed to create src pad's allocator"); return FALSE; } }
static gboolean gst_raw_video_parse_set_config_from_caps (GstRawBaseParse * raw_base_parse, GstRawBaseParseConfig config, GstCaps * caps) { int i; GstStructure *structure; GstRawVideoParse *raw_video_parse = GST_RAW_VIDEO_PARSE (raw_base_parse); GstRawVideoParseConfig *config_ptr = gst_raw_video_parse_get_config_ptr (raw_video_parse, config); g_assert (caps != NULL); /* Caps might get copied, and the copy needs to be unref'd. * Also, the caller retains ownership over the original caps. * So, to make this mechanism also work with cases where the * caps are *not* copied, ref the original caps here first. */ gst_caps_ref (caps); structure = gst_caps_get_structure (caps, 0); /* For unaligned raw data, the output caps stay the same, * except that video/x-unaligned-raw becomes video/x-raw, * since the parser aligns the frame data */ if (gst_structure_has_name (structure, "video/x-unaligned-raw")) { /* Copy the caps to be able to modify them */ GstCaps *new_caps = gst_caps_copy (caps); gst_caps_unref (caps); caps = new_caps; /* Change the media type to video/x-raw , otherwise * gst_video_info_from_caps() won't work */ structure = gst_caps_get_structure (caps, 0); gst_structure_set_name (structure, "video/x-raw"); } config_ptr->ready = gst_video_info_from_caps (&(config_ptr->info), caps); if (config_ptr->ready) { config_ptr->width = GST_VIDEO_INFO_WIDTH (&(config_ptr->info)); config_ptr->height = GST_VIDEO_INFO_HEIGHT (&(config_ptr->info)); config_ptr->pixel_aspect_ratio_n = GST_VIDEO_INFO_PAR_N (&(config_ptr->info)); config_ptr->pixel_aspect_ratio_d = GST_VIDEO_INFO_PAR_D (&(config_ptr->info)); config_ptr->framerate_n = GST_VIDEO_INFO_FPS_N (&(config_ptr->info)); config_ptr->framerate_d = GST_VIDEO_INFO_FPS_D (&(config_ptr->info)); config_ptr->interlaced = GST_VIDEO_INFO_IS_INTERLACED (&(config_ptr->info)); config_ptr->height = GST_VIDEO_INFO_HEIGHT (&(config_ptr->info)); config_ptr->top_field_first = 0; config_ptr->frame_stride = 0; for (i = 0; i < GST_VIDEO_MAX_PLANES; ++i) { config_ptr->plane_offsets[i] = GST_VIDEO_INFO_PLANE_OFFSET (&(config_ptr->info), i); config_ptr->plane_strides[i] = GST_VIDEO_INFO_PLANE_STRIDE (&(config_ptr->info), i); } } gst_caps_unref (caps); return config_ptr->ready; }
static gboolean gst_imx_egl_viv_sink_gles2_renderer_fill_texture(GstImxEglVivSinkGLES2Renderer *renderer, GstBuffer *buffer) { GstVideoMeta *video_meta; GstMapInfo map_info; guint num_extra_lines, stride[3], offset[3], is_phys_buf; GstImxPhysMemMeta *phys_mem_meta; GstVideoFormat fmt; GLenum gl_format; GLuint w, h, total_w, total_h; phys_mem_meta = NULL; fmt = renderer->video_info.finfo->format; gl_format = gst_imx_egl_viv_sink_gles2_renderer_get_viv_format(fmt); w = renderer->video_info.width; h = renderer->video_info.height; phys_mem_meta = GST_IMX_PHYS_MEM_META_GET(buffer); is_phys_buf = (phys_mem_meta != NULL) && (phys_mem_meta->phys_addr != 0); /* Get the stride and number of extra lines */ video_meta = gst_buffer_get_video_meta(buffer); if (video_meta != NULL) { for (guint i = 0; i < MIN(video_meta->n_planes, 3); ++i) { stride[i] = video_meta->stride[i]; offset[i] = video_meta->offset[i]; } } else { for (guint i = 0; i < MIN(GST_VIDEO_INFO_N_PLANES(&(renderer->video_info)), 3); ++i) { stride[i] = GST_VIDEO_INFO_PLANE_STRIDE(&(renderer->video_info), i); offset[i] = GST_VIDEO_INFO_PLANE_OFFSET(&(renderer->video_info), i); } } num_extra_lines = is_phys_buf ? (phys_mem_meta->padding / stride[0]) : 0; /* stride is in bytes, we need pixels */ total_w = stride[0] / gst_imx_egl_viv_sink_gles2_renderer_bpp(fmt); total_h = h + num_extra_lines; GST_LOG("w/h: %d/%d total_w/h: %d/%d", w, h, total_w, total_h); glUniform2f(renderer->uv_scale_uloc, (float)w / (float)total_w, (float)h / (float)total_h); /* Only update texture if the video frame actually changed */ if ((renderer->viv_planes[0] == NULL) || (renderer->video_info_updated)) { GST_LOG("video frame did change"); if (is_phys_buf) { GLvoid *virt_addr; GLuint phys_addr; phys_addr = (GLuint)(phys_mem_meta->phys_addr); GST_LOG("mapping physical address 0x%x of video frame in buffer %p into VIV texture", phys_addr, (gpointer)buffer); gst_buffer_map(buffer, &map_info, GST_MAP_READ); virt_addr = map_info.data; /* Just set to make sure the == NULL check above is false */ renderer->viv_planes[0] = virt_addr; glTexDirectVIVMap( GL_TEXTURE_2D, total_w, total_h, gl_format, (GLvoid **)(&virt_addr), &phys_addr ); gst_buffer_unmap(buffer, &map_info); GST_LOG("done showing frame in buffer %p with virtual address %p physical address 0x%x", (gpointer)buffer, virt_addr, phys_addr); if (!gst_imx_egl_viv_sink_gles2_renderer_check_gl_error("render", "glTexDirectVIVMap")) return FALSE; } else { glTexDirectVIV( GL_TEXTURE_2D, total_w, total_h, gl_format, (GLvoid **) &(renderer->viv_planes) ); if (!gst_imx_egl_viv_sink_gles2_renderer_check_gl_error("render", "glTexDirectVIV")) return FALSE; GST_LOG("copying pixels into VIV direct texture buffer"); gst_buffer_map(buffer, &map_info, GST_MAP_READ); switch (fmt) { case GST_VIDEO_FORMAT_I420: case GST_VIDEO_FORMAT_YV12: memcpy(renderer->viv_planes[0], map_info.data + offset[0], stride[0] * total_h); memcpy(renderer->viv_planes[1], map_info.data + offset[1], stride[1] * total_h / 2); memcpy(renderer->viv_planes[2], map_info.data + offset[2], stride[2] * total_h / 2); break; case GST_VIDEO_FORMAT_NV12: case GST_VIDEO_FORMAT_NV21: memcpy(renderer->viv_planes[0], map_info.data + offset[0], stride[0] * total_h); memcpy(renderer->viv_planes[1], map_info.data + offset[1], stride[1] * total_h / 2); break; default: memcpy(renderer->viv_planes[0], map_info.data, stride[0] * total_h); } gst_buffer_unmap(buffer, &map_info); } glTexDirectInvalidateVIV(GL_TEXTURE_2D); if (!gst_imx_egl_viv_sink_gles2_renderer_check_gl_error("render", "glTexDirectInvalidateVIV")) return FALSE; renderer->video_info_updated = FALSE; } else { GST_LOG("video frame did not change - not doing anything"); } return TRUE; }
static GstFlowReturn gst_vaapi_video_buffer_pool_alloc_buffer (GstBufferPool * pool, GstBuffer ** out_buffer_ptr, GstBufferPoolAcquireParams * params) { GstVaapiVideoBufferPoolPrivate *const priv = GST_VAAPI_VIDEO_BUFFER_POOL (pool)->priv; GstVaapiVideoBufferPoolAcquireParams *const priv_params = (GstVaapiVideoBufferPoolAcquireParams *) params; GstVaapiVideoMeta *meta; GstMemory *mem; GstBuffer *buffer; const gboolean alloc_vaapi_video_meta = !params || !(params->flags & GST_VAAPI_VIDEO_BUFFER_POOL_ACQUIRE_FLAG_NO_ALLOC); if (!priv->allocator) goto error_no_allocator; if (alloc_vaapi_video_meta) { meta = gst_vaapi_video_meta_new (priv->display); if (!meta) goto error_create_meta; buffer = gst_vaapi_video_buffer_new (meta); } else { meta = NULL; buffer = gst_vaapi_video_buffer_new_empty (); } if (!buffer) goto error_create_buffer; if (priv_params && priv_params->proxy) gst_vaapi_video_meta_set_surface_proxy (meta, priv_params->proxy); if (priv->use_dmabuf_memory) mem = gst_vaapi_dmabuf_memory_new (priv->allocator, meta); else mem = gst_vaapi_video_memory_new (priv->allocator, meta); if (!mem) goto error_create_memory; gst_vaapi_video_meta_replace (&meta, NULL); gst_buffer_append_memory (buffer, mem); if (priv->options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META) { GstVideoInfo *const vip = &priv->vmeta_vinfo; GstVideoMeta *vmeta; vmeta = gst_buffer_add_video_meta_full (buffer, 0, GST_VIDEO_INFO_FORMAT (vip), GST_VIDEO_INFO_WIDTH (vip), GST_VIDEO_INFO_HEIGHT (vip), GST_VIDEO_INFO_N_PLANES (vip), &GST_VIDEO_INFO_PLANE_OFFSET (vip, 0), &GST_VIDEO_INFO_PLANE_STRIDE (vip, 0)); if (GST_VAAPI_IS_VIDEO_MEMORY (mem)) { vmeta->map = gst_video_meta_map_vaapi_memory; vmeta->unmap = gst_video_meta_unmap_vaapi_memory; } } #if (USE_GLX || USE_EGL) if (priv->options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD) gst_buffer_add_texture_upload_meta (buffer); #endif *out_buffer_ptr = buffer; return GST_FLOW_OK; /* ERRORS */ error_no_allocator: { GST_ERROR_OBJECT (pool, "no GstAllocator in buffer pool"); return GST_FLOW_ERROR; } error_create_meta: { GST_ERROR_OBJECT (pool, "failed to allocate vaapi video meta"); return GST_FLOW_ERROR; } error_create_buffer: { GST_ERROR_OBJECT (pool, "failed to create video buffer"); gst_vaapi_video_meta_unref (meta); return GST_FLOW_ERROR; } error_create_memory: { GST_ERROR_OBJECT (pool, "failed to create video memory"); gst_buffer_unref (buffer); gst_vaapi_video_meta_unref (meta); return GST_FLOW_ERROR; } }
static gboolean gst_vaapi_video_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) { GstVaapiVideoBufferPoolPrivate *const priv = GST_VAAPI_VIDEO_BUFFER_POOL (pool)->priv; GstCaps *caps; GstVideoInfo new_allocation_vinfo; const GstVideoInfo *allocator_vinfo; const GstVideoInfo *negotiated_vinfo; GstVideoAlignment align; GstAllocator *allocator; gboolean ret, updated = FALSE; guint size, min_buffers, max_buffers; guint surface_alloc_flags; GST_DEBUG_OBJECT (pool, "config %" GST_PTR_FORMAT, config); caps = NULL; if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers, &max_buffers)) goto error_invalid_config; if (!caps) goto error_no_caps; if (!gst_video_info_from_caps (&new_allocation_vinfo, caps)) goto error_invalid_caps; allocator = NULL; if (!gst_buffer_pool_config_get_allocator (config, &allocator, NULL)) goto error_invalid_allocator; /* it is a valid allocator? */ if (allocator && (g_strcmp0 (allocator->mem_type, GST_VAAPI_VIDEO_MEMORY_NAME) != 0 && g_strcmp0 (allocator->mem_type, GST_VAAPI_DMABUF_ALLOCATOR_NAME) != 0)) allocator = NULL; /* get the allocator properties */ if (allocator) { priv->use_dmabuf_memory = gst_vaapi_is_dmabuf_allocator (allocator); negotiated_vinfo = gst_allocator_get_vaapi_negotiated_video_info (allocator); allocator_vinfo = gst_allocator_get_vaapi_video_info (allocator, &surface_alloc_flags); } else { priv->use_dmabuf_memory = FALSE; negotiated_vinfo = NULL; allocator_vinfo = NULL; surface_alloc_flags = 0; } /* reset or update the allocator if video resolution changed */ if (allocator_vinfo && gst_video_info_changed (allocator_vinfo, &new_allocation_vinfo)) { gst_object_replace ((GstObject **) & priv->allocator, NULL); if (allocator && priv->use_dmabuf_memory) { gst_allocator_set_vaapi_video_info (allocator, &new_allocation_vinfo, surface_alloc_flags); } else { allocator = NULL; } } if (!gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) goto error_no_vaapi_video_meta_option; /* create a new allocator if needed */ if (!allocator) { if (priv->use_dmabuf_memory) { allocator = gst_vaapi_dmabuf_allocator_new (priv->display, &new_allocation_vinfo, /* FIXME: */ 0, GST_PAD_SRC); } else { allocator = gst_vaapi_video_allocator_new (priv->display, &new_allocation_vinfo, surface_alloc_flags, 0); } if (!allocator) goto error_no_allocator; if (negotiated_vinfo) { gst_allocator_set_vaapi_negotiated_video_info (allocator, negotiated_vinfo); } GST_INFO_OBJECT (pool, "created new allocator %" GST_PTR_FORMAT, allocator); gst_buffer_pool_config_set_allocator (config, allocator, NULL); gst_object_unref (allocator); } /* use the allocator and set the video info for the vmeta */ if (allocator) { if (priv->allocator) gst_object_unref (priv->allocator); if ((priv->allocator = allocator)) gst_object_ref (allocator); negotiated_vinfo = gst_allocator_get_vaapi_negotiated_video_info (priv->allocator); allocator_vinfo = gst_allocator_get_vaapi_video_info (allocator, NULL); priv->vmeta_vinfo = (negotiated_vinfo) ? *negotiated_vinfo : *allocator_vinfo; /* last resource to set the correct buffer size */ if (GST_VIDEO_INFO_SIZE (allocator_vinfo) != size) { gst_buffer_pool_config_set_params (config, caps, GST_VIDEO_INFO_SIZE (allocator_vinfo), min_buffers, max_buffers); } } if (!priv->allocator) goto error_no_allocator; priv->options = 0; if (gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META)) { priv->options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META; } else { gint i; for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&new_allocation_vinfo); i++) { if (GST_VIDEO_INFO_PLANE_OFFSET (&new_allocation_vinfo, i) != GST_VIDEO_INFO_PLANE_OFFSET (&priv->vmeta_vinfo, i) || GST_VIDEO_INFO_PLANE_STRIDE (&new_allocation_vinfo, i) != GST_VIDEO_INFO_PLANE_STRIDE (&priv->vmeta_vinfo, i)) { priv->options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META; gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); updated = TRUE; break; } } } if (gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) { fill_video_alignment (GST_VAAPI_VIDEO_BUFFER_POOL (pool), &align); gst_buffer_pool_config_set_video_alignment (config, &align); } if (!priv->use_dmabuf_memory && gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META)) priv->options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD; ret = GST_BUFFER_POOL_CLASS (gst_vaapi_video_buffer_pool_parent_class)->set_config (pool, config); return !updated && ret; /* ERRORS */ error_invalid_config: { GST_ERROR_OBJECT (pool, "invalid config"); return FALSE; } error_no_caps: { GST_ERROR_OBJECT (pool, "no caps in config"); return FALSE; } error_invalid_caps: { GST_ERROR_OBJECT (pool, "invalid caps %" GST_PTR_FORMAT, caps); return FALSE; } error_invalid_allocator: { GST_ERROR_OBJECT (pool, "no allocator in config"); return FALSE; } error_no_vaapi_video_meta_option: { GST_ERROR_OBJECT (pool, "no GstVaapiVideoMeta option in config"); return FALSE; } error_no_allocator: { GST_ERROR_OBJECT (pool, "no allocator defined"); return FALSE; } }
static gboolean gst_vaapi_surface_create_full (GstVaapiSurface * surface, const GstVideoInfo * vip, guint flags) { #if VA_CHECK_VERSION(0,34,0) GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (surface); const GstVideoFormat format = GST_VIDEO_INFO_FORMAT (vip); VASurfaceID surface_id; VAStatus status; guint chroma_type, va_chroma_format, i; const VAImageFormat *va_format; VASurfaceAttrib attribs[3], *attrib; VASurfaceAttribExternalBuffers extbuf; gboolean extbuf_needed = FALSE; va_format = gst_vaapi_video_format_to_va_format (format); if (!va_format) goto error_unsupported_format; chroma_type = gst_vaapi_video_format_get_chroma_type (format); if (!chroma_type) goto error_unsupported_format; va_chroma_format = from_GstVaapiChromaType (chroma_type); if (!va_chroma_format) goto error_unsupported_format; memset (&extbuf, 0, sizeof (extbuf)); extbuf.pixel_format = va_format->fourcc; extbuf.width = GST_VIDEO_INFO_WIDTH (vip); extbuf.height = GST_VIDEO_INFO_HEIGHT (vip); extbuf_needed = ! !(flags & GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE); extbuf.num_planes = GST_VIDEO_INFO_N_PLANES (vip); if (flags & GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_STRIDES) { for (i = 0; i < extbuf.num_planes; i++) extbuf.pitches[i] = GST_VIDEO_INFO_PLANE_STRIDE (vip, i); extbuf_needed = TRUE; } if (flags & GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_OFFSETS) { for (i = 0; i < extbuf.num_planes; i++) extbuf.offsets[i] = GST_VIDEO_INFO_PLANE_OFFSET (vip, i); extbuf_needed = TRUE; } attrib = attribs; attrib->flags = VA_SURFACE_ATTRIB_SETTABLE; attrib->type = VASurfaceAttribPixelFormat; attrib->value.type = VAGenericValueTypeInteger; attrib->value.value.i = va_format->fourcc; attrib++; if (extbuf_needed) { attrib->flags = VA_SURFACE_ATTRIB_SETTABLE; attrib->type = VASurfaceAttribMemoryType; attrib->value.type = VAGenericValueTypeInteger; attrib->value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA; attrib++; attrib->flags = VA_SURFACE_ATTRIB_SETTABLE; attrib->type = VASurfaceAttribExternalBufferDescriptor; attrib->value.type = VAGenericValueTypePointer; attrib->value.value.p = &extbuf; attrib++; } GST_VAAPI_DISPLAY_LOCK (display); status = vaCreateSurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display), va_chroma_format, extbuf.width, extbuf.height, &surface_id, 1, attribs, attrib - attribs); GST_VAAPI_DISPLAY_UNLOCK (display); if (!vaapi_check_status (status, "vaCreateSurfaces()")) return FALSE; surface->format = format; surface->chroma_type = chroma_type; surface->width = extbuf.width; surface->height = extbuf.height; GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id)); GST_VAAPI_OBJECT_ID (surface) = surface_id; return TRUE; /* ERRORS */ error_unsupported_format: GST_ERROR ("unsupported format %s", gst_vaapi_video_format_to_string (format)); return FALSE; #else return FALSE; #endif }
static void gst_raw_video_parse_update_info (GstRawVideoParseConfig * config) { guint i; guint n_planes; guint last_plane; gsize last_plane_offset, last_plane_size; GstVideoInfo *info = &(config->info); GST_DEBUG ("updating info with width %u height %u format %s " " custom plane strides&offsets %d", config->width, config->height, gst_video_format_to_string (config->format), config->custom_plane_strides); gst_video_info_set_format (info, config->format, config->width, config->height); GST_VIDEO_INFO_PAR_N (info) = config->pixel_aspect_ratio_n; GST_VIDEO_INFO_PAR_D (info) = config->pixel_aspect_ratio_d; GST_VIDEO_INFO_FPS_N (info) = config->framerate_n; GST_VIDEO_INFO_FPS_D (info) = config->framerate_d; GST_VIDEO_INFO_INTERLACE_MODE (info) = config->interlaced ? GST_VIDEO_INTERLACE_MODE_INTERLEAVED : GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; /* Check if there are custom plane strides & offsets that need to be preserved */ if (config->custom_plane_strides) { /* In case there are, overwrite the offsets&strides computed by * gst_video_info_set_format with the custom ones */ for (i = 0; i < GST_VIDEO_MAX_PLANES; ++i) { GST_VIDEO_INFO_PLANE_OFFSET (info, i) = config->plane_offsets[i]; GST_VIDEO_INFO_PLANE_STRIDE (info, i) = config->plane_strides[i]; } } else { /* No custom planes&offsets; copy the computed ones into * the plane_offsets & plane_strides arrays to ensure they * are equal to the ones in the videoinfo */ for (i = 0; i < GST_VIDEO_MAX_PLANES; ++i) { config->plane_offsets[i] = GST_VIDEO_INFO_PLANE_OFFSET (info, i); config->plane_strides[i] = GST_VIDEO_INFO_PLANE_STRIDE (info, i); } } n_planes = GST_VIDEO_INFO_N_PLANES (info); if (n_planes < 1) n_planes = 1; /* Figure out what plane is the physically last one. Typically * this is the last plane in the list (= at index n_planes-1). * However, this is not guaranteed, so we have to scan the offsets * to find the last plane. */ last_plane_offset = 0; last_plane = 0; for (i = 0; i < n_planes; ++i) { gsize plane_offset = GST_VIDEO_INFO_PLANE_OFFSET (info, i); if (plane_offset >= last_plane_offset) { last_plane = i; last_plane_offset = plane_offset; } } last_plane_size = GST_VIDEO_INFO_PLANE_STRIDE (info, last_plane) * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info->finfo, last_plane, config->height); GST_VIDEO_INFO_SIZE (info) = last_plane_offset + last_plane_size; GST_DEBUG ("last plane #%u: offset: %" G_GSIZE_FORMAT " size: %" G_GSIZE_FORMAT " => frame size minus extra padding: %" G_GSIZE_FORMAT, last_plane, last_plane_offset, last_plane_size, GST_VIDEO_INFO_SIZE (info)); }
static gboolean gst_vaapi_surface_create_from_buffer_proxy (GstVaapiSurface * surface, GstVaapiBufferProxy * proxy, const GstVideoInfo * vip) { #if VA_CHECK_VERSION (0,36,0) GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (surface); GstVideoFormat format; VASurfaceID surface_id; VAStatus status; guint chroma_type, va_chroma_format; const VAImageFormat *va_format; VASurfaceAttrib attribs[2], *attrib; VASurfaceAttribExternalBuffers extbuf; unsigned long extbuf_handle; guint i, width, height; format = GST_VIDEO_INFO_FORMAT (vip); width = GST_VIDEO_INFO_WIDTH (vip); height = GST_VIDEO_INFO_HEIGHT (vip); gst_vaapi_buffer_proxy_replace (&surface->extbuf_proxy, proxy); va_format = gst_vaapi_video_format_to_va_format (format); if (!va_format) goto error_unsupported_format; chroma_type = gst_vaapi_video_format_get_chroma_type (format); if (!chroma_type) goto error_unsupported_format; va_chroma_format = from_GstVaapiChromaType (chroma_type); if (!va_chroma_format) goto error_unsupported_format; extbuf_handle = GST_VAAPI_BUFFER_PROXY_HANDLE (proxy); extbuf.pixel_format = va_format->fourcc; extbuf.width = width; extbuf.height = height; extbuf.data_size = GST_VAAPI_BUFFER_PROXY_SIZE (proxy); extbuf.num_planes = GST_VIDEO_INFO_N_PLANES (vip); for (i = 0; i < extbuf.num_planes; i++) { extbuf.pitches[i] = GST_VIDEO_INFO_PLANE_STRIDE (vip, i); extbuf.offsets[i] = GST_VIDEO_INFO_PLANE_OFFSET (vip, i); } extbuf.buffers = &extbuf_handle; extbuf.num_buffers = 1; extbuf.flags = 0; extbuf.private_data = NULL; attrib = attribs; attrib->type = VASurfaceAttribExternalBufferDescriptor; attrib->flags = VA_SURFACE_ATTRIB_SETTABLE; attrib->value.type = VAGenericValueTypePointer; attrib->value.value.p = &extbuf; attrib++; attrib->type = VASurfaceAttribMemoryType; attrib->flags = VA_SURFACE_ATTRIB_SETTABLE; attrib->value.type = VAGenericValueTypeInteger; attrib->value.value.i = from_GstVaapiBufferMemoryType (GST_VAAPI_BUFFER_PROXY_TYPE (proxy)); attrib++; GST_VAAPI_DISPLAY_LOCK (display); status = vaCreateSurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display), va_chroma_format, width, height, &surface_id, 1, attribs, attrib - attribs); GST_VAAPI_DISPLAY_UNLOCK (display); if (!vaapi_check_status (status, "vaCreateSurfaces()")) return FALSE; surface->format = format; surface->chroma_type = chroma_type; surface->width = width; surface->height = height; GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id)); GST_VAAPI_OBJECT_ID (surface) = surface_id; return TRUE; /* ERRORS */ error_unsupported_format: GST_ERROR ("unsupported format %s", gst_vaapi_video_format_to_string (format)); return FALSE; #else return FALSE; #endif }
static gboolean gst_kms_sink_import_dmabuf (GstKMSSink * self, GstBuffer * inbuf, GstBuffer ** outbuf) { gint prime_fds[GST_VIDEO_MAX_PLANES] = { 0, }; GstVideoMeta *meta; guint i, n_mem, n_planes; GstKMSMemory *kmsmem; guint mems_idx[GST_VIDEO_MAX_PLANES]; gsize mems_skip[GST_VIDEO_MAX_PLANES]; GstMemory *mems[GST_VIDEO_MAX_PLANES]; if (!self->has_prime_import) return FALSE; /* This will eliminate most non-dmabuf out there */ if (!gst_is_dmabuf_memory (gst_buffer_peek_memory (inbuf, 0))) return FALSE; n_planes = GST_VIDEO_INFO_N_PLANES (&self->vinfo); n_mem = gst_buffer_n_memory (inbuf); meta = gst_buffer_get_video_meta (inbuf); GST_TRACE_OBJECT (self, "Found a dmabuf with %u planes and %u memories", n_planes, n_mem); /* We cannot have multiple dmabuf per plane */ if (n_mem > n_planes) return FALSE; /* Update video info based on video meta */ if (meta) { GST_VIDEO_INFO_WIDTH (&self->vinfo) = meta->width; GST_VIDEO_INFO_HEIGHT (&self->vinfo) = meta->height; for (i = 0; i < meta->n_planes; i++) { GST_VIDEO_INFO_PLANE_OFFSET (&self->vinfo, i) = meta->offset[i]; GST_VIDEO_INFO_PLANE_STRIDE (&self->vinfo, i) = meta->stride[i]; } } /* Find and validate all memories */ for (i = 0; i < n_planes; i++) { guint length; if (!gst_buffer_find_memory (inbuf, GST_VIDEO_INFO_PLANE_OFFSET (&self->vinfo, i), 1, &mems_idx[i], &length, &mems_skip[i])) return FALSE; mems[i] = gst_buffer_peek_memory (inbuf, mems_idx[i]); /* And all memory found must be dmabuf */ if (!gst_is_dmabuf_memory (mems[i])) return FALSE; } kmsmem = (GstKMSMemory *) get_cached_kmsmem (mems[0]); if (kmsmem) { GST_LOG_OBJECT (self, "found KMS mem %p in DMABuf mem %p with fb id = %d", kmsmem, mems[0], kmsmem->fb_id); goto wrap_mem; } for (i = 0; i < n_planes; i++) prime_fds[i] = gst_dmabuf_memory_get_fd (mems[i]); GST_LOG_OBJECT (self, "found these prime ids: %d, %d, %d, %d", prime_fds[0], prime_fds[1], prime_fds[2], prime_fds[3]); kmsmem = gst_kms_allocator_dmabuf_import (self->allocator, prime_fds, n_planes, mems_skip, &self->vinfo); if (!kmsmem) return FALSE; GST_LOG_OBJECT (self, "setting KMS mem %p to DMABuf mem %p with fb id = %d", kmsmem, mems[0], kmsmem->fb_id); set_cached_kmsmem (mems[0], GST_MEMORY_CAST (kmsmem)); wrap_mem: *outbuf = gst_buffer_new (); if (!*outbuf) return FALSE; gst_buffer_append_memory (*outbuf, gst_memory_ref (GST_MEMORY_CAST (kmsmem))); gst_buffer_add_parent_buffer_meta (*outbuf, inbuf); return TRUE; }
static gboolean import_dmabuf_to_msdk_surface (GstMsdkVPP * thiz, GstBuffer * buf, MsdkSurface * msdk_surface) { GstMemory *mem = NULL; GstVideoInfo vinfo; GstVideoMeta *vmeta; GstMsdkMemoryID *msdk_mid = NULL; mfxFrameSurface1 *mfx_surface = NULL; gint fd, i; mem = gst_buffer_peek_memory (buf, 0); fd = gst_dmabuf_memory_get_fd (mem); if (fd < 0) return FALSE; vinfo = thiz->sinkpad_info; /* Update offset/stride/size if there is VideoMeta attached to * the buffer */ vmeta = gst_buffer_get_video_meta (buf); if (vmeta) { if (GST_VIDEO_INFO_FORMAT (&vinfo) != vmeta->format || GST_VIDEO_INFO_WIDTH (&vinfo) != vmeta->width || GST_VIDEO_INFO_HEIGHT (&vinfo) != vmeta->height || GST_VIDEO_INFO_N_PLANES (&vinfo) != vmeta->n_planes) { GST_ERROR_OBJECT (thiz, "VideoMeta attached to buffer is not matching" "the negotiated width/height/format"); return FALSE; } for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&vinfo); ++i) { GST_VIDEO_INFO_PLANE_OFFSET (&vinfo, i) = vmeta->offset[i]; GST_VIDEO_INFO_PLANE_STRIDE (&vinfo, i) = vmeta->stride[i]; } GST_VIDEO_INFO_SIZE (&vinfo) = gst_buffer_get_size (buf); } /* Upstream neither accepted the msdk pool nor the msdk buffer size restrictions. * Current media-driver and GMMLib will fail due to strict memory size restrictions. * Ideally, media-driver should accept what ever memory coming from other drivers * in case of dmabuf-import and this is how the intel-vaapi-driver works. * For now, in order to avoid any crash we check the buffer size and fallback * to copy frame method. * * See this: https://github.com/intel/media-driver/issues/169 * */ if (GST_VIDEO_INFO_SIZE (&vinfo) < GST_VIDEO_INFO_SIZE (&thiz->sinkpad_buffer_pool_info)) return FALSE; mfx_surface = msdk_surface->surface; msdk_mid = (GstMsdkMemoryID *) mfx_surface->Data.MemId; /* release the internal memory storage of associated mfxSurface */ gst_msdk_replace_mfx_memid (thiz->context, mfx_surface, VA_INVALID_ID); /* export dmabuf to vasurface */ if (!gst_msdk_export_dmabuf_to_vasurface (thiz->context, &vinfo, fd, msdk_mid->surface)) return FALSE; return TRUE; }
static gboolean gst_core_media_buffer_wrap_pixel_buffer (GstBuffer * buf, GstVideoInfo * info, CVPixelBufferRef pixel_buf, gboolean * has_padding, gboolean map) { guint n_planes; gsize offset[GST_VIDEO_MAX_PLANES] = { 0 }; gint stride[GST_VIDEO_MAX_PLANES] = { 0 }; GstVideoMeta *video_meta; UInt32 size; if (map && CVPixelBufferLockBaseAddress (pixel_buf, 0) != kCVReturnSuccess) { GST_ERROR ("Could not lock pixel buffer base address"); return FALSE; } *has_padding = FALSE; if (CVPixelBufferIsPlanar (pixel_buf)) { gint i, size = 0, plane_offset = 0; n_planes = CVPixelBufferGetPlaneCount (pixel_buf); for (i = 0; i < n_planes; i++) { stride[i] = CVPixelBufferGetBytesPerRowOfPlane (pixel_buf, i); if (stride[i] != GST_VIDEO_INFO_PLANE_STRIDE (info, i)) { *has_padding = TRUE; } size = stride[i] * CVPixelBufferGetHeightOfPlane (pixel_buf, i); offset[i] = plane_offset; plane_offset += size; if (map) { gst_buffer_append_memory (buf, gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, CVPixelBufferGetBaseAddressOfPlane (pixel_buf, i), size, 0, size, NULL, NULL)); } } } else { n_planes = 1; stride[0] = CVPixelBufferGetBytesPerRow (pixel_buf); offset[0] = 0; size = stride[0] * CVPixelBufferGetHeight (pixel_buf); if (map) { gst_buffer_append_memory (buf, gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, CVPixelBufferGetBaseAddress (pixel_buf), size, 0, size, NULL, NULL)); } } video_meta = gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE, GST_VIDEO_INFO_FORMAT (info), info->width, info->height, n_planes, offset, stride); return TRUE; }