Recherche avancée

Médias (1)

Mot : - Tags -/censure

Autres articles (8)

  • Encoding and processing into web-friendly formats

    13 avril 2011, par

    MediaSPIP automatically converts uploaded files to internet-compatible formats.
    Video files are encoded in MP4, Ogv and WebM (supported by HTML5) and MP4 (supported by Flash).
    Audio files are encoded in MP3 and Ogg (supported by HTML5) and MP3 (supported by Flash).
    Where possible, text is analyzed in order to retrieve the data needed for search engine detection, and then exported as a series of image files.
    All uploaded files are stored online in their original format, so you can (...)

  • D’autres logiciels intéressants

    12 avril 2011, par

    On ne revendique pas d’être les seuls à faire ce que l’on fait ... et on ne revendique surtout pas d’être les meilleurs non plus ... Ce que l’on fait, on essaie juste de le faire bien, et de mieux en mieux...
    La liste suivante correspond à des logiciels qui tendent peu ou prou à faire comme MediaSPIP ou que MediaSPIP tente peu ou prou à faire pareil, peu importe ...
    On ne les connais pas, on ne les a pas essayé, mais vous pouvez peut être y jeter un coup d’oeil.
    Videopress
    Site Internet : (...)

  • Menus personnalisés

    14 novembre 2010, par

    MediaSPIP utilise le plugin Menus pour gérer plusieurs menus configurables pour la navigation.
    Cela permet de laisser aux administrateurs de canaux la possibilité de configurer finement ces menus.
    Menus créés à l’initialisation du site
    Par défaut trois menus sont créés automatiquement à l’initialisation du site : Le menu principal ; Identifiant : barrenav ; Ce menu s’insère en général en haut de la page après le bloc d’entête, son identifiant le rend compatible avec les squelettes basés sur Zpip ; (...)

