it-swarm-id.com

Bagaimana saya bisa menggunakan ffmpeg untuk membagi video MPEG menjadi potongan 10 menit?

Sering ada kebutuhan di komunitas open source atau komunitas pengembang aktif untuk menerbitkan segmen video besar secara online. (Video pertemuan, perkemahan, pembicaraan teknologi ...) Karena saya adalah seorang pengembang dan bukan seorang videografer, saya tidak punya keinginan untuk membayar ekstra pada akun Vimeo premium. Bagaimana cara saya mengambil video pembicaraan teknologi MPEG 12,5 GB (1:20:00) dan mengirisnya menjadi segmen 00:10:00 agar mudah diunggah ke situs berbagi video?

73
Gabriel
$ ffmpeg -i source-file.foo -ss 0 -t 600 first-10-min.m4v
$ ffmpeg -i source-file.foo -ss 600 -t 600 second-10-min.m4v
$ ffmpeg -i source-file.foo -ss 1200 -t 600 third-10-min.m4v
...

Membungkus ini menjadi sebuah skrip untuk melakukannya dalam satu lingkaran tidak akan sulit.

Berhati-hatilah bahwa jika Anda mencoba menghitung jumlah iterasi berdasarkan pada durasi keluaran dari ffprobe panggilan bahwa ini adalah perkiraan dari rata-rata bit rate di awal klip dan ukuran file klip kecuali Anda memberi -count_frames argumen, yang memperlambat operasinya.

Hal lain yang harus diperhatikan adalah posisi -ss pilihan pada baris perintah penting . Di mana saya memilikinya sekarang lambat tapi akurat. Versi pertama dari jawaban ini memberikan alternatif cepat tapi tidak akurat . Artikel yang ditautkan juga menjelaskan sebagian besar alternatif yang cepat-tetapi-masih-akurat, yang Anda bayar dengan sedikit kerumitan.

Selain itu, saya tidak berpikir Anda benar-benar ingin memotong tepat 10 menit untuk setiap klip. Itu akan memotong tepat di tengah kalimat, bahkan kata-kata. Saya pikir Anda harus menggunakan editor video atau pemutar untuk menemukan titik potong alami yang hanya berjarak 10 menit.

Dengan asumsi file Anda dalam format yang dapat diterima YouTube secara langsung, Anda tidak perlu memasukkan ulang kode untuk mendapatkan segmen. Cukup kirimkan offset cut point natural ke ffmpeg, katakan untuk meneruskan A/V yang dikodekan melalui tidak tersentuh dengan menggunakan codec "copy":

$ ffmpeg -i source.m4v -ss 0 -t 593.3 -c copy part1.m4v
$ ffmpeg -i source.m4v -ss 593.3 -t 551.64 -c copy part2.m4v
$ ffmpeg -i source.m4v -ss 1144.94 -t 581.25 -c copy part3.m4v
...

-c copy argumen mengatakannya untuk menyalin semua aliran input (audio, video, dan yang lainnya, seperti subtitle) ke dalam output apa adanya. Untuk program A/V sederhana, itu setara dengan lebih banyak flag verbose -c:v copy -c:a copy atau bendera gaya lama -vcodec copy -acodec copy. Anda akan menggunakan gaya verbose yang lebih ketika Anda ingin menyalin hanya satu aliran, tetapi menyandikan ulang yang lain. Sebagai contoh, beberapa tahun yang lalu ada praktik umum dengan file QuickTime untuk mengompres video dengan video H.264 tetapi meninggalkan audio sebagai PCM tidak terkompresi ; jika Anda menemukan file seperti itu hari ini, Anda bisa memodernkannya dengan -c:v copy -c:a aac untuk memproses ulang hanya aliran audio, membiarkan video tidak tersentuh.

Titik awal untuk setiap perintah di atas setelah yang pertama adalah titik awal perintah sebelumnya ditambah durasi perintah sebelumnya.

72
Warren Young

Inilah solusi satu baris :

ffmpeg -i input.mp4 -c copy -map 0 -segment_time 00:20:00 -f segment output%03d.mp4

Harap dicatat bahwa ini tidak memberikan Anda pembagian yang akurat, tetapi harus sesuai dengan kebutuhan Anda. Sebagai gantinya akan dipotong pada frame pertama setelah waktu yang ditentukan setelah segment_time, dalam kode di atas akan setelah tanda 20 menit.

Jika ternyata hanya potongan pertama yang dapat dimainkan, coba tambahkan -reset_timestamps 1 seperti yang disebutkan dalam komentar.

ffmpeg -i input.mp4 -c copy -map 0 -segment_time 00:20:00 -f segment -reset_timestamps 1 output%03d.mp4
68
Jon

Menghadapi masalah yang sama sebelumnya dan mengumpulkan skrip Python sederhana untuk melakukan hal itu (menggunakan FFMpeg). Tersedia di sini: https://github.com/c0decracker/video-splitter , dan ditempel di bawah:

