[pitivi] assets: Take into account media files rotation information



commit 43bc581efaae224bb3de8f814df57a5d02134bbb
Author: Thibault Saunier <tsaunier igalia com>
Date:   Fri Aug 9 10:59:06 2019 -0400

    assets: Take into account media files rotation information
    
    And make sure that rotation is applied to proxies.
    Remove `ThumbnailBin` as we are not using it at all.
    
    Fixes https://gitlab.gnome.org/GNOME/pitivi/issues/2317

 pitivi/check.py                  | 21 +++-----------
 pitivi/dialogs/clipmediaprops.py |  8 +++---
 pitivi/editorperspective.py      |  4 +--
 pitivi/mediafilespreviewer.py    |  4 +--
 pitivi/project.py                |  4 +--
 pitivi/timeline/elements.py      |  8 +++---
 pitivi/timeline/previewers.py    | 32 ++++++---------------
 pitivi/utils/misc.py             | 62 ++++++++++++++++++++++++++++++++++++++++
 pitivi/utils/ui.py               |  4 +--
 9 files changed, 91 insertions(+), 56 deletions(-)
---
diff --git a/pitivi/check.py b/pitivi/check.py
index 9765e480..f45e2471 100644
--- a/pitivi/check.py
+++ b/pitivi/check.py
@@ -341,22 +341,6 @@ def require_version(modulename, version):
         exit(1)
 
 
