Initialize Tizen 2.3
[framework/multimedia/gst-plugins-ext0.10.git] / mobile / 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 = NULL;
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     if (buf)
459       gst_buffer_unref (buf);
460     return GST_FLOW_ERROR;
461   }
462 unexpected_eos:
463   {
464     GST_ERROR_OBJECT (src, "Unexpected EOS occured...");
465     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), ("unexpected end of file."));
466     if (buf)
467       gst_buffer_unref (buf);
468     return GST_FLOW_ERROR;
469   }
470 eos:
471   {
472     GST_ERROR_OBJECT (src, "non-regular file hits EOS");
473     if (buf)
474       gst_buffer_unref (buf);
475     return GST_FLOW_UNEXPECTED;
476   }
477 }
478
479 static GstFlowReturn
480 gst_pd_pushsrc_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer)
481 {
482   GST_LOG ("IN");
483
484   GstPDPushSrc *pdsrc;
485   GstFlowReturn ret;
486
487   pdsrc = GST_PD_PUSHSRC_CAST (basesrc);
488   ret = gst_pd_pushsrc_create_read (basesrc, offset, length, buffer);
489   GST_LOG ("OUT");
490
491   return ret;
492 }
493
494 static gboolean
495 gst_pd_pushsrc_query (GstBaseSrc * basesrc, GstQuery * query)
496 {
497   GST_LOG ("IN");
498
499   gboolean ret = FALSE;
500   GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc);
501
502   switch (GST_QUERY_TYPE (query)) {
503     case GST_QUERY_URI:
504       gst_query_set_uri (query, src->uri);
505       ret = TRUE;
506       break;
507     default:
508       ret = FALSE;
509       break;
510   }
511
512   if (!ret)
513     ret = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
514   GST_LOG ("OUT");
515
516   return ret;
517 }
518
519 static gboolean
520 gst_pd_pushsrc_checkgetrange (GstPad * pad)
521 {
522   GST_LOG ("IN");
523
524   GST_LOG ("OUT");
525
526   return FALSE;
527 }
528
529 static gboolean
530 gst_pd_pushsrc_is_seekable (GstBaseSrc * basesrc)
531 {
532   GST_LOG ("IN");
533
534   GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc);
535
536   GST_DEBUG_OBJECT (src, "seekable = %d", src->seekable);
537   GST_LOG ("OUT");
538
539   return src->seekable;
540
541 }
542
543 static gboolean
544 gst_pd_pushsrc_get_size (GstBaseSrc * basesrc, guint64 * size)
545 {
546   GST_LOG ("IN");
547
548   struct stat stat_results;
549   GstPDPushSrc *src;
550
551   src = GST_PD_PUSHSRC (basesrc);
552
553   if (!src->seekable) {
554     /* If it isn't seekable, we won't know the length (but fstat will still
555      * succeed, and wrongly say our length is zero. */
556     return FALSE;
557   }
558
559   if (fstat (src->fd, &stat_results) < 0)
560     goto could_not_stat;
561
562   //*size = stat_results.st_size;
563   /* Naveen : Intentionally, doing this because we dont know the file size...because its keep on increasing in PD case */
564   *size = G_MAXUINT64;
565
566   GST_DEBUG ("size of the file = %"G_GUINT64_FORMAT, *size);
567   
568   GST_LOG ("OUT");
569
570   return TRUE;
571
572   /* ERROR */
573 could_not_stat:
574   {
575     GST_ERROR_OBJECT (src, "Could not stat");
576     return FALSE;
577   }
578 }
579
580 /* open the file, necessary to go to READY state */
581 static gboolean
582 gst_pd_pushsrc_start (GstBaseSrc * basesrc)
583 {
584   GST_LOG ("IN");
585
586   GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc);
587   struct stat stat_results;
588
589   if (src->filename == NULL || src->filename[0] == '\0')
590     goto no_filename;
591
592   GST_INFO_OBJECT (src, "opening file %s", src->filename);
593
594   /* open the file */
595   src->fd = file_open (src->filename, O_RDONLY | O_BINARY, 0);
596
597   if (src->fd < 0)
598     goto open_failed;
599
600   /* check if it is a regular file, otherwise bail out */
601   if (fstat (src->fd, &stat_results) < 0)
602     goto no_stat;
603
604   if (S_ISDIR (stat_results.st_mode))
605     goto was_directory;
606
607   if (S_ISSOCK (stat_results.st_mode))
608     goto was_socket;
609
610   src->read_position = 0;
611
612   /* record if it's a regular (hence seekable and lengthable) file */
613   if (S_ISREG (stat_results.st_mode))
614     src->is_regular = TRUE;
615
616   {
617     /* we need to check if the underlying file is seekable. */
618     off_t res = lseek (src->fd, 0, SEEK_END);
619
620     if (res < 0) {
621       GST_LOG_OBJECT (src, "disabling seeking, not in mmap mode and lseek "
622           "failed: %s", g_strerror (errno));
623       src->seekable = FALSE;
624     } else {
625       src->seekable = TRUE;
626     }
627     lseek (src->fd, 0, SEEK_SET);
628   }
629
630   /* We can only really do seeking on regular files - for other file types, we
631    * don't know their length, so seeking isn't useful/meaningful */
632   src->seekable = src->seekable && src->is_regular;
633   GST_LOG ("OUT");
634
635   return TRUE;
636
637   /* ERROR */
638 no_filename:
639   {
640     GST_ERROR_OBJECT (src, "No file name specified for reading...");
641     GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
642         ("No file name specified for reading."), (NULL));
643     return FALSE;
644   }
645 open_failed:
646   {
647     switch (errno) {
648       case ENOENT:
649         GST_ERROR_OBJECT (src, "File could not be found");
650         GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
651             ("No such file \"\""));
652         break;
653       default:
654         GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
655             ("Could not open file for reading."),
656             GST_ERROR_SYSTEM);
657         break;
658     }
659     return FALSE;
660   }
661 no_stat:
662   {
663     GST_ERROR_OBJECT (src, "Could not get stat info...");       
664     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
665         ("Could not get info on \"\"."),  (NULL));
666     close (src->fd);
667     return FALSE;
668   }
669 was_directory:
670   {
671     GST_ERROR_OBJECT (src, "Is a Directory");
672     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
673         ("\"\" is a directory."), (NULL));
674     close (src->fd);
675     return FALSE;
676   }
677 was_socket:
678   {
679    GST_ERROR_OBJECT (src, "Is a Socket");       
680     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
681         ("File \"\" is a socket."), (NULL));
682     close (src->fd);
683     return FALSE;
684   }
685 }
686
687 /* unmap and close the file */
688 static gboolean
689 gst_pd_pushsrc_stop (GstBaseSrc * basesrc)
690 {
691   GST_LOG ("IN");
692
693   GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc);
694
695   /* close the file */
696   close (src->fd);
697
698   /* zero out a lot of our state */
699   src->fd = 0;
700   src->is_regular = FALSE;
701
702   GST_LOG ("OUT");
703
704   return TRUE;
705 }
706
707 /*** GSTURIHANDLER INTERFACE *************************************************/
708
709 static GstURIType
710 gst_pd_pushsrc_uri_get_type (void)
711 {
712   GST_LOG ("IN");
713   GST_LOG ("OUT");
714
715   return GST_URI_SRC;
716 }
717
718 static gchar **
719 gst_pd_pushsrc_uri_get_protocols (void)
720 {
721   GST_LOG ("IN");
722   static gchar *protocols[] = { (char *) "file", NULL };
723   GST_LOG ("OUT");
724
725   return protocols;
726 }
727
728 static const gchar *
729 gst_pd_pushsrc_uri_get_uri (GstURIHandler * handler)
730 {
731   GST_LOG ("IN");
732   GstPDPushSrc *src = GST_PD_PUSHSRC (handler);
733   GST_LOG ("OUT");
734
735   return src->uri;
736 }
737
738 static gboolean
739 gst_pd_pushsrc_uri_set_uri (GstURIHandler * handler, const gchar * uri)
740 {
741   GST_LOG ("IN");
742
743   gchar *location, *hostname = NULL;
744   gboolean ret = FALSE;
745   GstPDPushSrc *src = GST_PD_PUSHSRC (handler);
746   GError *error = NULL;
747
748   if (strcmp (uri, "file://") == 0) {
749     /* Special case for "file://" as this is used by some applications
750      *  to test with gst_element_make_from_uri if there's an element
751      *  that supports the URI protocol. */
752     gst_pd_pushsrc_set_location (src, NULL);
753     return TRUE;
754   }
755
756   location = g_filename_from_uri (uri, &hostname, &error);
757
758   if (!location || error) {
759     if (error) {
760       GST_WARNING_OBJECT (src, "Invalid URI '%s' for filesrc: %s", uri,
761           error->message);
762       g_error_free (error);
763     } else {
764       GST_WARNING_OBJECT (src, "Invalid URI '%s' for filesrc", uri);
765     }
766     goto beach;
767   }
768
769   if ((hostname) && (strcmp (hostname, "localhost"))) {
770     /* Only 'localhost' is permitted */
771     GST_WARNING_OBJECT (src, "Invalid hostname '%s' for filesrc", hostname);
772     goto beach;
773   }
774 #ifdef G_OS_WIN32
775   /* Unfortunately, g_filename_from_uri() doesn't handle some UNC paths
776    * correctly on windows, it leaves them with an extra backslash
777    * at the start if they're of the mozilla-style file://///host/path/file 
778    * form. Correct this.
779    */
780   if (location[0] == '\\' && location[1] == '\\' && location[2] == '\\')
781     g_memmove (location, location + 1, strlen (location + 1) + 1);
782 #endif
783
784   ret = gst_pd_pushsrc_set_location (src, location);
785
786   GST_LOG ("OUT");
787
788 beach:
789   if (location)
790     g_free (location);
791   if (hostname)
792     g_free (hostname);
793
794   return ret;
795 }
796
797 static void
798 gst_pd_pushsrc_uri_handler_init (gpointer g_iface, gpointer iface_data)
799 {
800   GST_LOG ("IN");
801   GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
802
803   iface->get_type = gst_pd_pushsrc_uri_get_type;
804   iface->get_protocols = gst_pd_pushsrc_uri_get_protocols;
805   iface->get_uri = gst_pd_pushsrc_uri_get_uri;
806   iface->set_uri = gst_pd_pushsrc_uri_set_uri;
807   GST_LOG ("OUT");
808 }
809
810 static gboolean
811 gst_pd_pushsrc_plugin_init (GstPlugin *plugin)
812 {
813     if (!gst_element_register (plugin, "pdpushsrc", GST_RANK_NONE, gst_pd_pushsrc_get_type()))
814     {
815         return FALSE;
816     }
817     return TRUE;
818 }
819
820 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
821                    GST_VERSION_MINOR,
822                    "pdpushsrc",
823                    "PD push source",
824                    gst_pd_pushsrc_plugin_init,
825                    VERSION,
826                    "LGPL",
827                    "Samsung Electronics Co",
828                    "http://www.samsung.com")
829
830