melunko@917
|
1 |
|
melunko@917
|
2 |
#ifdef HAVE_CONFIG_H
|
melunko@917
|
3 |
#include "config.h"
|
melunko@917
|
4 |
#endif
|
melunko@917
|
5 |
|
melunko@917
|
6 |
#include <gst/gst.h>
|
melunko@917
|
7 |
#include <gst/base/gstcollectpads.h>
|
melunko@917
|
8 |
|
melunko@917
|
9 |
#include <stdlib.h>
|
melunko@917
|
10 |
#include <string.h>
|
melunko@917
|
11 |
|
melunko@917
|
12 |
/* gpac includes */
|
melunko@917
|
13 |
#include <gpac/isomedia.h>
|
melunko@917
|
14 |
|
melunko@917
|
15 |
#define GST_TYPE_GPAC_MUX (gst_gpac_mux_get_type())
|
melunko@917
|
16 |
#define GST_GPAC_MUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GPAC_MUX, GstGpacMux))
|
melunko@917
|
17 |
#define GST_GPAC_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GPAC_MUX, GstGpacMux))
|
melunko@917
|
18 |
#define GST_IS_GPAC_MUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GPAC_MUX))
|
melunko@917
|
19 |
#define GST_IS_GPAC_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GPAC_MUX))
|
melunko@917
|
20 |
|
melunko@917
|
21 |
typedef struct _GstGpacMux GstGpacMux;
|
melunko@917
|
22 |
typedef struct _GstGpacMuxClass GstGpacMuxClass;
|
melunko@917
|
23 |
|
melunko@917
|
24 |
typedef enum
|
melunko@917
|
25 |
{
|
melunko@917
|
26 |
GST_GPAC_PAD_STATE_CONTROL = 0,
|
melunko@917
|
27 |
GST_GPAC_PAD_STATE_DATA = 1
|
melunko@917
|
28 |
}
|
melunko@917
|
29 |
GstGpacPadState;
|
melunko@917
|
30 |
|
melunko@917
|
31 |
typedef struct
|
melunko@917
|
32 |
{
|
melunko@917
|
33 |
GstCollectData collect; /* we extend the CollectData */
|
melunko@917
|
34 |
|
melunko@917
|
35 |
gint track_number;
|
melunko@917
|
36 |
guint32 di; /* outDescriptionIndex */
|
melunko@917
|
37 |
|
melunko@920
|
38 |
GstBuffer *buffer;
|
melunko@920
|
39 |
GstBuffer *next_buffer;
|
melunko@920
|
40 |
|
melunko@917
|
41 |
guint32 frame_count;
|
melunko@917
|
42 |
gboolean is_video;
|
melunko@917
|
43 |
|
melunko@920
|
44 |
gboolean eos;
|
melunko@920
|
45 |
|
melunko@917
|
46 |
} GstGpacPad;
|
melunko@917
|
47 |
|
melunko@917
|
48 |
struct _GstGpacMux
|
melunko@917
|
49 |
{
|
melunko@917
|
50 |
GstElement element;
|
melunko@917
|
51 |
|
melunko@917
|
52 |
GstPad *srcpad;
|
melunko@917
|
53 |
GstCollectPads *collect;
|
melunko@920
|
54 |
gint active_pads;
|
melunko@917
|
55 |
|
melunko@917
|
56 |
GF_ISOFile *file;
|
melunko@917
|
57 |
|
melunko@917
|
58 |
};
|
melunko@917
|
59 |
|
melunko@917
|
60 |
struct _GstGpacMuxClass
|
melunko@917
|
61 |
{
|
melunko@917
|
62 |
GstElementClass parent_class;
|
melunko@917
|
63 |
};
|
melunko@917
|
64 |
|
melunko@917
|
65 |
/* elementfactory information */
|
melunko@917
|
66 |
static const GstElementDetails gst_gpac_mux_details =
|
melunko@917
|
67 |
GST_ELEMENT_DETAILS ("Gpac muxer",
|
melunko@917
|
68 |
"Codec/Muxer",
|
melunko@917
|
69 |
"mux mp4 streams",
|
melunko@917
|
70 |
"Hallyson Melo <hallyson.melo@indt.org.br");
|
melunko@917
|
71 |
|
melunko@917
|
72 |
/* GpacMux signals and args */
|
melunko@917
|
73 |
enum
|
melunko@917
|
74 |
{
|
melunko@917
|
75 |
/* FILL ME */
|
melunko@917
|
76 |
LAST_SIGNAL
|
melunko@917
|
77 |
};
|
melunko@917
|
78 |
|
melunko@917
|
79 |
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
melunko@917
|
80 |
GST_PAD_SRC,
|
melunko@917
|
81 |
GST_PAD_ALWAYS,
|
melunko@917
|
82 |
GST_STATIC_CAPS ("video/quicktime")
|
melunko@917
|
83 |
);
|
melunko@917
|
84 |
|
melunko@917
|
85 |
static GstStaticPadTemplate audio_sink_factory = GST_STATIC_PAD_TEMPLATE ("audio_%d",
|
melunko@917
|
86 |
GST_PAD_SINK,
|
melunko@917
|
87 |
GST_PAD_REQUEST,
|
melunko@917
|
88 |
GST_STATIC_CAPS (
|
melunko@917
|
89 |
"audio/mpeg, "
|
melunko@917
|
90 |
"mpegversion = (int) 4, "
|
melunko@917
|
91 |
"channels = (int) { 1, 2 }, "
|
melunko@917
|
92 |
"rate = (int) [ 8000, 96000 ]")
|
melunko@917
|
93 |
);
|
melunko@917
|
94 |
//GST_STATIC_CAPS ("audio/mpeg, mpegversion = 1, layer = 3")
|
melunko@917
|
95 |
|
melunko@917
|
96 |
static GstStaticPadTemplate video_sink_factory = GST_STATIC_PAD_TEMPLATE ("video_%d",
|
melunko@917
|
97 |
GST_PAD_SINK,
|
melunko@917
|
98 |
GST_PAD_REQUEST,
|
melunko@917
|
99 |
GST_STATIC_CAPS ("video/mpeg, mpegversion = 4")
|
melunko@917
|
100 |
);
|
melunko@917
|
101 |
|
melunko@917
|
102 |
static void gst_gpac_mux_base_init (gpointer g_class);
|
melunko@917
|
103 |
static void gst_gpac_mux_class_init (GstGpacMuxClass * klass);
|
melunko@917
|
104 |
static void gst_gpac_mux_init (GstGpacMux * gpac_mux);
|
melunko@917
|
105 |
static void gst_gpac_mux_finalize (GObject * object);
|
melunko@917
|
106 |
|
melunko@917
|
107 |
static GstFlowReturn
|
melunko@917
|
108 |
gst_gpac_mux_collected (GstCollectPads * pads, GstGpacMux * gpac_mux);
|
melunko@917
|
109 |
|
melunko@917
|
110 |
static gboolean gst_gpac_mux_handle_src_event (GstPad * pad, GstEvent * event);
|
melunko@917
|
111 |
static GstPad *gst_gpac_mux_request_new_pad (GstElement * element,
|
melunko@917
|
112 |
GstPadTemplate * templ, const gchar * name);
|
melunko@917
|
113 |
static void gst_gpac_mux_release_pad (GstElement * element, GstPad * pad);
|
melunko@917
|
114 |
|
melunko@917
|
115 |
static GstStateChangeReturn gst_gpac_mux_change_state (GstElement * element,
|
melunko@917
|
116 |
GstStateChange transition);
|
melunko@917
|
117 |
|
melunko@920
|
118 |
static GstGpacPad* gst_gpac_mux_queue_pads (GstGpacMux * gpac_mux);
|
melunko@920
|
119 |
static GstFlowReturn gst_gpac_mux_process_pad (GstGpacMux * gpac_mux, GstGpacPad *pad);
|
melunko@920
|
120 |
static gboolean gst_gpac_mux_all_pads_eos (GstCollectPads * pads);
|
melunko@920
|
121 |
static gint gst_gpac_mux_compare_pads (GstGpacMux * ogg_mux, GstGpacPad *first,
|
melunko@920
|
122 |
GstGpacPad *second);
|
melunko@920
|
123 |
|
melunko@920
|
124 |
|
melunko@917
|
125 |
static GstElementClass *parent_class = NULL;
|
melunko@917
|
126 |
|
melunko@917
|
127 |
GType
|
melunko@917
|
128 |
gst_gpac_mux_get_type (void)
|
melunko@917
|
129 |
{
|
melunko@917
|
130 |
static GType gpac_mux_type = 0;
|
melunko@917
|
131 |
|
melunko@917
|
132 |
if (G_UNLIKELY (gpac_mux_type == 0)) {
|
melunko@917
|
133 |
static const GTypeInfo gpac_mux_info = {
|
melunko@917
|
134 |
sizeof (GstGpacMuxClass),
|
melunko@917
|
135 |
gst_gpac_mux_base_init,
|
melunko@917
|
136 |
NULL,
|
melunko@917
|
137 |
(GClassInitFunc) gst_gpac_mux_class_init,
|
melunko@917
|
138 |
NULL,
|
melunko@917
|
139 |
NULL,
|
melunko@917
|
140 |
sizeof (GstGpacMux),
|
melunko@917
|
141 |
0,
|
melunko@917
|
142 |
(GInstanceInitFunc) gst_gpac_mux_init,
|
melunko@917
|
143 |
};
|
melunko@917
|
144 |
|
melunko@917
|
145 |
gpac_mux_type =
|
melunko@917
|
146 |
g_type_register_static (GST_TYPE_ELEMENT, "GstGpacMux", &gpac_mux_info,
|
melunko@917
|
147 |
0);
|
melunko@917
|
148 |
}
|
melunko@917
|
149 |
return gpac_mux_type;
|
melunko@917
|
150 |
}
|
melunko@917
|
151 |
|
melunko@917
|
152 |
static void
|
melunko@917
|
153 |
gst_gpac_mux_base_init (gpointer g_class)
|
melunko@917
|
154 |
{
|
melunko@917
|
155 |
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
melunko@917
|
156 |
|
melunko@917
|
157 |
gst_element_class_add_pad_template (element_class,
|
melunko@917
|
158 |
gst_static_pad_template_get (&src_factory));
|
melunko@917
|
159 |
gst_element_class_add_pad_template (element_class,
|
melunko@917
|
160 |
gst_static_pad_template_get (&audio_sink_factory));
|
melunko@917
|
161 |
gst_element_class_add_pad_template (element_class,
|
melunko@917
|
162 |
gst_static_pad_template_get (&video_sink_factory));
|
melunko@917
|
163 |
|
melunko@917
|
164 |
gst_element_class_set_details (element_class, &gst_gpac_mux_details);
|
melunko@917
|
165 |
}
|
melunko@917
|
166 |
|
melunko@917
|
167 |
static void
|
melunko@917
|
168 |
gst_gpac_mux_class_init (GstGpacMuxClass * klass)
|
melunko@917
|
169 |
{
|
melunko@917
|
170 |
GObjectClass *gobject_class;
|
melunko@917
|
171 |
GstElementClass *gstelement_class;
|
melunko@917
|
172 |
|
melunko@917
|
173 |
gobject_class = (GObjectClass *) klass;
|
melunko@917
|
174 |
gstelement_class = (GstElementClass *) klass;
|
melunko@917
|
175 |
|
melunko@917
|
176 |
parent_class = g_type_class_peek_parent (klass);
|
melunko@917
|
177 |
|
melunko@917
|
178 |
gobject_class->finalize = gst_gpac_mux_finalize;
|
melunko@917
|
179 |
|
melunko@917
|
180 |
gstelement_class->request_new_pad = gst_gpac_mux_request_new_pad;
|
melunko@917
|
181 |
gstelement_class->release_pad = gst_gpac_mux_release_pad;
|
melunko@917
|
182 |
|
melunko@917
|
183 |
gstelement_class->change_state = gst_gpac_mux_change_state;
|
melunko@917
|
184 |
|
melunko@917
|
185 |
}
|
melunko@917
|
186 |
|
melunko@917
|
187 |
static void
|
melunko@917
|
188 |
gst_gpac_mux_init (GstGpacMux * gpac_mux)
|
melunko@917
|
189 |
{
|
melunko@917
|
190 |
GstElementClass *klass = GST_ELEMENT_GET_CLASS (gpac_mux);
|
melunko@917
|
191 |
|
melunko@917
|
192 |
gpac_mux->srcpad =
|
melunko@917
|
193 |
gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
|
melunko@917
|
194 |
"src"), "src");
|
melunko@917
|
195 |
gst_pad_set_event_function (gpac_mux->srcpad, gst_gpac_mux_handle_src_event);
|
melunko@917
|
196 |
gst_element_add_pad (GST_ELEMENT (gpac_mux), gpac_mux->srcpad);
|
melunko@917
|
197 |
|
melunko@917
|
198 |
gpac_mux->collect = gst_collect_pads_new ();
|
melunko@917
|
199 |
gst_collect_pads_set_function (gpac_mux->collect,
|
melunko@917
|
200 |
(GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_gpac_mux_collected),
|
melunko@917
|
201 |
gpac_mux);
|
melunko@917
|
202 |
|
melunko@917
|
203 |
/* Opens gpac library */
|
melunko@917
|
204 |
/* FIXME */
|
melunko@917
|
205 |
gpac_mux->file = gf_isom_open("/tmp/gpac.mp4", GF_ISOM_OPEN_WRITE, NULL);
|
melunko@917
|
206 |
gf_isom_set_storage_mode(gpac_mux->file, GF_ISOM_STORE_FLAT /*STREAMABLE*/);
|
melunko@917
|
207 |
|
melunko@917
|
208 |
//gst_gpac_mux_clear (gpac_mux);
|
melunko@917
|
209 |
}
|
melunko@917
|
210 |
|
melunko@917
|
211 |
static void
|
melunko@917
|
212 |
gst_gpac_mux_finalize (GObject * object)
|
melunko@917
|
213 |
{
|
melunko@917
|
214 |
GstGpacMux *gpac_mux;
|
melunko@917
|
215 |
|
melunko@917
|
216 |
gpac_mux = GST_GPAC_MUX (object);
|
melunko@917
|
217 |
|
melunko@917
|
218 |
if (gpac_mux->collect) {
|
melunko@917
|
219 |
gst_object_unref (gpac_mux->collect);
|
melunko@917
|
220 |
gpac_mux->collect = NULL;
|
melunko@917
|
221 |
}
|
melunko@917
|
222 |
|
melunko@917
|
223 |
G_OBJECT_CLASS (parent_class)->finalize (object);
|
melunko@917
|
224 |
}
|
melunko@917
|
225 |
|
melunko@917
|
226 |
static void
|
melunko@917
|
227 |
gst_gpac_mux_gpac_pad_destroy_notify (GstCollectData * data)
|
melunko@917
|
228 |
{
|
melunko@917
|
229 |
GstGpacPad *gpacpad = (GstGpacPad *) data;
|
melunko@917
|
230 |
GstBuffer *buf;
|
melunko@917
|
231 |
|
melunko@917
|
232 |
}
|
melunko@917
|
233 |
|
melunko@917
|
234 |
static GstPadLinkReturn
|
melunko@917
|
235 |
gst_gpac_mux_sinkconnect (GstPad * pad, GstPad * peer)
|
melunko@917
|
236 |
{
|
melunko@917
|
237 |
GstGpacMux *gpac_mux;
|
melunko@917
|
238 |
|
melunko@917
|
239 |
gpac_mux = GST_GPAC_MUX (gst_pad_get_parent (pad));
|
melunko@917
|
240 |
|
melunko@917
|
241 |
GST_DEBUG_OBJECT (gpac_mux, "sinkconnect triggered on %s", GST_PAD_NAME (pad));
|
melunko@917
|
242 |
|
melunko@917
|
243 |
gst_object_unref (gpac_mux);
|
melunko@917
|
244 |
|
melunko@917
|
245 |
return GST_PAD_LINK_OK;
|
melunko@917
|
246 |
}
|
melunko@917
|
247 |
|
melunko@917
|
248 |
static GstPad *
|
melunko@917
|
249 |
gst_gpac_mux_request_new_pad (GstElement * element,
|
melunko@917
|
250 |
GstPadTemplate * templ, const gchar * req_name)
|
melunko@917
|
251 |
{
|
melunko@917
|
252 |
GstGpacMux *gpac_mux;
|
melunko@917
|
253 |
GstPad *newpad;
|
melunko@917
|
254 |
GstElementClass *klass;
|
melunko@917
|
255 |
gchar *padname = NULL;
|
melunko@917
|
256 |
gint serial;
|
melunko@917
|
257 |
gboolean is_video = FALSE;
|
melunko@917
|
258 |
|
melunko@917
|
259 |
g_return_val_if_fail (templ != NULL, NULL);
|
melunko@917
|
260 |
|
melunko@917
|
261 |
if (templ->direction != GST_PAD_SINK)
|
melunko@917
|
262 |
goto wrong_direction;
|
melunko@917
|
263 |
|
melunko@917
|
264 |
g_return_val_if_fail (GST_IS_GPAC_MUX (element), NULL);
|
melunko@917
|
265 |
gpac_mux = GST_GPAC_MUX (element);
|
melunko@917
|
266 |
|
melunko@917
|
267 |
klass = GST_ELEMENT_GET_CLASS (element);
|
melunko@917
|
268 |
|
melunko@917
|
269 |
if (req_name == NULL || strlen (req_name) < 6) {
|
melunko@917
|
270 |
/* no name given when requesting the pad, use random serial number */
|
melunko@917
|
271 |
serial = rand ();
|
melunko@917
|
272 |
} else {
|
melunko@917
|
273 |
/* parse serial number from requested padname */
|
melunko@917
|
274 |
serial = atoi (&req_name[5]);
|
melunko@917
|
275 |
}
|
melunko@917
|
276 |
|
melunko@917
|
277 |
if (templ == gst_element_class_get_pad_template (klass, "video_%d")) {
|
melunko@917
|
278 |
is_video = TRUE;
|
melunko@917
|
279 |
padname = g_strdup_printf ("video_%d", serial);
|
melunko@917
|
280 |
} else if (templ != gst_element_class_get_pad_template (klass, "audio_%d")) {
|
melunko@917
|
281 |
goto wrong_template;
|
melunko@917
|
282 |
} else {
|
melunko@917
|
283 |
padname = g_strdup_printf ("audio_%d", serial);
|
melunko@917
|
284 |
}
|
melunko@917
|
285 |
|
melunko@917
|
286 |
|
melunko@917
|
287 |
{
|
melunko@917
|
288 |
|
melunko@917
|
289 |
/* create new pad with the name */
|
melunko@917
|
290 |
GST_DEBUG_OBJECT (gpac_mux, "Creating new pad for serial %d", serial);
|
melunko@920
|
291 |
|
melunko@917
|
292 |
newpad = gst_pad_new_from_template (templ, padname);
|
melunko@917
|
293 |
g_free (padname);
|
melunko@917
|
294 |
|
melunko@917
|
295 |
/* construct our own wrapper data structure for the pad to
|
melunko@917
|
296 |
* keep track of its status */
|
melunko@917
|
297 |
{
|
melunko@917
|
298 |
GstGpacPad *gpacpad;
|
melunko@917
|
299 |
|
melunko@917
|
300 |
gpacpad = (GstGpacPad *)
|
melunko@917
|
301 |
gst_collect_pads_add_pad_full (gpac_mux->collect, newpad,
|
melunko@917
|
302 |
sizeof (GstGpacPad), gst_gpac_mux_gpac_pad_destroy_notify);
|
melunko@920
|
303 |
gpac_mux->active_pads++;
|
melunko@917
|
304 |
|
melunko@917
|
305 |
/* gpac new track */
|
melunko@917
|
306 |
gpacpad->is_video = is_video;
|
melunko@917
|
307 |
if (gpacpad->is_video) {
|
melunko@917
|
308 |
gpacpad->track_number = gf_isom_new_track(gpac_mux->file, 0,
|
melunko@917
|
309 |
GF_ISOM_MEDIA_VISUAL, 10 * 1000 /* time scale */);
|
melunko@917
|
310 |
} else {
|
melunko@917
|
311 |
gpacpad->track_number = gf_isom_new_track(gpac_mux->file, 0,
|
melunko@917
|
312 |
GF_ISOM_MEDIA_AUDIO, 48000 /*time scale */);
|
melunko@917
|
313 |
|
melunko@917
|
314 |
}
|
melunko@917
|
315 |
if (gpacpad->track_number == 0) {
|
melunko@917
|
316 |
g_warning ("Error while adding the new gpac track");
|
melunko@917
|
317 |
} else {
|
melunko@917
|
318 |
gf_isom_set_track_enabled(gpac_mux->file, gpacpad->track_number, 1);
|
melunko@917
|
319 |
if (is_video) {
|
melunko@917
|
320 |
GF_ESD *esd = gf_odf_desc_esd_new (0);
|
melunko@917
|
321 |
esd->ESID = gf_isom_get_track_id(gpac_mux->file, gpacpad->track_number);
|
melunko@917
|
322 |
|
melunko@917
|
323 |
gf_isom_new_mpeg4_description( gpac_mux->file, gpacpad->track_number,
|
melunko@917
|
324 |
esd, NULL, NULL, &(gpacpad->di));
|
melunko@917
|
325 |
|
melunko@917
|
326 |
gf_isom_set_visual_info (gpac_mux->file, gpacpad->track_number, gpacpad->di, 320, 240);//fixme
|
melunko@917
|
327 |
//gf_isom_set_cts_packing (gpac_mux->file, gpacpad->track_number, 0);
|
melunko@917
|
328 |
} else {
|
melunko@917
|
329 |
GF_ESD *esd = gf_odf_desc_esd_new (2);
|
melunko@917
|
330 |
esd->ESID = gf_isom_get_track_id(gpac_mux->file, gpacpad->track_number);
|
melunko@917
|
331 |
|
melunko@917
|
332 |
gf_isom_new_mpeg4_description(gpac_mux->file, gpacpad->track_number,
|
melunko@917
|
333 |
esd, NULL, NULL, &(gpacpad->di));
|
melunko@917
|
334 |
|
melunko@917
|
335 |
gf_isom_set_audio_info(gpac_mux->file, gpacpad->track_number,
|
melunko@917
|
336 |
gpacpad->di, 48000, 2 /*num channels */, 16);
|
melunko@917
|
337 |
}
|
melunko@917
|
338 |
}
|
melunko@917
|
339 |
}
|
melunko@917
|
340 |
}
|
melunko@917
|
341 |
|
melunko@917
|
342 |
/* setup some pad functions */
|
melunko@917
|
343 |
gst_pad_set_link_function (newpad, gst_gpac_mux_sinkconnect);
|
melunko@917
|
344 |
/* dd the pad to the element */
|
melunko@917
|
345 |
gst_element_add_pad (element, newpad);
|
melunko@917
|
346 |
|
melunko@917
|
347 |
return newpad;
|
melunko@917
|
348 |
|
melunko@917
|
349 |
/* ERRORS */
|
melunko@917
|
350 |
wrong_direction:
|
melunko@917
|
351 |
{
|
melunko@917
|
352 |
g_warning ("gpac_mux: request pad that is not a SINK pad\n");
|
melunko@917
|
353 |
return NULL;
|
melunko@917
|
354 |
}
|
melunko@917
|
355 |
wrong_template:
|
melunko@917
|
356 |
{
|
melunko@917
|
357 |
g_warning ("gpac_mux: this is not our template!\n");
|
melunko@917
|
358 |
return NULL;
|
melunko@917
|
359 |
}
|
melunko@917
|
360 |
}
|
melunko@917
|
361 |
|
melunko@917
|
362 |
static void
|
melunko@917
|
363 |
gst_gpac_mux_release_pad (GstElement * element, GstPad * pad)
|
melunko@917
|
364 |
{
|
melunko@917
|
365 |
GstGpacMux *gpac_mux;
|
melunko@917
|
366 |
|
melunko@917
|
367 |
gpac_mux = GST_GPAC_MUX (gst_pad_get_parent (pad));
|
melunko@917
|
368 |
|
melunko@917
|
369 |
gst_collect_pads_remove_pad (gpac_mux->collect, pad);
|
melunko@917
|
370 |
gst_element_remove_pad (element, pad);
|
melunko@917
|
371 |
}
|
melunko@917
|
372 |
|
melunko@917
|
373 |
/* handle events */
|
melunko@917
|
374 |
static gboolean
|
melunko@917
|
375 |
gst_gpac_mux_handle_src_event (GstPad * pad, GstEvent * event)
|
melunko@917
|
376 |
{
|
melunko@917
|
377 |
GstEventType type;
|
melunko@917
|
378 |
|
melunko@917
|
379 |
type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
|
melunko@917
|
380 |
|
melunko@917
|
381 |
switch (type) {
|
melunko@917
|
382 |
case GST_EVENT_SEEK:
|
melunko@917
|
383 |
/* disable seeking for now */
|
melunko@917
|
384 |
return FALSE;
|
melunko@917
|
385 |
default:
|
melunko@917
|
386 |
break;
|
melunko@917
|
387 |
}
|
melunko@917
|
388 |
|
melunko@917
|
389 |
return gst_pad_event_default (pad, event);
|
melunko@917
|
390 |
}
|
melunko@917
|
391 |
|
melunko@917
|
392 |
static GstFlowReturn
|
melunko@917
|
393 |
gst_gpac_mux_push_buffer (GstGpacMux * mux, GstBuffer * buffer)
|
melunko@917
|
394 |
{
|
melunko@917
|
395 |
GstCaps *caps;
|
melunko@917
|
396 |
#if 0
|
melunko@917
|
397 |
/* fix up OFFSET and OFFSET_END again */
|
melunko@917
|
398 |
GST_BUFFER_OFFSET (buffer) = mux->offset;
|
melunko@917
|
399 |
mux->offset += GST_BUFFER_SIZE (buffer);
|
melunko@917
|
400 |
GST_BUFFER_OFFSET_END (buffer) = mux->offset;
|
melunko@917
|
401 |
|
melunko@917
|
402 |
/* Ensure we have monotonically increasing timestamps in the output. */
|
melunko@917
|
403 |
if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
|
melunko@917
|
404 |
if (mux->last_ts != GST_CLOCK_TIME_NONE &&
|
melunko@917
|
405 |
GST_BUFFER_TIMESTAMP (buffer) < mux->last_ts)
|
melunko@917
|
406 |
GST_BUFFER_TIMESTAMP (buffer) = mux->last_ts;
|
melunko@917
|
407 |
else
|
melunko@917
|
408 |
mux->last_ts = GST_BUFFER_TIMESTAMP (buffer);
|
melunko@917
|
409 |
}
|
melunko@917
|
410 |
#endif
|
melunko@917
|
411 |
|
melunko@917
|
412 |
caps = gst_pad_get_negotiated_caps (mux->srcpad);
|
melunko@917
|
413 |
gst_buffer_set_caps (buffer, caps);
|
melunko@917
|
414 |
if (caps != NULL) {
|
melunko@917
|
415 |
gst_caps_unref (caps);
|
melunko@917
|
416 |
}
|
melunko@917
|
417 |
|
melunko@917
|
418 |
return gst_pad_push (mux->srcpad, buffer);
|
melunko@917
|
419 |
}
|
melunko@917
|
420 |
|
melunko@920
|
421 |
static GstFlowReturn
|
melunko@920
|
422 |
gst_gpac_mux_collected (GstCollectPads * pads, GstGpacMux * gpac_mux)
|
melunko@920
|
423 |
{
|
melunko@920
|
424 |
GstFlowReturn ret = GST_FLOW_OK;
|
melunko@920
|
425 |
GstGpacPad *pad;
|
melunko@920
|
426 |
gint active_before;
|
melunko@920
|
427 |
|
melunko@920
|
428 |
GST_LOG_OBJECT (gpac_mux, "collected");
|
melunko@920
|
429 |
|
melunko@920
|
430 |
active_before = gpac_mux->active_pads;
|
melunko@920
|
431 |
|
melunko@920
|
432 |
pad = gst_gpac_mux_queue_pads (gpac_mux);
|
melunko@920
|
433 |
if (!pad) {
|
melunko@920
|
434 |
return GST_FLOW_WRONG_STATE;
|
melunko@920
|
435 |
}
|
melunko@920
|
436 |
|
melunko@920
|
437 |
if (pad->buffer) {
|
melunko@920
|
438 |
ret = gst_gpac_mux_process_pad (gpac_mux, pad);
|
melunko@920
|
439 |
}
|
melunko@920
|
440 |
|
melunko@920
|
441 |
if (gpac_mux->active_pads < active_before) {
|
melunko@920
|
442 |
/* If the active pad count went down, this mean at least one pad has gone
|
melunko@920
|
443 |
* EOS. Since CollectPads only calls _collected() once when all pads are
|
melunko@920
|
444 |
* EOS, and our code doesn't _pop() from all pads we need to check that by
|
melunko@920
|
445 |
* peeking on all pads, else we won't be called again and the muxing will
|
melunko@920
|
446 |
* not terminate (push out EOS). */
|
melunko@920
|
447 |
printf ("XXXX um pad foi desativado %" GST_PTR_FORMAT "\n", pad);
|
melunko@920
|
448 |
|
melunko@920
|
449 |
/* if all the pads have been removed, flush all pending data */
|
melunko@920
|
450 |
if ((ret == GST_FLOW_OK) && gst_gpac_mux_all_pads_eos (pads)) {
|
melunko@920
|
451 |
GST_LOG_OBJECT (gpac_mux, "no pads remaining, flushing data");
|
melunko@920
|
452 |
|
melunko@920
|
453 |
do {
|
melunko@920
|
454 |
pad = gst_gpac_mux_queue_pads (gpac_mux);
|
melunko@920
|
455 |
if (pad)
|
melunko@920
|
456 |
ret = gst_gpac_mux_process_pad (gpac_mux, pad);
|
melunko@920
|
457 |
} while ((ret == GST_FLOW_OK) && (pad != NULL));
|
melunko@920
|
458 |
|
melunko@920
|
459 |
/* gpac file close (eos) */
|
melunko@920
|
460 |
// Fixme: this should flush all data to src pad
|
melunko@920
|
461 |
// Fixme: where to release gpac_mux->file?
|
melunko@920
|
462 |
printf ("CCCCCCCCCCCCCCCCcclosing the file\n");
|
melunko@920
|
463 |
gf_isom_close (gpac_mux->file);
|
melunko@920
|
464 |
|
melunko@920
|
465 |
|
melunko@920
|
466 |
GST_DEBUG_OBJECT (gpac_mux, "Pushing EOS");
|
melunko@920
|
467 |
gst_pad_push_event (gpac_mux->srcpad, gst_event_new_eos ());
|
melunko@920
|
468 |
}
|
melunko@920
|
469 |
}
|
melunko@920
|
470 |
|
melunko@920
|
471 |
return ret;
|
melunko@920
|
472 |
|
melunko@920
|
473 |
}
|
melunko@920
|
474 |
|
melunko@917
|
475 |
static gboolean
|
melunko@920
|
476 |
gst_gpac_mux_all_pads_eos (GstCollectPads * pads)
|
melunko@917
|
477 |
{
|
melunko@920
|
478 |
GSList *walk;
|
melunko@917
|
479 |
gboolean alleos = TRUE;
|
melunko@917
|
480 |
|
melunko@920
|
481 |
walk = pads->data;
|
melunko@920
|
482 |
while (walk) {
|
melunko@917
|
483 |
GstBuffer *buf;
|
melunko@920
|
484 |
GstCollectData *data = (GstCollectData *) walk->data;
|
melunko@917
|
485 |
|
melunko@917
|
486 |
buf = gst_collect_pads_peek (pads, data);
|
melunko@917
|
487 |
if (buf) {
|
melunko@917
|
488 |
alleos = FALSE;
|
melunko@917
|
489 |
gst_buffer_unref (buf);
|
melunko@920
|
490 |
break;
|
melunko@917
|
491 |
}
|
melunko@920
|
492 |
walk = walk->next;
|
melunko@917
|
493 |
}
|
melunko@920
|
494 |
|
melunko@917
|
495 |
return alleos;
|
melunko@917
|
496 |
}
|
melunko@920
|
497 |
|
melunko@920
|
498 |
|
melunko@917
|
499 |
static GstFlowReturn
|
melunko@920
|
500 |
gst_gpac_mux_process_pad (GstGpacMux *gpac_mux, GstGpacPad *pad)
|
melunko@917
|
501 |
{
|
melunko@917
|
502 |
GstFlowReturn ret = GST_FLOW_OK;
|
melunko@920
|
503 |
GF_ISOSample *sample;
|
melunko@917
|
504 |
|
melunko@920
|
505 |
if (pad->buffer == NULL) {
|
melunko@920
|
506 |
printf ("Buffer is null, wrong state\n");
|
melunko@920
|
507 |
return GST_FLOW_WRONG_STATE;
|
melunko@917
|
508 |
}
|
melunko@917
|
509 |
|
melunko@920
|
510 |
/* gpac output */
|
melunko@920
|
511 |
printf ("xxxxxx buffer size: %d\n", GST_BUFFER_SIZE(pad->buffer)); fflush (stdout);
|
melunko@920
|
512 |
printf ("xxxx frames %d\n", pad->frame_count);
|
melunko@920
|
513 |
|
melunko@920
|
514 |
sample = gf_isom_sample_new();
|
melunko@920
|
515 |
sample->dataLength = GST_BUFFER_SIZE(pad->buffer);
|
melunko@920
|
516 |
sample->data = GST_BUFFER_DATA(pad->buffer);
|
melunko@920
|
517 |
sample->CTS_Offset = 0;
|
melunko@920
|
518 |
|
melunko@920
|
519 |
if (pad->is_video) {
|
melunko@920
|
520 |
sample->IsRAP = 0;
|
melunko@920
|
521 |
sample->DTS += 1000*pad->frame_count;
|
melunko@920
|
522 |
} else {
|
melunko@920
|
523 |
sample->IsRAP = 0;
|
melunko@920
|
524 |
sample->DTS = 2048*pad->frame_count;
|
melunko@920
|
525 |
}
|
melunko@920
|
526 |
|
melunko@920
|
527 |
gf_isom_add_sample(gpac_mux->file, pad->track_number,
|
melunko@920
|
528 |
pad->di, sample);
|
melunko@920
|
529 |
sample->data = NULL;
|
melunko@920
|
530 |
|
melunko@920
|
531 |
gf_isom_sample_del(&sample);
|
melunko@920
|
532 |
|
melunko@920
|
533 |
|
melunko@920
|
534 |
/* gstreamer output (push) */
|
melunko@920
|
535 |
ret = gst_gpac_mux_push_buffer (gpac_mux, pad->buffer);
|
melunko@920
|
536 |
pad->buffer = NULL;
|
melunko@920
|
537 |
|
melunko@920
|
538 |
if (ret != GST_FLOW_OK) {
|
melunko@920
|
539 |
}
|
melunko@920
|
540 |
|
melunko@920
|
541 |
pad->frame_count++;
|
melunko@920
|
542 |
|
melunko@917
|
543 |
return ret;
|
melunko@917
|
544 |
}
|
melunko@917
|
545 |
|
melunko@917
|
546 |
/* reset all variables in the gpac pads. */
|
melunko@917
|
547 |
static void
|
melunko@917
|
548 |
gst_gpac_mux_init_collectpads (GstCollectPads * collect)
|
melunko@917
|
549 |
{
|
melunko@920
|
550 |
GSList *iter;
|
melunko@917
|
551 |
|
melunko@920
|
552 |
iter = collect->data;
|
melunko@920
|
553 |
while (iter) {
|
melunko@920
|
554 |
GstGpacPad *gpacpad = (GstGpacPad *) iter->data;
|
melunko@917
|
555 |
|
melunko@920
|
556 |
//gpac_stream_init (&gpacpad->stream, gpacpad->serial);
|
melunko@917
|
557 |
//gpacpad->packetno = 0;
|
melunko@917
|
558 |
//gpacpad->pageno = 0;
|
melunko@917
|
559 |
//gpacpad->eos = FALSE;
|
melunko@917
|
560 |
/* we assume there will be some control data first for this pad */
|
melunko@917
|
561 |
//gpacpad->state = GST_GPAC_PAD_STATE_CONTROL;
|
melunko@917
|
562 |
//gpacpad->new_page = TRUE;
|
melunko@917
|
563 |
//gpacpad->first_delta = FALSE;
|
melunko@917
|
564 |
//gpacpad->prev_delta = FALSE;
|
melunko@917
|
565 |
//gpacpad->pagebuffers = g_queue_new ();
|
melunko@917
|
566 |
|
melunko@920
|
567 |
iter = g_slist_next (iter);
|
melunko@917
|
568 |
}
|
melunko@917
|
569 |
}
|
melunko@917
|
570 |
|
melunko@917
|
571 |
/* Clear all buffers from the collectpads object */
|
melunko@917
|
572 |
static void
|
melunko@917
|
573 |
gst_gpac_mux_clear_collectpads (GstCollectPads * collect)
|
melunko@917
|
574 |
{
|
melunko@920
|
575 |
GSList *iter;
|
melunko@917
|
576 |
|
melunko@920
|
577 |
for (iter = collect->data; iter; iter = g_slist_next (iter)) {
|
melunko@920
|
578 |
GstGpacPad *gpacpad = (GstGpacPad *) iter->data;
|
melunko@917
|
579 |
GstBuffer *buf;
|
melunko@917
|
580 |
|
melunko@917
|
581 |
//gpac_stream_clear (&gpacpad->stream);
|
melunko@917
|
582 |
/*
|
melunko@917
|
583 |
while ((buf = g_queue_pop_head (gpacpad->pagebuffers)) != NULL) {
|
melunko@917
|
584 |
gst_buffer_unref (buf);
|
melunko@917
|
585 |
}
|
melunko@917
|
586 |
g_queue_free (gpacpad->pagebuffers);
|
melunko@917
|
587 |
gpacpad->pagebuffers = NULL;*/
|
melunko@917
|
588 |
}
|
melunko@917
|
589 |
}
|
melunko@917
|
590 |
|
melunko@917
|
591 |
static GstStateChangeReturn
|
melunko@917
|
592 |
gst_gpac_mux_change_state (GstElement * element, GstStateChange transition)
|
melunko@917
|
593 |
{
|
melunko@917
|
594 |
GstGpacMux *gpac_mux;
|
melunko@917
|
595 |
GstStateChangeReturn ret;
|
melunko@917
|
596 |
|
melunko@917
|
597 |
gpac_mux = GST_GPAC_MUX (element);
|
melunko@917
|
598 |
|
melunko@917
|
599 |
switch (transition) {
|
melunko@917
|
600 |
case GST_STATE_CHANGE_NULL_TO_READY:
|
melunko@917
|
601 |
break;
|
melunko@917
|
602 |
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
melunko@917
|
603 |
//gst_gpac_mux_clear (gpac_mux);
|
melunko@917
|
604 |
//gst_gpac_mux_init_collectpads (gpac_mux->collect);
|
melunko@917
|
605 |
gst_collect_pads_start (gpac_mux->collect);
|
melunko@917
|
606 |
break;
|
melunko@917
|
607 |
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
melunko@917
|
608 |
break;
|
melunko@917
|
609 |
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
melunko@917
|
610 |
gst_collect_pads_stop (gpac_mux->collect);
|
melunko@917
|
611 |
break;
|
melunko@917
|
612 |
default:
|
melunko@917
|
613 |
break;
|
melunko@917
|
614 |
}
|
melunko@917
|
615 |
|
melunko@917
|
616 |
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
melunko@917
|
617 |
|
melunko@917
|
618 |
switch (transition) {
|
melunko@917
|
619 |
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
melunko@917
|
620 |
break;
|
melunko@917
|
621 |
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
melunko@917
|
622 |
gst_gpac_mux_clear_collectpads (gpac_mux->collect);
|
melunko@917
|
623 |
break;
|
melunko@917
|
624 |
case GST_STATE_CHANGE_READY_TO_NULL:
|
melunko@917
|
625 |
break;
|
melunko@917
|
626 |
default:
|
melunko@917
|
627 |
break;
|
melunko@917
|
628 |
}
|
melunko@917
|
629 |
|
melunko@917
|
630 |
return ret;
|
melunko@917
|
631 |
|
melunko@917
|
632 |
}
|
melunko@917
|
633 |
|
melunko@920
|
634 |
static GstGpacPad *
|
melunko@920
|
635 |
gst_gpac_mux_queue_pads (GstGpacMux * gpac_mux)
|
melunko@920
|
636 |
{
|
melunko@920
|
637 |
GstGpacPad *bestpad = NULL;//, *still_hungry = NULL;
|
melunko@920
|
638 |
GSList *iter;
|
melunko@920
|
639 |
|
melunko@920
|
640 |
/* try to make sure we have a buffer from each usable pad first */
|
melunko@920
|
641 |
iter = gpac_mux->collect->data;
|
melunko@920
|
642 |
while (iter) {
|
melunko@920
|
643 |
GstGpacPad *pad;
|
melunko@920
|
644 |
GstCollectData *data;
|
melunko@920
|
645 |
|
melunko@920
|
646 |
data = (GstCollectData *) iter->data;
|
melunko@920
|
647 |
pad = (GstGpacPad *) data;
|
melunko@920
|
648 |
|
melunko@920
|
649 |
iter = g_slist_next (iter);
|
melunko@920
|
650 |
|
melunko@920
|
651 |
GST_LOG_OBJECT (data->pad, "looking at pad for buffer");
|
melunko@920
|
652 |
|
melunko@920
|
653 |
/* try to get a new buffer for this pad if needed and possible */
|
melunko@920
|
654 |
if (pad->buffer == NULL) {
|
melunko@920
|
655 |
GstBuffer *buf;
|
melunko@920
|
656 |
|
melunko@920
|
657 |
buf = gst_collect_pads_pop (gpac_mux->collect, data);
|
melunko@920
|
658 |
GST_LOG_OBJECT (data->pad, "popped buffer %" GST_PTR_FORMAT, buf);
|
melunko@920
|
659 |
|
melunko@920
|
660 |
/* On EOS we get a NULL buffer */
|
melunko@920
|
661 |
if (buf == NULL) {
|
melunko@920
|
662 |
printf ("EENENENENENEND OF STREAM EOS\n");
|
melunko@920
|
663 |
GST_DEBUG_OBJECT (data->pad, "EOS on pad");
|
melunko@920
|
664 |
if (!pad->eos) {
|
melunko@920
|
665 |
/* it's no longer active */
|
melunko@920
|
666 |
gpac_mux->active_pads--;
|
melunko@920
|
667 |
pad->eos = TRUE;
|
melunko@920
|
668 |
|
melunko@920
|
669 |
}
|
melunko@920
|
670 |
}
|
melunko@920
|
671 |
|
melunko@920
|
672 |
pad->buffer = buf;
|
melunko@920
|
673 |
}
|
melunko@920
|
674 |
|
melunko@920
|
675 |
/* we should have a buffer now, see if it is the best pad to
|
melunko@920
|
676 |
* pull on */
|
melunko@920
|
677 |
if (gst_gpac_mux_compare_pads (gpac_mux, bestpad, pad) > 0) {
|
melunko@920
|
678 |
GST_LOG_OBJECT (data->pad,
|
melunko@920
|
679 |
"new best pad, with buffers %" GST_PTR_FORMAT, pad->buffer);
|
melunko@920
|
680 |
bestpad = pad;
|
melunko@920
|
681 |
}
|
melunko@920
|
682 |
}
|
melunko@920
|
683 |
|
melunko@920
|
684 |
return bestpad;
|
melunko@920
|
685 |
}
|
melunko@920
|
686 |
|
melunko@920
|
687 |
static gint
|
melunko@920
|
688 |
gst_gpac_mux_compare_pads (GstGpacMux * ogg_mux, GstGpacPad *first,
|
melunko@920
|
689 |
GstGpacPad *second)
|
melunko@920
|
690 |
{
|
melunko@920
|
691 |
guint64 firsttime, secondtime;
|
melunko@920
|
692 |
|
melunko@920
|
693 |
/* if the first pad doesn't contain anything or is even NULL, return
|
melunko@920
|
694 |
* the second pad as best candidate and vice versa */
|
melunko@920
|
695 |
if (first == NULL || (first->buffer == NULL))
|
melunko@920
|
696 |
return 1;
|
melunko@920
|
697 |
if (second == NULL || (second->buffer == NULL))
|
melunko@920
|
698 |
return -1;
|
melunko@920
|
699 |
|
melunko@920
|
700 |
/* no timestamp on first buffer, it must go first */
|
melunko@920
|
701 |
if (first->buffer)
|
melunko@920
|
702 |
firsttime = GST_BUFFER_TIMESTAMP (first->buffer);
|
melunko@920
|
703 |
if (firsttime == GST_CLOCK_TIME_NONE)
|
melunko@920
|
704 |
return -1;
|
melunko@920
|
705 |
|
melunko@920
|
706 |
/* no timestamp on second buffer, it must go first */
|
melunko@920
|
707 |
if (second->buffer)
|
melunko@920
|
708 |
secondtime = GST_BUFFER_TIMESTAMP (second->buffer);
|
melunko@920
|
709 |
if (secondtime == GST_CLOCK_TIME_NONE)
|
melunko@920
|
710 |
return 1;
|
melunko@920
|
711 |
|
melunko@920
|
712 |
/* first buffer has higher timestamp, second one should go first */
|
melunko@920
|
713 |
if (secondtime < firsttime)
|
melunko@920
|
714 |
return 1;
|
melunko@920
|
715 |
/* second buffer has higher timestamp, first one should go first */
|
melunko@920
|
716 |
else if (secondtime > firsttime)
|
melunko@920
|
717 |
return -1;
|
melunko@920
|
718 |
|
melunko@920
|
719 |
/* same priority if all of the above failed */
|
melunko@920
|
720 |
return 0;
|
melunko@920
|
721 |
}
|
melunko@920
|
722 |
|
melunko@920
|
723 |
|
melunko@920
|
724 |
|
melunko@917
|
725 |
static gboolean
|
melunko@917
|
726 |
gst_gpac_mux_plugin_init (GstPlugin * plugin)
|
melunko@917
|
727 |
{
|
melunko@917
|
728 |
return gst_element_register (plugin, "gpacmux", GST_RANK_NONE,
|
melunko@917
|
729 |
GST_TYPE_GPAC_MUX);
|
melunko@917
|
730 |
}
|
melunko@917
|
731 |
|
melunko@917
|
732 |
GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
|
melunko@917
|
733 |
GST_VERSION_MINOR,
|
melunko@917
|
734 |
"gpacmux",
|
melunko@917
|
735 |
"Muxes audio and video",
|
melunko@917
|
736 |
gst_gpac_mux_plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME,
|
melunko@917
|
737 |
GST_PACKAGE_ORIGIN)
|
melunko@917
|
738 |
|