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>