Rewrites a lot of code

Streams are now parsed to objects, making it easier to get required information.
Improved styling.
Some better comments.
Better input parsing.
This commit is contained in:
Kristian Knarvik 2019-10-06 01:02:47 +02:00
parent 0a39a69e73
commit 20e6df04f1
10 changed files with 684 additions and 429 deletions

View File

@ -6,11 +6,17 @@
</artifacts-to-build> </artifacts-to-build>
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="e9b48a04-29ff-46ce-9630-42742dc34d68" name="Default" comment="Improves reading of input"> <list default="true" id="e9b48a04-29ff-46ce-9630-42742dc34d68" name="Default" comment="Rewrites a lot of code&#10;&#10;Streams are now parsed to objects, making it easier to get required information.&#10;Improved styling.&#10;Some better comments.&#10;Better input parsing.">
<change afterPath="$PROJECT_DIR$/src/ffmpegconverter/streams/AudioStream.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/ffmpegconverter/streams/StreamObject.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/ffmpegconverter/streams/SubtitleStream.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/ffmpegconverter/streams/VideoStream.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/ffmpegconverter/Main.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/ffmpegconverter/Main.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/ffmpegconverter/Main.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/ffmpegconverter/Main.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/ffmpegconverter/converter/AnimeConverter.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/ffmpegconverter/converter/AnimeConverter.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/ffmpegconverter/converter/AnimeConverter.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/ffmpegconverter/converter/AnimeConverter.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/ffmpegconverter/converter/AudioConverter.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/ffmpegconverter/converter/AudioConverter.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/ffmpegconverter/converter/Converter.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/ffmpegconverter/converter/Converter.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/ffmpegconverter/converter/Converter.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/ffmpegconverter/converter/Converter.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/ffmpegconverter/converter/VideoConverter.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/ffmpegconverter/converter/VideoConverter.java" afterDir="false" />
</list> </list>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" /> <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
@ -32,23 +38,97 @@
<file pinned="false" current-in-tab="false"> <file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/converter/Converter.java"> <entry file="file://$PROJECT_DIR$/src/ffmpegconverter/converter/Converter.java">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="187"> <state relative-caret-position="180">
<caret line="320" column="66" selection-start-line="320" selection-start-column="66" selection-end-line="320" selection-end-column="66" /> <caret line="398" column="80" selection-start-line="398" selection-start-column="80" selection-end-line="398" selection-end-column="80" />
<folding> <folding>
<element signature="imports" expanded="true" /> <element signature="imports" expanded="true" />
<element signature="method#fileCollisionPrevention#0;class#Converter#0" />
<element signature="docComment;method#read#0;class#Converter#0" />
<element signature="method#read#0;class#Converter#0" />
<element signature="docComment;method#ffmpegWebVideo#0;class#Converter#0" />
<element signature="method#ffmpegWebVideo#0;class#Converter#0" />
<element signature="docComment;method#generalFile#0;class#Converter#0" />
<element signature="method#generalFile#0;class#Converter#0" />
<element signature="docComment;method#listIndexes#0;class#Converter#0" />
<element signature="docComment;method#stringBetween#0;class#Converter#0" />
<element signature="docComment;method#stringBetweenSingle#0;class#Converter#0" />
<element signature="method#stringBetweenSingle#0;class#Converter#0" />
<element signature="e#7792#7793#0" expanded="true" />
<element signature="e#7875#7876#0" expanded="true" />
<element signature="e#7924#7925#0" expanded="true" />
<element signature="e#7987#7988#0" expanded="true" />
<element signature="docComment;method#concatenate#0;class#Converter#0" />
<element signature="method#concatenate#0;class#Converter#0" /> <element signature="method#concatenate#0;class#Converter#0" />
<element signature="docComment;method#parseStreams#0;class#Converter#0" />
<element signature="method#parseStreams#0;class#Converter#0" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
</file> </file>
<file pinned="false" current-in-tab="false"> <file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/streams/AudioStream.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="357">
<caret line="27" column="5" selection-start-line="27" selection-start-column="5" selection-end-line="27" selection-end-column="5" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/streams/SubtitleStream.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="284">
<caret line="47" column="4" selection-start-line="47" selection-start-column="4" selection-end-line="47" selection-end-column="4" />
<folding>
<element signature="e#980#981#0" expanded="true" />
<element signature="e#1066#1067#0" expanded="true" />
<element signature="e#1658#1659#0" expanded="true" />
<element signature="e#1723#1724#0" expanded="true" />
<element signature="e#1809#1810#0" expanded="true" />
<element signature="e#1893#1894#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/streams/VideoStream.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="51">
<caret line="3" column="38" selection-start-line="3" selection-start-column="38" selection-end-line="3" selection-end-column="38" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/streams/StreamObject.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="191">
<caret line="23" column="4" selection-start-line="23" selection-start-column="4" selection-end-line="23" selection-end-column="4" />
<folding>
<element signature="e#313#314#0" expanded="true" />
<element signature="e#350#351#0" expanded="true" />
<element signature="e#469#470#0" expanded="true" />
<element signature="e#506#507#0" expanded="true" />
<element signature="e#639#640#0" expanded="true" />
<element signature="e#680#681#0" expanded="true" />
<element signature="e#841#842#0" expanded="true" />
<element signature="e#882#883#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/converter/AnimeConverter.java"> <entry file="file://$PROJECT_DIR$/src/ffmpegconverter/converter/AnimeConverter.java">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="249"> <state relative-caret-position="147">
<caret line="116" column="57" selection-start-line="116" selection-start-column="57" selection-end-line="116" selection-end-column="57" /> <caret line="71" column="52" lean-forward="true" selection-start-line="71" selection-start-column="52" selection-end-line="71" selection-end-column="52" />
<folding> <folding>
<element signature="imports" expanded="true" /> <element signature="imports" expanded="true" />
<element signature="e#5093#5094#0" expanded="true" />
<element signature="e#5129#5130#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
@ -57,23 +137,21 @@
<file pinned="false" current-in-tab="false"> <file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/converter/AudioConverter.java"> <entry file="file://$PROJECT_DIR$/src/ffmpegconverter/converter/AudioConverter.java">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="34"> <state relative-caret-position="102">
<caret line="7" column="30" selection-start-line="7" selection-start-column="30" selection-end-line="7" selection-end-column="30" /> <caret line="6" column="27" selection-start-line="6" selection-start-column="27" selection-end-line="6" selection-end-column="27" />
<folding>
<element signature="imports" expanded="true" />
</folding>
</state> </state>
</provider> </provider>
</entry> </entry>
</file> </file>
<file pinned="false" current-in-tab="true"> <file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/Main.java"> <entry file="file://$PROJECT_DIR$/src/ffmpegconverter/Main.java">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="231"> <state relative-caret-position="395">
<caret line="149" column="31" lean-forward="true" selection-start-line="149" selection-start-column="31" selection-end-line="149" selection-end-column="31" /> <caret line="138" column="53" lean-forward="true" selection-start-line="138" selection-start-column="53" selection-end-line="138" selection-end-column="53" />
<folding> <folding>
<element signature="imports" expanded="true" /> <element signature="imports" expanded="true" />
<element signature="method#testArgumentValue#0;class#converterArgument#0;class#Main#0" /> <element signature="class#converterArgumentValueType#0;class#Main#0" />
<element signature="method#tokenizer#0;class#Main#0" />
<element signature="method#getList#0;class#Main#0" /> <element signature="method#getList#0;class#Main#0" />
</folding> </folding>
</state> </state>
@ -83,12 +161,11 @@
<file pinned="false" current-in-tab="false"> <file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/converter/VideoConverter.java"> <entry file="file://$PROJECT_DIR$/src/ffmpegconverter/converter/VideoConverter.java">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="731"> <state relative-caret-position="191">
<caret line="56" column="38" selection-start-line="56" selection-start-column="38" selection-end-line="56" selection-end-column="38" /> <caret line="61" column="12" selection-start-line="61" selection-start-column="12" selection-end-line="61" selection-end-column="12" />
<folding> <folding>
<element signature="imports" expanded="true" /> <element signature="imports" expanded="true" />
<element signature="docComment;method#processFile#0;class#VideoConverter#0" /> <element signature="docComment;method#processFile#0;class#VideoConverter#0" />
<element signature="method#processFile#0;class#VideoConverter#0" />
</folding> </folding>
</state> </state>
</provider> </provider>
@ -96,16 +173,31 @@
</file> </file>
</leaf> </leaf>
</component> </component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Class" />
</list>
</option>
</component>
<component name="FindInProjectRecents"> <component name="FindInProjectRecents">
<findStrings> <findStrings>
<find>stripexten</find> <find>stripexten</find>
<find>System.out.</find> <find>System.out.</find>
<find>listSubtitlesRelative</find>
<find>debug</find> <find>debug</find>
<find>isimage</find> <find>isimage</find>
<find>jap</find> <find>jap</find>
<find>listFilesRec</find> <find>listFilesRec</find>
<find>readInput</find> <find>readInput</find>
<find>isImageSub</find>
<find>isImageS</find>
<find>subList</find>
<find>listAudio</find>
<find>listVideo</find>
<find>probeFile</find>
<find>listSubtitlesRelative</find>
<find>PROBE_SPL</find>
<find>filterSubtitleStreams</find>
</findStrings> </findStrings>
</component> </component>
<component name="Git.Settings"> <component name="Git.Settings">
@ -115,10 +207,16 @@
<component name="IdeDocumentHistory"> <component name="IdeDocumentHistory">
<option name="CHANGED_PATHS"> <option name="CHANGED_PATHS">
<list> <list>
<option value="$PROJECT_DIR$/src/ffmpegconverter/converter/VideoConverter.java" /> <option value="$PROJECT_DIR$/src/ffmpegconverter/streams/Video.java" />
<option value="$PROJECT_DIR$/src/ffmpegconverter/streams/AudioStream.java" />
<option value="$PROJECT_DIR$/src/ffmpegconverter/converter/AnimeConverter.java" /> <option value="$PROJECT_DIR$/src/ffmpegconverter/converter/AnimeConverter.java" />
<option value="$PROJECT_DIR$/src/ffmpegconverter/converter/Converter.java" /> <option value="$PROJECT_DIR$/src/ffmpegconverter/converter/AudioConverter.java" />
<option value="$PROJECT_DIR$/src/ffmpegconverter/streams/StreamObject.java" />
<option value="$PROJECT_DIR$/src/ffmpegconverter/streams/VideoStream.java" />
<option value="$PROJECT_DIR$/src/ffmpegconverter/streams/SubtitleStream.java" />
<option value="$PROJECT_DIR$/src/ffmpegconverter/Main.java" /> <option value="$PROJECT_DIR$/src/ffmpegconverter/Main.java" />
<option value="$PROJECT_DIR$/src/ffmpegconverter/converter/Converter.java" />
<option value="$PROJECT_DIR$/src/ffmpegconverter/converter/VideoConverter.java" />
</list> </list>
</option> </option>
</component> </component>
@ -139,24 +237,6 @@
<item name="FFmpegConvert1" type="b2602c69:ProjectViewProjectNode" /> <item name="FFmpegConvert1" type="b2602c69:ProjectViewProjectNode" />
<item name="FFmpegConvert1" type="462c0819:PsiDirectoryNode" /> <item name="FFmpegConvert1" type="462c0819:PsiDirectoryNode" />
</path> </path>
<path>
<item name="FFmpegConvert1" type="b2602c69:ProjectViewProjectNode" />
<item name="FFmpegConvert1" type="462c0819:PsiDirectoryNode" />
<item name="out" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="FFmpegConvert1" type="b2602c69:ProjectViewProjectNode" />
<item name="FFmpegConvert1" type="462c0819:PsiDirectoryNode" />
<item name="out" type="462c0819:PsiDirectoryNode" />
<item name="artifacts" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="FFmpegConvert1" type="b2602c69:ProjectViewProjectNode" />
<item name="FFmpegConvert1" type="462c0819:PsiDirectoryNode" />
<item name="out" type="462c0819:PsiDirectoryNode" />
<item name="artifacts" type="462c0819:PsiDirectoryNode" />
<item name="FFmpegConvert" type="462c0819:PsiDirectoryNode" />
</path>
<path> <path>
<item name="FFmpegConvert1" type="b2602c69:ProjectViewProjectNode" /> <item name="FFmpegConvert1" type="b2602c69:ProjectViewProjectNode" />
<item name="FFmpegConvert1" type="462c0819:PsiDirectoryNode" /> <item name="FFmpegConvert1" type="462c0819:PsiDirectoryNode" />
@ -175,18 +255,25 @@
<item name="ffmpegconverter" type="462c0819:PsiDirectoryNode" /> <item name="ffmpegconverter" type="462c0819:PsiDirectoryNode" />
<item name="converter" type="462c0819:PsiDirectoryNode" /> <item name="converter" type="462c0819:PsiDirectoryNode" />
</path> </path>
<path>
<item name="FFmpegConvert1" type="b2602c69:ProjectViewProjectNode" />
<item name="FFmpegConvert1" type="462c0819:PsiDirectoryNode" />
<item name="src" type="462c0819:PsiDirectoryNode" />
<item name="ffmpegconverter" type="462c0819:PsiDirectoryNode" />
<item name="streams" type="462c0819:PsiDirectoryNode" />
</path>
</expand> </expand>
<select /> <select />
</subPane> </subPane>
</pane> </pane>
<pane id="Scope" />
<pane id="PackagesPane" /> <pane id="PackagesPane" />
<pane id="Scope" />
</panes> </panes>
</component> </component>
<component name="PropertiesComponent"> <component name="PropertiesComponent">
<property name="WebServerToolWindowFactoryState" value="false" /> <property name="WebServerToolWindowFactoryState" value="false" />
<property name="aspect.path.notification.shown" value="true" /> <property name="aspect.path.notification.shown" value="true" />
<property name="com.android.tools.idea.instantapp.provision.ProvisionBeforeRunTaskProvider.myTimeStamp" value="1566327893996" /> <property name="com.android.tools.idea.instantapp.provision.ProvisionBeforeRunTaskProvider.myTimeStamp" value="1570316553479" />
<property name="last_opened_file_path" value="$PROJECT_DIR$/../rogue-one-oh-one" /> <property name="last_opened_file_path" value="$PROJECT_DIR$/../rogue-one-oh-one" />
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" /> <property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
<property name="nodejs_npm_path_reset_for_default_project" value="true" /> <property name="nodejs_npm_path_reset_for_default_project" value="true" />
@ -334,7 +421,9 @@
<workItem from="1560477751040" duration="2758000" /> <workItem from="1560477751040" duration="2758000" />
<workItem from="1561162925209" duration="2043000" /> <workItem from="1561162925209" duration="2043000" />
<workItem from="1561850923206" duration="1264000" /> <workItem from="1561850923206" duration="1264000" />
<workItem from="1566295287966" duration="2888000" /> <workItem from="1566295287966" duration="29127000" />
<workItem from="1568269273856" duration="26000" />
<workItem from="1570010166713" duration="19096000" />
</task> </task>
<task id="LOCAL-00001" summary="Adds missing files"> <task id="LOCAL-00001" summary="Adds missing files">
<created>1538261222377</created> <created>1538261222377</created>
@ -364,13 +453,20 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1545090945641</updated> <updated>1545090945641</updated>
</task> </task>
<option name="localTasksCounter" value="5" /> <task id="LOCAL-00005" summary="Improves reading of input">
<created>1566327932040</created>
<option name="number" value="00005" />
<option name="presentableId" value="LOCAL-00005" />
<option name="project" value="LOCAL" />
<updated>1566327932040</updated>
</task>
<option name="localTasksCounter" value="6" />
<servers /> <servers />
</component> </component>
<component name="TimeTrackingManager"> <component name="TimeTrackingManager">
<option name="totallyTimeSpent" value="105468000" /> <option name="totallyTimeSpent" value="150829000" />
</component> </component>
<component name="TodoView"> <component name="TodoView" selected-index="4">
<todo-panel id="selected-file"> <todo-panel id="selected-file">
<is-autoscroll-to-source value="true" /> <is-autoscroll-to-source value="true" />
</todo-panel> </todo-panel>
@ -383,26 +479,27 @@
<frame x="-8" y="-8" width="1936" height="1056" extended-state="6" /> <frame x="-8" y="-8" width="1936" height="1056" extended-state="6" />
<editor active="true" /> <editor active="true" />
<layout> <layout>
<window_info content_ui="combo" id="Project" order="0" visible="true" weight="0.1130064" /> <window_info content_ui="combo" id="Project" order="0" visible="true" weight="0.1433902" />
<window_info id="Structure" order="1" side_tool="true" weight="0.25" /> <window_info id="Structure" order="1" side_tool="true" weight="0.25" />
<window_info id="Image Layers" order="2" /> <window_info id="Image Layers" order="2" />
<window_info id="Designer" order="3" /> <window_info id="Designer" order="3" />
<window_info id="UI Designer" order="4" /> <window_info id="UI Designer" order="4" />
<window_info id="Capture Tool" order="5" /> <window_info id="Capture Tool" order="5" />
<window_info id="Favorites" order="6" side_tool="true" /> <window_info id="Favorites" order="6" side_tool="true" />
<window_info anchor="bottom" id="Duplicate detector" visible="true" weight="0.32936078" />
<window_info anchor="bottom" id="Message" order="0" /> <window_info anchor="bottom" id="Message" order="0" />
<window_info anchor="bottom" id="Find" order="1" /> <window_info anchor="bottom" id="Find" order="1" weight="0.32936078" />
<window_info anchor="bottom" id="Run" order="2" sideWeight="0.75054705" weight="0.48754063" /> <window_info anchor="bottom" id="Run" order="2" sideWeight="0.75054705" weight="0.31310943" />
<window_info anchor="bottom" id="Debug" order="3" sideWeight="0.49895614" weight="0.39869988" /> <window_info anchor="bottom" id="Debug" order="3" sideWeight="0.49895614" weight="0.39869988" />
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" /> <window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" /> <window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
<window_info anchor="bottom" id="TODO" order="6" sideWeight="0.49946696" weight="0.32936078" /> <window_info anchor="bottom" id="TODO" order="6" sideWeight="0.49946696" weight="0.32936078" />
<window_info anchor="bottom" id="Version Control" order="7" sideWeight="0.4989059" weight="0.32827735" /> <window_info anchor="bottom" id="Version Control" order="7" sideWeight="0.4989059" weight="0.32827735" />
<window_info anchor="bottom" id="Database Changes" order="8" show_stripe_button="false" /> <window_info anchor="bottom" id="Database Changes" order="8" show_stripe_button="false" />
<window_info anchor="bottom" id="Statistic" order="9" sideWeight="0.49946696" weight="0.32936078" /> <window_info anchor="bottom" id="Statistic" order="9" sideWeight="0.49946696" weight="0.32932165" />
<window_info anchor="bottom" id="Terminal" order="10" sideWeight="0.4989059" weight="0.32827735" /> <window_info anchor="bottom" id="Terminal" order="10" sideWeight="0.4989059" weight="0.32822758" />
<window_info anchor="bottom" id="Event Log" order="11" sideWeight="0.24945295" side_tool="true" weight="0.47811815" /> <window_info anchor="bottom" id="Event Log" order="11" sideWeight="0.24945295" side_tool="true" weight="0.47811815" />
<window_info active="true" anchor="bottom" id="Messages" order="12" sideWeight="0.49840087" visible="true" weight="0.32827735" /> <window_info anchor="bottom" id="Messages" order="12" sideWeight="0.49840087" weight="0.32719395" />
<window_info anchor="bottom" id="Docker" order="13" show_stripe_button="false" /> <window_info anchor="bottom" id="Docker" order="13" show_stripe_button="false" />
<window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" /> <window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" />
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" /> <window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
@ -425,7 +522,8 @@
<MESSAGE value="Adds hardsubbing of subtitles with same name as video file&#10;&#10;Better file collision detection&#10;Adds debug mode to only render part of the video" /> <MESSAGE value="Adds hardsubbing of subtitles with same name as video file&#10;&#10;Better file collision detection&#10;Adds debug mode to only render part of the video" />
<MESSAGE value="Adds surround to stereo" /> <MESSAGE value="Adds surround to stereo" />
<MESSAGE value="Improves reading of input" /> <MESSAGE value="Improves reading of input" />
<option name="LAST_COMMIT_MESSAGE" value="Improves reading of input" /> <MESSAGE value="Rewrites a lot of code&#10;&#10;Streams are now parsed to objects, making it easier to get required information.&#10;Improved styling.&#10;Some better comments.&#10;Better input parsing." />
<option name="LAST_COMMIT_MESSAGE" value="Rewrites a lot of code&#10;&#10;Streams are now parsed to objects, making it easier to get required information.&#10;Improved styling.&#10;Some better comments.&#10;Better input parsing." />
</component> </component>
<component name="editorHistoryManager"> <component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/misc.xml" /> <entry file="file://$PROJECT_DIR$/misc.xml" />
@ -446,59 +544,122 @@
</entry> </entry>
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/converter/AudioConverter.java"> <entry file="file://$PROJECT_DIR$/src/ffmpegconverter/converter/AudioConverter.java">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="34"> <state relative-caret-position="102">
<caret line="7" column="30" selection-start-line="7" selection-start-column="30" selection-end-line="7" selection-end-column="30" /> <caret line="6" column="27" selection-start-line="6" selection-start-column="27" selection-end-line="6" selection-end-column="27" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/streams/VideoStream.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="51">
<caret line="3" column="38" selection-start-line="3" selection-start-column="38" selection-end-line="3" selection-end-column="38" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/streams/AudioStream.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="357">
<caret line="27" column="5" selection-start-line="27" selection-start-column="5" selection-end-line="27" selection-end-column="5" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/streams/StreamObject.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="191">
<caret line="23" column="4" selection-start-line="23" selection-start-column="4" selection-end-line="23" selection-end-column="4" />
<folding> <folding>
<element signature="imports" expanded="true" /> <element signature="e#313#314#0" expanded="true" />
<element signature="e#350#351#0" expanded="true" />
<element signature="e#469#470#0" expanded="true" />
<element signature="e#506#507#0" expanded="true" />
<element signature="e#639#640#0" expanded="true" />
<element signature="e#680#681#0" expanded="true" />
<element signature="e#841#842#0" expanded="true" />
<element signature="e#882#883#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/converter/VideoConverter.java"> <entry file="file://$PROJECT_DIR$/src/ffmpegconverter/streams/SubtitleStream.java">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="731"> <state relative-caret-position="284">
<caret line="56" column="38" selection-start-line="56" selection-start-column="38" selection-end-line="56" selection-end-column="38" /> <caret line="47" column="4" selection-start-line="47" selection-start-column="4" selection-end-line="47" selection-end-column="4" />
<folding> <folding>
<element signature="imports" expanded="true" /> <element signature="e#980#981#0" expanded="true" />
<element signature="docComment;method#processFile#0;class#VideoConverter#0" /> <element signature="e#1066#1067#0" expanded="true" />
<element signature="method#processFile#0;class#VideoConverter#0" /> <element signature="e#1658#1659#0" expanded="true" />
<element signature="e#1723#1724#0" expanded="true" />
<element signature="e#1809#1810#0" expanded="true" />
<element signature="e#1893#1894#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/converter/Converter.java"> <entry file="file://$PROJECT_DIR$/src/ffmpegconverter/converter/Converter.java">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="187"> <state relative-caret-position="180">
<caret line="320" column="66" selection-start-line="320" selection-start-column="66" selection-end-line="320" selection-end-column="66" /> <caret line="398" column="80" selection-start-line="398" selection-start-column="80" selection-end-line="398" selection-end-column="80" />
<folding> <folding>
<element signature="imports" expanded="true" /> <element signature="imports" expanded="true" />
<element signature="method#fileCollisionPrevention#0;class#Converter#0" />
<element signature="docComment;method#read#0;class#Converter#0" />
<element signature="method#read#0;class#Converter#0" />
<element signature="docComment;method#ffmpegWebVideo#0;class#Converter#0" />
<element signature="method#ffmpegWebVideo#0;class#Converter#0" />
<element signature="docComment;method#generalFile#0;class#Converter#0" />
<element signature="method#generalFile#0;class#Converter#0" />
<element signature="docComment;method#listIndexes#0;class#Converter#0" />
<element signature="docComment;method#stringBetween#0;class#Converter#0" />
<element signature="docComment;method#stringBetweenSingle#0;class#Converter#0" />
<element signature="method#stringBetweenSingle#0;class#Converter#0" />
<element signature="e#7792#7793#0" expanded="true" />
<element signature="e#7875#7876#0" expanded="true" />
<element signature="e#7924#7925#0" expanded="true" />
<element signature="e#7987#7988#0" expanded="true" />
<element signature="docComment;method#concatenate#0;class#Converter#0" />
<element signature="method#concatenate#0;class#Converter#0" /> <element signature="method#concatenate#0;class#Converter#0" />
<element signature="docComment;method#parseStreams#0;class#Converter#0" />
<element signature="method#parseStreams#0;class#Converter#0" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/converter/AnimeConverter.java"> <entry file="file://$PROJECT_DIR$/src/ffmpegconverter/converter/VideoConverter.java">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="249"> <state relative-caret-position="191">
<caret line="116" column="57" selection-start-line="116" selection-start-column="57" selection-end-line="116" selection-end-column="57" /> <caret line="61" column="12" selection-start-line="61" selection-start-column="12" selection-end-line="61" selection-end-column="12" />
<folding> <folding>
<element signature="imports" expanded="true" /> <element signature="imports" expanded="true" />
<element signature="docComment;method#processFile#0;class#VideoConverter#0" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/Main.java"> <entry file="file://$PROJECT_DIR$/src/ffmpegconverter/Main.java">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="231"> <state relative-caret-position="395">
<caret line="149" column="31" lean-forward="true" selection-start-line="149" selection-start-column="31" selection-end-line="149" selection-end-column="31" /> <caret line="138" column="53" lean-forward="true" selection-start-line="138" selection-start-column="53" selection-end-line="138" selection-end-column="53" />
<folding> <folding>
<element signature="imports" expanded="true" /> <element signature="imports" expanded="true" />
<element signature="method#testArgumentValue#0;class#converterArgument#0;class#Main#0" /> <element signature="class#converterArgumentValueType#0;class#Main#0" />
<element signature="method#tokenizer#0;class#Main#0" />
<element signature="method#getList#0;class#Main#0" /> <element signature="method#getList#0;class#Main#0" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/src/ffmpegconverter/converter/AnimeConverter.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="147">
<caret line="71" column="52" lean-forward="true" selection-start-line="71" selection-start-column="52" selection-end-line="71" selection-end-column="52" />
<folding>
<element signature="imports" expanded="true" />
<element signature="e#5093#5094#0" expanded="true" />
<element signature="e#5129#5130#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</component> </component>
<component name="masterDetails"> <component name="masterDetails">
<states> <states>

