Büyük .mov video dosyalarını siyah karelerdeki daha küçük dosyalara otomatik olarak böler (sahne değişiklikleri)?


11

Tape_01.mov, tape_02.mov, ..., tape_65.mov adlı 65 .mov video dosyam var. Her biri yaklaşık 2,5 saat uzunluğundadır ve birçok gigabayt alır. Bunlar VHS kasetlerin (ailemin "ev filmleri") dijital kopyalarıdır.

Her 2,5 saatlik .mov video dosyası birçok "bölüm" içerir (bazen sahne siyah bir ekranın solmasına neden olur ve ardından yeni bir sahne kaybolur).

Ana hedefim 65 büyük dosyanın bölümlere göre daha küçük dosyalara bölünmesini sağlamak. Bunun "sahneler" arasındaki siyah karelerin algılanmasıyla otomatik olarak yapılmasını istiyorum.

65 orijinal dosya adını aktarmak ve sonuçta elde edilen parçaları tape_01-ch_01.mov, tape_01-ch_02.mov, tape_01-ch_03.mov, ffmpeg (veya herhangi bir şey) kullanabilir miyim? vb? Ve ben bunu yapmak istiyorum olmadan yeniden kodlama (Ben basit kayıpsız dilim olmak istiyorum).

Bunu nasıl yapabilirim?

İşte istediğim adımlar:

  1. Mp4 dosyaları (tape_01.mp4, tape_02.mp4, ..., tape_65.mp4 olarak adlandırılır) olarak dışa aktarmak için .mov dosyaları (tape_01.mov, tape_02.mov, ..., tape_65.mov adlı) bir klasör üzerinden yineleyin . Sıkıştırma ayarlarının bu adım için kolayca yapılandırılmasını istiyorum. Orijinal .mov dosyaları, .mp4 dosyaları oluşturulduktan sonra da var olmalıdır.
  2. Mp4 dosyaları üzerinde yineleme: her mp4 dosyası için, "sahneler" arasındaki siyah segmentlerin başlangıç ​​zamanını ve süresini belirten bir metin dosyası oluşturun. Her mp4'te bu siyah sahne sonlarından 0 veya daha fazlası olabilir. Başlangıç ​​zamanı ve süresi saniyenin bir kısmına kadar kesin olmalıdır. SS: DD: SS biçimi yeterince kesin değil.
  3. Daha sonra sahne değişikliklerini (siyah segmentler) doğru bir şekilde tanımlayıp tanımlamadıklarını görmek için bu metin dosyalarını manuel olarak iki kez kontrol edebilirim. İstersem zamanlamaları ayarlayabilirim.
  4. Başka bir komut dosyası her mp4 dosyasını ve onun txt dosyasını okuyacak ve (süper hızlı ve kayıpsız bir şekilde) mp4'ü metin dosyasının satırlarına göre gerektiği kadar parçaya ayıracaktır (zamanlamalar burada belirtilmiştir). Bölmeler her siyah segmentin ortasında gerçekleşmelidir. Burada, karartma-siyah sahne değişikliklerine sahip örnek bir mp4 dosyası (gizlilik amacıyla kaldırılmış). Daha küçük mp4 dosyaları oluşturulurken orijinal mp4 dosyalarına dokunulmamalıdır. Daha küçük mp4 dosyaları, tape_01_001.mp4, tape_01_002.mp4, tape_01_003.mp4, vb. Adlandırma şemasına sahip olmalıdır.
  5. Bonus! Başka bir komut dosyası daha sonra küçük mp4 dosyaları üzerinde yineleme ve bu kişi için çalışıyor gibi ekran görüntüleri bir mozaik olan her biri için bir .png görüntü oluşturmak harika olurdu: FFmpeg kullanarak bir Video için anlamlı küçük resimler

Bu komut dosyalarının Mac, Ubuntu ve Windows Git Bash'te çalıştırabileceğim kabuk komut dosyaları olmasını istiyorum.

Yanıtlar:


11

Uzun videoları siyah sahnelerle daha küçük bölümlere ayırmak için iki PowerShell betiği.

Bunları Detect_black.ps1 ve Cut_black.ps1 olarak kaydedin. İndir Windows için ffmpeg ve komut dizisini seçeneği bölümünün altındaki FFMPEG.exe yolunu ve video klasörünü söyle.

resim açıklamasını buraya girin

