August 12, 2018

[GSoC’18] Pitivi’s UI Polishing – Final Report

As part of Google Summer of Code 2018, I worked on the project Pitivi: UI Polishing. This is my final report to showcase the work that I have done during the program.

Work Done

I worked on the issue #1302 to integrate Pitivi’s welcome dialog box into its main window and display projects in a more informative, discoverable, and user friendly layout. This is how Pitivi greeted users before I started working on the issue:

Screenshot from 2018-08-11 13-59-26

My first task was to remove the welcome dialog from Pitivi and integrate a simple greeter perspective that displays the name of recent projects in a listbox with all the relevant buttons placed in the headerbar. This was a big task and took nearly 5 weeks to complete. The main challenge of this task was to understand the big codebase of main window and refactor it. The refactoration lead to the following architectural changes:

pitivi_architecture (2)

In the the new architecture, I have developed a perspective based system which allows easily adding more perspectives to Pitivi. Every class has single responsibility in the new architecture as opposed to everything being managed by main window in the previous architecture.

!33 is the merge request for this change and 330d62a4 is the committed code. This is how the greeter perspective looked like after this change:

pitivi_greeter_ad

I also did some code clean up to conclude my greeter perspective’s integration:

  • Remove unused “ignore_saved_changes” param from newBlankProject() function in project class – b2f19ea3
  • Make newly added shortcuts available when users upgrade Pitivi – 8b3a691a
  • Move dialog for locating missing asset to dialogs package – c08007a8
  • Remove directly called callback methods – 7a8d23ba
  • Remove project title functionality because we only care about project file name – 4ea9d89f

My next task was to display meta info regarding a project such as its directory and last updated timestamp in the greeter perspective. !43 is the merge request for this change and ff672460 is the committed code. This is how the greeter perspective looked like after this change:

aaa

My next task was to show a welcome message on greeter perspective when there are no recent projects. !44 is the merge request for this change and d9c8f6c8 is the committed code. This is how the empty (no recent projects) greeter screen looks like:

empty_greeter

Finally, I added the following to greeter perspective:

  1. “Search” feature for easy browsing of recent projects, and
  2. “Selection” feature for removing project(s) from recent projects list.

!46 is the merge request for search feature and c72ebce7 is the committed code. !48 is the merge request for selection feature and 809d7599 is the committed code.

searchSearch feature
removeSelection feature

After resolving issue #1302, I worked on the issue #1462 to integrate project thumbnails in greeter perspective. The main idea behind these thumbnails is to give the user a hint what a certain project is about. The main challange of this task was to come up with a simple and robust algorithm for thumbnail generation (link). More details about our project thumbnail generation approach can be found here.

!51 is the merge request for this change and a6511c1e is the committed code.

I also made the following optimizations to project thumbnails (!54):

  • Use assets thumbnails if no thumbnails are present in XDG cache – cb47d926
  • While opening greeter perspective, defer loading of project thumbnails until the main thread is idle – 37c973e1

So this is how the greeter perspective looks finally after all these changes:

Screenshot from 2018-07-21 00-29-40

After wrapping integration of project thumbnails, I added the following features to greeter perspective:

  • Right click on a recent project to select it and start selection mode – !67 is the merge request and 6db06472 is the committed code
  • Drag & drop a project file from Nautilus onto greeter to open it – !68 is the merge request and 817d885a is the committed  code

Next, I worked on the issue #1816 to allow video viewer resizing.

The first task was to integrate a marker on the bottom left corner of the viewer container to allow for easy resizing of the viewer. !60 is the merge request for this change and 25609f3a is the committed code.

resize1Viewer resizing using corner marker

Work in Progress…

Two more tasks are left under issue #1816:

  1. Displaying resize status (in %) over slightly dimmed video, and
  2. Snapping of viewer to 100% and 50% if the current resize status is between [100%, 100% + Δ ] and [50%, 50% + Δ ] respectively.

I have submitted a merge request !70 for review for both these tasks.

resize2Displaying resize status over dimmed video

Final Words

I would like to thank my mentor Alexandru Băluț (aleb) for his help and guidance throughout this project. I would also like to thank all other members of GNOME community who helped me along the way. This turned out to be an amazing summer for me with lots of learning and fun. I will continue to contribute to Pitivi as I feel like this is just the beginning of many exciting things yet to be done in Pitivi to make it the best video editing application.

Until next time 🙂

July 31, 2018

WebKitGTK and WPE gain WebRTC support back!

WebRTC is a w3c draft protocol that “enables rich, high-quality RTP applications to be developed for the browser, mobile platforms, and IoT devices, and allow them all to communicate via a common set of protocols”. The protocol is mainly used to provide video conferencing systems from within web browsers.

https://appr.tc running in WebKitGTKhttps://appr.tc running in WebKitGTK

A brief history

At the very beginning of the WebRTC protocol, before 2013, Google was still using WebKit in chrome and they started to implement support using LibWebRTC but when they started the blink fork the implementation stopped in WebKit.

Around 2015/2016 Ericsson and Igalia (later sponsored by Metrological) implemented WebRTC support into WebKit, but instead of using LibWebRTC from google, OpenWebRTC was used. This had the advantage of being implemented on top of the GStreamer framework which happens to be used for the Multimedia processing inside WebKitGTK and WebKitWPE. At that point in time, the standardization of the WebRTC protocol was still moving fast, mostly pushed by Google itself, and it was hard to be interoperable with the rest of the world. Despite of that, the WebKit/GTK/WPE WebRTC implementation started to be usable with website like appr.tc at the end of 2016.

Meanwhile, in late 2016, Apple decided to implement WebRTC support on top of google LibWebRTC in their ports of WebKit which led to WebRTC support in WebKit announcement in June 2017.

Later in 2017 the OpenWebRTC project lost momentum and as it was considered unmaintained, we, at Igalia, decided to use LibWebRTC for WebKitGTK and WebKitWPE too. At that point, the OpenWebRTC backend was completely removed.

GStreamer/LibWebRTC implementation

Given that Apple had implemented a LibWebRTC based backend in WebKit, and because this library is being used by the two main web browsers (Chrome and Firefox), we decided to reuse Apple’s work to implement support in our ports based on LibWebRTC at the end of 2017. A that point, the two main APIs required to allow video conferencing with WebRTC needed to be implemented:

  • MediaDevices.GetUserMedia and MediaStream: Allows to retrieve Audio and Video streams from the user Cameras and Microphones (potentially more than that but those are the main use cases we cared about).
  • RTCPeerConnection: Represents a WebRTC connection between the local computer and a remote peer.

As WeKit/GTK/WPE heavily relies on GStreamer for the multimedia processing, and given its flexibility, we made sure that our implementation of those APIs leverage the power of the framework and the existing integration of GStreamer in our WebKit ports.

Note that the whole implementation is reusing (after refactoring) big parts of the infrastructure introduced during the previously described history of WebRTC support in WebKit.

GetUserMedia/MediaStream

To implement that part of the API the following main components were developed:

  • RealtimeMediaSourceCenterLibWebRTC: Main entry point for our GStreamer based LibWebRTC backend.
  • GStreamerCaptureDeviceManager: A class to list and manage local Video/Audio devices using the GstDeviceMonitor API.
  • GStreamerCaptureDevice: Implementation of WebKit abstraction for capture devices, basically wrapping GstDevices.
  • GStreamerMediaStreamSource: A GStreamer Source element which wraps WebKit abstraction of MediaStreams to be used directly in a playbin3 pipeline (through a custom mediastream:// protocol). This implementation leverages latest GstStream APIs so it is already one foot into the future.

The main commit can be found here

RTCPeerConnection

Enabling the PeerConnection API meant bridging previously implemented APIs and the LibWebRTC backend developed by Apple:

  • RealtimeOutgoing/Video/Audio/SourceLibWebRTC: Passing local stream (basically from microphone or camera) to LibWebRTC to be sent to the peer.
  • RealtimeIncoming/Video/Audio/SourceLibWebRTC: Passing remote stream (from a remote peer) to the MediaStream object and in turn to the GStreamerMediaStreamSource element.

On top of that and to leverage GStreamer Memory management and negotiation capabilities we implemented encoders and decoder for LibWebRTC (namely GStreamerVideoEncoder and GStreamerVideoDecoders). This brings us a huge number of Hardware accelerated encoders and decoders implementations, especially on embedded devices, which is a big advantage in particular for WPE which is tuned for those platforms.

The main commit can be found here

WebKitWebRTC dataflow diagram

Conclusion

While we were able to make GStreamer and LibWebRTC work well together in that implementation, using the new GstWebRTC component (that is now in upstream GStreamer) as a WebRTC backend would be cleaner. Many pieces of the current implementation could be reused and it would allow us to have a simpler infrastructure and avoid having several RTP stack in the WebKitGTK and WebKitWPE ports.

Most of the required APIs and features have been implemented, but a few are still under development (namely MediaDevices.enumerateDevices, canvas captureStream and WebAudio and MediaStream bridging) meaning that many Web applications using WebRTC already work, but some don’t yet, we are working on those!

A big thanks to my employer Igalia and Metrological for sponsoring our work on that!

July 24, 2018

[GSoC 2018] Welcome Window Integration in Pitivi – Conclusion

In my last post (link), I talked about integrating “Search” and “Remove” feature in Pitivi’s welcome window. Search feature allowed for easy browsing of recent projects and remove feature allowed removing project(s) from recent projects list.

In this post, I want to introduce “Project Thumbnails”. I have successfully integrated project thumbnails in recent projects list. This is the last task under issue 1302.

The main idea behind thumbnails is to give the user a hint what a certain project is about. This can be seen as information in addition to project name and uri which helps to identify the desired project faster and more easily.

Screenshot from 2018-07-20 23-01-52Project thumbnails integrated in recent projects list

We display our project thumbnails in a dark grayish container of size 96×54 (16:9). We preserve the aspect ratio of our project thumbnails while displaying them in the container, for example, aspect ratio of thumbnail of project “demo3” in the above screenshot is 21:9 while projects “demo7” and “demo1” have 16:9 aspect ratio thumbnails. If a project has no thumbnail, such as an empty project, we show “video-x-generic” theme icon as project thumbnail, for example, project “demo4” in the above screenshot.

We create a thumbnail for a project if and only if:

  • the project doesn’t have a thumbnail, or
  • user imported/deleted asset(s) while working on the project.

Our project thumbnail generation approach is as follows:

  1. We go through all the assets in the project and fetch their thumbnails from the XDG cache.
  2. Out of all the fetched thumbnails, we pick the one with maximum file size as our project thumbnail (Why?).
  3. If we are not able to get any thumbnail from the XDG cache, we pick the preview thumbnail of the first asset that has a thumbnail cache** as our project thumbnail.

** This is the cache maintained by Pitivi for the assets imported in a project. This is different from XDG cache. XDG cache is a system wide cache for thumbnails.

So, finally after 10 weeks, I conclude the issue 1302. To give a brief idea of what I did in these 10 weeks, this is how welcome dialog in Pitivi looked 10 weeks back…

Pitivi's Current Welcome Dialog

And this is how it looks now…

Screenshot from 2018-07-21 00-29-40

I would also like to express my gratitude to my mentor Alexandru Băluț (aleb) for helping and guiding me throughout these 10 weeks.

Next, I will be working on the issue 1816. My aim is to complete it in the next 2 weeks.

I will keep posting my progress on this blog. Until next time.

Stay tuned 🙂

Writing a freesound plugin for Pitivi

I always say that my first geeky passion is computer programming. But that is a passion I developed about 8 years ago. Another geeky passion I have recently developed has been security analysis. Because of this reason I started a Youtube channel the previous year called “Inversor Moderno” (“Modern investor” in English). Besides the fact that I prefer to follow the fundamental analysis and to be more specific the “value investing” philosophy, I started the channel with the purpose of leaning and teaching more about investments and specifically about quantitative trading. However, it has been a long time since the last time I uploaded a video.

Inversor moderno intro

The intro of my videos was made using Blender and Pitivi. The bag of money was made in Blender and the sound of the Wall Street bell was added using Pitivi. All the rest of each video in my channel are made using Pitivi. I consider that the best ideas you may have come up when you really start to eat your own dog food. When I was animating the intro, I remembered that when I started trading, the platform I used notified me with a Wall Street bell sound when a position touched “take profit” or “stop loss”. So I wanted to add a sound like this one to my intro. Then I thought: “It would be nice if Pitivi had a sound library”.

Flashback: I remember I had an introductory course in the university in which students had as an assignment task to develop a video game. Nobody knew how to develop a video game, but the idea was also to research. By that time, I knew something about Blender and the BGE and I could convince to my friends to use Blender. We modeled the university in Blender and then put a human in there with Makehuman. But our game needed sounds. Searching for Creative Commons sounds, I found the Freesound database.

preview

Luckily, not only has an API to access their sound database, but it also has a [Python module](https://github.com/MTG/freesound-python). So I decided to write a plugin that allows to query for some sounds from Pitivi and importing them to the Pitivi Media Library. I made the first step the previous year, but I didn't continue it. This last week, I decided to continue this mini-project. The plugin is working now, but there are some things to complete and a lot more to review. However, you can see a preview here.

preview

I need suggestions about design. I am still not sure if I should use a GtkListBox or if a GtkTreeView would look better. Also I don’t know what message should be shown when no result is found after searching and also what message to show when the Freesound library window is open for the first time.

You can try this feature in my branch (yes, it needs to be rebased).

July 14, 2018

[GSoC 2018] Welcome Window Integration in Pitivi – Part 4

In my last post (link), I talked about:

  1. Changing the layout of recent projects items to display meta info regarding a project such as its directory and last updated timestamp, and
  2. Displaying greeter message when there are no recent projects.

In this post, I want to introduce the two new features that I have added to the new welcome window in Pitivi:

  1. “Search” feature for easy browsing of recent projects (box marked as “1” in the screenshot below), and
  2. “Remove” feature to allow removing project(s) from recent projects list (box marked as “2” in the screenshot below).

sear

“Search” feature…

Search feature is meant to allow users to easily browse throught recent projects list to quickly get to the project they want to work on. This feature can be pretty handy if there are lots of recent projects.

I have implemented it using Gtk.SearchEntry and it is focussed by default to allow users to quickly search for a project as soon as the welcome window appears.

Screenshot from 2018-07-14 23-53-19Recent projects found for search query “demo1”
Screenshot from 2018-07-14 23-55-01No recent project found for search query “demo12”

“Remove” feature…

Remove feature is meant to remove unwanted/unused project(s) from recent projects list. The removed project(s) are not deleted from the disk. One use case for this feature can be to unclutter the recent projects list after we have finished working on a project and we no longer need it.

Screenshot from 2018-07-15 00-06-45Remove project(s) screen
Screenshot from 2018-07-15 00-09-02Selected “demo4” project for removal
Screenshot from 2018-07-15 00-10-18“demo4” project removed from recent projects list

The next and the last task under “Welcome Window Integration in Pitivi” as per my GSoC project is to integrate project thumbnails in recent projects list. I am currently working on this task and hope to finish it by next week.

I will keep posting my progress on this blog. Until next time.

Stay tuned 🙂

July 12, 2018

[GSoC 2018] Welcome Window Integration in Pitivi – Part 3

In my last post (link), I talked about Pitivi finally getting a Welcome window. In this window, the layout of the recent projects list was pretty basic – we were only showing the name of the projects.

pitivi_greeter_adWelcome window – “Recent Projects” list is only showing name of projects

The next two tasks on my ToDo list were –

  1. Displaying meta info regarding a project, such as its directory and last updated timestamp, and
  2. Greeter message on Welcome window when there are no recent projects.

I have successfully completed these two tasks. The layout of recent projects list now shows project name, project uri, and project’s last updation timestamp.

greeter_newNew layout of recent projects list

Note: If the project is inside user’s home directory, we replace the home directory path with (tilde).  Also, the “Updated” info might not be accurate everytime as it is not displaying project’s last updation timestamp in very specific manner (like 30 mins ago, 2 days ago, etc.) but in a vague manner (like Just now, Yesterday, etc.). The idea is to present this info in a nice human readable format and not care much about the accuracy of the timestamp as it doesn’t matter too much for a video editing app. Also, there are other GNOME apps like Builder who display updation timestamp in exact same manner.

This is how the empty (no recent projects) greeter screen looks like –

empty_greeter

For now we have kept this screen very simple as it is more like a one time welcome screen and we don’t want to put a lot of effort into it as we have other important tasks at hand. Almost all the time users will be dealing with the screen displaying recent projects.

The next two tasks on my ToDo list are:

  1. Adding search functionality for easy browsing of projects.
  2. Allowing removing items from “Recent Projects” list.

I will keep posting my progress on this blog. Until next time.

Stay tuned 🙂

June 22, 2018

Behind the GESSourceClip rate

Initial Approach

GES has an effects infrastructure for adding and managing GStreamer elements. Since the rate property uses videorate and pitch elements to work, the idea was to use this existing infrastructure but to the hide the effects from the user as they are required only internally.

Step 1: Use effects

All media elements are truly set on a clip only when it is added to a layer, this involves the construction of GESAudioSource and/or GESVideoSource of the clip. An effect can be added only after these sources have been added to the clip. As a result, the rate property was configured to add pitch and/or videorate as effects only after the sources were added.

Step 2: Hide the effects

To hide the effects from the user - accommodate the hidden effects in GESClip by mimicing the behaviour of a normal effect and maintain a reference to the ‘hidden’ rate changing effects to not display them as top effects.

A GESClip is a subclass of GESContainer - which gives it the ability to hold the source track elements and the effects. Many operations in GES call the GES_CONTAINER_CHILDREN (clip) method when required to retrieve and make changes to the children of a clip - effects/sources contained in the clip. Since the rate changing effects were not truly hidden, they are contained in the clip and hence showed up as the container’s children.

Step 3: Start from scratch

Although the above approach of maintaining hidden effects works to hide them from the user, to hide and make GES sometimes ignore and sometimes utilise the effect API was not only difficult but required making a lot of ugly changes to many parts of GES. It became obvious that a rework of the way things worked was required when running tests on the branch resulted in most of the existing tests failing.

Current Implementation

Mathieu suggested that instead of using the effect API, we should dig a little deeper and add the videorate and pitch elements to the sources of the clip ourself. This genius and simple solution eliminated many of the problems faced in the initial approach.

pitch is simply added to the audiosrcbin- a GstBin of GESAudioSource, while videorate was already in place in a GESVideoSource to adjust frames, as a result, rate is now added as a child property of the audio and video source in GES. The parent GESSource handles creating, linking and managing the audiosrcbin and videosrcbin. Rate property added to GESSourceClip - base class for sources of a GESLayer, changes the rate child property of its sources to function.

The pitch element being from the gst-plugins-bad didn’t behave so well and required some fixes for bug 796603 by Matheiu and a followup fix for bug 796613 by myself after which all existing tests of GES passed! (hurray)

While pushing new tests, I realised that since we no longer rely on the effect API, the rate property had to be serialised and deserialised by adding to the xges xml formatter.

Same functionality with ges-launch holds, simply adding rate to command changes speed of a clip.

ges-launch-1.0 +clip ~/path/to/video.mp4 inpoint=10 duration=20 rate=2.0

The above command plays the 20 seconds of the input video from the 10 second mark at a rate of 2.0, that is, for 10 seconds.

The project can saved and loaded back-in using the following commands,

ges-launch-1.0 +clip ~/path/to/video.mp4 inpoint=10 duration=20 rate=2.0 --save project.xges

ges-launch-1.0 --load project.xges

The primary focus of work has been on the getting the GES implementation right. I’m yet to try out a few suggestions I got from GNOME design on the Pitivi UI side of things.

This has been the story so far. You can find my work here and follow issue 2202 for updates. Until next time.

June 21, 2018

[GSoC 2018] Welcome Window Integration in Pitivi – Part 2

In my last post (link), I gave an overview of Welcome window integration in Pitivi. I started working on this task from the first coding day of Google Summer of Code 2018, i.e. May 14, 2018 and after one amazing month of coding it finally got merged (commit) on June 19, 2018. Apparently it was a large change consisting of 702 additions and 329 deletions (link) involving 75 code-review discussions and 29 versions. A special thanks to my mentor aleb for giving constructive reviews on my code.

So, finally Pitivi has a Welcome Window!!! and this is how it looks like:

pitivi_greeter_alWelcome window – Adwaita light theme
pitivi_greeter_adWelcome window – Adwaita dark theme

There are two major changes in the Editor window:

1. We have added a “Close Project” button in the header bar of Editor window that closes the current project and opens Welcome window.

editor-headerbar“Close Project” button (highlighted in right)

2. We have removed “New Project” and “Open Project” options from the menu because these options are already provided in the Welcome window’s headerbar and it can get confusing for the user to have these in multiple places.

In the coming weeks, I will do more additions to the Welcome window such as:

1. Custom project view – displaying meta info regarding a project, such as its directory and last accessed timestamp.

custom_viewInitial design of custom project view

2. Greeter message on Welcome window when user opens Pitivi for the first time or when there are no recent projects.

3. Integrating project thumbnail into project’s custom view.

4. Adding search functionality for easy browsing of projects.

5. Allowing removing items from “Recent Projects” list.

I believe there are more exciting things to come in the upcoming weeks. I will keep posting my progress on this blog. Until next time.

Stay tuned 🙂

June 02, 2018

[GSoC 2018] Welcome Window Integration in Pitivi – Part 1

I will be working on Pitivi as my Google Summer of Code 2018 project under GNOME. One of the major task in my project is to integrate the current Welcome dialog box of Pitivi into it’s main window and display projects in a more informative, discoverable, and user friendly layout.

Currently when Pitivi starts, a Welcome dialog appears that displays the recent projects and some buttons for creating a new project, browsing projects, etc. This dialog box needs to be integrated into the main window.

Pitivi's Current Welcome DialogPitivi’s current welcome dialog

Some GNOME apps that already have their Welcome screen integrated into their main window are Builder, Boxes, Notes, ToDo, etc.

builderIntegrated welcome window in GNOME Builder app
ToDoIntegrated welcome window in GNOME ToDo app

The integration of Welcome dialog into Pitivi’s main window will provide us with more space that will be used for –

  • displaying relevant meta information regarding a project like its directory, last access timestamp, thumbnail, etc. in a nice custom layout rather than just displaying the title of the project (which we currently do in Pitivi’s Welcome dialog)
  • displaying projects categorically as “Starred” and “Recent”
  • providing a search interface to allow for easy browsing of projects
  • better positioning of the buttons based on their actions. Rather than stacking all
    the buttons vertically (which we currently do in Pitivi’s Welcome dialog), we will
    place Important buttons like  “New Project”, “Open Project”, etc. in the Header Bar, and Other buttons like “Help”, “Keyboard Shortcuts”, etc. inside a menu in the Header Bar

As of now, I have integrated the welcome dialog into Pitivi’s main window. Now, we have two main screens in Pitivi – Greeter Perspective (the welcome screen) and Editor Perspective (the video editing screen). The main window manages these perspectives and handles the switch between them.

pitivi_new_1Integrated welcome/greeter window in Pitivi. Notice that the important action buttons like “New” and “Open” are shown prominently in the header bar.
pitivi_new_2Integrated welcome/greeter window in Pitivi. Notice that other (not so important) action buttons like “Keyboard Shortcuts”, “User Manual”, etc. are shown inside a menu in the header bar.

Currently, I have a merge request pending for this change !33. I will keep posting my progress on this blog and on the issue 1302. Until next time.

Stay tuned 🙂

Bringing slow motion to Pitivi

GSoC again :)

Last year, I worked on the project ‘Pitivi: Color correction interface using three chromatic wheels’ as part of my Google Summer of Code. This year again, I’m working on Pitivi under the GNOME organisation. Mathieu Duponchellle and Thibault Saunier are mentoring my project this time.

For the past couple of weeks, I’ve been hacking on GStreamer Editing Services (GES), Pitivi’s backend, to add the ‘rate’ property to a clip. This is the first step towards my project ‘Slow-motion Video’ which has two objectives:

  • Add the clip speed feature to Pitivi
  • Allow parts of a single clip to have variable speeds.

A closer look

The newly introduced ‘rate’ property to a clip uses two GStreamer effects - videorate and pitch to modify the rate of video and audio respectively. GES already facilitates adding and maintaining effects. These effects while relying upon the existing framework to work are kept hidden from the user as internal effects.

A GESClip is a subclass of GESTimelineElement, it therefore has the following relevant properties:

GstClockTime start position (in time) of the object
GstClockTime inpoint position in the media from which the object should be used
GstClockTime duration duration of the object to be used
GstClockTime maxduration The maximum duration the object can have

On changing the rate, the duration and max-duration change as a result.

  duration = input_duration/rate
  maxduration = (asset_duration - inpoint)/rate + inpoint

where, input_duration is the duration of the asset being used and asset_duration is the entire duration of the asset.

After having made the above change to GES, I made a simple UI in Pitivi to test out the rate feature. Speed property is now part of clip properties. Here’s what it looks like

Yuna Proj

I also enabled the ‘rate’ property of GESClip to work with ges-launch - a command line tool which can be used to create multimedia timeline and render/play it.

ges-launch-1.0 +clip ~/path/to/video.mp4 inpoint=10 
duration=20 rate=2.0

The above command plays the 20 seconds of the input video from the 10 second mark at a rate of 2.0, that is, for 10 seconds.

The complex part is to ensure that the entire infrastructure remains stable on this addition and this is what I am currently up to. I’m constantly pushing fixes to ensure that all existing features and operations in GES and Pitivi work with the rate property. Hopefully, by the next time I blog I can upload a clean demo video showcasing the rate feature in Pitivi :)

You can find my work on the issue 2202. Feel free to ping me on #pitivi channel on freenode. Until next time.

April 27, 2018

Dropping support for non-square pixels in Pitivi

Emerging from the long history of the video broadcast industry, there are legacy standards which specify rectangular pixels instead of square pixels. Yes, really! According to Wikipedia, non-square pixels originate in early digital TV standards:

