FFmpeg: Comment diviser efficacement une vidéo?


103

Je souhaite diviser une grande vidéo avi en deux vidéos consécutives plus petites. J'utilise ffmpeg.

Une façon consiste à exécuter ffmpeg deux fois:

ffmpeg -i input.avi -vcodec copy -acodec copy -ss 00:00:00 -t 00:30:00 output1.avi
ffmpeg -i input.avi -vcodec copy -acodec copy -ss 00:30:00 -t 00:30:00 output2.avi

Mais selon la page de manuel de ffmpeg, je peux créer plus d'un fichier de sortie à partir d'un fichier d'entrée en utilisant une seule ligne:

ffmpeg -i input.avi -vcodec copy -acodec copy -ss 00:00:00 -t 00:30:00 output1.avi \
   -vcodec copy -acodec copy -ss 00:30:00 -t 00:30:00 output2.avi

Ma question est la suivante: la dernière approche économise-t-elle du temps de calcul et de la mémoire?


3
lors de l'utilisation de "-vcodec copy -acodec copy" c'est très rapide :))
Savas Adar

@Antony, pourquoi ne pas chronométrer les deux versions (et regarder le moniteur de mémoire tel que htop), et nous dire quelle est la réponse?
AlcubierreDrive

Le premier exemple le fait de manière séquentielle, tandis que le deuxième exemple utilise des threads. Les deux feront la même chose, aucune accélération notable ne devrait se produire. Mais pour simplifier les choses, vous pouvez utiliser le segmenteur de flux ffmpeg muxer: ffmpeg.org
Mladen B.

1
Cet exemple semble vraiment faux! La documentation ffmpeg dit à propos de l'option -ss: "Lorsqu'elle est utilisée comme option d'entrée (avant -i), recherche dans ce fichier d'entrée pour la positionner. Lorsqu'elle est utilisée comme option de sortie (avant un nom de fichier de sortie), décode mais rejette l'entrée jusqu'à ce que les horodatages atteignent la position. " Vous l'utilisez dans la position de sortie, donc votre deuxième ligne gaspille l'effort de décodage et de rejet des 30 premières minutes.
Lucian Wischik

1
@LucianWischik, mais l'utilisation -sscomme option d'entrée dans la deuxième division peut ne pas être précise, vous pourriez donc ne pas obtenir une division nette. OMI l'exemple par OP est plus correct.
jiggunjer

Réponses:


82

Le wiki ffmpeg renvoie à cette page en référence à "Comment diviser une vidéo efficacement". Je ne suis pas convaincu que cette page répond à cette question, alors j'ai fait ce que @AlcubierreDrive a suggéré…

echo "Two commands" 
time ffmpeg -v quiet -y -i input.ts -vcodec copy -acodec copy -ss 00:00:00 -t 00:30:00 -sn test1.mkv
time ffmpeg -v quiet -y -i input.ts -vcodec copy -acodec copy -ss 00:30:00 -t 01:00:00 -sn test2.mkv
echo "One command" 
time ffmpeg -v quiet -y -i input.ts -vcodec copy -acodec copy -ss 00:00:00 -t 00:30:00 \
  -sn test3.mkv -vcodec copy -acodec copy -ss 00:30:00 -t 01:00:00 -sn test4.mkv

Quelles sorties ...

Two commands
real    0m16.201s
user    0m1.830s
sys 0m1.301s

real    0m43.621s
user    0m4.943s
sys 0m2.908s

One command
real    0m59.410s
user    0m5.577s
sys 0m3.939s

J'ai testé un fichier SD & HD, après quelques essais et un peu de maths.

Two commands SD 0m53.94 #2 wins  
One command  SD 0m49.63  

Two commands SD 0m55.00  
One command  SD 0m52.26 #1 wins 

Two commands SD 0m58.60 #2 wins  
One command  SD 0m58.61 

Two commands SD 0m54.60  
One command  SD 0m50.51 #1 wins 

