Konversi video ke ukuran layar tetap dengan memotong dan mengubah ukuran

22

Saya sudah mencoba memikirkannya sendiri, tetapi banyak sekali opsi yang membuat saya bingung.

Saya ingin menggunakan idealnya baik ffmpegatau mencoder(atau sesuatu yang lain, tetapi kedua saya tahu saya telah bekerja) untuk mengkonversi video yang masuk ke ukuran layar tetap.

Jika video lebih lebar atau terlalu pendek untuk itu, maka potong video tengah. Jika itu bukan ukuran yang tepat, ukurannya naik atau turun untuk membuatnya persis dengan ukuran layar tetap.

Hal terakhir yang saya butuhkan adalah 720x480 dalam AVI XVid dengan trek audio MP3.

Saya telah menemukan banyak halaman yang menunjukkan cara mengubah ukuran ke resolusi maksimum, tetapi saya membutuhkan video untuk menjadi resolusi yang tepat (dengan bagian-bagian tambahan dipotong, tidak ada bilah hitam).

Adakah yang bisa memberitahu saya baris perintah untuk menjalankan - atau setidaknya mendapatkan saya / sebagian besar jalan ke sana? Jika perlu beberapa perintah baris (jalankan X untuk mendapatkan resolusi, lakukan perhitungan ini dan kemudian jalankan Y dengan output dari perhitungan itu) Saya bisa skrip itu.

Andy Jeffries
sumber
Tampaknya perangkat video berfungsi dengan Mpeg4 dan juga AVI XVid, jika itu lebih mudah / lebih baik.
Andy Jeffries

Jawaban:

19

Saya bukan guru ffmpeg, tapi ini seharusnya bisa.

Pertama-tama, Anda bisa mendapatkan ukuran video input seperti ini:

ffprobe -v error -of flat=s=_ -select_streams v:0 -show_entries stream=height,width in.mp4

Dengan ffmpeg yang cukup baru, Anda dapat mengubah ukuran video Anda dengan opsi-opsi ini:

ffmpeg -i in.mp4 -vf scale=720:480 out.mp4

Anda dapat mengatur lebar atau tinggi -1untuk membiarkan ffmpegmengubah ukuran video menjaga rasio aspek. Sebenarnya, -2ini adalah pilihan yang lebih baik karena nilai yang dihitung harus genap. Jadi Anda bisa mengetik:

ffmpeg -i in.mp4 -vf scale=720:-2 out.mp4

Setelah Anda mendapatkan video, mungkin lebih besar dari yang diharapkan 720x480karena Anda membiarkan ffmpegmenghitung tinggi, jadi Anda harus memotongnya. Ini bisa dilakukan seperti ini:

ffmpeg -i in.mp4 -filter:v "crop=in_w:480" out.mp4

Akhirnya, Anda dapat menulis skrip seperti ini (dapat dengan mudah dioptimalkan, tetapi saya membuatnya mudah dibaca):

#!/bin/bash

FILE="/tmp/test.mp4"
TMP="/tmp/tmp.mp4"
OUT="/tmp/out.mp4"

OUT_WIDTH=720
OUT_HEIGHT=480

# Get the size of input video:
eval $(ffprobe -v error -of flat=s=_ -select_streams v:0 -show_entries stream=height,width ${FILE})
IN_WIDTH=${streams_stream_0_width}
IN_HEIGHT=${streams_stream_0_height}

# Get the difference between actual and desired size
W_DIFF=$[ ${OUT_WIDTH} - ${IN_WIDTH} ]
H_DIFF=$[ ${OUT_HEIGHT} - ${IN_HEIGHT} ]

# Let's take the shorter side, so the video will be at least as big
# as the desired size:
CROP_SIDE="n"
if [ ${W_DIFF} -lt ${H_DIFF} ] ; then
  SCALE="-2:${OUT_HEIGHT}"
  CROP_SIDE="w"
else
  SCALE="${OUT_WIDTH}:-2"
  CROP_SIDE="h"
fi

# Then perform a first resizing
ffmpeg -i ${FILE} -vf scale=${SCALE} ${TMP}

# Now get the temporary video size
eval $(ffprobe -v error -of flat=s=_ -select_streams v:0 -show_entries stream=height,width ${TMP})
IN_WIDTH=${streams_stream_0_width}
IN_HEIGHT=${streams_stream_0_height}

# Calculate how much we should crop
if [ "z${CROP_SIDE}" = "zh" ] ; then
  DIFF=$[ ${IN_HEIGHT} - ${OUT_HEIGHT} ]
  CROP="in_w:in_h-${DIFF}"
elif [ "z${CROP_SIDE}" = "zw" ] ; then
  DIFF=$[ ${IN_WIDTH} - ${OUT_WIDTH} ]
  CROP="in_w-${DIFF}:in_h"
fi

