Command-line video editing in Linux (cut, join and preview)

Solution 1:

Yes, there is. Try using the app called "Melt". See the documentation here.

If you use a Debian derived distro:

apt-get install melt

Solution 2:

Ok, since I cannot find much about melt command line usage, here are some notes.. (and after this, see this answer Using process substitution to trick programs expecting files, with specific extensions as argument? - Unix & Linux Stack Exchange for a script example via bash)

To begin with - there is a Ubuntu/Debian package for melt (I have Ubuntu 11.04 with MLT melt 0.6.2); the link given by @Ielton is for the "Media Lovin' Toolkit" (MLT) Wiki, which melt is a part of (but also openshot and kdenlive). Here is the link to the documentation text files from their git: mltframework.org/mlt.git/tree - docs/; note the wiki has a page about BuildScripts.

For now, the biggest (only) problem I have with it, is that I cannot find a way to export an uncompressed video composition (either as png frames, or some uncompressed video format).

 

First, in command-line melt you can control playback through frames; for instance, to "create" a 15-frame long white blank, and view it with the built-in melt player, use

melt -blank 15

When you view with melt, you will also get a command line info to stderr for the built-in player:

$ melt -blank 15 
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
|1=-10| |2= -5| |3= -2| |4= -1| |5=  0| |6=  1| |7=  2| |8=  5| |9= 10|
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
+---------------------------------------------------------------------+
|               H = back 1 minute,  L = forward 1 minute              |
|                 h = previous frame,  l = next frame                 |
|           g = start of clip, j = next clip, k = previous clip       |
|                0 = restart, q = quit, space = play                  |
+---------------------------------------------------------------------+
Current Position:         15

Once melt is done playing back, it will not exit - so you should type q to exit it.

We should note there are so-called "producers" and "consumers" in melt. If nothing is specified, then the default "consumer" is an SDL (Simple DirectMedia Layer) window playing back the video; so the above command is the same as:

melt -blank 15 -consumer sdl

Thus, if we want to save what melt displays, we should change the consumer to something that will support a file format. To get a list of consumers:

$ melt -query "consumers"
---
consumers:
  - sdl
  - sdl_audio
  - sdl_preview
  - sdl_still
  - gtk2_preview
  - avformat
  - libdv
  - xml
  - decklink
  - null
...

The libdv consumer will output DV formatted data directly to stdout, so to save the video to a .dv file you'd do:

melt -blank 15 -consumer libdv > test.dv

Note that from the listed consumers, the only format I have tried, that can also be opened in another application is libdv (I used vlc as another application); however, this may fail for a different type of transcoding (e.g. if instead of a blank, I try to convert a snippet from an .flv file, the resulting .dv file opens and plays in vlc, but is corrupt).

 

Now for the editing part; essentially, you can specify a series of file-name/in/out stanzas directly on the command line; say you have a file, video.avi - then you could do:

melt video.avi in=30 out=79 -blank 15 video.avi in=30 out=79

or slightly better formatted:

melt \ 
video.avi in=30 out=79 \ 
-blank 15 \
video.avi in=30 out=79

This means video.avi from its frame 30 to its frame 79 will be played; then a 15-frame blank; and then the video.avi sequence from frame 30 to frame 79 again.

To utilize images (say, .png) in a video edit composition:

melt \
video.avi in=30 out=79 \
test.png in=0 out=15 \
video.avi in=30 out=79 \
-blank 15

Note that for test.png, in= parameter doesn't need to be 0 - however, the image will be displayed for out-in time; in this case, it would be easiest to simply leave the in=0 parameter out altogether.

 

The good thing is that this editing sequence can be saved - or as melt calls it, serialized - to a file; note there are two ways of such serialization: "simple" or XML. For instance, to save the above command as a "simple" serialized file, we can just add the -serialise [filename] switch to the command:

$ melt video.avi in=30 out=79 -blank 15 video.avi in=30 out=79 -serialise file.melt 
Project saved as file.melt.

Now the file.melt contains:

video.avi
in=30
out=79
-blank
15
video.avi
in=30
out=79

Seemingly, this "simple" serialized file format doesn't contain a "commenting" character - if I try to add a "# comment" line, melt complains with: 'Failed to load "# comment"' (but apart from that, seems that such a line is ignored, and playback continues anyways). ".melt" seems to be an extension that melt recognizes as simple serialized file.

Now, to re-play back this serialized file, we could in principle just call melt file.melt - however, a more complete command line would be:

melt melt_file:file.melt -consumer sdl

... which would mean: use the melt_file "producer" to open file.melt, and render its frames on the "consumer" sdl (window).

Note that I have the experience, that (say) .flv videos play without a problem on the command line - however, cause a segmentation fault when they are specified in the file.melt serialized file! .dv videos produced by melt itself, seem to work fine in file.melt...

 

The XML type of serialization can be achieved by using the -consumer xml: switch (instead of -serialise) - so the above example would now be:

melt video.avi in=30 out=79 -blank 15 video.avi in=30 out=79 -consumer xml:file.mlt

To "play back" the newly generated file.mlt XML file, one can now do directly melt file.mlt - or, a more complete command line would be:

melt xml:file.mlt -consumer sdl

