Module lib.webpage.streamingpage

Function define the web page to see the camera streaming

Expand source code
# Distributed under Pycameresp License
# Copyright (c) 2023 Remi BERTHOLET
""" Function define the web page to see the camera streaming """
import uasyncio
import server.httpserver
import server.httprequest
from htmltemplate       import *
import video.video
import tools.logger
import tools.tasking
import tools.info
import tools.watchdog
import tools.features

class Streaming:
        """ Management class of video streaming of the camera via an html page """
        streaming_id = [0]
        inactivity = [None]
        config = [None]
        durty = [False]

        @staticmethod
        def set_config(config):
                """ Set current configuration """
                Streaming.config[0] = config
                Streaming.durty[0] = True

        @staticmethod
        def get_config():
                """ Get current configuration """
                return Streaming.config[0]

        @staticmethod
        def is_durty():
                """ Indicates if the configuration changed """
                return Streaming.durty[0]

        @staticmethod
        def reset_durty():
                """ Reset the configuration changed flag """
                Streaming.durty[0] = False

        @staticmethod
        def get_html(request):
                """ Return streaming html part with javascript code """
                Streaming.activity()
                Streaming.streaming_id[0] += id(request)
                return Tag(b"""
                <div style="position: relative;">
                        <img id="video-stream" src="" width="100%%"/>
                        <table id="zone_masking" style="position: absolute;top:0px" />
                </div>  
                <script>
                        var streamUrl = document.location.protocol + "//" + document.location.hostname + ':%d';
                        document.getElementById('video-stream').src = `${streamUrl}/camera/start?streaming_id=%d`;
                </script>"""%(request.port+1,Streaming.streaming_id[0]))

        @staticmethod
        def activity():
                """ User activity detected """
                if Streaming.inactivity[0]:
                        Streaming.inactivity[0].stop()
                        Streaming.inactivity[0] = None
                Streaming.inactivity[0] = tools.tasking.Inactivity(Streaming.stop, duration=tools.watchdog.LONG_WATCH_DOG, timer_id=1)

        @staticmethod
        def get_streaming_id():
                """ Return the current streaming id """
                return Streaming.streaming_id[0]

        @staticmethod
        def stop():
                """ Stop streaming """
                Streaming.streaming_id[0] += 1

@server.httpserver.HttpServer.add_route(b'/camera/start', available=tools.info.iscamera() and video.video.Camera.is_activated() and tools.features.features.camera)
async def camera_start_streaming(request, response, args):
        """ Start video streaming """
        tools.tasking.Tasks.slow_down()
        if request.name != "HttpStreaming":
                return

        try:
                writer = None
                currentstreaming_id = int(request.params[b"streaming_id"])
                reserved = await video.video.Camera.reserve(request, timeout=5, suspension=10)
                if reserved:
                        failed = False
                        video.video.Camera.open()

                        response.set_status(b"200")
                        response.set_header(b"Content-Type"               ,b"multipart/x-mixed-replace")
                        response.set_header(b"Transfer-Encoding"          ,b"chunked")
                        response.set_header(b"Access-Control-Allow-Origin",b"*")

                        await response.serialize(response.streamio)
                        writer = response.streamio
                        identifier = b"\r\n%x\r\n\r\n--%s\r\n\r\n"%(len(response.identifier) + 6, response.identifier)
                        frame = b'%s36\r\nContent-Type: image/jpeg\r\nContent-Length: %8d\r\n\r\n\r\n%x\r\n'

                        if tools.filesystem.ismicropython():
                                micropython = True
                        else:
                                micropython = False

                        if Streaming.is_durty():
                                video.video.Camera.configure(Streaming.get_config())
                                Streaming.reset_durty()

                        image = video.video.Camera.capture()
                        length = len(image)
                        try:
                                await writer.write(frame%(b"", length, length))
                                await writer.write(image)
                        except Exception as err:
                                failed = True
                                currentstreaming_id = 0

                        while currentstreaming_id == Streaming.get_streaming_id():
                                if Streaming.is_durty():
                                        video.video.Camera.configure(Streaming.get_config())
                                        Streaming.reset_durty()
                                image = video.video.Camera.capture()
                                length = len(image)
                                try:
                                        await writer.write(frame%(identifier, length, length))
                                        await writer.write(image)
                                except Exception as err:
                                        failed = True
                                        break
                                if micropython is False:
                                        await uasyncio.sleep(0.1)
                        if failed is False:
                                await writer.write(identifier)
                else:
                        pass
        except Exception as err:
                tools.logger.syslog(err)
        finally:
                if reserved:
                        await video.video.Camera.unreserve(request)
                if writer:
                        await writer.close()

Functions

async def camera_start_streaming(request, response, args)

Start video streaming

