tarina

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

commit 4f9105eea4c731c150e11c6f870848f672b31e9e
parent abbd596011e09f661eab0033999f5fb43ae3e56f
Author: rbckman <rob@tarina.org>
Date:   Thu, 14 Apr 2022 11:52:28 +0100

binned 2028x1080 as standard mode for video, hide/show menu, shut screen power on off

Diffstat:
Aextras/h264streamer.py | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mgui/src/main.c | 54++++++++++++++++++++++++++++++++++++------------------
Mgui/tarinagui.bin | 0
Mtarina.py | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
4 files changed, 164 insertions(+), 36 deletions(-)

diff --git a/extras/h264streamer.py b/extras/h264streamer.py @@ -0,0 +1,64 @@ +import io +import picamerax as picamera +import time +from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer +from wsgiref.simple_server import make_server +from ws4py.websocket import WebSocket +from ws4py.server.wsgirefserver import WSGIServer, WebSocketWSGIHandler, WebSocketWSGIRequestHandler +from ws4py.server.wsgiutils import WebSocketWSGIApplication +from threading import Thread, Condition + + +class FrameBuffer(object): + def __init__(self): + self.frame = None + self.buffer = io.BytesIO() + self.condition = Condition() + + def write(self, buf): + if buf.startswith(b'\x00\x00\x00\x01'): + with self.condition: + self.buffer.seek(0) + self.buffer.write(buf) + self.buffer.truncate() + self.frame = self.buffer.getvalue() + self.condition.notify_all() + + +def stream(): + with picamera.PiCamera(resolution='1920x816', framerate=25) as camera: + broadcasting = True + frame_buffer = FrameBuffer() + camera.start_recording(frame_buffer, format='h264', profile="baseline") + try: + WebSocketWSGIHandler.http_version = '1.1' + websocketd = make_server('', 9000, server_class=WSGIServer, + handler_class=WebSocketWSGIRequestHandler, + app=WebSocketWSGIApplication(handler_cls=WebSocket)) + websocketd.initialize_websockets_manager() + websocketd_thread = Thread(target=websocketd.serve_forever) + + httpd = ThreadingHTTPServer(('', 8000), SimpleHTTPRequestHandler) + httpd_thread = Thread(target=httpd.serve_forever) + + try: + websocketd_thread.start() + httpd_thread.start() + while broadcasting: + with frame_buffer.condition: + frame_buffer.condition.wait() + websocketd.manager.broadcast(frame_buffer.frame, binary=True) + except KeyboardInterrupt: + pass + finally: + websocketd.shutdown() + httpd.shutdown() + broadcasting = False + raise KeyboardInterrupt + except KeyboardInterrupt: + pass + finally: + camera.stop_recording() + +if __name__ == "__main__": + stream() diff --git a/gui/src/main.c b/gui/src/main.c @@ -44,12 +44,20 @@ int32_t render_subtitle(GRAPHICS_RESOURCE_HANDLE img, const char *text, const ui graphics_get_resource_size(img, &img_w, &img_h); // split now points to last line of text. split-text = length of initial text. text_length-(split-text) is length of last line + if (fontcolor == 6) { + graphics_resource_render_text_ext(img, x_offset, y_offset-height, + GRAPHICS_RESOURCE_WIDTH, + GRAPHICS_RESOURCE_HEIGHT, + GRAPHICS_RGBA32(225,255,255,0), /* fg */ + GRAPHICS_RGBA32(0,0,0,0), /* bg */ + text, 80, text_size); + } if (fontcolor == 5) { graphics_resource_render_text_ext(img, x_offset, y_offset-height, GRAPHICS_RESOURCE_WIDTH, GRAPHICS_RESOURCE_HEIGHT, GRAPHICS_RGBA32(225,255,255,0xff), /* fg */ - GRAPHICS_RGBA32(0,0,0,0xff), /* bg */ + GRAPHICS_RGBA32(0,0,0,150), /* bg */ text, 80, text_size); } if (fontcolor == 4) { @@ -57,7 +65,7 @@ int32_t render_subtitle(GRAPHICS_RESOURCE_HANDLE img, const char *text, const ui GRAPHICS_RESOURCE_WIDTH, GRAPHICS_RESOURCE_HEIGHT, GRAPHICS_RGBA32(30,255,255,0xff), /* fg */ - GRAPHICS_RGBA32(0,0,0,0xff), /* bg */ + GRAPHICS_RGBA32(0,0,0,150), /* bg */ text, 80, text_size); } if (fontcolor == 3) { @@ -65,7 +73,7 @@ int32_t render_subtitle(GRAPHICS_RESOURCE_HANDLE img, const char *text, const ui GRAPHICS_RESOURCE_WIDTH, GRAPHICS_RESOURCE_HEIGHT, GRAPHICS_RGBA32(30,30,255,0xff), /* fg */ - GRAPHICS_RGBA32(0,0,0,0xff), /* bg */ + GRAPHICS_RGBA32(0,0,0,150), /* bg */ text, 80, text_size); } if (fontcolor == 2) { @@ -73,7 +81,7 @@ int32_t render_subtitle(GRAPHICS_RESOURCE_HANDLE img, const char *text, const ui GRAPHICS_RESOURCE_WIDTH, GRAPHICS_RESOURCE_HEIGHT, GRAPHICS_RGBA32(30,255,30,0xff), /* fg */ - GRAPHICS_RGBA32(0,0,0,0xff), /* bg */ + GRAPHICS_RGBA32(0,0,0,150), /* bg */ text, 80, text_size); } if (fontcolor == 1) { @@ -119,6 +127,8 @@ int main(void) ssize_t read = 0; int linenr = 0; int selected; + int showmenu; + int menuadd = 1; char newread[500]; char oldread[500]; char vumeter[130]; @@ -147,7 +157,7 @@ int main(void) // selected 0 1 2 3 4 5 6 7 8 int space = 10; int morespace = 12; - int color = 5; + int color = 3; int row1 = 0; int row2 = 0; int row3 = 0; @@ -164,42 +174,50 @@ int main(void) //printf("%s",line); if (linenr == 0) selected = atoi(line); - if (linenr == selected + 2) + if (linenr == 1) + showmenu = atoi(line); + if (linenr == selected + 2 + menuadd) color = 1; //selected color else - color = 5; //unselected - if ((linenr == 1) && (read > 0)) + if (showmenu == 1) + color = 5; //unselected; + else + color = 6; + if ((linenr == 1 + menuadd) && (read > 0)) header = 1; //write header menu - if ((linenr == 1) && (read == 0)) + if ((linenr == 1 + menuadd) && (read == 0)) header = 0; //write normal menu if (header == 0) { - if ((linenr == 6) && (read > 0)) //show recording time if there is any - render_subtitle(img, line, text_size, 700, y_offset3, 3); - if (linenr >= 2 && linenr <= 5){ + if ((linenr == 6 + menuadd) && (read > 0)){ //show recording time if there is any + render_subtitle(img, line, text_size, 700, y_offset2, 3); + } + if (linenr >= 2 + menuadd && linenr <= 5 + menuadd){ + if (color == 6) + color = 2; render_subtitle(img, line, text_size, row1, y_offset2, color); row1 += read * space + morespace; } - if (linenr >= 7 && linenr <= 12){ + if (linenr >= 7+menuadd && linenr <= 12+menuadd){ render_subtitle(img, line, text_size, row2, y_offset3, color); row2 += read * space + morespace; } - if (linenr >= 13 && linenr <= 20){ + if (linenr >= 13+menuadd && linenr <= 20+menuadd){ render_subtitle(img, line, text_size, row3, y_offset4, color); row3 += read * space + morespace; } - if (linenr >= 21 && linenr <= 27){ + if (linenr >= 21+menuadd && linenr <= 27+menuadd){ render_subtitle(img, line, text_size, row4, y_offset5, color); row4 += read * space + morespace; } - if (linenr >= 28 && linenr <= 40){ + if (linenr >= 28+menuadd && linenr <= 40+menuadd){ render_subtitle(img, line, text_size, row5, y_offset6, color); row5 += read * space + morespace; } } if (header == 1) { - if (linenr == 1) + if (linenr == 1+menuadd) render_subtitle(img, line, text_size, 0, y_offset2, 5); - if (linenr > 1) { + if (linenr > 1+menuadd) { render_subtitle(img, line, text_size, row1, y_offset3, color); row1 += read * space + morespace; } diff --git a/gui/tarinagui.bin b/gui/tarinagui.bin Binary files differ. diff --git a/tarina.py b/tarina.py @@ -74,7 +74,7 @@ while probei2c < 10: #MAIN def main(): - global headphoneslevel, miclevel, tarinafolder, screen, loadfilmsettings, plughw, channels, filmfolder, filmname, scene + global headphoneslevel, miclevel, tarinafolder, screen, loadfilmsettings, plughw, channels, filmfolder, filmname, scene, showmenu # Get path of the current dir, then use it as working directory: rundir = os.path.dirname(__file__) if rundir != '': @@ -84,6 +84,7 @@ def main(): if os.path.isdir(filmfolder) == False: os.makedirs(filmfolder) tarinafolder = os.getcwd() + #MENUS menu = 'FILM:', 'SCENE:', 'SHOT:', 'TAKE:', '', 'SHUTTER:', 'ISO:', 'RED:', 'BLUE:', 'FPS:', 'Q:', 'BRIGHT:', 'CONT:', 'SAT:', 'FLIP:', 'BEEP:', 'LENGTH:', 'HW:', 'CH:', 'MIC:', 'PHONES:', 'COMP:', 'TIMELAPSE', 'LENS:', 'DSK:', 'SHUTDOWN', 'SRV:', 'WIFI:', 'UPDATE', 'UPLOAD', 'BACKUP', 'LOAD', 'NEW', 'TITLE', 'LIVE:' #STANDARD VALUES (some of these may not be needed, should do some clean up) @@ -102,7 +103,9 @@ def main(): retake = False lastmenu = '' rendermenu = True + showmenu = 1 overlay = None + underlay = None reclenght = 0 t = 0 rectime = '' @@ -150,12 +153,16 @@ def main(): run_command('tvservice -o') #Kernel page cache optimization for sd card run_command('sudo ' + tarinafolder + '/extras/sdcardhack.sh') + #Make screen shut off work and run full brightness + run_command('gpio -g mode 19 pwm ') + run_command('gpio -g pwm 19 1023') #COUNT DISKSPACE disk = os.statvfs(filmfolder) diskleft = str(int(disk.f_bavail * disk.f_frsize / 1024 / 1024 / 1024)) + 'Gb' #START INTERFACE startinterface() camera = startcamera(lens,fps) + #LOAD FILM AND SCENE SETTINGS try: filmname = getfilms(filmfolder)[0][0] @@ -198,7 +205,7 @@ def main(): peakshot = shot - 1 peaktake = counttakes(filmname, filmfolder, scene, peakshot) p_imagename = filmfolder + filmname + '/scene' + str(scene).zfill(3) + '/shot' + str(peakshot).zfill(3) + '/take' + str(peaktake).zfill(3) + '.jpeg' - overlay = displayimage(camera, p_imagename, overlay) + overlay = displayimage(camera, p_imagename, overlay, 3) while holdbutton == 'peak': pressed, buttonpressed, buttontime, holdbutton, event, keydelay = getbutton(pressed, buttonpressed, buttontime, holdbutton) writemessage('peaking ' + str(peakshot)) @@ -264,7 +271,7 @@ def main(): trim_filename = foldername + 'take' + str(take).zfill(3) videotrim(foldername + filename, trim_filename, trim[0], trim[1]) imagename = foldername + filename + '.jpeg' - overlay = displayimage(camera, imagename, overlay) + overlay = displayimage(camera, imagename, overlay, 3) camera.start_preview() #DUB SHOT elif pressed == 'middle' and menu[selected] == 'SHOT:': @@ -522,6 +529,12 @@ def main(): elif backlight == True: run_command('gpio -g pwm 19 0') backlight = False + elif pressed == 'showmenu': + if showmenu == 1: + # requires wiringpi installed + showmenu = 0 + elif showmenu == 0: + showmenu = 1 #REMOVE #take elif pressed == 'remove' and menu[selected] == 'TAKE:': @@ -585,9 +598,10 @@ def main(): if os.path.isdir(foldername) == False: os.makedirs(foldername) os.system(tarinafolder + '/alsa-utils-1.1.3/aplay/arecord -D plughw:' + str(plughw) + ' -f S16_LE -c ' + str(channels) + ' -r44100 -vv /dev/shm/' + filename + '.wav &') - camera.start_recording(foldername + filename + '.h264', format='h264', quality=quality) + camera.start_recording(foldername + filename + '.h264', format='h264', quality=quality, level='4.2') starttime = time.time() recording = True + showmenu = 0 elif beepcountdown > 0 and beeping == True: beeping = False beepcountdown = 0 @@ -596,6 +610,7 @@ def main(): disk = os.statvfs(tarinafolder + '/') diskleft = str(int(disk.f_bavail * disk.f_frsize / 1024 / 1024 / 1024)) + 'Gb' recording = False + showmenu = 1 camera.stop_recording() #time.sleep(0.005) #get audio at least 0.1 longer os.system('pkill arecord') @@ -990,7 +1005,7 @@ def main(): p = counttakes(filmname, filmfolder, 1, 1) imagename = filmfolder + filmname + '/scene' + str(1).zfill(3) + '/shot' + str(1).zfill(3) + '/take' + str(p).zfill(3) + '.jpeg' imagename = filmfolder + filmname + '/scene' + str(scene).zfill(3) + '/shot' + str(shot).zfill(3) + '/take' + str(take).zfill(3) + '.jpeg' - overlay = displayimage(camera, imagename, overlay) + overlay = displayimage(camera, imagename, overlay, 3) oldscene = scene oldshot = shot oldtake = take @@ -1018,7 +1033,7 @@ def main(): if buttonpressed == True or recording == True or rendermenu == True: lastmenu = menu[selected] settings = filmname, str(scene) + '/' + str(scenes), str(shot) + '/' + str(shots), str(take) + '/' + str(takes), rectime, camerashutter, cameraiso, camerared, camerablue, str(camera.framerate), str(quality), str(camera.brightness), str(camera.contrast), str(camera.saturation), str(flip), str(beeps), str(reclenght), str(plughw), str(channels), str(miclevel), str(headphoneslevel), str(comp), '', lens, diskleft, '', serverstate, wifistate, '', '', '', '', '', '', live - writemenu(menu,settings,selected,'') + writemenu(menu,settings,selected,'',showmenu) #Rerender menu if picamera settings change if settings != oldsettings: rendermenu = True @@ -1069,9 +1084,10 @@ def loadsettings(filmfolder, filmname): #--------------Write the menu layer to dispmanx-------------- -def writemenu(menu,settings,selected,header): +def writemenu(menu,settings,selected,header,showmenu): menudone = '' menudone += str(selected) + '\n' + menudone += str(showmenu) + '\n' menudone += header + '\n' for i, s in zip(menu, settings): menudone += i + s + '\n' @@ -1214,9 +1230,33 @@ def run_command(command_line): logger.info('Process finished') return True +#-------------Display bakg------------------- + +def displaybakg(camera, filename, underlay, layer): + # Load the arbitrarily sized image + img = Image.open(filename) + # Create an image padded to the required size with + # mode 'RGB' + pad = Image.new('RGB', ( + ((img.size[0] + 31) // 32) * 32, + ((img.size[1] + 15) // 16) * 16, + )) + # Paste the original image into the padded one + pad.paste(img, (0, 0)) + + # Add the overlay with the padded image as the source, + # but the original image's dimensions + underlay = camera.add_overlay(pad.tobytes(), size=img.size) + # By default, the overlay is in layer 0, beneath the + # preview (which defaults to layer 2). Here we make + # the new overlay semi-transparent, then move it above + # the preview + underlay.alpha = 255 + underlay.layer = layer + #-------------Display jpeg------------------- -def displayimage(camera, filename, overlay): +def displayimage(camera, filename, overlay, layer): # Load the arbitrarily sized image try: img = Image.open(filename) @@ -1242,7 +1282,7 @@ def displayimage(camera, filename, overlay): # the new overlay semi-transparent, then move it above # the preview overlay.alpha = 255 - overlay.layer = 3 + overlay.layer = layer return overlay def removeimage(camera, overlay): @@ -1385,7 +1425,7 @@ def getconfig(camera): menu = 'rev.C', 'rev.D', 'hq-camera' while True: settings = '', '', '' - writemenu(menu,settings,selected,header) + writemenu(menu,settings,selected,header,showmenu) pressed, buttonpressed, buttontime, holdbutton, event, keydelay = getbutton(pressed, buttonpressed, buttontime, holdbutton) if pressed == 'right': if selected < (len(settings) - 1): @@ -1419,7 +1459,7 @@ def loadfilm(filmname, filmfolder): menu = 'FILM:', 'BACK' while True: settings = films[selectedfilm][0], '' - writemenu(menu,settings,selected,header) + writemenu(menu,settings,selected,header,showmenu) pressed, buttonpressed, buttontime, holdbutton, event, keydelay = getbutton(pressed, buttonpressed, buttontime, holdbutton) if pressed == 'down': if selectedfilm < filmstotal: @@ -1530,7 +1570,7 @@ def timelapse(beeps,camera,foldername,filename,between,duration): menu = 'DELAY:', 'DURATION:', 'START', 'BACK' while True: settings = str(round(between,2)), str(round(duration,2)), '', '' - writemenu(menu,settings,selected,header) + writemenu(menu,settings,selected,header,showmenu) seconds = (3600 / between) * duration vumetermessage('1 h timelapse filming equals ' + str(round(seconds,2)) + ' second clip ') pressed, buttonpressed, buttontime, holdbutton, event, keydelay = getbutton(pressed, buttonpressed, buttontime, holdbutton) @@ -1656,7 +1696,7 @@ def remove(filmfolder, filmname, scene, shot, take, sceneshotortake): settings = 'NO', 'YES' selected = 0 while True: - writemenu(menu,settings,selected,header) + writemenu(menu,settings,selected,header,showmenu) pressed, buttonpressed, buttontime, holdbutton, event, keydelay = getbutton(pressed, buttonpressed, buttontime, holdbutton) if pressed == 'right': if selected < (len(settings) - 1): @@ -2309,7 +2349,7 @@ def removedub(dubfolder, dubnr): menu = 'NO', 'YES' settings = '', '' while True: - writemenu(menu,settings,selected,header) + writemenu(menu,settings,selected,header,showmenu) pressed, buttonpressed, buttontime, holdbutton, event, keydelay = getbutton(pressed, buttonpressed, buttontime, holdbutton) if pressed == 'right': if selected < (len(menu) - 1): @@ -2393,7 +2433,7 @@ def clipsettings(filmfolder, filmname, scene, shot, plughw): else: menu = 'BACK', 'ADD:', '', '' settings = '', 'd:' + str(nmix) + '/o:' + str(ndub), 'in:' + str(nfadein), 'out:' + str(nfadeout) - writemenu(menu,settings,selected,header) + writemenu(menu,settings,selected,header,showmenu) pressed, buttonpressed, buttontime, holdbutton, event, keydelay = getbutton(pressed, buttonpressed, buttontime, holdbutton) #NEW DUB SETTINGS @@ -2604,7 +2644,7 @@ def playdub(filename, player_menu): header = 'Dubbing ' + str(round(t,1)) else: header = 'Playing ' + str(round(t,1)) + ' of ' + str(clipduration) + ' s' - writemenu(menu,settings,selected,header) + writemenu(menu,settings,selected,header,showmenu) pressed, buttonpressed, buttontime, holdbutton, event, keydelay = getbutton(pressed, buttonpressed, buttontime, holdbutton) if buttonpressed == True: flushbutton() @@ -2975,7 +3015,7 @@ def uploadfilm(filename, filmname): selected = 0 while True: header = 'Where do you want to upload?' - writemenu(menu,settings,selected,header) + writemenu(menu,settings,selected,header,showmenu) pressed, buttonpressed, buttontime, holdbutton, event, keydelay = getbutton(pressed, buttonpressed, buttontime, holdbutton) if pressed == 'right': if selected < (len(menu) - 1): @@ -3191,6 +3231,8 @@ def getbutton(lastbutton, buttonpressed, buttontime, holdbutton): pressed = 'peak' elif (readbus2 == 245 and readbus == 223): pressed = 'screen' + elif (readbus2 == 245 and readbus == 247): + pressed = 'showmenu' elif event == 'I' or event == 'P' or (readbus2 == 244 and readbus == 255): pressed = 'insert' elif event == 'C' or (readbus2 == 245 and readbus == 254): @@ -3233,7 +3275,11 @@ def stopinterface(camera): def startcamera(lens, fps): camera = picamera.PiCamera() - camera.resolution = (1920, 1080) #tested modes 1920x816, 1296x552/578, v2 1640x698, 1640x1232 + camera.resolution = (2028, 1080) #tested modes 1920x816, 1296x552/578, v2 1640x698, 1640x1232, hqbinned 2028x1080 + #Background image + underlay = None + bakgimg = tarinafolder + '/extras/bakg.jpg' + displaybakg(camera, bakgimg, underlay, 2) #lensshade = '' #npzfile = np.load('lenses/' + lens) #lensshade = npzfile['lens_shading_table']