1. 程式人生 > >FFMPEG-如何對視訊按時長切片與壓縮

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

舉一個例子,如果要把一個3分鐘的檔案,按每1分鐘切一個片,可以用下面的方式切成三個檔案

/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