De video’s knippen op basis van begin- en eindtijd met ffmpeg

Ik heb geprobeerd de video te knippen met de begin- en eindtijd van de video met het volgende commando

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

Met het bovenstaande commando wil ik de video knippen van 00:00:03naar 00:00:08. Maar het snijdt de video niet tussen die tijden in plaats van dat het de video met de eerste 11 seconden afsnijdt. kan iemand me helpen hoe dit op te lossen?

Bewerken 1:

Ik heb geprobeerd te knippen met behulp van de volgende opdracht die wordt voorgesteld door mark4o

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

Maar er werd de volgende fout getoond.

de encoder ‘aac’ is experimenteel, maar experimentele codecs zijn niet ingeschakeld

dus ik heb de -strict -2toegevoegd aan de opdracht, d.w.z.

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

Nu werkt het prima.


Antwoord 1, autoriteit 100%

U heeft waarschijnlijk geen keyframe bij de markering van 3 seconden. Omdat niet-keyframes verschillen met andere frames coderen, hebben ze alle gegevens nodig die beginnen met het vorige keyframe.

Met de mp4-container is het mogelijk om op een niet-keyframe te knippen zonder opnieuw te coderen met behulp van een bewerkingslijst. Met andere woorden, als het dichtstbijzijnde keyframe vóór 3s op 0s staat, zal het de video kopiëren vanaf 0s en een bewerkingslijst gebruiken om de speler te vertellen dat het 3 seconden later moet beginnen met afspelen.

Als je de nieuwste ffmpegvan git master gebruikt, zal het dit doen met behulp van een bewerkingslijst wanneer het wordt aangeroepen met het commando dat je mits. Als dit voor u niet werkt, gebruikt u waarschijnlijk een oudere versie van ffmpeg, of uw speler ondersteunt geen bewerkingslijsten. Sommige spelers negeren de bewerkingslijst en spelen altijd alle media in het bestand van begin tot eind af.

Als u precies wilt knippen vanaf een niet-keyframe en wilt dat het wordt afgespeeld vanaf het gewenste punt op een speler die geen bewerkingslijsten ondersteunt, of als u ervoor wilt zorgen dat het geknipte gedeelte niet daadwerkelijk in het uitvoerbestand staat (bijvoorbeeld als het vertrouwelijke informatie bevat), dan kunt u dat doen door opnieuw te coderen zodat er precies op de gewenste starttijd een keyframe is. Opnieuw coderen is de standaardinstelling als u copyniet opgeeft. Bijvoorbeeld:

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

Als je opnieuw codeert, wil je misschien ook extra kwaliteitsgerelateerde opties of een bepaalde AAC-encoder toevoegen. Zie voor meer informatie de x264 Encoding Guidevoor video en AAC-coderingsgidsvoor audio.

Ook de optie -tspecificeert een duur, geen eindtijd. De bovenstaande opdracht codeert 8s video vanaf 3s. Gebruik -t 5om te beginnen bij 3s en te eindigen bij 8s. Als u een huidige versie van ffmpeg gebruikt, kunt u ook -tvervangen door -toin de bovenstaande opdracht om op de opgegeven tijd te eindigen.


Antwoord 2, autoriteit 92%

Probeer dit te gebruiken. Het is de snelste en beste ffmpeg-manier die ik heb bedacht:

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

Met deze opdracht wordt je video binnen enkele seconden bijgesneden!

Uitleg van de opdracht:

-i:Dit specificeert het invoerbestand. In dat geval is het (input.mp4).
-ss:Gebruikt met -i, dit zoekt in het invoerbestand (input.mp4) naar positie.
00:01:00:dit is de tijd waarmee je bijgesneden video begint.
-to:Dit specificeert de duur van begin (00:01:40) tot einde (00:02:12).
00:02:00:dit is het tijdstip waarop je bijgesneden video eindigt.
-c copy:dit is een optie om te trimmen via stream copy. (NB: erg snel)

Het timingformaat is: uu:mm:ss

Houd er rekening mee dat het huidige antwoord met veel stemmen achterhaald is en dat het trimmen extreem traag zou zijn. Bekijk voor meer informatie dit officiële ffmpeg artikel.


Antwoord 3, autoriteit 15%

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

Gebruik -c copyom direct in te voeren. In dat geval zal ffmpeg de video niet opnieuw coderen, maar alleen op maat knippen.


Antwoord 4, autoriteit 5%

   ffmpeg -i movie.mp4 -vf trim=3:8 cut.mp4

Laat alles vallen behalve van tweede 3 naar tweede 8.


Antwoord 5, autoriteit 3%

nieuw antwoord (snel)

Je kunt bash het rekenwerk voor je laten doen, en het werkt in milliseconden.

toSeconds() {
    awk -F: 'NF==3 { print ($1 * 3600) + ($2 * 60) + $3 } NF==2 { print ($1 * 60) + $2 } NF==1 { print 0 + $1 }' <<< $1
}
StartSeconds=$(toSeconds "45.5")
EndSeconds=$(toSeconds "1:00.5")
Duration=$(bc <<< "(${EndSeconds} + 0.01) - ${StartSeconds}" | awk '{ printf "%.4f", $0 }')
ffmpeg -ss $StartSeconds -i input.mpg -t $Duration output.mpg

