Blame gst-libs/gst/video/gstvideotimecode.c

Packit 971217
/* GStreamer
Packit 971217
 * Copyright (C) <2016> Vivia Nikolaidou <vivia@toolsonair.com>
Packit 971217
 *
Packit 971217
 * This library is free software; you can redistribute it and/or
Packit 971217
 * modify it under the terms of the GNU Library General Public
Packit 971217
 * License as published by the Free Software Foundation; either
Packit 971217
 * version 2 of the License, or (at your option) any later version.
Packit 971217
 *
Packit 971217
 * This library is distributed in the hope that it will be useful,
Packit 971217
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 971217
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 971217
 * Library General Public License for more details.
Packit 971217
 *
Packit 971217
 * You should have received a copy of the GNU Library General Public
Packit 971217
 * License along with this library; if not, write to the
Packit 971217
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 971217
 * Boston, MA 02110-1301, USA.
Packit 971217
 */
Packit 971217
Packit 971217
#include <stdio.h>
Packit 971217
#include "gstvideotimecode.h"
Packit 971217
Packit 971217
static void
Packit 971217
gst_video_time_code_gvalue_to_string (const GValue * tc_val, GValue * str_val);
Packit 971217
static void
Packit 971217
gst_video_time_code_gvalue_from_string (const GValue * str_val,
Packit 971217
    GValue * tc_val);
Packit 971217
static gboolean gst_video_time_code_deserialize (GValue * dest,
Packit 971217
    const gchar * tc_str);
Packit 971217
static gchar *gst_video_time_code_serialize (const GValue * val);
Packit 971217
Packit 971217
static void
Packit 971217
_init (GType type)
Packit 971217
{
Packit 971217
  static GstValueTable table =
Packit 971217
      { 0, (GstValueCompareFunc) gst_video_time_code_compare,
Packit 971217
    (GstValueSerializeFunc) gst_video_time_code_serialize,
Packit 971217
    (GstValueDeserializeFunc) gst_video_time_code_deserialize
Packit 971217
  };
Packit 971217
Packit 971217
  table.type = type;
Packit 971217
  gst_value_register (&table);
Packit 971217
  g_value_register_transform_func (type, G_TYPE_STRING,
Packit 971217
      (GValueTransform) gst_video_time_code_gvalue_to_string);
Packit 971217
  g_value_register_transform_func (G_TYPE_STRING, type,
Packit 971217
      (GValueTransform) gst_video_time_code_gvalue_from_string);
Packit 971217
}
Packit 971217
Packit 971217
G_DEFINE_BOXED_TYPE_WITH_CODE (GstVideoTimeCode, gst_video_time_code,
Packit 971217
    (GBoxedCopyFunc) gst_video_time_code_copy,
Packit 971217
    (GBoxedFreeFunc) gst_video_time_code_free, _init (g_define_type_id));
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_is_valid:
Packit 971217
 * @tc: #GstVideoTimeCode to check
Packit 971217
 *
