diff --git a/gst-libs/gst/video/gstvideometa.c b/gst-libs/gst/video/gstvideometa.c index ae3e43f61c..06dea5d46b 100644 --- a/gst-libs/gst/video/gstvideometa.c +++ b/gst-libs/gst/video/gstvideometa.c @@ -846,3 +846,141 @@ gst_buffer_add_video_region_of_interest_meta_id (GstBuffer * buffer, return meta; } + +/* Time Code Meta implementation *******************************************/ + +GType +gst_video_time_code_meta_api_get_type (void) +{ + static volatile GType type; + + if (g_once_init_enter (&type)) { + static const gchar *tags[] = { NULL }; + GType _type = gst_meta_api_type_register ("GstVideoTimeCodeMetaAPI", tags); + GST_INFO ("registering"); + g_once_init_leave (&type, _type); + } + return type; +} + + +static gboolean +gst_video_time_code_meta_transform (GstBuffer * dest, GstMeta * meta, + GstBuffer * buffer, GQuark type, gpointer data) +{ + GstVideoTimeCodeMeta *dmeta, *smeta; + + if (GST_META_TRANSFORM_IS_COPY (type)) { + smeta = (GstVideoTimeCodeMeta *) meta; + + GST_DEBUG ("copy time code metadata"); + dmeta = + gst_buffer_add_video_time_code_meta_full (dest, smeta->tc.config.fps_n, + smeta->tc.config.fps_d, smeta->tc.config.latest_daily_jam, + smeta->tc.config.flags, smeta->tc.hours, smeta->tc.minutes, + smeta->tc.seconds, smeta->tc.frames, smeta->tc.field_count); + if (!dmeta) + return FALSE; + } else { + /* return FALSE, if transform type is not supported */ + return FALSE; + } + return TRUE; +} + +static gboolean +gst_video_time_code_meta_init (GstMeta * meta, gpointer params, + GstBuffer * buffer) +{ + GstVideoTimeCodeMeta *emeta = (GstVideoTimeCodeMeta *) meta; + memset (&emeta->tc, 0, sizeof (emeta->tc)); + gst_video_time_code_clear (&emeta->tc); + + return TRUE; +} + +static void +gst_video_time_code_meta_free (GstMeta * meta, GstBuffer * buffer) +{ + GstVideoTimeCodeMeta *emeta = (GstVideoTimeCodeMeta *) meta; + + gst_video_time_code_clear (&emeta->tc); +} + +const GstMetaInfo * +gst_video_time_code_meta_get_info (void) +{ + static const GstMetaInfo *meta_info = NULL; + + if (g_once_init_enter (&meta_info)) { + const GstMetaInfo *mi = + gst_meta_register (GST_VIDEO_TIME_CODE_META_API_TYPE, + "GstVideoTimeCodeMeta", + sizeof (GstVideoTimeCodeMeta), + gst_video_time_code_meta_init, + gst_video_time_code_meta_free, + gst_video_time_code_meta_transform); + g_once_init_leave (&meta_info, mi); + } + return meta_info; +} + +/** + * gst_buffer_add_video_time_code_meta: + * @buffer: a #GstBuffer + * @tc: a #GstVideoTimeCode + * + * Attaches #GstVideoTimeCodeMeta metadata to @buffer with the given + * parameters. + * + * Returns: (transfer none): the #GstVideoTimeCodeMeta on @buffer. + * + * Since: 1.10 + */ +GstVideoTimeCodeMeta * +gst_buffer_add_video_time_code_meta (GstBuffer * buffer, GstVideoTimeCode * tc) +{ + g_return_val_if_fail (gst_video_time_code_is_valid (tc), NULL); + return gst_buffer_add_video_time_code_meta_full (buffer, tc->config.fps_n, + tc->config.fps_d, tc->config.latest_daily_jam, tc->config.flags, + tc->hours, tc->minutes, tc->seconds, tc->frames, tc->field_count); +} + +/** + * gst_buffer_add_video_time_code_meta_full: + * @buffer: a #GstBuffer + * @fps_n: framerate numerator + * @fps_d: framerate denominator + * @latest_daily_jam: a #GDateTime for the latest daily jam + * @flags: a #GstVideoTimeCodeFlags + * @hours: hours since the daily jam + * @minutes: minutes since the daily jam + * @seconds: seconds since the daily jam + * @frames: frames since the daily jam + * @field_count: fields since the daily jam + * + * Attaches #GstVideoTimeCodeMeta metadata to @buffer with the given + * parameters. + * + * Returns: (transfer none): the #GstVideoTimeCodeMeta on @buffer. + * + * Since: 1.10 + */ +GstVideoTimeCodeMeta * +gst_buffer_add_video_time_code_meta_full (GstBuffer * buffer, guint fps_n, + guint fps_d, GDateTime * latest_daily_jam, GstVideoTimeCodeFlags flags, + guint hours, guint minutes, guint seconds, guint frames, guint field_count) +{ + GstVideoTimeCodeMeta *meta; + + g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL); + + meta = (GstVideoTimeCodeMeta *) gst_buffer_add_meta (buffer, + GST_VIDEO_TIME_CODE_META_INFO, NULL); + gst_video_time_code_init (&meta->tc, fps_n, fps_d, latest_daily_jam, flags, + hours, minutes, seconds, frames, field_count); + + g_return_val_if_fail (gst_video_time_code_is_valid (&meta->tc), NULL); + + return meta; +} diff --git a/gst-libs/gst/video/gstvideometa.h b/gst-libs/gst/video/gstvideometa.h index deb793d006..d5e1562a6e 100644 --- a/gst-libs/gst/video/gstvideometa.h +++ b/gst-libs/gst/video/gstvideometa.h @@ -23,6 +23,7 @@ #include #include +#include G_BEGIN_DECLS @@ -295,6 +296,46 @@ GstVideoRegionOfInterestMeta *gst_buffer_add_video_region_of_interest_meta_id (G guint w, guint h); +/** + * GstVideoTimeCodeMeta: + * @meta: parent #GstMeta + * @tc: the GstVideoTimeCode to attach + * + * Extra buffer metadata describing the GstVideoTimeCode of the frame. + * + * Each frame is assumed to have its own timecode, i.e. they are not + * automatically incremented/interpolated. + * + * Since: 1.10 + */ +typedef struct { + GstMeta meta; + + GstVideoTimeCode tc; +} GstVideoTimeCodeMeta; + +GType gst_video_time_code_meta_api_get_type (void); +#define GST_VIDEO_TIME_CODE_META_API_TYPE (gst_video_time_code_meta_api_get_type()) +const GstMetaInfo *gst_video_time_code_meta_get_info (void); +#define GST_VIDEO_TIME_CODE_META_INFO (gst_video_time_code_meta_get_info()) + +#define gst_buffer_get_video_time_code_meta(b) \ + ((GstVideoTimeCodeMeta*)gst_buffer_get_meta((b),GST_VIDEO_TIME_CODE_META_API_TYPE)) +GstVideoTimeCodeMeta *gst_buffer_add_video_time_code_meta (GstBuffer * buffer, + GstVideoTimeCode * tc); + +GstVideoTimeCodeMeta * +gst_buffer_add_video_time_code_meta_full (GstBuffer * buffer, + guint fps_n, + guint fps_d, + GDateTime * latest_daily_jam, + GstVideoTimeCodeFlags flags, + guint hours, + guint minutes, + guint seconds, + guint frames, + guint field_count); + G_END_DECLS #endif /* __GST_VIDEO_META_H__ */