Two commands SD 0m53.94  
One command  SD 0m49.63 #1 wins  

Two commands SD 0m55.00  
One command  SD 0m52.26 #1 wins 

Two commands SD 0m58.71  
One command  SD 0m58.61 #1 wins

Two commands SD 0m54.63  
One command  SD 0m50.51 #1 wins  

Two commands SD 1m6.67s #2 wins  
One command  SD 1m20.18  

Two commands SD 1m7.67  
One command  SD 1m6.72 #1 wins

Two commands SD 1m4.92  
One command  SD 1m2.24 #1 wins

Two commands SD 1m1.73  
One command  SD 0m59.72 #1 wins

Two commands HD 4m23.20  
One command  HD 3m40.02 #1 wins

Two commands SD 1m1.30  
One command  SD 0m59.59 #1 wins  

Two commands HD 3m47.89  
One command  HD 3m29.59 #1 wins  

Two commands SD 0m59.82  
One command  SD 0m59.41 #1 wins  

Two commands HD 3m51.18  
One command  HD 3m30.79 #1 wins  

Fichier SD = 1,35 Go de flux de transport DVB
Fichier HD = 3,14 Go de flux de transport DVB

Conclusion

La commande unique est meilleure si vous manipulez HD, elle est d'accord avec les commentaires du manuel sur l'utilisation de -ss après le fichier d'entrée pour faire une «recherche lente». Les fichiers SD ont une différence négligeable.

La version à deux commandes devrait être plus rapide en ajoutant un autre -ss avant le fichier d'entrée pour une «recherche rapide» suivie d'une recherche lente plus précise.


Si TS contient plusieurs programmes (programmes télévisés capturés par DVB-T), comment les diviser? Par exemple, j'ai un fichier TS qui contient football + cuisine + dessin animé. Comment puis-je diviser ce fichier TS en 3 fichiers mpg?
Dr.jacky

J'ai utilisé votre réponse dans ma question ici ( stackoverflow.com/questions/41983940/… ) mais cela n'a pas fonctionné, que pensez-vous que je fais de mal?
utdev

1
Le fichier de résultat était sans vidéo (seulement audio) dans mon cas. Après quelques expériences, j'ai trouvé la soultion. Il doit spécifier la clé pour "ne pas modifier la qualité" comme ceci -q:v 0.
oklas

19

Voici un script utile, il vous aide à fractionner automatiquement: Un script pour fractionner des vidéos à l'aide de ffmpeg

#!/bin/bash
 
# Written by Alexis Bezverkhyy <alexis@grapsus.net> in 2011
# This is free and unencumbered software released into the public domain.
# For more information, please refer to <http://unlicense.org/>
 
function usage {
        echo "Usage : ffsplit.sh input.file chunk-duration [output-filename-format]"
        echo -e "\t - input file may be any kind of file reconginzed by ffmpeg"
        echo -e "\t - chunk duration must be in seconds"
        echo -e "\t - output filename format must be printf-like, for example myvideo-part-%04d.avi"
        echo -e "\t - if no output filename format is given, it will be computed\
 automatically from input filename"
}
 
IN_FILE="$1"
OUT_FILE_FORMAT="$3"
typeset -i CHUNK_LEN
CHUNK_LEN="$2"
 
DURATION_HMS=$(ffmpeg -i "$IN_FILE" 2>&1 | grep Duration | cut -f 4 -d ' ')
DURATION_H=$(echo "$DURATION_HMS" | cut -d ':' -f 1)
DURATION_M=$(echo "$DURATION_HMS" | cut -d ':' -f 2)
DURATION_S=$(echo "$DURATION_HMS" | cut -d ':' -f 3 | cut -d '.' -f 1)
let "DURATION = ( DURATION_H * 60 + DURATION_M ) * 60 + DURATION_S"
 
if [ "$DURATION" = '0' ] ; then
        echo "Invalid input video"
        usage
        exit 1
