Java Forum / General / August 2007
Java Media Framework:To Compress AVI video.
Misterysword@hotmail.com - 20 Jul 2007 10:41 GMT Hi!! I have got a program that it make an AVI video without compressing, with RGB format.
How can I compress the video with format MJPEG (for example)????
Regards!
Andrew Thompson - 20 Jul 2007 11:04 GMT >Hi!! I have got a program that it make an AVI video without >compressing, with RGB format. > >How can I compress the video with format MJPEG (for example)???? The JMF Performance Pack supports MJPEG (422) for AVI encoding on Win and *nix, so the code should only need to call for that CODEC at the time of encoding.
 Signature Andrew Thompson http://www.athompson.info/andrew/
Misterysword@hotmail.com - 03 Aug 2007 08:50 GMT > Misterysw...@hotmail.com wrote: > >Hi!! I have got a program that it make an AVI video without [quoted text clipped - 10 lines] > > Message posted viahttp://www.javakb.com Hi.
I do:
_______________________________________________________________
Format f[] = tcs[0].getSupportedFormats();
if (f == null || f.length <= 0) { System.err.println("The mux does not support the input format: " + tcs[0].getFormat()); return false; } else{ for( int i=0; i< f.length; i++ ){ if( f[i].getEncoding().equals("mjpg") ){ tcs[0].setFormat(f[i]); } } }
_______________________________________________________________
But I don't work... Can you give me an example code? Thanks
Andrew Thompson - 03 Aug 2007 10:03 GMT ...
>I do: <Snip code snippet>
Code that is not compilable is no use to me, I will not look at it. If you want me to look at code, post an SSCCE*.
>But I don't work... It does not work? Maybe it is just lazy. Try giving it a flogging, that might 'motivate' it.
>..Can you give me an example code? Can you pay me? I am happy to churn out code, or perform consultancy, for an appropriate fee. For free, here (with the damnable JMF) you get my attention for an SSCCE*.
>...Thanks No worries.
* An SSCCE is a very specific type of code.. <http://www.physci.org/codes/sscce.html>
 Signature Andrew Thompson http://www.athompson.info/andrew/
