[vlc-devel] [PATCH 3/6] Support for displaying rotated movies.

Matthias Keiser matthias at tristan-inc.com
Thu Feb 27 23:34:52 CET 2014


---
 src/video_output/display.c | 172 ++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 155 insertions(+), 17 deletions(-)

diff --git a/src/video_output/display.c b/src/video_output/display.c
index 906bca0..83ed21d 100644
--- a/src/video_output/display.c
+++ b/src/video_output/display.c
@@ -197,6 +197,13 @@ void vout_display_GetDefaultDisplaySize(unsigned *width, unsigned *height,
 
     *width  = *width  * cfg->zoom.num / cfg->zoom.den;
     *height = *height * cfg->zoom.num / cfg->zoom.den;
+
+    if (ORIENT_IS_SWAP(source->orientation)) {
+
+        unsigned store = *width;
+        *width = *height;
+        *height = store;
+    }
 }
 
 /* */
@@ -214,6 +221,10 @@ void vout_display_PlacePicture(vout_display_place_t *place,
     unsigned display_width;
     unsigned display_height;
 
+    video_format_t sourceRot;
+    video_format_t *p_sourceRot = &sourceRot;
+    video_format_ApplyRotation(source, p_sourceRot);
+
     if (cfg->is_display_filled) {
         display_width  = cfg->display.width;
         display_height = cfg->display.height;
@@ -223,7 +234,7 @@ void vout_display_PlacePicture(vout_display_place_t *place,
         cfg_tmp.display.width  = 0;
         cfg_tmp.display.height = 0;
         vout_display_GetDefaultDisplaySize(&display_width, &display_height,
-                                           source, &cfg_tmp);
+                                           p_sourceRot, &cfg_tmp);
 
         if (do_clipping) {
             display_width  = __MIN(display_width,  cfg->display.width);
@@ -231,12 +242,12 @@ void vout_display_PlacePicture(vout_display_place_t *place,
         }
     }
 
-    const unsigned width  = source->i_visible_width;
-    const unsigned height = source->i_visible_height;
+    const unsigned width  = p_sourceRot->i_visible_width;
+    const unsigned height = p_sourceRot->i_visible_height;
     /* Compute the height if we use the width to fill up display_width */
-    const int64_t scaled_height = (int64_t)height * display_width  * cfg->display.sar.num * source->i_sar_den / width  / source->i_sar_num / cfg->display.sar.den;
+    const int64_t scaled_height = (int64_t)height * display_width  * cfg->display.sar.num * p_sourceRot->i_sar_den / width  / p_sourceRot->i_sar_num / cfg->display.sar.den;
     /* And the same but switching width/height */
-    const int64_t scaled_width  = (int64_t)width  * display_height * cfg->display.sar.den * source->i_sar_num / height / source->i_sar_den / cfg->display.sar.num;
+    const int64_t scaled_width  = (int64_t)width  * display_height * cfg->display.sar.den * p_sourceRot->i_sar_num / height / p_sourceRot->i_sar_den / cfg->display.sar.num;
 
     /* We keep the solution that avoid filling outside the display */
     if (scaled_width <= cfg->display.width) {
@@ -385,6 +396,88 @@ static void VoutDisplayCreateRender(vout_display_t *vd)
     v_dst.i_sar_num = 0;
     v_dst.i_sar_den = 0;
 
+    es_format_t src;
+    es_format_InitFromVideo(&src, &v_src);
+
+    filter_t *filter;
+
+    //We only handle orientaion conversion to ORIENT_NORMAL.
+    if (v_src.orientation != v_dst.orientation && v_dst.orientation == ORIENT_NORMAL) {
+
+        const char *type;
+
+        switch (vd->source.orientation) {
+
+            case ORIENT_ROTATED_90:
+                type = "90";
+                break;
+            case ORIENT_ROTATED_180:
+                type = "180";
+                break;
+            case ORIENT_ROTATED_270:
+                type = "270";
+                break;
+            case ORIENT_HFLIPPED:
+                type = "hflip";
+                break;
+            case ORIENT_VFLIPPED:
+                type = "vflip";
+                break;
+            case ORIENT_TRANSPOSED:
+                type = "transpose";
+                break;
+            case ORIENT_ANTI_TRANSPOSED:
+                type = "antitranspose";
+                break;
+            default:
+                type = NULL;
+                break;
+        }
+
+        if (type) {
+
+            osys->filters = filter_chain_New(vd, "video filter2", true,
+                                             FilterAllocationInit,
+                                             FilterAllocationClean, vd);
+            assert(osys->filters); /* TODO critical */
+
+            config_chain_t *cfg;
+            char *name;
+            char config[100];
+            snprintf(config, 100, "transform{type=%s}", type);
+            char *next;
+            VLC_UNUSED(next);
+            next = config_ChainCreate(&name, &cfg, config);
+
+            //Don't make the transform filter trip over chroma conversions.
+            video_format_t v_src_norm = src.video;
+            v_src_norm.orientation = ORIENT_NORMAL; //Transform filter fills in all other geometric values.
+            es_format_t src_norm;
+            es_format_InitFromVideo(&src_norm, &v_src_norm);
+            filter = filter_chain_AppendFilter(osys->filters, name, cfg, &src, &src_norm);
+
+            es_format_Clean(&src_norm);
+            es_format_Clean(&src);
+            config_ChainDestroy(cfg);
+
+            if (!filter) {
+                msg_Dbg(vd, "Failed to create picture orientation transform filter.");
+                filter_chain_Delete(osys->filters);
+                osys->filters = NULL;
+            }
+            else {
+                es_format_Copy(&src, filter_chain_GetFmtOut(osys->filters));
+                v_src = src.video;
+
+                //FIXME:
+                //The transform filter produces x/y offsets which seem to be off by 1.
+                //Instead of triggering the swscale filter because of this we simeply ignore it.
+                v_src.i_x_offset = v_dst.i_x_offset;
+                v_src.i_y_offset = v_dst.i_y_offset;
+            }
+        }
+    }
+
     video_format_t v_dst_cmp = v_dst;
     if ((v_src.i_chroma == VLC_CODEC_J420 && v_dst.i_chroma == VLC_CODEC_I420) ||
         (v_src.i_chroma == VLC_CODEC_J422 && v_dst.i_chroma == VLC_CODEC_I422) ||
@@ -393,34 +486,39 @@ static void VoutDisplayCreateRender(vout_display_t *vd)
         v_dst_cmp.i_chroma = v_src.i_chroma;
 
     const bool convert = memcmp(&v_src, &v_dst_cmp, sizeof(v_src)) != 0;
-    if (!convert)
+
+    if (!convert) {
+        es_format_Clean(&src);
         return;
+    }
 
     msg_Dbg(vd, "A filter to adapt decoder to display is needed");
 
-    osys->filters = filter_chain_New(vd, "video filter2", false,
-                                     FilterAllocationInit,
-                                     FilterAllocationClean, vd);
-    assert(osys->filters); /* TODO critical */
-
     /* */
-    es_format_t src;
-    es_format_InitFromVideo(&src, &v_src);
+    if (!osys->filters)
+        osys->filters = filter_chain_New(vd, "video filter2", true,
+                                         FilterAllocationInit,
+                                         FilterAllocationClean, vd);
 
-    /* */
-    es_format_t dst;
+    assert(osys->filters); /* TODO critical */
 
-    filter_t *filter;
     for (int i = 0; i < 1 + (v_dst_cmp.i_chroma != v_dst.i_chroma); i++) {
 
+        es_format_t dst;
+
         es_format_InitFromVideo(&dst, i == 0 ? &v_dst : &v_dst_cmp);
 
-        filter_chain_Reset(osys->filters, &src, &dst);
         filter = filter_chain_AppendFilter(osys->filters,
                                            NULL, NULL, &src, &dst);
+
+        es_format_Clean(&dst);
+
         if (filter)
             break;
     }
+
+    es_format_Clean(&src);
+
     if (!filter)
         msg_Err(vd, "Failed to adapt decoder format to display");
 }
@@ -520,6 +618,46 @@ static void VoutDisplayEventMouse(vout_display_t *vd, int event, va_list args)
         }
     }
 
+    //vout modules report the mouse position in display coordinates,
+    //but the receivers most likely expect non-transformed coordinates.
+    switch (vd->source.orientation) {
+
+        int store;
+
+        case ORIENT_ROTATED_90:
+            store = m.i_x;
+            m.i_x = m.i_y;
+            m.i_y = vd->source.i_visible_height - store;
+            break;
+        case ORIENT_ROTATED_180:
+            m.i_x = vd->source.i_visible_width - m.i_x;
+            m.i_y = vd->source.i_visible_height - m.i_y;
+            break;
+        case ORIENT_ROTATED_270:
+            store = m.i_x;
+            m.i_x = vd->source.i_visible_width - m.i_y;
+            m.i_y = store;
+            break;
+        case ORIENT_HFLIPPED:
+            m.i_x = vd->source.i_visible_width - m.i_x;
+            break;
+        case ORIENT_VFLIPPED:
+            m.i_y = vd->source.i_visible_height - m.i_y;
+            break;
+        case ORIENT_TRANSPOSED:
+            store = m.i_x;
+            m.i_x = m.i_y;
+            m.i_y = store;
+            break;
+        case ORIENT_ANTI_TRANSPOSED:
+            store = m.i_x;
+            m.i_x = vd->source.i_visible_width - m.i_y;
+            m.i_y = vd->source.i_visible_height - store;
+            break;
+        default:
+            break;
+    }
+
     /* */
     osys->mouse.state = m;
 
-- 
1.8.3.4 (Apple Git-47)


More information about the vlc-devel mailing list