... which would mean: use the xml "producer" (note, previously it was a consumer) to open file.mlt, and render its frames on the "consumer" sdl (window).

Note that in this case, I've experienced that the very same .flv videos that caused segfault with a simple serialization file - work just fine with an XML serialization file!

In this case, the resulting file.mlt XML file has a lot more settings, such as resolution, frame rate, codec information etc - but it is also more difficult to work with in a text editor directly:

<?xml version="1.0" encoding="utf-8"?>
<mlt root="/path/to" title="video.avi">
  <profile description="automatic" width="320" height="240" progressive="1" sample_aspect_num="1" sample_aspect_den="1" display_aspect_num="320" display_aspect_den="240" frame_rate_num="25" frame_rate_den="1" colorspace="601"/>
  <producer id="producer0" in="30" out="79">
    <property name="mlt_type">producer</property>
    <property name="aspect_ratio">1.000000</property>
    <property name="length">125</property>
    <property name="eof">pause</property>
    <property name="resource">video.avi</property>
    <property name="meta.media.nb_streams">2</property>
    <property name="meta.media.0.stream.type">video</property>
    <property name="meta.media.0.stream.frame_rate">25.000000</property>
    <property name="meta.media.0.stream.sample_aspect_ratio">0.000000</property>
    <property name="meta.media.0.codec.frame_rate">25.000000</property>
    <property name="meta.media.0.codec.pix_fmt">yuv420p</property>
    <property name="meta.media.0.codec.sample_aspect_ratio">1.000000</property>
    <property name="meta.media.0.codec.colorspace">601</property>
    <property name="meta.media.0.codec.name">mpeg4</property>
    <property name="meta.media.0.codec.long_name">MPEG-4 part 2</property>
    <property name="meta.media.0.codec.bit_rate">0</property>
    <property name="meta.media.1.stream.type">audio</property>
    <property name="meta.media.1.codec.sample_fmt">s16</property>
    <property name="meta.media.1.codec.sample_rate">22050</property>
    <property name="meta.media.1.codec.channels">1</property>
    <property name="meta.media.1.codec.name">mp2</property>
    <property name="meta.media.1.codec.long_name">MP2 (MPEG audio layer 2)</property>
    <property name="meta.media.1.codec.bit_rate">64000</property>
    <property name="seekable">1</property>
    <property name="meta.media.sample_aspect_num">1</property>
    <property name="meta.media.sample_aspect_den">1</property>
    <property name="meta.attr.title.markup"></property>
    <property name="meta.attr.author.markup"></property>
    <property name="meta.attr.copyright.markup"></property>
    <property name="meta.attr.comment.markup"></property>
    <property name="meta.attr.album.markup"></property>
    <property name="audio_index">1</property>
    <property name="video_index">0</property>
    <property name="mlt_service">avformat</property>
  </producer>
  <producer id="producer1" in="30" out="79">
    <property name="mlt_type">producer</property>
    <property name="aspect_ratio">1.000000</property>
    <property name="length">125</property>
    <property name="eof">pause</property>
    <property name="resource">video.avi</property>
    <property name="meta.media.nb_streams">2</property>
    <property name="meta.media.0.stream.type">video</property>
    <property name="meta.media.0.stream.frame_rate">25.000000</property>
    <property name="meta.media.0.stream.sample_aspect_ratio">0.000000</property>
    <property name="meta.media.0.codec.frame_rate">25.000000</property>
    <property name="meta.media.0.codec.pix_fmt">yuv420p</property>
    <property name="meta.media.0.codec.sample_aspect_ratio">1.000000</property>
    <property name="meta.media.0.codec.colorspace">601</property>
    <property name="meta.media.0.codec.name">mpeg4</property>
    <property name="meta.media.0.codec.long_name">MPEG-4 part 2</property>
    <property name="meta.media.0.codec.bit_rate">0</property>
    <property name="meta.media.1.stream.type">audio</property>
    <property name="meta.media.1.codec.sample_fmt">s16</property>
    <property name="meta.media.1.codec.sample_rate">22050</property>
    <property name="meta.media.1.codec.channels">1</property>
    <property name="meta.media.1.codec.name">mp2</property>
    <property name="meta.media.1.codec.long_name">MP2 (MPEG audio layer 2)</property>
    <property name="meta.media.1.codec.bit_rate">64000</property>
    <property name="seekable">1</property>
    <property name="meta.media.sample_aspect_num">1</property>
    <property name="meta.media.sample_aspect_den">1</property>
    <property name="meta.attr.title.markup"></property>
    <property name="meta.attr.author.markup"></property>
    <property name="meta.attr.copyright.markup"></property>
    <property name="meta.attr.comment.markup"></property>
    <property name="meta.attr.album.markup"></property>
    <property name="audio_index">1</property>
    <property name="video_index">0</property>
    <property name="mlt_service">avformat</property>
  </producer>
  <playlist id="playlist0">
    <entry producer="producer0" in="0" out="49"/>
    <blank length="16"/>
    <entry producer="producer1" in="0" out="49"/>
  </playlist>
  <tractor id="tractor0" title="video.avi" global_feed="1" in="0" out="115">
    <track producer="playlist0"/>
  </tractor>
</mlt>