tarina

git clone https://git.tarina.org/tarina
Log | Files | Refs | README | LICENSE

commit 05e6e36ee38f23d9f48d3b00cfbda596c9d78d1f
parent 02572e33cf820f43a9a0337d3817bc0a46b0bc05
Author: Robin Bäckman <rob@tarina.org>
Date:   Fri, 13 Nov 2020 18:15:55 +0200

Merge pull request #1 from rbckman/hq-camera

Hq camera
Diffstat:
MREADME.md | 1+
Mdocs/tarina-manual.md | 11+++++++++++
Minstall.sh | 12++++++++----
Mtarina.py | 158+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
4 files changed, 126 insertions(+), 56 deletions(-)

diff --git a/README.md b/README.md @@ -29,6 +29,7 @@ Hardware The parts are built around the world by different manufacturers. They've been chosen on the basis of features, quality, openness, availabilty and price. One of the central ideas of the project is to have a camera that could be upgraded or repaired by the fact that you easily just switch a component. The casis of the camera is all 3d printable with a design that has the key element of flipping the lens 180 (gonzo style). Here's the main components: [Raspberry Pi 3](https://www.raspberrypi.org/products/raspberry-pi-3-model-b/)<br> +[Raspberry Pi High Quality Camera](https://www.raspberrypi.org/products/raspberry-pi-high-quality-camera/?resellerType=home) or <br> [Arducam 5 MP OV5647 camera module with CS lens 2718](https://www.ebay.com/itm/OV5647-Camera-Board-w-CS-mount-Lens-for-Raspberry-Pi-3-B-B-2-Model-B-/281212355128?txnId=1913825600018)<br> [3.5 inch 800x480 TFT Screen](https://www.aliexpress.com/store/product/U-Geek-Raspberry-Pi-3-5-inch-800-480-TFT-Screen-HD-HighSpeed-LCD-Module-3/1954241_32672157641.html)<br> [USB via vt1620a Sound card](https://www.aliexpress.com/item/Professional-External-USB-Sound-Card-Adapter-Virtual-7-1-Channel-3D-Audio-with-3-5mm-Headset/32588038556.html?spm=2114.01010208.8.8.E8ZKLB)<br> diff --git a/docs/tarina-manual.md b/docs/tarina-manual.md @@ -151,6 +151,17 @@ This is a good performance card. [Aliexpress](https://www.aliexpress.com/item/32676225311.html?spm=a2g0o.productlist.0.0.11ed1b664kPdEf&algo_pvid=d9155fff-7ddc-47bb-9512-f7e686fe69ac&algo_expid=d9155fff-7ddc-47bb-9512-f7e686fe69ac-0&btsid=e2f36205-1c37-47bc-9a94-c006837f0992&ws_ab_test=searchweb0_0,searchweb201602_7,searchweb201603_55) +Raspberry Pi High Quality Camera (recommended) +---------------------------------------------- +Price ~60 eur + +This is the recommended camera module for Tarina, 12.3 megapixel Sony IMX477 sensor, 7.9mm diagonal image size, and back-illuminated sensor architecture, with adjustable back focus and support for C- and CS-mount lenses. + +**Links** +**Buy** +[Raspberry pi](https://www.raspberrypi.org/products/raspberry-pi-high-quality-camera/?resellerType=home) + + Arducam 5 MP OV5647 camera module with CS lens ---------------------------------------------- Price ~30 eur diff --git a/install.sh b/install.sh @@ -52,9 +52,10 @@ sudo pip3 install omxplayer-wrapper echo "installing blessed..." sudo pip3 install blessed echo "installing rwb27s openflexure microscope fork of picamera with lens shading correction..." -sudo pip3 --no-cache-dir install https://github.com/rbckman/picamera/archive/master.zip --upgrade +#sudo pip3 --no-cache-dir install https://github.com/chrisruk/picamera/archive/hq-camera-new-framerates.zip --upgrade +sudo pip3 install --upgrade picamerax echo "installing web.py for the tarina webserver..." -sudo pip3 install web.py==0.40-dev1 +sudo pip3 install web.py==0.61 if grep -q -F '#tarina-rpi-configuration-1.0' /boot/config.txt then @@ -122,7 +123,10 @@ then echo "Debian Buster Alsa config" cat <<'EOF' > /etc/modprobe.d/alsa-base.conf #set index value -options snd_usb_audio index=-2 +options snd-usb-audio index=0 +options snd_bcm2835 index=1 +#reorder +options snd slots=snd_usb_audio, snd_bcm2835 EOF else echo "Debian Stretch Alsa config" @@ -147,7 +151,7 @@ Conflicts=getty@tty1.service [Service] Type=simple RemainAfterExit=yes -ExecStart=/usr/bin/python3 /home/pi/tarina/tarina.py +ExecStart=/usr/bin/python3 /home/pi/tarina/tarina.py default User=pi Restart=on-failure StandardInput=tty-force diff --git a/tarina.py b/tarina.py @@ -33,12 +33,13 @@ from PIL import Image import smbus import socket import configparser +import secrets #import shlex from blessed import Terminal #if buttons are installed try: - bus = smbus.SMBus(3) # Rev 2 Pi uses 1 + bus = smbus.SMBus(11) # Rev 2 Pi uses 1 DEVICE = 0x20 # Device address (A0-A2) IODIRB = 0x0d # Pin pullups B-side IODIRA = 0x00 # Pin pullups A-side 0x0c @@ -153,10 +154,15 @@ def main(): oldtake = take #TURN OFF WIFI AND TARINA SERVER - serverstate = 'off' - wifistate = 'off' - run_command('sudo iwconfig wlan0 txpower off') - serverstate = tarinaserver(False) + if str(sys.argv[0]) == 'default': + serverstate = 'off' + wifistate = 'off' + run_command('sudo iwconfig wlan0 txpower off') + serverstate = tarinaserver(False) + else: + serverstate = 'off' + wifistate = 'on' + serverstate = tarinaserver(False) foldername = filmfolder + filmname + '/' + 'scene' + str(scene).zfill(3) +'/shot' + str(shot).zfill(3) + '/' filename = 'take' + str(take).zfill(3) @@ -226,6 +232,7 @@ def main(): camera.stop_preview() foldername = filmfolder + filmname + '/' + 'scene' + str(scene).zfill(3) +'/shot' + str(shot).zfill(3) + '/' filename = 'take' + str(take).zfill(3) + compileshot(foldername + filename) playdub(foldername + filename, False, headphoneslevel) imagename = foldername + filename + '.jpeg' overlay = displayimage(camera, imagename) @@ -306,6 +313,11 @@ def main(): filmname = newfilmname os.makedirs(filmfolder + filmname) writemessage('Good luck with your film ' + filmname + '!') + #make a filmhash + print('making filmhash...') + filmhash = secrets.token_urlsafe(16) + with open(filmfolder + filmname + '.filmhash', 'w') as f: + f.write(filmhash) updatethumb = True updatemenu = True scene = 1 @@ -325,13 +337,6 @@ def main(): else: vumetermessage('') - #ADELAY - elif pressed == 'middle' and menu[selected] == 'ADELAY': - foldername = filmfolder + filmname + '/' + 'scene' + str(scene).zfill(3) +'/shot' + str(shot).zfill(3) + '/' - filename = 'take' + str(take).zfill(3) - os.system('cp ' + foldername + filename + '.wav /dev/shm/') - delayerr = audiodelay(foldername,filename) - #YANK(COPY) SHOT elif event == 'Y' and menu[selected] == 'SHOT:' and recordable == False: yankedshot = filmfolder + filmname + '/' + 'scene' + str(scene).zfill(3) +'/shot' + str(shot).zfill(3) @@ -487,7 +492,7 @@ def main(): if os.path.isdir(foldername) == False: os.makedirs(foldername) os.system(tarinafolder + '/alsa-utils-1.1.3/aplay/arecord -D hw:0 -f S16_LE -c 1 -r44100 -vv /dev/shm/' + filename + '.wav &') - camera.start_recording(foldername + filename + '.h264', format='h264', quality=26, bitrate=3000000) + camera.start_recording(foldername + filename + '.h264', format='h264', quality=26, bitrate=5000000) starttime = time.time() recording = True elif recording == True and float(time.time() - starttime) > 0.2: @@ -509,8 +514,9 @@ def main(): vumetermessage('Tarina ' + tarinaversion[:-1] + ' ' + tarinavername[:-1]) thefile = foldername + filename updatethumb = True - compileshot(foldername + filename) - delayerr = audiodelay(foldername,filename) + #compileshot(foldername + filename) + os.system('cp /dev/shm/' + filename + '.wav ' + foldername + filename + '.wav') + #delayerr = audiodelay(foldername,filename) if beeps > 0: buzz(300) #if not in last shot or take then go to it @@ -777,7 +783,7 @@ def main(): logger.info('okey something has changed') foldername = filmfolder + filmname + '/' + 'scene' + str(scene).zfill(3) +'/shot' + str(shot).zfill(3) + '/' filename = 'take' + str(take).zfill(3) - recordable = not os.path.isfile(foldername + filename + '.mp4') + recordable = not os.path.isfile(foldername + filename + '.mp4') and not os.path.isfile(foldername + filename + '.h264') overlay = removeimage(camera, overlay) imagename = filmfolder + filmname + '/scene' + str(scene).zfill(3) + '/shot' + str(shot).zfill(3) + '/take' + str(take).zfill(3) + '.jpeg' overlay = displayimage(camera, imagename) @@ -938,7 +944,7 @@ def countlast(filmname, filmfolder): allfiles = [] takes = 0 for a in allfiles: - if '.mp4' in a: + if '.mp4' in a or '.h264' in a: takes = takes + 1 return scenes, shots, takes @@ -980,7 +986,7 @@ def counttakes(filmname, filmfolder, scene, shot): allfiles = [] return takes for a in allfiles: - if '.mp4' in a: + if '.mp4' in a or '.h264' in a: takes = takes + 1 return takes @@ -1134,7 +1140,8 @@ def getfilms(filmfolder): #-------------Load tarina config--------------- -def getconfig(version): +def getconfig(camera): + version = camera.revision home = os.path.expanduser('~') configfile = home + '/.tarina/config.ini' configdir = os.path.dirname(configfile) @@ -1159,9 +1166,9 @@ def getconfig(version): holdbutton = '' selected = 0 header = 'What revision of ' + version + ' sensor are you using?' - menu = 'rev.C', 'rev.D' + menu = 'rev.C', 'rev.D', 'hq-camera' while True: - settings = '', '' + settings = '', '', '' writemenu(menu,settings,selected,header) pressed, buttonpressed, buttontime, holdbutton, event, keydelay = getbutton(pressed, buttonpressed, buttontime, holdbutton) if pressed == 'right': @@ -1350,7 +1357,7 @@ def timelapse(beeps,camera,foldername,filename): if recording == False and t > between: if beeps > 0: buzz(150) - camera.start_recording(foldername + 'timelapse/' + filename + '_' + str(n).zfill(3) + '.h264', format='h264', quality=26, bitrate=3000000) + camera.start_recording(foldername + 'timelapse/' + filename + '_' + str(n).zfill(3) + '.h264', format='h264', quality=26, bitrate=5000000) if sound == True: os.system(tarinafolder + '/alsa-utils-1.1.3/aplay/arecord -D hw:0 -f S16_LE -c 1 -r 44100 -vv /dev/shm/' + filename + '_' + str(n).zfill(3) + '.wav &') files.append(foldername + 'timelapse/' + filename + '_' + str(n).zfill(3)) @@ -1445,7 +1452,7 @@ def remove(filmfolder, filmname, scene, shot, take, sceneshotortake): elif pressed == 'middle': if selected == 1: if sceneshotortake == 'take': - #os.system('rm ' + foldername + filename + '.h264') + os.system('rm ' + foldername + filename + '.h264') os.system('rm ' + foldername + filename + '.mp4') os.system('rm ' + foldername + filename + '.wav') os.system('rm ' + foldername + filename + '.jpeg') @@ -1489,9 +1496,9 @@ def organize(filmfolder, filmname): os.system('rm -r ' + filmfolder + filmname + '/' + i + '/' + p) organized_nr = 1 for s in sorted(takes): - if '.mp4' in s: + if '.mp4' in s or '.h264' in s: #print(s) - unorganized_nr = int(s[4:-4]) + unorganized_nr = int(s[4:7]) if organized_nr == unorganized_nr: #print('correct') pass @@ -1499,6 +1506,7 @@ def organize(filmfolder, filmname): #print('false, correcting from ' + str(unorganized_nr) + ' to ' + str(organized_nr)) mv = 'mv ' + filmfolder + filmname + '/' + i + '/' + p + '/take' + str(unorganized_nr).zfill(3) run_command(mv + '.mp4 ' + filmfolder + filmname + '/' + i + '/' + p + '/take' + str(organized_nr).zfill(3) + '.mp4') + run_command(mv + '.h264 ' + filmfolder + filmname + '/' + i + '/' + p + '/take' + str(organized_nr).zfill(3) + '.h264') run_command(mv + '.wav ' + filmfolder + filmname + '/' + i + '/' + p + '/take' + str(organized_nr).zfill(3) + '.wav') run_command(mv + '.jpeg ' + filmfolder + filmname + '/' + i + '/' + p + '/take' + str(organized_nr).zfill(3) + '.jpeg') organized_nr += 1 @@ -1610,6 +1618,7 @@ def compileshot(filename): else: writemessage('Converting to playable video') run_command('MP4Box -fps 25 -add ' + filename + '.h264 ' + filename + '.mp4') + delayerr = audiodelay(filename) os.system('rm ' + filename + '.h264') #run_command('omxplayer --layer 3 ' + filmfolder + '/.rendered/' + filename + '.mp4 &') #time.sleep(0.8) @@ -1740,6 +1749,7 @@ def renderscene(filmfolder, filmname, scene): # Video Hash for p in filmfiles: + compileshot(p) videohash = videohash + str(int(countsize(p + '.mp4'))) print('Videohash of scene is: ' + videohash) try: @@ -1809,6 +1819,7 @@ def renderfilm(filmfolder, filmname, comp): filmdir = filmfolder + filmname + '/' for p in filmfiles: print(p) + compileshot(p) videohash += str(int(countsize(p + '.mp4'))) print('Videohash of film is: ' + videohash) try: @@ -2270,11 +2281,11 @@ def viewfilm(filmfolder, filmname): #--------------Audiodelay-------------------- # make audio file same lenght as video file -def audiodelay(foldername, filename): +def audiodelay(filename): writemessage('Audio syncing..') - pipe = subprocess.check_output('mediainfo --Inform="Video;%Duration%" ' + foldername + filename + '.mp4', shell=True) + pipe = subprocess.check_output('mediainfo --Inform="Video;%Duration%" ' + filename + '.mp4', shell=True) videolenght = pipe.decode().strip() - pipe = subprocess.check_output('mediainfo --Inform="Audio;%Duration%" /dev/shm/' + filename + '.wav', shell=True) + pipe = subprocess.check_output('mediainfo --Inform="Audio;%Duration%" ' + filename + '.wav', shell=True) audiolenght = pipe.decode().strip() #if there is no audio lenght logger.info('audio is:' + audiolenght) @@ -2291,9 +2302,9 @@ def audiodelay(foldername, filename): newaudiolenght = int(audiolenght) - audiosync logger.info('Audiofile is: ' + str(audiosync) + 'ms longer') #trim from end and put a 0.01 in- and outfade - run_command('sox -V0 /dev/shm/' + filename + '.wav ' + foldername + filename + '_temp.wav trim 0 -' + str(int(audiosync)/1000)) - run_command('sox -V0 -G ' + foldername + filename + '_temp.wav ' + foldername + filename + '.wav fade 0.01 0 0.01') - os.remove(foldername + filename + '_temp.wav') + run_command('sox -V0 ' + filename + '.wav ' + filename + '_temp.wav trim 0 -' + str(int(audiosync)/1000)) + run_command('sox -V0 -G ' + filename + '_temp.wav ' + filename + '.wav fade 0.01 0 0.01') + os.remove(filename + '_temp.wav') #if int(audiosync) > 400: # writemessage('WARNING!!! VIDEO FRAMES DROPPED!') # vumetermessage('Consider changing to a faster microsd card.') @@ -2309,15 +2320,15 @@ def audiodelay(foldername, filename): # audiosyncms = 1000 + audiosyncms logger.info('Videofile is: ' + str(audiosync) + 'ms longer') #make fade - run_command('sox -V0 -G /dev/shm/' + filename + '.wav ' + foldername + filename + '_temp.wav fade 0.01 0 0.01') + run_command('sox -V0 -G ' + filename + '.wav ' + filename + '_temp.wav fade 0.01 0 0.01') #make delay file run_command('sox -V0 -n -r 44100 -c 1 /dev/shm/silence.wav trim 0.0 ' + str(int(audiosync)/1000)) #add silence to end - run_command('sox -V0 /dev/shm/silence.wav ' + foldername + filename + '_temp.wav ' + foldername + filename + '.wav') - os.remove(foldername + filename + '_temp.wav') + run_command('sox -V0 /dev/shm/silence.wav ' + filename + '_temp.wav ' + filename + '.wav') + os.remove(filename + '_temp.wav') os.remove('/dev/shm/silence.wav') delayerr = 'V' + str(audiosync) - os.remove('/dev/shm/' + filename + '.wav') + #os.remove('/dev/shm/' + filename + '.wav') return delayerr #os.system('mv audiosynced.wav ' + filename + '.wav') #os.system('rm silence.wav') @@ -2346,6 +2357,7 @@ def copytousb(filmfolder): buttontime = time.time() holdbutton = '' writemessage('Searching for usb storage device, middlebutton to cancel') + films = getfilms(filmfolder) while True: pressed, buttonpressed, buttontime, holdbutton, event, keydelay = getbutton(pressed, buttonpressed, buttontime, holdbutton) usbconnected = os.path.ismount('/media/usb0') @@ -2363,19 +2375,58 @@ def copytousb(filmfolder): try: p = subprocess.check_output('stat -f -c %T /media/usb0', shell=True) filesystem = p.decode() - writemessage('Copying files...') - run_command('rsync -avr -P ' + filmfolder + '* /media/usb0/tarinafilms/') - run_command('sync') - run_command('pumount /media/usb0') - writemessage('all files copied successfully!') - waitforanykey() - writemessage('You can safely unplug the usb device now') - time.sleep(2) - return + print('filesystem info: ' + filesystem) except: - writemessage('Nope! something wrong with ur drive :(') + writemessage('Oh-no! dont know your filesystem') waitforanykey() return + for filmname in films: + #check filmhash + filmname = filmname[0] + usbpath = '/media/usb0/tarinafilms/'+filmname + usbfilmhash = '' + filmhash = '' + while True: + if os.path.exists(usbpath) == False: + break + try: + with open(filmfolder + filmname + '/.filmhash', 'r') as f: + filmhash = f.readline().strip() + print('filmhash is: ' + filmhash) + except: + print('no filmhash found!') + try: + with open(usbpath + '/.filmhash', 'r') as f: + usbfilmhash = f.readline().strip() + print('usbfilmhash is: ' + usbfilmhash) + except: + print('no usbfilmhash found!') + if usbfilmhash == filmhash: + print('same moviefilm found, updating clips...') + break + else: + writemessage('Found a subsequent moviefilm...') + print('same film exist with different filmhashes, copying to subsequent film folder') + time.sleep(2) + usbpath += '_new' + try: + os.makedirs(usbpath) + writemessage('Copying film ' + filmname + '...') + except: + writemessage('Found existing ' + filmname + ', copying new files... ') + try: + run_command('rsync -avr -P ' + filmfolder + filmname + '/ ' + usbpath) + except: + writemessage('couldnt copy film ' + filmname) + waitforanykey() + return + run_command('sync') + run_command('pumount /media/usb0') + writemessage('all files copied successfully!') + waitforanykey() + writemessage('You can safely unplug the usb device now') + time.sleep(2) + return #-----------Check for the webz--------- @@ -2383,7 +2434,7 @@ def webz_on(): try: # connect to the host -- tells us if the host is actually # reachable - socket.create_connection(("www.google.com", 80)) + socket.create_connection(("google.com", 80)) return True except OSError: pass @@ -2520,10 +2571,10 @@ def getbutton(lastbutton, buttonpressed, buttontime, holdbutton): val = term.inkey(timeout=0) if val.is_sequence: event = val.name - print(event) + #print(event) elif val: event = val - print(event) + #print(event) else: event = '' keydelay = 0.08 @@ -2589,16 +2640,18 @@ def startcamera(lens): #lensshade = '' #npzfile = np.load('lenses/' + lens) #lensshade = npzfile['lens_shading_table'] - table = read_table('lenses/' + lens) #camera.framerate = 24.999 - v = camera.revision - camera_model, camera_revision = getconfig(v) + camera_model, camera_revision = getconfig(camera) # v1 = 'ov5647' # v2 = ? logger.info("picamera version is: " + camera_model + ' ' + camera_revision) if camera_model == 'imx219': + table = read_table('lenses/' + lens) + camera.lens_shading_table = table camera.framerate = 24.999 if camera_model == 'ov5647': + table = read_table('lenses/' + lens) + camera.lens_shading_table = table # Different versions of ov5647 with different clock speeds, need to make a config file # if there's more frames then the video will be longer when converting it to 25 fps, # I try to get it as perfect as possible with trial and error. @@ -2608,12 +2661,13 @@ def startcamera(lens): # ov5647 Rev D" if camera_revision == 'rev.D': camera.framerate = 23.15 + else: + camera.framerate = 24.999 camera.crop = (0, 0, 1.0, 1.0) camera.video_stabilization = True camera.led = False #lens_shading_table = np.zeros(camera._lens_shading_table_shape(), dtype=np.uint8) + 32 #camera.lens_shading_table = lens_shading_table - camera.lens_shading_table = table camera.start_preview() camera.awb_mode = 'auto' return camera