FFmpeg: Video nasıl verimli bir şekilde bölünür?


103

Büyük bir avi videosunu art arda iki küçük videoya bölmek istiyorum. Ffmpeg kullanıyorum.

Bunun bir yolu ffmpeg'i iki kez çalıştırmaktır:

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

Ancak ffmpeg'in kılavuz sayfasına göre, tek bir satır kullanarak bir girdi dosyasından birden fazla çıktı dosyası oluşturabilirim :

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

Sorum şu, sonraki yaklaşım hesaplama süresinden ve hafızadan tasarruf sağlıyor mu?


3
"-vcodec kopyası -acodec kopyası" kullanıldığında çok hızlıdır :))
Savas Adar

@Antony, Neden her iki sürümü de zamanlamıyorsun (ve bellek monitörüne bakmıyorsun htop) ve bize cevabın ne olduğunu söylemiyorsun?
AlcubierreDrive

İlk örnek bunu sırayla yaparken, ikinci örnek konuları kullanır. Her ikisi de aynı şeyi yapacak, gözle görülür hızlanma olmamalı. Ancak işleri basitleştirmek için, ffmpeg stream segmenter muxer'ı
Mladen B.

1
Bu örnek çok yanlış görünüyor! Ffmpeg dokümantasyonu -ss seçeneği hakkında şunları söyler: "Bir giriş seçeneği olarak kullanıldığında (-i'den önce), bu girdi dosyasında konum arar. zaman damgaları konuma ulaşır. " Çıktı konumunda kullanıyorsunuz, bu nedenle ikinci satırınız kod çözme ve ilk 30 dakikanın atılması için çaba harcıyor.
Lucian Wischik

1
@LucianWischik ancak -ssikinci bölmede girdi seçeneği olarak kullanmak doğru olmayabilir, bu nedenle temiz bir bölme elde edemeyebilirsiniz. IMO OP'nin verdiği örnek daha doğrudur.
jiggunjer

Yanıtlar:


82

Ffmpeg wiki, "Videonun verimli bir şekilde nasıl bölüneceği" konusuna referansla bu sayfaya geri bağlanır. Bu sayfanın bu soruyu yanıtladığına ikna olmadım, bu yüzden @ AlcubierreDrive'ın önerdiği gibi yaptım…

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

Hangi çıktılar ...

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

Birkaç çalıştırma ve biraz matematik işleminden sonra bir SD ve HD dosyasını test ettim.

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  

SD dosyası = 1.35GB DVB taşıma akışı
HD dosyası = 3.14GB DVB taşıma akışı

Sonuç

Tek bir komut, HD ile çalışıyorsanız daha iyidir, 'yavaş arama' yapmak için giriş dosyasından sonra -ss kullanımıyla ilgili kılavuzların açıklamalarına uygundur. SD dosyalarının ihmal edilebilir bir farkı vardır.

İki komut sürümü, bir 'hızlı arama' için girdi dosyasından önce başka bir -ss ekleyerek ve ardından daha doğru yavaş arama ile daha hızlı olmalıdır.


TS birden fazla program içeriyorsa (DVB-T tarafından yakalanan TV programları), onu nasıl bölebilir? Örneğin, futbol + yemek + çizgi film içeren bir TS dosyam var. Bu TS dosyasını 3 mpg dosyasına nasıl bölebilirim?
Dr.jacky

Cevabınızı buradaki sorumda kullandım ( stackoverflow.com/questions/41983940/… ) ama işe yaramadı, neyi yanlış yaptığımı düşünüyorsunuz?
utdev

1
Sonuç dosyası benim durumumda video içermiyordu (yalnızca ses). Bazı deneylerden sonra ruhu buldum. Bunun gibi "kaliteyi değiştirmeyin" için anahtar belirtmesi gerekir -q:v 0.
oklas

19

İşte kullanışlı bir komut dosyası, otomatik olarak bölmenize yardımcı olur: Videoları ffmpeg kullanarak bölmek için bir komut dosyası

#!/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
SEARAS ile aynı yorum sizin için de geçerli. Toplu iş dosyaları yazmak, kesinlikle gerekli olduğunda ve başka seçeneğiniz olmadığında kullanışlıdır, çünkü taşınabilir değildir. Örneğin, aynı komut dosyasını Windows'ta çalıştıramazsınız. Daha genel / taşınabilir yollar olduğunda, bunları taşımak için gereken zamandan tasarruf etmek için toplu komut dosyalarından kaçınılmalıdır. Ffmpeg'in bu sorunu çözmek için birden fazla yolu olduğundan, doğru yol, komut dosyalarının yardımı olmadan ffmpeg'i tek başına kullanmaktır.
Mladen B.

Güzel senaryo. Yazdın mı GitHub'da mı? Bazı önerilerde bulunmak istiyorum :)
sesler

mp4 için sahneler zarar görür. kopyayı şununla daha iyi değiştirin: -vcodec libx264 -acodec aac
kishu

8