fi
 
if [ "$CHUNK_LEN" = "0" ] ; then
        echo "Invalid chunk size"
        usage
        exit 2
fi
 
if [ -z "$OUT_FILE_FORMAT" ] ; then
        FILE_EXT=$(echo "$IN_FILE" | sed 's/^.*\.\([a-zA-Z0-9]\+\)$/\1/')
        FILE_NAME=$(echo "$IN_FILE" | sed 's/^\(.*\)\.[a-zA-Z0-9]\+$/\1/')
        OUT_FILE_FORMAT="${FILE_NAME}-%03d.${FILE_EXT}"
        echo "Using default output file format : $OUT_FILE_FORMAT"
fi
 
N='1'
OFFSET='0'
let 'N_FILES = DURATION / CHUNK_LEN + 1'
 
while [ "$OFFSET" -lt "$DURATION" ] ; do
        OUT_FILE=$(printf "$OUT_FILE_FORMAT" "$N")
        echo "writing $OUT_FILE ($N/$N_FILES)..."
        ffmpeg -i "$IN_FILE" -vcodec copy -acodec copy -ss "$OFFSET" -t "$CHUNK_LEN" "$OUT_FILE"
        let "N = N + 1"
        let "OFFSET = OFFSET + CHUNK_LEN"
done

2
Même commentaire pour vous que pour SEARAS. L'écriture de fichiers batch est utile en cas de nécessité absolue et lorsque vous n'avez pas d'autre option disponible, car elle n'est pas portable. Vous ne pourrez pas exécuter le même script sous Windows, par exemple. Lorsqu'il existe des moyens plus génériques / portables, les scripts batch doivent être évités, pour gagner du temps pour les porter. Puisque ffmpeg a plusieurs façons de résoudre ce problème, la bonne façon serait d'utiliser ffmpeg seul, sans l'aide de scripts.
Mladen B.

Beau script. L'avez-vous écrit? Est-ce sur GitHub? J'aimerais faire quelques suggestions :)
voix

pour mp4, les scènes sont endommagées. mieux remplacer la copie par: -vcodec libx264 -acodec aac
kishu

8

D'après mon expérience, n'utilisez pas ffmpeg pour le fractionnement / la jointure. MP4Box, est plus rapide et léger que ffmpeg. Essayez-le. Par exemple, si vous souhaitez diviser un fichier MP4 de 1400 Mo en deux parties de 700 Mo, vous pouvez utiliser la cmdl suivante: MP4Box -splits 716800 input.mp4 par exemple, pour concaténer deux fichiers, vous pouvez utiliser:

MP4Box -cat file1.mp4 -cat file2.mp4 output.mp4

Ou si vous avez besoin d'une division par temps, utilisez -splitx StartTime:EndTime:

MP4Box -add input.mp4 -splitx 0:15 -new split.mp4


C'était exactement ce dont j'avais besoin! Lorsque je coupais avec ffmpeg, les clips ne commençaient pas sur des images clés et présentaient des gels étranges aux extrémités. L'utilisation de MP4Box -splitz a fait l'affaire!
mat

1
comment puis-je découper la vidéo en utilisant Mp4Box avec plusieurs nombres? par exemple, je dois avoir des sous-clips en quelques secondes sont: 5 - 8, 21 - 30, 12 - 18 donc j'ai besoin de trois fichiers vidéo de sortie.
mhndev

Et est beaucoup plus facile à utiliser EndTimeque -t.
vmassuchetto


2

la dernière approche économise-t-elle du temps de calcul et de la mémoire?

Il n'y a pas de grande différence entre ces deux exemples que vous avez fournis. Le premier exemple coupe la vidéo séquentiellement, en 2 étapes, tandis que le deuxième exemple le fait en même temps (en utilisant des threads). Aucune accélération particulière ne sera perceptible. Vous pouvez en savoir plus sur la création de plusieurs sorties avec FFmpeg

