2 * gstcmmlutils.c - GStreamer CMML utility functions
3 * Copyright (C) 2005 Alessandro Decina
6 * Alessandro Decina <alessandro@nnva.org>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
24 #include "gstcmmlutils.h"
36 gst_cmml_clock_time_from_npt (const gchar * time)
44 GstClockTime hours_t = 0, seconds_t = 0;
46 if (!strncmp (time, "npt:", 4))
49 /* parse npt-hhmmss */
50 fields = sscanf (time, "%d:%d:%d.%d", &hours, &minutes, &seconds, &mseconds);
52 if (hours < 0 || (guint) minutes > 59 || (guint) seconds > 59)
55 hours_t = gst_util_uint64_scale (hours, GST_SECOND * 3600, 1);
56 if (hours_t == G_MAXUINT64)
59 seconds_t = seconds * GST_SECOND;
66 fields = sscanf (time, "%" G_GUINT64_FORMAT ".%d", &u64seconds, &mseconds);
70 seconds_t = gst_util_uint64_scale_int (u64seconds, GST_SECOND, 1);
71 if (seconds_t == G_MAXUINT64)
75 if ((guint) mseconds > 999)
78 res = (minutes * 60) * GST_SECOND + mseconds * GST_MSECOND;
79 if (G_MAXUINT64 - hours_t - seconds_t < res)
82 res += hours_t + seconds_t;
88 return GST_CLOCK_TIME_NONE;
92 gst_cmml_clock_time_from_smpte (const gchar * time)
96 gint hours, minutes, seconds;
101 if (!strncmp (time, "smpte-24:", 9)) {
104 } else if (!strncmp (time, "smpte-24-drop:", 14)) {
107 } else if (!strncmp (time, "smpte-25:", 9)) {
110 } else if (!strncmp (time, "smpte-30:", 9)) {
113 } else if (!strncmp (time, "smpte-30-drop:", 14)) {
116 } else if (!strncmp (time, "smpte-50:", 9)) {
119 } else if (!strncmp (time, "smpte-60:", 9)) {
122 } else if (!strncmp (time, "smpte-60-drop:", 14)) {
126 return GST_CLOCK_TIME_NONE;
129 fields = sscanf (time, "%d:%d:%d:%f", &hours, &minutes, &seconds, &frames);
131 if (hours < 0 || (guint) minutes > 59 || (guint) seconds > 59 ||
132 frames < 0 || frames > ceil (framerate)) {
133 res = GST_CLOCK_TIME_NONE;
135 hours_t = gst_util_uint64_scale (hours, GST_SECOND * 3600, 1);
136 if (hours_t == G_MAXUINT64)
139 res = ((minutes * 60) + seconds + (frames / framerate))
141 if (G_MAXUINT64 - hours_t < res)
147 res = GST_CLOCK_TIME_NONE;
152 return GST_CLOCK_TIME_NONE;
156 gst_cmml_clock_time_to_npt (const GstClockTime time)
158 guint seconds, hours, minutes, mseconds;
161 g_return_val_if_fail (time != GST_CLOCK_TIME_NONE, NULL);
163 hours = time / (GST_SECOND * 3600);
164 minutes = (time / ((GST_SECOND * 60)) % 60);
165 seconds = (time / GST_SECOND) % 60;
166 mseconds = (time % GST_SECOND) / GST_MSECOND;
171 res = g_strdup_printf ("%u:%02u:%02u.%03u",
172 hours, minutes, seconds, mseconds);
178 gst_cmml_clock_time_to_granule (GstClockTime prev_time,
179 GstClockTime current_time, gint64 granulerate_n, gint64 granulerate_d,
182 guint64 keyindex, keyoffset, granulepos, maxoffset;
185 g_return_val_if_fail (granulerate_d != 0, -1);
186 g_return_val_if_fail (granuleshift > 0, -1);
187 g_return_val_if_fail (granuleshift <= 64, -1);
189 if (prev_time == GST_CLOCK_TIME_NONE)
192 if (prev_time > current_time)
195 /* GST_SECOND / (granulerate_n / granulerate_d) */
196 granulerate = gst_util_uint64_scale (GST_SECOND,
197 granulerate_d, granulerate_n);
199 prev_time = prev_time / granulerate;
201 /* granuleshift == 64 should be a << 0 shift, which is defined */
202 maxoffset = ((guint64) 1 << (64 - granuleshift)) - 1;
203 if (prev_time > maxoffset)
204 /* we need more than 64 - granuleshift bits to encode prev_time */
207 keyindex = prev_time << granuleshift;
209 keyoffset = (current_time / granulerate) - prev_time;
210 /* make sure we don't shift to the limits of the types as this is undefined. */
211 if (granuleshift == 64)
212 maxoffset = G_MAXUINT64;
214 maxoffset = ((guint64) 1 << granuleshift) - 1;
216 if (keyoffset > maxoffset)
217 /* we need more than granuleshift bits to encode prev_time - current_time */
220 granulepos = keyindex + keyoffset;
230 gst_cmml_track_list_new ()
232 return g_hash_table_new (g_str_hash, g_str_equal);
236 gst_cmml_track_list_destroy_track (gchar * key,
237 GstCmmlTrack * track, gpointer user_data)
241 for (walk = track->clips; walk; walk = g_list_next (walk))
242 g_object_unref (G_OBJECT (walk->data));
245 g_list_free (track->clips);
252 gst_cmml_track_list_destroy (GHashTable * tracks)
254 g_hash_table_foreach_remove (tracks,
255 (GHRFunc) gst_cmml_track_list_destroy_track, NULL);
256 g_hash_table_destroy (tracks);
260 gst_cmml_track_list_compare_clips (GstCmmlTagClip * a, GstCmmlTagClip * b)
262 if (a->start_time < b->start_time)
269 gst_cmml_track_list_add_clip (GHashTable * tracks, GstCmmlTagClip * clip)
275 g_return_if_fail (clip->track != NULL);
277 if (g_hash_table_lookup_extended (tracks, clip->track, &key, &value)) {
278 track_name = (gchar *) key;
279 track = (GstCmmlTrack *) value;
281 track_name = g_strdup ((gchar *) clip->track);
282 track = g_new0 (GstCmmlTrack, 1);
283 g_hash_table_insert (tracks, track_name, track);
286 /* add clip to the tracklist */
287 track->clips = g_list_insert_sorted (track->clips, g_object_ref (clip),
288 (GCompareFunc) gst_cmml_track_list_compare_clips);
292 gst_cmml_track_list_del_clip (GHashTable * tracks, GstCmmlTagClip * clip)
296 gboolean res = FALSE;
298 g_return_val_if_fail (clip->track != NULL, FALSE);
300 track = g_hash_table_lookup (tracks, clip->track);
302 link = g_list_find (track->clips, clip);
304 g_object_unref (G_OBJECT (link->data));
305 track->clips = g_list_delete_link (track->clips, link);
314 gst_cmml_track_list_has_clip (GHashTable * tracks, GstCmmlTagClip * clip)
319 gboolean res = FALSE;
321 track = g_hash_table_lookup (tracks, (gchar *) clip->track);
323 for (walk = track->clips; walk; walk = g_list_next (walk)) {
324 tmp = GST_CMML_TAG_CLIP (walk->data);
325 if (tmp->start_time == clip->start_time) {
336 gst_cmml_track_list_merge_track (gchar * track_name,
337 GstCmmlTrack * track, GList ** list)
342 for (walk = track->clips; walk; walk = g_list_next (walk)) {
343 cur = GST_CMML_TAG_CLIP (walk->data);
344 *list = g_list_insert_sorted (*list, cur,
345 (GCompareFunc) gst_cmml_track_list_compare_clips);
352 gst_cmml_track_list_get_track_clips (GHashTable * tracks,
353 const gchar * track_name)
357 g_return_val_if_fail (track_name != NULL, NULL);
359 track = g_hash_table_lookup (tracks, track_name);
360 return track ? track->clips : NULL;
364 gst_cmml_track_list_get_clips (GHashTable * tracks)
368 g_hash_table_foreach (tracks,
369 (GHFunc) gst_cmml_track_list_merge_track, &list);
374 gst_cmml_track_list_get_track_last_clip (GHashTable * tracks,
375 const gchar * track_name)
380 g_return_val_if_fail (track_name != NULL, NULL);
382 track = g_hash_table_lookup (tracks, track_name);
383 if (track && track->clips)
384 res = g_list_last (track->clips);
386 return res ? GST_CMML_TAG_CLIP (res->data) : NULL;
390 gst_cmml_track_list_set_data (GHashTable * tracks,
391 const gchar * track_name, gpointer data)
395 g_return_if_fail (track_name != NULL);
397 track = g_hash_table_lookup (tracks, track_name);
399 track->user_data = data;
403 gst_cmml_track_get_data (GHashTable * tracks, const gchar * track_name)
407 g_return_val_if_fail (track_name != NULL, NULL);
409 track = g_hash_table_lookup (tracks, track_name);
410 return track ? track->user_data : NULL;