static void gst_fragment_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) { GstFragment *fragment = GST_FRAGMENT (object); switch (property_id) { case PROP_INDEX: g_value_set_uint (value, fragment->index); break; case PROP_NAME: g_value_set_string (value, fragment->name); break; case PROP_DURATION: g_value_set_uint64 (value, fragment->stop_time - fragment->start_time); break; case PROP_DISCONTINOUS: g_value_set_boolean (value, fragment->discontinuous); break; case PROP_BUFFER: g_value_take_boxed (value, gst_fragment_get_buffer (fragment)); break; case PROP_CAPS: g_value_take_boxed (value, gst_fragment_get_caps (fragment)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } }
static void gst_hls_demux_stream_loop (GstHLSDemux * demux) { GstFragment *fragment; GstBuffer *buf; GstFlowReturn ret; GstCaps *bufcaps, *srccaps = NULL; /* Loop for the source pad task. The task is started when we have * received the main playlist from the source element. It tries first to * cache the first fragments and then it waits until it has more data in the * queue. This task is woken up when we push a new fragment to the queue or * when we reached the end of the playlist */ if (G_UNLIKELY (demux->need_cache)) { if (!gst_hls_demux_cache_fragments (demux)) goto cache_error; /* we can start now the updates thread (only if on playing) */ if (GST_STATE (demux) == GST_STATE_PLAYING) gst_task_start (demux->updates_task); GST_INFO_OBJECT (demux, "First fragments cached successfully"); } if (g_queue_is_empty (demux->queue)) { if (demux->end_of_playlist) goto end_of_playlist; goto pause_task; } fragment = g_queue_pop_head (demux->queue); buf = gst_fragment_get_buffer (fragment); /* Figure out if we need to create/switch pads */ if (G_LIKELY (demux->srcpad)) srccaps = gst_pad_get_current_caps (demux->srcpad); bufcaps = gst_fragment_get_caps (fragment); if (G_UNLIKELY (!srccaps || !gst_caps_is_equal_fixed (bufcaps, srccaps) || demux->need_segment)) { switch_pads (demux, bufcaps); demux->need_segment = TRUE; } gst_caps_unref (bufcaps); if (G_LIKELY (srccaps)) gst_caps_unref (srccaps); g_object_unref (fragment); if (demux->need_segment) { GstSegment segment; GstClockTime start = GST_BUFFER_PTS (buf); start += demux->position_shift; /* And send a newsegment */ GST_DEBUG_OBJECT (demux, "Sending new-segment. segment start:%" GST_TIME_FORMAT, GST_TIME_ARGS (start)); gst_segment_init (&segment, GST_FORMAT_TIME); segment.start = start; segment.time = start; gst_pad_push_event (demux->srcpad, gst_event_new_segment (&segment)); demux->need_segment = FALSE; demux->position_shift = 0; } ret = gst_pad_push (demux->srcpad, buf); if (ret != GST_FLOW_OK) goto error_pushing; return; end_of_playlist: { GST_DEBUG_OBJECT (demux, "Reached end of playlist, sending EOS"); gst_pad_push_event (demux->srcpad, gst_event_new_eos ()); gst_hls_demux_stop (demux); return; } cache_error: { gst_task_pause (demux->stream_task); if (!demux->cancelled) { GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND, ("Could not cache the first fragments"), (NULL)); gst_hls_demux_stop (demux); } return; } error_pushing: { /* FIXME: handle error */ GST_DEBUG_OBJECT (demux, "Error pushing buffer: %s... stopping task", gst_flow_get_name (ret)); gst_hls_demux_stop (demux); return; } pause_task: { gst_task_pause (demux->stream_task); return; } }
static gboolean gst_hls_demux_get_next_fragment (GstHLSDemux * demux, gboolean caching) { GstFragment *download; const gchar *next_fragment_uri; GstClockTime duration; GstClockTime timestamp; GstBuffer *buf; 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->stream_task); return FALSE; } GST_INFO_OBJECT (demux, "Fetching next fragment %s", next_fragment_uri); download = gst_uri_downloader_fetch_uri (demux->downloader, next_fragment_uri); if (download == NULL) goto error; buf = gst_fragment_get_buffer (download); GST_BUFFER_DURATION (buf) = duration; GST_BUFFER_PTS (buf) = timestamp; /* We actually need to do this every time we switch bitrate */ if (G_UNLIKELY (demux->do_typefind)) { GstCaps *caps = gst_fragment_get_caps (download); 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; } gst_caps_unref (caps); } else { gst_fragment_set_caps (download, 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, download); if (!caching) { GST_TASK_SIGNAL (demux->updates_task); gst_task_start (demux->stream_task); } return TRUE; error: { gst_hls_demux_stop (demux); return FALSE; } }