mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-28 03:00:35 +00:00
videotimecode: New GstVideoTimeCodeInterval type, ability to add to a GstVideoTimeCode
Sometimes there is a human-oriented timecode that represents an interval between two other timecodes. It corresponds to the human perception of "add X hours" or "add X seconds" to a specific timecode, taking drop-frame oddities into account. This interval-representing timecode is now a GstVideoTimeCodeInterval. Also added function to add it to a GstVideoTimeCode. https://bugzilla.gnome.org/show_bug.cgi?id=776447
This commit is contained in:
parent
7bd7b2209a
commit
629e8229a7
2 changed files with 237 additions and 0 deletions
|
@ -716,3 +716,198 @@ gst_video_time_code_free (GstVideoTimeCode * tc)
|
|||
|
||||
g_free (tc);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_video_time_code_add_interval:
|
||||
* @tc: The #GstVideoTimeCode where the diff should be added
|
||||
* @tc_inter: The #GstVideoTimeCodeInterval to add to @tc
|
||||
*
|
||||
* This makes a component-wise addition of @tc_inter to @tc. For example,
|
||||
* adding ("01:02:03:04", "00:01:00:00") will return "01:03:03:04".
|
||||
* When it comes to drop-frame timecodes,
|
||||
* adding ("00:00:00;00", "00:01:00:00") will return "00:01:00;02"
|
||||
* because of drop-frame oddities. However,
|
||||
* adding ("00:09:00;02", "00:01:00:00") will return "00:10:00;00"
|
||||
* because this time we can have an exact minute.
|
||||
*
|
||||
* Returns: A new #GstVideoTimeCode with @tc_inter added.
|
||||
*
|
||||
* Since: 1.12
|
||||
*/
|
||||
GstVideoTimeCode *
|
||||
gst_video_time_code_add_interval (const GstVideoTimeCode * tc,
|
||||
const GstVideoTimeCodeInterval * tc_inter)
|
||||
{
|
||||
GstVideoTimeCode *ret =
|
||||
gst_video_time_code_new (tc->config.fps_n, tc->config.fps_d,
|
||||
tc->config.latest_daily_jam, tc->config.flags, tc_inter->hours,
|
||||
tc_inter->minutes, tc_inter->seconds, tc_inter->frames, 0);
|
||||
guint frames_to_add = gst_video_time_code_frames_since_daily_jam (tc);
|
||||
gboolean check_again = FALSE;
|
||||
|
||||
/* Drop-frame compensation: 00:01:00;00 is falsely interpreted as
|
||||
* 00:00:59;28 */
|
||||
if (tc->config.flags & GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME &&
|
||||
tc_inter->frames == 0 && tc_inter->seconds == 0
|
||||
&& (tc_inter->minutes % 10 != 0)) {
|
||||
/* User wants us to split at invalid timecodes */
|
||||
check_again = TRUE;
|
||||
if (tc->minutes % 10 == 0) {
|
||||
/* Apply compensation every 10th minute: before adding the frames,
|
||||
* but only if we are before the "invalid frame" mark */
|
||||
if (tc->config.fps_n == 30000 && tc->frames <= 2) {
|
||||
frames_to_add += 2;
|
||||
check_again = FALSE;
|
||||
} else if (tc->config.fps_n == 60000 && tc->frames <= 4) {
|
||||
frames_to_add += 4;
|
||||
check_again = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
gst_video_time_code_add_frames (ret, frames_to_add);
|
||||
if (check_again && ret->minutes % 10 == 0) {
|
||||
if (ret->config.fps_n == 30000 && tc->frames > 2) {
|
||||
frames_to_add = 2;
|
||||
} else if (ret->config.fps_n == 60000 && tc->frames > 4) {
|
||||
frames_to_add = 4;
|
||||
} else {
|
||||
frames_to_add = 0;
|
||||
}
|
||||
gst_video_time_code_add_frames (ret, frames_to_add);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
G_DEFINE_BOXED_TYPE (GstVideoTimeCodeInterval, gst_video_time_code_interval,
|
||||
(GBoxedCopyFunc) gst_video_time_code_interval_copy,
|
||||
(GBoxedFreeFunc) gst_video_time_code_interval_free);
|
||||
|
||||
/**
|
||||
* gst_video_time_code_interval_new:
|
||||
* @hours: the hours field of #GstVideoTimeCodeInterval
|
||||
* @minutes: the minutes field of #GstVideoTimeCodeInterval
|
||||
* @seconds: the seconds field of #GstVideoTimeCodeInterval
|
||||
* @frames: the frames field of #GstVideoTimeCodeInterval
|
||||
*
|
||||
* Returns: a new #GstVideoTimeCodeInterval with the given values.
|
||||
*
|
||||
* Since: 1.12
|
||||
*/
|
||||
GstVideoTimeCodeInterval *
|
||||
gst_video_time_code_interval_new (guint hours, guint minutes, guint seconds,
|
||||
guint frames)
|
||||
{
|
||||
GstVideoTimeCodeInterval *tc;
|
||||
|
||||
tc = g_new0 (GstVideoTimeCodeInterval, 1);
|
||||
gst_video_time_code_interval_init (tc, hours, minutes, seconds, frames);
|
||||
return tc;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_video_time_code_interval_new_from_string:
|
||||
* @tc_inter_str: The string that represents the #GstVideoTimeCodeInterval
|
||||
*
|
||||
* @tc_inter_str must only have ":" as separators.
|
||||
*
|
||||
* Returns: a new #GstVideoTimeCodeInterval from the given string
|
||||
*
|
||||
* Since: 1.12
|
||||
*/
|
||||
GstVideoTimeCodeInterval *
|
||||
gst_video_time_code_interval_new_from_string (const gchar * tc_inter_str)
|
||||
{
|
||||
GstVideoTimeCodeInterval *tc;
|
||||
guint hours, minutes, seconds, frames;
|
||||
|
||||
if (sscanf (tc_inter_str, "%02u:%02u:%02u:%02u", &hours, &minutes, &seconds,
|
||||
&frames)
|
||||
== 4
|
||||
|| sscanf (tc_inter_str, "%02u:%02u:%02u;%02u", &hours, &minutes,
|
||||
&seconds, &frames)
|
||||
== 4
|
||||
|| sscanf (tc_inter_str, "%02u:%02u:%02u.%02u", &hours, &minutes,
|
||||
&seconds, &frames)
|
||||
== 4
|
||||
|| sscanf (tc_inter_str, "%02u:%02u:%02u,%02u", &hours, &minutes,
|
||||
&seconds, &frames)
|
||||
== 4) {
|
||||
tc = gst_video_time_code_interval_new (hours, minutes, seconds, frames);
|
||||
|
||||
return tc;
|
||||
} else {
|
||||
GST_ERROR ("Warning: Could not parse timecode %s. "
|
||||
"Please input a timecode in the form 00:00:00:00", tc_inter_str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_video_time_code_interval_init:
|
||||
* @tc: a #GstVideoTimeCodeInterval
|
||||
* @hours: the hours field of #GstVideoTimeCodeInterval
|
||||
* @minutes: the minutes field of #GstVideoTimeCodeInterval
|
||||
* @seconds: the seconds field of #GstVideoTimeCodeInterval
|
||||
* @frames: the frames field of #GstVideoTimeCodeInterval
|
||||
*
|
||||
* Initializes @tc with the given values.
|
||||
*
|
||||
* Since: 1.12
|
||||
*/
|
||||
void
|
||||
gst_video_time_code_interval_init (GstVideoTimeCodeInterval * tc, guint hours,
|
||||
guint minutes, guint seconds, guint frames)
|
||||
{
|
||||
tc->hours = hours;
|
||||
tc->minutes = minutes;
|
||||
tc->seconds = seconds;
|
||||
tc->frames = frames;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_video_time_code_interval_clear:
|
||||
* @tc: a #GstVideoTimeCodeInterval
|
||||
*
|
||||
* Initializes @tc with empty/zero/NULL values.
|
||||
*
|
||||
* Since: 1.12
|
||||
*/
|
||||
void
|
||||
gst_video_time_code_interval_clear (GstVideoTimeCodeInterval * tc)
|
||||
{
|
||||
tc->hours = 0;
|
||||
tc->minutes = 0;
|
||||
tc->seconds = 0;
|
||||
tc->frames = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_video_time_code_interval_copy:
|
||||
* @tc: a #GstVideoTimeCodeInterval
|
||||
*
|
||||
* Returns: a new #GstVideoTimeCodeInterval with the same values as @tc .
|
||||
*
|
||||
* Since: 1.12
|
||||
*/
|
||||
GstVideoTimeCodeInterval *
|
||||
gst_video_time_code_interval_copy (const GstVideoTimeCodeInterval * tc)
|
||||
{
|
||||
return gst_video_time_code_interval_new (tc->hours, tc->minutes,
|
||||
tc->seconds, tc->frames);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_video_time_code_interval_free:
|
||||
* @tc: a #GstVideoTimeCodeInterval
|
||||
*
|
||||
* Frees @tc .
|
||||
*
|
||||
* Since: 1.12
|
||||
*/
|
||||
void
|
||||
gst_video_time_code_interval_free (GstVideoTimeCodeInterval * tc)
|
||||
{
|
||||
g_free (tc);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ G_BEGIN_DECLS
|
|||
|
||||
typedef struct _GstVideoTimeCodeConfig GstVideoTimeCodeConfig;
|
||||
typedef struct _GstVideoTimeCode GstVideoTimeCode;
|
||||
typedef struct _GstVideoTimeCodeInterval GstVideoTimeCodeInterval;
|
||||
|
||||
/**
|
||||
* GstVideoTimeCodeFlags:
|
||||
|
@ -100,6 +101,26 @@ struct _GstVideoTimeCode {
|
|||
guint field_count;
|
||||
};
|
||||
|
||||
/**
|
||||
* GstVideoTimeCodeInterval:
|
||||
* @hours: the hours field of #GstVideoTimeCodeInterval
|
||||
* @minutes: the minutes field of #GstVideoTimeCodeInterval
|
||||
* @seconds: the seconds field of #GstVideoTimeCodeInterval
|
||||
* @frames: the frames field of #GstVideoTimeCodeInterval
|
||||
*
|
||||
* A representation of a difference between two #GstVideoTimeCode instances.
|
||||
* Will not necessarily correspond to a real timecode (e.g. 00:00:10;00)
|
||||
*
|
||||
* Since: 1.12
|
||||
*/
|
||||
struct _GstVideoTimeCodeInterval {
|
||||
guint hours;
|
||||
guint minutes;
|
||||
guint seconds;
|
||||
guint frames;
|
||||
};
|
||||
|
||||
|
||||
#define GST_TYPE_VIDEO_TIME_CODE (gst_video_time_code_get_type())
|
||||
GType gst_video_time_code_get_type (void);
|
||||
|
||||
|
@ -147,6 +168,27 @@ guint64 gst_video_time_code_nsec_since_daily_jam (const GstVideoTimeCode * tc
|
|||
|
||||
guint64 gst_video_time_code_frames_since_daily_jam (const GstVideoTimeCode * tc);
|
||||
|
||||
GstVideoTimeCode * gst_video_time_code_add_interval (const GstVideoTimeCode * tc, const GstVideoTimeCodeInterval * tc_inter);
|
||||
|
||||
#define GST_TYPE_VIDEO_TIME_CODE_INTERVAL (gst_video_time_code_interval_get_type())
|
||||
GType gst_video_time_code_interval_get_type (void);
|
||||
|
||||
GstVideoTimeCodeInterval * gst_video_time_code_interval_new (guint hours,
|
||||
guint minutes,
|
||||
guint seconds,
|
||||
guint frames);
|
||||
GstVideoTimeCodeInterval * gst_video_time_code_interval_new_from_string (const gchar * tc_inter_str);
|
||||
void gst_video_time_code_interval_free (GstVideoTimeCodeInterval * tc);
|
||||
|
||||
GstVideoTimeCodeInterval * gst_video_time_code_interval_copy (const GstVideoTimeCodeInterval * tc);
|
||||
|
||||
void gst_video_time_code_interval_init (GstVideoTimeCodeInterval * tc,
|
||||
guint hours,
|
||||
guint minutes,
|
||||
guint seconds,
|
||||
guint frames);
|
||||
void gst_video_time_code_interval_clear (GstVideoTimeCodeInterval * tc);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_VIDEO_TIME_CODE_H__ */
|
||||
|
|
Loading…
Reference in a new issue