static gboolean gst_raw_parse_sink_activatepull (GstPad * sinkpad, gboolean active) { GstRawParse *rp = GST_RAW_PARSE (gst_pad_get_parent (sinkpad)); gboolean result; if (active) { GstFormat format; gint64 duration; /* get the duration in bytes */ format = GST_FORMAT_BYTES; result = gst_pad_query_peer_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; } gst_segment_set_duration (&rp->segment, GST_FORMAT_TIME, duration); result = gst_raw_parse_handle_seek_pull (rp, NULL); } else { result = gst_pad_stop_task (sinkpad); } gst_object_unref (rp); return result; }
static GstFlowReturn gst_aiff_parse_stream_headers (GstAiffParse * aiff) { GstFlowReturn res; GstBuffer *buf; guint32 tag, size; gboolean gotdata = FALSE; gboolean done = FALSE; GstEvent **event_p; GstFormat bformat; gint64 upstream_size = 0; bformat = GST_FORMAT_BYTES; gst_pad_query_peer_duration (aiff->sinkpad, &bformat, &upstream_size); GST_DEBUG_OBJECT (aiff, "upstream size %" G_GUINT64_FORMAT, upstream_size); /* loop headers until we get data */ while (!done) { if (aiff->streaming) { if (!gst_aiff_parse_peek_chunk_info (aiff, &tag, &size)) return GST_FLOW_OK; } else { if ((res = gst_pad_pull_range (aiff->sinkpad, aiff->offset, 8, &buf)) != GST_FLOW_OK) goto header_read_error; tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)); size = GST_READ_UINT32_BE (GST_BUFFER_DATA (buf) + 4); } GST_INFO_OBJECT (aiff, "Got TAG: %" GST_FOURCC_FORMAT ", offset %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (tag), aiff->offset); /* We just keep reading chunks until we find the one we're interested in. */ switch (tag) { case GST_MAKE_FOURCC ('C', 'O', 'M', 'M'):{ if (aiff->streaming) { if (!gst_aiff_parse_peek_chunk (aiff, &tag, &size)) return GST_FLOW_OK; gst_adapter_flush (aiff->adapter, 8); aiff->offset += 8; buf = gst_adapter_take_buffer (aiff->adapter, size); } else { if ((res = gst_aiff_parse_read_chunk (aiff, &aiff->offset, &tag, &buf)) != GST_FLOW_OK) return res; } if (!gst_aiff_parse_parse_comm (aiff, buf)) { gst_buffer_unref (buf); goto parse_header_error; } gst_buffer_unref (buf); /* do sanity checks of header fields */ if (aiff->channels == 0) goto no_channels; if (aiff->rate == 0) goto no_rate; GST_DEBUG_OBJECT (aiff, "creating the caps"); aiff->caps = gst_aiff_parse_create_caps (aiff); if (!aiff->caps) goto unknown_format; gst_pad_set_caps (aiff->srcpad, aiff->caps); aiff->bytes_per_sample = aiff->channels * aiff->width / 8; aiff->bps = aiff->bytes_per_sample * aiff->rate; if (aiff->bytes_per_sample <= 0) goto no_bytes_per_sample; aiff->got_comm = TRUE; break; } case GST_MAKE_FOURCC ('S', 'S', 'N', 'D'):{ GstFormat fmt; GstBuffer *ssndbuf = NULL; const guint8 *ssnddata = NULL; guint32 datasize; GST_DEBUG_OBJECT (aiff, "Got 'SSND' TAG, size : %d", size); /* Now, read the 8-byte header in the SSND chunk */ if (aiff->streaming) { if (!gst_aiff_parse_peek_data (aiff, 16, &ssnddata)) return GST_FLOW_OK; } else { gst_buffer_unref (buf); if ((res = gst_pad_pull_range (aiff->sinkpad, aiff->offset, 16, &ssndbuf)) != GST_FLOW_OK) goto header_read_error; ssnddata = GST_BUFFER_DATA (ssndbuf); } aiff->ssnd_offset = GST_READ_UINT32_BE (ssnddata + 8); aiff->ssnd_blocksize = GST_READ_UINT32_BE (ssnddata + 12); gotdata = TRUE; if (aiff->streaming) { gst_adapter_flush (aiff->adapter, 16); } else { gst_buffer_unref (ssndbuf); } /* 8 byte chunk header, 16 byte SSND header */ aiff->offset += 24; datasize = size - 16; aiff->datastart = aiff->offset + aiff->ssnd_offset; /* file might be truncated */ fmt = GST_FORMAT_BYTES; if (upstream_size) { size = MIN (datasize, (upstream_size - aiff->datastart)); } aiff->datasize = (guint64) datasize; aiff->dataleft = (guint64) datasize; aiff->end_offset = datasize + aiff->datastart; if (!aiff->streaming) { /* We will continue looking at chunks until the end - to read tags, * etc. */ aiff->offset += datasize; } GST_DEBUG_OBJECT (aiff, "datasize = %d", datasize); if (aiff->streaming) { done = TRUE; } break; } default: gst_aiff_parse_ignore_chunk (aiff, buf, tag, size); } if (upstream_size && (aiff->offset >= upstream_size)) { /* Now we have gone through the whole file */ done = TRUE; } } /* We read all the chunks (in pull mode) or reached the SSND chunk * (in push mode). We must have both COMM and SSND now; error out * otherwise. */ if (!aiff->got_comm) { GST_WARNING_OBJECT (aiff, "Failed to find COMM chunk"); goto no_header; } if (!gotdata) { GST_WARNING_OBJECT (aiff, "Failed to find SSND chunk"); goto no_data; } GST_DEBUG_OBJECT (aiff, "Finished parsing headers"); if (gst_aiff_parse_calculate_duration (aiff)) { gst_segment_init (&aiff->segment, GST_FORMAT_TIME); gst_segment_set_duration (&aiff->segment, GST_FORMAT_TIME, aiff->duration); } else { /* no bitrate, let downstream peer do the math, we'll feed it bytes. */ gst_segment_init (&aiff->segment, GST_FORMAT_BYTES); gst_segment_set_duration (&aiff->segment, GST_FORMAT_BYTES, aiff->datasize); } /* now we have all the info to perform a pending seek if any, if no * event, this will still do the right thing and it will also send * the right newsegment event downstream. */ gst_aiff_parse_perform_seek (aiff, aiff->seek_event); /* remove pending event */ event_p = &aiff->seek_event; gst_event_replace (event_p, NULL); /* we just started, we are discont */ aiff->discont = TRUE; aiff->state = AIFF_PARSE_DATA; return GST_FLOW_OK; /* ERROR */ no_header: { GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL), ("Invalid AIFF header (no COMM found)")); return GST_FLOW_ERROR; } no_data: { GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL), ("Invalid AIFF: no SSND found")); return GST_FLOW_ERROR; } parse_header_error: { GST_ELEMENT_ERROR (aiff, STREAM, DEMUX, (NULL), ("Couldn't parse audio header")); return GST_FLOW_ERROR; } no_channels: { GST_ELEMENT_ERROR (aiff, STREAM, FAILED, (NULL), ("Stream claims to contain no channels - invalid data")); return GST_FLOW_ERROR; } no_rate: { GST_ELEMENT_ERROR (aiff, STREAM, FAILED, (NULL), ("Stream with sample_rate == 0 - invalid data")); return GST_FLOW_ERROR; } no_bytes_per_sample: { GST_ELEMENT_ERROR (aiff, STREAM, FAILED, (NULL), ("Could not caluclate bytes per sample - invalid data")); return GST_FLOW_ERROR; } unknown_format: { GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL), ("No caps found for format 0x%x, %d channels, %d Hz", aiff->format, aiff->channels, aiff->rate)); return GST_FLOW_ERROR; } header_read_error: { GST_ELEMENT_ERROR (aiff, STREAM, DEMUX, (NULL), ("Couldn't read in header")); return GST_FLOW_ERROR; } }
static void gst_soup_http_src_got_headers_cb (SoupMessage * msg, GstSoupHTTPSrc * src) { const char *value; GstTagList *tag_list; GstBaseSrc *basesrc; guint64 newsize; GHashTable *params = NULL; GST_DEBUG_OBJECT (src, "got headers:"); soup_message_headers_foreach (msg->response_headers, gst_soup_http_src_headers_foreach, src); if (msg->status_code == 407 && src->proxy_id && src->proxy_pw) return; if (src->automatic_redirect && SOUP_STATUS_IS_REDIRECTION (msg->status_code)) { GST_DEBUG_OBJECT (src, "%u redirect to \"%s\"", msg->status_code, soup_message_headers_get_one (msg->response_headers, "Location")); return; } if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) return; src->session_io_status = GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_RUNNING; /* Parse Content-Length. */ if (soup_message_headers_get_encoding (msg->response_headers) == SOUP_ENCODING_CONTENT_LENGTH) { newsize = src->request_position + soup_message_headers_get_content_length (msg->response_headers); if (!src->have_size || (src->content_size != newsize)) { src->content_size = newsize; src->have_size = TRUE; src->seekable = TRUE; GST_DEBUG_OBJECT (src, "size = %" G_GUINT64_FORMAT, src->content_size); basesrc = GST_BASE_SRC_CAST (src); gst_segment_set_duration (&basesrc->segment, GST_FORMAT_BYTES, src->content_size); gst_element_post_message (GST_ELEMENT (src), gst_message_new_duration (GST_OBJECT (src), GST_FORMAT_BYTES, src->content_size)); } } /* Icecast stuff */ tag_list = gst_tag_list_new (); if ((value = soup_message_headers_get_one (msg->response_headers, "icy-metaint")) != NULL) { gint icy_metaint = atoi (value); GST_DEBUG_OBJECT (src, "icy-metaint: %s (parsed: %d)", value, icy_metaint); if (icy_metaint > 0) { if (src->src_caps) gst_caps_unref (src->src_caps); src->src_caps = gst_caps_new_simple ("application/x-icy", "metadata-interval", G_TYPE_INT, icy_metaint, NULL); } } if ((value = soup_message_headers_get_content_type (msg->response_headers, ¶ms)) != NULL) { GST_DEBUG_OBJECT (src, "Content-Type: %s", value); if (g_ascii_strcasecmp (value, "audio/L16") == 0) { gint channels = 2; gint rate = 44100; char *param; if (src->src_caps) gst_caps_unref (src->src_caps); param = g_hash_table_lookup (params, "channels"); if (param != NULL) channels = atol (param); param = g_hash_table_lookup (params, "rate"); if (param != NULL) rate = atol (param); src->src_caps = gst_caps_new_simple ("audio/x-raw-int", "channels", G_TYPE_INT, channels, "rate", G_TYPE_INT, rate, "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, "signed", G_TYPE_BOOLEAN, TRUE, "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL); } else { /* Set the Content-Type field on the caps */ if (src->src_caps) gst_caps_set_simple (src->src_caps, "content-type", G_TYPE_STRING, value, NULL); } } if (params != NULL) g_hash_table_destroy (params); if ((value = soup_message_headers_get_one (msg->response_headers, "icy-name")) != NULL) { g_free (src->iradio_name); src->iradio_name = gst_soup_http_src_unicodify (value); if (src->iradio_name) { g_object_notify (G_OBJECT (src), "iradio-name"); gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_ORGANIZATION, src->iradio_name, NULL); } } if ((value = soup_message_headers_get_one (msg->response_headers, "icy-genre")) != NULL) { g_free (src->iradio_genre); src->iradio_genre = gst_soup_http_src_unicodify (value); if (src->iradio_genre) { g_object_notify (G_OBJECT (src), "iradio-genre"); gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_GENRE, src->iradio_genre, NULL); } } if ((value = soup_message_headers_get_one (msg->response_headers, "icy-url")) != NULL) { g_free (src->iradio_url); src->iradio_url = gst_soup_http_src_unicodify (value); if (src->iradio_url) { g_object_notify (G_OBJECT (src), "iradio-url"); gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_LOCATION, src->iradio_url, NULL); } } if (!gst_tag_list_is_empty (tag_list)) { GST_DEBUG_OBJECT (src, "calling gst_element_found_tags with %" GST_PTR_FORMAT, tag_list); gst_element_found_tags (GST_ELEMENT_CAST (src), tag_list); } else { gst_tag_list_free (tag_list); } /* Handle HTTP errors. */ gst_soup_http_src_parse_status (msg, src); /* Check if Range header was respected. */ if (src->ret == GST_FLOW_CUSTOM_ERROR && src->read_position && msg->status_code != SOUP_STATUS_PARTIAL_CONTENT) { src->seekable = FALSE; GST_ELEMENT_ERROR (src, RESOURCE, SEEK, (_("Server does not support seeking.")), ("Server does not accept Range HTTP header, URL: %s", src->location)); src->ret = GST_FLOW_ERROR; } }
static GstFlowReturn gst_app_src_create (GstBaseSrc * bsrc, guint64 offset, guint size, GstBuffer ** buf) { GstAppSrc *appsrc = GST_APP_SRC_CAST (bsrc); GstAppSrcPrivate *priv = appsrc->priv; GstFlowReturn ret; GstCaps *caps; GST_OBJECT_LOCK (appsrc); caps = priv->caps ? gst_caps_ref (priv->caps) : NULL; if (G_UNLIKELY (priv->size != bsrc->segment.duration && bsrc->segment.format == GST_FORMAT_BYTES)) { GST_DEBUG_OBJECT (appsrc, "Size changed from %" G_GINT64_FORMAT " to %" G_GINT64_FORMAT, bsrc->segment.duration, priv->size); gst_segment_set_duration (&bsrc->segment, GST_FORMAT_BYTES, priv->size); GST_OBJECT_UNLOCK (appsrc); gst_element_post_message (GST_ELEMENT (appsrc), gst_message_new_duration (GST_OBJECT (appsrc), GST_FORMAT_BYTES, priv->size)); } else { GST_OBJECT_UNLOCK (appsrc); } g_mutex_lock (priv->mutex); /* check flushing first */ if (G_UNLIKELY (priv->flushing)) goto flushing; if (priv->stream_type == GST_APP_STREAM_TYPE_RANDOM_ACCESS) { /* if we are dealing with a random-access stream, issue a seek if the offset * changed. */ if (G_UNLIKELY (priv->offset != offset)) { gboolean res; /* do the seek */ res = gst_app_src_emit_seek (appsrc, offset); if (G_UNLIKELY (!res)) /* failing to seek is fatal */ goto seek_error; priv->offset = offset; } } while (TRUE) { /* return data as long as we have some */ if (!g_queue_is_empty (priv->queue)) { guint buf_size; *buf = g_queue_pop_head (priv->queue); buf_size = GST_BUFFER_SIZE (*buf); GST_DEBUG_OBJECT (appsrc, "we have buffer %p of size %u", *buf, buf_size); priv->queued_bytes -= buf_size; /* only update the offset when in random_access mode */ if (priv->stream_type == GST_APP_STREAM_TYPE_RANDOM_ACCESS) priv->offset += buf_size; if (caps) { *buf = gst_buffer_make_metadata_writable (*buf); gst_buffer_set_caps (*buf, caps); } /* signal that we removed an item */ g_cond_broadcast (priv->cond); /* see if we go lower than the empty-percent */ if (priv->min_percent && priv->max_bytes) { if (priv->queued_bytes * 100 / priv->max_bytes <= priv->min_percent) /* ignore flushing state, we got a buffer and we will return it now. * Errors will be handled in the next round */ gst_app_src_emit_need_data (appsrc, size); } ret = GST_FLOW_OK; break; } else { gst_app_src_emit_need_data (appsrc, size); /* we can be flushing now because we released the lock above */ if (G_UNLIKELY (priv->flushing)) goto flushing; /* if we have a buffer now, continue the loop and try to return it. In * random-access mode (where a buffer is normally pushed in the above * signal) we can still be empty because the pushed buffer got flushed or * when the application pushes the requested buffer later, we support both * possiblities. */ if (!g_queue_is_empty (priv->queue)) continue; /* no buffer yet, maybe we are EOS, if not, block for more data. */ } /* check EOS */ if (G_UNLIKELY (priv->is_eos)) goto eos; /* nothing to return, wait a while for new data or flushing. */ g_cond_wait (priv->cond, priv->mutex); } g_mutex_unlock (priv->mutex); if (caps) gst_caps_unref (caps); return ret; /* ERRORS */ flushing: { GST_DEBUG_OBJECT (appsrc, "we are flushing"); g_mutex_unlock (priv->mutex); if (caps) gst_caps_unref (caps); return GST_FLOW_WRONG_STATE; } eos: { GST_DEBUG_OBJECT (appsrc, "we are EOS"); g_mutex_unlock (priv->mutex); if (caps) gst_caps_unref (caps); return GST_FLOW_UNEXPECTED; } seek_error: { g_mutex_unlock (priv->mutex); if (caps) gst_caps_unref (caps); GST_ELEMENT_ERROR (appsrc, RESOURCE, READ, ("failed to seek"), GST_ERROR_SYSTEM); return GST_FLOW_ERROR; } }
static gboolean gst_musepack_stream_init (GstMusepackDec * musepackdec) { mpc_streaminfo i; GstTagList *tags; GstCaps *caps; /* set up reading */ gst_musepack_init_reader (musepackdec->r, musepackdec); #ifdef MPC_IS_OLD_API /* streaminfo */ mpc_streaminfo_init (&i); if (mpc_streaminfo_read (&i, musepackdec->r) < 0) { GST_ELEMENT_ERROR (musepackdec, STREAM, WRONG_TYPE, (NULL), (NULL)); return FALSE; } /* decoding */ mpc_decoder_setup (musepackdec->d, musepackdec->r); mpc_decoder_scale_output (musepackdec->d, 1.0); if (!mpc_decoder_initialize (musepackdec->d, &i)) { GST_ELEMENT_ERROR (musepackdec, STREAM, WRONG_TYPE, (NULL), (NULL)); return FALSE; } #else musepackdec->d = mpc_demux_init (musepackdec->r); if (!musepackdec->d) { GST_ELEMENT_ERROR (musepackdec, STREAM, WRONG_TYPE, (NULL), (NULL)); return FALSE; } mpc_demux_get_info (musepackdec->d, &i); #endif /* capsnego */ caps = gst_caps_from_string (BASE_CAPS); gst_caps_set_simple (caps, "endianness", G_TYPE_INT, G_BYTE_ORDER, "channels", G_TYPE_INT, i.channels, "rate", G_TYPE_INT, i.sample_freq, NULL); gst_pad_use_fixed_caps (musepackdec->srcpad); if (!gst_pad_set_caps (musepackdec->srcpad, caps)) { GST_ELEMENT_ERROR (musepackdec, CORE, NEGOTIATION, (NULL), (NULL)); return FALSE; } g_atomic_int_set (&musepackdec->bps, 4 * i.channels); g_atomic_int_set (&musepackdec->rate, i.sample_freq); gst_segment_set_last_stop (&musepackdec->segment, GST_FORMAT_DEFAULT, 0); gst_segment_set_duration (&musepackdec->segment, GST_FORMAT_DEFAULT, mpc_streaminfo_get_length_samples (&i)); /* send basic tags */ tags = gst_tag_list_new (); gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_AUDIO_CODEC, "Musepack", NULL); if (i.encoder[0] != '\0' && i.encoder_version > 0) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, i.encoder, GST_TAG_ENCODER_VERSION, i.encoder_version, NULL); } if (i.bitrate > 0) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, i.bitrate, NULL); } else if (i.average_bitrate > 0.0) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, (guint) i.average_bitrate, NULL); } if (i.gain_title != 0 || i.gain_album != 0) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_TRACK_GAIN, (gdouble) i.gain_title / 100.0, GST_TAG_ALBUM_GAIN, (gdouble) i.gain_album / 100.0, NULL); } if (i.peak_title != 0 && i.peak_title != 32767 && i.peak_album != 0 && i.peak_album != 32767) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_TRACK_PEAK, (gdouble) i.peak_title / 32767.0, GST_TAG_ALBUM_PEAK, (gdouble) i.peak_album / 32767.0, NULL); } GST_LOG_OBJECT (musepackdec, "Posting tags: %" GST_PTR_FORMAT, tags); gst_element_found_tags (GST_ELEMENT (musepackdec), tags); return TRUE; }