Chuyển đổi video thành kích thước màn hình cố định bằng cách cắt và thay đổi kích thước


22

Tôi đã cố gắng tự mình tìm ra điều này, nhưng vô số lựa chọn chỉ gây khó khăn cho tôi.

Tôi muốn sử dụng lý tưởng ffmpeghoặc mencoder(hoặc một cái gì đó khác, nhưng hai cái tôi biết tôi đang làm việc) để chuyển đổi bất kỳ video đến thành kích thước màn hình cố định.

Nếu video rộng hơn hoặc quá ngắn đối với video, thì hãy cắt giữa video. Nếu đó không phải là kích thước phù hợp, thay đổi kích thước lên hoặc xuống để làm cho nó chính xác kích thước màn hình cố định.

Điều cuối cùng chính xác tôi cần là 720x480 trong AVI XVid với bản nhạc MP3.

Tôi đã tìm thấy rất nhiều trang cho thấy cách thay đổi kích thước thành độ phân giải tối đa, nhưng tôi cần video phải chính xác với độ phân giải đó (với các phần bổ sung bị cắt, không có thanh màu đen).

Bất cứ ai có thể cho tôi biết dòng lệnh để chạy - hoặc ít nhất là giúp tôi một số / hầu hết các cách đó? Nếu nó cần nhiều dòng lệnh (chạy X để có độ phân giải, hãy thực hiện phép tính này và sau đó chạy Y với đầu ra của phép tính đó) Tôi có thể viết kịch bản đó.


Rõ ràng thiết bị video hoạt động với Mpeg4 cũng như XVid AVI, nếu điều đó dễ dàng hơn / tốt hơn.
Andy Jeffries

Câu trả lời:


19

Tôi không phải là bậc thầy về ffmpeg, nhưng điều này sẽ tạo nên mánh khóe.

Trước hết, bạn có thể nhận được kích thước của video đầu vào như thế này:

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

Với một ffmpeg hợp lý gần đây, bạn có thể thay đổi kích thước video của mình bằng các tùy chọn sau:

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

Bạn có thể đặt chiều rộng hoặc chiều cao thành -1để cho phép ffmpegthay đổi kích thước video giữ tỷ lệ khung hình. Trên thực tế, -2là một lựa chọn tốt hơn vì giá trị tính toán nên thậm chí. Vì vậy, bạn có thể gõ:

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

Khi bạn nhận được video, nó có thể lớn hơn mong đợi 720x480vì bạn để ffmpegtính chiều cao, vì vậy bạn sẽ phải cắt nó. Điều này có thể được thực hiện như thế này:

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

Cuối cùng, bạn có thể viết một tập lệnh như thế này (có thể dễ dàng tối ưu hóa, nhưng tôi giữ nó đơn giản cho mức độ dễ đọc):

#!/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}

Tôi có cảm giác buồn cười rằng nó đã bỏ lỡ một kịch bản, nhưng tôi đã thử nó với vô số tệp video và nó dường như cắt chính xác và thay đổi kích thước video thành kích thước chính xác tuyệt đối - hoàn thành tốt!
Andy Jeffries

có vẻ như có một số sai với quyết định CROP_SIDE.
Kinh

`# Lấy tỷ lệ giữa kích thước thực tế và kích thước mong muốn 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}' # Hãy lấy phần ngắn hơn, do đó, video sẽ có kích thước lớn nhất bằng kích thước mong muốn và cắt phần dài hơn: crop_side = 'n' if [$ {w_rate} -gt $ {h_rate}]; sau đó scale = "- 2: $ {out_height}" crop_side = 'w' other scale = "$ {out_creen}: - 2" crop_side = 'h' fi `
Kinh

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

Thay thế "input.file" bằng tên của tệp đầu vào của bạn.


Đây phải là câu trả lời hàng đầu vì nó không yêu cầu một cuộc gọi đến ffprobe. Lưu ý các dấu phẩy dấu gạch chéo ngược trong lệnh. Bạn sẽ cần thoát khỏi dấu gạch chéo ngược nếu bạn đang đặt lệnh trong chuỗi C / JavaScript / PHP.
cleong

Hay đấy, Brian. Phần bộ lọc video cũng chính xác là những gì tôi cần. (tức là để chuyển đổi video 4: 3 cũ thành 16: 9)!
Dave

1
Thiên tài! Tất cả được thực hiện trong một.
Soli

2
Sạch sẽ hơn nhiều mà kịch bản ở trên. Lưu ý nếu bạn không muốn XVID / MP3, bạn chỉ có thể thay đổi các thẻ sau dấu ngoặc kép thứ hai thành một cái gì đó như-c:a copy scaled_result.mp4
Nick

7

Nếu bạn muốn cắt và chia tỷ lệ trong một lần, bạn có thể tạo một bộ lọc theo tỷ lệ cắt theo tỷ lệ như sau:

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

Đầu tiên ở trên cắt một video thành chân dung 16: 9, sau đó chia tỷ lệ thành 400px cao x chiều rộng (số chẵn) thích hợp.


1

Tôi mới sử dụng ffmpeg nhưng giờ đây đã có một trình chuyển đổi nhỏ xinh xắn trong VB.NET, tạo các phim thô có định dạng đầu ra khác nhau để sử dụng trong các thiết bị nhỏ có quyền truy cập thẻ SD nhưng không đủ năng lượng để giải mã video phức tạp.

Do cách thức hoạt động khi thay đổi kích thước và cắt xén, tôi phải mã hóa thủ công và xây dựng các tham số. Về cơ bản tôi cần biết chiều rộng và chiều cao kết quả.

Tôi có 2 hộp kiểm cho các tùy chọn: -

Giữ nguyên tỷ lệ khung hình (X) Điền vào tất cả các pixel (X)

Chỉ cần 4 biến là đầu vào (1) Chiều rộng video gốc, (2) Chiều cao video gốc, (3) Chiều rộng thiết bị, (4) Chiều cao thiết bị.

Mặc dù đối với VB.NET có thể được điều chỉnh khá dễ dàng đối với mọi ngôn ngữ.

    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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.