it-swarm-ko.com

ffmpeg를 사용하여 MPEG 비디오를 10 분 단위로 분할하려면 어떻게해야합니까?

오픈 소스 또는 활발한 개발자 커뮤니티에서 대규모 비디오 세그먼트를 온라인으로 게시해야하는 경우가 종종 있습니다. (미팅 동영상, 캠프 아웃, 기술 강연 ...) 동영상 개발자가 아니라 개발자이기 때문에 프리미엄 Vimeo 계정에서 추가 스크래치를 없애고 싶지 않습니다. 그러면 12.5GB (1:20:00) MPEG 기술 토크 비디오를 가져 와서 비디오 공유 사이트에 쉽게 업로드 할 수 있도록 00:10:00 세그먼트로 슬라이스하는 방법은 무엇입니까?

73
Gabriel
$ 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 호출의 출력 지속 시간을 기반으로 반복 횟수를 계산하려고하면 평균에서 estimated 라는 점에 유의하십시오. -count_frames 인수를 지정하지 않으면 클립 시작시의 비트 전송률과 클립의 파일 크기가 상당히 느려집니다.

알아 두어야 할 또 다른 사항은 명령 행에서 -ss 옵션의 위치 matters 입니다. 내가 가진 곳은 지금 느리지 만 정확합니다. 이 답변의 첫 번째 버전은 빠르지 만 부정확 한 대안을 제시했습니다. 링크 된 기사는 또한 매우 빠르지 만 여전히 정확한 대안을 설명합니다.

그 외에도, 각 클립마다 정확히 10 분을 자르고 싶지는 않습니다. 그것은 문장의 한가운데서, 심지어 단어까지 잘릴 것입니다. 비디오 편집기 나 플레이어를 사용하여 10 분 간격으로 자연스러운 컷 포인트를 찾아야한다고 생각합니다.

파일이 YouTube에서 직접 사용할 수있는 형식으로되어 있다고 가정하면 세그먼트를 얻기 위해 다시 인코딩 할 필요가 없습니다. "cut"코덱을 사용하여 자연 컷 포인트 오프셋을 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와 같습니다. 스트림 중 하나만 복사하고 다른 스트림은 다시 인코딩하려는 경우 더 자세한 스타일을 사용합니다. 예를 들어, 몇 년 전 H.264 비디오로 비디오를 압축하지만 오디오는 ncompressed PCM ; 이러한 파일을 오늘 살펴본 경우 -c:v copy -c:a aac로 파일을 현대화하여 오디오 스트림 만 다시 처리하여 비디오를 그대로 두십시오.

첫 번째 이후 이후의 모든 명령에 대한 시작 지점은 이전 명령의 시작 지점에 이전 명령의 지속 시간을 더한 것입니다.

72
Warren Young

여기서 한 줄 해결책이 있습니다 :

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
68
Jon

이전에 같은 문제에 직면하고 간단한 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)
7
c0decracker

Alternate more readable 방식은

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
*/

Here 's 일반적으로 사용되는 FFmpeg 명령의 소스와 목록.

4
Niket Pathak

실제로 동일한 청크를 만들려면 ffmpeg가 모든 청크의 첫 번째 프레임에 i-frame을 만들도록 강제해야하므로 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
4

대체 형식의 정확한 문장 부호는 -ss mm:ss.xxx. 직관적이지만 잘못된 mm:ss:xx 소용이 없습니다.

$ man ffmpeg | grep -C1 position

-ss 위치
초 단위로 주어진 시간 위치를 찾으십시오. "hh : mm : ss [.xxx]"구문도 지원됩니다.

참조 herehere .

3
Mark Hudson

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 등의 파일로 출력됩니다.

1
John Allard
#!/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
0
Alex_Shilli