FFMPEG-如何對視訊按時長切片與壓縮
本文介紹如何用ffmpeg開源元件按時長進行切片,舉一個例子,一個視訊網站,拿到一個時長1.5小時的電影,使用者點選播放時,常用的技術方案就是把一個完整的大檔案,轉碼後切成按固定時長的小檔案,分發到cdn上去,這樣使用者就可以實現就近下載,包括拖放等操作,這裡面有比較多的技術細節,本文只討論第一步,按時長切片。
一 獲取視訊時長
ffmpeg安裝後,直接執行ffmpeg -i 檔案就可以從內容中獲取到時長,如下圖所示,其中的Duration就是時長
wangyachangdeMacBook-Pro:ffmpeg wangyachang$ /usr/local/ffmpeg/bin/ffmpeg -i movie.mp4 ffmpeg version 3.0.2 Copyright (c) 2000-2016 the FFmpeg developers built with Apple LLVM version 7.0.2 (clang-700.1.81) configuration: --prefix=/usr/local/ffmpeg/ --disable-yasm libavutil 55. 17.103 / 55. 17.103 libavcodec 57. 24.102 / 57. 24.102 libavformat 57. 25.100 / 57. 25.100 libavdevice 57. 0.101 / 57. 0.101 libavfilter 6. 31.100 / 6. 31.100 libswscale 4. 0.100 / 4. 0.100 libswresample 2. 0.101 / 2. 0.101 Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'movie.mp4': Metadata: major_brand : isom minor_version : 1 compatible_brands: isom creation_time : 2015-11-04 06:54:54 encoder : FormatFactory : www.pcfreetime.com Duration: 00:03:25.01, start: 0.000000, bitrate: 1101 kb/s Stream #0:0(und): Video: mpeg4 (Simple Profile) (mp4v / 0x7634706D), yuv420p, 720x480 [SAR 32:27 DAR 16:9], 977 kb/s, 24 fps, 24 tbr, 24k tbn, 24 tbc (default) Metadata: creation_time : 2015-11-04 06:54:54 handler_name : video Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 122 kb/s (default) Metadata: creation_time : 2015-11-04 06:54:54 handler_name : sound
不過上面的資訊是列印到標準出錯的,用下面的命令可以取到對應資訊
wangyachangdeMacBook-Pro:ffmpeg wangyachang$ /usr/local/ffmpeg/bin/ffmpeg -i movie.mp4 2>&1 | grep Duration
Duration: 00:03:25.01, start: 0.000000, bitrate: 1101 kb/s
通過awk可以方便的取出時\分\秒。
二 切片
通過下面的命令可以實現切片。
/usr/local/ffmpeg/bin/ffmpeg -ss START -t LENGTH -i INPUTFILE -vcodec copy -acodec copy OUTFILE
/usr/local/ffmpeg/bin/ffmpeg -ss 0 -t 00:01:00 -i movie.mp4 -vcodec copy -acodec copy movie-1.mp4
/usr/local/ffmpeg/bin/ffmpeg -ss 00:01:00 -t 00:02:00 -i movie.mp4 -vcodec copy -acodec copy movie-2.mp4
/usr/local/ffmpeg/bin/ffmpeg
-ss 00:02:00 -t 00:03:00 -i movie.mp4 -vcodec copy -acodec copy movie-3.mp4
ffmpeg version 3.0.2 Copyright (c) 2000-2016 the FFmpeg developers
built with Apple LLVM version 7.0.2 (clang-700.1.81)
configuration: --prefix=/usr/local/ffmpeg/ --disable-yasm
libavutil 55. 17.103 / 55. 17.103
libavcodec 57. 24.102 / 57. 24.102
libavformat 57. 25.100 / 57. 25.100
libavdevice 57. 0.101 / 57. 0.101
libavfilter 6. 31.100 / 6. 31.100
libswscale 4. 0.100 / 4. 0.100
libswresample 2. 0.101 / 2. 0.101
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'movie.mp4':
Metadata:
major_brand : isom
minor_version : 1
compatible_brands: isom
creation_time : 2015-11-04 06:54:54
encoder : FormatFactory : www.pcfreetime.com
Duration: 00:03:25.01, start: 0.000000, bitrate: 1101 kb/s
Stream #0:0(und): Video: mpeg4 (Simple Profile) (mp4v / 0x7634706D), yuv420p, 720x480 [SAR 32:27 DAR 16:9], 977 kb/s, 24 fps, 24 tbr, 24k tbn, 24 tbc (default)
Metadata:
creation_time : 2015-11-04 06:54:54
handler_name : video
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 122 kb/s (default)
Metadata:
creation_time : 2015-11-04 06:54:54
handler_name : sound
File 'movie-1.mp4' already exists. Overwrite ? [y/N] y
Output #0, mp4, to 'movie-1.mp4':
Metadata:
major_brand : isom
minor_version : 1
compatible_brands: isom
encoder : Lavf57.25.100
Stream #0:0(und): Video: mpeg4 ( [0][0][0] / 0x0020), yuv420p, 720x480 [SAR 32:27 DAR 16:9], q=2-31, 977 kb/s, 24 fps, 24 tbr, 24k tbn, 24k tbc (default)
Metadata:
creation_time : 2015-11-04 06:54:54
handler_name : video
Stream #0:1(und): Audio: aac (LC) ([64][0][0][0] / 0x0040), 44100 Hz, stereo, 122 kb/s (default)
Metadata:
creation_time : 2015-11-04 06:54:54
handler_name : sound
Stream mapping:
Stream #0:0 -> #0:0 (copy)
Stream #0:1 -> #0:1 (copy)
Press [q] to stop, [?] for help
frame= 1440 fps=0.0 q=-1.0 Lsize= 8435kB time=00:01:00.00 bitrate=1151.7kbits/s speed=1.59e+03x
video:7480kB audio:920kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.419454%
最後,分享一個開源的指令碼,做了一些優化,十分感謝原作者
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#本指令碼使用ffmpeg分割音視訊檔案,分割過程不進行轉碼或壓縮
import subprocess
import re
import os
import math
from optparse import OptionParser
length_regexp = 'Duration: (\d{2}):(\d{2}):(\d{2})\.\d+,'
re_length = re.compile(length_regexp)
def main():
(filename, split_length, file_list) = parse_options()
if split_length <= 0:
print "Split length can't be 0"
raise SystemExit
output = subprocess.Popen("/usr/local/ffmpeg/bin/ffmpeg -i '"+filename+"' 2>&1 | grep 'Duration'",
shell = True,
stdout = subprocess.PIPE
).stdout.read()
print output
matches = re_length.search(output)
if matches:
video_length = int(matches.group(1)) * 3600 + \
int(matches.group(2)) * 60 + \
int(matches.group(3))
print "Video length in seconds: "+str(video_length)
else:
print "Can't determine video length."
raise SystemExit
split_count = int(math.ceil(video_length/float(split_length)))
if(split_count == 1):
print "Video length is less then the target split length."
raise SystemExit
print split_count, video_length, split_length
if os.path.exists(file_list):
os.remove(file_list)
fp = open(file_list, "wb")
split_cmd = "/usr/local/ffmpeg/bin/ffmpeg -i '"+filename+"' -vcodec copy "
for n in range(0, split_count):
split_str = ""
if n == 0:
split_start = 0
else:
split_start = split_length * n
output_filename = filename[:-4] + "-" + str(n) + "." + filename[-3:]
split_str += " -ss "+str(split_start)+" -t "+str(split_length) + \
" '"+output_filename+ \
"'"
print "About to run: "+split_cmd+split_str
fp.write(output_filename+"\n")
output = subprocess.Popen(split_cmd+split_str, shell = True, stdout =
subprocess.PIPE).stdout.read()
fp.close()
def parse_options():
parser = OptionParser()
parser.add_option("-f", "--file",
dest = "filename",
help = "file to split, for example sample.avi",
type = "string",
action = "store"
)
parser.add_option("-s", "--split-size",
dest = "split_size",
help = "split or chunk size in seconds, for example 10",
type = "int",
action = "store"
)
parser.add_option("-o", "--file-list",
dest = "file_list",
help = "output file_list",
type = "string",
action = "store"
)
(options, args) = parser.parse_args()
if options.filename and options.split_size and options.file_list:
return (options.filename, options.split_size, options.file_list)
else:
parser.print_help()
raise SystemExit
if __name__ == '__main__':
try:
main()
except Exception, e:
print "Exception occured running main():"
print str(e)
三 壓縮
/usr/local/ffmpeg/bin/ffmpeg -i "2.4_mission.mp4" -vcodec libx264 -s 1920X1080 -vf "movie=stark.png [watermark]; [in][watermark] overlay=main_w-overlay_w-10:10 [out]" -acodec copy "2.4_1080P.mp4"
壓縮效果還不錯,99m的原檔案,壓縮後畫質未變的情況下,體積變成14m。
參考文獻: http://icephoenix.us/notes-for-myself/auto-splitting-video-file-in-equal-chunks-with-ffmpeg-and-python/ http://blog.itpub.net/29754888/viewspace-1383562/
http://blog.csdn.net/dotphoenix/article/details/9714773