GstCaps * gst_fragment_get_caps (GstFragment * fragment) { g_return_val_if_fail (fragment != NULL, NULL); if (!fragment->completed) return NULL; g_mutex_lock (&fragment->priv->lock); if (fragment->priv->caps == NULL) { guint64 offset, offset_end; /* FIXME: This is currently necessary as typefinding only * works with 0 offsets... need to find a better way to * do that */ offset = GST_BUFFER_OFFSET (fragment->priv->buffer); offset_end = GST_BUFFER_OFFSET_END (fragment->priv->buffer); GST_BUFFER_OFFSET (fragment->priv->buffer) = GST_BUFFER_OFFSET_NONE; GST_BUFFER_OFFSET_END (fragment->priv->buffer) = GST_BUFFER_OFFSET_NONE; fragment->priv->caps = gst_type_find_helper_for_buffer (NULL, fragment->priv->buffer, NULL); GST_BUFFER_OFFSET (fragment->priv->buffer) = offset; GST_BUFFER_OFFSET_END (fragment->priv->buffer) = offset_end; } gst_caps_ref (fragment->priv->caps); g_mutex_unlock (&fragment->priv->lock); return fragment->priv->caps; }
static GstCaps * typefind_test_file (const gchar * filename) { GstBuffer *buf; GError *err = NULL; GstCaps *caps = NULL; gchar *path, *data = NULL; gsize data_len; path = g_build_filename (GST_TEST_FILES_PATH, filename, NULL); GST_LOG ("reading file '%s'", path); if (!g_file_get_contents (path, &data, &data_len, &err)) { g_error ("error loading test file: %s", err->message); } buf = gst_buffer_new (); gst_buffer_append_memory (buf, gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, (gpointer) data, data_len, 0, data_len, NULL, NULL)); GST_BUFFER_OFFSET (buf) = 0; caps = gst_type_find_helper_for_buffer (NULL, buf, NULL); fail_unless (caps != NULL); GST_LOG ("Found type: %" GST_PTR_FORMAT, caps); gst_buffer_unref (buf); g_free (data); g_free (path); return caps; }
static gboolean gst_hls_demux_get_next_fragment (GstHLSDemux * demux) { GstBuffer *buf; guint avail; const gchar *next_fragment_uri; GstClockTime duration; GstClockTime timestamp; gboolean discont; if (!gst_m3u8_client_get_next_fragment (demux->client, &discont, &next_fragment_uri, &duration, ×tamp)) { GST_INFO_OBJECT (demux, "This playlist doesn't contain more fragments"); demux->end_of_playlist = TRUE; gst_task_start (demux->task); return FALSE; } GST_INFO_OBJECT (demux, "Fetching next fragment %s", next_fragment_uri); if (!gst_hls_demux_fetch_location (demux, next_fragment_uri)) { /* FIXME: The gst_m3u8_get_next_fragment increments the sequence number but another thread might call get_next_fragment and this decrement will not redownload the failed fragment, but might duplicate the download of a succeeded fragment */ g_atomic_int_add (&demux->client->sequence, -1); return FALSE; } avail = gst_adapter_available (demux->download); buf = gst_adapter_take_buffer (demux->download, avail); GST_BUFFER_DURATION (buf) = duration; GST_BUFFER_TIMESTAMP (buf) = timestamp; /* We actually need to do this every time we switch bitrate */ if (G_UNLIKELY (demux->do_typefind)) { GstCaps *caps = gst_type_find_helper_for_buffer (NULL, buf, NULL); if (!demux->input_caps || !gst_caps_is_equal (caps, demux->input_caps)) { gst_caps_replace (&demux->input_caps, caps); /* gst_pad_set_caps (demux->srcpad, demux->input_caps); */ GST_INFO_OBJECT (demux, "Input source caps: %" GST_PTR_FORMAT, demux->input_caps); demux->do_typefind = FALSE; } else gst_caps_unref (caps); } gst_buffer_set_caps (buf, demux->input_caps); if (discont) { GST_DEBUG_OBJECT (demux, "Marking fragment as discontinuous"); GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); } g_queue_push_tail (demux->queue, buf); gst_task_start (demux->task); gst_adapter_clear (demux->download); return TRUE; }
static GstFlowReturn gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind) { GstTypeFindProbability probability; GstCaps *caps; if (GST_BUFFER_SIZE (typefind->store) < TYPE_FIND_MIN_SIZE) { GST_DEBUG_OBJECT (typefind, "not enough data for typefinding yet " "(%u bytes)", GST_BUFFER_SIZE (typefind->store)); return GST_FLOW_OK; } caps = gst_type_find_helper_for_buffer (GST_OBJECT (typefind), typefind->store, &probability); if (caps == NULL && GST_BUFFER_SIZE (typefind->store) > TYPE_FIND_MAX_SIZE) { GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL)); stop_typefinding (typefind); return GST_FLOW_ERROR; } else if (caps == NULL) { GST_DEBUG_OBJECT (typefind, "no caps found with %u bytes of data, " "waiting for more data", GST_BUFFER_SIZE (typefind->store)); return GST_FLOW_OK; } /* found a type */ if (probability < typefind->min_probability) { GST_DEBUG_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", but " "probability is %u which is lower than the required minimum of %u", caps, probability, typefind->min_probability); gst_caps_replace (&caps, NULL); if (GST_BUFFER_SIZE (typefind->store) >= TYPE_FIND_MAX_SIZE) { GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL)); stop_typefinding (typefind); return GST_FLOW_ERROR; } GST_DEBUG_OBJECT (typefind, "waiting for more data to try again"); return GST_FLOW_OK; } /* probability is good enough too, so let's make it known ... */ g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, probability, caps); /* .. and send out the accumulated data */ stop_typefinding (typefind); gst_caps_unref (caps); return GST_FLOW_OK; }
static GstFlowReturn gst_type_find_element_chain (GstPad * pad, GstBuffer * buffer) { res = gst_type_find_element_chain_do_typefinding (typefind); { GstCaps *caps; caps = gst_type_find_helper_for_buffer (GST_OBJECT (typefind), typefind->store, &probability); // gstreamer/libs/gst/base/gsttypefindhelper.c // All available typefinders will be called on the data in order of rank. If // a typefinding function returns a probability of #GST_TYPE_FIND_MAXIMUM, // typefinding is stopped immediately and the found caps will be returned // right away. Otherwise, all available typefind functions will the tried, // and the caps with the highest probability will be returned { type_list = gst_type_find_factory_get_list (); type_list = g_list_sort (type_list, type_find_factory_rank_cmp); gst_type_find_factory_call_function (helper.factory, &find); { // find function from factory new_factory = GST_TYPE_FIND_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE (factory))); new_factory->function (find, new_factory->user_data); gst_object_unref (new_factory); } // gst_type_find_factory_call_function() } // gst_type_find_helper_for_buffer() /* probability is good enough too, so let's make it known ... */ g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, probability, caps); // stop typefind stop_typefinding (typefind); { // TODO: why set itself to NULL? gst_element_get_state (GST_ELEMENT (typefind), &state, NULL, 0); // reset state to normal typefind->mode = MODE_NORMAL; // send cache event and buffers gst_type_find_element_send_cached_events (typefind); gst_pad_push (typefind->src, typefind->store); } } // gst_type_find_element_chain_do_typefinding() }
static gboolean gst_hls_demux_get_next_fragment (GstHLSDemux * demux, gboolean retry) { GstBuffer *buf; guint avail; const gchar *next_fragment_uri; GstClockTime duration; gboolean discont; if (!gst_m3u8_client_get_next_fragment (demux->client, &discont, &next_fragment_uri, &duration)) { GST_INFO_OBJECT (demux, "This playlist doesn't contain more fragments"); demux->end_of_playlist = TRUE; GST_TASK_SIGNAL (demux->task); return FALSE; } GST_INFO_OBJECT (demux, "Fetching next fragment %s", next_fragment_uri); if (!gst_hls_demux_fetch_location (demux, next_fragment_uri)) return FALSE; avail = gst_adapter_available (demux->download); buf = gst_adapter_take_buffer (demux->download, avail); GST_BUFFER_DURATION (buf) = duration; if (G_UNLIKELY (demux->input_caps == NULL)) { demux->input_caps = gst_type_find_helper_for_buffer (NULL, buf, NULL); if (demux->input_caps) { gst_pad_set_caps (demux->srcpad, demux->input_caps); GST_INFO_OBJECT (demux, "Input source caps: %" GST_PTR_FORMAT, demux->input_caps); } } if (discont) { GST_DEBUG_OBJECT (demux, "Marking fragment as discontinuous"); GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); } g_queue_push_tail (demux->queue, buf); GST_TASK_SIGNAL (demux->task); gst_adapter_clear (demux->download); return TRUE; }
GstCaps * gst_fragment_get_caps (GstFragment * fragment) { g_return_val_if_fail (fragment != NULL, NULL); if (!fragment->completed) return NULL; g_mutex_lock (&fragment->priv->lock); if (fragment->priv->caps == NULL) { GstBuffer *buf = gst_buffer_list_get (fragment->priv->buffer_list, 0, 0); fragment->priv->caps = gst_type_find_helper_for_buffer (NULL, buf, NULL); } gst_caps_ref (fragment->priv->caps); g_mutex_unlock (&fragment->priv->lock); return fragment->priv->caps; }
static GstCaps * typefind_data (const guint8 * data, gsize data_size, GstTypeFindProbability * prob) { GstBuffer *buf; GstCaps *caps; GST_MEMDUMP ("typefind data", data, data_size); buf = gst_buffer_new (); gst_buffer_append_memory (buf, gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, (guint8 *) data, data_size, 0, data_size, NULL, NULL)); GST_BUFFER_OFFSET (buf) = 0; caps = gst_type_find_helper_for_buffer (NULL, buf, prob); GST_INFO ("caps: %" GST_PTR_FORMAT ", probability=%u", caps, *prob); gst_buffer_unref (buf); return caps; }
static GstFlowReturn gst_icydemux_typefind_or_forward (GstICYDemux * icydemux, GstBuffer * buf) { if (icydemux->typefinding) { GstBuffer *tf_buf; GstCaps *caps = NULL; GstTypeFindProbability prob; /* If we have a content-type from upstream, let's see if we can shortcut * typefinding */ if (G_UNLIKELY (icydemux->content_type)) { if (!g_ascii_strcasecmp (icydemux->content_type, "video/nsv")) { GST_DEBUG ("We have a NSV stream"); caps = gst_caps_new_simple ("video/x-nsv", NULL); } else { GST_DEBUG ("Upstream Content-Type isn't supported"); g_free (icydemux->content_type); icydemux->content_type = NULL; } } if (icydemux->typefind_buf) { icydemux->typefind_buf = gst_buffer_join (icydemux->typefind_buf, buf); } else { icydemux->typefind_buf = buf; } /* Only typefind if we haven't already got some caps */ if (caps == NULL) { caps = gst_type_find_helper_for_buffer (GST_OBJECT (icydemux), icydemux->typefind_buf, &prob); if (caps == NULL) { if (GST_BUFFER_SIZE (icydemux->typefind_buf) < ICY_TYPE_FIND_MAX_SIZE) { /* Just break for more data */ return GST_FLOW_OK; } /* We failed typefind */ GST_ELEMENT_ERROR (icydemux, STREAM, TYPE_NOT_FOUND, (NULL), ("No caps found for contents within an ICY stream")); gst_buffer_unref (icydemux->typefind_buf); icydemux->typefind_buf = NULL; return GST_FLOW_ERROR; } } if (!gst_icydemux_add_srcpad (icydemux, caps)) { GST_DEBUG_OBJECT (icydemux, "Failed to add srcpad"); gst_caps_unref (caps); gst_buffer_unref (icydemux->typefind_buf); icydemux->typefind_buf = NULL; return GST_FLOW_ERROR; } gst_caps_unref (caps); if (icydemux->cached_events) { gst_icydemux_send_cached_events (icydemux); } if (icydemux->cached_tags) { gst_icydemux_send_tag_event (icydemux, icydemux->cached_tags); icydemux->cached_tags = NULL; } /* Move onto streaming: call ourselves recursively with the typefind buffer * to get that forwarded. */ icydemux->typefinding = FALSE; tf_buf = icydemux->typefind_buf; icydemux->typefind_buf = NULL; return gst_icydemux_typefind_or_forward (icydemux, tf_buf); } else { if (G_UNLIKELY (icydemux->srcpad == NULL)) { gst_buffer_unref (buf); return GST_FLOW_ERROR; } buf = gst_buffer_make_metadata_writable (buf); gst_buffer_set_caps (buf, icydemux->src_caps); /* Most things don't care, and it's a pain to track (we should preserve a * 0 offset on the first buffer though if it's there, for id3demux etc.) */ if (GST_BUFFER_OFFSET (buf) != 0) { GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE; } return gst_pad_push (icydemux->srcpad, buf); } }
/** * gst_tag_image_data_to_image_sample: * @image_data: the (encoded) image * @image_data_len: the length of the encoded image data at @image_data * @image_type: type of the image, or #GST_TAG_IMAGE_TYPE_UNDEFINED. Pass * #GST_TAG_IMAGE_TYPE_NONE if no image type should be set at all (e.g. * for preview images) * * Helper function for tag-reading plugins to create a #GstSample suitable to * add to a #GstTagList as an image tag (such as #GST_TAG_IMAGE or * #GST_TAG_PREVIEW_IMAGE) from the encoded image data and an (optional) image * type. * * Background: cover art and other images in tags are usually stored as a * blob of binary image data, often accompanied by a MIME type or some other * content type string (e.g. 'png', 'jpeg', 'jpg'). Sometimes there is also an * 'image type' to indicate what kind of image this is (e.g. front cover, * back cover, artist, etc.). The image data may also be an URI to the image * rather than the image itself. * * In GStreamer, image tags are #GstSample<!-- -->s containing the raw image * data, with the sample caps describing the content type of the image * (e.g. image/jpeg, image/png, text/uri-list). The sample info may contain * an additional 'image-type' field of #GST_TYPE_TAG_IMAGE_TYPE to describe * the type of image (front cover, back cover etc.). #GST_TAG_PREVIEW_IMAGE * tags should not carry an image type, their type is already indicated via * the special tag name. * * This function will do various checks and typefind the encoded image * data (we can't trust the declared mime type). * * Returns: a newly-allocated image sample for use in tag lists, or NULL */ GstSample * gst_tag_image_data_to_image_sample (const guint8 * image_data, guint image_data_len, GstTagImageType image_type) { const gchar *name; GstBuffer *image; GstSample *sample; GstCaps *caps; GstMapInfo info; GstStructure *image_info = NULL; g_return_val_if_fail (image_data != NULL, NULL); g_return_val_if_fail (image_data_len > 0, NULL); g_return_val_if_fail (gst_tag_image_type_is_valid (image_type), NULL); GST_DEBUG ("image data len: %u bytes", image_data_len); /* allocate space for a NUL terminator for an uri too */ image = gst_buffer_new_and_alloc (image_data_len + 1); if (image == NULL) goto alloc_failed; gst_buffer_map (image, &info, GST_MAP_WRITE); memcpy (info.data, image_data, image_data_len); info.data[image_data_len] = '\0'; gst_buffer_unmap (image, &info); /* Find GStreamer media type, can't trust declared type */ caps = gst_type_find_helper_for_buffer (NULL, image, NULL); if (caps == NULL) goto no_type; GST_DEBUG ("Found GStreamer media type: %" GST_PTR_FORMAT, caps); /* sanity check: make sure typefound/declared caps are either URI or image */ name = gst_structure_get_name (gst_caps_get_structure (caps, 0)); if (!g_str_has_prefix (name, "image/") && !g_str_has_prefix (name, "video/") && !g_str_equal (name, "text/uri-list")) { GST_DEBUG ("Unexpected image type '%s', ignoring image frame", name); goto error; } /* Decrease size by 1 if we don't have an URI list * to keep the original size of the image */ if (!g_str_equal (name, "text/uri-list")) gst_buffer_set_size (image, image_data_len); if (image_type != GST_TAG_IMAGE_TYPE_NONE) { GST_LOG ("Setting image type: %d", image_type); image_info = gst_structure_new ("GstTagImageInfo", "image-type", GST_TYPE_TAG_IMAGE_TYPE, image_type, NULL); } sample = gst_sample_new (image, caps, NULL, image_info); gst_buffer_unref (image); gst_caps_unref (caps); return sample; /* ERRORS */ no_type: { GST_DEBUG ("Could not determine GStreamer media type, ignoring image"); /* fall through */ } error: { if (image) gst_buffer_unref (image); if (caps) gst_caps_unref (caps); return NULL; } alloc_failed: { GST_WARNING ("failed to allocate buffer of %d for image", image_data_len); gst_buffer_unref (image); return NULL; } }
static gboolean gst_data_uri_src_set_uri (GstURIHandler * handler, const gchar * uri, GError ** error) { GstDataURISrc *src = GST_DATA_URI_SRC (handler); gboolean ret = FALSE; gchar *mimetype = NULL; const gchar *parameters_start; const gchar *data_start; const gchar *orig_uri = uri; GstCaps *caps; GstBuffer *buffer; gboolean base64 = FALSE; gchar *charset = NULL; gpointer bdata; gsize bsize; GST_OBJECT_LOCK (src); if (GST_STATE (src) >= GST_STATE_PAUSED) goto wrong_state; GST_OBJECT_UNLOCK (src); /* uri must be an URI as defined in RFC 2397 * data:[<mediatype>][;base64],<data> */ if (strncmp ("data:", uri, 5) != 0) goto invalid_uri; uri += 5; parameters_start = strchr (uri, ';'); data_start = strchr (uri, ','); if (data_start == NULL) goto invalid_uri; if (data_start != uri && parameters_start != uri) mimetype = g_strndup (uri, (parameters_start ? parameters_start : data_start) - uri); else mimetype = g_strdup ("text/plain"); GST_DEBUG_OBJECT (src, "Mimetype: %s", mimetype); if (parameters_start != NULL) { gchar **walk; gchar *parameters = g_strndup (parameters_start + 1, data_start - parameters_start - 1); gchar **parameters_strv; parameters_strv = g_strsplit (parameters, ";", -1); GST_DEBUG_OBJECT (src, "Parameters: "); walk = parameters_strv; while (*walk) { GST_DEBUG_OBJECT (src, "\t %s", *walk); if (strcmp ("base64", *walk) == 0) { base64 = TRUE; } else if (strncmp ("charset=", *walk, 8) == 0) { charset = g_strdup (*walk + 8); } walk++; } g_free (parameters); g_strfreev (parameters_strv); } /* Skip comma */ data_start += 1; if (base64) { bdata = g_base64_decode (data_start, &bsize); } else { /* URI encoded, i.e. "percent" encoding */ bdata = g_uri_unescape_string (data_start, NULL); if (bdata == NULL) goto invalid_uri_encoded_data; bsize = strlen (bdata) + 1; } /* Convert to UTF8 */ if (strcmp ("text/plain", mimetype) == 0 && charset && g_ascii_strcasecmp ("US-ASCII", charset) != 0 && g_ascii_strcasecmp ("UTF-8", charset) != 0) { gsize read; gsize written; gpointer data; data = g_convert_with_fallback (bdata, -1, "UTF-8", charset, (char *) "*", &read, &written, NULL); g_free (bdata); bdata = data; bsize = written; } buffer = gst_buffer_new_wrapped (bdata, bsize); caps = gst_type_find_helper_for_buffer (GST_OBJECT (src), buffer, NULL); if (!caps) caps = gst_caps_new_empty_simple (mimetype); gst_base_src_set_caps (GST_BASE_SRC_CAST (src), caps); gst_caps_unref (caps); GST_OBJECT_LOCK (src); gst_buffer_replace (&src->buffer, buffer); gst_buffer_unref (buffer); g_free (src->uri); src->uri = g_strdup (orig_uri); GST_OBJECT_UNLOCK (src); ret = TRUE; out: g_free (mimetype); g_free (charset); return ret; wrong_state: { GST_WARNING_OBJECT (src, "Can't set URI in %s state", gst_element_state_get_name (GST_STATE (src))); GST_OBJECT_UNLOCK (src); g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_STATE, "Changing the 'uri' property on dataurisrc while it is running " "is not supported"); goto out; } invalid_uri: { GST_WARNING_OBJECT (src, "invalid URI '%s'", uri); g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, "Invalid data URI"); goto out; } invalid_uri_encoded_data: { GST_WARNING_OBJECT (src, "Failed to parse data encoded in URI '%s'", uri); g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, "Could not parse data encoded in data URI"); goto out; } }
static gboolean gst_type_find_element_handle_event (GstPad * pad, GstEvent * event) { gboolean res = FALSE; GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad)); GST_DEBUG_OBJECT (typefind, "got %s event in mode %d", GST_EVENT_TYPE_NAME (event), typefind->mode); switch (typefind->mode) { case MODE_TYPEFIND: switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS:{ GstTypeFindProbability prob = 0; GstCaps *caps = NULL; GST_INFO_OBJECT (typefind, "Got EOS and no type found yet"); /* we might not have started typefinding yet because there was not * enough data so far; just give it a shot now and see what we get */ if (typefind->store) { caps = gst_type_find_helper_for_buffer (GST_OBJECT (typefind), typefind->store, &prob); if (caps && prob >= typefind->min_probability) { g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, prob, caps); } else { GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL)); } gst_caps_replace (&caps, NULL); } else { /* keep message in sync with the one in the pad activate function */ GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (_("Stream contains no data.")), ("Can't typefind empty stream")); } stop_typefinding (typefind); res = gst_pad_push_event (typefind->src, event); break; } case GST_EVENT_FLUSH_STOP: g_list_foreach (typefind->cached_events, (GFunc) gst_mini_object_unref, NULL); g_list_free (typefind->cached_events); typefind->cached_events = NULL; gst_buffer_replace (&typefind->store, NULL); /* fall through */ case GST_EVENT_FLUSH_START: res = gst_pad_push_event (typefind->src, event); break; default: GST_DEBUG_OBJECT (typefind, "Saving %s event to send later", GST_EVENT_TYPE_NAME (event)); typefind->cached_events = g_list_append (typefind->cached_events, event); res = TRUE; break; } break; case MODE_NORMAL: res = gst_pad_push_event (typefind->src, event); break; case MODE_ERROR: break; default: g_assert_not_reached (); } return res; }
static GstFlowReturn gst_bz2dec_chain (GstPad * pad, GstBuffer * in) { GstFlowReturn flow; GstBuffer *out; GstBz2dec *b; int r = BZ_OK; b = GST_BZ2DEC (GST_PAD_PARENT (pad)); if (!b->ready) goto not_ready; b->stream.next_in = (char *) GST_BUFFER_DATA (in); b->stream.avail_in = GST_BUFFER_SIZE (in); do { guint n; /* Create the output buffer */ flow = gst_pad_alloc_buffer (b->src, b->offset, b->offset ? b->buffer_size : b->first_buffer_size, GST_PAD_CAPS (b->src), &out); if (flow != GST_FLOW_OK) { GST_DEBUG_OBJECT (b, "pad alloc failed: %s", gst_flow_get_name (flow)); gst_bz2dec_decompress_init (b); break; } /* Decode */ b->stream.next_out = (char *) GST_BUFFER_DATA (out); b->stream.avail_out = GST_BUFFER_SIZE (out); r = BZ2_bzDecompress (&b->stream); if ((r != BZ_OK) && (r != BZ_STREAM_END)) goto decode_failed; if (b->stream.avail_out >= GST_BUFFER_SIZE (out)) { gst_buffer_unref (out); break; } GST_BUFFER_SIZE (out) -= b->stream.avail_out; GST_BUFFER_OFFSET (out) = b->stream.total_out_lo32 - GST_BUFFER_SIZE (out); /* Configure source pad (if necessary) */ if (!b->offset) { GstCaps *caps = NULL; caps = gst_type_find_helper_for_buffer (GST_OBJECT (b), out, NULL); if (caps) { gst_buffer_set_caps (out, caps); gst_pad_set_caps (b->src, caps); gst_pad_use_fixed_caps (b->src); gst_caps_unref (caps); } else { /* FIXME: shouldn't we queue output buffers until we have a type? */ } } /* Push data */ n = GST_BUFFER_SIZE (out); flow = gst_pad_push (b->src, out); if (flow != GST_FLOW_OK) break; b->offset += n; } while (r != BZ_STREAM_END); done: gst_buffer_unref (in); return flow; /* ERRORS */ decode_failed: { GST_ELEMENT_ERROR (b, STREAM, DECODE, (NULL), ("Failed to decompress data (error code %i).", r)); gst_bz2dec_decompress_init (b); gst_buffer_unref (out); flow = GST_FLOW_ERROR; goto done; } not_ready: { GST_ELEMENT_ERROR (b, LIBRARY, FAILED, (NULL), ("Decompressor not ready.")); flow = GST_FLOW_WRONG_STATE; goto done; } }