Cortar los videos según la hora de inicio y finalización usando ffmpeg

513

Traté de cortar el video usando la hora de inicio y finalización del video usando el siguiente comando

ffmpeg -ss 00:00:03 -t 00:00:08 -i movie.mp4 -acodec copy -vcodec copy -async 1 cut.mp4

Al usar el comando anterior, quiero cortar el video de 00:00:03a 00:00:08. Pero no está cortando el video entre esos momentos en lugar de estar cortando el video con los primeros 11 segundos. ¿Alguien puede ayudarme a resolver esto?

Editar 1:

He intentado cortar usando el siguiente comando sugerido por mark4o

ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 cut.mp4

Pero se mostró el siguiente error.

el codificador 'aac' es experimental pero los códecs experimentales no están habilitados

así que agregué -strict -2el comando, es decir,

ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 -strict -2 cut.mp4

Ahora está funcionando bien.

Kalai
fuente
3
Falta la salida completa de la consola ffmpeg sin cortar. Por favor siempre incluya esto cuando pregunte. Gracias.
slhck
3
¿De dónde sacaste el estricto 2? Simplemente curioso ya que no está en los documentos: ffmpeg.org/ffmpeg.html
StackOverflowed
Es por la calidad después de instalar ffmpeg, en ffmpeg ayuda puedes encontrar esta opción
Kalai
1
superuser.com/questions/138331/using-ffmpeg-to-cut-up-video
Ciro Santilli郝海东冠状病六四事件法轮功
1
Creo que el problema aquí fue en realidad el hecho de que pusiste desde y ANTES de -i movie.mp4. Los argumentos para esa secuencia van DESPUÉS de ella, ¿verdad? Por eso la otra manera funcionó. = /
Brent Rittenhouse

Respuestas:

576

Probablemente no tenga un fotograma clave en la marca de 3 segundos. Debido a que los fotogramas que no son clave codifican diferencias de otros fotogramas, requieren todos los datos que comienzan con el fotograma clave anterior.

Con el contenedor mp4 es posible cortar en un fotograma no clave sin volver a codificar utilizando una lista de edición. En otras palabras, si el fotograma clave más cercano antes de 3s está en 0s, copiará el video que comienza en 0s y usará una lista de edición para indicarle al jugador que comience a jugar 3 segundos después.

Si está utilizando la última versión de ffmpeg de git master, lo hará mediante una lista de edición cuando se invoque con el comando que proporcionó. Si esto no funciona para usted, entonces probablemente esté utilizando una versión anterior de ffmpeg o su reproductor no sea compatible con las listas de edición. Algunos jugadores ignorarán la lista de edición y siempre reproducirán todos los medios del archivo de principio a fin.

Si desea cortar con precisión comenzando en un fotograma no clave y desea que se reproduzca comenzando en el punto deseado en un reproductor que no admite listas de edición, o si desea asegurarse de que la porción de corte no esté realmente en el archivo de salida (por ejemplo si contiene información confidencial), puede hacerlo volviendo a codificar para que haya un fotograma clave precisamente a la hora de inicio deseada. Volver a codificar es el valor predeterminado si no especifica copy. Por ejemplo:

ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 cut.mp4

Al volver a codificar, es posible que también desee incluir opciones adicionales relacionadas con la calidad o un codificador AAC en particular. Para obtener detalles, consulte la Guía de codificación x264 de ffmpeg para video y la Guía de codificación AAC para audio.

Además, la -topción especifica una duración, no una hora de finalización. El comando anterior codificará 8 segundos de video a partir de 3 segundos. Para comenzar a los 3 segundos y terminar a los 8 segundos use -t 5. Si está utilizando una versión actual de FFmpeg también puede reemplazar -tcon -toen el comando anterior a extremo a la hora especificada.

mark4o
fuente
44
¿Hay un atajo para especificar hasta el final del video?
Jikku Jose
20
@JikkuJose: Omita el -t/ -toy su argumento para continuar hasta el final.
mark4o
41
Nota: es más rápido suministrar -ssANTES del archivo de entrada (antes -i), porque de esa manera ffmpeg saltará directamente a la ubicación. Sin embargo, eso también establecerá el tiempo "cero" en esa ubicación, lo que significa que -toseñalará el momento equivocado. Fuente: trac.ffmpeg.org/wiki/Seeking
Denilson Sá Maia
44
Tengo un problema de sincronización de audio y video después de usar esto ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 cut.mp4, aunque el archivo original no tiene ese problema.
user2002522
66
@ user2002522: intente sin el -async 1.
mark4o
433