Misterysword@hotmail.com - 03 Aug 2007 17:52 GMT > Misterysw...@hotmail.com wrote: > [quoted text clipped - 31 lines] > > Message posted via JavaKB.comhttp://www.javakb.com/Uwe/Forums.aspx/java-general/200708/1 Ok, sorry for my stupidity...
For example, compilable code:
import java.awt.*; import java.awt.image.*; import java.io.*; import javax.imageio.*; import javax.media.*; import javax.media.control.*; import javax.media.datasink.*; import javax.media.format.*; import javax.media.protocol.*;
/**For AVI files, each frame must have a time stamp set.See the following message from the jmf - interest archives for details : http : //archives.java.sun.com/cgi-bin/wa?A2=ind0107&L=jmf- interest&P=R34660 */ public class AviCreator implements ControllerListener, DataSinkListener {
private boolean doIt(int width, int height, int frameRate, MediaLocator outML) {
ImageDataSource ids = new ImageDataSource(width, height, frameRate); Processor p; try { System.err.println("- create processor for the image datasource ..."); p = Manager.createProcessor(ids); } catch (Exception e) { System.err.println("Yikes! Cannot create a processor from the data source."); return false; } p.addControllerListener(this); // Put the Processor into configured state so we can set some processing options on the processor. p.configure(); if (!waitForState(p, Processor.Configured)) { System.err.println("Failed to configure the processor."); return false; } // Set the output content descriptor to QuickTime. p.setContentDescriptor(new ContentDescriptor(FileTypeDescriptor.MSVIDEO)); //p.setContentDescriptor(new ContentDescriptor(FileTypeDescriptor.QUICKTIME)); // Query for the processor for supported formats. // Then set it on the processor. TrackControl tcs[] = p.getTrackControls(); Format f[] = tcs[0].getSupportedFormats(); if (f == null || f.length <= 0) { System.err.println("The mux does not support the input format: " + tcs[0].getFormat()); return false; } tcs[0].setFormat(f[0]); System.err.println("Setting the track format to: " + f[0]); // We are done with programming the processor. Let's just realize it. p.realize(); if (!waitForState(p, Processor.Realized)) { System.err.println("Failed to realize the processor."); return false; } // Now, we'll need to create a DataSink. DataSink dsink; if ((dsink = createDataSink(p, outML)) == null) { System.err.println("Failed to create a DataSink for the given output MediaLocator: " + outML); return false; } dsink.addDataSinkListener(this); fileDone = false; System.err.println("start processing..."); // OK, we can now start the actual transcoding. try {
p.start(); dsink.start();
} catch (IOException e) { System.err.println("IO error during processing"); return false; } // Wait for EndOfStream event. waitForFileDone(); // Cleanup. try { dsink.close(); } catch (Exception e) { } p.removeControllerListener(this); System.err.println("...done processing."); return true; }
/** Create the DataSink. */ private DataSink createDataSink(Processor p, MediaLocator outML) { DataSource ds; if ((ds = p.getDataOutput()) == null) { System.err.println("Something is really wrong: the processor does not have an output DataSource"); return null; } DataSink dsink; try { System.err.println("- create DataSink for: " + outML); dsink = Manager.createDataSink(ds, outML); dsink.open(); } catch (Exception e) { System.err.println("Cannot create the DataSink: " + e); return null; } return dsink; }
private Object waitSync = new Object();
private boolean stateTransitionOK = true;
/** Block until the processor has transitioned to the given state. * Return false if the transition failed. */ private boolean waitForState(Processor p, int state) { synchronized (waitSync) { try { while (p.getState() < state && stateTransitionOK) { waitSync.wait(); } } catch (Exception e) { } } return stateTransitionOK; }
/** Controller Listener. */ public void controllerUpdate(ControllerEvent evt) {
if (evt instanceof ConfigureCompleteEvent || evt instanceof RealizeCompleteEvent || evt instanceof PrefetchCompleteEvent) { synchronized (waitSync) { stateTransitionOK = true; waitSync.notifyAll(); } } else if (evt instanceof ResourceUnavailableEvent) { synchronized (waitSync) { stateTransitionOK = false; waitSync.notifyAll(); } } else if (evt instanceof EndOfMediaEvent) { evt.getSourceController().stop(); evt.getSourceController().close(); System.out.println("Se procue CONTROLLER-END"); } }
private Object waitFileSync = new Object();
private boolean fileDone = false;
private boolean fileSuccess = true;
/** Block until file writing is done. */ private boolean waitForFileDone() { synchronized (waitFileSync) { try { while (!fileDone) { waitFileSync.wait(); } } catch (Exception e) { } } return fileSuccess; }
/** * Event handler for the file writer. */ public void dataSinkUpdate(DataSinkEvent evt) { if (evt instanceof EndOfStreamEvent) { synchronized (waitFileSync) { fileDone = true; waitFileSync.notifyAll(); System.out.println("Se procue DATASINKEVENT-END"); } } else if (evt instanceof DataSinkErrorEvent) { synchronized (waitFileSync) { fileDone = true; fileSuccess = false; waitFileSync.notifyAll(); } } }
/** Self-test main. * @param args Arguments from the command-line. * @exception java.lang.Exception case of errors. */ public static void main(String args[]) throws Exception { //jpegCreator.main(null); //if (args.length == 0) // prUsage(); // Parse the arguments. int i = 0; int width = -1, height = -1, frameRate = 1; //Vector inputFiles = new Vector(); String outputURL = null; //width = 658; //height = 573; width = 1280;//657; height = 800;//573; outputURL = "test.avi"; //outputURL = "test.mov"; // Generate the output media locators. MediaLocator oml; if ((oml = createMediaLocator(outputURL)) == null) { System.err.println("Cannot build media locator from: " + outputURL); System.exit(1); } AviCreator imageToMovie = new AviCreator(); imageToMovie.doIt(width, height, frameRate, oml); System.exit(0); }
/* static void prUsage() { System.err.println("Usage: java JpegImagesToMovie -w <width> -h <height> -f <frame rate> -o <output URL> <input JPEG file 1> <input JPEG file 2> ..."); System.exit( -1); } */
/** Create a media locator from the given string. */ // Allows JMF to locate output file. private static MediaLocator createMediaLocator(String url) { MediaLocator ml; if (url.indexOf(":") > 0 && (ml = new MediaLocator(url)) != null) { return ml; } if (url.startsWith(File.separator)) { if ((ml = new MediaLocator("file:" + url)) != null) { return ml; } } else { String file = "file:" + System.getProperty("user.dir") + File.separator + url; if ((ml = new MediaLocator(file)) != null) { return ml; } } return null; }
/////////////////////////////////////////////// // // Inner classes. ///////////////////////////////////////////////
/** A DataSource to read from a list of JPEG image files and turn that into a stream of JMF buffers. * The DataSource is not seekable or positionable. */ private class ImageDataSource extends PullBufferDataSource {
private ImageSourceStream[] streams;
ImageDataSource(int width, int height, int frameRate) { streams = new ImageSourceStream[1]; streams[0] = new ImageSourceStream(width, height, frameRate); }
public void setLocator(MediaLocator source) { }
public MediaLocator getLocator() { return null; }
/** Content type is of RAW since we are sending buffers of video frames without a container format. */ public String getContentType() { return ContentDescriptor.RAW; }
public void connect() { }
public void disconnect() { }
public void start() { }
public void stop() { }
/** Return the ImageSourceStreams. */ public PullBufferStream[] getStreams() { return streams; }
/** We could have derived the duration from the number of frames and frame rate. But for the purpose of this program, it's not necessary. */ public Time getDuration() { System.out.println("dur is " + streams[0].nextImage); //return new Time(1000000000); return DURATION_UNKNOWN; }
public Object[] getControls() { return new Object[0]; }
public Object getControl(String type) { return null; } }
/** The source stream to go along with ImageDataSource. */ class ImageSourceStream implements PullBufferStream {
private final int width, height;
private final VideoFormat format;
private BufferedImage frame = null;
// Bug fix from Forums - next two lines private float frameRate; private long seqNo = 0;
private int nextImage = 0; // index of the next image to be read. private boolean ended = false;
public ImageSourceStream(int width, int height, int frameRate) { this.width = width; this.height = height;
// Bug fix from Forums (next line) this.frameRate = (float) frameRate;
final int rMask = 0x00ff0000; final int gMask = 0x0000FF00; final int bMask = 0x000000ff;
format = new javax.media.format.RGBFormat(new Dimension(width, height), Format.NOT_SPECIFIED, Format.intArray, frameRate, 32, bMask, gMask, rMask);
}
/** * We should never need to block assuming data are read from files. */ public boolean willReadBlock() { return false; }
/** This is called from the Processor to read a frame worth of video data. */ public void read(Buffer buf) throws IOException { // Check if we've finished all the frames. if (nextImage >= 5) { // We are done. Set EndOfMedia. System.err.println("Done reading all images."); buf.setEOM(true); buf.setOffset(0); buf.setLength(0); ended = true; return; } int max = (int) Math.log10(252); int current = (nextImage != 0) ? (int) Math.log10(nextImage) : 0; StringBuilder b = new StringBuilder("image"); for (int i = current; i < max; i++) { b.append(0); } b.append(nextImage).append(".png"); System.out.println(b.toString()); BufferedImage image = ImageIO.read(new File(b.toString())); if ((image.getWidth() != width) || (image.getHeight() != height)) { // Lazily create frame of the correct size. if (frame == null) { frame = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); } Graphics2D graphics = frame.createGraphics(); graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); graphics.drawImage(image, 0, 0, width, height, null); graphics.dispose(); } else { frame = image; } nextImage++; int[] data = null; if (buf.getData() instanceof int[]) { data = (int[]) buf.getData(); } // Check to see the given buffer is big enough for the frame. if (data == null || data.length < width * height) { data = new int[width * height]; buf.setData(data); } data = frame.getRGB(0, 0, width, height, data, 0, width); // Bug fix from Forums ( next 3 lines). long time = (long) (seqNo * (1000 / frameRate) * 1000000); buf.setTimeStamp(time); buf.setSequenceNumber(seqNo++); buf.setData(data); buf.setOffset(0); buf.setLength(width * height); buf.setFormat(format); buf.setFlags(buf.getFlags() | Buffer.FLAG_KEY_FRAME); }
/** * Return the format of each video frame. That will be JPEG. */ public Format getFormat() { return format; }
public ContentDescriptor getContentDescriptor() { return new ContentDescriptor(ContentDescriptor.RAW); }
public long getContentLength() { return 0; }
public boolean endOfStream() { return ended; }
public Object[] getControls() { return new Object[0]; }
public Object getControl(String type) { return null; } } }
______________________________________________________________________________________________________________
Notes:
- This program makes a AVI video (with name "test.avi") from a sequence of images (PNG). - You must put images with this type of name: "image000.png", "image001.png", "image002.png"....In this case, you must put five images (from 000 to 004). You can change the number of images in the line: 359 (method: read( Buffer buf ) ).
PROBLEM:
The size of video is fairly big since I don't use compression. Frames are RGB. This video should be compressed with MJPEG, but I don't know to use compression. I thing that the key is in the lines 39-45. I changed this part and I put:
__________________________________________________________________________-
Format f[] = tcs[0].getSupportedFormats();
if (f == null || f.length <= 0) { System.err.println("The mux does not support the input format: " + tcs[0].getFormat()); return false; } /*else{ for( int i=0; i< f.length; i++ ){ System.err.println("PASA="+f[i].getEncoding()); if( f[i].getEncoding().equals("mjpg") ){ tcs[0].setFormat(f[i]); System.err.println("Lo coge en="+i); } } }*/
tcs[0].setFormat(f[0]);
______________________________________________________________________________________________________________________
BUT I didn't work...
Please, help me with any idea.
Regards.
Lew - 03 Aug 2007 23:10 GMT > /**For AVI files, each frame must have a time stamp set.See the > following message from the jmf - interest archives for details : [quoted text clipped - 18 lines] > return false; > } ...
Dude, indent your code (with spaces, not TABs) in the future. This is very hard to read.
 Signature Lew
Andrew Thompson - 04 Aug 2007 02:44 GMT >> /**For AVI files, each frame must have a time stamp set.See the >> following message from the jmf - interest archives for details : [quoted text clipped - 5 lines] >Dude, indent your code (with spaces, not TABs) in the future. This is very >hard to read. 1) I'll start by agreeing with that, then go on to point out that it is mentioned in the SSCCE document to which I first linked.
2) Also, over 500 lines of code? That is *not* an SSCCE! (hint: what does the first 'S' stand for?) Without even looking closely at that mess, I can guess this problem could be expressed in under 200 lines of code, and for those experienced with making SSCCE's, maybe less than 50.
So, my advice would be to revisit that code, and progressively remove *every* line that can be removed, yet still display the basic problem.
3) Short lines only! Many long lines in that code were 'line-wrapped' and therefore were broken when I went to compile it. A couple of notes about breaking up lines..
System.out.println("A very, extremely, unnecessarily, long and obtuse series of words");
..can be broken into short lines like this..
System.out.println("A very, " + "extremely, unnecessarily, " + "long and obtuse series of " + "words");
Most other type of lines can be broken on any 'dot, comma or brace'. E.G.
System.out.println("Hi!");
..can actually be broken into separate lines like this..
System . out . println ( "Hi!");
(That is of course, a ridiculous extent to take it to - I am just making a point that there are lots of places where most code lines can be safely wrapped onto a new line).
4) Then, (and this is *not* covered in the SSCCE document but..) media projects are tricky to make SSCCE's for.
In particular, the problem *might* be with the source media, and even if not, we are unable to run it, lacking an appropriate animation file to start with.
In this case, perhaps you can use a little animation I made, as the 'test source'. It is here.. <http://www.javasaver.com/testjs/jmf/anim/lunarphases.mov> That is a mov of around 210Kb. I am not sure that a mov is suitable for this test, but if not, have a look at <http://www.javasaver.com/testjs/jmf/#media> for other possiblilities.
If you change the code to refer to that lunar phases mov (directly by URL), not only can anybody run it, but the clever ones can download the mov and use the local copy.
So - I hear that you are not confident with English, & the fine details of the SSCCE document may not have been clear to you, but if you do not understand anything I say, please ask, rather than dumping 500+ lines of unformatted, uncompilable code on us!
 Signature Andrew Thompson http://www.athompson.info/andrew/
Misterysword@hotmail.com - 04 Aug 2007 14:13 GMT > >> /**For AVI files, each frame must have a time stamp set.See the > >> following message from the jmf - interest archives for details : [quoted text clipped - 81 lines] > > Message posted viahttp://www.javakb.com Thank you for his advices. I do not want that you lose any more time with me, so that I only ask you one thing:
In JMF, how do you add a codec? I need to compress the information (with cinepak or mjpg format...) and I think that a codec is the only way.
Thank you for everything.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|