Sur d’autres sites (4078)

  • CGO : How do I write to a file in Golang using a pointer to the C data ?

    24 avril 2018, par nevernew

    I’m writing an app for the windows platform using FFmpeg and it’s golang wrapper goav, but I’m having trouble understanding how to use the C pointers to gain access to an array.

    I’m trying to write the frame data, pointed to by a uint8 pointer from C, to a .ppm file in golang.

    Once I have this done, for proof of concept that FFmpeg is doing what I expect it to, I want to set the frames to a texture in OpenGl to make a video player with cool transitions ; any pointers to do that nice and efficiently would be so very helpful ! I’m guessing I need to write some shader code to draw the ppm as a texture...

    I’m starting to understanding how to cast the pointers between C and Go types, but how can I access the data and write it in Go with the same result as C ? In C I just have to set the pointer offset for the data and state how much of it to write :

    for (y = 0; y < height; y++) {
       fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);
    }

    I’ve stripped out all the relevant parts of the C code, the wrapper and my code, shown below :

    C code - libavutil/frame.h

    #include

    typedef struct AVFrame {
    #define AV_NUM_DATA_POINTERS 8
       uint8_t *data[AV_NUM_DATA_POINTERS];
       int linesize[AV_NUM_DATA_POINTERS];
    }

    Golang goav wrapper

    package avutil

    /*
       #cgo pkg-config: libavutil
       #include <libavutil></libavutil>frame.h>
       #include
    */
    import "C"
    import (
       "unsafe"
    )

    type Frame C.struct_AVFrame

    func Data(f *Frame) *uint8 {
       return (*uint8)(unsafe.Pointer((*C.uint8_t)(unsafe.Pointer(&amp;f.data))))
    }
    func Linesize(f *Frame) int {
       return int(*(*C.int)(unsafe.Pointer(&amp;f.linesize)))
    }

    My Golang code

    package main

    import "github.com/giorgisio/goav/avutil"

    func saveFrame(videoFrame *avutil.Frame, width int, height int, iFrame int) {
       var szFilename string
       var y int
       var file *os.File
       var err error

       szFilename = ""

       // Open file
       szFilename = fmt.Sprintf("frame%d.ppm", iFrame)

       if file, err = os.Open(szFilename); err != nil {
           log.Println("Error Reading")
       }

       // Write header
       fh := []byte(fmt.Sprintf("P6\n%d %d\n255\n", width, height))
       file.Write(fh)
       var b byte = 0
       // Write pixel data
       for y = 0; y &lt; height; y++ {
           d := avutil.Data(videoFrame) // d should be a pointer to the first byte of data
           l := avutil.Linesize(videoFrame)

           // I'm basically lost trying to figure out how to write this to a file
           data := make([]byte, width*3)

           addr := int(*d) + y*l // figure out the address

           for i := 0; i &lt; l; i++ {
               // This is where I'm having the problem, I get an "invalid
               // memory address or nil pointer dereference" error
               byteArrayPtr := (*byte)(unsafe.Pointer(uintptr(addr) + uintptr(i)*unsafe.Sizeof(b)))
               data = append(data, *byteArrayPtr)
               fmt.Println(*byteArrayPtr)
           }
           file.Write(data)
       }

       file.Close()
    }

    So, how can I write to a file using a pointer to the data, like you can do in C ?

  • [ffmpeg][asyncio] main process is held by ffmpeg command

    5 octobre 2024, par Michael Lopez

    I created a python program for handling my Arlo Camera. To do that I have been using the pyaarlo library (https://github.com/twrecked/pyaarlo) to catch camera's events.&#xA;The goal is to monitor if there is an active stream on cameras, get the RTSP stream url and reStream it to a HLS playlist for local usage.

    &#xA;

    Here the python code :

    &#xA;

    import asyncio&#xA;from decouple import config&#xA;import logging&#xA;from my_pyaarlo import PyArlo&#xA;import urllib.parse&#xA;from queue import Queue&#xA;import signal&#xA;&#xA;# Read config from ENV (unchanged)&#xA;ARLO_USER = config(&#x27;ARLO_USER&#x27;)&#xA;ARLO_PASS = config(&#x27;ARLO_PASS&#x27;)&#xA;IMAP_HOST = config(&#x27;IMAP_HOST&#x27;)&#xA;IMAP_USER = config(&#x27;IMAP_USER&#x27;)&#xA;IMAP_PASS = config(&#x27;IMAP_PASS&#x27;)&#xA;DEBUG = config(&#x27;DEBUG&#x27;, default=False, cast=bool)&#xA;PYAARLO_BACKEND = config(&#x27;PYAARLO_BACKEND&#x27;, default=None)&#xA;PYAARLO_REFRESH_DEVICES = config(&#x27;PYAARLO_REFRESH_DEVICES&#x27;, default=0, cast=int)&#xA;PYAARLO_STREAM_TIMEOUT = config(&#x27;PYAARLO_STREAM_TIMEOUT&#x27;, default=0, cast=int)&#xA;PYAARLO_STORAGE_DIR = config(&#x27;PYAARLO_STORAGE_DIR&#x27;, default=None)&#xA;PYAARLO_ECDH_CURVE = config(&#x27;PYAARLO_ECDH_CURVE&#x27;, default=None)&#xA;&#xA;# Initialize logging&#xA;logging.basicConfig(&#xA;    level=logging.DEBUG if DEBUG else logging.INFO,&#xA;    format=&#x27;%(asctime)s [%(levelname)s] %(name)s: %(message)s&#x27;&#xA;)&#xA;logger = logging.getLogger(__name__)&#xA;&#xA;ffmpeg_processes = {}&#xA;event_queue = Queue()&#xA;shutdown_event = asyncio.Event()&#xA;&#xA;async def handle_idle_event(camera):&#xA;    logger.info(f"Idle event detected for camera: {camera.name}")&#xA;    await stop_ffmpeg_stream(camera.name)&#xA;&#xA;async def get_stream_url(camera):&#xA;    try:&#xA;        # Attempt to get the stream URL&#xA;        stream_url = await asyncio.to_thread(camera.get_stream()&#xA;        if stream_url:&#xA;            return stream_url&#xA;        else:&#xA;            logger.warning(f"Unable to get stream URL for {camera.name}. Stream might not be active.")&#xA;            return None&#xA;    except Exception as e:&#xA;        logger.error(f"Error getting stream URL for {camera.name}: {e}")&#xA;        return None&#xA;&#xA;async def handle_user_stream_active_event(camera):&#xA;    logger.info(f"User stream active event detected for camera: {camera.name}")&#xA;&#xA;    # Get the stream URL&#xA;    stream_url = await get_stream_url(camera)&#xA;    if stream_url:&#xA;        logger.info(f"Stream URL for {camera.name}: {stream_url}")&#xA;        await start_ffmpeg_stream(camera.name, stream_url)&#xA;    else:&#xA;        logger.warning(f"No stream URL available for {camera.name}")&#xA;&#xA;async def event_handler(device, attr, value):&#xA;    logger.debug(f"Event: {device.name}, Attribute: {attr}, Value: {value}")&#xA;    if attr == &#x27;activityState&#x27;:&#xA;        if value == &#x27;idle&#x27;:&#xA;            await handle_idle_event(device)&#xA;        elif value in [&#x27;userStreamActive&#x27;]:&#xA;            await handle_user_stream_active_event(device)&#xA;    elif attr == &#x27;mediaUploadNotification&#x27;:&#xA;        logger.info(f"Media uploaded for camera: {device.name}")&#xA;&#xA;def sync_event_handler(device, attr, value):&#xA;    # This function will be called by PyArlo&#x27;s synchronous callbacks&#xA;    event_queue.put((device, attr, value))&#xA;&#xA;async def process_event_queue():&#xA;    while not shutdown_event.is_set():&#xA;        try:&#xA;            if not event_queue.empty():&#xA;                device, attr, value = event_queue.get()&#xA;                await event_handler(device, attr, value)&#xA;            await asyncio.sleep(0.1)  # Small delay to prevent busy-waiting&#xA;        except asyncio.CancelledError:&#xA;            break&#xA;        except Exception as e:&#xA;            logger.error(f"Error processing event: {e}")&#xA;&#xA;async def display_status(arlo):&#xA;    while not shutdown_event.is_set():&#xA;        print("\n--- Camera Statuses ---")&#xA;        for camera in arlo.cameras:&#xA;            print(f"{camera.name}: {camera.state}")&#xA;        print("------------------------")&#xA;        await asyncio.sleep(5)&#xA;&#xA;async def start_ffmpeg_stream(camera_name, stream_url):&#xA;    if camera_name not in ffmpeg_processes:&#xA;        output_hls = f"/tmp/{camera_name}.m3u8"&#xA;&#xA;        try:&#xA;            new_url = urllib.parse.quote(stream_url.encode(), safe=&#x27;:/?&amp;=&#x27;)&#xA;            logger.info(f"NEW_URL: {new_url}")&#xA;&#xA;            ffmpeg_cmd = [&#xA;                "ffmpeg", "-hide_banner", "-loglevel", "quiet", "-nostats", "-nostdin", "-y", "-re",&#xA;                "-i", new_url,&#xA;                "-c:v", "libx264", "-preset", "veryfast",&#xA;                "-an", "-sn",&#xA;                "-f", "hls", "-hls_time", "4", "-hls_list_size", "10",&#xA;                "-hls_flags", "delete_segments", output_hls,&#xA;            ]&#xA;            logger.info(f"Starting FFmpeg command: {ffmpeg_cmd}")&#xA;            &#xA;            process = await asyncio.create_subprocess_exec(&#xA;                *ffmpeg_cmd,&#xA;                stdout=asyncio.subprocess.DEVNULL,&#xA;                stderr=asyncio.subprocess.DEVNULL&#xA;            )&#xA;            ffmpeg_processes[camera_name] = process&#xA;            logger.info(f"Started ffmpeg process with PID: {process.pid}")&#xA;&#xA;        except Exception as e:&#xA;            logger.error(f"Error starting FFmpeg for {camera_name}: {e}")&#xA;&#xA;async def stop_ffmpeg_stream(camera_name):&#xA;    logger.info(f"Stopping ffmpeg process for {camera_name}")&#xA;    ffmpeg_process = ffmpeg_processes.pop(camera_name, None)&#xA;    if ffmpeg_process:&#xA;        ffmpeg_process.terminate()&#xA;&#xA;        try:&#xA;            await ffmpeg_process.wait()&#xA;            logger.info(f"{camera_name} stopped successfully")&#xA;        except Exception as e:&#xA;            print(f"FFMPEG Process didn&#x27;t stop in time, forcefully terminating: {e}")&#xA;            ffmpeg_process.kill()&#xA;    else:&#xA;        logger.info(f"FFmpeg process for {camera_name} already stopped")&#xA;&#xA;async def shutdown(signal, loop):&#xA;    logger.info(f"Received exit signal {signal.name}...")&#xA;    shutdown_event.set()&#xA;    tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]&#xA;    [task.cancel() for task in tasks]&#xA;    logger.info(f"Cancelling {len(tasks)} outstanding tasks")&#xA;    await asyncio.gather(*tasks, return_exceptions=True)&#xA;    loop.stop()&#xA;&#xA;async def main():&#xA;    # Initialize PyArlo&#xA;    arlo_args = {&#xA;        &#x27;username&#x27;: ARLO_USER,&#xA;        &#x27;password&#x27;: ARLO_PASS,&#xA;        &#x27;tfa_source&#x27;: &#x27;imap&#x27;,&#xA;        &#x27;tfa_type&#x27;: &#x27;email&#x27;,&#xA;        &#x27;tfa_host&#x27;: IMAP_HOST,&#xA;        &#x27;tfa_username&#x27;: IMAP_USER,&#xA;        &#x27;tfa_password&#x27;: IMAP_PASS,&#xA;        &#x27;save_session&#x27;: True,&#xA;        &#x27;verbose_debug&#x27;: DEBUG&#xA;    }&#xA;&#xA;    # Add optional arguments&#xA;    for arg, value in [&#xA;        (&#x27;refresh_devices_every&#x27;, PYAARLO_REFRESH_DEVICES),&#xA;        (&#x27;stream_timeout&#x27;, PYAARLO_STREAM_TIMEOUT),&#xA;        (&#x27;backend&#x27;, PYAARLO_BACKEND),&#xA;        (&#x27;storage_dir&#x27;, PYAARLO_STORAGE_DIR),&#xA;        (&#x27;ecdh_curve&#x27;, PYAARLO_ECDH_CURVE)&#xA;    ]:&#xA;        if value:&#xA;            arlo_args[arg] = value&#xA;    &#xA;    try:&#xA;        arlo = await asyncio.to_thread(PyArlo, **arlo_args)&#xA;    except Exception as e:&#xA;        logger.error(f"Failed to initialize PyArlo: {e}")&#xA;        return&#xA;&#xA;    logger.info("Connected to Arlo. Monitoring events...")&#xA;&#xA;    # Register event handlers for each camera&#xA;    for camera in arlo.cameras:&#xA;        camera.add_attr_callback(&#x27;*&#x27;, sync_event_handler)&#xA;&#xA;    # Start the status display task&#xA;    status_task = asyncio.create_task(display_status(arlo))&#xA;&#xA;    # Start the event processing task&#xA;    event_processing_task = asyncio.create_task(process_event_queue())&#xA;&#xA;    # Set up signal handlers&#xA;    loop = asyncio.get_running_loop()&#xA;    for s in (signal.SIGHUP, signal.SIGTERM, signal.SIGINT):&#xA;        loop.add_signal_handler(&#xA;            s, lambda s=s: asyncio.create_task(shutdown(s, loop)))&#xA;&#xA;    try:&#xA;        # Keep the main coroutine running&#xA;        while not shutdown_event.is_set():&#xA;            try:&#xA;                await asyncio.sleep(1)&#xA;            except asyncio.CancelledError:&#xA;                break&#xA;    except Exception as e:&#xA;        logger.error(f"Unexpected error in main loop: {e}")&#xA;    finally:&#xA;        logger.info("Shutting down...")&#xA;        for camera_name in list(ffmpeg_processes.keys()):&#xA;            await stop_ffmpeg_stream(camera_name)&#xA;        &#xA;        # Cancel and wait for all tasks&#xA;        tasks = [status_task, event_processing_task]&#xA;        for task in tasks:&#xA;            if not task.done():&#xA;                task.cancel()&#xA;        await asyncio.gather(*tasks, return_exceptions=True)&#xA;        &#xA;        logger.info("Program terminated.")&#xA;&#xA;if __name__ == "__main__":&#xA;    try:&#xA;        asyncio.run(main())&#xA;    except KeyboardInterrupt:&#xA;        logger.info("Keyboard interrupt received. Exiting.")&#xA;    except Exception as e:&#xA;        logger.error(f"Unhandled exception: {e}")&#xA;    finally:&#xA;        logger.info("Program exit complete.")&#xA;

    &#xA;

    My issue is about the ffmpeg command which is hold the main process (or the event loop) when it runs, blocking the events coming from the pyaarlo library. The state of the camera continues to work with the good information.

    &#xA;

    I tried lot of things, without asyncio, with multiprocessing, with subprocess, ... the behavior is always the same. In some cases, I received the idle event after the key interrupt.

    &#xA;

    Another information :

    &#xA;

      &#xA;
    • When I stop the active stream, the event is not received but when I start the stream just after, that event is received.
    • &#xA;

    • When I run the same ffmpeg command but with a local long video file, everything is Ok. So, it why I guess that the ffmpeg command is impacting the main process.
    • &#xA;

    &#xA;

    I succedeed in running the ffmpeg command with rtsp url stream but without a loop event monitoring :

    &#xA;

    import asyncio&#xA;import signal&#xA;import sys&#xA;import os&#xA;&#xA;async def run_infinite_command():&#xA;    # Start a simple HTTP server as our "infinite" command&#xA;    url = "rstp://localhost:8554/camera1/stream" # it is a fake url&#xA;    ffmpeg_cmd = [&#xA;        "ffmpeg", "-re", "-i", url,&#xA;        "-c:v", "libx264", "-preset", "veryfast",&#xA;        "-c:a", "copy",&#xA;        "-f", "hls", "-hls_time", "4", "-hls_list_size", "10",&#xA;        "-hls_flags", "delete_segments", "/tmp/output.m3u8"&#xA;    ]&#xA;    &#xA;    process = await asyncio.create_subprocess_exec(&#xA;        *ffmpeg_cmd,&#xA;        stdout=asyncio.subprocess.DEVNULL,&#xA;        stderr=asyncio.subprocess.DEVNULL&#xA;    )&#xA;    &#xA;    print(f"Started HTTP server with PID: {process.pid}")&#xA;    return process&#xA;&#xA;async def main():&#xA;    # Start the infinite command&#xA;    process = await run_infinite_command()&#xA;&#xA;    # Run the main loop for a few seconds&#xA;    for i in range(10):&#xA;        print(f"Main loop iteration {i&#x2B;1}")&#xA;        await asyncio.sleep(1)&#xA;&#xA;    # Stop the infinite command&#xA;    print("Stopping the HTTP server...")&#xA;    if sys.platform == "win32":&#xA;        # On Windows, we need to use CTRL_C_EVENT&#xA;        os.kill(process.pid, signal.CTRL_C_EVENT)&#xA;    else:&#xA;        # On Unix-like systems, we can use SIGTERM&#xA;        process.send_signal(signal.SIGTERM)&#xA;&#xA;    # Wait for the process to finish&#xA;    try:&#xA;        await asyncio.wait_for(process.wait(), timeout=5.0)&#xA;        print("HTTP server stopped successfully")&#xA;    except asyncio.TimeoutError:&#xA;        print("HTTP server didn&#x27;t stop in time, forcefully terminating")&#xA;        process.kill()&#xA;&#xA;    print("Program finished")&#xA;&#xA;if __name__ == "__main__":&#xA;    asyncio.run(main())&#xA;

    &#xA;

    With this script, the ffmpeg command is correctly launched and terminated after the for loop.

    &#xA;

    Could you help ?

    &#xA;

  • Main process is held by ffmpeg command

    6 octobre 2024, par Michael Lopez

    I created a python program for handling my Arlo Camera. To do that I have been using the pyaarlo library (https://github.com/twrecked/pyaarlo) to catch camera's events.&#xA;The goal is to monitor if there is an active stream on cameras, get the RTSP stream url and reStream it to a HLS playlist for local usage.

    &#xA;

    Here the python code :

    &#xA;

    import asyncio&#xA;from decouple import config&#xA;import logging&#xA;from my_pyaarlo import PyArlo&#xA;import urllib.parse&#xA;from queue import Queue&#xA;import signal&#xA;&#xA;# Read config from ENV (unchanged)&#xA;ARLO_USER = config(&#x27;ARLO_USER&#x27;)&#xA;ARLO_PASS = config(&#x27;ARLO_PASS&#x27;)&#xA;IMAP_HOST = config(&#x27;IMAP_HOST&#x27;)&#xA;IMAP_USER = config(&#x27;IMAP_USER&#x27;)&#xA;IMAP_PASS = config(&#x27;IMAP_PASS&#x27;)&#xA;DEBUG = config(&#x27;DEBUG&#x27;, default=False, cast=bool)&#xA;PYAARLO_BACKEND = config(&#x27;PYAARLO_BACKEND&#x27;, default=None)&#xA;PYAARLO_REFRESH_DEVICES = config(&#x27;PYAARLO_REFRESH_DEVICES&#x27;, default=0, cast=int)&#xA;PYAARLO_STREAM_TIMEOUT = config(&#x27;PYAARLO_STREAM_TIMEOUT&#x27;, default=0, cast=int)&#xA;PYAARLO_STORAGE_DIR = config(&#x27;PYAARLO_STORAGE_DIR&#x27;, default=None)&#xA;PYAARLO_ECDH_CURVE = config(&#x27;PYAARLO_ECDH_CURVE&#x27;, default=None)&#xA;&#xA;# Initialize logging&#xA;logging.basicConfig(&#xA;    level=logging.DEBUG if DEBUG else logging.INFO,&#xA;    format=&#x27;%(asctime)s [%(levelname)s] %(name)s: %(message)s&#x27;&#xA;)&#xA;logger = logging.getLogger(__name__)&#xA;&#xA;ffmpeg_processes = {}&#xA;event_queue = Queue()&#xA;shutdown_event = asyncio.Event()&#xA;&#xA;async def handle_idle_event(camera):&#xA;    logger.info(f"Idle event detected for camera: {camera.name}")&#xA;    await stop_ffmpeg_stream(camera.name)&#xA;&#xA;async def get_stream_url(camera):&#xA;    try:&#xA;        # Attempt to get the stream URL&#xA;        stream_url = await asyncio.to_thread(camera.get_stream()&#xA;        if stream_url:&#xA;            return stream_url&#xA;        else:&#xA;            logger.warning(f"Unable to get stream URL for {camera.name}. Stream might not be active.")&#xA;            return None&#xA;    except Exception as e:&#xA;        logger.error(f"Error getting stream URL for {camera.name}: {e}")&#xA;        return None&#xA;&#xA;async def handle_user_stream_active_event(camera):&#xA;    logger.info(f"User stream active event detected for camera: {camera.name}")&#xA;&#xA;    # Get the stream URL&#xA;    stream_url = await get_stream_url(camera)&#xA;    if stream_url:&#xA;        logger.info(f"Stream URL for {camera.name}: {stream_url}")&#xA;        await start_ffmpeg_stream(camera.name, stream_url)&#xA;    else:&#xA;        logger.warning(f"No stream URL available for {camera.name}")&#xA;&#xA;async def event_handler(device, attr, value):&#xA;    logger.debug(f"Event: {device.name}, Attribute: {attr}, Value: {value}")&#xA;    if attr == &#x27;activityState&#x27;:&#xA;        if value == &#x27;idle&#x27;:&#xA;            await handle_idle_event(device)&#xA;        elif value in [&#x27;userStreamActive&#x27;]:&#xA;            await handle_user_stream_active_event(device)&#xA;    elif attr == &#x27;mediaUploadNotification&#x27;:&#xA;        logger.info(f"Media uploaded for camera: {device.name}")&#xA;&#xA;def sync_event_handler(device, attr, value):&#xA;    # This function will be called by PyArlo&#x27;s synchronous callbacks&#xA;    event_queue.put((device, attr, value))&#xA;&#xA;async def process_event_queue():&#xA;    while not shutdown_event.is_set():&#xA;        try:&#xA;            if not event_queue.empty():&#xA;                device, attr, value = event_queue.get()&#xA;                await event_handler(device, attr, value)&#xA;            await asyncio.sleep(0.1)  # Small delay to prevent busy-waiting&#xA;        except asyncio.CancelledError:&#xA;            break&#xA;        except Exception as e:&#xA;            logger.error(f"Error processing event: {e}")&#xA;&#xA;async def display_status(arlo):&#xA;    while not shutdown_event.is_set():&#xA;        print("\n--- Camera Statuses ---")&#xA;        for camera in arlo.cameras:&#xA;            print(f"{camera.name}: {camera.state}")&#xA;        print("------------------------")&#xA;        await asyncio.sleep(5)&#xA;&#xA;async def start_ffmpeg_stream(camera_name, stream_url):&#xA;    if camera_name not in ffmpeg_processes:&#xA;        output_hls = f"/tmp/{camera_name}.m3u8"&#xA;&#xA;        try:&#xA;            new_url = urllib.parse.quote(stream_url.encode(), safe=&#x27;:/?&amp;=&#x27;)&#xA;            logger.info(f"NEW_URL: {new_url}")&#xA;&#xA;            ffmpeg_cmd = [&#xA;                "ffmpeg", "-hide_banner", "-loglevel", "quiet", "-nostats", "-nostdin", "-y", "-re",&#xA;                "-i", new_url,&#xA;                "-c:v", "libx264", "-preset", "veryfast",&#xA;                "-an", "-sn",&#xA;                "-f", "hls", "-hls_time", "4", "-hls_list_size", "10",&#xA;                "-hls_flags", "delete_segments", output_hls,&#xA;            ]&#xA;            logger.info(f"Starting FFmpeg command: {ffmpeg_cmd}")&#xA;            &#xA;            process = await asyncio.create_subprocess_exec(&#xA;                *ffmpeg_cmd,&#xA;                stdout=asyncio.subprocess.DEVNULL,&#xA;                stderr=asyncio.subprocess.DEVNULL&#xA;            )&#xA;            ffmpeg_processes[camera_name] = process&#xA;            logger.info(f"Started ffmpeg process with PID: {process.pid}")&#xA;&#xA;        except Exception as e:&#xA;            logger.error(f"Error starting FFmpeg for {camera_name}: {e}")&#xA;&#xA;async def stop_ffmpeg_stream(camera_name):&#xA;    logger.info(f"Stopping ffmpeg process for {camera_name}")&#xA;    ffmpeg_process = ffmpeg_processes.pop(camera_name, None)&#xA;    if ffmpeg_process:&#xA;        ffmpeg_process.terminate()&#xA;&#xA;        try:&#xA;            await ffmpeg_process.wait()&#xA;            logger.info(f"{camera_name} stopped successfully")&#xA;        except Exception as e:&#xA;            print(f"FFMPEG Process didn&#x27;t stop in time, forcefully terminating: {e}")&#xA;            ffmpeg_process.kill()&#xA;    else:&#xA;        logger.info(f"FFmpeg process for {camera_name} already stopped")&#xA;&#xA;async def shutdown(signal, loop):&#xA;    logger.info(f"Received exit signal {signal.name}...")&#xA;    shutdown_event.set()&#xA;    tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]&#xA;    [task.cancel() for task in tasks]&#xA;    logger.info(f"Cancelling {len(tasks)} outstanding tasks")&#xA;    await asyncio.gather(*tasks, return_exceptions=True)&#xA;    loop.stop()&#xA;&#xA;async def main():&#xA;    # Initialize PyArlo&#xA;    arlo_args = {&#xA;        &#x27;username&#x27;: ARLO_USER,&#xA;        &#x27;password&#x27;: ARLO_PASS,&#xA;        &#x27;tfa_source&#x27;: &#x27;imap&#x27;,&#xA;        &#x27;tfa_type&#x27;: &#x27;email&#x27;,&#xA;        &#x27;tfa_host&#x27;: IMAP_HOST,&#xA;        &#x27;tfa_username&#x27;: IMAP_USER,&#xA;        &#x27;tfa_password&#x27;: IMAP_PASS,&#xA;        &#x27;save_session&#x27;: True,&#xA;        &#x27;verbose_debug&#x27;: DEBUG&#xA;    }&#xA;&#xA;    # Add optional arguments&#xA;    for arg, value in [&#xA;        (&#x27;refresh_devices_every&#x27;, PYAARLO_REFRESH_DEVICES),&#xA;        (&#x27;stream_timeout&#x27;, PYAARLO_STREAM_TIMEOUT),&#xA;        (&#x27;backend&#x27;, PYAARLO_BACKEND),&#xA;        (&#x27;storage_dir&#x27;, PYAARLO_STORAGE_DIR),&#xA;        (&#x27;ecdh_curve&#x27;, PYAARLO_ECDH_CURVE)&#xA;    ]:&#xA;        if value:&#xA;            arlo_args[arg] = value&#xA;    &#xA;    try:&#xA;        arlo = await asyncio.to_thread(PyArlo, **arlo_args)&#xA;    except Exception as e:&#xA;        logger.error(f"Failed to initialize PyArlo: {e}")&#xA;        return&#xA;&#xA;    logger.info("Connected to Arlo. Monitoring events...")&#xA;&#xA;    # Register event handlers for each camera&#xA;    for camera in arlo.cameras:&#xA;        camera.add_attr_callback(&#x27;*&#x27;, sync_event_handler)&#xA;&#xA;    # Start the status display task&#xA;    status_task = asyncio.create_task(display_status(arlo))&#xA;&#xA;    # Start the event processing task&#xA;    event_processing_task = asyncio.create_task(process_event_queue())&#xA;&#xA;    # Set up signal handlers&#xA;    loop = asyncio.get_running_loop()&#xA;    for s in (signal.SIGHUP, signal.SIGTERM, signal.SIGINT):&#xA;        loop.add_signal_handler(&#xA;            s, lambda s=s: asyncio.create_task(shutdown(s, loop)))&#xA;&#xA;    try:&#xA;        # Keep the main coroutine running&#xA;        while not shutdown_event.is_set():&#xA;            try:&#xA;                await asyncio.sleep(1)&#xA;            except asyncio.CancelledError:&#xA;                break&#xA;    except Exception as e:&#xA;        logger.error(f"Unexpected error in main loop: {e}")&#xA;    finally:&#xA;        logger.info("Shutting down...")&#xA;        for camera_name in list(ffmpeg_processes.keys()):&#xA;            await stop_ffmpeg_stream(camera_name)&#xA;        &#xA;        # Cancel and wait for all tasks&#xA;        tasks = [status_task, event_processing_task]&#xA;        for task in tasks:&#xA;            if not task.done():&#xA;                task.cancel()&#xA;        await asyncio.gather(*tasks, return_exceptions=True)&#xA;        &#xA;        logger.info("Program terminated.")&#xA;&#xA;if __name__ == "__main__":&#xA;    try:&#xA;        asyncio.run(main())&#xA;    except KeyboardInterrupt:&#xA;        logger.info("Keyboard interrupt received. Exiting.")&#xA;    except Exception as e:&#xA;        logger.error(f"Unhandled exception: {e}")&#xA;    finally:&#xA;        logger.info("Program exit complete.")&#xA;

    &#xA;

    My issue is about the ffmpeg command which is hold the main process (or the event loop) when it runs, blocking the events coming from the pyaarlo library. The state of the camera continues to work with the good information.

    &#xA;

    I tried lot of things, without asyncio, with multiprocessing, with subprocess, ... the behavior is always the same. In some cases, I received the idle event after the key interrupt.

    &#xA;

    Another information :

    &#xA;

      &#xA;
    • When I stop the active stream, the event is not received but when I start the stream just after, that event is received.
    • &#xA;

    • When I run the same ffmpeg command but with a local long video file, everything is Ok. So, it why I guess that the ffmpeg command is impacting the main process.
    • &#xA;

    &#xA;

    I succedeed in running the ffmpeg command with rtsp url stream but without a loop event monitoring :

    &#xA;

    import asyncio&#xA;import signal&#xA;import sys&#xA;import os&#xA;&#xA;async def run_infinite_command():&#xA;    # Start a simple HTTP server as our "infinite" command&#xA;    url = "rstp://localhost:8554/camera1/stream" # it is a fake url&#xA;    ffmpeg_cmd = [&#xA;        "ffmpeg", "-re", "-i", url,&#xA;        "-c:v", "libx264", "-preset", "veryfast",&#xA;        "-c:a", "copy",&#xA;        "-f", "hls", "-hls_time", "4", "-hls_list_size", "10",&#xA;        "-hls_flags", "delete_segments", "/tmp/output.m3u8"&#xA;    ]&#xA;    &#xA;    process = await asyncio.create_subprocess_exec(&#xA;        *ffmpeg_cmd,&#xA;        stdout=asyncio.subprocess.DEVNULL,&#xA;        stderr=asyncio.subprocess.DEVNULL&#xA;    )&#xA;    &#xA;    print(f"Started HTTP server with PID: {process.pid}")&#xA;    return process&#xA;&#xA;async def main():&#xA;    # Start the infinite command&#xA;    process = await run_infinite_command()&#xA;&#xA;    # Run the main loop for a few seconds&#xA;    for i in range(10):&#xA;        print(f"Main loop iteration {i&#x2B;1}")&#xA;        await asyncio.sleep(1)&#xA;&#xA;    # Stop the infinite command&#xA;    print("Stopping the HTTP server...")&#xA;    if sys.platform == "win32":&#xA;        # On Windows, we need to use CTRL_C_EVENT&#xA;        os.kill(process.pid, signal.CTRL_C_EVENT)&#xA;    else:&#xA;        # On Unix-like systems, we can use SIGTERM&#xA;        process.send_signal(signal.SIGTERM)&#xA;&#xA;    # Wait for the process to finish&#xA;    try:&#xA;        await asyncio.wait_for(process.wait(), timeout=5.0)&#xA;        print("HTTP server stopped successfully")&#xA;    except asyncio.TimeoutError:&#xA;        print("HTTP server didn&#x27;t stop in time, forcefully terminating")&#xA;        process.kill()&#xA;&#xA;    print("Program finished")&#xA;&#xA;if __name__ == "__main__":&#xA;    asyncio.run(main())&#xA;

    &#xA;

    With this script, the ffmpeg command is correctly launched and terminated after the for loop.

    &#xA;

    Could you help ?

    &#xA;