def exportToPremiere(myInput, temp, output, clips, tracks, sampleRate, log): def makepath(filepath): return 'file://localhost' + os.path.abspath(filepath) def speedup(speed): r = '\t\t\t\t\t\t<filter>\n' r += '\t\t\t\t\t\t\t<effect>\n' r += '\t\t\t\t\t\t\t\t<name>Time Remap</name>\n' r += '\t\t\t\t\t\t\t\t<effectid>timeremap</effectid>\n' r += '\t\t\t\t\t\t\t\t<effectcategory>motion</effectcategory>\n' r += '\t\t\t\t\t\t\t\t<effecttype>motion</effecttype>\n' r += '\t\t\t\t\t\t\t\t<mediatype>video</mediatype>\n' r += '\t\t\t\t\t\t\t\t<parameter authoringApp="PremierePro">\n' r += '\t\t\t\t\t\t\t\t\t<parameterid>variablespeed</parameterid>\n' r += '\t\t\t\t\t\t\t\t\t<name>variablespeed</name>\n' r += '\t\t\t\t\t\t\t\t\t<valuemin>0</valuemin>\n' r += '\t\t\t\t\t\t\t\t\t<valuemax>1</valuemax>\n' r += '\t\t\t\t\t\t\t\t\t<value>0</value>\n' r += '\t\t\t\t\t\t\t\t</parameter>\n' r += '\t\t\t\t\t\t\t\t<parameter authoringApp="PremierePro">\n' r += '\t\t\t\t\t\t\t\t\t<parameterid>speed</parameterid>\n' r += '\t\t\t\t\t\t\t\t\t<name>speed</name>\n' r += '\t\t\t\t\t\t\t\t\t<valuemin>-100000</valuemin>\n' r += '\t\t\t\t\t\t\t\t\t<valuemax>100000</valuemax>\n' r += f'\t\t\t\t\t\t\t\t\t<value>{speed}</value>\n' r += '\t\t\t\t\t\t\t\t</parameter>\n' r += '\t\t\t\t\t\t\t\t<parameter authoringApp="PremierePro">\n' r += '\t\t\t\t\t\t\t\t\t<parameterid>reverse</parameterid>\n' r += '\t\t\t\t\t\t\t\t\t<name>reverse</name>\n' r += '\t\t\t\t\t\t\t\t\t<value>FALSE</value>\n' r += '\t\t\t\t\t\t\t\t</parameter>\n' r += '\t\t\t\t\t\t\t\t<parameter authoringApp="PremierePro">\n' r += '\t\t\t\t\t\t\t\t\t<parameterid>frameblending</parameterid>\n' r += '\t\t\t\t\t\t\t\t\t<name>frameblending</name>\n' r += '\t\t\t\t\t\t\t\t\t<value>FALSE</value>\n' r += '\t\t\t\t\t\t\t\t</parameter>\n' r += '\t\t\t\t\t\t\t</effect>\n' r += '\t\t\t\t\t\t</filter>\n' return r pathurl = makepath(myInput) name = os.path.basename(myInput) audioFile = isAudioFile(myInput) log.debug('tracks: ' + str(tracks)) log.debug(os.path.dirname(os.path.abspath(myInput))) if (tracks > 1): # XML in Adobe Premiere doesn't support multiple audio tracks so # we need to do some stupid things to get it working. from shutil import rmtree inFolder = os.path.dirname(os.path.abspath(myInput)) hmm = name[:name.rfind('.')] newFolderName = os.path.join(inFolder, hmm + '_tracks') try: os.mkdir(newFolderName) except OSError: rmtree(newFolderName) os.mkdir(newFolderName) trackurls = [pathurl] for i in range(1, tracks): newtrack = os.path.join(newFolderName, f'{i}.wav') os.rename(os.path.join(temp, f'{i}.wav'), newtrack) trackurls.append(newtrack) ntsc = 'FALSE' ana = 'FALSE' # anamorphic alphatype = 'none' depth = '16' if (not audioFile): try: import cv2 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): groupName = 'Auto-Editor Audio Group' with open(output, 'w', encoding='utf-8') as outfile: outfile.write('<!-- Generated by Auto-Editor -->\n') outfile.write( '<!-- https://github.com/WyattBlue/auto-editor -->\n\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(f'\t\t<name>{groupName}</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" 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>') # Exit out of this function prematurely. return None groupName = 'Auto-Editor Video Group' with open(output, '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(f'\t\t<name>{groupName}</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+1}">\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-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<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-1"/>\n') if (clip[2] != 100): outfile.write(speedup(clip[2])) # Linking for video blocks for i in range(max(3, tracks + 1)): 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)))+j+1}</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 > 0): 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') # Audio Clips for t in range(tracks): if (t == 0): print('') log.debug('t variable: ' + str(t)) total = 0 outfile.write( '\t\t\t\t<track currentExplodedTrackIndex="0" premiereTrackType="Stereo">\n' ) for j, clip in enumerate(clips): clipItemNum = len(clips) + 1 + j + (t * len(clips)) outfile.write( f'\t\t\t\t\t<clipitem id="clipitem-{clipItemNum}" 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' ) if (t > 0): outfile.write(f'\t\t\t\t\t\t<file id="file-{t+1}">\n') outfile.write(f'\t\t\t\t\t\t\t<name>{name}{t}</name>\n') outfile.write( f'\t\t\t\t\t\t\t<pathurl>{trackurls[t]}</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-{t+1}"/>\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') outfile.write('\t\t\t\t\t\t<labels>\n') outfile.write('\t\t\t\t\t\t\t<label2>Iris</label2>\n') outfile.write('\t\t\t\t\t\t</labels>\n') # Add speed effect for audio blocks if (clip[2] != 100): outfile.write(speedup(clip[2])) 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('')
def exportToResolve(myInput, output, clips, duration, sampleRate, log): pathurl = 'file://localhost' + os.path.abspath(myInput) name = os.path.basename(myInput) audioFile = isAudioFile(myInput) ntsc = 'FALSE' ana = 'FALSE' # anamorphic 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 = '1920' height = '1080' else: width = '1920' height = '1080' pixelar = 'square' # pixel aspect ratio colordepth = '24' sr = sampleRate if(audioFile): with open(output, 'w', encoding='utf-8') as outfile: outfile.write('<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE xmeml>\n') outfile.write('<xmeml version="5">\n') outfile.write('\t<sequence>\n') outfile.write('\t\t<name>Auto-Editor Audio Group</name>\n') outfile.write(f'\t\t<duration>{duration}</duration>\n') outfile.write('\t\t<rate>\n') outfile.write('\t\t\t<timebase>30</timebase>\n') outfile.write(f'\t\t\t<ntsc>{ntsc}</ntsc>\n') outfile.write('\t\t</rate>\n') outfile.write('\t\t<in>-1</in>\n') outfile.write('\t\t<out>-1</out>\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(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<pixelaspectratio>{pixelar}</pixelaspectratio>\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('\t\t\t\t\t</samplecharacteristics>\n') outfile.write('\t\t\t\t</format>\n') outfile.write('\t\t\t</video>\n') outfile.write('\t\t\t<audio>\n') outfile.write('\t\t\t\t<track>\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<channelcount>1</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\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') 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>') # Exit out of this function prematurely. return None # End of audio file code. with open(output, 'w', encoding='utf-8') as outfile: outfile.write('<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE xmeml>\n') outfile.write('<xmeml version="4">\n') outfile.write('\t<sequence id="sequence-1" TL.SQAudioVisibleBase="0" TL.SQVideoVisibleBase="0" TL.SQVisibleBaseTime="0" TL.SQAVDividerPosition="0.5" TL.SQHideShyTracks="0" TL.SQHeaderWidth="236" TL.SQTimePerPixel="0.013085939262623341" MZ.EditLine="0" MZ.Sequence.PreviewFrameSizeHeight="720" MZ.Sequence.AudioTimeDisplayFormat="200" MZ.Sequence.PreviewRenderingClassID="1297106761" MZ.Sequence.PreviewRenderingPresetCodec="1297107278" MZ.Sequence.PreviewRenderingPresetPath="EncoderPresets/SequencePreview/795454d9-d3c2-429d-9474-923ab13b7018/I-Frame Only MPEG.epr" MZ.Sequence.PreviewUseMaxRenderQuality="false" MZ.Sequence.PreviewUseMaxBitDepth="false" MZ.Sequence.EditingModeGUID="795454d9-d3c2-429d-9474-923ab13b7018" MZ.Sequence.VideoTimeDisplayFormat="104" MZ.WorkOutPoint="10770278400000" MZ.WorkInPoint="0" explodedTracks="true">\n') outfile.write('\t\t<rate>\n') outfile.write('\t\t\t<timebase>30</timebase>\n') outfile.write(f'\t\t\t<ntsc>{ntsc}</ntsc>\n') outfile.write('\t\t</rate>\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(f'\t\t\t\t\t\t\t<duration>{duration}</duration>\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('')
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)
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)
def preview(myInput, chunks, speeds, debug): if(not os.path.isfile(myInput)): print('preview.py: Could not find file ', myInput) sys.exit(1) audioFile = isAudioFile(myInput) if(audioFile): fps = 30 else: import cv2 cap = cv2.VideoCapture(myInput) fps = cap.get(cv2.CAP_PROP_FPS) cap.release() cv2.destroyAllWindows() def printTimeFrame(title, frames, fps): inSec = round(frames / fps, 1) 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] print('') printTimeFrame('Old length', oldTime, fps) newL = getNewLength(chunks, speeds, fps) printTimeFrame('New length', newL * fps, fps) print('') clips = 0 cuts = 0 cutL = [] 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 leng = chunk[1] - chunk[0] cutL.append(leng) print('Number of clips:', clips) printTimeFrame('Smallest clip length', min(clipLengths), fps) printTimeFrame('Largest clip length', max(clipLengths), fps) printTimeFrame('Average clip length', sum(clipLengths) / len(clipLengths), fps) print('') print('Number of cuts:', cuts) printTimeFrame('Smallest cut length', min(cutL), fps) printTimeFrame('Largest cut length', max(cutL), fps) printTimeFrame('Average cut length', sum(cutL) / len(cutL), fps) print('') if(not audioFile): print('Video framerate:', fps) if(debug): print('Chunks:') print(chunks)
def exportToPremiere(myInput, output, clips, sampleRate, log): pathurl = 'file://localhost' + os.path.abspath(myInput) name = os.path.basename(myInput) audioFile = isAudioFile(myInput) 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(output, '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>') # Exit out of this function prematurely. return None # End of audio file code. with open(output, '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('')