Changeset - df28c994365d
[Not reviewed]
default
0 2 0
drewp@bigasterisk.com - 6 years ago 2019-06-08 07:46:59
drewp@bigasterisk.com
different camera and crop settings for prod
Ignore-this: 8541c1fbd9820dbc8cfb4818de86b7d6
2 files changed with 7 insertions and 7 deletions:
0 comments (0 inline, 0 general)
bin/vidref
Show inline comments
 
@@ -49,51 +49,50 @@ stats = scales.collection(
 
class Snapshot(cyclone.web.RequestHandler):
 

	
 
    @defer.inlineCallbacks
 
    def post(self):
 
        # save next pic
 
        # return /snapshot/path
 
        try:
 
            snapshotDir = 'todo'
 
            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'
 
)
 
    #'/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)
 
        stats.liveClients += 1
 

	
 
    def connectionLost(self, reason):
 
        #self.subj.dispose()
 
        stats.liveClients -= 1
 

	
 
    def onFrame(self, cf: videorecorder.CaptureFrame):
 
        if cf is None: return
 

	
 
        stats.liveWebsocketFrameFps.mark()
 

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

	
 

	
light9/vidref/videorecorder.py
Show inline comments
 
@@ -185,102 +185,103 @@ class FramesToVideoFiles:
 

	
 
        # should be a little queue to miss fewer frames
 
        t1 = time.time()
 
        while self.nextImg is None:
 
            time.sleep(.015)
 
        stats.waitForNextImg = time.time() - t1
 
        cf, self.nextImg = self.nextImg, None
 

	
 
        self.frameMap.write(f'video {video_time_secs:g} = song {cf.t:g}\n')
 
        self.currentClipFrameCount += 1
 
        return numpy.asarray(cf.img)
 

	
 

	
 
class GstSource:
 

	
 
    def __init__(self, dev):
 
        """
 
        make new gst pipeline
 
        """
 
        Gst.init(None)
 
        self.musicTime = MusicTime(pollCurvecalc=False)
 
        self.liveImages: BehaviorSubject = BehaviorSubject(
 
            None)  # stream of Optional[CaptureFrame]
 

	
 
        size = [640, 480]
 
        # need to use 640,480 on some webcams or they fail mysteriously
 
        size = [800, 600]
 

	
 
        log.info("new pipeline using device=%s" % dev)
 

	
 
        # using videocrop breaks the pipeline, may be this issue
 
        # https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/732
 
        pipeStr = (
 
            #f"v4l2src device=\"{dev}\""
 
            f'autovideosrc'
 
            f"v4l2src device=\"{dev}\""
 
            #            f'autovideosrc'
 
            f" ! videoconvert"
 
            f" ! appsink emit-signals=true max-buffers=1 drop=true name=end0 caps=video/x-raw,format=RGB,width={size[0]},height={size[1]}"
 
        )
 
        log.info("pipeline: %s" % pipeStr)
 

	
 
        self.pipe = Gst.parse_launch(pipeStr)
 

	
 
        self.setupPipelineError(self.pipe, self.onError)
 

	
 
        self.appsink = self.pipe.get_by_name('end0')
 
        self.appsink.connect('new-sample', self.new_sample)
 

	
 
        self.pipe.set_state(Gst.State.PLAYING)
 
        log.info('gst pipeline is recording video')
 

	
 
    def new_sample(self, appsink):
 
        try:
 
            sample = appsink.emit('pull-sample')
 
            caps = sample.get_caps()
 
            buf = sample.get_buffer()
 
            (result, mapinfo) = buf.map(Gst.MapFlags.READ)
 
            try:
 
                img = PIL.Image.frombytes(
 
                    'RGB', (caps.get_structure(0).get_value('width'),
 
                            caps.get_structure(0).get_value('height')),
 
                    mapinfo.data)
 
                img = self.crop(img)
 
            finally:
 
                buf.unmap(mapinfo)
 
            # could get gst's frame time and pass it to getLatest
 
            latest = self.musicTime.getLatest()
 
            if 'song' in latest:
 
                stats.queueGstFrameFps.mark()
 
                self.liveImages.on_next(
 
                    CaptureFrame(img=img,
 
                                 song=Song(latest['song']),
 
                                 t=latest['t'],
 
                                 isPlaying=latest['playing']))
 
        except Exception:
 
            traceback.print_exc()
 
        return Gst.FlowReturn.OK
 

	
 
    @stats.crop.time()
 
    def crop(self, img):
 
        return img.crop((0, 100, 640, 380))
 
        return img.crop((40, 100, 790, 310))
 

	
 
    def setupPipelineError(self, pipe, cb):
 
        bus = pipe.get_bus()
 

	
 
        def onBusMessage(bus, msg):
 

	
 
            print('nusmsg', msg)
 
            if msg.type == Gst.MessageType.ERROR:
 
                _, txt = msg.parse_error()
 
                cb(txt)
 
            return True
 

	
 
        # not working; use GST_DEBUG=4 to see errors
 
        bus.add_watch(0, onBusMessage)
 
        bus.connect('message', onBusMessage)
 

	
 
    def onError(self, messageText):
 
        if ('v4l2src' in messageText and
 
            ('No such file or directory' in messageText or
 
             'Resource temporarily unavailable' in messageText or
 
             'No such device' in messageText)):
 
            log.error(messageText)
 
            os.abort()
 
        else:
0 comments (0 inline, 0 general)