timecodestamper: add support for closedcaption input

Some closedcaption elements like sccenc except input buffers
to have timecode metas. The original use case is to serialize
closed captions extracted from a video stream, in that case
ccextractor copies the video time code metas to the closed
caption buffers, but no such mechanism exists when creating
a CC stream ex nihilo.

Remedy that by having timecodestamper accept closedcaption
input caps, as long as they have a framerate.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2490>
This commit is contained in:
Mathieu Duponchelle 2021-08-26 04:12:07 +02:00 committed by GStreamer Marge Bot
parent 5cf4dc2b82
commit 5bd31b8cce
3 changed files with 92 additions and 76 deletions

View file

@ -224034,12 +224034,12 @@
"presence": "request" "presence": "request"
}, },
"sink": { "sink": {
"caps": "video/x-raw:\n framerate: [ 1/2147483647, 2147483647/1 ]\n", "caps": "video/x-raw:\n framerate: [ 1/2147483647, 2147483647/1 ]\nclosedcaption/x-cea-608:\n framerate: [ 1/2147483647, 2147483647/1 ]\nclosedcaption/x-cea-708:\n framerate: [ 1/2147483647, 2147483647/1 ]\n",
"direction": "sink", "direction": "sink",
"presence": "always" "presence": "always"
}, },
"src": { "src": {
"caps": "video/x-raw:\n framerate: [ 1/2147483647, 2147483647/1 ]\n", "caps": "video/x-raw:\n framerate: [ 1/2147483647, 2147483647/1 ]\nclosedcaption/x-cea-608:\n framerate: [ 1/2147483647, 2147483647/1 ]\nclosedcaption/x-cea-708:\n framerate: [ 1/2147483647, 2147483647/1 ]\n",
"direction": "src", "direction": "src",
"presence": "always" "presence": "always"
} }

View file