Her iki komut dosyası da mevcut video dosyalarına dokunmaz, dokunulmaz.
Ancak, giriş videolarınızın olduğu yerde birkaç yeni dosya alacaksınız

  • Her iki kullanılan ffmpeg komutu için konsol çıkışı ile video başına bir günlük dosyası
  • Manuel ince ayar için tüm video sahnelerini içeren video başına bir CSV dosyası
  • Daha önce tespit edilen siyah sahneye bağlı olarak birkaç yeni video

resim açıklamasını buraya girin


Çalıştırılacak ilk komut dosyası: Detect_black.ps1

 ### Options __________________________________________________________________________________________________________
$ffmpeg = ".\ffmpeg.exe"            # Set path to your ffmpeg.exe; Build Version: git-45581ed (2014-02-16)
$folder = ".\Videos\*"              # Set path to your video folder; '\*' must be appended
$filter = @("*.mov","*.mp4")        # Set which file extensions should be processed
$dur = 4                            # Set the minimum detected black duration (in seconds)
$pic = 0.98                         # Set the threshold for considering a picture as "black" (in percent)
$pix = 0.15                         # Set the threshold for considering a pixel "black" (in luminance)

### Main Program ______________________________________________________________________________________________________

foreach ($video in dir $folder -include $filter -exclude "*_???.*" -r){

  ### Set path to logfile
  $logfile = "$($video.FullName)_ffmpeg.log"

  ### analyse each video with ffmpeg and search for black scenes
  & $ffmpeg -i $video -vf blackdetect=d=`"$dur`":pic_th=`"$pic`":pix_th=`"$pix`" -an -f null - 2> $logfile

  ### Use regex to extract timings from logfile
  $report = @()
  Select-String 'black_start:.*black_end:' $logfile | % { 
    $black          = "" | Select  start, end, cut

    # extract start time of black scene
    $start_s     = $_.line -match '(?<=black_start:)\S*(?= black_end:)'    | % {$matches[0]}
    $start_ts    = [timespan]::fromseconds($start_s)
    $black.start = "{0:HH:mm:ss.fff}" -f ([datetime]$start_ts.Ticks)

    # extract duration of black scene
    $end_s       = $_.line -match '(?<=black_end:)\S*(?= black_duration:)' | % {$matches[0]}
    $end_ts      = [timespan]::fromseconds($end_s)
    $black.end   = "{0:HH:mm:ss.fff}" -f ([datetime]$end_ts.Ticks)    

    # calculate cut point: black start time + black duration / 2
    $cut_s       = ([double]$start_s + [double]$end_s) / 2
    $cut_ts      = [timespan]::fromseconds($cut_s)
    $black.cut   = "{0:HH:mm:ss.fff}" -f ([datetime]$cut_ts.Ticks)

    $report += $black
  }

  ### Write start time, duration and the cut point for each black scene to a seperate CSV
  $report | Export-Csv -path "$($video.FullName)_cutpoints.csv" –NoTypeInformation
}

O nasıl çalışır

İlk komut dosyası, belirli video uzantılarıyla eşleşen ve kalıpla eşleşmeyen tüm video dosyaları üzerinden yinelenir *_???.*, çünkü yeni video bölümleri adlandırılmıştır <filename>_###.<ext>ve bunları hariç tutmak istiyoruz.

Tüm siyah sahneleri arar ve başlangıç ​​zaman damgasını ve siyah sahne süresini adlı yeni bir CSV dosyasına yazar <video_name>_cutpoints.txt

Gösterildiği gibi, aynı zamanda kesim noktaları hesaplar: cutpoint = black_start + black_duration / 2. Daha sonra video bu zaman damgalarında bölümlere ayrılır.

Örnek videonuz için cutpoints.txt dosyası şunu gösterir:

start          end            cut
00:03:56.908   00:04:02.247   00:03:59.578
00:08:02.525   00:08:10.233   00:08:06.379

Bir koşudan sonra, istenirse kesme noktalarını elle değiştirebilirsiniz. Komut dosyasını tekrar çalıştırırsanız, tüm eski içeriğin üzerine yazılır. Elle düzenlerken dikkatli olun ve çalışmanızı başka bir yere kaydedin.

Örnek video için siyah sahneleri tespit etmek için ffmpeg komutu

$ffmpeg -i "Tape_10_3b.mp4" -vf blackdetect=d=4:pic_th=0.98:pix_th=0.15 -an -f null

