static GstFlowReturn gst_flac_dec_handle_frame (GstAudioDecoder * audio_dec, GstBuffer * buf) { GstFlacDec *dec; dec = GST_FLAC_DEC (audio_dec); /* drain remaining data? */ if (G_UNLIKELY (buf == NULL)) { gst_flac_dec_flush (audio_dec, FALSE); return GST_FLOW_OK; } GST_LOG_OBJECT (dec, "frame: ts %" GST_TIME_FORMAT ", flags 0x%04x, " "%" G_GSIZE_FORMAT " bytes", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_FLAGS (buf), gst_buffer_get_size (buf)); /* drop any in-stream headers, we've processed those in set_format already */ if (G_UNLIKELY (!dec->got_headers)) { gboolean got_audio_frame; GstMapInfo map; /* check if this is a flac audio frame (rather than a header or junk) */ gst_buffer_map (buf, &map, GST_MAP_READ); got_audio_frame = gst_flac_dec_scan_got_frame (dec, map.data, map.size, NULL); gst_buffer_unmap (buf, &map); if (!got_audio_frame) { GST_INFO_OBJECT (dec, "dropping in-stream header, %" G_GSIZE_FORMAT " " "bytes", map.size); gst_audio_decoder_finish_frame (audio_dec, NULL, 1); return GST_FLOW_OK; } GST_INFO_OBJECT (dec, "first audio frame, got all in-stream headers now"); dec->got_headers = TRUE; } gst_adapter_push (dec->adapter, gst_buffer_ref (buf)); buf = NULL; dec->last_flow = GST_FLOW_OK; /* framed - there should always be enough data to decode something */ GST_LOG_OBJECT (dec, "%" G_GSIZE_FORMAT " bytes available", gst_adapter_available (dec->adapter)); if (!FLAC__stream_decoder_process_single (dec->decoder)) { GST_INFO_OBJECT (dec, "process_single failed"); } return dec->last_flow; }
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 void default_reset_buffer (GstBufferPool * pool, GstBuffer * buffer) { GST_BUFFER_FLAGS (buffer) = 0; GST_BUFFER_PTS (buffer) = GST_CLOCK_TIME_NONE; GST_BUFFER_DTS (buffer) = GST_CLOCK_TIME_NONE; GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE; GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE; GST_BUFFER_OFFSET_END (buffer) = GST_BUFFER_OFFSET_NONE; /* remove all metadata without the POOLED flag */ gst_buffer_foreach_meta (buffer, remove_meta_unpooled, pool); }
static void gst_identity_update_last_message_for_buffer (GstIdentity * identity, const gchar * action, GstBuffer * buf, gsize size) { gchar dts_str[64], pts_str[64], dur_str[64]; gchar flag_str[100]; GST_OBJECT_LOCK (identity); { const char *flag_list[] = { "", "", "", "", "live", "decode-only", "discont", "resync", "corrupted", "marker", "header", "gap", "droppable", "delta-unit", "tag-memory", "FIXME" }; int i; char *end = flag_str; end[0] = '\0'; for (i = 0; i < G_N_ELEMENTS (flag_list); i++) { if (GST_MINI_OBJECT_CAST (buf)->flags & (1 << i)) { strcpy (end, flag_list[i]); end += strlen (end); end[0] = ' '; end[1] = '\0'; end++; } } } g_free (identity->last_message); identity->last_message = g_strdup_printf ("%s ******* (%s:%s) " "(%" G_GSIZE_FORMAT " bytes, dts: %s, pts:%s, duration: %s, offset: %" G_GINT64_FORMAT ", " "offset_end: % " G_GINT64_FORMAT ", flags: %08x %s) %p", action, GST_DEBUG_PAD_NAME (GST_BASE_TRANSFORM_CAST (identity)->sinkpad), size, print_pretty_time (dts_str, sizeof (dts_str), GST_BUFFER_DTS (buf)), print_pretty_time (pts_str, sizeof (pts_str), GST_BUFFER_PTS (buf)), print_pretty_time (dur_str, sizeof (dur_str), GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), flag_str, buf); GST_OBJECT_UNLOCK (identity); gst_identity_notify_last_message (identity); }
static void do_buffer_stats (GstStatsTracer * self, GstPad * this_pad, GstPadStats * this_pad_stats, GstPad * that_pad, GstPadStats * that_pad_stats, GstBuffer * buf, GstClockTime elapsed) { GstElement *this_elem = get_real_pad_parent (this_pad); GstElementStats *this_elem_stats = get_element_stats (self, this_elem); GstElement *that_elem = get_real_pad_parent (that_pad); GstElementStats *that_elem_stats = get_element_stats (self, that_elem); GstClockTime pts = GST_BUFFER_PTS (buf); GstClockTime dts = GST_BUFFER_DTS (buf); GstClockTime dur = GST_BUFFER_DURATION (buf); gst_tracer_record_log (tr_buffer, (guint64) (guintptr) g_thread_self (), elapsed, this_pad_stats->index, this_elem_stats->index, that_pad_stats->index, that_elem_stats->index, gst_buffer_get_size (buf), GST_CLOCK_TIME_IS_VALID (pts), pts, GST_CLOCK_TIME_IS_VALID (dts), dts, GST_CLOCK_TIME_IS_VALID (dur), dur, GST_BUFFER_FLAGS (buf)); }
static void gst_identity_update_last_message_for_buffer (GstIdentity * identity, const gchar * action, GstBuffer * buf) { gchar ts_str[64], dur_str[64]; GST_OBJECT_LOCK (identity); g_free (identity->last_message); identity->last_message = g_strdup_printf ("%s ******* (%s:%s)i " "(%u bytes, timestamp: %s, duration: %s, offset: %" G_GINT64_FORMAT ", " "offset_end: % " G_GINT64_FORMAT ", flags: %d) %p", action, GST_DEBUG_PAD_NAME (GST_BASE_TRANSFORM_CAST (identity)->sinkpad), GST_BUFFER_SIZE (buf), print_pretty_time (ts_str, sizeof (ts_str), GST_BUFFER_TIMESTAMP (buf)), print_pretty_time (dur_str, sizeof (dur_str), GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf); GST_OBJECT_UNLOCK (identity); gst_identity_notify_last_message (identity); }
static void gst_compare_meta (GstCompare * comp, GstBuffer * buf1, GstCaps * caps1, GstBuffer * buf2, GstCaps * caps2) { gint flags = 0; if (comp->meta & GST_BUFFER_COPY_FLAGS) { if (GST_BUFFER_FLAGS (buf1) != GST_BUFFER_FLAGS (buf2)) { flags |= GST_BUFFER_COPY_FLAGS; GST_DEBUG_OBJECT (comp, "flags %d != flags %d", GST_BUFFER_FLAGS (buf1), GST_BUFFER_FLAGS (buf2)); } } if (comp->meta & GST_BUFFER_COPY_TIMESTAMPS) { if (GST_BUFFER_TIMESTAMP (buf1) != GST_BUFFER_TIMESTAMP (buf2)) { flags |= GST_BUFFER_COPY_TIMESTAMPS; GST_DEBUG_OBJECT (comp, "ts %" GST_TIME_FORMAT " != ts %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf1)), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf2))); } if (GST_BUFFER_DURATION (buf1) != GST_BUFFER_DURATION (buf2)) { flags |= GST_BUFFER_COPY_TIMESTAMPS; GST_DEBUG_OBJECT (comp, "dur %" GST_TIME_FORMAT " != dur %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_DURATION (buf1)), GST_TIME_ARGS (GST_BUFFER_DURATION (buf2))); } if (comp->offset_ts) { if (GST_BUFFER_OFFSET (buf1) != GST_BUFFER_OFFSET (buf2)) { flags |= GST_BUFFER_COPY_TIMESTAMPS; GST_DEBUG_OBJECT (comp, "offset %" G_GINT64_FORMAT " != offset %" G_GINT64_FORMAT, GST_BUFFER_OFFSET (buf1), GST_BUFFER_OFFSET (buf2)); } if (GST_BUFFER_OFFSET_END (buf1) != GST_BUFFER_OFFSET_END (buf2)) { flags |= GST_BUFFER_COPY_TIMESTAMPS; GST_DEBUG_OBJECT (comp, "offset_end %" G_GINT64_FORMAT " != offset_end %" G_GINT64_FORMAT, GST_BUFFER_OFFSET_END (buf1), GST_BUFFER_OFFSET_END (buf2)); } } } #if 0 /* FIXME ?? */ if (comp->meta & GST_BUFFER_COPY_CAPS) { if (!gst_caps_is_equal (caps1, caps2)) { flags |= GST_BUFFER_COPY_CAPS; GST_DEBUG_OBJECT (comp, "caps %" GST_PTR_FORMAT " != caps %" GST_PTR_FORMAT, caps1, caps2); } } #endif /* signal mismatch by debug and message */ if (flags) { GST_WARNING_OBJECT (comp, "buffers %p and %p failed metadata match %d", buf1, buf2, flags); gst_element_post_message (GST_ELEMENT (comp), gst_message_new_element (GST_OBJECT (comp), gst_structure_new ("delta", "meta", G_TYPE_INT, flags, NULL))); } }
static GstFlowReturn gst_identity_transform_ip (GstBaseTransform * trans, GstBuffer * buf) { GstFlowReturn ret = GST_FLOW_OK; GstIdentity *identity = GST_IDENTITY (trans); GstClockTime runtimestamp = G_GINT64_CONSTANT (0); if (identity->check_perfect) gst_identity_check_perfect (identity, buf); if (identity->check_imperfect_timestamp) gst_identity_check_imperfect_timestamp (identity, buf); if (identity->check_imperfect_offset) gst_identity_check_imperfect_offset (identity, buf); /* update prev values */ identity->prev_timestamp = GST_BUFFER_TIMESTAMP (buf); identity->prev_duration = GST_BUFFER_DURATION (buf); identity->prev_offset_end = GST_BUFFER_OFFSET_END (buf); identity->prev_offset = GST_BUFFER_OFFSET (buf); if (identity->error_after >= 0) { identity->error_after--; if (identity->error_after == 0) { GST_ELEMENT_ERROR (identity, CORE, FAILED, (_("Failed after iterations as requested.")), (NULL)); return GST_FLOW_ERROR; } } if (identity->drop_probability > 0.0) { if ((gfloat) (1.0 * rand () / (RAND_MAX)) < identity->drop_probability) { if (!identity->silent) { GST_OBJECT_LOCK (identity); g_free (identity->last_message); identity->last_message = g_strdup_printf ("dropping ******* (%s:%s)i (%d bytes, timestamp: %" GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %" G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p", GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf); GST_OBJECT_UNLOCK (identity); g_object_notify (G_OBJECT (identity), "last-message"); } /* return DROPPED to basetransform. */ return GST_BASE_TRANSFORM_FLOW_DROPPED; } } if (identity->dump) { gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); } if (!identity->silent) { GST_OBJECT_LOCK (identity); g_free (identity->last_message); identity->last_message = g_strdup_printf ("chain ******* (%s:%s)i (%d bytes, timestamp: %" GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %" G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p", GST_DEBUG_PAD_NAME (trans->sinkpad), GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf); GST_OBJECT_UNLOCK (identity); g_object_notify (G_OBJECT (identity), "last-message"); } if (identity->datarate > 0) { GstClockTime time = gst_util_uint64_scale_int (identity->offset, GST_SECOND, identity->datarate); GST_BUFFER_TIMESTAMP (buf) = time; GST_BUFFER_DURATION (buf) = GST_BUFFER_SIZE (buf) * GST_SECOND / identity->datarate; } if (identity->signal_handoffs) g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0, buf); if (trans->segment.format == GST_FORMAT_TIME) runtimestamp = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf)); if ((identity->sync) && (trans->segment.format == GST_FORMAT_TIME)) { GstClock *clock; GST_OBJECT_LOCK (identity); if ((clock = GST_ELEMENT (identity)->clock)) { GstClockReturn cret; GstClockTime timestamp; timestamp = runtimestamp + GST_ELEMENT (identity)->base_time; /* save id if we need to unlock */ /* FIXME: actually unlock this somewhere in the state changes */ identity->clock_id = gst_clock_new_single_shot_id (clock, timestamp); GST_OBJECT_UNLOCK (identity); cret = gst_clock_id_wait (identity->clock_id, NULL); GST_OBJECT_LOCK (identity); if (identity->clock_id) { gst_clock_id_unref (identity->clock_id); identity->clock_id = NULL; } if (cret == GST_CLOCK_UNSCHEDULED) ret = GST_FLOW_UNEXPECTED; } GST_OBJECT_UNLOCK (identity); } identity->offset += GST_BUFFER_SIZE (buf); if (identity->sleep_time && ret == GST_FLOW_OK) g_usleep (identity->sleep_time); if (identity->single_segment && (trans->segment.format == GST_FORMAT_TIME) && (ret == GST_FLOW_OK)) { GST_BUFFER_TIMESTAMP (buf) = runtimestamp; GST_BUFFER_OFFSET (buf) = GST_CLOCK_TIME_NONE; GST_BUFFER_OFFSET_END (buf) = GST_CLOCK_TIME_NONE; } return ret; }
static GstFlowReturn gst_gdp_depay_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstGDPDepay *this; GstFlowReturn ret = GST_FLOW_OK; GstCaps *caps; GstBuffer *buf; GstEvent *event; guint available; this = GST_GDP_DEPAY (parent); /* On DISCONT, get rid of accumulated data. We assume a buffer after the * DISCONT contains (part of) a new valid header, if not we error because we * lost sync */ if (GST_BUFFER_IS_DISCONT (buffer)) { gst_adapter_clear (this->adapter); this->state = GST_GDP_DEPAY_STATE_HEADER; } gst_adapter_push (this->adapter, buffer); while (TRUE) { switch (this->state) { case GST_GDP_DEPAY_STATE_HEADER: { guint8 *header; /* collect a complete header, validate and store the header. Figure out * the payload length and switch to the PAYLOAD state */ available = gst_adapter_available (this->adapter); if (available < GST_DP_HEADER_LENGTH) goto done; GST_LOG_OBJECT (this, "reading GDP header from adapter"); header = gst_adapter_take (this->adapter, GST_DP_HEADER_LENGTH); if (!gst_dp_validate_header (GST_DP_HEADER_LENGTH, header)) { g_free (header); goto header_validate_error; } /* store types and payload length. Also store the header, which we need * to make the payload. */ this->payload_length = gst_dp_header_payload_length (header); this->payload_type = gst_dp_header_payload_type (header); /* free previous header and store new one. */ g_free (this->header); this->header = header; GST_LOG_OBJECT (this, "read GDP header, payload size %d, payload type %d, switching to state PAYLOAD", this->payload_length, this->payload_type); this->state = GST_GDP_DEPAY_STATE_PAYLOAD; break; } case GST_GDP_DEPAY_STATE_PAYLOAD: { /* in this state we wait for all the payload data to be available in the * adapter. Then we switch to the state where we actually process the * payload. */ available = gst_adapter_available (this->adapter); if (available < this->payload_length) goto done; /* change state based on type */ if (this->payload_type == GST_DP_PAYLOAD_BUFFER) { GST_LOG_OBJECT (this, "switching to state BUFFER"); this->state = GST_GDP_DEPAY_STATE_BUFFER; } else if (this->payload_type == GST_DP_PAYLOAD_CAPS) { GST_LOG_OBJECT (this, "switching to state CAPS"); this->state = GST_GDP_DEPAY_STATE_CAPS; } else if (this->payload_type >= GST_DP_PAYLOAD_EVENT_NONE) { GST_LOG_OBJECT (this, "switching to state EVENT"); this->state = GST_GDP_DEPAY_STATE_EVENT; } else { goto wrong_type; } if (this->payload_length) { const guint8 *data; gboolean res; data = gst_adapter_map (this->adapter, this->payload_length); res = gst_dp_validate_payload (GST_DP_HEADER_LENGTH, this->header, data); gst_adapter_unmap (this->adapter); if (!res) goto payload_validate_error; } break; } case GST_GDP_DEPAY_STATE_BUFFER: { /* if we receive a buffer without caps first, we error out */ if (!this->caps) goto no_caps; GST_LOG_OBJECT (this, "reading GDP buffer from adapter"); buf = gst_dp_buffer_from_header (GST_DP_HEADER_LENGTH, this->header); if (!buf) goto buffer_failed; /* now take the payload if there is any */ if (this->payload_length > 0) { GstMapInfo map; gst_buffer_map (buf, &map, GST_MAP_WRITE); gst_adapter_copy (this->adapter, map.data, 0, this->payload_length); gst_buffer_unmap (buf, &map); gst_adapter_flush (this->adapter, this->payload_length); } /* set caps and push */ GST_LOG_OBJECT (this, "deserialized buffer %p, pushing, timestamp %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT ", size %" G_GSIZE_FORMAT ", flags 0x%x", buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf), gst_buffer_get_size (buf), GST_BUFFER_FLAGS (buf)); ret = gst_pad_push (this->srcpad, buf); if (ret != GST_FLOW_OK) goto push_error; GST_LOG_OBJECT (this, "switching to state HEADER"); this->state = GST_GDP_DEPAY_STATE_HEADER; break; } case GST_GDP_DEPAY_STATE_CAPS: { guint8 *payload; /* take the payload of the caps */ GST_LOG_OBJECT (this, "reading GDP caps from adapter"); payload = gst_adapter_take (this->adapter, this->payload_length); caps = gst_dp_caps_from_packet (GST_DP_HEADER_LENGTH, this->header, payload); g_free (payload); if (!caps) goto caps_failed; GST_DEBUG_OBJECT (this, "deserialized caps %" GST_PTR_FORMAT, caps); gst_caps_replace (&(this->caps), caps); gst_pad_set_caps (this->srcpad, caps); /* drop the creation ref we still have */ gst_caps_unref (caps); GST_LOG_OBJECT (this, "switching to state HEADER"); this->state = GST_GDP_DEPAY_STATE_HEADER; break; } case GST_GDP_DEPAY_STATE_EVENT: { guint8 *payload; GST_LOG_OBJECT (this, "reading GDP event from adapter"); /* adapter doesn't like 0 length payload */ if (this->payload_length > 0) payload = gst_adapter_take (this->adapter, this->payload_length); else payload = NULL; event = gst_dp_event_from_packet (GST_DP_HEADER_LENGTH, this->header, payload); g_free (payload); if (!event) goto event_failed; GST_DEBUG_OBJECT (this, "deserialized event %p of type %s, pushing", event, gst_event_type_get_name (event->type)); gst_pad_push_event (this->srcpad, event); GST_LOG_OBJECT (this, "switching to state HEADER"); this->state = GST_GDP_DEPAY_STATE_HEADER; break; } } } done: return ret; /* ERRORS */ header_validate_error: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("GDP packet header does not validate")); ret = GST_FLOW_ERROR; goto done; } payload_validate_error: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("GDP packet payload does not validate")); ret = GST_FLOW_ERROR; goto done; } wrong_type: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("GDP packet header is of wrong type")); ret = GST_FLOW_ERROR; goto done; } no_caps: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("Received a buffer without first receiving caps")); ret = GST_FLOW_NOT_NEGOTIATED; goto done; } buffer_failed: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("could not create buffer from GDP packet")); ret = GST_FLOW_ERROR; goto done; } push_error: { GST_WARNING_OBJECT (this, "pushing depayloaded buffer returned %d", ret); goto done; } caps_failed: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("could not create caps from GDP packet")); ret = GST_FLOW_ERROR; goto done; } event_failed: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("could not create event from GDP packet")); ret = GST_FLOW_ERROR; goto done; } }
/** * gst_buffer_create_sub: * @parent: a #GstBuffer. * @offset: the offset into parent #GstBuffer at which the new sub-buffer * begins. * @size: the size of the new #GstBuffer sub-buffer, in bytes. * * Creates a sub-buffer from @parent at @offset and @size. * This sub-buffer uses the actual memory space of the parent buffer. * This function will copy the offset and timestamp fields when the * offset is 0. If not, they will be set to #GST_CLOCK_TIME_NONE and * #GST_BUFFER_OFFSET_NONE. * If @offset equals 0 and @size equals the total size of @buffer, the * duration and offset end fields are also copied. If not they will be set * to #GST_CLOCK_TIME_NONE and #GST_BUFFER_OFFSET_NONE. * * MT safe. * Returns: the new #GstBuffer. * Returns NULL if the arguments were invalid. */ GstBuffer * gst_buffer_create_sub (GstBuffer * buffer, guint offset, guint size) { GstSubBuffer *subbuffer; GstBuffer *parent; gboolean complete; g_return_val_if_fail (buffer != NULL, NULL); g_return_val_if_fail (buffer->mini_object.refcount > 0, NULL); g_return_val_if_fail (buffer->size >= offset + size, NULL); /* find real parent */ if (GST_IS_SUBBUFFER (buffer)) { parent = GST_SUBBUFFER_CAST (buffer)->parent; } else { parent = buffer; } gst_buffer_ref (parent); /* create the new buffer */ subbuffer = (GstSubBuffer *) gst_mini_object_new (_gst_subbuffer_type); subbuffer->parent = parent; GST_CAT_LOG (GST_CAT_BUFFER, "new subbuffer %p (parent %p)", subbuffer, parent); /* set the right values in the child */ GST_BUFFER_DATA (GST_BUFFER_CAST (subbuffer)) = buffer->data + offset; GST_BUFFER_SIZE (GST_BUFFER_CAST (subbuffer)) = size; if ((offset == 0) && (size == GST_BUFFER_SIZE (buffer))) { /* copy all the flags except IN_CAPS */ GST_BUFFER_FLAG_SET (subbuffer, GST_BUFFER_FLAGS (buffer)); GST_BUFFER_FLAG_UNSET (subbuffer, GST_BUFFER_FLAG_IN_CAPS); } else { /* copy only PREROLL & GAP flags */ GST_BUFFER_FLAG_SET (subbuffer, (GST_BUFFER_FLAGS (buffer) & (GST_BUFFER_FLAG_PREROLL | GST_BUFFER_FLAG_GAP))); } /* we can copy the timestamp and offset if the new buffer starts at * offset 0 */ if (offset == 0) { GST_BUFFER_TIMESTAMP (subbuffer) = GST_BUFFER_TIMESTAMP (buffer); GST_BUFFER_OFFSET (subbuffer) = GST_BUFFER_OFFSET (buffer); complete = (buffer->size == size); } else { GST_BUFFER_TIMESTAMP (subbuffer) = GST_CLOCK_TIME_NONE; GST_BUFFER_OFFSET (subbuffer) = GST_BUFFER_OFFSET_NONE; complete = FALSE; } if (complete) { GstCaps *caps; /* if we copied the complete buffer we can copy the duration, * offset_end and caps as well */ GST_BUFFER_DURATION (subbuffer) = GST_BUFFER_DURATION (buffer); GST_BUFFER_OFFSET_END (subbuffer) = GST_BUFFER_OFFSET_END (buffer); if ((caps = GST_BUFFER_CAPS (buffer))) gst_caps_ref (caps); GST_BUFFER_CAPS (subbuffer) = caps; } else { GST_BUFFER_DURATION (subbuffer) = GST_CLOCK_TIME_NONE; GST_BUFFER_OFFSET_END (subbuffer) = GST_BUFFER_OFFSET_NONE; GST_BUFFER_CAPS (subbuffer) = NULL; } return GST_BUFFER_CAST (subbuffer); }
gboolean gst_imx_blitter_set_input_frame(GstImxBlitter *blitter, GstBuffer *frame) { gboolean ret; GstImxPhysMemMeta *phys_mem_meta; GstImxBlitterClass *klass; g_assert(blitter != NULL); klass = GST_IMX_BLITTER_CLASS(G_OBJECT_GET_CLASS(blitter)); g_assert(klass->set_input_frame != NULL); if (frame == NULL) return klass->set_input_frame(blitter, NULL); phys_mem_meta = GST_IMX_PHYS_MEM_META_GET(frame); if ((phys_mem_meta == NULL) || (phys_mem_meta->phys_addr == 0)) { GstFlowReturn flow_ret; GstBuffer *internal_input_frame; /* No DMA memory present; the input frame needs to be copied to an internal input frame */ GST_TRACE_OBJECT(blitter, "input frame does not use DMA memory - copying input frame to internal frame"); { if (blitter->dma_bufferpool == NULL) { GST_TRACE_OBJECT(blitter, "need to create internal bufferpool"); /* DMA bufferpool does not exist yet - create it now, * so that it can in turn create the internal input frame */ GstCaps *caps = gst_video_info_to_caps(&(blitter->input_video_info)); blitter->dma_bufferpool = gst_imx_blitter_create_bufferpool( blitter, caps, blitter->input_video_info.size, 0, 0, NULL, NULL ); gst_caps_unref(caps); if (blitter->dma_bufferpool == NULL) { GST_ERROR_OBJECT(blitter, "failed to create internal bufferpool"); return FALSE; } } /* Future versions of this code may propose the internal bufferpool upstream; * hence the is_active check */ if (!gst_buffer_pool_is_active(blitter->dma_bufferpool)) gst_buffer_pool_set_active(blitter->dma_bufferpool, TRUE); } /* Create new internal input frame */ GST_TRACE_OBJECT(blitter, "acquiring buffer for internal input frame"); internal_input_frame = NULL; flow_ret = gst_buffer_pool_acquire_buffer(blitter->dma_bufferpool, &internal_input_frame, NULL); if (flow_ret != GST_FLOW_OK) { if (internal_input_frame != NULL) gst_buffer_unref(internal_input_frame); GST_ERROR_OBJECT(blitter, "error acquiring input frame buffer: %s", gst_pad_mode_get_name(flow_ret)); return FALSE; } /* Copy the input buffer's pixels to the internal input frame */ { GstVideoFrame input_vidframe, internal_input_vidframe; gst_video_frame_map(&input_vidframe, &(blitter->input_video_info), frame, GST_MAP_READ); gst_video_frame_map(&internal_input_vidframe, &(blitter->input_video_info), internal_input_frame, GST_MAP_WRITE); /* gst_video_frame_copy() makes sure stride and plane offset values from both frames are respected */ gst_video_frame_copy(&internal_input_vidframe, &input_vidframe); /* copy interlace flags */ GST_BUFFER_FLAGS(internal_input_frame) |= (GST_BUFFER_FLAGS(frame) & (GST_VIDEO_BUFFER_FLAG_INTERLACED | GST_VIDEO_BUFFER_FLAG_TFF | GST_VIDEO_BUFFER_FLAG_RFF | GST_VIDEO_BUFFER_FLAG_ONEFIELD)); gst_video_frame_unmap(&internal_input_vidframe); gst_video_frame_unmap(&input_vidframe); } ret = klass->set_input_frame(blitter, internal_input_frame); gst_buffer_unref(internal_input_frame); } else { GST_TRACE_OBJECT(blitter, "input frame uses DMA memory - setting it directly as input frame"); ret = klass->set_input_frame(blitter, frame); } return ret; }
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; } }
static GstFlowReturn gst_interlace_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstInterlace *interlace = GST_INTERLACE (parent); GstFlowReturn ret = GST_FLOW_OK; gint num_fields = 0; int current_fields; const PulldownFormat *format; GST_DEBUG ("Received buffer at %u:%02u:%02u:%09u", (guint) (GST_BUFFER_TIMESTAMP (buffer) / (GST_SECOND * 60 * 60)), (guint) ((GST_BUFFER_TIMESTAMP (buffer) / (GST_SECOND * 60)) % 60), (guint) ((GST_BUFFER_TIMESTAMP (buffer) / GST_SECOND) % 60), (guint) (GST_BUFFER_TIMESTAMP (buffer) % GST_SECOND)); GST_DEBUG ("duration %" GST_TIME_FORMAT " flags %04x %s %s %s", GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_FLAGS (buffer), (GST_BUFFER_FLAGS (buffer) & GST_VIDEO_BUFFER_FLAG_TFF) ? "tff" : "", (GST_BUFFER_FLAGS (buffer) & GST_VIDEO_BUFFER_FLAG_RFF) ? "rff" : "", (GST_BUFFER_FLAGS (buffer) & GST_VIDEO_BUFFER_FLAG_ONEFIELD) ? "onefield" : ""); if (GST_BUFFER_FLAGS (buffer) & GST_BUFFER_FLAG_DISCONT) { GST_DEBUG ("discont"); if (interlace->stored_frame) { gst_buffer_unref (interlace->stored_frame); } interlace->stored_frame = NULL; interlace->stored_fields = 0; if (interlace->top_field_first) { interlace->field_index = 0; } else { interlace->field_index = 1; } } if (interlace->timebase == GST_CLOCK_TIME_NONE) { /* get the initial ts */ interlace->timebase = GST_BUFFER_TIMESTAMP (buffer); } format = &formats[interlace->pattern]; if (interlace->stored_fields == 0 && interlace->phase_index == interlace->pattern_offset && GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) { interlace->timebase = GST_BUFFER_TIMESTAMP (buffer); interlace->fields_since_timebase = 0; } if (!format->n_fields[interlace->phase_index]) { interlace->phase_index = 0; } current_fields = format->n_fields[interlace->phase_index]; /* increment the phase index */ interlace->phase_index++; GST_DEBUG ("incoming buffer assigned %d fields", current_fields); num_fields = interlace->stored_fields + current_fields; while (num_fields >= 2) { GstBuffer *output_buffer; int n_output_fields; gboolean interlaced = FALSE; GST_DEBUG ("have %d fields, %d current, %d stored", num_fields, current_fields, interlace->stored_fields); if (interlace->stored_fields > 0) { GST_DEBUG ("1 field from stored, 1 from current"); output_buffer = gst_buffer_new_and_alloc (gst_buffer_get_size (buffer)); /* take the first field from the stored frame */ copy_field (interlace, output_buffer, interlace->stored_frame, interlace->field_index); interlace->stored_fields--; /* take the second field from the incoming buffer */ copy_field (interlace, output_buffer, buffer, interlace->field_index ^ 1); current_fields--; n_output_fields = 2; interlaced = TRUE; } else { output_buffer = gst_buffer_make_writable (gst_buffer_ref (buffer)); if (num_fields >= 3 && interlace->allow_rff) { GST_DEBUG ("3 fields from current"); /* take both fields from incoming buffer */ current_fields -= 3; n_output_fields = 3; } else { GST_DEBUG ("2 fields from current"); /* take both buffers from incoming buffer */ current_fields -= 2; n_output_fields = 2; } } num_fields -= n_output_fields; gst_interlace_decorate_buffer (interlace, output_buffer, n_output_fields, interlaced); interlace->fields_since_timebase += n_output_fields; interlace->field_index ^= (n_output_fields & 1); GST_DEBUG_OBJECT (interlace, "output timestamp %" GST_TIME_FORMAT " duration %" GST_TIME_FORMAT " flags %04x %s %s %s", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (output_buffer)), GST_TIME_ARGS (GST_BUFFER_DURATION (output_buffer)), GST_BUFFER_FLAGS (output_buffer), (GST_BUFFER_FLAGS (output_buffer) & GST_VIDEO_BUFFER_FLAG_TFF) ? "tff" : "", (GST_BUFFER_FLAGS (output_buffer) & GST_VIDEO_BUFFER_FLAG_RFF) ? "rff" : "", (GST_BUFFER_FLAGS (output_buffer) & GST_VIDEO_BUFFER_FLAG_ONEFIELD) ? "onefield" : ""); ret = gst_pad_push (interlace->srcpad, output_buffer); if (ret != GST_FLOW_OK) { GST_DEBUG_OBJECT (interlace, "Failed to push buffer %p", output_buffer); break; } } GST_DEBUG ("done. %d fields remaining", current_fields); if (interlace->stored_frame) { gst_buffer_unref (interlace->stored_frame); interlace->stored_frame = NULL; interlace->stored_fields = 0; } if (current_fields > 0) { interlace->stored_frame = buffer; interlace->stored_fields = current_fields; } else { gst_buffer_unref (buffer); } return ret; }
static GstFlowReturn mpegtsmux_collected (GstCollectPads2 * pads, MpegTsMux * mux) { GstFlowReturn ret = GST_FLOW_OK; MpegTsPadData *best = NULL; GST_DEBUG_OBJECT (mux, "Pads collected"); if (G_UNLIKELY (mux->first)) { ret = mpegtsmux_create_streams (mux); if (G_UNLIKELY (ret != GST_FLOW_OK)) return ret; mpegtsdemux_prepare_srcpad (mux); mux->first = FALSE; } best = mpegtsmux_choose_best_stream (mux); if (best != NULL) { TsMuxProgram *prog = best->prog; GstBuffer *buf = best->queued_buf; gint64 pts = -1; gboolean delta = TRUE; if (prog == NULL) { GST_ELEMENT_ERROR (mux, STREAM, MUX, ("Stream on pad %" GST_PTR_FORMAT " is not associated with any program", COLLECT_DATA_PAD (best)), (NULL)); return GST_FLOW_ERROR; } if (mux->force_key_unit_event != NULL && best->stream->is_video_stream) { GstEvent *event; event = check_pending_key_unit_event (mux->force_key_unit_event, &best->collect.segment, GST_BUFFER_TIMESTAMP (buf), GST_BUFFER_FLAGS (buf), mux->pending_key_unit_ts); if (event) { GstClockTime running_time; guint count; GList *cur; mux->pending_key_unit_ts = GST_CLOCK_TIME_NONE; gst_event_replace (&mux->force_key_unit_event, NULL); gst_video_event_parse_downstream_force_key_unit (event, NULL, NULL, &running_time, NULL, &count); GST_INFO_OBJECT (mux, "pushing downstream force-key-unit event %d " "%" GST_TIME_FORMAT " count %d", gst_event_get_seqnum (event), GST_TIME_ARGS (running_time), count); gst_pad_push_event (mux->srcpad, event); /* output PAT */ mux->tsmux->last_pat_ts = -1; /* output PMT for each program */ for (cur = g_list_first (mux->tsmux->programs); cur != NULL; cur = g_list_next (cur)) { TsMuxProgram *program = (TsMuxProgram *) cur->data; program->last_pmt_ts = -1; } tsmux_program_set_pcr_stream (prog, NULL); } } if (G_UNLIKELY (prog->pcr_stream == NULL)) { /* Take the first data stream for the PCR */ GST_DEBUG_OBJECT (COLLECT_DATA_PAD (best), "Use stream (pid=%d) from pad as PCR for program (prog_id = %d)", MPEG_TS_PAD_DATA (best)->pid, MPEG_TS_PAD_DATA (best)->prog_id); /* Set the chosen PCR stream */ tsmux_program_set_pcr_stream (prog, best->stream); } g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); if (best->stream->is_video_stream) delta = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); GST_DEBUG_OBJECT (mux, "delta: %d", delta); GST_DEBUG_OBJECT (COLLECT_DATA_PAD (best), "Chose stream for output (PID: 0x%04x)", best->pid); if (GST_CLOCK_TIME_IS_VALID (best->cur_ts)) { pts = GSTTIME_TO_MPEGTIME (best->cur_ts); GST_DEBUG_OBJECT (mux, "Buffer has TS %" GST_TIME_FORMAT " pts %" G_GINT64_FORMAT, GST_TIME_ARGS (best->cur_ts), pts); } tsmux_stream_add_data (best->stream, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), buf, pts, -1, !delta); best->queued_buf = NULL; mux->is_delta = delta; while (tsmux_stream_bytes_in_buffer (best->stream) > 0) { if (!tsmux_write_stream_packet (mux->tsmux, best->stream)) { /* Failed writing data for some reason. Set appropriate error */ GST_DEBUG_OBJECT (mux, "Failed to write data packet"); GST_ELEMENT_ERROR (mux, STREAM, MUX, ("Failed writing output data to stream %04x", best->stream->id), (NULL)); goto write_fail; } } if (prog->pcr_stream == best->stream) { mux->last_ts = best->last_ts; } } else { /* FIXME: Drain all remaining streams */ /* At EOS */ gst_pad_push_event (mux->srcpad, gst_event_new_eos ()); } return ret; write_fail: return mux->last_flow_ret; }