c7c1ad5a1d7acae4684fa2901c375caf0c58e7cb
[framework/multimedia/gst-plugins-ext0.10.git] / pdpushsrc / src / gstpdpushsrc.c
1 /*
2  * pdpushsrc
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Seungbae Shin <seungbae.shin@samsung.com>
7  *
8  * This library is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU Lesser General Public License as published by the
10  * Free Software Foundation; either version 2.1 of the License, or (at your option)
11  * any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but WITHOUT ANY
14  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16  * License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this library; if not, write to the Free Software Foundation, Inc., 51
20  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  *
22  */
23
24
25 #ifdef HAVE_CONFIG_H
26 #  include "config.h"
27 #endif
28
29 #include <gst/gst.h>
30 #include "gstpdpushsrc.h"
31 #include <errno.h>
32 #include <stdio.h>
33 #include <sys/types.h>
34 #ifdef G_OS_WIN32
35 #include <io.h>                 /* lseek, open, close, read */
36 /* On win32, stat* default to 32 bit; we need the 64-bit
37  * variants, so explicitly define it that way. */
38 #define stat __stat64
39 #define fstat _fstat64
40 #undef lseek
41 #define lseek _lseeki64
42 #undef off_t
43 #define off_t guint64
44 /* Prevent stat.h from defining the stat* functions as
45  * _stat*, since we're explicitly overriding that */
46 #undef _INC_STAT_INL
47 #endif
48 #include <sys/stat.h>
49 #include <fcntl.h>
50
51 #ifdef HAVE_UNISTD_H
52 #  include <unistd.h>
53 #endif
54
55 #include <errno.h>
56 #include <string.h>
57
58 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
59     GST_PAD_SRC,
60     GST_PAD_ALWAYS,
61     GST_STATIC_CAPS_ANY);
62
63 /* FIXME we should be using glib for this */
64 #ifndef S_ISREG
65 #define S_ISREG(mode) ((mode)&_S_IFREG)
66 #endif
67 #ifndef S_ISDIR
68 #define S_ISDIR(mode) ((mode)&_S_IFDIR)
69 #endif
70 #ifndef S_ISSOCK
71 #define S_ISSOCK(x) (0)
72 #endif
73 #ifndef O_BINARY
74 #define O_BINARY (0)
75 #endif
76
77 static int
78 file_open (const gchar * filename, int flags, int mode)
79 {
80   return open (filename, flags, mode);
81 }
82
83 GST_DEBUG_CATEGORY_STATIC (gst_pd_pushsrc_debug);
84 #define GST_CAT_DEFAULT gst_pd_pushsrc_debug
85
86 /* FileSrc signals and args */
87 enum
88 {
89   /* FILL ME */
90   LAST_SIGNAL
91 };
92
93 #define DEFAULT_BLOCKSIZE       4*1024
94
95 enum
96 {
97   ARG_0,
98   ARG_LOCATION,
99   ARG_EOS,
100 };
101
102 static void gst_pd_pushsrc_finalize (GObject * object);
103
104 static void gst_pd_pushsrc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec);
105 static void gst_pd_pushsrc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec);
106
107 static gboolean gst_pd_pushsrc_start (GstBaseSrc * basesrc);
108 static gboolean gst_pd_pushsrc_stop (GstBaseSrc * basesrc);
109
110 static gboolean gst_pd_pushsrc_is_seekable (GstBaseSrc * src);
111 static gboolean gst_pd_pushsrc_get_size (GstBaseSrc * src, guint64 * size);
112 static gboolean gst_pd_pushsrc_query (GstBaseSrc * src, GstQuery * query);
113 static void gst_pd_pushsrc_uri_handler_init (gpointer g_iface, gpointer iface_data);
114 static GstFlowReturn gst_pd_pushsrc_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer);
115 static gboolean gst_pd_pushsrc_checkgetrange (GstPad * pad);
116
117 static void
118 _do_init (GType pd_pushsrc_type)
119 {
120   static const GInterfaceInfo urihandler_info = {
121     gst_pd_pushsrc_uri_handler_init,
122     NULL,
123     NULL
124   };
125
126   g_type_add_interface_static (pd_pushsrc_type, GST_TYPE_URI_HANDLER, &urihandler_info);
127   GST_DEBUG_CATEGORY_INIT (gst_pd_pushsrc_debug, "pdpushsrc", 0, "PD push source element");
128 }
129
130 GST_BOILERPLATE_FULL (GstPDPushSrc, gst_pd_pushsrc, GstBaseSrc, GST_TYPE_BASE_SRC, _do_init);
131
132 static void
133 gst_pd_pushsrc_base_init (gpointer g_class)
134 {
135   GST_LOG ("IN");
136
137   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
138
139   gst_element_class_set_details_simple (gstelement_class,
140       "PD push source",
141       "Source/File",
142       "Read from arbitrary point in a file",
143       "Naveen Ch <naveen.ch@samsung.com>");
144   gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&srctemplate));
145
146   GST_LOG ("OUT");
147 }
148
149 static void
150 gst_pd_pushsrc_class_init (GstPDPushSrcClass * klass)
151 {
152   GST_LOG ("IN");
153
154   GObjectClass *gobject_class;
155   GstBaseSrcClass *gstbasesrc_class;
156
157   gobject_class = G_OBJECT_CLASS (klass);
158   gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
159
160   gobject_class->set_property = gst_pd_pushsrc_set_property;
161   gobject_class->get_property = gst_pd_pushsrc_get_property;
162   gobject_class->finalize = gst_pd_pushsrc_finalize;
163
164   g_object_class_install_property (gobject_class, ARG_LOCATION,
165       g_param_spec_string ("location", "File Location",
166           "Location of the file to read", NULL,
167           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
168           GST_PARAM_MUTABLE_READY));
169    
170     g_object_class_install_property (gobject_class, ARG_EOS,
171                                     g_param_spec_boolean ("eos",
172                                         "EOS recived on downloading pipeline",
173                                         "download of clip is over",
174                                         0,
175                                         G_PARAM_READWRITE));
176    
177   gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_start);
178   gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_stop);
179   gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_is_seekable);
180   gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_get_size);
181   gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_query);
182   gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_create);
183
184   if (sizeof (off_t) < 8) {
185     GST_LOG ("No large file support, sizeof (off_t) = %" G_GSIZE_FORMAT "!",
186         sizeof (off_t));
187   }
188
189   GST_LOG ("OUT");
190  
191 }
192
193 static void
194 gst_pd_pushsrc_init (GstPDPushSrc * src, GstPDPushSrcClass * g_class)
195 {
196   GST_LOG ("IN");
197   GstBaseSrc *basesrc = GST_BASE_SRC (src);
198
199   src->filename = NULL;
200   src->fd = 0;
201   src->uri = NULL;
202   src->is_regular = FALSE;
203   src->is_eos = FALSE;
204   
205   gst_pad_set_checkgetrange_function (basesrc->srcpad, GST_DEBUG_FUNCPTR (gst_pd_pushsrc_checkgetrange));
206
207   GST_LOG ("OUT");
208 }
209
210 static void
211 gst_pd_pushsrc_finalize (GObject * object)
212 {
213   GST_LOG ("IN");
214
215   GstPDPushSrc *src;
216
217   src = GST_PD_PUSHSRC (object);
218
219   g_free (src->filename);
220   g_free (src->uri);
221
222   G_OBJECT_CLASS (parent_class)->finalize (object);
223
224   GST_LOG ("OUT");
225 }
226
227 static gboolean
228 gst_pd_pushsrc_set_location (GstPDPushSrc * src, const gchar * location)
229 {
230   GST_LOG ("IN");
231
232   GstState state;
233
234   /* the element must be stopped in order to do this */
235   GST_OBJECT_LOCK (src);
236   state = GST_STATE (src);
237   if (state != GST_STATE_READY && state != GST_STATE_NULL)
238     goto wrong_state;
239   GST_OBJECT_UNLOCK (src);
240
241   g_free (src->filename);
242   g_free (src->uri);
243
244   /* clear the filename if we get a NULL (is that possible?) */
245   if (location == NULL) {
246     src->filename = NULL;
247     src->uri = NULL;
248   } else {
249     /* we store the filename as received by the application. On Windows this
250      * should be UTF8 */
251     src->filename = g_strdup (location);
252     src->uri = gst_filename_to_uri (location, NULL);
253     GST_INFO ("filename : %s", src->filename);
254     GST_INFO ("uri      : %s", src->uri);
255   }
256   g_object_notify (G_OBJECT (src), "location");
257   gst_uri_handler_new_uri (GST_URI_HANDLER (src), src->uri);
258   
259   GST_LOG ("OUT");
260
261   return TRUE;
262
263   /* ERROR */
264 wrong_state:
265   {
266     g_warning ("Changing the `location' property on filesrc when a file is "
267         "open is not supported.");
268     GST_OBJECT_UNLOCK (src);
269     GST_LOG ("OUT :: wrong_state");
270     return FALSE;
271   }
272 }
273
274 static void
275 gst_pd_pushsrc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
276 {
277   GST_LOG ("IN");
278
279   GstPDPushSrc *src;
280
281   g_return_if_fail (GST_IS_PD_PUSHSRC (object));
282
283   src = GST_PD_PUSHSRC (object);
284
285   switch (prop_id) {
286     case ARG_LOCATION:
287       gst_pd_pushsrc_set_location (src, g_value_get_string (value));
288       break;
289     case ARG_EOS:
290       src->is_eos = g_value_get_boolean (value);
291       g_print ("\n\n\nis_eos is becoming %d\n\n\n", src->is_eos);
292       break;
293     default:
294       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
295       break;
296   }
297   GST_LOG ("OUT");
298 }
299
300 static void
301 gst_pd_pushsrc_get_property (GObject * object, guint prop_id, GValue * value,
302     GParamSpec * pspec)
303 {
304   GST_LOG ("IN");
305   GstPDPushSrc *src;
306
307   g_return_if_fail (GST_IS_PD_PUSHSRC (object));
308
309   src = GST_PD_PUSHSRC (object);
310
311   switch (prop_id) {
312     case ARG_LOCATION:
313       g_value_set_string (value, src->filename);
314       break;
315     case ARG_EOS:
316       g_value_set_boolean (value, src->is_eos);
317       break;
318     default:
319       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
320       break;
321   }
322   GST_LOG ("OUT");
323 }
324
325 static GstFlowReturn
326 gst_pd_pushsrc_create_read (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer)
327 {
328   GST_LOG ("IN");
329
330   int ret;
331   GstBuffer *buf;
332   struct stat stat_results;
333   GstPDPushSrc *src;
334
335   src = GST_PD_PUSHSRC_CAST (basesrc);
336   
337   GST_LOG_OBJECT (src, "read position = %"G_GUINT64_FORMAT ", offset = %"G_GUINT64_FORMAT", length = %d", 
338         src->read_position, offset, length);
339   
340   memset (&stat_results, 0, sizeof (stat_results));
341   
342   if (fstat (src->fd, &stat_results) < 0)
343     goto could_not_stat;
344
345   GST_LOG_OBJECT (src, "offset + length = %"G_GUINT64_FORMAT " and filesize = %"G_GUINT64_FORMAT, offset + length, stat_results.st_size);
346
347   while ((offset + length) > stat_results.st_size)
348   {
349     fd_set fds;
350     int ret;
351     struct timeval timeout = {0,};
352     guint64 avail_size = 0;
353
354     if (src->is_eos)
355         goto eos;
356
357     FD_ZERO (&fds);
358     FD_SET (src->fd, &fds);
359
360     timeout.tv_sec = 0;
361     timeout.tv_usec = ((basesrc->blocksize * 8 * 1000) / 64000); // wait_time = (blocksize * 8) / (min downloadratei.e. 64Kbps)
362
363     GST_DEBUG_OBJECT (src, "Going to wait for %ld msec", timeout.tv_usec);
364
365     ret = select (src->fd + 1, &fds, NULL, NULL, &timeout);
366     if (-1 == ret) 
367     {
368       GST_ERROR_OBJECT (src, "ERROR in select () : reason - %s...\n", strerror(errno));
369       return GST_FLOW_ERROR;
370     }
371     else if (0 == ret)
372     {
373       GST_WARNING_OBJECT (src, "select () timeout happened...");
374     }
375     else
376     {
377       memset (&stat_results, 0, sizeof (stat_results));
378   
379       if (fstat (src->fd, &stat_results) < 0)
380         goto could_not_stat;
381
382       avail_size = stat_results.st_size;
383
384       GST_LOG_OBJECT (src, "Available data size in file = %"G_GUINT64_FORMAT, avail_size);
385
386       if ((offset + length) > avail_size)
387       {
388         GST_LOG_OBJECT (src, "Enough data is NOT available...");
389       }
390       else
391       {
392         GST_LOG_OBJECT (src, "Enough data is available...");
393       }
394     }
395   }
396
397   if (G_UNLIKELY (src->read_position != offset)) {
398     off_t res;
399
400     res = lseek (src->fd, offset, SEEK_SET);
401     if (G_UNLIKELY (res < 0 || res != offset))
402       goto seek_failed;
403     src->read_position = offset;
404   }
405   
406   buf = gst_buffer_try_new_and_alloc (length);
407   if (G_UNLIKELY (buf == NULL && length > 0)) {
408     GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", length);
409     return GST_FLOW_ERROR;
410   }
411
412   /* No need to read anything if length is 0 */
413   if (length > 0) {
414     GST_LOG_OBJECT (src, "Reading %d bytes at offset 0x%" G_GINT64_MODIFIER "x",
415         length, offset);
416     ret = read (src->fd, GST_BUFFER_DATA (buf), length);
417     if (G_UNLIKELY (ret < 0))
418       goto could_not_read;
419
420     /* seekable regular files should have given us what we expected */
421     if (G_UNLIKELY ((guint) ret < length && src->seekable))
422       goto unexpected_eos;
423
424     /* other files should eos if they read 0 and more was requested */
425     if (G_UNLIKELY (ret == 0 && length > 0))
426       goto eos;
427
428     length = ret;
429     GST_BUFFER_SIZE (buf) = length;
430     GST_BUFFER_OFFSET (buf) = offset;
431     GST_BUFFER_OFFSET_END (buf) = offset + length;
432
433     src->read_position += length;
434   }
435
436   *buffer = buf;
437   GST_LOG ("OUT");
438
439   return GST_FLOW_OK;
440
441   /* ERROR */
442 seek_failed:
443   {
444     GST_ERROR_OBJECT (src, "Seek failed...");
445     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
446     return GST_FLOW_ERROR;
447   }
448 could_not_stat:
449   {
450     GST_ERROR_OBJECT (src, "Could not stat");
451     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
452     return GST_FLOW_ERROR;
453   }
454 could_not_read:
455   {
456     GST_ERROR_OBJECT (src, "Could not read...");
457     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
458     gst_buffer_unref (buf);
459     return GST_FLOW_ERROR;
460   }
461 unexpected_eos:
462   {
463     GST_ERROR_OBJECT (src, "Unexpected EOS occured...");
464     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
465         ("unexpected end of file."));
466     gst_buffer_unref (buf);
467     return GST_FLOW_ERROR;
468   }
469 eos:
470   {
471     GST_ERROR_OBJECT (src, "non-regular file hits EOS");
472     gst_buffer_unref (buf);
473     return GST_FLOW_UNEXPECTED;
474   }
475 }
476
477 static GstFlowReturn
478 gst_pd_pushsrc_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer)
479 {
480   GST_LOG ("IN");
481
482   GstPDPushSrc *pdsrc;
483   GstFlowReturn ret;
484
485   pdsrc = GST_PD_PUSHSRC_CAST (basesrc);
486   ret = gst_pd_pushsrc_create_read (basesrc, offset, length, buffer);
487   GST_LOG ("OUT");
488
489   return ret;
490 }
491
492 static gboolean
493 gst_pd_pushsrc_query (GstBaseSrc * basesrc, GstQuery * query)
494 {
495   GST_LOG ("IN");
496
497   gboolean ret = FALSE;
498   GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc);
499
500   switch (GST_QUERY_TYPE (query)) {
501     case GST_QUERY_URI:
502       gst_query_set_uri (query, src->uri);
503       ret = TRUE;
504       break;
505     default:
506       ret = FALSE;
507       break;
508   }
509
510   if (!ret)
511     ret = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
512   GST_LOG ("OUT");
513
514   return ret;
515 }
516
517 static gboolean
518 gst_pd_pushsrc_checkgetrange (GstPad * pad)
519 {
520   GST_LOG ("IN");
521
522   GST_LOG ("OUT");
523
524   return FALSE;
525 }
526
527 static gboolean
528 gst_pd_pushsrc_is_seekable (GstBaseSrc * basesrc)
529 {
530   GST_LOG ("IN");
531
532   GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc);
533
534   GST_DEBUG_OBJECT (src, "seekable = %d", src->seekable);
535   GST_LOG ("OUT");
536
537   return src->seekable;
538
539 }
540
541 static gboolean
542 gst_pd_pushsrc_get_size (GstBaseSrc * basesrc, guint64 * size)
543 {
544   GST_LOG ("IN");
545
546   struct stat stat_results;
547   GstPDPushSrc *src;
548
549   src = GST_PD_PUSHSRC (basesrc);
550
551   if (!src->seekable) {
552     /* If it isn't seekable, we won't know the length (but fstat will still
553      * succeed, and wrongly say our length is zero. */
554     return FALSE;
555   }
556
557   if (fstat (src->fd, &stat_results) < 0)
558     goto could_not_stat;
559
560   //*size = stat_results.st_size;
561   /* Naveen : Intentionally, doing this because we dont know the file size...because its keep on increasing in PD case */
562   *size = G_MAXUINT64;
563
564   GST_DEBUG ("size of the file = %"G_GUINT64_FORMAT, *size);
565   
566   GST_LOG ("OUT");
567
568   return TRUE;
569
570   /* ERROR */
571 could_not_stat:
572   {
573     GST_ERROR_OBJECT (src, "Could not stat");
574     return FALSE;
575   }
576 }
577
578 /* open the file, necessary to go to READY state */
579 static gboolean
580 gst_pd_pushsrc_start (GstBaseSrc * basesrc)
581 {
582   GST_LOG ("IN");
583
584   GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc);
585   struct stat stat_results;
586
587   if (src->filename == NULL || src->filename[0] == '\0')
588     goto no_filename;
589
590   GST_INFO_OBJECT (src, "opening file %s", src->filename);
591
592   /* open the file */
593   src->fd = file_open (src->filename, O_RDONLY | O_BINARY, 0);
594
595   if (src->fd < 0)
596     goto open_failed;
597
598   /* check if it is a regular file, otherwise bail out */
599   if (fstat (src->fd, &stat_results) < 0)
600     goto no_stat;
601
602   if (S_ISDIR (stat_results.st_mode))
603     goto was_directory;
604
605   if (S_ISSOCK (stat_results.st_mode))
606     goto was_socket;
607
608   src->read_position = 0;
609
610   /* record if it's a regular (hence seekable and lengthable) file */
611   if (S_ISREG (stat_results.st_mode))
612     src->is_regular = TRUE;
613
614   {
615     /* we need to check if the underlying file is seekable. */
616     off_t res = lseek (src->fd, 0, SEEK_END);
617
618     if (res < 0) {
619       GST_LOG_OBJECT (src, "disabling seeking, not in mmap mode and lseek "
620           "failed: %s", g_strerror (errno));
621       src->seekable = FALSE;
622     } else {
623       src->seekable = TRUE;
624     }
625     lseek (src->fd, 0, SEEK_SET);
626   }
627
628   /* We can only really do seeking on regular files - for other file types, we
629    * don't know their length, so seeking isn't useful/meaningful */
630   src->seekable = src->seekable && src->is_regular;
631   GST_LOG ("OUT");
632
633   return TRUE;
634
635   /* ERROR */
636 no_filename:
637   {
638     GST_ERROR_OBJECT (src, "No file name specified for reading...");
639     GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
640         ("No file name specified for reading."), (NULL));
641     return FALSE;
642   }
643 open_failed:
644   {
645     switch (errno) {
646       case ENOENT:
647         GST_ERROR_OBJECT (src, "File could not be found");
648         GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
649             ("No such file \"\""));
650         break;
651       default:
652         GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
653             ("Could not open file for reading."),
654             GST_ERROR_SYSTEM);
655         break;
656     }
657     return FALSE;
658   }
659 no_stat:
660   {
661     GST_ERROR_OBJECT (src, "Could not get stat info...");       
662     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
663         ("Could not get info on \"\"."),  (NULL));
664     close (src->fd);
665     return FALSE;
666   }
667 was_directory:
668   {
669     GST_ERROR_OBJECT (src, "Is a Directory");
670     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
671         ("\"\" is a directory."), (NULL));
672     close (src->fd);
673     return FALSE;
674   }
675 was_socket:
676   {
677    GST_ERROR_OBJECT (src, "Is a Socket");       
678     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
679         ("File \"\" is a socket."), (NULL));
680     close (src->fd);
681     return FALSE;
682   }
683 }
684
685 /* unmap and close the file */
686 static gboolean
687 gst_pd_pushsrc_stop (GstBaseSrc * basesrc)
688 {
689   GST_LOG ("IN");
690
691   GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc);
692
693   /* close the file */
694   close (src->fd);
695
696   /* zero out a lot of our state */
697   src->fd = 0;
698   src->is_regular = FALSE;
699
700   GST_LOG ("OUT");
701
702   return TRUE;
703 }
704
705 /*** GSTURIHANDLER INTERFACE *************************************************/
706
707 static GstURIType
708 gst_pd_pushsrc_uri_get_type (void)
709 {
710   GST_LOG ("IN");
711   GST_LOG ("OUT");
712
713   return GST_URI_SRC;
714 }
715
716 static gchar **
717 gst_pd_pushsrc_uri_get_protocols (void)
718 {
719   GST_LOG ("IN");
720   static gchar *protocols[] = { (char *) "file", NULL };
721   GST_LOG ("OUT");
722
723   return protocols;
724 }
725
726 static const gchar *
727 gst_pd_pushsrc_uri_get_uri (GstURIHandler * handler)
728 {
729   GST_LOG ("IN");
730   GstPDPushSrc *src = GST_PD_PUSHSRC (handler);
731   GST_LOG ("OUT");
732
733   return src->uri;
734 }
735
736 static gboolean
737 gst_pd_pushsrc_uri_set_uri (GstURIHandler * handler, const gchar * uri)
738 {
739   GST_LOG ("IN");
740
741   gchar *location, *hostname = NULL;
742   gboolean ret = FALSE;
743   GstPDPushSrc *src = GST_PD_PUSHSRC (handler);
744   GError *error = NULL;
745
746   if (strcmp (uri, "file://") == 0) {
747     /* Special case for "file://" as this is used by some applications
748      *  to test with gst_element_make_from_uri if there's an element
749      *  that supports the URI protocol. */
750     gst_pd_pushsrc_set_location (src, NULL);
751     return TRUE;
752   }
753
754   location = g_filename_from_uri (uri, &hostname, &error);
755
756   if (!location || error) {
757     if (error) {
758       GST_WARNING_OBJECT (src, "Invalid URI '%s' for filesrc: %s", uri,
759           error->message);
760       g_error_free (error);
761     } else {
762       GST_WARNING_OBJECT (src, "Invalid URI '%s' for filesrc", uri);
763     }
764     goto beach;
765   }
766
767   if ((hostname) && (strcmp (hostname, "localhost"))) {
768     /* Only 'localhost' is permitted */
769     GST_WARNING_OBJECT (src, "Invalid hostname '%s' for filesrc", hostname);
770     goto beach;
771   }
772 #ifdef G_OS_WIN32
773   /* Unfortunately, g_filename_from_uri() doesn't handle some UNC paths
774    * correctly on windows, it leaves them with an extra backslash
775    * at the start if they're of the mozilla-style file://///host/path/file 
776    * form. Correct this.
777    */
778   if (location[0] == '\\' && location[1] == '\\' && location[2] == '\\')
779     g_memmove (location, location + 1, strlen (location + 1) + 1);
780 #endif
781
782   ret = gst_pd_pushsrc_set_location (src, location);
783
784   GST_LOG ("OUT");
785
786 beach:
787   if (location)
788     g_free (location);
789   if (hostname)
790     g_free (hostname);
791
792   return ret;
793 }
794
795 static void
796 gst_pd_pushsrc_uri_handler_init (gpointer g_iface, gpointer iface_data)
797 {
798   GST_LOG ("IN");
799   GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
800
801   iface->get_type = gst_pd_pushsrc_uri_get_type;
802   iface->get_protocols = gst_pd_pushsrc_uri_get_protocols;
803   iface->get_uri = gst_pd_pushsrc_uri_get_uri;
804   iface->set_uri = gst_pd_pushsrc_uri_set_uri;
805   GST_LOG ("OUT");
806 }
807
808 static gboolean
809 gst_pd_pushsrc_plugin_init (GstPlugin *plugin)
810 {
811     if (!gst_element_register (plugin, "pdpushsrc", GST_RANK_PRIMARY, gst_pd_pushsrc_get_type()))
812     {
813         return FALSE;
814     }
815     return TRUE;
816 }
817
818 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
819                    GST_VERSION_MINOR,
820                    "pdpushsrc",
821                    "PD push source",
822                    gst_pd_pushsrc_plugin_init,
823                    VERSION,
824                    "LGPL",
825                    "Samsung Electronics Co",
826                    "http://www.samsung.com")
827
828