Пример #1
0
static void
gst_hls_sink_dispose (GObject * object)
{
  GstHlsSink *sink = GST_HLS_SINK_CAST (object);

  G_OBJECT_CLASS (parent_class)->dispose ((GObject *) sink);
}
Пример #2
0
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;
  }
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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);
}
Пример #6
0
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;
}
Пример #7
0
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;
}
Пример #8
0
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;
  }
}
Пример #9
0
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,
          &timestamp, &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;
}
Пример #10
0
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);
}