static void gst_omxbuffertransport_finalize(GstBuffer *gstbuffer) { GstOmxBufferTransport *self = GST_OMXBUFFERTRANSPORT(gstbuffer); GST_LOG("begin\n"); release_buffer (self->port, self->omxbuffer); self->omxbuffer = NULL; self->port = NULL; /* Call GstBuffer's finalize routine, so our base class can do it's cleanup * as well. If we don't do this, we'll have a memory leak that is very * difficult to track down. */ GST_BUFFER_CLASS(parent_class)-> mini_object_class.finalize(GST_MINI_OBJECT(gstbuffer)); GST_LOG("end finalize\n"); }
static void gupnp_dlna_gst_image_information_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { GUPnPDLNAGstImageInformation *info = GUPNP_DLNA_GST_IMAGE_INFORMATION (object); GUPnPDLNAGstImageInformationPrivate *priv = info->priv; switch (property_id) { case PROP_INFO: gst_value_set_mini_object (value, GST_MINI_OBJECT (priv->info)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } }
static void gst_pvr_bufferpool_finalize (GstPvrBufferPool * self) { GST_DEBUG_OBJECT (self->element, "destroy bufferpool"); g_mutex_free (self->lock); self->lock = NULL; g_queue_free (self->free_buffers); self->free_buffers = NULL; g_queue_free (self->used_buffers); self->used_buffers = NULL; gst_caps_unref (self->caps); self->caps = NULL; gst_object_unref (self->element); self->element = NULL; GST_MINI_OBJECT_CLASS (bufferpool_parent_class)->finalize (GST_MINI_OBJECT (self)); }
static void gst_v4l2_buffer_pool_finalize (GstV4l2BufferPool * pool) { g_mutex_free (pool->lock); pool->lock = NULL; g_async_queue_unref (pool->avail_buffers); pool->avail_buffers = NULL; if (pool->video_fd >= 0) v4l2_close (pool->video_fd); if (pool->buffers) { g_free (pool->buffers); pool->buffers = NULL; } GST_MINI_OBJECT_CLASS (buffer_pool_parent_class)->finalize (GST_MINI_OBJECT (pool)); }
static void gst_wayland_buffer_destroy (GstWaylandSink * sink, GstWlBuffer * buffer) { if (buffer->wlsink) { buffer->wlsink = NULL; gst_object_unref (sink); } if (buffer->wbuffer) { wl_buffer_destroy (buffer->wbuffer); buffer->wbuffer = NULL; } if (buffer->pool) { wl_shm_pool_destroy (buffer->pool); buffer->pool = NULL; } GST_MINI_OBJECT_CLASS (gst_wlbuffer_parent_class)->finalize (GST_MINI_OBJECT (buffer)); }
static gboolean gst_ffmpegscale_handle_src_event(GstPad* pad, GstEvent* event) { GstFFMpegScale* scale; GstStructure* structure; gdouble pointer; gboolean res; scale = GST_FFMPEGSCALE(gst_pad_get_parent(pad)); switch (GST_EVENT_TYPE(event)) { case GST_EVENT_NAVIGATION: event = GST_EVENT(gst_mini_object_make_writable(GST_MINI_OBJECT(event))); structure = (GstStructure*) gst_event_get_structure(event); if (gst_structure_get_double(structure, "pointer_x", &pointer)) { gst_structure_set(structure, "pointer_x", G_TYPE_DOUBLE, pointer * scale->in_width / scale->out_width, NULL); } if (gst_structure_get_double(structure, "pointer_y", &pointer)) { gst_structure_set(structure, "pointer_y", G_TYPE_DOUBLE, pointer * scale->in_height / scale->out_height, NULL); } break; default: break; } res = gst_pad_event_default(pad, event); gst_object_unref(scale); return res; }
static void gst_buffer_manager_finalize (GstBufferClassBufferPool * pool) { g_mutex_free (pool->lock); pool->lock = NULL; if (pool->avail_buffers) { g_async_queue_unref (pool->avail_buffers); pool->avail_buffers = NULL; } if (pool->buffers) { g_free (pool->buffers); pool->buffers = NULL; } gst_caps_unref (pool->caps); pool->caps = NULL; GST_MINI_OBJECT_CLASS (buffer_pool_parent_class)->finalize (GST_MINI_OBJECT (pool)); }
static void gst_vdp_video_buffer_finalize (GstVdpVideoBuffer * buffer) { GstVdpDevice *device; VdpStatus status; if (gst_vdp_buffer_revive (GST_VDP_BUFFER_CAST (buffer))) return; device = buffer->device; status = device->vdp_video_surface_destroy (buffer->surface); if (status != VDP_STATUS_OK) GST_ERROR ("Couldn't destroy the buffers VdpVideoSurface, error returned was: %s", device->vdp_get_error_string (status)); g_object_unref (buffer->device); GST_MINI_OBJECT_CLASS (gst_vdp_video_buffer_parent_class)->finalize (GST_MINI_OBJECT (buffer)); }
static gboolean gst_video_scale_src_event (GstBaseTransform * trans, GstEvent * event) { GstVideoScale *videoscale = GST_VIDEO_SCALE_CAST (trans); GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans); gboolean ret; gdouble a; GstStructure *structure; GST_DEBUG_OBJECT (videoscale, "handling %s event", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NAVIGATION: if (filter->in_info.width != filter->out_info.width || filter->in_info.height != filter->out_info.height) { event = GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event))); structure = (GstStructure *) gst_event_get_structure (event); if (gst_structure_get_double (structure, "pointer_x", &a)) { gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, a * filter->in_info.width / filter->out_info.width, NULL); } if (gst_structure_get_double (structure, "pointer_y", &a)) { gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, a * filter->in_info.height / filter->out_info.height, NULL); } } break; default: break; } ret = GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event); return ret; }
void test_ref_threaded() { GstBuffer *buffer; GstMiniObject *mobj; gint expected; xmlfile = "gstminiobject_test_ref_threaded"; std_log(LOG_FILENAME_LINE, "Test Started test_ref_threaded"); buffer = gst_buffer_new_and_alloc (4); mobj = GST_MINI_OBJECT (buffer); MAIN_START_THREADS (num_threads, thread_ref, mobj); MAIN_STOP_THREADS (); expected = num_threads * refs_per_thread + 1; ASSERT_MINI_OBJECT_REFCOUNT (mobj, "miniobject", expected); std_log(LOG_FILENAME_LINE, "Test Successful"); create_xml(0); }
static gboolean gst_v4l2_is_buffer_valid (GstBuffer * buffer, GstV4l2MemoryGroup ** out_group) { GstMemory *mem = gst_buffer_peek_memory (buffer, 0); gboolean valid = FALSE; if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY)) goto done; if (gst_is_dmabuf_memory (mem)) mem = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem), GST_V4L2_MEMORY_QUARK); if (mem && gst_is_v4l2_memory (mem)) { GstV4l2Memory *vmem = (GstV4l2Memory *) mem; GstV4l2MemoryGroup *group = vmem->group; gint i; if (group->n_mem != gst_buffer_n_memory (buffer)) goto done; for (i = 0; i < group->n_mem; i++) { if (group->mem[i] != gst_buffer_peek_memory (buffer, i)) goto done; if (!gst_memory_is_writable (group->mem[i])) goto done; } valid = TRUE; if (out_group) *out_group = group; } done: return valid; }
static void gst_mmap_buffer_finalize (GstMmapBuffer * mmap_buffer) { guint size; gpointer data; guint64 offset; GstFileSrc *src; GstBuffer *buffer = GST_BUFFER (mmap_buffer); /* get info */ size = GST_BUFFER_SIZE (buffer); offset = GST_BUFFER_OFFSET (buffer); data = GST_BUFFER_DATA (buffer); src = mmap_buffer->filesrc; GST_LOG ("freeing mmap()d buffer at %" G_GUINT64_FORMAT "+%u", offset, size); #ifdef MADV_DONTNEED /* madvise to tell the kernel what to do with it */ if (madvise (data, size, MADV_DONTNEED) < 0) { GST_WARNING_OBJECT (src, "warning: madvise failed: %s", g_strerror (errno)); } #endif /* now unmap the memory */ if (munmap (data, size) < 0) { GST_WARNING_OBJECT (src, "warning: munmap failed: %s", g_strerror (errno)); } /* cast to unsigned long, since there's no gportable way to print * guint64 as hex */ GST_LOG ("unmapped region %08lx+%08lx at %p", (gulong) offset, (gulong) size, data); GST_MINI_OBJECT_CLASS (gst_mmap_buffer_parent_class)->finalize (GST_MINI_OBJECT (mmap_buffer)); }
static gboolean gst_pixbufscale_handle_src_event (GstBaseTransform * trans, GstEvent * event) { GstPixbufScale *pixbufscale; gboolean ret; double a; GstStructure *structure; pixbufscale = GST_PIXBUFSCALE (trans); GST_DEBUG_OBJECT (pixbufscale, "handling %s event", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NAVIGATION: event = GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event))); structure = (GstStructure *) gst_event_get_structure (event); if (gst_structure_get_double (structure, "pointer_x", &a)) { gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, a * pixbufscale->from_width / pixbufscale->to_width, NULL); } if (gst_structure_get_double (structure, "pointer_y", &a)) { gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, a * pixbufscale->from_height / pixbufscale->to_height, NULL); } break; default: break; } ret = GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event); return ret; }
GstV4l2MemoryGroup * gst_v4l2_allocator_alloc_dmabuf (GstV4l2Allocator * allocator, GstAllocator * dmabuf_allocator) { GstV4l2MemoryGroup *group; gint i; g_return_val_if_fail (allocator->memory == V4L2_MEMORY_MMAP, NULL); group = gst_v4l2_allocator_alloc (allocator); if (group == NULL) return NULL; for (i = 0; i < group->n_mem; i++) { GstV4l2Memory *mem; GstMemory *dma_mem; gint dmafd; if (group->mem[i] == NULL) { struct v4l2_exportbuffer expbuf = { 0 }; expbuf.type = allocator->type; expbuf.index = group->buffer.index; expbuf.plane = i; expbuf.flags = O_CLOEXEC | O_RDWR; if (v4l2_ioctl (allocator->video_fd, VIDIOC_EXPBUF, &expbuf) < 0) goto expbuf_failed; GST_LOG_OBJECT (allocator, "exported DMABUF as fd %i plane %d", expbuf.fd, i); group->mem[i] = (GstMemory *) _v4l2mem_new (0, GST_ALLOCATOR (allocator), NULL, group->planes[i].length, 0, 0, group->planes[i].length, i, NULL, expbuf.fd, group); } else { /* Take back the allocator reference */ gst_object_ref (allocator); } g_assert (gst_is_v4l2_memory (group->mem[i])); mem = (GstV4l2Memory *) group->mem[i]; if ((dmafd = dup (mem->dmafd)) < 0) goto dup_failed; dma_mem = gst_dmabuf_allocator_alloc (dmabuf_allocator, dmafd, mem->mem.maxsize); gst_mini_object_set_qdata (GST_MINI_OBJECT (dma_mem), GST_V4L2_MEMORY_QUARK, mem, (GDestroyNotify) gst_memory_unref); group->mem[i] = dma_mem; group->mems_allocated++; } gst_v4l2_allocator_reset_size (allocator, group); return group; expbuf_failed: { GST_ERROR_OBJECT (allocator, "Failed to export DMABUF: %s", g_strerror (errno)); goto cleanup; } dup_failed: { GST_ERROR_OBJECT (allocator, "Failed to dup DMABUF descriptor: %s", g_strerror (errno)); goto cleanup; } cleanup: { _cleanup_failed_alloc (allocator, group); return NULL; } }
/** * gst_v4l2_buffer_pool_new: * @v4l2elem: the v4l2 element (src or sink) that owns this pool * @fd: the video device file descriptor * @num_buffers: the requested number of buffers in the pool * @caps: the caps to set on the buffer * @requeuebuf: if %TRUE, and if the pool is still in the running state, a * buffer with no remaining references is immediately passed back to v4l2 * (VIDIOC_QBUF), otherwise it is returned to the pool of available buffers * (which can be accessed via gst_v4l2_buffer_pool_get(). * * Construct a new buffer pool. * * Returns: the new pool, use gst_v4l2_buffer_pool_destroy() to free resources */ GstV4l2BufferPool * gst_v4l2_buffer_pool_new (GstElement * v4l2elem, gint fd, gint num_buffers, GstCaps * caps, gboolean requeuebuf, enum v4l2_buf_type type) { GstV4l2BufferPool *pool; gint n; struct v4l2_requestbuffers breq; pool = (GstV4l2BufferPool *) gst_mini_object_new (GST_TYPE_V4L2_BUFFER_POOL); pool->video_fd = v4l2_dup (fd); if (pool->video_fd < 0) goto dup_failed; /* first, lets request buffers, and see how many we can get: */ GST_DEBUG_OBJECT (v4l2elem, "STREAMING, requesting %d MMAP buffers", num_buffers); memset (&breq, 0, sizeof (struct v4l2_requestbuffers)); breq.type = type; breq.count = num_buffers; breq.memory = V4L2_MEMORY_MMAP; if (v4l2_ioctl (fd, VIDIOC_REQBUFS, &breq) < 0) goto reqbufs_failed; GST_LOG_OBJECT (v4l2elem, " count: %u", breq.count); GST_LOG_OBJECT (v4l2elem, " type: %d", breq.type); GST_LOG_OBJECT (v4l2elem, " memory: %d", breq.memory); if (breq.count < GST_V4L2_MIN_BUFFERS) goto no_buffers; if (num_buffers != breq.count) { GST_WARNING_OBJECT (v4l2elem, "using %u buffers instead", breq.count); num_buffers = breq.count; } pool->v4l2elem = v4l2elem; pool->requeuebuf = requeuebuf; pool->type = type; pool->buffer_count = num_buffers; pool->buffers = g_new0 (GstV4l2Buffer *, num_buffers); pool->avail_buffers = g_async_queue_new (); /* now, map the buffers: */ for (n = 0; n < num_buffers; n++) { pool->buffers[n] = gst_v4l2_buffer_new (pool, n, caps); if (!pool->buffers[n]) goto buffer_new_failed; pool->num_live_buffers++; g_async_queue_push (pool->avail_buffers, pool->buffers[n]); } return pool; /* ERRORS */ dup_failed: { gint errnosave = errno; gst_mini_object_unref (GST_MINI_OBJECT (pool)); errno = errnosave; return NULL; } reqbufs_failed: { GstV4l2Object *v4l2object = get_v4l2_object (v4l2elem); GST_ELEMENT_ERROR (v4l2elem, RESOURCE, READ, (_("Could not get buffers from device '%s'."), v4l2object->videodev), ("error requesting %d buffers: %s", num_buffers, g_strerror (errno))); return NULL; } no_buffers: { GstV4l2Object *v4l2object = get_v4l2_object (v4l2elem); GST_ELEMENT_ERROR (v4l2elem, RESOURCE, READ, (_("Could not get enough buffers from device '%s'."), v4l2object->videodev), ("we received %d from device '%s', we want at least %d", breq.count, v4l2object->videodev, GST_V4L2_MIN_BUFFERS)); return NULL; } buffer_new_failed: { gint errnosave = errno; gst_v4l2_buffer_pool_destroy (pool); errno = errnosave; return NULL; } }
static gboolean splitmux_part_pad_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstSplitMuxPartPad *part_pad = SPLITMUX_PART_PAD_CAST (pad); GstSplitMuxPartReader *reader = part_pad->reader; gboolean ret = TRUE; SplitMuxSrcPad *target; GstDataQueueItem *item; SPLITMUX_PART_LOCK (reader); target = gst_object_ref (part_pad->target); GST_LOG_OBJECT (reader, "Pad %" GST_PTR_FORMAT " event %" GST_PTR_FORMAT, pad, event); if (part_pad->flushing && GST_EVENT_TYPE (event) != GST_EVENT_FLUSH_STOP) goto drop_event; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEGMENT:{ GstSegment *seg = &part_pad->segment; GST_LOG_OBJECT (pad, "Received segment %" GST_PTR_FORMAT, event); gst_event_copy_segment (event, seg); gst_event_copy_segment (event, &part_pad->orig_segment); if (seg->format != GST_FORMAT_TIME) goto wrong_segment; /* Adjust segment */ /* Adjust start/stop so the overall file is 0 + start_offset based */ if (seg->stop != -1) { seg->stop -= seg->start; seg->stop += seg->time + reader->start_offset; } seg->start = seg->time + reader->start_offset; seg->time += reader->start_offset; seg->position += reader->start_offset; GST_LOG_OBJECT (pad, "Adjusted segment now %" GST_PTR_FORMAT, event); /* Replace event */ gst_event_unref (event); event = gst_event_new_segment (seg); if (reader->prep_state != PART_STATE_PREPARING_COLLECT_STREAMS && reader->prep_state != PART_STATE_PREPARING_MEASURE_STREAMS) break; /* Only do further stuff with segments during initial measuring */ /* Take the first segment from the first part */ if (target->segment.format == GST_FORMAT_UNDEFINED) { gst_segment_copy_into (seg, &target->segment); GST_DEBUG_OBJECT (reader, "Target pad segment now %" GST_SEGMENT_FORMAT, &target->segment); } if (seg->stop != -1 && target->segment.stop != -1) { GstClockTime stop = seg->base + seg->stop; if (stop > target->segment.stop) { target->segment.stop = stop; GST_DEBUG_OBJECT (reader, "Adjusting segment stop by %" GST_TIME_FORMAT " output now %" GST_SEGMENT_FORMAT, GST_TIME_ARGS (reader->start_offset), &target->segment); } } GST_LOG_OBJECT (pad, "Forwarding segment %" GST_PTR_FORMAT, event); break; } case GST_EVENT_EOS:{ GST_DEBUG_OBJECT (part_pad, "State %u EOS event. MaxTS seen %" GST_TIME_FORMAT, reader->prep_state, GST_TIME_ARGS (part_pad->max_ts)); if (reader->prep_state == PART_STATE_PREPARING_COLLECT_STREAMS || reader->prep_state == PART_STATE_PREPARING_MEASURE_STREAMS) { /* Mark this pad as EOS */ part_pad->is_eos = TRUE; if (splitmux_part_is_eos_locked (reader)) { /* Finished measuring things, set state and tell the state change func * so it can seek back to the start */ GST_LOG_OBJECT (reader, "EOS while measuring streams. Resetting for ready"); reader->prep_state = PART_STATE_PREPARING_RESET_FOR_READY; SPLITMUX_PART_BROADCAST (reader); } goto drop_event; } break; } case GST_EVENT_FLUSH_START: reader->flushing = TRUE; part_pad->flushing = TRUE; GST_LOG_OBJECT (reader, "Pad %" GST_PTR_FORMAT " flushing dataqueue", part_pad); gst_data_queue_set_flushing (part_pad->queue, TRUE); SPLITMUX_PART_BROADCAST (reader); break; case GST_EVENT_FLUSH_STOP:{ gst_data_queue_set_flushing (part_pad->queue, FALSE); gst_data_queue_flush (part_pad->queue); part_pad->seen_buffer = FALSE; part_pad->flushing = FALSE; part_pad->is_eos = FALSE; reader->flushing = splitmux_is_flushing (reader); GST_LOG_OBJECT (reader, "%s pad %" GST_PTR_FORMAT " flush_stop. Overall flushing=%d", reader->path, pad, reader->flushing); SPLITMUX_PART_BROADCAST (reader); break; } default: break; } /* Don't send events downstream while preparing */ if (reader->prep_state != PART_STATE_READY) goto drop_event; /* Don't pass flush events - those are done by the parent */ if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_START || GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) goto drop_event; if (!block_until_can_push (reader)) { SPLITMUX_PART_UNLOCK (reader); gst_object_unref (target); gst_event_unref (event); return FALSE; } switch (GST_EVENT_TYPE (event)) { case GST_EVENT_GAP:{ /* FIXME: Drop initial gap (if any) in each segment, not all GAPs */ goto drop_event; } default: break; } /* We are active, and one queue is empty, place this buffer in * the dataqueue */ gst_object_ref (part_pad->queue); SPLITMUX_PART_UNLOCK (reader); GST_LOG_OBJECT (reader, "Enqueueing event %" GST_PTR_FORMAT, event); item = g_slice_new (GstDataQueueItem); item->destroy = (GDestroyNotify) splitmux_part_free_queue_item; item->object = GST_MINI_OBJECT (event); item->size = 0; item->duration = 0; if (item->duration == GST_CLOCK_TIME_NONE) item->duration = 0; item->visible = FALSE; if (!gst_data_queue_push (part_pad->queue, item)) { splitmux_part_free_queue_item (item); ret = FALSE; } gst_object_unref (part_pad->queue); gst_object_unref (target); return ret; wrong_segment: gst_event_unref (event); gst_object_unref (target); SPLITMUX_PART_UNLOCK (reader); GST_ELEMENT_ERROR (reader, STREAM, FAILED, (NULL), ("Received non-time segment - reader %s pad %" GST_PTR_FORMAT, reader->path, pad)); return FALSE; drop_event: GST_LOG_OBJECT (pad, "Dropping event %" GST_PTR_FORMAT " from %" GST_PTR_FORMAT " on %" GST_PTR_FORMAT, event, pad, target); gst_event_unref (event); gst_object_unref (target); SPLITMUX_PART_UNLOCK (reader); return TRUE; }
static GstV4l2Buffer * gst_v4l2_buffer_new (GstV4l2BufferPool * pool, guint index, GstCaps * caps) { GstV4l2Buffer *ret; guint8 *data; ret = (GstV4l2Buffer *) gst_mini_object_new (GST_TYPE_V4L2_BUFFER); GST_LOG_OBJECT (pool->v4l2elem, "creating buffer %u, %p in pool %p", index, ret, pool); ret->pool = (GstV4l2BufferPool *) gst_mini_object_ref (GST_MINI_OBJECT (pool)); ret->vbuffer.index = index; ret->vbuffer.type = pool->type; ret->vbuffer.memory = V4L2_MEMORY_MMAP; if (v4l2_ioctl (pool->video_fd, VIDIOC_QUERYBUF, &ret->vbuffer) < 0) goto querybuf_failed; GST_LOG_OBJECT (pool->v4l2elem, " index: %u", ret->vbuffer.index); GST_LOG_OBJECT (pool->v4l2elem, " type: %d", ret->vbuffer.type); GST_LOG_OBJECT (pool->v4l2elem, " bytesused: %u", ret->vbuffer.bytesused); GST_LOG_OBJECT (pool->v4l2elem, " flags: %08x", ret->vbuffer.flags); GST_LOG_OBJECT (pool->v4l2elem, " field: %d", ret->vbuffer.field); GST_LOG_OBJECT (pool->v4l2elem, " memory: %d", ret->vbuffer.memory); if (ret->vbuffer.memory == V4L2_MEMORY_MMAP) GST_LOG_OBJECT (pool->v4l2elem, " MMAP offset: %u", ret->vbuffer.m.offset); GST_LOG_OBJECT (pool->v4l2elem, " length: %u", ret->vbuffer.length); GST_LOG_OBJECT (pool->v4l2elem, " input: %u", ret->vbuffer.input); data = (guint8 *) v4l2_mmap (0, ret->vbuffer.length, PROT_READ | PROT_WRITE, MAP_SHARED, pool->video_fd, ret->vbuffer.m.offset); if (data == MAP_FAILED) goto mmap_failed; GST_BUFFER_DATA (ret) = data; GST_BUFFER_SIZE (ret) = ret->vbuffer.length; GST_BUFFER_FLAG_SET (ret, GST_BUFFER_FLAG_READONLY); gst_buffer_set_caps (GST_BUFFER (ret), caps); return ret; /* ERRORS */ querybuf_failed: { gint errnosave = errno; GST_WARNING ("Failed QUERYBUF: %s", g_strerror (errnosave)); gst_buffer_unref (GST_BUFFER (ret)); errno = errnosave; return NULL; } mmap_failed: { gint errnosave = errno; GST_WARNING ("Failed to mmap: %s", g_strerror (errnosave)); gst_buffer_unref (GST_BUFFER (ret)); errno = errnosave; return NULL; } }
static GstMemory * get_cached_kmsmem (GstMemory * mem) { return gst_mini_object_get_qdata (GST_MINI_OBJECT (mem), g_quark_from_static_string ("kmsmem")); }
static void gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer) { GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool); GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class); GstV4l2Object *obj = pool->obj; GST_DEBUG_OBJECT (pool, "release buffer %p", buffer); switch (obj->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: /* capture, put the buffer back in the queue so that we can refill it * later. */ switch (obj->mode) { case GST_V4L2_IO_RW: /* release back in the pool */ pclass->release_buffer (bpool, buffer); break; case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_MMAP: case GST_V4L2_IO_USERPTR: case GST_V4L2_IO_DMABUF_IMPORT: { if (gst_v4l2_is_buffer_valid (buffer, NULL)) { /* queue back in the device */ if (pool->other_pool) gst_v4l2_buffer_pool_prepare_buffer (pool, buffer, NULL); if (gst_v4l2_buffer_pool_qbuf (pool, buffer) != GST_FLOW_OK) pclass->release_buffer (bpool, buffer); } else { /* Simply release invalide/modified buffer, the allocator will * give it back later */ GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY); pclass->release_buffer (bpool, buffer); } break; } default: g_assert_not_reached (); break; } break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: switch (obj->mode) { case GST_V4L2_IO_RW: /* release back in the pool */ pclass->release_buffer (bpool, buffer); break; case GST_V4L2_IO_MMAP: case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_USERPTR: case GST_V4L2_IO_DMABUF_IMPORT: { GstV4l2MemoryGroup *group; guint index; if (!gst_v4l2_is_buffer_valid (buffer, &group)) { /* Simply release invalide/modified buffer, the allocator will * give it back later */ GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY); pclass->release_buffer (bpool, buffer); break; } index = group->buffer.index; if (pool->buffers[index] == NULL) { GST_LOG_OBJECT (pool, "buffer %u not queued, putting on free list", index); /* Remove qdata, this will unmap any map data in userptr */ gst_mini_object_set_qdata (GST_MINI_OBJECT (buffer), GST_V4L2_IMPORT_QUARK, NULL, NULL); /* reset to default size */ gst_v4l2_allocator_reset_group (pool->vallocator, group); /* playback, put the buffer back in the queue to refill later. */ pclass->release_buffer (bpool, buffer); } else { /* We keep a ref on queued buffer, so this should never happen */ g_assert_not_reached (); } break; } default: g_assert_not_reached (); break; } break; default: g_assert_not_reached (); break; } }
static void test_one_after_other_full (gboolean async) { GstElement *pipeline; GstElement *comp, *sink, *source1, *source2; CollectStructure *collect; GstBus *bus; GstMessage *message; gboolean carry_on = TRUE; guint64 start, stop; gint64 duration; GstPad *sinkpad; pipeline = gst_pipeline_new ("test_pipeline"); comp = gst_element_factory_make_or_warn ("gnlcomposition", "test_composition"); fail_if (comp == NULL); /* Source 1 Start : 0s Duration : 1s Media start : 5s Media Duartion : 1s Priority : 1 */ source1 = videotest_gnl_src_full ("source1", 0, 1 * GST_SECOND, 5 * GST_SECOND, 1 * GST_SECOND, 3, 1); fail_if (source1 == NULL); check_start_stop_duration (source1, 0, 1 * GST_SECOND, 1 * GST_SECOND); /* Source 2 Start : 1s Duration : 1s Media start : 2s Media Duration : 1s Priority : 1 */ source2 = videotest_gnl_src_full ("source2", 1 * GST_SECOND, 1 * GST_SECOND, 2 * GST_SECOND, 1 * GST_SECOND, 2, 1); fail_if (source2 == NULL); check_start_stop_duration (source2, 1 * GST_SECOND, 2 * GST_SECOND, 1 * GST_SECOND); /* Add one source */ DISABLE_ASYNC_UPDATE; gst_bin_add (GST_BIN (comp), source1); ENABLE_ASYNC_UPDATE; check_start_stop_duration (comp, 0, 1 * GST_SECOND, 1 * GST_SECOND); ASSERT_OBJECT_REFCOUNT (source1, "source1", 1); /* Second source */ DISABLE_ASYNC_UPDATE; gst_bin_add (GST_BIN (comp), source2); ENABLE_ASYNC_UPDATE; check_start_stop_duration (comp, 0, 2 * GST_SECOND, 2 * GST_SECOND); ASSERT_OBJECT_REFCOUNT (source2, "source2", 1); /* Remove first source */ gst_object_ref (source1); DISABLE_ASYNC_UPDATE; gst_bin_remove (GST_BIN (comp), source1); ENABLE_ASYNC_UPDATE; check_start_stop_duration (comp, 1 * GST_SECOND, 2 * GST_SECOND, 1 * GST_SECOND); ASSERT_OBJECT_REFCOUNT (source1, "source1", 1); /* Re-add first source */ DISABLE_ASYNC_UPDATE; gst_bin_add (GST_BIN (comp), source1); ENABLE_ASYNC_UPDATE; check_start_stop_duration (comp, 0, 2 * GST_SECOND, 2 * GST_SECOND); gst_object_unref (source1); ASSERT_OBJECT_REFCOUNT (source1, "source1", 1); sink = gst_element_factory_make_or_warn ("fakesink", "sink"); fail_if (sink == NULL); gst_bin_add_many (GST_BIN (pipeline), comp, sink, NULL); /* Shared data */ collect = g_new0 (CollectStructure, 1); collect->comp = comp; collect->sink = sink; /* Expected segments */ collect->expected_segments = g_list_append (collect->expected_segments, segment_new (1.0, GST_FORMAT_TIME, 5 * GST_SECOND, 6 * GST_SECOND, 0)); collect->expected_segments = g_list_append (collect->expected_segments, segment_new (1.0, GST_FORMAT_TIME, 2 * GST_SECOND, 3 * GST_SECOND, 1 * GST_SECOND)); g_signal_connect (G_OBJECT (comp), "pad-added", G_CALLBACK (composition_pad_added_cb), collect); sinkpad = gst_element_get_pad (sink, "sink"); gst_pad_add_event_probe (sinkpad, G_CALLBACK (sinkpad_event_probe), collect); gst_pad_add_buffer_probe (sinkpad, G_CALLBACK (sinkpad_buffer_probe), collect); bus = gst_element_get_bus (GST_ELEMENT (pipeline)); GST_DEBUG ("Setting pipeline to PLAYING"); ASSERT_OBJECT_REFCOUNT (source1, "source1", 1); fail_if (gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE); GST_DEBUG ("Let's poll the bus"); while (carry_on) { message = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_SECOND / 2); if (message) { switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_EOS: /* we should check if we really finished here */ GST_WARNING ("Got an EOS"); carry_on = FALSE; break; case GST_MESSAGE_SEGMENT_START: case GST_MESSAGE_SEGMENT_DONE: /* We shouldn't see any segement messages, since we didn't do a segment seek */ GST_WARNING ("Saw a Segment start/stop"); fail_if (TRUE); break; case GST_MESSAGE_ERROR: GST_WARNING ("Saw an ERROR"); fail_if (TRUE); default: break; } gst_mini_object_unref (GST_MINI_OBJECT (message)); } } GST_DEBUG ("Setting pipeline to NULL"); fail_if (gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_READY) == GST_STATE_CHANGE_FAILURE); fail_if (collect->expected_segments != NULL); GST_DEBUG ("Resetted pipeline to READY"); /* Expected segments */ collect->expected_segments = g_list_append (collect->expected_segments, segment_new (1.0, GST_FORMAT_TIME, 5 * GST_SECOND, 6 * GST_SECOND, 0)); collect->expected_segments = g_list_append (collect->expected_segments, segment_new (1.0, GST_FORMAT_TIME, 2 * GST_SECOND, 3 * GST_SECOND, 1 * GST_SECOND)); collect->gotsegment = FALSE; GST_DEBUG ("Setting pipeline to PLAYING again"); fail_if (gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE); carry_on = TRUE; GST_DEBUG ("Let's poll the bus AGAIN"); while (carry_on) { message = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_SECOND / 2); if (message) { switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_EOS: /* we should check if we really finished here */ carry_on = FALSE; break; case GST_MESSAGE_SEGMENT_START: case GST_MESSAGE_SEGMENT_DONE: /* We shouldn't see any segement messages, since we didn't do a segment seek */ GST_WARNING ("Saw a Segment start/stop"); fail_if (TRUE); break; case GST_MESSAGE_ERROR: GST_ERROR ("Saw an ERROR"); fail_if (TRUE); default: break; } gst_mini_object_unref (GST_MINI_OBJECT (message)); } else { GST_DEBUG ("bus_poll responded, but there wasn't any message..."); } } fail_if (collect->expected_segments != NULL); gst_object_unref (GST_OBJECT (sinkpad)); fail_if (gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL) == GST_STATE_CHANGE_FAILURE); ASSERT_OBJECT_REFCOUNT_BETWEEN (pipeline, "main pipeline", 1, 2); gst_object_unref (pipeline); ASSERT_OBJECT_REFCOUNT_BETWEEN (bus, "main bus", 1, 2); gst_object_unref (bus); g_free (collect); }
/** * gst_v4l2_buffer_pool_process: * @bpool: a #GstBufferPool * @buf: a #GstBuffer, maybe be replaced * * Process @buf in @bpool. For capture devices, this functions fills @buf with * data from the device. For output devices, this functions send the contents of * @buf to the device for playback. * * Returns: %GST_FLOW_OK on success. */ GstFlowReturn gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer ** buf) { GstFlowReturn ret = GST_FLOW_OK; GstBufferPool *bpool = GST_BUFFER_POOL_CAST (pool); GstV4l2Object *obj = pool->obj; GST_DEBUG_OBJECT (pool, "process buffer %p", buf); g_return_val_if_fail (gst_buffer_pool_is_active (bpool), GST_FLOW_ERROR); if (GST_BUFFER_POOL_IS_FLUSHING (pool)) return GST_FLOW_FLUSHING; switch (obj->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: /* capture */ switch (obj->mode) { case GST_V4L2_IO_RW: /* capture into the buffer */ ret = gst_v4l2_do_read (pool, *buf); break; case GST_V4L2_IO_MMAP: case GST_V4L2_IO_DMABUF: { GstBuffer *tmp; if ((*buf)->pool == bpool) { if (gst_buffer_get_size (*buf) == 0) goto eos; /* start copying buffers when we are running low on buffers */ if (g_atomic_int_get (&pool->num_queued) < pool->copy_threshold) { GstBuffer *copy; if (GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP)) { if (gst_buffer_pool_acquire_buffer (bpool, ©, NULL) == GST_FLOW_OK) { gst_v4l2_buffer_pool_release_buffer (bpool, copy); goto done; } } /* copy the buffer */ copy = gst_buffer_copy_region (*buf, GST_BUFFER_COPY_ALL | GST_BUFFER_COPY_DEEP, 0, -1); GST_LOG_OBJECT (pool, "copy buffer %p->%p", *buf, copy); /* and requeue so that we can continue capturing */ gst_buffer_unref (*buf); *buf = copy; } /* nothing, data was inside the buffer when we did _acquire() */ goto done; } /* buffer not from our pool, grab a frame and copy it into the target */ if ((ret = gst_v4l2_buffer_pool_dqbuf (pool, &tmp)) != GST_FLOW_OK) goto done; /* An empty buffer on capture indicates the end of stream */ if (gst_buffer_get_size (tmp) == 0) { gst_v4l2_buffer_pool_release_buffer (bpool, tmp); goto eos; } ret = gst_v4l2_buffer_pool_copy_buffer (pool, *buf, tmp); /* an queue the buffer again after the copy */ gst_v4l2_buffer_pool_release_buffer (bpool, tmp); if (ret != GST_FLOW_OK) goto copy_failed; break; } case GST_V4L2_IO_USERPTR: { struct UserPtrData *data; /* Replace our buffer with downstream allocated buffer */ data = gst_mini_object_steal_qdata (GST_MINI_OBJECT (*buf), GST_V4L2_IMPORT_QUARK); gst_buffer_replace (buf, data->buffer); _unmap_userptr_frame (data); break; } case GST_V4L2_IO_DMABUF_IMPORT: { GstBuffer *tmp; /* Replace our buffer with downstream allocated buffer */ tmp = gst_mini_object_steal_qdata (GST_MINI_OBJECT (*buf), GST_V4L2_IMPORT_QUARK); gst_buffer_replace (buf, tmp); gst_buffer_unref (tmp); break; } default: g_assert_not_reached (); break; } break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: /* playback */ switch (obj->mode) { case GST_V4L2_IO_RW: /* FIXME, do write() */ GST_WARNING_OBJECT (pool, "implement write()"); break; case GST_V4L2_IO_USERPTR: case GST_V4L2_IO_DMABUF_IMPORT: case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_MMAP: { GstBuffer *to_queue = NULL; GstV4l2MemoryGroup *group; gint index; if ((*buf)->pool != bpool) goto copying; if (!gst_v4l2_is_buffer_valid (*buf, &group)) goto copying; index = group->buffer.index; GST_LOG_OBJECT (pool, "processing buffer %i from our pool", index); index = group->buffer.index; if (pool->buffers[index] != NULL) { GST_LOG_OBJECT (pool, "buffer %i already queued, copying", index); goto copying; } /* we can queue directly */ to_queue = gst_buffer_ref (*buf); copying: if (to_queue == NULL) { GstBufferPoolAcquireParams params = { 0 }; GST_LOG_OBJECT (pool, "alloc buffer from our pool"); /* this can return EOS if all buffers are outstanding which would * be strange because we would expect the upstream element to have * allocated them and returned to us.. */ params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT; ret = gst_buffer_pool_acquire_buffer (bpool, &to_queue, ¶ms); if (ret != GST_FLOW_OK) goto acquire_failed; ret = gst_v4l2_buffer_pool_prepare_buffer (pool, to_queue, *buf); if (ret != GST_FLOW_OK) { gst_buffer_unref (to_queue); goto prepare_failed; } } if ((ret = gst_v4l2_buffer_pool_qbuf (pool, to_queue)) != GST_FLOW_OK) goto queue_failed; /* if we are not streaming yet (this is the first buffer, start * streaming now */ if (!gst_v4l2_buffer_pool_streamon (pool)) { /* don't check return value because qbuf would have failed */ gst_v4l2_is_buffer_valid (to_queue, &group); /* qbuf has taken the ref of the to_queue buffer but we are no in * streaming state, so the flush logic won't be performed. * To avoid leaks, flush the allocator and restore the queued * buffer as non-queued */ gst_v4l2_allocator_flush (pool->vallocator); pool->buffers[group->buffer.index] = NULL; gst_mini_object_set_qdata (GST_MINI_OBJECT (to_queue), GST_V4L2_IMPORT_QUARK, NULL, NULL); gst_buffer_unref (to_queue); g_atomic_int_add (&pool->num_queued, -1); goto start_failed; } if (g_atomic_int_get (&pool->num_queued) >= pool->min_latency) { GstBuffer *out; /* all buffers are queued, try to dequeue one and release it back * into the pool so that _acquire can get to it again. */ ret = gst_v4l2_buffer_pool_dqbuf (pool, &out); if (ret == GST_FLOW_OK) /* release the rendered buffer back into the pool. This wakes up any * thread waiting for a buffer in _acquire(). */ gst_buffer_unref (out); } break; } default: g_assert_not_reached (); break; } break; default: g_assert_not_reached (); break; } done: return ret; /* ERRORS */ copy_failed: { GST_ERROR_OBJECT (pool, "failed to copy buffer"); return ret; } eos: { GST_DEBUG_OBJECT (pool, "end of stream reached"); return GST_FLOW_EOS; } acquire_failed: { if (ret == GST_FLOW_FLUSHING) GST_DEBUG_OBJECT (pool, "flushing"); else GST_WARNING_OBJECT (pool, "failed to acquire a buffer: %s", gst_flow_get_name (ret)); return ret; } prepare_failed: { GST_ERROR_OBJECT (pool, "failed to prepare data"); return ret; } queue_failed: { GST_ERROR_OBJECT (pool, "failed to queue buffer"); return ret; } start_failed: { GST_ERROR_OBJECT (pool, "failed to start streaming"); return GST_FLOW_ERROR; } }
static GstVaapiSurface * _get_cached_surface (GstBuffer * buf) { return gst_mini_object_get_qdata (GST_MINI_OBJECT (buf), g_quark_from_static_string ("GstVaapiDMABufSurface")); }
static GstFlowReturn gst_v4l2_buffer_pool_import_userptr (GstV4l2BufferPool * pool, GstBuffer * dest, GstBuffer * src) { GstFlowReturn ret = GST_FLOW_OK; GstV4l2MemoryGroup *group = NULL; GstMapFlags flags; const GstVideoFormatInfo *finfo = pool->caps_info.finfo; struct UserPtrData *data = NULL; GST_LOG_OBJECT (pool, "importing userptr"); /* get the group */ if (!gst_v4l2_is_buffer_valid (dest, &group)) goto not_our_buffer; if (V4L2_TYPE_IS_OUTPUT (pool->obj->type)) flags = GST_MAP_READ; else flags = GST_MAP_WRITE; data = g_slice_new0 (struct UserPtrData); if (finfo && (finfo->format != GST_VIDEO_FORMAT_UNKNOWN && finfo->format != GST_VIDEO_FORMAT_ENCODED)) { data->is_frame = TRUE; if (!gst_video_frame_map (&data->frame, &pool->caps_info, src, flags)) goto invalid_buffer; if (!gst_v4l2_allocator_import_userptr (pool->vallocator, group, data->frame.info.size, finfo->n_planes, data->frame.data, data->frame.info.offset)) goto import_failed; } else { gsize offset[1] = { 0 }; gpointer ptr[1]; data->is_frame = FALSE; if (!gst_buffer_map (src, &data->map, flags)) goto invalid_buffer; ptr[0] = data->map.data; if (!gst_v4l2_allocator_import_userptr (pool->vallocator, group, data->map.size, 1, ptr, offset)) goto import_failed; } data->buffer = gst_buffer_ref (src); gst_mini_object_set_qdata (GST_MINI_OBJECT (dest), GST_V4L2_IMPORT_QUARK, data, (GDestroyNotify) _unmap_userptr_frame); return ret; not_our_buffer: { GST_ERROR_OBJECT (pool, "destination buffer invalid or not from our pool"); return GST_FLOW_ERROR; } invalid_buffer: { GST_ERROR_OBJECT (pool, "could not map buffer"); g_slice_free (struct UserPtrData, data); return GST_FLOW_ERROR; } import_failed: { GST_ERROR_OBJECT (pool, "failed to import data"); _unmap_userptr_frame (data); return GST_FLOW_ERROR; } }
static void gst_v4l2_buffer_pool_flush_stop (GstBufferPool * bpool) { GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool); GstV4l2Object *obj = pool->obj; gint i; GST_DEBUG_OBJECT (pool, "stop flushing"); /* If we haven't started streaming yet, simply call streamon */ if (!pool->streaming) goto streamon; if (pool->other_pool) gst_buffer_pool_set_flushing (pool->other_pool, FALSE); if (!gst_v4l2_buffer_pool_streamoff (pool)) goto stop_failed; gst_v4l2_allocator_flush (pool->vallocator); /* Reset our state */ switch (obj->mode) { case GST_V4L2_IO_RW: break; case GST_V4L2_IO_MMAP: case GST_V4L2_IO_USERPTR: case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_DMABUF_IMPORT: { gsize num_allocated; num_allocated = gst_v4l2_allocator_num_allocated (pool->vallocator); for (i = 0; i < num_allocated; i++) { /* Re-enqueue buffers */ if (pool->buffers[i]) { GstBufferPool *bpool = (GstBufferPool *) pool; GstBuffer *buffer = pool->buffers[i]; pool->buffers[i] = NULL; /* Remove qdata, this will unmap any map data in * userptr/dmabuf-import */ gst_mini_object_set_qdata (GST_MINI_OBJECT (buffer), GST_V4L2_IMPORT_QUARK, NULL, NULL); if (V4L2_TYPE_IS_OUTPUT (obj->type)) gst_buffer_unref (buffer); else gst_v4l2_buffer_pool_release_buffer (bpool, buffer); g_atomic_int_add (&pool->num_queued, -1); } } break; } default: g_assert_not_reached (); break; } streamon: /* Start streaming on capture device only */ if (!V4L2_TYPE_IS_OUTPUT (obj->type)) gst_v4l2_buffer_pool_streamon (pool); gst_poll_set_flushing (pool->poll, FALSE); return; /* ERRORS */ stop_failed: { GST_ERROR_OBJECT (pool, "device refused to flush"); } }
static GstFlowReturn gst_fake_src_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** ret) { GstFakeSrc *src; GstBuffer *buf; GstClockTime time; src = GST_FAKE_SRC (basesrc); buf = gst_fake_src_create_buffer (src); GST_BUFFER_OFFSET (buf) = src->buffer_count++; if (src->datarate > 0) { time = (src->bytes_sent * GST_SECOND) / src->datarate; GST_BUFFER_DURATION (buf) = GST_BUFFER_SIZE (buf) * GST_SECOND / src->datarate; } else if (gst_base_src_is_live (basesrc)) { GstClock *clock; clock = gst_element_get_clock (GST_ELEMENT (src)); if (clock) { time = gst_clock_get_time (clock); time -= gst_element_get_base_time (GST_ELEMENT (src)); gst_object_unref (clock); } else { /* not an error not to have a clock */ time = GST_CLOCK_TIME_NONE; } } else { time = GST_CLOCK_TIME_NONE; } GST_BUFFER_TIMESTAMP (buf) = time; if (!src->silent) { gchar ts_str[64], dur_str[64]; GST_OBJECT_LOCK (src); g_free (src->last_message); if (GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) { g_snprintf (ts_str, sizeof (ts_str), "%" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); } else { g_strlcpy (ts_str, "none", sizeof (ts_str)); } if (GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE) { g_snprintf (dur_str, sizeof (dur_str), "%" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); } else { g_strlcpy (dur_str, "none", sizeof (dur_str)); } src->last_message = g_strdup_printf ("get ******* > (%5d bytes, timestamp: %s" ", duration: %s, offset: %" G_GINT64_FORMAT ", offset_end: %" G_GINT64_FORMAT ", flags: %d) %p", GST_BUFFER_SIZE (buf), ts_str, dur_str, GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf), GST_MINI_OBJECT (buf)->flags, buf); GST_OBJECT_UNLOCK (src); g_object_notify (G_OBJECT (src), "last_message"); } if (src->signal_handoffs) { GST_LOG_OBJECT (src, "pre handoff emit"); g_signal_emit (G_OBJECT (src), gst_fake_src_signals[SIGNAL_HANDOFF], 0, buf, basesrc->srcpad); GST_LOG_OBJECT (src, "post handoff emit"); } src->bytes_sent += GST_BUFFER_SIZE (buf); *ret = buf; return GST_FLOW_OK; }
static gboolean gst_video_flip_src_event (GstBaseTransform * trans, GstEvent * event) { GstVideoFlip *vf = GST_VIDEO_FLIP (trans); gdouble new_x, new_y, x, y; GstStructure *structure; GST_DEBUG_OBJECT (vf, "handling %s event", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NAVIGATION: event = GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event))); structure = (GstStructure *) gst_event_get_structure (event); if (gst_structure_get_double (structure, "pointer_x", &x) && gst_structure_get_double (structure, "pointer_y", &y)) { GST_DEBUG_OBJECT (vf, "converting %fx%f", x, y); switch (vf->method) { case GST_VIDEO_FLIP_METHOD_90R: new_x = y; new_y = vf->to_width - x; break; case GST_VIDEO_FLIP_METHOD_90L: new_x = vf->to_height - y; new_y = x; break; case GST_VIDEO_FLIP_METHOD_OTHER: new_x = vf->to_height - y; new_y = vf->to_width - x; break; case GST_VIDEO_FLIP_METHOD_TRANS: new_x = y; new_y = x; break; case GST_VIDEO_FLIP_METHOD_180: new_x = vf->to_width - x; new_y = vf->to_height - y; break; case GST_VIDEO_FLIP_METHOD_HORIZ: new_x = vf->to_width - x; new_y = y; break; case GST_VIDEO_FLIP_METHOD_VERT: new_x = x; new_y = vf->to_height - y; break; default: new_x = x; new_y = y; break; } GST_DEBUG_OBJECT (vf, "to %fx%f", new_x, new_y); gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, new_x, "pointer_y", G_TYPE_DOUBLE, new_y, NULL); } break; default: break; } return TRUE; }
static GstEvent * gst_rg_volume_tag_event (GstRgVolume * self, GstEvent * event) { GstTagList *tag_list; gboolean has_track_gain, has_track_peak, has_album_gain, has_album_peak; gboolean has_ref_level; g_return_val_if_fail (event != NULL, NULL); g_return_val_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_TAG, event); gst_event_parse_tag (event, &tag_list); if (gst_tag_list_is_empty (tag_list)) return event; has_track_gain = gst_tag_list_get_double (tag_list, GST_TAG_TRACK_GAIN, &self->track_gain); has_track_peak = gst_tag_list_get_double (tag_list, GST_TAG_TRACK_PEAK, &self->track_peak); has_album_gain = gst_tag_list_get_double (tag_list, GST_TAG_ALBUM_GAIN, &self->album_gain); has_album_peak = gst_tag_list_get_double (tag_list, GST_TAG_ALBUM_PEAK, &self->album_peak); has_ref_level = gst_tag_list_get_double (tag_list, GST_TAG_REFERENCE_LEVEL, &self->reference_level); if (!has_track_gain && !has_track_peak && !has_album_gain && !has_album_peak) return event; if (has_ref_level && (has_track_gain || has_album_gain) && (ABS (self->reference_level - RG_REFERENCE_LEVEL) > 1.e-6)) { /* Log a message stating the amount of adjustment that is applied below. */ GST_DEBUG_OBJECT (self, "compensating for reference level difference by %" GAIN_FORMAT, RG_REFERENCE_LEVEL - self->reference_level); } if (has_track_gain) { self->track_gain += RG_REFERENCE_LEVEL - self->reference_level; } if (has_album_gain) { self->album_gain += RG_REFERENCE_LEVEL - self->reference_level; } /* Ignore values that are obviously invalid. */ if (G_UNLIKELY (has_track_gain && !VALID_GAIN (self->track_gain))) { GST_DEBUG_OBJECT (self, "ignoring bogus track gain value %" GAIN_FORMAT, self->track_gain); has_track_gain = FALSE; } if (G_UNLIKELY (has_track_peak && !VALID_PEAK (self->track_peak))) { GST_DEBUG_OBJECT (self, "ignoring bogus track peak value %" PEAK_FORMAT, self->track_peak); has_track_peak = FALSE; } if (G_UNLIKELY (has_album_gain && !VALID_GAIN (self->album_gain))) { GST_DEBUG_OBJECT (self, "ignoring bogus album gain value %" GAIN_FORMAT, self->album_gain); has_album_gain = FALSE; } if (G_UNLIKELY (has_album_peak && !VALID_PEAK (self->album_peak))) { GST_DEBUG_OBJECT (self, "ignoring bogus album peak value %" PEAK_FORMAT, self->album_peak); has_album_peak = FALSE; } /* Clamp peaks >1.0. Float based decoders can produce spurious samples >1.0, * cutting these files back to 1.0 should not cause any audible distortion. * This is most often seen with Vorbis files. */ if (has_track_peak && self->track_peak > 1.) { GST_DEBUG_OBJECT (self, "clamping track peak %" PEAK_FORMAT " to 1.0", self->track_peak); self->track_peak = 1.0; } if (has_album_peak && self->album_peak > 1.) { GST_DEBUG_OBJECT (self, "clamping album peak %" PEAK_FORMAT " to 1.0", self->album_peak); self->album_peak = 1.0; } self->has_track_gain |= has_track_gain; self->has_track_peak |= has_track_peak; self->has_album_gain |= has_album_gain; self->has_album_peak |= has_album_peak; event = (GstEvent *) gst_mini_object_make_writable (GST_MINI_OBJECT (event)); gst_event_parse_tag (event, &tag_list); gst_tag_list_remove_tag (tag_list, GST_TAG_TRACK_GAIN); gst_tag_list_remove_tag (tag_list, GST_TAG_TRACK_PEAK); gst_tag_list_remove_tag (tag_list, GST_TAG_ALBUM_GAIN); gst_tag_list_remove_tag (tag_list, GST_TAG_ALBUM_PEAK); gst_tag_list_remove_tag (tag_list, GST_TAG_REFERENCE_LEVEL); gst_rg_volume_update_gain (self); if (gst_tag_list_is_empty (tag_list)) { gst_event_unref (event); event = NULL; } return event; }