diff mbox

[15/19] dvdspu: add interlaced support

Message ID 1325628171-4803-8-git-send-email-rob@ti.com
State New
Headers show

Commit Message

Rob Clark Jan. 3, 2012, 10:02 p.m. UTC
---
See: https://bugzilla.gnome.org/show_bug.cgi?id=667224

 gst/dvdspu/gstdvdspu.c            |    5 +
 gst/dvdspu/gstdvdspu.h            |    1 +
 gst/dvdspu/gstspu-vobsub-render.c |  185 ++++++++++++++++++++++---------------
 3 files changed, 116 insertions(+), 75 deletions(-)
diff mbox

Patch

diff --git a/gst/dvdspu/gstdvdspu.c b/gst/dvdspu/gstdvdspu.c
index fa68b24..4b20983 100644
--- a/gst/dvdspu/gstdvdspu.c
+++ b/gst/dvdspu/gstdvdspu.c
@@ -321,6 +321,7 @@  gst_dvd_spu_video_set_caps (GstPad * pad, GstCaps * caps)
   gint i;
   gint fps_n, fps_d;
   guint32 format;
+  gboolean interlaced = FALSE;
   SpuState *state;
 
   s = gst_caps_get_structure (caps, 0);
@@ -332,12 +333,16 @@  gst_dvd_spu_video_set_caps (GstPad * pad, GstCaps * caps)
     goto done;
   }
 
+  /* interlaced field is optional: */
+  gst_structure_get_boolean (s, "interlaced", &interlaced);
+
   DVD_SPU_LOCK (dvdspu);
 
   state = &dvdspu->spu_state;
 
   state->fps_n = fps_n;
   state->fps_d = fps_d;
+  state->interlaced = interlaced;
 
   state->vid_height = h;
   state->Y_height = GST_ROUND_UP_2 (h);
diff --git a/gst/dvdspu/gstdvdspu.h b/gst/dvdspu/gstdvdspu.h
index d78f60f..9a2f4d8 100644
--- a/gst/dvdspu/gstdvdspu.h
+++ b/gst/dvdspu/gstdvdspu.h
@@ -75,6 +75,7 @@  struct SpuState {
   gint16 Y_height, UV_height;
   gint32 U_offset, V_offset;
   gint8  UV_pixstride;
+  gboolean interlaced;
 
   guint32 *comp_bufs[3]; /* Compositing buffers for U+V & A */
   guint16 comp_left;
diff --git a/gst/dvdspu/gstspu-vobsub-render.c b/gst/dvdspu/gstspu-vobsub-render.c
index 83943e9..ad8d96b 100644
--- a/gst/dvdspu/gstspu-vobsub-render.c
+++ b/gst/dvdspu/gstspu-vobsub-render.c
@@ -392,6 +392,21 @@  gstspu_vobsub_clear_comp_buffers (SpuState * state)
   state->vobsub.comp_last_x[1] = -1;
 }
 
+static inline gint
+ilaced_y (SpuState * state, gint y)
+{
+  if (state->interlaced) {
+    if (y % 2) {
+      /* odd field */
+      y = (y + state->Y_height) / 2;
+    } else {
+      /* even field */
+      y = y / 2;
+    }
+  }
+  return y;
+}
+
 static void
 gstspu_vobsub_draw_highlight (SpuState * state,
     GstBuffer * buf, SpuRect *rect)
@@ -399,36 +414,113 @@  gstspu_vobsub_draw_highlight (SpuState * state,
   guint8 *cur;
   gint16 pos;
 
-  cur = GST_BUFFER_DATA (buf) + state->Y_stride * rect->top;
+  cur = GST_BUFFER_DATA (buf) + state->Y_stride *
+      ilaced_y (state, rect->top);
   for (pos = rect->left + 1; pos < rect->right; pos++)
     cur[pos] = (cur[pos] / 2) + 0x8;
-  cur = GST_BUFFER_DATA (buf) + state->Y_stride * rect->bottom;
+  cur = GST_BUFFER_DATA (buf) + state->Y_stride *
+      ilaced_y (state, rect->bottom);
   for (pos = rect->left + 1; pos < rect->right; pos++)
     cur[pos] = (cur[pos] / 2) + 0x8;
-  cur = GST_BUFFER_DATA (buf) + state->Y_stride * rect->top;
   for (pos = rect->top; pos <= rect->bottom; pos++) {
+    cur = GST_BUFFER_DATA (buf) + state->Y_stride *
+        ilaced_y (state, pos);
     cur[rect->left] = (cur[rect->left] / 2) + 0x8;
     cur[rect->right] = (cur[rect->right] / 2) + 0x8;
-    cur += state->Y_stride;
   }
 }
 
