hls: Add a GstFragment class that represents a fragment in a m3u playlist
authorAndoni Morales Alastruey <ylatuya@gmail.com>
Thu, 7 Jul 2011 23:09:00 +0000 (01:09 +0200)
committerThibault Saunier <thibault.saunier@collabora.com>
Thu, 5 Apr 2012 14:15:12 +0000 (10:15 -0400)
gst/hls/Makefile.am
gst/hls/gstfragment.c [new file with mode: 0644]
gst/hls/gstfragment.h [new file with mode: 0644]

index fec8eeb..7a82975 100644 (file)
@@ -4,6 +4,7 @@ plugin_LTLIBRARIES = libgstfragmented.la
 libgstfragmented_la_SOURCES =                  \
        m3u8.c                                  \
        gsthlsdemux.c                           \
+       gstfragment.c                           \
        gstfragmentedplugin.c
 
 libgstfragmented_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(SOUP_CFLAGS)
@@ -14,6 +15,7 @@ libgstfragmented_la_LIBTOOLFLAGS = --tag=disable-static
 # headers we need but don't want installed
 noinst_HEADERS =                       \
        gstfragmented.h         \
+       gstfragment.h                           \
        gsthlsdemux.h                   \
        m3u8.h
 
diff --git a/gst/hls/gstfragment.c b/gst/hls/gstfragment.c
new file mode 100644 (file)
index 0000000..210a930
--- /dev/null
@@ -0,0 +1,226 @@
+/* GStreamer
+ * Copyright (C) 2011 Andoni Morales Alastruey <ylatuya@gmail.com>
+ *
+ * gstfragment.c:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+#include "gstfragmented.h"
+#include "gstfragment.h"
+
+#define GST_CAT_DEFAULT fragmented_debug
+
+#define GST_FRAGMENT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_FRAGMENT, GstFragmentPrivate))
+
+enum
+{
+  PROP_0,
+  PROP_INDEX,
+  PROP_NAME,
+  PROP_DURATION,
+  PROP_DISCONTINOUS,
+  PROP_BUFFER_LIST,
+  PROP_LAST
+};
+
+struct _GstFragmentPrivate
+{
+  GstBufferList *buffer_list;
+  GstBufferListIterator *buffer_iterator;
+  gboolean can_set_headers;
+  gboolean has_headers;
+};
+
+G_DEFINE_TYPE (GstFragment, gst_fragment, G_TYPE_OBJECT);
+
+static void gst_fragment_dispose (GObject * object);
+static void gst_fragment_finalize (GObject * object);
+
+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_LIST:
+      g_value_set_object (value, gst_fragment_get_buffer_list (fragment));
+      break;
+
+    default:
+      /* We don't have any other property... */
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_fragment_class_init (GstFragmentClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GstFragmentPrivate));
+
+  gobject_class->get_property = gst_fragment_get_property;
+  gobject_class->dispose = gst_fragment_dispose;
+  gobject_class->finalize = gst_fragment_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_INDEX,
+      g_param_spec_uint ("index", "Index", "Index of the fragment", 0,
+          G_MAXUINT, 0, G_PARAM_READABLE));
+
+  g_object_class_install_property (gobject_class, PROP_NAME,
+      g_param_spec_string ("name", "Name",
+          "Name of the fragment (eg:fragment-12.ts)", NULL, G_PARAM_READABLE));
+
+  g_object_class_install_property (gobject_class, PROP_DISCONTINOUS,
+      g_param_spec_boolean ("discontinuous", "Discontinous",
+          "Whether this fragment has a discontinuity or not",
+          FALSE, G_PARAM_READABLE));
+
+  g_object_class_install_property (gobject_class, PROP_DURATION,
+      g_param_spec_uint64 ("duration", "Fragment duration",
+          "Duration of the fragment", 0, G_MAXUINT64, 0, G_PARAM_READABLE));
+
+  g_object_class_install_property (gobject_class, PROP_BUFFER_LIST,
+      g_param_spec_object ("buffer-list", "Buffer List",
+          "A list with the fragment's buffers", GST_TYPE_FRAGMENT,
+          G_PARAM_READABLE));
+}
+
+static void
+gst_fragment_init (GstFragment * fragment)
+{
+  GstFragmentPrivate *priv;
+
+  fragment->priv = priv = GST_FRAGMENT_GET_PRIVATE (fragment);
+  fragment->priv->buffer_list = gst_buffer_list_new ();
+  fragment->priv->buffer_iterator =
+      gst_buffer_list_iterate (fragment->priv->buffer_list);
+  gst_buffer_list_iterator_add_group (fragment->priv->buffer_iterator);
+  fragment->priv->can_set_headers = TRUE;
+  fragment->priv->has_headers = FALSE;
+  fragment->download_start_time = g_get_real_time ();
+  fragment->start_time = 0;
+  fragment->stop_time = 0;
+  fragment->index = 0;
+  fragment->name = g_strdup ("");
+  fragment->completed = FALSE;
+  fragment->discontinuous = FALSE;
+}
+
+GstFragment *
+gst_fragment_new (void)
+{
+  return GST_FRAGMENT (g_object_new (GST_TYPE_FRAGMENT, NULL));
+}
+
+static void
+gst_fragment_finalize (GObject * gobject)
+{
+  GstFragment *fragment = GST_FRAGMENT (gobject);
+
+  g_free (fragment->name);
+
+  G_OBJECT_CLASS (gst_fragment_parent_class)->finalize (gobject);
+}
+
+void
+gst_fragment_dispose (GObject * object)
+{
+  GstFragment *fragment = GST_FRAGMENT (object);
+
+  if (fragment->priv->buffer_list != NULL) {
+    gst_buffer_list_iterator_free (fragment->priv->buffer_iterator);
+    gst_buffer_list_unref (fragment->priv->buffer_list);
+    fragment->priv->buffer_list = NULL;
+  }
+
+  G_OBJECT_CLASS (gst_fragment_parent_class)->dispose (object);
+}
+
+GstBufferList *
+gst_fragment_get_buffer_list (GstFragment * fragment)
+{
+  g_return_val_if_fail (fragment != NULL, NULL);
+
+  if (!fragment->completed)
+    return NULL;
+
+  gst_buffer_list_ref (fragment->priv->buffer_list);
+  return fragment->priv->buffer_list;
+}
+
+gboolean
+gst_fragment_set_headers (GstFragment * fragment, GstBuffer ** buffer,
+    guint count)
+{
+  guint i;
+
+  g_return_val_if_fail (fragment != NULL, FALSE);
+  g_return_val_if_fail (buffer != NULL, FALSE);
+
+  if (!fragment->priv->can_set_headers)
+    return FALSE;
+
+  for (i = 0; i < count; i++) {
+    gst_buffer_ref (buffer[i]);
+    gst_buffer_list_iterator_add (fragment->priv->buffer_iterator, buffer[i]);
+    gst_buffer_list_iterator_add_group (fragment->priv->buffer_iterator);
+  }
+  fragment->priv->has_headers = TRUE;
+  return TRUE;
+}
+
+gboolean
+gst_fragment_add_buffer (GstFragment * fragment, GstBuffer * buffer)
+{
+  g_return_val_if_fail (fragment != NULL, FALSE);
+  g_return_val_if_fail (buffer != NULL, FALSE);
+
+  if (fragment->completed) {
+    GST_WARNING ("Fragment is completed, could not add more buffers");
+    return FALSE;
+  }
+
+  /* if this is the first buffer forbid setting the headers anymore */
+  if (G_UNLIKELY (fragment->priv->can_set_headers)) {
+    fragment->priv->can_set_headers = FALSE;
+  }
+
+  GST_DEBUG ("Adding new buffer to the fragment");
+  gst_buffer_ref (buffer);
+  gst_buffer_list_iterator_add (fragment->priv->buffer_iterator, buffer);
+  return TRUE;
+}
diff --git a/gst/hls/gstfragment.h b/gst/hls/gstfragment.h
new file mode 100644 (file)
index 0000000..9ea0186
--- /dev/null
@@ -0,0 +1,69 @@
+/* GStreamer
+ * Copyright (C) 2011 Andoni Morales Alastruey <ylatuya@gmail.com>
+ *
+ * gstfragment.h:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GSTFRAGMENT_H__
+#define __GSTFRAGMENT_H__
+
+#include <glib-object.h>
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_FRAGMENT (gst_fragment_get_type())
+#define GST_FRAGMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FRAGMENT,GstFragment))
+#define GST_FRAGMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FRAGMENT,GstFragmentClass))
+#define GST_IS_FRAGMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FRAGMENT))
+#define GST_IS_FRAGMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FRAGMENT))
+
+typedef struct _GstFragment GstFragment;
+typedef struct _GstFragmentPrivate GstFragmentPrivate;
+typedef struct _GstFragmentClass GstFragmentClass;
+
+struct _GstFragment
+{
+  GObject parent;
+
+  gchar * name;                 /* Name of the fragment */
+  gboolean completed;           /* Whether the fragment is complete or not */
+  guint64 download_start_time;  /* Epoch time when the download started */
+  guint64 download_stop_time;   /* Epoch time when the download finished */
+  guint64 start_time;           /* Start time of the fragment */
+  guint64 stop_time;            /* Stop time of the fragment */
+  gboolean index;               /* Index of the fragment */
+  gboolean discontinuous;       /* Whether this fragment is discontinuous or not */
+
+  GstFragmentPrivate *priv;
+};
+
+struct _GstFragmentClass
+{
+  GObjectClass parent_class;
+};
+
+GType gst_fragment_get_type (void);
+
+GstBufferList * gst_fragment_get_buffer_list (GstFragment *fragment);
+gboolean gst_fragment_set_headers (GstFragment *fragment, GstBuffer **buffer, guint count);
+gboolean gst_fragment_add_buffer (GstFragment *fragment, GstBuffer *buffer);
+GstFragment * gst_fragment_new (void);
+
+G_END_DECLS
+#endif /* __GSTFRAGMENT_H__ */