recherche
Maisondéveloppement back-endTutoriel PythonDonnées vidéo IO via le sous-processus ffmpeg

Alors que je reprenais ma recherche d'emploi (oui, je suis toujours #OpenToWork, pingez-moi !), dans l'une des candidatures, on m'a demandé d'implémenter un prototype qui traite des données vidéo. Pendant que je travaillais sur le projet, j'ai reçu de manière inattendue beaucoup d'aide de la part des chatbots génératifs d'IA en raison de ma relative inexpérience dans le domaine.

Video data IO through ffmpeg subprocess

Comme mentionné dans le titre, ffmpeg a été utilisé pour effectuer certains travaux de prétraitement. L'un des objectifs du projet était de pouvoir lire plusieurs fichiers vidéo les uns après les autres. Bien qu'il existe plusieurs façons d'y parvenir, j'ai décidé d'opter pour la solution la plus évidente, en les concaténant ensemble.

$ cat video1 video2 video3 | python further-work.py

Pour y parvenir, j'ai d'abord dû réencoder les fichiers dans des formats qui le permettraient. Après avoir « discuté » avec Google Gemini à ce sujet, le chatbot m'a recommandé d'utiliser MPEG-TS à cet effet.

MPEG Transport Stream (MPEG-TS) fonctionne en encapsulant des flux élémentaires en paquets. Ces flux comprennent des données audio, vidéo et PSIP, qui sont mises en paquets en petits segments. Chaque flux est découpé en sections de 188 octets et entrelacé. Ce processus garantit moins de latence et une plus grande résilience aux erreurs, ce qui le rend idéal pour les vidéoconférences où les images volumineuses peuvent introduire un retard audio.

Cité de https://castr.com/blog/mpeg-transport-stream-mpeg-ts/

Il existe d'autres formats de fichiers qui pourraient être utilisés à cet effet, mais ils n'ont aucun rapport avec la discussion. Une fois la vidéo réencodée dans ce format, les données vidéo seront envoyées dans une file d'attente, pour être consommées par d'autres modules, exécutés dans d'autres processus.

Après avoir défini à la fois l'entrée (une liste de fichiers vidéo à récupérer en ligne) et la sortie (le contenu du fichier vidéo réencodé), il était temps de comprendre comment procéder. Malheureusement, ffmpeg est un utilitaire tellement compliqué qui fait tellement de choses. Il y a/y a eu plusieurs tentatives pour fournir une interface pour aider les utilisateurs (je voulais vraiment essayer ça, mais il est mort maintenant, apparemment). Cependant, compte tenu de l’utilité actuelle de l’IA générative, il suffit de quelques invites pour obtenir la bonne commande.

ffmpeg -hwaccel cuda -i pipe:0 -c:v h264_nvenc -b:v 1.5M -c:a aac -b:a 128k -f mpegts -y pipe:1

Il a même donné une explication sur la signification de chacun de ces arguments, comme le montre la capture d'écran ci-dessous.

Video data IO through ffmpeg subprocess
Tentative de Gemini d'expliquer la commande ffmpeg

En bref, la commande accepte le contenu du fichier vidéo via stdin et génère le contenu du fichier vidéo réencodé sous forme de sortie standard.

Il est maintenant temps de coder l'implémentation, car je voulais à la fois lire et écrire dans ffmpeg simultanément, ce sera donc une application asyncio. La bibliothèque client http que nous utilisons cette fois est httpx, qui dispose d'une méthode pour récupérer le téléchargement par lots plus petits :

$ cat video1 video2 video3 | python further-work.py

Nous nous soucierons du traitement réel plus tard, pour l'instant, nous obtiendrons simplement le code pour imprimer les morceaux à l'écran.

Ensuite, nous écrivons une fonction pour appeler ffmpeg, via asyncio.create_subprocess_exec

