/*
* @(#)QuickTimeReader.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.media.quicktime;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.stream.ImageInputStream;
import org.monte.media.Buffer;
import org.monte.media.Format;
import org.monte.media.MovieReader;
import org.monte.media.math.Rational;
import static org.monte.media.FormatKeys.*;
import static org.monte.media.AudioFormatKeys.*;
import static org.monte.media.VideoFormatKeys.*;
import org.monte.media.Codec;
import org.monte.media.Registry;
import static org.monte.media.BufferFlag.*;
/**
* {@code QuickTimeReader}.
*
* @author Werner Randelshofer
* @version $Id: QuickTimeReader.java 305 2013-01-04 16:07:34Z werner $
*/
public class QuickTimeReader extends QuickTimeInputStream implements MovieReader {
public final static Format QUICKTIME = new Format(MediaTypeKey,MediaType.FILE,MimeTypeKey,MIME_QUICKTIME);
/**
* Creates a new instance.
*
* @param file the input file
*/
public QuickTimeReader(File file) throws IOException {
super(file);
}
/**
* Creates a new instance.
*
* @param in the input stream.
*/
public QuickTimeReader(ImageInputStream in) throws IOException {
super(in);
}
@Override
public long timeToSample(int track, Rational seconds) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Rational sampleToTime(int track, long sample) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Format getFileFormat() throws IOException {
return QUICKTIME;
}
@Override
public Format getFormat(int track) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public long getChunkCount(int track) throws IOException {
ensureRealized();
return tracks.get(track).sampleCount;
}
/**
* Reads an image.
*
* @param track The track number
* @param img An image that can be reused if it fits the media format of the
* track. Pass null to create a new image on each read.
* @return An image or null if the end of the media has been reached.
* @throws IOException
*/
public BufferedImage read(int track, BufferedImage img) throws IOException {
AbstractQuickTimeStream.Track tr = tracks.get(track);
if (tr.inputBuffer == null) {
tr.inputBuffer = new Buffer();
}
if (tr.codec == null) {
createCodec(tr);
}
Buffer buf = new Buffer();
buf.data = img;
do {
read(track, tr.inputBuffer);
// FIXME - We assume a one-step codec here!
tr.codec.process(tr.inputBuffer, buf);
} while (buf.isFlag(DISCARD) && !buf.isFlag(END_OF_MEDIA));
if (tr.inputBuffer.isFlag(END_OF_MEDIA)) {
return null;
}
return (BufferedImage) buf.data;
}
@Override
public void read(int track, Buffer buffer) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public int nextTrack() throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void setMovieReadTime(Rational newValue) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Rational getReadTime(int track) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Rational getDuration() throws IOException {
return new Rational(getMovieDuration(), getMovieTimeScale());
}
@Override
public Rational getDuration(int track) throws IOException {
ensureRealized();
Track tr = tracks.get(track);
// FIXME - This method must take the edit list of the track into account
Rational trackDuration = new Rational(tr.mediaDuration,tr.mediaTimeScale);
return trackDuration;
}
@Override
public int findTrack(int fromTrack, Format format) throws IOException {
for (int i=fromTrack,n=getTrackCount();i<n;i++) {
if (getFormat(i).matches(format)) {
return i;
}
}
return -1;
}
private void createCodec(AbstractQuickTimeStream.Track tr) {
Format fmt = tr.format;
Codec codec = createCodec(fmt);
String enc = fmt.get(EncodingKey);
if (codec == null) {
throw new UnsupportedOperationException("Track " + tr + " no codec found for format " + fmt);
} else {
if (fmt.get(MediaTypeKey) == MediaType.VIDEO) {
if (null == codec.setInputFormat(fmt)) {
throw new UnsupportedOperationException("Track " + tr + " codec does not support input format " + fmt + ". codec=" + codec);
}
Format outFormat = fmt.prepend(MediaTypeKey, MediaType.VIDEO,//
MimeTypeKey, MIME_JAVA,
EncodingKey, ENCODING_BUFFERED_IMAGE, DataClassKey, BufferedImage.class);
if (null == codec.setOutputFormat(outFormat)) {
throw new UnsupportedOperationException("Track " + tr + " codec does not support output format " + outFormat + ". codec=" + codec);
}
}
}
tr.codec = codec;
}
private Codec createCodec(Format fmt) {
Codec[] codecs = Registry.getInstance().getDecoders(fmt.prepend(MimeTypeKey, MIME_AVI));
return codecs.length == 0 ? null : codecs[0];
}
}