मैं 10 मिनट के विखंडू में एमपीईजी वीडियो को विभाजित करने के लिए ffmpeg का उपयोग कैसे कर सकता हूं?


62

बड़े वीडियो खंडों को ऑनलाइन प्रकाशित करने के लिए अक्सर खुले स्रोत या सक्रिय डेवलपर समुदाय की आवश्यकता होती है। (मीट-अप वीडियो, कैंपआउट, टेक वार्ता ...) होने के नाते कि मैं एक डेवलपर हूं और वीडियोग्राफर नहीं हूं, मुझे प्रीमियम वीमो अकाउंट पर अतिरिक्त खरोंच को दूर करने की कोई इच्छा नहीं है। फिर मैं 12.5 जीबी (1:20:00) एमपीईजी टेक टॉक वीडियो कैसे लेता हूं और वीडियो साझा करने वाली साइटों पर आसानी से अपलोड करने के लिए 00:10:00 सेगमेंट में इसे स्लाइस करता हूं?


नए टैग को समायोजित करने के लिए @StevenD के लिए विशेष धन्यवाद।
गेब्रियल

जवाबों:


69
$ 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तर्क नहीं देते हैं, जो इसके संचालन को काफी धीमा कर देता है ।

एक और बात यह है कि -ssकमांड लाइन पर विकल्प की स्थिति मायने रखती है । जहां मेरे पास यह अब धीमा है, लेकिन सटीक है। इस उत्तर के पहले संस्करण ने तेज लेकिन गलत विकल्प दिया। लिंक किए गए लेख में ज्यादातर तेजी से लेकिन अभी भी सटीक विकल्प का वर्णन है, जो आप थोड़ी जटिलता के साथ भुगतान करते हैं।

वह सब अलग, मुझे नहीं लगता कि आप वास्तव में प्रत्येक क्लिप के लिए ठीक 10 मिनट काटना चाहते हैं। यह वाक्यों के बीच में कटौती करेगा, यहां तक ​​कि शब्द भी। मुझे लगता है कि आपको एक वीडियो संपादक या खिलाड़ी का उपयोग करना चाहिए ताकि प्राकृतिक कट प्वाइंट को केवल 10 मिनट के लिए अलग किया जा सके।

मान लें कि आपकी फ़ाइल एक ऐसे प्रारूप में है जिसे YouTube सीधे स्वीकार कर सकता है, आपको सेगमेंट प्राप्त करने के लिए पुन: लोड करने की आवश्यकता नहीं है। बस प्राकृतिक कट पॉइंट ऑफ़सेट को ffmpegपास करें, यह बताकर कि एन्कोडेड ए / वी को "एनर्जी" का उपयोग करके अछूता से गुजरना है:

$ 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तर्क यह बताता है के रूप में-है उत्पादन में सभी इनपुट धाराओं (ऑडियो, वीडियो, और संभवतः जैसे उपशीर्षक दूसरों) कॉपी करने के लिए। सरल ए / वी कार्यक्रमों के लिए, यह अधिक क्रिया झंडे -c:v copy -c:a copyया पुरानी शैली के झंडे के बराबर है -vcodec copy -acodec copy। आप अधिक वर्बोज़ शैली का उपयोग करेंगे जब आप केवल एक ही स्ट्रीम को कॉपी करना चाहते हैं, लेकिन दूसरे को फिर से एनकोड करें। उदाहरण के लिए, कई साल पहले H.264 वीडियो के साथ वीडियो को संपीड़ित करने के लिए QuickTime फ़ाइलों के साथ एक आम प्रथा थी लेकिन ऑडियो को असम्पीडित PCM के रूप में छोड़ दें ; यदि आप आज ऐसी किसी फ़ाइल में भाग गए हैं, तो आप इसे -c:v copy -c:a aacकेवल ऑडियो स्ट्रीम को पुन: पेश करने के लिए आधुनिक बना सकते हैं , जिससे वीडियो अछूता नहीं रह जाएगा।

पहले के बाद के प्रत्येक कमांड के लिए शुरुआती बिंदु, पिछले कमांड का प्रारंभ बिंदु और पिछली कमांड की अवधि है।


1
"प्रत्येक क्लिप के लिए बिल्कुल 10 मिनट काटना" एक अच्छा बिंदु है।
क्रिस

शायद -show_packets param का उपयोग करके आप इसे और अधिक सटीक बना सकते हैं।
रोजरपैक

कैसे एक पाश में ऊपर रखने के लिए?
kRazzy R

मैं इस cmd का उपयोग करता हूँ फिर यह सही में विभाजित हो जाता है, लेकिन अब वीडियो और ऑडियो SYNC पर नहीं हैं
सुनील चौधरी

@ सुनीलचौधरी: ए / वी फ़ाइल प्रारूप जटिल हैं और सभी सॉफ्टवेयर उन्हें एक ही तरह से लागू नहीं करते हैं, ताकि ffmpegऑडियो और वीडियो धाराओं के बीच सिंक्रनाइज़ेशन बनाए रखने के लिए जानकारी स्रोत फ़ाइल में मौजूद न हो। यदि आपके साथ ऐसा हो रहा है, तो विभाजन के अधिक जटिल तरीके हैं जो समस्या से बचते हैं।
वॉरेन यंग

