static GSList * get_chunk (GstAdapter * adapter, int offset, int *skip) { GSList *g; #if 1 if (skip) *skip = 0; #endif g_return_val_if_fail (offset >= 0, NULL); g_return_val_if_fail (offset < adapter->size, NULL); offset += adapter->skip; g = adapter->buflist; while (g) { if (offset < GST_BUFFER_SIZE (GST_BUFFER_CAST (g->data))) { if (skip) *skip = offset; return g; } offset -= GST_BUFFER_SIZE (GST_BUFFER_CAST (g->data)); g = g->next; } g_assert_not_reached (); }
/* For reverse playback we use a technique that can be used for * any keyframe based video codec. * * Input: * Buffer decoding order: 7 8 9 4 5 6 1 2 3 EOS * Keyframe flag: K K * Discont flag: D D D * * - Each Discont marks a discont in the decoding order. * - The keyframes mark where we can start decoding. * * First we prepend incomming buffers to the gather queue, whenever we receive * a discont, we flush out the gather queue. * * The above data will be accumulated in the gather queue like this: * * gather queue: 9 8 7 * D * * Whe buffer 4 is received (with a DISCONT), we flush the gather queue like * this: * * while (gather) * take head of queue and prepend to decode queue. * if we copied a keyframe, decode the decode queue. * * After we flushed the gather queue, we add 4 to the (now empty) gather queue. * We get the following situation: * * gather queue: 4 * decode queue: 7 8 9 * * After we received 5 (Keyframe) and 6: * * gather queue: 6 5 4 * decode queue: 7 8 9 * * When we receive 1 (DISCONT) which triggers a flush of the gather queue: * * Copy head of the gather queue (6) to decode queue: * * gather queue: 5 4 * decode queue: 6 7 8 9 * * Copy head of the gather queue (5) to decode queue. This is a keyframe so we * can start decoding. * * gather queue: 4 * decode queue: 5 6 7 8 9 * * Decode frames in decode queue, store raw decoded data in output queue, we * can take the head of the decode queue and prepend the decoded result in the * output queue: * * gather queue: 4 * decode queue: * output queue: 9 8 7 6 5 * * Now output all the frames in the output queue, picking a frame from the * head of the queue. * * Copy head of the gather queue (4) to decode queue, we flushed the gather * queue and can now store input buffer in the gather queue: * * gather queue: 1 * decode queue: 4 * * When we receive EOS, the queue looks like: * * gather queue: 3 2 1 * decode queue: 4 * * Fill decode queue, first keyframe we copy is 2: * * gather queue: 1 * decode queue: 2 3 4 * * Decoded output: * * gather queue: 1 * decode queue: * output queue: 4 3 2 * * Leftover buffer 1 cannot be decoded and must be discarded. */ static GstFlowReturn theora_dec_flush_decode (GstTheoraDec * dec) { GstFlowReturn res = GST_FLOW_OK; while (dec->decode) { GstBuffer *buf = GST_BUFFER_CAST (dec->decode->data); GST_DEBUG_OBJECT (dec, "decoding buffer %p, ts %" GST_TIME_FORMAT, buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); /* decode buffer, prepend to output queue */ res = theora_dec_decode_buffer (dec, buf); /* don't need it anymore now */ gst_buffer_unref (buf); dec->decode = g_list_delete_link (dec->decode, dec->decode); } while (dec->queued) { GstBuffer *buf = GST_BUFFER_CAST (dec->queued->data); /* iterate ouput queue an push downstream */ res = gst_pad_push (dec->srcpad, buf); dec->queued = g_list_delete_link (dec->queued, dec->queued); } return res; }
GstFlowReturn gst_vdp_output_src_pad_push (GstVdpOutputSrcPad * vdp_pad, GstVdpOutputBuffer * output_buf, GError ** error) { GstPad *pad; GstBuffer *outbuf; g_return_val_if_fail (GST_IS_VDP_OUTPUT_SRC_PAD (vdp_pad), GST_FLOW_ERROR); g_return_val_if_fail (GST_IS_VDP_OUTPUT_BUFFER (output_buf), GST_FLOW_ERROR); pad = (GstPad *) vdp_pad; if (G_UNLIKELY (!GST_PAD_CAPS (pad))) return GST_FLOW_NOT_NEGOTIATED; switch (vdp_pad->output_format) { case GST_VDP_OUTPUT_SRC_PAD_FORMAT_RGB: { GstFlowReturn ret; guint size; gst_vdp_output_buffer_calculate_size (output_buf, &size); vdp_pad->lock_caps = TRUE; ret = gst_pad_alloc_buffer (pad, 0, size, GST_PAD_CAPS (vdp_pad), &outbuf); vdp_pad->lock_caps = FALSE; if (ret != GST_FLOW_OK) { gst_buffer_unref (GST_BUFFER_CAST (output_buf)); return ret; } if (!gst_vdp_output_buffer_download (output_buf, outbuf, error)) { gst_buffer_unref (GST_BUFFER_CAST (output_buf)); gst_buffer_unref (outbuf); return GST_FLOW_ERROR; } gst_buffer_copy_metadata (outbuf, (const GstBuffer *) output_buf, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS); gst_buffer_unref (GST_BUFFER_CAST (output_buf)); break; } case GST_VDP_OUTPUT_SRC_PAD_FORMAT_VDPAU: { outbuf = GST_BUFFER_CAST (output_buf); break; } default: g_assert_not_reached (); break; } gst_buffer_set_caps (outbuf, GST_PAD_CAPS (vdp_pad)); return gst_pad_push (pad, outbuf); }
static GstMozVideoBuffer* gst_moz_video_buffer_copy(GstMozVideoBuffer* self) { GstMozVideoBuffer* copy; g_return_val_if_fail(GST_IS_MOZ_VIDEO_BUFFER(self), NULL); copy = gst_moz_video_buffer_new(); /* we simply copy everything from our parent */ GST_BUFFER_DATA(GST_BUFFER_CAST(copy)) = (guint8*)g_memdup(GST_BUFFER_DATA(GST_BUFFER_CAST(self)), GST_BUFFER_SIZE(GST_BUFFER_CAST(self))); /* make sure it gets freed(even if the parent is subclassed, we return a normal buffer) */ GST_BUFFER_MALLOCDATA(GST_BUFFER_CAST(copy)) = GST_BUFFER_DATA(GST_BUFFER_CAST(copy)); GST_BUFFER_SIZE(GST_BUFFER_CAST(copy)) = GST_BUFFER_SIZE(GST_BUFFER_CAST(self)); /* copy metadata */ gst_buffer_copy_metadata(GST_BUFFER_CAST(copy), GST_BUFFER_CAST(self), (GstBufferCopyFlags)GST_BUFFER_COPY_ALL); /* copy videobuffer */ if(self->data) copy->data = (GstMozVideoBufferData*)g_boxed_copy(GST_TYPE_MOZ_VIDEO_BUFFER_DATA, self->data); return copy; }
static void my_recycle_buffer_finalize (GstMiniObject * mini_object) { GstBuffer *self = GST_BUFFER_CAST (mini_object); if (self->pool != NULL) { my_buffer_pool_add (self->pool, GST_BUFFER_CAST (self)); g_usleep (G_USEC_PER_SEC / 100); } else { GST_MINI_OBJECT_CLASS (my_recycle_buffer_parent_class)->finalize (mini_object); } }
static VdpBitstreamBuffer * gst_vdp_h264_dec_create_bitstream_buffers (GstVdpH264Dec * h264_dec, GstH264Frame * h264_frame, guint * n_bufs) { VdpBitstreamBuffer *bufs; if (h264_dec->packetized) { guint i; bufs = g_new (VdpBitstreamBuffer, h264_frame->slices->len * 2); *n_bufs = h264_frame->slices->len * 2; for (i = 0; i < h264_frame->slices->len; i++) { static const guint8 start_code[] = { 0x00, 0x00, 0x01 }; guint idx; GstBuffer *buf; idx = i * 2; bufs[idx].bitstream = start_code; bufs[idx].bitstream_bytes = 3; bufs[idx].struct_version = VDP_BITSTREAM_BUFFER_VERSION; idx = idx + 1; buf = GST_BUFFER_CAST (g_ptr_array_index (h264_frame->slices, i)); bufs[idx].bitstream = GST_BUFFER_DATA (buf) + h264_dec->nal_length_size; bufs[idx].bitstream_bytes = GST_BUFFER_SIZE (buf) - h264_dec->nal_length_size; bufs[idx].struct_version = VDP_BITSTREAM_BUFFER_VERSION; } } else { guint i; bufs = g_new (VdpBitstreamBuffer, h264_frame->slices->len); *n_bufs = h264_frame->slices->len; for (i = 0; i < h264_frame->slices->len; i++) { GstBuffer *buf; buf = GST_BUFFER_CAST (g_ptr_array_index (h264_frame->slices, i)); bufs[i].bitstream = GST_BUFFER_DATA (buf); bufs[i].bitstream_bytes = GST_BUFFER_SIZE (buf); bufs[i].struct_version = VDP_BITSTREAM_BUFFER_VERSION; } } return bufs; }
/** * gst_buffer_list_iterator_next: * @it: a #GstBufferListIterator * * Returns the next buffer in the list iterated with @it. If the iterator is at * the end of a group, NULL will be returned. This function may be called * repeatedly to iterate through the current group. * * The caller will not get a new ref to the returned #GstBuffer and must not * unref it. * * Returns: the next buffer in the current group of the buffer list, or NULL * * Since: 0.10.24 */ GstBuffer * gst_buffer_list_iterator_next (GstBufferListIterator * it) { GstBuffer *buffer; g_return_val_if_fail (it != NULL, NULL); while (it->next != NULL && it->next->data != GROUP_START && it->next->data == STOLEN) { it->next = g_list_next (it->next); } if (it->next == NULL || it->next->data == GROUP_START) { goto no_buffer; } buffer = GST_BUFFER_CAST (it->next->data); it->last_returned = it->next; it->next = g_list_next (it->next); return buffer; no_buffer: { it->last_returned = NULL; return NULL; } }
static GstFlowReturn theora_dec_chain_reverse (GstTheoraDec * dec, gboolean discont, GstBuffer * buf) { GstFlowReturn res = GST_FLOW_OK; /* if we have a discont, move buffers to the decode list */ if (G_UNLIKELY (discont)) { GST_DEBUG_OBJECT (dec, "received discont,gathering buffers"); while (dec->gather) { GstBuffer *gbuf; guint8 *data; gbuf = GST_BUFFER_CAST (dec->gather->data); /* remove from the gather list */ dec->gather = g_list_delete_link (dec->gather, dec->gather); /* copy to decode queue */ dec->decode = g_list_prepend (dec->decode, gbuf); /* if we copied a keyframe, flush and decode the decode queue */ data = GST_BUFFER_DATA (gbuf); if ((data[0] & 0x40) == 0) { GST_DEBUG_OBJECT (dec, "copied keyframe"); res = theora_dec_flush_decode (dec); } } } /* add buffer to gather queue */ GST_DEBUG_OBJECT (dec, "gathering buffer %p, size %u", buf, GST_BUFFER_SIZE (buf)); dec->gather = g_list_prepend (dec->gather, buf); return res; }
static GstFlowReturn gst_funnel_sink_chain_object (GstPad * pad, GstFunnel * funnel, gboolean is_list, GstMiniObject * obj) { GstFlowReturn res; GST_DEBUG_OBJECT (pad, "received %" GST_PTR_FORMAT, obj); GST_PAD_STREAM_LOCK (funnel->srcpad); if ((funnel->last_sinkpad == NULL) || ((funnel->forward_sticky_events_mode != GST_FUNNEL_FORWARD_STICKY_EVENTS_MODE_NEVER) && (funnel->last_sinkpad != pad))) { GST_DEBUG_OBJECT (pad, "Forwarding sticky events"); gst_pad_sticky_events_foreach (pad, forward_events_on_stream_changed, funnel); gst_object_replace ((GstObject **) & funnel->last_sinkpad, GST_OBJECT (pad)); } if (is_list) res = gst_pad_push_list (funnel->srcpad, GST_BUFFER_LIST_CAST (obj)); else res = gst_pad_push (funnel->srcpad, GST_BUFFER_CAST (obj)); GST_PAD_STREAM_UNLOCK (funnel->srcpad); GST_LOG_OBJECT (pad, "handled buffer%s %s", (is_list ? "list" : ""), gst_flow_get_name (res)); return res; }
static GstFlowReturn vorbis_dec_chain_reverse (GstVorbisDec * vd, gboolean discont, GstBuffer * buf) { GstFlowReturn result = GST_FLOW_OK; /* if we have a discont, move buffers to the decode list */ if (G_UNLIKELY (discont)) { GST_DEBUG_OBJECT (vd, "received discont"); while (vd->gather) { GstBuffer *gbuf; gbuf = GST_BUFFER_CAST (vd->gather->data); /* remove from the gather list */ vd->gather = g_list_delete_link (vd->gather, vd->gather); /* copy to decode queue */ vd->decode = g_list_prepend (vd->decode, gbuf); } /* flush and decode the decode queue */ result = vorbis_dec_flush_decode (vd); } if (G_LIKELY (buf)) { GST_DEBUG_OBJECT (vd, "gathering buffer %p of size %u, time %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, buf, GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); /* add buffer to gather queue */ vd->gather = g_list_prepend (vd->gather, buf); } return result; }
/** * rtp_jitter_buffer_insert: * @jbuf: an #RTPJitterBuffer * @buf: a buffer * @time: a running_time when this buffer was received in nanoseconds * @clock_rate: the clock-rate of the payload of @buf * @max_delay: the maximum lateness of @buf * @tail: TRUE when the tail element changed. * * Inserts @buf into the packet queue of @jbuf. The sequence number of the * packet will be used to sort the packets. This function takes ownerhip of * @buf when the function returns %TRUE. * @buf should have writable metadata when calling this function. * * Returns: %FALSE if a packet with the same number already existed. */ gboolean rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, GstBuffer * buf, GstClockTime time, guint32 clock_rate, GstClockTime max_delay, gboolean * tail) { GList *list; guint32 rtptime; guint16 seqnum; g_return_val_if_fail (jbuf != NULL, FALSE); g_return_val_if_fail (buf != NULL, FALSE); seqnum = gst_rtp_buffer_get_seq (buf); /* loop the list to skip strictly smaller seqnum buffers */ for (list = jbuf->packets->head; list; list = g_list_next (list)) { guint16 qseq; gint gap; qseq = gst_rtp_buffer_get_seq (GST_BUFFER_CAST (list->data)); /* compare the new seqnum to the one in the buffer */ gap = gst_rtp_buffer_compare_seqnum (seqnum, qseq); /* we hit a packet with the same seqnum, notify a duplicate */ if (G_UNLIKELY (gap == 0)) goto duplicate; /* seqnum > qseq, we can stop looking */ if (G_LIKELY (gap < 0)) break; } /* do skew calculation by measuring the difference between rtptime and the * receive time, this function will retimestamp @buf with the skew corrected * running time. */ rtptime = gst_rtp_buffer_get_timestamp (buf); time = calculate_skew (jbuf, rtptime, time, clock_rate, max_delay); GST_BUFFER_TIMESTAMP (buf) = time; /* It's more likely that the packet was inserted in the front of the buffer */ if (G_LIKELY (list)) g_queue_insert_before (jbuf->packets, list, buf); else g_queue_push_tail (jbuf->packets, buf); /* tail was changed when we did not find a previous packet, we set the return * flag when requested. */ if (G_LIKELY (tail)) *tail = (list == NULL); return TRUE; /* ERRORS */ duplicate: { GST_WARNING ("duplicate packet %d found", (gint) seqnum); return FALSE; } }
gboolean shmdata_base_reader_reset_time (GstPad *pad, GstMiniObject * mini_obj, gpointer user_data) { shmdata_base_reader_t *context = (shmdata_base_reader_t *) user_data; if (GST_IS_EVENT (mini_obj)) { //g_debug ("EVENT %s", GST_EVENT_TYPE_NAME (GST_EVENT_CAST(mini_obj))); } else if (GST_IS_BUFFER (mini_obj)) { GstBuffer *buffer = GST_BUFFER_CAST (mini_obj); /* g_debug ("shmdata writer data frame (%p), data size %d, timestamp %llu, caps %s", */ /* GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), */ /* GST_TIME_AS_MSECONDS (GST_BUFFER_TIMESTAMP (buffer)), */ /* gst_caps_to_string (GST_BUFFER_CAPS (buffer))); */ if (context->timereset_) { context->timeshift_ = GST_BUFFER_TIMESTAMP (buffer); context->timereset_ = FALSE; } GST_BUFFER_TIMESTAMP (buffer) = GST_BUFFER_TIMESTAMP (buffer) - context->timeshift_; } else if (GST_IS_MESSAGE (mini_obj)) { } return TRUE; }
static GstFlowReturn vorbis_parse_drain_queue (GstVorbisParse * parse, gint64 granulepos) { GstFlowReturn ret = GST_FLOW_OK; GList *walk; gint64 cur = granulepos; gint64 gp; for (walk = parse->buffer_queue->head; walk; walk = walk->next) cur -= GST_BUFFER_OFFSET (walk->data); if (parse->prev_granulepos != -1) cur = MAX (cur, parse->prev_granulepos); while (!g_queue_is_empty (parse->buffer_queue)) { GstBuffer *buf; buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue)); cur += GST_BUFFER_OFFSET (buf); gp = CLAMP (cur, 0, granulepos); ret = vorbis_parse_push_buffer (parse, buf, gp); if (ret != GST_FLOW_OK) goto done; } parse->prev_granulepos = granulepos; done: return ret; }
static gboolean gst_vdp_sink_stop (GstBaseSink * bsink) { VdpSink *vdp_sink = GST_VDP_SINK (bsink); vdp_sink->running = FALSE; /* Wait for our event thread to finish before we clean up our stuff. */ if (vdp_sink->event_thread) g_thread_join (vdp_sink->event_thread); if (vdp_sink->cur_image) { gst_buffer_unref (GST_BUFFER_CAST (vdp_sink->cur_image)); vdp_sink->cur_image = NULL; } g_mutex_lock (vdp_sink->flow_lock); if (vdp_sink->window) { gst_vdp_sink_window_destroy (vdp_sink, vdp_sink->window); vdp_sink->window = NULL; } g_mutex_unlock (vdp_sink->flow_lock); gst_vdp_device_clear (vdp_sink); return TRUE; }
static GstFlowReturn vorbis_parse_drain_queue_prematurely (GstVorbisParse * parse) { GstFlowReturn ret = GST_FLOW_OK; gint64 granulepos = MAX (parse->prev_granulepos, 0); /* got an EOS event, make sure to push out any buffers that were in the queue * -- won't normally be the case, but this catches the * didn't-get-a-granulepos-on-the-last-packet case. Assuming a continuous * stream. */ /* if we got EOS before any buffers came, go ahead and push the other events * first */ vorbis_parse_drain_event_queue (parse); while (!g_queue_is_empty (parse->buffer_queue)) { GstBuffer *buf; buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue)); granulepos += GST_BUFFER_OFFSET (buf); ret = vorbis_parse_push_buffer (parse, buf, granulepos); if (ret != GST_FLOW_OK) goto done; } parse->prev_granulepos = granulepos; done: return ret; }
/* * Input: * Buffer decoding order: 7 8 9 4 5 6 3 1 2 EOS * Discont flag: D D D D * * - Each Discont marks a discont in the decoding order. * * for vorbis, each buffer is a keyframe when we have the previous * buffer. This means that to decode buffer 7, we need buffer 6, which * arrives out of order. * * we first gather buffers in the gather queue until we get a DISCONT. We * prepend each incomming buffer so that they are in reversed order. * * gather queue: 9 8 7 * decode queue: * output queue: * * When a DISCONT is received (buffer 4), we move the gather queue to the * decode queue. This is simply done be taking the head of the gather queue * and prepending it to the decode queue. This yields: * * gather queue: * decode queue: 7 8 9 * output queue: * * Then we decode each buffer in the decode queue in order and put the output * buffer in the output queue. The first buffer (7) will not produce any output * because it needs the previous buffer (6) which did not arrive yet. This * yields: * * gather queue: * decode queue: 7 8 9 * output queue: 9 8 * * Then we remove the consumed buffers from the decode queue. Buffer 7 is not * completely consumed, we need to keep it around for when we receive buffer * 6. This yields: * * gather queue: * decode queue: 7 * output queue: 9 8 * * Then we accumulate more buffers: * * gather queue: 6 5 4 * decode queue: 7 * output queue: * * prepending to the decode queue on DISCONT yields: * * gather queue: * decode queue: 4 5 6 7 * output queue: * * after decoding and keeping buffer 4: * * gather queue: * decode queue: 4 * output queue: 7 6 5 * * Etc.. */ static GstFlowReturn vorbis_dec_flush_decode (GstVorbisDec * dec) { GstFlowReturn res = GST_FLOW_OK; GList *walk; walk = dec->decode; GST_DEBUG_OBJECT (dec, "flushing buffers to decoder"); while (walk) { GList *next; GstBuffer *buf = GST_BUFFER_CAST (walk->data); GST_DEBUG_OBJECT (dec, "decoding buffer %p, ts %" GST_TIME_FORMAT, buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); next = g_list_next (walk); /* decode buffer, prepend to output queue */ res = vorbis_dec_decode_buffer (dec, buf); /* if we generated output, we can discard the buffer, else we * keep it in the queue */ if (dec->queued) { GST_DEBUG_OBJECT (dec, "decoded buffer to %p", dec->queued->data); dec->decode = g_list_delete_link (dec->decode, walk); gst_buffer_unref (buf); } else { GST_DEBUG_OBJECT (dec, "buffer did not decode, keeping"); } walk = next; } while (dec->queued) { GstBuffer *buf = GST_BUFFER_CAST (dec->queued->data); GstClockTime timestamp, duration; timestamp = GST_BUFFER_TIMESTAMP (buf); duration = GST_BUFFER_DURATION (buf); vorbis_do_timestamps (dec, buf, TRUE, timestamp, duration); res = vorbis_dec_push_forward (dec, buf); dec->queued = g_list_delete_link (dec->queued, dec->queued); } return res; }
GstCaps * gst_type_find_helper_get_range (GstObject * obj, GstTypeFindHelperGetRangeFunction func, guint64 size, GstTypeFindProbability * prob) { GstTypeFindHelper helper; GstTypeFind find; GSList *walk; GList *l, *type_list; GstCaps *result = NULL; g_return_val_if_fail (GST_IS_OBJECT (obj), NULL); g_return_val_if_fail (func != NULL, NULL); helper.buffers = NULL; helper.size = size; helper.last_offset = 0; helper.func = func; helper.best_probability = 0; helper.caps = NULL; helper.obj = obj; find.data = &helper; find.peek = helper_find_peek; find.suggest = helper_find_suggest; if (size == 0 || size == (guint64) - 1) { find.get_length = NULL; } else { find.get_length = helper_find_get_length; } /* FIXME: we need to keep this list within the registry */ type_list = gst_type_find_factory_get_list (); type_list = g_list_sort (type_list, type_find_factory_rank_cmp); for (l = type_list; l; l = l->next) { helper.factory = GST_TYPE_FIND_FACTORY (l->data); gst_type_find_factory_call_function (helper.factory, &find); if (helper.best_probability >= GST_TYPE_FIND_MAXIMUM) break; } gst_plugin_feature_list_free (type_list); for (walk = helper.buffers; walk; walk = walk->next) gst_buffer_unref (GST_BUFFER_CAST (walk->data)); g_slist_free (helper.buffers); if (helper.best_probability > 0) result = helper.caps; if (prob) *prob = helper.best_probability; GST_LOG_OBJECT (obj, "Returning %" GST_PTR_FORMAT " (probability = %u)", result, (guint) helper.best_probability); return result; }
static gboolean handle_queued_objects (APP_STATE_T * state) { GstMiniObject *object = NULL; g_mutex_lock (&state->queue_lock); if (state->flushing) { g_cond_broadcast (&state->cond); goto beach; } else if (g_async_queue_length (state->queue) == 0) { goto beach; } if ((object = g_async_queue_try_pop (state->queue))) { if (GST_IS_BUFFER (object)) { GstBuffer *buffer = GST_BUFFER_CAST (object); update_image (state, buffer); render_scene (state); gst_buffer_unref (buffer); if (!SYNC_BUFFERS) { object = NULL; } } else if (GST_IS_QUERY (object)) { GstQuery *query = GST_QUERY_CAST (object); GstStructure *s = (GstStructure *) gst_query_get_structure (query); if (gst_structure_has_name (s, "not-used")) { g_assert_not_reached (); } else { g_assert_not_reached (); } } else if (GST_IS_EVENT (object)) { GstEvent *event = GST_EVENT_CAST (object); g_print ("\nevent %p %s\n", event, gst_event_type_get_name (GST_EVENT_TYPE (event))); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: flush_internal (state); break; default: break; } gst_event_unref (event); object = NULL; } } if (object) { state->popped_obj = object; g_cond_broadcast (&state->cond); } beach: g_mutex_unlock (&state->queue_lock); return FALSE; }
static GstFlowReturn theora_parse_drain_queue (GstTheoraParse * parse, gint64 granulepos) { GstFlowReturn ret = GST_FLOW_OK; gint64 keyframe, prev_frame, frame; parse_granulepos (parse, granulepos, &keyframe, &frame); GST_DEBUG ("draining queue of length %d", g_queue_get_length (parse->buffer_queue)); GST_LOG_OBJECT (parse, "gp %" G_GINT64_FORMAT ", kf %" G_GINT64_FORMAT ", frame %" G_GINT64_FORMAT, granulepos, keyframe, frame); prev_frame = frame - g_queue_get_length (parse->buffer_queue); GST_LOG_OBJECT (parse, "new prev %" G_GINT64_FORMAT ", prev %" G_GINT64_FORMAT, prev_frame, parse->prev_frame); if (prev_frame < parse->prev_frame) { GST_WARNING ("jumped %" G_GINT64_FORMAT " frames backwards! not sure what to do here", parse->prev_frame - prev_frame); parse->prev_frame = prev_frame; } else if (prev_frame > parse->prev_frame) { GST_INFO ("discontinuity detected (%" G_GINT64_FORMAT " frames)", prev_frame - parse->prev_frame); if (keyframe <= prev_frame && keyframe > parse->prev_keyframe) parse->prev_keyframe = keyframe; parse->prev_frame = prev_frame; } while (!g_queue_is_empty (parse->buffer_queue)) { GstBuffer *buf; parse->prev_frame++; g_assert (parse->prev_frame >= 0); buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue)); if (is_keyframe (buf)) /* we have a keyframe */ parse->prev_keyframe = parse->prev_frame; else GST_BUFFER_FLAGS (buf) |= GST_BUFFER_FLAG_DELTA_UNIT; ret = theora_parse_push_buffer (parse, buf, parse->prev_keyframe, parse->prev_frame); if (ret != GST_FLOW_OK) goto done; } done: return ret; }
static gboolean scan_slow (GstAdapter * adapter, GSList * g, int skip, guint32 pattern, guint32 mask) { guint8 tmp[4]; int j; pattern &= mask; for (j = 0; j < 4; j++) { tmp[j] = ((guint8 *) GST_BUFFER_DATA (GST_BUFFER_CAST (g->data)))[skip]; skip++; if (skip >= GST_BUFFER_SIZE (GST_BUFFER_CAST (g->data))) { g = g->next; skip = 0; } } return ((GST_READ_UINT32_BE (tmp) & mask) == pattern); }
static GstBuffer * my_recycle_buffer_new (MyBufferPool * pool) { MyRecycleBuffer *buf; buf = MY_RECYCLE_BUFFER (gst_mini_object_new (MY_TYPE_RECYCLE_BUFFER)); buf->pool = pool; return GST_BUFFER_CAST (buf); }
static GstBuffer * my_recycle_buffer_new (MyBufferPool * pool) { GstBuffer *buf; buf = gst_buffer_new (); //buf->pool = pool; return GST_BUFFER_CAST (buf); }
static GstFlowReturn gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstGLImageSink *glimage_sink = NULL; GstGLBuffer *gl_buffer = NULL; glimage_sink = GST_GLIMAGE_SINK (bsink); GST_INFO ("buffer size: %d", GST_BUFFER_SIZE (buf)); //is gl if (glimage_sink->is_gl) { //increment gl buffer ref before storage gl_buffer = GST_GL_BUFFER (gst_buffer_ref (buf)); } //is not gl else { //blocking call gl_buffer = gst_gl_buffer_new (glimage_sink->display, glimage_sink->width, glimage_sink->height); //blocking call gst_gl_display_do_upload (glimage_sink->display, gl_buffer->texture, glimage_sink->width, glimage_sink->height, GST_BUFFER_DATA (buf)); //gl_buffer is created in this block, so the gl buffer is already referenced } if (glimage_sink->window_id != glimage_sink->new_window_id) { glimage_sink->window_id = glimage_sink->new_window_id; gst_gl_display_set_window_id (glimage_sink->display, glimage_sink->window_id); } //the buffer is cleared when an other comes in if (glimage_sink->stored_buffer) { gst_buffer_unref (GST_BUFFER_CAST (glimage_sink->stored_buffer)); glimage_sink->stored_buffer = NULL; } //store current buffer glimage_sink->stored_buffer = gl_buffer; //redisplay opengl scene if (gl_buffer->texture && gst_gl_display_redisplay (glimage_sink->display, gl_buffer->texture, gl_buffer->width, gl_buffer->height, glimage_sink->window_width, glimage_sink->window_height, glimage_sink->keep_aspect_ratio)) return GST_FLOW_OK; else { GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND, GST_GL_DISPLAY_ERR_MSG (glimage_sink->display), (NULL)); return GST_FLOW_ERROR; } }
int gst_adapter_masked_scan_uint32_compat (GstAdapter * adapter, guint32 mask, guint32 pattern, guint offset, guint n) { GSList *g; int j; int k; int skip; int m; g_return_val_if_fail (n >= 0, -1); g_return_val_if_fail (offset >= 0, -1); g_return_val_if_fail (offset + n + 4 <= adapter->size, -1); g = get_chunk (adapter, offset, &skip); j = 0; while (j < n) { m = MIN (GST_BUFFER_SIZE (GST_BUFFER_CAST (g->data)) - skip - 4, 0); if (m > 0) { k = scan_fast (GST_BUFFER_DATA (GST_BUFFER_CAST (g->data)) + skip, pattern, mask, m); if (k < m) { return offset + j + k; } j += m; skip += m; } else { if (scan_slow (adapter, g, skip, pattern, mask)) { return offset + j; } j++; skip++; } if (skip >= GST_BUFFER_SIZE (GST_BUFFER_CAST (g->data))) { g = g->next; skip = 0; } } return -1; }
static gboolean gst_gl_deinterlace_filter (GstGLFilter * filter, GstGLBuffer * inbuf, GstGLBuffer * outbuf) { GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter); //blocking call, use a FBO gst_gl_display_use_fbo (filter->display, filter->width, filter->height, filter->fbo, filter->depthbuffer, outbuf->texture, gst_gl_deinterlace_callback, inbuf->width, inbuf->height, inbuf->texture, 0, filter->width, 0, filter->height, GST_GL_DISPLAY_PROJECTION_ORTHO2D, (gpointer) deinterlace_filter); if (deinterlace_filter->gl_buffer_prev) gst_buffer_unref (GST_BUFFER_CAST (deinterlace_filter->gl_buffer_prev)); deinterlace_filter->gl_buffer_prev = GST_GL_BUFFER (gst_buffer_ref (GST_BUFFER_CAST (inbuf))); return TRUE; }
static void gst_gl_deinterlace_reset (GstGLFilter * filter) { GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter); if (deinterlace_filter->gl_buffer_prev) { gst_buffer_unref (GST_BUFFER_CAST (deinterlace_filter->gl_buffer_prev)); deinterlace_filter->gl_buffer_prev = NULL; } //blocking call, wait the opengl thread has destroyed the shader gst_gl_display_del_shader (filter->display, deinterlace_filter->shader); }
void QGstXvImageBufferPool::doAlloc() { //should be always called from the main thread with m_poolMutex locked //Q_ASSERT(QThread::currentThread() == thread()); XSync(QX11Info::display(), false); QGstXvImageBuffer *xvBuffer = (QGstXvImageBuffer *)gst_mini_object_new(QGstXvImageBuffer::get_type()); quint64 portId = m_format.property("portId").toULongLong(); int xvFormatId = m_format.property("xvFormatId").toInt(); xvBuffer->xvImage = XvShmCreateImage( QX11Info::display(), portId, xvFormatId, 0, m_format.frameWidth(), m_format.frameHeight(), &xvBuffer->shmInfo ); if (!xvBuffer->xvImage) { qWarning() << "QGstXvImageBufferPool: XvShmCreateImage failed"; return; } XSync(QX11Info::display(), false); xvBuffer->shmInfo.shmid = shmget(IPC_PRIVATE, xvBuffer->xvImage->data_size, IPC_CREAT | 0777); xvBuffer->shmInfo.shmaddr = xvBuffer->xvImage->data = (char*)shmat(xvBuffer->shmInfo.shmid, 0, 0); xvBuffer->shmInfo.readOnly = False; if (!XShmAttach(QX11Info::display(), &xvBuffer->shmInfo)) { qWarning() << "QGstXvImageBufferPool: XShmAttach failed"; return; } XSync(QX11Info::display(), false); shmctl (xvBuffer->shmInfo.shmid, IPC_RMID, NULL); xvBuffer->pool = this; GST_MINI_OBJECT_CAST(xvBuffer)->flags = 0; gst_buffer_set_caps(GST_BUFFER_CAST(xvBuffer), m_caps); GST_BUFFER_DATA(xvBuffer) = (uchar*)xvBuffer->xvImage->data; GST_BUFFER_SIZE(xvBuffer) = xvBuffer->xvImage->data_size; m_allBuffers.append(xvBuffer); m_pool.append(xvBuffer); XSync(QX11Info::display(), false); }
static GstFlowReturn theora_parse_drain_queue_prematurely (GstTheoraParse * parse) { GstFlowReturn ret = GST_FLOW_OK; /* got an EOS event, make sure to push out any buffers that were in the queue * -- won't normally be the case, but this catches the * didn't-get-a-granulepos-on-the-last-packet case. Assuming a continuous * stream. */ GST_DEBUG_OBJECT (parse, "got EOS, draining queue"); /* if we get an eos before pushing the streamheaders, drain our events before * eos */ theora_parse_drain_event_queue (parse); while (!g_queue_is_empty (parse->buffer_queue)) { GstBuffer *buf; buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue)); parse->prev_frame++; if (is_keyframe (buf)) /* we have a keyframe */ parse->prev_keyframe = parse->prev_frame; else GST_BUFFER_FLAGS (buf) |= GST_BUFFER_FLAG_DELTA_UNIT; if (parse->prev_keyframe < 0) { if (GST_BUFFER_OFFSET_END_IS_VALID (buf)) { parse_granulepos (parse, GST_BUFFER_OFFSET_END (buf), &parse->prev_keyframe, NULL); } else { /* No previous keyframe known; can't extract one from this frame. That * means we can't do any valid output for this frame, just continue to * the next frame. */ gst_buffer_unref (buf); continue; } } ret = theora_parse_push_buffer (parse, buf, parse->prev_keyframe, parse->prev_frame); if (ret != GST_FLOW_OK) goto done; } done: return ret; }
static gboolean on_video_sink_data_flow (GstPad * pad, GstMiniObject * mini_obj, gpointer user_data) { GstFPSDisplaySink *self = GST_FPS_DISPLAY_SINK (user_data); #if 0 if (GST_IS_BUFFER (mini_obj)) { GstBuffer *buf = GST_BUFFER_CAST (mini_obj); if (GST_CLOCK_TIME_IS_VALID (self->next_ts)) { if (GST_BUFFER_TIMESTAMP (buf) <= self->next_ts) { self->frames_rendered++; } else { GST_WARNING_OBJECT (self, "dropping frame : ts %" GST_TIME_FORMAT " < expected_ts %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_ARGS (self->next_ts)); self->frames_dropped++; } } else { self->frames_rendered++; } } else #endif if (GST_IS_EVENT (mini_obj)) { GstEvent *ev = GST_EVENT_CAST (mini_obj); if (GST_EVENT_TYPE (ev) == GST_EVENT_QOS) { GstClockTimeDiff diff; GstClockTime ts; gst_event_parse_qos (ev, NULL, &diff, &ts); if (diff <= 0.0) { g_atomic_int_inc (&self->frames_rendered); } else { g_atomic_int_inc (&self->frames_dropped); } ts = gst_util_get_timestamp (); if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (self->start_ts))) { self->interval_ts = self->last_ts = self->start_ts = ts; } if (GST_CLOCK_DIFF (self->interval_ts, ts) > self->fps_update_interval) { display_current_fps (self); self->interval_ts = ts; } } } return TRUE; }
static void theora_parse_clear_queue (GstTheoraParse * parse) { while (parse->buffer_queue->length) { GstBuffer *buf; buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue)); gst_buffer_unref (buf); } while (parse->event_queue->length) { GstEvent *event; event = GST_EVENT_CAST (g_queue_pop_head (parse->event_queue)); gst_event_unref (event); } }