Bagaimana saya bisa memasukkan video ke ukuran tertentu, tetapi jangan meningkatkannya dengan FFmpeg?

13

Saya perlu memasukkan video ke 640x360 (maksimum yang dapat ditangani oleh pemutar ponsel saya), selain juga menjaga rasio aspek , tetapi saya juga ingin video tidak berubah jika lebih kecil dari 640x360 (tidak ada gunanya meningkatkan skala setelah semua).

Apakah ada cara untuk mendapatkan perilaku ini menggunakan command line ffmpeg?

sashoalm
sumber
Saya tidak berpikir ini bisa dilakukan hanya dalam ffmpeg, tetapi jika Anda mau skrip itu, pasti bisa dilakukan.
evilsoup
Saya sudah menuliskannya, tetapi saya ingin membersihkan kode saya kalau-kalau itu tidak diperlukan.
sashoalm
Mungkin saja dengan filter skala yang menggunakan fungsi seperti min(…)tetapi yang paling mudah dengan skrip sederhana yang mem-parsing dimensi. Lihat perintah saya di sini untuk contoh tentang apa yang dapat dilakukan: superuser.com/questions/547296/…
slhck

Jawaban:

9

Dengan versi ffmpeg yang lebih baru, Anda dapat menggunakan opsi scalefilter force_original_aspect_ratio. Misalnya, agar sesuai dengan video menjadi 1280 × 720, tanpa upscaling (lihat posting ini untuk info lebih lanjut):

ffmpeg -i input.mp4 -filter:v "scale='min(1280,iw)':min'(720,ih)':force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2" output.mp4

Di sini, scalefilter menskala hingga 1280 × 720 jika input video lebih besar dari itu. Jika lebih kecil, itu tidak akan ditingkatkan. The padfilter diperlukan untuk membawa video output ke 1280 × 720, dalam hal rasio aspek atau ukuran berbeda dari ukuran target.


Dengan versi ffmpeg yang lebih lama, ada solusi yang agak kabur. Pertama, tentukan lebar, tinggi, dan rasio aspek dari output Anda. Ini akan menyelamatkan kita dari mengetik.

width=640; height=360
aspect=$( bc <<< "scale=3; $width / $height") # <= floating point division

Sekarang, mari kita terapkan perintah filter super kompleks yang ditulis Jim Worrall :

ffmpeg -i input.mp4 -vf "scale = min(1\,gt(iw\,$width)+gt(ih\,$height)) * (gte(a\,$aspect)*$width + \
lt(a\,$aspect)*(($height*iw)/ih)) + not(min(1\,gt(iw\,$width)+gt(ih\,$height)))*iw : \
min(1\,gt(iw\,$width)+gt(ih\,$height)) * (lte(a\,$aspect)*$height + \
gt(a\,$aspect)*(($width*ih)/iw)) + not(min(1\,gt(iw\,$width)+gt(ih\,$height)))*ih" \
output.mp4

Saya tidak akan menjelaskan apa yang dilakukan semua ini, tetapi pada dasarnya Anda dapat memberi makan video apa pun, dan itu hanya akan turun, bukan kelas atas. Jika Anda siap, Anda dapat membedah filter ke dalam ekspresi individualnya. Dimungkinkan untuk mempersingkat ini, tetapi berfungsi seperti itu juga.

slhck
sumber
1
1 tetapi itu adalah perintah yang benar-benar mengerikan: P
evilsoup
Saya tau? Saya menghabiskan sepuluh menit mencoba memecahnya menjadi bagian-bagian logis dan kemudian memasukkan beberapa nilai tetapi saya menyerah. Ini agak tua dan mungkin mungkin untuk menulisnya jauh lebih ringkas daripada ini.
slhck
13

Versi yang lebih mudah dibaca dapat terlihat seperti berikut:

-filter_complex "scale=iw*min(1\,min(640/iw\,360/ih)):-1"

640 / iw adalah faktor penskalaan horizontal dan 360 / ih adalah faktor penskalaan vertikal

Anda ingin memasangkan gambar berskala di dalam kotak keluaran dan menjaga rasio aspek (penyimpanan). Anda melakukan ini dengan memilih faktor penskalaan terkecil dengan fungsi minimum: min (640 / iw, 360 / ih)

Anda ingin mencegah peningkatan (mis. Faktor penskalaan> 1.0) sehingga Anda menambahkan fungsi minimum lainnya: min (1, min (640 / iw, 360 / ih))

Langkah selanjutnya adalah menghitung resolusi keluaran dengan mengalikan faktor penskalaan dengan lebar-masukan dan tinggi-masukan:
lebar-keluaran = iw * min (1, min (640 / iw, 360 / ih))
output-height = ih * mnt (1, mnt (640 / iw, 360 / ih))

Langkah terakhir adalah membuat perintah filter. Tidak perlu menentukan tinggi output, Anda dapat menentukan -1 dan ffmpeg akan menjaga rasio aspek dengan menerapkan faktor penskalaan yang sama dengan lebar.

immerzl
sumber
A + Berfungsi di luar kotak. Solusi jawaban yang dipilih tidak mempertahankan rasio aspek. Itu meremas frame.
287352
5

Saya memiliki masalah yang sama juga, tetapi diselesaikan dengan memasang video dalam bujur sangkar 640x640 (karena video vertikal dibuat dengan smartphone).

Jadi dengan menggunakan logika immerzi dan beberapa penelitian saya berakhir dengan ini:

-vf "scale=iw*min(1\,if(gt(iw\,ih)\,640/iw\,(640*sar)/ih)):(floor((ow/dar)/2))*2"

bagian terakhir adalah untuk memiliki ketinggian yang dapat dibagi 2 yang dibutuhkan oleh banyak encoders.

Shebuka
sumber