/* 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; }