4 * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, Naveen Cherukuri <naveen.ch@samsung.com>
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
26 * Alternatively, the contents of this file may be used under the
27 * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
28 * which case the following provisions apply instead of the ones
31 * This library is free software; you can redistribute it and/or
32 * modify it under the terms of the GNU Library General Public
33 * License as published by the Free Software Foundation; either
34 * version 2 of the License, or (at your option) any later version.
36 * This library is distributed in the hope that it will be useful,
37 * but WITHOUT ANY WARRANTY; without even the implied warranty of
38 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39 * Library General Public License for more details.
41 * You should have received a copy of the GNU Library General Public
42 * License along with this library; if not, write to the
43 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
44 * Boston, MA 02111-1307, USA.
51 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
52 * with newer GLib versions (>= 2.31.0) */
53 #define GLIB_DISABLE_DEPRECATION_WARNINGS
56 #include <sys/types.h>
58 #include <gst/tag/tag.h>
63 #include "gsthlsdemux2.h"
68 PROP_BITRATE_SWITCH_TOLERANCE,
69 PROP_FORCE_LOWER_BITRATE,
74 #define HLS_VIDEO_CAPS \
77 "mpegversion = (int) { 1, 2, 4 }, " \
78 "systemstream = (boolean) FALSE; " \
79 "video/x-h264,stream-format=(string)byte-stream," \
80 "alignment=(string)nal;" \
83 "wmvversion = (int) 3, " \
84 "format = (fourcc) WVC1" \
87 #define HLS_AUDIO_CAPS \
90 "mpegversion = (int) { 1, 4 };" \
92 "width = (int) { 16, 20, 24 }, " \
93 "rate = (int) { 48000, 96000 }, " \
94 "channels = (int) [ 1, 8 ], " \
95 "dynamic_range = (int) [ 0, 255 ], " \
96 "emphasis = (boolean) { FALSE, TRUE }, " \
97 "mute = (boolean) { FALSE, TRUE }; " \
98 "audio/x-ac3; audio/x-eac3;" \
100 "audio/x-private-ts-lpcm;" \
101 "application/x-id3" \
104 /* Can also use the subpicture pads for text subtitles? */
105 #define HLS_SUBPICTURE_CAPS \
106 GST_STATIC_CAPS ("subpicture/x-pgs; video/x-dvd-subpicture")
108 static GstStaticPadTemplate hlsdemux2_sink_template =
109 GST_STATIC_PAD_TEMPLATE ("sink",
112 GST_STATIC_CAPS ("application/x-hls"));
114 static GstStaticPadTemplate hlsdemux2_videosrc_template =
115 GST_STATIC_PAD_TEMPLATE ("video",
120 static GstStaticPadTemplate hlsdemux2_audiosrc_template =
121 GST_STATIC_PAD_TEMPLATE ("audio",
126 static GstStaticPadTemplate hlsdemux2_subpicture_template =
127 GST_STATIC_PAD_TEMPLATE ("subpicture",
130 HLS_SUBPICTURE_CAPS);
132 static GstStaticPadTemplate hlsdemux2_private_template =
133 GST_STATIC_PAD_TEMPLATE ("private",
136 GST_STATIC_CAPS_ANY);
138 GST_DEBUG_CATEGORY_STATIC (gst_hlsdemux2_debug);
139 #define GST_CAT_DEFAULT gst_hlsdemux2_debug
141 GST_DEBUG_CATEGORY (hlsdemux2_m3u8_debug);
143 static const float update_interval_factor[] = { 1, 0.5, 1.5, 3 };
145 #define HLS_DEFAULT_FRAME_DURATION (0.04 * GST_SECOND) // 40ms
146 #define DEFAULT_BLOCKSIZE (8 * 1024) // 8 kbytes
147 #define DEFAULT_FAST_SWITCH_BUFFER_SIZE 0.7 // factor
148 static void _do_init (GType type)
150 GST_DEBUG_CATEGORY_INIT (gst_hlsdemux2_debug, "hlsdemux2", 0, "hlsdemux2 element");
151 GST_DEBUG_CATEGORY_INIT (hlsdemux2_m3u8_debug, "hlsdemux2m3u8", 0, "m3u8 parser");
154 GST_BOILERPLATE_FULL (GstHLSDemux2, gst_hlsdemux2, GstElement, GST_TYPE_ELEMENT, _do_init);
156 #define DEFAULT_BITRATE_SWITCH_TOLERANCE 0.4
157 #define DEFAULT_FAILED_COUNT 3
158 #define DEFAULT_TARGET_DURATION 10
159 #define DEFAULT_NUM_FRAGMENTS_CACHE 3
160 #define DEFAULT_TOTAL_CACHE_DURATION (DEFAULT_NUM_FRAGMENTS_CACHE * DEFAULT_TARGET_DURATION * GST_SECOND)
162 #define PREDEFINED_VIDEO_FRAME_LOCATION "/usr/etc/sec_audio_fixed_qvga.264"
163 //#define PREDEFINED_VIDEO_FRAME_LOCATION "/usr/etc/blackframe_QVGA.264"
164 #define PREDEFINED_IMAGE_FRAME_LOCATION "/usr/etc/sec_audio_fixed_qvga.jpg"
166 #define HLSDEMUX2_SOUP_FAILED_CNT 10
167 #define DEFAULT_FORCE_LOWER_BITRATE FALSE
168 #define FORCE_LOW_BITRATE_AFTER_CNT 4
169 #define HLSDEMUX2_HTTP_TIMEOUT 30 //30sec
172 HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE = 0,
173 HLSDEMUX2_HTTP_ERROR_RECOVERABLE = 1,
176 typedef struct _HLSDemux2_HTTP_error HLSDemux2_HTTP_error;
178 typedef gboolean (*HLS_HTTP_error_handle_function) (GstHLSDemux2 *demux, gchar *element_name);
180 struct _HLSDemux2_HTTP_error {
181 guint HTTP_error_code;
182 const gchar *error_phrase;
184 HLS_HTTP_error_handle_function handle_error;
187 struct _GstHLSDemux2PvtStream
194 HLSDEMUX2_STREAM_TYPE type;
196 GstBuffer *id3_buffer;
197 GstBuffer *image_buffer;
198 GstBuffer *video_buffer;
199 gboolean got_img_buffer;
200 GstElement *convert_pipe;
201 GCond *img_load_cond;
202 GMutex *img_load_lock;
204 GMutex *convert_lock;
207 struct _GstHLSDemux2Stream
216 HLSDEMUX2_STREAM_TYPE type;
220 gint64 cached_duration;
221 GThread *dummy_data_thread; /* for pushing dummy video data */
222 GstClockTime base_ts; /* base ts start */
223 GstClockTime fts; /* first valid timestamp in a fragment */
224 GstClockTime lts; /* last valid timestamp in a fragment */
225 /* expected first timestamp in next fragment : usefule for handling fragments discontinuities*/
227 GstClockTime prev_nts; /* stores last nts for handling .aac files */
228 gboolean valid_fts_rcvd;
229 GstClockTime cdisc; /* current disc time */
230 GstClockTime frame_duration;
231 guint64 total_stream_time;
232 GstClockTime total_disc;
233 GQueue *downloader_queue;
234 gboolean need_newsegment;
235 GstEvent *newsegment;
238 /* GStreamer virtual functions */
239 static void gst_hlsdemux2_set_property (GObject * object, guint prop_id,
240 const GValue * value, GParamSpec * pspec);
241 static void gst_hlsdemux2_get_property (GObject * object, guint prop_id,
242 GValue * value, GParamSpec * pspec);
243 static gboolean gst_hlsdemux2_sink_event (GstPad * pad, GstEvent * event);
244 static GstStateChangeReturn gst_hlsdemux2_change_state (GstElement * element, GstStateChange transition);
245 static void gst_hlsdemux2_dispose (GObject * obj);
246 static GstFlowReturn gst_hlsdemux2_chain (GstPad * pad, GstBuffer * buf);
247 static gboolean gst_hlsdemux2_handle_src_event (GstPad * pad, GstEvent * event);
249 /* init & de-init functions */
250 static void gst_hlsdemux2_private_init (GstHLSDemux2 *demux);
251 static void gst_hlsdemux2_private_deinit (GstHLSDemux2 *demux);
252 static void gst_hlsdemux2_playlist_downloader_init (GstHLSDemux2 *demux);
253 static void gst_hlsdemux2_playlist_downloader_deinit (GstHLSDemux2 *demux);
254 static void gst_hlsdemux2_key_downloader_init (GstHLSDemux2 *demux);
255 static void gst_hlsdemux2_key_downloader_deinit (GstHLSDemux2 *demux);
256 static void gst_hlsdemux2_fragment_downloader_init (GstHLSDemux2 *demux);
257 static void gst_hlsdemux2_fragment_downloader_deinit (GstHLSDemux2 *demux);
259 /* helper functions */
260 static void gst_hlsdemux2_stop (GstHLSDemux2 * demux);
261 static gboolean gst_hlsdemux2_set_location (GstHLSDemux2 * demux, const gchar * uri);
262 static gchar *gst_hlsdemux2_src_buf_to_utf8_playlist (GstBuffer * buf);
263 static void gst_hlsdemux2_new_pad_added (GstElement *element, GstPad *pad, gpointer data);
264 static void gst_hlsdemux2_get_cookies(GstHLSDemux2 *demux);
265 static void gst_hlsdemux2_get_user_agent(GstHLSDemux2 *demux);
266 static gboolean gst_hlsdemux2_update_playlist (GstHLSDemux2 * demux, gboolean update, gboolean *is_error);
267 static gboolean gst_hlsdemux2_schedule (GstHLSDemux2 * demux);
268 static void gst_hlsdemux2_calculate_pushed_duration (GstHLSDemux2 *demux, GstHLSDemux2Stream *stream,
271 /* stream specific functions */
272 static void gst_hlsdemux2_stream_init (GstHLSDemux2 *demux, GstHLSDemux2Stream *stream,
273 HLSDEMUX2_STREAM_TYPE stream_type, gchar *name, GstCaps *src_caps);
274 static void gst_hlsdemux2_stream_deinit (GstHLSDemux2Stream *stream, gpointer data);
275 static void gst_hlsdemux2_stop_stream (GstHLSDemux2 *demux);
276 static HLSDemux2SinkBin *gst_hlsdemux2_create_stream (GstHLSDemux2 *demux, gchar *name, GstCaps *caps);
279 static void gst_hlsdemux2_push_loop (GstHLSDemux2Stream *stream);
280 static void gst_hlsdemux2_fragment_download_loop (GstHLSDemux2 * demux);
282 /* playlist download related functions */
283 static void gst_hlsdemux2_on_playlist_buffer (GstElement * appsink, void* data);
284 static GstBusSyncReply gst_hlsdemux2_playlist_download_bus_sync_cb (GstBus * bus, GstMessage *msg, gpointer data);
286 /* key file download related functions */
287 static gboolean gst_hlsdemux2_key_download_bus_cb(GstBus *bus, GstMessage *msg, gpointer data);
288 static void gst_hlsdemux2_on_key_buffer (GstElement *appsink, void *data);
290 /* fragment download related functions */
291 static gboolean gst_hlsdemux2_fragment_download_bus_cb(GstBus *bus, GstMessage *msg, gpointer data);
292 static void gst_hlsdemux2_downloader_new_buffer (GstElement *appsink, void *user_data);
293 static void gst_hlsdemux2_downloader_eos (GstElement * appsink, void* user_data);
295 /* probe functions */
296 static gboolean gst_hlsdemux2_sink_event_handler (GstPad * pad, GstEvent * event, gpointer data);
297 static gboolean gst_hlsdemux2_change_playlist (GstHLSDemux2 * demux, guint max_bitrate, gboolean *is_switched);
298 static gboolean gst_hlsdemux2_download_monitor_thread (GstHLSDemux2 *demux);
299 static void gst_hlsdemux2_push_eos (GstHLSDemux2 *demux);
300 static void gst_hlsdemux2_apply_disc (GstHLSDemux2 * demux);
301 static gboolean gst_hlsdemux2_queue_buffer_handler (GstPad * pad, GstBuffer *buffer, gpointer data);
302 static gboolean hlsdemux2_HTTP_not_found(GstHLSDemux2 *demux, gchar *element_name);
303 static gboolean hlsdemux2_HTTP_time_out (GstHLSDemux2 *demux, gchar *element_name);
304 static gboolean hlsdemux2_HTTP_repeat_request (GstHLSDemux2 *demux, gchar *element_name);
305 static void gst_hlsdemux2_handle_private_pad (GstHLSDemux2 *demux, GstPad *srcpad);
306 static void gst_hlsdemux2_private_sink_on_new_buffer (GstElement *appsink, void *user_data);
307 static void gst_hlsdemux2_private_sink_on_eos (GstElement * appsink, void* user_data);
308 static gboolean gst_hlsdemux2_imagebuf_pipe_bus_cb (GstBus *bus, GstMessage *msg, gpointer data);
309 static gboolean gst_hlsdemux2_set_video_buffer (GstPad * srcpad, GstBuffer * buffer, gpointer user_data);
310 static gboolean gst_hlsdemux2_done_video_buffer (GstPad * srcpad, GstEvent * event, gpointer user_data);
311 static gboolean gst_hlsdemux2_check_fast_switch (GstHLSDemux2 *demux);
313 static const HLSDemux2_HTTP_error http_errors[] = {
315 /* transport errors by libsoup */
316 { 1, "Cancelled", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
317 { 2, "Cannot resolve hostname", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
318 { 3, "Cannot resolve proxy hostname", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
319 { 4, "Cannot connect to destination", HLSDEMUX2_HTTP_ERROR_RECOVERABLE, hlsdemux2_HTTP_repeat_request },
320 { 5, "Cannot connect to proxy", HLSDEMUX2_HTTP_ERROR_RECOVERABLE, hlsdemux2_HTTP_repeat_request },
321 { 6, "SSL handshake failed", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
322 { 7, "Connection terminated unexpectedly", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
323 { 8, "Message Corrupt", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
324 { 9, "Too many redirects", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
327 { 400, "Bad Request", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
328 { 401, "Unauthorized", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
329 { 402, "Payment Required", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
330 { 403, "Forbidden", HLSDEMUX2_HTTP_ERROR_RECOVERABLE, hlsdemux2_HTTP_repeat_request }, // TODO: Currently taking it as recoverable for testing
331 { 404, "Not Found", HLSDEMUX2_HTTP_ERROR_RECOVERABLE, hlsdemux2_HTTP_not_found },
332 { 405, "Method Not Allowed", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
333 { 406, "Not Acceptable", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
334 { 407, "Proxy Authentication Required", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
335 { 408, "Request Timeout", HLSDEMUX2_HTTP_ERROR_RECOVERABLE, hlsdemux2_HTTP_time_out },
336 { 409, "Conflict", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
337 { 410, "Gone", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
338 { 411, "Length Required", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
339 { 412, "Precondition Failed", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
340 { 413, "Request Entity Too Large", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
341 { 414, "Request-URI Too Long", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
342 { 415, "Unsupported Media Type", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
343 { 416, "Requested Range Not Satisfiable", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
344 { 417, "Expectation Failed", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
345 { 418, "Unprocessable Entity", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
346 { 419, "Locked", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
347 { 420, "Failed Dependency", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
350 { 500, "Internal Server Error", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
351 { 501, "Not Implemented", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
352 { 502, "Bad Gateway", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
353 { 503, "Service Unavailable", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL }, // TODO: need to make as recoverable with timout value
354 { 504, "Gateway Timeout", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
355 { 505, "HTTP Version Not Supported", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
356 { 506, "Insufficient Storage", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
357 { 507, "Not Extended", HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE, NULL },
362 gst_hlsdemux2_base_init (gpointer g_class)
364 GstElementClass *element_class= GST_ELEMENT_CLASS (g_class);
366 gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&hlsdemux2_videosrc_template));
367 gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&hlsdemux2_audiosrc_template));
368 gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&hlsdemux2_subpicture_template));
369 gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&hlsdemux2_sink_template));
371 gst_element_class_set_details_simple (element_class,
374 "HTTP Live Streaming (HLS) demuxer",
375 "Naveen Cherukuri<naveen.ch@samsung.com>");
379 gst_hlsdemux2_class_init (GstHLSDemux2Class * klass)
381 GObjectClass *gobject_class;
382 GstElementClass *gstelement_class;
384 gobject_class = (GObjectClass *) klass;
385 gstelement_class = (GstElementClass *) klass;
387 gobject_class->set_property = gst_hlsdemux2_set_property;
388 gobject_class->get_property = gst_hlsdemux2_get_property;
389 gobject_class->dispose = gst_hlsdemux2_dispose;
391 g_object_class_install_property (gobject_class, PROP_BITRATE_SWITCH_TOLERANCE,
392 g_param_spec_float ("bitrate-switch-tolerance",
393 "Bitrate switch tolerance",
394 "Tolerance with respect of the fragment duration to switch to "
395 "a different bitrate if the client is too slow/fast.",
396 0, 1, DEFAULT_BITRATE_SWITCH_TOLERANCE,
397 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
399 g_object_class_install_property (gobject_class, PROP_FORCE_LOWER_BITRATE,
400 g_param_spec_boolean ("force-low-bitrate",
401 "forcing lower variant", "forcing lower variant after every few fragments [for debugging purpose only]",
402 DEFAULT_FORCE_LOWER_BITRATE,
403 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
405 g_object_class_install_property (gobject_class, PROP_BLOCKSIZE,
406 g_param_spec_ulong ("blocksize", "Block size",
407 "Size in bytes to read per buffer (-1 = default)", 0, G_MAXULONG,
408 DEFAULT_BLOCKSIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
410 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_hlsdemux2_change_state);
414 gst_hlsdemux2_init (GstHLSDemux2 * demux, GstHLSDemux2Class * klass)
417 demux->sinkpad = gst_pad_new_from_static_template (&hlsdemux2_sink_template, "sink");
418 gst_pad_set_chain_function (demux->sinkpad, GST_DEBUG_FUNCPTR (gst_hlsdemux2_chain));
419 gst_pad_set_event_function (demux->sinkpad, GST_DEBUG_FUNCPTR (gst_hlsdemux2_sink_event));
420 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
422 gst_hlsdemux2_private_init (demux);
424 /* fragment downloader init */
425 gst_hlsdemux2_fragment_downloader_init (demux);
427 /* playlist downloader init */
428 gst_hlsdemux2_playlist_downloader_init (demux);
430 /* key downloader init */
431 gst_hlsdemux2_key_downloader_init (demux);
436 gst_hlsdemux2_dispose (GObject * obj)
438 GstHLSDemux2 *demux = GST_HLSDEMUX2 (obj);
440 GST_INFO_OBJECT (demux,"entering");
442 gst_hlsdemux2_stop (demux);
444 gst_hlsdemux2_private_deinit (demux);
446 gst_hlsdemux2_fragment_downloader_deinit (demux);
448 gst_hlsdemux2_playlist_downloader_deinit (demux);
450 gst_hlsdemux2_key_downloader_deinit (demux);
452 GST_INFO_OBJECT (demux,"leaving");
454 G_OBJECT_CLASS (parent_class)->dispose (obj);
458 gst_hlsdemux2_private_init (GstHLSDemux2 *demux)
460 demux->is_live = TRUE;
461 demux->bitrate_switch_tol = DEFAULT_BITRATE_SWITCH_TOLERANCE;
462 demux->percent = 100;
463 demux->active_stream_cnt = 0;
464 demux->download_task = NULL;
465 demux->pl_update_lock = g_mutex_new ();
466 demux->pl_update_cond = g_cond_new ();
467 demux->cancelled = FALSE;
468 demux->total_cache_duration = DEFAULT_TOTAL_CACHE_DURATION;
469 demux->target_duration = DEFAULT_TARGET_DURATION;
470 demux->keyCookie = NULL;
471 demux->playlistCookie = NULL;
472 demux->fragCookie = NULL;
473 demux->lastCookie = NULL;
474 demux->keyDomain = NULL;
475 demux->playlistDomain = NULL;
476 demux->fragDomain = NULL;
477 demux->lastDomain = NULL;
478 demux->user_agent = NULL;
479 demux->buffering_lock = g_mutex_new ();
480 demux->soup_request_fail_cnt = HLSDEMUX2_SOUP_FAILED_CNT;
481 demux->force_lower_bitrate = DEFAULT_FORCE_LOWER_BITRATE;
482 demux->cfrag_dur = 0;
483 demux->error_posted = FALSE;
484 demux->playlist_uri = NULL;
485 demux->frag_uri = NULL;
486 demux->key_uri = NULL;
487 demux->blocksize = DEFAULT_BLOCKSIZE;
488 demux->flushing = FALSE;
490 demux->cur_audio_fts = GST_CLOCK_TIME_NONE;
491 demux->is_buffering = TRUE;
492 demux->buffering_posting_thread = NULL;
493 demux->post_msg_lock = g_mutex_new ();
494 demux->post_msg_start = g_cond_new ();
495 demux->post_msg_exit = g_cond_new ();
496 demux->stream_config = HLSDEMUX2_SINGLE_VARIANT;
497 demux->has_image_buffer = FALSE;
498 demux->prev_image_buffer = NULL;
499 demux->prev_video_buffer = NULL;
500 demux->private_stream = NULL;
504 gst_hlsdemux2_private_deinit (GstHLSDemux2 *demux)
506 demux->end_of_playlist = FALSE;
508 if (demux->pl_update_lock) {
509 g_mutex_free (demux->pl_update_lock);
510 demux->pl_update_lock = NULL;
513 if (demux->pl_update_cond) {
514 g_cond_free (demux->pl_update_cond);
515 demux->pl_update_cond = NULL;
518 if (demux->buffering_lock) {
519 g_mutex_free (demux->buffering_lock);
520 demux->buffering_lock = NULL;
523 if (demux->user_agent) {
524 g_free (demux->user_agent);
525 demux->user_agent = NULL;
528 if (demux->playlist) {
529 gst_buffer_unref (demux->playlist);
530 demux->playlist = NULL;
533 if (demux->fragCookie) {
534 g_strfreev (demux->fragCookie);
535 demux->fragCookie = NULL;
538 if (demux->keyCookie) {
539 g_strfreev (demux->keyCookie);
540 demux->keyCookie = NULL;
543 if (demux->lastCookie) {
544 g_strfreev (demux->lastCookie);
545 demux->lastCookie = NULL;
548 if (demux->playlistCookie) {
549 g_strfreev (demux->playlistCookie);
550 demux->playlistCookie = NULL;
553 if (demux->fragDomain) {
554 g_free (demux->fragDomain);
555 demux->fragDomain = NULL;
558 if (demux->keyDomain) {
559 g_free (demux->keyDomain);
560 demux->keyDomain = NULL;
563 if (demux->lastDomain) {
564 g_free (demux->lastDomain);
565 demux->lastDomain = NULL;
568 if (demux->playlistDomain) {
569 g_free (demux->playlistDomain);
570 demux->playlistDomain = NULL;
573 if (demux->playlist_uri) {
574 g_free (demux->playlist_uri);
575 demux->playlist_uri = NULL;
578 if (demux->key_uri) {
579 g_free (demux->key_uri);
580 demux->key_uri = NULL;
583 if (demux->frag_uri) {
584 g_free (demux->frag_uri);
585 demux->frag_uri = NULL;
588 if (demux->prev_image_buffer) {
589 gst_buffer_unref (demux->prev_image_buffer);
590 demux->prev_image_buffer = NULL;
593 if (demux->prev_video_buffer) {
594 gst_buffer_unref (demux->prev_video_buffer);
595 demux->prev_video_buffer = NULL;
598 if (demux->private_stream) {
599 g_free (demux->private_stream);
600 demux->private_stream = NULL;
604 gst_m3u8_client_free (demux->client);
605 demux->client = NULL;
610 gst_hlsdemux2_fragment_downloader_init (GstHLSDemux2 *demux)
612 demux->fdownloader = g_new0 (HLSDemux2FragDownloader, 1);
613 demux->fdownloader->pipe = NULL;
614 demux->fdownloader->urisrc = NULL;
615 demux->fdownloader->queue = NULL;
616 demux->fdownloader->typefind = NULL;
617 demux->fdownloader->demuxer = NULL;
618 demux->fdownloader->sinkbins = NULL;
619 demux->fdownloader->lock = g_mutex_new ();
620 demux->fdownloader->cond = g_cond_new ();
621 demux->fdownloader->is_encrypted = FALSE;
622 demux->fdownloader->content_size = 0;
623 demux->fdownloader->get_next_frag = FALSE;
624 demux->fdownloader->applied_fast_switch = FALSE;
625 demux->fdownloader->remaining_data = NULL;
626 demux->fdownloader->remaining_size = 0;
627 demux->fdownloader->first_buffer = TRUE;
628 demux->fdownloader->cur_stream_cnt = 0;
629 demux->fdownloader->force_timestamps = FALSE;
630 demux->fdownloader->error_rcvd = FALSE;
631 demux->fdownloader->find_mediaseq = FALSE;
632 demux->fdownloader->seeked_pos = 0;
633 demux->fdownloader->cur_running_dur = 0;
634 demux->fdownloader->download_rate = -1;
635 demux->fdownloader->download_start_ts = 0;
636 demux->fdownloader->download_stop_ts = 0;
637 demux->fdownloader->src_downloaded_size = 0;
638 demux->fdownloader->queue_downloaded_size = 0;
639 demux->fdownloader->ndownloaded = 0;
640 demux->fdownloader->chunk_downloaded_size = 0;
641 demux->fdownloader->chunk_start_ts = 0;
642 demux->fdownloader->avg_chunk_drates = g_array_new(FALSE, TRUE, sizeof(guint64));
643 demux->fdownloader->avg_frag_drates = g_array_new(FALSE, TRUE, sizeof(guint64));
647 gst_hlsdemux2_fragment_downloader_deinit (GstHLSDemux2 *demux)
649 if (!demux->fdownloader)
652 /* free fragment downloader structure */
653 if (demux->fdownloader->lock) {
654 g_mutex_free (demux->fdownloader->lock);
655 demux->fdownloader->lock = NULL;
658 if (demux->fdownloader->cond) {
659 g_cond_free (demux->fdownloader->cond);
660 demux->fdownloader->cond = NULL;
663 if (demux->fdownloader->remaining_data) {
664 g_free (demux->fdownloader->remaining_data);
665 demux->fdownloader->remaining_data = NULL;
668 if (demux->fdownloader->avg_chunk_drates) {
669 g_array_free(demux->fdownloader->avg_chunk_drates, TRUE);
670 demux->fdownloader->avg_chunk_drates = NULL;
673 if (demux->fdownloader->avg_frag_drates) {
674 g_array_free(demux->fdownloader->avg_frag_drates, TRUE);
675 demux->fdownloader->avg_frag_drates = NULL;
678 g_free (demux->fdownloader);
679 demux->fdownloader = NULL;
683 gst_hlsdemux2_playlist_downloader_init (GstHLSDemux2 *demux)
685 demux->pldownloader = g_new0 (HLSDemux2PLDownloader, 1);
686 demux->pldownloader->pipe = NULL;
687 demux->pldownloader->bus = NULL;
688 demux->pldownloader->urisrc = NULL;
689 demux->pldownloader->sink = NULL;
690 demux->pldownloader->lock = g_mutex_new ();
691 demux->pldownloader->cond = g_cond_new ();
692 demux->pldownloader->playlist = NULL;
693 demux->pldownloader->recovery_mode = HLSDEMUX2_NO_RECOVERY;
697 gst_hlsdemux2_playlist_downloader_deinit (GstHLSDemux2 *demux)
699 if (!demux->pldownloader)
702 /* free playlist downloader structure */
703 if (demux->pldownloader->lock) {
704 g_mutex_free (demux->pldownloader->lock);
705 demux->pldownloader->lock = NULL;
708 if (demux->pldownloader->cond) {
709 g_cond_free (demux->pldownloader->cond);
710 demux->pldownloader->cond = NULL;
713 if (demux->pldownloader->playlist){
714 gst_buffer_unref (demux->pldownloader->playlist);
715 demux->pldownloader->playlist = NULL;
718 g_free (demux->pldownloader);
719 demux->pldownloader = NULL;
723 gst_hlsdemux2_key_downloader_init (GstHLSDemux2 *demux)
725 demux->kdownloader = g_new0 (HLSDemux2KeyDownloader, 1);
726 demux->kdownloader->pipe = NULL;
727 demux->kdownloader->bus = NULL;
728 demux->kdownloader->urisrc = NULL;
729 demux->kdownloader->sink = NULL;
730 demux->kdownloader->lock = g_mutex_new ();
731 demux->kdownloader->cond = g_cond_new ();
732 demux->kdownloader->key = NULL;
733 demux->kdownloader->prev_key_uri = NULL;
737 gst_hlsdemux2_key_downloader_deinit (GstHLSDemux2 *demux)
739 /* free key file downloader structure */
740 if (!demux->kdownloader)
743 if (demux->kdownloader->lock) {
744 g_mutex_free (demux->kdownloader->lock);
745 demux->kdownloader->lock = NULL;
748 if (demux->kdownloader->cond) {
749 g_cond_free (demux->kdownloader->cond);
750 demux->kdownloader->cond = NULL;
753 if (demux->kdownloader->key){
754 gst_buffer_unref (demux->kdownloader->key);
755 demux->kdownloader->key = NULL;
758 if (demux->kdownloader->prev_key_uri) {
759 g_free (demux->kdownloader->prev_key_uri);
760 demux->kdownloader->prev_key_uri = NULL;
763 g_free (demux->kdownloader);
764 demux->kdownloader = NULL;
768 gst_hlsdemux2_set_property (GObject * object, guint prop_id,
769 const GValue * value, GParamSpec * pspec)
771 GstHLSDemux2 *demux = GST_HLSDEMUX2 (object);
774 case PROP_BITRATE_SWITCH_TOLERANCE:
775 demux->bitrate_switch_tol = g_value_get_float (value);
777 case PROP_FORCE_LOWER_BITRATE:
778 demux->force_lower_bitrate = g_value_get_boolean (value);
781 demux->blocksize = g_value_get_ulong (value);
784 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
790 gst_hlsdemux2_get_property (GObject * object, guint prop_id,
791 GValue * value, GParamSpec * pspec)
793 GstHLSDemux2 *demux = GST_HLSDEMUX2 (object);
796 case PROP_BITRATE_SWITCH_TOLERANCE:
797 g_value_set_float (value, demux->bitrate_switch_tol);
799 case PROP_FORCE_LOWER_BITRATE:
800 g_value_set_boolean (value, demux->force_lower_bitrate);
803 g_value_set_ulong (value, demux->blocksize);
806 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
812 gst_hlsdemux2_sink_event (GstPad * pad, GstEvent * event)
814 GstHLSDemux2 *demux = GST_HLSDEMUX2 (gst_pad_get_parent (pad));
815 GstQuery *query = NULL;
816 gboolean ret = FALSE;
819 GST_LOG_OBJECT (demux, "Received event '%s' on sink pad...", GST_EVENT_TYPE_NAME (event));
821 switch (event->type) {
822 case GST_EVENT_EOS: {
823 gchar *playlist = NULL;
826 if (demux->playlist == NULL) {
827 GST_ERROR_OBJECT (demux, "Received EOS without a playlist.");
831 GST_INFO_OBJECT (demux, "Got EOS on the sink pad: playlist file fetched");
833 query = gst_query_new_uri ();
835 /* query the location from upstream element for absolute path */
836 ret = gst_pad_peer_query (demux->sinkpad, query);
838 gst_query_parse_uri (query, &uri);
839 gst_hlsdemux2_set_location (demux, uri);
842 GST_ERROR_OBJECT (demux, "failed to query URI from upstream");
845 gst_query_unref (query);
848 /* get cookies from upstream httpsrc */
849 gst_hlsdemux2_get_cookies (demux);
851 /* get user-agent from upstream httpsrc */
852 gst_hlsdemux2_get_user_agent (demux);
854 playlist = gst_hlsdemux2_src_buf_to_utf8_playlist (demux->playlist);
855 demux->playlist = NULL;
857 if (playlist == NULL) {
858 GST_ERROR_OBJECT (demux, "Error validating first playlist.");
859 GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Invalid playlist."), (NULL));
863 if (!gst_m3u8_client_update (demux->client, playlist)) {
864 /* In most cases, this will happen if we set a wrong url in the
865 * source element and we have received the 404 HTML response instead of
867 GST_ERROR_OBJECT (demux, "failed to parse playlist...");
868 GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Invalid playlist."), (NULL));
872 /* Loop to download the fragments & updates playlist */
873 g_static_rec_mutex_init (&demux->download_lock);
874 demux->download_task = gst_task_create ((GstTaskFunction) gst_hlsdemux2_fragment_download_loop, demux);
875 if (NULL == demux->download_task) {
876 GST_ERROR_OBJECT (demux, "failed to create download task...");
877 GST_ELEMENT_ERROR (demux, RESOURCE, FAILED, ("failed to fragment download task"), (NULL));
880 gst_task_set_lock (demux->download_task, &demux->download_lock);
881 gst_task_start (demux->download_task);
883 /* create thread to send dummy data */
884 demux->buffering_posting_thread = g_thread_create (
885 (GThreadFunc) gst_hlsdemux2_download_monitor_thread, demux, TRUE, &err);
887 /* Swallow EOS, we'll push our own */
888 gst_event_unref (event);
889 gst_object_unref (demux);
892 case GST_EVENT_NEWSEGMENT:
893 /* Swallow newsegments, we'll push our own */
894 gst_event_unref (event);
895 gst_object_unref (demux);
898 gst_object_unref (demux);
902 return gst_pad_event_default (pad, event);
905 gst_hlsdemux2_stop (demux);
906 gst_event_unref (event);
907 gst_object_unref (demux);
910 gst_query_unref (query);
912 GST_LOG_OBJECT (demux,"Returning from sink event...");
916 static GstStateChangeReturn
917 gst_hlsdemux2_change_state (GstElement * element, GstStateChange transition)
919 GstStateChangeReturn ret;
920 GstHLSDemux2 *demux = GST_HLSDEMUX2 (element);
921 gboolean bret = FALSE;
923 switch (transition) {
924 case GST_STATE_CHANGE_READY_TO_PAUSED:
926 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
927 GST_INFO_OBJECT (demux,"PAUSED->PLAYING");
929 case GST_STATE_CHANGE_PAUSED_TO_READY:
930 GST_INFO_OBJECT (demux,"PAUSED->READY before parent");
931 gst_hlsdemux2_stop (demux);
937 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
939 switch (transition) {
940 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
941 GST_INFO_OBJECT (demux,"PLAYING->PAUSED");
943 case GST_STATE_CHANGE_PAUSED_TO_READY:
944 GST_INFO_OBJECT (demux,"PAUSED->READY after parent");
945 if (demux->download_task) {
946 bret = gst_task_join (demux->download_task);
947 GST_DEBUG_OBJECT (demux,"Joining download task : %d", bret);
950 case GST_STATE_CHANGE_READY_TO_NULL:
951 GST_INFO_OBJECT (demux,"READY->NULL");
962 gst_hlsdemux2_chain (GstPad * pad, GstBuffer * buf)
964 GstHLSDemux2 *demux = GST_HLSDEMUX2 (gst_pad_get_parent (pad));
966 if (demux->playlist == NULL)
967 demux->playlist = buf;
969 demux->playlist = gst_buffer_join (demux->playlist, buf);
970 gst_object_unref (demux);
976 gst_hlsdemux2_handle_src_event (GstPad * pad, GstEvent * event)
978 GstHLSDemux2 *hlsdemux2 = NULL;
979 GstHLSDemux2Stream *stream = NULL;
981 stream = (GstHLSDemux2Stream *) (gst_pad_get_element_private (pad));
982 hlsdemux2 = stream->parent;
984 switch (event->type) {
985 case GST_EVENT_SEEK: {
989 GstSeekType start_type, stop_type;
993 if (gst_m3u8_client_is_live (hlsdemux2->client)) {
994 GST_WARNING_OBJECT (stream->pad, "SEEK is NOT Supported in LIVE");
998 GST_INFO_OBJECT (stream->pad, "received SEEK event..");
1000 gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
1003 if (format != GST_FORMAT_TIME) {
1004 GST_WARNING_OBJECT (stream->pad, "received seek with unsupported format");
1008 // TODO: Validate requested SEEK time is within the duration or not
1010 hlsdemux2->end_of_playlist = FALSE; // resent end of playlist
1012 GST_DEBUG_OBJECT (stream->pad, "SEEK event with rate: %f start: %" GST_TIME_FORMAT
1013 " stop: %" GST_TIME_FORMAT, rate, GST_TIME_ARGS (start),
1014 GST_TIME_ARGS (stop));
1016 if (!(flags & GST_SEEK_FLAG_FLUSH)) {
1017 GST_WARNING_OBJECT (stream->pad, "non-flush seek is not supported yet");
1021 hlsdemux2->flushing = TRUE;
1023 /* signal queue full condition to come out */
1024 for (idx = 0; idx < HLSDEMUX2_STREAM_NUM; idx++) {
1025 GstHLSDemux2Stream *cur_stream = hlsdemux2->streams[idx];
1028 cur_stream->eos = FALSE; // resent stream EOS
1029 if (cur_stream->queue) {
1030 GST_INFO_OBJECT (cur_stream->pad, "signalling stream queue");
1031 g_cond_signal (cur_stream->queue_full); /* to signal downloader eos blocking */
1032 g_cond_signal (cur_stream->queue_empty); /* incase push_loop blocked on condition */
1037 /* send FLUSH_START event to all source pads */
1038 if (flags & GST_SEEK_FLAG_FLUSH) {
1040 GST_INFO_OBJECT (hlsdemux2, "sending flush start on all the stream pads");
1042 for (idx = 0; idx < HLSDEMUX2_STREAM_NUM; idx++) {
1043 GstHLSDemux2Stream *cur_stream = hlsdemux2->streams[idx];
1045 if (cur_stream && GST_PAD_TASK(cur_stream->pad)) {
1046 gboolean bret = FALSE;
1047 bret = gst_pad_push_event (cur_stream->pad, gst_event_new_flush_start ());
1048 GST_DEBUG_OBJECT (cur_stream->pad, "flush_start returned = %d", bret);
1053 /* wait till all stream pad's task paused */
1054 for (idx = 0; idx < HLSDEMUX2_STREAM_NUM; idx++) {
1055 GstHLSDemux2Stream *cur_stream = hlsdemux2->streams[idx];
1057 if (cur_stream && GST_PAD_TASK(cur_stream->pad)) {
1058 GST_INFO_OBJECT (cur_stream->pad, "trying acquire stream lock");
1059 GST_PAD_STREAM_LOCK (cur_stream->pad);
1060 GST_INFO_OBJECT (cur_stream->pad, "acquired stream lock");
1061 GST_PAD_STREAM_UNLOCK (cur_stream->pad);
1065 /* pause fragment download loop */
1066 g_mutex_lock (hlsdemux2->kdownloader->lock);
1067 GST_INFO_OBJECT (stream->pad, "Signalling key downloader condition");
1068 g_cond_signal (hlsdemux2->kdownloader->cond);
1069 g_mutex_unlock (hlsdemux2->kdownloader->lock);
1071 g_mutex_lock (hlsdemux2->fdownloader->lock);
1072 GST_INFO_OBJECT (stream->pad, "Signalling fragment downloader condition");
1073 g_cond_signal (hlsdemux2->fdownloader->cond);
1074 g_mutex_unlock (hlsdemux2->fdownloader->lock);
1076 g_mutex_lock (hlsdemux2->pldownloader->lock);
1077 GST_INFO_OBJECT (stream->pad, "Signalling playlist downloader condition");
1078 g_cond_signal (hlsdemux2->pldownloader->cond);
1079 g_mutex_unlock (hlsdemux2->pldownloader->lock);
1081 GST_INFO_OBJECT (stream->pad, "waiting for download task to pause...");
1082 g_static_rec_mutex_lock (&hlsdemux2->download_lock);
1083 g_static_rec_mutex_unlock (&hlsdemux2->download_lock);
1085 GST_INFO_OBJECT (hlsdemux2, "Download task paused");
1087 /* clear internal stream queues */
1088 for (idx = 0; idx < HLSDEMUX2_STREAM_NUM; idx++) {
1089 GstHLSDemux2Stream *cur_stream = hlsdemux2->streams[idx];
1091 if (cur_stream && cur_stream->queue) {
1092 while (!g_queue_is_empty (cur_stream->queue)) {
1093 gpointer data = NULL;
1094 data = g_queue_pop_head (cur_stream->queue);
1095 gst_object_unref (data);
1097 g_queue_clear (cur_stream->queue);
1098 cur_stream->cached_duration = 0;
1099 stream->percent = 0;
1101 while (!g_queue_is_empty (cur_stream->downloader_queue)) {
1102 gpointer data = NULL;
1103 data = g_queue_pop_head (cur_stream->downloader_queue);
1104 gst_object_unref (data);
1106 g_queue_clear (cur_stream->downloader_queue);
1110 #if 0 /* useful when we want to switch to lowest variant on seek for faster buffering */
1111 if (gst_m3u8_client_has_variant_playlist (hlsdemux2->client)) {
1112 /* intentionally sending zero download rate, to move to least possible variant */
1113 gst_hlsdemux2_change_playlist (hlsdemux2, 0, NULL);
1117 /* send FLUSH_STOP event to all source pads */
1118 if (flags & GST_SEEK_FLAG_FLUSH) {
1120 GST_INFO_OBJECT (hlsdemux2, "sending flush stop");
1122 for (idx = 0; idx < HLSDEMUX2_STREAM_NUM; idx++) {
1123 GstHLSDemux2Stream *cur_stream = hlsdemux2->streams[idx];
1125 if (cur_stream && GST_PAD_TASK(cur_stream->pad)) {
1126 gboolean bret = FALSE;
1127 bret = gst_pad_push_event (cur_stream->pad, gst_event_new_flush_stop ());
1128 GST_DEBUG_OBJECT (cur_stream->pad, "flush_stop returned = %d", bret);
1133 hlsdemux2->flushing = FALSE;
1134 hlsdemux2->fdownloader->find_mediaseq = TRUE;
1135 hlsdemux2->fdownloader->seeked_pos = start;
1137 /* start all streams loop tasks & fragment download task */
1138 for (idx = 0; idx < HLSDEMUX2_STREAM_NUM; idx++) {
1139 GstHLSDemux2Stream *cur_stream = hlsdemux2->streams[idx];
1141 if (cur_stream && GST_PAD_TASK(cur_stream->pad)) {
1142 GST_INFO_OBJECT (cur_stream->pad, "Starting push task");
1143 cur_stream->need_newsegment = TRUE;
1144 cur_stream->nts = GST_CLOCK_TIME_NONE; /*useful for audio-only seeking */
1145 cur_stream->cdisc = 0;
1146 cur_stream->fts = GST_CLOCK_TIME_NONE;
1147 cur_stream->valid_fts_rcvd = FALSE;
1148 cur_stream->total_stream_time = 0;
1150 if (!gst_pad_start_task (cur_stream->pad, (GstTaskFunction) gst_hlsdemux2_push_loop, cur_stream)) {
1151 GST_ERROR_OBJECT (hlsdemux2, "failed to start stream task...");
1152 GST_ELEMENT_ERROR (hlsdemux2, RESOURCE, FAILED, ("failed to create stream push loop"), (NULL));
1158 gst_hlsdemux2_apply_disc (hlsdemux2);
1160 GST_INFO_OBJECT (hlsdemux2, "Starting Download task..");
1162 gst_task_start (hlsdemux2->download_task);
1164 GST_INFO_OBJECT (hlsdemux2, "Successfully configured SEEK...");
1165 gst_event_unref (event);
1172 return gst_pad_event_default (pad, event);
1175 GST_ERROR_OBJECT (hlsdemux2, "seeking failed...");
1176 gst_event_unref (event);
1181 gst_hlsdemux2_src_query (GstPad *pad, GstQuery * query)
1183 GstHLSDemux2 *hlsdemux2 = NULL;
1184 gboolean ret = FALSE;
1185 GstHLSDemux2Stream *stream = NULL;
1190 stream = (GstHLSDemux2Stream *) (gst_pad_get_element_private (pad));
1191 hlsdemux2 = stream->parent;
1193 switch (query->type) {
1194 case GST_QUERY_DURATION:{
1195 GstClockTime duration = -1;
1198 gst_query_parse_duration (query, &fmt, NULL);
1199 if (fmt == GST_FORMAT_TIME) {
1200 duration = gst_m3u8_client_get_duration (hlsdemux2->client);
1201 if (GST_CLOCK_TIME_IS_VALID (duration) && duration > 0) {
1202 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
1206 GST_LOG_OBJECT (hlsdemux2, "GST_QUERY_DURATION returns %s with duration %"
1207 GST_TIME_FORMAT, ret ? "TRUE" : "FALSE", GST_TIME_ARGS (duration));
1211 if (hlsdemux2->client) {
1212 /* FIXME: Do we answer with the variant playlist, with the current
1213 * playlist or the the uri of the least downlowaded fragment? */
1214 gst_query_set_uri (query, gst_m3u8_client_get_uri (hlsdemux2->client));
1218 case GST_QUERY_SEEKING:{
1222 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
1223 GST_INFO_OBJECT (hlsdemux2, "Received GST_QUERY_SEEKING with format %d",
1225 if (fmt == GST_FORMAT_TIME) {
1226 GstClockTime duration;
1228 duration = gst_m3u8_client_get_duration (hlsdemux2->client);
1229 if (GST_CLOCK_TIME_IS_VALID (duration) && duration > 0)
1232 gst_query_set_seeking (query, fmt,
1233 !gst_m3u8_client_is_live (hlsdemux2->client), 0, stop);
1235 GST_INFO_OBJECT (hlsdemux2, "GST_QUERY_SEEKING returning with stop : %"
1236 GST_TIME_FORMAT, GST_TIME_ARGS (stop));
1241 /* Don't fordward queries upstream because of the special nature of this
1242 * "demuxer", which relies on the upstream element only to be fed with the
1251 gst_hlsdemux2_uri_get_domain ( GstHLSDemux2 *demux, gchar * uri)
1253 gchar *pointer = uri;
1254 gchar *domain = NULL;
1258 domain = g_malloc0(strlen (uri));
1260 GST_ERROR_OBJECT (demux, "failed to allocate memory...\n");
1261 GST_ELEMENT_ERROR (demux, RESOURCE, NO_SPACE_LEFT, ("can't allocate memory"), (NULL));
1265 while(*pointer != '\0') {
1276 domain[counter]=*pointer;
1278 } else if(flag == 2) {
1279 domain[counter]='\0';
1285 GST_DEBUG_OBJECT (demux, "uri = %s and domain = %s", uri, domain);
1290 gst_hlsdemux2_get_cookies(GstHLSDemux2 *demux)
1293 GstStructure *structure;
1294 gboolean bret = FALSE;
1296 structure = gst_structure_new ("HTTPCookies",
1297 "cookies", G_TYPE_STRING, NULL, NULL);
1299 cquery = gst_query_new_application (GST_QUERY_CUSTOM, structure);
1301 bret = gst_pad_peer_query (demux->sinkpad, cquery);
1303 const GstStructure *s;
1304 const GValue *value;
1306 s = gst_query_get_structure (cquery);
1307 value = gst_structure_get_value (s, "cookies");
1308 demux->playlistCookie = g_strdupv (g_value_get_boxed (value));
1310 GST_INFO_OBJECT (demux, "Received playlist cookies from upstream element : %s", demux->playlistCookie ? *(demux->playlistCookie) : NULL);
1311 if(demux->playlistCookie){
1312 demux->lastCookie = g_strdupv(demux->playlistCookie);
1315 GST_WARNING_OBJECT (demux, "Failed to get cookies");
1318 gst_query_unref (cquery);
1322 gst_hlsdemux2_get_user_agent(GstHLSDemux2 *demux)
1325 GstStructure *structure;
1326 gboolean bret = FALSE;
1328 structure = gst_structure_new ("HTTPUserAgent",
1329 "user-agent", G_TYPE_STRING, NULL, NULL);
1331 cquery = gst_query_new_application (GST_QUERY_CUSTOM, structure);
1333 bret = gst_pad_peer_query (demux->sinkpad, cquery);
1335 const GstStructure *s;
1336 const GValue *value;
1338 GST_INFO_OBJECT (demux, "Received user-agent from upstream element...");
1340 s = gst_query_get_structure (cquery);
1341 value = gst_structure_get_value (s, "user-agent");
1342 demux->user_agent = g_strdup (g_value_get_string (value));
1344 GST_INFO_OBJECT (demux,"User agent received from query : %s", demux->user_agent);
1346 GST_WARNING_OBJECT (demux, "Failed to get user-agent");
1349 gst_query_unref (cquery);
1353 gst_hlsdemux2_create_playlist_download (GstHLSDemux2 *demux, const gchar *playlist_uri)
1355 if (!gst_uri_is_valid (playlist_uri)) {
1356 GST_ERROR_OBJECT (demux, "invalid uri : %s...", playlist_uri == NULL ? "NULL" : playlist_uri);
1360 if (demux->cancelled || demux->flushing) {
1361 GST_WARNING_OBJECT (demux,"returning from download playlist due to cancel or flushing..");
1365 /* create playlist downloader pipeline */
1366 demux->pldownloader->pipe = gst_pipeline_new ("playlist-downloader");
1367 if (!demux->pldownloader->pipe) {
1368 GST_ERROR_OBJECT (demux, "failed to create pipeline");
1372 demux->pldownloader->bus = gst_pipeline_get_bus (GST_PIPELINE (demux->pldownloader->pipe));
1373 gst_bus_set_sync_handler(demux->pldownloader->bus, gst_hlsdemux2_playlist_download_bus_sync_cb, demux);
1375 gst_object_unref (demux->pldownloader->bus);
1377 GST_INFO_OBJECT (demux, "Creating source element for the URI : %s", playlist_uri);
1379 /* creating source element */
1380 demux->pldownloader->urisrc = gst_element_make_from_uri (GST_URI_SRC, playlist_uri, "playlisturisrc");
1381 if (!demux->pldownloader->urisrc) {
1382 GST_ERROR_OBJECT (demux, "failed to create urisrc");
1385 g_object_set (G_OBJECT (demux->pldownloader->urisrc), "timeout", HLSDEMUX2_HTTP_TIMEOUT, NULL);
1386 g_object_set (G_OBJECT (demux->pldownloader->urisrc), "user-agent", demux->user_agent, NULL);
1387 g_object_set (G_OBJECT (demux->pldownloader->urisrc), "ahs-streaming", TRUE, NULL);
1389 demux->playlistDomain = gst_hlsdemux2_uri_get_domain(demux, playlist_uri);
1390 if(!g_strcmp0(demux->playlistDomain, demux->lastDomain) && demux->lastCookie) {
1391 g_strfreev (demux->playlistCookie);
1392 demux->playlistCookie = g_strdupv (demux->lastCookie);
1395 if (demux->playlistCookie) {
1396 GST_DEBUG_OBJECT (demux, "Setting cookies before PLAYLIST download, before PLAYING: %s", *(demux->playlistCookie));
1397 /* setting cookies */
1398 g_object_set (demux->pldownloader->urisrc, "cookies", demux->playlistCookie, NULL);
1401 /* create sink element */
1402 demux->pldownloader->sink = gst_element_factory_make ("appsink", "playlistsink");
1403 if (!demux->pldownloader->sink) {
1404 GST_ERROR_OBJECT (demux, "failed to create playlist sink element");
1407 g_object_set (G_OBJECT (demux->pldownloader->sink), "sync", FALSE, "emit-signals", TRUE, NULL);
1408 g_signal_connect (demux->pldownloader->sink, "new-buffer", G_CALLBACK (gst_hlsdemux2_on_playlist_buffer), demux);
1410 gst_bin_add_many (GST_BIN (demux->pldownloader->pipe), demux->pldownloader->urisrc, demux->pldownloader->sink, NULL);
1412 if (!gst_element_link_many (demux->pldownloader->urisrc, demux->pldownloader->sink, NULL)) {
1413 GST_ERROR_OBJECT (demux, "failed to link src & demux elements...");
1421 gst_hlsdemux2_destroy_playlist_download (GstHLSDemux2 * demux)
1423 if (demux->pldownloader->pipe) {
1424 GST_DEBUG_OBJECT (demux, "Shutting down playlist download pipeline");
1425 gst_element_set_state (demux->pldownloader->pipe, GST_STATE_NULL);
1426 gst_element_get_state (demux->pldownloader->pipe, NULL, NULL, GST_CLOCK_TIME_NONE);
1427 gst_object_unref (demux->pldownloader->pipe);
1428 demux->pldownloader->pipe = NULL;
1433 gst_hlsdemux2_download_playlist (GstHLSDemux2 *demux, const gchar * uri)
1435 GstStateChangeReturn ret;
1437 if (demux->playlist_uri) {
1438 g_free (demux->playlist_uri);
1440 demux->playlist_uri = g_strdup (uri);
1442 demux->pldownloader->download_start_ts = gst_util_get_timestamp();
1444 if (!gst_hlsdemux2_create_playlist_download (demux, uri)) {
1445 GST_ERROR_OBJECT (demux, "failed to create playlist download pipeline");
1449 ret = gst_element_set_state (demux->pldownloader->pipe, GST_STATE_PLAYING);
1450 if (ret == GST_STATE_CHANGE_FAILURE) {
1451 GST_ERROR_OBJECT (demux, "set_state failed...");
1455 /* schedule the next update of playlist */
1457 gst_hlsdemux2_schedule (demux);
1460 * - the download succeed (EOS)
1461 * - the download failed (Error message on the fetcher bus)
1462 * - the download was canceled
1464 GST_LOG_OBJECT (demux, "Waiting to fetch the URI");
1465 g_cond_wait (demux->pldownloader->cond, demux->pldownloader->lock);
1466 GST_LOG_OBJECT (demux, "Recived signal to shutdown...");
1468 if (demux->playlistCookie)
1469 g_strfreev (demux->playlistCookie);
1471 g_object_get (demux->pldownloader->urisrc, "cookies", &demux->playlistCookie, NULL);
1473 GST_DEBUG_OBJECT (demux, "Got cookies after PLAYLIST download : %s", demux->playlistCookie ? *(demux->playlistCookie) : NULL);
1475 if(demux->playlistCookie){
1476 g_strfreev(demux->lastCookie);
1477 g_free(demux->lastDomain);
1478 demux->lastCookie = g_strdupv(demux->playlistCookie);
1479 demux->lastDomain = g_strdup(demux->playlistDomain);
1482 gst_hlsdemux2_destroy_playlist_download (demux);
1484 if (demux->cancelled || demux->flushing)
1492 gst_hlsdemux2_update_playlist (GstHLSDemux2 * demux, gboolean update, gboolean *is_error)
1494 gchar *playlist = NULL;
1495 gboolean updated = FALSE;
1496 const gchar *playlist_uri = gst_m3u8_client_get_current_uri (demux->client);
1500 if (!gst_m3u8_client_is_playlist_download_needed (demux->client)) {
1501 GST_INFO_OBJECT (demux, "Playlist download is not needed...");
1505 g_mutex_lock (demux->pldownloader->lock);
1509 if (!gst_hlsdemux2_download_playlist (demux, playlist_uri)) {
1510 GST_ERROR_OBJECT (demux, "failed to create playlist download");
1514 if ((demux->pldownloader->playlist == NULL) || (GST_BUFFER_DATA(demux->pldownloader->playlist) == NULL)) {
1515 // TODO: don't exact reason, why eos is coming from soup without data...
1516 GST_ERROR_OBJECT (demux, "Received playlist eos, without playlist data -> TRY AGAIN");
1520 /* reset the count */
1521 demux->soup_request_fail_cnt = HLSDEMUX2_SOUP_FAILED_CNT;
1523 playlist = gst_hlsdemux2_src_buf_to_utf8_playlist (demux->pldownloader->playlist);
1525 GST_ERROR_OBJECT(demux, "failed to create playlist");
1528 demux->pldownloader->playlist = NULL;
1530 updated = gst_m3u8_client_update (demux->client, playlist);
1531 g_mutex_unlock (demux->pldownloader->lock);
1536 if (demux->flushing)
1538 g_mutex_unlock (demux->pldownloader->lock);
1543 gst_hlsdemux2_create_key_download (GstHLSDemux2 *demux, const gchar *key_uri)
1545 if (!gst_uri_is_valid (key_uri)) {
1546 GST_ERROR_OBJECT (demux, "invalid uri : %s...", key_uri == NULL ? "NULL" : key_uri);
1550 if (demux->cancelled || demux->flushing) {
1551 GST_WARNING_OBJECT (demux,"returning from download key due to cancel or flushing..");
1555 demux->kdownloader->pipe = gst_pipeline_new ("keydownloader");
1556 if (!demux->kdownloader->pipe) {
1557 GST_ERROR_OBJECT (demux, "failed to create pipeline");
1561 demux->kdownloader->bus = gst_pipeline_get_bus (GST_PIPELINE (demux->kdownloader->pipe));
1562 gst_bus_add_watch (demux->kdownloader->bus, (GstBusFunc)gst_hlsdemux2_key_download_bus_cb, demux);
1563 gst_object_unref (demux->kdownloader->bus);
1565 GST_INFO_OBJECT (demux, "Creating source element for the URI : %s", key_uri);
1567 demux->kdownloader->urisrc = gst_element_make_from_uri (GST_URI_SRC, key_uri, "keyurisrc");
1568 if (!demux->kdownloader->urisrc) {
1569 GST_ERROR_OBJECT (demux, "failed to create urisrc");
1573 g_object_set (G_OBJECT (demux->kdownloader->urisrc), "timeout", HLSDEMUX2_HTTP_TIMEOUT, NULL);
1574 g_object_set (G_OBJECT (demux->kdownloader->urisrc), "user-agent", demux->user_agent, NULL);
1575 g_object_set (G_OBJECT (demux->kdownloader->urisrc), "ahs-streaming", TRUE, NULL);
1577 demux->keyDomain = gst_hlsdemux2_uri_get_domain(demux, key_uri);
1578 if(!g_strcmp0(demux->keyDomain, demux->lastDomain) && demux->lastCookie) {
1579 g_strfreev(demux->keyCookie);
1580 demux->keyCookie = g_strdupv(demux->lastCookie);
1583 if (demux->keyCookie) {
1584 GST_DEBUG_OBJECT (demux, "Setting cookies before KEY download goto PLAYING : %s", *(demux->keyCookie));
1585 g_object_set (demux->kdownloader->urisrc, "cookies", demux->keyCookie, NULL);
1588 demux->kdownloader->sink = gst_element_factory_make ("appsink", "keyfilesink");
1589 if (!demux->kdownloader->sink) {
1590 GST_ERROR_OBJECT (demux, "failed to create playlist sink element");
1593 g_object_set (G_OBJECT (demux->kdownloader->sink), "sync", FALSE, "emit-signals", TRUE, NULL);
1594 g_signal_connect (demux->kdownloader->sink, "new-buffer", G_CALLBACK (gst_hlsdemux2_on_key_buffer), demux);
1596 gst_bin_add_many (GST_BIN (demux->kdownloader->pipe), demux->kdownloader->urisrc, demux->kdownloader->sink, NULL);
1598 if (!gst_element_link_many (demux->kdownloader->urisrc, demux->kdownloader->sink, NULL)) {
1599 GST_ERROR_OBJECT (demux, "failed to link src & demux elements...");
1607 gst_hlsdemux2_destroy_key_download (GstHLSDemux2 * demux)
1609 if (demux->kdownloader->pipe) {
1610 GST_DEBUG_OBJECT (demux, "Shutting down key download pipeline");
1611 gst_element_set_state (demux->kdownloader->pipe, GST_STATE_NULL);
1612 gst_element_get_state (demux->kdownloader->pipe, NULL, NULL, GST_CLOCK_TIME_NONE);
1613 gst_object_unref (demux->kdownloader->pipe);
1614 demux->kdownloader->pipe = NULL;
1619 gst_hlsdemux2_download_key (GstHLSDemux2 *demux, const gchar * uri)
1621 GstStateChangeReturn ret;
1623 if (demux->key_uri) {
1624 g_free (demux->key_uri);
1626 demux->key_uri = g_strdup (uri);
1628 g_mutex_lock (demux->kdownloader->lock);
1630 if (!gst_hlsdemux2_create_key_download (demux, uri)) {
1631 GST_ERROR_OBJECT (demux, "failed to create key download pipeline");
1635 ret = gst_element_set_state (demux->kdownloader->pipe, GST_STATE_PLAYING);
1636 if (ret == GST_STATE_CHANGE_FAILURE) {
1637 GST_ERROR_OBJECT (demux, "set_state failed...");
1642 * - the download succeed (EOS)
1643 * - the download failed (Error message on the fetcher bus)
1644 * - the download was canceled
1646 GST_DEBUG_OBJECT (demux, "Waiting to fetch the key URI");
1647 g_cond_wait (demux->kdownloader->cond, demux->kdownloader->lock);
1648 GST_DEBUG_OBJECT (demux, "Recived signal to shutdown key downloader...");
1649 g_mutex_unlock (demux->kdownloader->lock);
1651 if (demux->keyCookie) {
1652 g_object_get (demux->kdownloader->urisrc, "cookies", &demux->keyCookie, NULL);
1655 GST_DEBUG_OBJECT (demux, "Got cookies after KEY download : %s", demux->keyCookie ? *(demux->keyCookie) : NULL);
1657 if(demux->keyCookie){
1658 g_strfreev(demux->lastCookie);
1659 g_free(demux->lastDomain);
1660 demux->lastCookie = g_strdupv(demux->keyCookie);
1661 demux->lastDomain = g_strdup(demux->keyDomain);
1664 gst_hlsdemux2_destroy_key_download (demux);
1666 if (demux->cancelled || demux->flushing)
1673 gst_hlsdemux2_have_type_cb (GstElement * typefind, guint probability,
1674 GstCaps * caps, GstHLSDemux2 * demux)
1676 GstStructure *structure = NULL;
1678 structure = gst_caps_get_structure (caps, 0);
1680 GST_DEBUG_OBJECT (demux, "typefind found caps %" GST_PTR_FORMAT, caps);
1682 if (gst_structure_has_name (structure, "video/mpegts")) {
1683 /* found ts fragment */
1684 demux->fdownloader->demuxer = gst_element_factory_make ("mpegtsdemux", "tsdemux");
1685 if (!demux->fdownloader->demuxer) {
1686 GST_ERROR_OBJECT (demux, "failed to create mpegtsdemux element");
1687 GST_ELEMENT_ERROR (demux, CORE, MISSING_PLUGIN, ("failed to create mpegtsdemuxer element"), (NULL));
1690 g_signal_connect (demux->fdownloader->demuxer, "pad-added", G_CALLBACK (gst_hlsdemux2_new_pad_added), demux);
1692 gst_bin_add (GST_BIN (demux->fdownloader->pipe), demux->fdownloader->demuxer);
1694 /* set queue element to PLAYING state */
1695 gst_element_set_state (demux->fdownloader->demuxer, GST_STATE_PLAYING);
1697 if (!gst_element_link (demux->fdownloader->typefind, demux->fdownloader->demuxer)) {
1698 GST_ERROR_OBJECT (demux, "failed to link src and demux elements...");
1699 GST_ELEMENT_ERROR (demux, CORE, NEGOTIATION, ("failed to link typefind & demuxer"), (NULL));
1702 } else if (gst_structure_has_name (structure, "application/x-id3")) {
1703 /* found ts fragment */
1704 demux->fdownloader->demuxer = gst_element_factory_make ("id3demux", "id3demuxer");
1705 if (!demux->fdownloader->demuxer) {
1706 GST_ERROR_OBJECT (demux, "failed to create mpegtsdemux element");
1707 GST_ELEMENT_ERROR (demux, CORE, MISSING_PLUGIN, ("failed to create id3demuxer element"), (NULL));
1710 g_signal_connect (demux->fdownloader->demuxer, "pad-added", G_CALLBACK (gst_hlsdemux2_new_pad_added), demux);
1712 gst_bin_add (GST_BIN (demux->fdownloader->pipe), demux->fdownloader->demuxer);
1714 /* set queue element to PLAYING state */
1715 gst_element_set_state (demux->fdownloader->demuxer, GST_STATE_PLAYING);
1717 if (!gst_element_link_many (demux->fdownloader->typefind, demux->fdownloader->demuxer, NULL)) {
1718 GST_ERROR_OBJECT (demux, "failed to link src and demux elements...");
1719 GST_ELEMENT_ERROR (demux, CORE, NEGOTIATION, ("failed to link typefind & demuxer"), (NULL));
1723 /* as the fragment does not contain in container format, force the timestamps based on fragment duration */
1724 demux->fdownloader->force_timestamps = TRUE;
1729 gst_hlsdemux2_download_monitor_thread (GstHLSDemux2 *demux)
1731 GTimeVal post_msg_update = {0, };
1733 g_mutex_lock (demux->post_msg_lock);
1734 GST_INFO_OBJECT (demux, "waiting for streaming to start to post message...");
1735 g_cond_wait (demux->post_msg_start, demux->post_msg_lock);
1736 GST_INFO_OBJECT (demux, "Start posting messages...");
1737 g_mutex_unlock (demux->post_msg_lock);
1740 gboolean do_post = FALSE;
1741 guint64 percent = 0;
1743 guint64 total_percent = 0;
1744 gboolean bret = FALSE;
1746 if (demux->cancelled) {
1747 GST_WARNING_OBJECT (demux, "returning msg posting thread...");
1751 /* schedule the next update using the target duration field of the
1753 post_msg_update.tv_sec = 0;
1754 post_msg_update.tv_usec = 0;
1756 g_get_current_time (&post_msg_update);
1757 g_time_val_add (&post_msg_update, 200000); // posts buffering msg after every 0.5 sec
1759 /* verify fast switch from here */
1760 g_mutex_lock (demux->fdownloader->lock);
1761 if (demux->fdownloader->ndownloaded
1762 && !demux->fdownloader->applied_fast_switch && demux->fdownloader->download_start_ts) {
1763 gst_hlsdemux2_check_fast_switch (demux);
1765 g_mutex_unlock (demux->fdownloader->lock);
1767 /* calculate avg percent of streams' percentages */
1768 for (idx = 0; idx < HLSDEMUX2_STREAM_NUM; idx++) {
1769 GstHLSDemux2Stream *stream = demux->streams[idx];
1771 guint64 stream_percent = 0;
1773 stream_percent = ((stream->cached_duration * 100) / (demux->total_cache_duration / DEFAULT_NUM_FRAGMENTS_CACHE));
1774 GST_DEBUG_OBJECT (stream->pad, "stream percent = %"G_GUINT64_FORMAT, stream_percent);
1775 total_percent += stream_percent;
1778 percent = total_percent / demux->active_stream_cnt;
1780 if (demux->is_buffering) {
1783 demux->is_buffering = FALSE;
1786 /* if buffering drops below 10% lets start posting msgs */
1787 demux->is_buffering = TRUE;
1793 GstMessage *message;
1795 if (percent > 100) {
1796 //GST_LOG_OBJECT (demux, " exceeded percent = %d", (gint) percent);
1800 if (demux->end_of_playlist) {
1801 GST_INFO_OBJECT (demux, "end of the playlist reached... always post 100%");
1805 if (percent != demux->percent) {
1806 g_mutex_lock (demux->buffering_lock);
1807 demux->percent = percent;
1808 g_mutex_unlock (demux->buffering_lock);
1810 GST_LOG_OBJECT (demux, "buffering %d percent", (gint) percent);
1812 /* posting buffering to internal bus, which will take average & post to main bus */
1813 message = gst_message_new_buffering (GST_OBJECT_CAST (demux), (gint) demux->percent);
1814 if (!gst_element_post_message (GST_ELEMENT_CAST (demux), message)) {
1815 GST_WARNING_OBJECT (demux, "failed to post buffering msg...");
1820 g_mutex_lock (demux->post_msg_lock);
1821 /* block until the next scheduled update or the exit signal */
1822 bret = g_cond_timed_wait (demux->post_msg_exit, demux->post_msg_lock, &post_msg_update);
1823 g_mutex_unlock (demux->post_msg_lock);
1826 GST_WARNING_OBJECT (demux, "signalled to exit posting msgs...");
1835 gst_hlsdemux2_fragurisrc_event_handler (GstPad * pad, GstEvent *event, gpointer data)
1837 GstHLSDemux2 *demux = (GstHLSDemux2 *)data;
1839 if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
1840 GTimeVal time = {0, };
1842 GST_INFO_OBJECT (demux, "received EOS from fragment downloader's httpsrc");
1844 if (demux->fdownloader->error_rcvd) {
1845 GST_WARNING_OBJECT (demux, "received EOS event after ERROR.. discard this");
1846 demux->fdownloader->src_downloaded_size = 0;
1847 demux->fdownloader->download_stop_ts = demux->fdownloader->download_start_ts = 0;
1851 /* download rate calculation : note down stop time*/
1852 g_get_current_time (&time);
1853 demux->fdownloader->download_stop_ts = gst_util_get_timestamp();
1855 GST_INFO_OBJECT (demux, "download stop_ts = %"G_GUINT64_FORMAT, demux->fdownloader->download_stop_ts);
1856 GST_INFO_OBJECT (demux, "time taken to download current fragment = %"G_GUINT64_FORMAT, demux->fdownloader->download_stop_ts - demux->fdownloader->download_start_ts);
1857 GST_INFO_OBJECT (demux, "fragment downloaded size = %"G_GUINT64_FORMAT" and content_size = %"G_GUINT64_FORMAT,
1858 demux->fdownloader->src_downloaded_size, demux->fdownloader->content_size);
1860 if (demux->fdownloader->src_downloaded_size && (demux->fdownloader->src_downloaded_size == demux->fdownloader->content_size)) {
1861 guint64 download_rate = 0;
1865 /* calculate current fragment download rate */
1866 download_rate = (demux->fdownloader->src_downloaded_size * 8 * GST_SECOND) /
1867 (demux->fdownloader->download_stop_ts - demux->fdownloader->download_start_ts);
1869 if (demux->fdownloader->avg_frag_drates->len == HLSDEMUX2_MAX_N_PAST_FRAG_DOWNLOADRATES) {
1870 /* removing starting element */
1871 g_array_remove_index (demux->fdownloader->avg_frag_drates, 0);
1872 GST_DEBUG_OBJECT (demux, "removing index from download rates");
1874 g_array_append_val (demux->fdownloader->avg_frag_drates, download_rate);
1876 for (i = 0 ; i < demux->fdownloader->avg_frag_drates->len; i++) {
1877 dsum += g_array_index (demux->fdownloader->avg_frag_drates, guint64, i);
1880 demux->fdownloader->download_rate = dsum / demux->fdownloader->avg_frag_drates->len;
1882 GST_INFO_OBJECT (demux, " >>>> DOWNLOAD RATE = %"G_GUINT64_FORMAT, demux->fdownloader->download_rate);
1884 GST_WARNING_OBJECT (demux, "something wrong better not to calculate download rate with this and discard EOS...");
1885 demux->fdownloader->src_downloaded_size = 0;
1886 demux->fdownloader->download_stop_ts = demux->fdownloader->download_start_ts = 0;
1890 demux->fdownloader->src_downloaded_size = 0;
1891 demux->fdownloader->download_stop_ts = demux->fdownloader->download_start_ts = 0;
1898 gst_hlsdemux2_check_fast_switch (GstHLSDemux2 *demux)
1900 GstClockTime elapsed_time = 0;
1902 guint64 download_rate = 0;
1904 elapsed_time = gst_util_get_timestamp();
1906 if (gst_m3u8_client_has_variant_playlist (demux->client) &&
1907 ((elapsed_time - demux->fdownloader->download_start_ts) >
1908 (HLSDEMUX2_FAST_CHECK_WARNING_TIME_FACTOR * demux->target_duration))) {
1909 guint64 drate_sum = 0;
1910 GList *previous_variant, *current_variant;
1911 gint old_bandwidth, new_bandwidth;
1913 GST_INFO_OBJECT (demux, "Doing fast switch using array len %d...", demux->fdownloader->avg_chunk_drates->len);
1915 for (i = 0 ; i < demux->fdownloader->avg_chunk_drates->len; i++) {
1916 drate_sum += g_array_index (demux->fdownloader->avg_chunk_drates, guint64, i);
1919 /* 0.9 factor is for compensating for connection time*/
1920 download_rate = (drate_sum * 0.9) / demux->fdownloader->avg_chunk_drates->len;
1922 GST_INFO_OBJECT (demux, "average chunk download rate = %"G_GUINT64_FORMAT, download_rate);
1924 if ((elapsed_time - demux->fdownloader->download_start_ts) >
1925 (HLSDEMUX2_FAST_CHECK_CRITICAL_TIME_FACTOR * demux->target_duration)) {
1926 GST_WARNING_OBJECT (demux, "Reached FAST_SWITCH critical point...do fast_switch");
1930 previous_variant = demux->client->main->current_variant;
1931 current_variant = gst_m3u8_client_get_playlist_for_bitrate (demux->client, download_rate);
1933 old_bandwidth = GST_M3U8 (previous_variant->data)->bandwidth;
1934 new_bandwidth = GST_M3U8 (current_variant->data)->bandwidth;
1936 GST_INFO_OBJECT (demux, "variant's bandwidth got using average chunk download rate is %d", new_bandwidth);
1938 /* Don't do anything else if the playlist is the same */
1939 if (new_bandwidth == old_bandwidth) {
1940 GST_WARNING_OBJECT (demux, "Either BW is recovering or NO LOWER variant available than current, DON'T DO FAST_SWITCH...");
1944 GST_WARNING_OBJECT (demux, "Going to do fast_switch due to BW problem...");
1952 demux->fdownloader->download_rate = download_rate;
1954 /* flush previous fragment downloads history */
1955 for (i = 3; i ; --i) {
1956 g_array_remove_index (demux->fdownloader->avg_frag_drates, i - 1);
1959 GST_INFO_OBJECT (demux, "in fast download rate : len %d...", demux->fdownloader->avg_frag_drates->len);
1960 g_array_append_val (demux->fdownloader->avg_frag_drates, demux->fdownloader->download_rate);
1962 GST_INFO_OBJECT (demux, " >>>> DOWNLOAD RATE in fast switch = %"G_GUINT64_FORMAT, demux->fdownloader->download_rate);
1964 demux->fdownloader->applied_fast_switch = TRUE;
1966 /* close current fragment */
1967 g_cond_signal (demux->fdownloader->cond);
1974 gst_hlsdemux2_fragurisrc_buffer_handler (GstPad * pad, GstBuffer *buffer, gpointer data)
1976 GstHLSDemux2 *demux = (GstHLSDemux2 *)data;
1977 GstClockTime elapsed_ts = 0;
1978 guint64 chunk_drate = 0;
1980 /* if block_switch already enabled no need to cross check. IMP check*/
1981 if (demux->fdownloader->applied_fast_switch) {
1982 GST_WARNING_OBJECT (demux, "already applied fast_switch.. drop current buffer");
1986 demux->fdownloader->src_downloaded_size += GST_BUFFER_SIZE(buffer);
1988 if (demux->fdownloader->first_buffer) {
1989 /* get the content size for doing last buffer decryption & for vaidating complete download happend or not */
1990 GST_INFO_OBJECT (demux, "just received first buffer...");
1991 g_object_get (demux->fdownloader->urisrc, "content-size", &demux->fdownloader->content_size, NULL);
1992 GST_INFO_OBJECT (demux, "content size = %"G_GUINT64_FORMAT, demux->fdownloader->content_size);
1993 demux->fdownloader->first_buffer = FALSE;
1994 demux->fdownloader->chunk_start_ts = gst_util_get_timestamp();
1995 demux->fdownloader->chunk_downloaded_size = 0;
1999 demux->fdownloader->chunk_downloaded_size += GST_BUFFER_SIZE(buffer);
2000 elapsed_ts = gst_util_get_timestamp();
2002 if ((elapsed_ts - demux->fdownloader->chunk_start_ts) > HLSDEMUX2_CHUNK_TIME_DURATION) {
2003 GST_DEBUG_OBJECT (demux, "chunk downloaded time = %"GST_TIME_FORMAT,
2004 GST_TIME_ARGS(elapsed_ts - demux->fdownloader->chunk_start_ts));
2006 chunk_drate = (demux->fdownloader->chunk_downloaded_size * 8 * GST_SECOND) / (elapsed_ts - demux->fdownloader->chunk_start_ts);
2007 demux->fdownloader->chunk_start_ts = elapsed_ts;
2008 demux->fdownloader->chunk_downloaded_size = 0;
2010 GST_DEBUG_OBJECT(demux, "CHUNK DOWNLOAD RATE = %"G_GUINT64_FORMAT, chunk_drate);
2012 if (demux->fdownloader->avg_chunk_drates->len == HLSDEMUX2_NUM_CHUNK_DOWNLOADS_FAST_SWITCH) {
2013 /* removing starting element */
2014 g_array_remove_index (demux->fdownloader->avg_chunk_drates, 0);
2016 g_array_append_val (demux->fdownloader->avg_chunk_drates, chunk_drate);
2019 GST_LOG_OBJECT (demux, "fragment downloaded size at urisrc = %"G_GUINT64_FORMAT, demux->fdownloader->src_downloaded_size);
2025 gst_hlsdemux2_queue_buffer_handler (GstPad *pad, GstBuffer *buffer, gpointer data)
2027 GstHLSDemux2 *demux = (GstHLSDemux2 *)data;
2028 unsigned char *encry_data = NULL;
2029 unsigned char *outdata = NULL;
2030 unsigned char *remained_data = NULL;
2031 unsigned char* total_data = NULL;
2033 demux->fdownloader->queue_downloaded_size += GST_BUFFER_SIZE(buffer);
2035 GST_DEBUG_OBJECT (demux, "total downloaded size = %"G_GUINT64_FORMAT, demux->fdownloader->queue_downloaded_size);
2037 if (demux->fdownloader->is_encrypted) {
2038 guint encry_data_size = 0;
2039 unsigned char *indata = GST_BUFFER_DATA (buffer);
2040 guint insize = GST_BUFFER_SIZE (buffer);
2043 if (demux->fdownloader->remaining_data && demux->fdownloader->remaining_size) {
2044 GST_LOG_OBJECT (demux, "remain size = %d..", demux->fdownloader->remaining_size);
2046 encry_data = (unsigned char *) malloc (insize + demux->fdownloader->remaining_size);
2048 GST_ERROR_OBJECT (demux, "failed to allocate memory...\n");
2049 GST_ELEMENT_ERROR (demux, RESOURCE, NO_SPACE_LEFT, ("can't allocate memory"), (NULL));
2053 /* copy remaining data in previous iteration */
2054 memcpy (encry_data, demux->fdownloader->remaining_data, demux->fdownloader->remaining_size);
2055 /* copy input encrypted data of current iteration */
2056 memcpy (encry_data + demux->fdownloader->remaining_size, indata, insize);
2058 encry_data_size = insize + demux->fdownloader->remaining_size;
2060 free (demux->fdownloader->remaining_data);
2061 demux->fdownloader->remaining_data = NULL;
2062 demux->fdownloader->remaining_size = 0;
2064 encry_data_size = insize;
2065 encry_data = indata;
2068 demux->fdownloader->remaining_size = encry_data_size % GST_HLS_DEMUX_AES_BLOCK_SIZE;
2070 if (demux->fdownloader->remaining_size) {
2071 GST_LOG_OBJECT (demux, "Remining in current iteration = %d\n", demux->fdownloader->remaining_size);
2072 demux->fdownloader->remaining_data = (gchar *) malloc (demux->fdownloader->remaining_size);
2073 if ( demux->fdownloader->remaining_data == NULL) {
2074 GST_ERROR_OBJECT (demux, "failed to allocate memory...\n");
2075 GST_ELEMENT_ERROR (demux, RESOURCE, NO_SPACE_LEFT, ("can't allocate memory"), (NULL));
2079 /* copy remained portion to buffer */
2080 memcpy (demux->fdownloader->remaining_data,
2081 encry_data + encry_data_size - demux->fdownloader->remaining_size,
2082 demux->fdownloader->remaining_size);
2085 out_len = encry_data_size - demux->fdownloader->remaining_size + GST_HLS_DEMUX_AES_BLOCK_SIZE;
2086 outdata = (unsigned char *) malloc (out_len);
2088 GST_ERROR_OBJECT (demux, "failed to allocate memory...\n");
2089 GST_ELEMENT_ERROR (demux, RESOURCE, NO_SPACE_LEFT, ("can't allocate memory"), (NULL));
2093 if (!gst_m3u8_client_decrypt_update (demux->client, outdata, &out_len,
2094 encry_data, encry_data_size - demux->fdownloader->remaining_size)) {
2095 GST_ERROR_OBJECT (demux, "failed to decrypt...\n");
2096 GST_ELEMENT_ERROR (demux, STREAM, FAILED, ("failed to decrypt"), (NULL));
2100 if (encry_data != indata) {
2101 g_free (encry_data);
2105 g_free (GST_BUFFER_MALLOCDATA(buffer));
2107 /* decrypt the final buffer */
2108 if (demux->fdownloader->queue_downloaded_size == demux->fdownloader->content_size) {
2109 gint remained_size = 0;
2112 GST_LOG_OBJECT (demux, "remained data = %p & remained size = %d", demux->fdownloader->remaining_data, demux->fdownloader->remaining_size);
2114 remained_data = (unsigned char *) malloc (GST_HLS_DEMUX_AES_BLOCK_SIZE);
2115 if (!remained_data) {
2116 GST_ERROR_OBJECT (demux, "failed to allocate memory...\n");
2117 GST_ELEMENT_ERROR (demux, RESOURCE, NO_SPACE_LEFT, ("can't allocate memory"), (NULL));
2120 gst_m3u8_client_decrypt_final (demux->client, remained_data, &remained_size);
2121 GST_LOG_OBJECT (demux,"remained size = %d\n", remained_size);
2123 if (remained_size) {
2124 total_len = out_len + remained_size;
2126 total_data = (unsigned char *) malloc (total_len);
2128 GST_ERROR_OBJECT (demux, "failed to allocate memory...\n");
2129 GST_ELEMENT_ERROR (demux, RESOURCE, NO_SPACE_LEFT, ("can't allocate memory"), (NULL));
2133 memcpy (total_data, outdata, out_len);
2134 memcpy (total_data+out_len, remained_data, remained_size);
2136 GST_BUFFER_MALLOCDATA(buffer) = GST_BUFFER_DATA(buffer) = total_data;
2137 GST_BUFFER_SIZE(buffer) = total_len;
2138 g_free (remained_data);
2141 GST_BUFFER_MALLOCDATA(buffer) = GST_BUFFER_DATA(buffer) = outdata;
2142 GST_BUFFER_SIZE(buffer) = out_len;
2143 g_free (remained_data);
2146 if (!gst_m3u8_client_decrypt_deinit (demux->client)) {
2147 GST_WARNING_OBJECT (demux, "decryption cleanup failed...");
2150 GST_BUFFER_MALLOCDATA(buffer) = GST_BUFFER_DATA(buffer) = outdata;
2151 GST_BUFFER_SIZE(buffer) = out_len;
2165 free (remained_data);
2171 gst_hlsdemux2_create_fragment_download (GstHLSDemux2 * demux, const gchar * uri)
2174 GstPad *srcpad = NULL;
2176 if (!gst_uri_is_valid (uri)) {
2177 GST_ERROR_OBJECT (demux, "invalid uri : %s...", uri == NULL ? "NULL" : uri);
2181 /* re-initialize fragment variables */
2182 demux->fdownloader->first_buffer = TRUE;
2183 demux->fdownloader->cur_stream_cnt = 0;
2184 demux->fdownloader->error_rcvd = FALSE;
2186 demux->fdownloader->pipe = gst_pipeline_new ("frag-fdownloader");
2187 if (!demux->fdownloader->pipe) {
2188 GST_ERROR_OBJECT (demux, "failed to create pipeline");
2192 bus = gst_pipeline_get_bus (GST_PIPELINE (demux->fdownloader->pipe));
2193 gst_bus_add_watch (bus, (GstBusFunc)gst_hlsdemux2_fragment_download_bus_cb, demux);
2194 gst_object_unref (bus);
2196 GST_INFO_OBJECT (demux, "Creating source element for the URI : %s", uri);
2198 demux->fdownloader->urisrc = gst_element_make_from_uri (GST_URI_SRC, uri, "fragurisrc");
2199 if (!demux->fdownloader->urisrc) {
2200 GST_ERROR_OBJECT (demux, "failed to create urisrc");
2204 g_object_set (G_OBJECT (demux->fdownloader->urisrc), "timeout", HLSDEMUX2_HTTP_TIMEOUT, NULL);
2205 g_object_set (G_OBJECT (demux->fdownloader->urisrc), "user-agent", demux->user_agent, NULL);
2206 g_object_set (G_OBJECT (demux->fdownloader->urisrc), "ahs-streaming", TRUE, NULL);
2207 g_object_set (G_OBJECT (demux->fdownloader->urisrc), "blocksize", DEFAULT_BLOCKSIZE, NULL);
2209 demux->fragDomain = gst_hlsdemux2_uri_get_domain(demux, uri);
2210 if(!g_strcmp0 (demux->fragDomain, demux->lastDomain) && demux->lastCookie) {
2211 g_strfreev(demux->fragCookie);
2212 demux->fragCookie = g_strdupv (demux->lastCookie);
2215 if (demux->fragCookie) {
2216 GST_DEBUG_OBJECT (demux, "Setting cookies before FRAG download goto PLAYING: %s", *(demux->fragCookie));
2217 g_object_set (demux->fdownloader->urisrc, "cookies", demux->fragCookie, NULL);
2220 srcpad = gst_element_get_static_pad (demux->fdownloader->urisrc, "src");
2222 GST_ERROR_OBJECT (demux, "failed to get source pad from urisrc...");
2226 gst_pad_add_event_probe (srcpad, G_CALLBACK (gst_hlsdemux2_fragurisrc_event_handler), demux);
2227 gst_pad_add_buffer_probe (srcpad, G_CALLBACK (gst_hlsdemux2_fragurisrc_buffer_handler), demux);
2229 gst_object_unref (srcpad);
2231 demux->fdownloader->queue = gst_element_factory_make ("queue2", "frag_queue");
2232 if (!demux->fdownloader->queue) {
2233 GST_ERROR_OBJECT (demux, "failed to create queue2");
2237 g_object_set (G_OBJECT (demux->fdownloader->queue),
2238 "max-size-buffers", 0,
2239 "max-size-bytes", 0,
2240 "max-size-time", 0 * GST_SECOND, NULL);
2242 srcpad = gst_element_get_static_pad (demux->fdownloader->queue, "src");
2244 GST_ERROR_OBJECT (demux, "failed to get source pad from fragment queue...");
2248 gst_pad_add_buffer_probe (srcpad, G_CALLBACK (gst_hlsdemux2_queue_buffer_handler), demux);
2250 demux->fdownloader->typefind = gst_element_factory_make ("typefind", "typefinder");
2251 if (!demux->fdownloader->typefind) {
2252 GST_ERROR_OBJECT (demux, "failed to create typefind element");
2253 gst_object_unref (srcpad);
2257 gst_bin_add_many (GST_BIN (demux->fdownloader->pipe),
2258 demux->fdownloader->urisrc, demux->fdownloader->queue, demux->fdownloader->typefind, NULL);
2260 if (!gst_element_link_many (demux->fdownloader->urisrc,
2261 demux->fdownloader->queue, demux->fdownloader->typefind, NULL)) {
2262 GST_ERROR_OBJECT (demux, "failed to link src, queue & typefind elements...");
2263 gst_object_unref (srcpad);
2267 /* typefind callback to determine file type */
2268 g_signal_connect (demux->fdownloader->typefind, "have-type", G_CALLBACK (gst_hlsdemux2_have_type_cb), demux);
2270 gst_object_unref (srcpad);
2276 gst_hlsdemux2_destroy_fragment_download (GstHLSDemux2 * demux)
2278 if (demux->fdownloader->pipe) {
2279 GST_DEBUG_OBJECT (demux, "completely closing fragment downloader pipeline");
2280 gst_element_set_state (demux->fdownloader->pipe, GST_STATE_NULL);
2281 gst_element_get_state (demux->fdownloader->pipe, NULL, NULL, GST_CLOCK_TIME_NONE);
2282 GST_DEBUG_OBJECT (demux, "completely closed fragment downloader pipeline");
2283 gst_object_unref (demux->fdownloader->pipe);
2284 demux->has_image_buffer = FALSE;
2285 demux->fdownloader->pipe = NULL;
2286 demux->fdownloader->cur_stream_cnt = 0;
2287 g_list_free (demux->fdownloader->sinkbins); // all sink elements will be unreffed when pipeline is unreffed
2288 demux->fdownloader->sinkbins = 0;
2293 gst_hlsdemux2_download_fragment (GstHLSDemux2 *demux, const gchar * uri)
2295 GstStateChangeReturn ret;
2297 g_mutex_lock (demux->fdownloader->lock);
2299 if (demux->cancelled || demux->flushing) {
2300 GST_WARNING_OBJECT (demux,"returning from download fragment due to cancel or flushing..");
2301 g_mutex_unlock (demux->fdownloader->lock);
2305 if (demux->frag_uri) {
2306 g_free (demux->frag_uri);
2308 demux->frag_uri = g_strdup (uri);
2310 demux->fdownloader->get_next_frag = FALSE;
2312 if (!gst_hlsdemux2_create_fragment_download (demux, uri)) {
2313 GST_ERROR_OBJECT (demux, "failed to create download pipeline");
2314 g_mutex_unlock (demux->fdownloader->lock);
2318 /* download rate calculation : note down start time*/
2319 demux->fdownloader->download_start_ts = gst_util_get_timestamp();
2320 GST_INFO_OBJECT (demux, "download start_ts = %"G_GUINT64_FORMAT, demux->fdownloader->download_start_ts);
2322 ret = gst_element_set_state (demux->fdownloader->pipe, GST_STATE_PLAYING);
2323 if (ret == GST_STATE_CHANGE_FAILURE) {
2324 GST_ERROR_OBJECT (demux, "set_state failed...");
2325 g_mutex_unlock (demux->fdownloader->lock);
2328 gst_element_get_state (demux->fdownloader->pipe, NULL, NULL, -1);
2331 * - the download succeed (EOS)
2332 * - the download failed (Error message on the fetcher bus)
2333 * - the download was canceled
2335 GST_DEBUG_OBJECT (demux, "Waiting to fetch the URI");
2336 g_cond_wait (demux->fdownloader->cond, demux->fdownloader->lock);
2337 GST_INFO_OBJECT (demux, "Recived signal to shutdown...");
2339 if (demux->fragCookie)
2340 g_strfreev (demux->fragCookie);
2342 g_object_get (demux->fdownloader->urisrc, "cookies", &demux->fragCookie, NULL);
2344 GST_DEBUG_OBJECT (demux, "Got cookies after FRAG download : %s", demux->fragCookie ? *(demux->fragCookie) : NULL);
2346 if (demux->fdownloader->applied_fast_switch) {
2347 if (demux->fdownloader->src_downloaded_size == demux->fdownloader->content_size) {
2348 /* to handle case, when both fast_switch & bus_callback signalled at same moment */
2349 GST_WARNING_OBJECT (demux, "ignoring fast_switch as fragment download is completed...");
2350 demux->fdownloader->applied_fast_switch = FALSE;
2352 GST_WARNING_OBJECT (demux, "decrement the media sequence by one, due to fast_switch");
2353 gst_m3u8_client_decrement_sequence (demux->client);
2357 if (demux->cancelled || demux->flushing ||
2358 demux->fdownloader->get_next_frag || demux->fdownloader->applied_fast_switch) {
2359 GstBuffer *buf = NULL;
2362 /* clear stream queues if we already downloaded some data */
2363 for (idx = 0; idx < HLSDEMUX2_STREAM_NUM; idx++) {
2364 GstHLSDemux2Stream *stream = demux->streams[idx];
2366 while (!g_queue_is_empty (stream->downloader_queue)) {
2367 buf = g_queue_pop_head (stream->downloader_queue);
2368 gst_buffer_unref (buf);
2370 GST_LOG_OBJECT (stream->pad, "cleared stream download queue...");
2371 g_queue_clear (stream->downloader_queue);
2376 if(demux->fragCookie){
2377 g_strfreev(demux->lastCookie);
2378 g_free(demux->lastDomain);
2379 demux->lastCookie = g_strdupv(demux->fragCookie);
2380 demux->lastDomain = g_strdup(demux->fragDomain);
2383 if(demux->active_stream_cnt == 1 && !demux->private_stream) {
2384 gchar *image_header = NULL;
2385 GValue codec_type = G_VALUE_INIT;
2386 GValue image_data = G_VALUE_INIT;
2387 GstMessage * tag_message = NULL;
2388 struct stat stat_results;
2390 GstBuffer *image_buffer = NULL;
2391 GstTagList * tag_list = gst_tag_list_new();
2394 GST_INFO_OBJECT (demux, "Going to show fixed image");
2395 dummy_fp = open (PREDEFINED_IMAGE_FRAME_LOCATION, O_RDONLY);
2397 GST_WARNING_OBJECT (demux, "failed to open fixed image file : %s...", PREDEFINED_IMAGE_FRAME_LOCATION);
2398 goto skip_posting_image;
2401 GST_LOG_OBJECT (demux, "opened fixed image file %s successfully...", PREDEFINED_IMAGE_FRAME_LOCATION);
2403 if (fstat (dummy_fp, &stat_results) < 0) {
2404 GST_WARNING_OBJECT (demux, "failed to get stats of a file...");
2406 goto skip_posting_image;
2409 GST_LOG_OBJECT (demux, "size of the dummy file = %d", stat_results.st_size);
2411 image_buffer = gst_buffer_new_and_alloc (stat_results.st_size);
2412 if (!image_buffer) {
2413 GST_ERROR_OBJECT (demux, "failed to allocate memory...");
2414 GST_ELEMENT_ERROR (demux, RESOURCE, NO_SPACE_LEFT, ("can't allocate memory"), (NULL));
2419 iread = read (dummy_fp, GST_BUFFER_DATA (image_buffer), stat_results.st_size);
2421 GST_LOG_OBJECT (demux, "read size = %d successfully", iread);
2425 /* check whether it is same as previous image */
2426 if (demux->prev_image_buffer &&
2427 (GST_BUFFER_SIZE(demux->prev_image_buffer) == GST_BUFFER_SIZE(image_buffer))) {
2428 if (!memcmp (GST_BUFFER_DATA(demux->prev_image_buffer), GST_BUFFER_DATA(image_buffer), GST_BUFFER_SIZE(image_buffer))) {
2429 GST_INFO_OBJECT (demux, "current & previous embedded images are same..no need to post image again");
2430 gst_buffer_unref (image_buffer);
2431 goto skip_posting_image;
2435 if (demux->prev_image_buffer) {
2436 gst_buffer_unref (demux->prev_image_buffer);
2438 demux->prev_image_buffer = gst_buffer_copy(image_buffer);
2440 g_value_init (&codec_type, G_TYPE_STRING);
2441 g_value_init (&image_data, GST_TYPE_BUFFER);
2442 gst_value_set_buffer(&image_data, image_buffer);
2444 image_header = g_strndup((gchar *) image_buffer->data, 8);
2446 if((image_header[0] == 0xFF) && (image_header[1] == 0xD8)) {
2447 GST_INFO_OBJECT(demux, "Found JPEG image header");
2448 g_value_set_static_string (&codec_type, "image/jpeg");
2449 gst_tag_list_add_value(tag_list, GST_TAG_MERGE_APPEND, GST_TAG_CODEC, &codec_type);
2450 } else if (!g_strcmp0(image_header, "\211PNG\015\012\032\012")) {
2451 GST_INFO_OBJECT(demux, "Found PNG image header");
2452 g_value_set_static_string (&codec_type, "image/png");
2453 gst_tag_list_add_value(tag_list, GST_TAG_MERGE_APPEND, GST_TAG_CODEC, &codec_type);
2455 g_value_set_static_string (&codec_type, "image/unknown");
2456 GST_INFO_OBJECT(demux, "Unknown image header");
2457 gst_tag_list_add_value(tag_list, GST_TAG_MERGE_APPEND, GST_TAG_CODEC, &codec_type);
2460 gst_tag_list_add_value (tag_list, GST_TAG_MERGE_APPEND, GST_TAG_IMAGE, &image_data);
2462 GST_INFO_OBJECT(demux, "Set value : %s", g_value_get_string (&codec_type));
2463 g_value_unset(&codec_type);
2465 tag_message = gst_message_new_tag (GST_OBJECT_CAST (demux), tag_list);
2466 if(!gst_element_post_message (GST_ELEMENT_CAST (demux), tag_message)) {
2467 GST_ERROR_OBJECT (demux, "failed to post fixed image tag");
2470 GST_INFO_OBJECT (demux, "successfully posted image tag...");
2471 gst_buffer_unref (image_buffer);
2472 g_free (image_header);
2477 gst_hlsdemux2_destroy_fragment_download (demux);
2479 if (demux->fdownloader->remaining_data) {
2480 free (demux->fdownloader->remaining_data);
2481 demux->fdownloader->remaining_data = NULL;
2484 demux->fdownloader->remaining_size = 0;
2485 demux->fdownloader->src_downloaded_size = 0;
2486 demux->fdownloader->queue_downloaded_size = 0;
2487 demux->fdownloader->download_stop_ts = demux->fdownloader->download_start_ts = 0;
2488 demux->fdownloader->applied_fast_switch = FALSE;
2489 demux->fdownloader->content_size = 0;
2491 if (demux->cancelled || demux->flushing) {
2492 GST_WARNING_OBJECT (demux, "returning false due to flushing/cancelled");
2494 } else if (demux->fdownloader->get_next_frag || demux->fdownloader->applied_fast_switch) {
2495 GST_INFO_OBJECT (demux, "Requesting next fragment due to error or same sequence number from different variant");
2499 demux->fdownloader->ndownloaded++;
2501 GST_INFO_OBJECT (demux, "number of fragments downloaded = %d", demux->fdownloader->ndownloaded);
2503 /* reset the count */
2504 demux->soup_request_fail_cnt = HLSDEMUX2_SOUP_FAILED_CNT;
2507 if (demux->private_stream) {
2508 g_free (demux->private_stream);
2509 demux->private_stream = NULL;
2511 g_mutex_unlock (demux->fdownloader->lock);
2516 if (demux->private_stream) {
2517 g_free (demux->private_stream);
2518 demux->private_stream = NULL;
2520 g_mutex_unlock (demux->fdownloader->lock);
2526 gst_hlsdemux2_change_playlist (GstHLSDemux2 * demux, guint max_bitrate, gboolean *is_switched)
2528 GList *previous_variant, *current_variant;
2529 gint old_bandwidth, new_bandwidth;
2531 previous_variant = demux->client->main->current_variant;
2532 current_variant = gst_m3u8_client_get_playlist_for_bitrate (demux->client, max_bitrate);
2534 old_bandwidth = GST_M3U8 (previous_variant->data)->bandwidth;
2535 new_bandwidth = GST_M3U8 (current_variant->data)->bandwidth;
2537 /* Don't do anything else if the playlist is the same */
2538 if (new_bandwidth == old_bandwidth) {
2540 *is_switched = FALSE;
2544 GST_M3U8_CLIENT_LOCK (demux->client);
2545 demux->client->main->current_variant = current_variant;
2546 GST_M3U8_CLIENT_UNLOCK (demux->client);
2548 gst_m3u8_client_set_current (demux->client, current_variant->data);
2550 GST_INFO_OBJECT (demux, "Client was on %dbps, max allowed is %dbps, switching"
2551 " to bitrate %dbps", old_bandwidth, max_bitrate, new_bandwidth);
2553 gst_hlsdemux2_apply_disc(demux);
2556 *is_switched = TRUE;
2562 gst_hlsdemux2_get_next_fragment (GstHLSDemux2 * demux, gboolean *is_error)
2564 const gchar *next_fragment_uri = NULL;;
2565 gchar *next_fragment_key_uri = NULL;
2567 GstClockTime duration;
2568 GstClockTime timestamp;
2569 gboolean discont = FALSE;
2570 gboolean bret = TRUE;
2571 GstClockTime lookup_time = 0;
2573 GstHLSDemux2Stream *stream = NULL;
2575 if (!demux->is_live) {
2576 for (i = 0; i< HLSDEMUX2_STREAM_NUM; i++) {
2577 stream = demux->streams[i];
2579 lookup_time = stream->lts + stream->frame_duration + (0.5 * GST_SECOND);
2580 GST_INFO_OBJECT (stream->pad, "Lookup time = %"GST_TIME_FORMAT, GST_TIME_ARGS(lookup_time));
2581 stream->frame_duration = 0;
2582 if (stream->type == HLSDEMUX2_STREAM_AUDIO)
2588 if (!gst_m3u8_client_get_next_fragment (demux->client, lookup_time,
2589 &discont, &next_fragment_uri, &duration, ×tamp, &next_fragment_key_uri, &iv)) {
2591 GST_INFO_OBJECT (demux, "This playlist doesn't contain more fragments");
2593 if (demux->is_live && (demux->client->update_failed_count < DEFAULT_FAILED_COUNT)) {
2594 GST_WARNING_OBJECT (demux, "Could not get next fragment, try again after updating playlist...");
2602 demux->cfrag_dur = duration;
2603 demux->fdownloader->cur_running_dur += duration;
2605 GST_LOG_OBJECT (demux, "current running duration = %"GST_TIME_FORMAT, GST_TIME_ARGS(demux->fdownloader->cur_running_dur));
2607 GST_DEBUG_OBJECT (demux, "Fetching next fragment = %s & key uri = %s", next_fragment_uri, next_fragment_key_uri);
2609 /* when hls requests next fragment due to some error like NOT_FOUND, then also we need to set apply disc */
2610 if (discont || demux->fdownloader->get_next_frag)
2611 gst_hlsdemux2_apply_disc (demux);
2613 if (next_fragment_key_uri) {
2614 /* download key data & initialize decryption with key data & IV */
2615 GST_INFO_OBJECT (demux, "Fetching next fragment key %s", next_fragment_key_uri);
2617 if (demux->kdownloader->prev_key_uri) {
2618 if (strcmp (demux->kdownloader->prev_key_uri, next_fragment_key_uri)) {
2619 /* if previous & current key uris are different, download new one */
2620 if (demux->kdownloader->key) {
2621 gst_buffer_unref (demux->kdownloader->key);
2622 demux->kdownloader->key = NULL;
2625 if (demux->kdownloader->prev_key_uri)
2626 g_free (demux->kdownloader->prev_key_uri);
2628 demux->kdownloader->prev_key_uri = g_strdup(next_fragment_key_uri);
2630 /* download the key data as there is a change */
2631 if (!gst_hlsdemux2_download_key (demux, next_fragment_key_uri)) {
2632 GST_ERROR_OBJECT (demux, "failed to download key...");
2636 GST_INFO_OBJECT (demux, "already having the key...no need to download again");
2639 if (demux->kdownloader->key) {
2640 gst_buffer_unref (demux->kdownloader->key);
2641 demux->kdownloader->key = NULL;
2644 demux->kdownloader->prev_key_uri = g_strdup(next_fragment_key_uri);
2646 if (!gst_hlsdemux2_download_key (demux, next_fragment_key_uri)) {
2647 GST_ERROR_OBJECT (demux, "failed to download key...");
2650 /* reset the count */
2651 demux->soup_request_fail_cnt = HLSDEMUX2_SOUP_FAILED_CNT;
2654 if (!demux->kdownloader->key || !GST_BUFFER_DATA (demux->kdownloader->key)) {
2655 GST_ERROR_OBJECT (demux, "eos received without key content...");
2659 if (!gst_m3u8_client_decrypt_init (demux->client, GST_BUFFER_DATA (demux->kdownloader->key), iv)) {
2660 GST_ERROR_OBJECT (demux, "failed to initialize AES decryption...");
2664 demux->fdownloader->is_encrypted = TRUE;
2667 if (!gst_hlsdemux2_download_fragment (demux, next_fragment_uri)) {
2668 GST_ERROR_OBJECT (demux, "failed to download fragment...");
2673 if (next_fragment_uri)
2674 g_free ((gpointer)next_fragment_uri);
2675 if (next_fragment_key_uri)
2676 g_free ((gpointer)next_fragment_key_uri);
2678 g_free ((gpointer)iv);
2683 if (!demux->flushing)
2689 GST_INFO_OBJECT (demux, "Reached end of playlist, sending EOS");
2691 gst_hlsdemux2_push_eos (demux);
2693 demux->end_of_playlist = TRUE;
2700 gst_hlsdemux2_switch_playlist (GstHLSDemux2 * demux, gboolean *is_switched)
2702 GST_M3U8_CLIENT_LOCK (demux->client);
2703 if (!demux->client->main->lists) {
2704 /* not a variant to switch */
2705 GST_M3U8_CLIENT_UNLOCK (demux->client);
2706 GST_INFO_OBJECT (demux, "not a variant to switch...");
2709 GST_M3U8_CLIENT_UNLOCK (demux->client);
2711 if (demux->force_lower_bitrate && (demux->fdownloader->ndownloaded % FORCE_LOW_BITRATE_AFTER_CNT == 0)) {
2712 demux->fdownloader->download_rate = 0; // Using some temp lowest value
2713 GST_WARNING_OBJECT (demux, "resetting to lowest one bitrate = %"G_GUINT64_FORMAT, demux->fdownloader->download_rate);
2716 return gst_hlsdemux2_change_playlist (demux, demux->fdownloader->download_rate, is_switched);
2720 gst_hlsdemux2_apply_disc (GstHLSDemux2 * demux)
2723 GstHLSDemux2Stream *stream = NULL;
2725 for (i = 0; i< HLSDEMUX2_STREAM_NUM; i++) {
2726 stream = demux->streams[i];
2729 stream->apply_disc = TRUE;
2730 GST_INFO_OBJECT (stream->pad, "apply discontinuity...");
2736 gst_hlsdemux2_fragment_download_loop (GstHLSDemux2 * demux)
2738 gboolean is_error = FALSE;
2739 gboolean bret = FALSE;
2740 GTimeVal tmp_update = {0, };
2742 guint64 current_time = 0;
2743 guint64 nextupdate_time = 0;
2745 /* if variant playlist, get current subplaylist first */
2746 if (gst_m3u8_client_has_variant_playlist(demux->client)) {
2747 gboolean is_error = FALSE;
2749 if (!gst_hlsdemux2_update_playlist (demux, FALSE, &is_error)) {
2750 GST_ERROR_OBJECT (demux, "failed to update playlist. uri : %s", gst_m3u8_client_get_current_uri(demux->client));
2751 GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND, ("Could not update the playlist"), (NULL));
2754 } else if (demux->is_live) {
2755 /* single variant live.. so schedule for starting */
2757 gst_hlsdemux2_schedule (demux);
2760 if (demux->fdownloader->find_mediaseq) {
2762 GstClockTime current_pos, target_pos;
2763 gint current_sequence;
2764 GstM3U8MediaFile *file;
2766 GstHLSDemux2Stream *stream = NULL;
2768 GST_M3U8_CLIENT_LOCK (demux->client);
2769 file = GST_M3U8_MEDIA_FILE (demux->client->current->files->data);
2770 current_sequence = file->sequence;
2772 target_pos = demux->fdownloader->seeked_pos;
2773 for (walk = demux->client->current->files; walk; walk = walk->next) {
2776 current_sequence = file->sequence;
2777 if (current_pos <= target_pos &&
2778 target_pos < current_pos + file->duration) {
2781 current_pos += file->duration;
2783 GST_M3U8_CLIENT_UNLOCK (demux->client);
2786 GST_WARNING_OBJECT (demux, "Could not find seeked fragment");
2788 GST_M3U8_CLIENT_LOCK (demux->client);
2789 GST_INFO_OBJECT (demux, "seeking to sequence %d", current_sequence);
2790 demux->client->sequence = current_sequence;
2791 GST_M3U8_CLIENT_UNLOCK (demux->client);
2792 demux->ns_start = demux->fdownloader->cur_running_dur = current_pos; // NON-accurate seek
2794 for (i = 0; i< HLSDEMUX2_STREAM_NUM; i++) {
2795 stream = demux->streams[i];
2796 #ifdef LATEST_AV_SYNC
2798 stream->lts = stream->total_stream_time = current_pos;
2799 GST_INFO_OBJECT (stream->pad, "Changed stream->lts to %"GST_TIME_FORMAT, GST_TIME_ARGS(stream->lts));
2802 if (stream && stream->type == HLSDEMUX2_STREAM_AUDIO) {
2803 stream->lts = current_pos;
2808 demux->fdownloader->find_mediaseq = FALSE;
2811 demux->target_duration = gst_m3u8_client_get_target_duration(demux->client);
2812 demux->total_cache_duration = DEFAULT_NUM_FRAGMENTS_CACHE * demux->target_duration;
2813 demux->is_live = gst_m3u8_client_is_live(demux->client);
2815 GST_INFO_OBJECT (demux, "Total cache duration = %"GST_TIME_FORMAT, GST_TIME_ARGS(demux->total_cache_duration));
2819 if (demux->cancelled)
2822 /* get the next fragement */
2823 bret = gst_hlsdemux2_get_next_fragment (demux, &is_error);
2827 GST_ERROR_OBJECT (demux, "error in getting next fragment");
2828 GST_ELEMENT_ERROR (demux, RESOURCE, FAILED, ("could not download fragment"), (NULL));
2831 if (!demux->end_of_playlist) {
2832 if (demux->flushing) {
2833 GST_WARNING_OBJECT (demux, "SEEK is in progress.. pause the task");
2835 } else if (demux->client->update_failed_count < DEFAULT_FAILED_COUNT) {
2836 GST_WARNING_OBJECT (demux, "Could not update fragment & playlist update failed count = %d",
2837 demux->client->update_failed_count);
2839 GST_ERROR_OBJECT (demux, "Could not get next fragment..");
2840 GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND, ("Could not get next fragment..."), (NULL));
2844 GST_INFO_OBJECT (demux, "end of fragment download, doing pause");
2849 /* reset the update failed count */
2850 demux->client->update_failed_count = 0;
2853 if (demux->cancelled)
2856 if (demux->is_live) {
2857 /* get the current time */
2858 current.tv_sec = current.tv_usec = 0;
2859 g_get_current_time (¤t);
2861 current_time = (current.tv_sec * 1000000)+ current.tv_usec;
2862 nextupdate_time = (demux->next_update.tv_sec * 1000000)+ demux->next_update.tv_usec;
2865 if (demux->is_live && ((current_time > nextupdate_time) || !bret)) {
2866 gboolean is_switched = FALSE;
2868 /* try to switch to another bitrate if needed */
2869 // TODO: take care of return value
2870 gst_hlsdemux2_switch_playlist (demux, &is_switched);
2872 g_mutex_lock (demux->pl_update_lock);
2874 /* block until the next scheduled update or the exit signal */
2875 bret = g_cond_timed_wait (demux->pl_update_cond, demux->pl_update_lock, &demux->next_update);
2877 g_mutex_unlock (demux->pl_update_lock);
2879 GST_DEBUG_OBJECT (demux, "playlist update wait is completed. reason : %s", bret ? "Received signal" : "time-out");
2881 tmp_update.tv_sec = 0;
2882 tmp_update.tv_usec = 0;
2884 g_get_current_time (&tmp_update);
2887 GST_DEBUG_OBJECT (demux, "Sombody signalled manifest waiting... going to exit and diff = %ld",
2888 ((demux->next_update.tv_sec * 1000000)+ demux->next_update.tv_usec) - ((tmp_update.tv_sec * 1000000)+ tmp_update.tv_usec));
2890 } else if (demux->cancelled) {
2891 GST_WARNING_OBJECT (demux, "closing is in progress..exit now");
2895 if (!gst_hlsdemux2_update_playlist (demux, FALSE, &is_error)) {
2897 GST_ERROR_OBJECT (demux, "failed to update playlist...");
2898 GST_ELEMENT_ERROR (demux, RESOURCE, FAILED, ("failed to update playlist"), (NULL));
2901 if (demux->flushing) {
2902 GST_WARNING_OBJECT (demux, "SEEK is in progress.. pause the task");
2904 } else if (demux->client->update_failed_count < DEFAULT_FAILED_COUNT) {
2905 GST_WARNING_OBJECT (demux, "Could not update playlist & playlist update failed count = %d",
2906 demux->client->update_failed_count);
2909 GST_ERROR_OBJECT (demux, "Could not update playlist..");
2910 GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND, ("Could not update playlist..."), (NULL));
2917 gboolean is_switched = FALSE;
2919 /* try to switch to another bitrate if needed */
2920 // TODO: take care of return value
2922 /* when in recovery mode, do not obey download rates */
2923 if (demux->pldownloader->recovery_mode == HLSDEMUX2_NO_RECOVERY)
2924 gst_hlsdemux2_switch_playlist (demux, &is_switched);
2927 if (!gst_hlsdemux2_update_playlist (demux, FALSE, &is_error)) {
2929 GST_ERROR_OBJECT (demux, "failed to update playlist...");
2930 GST_ELEMENT_ERROR (demux, RESOURCE, FAILED, ("failed to update playlist"), (NULL));
2933 if (demux->flushing) {
2934 GST_WARNING_OBJECT (demux, "SEEK is in progress.. pause the task");
2936 } else if (demux->client->update_failed_count < DEFAULT_FAILED_COUNT) {
2937 GST_WARNING_OBJECT (demux, "Could not update playlist & playlist update failed count = %d",
2938 demux->client->update_failed_count);
2941 GST_ERROR_OBJECT (demux, "Could not update playlist..");
2942 GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND, ("Could not update playlist..."), (NULL));
2947 } else if (demux->is_live) {
2948 GstClockTime current_time = gst_util_get_timestamp();
2950 if ((current_time - demux->pldownloader->download_start_ts) <
2951 (PLAYLIST_REFRESH_TIMEOUT - (HLSDEMUX2_FAST_CHECK_CRITICAL_TIME_FACTOR * demux->target_duration) - HLSDEMUX2_OVERHEAD)) {
2952 GST_INFO_OBJECT (demux, "Eligible to download next fragment w/o playlist update : "
2953 "elapsed time since last playlist request = %"GST_TIME_FORMAT" and max_time_limit = %"GST_TIME_FORMAT,
2954 GST_TIME_ARGS(current_time - demux->pldownloader->download_start_ts),
2955 GST_TIME_ARGS(PLAYLIST_REFRESH_TIMEOUT - (HLSDEMUX2_FAST_CHECK_CRITICAL_TIME_FACTOR * demux->target_duration) - HLSDEMUX2_OVERHEAD));
2958 GST_INFO_OBJECT (demux, "NOT Eligible to download next fragment w/o playlist update : "
2959 "elapsed time since previous request = %"GST_TIME_FORMAT" and max_time_limit = %"GST_TIME_FORMAT,
2960 GST_TIME_ARGS(current_time - demux->pldownloader->download_start_ts),
2961 GST_TIME_ARGS(PLAYLIST_REFRESH_TIMEOUT - (HLSDEMUX2_FAST_CHECK_CRITICAL_TIME_FACTOR * demux->target_duration) - HLSDEMUX2_OVERHEAD));
2963 /* we are not eligible to download, next fragment.. So wait till next playlist update */
2964 g_mutex_lock (demux->pl_update_lock);
2965 /* block until the next scheduled update or the exit signal */
2966 bret = g_cond_timed_wait (demux->pl_update_cond, demux->pl_update_lock, &demux->next_update);
2967 g_mutex_unlock (demux->pl_update_lock);
2969 GST_DEBUG_OBJECT (demux, "playlist update wait is completed. reason : %s", bret ? "Received signal" : "time-out");
2971 tmp_update.tv_sec = 0;
2972 tmp_update.tv_usec = 0;
2974 g_get_current_time (&tmp_update);
2977 GST_DEBUG_OBJECT (demux, "Sombody signalled manifest waiting... going to exit and diff = %ld",
2978 ((demux->next_update.tv_sec * 1000000)+ demux->next_update.tv_usec) - ((tmp_update.tv_sec * 1000000)+ tmp_update.tv_usec));
2980 } else if (demux->cancelled) {
2981 GST_WARNING_OBJECT (demux, "closing is in progress..exit now");
2985 if (!gst_hlsdemux2_update_playlist (demux, FALSE, &is_error)) {
2987 GST_ERROR_OBJECT (demux, "failed to update playlist...");
2988 GST_ELEMENT_ERROR (demux, RESOURCE, FAILED, ("failed to update playlist"), (NULL));
2991 if (demux->flushing) {
2992 GST_WARNING_OBJECT (demux, "SEEK is in progress.. pause the task");
2994 } else if (demux->client->update_failed_count < DEFAULT_FAILED_COUNT) {
2995 GST_WARNING_OBJECT (demux, "Could not update playlist & playlist update failed count = %d",
2996 demux->client->update_failed_count);
2999 GST_ERROR_OBJECT (demux, "Could not update playlist..");
3000 GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND, ("Could not update playlist..."), (NULL));
3011 GST_WARNING_OBJECT (demux, "Going to PAUSE download task from self");
3012 gst_task_pause (demux->download_task);
3017 gst_hlsdemux2_calculate_popped_duration (GstHLSDemux2 *demux, GstHLSDemux2Stream *stream,
3020 gpointer data = NULL;
3021 gint i = g_queue_get_length (stream->queue);
3023 /* get the buffer with valid timestamp from tail of the queue */
3025 data = g_queue_peek_nth (stream->queue, (i - 1));
3030 if (GST_IS_BUFFER ((GstBuffer *)data)) {
3031 if (GST_BUFFER_TIMESTAMP_IS_VALID(data)) {
3032 /* found valid timestamp & stop searching */
3033 GST_LOG_OBJECT (stream->pad, "data found buffer with valid ts = %"GST_TIME_FORMAT " len = %d & i = %d",
3034 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(data)), g_queue_get_length (stream->queue), i);
3045 if (GST_BUFFER_TIMESTAMP (outbuf) <= GST_BUFFER_TIMESTAMP ((GstBuffer *)data)) {
3046 stream->cached_duration = GST_BUFFER_TIMESTAMP ((GstBuffer *)data) - GST_BUFFER_TIMESTAMP (outbuf);
3047 GST_DEBUG_OBJECT (stream->pad, "cache duration in popping : %"GST_TIME_FORMAT, GST_TIME_ARGS(stream->cached_duration));
3049 GST_ERROR_OBJECT (stream->pad, "Wrong order.. not calculating");
3056 gst_hlsdemux2_push_loop (GstHLSDemux2Stream *stream)
3058 GstHLSDemux2 *demux = stream->parent;
3059 GstFlowReturn fret = GST_FLOW_OK;
3060 gpointer data = NULL;
3062 // TODO: need to take care of EOS handling....
3064 if (demux->cancelled || demux->flushing)
3067 g_mutex_lock (stream->queue_lock);
3069 if (g_queue_is_empty (stream->queue)) {
3070 GST_LOG_OBJECT (stream->pad,"queue is empty wait till, some buffers are available...");
3071 g_cond_wait (stream->queue_empty, stream->queue_lock);
3072 GST_LOG_OBJECT (stream->pad,"Received queue empty signal...");
3075 if (demux->cancelled || demux->flushing) {
3076 GST_ERROR_OBJECT (stream->pad, "Shutting down push loop");
3077 g_mutex_unlock (stream->queue_lock);
3081 if (g_queue_is_empty (stream->queue)) {
3082 GST_ERROR_OBJECT (stream->pad, "Queue empty undesired....");
3083 g_mutex_unlock (stream->queue_lock);
3087 data = g_queue_pop_head (stream->queue);
3089 GST_ERROR_OBJECT (stream->pad, "Received null data...");
3090 GST_ELEMENT_ERROR (demux, CORE, FAILED, ("Unhandled GstObjectType"), (NULL));
3091 g_mutex_unlock (stream->queue_lock);
3095 /* Calculate duration only when
3096 * 1. popped obj is a buffer and
3097 * 2. buffer has valid ts and
3098 * 3. queue length > 1
3101 if (GST_IS_BUFFER(data) &&
3102 GST_BUFFER_TIMESTAMP_IS_VALID(data) ) {
3104 /* calculate buffering duration */
3105 gst_hlsdemux2_calculate_popped_duration (demux, stream, data);
3107 if (stream->cached_duration < 0) {
3108 GST_WARNING_OBJECT (stream->pad, "Wrong cached duration in push_loop...\n");
3109 stream->cached_duration = 0;
3113 g_mutex_unlock (stream->queue_lock);
3115 if (GST_IS_EVENT(data)) {
3116 GstEvent *event = (GstEvent *)data;
3118 switch (GST_EVENT_TYPE (event)) {
3119 case GST_EVENT_NEWSEGMENT: {
3122 gdouble rate, arate;
3123 gint64 start, stop, pos;
3124 gst_event_parse_new_segment_full(event, &update, &rate, &arate, &format, &start, &stop, &pos);
3125 GST_INFO_OBJECT (stream->pad, "Pushing newsegment to downstream : rate = %0.3f, start = %"GST_TIME_FORMAT
3126 ", stop = %"GST_TIME_FORMAT, rate, GST_TIME_ARGS(start), GST_TIME_ARGS(stop));
3130 GST_INFO_OBJECT (stream->pad, "going to push eos event to downstream");
3134 GST_ERROR_OBJECT (stream->pad, "not handled event...still pushing event");
3137 if (!gst_pad_push_event (stream->pad, event)) {
3138 GST_ERROR_OBJECT (demux, "failed to push newsegment event");
3139 GST_ELEMENT_ERROR (demux, CORE, PAD, ("failed to push '%s' event", GST_EVENT_TYPE_NAME(event)), (NULL));
3143 GST_INFO_OBJECT (stream->pad, "Pushed '%s' event...", GST_EVENT_TYPE_NAME(event));
3146 //gst_element_post_message (GST_ELEMENT_CAST (stream->sink), gst_message_new_eos (GST_OBJECT_CAST(stream->sink)));
3147 GST_INFO_OBJECT (stream->pad, "Pausing the task");
3150 } else if (GST_IS_BUFFER(data)) {
3151 GstCaps *temp_caps = NULL;
3152 g_cond_signal (stream->queue_full);
3154 GST_DEBUG_OBJECT (stream->pad, "Pushing buffer : size = %d, ts = %"GST_TIME_FORMAT", dur = %"GST_TIME_FORMAT,
3155 GST_BUFFER_SIZE(data), GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(data)), GST_TIME_ARGS(GST_BUFFER_DURATION(data)));
3157 temp_caps = gst_buffer_get_caps((GstBuffer *)data);
3158 temp_caps = gst_caps_make_writable (temp_caps);
3159 gst_caps_set_simple (temp_caps,"hls_streaming", G_TYPE_BOOLEAN, TRUE, NULL);
3160 gst_buffer_set_caps((GstBuffer *)data, temp_caps);
3161 gst_caps_unref(temp_caps);
3163 /* push data to downstream*/
3164 fret = gst_pad_push (stream->pad, data);
3165 if (fret != GST_FLOW_OK) {
3166 GST_ERROR_OBJECT (stream->pad, "failed to push data, reason : %s", gst_flow_get_name (fret));
3170 GST_ERROR_OBJECT (stream->pad, "unhandled object type..still pushing");
3171 //GST_ELEMENT_ERROR (demux, CORE, FAILED, ("Unhandled GstObjectType"), (NULL));
3173 gst_object_unref (data);
3176 if (demux->cancelled || demux->flushing) {
3184 GST_WARNING_OBJECT (stream->pad, "Pausing the push task...");
3186 if (fret < GST_FLOW_UNEXPECTED) {
3187 GST_ERROR_OBJECT (stream->pad, "Crtical error in push loop....");
3188 GST_ELEMENT_ERROR (demux, CORE, PAD, ("failed to push. reason - %s", gst_flow_get_name (fret)), (NULL));
3191 gst_pad_pause_task (stream->pad);
3196 // TODO: need to review change_playlist API
3199 gst_hlsdemux2_schedule (GstHLSDemux2 * demux)
3201 gfloat update_factor;
3203 GstClockTime last_frag_duration;
3205 /* As defined in §6.3.4. Reloading the Playlist file:
3206 * "If the client reloads a Playlist file and finds that it has not
3207 * changed then it MUST wait for a period of time before retrying. The
3208 * minimum delay is a multiple of the target duration. This multiple is
3209 * 0.5 for the first attempt, 1.5 for the second, and 3.0 thereafter."
3211 count = demux->client->update_failed_count;
3213 update_factor = update_interval_factor[count];
3215 update_factor = update_interval_factor[3];
3217 /* schedule the next update using the target duration field of the
3219 demux->next_update.tv_sec = 0;
3220 demux->next_update.tv_usec = 0;
3222 last_frag_duration = gst_m3u8_client_get_last_fragment_duration (demux->client);
3224 GST_DEBUG_OBJECT (demux, "last fragment duration = %"GST_TIME_FORMAT" and next update = %"GST_TIME_FORMAT,
3225 GST_TIME_ARGS(last_frag_duration), GST_TIME_ARGS(GST_TIME_AS_USECONDS(last_frag_duration) * 1000));
3227 g_get_current_time (&demux->next_update);
3229 //g_time_val_add (&demux->next_update, last_frag_duration / GST_SECOND * G_USEC_PER_SEC * update_factor);
3230 g_time_val_add (&demux->next_update, GST_TIME_AS_USECONDS(last_frag_duration)* update_factor);
3236 gst_hlsdemux2_new_pad_added (GstElement *element, GstPad *srcpad, gpointer data)
3238 GstHLSDemux2 *demux = (GstHLSDemux2 *)data;
3239 GstPad *sinkpad = NULL;
3240 GstCaps *caps = NULL;
3241 HLSDemux2SinkBin *sinkbin = NULL;
3242 gchar *demuxer_name = NULL;
3243 gchar *src_pad_name = NULL;
3245 GST_INFO_OBJECT (demux, "received the src_pad '%s' from mpeg2ts demuxer...", GST_PAD_NAME(srcpad));
3247 if (strstr (GST_PAD_NAME(srcpad), "private")) {
3248 /* handle private image TAG */
3249 gst_hlsdemux2_handle_private_pad (demux, srcpad);
3253 caps = GST_PAD_CAPS (srcpad);
3254 demuxer_name = GST_ELEMENT_NAME (element);
3256 sinkbin = gst_hlsdemux2_create_stream (demux, demuxer_name, caps);
3261 sinkpad = gst_element_get_pad(GST_ELEMENT(sinkbin->sinkbin), "sink");
3263 GST_ERROR_OBJECT (demux, "failed to get sinkpad from element - %s", GST_PAD_NAME(sinkbin->sinkbin));
3264 GST_ELEMENT_ERROR (demux, CORE, PAD, ("could not get sink pad"), (NULL));
3268 /* link demuxer srcpad & sink element's sink pad */
3269 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
3270 GST_ERROR_OBJECT (demux, "failed to link pad '%s' & sink's sink pad", GST_PAD_NAME(srcpad));
3271 GST_ELEMENT_ERROR (demux, CORE, NEGOTIATION, ("Could not link pads.."), (NULL));
3272 gst_object_unref(sinkpad);
3276 if (sinkbin->parser) {
3277 GST_INFO_OBJECT (demux, "linking parser");
3278 if (!gst_element_link_many (sinkbin->queue, sinkbin->parser, sinkbin->sink, NULL)) {
3279 GST_ERROR_OBJECT (demux, "failed to link sink bin elements");
3280 GST_ELEMENT_ERROR (demux, CORE, NEGOTIATION, ("Could not link pads.."), (NULL));
3281 gst_object_unref(sinkpad);
3285 if (!gst_element_link_many (sinkbin->queue, sinkbin->sink, NULL)) {
3286 GST_ERROR_OBJECT (demux, "failed to link sink bin elements");
3287 GST_ELEMENT_ERROR (demux, CORE, NEGOTIATION, ("Could not link pads.."), (NULL));
3288 gst_object_unref(sinkpad);
3292 demux->fdownloader->cur_stream_cnt++;
3294 src_pad_name = gst_pad_get_name(srcpad);
3295 GST_INFO_OBJECT (demux, "succesfully linked pad (%s) with stream pad and current stream cnt = %d",
3296 src_pad_name, demux->fdownloader->cur_stream_cnt);
3297 g_free(src_pad_name);
3298 src_pad_name = NULL;
3300 gst_element_set_state (GST_ELEMENT(sinkbin->sinkbin), GST_STATE_PLAYING);
3302 gst_object_unref (sinkpad);
3306 gst_hlsdemux2_check_stream_type_exist (GstHLSDemux2 *demux, HLSDEMUX2_STREAM_TYPE stream_type)
3309 GstHLSDemux2Stream *stream = NULL;
3311 for (i = 0; i< HLSDEMUX2_STREAM_NUM; i++) {
3312 stream = demux->streams[i];
3314 if (stream && (stream->type == stream_type)) {
3315 GST_INFO_OBJECT (demux, "stream type '%d' is already present", stream_type);
3320 GST_INFO_OBJECT (demux, "received new stream type [%d]", stream_type);
3325 static HLSDemux2SinkBin *
3326 gst_hlsdemux2_create_stream (GstHLSDemux2 *demux, gchar *demuxer_name, GstCaps *caps)
3328 GstHLSDemux2Stream *stream = NULL;
3329 GstPad *sinkpad = NULL;
3330 GstPad *linkpad = NULL;
3331 HLSDEMUX2_STREAM_TYPE stream_type;
3332 gchar *element_name = NULL;
3333 gboolean stream_exist = FALSE;
3335 HLSDemux2SinkBin *bin = NULL;
3336 GstStructure *structure = NULL;
3338 gchar *stream_name = NULL;
3340 stream = g_new0 (GstHLSDemux2Stream, 1);
3342 structure = gst_caps_get_structure (caps, 0);
3344 mime = gst_structure_get_name (structure);
3346 if (strstr (mime, "video")) {
3347 stream_type = HLSDEMUX2_STREAM_VIDEO;
3348 GST_DEBUG_OBJECT (demux, "Its a Multi-variant, Audio only stream..");
3349 demux->stream_config = HLSDEMUX2_MULTI_VARIANT;
3350 stream_name = g_strdup ("video");
3351 } else if (strstr (mime, "audio")) {
3352 stream_type = HLSDEMUX2_STREAM_AUDIO;
3353 stream_name = g_strdup ("audio");
3354 } else if (strstr (mime, "subpicture")) {
3355 stream_type = HLSDEMUX2_STREAM_TEXT;
3356 stream_name = g_strdup ("subpicture");
3357 } else if (strstr (mime, "private")) {
3358 stream_type = HLSDEMUX2_STREAM_PRIVATE;
3359 stream_name = g_strdup ("private");
3361 GST_ELEMENT_ERROR (demux, CORE, PAD, ("Received unknown named pad"), (NULL));
3365 stream_exist = gst_hlsdemux2_check_stream_type_exist (demux, stream_type);
3367 if (!stream_exist) {
3368 stream = g_new0 (GstHLSDemux2Stream, 1);
3369 gst_hlsdemux2_stream_init (demux, stream, stream_type, stream_name, caps);
3371 if (!stream->is_linked) {
3377 for (i = 0; i< HLSDEMUX2_STREAM_NUM; i++) {
3378 stream = demux->streams[i];
3379 if (stream && (stream->type == stream_type)) {
3380 GST_INFO_OBJECT (demux, "found the stream - '%d'", stream->type);
3389 bin = g_new0 (HLSDemux2SinkBin, 1);
3391 element_name = g_strdup_printf("%s-%s", stream_name, "bin");
3392 bin->sinkbin = GST_BIN(gst_bin_new (element_name));
3393 if (!bin->sinkbin) {
3394 GST_ERROR_OBJECT (demux, "failed to create sink bin - %s", element_name);
3395 GST_ELEMENT_ERROR (demux, CORE, FAILED, ("failed to create bin - %s", element_name), (NULL));
3398 g_free (element_name);
3399 element_name = NULL;
3401 /* create queue element */
3402 element_name = g_strdup_printf("%s-%s", stream_name, "queue");
3403 bin->queue = gst_element_factory_make ("queue", element_name);
3405 GST_ERROR_OBJECT (demux, "failed to create queue element - %s", element_name);
3406 GST_ELEMENT_ERROR (demux, CORE, FAILED, ("failed to create element - %s", element_name), (NULL));
3409 g_free (element_name);
3410 element_name = NULL;
3412 if ((stream->type == HLSDEMUX2_STREAM_AUDIO) &&
3413 g_strstr_len(demuxer_name, strlen(demuxer_name), "id3")) {
3414 /* create parser element */
3416 GST_INFO_OBJECT (stream->pad, "demuxer is id3demuxer, so create audio parser...");
3418 element_name = g_strdup_printf("%s-%s", stream_name, "parse");
3419 bin->parser = gst_element_factory_make ("aacparse", element_name);
3421 GST_ERROR_OBJECT (demux, "failed to create parser element - %s", element_name);
3422 GST_ELEMENT_ERROR (demux, CORE, FAILED, ("failed to create element - %s", element_name), (NULL));
3425 g_free (element_name);
3426 element_name = NULL;
3427 gst_bin_add (GST_BIN (bin->sinkbin), bin->parser);
3430 /* create sink element */
3431 element_name = g_strdup_printf("%s-%s", stream_name, "sink");
3432 bin->sink = gst_element_factory_make ("appsink", element_name);
3434 GST_ERROR_OBJECT (demux, "failed to create sink element - %s", element_name);
3435 GST_ELEMENT_ERROR (demux, CORE, FAILED, ("failed to create element - %s", element_name), (NULL));
3439 g_object_set (G_OBJECT (bin->sink), "sync", FALSE, "emit-signals", TRUE, NULL);
3440 g_signal_connect (bin->sink, "new-buffer", G_CALLBACK (gst_hlsdemux2_downloader_new_buffer), stream);
3441 g_signal_connect (bin->sink, "eos", G_CALLBACK (gst_hlsdemux2_downloader_eos), stream);
3443 gst_bin_add_many (GST_BIN (bin->sinkbin), bin->queue, bin->sink, NULL);
3445 gst_bin_add (GST_BIN (demux->fdownloader->pipe), GST_ELEMENT(bin->sinkbin));
3447 /* set queue element to PLAYING state */
3448 gst_element_set_state (GST_ELEMENT(bin->sinkbin), GST_STATE_READY);
3450 sinkpad = gst_element_get_pad(bin->sink, "sink");
3452 GST_ERROR_OBJECT (demux, "failed to get sinkpad from element - %s", element_name);
3453 GST_ELEMENT_ERROR (demux, CORE, PAD, ("Count not get sink pad"), (NULL));
3456 g_free (element_name);
3457 element_name = NULL;
3459 /* adding probe to get new segment events */
3460 sink_probe = gst_pad_add_event_probe (sinkpad,
3461 G_CALLBACK (gst_hlsdemux2_sink_event_handler), stream);
3463 if (!stream_exist) {
3464 /* add stream to stream_type list */
3465 demux->streams[stream_type] = stream;
3466 demux->active_stream_cnt++;
3467 GST_INFO_OBJECT (demux, "number of active streams = %d", demux->active_stream_cnt);
3470 linkpad = gst_element_get_pad(bin->queue, "sink");
3472 element_name = gst_element_get_name (bin->queue);
3473 GST_ERROR_OBJECT (demux, "failed to get sinkpad from element - %s", element_name);
3474 GST_ELEMENT_ERROR (demux, CORE, PAD, ("could not get sink pad"), (NULL));
3478 gst_pad_set_active(linkpad,TRUE);
3480 gst_element_add_pad (GST_ELEMENT(bin->sinkbin), gst_ghost_pad_new ("sink", linkpad));
3482 GST_INFO_OBJECT (stream->pad, "successfully created stream...");
3484 demux->fdownloader->sinkbins = g_list_append (demux->fdownloader->sinkbins, bin);
3486 g_cond_signal (demux->post_msg_start);
3488 g_free (stream_name);
3495 g_free (element_name);
3498 g_free (stream_name);
3504 gst_hlsdemux2_private_image_to_vid(gpointer user_data,GstBuffer *image_buffer)
3506 GstHLSDemux2PvtStream *pvt_stream = (GstHLSDemux2PvtStream *) user_data;
3507 GstHLSDemux2 *demux = (GstHLSDemux2 *) pvt_stream->parent;
3508 GstPad *pad, *srcpad;
3509 GstElement *appsrc, *appsink, *dec, *videorate, *capsfilter, *enc;
3510 GstCaps *scale_caps, *image_caps;
3512 GstFlowReturn fret = GST_FLOW_OK;
3514 gchar *image_header = g_strndup((gchar *) image_buffer->data, 8);
3515 if(!((image_header[0] == 0xFF) && (image_header[1] == 0xD8))) {
3516 GST_WARNING_OBJECT(demux, "Not a valid JPEG image header : %d %d",image_header[0],image_header[1]);
3520 GST_DEBUG_OBJECT(demux, "IMAGE DATA [%d,%d]",pvt_stream->image_buffer->data[0],pvt_stream->image_buffer->data[1]);
3522 GST_INFO_OBJECT (demux, "Creating jpeg->h264 conversion pipeline");
3524 pvt_stream->convert_pipe = gst_pipeline_new ("jpegdec-pipe");
3525 if (!pvt_stream->convert_pipe) {
3526 GST_ERROR_OBJECT (demux, "failed to create pipeline");
3530 bus = gst_pipeline_get_bus (GST_PIPELINE (pvt_stream->convert_pipe));
3531 gst_bus_add_watch (bus, (GstBusFunc)gst_hlsdemux2_imagebuf_pipe_bus_cb, user_data);
3532 gst_object_unref (bus);
3534 appsrc = gst_element_factory_make ("appsrc", "imgbuf-src");
3536 GST_ERROR_OBJECT (demux, "failed to create appSrc element");
3540 appsink = gst_element_factory_make ("appsink", "imgbuf-sink");
3542 GST_ERROR_OBJECT (demux, "failed to create appSink element");
3546 dec = gst_element_factory_make ("jpegdec", "jpeg-decoder");
3548 GST_ERROR_OBJECT (demux, "failed to create jpeg-decoder element");
3552 videorate = gst_element_factory_make ("videorate", "video-rate");
3554 GST_ERROR_OBJECT (demux, "failed to create ffmpeg-converter element");
3558 capsfilter = gst_element_factory_make ("capsfilter", "caps-filter");
3560 GST_ERROR_OBJECT (demux, "failed to create caps-filter element");
3564 scale_caps = gst_caps_new_simple ("video/x-raw-yuv",
3565 "width" , G_TYPE_INT, 480,
3566 "height", G_TYPE_INT, 270,
3567 "framerate",GST_TYPE_FRACTION,30,1,
3568 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('I','4','2','0'),
3570 g_object_set (capsfilter, "caps", scale_caps, NULL);
3572 enc = gst_element_factory_make ("savsenc_h264", "h264-encoder");
3574 GST_ERROR_OBJECT (demux, "failed to create h264-encoder element");
3578 image_caps = gst_caps_new_simple ("image/jpeg",
3579 "framerate", GST_TYPE_FRACTION, 30, 1,
3580 "width", G_TYPE_INT, 480,
3581 "height", G_TYPE_INT, 270,
3583 gst_buffer_set_caps (image_buffer, image_caps);
3585 gst_bin_add_many (GST_BIN (pvt_stream->convert_pipe), appsrc, dec, videorate, capsfilter, enc, appsink, NULL);
3586 if (!gst_element_link_many ( appsrc, dec, videorate, capsfilter, enc, appsink, NULL)) {
3587 GST_ERROR_OBJECT (demux, "failed to link elements...");
3591 pad = gst_element_get_static_pad(appsink,"sink");
3592 gst_pad_add_buffer_probe (pad,G_CALLBACK (gst_hlsdemux2_set_video_buffer), user_data);
3593 gst_pad_add_event_probe (pad,G_CALLBACK (gst_hlsdemux2_done_video_buffer), user_data);
3594 gst_element_set_state (pvt_stream->convert_pipe, GST_STATE_PLAYING);
3596 fret = gst_app_src_push_buffer ((GstAppSrc *)appsrc, pvt_stream->image_buffer);
3597 if(fret != GST_FLOW_OK){
3598 GST_ERROR_OBJECT (demux, "Push Failed; Error: %s[%d]", gst_flow_get_name(fret),fret);
3602 fret = gst_app_src_end_of_stream ((GstAppSrc *)appsrc);
3603 if(fret != GST_FLOW_OK){
3604 GST_ERROR_OBJECT (demux, "Push EOS Failed; Error: %s[%d]", gst_flow_get_name(fret),fret);
3607 g_free(image_header);
3608 image_header = NULL;
3612 GST_ERROR_OBJECT (demux, "ERROR ERROR ERROR: tut tut tut ");
3613 g_free(image_header);
3614 image_header = NULL;
3619 gst_hlsdemux2_push_dummy_data (GstHLSDemux2Stream *stream)
3621 GstHLSDemux2 *demux = stream->parent;
3622 struct stat stat_results;
3623 GstBuffer *buf = NULL;
3626 GstCaps *caps = NULL;
3627 GstBuffer *pushbuf = NULL;
3628 GstClockTime stop = GST_CLOCK_TIME_NONE;
3629 GstClockTime next_ts = GST_CLOCK_TIME_NONE;
3630 gboolean first_frame = TRUE;
3632 gboolean convert_success = TRUE;
3633 GstHLSDemux2Stream *cur_stream = NULL;
3635 GstClockTime cdisc = 0;
3637 GST_INFO_OBJECT (demux, "START dummy video data thread");
3639 /* Read dummy frame */
3640 if(demux->has_image_buffer) {
3641 GstHLSDemux2PvtStream *pvt_stream = demux->private_stream;
3643 g_mutex_lock (pvt_stream->img_load_lock);
3644 if(pvt_stream->got_img_buffer == FALSE)
3645 g_cond_wait(pvt_stream->img_load_cond, pvt_stream->img_load_lock);
3646 g_mutex_unlock (pvt_stream->img_load_lock);
3648 GST_LOG_OBJECT (demux, "prev_image_buffer = %p and image_buffer = %p",
3649 demux->prev_image_buffer, pvt_stream->image_buffer);
3651 /* check whether it is same as previous image */
3652 if (demux->prev_video_buffer && demux->prev_image_buffer &&
3653 (GST_BUFFER_SIZE(demux->prev_image_buffer) == GST_BUFFER_SIZE(pvt_stream->image_buffer))) {
3654 if (!memcmp (GST_BUFFER_DATA(demux->prev_image_buffer), GST_BUFFER_DATA(pvt_stream->image_buffer),
3655 GST_BUFFER_SIZE(pvt_stream->image_buffer))) {
3656 GST_INFO_OBJECT (demux, "current & previous embedded images are same..no need to prepare video buffer");
3657 gst_buffer_unref(pvt_stream->image_buffer);
3658 pvt_stream->image_buffer = NULL;
3659 buf = gst_buffer_copy(demux->prev_video_buffer);
3664 if (demux->prev_image_buffer) {
3665 gst_buffer_unref (demux->prev_image_buffer);
3667 demux->prev_image_buffer = gst_buffer_copy(pvt_stream->image_buffer);
3669 g_mutex_lock (pvt_stream->convert_lock);
3670 convert_success = gst_hlsdemux2_private_image_to_vid(pvt_stream, pvt_stream->image_buffer);
3672 g_cond_wait(pvt_stream->convert_cond, pvt_stream->convert_lock);
3673 g_mutex_unlock (pvt_stream->convert_lock);
3675 if(pvt_stream->convert_pipe){
3676 pvt_stream->convert_pipe = NULL;
3677 gst_object_unref(pvt_stream->convert_pipe);
3680 if (demux->prev_video_buffer) {
3681 gst_buffer_unref (demux->prev_video_buffer);
3682 demux->prev_video_buffer = NULL;
3685 if(convert_success){
3686 buf = pvt_stream->video_buffer;
3687 pvt_stream->video_buffer = NULL;
3688 demux->prev_video_buffer = gst_buffer_copy(buf);
3689 GST_DEBUG_OBJECT (demux, "Set Image from buffer - success [%d,%d]", buf->data[0], buf->data[1]);
3690 GST_INFO_OBJECT (demux, "Going to show embedded image");
3694 //load black frame if error occured while creating video buffer.
3695 if(demux->has_image_buffer == FALSE || convert_success == FALSE)
3697 GST_INFO_OBJECT (demux, "Going to show fixed image");
3698 dummy_fp = open (PREDEFINED_VIDEO_FRAME_LOCATION, O_RDONLY);
3700 GST_ERROR_OBJECT (stream->pad, "failed to open dummy data file : %s...", PREDEFINED_VIDEO_FRAME_LOCATION);
3701 GST_ELEMENT_ERROR (demux, RESOURCE, OPEN_READ, ("Failed open file '%s' for reading. reason : %s",PREDEFINED_VIDEO_FRAME_LOCATION ,g_strerror(errno)), (NULL));
3705 GST_LOG_OBJECT (stream->pad, "opened dummy video file %s succefully...", PREDEFINED_VIDEO_FRAME_LOCATION);
3707 if (fstat (dummy_fp, &stat_results) < 0) {
3708 GST_ERROR_OBJECT (stream->pad, "failed to get stats of a file...");
3709 GST_ELEMENT_ERROR (demux, RESOURCE, FAILED, ("Failed get stats. reason : %s", g_strerror(errno)), (NULL));
3714 GST_LOG_OBJECT (stream->pad, "size of the dummy file = %d\n", stat_results.st_size);
3716 buf = gst_buffer_new_and_alloc (stat_results.st_size);
3718 GST_ERROR_OBJECT (stream->pad, "failed to allocate memory...");
3719 GST_ELEMENT_ERROR (demux, RESOURCE, NO_SPACE_LEFT, ("can't allocate memory"), (NULL));
3724 iread = read (dummy_fp, GST_BUFFER_DATA (buf), stat_results.st_size);
3731 for (n = 0; n < HLSDEMUX2_STREAM_NUM; n++) {
3732 cur_stream = demux->streams[n];
3734 if (cur_stream && (stream != cur_stream)) {
3735 cdisc = cur_stream->cdisc;
3739 stream->nts = stop = stream->fts + demux->cfrag_dur;
3740 stream->total_disc += cdisc;
3741 stream->cdisc = cdisc;
3742 next_ts = stream->fts;
3744 GST_INFO_OBJECT (stream->pad, "Dummy video start_ts = %"GST_TIME_FORMAT" and stop_ts = %"GST_TIME_FORMAT,
3745 GST_TIME_ARGS(stream->fts), GST_TIME_ARGS(stop));
3747 /* set caps on buffer */
3748 caps = gst_caps_new_simple ("video/x-h264",
3749 "stream-format", G_TYPE_STRING, "byte-stream",
3750 "alignment", G_TYPE_STRING, "nal",
3753 gst_buffer_set_caps (buf, caps);
3755 if (stream->need_newsegment) {
3756 GST_INFO_OBJECT (stream->pad, "need to send new segment event based on audio");
3757 g_queue_push_tail (stream->queue, (demux->streams[HLSDEMUX2_STREAM_AUDIO])->newsegment);
3758 stream->need_newsegment = FALSE;
3763 if (demux->cancelled || demux->flushing) {
3764 GST_WARNING_OBJECT (stream->pad, "Stopping dummy push task...");
3768 g_mutex_lock (stream->queue_lock);
3770 pushbuf = gst_buffer_copy (buf);
3771 gst_buffer_set_caps (pushbuf, caps);
3772 GST_BUFFER_TIMESTAMP (pushbuf) = stream->lts = next_ts;
3773 GST_BUFFER_DURATION (pushbuf) = GST_CLOCK_TIME_NONE;
3776 GST_BUFFER_FLAG_SET (pushbuf, GST_BUFFER_FLAG_DISCONT);
3777 first_frame = FALSE;
3780 GST_LOG_OBJECT (stream->pad, "Pushing dummy buffer : ts = %"GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (pushbuf)));
3782 /* calculate cached duration */
3783 gst_hlsdemux2_calculate_pushed_duration (demux, stream, pushbuf);
3785 if (stream->cached_duration >= 0) {
3787 percent = (stream->cached_duration * 100) / demux->total_cache_duration;
3788 GST_LOG_OBJECT (stream->pad, "percent done = %"G_GINT64_FORMAT, percent);
3790 if (percent > 100) {
3791 guint64 overall_percent = 0;
3793 g_mutex_lock (demux->buffering_lock);
3794 overall_percent = demux->percent;
3795 g_mutex_unlock (demux->buffering_lock);
3797 if (overall_percent < 100) { /* otherwise, may cause blocking while buffering*/
3798 GST_DEBUG_OBJECT (stream->pad, "@@@@@@@@@@@ queue should not go to wait now @@@@@@@@");
3800 /* update buffering & wait if space is not available */
3801 GST_DEBUG_OBJECT (stream->pad, "Reached more than 100 percent, queue full & wait till free");
3802 g_cond_wait(stream->queue_full, stream->queue_lock);
3803 GST_DEBUG_OBJECT (stream->pad,"Received signal to add more data...");
3808 g_cond_signal (stream->queue_empty);
3810 g_mutex_unlock (stream->queue_lock);
3812 /* calculate next timestamp */
3813 next_ts += HLS_DEFAULT_FRAME_DURATION;
3815 if (next_ts > stop) {
3816 GST_DEBUG_OBJECT (stream->pad, "Reached Endof the fragment ....\n\n");
3821 if (demux->end_of_playlist) {
3822 /* end of playlist, push EOS to queue */
3823 GST_INFO_OBJECT (stream->pad, "pushing EOS event to stream's queue");
3824 g_queue_push_tail (stream->queue, gst_event_new_eos ());
3827 #ifdef LATEST_AV_SYNC
3828 if (demux->is_live) {
3829 stream->total_stream_time += (stream->lts - stream->fts);
3831 stream->total_stream_time += (stream->lts - stream->fts + HLS_DEFAULT_FRAME_DURATION);
3832 stream->total_stream_time = stream->nts;
3835 stream->total_stream_time += (stream->lts - stream->fts);
3838 GST_DEBUG_OBJECT (stream->pad, "---------------- TS VALUES ----------------");
3839 GST_DEBUG_OBJECT (stream->pad, "valid start ts = %"GST_TIME_FORMAT, GST_TIME_ARGS(stream->fts));
3840 GST_DEBUG_OBJECT (stream->pad, "valid end ts = %"GST_TIME_FORMAT, GST_TIME_ARGS(stream->lts));
3841 GST_DEBUG_OBJECT (stream->pad, "fragment duration received = %"GST_TIME_FORMAT, GST_TIME_ARGS(stream->lts - stream->fts));
3842 GST_DEBUG_OBJECT (stream->pad, "total stream time = %"GST_TIME_FORMAT,GST_TIME_ARGS(stream->total_stream_time));
3843 GST_DEBUG_OBJECT (stream->pad, "total disc time = %"GST_TIME_FORMAT, GST_TIME_ARGS(stream->total_disc));
3844 GST_DEBUG_OBJECT (stream->pad, "next expected start ts = %"GST_TIME_FORMAT, GST_TIME_ARGS(stream->nts));
3845 GST_DEBUG_OBJECT (stream->pad, "---------------- DUMP VALUES END----------------");
3847 stream->apply_disc = FALSE;
3848 stream->fts = GST_CLOCK_TIME_NONE;
3849 stream->valid_fts_rcvd = FALSE;
3850 stream->prev_nts = stream->nts;
3854 GST_INFO_OBJECT (stream->pad, "Stopping dummy data thread...");
3855 gst_buffer_unref (buf);
3856 stream->dummy_data_thread = NULL;
3863 gst_hlsdemux2_sink_event_handler (GstPad * pad, GstEvent * event, gpointer data)
3865 GstHLSDemux2Stream *stream = (GstHLSDemux2Stream *)data;
3866 GstHLSDemux2 *demux = stream->parent;
3868 if ((GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) && stream->need_newsegment) {
3869 GstEvent *newsegment = NULL;
3872 gdouble rate, arate;
3873 gint64 start, stop, pos;
3875 newsegment = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, demux->ns_start, -1, demux->ns_start);
3877 GST_INFO_OBJECT (stream->pad, "Received NEWSEGMENT event...");
3879 g_mutex_lock (stream->queue_lock);
3881 gst_event_parse_new_segment_full(event, &update, &rate, &arate, &format, &start, &stop, &pos);
3883 if (!GST_CLOCK_TIME_IS_VALID(stream->base_ts)) {
3884 GST_INFO_OBJECT (stream->pad, "storing stream's base timestamp = %"GST_TIME_FORMAT, GST_TIME_ARGS(start));
3885 stream->base_ts = start;
3888 g_queue_push_tail (stream->queue, newsegment);
3890 GST_INFO_OBJECT (stream->pad, "Pushed new segment event with start = %"GST_TIME_FORMAT" to queue..",
3891 GST_TIME_ARGS(demux->ns_start));
3893 g_mutex_unlock (stream->queue_lock);
3895 stream->need_newsegment = FALSE;
3896 stream->prev_nts = demux->ns_start;
3898 if (stream->newsegment)
3899 gst_event_unref (stream->newsegment);
3901 stream->newsegment = gst_event_copy (newsegment);
3907 hlsdemux2_HTTP_repeat_request (GstHLSDemux2 *demux, gchar *element_name)
3909 if (g_strrstr(element_name, "fragurisrc")) {
3911 GstBuffer *buf = NULL;
3913 /* clear stream queues if we already downloaded some data */
3914 for (idx = 0; idx < HLSDEMUX2_STREAM_NUM; idx++) {
3915 GstHLSDemux2Stream *stream = demux->streams[idx];
3917 while (!g_queue_is_empty (stream->downloader_queue)) {
3918 buf = g_queue_pop_head (stream->downloader_queue);
3919 gst_buffer_unref (buf);
3921 GST_LOG_OBJECT (stream->pad, "cleared stream download queue...");
3922 g_queue_clear (stream->downloader_queue);
3926 /* request the same fragment again */
3927 if (demux->fragCookie)
3928 g_strfreev (demux->fragCookie);
3930 g_object_get (demux->fdownloader->urisrc, "cookies", &demux->fragCookie, NULL);
3931 GST_DEBUG_OBJECT (demux, "Got cookies after FRAGMENT download : %s", demux->fragCookie ? *(demux->fragCookie) : NULL);
3933 GST_INFO_OBJECT (demux, "========>>>>>Going to download fragment AGAIN: %s", demux->frag_uri);
3935 gst_hlsdemux2_destroy_fragment_download (demux);
3937 if (!gst_hlsdemux2_create_fragment_download (demux, demux->frag_uri)) {
3938 GST_ERROR_OBJECT (demux, "failed to create download pipeline");
3939 GST_ELEMENT_ERROR (demux, CORE, FAILED, ("Failed to create pipeline"), (NULL));
3943 /* download rate calculation : note down start time*/
3944 demux->fdownloader->download_start_ts = gst_util_get_timestamp();
3946 gst_element_set_state (demux->fdownloader->pipe, GST_STATE_PLAYING);
3949 } else if (g_strrstr(element_name, "playlisturisrc")) {
3951 if (demux->playlistCookie)
3952 g_strfreev (demux->playlistCookie);
3954 g_object_get (demux->pldownloader->urisrc, "cookies", &demux->playlistCookie, NULL);
3956 GST_DEBUG_OBJECT (demux, "Got cookies after PLAYLIST download : %s", demux->playlistCookie ? *(demux->playlistCookie) : NULL);
3958 gst_hlsdemux2_destroy_playlist_download (demux);
3960 GST_INFO_OBJECT (demux, "========>>>>>Going to download playlist AGAIN: %s", demux->playlist_uri);
3961 if (!gst_hlsdemux2_create_playlist_download (demux, demux->playlist_uri)) {
3962 GST_ERROR_OBJECT (demux, "failed to create download pipeline");
3963 GST_ELEMENT_ERROR (demux, CORE, FAILED, ("Failed to create pipeline"), (NULL));
3967 gst_element_set_state (demux->pldownloader->pipe, GST_STATE_PLAYING);
3969 } else if (g_strrstr(element_name, "keyurisrc")) {
3971 if (demux->keyCookie)
3972 g_strfreev (demux->keyCookie);
3974 g_object_get (demux->kdownloader->urisrc, "cookies", &demux->keyCookie, NULL);
3976 GST_DEBUG_OBJECT (demux, "Got cookies after KEY download : %s", demux->keyCookie ? *(demux->keyCookie) : NULL);
3978 GST_INFO_OBJECT (demux, "========>>>>>Going to download key AGAIN: %s", demux->key_uri);
3980 gst_hlsdemux2_destroy_key_download (demux);
3982 if (!gst_hlsdemux2_create_key_download (demux, demux->key_uri)) {
3983 GST_ERROR_OBJECT (demux, "failed to create download pipeline");
3984 GST_ELEMENT_ERROR (demux, CORE, FAILED, ("Failed to create pipeline"), (NULL));
3988 gst_element_set_state (demux->kdownloader->pipe, GST_STATE_PLAYING);
3997 hlsdemux2_HTTP_time_out (GstHLSDemux2 *demux, gchar *element_name)
3999 if (g_strrstr(element_name, "fragurisrc")) {
4000 /* as it is because of timeout, there is no point in requesting the same fragment again, so request next one */
4001 GST_INFO_OBJECT (demux, "signalling fragment downloader to get next fragment...");
4002 demux->fdownloader->get_next_frag = TRUE;
4003 g_cond_signal (demux->fdownloader->cond);
4005 } else if (g_strrstr(element_name, "playlisturisrc")) {
4007 if (demux->playlistCookie)
4008 g_strfreev (demux->playlistCookie);
4010 g_object_get (demux->pldownloader->urisrc, "cookies", &demux->playlistCookie, NULL);
4012 GST_DEBUG_OBJECT (demux, "Got cookies after PLAYLIST download : %s", demux->playlistCookie ? *(demux->playlistCookie) : NULL);
4014 gst_hlsdemux2_destroy_playlist_download (demux);
4016 GST_INFO_OBJECT (demux, "========>>>>>Going to download playlist AGAIN: %s", demux->playlist_uri);
4017 if (!gst_hlsdemux2_create_playlist_download (demux, demux->playlist_uri)) {
4018 GST_ERROR_OBJECT (demux, "failed to create download pipeline");
4019 GST_ELEMENT_ERROR (demux, CORE, FAILED, ("Failed to create pipeline"), (NULL));
4023 gst_element_set_state (demux->pldownloader->pipe, GST_STATE_PLAYING);
4025 } else if (g_strrstr(element_name, "keyurisrc")) {
4027 if (demux->keyCookie)
4028 g_strfreev (demux->keyCookie);
4030 g_object_get (demux->kdownloader->urisrc, "cookies", &demux->keyCookie, NULL);
4032 GST_DEBUG_OBJECT (demux, "Got cookies after KEY download : %s", demux->keyCookie ? *(demux->keyCookie) : NULL);
4034 GST_INFO_OBJECT (demux, "========>>>>>Going to download key AGAIN: %s", demux->key_uri);
4036 gst_hlsdemux2_destroy_key_download (demux);
4038 if (!gst_hlsdemux2_create_key_download (demux, demux->key_uri)) {
4039 GST_ERROR_OBJECT (demux, "failed to create download pipeline");
4040 GST_ELEMENT_ERROR (demux, CORE, FAILED, ("Failed to create pipeline"), (NULL));
4044 gst_element_set_state (demux->kdownloader->pipe, GST_STATE_PLAYING);
4052 hlsdemux2_HTTP_not_found(GstHLSDemux2 *demux, gchar *element_name)
4054 if (g_strrstr(element_name, "fragurisrc")) {
4055 if (demux->is_live) {
4056 /* request next fragment url */
4057 GST_INFO_OBJECT (demux, "signalling fragment downloader to get next fragment...");
4058 demux->fdownloader->get_next_frag = TRUE;
4059 g_cond_signal (demux->fdownloader->cond);
4063 #if 0 // In future enable
4064 GList *next_variant = NULL;
4066 if (demux->pldownloader->recovery_mode == HLSDEMUX2_NO_RECOVERY)
4067 demux->pldownloader->recovery_mode = HLSDEMUX2_DOWNWARD_RECOVERY;
4069 if (demux->pldownloader->recovery_mode == HLSDEMUX2_DOWNWARD_RECOVERY) {
4070 /* get next available lower variant */
4071 next_variant = gst_m3u8_client_get_next_lower_bw_playlist (demux->client);
4072 if (!next_variant) {
4073 GST_WARNING_OBJECT (demux, "no next lower variants.. Go Upward");
4074 demux->pldownloader->recovery_mode = HLSDEMUX2_UPWARD_RECOVERY;
4078 if (demux->pldownloader->recovery_mode == HLSDEMUX2_UPWARD_RECOVERY) {
4079 /* get next available lower variant */
4080 next_variant = gst_m3u8_client_get_next_higher_bw_playlist (demux->client);
4081 if (!next_variant) {
4082 GST_ERROR_OBJECT (demux, "no next higher variants.. need to exit");
4083 demux->pldownloader->recovery_mode = HLSDEMUX2_NO_RECOVERY;
4088 /* change variant */
4089 GST_M3U8_CLIENT_LOCK (demux->client);
4090 demux->client->main->current_variant = next_variant;
4091 GST_M3U8_CLIENT_UNLOCK (demux->client);
4093 gst_m3u8_client_set_current (demux->client, next_variant->data);
4095 demux->fdownloader->get_next_frag = TRUE;
4096 g_cond_signal (demux->fdownloader->cond);
4103 } else if (g_strrstr(element_name, "playlisturisrc")) {
4104 GList *next_variant = NULL;
4106 if (demux->pldownloader->recovery_mode == HLSDEMUX2_NO_RECOVERY)
4107 demux->pldownloader->recovery_mode = HLSDEMUX2_DOWNWARD_RECOVERY;
4109 if (demux->pldownloader->recovery_mode == HLSDEMUX2_DOWNWARD_RECOVERY) {
4110 /* get next available lower variant */
4111 next_variant = gst_m3u8_client_get_next_lower_bw_playlist (demux->client);
4112 if (!next_variant) {
4113 GST_WARNING_OBJECT (demux, "no next lower variants.. Go Upward");
4114 demux->pldownloader->recovery_mode = HLSDEMUX2_UPWARD_RECOVERY;
4118 if (demux->pldownloader->recovery_mode == HLSDEMUX2_UPWARD_RECOVERY) {
4119 /* get next available lower variant */
4120 next_variant = gst_m3u8_client_get_next_higher_bw_playlist (demux->client);
4121 if (!next_variant) {
4122 GST_ERROR_OBJECT (demux, "no next higher variants.. need to exit");
4123 demux->pldownloader->recovery_mode = HLSDEMUX2_NO_RECOVERY;
4128 /* change variant */
4129 GST_M3U8_CLIENT_LOCK (demux->client);
4130 demux->client->main->current_variant = next_variant;
4131 GST_M3U8_CLIENT_UNLOCK (demux->client);
4133 gst_m3u8_client_set_current (demux->client, next_variant->data);
4135 /* get new playlist uri */
4136 demux->playlist_uri = g_strdup (gst_m3u8_client_get_current_uri (demux->client));
4138 if (demux->playlistCookie)
4139 g_strfreev (demux->playlistCookie);
4141 g_object_get (demux->pldownloader->urisrc, "cookies", &demux->playlistCookie, NULL);
4143 GST_DEBUG_OBJECT (demux, "Got cookies after PLAYLIST download : %s", demux->playlistCookie ? *(demux->playlistCookie) : NULL);
4145 gst_hlsdemux2_destroy_playlist_download (demux);
4147 GST_INFO_OBJECT (demux, "========>>>>>Going to download recovery playlist : %s", demux->playlist_uri);
4148 if (!gst_hlsdemux2_create_playlist_download (demux, demux->playlist_uri)) {
4149 GST_ERROR_OBJECT (demux, "failed to create download pipeline");
4150 GST_ELEMENT_ERROR (demux, CORE, FAILED, ("Failed to create pipeline"), (NULL));
4154 gst_element_set_state (demux->pldownloader->pipe, GST_STATE_PLAYING);
4158 } else if (g_strrstr(element_name, "keyurisrc")) {
4159 /* treating it as non-recoverable error */
4167 gst_hlsdemux2_handle_HTTP_error (GstHLSDemux2 *demux, GError *error, gchar *element_name) {
4169 guint n_http_errors = sizeof (http_errors) / sizeof (http_errors[0]);
4172 return HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE;
4173 for (i = 0; i < n_http_errors; i++) {
4174 if (G_LIKELY (!strncmp(error->message, http_errors[i].error_phrase, strlen(error->message)))) {
4175 if (http_errors[i].handle_error) {
4176 return http_errors[i].handle_error (demux, element_name);
4178 return http_errors[i].error_type;
4181 return HLSDEMUX2_HTTP_ERROR_NONRECOVERABLE;
4185 gst_hlsdemux2_fragment_download_bus_cb(GstBus *bus, GstMessage *msg, gpointer data)
4187 GstHLSDemux2 *demux = (GstHLSDemux2 *)data;
4188 GError *error = NULL;
4189 gchar* debug = NULL;
4190 gboolean bret = TRUE;
4191 GstMessage *err_msg = NULL;
4192 gchar *ele_name = gst_element_get_name (GST_MESSAGE_SRC (msg));
4194 switch (GST_MESSAGE_TYPE(msg)) {
4195 case GST_MESSAGE_EOS: {
4196 GST_INFO_OBJECT (demux, "received EOS on download pipe from '%s'..", ele_name);
4197 demux->pldownloader->recovery_mode = HLSDEMUX2_NO_RECOVERY;
4198 g_cond_signal(demux->fdownloader->cond);
4201 case GST_MESSAGE_ERROR: {
4202 GST_ERROR_OBJECT (demux, "Error from %s\n", ele_name);
4204 gst_message_parse_error( msg, &error, &debug );
4206 demux->fdownloader->error_rcvd = TRUE;
4209 GST_ERROR_OBJECT (demux, "GST_MESSAGE_ERROR: error->message = %s and error->code = %d", error->message);
4211 GST_ERROR_OBJECT (demux, "GST_MESSAGE_ERROR: debug = %s", debug);
4213 if (g_strrstr(ele_name, "fragurisrc") && !demux->cancelled && demux->soup_request_fail_cnt) {
4215 /* flush the error msgs pending.. as we are going to create new pipeline */
4216 gst_bus_set_flushing (bus, TRUE);
4218 bret = gst_hlsdemux2_handle_HTTP_error (demux, error, ele_name);
4222 demux->soup_request_fail_cnt--;
4223 GST_WARNING_OBJECT (demux, "HTTP error count remaining = %d", demux->soup_request_fail_cnt);
4230 GST_ERROR_OBJECT (demux, "posting error from fragment download callback");
4232 err_msg = gst_message_new_error (GST_OBJECT(demux), error, debug);
4233 if (!gst_element_post_message (GST_ELEMENT(demux), err_msg)) {
4234 GST_ERROR_OBJECT (demux, "failed to post error");
4238 gst_hlsdemux2_stop (demux);
4241 case GST_MESSAGE_WARNING: {
4242 gst_message_parse_warning(msg, &error, &debug);
4243 GST_WARNING_OBJECT(demux, "warning : %s\n", error->message);
4244 GST_WARNING_OBJECT(demux, "debug : %s\n", debug);
4247 case GST_MESSAGE_ELEMENT: {
4248 const GstStructure *s = gst_message_get_structure (msg);
4250 if (gst_structure_has_name (s, "cookies")) {
4251 const GValue *value;
4252 gchar **cookies = NULL;
4253 gchar *cookie = NULL;
4254 value = gst_structure_get_value (s, "cookies");
4255 cookie = g_strdup_value_contents(value);
4258 GST_ERROR_OBJECT (demux, "received cookies from soup : %s", *cookies);
4272 g_error_free( error);
4275 gst_hlsdemux2_stop (demux);
4282 static GstBusSyncReply
4283 gst_hlsdemux2_playlist_download_bus_sync_cb (GstBus * bus, GstMessage *msg, gpointer data)
4285 GstHLSDemux2 *demux = (GstHLSDemux2 *)data;
4286 GstBusSyncReply reply = GST_BUS_DROP;
4288 GError *error = NULL;
4289 gchar *debug = NULL;
4290 gboolean bret = TRUE;
4291 GstMessage *err_msg = NULL;
4292 gchar *ele_name = gst_element_get_name (GST_MESSAGE_SRC (msg));
4294 switch (GST_MESSAGE_TYPE(msg)) {
4295 case GST_MESSAGE_EOS: {
4296 GST_DEBUG_OBJECT (demux, "received EOS on playlist download pipe..");
4297 demux->pldownloader->recovery_mode = HLSDEMUX2_NO_RECOVERY;
4298 g_mutex_lock (demux->pldownloader->lock);
4299 g_cond_broadcast (demux->pldownloader->cond);
4300 g_mutex_unlock (demux->pldownloader->lock);
4303 case GST_MESSAGE_ERROR: {
4304 GST_ERROR_OBJECT (demux, "Error from %s element", ele_name);
4306 gst_message_parse_error( msg, &error, &debug );
4308 GST_ERROR_OBJECT (demux, "GST_MESSAGE_ERROR: error= %s", error->message);
4310 GST_ERROR_OBJECT (demux, "GST_MESSAGE_ERROR: debug = %s", debug);
4312 if (g_strrstr(ele_name, "playlisturisrc") && !demux->cancelled && demux->soup_request_fail_cnt) {
4314 /* flush the error msgs pending.. as we are going to create new pipeline */
4315 gst_bus_set_flushing (bus, TRUE);
4317 bret = gst_hlsdemux2_handle_HTTP_error (demux, error, ele_name);
4321 demux->soup_request_fail_cnt--;
4322 GST_WARNING_OBJECT (demux, "HTTP error count remaining = %d", demux->soup_request_fail_cnt);
4329 GST_ERROR_OBJECT (demux, "posting error from playlist callback...");
4331 err_msg = gst_message_new_error (GST_OBJECT(demux), error, debug);
4332 if (!gst_element_post_message (GST_ELEMENT(demux), err_msg)) {
4333 GST_ERROR_OBJECT (demux, "failed to post error");
4337 gst_hlsdemux2_stop (demux);
4340 case GST_MESSAGE_WARNING: {
4341 gst_message_parse_warning(msg, &error, &debug);
4343 GST_WARNING_OBJECT(demux, "warning : %s\n", error->message);
4344 GST_WARNING_OBJECT(demux, "debug : %s\n", debug);
4347 case GST_MESSAGE_ELEMENT: {
4348 const GstStructure *s = gst_message_get_structure (msg);
4350 if (gst_structure_has_name (s, "cookies")) {
4351 const GValue *value;
4352 gchar **cookies = NULL;
4353 gchar *cookie = NULL;
4354 value = gst_structure_get_value (s, "cookies");
4355 cookie = g_strdup_value_contents(value);
4358 GST_ERROR_OBJECT (demux, "received cookies from soup : %s", *cookies);
4363 //GST_LOG_OBJECT(demux, "unhandled message : %s\n", gst_message_type_get_name (GST_MESSAGE_TYPE (msg)));
4373 g_error_free( error);
4376 gst_hlsdemux2_stop (demux);
4384 gst_hlsdemux2_key_download_bus_cb(GstBus *bus, GstMessage *msg, gpointer data)
4386 GstHLSDemux2 *demux = (GstHLSDemux2 *)data;
4387 GError *error = NULL;
4388 gchar* debug = NULL;
4389 gboolean bret = TRUE;
4390 GstMessage *err_msg = NULL;
4391 gchar *ele_name = gst_element_get_name (GST_MESSAGE_SRC (msg));
4393 switch (GST_MESSAGE_TYPE(msg)) {
4394 case GST_MESSAGE_EOS: {
4395 GST_DEBUG_OBJECT (demux, "received EOS on key download pipe..");
4396 demux->pldownloader->recovery_mode = HLSDEMUX2_NO_RECOVERY;
4397 g_mutex_lock (demux->kdownloader->lock);
4398 g_cond_signal (demux->kdownloader->cond);
4399 g_mutex_unlock (demux->kdownloader->lock);
4402 case GST_MESSAGE_ERROR: {
4403 GST_INFO_OBJECT (demux, "Error from %s element...", ele_name);
4405 gst_message_parse_error(msg, &error, &debug);
4408 GST_ERROR_OBJECT (demux, "GST_MESSAGE_ERROR: error= %s", error->message);
4410 GST_ERROR_OBJECT (demux, "GST_MESSAGE_ERROR: debug = %s", debug);
4412 if (g_strrstr(ele_name, "keyurisrc") && !demux->cancelled && demux->soup_request_fail_cnt) {
4414 /* flush the error msgs pending.. as we are going to create new pipeline */
4415 gst_bus_set_flushing (bus, TRUE);
4417 bret = gst_hlsdemux2_handle_HTTP_error (demux, error, ele_name);
4421 demux->soup_request_fail_cnt--;
4422 GST_WARNING_OBJECT (demux, "HTTP error count remaining = %d", demux->soup_request_fail_cnt);
4428 GST_ERROR_OBJECT (demux, "Error posting from key downloader...");
4429 err_msg = gst_message_new_error (GST_OBJECT(demux), error, debug);
4431 if (!gst_element_post_message (GST_ELEMENT(demux), err_msg)) {
4432 GST_ERROR_OBJECT (demux, "failed to post error");
4433 gst_hlsdemux2_stop (demux);
4437 gst_hlsdemux2_stop (demux);
4440 case GST_MESSAGE_WARNING: {
4441 gst_message_parse_warning(msg, &error, &debug);
4443 GST_WARNING_OBJECT(demux, "warning : %s\n", error->message);
4444 GST_WARNING_OBJECT(demux, "debug : %s\n", debug);
4447 case GST_MESSAGE_ELEMENT: {
4448 const GstStructure *s = gst_message_get_structure (msg);
4450 if (gst_structure_has_name (s, "cookies")) {
4451 const GValue *value;
4452 gchar **cookies = NULL;
4453 gchar *cookie = NULL;
4454 value = gst_structure_get_value (s, "cookies");
4455 cookie = g_strdup_value_contents(value);
4458 GST_ERROR_OBJECT (demux, "received cookies from soup : %s", *cookies);
4473 g_error_free( error);
4476 gst_hlsdemux2_stop (demux);
4484 gst_hlsdemux2_calculate_pushed_duration (GstHLSDemux2 *demux, GstHLSDemux2Stream *stream,
4489 gpointer data = NULL;
4491 // TODO: for all timestamps -1 case, we need to add max-bytes also
4493 g_queue_push_tail (stream->queue, inbuf);
4495 len = g_queue_get_length (stream->queue);
4497 /* peek the head buffer having valid timestamp to calculate cached duration */
4498 while (qidx < len) {
4499 data = g_queue_peek_nth (stream->queue, qidx);
4501 if (GST_IS_BUFFER (data)) {
4502 if (GST_BUFFER_TIMESTAMP_IS_VALID(data)) {
4503 GST_LOG_OBJECT (stream->pad, "data found buffer with valid ts = %"GST_TIME_FORMAT " len = %d & qidx = %d",
4504 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(data)), len, qidx);
4510 if(GST_IS_BUFFER (data)) {
4511 if (GST_BUFFER_TIMESTAMP (inbuf) >= GST_BUFFER_TIMESTAMP ((GstBuffer *)data)) {
4512 stream->cached_duration = GST_BUFFER_TIMESTAMP (inbuf) - GST_BUFFER_TIMESTAMP ((GstBuffer *)data);
4513 GST_LOG_OBJECT (stream->pad, "len = %d, cached duration = %"GST_TIME_FORMAT,
4514 g_queue_get_length (stream->queue), GST_TIME_ARGS(stream->cached_duration));
4516 GST_WARNING_OBJECT (stream->pad, "Wrong order.. not calculating");
4523 gst_hlsdemux2_alter_timestamps (GstHLSDemux2Stream *stream, GstBuffer *inbuf)
4525 GstHLSDemux2 *demux = stream->parent;
4526 GstClockTime cts = 0;
4528 /* set discontinuity only when there is real fragment discontinuity */
4529 if (GST_BUFFER_IS_DISCONT(inbuf)) {
4530 if (!stream->apply_disc) {
4531 GST_BUFFER_FLAG_UNSET (inbuf, GST_BUFFER_FLAG_DISCONT);
4532 GST_INFO_OBJECT (stream->pad, "unsetting discontinuity flag...");
4536 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (inbuf))) {
4537 if (GST_BUFFER_TIMESTAMP (inbuf) >= stream->base_ts) {
4538 cts = GST_BUFFER_TIMESTAMP (inbuf) - stream->base_ts;
4540 /* this buffer should be dropped at sink */
4541 GST_WARNING_OBJECT (stream->pad, "input timestamp [%"GST_TIME_FORMAT"] is less than base_ts [%"GST_TIME_FORMAT"]",
4542 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (inbuf)), GST_TIME_ARGS(stream->base_ts));
4543 if (stream->type == HLSDEMUX2_STREAM_AUDIO) {
4546 GST_BUFFER_TIMESTAMP (inbuf) = GST_CLOCK_TIME_NONE;
4551 /* this buffer should be dropped at sink */
4552 GST_LOG_OBJECT (stream->pad, "invalid input timestamp (i.e. GST_CLOCK_TIME_NONE)");
4553 #ifdef LATEST_AV_SYNC
4554 if (!demux->is_live && (stream->type == HLSDEMUX2_STREAM_AUDIO) && !stream->valid_fts_rcvd){
4555 GST_WARNING_OBJECT (stream->pad, "dropping invalid ts buffer, due to no valid first ts yet...");
4562 /* handle discontinuity in stream */
4563 if(GST_CLOCK_TIME_IS_VALID (stream->nts) && (GST_CLOCK_DIFF(stream->nts,cts) > (2 * GST_SECOND)) && stream->apply_disc) {
4564 GST_INFO_OBJECT (stream->pad, "cts = %"GST_TIME_FORMAT" and prev_next_ts = %"GST_TIME_FORMAT,
4565 GST_TIME_ARGS(cts), GST_TIME_ARGS(stream->nts));
4566 GST_INFO_OBJECT (stream->pad,"Received disc = %"GST_TIME_FORMAT, GST_TIME_ARGS(cts - stream->nts));
4567 stream->cdisc = cts - stream->nts;
4568 stream->total_disc += (cts - stream->nts);
4569 GST_INFO_OBJECT (stream->pad, "total disc = %"GST_TIME_FORMAT, GST_TIME_ARGS(stream->total_disc));
4570 stream->apply_disc = FALSE;
4573 cts -= stream->cdisc;
4575 /* get the max last ts, required because of frame reordering */
4576 stream->lts = cts > stream->lts ? cts : stream->lts;
4578 GST_DEBUG_OBJECT (stream->pad, "modifying buffer timestamp : %"GST_TIME_FORMAT" -> %"GST_TIME_FORMAT,
4579 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (inbuf)), GST_TIME_ARGS(cts));
4581 #ifndef LATEST_AV_SYNC
4582 /* store first valid timestamp of a fragment */
4583 if (stream->fts == GST_CLOCK_TIME_NONE) {
4585 stream->nts = stream->fts + demux->cfrag_dur;
4586 GST_INFO_OBJECT (stream->pad, "storing first ts = %"GST_TIME_FORMAT, GST_TIME_ARGS(stream->fts));
4587 if (demux->is_live && stream->type == HLSDEMUX2_STREAM_AUDIO)
4588 demux->cur_audio_fts = cts;
4592 #ifdef LATEST_AV_SYNC
4593 /* 10/31/2013: dont want to disturb live case at this moment */
4594 if (!stream->valid_fts_rcvd) {
4595 if (stream->type == HLSDEMUX2_STREAM_AUDIO) {
4596 if (!demux->is_live && (GST_CLOCK_DIFF(cts, stream->prev_nts) > (10 * GST_MSECOND))) {
4597 GST_WARNING_OBJECT (stream->pad, "already seen audio timestamps[%"GST_TIME_FORMAT"]"
4598 " and previous_nts = %"GST_TIME_FORMAT"...drop this",
4599 GST_TIME_ARGS(cts), GST_TIME_ARGS(stream->prev_nts));
4602 GST_INFO_OBJECT (stream->pad, "recevied valid audio first ts = %"GST_TIME_FORMAT,
4603 GST_TIME_ARGS (cts));
4604 demux->cur_audio_fts = cts;
4608 stream->valid_fts_rcvd = TRUE;
4610 stream->nts = stream->fts + demux->cfrag_dur; // Approximate nts
4612 GST_INFO_OBJECT (stream->pad, "storing first ts = %"GST_TIME_FORMAT, GST_TIME_ARGS(stream->fts));
4613 } else if (!stream->frame_duration) {
4614 stream->frame_duration = cts - stream->fts;
4615 GST_DEBUG_OBJECT (stream->pad, "frame duration = %"GST_TIME_FORMAT, GST_TIME_ARGS(stream->frame_duration));
4620 /* 10/31/2013: dont want to disturb live case at this moment */
4621 if (!demux->is_live && stream->type == HLSDEMUX2_STREAM_AUDIO) {
4622 if (!stream->valid_fts_rcvd) {
4623 if (GST_CLOCK_DIFF(cts, stream->prev_nts) > 0) {
4624 GST_WARNING_OBJECT (stream->pad, "already seen audio timestamps[%"GST_TIME_FORMAT"]"
4625 " and previous_nts = %"GST_TIME_FORMAT"...drop this",
4626 GST_TIME_ARGS(cts), GST_TIME_ARGS(stream->prev_nts));
4629 GST_INFO_OBJECT (stream->pad, "recevied valid audio first ts = %"GST_TIME_FORMAT,
4630 GST_TIME_ARGS (cts));
4631 demux->cur_audio_fts = cts;
4632 stream->valid_fts_rcvd = TRUE;
4634 } else if (!stream->frame_duration) {
4635 stream->frame_duration = cts - demux->cur_audio_fts;
4636 GST_DEBUG_OBJECT (demux, "audio frame duration = %"GST_TIME_FORMAT, GST_TIME_ARGS(stream->frame_duration));
4641 GST_BUFFER_TIMESTAMP (inbuf) = cts;
4647 gst_hlsdemux2_downloader_new_buffer (GstElement *appsink, void *user_data)
4649 GstHLSDemux2Stream *stream = (GstHLSDemux2Stream *)user_data;
4650 GstHLSDemux2 *demux = stream->parent;
4651 GstBuffer *inbuf = NULL;
4652 gboolean bret = FALSE;
4654 if (demux->cancelled ) {
4658 inbuf = gst_app_sink_pull_buffer ((GstAppSink *)appsink);
4660 GST_WARNING_OBJECT (demux, "Input buffer not available...");
4664 GST_LOG_OBJECT (stream->pad, "Received buffer with size = %d and ts = %"GST_TIME_FORMAT,
4665 GST_BUFFER_SIZE(inbuf), GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(inbuf)));
4667 if (demux->fdownloader->force_timestamps) {
4668 GST_BUFFER_TIMESTAMP(inbuf) += (stream->prev_nts + stream->base_ts);
4669 GST_DEBUG_OBJECT (stream->pad, "forced timestamp = %"GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(inbuf)));
4672 /* alter the timestamps */
4673 bret = gst_hlsdemux2_alter_timestamps (stream, inbuf);
4675 gst_buffer_unref (inbuf);
4679 /* store buffer in queue */
4680 g_queue_push_tail (stream->downloader_queue, inbuf);
4686 gst_hlsdemux2_imagebuf_pipe_bus_cb(GstBus *bus, GstMessage *msg, gpointer data)
4688 GstHLSDemux2PvtStream *stream = (GstHLSDemux2PvtStream *)data;
4689 GstHLSDemux2 *demux = (GstHLSDemux2 *)stream->parent;
4690 gboolean bret = TRUE;
4691 gchar *ele_name = gst_element_get_name (GST_MESSAGE_SRC (msg));
4693 GST_INFO_OBJECT(demux, "Message on BUS : %s", gst_message_type_get_name(GST_MESSAGE_TYPE(msg)));
4694 switch (GST_MESSAGE_TYPE(msg)) {
4695 case GST_MESSAGE_EOS: {
4696 GST_INFO_OBJECT (demux, "received EOS on IMAGE pipe from '%s'.. Closing pipeline", ele_name);
4697 g_cond_signal (stream->convert_cond);
4698 gst_object_unref (stream->convert_pipe);
4701 case GST_MESSAGE_ERROR: {
4702 GST_ERROR_OBJECT (demux, "Error Image Pipe from %s\n", ele_name);
4707 GST_DEBUG_OBJECT (demux, "Message on Image Pipe : %s from %s\n", gst_message_type_get_name(GST_MESSAGE_TYPE(msg)), ele_name);
4717 static gboolean gst_hlsdemux2_done_video_buffer (GstPad * srcpad, GstEvent * event, gpointer user_data)
4719 GstHLSDemux2PvtStream *stream = (GstHLSDemux2PvtStream *)user_data;
4720 GstHLSDemux2 *demux = (GstHLSDemux2 *)stream->parent;
4721 GST_LOG_OBJECT(demux,"EVENT %s on pad : %s having caps : %"GST_PTR_FORMAT,GST_EVENT_TYPE_NAME (event), GST_PAD_NAME(srcpad), srcpad->caps);
4722 if(event->type == GST_EVENT_EOS){
4723 GST_DEBUG_OBJECT(demux,"EVENT : %s Size : %d Pushing to demux video buffer [%d,%d]",
4724 GST_EVENT_TYPE_NAME (event),GST_BUFFER_SIZE(stream->video_buffer),
4725 stream->video_buffer->data[0],stream->video_buffer->data[1]);
4726 g_cond_signal (stream->convert_cond);
4731 static gboolean gst_hlsdemux2_set_video_buffer (GstPad * srcpad, GstBuffer * buffer, gpointer user_data)
4733 GstHLSDemux2PvtStream *pvt_stream = (GstHLSDemux2PvtStream *)user_data;
4734 GstHLSDemux2 *demux = (GstHLSDemux2 *)pvt_stream->parent;
4735 GST_LOG_OBJECT(demux,"BUFFER size:%d on pad having caps : %"GST_PTR_FORMAT,GST_BUFFER_SIZE(buffer), srcpad->caps);
4736 GST_LOG_OBJECT(demux,"BUFFER DATA : %d %d",buffer->data[0],buffer->data[1]);
4737 pvt_stream->video_buffer = buffer;
4742 gst_hlsdemux2_downloader_eos (GstElement * appsink, void* user_data)
4744 GstHLSDemux2Stream *stream = (GstHLSDemux2Stream *)user_data;
4745 GstHLSDemux2 *demux = stream->parent;
4746 GstBuffer *buf = NULL;
4749 /* push all data to queue specific to this stream */
4751 if (demux->cancelled || demux->flushing) {
4752 GST_WARNING_OBJECT (demux, "returning due to cancelled / flushing");
4756 if (g_queue_is_empty (stream->downloader_queue)) {
4757 GST_WARNING_OBJECT (demux, "EOS received without any buffer in downloader queue");
4761 if (demux->fdownloader->force_timestamps) {
4762 demux->cur_audio_fts = stream->prev_nts;
4765 if (demux->fdownloader->cur_stream_cnt < demux->active_stream_cnt) {
4768 GST_INFO_OBJECT (demux, "need to send dummy data.. check for the stream");
4770 /* signal queue full condition to come out */
4771 for (idx = 0; idx < HLSDEMUX2_STREAM_NUM; idx++) {
4772 GstHLSDemux2Stream *cur_stream = demux->streams[idx];
4773 GError *error = NULL;
4776 if (g_queue_is_empty (cur_stream->downloader_queue)) {
4777 GST_INFO_OBJECT (cur_stream->pad, "enable sending dummy data");
4779 /* take first ts of audio as cur_stream fts */
4780 cur_stream->fts = demux->cur_audio_fts;
4782 /* create thread to send dummy data */
4783 cur_stream->dummy_data_thread = g_thread_create ((GThreadFunc) gst_hlsdemux2_push_dummy_data,
4784 cur_stream, TRUE, &error);
4790 while (!g_queue_is_empty (stream->downloader_queue)) {
4792 if (demux->cancelled || demux->flushing) {
4793 GST_WARNING_OBJECT (stream->pad, "on cancel/flushing stopping pushing");
4797 buf = (GstBuffer *) g_queue_pop_head (stream->downloader_queue);
4799 GST_DEBUG_OBJECT (stream->pad, "input buffer timestamp : %"GST_TIME_FORMAT,
4800 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buf)));
4802 g_mutex_lock (stream->queue_lock);
4804 if (!GST_BUFFER_TIMESTAMP_IS_VALID(buf)){
4805 g_queue_push_tail (stream->queue, buf);
4806 g_cond_signal (stream->queue_empty);
4807 g_mutex_unlock (stream->queue_lock);
4811 GST_LOG_OBJECT (stream->pad, "buffer size = %d, ts = %"GST_TIME_FORMAT", dur = %"GST_TIME_FORMAT,
4812 GST_BUFFER_SIZE(buf), GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buf)), GST_TIME_ARGS(GST_BUFFER_DURATION(buf)));
4814 /* calculate cached duration */
4815 gst_hlsdemux2_calculate_pushed_duration (demux, stream, buf);
4817 if (stream->cached_duration < 0)
4818 stream->cached_duration = 0;
4820 percent = (stream->cached_duration * 100) / demux->total_cache_duration;
4821 GST_LOG_OBJECT (stream->pad, "percent done = %"G_GINT64_FORMAT, (gint)percent, percent);
4823 if (percent > 100) {
4824 guint64 overall_percent = 0;
4826 g_mutex_lock (demux->buffering_lock);
4827 overall_percent = demux->percent;
4828 g_mutex_unlock (demux->buffering_lock);
4830 if (overall_percent < 100) { /* otherwise, may cause blocking while buffering*/
4831 if (percent > 400) {
4832 GST_ERROR_OBJECT (stream->pad,"having worrest buffering.. exiting");
4833 GST_ELEMENT_ERROR (demux, STREAM, FAILED, ("wrong buffering.. check implementation"), (NULL));
4835 GST_INFO_OBJECT (stream->pad, "@@@@@@ queue should not go to wait now @@@@@@@@");
4837 /* update buffering & wait if space is not available */
4838 GST_LOG_OBJECT (stream->pad, "Reached more than 100 percent, queue full & wait till free");
4839 g_cond_wait(stream->queue_full, stream->queue_lock);
4840 GST_LOG_OBJECT (stream->pad,"Received signal to add more data...");
4844 g_cond_signal (stream->queue_empty);
4846 g_mutex_unlock (stream->queue_lock);
4849 /* wait for dummy threads finish their processing */
4850 if (demux->fdownloader->cur_stream_cnt < demux->active_stream_cnt) {
4853 GST_INFO_OBJECT (demux, "need to close dummy threads");
4855 /* signal queue full condition to come out */
4856 for (idx = 0; idx < HLSDEMUX2_STREAM_NUM; idx++) {
4857 GstHLSDemux2Stream *cur_stream = demux->streams[idx];
4859 if (cur_stream && cur_stream->dummy_data_thread) {
4860 GST_INFO_OBJECT (stream->pad, "waiting for dummy push thread to finish...");
4861 g_thread_join(cur_stream->dummy_data_thread);
4862 cur_stream->dummy_data_thread = NULL;
4863 GST_INFO_OBJECT (stream->pad, "COMPLETED DUMMY PUSH...");
4868 #ifdef LATEST_AV_SYNC
4869 if (demux->is_live) {
4870 stream->total_stream_time += (stream->lts - stream->fts);
4872 stream->total_stream_time += (stream->lts - stream->fts + stream->frame_duration);
4873 stream->nts = stream->total_stream_time;
4876 stream->total_stream_time += (stream->lts - stream->fts);
4879 GST_DEBUG_OBJECT (stream->pad, "---------------- TS VALUES ----------------");
4880 GST_DEBUG_OBJECT (stream->pad, "valid start ts = %"GST_TIME_FORMAT, GST_TIME_ARGS(stream->fts));
4881 GST_DEBUG_OBJECT (stream->pad, "valid end ts = %"GST_TIME_FORMAT, GST_TIME_ARGS(stream->lts));
4882 GST_DEBUG_OBJECT (stream->pad, "fragment duration received = %"GST_TIME_FORMAT, GST_TIME_ARGS(stream->lts - stream->fts));
4883 GST_DEBUG_OBJECT (stream->pad, "total stream time = %"GST_TIME_FORMAT,GST_TIME_ARGS(stream->total_stream_time));
4884 GST_DEBUG_OBJECT (stream->pad, "total disc time = %"GST_TIME_FORMAT, GST_TIME_ARGS(stream->total_disc));
4885 GST_DEBUG_OBJECT (stream->pad, "next expected start ts = %"GST_TIME_FORMAT, GST_TIME_ARGS(stream->nts));
4886 GST_DEBUG_OBJECT (stream->pad, "---------------- DUMP VALUES END----------------");
4888 stream->apply_disc = FALSE;
4889 stream->fts = GST_CLOCK_TIME_NONE;
4890 stream->valid_fts_rcvd = FALSE;
4891 stream->prev_nts = stream->nts;
4892 demux->fdownloader->force_timestamps = FALSE;
4897 gst_hlsdemux2_push_eos (GstHLSDemux2 *demux)
4901 /* signal queue full condition to come out */
4902 for (idx = 0; idx < HLSDEMUX2_STREAM_NUM; idx++) {
4903 GstHLSDemux2Stream *stream = demux->streams[idx];
4906 g_mutex_lock (stream->queue_lock);
4907 /* end of playlist, push EOS to queue */
4908 GST_INFO_OBJECT (stream->pad, "pushing EOS event to stream's queue");
4909 g_queue_push_tail (stream->queue, gst_event_new_eos ());
4910 g_cond_signal (stream->queue_empty);
4911 g_mutex_unlock (stream->queue_lock);
4917 gst_hlsdemux2_on_playlist_buffer (GstElement *appsink, void *data)
4919 GstHLSDemux2 *demux = (GstHLSDemux2 *)data;
4920 GstBuffer *inbuf = NULL;
4922 inbuf = gst_app_sink_pull_buffer ((GstAppSink *)appsink);
4924 GST_WARNING_OBJECT (demux, "Input buffer not available...");
4928 if (demux->pldownloader->playlist == NULL) {
4929 demux->pldownloader->playlist = gst_buffer_copy (inbuf);
4930 gst_buffer_unref (inbuf);
4932 GstBuffer *buffer = NULL;
4933 guint size = GST_BUFFER_SIZE(demux->pldownloader->playlist) + GST_BUFFER_SIZE(inbuf);
4935 buffer = gst_buffer_new_and_alloc (size);
4937 GST_ERROR_OBJECT (demux, "failed allocate memory...");
4938 GST_ELEMENT_ERROR (demux, RESOURCE, NO_SPACE_LEFT, ("can't allocate memory"), (NULL));
4939 gst_buffer_unref (inbuf);
4940 gst_buffer_unref (demux->pldownloader->playlist);
4944 /*copy existing playlist buffer */
4945 memcpy (GST_BUFFER_DATA(buffer), GST_BUFFER_DATA(demux->pldownloader->playlist), GST_BUFFER_SIZE(demux->pldownloader->playlist));
4947 /*copy new playlist buffer */
4948 memcpy (GST_BUFFER_DATA(buffer) + GST_BUFFER_SIZE(demux->pldownloader->playlist),
4949 GST_BUFFER_DATA(inbuf), GST_BUFFER_SIZE(inbuf));
4951 gst_buffer_unref (inbuf);
4952 gst_buffer_unref (demux->pldownloader->playlist);
4953 demux->pldownloader->playlist = buffer;
4960 gst_hlsdemux2_on_key_buffer (GstElement *appsink, void *data)
4962 GstHLSDemux2 *demux = (GstHLSDemux2 *)data;
4963 GstBuffer *inbuf = NULL;
4965 inbuf = gst_app_sink_pull_buffer ((GstAppSink *)appsink);
4967 GST_WARNING_OBJECT (demux, "Input buffer not available...");
4971 if (demux->kdownloader->key == NULL) {
4972 demux->kdownloader->key = gst_buffer_copy (inbuf);
4973 gst_buffer_unref (inbuf);
4975 GstBuffer *buffer = NULL;
4976 guint size = GST_BUFFER_SIZE(demux->kdownloader->key) + GST_BUFFER_SIZE(inbuf);
4978 buffer = gst_buffer_new_and_alloc (size);
4980 GST_ERROR_OBJECT (demux, "failed allocate memory...");
4981 GST_ELEMENT_ERROR (demux, RESOURCE, NO_SPACE_LEFT, ("can't allocate memory"), (NULL));
4982 gst_buffer_unref (inbuf);
4983 gst_buffer_unref (demux->kdownloader->key);
4987 /*copy existing playlist buffer */
4988 memcpy (GST_BUFFER_DATA(buffer), GST_BUFFER_DATA(demux->kdownloader->key), GST_BUFFER_SIZE(demux->kdownloader->key));
4990 /*copy new playlist buffer */
4991 memcpy (GST_BUFFER_DATA(buffer) + GST_BUFFER_SIZE(demux->kdownloader->key),
4992 GST_BUFFER_DATA(inbuf), GST_BUFFER_SIZE(inbuf));
4994 gst_buffer_unref (inbuf);
4995 gst_buffer_unref (demux->kdownloader->key);
4996 demux->kdownloader->key = buffer;
5003 gst_hlsdemux2_stop (GstHLSDemux2 *demux)
5005 GST_INFO_OBJECT (demux, "entering...");
5007 demux->cancelled = TRUE;
5009 g_cond_signal (demux->post_msg_start);
5010 g_cond_signal (demux->post_msg_exit);
5012 /* special case: for exiting playlist downloader created from sink event */
5013 if (demux->pldownloader && demux->pldownloader->cond)
5014 g_cond_broadcast (demux->pldownloader->cond);
5016 while (demux->download_task && (GST_TASK_STATE (demux->download_task) != GST_TASK_STOPPED)) {
5018 GstHLSDemux2Stream *stream = NULL;
5020 GST_INFO_OBJECT (demux, "Closing Download task...");
5022 /* signal queue full conditions */
5023 for (idx = 0; idx < HLSDEMUX2_STREAM_NUM; idx++) {
5024 stream = demux->streams[idx];
5026 if (stream && GST_PAD_TASK(stream->pad)) {
5027 gst_pad_push_event (stream->pad, gst_event_new_flush_start ());
5028 g_cond_broadcast(stream->queue_full);
5029 g_cond_broadcast(stream->queue_empty);
5033 if (demux->pl_update_cond)
5034 g_cond_broadcast (demux->pl_update_cond);
5036 if (demux->fdownloader && demux->fdownloader->cond)
5037 g_cond_broadcast (demux->fdownloader->cond);
5038 if (demux->kdownloader && demux->kdownloader->cond)
5039 g_cond_broadcast (demux->kdownloader->cond);
5040 if (demux->pldownloader && demux->pldownloader->cond)
5041 g_cond_broadcast (demux->pldownloader->cond);
5043 GST_INFO_OBJECT (demux, "Waiting to acquire download lock");
5044 g_static_rec_mutex_lock (&demux->download_lock);
5045 g_static_rec_mutex_unlock (&demux->download_lock);
5047 GST_INFO_OBJECT (demux, "Waiting download task JOIN");
5048 gst_task_join (demux->download_task);
5049 gst_object_unref (demux->download_task);
5050 demux->download_task = NULL;
5052 GST_INFO_OBJECT (demux, "Completed closing of download task...");
5054 g_thread_join(demux->buffering_posting_thread);
5055 GST_INFO_OBJECT (demux, "Completed closing of download monitor thread...");
5057 if (demux->fdownloader && demux->fdownloader->pipe) {
5058 GST_WARNING_OBJECT (demux, "Still fragment download exist");
5059 gst_hlsdemux2_destroy_fragment_download (demux);
5061 if (demux->pldownloader && demux->pldownloader->pipe) {
5062 GST_WARNING_OBJECT (demux, "Still playlist download exist");
5063 gst_hlsdemux2_destroy_playlist_download (demux);
5065 if (demux->kdownloader && demux->kdownloader->pipe) {
5066 GST_WARNING_OBJECT (demux, "Still key download exist");
5067 gst_hlsdemux2_destroy_key_download (demux);
5071 gst_hlsdemux2_stop_stream (demux);
5073 GST_INFO_OBJECT (demux, "leaving...");
5077 gst_hlsdemux2_stop_stream (GstHLSDemux2 *demux)
5080 GstHLSDemux2Stream *stream = NULL;
5081 gchar *pad_name = NULL;
5083 GST_INFO_OBJECT (demux, "entering");
5085 for (n = 0; n < HLSDEMUX2_STREAM_NUM; n++) {
5086 stream = demux->streams[n];
5088 if (stream && GST_PAD_TASK(stream->pad)) {
5089 pad_name = gst_pad_get_name (stream->pad);
5090 GST_INFO_OBJECT (stream->pad, "stopping pad task : %s", pad_name);
5091 gst_pad_stop_task (stream->pad);
5092 GST_INFO_OBJECT (stream->pad, "stopped pad task : %s", pad_name);
5098 for (n = 0; n < HLSDEMUX2_STREAM_NUM; n++) {
5099 if (demux->streams[n]) {
5100 gst_hlsdemux2_stream_deinit(demux->streams[n], demux);
5101 demux->streams[n] = NULL;
5104 demux->active_stream_cnt = 0;
5105 GST_INFO_OBJECT (demux, "leaving");
5109 gst_hlsdemux2_stream_init (GstHLSDemux2 *demux, GstHLSDemux2Stream *stream, HLSDEMUX2_STREAM_TYPE stream_type, gchar *name, GstCaps *src_caps)
5111 stream->queue = g_queue_new ();
5112 stream->queue_full = g_cond_new ();
5113 stream->queue_empty = g_cond_new ();
5114 stream->queue_lock = g_mutex_new ();
5115 stream->parent = demux;
5116 stream->type = stream_type;
5117 stream->percent = 100;
5118 stream->eos = FALSE;
5119 stream->cached_duration = 0;
5121 stream->dummy_data_thread = NULL;
5122 stream->base_ts = GST_CLOCK_TIME_NONE;
5123 stream->fts = GST_CLOCK_TIME_NONE;
5124 stream->valid_fts_rcvd = FALSE;
5125 stream->total_stream_time = 0;
5126 stream->total_disc = 0;
5128 stream->nts = GST_CLOCK_TIME_NONE;
5129 stream->prev_nts = 0;
5130 stream->downloader_queue = g_queue_new();
5131 stream->need_newsegment = TRUE;
5132 stream->newsegment = NULL;
5133 stream->frame_duration = 0;
5135 if (stream_type == HLSDEMUX2_STREAM_VIDEO) {
5136 stream->pad = gst_pad_new_from_static_template (&hlsdemux2_videosrc_template, name);
5137 GST_INFO_OBJECT (demux, "Its a Multi-variant stream..");
5138 demux->stream_config = HLSDEMUX2_MULTI_VARIANT;
5139 } else if (stream_type == HLSDEMUX2_STREAM_AUDIO) {
5140 stream->pad = gst_pad_new_from_static_template (&hlsdemux2_audiosrc_template, name);
5141 } else if (stream_type == HLSDEMUX2_STREAM_TEXT) {
5142 stream->pad = gst_pad_new_from_static_template (&hlsdemux2_subpicture_template, name);
5143 } else if (stream_type == HLSDEMUX2_STREAM_PRIVATE) {
5144 stream->pad = gst_pad_new_from_static_template (&hlsdemux2_private_template, name);
5147 GST_INFO_OBJECT (demux, "======>>>> created hlsdemux2 source pad : %s", name);
5149 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
5151 gst_pad_use_fixed_caps (stream->pad);
5152 gst_pad_set_event_function (stream->pad, gst_hlsdemux2_handle_src_event);
5153 gst_pad_set_query_function (stream->pad, gst_hlsdemux2_src_query);
5154 gst_pad_set_caps (stream->pad, src_caps);
5156 GST_DEBUG_OBJECT (demux, "adding pad %s %p to demux %p", GST_OBJECT_NAME (stream->pad), stream->pad, demux);
5157 gst_pad_set_active (stream->pad, TRUE);
5158 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
5160 if (!gst_pad_is_linked (stream->pad)) {
5161 GST_WARNING_OBJECT (stream->pad, "'%s' pad is not linked...", GST_OBJECT_NAME (stream->pad));
5162 stream->is_linked = FALSE;
5165 stream->is_linked = TRUE;
5167 if (!gst_pad_start_task (stream->pad, (GstTaskFunction) gst_hlsdemux2_push_loop, stream)) {
5168 GST_ERROR_OBJECT (demux, "failed to create stream task...");
5169 GST_ELEMENT_ERROR (demux, RESOURCE, FAILED, ("failed to create stream push loop"), (NULL));
5176 gst_hlsdemux2_stream_deinit (GstHLSDemux2Stream *stream, gpointer data)
5178 GstHLSDemux2 * demux = (GstHLSDemux2 *)data;
5181 if (stream->queue) {
5182 while (!g_queue_is_empty(stream->queue)) {
5183 gst_buffer_unref (g_queue_pop_head (stream->queue));
5185 g_queue_free (stream->queue);
5186 stream->queue = NULL;
5190 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
5194 if (stream->queue_lock) {
5195 g_mutex_free (stream->queue_lock);
5196 stream->queue_lock = NULL;
5198 if (stream->queue_full) {
5199 g_cond_free (stream->queue_full);
5200 stream->queue_full = NULL;
5202 if (stream->queue_empty) {
5203 g_cond_free (stream->queue_empty);
5204 stream->queue_empty= NULL;
5212 gst_hlsdemux2_set_location (GstHLSDemux2 * demux, const gchar * uri)
5215 gst_m3u8_client_free (demux->client);
5216 demux->client = gst_m3u8_client_new (uri);
5217 GST_INFO_OBJECT (demux, "Changed location: %s", uri);
5222 gst_hlsdemux2_src_buf_to_utf8_playlist (GstBuffer * buf)
5228 data = (gchar *) GST_BUFFER_DATA (buf);
5229 size = GST_BUFFER_SIZE (buf);
5231 #if 0 /* giving error some times, so removing*/
5232 if (!g_utf8_validate (data, size, NULL))
5233 goto validate_error;
5236 /* alloc size + 1 to end with a null character */
5237 playlist = g_malloc0 (size + 1);
5239 GST_ERROR ("failed to create memory...");
5240 gst_buffer_unref (buf);
5244 memcpy (playlist, data, size);
5245 playlist[size] = '\0';
5247 gst_buffer_unref (buf);
5251 gst_buffer_unref (buf);
5252 GST_ERROR ("failed to validate playlist");
5258 gst_hlsdemux2_handle_private_pad (GstHLSDemux2 *demux, GstPad *srcpad)
5260 GstHLSDemux2PvtStream *pvt_stream = NULL;
5261 gchar *sinkname = NULL;
5262 GstPad *sinkpad = NULL;
5264 pvt_stream = g_new0 (GstHLSDemux2PvtStream, 1);
5266 demux->private_stream = pvt_stream;
5267 pvt_stream->parent = demux;
5268 pvt_stream->type = HLSDEMUX2_STREAM_PRIVATE;
5269 pvt_stream->image_buffer = NULL;
5270 pvt_stream->got_img_buffer = FALSE;
5271 pvt_stream->video_buffer = NULL;
5272 pvt_stream->id3_buffer = NULL;
5273 pvt_stream->convert_lock = g_mutex_new ();
5274 pvt_stream->convert_cond = g_cond_new ();
5275 pvt_stream->sink = NULL;
5276 pvt_stream->img_load_lock = g_mutex_new ();
5277 pvt_stream->img_load_cond = g_cond_new ();
5279 /* create sink element */
5280 sinkname = g_strdup_printf("%s-%s", GST_PAD_NAME(srcpad) , "sink");
5281 pvt_stream->sink = gst_element_factory_make ("appsink", NULL);
5282 if (!pvt_stream->sink) {
5283 GST_ERROR_OBJECT (demux, "failed to create sink element - %s", sinkname);
5284 GST_ELEMENT_ERROR (demux, CORE, FAILED, ("failed to create element - %s", sinkname), (NULL));
5290 /* set sink element to PLAYING state */
5291 gst_bin_add (GST_BIN (demux->fdownloader->pipe), pvt_stream->sink);
5292 gst_element_set_state (pvt_stream->sink, GST_STATE_READY);
5293 g_object_set (G_OBJECT (pvt_stream->sink), "sync", FALSE, "emit-signals", TRUE, NULL);
5295 sinkpad = gst_element_get_pad(pvt_stream->sink, "sink");
5297 GST_ERROR_OBJECT (demux, "failed to get sinkpad from element - %s", sinkname);
5298 GST_ELEMENT_ERROR (demux, CORE, PAD, ("Count not get sink pad"), (NULL));
5304 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5305 GST_ERROR_OBJECT (demux, "failed to link sink bin elements");
5306 GST_ELEMENT_ERROR (demux, CORE, NEGOTIATION, ("Could not link pads.."), (NULL));
5307 gst_object_unref(sinkpad);
5310 gst_element_set_state (pvt_stream->sink, GST_STATE_PLAYING);
5312 g_signal_connect (pvt_stream->sink, "new-buffer", G_CALLBACK (gst_hlsdemux2_private_sink_on_new_buffer), pvt_stream);
5313 g_signal_connect (pvt_stream->sink, "eos", G_CALLBACK (gst_hlsdemux2_private_sink_on_eos), pvt_stream);
5315 gst_object_unref(sinkpad);
5317 GST_INFO_OBJECT (demux, "successfully created private pad bin...");
5325 gst_hlsdemux2_private_sink_on_new_buffer (GstElement *appsink, void *user_data)
5327 GstHLSDemux2PvtStream *pvt_stream = (GstHLSDemux2PvtStream *)user_data;
5328 GstHLSDemux2 *demux = pvt_stream->parent;
5329 GstBuffer *inbuf = NULL;
5331 inbuf = gst_app_sink_pull_buffer ((GstAppSink *)appsink);
5333 GST_ERROR_OBJECT (demux, "Input buffer not available....");
5337 GST_LOG_OBJECT (demux, "Image buffer received of size = %d", GST_BUFFER_SIZE (inbuf));
5338 if(pvt_stream->id3_buffer==NULL)
5339 pvt_stream->id3_buffer = gst_buffer_copy(inbuf);
5341 pvt_stream->id3_buffer = gst_buffer_join (pvt_stream->id3_buffer, inbuf);
5346 gst_hlsdemux2_private_sink_on_eos (GstElement * appsink, void* user_data)
5348 GstHLSDemux2PvtStream *pvt_stream = (GstHLSDemux2PvtStream *)user_data;
5349 GstHLSDemux2 *demux = pvt_stream->parent;
5350 GstBuffer *image_buffer = NULL;
5351 GstTagList *tag_list = gst_tag_list_from_id3v2_tag(pvt_stream->id3_buffer);
5353 GST_INFO_OBJECT (demux, "Processing image buffer");
5355 if(!gst_tag_list_get_buffer (tag_list, GST_TAG_IMAGE, &image_buffer)) {
5356 GST_ERROR_OBJECT(demux, "Failed to obtain image data.");
5360 if(demux->stream_config == HLSDEMUX2_SINGLE_VARIANT) {
5361 gchar *image_header = NULL;
5362 GValue codec_type = G_VALUE_INIT;
5363 GstMessage * tag_message = NULL;
5365 /* check whether it is same as previous image */
5366 if (demux->prev_image_buffer &&
5367 (GST_BUFFER_SIZE(demux->prev_image_buffer) == GST_BUFFER_SIZE(image_buffer))) {
5368 if (!memcmp (GST_BUFFER_DATA(demux->prev_image_buffer), GST_BUFFER_DATA(image_buffer), GST_BUFFER_SIZE(image_buffer))) {
5369 GST_INFO_OBJECT (demux, "current & previous embedded images are same..no need to post image again");
5370 gst_buffer_unref (image_buffer);
5375 if (demux->prev_image_buffer) {
5376 gst_buffer_unref (demux->prev_image_buffer);
5378 demux->prev_image_buffer = gst_buffer_copy(image_buffer);
5380 image_header = g_strndup((gchar *) image_buffer->data, 8);
5382 g_value_init (&codec_type, G_TYPE_STRING);
5384 if((image_header[0] == 0xFF) && (image_header[1] == 0xD8)) {
5385 GST_INFO_OBJECT(demux, "Found JPEG image header");
5386 g_value_set_static_string (&codec_type, "image/jpeg");
5387 gst_tag_list_add_value(tag_list, GST_TAG_MERGE_APPEND, GST_TAG_CODEC, &codec_type);
5388 } else if (!g_strcmp0(image_header, "\211PNG\015\012\032\012")) {
5389 GST_INFO_OBJECT(demux, "Found PNG image header");
5390 g_value_set_static_string (&codec_type, "image/png");
5391 gst_tag_list_add_value(tag_list, GST_TAG_MERGE_APPEND, GST_TAG_CODEC, &codec_type);
5393 g_value_set_static_string (&codec_type, "image/unknown");
5394 GST_INFO_OBJECT(demux, "Unknown image header");
5395 gst_tag_list_add_value(tag_list, GST_TAG_MERGE_APPEND, GST_TAG_CODEC, &codec_type);
5398 GST_INFO_OBJECT(demux, "Set value : %s", g_value_get_string (&codec_type));
5399 g_value_unset(&codec_type);
5401 tag_message = gst_message_new_tag (GST_OBJECT_CAST (demux), tag_list);
5402 if(!gst_element_post_message (GST_ELEMENT_CAST (demux), tag_message)) {
5403 GST_ERROR_OBJECT (demux, "failed to post image tag");
5404 gst_buffer_unref (image_buffer);
5405 g_free (image_header);
5409 GST_INFO_OBJECT (demux, "successfully posted image tag...");
5410 gst_buffer_unref (image_buffer);
5411 g_free (image_header);
5415 GST_INFO_OBJECT(demux, "image header : %d,%d", image_buffer->data[0],image_buffer->data[1]);
5417 pvt_stream->image_buffer = gst_buffer_copy(image_buffer);
5418 gst_buffer_unref (image_buffer);
5419 pvt_stream->got_img_buffer = TRUE;
5421 g_cond_signal (pvt_stream->img_load_cond);
5422 demux->has_image_buffer = TRUE;
5427 hlsdemux2_init (GstPlugin * plugin)
5429 if (!gst_element_register (plugin, "hlsdemux2", GST_RANK_PRIMARY + 1, GST_TYPE_HLSDEMUX2) || FALSE)
5434 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
5437 "HLS demux - 2 plugin",
5442 "http://www.samsung.com/")