Wednesday, December 1, 2010

Using Flickr for crash recorder backup

I have been looking at the possibility of using flickr to backup my crash recording videos. Since I used python and sl4a to create my crash recorder program I looked for python scripts which performed uploads to flickr. I found some and got one working (with a few updates/modifications). Unfortunately I found it very difficult to work out exactly what the script was doing due to unnecessarily complex nested calls and sorting, json, xml and mime_types methods. Flickr tells you exactly what data strings are needed (to provide you with what you require) so it really doesn't need hard to follow programs to achieve this. Therefore, I decided to write my own flickr upload script. To write your own flickr app you need to go to the flickr api garden and apply for your own flickr api_key and secret. Anybody who wants to use your app needs to have a flickr account and obtain an authorisation token. This is a 'one-off -' process so I have written 2 scripts: one to enable a user to get a token (only needs running once); the other to use the token to allow photo/video uploads.

---------------------------------

# FlickrToken.py by John Karwatzki November 2010
# Get a flickr authentication token to use an app

import hashlib, urllib, android
droid = android.Android()

# flickr key and secret for the crash recorder app
apikey = '88e6f2645d45df438689358aac3de9bb'
secret = '000f5e98af65ece4'

# write your own app with a new key and secret from flickr app garden
url = 'http://api.flickr.com/services/rest/?'

# get api signature and url
dstring = secret+'api_key'+apikey+'methodflickr.auth.getFrob'
apisig = hashlib.md5(dstring).hexdigest() # encrypt signature

# get the frob needed for a new flickrToken
args = 'method=flickr.auth.getFrob&api_key='+apikey+'&api_sig='+ apisig
f = urllib.urlopen(url + args)
resp = f.read()
f.close()
fr = resp.find('frob') # no need for json or xml routines
end = resp.find('</frob')
frob = resp[fr+5:end]

# get a flickr login signature and url using the frob
dstring = secret+'api_key'+ apikey +'frob' + frob + 'permswrite'
apisig = hashlib.md5(dstring).hexdigest()
logurl = 'http://www.flickr.com/services/auth/?api_key=' + apikey + '&perms=write&frob=' + frob + '&api_sig=' + apisig
droid.webViewShow(logurl, True) # login to flickr

# on exit from webView get a token for the app
dstring = secret+'api_key'+apikey+'frob'+frob+'methodflickr.auth.getToken'
apisig = hashlib.md5(dstring).hexdigest()
args = 'method=flickr.auth.getToken&' + 'api_key=' + apikey + '&frob=' + frob + '&api_sig=' + apisig
f = urllib.urlopen(url + args)
resp = f.read()
f.close()
print resp # this will show up any errors
tok = resp.find('token')
end = resp.find('</token')
token = resp[tok+6:end]

# save the token on your phone's sdcard
f = file('/sdcard/token.txt', 'w')
f.write(token)
f.close()
exit()
-----------------------------------------
# FlickrUpload.py by John Karwatzki November 2010

import hashlib, urllib, httplib

def upload(filename):
  apikey = '88e6f2645d45df438689358aac3de9bb'
  secret = '000f5e98af65ece4'

  # Check a flickr token exists on the phone's sdcard
  try:
    f = file('/sdcard/token.txt', 'r')
    token = f.read()
    f.close()
    if not token:
      raise IOError
  except IOError:
    print 'Token not found.  Run FlickrToken.py'
    exit()

  # get file mimetype (my phone only has jpg mp4 and 3gp)
  dot = filename.find('.')
  ext = filename[dot+1:dot+4]
  if ext == 'jpg':
    mtype = 'image/jpeg'
  elif ext == 'mp4':
    mtype = 'video/mp4'
  elif ext == '3gp':
    mtype = 'video/3gp'
  f = file(filename, 'rb') # get file data
  fdata = f.read()
  f.close()

  # get apisig for upload
  dstring = secret+'api_key'+apikey+'auth_token'+token
  apisig = hashlib.md5(dstring).hexdigest()

  # get multipart mime information string
  nl = '\r\n'
  boundary = '----boundary'
  content_type = 'multipart/form-data; boundary=' + boundary
  hd = '--' + boundary + nl + 'Content-Disposition: form-data; name='
  mp = hd + '"api_key"' + nl + nl + apikey + nl
  mp = mp + hd + '"auth_token"' + nl + nl + token + nl
  mp = mp + hd + '"api_sig"' + nl + nl + apisig + nl
  mp = mp + hd + '"photo"; filename="' + filename + '"' + nl
  mp = mp + 'Content-Type: ' + mtype + nl + nl
  mp = mp + fdata + nl + '--' + boundary + '--' + nl

  # send file to user's flickr account
  up = httplib.HTTP('flickr.com')
  up.putrequest('POST', '/services/upload/')
  up.putheader('content-type', content_type)
  up.putheader('content-length', str(len(mp)))
  up.endheaders()
  up.send(mp)
  up.getreply()
  print up.file.read() # check for any errors
  return()

