2016 Marine Corps Marathon Time-Lapse

The Marine Corps Marathon starts and finishes in Arlington, VA. There are 21 Arlington traffic cameras along the course. I used 20 of them to create a time-lapse of the race. There are also cameras operated by VDOT and DDOT, but those aren’t easy to access programmatically.

Research

I cross-referenced the traffic camera and race course maps to find cameras along the course and generated a file with the cameras in the order that runners pass them. Each row contains the order, camera ID, HLS stream port (the RTMP port listed on the open data portal + 10), and location.

1,cam19,8011,Wilson Blvd @ Lynn St.
2,cam112,8012,Lee Hwy @ Ft. Myer Dr. (EB)
3,cam111,8012,Lee Hwy @ Nash St.(EB)
4,cam14,8011,Lee Hwy @ Vietch St.
5,cam101,8012,Lee Hwy @ N. Adams St.
6,cam100,8012,Lee Hwy @ Cleveland St.
7,cam99,8012,Lee Hwy @ Danville St.
8,cam98,8012,Lee Hwy @ Highland St.
9,cam45,8011,Lee Hwy @ N. Kirkwood Rd.
10,cam125,8012,Army Navy @ Fern St
11,cam33,8011,Army Navy Dr. @ Eads St.
12,cam122,8012,12th St. @ Clark St.
13,cam123,8012,15th St. @ Crystal Dr.
14,cam133,8012,Crystal Dr. @ Water Park
15,cam132,8012,Crystal Dr. @ 18th St.
16,cam134,8012,Crystal Dr. @ MidBlock A
17,cam117,8012,23rd St. @ Crystal Dr.
18,cam154,8012,23rd St. @ Crystal Dr. (Hawk)
19,cam28,8011,26th St. @ Crystal Dr.
20,cam122,8012,12th St. @ Clark St.

Setup (Ubuntu 16.04)

I created a dedicated user to capture the images because my regular user has an encrypted home directory, which causes problems with cron jobs.

sudo apt install parallel ffmpeg imagemagick
sudo adduser --disabled-password cameras
sudo su cameras
cd /home/cameras
mkdir /home/cameras/mcm
cd /home/cameras/mcm
nano /home/cameras/mcm/cams.txt # See camera list above

The hand cyclists start at 7:40am and the course closes at 3:10pm, so there are three crontab entries. Note that the percent signs are escaped.

# 7:40am-7:59am
40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59 7 28 10 * /usr/bin/parallel --no-notice --colsep "," ffmpeg -loglevel panic -i https://itsvideo.arlingtonva.us:{3}/live/{2}.stream/playlist.m3u8 -f image2 -vframes 1 -strftime 1 /home/cameras/mcm/"\%FT\%H\%M-{1}.jpg" :::: /home/cameras/mcm/cams.txt >/dev/null 2>&1
# 8:00am-2:59pm
* 8,9,10,11,12,13,14 28 10 * /usr/bin/parallel --no-notice --colsep "," ffmpeg -loglevel panic -i https://itsvideo.arlingtonva.us:{3}/live/{2}.stream/playlist.m3u8 -f image2 -vframes 1 -strftime 1 /home/cameras/mcm/"\%FT\%H\%M-{1}.jpg" :::: /home/cameras/mcm/cams.txt >/dev/null 2>&1
# 3:00pm-3:09pm
0,1,2,3,4,5,6,7,8,9 15 28 10 * /usr/bin/parallel --no-notice --colsep "," ffmpeg -loglevel panic -i https://itsvideo.arlingtonva.us:{3}/live/{2}.stream/playlist.m3u8 -f image2 -vframes 1 -strftime 1 /home/cameras/mcm/"\%FT\%H\%M-{1}.jpg" :::: /home/cameras/mcm/cams.txt >/dev/null 2>&1

Post-Processing

Create a 5×4 grid for each minute’s images, with the time at the top:

time=0
for i in {1..450}
do
  tile_date="2016-10-27 10:24 -0400 $time seconds"
  montage /home/cameras/mcm/`date -d "$tile_date" +"%FT%H%M"`*.jpg -tile 5x4 -geometry +0+0 -title `date -d "$tile_date" +"%l:%M%p"` -background black -fill white /home/cameras/mcm/tiles-`printf "%04d" $i`.jpg
  time=$((time + 60))
done

Each grid is 1760×1176. The black border between tiles comes from the source images.

Create a time-lapse movie from the montages:

ffmpeg -framerate 10/1 -pattern_type glob -i "/home/cameras/mcm/tiles-*.jpg" -c:v libx264 -r 15 -pix_fmt yuv420p /home/cameras/mcm/MCM_2016.mp4

Leave a Reply

Your email address will not be published. Required fields are marked *