View File

@ -25,7 +25,7 @@ public class Main {
//parser(tokenizer("AnimeConverter \"C:\\Users\\Kristian\\Downloads\\Anime\\[Kametsu] ERASED (BD 1080p Hi10 FLAC)\"")); //parser(tokenizer("AnimeConverter \"C:\\Users\\Kristian\\Downloads\\Anime\\[Kametsu] ERASED (BD 1080p Hi10 FLAC)\""));
//System.exit(1); //System.exit(1);
int choice = getChoice("Which converter do you want do use?\n1. Anime to web mp4\n2. Audio converter\n3. Video converter", 1, 3); int choice = getChoice("Which converter do you want do use?\n1. Anime to web mp4\n2. Audio converter\n3. VideoStream converter", 1, 3);
System.out.println("Input for this converter:"); System.out.println("Input for this converter:");
switch (choice) { switch (choice) {
@ -183,8 +183,8 @@ public class Main {
private static void animeConverter() { private static void animeConverter() {
System.out.println("[Audio languages jpn,eng,ger,fre] [Subtitle languages eng,ger,fre] [Convert to stereo if necessary true/false] [Prevent signs&songs subtitles true/false]\nYour input: "); System.out.println("[Audio languages jpn,eng,ger,fre] [Subtitle languages eng,ger,fre] [Convert to stereo if necessary true/false] [Prevent signs&songs subtitles true/false]\nYour input: ");
List<String> input = readInput(4); List<String> input = readInput(4);
String[] audioLang = new String[]{"jpn"}; String[] audioLang = new String[]{"jpn", "*"};
String[] subtitleLang = new String[]{"eng"}; String[] subtitleLang = new String[]{"eng", "*"};
boolean toStereo = true; boolean toStereo = true;
boolean preventSigns = true; boolean preventSigns = true;
if (input.size() > 0 && getList(input, 0) != null) { if (input.size() > 0 && getList(input, 0) != null) {

View File

@ -1,5 +1,10 @@
package ffmpegconverter.converter; package ffmpegconverter.converter;
import ffmpegconverter.streams.AudioStream;
import ffmpegconverter.streams.StreamObject;
import ffmpegconverter.streams.SubtitleStream;
import ffmpegconverter.streams.VideoStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -40,9 +45,9 @@ public class AnimeConverter extends Converter {
* @throws IOException If the BufferedReader fails * @throws IOException If the BufferedReader fails
*/ */
private void processFile(File folder, File file) throws IOException { private void processFile(File folder, File file) throws IOException {
String[] streams = probeFile(ffprobePath, file); List<StreamObject> streams = probeFile(ffprobePath, file);
if (streams.length == 0) { if (streams.size() == 0) {
throw new IllegalArgumentException("The file has no streams"); throw new IllegalArgumentException("The file has no valid streams. Please make sure the file exists and is not corrupt.");
} }
String newPath = fileCollisionPrevention(folder.getAbsolutePath() + File.separator + stripExtension(file) + ".mp4", "mp4"); String newPath = fileCollisionPrevention(folder.getAbsolutePath() + File.separator + stripExtension(file) + ".mp4", "mp4");
convertProcess(new ProcessBuilder(builderCommand(ffmpegPath, file.getName(), streams, newPath)), folder); convertProcess(new ProcessBuilder(builderCommand(ffmpegPath, file.getName(), streams, newPath)), folder);
@ -57,73 +62,64 @@ public class AnimeConverter extends Converter {
* @param outFile The output file * @param outFile The output file
* @return A list of commands * @return A list of commands
*/ */
private String[] builderCommand(String executable, String fileName, String[] streams, String outFile) { private String[] builderCommand(String executable, String fileName, List<StreamObject> streams, String outFile) {
List<String> command = ffmpegWebVideo(executable, fileName); List<String> command = ffmpegWebVideo(executable, fileName);
if (this.debug) { if (this.debug) {
addDebug(command, 50, 120); addDebug(command, 50, 120);
} }
for (String lang : audioLang) { List<AudioStream> audioStreams = filterStreamsByType(streams, "audio");
List<Integer> audioStreams = listAudio(streams, lang); List<VideoStream> videoStreams = filterStreamsByType(streams, "video");
if (audioStreams.size() > 0) { List<SubtitleStream> subtitleStreams = filterStreamsByType(streams, "subtitle");
command.add("-map");
command.add("0:" + audioStreams.get(0)); audioStreams = filterAudioStreams(audioStreams, audioLang);
String[] channels = stringBetween(streams[audioStreams.get(0)], "channels=", " "); subtitleStreams = filterSubtitleStreams(subtitleStreams, subtitleLang, preventSignsAndSongs);
if (toStereo && channels.length > 0 && Integer.parseInt(channels[0]) > 2) {
command.add("-af"); VideoStream videoStream = null;
command.add("pan=stereo|FL=FC+0.30*FL+0.30*BL|FR=FC+0.30*FR+0.30*BR"); AudioStream audioStream = null;
} SubtitleStream subtitleStream = null;
break; if (videoStreams.size() > 0) {
} else { videoStream = videoStreams.get(0);
audioStreams = listAudio(streams); }
if (audioStreams.size() > 0) { if (audioStreams.size() > 0) {
command.add("-map"); audioStream = audioStreams.get(0);
command.add("0:" + audioStreams.get(0)); }
} if (subtitleStreams.size() > 0) {
subtitleStream = subtitleStreams.get(0);
}
if (videoStream == null) {
throw new IllegalArgumentException("The file does not have any valid video streams.");
}
if (audioStream != null) {
command.add("-map");
command.add("0:" + audioStream.getAbsoluteIndex());
if (toStereo && audioStream.getChannels() > 2) {
command.add("-af");
command.add("pan=stereo|FL=FC+0.30*FL+0.30*BL|FR=FC+0.30*FR+0.30*BR");
} }
} }
addSubtitles(streams, listVideo(streams), command, fileName);
if (subtitleStream != null && subtitleStream.getIsImageSubtitle()) {
command.add("-filter_complex");
command.add("[0:v:" + videoStream.getAbsoluteIndex() + "][0:" + subtitleStream.getAbsoluteIndex() + "]overlay");
} else if (subtitleStream != null) {
command.add("-map");
command.add("0:" + videoStream.getAbsoluteIndex());
command.add("-vf");
command.add("subtitles='" + fileName.replace("'", "\'") + "':si=" +
subtitleStream.getRelativeIndex());
} else {
command.add("-map");
command.add("0:" + videoStream.getAbsoluteIndex());
}
command.add(outFile); command.add(outFile);
return command.toArray(new String[0]); return command.toArray(new String[0]);
} }
private void addSubtitles(String[] streams, List<Integer> videoStreams, List<String> command, String fileName) {
for (String lang : subtitleLang) {
List<Integer> subtitleStreams;
List<Integer> subtitleStreamsAbsolute;
if (lang.equals("*")) {
subtitleStreams = listSubtitlesRelative(streams);
subtitleStreamsAbsolute = listSubtitles(streams);
} else if (preventSignsAndSongs) {
subtitleStreams = listSubtitlesRelative(streams, lang, new String[]{"title=Signs", "Signs/Songs"});
subtitleStreamsAbsolute = listSubtitles(streams, lang, new String[]{"title=Signs", "Signs/Songs"});
} else {
subtitleStreams = listSubtitlesRelative(streams, lang);
subtitleStreamsAbsolute = listSubtitles(streams, lang);
}
if (subtitleStreams.size() > 0 && videoStreams.size() > 0 && isImageSub(streams, subtitleStreamsAbsolute.get(0))) {
command.add("-filter_complex");
command.add("[0:v:" + listVideo(streams).get(0) + "][0:" + subtitleStreamsAbsolute.get(0) + "]overlay");
break;
} else if (subtitleStreams.size() > 0) {
if (videoStreams.size() > 0) {
command.add("-map");
command.add("0:" + listVideo(streams).get(0));
}
if (subtitleStreams.size() > 0) {
command.add("-vf");
command.add("subtitles='" + fileName.replace("'", "\'") + "':si=" + subtitleStreams.get(0));
}
break;
} else {
command.add("-map");
command.add("0:" + listVideo(streams).get(0));
}
}
}
@Override @Override
public String[] getValidFormats() { public String[] getValidFormats() {
return VIDEO_FORMATS; return VIDEO_FORMATS;

View File

@ -1,11 +1,11 @@
package ffmpegconverter.converter; package ffmpegconverter.converter;
import ffmpegconverter.streams.AudioStream;
import ffmpegconverter.streams.StreamObject;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.ListIterator;
public class AudioConverter extends Converter { public class AudioConverter extends Converter {
private String newExt; private String newExt;
@ -24,8 +24,8 @@ public class AudioConverter extends Converter {
* @throws IOException If the BufferedReader fails * @throws IOException If the BufferedReader fails
*/ */
private void processFile(File folder, File file, String newExt) throws IOException { private void processFile(File folder, File file, String newExt) throws IOException {
String[] streams = probeFile(ffprobePath, file); List<StreamObject> streams = probeFile(ffprobePath, file);
if (streams.length == 0) { if (streams.size() == 0) {
throw new IllegalArgumentException("The file has no streams"); throw new IllegalArgumentException("The file has no streams");
} }
String newPath = stripExtension(file) + "." + newExt; String newPath = stripExtension(file) + "." + newExt;
@ -41,12 +41,16 @@ public class AudioConverter extends Converter {
* @param outFile The output file * @param outFile The output file
* @return A list of commands * @return A list of commands
*/ */
private String[] builderCommand(String executable, String fileName, String[] streams, String outFile) { private String[] builderCommand(String executable, String fileName, List<StreamObject> streams, String outFile) {
List<String> command = generalFile(executable, fileName); List<String> command = generalFile(executable, fileName);
List<Integer> audioStreams = listAudio(streams); List<AudioStream> audioStreams = filterStreamsByType(streams, "audio");
AudioStream audioStream = null;
if (audioStreams.size() > 0) {
audioStream = audioStreams.get(0);
}
if (audioStreams.size() > 0) { if (audioStreams.size() > 0) {
command.add("-map"); command.add("-map");
command.add("0:" + audioStreams.get(0)); command.add("0:" + audioStream.getAbsoluteIndex());
} }
command.add(outFile); command.add(outFile);
return command.toArray(new String[0]); return command.toArray(new String[0]);
@ -61,120 +65,4 @@ public class AudioConverter extends Converter {
public void convert(File file) throws IOException { public void convert(File file) throws IOException {
processFile(file.getParentFile(), file, newExt); processFile(file.getParentFile(), file, newExt);
} }
public class StringList implements List<String> {
@Override
public int size() {
return 0;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(Object o) {
return false;
}
@Override
public Iterator<String> iterator() {
return null;
}
@Override
public Object[] toArray() {
return new Object[0];
}
@Override
public <T> T[] toArray(T[] a) {
return null;
}
@Override
public boolean add(String string) {
return false;
}
@Override
public boolean remove(Object o) {
return false;
}
@Override
public boolean containsAll(Collection<?> c) {
return false;
}
@Override
public boolean addAll(Collection<? extends String> c) {
return false;
}
@Override
public boolean addAll(int index, Collection<? extends String> c) {
return false;
}
@Override
public boolean removeAll(Collection<?> c) {
return false;
}
@Override
public boolean retainAll(Collection<?> c) {
return false;
}
@Override
public void clear() {
}
@Override
public String get(int index) {
return null;
}
@Override
public String set(int index, String element) {
return null;
}
@Override
public void add(int index, String element) {
}
@Override
public String remove(int index) {
return null;
}
@Override
public int indexOf(Object o) {
return 0;
}
@Override
public int lastIndexOf(Object o) {
return 0;
}
@Override
public ListIterator<String> listIterator() {
return null;
}
@Override
public ListIterator<String> listIterator(int index) {
return null;
}
@Override
public List<String> subList(int fromIndex, int toIndex) {
return null;
}
}
} }

View File

@ -1,11 +1,17 @@
package ffmpegconverter.converter; package ffmpegconverter.converter;
import ffmpegconverter.streams.AudioStream;
import ffmpegconverter.streams.StreamObject;
import ffmpegconverter.streams.SubtitleStream;
import ffmpegconverter.streams.VideoStream;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -16,13 +22,27 @@ public abstract class Converter {
String ffprobePath; String ffprobePath;
String ffmpegPath; String ffmpegPath;
private static final String PROBE_SPLIT_CHARACTER = "øæåÆØå";
public abstract String[] getValidFormats(); public abstract String[] getValidFormats();
public abstract void convert(File file) throws IOException; public abstract void convert(File file) throws IOException;
final String[] AUDIO_FORMATS = new String[] {".3gp", ".aa", ".aac", ".aax", ".act", ".aiff", ".amr", ".ape", ".au", ".awb", ".dct", ".dss", ".dvf", ".flac", ".gsm", ".iklax", ".ivs", ".m4a", ".m4b", ".m4p", ".mmf", ".mp3", ".mpc", ".msv", ".ogg", ".oga", ".mogg", ".opus", ".ra", ".rm", ".raw", ".sln", ".tta", ".vox", ".wav", ".wma", ".wv", ".webm", ".8svx"}; final String[] AUDIO_FORMATS = new String[] {".3gp", ".aa", ".aac", ".aax", ".act", ".aiff", ".amr", ".ape", ".au",
final String[] VIDEO_FORMATS = new String[] {".avi", ".mpg", ".mpeg", ".mkv", ".wmv", ".flv", ".webm", ".3gp", ".rmvb", ".3gpp", ".mts", ".m4v", ".mov", ".rm", ".asf", ".mp4", ".vob", ".ogv", ".drc", ".qt", ".yuv", ".asm", ".m4p", ".mp2", ".mpe", ".mpv", ".m2v", ".svi", ".3g2", ".roq", ".nsv"}; ".awb", ".dct", ".dss", ".dvf", ".flac", ".gsm", ".iklax", ".ivs", ".m4a", ".m4b", ".m4p", ".mmf", ".mp3",
".mpc", ".msv", ".ogg", ".oga", ".mogg", ".opus", ".ra", ".rm", ".raw", ".sln", ".tta", ".vox", ".wav",
".wma", ".wv", ".webm", ".8svx"};
final String[] VIDEO_FORMATS = new String[] {".avi", ".mpg", ".mpeg", ".mkv", ".wmv", ".flv", ".webm", ".3gp",
".rmvb", ".3gpp", ".mts", ".m4v", ".mov", ".rm", ".asf", ".mp4", ".vob", ".ogv", ".drc", ".qt", ".yuv",
".asm", ".m4p", ".mp2", ".mpe", ".mpv", ".m2v", ".svi", ".3g2", ".roq", ".nsv"};
static String[] probeFile(String ffprobePath, File file) throws IOException { /**
* Gets streams from a file
* @param ffprobePath The path/command to ffprobe
* @param file The file to probe
* @return A list of StreamObjects
* @throws IOException If the process can't be read
*/
static List<StreamObject> probeFile(String ffprobePath, File file) throws IOException {
ProcessBuilder builderProbe = new ProcessBuilder( ProcessBuilder builderProbe = new ProcessBuilder(
ffprobePath, ffprobePath,
"-v", "-v",
@ -37,13 +57,13 @@ public abstract class Converter {
BufferedReader readerProbe = new BufferedReader(new InputStreamReader(processProbe.getInputStream())); BufferedReader readerProbe = new BufferedReader(new InputStreamReader(processProbe.getInputStream()));
StringBuilder output = new StringBuilder(); StringBuilder output = new StringBuilder();
while (processProbe.isAlive()) { while (processProbe.isAlive()) {
String read = read(readerProbe, " "); String read = read(readerProbe, PROBE_SPLIT_CHARACTER);
if (!read.equals("")) { if (!read.equals("")) {
System.out.print(read); System.out.print(read);
output.append(read); output.append(read);
} }
} }
return stringBetween(output.toString(), "[STREAM]", "[/STREAM]"); return parseStreams(stringBetween(output.toString(), "[STREAM]", "[/STREAM]"));
} }
static String fileCollisionPrevention(String targetPath, String extension) { static String fileCollisionPrevention(String targetPath, String extension) {
@ -55,6 +75,12 @@ public abstract class Converter {
return file.toString(); return file.toString();
} }
/**
* Starts and prints output of a process
* @param process The process to run
* @param folder The folder the process should run in
* @throws IOException If the process can't be read
*/
static void convertProcess(ProcessBuilder process, File folder) throws IOException { static void convertProcess(ProcessBuilder process, File folder) throws IOException {
System.out.println(process.command()); System.out.println(process.command());
process.directory(folder); process.directory(folder);
@ -113,6 +139,12 @@ public abstract class Converter {
return command; return command;
} }
/**
* Adds debugging parameters for only converting parts of a file
* @param command The list containing the command to run
* @param start The offset before converting
* @param length The offset for stopping the conversion
*/
static void addDebug(List<String> command, int start, int length) { static void addDebug(List<String> command, int start, int length) {
command.add("-ss"); command.add("-ss");
command.add("" + start); command.add("" + start);
@ -120,156 +152,6 @@ public abstract class Converter {
command.add("" + length); command.add("" + length);
} }
//TODO: Create a new object for subtitle containing language, relative index, absolute index and codec. Also signs & songs.
/**
* Checks for the occurrence of otf attachments signifying the existence of image based subtitles.
*
* @param list A list of ffprobe indexes
* @return True if otf attachments were found.
*/
static boolean isImageSub(String[] list, int index) {
return list[index].contains("codec_name=hdmv_pgs_subtitle");
//Filename .sup
}
/**
* Lists all video streams.
*
* @param list A list of ffprobe indexes
* @return An integer list containing just the wanted indexes
*/
static List<Integer> listVideo(String[] list) {
return listIndexes(list, (string) -> string.contains("codec_type=video"));
}
/**
* Lists all audio streams.
*
* @param list A list of ffprobe indexes
* @return An integer list containing just the wanted indexes
*/
static List<Integer> listAudio(String[] list) {
return listIndexes(list, (string) -> string.contains("codec_type=audio"));
}
/**
* Lists all audio streams of a certain language.
*
* @param list A list of ffprobe indexes
* @param lang The wanted language
* @return An integer list containing just the wanted indexes
*/
static List<Integer> listAudio(String[] list, String lang) {
return listIndexes(list, (string) -> string.contains("codec_type=audio") && string.contains("language=" + lang));
}
/**
* Lists all subtitle streams of a certain language relatively to the number of subtitle streams.
* 0-based.
* Filters out all indexes containing anything in illegal
*
* @param list A list of ffprobe indexes
* @param lang The wanted language
* @param illegal A list of strings not to allow (Songs & Signs for example)
* @return An integer list containing just the wanted indexes
*/
static List<Integer> listSubtitles(String[] list, String lang, String[] illegal) {
List<Integer> subtitles = listIndexes(list, (string) -> string.contains("codec_type=subtitle")
&& string.contains("language=" + lang));
List<Integer> notWanted = listIndexes(list, (string) -> {
for (String s : illegal) {
if (string.contains(s)) {
return true;
}
}
return false;
});
subtitles.removeAll(notWanted);
return subtitles;
}
/**
* Lists all subtitle streams of a certain language.
*
* @param list A list of ffprobe indexes
* @param lang The wanted language
* @return An integer list containing just the wanted indexes
*/
static List<Integer> listSubtitles(String[] list, String lang) {
return listIndexes(list, (string) -> string.contains("codec_type=subtitle") && string.contains("language=" + lang));
}
/**
* Lists all subtitle indexes for video.
*
* @param list A list of ffprobe indexes
* @return An integer list containing just the wanted indexes
*/
static List<Integer> listSubtitles(String[] list) {
return listIndexes(list, (string) -> string.contains("codec_type=subtitle"));
}
/**
* Lists all subtitle streams of a certain language relatively to the number of subtitle streams.
* 0-based.
* Filters out all indexes containing anything in illegal
*
* @param list A list of ffprobe indexes
* @param lang The wanted language
* @param illegal A list of strings not to allow (Songs & Signs for example)
* @return An integer list containing just the wanted indexes
*/
static List<Integer> listSubtitlesRelative(String[] list, String lang, String[] illegal) {
List<Integer> relative = listSubtitlesRelative(list, lang);
List<Integer> subtitles = listSubtitles(list, lang);
List<Integer> notWanted = new ArrayList<>();
for (int i = 0; i < relative.size(); i++) {
for (String ill : illegal) {
if (list[subtitles.get(i)].contains(ill)) {
notWanted.add(i);
}
}
}
relative.removeAll(notWanted);
return relative;
}
/**
* Lists all subtitle streams of a certain language relatively to the number of subtitle streams.
* 0-based.
*
* @param list A list of ffprobe indexes
* @param lang The wanted language
* @return An integer list containing just the wanted indexes
*/
static List<Integer> listSubtitlesRelative(String[] list, String lang) {
list = subList(list, (string) -> string.contains("codec_type=subtitle"));
List<Integer> wanted = new ArrayList<>();
for (int i = 0; i < list.length; i++) {
if (list[i].contains("language=" + lang)) {
wanted.add(i);
}
}
return wanted;
}
/**
* Lists all subtitle streams relatively to the number of subtitle streams.
* 0-based.
*
* @param list A list of ffprobe indexes
* @return An integer list containing just the wanted indexes
*/
static List<Integer> listSubtitlesRelative(String[] list) {
list = subList(list, (string) -> string.contains("codec_type=subtitle"));
List<Integer> wanted = new ArrayList<>();
for (int i = 0; i < list.length; i++) {
wanted.add(i);
}
return wanted;
}
/** /**
* Lists all indexes fulfilling a predicate. * Lists all indexes fulfilling a predicate.
* *
@ -280,27 +162,26 @@ public abstract class Converter {
List<Integer> indexes = new ArrayList<>(); List<Integer> indexes = new ArrayList<>();
for (String str : list) { for (String str : list) {
if (p.test(str)) { if (p.test(str)) {
indexes.add(Integer.parseInt(stringBetweenSingle(str, "index=", " "))); indexes.add(Integer.parseInt(stringBetweenSingle(str, "index=", PROBE_SPLIT_CHARACTER)));
} }
} }
return indexes; return indexes;
} }
/** /**
* Returns a new list of the string for which the predicate is true. * Tests a predicate on a list
* * @param list A list
* @param list A list of ffprobe indexes * @param p A predicate
* @param p The predicate to test * @param <T> Any type
* @return A sublist of the original list * @return True if the list have an element for which the predicate is true
*/ */
private static String[] subList(String[] list, Predicate<String> p) { private static <T> boolean testPredicate(T[] list, Predicate<T> p) {
List<String> indexes = new ArrayList<>(); for (T o : list) {
for (String str : list) { if (p.test(o)) {
if (p.test(str)) { return true;
indexes.add(str);
} }
} }
return indexes.toArray(new String[]{}); return false;
} }
/** /**
@ -311,7 +192,7 @@ public abstract class Converter {
* @param end The substring after the wanted substring * @param end The substring after the wanted substring
* @return A list of all occurrences of the substring * @return A list of all occurrences of the substring
*/ */
static String[] stringBetween(String string, String start, String end) { private static String[] stringBetween(String string, String start, String end) {
int startPos = string.indexOf(start) + start.length(); int startPos = string.indexOf(start) + start.length();
if (!string.contains(start) || string.indexOf(end, startPos) < startPos) { if (!string.contains(start) || string.indexOf(end, startPos) < startPos) {
return new String[]{}; return new String[]{};
@ -338,10 +219,20 @@ public abstract class Converter {
return string.substring(startPos, string.indexOf(end, startPos)); return string.substring(startPos, string.indexOf(end, startPos));
} }
/**
* Gets filename without extension from File object
* @param file A file object
* @return A filename
*/
static String stripExtension(File file) { static String stripExtension(File file) {
return file.getName().substring(0, file.getName().lastIndexOf('.')); return file.getName().substring(0, file.getName().lastIndexOf('.'));
} }
/**
* Removes the extension from a file name
* @param file A filename
* @return A filename without its extension
*/
static String stripExtension(String file) { static String stripExtension(String file) {
return file.substring(0, file.lastIndexOf('.')); return file.substring(0, file.lastIndexOf('.'));
} }
@ -363,4 +254,166 @@ public abstract class Converter {
System.arraycopy(b, 0, c, aLen, bLen); System.arraycopy(b, 0, c, aLen, bLen);
return c; return c;
} }
/**
* Filters parsed streams into one of the stream types
* @param streams A list of stream objects
* @param codecType The codec type of the streams to select
* @param <G> The correct object type for the streams with the selected codec type
* @return A potentially shorter list of streams
*/
static <G extends StreamObject> List<G> filterStreamsByType(List<StreamObject> streams, String codecType) {
Iterator<StreamObject> i = streams.iterator();
List<G> newStreams = new ArrayList<>();
while (i.hasNext()) {
StreamObject next = i.next();
if (next.getCodecType().equals(codecType)) {
newStreams.add((G) next);
}
}
return newStreams;
}
/**
* Filters and sorts audio streams according to chosen languages
* @param audioStreams A list of audio streams
* @param audioLanguages A list of languages
* @return A list containing just audio tracks of chosen languages, sorted in order of languages
*/
static List<AudioStream> filterAudioStreams(List<AudioStream> audioStreams, String[] audioLanguages) {
List<AudioStream> filtered = new ArrayList<>();
for (String language : audioLanguages) {
for (AudioStream stream : audioStreams) {
if ((stream.getLanguage() != null && stream.getLanguage().equals(language)) || language.equals("*")) {
filtered.add(stream);
}
}
//Tries to reduce execution time from n^2
audioStreams.removeAll(filtered);
}
return filtered;
}
/**
* Filters and sorts subtitle streams according to chosen languages
* @param subtitleStreams A list of subtitle streams
* @param subtitleLanguages A list of languages
* @param preventSignsAndSongs Whether partial subtitles should be avoided
* @return A list containing just subtitles of chosen languages, sorted in order of languages
*/
static List<SubtitleStream> filterSubtitleStreams(List<SubtitleStream> subtitleStreams, String[] subtitleLanguages,
boolean preventSignsAndSongs) {
List<SubtitleStream> filtered = new ArrayList<>();
//Go through languages. Select all subtitles of the language
for (String language : subtitleLanguages) {
for (SubtitleStream stream : subtitleStreams) {
String streamLanguage = stream.getLanguage();
if (((streamLanguage != null && streamLanguage.equals(language)) || language.equals("*")) &&
(!preventSignsAndSongs || stream.getIsFullSubtitle())) {
filtered.add(stream);
}
}
//Tries to reduce execution time from n^2
subtitleStreams.removeAll(filtered);
}
return filtered;
}
/**
* Takes a list of all streams and parses each stream into one of three objects
* @param streams A list of all streams for the current file
* @return A list of StreamObjects
*/
private static List<StreamObject> parseStreams(String[] streams) {
List<StreamObject> parsedStreams = new ArrayList<>();
int relativeAudioIndex = 0;
int relativeVideoIndex = 0;
int relativeSubtitleIndex = 0;
for (String stream : streams) {
String[] streamParts = stream.split(PROBE_SPLIT_CHARACTER);
if (stream.contains("codec_type=video")) {
parsedStreams.add(parseVideoStream(streamParts, relativeVideoIndex++));
} else if (stream.contains("codec_type=audio")) {
parsedStreams.add(parseAudioStream(streamParts, relativeAudioIndex++));
} else if (stream.contains("codec_type=subtitle")) {
parsedStreams.add(parseSubtitleStream(streamParts, relativeSubtitleIndex++));
}
}
return parsedStreams;
}
/**
* Parses a list of video stream parameters to a video stream object
* @param streamParts A list of parameters belonging to an video stream
* @param relativeIndex The relative index of the video stream
* @return A SubtitleStream object
* @throws NumberFormatException If codec index contains a non-numeric value
*/
private static VideoStream parseVideoStream(String[] streamParts, int relativeIndex) throws NumberFormatException {
String codec = null;
int absoluteIndex = -1;
for (String streamPart : streamParts) {
if (streamPart.contains("codec_name=")) {
codec = streamPart.replace("codec_name=", "");
} else if (streamPart.contains("index=")) {
absoluteIndex = Integer.parseInt(streamPart.replace("index=", ""));
}
}
return new VideoStream(codec, absoluteIndex, relativeIndex);
}
/**
* Parses a list of audio stream parameters to an audio stream object
* @param streamParts A list of parameters belonging to an audio stream
* @param relativeIndex The relative index of the audio stream
* @return A SubtitleStream object
* @throws NumberFormatException If codec index contains a non-numeric value
*/
private static AudioStream parseAudioStream(String[] streamParts, int relativeIndex) throws NumberFormatException {
String codec = null;
int absoluteIndex = -1;
String language = null;
int channels = 0;
String title = "";
for (String streamPart : streamParts) {
if (streamPart.contains("codec_name=")) {
codec = streamPart.replace("codec_name=", "");
} else if (streamPart.contains("index=")) {
absoluteIndex = Integer.parseInt(streamPart.replace("index=", ""));
} else if (streamPart.contains("TAG:language=")) {
language = streamPart.replace("TAG:language=", "");
} else if (streamPart.contains("channels=")) {
channels = Integer.parseInt(streamPart.replace("channels=", ""));
} else if (streamPart.contains("TAG:title=")) {
title = streamPart.replace("TAG:title=", "");
}
}
return new AudioStream(codec, absoluteIndex, relativeIndex, language, title, channels);
}
/**
* Parses a list of subtitle stream parameters to a subtitle stream object
* @param streamParts A list of parameters belonging to a subtitle stream
* @param relativeIndex The relative index of the subtitle
* @return A SubtitleStream object
* @throws NumberFormatException If codec index contains a non-numeric value
*/
private static SubtitleStream parseSubtitleStream(String[] streamParts, int relativeIndex) throws NumberFormatException {
String codecName = null;
int absoluteIndex = -1;
String language = null;
String title = "";
for (String streamPart : streamParts) {
if (streamPart.contains("codec_name=")) {
codecName = streamPart.replace("codec_name=", "");
} else if (streamPart.contains("index=")) {
absoluteIndex = Integer.parseInt(streamPart.replace("index=", ""));
} else if (streamPart.contains("TAG:language=")) {
language = streamPart.replace("TAG:language=", "");
} else if (streamPart.contains("TAG:title=")) {
title = streamPart.replace("TAG:title=", "");
}
}
return new SubtitleStream(codecName, absoluteIndex, relativeIndex, language, title);
}
} }

View File

@ -1,5 +1,9 @@
package ffmpegconverter.converter; package ffmpegconverter.converter;
import ffmpegconverter.streams.AudioStream;
import ffmpegconverter.streams.StreamObject;
import ffmpegconverter.streams.VideoStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -22,8 +26,8 @@ public class VideoConverter extends Converter {
* @throws IOException If the BufferedReader fails * @throws IOException If the BufferedReader fails
*/ */
private void processFile(File folder, File file, String newExt) throws IOException { private void processFile(File folder, File file, String newExt) throws IOException {
String[] streams = probeFile(ffprobePath, file); List<StreamObject> streams = probeFile(ffprobePath, file);
if (streams.length == 0) { if (streams.size() == 0) {
throw new IllegalArgumentException("The file has no streams"); throw new IllegalArgumentException("The file has no streams");
} }
String newPath = fileCollisionPrevention(folder.getAbsolutePath() + File.separator + stripExtension(file) + "." + newExt, newExt); String newPath = fileCollisionPrevention(folder.getAbsolutePath() + File.separator + stripExtension(file) + "." + newExt, newExt);
@ -39,15 +43,24 @@ public class VideoConverter extends Converter {
* @param outFile The output file * @param outFile The output file
* @return A list of commands * @return A list of commands
*/ */
private String[] builderCommand(String executable, String fileName, String[] streams, String outFile, File folder) { private String[] builderCommand(String executable, String fileName, List<StreamObject> streams, String outFile, File folder) {
List<String> command = generalFile(executable, fileName); List<String> command = generalFile(executable, fileName);
if (this.debug) { if (this.debug) {
addDebug(command, 50, 120); addDebug(command, 50, 120);
} }
List<Integer> videoStreams = listVideo(streams); List<AudioStream> audioStreams = filterStreamsByType(streams, "audio");
List<Integer> audioStreams = listAudio(streams); List<VideoStream> videoStreams = filterStreamsByType(streams, "video");
VideoStream videoStream = null;
AudioStream audioStream = null;
if (videoStreams.size() > 0) {
videoStream = videoStreams.get(0);
}
if (audioStreams.size() > 0) {
audioStream = audioStreams.get(0);
}
String ext = hasExternalSubtitle(folder.getAbsolutePath(), fileName); String ext = hasExternalSubtitle(folder.getAbsolutePath(), fileName);
String ext2 = hasExternalImageSubtitle(folder.getAbsolutePath(), fileName); String ext2 = hasExternalImageSubtitle(folder.getAbsolutePath(), fileName);
@ -62,7 +75,7 @@ public class VideoConverter extends Converter {
} }
//TODO: Scale subtitles to video //TODO: Scale subtitles to video
command.add("-filter_complex"); command.add("-filter_complex");
command.add("[1:s]scale=width=1920:height=800,crop=w=1920:h=800:x=0:y=out_h[sub];[" + videoStreams.get(0) + ":v][sub]overlay"); command.add("[1:s]scale=width=1920:height=800,crop=w=1920:h=800:x=0:y=out_h[sub];[" + videoStream + ":v][sub]overlay");
command.add("-profile:v"); command.add("-profile:v");
command.add("baseline"); command.add("baseline");
} }
@ -70,11 +83,11 @@ public class VideoConverter extends Converter {
if (ext2.equals("") || !ext.equals("")) { if (ext2.equals("") || !ext.equals("")) {
if (videoStreams.size() > 0) { if (videoStreams.size() > 0) {
command.add("-map"); command.add("-map");
command.add("0:" + videoStreams.get(0)); command.add("0:" + videoStream);
} }
if (audioStreams.size() > 0) { if (audioStreams.size() > 0) {
command.add("-map"); command.add("-map");
command.add("0:" + audioStreams.get(0)); command.add("0:" + audioStream);
} }
} }
command.add("-af"); command.add("-af");

View File

@ -0,0 +1,29 @@
package ffmpegconverter.streams;
public class AudioStream extends StreamObject {
private String language; //The audio language
private int channels; //Whether mono, stereo, etc
private String title; //Titles exist
public AudioStream(String codec, int absoluteIndex, int relativeIndex, String language, String title, int channels) {
this.codecType = "audio";
this.codecName = codec;
this.absoluteIndex = absoluteIndex;
this.language = language;
this.title = title;
this.relativeIndex = relativeIndex;
this.channels = channels;
}
public String getLanguage() {
return this.language;
}
public int getChannels() {
return this.channels;
}
public String getTitle() {
return this.title;
}
}

View File

@ -0,0 +1,43 @@
package ffmpegconverter.streams;
/**
* An object representation of a stream in a media file
*/
public abstract class StreamObject {
int absoluteIndex;
int relativeIndex;
String codecName;
String codecType;
/**
* Gets the type of the stream codec (video/audio/subtitle)
* @return codec type
*/
public String getCodecType() {
return this.codecType;
}
/**
* Gets the name of the stream codec
* @return codec name
*/
public String getCodecName() {
return this.codecName;
}
/**
* Gets the absolute index of a stream object
* @return absolute index
*/
public int getAbsoluteIndex() {
return this.absoluteIndex;
}
/**
* Gets the relative index of a stream object (kth element of codec type)
* @return relative index
*/
public int getRelativeIndex() {
return this.relativeIndex;
}
}

View File

@ -0,0 +1,59 @@
package ffmpegconverter.streams;
/**
* An object representation of a subtitle stream in a media file
*/
public class SubtitleStream extends StreamObject {
private String language;
private String title; //Title shown
private boolean isFullSubtitle; //Songs and signs will be false
private boolean isImageSubtitle;
public SubtitleStream(String codecName, int absoluteIndex, int relativeIndex, String language, String title) {
this.codecType = "subtitle";
this.codecName = codecName;
this.absoluteIndex = absoluteIndex;
this.language = language;
this.title = title;
this.isFullSubtitle = isFullSubtitle();
this.relativeIndex = relativeIndex;
this.isImageSubtitle = isImageSubtitle();
}
/**
* Checks whether a subtitle is image based (as opposed to text based)
* @return True if the subtitle is image based
*/
private boolean isImageSubtitle() {
return codecName != null && getCodecName().equals("hdmv_pgs_subtitle");
}
/**
* Checks whether translates everything (as opposed to just songs and signs)
* @return True if the subtitles translate everything
*/
private boolean isFullSubtitle() {
if (getTitle() == null) {
return false;
}
String title = getTitle().toLowerCase();
return !(title.contains("songs and signs") || title.contains("songs & signs") || title.contains("songs ") ||
title.contains("signs/songs") || title.contains("[forced]") || title.contains("(forced)"));
}
public String getLanguage() {
return this.language;
}
public String getTitle() {
return this.title;
}
public boolean getIsImageSubtitle() {
return this.isImageSubtitle;
}
public boolean getIsFullSubtitle() {
return this.isFullSubtitle;
}
}

View File

@ -0,0 +1,13 @@
package ffmpegconverter.streams;
/**
* An object representation of a video stream in a media file
*/
public class VideoStream extends StreamObject {
public VideoStream(String codec, int absoluteIndex, int relativeIndex) {
this.codecType = "video";
this.codecName = codec;
this.absoluteIndex = absoluteIndex;
this.relativeIndex = relativeIndex;
}
}