gstfunnel: avoid access of freed pad
[platform/upstream/gstreamer.git] / gst / gstdatetime.c
1 /* GStreamer
2  * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "glib-compat-private.h"
25 #include "gst_private.h"
26 #include "gstdatetime.h"
27 #include <glib.h>
28 #include <math.h>
29
30 /**
31  * SECTION:gstdatetime
32  * @title: GstDateTime
33  * @short_description: A date, time and timezone structure
34  *
35  * Struct to store date, time and timezone information altogether.
36  * #GstDateTime is refcounted and immutable.
37  *
38  * Date information is handled using the proleptic Gregorian calendar.
39  *
40  * Provides basic creation functions and accessor functions to its fields.
41  *
42  * Since: 0.10.31
43  */
44
45 typedef enum
46 {
47   GST_DATE_TIME_FIELDS_INVALID = 0,
48   GST_DATE_TIME_FIELDS_Y,       /* have year                */
49   GST_DATE_TIME_FIELDS_YM,      /* have year and month      */
50   GST_DATE_TIME_FIELDS_YMD,     /* have year, month and day */
51   GST_DATE_TIME_FIELDS_YMD_HM,
52   GST_DATE_TIME_FIELDS_YMD_HMS
53 } GstDateTimeFields;
54
55 struct _GstDateTime
56 {
57   GDateTime *datetime;
58
59   GstDateTimeFields fields;
60   volatile gint ref_count;
61 };
62
63 static GstDateTime *
64 gst_date_time_new_from_gdatetime (GDateTime * dt)
65 {
66   GstDateTime *gst_dt;
67
68   if (!dt)
69     return NULL;
70
71   gst_dt = g_slice_new (GstDateTime);
72   gst_dt->datetime = dt;
73   gst_dt->fields = GST_DATE_TIME_FIELDS_YMD_HMS;
74   gst_dt->ref_count = 1;
75   return gst_dt;
76 }
77
78 /**
79  * gst_date_time_has_year:
80  * @datetime: a #GstDateTime
81  *
82  * Returns: TRUE if @datetime<!-- -->'s year field is set (which should always
83  *     be the case), otherwise FALSE
84  */
85 gboolean
86 gst_date_time_has_year (const GstDateTime * datetime)
87 {
88   g_return_val_if_fail (datetime != NULL, FALSE);
89
90   return (datetime->fields >= GST_DATE_TIME_FIELDS_Y);
91 }
92
93 /**
94  * gst_date_time_has_month:
95  * @datetime: a #GstDateTime
96  *
97  * Returns: TRUE if @datetime<!-- -->'s month field is set, otherwise FALSE
98  */
99 gboolean
100 gst_date_time_has_month (const GstDateTime * datetime)
101 {
102   g_return_val_if_fail (datetime != NULL, FALSE);
103
104   return (datetime->fields >= GST_DATE_TIME_FIELDS_YM);
105 }
106
107 /**
108  * gst_date_time_has_day:
109  * @datetime: a #GstDateTime
110  *
111  * Returns: TRUE if @datetime<!-- -->'s day field is set, otherwise FALSE
112  */
113 gboolean
114 gst_date_time_has_day (const GstDateTime * datetime)
115 {
116   g_return_val_if_fail (datetime != NULL, FALSE);
117
118   return (datetime->fields >= GST_DATE_TIME_FIELDS_YMD);
119 }
120
121 /**
122  * gst_date_time_has_time:
123  * @datetime: a #GstDateTime
124  *
125  * Returns: TRUE if @datetime<!-- -->'s hour and minute fields are set,
126  *     otherwise FALSE
127  */
128 gboolean
129 gst_date_time_has_time (const GstDateTime * datetime)
130 {
131   g_return_val_if_fail (datetime != NULL, FALSE);
132
133   return (datetime->fields >= GST_DATE_TIME_FIELDS_YMD_HM);
134 }
135
136 /**
137  * gst_date_time_has_second:
138  * @datetime: a #GstDateTime
139  *
140  * Returns: TRUE if @datetime<!-- -->'s second field is set, otherwise FALSE
141  */
142 gboolean
143 gst_date_time_has_second (const GstDateTime * datetime)
144 {
145   g_return_val_if_fail (datetime != NULL, FALSE);
146
147   return (datetime->fields >= GST_DATE_TIME_FIELDS_YMD_HMS);
148 }
149
150 /**
151  * gst_date_time_get_year:
152  * @datetime: a #GstDateTime
153  *
154  * Returns the year of this #GstDateTime
155  * Call gst_date_time_has_year before, to avoid warnings.
156  *
157  * Return value: The year of this #GstDateTime
158  * Since: 0.10.31
159  */
160 gint
161 gst_date_time_get_year (const GstDateTime * datetime)
162 {
163   g_return_val_if_fail (datetime != NULL, 0);
164
165   return g_date_time_get_year (datetime->datetime);
166 }
167
168 /**
169  * gst_date_time_get_month:
170  * @datetime: a #GstDateTime
171  *
172  * Returns the month of this #GstDateTime. January is 1, February is 2, etc..
173  * Call gst_date_time_has_month before, to avoid warnings.
174  *
175  * Return value: The month of this #GstDateTime
176  * Since: 0.10.31
177  */
178 gint
179 gst_date_time_get_month (const GstDateTime * datetime)
180 {
181   g_return_val_if_fail (datetime != NULL, 0);
182   g_return_val_if_fail (gst_date_time_has_month (datetime), 0);
183
184   return g_date_time_get_month (datetime->datetime);
185 }
186
187 /**
188  * gst_date_time_get_day:
189  * @datetime: a #GstDateTime
190  *
191  * Returns the day of this #GstDateTime.
192  * Call gst_date_time_has_day before, to avoid warnings.
193  *
194  * Return value: The day of this #GstDateTime
195  * Since: 0.10.31
196  */
197 gint
198 gst_date_time_get_day (const GstDateTime * datetime)
199 {
200   g_return_val_if_fail (datetime != NULL, 0);
201   g_return_val_if_fail (gst_date_time_has_day (datetime), 0);
202
203   return g_date_time_get_day_of_month (datetime->datetime);
204 }
205
206 /**
207  * gst_date_time_get_hour:
208  * @datetime: a #GstDateTime
209  *
210  * Retrieves the hour of the day represented by @datetime in the gregorian
211  * calendar. The return is in the range of 0 to 23.
212  * Call gst_date_time_has_haur before, to avoid warnings.
213  *
214  * Return value: the hour of the day
215  *
216  * Since: 0.10.31
217  */
218 gint
219 gst_date_time_get_hour (const GstDateTime * datetime)
220 {
221   g_return_val_if_fail (datetime != NULL, 0);
222   g_return_val_if_fail (gst_date_time_has_time (datetime), 0);
223
224   return g_date_time_get_hour (datetime->datetime);
225 }
226
227 /**
228  * gst_date_time_get_minute:
229  * @datetime: a #GstDateTime
230  *
231  * Retrieves the minute of the hour represented by @datetime in the gregorian
232  * calendar.
233  * Call gst_date_time_has_minute before, to avoid warnings.
234  *
235  * Return value: the minute of the hour
236  *
237  * Since: 0.10.31
238  */
239 gint
240 gst_date_time_get_minute (const GstDateTime * datetime)
241 {
242   g_return_val_if_fail (datetime != NULL, 0);
243   g_return_val_if_fail (gst_date_time_has_time (datetime), 0);
244
245   return g_date_time_get_minute (datetime->datetime);
246 }
247
248 /**
249  * gst_date_time_get_second:
250  * @datetime: a #GstDateTime
251  *
252  * Retrieves the second of the minute represented by @datetime in the gregorian
253  * calendar.
254  * Call gst_date_time_has_second before, to avoid warnings.
255  *
256  * Return value: the second represented by @datetime
257  *
258  * Since: 0.10.31
259  */
260 gint
261 gst_date_time_get_second (const GstDateTime * datetime)
262 {
263   g_return_val_if_fail (datetime != NULL, 0);
264   g_return_val_if_fail (gst_date_time_has_second (datetime), 0);
265
266   return g_date_time_get_second (datetime->datetime);
267 }
268
269 /**
270  * gst_date_time_get_microsecond:
271  * @datetime: a #GstDateTime
272  *
273  * Retrieves the fractional part of the seconds in microseconds represented by
274  * @datetime in the gregorian calendar.
275  *
276  * Return value: the microsecond of the second
277  *
278  * Since: 0.10.31
279  */
280 gint
281 gst_date_time_get_microsecond (const GstDateTime * datetime)
282 {
283   g_return_val_if_fail (datetime != NULL, 0);
284   g_return_val_if_fail (gst_date_time_has_second (datetime), 0);
285
286   return g_date_time_get_microsecond (datetime->datetime);
287 }
288
289 /**
290  * gst_date_time_get_time_zone_offset:
291  * @datetime: a #GstDateTime
292  *
293  * Retrieves the offset from UTC in hours that the timezone specified
294  * by @datetime represents. Timezones ahead (to the east) of UTC have positive
295  * values, timezones before (to the west) of UTC have negative values.
296  * If @datetime represents UTC time, then the offset is zero.
297  *
298  * Return value: the offset from UTC in hours
299  * Since: 0.10.31
300  */
301 gfloat
302 gst_date_time_get_time_zone_offset (const GstDateTime * datetime)
303 {
304   g_return_val_if_fail (datetime != NULL, 0.0);
305   g_return_val_if_fail (gst_date_time_has_time (datetime), 0.0);
306
307   return (g_date_time_get_utc_offset (datetime->datetime) /
308       G_USEC_PER_SEC) / 3600.0;
309 }
310
311 /**
312  * gst_date_time_new_y:
313  * @year: the gregorian year
314  *
315  * Creates a new #GstDateTime using the date and times in the gregorian calendar
316  * in the local timezone.
317  *
318  * @year should be from 1 to 9999.
319  *
320  * Free-function: gst_date_time_unref
321  *
322  * Return value: (transfer full): the newly created #GstDateTime
323  *
324  * Since:
325  */
326 GstDateTime *
327 gst_date_time_new_y (gint year)
328 {
329   return gst_date_time_new (0.0, year, -1, -1, -1, -1, -1);
330 }
331
332 /**
333  * gst_date_time_new_ym:
334  * @year: the gregorian year
335  * @month: the gregorian month
336  *
337  * Creates a new #GstDateTime using the date and times in the gregorian calendar
338  * in the local timezone.
339  *
340  * @year should be from 1 to 9999, @month should be from 1 to 12.
341  *
342  * If value is -1 then all over value will be ignored. For example
343  * if @month == -1, then #GstDateTime will created only for @year.
344  *
345  * Free-function: gst_date_time_unref
346  *
347  * Return value: (transfer full): the newly created #GstDateTime
348  *
349  * Since:
350  */
351 GstDateTime *
352 gst_date_time_new_ym (gint year, gint month)
353 {
354   return gst_date_time_new (0.0, year, month, -1, -1, -1, -1);
355 }
356
357 /**
358  * gst_date_time_new_ymd:
359  * @year: the gregorian year
360  * @month: the gregorian month
361  * @day: the day of the gregorian month
362  *
363  * Creates a new #GstDateTime using the date and times in the gregorian calendar
364  * in the local timezone.
365  *
366  * @year should be from 1 to 9999, @month should be from 1 to 12, @day from
367  * 1 to 31.
368  *
369  * If value is -1 then all over value will be ignored. For example
370  * if @month == -1, then #GstDateTime will created only for @year. If
371  * @day == -1, then #GstDateTime will created for @year and @month and
372  * so on.
373  *
374  * Free-function: gst_date_time_unref
375  *
376  * Return value: (transfer full): the newly created #GstDateTime
377  *
378  * Since:
379  */
380 GstDateTime *
381 gst_date_time_new_ymd (gint year, gint month, gint day)
382 {
383   return gst_date_time_new (0.0, year, month, day, -1, -1, -1);
384 }
385
386 /**
387  * gst_date_time_new_from_unix_epoch_local_time:
388  * @secs: seconds from the Unix epoch
389  *
390  * Creates a new #GstDateTime using the time since Jan 1, 1970 specified by
391  * @secs. The #GstDateTime is in the local timezone.
392  *
393  * Free-function: gst_date_time_unref
394  *
395  * Return value: (transfer full): the newly created #GstDateTime
396  *
397  * Since: 0.10.31
398  */
399 GstDateTime *
400 gst_date_time_new_from_unix_epoch_local_time (gint64 secs)
401 {
402   GstDateTime *datetime;
403   datetime =
404       gst_date_time_new_from_gdatetime (g_date_time_new_from_unix_local (secs));
405   return datetime;
406 }
407
408 /**
409  * gst_date_time_new_from_unix_epoch_utc:
410  * @secs: seconds from the Unix epoch
411  *
412  * Creates a new #GstDateTime using the time since Jan 1, 1970 specified by
413  * @secs. The #GstDateTime is in the UTC timezone.
414  *
415  * Free-function: gst_date_time_unref
416  *
417  * Return value: (transfer full): the newly created #GstDateTime
418  *
419  * Since: 0.10.31
420  */
421 GstDateTime *
422 gst_date_time_new_from_unix_epoch_utc (gint64 secs)
423 {
424   GstDateTime *datetime;
425   datetime =
426       gst_date_time_new_from_gdatetime (g_date_time_new_from_unix_utc (secs));
427   return datetime;
428 }
429
430 static GstDateTimeFields
431 gst_date_time_check_fields (gint * year, gint * month, gint * day,
432     gint * hour, gint * minute, gdouble * seconds)
433 {
434   if (*month == -1) {
435     *month = *day = 1;
436     *hour = *minute = *seconds = 0;
437     return GST_DATE_TIME_FIELDS_Y;
438   } else if (*day == -1) {
439     *day = 1;
440     *hour = *minute = *seconds = 0;
441     return GST_DATE_TIME_FIELDS_YM;
442   } else if (*hour == -1) {
443     *hour = *minute = *seconds = 0;
444     return GST_DATE_TIME_FIELDS_YMD;
445   } else if (*seconds == -1) {
446     *seconds = 0;
447     return GST_DATE_TIME_FIELDS_YMD_HM;
448   } else
449     return GST_DATE_TIME_FIELDS_YMD_HMS;
450 }
451
452 /**
453  * gst_date_time_new_local_time:
454  * @year: the gregorian year
455  * @month: the gregorian month, or -1
456  * @day: the day of the gregorian month, or -1
457  * @hour: the hour of the day, or -1
458  * @minute: the minute of the hour, or -1
459  * @seconds: the second of the minute, or -1
460  *
461  * Creates a new #GstDateTime using the date and times in the gregorian calendar
462  * in the local timezone.
463  *
464  * @year should be from 1 to 9999, @month should be from 1 to 12, @day from
465  * 1 to 31, @hour from 0 to 23, @minutes and @seconds from 0 to 59.
466  *
467  * If @month is -1, then the #GstDateTime created will only contain @year,
468  * and all other fields will be considered not set.
469  *
470  * If @day is -1, then the #GstDateTime created will only contain @year and
471  * @month and all other fields will be considered not set.
472  *
473  * If @hour is -1, then the #GstDateTime created will only contain @year and
474  * @month and @day, and the time fields will be considered not set. In this
475  * case @minute and @seconds should also be -1.
476  *
477  * Free-function: gst_date_time_unref
478  *
479  * Return value: (transfer full): the newly created #GstDateTime
480  *
481  * Since: 0.10.31
482  */
483 GstDateTime *
484 gst_date_time_new_local_time (gint year, gint month, gint day, gint hour,
485     gint minute, gdouble seconds)
486 {
487   GstDateTimeFields fields;
488   GstDateTime *datetime;
489
490   g_return_val_if_fail (year > 0 && year <= 9999, NULL);
491   g_return_val_if_fail ((month > 0 && month <= 12) || month == -1, NULL);
492   g_return_val_if_fail ((day > 0 && day <= 31) || day == -1, NULL);
493   g_return_val_if_fail ((hour >= 0 && hour < 24) || hour == -1, NULL);
494   g_return_val_if_fail ((minute >= 0 && minute < 60) || minute == -1, NULL);
495   g_return_val_if_fail ((seconds >= 0 && seconds < 60) || seconds == -1, NULL);
496
497   fields = gst_date_time_check_fields (&year, &month, &day,
498       &hour, &minute, &seconds);
499
500   datetime = gst_date_time_new_from_gdatetime (g_date_time_new_local (year,
501           month, day, hour, minute, seconds));
502
503   datetime->fields = fields;
504   return datetime;
505 }
506
507 /**
508  * gst_date_time_new_now_local_time:
509  *
510  * Creates a new #GstDateTime representing the current date and time.
511  *
512  * Free-function: gst_date_time_unref
513  *
514  * Return value: (transfer full): the newly created #GstDateTime which should
515  *     be freed with gst_date_time_unref().
516  *
517  * Since: 0.10.31
518  */
519 GstDateTime *
520 gst_date_time_new_now_local_time (void)
521 {
522   return gst_date_time_new_from_gdatetime (g_date_time_new_now_local ());
523 }
524
525 /**
526  * gst_date_time_new_now_utc:
527  *
528  * Creates a new #GstDateTime that represents the current instant at Universal
529  * coordinated time.
530  *
531  * Free-function: gst_date_time_unref
532  *
533  * Return value: (transfer full): the newly created #GstDateTime which should
534  *   be freed with gst_date_time_unref().
535  *
536  * Since: 0.10.31
537  */
538 GstDateTime *
539 gst_date_time_new_now_utc (void)
540 {
541   return gst_date_time_new_from_gdatetime (g_date_time_new_now_utc ());
542 }
543
544 gint
545 priv_gst_date_time_compare (gconstpointer dt1, gconstpointer dt2)
546 {
547   const GstDateTime *datetime1 = dt1;
548   const GstDateTime *datetime2 = dt2;
549   return g_date_time_compare (datetime1->datetime, datetime2->datetime);
550 }
551
552 /**
553  * gst_date_time_new:
554  * @tzoffset: Offset from UTC in hours.
555  * @year: the gregorian year
556  * @month: the gregorian month
557  * @day: the day of the gregorian month
558  * @hour: the hour of the day
559  * @minute: the minute of the hour
560  * @seconds: the second of the minute
561  *
562  * Creates a new #GstDateTime using the date and times in the gregorian calendar
563  * in the supplied timezone.
564  *
565  * @year should be from 1 to 9999, @month should be from 1 to 12, @day from
566  * 1 to 31, @hour from 0 to 23, @minutes and @seconds from 0 to 59.
567  *
568  * Note that @tzoffset is a float and was chosen so for being able to handle
569  * some fractional timezones, while it still keeps the readability of
570  * represeting it in hours for most timezones.
571  *
572  * If value is -1 then all over value will be ignored. For example
573  * if @month == -1, then #GstDateTime will created only for @year. If
574  * @day == -1, then #GstDateTime will created for @year and @month and
575  * so on.
576  *
577  * Free-function: gst_date_time_unref
578  *
579  * Return value: (transfer full): the newly created #GstDateTime
580  *
581  * Since: 0.10.31
582  */
583 GstDateTime *
584 gst_date_time_new (gfloat tzoffset, gint year, gint month, gint day, gint hour,
585     gint minute, gdouble seconds)
586 {
587   GstDateTimeFields fields;
588   gchar buf[6];
589   GTimeZone *tz;
590   GDateTime *dt;
591   GstDateTime *datetime;
592   gint tzhour, tzminute;
593
594   g_return_val_if_fail (year > 0 && year <= 9999, NULL);
595   g_return_val_if_fail ((month > 0 && month <= 12) || month == -1, NULL);
596   g_return_val_if_fail ((day > 0 && day <= 31) || day == -1, NULL);
597   g_return_val_if_fail ((hour >= 0 && hour < 24) || hour == -1, NULL);
598   g_return_val_if_fail ((minute >= 0 && minute < 60) || minute == -1, NULL);
599   g_return_val_if_fail ((seconds >= 0 && seconds < 60) || seconds == -1, NULL);
600   g_return_val_if_fail (tzoffset >= -12.0 && tzoffset <= 12.0, NULL);
601   g_return_val_if_fail ((hour >= 0 && minute >= 0) ||
602       (hour == -1 && minute == -1 && seconds == -1 && tzoffset == 0.0), NULL);
603
604   tzhour = (gint) ABS (tzoffset);
605   tzminute = (gint) ((ABS (tzoffset) - tzhour) * 60);
606
607   g_snprintf (buf, 6, "%c%02d%02d", tzoffset >= 0 ? '+' : '-', tzhour,
608       tzminute);
609
610   tz = g_time_zone_new (buf);
611
612   fields = gst_date_time_check_fields (&year, &month, &day,
613       &hour, &minute, &seconds);
614
615   dt = g_date_time_new (tz, year, month, day, hour, minute, seconds);
616   g_time_zone_unref (tz);
617
618   datetime = gst_date_time_new_from_gdatetime (dt);
619   datetime->fields = fields;
620
621   return datetime;
622 }
623
624 static void
625 gst_date_time_free (GstDateTime * datetime)
626 {
627   g_date_time_unref (datetime->datetime);
628   g_slice_free (GstDateTime, datetime);
629 }
630
631 /**
632  * gst_date_time_ref:
633  * @datetime: a #GstDateTime
634  *
635  * Atomically increments the reference count of @datetime by one.
636  *
637  * Return value: (transfer full): the reference @datetime
638  *
639  * Since: 0.10.31
640  */
641 GstDateTime *
642 gst_date_time_ref (GstDateTime * datetime)
643 {
644   g_return_val_if_fail (datetime != NULL, NULL);
645   g_return_val_if_fail (datetime->ref_count > 0, NULL);
646   g_atomic_int_inc (&datetime->ref_count);
647   return datetime;
648 }
649
650 /**
651  * gst_date_time_unref:
652  * @datetime: (transfer full): a #GstDateTime
653  *
654  * Atomically decrements the reference count of @datetime by one.  When the
655  * reference count reaches zero, the structure is freed.
656  *
657  * Since: 0.10.31
658  */
659 void
660 gst_date_time_unref (GstDateTime * datetime)
661 {
662   g_return_if_fail (datetime != NULL);
663   g_return_if_fail (datetime->ref_count > 0);
664
665   if (g_atomic_int_dec_and_test (&datetime->ref_count))
666     gst_date_time_free (datetime);
667 }