Tecrübelerime göre, bölme / birleştirme için ffmpeg kullanmayın. MP4Box, ffmpeg'den daha hızlı ve hafiftir. Lütfen dene. Örneğin, 1400mb'lik bir MP4 dosyasını 700mb'lik iki parçaya bölmek istiyorsanız, aşağıdaki cmdl'yi kullanabilirsiniz: MP4Box -splits 716800 input.mp4 örneğin, iki dosyayı birleştirmek için kullanabilirsiniz:

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

Veya zamana göre ayrılmanız gerekiyorsa, şunu kullanın -splitx StartTime:EndTime:

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


Bu tam olarak ihtiyacım olan şeydi! Ffmpeg ile keserken klipler ana karelerde başlamıyordu ve uçlarında tuhaf donmalar vardı. MP4Box -splitz kullanmak hile yaptı!
matt

1
Mp4Box kullanarak birden fazla numarayla videoyu nasıl kırpabilirim? örneğin saniyeler içinde alt kliplere ihtiyacım var: 5 - 8, 21 - 30, 12 - 18, bu yüzden üç çıktı video dosyasına ihtiyacım var.
mhndev

Ve kullanımına çok daha kolaydır EndTimedaha -t.
vmassuchetto


2

sonraki yaklaşım hesaplama süresinden ve bellekten tasarruf sağlar mı?

Sağladığınız bu iki örnek arasında büyük bir fark yok. İlk örnek videoyu 2 adımda sıralı olarak keserken, ikinci örnek aynı anda (ipler kullanarak) yapıyor. Belirli bir hızlanma fark edilmeyecektir. FFmpeg ile birden çok çıktı oluşturma hakkında daha fazla bilgi edinebilirsiniz

Dahası, kullanabileceğiniz şey (son FFmpeg'de), aşağıdakileri yapabilen akış segmenter çoklayıcıdır :

akışları neredeyse sabit süreli bir dizi ayrı dosyaya çıktı. Çıktı dosya adı düzeni, image2'ye benzer bir şekilde ayarlanabilir .


2

İşte gelen dosyayı 50 parçaya ayırmak için basit bir Windows yarasa dosyası. Her bölümün uzunluğu 1 dakikadır. Böyle aptalca senaryo için özür dilerim. Umarım aptal bir windows komut dosyasına sahip olmak daha iyidir. Belki birine yardımcı olur. (Bu sitedeki "bat dosya for döngüsü" temel alınmıştır.)

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

Bu, aslında ffmpegbir döngü olarak yeniden yazılan sorudaki (ardışık komutlar) ilk kod parçacığıdır . Bu, bu yaklaşımın veya tek bir komutun "hesaplama süresinden ve hafızadan tasarruf edip etmeyeceği" sorusuna cevap vermez.
BACON

1

İst test etmedi, ancak bu umut verici görünüyor:

Temel akış segmenter

Açıkçası, AVI'yi aynı boyuttaki bölümlere ayırmaktır, bu da bu parçaların kaliteyi kaybetmediği veya hafızayı artırmadığı veya yeniden hesaplanması gerektiği anlamına gelir.

Ayrıca codec kopyasını kullanır - bu, çok büyük akışları işleyebileceği anlamına mı geliyor? Bu benim sorunum olduğu için, avi'mi parçalamak istiyorum, böylece distorsiyondan kurtulmak için bir filtre kullanabilirim. Ama bir avi saatlerce çalışır.


-1

İşte videoyu bölmenin mükemmel bir yolu. Bunu daha önce yaptım ve benim için iyi çalışıyor.

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

Lütfen bunu takip edin ve mükemmel çalışacağından eminim.


Neden videoyu bölmenin "mükemmel yolu" bu? Sorudaki komut satırı gibi, geçersiniz ve -iardından -ssve gelir -t. Soru, aynı girdi dosyasından birden çok segmenti verimli bir şekilde nasıl çıkaracağınızla ilgilidir, oysa siz yalnızca tek bir segmenti çıkarıyorsunuz. Bunun soruyu nasıl yanıtladığını anlamıyorum.
BACON

-2

basit bir yol, publitio url tabanlı api ile trim seçeneğini kullanmaktır .

Videonuzu yükledikten sonra, url'de (so_2, eo_2) başlangıç ​​ofsetini ve bitiş uzaklığını şu şekilde ayarlayın:

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

bu, 2. saniyeden ve 2 saniyeden başlayarak anında yeni videolar oluşturacaktır. Videoları istediğiniz gibi bölebilirsiniz.


Soru, bir girdi dosyasından birden çok segmenti çıkarmak için iki yaklaşımdan hangisinin daha verimli olduğunu soruyor ffmpeg. Gerçekten çok hızlı bir internet bağlantınız olmadığı sürece, videonun tamamını bir bulut hizmetine yüklemek ve ardından sonuçları indirmek zorunda kalmanın işlem süresini önemli ölçüde artıracağını düşünüyorum. Öyle olsa bile, bu yine yaklaşım hangi soruya cevap vermez ileffmpeg daha verimlidir.
BACON
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.