integrate camera
This commit is contained in:
parent
9d49a0ce06
commit
6f91aa0465
|
@ -12,6 +12,7 @@ from listeners import KeypadListener, PipeListener
|
||||||
from blinkenLights import Blinkenlights
|
from blinkenLights import Blinkenlights
|
||||||
from soundLib import SoundLib
|
from soundLib import SoundLib
|
||||||
from webInterface import initWebInterface
|
from webInterface import initWebInterface
|
||||||
|
from stream import initCamera
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -133,6 +134,8 @@ class StateMachine:
|
||||||
|
|
||||||
self.LED = Blinkenlights(17)
|
self.LED = Blinkenlights(17)
|
||||||
|
|
||||||
|
initCamera()
|
||||||
|
|
||||||
def action():
|
def action():
|
||||||
if self.currentState == self.states.armed:
|
if self.currentState == self.states.armed:
|
||||||
self.selectState(SIGNALS.TRIGGER)
|
self.selectState(SIGNALS.TRIGGER)
|
||||||
|
|
91
stream.py
91
stream.py
|
@ -9,10 +9,14 @@
|
||||||
# - will not require SIGINT (this entire program won't understand them anyways)
|
# - will not require SIGINT (this entire program won't understand them anyways)
|
||||||
# - no tags or TOCs
|
# - no tags or TOCs
|
||||||
|
|
||||||
from auxilary import async
|
from auxilary import async, waitForPath
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
import gi, time
|
import gi, time, logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
gi.require_version('Gst', '1.0')
|
gi.require_version('Gst', '1.0')
|
||||||
gi.require_version('GObject', '2.0')
|
gi.require_version('GObject', '2.0')
|
||||||
|
|
||||||
|
@ -21,18 +25,18 @@ from gi.repository import Gst, GObject
|
||||||
class GstException(Exception):
|
class GstException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def gstPrintMsg(pName, frmt, *args, sName=None):
|
def gstPrintMsg(pName, frmt, *args, level=logging.DEBUG, sName=None):
|
||||||
if sName:
|
if sName:
|
||||||
print('[{}] [{}] '.format(pName, sName) + frmt.format(*args))
|
logger.log(level, '[{}] [{}] '.format(pName, sName) + frmt.format(*args))
|
||||||
else:
|
else:
|
||||||
print('[{}] '.format(pName) + frmt.format(*args))
|
logger.log(level, '[{}] '.format(pName) + frmt.format(*args))
|
||||||
|
|
||||||
def processErrorMessage(pName, sName, msg):
|
def processErrorMessage(pName, sName, msg, level=logging.DEBUG):
|
||||||
error, debug = msg.parse_error()
|
error, debug = msg.parse_error()
|
||||||
if debug:
|
if debug:
|
||||||
gstPrintMsg(pName, '{} - Additional debug info: {}', error.message, debug, sName=sName)
|
gstPrintMsg(pName, '{} - Additional debug info: {}', error.message, debug, level=level, sName=sName)
|
||||||
else:
|
else:
|
||||||
gstPrintMsg(pName, error.message, sName=sName)
|
gstPrintMsg(pName, error.message, level=level, sName=sName)
|
||||||
raise GstException(error)
|
raise GstException(error)
|
||||||
|
|
||||||
def linkElements(e1, e2, caps=None):
|
def linkElements(e1, e2, caps=None):
|
||||||
|
@ -76,15 +80,13 @@ def eventLoop(pipeline, block=True, doProgress=False, targetState=Gst.State.PLAY
|
||||||
if msgType == Gst.MessageType.REQUEST_STATE:
|
if msgType == Gst.MessageType.REQUEST_STATE:
|
||||||
state = msg.parse_request_state()
|
state = msg.parse_request_state()
|
||||||
|
|
||||||
print('Setting state to {} as requested by {}'.format(
|
logger.info('Setting state to %s as requested by %s',
|
||||||
Gst.Element.get_state_name(state),
|
Gst.Element.get_state_name(state), msgSrcName)
|
||||||
msgSrcName)
|
|
||||||
)
|
|
||||||
|
|
||||||
pipeline.set_state(state)
|
pipeline.set_state(state)
|
||||||
|
|
||||||
elif msgType == Gst.MessageType.CLOCK_LOST:
|
elif msgType == Gst.MessageType.CLOCK_LOST:
|
||||||
print('Clock lost. Getting new one.')
|
logger.debug('Clock lost. Getting new one.')
|
||||||
pipeline.set_state(Gst.State.PAUSED)
|
pipeline.set_state(Gst.State.PAUSED)
|
||||||
pipeline.set_state(Gst.State.PLAYING)
|
pipeline.set_state(Gst.State.PLAYING)
|
||||||
|
|
||||||
|
@ -105,18 +107,19 @@ def eventLoop(pipeline, block=True, doProgress=False, targetState=Gst.State.PLAY
|
||||||
error, debug = msg.parse_info()
|
error, debug = msg.parse_info()
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
gstPrintMsg(pName, debug, sName=msgSrcName)
|
gstPrintMsg(pName, debug, level=logging.INFO, sName=msgSrcName)
|
||||||
|
|
||||||
elif msgType == Gst.MessageType.WARNING:
|
elif msgType == Gst.MessageType.WARNING:
|
||||||
error, debug = msg.parse_warning()
|
error, debug = msg.parse_warning()
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
gstPrintMsg(pName, '{} - Additional debug info: {}', error.message, debug, sName=msgSrcName)
|
gstPrintMsg(pName, '{} - Additional debug info: {}', error.message,
|
||||||
|
debug, level=logging.INFO, sName=msgSrcName)
|
||||||
else:
|
else:
|
||||||
gstPrintMsg(pName, error.message, sName=msgSrcName)
|
gstPrintMsg(pName, error.message, level=logging.INFO, sName=msgSrcName)
|
||||||
|
|
||||||
elif msgType == Gst.MessageType.ERROR:
|
elif msgType == Gst.MessageType.ERROR:
|
||||||
processErrorMessage(pName, msgSrcName, msg)
|
processErrorMessage(pName, msgSrcName, msg, logging.ERROR)
|
||||||
|
|
||||||
elif msgType == Gst.MessageType.STATE_CHANGED:
|
elif msgType == Gst.MessageType.STATE_CHANGED:
|
||||||
# we only care about pipeline level state changes
|
# we only care about pipeline level state changes
|
||||||
|
@ -128,11 +131,13 @@ def eventLoop(pipeline, block=True, doProgress=False, targetState=Gst.State.PLAY
|
||||||
prerolled = True
|
prerolled = True
|
||||||
|
|
||||||
if buffering:
|
if buffering:
|
||||||
gstPrintMsg(pName, 'Prerolled, waiting for buffering to finish')
|
gstPrintMsg(pName, 'Prerolled, waiting for buffering to finish',
|
||||||
|
level=logging.INFO)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if inProgress:
|
if inProgress:
|
||||||
gstPrintMsg(pName, 'Prerolled, waiting for progress to finish')
|
gstPrintMsg(pName, 'Prerolled, waiting for progress to finish',
|
||||||
|
level=logging.INFO)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -185,19 +190,19 @@ def eventLoop(pipeline, block=True, doProgress=False, targetState=Gst.State.PLAY
|
||||||
# these are things I might not need...
|
# these are things I might not need...
|
||||||
elif msgType == Gst.MessageType.STREAM_START:
|
elif msgType == Gst.MessageType.STREAM_START:
|
||||||
if msgSrc == pipeline:
|
if msgSrc == pipeline:
|
||||||
gstPrintMsg(pName, 'Started stream')
|
gstPrintMsg(pName, 'Started stream', level=logging.INFO)
|
||||||
|
|
||||||
#~ elif msgType == Gst.MessageType.QOS:
|
elif msgType == Gst.MessageType.QOS:
|
||||||
#~ frmt, processed, dropped = msg.parse_qos_stats()
|
frmt, processed, dropped = msg.parse_qos_stats()
|
||||||
#~ jitter, proportion, quality = msg.parse_qos_values()
|
jitter, proportion, quality = msg.parse_qos_values()
|
||||||
|
|
||||||
#~ gstPrintMsg(
|
gstPrintMsg(
|
||||||
#~ pName,
|
pName,
|
||||||
#~ 'QOS stats: jitter={} dropped={}',
|
'QOS stats: jitter={} dropped={}',
|
||||||
#~ jitter,
|
jitter,
|
||||||
#~ '-' if frmt == Gst.Format.UNDEFINED else dropped,
|
'-' if frmt == Gst.Format.UNDEFINED else dropped,
|
||||||
#~ sName = msgSrcName
|
sName = msgSrcName
|
||||||
#~ )
|
)
|
||||||
|
|
||||||
elif msgType == Gst.MessageType.ELEMENT:
|
elif msgType == Gst.MessageType.ELEMENT:
|
||||||
gstPrintMsg(pName, 'Unknown message ELEMENT', sName=msgSrcName)
|
gstPrintMsg(pName, 'Unknown message ELEMENT', sName=msgSrcName)
|
||||||
|
@ -209,10 +214,10 @@ def eventLoop(pipeline, block=True, doProgress=False, targetState=Gst.State.PLAY
|
||||||
def startPipeline(pipeline, play=True):
|
def startPipeline(pipeline, play=True):
|
||||||
pName = pipeline.get_name()
|
pName = pipeline.get_name()
|
||||||
stateChange = pipeline.set_state(Gst.State.PAUSED)
|
stateChange = pipeline.set_state(Gst.State.PAUSED)
|
||||||
gstPrintMsg(pName, 'Setting to PAUSED')
|
gstPrintMsg(pName, 'Setting to PAUSED', level=logging.INFO)
|
||||||
|
|
||||||
if stateChange == Gst.StateChangeReturn.FAILURE:
|
if stateChange == Gst.StateChangeReturn.FAILURE:
|
||||||
gstPrintMsg(pName, 'Cannot set to PAUSE')
|
gstPrintMsg(pName, 'Cannot set to PAUSE', level=logging.INFO)
|
||||||
eventLoop(pipeline, block=False, doProgress=False, targetState=Gst.State.VOID_PENDING)
|
eventLoop(pipeline, block=False, doProgress=False, targetState=Gst.State.VOID_PENDING)
|
||||||
# we should always end up here because live
|
# we should always end up here because live
|
||||||
elif stateChange == Gst.StateChangeReturn.NO_PREROLL:
|
elif stateChange == Gst.StateChangeReturn.NO_PREROLL:
|
||||||
|
@ -222,7 +227,7 @@ def startPipeline(pipeline, play=True):
|
||||||
try:
|
try:
|
||||||
eventLoop(pipeline, block=True, doProgress=True, targetState=Gst.State.PAUSED)
|
eventLoop(pipeline, block=True, doProgress=True, targetState=Gst.State.PAUSED)
|
||||||
except GstException:
|
except GstException:
|
||||||
gstPrintMsg(pName, 'Does not want to preroll')
|
gstPrintMsg(pName, 'Does not want to preroll', level=logging.ERROR)
|
||||||
# some cleanup here?
|
# some cleanup here?
|
||||||
raise
|
raise
|
||||||
elif stateChange == Gst.StateChangeReturn.SUCCESS:
|
elif stateChange == Gst.StateChangeReturn.SUCCESS:
|
||||||
|
@ -232,19 +237,19 @@ def startPipeline(pipeline, play=True):
|
||||||
try:
|
try:
|
||||||
eventLoop(pipeline, block=False, doProgress=True, targetState=Gst.State.PLAYING)
|
eventLoop(pipeline, block=False, doProgress=True, targetState=Gst.State.PLAYING)
|
||||||
except GstException:
|
except GstException:
|
||||||
gstPrintMsg(pName, 'Does not want to preroll')
|
gstPrintMsg(pName, 'Does not want to preroll', level=logging.ERROR)
|
||||||
# some cleanup here?
|
# some cleanup here?
|
||||||
raise
|
raise
|
||||||
# ...and end up here
|
# ...and end up here
|
||||||
else:
|
else:
|
||||||
if play:
|
if play:
|
||||||
gstPrintMsg(pName, 'Setting to PLAYING')
|
gstPrintMsg(pName, 'Setting to PLAYING', level=logging.INFO)
|
||||||
|
|
||||||
# and since this will ALWAYS be successful (maybe)...
|
# and since this will ALWAYS be successful (maybe)...
|
||||||
if pipeline.set_state(Gst.State.PLAYING) == Gst.StateChangeReturn.FAILURE:
|
if pipeline.set_state(Gst.State.PLAYING) == Gst.StateChangeReturn.FAILURE:
|
||||||
gstPrintMsg(pName, 'Cannot set to PLAYING')
|
gstPrintMsg(pName, 'Cannot set to PLAYING', level=logging.ERROR)
|
||||||
err = pipeline.get_bus().pop_filtered(Gst.MessageType.Error)
|
err = pipeline.get_bus().pop_filtered(Gst.MessageType.Error)
|
||||||
processErrorMessage(pName, msgSrcName, err)
|
processErrorMessage(pName, msgSrcName, err, logging.ERROR)
|
||||||
|
|
||||||
# ...we and end up here and loop until Tool releases their next album
|
# ...we and end up here and loop until Tool releases their next album
|
||||||
try:
|
try:
|
||||||
|
@ -253,9 +258,11 @@ def startPipeline(pipeline, play=True):
|
||||||
# cleanup or recover
|
# cleanup or recover
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def Camera(video=True, audio=True):
|
def initCamera(video=True, audio=True):
|
||||||
pipeline = Gst.Pipeline.new("camera")
|
pipeline = Gst.Pipeline.new("camera")
|
||||||
|
|
||||||
|
vPath = '/dev/video0'
|
||||||
|
|
||||||
if video:
|
if video:
|
||||||
vSource = Gst.ElementFactory.make("v4l2src", "videoSource")
|
vSource = Gst.ElementFactory.make("v4l2src", "videoSource")
|
||||||
vConvert = Gst.ElementFactory.make("videoconvert", "videoConvert")
|
vConvert = Gst.ElementFactory.make("videoconvert", "videoConvert")
|
||||||
|
@ -265,7 +272,7 @@ def Camera(video=True, audio=True):
|
||||||
vRTPPay = Gst.ElementFactory.make("rtph264pay", "videoRTPPayload")
|
vRTPPay = Gst.ElementFactory.make("rtph264pay", "videoRTPPayload")
|
||||||
vRTPSink = Gst.ElementFactory.make("multiudpsink", "videoRTPSink")
|
vRTPSink = Gst.ElementFactory.make("multiudpsink", "videoRTPSink")
|
||||||
|
|
||||||
vSource.set_property('device', '/dev/video0')
|
vSource.set_property('device', vPath)
|
||||||
vRTPPay.set_property('config-interval', 1)
|
vRTPPay.set_property('config-interval', 1)
|
||||||
vRTPPay.set_property('pt', 96)
|
vRTPPay.set_property('pt', 96)
|
||||||
vRTPSink.set_property('clients', '127.0.0.1:9001,127.0.0.1:9002')
|
vRTPSink.set_property('clients', '127.0.0.1:9001,127.0.0.1:9002')
|
||||||
|
@ -302,6 +309,8 @@ def Camera(video=True, audio=True):
|
||||||
linkElements(aEncode, aRTPPay)
|
linkElements(aEncode, aRTPPay)
|
||||||
linkElements(aRTPPay, aRTPSink)
|
linkElements(aRTPPay, aRTPSink)
|
||||||
|
|
||||||
|
waitForPath(vPath) # video is on usb, so wait until it comes back after we hard reset the bus
|
||||||
|
|
||||||
startPipeline(pipeline)
|
startPipeline(pipeline)
|
||||||
|
|
||||||
class FileDump:
|
class FileDump:
|
||||||
|
@ -348,10 +357,6 @@ class FileDump:
|
||||||
self.pipeline.set_state(Gst.State.PAUSED)
|
self.pipeline.set_state(Gst.State.PAUSED)
|
||||||
|
|
||||||
Gst.init(None)
|
Gst.init(None)
|
||||||
Camera()
|
|
||||||
|
|
||||||
while 1:
|
|
||||||
time.sleep(3600)
|
|
||||||
|
|
||||||
# this works for file dump
|
# this works for file dump
|
||||||
# gst-launch-1.0 -v udpsrc port=8001 ! application/x-rtp,encoding-name=OPUS,payload=96 !
|
# gst-launch-1.0 -v udpsrc port=8001 ! application/x-rtp,encoding-name=OPUS,payload=96 !
|
||||||
|
|
Loading…
Reference in New Issue