#!/usr/bin/env python
import subprocess
import re
import math
from optparse import OptionParser
length_regexp = 'Duration: (\d{2}):(\d{2}):(\d{2})\.\d+,'
re_length = re.compile(length_regexp)
def main():
    (filename, split_length) = parse_options()
    if split_length <= 0:
        print "Split length can't be 0"
        raise SystemExit
    output = subprocess.Popen("ffmpeg -i '"+filename+"' 2>&1 | grep 'Duration'",
                              Shell = True,
                              stdout = subprocess.PIPE
    ).stdout.read()
    print output
    matches = re_length.search(output)
    if matches:
        video_length = int(matches.group(1)) * 3600 + \
                       int(matches.group(2)) * 60 + \
                       int(matches.group(3))
        print "Video length in seconds: "+str(video_length)
    else:
        print "Can't determine video length."
        raise SystemExit
    split_count = int(math.ceil(video_length/float(split_length)))
    if(split_count == 1):
        print "Video length is less then the target split length."
        raise SystemExit
    split_cmd = "ffmpeg -i '"+filename+"' -vcodec copy "
    for n in range(0, split_count):
        split_str = ""
        if n == 0:
            split_start = 0
        else:
            split_start = split_length * n
            split_str += " -ss "+str(split_start)+" -t "+str(split_length) + \
                         " '"+filename[:-4] + "-" + str(n) + "." + filename[-3:] + \
                         "'"
    print "About to run: "+split_cmd+split_str
    output = subprocess.Popen(split_cmd+split_str, Shell = True, stdout =
                              subprocess.PIPE).stdout.read()
def parse_options():
    parser = OptionParser()
    parser.add_option("-f", "--file",
                      dest = "filename",
                      help = "file to split, for example sample.avi",
                      type = "string",
                      action = "store"
    )
    parser.add_option("-s", "--split-size",
                      dest = "split_size",
                      help = "split or chunk size in seconds, for example 10",
                      type = "int",
                      action = "store"
    )
    (options, args) = parser.parse_args()
    if options.filename and options.split_size:
        return (options.filename, options.split_size)
    else:
        parser.print_help()
        raise SystemExit
if __name__ == '__main__':
    try:
        main()
    except Exception, e:
        print "Exception occured running main():"
        print str(e)
7
c0decracker

Cara Alternatif lebih banyak dapat dibaca adalah

ffmpeg -i input.mp4 -ss 00:00:00 -to 00:10:00 -c copy output1.mp4
ffmpeg -i input.mp4 -ss 00:10:00 -to 00:20:00 -c copy output2.mp4

/**
* -i  input file
* -ss start time in seconds or in hh:mm:ss
* -to end time in seconds or in hh:mm:ss
* -c codec to use
*/

Ini sumber dan daftar perintah FFmpeg yang umum digunakan.

4
Niket Pathak

Jika Anda ingin membuat Chunks yang benar-benar sama harus memaksa ffmpeg untuk membuat i-frame pada frame pertama setiap chunks sehingga Anda dapat menggunakan perintah ini untuk membuat chunk 0,5 detik.

ffmpeg -hide_banner  -err_detect ignore_err -i input.mp4 -r 24 -codec:v libx264  -vsync 1  -codec:a aac  -ac 2  -ar 48k  -f segment   -preset fast  -segment_format mpegts  -segment_time 0.5 -force_key_frames  "expr: gte(t, n_forced * 0.5)" out%d.mkv
4

Perhatikan tanda baca yang tepat dari format alternatif adalah -ss mm:ss.xxx. Saya berjuang selama berjam-jam mencoba menggunakan mm:ss:xx Intuitif-tetapi-salah tidak berhasil.

$ man ffmpeg | grep -C1 position

Posisi -ss
Cari posisi waktu tertentu dalam detik. Sintaks "hh: mm: ss [.xxx]" juga didukung.

Referensi di sini dan di sini .

3
Mark Hudson

Cukup gunakan apa yang dibangun ke ffmpeg untuk melakukan hal ini.

ffmpeg -i invid.mp4 -threads 3 -vcodec copy -f segment -segment_time 2 cam_out_h264%04d.mp4

Ini akan membaginya menjadi chuck sekitar 2 detik, membaginya di keyframes yang relevan, dan akan menampilkan ke file cam_out_h2640001.mp4, cam_out_h2640002.mp4, dll.

1
John Allard
#!/bin/bash

if [ "X$1" == "X" ]; then
    echo "No file name for split, exiting ..."
    exit 1
fi

if [ ! -f "$1" ]; then
    echo "The file '$1' doesn't exist. exiting ..."
    exit 1
fi

duration=$(ffmpeg -i "$1" 2>&1 | grep Duration | sed 's/^.*Duration: \(.*\)\..., start.*$/\1/' | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')      #'
split_time=${split_time:-55}
time=0
part=1

filename=${file%%.*}
postfix=${file##*.}

while [ ${time} -le ${duration} ]; do

echo    ffmpeg -i "$1" -vcodec copy -ss ${time} -t ${split_time} "${filename}-${part}.${postfix}"
    (( part++ ))
    (( time = time + split_time ))

done
0
Alex_Shilli