แปลงวิดีโอเป็นขนาดหน้าจอคงที่โดยการครอบตัดและปรับขนาด


22

ฉันพยายามคิดออกเอง แต่ตัวเลือกมากมายทำให้ฉันงุนงง

ฉันต้องการใช้อย่างใดอย่างหนึ่งffmpegหรือmencoder(หรืออย่างอื่น แต่ทั้งสองฉันรู้ว่าฉันกำลังทำงาน) เพื่อแปลงวิดีโอที่เข้ามาเป็นขนาดหน้าจอคงที่

หากวิดีโอนั้นกว้างหรือสั้นเกินไปก็ให้ทำการครอบตัดวิดีโอไปที่กึ่งกลาง หากไม่ใช่ขนาดที่เหมาะสมให้ปรับขนาดขึ้นหรือลงเพื่อทำให้ขนาดหน้าจอคงที่

สิ่งสุดท้ายที่แน่นอนที่ฉันต้องการคือ 720x480 ใน XVid AVI พร้อมแทร็กเสียง MP3

ฉันพบหน้าเว็บจำนวนมากที่แสดงวิธีปรับขนาดให้เป็นความละเอียดสูงสุด แต่ฉันต้องการวิดีโอเพื่อให้ได้ความละเอียดนั้นอย่างแน่นอน

ทุกคนสามารถบอกบรรทัดคำสั่งให้เรียกใช้ - หรืออย่างน้อยก็ช่วยให้ฉัน / ส่วนใหญ่ของวิธีการที่นั่น? หากจำเป็นต้องมีหลายบรรทัดคำสั่ง (เรียกใช้ X เพื่อรับความละเอียดทำคำนวณนี้แล้วเรียกใช้ Y กับผลลัพธ์ของการคำนวณนั้น) ฉันสามารถสคริปต์ที่


เห็นได้ชัดว่าอุปกรณ์วิดีโอใช้งานได้กับ Mpeg4 เช่นเดียวกับ XVid AVI ถ้ามันง่ายกว่า / ดีกว่า
Andy Jeffries

คำตอบ:


19

ฉันไม่ใช่กูรู ffmpeg แต่สิ่งนี้ควรทำเคล็ดลับ

ก่อนอื่นคุณจะได้ขนาดวิดีโออินพุตดังนี้:

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

ด้วย ffmpeg ที่ผ่านมาอย่างสมเหตุสมผลคุณสามารถปรับขนาดวิดีโอของคุณด้วยตัวเลือกเหล่านี้:

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

คุณสามารถตั้งค่าความกว้างหรือความสูงเป็น-1เพื่อffmpegปรับขนาดวิดีโอให้คงอัตราส่วนไว้ ที่จริงแล้ว-2เป็นตัวเลือกที่ดีกว่าเนื่องจากมูลค่าที่คำนวณได้ควรเท่ากัน ดังนั้นคุณสามารถพิมพ์:

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

เมื่อคุณได้รับวิดีโอมันอาจจะใหญ่กว่าที่คาดไว้720x480เนื่องจากคุณffmpegคำนวณความสูงดังนั้นคุณจะต้องครอบตัดมัน สิ่งนี้สามารถทำได้ดังนี้:

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

ในที่สุดคุณสามารถเขียนสคริปต์เช่นนี้ (สามารถเพิ่มประสิทธิภาพได้อย่างง่ายดาย แต่ฉันทำให้มันง่ายสำหรับความชัดเจน):

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

ฉันมีความรู้สึกตลก ๆ ที่มันจะพลาดสถานการณ์ แต่ฉันได้ลองกับไฟล์วิดีโอมากมายและดูเหมือนว่าจะครอบตัดและปรับขนาดวิดีโอให้มีขนาดที่ถูกต้องสมบูรณ์ - ทำได้ดีมาก!
Andy Jeffries

ดูเหมือนว่ามีบางอย่างผิดปกติกับการตัดสินใจของ CROP_SIDE
พระสูตร

`# รับอัตราระหว่างขนาดจริงและขนาดที่ต้องการ 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}' # ลองเลือกด้านที่สั้นกว่าดังนั้นวิดีโอจะมีขนาดใหญ่กว่าขนาดที่ต้องการอย่างน้อย # และครอบตัดด้านที่ยาวกว่า: crop_side = 'n' ถ้า [$ {w_rate} -gt $ {h_rate}]; ดังนั้น scale = "- 2: $ {out_height}" crop_side = 'w' else scale = "$ {out_width}: - 2" crop_side = 'h' fi `
พระสูตร

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

แทนที่ "input.file" ด้วยชื่อไฟล์อินพุตของคุณ


นี่ควรเป็นคำตอบยอดนิยมเนื่องจากไม่จำเป็นต้องมีการโทรไปที่ ffprobe หมายเหตุเครื่องหมายคอมม่า backslash ในลำดับคำสั่ง คุณจะต้องหลีกเลี่ยงแบ็กสแลชหากคุณกำลังวางคำสั่งในสตริง C / JavaScript / PHP
cleong

นิสัยดีบ ส่วนตัวกรองวิดีโอเป็นสิ่งที่ฉันต้องการเช่นกัน (เช่นการแปลงวิดีโอ 4: 3 เก่าเป็น 16: 9)!
เดฟ

1
อัจฉริยะ! ทั้งหมดทำในที่เดียว
Soli

2
ทำความสะอาดมากว่าสคริปต์ด้านบน หมายเหตุหากคุณไม่ต้องการ XVID / MP3 คุณสามารถเปลี่ยนแท็กหลังจากเครื่องหมายคำพูดที่สองเป็นอย่างเช่น-c:a copy scaled_result.mp4
Nick

7

หากคุณต้องการครอปและปรับสเกลในครั้งเดียวคุณสามารถสร้างเครือข่ายตัวกรองการครอบตัดและขนาดดังนี้:

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

ด้านบนแรกตัดวิดีโอเป็นแนวตั้ง 16: 9 จากนั้นปรับขนาดให้สูง 400px x ความกว้าง (เลขคู่) ที่เหมาะสม


1

ฉันใหม่กับ ffmpeg แต่ตอนนี้มีตัวแปลงเล็ก ๆ ที่ดีใน VB.NET ที่สร้างภาพยนตร์ดิบของรูปแบบเอาต์พุตต่าง ๆ สำหรับใช้ในอุปกรณ์ขนาดเล็กที่มีการเข้าถึงการ์ด SD แต่ไม่มีพลังงานเพียงพอที่จะถอดรหัสวิดีโอที่ซับซ้อน

เนื่องจากวิธีการทำงานเมื่อปรับขนาดและครอบตัดฉันต้องเขียนโค้ดด้วยตนเองและสร้างพารามิเตอร์ โดยทั่วไปฉันจำเป็นต้องทราบความกว้างและความสูงของผลลัพธ์

ฉันมีช่องทำเครื่องหมาย 2 ช่องสำหรับตัวเลือก: -

รักษาอัตราส่วนภาพ (X) เติมพิกเซลทั้งหมด (X)

ต้องการตัวแปร 4 ตัวเท่านั้นเป็นอินพุต (1) ความกว้างวิดีโอดั้งเดิม (2) ความสูงวิดีโอดั้งเดิม (3) ความกว้างอุปกรณ์ (4) ความสูงอุปกรณ์

แม้ว่าสำหรับ VB.NET นั้นสามารถดัดแปลงได้ง่ายสำหรับทุกภาษา

    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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.