Recherche avancée

Médias (2)

Mot : - Tags -/media

Autres articles (58)

  • Gestion générale des documents

    13 mai 2011, par

    MédiaSPIP ne modifie jamais le document original mis en ligne.
    Pour chaque document mis en ligne il effectue deux opérations successives : la création d’une version supplémentaire qui peut être facilement consultée en ligne tout en laissant l’original téléchargeable dans le cas où le document original ne peut être lu dans un navigateur Internet ; la récupération des métadonnées du document original pour illustrer textuellement le fichier ;
    Les tableaux ci-dessous expliquent ce que peut faire MédiaSPIP (...)

  • List of compatible distributions

    26 avril 2011, par

    The table below is the list of Linux distributions compatible with the automated installation script of MediaSPIP. Distribution nameVersion nameVersion number Debian Squeeze 6.x.x Debian Weezy 7.x.x Debian Jessie 8.x.x Ubuntu The Precise Pangolin 12.04 LTS Ubuntu The Trusty Tahr 14.04
    If you want to help us improve this list, you can provide us access to a machine whose distribution is not mentioned above or send the necessary fixes to add (...)

  • Des sites réalisés avec MediaSPIP

    2 mai 2011, par

    Cette page présente quelques-uns des sites fonctionnant sous MediaSPIP.
    Vous pouvez bien entendu ajouter le votre grâce au formulaire en bas de page.

Sur d’autres sites (6569)

  • Introducing Matomo SEO Web Vitals

    13 septembre 2021, par Ben Erskine — About, Analytics Tips, Plugins

    SEO Web Vitals track your critical website performance metrics and are a core element of SEO best practice. 

    Start using Matomo SEO Web Vitals to monitor your website performance, optimise your visitor experience, improve your search result rankings, and see how your site compares to your competitors.

    SEO Web Vitals

    What are SEO Web Vitals ?

    Web Vitals are made up of a number of important metrics, such as your website’s page speed and loading performance, these metrics all play an important role in search engine optimisation. 

    The more technical terms for these metrics are Page Speed Score, First Contentful Paint (FCP), Final Input Delay (FID), Last Contentful Paint (LCP) and Cumulative Layout Shift (CLS).

    Why should you use SEO Web Vitals ?

    SEO Web Vitals are being used more and more by search engines such as Google to rank websites so they help ensure a great page experience for users who arrive via links from their search results. 

    By monitoring your SEO Web Vitals you can see how good or bad a single page performs and then prioritise the optimisation of strategically important pages to help improve the ranking position within search engine results.

    For ease of use you can receive regular reports in your email inbox and you can configure custom alerts to automatically notify you when a page score changes significantly. This saves time by not having to check page performance scores manually while ensuring you will be notified should there be any important change that needs to be actioned.

    You should use SEO Web Vitals to understand how your site performance is impacting your overall visitor experience.

    Four key benefits of using SEO Web Vitals :

    Improve your search result rankings

    • SEO Web Vitals are a core element of SEO best practice and directly impact your search rankings.
    • Pages that load quickly and are more stable deliver a better user experience, so they’re ranked higher by search engines.

    Optimise your website visitor experience

    • Know how quickly pages on your website load to ensure you deliver an optimal visitor experience.
    • Identify page stability issues and implement the changes needed to enhance your visitor experience.

    Automate your website performance monitoring

    • Have peace of mind knowing if your metrics decrease, you can find and fix the root cause quickly.
    • Configure performance alerts and get automated reports sent to you.

    Incorporate website performance into your competitor analysis

    • These performance metrics are essentially open for anyone to inspect, so you can measure and benchmark your site against competitors. 

    How can I improve my SEO Web Vitals ?

    There are so many ways to improve these performance metrics, here are five of the common contributing factors.

    1. Your page speed score is a weighted average of your other performance metrics, so focus on improving the underlying metrics that contribute to this score.
    2. Ensure you use a high quality web host with an appropriate plan for your level of traffic to help improve your FCP time.
    3. Try removing large elements that aren’t required on your page to improve your LCP time.
    4. Optimise against Total Blocking Time to Improve your FID score.
    5. Consider using a Layout Shift Debugger to improve Your CLS Score

    Guide to Matomo SEO Web Vitals

    For more information and to learn how to configure SEO Web Vitals in Matomo, check out our full guide to SEO Web Vitals.

    You will learn :

    Need more resources ?

    Matomo Plugin SEO Web Vitals

    Matomo SEO Web Vitals FAQs

  • 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.
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.

    


    Here the python code :

    


    import asyncio
