static inline gboolean gst_ts_shifter_src_event (GstPad * pad, GstObject * parent, GstEvent * event) { gboolean ret = TRUE; GstTSShifter *ts = GST_TS_SHIFTER (parent); if (G_UNLIKELY (ts == NULL)) { gst_event_unref (event); return FALSE; } switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: { GST_CAT_LOG_OBJECT (ts_flow, ts, "received seek event"); /* Do the seek ourself now */ ret = gst_ts_shifter_handle_seek (ts, event); break; } case GST_EVENT_QOS: { break; } default: GST_CAT_LOG_OBJECT (ts_flow, ts, "dropped event %s", GST_EVENT_TYPE_NAME (event)); ret = FALSE; break; } gst_event_unref (event); return ret; }
/** * gst_clock_add_observation: * @clock: a #GstClock * @slave: a time on the slave * @master: a time on the master * @r_squared: (out): a pointer to hold the result * * The time @master of the master clock and the time @slave of the slave * clock are added to the list of observations. If enough observations * are available, a linear regression algorithm is run on the * observations and @clock is recalibrated. * * If this functions returns %TRUE, @r_squared will contain the * correlation coefficient of the interpolation. A value of 1.0 * means a perfect regression was performed. This value can * be used to control the sampling frequency of the master and slave * clocks. * * Returns: %TRUE if enough observations were added to run the * regression algorithm. * * MT safe. */ gboolean gst_clock_add_observation (GstClock * clock, GstClockTime slave, GstClockTime master, gdouble * r_squared) { GstClockTime m_num, m_denom, b, xbase; GstClockPrivate *priv; g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE); g_return_val_if_fail (r_squared != NULL, FALSE); priv = clock->priv; GST_CLOCK_SLAVE_LOCK (clock); GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, clock, "adding observation slave %" GST_TIME_FORMAT ", master %" GST_TIME_FORMAT, GST_TIME_ARGS (slave), GST_TIME_ARGS (master)); priv->times[(4 * priv->time_index)] = slave; priv->times[(4 * priv->time_index) + 2] = master; priv->time_index++; if (G_UNLIKELY (priv->time_index == priv->window_size)) { priv->filling = FALSE; priv->time_index = 0; } if (G_UNLIKELY (priv->filling && priv->time_index < priv->window_threshold)) goto filling; if (!do_linear_regression (clock, &m_num, &m_denom, &b, &xbase, r_squared)) goto invalid; GST_CLOCK_SLAVE_UNLOCK (clock); GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, clock, "adjusting clock to m=%" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT ", b=%" G_GUINT64_FORMAT " (rsquared=%g)", m_num, m_denom, b, *r_squared); /* if we have a valid regression, adjust the clock */ gst_clock_set_calibration (clock, xbase, b, m_num, m_denom); return TRUE; filling: { GST_CLOCK_SLAVE_UNLOCK (clock); return FALSE; } invalid: { /* no valid regression has been done, ignore the result then */ GST_CLOCK_SLAVE_UNLOCK (clock); return TRUE; } }
/* called repeadedly with @pad as the source pad. This function should push out * data to the peer element. */ static void gst_ts_shifter_loop (GstPad * pad) { GstTSShifter *ts; GstFlowReturn ret; ts = GST_TS_SHIFTER (GST_PAD_PARENT (pad)); /* have to lock for thread-safety */ FLOW_MUTEX_LOCK_CHECK (ts, ts->srcresult, out_flushing); if (gst_ts_cache_is_empty (ts->cache) && !ts->is_eos) { GST_CAT_LOG_OBJECT (ts_flow, ts, "empty, waiting for new data"); do { /* Wait for data to be available, we could be unlocked because of a flush. */ FLOW_WAIT_ADD_CHECK (ts, ts->srcresult, out_flushing); } while (gst_ts_cache_is_empty (ts->cache) && !ts->is_eos); } ret = gst_ts_shifter_pop (ts); ts->srcresult = ret; if (ret != GST_FLOW_OK) goto out_flushing; FLOW_MUTEX_UNLOCK (ts); return; /* ERRORS */ out_flushing: { gboolean eos = ts->is_eos; GstFlowReturn ret = ts->srcresult; gst_pad_pause_task (ts->srcpad); FLOW_MUTEX_UNLOCK (ts); GST_CAT_LOG_OBJECT (ts_flow, ts, "pause task, reason: %s", gst_flow_get_name (ts->srcresult)); /* let app know about us giving up if upstream is not expected to do so */ /* UNEXPECTED is already taken care of elsewhere */ if (eos && (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS)) { GST_ELEMENT_ERROR (ts, STREAM, FAILED, ("Internal data flow error."), ("streaming task paused, reason %s (%d)", gst_flow_get_name (ret), ret)); GST_CAT_LOG_OBJECT (ts_flow, ts, "pushing EOS"); gst_pad_push_event (ts->srcpad, gst_event_new_eos ()); } return; } }
/* copy data into @dest, skipping @skip bytes from the head buffers */ static void copy_into_unchecked (GstAdapter * adapter, guint8 * dest, gsize skip, gsize size) { GSList *g; GstBuffer *buf; gsize bsize, csize; /* first step, do skipping */ /* we might well be copying where we were scanning */ if (adapter->scan_entry && (adapter->scan_offset <= skip)) { g = adapter->scan_entry; skip -= adapter->scan_offset; } else { g = adapter->buflist; } buf = g->data; bsize = gst_buffer_get_size (buf); while (G_UNLIKELY (skip >= bsize)) { skip -= bsize; g = g_slist_next (g); buf = g->data; bsize = gst_buffer_get_size (buf); } /* copy partial buffer */ csize = MIN (bsize - skip, size); GST_DEBUG ("bsize %" G_GSIZE_FORMAT ", skip %" G_GSIZE_FORMAT ", csize %" G_GSIZE_FORMAT, bsize, skip, csize); GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, adapter, "extract %" G_GSIZE_FORMAT " bytes", csize); gst_buffer_extract (buf, skip, dest, csize); size -= csize; dest += csize; /* second step, copy remainder */ while (size > 0) { g = g_slist_next (g); buf = g->data; bsize = gst_buffer_get_size (buf); if (G_LIKELY (bsize > 0)) { csize = MIN (bsize, size); GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, adapter, "extract %" G_GSIZE_FORMAT " bytes", csize); gst_buffer_extract (buf, 0, dest, csize); size -= csize; dest += csize; } } }
static int spotify_cb_music_delivery (sp_session *spotify_session, const sp_audioformat *format,const void *frames, int num_frames) { GstBuffer *buffer; guint sample_rate = format->sample_rate; guint channels = format->channels; guint bufsize = num_frames * sizeof (int16_t) * channels; guint availible; GST_CAT_DEBUG_OBJECT (gst_spot_src_debug_cb, ugly_spot, "Music_delivery callback"); GST_SPOT_SRC_FORMAT (ugly_spot)->sample_rate = sample_rate; GST_SPOT_SRC_FORMAT (ugly_spot)->channels = channels; GST_SPOT_SRC_FORMAT (ugly_spot)->sample_type = format->sample_type; GST_CAT_LOG_OBJECT (gst_spot_src_debug_audio, ugly_spot, "Start %p with %d frames with size=%d", frames, num_frames, bufsize); if (num_frames == 0) { /* we have a seek */ return 0; } buffer = gst_buffer_new_and_alloc (bufsize); memcpy (GST_BUFFER_DATA (buffer), (guint8*)frames, bufsize); g_mutex_lock (GST_SPOT_SRC_ADAPTER_MUTEX (ugly_spot)); availible = gst_adapter_available (GST_SPOT_SRC_ADAPTER (ugly_spot)); GST_CAT_LOG_OBJECT (gst_spot_src_debug_audio, ugly_spot, "Availiable before push = %d", availible); /* see if we have buffertime of audio */ if (availible >= (GST_SPOT_SRC_BUFFER_TIME (ugly_spot)/1000000) * sample_rate * 4) { GST_CAT_LOG_OBJECT (gst_spot_src_debug_audio, ugly_spot, "Return 0, adapter is full = %d", availible); gst_buffer_unref (buffer); /* data is available broadcast read thread */ g_cond_broadcast (GST_SPOT_SRC_ADAPTER_COND (ugly_spot)); g_mutex_unlock (GST_SPOT_SRC_ADAPTER_MUTEX (ugly_spot)); return 0; } gst_adapter_push (GST_SPOT_SRC_ADAPTER (ugly_spot), buffer); availible = gst_adapter_available (GST_SPOT_SRC_ADAPTER (ugly_spot)); GST_CAT_LOG_OBJECT (gst_spot_src_debug_audio, ugly_spot, "Availiable after push = %d", availible); /* data is available broadcast read thread */ g_cond_broadcast (GST_SPOT_SRC_ADAPTER_COND (ugly_spot)); g_mutex_unlock (GST_SPOT_SRC_ADAPTER_MUTEX (ugly_spot)); GST_CAT_LOG_OBJECT (gst_spot_src_debug_audio, ugly_spot, "Return num_frames=%d", num_frames); return num_frames; }
static gboolean gst_spot_src_get_size (GstBaseSrc * basesrc, guint64 * size) { GstSpotSrc *spot; guint64 duration = 0; spot = GST_SPOT_SRC (basesrc); /* duration in ms */ duration = run_spot_cmd (spot, SPOT_CMD_DURATION, 0); /* duration in ns */ duration = 1000000 * duration; if (!duration) { GST_CAT_ERROR_OBJECT (gst_spot_src_debug_audio, spot, "No duration error"); goto no_duration; } *size = (duration/1000000000) * 44100 * 4; GST_CAT_LOG_OBJECT (gst_spot_src_debug_audio, spot, "Duration=%" G_GUINT64_FORMAT " => size=%" G_GUINT64_FORMAT, duration, *size); return TRUE; no_duration: return FALSE; }
/* Changing a GObject property of a GstObject will result in "deep_notify" * signals being emitted by the object itself, as well as in each parent * object. This is so that an application can connect a listener to the * top-level bin to catch property-change notifications for all contained * elements. * * This function is not MT safe in glib < 2.8 so we need to lock it with a * classwide mutex in that case. * * MT safe. */ static void gst_object_dispatch_properties_changed (GObject * object, guint n_pspecs, GParamSpec ** pspecs) { GstObject *gst_object, *parent, *old_parent; guint i; gchar *name, *debug_name; /* do the standard dispatching */ parent_class->dispatch_properties_changed (object, n_pspecs, pspecs); gst_object = GST_OBJECT_CAST (object); name = gst_object_get_name (gst_object); debug_name = GST_STR_NULL (name); /* now let the parent dispatch those, too */ parent = gst_object_get_parent (gst_object); while (parent) { for (i = 0; i < n_pspecs; i++) { GST_CAT_LOG_OBJECT (GST_CAT_PROPERTIES, parent, "deep notification from %s (%s)", debug_name, pspecs[i]->name); g_signal_emit (parent, gst_object_signals[DEEP_NOTIFY], g_quark_from_string (pspecs[i]->name), gst_object, pspecs[i]); } old_parent = parent; parent = gst_object_get_parent (old_parent); gst_object_unref (old_parent); } g_free (name); }
/* dispose is called when the object has to release all links * to other objects */ static void gst_object_dispose (GObject * object) { GstObject *parent; GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose"); GST_OBJECT_LOCK (object); if ((parent = GST_OBJECT_PARENT (object))) goto have_parent; GST_OBJECT_PARENT (object) = NULL; GST_OBJECT_UNLOCK (object); parent_class->dispose (object); return; /* ERRORS */ have_parent: { g_critical ("\nTrying to dispose object \"%s\", but it still has a " "parent \"%s\".\nYou need to let the parent manage the " "object instead of unreffing the object directly.\n", GST_OBJECT_NAME (object), GST_OBJECT_NAME (parent)); GST_OBJECT_UNLOCK (object); /* ref the object again to revive it in this error case */ object = gst_object_ref (object); return; } }
static void spotify_cb_notify_main_thread (sp_session *spotify_session) { GST_CAT_LOG_OBJECT (gst_spot_src_debug_cb, ugly_spot, "Notify_main_thread callback"); GST_CAT_DEBUG_OBJECT (gst_spot_src_debug_threads, ugly_spot, "Broadcast process_events_cond"); g_cond_broadcast (ugly_spot->process_events_cond); }
EXPORT_C #endif void gst_object_unparent (GstObject * object) { GstObject *parent; g_return_if_fail (GST_IS_OBJECT (object)); GST_OBJECT_LOCK (object); parent = object->parent; if (G_LIKELY (parent != NULL)) { GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unparent"); object->parent = NULL; GST_OBJECT_UNLOCK (object); g_signal_emit (object, gst_object_signals[PARENT_UNSET], 0, parent); gst_object_unref (object); } else { GST_OBJECT_UNLOCK (object); } }
/** * gst_object_sink: * @object: a #GstObject to sink * * If @object was floating, the #GST_OBJECT_FLOATING flag is removed * and @object is unreffed. When @object was not floating, * this function does nothing. * * Any newly created object has a refcount of 1 and is floating. * This function should be used when creating a new object to * symbolically 'take ownership' of @object. This done by first doing a * gst_object_ref() to keep a reference to @object and then gst_object_sink() * to remove and unref any floating references to @object. * Use gst_object_set_parent() to have this done for you. * * MT safe. This function grabs and releases @object lock. */ void gst_object_sink (gpointer object) { g_return_if_fail (GST_IS_OBJECT (object)); GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "sink"); GST_OBJECT_LOCK (object); if (G_LIKELY (GST_OBJECT_IS_FLOATING (object))) { GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "clear floating flag"); GST_OBJECT_FLAG_UNSET (object, GST_OBJECT_FLOATING); GST_OBJECT_UNLOCK (object); gst_object_unref (object); } else { GST_OBJECT_UNLOCK (object); } }
static GstFlowReturn gst_mpeg2dec_crop_buffer (GstMpeg2dec * dec, GstVideoCodecFrame * in_frame, GstVideoFrame * input_vframe) { GstVideoCodecState *state; GstVideoInfo *info; GstVideoInfo *dinfo; GstVideoFrame output_frame; GstFlowReturn ret; GstBuffer *buffer = NULL; state = gst_video_decoder_get_output_state (GST_VIDEO_DECODER (dec)); info = &state->info; dinfo = &dec->decoded_info; GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, dec, "Copying input buffer %ux%u (%" G_GSIZE_FORMAT ") to output buffer " "%ux%u (%" G_GSIZE_FORMAT ")", dinfo->width, dinfo->height, dinfo->size, info->width, info->height, info->size); ret = gst_buffer_pool_acquire_buffer (dec->downstream_pool, &buffer, NULL); if (ret != GST_FLOW_OK) goto beach; if (!gst_video_frame_map (&output_frame, info, buffer, GST_MAP_WRITE)) goto map_fail; if (in_frame->output_buffer) gst_buffer_unref (in_frame->output_buffer); in_frame->output_buffer = buffer; if (!gst_video_frame_copy (&output_frame, input_vframe)) goto copy_failed; gst_video_frame_unmap (&output_frame); GST_BUFFER_FLAGS (in_frame->output_buffer) = GST_BUFFER_FLAGS (input_vframe->buffer); beach: gst_video_codec_state_unref (state); return ret; map_fail: { GST_ERROR_OBJECT (dec, "Failed to map output frame"); gst_video_codec_state_unref (state); return GST_FLOW_ERROR; } copy_failed: { GST_ERROR_OBJECT (dec, "Failed to copy output frame"); gst_video_codec_state_unref (state); return GST_FLOW_ERROR; } }
static GstFlowReturn gst_dshowvideodec_chain (GstPad * pad, GstBuffer * buffer) { GstDshowVideoDec *vdec = (GstDshowVideoDec *) gst_pad_get_parent (pad); bool discont = FALSE; GstClockTime stop; if (!vdec->setup) { /* we are not setup */ GST_WARNING_OBJECT (vdec, "Decoder not set up, failing"); vdec->last_ret = GST_FLOW_FLUSHING; goto beach; } if (GST_FLOW_IS_FATAL (vdec->last_ret)) { GST_DEBUG_OBJECT (vdec, "last decoding iteration generated a fatal error " "%s", gst_flow_get_name (vdec->last_ret)); goto beach; } /* check if duration is valid and use duration only when it's valid /* because dshow is not decoding frames having stop smaller than start */ if (GST_BUFFER_DURATION_IS_VALID (buffer)) { stop = GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer); } else { stop = GST_BUFFER_TIMESTAMP (buffer); } GST_CAT_LOG_OBJECT (dshowvideodec_debug, vdec, "chain (size %d)=> pts %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT, GST_BUFFER_SIZE (buffer), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), GST_TIME_ARGS (stop)); /* if the incoming buffer has discont flag set => flush decoder data */ if (buffer && GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) { GST_CAT_DEBUG_OBJECT (dshowvideodec_debug, vdec, "this buffer has a DISCONT flag (%" GST_TIME_FORMAT "), flushing", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); gst_dshowvideodec_flush (vdec); discont = TRUE; } /* push the buffer to the directshow decoder */ vdec->fakesrc->GetOutputPin()->PushBuffer( GST_BUFFER_DATA (buffer), GST_BUFFER_TIMESTAMP (buffer), stop, GST_BUFFER_SIZE (buffer), discont); beach: gst_buffer_unref (buffer); gst_object_unref (vdec); return vdec->last_ret; }
static GstFlowReturn gst_v4l2_buffer_pool_copy_buffer (GstV4l2BufferPool * pool, GstBuffer * dest, GstBuffer * src) { const GstVideoFormatInfo *finfo = pool->caps_info.finfo; GST_LOG_OBJECT (pool, "copying buffer"); if (finfo && (finfo->format != GST_VIDEO_FORMAT_UNKNOWN && finfo->format != GST_VIDEO_FORMAT_ENCODED)) { GstVideoFrame src_frame, dest_frame; GST_DEBUG_OBJECT (pool, "copy video frame"); /* we have raw video, use videoframe copy to get strides right */ if (!gst_video_frame_map (&src_frame, &pool->caps_info, src, GST_MAP_READ)) goto invalid_buffer; if (!gst_video_frame_map (&dest_frame, &pool->caps_info, dest, GST_MAP_WRITE)) { gst_video_frame_unmap (&src_frame); goto invalid_buffer; } gst_video_frame_copy (&dest_frame, &src_frame); gst_video_frame_unmap (&src_frame); gst_video_frame_unmap (&dest_frame); } else { GstMapInfo map; GST_DEBUG_OBJECT (pool, "copy raw bytes"); if (!gst_buffer_map (src, &map, GST_MAP_READ)) goto invalid_buffer; gst_buffer_fill (dest, 0, map.data, gst_buffer_get_size (src)); gst_buffer_unmap (src, &map); gst_buffer_resize (dest, 0, gst_buffer_get_size (src)); } GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, pool, "slow copy into buffer %p", dest); return GST_FLOW_OK; invalid_buffer: { GST_ERROR_OBJECT (pool, "could not map buffer"); return GST_FLOW_ERROR; } }
/** * gst_object_unref: * @object: a #GstObject to unreference * * Decrements the reference count on @object. If reference count hits * zero, destroy @object. This function does not take the lock * on @object as it relies on atomic refcounting. * * The unref method should never be called with the LOCK held since * this might deadlock the dispose function. */ void gst_object_unref (gpointer object) { g_return_if_fail (object != NULL); g_return_if_fail (((GObject *) object)->ref_count > 0); #ifdef DEBUG_REFCOUNT GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "%p unref %d->%d", object, ((GObject *) object)->ref_count, ((GObject *) object)->ref_count - 1); #endif g_object_unref (object); }
/** * gst_object_ref: * @object: a #GstObject to reference * * Increments the reference count on @object. This function * does not take the lock on @object because it relies on * atomic refcounting. * * This object returns the input parameter to ease writing * constructs like : * result = gst_object_ref (object->parent); * * Returns: A pointer to @object */ gpointer gst_object_ref (gpointer object) { g_return_val_if_fail (object != NULL, NULL); #ifdef DEBUG_REFCOUNT GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "%p ref %d->%d", object, ((GObject *) object)->ref_count, ((GObject *) object)->ref_count + 1); #endif g_object_ref (object); return object; }
static void gst_object_init (GstObject * object) { object->lock = g_mutex_new (); object->parent = NULL; object->name = NULL; GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "%p new", object); #ifndef GST_DISABLE_TRACE gst_alloc_trace_new (_gst_object_trace, object); #endif object->flags = 0; GST_OBJECT_FLAG_SET (object, GST_OBJECT_FLOATING); }
static OMX_ERRORTYPE FillBufferDone (OMX_HANDLETYPE omx_handle, OMX_PTR app_data, OMX_BUFFERHEADERTYPE *omx_buffer) { GOmxCore *core; GOmxPort *port; core = (GOmxCore *) app_data; port = get_port (core, omx_buffer->nOutputPortIndex); GST_CAT_LOG_OBJECT (gstomx_util_debug, core->object, "omx_buffer=%p", omx_buffer); got_buffer (core, port, omx_buffer); return OMX_ErrorNone; }
/* finalize is called when the object has to free its resources */ static void gst_object_finalize (GObject * object) { GstObject *gstobject = GST_OBJECT (object); GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "finalize"); g_signal_handlers_destroy (object); g_free (gstobject->name); g_mutex_free (gstobject->lock); #ifndef GST_DISABLE_TRACE gst_alloc_trace_free (_gst_object_trace, object); #endif parent_class->finalize (object); }
/* Changing a GObject property of a GstObject will result in "deep-notify" * signals being emitted by the object itself, as well as in each parent * object. This is so that an application can connect a listener to the * top-level bin to catch property-change notifications for all contained * elements. * * MT safe. */ static void gst_object_dispatch_properties_changed (GObject * object, guint n_pspecs, GParamSpec ** pspecs) { GstObject *gst_object, *parent, *old_parent; guint i; #ifndef GST_DISABLE_GST_DEBUG gchar *name = NULL; const gchar *debug_name; #endif /* do the standard dispatching */ ((GObjectClass *) gst_object_parent_class)->dispatch_properties_changed (object, n_pspecs, pspecs); gst_object = GST_OBJECT_CAST (object); #ifndef GST_DISABLE_GST_DEBUG if (G_UNLIKELY (_gst_debug_min >= GST_LEVEL_LOG)) { name = gst_object_get_name (gst_object); debug_name = GST_STR_NULL (name); } else debug_name = ""; #endif /* now let the parent dispatch those, too */ parent = gst_object_get_parent (gst_object); while (parent) { for (i = 0; i < n_pspecs; i++) { GST_CAT_LOG_OBJECT (GST_CAT_PROPERTIES, parent, "deep notification from %s (%s)", debug_name, pspecs[i]->name); g_signal_emit (parent, gst_object_signals[DEEP_NOTIFY], g_quark_from_string (pspecs[i]->name), gst_object, pspecs[i]); } old_parent = parent; parent = gst_object_get_parent (old_parent); gst_object_unref (old_parent); } #ifndef GST_DISABLE_GST_DEBUG g_free (name); #endif }
EXPORT_C #endif gboolean gst_object_set_parent (GstObject * object, GstObject * parent) { g_return_val_if_fail (GST_IS_OBJECT (object), FALSE); g_return_val_if_fail (GST_IS_OBJECT (parent), FALSE); g_return_val_if_fail (object != parent, FALSE); GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "set parent (ref and sink)"); GST_OBJECT_LOCK (object); if (G_UNLIKELY (object->parent != NULL)) goto had_parent; /* sink object, we don't call our own function because we don't * need to release/acquire the lock needlessly or touch the refcount * in the floating case. */ object->parent = parent; if (G_LIKELY (GST_OBJECT_IS_FLOATING (object))) { GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unsetting floating flag"); GST_OBJECT_FLAG_UNSET (object, GST_OBJECT_FLOATING); GST_OBJECT_UNLOCK (object); } else { GST_OBJECT_UNLOCK (object); gst_object_ref (object); } g_signal_emit (object, gst_object_signals[PARENT_SET], 0, parent); return TRUE; /* ERROR handling */ had_parent: { GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "set parent failed, object already had a parent"); GST_OBJECT_UNLOCK (object); return FALSE; } }
/* internal function, nbytes should be flushed after calling this function */ static guint8 * gst_adapter_take_internal (GstAdapter * adapter, gsize nbytes) { guint8 *data; gsize toreuse, tocopy; /* see how much data we can reuse from the assembled memory and how much * we need to copy */ toreuse = MIN (nbytes, adapter->assembled_len); tocopy = nbytes - toreuse; /* find memory to return */ if (adapter->assembled_size >= nbytes && toreuse > 0) { /* we reuse already allocated memory but only when we're going to reuse * something from it because else we are worse than the malloc and copy * case below */ GST_LOG_OBJECT (adapter, "reusing %" G_GSIZE_FORMAT " bytes of assembled" " data", toreuse); /* we have enough free space in the assembled array */ data = adapter->assembled_data; /* flush after this function should set the assembled_size to 0 */ adapter->assembled_data = g_malloc (adapter->assembled_size); } else { GST_LOG_OBJECT (adapter, "allocating %" G_GSIZE_FORMAT " bytes", nbytes); /* not enough bytes in the assembled array, just allocate new space */ data = g_malloc (nbytes); /* reuse what we can from the already assembled data */ if (toreuse) { GST_LOG_OBJECT (adapter, "reusing %" G_GSIZE_FORMAT " bytes", toreuse); GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, adapter, "memcpy %" G_GSIZE_FORMAT " bytes", toreuse); memcpy (data, adapter->assembled_data, toreuse); } } if (tocopy) { /* copy the remaining data */ copy_into_unchecked (adapter, toreuse + data, toreuse + adapter->skip, tocopy); } return data; }
static GstFlowReturn gst_ts_shifter_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstTSShifter *ts = GST_TS_SHIFTER (parent); GstFlowReturn res; GstMapInfo map; GST_CAT_LOG_OBJECT (ts_flow, ts, "received buffer %p of size %d, time %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, buffer, gst_buffer_get_size (buffer), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), GST_TIME_ARGS (GST_BUFFER_DURATION (buffer))); gst_buffer_map (buffer, &map, GST_MAP_READ); res = gst_ts_shifter_push (ts, map.data, map.size); gst_buffer_unmap (buffer, &map); gst_buffer_unref (buffer); return res; }
/****************************************************** * gst_v4l2src_grab_frame (): * grab a frame for capturing * return value: GST_FLOW_OK, GST_FLOW_WRONG_STATE or GST_FLOW_ERROR ******************************************************/ GstFlowReturn gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf) { #define NUM_TRIALS 50 GstV4l2Object *v4l2object; GstV4l2BufferPool *pool; gint32 trials = NUM_TRIALS; GstBuffer *pool_buffer; gboolean need_copy; gint ret; v4l2object = v4l2src->v4l2object; pool = v4l2src->pool; if (!pool) goto no_buffer_pool; GST_DEBUG_OBJECT (v4l2src, "grab frame"); for (;;) { if (v4l2object->can_poll_device) { ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE); if (G_UNLIKELY (ret < 0)) { if (errno == EBUSY) goto stopped; if (errno == ENXIO) { GST_DEBUG_OBJECT (v4l2src, "v4l2 device doesn't support polling. Disabling"); v4l2object->can_poll_device = FALSE; } else { if (errno != EAGAIN && errno != EINTR) goto select_error; } } } pool_buffer = GST_BUFFER (gst_v4l2_buffer_pool_dqbuf (pool)); if (pool_buffer) break; GST_WARNING_OBJECT (pool->v4l2elem, "trials=%d", trials); /* if the sync() got interrupted, we can retry */ switch (errno) { case EINVAL: case ENOMEM: /* fatal */ return GST_FLOW_ERROR; case EAGAIN: case EIO: case EINTR: default: /* try again, until too many trials */ break; } /* check nr. of attempts to capture */ if (--trials == -1) { goto too_many_trials; } } /* if we are handing out the last buffer in the pool, we need to make a * copy and bring the buffer back in the pool. */ need_copy = v4l2src->always_copy || !gst_v4l2_buffer_pool_available_buffers (pool); if (G_UNLIKELY (need_copy)) { if (!v4l2src->always_copy) { GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, v4l2src, "running out of buffers, making a copy to reuse current one"); } *buf = gst_buffer_copy (pool_buffer); GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY); /* this will requeue */ gst_buffer_unref (pool_buffer); } else { *buf = pool_buffer; } /* we set the buffer metadata in gst_v4l2src_create() */ return GST_FLOW_OK; /* ERRORS */ no_buffer_pool: { GST_DEBUG ("no buffer pool"); return GST_FLOW_WRONG_STATE; } select_error: { GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, READ, (NULL), ("select error %d: %s (%d)", ret, g_strerror (errno), errno)); return GST_FLOW_ERROR; } stopped: { GST_DEBUG ("stop called"); return GST_FLOW_WRONG_STATE; } too_many_trials: { GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED, (_("Failed trying to get video frames from device '%s'."), v4l2object->videodev), (_("Failed after %d tries. device %s. system error: %s"), NUM_TRIALS, v4l2object->videodev, g_strerror (errno))); return GST_FLOW_ERROR; } }
static GstFlowReturn gst_mpeg2dec_crop_buffer (GstMpeg2dec * dec, GstVideoCodecFrame * in_frame, GstVideoFrame * input_vframe) { GstVideoCodecState *state; GstVideoInfo *info; GstVideoInfo *dinfo; guint c, n_planes; GstVideoFrame output_frame; GstFlowReturn ret; state = gst_video_decoder_get_output_state (GST_VIDEO_DECODER (dec)); info = &state->info; dinfo = &dec->decoded_info; GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, dec, "Copying input buffer %ux%u (%" G_GSIZE_FORMAT ") to output buffer " "%ux%u (%" G_GSIZE_FORMAT ")", dinfo->width, dinfo->height, dinfo->size, info->width, info->height, info->size); ret = gst_video_decoder_allocate_output_frame (GST_VIDEO_DECODER (dec), in_frame); if (ret != GST_FLOW_OK) goto beach; if (!gst_video_frame_map (&output_frame, info, in_frame->output_buffer, GST_MAP_WRITE)) goto map_fail; n_planes = GST_VIDEO_FRAME_N_PLANES (&output_frame); for (c = 0; c < n_planes; c++) { guint w, h, j; guint8 *sp, *dp; gint ss, ds; sp = GST_VIDEO_FRAME_PLANE_DATA (input_vframe, c); dp = GST_VIDEO_FRAME_PLANE_DATA (&output_frame, c); ss = GST_VIDEO_FRAME_PLANE_STRIDE (input_vframe, c); ds = GST_VIDEO_FRAME_PLANE_STRIDE (&output_frame, c); w = MIN (ABS (ss), ABS (ds)); h = GST_VIDEO_FRAME_COMP_HEIGHT (&output_frame, c); GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy plane %u, w:%u h:%u ", c, w, h); for (j = 0; j < h; j++) { memcpy (dp, sp, w); dp += ds; sp += ss; } } gst_video_frame_unmap (&output_frame); GST_BUFFER_FLAGS (in_frame->output_buffer) = GST_BUFFER_FLAGS (input_vframe->buffer); beach: gst_video_codec_state_unref (state); return ret; map_fail: { GST_ERROR_OBJECT (dec, "Failed to map output frame"); gst_video_codec_state_unref (state); return GST_FLOW_ERROR; } }
gint main (gint argc, gchar * argv[]) { gst_init (&argc, &argv); GST_DEBUG_CATEGORY_INIT (cat_default, "GST_Check_default", 0, "default category for this test"); GST_DEBUG_CATEGORY_INIT (cat2, "GST_Check_2", 0, "second category for this test"); #ifndef GST_DISABLE_GST_DEBUG g_assert (gst_debug_remove_log_function (gst_debug_log_default) == 1); #endif gst_debug_add_log_function (check_message, NULL); count = 0; GST_ERROR ("This is an error."); ++count; GST_WARNING ("This is a warning."); ++count; GST_INFO ("This is an info message."); ++count; GST_DEBUG ("This is a debug message."); ++count; GST_LOG ("This is a log message."); ++count; GST_CAT_ERROR (cat2, "This is an error with category."); ++count; GST_CAT_WARNING (cat2, "This is a warning with category."); ++count; GST_CAT_INFO (cat2, "This is an info message with category."); ++count; GST_CAT_DEBUG (cat2, "This is a debug message with category."); ++count; GST_CAT_LOG (cat2, "This is a log message with category."); count = -1; pipeline = gst_element_factory_make ("pipeline", "testelement"); count = 10; GST_ERROR_OBJECT (pipeline, "This is an error with object."); ++count; GST_WARNING_OBJECT (pipeline, "This is a warning with object."); ++count; GST_INFO_OBJECT (pipeline, "This is an info message with object."); ++count; GST_DEBUG_OBJECT (pipeline, "This is a debug message with object."); ++count; GST_LOG_OBJECT (pipeline, "This is a log message with object."); ++count; GST_CAT_ERROR_OBJECT (cat2, pipeline, "This is an error with category and object."); ++count; GST_CAT_WARNING_OBJECT (cat2, pipeline, "This is a warning with category and object."); ++count; GST_CAT_INFO_OBJECT (cat2, pipeline, "This is an info message with category and object."); ++count; GST_CAT_DEBUG_OBJECT (cat2, pipeline, "This is a debug message with category and object."); ++count; GST_CAT_LOG_OBJECT (cat2, pipeline, "This is a log message with category and object."); count = -1; #ifndef GST_DISABLE_GST_DEBUG g_assert (gst_debug_remove_log_function (check_message) == 1); #endif return 0; }
/** * gst_clock_add_observation_unapplied: * @clock: a #GstClock * @slave: a time on the slave * @master: a time on the master * @r_squared: (out): a pointer to hold the result * @internal: (out) (allow-none): a location to store the internal time * @external: (out) (allow-none): a location to store the external time * @rate_num: (out) (allow-none): a location to store the rate numerator * @rate_denom: (out) (allow-none): a location to store the rate denominator * * Add a clock observation to the internal slaving algorithm the same as * gst_clock_add_observation(), and return the result of the master clock * estimation, without updating the internal calibration. * * The caller can then take the results and call gst_clock_set_calibration() * with the values, or some modified version of them. * * Since: 1.6 */ gboolean gst_clock_add_observation_unapplied (GstClock * clock, GstClockTime slave, GstClockTime master, gdouble * r_squared, GstClockTime * internal, GstClockTime * external, GstClockTime * rate_num, GstClockTime * rate_denom) { GstClockTime m_num, m_denom, b, xbase; GstClockPrivate *priv; guint n; g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE); g_return_val_if_fail (r_squared != NULL, FALSE); priv = clock->priv; GST_CLOCK_SLAVE_LOCK (clock); GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, clock, "adding observation slave %" GST_TIME_FORMAT ", master %" GST_TIME_FORMAT, GST_TIME_ARGS (slave), GST_TIME_ARGS (master)); priv->times[(4 * priv->time_index)] = slave; priv->times[(4 * priv->time_index) + 2] = master; priv->time_index++; if (G_UNLIKELY (priv->time_index == priv->window_size)) { priv->filling = FALSE; priv->time_index = 0; } if (G_UNLIKELY (priv->filling && priv->time_index < priv->window_threshold)) goto filling; n = priv->filling ? priv->time_index : priv->window_size; if (!_priv_gst_do_linear_regression (priv->times, n, &m_num, &m_denom, &b, &xbase, r_squared)) goto invalid; GST_CLOCK_SLAVE_UNLOCK (clock); GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, clock, "adjusting clock to m=%" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT ", b=%" G_GUINT64_FORMAT " (rsquared=%g)", m_num, m_denom, b, *r_squared); if (internal) *internal = xbase; if (external) *external = b; if (rate_num) *rate_num = m_num; if (rate_denom) *rate_denom = m_denom; return TRUE; filling: { GST_CLOCK_SLAVE_UNLOCK (clock); return FALSE; } invalid: { /* no valid regression has been done, ignore the result then */ GST_CLOCK_SLAVE_UNLOCK (clock); return TRUE; } }
static GstCaps * gst_waveform_sink_getcaps (GstBaseSink * bsink) { GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (bsink); MMRESULT mmresult; WAVEOUTCAPS wocaps; GstCaps *caps, *caps_temp; /* return the cached caps if already defined */ if (wfsink->cached_caps) { return gst_caps_ref (wfsink->cached_caps); } /* get the default device caps */ mmresult = waveOutGetDevCaps (WAVE_MAPPER, &wocaps, sizeof (wocaps)); if (mmresult != MMSYSERR_NOERROR) { waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1); GST_ELEMENT_ERROR (wfsink, RESOURCE, SETTINGS, ("gst_waveform_sink_getcaps: waveOutGetDevCaps failed error=>%s", wfsink->error_string), (NULL)); return NULL; } caps = gst_caps_new_empty (); /* create a caps for all wave formats supported by the device starting by the best quality format */ if (wocaps.dwFormats & WAVE_FORMAT_96S16) { caps_temp = gst_waveform_sink_create_caps (96000, 2, 16); if (caps_temp) { gst_caps_append (caps, caps_temp); } } if (wocaps.dwFormats & WAVE_FORMAT_96S08) { caps_temp = gst_waveform_sink_create_caps (96000, 2, 8); if (caps_temp) { gst_caps_append (caps, caps_temp); } } if (wocaps.dwFormats & WAVE_FORMAT_96M16) { caps_temp = gst_waveform_sink_create_caps (96000, 1, 16); if (caps_temp) { gst_caps_append (caps, caps_temp); } } if (wocaps.dwFormats & WAVE_FORMAT_96M08) { caps_temp = gst_waveform_sink_create_caps (96000, 1, 8); if (caps_temp) { gst_caps_append (caps, caps_temp); } } if (wocaps.dwFormats & WAVE_FORMAT_4S16) { caps_temp = gst_waveform_sink_create_caps (44100, 2, 16); if (caps_temp) { gst_caps_append (caps, caps_temp); } } if (wocaps.dwFormats & WAVE_FORMAT_4S08) { caps_temp = gst_waveform_sink_create_caps (44100, 2, 8); if (caps_temp) { gst_caps_append (caps, caps_temp); } } if (wocaps.dwFormats & WAVE_FORMAT_4M16) { caps_temp = gst_waveform_sink_create_caps (44100, 1, 16); if (caps_temp) { gst_caps_append (caps, caps_temp); } } if (wocaps.dwFormats & WAVE_FORMAT_4M08) { caps_temp = gst_waveform_sink_create_caps (44100, 1, 8); if (caps_temp) { gst_caps_append (caps, caps_temp); } } if (wocaps.dwFormats & WAVE_FORMAT_2S16) { caps_temp = gst_waveform_sink_create_caps (22050, 2, 16); if (caps_temp) { gst_caps_append (caps, caps_temp); } } if (wocaps.dwFormats & WAVE_FORMAT_2S08) { caps_temp = gst_waveform_sink_create_caps (22050, 2, 8); if (caps_temp) { gst_caps_append (caps, caps_temp); } } if (wocaps.dwFormats & WAVE_FORMAT_2M16) { caps_temp = gst_waveform_sink_create_caps (22050, 1, 16); if (caps_temp) { gst_caps_append (caps, caps_temp); } } if (wocaps.dwFormats & WAVE_FORMAT_2M08) { caps_temp = gst_waveform_sink_create_caps (22050, 1, 8); if (caps_temp) { gst_caps_append (caps, caps_temp); } } if (wocaps.dwFormats & WAVE_FORMAT_1S16) { caps_temp = gst_waveform_sink_create_caps (11025, 2, 16); if (caps_temp) { gst_caps_append (caps, caps_temp); } } if (wocaps.dwFormats & WAVE_FORMAT_1S08) { caps_temp = gst_waveform_sink_create_caps (11025, 2, 8); if (caps_temp) { gst_caps_append (caps, caps_temp); } } if (wocaps.dwFormats & WAVE_FORMAT_1M16) { caps_temp = gst_waveform_sink_create_caps (11025, 1, 16); if (caps_temp) { gst_caps_append (caps, caps_temp); } } if (wocaps.dwFormats & WAVE_FORMAT_1M08) { caps_temp = gst_waveform_sink_create_caps (11025, 1, 8); if (caps_temp) { gst_caps_append (caps, caps_temp); } } if (gst_caps_is_empty (caps)) { gst_caps_unref (caps); caps = NULL; } else { wfsink->cached_caps = gst_caps_ref (caps); } GST_CAT_LOG_OBJECT (waveformsink_debug, wfsink, "Returning caps %s", gst_caps_to_string (caps)); return caps; }
static gboolean gst_dshowvideodec_push_buffer (byte * buffer, long size, byte * src_object, UINT64 start, UINT64 stop) { GstDshowVideoDec *vdec = (GstDshowVideoDec *) src_object; GstDshowVideoDecClass *klass = (GstDshowVideoDecClass *) G_OBJECT_GET_CLASS (vdec); GstBuffer *buf = NULL; gboolean in_seg = FALSE; gint64 clip_start = 0, clip_stop = 0; /* check if this buffer is in our current segment */ in_seg = gst_segment_clip (vdec->segment, GST_FORMAT_TIME, start, stop, &clip_start, &clip_stop); /* if the buffer is out of segment do not push it downstream */ if (!in_seg) { GST_CAT_DEBUG_OBJECT (dshowvideodec_debug, vdec, "buffer is out of segment, start %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); return FALSE; } /* buffer is in our segment allocate a new out buffer and clip its * timestamps */ vdec->last_ret = gst_pad_alloc_buffer (vdec->srcpad, GST_BUFFER_OFFSET_NONE, size, GST_PAD_CAPS (vdec->srcpad), &buf); if (!buf) { GST_CAT_WARNING_OBJECT (dshowvideodec_debug, vdec, "can't not allocate a new GstBuffer"); return FALSE; } /* set buffer properties */ GST_BUFFER_TIMESTAMP (buf) = clip_start; GST_BUFFER_DURATION (buf) = clip_stop - clip_start; if (strstr (klass->entry->srccaps, "rgb")) { /* FOR RGB directshow decoder will return bottom-up BITMAP * There is probably a way to get top-bottom video frames from * the decoder... */ gint line = 0; guint stride = vdec->width * 4; for (; line < vdec->height; line++) { memcpy (GST_BUFFER_DATA (buf) + (line * stride), buffer + (size - ((line + 1) * (stride))), stride); } } else { memcpy (GST_BUFFER_DATA (buf), buffer, MIN (size, GST_BUFFER_SIZE (buf))); } GST_CAT_LOG_OBJECT (dshowvideodec_debug, vdec, "push_buffer (size %d)=> pts %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT " duration %" GST_TIME_FORMAT, size, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)), GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); /* push the buffer downstream */ vdec->last_ret = gst_pad_push (vdec->srcpad, buf); return TRUE; }
static guint gst_waveform_sink_write (GstAudioSink * asink, gpointer data, guint length) { GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink); WAVEHDR *waveheader; MMRESULT mmresult; guint bytes_to_write = length; guint remaining_length = length; wfsink->bytes_in_queue += length; while (remaining_length > 0) { if (wfsink->free_buffers_count == 0) { /* no free buffer available, wait for one */ Sleep (10); continue; } /* get the current write buffer header */ waveheader = &wfsink->wave_buffers[wfsink->write_buffer]; /* unprepare the header if needed */ if (waveheader->dwFlags & WHDR_PREPARED) { mmresult = waveOutUnprepareHeader (wfsink->hwaveout, waveheader, sizeof (WAVEHDR)); if (mmresult != MMSYSERR_NOERROR) { waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1); GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink, "Error unpreparing buffer => %s", wfsink->error_string); } } if (wfsink->buffer_size - waveheader->dwUser >= remaining_length) bytes_to_write = remaining_length; else bytes_to_write = wfsink->buffer_size - waveheader->dwUser; memcpy (waveheader->lpData + waveheader->dwUser, data, bytes_to_write); waveheader->dwUser += bytes_to_write; remaining_length -= bytes_to_write; data = (byte *) data + bytes_to_write; if (waveheader->dwUser == wfsink->buffer_size) { /* we have filled a buffer, let's prepare it and next write it to the device */ mmresult = waveOutPrepareHeader (wfsink->hwaveout, waveheader, sizeof (WAVEHDR)); if (mmresult != MMSYSERR_NOERROR) { waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1); GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink, "gst_waveform_sink_write: Error preparing header => %s", wfsink->error_string); } mmresult = waveOutWrite (wfsink->hwaveout, waveheader, sizeof (WAVEHDR)); if (mmresult != MMSYSERR_NOERROR) { waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1); GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink, "gst_waveform_sink_write: Error writting buffer to the device => %s", wfsink->error_string); } EnterCriticalSection (&wfsink->critic_wave); wfsink->free_buffers_count--; LeaveCriticalSection (&wfsink->critic_wave); wfsink->write_buffer++; wfsink->write_buffer %= wfsink->buffer_count; waveheader->dwUser = 0; wfsink->bytes_in_queue = 0; GST_CAT_LOG_OBJECT (waveformsink_debug, wfsink, "gst_waveform_sink_write: Writting a buffer to the device (free buffers remaining=%d, write buffer=%d)", wfsink->free_buffers_count, wfsink->write_buffer); } } return length; }