
org.monte.media.seq.SEQReader Maven / Gradle / Ivy
/*
* @(#)SEQReader.java 1.0 2011-02-19
*
* Copyright (c) 2011 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.media.seq;
import org.monte.media.image.BitmapImage;
import java.awt.image.IndexColorModel;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import javax.imageio.stream.FileImageInputStream;
/**
* {@code SEQReader}.
*
* @author Werner Randelshofer
* @version 1.0 2011-02-19 Created.
*/
public class SEQReader {
private SEQMovieTrack track;
// ---- BEGIN Decoder variables ----
/**
* Index of the frame which has been delta
* decoded in its even or odd bitmap buffer.
*/
private int fetchedEven = -1, fetchedOdd = -1;
/** Two bitmaps are needed for double buffering. */
private BitmapImage bitmapEven, bitmapOdd;
// ---- END Decoder variables ----
public SEQReader(File file) throws IOException {
this(file, true);
}
public SEQReader(File file, boolean variableFramerate) throws IOException {
FileImageInputStream in = null;
try {
in = new FileImageInputStream(file);
SEQDecoder decoder = new SEQDecoder(in);
track = new SEQMovieTrack();
decoder.produce(track, false);
if (variableFramerate) {
int removed = removeDuplicateFrames(track);
// System.out.println(removed + " frames removed");
}
} finally {
if (in != null) {
in.close();
}
}
}
public void close() throws IOException {
// nothing to do
}
public int getFrameCount() {
return track.getFrameCount();
}
public int getTimeBase() {
return track.getJiffies();
}
public BitmapImage createCompatibleBitmap() {
return new BitmapImage(
track.getWidth(),
track.getHeight(),
track.getNbPlanes() + (track.getMasking() == SEQMovieTrack.MSK_HAS_MASK ? 1 : 0),
track.getFrame(0).getColorModel());
}
/** Reads a frame into the supplied image. */
public void readFrame(int index, BitmapImage image) {
BitmapImage fetched = fetchFrame(index);
System.arraycopy(fetched.getBitmap(), 0, image.getBitmap(), 0, fetched.getBitmap().length);
image.setPlanarColorModel(track.getFrame(index).getColorModel());
}
public int getJiffies() {
return track.getJiffies();
}
/** Reads the duration of the specified frame. */
public int getDuration(int index) {
return (int) track.getFrame(index).getRelTime();
}
private BitmapImage fetchFrame(int index) {
if (bitmapOdd == null || bitmapEven == null) {
bitmapOdd = createCompatibleBitmap();
bitmapEven = createCompatibleBitmap();
}
SEQFrame frame = null;
int fetched;
int interleave = track.getInterleave();
BitmapImage bitmap;
if (interleave == 1 || (index & 1) == 0) {
// even?
if (fetchedEven == index) {
return bitmapEven;
}
fetched = fetchedEven;
bitmap = bitmapEven;
fetchedEven = index;
if (fetched == index + interleave && track.getFrame(fetched).isBidirectional()) {
frame = (SEQFrame) track.getFrame(fetched);
frame.decode(bitmap, track);
return bitmap;
} else {
if (fetched > index) {
frame = (SEQFrame) track.getFrame(0);
frame.decode(bitmap, track);
fetched = 0;
}
}
} else {
// odd?
if (fetchedOdd == index) {
return bitmapOdd;
}
fetched = fetchedOdd;
bitmap = bitmapOdd;
fetchedOdd = index;
if (fetched == index + interleave && track.getFrame(fetched).isBidirectional()) {
frame = (SEQFrame) track.getFrame(fetched);
frame.decode(bitmap, track);
return bitmap;
} else {
if (fetched > index) {
frame = (SEQFrame) track.getFrame(0);
frame.decode(bitmap, track);
frame = (SEQFrame) track.getFrame(1);
frame.decode(bitmap, track);
fetched = 1;
}
}
}
for (int i = fetched + interleave; i <= index; i += interleave) {
frame = (SEQFrame) track.getFrame(i);
frame.decode(bitmap, track);
}
return bitmap;
}
private int removeDuplicateFrames(SEQMovieTrack track) {
int width = track.getWidth();
int height = track.getHeight();
SEQFrame f0 = track.getFrame(0);
BitmapImage bmp = new BitmapImage(width, height, track.getNbPlanes(), f0.getColorModel());
bmp.setPreferredChunkyColorModel(f0.getColorModel());
byte[] previousBmp = new byte[bmp.getBitmap().length];
int[] previousColors = new int[16];
int[] colors = new int[16];
int removed = 0;
SEQFrame previousF = f0;
for (int i = 1, n = track.getFrameCount(); i < n; i++) {
SEQFrame f = track.getFrame(i);
f.decode(bmp, track);
((IndexColorModel) f.getColorModel()).getRGBs(colors);
if (Arrays.equals(bmp.getBitmap(), previousBmp)
&& Arrays.equals(colors, previousColors)) {
previousF.setRelTime(previousF.getRelTime() + f.getRelTime());
track.removeFrame(i);
--n;
--i;
++removed;
continue;
} else {
System.arraycopy(colors, 0, previousColors, 0, 16);
System.arraycopy(bmp.getBitmap(), 0, previousBmp, 0, previousBmp.length);
}
previousF = f;
}
return removed;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy