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