from decouple import config
import logging
from my_pyaarlo import PyArlo
import urllib.parse
from queue import Queue
import signal

# Read config from ENV (unchanged)
ARLO_USER = config('ARLO_USER')
ARLO_PASS = config('ARLO_PASS')
IMAP_HOST = config('IMAP_HOST')
IMAP_USER = config('IMAP_USER')
IMAP_PASS = config('IMAP_PASS')
DEBUG = config('DEBUG', default=False, cast=bool)
PYAARLO_BACKEND = config('PYAARLO_BACKEND', default=None)
PYAARLO_REFRESH_DEVICES = config('PYAARLO_REFRESH_DEVICES', default=0, cast=int)
PYAARLO_STREAM_TIMEOUT = config('PYAARLO_STREAM_TIMEOUT', default=0, cast=int)
PYAARLO_STORAGE_DIR = config('PYAARLO_STORAGE_DIR', default=None)
PYAARLO_ECDH_CURVE = config('PYAARLO_ECDH_CURVE', default=None)

# Initialize logging
logging.basicConfig(
    level=logging.DEBUG if DEBUG else logging.INFO,
    format='%(asctime)s [%(levelname)s] %(name)s: %(message)s'
)
logger = logging.getLogger(__name__)

ffmpeg_processes = {}
event_queue = Queue()
shutdown_event = asyncio.Event()

async def handle_idle_event(camera):
    logger.info(f"Idle event detected for camera: {camera.name}")
    await stop_ffmpeg_stream(camera.name)

