多くの場合、オープンソースまたはアクティブな開発者コミュニティでは、大きなビデオセグメントをオンラインで公開する必要があります。 (打ち合わせのビデオ、キャンプアウト、テックトーク...)私は開発者でありビデオグラファーではないので、プレミアムVimeoアカウントの余分なスクラッチをフォークしたくありません。その後、12.5 GB(1:20:00)のMPEGテックトークビデオを00:10:00セグメントに分割して、ビデオ共有サイトに簡単にアップロードするにはどうすればよいですか?
$ ffmpeg -i source-file.foo -ss 0 -t 600 first-10-min.m4v
$ ffmpeg -i source-file.foo -ss 600 -t 600 second-10-min.m4v
$ ffmpeg -i source-file.foo -ss 1200 -t 600 third-10-min.m4v
...
これをスクリプトにまとめてループで実行することは難しくありません。
ffprobe
呼び出しからの継続時間出力に基づいて反復数を計算しようとすると、これは平均から推定であることに注意してください。 -count_frames
引数を指定しない限り、クリップの開始時のビットレートとクリップのファイルサイズ。操作が大幅に遅くなります。
もう1つ注意すべき点は、コマンドラインの-ss
オプションの位置 matters です。私が今持っているところは遅いですが正確です。この回答の最初のバージョンは 高速ですが不正確 代替案を提供しました。リンク先の記事では、ほとんどが高速で正確な代替手段についても説明しています。これは、少し複雑な方法で支払うものです。
それはさておき、私はあなたが本当に各クリップのために正確に10分でカットしたいと思っているとは思いません。これにより、単語の場合も含めて、文章の真ん中にカットが挿入されます。ビデオエディターまたはプレーヤーを使用して、わずか10分の間隔で自然なカットポイントを見つける必要があると思います。
ファイルがYouTubeが直接受け入れることができる形式であると仮定すると、セグメントを取得するために再エンコードする必要はありません。ナチュラルカットポイントのオフセットをffmpeg
に渡し、エンコードされたA/Vをそのまま「コピー」コーデックを使用して渡すように伝えます。
$ ffmpeg -i source.m4v -ss 0 -t 593.3 -c copy part1.m4v
$ ffmpeg -i source.m4v -ss 593.3 -t 551.64 -c copy part2.m4v
$ ffmpeg -i source.m4v -ss 1144.94 -t 581.25 -c copy part3.m4v
...
-c copy
引数は、すべての入力ストリーム(オーディオ、ビデオ、および場合によっては字幕など他のもの)をそのまま出力にコピーするように指示します。単純なA/Vプログラムの場合、これはより詳細なフラグ-c:v copy -c:a copy
または古いスタイルのフラグ-vcodec copy -acodec copy
と同等です。ストリームの1つだけをコピーし、もう1つを再エンコードする場合は、より詳細なスタイルを使用します。たとえば、何年も前に、QuickTimeファイルを使用してH.264ビデオでビデオを圧縮し、オーディオは 非圧縮PCM のままにするという一般的な慣習がありました。今日そのようなファイルに出くわした場合、-c:v copy -c:a aac
を使用してファイルを最新化し、オーディオストリームのみを再処理して、ビデオをそのままにしておくことができます。
最初のコマンドの後の上記のすべてのコマンドの開始点は、前のコマンドの開始点に前のコマンドの継続時間を加えたものです。
ffmpeg -i input.mp4 -c copy -map 0 -segment_time 00:20:00 -f segment output%03d.mp4
これは正確な分割を提供するわけではありませんが、ニーズに合うはずです。代わりに、segment_time
の後に指定された時間の後の最初のフレームでカットします。上のコードでは、20分のマークの後です。
最初のチャンクしか再生できないことがわかった場合は、コメントに記載されているように-reset_timestamps 1
を追加してみてください。
ffmpeg -i input.mp4 -c copy -map 0 -segment_time 00:20:00 -f segment -reset_timestamps 1 output%03d.mp4
以前に同じ問題に直面し、単純なPythonそれを行うためのスクリプトを(FFMpegを使用して)まとめました。ここから入手できます: https://github.com/c0decracker/video-splitter 、および以下に貼り付けます:
#!/usr/bin/env python
import subprocess
import re
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) = parse_options()
if split_length <= 0:
print "Split length can't be 0"
raise SystemExit
output = subprocess.Popen("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
split_cmd = "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
split_str += " -ss "+str(split_start)+" -t "+str(split_length) + \
" '"+filename[:-4] + "-" + str(n) + "." + filename[-3:] + \
"'"
print "About to run: "+split_cmd+split_str
output = subprocess.Popen(split_cmd+split_str, Shell = True, stdout =
subprocess.PIPE).stdout.read()
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"
)
(options, args) = parser.parse_args()
if options.filename and options.split_size:
return (options.filename, options.split_size)
else:
parser.print_help()
raise SystemExit
if __name__ == '__main__':
try:
main()
except Exception, e:
print "Exception occured running main():"
print str(e)
Alternateより読みやすい方法は
ffmpeg -i input.mp4 -ss 00:00:00 -to 00:10:00 -c copy output1.mp4
ffmpeg -i input.mp4 -ss 00:10:00 -to 00:20:00 -c copy output2.mp4
/**
* -i input file
* -ss start time in seconds or in hh:mm:ss
* -to end time in seconds or in hh:mm:ss
* -c codec to use
*/
こちら一般的に使用されるFFmpegコマンドのソースとリスト。
本当に同じチャンクを作成したい場合は、ffmpegですべてのチャンクの最初のフレームにiフレームを作成する必要があるため、このコマンドを使用して0.5秒のチャンクを作成できます。
ffmpeg -hide_banner -err_detect ignore_err -i input.mp4 -r 24 -codec:v libx264 -vsync 1 -codec:a aac -ac 2 -ar 48k -f segment -preset fast -segment_format mpegts -segment_time 0.5 -force_key_frames "expr: gte(t, n_forced * 0.5)" out%d.mkv
これを行うには、ffmpegに組み込まれているものを使用してください。
ffmpeg -i invid.mp4 -threads 3 -vcodec copy -f segment -segment_time 2 cam_out_h264%04d.mp4
これにより、約2秒のチャックに分割され、関連するキーフレームで分割され、cam_out_h2640001.mp4、cam_out_h2640002.mp4などのファイルに出力されます。
#!/bin/bash
if [ "X$1" == "X" ]; then
echo "No file name for split, exiting ..."
exit 1
fi
if [ ! -f "$1" ]; then
echo "The file '$1' doesn't exist. exiting ..."
exit 1
fi
duration=$(ffmpeg -i "$1" 2>&1 | grep Duration | sed 's/^.*Duration: \(.*\)\..., start.*$/\1/' | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }') #'
split_time=${split_time:-55}
time=0
part=1
filename=${file%%.*}
postfix=${file##*.}
while [ ${time} -le ${duration} ]; do
echo ffmpeg -i "$1" -vcodec copy -ss ${time} -t ${split_time} "${filename}-${part}.${postfix}"
(( part++ ))
(( time = time + split_time ))
done