FFmpeg: Bagaimana cara membagi video secara efisien?

103

Saya ingin membagi video avi besar menjadi dua video kecil berturut-turut. Saya menggunakan ffmpeg.

Salah satu caranya adalah dengan menjalankan ffmpeg dua kali:

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

Tetapi menurut halaman manual ffmpeg, saya dapat membuat lebih dari satu file ouput dari satu file input hanya dengan menggunakan satu baris:

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

Pertanyaan saya adalah, apakah pendekatan selanjutnya menghemat waktu komputasi dan memori?

Antony
sumber
3
saat menggunakan "-vcodec copy -acodec copy" itu sangat cepat :))
Savas Adar
@ Antony, Mengapa Anda tidak menghitung waktu kedua versi (dan melihat monitor memori seperti itu htop), dan memberi tahu kami apa jawabannya?
AlcubierreDrive
Contoh pertama melakukannya secara berurutan, sedangkan contoh kedua menggunakan utas. Keduanya akan melakukan hal yang sama, tidak ada percepatan yang terlihat. Tetapi untuk menyederhanakannya, Anda dapat menggunakan ffmpeg stream segmenter muxer: ffmpeg.org/…
Mladen B.
1
Contoh ini terlihat sangat salah! Dokumentasi ffmpeg menjelaskan tentang opsi -ss: "Saat digunakan sebagai opsi masukan (sebelum -i), cari di file masukan ini ke posisi. Saat digunakan sebagai opsi keluaran (sebelum nama file keluaran), men-decode tetapi membuang masukan sampai cap waktu mencapai posisi. " Anda menggunakannya di posisi keluaran, jadi baris kedua Anda membuang-buang tenaga untuk memecahkan kode dan membuang 30 menit pertama.
Lucian Wischik
1
@LucianWischik tetapi menggunakan -ssopsi input pada pembagian kedua mungkin tidak akurat, jadi Anda mungkin tidak mendapatkan pemisahan yang bersih. IMO contoh OP lebih tepat.
jiggunjer

Jawaban:

82

Wiki ffmpeg menautkan kembali ke halaman ini mengacu pada "Bagaimana membagi video secara efisien". Saya tidak yakin halaman ini menjawab pertanyaan itu, jadi saya melakukan seperti yang disarankan @AlcubierreDrive…

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

Output mana ...

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

Saya menguji file SD & HD, setelah beberapa kali berjalan & sedikit matematika.

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  

File SD = 1,35GB aliran transportasi DVB
file HD = 3,14GB aliran transportasi DVB

Kesimpulan

Perintah tunggal lebih baik jika Anda menangani HD, ini setuju dengan komentar manual tentang penggunaan -ss setelah file input untuk melakukan 'pencarian lambat'. File SD memiliki perbedaan yang dapat diabaikan.

Versi dua perintah harus lebih cepat dengan menambahkan -ss sebelum file input untuk 'pencarian cepat' diikuti dengan pencarian lambat yang lebih akurat.

pengguna2867531
sumber
Jika TS berisi beberapa program (program TV yang ditangkap oleh DVB-T), bagaimana cara membaginya? Misalnya saya memiliki file TS yang berisi football + cooking + cartoon. Bagaimana cara membagi file TS ini menjadi 3 file mpg?
Dr.jacky
Saya menggunakan jawaban Anda dalam pertanyaan saya di sini ( stackoverflow.com/questions/41983940/… ) tetapi tidak berhasil, menurut Anda apa yang saya lakukan salah?
utdev
1
File hasil tanpa video (hanya audio) dalam kasus saya. Setelah beberapa percobaan saya menemukan soultion. Ini perlu menentukan kunci untuk "jangan mengubah kualitas" seperti ini -q:v 0.
oklas
19

Berikut adalah skrip yang berguna, ini membantu Anda memisahkan secara otomatis: Skrip untuk membagi video menggunakan ffmpeg

#!/bin/bash
 
# Written by Alexis Bezverkhyy <[email protected]> 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
Marco C.
sumber
2
Komentar yang sama berlaku untuk Anda seperti untuk SEARAS. Menulis file batch berguna saat benar-benar dibutuhkan dan saat Anda tidak memiliki opsi lain yang tersedia, karena ini tidak portabel. Anda tidak akan dapat menjalankan skrip yang sama di Windows, misalnya. Ketika ada cara yang lebih umum / portabel, skrip batch harus dihindari, untuk menghemat waktu yang diperlukan untuk mem-portnya. Karena ffmpeg memiliki banyak cara untuk mengatasi masalah ini, cara yang tepat adalah menggunakan ffmpeg saja, tanpa bantuan skrip.
Mladen B.
Naskah yang bagus. Apakah kamu yang menulisnya? Apakah di GitHub? Saya ingin memberikan beberapa saran :)
suara
untuk mp4, adegan rusak. lebih baik ganti salinan dengan: -vcodec libx264 -acodec aac
kishu
8

