예제 #1
0
/* Must be called with object lock */
static void
gst_timecodestamper_reset_timecode (GstTimeCodeStamper * timecodestamper)
{
  GDateTime *jam = NULL;

  if (timecodestamper->first_tc &&
      timecodestamper->first_tc->config.latest_daily_jam)
    jam = g_date_time_ref (timecodestamper->first_tc->config.latest_daily_jam);
  else if (timecodestamper->current_tc->config.latest_daily_jam)
    jam =
        g_date_time_ref (timecodestamper->current_tc->config.latest_daily_jam);
  gst_video_time_code_clear (timecodestamper->current_tc);
  /* FIXME: What if the buffer doesn't contain both top and bottom fields? */
  gst_video_time_code_init (timecodestamper->current_tc,
      timecodestamper->vinfo.fps_n,
      timecodestamper->vinfo.fps_d,
      jam,
      timecodestamper->vinfo.interlace_mode ==
      GST_VIDEO_INTERLACE_MODE_PROGRESSIVE ? 0 :
      GST_VIDEO_TIME_CODE_FLAGS_INTERLACED, 0, 0, 0, 0, 0);
  if (jam)
    g_date_time_unref (jam);
  if (timecodestamper->first_tc) {
    timecodestamper->current_tc->hours = timecodestamper->first_tc->hours;
    timecodestamper->current_tc->minutes = timecodestamper->first_tc->minutes;
    timecodestamper->current_tc->seconds = timecodestamper->first_tc->seconds;
    timecodestamper->current_tc->frames = timecodestamper->first_tc->frames;
    timecodestamper->current_tc->field_count =
        timecodestamper->first_tc->field_count;
  }
  gst_timecodestamper_set_drop_frame (timecodestamper);
}
/**
 * gst_video_time_code_new:
 * @fps_n: Numerator of the frame rate
 * @fps_d: Denominator of the frame rate
 * @latest_daily_jam: The latest daily jam of the #GstVideoTimeCode
 * @flags: #GstVideoTimeCodeFlags
 * @hours: the hours field of #GstVideoTimeCode
 * @minutes: the minutes field of #GstVideoTimeCode
 * @seconds: the seconds field of #GstVideoTimeCode
 * @frames: the frames field of #GstVideoTimeCode
 * @field_count: Interlaced video field count
 *
 * @field_count is 0 for progressive, 1 or 2 for interlaced.
 * @latest_daiy_jam reference is stolen from caller.
 *
 * Returns: a new #GstVideoTimeCode with the given values.
 *
 * Since: 1.10
 */