De plus, ce que vous pouvez utiliser (dans FFmpeg récent) est le multiplexeur de segment de flux qui peut:

flux de sortie vers un certain nombre de fichiers séparés de durée presque fixe. Le modèle de nom de fichier de sortie peut être défini de la même manière que image2 .


2

Voici un simple fichier bat de Windows pour diviser le fichier entrant en 50 parties. Chaque partie a une durée de 1 minute. Désolé pour un script aussi stupide. J'espère qu'il vaut mieux avoir un script Windows stupide au lieu de ne pas l'avoir du tout. Peut-être que ça aide quelqu'un. (Basé sur "bat file for loop" de ce site.)

set var=0
@echo off
:start
set lz=
if %var% EQU 50 goto end
if %var% LEQ 9 set lz=0
echo part %lz%%var%
ffmpeg -ss 00:%lz%%var%:00 -t 00:01:00 -i %1 -acodec copy -vcodec copy %2_%lz%%var%.mp4
set /a var+=1
goto start

:end
echo var has reached %var%.
exit

Il s'agit essentiellement du premier extrait de code de la question ( ffmpegcommandes consécutives ) réécrit en boucle. Cela ne répond pas à la question de savoir si cette approche ou une seule commande "économisera du temps de calcul et de la mémoire".
BACON

1

Je n'ai pas testé ist, mais cela semble prometteur:

Segmenteur de flux de base

Il divise évidemment l'AVI en segments de même taille, ce qui implique que ces blocs ne perdent pas de qualité, n'augmentent pas la mémoire ou doivent être recalculés.

Il utilise également la copie du codec - cela signifie-t-il qu'il peut gérer de très gros flux? Parce que c'est mon problème, je veux décomposer mon avi pour pouvoir utiliser un filtre pour me débarrasser de la distorsion. Mais tout un avi fonctionne pendant des heures.


-1

Voici un moyen idéal pour diviser la vidéo. Je l'ai déjà fait et cela fonctionne bien pour moi.

ffmpeg -i C:\xampp\htdocs\videoCutting\movie.mp4 -ss 00:00:00 -t 00:00:05 -async 1 C:\xampp\htdocs\videoCutting\SampleVideoNew.mp4 (Pour cmd). shell_exec('ffmpeg -i C:\xampp\htdocs\videoCutting\movie.mp4 -ss 00:00:00 -t 00:00:05 -async 1 C:\xampp\htdocs\videoCutting\SampleVideoNew.mp4')(pour php).

Veuillez suivre ceci et je suis sûr que cela fonctionnera parfaitement.


Pourquoi est-ce le «moyen idéal» de diviser la vidéo? Comme la ligne de commande dans la question, vous passez -isuivi de -sset -t. La question est de savoir comment extraire efficacement plusieurs segments du même fichier d'entrée, alors que vous n'en extrayez qu'un seul segment. Je ne vois pas comment cela répond à la question.
BACON

-2

un moyen simple consiste à utiliser l'option trim avec l' API basée sur l'URL de publitio .

une fois que vous avez téléchargé votre vidéo, définissez simplement le décalage de début et le décalage de fin dans l'URL (so_2, eo_2) comme suit:

    https://media.publit.io/file/so_2,eo_2/tummy.mp4

cela créera instantanément de nouvelles vidéos à partir de la 2ème seconde et d'une durée de 2 secondes. vous pouvez diviser les vidéos de cette façon comme vous le souhaitez.


La question est de savoir quelle est la plus efficace des deux approches pour extraire plusieurs segments d'un fichier d'entrée avec ffmpeg. À moins que vous ne disposiez d'une connexion Internet vraiment très rapide, je pense que le fait de devoir télécharger la vidéo entière sur un service cloud, puis de télécharger les résultats, augmentera considérablement le temps de traitement. Cependant, cela ne répond toujours pas à la question qui approche avecffmpeg est plus efficace.
BACON
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.