Timelapse/Ffmpeg: Difference between revisions
From charlesreid1
(Created page with "Notes on the use of ffmpeg, specifically for timelapse videos. =Flags= {{TimelapseFlag}} Category:Ffmpeg") |
No edit summary |
||
| Line 1: | Line 1: | ||
Notes on the use of ffmpeg, specifically for timelapse videos. | Notes on the use of ffmpeg, specifically for timelapse videos. | ||
=Creating Video from Image Files= | |||
These notes are based on the notes at the [[Ffmpeg]] page. | |||
==Renaming Files== | |||
One of the quirks of ffmpeg is that, if you are converting a large number of files, they have to be sequentially numbered, <u>starting with 0 OR 1</u>. | |||
===Renaming Files: Test Run=== | |||
The best way to do this is to put all the photos you want to add to your timelapse into one big folder, in the order you want them. Then do a <code>/bin/ls -1</code> to list them all in order. Then use a bash for loop to name each file in a sequential fashion: 0001.jpg, 0002.jpg, etc. | |||
<pre> | |||
#!/bin/sh | |||
i=1 | |||
for file in `/bin/ls -1 *.jpg`; do | |||
filestrip=$(echo "$file" | sed 's/\.jpg//') | |||
newfile=$(printf "${filestrip}_%04d.jpg" "$i") | |||
echo "mv ${file} ${newfile}" | |||
i=$((i+1)) | |||
done | |||
</pre> | |||
The output of this file, run on a dummy directory with 8 dummy files (note that it preserves the original filename, without the extension) | |||
<pre> | |||
$ ./doit.sh | |||
mv f1.jpg f1_0001.jpg | |||
mv f2.jpg f2_0002.jpg | |||
mv f3.jpg f3_0003.jpg | |||
mv f4.jpg f4_0004.jpg | |||
mv f5.jpg f5_0005.jpg | |||
mv f6.jpg f6_0006.jpg | |||
mv f7.jpg f7_0007.jpg | |||
mv f8.jpg f8_0008.jpg | |||
</pre> | |||
===Renaming Files: Real Deal=== | |||
When it was time to run the real script, I copied the above script into the directory containing the downsampled pile of 8,000 photos, and made one modification: the line that actually EXECUTES, not just PRINTS, the mv command. | |||
This strips out the six-digit time suffix, which changes from photo to photo. This gives all of the photos the same prefix, which is also essential for ffmpeg. | |||
<pre> | |||
#!/bin/sh | |||
i=1 | |||
for file in `/bin/ls -1 *.jpg`; do | |||
filestrip=$(echo "$file" | sed 's/-[0-9]\{6\}\.jpg//') | |||
newfile=$(printf "${filestrip}_%04d.jpg" "$i") | |||
echo "mv ${file} ${newfile}" | |||
mv ${file} ${newfile} | |||
i=$((i+1)) | |||
done | |||
</pre> | |||
Ran it. It took almost a minute, but it renamed all the files like a charm. | |||
Let's break down that sed expression: | |||
<code>sed 's/-[0-9]\{6\}\.jpg//'</code> | |||
This looks for an expression like <code>-000000</code> (the <code>[0-9]</code> means any digit, and the <code>\{6\}</code> means 6 in a row), followed by the expression <code>.jpg</code>. This is the six digit hour-minute-second timestamp at the end of the filename, before the suffix. We want to get rid of both the jpg suffix and the non-unique timestamp, so that all the photos will have the same filename prefix. | |||
The double slash means, replace whatever you find with the empty string. A few before/afters: | |||
<pre> | |||
20160730-165955_8313.jpg | |||
20160730_8313.jpg | |||
20160730-170000_8314.jpg | |||
20160730_8314.jpg | |||
20160730-170005_8315.jpg | |||
20160730_8315.jpg | |||
20160730-170010_8316.jpg | |||
20160730_8316.jpg | |||
20160730-170015_8317.jpg | |||
20160730_8317.jpg | |||
20160730-170020_8318.jpg | |||
20160730_8318.jpg | |||
</pre> | |||
==Using ffmpeg== | |||
Now we get to use ffmpeg to stitch these image files together into movies. | |||
A full treatment of ffmpeg would take a lot more space, so we'll leave that to the [[Ffmpeg]] page. | |||
Here we'll just go through the bare minimum to make a viable timelapse movie. | |||
===Reviewing Filenames=== | |||
Just a review: ffmpeg is very picky about filenames. It expects files to have a similar prefix, and to have a numbering scheme that starts with 0 or 1. Example of a scheme it likes: | |||
<pre> | |||
$ /bin/ls -1 | |||
20160730_0001.jpg | |||
20160730_0002.jpg | |||
20160730_0003.jpg | |||
20160730_0004.jpg | |||
20160730_0005.jpg | |||
20160730_0006.jpg | |||
20160730_0007.jpg | |||
20160730_0008.jpg | |||
20160730_0009.jpg | |||
20160730_0010.jpg | |||
20160730_0011.jpg | |||
20160730_0012.jpg | |||
20160730_0013.jpg | |||
20160730_0014.jpg | |||
20160730_0015.jpg | |||
20160730_0016.jpg | |||
20160730_0017.jpg | |||
20160730_0018.jpg | |||
20160730_0019.jpg | |||
</pre> | |||
Make sure that's what you've got. That's what all the filename wrangling nonsense is about anyway. | |||
<pre> | |||
ffmpeg -i 20160730_%04d.jpg -q:v 1 -vcodec mpeg4 movie_output.mp4 | |||
</pre> | |||
The <code>%04d</code> just means, a 4-digit number that increments, starting at 0 or 1. | |||
===Running ffmpeg=== | |||
When I ran the above ffmpeg command, I saw several lines like this: | |||
<pre> | |||
$ ffmpeg -i 20160730_%04d.jpg -q:v 1 -vcodec mpeg4 movie1.mp4 | |||
[...] | |||
frame= 3670 fps= 58 q=1.0 size= 32379kB time=00:02:26.80 bitrate=1806.9kbits/s speed=2.31x | |||
frame= 4906 fps= 58 q=1.0 size= 42788kB time=00:03:16.24 bitrate=1786.2kbits/s speed=2.32x | |||
frame= 6611 fps= 56 q=1.0 size= 70847kB time=00:04:24.44 bitrate=2194.8kbits/s speed=2.2 | |||
frame= 6639 fps= 56 q=1.0 size= 71354kB time=00:04:25.56 bitrate=2201.1kbits/s speed=2.2 | |||
</pre> | |||
This didn't make much sense to me... 56 frames per second? However, the videos is 5:32, or 332 seconds long, and 332 seconds * 26 frames per second gives 8632, much closer to the actual count of photos in the directory. So, the video looks like it is actually 26 fps. | |||
====Stock ffmpeg==== | |||
The "stock" or baseline ffmpeg command I started with was: | |||
<pre> | |||
$ ffmpeg -i 20160730_%04d.jpg -q:v 1 -vcodec mpeg4 movie1.mp4 | |||
</pre> | |||
This resulted in the movie below: | |||
<html> | |||
<iframe src="https://player.vimeo.com/video/176893370" width="640" height="427" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> | |||
<p><a href="https://vimeo.com/176893370">Raspberry Pi Timelapse: Midnight to Mid-Morning</a> from <a href="https://vimeo.com/charlesreid1">charlesreid1</a> on <a href="https://vimeo.com">Vimeo</a>.</p> | |||
</html> | |||
===Slower Framerate/Stop Motion=== | |||
Next I tried a different frame rate, 15 fps, with the <code>-r 15</code> flag. This gives it much more of a stop-motion look - I'm not sure how it's filling in all the frames, but it moves at the same rate. In other words, halving the frame rate will not double the length of your video. Frames are simply removed from the original video. (It may be as crude as showing 15 frames, then stopping for 15 frames.) | |||
<pre> | |||
$ ffmpeg -i 20160730_%04d.jpg -r 15 -q:v 1 -vcodec mpeg4 movie1.mp4 | |||
</pre> | |||
The slower framerate requires a faster capture rate as well - it's great for stop motion, but if people are running across the screen in 4 or 5 frames, you don't get much of a stop motion effect. Much better is to calibrate the frame rate to the height of the camera and the subject matter. A 15th floor camera above a city street can have a slower frame rate due to its wider field of vision and the slower scale of motion from the 15th floor. On the other hand, a 4th floor view of construction workers at a construction site may be closer to the movement, have a narrower range of view, and therefore require a faster frame rate to capture the relative scale of motion. | |||
Proof the timing is exactly the same in both videos: here's a screenshot from both videos of 3:17, when the street lamp is on: | |||
{|- | |||
|[[Image:Lamp1.png|200px]] | |||
|[[Image:Lamp2.png|200px]] | |||
|- | |||
|'''26 fps''' | |||
|'''15 fps''' | |||
|} | |||
then of 3:18, when the street lamp turns off: | |||
{|- | |||
|[[Image:Lamp3.png|200px]] | |||
|[[Image:Lamp4.png|200px]] | |||
|- | |||
|'''26 fps''' | |||
|'''15 fps''' | |||
|} | |||
Capturing 1 frame every 2 seconds, and setting to 15 fps, ''almost'' looked right for stop motion, but everything was too fast by a factor of about 2. | |||
<html> | |||
<iframe src="https://player.vimeo.com/video/176894252" width="640" height="427" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> | |||
<p><a href="https://vimeo.com/176894252">Raspberry Pi Timelapse: Midnight to Mid-Morning (15 fps)</a> from <a href="https://vimeo.com/charlesreid1">charlesreid1</a> on <a href="https://vimeo.com">Vimeo</a>.</p> | |||
</html> | |||
=Flags= | =Flags= | ||
Revision as of 04:02, 31 July 2016
Notes on the use of ffmpeg, specifically for timelapse videos.
Creating Video from Image Files
These notes are based on the notes at the Ffmpeg page.
Renaming Files
One of the quirks of ffmpeg is that, if you are converting a large number of files, they have to be sequentially numbered, starting with 0 OR 1.
Renaming Files: Test Run
The best way to do this is to put all the photos you want to add to your timelapse into one big folder, in the order you want them. Then do a /bin/ls -1 to list them all in order. Then use a bash for loop to name each file in a sequential fashion: 0001.jpg, 0002.jpg, etc.
#!/bin/sh
i=1
for file in `/bin/ls -1 *.jpg`; do
filestrip=$(echo "$file" | sed 's/\.jpg//')
newfile=$(printf "${filestrip}_%04d.jpg" "$i")
echo "mv ${file} ${newfile}"
i=$((i+1))
done
The output of this file, run on a dummy directory with 8 dummy files (note that it preserves the original filename, without the extension)
$ ./doit.sh mv f1.jpg f1_0001.jpg mv f2.jpg f2_0002.jpg mv f3.jpg f3_0003.jpg mv f4.jpg f4_0004.jpg mv f5.jpg f5_0005.jpg mv f6.jpg f6_0006.jpg mv f7.jpg f7_0007.jpg mv f8.jpg f8_0008.jpg
Renaming Files: Real Deal
When it was time to run the real script, I copied the above script into the directory containing the downsampled pile of 8,000 photos, and made one modification: the line that actually EXECUTES, not just PRINTS, the mv command.
This strips out the six-digit time suffix, which changes from photo to photo. This gives all of the photos the same prefix, which is also essential for ffmpeg.
#!/bin/sh
i=1
for file in `/bin/ls -1 *.jpg`; do
filestrip=$(echo "$file" | sed 's/-[0-9]\{6\}\.jpg//')
newfile=$(printf "${filestrip}_%04d.jpg" "$i")
echo "mv ${file} ${newfile}"
mv ${file} ${newfile}
i=$((i+1))
done
Ran it. It took almost a minute, but it renamed all the files like a charm.
Let's break down that sed expression:
sed 's/-[0-9]\{6\}\.jpg//'
This looks for an expression like -000000 (the [0-9] means any digit, and the \{6\} means 6 in a row), followed by the expression .jpg. This is the six digit hour-minute-second timestamp at the end of the filename, before the suffix. We want to get rid of both the jpg suffix and the non-unique timestamp, so that all the photos will have the same filename prefix.
The double slash means, replace whatever you find with the empty string. A few before/afters:
20160730-165955_8313.jpg 20160730_8313.jpg 20160730-170000_8314.jpg 20160730_8314.jpg 20160730-170005_8315.jpg 20160730_8315.jpg 20160730-170010_8316.jpg 20160730_8316.jpg 20160730-170015_8317.jpg 20160730_8317.jpg 20160730-170020_8318.jpg 20160730_8318.jpg
Using ffmpeg
Now we get to use ffmpeg to stitch these image files together into movies.
A full treatment of ffmpeg would take a lot more space, so we'll leave that to the Ffmpeg page.
Here we'll just go through the bare minimum to make a viable timelapse movie.
Reviewing Filenames
Just a review: ffmpeg is very picky about filenames. It expects files to have a similar prefix, and to have a numbering scheme that starts with 0 or 1. Example of a scheme it likes:
$ /bin/ls -1 20160730_0001.jpg 20160730_0002.jpg 20160730_0003.jpg 20160730_0004.jpg 20160730_0005.jpg 20160730_0006.jpg 20160730_0007.jpg 20160730_0008.jpg 20160730_0009.jpg 20160730_0010.jpg 20160730_0011.jpg 20160730_0012.jpg 20160730_0013.jpg 20160730_0014.jpg 20160730_0015.jpg 20160730_0016.jpg 20160730_0017.jpg 20160730_0018.jpg 20160730_0019.jpg
Make sure that's what you've got. That's what all the filename wrangling nonsense is about anyway.
ffmpeg -i 20160730_%04d.jpg -q:v 1 -vcodec mpeg4 movie_output.mp4
The %04d just means, a 4-digit number that increments, starting at 0 or 1.
Running ffmpeg
When I ran the above ffmpeg command, I saw several lines like this:
$ ffmpeg -i 20160730_%04d.jpg -q:v 1 -vcodec mpeg4 movie1.mp4 [...] frame= 3670 fps= 58 q=1.0 size= 32379kB time=00:02:26.80 bitrate=1806.9kbits/s speed=2.31x frame= 4906 fps= 58 q=1.0 size= 42788kB time=00:03:16.24 bitrate=1786.2kbits/s speed=2.32x frame= 6611 fps= 56 q=1.0 size= 70847kB time=00:04:24.44 bitrate=2194.8kbits/s speed=2.2 frame= 6639 fps= 56 q=1.0 size= 71354kB time=00:04:25.56 bitrate=2201.1kbits/s speed=2.2
This didn't make much sense to me... 56 frames per second? However, the videos is 5:32, or 332 seconds long, and 332 seconds * 26 frames per second gives 8632, much closer to the actual count of photos in the directory. So, the video looks like it is actually 26 fps.
Stock ffmpeg
The "stock" or baseline ffmpeg command I started with was:
$ ffmpeg -i 20160730_%04d.jpg -q:v 1 -vcodec mpeg4 movie1.mp4
This resulted in the movie below:
Raspberry Pi Timelapse: Midnight to Mid-Morning from charlesreid1 on Vimeo.
Slower Framerate/Stop Motion
Next I tried a different frame rate, 15 fps, with the -r 15 flag. This gives it much more of a stop-motion look - I'm not sure how it's filling in all the frames, but it moves at the same rate. In other words, halving the frame rate will not double the length of your video. Frames are simply removed from the original video. (It may be as crude as showing 15 frames, then stopping for 15 frames.)
$ ffmpeg -i 20160730_%04d.jpg -r 15 -q:v 1 -vcodec mpeg4 movie1.mp4
The slower framerate requires a faster capture rate as well - it's great for stop motion, but if people are running across the screen in 4 or 5 frames, you don't get much of a stop motion effect. Much better is to calibrate the frame rate to the height of the camera and the subject matter. A 15th floor camera above a city street can have a slower frame rate due to its wider field of vision and the slower scale of motion from the 15th floor. On the other hand, a 4th floor view of construction workers at a construction site may be closer to the movement, have a narrower range of view, and therefore require a faster frame rate to capture the relative scale of motion.
Proof the timing is exactly the same in both videos: here's a screenshot from both videos of 3:17, when the street lamp is on:
| 26 fps | 15 fps |
then of 3:18, when the street lamp turns off:
| 26 fps | 15 fps |
Capturing 1 frame every 2 seconds, and setting to 15 fps, almost looked right for stop motion, but everything was too fast by a factor of about 2.
Raspberry Pi Timelapse: Midnight to Mid-Morning (15 fps) from charlesreid1 on Vimeo.
Flags
| Timelapse Photography tools for timelapse photography
|