emotion: protection against bad decoder.
authorcedric <cedric>
Sat, 3 Sep 2011 12:36:04 +0000 (12:36 +0000)
committercedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sat, 3 Sep 2011 12:36:04 +0000 (12:36 +0000)
git-svn-id: http://svn.enlightenment.org/svn/e/trunk/emotion@63118 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/modules/gstreamer/emotion_gstreamer.h
src/modules/gstreamer/emotion_sink.c

index 908172e..9dd3ab9 100644 (file)
 #include "emotion_private.h"
 
 typedef void (*Evas_Video_Convert_Cb)(unsigned char *evas_data,
-                                     const unsigned char *gst_data,
-                                     unsigned int w,
-                                     unsigned int h);
+                                      const unsigned char *gst_data,
+                                      unsigned int w,
+                                      unsigned int h,
+                                      unsigned int output_height);
 
 typedef struct _EvasVideoSinkPrivate EvasVideoSinkPrivate;
 typedef struct _EvasVideoSink        EvasVideoSink;
@@ -122,8 +123,9 @@ struct _EvasVideoSinkPrivate {
 
    Evas_Video_Convert_Cb func;
 
-   int width;
-   int height;
+   unsigned int width;
+   unsigned int height;
+   unsigned int source_height;
    Evas_Colorspace eformat;
 
    Eina_Lock m;
index 9070b2c..09accdd 100644 (file)
@@ -45,12 +45,12 @@ static void evas_video_sink_samsung_main_render(void *data);
 
 static void
 _evas_video_bgrx_step(unsigned char *evas_data, const unsigned char *gst_data,
-                      unsigned int w, unsigned int h, unsigned int step)
+                      unsigned int w, unsigned int h __UNUSED__, unsigned int output_height, unsigned int step)
 {
    unsigned int x;
    unsigned int y;
 
-   for (y = 0; y < h; ++y)
+   for (y = 0; y < output_height; ++y)
      {
         for (x = 0; x < w; x++)
           {
@@ -65,24 +65,24 @@ _evas_video_bgrx_step(unsigned char *evas_data, const unsigned char *gst_data,
 }
 
 static void
-_evas_video_bgr(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h)
+_evas_video_bgr(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h, unsigned int output_height)
 {
-   _evas_video_bgrx_step(evas_data, gst_data, w, h, 3);
+   _evas_video_bgrx_step(evas_data, gst_data, w, h, output_height, 3);
 }
 
 static void
-_evas_video_bgrx(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h)
+_evas_video_bgrx(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h, unsigned int output_height)
 {
-   _evas_video_bgrx_step(evas_data, gst_data, w, h, 4);
+   _evas_video_bgrx_step(evas_data, gst_data, w, h, output_height, 4);
 }
 
 static void
-_evas_video_bgra(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h)
+_evas_video_bgra(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h __UNUSED__, unsigned int output_height)
 {
    unsigned int x;
    unsigned int y;
 
-   for (y = 0; y < h; ++y)
+   for (y = 0; y < output_height; ++y)
      {
         unsigned char alpha;
 
@@ -100,75 +100,81 @@ _evas_video_bgra(unsigned char *evas_data, const unsigned char *gst_data, unsign
 }
 
 static void
-_evas_video_i420(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h)
+_evas_video_i420(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h, unsigned int output_height)
 {
    const unsigned char **rows;
-   unsigned int i;
+   unsigned int i, j;
+   unsigned int rh;
+
+   rh = output_height;
 
    rows = (const unsigned char **)evas_data;
 
-   for (i = 0; i < h; i++)
+   for (i = 0; i < rh; i++)
      rows[i] = &gst_data[i * w];
 
-   rows += h;
-   for (i = 0; i < (h / 2); i++)
-     rows[i] = &gst_data[h * w + i * (w / 2)];
+   for (j = 0; j < (rh / 2); j++, i++)
+     rows[i] = &gst_data[h * w + j * (w / 2)];
 
-   rows += h / 2;
-   for (i = 0; i < (h / 2); i++)
-     rows[i] = &gst_data[h * w + h * (w /4) + i * (w / 2)];
+   for (j = 0; j < (rh / 2); j++, i++)
+     rows[i] = &gst_data[h * w + h * (w / 4) + j * (w / 2)];
+   WRN("I420: %i (max: %i for height %i, real height = %i) = %p", i, 2 * h, h, rh, evas_data);
 }
 
 static void
-_evas_video_yv12(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h)
+_evas_video_yv12(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h, unsigned int output_height)
 {
    const unsigned char **rows;
-   unsigned int i;
+   unsigned int i, j;
+   unsigned int rh;
+
+   rh = output_height;
 
    rows = (const unsigned char **)evas_data;
 
-   for (i = 0; i < h; i++)
+   for (i = 0; i < rh; i++)
      rows[i] = &gst_data[i * w];
 
-   rows += h;
-   for (i = 0; i < (h / 2); i++)
-     rows[i] = &gst_data[h * w + h * (w /4) + i * (w / 2)];
+   for (j = 0; j < (rh / 2); j++, i++)
+     rows[i] = &gst_data[h * w + h * (w / 4) + j * (w / 2)];
 
-   rows += h / 2;
-   for (i = 0; i < (h / 2); i++)
-     rows[i] = &gst_data[h * w + i * (w / 2)];
+   for (j = 0; j < (rh / 2); j++, i++)
+     rows[i] = &gst_data[h * w + j * (w / 2)];
+   WRN("YV12: %i (max: %i for height %i, real height = %i) = %p", i, 2 * h, h, rh, evas_data);
 }
 
 static void
-_evas_video_yuy2(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h)
+_evas_video_yuy2(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h __UNUSED__, unsigned int output_height)
 {
    const unsigned char **rows;
    unsigned int i;
 
    rows = (const unsigned char **)evas_data;
 
-   for (i = 0; i < h; i++)
+   for (i = 0; i < output_height; i++)
      rows[i] = &gst_data[i * w * 2];
 }
 
 static void
-_evas_video_nv12(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h)
+_evas_video_nv12(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h, unsigned int output_height)
 {
    const unsigned char **rows;
    unsigned int i, j;
+   unsigned int rh;
+
+   rh = output_height;
 
    rows = (const unsigned char **)evas_data;
 
-   for (i = 0; i < h; i++)
+   for (i = 0; i < rh; i++)
      rows[i] = &gst_data[i * w];
 
-   rows += h;
-   for (j = 0; j < (h / 2); j++, i++)
+   for (j = 0; j < (rh / 2); j++, i++)
      rows[i] = &gst_data[h * w + j * w];
 }
 
 static void
-_evas_video_mt12(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h)
+_evas_video_mt12(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h, unsigned int output_height __UNUSED__)
 {
    const unsigned char **rows;
    unsigned int i;
@@ -185,13 +191,12 @@ _evas_video_mt12(unsigned char *evas_data, const unsigned char *gst_data, unsign
         i++;
      }
 
-   rows += h;
    for (j = 0; j < ((h / 2) / 32) / 2; ++j, ++i)
      rows[i] = &gst_data[h * w + j * (w / 2) * 2 * 16];
 }
 
 static void
-_evas_video_st12_multiplane(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h)
+_evas_video_st12_multiplane(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h, unsigned int output_height __UNUSED__)
 {
    const GstMultiPlaneImageBuffer *mp_buf = (const GstMultiPlaneImageBuffer *) gst_data;
    const unsigned char **rows;
@@ -215,7 +220,7 @@ _evas_video_st12_multiplane(unsigned char *evas_data, const unsigned char *gst_d
 }
 
 static void
-_evas_video_st12(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h)
+_evas_video_st12(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h, unsigned int output_height __UNUSED__)
 {
    const SCMN_IMGB *imgb = (const SCMN_IMGB *) gst_data;
    const unsigned char **rows;
@@ -241,12 +246,13 @@ static const struct {
    guint32 fourcc;
    Evas_Colorspace eformat;
    Evas_Video_Convert_Cb func;
+   Eina_Bool force_height;
 } colorspace_fourcc_convertion[] = {
-  { GST_MAKE_FOURCC('I', '4', '2', '0'), EVAS_COLORSPACE_YCBCR422P601_PL, _evas_video_i420 },
-  { GST_MAKE_FOURCC('Y', 'V', '1', '2'), EVAS_COLORSPACE_YCBCR422P601_PL, _evas_video_yv12 },
-  { GST_MAKE_FOURCC('Y', 'U', 'Y', '2'), EVAS_COLORSPACE_YCBCR422601_PL, _evas_video_yuy2 },
-  { GST_MAKE_FOURCC('N', 'V', '1', '2'), EVAS_COLORSPACE_YCBCR420NV12601_PL, _evas_video_nv12 },
-  { GST_MAKE_FOURCC('T', 'M', '1', '2'), EVAS_COLORSPACE_YCBCR420TM12601_PL, _evas_video_mt12 }
+  { GST_MAKE_FOURCC('I', '4', '2', '0'), EVAS_COLORSPACE_YCBCR422P601_PL, _evas_video_i420, EINA_TRUE },
+  { GST_MAKE_FOURCC('Y', 'V', '1', '2'), EVAS_COLORSPACE_YCBCR422P601_PL, _evas_video_yv12, EINA_TRUE },
+  { GST_MAKE_FOURCC('Y', 'U', 'Y', '2'), EVAS_COLORSPACE_YCBCR422601_PL, _evas_video_yuy2, EINA_FALSE },
+  { GST_MAKE_FOURCC('N', 'V', '1', '2'), EVAS_COLORSPACE_YCBCR420NV12601_PL, _evas_video_nv12, EINA_TRUE },
+  { GST_MAKE_FOURCC('T', 'M', '1', '2'), EVAS_COLORSPACE_YCBCR420TM12601_PL, _evas_video_mt12, EINA_TRUE }
 };
 
 static const struct {
@@ -290,7 +296,6 @@ evas_video_sink_init(EvasVideoSink* sink, EvasVideoSinkClass* klass __UNUSED__)
    priv->unlocked = EINA_FALSE;
 }
 
-
 /**** Object methods ****/
 static void
 _cleanup_priv(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
@@ -418,15 +423,21 @@ gboolean evas_video_sink_set_caps(GstBaseSink *bsink, GstCaps *caps)
 
    structure = gst_caps_get_structure(caps, 0);
 
-   if (gst_structure_get_int(structure, "width", &priv->width)
-       && gst_structure_get_int(structure, "height", &priv->height)
+   if (gst_structure_get_int(structure, "width", (int*) &priv->width)
+       && gst_structure_get_int(structure, "height", (int*) &priv->height)
        && gst_structure_get_fourcc(structure, "format", &fourcc))
      {
+        priv->source_height = priv->height;
+
         for (i = 0; i < sizeof (colorspace_fourcc_convertion) / sizeof (colorspace_fourcc_convertion[0]); ++i)
           if (fourcc == colorspace_fourcc_convertion[i].fourcc)
             {
                priv->eformat = colorspace_fourcc_convertion[i].eformat;
                priv->func = colorspace_fourcc_convertion[i].func;
+               if (colorspace_fourcc_convertion[i].force_height)
+                 {
+                    priv->height = (priv->height >> 1) << 1;
+                 }
                return TRUE;
             }
 
@@ -440,12 +451,14 @@ gboolean evas_video_sink_set_caps(GstBaseSink *bsink, GstCaps *caps)
      }
 
    INF("fallback code !");
-   if (!gst_video_format_parse_caps(caps, &format, &priv->width, &priv->height))
+   if (!gst_video_format_parse_caps(caps, &format, (int*) &priv->width, (int*) &priv->height))
      {
         ERR("Unable to parse caps.");
         return FALSE;
      }
 
+   priv->source_height = priv->height;
+
    for (i = 0; i < sizeof (colorspace_format_convertion) / sizeof (colorspace_format_convertion[0]); ++i)
      if (format == colorspace_format_convertion[i].format)
        {
@@ -689,7 +702,7 @@ evas_video_sink_samsung_main_render(void *data)
    evas_data = evas_object_image_data_get(priv->o, 1);
 
    if (priv->func)
-     priv->func(evas_data, gst_data, stride, elevation);
+     priv->func(evas_data, gst_data, stride, elevation, elevation);
    else
      WRN("No way to decode %x colorspace !", priv->eformat);
 
@@ -753,7 +766,7 @@ evas_video_sink_main_render(void *data)
 
    _emotion_gstreamer_video_pipeline_parse(ev, EINA_TRUE);
 
-   INF("sink main render [%i, %i]", priv->width, priv->height);
+   INF("sink main render [%i, %i] (source height: %i)", priv->width, priv->height, priv->source_height);
 
    evas_object_image_alpha_set(priv->o, 0);
    evas_object_image_colorspace_set(priv->o, priv->eformat);
@@ -762,7 +775,7 @@ evas_video_sink_main_render(void *data)
    evas_data = evas_object_image_data_get(priv->o, 1);
 
    if (priv->func)
-     priv->func(evas_data, GST_BUFFER_DATA(buffer), priv->width, priv->height);
+     priv->func(evas_data, GST_BUFFER_DATA(buffer), priv->width, priv->source_height, priv->height);
    else
      WRN("No way to decode %x colorspace !", priv->eformat);
 
@@ -979,6 +992,8 @@ gstreamer_video_sink_new(Emotion_Gstreamer_Video *ev,
    g_object_set(G_OBJECT(sink), "evas-object", obj, NULL);
    g_object_set(G_OBJECT(sink), "ev", ev, NULL);
 
+   evas_object_image_pixels_get_callback_set(obj, NULL, NULL);
+
    g_object_get(G_OBJECT(playbin), "flags", &flags, NULL);
    g_object_set(G_OBJECT(playbin), "flags", flags | GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_DOWNLOAD | GST_PLAY_FLAG_BUFFERING, NULL);
    g_object_set(G_OBJECT(playbin), "video-sink", sink, NULL);