Mengubah ukuran video dengan ffmpeg / avconv agar sesuai dengan pemutar berukuran statis

65

Saya memiliki pemutar video html 5 yang lebar 700px, tinggi 400px. Saya mencoba avconvmenggunakan ffmpeg untuk mengubah ukuran (sambil mempertahankan rasio aspek) dan memastikannya pas dengan pemain saya.

Input dapat berupa file dengan ukuran berapa pun, jadi saya perlu mengubah ukuran yang lebih besar tetapi memusatkan yang lebih kecil dengan bilah hitam. Sejauh ini saya sudah mencoba: -sdan -aspect, saya sudah melihat paddigunakan dengan -vfsaklar tetapi tidak mengerti cara kerjanya cukup untuk mendapatkan apa yang saya butuhkan.

Gambar-gambar

Ini adalah gagasan kasar tentang apa yang saya butuhkan. Saya tidak yakin apakah itu mungkin. Ini hampir seperti CSS max-width / max-height. Saya menyadari ini mungkin hanya omong kosong kata-kata tetapi jika ada orang yang mengerti apa yang saya bicarakan, saya akan menghargai bantuan, Terima kasih.

perintah avconv:

avconv -y -i control.avi -vcodec libx264 -b 2000k -bufsize 20M -acodec aac -strict experimental -ar 44100 -ab 256k bigbuck_out.mp4

Jamie Taylor
sumber
4
Saya akan menulis jawaban nanti, tetapi saya pikir saya akan menyebutkan yang berikut: Mengkode ulang video hanya untuk menambahkan pilar-atau memperbaiki kotak surat adalah ide yang buruk. Anda tidak hanya akan kehilangan kualitas dalam proses itu (atau meningkatkan ukuran file yang tidak perlu), Anda juga akan membuat tidak mungkin untuk menghilangkan bilah di kemudian hari. Idealnya, pemutar Anda hanya perlu mengatasinya dan mengubah ukuran video saat menampilkannya. Apa kasus penggunaan Anda jika saya dapat bertanya?
slhck
Kami menyimpan file asli dalam bucket S3, jadi itu tidak masalah, dan kami melakukan enkode ulang karena kami menerima cakupan besar tipe video, semua ini harus berakhir sebagai file h.264 mp4 yang cocok untuk streaming melalui sebuah browser. Jadi, Anda akan menyarankan mengubah ukuran video dan kemudian membuat html / css pillar / letterbox? Terima kasih
Jamie Taylor
1
Sebagai pemilik jawaban yang diterima, saya sarankan Anda untuk tidak menerima posting saya dan menerima jawaban LordNeckbeard sebagai gantinya, karena ini adalah yang terbaru dan lebih sederhana.
slhck
Sslhck, saya mempertimbangkannya, dengan restu Anda, saya akan membuatnya begitu.
Jamie Taylor

Jawaban:

52

Metode sederhana adalah dengan menggunakan force_original_aspect_ratioopsi dalam filter skala .

gambar asli
Gambar asli. Merupakan video rasio aspek 640x480, 4: 3.

Dalam contoh-contoh ini gambar asli akan diskalakan agar sesuai dengan keluaran rasio aspek 16: 9 sambil mempertahankan rasio aspek asli. Untuk melakukan ini, Anda dapat:

Kotak surat atau kotak surat

gambar kotak pil
Gambar kotak-kotak. Menyesuaikan input 640x480 (4: 3) ke dalam output 1280x720 (16: 9).

ffmpeg -i input -vf "scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2" output
  • Ini akan meningkatkan gambar. Jika Anda ingin menghindari peningkatan, lihat contoh di bawah ini.

  • Sebaliknya, letterboxing akan terjadi jika rasio aspek input lebih lebar daripada rasio aspek output. Misalnya, input dengan rasio aspek 2,35: 1 yang cocok dengan output 16: 9 akan menghasilkan letterboxing.

