Raspberry pi zero 2W MJPG Stream and H264 Capture at the same time
I have been trialling raspistill, raspivid, libcamera, picamera for a while now and have landed on the below code as an example of running an MP4 video capture while offering the ability to see a live stream if required. The code gets split into backend python that captures the MJPG stream and the h264 stream and then the h264 stream gets converted to MP4 via MP4Box (gpac). The front end is a combo of html, php, css etc.
Biggest issue so far was the ability to run the MJPG stream for more than 5 hours without the RPI needing to be rebooted to recover. This was achieved by stop and starting the MJPG picamera stream every hour approximately. That way the MJPG stream would not die a slow death. This particular code sits in my car. I create a /temp in memory so the h264 file is first stored in memory before conversion to MP4 and saving to SDCARD (Try reduce number of writes and increase speed of capture/conversion etc in a different subprocess).
I control LIFX front porch light if car sees movement and you could also upload to onedrive using rclone. I use a fisheye lens on a RPI v2. PHP html code to follow . Apache2 used to access mp4 files remotely and MJPG streamed via inbuilt port on port 8000. only wifi enabled.
Python3 Code:
# Web streaming example
# Source code from the official PiCamera package
# http://picamera.readthedocs.io/en/latest/recipes2.html#web-streaming
import io
import os
import sys
import picamera
import logging
import socketserver
from threading import Condition
from http import server
import datetime
import shutil
import pathlib
import threading
from threading import Thread
import subprocess
#for http api access to LIFX Cloud
import requests
#import multiprocessing
import multiprocessing as mp
now = datetime.datetime.now()
import time
import smtplib #Import smtplib for the actual sending function
from email.message import EmailMessage #Import the email modules we'll need
#Gmail Credentials
usernameGmail = 'Blahblah@gmail.com'
passwordGmail = 'lkjhgfdghjkl'
rpiType = "rpi"
rpiIpAddress = "10.10.10.10"
rpiName = rpiType + "-" + "10-10-10-10"
areaName = "sms-fisheye-stream-car-cam"
fromEmailAddress = "blahblah@gmail.com"
toEmailAddress = "blahblah@gmail.com"
emailSubject = rpiName + " Rebooted"
emailContent = rpiName + " " + areaName + " Startup or reboot time " + now.strftime("%Y-%m-%d %H:%M:%S.%f")
#Vars
#log file paths
PATH = '/home/pi/html-php-scripts/mp4/logs/'
try:
#Create Directory if it does not exist
pathlib.Path('/temp/mp4/').mkdir(parents=True, exist_ok=True)
except OSError as error:
print(error)
print("File path can not be removed")
try:
statePath = '/temp/mp4/state/'
#pathlib.Path(statePath).mkdir(parents=True, exist_ok=True)
os.makedirs(statePath, mode=0o755, exist_ok=True)
except OSError as error:
sys.exit("Can't create {dir}: {err}".format(dir=statepath, err=error))
flagCounterPath = '/temp/mp4/state/flagCounter.conf'
averageFileSizeMp4BytesPath = '/temp/mp4/state/averageFileSizeMp4Bytes.conf'
#make sure file is initialised
averageFileSizeMp4Bytes = 0
averageFileSizeMp4BytesFile= open(averageFileSizeMp4BytesPath,"w+")
averageFileSizeMp4BytesFile.write(str(averageFileSizeMp4Bytes))
#Initialise file vars
flagCounterFile= open(flagCounterPath,"w+")
averageFileSizeMp4BytesFile= open(averageFileSizeMp4BytesPath,"w+")
flagCounterFile.write(str(0))
averageFileSizeMp4BytesFile.write(str(0))
flagCounterFile.close()
averageFileSizeMp4BytesFile.close()
tempCollectFileSizeInt = 0
tempCollectFileSizeCompare = 0
previousTempCollectFileSizeInt = 0
previousTempFileNameMp4Path = " "
fisheyeCamMp4SavePath=""
fisheyeCamH264SavePath=""
fileNameH264Path=""
fileNameMp4Path=""
#Multiply the average by this factor to make sure there is movement
percentageDifference = 1.05
counter=0
#Refresh the average after 5 (0-4)
flagCounterMax = 2
###cloud.lifx.com access token
###0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x0x
###LIFX Front Door Light
#Define a function
#try:
# #remove temp
# shutil.rmtree('/temp/mp4', ignore_errors=True)
# print('Cleaned up /temp....Complete')
#except OSError as error:
# print(error)
# print("File path can not be removed")
PAGE="""\
<html>
<head>
<meta http-equiv="refresh" content="600">
<title>RPI - Car camera</title>
<style>
img {
width: auto;
height: auto;
/*Magic!*/
max-width:70vw;*/
max-height:70vw;*/
}
</style>
</head>
<body>
<center><h1>RPI - Car Camera</h1></center>
<center><img src="stream.mjpg"</center>
</body>
</html>
"""
class StreamingOutput(object):
def __init__(self):
self.frame = None
self.buffer = io.BytesIO()
self.condition = Condition()
def write(self, buf):
if buf.startswith(b'\xff\xd8'):
# New frame, copy the existing buffer's content and notify all
# clients it's available
self.buffer.truncate()
with self.condition:
self.frame = self.buffer.getvalue()
self.condition.notify_all()
self.buffer.seek(0)
return self.buffer.write(buf)
class StreamingHandler(server.BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/':
self.send_response(301)
self.send_header('Location', '/index.html')
self.end_headers()
elif self.path == '/index.html':
content = PAGE.encode('utf-8')
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.send_header('Content-Length', len(content))
self.end_headers()
self.wfile.write(content)
elif self.path == '/stream.mjpg':
self.send_response(200)
self.send_header('Age', 0)
self.send_header('Cache-Control', 'no-cache, private')
self.send_header('Pragma', 'no-cache')
self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=--FRAME')
self.end_headers()
try:
while True:
with output.condition:
output.condition.wait()
frame = output.frame
self.wfile.write(b'--FRAME\r\n')
self.send_header('Content-Type', 'image/jpeg')
self.send_header('Content-Length', len(frame))
self.end_headers()
self.wfile.write(frame)
self.wfile.write(b'\r\n')
except Exception as e:
logging.warning('Removed streaming client %s: %s',self.client_address, str(e))
pass
else:
self.send_error(404)
self.end_headers()
pass
class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
allow_reuse_address = True
daemon_threads = True
#Email function
def sendEmailTrigger():
try:
now = datetime.datetime.now()
print("Either first startup or a reboot " + rpiName + " must have rebooted as the application has restarted")
#print("1--",",","Either first startup or a reboot " + rpiName + " must have rebooted as the application has restarted",",",now.strftime("%Y-%m-%d %H:%M:%S.%f"),file=open(logPath+logFileName, "a"))
# me == the sender's email address
# you == the recipient's email address
msg = EmailMessage()
msg['Subject'] = emailSubject
msg['From'] = fromEmailAddress
msg['To'] = toEmailAddress
msgContentEmail = emailContent
msg.set_content(msgContentEmail)
#Gmail user/pass
s = smtplib.SMTP('smtp.gmail.com:587')
s.starttls()
response = str(s.login(usernameGmail,passwordGmail))
s.send_message(msg)
s.quit()
now = datetime.datetime.now()
if 'Accepted' in response:
print("Email Auth successful. Email should have been sent...")
#print("1--",",","Email Auth successful. Email should have been sent...",",",now.strftime("%Y-%m-%d %H:%M:%S.%f"),file=open(logPath+logFileName, "a"))
else:
print("Email Auth failed. Email most likely NOT sent...")
#print("0--",",","Email Auth failed. Email most likely NOT sent...",",",now.strftime("%Y-%m-%d %H:%M:%S.%f"),file=open(logPath+logFileName, "a"))
except Exception as inst:
print(type(inst)) # the exception instance
print(inst.args) # arguments stored in .args
print(inst) # __str__ allows args to be printed directly,
# but may be overridden in exception subclasses
x, y = inst.args # unpack args
print('x =', x)
print('y =', y)
print("Alarm disarmed or Email problems - something went wrong...")
#print("0--",",","Email problems - something went wrong... Email most likely NOT sent...",",",now.strftime("%Y-%m-%d %H:%M:%S.%f"),file=open(logPath+logFileName, "a"))
pass
def frontLightControl():
####Turn on LIFX Front Door Light
try:
print("Starting sub process of LIFX front light control")
#{
# "results": [
# {
# "id": "d07xxxxxxxxxx",
# "status": "ok",
# "label": "Front-Door-Light"
# },
# {
# "id": "d07xxxxxddddxxxxx",
# "status": "ok",
# "label": "activity lamp"
# }
# ]
#}
#############DEBUG LIFX#################################################################
#Set LIFX Lamp status - Off - Green
#Start with authentication
accessToken = "c0XXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
#headers = {"Authorization": "Bearer ",token}
headers={'Authorization': 'Bearer {}'.format(accessToken)}
#payload = {"power": "on","color": "green saturation:1.0","brightness": 1.0,}
#payload = {"power_off": True}
#response = requests.post('https://api.lifx.com/v1/lights/all/effects/off', data=payload, headers=headers)
#payload = {"power": "on","color": "white", "brightness":1.0,"fast":True}
payload = {"power": "on","color": "white kelvin:9000", "brightness":1.0}
response = requests.put('https://api.lifx.com/v1/lights/d07xxxxxxxxxxxx/state', data=payload, headers=headers)
print(response.text)
#turn lamp on and sleep before turning off
for i in range(1,60,1):
time.sleep(1)
print("Sleeping for ",i," second out of 60 seconds")
except:
print("something went wrong starting front door light control. Check cloud.lifx.com")
pass
try:
#above keeps light on for atleast 20 seconds
#this will aggregate the turn off of front light after no movemnet of garage or front door cameras
#turn lamp on and sleep before turning off
for i in range(1,15,1):
time.sleep(1)
print("Sleeping for ",i," second out of 15 seconds")
#Set LIFX Lamp status - Off - Green
#Start with authentication
accessToken = "c0exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
headers={'Authorization': 'Bearer {}'.format(accessToken)}
payload = {"power_off": True}
response = requests.post('https://api.lifx.com/v1/lights/d07xxxxxxxxxx/effects/off', data=payload, headers=headers)
print(response.text)
except:
print("Something went wrong turning off front door light control.")
pass
def convertH264Mp4(fisheyeCamMp4SavePath,fisheyeCamH264SavePath,fileNameMp4):
now = datetime.datetime.now()
#Delete raw h264 file command
fisheyeCamCommandDeleteH264 = 'rm -Rf ' + fisheyeCamH264SavePath
#Convert from h264 to mp4 - sudo apt-get install gpac
fisheyeCamCommandConvertH264Mp4 = 'MP4Box -fps 25 -add ' + fisheyeCamH264SavePath+ ' ' + fisheyeCamMp4SavePath
#run MP4Box command
outputFisheyeCamConvertH264Mp4Result = subprocess.getoutput(fisheyeCamCommandConvertH264Mp4)
#run h264 file delete command
outputFisheyeCamDeleteH264Result = subprocess.getoutput(fisheyeCamCommandDeleteH264)
#Command to run rclone and sync with OneDrive
#rcloneCommand = '/usr/bin/rclone -v copy '+fisheyeCamMp4SavePath+' onedrive:Documents/Personal/pi-cam/fisheye-side-gate-cam/'+now.strftime("%Y-%m-%d")+'/'
#run rclone command
#outputRcloneCommandResult = subprocess.getoutput(rcloneCommand)
####print(counter,",",outputRcloneCommandResult,",",fileNameMp4Path,",",now.strftime("%Y-%m-%d %H:%M:%S.%f"),file=open(PATH+"fisheye-cam-"+now.strftime("%Y-%m-%d")+".fisheye-cam.log", "a"))
logFileSizeMp4(fisheyeCamMp4SavePath,fileNameMp4)
def logFileSizeMp4(fisheyeCamMp4SavePath,fileNameMp4):
now = datetime.datetime.now()
#Path for the motion videos
#motionPath = '/home/pi/html-php-scripts/mp4/'+now.strftime("%Y-%m-%d")+'/motion'
#objectPath = '/home/pi/html-php-scripts/mp4/'+now.strftime("%Y-%m-%d")+'/motion/object'
try:
#Create Directory if it does not exist - sort in days
#pathlib.Path('/home/pi/html-php-scripts/fisheye-cam/videos/'+now.strftime("%Y-%m-%d")).mkdir(parents=True, exist_ok=True)
motionPath = '/home/pi/html-php-scripts/mp4/'+now.strftime("%Y-%m-%d")+'/motion'
if not os.path.exists(motionPath):
os.makedirs(motionPath, mode=0o755, exist_ok=True)
###os.mkdirs(motionPath,exist_ok=True)
except:
sys.exit("Can't create {dir}: {err}".format(dir=statepath, err=e))
#DEBUG - Motion Object path
try:
#Create Directory if it does not exist - sort in days
#pathlib.Path('/home/pi/html-php-scripts/fisheye-cam/videos/'+now.strftime("%Y-%m-%d")).mkdir(parents=True, exist_ok=True)
objectPath = '/home/pi/html-php-scripts/mp4/'+now.strftime("%Y-%m-%d")+'/motion/object'
if not os.path.exists(objectPath):
os.makedirs(objectPath, mode=0o755, exist_ok=True)
except:
sys.exit("Can't create {dir}: {err}".format(dir=statepath, err=e))
#DEBUG
#print(fisheyeCamMp4SavePath)
fileSizeMp4Bytes = os.path.getsize(fisheyeCamMp4SavePath)
#Debug
#print("filesize in bytes",fileSizeMp4Bytes)
fileSizeMp4MBytes = fileSizeMp4Bytes / 1048576
#DEBUG
#print("filesize in bytes",fileSizeMp4MBytes," MBytes")
print(fileSizeMp4Bytes,",","Bytes,",fileSizeMp4MBytes,",","MBytes,",fileNameMp4,",",now.strftime("%Y-%m-%d %H:%M:%S.%f"),file=open(PATH+"fisheye-car-cam-mp4-"+now.strftime("%Y-%m-%d")+"-filesize.log", "a"))
####################################
with open(averageFileSizeMp4BytesPath, 'r') as averageFileSizeMp4BytesFile:
for line in averageFileSizeMp4BytesFile:
averageFileSizeMp4Bytes = float(line)
print("..........................................")
print("averageFileSizeMp4Bytes: ",averageFileSizeMp4Bytes)
if averageFileSizeMp4Bytes == 0:
averageFileSizeMp4Bytes = fileSizeMp4Bytes
averageFileSizeMp4BytesFile= open(averageFileSizeMp4BytesPath,"w+")
averageFileSizeMp4BytesFile.write(str(averageFileSizeMp4Bytes))
else:
averageFileSizeMp4Bytes = (fileSizeMp4Bytes + averageFileSizeMp4Bytes) / 2
averageFileSizeMp4BytesFile= open(averageFileSizeMp4BytesPath,"w+")
averageFileSizeMp4BytesFile.write(str(averageFileSizeMp4Bytes))
#multiply by the factor to determine if movement motion occurrued
compareSizeChange = averageFileSizeMp4Bytes * percentageDifference
#Calculate a percentage difference
percentChange = (round((fileSizeMp4Bytes / compareSizeChange),4))*100
print("..........................................")
print("upper limit difference file size = ", compareSizeChange)
print("Actual new filesize video bytes = ", fileSizeMp4Bytes)
print("Actual new filesize video Mega bytes = ", fileSizeMp4MBytes)
print("Percetage change in size if bigger/smaller than average filesize = ", percentChange ,"%")
#DEBUG
print("Avg Size and counter,",round(averageFileSizeMp4Bytes,2),",",",Percentage Compare value against file size,",round(compareSizeChange,2),",","File Size,",fileSizeMp4Bytes,",","B,",fileNameMp4,",Diff Factor,",percentageDifference,",change,",round(percentChange,2),"%,",now.strftime("%Y-%m-%d %H:%M:%S.%f"),file=open(PATH+"fisheye-car-cam-mp4-"+now.strftime("%Y-%m-%d")+"-filesize.percent.change.log", "a"))
#check if first round where comapreSizeChange will be zero
if ((fileSizeMp4Bytes >= compareSizeChange) and (compareSizeChange > 0)) :
try:
print("..........................................")
print("greater than "+str(percentageDifference)+" so log it to motion")
#save to motion directory
print("filesize in bytes",fileSizeMp4MBytes," MBytes")
fisheyeCamCommandCopyMotion = 'cp '+fisheyeCamMp4SavePath+' '+motionPath+'/'+fileNameMp4
print(fisheyeCamCommandCopyMotion)
outputFisheyeCamCommandCopyMotionResult = subprocess.getoutput(fisheyeCamCommandCopyMotion)
except OSError as error:
sys.exit("Can't create {dir}: {err}".format(dir=statepath, err=error))
##OBjects
#DEBUG greater than 110% - Mostly likely an actual object moving as opposed to wind
if (percentChange >= 109):
try:
print("..........................................")
print("greater than or equal to "+str(percentChange)+" so log it to object dir")
#save to motion directory
print("filesize in bytes",fileSizeMp4MBytes," MBytes")
fisheyeCamCommandCopyMotionObject = 'cp '+fisheyeCamMp4SavePath+' '+objectPath+'/'+fileNameMp4
print(fisheyeCamCommandCopyMotionObject)
outputFisheyeCamCommandCopyMotionObjectResult = subprocess.getoutput(fisheyeCamCommandCopyMotionObject)
except OSError as error:
sys.exit("Can't create {dir}: {err}".format(dir=statepath, err=error))
else:
print("percentChange must be less than 105%.......")
print("motion object path:",objectPath)
#print("averageFileSizeMp4Bytes............ = ", averageFileSizeMp4Bytes)
#########################################################################
#########################################################################
check24Hour = int(now.strftime("%H"))
#check24Minutes = int(now.strftime("%M"))
#convert to minutes to make more granualar
#check24HourToMinutes = (check24Hour * 60) + (check24Minutes)
#check time of day restrictions - 1110=6:30pm
#Summertime change times to earlier and later daytime
#check time of day restrictions - 1110=6:30pm
#Summertime change times to earlier and later daytime
#night time
###if check24HourToMinutes >= 1140 or check24HourToMinutes <= 300: #check24Hour <= "06" or check24Hour <= "6"):
if check24Hour >= 18 or check24Hour <= 6:
#front light control sub process
#lifx = mp.Process(target=frontLightControl, args=())
#lifx.start()
lifx_thread = Thread(target=frontLightControl)
lifx_thread.start()
else:
print("Day time so no need to control front light")
else:
print("probably no motion worth noting...........")
print("motion path:",motionPath)
print("averageFileSizeMp4Bytes............ = ", averageFileSizeMp4Bytes)
#########################################################################
#########################################################################
#DEBUG - Reboot nightly til I figure out whats wrong
#rebootRpi()
#flagCounterFile.close()
averageFileSizeMp4BytesFile.close()
#######################
#Start of main program#
#######################
if __name__ == "__main__":
#Debug
now = datetime.datetime.now()
#log file paths
PATH = '/home/pi/html-php-scripts/mp4/logs/'
print("Starting stream capture cam program")
try:
print(now.strftime("%Y-%m-%d %H:%M:%S.%f"),",Starting stream capture cam program",file=open(PATH+"debug-fisheye-car-cam-"+now.strftime("%Y-%m-%d")+".log", "a"))
except OSError as error:
print("Save debug file error:::", error)
#Email to show rpi rebooted / restarted - delay to let network to startup
print("Sleeping for 5 seconds - delayed start")
print(now.strftime("%Y-%m-%d %H:%M:%S.%f"),",Sleeping for 5 seconds - delayed start",file=open(PATH+"debug-fisheye-car-cam-"+now.strftime("%Y-%m-%d")+".log", "a"))
#sleep
time.sleep(5)
#notify via email of start or restart/reboot
sendEmailTrigger()
with picamera.PiCamera(resolution='1640x1232', framerate=30) as camera:
camera.rotation = 90
output = StreamingOutput()
address = ('', 8000)
server = StreamingServer(address, StreamingHandler)
server_thread = Thread(target=server.serve_forever)
server_thread.start()
#multiprocess streaming conversion
#m = mp.Process(target=server.serve_forever, args=())
#m.start()
print("Starting STREAM CAM program")
now = datetime.datetime.now()
print("Date and Time started:::", now.strftime("%Y-%m-%d %H:%M:%S.%f"))
print(now.strftime("%Y-%m-%d %H:%M:%S.%f"),",Streaming started on port 8000 and mp4 splitter recording.",file=open(PATH+"debug-fisheye-car-cam-"+now.strftime("%Y-%m-%d")+".log", "a"))
camera.start_recording(output, format='mjpeg',splitter_port=1,bitrate=20000000)
print("Server started now onto h264")
while True:
#date and time now
now = datetime.datetime.now()
#check time as a debug measure where MJPEG stream dies every 24 hours - reboot to refresh
checkHour = str(now.strftime("%H"))
checkMinute = str(now.strftime("%M"))
try:
#stop and start mjpeg stream every 60 seconds
minuteDivider = int(checkMinute)%60
if (minuteDivider == 0):
camera.stop_recording(splitter_port=1)
print("Date and Time mjpeg restarted:::", now.strftime("%Y-%m-%d %H:%M:%S.%f"))
print(now.strftime("%Y-%m-%d %H:%M:%S.%f"),",","mjpeg stream restarted",file=open(PATH+"mjpg-restart-status-" + now.strftime("%Y-%m-%d")+".log","a"))
camera.start_recording(output, format='mjpeg',splitter_port=1,bitrate=25000000)
else:
print("Date and Time not divisible exactly by 60 ::: remainder :::",",",minuteDivider,now.strftime("%Y-%m-%d %H:%M:%S.%f"))
#Debug
print(now.strftime("%Y-%m-%d %H:%M:%S.%f"),",Date and Time not divisible exactly by 60 ::: remainder:::,",minuteDivider,file=open(PATH+"mjpg-restart-status-" + now.strftime("%Y-%m-%d")+".log","a"))
except Exception as e:
print(e)
print(now.strftime("%Y-%m-%d %H:%M:%S.%f"),",",e,file=open(PATH+"mjpg-restart-status-" + now.strftime("%Y-%m-%d")+".log","a"))
pass
try:
statePath = '/home/pi/html-php-scripts/mp4/logs'
#pathlib.Path(statePath).mkdir(parents=True, exist_ok=True)
os.makedirs(statePath, mode=0o755, exist_ok=True)
except OSError as error:
sys.exit("Can't create {dir}: {err}".format(dir=statepath, err=error))
try:
#delete old files older than
n = 3
#Debug
#delete files older than x days
now = datetime.datetime.now()
print(now.strftime("%Y-%m-%d %H:%M:%S.%f"),",Check dirs and files older than 3 days and delete...",file=open(PATH+"debug-fisheye-car-cam-"+now.strftime("%Y-%m-%d")+".log", "a"))
date_N_days_ago = datetime.datetime.now() - datetime.timedelta(days=n)
#remove directoy n days ago
shutil.rmtree('/home/pi/html-php-scripts/mp4/'+date_N_days_ago.strftime("%Y-%m-%d"))
except OSError as error:
#sys.exit("Can't delete: {err}", err=error)
print("Failed to clean up Dirs and Files....continue...",error)
print(now.strftime("%Y-%m-%d %H:%M:%S.%f"),",Failed to clean up Dirs and Files....continue...,",error,file=open(PATH+"debug-fisheye-car-cam-"+now.strftime("%Y-%m-%d")+".log", "a"))
pass
#DEBUG
print("..........................................")
#Create full path - H264
fileNameH264 = "stream-" + now.strftime("%Y-%m-%d--%H-%M-%S-%f")+".h264"
#Create full path - MP4
fileNameMp4 = "stream-" + now.strftime("%Y-%m-%d--%H-%M-%S-%f")+".mp4"
#Create full path - h264
fileNameH264Path = "/temp/mp4/"+fileNameH264
#Create full path - mp4
fileNameMp4Path = "/home/pi/html-php-scripts/mp4/"+now.strftime("%Y-%m-%d")+"/"+fileNameMp4
try:
#Create Directory if it does not exist - sort in days
pathlib.Path('/home/pi/html-php-scripts/mp4/'+now.strftime("%Y-%m-%d")).mkdir(parents=True, exist_ok=True)
except:
pass
#fisheyeCamImageSavePath = fileNameJpgPath
fisheyeCamH264SavePath = fileNameH264Path
fisheyeCamMp4SavePath = fileNameMp4Path
###################################################################################################
#try saving buffer to file mjpeg
#fileNameH264 = "stream-h264-"+now.strftime("%Y-%m-%d-%H-%M")+".h264"
#fileH264Path = "/home/pi/html-php-scripts/mjpeg/"+now.strftime("%Y-%m-%d")+"/"+fileH264
camera.annotate_frame_num = True
camera.annotate_text = now.strftime("%Y-%m-%d %H:%M:%S.%f")
camera.start_recording(fileNameH264Path, format='h264', splitter_port=2,quality=25,bitrate=0)
camera.wait_recording(20, splitter_port=2)
#init text frame nubers
camera.stop_recording(splitter_port=2)
#multiprocess h264 to mp4 conversion
d = mp.Process(target=convertH264Mp4, args=(fisheyeCamMp4SavePath,fisheyeCamH264SavePath,fileNameMp4))
d.start()