2013年6月5日 星期三

ffmpeg 使用心得







使用了一陣子的 FFMpeg 處理影片,越用越喜歡這套軟體。
一開始,為了要將影片轉成 ipod touch 3代,可用的格式,特別學習
ffmpeg,試了好幾天,終於找出來滿意的方法,特此記錄下來,免得忘了。

轉檔時的指令

ffmpeg -i $1 -s 720x406 -vpre ipod -ac 2 -sn -y -vf subtitles=$1.srt $1.m4v
其中
-i \$1 是要轉檔的檔名
-s 720x406 是轉檔後的解析度,406 = 720 * 720 /
1280,(原始檔的解析度為
1280x720)。這個一定要去計算,不然,在電視上看,畫面比例會不對,字幕可能出不來。
-vpre ipod 是為了 ipod 特別找出來的 preset,設定如後。
--ac 2 是轉成立體聲,不然 ipod touch 沒辦法播放。
--sn 不顯示原始檔中的字幕。因為,我要用另外的字幕檔。
--vf subtitles 為 srt 字幕檔。

preset設定

preset 可以放在 \~/.ffmpeg,檔名為 arg.ffpreset。
例如,我設定了一個專門轉到 ipod touch 的 preset 檔,命名為
ipod.ffpreset。 :
strict=-2

vcodec=libx264
vprofile=main
level=30
maxrate=10000000
bufsize=10000000

preset=fast
#preset=slower

crf=20
#bf=0
#refs=1

#ab=192k

字幕

參考 How to burn subtitles into the
video

原檔中已有圖片格式的字幕時,可直接燒錄:

-filter_complex '[0:v][0:s:1]overlay[v]' -map [v] -map 0:a
此處 -map 一定要下,不然會有錯誤訊息。 其中 -map 0:a
是指所有的音軌,也可以直接指定音軌 -map 0:1
出現的訊息如下:
Stream mapping:
  Stream #0:0 (h264) -> overlay:main (graph 0)
  Stream #0:4 (pgssub) -> overlay:overlay (graph 0)
  overlay (graph 0) -> Stream #0:0 (libx264)

加入外部字幕檔

1. 自行編輯字幕檔

這個很少用到,在 linux 中,就找到 aegisub
是可用的,那就拿來用了,沒有什麼特別的考慮。

2. 提取 mkv 內 srt 或 ass 字幕

提取 mkv 內的文字字幕,用 :
ffmpeg -i $1.mkv -vn -an -scodec copy $1.ssa
或:
ffmpeg -i \$1.mkv -vn -an -scodec copy \$1.srt
有時會出現下列的錯誤訊息,內嵌的應該就是圖片格式字幕。 :
Could not write header for output file #0 (incorrect codec parameters ?): Operation not permitted
爲了能改變字型大小,使用 ass 格式。

3. srt

先轉成 ssa 檔,
ffmpeg -i s.srt s.ssa
s.ssa 中加上
; 同步字幕
Synch Point:0
; PlayResX/Y 影片解析度
PlayResX:720
PlayResY:480
; 調整字幕速度
Timer:100.0000
作出 ssa 檔後,可以用文字編輯器開啓,修改一下 fontname 和
fontsize,讓字型美一點。 各參數用法見 ASS
字幕格式

如果不想控制字幕格式,就不須轉成 ass 格式,就用下列指令燒錄到影片。
-vf subtitles=sub.srt

4. 字幕轉成繁體

可以再用 opencc 把字幕轉成繁體:
opencc -i $1.ssa -o o.ssa

5. ass

用 -vf 燒錄到影片中。
-vf ass=s.ssa
或直接加入影片中,不是燒錄上去。
ffmpeg -i video.avi -i sub.ass -map 0:0 -map 0:2 -map 1 -c:a copy -c:v copy -c:s copy video.mkv
其中 video.avi 有一個視頻軌、兩個音頻軌,取其中的視頻軌 (mpa 0:0)
和第二個音頻軌 (map 0:2) 加 sub.ass (map 1) 做成 video.mkv
而不重新編碼。
重點注意: -i sub.ass -map 1 -c:s copy。 此處的 sub.ass 也可以是
sub.srt。

合併多個影片

參考 How to concatenate (join, merge) media
files

mpeg:
ffmpeg -i "concat:input1.mpg|input2.mpg|input3.mpg" -c copy output.mpg
not mpeg:
This is easiest to explain using an example::

    ffmpeg -i input1.mp4 -i input2.webm \
    -filter_complex '[0:0] [0:1] [1:0] [1:1] concat=n=2:v=1:a=1 [v] [a]' \
    -map '[v]' -map '[a]' <encoding options> output.mkv

On the -filter_complex line, the following:

'[0:0] [0:1] [1:0] [1:1]
tells ffmpeg what streams to send to the concat filter;
in this case, streams 0 and 1 from input 0 (input1.mp4 in this example),
and streams 0 and 1 from input 1 (input2.webm).

concat=n=2:v=1:a=1 [v] [a]'
This is the concat filter itself. n=2 is telling the filter that there are two input files;
v=1 is telling it that there will be one video stream;
a=1 is telling it that there will be one audio stream.
[v] and [a] are names for the output streams, to allow the rest of the ffmpeg line to use the output of the concat filter.

