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"
37 gst_cmml_clock_time_from_npt (const gchar * time)
45 GstClockTime hours_t = 0, seconds_t = 0;
47 if (!strncmp (time, "npt:", 4))
50 /* parse npt-hhmmss */
51 fields = sscanf (time, "%d:%d:%d.%d", &hours, &minutes, &seconds, &mseconds);
53 if (hours < 0 || (guint) minutes > 59 || (guint) seconds > 59)
56 hours_t = gst_util_uint64_scale (hours, GST_SECOND * 3600, 1);
57 if (hours_t == G_MAXUINT64)
60 seconds_t = seconds * GST_SECOND;
67 fields = sscanf (time, "%" G_GUINT64_FORMAT ".%d", &u64seconds, &mseconds);
71 seconds_t = gst_util_uint64_scale_int (u64seconds, GST_SECOND, 1);
72 if (seconds_t == G_MAXUINT64)
76 if ((guint) mseconds > 999)
79 res = (minutes * 60) * GST_SECOND + mseconds * GST_MSECOND;
80 if (G_MAXUINT64 - hours_t - seconds_t < res)
83 res += hours_t + seconds_t;
89 return GST_CLOCK_TIME_NONE;
93 gst_cmml_clock_time_from_smpte (const gchar * time)
97 gint hours, minutes, seconds;
102 if (!strncmp (time, "smpte-24:", 9)) {
105 } else if (!strncmp (time, "smpte-24-drop:", 14)) {
108 } else if (!strncmp (time, "smpte-25:", 9)) {
111 } else if (!strncmp (time, "smpte-30:", 9)) {
114 } else if (!strncmp (time, "smpte-30-drop:", 14)) {
117 } else if (!strncmp (time, "smpte-50:", 9)) {
120 } else if (!strncmp (time, "smpte-60:", 9)) {
123 } else if (!strncmp (time, "smpte-60-drop:", 14)) {
127 return GST_CLOCK_TIME_NONE;
130 fields = sscanf (time, "%d:%d:%d:%f", &hours, &minutes, &seconds, &frames);
132 if (hours < 0 || (guint) minutes > 59 || (guint) seconds > 59 ||
133 frames < 0 || frames > ceil (framerate)) {
134 res = GST_CLOCK_TIME_NONE;
136 hours_t = gst_util_uint64_scale (hours, GST_SECOND * 3600, 1);
137 if (hours_t == G_MAXUINT64)
140 res = ((minutes * 60) + seconds + (frames / framerate))
142 if (G_MAXUINT64 - hours_t < res)
148 res = GST_CLOCK_TIME_NONE;
153 return GST_CLOCK_TIME_NONE;
157 gst_cmml_clock_time_to_npt (const GstClockTime time)
159 guint seconds, hours, minutes, mseconds;
162 g_return_val_if_fail (time != GST_CLOCK_TIME_NONE, NULL);
164 hours = time / (GST_SECOND * 3600);
165 minutes = (time / ((GST_SECOND * 60)) % 60);
166 seconds = (time / GST_SECOND) % 60;
167 mseconds = (time % GST_SECOND) / GST_MSECOND;
172 res = g_strdup_printf ("%u:%02u:%02u.%03u",
173 hours, minutes, seconds, mseconds);
179 gst_cmml_clock_time_to_granule (GstClockTime prev_time,
180 GstClockTime current_time, gint64 granulerate_n, gint64 granulerate_d,
183 guint64 keyindex, keyoffset, granulepos, maxoffset;
186 g_return_val_if_fail (granulerate_d != 0, -1);
187 g_return_val_if_fail (granuleshift > 0, -1);
188 g_return_val_if_fail (granuleshift <= 64, -1);
190 if (prev_time == GST_CLOCK_TIME_NONE)
193 if (prev_time > current_time)
196 /* GST_SECOND / (granulerate_n / granulerate_d) */
197 granulerate = gst_util_uint64_scale (GST_SECOND,
198 granulerate_d, granulerate_n);
200 prev_time = prev_time / granulerate;
202 /* granuleshift == 64 should be a << 0 shift, which is defined */
203 maxoffset = ((guint64) 1 << (64 - granuleshift)) - 1;
204 if (prev_time > maxoffset)
205 /* we need more than 64 - granuleshift bits to encode prev_time */
208 keyindex = prev_time << granuleshift;
210 keyoffset = (current_time / granulerate) - prev_time;
211 /* make sure we don't shift to the limits of the types as this is undefined. */
212 if (granuleshift == 64)
213 maxoffset = G_MAXUINT64;
215 maxoffset = ((guint64) 1 << granuleshift) - 1;
217 if (keyoffset > maxoffset)
218 /* we need more than granuleshift bits to encode prev_time - current_time */
221 granulepos = keyindex + keyoffset;
231 gst_cmml_track_list_new (void)
233 return g_hash_table_new (g_str_hash, g_str_equal);
237 gst_cmml_track_list_destroy_track (gchar * key,
238 GstCmmlTrack * track, gpointer user_data)
242 for (walk = track->clips; walk; walk = g_list_next (walk))
243 g_object_unref (G_OBJECT (walk->data));
246 g_list_free (track->clips);
253 gst_cmml_track_list_destroy (GHashTable * tracks)
255 g_hash_table_foreach_remove (tracks,
256 (GHRFunc) gst_cmml_track_list_destroy_track, NULL);
257 g_hash_table_destroy (tracks);
261 gst_cmml_track_list_compare_clips (GstCmmlTagClip * a, GstCmmlTagClip * b)
263 if (a->start_time < b->start_time)
270 gst_cmml_track_list_add_clip (GHashTable * tracks, GstCmmlTagClip * clip)
276 g_return_if_fail (clip->track != NULL);
278 if (g_hash_table_lookup_extended (tracks, clip->track, &key, &value)) {
279 track_name = (gchar *) key;
280 track = (GstCmmlTrack *) value;
282 track_name = g_strdup ((gchar *) clip->track);
283 track = g_new0 (GstCmmlTrack, 1);
284 g_hash_table_insert (tracks, track_name, track);
287 /* add clip to the tracklist */
288 track->clips = g_list_insert_sorted (track->clips, g_object_ref (clip),
289 (GCompareFunc) gst_cmml_track_list_compare_clips);
293 gst_cmml_track_list_del_clip (GHashTable * tracks, GstCmmlTagClip * clip)
297 gboolean res = FALSE;
299 g_return_val_if_fail (clip->track != NULL, FALSE);
301 track = g_hash_table_lookup (tracks, clip->track);
303 link = g_list_find (track->clips, clip);
305 g_object_unref (G_OBJECT (link->data));
306 track->clips = g_list_delete_link (track->clips, link);
315 gst_cmml_track_list_has_clip (GHashTable * tracks, GstCmmlTagClip * clip)
320 gboolean res = FALSE;
322 track = g_hash_table_lookup (tracks, (gchar *) clip->track);
324 for (walk = track->clips; walk; walk = g_list_next (walk)) {
325 tmp = GST_CMML_TAG_CLIP (walk->data);
326 if (tmp->start_time == clip->start_time) {
337 gst_cmml_track_list_merge_track (gchar * track_name,
338 GstCmmlTrack * track, GList ** list)
343 for (walk = track->clips; walk; walk = g_list_next (walk)) {
344 cur = GST_CMML_TAG_CLIP (walk->data);
345 *list = g_list_insert_sorted (*list, cur,
346 (GCompareFunc) gst_cmml_track_list_compare_clips);
353 gst_cmml_track_list_get_track_clips (GHashTable * tracks,
354 const gchar * track_name)
358 g_return_val_if_fail (track_name != NULL, NULL);
360 track = g_hash_table_lookup (tracks, track_name);
361 return track ? track->clips : NULL;
365 gst_cmml_track_list_get_clips (GHashTable * tracks)
369 g_hash_table_foreach (tracks,
370 (GHFunc) gst_cmml_track_list_merge_track, &list);
375 gst_cmml_track_list_get_track_last_clip (GHashTable * tracks,
376 const gchar * track_name)
381 g_return_val_if_fail (track_name != NULL, NULL);
383 track = g_hash_table_lookup (tracks, track_name);
384 if (track && track->clips)
385 res = g_list_last (track->clips);
387 return res ? GST_CMML_TAG_CLIP (res->data) : NULL;