{
 "metadata": {
  "name": "",
  "signature": "sha256:b3db3d09e064cfe84d747d44f9507670e8eab728c8bb5cbb4ed2b6cb99f11a98"
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import json, re, subprocess, urllib2\n",
      "\n",
      "def get_fps_given_nframes(url, nframes):\n",
      "    try:\n",
      "        out = subprocess.check_output(['ffprobe', '-i', url, '-show_frames', '-read_intervals', '%+#' + str(nframes), '-select_streams', 'v'], stderr=subprocess.STDOUT)\n",
      "    except subprocess.CalledProcessError:\n",
      "        return None\n",
      "    frametimes = [float(match.group(1)) for match in re.finditer(r'pts_time=([\\d\\.]+)', out)]\n",
      "    # frametimes contain the beginning timestamps of each frame\n",
      "    # len(frametimes) - 1 is the numerator below due to fencepost:\n",
      "    fps = (len(frametimes) - 1) / (max(frametimes) - min(frametimes)) \n",
      "    return fps\n",
      "\n",
      "def print_fps_stats(root_url):\n",
      "    r = json.loads(urllib2.urlopen(root_url + '/r.json').read())\n",
      "    nframes = int(r['frames']) + int(r['leader'])\n",
      "    advertised_fps = float(r['fps'])\n",
      "    print '%s:' % root_url\n",
      "    for video in ['/0/0/0.mp4', '/0/0/0.webm']:\n",
      "        url = root_url + video\n",
      "        actual_fps = get_fps_given_nframes(url, nframes)\n",
      "        if actual_fps != None:\n",
      "            print ('  %s: %d frames, advertised %.4f, actual %.4f, adv/act = %.2f%%' % \n",
      "                   (video, nframes, advertised_fps, actual_fps, advertised_fps / actual_fps * 100.0))\n",
      "        else:\n",
      "            print '  %s: not found' % video"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 1
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Compare actual FPS versus advertised FPS\n",
      "========================================"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Earth Engine\n",
      "------------\n",
      "FPS are right on the money for both mp4 and webm"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "print_fps_stats('https://earthengine.google.org/timelapse/data/20130507/1068x600')\n",
      "print_fps_stats('http://commondatastorage.googleapis.com/earthengine-timelapse/seasonal-20140202/1068x600')"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "https://earthengine.google.org/timelapse/data/20130507/1068x600:\n",
        "  /0/0/0.mp4: 29 frames, advertised 10.0000, actual 10.0000, adv/act = 100.00%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: 29 frames, advertised 10.0000, actual 10.0000, adv/act = 100.00%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://commondatastorage.googleapis.com/earthengine-timelapse/seasonal-20140202/1068x600:"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.mp4: 634 frames, advertised 12.0000, actual 12.0000, adv/act = 100.00%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: 634 frames, advertised 12.0000, actual 12.0002, adv/act = 100.00%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n"
       ]
      }
     ],
     "prompt_number": 174
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "timemachine.cmucreatelab.org\n",
      "----------------------------\n",
      "\n",
      "Almost all the FPS are 100% accurate for both mp4 and webm.  The one exception is Blue Marble, which is 99.98%, but since it's only 12 frames long, such a tiny error only results in a .0024 frame error by the end.  (Perhaps it's a lack of precision in reading the frame time, in which case the % error would naturally go down in the longer videos).\n",
      "\n",
      "An aside:  some of the appended black trailers for .mp4 appear to be have a different FPS from the main video, so print_fps_stats compensates by only looking at the frames before the trailer.\n"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "print_fps_stats('http://g7.gigapan.org/timemachines/brassica-15m-g10-bf0-l/brassica-15m-g10-bf0-l-1088x624')\n",
      "print_fps_stats('http://g7.gigapan.org/timemachines/e5-crf28-g10-bf0-l/e5-crf28-g10-bf0-l90-25fps-1088x624')\n",
      "print_fps_stats('http://g7.gigapan.org/timemachines/blue-marble-v2/blue-marble-v2-crf28-6fps-1088x624')\n",
      "print_fps_stats('http://g7.gigapan.org/timemachines/pittsburgh-v12/crf26-12fps-l70-1088x624')"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "http://g7.gigapan.org/timemachines/brassica-15m-g10-bf0-l/brassica-15m-g10-bf0-l-1088x624:\n",
        "  /0/0/0.mp4: 3130 frames, advertised 25.0000, actual 25.0000, adv/act = 100.00%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: 3130 frames, advertised 25.0000, actual 25.0000, adv/act = 100.00%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://g7.gigapan.org/timemachines/e5-crf28-g10-bf0-l/e5-crf28-g10-bf0-l90-25fps-1088x624:"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.mp4: 1457 frames, advertised 25.0000, actual 25.0000, adv/act = 100.00%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: 1457 frames, advertised 25.0000, actual 25.0000, adv/act = 100.00%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://g7.gigapan.org/timemachines/blue-marble-v2/blue-marble-v2-crf28-6fps-1088x624:"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.mp4: 12 frames, advertised 6.0000, actual 6.0000, adv/act = 100.00%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: 12 frames, advertised 6.0000, actual 6.0011, adv/act = 99.98%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://g7.gigapan.org/timemachines/pittsburgh-v12/crf26-12fps-l70-1088x624:"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.mp4: 15271 frames, advertised 12.0000, actual 12.0000, adv/act = 100.00%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: 15271 frames, advertised 12.0000, actual 12.0000, adv/act = 100.00%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n"
       ]
      }
     ],
     "prompt_number": 2
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "BreatheCam\n",
      "----------\n",
      "\n",
      "Looks like the transition from spot-on to 100.08% happens on March 10, which appears to be the same day the URL pattern for\n",
      "the root directory changes.  100.08% * 1440 frames ~= 1489.2, so the error is definitely enough to give us errors seeking."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "print_fps_stats('http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-02-17.timemachine/crf26-12fps-l70-1424x800')\n",
      "print_fps_stats('http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-01.timemachine/crf26-12fps-l70-1424x800')\n",
      "print_fps_stats('http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-04.timemachine/crf26-12fps-l70-1424x800')\n",
      "print_fps_stats('http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-07.timemachine/crf26-12fps-l70-1424x800')\n",
      "print_fps_stats('http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-08.timemachine/crf26-12fps-l70-1424x800')\n",
      "print_fps_stats('http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-09.timemachine/crf26-12fps-l70-1424x800')\n",
      "print_fps_stats('http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-10.timemachine/crf26-12fps-1424x800')\n",
      "print_fps_stats('http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-11.timemachine/crf26-12fps-1424x800')\n",
      "print_fps_stats('http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-12.timemachine/crf26-12fps-1424x800')\n",
      "print_fps_stats('http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-15.timemachine/crf26-12fps-1424x800')\n",
      "print_fps_stats('http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-20.timemachine/crf26-12fps-1424x800')\n",
      "print_fps_stats('http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-04-01.timemachine/crf26-12fps-1424x800')\n",
      "print_fps_stats('http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-05-01.timemachine/crf26-12fps-1424x800')\n",
      "print_fps_stats('http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-06-01.timemachine/crf26-12fps-1424x800')\n",
      "print_fps_stats('http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-07-01.timemachine/crf26-12fps-1424x800')\n",
      "print_fps_stats('http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-08-01.timemachine/crf26-12fps-1424x800')"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-02-17.timemachine/crf26-12fps-l70-1424x800:\n",
        "  /0/0/0.mp4: 1510 frames, advertised 12.0000, actual 12.0000, adv/act = 100.00%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: not found"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-01.timemachine/crf26-12fps-l70-1424x800:"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.mp4: 1488 frames, advertised 12.0000, actual 12.0000, adv/act = 100.00%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: not found"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-04.timemachine/crf26-12fps-l70-1424x800:\n",
        "  /0/0/0.mp4: 1506 frames, advertised 12.0000, actual 12.0000, adv/act = 100.00%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: not found"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-07.timemachine/crf26-12fps-l70-1424x800:\n",
        "  /0/0/0.mp4: 1510 frames, advertised 12.0000, actual 12.0000, adv/act = 100.00%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: not found"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-08.timemachine/crf26-12fps-l70-1424x800:\n",
        "  /0/0/0.mp4: 1506 frames, advertised 12.0000, actual 12.0000, adv/act = 100.00%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: not found"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-09.timemachine/crf26-12fps-l70-1424x800:\n",
        "  /0/0/0.mp4: 1450 frames, advertised 12.0000, actual 12.0000, adv/act = 100.00%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: not found"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-10.timemachine/crf26-12fps-1424x800:"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.mp4: 1388 frames, advertised 12.0000, actual 11.9910, adv/act = 100.08%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: not found"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-11.timemachine/crf26-12fps-1424x800:\n",
        "  /0/0/0.mp4: 1488 frames, advertised 12.0000, actual 11.9909, adv/act = 100.08%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: not found"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-12.timemachine/crf26-12fps-1424x800:\n",
        "  /0/0/0.mp4: 1494 frames, advertised 12.0000, actual 11.9910, adv/act = 100.08%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: not found"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-15.timemachine/crf26-12fps-1424x800:\n",
        "  /0/0/0.mp4: 1498 frames, advertised 12.0000, actual 11.9909, adv/act = 100.08%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: not found"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-03-20.timemachine/crf26-12fps-1424x800:\n",
        "  /0/0/0.mp4: 1508 frames, advertised 12.0000, actual 11.9909, adv/act = 100.08%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: not found"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-04-01.timemachine/crf26-12fps-1424x800:"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.mp4: 1468 frames, advertised 12.0000, actual 11.9909, adv/act = 100.08%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: not found"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-05-01.timemachine/crf26-12fps-1424x800:"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.mp4: 1508 frames, advertised 12.0000, actual 11.9909, adv/act = 100.08%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: not found"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-06-01.timemachine/crf26-12fps-1424x800:"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.mp4: 1508 frames, advertised 12.0000, actual 11.9909, adv/act = 100.08%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: not found"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-07-01.timemachine/crf26-12fps-1424x800:"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.mp4: 875 frames, advertised 12.0000, actual 11.9913, adv/act = 100.07%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: not found"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "http://timemachine1.gc.cs.cmu.edu/timemachines/breathecam/timemachines/heinz/2014-08-01.timemachine/crf26-12fps-1424x800:"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.mp4: 1078 frames, advertised 12.0000, actual 11.9911, adv/act = 100.07%"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "  /0/0/0.webm: not found"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n"
       ]
      }
     ],
     "prompt_number": 5
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Code that's no longer needed:\n",
      "-----------------------------"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "def get_fps_nframes(url):\n",
      "    try:\n",
      "        out = subprocess.check_output(['ffprobe', '-i', url, '-show_frames', '-select_streams', 'v'], stderr=subprocess.STDOUT)\n",
      "    except subprocess.CalledProcessError:\n",
      "        return (None, None)\n",
      "    nframes = len(list(re.finditer(r'\\[FRAME\\]', out)))\n",
      "    components = re.search(r'Duration: ([\\:\\.\\d]+)', out).group(1).split(':')\n",
      "    if len(components) != 3:\n",
      "        raise(\"Unrecognized format for duration\")\n",
      "    duration = 3600 * float(components[0]) + 60 * float(components[1]) + float(components[2])\n",
      "    print 'duration=%g' % duration\n",
      "    return (nframes / duration, nframes)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 4
    }
   ],
   "metadata": {}
  }
 ]
}