/* 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_TRACE_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 */ gst_object_ref (object); return; } }
/** * 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_TRACE_OBJECT (GST_CAT_REFCOUNTING, object, "sink"); GST_OBJECT_LOCK (object); if (G_LIKELY (GST_OBJECT_IS_FLOATING (object))) { GST_CAT_TRACE_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); } }
/** * gst_object_ref_sink: (skip) * @object: a #GstObject to sink * * Increase the reference count of @object, and possibly remove the floating * reference, if @object has a floating reference. * * In other words, if the object is floating, then this call "assumes ownership" * of the floating reference, converting it to a normal reference by clearing * the floating flag while leaving the reference count unchanged. If the object * is not floating, then this call adds a new normal reference increasing the * reference count by one. */ gpointer gst_object_ref_sink (gpointer object) { g_return_val_if_fail (object != NULL, NULL); #ifdef DEBUG_REFCOUNT GST_CAT_TRACE_OBJECT (GST_CAT_REFCOUNTING, object, "%p ref_sink %d->%d", object, ((GObject *) object)->ref_count, ((GObject *) object)->ref_count + 1); #endif return g_object_ref_sink (object); }
/** * gst_object_unref: * @object: (type Gst.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_TRACE_OBJECT (GST_CAT_REFCOUNTING, object, "%p unref %d->%d", object, ((GObject *) object)->ref_count, ((GObject *) object)->ref_count - 1); #endif g_object_unref (object); }
/* Allocate buffer and copy image data into Y444 format */ static GstFlowReturn daala_handle_image (GstDaalaDec * dec, od_img * img, GstVideoCodecFrame * frame) { GstVideoDecoder *decoder = GST_VIDEO_DECODER (dec); gint width, height, stride; GstFlowReturn result; gint i, comp; guint8 *dest, *src; GstVideoFrame vframe; result = gst_video_decoder_allocate_output_frame (decoder, frame); if (G_UNLIKELY (result != GST_FLOW_OK)) { GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s", gst_flow_get_name (result)); return result; } /* if only libdaala would allow us to give it a destination frame */ GST_CAT_TRACE_OBJECT (GST_CAT_PERFORMANCE, dec, "doing unavoidable video frame copy"); if (G_UNLIKELY (!gst_video_frame_map (&vframe, &dec->output_state->info, frame->output_buffer, GST_MAP_WRITE))) goto invalid_frame; for (comp = 0; comp < 3; comp++) { width = GST_VIDEO_FRAME_COMP_WIDTH (&vframe, comp); height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, comp); stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, comp); dest = GST_VIDEO_FRAME_COMP_DATA (&vframe, comp); src = img->planes[comp].data; for (i = 0; i < height; i++) { memcpy (dest, src, width); dest += stride; src += img->planes[comp].ystride; } } gst_video_frame_unmap (&vframe); return GST_FLOW_OK; invalid_frame: { GST_DEBUG_OBJECT (dec, "could not map video frame"); return GST_FLOW_ERROR; } }
static void gst_object_init (GstObject * object) { object->lock = g_mutex_new (); object->parent = NULL; object->name = NULL; GST_CAT_TRACE_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 void gst_object_init (GstObject * object) { g_mutex_init (&object->lock); object->parent = NULL; object->name = NULL; GST_CAT_TRACE_OBJECT (GST_CAT_REFCOUNTING, object, "%p new", object); #ifndef GST_DISABLE_TRACE _gst_alloc_trace_new (_gst_object_trace, object); #endif object->flags = 0; object->control_rate = 100 * GST_MSECOND; object->last_sync = GST_CLOCK_TIME_NONE; }
static GstClockTime gst_test_clock_get_internal_time (GstClock * clock) { GstTestClock *test_clock = GST_TEST_CLOCK (clock); GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock); GstClockTime result; GST_OBJECT_LOCK (test_clock); GST_CAT_TRACE_OBJECT (GST_CAT_TEST_CLOCK, test_clock, "retrieving test clock time %" GST_TIME_FORMAT, GST_TIME_ARGS (priv->internal_time)); result = priv->internal_time; GST_OBJECT_UNLOCK (test_clock); return result; }
/* finalize is called when the object has to free its resources */ static void gst_object_finalize (GObject * object) { GstObject *gstobject = GST_OBJECT_CAST (object); GST_CAT_TRACE_OBJECT (GST_CAT_REFCOUNTING, object, "finalize"); g_signal_handlers_destroy (object); g_free (gstobject->name); g_mutex_clear (&gstobject->lock); #ifndef GST_DISABLE_TRACE _gst_alloc_trace_free (_gst_object_trace, object); #endif ((GObjectClass *) gst_object_parent_class)->finalize (object); }
static void gst_test_clock_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec) { GstTestClock *test_clock = GST_TEST_CLOCK (object); GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock); switch (property_id) { case PROP_START_TIME: priv->start_time = g_value_get_uint64 (value); GST_CAT_TRACE_OBJECT (GST_CAT_TEST_CLOCK, test_clock, "test clock start time initialized at %" GST_TIME_FORMAT, GST_TIME_ARGS (priv->start_time)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } }
/* dispose is called when the object has to release all links * to other objects */ static void gst_object_dispose (GObject * object) { GstObject *self = (GstObject *) object; GstObject *parent; GST_CAT_TRACE_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); if (self->control_bindings) { GList *node; for (node = self->control_bindings; node; node = g_list_next (node)) { gst_object_unparent (node->data); } g_list_free (self->control_bindings); self->control_bindings = NULL; } ((GObjectClass *) gst_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 */ gst_object_ref (object); return; } }
/** * gst_object_set_parent: * @object: a #GstObject * @parent: new parent of object * * Sets the parent of @object to @parent. The object's reference count will * be incremented, and any floating reference will be removed (see gst_object_sink()). * * This function causes the parent-set signal to be emitted when the parent * was successfully set. * * Returns: TRUE if @parent could be set or FALSE when @object * already had a parent or @object and @parent are the same. * * MT safe. Grabs and releases @object's LOCK. */ 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_TRACE_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; } }
/** * gst_object_unparent: * @object: a #GstObject to unparent * * Clear the parent of @object, removing the associated reference. * This function decreases the refcount of @object. * * MT safe. Grabs and releases @object's lock. */ 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_TRACE_OBJECT (GST_CAT_REFCOUNTING, object, "unparent"); object->parent = NULL; GST_OBJECT_UNLOCK (object); /* g_object_notify_by_pspec ((GObject *)object, properties[PROP_PARENT]); */ gst_object_unref (object); } else { GST_OBJECT_UNLOCK (object); } }
/** * gst_object_unparent: * @object: a #GstObject to unparent * * Clear the parent of @object, removing the associated reference. * This function decreases the refcount of @object. * * MT safe. Grabs and releases @object's lock. */ 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_TRACE_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); } }
/* Allocate buffer and copy image data into Y444 format */ static GstFlowReturn theora_handle_image (GstTheoraDec * dec, th_ycbcr_buffer buf, GstVideoCodecFrame * frame) { GstVideoDecoder *decoder = GST_VIDEO_DECODER (dec); gint width, height, stride; GstFlowReturn result; gint i, comp; guint8 *dest, *src; GstVideoFrame vframe; gint pic_width, pic_height; gint offset_x, offset_y; result = gst_video_decoder_allocate_output_frame (decoder, frame); if (G_UNLIKELY (result != GST_FLOW_OK)) { GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s", gst_flow_get_name (result)); return result; } if (!dec->can_crop) { /* we need to crop the hard way */ offset_x = dec->info.pic_x; offset_y = dec->info.pic_y; pic_width = dec->info.pic_width; pic_height = dec->info.pic_height; /* Ensure correct offsets in chroma for formats that need it * by rounding the offset. libtheora will add proper pixels, * so no need to handle them ourselves. */ if (offset_x & 1 && dec->info.pixel_fmt != TH_PF_444) offset_x--; if (offset_y & 1 && dec->info.pixel_fmt == TH_PF_420) offset_y--; } else { /* copy the whole frame */ offset_x = 0; offset_y = 0; pic_width = dec->info.frame_width; pic_height = dec->info.frame_height; if (dec->info.pic_width != dec->info.frame_width || dec->info.pic_height != dec->info.frame_height || dec->info.pic_x != 0 || dec->info.pic_y != 0) { GstVideoMeta *vmeta; GstVideoCropMeta *cmeta; vmeta = gst_buffer_get_video_meta (frame->output_buffer); /* If the buffer pool didn't add the meta already * we add it ourselves here */ if (!vmeta) vmeta = gst_buffer_add_video_meta (frame->output_buffer, GST_VIDEO_FRAME_FLAG_NONE, dec->output_state->info.finfo->format, dec->info.frame_width, dec->info.frame_height); /* Just to be sure that the buffer pool doesn't do something * completely weird and we would crash later */ g_assert (vmeta->format == dec->output_state->info.finfo->format); g_assert (vmeta->width == dec->info.frame_width); g_assert (vmeta->height == dec->info.frame_height); cmeta = gst_buffer_add_video_crop_meta (frame->output_buffer); /* we can do things slightly more efficient when we know that * downstream understands clipping */ cmeta->x = dec->info.pic_x; cmeta->y = dec->info.pic_y; cmeta->width = dec->info.pic_width; cmeta->height = dec->info.pic_height; } } /* if only libtheora would allow us to give it a destination frame */ GST_CAT_TRACE_OBJECT (GST_CAT_PERFORMANCE, dec, "doing unavoidable video frame copy"); if (G_UNLIKELY (!gst_video_frame_map (&vframe, &dec->output_state->info, frame->output_buffer, GST_MAP_WRITE))) goto invalid_frame; for (comp = 0; comp < 3; comp++) { width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (vframe.info.finfo, comp, pic_width); height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vframe.info.finfo, comp, pic_height); stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, comp); dest = GST_VIDEO_FRAME_COMP_DATA (&vframe, comp); src = buf[comp].data; src += ((height == pic_height) ? offset_y : offset_y / 2) * buf[comp].stride; src += (width == pic_width) ? offset_x : offset_x / 2; for (i = 0; i < height; i++) { memcpy (dest, src, width); dest += stride; src += buf[comp].stride; } } gst_video_frame_unmap (&vframe); return GST_FLOW_OK; invalid_frame: { GST_DEBUG_OBJECT (dec, "could not map video frame"); return GST_FLOW_ERROR; } }
static GstFlowReturn gst_ffmpegauddec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf) { GstFFMpegAudDec *ffmpegdec; GstFFMpegAudDecClass *oclass; guint8 *data, *bdata; GstMapInfo map; gint size, bsize, len, have_data; GstFlowReturn ret = GST_FLOW_OK; gboolean do_padding, is_header; ffmpegdec = (GstFFMpegAudDec *) decoder; if (G_UNLIKELY (!ffmpegdec->opened)) goto not_negotiated; if (inbuf == NULL) { gst_ffmpegauddec_drain (ffmpegdec); return GST_FLOW_OK; } inbuf = gst_buffer_ref (inbuf); is_header = GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_HEADER); oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); GST_LOG_OBJECT (ffmpegdec, "Received new data of size %" G_GSIZE_FORMAT ", offset:%" G_GUINT64_FORMAT ", ts:%" GST_TIME_FORMAT ", dur:%" GST_TIME_FORMAT, gst_buffer_get_size (inbuf), GST_BUFFER_OFFSET (inbuf), GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)), GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf))); /* workarounds, functions write to buffers: * libavcodec/svq1.c:svq1_decode_frame writes to the given buffer. * libavcodec/svq3.c:svq3_decode_slice_header too. * ffmpeg devs know about it and will fix it (they said). */ if (oclass->in_plugin->id == AV_CODEC_ID_SVQ1 || oclass->in_plugin->id == AV_CODEC_ID_SVQ3) { inbuf = gst_buffer_make_writable (inbuf); } gst_buffer_map (inbuf, &map, GST_MAP_READ); bdata = map.data; bsize = map.size; if (bsize > 0 && (!GST_MEMORY_IS_ZERO_PADDED (map.memory) || (map.maxsize - map.size) < FF_INPUT_BUFFER_PADDING_SIZE)) { /* add padding */ if (ffmpegdec->padded_size < bsize + FF_INPUT_BUFFER_PADDING_SIZE) { ffmpegdec->padded_size = bsize + FF_INPUT_BUFFER_PADDING_SIZE; ffmpegdec->padded = g_realloc (ffmpegdec->padded, ffmpegdec->padded_size); GST_LOG_OBJECT (ffmpegdec, "resized padding buffer to %d", ffmpegdec->padded_size); } GST_CAT_TRACE_OBJECT (CAT_PERFORMANCE, ffmpegdec, "Copy input to add padding"); memcpy (ffmpegdec->padded, bdata, bsize); memset (ffmpegdec->padded + bsize, 0, FF_INPUT_BUFFER_PADDING_SIZE); bdata = ffmpegdec->padded; do_padding = TRUE; } else { do_padding = FALSE; } do { guint8 tmp_padding[FF_INPUT_BUFFER_PADDING_SIZE]; data = bdata; size = bsize; if (do_padding) { /* add temporary padding */ GST_CAT_TRACE_OBJECT (CAT_PERFORMANCE, ffmpegdec, "Add temporary input padding"); memcpy (tmp_padding, data + size, FF_INPUT_BUFFER_PADDING_SIZE); memset (data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); } /* decode a frame of audio now */ len = gst_ffmpegauddec_frame (ffmpegdec, data, size, &have_data, &ret); if (do_padding) { memcpy (data + size, tmp_padding, FF_INPUT_BUFFER_PADDING_SIZE); } if (ret != GST_FLOW_OK) { GST_LOG_OBJECT (ffmpegdec, "breaking because of flow ret %s", gst_flow_get_name (ret)); /* bad flow return, make sure we discard all data and exit */ bsize = 0; break; } if (len == 0 && have_data == 0) { /* nothing was decoded, this could be because no data was available or * because we were skipping frames. * If we have no context we must exit and wait for more data, we keep the * data we tried. */ GST_LOG_OBJECT (ffmpegdec, "Decoding didn't return any data, breaking"); break; } else if (len < 0) { /* a decoding error happened, we must break and try again with next data. */ GST_LOG_OBJECT (ffmpegdec, "Decoding error, breaking"); bsize = 0; break; } /* prepare for the next round, for codecs with a context we did this * already when using the parser. */ bsize -= len; bdata += len; do_padding = TRUE; GST_LOG_OBJECT (ffmpegdec, "Before (while bsize>0). bsize:%d , bdata:%p", bsize, bdata); } while (bsize > 0); gst_buffer_unmap (inbuf, &map); gst_buffer_unref (inbuf); if (ffmpegdec->outbuf) ret = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (ffmpegdec), ffmpegdec->outbuf, 1); else if (len < 0 || is_header) ret = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (ffmpegdec), NULL, 1); ffmpegdec->outbuf = NULL; if (bsize > 0) { GST_DEBUG_OBJECT (ffmpegdec, "Dropping %d bytes of data", bsize); } return ret; /* ERRORS */ not_negotiated: { oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL), ("avdec_%s: input format was not set before data start", oclass->in_plugin->name)); return GST_FLOW_NOT_NEGOTIATED; } }