g_free (frame);
}
+static GstVideoFrame *
+gst_deinterlace_pop_history (GstDeinterlace * self)
+{
+ GstVideoFrame *frame;
+
+ g_return_val_if_fail (self->history_count > 0, NULL);
+
+ GST_DEBUG_OBJECT (self, "Pop last history frame -- current history size %d",
+ self->history_count);
+
+ frame = self->field_history[self->history_count - 1].frame;
+
+ self->history_count--;
+ if (self->locking != GST_DEINTERLACE_LOCKING_NONE && (!self->history_count
+ || GST_VIDEO_FRAME_PLANE_DATA (frame, 0) !=
+ GST_VIDEO_FRAME_PLANE_DATA (self->field_history[self->history_count -
+ 1].frame, 0))) {
+ if (!self->low_latency)
+ self->state_count--;
+ if (self->pattern_lock) {
+ self->pattern_count++;
+ if (self->pattern != -1
+ && self->pattern_count >= telecine_patterns[self->pattern].length) {
+ self->pattern_count = 0;
+ self->output_count = 0;
+ }
+ }
+ }
+
+ GST_DEBUG_OBJECT (self, "Returning frame: %p %" GST_TIME_FORMAT
+ " with duration %" GST_TIME_FORMAT " and size %" G_GSIZE_FORMAT, frame,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (frame->buffer)),
+ GST_TIME_ARGS (GST_BUFFER_DURATION (frame->buffer)),
+ GST_VIDEO_FRAME_SIZE (frame));
+
+ return frame;
+}
+
+static void
+gst_deinterlace_delete_meta_at (GstDeinterlace * self, gint idx)
+{
+ if (self->field_history[idx].frame) {
+ if (self->field_history[idx].tc) {
+ gst_video_time_code_free (self->field_history[idx].tc);
+ self->field_history[idx].tc = NULL;
+ }
+ if (self->field_history[idx].caption) {
+ g_free (self->field_history[idx].caption->data);
+ g_free (self->field_history[idx].caption);
+ self->field_history[idx].caption = NULL;
+ }
+ }
+}
+
+static void
+gst_deinterlace_pop_and_clear (GstDeinterlace * self)
+{
+ gint idx;
+
+ if (self->history_count <= 0)
+ return;
+
+ idx = self->history_count - 1;
+ gst_deinterlace_delete_meta_at (self, idx);
+
+ /* FIXME: pop_history should return a structure with the frame and its meta.
+ * Currently we're just doing guesswork with the indices. Maybe just
+ * refactor the history functionality to make something clearer */
+ gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+}
+
static void
gst_deinterlace_reset_history (GstDeinterlace * self, gboolean drop_all)
{
if (self->field_history[i].frame) {
gst_video_frame_unmap_and_free (self->field_history[i].frame);
self->field_history[i].frame = NULL;
- if (self->field_history[i].tc) {
- gst_video_time_code_free (self->field_history[i].tc);
- }
+ gst_deinterlace_delete_meta_at (self, i);
}
}
}
GST_TIME_ARGS (self->pattern_buf_dur));
}
-static GstVideoFrame *
-gst_deinterlace_pop_history (GstDeinterlace * self)
-{
- GstVideoFrame *frame;
-
- g_return_val_if_fail (self->history_count > 0, NULL);
-
- GST_DEBUG_OBJECT (self, "Pop last history frame -- current history size %d",
- self->history_count);
-
- frame = self->field_history[self->history_count - 1].frame;
-
- self->history_count--;
- if (self->locking != GST_DEINTERLACE_LOCKING_NONE && (!self->history_count
- || GST_VIDEO_FRAME_PLANE_DATA (frame, 0) !=
- GST_VIDEO_FRAME_PLANE_DATA (self->field_history[self->history_count -
- 1].frame, 0))) {
- if (!self->low_latency)
- self->state_count--;
- if (self->pattern_lock) {
- self->pattern_count++;
- if (self->pattern != -1
- && self->pattern_count >= telecine_patterns[self->pattern].length) {
- self->pattern_count = 0;
- self->output_count = 0;
- }
- }
- }
-
- GST_DEBUG_OBJECT (self, "Returning frame: %p %" GST_TIME_FORMAT
- " with duration %" GST_TIME_FORMAT " and size %" G_GSIZE_FORMAT, frame,
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (frame->buffer)),
- GST_TIME_ARGS (GST_BUFFER_DURATION (frame->buffer)),
- GST_VIDEO_FRAME_SIZE (frame));
-
- return frame;
-}
-
static void
gst_deinterlace_get_buffer_state (GstDeinterlace * self, GstVideoFrame * frame,
guint8 * state, GstVideoInterlaceMode * i_mode)
self->field_history[i - fields_to_push].frame;
self->field_history[i].flags =
self->field_history[i - fields_to_push].flags;
- if (self->field_history[i].tc)
- gst_video_time_code_free (self->field_history[i].tc);
- if (self->field_history[i - fields_to_push].tc) {
- self->field_history[i].tc =
- gst_video_time_code_copy (self->field_history[i - fields_to_push].tc);
- } else {
- self->field_history[i].tc = NULL;
- }
+ self->field_history[i].tc = self->field_history[i - fields_to_push].tc;
+ self->field_history[i].caption =
+ self->field_history[i - fields_to_push].caption;
}
if (field_layout == GST_DEINTERLACE_LAYOUT_AUTO) {
if (!onefield) {
GstVideoTimeCodeMeta *meta = gst_buffer_get_video_time_code_meta (buffer);
+ GstVideoCaptionMeta *cc_meta = gst_buffer_get_video_caption_meta (buffer);
GST_DEBUG_OBJECT (self, "Two fields");
self->field_history[1].frame = field1;
self->field_history[1].tc->config.flags &=
~GST_VIDEO_TIME_CODE_FLAGS_INTERLACED;
}
+
+ if (cc_meta) {
+ self->field_history[0].caption = g_new (GstVideoCaptionMeta, 1);
+ self->field_history[0].caption->data = g_malloc (cc_meta->size);
+ self->field_history[0].caption->caption_type = cc_meta->caption_type;
+ self->field_history[0].caption->size = cc_meta->size;
+ memcpy (self->field_history[0].caption->data, cc_meta->data,
+ cc_meta->size);
+ self->field_history[1].caption = g_new (GstVideoCaptionMeta, 1);
+ self->field_history[1].caption->data = g_malloc (cc_meta->size);
+ self->field_history[1].caption->caption_type = cc_meta->caption_type;
+ self->field_history[1].caption->size = cc_meta->size;
+ memcpy (self->field_history[1].caption->data, cc_meta->data,
+ cc_meta->size);
+ }
} else { /* onefield */
GstVideoTimeCodeMeta *meta = gst_buffer_get_video_time_code_meta (buffer);
+ GstVideoCaptionMeta *cc_meta = gst_buffer_get_video_caption_meta (buffer);
GST_DEBUG_OBJECT (self, "One field");
self->field_history[0].frame = field1;
self->field_history[0].tc->config.flags &=
~GST_VIDEO_TIME_CODE_FLAGS_INTERLACED;
}
+
+ if (cc_meta) {
+ self->field_history[0].caption = g_new (GstVideoCaptionMeta, 1);
+ self->field_history[0].caption->data = g_malloc (cc_meta->size);
+ self->field_history[0].caption->caption_type = cc_meta->caption_type;
+ self->field_history[0].caption->size = cc_meta->size;
+ memcpy (self->field_history[0].caption->data, cc_meta->data,
+ cc_meta->size);
+ }
gst_video_frame_unmap_and_free (field2);
}
TelecinePattern pattern;
guint8 phase, count;
const GstDeinterlaceLocking locking = self->locking;
+ gboolean cc_added = FALSE;
memset (&pattern, 0, sizeof (pattern));
if (flush_one && self->drop_orphans) {
GST_DEBUG_OBJECT (self, "Dropping orphan first field");
self->cur_field_idx--;
- gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+ gst_deinterlace_pop_and_clear (self);
goto restart;
}
}
GST_DEBUG_OBJECT (self,
"Frame type: Progressive; pushing buffer as a frame");
/* pop and push */
+ gst_deinterlace_delete_meta_at (self, self->history_count - 1);
self->cur_field_idx--;
field1_frame = gst_deinterlace_pop_history (self);
field1_buffer = field1_frame->buffer;
gst_buffer_ref (field1_buffer);
gst_video_frame_unmap_and_free (field1_frame);
+
/* field2 is the same buffer as field1, but we need to remove it from the
* history anyway */
self->cur_field_idx--;
- gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+ gst_deinterlace_pop_and_clear (self);
GST_DEBUG_OBJECT (self,
"[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
GST_TIME_FORMAT,
gst_buffer_add_video_time_code_meta (outbuf,
self->field_history[index].tc);
}
+ if (self->field_history[index].caption) {
+ g_assert (self->field_history[index].caption->data != NULL);
+ g_assert (!cc_added);
+ gst_buffer_add_video_caption_meta (outbuf,
+ self->field_history[index].caption->caption_type,
+ self->field_history[index].caption->data,
+ self->field_history[index].caption->size);
+ cc_added = TRUE;
+ }
if (IS_TELECINE (interlacing_mode) && !self->telecine_tc_warned) {
self->telecine_tc_warned = TRUE;
GST_FIXME_OBJECT (self,
/* Check if we need to drop the frame because of QoS */
if (!gst_deinterlace_do_qos (self, buf)) {
self->cur_field_idx--;
- gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+ gst_deinterlace_pop_and_clear (self);
gst_buffer_unref (outbuf);
outbuf = NULL;
ret = GST_FLOW_OK;
} else {
if (self->cur_field_idx < 0 && flushing) {
if (self->history_count == 1) {
- gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+ gst_deinterlace_pop_and_clear (self);
goto need_more;
}
self->cur_field_idx++;
|| self->cur_field_idx + 1 +
gst_deinterlace_method_get_latency (self->method) <
self->history_count || flushing) {
- gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+ gst_deinterlace_pop_and_clear (self);
}
if (gst_deinterlace_clip_buffer (self, outbuf)) {
GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
self->history_count);
self->cur_field_idx--;
- gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+ gst_deinterlace_pop_and_clear (self);
interlacing_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
return ret;
}
&& !IS_TELECINE (interlacing_mode))) {
GST_DEBUG_OBJECT (self, "Removing unused top field");
self->cur_field_idx--;
- gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+ gst_deinterlace_pop_and_clear (self);
if (flush_one && !self->drop_orphans) {
GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
gst_buffer_add_video_time_code_meta (outbuf,
self->field_history[index].tc);
}
+ if (self->field_history[index].caption && !cc_added) {
+ g_assert (self->field_history[index].caption->data != NULL);
+ gst_buffer_add_video_caption_meta (outbuf,
+ self->field_history[index].caption->caption_type,
+ self->field_history[index].caption->data,
+ self->field_history[index].caption->size);
+ cc_added = TRUE;
+ }
if (IS_TELECINE (interlacing_mode) && !self->telecine_tc_warned) {
self->telecine_tc_warned = TRUE;
GST_FIXME_OBJECT (self,
/* Check if we need to drop the frame because of QoS */
if (!gst_deinterlace_do_qos (self, buf)) {
self->cur_field_idx--;
- gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+ gst_deinterlace_pop_and_clear (self);
gst_buffer_unref (outbuf);
outbuf = NULL;
ret = GST_FLOW_OK;
|| self->cur_field_idx + 1 +
gst_deinterlace_method_get_latency (self->method) <
self->history_count) {
- gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+ gst_deinterlace_pop_and_clear (self);
}
if (gst_deinterlace_clip_buffer (self, outbuf)) {
GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
self->history_count);
self->cur_field_idx--;
- gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+ gst_deinterlace_pop_and_clear (self);
interlacing_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
return ret;
}
&& !IS_TELECINE (interlacing_mode))) {
GST_DEBUG_OBJECT (self, "Removing unused bottom field");
self->cur_field_idx--;
- gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
+ gst_deinterlace_pop_and_clear (self);
if (flush_one && !self->drop_orphans) {
GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");