Sama seperti di atas tetapi tanpa upscaling

tidak ada peningkatan
640x480 (4: 3) input ke output 1280x720 (16: 9) tanpa upscaling.

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

Tanaman

masukkan deskripsi gambar di sini
Gambar yang dipangkas. Rasio aspek input 4: 3, rasio aspek keluaran 16: 9.

ffmpeg -i input -vf "scale=1280:720:force_original_aspect_ratio=increase,crop=1280:720" output
llogan
sumber
Dan bagi saya untuk menambahkan isian kosong?
Tiago Ferezin
@TiagoFerezin Apa itu "isian kosong"?
llogan
oh maaf, Isi dengan warna lain, bukan hitam, misalnya
Tiago Ferezin
2
@TiagoFerezin Ah, ya. Mudah untuk dilakukan. Dalam contoh yang menggunakan filter pad Anda dapat menambahkan coloropsi, seperti pad=1280:720:(ow-iw)/2:(oh-ih)/2:color=red(atau Anda dapat menggunakan heksadesimal jika Anda mau). Lihat daftar warna .
Logan
61

Inilah perintah yang akan menambahkan pillar atau letterboxing untuk lebar keluaran tetap. Ini agak lama, tetapi Anda harus menentukan padding beberapa cara.

Pertama, di shell Anda tentukan lebar dan tinggi keluaran:

width=700
height=400

Kemudian jalankan perintah:

ffmpeg -i in.mp4 -filter:v "scale=iw*min($width/iw\,$height/ih):ih*min($width/iw\,$height/ih), pad=$width:$height:($width-iw*min($width/iw\,$height/ih))/2:($height-ih*min($width/iw\,$height/ih))/2" out.mp4

Ini dilepaskan ke hal-hal mendasar yang diperlukan untuk mengubah ukuran dan membalut — tambahkan opsi video dan audio lainnya sesuai keinginan Anda. Perhatikan bahwa angka untuk widthdan heightharus dapat dibagi 2 agar dapat berfungsi untuk sebagian besar codec.

Inilah penjelasan tentang apa yang terjadi:

  • Penskalaan:
    • Pertama kita perlu mencari tahu apakah skala dengan lebar atau tinggi.
    • Untuk melakukan ini, kami membagi lebar output dengan lebar input, dan tinggi output dengan tinggi input. Ini akan memberi kita faktor skala untuk setiap dimensi.
    • Kami kemudian memeriksa mana yang lebih rendah (dengan min()) dan hanya memilih faktor itu untuk mengubah ukuran.
    • Akhirnya, kami mengalikan lebar dan tinggi input dengan faktor itu ( iw*min(…):ih*min(…)).
  • Lapisan:
    • $width:$height adalah lebar dan tinggi keluaran
    • Untuk mengetahui di mana menempatkan video yang dihasilkan, kita perlu mengurangi lebar yang diskalakan dari lebar keluaran maksimum, dan tinggi yang diskalakan dari tinggi output maksimum.
    • Lebar dan tinggi yang diskalakan adalah ekspresi dari scalefilter.
    • Kami membagi hasil offset dengan 2 untuk menambahkan batas di kedua sisi.
