/** * gst_gl_base_memory_memcpy: * @src: the source #GstGLBaseMemory * @dest: the destination #GstGLBaseMemory * @offset: the offset to start at * @size: the number of bytes to copy * * Returns: whether the copy suceeded. */ gboolean gst_gl_base_memory_memcpy (GstGLBaseMemory * src, GstGLBaseMemory * dest, gssize offset, gssize size) { GstMapInfo sinfo, dinfo; if (!gst_gl_base_memory_alloc_data (GST_GL_BASE_MEMORY_CAST (dest))) return FALSE; if (!gst_memory_map ((GstMemory *) src, &sinfo, GST_MAP_READ)) { GST_CAT_WARNING (GST_CAT_GL_BASE_MEMORY, "could not read map source memory %p", src); return FALSE; } if (!gst_memory_map ((GstMemory *) dest, &dinfo, GST_MAP_WRITE)) { GST_CAT_WARNING (GST_CAT_GL_BASE_MEMORY, "could not write map dest memory %p", dest); gst_memory_unmap ((GstMemory *) src, &sinfo); return FALSE; } if (size == -1) size = sinfo.size > offset ? sinfo.size - offset : 0; GST_CAT_DEBUG (GST_CAT_GL_BASE_MEMORY, "memcpy %" G_GSSIZE_FORMAT " memory %p -> %p", size, src, dest); memcpy (dinfo.data, sinfo.data + offset, size); gst_memory_unmap ((GstMemory *) dest, &dinfo); gst_memory_unmap ((GstMemory *) src, &sinfo); return TRUE; }
gboolean gst_gl_base_buffer_copy_buffer_sub_data (GstGLBaseBuffer * src, GstGLBaseBuffer * dest, gssize offset, gssize size) { const GstGLFuncs *gl = src->context->gl_vtable; GstMapInfo sinfo, dinfo; if (!gl->CopyBufferSubData) /* This is GL(ES) 3.0+ only */ return FALSE; if (!gst_memory_map ((GstMemory *) src, &sinfo, GST_MAP_READ | GST_MAP_GL)) { GST_CAT_WARNING (GST_CAT_GL_BASE_BUFFER, "failed to read map source memory %p", src); return FALSE; } if (!gst_memory_map ((GstMemory *) dest, &dinfo, GST_MAP_WRITE | GST_MAP_GL)) { GST_CAT_WARNING (GST_CAT_GL_BASE_BUFFER, "failed to write map destination memory %p", dest); gst_memory_unmap ((GstMemory *) src, &sinfo); return FALSE; } gl->BindBuffer (GL_COPY_READ_BUFFER, src->id); gl->BindBuffer (GL_COPY_WRITE_BUFFER, dest->id); gl->CopyBufferSubData (GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, offset, 0, size); gst_memory_unmap ((GstMemory *) src, &sinfo); gst_memory_unmap ((GstMemory *) dest, &dinfo); return TRUE; }
static GstMemory * _fallback_mem_copy (GstMemory * mem, gssize offset, gssize size) { GstMemory *copy; GstMapInfo sinfo, dinfo; GstAllocationParams params = { 0, mem->align, 0, 0, }; GstAllocator *allocator; if (!gst_memory_map (mem, &sinfo, GST_MAP_READ)) return NULL; if (size == -1) size = sinfo.size > offset ? sinfo.size - offset : 0; /* use the same allocator as the memory we copy */ allocator = mem->allocator; if (GST_OBJECT_FLAG_IS_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC)) allocator = NULL; copy = gst_allocator_alloc (allocator, size, ¶ms); if (!gst_memory_map (copy, &dinfo, GST_MAP_WRITE)) { GST_CAT_WARNING (GST_CAT_MEMORY, "could not write map memory %p", copy); gst_allocator_free (mem->allocator, copy); gst_memory_unmap (mem, &sinfo); return NULL; } GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "memcpy %" G_GSSIZE_FORMAT " memory %p -> %p", size, mem, copy); memcpy (dinfo.data, sinfo.data + offset, size); gst_memory_unmap (copy, &dinfo); gst_memory_unmap (mem, &sinfo); return copy; }
gboolean gst_gl_base_buffer_memcpy (GstGLBaseBuffer * src, GstGLBaseBuffer * dest, gssize offset, gssize size) { GstMapInfo sinfo, dinfo; if (!gst_memory_map ((GstMemory *) src, &sinfo, GST_MAP_READ)) { GST_CAT_WARNING (GST_CAT_GL_BASE_BUFFER, "could not read map source memory %p", src); return FALSE; } if (!gst_memory_map ((GstMemory *) dest, &dinfo, GST_MAP_WRITE)) { GST_CAT_WARNING (GST_CAT_GL_BASE_BUFFER, "could not write map dest memory %p", dest); gst_memory_unmap ((GstMemory *) src, &sinfo); return FALSE; } GST_CAT_DEBUG (GST_CAT_GL_BASE_BUFFER, "memcpy %" G_GSSIZE_FORMAT " memory %p -> %p", size, src, dest); memcpy (dinfo.data, sinfo.data + offset, size); gst_memory_unmap ((GstMemory *) dest, &dinfo); gst_memory_unmap ((GstMemory *) src, &sinfo); return TRUE; }
static GstMemory * _gl_mem_copy (GstGLMemoryPBO * src, gssize offset, gssize size) { GstAllocationParams params = { 0, GST_MEMORY_CAST (src)->align, 0, 0 }; GstGLBaseMemoryAllocator *base_mem_allocator; GstAllocator *allocator; GstMemory *dest = NULL; allocator = GST_MEMORY_CAST (src)->allocator; base_mem_allocator = (GstGLBaseMemoryAllocator *) allocator; if (src->mem.tex_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES) { GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Cannot copy External OES textures"); return NULL; } /* If not doing a full copy, then copy to sysmem, the 2D represention of the * texture would become wrong */ if (offset > 0 || size < GST_MEMORY_CAST (src)->size) { return base_mem_allocator->fallback_mem_copy (GST_MEMORY_CAST (src), offset, size); } dest = (GstMemory *) _gl_mem_new (allocator, NULL, src->mem.mem.context, src->mem.tex_target, ¶ms, &src->mem.info, src->mem.plane, &src->mem.valign, NULL, NULL); if (GST_MEMORY_FLAG_IS_SET (src, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)) { if (!gst_gl_base_memory_memcpy ((GstGLBaseMemory *) src, (GstGLBaseMemory *) dest, offset, size)) { GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Could not copy GL Memory"); gst_memory_unref (GST_MEMORY_CAST (dest)); return NULL; } } else { GstMapInfo dinfo; if (!gst_memory_map (GST_MEMORY_CAST (dest), &dinfo, GST_MAP_WRITE | GST_MAP_GL)) { GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Failed not map destination " "for writing"); gst_memory_unref (GST_MEMORY_CAST (dest)); return NULL; } if (!gst_gl_memory_copy_into ((GstGLMemory *) src, ((GstGLMemory *) dest)->tex_id, src->mem.tex_target, src->mem.tex_type, src->mem.tex_width, GL_MEM_HEIGHT (src))) { GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Could not copy GL Memory"); gst_memory_unmap (GST_MEMORY_CAST (dest), &dinfo); gst_memory_unref (GST_MEMORY_CAST (dest)); return NULL; } gst_memory_unmap (GST_MEMORY_CAST (dest), &dinfo); } return dest; }
GstFlowReturn on_new_preroll(GstAppSink *appsink, gpointer user_data) { GstSample* sample = NULL; GstBuffer* buffer; GstMemory* memory; GstMapInfo info; GstClockTime clocktime; g_debug("on_new_preroll "); sample = gst_app_sink_pull_sample (appsink); if (sample) { g_debug("pulled sample\n"); buffer = gst_sample_get_buffer(sample); clocktime = GST_BUFFER_PTS(buffer); memory = gst_buffer_get_memory(buffer, 0); gst_memory_map(memory, &info, GST_MAP_READ); /* You can access raw memory at info.data */ if(app.output_callback) app.output_callback(info.data, info.size); //fwrite(info.data, 1, info.size, app.outfile); gst_memory_unmap(memory, &info); gst_memory_unref(memory); gst_sample_unref(sample); } return GST_FLOW_OK; }
void groj_config_set_time(GstMemory *cmem, double time){ GstMapInfo info; gst_memory_map (cmem, &info, GST_MAP_WRITE); ((struct RojConfig *)info.data)->time = time; gst_memory_unmap (cmem, &info); }
static void user_write_data (png_structp png_ptr, png_bytep data, png_uint_32 length) { GstPngEnc *pngenc; GstMemory *mem; GstMapInfo minfo; pngenc = (GstPngEnc *) png_get_io_ptr (png_ptr); mem = gst_allocator_alloc (NULL, length, NULL); if (!mem) { GST_ERROR_OBJECT (pngenc, "Failed to allocate memory"); png_error (png_ptr, "Failed to allocate memory"); /* never reached */ return; } if (!gst_memory_map (mem, &minfo, GST_MAP_WRITE)) { GST_ERROR_OBJECT (pngenc, "Failed to map memory"); gst_memory_unref (mem); png_error (png_ptr, "Failed to map memory"); /* never reached */ return; } memcpy (minfo.data, data, length); gst_memory_unmap (mem, &minfo); gst_buffer_append_memory (pngenc->buffer_out, mem); }
void groj_config_set_number(GstMemory *cmem, unsigned long number){ GstMapInfo info; gst_memory_map (cmem, &info, GST_MAP_WRITE); ((struct RojConfig *)info.data)->number = number; gst_memory_unmap (cmem, &info); }
static gpointer _gl_mem_map_gpu_access (GstGLMemoryPBO * gl_mem, GstMapInfo * info, gsize size) { gpointer data = &gl_mem->mem.tex_id; if ((info->flags & GST_MAP_READ) == GST_MAP_READ) { if (gl_mem->pbo && CONTEXT_SUPPORTS_PBO_UPLOAD (gl_mem->mem.mem.context)) { GstMapInfo pbo_info; /* data -> pbo */ if (!gst_memory_map (GST_MEMORY_CAST (gl_mem->pbo), &pbo_info, GST_MAP_READ | GST_MAP_GL)) { GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Failed to map pbo"); return NULL; } /* pbo -> texture */ _upload_pbo_memory (gl_mem, info, gl_mem->pbo, &pbo_info); gst_memory_unmap (GST_MEMORY_CAST (gl_mem->pbo), &pbo_info); } else { GstGLMemoryAllocatorClass *alloc_class; alloc_class = GST_GL_MEMORY_ALLOCATOR_CLASS (parent_class); data = alloc_class->map ((GstGLBaseMemory *) gl_mem, info, size); } } return data; }
double groj_config_get_time(GstMemory *cmem) { GstMapInfo info; gst_memory_map (cmem, &info, GST_MAP_READ); double time = ((struct RojConfig *)info.data)->time; gst_memory_unmap (cmem, &info); return time; }
unsigned long groj_config_get_number(GstMemory *cmem) { GstMapInfo info; gst_memory_map (cmem, &info, GST_MAP_READ); unsigned long number = ((struct RojConfig *)info.data)->number; gst_memory_unmap (cmem, &info); return number; }
static gpointer _pbo_download_transfer (GstGLMemoryPBO * gl_mem, GstMapInfo * info, gsize size) { GstMapInfo *pbo_info; gl_mem->pbo->target = GL_PIXEL_PACK_BUFFER; /* texture -> pbo */ if (info->flags & GST_MAP_READ && GST_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)) { GstMapInfo info; GST_CAT_TRACE (GST_CAT_GL_MEMORY, "attempting download of texture %u " "using pbo %u", gl_mem->mem.tex_id, gl_mem->pbo->id); if (!gst_memory_map (GST_MEMORY_CAST (gl_mem->pbo), &info, GST_MAP_WRITE | GST_MAP_GL)) { GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Failed to write to PBO"); return NULL; } if (!_read_pixels_to_pbo (gl_mem)) { gst_memory_unmap (GST_MEMORY_CAST (gl_mem->pbo), &info); return NULL; } gst_memory_unmap (GST_MEMORY_CAST (gl_mem->pbo), &info); } pbo_info = g_new0 (GstMapInfo, 1); /* pbo -> data */ /* get a cpu accessible mapping from the pbo */ if (!gst_memory_map (GST_MEMORY_CAST (gl_mem->pbo), pbo_info, info->flags)) { GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Failed to map pbo"); g_free (pbo_info); return NULL; } info->user_data[0] = pbo_info; return pbo_info->data; }
/* Custom FreeBlock function for CMBlockBuffer */ static void cm_block_buffer_freeblock (void *refCon, void *doomedMemoryBlock, size_t sizeInBytes) { GstMapInfo *info = (GstMapInfo *) refCon; gst_memory_unmap (info->memory, info); gst_memory_unref (info->memory); g_slice_free (GstMapInfo, info); }
static CMBlockBufferRef cm_block_buffer_from_gst_buffer (GstBuffer * buf, GstMapFlags flags) { OSStatus status; CMBlockBufferRef bbuf; CMBlockBufferCustomBlockSource blockSource; guint memcount, i; /* Initialize custom block source structure */ blockSource.version = kCMBlockBufferCustomBlockSourceVersion; blockSource.AllocateBlock = NULL; blockSource.FreeBlock = cm_block_buffer_freeblock; /* Determine number of memory blocks */ memcount = gst_buffer_n_memory (buf); status = CMBlockBufferCreateEmpty (NULL, memcount, 0, &bbuf); if (status != kCMBlockBufferNoErr) { GST_ERROR ("CMBlockBufferCreateEmpty returned %d", (int) status); return NULL; } /* Go over all GstMemory objects and add them to the CMBlockBuffer */ for (i = 0; i < memcount; ++i) { GstMemory *mem; GstMapInfo *info; mem = gst_buffer_get_memory (buf, i); info = g_slice_new (GstMapInfo); if (!gst_memory_map (mem, info, flags)) { GST_ERROR ("failed mapping memory"); g_slice_free (GstMapInfo, info); gst_memory_unref (mem); CFRelease (bbuf); return NULL; } blockSource.refCon = info; status = CMBlockBufferAppendMemoryBlock (bbuf, info->data, info->size, NULL, &blockSource, 0, info->size, 0); if (status != kCMBlockBufferNoErr) { GST_ERROR ("CMBlockBufferAppendMemoryBlock returned %d", (int) status); gst_memory_unmap (mem, info); g_slice_free (GstMapInfo, info); gst_memory_unref (mem); CFRelease (bbuf); return NULL; } } return bbuf; }
static void _gl_mem_unmap_cpu_access (GstGLMemoryPBO * gl_mem, GstMapInfo * info) { if (!gl_mem->pbo || !CONTEXT_SUPPORTS_PBO_DOWNLOAD (gl_mem->mem.mem.context)) /* PBO's not supported */ return; gl_mem->pbo->target = GL_PIXEL_PACK_BUFFER; gst_memory_unmap (GST_MEMORY_CAST (gl_mem->pbo), (GstMapInfo *) info->user_data[0]); g_free (info->user_data[0]); }
static GstMemory * gst_wl_shm_allocator_alloc (GstAllocator * allocator, gsize size, GstAllocationParams * params) { GstWlShmAllocator *self = GST_WL_SHM_ALLOCATOR (allocator); char filename[1024]; static int init = 0; int fd; GstMemory *mem; GstMapInfo info; /* TODO: make use of the allocation params, if necessary */ /* allocate shm pool */ snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (), "wayland-shm", init++, "XXXXXX"); fd = g_mkstemp (filename); if (fd < 0) { GST_ERROR_OBJECT (self, "opening temp file %s failed: %s", filename, strerror (errno)); return NULL; } if (ftruncate (fd, size) < 0) { GST_ERROR_OBJECT (self, "ftruncate failed: %s", strerror (errno)); close (fd); return NULL; } mem = gst_fd_allocator_alloc (allocator, fd, size, GST_FD_MEMORY_FLAG_KEEP_MAPPED); if (G_UNLIKELY (!mem)) { GST_ERROR_OBJECT (self, "GstFdMemory allocation failed"); close (fd); return NULL; } /* we need to map the memory in order to unlink the file without losing it */ if (!gst_memory_map (mem, &info, GST_MAP_READWRITE)) { GST_ERROR_OBJECT (self, "GstFdMemory map failed"); close (fd); return NULL; } /* unmap will not really munmap(), we just * need it to release the miniobject lock */ gst_memory_unmap (mem, &info); unlink (filename); return mem; }
static gboolean _read_pixels_to_pbo (GstGLMemoryPBO * gl_mem) { if (!gl_mem->pbo || !CONTEXT_SUPPORTS_PBO_DOWNLOAD (gl_mem->mem.mem.context) || gl_mem->mem.tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE || gl_mem->mem.tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA) /* unsupported */ return FALSE; if (GST_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)) { /* copy texture data into into the pbo and map that */ gsize plane_start; GstMapInfo pbo_info; plane_start = gst_gl_get_plane_start (&gl_mem->mem.info, &gl_mem->mem.valign, gl_mem->mem.plane) + GST_MEMORY_CAST (gl_mem)->offset; gl_mem->pbo->target = GL_PIXEL_PACK_BUFFER; if (!gst_memory_map (GST_MEMORY_CAST (gl_mem->pbo), &pbo_info, GST_MAP_WRITE | GST_MAP_GL)) { GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Failed to map pbo for writing"); return FALSE; } if (!gst_gl_memory_read_pixels ((GstGLMemory *) gl_mem, (gpointer) plane_start)) { gst_memory_unmap (GST_MEMORY_CAST (gl_mem->pbo), &pbo_info); return FALSE; } gst_memory_unmap (GST_MEMORY_CAST (gl_mem->pbo), &pbo_info); } return TRUE; }
static void gst_udpsrc_reset_memory_allocator (GstUDPSrc * src) { if (src->mem != NULL) { gst_memory_unmap (src->mem, &src->map); gst_memory_unref (src->mem); src->mem = NULL; } if (src->mem_max != NULL) { gst_memory_unmap (src->mem_max, &src->map_max); gst_memory_unref (src->mem_max); src->mem_max = NULL; } src->vec[0].buffer = NULL; src->vec[0].size = 0; src->vec[1].buffer = NULL; src->vec[1].size = 0; if (src->allocator != NULL) { gst_object_unref (src->allocator); src->allocator = NULL; } }
static void _upload_transfer (GstGLContext * context, GstGLMemoryPBO * gl_mem) { GstGLBaseMemory *mem = (GstGLBaseMemory *) gl_mem; GstMapInfo info; g_mutex_lock (&mem->lock); gl_mem->pbo->target = GL_PIXEL_UNPACK_BUFFER; if (!gst_memory_map (GST_MEMORY_CAST (gl_mem->pbo), &info, GST_MAP_READ | GST_MAP_GL)) { GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Failed to map pbo for reading"); } else { gst_memory_unmap (GST_MEMORY_CAST (gl_mem->pbo), &info); } g_mutex_unlock (&mem->lock); }
static gboolean _do_download (GstGLDownload * download, guint texture_id, gpointer data[GST_VIDEO_MAX_PLANES]) { guint out_width, out_height; GstBuffer *inbuf, *outbuf; GstMapInfo map_info; gboolean ret = TRUE; gint i; out_width = GST_VIDEO_INFO_WIDTH (&download->info); out_height = GST_VIDEO_INFO_HEIGHT (&download->info); if (!download->initted) { if (!_init_download (download)) return FALSE; } GST_TRACE ("doing download of texture:%u (%ux%u)", download->priv->in_tex[0]->tex_id, out_width, out_height); inbuf = gst_buffer_new (); gst_buffer_append_memory (inbuf, gst_memory_ref ((GstMemory *) download->priv->in_tex[0])); outbuf = gst_gl_color_convert_perform (download->convert, inbuf); if (!outbuf) return FALSE; for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&download->info); i++) { GstMemory *out_mem = gst_buffer_peek_memory (outbuf, i); gpointer temp_data = ((GstGLMemory *) out_mem)->data; ((GstGLMemory *) out_mem)->data = data[i]; if (!gst_memory_map (out_mem, &map_info, GST_MAP_READ)) { GST_ERROR_OBJECT (download, "Failed to map memory"); ret = FALSE; } gst_memory_unmap (out_mem, &map_info); ((GstGLMemory *) out_mem)->data = temp_data; } gst_buffer_unref (inbuf); gst_buffer_unref (outbuf); return ret; }
void GStreamerReader::CopyIntoImageBuffer(GstBuffer* aBuffer, GstBuffer** aOutBuffer, nsRefPtr<PlanarYCbCrImage> &image) { *aOutBuffer = gst_buffer_new_allocate(mAllocator, gst_buffer_get_size(aBuffer), nullptr); GstMemory *mem = gst_buffer_peek_memory(*aOutBuffer, 0); GstMapInfo map_info; gst_memory_map(mem, &map_info, GST_MAP_WRITE); gst_buffer_extract(aBuffer, 0, map_info.data, gst_buffer_get_size(aBuffer)); gst_memory_unmap(mem, &map_info); /* create a new gst buffer with the newly created memory and copy the * metadata over from the incoming buffer */ gst_buffer_copy_into(*aOutBuffer, aBuffer, (GstBufferCopyFlags)(GST_BUFFER_COPY_METADATA), 0, -1); image = GetImageFromBuffer(*aOutBuffer); }
static GstFlowReturn gst_shm_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstShmSink *self = GST_SHM_SINK (bsink); int rv = 0; GstMapInfo map; gboolean need_new_memory = FALSE; GstFlowReturn ret = GST_FLOW_OK; GstMemory *memory = NULL; GstBuffer *sendbuf = NULL; gsize written_bytes; GST_OBJECT_LOCK (self); while (self->wait_for_connection && !self->clients) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { GST_OBJECT_UNLOCK (self); ret = gst_base_sink_wait_preroll (bsink); if (ret == GST_FLOW_OK) GST_OBJECT_LOCK (self); else return ret; } } while (!gst_shm_sink_can_render (self, GST_BUFFER_TIMESTAMP (buf))) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { GST_OBJECT_UNLOCK (self); ret = gst_base_sink_wait_preroll (bsink); if (ret == GST_FLOW_OK) GST_OBJECT_LOCK (self); else return ret; } } if (gst_buffer_n_memory (buf) > 1) { GST_LOG_OBJECT (self, "Buffer %p has %d GstMemory, we only support a single" " one, need to do a memcpy", buf, gst_buffer_n_memory (buf)); need_new_memory = TRUE; } else { memory = gst_buffer_peek_memory (buf, 0); if (memory->allocator != GST_ALLOCATOR (self->allocator)) { need_new_memory = TRUE; GST_LOG_OBJECT (self, "Memory in buffer %p was not allocated by " "%" GST_PTR_FORMAT ", will memcpy", buf, memory->allocator); } } if (need_new_memory) { if (gst_buffer_get_size (buf) > sp_writer_get_max_buf_size (self->pipe)) { gsize area_size = sp_writer_get_max_buf_size (self->pipe); GST_ELEMENT_ERROR (self, RESOURCE, NO_SPACE_LEFT, (NULL), ("Shared memory area of size %" G_GSIZE_FORMAT " is smaller than" "buffer of size %" G_GSIZE_FORMAT, area_size, gst_buffer_get_size (buf))); goto error; } while ((memory = gst_shm_sink_allocator_alloc_locked (self->allocator, gst_buffer_get_size (buf), &self->params)) == NULL) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { GST_OBJECT_UNLOCK (self); ret = gst_base_sink_wait_preroll (bsink); if (ret == GST_FLOW_OK) GST_OBJECT_LOCK (self); else return ret; } } while (self->wait_for_connection && !self->clients) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { GST_OBJECT_UNLOCK (self); ret = gst_base_sink_wait_preroll (bsink); if (ret == GST_FLOW_OK) { GST_OBJECT_LOCK (self); } else { gst_memory_unref (memory); return ret; } } } if (!gst_memory_map (memory, &map, GST_MAP_WRITE)) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("Failed to map memory")); goto error; } GST_DEBUG_OBJECT (self, "Copying %" G_GSIZE_FORMAT " bytes into map of size %" G_GSIZE_FORMAT " bytes.", gst_buffer_get_size (buf), map.size); written_bytes = gst_buffer_extract (buf, 0, map.data, map.size); GST_DEBUG_OBJECT (self, "Copied %" G_GSIZE_FORMAT " bytes.", written_bytes); gst_memory_unmap (memory, &map); sendbuf = gst_buffer_new (); if (!gst_buffer_copy_into (sendbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1)) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("Failed to copy data into send buffer")); gst_buffer_unref (sendbuf); goto error; } gst_buffer_append_memory (sendbuf, memory); } else { sendbuf = gst_buffer_ref (buf); } if (!gst_buffer_map (sendbuf, &map, GST_MAP_READ)) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("Failed to map data into send buffer")); goto error; } /* Make the memory readonly as of now as we've sent it to the other side * We know it's not mapped for writing anywhere as we just mapped it for * reading */ rv = sp_writer_send_buf (self->pipe, (char *) map.data, map.size, sendbuf); if (rv == -1) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("Failed to send data over SHM")); gst_buffer_unmap (sendbuf, &map); goto error; } gst_buffer_unmap (sendbuf, &map); GST_OBJECT_UNLOCK (self); if (rv == 0) { GST_DEBUG_OBJECT (self, "No clients connected, unreffing buffer"); gst_buffer_unref (sendbuf); } return ret; error: GST_OBJECT_UNLOCK (self); return GST_FLOW_ERROR; }
static void _gl_mem_copy_thread (GstGLContext * context, gpointer data) { const GstGLFuncs *gl; GstGLMemoryPBOCopyParams *copy_params; GstGLMemoryPBO *src; guint tex_id; guint out_tex_target; GLuint fboId; gsize out_width, out_height, out_stride; GLuint out_gl_format, out_gl_type; GLuint in_gl_format, in_gl_type; gsize in_size, out_size; copy_params = (GstGLMemoryPBOCopyParams *) data; src = copy_params->src; tex_id = copy_params->tex_id; out_tex_target = gst_gl_texture_target_to_gl (copy_params->tex_target); out_width = copy_params->out_width; out_height = copy_params->out_height; out_stride = copy_params->out_stride; gl = context->gl_vtable; out_gl_format = gst_gl_format_from_gl_texture_type (copy_params->out_format); out_gl_type = GL_UNSIGNED_BYTE; if (copy_params->out_format == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) out_gl_type = GL_UNSIGNED_SHORT_5_6_5; in_gl_format = gst_gl_format_from_gl_texture_type (src->mem.tex_type); in_gl_type = GL_UNSIGNED_BYTE; if (src->mem.tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) in_gl_type = GL_UNSIGNED_SHORT_5_6_5; if (!gl->GenFramebuffers) { gst_gl_context_set_error (context, "Context, EXT_framebuffer_object not supported"); goto error; } in_size = GL_MEM_HEIGHT (src) * GL_MEM_STRIDE (src); out_size = out_height * out_stride; if (copy_params->respecify) { if (in_size != out_size) { GST_ERROR ("Cannot copy between textures with backing data of different" "sizes. input %" G_GSIZE_FORMAT " output %" G_GSIZE_FORMAT, in_size, out_size); goto error; } } if (!tex_id) { guint internal_format; guint out_gl_type; out_gl_type = GL_UNSIGNED_BYTE; if (copy_params->out_format == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) out_gl_type = GL_UNSIGNED_SHORT_5_6_5; internal_format = gst_gl_sized_gl_format_from_gl_format_type (context, out_gl_format, out_gl_type); tex_id = _new_texture (context, out_tex_target, internal_format, out_gl_format, out_gl_type, copy_params->out_width, copy_params->out_height); } if (!tex_id) { GST_WARNING ("Could not create GL texture with context:%p", context); } GST_LOG ("copying memory %p, tex %u into texture %i", src, src->mem.tex_id, tex_id); /* FIXME: try and avoid creating and destroying fbo's every copy... */ /* create a framebuffer object */ gl->GenFramebuffers (1, &fboId); gl->BindFramebuffer (GL_FRAMEBUFFER, fboId); gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, gst_gl_texture_target_to_gl (src->mem.tex_target), src->mem.tex_id, 0); // if (!gst_gl_context_check_framebuffer_status (src->mem.mem.context)) // goto fbo_error; gl->BindTexture (out_tex_target, tex_id); if (copy_params->respecify) { GstMapInfo pbo_info; if (!gl->GenBuffers || !src->pbo) { gst_gl_context_set_error (context, "Cannot reinterpret texture contents " "without pixel buffer objects"); gl->BindTexture (out_tex_target, 0); goto fbo_error; } if (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2 && (in_gl_format != GL_RGBA || in_gl_type != GL_UNSIGNED_BYTE)) { gst_gl_context_set_error (context, "Cannot copy non RGBA/UNSIGNED_BYTE " "textures on GLES2"); gl->BindTexture (out_tex_target, 0); goto fbo_error; } GST_TRACE ("copying texture data with size of %u*%u*%u", gst_gl_format_type_n_bytes (in_gl_format, in_gl_type), src->mem.tex_width, GL_MEM_HEIGHT (src)); /* copy tex */ _read_pixels_to_pbo (src); src->pbo->target = GL_PIXEL_UNPACK_BUFFER; if (!gst_memory_map (GST_MEMORY_CAST (src->pbo), &pbo_info, GST_MAP_READ | GST_MAP_GL)) { GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Failed to map pbo for reading"); goto fbo_error; } gl->TexSubImage2D (out_tex_target, 0, 0, 0, out_width, out_height, out_gl_format, out_gl_type, 0); gst_memory_unmap (GST_MEMORY_CAST (src->pbo), &pbo_info); } else { /* different sizes */ gst_gl_memory_copy_teximage (GST_GL_MEMORY_CAST (src), tex_id, copy_params->tex_target, copy_params->out_format, out_width, out_height); } gl->BindTexture (out_tex_target, 0); gl->BindFramebuffer (GL_FRAMEBUFFER, 0); gl->DeleteFramebuffers (1, &fboId); copy_params->tex_id = tex_id; copy_params->result = TRUE; return; /* ERRORS */ fbo_error: { gl->DeleteFramebuffers (1, &fboId); copy_params->tex_id = 0; copy_params->result = FALSE; return; } error: { copy_params->result = FALSE; return; } }
/* Copy fixed header and extension. Replace current ssrc by ssrc1, * remove OSN and replace current seq num by OSN. * Copy memory to avoid to manually copy each rtp buffer field. */ static GstBuffer * _gst_rtp_buffer_new_from_rtx (GstRTPBuffer * rtp, guint32 ssrc1, guint16 orign_seqnum, guint8 origin_payload_type) { GstMemory *mem = NULL; GstRTPBuffer new_rtp = GST_RTP_BUFFER_INIT; GstBuffer *new_buffer = gst_buffer_new (); GstMapInfo map; guint payload_len = 0; /* copy fixed header */ mem = gst_memory_copy (rtp->map[0].memory, (guint8 *) rtp->data[0] - rtp->map[0].data, rtp->size[0]); gst_buffer_append_memory (new_buffer, mem); /* copy extension if any */ if (rtp->size[1]) { mem = gst_memory_copy (rtp->map[1].memory, (guint8 *) rtp->data[1] - rtp->map[1].data, rtp->size[1]); gst_buffer_append_memory (new_buffer, mem); } /* copy payload and remove OSN */ payload_len = rtp->size[2] - 2; mem = gst_allocator_alloc (NULL, payload_len, NULL); gst_memory_map (mem, &map, GST_MAP_WRITE); if (rtp->size[2]) memcpy (map.data, (guint8 *) rtp->data[2] + 2, payload_len); gst_memory_unmap (mem, &map); gst_buffer_append_memory (new_buffer, mem); /* the sender always constructs rtx packets without padding, * But the receiver can still receive rtx packets with padding. * So just copy it. */ if (rtp->size[3]) { guint pad_len = rtp->size[3]; mem = gst_allocator_alloc (NULL, pad_len, NULL); gst_memory_map (mem, &map, GST_MAP_WRITE); map.data[pad_len - 1] = pad_len; gst_memory_unmap (mem, &map); gst_buffer_append_memory (new_buffer, mem); } /* set ssrc and seq num */ gst_rtp_buffer_map (new_buffer, GST_MAP_WRITE, &new_rtp); gst_rtp_buffer_set_ssrc (&new_rtp, ssrc1); gst_rtp_buffer_set_seq (&new_rtp, orign_seqnum); gst_rtp_buffer_set_payload_type (&new_rtp, origin_payload_type); gst_rtp_buffer_unmap (&new_rtp); gst_buffer_copy_into (new_buffer, rtp->buffer, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1); GST_BUFFER_FLAG_SET (new_buffer, GST_RTP_BUFFER_FLAG_RETRANSMISSION); return new_buffer; }
static GstFlowReturn gst_multiudpsink_render (GstBaseSink * bsink, GstBuffer * buffer) { GstMultiUDPSink *sink; GList *clients; GOutputVector *vec; GstMapInfo *map; guint n_mem, i; gsize size; GstMemory *mem; gint num, no_clients; GError *err = NULL; sink = GST_MULTIUDPSINK (bsink); n_mem = gst_buffer_n_memory (buffer); if (n_mem == 0) goto no_data; /* allocated on the stack, the max number of memory blocks is limited so this * should not cause stack overflows */ vec = sink->vec; map = sink->map; size = 0; for (i = 0; i < n_mem; i++) { mem = gst_buffer_get_memory (buffer, i); gst_memory_map (mem, &map[i], GST_MAP_READ); vec[i].buffer = map[i].data; vec[i].size = map[i].size; size += map[i].size; } sink->bytes_to_serve += size; /* grab lock while iterating and sending to clients, this should be * fast as UDP never blocks */ g_mutex_lock (&sink->client_lock); GST_LOG_OBJECT (bsink, "about to send %" G_GSIZE_FORMAT " bytes in %u blocks", size, n_mem); no_clients = 0; num = 0; for (clients = sink->clients; clients; clients = g_list_next (clients)) { GstUDPClient *client; GSocket *socket; GSocketFamily family; gint count; client = (GstUDPClient *) clients->data; no_clients++; GST_LOG_OBJECT (sink, "sending %" G_GSIZE_FORMAT " bytes to client %p", size, client); family = g_socket_address_get_family (G_SOCKET_ADDRESS (client->addr)); /* Select socket to send from for this address */ if (family == G_SOCKET_FAMILY_IPV6 || !sink->used_socket) socket = sink->used_socket_v6; else socket = sink->used_socket; count = sink->send_duplicates ? client->refcount : 1; while (count--) { gssize ret; ret = g_socket_send_message (socket, client->addr, vec, n_mem, NULL, 0, 0, sink->cancellable, &err); if (G_UNLIKELY (ret < 0)) { if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) goto flushing; /* we continue after posting a warning, next packets might be ok * again */ if (size > UDP_MAX_SIZE) { GST_ELEMENT_WARNING (sink, RESOURCE, WRITE, ("Attempting to send a UDP packet larger than maximum size " "(%" G_GSIZE_FORMAT " > %d)", size, UDP_MAX_SIZE), ("Reason: %s", err ? err->message : "unknown reason")); } else { GST_ELEMENT_WARNING (sink, RESOURCE, WRITE, ("Error sending UDP packet"), ("Reason: %s", err ? err->message : "unknown reason")); } g_clear_error (&err); } else { num++; client->bytes_sent += ret; client->packets_sent++; sink->bytes_served += ret; } } } g_mutex_unlock (&sink->client_lock); /* unmap all memory again */ for (i = 0; i < n_mem; i++) { gst_memory_unmap (map[i].memory, &map[i]); gst_memory_unref (map[i].memory); } GST_LOG_OBJECT (sink, "sent %" G_GSIZE_FORMAT " bytes to %d (of %d) clients", size, num, no_clients); return GST_FLOW_OK; no_data: { return GST_FLOW_OK; } flushing: { GST_DEBUG ("we are flushing"); g_mutex_unlock (&sink->client_lock); g_clear_error (&err); /* unmap all memory */ for (i = 0; i < n_mem; i++) { gst_memory_unmap (map[i].memory, &map[i]); gst_memory_unref (map[i].memory); } return GST_FLOW_FLUSHING; } }
static GstFlowReturn gst_shm_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstShmSink *self = GST_SHM_SINK (bsink); int rv = 0; GstMapInfo map; gboolean need_new_memory = FALSE; GstFlowReturn ret = GST_FLOW_OK; GstMemory *memory = NULL; GstBuffer *sendbuf = NULL; GST_OBJECT_LOCK (self); while (self->wait_for_connection && !self->clients) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) goto flushing; } while (!gst_shm_sink_can_render (self, GST_BUFFER_TIMESTAMP (buf))) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) goto flushing; } if (gst_buffer_n_memory (buf) > 1) { GST_LOG_OBJECT (self, "Buffer %p has %d GstMemory, we only support a single" " one, need to do a memcpy", buf, gst_buffer_n_memory (buf)); need_new_memory = TRUE; } else { memory = gst_buffer_peek_memory (buf, 0); if (memory->allocator != GST_ALLOCATOR (self->allocator)) { need_new_memory = TRUE; GST_LOG_OBJECT (self, "Memory in buffer %p was not allocated by " "%" GST_PTR_FORMAT ", will memcpy", buf, memory->allocator); } } if (need_new_memory) { if (gst_buffer_get_size (buf) > sp_writer_get_max_buf_size (self->pipe)) { gsize area_size = sp_writer_get_max_buf_size (self->pipe); GST_OBJECT_UNLOCK (self); GST_ELEMENT_ERROR (self, RESOURCE, NO_SPACE_LEFT, ("Shared memory area is too small"), ("Shared memory area of size %" G_GSIZE_FORMAT " is smaller than" "buffer of size %" G_GSIZE_FORMAT, area_size, gst_buffer_get_size (buf))); return GST_FLOW_ERROR; } while ((memory = gst_shm_sink_allocator_alloc_locked (self->allocator, gst_buffer_get_size (buf), &self->params)) == NULL) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) goto flushing; } while (self->wait_for_connection && !self->clients) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { gst_memory_unref (memory); GST_OBJECT_UNLOCK (self); return GST_FLOW_FLUSHING; } } gst_memory_map (memory, &map, GST_MAP_WRITE); gst_buffer_extract (buf, 0, map.data, map.size); gst_memory_unmap (memory, &map); sendbuf = gst_buffer_new (); gst_buffer_copy_into (sendbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1); gst_buffer_append_memory (sendbuf, memory); } else { sendbuf = gst_buffer_ref (buf); } gst_buffer_map (sendbuf, &map, GST_MAP_READ); /* Make the memory readonly as of now as we've sent it to the other side * We know it's not mapped for writing anywhere as we just mapped it for * reading */ rv = sp_writer_send_buf (self->pipe, (char *) map.data, map.size, sendbuf); gst_buffer_unmap (sendbuf, &map); GST_OBJECT_UNLOCK (self); if (rv == 0) { GST_DEBUG_OBJECT (self, "No clients connected, unreffing buffer"); gst_buffer_unref (sendbuf); } else if (rv == -1) { GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Invalid allocated buffer"), ("The shmpipe library rejects our buffer, this is a bug")); ret = GST_FLOW_ERROR; } /* If we allocated our own memory, then unmap it */ return ret; flushing: GST_OBJECT_UNLOCK (self); return GST_FLOW_FLUSHING; }
static void test_transfer_allocator (const gchar * allocator_name) { GstAllocator *gl_allocator; GstGLBaseMemoryAllocator *base_mem_alloc; GstVideoInfo v_info; GstMemory *mem, *mem2, *mem3; GstMapInfo map_info; GstGLVideoAllocationParams *params; gl_allocator = gst_allocator_find (allocator_name); fail_if (gl_allocator == NULL); base_mem_alloc = GST_GL_BASE_MEMORY_ALLOCATOR (gl_allocator); gst_video_info_set_format (&v_info, GST_VIDEO_FORMAT_RGBA, 1, 1); params = gst_gl_video_allocation_params_new (context, NULL, &v_info, 0, NULL, GST_GL_TEXTURE_TARGET_2D, GST_VIDEO_GL_TEXTURE_TYPE_RGBA); /* texture creation */ mem = (GstMemory *) gst_gl_base_memory_alloc (base_mem_alloc, (GstGLAllocationParams *) params); gst_gl_allocation_params_free ((GstGLAllocationParams *) params); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); /* test wrapping raw data */ params = gst_gl_video_allocation_params_new_wrapped_data (context, NULL, &v_info, 0, NULL, GST_GL_TEXTURE_TARGET_2D, GST_VIDEO_GL_TEXTURE_TYPE_RGBA, rgba_pixel, NULL, NULL); mem2 = (GstMemory *) gst_gl_base_memory_alloc (base_mem_alloc, (GstGLAllocationParams *) params); gst_gl_allocation_params_free ((GstGLAllocationParams *) params); fail_if (mem == NULL); fail_unless (GST_MEMORY_FLAG_IS_SET (mem2, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); /* wrapped texture creation */ params = gst_gl_video_allocation_params_new_wrapped_texture (context, NULL, &v_info, 0, NULL, GST_GL_TEXTURE_TARGET_2D, GST_VIDEO_GL_TEXTURE_TYPE_RGBA, ((GstGLMemory *) mem)->tex_id, NULL, NULL); mem3 = (GstMemory *) gst_gl_base_memory_alloc (base_mem_alloc, (GstGLAllocationParams *) params); gst_gl_allocation_params_free ((GstGLAllocationParams *) params); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem3, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (GST_MEMORY_FLAG_IS_SET (mem3, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); /* check data/flags are correct */ fail_unless (gst_memory_map (mem2, &map_info, GST_MAP_READ)); fail_unless (GST_MEMORY_FLAG_IS_SET (mem2, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); fail_unless (memcmp (map_info.data, rgba_pixel, G_N_ELEMENTS (rgba_pixel)) == 0, "0x%02x%02x%02x%02x != 0x%02x%02x%02x%02x", map_info.data[0], map_info.data[1], map_info.data[2], map_info.data[3], (guint8) rgba_pixel[0], (guint8) rgba_pixel[1], (guint8) rgba_pixel[2], (guint8) rgba_pixel[3]); gst_memory_unmap (mem2, &map_info); fail_unless (GST_MEMORY_FLAG_IS_SET (mem2, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); fail_unless (gst_memory_map (mem2, &map_info, GST_MAP_READ | GST_MAP_GL)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); /* test texture copy */ fail_unless (gst_gl_memory_copy_into ((GstGLMemory *) mem2, ((GstGLMemory *) mem)->tex_id, GST_GL_TEXTURE_TARGET_2D, GST_VIDEO_GL_TEXTURE_TYPE_RGBA, 1, 1)); GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (GST_MEMORY_FLAG_IS_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); gst_memory_unmap (mem2, &map_info); /* test download of copied texture */ fail_unless (gst_memory_map (mem, &map_info, GST_MAP_READ)); fail_unless (memcmp (map_info.data, rgba_pixel, G_N_ELEMENTS (rgba_pixel)) == 0, "0x%02x%02x%02x%02x != 0x%02x%02x%02x%02x", (guint8) map_info.data[0], (guint8) map_info.data[1], (guint8) map_info.data[2], (guint8) map_info.data[3], (guint8) rgba_pixel[0], (guint8) rgba_pixel[1], (guint8) rgba_pixel[2], (guint8) rgba_pixel[3]); gst_memory_unmap (mem, &map_info); /* test download of wrapped copied texture */ fail_unless (gst_memory_map (mem3, &map_info, GST_MAP_READ)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); fail_unless (memcmp (map_info.data, rgba_pixel, G_N_ELEMENTS (rgba_pixel)) == 0, "0x%02x%02x%02x%02x != 0x%02x%02x%02x%02x", (guint8) map_info.data[0], (guint8) map_info.data[1], (guint8) map_info.data[2], (guint8) map_info.data[3], (guint8) rgba_pixel[0], (guint8) rgba_pixel[1], (guint8) rgba_pixel[2], (guint8) rgba_pixel[3]); gst_memory_unmap (mem3, &map_info); /* test upload flag */ fail_unless (gst_memory_map (mem3, &map_info, GST_MAP_WRITE)); gst_memory_unmap (mem3, &map_info); fail_unless (GST_MEMORY_FLAG_IS_SET (mem3, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem3, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); /* test download flag */ fail_unless (gst_memory_map (mem3, &map_info, GST_MAP_WRITE | GST_MAP_GL)); gst_memory_unmap (mem3, &map_info); fail_unless (!GST_MEMORY_FLAG_IS_SET (mem3, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD)); fail_unless (GST_MEMORY_FLAG_IS_SET (mem3, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD)); gst_memory_unref (mem); gst_memory_unref (mem2); gst_memory_unref (mem3); gst_object_unref (gl_allocator); }
static GstFlowReturn gst_openjpeg_enc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame) { GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (encoder); GstFlowReturn ret = GST_FLOW_OK; #ifdef HAVE_OPENJPEG_1 opj_cinfo_t *enc; GstMapInfo map; guint length; opj_cio_t *io; #else opj_codec_t *enc; opj_stream_t *stream; MemStream mstream; #endif opj_image_t *image; GstVideoFrame vframe; GST_DEBUG_OBJECT (self, "Handling frame"); enc = opj_create_compress (self->codec_format); if (!enc) goto initialization_error; #ifdef HAVE_OPENJPEG_1 if (G_UNLIKELY (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= GST_LEVEL_TRACE)) { opj_event_mgr_t callbacks; callbacks.error_handler = gst_openjpeg_enc_opj_error; callbacks.warning_handler = gst_openjpeg_enc_opj_warning; callbacks.info_handler = gst_openjpeg_enc_opj_info; opj_set_event_mgr ((opj_common_ptr) enc, &callbacks, self); } else { opj_set_event_mgr ((opj_common_ptr) enc, NULL, NULL); } #else if (G_UNLIKELY (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= GST_LEVEL_TRACE)) { opj_set_info_handler (enc, gst_openjpeg_enc_opj_info, self); opj_set_warning_handler (enc, gst_openjpeg_enc_opj_warning, self); opj_set_error_handler (enc, gst_openjpeg_enc_opj_error, self); } else { opj_set_info_handler (enc, NULL, NULL); opj_set_warning_handler (enc, NULL, NULL); opj_set_error_handler (enc, NULL, NULL); } #endif if (!gst_video_frame_map (&vframe, &self->input_state->info, frame->input_buffer, GST_MAP_READ)) goto map_read_error; image = gst_openjpeg_enc_fill_image (self, &vframe); if (!image) goto fill_image_error; gst_video_frame_unmap (&vframe); opj_setup_encoder (enc, &self->params, image); #ifdef HAVE_OPENJPEG_1 io = opj_cio_open ((opj_common_ptr) enc, NULL, 0); if (!io) goto open_error; if (!opj_encode (enc, io, image, NULL)) goto encode_error; opj_image_destroy (image); length = cio_tell (io); ret = gst_video_encoder_allocate_output_frame (encoder, frame, length + (self->is_jp2c ? 8 : 0)); if (ret != GST_FLOW_OK) goto allocate_error; gst_buffer_fill (frame->output_buffer, self->is_jp2c ? 8 : 0, io->buffer, length); if (self->is_jp2c) { gst_buffer_map (frame->output_buffer, &map, GST_MAP_WRITE); GST_WRITE_UINT32_BE (map.data, length + 8); GST_WRITE_UINT32_BE (map.data + 4, GST_MAKE_FOURCC ('j', 'p', '2', 'c')); gst_buffer_unmap (frame->output_buffer, &map); } opj_cio_close (io); opj_destroy_compress (enc); #else stream = opj_stream_create (4096, OPJ_FALSE); if (!stream) goto open_error; mstream.allocsize = 4096; mstream.data = g_malloc (mstream.allocsize); mstream.offset = 0; mstream.size = 0; opj_stream_set_read_function (stream, read_fn); opj_stream_set_write_function (stream, write_fn); opj_stream_set_skip_function (stream, skip_fn); opj_stream_set_seek_function (stream, seek_fn); opj_stream_set_user_data (stream, &mstream); opj_stream_set_user_data_length (stream, mstream.size); if (!opj_start_compress (enc, image, stream)) goto encode_error; if (!opj_encode (enc, stream)) goto encode_error; if (!opj_end_compress (enc, stream)) goto encode_error; opj_image_destroy (image); opj_stream_destroy (stream); opj_destroy_codec (enc); frame->output_buffer = gst_buffer_new (); if (self->is_jp2c) { GstMapInfo map; GstMemory *mem; mem = gst_allocator_alloc (NULL, 8, NULL); gst_memory_map (mem, &map, GST_MAP_WRITE); GST_WRITE_UINT32_BE (map.data, mstream.size + 8); GST_WRITE_UINT32_BE (map.data + 4, GST_MAKE_FOURCC ('j', 'p', '2', 'c')); gst_memory_unmap (mem, &map); gst_buffer_append_memory (frame->output_buffer, mem); } gst_buffer_append_memory (frame->output_buffer, gst_memory_new_wrapped (0, mstream.data, mstream.allocsize, 0, mstream.size, NULL, (GDestroyNotify) g_free)); #endif ret = gst_video_encoder_finish_frame (encoder, frame); return ret; initialization_error: { gst_video_codec_frame_unref (frame); GST_ELEMENT_ERROR (self, LIBRARY, INIT, ("Failed to initialize OpenJPEG encoder"), (NULL)); return GST_FLOW_ERROR; } map_read_error: { #ifdef HAVE_OPENJPEG_1 opj_destroy_compress (enc); #else opj_destroy_codec (enc); #endif gst_video_codec_frame_unref (frame); GST_ELEMENT_ERROR (self, CORE, FAILED, ("Failed to map input buffer"), (NULL)); return GST_FLOW_ERROR; } fill_image_error: { #ifdef HAVE_OPENJPEG_1 opj_destroy_compress (enc); #else opj_destroy_codec (enc); #endif gst_video_frame_unmap (&vframe); gst_video_codec_frame_unref (frame); GST_ELEMENT_ERROR (self, LIBRARY, INIT, ("Failed to fill OpenJPEG image"), (NULL)); return GST_FLOW_ERROR; } open_error: { opj_image_destroy (image); #ifdef HAVE_OPENJPEG_1 opj_destroy_compress (enc); #else opj_destroy_codec (enc); #endif gst_video_codec_frame_unref (frame); GST_ELEMENT_ERROR (self, LIBRARY, INIT, ("Failed to open OpenJPEG data"), (NULL)); return GST_FLOW_ERROR; } encode_error: { #ifdef HAVE_OPENJPEG_1 opj_cio_close (io); opj_image_destroy (image); opj_destroy_compress (enc); #else opj_stream_destroy (stream); g_free (mstream.data); opj_image_destroy (image); opj_destroy_codec (enc); #endif gst_video_codec_frame_unref (frame); GST_ELEMENT_ERROR (self, STREAM, ENCODE, ("Failed to encode OpenJPEG stream"), (NULL)); return GST_FLOW_ERROR; } #ifdef HAVE_OPENJPEG_1 allocate_error: { opj_cio_close (io); opj_destroy_compress (enc); gst_video_codec_frame_unref (frame); GST_ELEMENT_ERROR (self, CORE, FAILED, ("Failed to allocate output buffer"), (NULL)); return ret; } #endif }
gboolean _gst_playbin_get_current_frame (GstElement *playbin, int video_fps_n, int video_fps_d, FrameReadyCallback cb, gpointer user_data) { ScreenshotData *data; GstCaps *to_caps; GstSample *sample; GstCaps *sample_caps; GstStructure *s; int outwidth; int outheight; data = g_new0 (ScreenshotData, 1); data->cb = cb; data->user_data = user_data; /* our desired output format (RGB24) */ to_caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "RGB", /* Note: we don't ask for a specific width/height here, so that * videoscale can adjust dimensions from a non-1/1 pixel aspect * ratio to a 1/1 pixel-aspect-ratio. We also don't ask for a * specific framerate, because the input framerate won't * necessarily match the output framerate if there's a deinterlacer * in the pipeline. */ "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, NULL); /* get frame */ sample = NULL; g_signal_emit_by_name (playbin, "convert-sample", to_caps, &sample); gst_caps_unref (to_caps); if (sample == NULL) { g_warning ("Could not take screenshot: %s", "failed to retrieve or convert video frame"); screenshot_data_finalize (data); return FALSE; } sample_caps = gst_sample_get_caps (sample); if (sample_caps == NULL) { g_warning ("Could not take screenshot: %s", "no caps on output buffer"); return FALSE; } s = gst_caps_get_structure (sample_caps, 0); gst_structure_get_int (s, "width", &outwidth); gst_structure_get_int (s, "height", &outheight); if ((outwidth > 0) && (outheight > 0)) { GstMemory *memory; GstMapInfo info; memory = gst_buffer_get_memory (gst_sample_get_buffer (sample), 0); gst_memory_map (memory, &info, GST_MAP_READ); data->pixbuf = gdk_pixbuf_new_from_data (info.data, GDK_COLORSPACE_RGB, FALSE, 8, outwidth, outheight, GST_ROUND_UP_4 (outwidth * 3), destroy_pixbuf, sample); gst_memory_unmap (memory, &info); } if (data->pixbuf == NULL) g_warning ("Could not take screenshot: %s", "could not create pixbuf"); screenshot_data_finalize (data); return TRUE; }