Google Summer of Code Final Report @Pitivi~Cut Mode.
Let's quickly go over the project :)
Pitivi ~Cut Mode
The Idea for this project is to have two timelines to ease certain types of tasks and increase productivity. This will essentially bring in a non-zoomable Timeline which will serve to ease the task of trimming, cutting, rearranging clips on the timeline in sync with the other timeline.
You can also watch the GUADEC Intern Lightening talks 2021, I talk about my project "Cut-Mode" with the other contributors and communty members.
Benefits?
Mostly, when we have a movie of a longer duration, we want to use the Zoom feature to see the whole timeline and scroll in-out to perform edits and rearrange clips. It consumes a lot of time which may be used productively somewhere, so to reduce user actions we have a zoom fitted timeline with small height layers so that all the layers and tracks are always visible. Now you only think about Zoom when you want to perform some precise edits, others on the Zoom fitted timeline ;).
From now, we will call the ZoomFitted timeline a Mini Timeline and the other simply a Timeline.
Longer duration timeline?
You can easily keep track having the scaled, reduced size elements on the Mini Timeline.
Further, it scales as you add elements at the end (Timeline Duration Increases) vice-versa, the whole timeline fits in the Mini Timeline view.
Many layers to work with?
Pitivi allows you to unlock all the views to a separate window, so If you have more layers, you may undock the views to separate screens and expand the Mini Timeline to make all the layers visible at the same time.
Let's dive deep!
Consider a case where we want to edit a portion of a timeline, for
precise edits we have to zoom in at the required position, do the edits,
zoom out, move to the next position, and so on for subsequent edits.
This eats up a lot of precious time. The new Mini timeline allows the
user to see the zoomed view as well as keep track of position in the
Mini timeline at the same time. Now you can move anywhere in the
timeline with a single click, preserving the zoomed view in Playhead Locked
mode, can be enabled via keys `Alt+P`.
It scrolls the Timeline horizontally
such that Playhead is centered concerning the Timeline.
Mini Timeline also allows you to rearrange clips so, where you have a short clip of about a few seconds and you wish to relocate it, say from start to the end of the timeline, you would select a clip, zoom out the timeline and drag it to end, zoom in to come to the same state. Another way is to start dragging and use the over scroll mechanism and wait for your desired position. Neither of them is ideal. The new Mini timeline allows us to quickly locate clips and drag them at any position since the entire duration is always in view.
What else?
You can do all the stuff on Mini Timeline that you do on the conventional Timeline. For example, you can drag clips directly on the Mini Timeline, select overlapped clips to apply transitions, drag effects directly over the mini timeline elements, etc.
Drag on the Mini Timeline.
Apply transitions & Drop effects.
Finally, when you are done, you can easily hide it by hitting keys `Alt+C`
.Implementation
I present you a high-level overview of how everything is structured.
The Layer class was refactored and subclassed into two implementations, namely, Full Layer and Mini Layer.
Similarly, the Clip class was refactored and subclassed into Full Clip and Mini Clip.
Similarly, for other related classes as well.
So, now, the Timeline architecture changes to
Code Snippets
1. As the Mini Timeline does not change with zoom-level (unlike Timeline) and always
remains
zoom-fitted, the Mini versions of classes do not subclass
Zoomable
, instead,
they use the
best ratio to transform positions whenever changed.
Below is the method for the calculation of the best ratio to fit the Timeline into the view.
def calc_best_zoom_ratio(self, mini=True):
"""Returns the zoom ratio so that the entire timeline is in (mini)view."""
duration = 0 if not self.ges_timeline else self.ges_timeline.get_duration()
if not duration or (mini and not self.mini_layout_container.get_visible()):
# Maximum available width, the parent is TimelineContainer
return self.get_parent().get_allocated_width()
# Add Gst.SECOND - 1 to the timeline duration to make sure the
# last second of the timeline will be in view.
timeline_duration = duration + Gst.SECOND - 1
timeline_duration_s = int(timeline_duration / Gst.SECOND)
self.debug("Adjusting zoom for a timeline duration of %s secs",
timeline_duration_s)
layout = self.mini_layout if mini else self.layout
zoom_ratio = layout.get_allocation().width / timeline_duration_s
return zoom_ratio
2. The Clips/Elements on the Mini Timeline are just simple representations without the thumbnails, we use color-filled rectangles (the color is decided based on the type of clip) to represent them.
class MiniPreview (Gtk.Layout):
"""Mini Clip previewer to draw color filled mini clips."""
def __init__(self, color):
Gtk.Layout.__init__(self)
self.get_style_context().add_class("MiniPreviewer")
self.color = color
self.props.height_request = MINI_LAYER_HEIGHT
def do_draw(self, context):
rect = Gdk.cairo_get_clip_rectangle(context)[1]
context.set_source_rgb(*self.color)
context.rectangle(0, 0, rect.width, rect.height)
context.fill()
All the Code and the changes are available on MR !397
Implementing the Mini Timeline became easy with the feedback from mentors and the clean and extensible codebase.
That's it for now. I will be adding more things here as they come.
Have a great day!
Will update you soon.
Thanks!