async def get_stream_url(camera):
    try:
        # Attempt to get the stream URL
        stream_url = await asyncio.to_thread(camera.get_stream()
        if stream_url:
            return stream_url
        else:
            logger.warning(f"Unable to get stream URL for {camera.name}. Stream might not be active.")
            return None
    except Exception as e:
        logger.error(f"Error getting stream URL for {camera.name}: {e}")
        return None

async def handle_user_stream_active_event(camera):
    logger.info(f"User stream active event detected for camera: {camera.name}")

    # Get the stream URL
    stream_url = await get_stream_url(camera)
    if stream_url:
        logger.info(f"Stream URL for {camera.name}: {stream_url}")
        await start_ffmpeg_stream(camera.name, stream_url)
    else:
        logger.warning(f"No stream URL available for {camera.name}")

async def event_handler(device, attr, value):
    logger.debug(f"Event: {device.name}, Attribute: {attr}, Value: {value}")
    if attr == 'activityState':
        if value == 'idle':
            await handle_idle_event(device)
        elif value in ['userStreamActive']:
            await handle_user_stream_active_event(device)
    elif attr == 'mediaUploadNotification':
        logger.info(f"Media uploaded for camera: {device.name}")

def sync_event_handler(device, attr, value):
    # This function will be called by PyArlo's synchronous callbacks
    event_queue.put((device, attr, value))

async def process_event_queue():
    while not shutdown_event.is_set():
        try:
            if not event_queue.empty():
                device, attr, value = event_queue.get()
                await event_handler(device, attr, value)
            await asyncio.sleep(0.1)  # Small delay to prevent busy-waiting
        except asyncio.CancelledError:
            break
        except Exception as e:
            logger.error(f"Error processing event: {e}")

async def display_status(arlo):
    while not shutdown_event.is_set():
        print("\n--- Camera Statuses ---")
        for camera in arlo.cameras:
            print(f"{camera.name}: {camera.state}")
        print("------------------------")
        await asyncio.sleep(5)

async def start_ffmpeg_stream(camera_name, stream_url):
    if camera_name not in ffmpeg_processes:
        output_hls = f"/tmp/{camera_name}.m3u8"

        try:
            new_url = urllib.parse.quote(stream_url.encode(), safe=':/?&=')
            logger.info(f"NEW_URL: {new_url}")

            ffmpeg_cmd = [
                "ffmpeg", "-hide_banner", "-loglevel", "quiet", "-nostats", "-nostdin", "-y", "-re",
                "-i", new_url,
                "-c:v", "libx264", "-preset", "veryfast",
                "-an", "-sn",
                "-f", "hls", "-hls_time", "4", "-hls_list_size", "10",
                "-hls_flags", "delete_segments", output_hls,
            ]
            logger.info(f"Starting FFmpeg command: {ffmpeg_cmd}")
            
            process = await asyncio.create_subprocess_exec(
                *ffmpeg_cmd,
                stdout=asyncio.subprocess.DEVNULL,
                stderr=asyncio.subprocess.DEVNULL
            )
            ffmpeg_processes[camera_name] = process
            logger.info(f"Started ffmpeg process with PID: {process.pid}")

        except Exception as e:
            logger.error(f"Error starting FFmpeg for {camera_name}: {e}")

async def stop_ffmpeg_stream(camera_name):
    logger.info(f"Stopping ffmpeg process for {camera_name}")
    ffmpeg_process = ffmpeg_processes.pop(camera_name, None)
    if ffmpeg_process:
        ffmpeg_process.terminate()

        try:
            await ffmpeg_process.wait()
            logger.info(f"{camera_name} stopped successfully")
        except Exception as e:
            print(f"FFMPEG Process didn't stop in time, forcefully terminating: {e}")
            ffmpeg_process.kill()
    else:
        logger.info(f"FFmpeg process for {camera_name} already stopped")

async def shutdown(signal, loop):
    logger.info(f"Received exit signal {signal.name}...")
    shutdown_event.set()
    tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
    [task.cancel() for task in tasks]
    logger.info(f"Cancelling {len(tasks)} outstanding tasks")
    await asyncio.gather(*tasks, return_exceptions=True)
    loop.stop()

async def main():
    # Initialize PyArlo
    arlo_args = {
        'username': ARLO_USER,
        'password': ARLO_PASS,
        'tfa_source': 'imap',
        'tfa_type': 'email',
        'tfa_host': IMAP_HOST,
        'tfa_username': IMAP_USER,
        'tfa_password': IMAP_PASS,
        'save_session': True,
        'verbose_debug': DEBUG
    }

    # Add optional arguments
    for arg, value in [
        ('refresh_devices_every', PYAARLO_REFRESH_DEVICES),
        ('stream_timeout', PYAARLO_STREAM_TIMEOUT),
        ('backend', PYAARLO_BACKEND),
        ('storage_dir', PYAARLO_STORAGE_DIR),
        ('ecdh_curve', PYAARLO_ECDH_CURVE)
    ]:
        if value:
            arlo_args[arg] = value
    
    try:
        arlo = await asyncio.to_thread(PyArlo, **arlo_args)
    except Exception as e:
        logger.error(f"Failed to initialize PyArlo: {e}")
        return

    logger.info("Connected to Arlo. Monitoring events...")

    # Register event handlers for each camera
    for camera in arlo.cameras:
        camera.add_attr_callback('*', sync_event_handler)

    # Start the status display task
    status_task = asyncio.create_task(display_status(arlo))

    # Start the event processing task
    event_processing_task = asyncio.create_task(process_event_queue())

    # Set up signal handlers
    loop = asyncio.get_running_loop()
    for s in (signal.SIGHUP, signal.SIGTERM, signal.SIGINT):
        loop.add_signal_handler(
            s, lambda s=s: asyncio.create_task(shutdown(s, loop)))

    try:
        # Keep the main coroutine running
        while not shutdown_event.is_set():
            try:
                await asyncio.sleep(1)
            except asyncio.CancelledError:
                break
    except Exception as e:
        logger.error(f"Unexpected error in main loop: {e}")
    finally:
        logger.info("Shutting down...")
        for camera_name in list(ffmpeg_processes.keys()):
            await stop_ffmpeg_stream(camera_name)
        
        # Cancel and wait for all tasks
        tasks = [status_task, event_processing_task]
        for task in tasks:
            if not task.done():
                task.cancel()
        await asyncio.gather(*tasks, return_exceptions=True)
        
        logger.info("Program terminated.")

if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        logger.info("Keyboard interrupt received. Exiting.")
    except Exception as e:
        logger.error(f"Unhandled exception: {e}")
    finally:
        logger.info("Program exit complete.")


    


    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.

    


    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.

    


    Another information :

    


      

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


    • 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.
    • 


    


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

    


    import asyncio
import signal
import sys
import os

async def run_infinite_command():
    # Start a simple HTTP server as our "infinite" command
    url = "rstp://localhost:8554/camera1/stream" # it is a fake url
    ffmpeg_cmd = [
        "ffmpeg", "-re", "-i", url,
        "-c:v", "libx264", "-preset", "veryfast",
        "-c:a", "copy",
        "-f", "hls", "-hls_time", "4", "-hls_list_size", "10",
        "-hls_flags", "delete_segments", "/tmp/output.m3u8"
    ]
    
    process = await asyncio.create_subprocess_exec(
        *ffmpeg_cmd,
        stdout=asyncio.subprocess.DEVNULL,
        stderr=asyncio.subprocess.DEVNULL
    )
    
    print(f"Started HTTP server with PID: {process.pid}")
    return process

async def main():
    # Start the infinite command
    process = await run_infinite_command()

    # Run the main loop for a few seconds
    for i in range(10):
        print(f"Main loop iteration {i+1}")
        await asyncio.sleep(1)

    # Stop the infinite command
    print("Stopping the HTTP server...")
    if sys.platform == "win32":
        # On Windows, we need to use CTRL_C_EVENT
        os.kill(process.pid, signal.CTRL_C_EVENT)
    else:
        # On Unix-like systems, we can use SIGTERM
        process.send_signal(signal.SIGTERM)

    # Wait for the process to finish
    try:
        await asyncio.wait_for(process.wait(), timeout=5.0)
        print("HTTP server stopped successfully")
    except asyncio.TimeoutError:
        print("HTTP server didn't stop in time, forcefully terminating")
        process.kill()

    print("Program finished")

if __name__ == "__main__":
    asyncio.run(main())


    


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

    


    Could you help ?

    


  • [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.
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.

    


    Here the python code :

    


    import asyncio
from decouple import config
import logging
from my_pyaarlo import PyArlo
import urllib.parse
from queue import Queue
import signal

# Read config from ENV (unchanged)
ARLO_USER = config('ARLO_USER')
ARLO_PASS = config('ARLO_PASS')
IMAP_HOST = config('IMAP_HOST')
IMAP_USER = config('IMAP_USER')
IMAP_PASS = config('IMAP_PASS')
DEBUG = config('DEBUG', default=False, cast=bool)
PYAARLO_BACKEND = config('PYAARLO_BACKEND', default=None)
PYAARLO_REFRESH_DEVICES = config('PYAARLO_REFRESH_DEVICES', default=0, cast=int)
PYAARLO_STREAM_TIMEOUT = config('PYAARLO_STREAM_TIMEOUT', default=0, cast=int)
PYAARLO_STORAGE_DIR = config('PYAARLO_STORAGE_DIR', default=None)
PYAARLO_ECDH_CURVE = config('PYAARLO_ECDH_CURVE', default=None)

# Initialize logging
logging.basicConfig(
    level=logging.DEBUG if DEBUG else logging.INFO,
    format='%(asctime)s [%(levelname)s] %(name)s: %(message)s'
)
logger = logging.getLogger(__name__)

ffmpeg_processes = {}
event_queue = Queue()
shutdown_event = asyncio.Event()

async def handle_idle_event(camera):
    logger.info(f"Idle event detected for camera: {camera.name}")
    await stop_ffmpeg_stream(camera.name)

async def get_stream_url(camera):
    try:
        # Attempt to get the stream URL
        stream_url = await asyncio.to_thread(camera.get_stream()
        if stream_url:
            return stream_url
        else:
            logger.warning(f"Unable to get stream URL for {camera.name}. Stream might not be active.")
            return None
    except Exception as e:
        logger.error(f"Error getting stream URL for {camera.name}: {e}")
        return None

async def handle_user_stream_active_event(camera):
    logger.info(f"User stream active event detected for camera: {camera.name}")

    # Get the stream URL
    stream_url = await get_stream_url(camera)
    if stream_url:
        logger.info(f"Stream URL for {camera.name}: {stream_url}")
        await start_ffmpeg_stream(camera.name, stream_url)
    else:
        logger.warning(f"No stream URL available for {camera.name}")

async def event_handler(device, attr, value):
    logger.debug(f"Event: {device.name}, Attribute: {attr}, Value: {value}")
    if attr == 'activityState':
        if value == 'idle':
            await handle_idle_event(device)
        elif value in ['userStreamActive']:
            await handle_user_stream_active_event(device)
    elif attr == 'mediaUploadNotification':
        logger.info(f"Media uploaded for camera: {device.name}")

def sync_event_handler(device, attr, value):
    # This function will be called by PyArlo's synchronous callbacks
    event_queue.put((device, attr, value))

async def process_event_queue():
    while not shutdown_event.is_set():
        try:
            if not event_queue.empty():
                device, attr, value = event_queue.get()
                await event_handler(device, attr, value)
            await asyncio.sleep(0.1)  # Small delay to prevent busy-waiting
        except asyncio.CancelledError:
            break
        except Exception as e:
            logger.error(f"Error processing event: {e}")

async def display_status(arlo):
    while not shutdown_event.is_set():
        print("\n--- Camera Statuses ---")
        for camera in arlo.cameras:
            print(f"{camera.name}: {camera.state}")
        print("------------------------")
        await asyncio.sleep(5)

async def start_ffmpeg_stream(camera_name, stream_url):
    if camera_name not in ffmpeg_processes:
        output_hls = f"/tmp/{camera_name}.m3u8"

        try:
            new_url = urllib.parse.quote(stream_url.encode(), safe=':/?&=')
            logger.info(f"NEW_URL: {new_url}")

            ffmpeg_cmd = [
                "ffmpeg", "-hide_banner", "-loglevel", "quiet", "-nostats", "-nostdin", "-y", "-re",
                "-i", new_url,
                "-c:v", "libx264", "-preset", "veryfast",
                "-an", "-sn",
                "-f", "hls", "-hls_time", "4", "-hls_list_size", "10",
                "-hls_flags", "delete_segments", output_hls,
            ]
            logger.info(f"Starting FFmpeg command: {ffmpeg_cmd}")
            
            process = await asyncio.create_subprocess_exec(
                *ffmpeg_cmd,
                stdout=asyncio.subprocess.DEVNULL,
                stderr=asyncio.subprocess.DEVNULL
            )
            ffmpeg_processes[camera_name] = process
            logger.info(f"Started ffmpeg process with PID: {process.pid}")

        except Exception as e:
            logger.error(f"Error starting FFmpeg for {camera_name}: {e}")

async def stop_ffmpeg_stream(camera_name):
    logger.info(f"Stopping ffmpeg process for {camera_name}")
    ffmpeg_process = ffmpeg_processes.pop(camera_name, None)
    if ffmpeg_process:
        ffmpeg_process.terminate()

        try:
            await ffmpeg_process.wait()
            logger.info(f"{camera_name} stopped successfully")
        except Exception as e:
            print(f"FFMPEG Process didn't stop in time, forcefully terminating: {e}")
            ffmpeg_process.kill()
    else:
        logger.info(f"FFmpeg process for {camera_name} already stopped")

async def shutdown(signal, loop):
    logger.info(f"Received exit signal {signal.name}...")
    shutdown_event.set()
    tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
    [task.cancel() for task in tasks]
    logger.info(f"Cancelling {len(tasks)} outstanding tasks")
    await asyncio.gather(*tasks, return_exceptions=True)
    loop.stop()

async def main():
    # Initialize PyArlo
    arlo_args = {
        'username': ARLO_USER,
        'password': ARLO_PASS,
        'tfa_source': 'imap',
        'tfa_type': 'email',
        'tfa_host': IMAP_HOST,
        'tfa_username': IMAP_USER,
        'tfa_password': IMAP_PASS,
        'save_session': True,
        'verbose_debug': DEBUG
    }

    # Add optional arguments
    for arg, value in [
        ('refresh_devices_every', PYAARLO_REFRESH_DEVICES),
        ('stream_timeout', PYAARLO_STREAM_TIMEOUT),
        ('backend', PYAARLO_BACKEND),
        ('storage_dir', PYAARLO_STORAGE_DIR),
        ('ecdh_curve', PYAARLO_ECDH_CURVE)
    ]:
        if value:
            arlo_args[arg] = value
    
    try:
        arlo = await asyncio.to_thread(PyArlo, **arlo_args)
    except Exception as e:
        logger.error(f"Failed to initialize PyArlo: {e}")
        return

    logger.info("Connected to Arlo. Monitoring events...")

    # Register event handlers for each camera
    for camera in arlo.cameras:
        camera.add_attr_callback('*', sync_event_handler)

    # Start the status display task
    status_task = asyncio.create_task(display_status(arlo))

    # Start the event processing task
    event_processing_task = asyncio.create_task(process_event_queue())

    # Set up signal handlers
    loop = asyncio.get_running_loop()
    for s in (signal.SIGHUP, signal.SIGTERM, signal.SIGINT):
        loop.add_signal_handler(
            s, lambda s=s: asyncio.create_task(shutdown(s, loop)))

    try:
        # Keep the main coroutine running
        while not shutdown_event.is_set():
            try:
                await asyncio.sleep(1)
            except asyncio.CancelledError:
                break
    except Exception as e:
        logger.error(f"Unexpected error in main loop: {e}")
    finally:
        logger.info("Shutting down...")
        for camera_name in list(ffmpeg_processes.keys()):
            await stop_ffmpeg_stream(camera_name)
        
        # Cancel and wait for all tasks
        tasks = [status_task, event_processing_task]
        for task in tasks:
            if not task.done():
                task.cancel()
        await asyncio.gather(*tasks, return_exceptions=True)
        
        logger.info("Program terminated.")

if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        logger.info("Keyboard interrupt received. Exiting.")
    except Exception as e:
        logger.error(f"Unhandled exception: {e}")
    finally:
        logger.info("Program exit complete.")


    


    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.

    


    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.

    


    Another information :

    


      

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


    • 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.
    • 


    


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

    


    import asyncio
import signal
import sys
import os

async def run_infinite_command():
    # Start a simple HTTP server as our "infinite" command
    url = "rstp://localhost:8554/camera1/stream" # it is a fake url
    ffmpeg_cmd = [
        "ffmpeg", "-re", "-i", url,
        "-c:v", "libx264", "-preset", "veryfast",
        "-c:a", "copy",
        "-f", "hls", "-hls_time", "4", "-hls_list_size", "10",
        "-hls_flags", "delete_segments", "/tmp/output.m3u8"
    ]
    
    process = await asyncio.create_subprocess_exec(
        *ffmpeg_cmd,
        stdout=asyncio.subprocess.DEVNULL,
        stderr=asyncio.subprocess.DEVNULL
    )
    
    print(f"Started HTTP server with PID: {process.pid}")
    return process

async def main():
    # Start the infinite command
    process = await run_infinite_command()

    # Run the main loop for a few seconds
    for i in range(10):
        print(f"Main loop iteration {i+1}")
        await asyncio.sleep(1)

    # Stop the infinite command
    print("Stopping the HTTP server...")
    if sys.platform == "win32":
        # On Windows, we need to use CTRL_C_EVENT
        os.kill(process.pid, signal.CTRL_C_EVENT)
    else:
        # On Unix-like systems, we can use SIGTERM
        process.send_signal(signal.SIGTERM)

    # Wait for the process to finish
    try:
        await asyncio.wait_for(process.wait(), timeout=5.0)
        print("HTTP server stopped successfully")
    except asyncio.TimeoutError:
        print("HTTP server didn't stop in time, forcefully terminating")
        process.kill()

    print("Program finished")

if __name__ == "__main__":
    asyncio.run(main())


    


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

    


    Could you help ?