본문 바로가기
ffmpeg cut and merge.py #코드스니핏
# -*- coding:utf-8 -*-
import sys
import re
import datetime
import os
import subprocess
from dprint import dprint
import pathlib

def createDirectory(directory):
    try:
        if not os.path.exists(directory):
            os.makedirs(directory)
    except OSError:
        print("Error: Failed to create the directory.")

def length_with_ffprobe(filename):
    import subprocess, json
    result = subprocess.check_output(
            f'ffprobe -v quiet -show_streams -select_streams v:0 -of json "{filename}"', shell=True).decode()
    fields = json.loads(result)['streams'][0]

    duration = fields['duration']
    float_duration = float(duration)
    hour =  int(float_duration/60/60)
    min = int((float_duration - hour*60*60) / 60)
    sec = int(float_duration - hour*60*60 - min*60)

    print("%d:%s:%s" %(hour, str(min).zfill(2), str(sec).zfill(2)))
    return "%d:%s:%s" %(hour, str(min).zfill(2), str(sec).zfill(2))

### configuration
str_mp4File = '......mp4'
if len(sys.argv) == 2 : 
    str_mp4File = sys.argv[1]
else : 
    print("no argument mp4 - error(1) ")
    sys.exit()
str_cutFile = str_mp4File[:-4]+".cut"

if not os.path.isfile(str_cutFile)  :
    pathlib.Path(str_cutFile).touch()
    print (".cut file has been created")
    sys.exit()

### Global variables
mp4_time_list = ["0:0"]
mp4_alive_remove_lst = []
mp4_time_list_touched = []

fullPath = str(pathlib.Path().resolve())+"/"
dir_ = str_mp4File.split(" ")[0]
workingPath = str(fullPath) + "/" + (dir_).rstrip()+"/"
createDirectory(workingPath)

str_mp4File_with_fullpath = fullPath + str_mp4File
str_cutFile_with_fullpath = fullPath + str_cutFile
str_mgrFile_with_fullpath = str_cutFile_with_fullpath[0:-4]+".mgr"

# parsing the input file 
with open(fullPath+str_cutFile, 'r') as f:
    for line in f:
        try :
            pattern_time_raw = '\d{1,2}?:\d{1,2}:?\d{0,2}'
            pattern_time = re.compile(pattern_time_raw)
            time = re.findall(pattern_time, line)[0]
        except :
            time = length_with_ffprobe(str_mp4File_with_fullpath)
        mp4_time_list.append(time)
        if "살림" in  line : 
            mp4_alive_remove_lst.append(True)
        else :
            mp4_alive_remove_lst.append(False)

dprint(mp4_time_list)
dprint(mp4_alive_remove_lst)

for idx, (time_curr, time_next) in enumerate(zip(mp4_time_list[:-1], mp4_time_list[1:])): 
    time_start = time_curr.split(':')
    time_end = time_next.split(':')

    if len(time_start) == 3 :
        start_hour = int(time_start[0])
        start_minute = int(time_start[1])
        start_second = int(time_start[2])
    else :
        start_hour = 0
        start_minute = int(time_start[0])
        start_second = int(time_start[1])

    if len(time_end) == 3 :
        end_hour = int(time_end[0])
        end_minute = int(time_end[1])
        end_second = int(time_end[2])
    else :
        end_hour = 0
        end_minute = int(time_end[0])
        end_second = int(time_end[1])

    print ("%d:%d:%d ~ %d:%d:%d"%(start_hour, start_minute, start_second, end_hour, end_minute, end_second))

    startMin = start_hour * 60 + start_minute
    startSec = start_second
    endMin = end_hour * 60 + end_minute
    endSec = end_second

    dbg_time = ("startMin : %d, startSec : %d, endMin : %d, endSec : %d" %(startMin, startSec, endMin, endSec))
    print (dbg_time)

    startTime = startMin*60+startSec
    endTime = endMin*60+endSec

    durationTime = endTime-startTime
    dprint(durationTime)
    print(idx)

    mp4_time_list_touched.append( {"startTime" :startTime, "durationTime" : durationTime, "alive" : mp4_alive_remove_lst[idx]} )

print(mp4_time_list_touched)

for ix, data in enumerate(mp4_time_list_touched):
    if data['alive'] == True:
        # 가장 가까운 이전 키프레임을 찾습니다
        cmd_keyframe = f"ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 -read_intervals {data['startTime']}%+#1 '{str_mp4File_with_fullpath}'"
        keyframe_packet = int(subprocess.check_output(cmd_keyframe, shell=True).decode().strip())

        # 키프레임의 시간을 찾습니다
        cmd_keyframe_time = f"ffprobe -v error -select_streams v:0 -count_packets -show_entries packet=pts_time -of csv=p=0 -read_intervals {data['startTime']}%+#1 '{str_mp4File_with_fullpath}' | sed -n {keyframe_packet}p"
        keyframe_time = float(subprocess.check_output(cmd_keyframe_time, shell=True).decode().strip())

        # 수정된 시작 시간을 사용하여 비디오를 자릅니다
        cmd = f"ffmpeg -nostdin -i '{str_mp4File_with_fullpath}' -ss {keyframe_time} -c copy -t {data['durationTime']} '{workingPath}{ix}.mp4'"
        subprocess.call(cmd, shell=True)
    else:
        continue

print(mp4_time_list_touched)

if os.path.isfile(str_mgrFile_with_fullpath) :
    os.remove(str_mgrFile_with_fullpath)

with open (str_mgrFile_with_fullpath, "a") as f :
    for ix, data in enumerate(mp4_time_list_touched) :
        if data['alive'] == True :
            f.write('file %s%d.mp4\n'%(workingPath,ix))

str_Ofile = str_mp4File_with_fullpath[0:-4]+".cut.mp4"
cmd = "ffmpeg -nostdin -f concat -safe 0 -i \'%s\' -c copy \'%s\'" %(str_mgrFile_with_fullpath, str_Ofile)
print(cmd)
subprocess.call(cmd, shell=True)

댓글