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"


#Email

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()