# This is all you need to call upload
upload('sdcard/Photos/pic1.jpg')
upload('sdcard/Photos/pic2.jpg')
exit()

Monday, October 11, 2010

Crash recorder using android scripting and python

I have been working on a demonstrator script to determine the
feasibility of using an android phone as a vehicle crash recording
system.  I have been using SL4A and python (see the attached file) but
the final program would need integration into the Google sat nav app.
Due to the slow speed at which sensor events are recovered from the
event buffer I can't get much further with it at the moment.

# Crash recorder, John Karwatzki September 2010
# When the android phone is used in sat nav mode the
# camera will be facing the front of the vehicle.
# This python script is the first attempt at using the
# z force sensor to detect a crash. The camera provides
# video recording before, during and after the crash
# It will be developed further in the future
import android
import shutil
import os
import time
droid = android.Android()
crash = False
g = 12 # sensitivity value for g-force
# We need to use an available 'rw' directory in ram to
# avoid excessive writing to the sd card
s = 'app-cache/'
# (It would be preferable for SL4A to provide a temporary
# directory for scripting use)
# temporary video files (2 required for continuous recording)
v1 = 'vid1.mp4'
v2 = 'vid2.mp4'
# crash event files
v3 = 'before.mp4'
v4 = 'crash.mp4'
v5 = 'after.mp4'
# take initial setup video
droid.recorderCaptureVideo(s + v2, 3, True)
droid.recorderStop()  # required when recorder is restarted
os.chmod(s + v2, 0777) # allow rw access
v = 0 # swap recordings from one file to the other
# We will need a better way to stop the script in the
# final version. At the moment just shake the phone.
while crash is False:
  if v is 0:
    vid = s + v1
    v = 1
  else:
    vid = s + v2
    v = 0
  # Take 10 second video
  #  We need to disable output to the screen in the final version
  droid.startSensing(5) # Put sensor data into the event buffer
  droid.recorderCaptureVideo(vid, 10, True)
  droid.recorderStop()
  droid.stopSensing()
  os.chmod(vid, 0777)
  # check the event buffer
  e = droid.receiveEvent()
  for count in range(1, 10):  # Ignore the first 10 (no data)
    e = droid.receiveEvent()
  while e.result is not None:
    e = droid.receiveEvent() # We don't need all these
    e = droid.receiveEvent() # but we have to pull them
    e = droid.receiveEvent() # out regardless. This takes
    e = droid.receiveEvent() # 4 to 5 seconds for 300
      # events which is too slow for real time!
    if e.result is not None: # Check for end of event buffer
      z = e.result['data']['zforce'] # Check for crash
      if z > g:
        crash = True
# take video after crash
droid.recorderCaptureVideo(s + v5, 5, True)
os.chmod(s + v5, 0777)
if v is 0:
  os.rename(s + v2, s + v4) # Rename videos to Before, During
  os.rename(s + v1, s + v3) # and After
else:
  os.rename(s + v1, s + v4)
  os.rename(s + v2, s + v3)
# Save videos on sd card (or Flickr.upload if it
# becomes available on SL4A)
shutil.copyfile(s + v3, '/sdcard/' + v3)
shutil.copyfile(s + v4, '/sdcard/' + v4)
shutil.copyfile(s + v5, '/sdcard/' + v5)