slhck
sumber
3
@JamieTaylor Pertimbangkan menambah -movflags +faststartcontoh slhck. Ini akan memungkinkan video Anda yang diunduh secara progresif untuk memulai pemutaran sebelum sepenuhnya diunduh, dan juga melihat Panduan Pengkodean FFmpeg dan x264 dan Panduan Pengkodean FFmpeg dan AAC untuk instruksi dan contoh pengkodean lebih lanjut.
llogan
Anda dapat mempersingkat filter pad untuk ini, saya pikir:pad=$width:$height:(ow-iw)/2:(oh-ih)/2"
jdi
1
@jdi Ini tidak akan berfungsi jika Anda downscaling, karena itu akan menghasilkan nilai negatif untuk ow-iw.
slhck
Terima kasih untuk titik awalnya! Namun, untuk mendapatkan rasio aspek yang tepat untuk video dengan rasio aspek sampel! = 1, setiap kejadian "iw" harus dikalikan dengan "sar", jadi ganti SETIAP kemunculan "iw" dengan "(sar * iw)" dalam ekspresi filter bekerja untuk saya.
schieferstapel
@slhck Hei, saya mencoba di android tapi sepertinya tidak berfungsi, bisakah Anda membantu saya dengan itu !!! ffmpeg -i input.mp4 -filter: skala v = 640 * min (700 / 640.400 / 360): 360 * min (700 / 640.400 / 360), pad = 700: 400: (700-640 * min (700 / 640.400) / 360)) / 2: (400-360 * mnt (700 / 640.400 / 360)) / 2 output.mp4
Nisarg
8

Menurut saya, Anda perlu melakukan ini dalam tiga langkah:

  1. Periksa rasio aspek input
  2. Skala video dengan DAR> 7/4 lebar-bijaksana (ubah lebar menjadi 700, dan skala tinggi untuk menjaga rasio aspek), dan skala mereka dengan DAR <7/4 tinggi-bijaksana
  3. Pad video sehingga pas di ruang 700: 400.

FFmpeg / avconv dapat melakukan penskalaan / padding dengan filter video dalam satu langkah, transcoding hanya sekali. Misalnya, untuk mengambil video 16: 9, skalakan dengan lebar, lalu hasilkan kotak surat:

ffmpeg -i input.avi -filter:v 'scale=700:-1,pad=700:400:(ow-iw)/2:(oh-ih)/2' \
-c:v libx264 -b:v 2000k -bufsize 20M -c:a aac -strict experimental -ar 44100 -b:a 256k output.mp4

... tetapi untuk langkah pertama (mendeteksi rasio aspek dan membandingkannya dengan 7: 4 yang Anda butuhkan) Anda harus menggunakan skrip sejenis.

ffprobe input.avi 2>&1 | sed -n '/Video:/s/.*DAR \([0-9]*:[0-9]*\)].*/\1/p'

... akan memberi Anda rasio aspek video, yang akan terlihat seperti '16: 9 'atau' 4: 3 '. Dalam skrip bash, saya akan menggunakan sesuatu seperti:

#!/bin/bash

##  Get the aspect ratio in the form x/y
dar=$(ffprobe test0.mp4 2>&1 | sed -n '/Video:/s/.*DAR \([0-9]*:[0:9]*\)].*/\1/p' | sed 's|:|/|')
##  use bc to do x/y*100 (bash can't handle floats)
DAR=$(bc <<< 'scale=2; $dar*100')

##  ${DAR%.00} will remove the trailing .00 left by bc
if [ ${DAR%.00} -ge 175 ]; then
    ffmpeg -i "$1" -filter:v 'scale=700:-1,pad=700:400:(ow-iw)/2:(oh-ih)/2' \
    -c:v libx264 -b:v 2000k -bufsize 20M -c:a aac -strict experimental -ar 44100 -b:a 256k "${1%.*}.mp4
else
    ffmpeg -i "$1" -filter:v 'scale=-1:400,pad=700:400:(ow-iw)/2:(oh-ih)/2' \
    -c:v libx264 -b:v 2000k -bufsize 20M -c:a aac -strict experimental -ar 44100 -b:a 256k "${1%.*}.mp4
fi

exit 0

Tentunya Anda harus menyesuaikannya dengan kebutuhan Anda.

Evilsoup
sumber
1
Namun dimungkinkan untuk melakukannya dalam satu langkah, lihat jawaban saya.
slhck
@ Slhck Sekarang lebih mudah. Lihat jawabannya dengan gitar-belanak.
Logan
@ LordNeckbeard Terima kasih! Saya baru-baru melihat opsi itu, memang membuatnya jauh lebih mudah.
slhck