Files @ 19c2e6216cf8
Branch filter:

Location: light9/bin/vidref - annotation

Drew Perttula
support disconnect() on a reconnectingWebSocket to make it stop connecting
Ignore-this: db2fa6ff2ccdeadecf1fc7a1d144535c
b5efddd80dad
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
0dc3715050cf
0dc3715050cf
6f49dc917aa3
6f49dc917aa3
d96c09669b40
6f49dc917aa3
1d9547f90737
6f49dc917aa3
6f49dc917aa3
087f6cbe4b22
3c523c71da29
1d9547f90737
6f49dc917aa3
6fa4288da8a6
6f49dc917aa3
cfd5d5be1b50
cfd5d5be1b50
7772cc48e016
cfd5d5be1b50
cfd5d5be1b50
2ee97997ee56
6f1eb6437c96
7772cc48e016
1d9547f90737
7772cc48e016
1d9547f90737
1d9547f90737
1d9547f90737
1d9547f90737
1d9547f90737
1d9547f90737
1d9547f90737
1d9547f90737
1d9547f90737
1d9547f90737
7772cc48e016
1d9547f90737
1d9547f90737
1d9547f90737
3c523c71da29
1d9547f90737
1d9547f90737
1d9547f90737
1d9547f90737
7772cc48e016
6f49dc917aa3
0dc3715050cf
82e98aa4d159
0dc3715050cf
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
0dc3715050cf
0dc3715050cf
6f49dc917aa3
0dc3715050cf
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
0dc3715050cf
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
1d9547f90737
1d9547f90737
1d9547f90737
6b5e079b3dbe
6b5e079b3dbe
7772cc48e016
6b5e079b3dbe
6b5e079b3dbe
6b5e079b3dbe
6b5e079b3dbe
6b5e079b3dbe
6b5e079b3dbe
6b5e079b3dbe
6b5e079b3dbe
0dc3715050cf
0dc3715050cf
0dc3715050cf
087f6cbe4b22
1d9547f90737
7772cc48e016
7772cc48e016
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
157985a971dc
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
157985a971dc
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
6f49dc917aa3
1d9547f90737
b0337e6f68f1
89adbbb06bcd
#!bin/python
"""
Camera images of the stage. View live on a web page and also save
them to disk. Retrieve images based on the song and time that was
playing when they were taken. Also, save snapshot images to a place
they can be used again as thumbnails of effects.

bin/vidref main
light9/vidref/videorecorder.py capture frames and save them
light9/vidref/replay.py backend for vidref.js playback element- figures out which frames go with the current song and time
light9/vidref/index.html web ui for watching current stage and song playback
light9/vidref/setup.html web ui for setup of camera params and frame crop
light9/web/light9-vidref-live.js LitElement for live video frames
light9/web/light9-vidref-playback.js LitElement for video playback

"""
from run_local import log

from twisted.internet import reactor, defer

import logging, optparse, json, base64
import cyclone.web, cyclone.httpclient, cyclone.websocket
from light9 import networking
from light9.vidref.replay import snapshotDir
from light9.vidref import videorecorder
from rdfdb.syncedgraph import SyncedGraph
from io import BytesIO

parser = optparse.OptionParser()
parser.add_option("-v", "--verbose", action="store_true", help="logging.DEBUG")
(options, args) = parser.parse_args()

log.setLevel(logging.DEBUG if options.verbose else logging.INFO)


class Snapshot(cyclone.web.RequestHandler):

    @defer.inlineCallbacks
    def post(self):
        # save next pic
        # return /snapshot/path
        try:
            outputFilename = yield self.settings.gui.snapshot()

            assert outputFilename.startswith(snapshotDir())
            out = networking.vidref.path(
                "snapshot/%s" % outputFilename[len(snapshotDir()):].lstrip('/'))

            self.write(json.dumps({'snapshot': out}))
            self.set_header("Location", out)
            self.set_status(303)
        except Exception:
            import traceback
            traceback.print_exc()
            raise


pipeline = videorecorder.GstSource(
    '/dev/v4l/by-id/usb-Bison_HD_Webcam_200901010001-video-index0'
    #    '/dev/v4l/by-id/usb-Generic_FULL_HD_1080P_Webcam_200901010001-video-index0'
)


class Live(cyclone.websocket.WebSocketHandler):

    def connectionMade(self, *args, **kwargs):
        pipeline.liveImages.subscribe(on_next=self.onFrame)

    def connectionLost(self, reason):
        0  #self.subj.dispose()

    def onFrame(self, cf: videorecorder.CaptureFrame):
        if cf is None: return
        output = BytesIO()
        cf.img.save(output, 'jpeg', quality=80)

        self.sendMessage(
            json.dumps({
                'jpeg':
                base64.b64encode(output.getvalue()).decode('ascii'),
                'description':
                f't={cf.t}',
            }))


class SnapshotPic(cyclone.web.StaticFileHandler):
    pass


class Time(cyclone.web.RequestHandler):

    def put(self):
        body = json.loads(self.request.body)
        t = body['t']
        source = body['source']
        self.settings.gui.incomingTime(t, source)
        self.set_status(202)


#graph = SyncedGraph(networking.rdfdb.url, "vidref")
outVideos = videorecorder.FramesToVideoFiles(pipeline.liveImages)
#outVideos.save('/tmp/mov1')

port = networking.vidref.port
reactor.listenTCP(
    port,
    cyclone.web.Application(
        handlers=[
            (r'/()', cyclone.web.StaticFileHandler, {
                'path': 'light9/vidref',
                'default_filename': 'index.html'
            }),
            (r'/setup/()', cyclone.web.StaticFileHandler, {
                'path': 'light9/vidref',
                'default_filename': 'setup.html'
            }),
            (r'/live', Live),
            (r'/snapshot', Snapshot),
            (r'/snapshot/(.*)', SnapshotPic, {
                "path": snapshotDir()
            }),
            (r'/time', Time),
        ],
        debug=True,
    ))
log.info("serving on %s" % port)

reactor.run()