static void gst_hls_sink_dispose (GObject * object) { GstHlsSink *sink = GST_HLS_SINK_CAST (object); G_OBJECT_CLASS (parent_class)->dispose ((GObject *) sink); }
static void gst_hls_sink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstHlsSink *sink = GST_HLS_SINK_CAST (object); switch (prop_id) { case PROP_LOCATION: g_value_set_string (value, sink->location); break; case PROP_PLAYLIST_LOCATION: g_value_set_string (value, sink->playlist_location); break; case PROP_PLAYLIST_ROOT: g_value_set_string (value, sink->playlist_root); break; case PROP_MAX_FILES: g_value_set_uint (value, sink->max_files); break; case PROP_TARGET_DURATION: g_value_set_uint (value, sink->target_duration); break; case PROP_PLAYLIST_LENGTH: g_value_set_uint (value, sink->playlist_length); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static GstFlowReturn gst_hls_sink_chain_list (GstPad * pad, GstObject * parent, GstBufferList * list) { guint i, len; GstBuffer *buffer; GstFlowReturn ret; GstHlsSink *sink = GST_HLS_SINK_CAST (parent); if (sink->target_duration == 0 || sink->waiting_fku) return gst_proxy_pad_chain_list_default (pad, parent, list); GST_DEBUG_OBJECT (pad, "chaining each group in list as a merged buffer"); len = gst_buffer_list_length (list); ret = GST_FLOW_OK; for (i = 0; i < len; i++) { buffer = gst_buffer_list_get (list, i); if (!sink->waiting_fku) gst_hls_sink_check_schedule_next_key_unit (sink, buffer); ret = gst_pad_chain (pad, gst_buffer_ref (buffer)); if (ret != GST_FLOW_OK) break; } gst_buffer_list_unref (list); return ret; }
static GstStateChangeReturn gst_hls_sink_change_state (GstElement * element, GstStateChange trans) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstHlsSink *sink = GST_HLS_SINK_CAST (element); switch (trans) { case GST_STATE_CHANGE_NULL_TO_READY: if (!gst_hls_sink_create_elements (sink)) { return GST_STATE_CHANGE_FAILURE; } break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, trans); switch (trans) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: gst_hls_sink_reset (sink); break; case GST_STATE_CHANGE_READY_TO_NULL: gst_hls_sink_reset (sink); break; default: break; } return ret; }
static void gst_hls_sink_finalize (GObject * object) { GstHlsSink *sink = GST_HLS_SINK_CAST (object); g_free (sink->location); g_free (sink->playlist_location); g_free (sink->playlist_root); G_OBJECT_CLASS (parent_class)->finalize ((GObject *) sink); }
static GstPadProbeReturn gst_hls_sink_ghost_buffer_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data) { GstHlsSink *sink = GST_HLS_SINK_CAST (data); GstBuffer *buffer = gst_pad_probe_info_get_buffer (info); if (sink->target_duration == 0 || sink->waiting_fku) return GST_PAD_PROBE_OK; gst_hls_sink_check_schedule_next_key_unit (sink, buffer); return GST_PAD_PROBE_OK; }
static GstPadProbeReturn gst_hls_sink_ghost_buffer_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data) { GstHlsSink *sink = GST_HLS_SINK_CAST (data); GstBuffer *buffer = gst_pad_probe_info_get_buffer (info); GstClockTime timestamp; timestamp = GST_BUFFER_TIMESTAMP (buffer); if (sink->target_duration == 0 || !GST_CLOCK_TIME_IS_VALID (timestamp) || sink->waiting_fku) return GST_PAD_PROBE_OK; sink->last_running_time = gst_segment_to_running_time (&sink->segment, GST_FORMAT_TIME, timestamp); schedule_next_key_unit (sink); return GST_PAD_PROBE_OK; }
static void gst_hls_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstHlsSink *sink = GST_HLS_SINK_CAST (object); switch (prop_id) { case PROP_LOCATION: g_free (sink->location); sink->location = g_value_dup_string (value); if (sink->multifilesink) g_object_set (sink->multifilesink, "location", sink->location, NULL); break; case PROP_PLAYLIST_LOCATION: g_free (sink->playlist_location); sink->playlist_location = g_value_dup_string (value); break; case PROP_PLAYLIST_ROOT: g_free (sink->playlist_root); sink->playlist_root = g_value_dup_string (value); break; case PROP_MAX_FILES: sink->max_files = g_value_get_uint (value); if (sink->multifilesink) { g_object_set (sink->multifilesink, "location", sink->location, "next-file", 3, "post-messages", TRUE, "max-files", sink->max_files, NULL); } break; case PROP_TARGET_DURATION: sink->target_duration = g_value_get_uint (value); break; case PROP_PLAYLIST_LENGTH: sink->playlist_length = g_value_get_uint (value); sink->playlist->window_size = sink->playlist_length; break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static GstPadProbeReturn gst_hls_sink_ghost_event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data) { GstHlsSink *sink = GST_HLS_SINK_CAST (data); GstEvent *event = gst_pad_probe_info_get_event (info); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEGMENT: { gst_event_copy_segment (event, &sink->segment); break; } case GST_EVENT_FLUSH_STOP: gst_segment_init (&sink->segment, GST_FORMAT_UNDEFINED); break; case GST_EVENT_CUSTOM_DOWNSTREAM: { GstClockTime timestamp; GstClockTime running_time, stream_time; gboolean all_headers; guint count; if (!gst_video_event_is_force_key_unit (event)) break; gst_event_replace (&sink->force_key_unit_event, event); gst_video_event_parse_downstream_force_key_unit (event, ×tamp, &stream_time, &running_time, &all_headers, &count); GST_INFO_OBJECT (sink, "setting index %d", count); sink->index = count; break; } default: break; } return GST_PAD_PROBE_OK; }
static void gst_hls_sink_handle_message (GstBin * bin, GstMessage * message) { GstHlsSink *sink = GST_HLS_SINK_CAST (bin); switch (message->type) { case GST_MESSAGE_ELEMENT: { const char *filename; GstClockTime running_time, duration; gboolean discont = FALSE; gchar *entry_location; const GstStructure *structure; structure = gst_message_get_structure (message); if (strcmp (gst_structure_get_name (structure), "GstMultiFileSink")) break; filename = gst_structure_get_string (structure, "filename"); gst_structure_get_clock_time (structure, "running-time", &running_time); duration = running_time - sink->last_running_time; sink->last_running_time = running_time; GST_INFO_OBJECT (sink, "COUNT %d", sink->index); if (sink->playlist_root == NULL) entry_location = g_path_get_basename (filename); else { gchar *name = g_path_get_basename (filename); entry_location = g_build_filename (sink->playlist_root, name, NULL); g_free (name); } gst_m3u8_playlist_add_entry (sink->playlist, entry_location, NULL, duration, sink->index, discont); g_free (entry_location); gst_hls_sink_write_playlist (sink); /* multifilesink is starting a new file. It means that upstream sent a key * unit and we can schedule the next key unit now. */ sink->waiting_fku = FALSE; schedule_next_key_unit (sink); /* multifilesink is an internal implementation detail. If applications * need a notification, we should probably do our own message */ GST_DEBUG_OBJECT (bin, "dropping message %" GST_PTR_FORMAT, message); gst_message_unref (message); message = NULL; break; } case GST_MESSAGE_EOS:{ sink->playlist->end_list = TRUE; gst_hls_sink_write_playlist (sink); break; } default: break; } if (message) GST_BIN_CLASS (parent_class)->handle_message (bin, message); }