static void no_more_pads (GstElement * element, GstSplitMuxPartReader * reader) { GstClockTime duration = GST_CLOCK_TIME_NONE; GList *cur; /* Query the minimum duration of any pad in this piece and store it. * FIXME: Only consider audio and video */ SPLITMUX_PART_LOCK (reader); for (cur = g_list_first (reader->pads); cur != NULL; cur = g_list_next (cur)) { GstPad *target = GST_PAD_CAST (cur->data); if (target) { gint64 cur_duration; if (gst_pad_peer_query_duration (target, GST_FORMAT_TIME, &cur_duration)) { GST_INFO_OBJECT (reader, "file %s pad %" GST_PTR_FORMAT " duration %" GST_TIME_FORMAT, reader->path, target, GST_TIME_ARGS (cur_duration)); if (cur_duration < duration) duration = cur_duration; } } } GST_INFO_OBJECT (reader, "file %s duration %" GST_TIME_FORMAT, reader->path, GST_TIME_ARGS (duration)); reader->duration = (GstClockTime) duration; reader->no_more_pads = TRUE; check_if_pads_collected (reader); SPLITMUX_PART_UNLOCK (reader); }
static void gst_wavpack_dec_post_tags (GstWavpackDec * dec) { GstTagList *list; GstFormat format_time = GST_FORMAT_TIME, format_bytes = GST_FORMAT_BYTES; gint64 duration, size; /* try to estimate the average bitrate */ if (gst_pad_peer_query_duration (GST_AUDIO_DECODER_SINK_PAD (dec), format_bytes, &size) && gst_pad_peer_query_duration (GST_AUDIO_DECODER_SINK_PAD (dec), format_time, &duration) && size > 0 && duration > 0) { guint64 bitrate; list = gst_tag_list_new_empty (); bitrate = gst_util_uint64_scale (size, 8 * GST_SECOND, duration); gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, (guint) bitrate, NULL); gst_audio_decoder_merge_tags (GST_AUDIO_DECODER (dec), list, GST_TAG_MERGE_REPLACE); } }
/*********************************************************************************** * Query ***********************************************************************************/ static gboolean mpegts_demuxer_sink_query (GstPad *pad, GstObject *parent, GstQuery *query) { gboolean result = TRUE; MpegTSDemuxer *demuxer = MPEGTS_DEMUXER(parent); switch (GST_QUERY_TYPE(query)) { case GST_QUERY_DURATION: { GstFormat format; gst_query_parse_duration(query, &format, NULL); if (format == GST_FORMAT_TIME) result = gst_pad_peer_query(pad, query); else if (format == GST_FORMAT_BYTES) { g_mutex_lock(&demuxer->lock); int bit_rate = (demuxer->context != NULL) ? demuxer->context->bit_rate : 0; g_mutex_unlock(&demuxer->lock); if (bit_rate > 0) { gint64 duration = GST_CLOCK_TIME_NONE; if (gst_pad_peer_query_duration(pad, GST_FORMAT_TIME, &duration)) { // Approximate duration in bytes for a certain time duration and bit rate. if (duration != GST_CLOCK_TIME_NONE) duration = (double)(duration * bit_rate) / GST_SECOND / 8; gst_query_set_duration(query, format, duration); } else result = FALSE; } else result = gst_pad_peer_query(pad, query); } break; } default: result = gst_pad_peer_query(pad, query); break; } return result; }
static gboolean gst_raw_parse_sink_activatemode (GstPad * sinkpad, GstObject * parent, GstPadMode mode, gboolean active) { GstRawParse *rp = GST_RAW_PARSE (parent); gboolean result; switch (mode) { case GST_PAD_MODE_PULL: if (active) { GstFormat format; gint64 duration; /* get the duration in bytes */ format = GST_FORMAT_BYTES; result = gst_pad_peer_query_duration (sinkpad, format, &duration); if (result) { GST_DEBUG_OBJECT (rp, "got duration %" GST_TIME_FORMAT, GST_TIME_ARGS (duration)); rp->upstream_length = duration; /* convert to time */ gst_raw_parse_convert (rp, format, duration, GST_FORMAT_TIME, &duration); } else { rp->upstream_length = -1; duration = -1; } rp->segment.duration = duration; rp->push_stream_start = TRUE; result = gst_raw_parse_handle_seek_pull (rp, NULL); rp->mode = mode; } else { result = gst_pad_stop_task (sinkpad); } return result; case GST_PAD_MODE_PUSH: rp->mode = mode; return TRUE; default: return FALSE; } }
static gboolean gst_interleave_src_query_duration (GstInterleave * self, GstQuery * query) { gint64 max; gboolean res; GstFormat format; GstIterator *it; gboolean done; /* parse format */ gst_query_parse_duration (query, &format, NULL); max = -1; res = TRUE; done = FALSE; /* Take maximum of all durations */ it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self)); while (!done) { GstIteratorResult ires; GValue item = { 0, }; ires = gst_iterator_next (it, &item); switch (ires) { case GST_ITERATOR_DONE: done = TRUE; break; case GST_ITERATOR_OK: { GstPad *pad = GST_PAD_CAST (g_value_dup_object (&item)); gint64 duration; /* ask sink peer for duration */ res &= gst_pad_peer_query_duration (pad, format, &duration); /* take max from all valid return values */ if (res) { /* valid unknown length, stop searching */ if (duration == -1) { max = duration; done = TRUE; } /* else see if bigger than current max */ else if (duration > max) max = duration; } gst_object_unref (pad); g_value_unset (&item); break; } case GST_ITERATOR_RESYNC: max = -1; res = TRUE; gst_iterator_resync (it); break; default: res = FALSE; done = TRUE; break; } } gst_iterator_free (it); if (res) { /* If in bytes format we have to multiply with the number of channels * to get the correct results. All other formats should be fine */ if (format == GST_FORMAT_BYTES && max != -1) max *= self->channels; /* and store the max */ GST_DEBUG_OBJECT (self, "Total duration in format %s: %" GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (max)); gst_query_set_duration (query, format, max); } return res; }
static gboolean gst_frei0r_mixer_src_query_duration (GstFrei0rMixer * self, GstQuery * query) { gint64 min; gboolean res; GstFormat format; GstIterator *it; gboolean done; /* parse format */ gst_query_parse_duration (query, &format, NULL); min = -1; res = TRUE; done = FALSE; /* Take minimum of all durations */ it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self)); while (!done) { GstIteratorResult ires; GValue item = { 0 }; ires = gst_iterator_next (it, &item); switch (ires) { case GST_ITERATOR_DONE: done = TRUE; break; case GST_ITERATOR_OK: { GstPad *pad = g_value_get_object (&item); gint64 duration; /* ask sink peer for duration */ res &= gst_pad_peer_query_duration (pad, format, &duration); /* take min from all valid return values */ if (res) { /* valid unknown length, stop searching */ if (duration == -1) { min = duration; done = TRUE; } /* else see if smaller than current min */ else if (duration < min) min = duration; } g_value_reset (&item); break; } case GST_ITERATOR_RESYNC: min = -1; res = TRUE; gst_iterator_resync (it); break; default: res = FALSE; done = TRUE; break; } g_value_unset (&item); } gst_iterator_free (it); if (res) { /* and store the min */ GST_DEBUG_OBJECT (self, "Total duration in format %s: %" GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (min)); gst_query_set_duration (query, format, min); } return res; }
static void gst_raw_parse_loop (GstElement * element) { GstRawParse *rp = GST_RAW_PARSE (element); GstRawParseClass *rp_class = GST_RAW_PARSE_GET_CLASS (rp); GstFlowReturn ret; GstBuffer *buffer; gint size; if (!gst_raw_parse_set_src_caps (rp)) goto no_caps; if (rp->start_segment) { GST_DEBUG_OBJECT (rp, "sending start segment"); gst_pad_push_event (rp->srcpad, rp->start_segment); rp->start_segment = NULL; } if (rp_class->multiple_frames_per_buffer && rp->framesize < 4096) size = 4096 - (4096 % rp->framesize); else size = rp->framesize; if (rp->segment.rate >= 0) { if (rp->offset + size > rp->upstream_length) { GstFormat fmt = GST_FORMAT_BYTES; if (!gst_pad_peer_query_duration (rp->sinkpad, fmt, &rp->upstream_length)) { GST_WARNING_OBJECT (rp, "Could not get upstream duration, trying to pull frame by frame"); size = rp->framesize; } else if (rp->upstream_length < rp->offset + rp->framesize) { ret = GST_FLOW_EOS; goto pause; } else if (rp->offset + size > rp->upstream_length) { size = rp->upstream_length - rp->offset; size -= size % rp->framesize; } } } else { if (rp->offset == 0) { ret = GST_FLOW_EOS; goto pause; } else if (rp->offset < size) { size -= rp->offset; } rp->offset -= size; } buffer = NULL; ret = gst_pad_pull_range (rp->sinkpad, rp->offset, size, &buffer); if (ret != GST_FLOW_OK) { GST_DEBUG_OBJECT (rp, "pull_range (%" G_GINT64_FORMAT ", %u) " "failed, flow: %s", rp->offset, size, gst_flow_get_name (ret)); buffer = NULL; goto pause; } if (gst_buffer_get_size (buffer) < size) { GST_DEBUG_OBJECT (rp, "Short read at offset %" G_GINT64_FORMAT ", got only %" G_GSIZE_FORMAT " of %u bytes", rp->offset, gst_buffer_get_size (buffer), size); if (size > rp->framesize) { gst_buffer_set_size (buffer, gst_buffer_get_size (buffer) - gst_buffer_get_size (buffer) % rp->framesize); } else { gst_buffer_unref (buffer); buffer = NULL; ret = GST_FLOW_EOS; goto pause; } } ret = gst_raw_parse_push_buffer (rp, buffer); if (ret != GST_FLOW_OK) goto pause; return; /* ERRORS */ no_caps: { GST_ERROR_OBJECT (rp, "could not negotiate caps"); ret = GST_FLOW_NOT_NEGOTIATED; goto pause; } pause: { const gchar *reason = gst_flow_get_name (ret); GST_LOG_OBJECT (rp, "pausing task, reason %s", reason); gst_pad_pause_task (rp->sinkpad); if (ret == GST_FLOW_EOS) { if (rp->segment.flags & GST_SEEK_FLAG_SEGMENT) { GstClockTime stop; GST_LOG_OBJECT (rp, "Sending segment done"); if ((stop = rp->segment.stop) == -1) stop = rp->segment.duration; gst_element_post_message (GST_ELEMENT_CAST (rp), gst_message_new_segment_done (GST_OBJECT_CAST (rp), rp->segment.format, stop)); gst_pad_push_event (rp->srcpad, gst_event_new_segment_done (rp->segment.format, stop)); } else { GST_LOG_OBJECT (rp, "Sending EOS, at end of stream"); gst_pad_push_event (rp->srcpad, gst_event_new_eos ()); } } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) { GST_ELEMENT_ERROR (rp, STREAM, FAILED, ("Internal data stream error."), ("stream stopped, reason %s", reason)); gst_pad_push_event (rp->srcpad, gst_event_new_eos ()); } return; } }
static GstFlowReturn mpegts_base_scan (MpegTSBase * base) { GstFlowReturn ret = GST_FLOW_OK; GstBuffer *buf = NULL; guint i; gboolean done = FALSE; MpegTSPacketizerPacketReturn pret; gint64 tmpval; gint64 upstream_size, seek_pos, reverse_limit; GstFormat format; guint initial_pcr_seen; GST_DEBUG ("Scanning for initial sync point"); /* Find initial sync point and at least 5 PCR values */ for (i = 0; i < 20 && !done; i++) { GST_DEBUG ("Grabbing %d => %d", i * 65536, (i + 1) * 65536); ret = gst_pad_pull_range (base->sinkpad, i * 65536, 65536, &buf); if (G_UNLIKELY (ret == GST_FLOW_EOS)) break; if (G_UNLIKELY (ret != GST_FLOW_OK)) goto beach; /* Push to packetizer */ mpegts_packetizer_push (base->packetizer, buf); buf = NULL; if (mpegts_packetizer_has_packets (base->packetizer)) { if (base->seek_offset == -1) { /* Mark the initial sync point and remember the packetsize */ base->seek_offset = base->packetizer->offset; GST_DEBUG ("Sync point is now %" G_GUINT64_FORMAT, base->seek_offset); base->packetsize = base->packetizer->packet_size; } while (1) { /* Eat up all packets */ pret = mpegts_packetizer_process_next_packet (base->packetizer); if (pret == PACKET_NEED_MORE) break; if (pret != PACKET_BAD && base->packetizer->nb_seen_offsets >= 5) { GST_DEBUG ("Got enough initial PCR"); done = TRUE; break; } } } } initial_pcr_seen = base->packetizer->nb_seen_offsets; if (G_UNLIKELY (initial_pcr_seen == 0)) goto no_initial_pcr; GST_DEBUG ("Seen %d initial PCR", initial_pcr_seen); /* Now send data from the end */ /* Get the size of upstream */ format = GST_FORMAT_BYTES; if (!gst_pad_peer_query_duration (base->sinkpad, format, &tmpval)) goto beach; upstream_size = tmpval; /* The scanning takes place on the last 2048kB. Considering PCR should * be present at least every 100ms, this should cope with streams * up to 160Mbit/s */ reverse_limit = MAX (0, upstream_size - 2097152); /* Find last PCR value, searching backwards by chunks of 300 MPEG-ts packets */ for (seek_pos = MAX (0, upstream_size - 56400); seek_pos >= reverse_limit; seek_pos -= 56400) { mpegts_packetizer_clear (base->packetizer); GST_DEBUG ("Grabbing %" G_GUINT64_FORMAT " => %" G_GUINT64_FORMAT, seek_pos, seek_pos + 56400); ret = gst_pad_pull_range (base->sinkpad, seek_pos, 56400, &buf); if (G_UNLIKELY (ret == GST_FLOW_EOS)) break; if (G_UNLIKELY (ret != GST_FLOW_OK)) goto beach; /* Push to packetizer */ mpegts_packetizer_push (base->packetizer, buf); buf = NULL; if (mpegts_packetizer_has_packets (base->packetizer)) { pret = PACKET_OK; /* Eat up all packets, really try to get last PCR(s) */ while (pret != PACKET_NEED_MORE) pret = mpegts_packetizer_process_next_packet (base->packetizer); if (base->packetizer->nb_seen_offsets > initial_pcr_seen) { GST_DEBUG ("Got last PCR(s) (total seen:%d)", base->packetizer->nb_seen_offsets); break; } } } beach: mpegts_packetizer_clear (base->packetizer); return ret; no_initial_pcr: mpegts_packetizer_clear (base->packetizer); GST_WARNING_OBJECT (base, "Couldn't find any PCR within the first %d bytes", 10 * 65536); return GST_FLOW_ERROR; }
static GstFlowReturn gst_real_audio_demux_parse_header (GstRealAudioDemux * demux) { const guint8 *data; gchar *codec_name = NULL; GstCaps *caps = NULL; GstEvent *event; gchar *stream_id; guint avail; g_assert (demux->ra_version == 4 || demux->ra_version == 3); avail = gst_adapter_available (demux->adapter); if (avail < 16) return GST_FLOW_OK; if (!gst_real_audio_demux_get_data_offset_from_header (demux)) return GST_FLOW_ERROR; /* shouldn't happen */ GST_DEBUG_OBJECT (demux, "data_offset = %u", demux->data_offset); if (avail + 6 < demux->data_offset) { GST_DEBUG_OBJECT (demux, "Need %u bytes, but only %u available now", demux->data_offset - 6, avail); return GST_FLOW_OK; } data = gst_adapter_map (demux->adapter, demux->data_offset - 6); g_assert (data); switch (demux->ra_version) { case 3: demux->fourcc = GST_RM_AUD_14_4; demux->packet_size = 20; demux->sample_rate = 8000; demux->channels = 1; demux->sample_width = 16; demux->flavour = 1; demux->leaf_size = 0; demux->height = 0; break; case 4: demux->flavour = GST_READ_UINT16_BE (data + 16); /* demux->frame_size = GST_READ_UINT32_BE (data + 36); */ demux->leaf_size = GST_READ_UINT16_BE (data + 38); demux->height = GST_READ_UINT16_BE (data + 34); demux->packet_size = GST_READ_UINT32_BE (data + 18); demux->sample_rate = GST_READ_UINT16_BE (data + 42); demux->sample_width = GST_READ_UINT16_BE (data + 46); demux->channels = GST_READ_UINT16_BE (data + 48); demux->fourcc = GST_READ_UINT32_LE (data + 56); demux->pending_tags = gst_rm_utils_read_tags (data + 63, demux->data_offset - 63, gst_rm_utils_read_string8); if (demux->pending_tags) gst_tag_list_set_scope (demux->pending_tags, GST_TAG_SCOPE_GLOBAL); break; default: g_assert_not_reached (); #if 0 case 5: demux->flavour = GST_READ_UINT16_BE (data + 16); /* demux->frame_size = GST_READ_UINT32_BE (data + 36); */ demux->leaf_size = GST_READ_UINT16_BE (data + 38); demux->height = GST_READ_UINT16_BE (data + 34); demux->sample_rate = GST_READ_UINT16_BE (data + 48); demux->sample_width = GST_READ_UINT16_BE (data + 52); demux->n_channels = GST_READ_UINT16_BE (data + 54); demux->fourcc = RMDEMUX_FOURCC_GET (data + 60); break; #endif } GST_INFO_OBJECT (demux, "packet_size = %u", demux->packet_size); GST_INFO_OBJECT (demux, "sample_rate = %u", demux->sample_rate); GST_INFO_OBJECT (demux, "sample_width = %u", demux->sample_width); GST_INFO_OBJECT (demux, "channels = %u", demux->channels); GST_INFO_OBJECT (demux, "fourcc = '%" GST_FOURCC_FORMAT "' (%08X)", GST_FOURCC_ARGS (demux->fourcc), demux->fourcc); switch (demux->fourcc) { case GST_RM_AUD_14_4: caps = gst_caps_new_simple ("audio/x-pn-realaudio", "raversion", G_TYPE_INT, 1, NULL); demux->byterate_num = 1000; demux->byterate_denom = 1; break; case GST_RM_AUD_28_8: /* FIXME: needs descrambling */ caps = gst_caps_new_simple ("audio/x-pn-realaudio", "raversion", G_TYPE_INT, 2, NULL); break; case GST_RM_AUD_DNET: caps = gst_caps_new_simple ("audio/x-ac3", "rate", G_TYPE_INT, demux->sample_rate, NULL); if (demux->packet_size == 0 || demux->sample_rate == 0) goto broken_file; demux->byterate_num = demux->packet_size * demux->sample_rate; demux->byterate_denom = 1536; break; /* Sipro/ACELP.NET Voice Codec (MIME unknown) */ case GST_RM_AUD_SIPR: caps = gst_caps_new_empty_simple ("audio/x-sipro"); break; default: GST_WARNING_OBJECT (demux, "unknown fourcc %08X", demux->fourcc); break; } if (caps == NULL) goto unknown_fourcc; gst_caps_set_simple (caps, "flavor", G_TYPE_INT, demux->flavour, "rate", G_TYPE_INT, demux->sample_rate, "channels", G_TYPE_INT, demux->channels, "width", G_TYPE_INT, demux->sample_width, "leaf_size", G_TYPE_INT, demux->leaf_size, "packet_size", G_TYPE_INT, demux->packet_size, "height", G_TYPE_INT, demux->height, NULL); GST_INFO_OBJECT (demux, "Adding source pad, caps %" GST_PTR_FORMAT, caps); demux->srcpad = gst_pad_new_from_static_template (&src_template, "src"); gst_pad_set_event_function (demux->srcpad, GST_DEBUG_FUNCPTR (gst_real_audio_demux_src_event)); gst_pad_set_query_function (demux->srcpad, GST_DEBUG_FUNCPTR (gst_real_audio_demux_src_query)); gst_pad_set_active (demux->srcpad, TRUE); gst_pad_use_fixed_caps (demux->srcpad); stream_id = gst_pad_create_stream_id (demux->srcpad, GST_ELEMENT_CAST (demux), NULL); event = gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0); if (event) { if (gst_event_parse_group_id (event, &demux->group_id)) demux->have_group_id = TRUE; else demux->have_group_id = FALSE; gst_event_unref (event); } else if (!demux->have_group_id) { demux->have_group_id = TRUE; demux->group_id = gst_util_group_id_next (); } event = gst_event_new_stream_start (stream_id); if (demux->have_group_id) gst_event_set_group_id (event, demux->group_id); gst_pad_push_event (demux->srcpad, event); g_free (stream_id); gst_pad_set_caps (demux->srcpad, caps); codec_name = gst_pb_utils_get_codec_description (caps); gst_caps_unref (caps); gst_element_add_pad (GST_ELEMENT (demux), demux->srcpad); if (demux->byterate_num > 0 && demux->byterate_denom > 0) { GstFormat bformat = GST_FORMAT_BYTES; gint64 size_bytes = 0; GST_INFO_OBJECT (demux, "byte rate = %u/%u = %u bytes/sec", demux->byterate_num, demux->byterate_denom, demux->byterate_num / demux->byterate_denom); if (gst_pad_peer_query_duration (demux->sinkpad, bformat, &size_bytes)) { demux->duration = gst_real_demux_get_timestamp_from_offset (demux, size_bytes); demux->upstream_size = size_bytes; GST_INFO_OBJECT (demux, "upstream_size = %" G_GUINT64_FORMAT, demux->upstream_size); GST_INFO_OBJECT (demux, "duration = %" GST_TIME_FORMAT, GST_TIME_ARGS (demux->duration)); } } demux->need_newsegment = TRUE; if (codec_name) { if (demux->pending_tags == NULL) { demux->pending_tags = gst_tag_list_new_empty (); gst_tag_list_set_scope (demux->pending_tags, GST_TAG_SCOPE_GLOBAL); } gst_tag_list_add (demux->pending_tags, GST_TAG_MERGE_REPLACE, GST_TAG_AUDIO_CODEC, codec_name, NULL); g_free (codec_name); } gst_adapter_unmap (demux->adapter); gst_adapter_flush (demux->adapter, demux->data_offset - 6); demux->state = REAL_AUDIO_DEMUX_STATE_DATA; demux->need_newsegment = TRUE; return GST_FLOW_OK; /* ERRORS */ unknown_fourcc: { GST_ELEMENT_ERROR (GST_ELEMENT (demux), STREAM, DECODE, (NULL), ("Unknown fourcc '%" GST_FOURCC_FORMAT "'", GST_FOURCC_ARGS (demux->fourcc))); return GST_FLOW_ERROR; } broken_file: { GST_ELEMENT_ERROR (GST_ELEMENT (demux), STREAM, DECODE, (NULL), ("Broken file - invalid sample_rate or other header value")); return GST_FLOW_ERROR; } }
static gboolean gst_progress_report_do_query (GstProgressReport * filter, GstFormat format, gint hh, gint mm, gint ss, GstBuffer * buf) { const gchar *format_name = NULL; GstPad *sink_pad; gint64 cur, total; sink_pad = GST_BASE_TRANSFORM (filter)->sinkpad; GST_LOG_OBJECT (filter, "querying using format %d (%s)", format, gst_format_get_name (format)); if (filter->do_query || !buf) { GST_LOG_OBJECT (filter, "using upstream query"); if (!gst_pad_peer_query_position (sink_pad, format, &cur) || !gst_pad_peer_query_duration (sink_pad, format, &total)) { return FALSE; } } else { GstBaseTransform *base = GST_BASE_TRANSFORM (filter); GST_LOG_OBJECT (filter, "using buffer metadata"); if (format == GST_FORMAT_TIME && base->segment.format == GST_FORMAT_TIME) { cur = gst_segment_to_stream_time (&base->segment, format, GST_BUFFER_TIMESTAMP (buf)); total = base->segment.duration; } else { return FALSE; } } switch (format) { case GST_FORMAT_BYTES: format_name = "bytes"; break; case GST_FORMAT_BUFFERS: format_name = "buffers"; break; case GST_FORMAT_PERCENT: format_name = "percent"; break; case GST_FORMAT_TIME: format_name = "seconds"; cur /= GST_SECOND; total /= GST_SECOND; break; case GST_FORMAT_DEFAULT:{ GstCaps *caps; format_name = "bogounits"; caps = gst_pad_get_current_caps (GST_BASE_TRANSFORM (filter)->sinkpad); if (caps) { if (gst_caps_is_fixed (caps) && !gst_caps_is_any (caps)) { GstStructure *s = gst_caps_get_structure (caps, 0); const gchar *mime_type = gst_structure_get_name (s); if (g_str_has_prefix (mime_type, "video/") || g_str_has_prefix (mime_type, "image/")) { format_name = "frames"; } else if (g_str_has_prefix (mime_type, "audio/")) { format_name = "samples"; } } gst_caps_unref (caps); } break; } default:{ const GstFormatDefinition *details; details = gst_format_get_details (format); if (details) { format_name = details->nick; } else { format_name = "unknown"; } break; } } if (!filter->silent) { if (total > 0) { g_print ("%s (%02d:%02d:%02d): %" G_GINT64_FORMAT " / %" G_GINT64_FORMAT " %s (%4.1f %%)\n", GST_OBJECT_NAME (filter), hh, mm, ss, cur, total, format_name, (gdouble) cur / total * 100.0); } else { g_print ("%s (%02d:%02d:%02d): %" G_GINT64_FORMAT " %s\n", GST_OBJECT_NAME (filter), hh, mm, ss, cur, format_name); } } gst_progress_report_post_progress (filter, format, cur, total); return TRUE; }
/* FIXME, the duration query should reflect how long you will produce * data, that is the amount of stream time until you will emit EOS. * * For synchronized mixing this is always the max of all the durations * of upstream since we emit EOS when all of them finished. * * We don't do synchronized mixing so this really depends on where the * streams where punched in and what their relative offsets are against * eachother which we can get from the first timestamps we see. * * When we add a new stream (or remove a stream) the duration might * also become invalid again and we need to post a new DURATION * message to notify this fact to the parent. * For now we take the max of all the upstream elements so the simple * cases work at least somewhat. */ static gboolean gst_audio_aggregator_query_duration (GstAudioAggregator * aagg, GstQuery * query) { gint64 max; gboolean res; GstFormat format; GstIterator *it; gboolean done; GValue item = { 0, }; /* parse format */ gst_query_parse_duration (query, &format, NULL); max = -1; res = TRUE; done = FALSE; it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (aagg)); while (!done) { GstIteratorResult ires; ires = gst_iterator_next (it, &item); switch (ires) { case GST_ITERATOR_DONE: done = TRUE; break; case GST_ITERATOR_OK: { GstPad *pad = g_value_get_object (&item); gint64 duration; /* ask sink peer for duration */ res &= gst_pad_peer_query_duration (pad, format, &duration); /* take max from all valid return values */ if (res) { /* valid unknown length, stop searching */ if (duration == -1) { max = duration; done = TRUE; } /* else see if bigger than current max */ else if (duration > max) max = duration; } g_value_reset (&item); break; } case GST_ITERATOR_RESYNC: max = -1; res = TRUE; gst_iterator_resync (it); break; default: res = FALSE; done = TRUE; break; } } g_value_unset (&item); gst_iterator_free (it); if (res) { /* and store the max */ GST_DEBUG_OBJECT (aagg, "Total duration in format %s: %" GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (max)); gst_query_set_duration (query, format, max); } return res; }
static GstFlowReturn mpegts_base_scan (MpegTSBase * base) { GstFlowReturn ret = GST_FLOW_OK; GstBuffer *buf = NULL; guint i; gboolean done = FALSE; MpegTSPacketizerPacketReturn pret; gint64 tmpval; guint64 upstream_size, seek_pos; GstFormat format; guint initial_pcr_seen; GST_DEBUG ("Scanning for initial sync point"); /* Find initial sync point and at least 5 PCR values */ for (i = 0; i < 10 && !done; i++) { GST_DEBUG ("Grabbing %d => %d", i * 65536, 65536); ret = gst_pad_pull_range (base->sinkpad, i * 65536, 65536, &buf); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto beach; /* Push to packetizer */ mpegts_packetizer_push (base->packetizer, buf); buf = NULL; if (mpegts_packetizer_has_packets (base->packetizer)) { if (base->seek_offset == -1) { /* Mark the initial sync point and remember the packetsize */ base->seek_offset = base->packetizer->offset; GST_DEBUG ("Sync point is now %" G_GUINT64_FORMAT, base->seek_offset); base->packetsize = base->packetizer->packet_size; } while (1) { /* Eat up all packets */ pret = mpegts_packetizer_process_next_packet (base->packetizer); if (pret == PACKET_NEED_MORE) break; if (pret != PACKET_BAD && mpegts_packetizer_get_seen_pcr (base->packetizer) >= 5) { GST_DEBUG ("Got enough initial PCR"); done = TRUE; break; } } } } initial_pcr_seen = mpegts_packetizer_get_seen_pcr (base->packetizer); if (G_UNLIKELY (initial_pcr_seen == 0)) goto no_initial_pcr; GST_DEBUG ("Seen %d initial PCR", initial_pcr_seen); /* Now send data from the end */ mpegts_packetizer_clear (base->packetizer); /* Get the size of upstream */ format = GST_FORMAT_BYTES; if (!gst_pad_peer_query_duration (base->sinkpad, format, &tmpval)) goto beach; upstream_size = tmpval; done = FALSE; /* Find last PCR value */ for (seek_pos = MAX (0, upstream_size - 655360); seek_pos < upstream_size && !done; seek_pos += 65536) { GST_DEBUG ("Grabbing %" G_GUINT64_FORMAT " => %d", seek_pos, 65536); ret = gst_pad_pull_range (base->sinkpad, seek_pos, 65536, &buf); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto beach; /* Push to packetizer */ mpegts_packetizer_push (base->packetizer, buf); buf = NULL; if (mpegts_packetizer_has_packets (base->packetizer)) { while (1) { /* Eat up all packets */ pret = mpegts_packetizer_process_next_packet (base->packetizer); if (pret == PACKET_NEED_MORE) break; if (pret != PACKET_BAD && mpegts_packetizer_get_seen_pcr (base->packetizer) > initial_pcr_seen) { GST_DEBUG ("Got last PCR"); done = TRUE; break; } } } } beach: mpegts_packetizer_clear (base->packetizer); return ret; no_initial_pcr: mpegts_packetizer_clear (base->packetizer); GST_WARNING_OBJECT (base, "Couldn't find any PCR within the first %d bytes", 10 * 65536); return GST_FLOW_ERROR; }