@ -92,17 +92,21 @@ enum
#define DEFAULT_LTC_QUEUE 100 #define DEFAULT_LTC_QUEUE 100
static GstStaticPadTemplate gst_timecodestamper_src_template = static GstStaticPadTemplate gst_timecodestamper_src_template =
GST_STATIC_PAD_TEMPLATE ("src", GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC, GST_PAD_SRC,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw, framerate=[1/2147483647, 2147483647/1]") GST_STATIC_CAPS ("video/x-raw, framerate=[1/2147483647, 2147483647/1]; "
"closedcaption/x-cea-608, framerate=[1/2147483647, 2147483647/1]; "
"closedcaption/x-cea-708, framerate=[1/2147483647, 2147483647/1]; ")
); );
static GstStaticPadTemplate gst_timecodestamper_sink_template = static GstStaticPadTemplate gst_timecodestamper_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_SINK,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw, framerate=[1/2147483647, 2147483647/1]") GST_STATIC_CAPS ("video/x-raw, framerate=[1/2147483647, 2147483647/1]; "
"closedcaption/x-cea-608, framerate=[1/2147483647, 2147483647/1]; "
"closedcaption/x-cea-708, framerate=[1/2147483647, 2147483647/1]; ")
); );
static GstStaticPadTemplate gst_timecodestamper_ltc_template = static GstStaticPadTemplate gst_timecodestamper_ltc_template =
@ -507,8 +511,8 @@ gst_timecodestamper_set_property (GObject * object, guint prop_id,
if (timecodestamper->ltc_internal_tc) { if (timecodestamper->ltc_internal_tc) {
if (timecodestamper->ltc_internal_tc->config.latest_daily_jam) { if (timecodestamper->ltc_internal_tc->config.latest_daily_jam) {
g_date_time_unref (timecodestamper->ltc_internal_tc->config. g_date_time_unref (timecodestamper->ltc_internal_tc->
latest_daily_jam); config.latest_daily_jam);
} }
timecodestamper->ltc_internal_tc->config.latest_daily_jam = timecodestamper->ltc_internal_tc->config.latest_daily_jam =
g_date_time_ref (timecodestamper->ltc_daily_jam); g_date_time_ref (timecodestamper->ltc_daily_jam);
@ -632,7 +636,9 @@ gst_timecodestamper_stop (GstBaseTransform * trans)
g_mutex_unlock (&timecodestamper->mutex); g_mutex_unlock (&timecodestamper->mutex);
#endif #endif
gst_video_info_init (&timecodestamper->vinfo); timecodestamper->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
timecodestamper->fps_n = 0;
timecodestamper->fps_d = 1;
if (timecodestamper->internal_tc != NULL) { if (timecodestamper->internal_tc != NULL) {
gst_video_time_code_free (timecodestamper->internal_tc); gst_video_time_code_free (timecodestamper->internal_tc);
@ -691,15 +697,19 @@ gst_timecodestamper_stop (GstBaseTransform * trans)
static gboolean static gboolean
gst_timecodestamper_start (GstBaseTransform * trans) gst_timecodestamper_start (GstBaseTransform * trans)
{ {
#if HAVE_LTC
GstTimeCodeStamper *timecodestamper = GST_TIME_CODE_STAMPER (trans); GstTimeCodeStamper *timecodestamper = GST_TIME_CODE_STAMPER (trans);
#if HAVE_LTC
g_mutex_lock (&timecodestamper->mutex); g_mutex_lock (&timecodestamper->mutex);
timecodestamper->video_flushing = FALSE; timecodestamper->video_flushing = FALSE;
timecodestamper->video_eos = FALSE; timecodestamper->video_eos = FALSE;
g_mutex_unlock (&timecodestamper->mutex); g_mutex_unlock (&timecodestamper->mutex);
#endif #endif
timecodestamper->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
timecodestamper->fps_n = 0;
timecodestamper->fps_d = 1;
return TRUE; return TRUE;
} }
@ -707,9 +717,8 @@ gst_timecodestamper_start (GstBaseTransform * trans)
static void static void
gst_timecodestamper_update_drop_frame (GstTimeCodeStamper * timecodestamper) gst_timecodestamper_update_drop_frame (GstTimeCodeStamper * timecodestamper)
{ {
if (timecodestamper->drop_frame && timecodestamper->vinfo.fps_d == 1001 && if (timecodestamper->drop_frame && timecodestamper->fps_d == 1001 &&
(timecodestamper->vinfo.fps_n == 30000 || (timecodestamper->fps_n == 30000 || timecodestamper->fps_n == 60000)) {
timecodestamper->vinfo.fps_n == 60000)) {
if (timecodestamper->internal_tc) if (timecodestamper->internal_tc)
timecodestamper->internal_tc->config.flags |= timecodestamper->internal_tc->config.flags |=
GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME; GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME;
@ -756,7 +765,7 @@ gst_timecodestamper_update_drop_frame (GstTimeCodeStamper * timecodestamper)
static void static void
gst_timecodestamper_update_timecode_framerate (GstTimeCodeStamper * gst_timecodestamper_update_timecode_framerate (GstTimeCodeStamper *
timecodestamper, const GstVideoInfo * vinfo, GstVideoTimeCode * timecode, timecodestamper, gint fps_n, gint fps_d, GstVideoTimeCode * timecode,
gboolean is_ltc) gboolean is_ltc)
{ {
guint64 nframes; guint64 nframes;
@ -767,13 +776,11 @@ gst_timecodestamper_update_timecode_framerate (GstTimeCodeStamper *
if (!timecode) if (!timecode)
return; return;
if (timecodestamper->vinfo.interlace_mode != if (timecodestamper->interlace_mode != GST_VIDEO_INTERLACE_MODE_PROGRESSIVE)
GST_VIDEO_INTERLACE_MODE_PROGRESSIVE)
tc_flags |= GST_VIDEO_TIME_CODE_FLAGS_INTERLACED; tc_flags |= GST_VIDEO_TIME_CODE_FLAGS_INTERLACED;
if (timecodestamper->drop_frame && timecodestamper->vinfo.fps_d == 1001 && if (timecodestamper->drop_frame && timecodestamper->fps_d == 1001 &&
(timecodestamper->vinfo.fps_n == 30000 || (timecodestamper->fps_n == 30000 || timecodestamper->fps_n == 60000))
timecodestamper->vinfo.fps_n == 60000))
tc_flags |= GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME; tc_flags |= GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME;
/* If this is an LTC timecode and we have no framerate yet in there then /* If this is an LTC timecode and we have no framerate yet in there then
@ -782,19 +789,17 @@ gst_timecodestamper_update_timecode_framerate (GstTimeCodeStamper *
nframes = gst_video_time_code_frames_since_daily_jam (timecode); nframes = gst_video_time_code_frames_since_daily_jam (timecode);
time = time =
gst_util_uint64_scale (nframes, gst_util_uint64_scale (nframes,
GST_SECOND * timecodestamper->vinfo.fps_d, GST_SECOND * timecodestamper->fps_d, timecodestamper->fps_n);
timecodestamper->vinfo.fps_n);
jam = jam =
timecode->config.latest_daily_jam ? g_date_time_ref (timecode-> timecode->config.latest_daily_jam ? g_date_time_ref (timecode->config.
config.latest_daily_jam) : NULL; latest_daily_jam) : NULL;
gst_video_time_code_clear (timecode); gst_video_time_code_clear (timecode);
gst_video_time_code_init (timecode, timecodestamper->vinfo.fps_n, gst_video_time_code_init (timecode, timecodestamper->fps_n,
timecodestamper->vinfo.fps_d, jam, tc_flags, 0, 0, 0, 0, 0); timecodestamper->fps_d, jam, tc_flags, 0, 0, 0, 0, 0);
if (jam) if (jam)
g_date_time_unref (jam); g_date_time_unref (jam);
nframes = nframes = gst_util_uint64_scale (time, fps_n, GST_SECOND * fps_d);
gst_util_uint64_scale (time, vinfo->fps_n, GST_SECOND * vinfo->fps_d);
gst_video_time_code_add_frames (timecode, nframes); gst_video_time_code_add_frames (timecode, nframes);
} }
} }
@ -802,18 +807,17 @@ gst_timecodestamper_update_timecode_framerate (GstTimeCodeStamper *
/* Must be called with object lock */ /* Must be called with object lock */
static gboolean static gboolean
gst_timecodestamper_update_framerate (GstTimeCodeStamper * timecodestamper, gst_timecodestamper_update_framerate (GstTimeCodeStamper * timecodestamper,
const GstVideoInfo * vinfo) gint fps_n, gint fps_d)
{ {
/* Nothing changed */ /* Nothing changed */
if (vinfo->fps_n == timecodestamper->vinfo.fps_n && if (fps_n == timecodestamper->fps_n && fps_d == timecodestamper->fps_d)
vinfo->fps_d == timecodestamper->vinfo.fps_d)
return FALSE; return FALSE;
gst_timecodestamper_update_timecode_framerate (timecodestamper, vinfo, gst_timecodestamper_update_timecode_framerate (timecodestamper, fps_n, fps_d,
timecodestamper->internal_tc, FALSE); timecodestamper->internal_tc, FALSE);
gst_timecodestamper_update_timecode_framerate (timecodestamper, vinfo, gst_timecodestamper_update_timecode_framerate (timecodestamper, fps_n, fps_d,
timecodestamper->last_tc, FALSE); timecodestamper->last_tc, FALSE);
gst_timecodestamper_update_timecode_framerate (timecodestamper, vinfo, gst_timecodestamper_update_timecode_framerate (timecodestamper, fps_n, fps_d,
timecodestamper->rtc_tc, FALSE); timecodestamper->rtc_tc, FALSE);
#if HAVE_LTC #if HAVE_LTC
@ -823,11 +827,11 @@ gst_timecodestamper_update_framerate (GstTimeCodeStamper * timecodestamper,
for (l = timecodestamper->ltc_current_tcs.head; l; l = l->next) { for (l = timecodestamper->ltc_current_tcs.head; l; l = l->next) {
TimestampedTimecode *tc = l->data; TimestampedTimecode *tc = l->data;
gst_timecodestamper_update_timecode_framerate (timecodestamper, vinfo, gst_timecodestamper_update_timecode_framerate (timecodestamper, fps_n,
&tc->timecode, TRUE); fps_d, &tc->timecode, TRUE);
} }
} }
gst_timecodestamper_update_timecode_framerate (timecodestamper, vinfo, gst_timecodestamper_update_timecode_framerate (timecodestamper, fps_n, fps_d,
timecodestamper->ltc_internal_tc, FALSE); timecodestamper->ltc_internal_tc, FALSE);
#endif #endif
@ -866,27 +870,42 @@ gst_timecodestamper_sink_event (GstBaseTransform * trans, GstEvent * event)
case GST_EVENT_CAPS: case GST_EVENT_CAPS:
{ {
GstCaps *caps; GstCaps *caps;
GstVideoInfo info;
gboolean latency_changed; gboolean latency_changed;
const gchar *interlace_mode;
GstStructure *s;
gint fps_n, fps_d;
GST_OBJECT_LOCK (timecodestamper); GST_OBJECT_LOCK (timecodestamper);
gst_event_parse_caps (event, &caps); gst_event_parse_caps (event, &caps);
if (!gst_video_info_from_caps (&info, caps)) {
s = gst_caps_get_structure (caps, 0);
if (!gst_structure_get_fraction (s, "framerate", &fps_n, &fps_d)) {
GST_ERROR_OBJECT (timecodestamper, "Expected framerate in caps");
GST_OBJECT_UNLOCK (timecodestamper); GST_OBJECT_UNLOCK (timecodestamper);
gst_event_unref (event); gst_event_unref (event);
return FALSE; return FALSE;
} }
if (info.fps_n == 0) {
GST_WARNING_OBJECT (timecodestamper, if (fps_n == 0) {
GST_ERROR_OBJECT (timecodestamper,
"Non-constant frame rate found. Refusing to create a timecode"); "Non-constant frame rate found. Refusing to create a timecode");
GST_OBJECT_UNLOCK (timecodestamper); GST_OBJECT_UNLOCK (timecodestamper);
gst_event_unref (event); gst_event_unref (event);
return FALSE; return FALSE;
} }
if ((interlace_mode = gst_structure_get_string (s, "interlace-mode"))) {
timecodestamper->interlace_mode =
gst_video_interlace_mode_from_string (interlace_mode);
}
latency_changed = latency_changed =
gst_timecodestamper_update_framerate (timecodestamper, &info); gst_timecodestamper_update_framerate (timecodestamper, fps_n, fps_d);
timecodestamper->vinfo = info;
timecodestamper->fps_n = fps_n;
timecodestamper->fps_d = fps_d;
GST_OBJECT_UNLOCK (timecodestamper); GST_OBJECT_UNLOCK (timecodestamper);
if (latency_changed) if (latency_changed)
@ -955,11 +974,10 @@ gst_timecodestamper_src_event (GstBaseTransform * trans, GstEvent * event)
} }
GST_OBJECT_LOCK (timecodestamper); GST_OBJECT_LOCK (timecodestamper);
if (timecodestamper->vinfo.fps_d && timecodestamper->vinfo.fps_n) { if (timecodestamper->fps_d && timecodestamper->fps_n) {
timecodestamper->prev_seek_seqnum = GST_EVENT_SEQNUM (event); timecodestamper->prev_seek_seqnum = GST_EVENT_SEQNUM (event);
timecodestamper->seeked_frames = gst_util_uint64_scale (start, timecodestamper->seeked_frames = gst_util_uint64_scale (start,
timecodestamper->vinfo.fps_n, timecodestamper->fps_n, timecodestamper->fps_d * GST_SECOND);
timecodestamper->vinfo.fps_d * GST_SECOND);
} }
GST_OBJECT_UNLOCK (timecodestamper); GST_OBJECT_UNLOCK (timecodestamper);
break; break;
@ -996,7 +1014,7 @@ gst_timecodestamper_query (GstBaseTransform * trans,
gst_pad_query_default (GST_BASE_TRANSFORM_SRC_PAD (trans), gst_pad_query_default (GST_BASE_TRANSFORM_SRC_PAD (trans),
GST_OBJECT_CAST (trans), query); GST_OBJECT_CAST (trans), query);
g_mutex_lock (&timecodestamper->mutex); g_mutex_lock (&timecodestamper->mutex);
if (res && timecodestamper->vinfo.fps_n && timecodestamper->vinfo.fps_d) { if (res && timecodestamper->fps_n && timecodestamper->fps_d) {
gst_query_parse_latency (query, &live, &min_latency, &max_latency); gst_query_parse_latency (query, &live, &min_latency, &max_latency);
if (live && timecodestamper->ltcpad) { if (live && timecodestamper->ltcpad) {
/* Introduce additional LTC for waiting for LTC timecodes. The /* Introduce additional LTC for waiting for LTC timecodes. The
@ -1086,7 +1104,7 @@ gst_timecodestamper_transform_ip (GstBaseTransform * vfilter,
GstFlowReturn flow_ret = GST_FLOW_OK; GstFlowReturn flow_ret = GST_FLOW_OK;
GstVideoTimeCodeFlags tc_flags = 0; GstVideoTimeCodeFlags tc_flags = 0;
if (timecodestamper->vinfo.fps_n == 0 || timecodestamper->vinfo.fps_d == 0 if (timecodestamper->fps_n == 0 || timecodestamper->fps_d == 0
|| !GST_BUFFER_PTS_IS_VALID (buffer)) { || !GST_BUFFER_PTS_IS_VALID (buffer)) {
gst_buffer_unref (buffer); gst_buffer_unref (buffer);
return GST_FLOW_NOT_NEGOTIATED; return GST_FLOW_NOT_NEGOTIATED;
@ -1140,13 +1158,11 @@ gst_timecodestamper_transform_ip (GstBaseTransform * vfilter,
/* Update all our internal timecodes as needed */ /* Update all our internal timecodes as needed */
GST_OBJECT_LOCK (timecodestamper); GST_OBJECT_LOCK (timecodestamper);
if (timecodestamper->vinfo.interlace_mode != if (timecodestamper->interlace_mode != GST_VIDEO_INTERLACE_MODE_PROGRESSIVE)
GST_VIDEO_INTERLACE_MODE_PROGRESSIVE)
tc_flags |= GST_VIDEO_TIME_CODE_FLAGS_INTERLACED; tc_flags |= GST_VIDEO_TIME_CODE_FLAGS_INTERLACED;
if (timecodestamper->drop_frame && timecodestamper->vinfo.fps_d == 1001 && if (timecodestamper->drop_frame && timecodestamper->fps_d == 1001 &&
(timecodestamper->vinfo.fps_n == 30000 || (timecodestamper->fps_n == 30000 || timecodestamper->fps_n == 60000))
timecodestamper->vinfo.fps_n == 60000))
tc_flags |= GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME; tc_flags |= GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME;
/* If we don't have an internal timecode yet then either a new one was just /* If we don't have an internal timecode yet then either a new one was just
@ -1162,8 +1178,8 @@ gst_timecodestamper_transform_ip (GstBaseTransform * vfilter,
timecodestamper->reset_internal_tc_from_seek = FALSE; timecodestamper->reset_internal_tc_from_seek = FALSE;
if (timecodestamper->set_internal_tc) { if (timecodestamper->set_internal_tc) {
timecodestamper->internal_tc = timecodestamper->internal_tc =
gst_video_time_code_new (timecodestamper->vinfo.fps_n, gst_video_time_code_new (timecodestamper->fps_n,
timecodestamper->vinfo.fps_d, timecodestamper->fps_d,
timecodestamper->set_internal_tc->config.latest_daily_jam, tc_flags, timecodestamper->set_internal_tc->config.latest_daily_jam, tc_flags,
timecodestamper->set_internal_tc->hours, timecodestamper->set_internal_tc->hours,
timecodestamper->set_internal_tc->minutes, timecodestamper->set_internal_tc->minutes,
@ -1172,8 +1188,8 @@ gst_timecodestamper_transform_ip (GstBaseTransform * vfilter,
timecodestamper->set_internal_tc->field_count); timecodestamper->set_internal_tc->field_count);
} else { } else {
timecodestamper->internal_tc = timecodestamper->internal_tc =
gst_video_time_code_new (timecodestamper->vinfo.fps_n, gst_video_time_code_new (timecodestamper->fps_n,
timecodestamper->vinfo.fps_d, dt_frame, tc_flags, 0, 0, 0, 0, 0); timecodestamper->fps_d, dt_frame, tc_flags, 0, 0, 0, 0, 0);
if (timecodestamper->seeked_frames > 0) { if (timecodestamper->seeked_frames > 0) {
GST_DEBUG_OBJECT (timecodestamper, GST_DEBUG_OBJECT (timecodestamper,
"Adding %" G_GINT64_FORMAT " frames that were seeked", "Adding %" G_GINT64_FORMAT " frames that were seeked",
@ -1249,8 +1265,7 @@ gst_timecodestamper_transform_ip (GstBaseTransform * vfilter,
/* Create timecode for the current frame time */ /* Create timecode for the current frame time */
memset (&rtc_timecode_now, 0, sizeof (rtc_timecode_now)); memset (&rtc_timecode_now, 0, sizeof (rtc_timecode_now));
gst_video_time_code_init_from_date_time_full (&rtc_timecode_now, gst_video_time_code_init_from_date_time_full (&rtc_timecode_now,
timecodestamper->vinfo.fps_n, timecodestamper->vinfo.fps_d, dt_frame, timecodestamper->fps_n, timecodestamper->fps_d, dt_frame, tc_flags, 0);
tc_flags, 0);
tc_str = gst_video_time_code_to_string (&rtc_timecode_now); tc_str = gst_video_time_code_to_string (&rtc_timecode_now);
dt_str = g_date_time_format (dt_frame, "%F %R %z"); dt_str = g_date_time_format (dt_frame, "%F %R %z");
@ -1318,7 +1333,7 @@ gst_timecodestamper_transform_ip (GstBaseTransform * vfilter,
gboolean updated_internal = FALSE; gboolean updated_internal = FALSE;
frame_duration = gst_util_uint64_scale_int_ceil (GST_SECOND, frame_duration = gst_util_uint64_scale_int_ceil (GST_SECOND,
timecodestamper->vinfo.fps_d, timecodestamper->vinfo.fps_n); timecodestamper->fps_d, timecodestamper->fps_n);
g_mutex_lock (&timecodestamper->mutex); g_mutex_lock (&timecodestamper->mutex);
@ -1400,13 +1415,12 @@ gst_timecodestamper_transform_ip (GstBaseTransform * vfilter,
* done yet */ * done yet */
if (ltc_tc->timecode.config.fps_d == 0) { if (ltc_tc->timecode.config.fps_d == 0) {
gint fps_n_div = gint fps_n_div =
((gdouble) timecodestamper->vinfo.fps_n) / ((gdouble) timecodestamper->fps_n) /
timecodestamper->vinfo.fps_d > 30 ? 2 : 1; timecodestamper->fps_d > 30 ? 2 : 1;
ltc_tc->timecode.config.flags = tc_flags; ltc_tc->timecode.config.flags = tc_flags;
ltc_tc->timecode.config.fps_n = ltc_tc->timecode.config.fps_n = timecodestamper->fps_n / fps_n_div;
timecodestamper->vinfo.fps_n / fps_n_div; ltc_tc->timecode.config.fps_d = timecodestamper->fps_d;
ltc_tc->timecode.config.fps_d = timecodestamper->vinfo.fps_d;
} }
tc_str = gst_video_time_code_to_string (&ltc_tc->timecode); tc_str = gst_video_time_code_to_string (&ltc_tc->timecode);
@ -1512,8 +1526,8 @@ gst_timecodestamper_transform_ip (GstBaseTransform * vfilter,
tc = timecodestamper->internal_tc; tc = timecodestamper->internal_tc;
break; break;
case GST_TIME_CODE_STAMPER_SOURCE_ZERO: case GST_TIME_CODE_STAMPER_SOURCE_ZERO:
tc = gst_video_time_code_new (timecodestamper->vinfo.fps_n, tc = gst_video_time_code_new (timecodestamper->fps_n,
timecodestamper->vinfo.fps_d, NULL, tc_flags, 0, 0, 0, 0, 0); timecodestamper->fps_d, NULL, tc_flags, 0, 0, 0, 0, 0);
free_tc = TRUE; free_tc = TRUE;
break; break;
case GST_TIME_CODE_STAMPER_SOURCE_LAST_KNOWN: case GST_TIME_CODE_STAMPER_SOURCE_LAST_KNOWN:
@ -1524,8 +1538,8 @@ gst_timecodestamper_transform_ip (GstBaseTransform * vfilter,
case GST_TIME_CODE_STAMPER_SOURCE_LAST_KNOWN_OR_ZERO: case GST_TIME_CODE_STAMPER_SOURCE_LAST_KNOWN_OR_ZERO:
tc = timecodestamper->last_tc; tc = timecodestamper->last_tc;
if (!tc) { if (!tc) {
tc = gst_video_time_code_new (timecodestamper->vinfo.fps_n, tc = gst_video_time_code_new (timecodestamper->fps_n,
timecodestamper->vinfo.fps_d, NULL, tc_flags, 0, 0, 0, 0, 0); timecodestamper->fps_d, NULL, tc_flags, 0, 0, 0, 0, 0);
free_tc = TRUE; free_tc = TRUE;
} }
break; break;
@ -1535,8 +1549,8 @@ gst_timecodestamper_transform_ip (GstBaseTransform * vfilter,
tc = timecodestamper->ltc_internal_tc; tc = timecodestamper->ltc_internal_tc;
#endif #endif
if (!tc) { if (!tc) {
tc = gst_video_time_code_new (timecodestamper->vinfo.fps_n, tc = gst_video_time_code_new (timecodestamper->fps_n,
timecodestamper->vinfo.fps_d, NULL, tc_flags, 0, 0, 0, 0, 0); timecodestamper->fps_d, NULL, tc_flags, 0, 0, 0, 0, 0);
free_tc = TRUE; free_tc = TRUE;
} }
break; break;
@ -1603,8 +1617,8 @@ gst_timecodestamper_transform_ip (GstBaseTransform * vfilter,
gst_segment_to_stream_time (&vfilter->segment, GST_FORMAT_TIME, gst_segment_to_stream_time (&vfilter->segment, GST_FORMAT_TIME,
GST_BUFFER_PTS (buffer)); GST_BUFFER_PTS (buffer));
duration = duration =
gst_util_uint64_scale_int (GST_SECOND, timecodestamper->vinfo.fps_d, gst_util_uint64_scale_int (GST_SECOND, timecodestamper->fps_d,
timecodestamper->vinfo.fps_n); timecodestamper->fps_n);
s = gst_structure_new ("timecodestamper", "timestamp", G_TYPE_UINT64, s = gst_structure_new ("timecodestamper", "timestamp", G_TYPE_UINT64,
GST_BUFFER_PTS (buffer), "stream-time", G_TYPE_UINT64, stream_time, GST_BUFFER_PTS (buffer), "stream-time", G_TYPE_UINT64, stream_time,
"running-time", G_TYPE_UINT64, running_time, "duration", "running-time", G_TYPE_UINT64, running_time, "duration",
@ -1797,9 +1811,9 @@ gst_timecodestamper_ltcpad_chain (GstPad * pad,
GST_OBJECT_LOCK (timecodestamper); GST_OBJECT_LOCK (timecodestamper);
/* This is only for initialization and needs to be somewhat close to the /* This is only for initialization and needs to be somewhat close to the
* real value. It will be tracked automatically afterwards */ * real value. It will be tracked automatically afterwards */
if (timecodestamper->vinfo.fps_n) { if (timecodestamper->fps_n) {
samples_per_frame = timecodestamper->ainfo.rate * samples_per_frame = timecodestamper->ainfo.rate *
timecodestamper->vinfo.fps_d / timecodestamper->vinfo.fps_n; timecodestamper->fps_d / timecodestamper->fps_n;
} }
GST_OBJECT_UNLOCK (timecodestamper); GST_OBJECT_UNLOCK (timecodestamper);

View file

@ -96,8 +96,10 @@ struct _GstTimeCodeStamper
GstClockTime last_tc_running_time; GstClockTime last_tc_running_time;
GstVideoTimeCode *rtc_tc; GstVideoTimeCode *rtc_tc;
/* Internal state */ /* Internal state, protected by object lock, changed only from video streaming thread */
GstVideoInfo vinfo; /* protected by object lock, changed only from video streaming thread */ gint fps_n;
gint fps_d;
GstVideoInterlaceMode interlace_mode;
/* Seek handling, protected by the object lock */ /* Seek handling, protected by the object lock */
guint32 prev_seek_seqnum; guint32 prev_seek_seqnum;