static void deinterlace_frame_di_greedyh_planar (GstDeinterlaceMethod * method, const GstDeinterlaceField * history, guint history_count, GstVideoFrame * outframe, int cur_field_idx) { GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (method); GstDeinterlaceMethodGreedyHClass *klass = GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS (self); gint InfoIsOdd; gint RowStride; gint FieldHeight; gint Pitch; const guint8 *L1; // ptr to Line1, of 3 const guint8 *L2; // ptr to Line2, the weave line const guint8 *L3; // ptr to Line3 const guint8 *L2P; // ptr to prev Line2 guint8 *Dest; gint i; ScanlineFunction scanline; if (cur_field_idx + 2 > history_count || cur_field_idx < 1) { GstDeinterlaceMethod *backup_method; backup_method = g_object_new (gst_deinterlace_method_linear_get_type (), NULL); gst_deinterlace_method_setup (backup_method, method->vinfo); gst_deinterlace_method_deinterlace_frame (backup_method, history, history_count, outframe, cur_field_idx); g_object_unref (backup_method); return; } cur_field_idx += 2; for (i = 0; i < 3; i++) { InfoIsOdd = (history[cur_field_idx - 1].flags == PICTURE_INTERLACED_BOTTOM); RowStride = GST_VIDEO_FRAME_PLANE_STRIDE (outframe, i); FieldHeight = GST_VIDEO_FRAME_HEIGHT (outframe) / 2; Pitch = RowStride * 2; if (i == 0) scanline = klass->scanline_planar_y; else scanline = klass->scanline_planar_uv; Dest = GST_VIDEO_FRAME_PLANE_DATA (outframe, i); L1 = GST_VIDEO_FRAME_PLANE_DATA (history[cur_field_idx - 2].frame, i); if (history[cur_field_idx - 2].flags & PICTURE_INTERLACED_BOTTOM) L1 += RowStride; L2 = GST_VIDEO_FRAME_PLANE_DATA (history[cur_field_idx - 1].frame, i); if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM) L2 += RowStride; L3 = L1 + Pitch; L2P = GST_VIDEO_FRAME_PLANE_DATA (history[cur_field_idx - 3].frame, i); if (history[cur_field_idx - 3].flags & PICTURE_INTERLACED_BOTTOM) L2P += RowStride; deinterlace_frame_di_greedyh_planar_plane (self, L1, L2, L3, L2P, Dest, RowStride, FieldHeight, Pitch, InfoIsOdd, scanline); } }
static void deinterlace_frame_di_greedyh_planar (GstDeinterlaceMethod * method, const GstDeinterlaceField * history, guint history_count, GstBuffer * outbuf, int cur_field_idx) { GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (method); GstDeinterlaceMethodGreedyHClass *klass = GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS (self); gint InfoIsOdd; gint RowStride; gint FieldHeight; gint Pitch; const guint8 *L1; // ptr to Line1, of 3 const guint8 *L2; // ptr to Line2, the weave line const guint8 *L3; // ptr to Line3 const guint8 *L2P; // ptr to prev Line2 guint8 *Dest; gint i; gint Offset; ScanlineFunction scanline; if (cur_field_idx + 2 > history_count || cur_field_idx < 1) { GstDeinterlaceMethod *backup_method; backup_method = g_object_new (gst_deinterlace_method_linear_get_type (), NULL); gst_deinterlace_method_setup (backup_method, method->format, method->frame_width, method->frame_height); gst_deinterlace_method_deinterlace_frame (backup_method, history, history_count, outbuf, cur_field_idx); g_object_unref (backup_method); return; } cur_field_idx += 2; for (i = 0; i < 3; i++) { Offset = method->offset[i]; InfoIsOdd = (history[cur_field_idx - 1].flags == PICTURE_INTERLACED_BOTTOM); RowStride = method->row_stride[i]; FieldHeight = method->height[i] / 2; Pitch = method->row_stride[i] * 2; if (i == 0) scanline = klass->scanline_planar_y; else scanline = klass->scanline_planar_uv; Dest = GST_BUFFER_DATA (outbuf) + Offset; L1 = GST_BUFFER_DATA (history[cur_field_idx - 2].buf) + Offset; if (history[cur_field_idx - 2].flags & PICTURE_INTERLACED_BOTTOM) L1 += RowStride; L2 = GST_BUFFER_DATA (history[cur_field_idx - 1].buf) + Offset; if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM) L2 += RowStride; L3 = L1 + Pitch; L2P = GST_BUFFER_DATA (history[cur_field_idx - 3].buf) + Offset; if (history[cur_field_idx - 3].flags & PICTURE_INTERLACED_BOTTOM) L2P += RowStride; deinterlace_frame_di_greedyh_planar_plane (self, L1, L2, L3, L2P, Dest, RowStride, FieldHeight, Pitch, InfoIsOdd, scanline); } }
static void deinterlace_frame_di_greedyh_packed (GstDeinterlaceMethod * method, const GstDeinterlaceField * history, guint history_count, GstVideoFrame * outframe, int cur_field_idx) { GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (method); GstDeinterlaceMethodGreedyHClass *klass = GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS (self); gint InfoIsOdd = 0; gint Line; gint RowStride = GST_VIDEO_FRAME_COMP_STRIDE (outframe, 0); gint FieldHeight = GST_VIDEO_INFO_HEIGHT (method->vinfo) / 2; gint Pitch = RowStride * 2; const guint8 *L1; // ptr to Line1, of 3 const guint8 *L2; // ptr to Line2, the weave line const guint8 *L3; // ptr to Line3 const guint8 *L2P; // ptr to prev Line2 guint8 *Dest = GST_VIDEO_FRAME_COMP_DATA (outframe, 0); ScanlineFunction scanline; if (cur_field_idx + 2 > history_count || cur_field_idx < 1) { GstDeinterlaceMethod *backup_method; backup_method = g_object_new (gst_deinterlace_method_linear_get_type (), NULL); gst_deinterlace_method_setup (backup_method, method->vinfo); gst_deinterlace_method_deinterlace_frame (backup_method, history, history_count, outframe, cur_field_idx); g_object_unref (backup_method); return; } cur_field_idx += 2; switch (GST_VIDEO_INFO_FORMAT (method->vinfo)) { case GST_VIDEO_FORMAT_YUY2: case GST_VIDEO_FORMAT_YVYU: scanline = klass->scanline_yuy2; break; case GST_VIDEO_FORMAT_UYVY: scanline = klass->scanline_uyvy; break; case GST_VIDEO_FORMAT_AYUV: scanline = klass->scanline_ayuv; break; default: g_assert_not_reached (); return; } // copy first even line no matter what, and the first odd line if we're // processing an EVEN field. (note diff from other deint rtns.) if (history[cur_field_idx - 1].flags == PICTURE_INTERLACED_BOTTOM) { InfoIsOdd = 1; L1 = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 2].frame, 0); if (history[cur_field_idx - 2].flags & PICTURE_INTERLACED_BOTTOM) L1 += RowStride; L2 = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 1].frame, 0); if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM) L2 += RowStride; L3 = L1 + Pitch; L2P = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 3].frame, 0); if (history[cur_field_idx - 3].flags & PICTURE_INTERLACED_BOTTOM) L2P += RowStride; // copy first even line memcpy (Dest, L1, RowStride); Dest += RowStride; } else { InfoIsOdd = 0; L1 = GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 2].frame, 0); if (history[cur_field_idx - 2].flags & PICTURE_INTERLACED_BOTTOM) L1 += RowStride; L2 = (guint8 *) GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 1].frame, 0) + Pitch; if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM) L2 += RowStride; L3 = L1 + Pitch; L2P = (guint8 *) GST_VIDEO_FRAME_COMP_DATA (history[cur_field_idx - 3].frame, 0) + Pitch; if (history[cur_field_idx - 3].flags & PICTURE_INTERLACED_BOTTOM) L2P += RowStride; // copy first even line memcpy (Dest, L1, RowStride); Dest += RowStride; // then first odd line memcpy (Dest, L1, RowStride); Dest += RowStride; } for (Line = 0; Line < (FieldHeight - 1); ++Line) { scanline (self, L1, L2, L3, L2P, Dest, RowStride); Dest += RowStride; memcpy (Dest, L3, RowStride); Dest += RowStride; L1 += Pitch; L2 += Pitch; L3 += Pitch; L2P += Pitch; } if (InfoIsOdd) { memcpy (Dest, L2, RowStride); } }
static GstFlowReturn gst_deinterlace2_chain (GstPad * pad, GstBuffer * buf) { GstDeinterlace2 *self = NULL; GstClockTime timestamp; GstFlowReturn ret = GST_FLOW_OK; gint fields_required = 0; gint cur_field_idx = 0; self = GST_DEINTERLACE2 (GST_PAD_PARENT (pad)); gst_deinterlace2_push_history (self, buf); buf = NULL; fields_required = gst_deinterlace_method_get_fields_required (self->method); /* Not enough fields in the history */ if (self->history_count < fields_required + 1) { /* TODO: do bob or just forward frame */ GST_DEBUG ("HistoryCount=%d", self->history_count); return GST_FLOW_OK; } while (self->history_count >= fields_required) { if (self->fields == GST_DEINTERLACE2_ALL) GST_DEBUG ("All fields"); if (self->fields == GST_DEINTERLACE2_TF) GST_DEBUG ("Top fields"); if (self->fields == GST_DEINTERLACE2_BF) GST_DEBUG ("Bottom fields"); cur_field_idx = self->history_count - fields_required; if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP && self->fields == GST_DEINTERLACE2_TF) || self->fields == GST_DEINTERLACE2_ALL) { GST_DEBUG ("deinterlacing top field"); /* create new buffer */ ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad, GST_BUFFER_OFFSET_NONE, self->frame_size, GST_PAD_CAPS (self->srcpad), &self->out_buf); if (ret != GST_FLOW_OK) return ret; /* do magic calculus */ gst_deinterlace_method_deinterlace_frame (self->method, self); g_assert (self->history_count - 1 - gst_deinterlace_method_get_latency (self->method) >= 0); buf = self->field_history[self->history_count - 1 - gst_deinterlace_method_get_latency (self->method)].buf; timestamp = GST_BUFFER_TIMESTAMP (buf); gst_buffer_unref (gst_deinterlace2_pop_history (self)); GST_BUFFER_TIMESTAMP (self->out_buf) = timestamp; if (self->fields == GST_DEINTERLACE2_ALL) GST_BUFFER_DURATION (self->out_buf) = self->field_duration; else GST_BUFFER_DURATION (self->out_buf) = 2 * self->field_duration; ret = gst_pad_push (self->srcpad, self->out_buf); self->out_buf = NULL; if (ret != GST_FLOW_OK) return ret; } /* no calculation done: remove excess field */ else if (self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP && self->fields == GST_DEINTERLACE2_BF) { GST_DEBUG ("Removing unused top field"); gst_buffer_unref (gst_deinterlace2_pop_history (self)); } cur_field_idx = self->history_count - fields_required; if (self->history_count < fields_required) break; /* deinterlace bottom_field */ if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_BOTTOM && self->fields == GST_DEINTERLACE2_BF) || self->fields == GST_DEINTERLACE2_ALL) { GST_DEBUG ("deinterlacing bottom field"); /* create new buffer */ ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad, GST_BUFFER_OFFSET_NONE, self->frame_size, GST_PAD_CAPS (self->srcpad), &self->out_buf); if (ret != GST_FLOW_OK) return ret; /* do magic calculus */ gst_deinterlace_method_deinterlace_frame (self->method, self); g_assert (self->history_count - 1 - gst_deinterlace_method_get_latency (self->method) >= 0); buf = self->field_history[self->history_count - 1 - gst_deinterlace_method_get_latency (self->method)].buf; timestamp = GST_BUFFER_TIMESTAMP (buf); gst_buffer_unref (gst_deinterlace2_pop_history (self)); GST_BUFFER_TIMESTAMP (self->out_buf) = timestamp; if (self->fields == GST_DEINTERLACE2_ALL) GST_BUFFER_DURATION (self->out_buf) = self->field_duration; else GST_BUFFER_DURATION (self->out_buf) = 2 * self->field_duration; ret = gst_pad_push (self->srcpad, self->out_buf); self->out_buf = NULL; if (ret != GST_FLOW_OK) return ret; } /* no calculation done: remove excess field */ else if (self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_BOTTOM && self->fields == GST_DEINTERLACE2_TF) { GST_DEBUG ("Removing unused bottom field"); gst_buffer_unref (gst_deinterlace2_pop_history (self)); } } GST_DEBUG ("----chain end ----\n\n"); return ret; }