Dit levert, net als het oude antwoord, een clip van 15 seconden op. Deze methode is ideaal, zelfs bij het knippen van diep in een groot bestand, omdat zoeken niet is uitgeschakeld, in tegenstelling tot het oude antwoord. En ja, ik heb geverifieerd dat het frame perfect is.

OPMERKING:de starttijd is INCLUSIEFen de eindtijd is normaal EXCLUSIEF, vandaar de +0.01, om het inclusief te maken.

Als u mpvgebruikt, kunt u milliseconden tijdcodes in de OSD inschakelen met --osd-fractions


oud antwoord met uitleg (langzaam)

Om te knippen op basis van de start- en eindtijd van de bronvideo en te voorkomen dat u wiskunde moet doen, specificeert u de eindtijd als invoeroptie en de starttijd als uitvoeroptie.

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

Dit levert een cut van 15 seconden op van 0:45 tot 01:00.

Dit komt omdat wanneer -ssals uitvoeroptie wordt gegeven, de weggegooide tijd nog steeds wordt opgenomen in de totale tijd die wordt gelezen van de invoer, die -tgebruikt om weet wanneer je moet stoppen. Terwijl als -sswordt gegeven als een invoeroptie, de starttijd wordt gezocht en niet geteld, waar de verwarring vandaan komt.

Het is langzamer dan zoeken omdat het weggelaten segment nog steeds wordt verwerkt voordat het wordt verwijderd, maar dit is de enige manier om het te doen voor zover ik weet. Als je uit een groot bestand clipt, is het verstandiger om gewoon de wiskunde te doen en -sste gebruiken voor de invoer.


Antwoord 6, autoriteit 3%

Dit is wat ik gebruik en het duurt slechts enkele secondenom uit te voeren:

ffmpeg -i input.mp4 -ss 01:19:27 -to 02:18:51 -c:v copy -c:a copy output.mp4

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


Gegenereerde mp4-bestanden kunnen ook worden gebruikt in iMovie. Meer informatie over het verkrijgen van de volledige duur met behulp van get_duration(input_video)-model.


Als je meerdere tussenfilmpjes wilt samenvoegen, kun je het volgende Python-script gebruiken:

#!/usr/bin/env python3
import subprocess
def get_duration(input_video):
    cmd = ["ffprobe", "-i", input_video, "-show_entries", "format=duration",
           "-v", "quiet", "-sexagesimal", "-of", "csv=p=0"]
    return subprocess.check_output(cmd).decode("utf-8").strip()
if __name__ == "__main__":
    name = "input.mkv"
    times = []
    times.append(["00:00:00", "00:00:10"])
    times.append(["00:06:00", "00:07:00"])
    # times = [["00:00:00", get_duration(name)]]
    if len(times) == 1:
        time = times[0]
        cmd = ["ffmpeg", "-i", name, "-ss", time[0], "-to", time[1], "-c:v", "copy", "-c:a", "copy", "output.mp4"]
        subprocess.check_output(cmd)
    else:
        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", "output.mp4"]
        output = subprocess.check_output(cmd).decode("utf-8").strip()

Voorbeeldscript zal scènes tussen 00:00:00 - 00:00:10en 00:06:00 - 00:07:00knippen en samenvoegen.


Als je de volledige video wilt knippen (voor het geval je het mkv-formaat wilt converteren naar mp4), verwijder dan gewoon de volgende regel:

# times = [["00:00:00", get_duration(name)]]

Antwoord 7

Gebruik -to in plaats van -t: -to specificeert de eindtijd, -t specificeert de duur


Antwoord 8

voel je vrij om deze tool te gebruiken https://github.com/rooty0/ffmpeg_video_cutterdie ik schreef een tijdje geleden
Dat is zo’n beetje de cli-front-end voor ffmpeg … je hoeft alleen maar een yaml te maken wat je wilt verwijderen … zoiets als dit

cut_method: delete  # we're going to delete following video fragments from a video
timeframe:
  - from: start   # waiting for people to join the conference
    to: 4m
  - from: 10m11s  # awkward silence
    to: 15m50s
  - from: 30m5s   # Off-Topic Discussion
    to: end

en voer dan gewoon een tool uit om resultaat te krijgen


Antwoord 9

Ook al ben ik 6 jaar te laat, maar ik denk dat alle bovenstaande antwoorden de vraag @kalai@kalaivraagt.
Het onderstaande bash-script verwerkt een tekstbestand in het volgende formaat:

URL | start_time | end_time | filename

bijvoorbeeld

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

en doorloop het bestand, downloadt het bestand dat youtube-dlondersteunt, berekent de duur tussen start_timeen end_timeen geeft het door aan ffmpeg, aangezien -teigenlijk de duuris, niet de echte end_time

Stuur me een berichtje als je vragen hebt.

   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;

Other episodes