Komut dosyasının seçenek bölümünde düzenlenebilir 3 önemli sayı vardır

  • d=4 sadece 4 saniyeden uzun siyah sahnelerin algılandığı anlamına gelir
  • pic_th=0.98 bir resmi "siyah" olarak kabul etme eşiğidir (yüzde olarak)
  • pix=0.15(piksel cinsinden) bir pikseli "siyah" olarak kabul etme eşiğini ayarlar. Eski VHS videolarınız olduğundan, videolarınızda tamamen siyah sahneler yok. Varsayılan değer 10 çalışmaz ve eşiği biraz artırmak zorunda kaldım

Bir şeyler ters giderse, çağrılan ilgili günlük dosyasını kontrol edin <video_name>__ffmpeg.log. Aşağıdaki satırlar eksikse, tüm siyah sahneleri algılayana kadar yukarıda belirtilen sayıları artırın:

[blackdetect @ 0286ec80]
 black_start:236.908 black_end:242.247 black_duration:5.33877



Çalıştırılacak ikinci komut dosyası: cut_black.ps1

### Options __________________________________________________________________________________________________________
$ffmpeg = ".\ffmpeg.exe"            # Set path to your ffmpeg.exe; Build Version: git-45581ed (2014-02-16)
$folder = ".\Videos\*"              # Set path to your video folder; '\*' must be appended
$filter = @("*.mov","*.mp4")        # Set which file extensions should be processed

### Main Program ______________________________________________________________________________________________________

foreach ($video in dir $folder -include $filter -exclude "*_???.*" -r){

  ### Set path to logfile
  $logfile = "$($video.FullName)_ffmpeg.log"

  ### Read in all cutpoints from *_cutpoints.csv; concat to string e.g "00:03:23.014,00:06:32.289,..."  
  $cuts = ( Import-Csv "$($video.FullName)_cutpoints.csv" | % {$_.cut} ) -join ","

  ### put together the correct new name, "%03d" is a generic number placeholder for ffmpeg
  $output = $video.directory.Fullname + "\" + $video.basename + "_%03d" + $video.extension

  ### use ffmpeg to split current video in parts according to their cut points
  & $ffmpeg -i $video -f segment -segment_times $cuts -c copy -map 0 $output 2> $logfile        
}

O nasıl çalışır

İkinci komut dosyası, tüm komut dosyalarında olduğu gibi, ilk komut dosyasında olduğu gibi yinelenir. Bir videonun karşılık gelen kesim zaman damgalarını yalnızca okur cutpoints.txt.

Daha sonra, bölüm dosyaları için uygun bir dosya adı oluşturur ve ffmpeg'e videoyu segmentlere ayırmasını söyler. Şu anda videolar yeniden kodlanmadan dilimleniyor (süper hızlı ve kayıpsız). Bu nedenle, kesme noktası zaman damgalarında 1-2 saniye hatalı olabilir, çünkü ffmpeg yalnızca key_frames'de kesebilir. Sadece kopyaladığımız ve yeniden kodlamadığımız için, key_frames'i kendi başımıza ekleyemiyoruz.

Örnek video için komut

$ffmpeg -i "Tape_10_3b.mp4" -f segment -segment_times "00:03:59.578,00:08:06.379" -c copy -map 0 "Tape_10_3b_(%03d).mp4"

Bir şeyler ters giderse, ilgili ffmpeg.log dosyasına bir göz atın



Referanslar

  • Windows için FFmpeg indir
  • Segment dokümantasyonu: segment_times ve segment_frames seçeneklerdir



Yapmak

  • Kesim noktası dosyası olarak CSV biçiminin bir metin dosyasından daha iyi olup olmadığını OP'ye sorun, böylece bunları Excel ile biraz daha kolay düzenleyebilirsiniz
    »
  • Zaman damgalarını yalnızca saniyeler yerine [ss]: [mm]: [ss], [milisaniye] olarak biçimlendirmenin bir yolunu uygulayın
    »Uygulandı
  • Her bölüm için mozaik png dosyaları oluşturmak için bir ffmpeg komutu uygulayın
    »
  • Eğer ayrıntılı -c copyOP'ın senaryo için yeterli ya da biz tamamen yeniden kodlamak için gereken bir.
    Görünüşe göre Ryan zaten üzerinde .

Ne kadar kapsamlı bir cevap! Bunu takdir ediyorum! Ne yazık ki, şu anda bir mac'tayım ve önce bunu Bash'e nasıl çevireceğimizi bulmamız gerekecek.
Ryan

Bunu PowerShell'de hiç çalıştıramadım. Günlük dosyaları boş kalır.
Ryan

Yardımcı olmak için ne yükleyebileceğimi göreceğim. Bizi izlemeye devam edin. İlginiz için teşekkürler!
Ryan

Soruya bir örnek mp4 ekledim. Yardımın için teşekkürler!
Ryan