Intenta usar esto. Es la forma de ffmpeg más rápida y mejor que tengo:

 ffmpeg -ss 00:01:00 -i input.mp4 -to 00:02:00 -c copy output.mp4

¡Este comando recorta tu video en segundos!

Lo he explicado en mi blog aquí :

-i: esto especifica el archivo de entrada. En ese caso, es (input.mp4).
-ss: Utilizado con -i, esto busca en el archivo de entrada (input.mp4) a la posición.
00:01:00: Este es el momento en que comenzará su video recortado.
-to: Esto especifica la duración desde el inicio (00:01:40) hasta el final (00:02:12).
00:02:00: Este es el momento en que terminará su video recortado.
-c copy: esta es una opción para recortar a través de la copia de flujo. (Nota: muy rápido)

El formato de tiempo es: hh: mm: ss

Tenga en cuenta que la respuesta actual altamente votada está desactualizada y el recorte sería extremadamente lento. Para obtener más información, consulte este artículo oficial de ffmpeg .

George Chalhoub
fuente
99
Esto procesó mi archivo de 45 min 720p en 3s. Esta debería ser la respuesta correcta.
Dheeraj Bhaskar
77
Sin embargo, aún puede sufrir una falta de fotogramas clave con esto. Adopté su enfoque para cortar, luego volví a codificar según la respuesta aceptada para asegurarme de que minimizaba la cantidad de tiempo que necesitaba para volver a codificar.
pelson
77
Como dice @pelson, esto cortará los fotogramas clave y dejará los primeros segundos en blanco (si el tiempo de corte es entre fotogramas clave). Curiosamente, cambiando el orden de los parámetros resuelve el problema: ffmpeg -ss 00:01:00 -to 00:02:00 -i input.mp4 -ss 00:01:00 -to 00:02:00 -c copy output.mp4. Ahora, sin embargo, se omite el salto y el tiempo de finalización no es correcto (en mi caso).
Raphael
66
Debe usar esta respuesta si no necesita recortar en un milisegundo exacto, por lo tanto, seleccionará el fotograma clave más cercano disponible. Por eso es tan rápido, selecciona los fotogramas clave más cercanos y saca el fragmento sin la necesidad de volver a codificar. Sin embargo, si necesita un tiempo preciso, tomar el fotograma clave más cercano no es suficiente, porque ciertamente no coincidirá exactamente. La única solución disponible es volver a codificar el video, y es por eso que es tan lento. Sin embargo, esa es la única solución si necesita esto. Es por eso que la otra respuesta debe ser la aceptada, ya que ese es el problema de OP.
Yamaneko
44
No estoy seguro de por qué, pero esto no parece ser más correcto que la respuesta aceptada porque esto conduce a problemas con falta de fotogramas clave. Para videoclips cortos, el efecto es inaceptable. La reencodificación lenta parece ser la única solución en tales casos.
icarus74
91
ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 -c copy cut.mp4 

Use -c copy para hacer instantáneamente. En ese caso, ffmpeg no volverá a codificar el video, solo lo cortará según el tamaño.

Vlad Hudnitsky
fuente
2
of -c copy funciona muy bien, pero solo si elimino -async 1
dorien el
2
Esto termina fallando en la escritura debido a encabezados no válidos en el caso de diferentes contenedores de entrada y salida, por ejemplo, entrada .mkv y salida .mp4.
Assil Ksiksi
1
Muy bien, para convertir .mkv a .mp4 tienes que usar otro comando: ffmpeg -i movie.mkv -vcodec copy -acodec copy converted_movie.mp4y viceversa
Vlad Hudnitsky
¿Cuáles son las ventajas de volver a codificar? ¿Es útil si solo queremos videos más pequeños en el mismo formato?
Harsha
29
    ffmpeg -i movie.mp4 -vf trim=3:8 cut.mp4

Suelta todo excepto del segundo 3 al segundo 8.

JFMD
fuente
44
Obtengo los primeros 8 segundos con esto, con los primeros 3 segundos congelados en el primer fotograma. Se solucionó encadenando el setpts=PTS-STARTPTSfiltro después del filtro de recorte.
jiggunjer
Esto dice "El codificador 'aac' es experimental pero los códecs experimentales no están habilitados, agregue '-strict -2' si desea usarlo". Agregar -strict -2 no ayuda. El resultado es un archivo de longitud cero.
Ivan
44
@ Ivan, ¿intentaste agregar -strict -2antes cut.mp4(en lugar del final de la línea de comando)?
Jan Gondol
Oye, ¿puedes decirme si solo quiero video sin 3 a 8 segundos?
Parth Solanki
1
Esto es súper lento
Tessaracter
21