The term pixel aspect ratio was first coined when ITU-R BT.601 (commonly known as “Rec. 601“) specified that standard-definition television pictures are made of lines of exactly 720 non-square pixels.

Today, we’re announcing that we will no longer support rendering non-square pixels. It will still be possible to use videos with non-square pixels in your projects, though.

Pitivi allowed creating projects with non-square pixels, but there were quality and behavior issues, such as this inconsistent viewer and renderer behavior related to them.

GStreamer Editing Services (GES), the library used by Pitivi for video processing, is very flexible and allows using videos of any video format in the same project. However, normally, in a “pro” setup, most video editing applications are very strict about the formats they accept as input, so Pitivi and GES were a bit unconventional with the “anything goes” approach.

This might give a clue as to why it was rather complicated and not very rewarding to “properly” fix the rectangular pixels problems in GES. The following question arose in our IRC channel (#pitivi on freenode):

[2017-10-30 14:37:38] <thiblahute> nekohayo: So my main question would be, do we really care these days to be able to produce non square output?

And we mostly came to the conclusion that only dinosaurs are producing content with rectangular pixels, and that with our limited resources we can’t afford to spend time and effort on this:

[2017-10-30 14:44:06] <nekohayo> so… it seems that non-square only matters for older formats

[2017-10-30 14:44:45] <nekohayo> and since we gave up on handling DV tapes/firewire anyway… we could as well declare PAR dead. Because f*** the 1990-2000’s

[2017-10-30 14:45:29] <nekohayo> Mathieu_Du’s only got love for you if you were born in the 80’s

[2017-10-30 14:46:58] <Mathieu_Du> the what again ?

[2017-10-30 16:36:38] <nekohayo> pixel aspect ratio (acceptable in the 80’s)

[2017-10-30 16:37:28] <Mathieu_Du> aha, knew that song from lubosz though 🙂

As a result of this simplification, the aspect ratio controls in the project settings dialog have been removed—one less thing for the user to worry about—and so the project width and height are now the only settings defining the display aspect ratio.

video_settingsThe aspect ratio settings removed from the project settings dialog

April 12, 2018

How to use the x264 encoding presets when rendering an XGES project

x264 has a few generic encoding presets you can use when rendering. You can see the list of presets and exactly what encoding options they specify by running x264 --fullhelp. You'll most probably notice the following presets: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow. Ideally you'd always use veryslow when rendering, but you can't always wait for it to finish, so you go for faster ones. The ffmpeg wiki summarizes the difference between these presets:
veryslow helps about 3% compared to the slowerpreset, slower helps about 5% compared to the slow preset, and
slow helps about 5-10% compared to the medium preset.
To be able to use for example slow with ges-launch-1.0, you need to create a GStreamer preset. Add the following section to ~/.local/share/gstreamer-1.0/presets/GstX264Enc.prs
[slow12mbps]
speed-preset=slow
bitrate=12288
You need to specify a bitrate in kbits per second because the default value of 2048 kbits per second might not be what you want. I picked 12288 because it's what YT recommends for 1920x1080p50. See the documentation for the x264enc plugin to see all the options you can specify in the preset.

You might also be interested in specifying a tune:
tune=stillimage
 or a psy-tune:
psy-tune=film
Other tune values are: film, animation, grain, psnr, ssim. For the list of available tune values see the plugin source code.

To use the new preset, run:
$ ges-launch-1.0 -l pitivi-project.xges -o out.mp4 -f "video/quicktime,variant=iso:video/x-raw,width=1920,height=1080->video/x-h264+slow12mbps:audio/mpeg,mpegversion=1,layer=3"
The -f parameter accepts a serialized encoding profile.

Pitivi moves from Bugzilla to Phabricator

Using Bugzilla to manage Pitivi was a bit painful and we were looking for a replacement. Many projects seemed to switch to Phabricator lately, which looked like a very good platform for managing projects. We experimented migrating Bugzilla bugs to Phabricator, and we are pretty content with the result. The UI is nicer, we have a better search function, and the Git integration (with the code review component) works great.

We decided to make the switch official, so we updated the documentation on the wiki and website to link to Phabricator, closed the Pitivi Bugzilla “product” and closed the remaining bugs in Bugzilla with a custom made script. The script also linked each bug to the proper task in Phabricator.

For those new to Phabricator, remember that instead of creating a “bug” you create a “task”.

The War Against Deadlocks, part 2: GNonLin’s reincarnation (the other thousand Deadlocks)



GNonLin has served our cause well for a number of years, but was left with indelible marks from the Old World. We grew increasingly worried with GNonLin’s common affiliation with Deadlocks, to the point where it was known as “the Baron of Deadlocks” by our battalion. We tried correcting it, tried reasoning with it, but alas—we only got “not-negotiated” caps errors.


A swift operation took place. The baron was captured and we applied a mix of heavy persuasion and alchemy, until it renounced its questionable affiliations and was reborn. The rise of the Non Linear Engine (“NLE”) plugin brought much joy in the county. Users are no longer harassed by renegade Deadlocks as they peacefully seek along their timelines. The Deadlocks may still try to haunt us, but it’s a whole New World, in which old tricks won’t affect us anymore.


CaptureMission.jpg
Pictured: "The Capture of the Baron"


In the words of the Maintainers:


We reused parts of the videomixer plugin to create the compositor plugin, which, in comparison, is thread safe. The new compositor plugin is already used by quite a few multimedia apps. In this process we created a new base class, which helped rewriting the audiomixer plugin to fix it and make it thread safe. This allowed us to switch from using adder to using audiomixer.

As you might know, the GStreamer plugins are used for creating pipelines, for example: (video1 * effect1) + video2 = x. The compositor plugin implements the + in this equation. A pipeline is used by NLE to play a video project. NleComposition translates a project’s timeline into a GStreamer pipeline dynamically, depending on the current position:




Recently we finished the replacement of GNonLin with Non Linear Engine. This means the composition uses a master thread for setting up the pipeline, whereas before the old composition used to unlink/relink new pipelines from both the streaming thread and from the seeking thread and this was causing Deadlocks (“the other thousand”). Whatsmore, we previously had to have all the elements in the entire timeline available in the composition in the PAUSED state, which meant there were many—so many!—useless threads, created and waiting like sitting ducks; whereas elements are now created only when the pipeline needs them, and they are kept in the READY state until they are actually used by the pipeline.


Long live Non Linear Engine!

Setting up Supybot with the Bugzilla plugin

Supybot is an IRC bot, an application which can connect to a specific IRC channel and do stuff there. For example, with the Bugzilla plugin, Supybot can report on the channel whenever a new bug is filed, or if somebody mentions "bug 1234" in the conversation, it will print details about bug 1234.

Install supybot

First, you have to install Supybot. If you are using Arch Linux, get supybot from AUR, otherwise read the INSTALL file.

Create a supybot user on your system, or on a virtual machine where you want to run the bot.

groupadd --system supybot
useradd -m --system -g supybot supybot

Install the supybot Bugzilla plugin

If you want your bot to announce when new bugs are created, you need to set up an email account, register it on bugzilla and set it up so it gets mails when bugs for your project are created. For this go to Bugzilla -> Preferences -> Email Preferences and read the User Watching section!

Once you have the email account receiving emails from bugzilla, setup getmail on your machine so it downloads the messages from the email account to /var/mail/supybot.

touch /var/mail/supybot
chown supybot.supybot /var/mail/supybot
chmod g+w /var/mail/supybot
chmod o-rwx /var/mail/supybot
chown supybot.supybot /var/mail/supybot

Set the getmail job to download the messages using POP and to delete them from the server after retrieving them.

[destination]
type = Mboxrd
path = /var/mail/supybot

[options]
verbose = 2
message_log = ~/.getmail/gmail.log

Now add yourself to the supybot group (so your getmail cronjob can write the bugzilla emails to /var/mail/supybot). For this to take effect the best option is to re-login!
usermod -a -G supybot YOUR_USERNAME

Add a crontab to your account (not supybot) to fetch the bugzilla mail every minute.

* * * * * getmail -d -q -r /path/to/your/getmail/config/file

Setup your bot

Next you have to create a config, and here it gets even more tricky. Unfortunately, most of the Supybot documentation is gone because the supybot.com website is dead and only redirects to the sourceforge page of the project, where Supybot can be downloaded. You have to create a config using supybot-wizard:

mkdir /home/supybot/pitivi
cd /home/supybot/pitivi
# I suggest to act as an "advanced user" when the wizard asks you
# about what kind of user you are!
supybot-wizard
[...]
# Now see the conf file it created, feel free to rename it to bot.conf. ;)
ls -l *.conf


Copy the Supybot Bugzilla plugin to your setup. Unfortunately the original repository is broken, but you can get it from my Supybot Bugzilla repository.

cd /home/supybot/pitivi
mkdir plugins
cd plugins
bzr co bzr://bzr.everythingsolved.com/supybot/Bugzilla # Broken
git clone https://github.com/aleb/supybot-bugzilla.git Bugzilla


Copy the bugzilla section from this sample config file to your bot.conf file. Or copy it from the pitivibot's bot.conf file below.

###
# Determines the bot's default nick.
#
# Default value: supybot
###
supybot.nick: pitivibot

###
# Determines what alternative nicks will be used if the primary nick
# (supybot.nick) isn't available. A %s in this nick is replaced by the
# value of supybot.nick when used. If no alternates are given, or if all
# are used, the supybot.nick will be perturbed appropriately until an
# unused nick is found.
#
# Default value: %s` %s_
###
supybot.nick.alternates: %s` %s_

###
# Determines the bot's ident string, if the server doesn't provide one
# by default.
#
# Default value: supybot
###
supybot.ident: supybot

###
# Determines the user the bot sends to the server. A standard user using
# the current version of the bot will be generated if this is left
# empty.
#
# Default value:
###
supybot.user: pitivibot

###
# Determines what networks the bot will connect to.
#
# Default value:
###
supybot.networks: freenode

###
# Determines what password will be used on freenode. Yes, we know that
# technically passwords are server-specific and not network-specific,
# but this is the best we can do right now.
#
# Default value:
###
supybot.networks.freenode.password:

###
# Determines what servers the bot will connect to for freenode. Each
# will be tried in order, wrapping back to the first when the cycle is
# completed.
#
# Default value:
###
supybot.networks.freenode.servers: chat.eu.freenode.net

###
# Determines what channels the bot will join only on freenode.
#
# Default value:
###
supybot.networks.freenode.channels: #pitivi

###
# Determines what key (if any) will be used to join the channel.
#
# Default value:
###
supybot.networks.freenode.channels.key:

###
# Determines whether the bot will attempt to connect with SSL sockets to
# freenode.
#
# Default value: False
###
supybot.networks.freenode.ssl: False

###
# Determines how timestamps printed for human reading should be
# formatted. Refer to the Python documentation for the time module to
# see valid formatting characters for time formats.
#
# Default value: %I:%M %p, %B %d, %Y
###
supybot.reply.format.time: %H:%M %Y-%m-%d %Z

###
# Determines whether elapsed times will be given as "1 day, 2 hours, 3
# minutes, and 15 seconds" or as "1d 2h 3m 15s".
#
# Default value: False
###
supybot.reply.format.time.elapsed.short: True

###
# Determines the absolute maximum length of the bot's reply -- no reply
# will be passed through the bot with a length greater than this.
#
# Default value: 131072
###
supybot.reply.maximumLength: 131072

###
# Determines whether the bot will break up long messages into chunks and
# allow users to use the 'more' command to get the remaining chunks.
#
# Default value: True
###
supybot.reply.mores: True

###
# Determines what the maximum number of chunks (for use with the 'more'
# command) will be.
#
# Default value: 50
###
supybot.reply.mores.maximum: 50

###
# Determines how long individual chunks will be. If set to 0, uses our
# super-tweaked, get-the-most-out-of-an-individual-message default.
#
# Default value: 0
###
supybot.reply.mores.length: 0

###
# Determines how many mores will be sent instantly (i.e., without the
# use of the more command, immediately when they are formed). Defaults
# to 1, which means that a more command will be required for all but the
# first chunk.
#
# Default value: 1
###
supybot.reply.mores.instant: 1

###
# Determines whether the bot will send multi-message replies in a single
# message or in multiple messages. For safety purposes (so the bot is
# less likely to flood) it will normally send everything in a single
# message, using mores if necessary.
#
# Default value: True
###
supybot.reply.oneToOne: True

###
# Determines whether the bot will reply with an error message when it is
# addressed but not given a valid command. If this value is False, the
# bot will remain silent, as long as no other plugins override the
# normal behavior.
#
# Default value: True
###
supybot.reply.whenNotCommand: False

###
# Determines whether error messages that result from bugs in the bot
# will show a detailed error message (the uncaught exception) or a
# generic error message.
#
# Default value: False
###
supybot.reply.error.detailed: False

###
# Determines whether the bot will send error messages to users in
# private. You might want to do this in order to keep channel traffic to
# minimum. This can be used in combination with
# supybot.reply.error.withNotice.
#
# Default value: False
###
supybot.reply.error.inPrivate: False

###
# Determines whether the bot will send error messages to users via
# NOTICE instead of PRIVMSG. You might want to do this so users can
# ignore NOTICEs from the bot and not have to see error messages; or you
# might want to use it in combination with supybot.reply.errorInPrivate
# so private errors don't open a query window in most IRC clients.
#
# Default value: False
###
supybot.reply.error.withNotice: False

###
# Determines whether the bot will send an error message to users who
# attempt to call a command for which they do not have the necessary
# capability. You may wish to make this True if you don't want users to
# understand the underlying security system preventing them from running
# certain commands.
#
# Default value: False
###
supybot.reply.error.noCapability: False

###
# Determines whether the bot will reply privately when replying in a
# channel, rather than replying to the whole channel.
#
# Default value: False
###
supybot.reply.inPrivate: False

###
# Determines whether the bot will reply with a notice when replying in a
# channel, rather than replying with a privmsg as normal.
#
# Default value: False
###
supybot.reply.withNotice: False

###
# Determines whether the bot will reply with a notice when it is sending
# a private message, in order not to open a /query window in clients.
# This can be overridden by individual users via the user configuration
# variable reply.withNoticeWhenPrivate.
#
# Default value: False
###
supybot.reply.withNoticeWhenPrivate: False

###
# Determines whether the bot will always prefix the user's nick to its
# reply to that user's command.
#
# Default value: True
###
supybot.reply.withNickPrefix: False

###
# Determines whether the bot should attempt to reply to all messages
# even if they don't address it (either via its nick or a prefix
# character). If you set this to True, you almost certainly want to set
# supybot.reply.whenNotCommand to False.
#
# Default value: False
###
supybot.reply.whenNotAddressed: False

###
# Determines whether the bot will allow you to send channel-related
# commands outside of that channel. Sometimes people find it confusing
# if a channel-related command (like Filter.outfilter) changes the
# behavior of the channel but was sent outside the channel itself.
#
# Default value: False
###
supybot.reply.requireChannelCommandsToBeSentInChannel: False

###
# Supybot normally replies with the full help whenever a user misuses a
# command. If this value is set to True, the bot will only reply with
# the syntax of the command (the first line of the help) rather than the
# full help.
#
# Default value: False
###
supybot.reply.showSimpleSyntax: False

###
# Determines what prefix characters the bot will reply to. A prefix
# character is a single character that the bot will use to determine
# what messages are addressed to it; when there are no prefix characters
# set, it just uses its nick. Each character in this string is
# interpreted individually; you can have multiple prefix chars
# simultaneously, and if any one of them is used as a prefix the bot
# will assume it is being addressed.
#
# Default value:
###
supybot.reply.whenAddressedBy.chars:

###
# Determines what strings the bot will reply to when they are at the
# beginning of the message. Whereas prefix.chars can only be one
# character (although there can be many of them), this variable is a
# space-separated list of strings, so you can set something like '@@ ??'
# and the bot will reply when a message is prefixed by either @@ or ??.
#
# Default value:
###
supybot.reply.whenAddressedBy.strings:

###
# Determines whether the bot will reply when people address it by its
# nick, rather than with a prefix character.
#
# Default value: True
###
supybot.reply.whenAddressedBy.nick: False

###
# Determines whether the bot will reply when people address it by its
# nick at the end of the message, rather than at the beginning.
#
# Default value: False
###
supybot.reply.whenAddressedBy.nick.atEnd: False

###
# Determines what extra nicks the bot will always respond to when
# addressed by, even if its current nick is something else.
#
# Default value:
###
supybot.reply.whenAddressedBy.nicks:

###
# Determines whether the bot will unidentify someone when that person
# changes his or her nick. Setting this to True will cause the bot to
# track such changes. It defaults to False for a little greater
# security.
#
# Default value: False
###
supybot.followIdentificationThroughNickChanges: False

###
# Determines whether the bot will always join a channel when it's
# invited. If this value is False, the bot will only join a channel if
# the user inviting it has the 'admin' capability (or if it's explicitly
# told to join the channel using the Admin.join command)
#
# Default value: False
###
supybot.alwaysJoinOnInvite: False

###
# Determines what message the bot replies with when a command succeeded.
# If this configuration variable is empty, no success message will be
# sent.
###
supybot.replies.success: The operation succeeded.

###
# Determines what error message the bot gives when it wants to be
# ambiguous.
###
supybot.replies.error: An error has occurred and has been logged. Please\
contact this bot's administrator for more\
information.

###
# Determines what message the bot replies with when someone tries to use
# a command that requires being identified or having a password and
# neither credential is correct.
###
supybot.replies.incorrectAuthentication: Your hostmask doesn't match or your\
password is wrong.

###
# Determines what error message the bot replies with when someone tries
# to accessing some information on a user the bot doesn't know about.
###
supybot.replies.noUser: I can't find %s in my user database. If you didn't\
give a user name, then I might not know what your\
user is, and you'll need to identify before this\
command might work.

###
# Determines what error message the bot replies with when someone tries
# to do something that requires them to be registered but they're not
# currently recognized.
###
supybot.replies.notRegistered: You must be registered to use this command.\
If you are already registered, you must\
either identify (using the identify command)\
or add a hostmask matching your current\
hostmask (using the "hostmask add" command).

###
# Determines what error message is given when the bot is telling someone
# they aren't cool enough to use the command they tried to use.
###
supybot.replies.noCapability: You don't have the %s capability. If you think\
that you should have this capability, be sure\
that you are identified before trying again.\
The 'whoami' command can tell you if you're\
identified.

###
# Determines what generic error message is given when the bot is telling
# someone that they aren't cool enough to use the command they tried to
# use, and the author of the code calling errorNoCapability didn't
# provide an explicit capability for whatever reason.
###
supybot.replies.genericNoCapability: You're missing some capability you\
need. This could be because you\
actually possess the anti-capability\
for the capability that's required of\
you, or because the channel provides\
that anti-capability by default, or\
because the global capabilities include\
that anti-capability. Or, it could be\
because the channel or\
supybot.capabilities.default is set to\
False, meaning that no commands are\
allowed unless explicitly in your\
capabilities. Either way, you can't do\
what you want to do.

###
# Determines what error messages the bot sends to people who try to do
# things in a channel that really should be done in private.
###
supybot.replies.requiresPrivacy: That operation cannot be done in a channel.

###
# Determines what message the bot sends when it thinks you've
# encountered a bug that the developers don't know about.
###
supybot.replies.possibleBug: This may be a bug. If you think it is, please\
file a bug report at .

###
# A floating point number of seconds to throttle snarfed URLs, in order
# to prevent loops between two bots snarfing the same URLs and having
# the snarfed URL in the output of the snarf message.
#
# Default value: 10.0
###
supybot.snarfThrottle: 10.0

###
# Determines the number of seconds between running the upkeep function
# that flushes (commits) open databases, collects garbage, and records
# some useful statistics at the debugging level.
#
# Default value: 3600
###
supybot.upkeepInterval: 3600

###
# Determines whether the bot will periodically flush data and
# configuration files to disk. Generally, the only time you'll want to
# set this to False is when you want to modify those configuration files
# by hand and don't want the bot to flush its current version over your
# modifications. Do note that if you change this to False inside the
# bot, your changes won't be flushed. To make this change permanent, you
# must edit the registry yourself.
#
# Default value: True
###
supybot.flush: True

###
# Determines what characters are valid for quoting arguments to commands
# in order to prevent them from being tokenized.
#
# Default value: "
###
supybot.commands.quotes: "

###
# Determines whether the bot will allow nested commands, which rule. You
# definitely should keep this on.
#
# Default value: True
###
supybot.commands.nested: True

###
# Determines what the maximum number of nested commands will be; users
# will receive an error if they attempt commands more nested than this.
#
# Default value: 10
###
supybot.commands.nested.maximum: 10

###
# Supybot allows you to specify what brackets are used for your nested
# commands. Valid sets of brackets include [], <>, and {} (). [] has
# strong historical motivation, as well as being the brackets that don't
# require shift. <> or () might be slightly superior because they cannot
# occur in a nick. If this string is empty, nested commands will not be
# allowed in this channel.
#
# Default value: []
###
supybot.commands.nested.brackets: []

###
# Supybot allows nested commands. Enabling this option will allow nested
# commands with a syntax similar to UNIX pipes, for example: 'bot: foo |
# bar'.
#
# Default value: False
###
supybot.commands.nested.pipeSyntax: False

###
# Determines what commands have default plugins set, and which plugins
# are set to be the default for each of those commands.
###
supybot.commands.defaultPlugins.addcapability: Admin
supybot.commands.defaultPlugins.capabilities: User
supybot.commands.defaultPlugins.disable: Owner
supybot.commands.defaultPlugins.enable: Owner
supybot.commands.defaultPlugins.help: Misc
supybot.commands.defaultPlugins.ignore: Admin

###
# Determines what plugins automatically get precedence over all other
# plugins when selecting a default plugin for a command. By default,
# this includes the standard loaded plugins. You probably shouldn't
# change this if you don't know what you're doing; if you do know what
# you're doing, then also know that this set is case-sensitive.
#
# Default value: Plugin Admin Misc User Owner Config Channel
###
supybot.commands.defaultPlugins.importantPlugins: Plugin Admin Misc User Owner Config Channel
supybot.commands.defaultPlugins.list: Misc
supybot.commands.defaultPlugins.reload: Owner
supybot.commands.defaultPlugins.removecapability: Admin
supybot.commands.defaultPlugins.unignore: Admin

###
# Determines what commands are currently disabled. Such commands will
# not appear in command lists, etc. They will appear not even to exist.
#
# Default value:
###
supybot.commands.disabled:

###
# Determines whether the bot will defend itself against command-
# flooding.
#
# Default value: True
###
supybot.abuse.flood.command: True

###
# Determines how many commands users are allowed per minute. If a user
# sends more than this many commands in any 60 second period, he or she
# will be ignored for supybot.abuse.flood.command.punishment seconds.
#
# Default value: 12
###
supybot.abuse.flood.command.maximum: 12

###
# Determines how many seconds the bot will ignore users who flood it
# with commands.
#
# Default value: 300
###
supybot.abuse.flood.command.punishment: 300

###
# Determines whether the bot will defend itself against invalid command-
# flooding.
#
# Default value: True
###
supybot.abuse.flood.command.invalid: True

###
# Determines how many invalid commands users are allowed per minute. If
# a user sends more than this many invalid commands in any 60 second
# period, he or she will be ignored for
# supybot.abuse.flood.command.invalid.punishment seconds. Typically,
# this value is lower than supybot.abuse.flood.command.maximum, since
# it's far less likely (and far more annoying) for users to flood with
# invalid commands than for them to flood with valid commands.
#
# Default value: 5
###
supybot.abuse.flood.command.invalid.maximum: 5

###
# Determines how many seconds the bot will ignore users who flood it
# with invalid commands. Typically, this value is higher than
# supybot.abuse.flood.command.punishment, since it's far less likely
# (and far more annoying) for users to flood witih invalid commands than
# for them to flood with valid commands.
#
# Default value: 600
###
supybot.abuse.flood.command.invalid.punishment: 600

###
# Determines the default length of time a driver should block waiting
# for input.
#
# Default value: 1.0
###
supybot.drivers.poll: 1.0

###
# Determines what driver module the bot will use. Socket, a simple
# driver based on timeout sockets, is used by default because it's
# simple and stable. Twisted is very stable and simple, and if you've
# got Twisted installed, is probably your best bet.
#
# Default value: default
###
supybot.drivers.module: default

###
# Determines the maximum time the bot will wait before attempting to
# reconnect to an IRC server. The bot may, of course, reconnect earlier
# if possible.
#
# Default value: 300.0
###
supybot.drivers.maxReconnectWait: 300.0

###
# Determines what directory configuration data is put into.
#
# Default value: conf
###
supybot.directories.conf: /home/supybot/pitivi/conf

###
# Determines what directory data is put into.
#
# Default value: data
###
supybot.directories.data: /home/supybot/pitivi/data

###
# Determines what directory temporary files are put into.
#
# Default value: tmp
###
supybot.directories.data.tmp: /home/supybot/pitivi/data/tmp

###
# Determines what directory backup data is put into.
#
# Default value: backup
###
supybot.directories.backup: /home/supybot/pitivi/backup

###
# Determines what directories the bot will look for plugins in. Accepts
# a comma-separated list of strings. This means that to add another
# directory, you can nest the former value and add a new one. E.g. you
# can say: bot: 'config supybot.directories.plugins [config
# supybot.directories.plugins], newPluginDirectory'.
#
# Default value:
###
supybot.directories.plugins: /home/supybot/pitivi/plugins

###
# Determines what directory the bot will store its logfiles in.
#
# Default value: logs
###
supybot.directories.log: /home/supybot/pitivi/logs

###
# Determines what plugins will be loaded.
#
# Default value:
###
supybot.plugins: Web Admin Misc Bugzilla User Owner Config Channel

###
# Determines whether this plugin is loaded by default.
###
supybot.plugins.Admin: True

###
# Determines whether this plugin is publicly visible.
#
# Default value: True
###
supybot.plugins.Admin.public: True

###
# Determines whether this plugin is loaded by default.
###
supybot.plugins.Bugzilla: True

###
# Determines whether this plugin is publicly visible.
#
# Default value: True
###
supybot.plugins.Bugzilla.public: True

###
# Determines whether the bug snarfer will be enabled, such that any
# Bugzilla URLs and bug ### seen in the channel will have their
# information reported into the channel.
#
# Default value: False
###
supybot.plugins.Bugzilla.bugSnarfer: True

###
# Users often say "bug XXX" several times in a row, in a channel. If
# "bug XXX" has been said in the last (this many) seconds, don't fetch
# its data again. If you change the value of this variable, you must
# reload this plugin for the change to take effect.
#
# Default value: 300
###
supybot.plugins.Bugzilla.bugSnarferTimeout: 300

###
# The fields to list when describing a bug, after the URL.
#
# Default value: bug_severity priority target_milestone assigned_to bug_status short_desc
###
supybot.plugins.Bugzilla.bugFormat: bug_severity priority target_milestone assigned_to bug_status short_desc

###
# The fields to list when describing an attachment after announcing a
# change to that attachment.
#
# Default value: type desc filename
###
supybot.plugins.Bugzilla.attachFormat: type desc filename

###
# How various messages should be formatted in terms of bold, colors,
# etc.
###

###
# When the plugin reports that something has changed on a bug, how
# should that string be formatted?
#
# Default value: teal
###
supybot.plugins.Bugzilla.format.change: teal

###
# When the plugin reports the details of an attachment, how should we
# format that string?
#
# Default value: green
###
supybot.plugins.Bugzilla.format.attachment: green

###
# When the plugin reports the details of a bug, how should we format
# that string?
#
# Default value: red
###
supybot.plugins.Bugzilla.format.bug: red

###
# The number of results to show when using the "query" command.
#
# Default value: 5
###
supybot.plugins.Bugzilla.queryResultLimit: 5

###
# A path to the mbox that we should be watching for bugmail.
#
# Default value:
###
supybot.plugins.Bugzilla.mbox: /var/mail/supybot

###
# How many seconds should we wait between polling the mbox?
#
# Default value: 10
###
supybot.plugins.Bugzilla.mboxPollTimeout: 10

###
# Various messages that can be re-formatted as you wish. If a message
# takes a format string, the available format variables are: product,
# component, bug_id, attach_id, and changer)
###

###
# What the bot will say when somebody adds a new attachment to a bug.
#
# Default value: %(changer)s added attachment %(attach_id)d to bug %(bug_id)d
###
supybot.plugins.Bugzilla.messages.newAttachment: %(changer)s added attachment %(attach_id)d to bug %(bug_id)d

###
# What the bot will say when a new bug is filed.
#
# Default value: New %(product)s bug %(bug_id)d filed by %(changer)s.
###
supybot.plugins.Bugzilla.messages.newBug: New %(product)s bug %(bug_id)d filed by %(changer)s.

###
# How should we describe it when somebody requests a flag without
# specifying a requestee? This should probably start with "from." It can
# also be entirely empty, if you want.
#
# Default value: from the wind
###
supybot.plugins.Bugzilla.messages.noRequestee: from the wind

###
# The various Bugzilla installations that have been created with the
# 'add' command.
#
# Default value:
###
supybot.plugins.Bugzilla.bugzillas: gnome

###
# Determines the URL to this Bugzilla installation. This must be
# identical to the urlbase (or sslbase) parameter used by the
# installation. (The url that shows up in emails.) It must end with a
# forward slash.
#
# Default value:
###
supybot.plugins.Bugzilla.bugzillas.gnome.url: https://bugzilla.gnome.org/

###
# Additional search terms in QuickSearch format, that will be added to
# every search done with "query" against this installation.
#
# Default value:
###
supybot.plugins.Bugzilla.bugzillas.gnome.queryTerms:

###
# Should *all* changes be reported to this channel?
#
# Default value: False
###
supybot.plugins.Bugzilla.bugzillas.gnome.watchedItems.all: False

###
# Whose changes should be reported to this channel?
#
# Default value:
###
supybot.plugins.Bugzilla.bugzillas.gnome.watchedItems.changer:

###
# What components should be reported to this channel?
#
# Default value:
###
supybot.plugins.Bugzilla.bugzillas.gnome.watchedItems.component:

###
# What products should be reported to this channel?
#
# Default value:
###
supybot.plugins.Bugzilla.bugzillas.gnome.watchedItems.product: pitivi

###
# The names of fields, as they appear in bugmail, that should be
# reported to this channel.
#
# Default value: newBug, newAttach, Flags, Attachment Flags, Resolution, Product, Component
###
supybot.plugins.Bugzilla.bugzillas.gnome.reportedChanges: newBug

###
# Some Bugzilla installations have gdb stack traces in comments. If you
# turn this on, the bot will report some basic details of any trace that
# shows up in the comments of a new bug.
#
# Default value: False
###
supybot.plugins.Bugzilla.bugzillas.gnome.traces.report: False

###
# Some functions are useless to report, from a stack trace. This
# contains a list of function names to skip over when reporting traces
# to the channel.
#
# Default value: __kernel_vsyscall raise abort ??
###
supybot.plugins.Bugzilla.bugzillas.gnome.traces.ignoreFunctions: __kernel_vsyscall raise abort ??

###
# How many stack frames should be reported from the crash?
#
# Default value: 5
###
supybot.plugins.Bugzilla.bugzillas.gnome.traces.frameLimit: 5

###
# If commands don't specify what installation to use, then which
# installation should we use?
#
# Default value:
###
supybot.plugins.Bugzilla.defaultBugzilla: gnome

###
# Determines whether this plugin is loaded by default.
###
supybot.plugins.Channel: True

###
# Determines whether this plugin is publicly visible.
#
# Default value: True
###
supybot.plugins.Channel.public: True

###
# Determines whether the bot will always try to rejoin a channel
# whenever it's kicked from the channel.
#
# Default value: True
###
supybot.plugins.Channel.alwaysRejoin: True

###
# Determines whether this plugin is loaded by default.
###
supybot.plugins.Config: True

###
# Determines whether this plugin is publicly visible.
#
# Default value: True
###
supybot.plugins.Config.public: True

###
# Determines whether this plugin is loaded by default.
###
supybot.plugins.Misc: True

###
# Determines whether this plugin is publicly visible.
#
# Default value: True
###
supybot.plugins.Misc.public: True

###
# Determines whether the bot will list private plugins with the list
# command if given the --private switch. If this is disabled, non-owner
# users should be unable to see what private plugins are loaded.
#
# Default value: True
###
supybot.plugins.Misc.listPrivatePlugins: False

###
# Determines the format string for timestamps in the Misc.last command.
# Refer to the Python documentation for the time module to see what
# formats are accepted. If you set this variable to the empty string,
# the timestamp will not be shown.
#
# Default value: [%H:%M:%S]
###
supybot.plugins.Misc.timestampFormat: [%H:%M:%S]

###
# Determines whether or not the timestamp will be included in the output
# of last when it is part of a nested command
#
# Default value: False
###
supybot.plugins.Misc.last.nested.includeTimestamp: False

###
# Determines whether or not the nick will be included in the output of
# last when it is part of a nested command
#
# Default value: False
###
supybot.plugins.Misc.last.nested.includeNick: False

###
# Determines whether this plugin is loaded by default.
###
supybot.plugins.Owner: True

###
# Determines whether this plugin is publicly visible.
#
# Default value: True
###
supybot.plugins.Owner.public: True

###
# Determines what quit message will be used by default. If the quit
# command is called without a quit message, this will be used. If this
# value is empty, the nick of the person giving the quit command will be
# used.
#
# Default value:
###
supybot.plugins.Owner.quitMsg:

###
# Determines whether this plugin is loaded by default.
###
supybot.plugins.User: True

###
# Determines whether this plugin is publicly visible.
#
# Default value: True
###
supybot.plugins.User.public: True

###
# Determines whether this plugin is loaded by default.
###
supybot.plugins.Web: False

###
# Determines whether this plugin is publicly visible.
#
# Default value: True
###
supybot.plugins.Web.public: True

###
# Determines whether the bot will output the HTML title of URLs it sees
# in the channel.
#
# Default value: False
###
supybot.plugins.Web.titleSnarfer: False

###
# Determines what URLs are to be snarfed and stored in the database in
# the channel; URLs matching the regexp given will not be snarfed. Give
# the empty string if you have no URLs that you'd like to exclude from
# being snarfed.
#
# Default value:
###
supybot.plugins.Web.nonSnarfingRegexp:

###
# Determines the maximum number of bytes the bot will download via the
# 'fetch' command in this plugin.
#
# Default value: 0
###
supybot.plugins.Web.fetch.maximum: 0

###
# Determines whether the bot will always load important plugins (Admin,
# Channel, Config, Misc, Owner, and User) regardless of what their
# configured state is. Generally, if these plugins are configured not to
# load, you didn't do it on purpose, and you still want them to load.
# Users who don't want to load these plugins are smart enough to change
# the value of this variable appropriately :)
#
# Default value: True
###
supybot.plugins.alwaysLoadImportant: True

###
# Determines what databases are available for use. If this value is not
# configured (that is, if its value is empty) then sane defaults will be
# provided.
#
# Default value: sqlite anydbm cdb flat pickle
###
supybot.databases:

###
# Determines what filename will be used for the users database. This
# file will go into the directory specified by the
# supybot.directories.conf variable.
#
# Default value: users.conf
###
supybot.databases.users.filename: users.conf

###
# Determines how long it takes identification to time out. If the value
# is less than or equal to zero, identification never times out.
#
# Default value: 0
###
supybot.databases.users.timeoutIdentification: 0

###
# Determines whether the bot will allow users to unregister their users.
# This can wreak havoc with already-existing databases, so by default we
# don't allow it. Enable this at your own risk. (Do also note that this
# does not prevent the owner of the bot from using the unregister
# command.)
#
# Default value: False
###
supybot.databases.users.allowUnregistration: False

###
# Determines what filename will be used for the ignores database. This
# file will go into the directory specified by the
# supybot.directories.conf variable.
#
# Default value: ignores.conf
###
supybot.databases.ignores.filename: ignores.conf

###
# Determines what filename will be used for the channels database. This
# file will go into the directory specified by the
# supybot.directories.conf variable.
#
# Default value: channels.conf
###
supybot.databases.channels.filename: channels.conf

###
# Determines whether database-based plugins that can be channel-specific
# will be so. This can be overridden by individual channels. Do note
# that the bot needs to be restarted immediately after changing this
# variable or your db plugins may not work for your channel; also note
# that you may wish to set
# supybot.databases.plugins.channelSpecific.link appropriately if you
# wish to share a certain channel's databases globally.
#
# Default value: True
###
supybot.databases.plugins.channelSpecific: False

###
# Determines what channel global (non-channel-specific) databases will
# be considered a part of. This is helpful if you've been running
# channel-specific for awhile and want to turn the databases for your
# primary channel into global databases. If
# supybot.databases.plugins.channelSpecific.link.allow prevents linking,
# the current channel will be used. Do note that the bot needs to be
# restarted immediately after changing this variable or your db plugins
# may not work for your channel.
#
# Default value: #
###
supybot.databases.plugins.channelSpecific.link: #

###
# Determines whether another channel's global (non-channel-specific)
# databases will be allowed to link to this channel's databases. Do note
# that the bot needs to be restarted immediately after changing this
# variable or your db plugins may not work for your channel.
#
# Default value: True
###
supybot.databases.plugins.channelSpecific.link.allow: True

###
# Determines whether CDB databases will be allowed as a database
# implementation.
#
# Default value: True
###
supybot.databases.types.cdb: True

###
# Determines how often CDB databases will have their modifications
# flushed to disk. When the number of modified records is greater than
# this part of the number of unmodified records, the database will be
# entirely flushed to disk.
#
# Default value: 0.5
###
supybot.databases.types.cdb.maximumModifications: 0.5

###
# Determines what will be used as the default banmask style.
#
# Default value: host user
###
supybot.protocols.irc.banmask: host user

###
# Determines whether the bot will strictly follow the RFC; currently
# this only affects what strings are considered to be nicks. If you're
# using a server or a network that requires you to message a nick such
# as services@this.network.server then you you should set this to False.
#
# Default value: False
###
supybot.protocols.irc.strictRfc: False

###
# Determines what user modes the bot will request from the server when
# it first connects. Many people might choose +i; some networks allow
# +x, which indicates to the auth services on those networks that you
# should be given a fake host.
#
# Default value:
###
supybot.protocols.irc.umodes:

###
# Determines what vhost the bot will bind to before connecting to the
# IRC server.
#
# Default value:
###
supybot.protocols.irc.vhost:

###
# Determines how many old messages the bot will keep around in its
# history. Changing this variable will not take effect until the bot is
# restarted.
#
# Default value: 1000
###
supybot.protocols.irc.maxHistoryLength: 1000

###
# A floating point number of seconds to throttle queued messages -- that
# is, messages will not be sent faster than once per throttleTime
# seconds.
#
# Default value: 1.0
###
supybot.protocols.irc.throttleTime: 1.0

###
# Determines whether the bot will send PINGs to the server it's
# connected to in order to keep the connection alive and discover
# earlier when it breaks. Really, this option only exists for debugging
# purposes: you always should make it True unless you're testing some
# strange server issues.
#
# Default value: True
###
supybot.protocols.irc.ping: True

###
# Determines the number of seconds between sending pings to the server,
# if pings are being sent to the server.
#
# Default value: 120
###
supybot.protocols.irc.ping.interval: 120

###
# Determines whether the bot will refuse duplicate messages to be queued
# for delivery to the server. This is a safety mechanism put in place to
# prevent plugins from sending the same message multiple times; most of
# the time it doesn't matter, unless you're doing certain kinds of
# plugin hacking.
#
# Default value: False
###
supybot.protocols.irc.queuing.duplicates: False

###
# Determines how many seconds must elapse between JOINs sent to the
# server.
#
# Default value: 0.0
###
supybot.protocols.irc.queuing.rateLimit.join: 0.0

###
# Determines how many bytes the bot will 'peek' at when looking through
# a URL for a doctype or title or something similar. It'll give up after
# it reads this many bytes, even if it hasn't found what it was looking
# for.
#
# Default value: 4096
###
supybot.protocols.http.peekSize: 4096

###
# Determines what proxy all HTTP requests should go through. The value
# should be of the form 'host:port'.
#
# Default value:
###
supybot.protocols.http.proxy:

###
# Determines whether the bot will ignore unregistered users by default.
# Of course, that'll make it particularly hard for those users to
# register or identify with the bot, but that's your problem to solve.
#
# Default value: False
###
supybot.defaultIgnore: False

###
# A string that is the external IP of the bot. If this is the empty
# string, the bot will attempt to find out its IP dynamically (though
# sometimes that doesn't work, hence this variable).
#
# Default value:
###
supybot.externalIP:

###
# Determines what the default timeout for socket objects will be. This
# means that *all* sockets will timeout when this many seconds has gone
# by (unless otherwise modified by the author of the code that uses the
# sockets).
#
# Default value: 10
###
supybot.defaultSocketTimeout: 10

###
# Determines what file the bot should write its PID (Process ID) to, so
# you can kill it more easily. If it's left unset (as is the default)
# then no PID file will be written. A restart is required for changes to
# this variable to take effect.
#
# Default value:
###
supybot.pidFile:

###
# Determines whether the bot will automatically thread all commands.
#
# Default value: False
###
supybot.debug.threadAllCommands: False

###
# Determines whether the bot will automatically flush all flushers
# *very* often. Useful for debugging when you don't know what's breaking
# or when, but think that it might be logged.
#
# Default value: False
###
supybot.debug.flushVeryOften: False

###
# Determines what the bot's logging format will be. The relevant
# documentation on the available formattings is Python's documentation
# on its logging module.
#
# Default value: %(levelname)s %(asctime)s %(name)s %(message)s
###
supybot.log.format: %(levelname)s %(asctime)s %(name)s %(message)s

###
# Determines what the minimum priority level logged to file will be. Do
# note that this value does not affect the level logged to stdout; for
# that, you should set the value of supybot.log.stdout.level. Valid
# values are DEBUG, INFO, WARNING, ERROR, and CRITICAL, in order of
# increasing priority.
#
# Default value: INFO
###
supybot.log.level: INFO

###
# Determines the format string for timestamps in logfiles. Refer to the
# Python documentation for the time module to see what formats are
# accepted. If you set this variable to the empty string, times will be
# logged in a simple seconds-since-epoch format.
#
# Default value: %Y-%m-%dT%H:%M:%S
###
supybot.log.timestampFormat: %Y-%m-%dT%H:%M:%S

###
# Determines whether the bot will log to stdout.
#
# Default value: True
###
supybot.log.stdout: True

###
# Determines whether the bot's logs to stdout (if enabled) will be
# colorized with ANSI color.
#
# Default value: False
###
supybot.log.stdout.colorized: True

###
# Determines whether the bot will wrap its logs when they're output to
# stdout.
#
# Default value: True
###
supybot.log.stdout.wrap: False

###
# Determines what the bot's logging format will be. The relevant
# documentation on the available formattings is Python's documentation
# on its logging module.
#
# Default value: %(levelname)s %(asctime)s %(message)s
###
supybot.log.stdout.format: %(levelname)s %(asctime)s %(message)s

###
# Determines what the minimum priority level logged will be. Valid
# values are DEBUG, INFO, WARNING, ERROR, and CRITICAL, in order of
# increasing priority.
#
# Default value: INFO
###
supybot.log.stdout.level: DEBUG

###
# Determines whether the bot will separate plugin logs into their own
# individual logfiles.
#
# Default value: False
###
supybot.log.plugins.individualLogfiles: False

###
# Determines what the bot's logging format will be. The relevant
# documentation on the available formattings is Python's documentation
# on its logging module.
#
# Default value: %(levelname)s %(asctime)s %(message)s
###
supybot.log.plugins.format: %(levelname)s %(asctime)s %(message)s

###
# These are the capabilities that are given to everyone by default. If
# they are normal capabilities, then the user will have to have the
# appropriate anti-capability if you want to override these
# capabilities; if they are anti-capabilities, then the user will have
# to have the actual capability to override these capabilities. See
# docs/CAPABILITIES if you don't understand why these default to what
# they do.
#
# Default value: -owner -admin -trusted
###
supybot.capabilities: -owner -admin -trusted

###
# Determines whether the bot by default will allow users to have a
# capability. If this is disabled, a user must explicitly have the
# capability for whatever command he wishes to run.
#
# Default value: True
###
supybot.capabilities.default: False

Make it dance

Now start your bot from the command line. This way you can see the debug log messages, in case you need to figure out why it does not work.

sudo -u supybot supybot /home/supybot/pitivi/bot.conf


Finally, create /lib/systemd/system/supybot.service to have it started automatically.
[Unit]
Description=Pitivi IRC bot

[Service]
User=supybot
ExecStart=/usr/bin/supybot /home/supybot/pitivi/bot.conf
UMask=0007
Restart=on-abort
StartLimitInterval=5m
StartLimitBurst=1

[Install]
WantedBy=multi-user.target

Remember to start it and enable it to start automatically.
systemctl start supybot
systemctl enable supybot


Alternatively, create a file in /etc/init/ so Supybot is started automatically when the system starts. I probably copied the file below from somewhere, but I don't remember from where.

# This IRC bot serves #pitivi.
description "Pitivi IRC bot"

# I got this from mysql.conf, you might want to have a look
# at other files in /etc/init/ and copy a section which
# looks appropriate. Basically it should start the daemon
# after the network is started.
start on (net-device-up
and local-filesystems
and runlevel [2345])
stop on runlevel [016]

# Restart if it dies unexpectedly. Should not happen.
respawn

# Make sure the binary exists.
# It's recommended you install supybot from the current git
# HEAD, because no features are being worked on, and it
# should be stable: http://sf.net/projects/supybot/develop
# In this case, the binary is in /usr/local/bin/supybot.
# This may differ if you are using, the package included in
# your Linux distribution, for example.
pre-start script
test -x /usr/local/bin/supybot || { stop; exit 0; }
end script

# Output to the console whatever it outputs.
console output

# Run the bot with the specified config file.
#
# The bot does not need to run as a daemon, unless
# there are other jobs depending on its sucessful start,
# for example. If there are, you should add "expect fork",
# and specify --daemon to the command line, and hope that
# it works, because:
# "One needs to be very careful with the expect stanza
# to avoid confusing Upstart: the program must fork in
# precisely the expected way." ion
#
# To create the supybot system user and system group, and
# add yourself to the group so you can easily edit files
# run:
# addgroup --system supybot
# adduser --system --ingroup supybot supybot
exec sudo -u supybot /usr/local/bin/supybot /home/supybot/pitivi/bot.conf


Congratulations! Send me an email and tell me how happy you are that you have your bot. ;)

Polishing Pitivi's ruler



In Pitivi, the ruler is displayed above the timeline to show the times corresponding with the current view. A series of H:MM:SS.XXX timestamps on a ruler might leave the impression that only trained professionals are supposed to use it. I had trouble reading the timestamps and looked for ways to make the ruler more useful. Read below for the story.

Pitivi ruler, Dec 2013

Relevant parts

Around the New Year 2013-2014 I thought about highlighting the relevant parts in the timestamp. For example, if you have 0:00:05.000 and then 0:00:10.000, you have to look quite a bit until you notice what changes from one to the other. In this case the "10" should be highlighted because that's different than the previous timestamp. This way it's easier to see what an interval represents. Jeff liked the idea and the commit went in.

The ruler being more useful, I started to look more at it while using Pitivi. One week later, after 6 code cleanup commits, the millis were being displayed with a smaller font, so they can be ignored more easily. One hour later though, the hours and millis were being displayed only when useful:
  • The hour is displayed only if greater than 0. 
  • The millis are displayed only when the zoom level is high enough that millis other than “.000” start to show up in the timestamps. This got improved later!
The shorter timestamps looked good so the changes went in.

Guessing most projects are less than one hour long and most of the time users don't use zoom levels where milliseconds matter—this was already a big improvement, it’s much easier to see “MM:SS” than “0:MM:SS.000”.

Pitivi ruler zoomed out, Jan 2014

Dividing an interval

An “interval” on the ruler is the interval at which the timestamps are shown. At different zoom levels, the length of the interval is picked automatically out of a hardcoded list, so you see an optimum number of timestamps. It was awkward that the displayed intervals were always divided in 10 parts. While it makes sense for a 10 seconds interval to be divided by 10, it’s not very useful when a 30 minutes interval is divided by 10.

It was easy to define the tick frequency for each of the hardcoded intervals, but it looked awkward for most of the zoom levels. Previously we clearly preferred largish interval sizes (so the interval can be divided in 10 smaller but still visible units) but it was not so nice anymore when a large interval is divided only in 2 units. Some fine-tune of the minimum interval length and the minimum division length was required. The smaller timestamps fit great with the smaller intervals:

Dividing by 2 is enough for some intervals, Dec 2015

Timestamp shape

While fine-tuning the minimum interval and interval division size, I realized that when displaying millis, it’s useful to display only the millis, except for the full second timestamps when only [H:]MM:SS is displayed. This way it’s much easier to see where the full seconds are, because “00:01” looks quite different shape-wise than “.500” which is displayed with a smaller font. Luckily, by keeping all the timestamps short (“.900” is the shortest and “9:00:00” is the longest), it was possible to have a simple formula for choosing the optimum interval per zoom level.

Pitivi ruler zoomed in, Jan 2016

The commit went in, along with a cherry.

Some did not like the pear-shaped playhead though, so we later replaced it with an empty diamond.

Pitivi playhead, Apr 2016

Start Pitivi and look at the ruler, zooming in and out, a nice feeling starts bubbling up inside.

Until we wrap up 0.96, you can already see the ruler in action by downloading the Pitivi bundle! BTW, the bundle already includes the proxy files functionality which allows using any video format reliably. Read: no more artifacts when using MTS files. When compared, the ruler polishing I described above is just me playing in the sand. The proxy files functionality brings Pitivi much closer to 1.0. Please try it out and tell us how it works for you! :)

If you are still here, see maybe the entire history of Pitivi’s ruler.

February 27, 2018

Migrating to GNOME’s GitLab

Three years ago we switched our bug tracker from Bugzilla to Freedesktop’s Phabricator instance. As very few projects were using it, the maintenance cost was too high for the gain, so the current plan is to obsolete it. Phabricator worked well for us, but now we say bye.

Luckily for us, GNOME hosts a GitLab instance since last year. We just migrated the Phabricator tasks to it and now we’re at https://gitlab.gnome.org/GNOME/pitivi.

This was possible thanks to Thibault for extending the bztogl tool used to migrate the tasks, to Carlos for carefully running it, and to the GNOME community for everything.

We’ll certainly benefit a lot from the tighter integration with GNOME. This makes it much easier for GNOME contributors of all kinds to take part in our awesome video editor.

September 22, 2017

Pitivi 1.0 Release Candidate — “Ocean Big Chair”

We’re proud to release the first Pitivi 1.0 release candidate “Ocean Big Chair” (0.99). This release has many bug fixes and performance improvements, and is a release candidate for 1.0. Our test suite grew considerably, from 164 to 191 meaningful unit tests.

You can install it right away using Flatpak.

GSoC

Early on this year, we got caught up in the Google Summer of Code. A lot of students hacked on Pitivi this spring, to get to know Pitivi better. As a result quite a few important fixes and improvements have been made. A big thank you to all of the students who contributed!

This summer we had three GSoC Pitivi projects. The GSoC work has been merged on the “master” branch and we made a separate “1.0” branch where we implement or backport the relevant fixes. A special thank you to Suhas Nayak and Ștefan-Adrian Popa, two of our GSoC students who contributed a large number of bugfixes and made possible this release.

1.0

As you might know, we’re focused on bug fixing until Pitivi 1.0. See what’s left to do for 1.0 in Phabricator.

We need people to test Pitivi (the Flatpak “stable” branch) and report back any crash or stability issue they notice, so we fix it. — If you want to help in any way, come to our IRC channel.

September 14, 2017

Cheese's pipeline

I have been reading the source code of Cheese. I wanted to get an idea of how it works. So this is what I understand. Below the diagram you will see an explanation of this, if you know about GStreamer you may want to skip the explanation.

Developer Console I

Cheese reads some data from the selected webcam device using the bin camera_source. In parallel, Cheese uses an autoaudiosrc to capture data from the sound card. The data from the webcam is sent to a tee which work is to duplicate the output.

Firstly, one of the outputs of this tee is passed to an element called element_bin_preview (this also uses a tee of nine outputs… but that’s not showed in the diagram). An elements_bin_preview has 9 sink pads. The output that flows out from there is (for each sink pad) passed to a filter and finally to a cluttersink. Its name on itself is just descriptive, elements_bin_preview is used to preview the effects in that 3x3 “grid” used for Cheese when you click on the “Effects” button.

Secondly, the data that flows from the other sink pad of the tee is sent to an element called current_selected_filter which is the filter that has been currently selected by the user by clicking the grid of effects in Cheese. In case of recording video, the output that flows out from one of the sink pads of the tee is sent in parallel with the autoaudiosrc to an encodebin which (of course) encodes and mixes to pass it to a filesink so you have the result (a video file) on your disk. In case of using the “burst mode” in Cheese, the second output of the tee is used to be passed to a filesink. The filesink can then capture some bunch of frames (by default 4 in Cheese) saving the output in the disk. filesink usually receives an index in its filename, so when you take a picture with Cheese, you will usually see that base names of file names have a number from 1 to 4 in the sufix when using “Burst mode”. Finally, the third output of the sink is used to show the output of the camera with the filter applied in the Cheese main window using a cluttersink element.

August 28, 2017

GSoC '17 - Final Report

This summer as part of Google Summer of Code 2017, I worked on the project “Pitivi: Color correction interface using three chromatic wheels”. As GSoC concludes, I’m writing this post as part of my final submission.

Status of the project

I worked on the task T3263 to setup the infrastructure to allow special effect interfaces. Previously, Pitivi simply autogenerated the UI for an effect based on the effect properties. Differential revision D1744 sets up the API to allow custom UI for an effect and D1777 improves the mechanism by providing a way to have a few custom widgets for effect properties while autogenerating the rest of the UI. If you’d like to know exactly how this mechanism developed and how it works, please refer to my GSoC Phase 1 Progress Report.

As an example to use this custom widget API, I worked on the task T7761, implementing a simple UI for the alpha filter effect - differential revision D1745

And finally, I worked on the task T2372 making the ‘Color correction interface using three chromatic wheels’ for the 3 point color balance effect. I had to learn how to make custom Gtk widgets and cairo for making the color wheel widget. Being new to this task, I referred to the GIMP’s color wheel widget and ended up making a standalone version of it removing dependencies like libgimp.

color wheel widget

However, we decided to use the GtkHSV for now instead of my implementation because although GtkHSV has now been deprecated it is still available as part of Gtk3 and is far more superior than my basic color wheel. Perhaps, it would be nice if we got the widget from upstream and if not, the alternative is to improve my implemenation of the color wheel widget which can be found here. D1838 holds the new custom UI for the 3 point color balance effect.

I was able to achieve one of the stretch goals of GSoC, task T7810 to implement color picking functionality. Differential revision D1855 introduces the ColorPickerButton which allows picking color from anywhere on the screen. As a result, the ColorPickerButton can be integrated in many places in Pitivi! :)

To summarise, here are the links to my work:

As of now, these revisions have not yet been merged. My immediate task is to follow through the review process to get these revisions merged.

The final product of my Google Summer of Code looks like this!

Final Words

I would like to thank my mentor Mathieu Duponchelle (Mathieu_Du) for guiding me. He’s been really encouraging and thoughtful. A special thank you to both the current maintianers, right from when I started contributing to Pitivi earlier this year, Alexandru Băluț (aleb) and Thibault Saunier (thiblahute) have been extremely helpful. It’s been great working with these people at Pitivi. I’ve had a wonderful journey so far. Ofcourse, this is not the end. My work for GSoC introduces so much more possibility and I would like to explore and continue contributing :)

Until next time.

GSoC 2017 : wrap-up and code submission

This post pretends to summarize what has been done during my project in the Google Summer of Code. This is also my Work Product Submission. The project has consisted on implementing a plugin manager for Pitivi and adding a plugin called the Developer Console.

Libpeas

The first part of my project I worked on the bug 780685. Currently it is not possible to implement a plugin system in Python based applications using Libpeas. I have wrote two patches (attachments 354018 and 354019) that fixes the problem. Get these patches merged was depending on Libpeas mantainer. Unfortunately, although he has already reviewed my code, he is currently disabled to review my patches. Lately, the GNOME Builder mantainer has offered to review my patches in bug 660014. As response to his review, these patches has been proposed: attachment 357644 and attachment 357645. In my opinion, the two set of patches proposed to the Libpeas mantainer and to the GNOME Builder mantainer are ready to merge, but it seems it will take time. This is not a a big obstacle for Pitivi, though, because I have added my patch as a source of Libpeas in the Pitivi’s Flatpak manifest. This has just been merged in Pitivi (see D1746).

Plugin Manager

The development of the Plugin manager consisted firstly on creating a module PluginManager that handles the plugins in Pitivi (see D1748), which also provides the API that exposes the application instance to the plugins. The plugin manager class is configuration-aware (see D1812) so it remembers which plugins were activated or deactivated on the last execution of the program. Then I have created an user interface for it (see D1789. The Preferences Dialog has been extended to list the available plugins and allow activating and deactivating them. It also handles plugins with dependencies as Libpeas does. Also, the Pitivi Preferences Dialog has been modified (see D1853) so plugins can add custom preferences widgets to the Pitivi Preferences Dialog. All the patches linked have just been merged in Pitivi. Other feature that has not been merged yet is one that classifies plugin in system and user plugins.

Plugin Manager UI

Developer Console Plugin

The developer console plugin is based on a Gedit’s plugin calle “pythonconsole”. Initially my project was reusing most of the “pythonconsole” plugin, but lately through many iterations of reviews it has been improved a lot. Gedit’s “pythonconsole” works trying to eval the input command and if it fails then it tries exec. This approach (see D1793) has been improved using the code module. I have added to it autocompletion support (see D1857). Also I have integrated color preferences with the Pitivi Settings and I have added the option to customize the font of the emulated console (see D1790, D1792 and D1828).

Developer Console I

The developer console (that uses code.InteractiveConsole) has access to internal objects on Pitivi. That behavior is achieved by adding a dictionary of locals variables, for example it receives as locals an argument like {"app": app}. The problem with this was that the user can (accidentally) override app to None for example and thus losing the access to the Pitivi’s internal objects. That has been solved by adding a custom class called Namespace that inherits from a dict overriding setitem so whenever the user wants to change the value of app (for example), the console writes an error message to stderr. Also, some “shorcuts” commands has been added for a fast access to objects that my mentor and I think will be frequently used. See D1793 or this old post for an extended explanation.

Developer Console I

This plugin is not merged yet, but some of the patches here has been accepted.

Documentation

Two patches that documents a basic behavior of the console has been proposed. The first patch (see D1858) provides plugin developers a very basic information about how to create a plugin. The second patch is a tutorial that explains how to create a plugin that does something useful that is to remove gaps between clips (see D1859). This patches has not been reviewed yet but my mentor told me that it would be helpful to have documentation, so I did this.

Yes… you can code in Pitivi :)

August 24, 2017

Writing a plugin for Pitivi I

The code I have written have been reviewed a lot. So these days I have been completing some minimal details in my code. My patches that implement the plugin manager for Pitivi has been accepted. The next bunch of patches that are on revision are the ones related to the developer console plugin. I want to thank the dedication that Alexandru Băluț (aleb) put to review my code, because this improve the software. While aleb was reviewing my patches, I have been writing some documentation that will be published later in The Pitivi Developer Documentation, but before that I want to share a simple example about how to write a plugin for Pitivi.

At GUADEC 2017, Christian Hergert gave a talk named “State of the Builder”. As I have said in my previous post this was one of the conferences I was most interested about. Unfortunately, there was a problem with the audio recorder and the video of his talk has not been published on Youtube. But I remember he showed a plugin in which you can play a video in GNOME Builder using GStreamer.

hergertme's tweet

Today I feel on the mood to do something similar. So why not to write a plugin to edit code in Pitivi?

Code Editor

Editing code in Pitivi

Yep… this is a joke and a tutorial at the same time. Let’s start.

Plugins location

User plugins that are from third-party developers should be placed at $HOME/.local/share/pitivi/plugins/.

The .plugin description

The first step to create plugin is to create a plugin description file. By convention, this file should be named module-name.plugin.

[Plugin]
Module=code_editor
Name=Code Editor
Description=A plugin to edit code in Python.
Authors=Example <example@example.com>
website=http://example.foo
Copyright=Copyright © Example
Loader=Python3

For a complete example of a plugin description file, see PeasPluginInfo documentation.

Creating a simple Python module

The only interface available to implement by Pitivi extensions is the Peas.Activatable. Extension modules should implement this interface and internally as soon this module is loaded Pitivi will set to it the object attribute to the Pitivi application object, which will give you access to almost everything.

Now create the file hello_world.py in the same directory of hello-world.py.

class CodeEditor(GObject.GObject, Peas.Activatable):
    __gtype_name__ = 'CodeEditor'
    object = GObject.Property(type=GObject.Object)

    def __init__(self):
        GObject.Object.__init__(self)

    def do_activate(self):
        print("Hello world!")

    def do_deactivate(self):
        print("Bye!")

You’ve just created your first plugin! It will print a message in the terminal when you activate or deactivate the plugin.

Replacing the Pitivi Timeline by a GtkSourceView

The plugin we wrote was bery simple, now we want to do something more complex.

We will rewrite our __init__ function to look like this:

    def __init__(self):
        GObject.Object.__init__(self)
        self.app = None
        self.source_view = None
        self._timeline = None

where self.app will represent the Pitivi application.

Now we want to do something useful when the plugin is activated. So we will replace this method by this:

    def do_activate(self):
        API = self.object
        self.app = API.app

        self._timeline = self.app.gui.timeline_ui.get_child_at(0, 1)
        self.app.gui.timeline_ui.remove(self._timeline)

        self.source_view = GtkSource.View()
        language_manager = GtkSource.LanguageManager()
        language = language_manager.get_language("python3")
        buf = self.source_view.get_buffer()
        buf.set_language(language)
        self.source_view.show()

The API object contains the Pitivi application, so we assign it to self.app just to access it without typing too much. Then we get the Timeline object that is the widget that displays a representation of the GES.Timeline. Then we create a GtkSourceView that is the widget that provides a text editor with features like highlighting (among others). Then we set to it as “python3” as the default language and then set it to the buffer of the GtkSourceView. Finally, we show the source view.

Now we wish to add just these lines to have a better code editor:

        self.source_view.props.show_line_numbers = True
        self.source_view.props.show_right_margin = True

Then the function do_deactivate is called every time we turn off the switch in the plugin manager. We destroy the GtkSourceView so it is removed from its parent, too. Finally we reattach the timeline so the timeline is visible again.

    def do_deactivate(self):
        self.source_view.destroy()
        self.app.gui.timeline_ui.attach(self._timeline, 0, 1, 2, 1)
        self.source_view = None

That’s it. You can do more if you want like adding support for more languages or a button to export the code as a file. You can also add preferences to the Preferences Dialog and add new settings. With this example I want to show you that you can go as far as you want just with imagination and some knowledge about programming.

Full code

from gi.repository import GObject
from gi.repository import GtkSource
from gi.repository import Peas


class CodeEditor(GObject.GObject, Peas.Activatable):
    __gtype_name__ = 'CodeEditor'
    object = GObject.Property(type=GObject.Object)

    def __init__(self):
        GObject.Object.__init__(self)
        self.app = None
        self.source_view = None
        self._timeline = None

    def do_activate(self):
        API = self.object
        self.app = API.app

        self._timeline = self.app.gui.timeline_ui.get_child_at(0, 1)
        self.app.gui.timeline_ui.remove(self._timeline)

        self.source_view = GtkSource.View()
        language_manager = GtkSource.LanguageManager()
        language = language_manager.get_language("python3")
        buf = self.source_view.get_buffer()
        buf.set_language(language)

        self.app.gui.timeline_ui.attach(self.source_view, 0, 1, 2, 1)
        self.source_view.show()

        self.source_view.props.show_line_numbers = True
        self.source_view.props.show_right_margin = True

    def do_deactivate(self):
        self.source_view.destroy()
        self.app.gui.timeline_ui.attach(self._timeline, 0, 1, 2, 1)
        self.source_view = None

As I said this was in part a tutorial and a joke at the same time. So I hope you have enjoyed the post and also I hope the plugin manager gets merged as soon as possible. I am writing serious documentation that will explain more about how to write plugins in Pitivi. I also want to thank to Christian Hergert to take his time to review my patch for Libpeas.

August 16, 2017

GUADEC 2017

One of the things I like the most about GNOME are the annual conferences called GUADEC. You can see in person to the folks you were chatting with on IRC. As I have mentioned in my previous posts, I am an accepted GSoC 2017 student this year, and thus like other students, I was invited to give a lightning talk about my project with Pitivi, that consist on adding a plugin system as I mentioned in other posts. I live in Peru, so the duration of the flight is really long. Actually, I found a great deal by going first to Madrid and then taking other flight to Manchester. From Lima to Amsterdam (the stop of my flight to Madrid) it was about 12 hours, from Amsterdam to Madrid it was about 3 hours and from Madrid to Manchester about 2 hours. Yup! Almost 17 hours flying. But it was worth it.

I arrived to Manchester on July 27 at 12:20 p.m. and the weather surprised me with a strong rain. It may be more surprising when you live in a city were it does not rain. Then I had to go to the Manchester Metropolitan University where many of the GNOME contributors would be hosted. When the bus stopped on the Manchester Metropolitan University I went to the first building of it I see and asked how to get to the Birley Fields, our accomodations. A man told me the directions and gave me a map. After some minutes walking I got the office that assigns the rooms to the new residents. I met there Mario, a guy from GNOME who is involved in Flatpak. It was interesting to talk with him in English when at the end we realized that we both could speak in Spanish. After leaving my stuff on my room, I left the room to walk outside and I found David King. It was incredible because it was almost three years we didn’t see to each other. In that day, I also met hadess (Bastien Nocera). He helped me to get a traveler adapter. This was also the day of pre-registration in a bar called KROBAR. I got joined to the GStreamer folks who I met before in GUADEC 2014. Some of the guys came up with the idea that the GNOME logo needs a new design. I talked about it before on the #gnome-design channel. I also met ystreet00 (Matthew Waters) who helped once to create a GStreamer plugin with OpenGL.

alt text

GNOME stickers

The next day the talks started. In the venue, one of the first things I did was to buy a GNOME t-shirt. One of the talks I was very interested in was the one of Alexander Larsson about Flatpak and the one of Christian Hergert about GNOME Builder. I was very interested in the conference of hergertme because I has taken some of the ideas of GNOME Builder to apply them in Pitivi. I don’t always use this application because I am not totally adapted to it, but now I am considering to use it more instead of just coding on Gedit. That day I met Lucie Charvát, a student of the Google Summer of Code who is working in a nice feature of GNOME Builder that I always was thinking that was missing. Finally, I met to suhas2go (Suhas), other of the GSoC guys working on Pitivi like me. It was really awesome to meet him :) That day I also found Julita, who put strong effort to spread the word of GNOME in Peru. She introduced me to Rafał Lużyński who is from Krakow. It was a great coincidence because I was going to visit visit Warsaw and Krakow after GUADEC.

Davind King explaining me about GTK dialogs

David King explaining me about GTK dialogs

The second day of talks I woke up very early, about 4:00 a.m. and it was so the rest of the days. I took this as an advantage to continue with my GSoC project. One of the conferences I was most interested in was the one about Wayland, which is a project I have some interest on getting involved because it seems challenging to me and because of the EVoC. Other talk I found pretty interesting and I think I will investigate more about it was the one titled “Fantastic Layouts And Where To Find Them”. I promise to post about it as soon I try it, because you can create different layouts in GTK+ with a very simple syntax, that seems really easy to remember and understand. That day we had the party for the 20th anniversary of GNOME. I met there Federico Mena, who was telling me about how they started GNOME. It was awesome to listen to him, it was like traveling to the past and I am very grateful with the work of this man. After the event finish, I met Christian Hergert in person. I was talking with him about libpeas and GSettings. After talking with him I was convinced that Pitivi should use GSettings instead of ConfigParser.

With Federico Mena on the screens

Selfie with Federico Mena on the 20th anniversary party

The last day of the conference three Pitivi contributors (Jeff, Suhas and I) were together. I showed to Jeff a project I was working on during my vacations of the university that was a plugin for GStreamer I called gstblendersrc which I hope to continue and finish after GSoC finishes. During talks there was an open talk I was interested in that was Microsoft loves Linux. I has never supported Microsoft, but they are good in business, my interest was basically because before arriving to Manchester, during my flight from Madrid to Manchester I was reading a book named Conscious Capitalism by John Mackey (CEO of Whole Foods Market) who states that capitalism gives efficiency to non-profit organizations. By the way, I recommend the GNOME Board to read this book. Then the groupal photo took place and the lighning talks. I hope to be in Almeria the next year that is where next GUADEC will take place. Then it was the city tour, but, unfortunately, I lost the group. Anyway, it was a great opportunity to hack on Pitivi.

GUADEC 2017 t-shirt

GUADEC 2017 t-shirt

The next days were the workshops. Suhas and I were working on Pitivi. Suhas learns very fast, I think. When I did my first GSoC I had some problems. We sometimes helped between us, but that was not happening with frequency. The last day of the workshops I was looking for David King because I was thinking about working in Cheese for my thesis, but I couldn’t find him. I was with Julita and Felipe Borges. I told him about a project I have on my mind to implement in Cheese that is adding stickers over the detected faces on people. He started to give me more ideas, like to have a library of stickers fed by the community. Also he told me that it could be possible to add watermarks in Cheese so in presentations events of GNOME, people can take pictures with Cheese with the stickers and the final picture would have a watermark of even the Cheese logo or the GNOME logo. Now I need to talk about it to some professors. That was my next-to-last day in Manchester. Felipe Borges showed me some pictures of the tour he had in the Manchester United Stadium. So I went there the last day of the workshops.

I took a photo to Suhas without telling him

I took a photo to Suhas without telling him anything

alt-text

August 08, 2017

My first GUADEC :D

I attended my first GUADEC this year which was held at Manchester, UK. One of the reason I started contributing to GNOME was becasue of the family like community it has. Being a newcomer at GNOME, I felt so welcomed and part of this huge family at GUADEC!

Day 1 - My lighting talk!

The conference kicked off with amazing talks on the first day. I’d like to mention the ones which were the highlights for me :) Allan Day’s “The GNOME Way” talked about the principles we should follow at GNOME. One principle that appealed to me the most was “We take responsibility for User Experience”, it made me realize the magnitude of impact my GSoC project - Custom Effect UI for Pitivi has. Christian Hergert showed us some cool animations of Builder!

One of my favorite talks of GUADEC was Arun Raghavan’s because of its simplicty. He talked about making better the home media experience on GNOME, how we already have all the pieces required for GNOME Screencast (GNOMECast!) and that all that needs to be done now is for someone to bring the pieces together. I wonder how much skill this ‘simple’ task would require :P

I was thrilled (and nervous) to see so many people attend the intern lightning talks. I got to present my GSoC work for Pitivi. The recording of the talks will soon be made available.

Day 2 - GNOME 20th Anniversary Party!

The highlight of the second day was Jonathan’s “The History of GNOME” - “All we are doing is removing features from when we started” :D. We spent the evening celebrating the 20th Anniversary of GNOME. The insider talks with a few GNOME Oldtimers was the best part of the party. Aaaaaand, I won 1 year VPN subscription in the raffle (where is my prize though, I haven’t got it yet :D)

Day 3 - Exploring Manchester!

There was a discussion/announcement about the decision to move to GitLab. Personally, I am very excited and totally in agreement. I think it would vastly increase the developer experience and make it easier for more people to contribute.

Juan Pablo’s talk about Glade showcased it’s modern UI and how one can easily insert custom widgets in glade by writing a simple catalog file (xml).

Later, we went on a city tour exploring Manchester..

Walking tour

Meeting people

Ofcourse I met a lot of people at GUADEC! However, I’d like to mention a few -

  • Jean-François Fortin Tam (Jeff/nekohayo) - My GSoC project builds upon Jeff’s work. He appreciated my work and was so glad to see the color wheel widget :)

  • Georges Stavracas (feaneron) - When I started open source, I used to go through feaneron’s blog a lot. His journey has been inspirational. I am so happy that I got to meet him!

The Trek!

Thanks to the weather gods showing mercy on us, we went on a trek to the Peak District. Allan Day was such a wonderful guide, it was my first time trekking and it was amazing ^_^

Trek

Final Words…

I’d like to thank the GNOME Foundation for sponsoring my visit to GUADEC, the organising team for doing a wonderful job and the volunteers for helping out :) Thank you all who were at this GUADEC in making it the most awesome one yet :D See you all next year at Almería.

GNOME Foundation Sponsorship

August 05, 2017

Sailing towards Pitivi 1.0 (with some stops along the way)

With the Ken-Burns effect project completed, most of my last two weeks were spent working on some existing tasks that should be solved for Pitivi 1.0, so we can get it out sooner. Here are some things I’ve been working on:

  1. Make sure well supported audio streams are not proxyed even if they are not in a container: T7756
  2. Solved a bug where the undo stack sometimes crashed when moving the viewer: T7800
  3. Added the possibility to create custom validation checks for the advanced properties of the encoders, which will make rendering more robust in the long run: D1804

Also, Alex Balut (aka aleb) found some time to test the Ken-Burns branch and suggested some changes. Therefore, the sail towards Pitivi 1.0 had some stops, in which I spent my time working on making the Ken-Burns project a bit better. The most noticeable improvement is the fact that the displayed values of the transformation properties are now updated more often, so they are more accurate (they were sometimes completely wrong as we were not updating them when we should have).

With that said, I will continue helping with the Pitivi 1.0 release and keep you posted on the progress. Until next time!

July 20, 2017

Pitivi: Transformation properties keyframes ready to land

In my last blog post, I was telling you how my GSOC project was close to its completion. Since then, I’ve been working on getting it to a deployable state, while also adding some final touches. Now, it should be ready to land and you’ll probably see it included in Pitivi 2.0.

About the final touches: one is extending the undo/redo system so it can handle activation of transformation properties keyframes and the reset to default operation (which will deactivate the keyframes).

The other one I’ve been working on is a mechanism which allows selection of the transformation properties keyframes. Before this, the only way of navigating to a certain keyframe was using the two arrows in the transformation box.

4

Now, you can also click on a keyframe to select it and the playhead will seek to its position. This should make navigation a bit more intuitive.

So, what’s next? Having anticipated that this project wouldn’t keep me occupied for all the summer, the plan at the beginning of GSOC was to start implementing another feature: rendering only a portion of the timeline. However, after discussing with my mentor, we decided that it would be better to work on solving some existing issues in order to have Pitivi 1.0 out as soon as possible.

Until next time!

July 16, 2017

Two Realizations...

How Custom Effect Widget API evolved

Simply using the initial API, for allowing custom widgets instead of the default UI for effects, has brought in a lot of changes to it. Being new to such a task of designing the API, it was good that I had to make an example custom UI for the alpha effect. I realized that the default UI for effects does a good job (I mean, you can’t do anything more fancy than the default sometimes), except for some widgets of effect properties where something more modern can provide a better user interface for editing. This called for an improvement to the existing custom widget mechanism.

Now, custom widgets for only certain properties can be added while falling back to the auto-generated UI for the rest. To maintain consistency, one has to connect a callback to the ‘create_property_widget’ signal and return a DynamicWidget wrapper around the custom property widget. Although, I would have liked to do away with this wrapper. It seems like the best approach as it would allow the designer to truly customize the widget.

D1777 holds these new changes.

Baby steps in making custom widgets

For the past few days, I’ve been learning gtk in c and cairo. Porting the classic EggClock to gtk3 and exploring the basics. My next immediate task is to make a color wheel widget. Gtk3 already had such a widget, GtkHSV, which is now deprecated (infact, removed from the master!). Having talked on the IRC, it seems Gtk had pulled the widget from GIMP but since they found that it was not being used by other applications, they decided to deprecate it. GIMP has taken back their widget. Although, our widget would heavily borrow code, it seems building a separate Pitivi Library of custom widgets would be the best thing to do.

Subclassing a GtkDrawingArea and drawing a circle, I was trying to run a skeleton-like custom widget code, all I could see was an empty window. Took me to some to ‘realize’ my mistake (I had left the overrided realize callback empty). I was so happy when I managed to draw this circle in cairo :P

baby custom cairo

Until next time :)

Pitivi Developer Console Plugin

The first part of my project was focused in adding support for creating Python-based plugin managers in libpeas and polishing the Pitivi Plugin Manager. Initially, before the Google Summer of Code started, the Pitivi Plugin Manager was done using the PeasGtkPluginManager. However the design didn’t fit pretty well in the Pitivi Preferences Dialog, so I had to implement it again but in Python. I took as reference the GNOME Builder Preferences window. It is worth to say that I could have used libdazzle, but Pitivi doesn’t use GSettings and instead it uses ConfigParser.

alt text

The second part of my project has been to finish to implement the Developer Console Plugin. This plugin allows developers to do some quick experiments at run-time when executing Pitivi. This is very useful if you are a Pitivi developer. I have actually used it while developing the Pitivi Plugin Manager and this same plugin.

When you enable the Developer Console Plugin, a new menu item will be added to the menu.

alt text

When you click on it, a new dialog will be displayed. The plugin is based on the Gedit’s one. But new features has been added like autocompletion and shortcuts commands. Also it is integrated with Pitivi so it can show preferences in the Pitivi Preferences Dialog. Adding those preferences has allowed me to find some bugs in Pitivi due to deprecated functions and to implement new functions that are usuful to add and remove pages from the preferences dialog.

alt text

I think that one of the most challenging parts of this part of my project has been to implement the shortcuts commands. Currently, the console works redirecting stdout and stderr to a GtkTextBuffer. When you hit return key, the input command is passed eval and if it doesn’t work, then it is passed to exec. If there is an error, the error is put in the GtkTextBuffer with the error color indicated in the preferences dialog. eval and exec, both takes as argument a dictionary. An example of this dictionary may be



namespace = {
    "objA": "banana",
    "objB": "some",
    "objC": "pigs",
    "objD": "fly"
}


When this namespace is passed to eval or *exec, actually, you can use those keys “objA”, “objB”, “objC” and “objD” as variables. So you for example could do somehing simple like:


eval("print(objC + ' ' + objD)", namespace)

And you would get as output:

pigs fly

Okay, nothing complicated with that. But the thing that was a bit complicated to me was that I was adding the internal GES.Timeline object to that dictionary to have it as a shortcut command with the name “timeline”. So if the user just typed timeline in the Pitivi Developer Console plugin, he/she would access quickly to the timeline without going through app.gui.timeline_ui.ges_timeline. The problem was that when the Developer Console was loaded, the Pitivi Timeline had not loaded yet, so if you typed timeline in the console plugin you would get a None value! The same problem occured with other similar objects.

The first idea was to keep it simple and add to the namespace functions instead of variables. So there was a function _get_timeline() as a shortcut command. So the user could do something timeline = _get_timeline(). But to be honest, it was ugly. I talked to Alex about this problem and I think that he possibly had the same idea, because he asked me that the access to the Pitivi Timeline should just as simple as typing timeline. His idea was to load the console when the timeline is loaded. I had the same idea before, but the problem was that if you open a new project in Pitivi a new GES.Timeline is loaded.

I was trying to think in some hack that can lie the user about that the timeline object is actually an object and instead execute a function _get_timeline() which returns the GES.Timeline. The first idea that came to my mind was Python class properties. So I could do something like:


class Shortcuts:
    def __init__(self):
        pass

    @property
    def timeline(self):
        return app.gui.timeline_ui.ges_timeline

shortcuts = Shortcuts()

namespace = {
    "timeline": shortcuts.timeline
}

But obviously that idea wouldn’t work because as soon the developer console loads, shortcuts.timeline would evaluate to None and I was facing the same problem described above. I started to get some distraction, like play SuperTuxKary, play on the PlayStation. Then I walked around the park thinking on a solution. Then an idea came to my mind and to be honest I am not sure why it didn’t come to my mind before. The solution was to override ‘dict’. So I would create a Namespace class that inherits from dict (overriding getitem) and a Shortcuts class containing all the shortcuts commands as methods. Whenever you requested an item from the Namespace, getitem(key) would scan in Shortcuts if there is a method with that key name. If it was there, then it executed the Shortcuts class’ method. I was changing the behavior of a typical dict. The following is the code of the Namespace class and the Shortucts that I called PitiviNamespace.



class Namespace(dict):
    class ShortcutReadOnly(Exception):
        pass

    def __init__(self):
        dict.__init__(self)
        for key in self.get_shortcuts():
            dict.__setitem__(self, key, None)

    @staticmethod
    def shortcut(func):
        """Decorator to add methods or properties to the namespace."""
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        setattr(wrapper, "__is_shortcut", True)
        return wrapper

    def __getitem__(self, key):
        if key in self.get_shortcuts():
            return getattr(self, key)
        return dict.__getitem__(self, key)

    def __setitem__(self, key, item):
        if key in self.get_shortcuts():
            raise Namespace.ShortcutReadOnly("Not possible to override '%s', "
                                             "because shortcuts commands are"
                                             "read-only." % key)
        dict.__setitem__(self, key, item)

    def __repr__(self):
        return "<%s at %s>" % (self.__class__.__name__, hex(id(self)))

    @classmethod
    def get_shortcuts(cls):
        for attr_name in dir(cls):
            attr = getattr(cls, attr_name)
            is_shortcut = False
            if hasattr(attr, "__is_shortcut"):
                is_shortcut = getattr(attr, "__is_shortcut")
            elif isinstance(attr, property):
                if hasattr(attr.fget, "__is_shortcut"):
                    is_shortcut = getattr(attr.fget, "__is_shortcut")
            if is_shortcut:
                yield attr_name




class PitiviNamespace(Namespace):
    """A class to define public objects in the namespace."""

    def __init__(self, app):
        Namespace.__init__(self)
        self._app = app

    @property
    @Namespace.shortcut
    def app(self):
        """Gets the internal Pitivi Main Application object."""
        return self._app

    # ...
    @property
    @Namespace.shortcut
    def timeline(self):
        """Gets the internal GES.Timeline."""
        return self._app.gui.timeline_ui.timeline.ges_timeline

    # ...

    @property
    @Namespace.shortcut
    def shortcuts(self):
        """Gets the available methods in the namespace."""
        print("These are the available methods or attributes.")
        print()
        for attr in self.get_shortcuts():
            print(" - %s" % attr)
        print()

    # ...


These has been the better ideas I had for the moment. The Developer Console Plugin can be refactored using the Python’s module called “code”, althought using it doesn’t skip the problem mentioned above because this module uses eval and exec calls under-the-hood. So it also needs a dict (namespace).

When you start the console you will see the following window with a banner:

alt text

When you type shortcuts, actually this object does not exist! But you are calling to the property shortcuts, so it will executed the decorated function.

alt text

Also, you cannot override shortcuts nor the shortcuts commands (methods decorated with @Namespace.shortcut) because it will raise an exception ShortcutReadOnly wich is handled internally by the console.

alt text

And then you can access whichever of the shortcuts, like the timeline:

alt text

That’s it. I hope you enjoy this post and I hope you can soon try this plugin!

July 06, 2017

Pitivi: Keyframes for transformation properties

With a bit more than a month into the GSOC coding time, my project is almost complete. As a reminder, I was working on implementing a keyframe curve for the transformation properties (which control the positioning and size of a clip) in Pitivi.

For the last two weeks, I’ve been working on integrating the newly added keyframe curve with the undo/redo system, as well as allow values for the keyframes to be specified by dragging the viewer. I’ve also had some battles with a pretty nasty bug which made the app crash all of a sudden. Fortunately, my mentor, Thibault Saunier, took a look at it and managed to crack it, so everything should work fine now.

With my project being close to completion, I thought it would be a good idea to make an extended demo video in which I explain how the new feature works:

I’m looking forward to your feedback or any suggestions on how to make the feature better. I encourage you to keep reading my blog for further updates.

Happy coding!

June 30, 2017

A way to have Custom Effect UI - Pitivi

In my previous post, I described ‘how’ I managed to port nekohayo and thiblahute’s work towards providing an interface for adding custom widgets for effects in Pitivi. In this, I’ll tell you ‘what’ it is that I have done in my first month of Google Summer of Code.

The initial design

How Pitivi auto-generates UI for effects is interesting. For every GStreamer effect in Pitivi, a GtkGrid with the right type of widgets for its properties are packed and to manage changes to these widgets and map back the changes to the effect properties, a DynamicWidget class is created and subclassed for different type of widgets. EffectsPropertiesManager provides and caches UIs for editing effects, while GstElementSettingsWidget is a container class for configuring the effects. It is sad that such a unique infrastructure leads to a rather uniform UI.

Porting nekohayo’s branch I ended up with a light-weight plugin like architecture for having custom widgets for effects. Now, when a GstElementSettingsWidget got created it searched a particular directory to see if there is ‘create_widget’ entry point in ‘foo_effect.py’ files and saved references to this entry point. GstElementSettingsWidget’s setElement method, which previously simply called add_widgets method to generate and show the GtkGrid, was changed

  • to call the ‘create_widget’ entry point if it existed.
  • Otherwise, check if we have a custom UI availabe as a glade file.
  • If all else fails, fallback to the auto-generation.

intial API diagram

Both of these ways of having custom UI utilized the mapBuilder method of GstElementSettingsWidget to map the GStreamer element’s properties to corresponding widgets and wrapping the widgets themself with the standardized DynamicWidget API to control them.

Problems with this design -

  • This ‘forced’ us to have different files for each custom widget.
  • References to the entry points were stored as a class attribute of GstElementSettingsWidget.
  • When Pitivi does have the ‘plugins’ feature, it should somehow, if required, be able to access this custom widget API, which this didn’t allow.

The current design

The solution we came up with was to add a ‘create_widget’ signal to EffectsPropertiesManager and connect a callback which would call the corresponding create_foo_widget method for a ‘foo’ effect. An accumulator stops emission of the signal when we receive a widget, again if all else fails then we fallback to the default handler of the signal which auto-generates the UI for the effect.

current API diagram

This removed rigidity in the API, giving the option of creating custom widgets in single or multiple files, it is left up to the one creating the widget. We are no more storing reference to the create_widget methods for individual widgets. Plugins can connect to the ‘create_widget’ signal to provide enhancements.

Another possible improvement

While making an example custom UI for the ‘alpha’ filter effect I noticed that within the custom widget for the effect, the widgets for individual properties can turn out to be same as the ones auto-generated. Having this additional feature of using a single custom widget for a particular property and auto-generating everything else would prove useful in such cases.

Although the current API for custom widgets is up and running with tests, we at Pitivi want to have stable 1.0 release, as result, the current decision is that Google Summer of Code projects will not be part of this release. Feel free to ping me on #pitivi channel on freenode :) Until next time.

June 23, 2017

Enabling Python support in Libpeas

Libpeas has been for a long time one of the most used libraries to implement plugins in GNOME applications. These are applications such as Gedit, GNOME Videos, GNOME Builder and others. Libpeas' README states:

Adding support for libpeas-enabled plugins in your own application is a matter
of minutes.

However this has not been the case in Python because there is a problem. Although, currently it is possible to write Python-based plugins like many applications currently do like Gedit that has its Python Console, it is not possible to implement plugin systems for applications. The source of the problem resides in the Libpeas' function peas_extension_set_newv, that receives an array of GParameter structures. But GParameter is not instropectible! Due to this problem, there was a large discussion in bugzilla. After some discussions, Emmanuele Bassi say that GParameter should be deprecated and adding a new function with the following prototype:

  gpointer g_object_newv2 (GType gtype,
                           guint n_properties,
                           const char *names[],
                           const GValue values[]);

Some months ago, I decided to implement Emmanuele Bassi's suggestion and finally the patches were merged in master branch, and the function mentioned about was added but with the name g_object_new_with_properties. After that, the same idea could be implemented in libpeas. I have written a new function called peas_extension_set_new_with_properties and peas_engine_create_with_properties. The patch was proposed before but Garret Regier suggested to do some checking and tests. So the new patch is just pending of review and it means that it will be possible to do the following:

extension_set = Peas.ExtensionSet.new_with_properties(engine, Peas.Activatable, ["object"], [a_gobject])

I have tried this function and it works. I have a very simple example that shows how to use Libpeas in Python with this patch. I think that this function will be really useful to all the GNOME community. I think that the function internally should use g_object_new_with_properties but for the while after talking with Garrett Regier (mantainer of Libpeas), peas_extension_set_with_properties will use GParameter internally for the while.

You have a very simple example of how to implement a Plugin System using Libpeas in Python in my github repository. I hope you can soon have this functionality in master.

 

The GInterface problem

According Libpeas' README:

One of the most frustrating limitations of the Gedit plugins engine was that it
only allows extending a single class, called GeditPlugin. With libpeas, this
limitation vanishes, and the application writer is now able to provide a set of
GInterfaces the plugin writer will be able to implement as his plugin requires.

The problem is that although PyGObject allows to import interfaces from libraries written in C like Peas.Activatable, it is not possible to define new interfaces. So we will be limited to use only Peas.Activatable and thus probably extending the application by accessing directly to the GApplication.

I have been investigating the problem in PyGObject. I was reading PyGObject's source code and I got an idea of how to solve this problem. I think that the solution is to add a metaclass to GObject.GInterface and as soon as a new interface is going to be defined, a new GType and a new GInterfaceInfo should be registered. However GObject.GInterface is actually written in C. I wasn't sure, to be honest, how to do that in C, but I knew I could get to a solution by investingating. I was investigating and I knew that the solution was to add a metaclass but I couldn't find too much information about that. So I asked in Python IRC channel. According Ned Batchelder (nedbat),  I was doing "something very very esoteric", but after some discussions I had an idea. I could finally add a metaclass to GObject.GInterface, so I think I am in the right way, but I know it will take time. As this will take a very long time to complete, it does not fall under the scope of my internship. So I will not give too much importance to it after my mentor, the other Pitivi mantainers and I agree to keep it simple. So Pitivi will have only extension sets implementing just Peas.Activatable for the while.

The case of GNOME Builder

I think that a clear example of the use of GInterface to add extension points is GNOME Builder. Gedit is also a good example, but they not have many extension points as GNOME Builder do. I have been reading the source code of GNOME Builder. They define multiple interfaces:

[cfoch@localhost gnome-builder]$ find -name *-addin.c  | head -10
./libide/buildconfig/ide-buildconfig-pipeline-addin.c
./libide/editor/ide-editor-workbench-addin.c
./libide/editor/ide-editor-view-addin.c
./libide/editor/ide-editor-layout-stack-addin.c
./libide/buildsystem/ide-build-pipeline-addin.c
./libide/workbench/ide-workbench-addin.c
./libide/workbench/ide-layout-stack-addin.c
./libide/preferences/ide-preferences-addin.c
./libide/buildui/ide-build-workbench-addin.c
./libide/genesis/ide-genesis-addin.c

For example, you can see that IdeWorkbenchAddin defines the following vfuncs:

struct _IdeWorkbenchAddinInterface
{
  GTypeInterface parent;

  gchar    *(*get_id)          (IdeWorkbenchAddin      *self);
  void      (*load)            (IdeWorkbenchAddin      *self,
                                IdeWorkbench           *workbench);
  void      (*unload)          (IdeWorkbenchAddin      *self,
                                IdeWorkbench           *workbench);
  gboolean  (*can_open)        (IdeWorkbenchAddin      *self,
                                IdeUri                 *uri,
                                const gchar            *content_type,
                                gint                   *priority);
  void      (*open_async)      (IdeWorkbenchAddin      *self,
                                IdeUri                 *uri,
                                const gchar            *content_type,
                                IdeWorkbenchOpenFlags   flags,
                                GCancellable           *cancellable,
                                GAsyncReadyCallback     callback,
                                gpointer                user_data);
  gboolean  (*open_finish)     (IdeWorkbenchAddin      *self,
                                GAsyncResult           *result,
                                GError                **error);
  void      (*perspective_set) (IdeWorkbenchAddin      *self,
                                IdePerspective         *perspective);
};

Having an interface like this one avoids to expose everything by accessing directly from the main application. In GNOME Builder, in libide/workbench/ide-workbench.c a extension set is created so all extensions implementing this interface can do what they are ordered to do in this file by calling the methods of the IdeWorkbenchAddinInterface:

  self->addins = peas_extension_set_new (peas_engine_get_default (),
                                         IDE_TYPE_WORKBENCH_ADDIN,
                                         NULL);

For example, to set the perspective. Different plugins may have different ways to set the perspective.

  if (self->addins != NULL)
    peas_extension_set_foreach (self->addins,
                                ide_workbench_notify_perspective_set,
                                perspective);

And the plugins that implement these interfaces doesn't need to know of other types (like the application). They just care about the perspective (and other objects that can be passed as arguments to its virtual functions).

static void
ide_workbench_notify_perspective_set (PeasExtensionSet *set,
                                      PeasPluginInfo   *plugin_info,
                                      PeasExtension    *exten,
                                      gpointer          user_data)
{
  IdeWorkbenchAddin *addin = (IdeWorkbenchAddin *)exten;
  IdePerspective *perspective = user_data;

  g_assert (PEAS_IS_EXTENSION_SET (set));
  g_assert (plugin_info != NULL);
  g_assert (IDE_IS_WORKBENCH_ADDIN (addin));
  g_assert (IDE_IS_PERSPECTIVE (perspective));

  ide_workbench_addin_perspective_set (addin, perspective);
}

 

Enabling Python support in Libpeas

Libpeas has been for a long time one of the most used libraries to implement plugins in GNOME applications. These are applications such as Gedit, GNOME Videos, GNOME Builder and others. Libpeas' README states:

Adding support for libpeas-enabled plugins in your own application is a matter
of minutes.

However this has not been the case in Python because there is a problem. Although, currently it is possible to write Python-based plugins like many applications currently do like Gedit that has its Python Console, it is not possible to implement plugin systems for applications. The source of the problem resides in the Libpeas' function peas_extension_set_newv, that receives an array of GParameter structures. But GParameter is not instropectible! Due to this problem, there was a large discussion in bugzilla. After some discussions, Emmanuele Bassi say that GParameter should be deprecated and adding a new function with the following prototype:

  gpointer g_object_newv2 (GType gtype,
                           guint n_properties,
                           const char *names[],
                           const GValue values[]);

Some months ago, I decided to implement Emmanuele Bassi's suggestion and finally the patches were merged in master branch, and the function mentioned about was added but with the name g_object_new_with_properties. After that, the same idea could be implemented in libpeas. I have written a new function called peas_extension_set_new_with_properties and peas_engine_create_with_properties. The patch was proposed before but Garret Regier suggested to do some checking and tests. So the new patch is just pending of review and it means that it will be possible to do the following:

extension_set = Peas.ExtensionSet.new_with_properties(engine, Peas.Activatable, ["object"], [a_gobject])

I have tried this function and it works. I have a very simple example that shows how to use Libpeas in Python with this patch. I think that this function will be really useful to all the GNOME community. I think that the function internally should use g_object_new_with_properties but for the while after talking with Garrett Regier (mantainer of Libpeas), peas_extension_set_with_properties will use GParameter internally for the while.

You have a very simple example of how to implement a Plugin System using Libpeas in Python in my github repository. I hope you can soon have this functionality in master.

 

The GInterface problem

According Libpeas' README:

One of the most frustrating limitations of the Gedit plugins engine was that it
only allows extending a single class, called GeditPlugin. With libpeas, this
limitation vanishes, and the application writer is now able to provide a set of
GInterfaces the plugin writer will be able to implement as his plugin requires.

The problem is that although PyGObject allows to import interfaces from libraries written in C like Peas.Activatable, it is not possible to define new interfaces. So we will be limited to use only Peas.Activatable and thus probably extending the application by accessing directly to the GApplication.

I have been investigating the problem in PyGObject. I was reading PyGObject's source code and I got an idea of how to solve this problem. I think that the solution is to add a metaclass to GObject.GInterface and as soon as a new interface is going to be defined, a new GType and a new GInterfaceInfo should be registered. However GObject.GInterface is actually written in C. I wasn't sure, to be honest, how to do that in C, but I knew I could get to a solution by investingating. I was investigating and I knew that the solution was to add a metaclass but I couldn't find too much information about that. So I asked in Python IRC channel. According Ned Batchelder (nedbat),  I was doing "something very very esoteric", but after some discussions I had an idea. I could finally add a metaclass to GObject.GInterface, so I think I am in the right way, but I know it will take time. As this will take a very long time to complete, it does not fall under the scope of my internship. So I will not give too much importance to it after my mentor, the other Pitivi mantainers and I agree to keep it simple. So Pitivi will have only extension sets implementing just Peas.Activatable for the while.

The case of GNOME Builder

I think that a clear example of the use of GInterface to add extension points is GNOME Builder. Gedit is also a good example, but they not have many extension points as GNOME Builder do. I have been reading the source code of GNOME Builder. They define multiple interfaces:

[cfoch@localhost gnome-builder]$ find -name *-addin.c  | head -10
./libide/buildconfig/ide-buildconfig-pipeline-addin.c
./libide/editor/ide-editor-workbench-addin.c
./libide/editor/ide-editor-view-addin.c
./libide/editor/ide-editor-layout-stack-addin.c
./libide/buildsystem/ide-build-pipeline-addin.c
./libide/workbench/ide-workbench-addin.c
./libide/workbench/ide-layout-stack-addin.c
./libide/preferences/ide-preferences-addin.c
./libide/buildui/ide-build-workbench-addin.c
./libide/genesis/ide-genesis-addin.c

For example, you can see that IdeWorkbenchAddin defines the following vfuncs:

struct _IdeWorkbenchAddinInterface
{
  GTypeInterface parent;

  gchar    *(*get_id)          (IdeWorkbenchAddin      *self);
  void      (*load)            (IdeWorkbenchAddin      *self,
                                IdeWorkbench           *workbench);
  void      (*unload)          (IdeWorkbenchAddin      *self,
                                IdeWorkbench           *workbench);
  gboolean  (*can_open)        (IdeWorkbenchAddin      *self,
                                IdeUri                 *uri,
                                const gchar            *content_type,
                                gint                   *priority);
  void      (*open_async)      (IdeWorkbenchAddin      *self,
                                IdeUri                 *uri,
                                const gchar            *content_type,
                                IdeWorkbenchOpenFlags   flags,
                                GCancellable           *cancellable,
                                GAsyncReadyCallback     callback,
                                gpointer                user_data);
  gboolean  (*open_finish)     (IdeWorkbenchAddin      *self,
                                GAsyncResult           *result,
                                GError                **error);
  void      (*perspective_set) (IdeWorkbenchAddin      *self,
                                IdePerspective         *perspective);
};

Having an interface like this one avoids to expose everything by accessing directly from the main application. In GNOME Builder, in libide/workbench/ide-workbench.c a extension set is created so all extensions implementing this interface can do what they are ordered to do in this file by calling the methods of the IdeWorkbenchAddinInterface:

  self->addins = peas_extension_set_new (peas_engine_get_default (),
                                         IDE_TYPE_WORKBENCH_ADDIN,
                                         NULL);

For example, to set the perspective. Different plugins may have different ways to set the perspective.

  if (self->addins != NULL)
    peas_extension_set_foreach (self->addins,
                                ide_workbench_notify_perspective_set,
                                perspective);

And the plugins that implement these interfaces doesn't need to know of other types (like the application). They just care about the perspective (and other objects that can be passed as arguments to its virtual functions).

static void
ide_workbench_notify_perspective_set (PeasExtensionSet *set,
                                      PeasPluginInfo   *plugin_info,
                                      PeasExtension    *exten,
                                      gpointer          user_data)
{
  IdeWorkbenchAddin *addin = (IdeWorkbenchAddin *)exten;
  IdePerspective *perspective = user_data;

  g_assert (PEAS_IS_EXTENSION_SET (set));
  g_assert (plugin_info != NULL);
  g_assert (IDE_IS_WORKBENCH_ADDIN (addin));
  g_assert (IDE_IS_PERSPECTIVE (perspective));

  ide_workbench_addin_perspective_set (addin, perspective);
}

 

June 21, 2017

Pitivi: UI for the Ken-Burns effect

It’s been three weeks since the coding period for GSOC 2017 started, so it’s time to show the world the progress I made. A short recap: I’ve been working on building a user interface which allows simulating the Ken-Burns effect and other similar effects in Pitivi. The idea is to allow adding keyframes on x, y, width, height properties of a clip, much like we are doing with other effects.

Fortunately, my mentor, Thibault Saunier, implemented this feature about 2 years ago, but a rebase of that branch was impossible, as the codebase underwent a lot of changes in the meantime. Even so, having his work as a guideline allowed me to move pretty fast. By now, I’ve implemented an interface that can be used to add and remove keyframes on transformation properties, using the transformation box to specify values at various timestamps. Here is a short demo:

What remains to be done is integrate the newly added feature with the undo/redo system, as well as allow users to specify values at various timestamps by interacting with the viewer. I encourage you to keep reading my blog for further updates. You can also check out my branch.

Until next time!

 

 

June 20, 2017

My story until GSoC 2017

It's almost 9 years I am using GNU/Linux as my default Operating System. The first time I used GNU/Linux was in 2008, when I wanted to crack the password of the computers of my school in order to install and play the games I wanted. So my first contact with GNU/Linux was through OPHCrack. I was absolutely impressed when I could get the password of the computers of my school in less than ten minutes. I was 14 and I think I wanted to be a hacker. Goals changed through time, though.

To be honest, I even didn't know that I was using GNU/Linux. But I started to investigate more and more about it. So I discovered there were many Linux distributions... and I decided to install Ubuntu. I decided to remove Windows, because my goal was to get adapted to Ubuntu as soon as possible. The first version of Ubuntu I tried was Ubuntu 8.04 (Hardy Heron). I had some difficulties, one of the ones I remember the most is that my WiFi card was not recognized. But I could overcome those problems. I noted two things very attractive in the desktop and it was that I could customize my environment as I wanted and that I could add some funny effects to the desktop: Compiz Fusion. Also, in that year I assisted to an event called the "Free Software Freedom Day" which was organized by the community Ubuntu Peru. In that conference my interest about Linux increased, because I knew that whoever could contribute to free software. There was a guy called Diego Escalante who was contributing to the GNOME Foundation in Epiphany and other guy called Nicolás Valcarcel who was a MOTU in Ubuntu. I think that my interest for contributing to Free Software started to grow there.

I started to contribute helping to new users in forums. In 2009, a guy from Uruguay I met in Internet called Diego Romero (who works in Mercadolibre Inc. now) and I created an on-line community called ubuntu-sud.com where we usually post news about Free Software and give some talks through IRC about different topics we has just learn. We were novices but we could help to beginners at least. Sometimes we invited folks that were contributing to relevant free software projects like OpenOffice.org. We got financed by a hosting company to host the website because one of the founders of that company liked our website. It was a good part of my life.

Logo of the old ubuntu-sud.com

Diego and I started to get busy because each of us had to prepare to study in the University and ubuntu-sud.com was shut down. I was in the academy but when I got some time I attended events about FOSS. In the university I got joined to the community Linux IDES and I talked to with a guy called Marco Villegas who I already knew in an event in another university. He told me that he had participated in the Google Summer of Code (aka GSoC) in Drupal and that motivated me to participate, too. By that time, I liked to contribute with wallpapers and skydomes for Compiz Fusion in GNOME-LOOK.ORG. I always wanted to contribute to GNOME, so I started to put more effort to investigate how to develop applications with PyGTK.

An old wallpaper I did when I started to use GNU/Linux

In 2013, I applied for a GSoC in Pitivi, but I wasn't accepted. In 2014, I applied for the GSoC to develop a new feature to allow Pitivi to support Image Sequences which is useful when film makers wish to create stop-motion movies. Although this feature was not merged, probably, due to many discussions about the underlying GStreamer plugin, I tried to persist even after the GSoC to satisfy the  suggestions and petitions of the other GStreamer folks. My last patch was ready but nobody tried it. Luckily, Aaron Boxer has shown his interest on this plugin. After that, as I said I have kept contributing to GNOME, mostly in Pitivi and lately in GObject introducing a new function g_object_new_with_properties that is introduced to deprecate GParameter. This function should be useful in Libpeas, for example. The problem with GParameter is that it wasn't introspectible. So you could do in Python something like:

from gi.repository import GObject
obj = GObject.Object.new(ObjClass, ["prop1", "prop2", "prop3"], [gvalue1, gvalue2, gvalue3])

 

This year, 2017, I have been accepted for the second time to the Google Summer of Code 2017. My project is to implement a plugin system in Pitivi and a set of 3 plugins. My mentor this year will be Alexandru Balut. If everything goes as I expect, I think that Pitivi could have the Plugin Manager merged in master before the middle of June. In an other post I will detail what I have done so far. The first stage of the project consists basically in adding a patch to Libpeas and create a plugin manager dialog in the Pitvi preferences dialog. The second stage will be to add a Developer Console plugin based on the Gedit's Python Console and the other stages will be to create a plugin to add markers to the Pitivi Timeline each ten seconds and a plugin to generate a movie from images automatically. In case time remains, I will be developing as much plugins as possible.

 

June 19, 2017

Not rebasing an old feature branch

Ultimately, my aim was to provide an interface, at the code level, for developers (rather designers) to improve the GUI of video effects. GStreamer effects are very beautifully handled in Pitivi, the main focus was to use this existing underlying infrastructure on top of which a way of easily adding custom UI for effects had to be setup.

One of the ways of stopping ‘duplication of effort’ in Open Source projects is to document everything, even failed/blocked attempts. Thanks to nekohayo (previous maintainer at Pitivi) opening task T3263, his work from 2013 towards providing such an interface is now up and running again.

Unless you want to preserve commits, rebasing a very old feature branch, that is not yours, is pointless. I did not want to waste time resolving merge conflicts in then unfamiliar code. Following a bottom-up approach, I started working on top of the current Pitivi master integrating the old code into it, step-by-step, one function at a time. Compiling and understanding the errors and then fixing them. I found this approach to be rather systematic and I think it is much faster since you start porting the code as you read it.

After I had completed porting, it was a first time for me hitting a git-core bug regarding support for multiple authors on a single commit. I simply settled with the temporary solution of using

Co-authored-by: Some One <some.one@example.foo>

in my commit messages.

Finally, at the end of all this I was able to get an example interface for the alpha filter built using glade to work via the above mechanism.

Glade UI File

Working UI

The exact API will, most likely, undergo change. I will describe it in detail in my next post in a couple of weeks. You can checkout my work so far D1744 and D1745, feel free to ping me on #pitivi on freenode :)

June 07, 2017

GSOC 2017: And so it begins

Hey everyone,

This is the beginning of what seems to be a really exciting summer. Why, you ask? Well, it’s because I’m going to spend most of it as a true GNOME contributor, working on a really cool project.

But let’s start from the beginning. Only 4 months ago, I was making my first steps as a contributor in the open-source world. One of the first things I discovered is how amazing and helpful the GNOME community is. I started by trying out a lot of GNOME apps and looking through the code behind them and that’s how I discovered Pitivi, a really great video editing solution. After my first patch on Pitivi got accepted, I was really hooked up. Fast forward a couple of patches and now I have the opportunity and great pleasure to work on my own project: UI for the Ken Burns effect, after being accepted for Google Summer of Code 2017. In this amazing journey, I’ve had some great mentoring: special thanks to Thibault Saunier (thiblahute), who is also my current mentor for GSOC 2017, and Alexandru Balut (aleb), who helped me along the way.

The goal of my GSOC project is to allow Pitivi users to create effects based on the positioning and zoom of their clips (like the Ken Burns effect). More precisely, when this project will be completed, Pitivi will support adding values for the position and zoom of the clip at various timestamps and smoothly transitioning between these values.

I’m expecting a lot of fun while working on this project and I encourage you to keep reading my blog for further updates. 🙂

Happy coding!

May 11, 2017

Three GSoC students hack on Pitivi this summer

We’re excited to have three students that will contribute to Pitivi this summer. Congratulations, Fabián Orccón, Suhas Nayak and Ștefan-Adrian Popa!

  • Fabián already had an internship with us two years ago. He’ll focus on a plugin system with great documentation for video hackers, and a first plugin for inspecting the timeline of the currently opened project in a Python console (T3193).
  • Suhas will focus on a modern color correction UI for the corresponding GStreamer plugin, and lay the path for similar changes to other effects (T2372).
  • Ștefan will focus on allowing users to apply Ken-Burns effects by manipulating the placement and zoom of the clips on the viewer (T7340).

You can follow the linked blogs or subscribe to the Phabricator tasks to stay up-to-date with the progress, or keep an eye on the Pitivi planet. Feel free to make suggestions about these projects on the corresponding tasks, or chat with us about them in our IRC channel. The official start of the coding period is May 30.

Besides mentoring for GSoC, the Pitivi maintainers are busy ironing out the last stability problems we’re aware of. We made great progress, expect version 0.99 sometime soon, followed by some more testing towards 1.0!

Thanks to Google for GSoC and to the GNOME Foundation for allowing us to have these projects under their umbrella this year!

May 06, 2017

Looking forward to a summer of bliss

As much as open source is about free and open software, it is also about community and GNOME is one big family! I started contributing to GNOME Pitivi, a video editor, in late January. Thanks to the extremely helpful current maintainers, Alexandru Băluț (aleb) and Thibault Saunier (thiblahute) I was able to quickly get started despite all of my university proxy related issues (I should get a VPN already!). I explored the codebase, made a few changes here and there fixing a few beginner level bugs.

This post is my first report on my Google Summer of Code project (yup! I got selected)

This summer, I will be improving Pitivi giving it the ability to add custom UI for video effects and also make a Color correction interface with three color wheels to improve user interaction and productivity! Mathieu Duponchelle (previous maintainer) will be mentoring my project. The only interaction I’ve had with Mathieu is over one of my failed attempts at solving a waveform bug :P. I look forward to learning a lot from him.

Stay tuned for updates regarding my summer of code!

January 21, 2017

Inside gobject_new

Sometimes when you do not have nothing to do, you can go to Netflix to watch your favorite movie, or you may read GObject source code. I have been reading how g_object_new works and I have decided to explain about it what I have understood so far.

First, we are going to remember the prototype and how we create a GObject.

This is the prototype of g_object_new:

gpointer
g_object_new (GType	   object_type,
	      const gchar *first_property_name,
	      ...)

So in order to create a GObject of the type G_TYPE_TEST we can just do something like:

GObject *my_object = g_object_new (G_TYPE_TEST, "dummy1", 100.0, "dummy2", 200, NULL);

This line creates a Detroit Red Wings jersey mens gobject setting the properties values of the property called “dummy1” to 100 and the value of the property called “dummy2” to 200. What does happen here?

When you defined the G_TYPE_TEST object, you had to define its properties. To do so you must have called g_object_class_install_property function.

  g_object_class_install_property (gobject_class,
				   PROP_DUMMY1,
				   g_param_spec_int ("dummy1",
						     NULL, 
						     NULL,
						     0, G_MAXINT, 0,
						     G_PARAM_CONSTRUCT | G_PARAM_READWRITE));

GObject has a “pool” of “properties” that are “ready to use”. What this piece of code do is to tell GObject that a property called “dummy1” that belongs to the class of G_TYPE_TEST should be added to the “pool”.

When you call g_object_new, it will set the values property per property. First it will lookup in the “pool” if the property “dummy1” exists for the class of G_TYPE_TEST. Then the following may happen:

  1. If the property does not exist (was not installed), a critical error should be shown:

    “%s: object class ‘%s’ has no property named ‘%s’”

  2. If the property is not writable (it has not the type G_PARAM_WRITE or G_PARAM_READWRITE set), then a critical error will be shown

    “%s: property ‘%s’ of object class ‘%s’ is not writable”film download

  3. If the property has been specified twice

    “%s: property ‘%s’ for type ‘%s’ cannot be set twice”

If whichever of the cases described above occur, the object will be created, but the rest of the properties will not be analyzed. However, if none of the above cases present, as this example is the case, g_object_new will internally create a GObjectConstructorParam which is just a structure:

struct _GObjectConstructParam
{
  GParamSpec *pspec;
  GValue     *value;
};

After creating this structure by setting the “pspec” to the parameter specification that was taken from the pool and setting tthe value to a new created GValue containing the value of 100 (in the example), this GObjectConstructParam will be put in an array. g_object_new has an array for each property (or parameter). g_object_new uses by default an array of size 16 which means that GObject sees more likely that GObject classes doesn’t have more than 16 properties, but if there cheap jerseys are more, it will increase the size of this array.

After populating the array for all the properties passed to g_object_new, properties are not set yet. When properties will start to be set (throughout an internal function called object_set_property), transformations between values will be set. So for example, you can pass a float value, but the property is defined as an integer, actually.

An internal function called g_object_new_internal will be called. First, this internal function will create an instance (using g_type_create_instance). Then only the construct properties will be set, in this case “dummy1” because it was defined with G_PARAM_CONSTRUCT. After construct properties have been set, the other properties will be set. Setting a property as was mentioned, involves a transformation between value types. But not only that, GObject keeps a notification queue ‘notify_queue’, so whenever a bunch of properties are set, this queue is locked in order to add the properties to this queue using the function g_object_notify_queue_add. After all the properties has been set, the queue is unlocked and the object is returned.

December 07, 2016

Pitivi 0.98 — Getting there

This is another release focused on fixing bugs and improving stability.

Improved timeline

We switched our official build to use GTK 3.22 and the framework did not like how we were using it, spamming us with warnings in the console. We fixed those and improved the timeline in the process and added more unit tests.

It was quite a journey. Initially, the GTK Inspector was useful to figure out which widgets the widget IDs in the warnings identified. Then we had to go back between the GTK documentation and the #gtk+ IRC channel until we figured out we were changing the size of some containers in their do_draw methods, which was not good.

Accelerated development

Taking advantage of an opportunity, with the last money from our coffers (the remaining 2014 fundraiser donations and the GSoC mentor stipends) we hired Alexandru Băluț, a long-time Pitivi contributor, so he can focus better on fixing issues blocking the 1.0 release. Alex worked on Pitivi in Oct, Nov, and will allocate more time in Dec 2016. Thanks again to everybody who donated!

Customizable keyboard shortcuts

Jakub Brindza, our GSoC 2016 student, finished the customizable keyboard shortcuts feature. See how it works in the screencast below.

Supported muxers and encoders

In the previous version, 0.97, we picked a set of supported muxers, audio encoders, video encoders, added integration tests for them in GES, and changed the rendering dialog to show very clearly the ones which are unsupported.

1.0

See what’s left to do for 1.0 in the 0.99 and 1.0 columns in Phabricator. If you want to help in any way, come to our IRC channel. We prepared a nice list of tasks suitable for newcomers. These are good also for students interested to apply for a GSoC with us.

The build system has been ported to meson, no more autogen! 😉

September 26, 2016

Making Viewer UIs for Pitivi

Being someone who has already experimented with two transformation box approaches for Pitivi in the past, maintainers thought I might be the right person to do a modern one.

Creating a user interface for a video transformation requires three things:

  • The implementation of the transformation
  • A way to draw the widgets over the viewer and
  • Mapping the input to the reverse transformation

The transformation

First of all the implementation of the transformation, which is in our case scaling and translation, is currently done by GES.UriSource, calculated on the CPU. In the first Pitivi transformation box I did in GSoC 2012 this was done by the notorious Frei0r plugins from GStreamer Plugins Bad, which is also a CPU implementation. In the second version this was done on the GPU with the gltransformation element I wrote for GSoC 2014.

A method to draw widgets over the viewer

In Pitivi’s case, the viewer is a GStreamer sink. In all three versions rendering of the overlay widgets was done by Cairo, but it was done differently for all three implementations, since they all used different sinks.

 

 

2012: The first one used a hacky solution where the sink and cairo drew in the same Gtk drawing area, acquired for GStreamer with the Gst Overlay API. Many Gtk and GStreamer devs wondered how this worked at all. This and Pitivi switching to more modern sinks was the reason why the first version of the box didn’t stay upstream for long.


lubosz-the-magician

 

2014: Still using Gst Overlay API, but this time with the glimagesink. The cairo widgets are rendered into OpenGL textures and composed in the glimagesink draw callback in the GStreamer GL context. Worked pretty smooth for me, but didn’t provide a fallback solution for users without GL. Clearly an approach for the future, but how about something solid?

screenshot-from-2016-09-26-16-04-40

 

2016: Now we have the almighty GtkSink in Pitivi. It is a Gtk widget and overlays can be added via Gtk Overlay. The sink is also exchangeable with GtkGLSink, which uses a GStreamer GL context to display the video texture and also can use GStreamer GL plugins like gltransformation without needing to download the GPU memory with gldownload. Cairo rendering now can be easily added over GStreamer sinks, yay.

screenshot-from-2016-09-26-16-03-27

 

Linking the UI with the components doing the transformation

The mapping of the input from the UI to the transformation is clearly dependent on the transformation you are using. In the 2012 version I needed to map the input to frei0r^-1. In 2014 I used an OpenGL Model-View-Projection matrix calculated in Graphene, which could also do rotations and 3D transformations (we have a z-axis, yay).

The 2016 implementation uses the inverse transformation for the GES.UriSource transformation, which is done by the GStreamer elements videomixer and videoscale. Of course things like keeping aspect ratio, maintaining limits and transforming Gtk widget coordinates to the transformation’s coordinates are part of this 3rd ingredient.

 

Extensibility

The new transformation box fits great with Pitivi by making clips selectable from the viewer, so you can manage multiple overlapping clips quite easily. But the best part of this implementation may be its extensibility. I already made two overlay classes, one for the normal clips which uses a GES.UriSource transformation and one for title clips aka GES.TextSource, which is using different coordinates and different GStreamer plugins. In this fashion other plugins can be written for the Pitivi viewer, for example for 3D transformations with gltransformation. Or you could do crazy stuff like a UI for barrel distortion etc.

Clone the code and contribute! 🙂

 

If you have any questions about this ask me. I’m lubosz on Freenode IRC.

August 23, 2016

GSoC with Pitivi

Customisable keyboard shortcuts for Pitivi
Google Summer of Code 2016 Summary

Over the summer I have been working on customisable keyboard shortcuts for Pitivi. Below, I am including an easy-to-read and concise summary of every bit of work I have done over the last three months.

The summary of all the code I have written can be found at:


The work above contains these key elements:
  • Refactor the code to use Gtk.Application.set_accels_for_action() in order to create the base for customisation.
  • Use the Gtk.ShortcutsWindow widget to allow the user to preview the keyboard shortcuts.
  • Refactor Pitivi’s Preferences dialog to use Gtk.StackSidebar.
  • Add keyboard shortcuts section to the Preferences dialog with a selectable list of all the shortcuts in the application to allow customisation.
  • Implement saving of shortcuts to an external configuration file for the case when a user changes the default shortcut settings.
  • Implement loading of saved accelerators from the configuration file and ignore the default accelerators when this happens.
  • Create a ShortcutsManager class dedicated to storing and handling of the accelerators. It is used for registering keyboard shortcuts in appropriate categories and their consequent management.
  • Fully support the ShortcutsManager class with tests, mostly using the Mock library.
  • Implement the customisation of accelerators via a separate dialog window opened after user's selection in preferences.

Blog posts describing all of the aforementioned work can be found at:


At the very end, I would like to specifically thank Alexandru Bălut for his great mentorship, valuable pieces of advice, willing approach towards answering my questions and, most importantly, for making me a better software developer.

August 21, 2016

GUADEC 2016, laptops and tablets made to run GNOME, surprise Pitivi meeting

I went there for the 2016 edition of GUADEC:

2016-08-17--21.35.31

I arrived a couple of days early to attend my last GNOME Foundation board meeting, in one of the KIT’s libraries. The building’s uncanny brutalist architecture only added to the nostalgia of a two years adventure coming to an end:

2016-08-16--17.44.34

Then…

And so I made a new talk proposal at the last minute, which was upvoted fairly quickly by attendees:

2016-08-12--15.03.12

The conference organizers counter-trolled me by inscribing it exactly like this onto the giant public schedule in the venue’s lobby:

2016-08-12--16.08.16

The result was this talk: Laptops & Tablets Manufactured to Run a Pure GNOME. Go watch it now if you missed it. Note: during the talk’s Q&A session, I mistakenly thought that Purism‘s tablets were using an ARM architecture; they’re actually planned to be Intel-based. And to make things clear, for laptop keyboard layouts, Purism is currently offering US/UK, which are different physical layouts (different cutting etc.).

Also relevant to your interests if you’re into that whole privacy thing:

In my luggage, I carried ~20 kilograms of the Foundation’s annual reports. Some folks were skeptical and thought I should “only bring a few of them, people aren’t usually interested in the annual report.” Well, they were dead wrong: within one afternoon, the annual reports “sold out” like hotcakes. See also my tandem lightning talk (at the 29mins mark) to get a glimpse of how much work we put into designing the new annual report this year. Also, if you took one of them at the conference, remember: they’re precious little works of art and a powerful tool to convince people to become contributors or sponsors to support GNOME, so make sure to use them towards that goal!

I was very happy to see Mathieu and Alexandru from the Pitivi team deciding to attend at the last minute, even if it was just for one day. We spent time with Jakub Steiner discussing his workflow and wishlist for a “perfect” video editor:

2016-08-15--17.05.53Pitivi makes people smile!
Left to right: Alexandru Băluț, Jakub “Skywalker” Steiner, Mathieu Duponchelle.

I took a handful of photos of the BoFs and uploaded them to my gallery for GUADEC 2016. Licensed under the Creative Commons “by attribution” 4.0 as usual, so that the GNOME Engagement team can use them for GNOME promotional materials if needed. Make sure you do the same and list yours in here.

The Flatpak BoF sessionThe Flatpak BoF session

Overall, this GUADEC was one of the most well-organized ones I’ve seen in years. I was floored by the amount of efforts and planning the local team put into this. They really deserve some kudos! Everything ran smoothly on the surface (I know that in such events there will always be odd situations happening here and there, but they dealt with them so efficiently that they were invisible). The team had a professional-grade two-way radio system to coordinate, a car and trailer to carry stuff around every day, made and reused food (pro-grade cafeteria counter metal containers = genius), a lifetime supply of IKEA mugs that got washed and reused frequently, tons of snacks, managed to pull in great sponsors even at the last minute, put signage in various parts of the city to guide people to the venue, had huge quantities of tasty dead animals (and plants) to eat at a very successful barbecue event, got an icecream vendor to come to the venue, and even filled up a pool and beanbags, for pete’s sake!

Thanks to the the Chaos Computer Club for providing a flawless live video streaming, recording and publishing service. Very rarely did we have GUADEC videos published in a timely fashion in the past, let alone streamed live and with proper laptop video output capture as well as proper sound mixing. This is fantastic.

I should mention the closing night’s event in the biergarten, with sponsored drinks and food by our friendly GStreamer experts Centricular, a very nice gesture that was well appreciated by everyone.

2016-08-15--19.23.28Survivors at rest in the snacks bunker on the last day of the BoFs

Thanks to everybody involved to make this event a success, and thanks to the GNOME Foundation for making it possible for me to attend.

gnome sponsored badge shadow

August 02, 2016

Save. Load. Reset. Shortcuts get new functionality.

In the recent days, I have been working on implementing the functionality behind saving and loading of custom shortcuts. Moreover, Pitivi's save logic can store the shortcuts in an external file, which holds the user's preferred settings. This file's contents can then be loaded and used to fill the Shortcuts Window - if the file exists. If it does not exist, Shortcut Manager class will simply use the default accelerator settings.

Secondly, I made a step forward in implementing the reseting functionality for the shortcuts. Whenever a user has customised shortcuts, she'll be able to reset it to Pitivi factory settings by a single click of a button. The important point here is that the back-end functionality for this button has just been implemented and so we are ready for putting it all together to some nice UI. It was important to define the logic of storing the default shortcuts, so that we have them accessible at any time, even if user decides to change all of them. Thanks to this, we are ready for reseting the shortcuts at any point in time.
Users will be able to reset either a particular action's accelerators, or reset them all by a single click.

Furthermore, I was able to practice unit testing a lot. For all the pieces of work - save, load and reset functionality - I provided unit tests with fairly extensive use of mock library. I learnt a lot through this, since I have to admit at the very beginning the idea behind what kind of tricks mock is actually doing behind the scenes was hard to understand for me. By now however, Pitivi has a code of good quality for all the work I have done (Alex thanks for the excellent reviews) supported by relevant tests.

So what is next?
Over the course of this and the next week, I will be concentrating on the UI primarily and bringing all the little pieces of work I have done together. Hopefully by the end of this week, I will be able to present an implemented and working UI for the Preferences shortcuts section and also add the reset buttons to reset one or all shortcuts.

July 18, 2016

Get Pitivi directly from us with Flatpak

Distributing apps as packages (deb, rpm, etc) is problematic. For example, the Pitivi package depends on the GTK package and Pitivi 0.95 broke in the distributions which updated to GTK version 3.20, because of the incorrect way we were using a virtual method. This is not the first time something like this happens. To avoid the slippery dependencies problem, two years ago we started making universal daily builds. They allowed everybody to run the latest Pitivi easily by downloading a large binary containing the app and all the dependencies.

A few problems still remained:

  • It was complicated to set up the Pitivi development environment. We had a huge script for setting up the development environment and new contributors always had problems. We tried to reuse the daily builds for preparing a development environment but it was hacky and we failed to make it work correctly.
  • Users were notified about available updates through a custom mechanism and updating was not ideal, requiring to download a huge binary blob.
  • Maintaining the AppImageKit based bundle required following many dependencies (security) updates and maintaining the build for them (even though we were sharing the burden with the whole GStreamer community, as we were using the Cerbero build system).

Recently Flatpak got our attention as it set out to fix these problems. Flatpak’s sandboxing allowed us to create a nice development environment. Our new dev env script reuses the one which flatpaks Pitivi so we got rid of the old ones. Also, Flatpak allows the user to only download binary diffs for updates. Moreover, the Gnome community already provides builds for their SDK and Runtimes, which contains almost everything we need for Pitivi; now, we only have to build a few libraries, which makes it much simpler for us to maintain the new bundles.

We’re enthusiastic about Flatpak. Jakub Steiner summarized Flatpak’s advantages very nicely:

Flatpak aims to solve the painful problem of the Linux distribution—the fact that the OS is intertwined with the applications. It is a pain to decouple the two to be able to:

  • Keep a particular version of an app around (and working, our note), regardless of OS updates. Or vice versa, be able to run an uptodate application on an older OS.
  • Allow application authors distribute binaries they built themselves. Binaries they can support and accept useful bug reports for. Binaries they can keep updated.

For now you need to use the command line to install Pitivi with Flatpak. In the near future, it should be trivial for you to install and manage our Flatpak build of Pitivi in your favorite software manager. GNOME Software is a good example.

 

 

July 11, 2016

Meet me halfway [of GSoC with Pitivi]

Hi everyone, it's been a while but I am back now with a short update on my work on Pitivi's customisable shortcuts.

Without too many words, this is the state of the shortcuts window after my recent works to add some forgotten shortcuts:









However, more interesting things happened on the back-end side of Pitivi.

I refactored the shortcuts logic, preparing everything for the implementation of shortcuts customisation. From now on, instead of the ShortcutsWindow class which originally handled both populating the window as well as gathering the data, Pitivi now features a dedicated ShortcutsManager class besides the ShortcutsWindow class.
This way, I could reach a more straightforward and less cluttered organisation of code with one class used only for displaying of the window while the other is handling data gathering and its storage.

This important step allowed me to move forward and start working on loading and saving of the shortcuts preferences. I am aiming for an implementation where by default, all shortcuts will be set from the code, however, once a user changes even a single shortcut, all of them will immediately be stored in an external configuration file which will be loaded from that point onwards and the default shortcuts will be ignored.
I decided to apply TDD for this part. I started with writing the tests and in the upcoming days I will be taking care of defining the loading and saving of shortcuts logic.

I think it will be very exciting, I can't wait to see the customisation working already and this is a very important step so I want to do it the best I can so that my progress increases every day and Pitivi users can enjoy shortcuts customisation as soon as possible.

June 30, 2016

Pitivi 0.96 — Cogito Ergo Proxy

Besides the usual cleanup and bug squashing, this release brings a fundamental feature which greatly improves the edit experience. Now you can edit and render a video project with any video files with great accuracy, thanks to proxy files.

Proxy editing: fast and accurate editing with any video format

The harsh reality of this world is that there is only a limited set of formats that really work well for video editing. Without those, rendering a project could have been inaccurate at times*. The user experience degrades when using container formats not designed for fast & accurate seeking. For example, seeking a video format where the keyframes are followed by one or more inter-frames (such as in VP8, H.264) is often slow.

To provide the best experience, we decided to give you the ability to seamlessly work with media formats suitable for video editing. This is accomplished with what we call “proxy” files. Other video editors advertise the use of downscaled proxy files which, besides the improved reliability, also provide better performance when the system is not powerful enough to handle high-quality video files in real-time.  We do not cover the the downscaled proxy files case yet—that’s planned for post 1.0. For now, our proxies are high-quality proxies intended to be used instead of the original, when editing and also when rendering the project.

Oh, and since we’re so smart, we now also generate the audio waveforms and filmstrip thumbnails at the same time as we are processing proxies. Super efficient.

So what is the difference between an original and its “proxy”? The proxy is a slightly degraded but easier-to-work-with version of the original:

gandalf-the-grey-fellowship-of-the-ring-gandalf-35160271-900-380.jpg

gtttrider6.jpg

Okay, okay, we might be stretching the analogy a little bit, but you get the picture.

When are proxies needed for stability?

The whitelist below shows the formats we officially support—which can be used safely without proxying them. For the rest, we recommend using proxy files to guard against bugs in the decoders and demuxers. Depending on how popular other formats get, we will consider officially supporting them. The intention is to keep the list short to avoid spending too much time on decoders and demuxers.

At the moment, the whitelist is comprised of the following:

  • Containers: QuickTime, Ogg, Matroska, WebM
  • Video codecs: H.264, MJPEG, VP8, Theora, raw
  • Audio codecs: Opus, MP3, Vorbis, FLAC, raw

How does it work?

When you import an asset with an unsupported format, it is by default transcoded using a codec suitable for video editing. You can disable or force the proxy creation on a per-asset basis, when you import or later at any time. Finally, when rendering, you can specify whether to use the proxies or the original files. You are always in control.

image07.pngOptions when importing files
Options for already imported video files
image08.pngOptions when rendering a project

As seen in the screenshots above, the state of an asset’s proxy is shown by an icon in the bottom-left corner of the asset thumbnail, in the Media Library. The icon can be one of:

  • none    The original is used.
  •         The proxy is being created by transcoding the asset.
  •         The proxy is ready and is used automatically.
  •         The proxy creation failed and the original is used.

The main disadvantage of using the intermediate proxy files for rendering is that some quality is lost when transcoding, but this is not noticeable in most cases. Other than that, transcoding the originals takes a bit of time and they take some disk space (around 10 times more for H.264 content, for example). In practice, we think that using proxy files is the best option. You decide what works for you but take into account what is considered safe and officially supported, and what is not.

It was very important to pick a codec that preserves the visual quality of the originals, so that final renders can be done out of the intermediate proxy files with no perceived quality loss. The other requirement was that seeking should be fast, meaning it had to be an intra-frames-only codec, where a frame is encoded and decoded independently of any other frame. Currently Pitivi uses MJPEG or ProRes for the proxy files, depending on which is available on the system.

For now, the audio is transcoded using Opus, even though it’s a lossy format, because the codec is very good. We’ll most probably switch to FLAC when it will be more supported in GStreamer because it loses no quality and has a pretty good compression ratio.

Scrubbing the timeline easily

Currently the user is able to select, move and edit clips by using the left mouse button. This is exactly how a user expects to interact with a GTK UI and it works very well. In addition to that, when clicking using the left mouse button, a seek is performed and the playhead is moved to that position. Some users were annoyed by this combined behavior so we added an option for disabling seek on left-click, but this was not enough.

Inspired by Blender’s different functionality assignation for left and right mouse buttons, we added the ability to seek by right-clicking. Now you can quickly and safely scrub on the timeline as well on the ruler using the right mouse button. Since Pitivi did not provide a context menu when right-clicking on the timeline, it was easy to make this possible. Try it out and let us know what you think. More details on the reasoning that led to this are visible in T3158.

Transformation box

The transformation box is back, thanks to Collabora and Lubosz Sarnecki! This is the third implementation of the transformation box, first one being hacky and second one being available only for users with GL video cards. Now it works great due to the almighty GtkSink, GStreamer’s latest GTK widget for displaying video.

The new transformation box fits great with Pitivi by making clips selectable from the viewer, so you can manage multiple overlapping clips quite easily. But the best part of this implementation may be its extensibility, an example being the module for the title clips.

image01.pngTransformation box around Alex’s parents’ cat’s best friend

Project settings: letting the computer figure things out

At least one of our contributors felt intimidated when he first saw the project settings dialog which used to show up when creating a new project. The project settings define how you preview the project while editing. You might want for example to choose a small video size if your computer is not very powerful, then at render time change that to get the best quality. These settings can be changed safely at any time.

The question was whether showing that dialog is really necessary at that point in time. Well, not really. Now, when you create a new project, some default values are set and then when you import the first video file, its properties are transposed to the project settings.

The logic is thus: either users don’t really care about the project settings and the “Project Settings” dialog showing up when creating a new project overwhelms them, or the user is an experienced videographer, in which case they’ll know when they need to change the project settings and where to find them. A very nice touch is that when the project settings are changed automatically, an infobar appears, so the user has the chance of opening the project settings and correct them if need be. More details in T3161.

image06.pngInfobar when the first clip is imported

New project settings and rendering UI

The widgets in the project settings dialog and the rendering dialog were split into multiple tabs, to fit on 1024×768 screens. Unfortunately this required clicking the tabs to see or edit the settings. Moving the eye is faster than clicking so we looked into this and came up with a solution to get rid of the tabs and keep the dialogs as small as possible.

The preset selection UI is now composed of a ComboBox plus a MenuButton. This way the preset selection UI takes extra vertical space instead of extra horizontal space. We find it works pretty good. More details about how it works and more screenshots in this doc.

image09.pngThe Project Settings dialog
image03.pngThe Render dialog

Keyboard shortcuts window

Jakub Brindza joined us as a GSoC student. The first step of his project is already done, a brand new keyboard shortcuts window built dynamically, to be able to support custom shortcuts. Next will be allowing users to customize the keyboard shortcuts.

image04.pngThe Keyboard Shortcuts window

Other noteworthy changes

  • The user manual has been updated to reflect the changes since we switched to the headerbar, about one year and a half ago.
  • The undo/redo removal has been undone.
  • We switched from AppImage to Flatpak to distribute our own builds. A big advantage is that due to Flatpak’s sandboxing we can use it for the development environment while previously we needed a separate complex script to take care of that.

* There was a very high chance of ending up with artifacts at the start of a clip with an inpoint.

June 21, 2016

Pitivi featuring Gtk.ShortcutsWindow - phase 1 complete!

After nearly a month of work on Pitivi, the project has moved forward by quite a bit. Pitivi now contains the all-new Gtk.ShortcutsWindow which is build up dynamically from various places across the app. 

First of all, reaching the current state would be impossible without refactoring the way accelerators were added to the Pitivi app. The documentation for this is not very detailed, however after some research with Alexandru Băluț, we found a solution in dropping the previously used Gtk.Application.add_accelerators() in favour of the current Gtk.Application.set_accels_for_action(). This created the basis for achieving the next goal, the customisation.
At this point also, I believe it would be appropriate to thank this way to lazka for the excellent work done on Python documentation as well as providing hints on how to build the shortcuts window dynamically. Secondly, Christoph Reiter deserves a credit since his implementation of how to build up shortcuts window was an excellent starting point for me, too, to better understand the structure of the desired implementation. 
For a preview of my implementation of shortcuts and shortcuts window utilising them, take a look at the following commits of mine:

Link 1: Refactoring to Gtk.Application.set_accels_for_action()

Link 2: Dynamic build-up of the Shortcuts window

The importance of this implementation is in the fact that now my steps are moving on to implementing customisation of shortcuts via Preferences, invoking a change in the Shortcuts Window after each customisation of any shortcut by the user. This dynamic build-up of the window will enable us to make sure users always have the most up-to-date details of their preferred shortcuts settings always at a hands distance. The Shortcuts Window is available from various places across the app - immediately from the welcome wizard window, from the menu inside the app, as well as simply by pressing Ctrl + ? or Ctrl + F1.

This way, users will never have to struggle with how to become more effective at using Pitivi. All the information is neatly presented right in the app, no need to go anywhere else.
Below is a small sneak peek of the newly-implemented feature:


Pitivi shortcuts window contains 2 pages of well-described shortcuts, natively supporting search too (courtesy of Gtk implementation :) )


Along the way, the code behind Pitivi gets some minor refactoring every now and then. I learnt a lot about the way inheritance, overriding, tests and other cool features work in Python, which is excellent as it enables me to learn a lot of interesting stuff.

Next on schedule is customisation, but prior to that, I'm refactoring the Pitivi Preferences window to utilise Gtk.StackSidebar for neat, modern organisation of all the current, and soon-to-be-added settings - the shortcuts settings - for the app. 
Stay tuned!

June 15, 2016

Working for Collabora Multimedia :)



This month is my first month working (part time) for the multimedia team at Collabora. I think you all know about this company which is specialized in open source softwares particularly in Gstreamer and all majors Gnome/Freedesktop technologies.

So I am now working on GStreamer related technologies and in particular on PiTiVi to make it rock more and more!

I am very glade to be part of this team and am looking forward the good time I am going to have hacking as a multimedian :)

May 24, 2016

Customisable shortcuts. Enhanced experience. Ctrl + P[ itivi ]

My second Google Summer of Code participation has just begun and I am very excited to share some of my new goals, plans and ideas.

First of all, I am challenging myself to try to keep my posts concise, on-topic and compelling as I want to brush up on the art of blogging as well as develop my language skills.

Thus, without further introduction, what lies ahead for me during the upcoming 3 months?

I will be contributing to Pitivi video editor under the flag of GNOME Organisation. I am going to work with Alexandru Băluț who is my mentor, as well as many other Pitivi contributors whom I already found to be very helpful and easy-to-talk-to people. :)
My task is to implement customisable shortcuts to the application and slightly more verbose abstract of my work can be found at the GSoC 2016 website.

Primary goals:
  • Refactor existing shortcuts to allow customisation using Gtk.AccelMap
  • Write tests for all the existing shortcuts in order to guarantee their correctness
  • Introduce the new GTK feature, GtkShortcutsWindow, to organise the shortcuts in an elegant and modern way
  • Implement the customisation of shortcuts via Preferences enhanced to use Gtk.StackSidebar for clarity
  • GtkShortcutsWindow to automatically update itself after users change their shortcut preferences
  • Define new shortcuts for JKL navigation along the timeline
I am honestly looking forward to the following few months as I expect and hope to learn about technologies and concepts I have not known before (Flatpak), extend my knowledge in areas I have some rudiments in already (Python, GTK, Git, Linux) and most importantly enjoy what I am going to do. 
I will be doing the best I can and hope to see the Pitivi community appreciating my work at the end of the summer.

Stay tuned to hear more about Pitivi development!



March 01, 2016

Hack Camp 2016: I

El sábado (27 de febrero) se realizó la primera etapa Hack Camp 2016 organizado por las comunidades de software libre locales de GNOME y Fedora. Llegué casi terminado el evento pero me sorprendió la cantidad de gente que estaba ahí dispuesta a saber más del software libre y especialmente como contribuir. Todos estos chicos estaban instalando Fedora en sus laptops, algunos por primera vez.

Apenas llegué, Julita me presentó con los asistentes del evento, donde comenté un poco de Pitivi, el proyecto al cual contribuyo, y cómo la gente podría contribuir a GNOME. Contribuir a la GNOME Foundation no solo requiere de saber programación. Uno puede contribuir por ejemplo en el equipo de diseño, traduciendo, documentando o simplemente propagando la palabra del software libre y GNOME.

Por mi parte, a mi me gusta programar, y por eso contribuyo escribiendo software. Tengo interés por la parte de multimedia, por eso estoy enganchado a Pitivi y a Gstreamer. Pitivi es un editor de video y está aproximándose a su versión 1.0. Actualmente no somos muchos los desarrolladores en Pitivi y sería un gran aporte para el programa tener más colaboradores. Para contribuir a Pitivi, no hay nada más que descargarse el código fuente y modificarlo para introducir mejoras. Para tener nuestro entorno listo, recomiendo seguir estas instrucciones.

1. Resolver dependencias.
2. Descargar este script.
3. Ejecuarlo, y leer un buen libro o ver una película. Toma tiempo compilar.

Si alguien del evento está interesado en contribuir a Pitivi, recomiendo hacer esto en casa. No queremos perder tiempo compilando en pleno evento.

February 22, 2016

Back from the DX hackfest

Back from the DX hackfest

I had the chance to attend the GNOME developer experience hackfest three weeks ago, I’m ashamed to admit three weeks went by before I took the time to write this post!

A lot of people I met there I already knew, I was happy to meet some people I didn’t yet, like James, who’s working on Oh-My-Vagrant.

Philip Withnall has already done a good job at summarizing the general issues we looked at as a group during this hackfest in this blogpost, so this post will revolve around my own experience over there.

I am currently working on hotdoc for collabora, and I spent the hackfest presenting it to the documentation team members (Ekaterina Gerasimova, Frédéric Péters, Bastian Ilso and Alexandre Franke), discussing its future use with them and Philip Chimento, and making some improvements to it with the help of Thibault Saunier.

Hotdoc improvements

I helped Frédéric with testing porting gtk from gtk-doc to hotdoc, and landed a patch from him in hotdoc-gi-extension, the resulting documentation seemed overall correct.

I worked with Thibault Saunier to implement a smart include feature in hotdoc.

GNOME Builder

I discussed how to use hotdoc as a GNOME Builder plugin with Christian Hergert, but the solution he advised me to follow actually falls short because hotdoc is python2, and it seems libpeas cannot handle both python2 and python3 in the same process. I’m still a bit confused as to why this limitation would exist, as the proposed solution involved exposing a D-Bus service, but I’m sure we’ll find a better solution when we need to.

GNOME developer portal

I discussed the future of https://developer.gnome.org/ with the documentation team. They liked the search interface in hotdoc (it does work quite well :), and we all agreed that a tighter integration with actual API references would be nice to have, amongst various other things (online editing for example).

The website is currently implemented as a series of mallard pages. Hotdoc does not read mallard pages, and it isn’t part of my current plans. A possible way forward would be to drop mallard altogether, and have all the pages be “hotdoc-flavored” markdown pages. I think this could make sense because:

  • gnome-devel-docs doesn’t make an extensive use of mallard.
  • markdown pages present a significantly lower barrier to entry, and most people are familiar with the syntax.
  • the developer site and the API references it would link to would share the same format for standalone documentation source files.

I have since then implemented a simple pandoc reader, and used it to make a very naive port of gnome-devel-docs, the result can be seen here

This port is naive because I made absolutely no manual edits to the produced markdown files, which explains why the index page looks pretty ugly, but pages like https://people.collabora.com/~meh/dgo_hotdoc/html/overview-media.html are pretty faithful to the source, and it would mostly be a matter of custom CSS and trivial edits to get the thing to really look good.

You can have a look at the generated markdown files here.

Philip Chimento’s devdocs work

Philip Chimento has been working on a fork of devdocs, in an effort to create a javascriot developer portal for GNOME. I see some drawbacks with his approach, which we’ve discussed together and I will not detail here, but overall his current solution has the advantage of code reuse, and lightweightness, as the output is generated stictly from gir files.

My opinion on this is that his work is a nice short-term solution to a clear problem (gathering together the javascript documentation for most (all ?) GNOME libraries, and I suggested linking to it on the current portal.

However I think the design of devdocs and his solution will fall short for the long-term requirements that the GNOME documentation team seems to set, and Philip seemed to agree.

This is still a very open issue, and Philip and I definitely intend to work together to provide the best possible experience for GNOME hackers, newbies and senior alike.

November 19, 2015

Pitivi 0.95 — Enfant Suisse

Hey everyone! It’s time for a new Pitivi release, 0.95. This one packs a lot of bugfixes and architectural work to further stabilize the GES backend. In this blog post, I’ll give you an overview of the new and interesting stuff this release brings, coming out from a year of hard work. It’s pretty epic and you’re in for a few surprises, so I suggest listening to this song while you’re reading this blog post.

Engine rework: completed.

Those of you who attended my talk at GUADEC 2013 might remember this particular slide:

kill gnonlin

Well, it’s done now. It’s dead and buried.

This is something I’ve had on my mind for so long, I was even having nightmares about it—literally. To give you an idea just how ancient gnonlin was from an architectural standpoint, it was created fourteen years ago, merely six months after the first release of GStreamer itself. Well, y’know, a lot of stuff happens in 13-14 years.

So, over the past year, Mathieu and Thibault gradually refactored GNonLin into NLE, the new non-linear engine inside GES. For details, see the previous two blog posts about our War Against Deadlocks: the story about the mixing elements and the story about the new engine using them (replacing gnonlin).

The resulting improvements in reliability are not only palpable in daily use, they are actually quantifiable with the results our GES gst-validate test suite runs:

  • In the 1.4 series: 154 tests pass out of 198 (22.2% failures)
  • With the 1.6 release: 198 tests pass out of 198
— "What's going on? Give me a sitrep!" — "The tests… they all pass!" — "What?!"— “What’s going on? Give me a sitrep!”
— “The tests… they all pass!”
— “What?!”

Now 100% GTK, with new horizons

pitivi 0.95

We were hitting various limitations and bugs (such as this) in Clutter, the library we used to display and animate the project’s timeline. Eventually we came to a point where we had to change strategy and port the timeline to use pure GTK+ widgets, with Matplotlib for drawing the keyframes on clips. Quite some work went into the new timeline.

The viewer (the widget that shows the main video preview, above the timeline) using glimagesink was causing too many problems related to embedding in the X window. We switched to the new GtkSink instead, which also allowed us to test gtkglsink at the same time, as they are compatible.

Thanks to the new GTK timeline, we have a little surprise to show here: technically, Pitivi can also work on Mac OS X now. This is not an April Fool’s joke.

Some notes about the experiment are sitting there if you’re curious. At this time, we are not supporting the Mac OS version officially, because we don’t have the resources for that (yet?). I was told that we should be able to make something available for testing a Mac build once we reach 1.0. Want to make it happen sooner? Feel free to join us and to work on that.

Wait, that’s not all. These changes also allow us to make Pitivi work with the GDK Broadway backend, meaning we can even run Pitivi in a web browser! Yep, you heard that right. Pitivi in a web browser. What could possibly go wrong? ;)

Spit polishing

An improvement we’re quite happy about is that you can finally drag & drop a file from a different app directly to the timeline, to create a clip.

The layers’ representation changed somewhat. Previously, an audio-video clip would be displayed as two separate clips in the timeline, one for video and one for audio, on two separate layers. At times it was pretty awkward. While porting the timeline, Thibault simplified the layers model to have the notion of generic layers, in which audio-video clips are represented as a unified clip object. This also means that there is no more wasted space if the layer has only video or only audio.

Also worth mentioning:

  • We have resurrected the transformation box feature, but the UI is currently very primitive. See the Clip properties > Transformation section when a clip is selected on the timeline. You can also drag the image in the viewer to change the position of the selected clip at the current position and you can use the mouse wheel to zoom in/out.
  • While editing a project, every operation is saved in a scenario file. These can be used when reporting bugs. See how to use scenarios for reporting complicated bugs easily (or if you’re feeling geeky, the details about how the scenarios are used to automatically test the GES backend).
  • You can now copy/paste clips in the timeline.
  • We’re now compatible with smaller screen resolutions (such as 1024×768) again
  • We removed a bunch of widgets in the layer controls. They were placeholders for future features, we should put them back once the features actually become available.
  • Undo/redo has been disabled until we add unit tests and make sure it works properly. Until then you can Ctrl+S regularly.
  • See also the release notes for 0.95.

Infrastructure changes

  • The Pitivi team migrated from Bugzilla to Phabricator for bug/task tracking.
  • We now have a script to setup the development environment from the latest daily bundle. This hybrid approach makes it very easy for new developers to start hacking on Pitivi’s Python side without needing to build the rest.
  • It was difficult for us to keep using Dogtail, so we moved all the integration tests to GstValidate.
  • Some of you have suggested that we compress the all-in-one bundles using XZ, and so we did. Our packages are now 20% lighter than uncompressed tarballs, so they will take less time to download (which is nice if you’re using the dailies to test).
  • With some help from Jeffrey Schroeder, I have finally upgraded our MediaWiki instance to the latest stable release. We hadn’t upgraded it in four years (thankfully it was fairly locked down so we did not run into trouble), in big part because it was not version-controlled and thus was a pain in the butt to manage. I should be able to do a better job at keeping it up-to-date from now on.

Where do we stand on the fundraiser?

In terms of donations, less than the fundraiser’s first milestone was reached. Therefore, instead of working full-time and burning through the money in a matter of a few months, Thibault and Mathieu decided to work at a slower rate while simultaneously providing professional multimedia consulting services to put food on the table.

Nonetheless, they eventually reached the point where they had worked through all the donated funds, and so they continued in their free time. The GTK+ Timeline and GtkSink work, for example, is one of the big architectural changes that Thibault had to do on his spare time, without monetary compensation whatsoever.

Now is still a good time to let others know and ask those around you to donate! We appreciate it.

A call for ruthless testing

As it is much more stable already, we recommend all users to upgrade to Pitivi 0.95 and help us find remaining issues, if any. Until this release trickles down into distributions, you can download our all-in-one bundle and try out 0.95, right here and now. Enjoy!

You’re in luck: I already spent a lot of my (very limited) spare time testing and investigating the most serious issues. In fact, one of the reasons why it’s been so long since the last release is that I have been Thibault’s worse nightmare for months (there’s a reason why my name strikes fear in the hearts of GStreamer developers):

jeff-the-QA-hellbringer

Every two weeks or so, Thibault would come to me and say, “Hey look, I fixed all your bugs, how about we release now?”. I would then spend a day testing and return with ten more bugs. Then he would fix them all, and I would find ten other bugs in different areas. Then he would fix them, and I would find another batch that I couldn’t test last time. And so on and so forth, from spring to autumn. For example, these are the bugs I’ve found just for the GTK Timeline. Can’t believe I haven’t killed that poor guy.

Now that the blocker issues are solved, I’m quite impressed with how much more reliable this version of Pitivi is shaping out to be now. But hey, we’re not perfect, maybe there are bugs we’ve overlooked, so please grab 0.95 and try to break it as hard as you can, reporting the issues you find (especially freezes, crashes, incorrect output, etc.). We want it to be solid. Go wild.

office space printer


Thank you for reading, commenting and sharing! This blog post is part of a série of articles tracking progress made with work related to the 2014 Pitivi fundraiser. Researching and writing quality articles takes a lot of time, so please be patient and enjoy the ride! 😉
  1. An update from the 2014 summer battlefront
  2. The 0.94 release
  3. The War Against Deadlocks, part 1: The story of our new thread-safe mixing elements reimplementation
  4. The War Against Deadlocks, part 2: GNonLin's reincarnation
  5. The 0.95 release, the GTK+ timeline and sink
  6. Measuring quality/reliability through time (clarifying what gst-validate is)
  7. Our all-in-one binaries building infrastructure, and why it matters
  8. Samples, “scenario” files and you: how you can help us reproduce (almost) any bug very easily
  9. The 1.0 release and closure of the fundraiser

June 11, 2015

The War Against Deadlocks, part 1: The story of our new thread-safe mixing elements implementation

Let me tell you of a story that was lost and forgotten amidst Pitivi’s development battlegrounds last fall, a manuscript that I recovered from a Moldy Tome in a stony field. According to my historical data, the original author was a certain “Dorian Leger”, a French messenger that went missing from the vicinity of Paris.

Moldy TomeThe Moldy Tome as I found it

I am taking the liberty of altering fairly substantially this manuscript to clarify some parts while restoring its intent and style according to the historical context. It will serve as the first part of an epic tale (the second part is yet to be written, it will come in the next blog post, though it will probably have a more “modern” writing style), about our war against deadlocks, vile creatures that have been threatening the stability of our application for much too long. Technically, we’ve always been at war with EastasiaDeadlocks; you can see that even in the noble title of our 0.13.2 release, from a time when a different squad of maintainers roamed this land.

Previous maintainers fighting the FomorsPrevious maintainers fighting the Fomors, in the 0.8-0.10 GSt Era.

Without further ado, here is my transcription of the report:

Paris, le vingt-huit septembre, MMXIV

Dear supporters of the Video Editing Liberation Front,

Over the last month and a half, we have made major strides debugging and rewriting important backend code that Pitivi depends on. At the edge of the land of Pitivi, we are approaching the 0.94 milestone, which we plan on liberating in the coming weeks. I have been discussing with sieur Duponchelle to enquire about a particular piece of work the Company has been preparing for that purpose. He said, “We have torn out a large chunk of bug-ridden code in GStreamer and replaced it with a brand new videomixing element that we can finally show with pride and confidence. It will be a tremendous help in our battle against the Deadlocks; hopefully, it will give us stable and bug-free seeking in the timeline at last.”

Indeed, I have heard tales of previous Pitivi versions consistently crashing when seeking in a section of cross-faded (overlapped) clips. In other words, when we tried to select a frame that contained a cross-fade from one clip to another, Pitivi would freeze up and need to be put by the sword. Needless to say, this bug was killing not only the user experience, but also the morale of our troops, and needed to be dealt with as swiftly and efficiently as possible.

The technical problem behind this nuisance was a powerful piece of equipment in the GStreamer artillery: the GstElement videomixer. This contraption was trying to deal with threads other elements were throwing at it, which was by design extremely complex and error-prone—to the point where some have said it to be the work of the Devil itself.

Ming Dynasty eruptor proto-cannon

When we inspected the machine, we found the diagram above. Transcription of the odd scriptures in that diagram leads to the following interpretation of how it operated:

“To make this machine worketh, thou wilt receive buffers from all them sinkpads in different threads. Therefore, thou wilt wait for all thy pads to get a buffer to decide to mix & push the result on thy srcpad; hence thou shall be pushing buffers from the thread on which thee hath received thy last buffer. Eke, make sure not to stand in front of the machine when operating it.” — Dante, son of Sparda

Multithreading, if you recall your scholarship with the monks of Shaolin, is a difficult art to master. It allows running multimedia processing tasks in the background and enables several tasks to be executed simultaneously. A multi-threaded approach is essential to us, but also requires tedious management of variables shared by different threads (these variable usually describe audio data and video pixelization, in the case of the GstElement videomixer machine). As simultaneous threads often work on the same variables, the backend developer, proficient in the ancient C language, needs to ensure these threads do not simultaneously edit a variable, and the developer must carefully manage how threads give each other the signal to edit a variable.

shaolin tiger style

In the case of the strange machine that was causing those problems, we destroyed it with fire and rebuilt it with simplicity and harmony in mind. I cannot tell for sure, but I have been told that over ten thousand lines of ancient codes were rewritten through the exquisite art of multithreading kung fu. The new videomixer machine now has the srcpad running its own thread, and we aggregate and push buffers on the srcpad from that thread. This technique makes us much stronger against the Deadlocks.

As you have certainly seen for yourselves, previous Pitivi versions—particularly due to the mixing elements in GStreamer—were plagued with bugs causing threads to wait for each other indefinitely. To make this easier to imagine, let’s take a modern analogy: the previous videomixer implementation looked like a city full of cars at stop-sign intersections, waiting for the each other to go, causing endless traffic jams behind them. The good news is, after rewriting over 10,000 lines of code, the stop-signs were replaced by a much simpler and reliable system in 0.94, which means our videomixing element is now thread-friendly and ‘bug-free’. This required a complete rework of our mixing stack (by writing a new baseclass to substitute to collectpads2). It was quite an involved process.

We’re quite happy with what we have achieved there, but the Deadlocks are not so easily vanquished, and the story doesn’t end there. The rest of the manuscript is fairly short and consisted mostly of predictions for events that have now occurred since then, which I will be covering in the next blog post when I find more time, as it requires further analysis and expansion.


Thank you for reading, commenting and sharing! This blog post is part of a série of articles tracking progress made with work related to the 2014 Pitivi fundraiser. Researching and writing quality articles takes a lot of time, so please be patient and enjoy the ride! 😉
  1. An update from the 2014 summer battlefront
  2. The 0.94 release
  3. The War Against Deadlocks, part 1: The story of our new thread-safe mixing elements reimplementation
  4. The War Against Deadlocks, part 2: GNonLin's reincarnation
  5. The 0.95 release, the GTK+ timeline and sink
  6. Measuring quality/reliability through time (clarifying what gst-validate is)
  7. Our all-in-one binaries building infrastructure, and why it matters
  8. Samples, “scenario” files and you: how you can help us reproduce (almost) any bug very easily
  9. The 1.0 release and closure of the fundraiser

May 07, 2015

President’s Report — The State of the GNOME Foundation

As I hinted in my retrospective in February, 2014 has been crazy busy on a personal level. Let’s now take a look at 2014-2015 from a GNOME perspective.

When I offered my candidacy for the GNOME Foundation‘s Board of Directors in May last year, I knew that there would be plenty of issues to tackle if elected. As I was elected president afterwards, I was aware that I was getting into a demanding role that would not only test my resolve but also make use of my ability to set a clear direction and keep us moving forward through tough times. But even if someone tries to describe what’s involved in all this, it remains difficult to truly grasp the amount of work involved before you’ve experienced it yourself.

For one thing, I can say that running a branding & management consulting business at the same time as you’re steering an established public charity like the GNOME Foundation is definitely not easy.

2015-03-cal-blurredPictured: my calendar during the month of March

Throughout the year, I went through moments of great joy and periods of deep exhaustion where I cursed Firefox’s bug 60455 — working everyday until 1-2 AM (and waking up 5-6 hours later), for months on end, to get things done. Since 2015, my GTG todo list has consistently been at 4x my normal “healthy” quota. For example, in March, I was at 190 actionable tasks and a total of 520 tasks. Whew! So, in the name of sanity, I had to slow down some of my business activities and withdrew almost all of my involvement in the Pitivi project this term (I’ll be writing a news update blog post soon, I promise!).

I did not compromise on my involvement with the GNOME Foundation because I felt a huge responsibility towards my teammates and towards the Foundation Membership who elected us. Most of the board members, in addition to their daily work, underwent significant personal challenges during the year: relocating, career changes, family matters, all sorts of things that can affect one’s life. And yet, with the limited bandwidth we had, the Board soldiered on and accomplished many feats. I consider myself lucky to have had such a competent and deeply caring team of people to work through one of the busiest years GNOME has had yet!

2014-2015 GNOME Foundation board

What also keeps me motivated is the incredible strength of our community, the technical excellence of our platform and the fundamental need for a GNOME “desktop” (or GNOME OS) to exist. More than ever, we need Free and affordable computing for everyone. If proprietary vendors, DRM, the industry shift towards “renting” (rather than owning) software and the Snowden revelations taught us anything over the years, it’s that we need to be the truly free system that people can trust for all their computing needs, online and offline. Many have their heads in the clouds, but we need to keep our feet on the ground and be the bridge between the sky and earth—the safe base where people will come back to.

The Space Elevator, by Dusty CrosleyThe Space Elevator, by Dusty Crosley

For that reason, I’m pretty excited by our friends at Endless who are shipping a radically different desktop computer running GNOME and a set of applications that will run offline, designed to make the lives of millions (billions!) of people easier in the developing world. I’m proud of our little cousin, elementary, for shipping a new version of their OS—even as an established project with lots of momentum, we can still learn a lot from what they’re doing, and we certainly appreciate their involvement in our shared technologies. Fedora Workstation, with its refined focus, is something else I’m pretty happy about. With sandboxing, OSTree and Builder in the works, I’m looking forward to GNOME OS becoming a reality. We need something rock solid and for which we can sculpt the user experience from the ground up, something which also serves as a reference and entrypoint for new contributors willing to create applications for the exciting GNOME ecosystem.

We’ve made major strides towards creating a stable and refined platform over the past few years. We have our work cut out for us in a number of areas and I look forward to us tackling them as a community. For example, one thing I’m passionate about is having a “bulletproof” OS that can handle the most demanding creative workloads, without the user needing to worry about the system’s resource usage. I should be able to have Firefox (or Web/Epiphany) running at the same time as GIMP, Inkscape and Pitivi without an exabyte of RAM or having the kernel/graphics subsystem go unresponsive due to one application hoarding resources. I know we can do better in this space. With our unparalleled ability to oversee changes through the whole stack and upcoming technologies like containers & sandboxing, we have the potential to be the most advanced OS in the world—we just need to seize this opportunity.

There are also new fields of computing that we are poised to explore as a free desktop: virtual reality—bringing a new meaning to the term “virtual desktops”—is certainly the next big step in “office computing” (including productivity and creative work, entertainment, etc.—not just gaming). We should investigate VR as the next big evolution of the desktop. Imagine getting rid of the limitations imposed by computer multi-head monitor frames…

ghost in the shell VR

We should tackle these things one step at a time, together. It takes many small efforts to steer a ship this big, and the Foundation is there to support the community every step of the way.

Here is a snapshot of what the Foundation’s Board of Directors were up to this year:

  • Dealing with over 3700 emails
  • Held 25+ regular board meetings, on the phone or in person
    • In addition to those, we held a few “special meetings” for topics like adboard outreach and ED search to drain the swamp. Therefore, in practice, we have been meeting more often than the already fast-paced bi-weekly meetings schedule.
  • Exchanged over 24,000 lines of IRC discussion within the board
  • Resolved the cash-flow problem (a.k.a. financial/success crisis) that occurred in the spring of 2014. We collected on every single outstanding invoice for OPW and will be announcing more about this soon.
  • Dealt with two very serious complaints brought to our attention — one of them is not fully resolved yet, but we’re working on it.
  • Represented GNOME at various conferences (GUADEC, SFD, GSoC Mentors Summit, OSCON, FOSDEM, LGM, GNOME.Asia, LinuxCon North America, LinuxCon Europe, linux.conf.au and probably a bunch of others I’m forgetting).
  • Negotiated with Groupon for six months before the trademark opposition filing deadline. As we reached the deadline and could wait no longer, we prepared and launched a public fundraiser and awareness campaign. This initiative worked above all expectations, with more than 100K USD raised within a day and Groupon immediately capitulating upon seeing the incredible public support we were able to muster. We got coverage in a number of media outlets, including the World Trademark Review magazine. We hope that our experience stands for the proposition that companies must respect free software communities, and we’re already seeing our situation held up as an example to support that.
  • Reached out to current (and past) advisory board members on the phone or in person.
  • Sought new sponsorship opportunities
  • Set up a kanban system to keep track of the “big picture” of long-running projects and action items.
  • Started the hunt for an Executive Director, including forming a search & hiring committee
  • Reviewed & approved budgets and reimbursements for various events
  • Reviewed & approved various trademark use requests
  • Started work on prospecting new sources of funding for the GNOME sysadmin role
  • Provided advice on fundraising for the Telder font
  • Signed two legal agreements with the Software Freedom Conservancy for the transfer of Outreachy — more news on this later
  • Administered OPW (including legal and financial aspects), until the migration to Outreachy under the SFC was completed
  • Worked on various aspects of codes of conduct
  • Initiated work on a Privacy policy
  • Provided support for GNOME conferences, including GUADEC, GNOME.Asia, the Boston Summit and the West Coast Summit
  • Signed a deal with the WHS for handling funds in Europe — more news on this later
  • Various ongoing financial and legal tasks
  • Transferred the ownership of various assets (including domain names such as gnome.gr)
  • Responded to various press or events organization inquiries, phone calls, etc.
  • Apologized to people for not moving fast enough on some matters ;)

I can tell you, like anyone who has worked on a board of directors without an Executive Director for the entire term, that I have developed a tremendous amount of respect and patience towards the work done by each volunteer and team in the GNOME community. There is so much that needs to be done to keep the GNOME Project running, it would not be possible without your help. Thank you, everyone!

November 03, 2014

Tricks or Tracebacks? Pitivi 0.94 is here

Dear werepenguins, we’re thrilled to announce the immediate availability of Pitivi 0.94! This is the fourth release for the new version of our video editor based on GES, the GStreamer Editing Services library. Take a look at my previous blog post to understand in what context 0.94 has been brewing. This is mainly a maintenance release, but it does pack a few interesting improvements & features in addition to the bug fixes.

The first thing you will notice is that the main toolbar, menubar and titlebar have been replaced by a unified GTK HeaderBar, saving a ton of precious vertical space and making better use of the horizontal space. Once you try it, you can’t go back. There is beauty in the equilibrium it has now, compared to the previously clunky and unbalanced layout:

pitivi 0.94 headerbar comparison 1Pitivi 0.93 on the left, 0.94 on the right

The combined screenshot above allows you to get the “complete picture” of how this change affects the main window, but it’s hard to get a sense of scale and it does not really do justice to the awesomeness of client-side decorations like the GTK HeaderBar. So here’s a simplified version where all the “wasted space” is highlighted in red:

pitivi 0.94 headerbar comparison 2Pitivi 0.93 above, 0.94 below

Pretty rad, huh?

Beyond that eye-popping novelty, many distro/setup-dependent startup crashes have been investigated and fixed:

  • Various Linux distributions have started shipping a broken version of CoGL in recent months, which led to crashes. Technically this is a bug in the CoGL library/packaging, but we found out that the functions we were calling in that particular case were not needed for Pitivi, so we dropped our use of those broken CoGL APIs. Problem solved.
  • People running Pitivi outside of GNOME Shell were seeing crashes due to Clutter GStreamer video output, so we ported the viewer widget to use GStreamer’s new GL video output (glimagesink) instead of the ClutterSink. We had to fix various bugs in GStreamer’s glimagesink to raise it to the quality we needed, and our fixes have been integrated in GStreamer 1.4 (this is why we depend on that version). The GL image sink is expected to be a more future-proof solution.
  • We found issues related to gobject introspection or the overrides provided by gst-python. Again, make sure you have version 1.4 for things to work properly.
  • On avant-garde Linux distributions, you would get a TypeError traceback (“unsupported operand type(s) for /: ‘int’ and ‘NoneType”) preventing startup, which we investigated as bug 735529. This is now fixed in Pitivi.

We also have a collection of bug fixes to the way we handle the various resizeable & detachable components of the main window:

  • The default positioning of UI components (when starting from a fresh install) has been improved to be balanced properly
  • Undocked window components do not shift position on startup anymore
  • Docked window components do not shift position on startup anymore, when the window is not maximized. When the window is maximized, the issue remains (your help to investigate this problem is very much welcome, see bug 723061)

The title editor’s UI has been simplified and works much more reliably:

pitivi 0.94 title editor

Also:

  • Undo/redo should be globally working again; please file specific bug reports for the parts that don’t.
  • Pitivi has been ported to Python 3
  • The user manual is now up to date with the state of the new Pitivi series
  • Educational infobars throughout the UI have been tweaked to make their colors less intrusive
  • Various other fixes as usual. Testing and providing detailed reports for issues you encounter certainly helps!
  • There’s more. Find out in the release notes for 0.94!

This release is meant to be the last release based on our current “buggy stack”; indeed, as I mentioned in my previous status update, the next release (0.95) will run on top of a refined and incredibly more robust backend thanks to the work that Mathieu and Thibault have been doing to replace GNonLin by NLE (the new non-linear engine for GES) and fixing videomixing issues.

We recommend all 0.91/0.92/0.93 users to upgrade to this release. Until this trickles down into distributions, you can download our all-in-one bundle and try out 0.94, right here and now. Enjoy!

October 04, 2014

An update from the Pitivi 2014 summer battlefront

Hello gentle readers! You may have been wondering what has been going on since the 0.93 release and the Pitivi fundraising campaign. There are a few reasons why we’ve been quiet on the blogging side this summer:

  • Mathieu and Thibault have been working hard to bring us towards “1.0 quality”, improving and stabilizing various parts of GStreamer to make the backend of Pitivi more reliable (more details on this further below). They preferred to write code rather than spending their time doing marketing/fundraising. This is understandable, it is a better use of our scarce specialized resources.
  • Personally, I have been juggling with many obligations (my daily business, preparing for the conferences season, serving on the board of the GNOME Foundation, and Life in General), which left me with pretty much no time or energy to do development on marketing-related activities on Pitivi, just enough to participate in some discussions and help with administration/co-mentorship a bit. I did not have time to research blogging material about what others were doing, hence the lack of status updates in recent times.

Now that I finally have a little bit of time on my hands, I will provide you with the overdue high-level status update from the trenches.

Summer Wars. That’s totally how coding happens in the real world.

GUADEC, status of the 2014 fundraiser

For the curious among you, my account of GUADEC 2014 is here. Among the multiple presentations I gave there, my main talk was about Pitivi. I touched upon the status of the fundraiser in my talk; however, the recordings are not yet available, so I’ll share some select notes on this topic here:

  • Personally, I’ve always thought that, to be worth it, we should raise 200 thousand dollars per year, minimum (you’ll be able to hear the explanation for this belief of mine in the economic context I presented in my talk).
  • For this fundraiser, we aimed for a “modest” minimum target of 35k and an “optimistic” target of 100k. So, much less than 200k.
  • Early on after the campaign launch, we had to scale back on hopes of hitting the “optimistic” target and set 35k as the new “maximum” we could expect, as it became clear from the trend that we would not reach 100k.
  • Eventually, the fundraiser reached its plateau, at approximately 19K €, a little bit over half of our base target.

We had a flexible funding scheme, a great website and fundraising approach, we have the reputation and the skills to deliver, we had one of the best run campaigns out there (we actually got praised on that)… and yet, it seems that was not enough. shrugAfter four months spent preparing and curating our fundraiser, at one point we had to reassess our priorities and focus on “more urgent” things than full-time fundraising: improving code, earning a living, etc. Pushing further would have meant many more months of energy-draining marketing work which, as mentioned in the introduction of this post, was not feasible or productive for us at that point in time. Our friends at MediaGoblin certainly succeeded, in big part through their amazing focus and persistence (Chris Webber spent three months writing substantial motivational blog posts twice a week and applying for grants to achieve his goal. Think about it: fourteen blog articles!).

Okay so now you’re thinking, “But you still got a bit of money, so what have you guys done with that?”. We’ve accomplished some great QA/bugfixing work, just not as fast or as extensively as we’d like to. Pitivi 1.0 will happen but, short of seeing a large amount of donations, it will take more time to reach that goal (unless people step up with patches :).

What Mathieu & Thibault have been up to

For starters, they set up a continuous integration and multi-platform build system for quality assurance.

Then they worked on the GStreamer video mixer, basically doing a complete rework of our mixing stack, and made the beast thread-safe… this is supposed to fix a ton of deadlocks related to videomixing that were killing our user experience by causing frequent freezes. They are preparing a blog post specifically on this topic, but in the meantime you can see some gory details by looking at these commits they landed in GStreamer so far (more are on the way, pending review):

Then they pretty much rewrote all of GNonLin with a different, simpler design, and integrated it directly into GES under a new name: “NLE” (Non Linear Engine):

d82acb9454ea65266f23a4c6cc305bb4

The only part that survived from GNonLin, as far as I know, is the tree data structure generation. So, with “NLE” in GES, deadlocks from GNonLin should be a thing of the past; seeking around should be much more reliable and not cause freezes like it used to. This is still a major chunk of code: it represents around six thousand lines of new code in GES. Work is ongoing in this branch, expected to be completed and merged sometime in October, so I’m waiting to see what comes out of it in practice.

This is in addition to crazy bugs like bug 736896 and our regular bug fixing operations. See also the Pitivi tracker bug for GTK3, introspection and GST1 bugs and the Pitivi tracker bug for Python3 port issues.

The way forward

Now that a big chunk of the hardcore backend work has been done, Thibault and Mathieu will be able to focus on Pitivi (the UI) again. Here is the rough plan for coming months:

  1. “Scenarios” in Pitivi: each action from the user would be serialized (saved) as GstValidateScenario actions, allowing us to easily reproduce issues and bugs that you encounter.
  2. Go over the list of all reported Pitivi bugs and fix a crapton of them!
  3. At some point, we will call upon you to help us with extensive testing (including reporting the bugs and discussing with us to investigate them). We will then continue fixing bugs, release often and make sure we reach the quality you can expect of a 1.0 release.

More news to come


Thank you for reading, commenting and sharing! This blog post is part of a série of articles tracking progress made with work related to the 2014 Pitivi fundraiser. Researching and writing quality articles takes a lot of time, so please be patient and enjoy the ride! 😉
  1. An update from the 2014 summer battlefront
  2. The 0.94 release
  3. The War Against Deadlocks, part 1: The story of our new thread-safe mixing elements reimplementation
  4. The War Against Deadlocks, part 2: GNonLin's reincarnation
  5. The 0.95 release, the GTK+ timeline and sink
  6. Measuring quality/reliability through time (clarifying what gst-validate is)
  7. Our all-in-one binaries building infrastructure, and why it matters
  8. Samples, “scenario” files and you: how you can help us reproduce (almost) any bug very easily
  9. The 1.0 release and closure of the fundraiser

September 11, 2014

Recent Changes in Pitivi User Documentation

I feel like the basic (re)writing of Pitivi user docs is done so I thought I should take a while to describe the current state of the docs and point to further tasks that need to be done. When I started, nekohayo gave me his to-do list that he kept specifically for docs, which helped me to get going. For the first commit, the choice was clear: add Pitivi’s license to the manual’s license page. As close to a one-liner as you can get. Soon, I got into the flow and as a result, the user manual now looks a little more complete. Of course there are some remaining issues I haven’t had time to cover yet. These are mostly tracked in bugzilla.

Also, screenshots should be updated in the manual, but I was postponing this intentionally for two reasons. First, there might be some slight UI changes on the way to 1.0 and second, it is not a big deal since the gnome docs team recommends (because of the difficulties this poses for docs translation) to use only one screenshot — that of the main window overview. So the screenshot is just waiting for the right time to be switched.

More interestingly, I have an experimental branch containing a troubleshooting page. I know that the Pitivi developers work hard to clear all issues that would possibly need troubleshooting, but in the meantime, I thought this page could provide some guidance. You can look at the branch in my Github repository. Any thoughts or comments are appreciated!

August 29, 2014

Wow, 7 years….

Originally post to Collabora co-workers:

7 years since starting the Collabora Multimedia adventure,
7 years of challenges, struggles, and proving we could tackle them
7 years of success, pushing FOSS in more and more areas (I can still hear Christian say “de facto” !)
7 years of friendship, jokes, rants,
7 years of being challenged to outperform one self,
7 years of realizing you were working with the smartest and brightest engineers out there,
7 years of pushing the wtf-meter all the way to 11, yet translating that in a politically correct fashion to the clients
7 years of life …
7 years … that will never be forgotten, thanks to all of you

It’s never easy … but it’s time for me to take a long overdue break, see what other exciting things life has to offer, and start a new chapter.

So today is my last day at Collabora. I’ve decided that after 17 years of non-stop study and work (i.e. since I last took more than 2 weeks vacation in a row), it was time to take a break.

What’s next ? Tackling that insane todo-list one compiles over time but never gets to tackle :). Some hacking and GStreamer (obviously), some other life related stuff, traveling, visiting friends, exploring new technologies and fields I haven’t had time to look deeper into until now, maybe do some part-time teaching, write more articles and blogposts, take on some freelance work here and there, … But essentially, be in full control of what I’m doing for the next 6-12 months.

Who knows what will happen. It’s both scary … and tremendously exciting :)

PS 1: While my position at Collabora as Multimedia Domain Lead has already been taken over by the insane(ly amazing) Olivier Crete (“tester” from GStreamer fame), Collabora is looking for more Multimedia engineers. If you’re up for the challenge, contact them :)

PS 2. wtf-meter : http://www.osnews.com/story/19266/WTFs_m

PS 3. My non-Collabora email address is <my nickname>@<my nickname> dot com

August 28, 2014

GStreamer continuous testing (Part 1)

History so far

For the past 6-9 months, as part of some of the tasks I’ve been handling at Collabora, I’ve been working on setting up a continuous build and testing system for GStreamer. For those who’ve been following GStreamer for long enough, you might remember we had a buildbot instance back around 2005-2006, which continuously built and ran checks on every commit. And when it failed, it would also notify the developers on IRC (in more or less polite terms) that they’d broken the build.

The result was that master (sorry, I mean main, we were using CVS back then) was guaranteed to always be in a buildable state and tests always succeeded. Great, no regressions, no surprises.

At some point in time (around 2007 I think ?) the buildbot was no longer used/maintained… And eventually subtle issues crept in, you wouldn’t be guaranteed checkouts always compile, tests eventually broke, you’d need to track what introduced a regression (git bisect makes that easier, but avoiding it in the first place is even better), etc…

What to test

Fast-forward to 2013, after talking so much about it, it was time to bring back such a system in place. Quite a few things have changed since:

  • There’s a lot more code. In 2005, when 0.10 was released, the GStreamer project was around 400kLOC. We’re now around 1.5MLOC ! And I’m not even taking into account all the dependency code we use in cerbero, the system for building binary SDK releases.
  • There are more usages that we didn’t have back then. New modules (rtsp-server, editing-services, orc now under the GStreamer project umbrella, ..)
  • We provide binary releases for Windows, MacOSX, iOS, Android, …

The problems to tackle were “What do we test ? How do we spot regressions ? How to make it as useful as possible to developers ?”.

In order for a CI system to be useful, you want to limit the Signal-To-Noise ratio as much as possible. Just enabling a massive bunch of tests/use-cases with millions of things to fix is totally useless. Not only is it depressing to see millions of failed tests, but also you can’t spot regressions easily and essentially people don’t care anymore (it’s just noise). You want the system to become a simple boolean (Either everything passes, or something failed. And if it failed, it was because of that last commit(s)). In order to cope with that, you gradually activate/add items to do and check. The bare minimum was essentially testing whether all of GStreamer compiled on a standard linux setup. That serves as a reference point. If someone breaks the build, it becomes useful, you’ve spotted a regression, you can fix it. As time goes by, you start adding other steps and builds (make check passes on gstreamer core, activate that, passes on gst-plugins-base, activate that, cerbero builds fully/cleanly on debian, activate that, etc…).

The other important part is that you want to know as quickly as possible whether a regression was introduced. If you need to wait 3 hours for the CI system to report a regression … that person will have gone to sleep or be taken up by something else. If you know within 10-15mins, then it’s still fresh in their head, they are most likely still online, and you can correct the issue as quickly as possible.

Finally, what do we test ? GStreamer has gotten huge. in that sentence GStreamer is actually not just one module, but a whole collection (GStreamer core, gst-plugins*, but also ORC, gst-rtsp-server, gnonlin, gst-editing-services, ….). Whatever we produce for every release … must be covered. So this now includes the binary releases (formerly from gstreamer.com, but which are handled by the GStreamer project itself since 1.x). So we also need to make sure nothing breaks on all the platforms we target (Linux, Android, OSX, iOS, Windows, …).

To summarize

  1. CI system must be set-up progressively (to detect regressions)
  2. CI system must be fast (so person who introduced the regression can fix it ASAP)
  3. CI system must cover all our offering (including cerbero binary builds)

The result is here (yes, I know, we’re working on fixing the certificates once it moves to the final namespace).

How this was implemented, and what challenges were encountered and handled will be covered in a next post.

Feeds