+static void
+gstspu_vobsub_render_field (SpuState * state, GstBuffer * buf,
+    gint y, gint last_y, gint y_inc,
+    guint16 * rle_offset_even, guint16 * rle_offset_odd)
+{
+  guint8 *planes[3];            /* YUV frame pointers */
+
+  /* Store the start of each plane */
+  planes[0] = GST_BUFFER_DATA (buf);
+  planes[1] = planes[0] + state->U_offset;
+  planes[2] = planes[1] + state->V_offset;
+
+  /* Update our plane references to the first line of the disp_rect */
+  planes[0] += state->Y_stride * y;
+  planes[1] += state->UV_stride * (y / 2);
+  planes[2] += state->UV_stride * (y / 2);
+
+  /* Set up HL or Change Color & Contrast rect tracking */
+  if (state->vobsub.hl_rect.top != -1) {
+    state->vobsub.cur_chg_col = &state->vobsub.hl_ctrl_i;
+    state->vobsub.cur_chg_col_end = state->vobsub.cur_chg_col + 1;
+  } else if (state->vobsub.n_line_ctrl_i > 0) {
+    state->vobsub.cur_chg_col = state->vobsub.line_ctrl_i;
+    state->vobsub.cur_chg_col_end =
+        state->vobsub.cur_chg_col + state->vobsub.n_line_ctrl_i;
+  } else
+    state->vobsub.cur_chg_col = NULL;
+
+  for (state->vobsub.cur_Y = y; state->vobsub.cur_Y <= last_y;
+      state->vobsub.cur_Y += y_inc) {
+    gboolean clip, visible = FALSE;
+
+    clip = (state->vobsub.cur_Y < state->vobsub.clip_rect.top
+        || state->vobsub.cur_Y > state->vobsub.clip_rect.bottom);
+
+    /* Reset the compositing buffer */
+    gstspu_vobsub_clear_comp_buffers (state);
+    /* Render even line */
+    state->vobsub.comp_last_x_ptr = state->vobsub.comp_last_x;
+    visible |= gstspu_vobsub_render_line (state, planes, rle_offset_even);
+
+    /* Advance the luminance output pointer */
+    planes[0] += state->Y_stride;
+
+    state->vobsub.cur_Y += y_inc;
+
+    /* Render odd line */
+    state->vobsub.comp_last_x_ptr = state->vobsub.comp_last_x + 1;
+    visible |= gstspu_vobsub_render_line (state, planes, rle_offset_odd);
+
+    if (visible && !clip) {
+      /* Blend the accumulated UV compositing buffers onto the output */
+      gstspu_vobsub_blend_comp_buffers (state, planes);
+    }
+
+    /* Update all the output pointers */
+    planes[0] += state->Y_stride;
+    planes[1] += state->UV_stride;
+    planes[2] += state->UV_stride;
+  }
+  if (state->vobsub.cur_Y == state->vobsub.disp_rect.bottom) {
+    gboolean clip, visible = FALSE;
+
+    clip = (state->vobsub.cur_Y < state->vobsub.clip_rect.top
+        || state->vobsub.cur_Y > state->vobsub.clip_rect.bottom);
+
+    g_assert ((state->vobsub.disp_rect.bottom & 0x01) == 0);
+
+    if (!clip) {
+      /* Render a remaining lone last even line. y already has the correct value
+       * after the above loop exited. */
+      gstspu_vobsub_clear_comp_buffers (state);
+      state->vobsub.comp_last_x_ptr = state->vobsub.comp_last_x;
+      visible |= gstspu_vobsub_render_line (state, planes, rle_offset_even);
+      if (visible)
+        gstspu_vobsub_blend_comp_buffers (state, planes);
+    }
+  }
+
+}
+
 void
 gstspu_vobsub_render (GstDVDSpu * dvdspu, GstBuffer * buf)
 {
   SpuState *state = &dvdspu->spu_state;
-  guint8 *planes[3];            /* YUV frame pointers */
   gint y, last_y;
 
   /* Set up our initial state */
   if (G_UNLIKELY (state->vobsub.pix_buf == NULL))
     return;
 
-  /* Store the start of each plane */
-  planes[0] = GST_BUFFER_DATA (buf);
-  planes[1] = planes[0] + state->U_offset;
-  planes[2] = planes[1] + state->V_offset;
-
   GST_DEBUG_OBJECT (dvdspu,
       "Rendering SPU. disp_rect %d,%d to %d,%d. hl_rect %d,%d to %d,%d",
       state->vobsub.disp_rect.left, state->vobsub.disp_rect.top,
@@ -447,17 +539,6 @@  gstspu_vobsub_render (GstDVDSpu * dvdspu, GstBuffer * buf)
   /* Update all the palette caches */
   gstspu_vobsub_update_palettes (dvdspu, state);
 
-  /* Set up HL or Change Color & Contrast rect tracking */
-  if (state->vobsub.hl_rect.top != -1) {
-    state->vobsub.cur_chg_col = &state->vobsub.hl_ctrl_i;
-    state->vobsub.cur_chg_col_end = state->vobsub.cur_chg_col + 1;
-  } else if (state->vobsub.n_line_ctrl_i > 0) {
-    state->vobsub.cur_chg_col = state->vobsub.line_ctrl_i;
-    state->vobsub.cur_chg_col_end =
-        state->vobsub.cur_chg_col + state->vobsub.n_line_ctrl_i;
-  } else
-    state->vobsub.cur_chg_col = NULL;
-
   state->vobsub.clip_rect.left = state->vobsub.disp_rect.left;
   state->vobsub.clip_rect.right = state->vobsub.disp_rect.right;
 
@@ -533,60 +614,14 @@  gstspu_vobsub_render (GstDVDSpu * dvdspu, GstBuffer * buf)
    * single line at the end if the display rect ends on an even line too. */
   last_y = (state->vobsub.disp_rect.bottom - 1) & ~(0x01);
 
-  /* Update our plane references to the first line of the disp_rect */
-  planes[0] += state->Y_stride * y;
-  planes[1] += state->UV_stride * (y / 2);
-  planes[2] += state->UV_stride * (y / 2);
-
-  for (state->vobsub.cur_Y = y; state->vobsub.cur_Y <= last_y;
-      state->vobsub.cur_Y++) {
-    gboolean clip, visible = FALSE;
-
-    clip = (state->vobsub.cur_Y < state->vobsub.clip_rect.top
-        || state->vobsub.cur_Y > state->vobsub.clip_rect.bottom);
-
-    /* Reset the compositing buffer */
-    gstspu_vobsub_clear_comp_buffers (state);
-    /* Render even line */
-    state->vobsub.comp_last_x_ptr = state->vobsub.comp_last_x;
-    visible |= gstspu_vobsub_render_line (state, planes, &state->vobsub.cur_offsets[0]);
-    if (!clip) {
-      /* Advance the luminance output pointer */
-      planes[0] += state->Y_stride;
-    }
-    state->vobsub.cur_Y++;
-
-    /* Render odd line */
-    state->vobsub.comp_last_x_ptr = state->vobsub.comp_last_x + 1;
-    visible |= gstspu_vobsub_render_line (state, planes, &state->vobsub.cur_offsets[1]);
-
-    if (visible && !clip) {
-      /* Blend the accumulated UV compositing buffers onto the output */
-      gstspu_vobsub_blend_comp_buffers (state, planes);
-
-      /* Update all the output pointers */
-      planes[0] += state->Y_stride;
-      planes[1] += state->UV_stride;
-      planes[2] += state->UV_stride;
-    }
-  }
-  if (state->vobsub.cur_Y == state->vobsub.disp_rect.bottom) {
-    gboolean clip, visible = FALSE;
-
-    clip = (state->vobsub.cur_Y < state->vobsub.clip_rect.top
-        || state->vobsub.cur_Y > state->vobsub.clip_rect.bottom);
-
-    g_assert ((state->vobsub.disp_rect.bottom & 0x01) == 0);
-
-    if (!clip) {
-      /* Render a remaining lone last even line. y already has the correct value
-       * after the above loop exited. */
-      gstspu_vobsub_clear_comp_buffers (state);
-      state->vobsub.comp_last_x_ptr = state->vobsub.comp_last_x;
-      visible |= gstspu_vobsub_render_line (state, planes, &state->vobsub.cur_offsets[0]);
-      if (visible)
-        gstspu_vobsub_blend_comp_buffers (state, planes);
-    }
+  if (state->interlaced) {
+    gstspu_vobsub_render_field (state, buf, y, last_y, 2,
+        &state->vobsub.cur_offsets[0], &state->vobsub.cur_offsets[0]);
+    gstspu_vobsub_render_field (state, buf, y+1, last_y, 2,
+        &state->vobsub.cur_offsets[1], &state->vobsub.cur_offsets[1]);
+  } else {
+    gstspu_vobsub_render_field (state, buf, y, last_y, 1,
+        &state->vobsub.cur_offsets[0], &state->vobsub.cur_offsets[1]);
   }
 
   /* for debugging purposes, draw a faint rectangle at the edges of the disp_rect */