Recently, due to the project needs, the study of how to use Java to achieve video conversion, "really" waste a little thought, finishing, write to their own forget.
Ideas
Since there is no previous experience of the relevant functions, I really don't know where to start at first. Of course, this solution, Google immediately found the ffmpeg, online commentary with Java+ffmpeg to do video conversion of the article also a few, I mainly refer to this article.
The above mentioned article, basically has been the development process or something is very clear, here summarized below:
1) The core is the use of ffmpeg for video conversion, we do not write the conversion video code, just call FFmpeg, it will help us complete the video conversion. The types supported by FFmpeg are: asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv, etc., which can be converted directly using FFmpeg. FFmpeg unsupported types are: WMV9,RM,RMVB, etc., these types need to be converted to AVI (ffmpeg resolvable) format first with another tool (MEncoder).
2) Understand how Java calls external programs, which can be the most difficult, and will be the most pit place.
3) Set the FFmpeg parameters according to our requirements. (This kind of article is already a lot of online, I do not have to copy the paste, see here)
Code
The code in the article mentioned above is actually very friendly, basically it can be used, but there are still a lot of problems, and then the following is the code in this article:
1 Import java.io.File; 2 Import java.util.ArrayList; 3 Import Java.util.Calendar; 4 Import java.util.List; 5 6 public class Convertvideo {7 8 private final static String PATH = "C:\\ffmpeg\\input\\c.mp4"; 9 public static void Main (string[] args) {one!checkfile (PATH)) {System.out.prin TLN (PATH + "is not file"); return; (process ()) {System.out.println ("OK"); +} + private static Boolean process () {int type = Checkcontenttype (); The Boolean status = FALSE; if (type = = 0) {System.out.println ("Convert file directly to FLV file"); Status = processflv (PATH),//convert the file directly to FLV file, or else if (type = = 1) {String avif Ilepath = Processavi (type); if (Avifilepath = = null) return false;//AVI file did not get the STatus = processflv (Avifilepath);//convert AVI to FLV and return status; Checkcontenttype () {$ String type = path.substring (path.lastindexof (".") + 1, path.length ()) Notoginseng tolowercase (); FFmpeg//Can parse the format: (asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv, etc.) (Type.equals ("avi")) (40) return 0; Type.equals} else if ("mpg") {0; Type.equals} else if ("wmv") {0; Type.equals} else if ("3gp") {0; Type.equals} else if (("mov")) {0; Type.equals} else if ("mp4") {0 return; Type.equals} else if ("asf") {0; Type.equals} else if ("ASX") {0; "Else if (type.equals (" flv ")) {0; 57 } 58//FFmpeg unresolved file formats (WMV9,RM,RMVB, etc.), 59//can first be converted to AVI (ffmpeg resolvable) format with another tool (MEncoder). -Else if (type.equals ("WMV9")) {1; Type.equals} else if ("rm") {1; * Else if (type.equals ("RMVB")) {1; 9; A. Checkfile (String path) {The file = new file (path) of the private static Boolean if (!file.isfile ()) {return false; The "* *}" return true; 76} 77 78//For FFmpeg unresolved file formats (WMV9,RM,RMVB, etc.), you can first convert to AVI (ffmpeg resolvable) format with another tool (MEncoder). Processavi private static String (int type) {List<string> commend = new Arraylist<string> ( ); Bayi Commend.add ("C:\\ffmpeg\\mencoder"); Commend.add (PATH); Commend.add ("-oac"); Commend.add ("LAVC"); Commend.add ("-lavCopts "); Commend.add ("acodec=mp3:abitrate=64"); Commend.add ("-OVC"); Commend.add ("XviD"); Commend.add ("-xvidencopts"); Commend.add ("bitrate=600"); Commend.add ("-of"); Commend.add ("Avi"); Commend.add ("-O"); 94 Commend.add ("C:\\ffmpeg\\output\\a.avi"); try {processbuilder builder = new Processbuilder (); Builder.command (commend); 98 Builder.start (); return "C:\\ffmpeg\\output\\a.avi"; (Exception e) {101 e.printstacktrace (); 102 return NULL; 103} 104} 106//FFmpeg can parse the format: (asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv, etc.) 107 private static Boo Lean processflv (String Oldfilepath) {108 109 if (!checkfile (PATH)) {System.out.println (OLDFI Lepath + "is not file"); 111 return false; 112} 113 114//File name: the Calendar c = calendar.getinstance (); Savename String = string.valueof (C.gettimeinmillis ()) + Math.Round (math.random () * 100000); 117 List<string> commend = new arraylist<string> (); 118 Commend.add ("C:\\ffmpeg\\ffmpeg"); 119 Commend.add ("-i"); Commend.add (Oldfilepath); 121 Commend.add ("-ab"); 122 Commend.add ("56"); 123 Commend.add ("-ar"); 124 Commend.add ("22050"); Commend.add ("-qscale"); 126 Commend.add ("8"); 127 Commend.add ("-R"); Commend.add ("15"); 129 Commend.add ("-S"); Commend.add ("600x500"); 131 Commend.add ("c:\\ffmpeg\\output\\a.flv"); 133 try {134 Runtime runtime = Runtime.getruntime (); 135 Process proce = null; 136 String cmd = ""; 137 String cut = "C:\\ffmpeg\\ffmpeg.exe-i" 138 + Oldfilepath 139 + "-y-f image2-ss 8-t 0.001-s 600x500 C: \\ffmpeg\\output\\ "+" a.jpg "; 141 String cutcmd = cmd + cut; 142 Proce = runtime.exec (cutcmd); 143 Processbuilder builder = new Processbuilder (commend); 144 Builder.command (commend); 145 Builder.start (); 146 147 return true; 148} catch (Exception e) {149 e.printstacktrace (); return false; 151} 152} 153}
Next I have my own revised code:
1 Import java.io.File; 2 Import java.io.IOException; 3 Import java.util.ArrayList; 4 Import Java.util.Calendar; 5 Import Java.util.List; 6 public class Convertvideo {7 8 private static String InputPath = ""; 9 private static String OutputPath = ""; Each of the private static String Ffmpegpath = ""; public static void Main (String args[]) throws IOException {GetPath (); 17 1 8 if (!checkfile (InputPath)) {System.out.println (InputPath + "is not file"); retur N + if (process ()) {System.out.println ("OK"); vate static void GetPath () {//Get the current project path first, get the source file, destination file, converter path, diretory = new File (""); try {String Currpath = Diretory.getabsolutepath (); InputPath = Currpath + "\\inp Ut\\test.wmv "; OutputPath = Currpath + "\\output\\"; 33 Ffmpegpath = Currpath + "\\ffmpeg\\"; System.out.println (Currpath); (Exception e) {PNs System.out.println ("GetPath error"); 38} 39} 40 $ private static Boolean process () {Checkcontenttype int type = + = = = = = = = = = = = = = = = = = FALSE; 4 4 if (type = = 0) {System.out.println ("go directly to FLV format"); status = processflv (InputPath); /directly to the FLV format, or else if (type = = 1) {Avifilepath String = Processavi (type); Ifilepath = = null) The return false;//did not get the AVI format in the status = processflv (Avifilepath);//convert AVI to F LV Format: * * return status; * * * * The private static int Checkcontenttype () {String type = inputpath.substring (inputpath.lastind Exof (".") + 1, inputpath.length ()). toLowerCase (); FFmpeg can parse the format: (Asx,asf,mpg,wmv,3gp,mp4,mov,avi,FLV, etc) if (type.equals ("avi")) {0, + +} else if (Type.equals ("mpg")) {63 return 0; 0} else if (Type.equals ("wmv")) {67 ("3gp")} return 0; Type.equals} else if (("mov")) {0, +} else if (Type.equals ("mp4")) {71 return 0; Type.equals} else if (Type.equals ("ASF")) {return 0;???? return 0; Type.equals} else if ("flv") {0, 78} 79//ffmpeg unresolved file format (wmv9,rm,r MVB, etc.), 80//can be converted to the AVI (ffmpeg resolvable) format with another tool (MEncoder) first. Bayi Else if (type.equals ("WMV9")) {type.equals return 1;??? return 1; Type.equals} else if ("rmvb") {"1"); PrivatE Static Boolean checkfile (String path) {file File = new file (path);!file.isfile ()) {94 return false; () 97} 98 99//For FFmpeg unresolved file formats (WMV9,RM,RMVB, etc.), you can first convert to AVI (ffmpeg resolvable) format with another tool (mencoder). private static Stri ng Processavi (int type) {101 List<string> commend = new arraylist<string> (); 102 Commend.add (FF Mpegpath + "mencoder"); 103 Commend.add (InputPath); 104 Commend.add ("-OAC"); Commend.add ("LAVC"); 106 Commend.add ("-lavcopts"); 107 Commend.add ("acodec=mp3:abitrate=64"); 108 Commend.add ("-OVC"); 109 Commend.add ("XviD"), Commend.add ("-xvidencopts"), 111 Commend.add ("bitrate=600"); Mmend.add ("-of"); 113 Commend.add ("Avi"); Commend.add ("-O"); Commend.add (OutputPath + "A.avi") ); try {117 Processbuilder builder = new Processbuilder (); 118 Process Process = Builder.command (commend). Redirecterrorstream (True). Start (); 119 New PrintStream (proc Ess.getinputstream ()); New PrintStream (Process.geterrorstream ()); 121 process.waitfor (); 122 return OutputPath + "A.avi"; 123} catch (Exception e) {124 e.printstacktrace (); 125 return null;126}127}128 129//FFmpeg can parse the format: (asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv etc) the private Stati C Boolean processflv (String oldfilepath) {131 if (!checkfile (InputPath)) {133 SYSTEM.OUT.PRINTLN (o Ldfilepath + "is not file"); 134 return false;135}136 137 list<string> command = new arraylist<string> (); 138 Command.add (Ffmpegpath + "FFmpeg"); 139 Command.add ("-i"); Ommand.add (Oldfilepath), 141 command.add ("-ab"), 142 Command.add ("the" "143"); Command.add ("22050145 Command.add ("-qscale"), 146 Command.add ("8"), 147 Command.add ("-R"); 148 Command.add (" 149 Command.add ("-S"), Command.add ("600x500"), 151 Command.add (OutputPath + "a.flv"); 152 15 3 try {154 155//Scenario 1156//Process videoprocess = Runtime.getruntime (). EXEC (FF Mpegpath + "Ffmpeg-i" + Oldfilepath 157//+ "-ab 56-ar 22050-qscale 8-r 15-s 600x500" 158// + OutputPath + "a.flv"); 159 160//program 2161 Process videoprocess = new Processbuilder (command). Redirecterrorstream (True). Start (); 162 163 New PrintStream (Videoprocess.get Errorstream ()). Start (); 164 165 New PrintStream (Videoprocess.getinputstream ()). Start (); 166 167 videoprocess.waitfor (); 168 169 Return true;170} catch (Exception e) { 171 e.printsTacktrace (); 172 return false;173}174}175}176 177 class PrintStream extends Thread 178 {179 Java.io.InputStream __is = null;180 public PrintStream (Java.io.InputStream is) 181 {182 __is = is;183 } 184 185 public void Run () 186 {187 Try 188 {189 and (this = null) 190 {191 int _ch = __is.read () 192 if (_ch! =-1) 193 System.out.print (cha R) _ch); 194 Else break;195}196} 197 catch (Exception e) 198 {199 E.printstacktrace (); 200} 201}202}
Problem
In the original code there is a big problem, is not know when the video conversion end. Look at these two codes in the original text:
98 line at
1 Builder.command (commend); 2 Builder.start ();
145 Line at
1 Builder.start (); 2 3 return true;
After the process has started, the results are returned directly. You know, this way of writing does not block the current process, that is, of course, when the program returns, the Transcoding program (FFmpeg and MEncoder) is still executing. If you need to mencoder for intermediate transcoding, the original text of the writing will cause the AVI file is not converted to complete, the program calls the FFmpeg to convert. And for the final FLV file, we have no way of knowing exactly when the conversion is good, which is clearly not enough to meet our business needs.
Solution Solutions
The first idea is to block the current process (the main process), the instance code:
1 Process Process = new Processbuilder (command), start (), 2 process.waitfor (), 3 return true;
Using this scheme to run the program, found that the video turned to more than 10 seconds when the time is not turned, but the program has not returned, open the Process Manager, the FFmpeg process is still in, the memory is still occupied, but the CPU is 0,
At that time do not know what reason, on the internet for half a day, only to understand that this is a deadlock, but do not know what caused the cause. At that time, it has been felt that the deadlock is waitfor () function, it seems to use it to determine whether the child process is not the result is not, so in the online search for a half a day other judgment sub-process of the end of the method (in fact, it has been detours). Some say you can use Exitvalue (), so you have the following code:
1 Process Process = new Processbuilder (command). Start (); 2 while (true) {3 try {4 if (process.exitvalue () = = 0) 5 break ; 6 } 7 catch (illegalthreadstateexcep tion e) {8 continue; 9 }10}11 return true;
When the child process does not end, if the execution of Exitvalue () throws an exception, I use the method to catch the exception and then ignore it until the program ends Exitvalue () returns 0. However, failed, the situation and the same as in the WAITFOR () way, I think it may be another reason, in the go to Google, it may be because the JVM only provides limited cache space, When the output stream of an external program (child process) exceeds this limited space and the parent process does not read the data, the child process is blocked waitfor () will never return, causing a deadlock.
Official explanation:
Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly Write the input stream or read the output stream of the subprocess cause the subprocess to block, and even deadlock.
Know the problem will be the right remedy (in fact, I do not know if this is not the problem I encountered, only a variety of scattered bombs, hit the count). about how to read out the output stream of the sub-process, how to solve the deadlock, the online approach is much the same, write better can see this address.
The program is then changed to this:
1 Process Process = new Processbuilder (command). Start (); 2 3 new PrintStream (Process.getinputstream ()). Start (); 4 5 process.waitfor ();
The PrintStream class is as follows:
1 class PrintStream extends Thread 2 {3 java.io.InputStream __is = null; 4 public PrintStream (Java.io.InputS Tream is) 5 {6 __is = was; 7 } 8 9 public Void Run () Ten {one try while (this = null) is { _ch int = __is.read (); ( _ch! =-1) + System.out.print ((char) _ch); 18 Else break;19 } The catch (Exception e) is { e.printstacktrace (); }26}
Run, found or not, the symptoms and the same as before, I thought it is not the output stream too much, a thread not read fast enough (well, really silly very naïve, people are forced to really what ideas have), so I opened a few identical threads, the result is the same.
Just when I was about to give up, in Baidu know, looked at a trivial example, so made a small change, before the process started, redirected the next error output stream, as follows:
1 Process videoprocess = new Processbuilder (command). Redirecterrorstream (True). Start (); 2 3 new PrintStream ( Videoprocess.getinputstream ()). Start (); 4 5 videoprocess.waitfor (); 6 7 return true;
Then, then, then you can, messy ...
Conclusion
In fact, there are two ways to solve this problem, such things as I wrote above, as well as the following:
1 Process videoprocess = new Processbuilder (command). Start (); 2 3 new PrintStream (Videoprocess.geterrorstream ()). Start (); 4 5 new PrintStream (Videoprocess.getinputstream ()). Start (); 6 7 videoprocess.waitfor (); 8 9 return true;
In fact, the same is true, is to read out the FFmpeg output stream, to avoid the ffmpeg output stream plug full cache caused deadlock. But do not know why, ffmpeg output information is in the error output stream inside, I looked at the console printing results, found just some current transition status information, and no errors, puzzling.
In the process class, getInputStream is used to get the output stream of the processes, Getoutputstream is used to get the input stream of the process, Geterrorstream is used to get the error stream of the process. For the sake of insurance, it is best to read out the output stream and error stream of the process when it is read, so that the buffer can be emptied.
In fact, I deeply feel that these problems solved the experience is the standard of the loose-bomb programming, hit to which, after warning.
Java+windows+ffmpeg for video Conversion