5f1931688fa476f5f7867f82eb6645df3f993fb5
[platform/upstream/gstreamer.git] / ext / smoothstreaming / gstmssdemux.c
1 /* GStreamer
2  * Copyright (C) 2012 Smart TV Alliance
3  *  Author: Thiago Sousa Santos <thiago.sousa.santos@collabora.com>, Collabora Ltd.
4  *
5  * gstmssdemux.c:
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /**
24  * SECTION:element-mssdemux
25  *
26  * Demuxes a Microsoft's Smooth Streaming manifest into its audio and/or video streams.
27  *
28  * TODO
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include "gst/gst-i18n-plugin.h"
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include "gstmssdemux.h"
42
43 GST_DEBUG_CATEGORY (mssdemux_debug);
44
45 static GstStaticPadTemplate gst_mss_demux_sink_template =
46 GST_STATIC_PAD_TEMPLATE ("sink",
47     GST_PAD_SINK,
48     GST_PAD_ALWAYS,
49     GST_STATIC_CAPS ("application/vnd.ms-sstr+xml")
50     );
51
52 static GstStaticPadTemplate gst_mss_demux_videosrc_template =
53 GST_STATIC_PAD_TEMPLATE ("video_%02u",
54     GST_PAD_SRC,
55     GST_PAD_SOMETIMES,
56     GST_STATIC_CAPS_ANY);
57
58 static GstStaticPadTemplate gst_mss_demux_audiosrc_template =
59 GST_STATIC_PAD_TEMPLATE ("audio_%02u",
60     GST_PAD_SRC,
61     GST_PAD_SOMETIMES,
62     GST_STATIC_CAPS_ANY);
63
64 GST_BOILERPLATE (GstMssDemux, gst_mss_demux, GstMssDemux, GST_TYPE_ELEMENT);
65
66 static void gst_mss_demux_dispose (GObject * object);
67 static GstStateChangeReturn
68 gst_mss_demux_change_state (GstElement * element, GstStateChange transition);
69 static GstFlowReturn gst_mss_demux_chain (GstPad * pad, GstBuffer * buffer);
70 static GstFlowReturn gst_mss_demux_event (GstPad * pad, GstEvent * event);
71
72 static void gst_mss_demux_process_manifest (GstMssDemux * mssdemux);
73
74 static void
75 gst_mss_demux_base_init (gpointer klass)
76 {
77   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
78
79   gst_element_class_add_static_pad_template (element_class,
80       &gst_mss_demux_sink_template);
81   gst_element_class_add_static_pad_template (element_class,
82       &gst_mss_demux_videosrc_template);
83   gst_element_class_add_static_pad_template (element_class,
84       &gst_mss_demux_audiosrc_template);
85   gst_element_class_set_details_simple (element_class, "Smooth Streaming "
86       "demuxer", "Demuxer",
87       "Parse and demultiplex a Smooth Streaming manifest into audio and video "
88       "streams", "Thiago Santos <thiago.sousa.santos@collabora.com>");
89
90   GST_DEBUG_CATEGORY_INIT (mssdemux_debug, "mssdemux", 0, "mssdemux plugin");
91 }
92
93 static void
94 gst_mss_demux_class_init (GstMssDemuxClass * klass)
95 {
96   GObjectClass *gobject_class;
97   GstElementClass *gstelement_class;
98
99   gobject_class = (GObjectClass *) klass;
100   gstelement_class = (GstElementClass *) klass;
101
102   parent_class = g_type_class_peek_parent (klass);
103
104   gobject_class->dispose = gst_mss_demux_dispose;
105
106   gstelement_class->change_state =
107       GST_DEBUG_FUNCPTR (gst_mss_demux_change_state);
108 }
109
110 static void
111 gst_mss_demux_init (GstMssDemux * mssdemux, GstMssDemuxClass * klass)
112 {
113   mssdemux->sinkpad =
114       gst_pad_new_from_static_template (&gst_mss_demux_sink_template, "sink");
115   gst_pad_set_chain_function (mssdemux->sinkpad,
116       GST_DEBUG_FUNCPTR (gst_mss_demux_chain));
117   gst_pad_set_event_function (mssdemux->sinkpad,
118       GST_DEBUG_FUNCPTR (gst_mss_demux_event));
119   gst_element_add_pad (GST_ELEMENT_CAST (mssdemux), mssdemux->sinkpad);
120 }
121
122 static void
123 gst_mss_demux_reset (GstMssDemux * mssdemux)
124 {
125   if (mssdemux->manifest_buffer) {
126     gst_buffer_unref (mssdemux->manifest_buffer);
127   }
128   if (mssdemux->manifest) {
129     gst_mss_manifest_free (mssdemux->manifest);
130   }
131 }
132
133 static void
134 gst_mss_demux_dispose (GObject * object)
135 {
136   /* GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (object); */
137
138   G_OBJECT_CLASS (parent_class)->dispose (object);
139 }
140
141 static GstStateChangeReturn
142 gst_mss_demux_change_state (GstElement * element, GstStateChange transition)
143 {
144   GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (element);
145   GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
146
147   switch (transition) {
148     case GST_STATE_CHANGE_PAUSED_TO_READY:
149       break;
150     case GST_STATE_CHANGE_READY_TO_NULL:
151       gst_mss_demux_reset (mssdemux);
152       break;
153     default:
154       break;
155   }
156
157   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
158
159   switch (transition) {
160     case GST_STATE_CHANGE_PAUSED_TO_READY:{
161       break;
162     }
163     default:
164       break;
165   }
166
167   return result;
168 }
169
170 static GstFlowReturn
171 gst_mss_demux_chain (GstPad * pad, GstBuffer * buffer)
172 {
173   GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (GST_PAD_PARENT (pad));
174   if (mssdemux->manifest_buffer == NULL)
175     mssdemux->manifest_buffer = buffer;
176   else
177     mssdemux->manifest_buffer =
178         gst_buffer_join (mssdemux->manifest_buffer, buffer);
179
180   return GST_FLOW_OK;
181 }
182
183 static gboolean
184 gst_mss_demux_event (GstPad * pad, GstEvent * event)
185 {
186   GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (GST_PAD_PARENT (pad));
187   gboolean forward = TRUE;
188   gboolean ret = TRUE;
189
190   switch (GST_EVENT_TYPE (event)) {
191     case GST_EVENT_EOS:
192       if (mssdemux->manifest_buffer == NULL) {
193         GST_WARNING_OBJECT (mssdemux, "Received EOS without a manifest.");
194         break;
195       }
196
197       gst_mss_demux_process_manifest (mssdemux);
198       forward = FALSE;
199       break;
200     default:
201       break;
202   }
203
204   if (forward) {
205     ret = gst_pad_event_default (pad, event);
206   } else {
207     gst_event_unref (event);
208   }
209
210   return ret;
211 }
212
213 static void
214 gst_mss_demux_process_manifest (GstMssDemux * mssdemux)
215 {
216   g_return_if_fail (mssdemux->manifest_buffer != NULL);
217   g_return_if_fail (mssdemux->manifest == NULL);
218
219   mssdemux->manifest = gst_mss_manifest_new (mssdemux->manifest_buffer);
220   /* TODO */
221 }