/**
* @(#)Main.java
*
* Copyright (c) 2012 Werner Randelshofer, Goldau, Switzerland.
* All rights reserved.
*
* You may not use, copy or modify this file, except in compliance with the
* license agreement you entered into with Werner Randelshofer.
* For details see accompanying license terms.
*/
package org.monte.iodemo;
import java.util.ArrayList;
import org.monte.media.MovieReader;
import org.monte.media.MovieWriter;
import java.util.HashSet;
import org.monte.media.Codec;
import org.monte.media.Buffer;
import org.monte.media.math.Rational;
import org.monte.media.Format;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.IndexColorModel;
import java.io.*;
import java.util.Random;
import org.monte.media.BufferFlag;
import org.monte.media.Registry;
import org.monte.media.image.Images;
import static org.monte.media.VideoFormatKeys.*;
/**
* Demonstrates the use of {@link MovieReader} and {@link MovieWriter}.
* <p>
* This class creates a video file named montemedia-...codec....avi for
* each installed Codec, and writes simple animation frames into the file.
* Then, it attempts to read the frames back from the video file.
*
* @author Werner Randelshofer
* @version $Id: ReadWriteDemoMain.java 298 2013-01-03 07:39:43Z werner $
*/
public class ReadWriteDemoMain {
/**
* Main function.
*
* @param args the command line arguments (ignored)
*/
public static void main(String[] args) {
try {
HashSet<String> usedFilenames = new HashSet<String>();
// Test all available AVI video formats
for (Codec c : Registry.getInstance().getEncoders(new Format(MimeTypeKey, MIME_AVI, MediaTypeKey, MediaType.VIDEO))) {
for (Format f : c.getOutputFormats(new Format(DataClassKey, BufferedImage.class))) {
if (f.get(MimeTypeKey) == MIME_AVI) {
String filename = "montemedia-" + f.get(EncodingKey).trim() + f.get(DepthKey) + ".avi";
String filename2 = "montemedia-" + f.get(EncodingKey).trim() + f.get(DepthKey) + "(2).avi";
if (usedFilenames.add(filename)) {
test(new File(filename), new File(filename2), f);
}
}
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
private static void test(File file,File file2, Format format) throws IOException {
testWriting(file, format);
try {
testReading(file);
BufferedImage[] frames=readMovie(file);
writeMovie(file2,frames);
} catch (UnsupportedOperationException e) {
System.out.println(e);
}
}
private static void testWriting(File file, Format format) throws IOException {
System.out.println("Writing " + file);
// Make the format more specific
format = format.prepend(MediaTypeKey, MediaType.VIDEO, //
FrameRateKey, new Rational(30, 1),//
WidthKey, 320, //
HeightKey, 160);
// Create a buffered image for this format
BufferedImage img = createImage(format);
Graphics2D g = img.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
MovieWriter out = null;
try {
// Create the writer
out = Registry.getInstance().getWriter(format, file);
// Add a track to the writer
out.addTrack(format);
// initialize the animation
Random rnd = new Random(0); // use seed 0 to get reproducable output
g.setBackground(Color.WHITE);
g.clearRect(0, 0, img.getWidth(), img.getHeight());
Buffer buf = new Buffer();
buf.format = new Format(DataClassKey, BufferedImage.class);
buf.sampleDuration = format.get(FrameRateKey).inverse();
buf.data = img;
for (int i = 0; i < 100; i++) {
// Create an animation frame
g.setColor(new Color(rnd.nextInt()));
g.fillOval(rnd.nextInt(img.getWidth() - 30), rnd.nextInt(img.getHeight() - 30), 30, 30);
// write it to the writer
out.write(0, buf);
}
} finally {
// Close the writer
if (out != null) {
out.close();
}
// Dispose the graphics object
g.dispose();
}
}
private static void writeMovie(File file, BufferedImage[] frames) throws IOException {
MovieWriter out = Registry.getInstance().getWriter(file);
Format format = new Format(MediaTypeKey, MediaType.VIDEO, //
EncodingKey, ENCODING_AVI_MJPG,
FrameRateKey, new Rational(30, 1),//
WidthKey, frames[0].getWidth(), //
HeightKey, frames[0].getHeight(),//
DepthKey, 24
);
int track = out.addTrack(format);
try {
Buffer buf = new Buffer();
buf.format = new Format(DataClassKey, BufferedImage.class);
buf.sampleDuration = format.get(FrameRateKey).inverse();
for (int i = 0; i < frames.length; i++) {
buf.data = frames[i];
out.write(track, buf);
}
} finally {
out.close();
}
}
private static BufferedImage[] readMovie(File file) throws IOException {
ArrayList<BufferedImage> frames=new ArrayList<BufferedImage> ();
MovieReader in = Registry.getInstance().getReader(file);
Format format = new Format(DataClassKey, BufferedImage.class);
int track=in.findTrack(0,new Format(MediaTypeKey,MediaType.VIDEO));
Codec codec=Registry.getInstance().getCodec(in.getFormat(track), format);
try {
Buffer inbuf = new Buffer();
Buffer codecbuf = new Buffer();
do {
in.read(track, inbuf);
codec.process(inbuf, codecbuf);
if (!codecbuf.isFlag(BufferFlag.DISCARD)) {
frames.add(Images.cloneImage((BufferedImage)codecbuf.data));
}
} while (!inbuf.isFlag(BufferFlag.END_OF_MEDIA));
} finally {
in.close();
}
return frames.toArray(new BufferedImage[frames.size()]);
}
private static void testReading(File file) throws IOException {
System.out.println("Reading " + file);
MovieReader in = null;
try {
// Create the reader
in = Registry.getInstance().getReader(file);
// Look for the first video track
int track = 0;
while (track < in.getTrackCount()
&& in.getFormat(track).get(MediaTypeKey) != MediaType.VIDEO) {
track++;
}
// Read images from the track
Buffer inputBuffer = new Buffer();
Buffer codecBuffer = new Buffer();
Format imageFormat = new Format(DataClassKey, BufferedImage.class);
Codec codec = null;
BufferedImage img = null;
do {
in.read(track, inputBuffer);
Buffer imageBuffer = null;
if (inputBuffer.format.matches(imageFormat)) {
imageBuffer = inputBuffer;
} else {
if (codec == null) {
codec = Registry.getInstance().getCodec(inputBuffer.format, imageFormat);
}
if (codec == null) {
throw new UnsupportedOperationException("No Codec for " + inputBuffer.format);
}
codec.process(inputBuffer, codecBuffer);
imageBuffer = codecBuffer;
}
//...to do: do something with the image...
} while (img != null);
} finally {
// Close the rader
if (in != null) {
in.close();
}
}
}
/** Creates a buffered image of the specified depth with a random color palette.*/
private static BufferedImage createImage(Format format) {
int depth = format.get(DepthKey);
int width = format.get(WidthKey);
int height = format.get(HeightKey);
Random rnd = new Random(0); // use seed 0 to get reproducable output
BufferedImage img;
switch (depth) {
case 24:
default: {
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
break;
}
case 8: {
byte[] red = new byte[256];
byte[] green = new byte[256];
byte[] blue = new byte[256];
for (int i = 0; i < 255; i++) {
red[i] = (byte) rnd.nextInt(256);
green[i] = (byte) rnd.nextInt(256);
blue[i] = (byte) rnd.nextInt(256);
}
rnd.setSeed(0); // set back to 0 for reproducable output
IndexColorModel palette = new IndexColorModel(8, 256, red, green, blue);
img = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_INDEXED, palette);
break;
}
case 4: {
byte[] red = new byte[16];
byte[] green = new byte[16];
byte[] blue = new byte[16];
for (int i = 0; i < 15; i++) {
red[i] = (byte) rnd.nextInt(16);
green[i] = (byte) rnd.nextInt(16);
blue[i] = (byte) rnd.nextInt(16);
}
rnd.setSeed(0); // set back to 0 for reproducable output
IndexColorModel palette = new IndexColorModel(4, 16, red, green, blue);
img = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_INDEXED, palette);
break;
}
}
return img;
}
}