มีวิธีในการคว้าภาพขนาดย่อของวิดีโอใน FFmpeg หรือไม่?
ฉันต้องการคว้าเฟรมที่อยู่ตรงกลางที่สุดเป็นวิดีโอและใช้เป็นภาพขนาดย่อ ไม่ทราบระยะเวลาของวิดีโอ
ความสามารถในการระบุขนาดของภาพขนาดย่อก็จะมีประโยชน์เช่นกัน
มีวิธีในการคว้าภาพขนาดย่อของวิดีโอใน FFmpeg หรือไม่?
ฉันต้องการคว้าเฟรมที่อยู่ตรงกลางที่สุดเป็นวิดีโอและใช้เป็นภาพขนาดย่อ ไม่ทราบระยะเวลาของวิดีโอ
ความสามารถในการระบุขนาดของภาพขนาดย่อก็จะมีประโยชน์เช่นกัน
คำตอบ:
คำสั่งหนึ่งบรรทัด:
ffmpeg -i input.mp4 -vcodec mjpeg -vframes 1 -an -f rawvideo -ss `ffmpeg -i input.mp4 2>&1 | grep Duration | awk '{print $2}' | tr -d , | awk -F ':' '{print ($3+$2*60+$1*3600)/2}'` output.jpg
คำสั่งย่อยรับช่วงเวลาทั้งหมดของอินพุตวิดีโอ
ffmpeg -i input.mp4 2>&1 | grep Duration | awk '{print $2}' | tr -d ,
และไปป์ที่ awk เพื่อคำนวณระยะเวลา / 2 แบบนี้
echo '00:01:30.000' | awk -F ':' '{print ($3+$2*60+$1*3600)/2}'
ดังนั้นให้สิ่งนี้ระหว่างวินาทีเพื่อ -ss ตัวเลือกและมันเสร็จแล้ว
หากคุณต้องการระบุขนาดให้เลือกตัวเลือก -s เช่น WxH whet W และ H เป็นค่าจำนวนเต็ม (เช่น: -s 800x600 หรือ -s svga) หรืออ่านหน้า man ffmpeg เพื่อดูตัวเลือกหรือรูปแบบอื่น ๆ ที่มีอยู่
ffmpeg
เอาท์พุทเป็นเพียงเพื่อวัตถุประสงค์ในการให้ข้อมูลเท่านั้นและไม่ได้มีไว้สำหรับการแยกดังนั้นจึงประมวลผลก็อาจได้รับการพิจารณาที่เปราะบาง ใช้ffprobe
เพื่อรับช่วงเวลาแทน ดูFFmpeg วิกิพีเดีย: เคล็ดลับ
ก่อนอื่นใช้ FFmpeg เวอร์ชันล่าสุดเสมอ
หากคุณมีสิทธิ์เข้าถึง PHP คำถามของคุณจะได้รับคำตอบที่สมบูรณ์แบบใน Stack Overflow: ใช้ FFMpeg เพื่อรับเฟรมกลางของวิดีโอ
$output = shell_exec("/usr/local/bin/ffmpeg -i {$path}");
preg_match('/Duration: ([0-9]{2}):([0-9]{2}):([^ ,])+/', $output, $matches);
$time = str_replace("Duration: ", "", $matches[0]);
$time_breakdown = explode(":", $time);
$total_seconds = round(($time_breakdown[0]*60*60) + ($time_breakdown[1]*60) + $time_breakdown[2]);
shell_exec("/usr/local/bin/ffmpeg -y -i {$path} -f mjpeg -vframes 1 -ss " . ($total_seconds / 2) . " -s {$w}x{$h} {$output_filename}";
สิ่งที่มันจะทำคือเพียงดึงระยะเวลาจากเอาต์พุตของ FFmpeg และใช้สิ่งนั้นเพื่อกำหนดไทม์โคดของเฟรมกลาง
คุณสามารถปรับให้เข้ากับเปลือกหอยอื่น ๆ ได้อย่างง่ายดายและเพียงแค่แทรกคำสั่งต่อไปนี้โดยที่เฟรมกลางอยู่ที่ประมาณ534
วินาที:
ffmpeg -y -i input.mp4 -f mjpeg -vframes 1 -ss 534 thumbnail.jpg
คุณสามารถเปลี่ยนขนาดด้วย-s 480x320
หรือคล้ายกันได้ตลอดเวลาทั้งนี้ขึ้นอยู่กับขนาดที่คุณต้องการแทรกไว้ที่ไหนสักแห่งหลังจาก-i input.mp4
ตัวเลือก
การแก้ปัญหาข้างต้นไม่ถูกต้องเล็กน้อย มันจะให้ผลลัพธ์ทันที แต่คุณไม่สามารถระบุเฟรมที่คุณต้องการได้ หากคุณทราบเฟรมที่แน่นอนที่คุณต้องการแตกแล้วให้ใช้select
ตัวกรองเช่นกับหมายเลขเฟรม12345
:
ffmpeg -i input.mp4 -filter:v select="eq(n\,12345)" -vframes 1 thumbnail.jpg
โปรดทราบว่าคำสั่งนี้อาจใช้เวลาสักครู่เนื่องจากต้องข้ามไปยังเฟรมที่ระบุก่อนจึงจะสามารถแตกออกได้
ffmpeg -y -i input.mp4 -vf "crop=(ih*4/3):ih" -f mjpeg -vframes 1 -ss 534 thumbnail.jpg
-ss
ก่อนหน้าการ-i
ค้นหาควรเร็วกว่านี้มาก
นี่คือวิธีการที่ใช้:
ffprobe
เพื่อรับระยะเวลาbc
เพื่อคำนวณครึ่งระยะเวลาffmpeg
เพื่อสร้างภาพขนาดย่อตัวอย่าง:
input=video.mp4
duration=$(ffprobe -v error -show_entries format=duration -of default=nw=1:nk=1 "$input")
ffmpeg -ss "$(echo "$duration"/2 | bc)" -i "$input" -q:v 2 -vframes 1 output.jpg
คุณสามารถแทนที่การใช้ขี้เกียจของฉันbc
ด้วยทางเลือกที่คุณชื่นชอบเช่นawk
หรือprintf
ถ้าคุณต้องการ
คุณสามารถปรับขนาด / ปรับขนาดภาพโดยการเพิ่มตัวกรองขนาดเป็นตัวเลือกในการส่งออกของคุณคำสั่งเช่นffmpeg
-vf scale=320:-1
ระยะเวลาที่ให้มาffprobe
อาจไม่แม่นยำขึ้นอยู่กับอินพุต ในกรณีที่ไม่น่าเป็นไปได้ที่คุณมีปัญหาเช่นนี้คุณจะต้องถอดรหัสอินพุตทั้งหมดเช่นด้วยffmpeg -i input -f null -
และแยกวิเคราะห์เอาต์พุตเพื่อรับค่าระยะเวลาที่ถูกต้อง
$currentVideoDuration = shell_exec("$ffmpeg -i $videoPath 2>&1 | grep Duration");
$actualDuration = substr($currentVideoDuration, 11, 12);
$arrayWithHoursMinsAndSecs = explode(":", $actualDuration);
$thisVideoDurationInSeconds = $arrayWithHoursMinsAndSecs[2] + $arrayWithHoursMinsAndSecs[1]*60 + $arrayWithHoursMinsAndSecs[0]*3600;
$halfVideoDuration = $thisVideoDurationInSeconds/2;
echo 'midpoint of this video: '. $halfVideoDuration;
echo shell_exec("$ffmpeg -i $videoPath -y -ss 00:00:$halfVideoDuration -vframes 1 thumbnail.png 2>&1");
แทนที่ $ videopath ด้วยพา ธ ไปยังวิดีโอของคุณ
วิธีง่ายๆคือ:
ffmpeg -i l1.mp4 -ss 00:00:14.435 -vframes 1 out.png
คำสั่ง bash นี้ทำงานได้เหมือนเครื่องราง:
avconv -i 'in.mpg' -vcodec mjpeg -vframes 1 -an -f rawvideo \
-s 420x300 -ss `avconv -i in.mpg 2>&1 | grep Duration \
| awk '{print $2}' | tr -d , \
| awk -F ':' '{print ($3+$2*60+$1*3600)/2}'` out.jpg
-vcodec mjpeg -an -f rawvideo
ไม่จำเป็นเมื่อเอาต์พุตของคุณเป็นเพียง.jpg
ไฟล์ ฉันอยากจะแนะนำให้ส่งออกไปยัง PNG แทนและทำการบีบอัดในภายหลัง