Initialize Tizen 2.3
[framework/multimedia/gst-plugins-ext0.10.git] / mobile / drmsrc / src / gstdrmsrc.c
1 /*
2  * drmsrc
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: JongHyuk Choi <jhchoi.choi@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 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 #include "gstdrmsrc.h"
28
29 #define LOG_TRACE(message)  //g_print("DRM_SRC: %s: %d: %s - %s \n", __FILE__, __LINE__, __FUNCTION__, message);
30
31 #define GST_TAG_PLAYREADY "playready_file_path"
32
33 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,GST_STATIC_CAPS_ANY);
34
35
36 GST_DEBUG_CATEGORY_STATIC (gst_drm_src_debug);
37 #define GST_CAT_DEFAULT gst_drm_src_debug
38
39 enum
40 {
41         ARG_0,
42         ARG_LOCATION,
43         ARG_FD
44 };
45 static void gst_drm_src_finalize (GObject * object);
46 static void gst_drm_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec);
47 static void gst_drm_src_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec);
48 static gboolean gst_drm_src_start (GstBaseSrc * basesrc);
49 static gboolean gst_drm_src_stop (GstBaseSrc * basesrc);
50 static gboolean gst_drm_src_is_seekable (GstBaseSrc * src);
51 static gboolean gst_drm_src_get_size (GstBaseSrc * src, guint64 * size);
52 static GstFlowReturn gst_drm_src_create (GstBaseSrc * src, guint64 offset, guint length, GstBuffer ** buffer);
53 static void gst_drm_src_uri_handler_init (gpointer g_iface, gpointer iface_data);
54
55 /**
56  * This function does the following:
57  *  1. Initializes GstDrmSrc ( defines gst_drm_get_type)
58  *
59  * @param   drmsrc_type    [out]  GType
60  *
61  * @return  void
62  */
63 static void _do_init (GType drmsrc_type)
64 {
65        // 1. Initializes GstDrmSrc ( defines gst_drm_get_type)
66         static const GInterfaceInfo urihandler_info = {
67                 gst_drm_src_uri_handler_init,
68                 NULL,
69                 NULL
70         };
71
72         g_type_add_interface_static (drmsrc_type, GST_TYPE_URI_HANDLER, &urihandler_info);
73         GST_DEBUG_CATEGORY_INIT (gst_drm_src_debug, "drmsrc", 0, "drmsrc element");
74 }
75 GST_BOILERPLATE_FULL (GstDrmSrc, gst_drm_src, GstBaseSrc, GST_TYPE_BASE_SRC,   _do_init);
76 /**
77  * This function does the following:
78  *  1. Sets the class details
79  *  2. Adds the source pad template
80  *
81  * @param   g_class    [out]   gpointer
82  *
83  * @return  void
84  */
85 static void gst_drm_src_base_init (gpointer g_class)
86 {
87         GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
88         // 1. Sets the class details
89         gst_element_class_set_details_simple (gstelement_class,
90                 "DRM Source",
91                 "Source/File",
92                 "Read from arbitrary point in a standard/DRM file",
93                 "Kishore Arepalli  <kishore.a@samsung.com> and Sadanand Dodawadakar <sadanand.d@samsung.com>");
94       // 2. Adds the source pad template
95         gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&srctemplate));
96 }
97 /**
98  * This function does the following:
99  *  1. Installs the properties
100  *  2. Assigns the function pointers GObject class attributes
101  *
102  * @param   klass    [out]   GstDrmSrcClass Structure
103  *
104  * @return  void
105  */
106 static void gst_drm_src_class_init (GstDrmSrcClass * klass)
107 {
108         GObjectClass *gobject_class;
109         GstBaseSrcClass *gstbasesrc_class;
110         gobject_class = G_OBJECT_CLASS (klass);
111         gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
112         // Assigns the function pointers GObject class attributes
113         gobject_class->set_property = gst_drm_src_set_property;
114         gobject_class->get_property = gst_drm_src_get_property;
115         //  1. Installs the properties
116         g_object_class_install_property (gobject_class, ARG_FD,
117                 g_param_spec_int ("fd", "File-descriptor",
118                 "File-descriptor for the file being mmap()d", 0, G_MAXINT, 0,
119                 G_PARAM_READABLE));
120         g_object_class_install_property (gobject_class, ARG_LOCATION,
121                 g_param_spec_string ("location", "File Location",
122                 "Location of the file to read", NULL, G_PARAM_READWRITE));
123
124         // 2. Assigns the function pointers GObject class attributes
125         gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_drm_src_finalize);
126         gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_drm_src_start);
127         gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_drm_src_stop);
128         gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_drm_src_is_seekable);
129         gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_drm_src_get_size);
130         gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_drm_src_create);
131
132
133         gst_tag_register (GST_TAG_PLAYREADY, GST_TAG_FLAG_META,
134                         G_TYPE_STRING,
135                         "PlayReady File Path",
136                         "a tag that is specific to PlayReady File",
137                         NULL);
138 }
139 /**
140  * This function does the following:
141  *  1. Initilizes the parameters of GstDrmSrc
142  *
143  * @param   src    [out]   GstDrmSrc structure
144  * @param   g_class    [in]   GstDrmSrcClass structure
145  *
146  * @return  gboolean   Returns TRUE on success and FALSE on ERROR
147  */
148 static void gst_drm_src_init (GstDrmSrc * src, GstDrmSrcClass * g_class)
149 {
150         // 1. Initilizes the parameters of GstDrmSrc
151         src->filename = NULL;
152         src->fd = 0;
153         src->uri = NULL;
154         src->is_regular = FALSE;
155         src->seekable = FALSE;
156         PROFILE_INIT;
157 }
158 /**
159  * This function does the following:
160  *  1. deallocates the filename and uri
161  *  2. calls the parent class->finalize
162  *
163  * @param   object    [in]   GObject Structure
164  *
165  * @return  void
166  */
167 static void gst_drm_src_finalize (GObject * object)
168 {
169         GstDrmSrc *src;
170
171         src = GST_DRM_SRC (object);
172         //  1. deallocates the filename and uri
173         g_free (src->filename);
174         g_free (src->uri);
175         // 2. calls the parent class->finalize
176         G_OBJECT_CLASS (parent_class)->finalize (object);
177 }
178 /**
179  * This function does the following:
180  *  1. Checks the state
181  *  2. Checks the filename
182  *  3. Sets the filename
183  *
184  * @param   src    [in]   GstDrmSrc Structure
185  * @param   location    [in]   location of the file
186  *
187  * @return  gboolean   Returns TRUE on success and FALSE on ERROR
188  */
189 static gboolean gst_drm_src_set_location (GstDrmSrc * src, const gchar * location)
190 {
191         GstState state;
192
193         GST_OBJECT_LOCK (src);
194         //  1. Checks the state
195         state = GST_STATE (src);
196         if (state != GST_STATE_READY && state != GST_STATE_NULL)
197         {
198                 GST_DEBUG_OBJECT (src, "setting location in wrong state");
199                 GST_OBJECT_UNLOCK (src);
200                 return FALSE;
201         }
202         GST_OBJECT_UNLOCK (src);
203         g_free (src->filename);
204         g_free (src->uri);
205         //  2. Checks the filename
206         if (location == NULL)
207         {
208                 src->filename = NULL;
209                 src->uri = NULL;
210         }
211         else
212         {
213                 // 3. Sets the filename
214                 src->filename = g_strdup (location);
215                 src->uri = gst_uri_construct ("file", src->filename);
216         }
217         g_object_notify (G_OBJECT (src), "location");
218         gst_uri_handler_new_uri (GST_URI_HANDLER (src), src->uri);
219         return TRUE;
220 }
221 /**
222  * This function does the following:
223  *  1. Sets the location of the file.
224  *
225  * @param   object    [in]   GObject Structure
226  * @param   prop_id    [in]   id of the property
227  * @param   value    [in]   property value
228  * @param   pspec    [in]  GParamSpec Structure
229  *
230  * @return  void
231  */
232 static void gst_drm_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
233 {
234         GstDrmSrc *src;
235
236         g_return_if_fail (GST_IS_DRM_SRC (object));
237         src = GST_DRM_SRC (object);
238         switch (prop_id)
239         {
240                 //  1. Sets the location of the file.
241                 case ARG_LOCATION:
242                         gst_drm_src_set_location (src, g_value_get_string (value));
243                         break;
244                 default:
245                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
246                         break;
247         }
248 }
249 /**
250  * This function does the following:
251  *  1. Provides the location of the file.
252  *  2. Provides the file descriptor.
253  *
254  * @param   object    [in]   GObject Structure
255  * @param   prop_id    [in]   id of the property
256  * @param   value    [out]   property value
257  * @param   pspec    [in]  GParamSpec Structure
258  *
259  * @return  void
260  */
261 static void gst_drm_src_get_property (GObject * object, guint prop_id, GValue * value,GParamSpec * pspec)
262 {
263         GstDrmSrc *src;
264
265         g_return_if_fail (GST_IS_DRM_SRC (object));
266         src = GST_DRM_SRC (object);
267         switch (prop_id)
268         {
269                 //  1. Provides the location of the file.
270                 case ARG_LOCATION:
271                         g_value_set_string (value, src->filename);
272                         break;
273                 // 2. Provides the file descriptor.
274                 case ARG_FD:
275                         g_value_set_int (value, src->fd);
276                         break;
277                 default:
278                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
279                         break;
280         }
281 }
282
283 /**
284  * This function does the following:
285  *  1. Seeks to the specified position.
286  *  2. Allocates a buffer to push the data
287  *  3. Reads from the file and sets the related params
288  *
289  * @param   src    [in]   GstDrmSrc Structure
290  * @param   offset    [in]   offset of the file to seek
291  * @param   length    [in]   size of the data in bytes
292  * @param   buffer    [out]   GstBuffer to hold the contents
293  *
294  * @return  GstFlowReturn   Returns GST_FLOW_OK on success and ERROR on failure
295  */
296 static GstFlowReturn gst_drm_src_create_read (GstDrmSrc * src, guint64 offset, guint length, GstBuffer ** buffer)
297 {
298         int ret;
299         GstBuffer *buf;
300         // 1. Seeks to the specified position.
301         if (G_UNLIKELY (src->read_position != offset))
302         {
303                 off_t res;
304                 res = lseek (src->fd, offset, SEEK_SET);
305                 if (G_UNLIKELY (res < 0 || res != offset))
306                 {
307                         GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
308                         return GST_FLOW_ERROR;
309                 }
310                 src->read_position = offset;
311         }
312         // 2. Allocates a buffer to push the data
313         buf = gst_buffer_new_and_alloc (length);
314         GST_LOG_OBJECT (src, "Reading %d bytes", length);
315         // 3. Reads from the file and sets the related params
316         ret = read (src->fd, GST_BUFFER_DATA (buf), length);
317         if (G_UNLIKELY (ret < 0))
318         {
319                 GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
320                 gst_buffer_unref (buf);
321                 return GST_FLOW_ERROR;
322         }
323         if (G_UNLIKELY ((guint) ret < length && src->seekable))
324         {
325                 GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),("unexpected end of file."));
326                 gst_buffer_unref (buf);
327                 return GST_FLOW_ERROR;
328         }
329         if (G_UNLIKELY (ret == 0 && length > 0))
330         {
331                 GST_DEBUG ("non-regular file hits EOS");
332                 gst_buffer_unref (buf);
333                 return GST_FLOW_UNEXPECTED;
334         }
335         length = ret;
336         GST_BUFFER_SIZE (buf) = length;
337         GST_BUFFER_OFFSET (buf) = offset;
338         GST_BUFFER_OFFSET_END (buf) = offset + length;
339         *buffer = buf;
340         src->read_position += length;
341         return GST_FLOW_OK;
342 }
343 /**
344  * This function does the following:
345  *  1. Calls DRM file read chain method for drm files.
346  *  2. Calls normal file read chain method for standard files.
347  *
348  * @param   basesrc    [in]   BaseSrc Structure
349  * @param   size    [out]   Size of the file
350  *
351  * @return  gboolean   Returns TRUE on success and FALSE on ERROR
352  */
353 static GstFlowReturn gst_drm_src_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer)
354 {
355         GstDrmSrc *src = GST_DRM_SRC (basesrc);
356
357         // 1. Calls DRM file read chain method for drm files.
358
359         // 2. Calls normal file read chain method for standard files.
360         return gst_drm_src_create_read (src, offset, length, buffer);
361 }
362 /**
363  *
364  * @param   basesrc    [in]   BaseSrc Structure
365  *
366  * @return  gboolean   Returns TRUE if the file is seekable and FALSE if the file is not seekable
367  */
368 static gboolean gst_drm_src_is_seekable (GstBaseSrc * basesrc)
369 {
370         GstDrmSrc *src = GST_DRM_SRC (basesrc);
371         return src->seekable;
372 }
373 /**
374  * This function does the following:
375  *  1. Gets the filesize for drm file by using seek oprations
376  *  2. Gets the file size for standard file by using statistics
377  *
378  * @param   basesrc    [in]   BaseSrc Structure
379  * @param   size    [in]   Size of the file
380  *
381  * @return  gboolean   Returns TRUE on success and FALSE on ERROR
382  */
383 static gboolean gst_drm_src_get_size (GstBaseSrc * basesrc, guint64 * size)
384 {
385         struct stat stat_results;
386         GstDrmSrc *src = GST_DRM_SRC (basesrc);
387         unsigned int offset;
388
389         //  1. Gets the filesize for drm file by using seek oprations
390
391         // 2. Gets the file size for standard file by using statistics
392         if (fstat (src->fd, &stat_results) < 0)
393                 return FALSE;
394         *size = stat_results.st_size;
395         return TRUE;
396 }
397 /**
398  * This function does the following:
399  *  1. Checks the filename
400  *  2. Opens the file and check statistics of the file
401  *  7. Checks the seeking for standard files
402  *
403  * @param   basesrc    [in]   BaseSrc Structure
404  *
405  * @return  gboolean   Returns TRUE on success and FALSE on ERROR
406  */
407 static gboolean gst_drm_src_start (GstBaseSrc * basesrc)
408 {
409         GstDrmSrc *src = GST_DRM_SRC (basesrc);
410         struct stat stat_results;
411         off_t ret;
412 PROFILE_FUNC_BEGIN;
413         // 1. Checks the filename
414         if (src->filename == NULL || src->filename[0] == '\0')
415         {
416                 GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,("No file name specified for reading."), (NULL));
417                 return FALSE;
418         }
419         // 2. Opens the file and check statistics of the file
420         GST_INFO_OBJECT (src, "opening file %s", src->filename);
421         src->fd = open (src->filename, O_RDONLY | O_BINARY);
422         if (src->fd < 0)
423         {
424                 if(errno == ENOENT)
425                 {
426                         GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),("No such file \"%s\"", src->filename));
427                         return FALSE;
428                 }
429                 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("Could not open file \"%s\" for reading.", src->filename), GST_ERROR_SYSTEM);
430                 return FALSE;
431         }
432         if (fstat (src->fd, &stat_results) < 0)
433         {
434                 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("Could not get info on \"%s\".", src->filename), (NULL));
435                 close (src->fd);
436                 return FALSE;
437         }
438         if (S_ISDIR (stat_results.st_mode))
439         {
440                 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("\"%s\" is a directory.", src->filename), (NULL));
441                 close (src->fd);
442                 return FALSE;
443         }
444         if (S_ISSOCK (stat_results.st_mode))
445         {
446                 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("File \"%s\" is a socket.", src->filename), (NULL));
447                 close (src->fd);
448                 return FALSE;
449         }
450         src->read_position = 0;
451
452         // 7. Checks the seeking for standard files
453         if (S_ISREG (stat_results.st_mode))
454                 src->is_regular = TRUE;
455         ret = lseek (src->fd, 0, SEEK_END);
456         if (ret < 0)
457         {
458                 GST_LOG_OBJECT (src, "disabling seeking, not in mmap mode and lseek "
459                         "failed: %s", g_strerror (errno));
460                 src->seekable = FALSE;
461         }
462         else
463         {
464                 src->seekable = TRUE;
465         }
466         lseek (src->fd, 0, SEEK_SET);
467         src->seekable = src->seekable && src->is_regular;
468         PROFILE_FUNC_END;
469         return TRUE;
470 }
471 /**
472  * This function does the following:
473  *  1. Closes the file desciptor and resets the flags
474  *
475  * @param   basesrc    [in]   BaseSrc Structure
476  *
477  * @return  gboolean   Returns TRUE on success and FALSE on ERROR
478  */
479 static gboolean gst_drm_src_stop (GstBaseSrc * basesrc)
480 {
481         GstDrmSrc *src = GST_DRM_SRC (basesrc);
482
483         // 1. Closes the file desciptor and resets the flags
484         if(src->fd > 0)
485                 close (src->fd);
486         src->fd = 0;
487         src->is_regular = FALSE;
488 //      PROFILE_SHOW_RESULT;
489         return TRUE;
490 }
491 /**
492  *
493  * @param   void
494  *
495  * @return  GstURIType   Returns GST_URI_SRC
496  */
497
498 static GstURIType gst_drm_src_uri_get_type (void)
499 {
500         return GST_URI_SRC;
501 }
502
503 /**
504  * This function does the following:
505  *  1. Defines the list of protocols
506  *
507  * @param   void
508  *
509  * @return  gchar **   Returns the protocol list
510  */
511
512 static gchar ** gst_drm_src_uri_get_protocols (void)
513 {
514         static gchar *protocols[] = { "file", NULL };
515         return protocols;
516 }
517 /**
518  *
519  * @param   handler [in] GstURIHandler structure
520  *
521  * @return  gchar*   Returns the uri
522  */
523 static const gchar * gst_drm_src_uri_get_uri (GstURIHandler *handler)
524 {
525         GstDrmSrc *src = GST_DRM_SRC (handler);
526         return src->uri;
527 }
528 /**
529  * This function does the following:
530  *  1. Checks the protocol
531  *  2. Checks the whether it is absolute or not
532  *  3 sets the location
533  *
534  * @param   handler [in] GstURIHandler structure
535  * @param   uri [in] uri string
536  *
537  * @return  gboolean   Returns TRUE on success and FALSE on Error
538  */
539 static gboolean gst_drm_src_uri_set_uri (GstURIHandler *handler, const gchar * uri)
540 {
541         gchar *protocol, *location;
542         gboolean ret;
543         GstDrmSrc *src = GST_DRM_SRC (handler);
544         // 1. Checks the protocol
545         protocol = gst_uri_get_protocol (uri);
546         if (strcmp (protocol, "file") != 0)
547         {
548                 g_free (protocol);
549                 return FALSE;
550         }
551         g_free (protocol);
552         if (g_str_has_prefix (uri, "file://localhost/"))
553         {
554                 char *tmp;
555                 tmp = g_strconcat ("file://", uri + 16, NULL);
556                 location = gst_uri_get_location (tmp);
557                 g_free (tmp);
558         }
559         else if (strcmp (uri, "file://") == 0)
560         {
561                 gst_drm_src_set_location (src, NULL);
562                 return TRUE;
563         }
564         else
565         {
566                 location = gst_uri_get_location (uri);
567         }
568         if (!location)
569                 return FALSE;
570         // 2. Checks the whether it is absolute or not
571         if (!g_path_is_absolute (location))
572         {
573                 g_free (location);
574                 return FALSE;
575         }
576         // 3 sets the location
577         ret = gst_drm_src_set_location (src, location);
578         g_free (location);
579         return ret;
580 }
581 /**
582  * This function does the following:
583  *  1. Assignes the function pointer for URI related stuff
584  *
585  * @param   g_iface [in] an interface to URI handler
586  * @param   iface_data [in] a gpointer
587  *
588  * @return  void
589  */
590 static void gst_drm_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
591 {
592         GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
593         // 1. Assigning the function pointer for URI related stuff
594         iface->get_type = gst_drm_src_uri_get_type;
595         iface->get_protocols = gst_drm_src_uri_get_protocols;
596         iface->get_uri = gst_drm_src_uri_get_uri;
597         iface->set_uri = gst_drm_src_uri_set_uri;
598 }
599 /**
600  * This function does the following:
601  *  1. Registers an element as drmsrc
602  *
603  * @param   i_pPlugin [in] a plug-in structure
604  *
605  * @return  gboolean TRUE on SUCCESS and FALSE on Error
606  */
607 static gboolean plugin_init(GstPlugin* i_pPlugin)
608 {
609         return gst_element_register(i_pPlugin, "drmsrc", GST_RANK_NONE, GST_TYPE_DRM_SRC);;
610 }
611 /**
612  * This function does the following:
613  *  1. plugin defination
614  *
615  */
616 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
617                                                  GST_VERSION_MINOR,
618                                                  "drmsrc",
619                                                  "Plugin to read data from standad/DRM File",
620                                                  plugin_init,
621                                                  VERSION,
622                                                  "LGPL",
623                                                  "Samsung Electronics Co",
624                                                  "http://www.samsung.com/")
625