Dalam pengalaman saya, jangan gunakan ffmpeg untuk memisahkan / bergabung. MP4Box, lebih cepat dan ringan dari ffmpeg. Silakan mencobanya. Misalnya jika Anda ingin membagi file MP4 1400mb menjadi dua bagian menjadi 700mb Anda dapat menggunakan cmdl berikut: MP4Box -splits 716800 input.mp4 misalnya untuk menggabungkan dua file Anda dapat menggunakan:

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

Atau jika Anda perlu membagi waktu, gunakan -splitx StartTime:EndTime:

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

Klasik
sumber
Inilah yang saya butuhkan! Saat saya memotong dengan ffmpeg, klip tidak dimulai pada bingkai utama dan ada pembekuan aneh di ujungnya. Menggunakan MP4Box -splitz berhasil!
matt
1
bagaimana cara memangkas video menggunakan Mp4Box dengan banyak angka? sebagai contoh yang saya butuhkan untuk memiliki sub klip dalam hitungan detik adalah: 5 - 8, 21 - 30, 12 - 18 jadi saya membutuhkan tiga file video keluaran.
mhndev
Dan jauh lebih mudah digunakan EndTimedaripada -t.
vmassuchetto
2

apakah pendekatan selanjutnya menghemat waktu komputasi dan memori?

Tidak ada perbedaan besar antara kedua contoh yang Anda berikan. Contoh pertama memotong video secara berurutan, dalam 2 langkah, sedangkan contoh kedua melakukannya secara bersamaan (menggunakan utas). Tidak ada percepatan tertentu yang akan terlihat. Anda dapat membaca lebih lanjut tentang membuat beberapa output dengan FFmpeg

Lebih jauh lagi, yang dapat Anda gunakan (dalam FFmpeg baru-baru ini) adalah muxer pemisah aliran yang dapat:

output mengalir ke sejumlah file terpisah dengan durasi yang hampir tetap. Pola nama file keluaran dapat diatur dengan cara yang mirip dengan image2 .

Mladen B.
sumber
2

Berikut adalah file bat Windows sederhana untuk membagi file yang masuk menjadi 50 bagian. Setiap bagian berdurasi 1 menit. Maaf untuk skrip bodoh seperti itu. Saya berharap lebih baik memiliki skrip windows yang bodoh daripada tidak memilikinya sama sekali. Mungkin itu membantu seseorang. (Berdasarkan "bat file for loop" dari situs ini.)

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
Alex Bor
sumber
Ini pada dasarnya adalah potongan kode pertama dalam pertanyaan ( ffmpegperintah berurutan ) yang ditulis ulang sebagai loop. Ini tidak menjawab pertanyaan apakah pendekatan itu atau satu perintah akan "menghemat waktu komputasi dan memori".
BACON
1

Tidak melakukan pengujian, tetapi ini terlihat menjanjikan:

Pemisah aliran dasar

Ini jelas membagi AVI menjadi beberapa segmen dengan ukuran yang sama, yang menyiratkan bahwa potongan ini tidak kehilangan kualitas atau meningkatkan memori atau harus dihitung ulang.

Ia juga menggunakan salinan codec - apakah itu berarti ia dapat menangani aliran yang sangat besar? Karena ini masalah saya, saya ingin memecah avi saya sehingga saya bisa menggunakan filter untuk menghilangkan distorsinya. Tapi keseluruhan avi berjalan berjam-jam.

Mathias Weitz
sumber
-1

Berikut adalah cara sempurna untuk membagi video. Saya telah melakukannya sebelumnya, dan itu bekerja dengan baik untuk saya.

ffmpeg -i C:\xampp\htdocs\videoCutting\movie.mp4 -ss 00:00:00 -t 00:00:05 -async 1 C:\xampp\htdocs\videoCutting\SampleVideoNew.mp4 (Untuk 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')(untuk php).

Silakan ikuti ini dan saya yakin ini akan bekerja dengan sempurna.

Atul Upadhyay
sumber
Mengapa ini "cara sempurna" untuk membagi video? Seperti baris perintah dalam pertanyaan, Anda melintas -idiikuti oleh -ssdan -t. Pertanyaannya adalah tentang cara mengekstrak beberapa segmen secara efisien dari file input yang sama, sedangkan Anda hanya mengekstrak satu segmen. Saya tidak melihat bagaimana ini menjawab pertanyaan itu.
BACON
-2

salah satu cara sederhana adalah dengan menggunakan opsi trim dengan api berbasis url publitio .

setelah Anda mengupload video, cukup setel offset awal dan offset akhir di url (so_2, eo_2) seperti ini:

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

ini akan membuat video baru secara instan mulai dari detik ke-2 dan berdurasi 2 detik. Anda dapat membagi video dengan cara ini sesuka Anda.

ob1y2k.dll
sumber
Pertanyaannya adalah menanyakan pendekatan mana yang lebih efisien dari dua pendekatan untuk mengekstraksi beberapa segmen dari file input dengan ffmpeg. Kecuali jika Anda memiliki koneksi internet yang sangat, sangat cepat, saya pikir harus mengunggah seluruh video ke layanan cloud dan kemudian mengunduh hasilnya akan meningkatkan waktu pemrosesan secara signifikan. Meski begitu, ini masih belum menjawab pertanyaan denganffmpeg pendekatan mana yang lebih efisien.
BACON