ffmpeg -hwaccel cuda -i pipe:0 -c:v h264_nvenc -b:v 1.5M -c:a aac -b:a 128k -f mpegts -y pipe:1

Idéalement, nous utiliserions ici process.communicate(file_content) comme conseillé dans la documentation, malheureusement si nous faisions cela, nous devrions d'abord télécharger l'intégralité du fichier, ce qui retarderait inévitablement la réponse, ce qui n'était pas idéal.

À la place, nous pourrions utiliser process.stdin.write(), mettons à jour la fonction write_input d'origine :

import httpx

client = httpx.AsyncClient()

async def write_input(
    client: httpx.AsyncClient, video_link: str, process: asyncio.subprocess.Process
) -> None:
    async with client.stream("GET", video_link) as response:
        async for chunk in response.aiter_raw(1024):
            print(chunk) # this is the downloaded video file, in chunks

Avec chaque morceau téléchargé,

  1. nous le transmettons au processus via process.stdin.write(chunk).
  2. Une fois cela fait, nous écrivions un EOF (process.stdin.write_eof()) pour désigner la fin de l'entrée du fichier,
  3. suivi d'un .close() (et de l'attente correspondante .wait_closed())

Retour à la fonction video_send, nous continuons la fonction en lisant process.stdout. Être capable de lire et d'écrire est exactement la raison pour laquelle nous faisons cela via asyncio. Auparavant, en mode synchrone, nous ne pouvions effectuer les opérations que les unes après les autres dans un ordre fixe, mais nous pouvions désormais laisser le planificateur se soucier de l'ordre. Maintenant, la fonction a ajouté le code suivant pour lire le contenu du fichier réencodé et le publier dans la file d'attente :

async def video_send(client: httpx.AsyncClient, video_link: str) -> None:
    logger.info("DATA: Fetching video from link", link=video_link)
    process = await asyncio.create_subprocess_exec(
        "ffmpeg",
        "-hwaccel",
        "cuda",
        "-i",
        "pipe:0",
        "-c:v",
        "h264_nvenc",
        # "libx264",
        "-b:v",
        "1.5M",
        "-c:a",
        "aac",
        "-b:a",
        "128k",
        "-f",
        "mpegts",
        "-y",
        "pipe:1",
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
    )

    asyncio.create_task(write_input(client, video_link, process))

En boucle, nous

  1. Récupérer un morceau de données depuis ffmpeg stdout
  2. Si chunk est une chaîne vide, quittez la boucle
  3. Sinon, placez le morceau dans la file d'attente (via asyncio.to_thread, car nous utilisons ici une version sécurisée pour les processus)
  4. Ensuite, nous attendons que la commande se termine gracieusement, via process.wait()

Cela semble très simple maintenant, mais il m'a fallu toute la nuit pour faire cela correctement (et j'étais encore en train de réviser le code en écrivant ceci). La moitié du temps, je vérifiais la documentation pour m'assurer de ne rien manquer, le reste du temps, je demandais à Gemini de réviser mon code.

J'espère que cela vous sera utile, et c'est tout pour aujourd'hui. J'espère que nous reviendrons la semaine prochaine au contenu de l'Avent of Code précédemment promis.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Approche hybride de Python: compilation et interprétation combinéesApproche hybride de Python: compilation et interprétation combinéesMay 08, 2025 am 12:16 AM

Pythonusesahybridapproach, combinantcompilationToByteDodeAnd Intrepretation.1) CodeSompiledToplatForment-indépendantBytecode.2) ByteCodeisInterpretedByThepyThonVirtualmachine, améliorant la performance et la portabilité.

Apprenez les différences entre les 'pour' de PythonApprenez les différences entre les 'pour' de PythonMay 08, 2025 am 12:11 AM

Thekeydifferencesbetweenpython "pour" et "tandis que" Loopsare: 1) "pour" LoopsareIdEalForitatriant sur les séquences ouvraires, tandis que 2) "tandis que" LoopsarebetterforcontinUnUntilaconditionMetStwithoutPredefinedIberations.un.un

