package org.jcodec.api.android;
import java.io.File;
import java.io.IOException;
import org.jcodec.api.FrameGrab8Bit;
import org.jcodec.api.JCodecException;
import org.jcodec.api.PictureWithMetadata8Bit;
import org.jcodec.api.UnsupportedFormatException;
import org.jcodec.api.specific.ContainerAdaptor;
import org.jcodec.common.AndroidUtil;
import org.jcodec.common.io.FileChannelWrapper;
import org.jcodec.common.io.NIOUtils;
import org.jcodec.common.io.SeekableByteChannel;
import org.jcodec.common.SeekableDemuxerTrack;
import org.jcodec.common.model.Picture8Bit;
import android.graphics.Bitmap;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* Extracts frames from a movie into uncompressed images suitable for
* processing.
*
* Supports going to random points inside of a movie ( seeking ) by frame number
* of by second.
*
* NOTE: Supports only AVC ( H.264 ) in MP4 ( ISO BMF, QuickTime ) at this
* point.
*
* NOTE: Android specific routines
*
* @author The JCodec project
*
*/
public class AndroidFrameGrab8Bit extends FrameGrab8Bit {
public static AndroidFrameGrab8Bit createAndroidFrameGrab8Bit(SeekableByteChannel in)
throws IOException, JCodecException {
FrameGrab8Bit frameGrab = createFrameGrab8Bit(in);
return new AndroidFrameGrab8Bit(frameGrab.getVideoTrack(), frameGrab.getDecoder());
}
public AndroidFrameGrab8Bit(SeekableDemuxerTrack videoTrack, ContainerAdaptor decoder) {
super(videoTrack, decoder);
}
/**
* Get frame at a specified second as AWT image
*
* @param file
* @param second
* @return A decoded frame from a given point in video.
* @throws IOException
* @throws JCodecException
*/
public static Bitmap getFrame(File file, double second) throws IOException, JCodecException {
FileChannelWrapper ch = null;
try {
ch = NIOUtils.readableChannel(file);
return ((AndroidFrameGrab8Bit) createAndroidFrameGrab8Bit(ch).seekToSecondPrecise(second)).getFrame();
} finally {
NIOUtils.closeQuietly(ch);
}
}
/**
* Get frame at a specified second as AWT image
*
* @param file
* @param second
* @return A decoded frame from a given point in video.
* @throws UnsupportedFormatException
* @throws IOException
*/
public static Bitmap getFrame(SeekableByteChannel file, double second) throws JCodecException, IOException {
return ((AndroidFrameGrab8Bit) createAndroidFrameGrab8Bit(file).seekToSecondPrecise(second)).getFrame();
}
/**
* Get frame at current position in AWT image
*
* @return A decoded frame with metadata.
* @throws IOException
*/
public BitmapWithMetadata getFrameWithMetadata() throws IOException {
PictureWithMetadata8Bit pictureWithMeta = getNativeFrameWithMetadata();
if (pictureWithMeta == null)
return null;
Bitmap bitmap = AndroidUtil.toBitmap8Bit(pictureWithMeta.getPicture());
return new BitmapWithMetadata(bitmap, pictureWithMeta.getTimestamp(), pictureWithMeta.getDuration());
}
/**
* Get frame at current position in AWT image
*
* @return A decoded frame.
* @throws IOException
*/
public Bitmap getFrame() throws IOException {
return AndroidUtil.toBitmap8Bit(getNativeFrame());
}
/**
* Get frame at current position in AWT image
*
* @throws IOException
*/
public void getFrame(Bitmap bmp) throws IOException {
Picture8Bit picture = getNativeFrame();
AndroidUtil.toBitmap8Bit(picture, bmp);
}
/**
* Get frame at current position in AWT image
*
* @return A decoded picture with metadata. A bitmap provided is used.
*
* @throws IOException
*/
public BitmapWithMetadata getFrameWithMetadata(Bitmap bmp) throws IOException {
PictureWithMetadata8Bit pictureWithMetadata = getNativeFrameWithMetadata();
if (pictureWithMetadata == null)
return null;
AndroidUtil.toBitmap8Bit(pictureWithMetadata.getPicture(), bmp);
return new BitmapWithMetadata(bmp, pictureWithMetadata.getTimestamp(), pictureWithMetadata.getDuration());
}
/**
* Get frame at a specified frame number as AWT image
*
* @param file
* @param second
* @return
* @throws IOException
* @throws JCodecException
*/
public static Bitmap getFrame(File file, int frameNumber) throws IOException, JCodecException {
FileChannelWrapper ch = null;
try {
ch = NIOUtils.readableChannel(file);
return ((AndroidFrameGrab8Bit) createAndroidFrameGrab8Bit(ch).seekToFramePrecise(frameNumber)).getFrame();
} finally {
NIOUtils.closeQuietly(ch);
}
}
/**
* Get frame at a specified frame number as AWT image
*
* @param file
* @param second
* @return
* @throws IOException
* @throws JCodecException
*/
public static Bitmap getFrame(SeekableByteChannel file, int frameNumber) throws JCodecException, IOException {
return ((AndroidFrameGrab8Bit) createAndroidFrameGrab8Bit(file).seekToFramePrecise(frameNumber)).getFrame();
}
/**
* Get a specified frame by number from an already open demuxer track
*
* @param vt
* @param decoder
* @param frameNumber
* @return
* @throws IOException
* @throws JCodecException
*/
public static Bitmap getFrame(SeekableDemuxerTrack vt, ContainerAdaptor decoder, int frameNumber)
throws IOException, JCodecException {
return ((AndroidFrameGrab8Bit) new AndroidFrameGrab8Bit(vt, decoder).seekToFramePrecise(frameNumber)).getFrame();
}
/**
* Get a specified frame by second from an already open demuxer track
*
* @param vt
* @param decoder
* @param frameNumber
* @return
* @throws IOException
* @throws JCodecException
*/
public static Bitmap getFrame(SeekableDemuxerTrack vt, ContainerAdaptor decoder, double second)
throws IOException, JCodecException {
return ((AndroidFrameGrab8Bit) new AndroidFrameGrab8Bit(vt, decoder).seekToSecondPrecise(second)).getFrame();
}
/**
* Get a specified frame by number from an already open demuxer track (
* sloppy mode, i.e. nearest keyframe )
*
* @param vt
* @param decoder
* @param frameNumber
* @return
* @throws IOException
* @throws JCodecException
*/
public static Bitmap getFrameSloppy(SeekableDemuxerTrack vt, ContainerAdaptor decoder, int frameNumber)
throws IOException, JCodecException {
return ((AndroidFrameGrab8Bit) new AndroidFrameGrab8Bit(vt, decoder).seekToFrameSloppy(frameNumber)).getFrame();
}
/**
* Get a specified frame by second from an already open demuxer track (
* sloppy mode, i.e. nearest keyframe )
*
* @param vt
* @param decoder
* @param frameNumber
* @return
* @throws IOException
* @throws JCodecException
*/
public static Bitmap getFrameSloppy(SeekableDemuxerTrack vt, ContainerAdaptor decoder, double second)
throws IOException, JCodecException {
return ((AndroidFrameGrab8Bit) new AndroidFrameGrab8Bit(vt, decoder).seekToSecondSloppy(second)).getFrame();
}
}