# Then crop...
ffmpeg -i ${TMP} -filter:v "crop=${CROP}" ${OUT}
apaul
sumber
Saya memiliki perasaan lucu bahwa itu akan melewatkan skenario, tetapi saya sudah mencobanya dengan banyak file video dan tampaknya memotong dengan benar dan mengubah ukuran video ke ukuran yang benar-benar benar - bagus!
Andy Jeffries
sepertinya ada yang salah dengan keputusan CROP_SIDE.
Sutra
`# Dapatkan nilai antara ukuran aktual dan yang diinginkan w_rate = echo "scale=3; ${in_width}/${out_width}*1000"| bc | awk '{printf "%d", $0}' h_rate = echo "scale=3; ${in_height}/${out_height}*1000"| bc | awk '{printf "%d", $0}' # Mari kita ambil sisi yang lebih pendek, jadi video akan setidaknya sebesar ukuran # yang diinginkan, dan pangkas sisi yang lebih panjang: crop_side = 'n' jika [$ {w_rate} -gt $ {h_rate}]; kemudian scale = "- 2: $ {out_height}" crop_side = 'w' else scale = "$ {out_width}: - 2" crop_side = 'h' fi `
Sutra
23
ffmpeg -i input.file -vf "scale=(iw*sar)*max(720/(iw*sar)\,480/ih):ih*max(720/(iw*sar)\,480/ih), crop=720:480" -c:v mpeg4 -vtag XVID -q:v 4 -c:a libmp3lame -q:a 4 output.avi

Ganti "input.file" dengan nama file input Anda.

Brian
sumber
Ini harus menjadi jawaban teratas karena tidak memerlukan panggilan ke ffprobe. Perhatikan urutan koma backslash dalam perintah. Anda harus lolos dari garis miring terbalik jika Anda menempatkan perintah dalam string C / JavaScript / PHP.
cleong
Bagus, Brian. Bagian filter video persis seperti yang saya butuhkan. (Yaitu untuk mengkonversi video 4: 3 lama ke 16: 9)!
Dave
1
jenius! semua dilakukan dalam satu.
Soli
2
Jauh lebih bersih dari script di atas. Catatan jika Anda tidak ingin XVID / MP3 Anda dapat mengubah tag setelah tanda kutip kedua menjadi sesuatu seperti-c:a copy scaled_result.mp4
Nick
7

Jika Anda ingin memotong dan menskala dalam sekali jalan, Anda bisa membuat rantai penyaring potong-kemudian-skala seperti:

ffmpeg -i SomeInput.mp4 -vf "crop=in_h*9/16:in_h,scale=-2:400" -t 4 SomeOutput.mp4

Pertama di atas memotong video ke potret 16: 9, kemudian menskala ke ketinggian 400px x lebar (nomor genap) yang sesuai.

Chris
sumber
1

Saya baru mengenal ffmpeg tetapi sekarang memiliki konverter kecil yang bagus di VB.NET yang membuat film mentah dari berbagai format output untuk digunakan pada perangkat kecil yang memiliki akses kartu SD tetapi tidak cukup daya untuk memecahkan kode video yang kompleks.

Karena cara kerjanya ketika mengubah ukuran dan memotong saya harus kode secara manual dan membangun parameter. Pada dasarnya saya perlu tahu lebar dan tinggi yang dihasilkan.

Saya punya 2 kotak centang untuk opsi: -

Pertahankan Rasio Aspek (X) Isi Semua Piksel (X)

Hanya 4 variabel yang diperlukan sebagai input (1) Lebar video asli, (2) Tinggi video asli, (3) Lebar perangkat, (4) Tinggi perangkat.

Meskipun untuk VB.NET bisa diadaptasi cukup mudah untuk bahasa apa pun.

    Dim crop As String = "" ' will build this in ffmpeg format for -s or scale and crop

    If cbAspectRatio.Checked = False Then
        m_dest_output_w = sz._w
        m_dest_output_h = sz._h

        ' scale to w * h - simple
        crop = " -s " & m_dest_output_w & ":" & m_dest_output_h
    Else
        Dim ratio As Double = CDbl(m_video_width) / CDbl(m_video_height) ' this is aspect ratio of original unsized video

        If cbFillPixels.Checked = False Then ' shrink to fit
            If sz._w * ratio <= m_video_height Then
                m_dest_output_w = sz._w
                m_dest_output_h = sz._w / ratio
            Else
                m_dest_output_h = sz._h
                m_dest_output_w = sz._h / ratio
            End If

            ' no cropping just resizing to a non-filled area that fits

            crop = " -s " & m_dest_output_w & ":" & m_dest_output_h ' no cropping needed as letterboxed

        Else ' expand / fill --- cropping needed
            If sz._w * ratio >= m_video_height Then
                m_dest_output_w = sz._w
                m_dest_output_h = sz._w * ratio

                crop = ",crop=" & sz._w & ":" & sz._h & ":0:" & Math.Abs((m_dest_output_h - sz._h)) \ 2
            Else
                m_dest_output_h = sz._h
                m_dest_output_w = sz._h * ratio

                crop = ",crop=" & sz._w & ":" & sz._h & ":" & Math.Abs((m_dest_output_w - sz._w)) \ 2 & ":0"
            End If

            crop = " -vf scale=" & m_dest_output_w & ":" & m_dest_output_h & crop

            m_dest_output_w = sz._w
            m_dest_output_h = sz._h
        End If
    End If
TheWhitde
sumber