Note that the single quotes ' ' around the whole filter section are required.

-map '[v]' -map '[a]'
This tells ffmpeg to use the results of the concat filter rather than
the streams directly from the input files.

catflv

寫了個小小的 script,用來合併 flv,並轉成 ipod可用的 mp4。 :
#!/bin/bash

icnt=0

for file in $@
do
    filenames="$filenames -i $file "
    scat="$scat[$icnt:0][$icnt:1]"

    #echo $filenames, [$icnt], $scat
    icnt=$(($icnt+1))

done

scmd="ffmpeg $filenames -filter_complex '$scat concat=n=$#:v=1:a=1 [v] [a]' -map '[v]' -map '[a]' -vpre ipod -ab 132k out.mp4"
echo $scmd
eval $scmd

DVD備份

DVD to ISO

爲了保存有價值的影片,儘量用比較高品質的壓縮方法。
​1. 參考:Encoding DVD into HQ flash video using
ffmpeg

將 DVD copy 成 ISO 檔,並掛上: :
$ dd if=/dev/cdrom of=dvd.iso
$ mkdir mnt
$ sudo mount dvd.iso mnt -o loop
$ ls -al mnt/
total 10
dr-xr-xr-x 4 4294967295 4294967295  136 2009-09-30 20:45 .
drwxr-xr-x 5 dpavlin    dpavlin    4096 2009-10-15 22:01 ..
dr-xr-xr-x 2 4294967295 4294967295   40 2009-09-30 17:25 AUDIO_TS
dr-xr-xr-x 2 4294967295 4294967295  560 2009-09-30 18:45 VIDEO_TS
​2. 或使用 dvdbackup,就不必再 mount dvd.iso,而且可以用 libdvdcss
解除保護。
yaourt -S dvdbackup libdvdcss
dvdbackup -i /dev/cdrom -M -o ~/dvd_backup

DVD to MKV

先將 ISO 轉成 MKV :
cat VTS_01_[1234].VOB | ffmpeg -i - -probesize 214748000 -analyzeduration 214748000 \
-map 0:0 -map 0:1 -map 0:2 \
-crf 18 -preset veryslow -tune help\
-filter:v yadif \
-c:a copy -c:s copy -y a.mkv
-probesize 214748000 -analyzeduration 214748000
有時會因爲音軌或字幕軌太晚出現,ffmpeg
會偵測不到,這時就加長偵測的時間和大小。
-map 0:0 -map 0:1 -map 0:2 是要封裝到 mkv 的軌道。
-crf 18 -preset veryslow
用這個參數大概就好了,眼睛看不出來與原始有何差異。 有必要時可以再加上
-tune。
-filter:v yadif 就是 deinterlace。
-c:a copy -c:s copy 音軌和字幕軌都不重新編碼。
如果沒有字幕,可以先取得字幕檔,再保存到 mkv 中,如下: :
$ cat VTS_01_[1234].VOB | ffmpeg -i - -i a.ssa \
-map 0:0 -map 0:2 -map 1 \
-crf 18 -preset veryslow -tune zerolatency \
-filter:v yadif \
-c:a copy -c:s copy \
-y a.mkv
重點是 -i a.ssa -map 1 -c:s copy

MKV 轉成 mp4

如果要在 ipod 或智慧型手機上看,那就不需要太考慮品質,能用就好。
就用上面轉好的 mkv 檔,再轉一次。 如此,既可以用 mkv
保存高品質的影片,再轉成 mp4 的速度也比較快。
這是要注意字幕是圖片格式或是 srt/ass 文字式。

字幕是圖片格式

用 -filter_complex 直接燒錄 :
$ ffmpeg -i a.mkv \
-filter_complex '[0:v][0:s:1]overlay[v]' -map [v] -map 0:a \
-vpre ipod -ac 2 -ab 192k \
-y a.mp4

字幕是 srt 或 ass


  1. 先處理字幕檔 (前述)

  2. 用 -vf subtiles=a.srt 或 -vf ass=a.ass 把字幕燒進 mp4 中。 :
    $ ffmpeg -i a.mkv \
    -vpre ipod -ac 2 -ab 192k \
    -vf subtitles=a.srt \
    -y a.mp4
    

metadata

參考 ffmpeg
-metadata[:metadata_specifier] key=value (output,per-metadata) Set a
metadata key/value pair.
An optional metadata_specifier may be given to set metadata on streams
or chapters. See -map_metadata documentation for details.
This option overrides metadata set with -map_metadata. It is also
possible to delete metadata by using an empty value.
For example, for setting the title in the output file :
ffmpeg -i in.avi -metadata title="my title" out.flv
To set the language of the first audio stream :
ffmpeg -i INPUT -metadata:s:a:1 language=eng OUTPUT
例子: :
-metadata:s:1 title="日語" -metadata:s:2 title="國語" -metadata:s:3 title="中文"

參考資料


  1. FFmpeg wiki:
    x264EncodingGuide

  2. 直接看 help :
    $ ffmpeg --help
    $ x264 --fullhelp