52

यहाँ एक लाइन समाधान है :

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

2
यह वास्तव में आपको बहुत सटीक विभाजन देता है, यदि आप वीडियो की गुणवत्ता को महत्व देते हैं। किसी विशेष समय के आधार पर विभाजित होने के बजाय, यह अनुरोधित समय के बाद निकटतम कीफ़्रेम पर विभाजित होता है, इसलिए प्रत्येक नया सेगमेंट हमेशा एक कीफ़्रेम के साथ शुरू होता है।
मालविनस

3
इकाइयाँ क्या हैं? 8s? 8min? 8h?
user1133275

1
@ user1133275 इसकी दूसरी
जॉन

2
मैक पर, मैंने पाया कि यह एन आउटपुट वीडियो चंक था, लेकिन उनमें से केवल 1 एक वैध, देखने योग्य MP4 था। अन्य N-1 विडियो बिना किसी ऑडियो के रिक्त वीडियो (सभी काले) थे। इसे काम करने के लिए, मुझे reset_timestamps फ्लैग को इस तरह जोड़ना होगा: ffmpeg -i input.mp4 -c copy -map 0 -segment_time 8 -f सेगमेंट -reset_timestamps 1 आउटपुट 03d.mp4।
जरमोद

3
यह पाया कि -reset_timestamps 1मेरे लिए इस मुद्दे को ठीक करता है
jlarsch

6

एक ही समस्या का सामना पहले और एक साधारण पायथन लिपि को एक साथ करने के लिए किया (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)

1
अगली बार यह एक टिप्पणी में कृपया। लिंक-केवल उत्तर वास्तव में यहाँ पसंद नहीं किए जाते हैं, और यदि आप अपनी साइट का विज्ञापन करते हैं तो वही। यदि यह स्रोत कोड के साथ एक ओपनसोर्स परियोजना है, तो शायद यह एक अपवाद है, लेकिन मैंने अब आपके उत्तर को हटाने के लिए मतदान नहीं करके मेरी समीक्षा विशेषाधिकार प्राप्त कर लिया है । और हाँ, आप टिप्पणी पोस्ट नहीं कर सकते, लेकिन आपके द्वारा एकत्र किए जाने के बाद 5 अपवोट्स (जो आपके मामले में बहुत तेज़ लगते हैं)।
user259412

2
नमस्ते और साइट पर आपका स्वागत है। कृपया लिंक केवल उत्तर पोस्ट न करें। जबकि आपकी लिपि स्वयं एक महान उत्तर देगी, लेकिन इसका लिंक एक उत्तर नहीं है। यह एक उत्तर की ओर इशारा करते हुए एक साइनपोस्ट है । उस पर और अधिक यहाँ । चूंकि आपने कृपया लिंक दिया है, इसलिए मैंने आगे बढ़कर स्क्रिप्ट को आपके उत्तर की बॉडी में शामिल किया। यदि आपको इस पर आपत्ति है, तो कृपया उत्तर को पूरी तरह से हटा दें।
टेराडो

3

ध्यान दें कि वैकल्पिक प्रारूप का सटीक विराम चिह्न है -ss mm:ss.xxx। मैं घंटे के लिए संघर्ष किया सहज ज्ञान युक्त का उपयोग करने की कोशिश कर रहा है, लेकिन mm:ss:xxकोई फायदा नहीं हुआ।

$ man ffmpeg | grep -C1 position

-सी स्थिति
सेकंड में दिए गए समय की स्थिति की तलाश करें। "hh: mm: ss [.xxx]" सिंटैक्स भी समर्थित है।

संदर्भ यहाँ और यहाँ


3

यदि आप वास्तव में एक ही बनाना चाहते हैं तो चंक्स को ffmpeg को प्रत्येक चंक्स के पहले फ्रेम पर आई-फ्रेम बनाने के लिए मजबूर करना होगा ताकि आप इस कमांड का उपयोग 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

यह स्वीकृत उत्तर होना चाहिए। साथी को साझा करने के लिए धन्यवाद!
स्टीफन अहल्फ

3

एक वैकल्पिक अधिक पठनीय तरीका होगा

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 कमांड का स्रोत और सूची दी गई है।


0
#!/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

बस का उपयोग करें क्या वास्तव में ऐसा करने के लिए ffmpeg में बनाया गया है।

ffmpeg -i invid.mp4 -threads 3 -vcodec copy -f segment -segment_time 2 cam_out_h264%04d.mp4

यह इसे लगभग 2 सेकंड चक में विभाजित करेगा, प्रासंगिक कीफ्रेम में विभाजित करेगा, और फाइलों के लिए उत्पादन करेगा कैम_आउट_एच 2640001.mp4, कैम_आउट_एच 2640002.mp4, आदि।


मुझे यकीन नहीं है कि मुझे समझ में आ रहा है कि यह जवाब क्यों दिया गया है। यह काम तो ठीक करता है।
कॉस्टिन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.