Para cortar según el tiempo de inicio y finalización del video fuente y evitar tener que hacer cálculos matemáticos, especifique el tiempo de finalización como la opción de entrada y el tiempo de inicio como la opción de salida.

ffmpeg -t 1:00 -i input.mpg -ss 45 output.mpg

Esto producirá un corte de 15 segundos de 0:45 a 1:00.

Esto se debe a que cuando -ssse proporciona como una opción de salida, el tiempo descartado todavía se incluye en el tiempo total leído desde la entrada, que -tutiliza para saber cuándo detenerse. Mientras que si -ssse da como una opción de entrada , el tiempo de inicio se busca y no se cuenta , que es de donde proviene la confusión.

Es más lento que buscar ya que el segmento omitido todavía se procesa antes de descartarse, pero esta es la única forma de hacerlo, que yo sepa. Si está recortando desde lo más profundo de un archivo grande, es más prudente hacer los cálculos y usarlos -sspara la entrada.

RY
fuente
44
lento, pero lo único que funcionó para mí (sin perder marcos de otras respuestas)
techkuz
8

Esto es lo que uso:

ffmpeg -i input.mkv -ss 00:01:00 -to 00:02:00 -c:v copy -c:a copy output.mp4

Los mp4archivos generados también podrían usarse en iMovie.

Referencia: https://www.arj.no/2018/05/18/trimvideo


Si desea concatenar múltiples escenas de corte, puede usar el siguiente script:

#!/usr/bin/env python3

import subprocess

name = "batman.mp4"

times = []
times.append(["01:06:00", "01:07:00"])
times.append(["01:08:00", "01:09:00"])

open('concatenate.txt', 'w').close()
for idx, time in enumerate(times):
    output_filename = f"output{idx}.mp4"
    cmd = ["ffmpeg", "-i", name, "-ss", time[0], "-to", time[1], "-c:v", "copy", "-c:a", "copy", output_filename]
    subprocess.check_output(cmd)
    with open("concatenate.txt", "a") as myfile:
        myfile.write(f"file {output_filename}\n")

cmd = ["ffmpeg", "-f", "concat", "-i", "concatenate.txt", "-c", "copy", "final.mp4"]
output = subprocess.check_output(cmd).decode("utf-8").strip()
alper
fuente
Sin embargo
esto
1
Mi enfoque es diferente de las respuestas aceptadas. He probado aquellos que tienen más tiempo para construir el archivo mp4. @Tessaracter
Alper
1
Esta es la ÚNICA respuesta aquí que funcionó para mí para cortar un pequeño clip de un video grande. Esto funciona y rápido! Gracias
lacostenycoder
1
De nada, me alegro de poder ayudar. Pude encontrar esta respuesta después de probar muchos enfoques. La mayoría de ellos fueron bastante lentos. @lacostenycoder
Alper
¿No podría esto simplemente usar "-c" con "copy" en lugar de dividir -c: v y -c: a?
nstenz
-3

Aunque llego 6 años tarde, creo que todas las respuestas anteriores no respondieron adecuadamente la pregunta que @kalai está haciendo. El script bash a continuación procesará un archivo de texto en el siguiente formato:

URL | start_time | end_time | filename

por ejemplo

https://www.youtube.com/watch?v=iUDURCrvrMI|00:02:02|00:03:41|1

y recorrer el archivo, descarga el archivo que youtube-dladmite, calculando la duración entre start_timey end_timey pasándolo affmpeg , ya -tque en realidad es la duración , no la realend_time

Contáctame si tienes alguna pregunta.

    for i in $(<video.txt);
    do
        URL=`echo $i | cut -d "|" -f 1`;
        START=`echo $i | cut -d "|" -f 2`;
        END=`echo $i | cut -d "|" -f 3`;
        FILE=`echo $i | cut -d "|" -f 4`;

        SEC1=`echo $START | sed 's/^/((/; s/:/)*60+/g' | bc`
        SEC2=`echo $END | sed 's/^/((/; s/:/)*60+/g' | bc`

        DIFFSEC=`expr ${SEC2} - ${SEC1}`

        ffmpeg $(youtube-dl -g $URL | sed "s/.*/-ss $START -i &/") -t $DIFFSEC -c copy $FILE".mkv";
        ffmpeg -i $FILE".mkv" -f mp3 -ab 192000 -vn $FILE".mp3";
        rm $FILE".mkv";
    done;
rolodex
fuente
Esto genera solo un archivo de audio mp3 y NO un video.
lacostenycoder
Sí ... solo cambia el formato de salida.
rolodex