package info.guardianproject.iocipher.camera.encoders;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.jcodec.common.AudioFormat;
import org.jcodec.common.NIOUtils;
import org.jcodec.common.SeekableByteChannel;
import org.jcodec.common.model.Rational;
import org.jcodec.common.model.Size;
import org.jcodec.common.model.Unit;
import org.jcodec.containers.mp4.Brand;
import org.jcodec.containers.mp4.MP4Packet;
import org.jcodec.containers.mp4.TrackType;
import org.jcodec.containers.mp4.WebOptimizedMP4Muxer;
import org.jcodec.containers.mp4.muxer.FramesMP4MuxerTrack;
import org.jcodec.containers.mp4.muxer.MP4Muxer;
import org.jcodec.containers.mp4.muxer.PCMMP4MuxerTrack;
/**
*
* This file contains code from the IOCipher Camera Library "CipherCam".
*
* For more information about IOCipher, see https://guardianproject.info/code/iocipher
* and this sample library: https://github.com/n8fr8/IOCipherCameraExample
*
* IOCipher Camera Sample is distributed under this license (aka the 3-clause BSD license)
*
* Some of this class was originally part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* @author n8fr8, The JCodec project
*
*/
public class ImageToMJPEGMOVMuxer {
private SeekableByteChannel ch;
private FramesMP4MuxerTrack videoTrack;
private PCMMP4MuxerTrack audioTrack;
private int frameNo = 0;
private WebOptimizedMP4Muxer muxer;
private Size size;
private String imageType = "jpeg "; //or "png ";
private AudioFormat af = null;
private int framesPerSecond = -1;
private final static String ENCODER_NAME = "JCODEC";
public ImageToMJPEGMOVMuxer(SeekableByteChannel ch, AudioFormat af, int framesPerSecond) throws IOException {
this.ch = ch;
this.af = af;
this.framesPerSecond = framesPerSecond;
// Muxer that will store the encoded frames
muxer = new WebOptimizedMP4Muxer(ch, Brand.MP4, 4096*4);
// Add video track to muxer
videoTrack = muxer.addTrack(TrackType.VIDEO, framesPerSecond);
muxer.addTimecodeTrack(framesPerSecond);
videoTrack.setTgtChunkDuration(new Rational(3, 1), Unit.SEC);
if (af != null)
audioTrack = muxer.addPCMAudioTrack(af);
}
public void addFrame(int width, int height, ByteBuffer buff, long timeScaleFPS, long duration) throws IOException {
if (size == null) {
size = new Size(width,height);
videoTrack.addSampleEntry(MP4Muxer.videoSampleEntry(imageType, size, ENCODER_NAME));
if (af != null)
audioTrack.addSampleEntry(MP4Muxer.audioSampleEntry(af));
}
// Add packet to video track
videoTrack.addFrame(new MP4Packet(buff, frameNo, timeScaleFPS, duration, frameNo, true, null, frameNo, 0));
frameNo++;
}
public void addAudio (ByteBuffer buffer) throws IOException
{
audioTrack.addSamples(buffer);
}
public void finish() throws IOException {
videoTrack.addSampleEntry(MP4Muxer.videoSampleEntry(imageType, size, ENCODER_NAME));
// Write MP4 header and finalize recording
if (af != null)
audioTrack.addSampleEntry(MP4Muxer.audioSampleEntry(af));
muxer.writeHeader();
NIOUtils.closeQuietly(ch);
}
}