videospeeder 0.1: Linux和OSX下的倍速视频

象征意义大于实际意义,但是还是写上以防万一。
老规矩,GNU v2.
非原画全死请注意。
“桌面飞翔,移动骂娘”——Beining
我没写死禁止倍速调负数,大家可以看看是啥效果2333333
最后还有一个;小丸的办法,直接接视频。过后写。
https://github.com/cnbeining/videospeeder
代码下边。

#!/usr/bin/env python
#coding:utf-8
# Author:  Beining --<ACICFG>
# Contact: http://www.cnbeining.com/   |https://github.com/cnbeining/videospeeder
# Purpose: Acceletate video to bypass Letvcloud's transcode.
# Created: 08/28/2014
# LICENSE: GNU v2
import sys
import os
import os, sys, subprocess, shlex, re
from subprocess import call
import uuid
import math
import shutil
import getopt
#----------------------------------------------------------------------
def probe_file(filename):
    cmnd = ['ffprobe', '-show_format', '-pretty', '-loglevel', 'quiet', filename]
    p = subprocess.Popen(cmnd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    #print filename
    out, err =  p.communicate()
    #print out
    if err:
        print err
        return None
    return out
#----------------------------------------------------------------------
def time_to_sec(time_raw):
    """
    str->int
    ignore .*."""
    time_list = time_raw.split(':')
    hr = int(time_list[0]) * 3600
    minute = int(time_list[1]) * 60
    sec = int(float(time_list[2]))
    return int(hr + minute + sec)
#----------------------------------------------------------------------
def get_abspath(filename):
    """"""
    return str(os.path.abspath(filename))
#----------------------------------------------------------------------
def process(filename, target_bitrate, speedtime, outputfile):
    """str,int,float,str->?
    filename,outputfile comes with the path."""
    tmpdir = '/tmp/videospeeder-' + str(uuid.uuid4())
    if not os.path.exists(tmpdir):
        os.makedirs(tmpdir)
    audio_format = ''
    audio_duration = ''
    video_duration_sec = 0
    video_size_byte = 0
    audio_bitrate = ''
    audio_duration_sec = 0
    audio_size_byte = 0
    video_format = ''
    video_duration = ''
    video_bitrate = ''
    #demux audio file
    print('INFO: Checking audio...')
    os.system('ffmpeg -i \'' + filename + '\' -vn -c:a copy ' + tmpdir+'/audio.aac' +' > /dev/null 2>&1')
    try:
        for line in probe_file(tmpdir+'/audio.aac').split('\n'):
            if 'format_name' in line:
                audio_format = str(line.split('=')[1])
            if 'duration' in line:
                audio_duration = str(line.split('=')[1])
    except:
        print('ERROR: Cannot read audio file!')
        shutil.rmtree(tmpdir)
        exit()
    #In case someone screw the audio up
    if not 'aac' in audio_format:
        print(audio_format)
        print('ERROR: You have to use AAC as audio format!')
        shutil.rmtree(tmpdir)
        exit()
    #Check original file
    try:
        for line in probe_file(filename).split('\n'):
            if 'duration' in line:
                video_duration = str(line.split('=')[1])
                #Sti. there's a tag called "totalduration"...
                break
    except:
        print('ERROR: Cannot read video file!')
        shutil.rmtree(tmpdir)
        exit()
    #Calc...
    #By bitrate
    if target_bitrate != 0:
        print('INFO: Doing calculation...')
        try:
            video_duration_sec = time_to_sec(video_duration)
            video_size_byte = int(os.path.getsize(filename))
            audio_duration_sec = time_to_sec(audio_duration)
            audio_size_byte = int(os.path.getsize(tmpdir+'/audio.aac'))
        except:
            print('ERROR: Cannot calculate time, did you input a bitrate too high?')
            shutil.rmtree(tmpdir)
            exit()
        try:
            os.remove(tmpdir+'/audio.aac')
            pass
        except:
            print('WARNING: Cannot remove the aac file now...')
        time_audio = float(((audio_size_byte * 8.0) / audio_duration_sec) / 1180000)
        time_video = float(((video_size_byte * 8.0) / video_duration_sec) / target_bitrate)
        if time_audio < 1 and time_video < 1:
            print('ERROR: Cannot calculate target, your target bitrate is higher than the original file!')
            shutil.rmtree(tmpdir)
            exit()
        if time_audio == 1 and time_video == 1:
            speedtime = 1.1
        elif time_audio > time_video:
            speedtime = time_audio
        else:
            speedtime = time_video
    #Make patch
    print('INFO: Adding ' + str(speedtime - 1) + ' times to audio...')
    py_path = sys.path[0]
    os.chdir(py_path)
    os.system('ffmpeg -i \'' + filename + '\'  -c copy ' + tmpdir+'/video.mkv' +'> /dev/null 2>&1')
    os.system('mkvextract timecodes_v2 '+ tmpdir + '/video.mkv 0:' + tmpdir +'/tc-track0.txt '+ '1:' + tmpdir +'/tc-track1.txt > /dev/null 2>&1')
    #Video
    f = open(tmpdir + '/tc-track0.txt', 'r')
    video_timecode = f.readlines()
    f.close()
    video_timecode_speed = '# timecode format v2' + '\n'
    for i in video_timecode[1:]:
        video_timecode_speed = video_timecode_speed + str(float(i.strip()) * speedtime) + '\n'
    f = open(tmpdir + '/video_timecode_speed.txt', 'w')
    f.write(video_timecode_speed)
    f.close()
    #Audio
    f = open(tmpdir + '/tc-track1.txt', 'r')
    audio_timecode = f.readlines()
    f.close()
    audio_timecode_speed = '# timecode format v2' + '\n'
    for i in audio_timecode[1:]:
        audio_timecode_speed = audio_timecode_speed + str(float(i.strip()) * speedtime) + '\n'
    f = open(tmpdir + '/audio_timecode_speed.txt', 'w')
    f.write(audio_timecode_speed)
    f.close()
    py_path = sys.path[0]
    os.chdir(py_path)
    print('INFO: Making patched mkv...')
    os.system('mkvmerge -o  ' + tmpdir + '/video_patched.mkv --timecodes 0:' + tmpdir + '/video_timecode_speed.txt  --timecodes 1:' + tmpdir + '/audio_timecode_speed.txt ' +tmpdir + '/video.mkv > /dev/null 2>&1')
    try:
        os.remove(tmpdir+'/video.mkv')
        pass
    except:
        print('WARNING: Cannot remove the temporary mkv file now...')
    print('INFO: Making final output file...')
    os.system('ffmpeg -i ' + tmpdir + '/video_patched.mkv -c copy  '+outputfile +'> /dev/null 2>&1')
    print('Done!')
    #clean up
    try:
        shutil.rmtree(tmpdir)
    except:
        print('ERROR: Cannot remove temp dir, do it by yourself!')
#----------------------------------------------------------------------
def usage():
    """"""
    print('''Usage:
    python videospeeder.py (-h) (-i input.mp4) (-o output.mp4) (-b 0) (-x 3)
    -h: Default: None
        Help.
    -i: Default: Blank
        Input file.
        If the file and audioblacker are not under the same path,
        it is suggested to use absolute path to avoid possible failure.
    -o Default: input_filename.black.mp4
       Output file.
       Would be in the same folder with the original file if not specified.
    -b: Default: 0
        Target bitrate.
    -x: Default: 3
        Target speeding time.
    If bitrate is set, it will override the speeding time, if also set.
    Videospeeder will calculate both audio and video timing to make sure
    that both the audio and the video meets the requirments.
    Please notice that if your original video/audio bitrate is too small,
    Videospeeder would throw you an ERROR and quit.
        ''')
#----------------------------------------------------------------------
if __name__=='__main__':
    argv_list = []
    argv_list = sys.argv[1:]
    filename = ''
    target_bitrate = 0
    outputfile = ''
    speedtime = 3
    try:
        opts, args = getopt.getopt(argv_list, "hi:b:x:o:", ['help', 'input','bitrate', 'speedtime'
                                                           'outputfile'])
    except getopt.GetoptError:
        usage()
        exit()
    for o, a in opts:
        if o in ('-h', '--help'):
            usage()
            exit()
        elif o in ('-i', '--input'):
            filename = a
            try:
                argv_list.remove('-i')
            except:
                break
        elif o in ('-b', '--bitrate'):
            target_bitrate = int(a)
            try:
                argv_list.remove('-b')
            except:
                break
        elif o in ('-x', '--speedtime'):
            speedtime = int(a)
            try:
                argv_list.remove('-x')
            except:
                break
        elif o in ('-o', '--outputfile'):
            outputfile = a
            try:
                argv_list.remove('-o')
            except:
                break
    if filename == '':
        print('ERROR: No input file!')
        exit()
    if outputfile == '':
        outputfile = filename.split('.')[0]
        for i in filename.split('.')[1:-1]:
            outputfile = outputfile + '.' + i
        outputfile = outputfile + '.speed.mp4'
    process(filename, target_bitrate, speedtime, outputfile)
    exit()

 

Leave a Reply

Your email address will not be published. Required fields are marked *