-def get_square_width(video_info):
-    """Applies the pixel aspect ratio to the width of the video info.
-
-    Args:
-        video_info (GstPbutils.DiscovererVideoInfo): The video info.
-
-    Returns:
-        int: The width calculated exactly as GStreamer does.
-    """
-    width = video_info.get_width()
-    par_num = video_info.get_par_num()
-    par_denom = video_info.get_par_denom()
-    # We observed GStreamer does a simple int(), so we leave it like this.
-    return int(width * par_num / par_denom)
-
-
 def initialize_modules():
     """Initializes the modules.
 
@@ -393,10 +377,13 @@ def initialize_modules():
 
     require_version("GstPbutils", GST_API_VERSION)
     from gi.repository import GstPbutils
+    from pitivi.utils.misc import video_info_get_natural_height, video_info_get_natural_width, 
video_info_get_rotation
 
     # Monky patch a helper method for retrieving the size of a video
     # when using square pixels.
-    GstPbutils.DiscovererVideoInfo.get_square_width = get_square_width
+    GstPbutils.DiscovererVideoInfo.get_natural_width = video_info_get_natural_width
+    GstPbutils.DiscovererVideoInfo.get_natural_height = video_info_get_natural_height
+    GstPbutils.DiscovererVideoInfo.get_rotation = video_info_get_rotation
 
     if not os.environ.get("GES_DISCOVERY_TIMEOUT"):
         os.environ["GES_DISCOVERY_TIMEOUT"] = "5"
diff --git a/pitivi/dialogs/clipmediaprops.py b/pitivi/dialogs/clipmediaprops.py
index d929338f..da8fb1f9 100644
--- a/pitivi/dialogs/clipmediaprops.py
+++ b/pitivi/dialogs/clipmediaprops.py
@@ -82,8 +82,8 @@ class ClipMediaPropsDialog(object):
             break
 
         for stream in self.video_streams:
-            self.size_width.set_text(str(stream.get_square_width()))
-            self.size_height.set_text(str(stream.get_height()))
+            self.size_width.set_text(str(stream.get_natural_width()))
+            self.size_height.set_text(str(stream.get_natural_height()))
             self.is_image = stream.is_image()
             if not self.is_image:
                 num = stream.get_framerate_num()
@@ -138,8 +138,8 @@ class ClipMediaPropsDialog(object):
             # This also handles the case where the video is a still image
             video = self.video_streams[0]
             if self.size_checkbutton.get_active():
-                project.videowidth = video.get_square_width()
-                project.videoheight = video.get_height()
+                project.videowidth = video.get_natural_width()
+                project.videoheight = video.get_natural_height()
             if self.framerate_checkbutton.get_active() and not self.is_image:
                 project.videorate = Gst.Fraction(video.get_framerate_num(),
                                                  video.get_framerate_denom())
diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py
index 3a630bb5..0ff72c30 100644
--- a/pitivi/editorperspective.py
+++ b/pitivi/editorperspective.py
@@ -840,8 +840,8 @@ class PreviewAssetWindow(Gtk.Window):
         # For videos and images, automatically resize the window
         # Try to keep it 1:1 if it can fit within 85% of the parent window
         video = video_streams[0]
-        img_width = video.get_square_width()
-        img_height = video.get_height()
+        img_width = video.get_natural_width()
+        img_height = video.get_natural_height()
         mainwindow_width, mainwindow_height = self.app.gui.get_size()
         max_width = 0.85 * mainwindow_width
         max_height = 0.85 * mainwindow_height
diff --git a/pitivi/mediafilespreviewer.py b/pitivi/mediafilespreviewer.py
index da463860..4218540e 100644
--- a/pitivi/mediafilespreviewer.py
+++ b/pitivi/mediafilespreviewer.py
@@ -256,8 +256,8 @@ class PreviewWidget(Gtk.Grid, Loggable):
                 self.player.uri = self.current_selected_uri
                 self.player.setState(Gst.State.PAUSED)
                 self.pos_adj.props.upper = duration
-                video_width = video.get_square_width()
-                video_height = video.get_height()
+                video_width = video.get_natural_width()
+                video_height = video.get_natural_height()
                 w, h = self.__get_best_size(video_width, video_height)
                 self.preview_video.set_size_request(w, h)
                 self.preview_video.props.ratio = video_width / video_height
diff --git a/pitivi/project.py b/pitivi/project.py
index 6cceefd7..e6b7993f 100644
--- a/pitivi/project.py
+++ b/pitivi/project.py
@@ -1884,8 +1884,8 @@ class Project(Loggable, GES.Project):
         if video_streams and self._has_default_video_settings:
             video = video_streams[0]
             if not video.is_image():
-                self.videowidth = video.get_square_width()
-                self.videoheight = video.get_height()
+                self.videowidth = video.get_natural_width()
+                self.videoheight = video.get_natural_height()
                 if video.get_framerate_num() > 0:
                     # The asset has a non-variable framerate.
                     self.videorate = Gst.Fraction(video.get_framerate_num(),
diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py
index 073f63eb..0b5de8fd 100644
--- a/pitivi/timeline/elements.py
+++ b/pitivi/timeline/elements.py
@@ -898,8 +898,8 @@ class VideoSource(TimelineElement):
         video_source = self._ges_elem
         sinfo = video_source.get_asset().get_stream_info()
 
-        asset_width = sinfo.get_square_width()
-        asset_height = sinfo.get_height()
+        asset_width = sinfo.get_natural_width()
+        asset_height = sinfo.get_natural_height()
         parent = video_source.get_parent()
         if parent and not self.__videoflip:
             for track_element in parent.find_track_elements(
@@ -918,8 +918,8 @@ class VideoSource(TimelineElement):
             res, method = self.__videoflip.get_child_property("method")
             assert res
             if "clockwise" in method.value_nick and self.__videoflip.props.active:
-                asset_width = sinfo.get_height()
-                asset_height = sinfo.get_square_width()
+                asset_width = sinfo.get_natural_height()
+                asset_height = sinfo.get_natural_width()
 
         # Find the biggest size of the video inside the
         # final view (project size) keeping the aspect ratio
diff --git a/pitivi/timeline/previewers.py b/pitivi/timeline/previewers.py
index 1b87069c..56c21425 100644
--- a/pitivi/timeline/previewers.py
+++ b/pitivi/timeline/previewers.py
@@ -94,7 +94,7 @@ class PreviewerBin(Gst.Bin, Loggable):
         """Finalizes the previewer, saving data to the disk if needed."""
 
 
-class ThumbnailBin(PreviewerBin):
+class TeedThumbnailBin(PreviewerBin):
     """Bin to generate and save thumbnails to an SQLite database."""
 
     __gproperties__ = {
@@ -105,12 +105,13 @@ class ThumbnailBin(PreviewerBin):
                 GObject.ParamFlags.READWRITE),
     }
 
-    def __init__(self, bin_desc="videoconvert ! videorate ! "
-                 "videoscale method=lanczos ! "
-                 "capsfilter caps=video/x-raw,format=(string)RGBA,"
-                 "height=(int)%d,pixel-aspect-ratio=(fraction)1/1,"
-                 "framerate=2/1 ! gdkpixbufsink name=gdkpixbufsink " %
-                 THUMB_HEIGHT):
+    def __init__(self, bin_desc="videoconvert ! videoflip method=automatic ! tee name=t ! queue  "
+                 "max-size-buffers=0 max-size-bytes=0 max-size-time=0  ! "
+                 "videoconvert ! videorate ! videoscale method=lanczos ! "
+                 "capsfilter caps=video/x-raw,format=(string)RGBA,height=(int)%d,"
+                 "pixel-aspect-ratio=(fraction)1/1,"
+                 "framerate=2/1 ! gdkpixbufsink name=gdkpixbufsink "
+                 "t. ! queue " % THUMB_HEIGHT):
         PreviewerBin.__init__(self, bin_desc)
 
         self.uri = None
@@ -156,20 +157,6 @@ class ThumbnailBin(PreviewerBin):
             raise AttributeError('unknown property %s' % prop.name)
 
 
-class TeedThumbnailBin(ThumbnailBin):
-    """Bin to generate and save thumbnails to an SQLite database."""
-
-    def __init__(self):
-        ThumbnailBin.__init__(
-            self, bin_desc="tee name=t ! queue  "
-            "max-size-buffers=0 max-size-bytes=0 max-size-time=0  ! "
-            "videoconvert ! videorate ! videoscale method=lanczos ! "
-            "capsfilter caps=video/x-raw,format=(string)RGBA,height=(int)%d,"
-            "pixel-aspect-ratio=(fraction)1/1,"
-            "framerate=2/1 ! gdkpixbufsink name=gdkpixbufsink "
-            "t. ! queue " % THUMB_HEIGHT)
-
-
 # pylint: disable=too-many-instance-attributes
 class WaveformPreviewer(PreviewerBin):
     """Bin to generate and save waveforms as a .npy file."""
@@ -290,8 +277,6 @@ class WaveformPreviewer(PreviewerBin):
 
 Gst.Element.register(None, "waveformbin", Gst.Rank.NONE,
                      WaveformPreviewer)
-Gst.Element.register(None, "thumbnailbin", Gst.Rank.NONE,
-                     ThumbnailBin)
 Gst.Element.register(None, "teedthumbnailbin", Gst.Rank.NONE,
                      TeedThumbnailBin)
 
@@ -620,6 +605,7 @@ class AssetPreviewer(Previewer, Loggable):
             "uridecodebin uri={uri} name=decode ! "
             "videoconvert ! "
             "videorate ! "
+            "videoflip method=automatic ! "
             "videoscale method=lanczos ! "
             "capsfilter caps=video/x-raw,format=(string)RGBA,height=(int){height},"
             "pixel-aspect-ratio=(fraction)1/1,framerate={thumbs_per_second}/1 ! "
diff --git a/pitivi/utils/misc.py b/pitivi/utils/misc.py
index dc59bdc7..1368e1de 100644
--- a/pitivi/utils/misc.py
+++ b/pitivi/utils/misc.py
@@ -409,3 +409,65 @@ def fixate_caps_with_default_values(template, restrictions, default_values,
     res = res.fixate()
     log.debug("utils", "Fixated %s", res)
     return res
+
+
+# GstDiscovererInfo helpers
+def _get_square_width(video_info):
+    width = video_info.get_width()
+    par_num = video_info.get_par_num()
+    par_denom = video_info.get_par_denom()
+    # We observed GStreamer does a simple int(), so we leave it like this.
+    return int(width * par_num / par_denom)
+
+
+def video_info_get_rotation(video_info):
+    tags = video_info.get_tags()
+    if not tags:
+        return 0
+
+    is_rotated, rotation_string = tags.get_string(Gst.TAG_IMAGE_ORIENTATION)
+    if is_rotated:
+        try:
+            return int(rotation_string.replace('rotate-', ''))
+        except ValueError as e:
+            log.error("utils", "Did not understand orientation: %s (%s)", rotation_string, e)
+            return 0
+
+    return 0
+
+
+def video_info_get_natural_width(video_info):
+    """Applies the pixel aspect ratio and rotation information
+       to the width of the video info.
+
+    Args:
+        video_info (GstPbutils.DiscovererVideoInfo): The video info.
+
+    Returns:
+        int: The width calculated exactly as GStreamer does.
+    """
+    rotation = video_info.get_rotation()
+    if rotation in [90, 270]:
+        width = video_info.get_height()
+        par_num = video_info.get_par_num()
+        par_denom = video_info.get_par_denom()
+        # We observed GStreamer does a simple int(), so we leave it like this.
+        return int(width * par_num / par_denom)
+
+    return _get_square_width(video_info)
+
+
+def video_info_get_natural_height(video_info):
+    """Applies the rotation information to the height of the video.
+
+    Args:
+        video_info (GstPbutils.DiscovererVideoInfo): The video info.
+
+    Returns:
+        int: The height calculated exactly as GStreamer does.
+    """
+    rotation = video_info.get_rotation()
+    if rotation in [90, 270]:
+        return _get_square_width(video_info)
+
+    return video_info.get_height()
\ No newline at end of file
diff --git a/pitivi/utils/ui.py b/pitivi/utils/ui.py
index fe447b4f..fea22797 100644
--- a/pitivi/utils/ui.py
+++ b/pitivi/utils/ui.py
@@ -505,8 +505,8 @@ def beautify_stream(stream):
 
     elif type(stream) is DiscovererVideoInfo:
         par = stream.get_par_num() / stream.get_par_denom()
-        width = stream.get_width()
-        height = stream.get_height()
+        width = stream.get_natural_width()
+        height = stream.get_natural_height()
         if not stream.is_image():
             fps = format_framerate_value(stream)
             templ = _("<b>Video:</b> %d×%d <i>pixels</i> at %s <i>fps</i>")


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]