Python concaténate répertorie avec des doublonsPython concaténate répertorie avec des doublonsMay 08, 2025 am 12:09 AM

Dans Python, vous pouvez connecter des listes et gérer des éléments en double via une variété de méthodes: 1) Utiliser les opérateurs ou prolonger () pour conserver tous les éléments en double; 2) Convertissez en ensembles puis revenez aux listes pour supprimer tous les éléments en double, mais l'ordre d'origine sera perdu; 3) Utilisez des boucles ou des compréhensions de liste pour combiner des ensembles pour supprimer les éléments en double et maintenir l'ordre d'origine.

Python Liste de la liste des performances de concaténation: comparaison de la vitessePython Liste de la liste des performances de concaténation: comparaison de la vitesseMay 08, 2025 am 12:09 AM

ThefastestmethodforlistCaténationInpyThonDePendSonListSize: 1) forsmalllists, the opératorisefficient.2) Forlargerlists, list.extend () orlistcomprehensionsisfaster, witextend () étant lamememory-efficientBymoditifyListListsin-Lace.

Comment insérer des éléments dans une liste de python?Comment insérer des éléments dans une liste de python?May 08, 2025 am 12:07 AM

ToinsertElementsIntoapyThonList, useAppend () toaddtotheend, insert () foraspecificPosition, andExtend () forulTipleElements.1) useAppend () foraddingsingleitemStotheend.2) useinsert () toaddataspecificIndex, wila'slowerLlowerLarleLis

Les listes Python sont-elles des tableaux dynamiques ou des listes liées sous le capot?Les listes Python sont-elles des tableaux dynamiques ou des listes liées sous le capot?May 07, 2025 am 12:16 AM

Pythonlistsareimpoledasdynamicarrays, notLinkedlists.1) ils sont les plus utiles.

Comment supprimer les éléments d'une liste Python?Comment supprimer les éléments d'une liste Python?May 07, 2025 am 12:15 AM

PythonoffersfourmainMethodstoreMoElelementsfromalist: 1) retirez (valeur) supprimer la perception de la réavance, 2) la pop (index) supprimera-theredraturnsanelementAsaspecifiedIndex, 3) DelstatementRemoveselementsbyIndexor

Que devez-vous vérifier si vous obtenez une erreur 'Autorisation refusée' lorsque vous essayez d'exécuter un script?Que devez-vous vérifier si vous obtenez une erreur 'Autorisation refusée' lorsque vous essayez d'exécuter un script?May 07, 2025 am 12:12 AM

Toresolvea "Permissiondened" Erreur lorsqu'il a fait la recherche de suivi de suivi: 1) CheckAndAdAdAstheScript'sperMissionsusingChmod xmyscript.shtomakeitexecuable.2) s'assureraScriptisloatedInaDirectorywherewheyouHavewritePerMissions, telasyourhomedirectory.

See all articles

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Outils chauds

MantisBT

MantisBT

Mantis est un outil Web de suivi des défauts facile à déployer, conçu pour faciliter le suivi des défauts des produits. Cela nécessite PHP, MySQL et un serveur Web. Découvrez nos services de démonstration et d'hébergement.

MinGW - GNU minimaliste pour Windows

MinGW - GNU minimaliste pour Windows

Ce projet est en cours de migration vers osdn.net/projects/mingw, vous pouvez continuer à nous suivre là-bas. MinGW : un port Windows natif de GNU Compiler Collection (GCC), des bibliothèques d'importation et des fichiers d'en-tête librement distribuables pour la création d'applications Windows natives ; inclut des extensions du runtime MSVC pour prendre en charge la fonctionnalité C99. Tous les logiciels MinGW peuvent fonctionner sur les plates-formes Windows 64 bits.

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Dreamweaver Mac

Dreamweaver Mac

Outils de développement Web visuel

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP