Exemplo n.º 1
0
def fastVideo(ffmpeg, videoFile, outFile, silentT, frameMargin, SAMPLE_RATE,
    AUD_BITRATE, verbose, videoSpeed, silentSpeed, cutByThisTrack, keepTracksSep):

    print('Running from fastVideo.py')

    import cv2

    conwrite('Reading audio.')

    if(not os.path.isfile(videoFile)):
        print('Could not find file:', videoFile)
        sys.exit(1)

    TEMP = tempfile.mkdtemp()
    speeds = [silentSpeed, videoSpeed]

    cap = cv2.VideoCapture(videoFile)
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    fps = cap.get(cv2.CAP_PROP_FPS)

    tracks = vidTracks(videoFile, ffmpeg)

    if(cutByThisTrack >= tracks):
        print("Error! You choose a track that doesn't exist.")
        print(f'There are only {tracks-1} tracks. (starting from 0)')
        sys.exit(1)

    for trackNumber in range(tracks):
        cmd = [ffmpeg, '-i', videoFile, '-ab', AUD_BITRATE, '-ac', '2', '-ar',
        str(SAMPLE_RATE),'-map', f'0:a:{trackNumber}', f'{TEMP}/{trackNumber}.wav']
        if(verbose):
            cmd.extend(['-hide_banner'])
        else:
            cmd.extend(['-nostats', '-loglevel', '0'])
        subprocess.call(cmd)


    sampleRate, audioData = read(f'{TEMP}/{cutByThisTrack}.wav')
    chunks = getAudioChunks(audioData, sampleRate, fps, silentT, 2, frameMargin)

    # Handle the Audio
    for trackNumber in range(tracks):
        fastAudio(ffmpeg, f'{TEMP}/{trackNumber}.wav', f'{TEMP}/new{trackNumber}.wav',
            silentT, frameMargin, SAMPLE_RATE, AUD_BITRATE, verbose, silentSpeed,
            videoSpeed, False, chunks=chunks, fps=fps)

        if(not os.path.isfile(f'{TEMP}/new{trackNumber}.wav')):
            print('Error! Audio file not created.')
            sys.exit(1)

    out = cv2.VideoWriter(f'{TEMP}/spedup.mp4', fourcc, fps, (width, height))
    totalFrames = chunks[len(chunks) - 1][1]
    beginTime = time.time()

    remander = 0
    framesWritten = 0

    while cap.isOpened():
        ret, frame = cap.read()
        if(not ret):
            break

        cframe = int(cap.get(cv2.CAP_PROP_POS_FRAMES)) # current frame
        state = None
        for chunk in chunks:
            if(cframe >= chunk[0] and cframe <= chunk[1]):
                state = chunk[2]
                break

        if(state is not None):
            mySpeed = speeds[state]

            if(mySpeed != 99999):
                doIt = (1 / mySpeed) + remander
                for __ in range(int(doIt)):
                    out.write(frame)
                    framesWritten += 1
                remander = doIt % 1

        progressBar(cframe, totalFrames, beginTime, title='Creating new video')

    conwrite('Writing the output file.')

    cap.release()
    out.release()
    cv2.destroyAllWindows()

    if(verbose):
        print('Frames written', framesWritten)

    first = videoFile[:videoFile.rfind('.')]
    extension = videoFile[videoFile.rfind('.'):]

    if(outFile == ''):
        outFile = f'{first}_ALTERED{extension}'

    # Now mix new audio(s) and the new video.
    if(keepTracksSep):
        cmd = [ffmpeg, '-y']
        for i in range(tracks):
            cmd.extend(['-i', f'{TEMP}/new{i}.wav'])
        cmd.extend(['-i', f'{TEMP}/spedup.mp4'])
        for i in range(tracks):
            cmd.extend(['-map', f'{i}:a:0'])
        cmd.extend(['-map', f'{tracks}:v:0','-c:v', 'copy', '-movflags', '+faststart',
            outFile])
        if(verbose):
            cmd.extend(['-hide_banner'])
        else:
            cmd.extend(['-nostats', '-loglevel', '0'])
    else:
        # Merge all the audio tracks into one.
        if(tracks > 1):
            cmd = [ffmpeg]
            for i in range(tracks):
                cmd.extend(['-i', f'{TEMP}/new{i}.wav'])
            cmd.extend(['-filter_complex', f'amerge=inputs={tracks}', '-ac', '2',
                f'{TEMP}/newAudioFile.wav'])
            if(verbose):
                cmd.extend(['-hide_banner'])
            else:
                cmd.extend(['-nostats', '-loglevel', '0'])
            subprocess.call(cmd)
        else:
            os.rename(f'{TEMP}/new0.wav', f'{TEMP}/newAudioFile.wav')

        cmd = [ffmpeg, '-y', '-i', f'{TEMP}/newAudioFile.wav', '-i',
            f'{TEMP}/spedup.mp4', '-c:v', 'copy', '-movflags', '+faststart',
            outFile]
        if(verbose):
            cmd.extend(['-hide_banner'])
        else:
            cmd.extend(['-nostats', '-loglevel', '0'])
        subprocess.call(cmd)

    rmtree(TEMP)
    conwrite('')

    return outFile
Exemplo n.º 2
0
def main():
    parser = argparse.ArgumentParser(prog='Auto-Editor', usage='auto-editor [input] [options]')

    basic = parser.add_argument_group('Basic Options')
    basic.add_argument('input', nargs='*',
        help='the path to the file(s), folder, or url you want edited.')
    basic.add_argument('--frame_margin', '-m', type=int, default=6, metavar='6',
        help='set how many "silent" frames of on either side of "loud" sections be included.')
    basic.add_argument('--silent_threshold', '-t', type=float_type, default=0.04, metavar='0.04',
        help='set the volume that frames audio needs to surpass to be "loud". (0-1)')
    basic.add_argument('--video_speed', '--sounded_speed', '-v', type=float_type, default=1.00, metavar='1',
        help='set the speed that "loud" sections should be played at.')
    basic.add_argument('--silent_speed', '-s', type=float_type, default=99999, metavar='99999',
        help='set the speed that "silent" sections should be played at.')
    basic.add_argument('--output_file', '-o', nargs='*', metavar='',
        help='set the name(s) of the new output.')

    advance = parser.add_argument_group('Advanced Options')
    advance.add_argument('--no_open', action='store_true',
        help='do not open the file after editing is done.')
    advance.add_argument('--min_clip_length', '-mclip', type=int, default=3, metavar='3',
        help='set the minimum length a clip can be. If a clip is too short, cut it.')
    advance.add_argument('--min_cut_length', '-mcut', type=int, default=6, metavar='6',
        help="set the minimum length a cut can be. If a cut is too short, don't cut")
    advance.add_argument('--combine_files', action='store_true',
        help='combine all input files into one before editing.')
    advance.add_argument('--preview', action='store_true',
        help='show stats on how the input will be cut.')

    cutting = parser.add_argument_group('Cutting Options')
    cutting.add_argument('--cut_by_this_audio', '-ca', type=file_type, metavar='',
        help="base cuts by this audio file instead of the video's audio.")
    cutting.add_argument('--cut_by_this_track', '-ct', type=int, default=0, metavar='0',
        help='base cuts by a different audio track in the video.')
    cutting.add_argument('--cut_by_all_tracks', '-cat', action='store_true',
        help='combine all audio tracks into one before basing cuts.')
    cutting.add_argument('--keep_tracks_seperate', action='store_true',
        help="don't combine audio tracks when exporting.")

    debug = parser.add_argument_group('Developer/Debugging Options')
    debug.add_argument('--my_ffmpeg', action='store_true',
        help='use your ffmpeg and other binaries instead of the ones packaged.')
    debug.add_argument('--version', action='store_true',
        help='show which auto-editor you have.')
    debug.add_argument('--debug', '--verbose', action='store_true',
        help='show helpful debugging values.')

    misc = parser.add_argument_group('Export Options')
    misc.add_argument('--export_as_audio', '-exa', action='store_true',
        help='export as a WAV audio file.')
    misc.add_argument('--export_to_premiere', '-exp', action='store_true',
        help='export as an XML file for Adobe Premiere Pro instead of outputting a media file.')
    misc.add_argument('--export_to_resolve', '-exr', action='store_true',
        help='export as an XML file for DaVinci Resolve instead of outputting a media file.')

    size = parser.add_argument_group('Size Options')
    size.add_argument('--video_bitrate', '-vb', metavar='',
        help='set the number of bits per second for video.')
    size.add_argument('--audio_bitrate', '-ab', metavar='',
        help='set the number of bits per second for audio.')
    size.add_argument('--sample_rate', '-r', type=sample_rate_type, metavar='',
        help='set the sample rate of the input and output videos.')
    size.add_argument('--video_codec', '-vcodec', metavar='',
        help='set the video codec for the output file.')

    args = parser.parse_args()

    dirPath = os.path.dirname(os.path.realpath(__file__))
    # fixes pip not able to find other included modules.
    sys.path.append(os.path.abspath(dirPath))

    if(args.version):
        print('Auto-Editor version', version)
        sys.exit()

    if(args.export_to_premiere):
        print('Exporting to Adobe Premiere Pro XML file.')
    if(args.export_to_resolve):
        print('Exporting to DaVinci Resolve XML file.')
    if(args.export_as_audio):
        print('Exporting as audio.')

    newF = None
    newP = None
    if(platform.system() == 'Windows' and not args.my_ffmpeg):
        newF = os.path.join(dirPath, 'win-ffmpeg/bin/ffmpeg.exe')
        newP = os.path.join(dirPath, 'win-ffmpeg/bin/ffprobe.exe')
    if(platform.system() == 'Darwin' and not args.my_ffmpeg):
        newF = os.path.join(dirPath, 'mac-ffmpeg/bin/ffmpeg')
        newP = os.path.join(dirPath, 'mac-ffmpeg/bin/ffprobe')
    if(newF is not None and os.path.isfile(newF)):
        ffmpeg = newF
        ffprobe = newP
    else:
        ffmpeg = 'ffmpeg'
        ffprobe = 'ffprobe'

    makingDataFile = args.export_to_premiere or args.export_to_resolve

    is64bit = '64-bit' if sys.maxsize > 2**32 else '32-bit'

    if(args.debug):
        print('Python Version:', platform.python_version(), is64bit)
        print('Platform:', platform.system())
        # Platform can be 'Linux', 'Darwin' (macOS), 'Java', 'Windows'

        print('FFmpeg path:', ffmpeg)
        print('Auto-Editor version', version)
        if(args.input == []):
            sys.exit()

    from usefulFunctions import Log
    log = Log(3 if args.debug else 2)

    if(is64bit == '32-bit'):
        # I should have put this warning a long time ago.
        log.warning("You have the 32-bit version of Python, which means you won't be " \
            'able to handle long videos.')

    if(args.frame_margin < 0):
        log.error('Frame margin cannot be negative.')

    if(args.input == []):
        log.error('The following arguments are required: input\n' \
            'In other words, you need the path to a video or an audio file ' \
            'so that auto-editor can do the work for you.')

    if(args.silent_speed <= 0 or args.silent_speed > 99999):
        args.silent_speed = 99999
    if(args.video_speed <= 0 or args.video_speed > 99999):
        args.video_speed = 99999

    inputList = []
    for myInput in args.input:
        if(os.path.isdir(myInput)):
            def validFiles(path):
                for f in os.listdir(path):
                    if(not f.startswith('.') and not f.endswith('.xml')
                        and not f.endswith('.png') and not f.endswith('.md')
                        and not os.path.isdir(f)):
                        yield os.path.join(path, f)

            inputList += sorted(validFiles(myInput))
        elif(os.path.isfile(myInput)):
            inputList.append(myInput)
        elif(myInput.startswith('http://') or myInput.startswith('https://')):
            print('URL detected, using youtube-dl to download from webpage.')
            basename = re.sub(r'\W+', '-', myInput)
            cmd = ['youtube-dl', '-f', 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/mp4',
                   myInput, '--output', basename, '--no-check-certificate']
            if(ffmpeg != 'ffmpeg'):
                cmd.extend(['--ffmpeg-location', ffmpeg])
            subprocess.call(cmd)
            inputList.append(basename + '.mp4')
        else:
            log.error('Could not find file: ' + myInput)

    if(args.output_file is None):
        args.output_file = []

    if(len(args.output_file) < len(inputList)):
        for i in range(len(inputList) - len(args.output_file)):
            oldFile = inputList[i]
            dotIndex = oldFile.rfind('.')
            if(args.export_to_premiere or args.export_to_resolve):
                args.output_file.append(oldFile[:dotIndex] + '.xml')
            else:
                ext = oldFile[dotIndex:]
                if(args.export_as_audio):
                    ext = '.wav'
                end = '_ALTERED' + ext
                args.output_file.append(oldFile[:dotIndex] + end)

    TEMP = tempfile.mkdtemp()

    if(args.combine_files):
        with open(f'{TEMP}/combines.txt', 'w') as outfile:
            for fileref in inputList:
                outfile.write(f"file '{fileref}'\n")

        cmd = [ffmpeg, '-f', 'concat', '-safe', '0', '-i', f'{TEMP}/combines.txt',
            '-c', 'copy', 'combined.mp4']
        subprocess.call(cmd)
        inputList = ['combined.mp4']


    speeds = [args.silent_speed, args.video_speed]

    startTime = time.time()

    from usefulFunctions import isAudioFile, vidTracks, conwrite, getAudioChunks
    from wavfile import read, write

    numCuts = 0
    for i, INPUT_FILE in enumerate(inputList):
        newOutput = args.output_file[i]
        fileFormat = INPUT_FILE[INPUT_FILE.rfind('.'):]

        # Grab the sample rate from the input.
        sr = args.sample_rate
        if(sr is None):
            output = pipeToConsole([ffmpeg, '-i', INPUT_FILE, '-hide_banner'])
            try:
                matchDict = re.search(r'\s(?P<grp>\w+?)\sHz', output).groupdict()
                sr = matchDict['grp']
            except AttributeError:
                sr = 48000
        args.sample_rate = sr

        # Grab the audio bitrate from the input.
        abit = args.audio_bitrate
        if(abit is None):
            output = pipeToConsole([ffprobe, '-v', 'error', '-select_streams',
                'a:0', '-show_entries', 'stream=bit_rate', '-of',
                'compact=p=0:nk=1', INPUT_FILE])
            try:
                abit = int(output)
            except:
                log.warning("Couldn't automatically detect audio bitrate.")
                abit = '500k'
                log.debug('Setting audio bitrate to ' + abit)
            else:
                abit = str(round(abit / 1000)) + 'k'
        else:
            abit = str(abit)
        args.audio_bitrate = abit

        if(isAudioFile(INPUT_FILE)):
            fps = 30
            tracks = 1
            cmd = [ffmpeg, '-y', '-i', INPUT_FILE, '-b:a', args.audio_bitrate, '-ac', '2',
                '-ar', str(args.sample_rate), '-vn', f'{TEMP}/fastAud.wav']
            if(args.debug):
                cmd.extend(['-hide_banner'])
            else:
                cmd.extend(['-nostats', '-loglevel', '0'])
            subprocess.call(cmd)

            sampleRate, audioData = read(f'{TEMP}/fastAud.wav')
        else:
            if(args.export_to_premiere):
                fps = 29.97
            else:
                fps = ffmpegFPS(ffmpeg, INPUT_FILE, log)
            tracks = vidTracks(INPUT_FILE, ffprobe, log)
            if(args.cut_by_this_track >= tracks):
                log.error("You choose a track that doesn't exist.\n" \
                    f'There are only {tracks-1} tracks. (starting from 0)')

            vcodec = args.video_codec
            if(vcodec is None):
                output = pipeToConsole([ffmpeg, '-i', INPUT_FILE, '-hide_banner'])
                try:
                    matchDict = re.search(r'Video:\s(?P<video>\w+?)\s', output).groupdict()
                    vcodec = matchDict['video']
                    log.debug(vcodec)
                except AttributeError:
                    vcodec = 'copy'
                    log.warning("Couldn't automatically detect the video codec.")

            vbit = args.video_bitrate
            if(vbit is None):
                output = pipeToConsole([ffprobe, '-v', 'error', '-select_streams',
                    'v:0', '-show_entries', 'stream=bit_rate', '-of',
                    'compact=p=0:nk=1', INPUT_FILE])
                try:
                    vbit = int(output)
                except:
                    log.warning("Couldn't automatically detect video bitrate.")
                    vbit = '500k'
                    log.debug('Setting vbit to ' + vbit)
                else:
                    vbit += 300 * 1000 # Add more for better quality.
                    vbit = str(round(vbit / 1000)) + 'k'
            else:
                vbit = str(vbit)
                if(vcodec == 'copy'):
                    log.warning('Your bitrate will not be applied because' \
                        ' the video codec is "copy".')
            args.video_bitrate = vbit

            for trackNum in range(tracks):
                cmd = [ffmpeg, '-y', '-i', INPUT_FILE, '-ab', args.audio_bitrate,
                '-ac', '2', '-ar', str(args.sample_rate), '-map', f'0:a:{trackNum}',
                f'{TEMP}/{trackNum}.wav']
                if(args.debug):
                    cmd.extend(['-hide_banner'])
                else:
                    cmd.extend(['-nostats', '-loglevel', '0'])
                subprocess.call(cmd)

            if(args.cut_by_all_tracks):
                cmd = [ffmpeg, '-y', '-i', INPUT_FILE, '-filter_complex',
                    f'[0:a]amerge=inputs={tracks}', '-map', 'a', '-ar',
                    str(args.sample_rate), '-ac', '2', '-f', 'wav', f'{TEMP}/combined.wav']
                if(args.debug):
                    cmd.extend(['-hide_banner'])
                else:
                    cmd.extend(['-nostats', '-loglevel', '0'])

                subprocess.call(cmd)

                sampleRate, audioData = read(f'{TEMP}/combined.wav')
            else:
                if(os.path.isfile(f'{TEMP}/{args.cut_by_this_track}.wav')):
                    sampleRate, audioData = read(f'{TEMP}/{args.cut_by_this_track}.wav')
                else:
                    log.error('Audio track not found!')

        chunks = getAudioChunks(audioData, sampleRate, fps, args.silent_threshold,
            args.frame_margin, args.min_clip_length, args.min_cut_length, log)

        clips = []
        for chunk in chunks:
            if(speeds[chunk[2]] == 99999):
                numCuts += 1
            else:
                clips.append([chunk[0], chunk[1], speeds[chunk[2]] * 100])

        if(fps is None and not isAudioFile(INPUT_FILE)):
            if(makingDataFile):
                dotIndex = INPUT_FILE.rfind('.')
                end = '_constantFPS' + oldFile[dotIndex:]
                constantLoc = oldFile[:dotIndex] + end
            else:
                constantLoc = f'{TEMP}/constantVid{fileFormat}'
            cmd = [ffmpeg, '-y', '-i', INPUT_FILE, '-filter:v', f'fps=fps=30', constantLoc]
            if(args.debug):
                cmd.extend(['-hide_banner'])
            else:
                cmd.extend(['-nostats', '-loglevel', '0'])
            subprocess.call(cmd)
            INPUT_FILE = constancLoc

        if(args.preview):
            args.no_open = True
            from preview import preview

            preview(INPUT_FILE, chunks, speeds, args.debug)
            continue

        if(args.export_to_premiere):
            args.no_open = True
            from premiere import exportToPremiere

            exportToPremiere(INPUT_FILE, TEMP, newOutput, clips, tracks, sampleRate, log)
            continue
        if(args.export_to_resolve):
            args.no_open = True
            duration = chunks[len(chunks) - 1][1]
            from resolve import exportToResolve

            exportToResolve(INPUT_FILE, newOutput, clips, duration, sampleRate, log)
            continue
        if(isAudioFile(INPUT_FILE) and not makingDataFile):
            from fastAudio import fastAudio

            fastAudio(ffmpeg, INPUT_FILE, newOutput, chunks, speeds, args.audio_bitrate,
            sampleRate, args.debug, True, log)
            continue

        from fastVideo import fastVideo
        fastVideo(ffmpeg, INPUT_FILE, newOutput, chunks, speeds, tracks,
            args.audio_bitrate, sampleRate, args.debug, TEMP,
            args.keep_tracks_seperate, vcodec, fps, args.export_as_audio,
            args.video_bitrate, log)

    if(not os.path.isfile(newOutput)):
        log.error(f'The file {newOutput} was not created.')

    if(not args.preview and not makingDataFile):
        timeLength = round(time.time() - startTime, 2)
        minutes = timedelta(seconds=round(timeLength))
        print(f'Finished. took {timeLength} seconds ({minutes})')

    if(not args.preview and makingDataFile):
        timeSave = numCuts * 2 # assuming making each cut takes about 2 seconds.
        units = 'seconds'
        if(timeSave >= 3600):
            timeSave = round(timeSave / 3600, 1)
            if(timeSave % 1 == 0):
                timeSave = round(timeSave)
            units = 'hours'
        if(timeSave >= 60):
            timeSave = round(timeSave / 60, 1)
            if(timeSave >= 10 or timeSave % 1 == 0):
                timeSave = round(timeSave)
            units = 'minutes'

        print(f'Auto-Editor made {numCuts} cuts', end='') # Don't add a newline.
        if(numCuts > 4):
            print(f', which would have taken about {timeSave} {units} if edited manually.')
        else:
            print('.')

    if(not args.no_open):
        try:  # should work on Windows
            os.startfile(newOutput)
        except AttributeError:
            try:  # should work on MacOS and most Linux versions
                subprocess.call(['open', newOutput])
            except:
                try: # should work on WSL2
                    subprocess.call(['cmd.exe', '/C', 'start', newOutput])
                except:
                    log.warning('Could not open output file.')
    rmtree(TEMP)
Exemplo n.º 3
0
def main():
    options = []
    option_names = []

    def add_argument(*names,
                     nargs=1,
                     type=str,
                     default=None,
                     action='default',
                     range=None,
                     choices=None,
                     help='',
                     extra=''):
        nonlocal options
        nonlocal option_names

        newDic = {}
        newDic['names'] = names
        newDic['nargs'] = nargs
        newDic['type'] = type
        newDic['default'] = default
        newDic['action'] = action
        newDic['help'] = help
        newDic['extra'] = extra
        newDic['range'] = range
        newDic['choices'] = choices
        options.append(newDic)
        option_names = option_names + list(names)

    add_argument('(input)',
                 nargs='*',
                 help='the path to a file, folder, or url you want edited.')
    add_argument('--help',
                 '-h',
                 action='store_true',
                 help='print this message and exit.')

    add_argument(
        '--frame_margin',
        '-m',
        type=int,
        default=6,
        range='0 to Infinity',
        help=
        'set how many "silent" frames of on either side of "loud" sections be included.'
    )
    add_argument(
        '--silent_threshold',
        '-t',
        type=float_type,
        default=0.04,
        range='0 to 1',
        help='set the volume that frames audio needs to surpass to be "loud".')
    add_argument(
        '--video_speed',
        '--sounded_speed',
        '-v',
        type=float_type,
        default=1.00,
        range='0 to 999999',
        help='set the speed that "loud" sections should be played at.')
    add_argument(
        '--silent_speed',
        '-s',
        type=float_type,
        default=99999,
        range='0 to 99999',
        help='set the speed that "silent" sections should be played at.')
    add_argument('--output_file',
                 '-o',
                 nargs='*',
                 help='set the name(s) of the new output.')

    add_argument('--no_open',
                 action='store_true',
                 help='do not open the file after editing is done.')
    add_argument(
        '--min_clip_length',
        '-mclip',
        type=int,
        default=3,
        range='0 to Infinity',
        help=
        'set the minimum length a clip can be. If a clip is too short, cut it.'
    )
    add_argument(
        '--min_cut_length',
        '-mcut',
        type=int,
        default=6,
        range='0 to Infinity',
        help=
        "set the minimum length a cut can be. If a cut is too short, don't cut"
    )
    add_argument('--combine_files',
                 action='store_true',
                 help='combine all input files into one before editing.')
    add_argument('--preview',
                 action='store_true',
                 help='show stats on how the input will be cut.')

    add_argument(
        '--cut_by_this_audio',
        '-ca',
        type=file_type,
        help="base cuts by this audio file instead of the video's audio.")
    add_argument('--cut_by_this_track',
                 '-ct',
                 type=int,
                 default=0,
                 range='0 to the number of audio tracks',
                 help='base cuts by a different audio track in the video.')
    add_argument('--cut_by_all_tracks',
                 '-cat',
                 action='store_true',
                 help='combine all audio tracks into one before basing cuts.')
    add_argument('--keep_tracks_seperate',
                 action='store_true',
                 help="don't combine audio tracks when exporting.")

    add_argument(
        '--my_ffmpeg',
        action='store_true',
        help='use your ffmpeg and other binaries instead of the ones packaged.'
    )
    add_argument('--version',
                 action='store_true',
                 help='show which auto-editor you have.')
    add_argument('--debug',
                 '--verbose',
                 action='store_true',
                 help='show helpful debugging values.')

    # TODO: add export_as_video
    add_argument('--export_as_audio',
                 '-exa',
                 action='store_true',
                 help='export as a WAV audio file.')
    add_argument(
        '--export_to_premiere',
        '-exp',
        action='store_true',
        help=
        'export as an XML file for Adobe Premiere Pro instead of outputting a media file.'
    )
    add_argument(
        '--export_to_resolve',
        '-exr',
        action='store_true',
        help=
        'export as an XML file for DaVinci Resolve instead of outputting a media file.'
    )

    add_argument('--video_bitrate',
                 '-vb',
                 help='set the number of bits per second for video.')
    add_argument('--audio_bitrate',
                 '-ab',
                 help='set the number of bits per second for audio.')
    add_argument('--sample_rate',
                 '-r',
                 type=sample_rate_type,
                 help='set the sample rate of the input and output videos.')
    add_argument('--video_codec',
                 '-vcodec',
                 help='set the video codec for the output file.')
    add_argument(
        '--preset',
        '-p',
        default='medium',
        choices=[
            'ultrafast', 'superfast', 'veryfast', 'faster', 'fast', 'medium',
            'slow', 'slower', 'veryslow'
        ],
        help=
        'set the preset for ffmpeg to help save file size or increase quality.'
    )
    add_argument('--tune',
                 default='none',
                 choices=[
                     'film', 'animation', 'grain', 'stillimage', 'fastdecode',
                     'zerolatency', 'none'
                 ],
                 help='set the tune for ffmpeg to help compress video better.')

    add_argument(
        '--ignore',
        nargs='*',
        help=
        "the range (in seconds) that shouldn't be edited at all. (uses range syntax)"
    )
    add_argument('--cut_out', nargs='*',
        help='the range (in seconds) that should be cut out completely, '\
            'regardless of anything else. (uses range syntax)')

    dirPath = os.path.dirname(os.path.realpath(__file__))
    # Fixes pip not able to find other included modules.
    sys.path.append(os.path.abspath(dirPath))

    from usefulFunctions import Log

    class parse_options():
        def __init__(self, userArgs, log, *args):
            # Set the default options.
            for options in args:
                for option in options:
                    key = option['names'][0].replace('-', '')
                    if (option['action'] == 'store_true'):
                        value = False
                    elif (option['nargs'] != 1):
                        value = []
                    else:
                        value = option['default']
                    setattr(self, key, value)

            def get_option(item, the_args):
                for options in the_args:
                    for option in options:
                        if (item in option['names']):
                            return option
                return None

            # Figure out attributes changed by user.
            myList = []
            settingInputs = True
            optionList = 'input'
            i = 0
            while i < len(userArgs):
                item = userArgs[i]
                if (i == len(userArgs) - 1):
                    nextItem = None
                else:
                    nextItem = userArgs[i + 1]

                option = get_option(item, args)

                if (option is not None):
                    if (optionList is not None):
                        setattr(self, optionList, myList)
                    settingInputs = False
                    optionList = None
                    myList = []

                    key = option['names'][0].replace('-', '')

                    # show help for specific option.
                    if (nextItem == '-h' or nextItem == '--help'):
                        print(' ', ', '.join(option['names']))
                        print('   ', option['help'])
                        print('   ', option['extra'])
                        if (option['action'] == 'default'):
                            print('    type:', option['type'].__name__)
                            print('    default:', option['default'])
                            if (option['range'] is not None):
                                print('    range:', option['range'])
                            if (option['choices'] is not None):
                                print('    choices:',
                                      ', '.join(option['choices']))
                        else:
                            print(f'    type: flag')
                        sys.exit()

                    if (option['nargs'] != 1):
                        settingInputs = True
                        optionList = key
                    elif (option['action'] == 'store_true'):
                        value = True
                    else:
                        try:
                            # Convert to correct type.
                            value = option['type'](nextItem)
                        except:
                            typeName = option['type'].__name__
                            log.error(
                                f'Couldn\'t convert "{nextItem}" to {typeName}'
                            )
                        if (option['choices'] is not None):
                            if (value not in option['choices']):
                                log.error(
                                    f'{value} is not a choice for {option}')
                        i += 1
                    setattr(self, key, value)
                else:
                    if (settingInputs and not item.startswith('-')):
                        # Input file names
                        myList.append(item)
                    else:
                        # Unknown Option!
                        hmm = difflib.get_close_matches(item, option_names)
                        potential_options = ', '.join(hmm)
                        append = ''
                        if (hmm != []):
                            append = f'\n\n    Did you mean:\n        {potential_options}'
                        log.error(f'Unknown option: {item}{append}')
                i += 1
            if (settingInputs):
                setattr(self, optionList, myList)

    args = parse_options(sys.argv[1:], Log(3), options)

    # Print help screen for entire program.
    if (args.help):
        for option in options:
            print(' ', ', '.join(option['names']) + ':', option['help'])
        print('\nHave an issue? Make an issue. '\
            'Visit https://github.com/wyattblue/auto-editor/issues')
        sys.exit()

    if (args.version):
        print('Auto-Editor version', version)
        sys.exit()

    from usefulFunctions import isAudioFile, vidTracks, conwrite, getAudioChunks
    from wavfile import read, write

    if (not args.preview):
        if (args.export_to_premiere):
            conwrite('Exporting to Adobe Premiere Pro XML file.')
        elif (args.export_to_resolve):
            conwrite('Exporting to DaVinci Resolve XML file.')
        elif (args.export_as_audio):
            conwrite('Exporting as audio.')
        else:
            conwrite('Starting.')

    newF = None
    newP = None
    if (platform.system() == 'Windows' and not args.my_ffmpeg):
        newF = os.path.join(dirPath, 'win-ffmpeg/bin/ffmpeg.exe')
        newP = os.path.join(dirPath, 'win-ffmpeg/bin/ffprobe.exe')
    if (platform.system() == 'Darwin' and not args.my_ffmpeg):
        newF = os.path.join(dirPath, 'mac-ffmpeg/bin/ffmpeg')
        newP = os.path.join(dirPath, 'mac-ffmpeg/bin/ffprobe')
    if (newF is not None and os.path.isfile(newF)):
        ffmpeg = newF
        ffprobe = newP
    else:
        ffmpeg = 'ffmpeg'
        ffprobe = 'ffprobe'

    makingDataFile = args.export_to_premiere or args.export_to_resolve

    is64bit = '64-bit' if sys.maxsize > 2**32 else '32-bit'

    if (args.debug):
        print('Python Version:', platform.python_version(), is64bit)
        print('Platform:', platform.system())
        # Platform can be 'Linux', 'Darwin' (macOS), 'Java', 'Windows'

        print('FFmpeg path:', ffmpeg)
        print('Auto-Editor version', version)
        if (args.input == []):
            sys.exit()

    log = Log(3 if args.debug else 2)

    if (is64bit == '32-bit'):
        # I should have put this warning a long time ago.
        log.warning("You have the 32-bit version of Python, which means you won't be " \
            'able to handle long videos.')

    if (args.frame_margin < 0):
        log.error('Frame margin cannot be negative.')

    if (args.input == []):
        log.error(
            'You need the (input) argument so that auto-editor can do the work for you.'
        )

    if (args.silent_speed <= 0 or args.silent_speed > 99999):
        args.silent_speed = 99999
    if (args.video_speed <= 0 or args.video_speed > 99999):
        args.video_speed = 99999

    inputList = []
    for myInput in args.input:
        if (os.path.isdir(myInput)):

            def validFiles(path):
                for f in os.listdir(path):
                    if (not f.startswith('.') and not f.endswith('.xml')
                            and not f.endswith('.png')
                            and not f.endswith('.md')
                            and not os.path.isdir(f)):
                        yield os.path.join(path, f)

            inputList += sorted(validFiles(myInput))
        elif (os.path.isfile(myInput)):
            inputList.append(myInput)
        elif (myInput.startswith('http://') or myInput.startswith('https://')):
            print('URL detected, using youtube-dl to download from webpage.')
            basename = re.sub(r'\W+', '-', myInput)
            cmd = [
                'youtube-dl', '-f',
                'bestvideo[ext=mp4]+bestaudio[ext=m4a]/mp4', myInput,
                '--output', basename, '--no-check-certificate'
            ]
            if (ffmpeg != 'ffmpeg'):
                cmd.extend(['--ffmpeg-location', ffmpeg])
            subprocess.call(cmd)
            inputList.append(basename + '.mp4')
        else:
            log.error('Could not find file: ' + myInput)

    if (args.output_file is None):
        args.output_file = []

    if (len(args.output_file) < len(inputList)):
        for i in range(len(inputList) - len(args.output_file)):
            oldFile = inputList[i]
            dotIndex = oldFile.rfind('.')
            if (args.export_to_premiere or args.export_to_resolve):
                args.output_file.append(oldFile[:dotIndex] + '.xml')
            else:
                ext = oldFile[dotIndex:]
                if (args.export_as_audio):
                    ext = '.wav'
                end = '_ALTERED' + ext
                args.output_file.append(oldFile[:dotIndex] + end)

    TEMP = tempfile.mkdtemp()

    if (args.combine_files):
        with open(f'{TEMP}/combines.txt', 'w') as outfile:
            for fileref in inputList:
                outfile.write(f"file '{fileref}'\n")

        cmd = [
            ffmpeg, '-f', 'concat', '-safe', '0', '-i', f'{TEMP}/combines.txt',
            '-c', 'copy', 'combined.mp4'
        ]
        subprocess.call(cmd)
        inputList = ['combined.mp4']

    speeds = [args.silent_speed, args.video_speed]

    startTime = time.time()

    numCuts = 0
    for i, INPUT_FILE in enumerate(inputList):
        newOutput = args.output_file[i]
        fileFormat = INPUT_FILE[INPUT_FILE.rfind('.'):]

        # Grab the sample rate from the input.
        sr = args.sample_rate
        if (sr is None):
            output = pipeToConsole([ffmpeg, '-i', INPUT_FILE, '-hide_banner'])
            try:
                matchDict = re.search(r'\s(?P<grp>\w+?)\sHz',
                                      output).groupdict()
                sr = matchDict['grp']
            except AttributeError:
                sr = 48000
        args.sample_rate = sr

        # Grab the audio bitrate from the input.
        abit = args.audio_bitrate
        if (abit is None):
            output = pipeToConsole([
                ffprobe, '-v', 'error', '-select_streams', 'a:0',
                '-show_entries', 'stream=bit_rate', '-of', 'compact=p=0:nk=1',
                INPUT_FILE
            ])
            try:
                abit = int(output)
            except:
                log.warning("Couldn't automatically detect audio bitrate.")
                abit = '500k'
                log.debug('Setting audio bitrate to ' + abit)
            else:
                abit = str(round(abit / 1000)) + 'k'
        else:
            abit = str(abit)
        args.audio_bitrate = abit

        if (isAudioFile(INPUT_FILE)):
            fps = 30
            tracks = 1
            cmd = [
                ffmpeg, '-y', '-i', INPUT_FILE, '-b:a', args.audio_bitrate,
                '-ac', '2', '-ar',
                str(args.sample_rate), '-vn', f'{TEMP}/fastAud.wav'
            ]
            if (args.debug):
                cmd.extend(['-hide_banner'])
            else:
                cmd.extend(['-nostats', '-loglevel', '0'])
            subprocess.call(cmd)

            sampleRate, audioData = read(f'{TEMP}/fastAud.wav')
        else:
            if (args.export_to_premiere):
                fps = 29.97
            else:
                fps = ffmpegFPS(ffmpeg, INPUT_FILE, log)
            tracks = vidTracks(INPUT_FILE, ffprobe, log)
            if (args.cut_by_this_track >= tracks):
                log.error("You choose a track that doesn't exist.\n" \
                    f'There are only {tracks-1} tracks. (starting from 0)')

            vcodec = args.video_codec
            if (vcodec is None):
                output = pipeToConsole(
                    [ffmpeg, '-i', INPUT_FILE, '-hide_banner'])
                try:
                    matchDict = re.search(r'Video:\s(?P<video>\w+?)\s',
                                          output).groupdict()
                    vcodec = matchDict['video']
                    log.debug(vcodec)
                except AttributeError:
                    vcodec = 'copy'
                    log.warning(
                        "Couldn't automatically detect the video codec.")

            if (args.video_bitrate is not None and vcodec == 'copy'):
                log.warning('Your bitrate will not be applied because' \
                        ' the video codec is "copy".')

            for trackNum in range(tracks):
                cmd = [
                    ffmpeg, '-y', '-i', INPUT_FILE, '-ab', args.audio_bitrate,
                    '-ac', '2', '-ar',
                    str(args.sample_rate), '-map', f'0:a:{trackNum}',
                    f'{TEMP}/{trackNum}.wav'
                ]
                if (args.debug):
                    cmd.extend(['-hide_banner'])
                else:
                    cmd.extend(['-nostats', '-loglevel', '0'])
                subprocess.call(cmd)

            if (args.cut_by_all_tracks):
                cmd = [
                    ffmpeg, '-y', '-i', INPUT_FILE, '-filter_complex',
                    f'[0:a]amerge=inputs={tracks}', '-map', 'a', '-ar',
                    str(args.sample_rate), '-ac', '2', '-f', 'wav',
                    f'{TEMP}/combined.wav'
                ]
                if (args.debug):
                    cmd.extend(['-hide_banner'])
                else:
                    cmd.extend(['-nostats', '-loglevel', '0'])

                subprocess.call(cmd)

                sampleRate, audioData = read(f'{TEMP}/combined.wav')
            else:
                if (os.path.isfile(f'{TEMP}/{args.cut_by_this_track}.wav')):
                    sampleRate, audioData = read(
                        f'{TEMP}/{args.cut_by_this_track}.wav')
                else:
                    log.error('Audio track not found!')

        chunks = getAudioChunks(audioData, sampleRate, fps,
                                args.silent_threshold, args.frame_margin,
                                args.min_clip_length, args.min_cut_length,
                                args.ignore, args.cut_out, log)

        clips = []
        for chunk in chunks:
            if (speeds[chunk[2]] == 99999):
                numCuts += 1
            else:
                clips.append([chunk[0], chunk[1], speeds[chunk[2]] * 100])

        if (fps is None and not isAudioFile(INPUT_FILE)):
            if (makingDataFile):
                dotIndex = INPUT_FILE.rfind('.')
                end = '_constantFPS' + oldFile[dotIndex:]
                constantLoc = oldFile[:dotIndex] + end
            else:
                constantLoc = f'{TEMP}/constantVid{fileFormat}'
            cmd = [
                ffmpeg, '-y', '-i', INPUT_FILE, '-filter:v', f'fps=fps=30',
                constantLoc
            ]
            if (args.debug):
                cmd.extend(['-hide_banner'])
            else:
                cmd.extend(['-nostats', '-loglevel', '0'])
            subprocess.call(cmd)
            INPUT_FILE = constancLoc

        if (args.preview):
            args.no_open = True
            from preview import preview

            preview(INPUT_FILE, chunks, speeds, args.debug)
            continue

        if (args.export_to_premiere):
            args.no_open = True
            from premiere import exportToPremiere

            exportToPremiere(INPUT_FILE, TEMP, newOutput, clips, tracks,
                             sampleRate, log)
            continue
        if (args.export_to_resolve):
            args.no_open = True
            duration = chunks[len(chunks) - 1][1]
            from resolve import exportToResolve

            exportToResolve(INPUT_FILE, newOutput, clips, duration, sampleRate,
                            log)
            continue
        if (isAudioFile(INPUT_FILE) and not makingDataFile):
            from fastAudio import fastAudio

            fastAudio(ffmpeg, INPUT_FILE, newOutput, chunks, speeds,
                      args.audio_bitrate, sampleRate, args.debug, True, log)
            continue

        from fastVideo import fastVideo
        fastVideo(ffmpeg, INPUT_FILE, newOutput, chunks, speeds, tracks,
                  args.audio_bitrate, sampleRate, args.debug, TEMP,
                  args.keep_tracks_seperate, vcodec, fps, args.export_as_audio,
                  args.video_bitrate, args.preset, args.tune, log)

    if (not os.path.isfile(newOutput)):
        log.error(f'The file {newOutput} was not created.')

    if (not args.preview and not makingDataFile):
        timeLength = round(time.time() - startTime, 2)
        minutes = timedelta(seconds=round(timeLength))
        print(f'Finished. took {timeLength} seconds ({minutes})')

    if (not args.preview and makingDataFile):
        timeSave = numCuts * 2  # assuming making each cut takes about 2 seconds.
        units = 'seconds'
        if (timeSave >= 3600):
            timeSave = round(timeSave / 3600, 1)
            if (timeSave % 1 == 0):
                timeSave = round(timeSave)
            units = 'hours'
        if (timeSave >= 60):
            timeSave = round(timeSave / 60, 1)
            if (timeSave >= 10 or timeSave % 1 == 0):
                timeSave = round(timeSave)
            units = 'minutes'

        print(f'Auto-Editor made {numCuts} cuts',
              end='')  # Don't add a newline.
        if (numCuts > 4):
            print(
                f', which would have taken about {timeSave} {units} if edited manually.'
            )
        else:
            print('.')

    if (not args.no_open):
        try:  # should work on Windows
            os.startfile(newOutput)
        except AttributeError:
            try:  # should work on MacOS and most Linux versions
                subprocess.call(['open', newOutput])
            except:
                try:  # should work on WSL2
                    subprocess.call(['cmd.exe', '/C', 'start', newOutput])
                except:
                    log.warning('Could not open output file.')
    rmtree(TEMP)
Exemplo n.º 4
0
def fastAudio(ffmpeg,
              theFile,
              outFile,
              silentT,
              frameMargin,
              SAMPLE_RATE,
              audioBit,
              verbose,
              silentSpeed,
              soundedSpeed,
              needConvert,
              chunks=[],
              fps=30):

    if (not os.path.isfile(theFile)):
        print('Could not find file:', theFile)
        sys.exit(1)

    if (outFile == ''):
        fileName = theFile[:theFile.rfind('.')]
        outFile = f'{fileName}_ALTERED.wav'

    if (needConvert):
        # Only print this here so other scripts can use this function.
        print('Running from fastAudio.py')

        import tempfile
        from shutil import rmtree

        TEMP = tempfile.mkdtemp()

        cmd = [
            ffmpeg, '-i', theFile, '-b:a', audioBit, '-ac', '2', '-ar',
            str(SAMPLE_RATE), '-vn', f'{TEMP}/fastAud.wav'
        ]
        if (not verbose):
            cmd.extend(['-nostats', '-loglevel', '0'])
        subprocess.call(cmd)

        theFile = f'{TEMP}/fastAud.wav'

    speeds = [silentSpeed, soundedSpeed]

    sampleRate, audioData = read(theFile)
    if (chunks == []):
        print('Creating chunks')
        chunks = getAudioChunks(audioData, sampleRate, fps, silentT, 2,
                                frameMargin)

    newL = getNewLength(chunks, speeds, fps)
    # Get the new length in samples with some extra leeway.
    estLeng = int((newL * sampleRate) * 1.5) + int(sampleRate * 2)

    # Create an empty array for the new audio.
    newAudio = np.zeros((estLeng, 2), dtype=np.int16)

    channels = 2
    yPointer = 0

    totalChunks = len(chunks)
    beginTime = time.time()

    for chunkNum, chunk in enumerate(chunks):
        audioSampleStart = int(chunk[0] / fps * sampleRate)
        audioSampleEnd = int(audioSampleStart + (sampleRate / fps) *
                             (chunk[1] - chunk[0]))

        theSpeed = speeds[chunk[2]]

        if (theSpeed != 99999):
            spedChunk = audioData[audioSampleStart:audioSampleEnd]

            if (theSpeed == 1):
                yPointerEnd = yPointer + spedChunk.shape[0]
                newAudio[yPointer:yPointerEnd] = spedChunk
            else:
                spedupAudio = np.zeros((0, 2), dtype=np.int16)
                with ArrReader(spedChunk, channels, sampleRate, 2) as reader:
                    with ArrWriter(spedupAudio, channels, sampleRate,
                                   2) as writer:
                        phasevocoder(reader.channels,
                                     speed=theSpeed).run(reader, writer)
                        spedupAudio = writer.output

                yPointerEnd = yPointer + spedupAudio.shape[0]
                newAudio[yPointer:yPointerEnd] = spedupAudio

            myL = chunk[1] - chunk[0]
            mySamples = (myL / fps) * sampleRate
            newSamples = int(mySamples / theSpeed)

            yPointer = yPointer + newSamples
        else:
            # Speed is too high so skip this section.
            yPointerEnd = yPointer

        progressBar(chunkNum,
                    totalChunks,
                    beginTime,
                    title='Creating new audio')

    if (verbose):
        print('yPointer', yPointer)
        print('samples per frame', sampleRate / fps)
        print('Expected video length', yPointer / (sampleRate / fps))
    newAudio = newAudio[:yPointer]
    write(outFile, sampleRate, newAudio)

    if ('TEMP' in locals()):
        rmtree(TEMP)

    if (needConvert):
        return outFile
Exemplo n.º 5
0
def preview(ffmpeg, myInput, silentT, zoomT, frameMargin, sampleRate, videoSpeed,
        silentSpeed, cutByThisTrack, bitrate):
    TEMP = tempfile.mkdtemp()

    extension = myInput[myInput.rfind('.'):]
    audioFile = extension in ['.wav', '.mp3', '.m4a']

    if(audioFile):
        fps = 30

        cmd = [ffmpeg, '-i', myInput, '-b:a', bitrate, '-ac', '2', '-ar',
            str(sampleRate), '-vn', f'{TEMP}/fastAud.wav', '-nostats', '-loglevel', '0']
        subprocess.call(cmd)

        sampleRate, audioData = read(f'{TEMP}/fastAud.wav')
        chunks = getAudioChunks(audioData, sampleRate, fps, silentT, 2, frameMargin)
    else:
        import cv2

        cap = cv2.VideoCapture(myInput)
        fps = cap.get(cv2.CAP_PROP_FPS)

        tracks = vidTracks(myInput, ffmpeg)

        if(cutByThisTrack >= tracks):
            print("Error! You choose a track that doesn't exist.")
            print(f'There are only {tracks-1} tracks. (starting from 0)')
            sys.exit(1)

        for trackNumber in range(tracks):
            cmd = [ffmpeg, '-i', myInput, '-ab', bitrate, '-ac', '2', '-ar',
                str(sampleRate),'-map', f'0:a:{trackNumber}',  f'{TEMP}/{trackNumber}.wav',
                '-nostats', '-loglevel', '0']
            subprocess.call(cmd)

            sampleRate, audioData = read(f'{TEMP}/{cutByThisTrack}.wav')
            chunks = getAudioChunks(audioData, sampleRate, fps, silentT, 2, frameMargin)

    rmtree(TEMP)

    def printTimeFrame(title, frames, fps):
        inSec = round(frames / fps, 1)
        if(fps % 1 == 0):
            fps = round(fps)
        if(inSec < 1):
            minutes = f'{int(frames)}/{fps} frames'
        else:
            minutes = timedelta(seconds=round(inSec))
        print(f'{title}: {inSec} secs ({minutes})')


    oldTime = chunks[len(chunks)-1][1]
    printTimeFrame('Old length', oldTime, fps)

    speeds = [silentSpeed, videoSpeed]
    newL = getNewLength(chunks, speeds, fps)
    printTimeFrame('New length', newL * fps, fps)

    clips = 0
    cuts = 0
    clipLengths = []
    for chunk in chunks:
        state = chunk[2]
        if(speeds[state] != 99999):
            clips += 1
            leng = (chunk[1] - chunk[0]) / speeds[state]
            clipLengths.append(leng)
        else:
            cuts += 1

    print('Number of clips:', clips)
    #print('Number of cuts:', cuts)
    printTimeFrame('Smallest clip length', min(clipLengths), fps)
    printTimeFrame('Largest clip length', max(clipLengths), fps)
    printTimeFrame('Average clip length', sum(clipLengths) / len(clipLengths), fps)
Exemplo n.º 6
0
def exportToPremiere(ffmpeg, myInput, newOutput, silentT, zoomT, frameMargin,
                     sampleRate, videoSpeed, silentSpeed):
    print('Running from premiere.py')
    TEMP = tempfile.mkdtemp()

    fps = 29.97

    cmd = [
        ffmpeg, '-i', myInput, '-ab', '160k', '-ac', '2', '-ar',
        str(sampleRate), '-vn', f'{TEMP}/output.wav', '-nostats', '-loglevel',
        '0'
    ]
    subprocess.call(cmd)

    sampleRate, audioData = read(f'{TEMP}/output.wav')
    chunks = getAudioChunks(audioData, sampleRate, fps, silentT, zoomT,
                            frameMargin)
    rmtree(TEMP)

    clips = []
    newSpeed = [silentSpeed, videoSpeed]
    for chunk in chunks:
        if (newSpeed[chunk[2]] != 99999):
            clips.append([chunk[0], chunk[1], newSpeed[chunk[2]] * 100])

    if (len(clips) < 1):
        print('Error! Less than 1 clip.')
        sys.exit(1)

    pathurl = 'file://localhost' + os.path.abspath(myInput)

    name = os.path.basename(myInput)

    extension = myInput[myInput.rfind('.'):]
    audioFile = extension in ['.wav', '.mp3', '.m4a']

    first = myInput[:myInput.rfind('.')]
    newFile = f'{first}.xml'

    ntsc = 'FALSE'
    ana = 'FALSE'  # anamorphic
    alphatype = 'none'
    depth = '16'
    if (not audioFile):
        try:
            import cv2
            conwrite('Grabbing video dimensions.')

            cap = cv2.VideoCapture(myInput)
            width = str(int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)))
            height = str(int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))

            cap.release()
            cv2.destroyAllWindows()

        except ImportError:
            width = '1280'
            height = '720'

    pixelar = 'square'  # pixel aspect ratio
    colordepth = '24'
    sr = sampleRate

    if (audioFile):
        with open(newFile, 'w', encoding='utf-8') as outfile:
            outfile.write('<!-- Generated by Auto-Editor -->\n')
            outfile.write(
                '<!-- https://github.com/WyattBlue/auto-editor -->\n')
            outfile.write('\n')
            outfile.write(
                '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE xmeml>\n')
            outfile.write('<xmeml version="4">\n')
            outfile.write('\t<sequence>\n')
            outfile.write('\t<rate>\n')
            outfile.write('\t\t<timebase>30</timebase>\n')
            outfile.write('\t\t<ntsc>TRUE</ntsc>\n')
            outfile.write('\t</rate>\n')
            outfile.write('\t\t<name>Auto-Editor Audio Group</name>\n')
            outfile.write('\t\t<media>\n')
            outfile.write('\t\t\t<audio>\n')
            outfile.write('\t\t\t\t<numOutputChannels>2</numOutputChannels>\n')
            outfile.write('\t\t\t\t<format>\n')
            outfile.write('\t\t\t\t\t<samplecharacteristics>\n')
            outfile.write(f'\t\t\t\t\t\t<depth>{depth}</depth>\n')
            outfile.write(f'\t\t\t\t\t\t<samplerate>{sr}</samplerate>\n')
            outfile.write('\t\t\t\t\t</samplecharacteristics>\n')
            outfile.write('\t\t\t\t</format>\n')
            outfile.write(
                '\t\t\t\t<track currentExplodedTrackIndex="0" totalExplodedTrackCount="2" premiereTrackType="Stereo">\n'
            )

            total = 0
            for j, clip in enumerate(clips):
                myStart = int(total)
                total += (clip[1] - clip[0]) / (clip[2] / 100)
                myEnd = int(total)

                outfile.write(f'\t\t\t\t\t<clipitem id="clipitem-{j+1}">\n')
                outfile.write(
                    '\t\t\t\t\t\t<masterclipid>masterclip-1</masterclipid>\n')
                outfile.write(f'\t\t\t\t\t\t<name>{name}</name>\n')
                outfile.write(f'\t\t\t\t\t\t<start>{myStart}</start>\n')
                outfile.write(f'\t\t\t\t\t\t<end>{myEnd}</end>\n')
                outfile.write(
                    f'\t\t\t\t\t\t<in>{int(clip[0] / (clip[2] / 100))}</in>\n')
                outfile.write(
                    f'\t\t\t\t\t\t<out>{int(clip[1] / (clip[2] / 100))}</out>\n'
                )

                if (j == 0):
                    outfile.write('\t\t\t\t\t\t<file id="file-1">\n')
                    outfile.write(f'\t\t\t\t\t\t\t<name>{name}</name>\n')
                    outfile.write(
                        f'\t\t\t\t\t\t\t<pathurl>{pathurl}</pathurl>\n')
                    outfile.write('\t\t\t\t\t\t\t<rate>\n')
                    outfile.write('\t\t\t\t\t\t\t\t<timebase>30</timebase>\n')
                    outfile.write(f'\t\t\t\t\t\t\t\t<ntsc>{ntsc}</ntsc>\n')
                    outfile.write('\t\t\t\t\t\t\t</rate>\n')
                    outfile.write('\t\t\t\t\t\t\t<media>\n')
                    outfile.write('\t\t\t\t\t\t\t\t<audio>\n')
                    outfile.write(
                        '\t\t\t\t\t\t\t\t\t<samplecharacteristics>\n')
                    outfile.write(
                        f'\t\t\t\t\t\t\t\t\t\t<depth>{depth}</depth>\n')
                    outfile.write(
                        f'\t\t\t\t\t\t\t\t\t\t<samplerate>{sr}</samplerate>\n')
                    outfile.write(
                        '\t\t\t\t\t\t\t\t\t</samplecharacteristics>\n')
                    outfile.write(
                        '\t\t\t\t\t\t\t\t\t<channelcount>2</channelcount>\n')
                    outfile.write('\t\t\t\t\t\t\t\t</audio>\n')
                    outfile.write('\t\t\t\t\t\t\t</media>\n')
                    outfile.write('\t\t\t\t\t\t</file>\n')
                else:
                    outfile.write(f'\t\t\t\t\t\t<file id="file-1"/>\n')
                outfile.write('\t\t\t\t\t</clipitem>\n')

            outfile.write('\t\t\t\t</track>\n')
            outfile.write('\t\t\t</audio>\n')
            outfile.write('\t\t</media>\n')
            outfile.write('\t</sequence>\n')
            outfile.write('</xmeml>')

            return newFile

            # End of audio file code.

    with open(newFile, 'w', encoding='utf-8') as outfile:
        outfile.write('<!-- Generated by Auto-Editor -->\n')
        outfile.write('<!-- https://github.com/WyattBlue/auto-editor -->\n')
        outfile.write('\n')
        outfile.write(
            '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE xmeml>\n')
        outfile.write('<xmeml version="4">\n')
        outfile.write('\t<sequence>\n')
        outfile.write('\t\t<name>Auto-Editor Video Group</name>\n')
        outfile.write('\t\t<media>\n')
        outfile.write('\t\t\t<video>\n')
        outfile.write('\t\t\t\t<format>\n')
        outfile.write('\t\t\t\t\t<samplecharacteristics>\n')
        outfile.write('\t\t\t\t\t\t<rate>\n')
        outfile.write('\t\t\t\t\t\t\t<timebase>30</timebase>\n')
        outfile.write(f'\t\t\t\t\t\t\t<ntsc>{ntsc}</ntsc>\n')
        outfile.write('\t\t\t\t\t\t</rate>\n')
        outfile.write(f'\t\t\t\t\t\t<width>{width}</width>\n')
        outfile.write(f'\t\t\t\t\t\t<height>{height}</height>\n')
        outfile.write(f'\t\t\t\t\t\t<anamorphic>{ana}</anamorphic>\n')
        outfile.write(
            f'\t\t\t\t\t\t<pixelaspectratio>{pixelar}</pixelaspectratio>\n')
        outfile.write('\t\t\t\t\t\t<fielddominance>none</fielddominance>\n')
        outfile.write(f'\t\t\t\t\t\t<colordepth>{colordepth}</colordepth>\n')
        outfile.write('\t\t\t\t\t</samplecharacteristics>\n')
        outfile.write('\t\t\t\t</format>\n')
        outfile.write('\t\t\t\t<track>\n')

        # Handle clips.
        total = 0
        for j, clip in enumerate(clips):
            myStart = int(total)
            total += (clip[1] - clip[0]) / (clip[2] / 100)
            myEnd = int(total)

            outfile.write(f'\t\t\t\t\t<clipitem id="clipitem-{j+7}">\n')
            outfile.write(
                '\t\t\t\t\t\t<masterclipid>masterclip-2</masterclipid>\n')
            outfile.write(f'\t\t\t\t\t\t<name>{name}</name>\n')
            outfile.write(f'\t\t\t\t\t\t<start>{myStart}</start>\n')
            outfile.write(f'\t\t\t\t\t\t<end>{myEnd}</end>\n')
            outfile.write(
                f'\t\t\t\t\t\t<in>{int(clip[0] / (clip[2] / 100))}</in>\n')
            outfile.write(
                f'\t\t\t\t\t\t<out>{int(clip[1] / (clip[2] / 100))}</out>\n')

            if (j == 0):
                outfile.write('\t\t\t\t\t\t<file id="file-2">\n')
                outfile.write(f'\t\t\t\t\t\t\t<name>{name}</name>\n')
                outfile.write(f'\t\t\t\t\t\t\t<pathurl>{pathurl}</pathurl>\n')
                outfile.write('\t\t\t\t\t\t\t<rate>\n')
                outfile.write('\t\t\t\t\t\t\t\t<timebase>30</timebase>\n')
                outfile.write(f'\t\t\t\t\t\t\t\t<ntsc>{ntsc}</ntsc>\n')
                outfile.write('\t\t\t\t\t\t\t</rate>\n')
                outfile.write('\t\t\t\t\t\t\t<media>\n')
                outfile.write('\t\t\t\t\t\t\t\t<video>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t<samplecharacteristics>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t\t<rate>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t\t\t\t<timebase>30</timebase>\n')
                outfile.write(f'\t\t\t\t\t\t\t\t\t\t\t<ntsc>{ntsc}</ntsc>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t\t</rate>\n')
                outfile.write(f'\t\t\t\t\t\t\t\t\t\t<width>{width}</width>\n')
                outfile.write(
                    f'\t\t\t\t\t\t\t\t\t\t<height>{height}</height>\n')
                outfile.write(
                    f'\t\t\t\t\t\t\t\t\t\t<anamorphic>{ana}</anamorphic>\n')
                outfile.write(
                    f'\t\t\t\t\t\t\t\t\t\t<pixelaspectratio>{pixelar}</pixelaspectratio>\n'
                )
                outfile.write(
                    '\t\t\t\t\t\t\t\t\t\t<fielddominance>none</fielddominance>\n'
                )
                outfile.write('\t\t\t\t\t\t\t\t\t</samplecharacteristics>\n')
                outfile.write('\t\t\t\t\t\t\t\t</video>\n')
                outfile.write('\t\t\t\t\t\t\t\t<audio>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t<samplecharacteristics>\n')
                outfile.write(f'\t\t\t\t\t\t\t\t\t\t<depth>{depth}</depth>\n')
                outfile.write(
                    f'\t\t\t\t\t\t\t\t\t\t<samplerate>{sr}</samplerate>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t</samplecharacteristics>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t\t<channelcount>2</channelcount>\n')
                outfile.write('\t\t\t\t\t\t\t\t</audio>\n')
                outfile.write('\t\t\t\t\t\t\t</media>\n')
                outfile.write('\t\t\t\t\t\t</file>\n')
            else:
                outfile.write(f'\t\t\t\t\t\t<file id="file-2"/>\n')

            # Add the speed effect if nessecary
            if (clip[2] != 100):
                outfile.write('\t\t\t\t\t\t<filter>\n')
                outfile.write('\t\t\t\t\t\t\t<effect>\n')
                outfile.write('\t\t\t\t\t\t\t\t<name>Time Remap</name>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t<effectid>timeremap</effectid>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t<effectcategory>motion</effectcategory>\n'
                )
                outfile.write(
                    '\t\t\t\t\t\t\t\t<effecttype>motion</effecttype>\n')
                outfile.write('\t\t\t\t\t\t\t\t<mediatype>video</mediatype>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t<parameter authoringApp="PremierePro">\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t\t<parameterid>variablespeed</parameterid>\n'
                )
                outfile.write('\t\t\t\t\t\t\t\t\t<name>variablespeed</name>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t<valuemin>0</valuemin>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t<valuemax>1</valuemax>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t<value>0</value>\n')
                outfile.write('\t\t\t\t\t\t\t\t</parameter>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t<parameter authoringApp="PremierePro">\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t\t<parameterid>speed</parameterid>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t<name>speed</name>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t\t<valuemin>-100000</valuemin>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t\t<valuemax>100000</valuemax>\n')
                outfile.write(f'\t\t\t\t\t\t\t\t\t<value>{clip[2]}</value>\n')
                outfile.write('\t\t\t\t\t\t\t\t</parameter>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t<parameter authoringApp="PremierePro">\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t\t<parameterid>reverse</parameterid>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t<name>reverse</name>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t<value>FALSE</value>\n')
                outfile.write('\t\t\t\t\t\t\t\t</parameter>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t<parameter authoringApp="PremierePro">\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t\t<parameterid>frameblending</parameterid>\n'
                )
                outfile.write('\t\t\t\t\t\t\t\t\t<name>frameblending</name>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t<value>FALSE</value>\n')
                outfile.write('\t\t\t\t\t\t\t\t</parameter>\n')
                outfile.write('\t\t\t\t\t\t\t</effect>\n')
                outfile.write('\t\t\t\t\t\t</filter>\n')

            # Linking for video blocks
            for i in range(3):
                outfile.write('\t\t\t\t\t\t<link>\n')
                outfile.write(
                    f'\t\t\t\t\t\t\t<linkclipref>clipitem-{(i*(len(clips)+1))+7+j}</linkclipref>\n'
                )
                if (i == 0):
                    outfile.write(
                        '\t\t\t\t\t\t\t<mediatype>video</mediatype>\n')
                else:
                    outfile.write(
                        '\t\t\t\t\t\t\t<mediatype>audio</mediatype>\n')
                if (i == 2):
                    outfile.write('\t\t\t\t\t\t\t<trackindex>2</trackindex>\n')
                else:
                    outfile.write('\t\t\t\t\t\t\t<trackindex>1</trackindex>\n')
                outfile.write(f'\t\t\t\t\t\t\t<clipindex>{j+1}</clipindex>\n')
                if (i == 1 or i == 2):
                    outfile.write('\t\t\t\t\t\t\t<groupindex>1</groupindex>\n')
                outfile.write('\t\t\t\t\t\t</link>\n')
            outfile.write('\t\t\t\t\t</clipitem>\n')
        outfile.write('\t\t\t\t</track>\n')
        outfile.write('\t\t\t</video>\n')
        outfile.write('\t\t\t<audio>\n')
        outfile.write('\t\t\t\t<numOutputChannels>2</numOutputChannels>\n')
        outfile.write('\t\t\t\t<format>\n')
        outfile.write('\t\t\t\t\t<samplecharacteristics>\n')
        outfile.write(f'\t\t\t\t\t\t<depth>{depth}</depth>\n')
        outfile.write(f'\t\t\t\t\t\t<samplerate>{sr}</samplerate>\n')
        outfile.write('\t\t\t\t\t</samplecharacteristics>\n')
        outfile.write('\t\t\t\t</format>\n')
        outfile.write(
            '\t\t\t\t<track PannerIsInverted="true" PannerStartKeyframe="-91445760000000000,0.5,0,0,0,0,0,0" PannerName="Balance" currentExplodedTrackIndex="0" totalExplodedTrackCount="2" premiereTrackType="Stereo">\n'
        )

        # Audio Clips
        total = 0
        for j, clip in enumerate(clips):
            outfile.write(
                f'\t\t\t\t\t<clipitem id="clipitem-{len(clips)+8+j}" premiereChannelType="stereo">\n'
            )
            outfile.write(
                f'\t\t\t\t\t\t<masterclipid>masterclip-2</masterclipid>\n')
            outfile.write(f'\t\t\t\t\t\t<name>{name}</name>\n')

            myStart = int(total)
            total += (clip[1] - clip[0]) / (clip[2] / 100)
            myEnd = int(total)

            outfile.write(f'\t\t\t\t\t\t<start>{myStart}</start>\n')
            outfile.write(f'\t\t\t\t\t\t<end>{myEnd}</end>\n')

            outfile.write(
                f'\t\t\t\t\t\t<in>{int(clip[0] / (clip[2] / 100))}</in>\n')
            outfile.write(
                f'\t\t\t\t\t\t<out>{int(clip[1] / (clip[2] / 100))}</out>\n')
            outfile.write('\t\t\t\t\t\t<file id="file-2"/>\n')
            outfile.write('\t\t\t\t\t\t<sourcetrack>\n')
            outfile.write('\t\t\t\t\t\t\t<mediatype>audio</mediatype>\n')
            outfile.write('\t\t\t\t\t\t\t<trackindex>1</trackindex>\n')
            outfile.write('\t\t\t\t\t\t</sourcetrack>\n')

            # Add speed effect for audio blocks
            if (clip[2] != 100):
                outfile.write('\t\t\t\t\t\t<filter>\n')
                outfile.write('\t\t\t\t\t\t\t<effect>\n')
                outfile.write('\t\t\t\t\t\t\t\t<name>Time Remap</name>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t<effectid>timeremap</effectid>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t<effectcategory>motion</effectcategory>\n'
                )
                outfile.write(
                    '\t\t\t\t\t\t\t\t<effecttype>motion</effecttype>\n')
                outfile.write('\t\t\t\t\t\t\t\t<mediatype>video</mediatype>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t<parameter authoringApp="PremierePro">\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t\t<parameterid>variablespeed</parameterid>\n'
                )
                outfile.write('\t\t\t\t\t\t\t\t\t<name>variablespeed</name>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t<valuemin>0</valuemin>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t<valuemax>1</valuemax>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t<value>0</value>\n')
                outfile.write('\t\t\t\t\t\t\t\t</parameter>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t<parameter authoringApp="PremierePro">\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t\t<parameterid>speed</parameterid>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t<name>speed</name>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t\t<valuemin>-100000</valuemin>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t\t<valuemax>100000</valuemax>\n')
                outfile.write(f'\t\t\t\t\t\t\t\t\t<value>{clip[2]}</value>\n')
                outfile.write('\t\t\t\t\t\t\t\t</parameter>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t<parameter authoringApp="PremierePro">\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t\t<parameterid>reverse</parameterid>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t<name>reverse</name>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t<value>FALSE</value>\n')
                outfile.write('\t\t\t\t\t\t\t\t</parameter>\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t<parameter authoringApp="PremierePro">\n')
                outfile.write(
                    '\t\t\t\t\t\t\t\t\t<parameterid>frameblending</parameterid>\n'
                )
                outfile.write('\t\t\t\t\t\t\t\t\t<name>frameblending</name>\n')
                outfile.write('\t\t\t\t\t\t\t\t\t<value>FALSE</value>\n')
                outfile.write('\t\t\t\t\t\t\t\t</parameter>\n')
                outfile.write('\t\t\t\t\t\t\t</effect>\n')
                outfile.write('\t\t\t\t\t\t</filter>\n')

            if (audioFile):
                startOn = 1
            else:
                startOn = 0
            for i in range(startOn, 3):
                outfile.write('\t\t\t\t\t\t<link>\n')
                outfile.write(
                    f'\t\t\t\t\t\t\t<linkclipref>clipitem-{(i*(len(clips)+1))+7+j}</linkclipref>\n'
                )
                if (i == 0):
                    outfile.write(
                        '\t\t\t\t\t\t\t<mediatype>video</mediatype>\n')
                else:
                    outfile.write(
                        '\t\t\t\t\t\t\t<mediatype>audio</mediatype>\n')

                if (i == 2):
                    outfile.write('\t\t\t\t\t\t\t<trackindex>2</trackindex>\n')
                else:
                    outfile.write('\t\t\t\t\t\t\t<trackindex>1</trackindex>\n')

                outfile.write(f'\t\t\t\t\t\t\t<clipindex>{j+1}</clipindex>\n')

                if (i == 1 or i == 2):
                    outfile.write('\t\t\t\t\t\t\t<groupindex>1</groupindex>\n')
                outfile.write('\t\t\t\t\t\t</link>\n')
            outfile.write('\t\t\t\t\t</clipitem>\n')
        outfile.write('\t\t\t\t\t<outputchannelindex>1</outputchannelindex>\n')
        outfile.write('\t\t\t\t</track>\n')
        outfile.write('\t\t\t</audio>\n')
        outfile.write('\t\t</media>\n')
        outfile.write('\t</sequence>\n')
        outfile.write('</xmeml>')

    conwrite('')
    return newFile