Packit 971217
 * Returns: whether @tc is a valid timecode (supported frame rate,
Packit 971217
 * hours/minutes/seconds/frames not overflowing)
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_video_time_code_is_valid (const GstVideoTimeCode * tc)
Packit 971217
{
Packit 971217
  guint fr;
Packit 971217
Packit 971217
  g_return_val_if_fail (tc != NULL, FALSE);
Packit 971217
Packit 971217
  fr = (tc->config.fps_n + (tc->config.fps_d >> 1)) / tc->config.fps_d;
Packit 971217
Packit 971217
  if (tc->hours >= 24)
Packit 971217
    return FALSE;
Packit 971217
  if (tc->minutes >= 60)
Packit 971217
    return FALSE;
Packit 971217
  if (tc->seconds >= 60)
Packit 971217
    return FALSE;
Packit 971217
  if (tc->config.fps_d == 0)
Packit 971217
    return FALSE;
Packit 971217
  if (tc->frames >= fr && (tc->config.fps_n != 0 || tc->config.fps_d != 1))
Packit 971217
    return FALSE;
Packit 971217
  if (tc->config.fps_d == 1001) {
Packit 971217
    if (tc->config.fps_n != 30000 && tc->config.fps_n != 60000 &&
Packit 971217
        tc->config.fps_n != 24000)
Packit 971217
      return FALSE;
Packit 971217
  } else if (tc->config.fps_n % tc->config.fps_d != 0) {
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
  if ((tc->config.flags & GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME) &&
Packit 971217
      tc->minutes % 10 && tc->seconds == 0 && tc->frames < fr / 15) {
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_to_string:
Packit 971217
 * @tc: #GstVideoTimeCode to convert
Packit 971217
 *
Packit 971217
 * Returns: the SMPTE ST 2059-1:2015 string representation of @tc. That will
Packit 971217
 * take the form hh:mm:ss:ff . The last separator (between seconds and frames)
Packit 971217
 * may vary:
Packit 971217
 *
Packit 971217
 * ';' for drop-frame, non-interlaced content and for drop-frame interlaced
Packit 971217
 * field 2
Packit 971217
 * ',' for drop-frame interlaced field 1
Packit 971217
 * ':' for non-drop-frame, non-interlaced content and for non-drop-frame
Packit 971217
 * interlaced field 2
Packit 971217
 * '.' for non-drop-frame interlaced field 1
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
gchar *
Packit 971217
gst_video_time_code_to_string (const GstVideoTimeCode * tc)
Packit 971217
{
Packit 971217
  gchar *ret;
Packit 971217
  gboolean top_dot_present;
Packit 971217
  gchar sep;
Packit 971217
Packit 971217
  /* Top dot is present for non-interlaced content, and for field 2 in
Packit 971217
   * interlaced content */
Packit 971217
  top_dot_present =
Packit 971217
      !((tc->config.flags & GST_VIDEO_TIME_CODE_FLAGS_INTERLACED) != 0
Packit 971217
      && tc->field_count == 1);
Packit 971217
Packit 971217
  if (tc->config.flags & GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME)
Packit 971217
    sep = top_dot_present ? ';' : ',';
Packit 971217
  else
Packit 971217
    sep = top_dot_present ? ':' : '.';
Packit 971217
Packit 971217
  ret =
Packit 971217
      g_strdup_printf ("%02d:%02d:%02d%c%02d", tc->hours, tc->minutes,
Packit 971217
      tc->seconds, sep, tc->frames);
Packit 971217
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_to_date_time:
Packit 971217
 * @tc: A valid #GstVideoTimeCode to convert
Packit 971217
 *
Packit 971217
 * The @tc.config->latest_daily_jam is required to be non-NULL.
Packit 971217
 *
Packit 971217
 * Returns: the #GDateTime representation of @tc.
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
GDateTime *
Packit 971217
gst_video_time_code_to_date_time (const GstVideoTimeCode * tc)
Packit 971217
{
Packit 971217
  GDateTime *ret;
Packit 971217
  GDateTime *ret2;
Packit 971217
  gdouble add_us;
Packit 971217
Packit 971217
  g_return_val_if_fail (gst_video_time_code_is_valid (tc), NULL);
Packit 971217
  g_return_val_if_fail (tc->config.latest_daily_jam != NULL, NULL);
Packit 971217
Packit 971217
  ret = g_date_time_ref (tc->config.latest_daily_jam);
Packit 971217
Packit 971217
  if (ret == NULL) {
Packit 971217
    gchar *tc_str = gst_video_time_code_to_string (tc);
Packit 971217
    GST_WARNING
Packit 971217
        ("Asked to convert time code %s to GDateTime, but its latest daily jam is NULL",
Packit 971217
        tc_str);
Packit 971217
    g_free (tc_str);
Packit 971217
    g_date_time_unref (ret);
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
Packit 971217
  if (tc->config.fps_n == 0 && tc->config.fps_d == 1) {
Packit 971217
    gchar *tc_str = gst_video_time_code_to_string (tc);
Packit 971217
    GST_WARNING
Packit 971217
        ("Asked to convert time code %s to GDateTime, but its framerate is unknown",
Packit 971217
        tc_str);
Packit 971217
    g_free (tc_str);
Packit 971217
    g_date_time_unref (ret);
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
Packit 971217
  gst_util_fraction_to_double (tc->frames * tc->config.fps_d, tc->config.fps_n,
Packit 971217
      &add_us);
Packit 971217
  if ((tc->config.flags & GST_VIDEO_TIME_CODE_FLAGS_INTERLACED)
Packit 971217
      && tc->field_count == 1) {
Packit 971217
    gdouble sub_us;
Packit 971217
Packit 971217
    gst_util_fraction_to_double (tc->config.fps_d, 2 * tc->config.fps_n,
Packit 971217
        &sub_us);
Packit 971217
    add_us -= sub_us;
Packit 971217
  }
Packit 971217
Packit 971217
  ret2 = g_date_time_add_seconds (ret, add_us + tc->seconds);
Packit 971217
  g_date_time_unref (ret);
Packit 971217
  ret = g_date_time_add_minutes (ret2, tc->minutes);
Packit 971217
  g_date_time_unref (ret2);
Packit 971217
  ret2 = g_date_time_add_hours (ret, tc->hours);
Packit 971217
  g_date_time_unref (ret);
Packit 971217
Packit 971217
  return ret2;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_init_from_date_time:
Packit 971217
 * @tc: a #GstVideoTimeCode
Packit 971217
 * @fps_n: Numerator of the frame rate
Packit 971217
 * @fps_d: Denominator of the frame rate
Packit 971217
 * @dt: #GDateTime to convert
Packit 971217
 * @flags: #GstVideoTimeCodeFlags
Packit 971217
 * @field_count: Interlaced video field count
Packit 971217
 *
Packit 971217
 * The resulting config->latest_daily_jam is set to
Packit 971217
 * midnight, and timecode is set to the given time.
Packit 971217
 *
Packit 971217
 * Since: 1.12
Packit 971217
 */
Packit 971217
Packit 971217
void
Packit 971217
gst_video_time_code_init_from_date_time (GstVideoTimeCode * tc,
Packit 971217
    guint fps_n, guint fps_d,
Packit 971217
    GDateTime * dt, GstVideoTimeCodeFlags flags, guint field_count)
Packit 971217
{
Packit 971217
  GDateTime *jam;
Packit 971217
  guint64 frames;
Packit 971217
  gboolean add_a_frame = FALSE;
Packit 971217
Packit 971217
  jam = g_date_time_new_local (g_date_time_get_year (dt),
Packit 971217
      g_date_time_get_month (dt), g_date_time_get_day_of_month (dt), 0, 0, 0.0);
Packit 971217
Packit 971217
  /* Note: This might be inaccurate for 1 frame
Packit 971217
   * in case we have a drop frame timecode */
Packit 971217
  frames =
Packit 971217
      gst_util_uint64_scale_round (g_date_time_get_microsecond (dt) *
Packit 971217
      G_GINT64_CONSTANT (1000), fps_n, fps_d * GST_SECOND);
Packit 971217
  if (G_UNLIKELY (((frames == fps_n) && (fps_d == 1)) ||
Packit 971217
          ((frames == fps_n / 1000) && (fps_d == 1001)))) {
Packit 971217
    /* Avoid invalid timecodes */
Packit 971217
    frames--;
Packit 971217
    add_a_frame = TRUE;
Packit 971217
  }
Packit 971217
Packit 971217
  gst_video_time_code_init (tc, fps_n, fps_d, jam, flags,
Packit 971217
      g_date_time_get_hour (dt), g_date_time_get_minute (dt),
Packit 971217
      g_date_time_get_second (dt), frames, field_count);
Packit 971217
Packit 971217
  if (tc->config.flags & GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME) {
Packit 971217
    guint df = (tc->config.fps_n + (tc->config.fps_d >> 1)) /
Packit 971217
        (15 * tc->config.fps_d);
Packit 971217
    if (tc->minutes % 10 && tc->seconds == 0 && tc->frames < df) {
Packit 971217
      tc->frames = df;
Packit 971217
    }
Packit 971217
  }
Packit 971217
  if (add_a_frame)
Packit 971217
    gst_video_time_code_increment_frame (tc);
Packit 971217
Packit 971217
  g_date_time_unref (jam);
Packit 971217
Packit 971217
  g_return_if_fail (gst_video_time_code_is_valid (tc));
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_nsec_since_daily_jam:
Packit 971217
 * @tc: a valid #GstVideoTimeCode
Packit 971217
 *
Packit 971217
 * Returns: how many nsec have passed since the daily jam of @tc .
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
guint64
Packit 971217
gst_video_time_code_nsec_since_daily_jam (const GstVideoTimeCode * tc)
Packit 971217
{
Packit 971217
  guint64 frames, nsec;
Packit 971217
Packit 971217
  g_return_val_if_fail (gst_video_time_code_is_valid (tc), -1);
Packit 971217
Packit 971217
  if (tc->config.fps_n == 0 && tc->config.fps_d == 1) {
Packit 971217
    gchar *tc_str = gst_video_time_code_to_string (tc);
Packit 971217
    GST_WARNING
Packit 971217
        ("Asked to calculate nsec since daily jam of time code %s, but its framerate is unknown",
Packit 971217
        tc_str);
Packit 971217
    g_free (tc_str);
Packit 971217
    return -1;
Packit 971217
  }
Packit 971217
Packit 971217
  frames = gst_video_time_code_frames_since_daily_jam (tc);
Packit 971217
  nsec =
Packit 971217
      gst_util_uint64_scale (frames, GST_SECOND * tc->config.fps_d,
Packit 971217
      tc->config.fps_n);
Packit 971217
Packit 971217
  return nsec;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_frames_since_daily_jam:
Packit 971217
 * @tc: a valid #GstVideoTimeCode
Packit 971217
 *
Packit 971217
 * Returns: how many frames have passed since the daily jam of @tc .
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
guint64
Packit 971217
gst_video_time_code_frames_since_daily_jam (const GstVideoTimeCode * tc)
Packit 971217
{
Packit 971217
  guint ff_nom;
Packit 971217
  gdouble ff;
Packit 971217
Packit 971217
  g_return_val_if_fail (gst_video_time_code_is_valid (tc), -1);
Packit 971217
Packit 971217
  gst_util_fraction_to_double (tc->config.fps_n, tc->config.fps_d, &ff);
Packit 971217
  if (tc->config.fps_d == 1001) {
Packit 971217
    ff_nom = tc->config.fps_n / 1000;
Packit 971217
  } else {
Packit 971217
    ff_nom = ff;
Packit 971217
  }
Packit 971217
  if (tc->config.flags & GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME) {
Packit 971217
    /* these need to be truncated to integer: side effect, code looks cleaner
Packit 971217
     * */
Packit 971217
    guint ff_minutes = 60 * ff;
Packit 971217
    guint ff_hours = 3600 * ff;
Packit 971217
    /* for 30000/1001 we drop the first 2 frames per minute, for 60000/1001 we
Packit 971217
     * drop the first 4 : so we use this number */
Packit 971217
    guint dropframe_multiplier;
Packit 971217
Packit 971217
    if (tc->config.fps_n == 30000) {
Packit 971217
      dropframe_multiplier = 2;
Packit 971217
    } else if (tc->config.fps_n == 60000) {
Packit 971217
      dropframe_multiplier = 4;
Packit 971217
    } else {
Packit 971217
      GST_ERROR ("Unsupported drop frame rate %u/%u", tc->config.fps_n,
Packit 971217
          tc->config.fps_d);
Packit 971217
      return -1;
Packit 971217
    }
Packit 971217
Packit 971217
    return tc->frames + (ff_nom * tc->seconds) +
Packit 971217
        (ff_minutes * tc->minutes) +
Packit 971217
        dropframe_multiplier * ((gint) (tc->minutes / 10)) +
Packit 971217
        (ff_hours * tc->hours);
Packit 971217
  } else {
Packit 971217
    return tc->frames + (ff_nom * (tc->seconds + (60 * (tc->minutes +
Packit 971217
                    (60 * tc->hours)))));
Packit 971217
  }
Packit 971217
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_increment_frame:
Packit 971217
 * @tc: a valid #GstVideoTimeCode
Packit 971217
 *
Packit 971217
 * Adds one frame to @tc .
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_video_time_code_increment_frame (GstVideoTimeCode * tc)
Packit 971217
{
Packit 971217
  gst_video_time_code_add_frames (tc, 1);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_add_frames:
Packit 971217
 * @tc: a valid #GstVideoTimeCode
Packit 971217
 * @frames: How many frames to add or subtract
Packit 971217
 *
Packit 971217
 * Adds or subtracts @frames amount of frames to @tc. tc needs to
Packit 971217
 * contain valid data, as verified by #gst_video_time_code_is_valid.
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_video_time_code_add_frames (GstVideoTimeCode * tc, gint64 frames)
Packit 971217
{
Packit 971217
  guint64 framecount;
Packit 971217
  guint64 h_notmod24;
Packit 971217
  guint64 h_new, min_new, sec_new, frames_new;
Packit 971217
  gdouble ff;
Packit 971217
  guint ff_nom;
Packit 971217
  /* This allows for better readability than putting G_GUINT64_CONSTANT(60)
Packit 971217
   * into a long calculation line */
Packit 971217
  const guint64 sixty = 60;
Packit 971217
  /* formulas found in SMPTE ST 2059-1:2015 section 9.4.3
Packit 971217
   * and adapted for 60/1.001 as well as 30/1.001 */
Packit 971217
Packit 971217
  g_return_if_fail (gst_video_time_code_is_valid (tc));
Packit 971217
Packit 971217
  gst_util_fraction_to_double (tc->config.fps_n, tc->config.fps_d, &ff);
Packit 971217
  if (tc->config.fps_d == 1001) {
Packit 971217
    ff_nom = tc->config.fps_n / 1000;
Packit 971217
  } else {
Packit 971217
    ff_nom = ff;
Packit 971217
    if (tc->config.fps_d != 1)
Packit 971217
      GST_WARNING ("Unsupported frame rate %u/%u, results may be wrong",
Packit 971217
          tc->config.fps_n, tc->config.fps_d);
Packit 971217
  }
Packit 971217
  if (tc->config.flags & GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME) {
Packit 971217
    /* these need to be truncated to integer: side effect, code looks cleaner
Packit 971217
     * */
Packit 971217
    guint ff_minutes = 60 * ff;
Packit 971217
    guint ff_hours = 3600 * ff;
Packit 971217
    /* a bunch of intermediate variables, to avoid monster code with possible
Packit 971217
     * integer overflows */
Packit 971217
    guint64 min_new_tmp1, min_new_tmp2, min_new_tmp3, min_new_denom;
Packit 971217
    /* for 30000/1001 we drop the first 2 frames per minute, for 60000/1001 we
Packit 971217
     * drop the first 4 : so we use this number */
Packit 971217
    guint dropframe_multiplier;
Packit 971217
Packit 971217
    if (tc->config.fps_n == 30000)
Packit 971217
      dropframe_multiplier = 2;
Packit 971217
    else if (tc->config.fps_n == 60000)
Packit 971217
      dropframe_multiplier = 4;
Packit 971217
    else {
Packit 971217
      GST_ERROR ("Unsupported drop frame rate %u/%u", tc->config.fps_n,
Packit 971217
          tc->config.fps_d);
Packit 971217
      return;
Packit 971217
    }
Packit 971217
Packit 971217
    framecount =
Packit 971217
        frames + tc->frames + (ff_nom * tc->seconds) +
Packit 971217
        (ff_minutes * tc->minutes) +
Packit 971217
        dropframe_multiplier * ((gint) (tc->minutes / 10)) +
Packit 971217
        (ff_hours * tc->hours);
Packit 971217
    h_notmod24 = gst_util_uint64_scale_int (framecount, 1, ff_hours);
Packit 971217
Packit 971217
    min_new_denom = sixty * ff_nom;
Packit 971217
    min_new_tmp1 = (framecount - (h_notmod24 * ff_hours)) / min_new_denom;
Packit 971217
    min_new_tmp2 = framecount + dropframe_multiplier * min_new_tmp1;
Packit 971217
    min_new_tmp1 =
Packit 971217
        (framecount - (h_notmod24 * ff_hours)) / (sixty * 10 * ff_nom);
Packit 971217
    min_new_tmp3 =
Packit 971217
        dropframe_multiplier * min_new_tmp1 + (h_notmod24 * ff_hours);
Packit 971217
    min_new =
Packit 971217
        gst_util_uint64_scale_int (min_new_tmp2 - min_new_tmp3, 1,
Packit 971217
        min_new_denom);
Packit 971217
Packit 971217
    sec_new =
Packit 971217
        (guint64) ((framecount - (ff_minutes * min_new) -
Packit 971217
            dropframe_multiplier * ((gint) (min_new / 10)) -
Packit 971217
            (ff_hours * h_notmod24)) / ff_nom);
Packit 971217
Packit 971217
    frames_new =
Packit 971217
        framecount - (ff_nom * sec_new) - (ff_minutes * min_new) -
Packit 971217
        (dropframe_multiplier * ((gint) (min_new / 10))) -
Packit 971217
        (ff_hours * h_notmod24);
Packit 971217
  } else {
Packit 971217
    framecount =
Packit 971217
        frames + tc->frames + (ff_nom * (tc->seconds + (sixty * (tc->minutes +
Packit 971217
                    (sixty * tc->hours)))));
Packit 971217
    h_notmod24 =
Packit 971217
        gst_util_uint64_scale_int (framecount, 1, ff_nom * sixty * sixty);
Packit 971217
    min_new =
Packit 971217
        gst_util_uint64_scale_int ((framecount -
Packit 971217
            (ff_nom * sixty * sixty * h_notmod24)), 1, (ff_nom * sixty));
Packit 971217
    sec_new =
Packit 971217
        gst_util_uint64_scale_int ((framecount - (ff_nom * sixty * (min_new +
Packit 971217
                    (sixty * h_notmod24)))), 1, ff_nom);
Packit 971217
    frames_new =
Packit 971217
        framecount - (ff_nom * (sec_new + sixty * (min_new +
Packit 971217
                (sixty * h_notmod24))));
Packit 971217
    if (frames_new > ff_nom)
Packit 971217
      frames_new = 0;
Packit 971217
  }
Packit 971217
  h_new = h_notmod24 % 24;
Packit 971217
Packit 971217
  g_assert (min_new < 60);
Packit 971217
  g_assert (sec_new < 60);
Packit 971217
  g_assert (frames_new < ff_nom);
Packit 971217
  tc->hours = h_new;
Packit 971217
  tc->minutes = min_new;
Packit 971217
  tc->seconds = sec_new;
Packit 971217
  tc->frames = frames_new;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_compare:
Packit 971217
 * @tc1: a #GstVideoTimeCode
Packit 971217
 * @tc2: another #GstVideoTimeCode
Packit 971217
 *
Packit 971217
 * Compares @tc1 and @tc2 . If both have latest daily jam information, it is
Packit 971217
 * taken into account. Otherwise, it is assumed that the daily jam of both
Packit 971217
 * @tc1 and @tc2 was at the same time. Both time codes must be valid.
Packit 971217
 *
Packit 971217
 * Returns: 1 if @tc1 is after @tc2, -1 if @tc1 is before @tc2, 0 otherwise.
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
gint
Packit 971217
gst_video_time_code_compare (const GstVideoTimeCode * tc1,
Packit 971217
    const GstVideoTimeCode * tc2)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (gst_video_time_code_is_valid (tc1), -1);
Packit 971217
  g_return_val_if_fail (gst_video_time_code_is_valid (tc2), -1);
Packit 971217
Packit 971217
  if (tc1->config.latest_daily_jam == NULL
Packit 971217
      || tc2->config.latest_daily_jam == NULL) {
Packit 971217
    guint64 nsec1, nsec2;
Packit 971217
#ifndef GST_DISABLE_GST_DEBUG
Packit 971217
    gchar *str1, *str2;
Packit 971217
Packit 971217
    str1 = gst_video_time_code_to_string (tc1);
Packit 971217
    str2 = gst_video_time_code_to_string (tc2);
Packit 971217
    GST_INFO
Packit 971217
        ("Comparing time codes %s and %s, but at least one of them has no "
Packit 971217
        "latest daily jam information. Assuming they started together",
Packit 971217
        str1, str2);
Packit 971217
    g_free (str1);
Packit 971217
    g_free (str2);
Packit 971217
#endif
Packit 971217
    if (tc1->hours > tc2->hours) {
Packit 971217
      return 1;
Packit 971217
    } else if (tc1->hours < tc2->hours) {
Packit 971217
      return -1;
Packit 971217
    }
Packit 971217
    if (tc1->minutes > tc2->minutes) {
Packit 971217
      return 1;
Packit 971217
    } else if (tc1->minutes < tc2->minutes) {
Packit 971217
      return -1;
Packit 971217
    }
Packit 971217
    if (tc1->seconds > tc2->seconds) {
Packit 971217
      return 1;
Packit 971217
    } else if (tc1->seconds < tc2->seconds) {
Packit 971217
      return -1;
Packit 971217
    }
Packit 971217
Packit 971217
    nsec1 =
Packit 971217
        gst_util_uint64_scale (GST_SECOND,
Packit 971217
        tc1->frames * tc1->config.fps_n, tc1->config.fps_d);
Packit 971217
    nsec2 =
Packit 971217
        gst_util_uint64_scale (GST_SECOND,
Packit 971217
        tc2->frames * tc2->config.fps_n, tc2->config.fps_d);
Packit 971217
    if (nsec1 > nsec2) {
Packit 971217
      return 1;
Packit 971217
    } else if (nsec1 < nsec2) {
Packit 971217
      return -1;
Packit 971217
    }
Packit 971217
    if (tc1->config.flags & GST_VIDEO_TIME_CODE_FLAGS_INTERLACED) {
Packit 971217
      if (tc1->field_count > tc2->field_count)
Packit 971217
        return 1;
Packit 971217
      else if (tc1->field_count < tc2->field_count)
Packit 971217
        return -1;
Packit 971217
    }
Packit 971217
    return 0;
Packit 971217
  } else {
Packit 971217
    GDateTime *dt1, *dt2;
Packit 971217
    gint ret;
Packit 971217
Packit 971217
    dt1 = gst_video_time_code_to_date_time (tc1);
Packit 971217
    dt2 = gst_video_time_code_to_date_time (tc2);
Packit 971217
Packit 971217
    ret = g_date_time_compare (dt1, dt2);
Packit 971217
Packit 971217
    g_date_time_unref (dt1);
Packit 971217
    g_date_time_unref (dt2);
Packit 971217
Packit 971217
    return ret;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_new:
Packit 971217
 * @fps_n: Numerator of the frame rate
Packit 971217
 * @fps_d: Denominator of the frame rate
Packit 971217
 * @latest_daily_jam: The latest daily jam of the #GstVideoTimeCode
Packit 971217
 * @flags: #GstVideoTimeCodeFlags
Packit 971217
 * @hours: the hours field of #GstVideoTimeCode
Packit 971217
 * @minutes: the minutes field of #GstVideoTimeCode
Packit 971217
 * @seconds: the seconds field of #GstVideoTimeCode
Packit 971217
 * @frames: the frames field of #GstVideoTimeCode
Packit 971217
 * @field_count: Interlaced video field count
Packit 971217
 *
Packit 971217
 * @field_count is 0 for progressive, 1 or 2 for interlaced.
Packit 971217
 * @latest_daiy_jam reference is stolen from caller.
Packit 971217
 *
Packit 971217
 * Returns: a new #GstVideoTimeCode with the given values.
Packit 971217
 * The values are not checked for being in a valid range. To see if your
Packit 971217
 * timecode actually has valid content, use #gst_video_time_code_is_valid.
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
GstVideoTimeCode *
Packit 971217
gst_video_time_code_new (guint fps_n, guint fps_d, GDateTime * latest_daily_jam,
Packit 971217
    GstVideoTimeCodeFlags flags, guint hours, guint minutes, guint seconds,
Packit 971217
    guint frames, guint field_count)
Packit 971217
{
Packit 971217
  GstVideoTimeCode *tc;
Packit 971217
Packit 971217
  tc = g_new0 (GstVideoTimeCode, 1);
Packit 971217
  gst_video_time_code_init (tc, fps_n, fps_d, latest_daily_jam, flags, hours,
Packit 971217
      minutes, seconds, frames, field_count);
Packit 971217
  return tc;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_new_empty:
Packit 971217
 *
Packit 971217
 * Returns: a new empty #GstVideoTimeCode
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
GstVideoTimeCode *
Packit 971217
gst_video_time_code_new_empty (void)
Packit 971217
{
Packit 971217
  GstVideoTimeCode *tc;
Packit 971217
Packit 971217
  tc = g_new0 (GstVideoTimeCode, 1);
Packit 971217
  gst_video_time_code_clear (tc);
Packit 971217
  return tc;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_video_time_code_gvalue_from_string (const GValue * str_val, GValue * tc_val)
Packit 971217
{
Packit 971217
  const gchar *tc_str = g_value_get_string (str_val);
Packit 971217
  GstVideoTimeCode *tc;
Packit 971217
Packit 971217
  tc = gst_video_time_code_new_from_string (tc_str);
Packit 971217
  g_value_take_boxed (tc_val, tc);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_video_time_code_gvalue_to_string (const GValue * tc_val, GValue * str_val)
Packit 971217
{
Packit 971217
  const GstVideoTimeCode *tc = g_value_get_boxed (tc_val);
Packit 971217
  gchar *tc_str;
Packit 971217
Packit 971217
  tc_str = gst_video_time_code_to_string (tc);
Packit 971217
  g_value_take_string (str_val, tc_str);
Packit 971217
}
Packit 971217
Packit 971217
static gchar *
Packit 971217
gst_video_time_code_serialize (const GValue * val)
Packit 971217
{
Packit 971217
  GstVideoTimeCode *tc = g_value_get_boxed (val);
Packit 971217
  return gst_video_time_code_to_string (tc);
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
gst_video_time_code_deserialize (GValue * dest, const gchar * tc_str)
Packit 971217
{
Packit 971217
  GstVideoTimeCode *tc = gst_video_time_code_new_from_string (tc_str);
Packit 971217
Packit 971217
  if (tc == NULL || !gst_video_time_code_is_valid (tc))
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  g_value_take_boxed (dest, tc);
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_new_from_string:
Packit 971217
 * @tc_str: The string that represents the #GstVideoTimeCode
Packit 971217
 *
Packit 971217
 * Returns: a new #GstVideoTimeCode from the given string
Packit 971217
 *
Packit 971217
 * Since: 1.12
Packit 971217
 */
Packit 971217
GstVideoTimeCode *
Packit 971217
gst_video_time_code_new_from_string (const gchar * tc_str)
Packit 971217
{
Packit 971217
  GstVideoTimeCode *tc;
Packit 971217
  guint hours, minutes, seconds, frames;
Packit 971217
Packit 971217
  if (sscanf (tc_str, "%02u:%02u:%02u:%02u", &hours, &minutes, &seconds,
Packit 971217
          &frames)
Packit 971217
      == 4
Packit 971217
      || sscanf (tc_str, "%02u:%02u:%02u;%02u", &hours, &minutes, &seconds,
Packit 971217
          &frames)
Packit 971217
      == 4
Packit 971217
      || sscanf (tc_str, "%02u:%02u:%02u.%02u", &hours, &minutes, &seconds,
Packit 971217
          &frames)
Packit 971217
      == 4
Packit 971217
      || sscanf (tc_str, "%02u:%02u:%02u,%02u", &hours, &minutes, &seconds,
Packit 971217
          &frames)
Packit 971217
      == 4) {
Packit 971217
    tc = gst_video_time_code_new (0, 1, NULL, GST_VIDEO_TIME_CODE_FLAGS_NONE,
Packit 971217
        hours, minutes, seconds, frames, 0);
Packit 971217
Packit 971217
    return tc;
Packit 971217
  } else {
Packit 971217
    GST_ERROR ("Warning: Could not parse timecode %s. "
Packit 971217
        "Please input a timecode in the form 00:00:00:00", tc_str);
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_new_from_date_time:
Packit 971217
 * @fps_n: Numerator of the frame rate
Packit 971217
 * @fps_d: Denominator of the frame rate
Packit 971217
 * @dt: #GDateTime to convert
Packit 971217
 * @flags: #GstVideoTimeCodeFlags
Packit 971217
 * @field_count: Interlaced video field count
Packit 971217
 *
Packit 971217
 * The resulting config->latest_daily_jam is set to
Packit 971217
 * midnight, and timecode is set to the given time.
Packit 971217
 *
Packit 971217
 * Returns: the #GVideoTimeCode representation of @dt.
Packit 971217
 *
Packit 971217
 * Since: 1.12
Packit 971217
 */
Packit 971217
GstVideoTimeCode *
Packit 971217
gst_video_time_code_new_from_date_time (guint fps_n, guint fps_d,
Packit 971217
    GDateTime * dt, GstVideoTimeCodeFlags flags, guint field_count)
Packit 971217
{
Packit 971217
  GstVideoTimeCode *tc;
Packit 971217
  tc = gst_video_time_code_new_empty ();
Packit 971217
  gst_video_time_code_init_from_date_time (tc, fps_n, fps_d, dt, flags,
Packit 971217
      field_count);
Packit 971217
  return tc;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_init:
Packit 971217
 * @tc: a #GstVideoTimeCode
Packit 971217
 * @fps_n: Numerator of the frame rate
Packit 971217
 * @fps_d: Denominator of the frame rate
Packit 971217
 * @latest_daily_jam: The latest daily jam of the #GstVideoTimeCode
Packit 971217
 * @flags: #GstVideoTimeCodeFlags
Packit 971217
 * @hours: the hours field of #GstVideoTimeCode
Packit 971217
 * @minutes: the minutes field of #GstVideoTimeCode
Packit 971217
 * @seconds: the seconds field of #GstVideoTimeCode
Packit 971217
 * @frames: the frames field of #GstVideoTimeCode
Packit 971217
 * @field_count: Interlaced video field count
Packit 971217
 *
Packit 971217
 * @field_count is 0 for progressive, 1 or 2 for interlaced.
Packit 971217
 * @latest_daiy_jam reference is stolen from caller.
Packit 971217
 *
Packit 971217
 * Initializes @tc with the given values.
Packit 971217
 * The values are not checked for being in a valid range. To see if your
Packit 971217
 * timecode actually has valid content, use #gst_video_time_code_is_valid.
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_video_time_code_init (GstVideoTimeCode * tc, guint fps_n, guint fps_d,
Packit 971217
    GDateTime * latest_daily_jam, GstVideoTimeCodeFlags flags, guint hours,
Packit 971217
    guint minutes, guint seconds, guint frames, guint field_count)
Packit 971217
{
Packit 971217
  tc->hours = hours;
Packit 971217
  tc->minutes = minutes;
Packit 971217
  tc->seconds = seconds;
Packit 971217
  tc->frames = frames;
Packit 971217
  tc->field_count = field_count;
Packit 971217
  tc->config.fps_n = fps_n;
Packit 971217
  tc->config.fps_d = fps_d;
Packit 971217
  if (latest_daily_jam != NULL)
Packit 971217
    tc->config.latest_daily_jam = g_date_time_ref (latest_daily_jam);
Packit 971217
  else
Packit 971217
    tc->config.latest_daily_jam = NULL;
Packit 971217
  tc->config.flags = flags;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_clear:
Packit 971217
 * @tc: a #GstVideoTimeCode
Packit 971217
 *
Packit 971217
 * Initializes @tc with empty/zero/NULL values.
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_video_time_code_clear (GstVideoTimeCode * tc)
Packit 971217
{
Packit 971217
  tc->hours = 0;
Packit 971217
  tc->minutes = 0;
Packit 971217
  tc->seconds = 0;
Packit 971217
  tc->frames = 0;
Packit 971217
  tc->field_count = 0;
Packit 971217
  tc->config.fps_n = 0;
Packit 971217
  tc->config.fps_d = 1;
Packit 971217
  if (tc->config.latest_daily_jam != NULL)
Packit 971217
    g_date_time_unref (tc->config.latest_daily_jam);
Packit 971217
  tc->config.latest_daily_jam = NULL;
Packit 971217
  tc->config.flags = 0;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_copy:
Packit 971217
 * @tc: a #GstVideoTimeCode
Packit 971217
 *
Packit 971217
 * Returns: a new #GstVideoTimeCode with the same values as @tc .
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
GstVideoTimeCode *
Packit 971217
gst_video_time_code_copy (const GstVideoTimeCode * tc)
Packit 971217
{
Packit 971217
  return gst_video_time_code_new (tc->config.fps_n, tc->config.fps_d,
Packit 971217
      tc->config.latest_daily_jam, tc->config.flags, tc->hours, tc->minutes,
Packit 971217
      tc->seconds, tc->frames, tc->field_count);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_free:
Packit 971217
 * @tc: a #GstVideoTimeCode
Packit 971217
 *
Packit 971217
 * Frees @tc .
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_video_time_code_free (GstVideoTimeCode * tc)
Packit 971217
{
Packit 971217
  if (tc->config.latest_daily_jam != NULL)
Packit 971217
    g_date_time_unref (tc->config.latest_daily_jam);
Packit 971217
Packit 971217
  g_free (tc);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_add_interval:
Packit 971217
 * @tc: The #GstVideoTimeCode where the diff should be added. This
Packit 971217
 * must contain valid timecode values.
Packit 971217
 * @tc_inter: The #GstVideoTimeCodeInterval to add to @tc.
Packit 971217
 * The interval must contain valid values, except that for drop-frame
Packit 971217
 * timecode, it may also contain timecodes which would normally
Packit 971217
 * be dropped. These are then corrected to the next reasonable timecode.
Packit 971217
 *
Packit 971217
 * This makes a component-wise addition of @tc_inter to @tc. For example,
Packit 971217
 * adding ("01:02:03:04", "00:01:00:00") will return "01:03:03:04".
Packit 971217
 * When it comes to drop-frame timecodes,
Packit 971217
 * adding ("00:00:00;00", "00:01:00:00") will return "00:01:00;02"
Packit 971217
 * because of drop-frame oddities. However,
Packit 971217
 * adding ("00:09:00;02", "00:01:00:00") will return "00:10:00;00"
Packit 971217
 * because this time we can have an exact minute.
Packit 971217
 *
Packit 971217
 * Returns: A new #GstVideoTimeCode with @tc_inter added.
Packit 971217
 *
Packit 971217
 * Since: 1.12
Packit 971217
 */
Packit 971217
GstVideoTimeCode *
Packit 971217
gst_video_time_code_add_interval (const GstVideoTimeCode * tc,
Packit 971217
    const GstVideoTimeCodeInterval * tc_inter)
Packit 971217
{
Packit 971217
  GstVideoTimeCode *ret;
Packit 971217
  guint frames_to_add;
Packit 971217
  guint df;
Packit 971217
  gboolean needs_correction;
Packit 971217
Packit 971217
  g_return_val_if_fail (gst_video_time_code_is_valid (tc), NULL);
Packit 971217
Packit 971217
  ret = gst_video_time_code_new (tc->config.fps_n, tc->config.fps_d,
Packit 971217
      tc->config.latest_daily_jam, tc->config.flags, tc_inter->hours,
Packit 971217
      tc_inter->minutes, tc_inter->seconds, tc_inter->frames, 0);
Packit 971217
Packit 971217
  df = (tc->config.fps_n + (tc->config.fps_d >> 1)) / (tc->config.fps_d * 15);
Packit 971217
Packit 971217
  /* Drop-frame compensation: Create a valid timecode from the
Packit 971217
   * interval */
Packit 971217
  needs_correction = (tc->config.flags & GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME)
Packit 971217
      && ret->minutes % 10 && ret->seconds == 0 && ret->frames < df;
Packit 971217
  if (needs_correction) {
Packit 971217
    ret->minutes--;
Packit 971217
    ret->seconds = 59;
Packit 971217
    ret->frames = df * 14;
Packit 971217
  }
Packit 971217
Packit 971217
  if (!gst_video_time_code_is_valid (ret)) {
Packit 971217
    GST_ERROR ("Unsupported time code interval");
Packit 971217
    gst_video_time_code_free (ret);
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
Packit 971217
  frames_to_add = gst_video_time_code_frames_since_daily_jam (tc);
Packit 971217
Packit 971217
  /* Drop-frame compensation: 00:01:00;00 is falsely interpreted as
Packit 971217
   * 00:00:59;28 */
Packit 971217
  if (needs_correction) {
Packit 971217
    /* User wants us to split at invalid timecodes */
Packit 971217
    if (tc->minutes % 10 == 0 && tc->frames <= df) {
Packit 971217
      /* Apply compensation every 10th minute: before adding the frames,
Packit 971217
       * but only if we are before the "invalid frame" mark */
Packit 971217
      frames_to_add += df;
Packit 971217
      needs_correction = FALSE;
Packit 971217
    }
Packit 971217
  }
Packit 971217
  gst_video_time_code_add_frames (ret, frames_to_add);
Packit 971217
  if (needs_correction && ret->minutes % 10 == 0 && tc->frames > df) {
Packit 971217
    gst_video_time_code_add_frames (ret, df);
Packit 971217
  }
Packit 971217
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
G_DEFINE_BOXED_TYPE (GstVideoTimeCodeInterval, gst_video_time_code_interval,
Packit 971217
    (GBoxedCopyFunc) gst_video_time_code_interval_copy,
Packit 971217
    (GBoxedFreeFunc) gst_video_time_code_interval_free);
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_interval_new:
Packit 971217
 * @hours: the hours field of #GstVideoTimeCodeInterval
Packit 971217
 * @minutes: the minutes field of #GstVideoTimeCodeInterval
Packit 971217
 * @seconds: the seconds field of #GstVideoTimeCodeInterval
Packit 971217
 * @frames: the frames field of #GstVideoTimeCodeInterval
Packit 971217
 *
Packit 971217
 * Returns: a new #GstVideoTimeCodeInterval with the given values.
Packit 971217
 *
Packit 971217
 * Since: 1.12
Packit 971217
 */
Packit 971217
GstVideoTimeCodeInterval *
Packit 971217
gst_video_time_code_interval_new (guint hours, guint minutes, guint seconds,
Packit 971217
    guint frames)
Packit 971217
{
Packit 971217
  GstVideoTimeCodeInterval *tc;
Packit 971217
Packit 971217
  tc = g_new0 (GstVideoTimeCodeInterval, 1);
Packit 971217
  gst_video_time_code_interval_init (tc, hours, minutes, seconds, frames);
Packit 971217
  return tc;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_interval_new_from_string:
Packit 971217
 * @tc_inter_str: The string that represents the #GstVideoTimeCodeInterval
Packit 971217
 *
Packit 971217
 * @tc_inter_str must only have ":" as separators.
Packit 971217
 *
Packit 971217
 * Returns: a new #GstVideoTimeCodeInterval from the given string
Packit 971217
 *
Packit 971217
 * Since: 1.12
Packit 971217
 */
Packit 971217
GstVideoTimeCodeInterval *
Packit 971217
gst_video_time_code_interval_new_from_string (const gchar * tc_inter_str)
Packit 971217
{
Packit 971217
  GstVideoTimeCodeInterval *tc;
Packit 971217
  guint hours, minutes, seconds, frames;
Packit 971217
Packit 971217
  if (sscanf (tc_inter_str, "%02u:%02u:%02u:%02u", &hours, &minutes, &seconds,
Packit 971217
          &frames)
Packit 971217
      == 4
Packit 971217
      || sscanf (tc_inter_str, "%02u:%02u:%02u;%02u", &hours, &minutes,
Packit 971217
          &seconds, &frames)
Packit 971217
      == 4
Packit 971217
      || sscanf (tc_inter_str, "%02u:%02u:%02u.%02u", &hours, &minutes,
Packit 971217
          &seconds, &frames)
Packit 971217
      == 4
Packit 971217
      || sscanf (tc_inter_str, "%02u:%02u:%02u,%02u", &hours, &minutes,
Packit 971217
          &seconds, &frames)
Packit 971217
      == 4) {
Packit 971217
    tc = gst_video_time_code_interval_new (hours, minutes, seconds, frames);
Packit 971217
Packit 971217
    return tc;
Packit 971217
  } else {
Packit 971217
    GST_ERROR ("Warning: Could not parse timecode %s. "
Packit 971217
        "Please input a timecode in the form 00:00:00:00", tc_inter_str);
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_interval_init:
Packit 971217
 * @tc: a #GstVideoTimeCodeInterval
Packit 971217
 * @hours: the hours field of #GstVideoTimeCodeInterval
Packit 971217
 * @minutes: the minutes field of #GstVideoTimeCodeInterval
Packit 971217
 * @seconds: the seconds field of #GstVideoTimeCodeInterval
Packit 971217
 * @frames: the frames field of #GstVideoTimeCodeInterval
Packit 971217
 *
Packit 971217
 * Initializes @tc with the given values.
Packit 971217
 *
Packit 971217
 * Since: 1.12
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_video_time_code_interval_init (GstVideoTimeCodeInterval * tc, guint hours,
Packit 971217
    guint minutes, guint seconds, guint frames)
Packit 971217
{
Packit 971217
  tc->hours = hours;
Packit 971217
  tc->minutes = minutes;
Packit 971217
  tc->seconds = seconds;
Packit 971217
  tc->frames = frames;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_interval_clear:
Packit 971217
 * @tc: a #GstVideoTimeCodeInterval
Packit 971217
 *
Packit 971217
 * Initializes @tc with empty/zero/NULL values.
Packit 971217
 *
Packit 971217
 * Since: 1.12
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_video_time_code_interval_clear (GstVideoTimeCodeInterval * tc)
Packit 971217
{
Packit 971217
  tc->hours = 0;
Packit 971217
  tc->minutes = 0;
Packit 971217
  tc->seconds = 0;
Packit 971217
  tc->frames = 0;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_interval_copy:
Packit 971217
 * @tc: a #GstVideoTimeCodeInterval
Packit 971217
 *
Packit 971217
 * Returns: a new #GstVideoTimeCodeInterval with the same values as @tc .
Packit 971217
 *
Packit 971217
 * Since: 1.12
Packit 971217
 */
Packit 971217
GstVideoTimeCodeInterval *
Packit 971217
gst_video_time_code_interval_copy (const GstVideoTimeCodeInterval * tc)
Packit 971217
{
Packit 971217
  return gst_video_time_code_interval_new (tc->hours, tc->minutes,
Packit 971217
      tc->seconds, tc->frames);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_video_time_code_interval_free:
Packit 971217
 * @tc: a #GstVideoTimeCodeInterval
Packit 971217
 *
Packit 971217
 * Frees @tc .
Packit 971217
 *
Packit 971217
 * Since: 1.12
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_video_time_code_interval_free (GstVideoTimeCodeInterval * tc)
Packit 971217
{
Packit 971217
  g_free (tc);
Packit 971217
}