GstVideoTimeCode *
gst_video_time_code_new (guint fps_n, guint fps_d, GDateTime * latest_daily_jam,
    GstVideoTimeCodeFlags flags, guint hours, guint minutes, guint seconds,
    guint frames, guint field_count)
{
  GstVideoTimeCode *tc;

  tc = g_new0 (GstVideoTimeCode, 1);
  gst_video_time_code_init (tc, fps_n, fps_d, latest_daily_jam, flags, hours,
      minutes, seconds, frames, field_count);
  return tc;
}
static void
gst_timecodewait_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstTimeCodeWait *self = GST_TIMECODEWAIT (object);

  switch (prop_id) {
    case PROP_TARGET_TIME_CODE_STRING:{
      gchar **parts;
      const gchar *tc_str;
      guint hours, minutes, seconds, frames;

      tc_str = g_value_get_string (value);
      parts = g_strsplit (tc_str, ":", 4);
      if (!parts || parts[3] == NULL) {
        GST_ERROR_OBJECT (self,
            "Error: Could not parse timecode %s. Please input a timecode in the form 00:00:00:00",
            tc_str);
        g_strfreev (parts);
        return;
      }
      hours = g_ascii_strtoll (parts[0], NULL, 10);
      minutes = g_ascii_strtoll (parts[1], NULL, 10);
      seconds = g_ascii_strtoll (parts[2], NULL, 10);
      frames = g_ascii_strtoll (parts[3], NULL, 10);
      gst_video_time_code_init (self->tc, 0, 1, NULL, 0, hours, minutes,
          seconds, frames, 0);
      if (self->vinfo.finfo != NULL) {
        self->tc->config.fps_n = self->vinfo.fps_n;
        self->tc->config.fps_d = self->vinfo.fps_d;
      }
      self->from_string = TRUE;
      g_strfreev (parts);
      break;
    }
    case PROP_TARGET_TIME_CODE:{
      if (self->tc)
        gst_video_time_code_free (self->tc);
      self->tc = g_value_dup_boxed (value);
      self->from_string = FALSE;
      break;
    }
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
static GstFlowReturn
gst_timecodestamper_transform_ip (GstBaseTransform * vfilter,
    GstBuffer * buffer)
{
  GstTimeCodeStamper *timecodestamper = GST_TIME_CODE_STAMPER (vfilter);
  GstClockTime ref_time;

  GST_OBJECT_LOCK (timecodestamper);
  if (gst_buffer_get_video_time_code_meta (buffer)
      && !timecodestamper->override_existing) {
    GST_OBJECT_UNLOCK (timecodestamper);
    return GST_FLOW_OK;
  } else if (timecodestamper->override_existing) {
    gst_buffer_foreach_meta (buffer, remove_timecode_meta, NULL);
  }

  if (timecodestamper->source_clock != NULL) {
    if (timecodestamper->current_tc->hours == 0
        && timecodestamper->current_tc->minutes == 0
        && timecodestamper->current_tc->seconds == 0
        && timecodestamper->current_tc->frames == 0) {
      guint64 hours, minutes, seconds, frames;
      /* Daily jam time */

      ref_time = gst_clock_get_time (timecodestamper->source_clock);
      ref_time = ref_time % (24 * 60 * 60 * GST_SECOND);
      hours = ref_time / (GST_SECOND * 60 * 60);
      ref_time -= hours * GST_SECOND * 60 * 60;
      minutes = ref_time / (GST_SECOND * 60);
      ref_time -= minutes * GST_SECOND * 60;
      seconds = ref_time / GST_SECOND;
      ref_time -= seconds * GST_SECOND;
      /* Converting to frames for the whole ref_time might be inaccurate in case
       * we have a drop frame timecode */
      frames = gst_util_uint64_scale (ref_time, timecodestamper->vinfo.fps_n,
          timecodestamper->vinfo.fps_d * GST_SECOND);

      GST_DEBUG_OBJECT (timecodestamper,
          "Initializing with %" G_GUINT64_FORMAT ":%" G_GUINT64_FORMAT ":%"
          G_GUINT64_FORMAT ":%" G_GUINT64_FORMAT "", hours, minutes, seconds,
          frames);
      gst_video_time_code_init (timecodestamper->current_tc,
          timecodestamper->vinfo.fps_n,
          timecodestamper->vinfo.fps_d,
          NULL,
          timecodestamper->vinfo.interlace_mode ==
          GST_VIDEO_INTERLACE_MODE_PROGRESSIVE ? 0 :
          GST_VIDEO_TIME_CODE_FLAGS_INTERLACED, hours, minutes, seconds, 0, 0);
      gst_timecodestamper_set_drop_frame (timecodestamper);
      /* Do not use frames when initializing because maybe we have drop frame */
      gst_video_time_code_add_frames (timecodestamper->current_tc, frames);
    }
  } else if (timecodestamper->source_clock == NULL) {
    GstClockTime timecode_time;

    timecode_time =
        gst_video_time_code_nsec_since_daily_jam (timecodestamper->current_tc);
    ref_time =
        gst_segment_to_stream_time (&vfilter->segment, GST_FORMAT_TIME,
        buffer->pts);
    if (timecode_time != GST_CLOCK_TIME_NONE && ref_time != GST_CLOCK_TIME_NONE
        && ((timecode_time > ref_time && timecode_time - ref_time > GST_SECOND)
            || (ref_time > timecode_time
                && ref_time - timecode_time > GST_SECOND))) {
      gchar *tc_str =
          gst_video_time_code_to_string (timecodestamper->current_tc);
      GST_WARNING_OBJECT (timecodestamper,
          "Time code %s (stream time %" GST_TIME_FORMAT
          ") has drifted more than one second from stream time %"
          GST_TIME_FORMAT, tc_str, GST_TIME_ARGS (timecode_time),
          GST_TIME_ARGS (ref_time));
      g_free (tc_str);
    }
  }
  gst_buffer_add_video_time_code_meta (buffer, timecodestamper->current_tc);
  gst_video_time_code_increment_frame (timecodestamper->current_tc);
  GST_OBJECT_UNLOCK (timecodestamper);
  return GST_FLOW_OK;
}