Expand source code
@server.httpserver.HttpServer.add_route(b'/camera/start', available=tools.info.iscamera() and video.video.Camera.is_activated() and tools.features.features.camera)
async def camera_start_streaming(request, response, args):
        """ Start video streaming """
        tools.tasking.Tasks.slow_down()
        if request.name != "HttpStreaming":
                return

        try:
                writer = None
                currentstreaming_id = int(request.params[b"streaming_id"])
                reserved = await video.video.Camera.reserve(request, timeout=5, suspension=10)
                if reserved:
                        failed = False
                        video.video.Camera.open()

                        response.set_status(b"200")
                        response.set_header(b"Content-Type"               ,b"multipart/x-mixed-replace")
                        response.set_header(b"Transfer-Encoding"          ,b"chunked")
                        response.set_header(b"Access-Control-Allow-Origin",b"*")

                        await response.serialize(response.streamio)
                        writer = response.streamio
                        identifier = b"\r\n%x\r\n\r\n--%s\r\n\r\n"%(len(response.identifier) + 6, response.identifier)
                        frame = b'%s36\r\nContent-Type: image/jpeg\r\nContent-Length: %8d\r\n\r\n\r\n%x\r\n'

                        if tools.filesystem.ismicropython():
                                micropython = True
                        else:
                                micropython = False

                        if Streaming.is_durty():
                                video.video.Camera.configure(Streaming.get_config())
                                Streaming.reset_durty()

                        image = video.video.Camera.capture()
                        length = len(image)
                        try:
                                await writer.write(frame%(b"", length, length))
                                await writer.write(image)
                        except Exception as err:
                                failed = True
                                currentstreaming_id = 0

                        while currentstreaming_id == Streaming.get_streaming_id():
                                if Streaming.is_durty():
                                        video.video.Camera.configure(Streaming.get_config())
                                        Streaming.reset_durty()
                                image = video.video.Camera.capture()
                                length = len(image)
                                try:
                                        await writer.write(frame%(identifier, length, length))
                                        await writer.write(image)
                                except Exception as err:
                                        failed = True
                                        break
                                if micropython is False:
                                        await uasyncio.sleep(0.1)
                        if failed is False:
                                await writer.write(identifier)
                else:
                        pass
        except Exception as err:
                tools.logger.syslog(err)
        finally:
                if reserved:
                        await video.video.Camera.unreserve(request)
                if writer:
                        await writer.close()

Classes

class Streaming

Management class of video streaming of the camera via an html page

Expand source code
class Streaming:
        """ Management class of video streaming of the camera via an html page """
        streaming_id = [0]
        inactivity = [None]
        config = [None]
        durty = [False]

        @staticmethod
        def set_config(config):
                """ Set current configuration """
                Streaming.config[0] = config
                Streaming.durty[0] = True

        @staticmethod
        def get_config():
                """ Get current configuration """
                return Streaming.config[0]

        @staticmethod
        def is_durty():
                """ Indicates if the configuration changed """
                return Streaming.durty[0]

        @staticmethod
        def reset_durty():
                """ Reset the configuration changed flag """
                Streaming.durty[0] = False

        @staticmethod
        def get_html(request):
                """ Return streaming html part with javascript code """
                Streaming.activity()
                Streaming.streaming_id[0] += id(request)
                return Tag(b"""
                <div style="position: relative;">
                        <img id="video-stream" src="" width="100%%"/>
                        <table id="zone_masking" style="position: absolute;top:0px" />
                </div>  
                <script>
                        var streamUrl = document.location.protocol + "//" + document.location.hostname + ':%d';
                        document.getElementById('video-stream').src = `${streamUrl}/camera/start?streaming_id=%d`;
                </script>"""%(request.port+1,Streaming.streaming_id[0]))

        @staticmethod
        def activity():
                """ User activity detected """
                if Streaming.inactivity[0]:
                        Streaming.inactivity[0].stop()
                        Streaming.inactivity[0] = None
                Streaming.inactivity[0] = tools.tasking.Inactivity(Streaming.stop, duration=tools.watchdog.LONG_WATCH_DOG, timer_id=1)

        @staticmethod
        def get_streaming_id():
                """ Return the current streaming id """
                return Streaming.streaming_id[0]

        @staticmethod
        def stop():
                """ Stop streaming """
                Streaming.streaming_id[0] += 1

Class variables

var config
var durty
var inactivity
var streaming_id

Static methods

def activity()

User activity detected

Expand source code
@staticmethod
def activity():
        """ User activity detected """
        if Streaming.inactivity[0]:
                Streaming.inactivity[0].stop()
                Streaming.inactivity[0] = None
        Streaming.inactivity[0] = tools.tasking.Inactivity(Streaming.stop, duration=tools.watchdog.LONG_WATCH_DOG, timer_id=1)
def get_config()

Get current configuration

Expand source code
@staticmethod
def get_config():
        """ Get current configuration """
        return Streaming.config[0]
def get_html(request)

Return streaming html part with javascript code

Expand source code
@staticmethod
def get_html(request):
        """ Return streaming html part with javascript code """
        Streaming.activity()
        Streaming.streaming_id[0] += id(request)
        return Tag(b"""
        <div style="position: relative;">
                <img id="video-stream" src="" width="100%%"/>
                <table id="zone_masking" style="position: absolute;top:0px" />
        </div>  
        <script>
                var streamUrl = document.location.protocol + "//" + document.location.hostname + ':%d';
                document.getElementById('video-stream').src = `${streamUrl}/camera/start?streaming_id=%d`;
        </script>"""%(request.port+1,Streaming.streaming_id[0]))
def get_streaming_id()

Return the current streaming id

Expand source code
@staticmethod
def get_streaming_id():
        """ Return the current streaming id """
        return Streaming.streaming_id[0]
def is_durty()

Indicates if the configuration changed

Expand source code
@staticmethod
def is_durty():
        """ Indicates if the configuration changed """
        return Streaming.durty[0]
def reset_durty()

Reset the configuration changed flag

Expand source code
@staticmethod
def reset_durty():
        """ Reset the configuration changed flag """
        Streaming.durty[0] = False
def set_config(config)

Set current configuration

Expand source code
@staticmethod
def set_config(config):
        """ Set current configuration """
        Streaming.config[0] = config
        Streaming.durty[0] = True
def stop()

Stop streaming

Expand source code
@staticmethod
def stop():
        """ Stop streaming """
        Streaming.streaming_id[0] += 1