Gizlilik amacıyla, gerçek kaynak MOV'u yüklemeyeceğim. Kesmek ve ses çıkarmak istiyorum (mp4 için yaptığım gibi). Bu yüzden zaten gerçek bir orijinal kaynak olmazdı. Yine de, yüklemek çok büyük olurdu. Ve sahne bölme adımı muhtemelen disk alanı amacıyla MOV dosyaları yerine mp4 dosyalarında gerçekleşmelidir. Teşekkürler!
Ryan

3

İşte bonus: Bu 3. PowerShell betiği bir mozaik küçük resim oluşturur

Her bölüm videosu için aşağıdaki örnek gibi görünen bir resim alacaksınız.

### Options __________________________________________________________________________________________________________
$ffmpeg = ".\ffmpeg.exe"       # Set path to your ffmpeg.exe; Build Version: git-45581ed (2014-02-16)
$folder = ".\Videos\*"         # Set path to your video folder; '\*' must be appended
$x = 5                         # Set how many images per x-axis
$y = 4                         # Set how many images per y-axis
$w = 384                       # Set thumbnail width in px (full image width: 384px x 5 = 1920px,)

### Main Program ______________________________________________________________________________________________________

foreach ($video in dir $folder -include "*_???.mp4" -r){

  ### get video length in frames, an ingenious method
  $log = & $ffmpeg -i $video -vcodec copy -an -f null $video 2>&1   
  $frames = $log | Select-String '(?<=frame=.*)\S+(?=.*fps=)' | % { $_.Matches } | % { $_.Value }  
  $frame = [Math]::floor($frames / ($x * $y))

  ### put together the correct new picture name
  $output = $video.directory.Fullname + "\" + $video.basename + ".jpg"

  ### use ffmpeg to create one mosaic png per video file
  ### Basic explanation for -vf options:  http://trac.ffmpeg.org/wiki/FilteringGuide
#1  & $ffmpeg -y -i $video -vf "select=not(mod(n\,`"$frame`")),scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 $output
#2  & $ffmpeg -y -i $video -vf "yadif,select=not(mod(n\,`"$frame`")),scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 $output 
    & $ffmpeg -y -i $video -vf "mpdecimate,yadif,select=not(mod(n\,`"$frame`")),scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 $output       

#4  & $ffmpeg -y -i $video -vf "select='gt(scene\,0.06)',scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 -vsync vfr $output  
#5  & $ffmpeg -y -i $video -vf "yadif,select='gt(scene\,0.06)',scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 -vsync vfr $output  
#6  & $ffmpeg -y -i $video -vf "mpdecimate,yadif,select='gt(scene\,0.06)',scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 -vsync vfr $output  

#7  & $ffmpeg -y -i $video -vf "thumbnail,scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 $output
#8  & $ffmpeg -y -i $video -vf "yadif,thumbnail,scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 $output
#9  & $ffmpeg -y -i $video -vf "mpdecimate,yadif,thumbnail,scale=`"$w`":-1,tile=`"$x`"x`"$y`"" -frames:v 1 $output
}

Ana fikir, tüm video üzerinde sürekli bir görüntü akışı elde etmektir. Bunu ffmpeg'in seçme seçeneği ile yapıyoruz .

İlk olarak, toplam kare sayısını ustaca bir yöntemle (örneğin 2000) alırız ve varsayılan küçük resim sayımımıza böleriz (örneğin 5 x 4 = 20). Bu nedenle, her 100 karede bir görüntü oluşturmak istiyoruz.2000 / 20 = 100

Küçük resim oluşturmak için ortaya çıkan ffmpeg komutu şöyle görünebilir

ffmpeg -y -i input.mp4 -vf "mpdecimate,yadif,select=not(mod(n\,100)),scale=384:-1,tile=5x4" -frames:v 1 output.png

Yukarıdaki kodda, aşağıdakilerden oluşan 9 farklı -vfkombinasyon görüyorsunuz :

  • select=not(mod(n\,XXX)) burada XXX hesaplanmış bir kare hızıdır
  • thumbnail otomatik olarak en temsili çerçeveleri seçer
  • select='gt(scene\,XXX)+ -vsync vfrburada XXX oynamak zorunda olduğunuz bir eşiktir
  • mpdecimate- Yinelenen kareleri kaldırın. Siyah sahnelere karşı iyi
  • yadif- Giriş görüntüsünün yerini değiştirin. Neden bilmiyorum, ama işe yarıyor

Sürüm 3 bence en iyi seçimdir. Diğerlerinin tümü yorumlanır, ancak yine de deneyebilirsiniz. Ben kullanarak bulanık küçük resimlerin çoğu kaldırmak başardı mpdecimate, yadifve select=not(mod(n\,XXX)). Evet!

Sizin için örnek videolar Bunları önizleme olsun

resim açıklamasını buraya girin
Büyütmek için tıklayın

resim açıklamasını buraya girin
Büyütmek için tıklayın

Bu sürümler tarafından oluşturulan tüm küçük resimleri yükledim . Tam bir karşılaştırma için onlara bir göz atın.


Çok havalı! Buna bir göz atacağım. Bugün de select='gt(scene\,0.4)'işe gitmeye çalışarak saatlerimi boşa harcadım . Ve ben de fps="fps=1/600"çalışamadım. Bu arada, superuser.com/questions/725734 hakkında bir fikrin var mı? Tüm yardımlarınız için çok teşekkürler. Ailemin tonlarca eski hatırayı keşfetmesine yardımcı olmaktan dolayı çok heyecanlıyım.
Ryan

Altta listelediğim diğer 5 kodlama varyantını denediniz mi? "Sahne" seçeneği için çalışan bir örnek ekledim. FPS filtresini unutun. Ben bulanık başparmak çoğu kaldırmak başardı :)
nixda

0

Her iki komut dosyasını da takdir edin, videoları bölmenin harika bir yolu.

Yine de, daha sonra doğru zamanı göstermeyen videolarla ilgili bazı sorunlar yaşadım ve belirli bir zamana atlayamadım. Bir çözüm, Mp4Box'ı kullanarak akışları çıkartıp daha sonra karıştırmaktı.

Benim için bir başka, daha kolay yol, bölmek için mkvmerge kullanmaktı. Bu nedenle, her iki komut dosyasının da değiştirilmesi gerekiyordu. Detect_black.ps1 için, filtre seçeneğine yalnızca "* .mkv" eklenmelidir, ancak yalnızca mp4 dosyalarıyla başlıyorsanız bu gerekli değildir.

### Options        
$mkvmerge = ".\mkvmerge.exe"        # Set path to mkvmerge.exe
$folder = ".\*"                     # Set path to your video folder; '\*' must be appended
$filter = @("*.mov", "*.mp4", "*.mkv")        # Set which file extensions should be processed

### Main Program 
foreach ($video in dir $folder -include $filter -exclude "*_???.*" -r){

  ### Set path to logfile
  $logfile = "$($video.FullName)_ffmpeg.log"

  ### Read in all cutpoints from *_cutpoints.csv; concat to string e.g "00:03:23.014,00:06:32.289,..."  
  $cuts = ( Import-Csv "$($video.FullName)_cutpoints.csv" | % {$_.cut} ) -join ","

  ### put together the correct new name, "%03d" is a generic number placeholder for mkvmerge
  $output = $video.directory.Fullname + "\" + $video.basename + "-%03d" + ".mkv"

  ### use mkvmerge to split current video in parts according to their cut points and convert to mkv
  & $mkvmerge -o $output --split timecodes:$cuts $video
}

İşlev aynı, ancak şu ana kadar video sürelerinde sorun yok. İlham için teşekkürler.


-2

Umarım yanılıyorum, ama ne istediğini düşünmüyorum. Videoyu yeniden kodlarken mümkün olabilir, ancak "basit kayıpsız dilim" olarak hiçbir şekilde bilmiyorum.

Birçok video düzenleme programı, videolarınızı siyah karelere ayırabilecek bir otomatik analiz özelliğine veya eşdeğer bir şeye sahip olacaktır, ancak bu videonun yeniden kodlanmasını gerektirir.

İyi şanslar!


Kesinlikle mümkün. Videoyu kayıpsız bir şekilde sorunsuz bir şekilde dilimleyebilirsiniz (örneğin, ffmpeg'deki segment muxer ile , videoyu keserken ffmpeg wiki'ye bakın ). Herhangi bir iyi video düzenleme programı bunu yapabilmelidir. Tek sorun sahne değişikliklerini tespit etmektir.
slhck

1
Aslında yapamazsınız. En büyük problemler anahtar kareler olabilir. Düzenleme araçlarında bile oynatılırken düzgün bir şekilde oluşturulabilmesi için tüm kliplerin bir ana kare ile başlaması gerekir. Siyah kareler anahtar karelerle başlamazsa, kayıpsız kesimler kullanılırken uyumsuzluk olacaktır.
JasonXA
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.