package mjpeg;
import java.io.*; //Random access file writer
import java.util.*; //Vector
import javax.imageio.ImageIO; //encodingJPEG
//import com.sun.image.codec.jpeg.*; //jpegCodec
import com.keypoint.*; //pngCodec
import java.awt.image.BufferedImage;
public class MjpegWriter{
long frameNo = 0;
Vector<Long> frames;
Vector<Integer> fsizes;
long movi;
long[] frameP =null; //Frame pointer
long[] position = null; //File position pointer
RandomAccessFile videoFile =null; //Video file to write to
int height;
int width;
long frameCount;
//Constructor
public MjpegWriter(String fileName,int width,int height) throws Exception{
this.width = width;
this.height = height;
frameP = new long[3];
position = new long[3];
frames = new Vector<Long>();
fsizes = new Vector<Integer>();
frameCount = 0;
videoFile = new RandomAccessFile(fileName,"rw");
}
public void writeHeader() throws Exception{
String text = "RIFF";
videoFile.write(text.getBytes("ISO-8859-1")); //Riff
videoFile.write(intToByteArray(0)); //File size in bytes-8
//AVI
text = "AVI ";
videoFile.write(text.getBytes("ISO-8859-1")); //AVI
text = "LIST";
videoFile.write(text.getBytes("ISO-8859-1")); //LIST
videoFile.write(intToByteArray(192)); //list size (header size-12)
text = "hdrl";
videoFile.write(text.getBytes("ISO-8859-1")); //main header
text = "avih";
videoFile.write(text.getBytes("ISO-8859-1")); //avi header
videoFile.write(intToByteArray(14*4)); //avih size in bytes
//AVI header data
videoFile.write(intToByteArray(40000)); //usec per frame
videoFile.write(intToByteArray(25*3*width*height)); //bytes per sec
videoFile.write(intToByteArray(0)); //reserved
videoFile.write(intToByteArray(2320)); //flags (none required for raw)
frameP[0] = videoFile.getFilePointer();
videoFile.write(intToByteArray(0)); //total frames (none required for raw)
videoFile.write(intToByteArray(0)); //initial frames (0 for non-interleaved)
videoFile.write(intToByteArray(1)); //No. of streams
videoFile.write(intToByteArray(width*height*3)); //Buffer size
videoFile.write(intToByteArray(width)); //Width
videoFile.write(intToByteArray(height)); //Height
videoFile.write(intToByteArray(0)); //Reserved[4] set to zero
videoFile.write(intToByteArray(0)); //Reserved[4] set to zero
videoFile.write(intToByteArray(0)); //Reserved[4] set to zero
videoFile.write(intToByteArray(0)); //Reserved[4] set to zero
//AVI header written
//Stream header
text = "LIST";
videoFile.write(text.getBytes("ISO-8859-1"));
videoFile.write(intToByteArray(116)); //list size in bytes
text = "strl"; //Stream list
videoFile.write(text.getBytes("ISO-8859-1")); //Stream list
text = "strh"; //Stream header
videoFile.write(text.getBytes("ISO-8859-1")); //videoFileStream header
videoFile.write(intToByteArray(56)); //videoFileStream header size in bytes
//Stream header data
text = "vids"; //Stream header
videoFile.write(text.getBytes("ISO-8859-1")); //videoFileStream header
text = "MJPG"; //Stream handler
videoFile.write(text.getBytes("ISO-8859-1")); //Stream handler
videoFile.write(intToByteArray(0)); //Flags
videoFile.write(intToByteArray(0)); //Priority none needed for raw..
videoFile.write(intToByteArray(0)); //Language needed for raw..
//InitialFrames not used -> no audio...
videoFile.write(intToByteArray(1)); //dwScale
videoFile.write(intToByteArray(25)); //dwRate
videoFile.write(intToByteArray(0)); //dwStart
frameP[1] = videoFile.getFilePointer();
videoFile.write(intToByteArray(0)); //dwLength
videoFile.write(intToByteArray(0)); //dwBuffer
videoFile.write(intToByteArray(-1)); //dwQuality
videoFile.write(intToByteArray(0)); //dwSampleSize
videoFile.write(intToByteArray(0)); //rcFrame
videoFile.write(intToByteArray(0)); //rcFrame
//Stream header data written
text = "strf"; //Stream format
videoFile.write(text.getBytes("ISO-8859-1")); //videoFileStream format
videoFile.write(intToByteArray(40)); //videoFileStream fomat size in bytes
videoFile.write(intToByteArray(40)); //Format header length = 40
//format data
videoFile.write(intToByteArray(width)); //width
videoFile.write(intToByteArray(height)); //height
videoFile.write(shortToByteArray((short) 1)); //planes = must be 1
videoFile.write(shortToByteArray((short) 0)); //bitCount (0 =jpeg tai png)
text = "MJPG"; //Compression
videoFile.write(text.getBytes("ISO-8859-1")); //compression
videoFile.write(intToByteArray(width*height*3)); //image size in bytes
videoFile.write(intToByteArray(0)); //xpixels per meter
videoFile.write(intToByteArray(0)); //ypixels per meter
videoFile.write(intToByteArray(0)); //ClrUsed
videoFile.write(intToByteArray(0)); //ClrImportant
//format data written...
//DATA chunk!!
text = "LIST"; //MOVI chunk
videoFile.write(text.getBytes("ISO-8859-1")); //Movi chunk
frameP[2] = videoFile.getFilePointer(); //Insert pointer for decoded data
videoFile.write(intToByteArray(0)); //Decoded Data size!!
movi = videoFile.getFilePointer();
text = "movi"; //MOVI list name
videoFile.write(text.getBytes("ISO-8859-1")); //Movi list name
}
//Functions
public void write_frame(BufferedImage image) throws Exception{
String text = "00dc"; //MOVI chunk
position[0] =videoFile.getFilePointer();
videoFile.write(text.getBytes("ISO-8859-1")); //Movi chunk
videoFile.write(intToByteArray(width*height*3));//Movi chunk size place holder....
position[1] =videoFile.getFilePointer();
write_JPEG(image);
if ((videoFile.getFilePointer()-position[0])%4 > 0){ //Zero padding
byte[] padding = new byte[(int) ((videoFile.getFilePointer()-position[0])%4)];
videoFile.write(padding);
}
position[2] =videoFile.getFilePointer();
videoFile.seek(position[0]+4);
videoFile.write(intToByteArray((int) (position[2]-position[1]))); //Movi chunk size
videoFile.seek(position[2]);
frames.add(position[0]-movi);
fsizes.add((int) (position[2]-position[1]));
++frameCount;
}
public void finalize_mjpeg() throws Exception{
long currentPosition = videoFile.getFilePointer();
long idxPos = currentPosition;
videoFile.seek(movi-4);
videoFile.write(intToByteArray((int) (currentPosition-movi))); //Movi chunk size
videoFile.seek(currentPosition);
//Write index
String text = "idx1"; //idx1 chunk
videoFile.write(text.getBytes("ISO-8859-1")); //idx1 chunk
videoFile.write(intToByteArray((int) (frameCount*4*4))); //index size
for (int k = 0;k<frameCount;k++){
text = "00dc"; //idx1 chunk
videoFile.write(text.getBytes("ISO-8859-1")); //idx1 chunk
videoFile.write(intToByteArray((int) 16)); //Key frame flag!!
videoFile.write(intToByteArray(frames.get(k).intValue())); //offset from BEGINNING of (thus the +4) movi!!
videoFile.write(intToByteArray((int) (fsizes.get(k)))); //chunk size
}
currentPosition = videoFile.getFilePointer();
videoFile.seek(4);
videoFile.write(intToByteArray((int) (currentPosition-8))); //File size
videoFile.seek(frameP[0]);
videoFile.write(intToByteArray((int) frameCount));
videoFile.seek(frameP[1]);
videoFile.write(intToByteArray((int) frameCount)); //frames2
videoFile.seek(frameP[2]);
videoFile.write(intToByteArray((int) (idxPos-movi))); //encoded image data amount
//Index written...
//Close videoFile
videoFile.close();
}
void write_JPEG(BufferedImage data) throws Exception
{
ByteArrayOutputStream outData = new ByteArrayOutputStream();
ImageIO.write(data, "jpeg", outData);
/*
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(outData);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(data);
param.setQuality((float) 0.9,false);
encoder.setJPEGEncodeParam(param);
encoder.encode(data);
*/
//Get the byte array next from the outData
byte[] compressedData = outData.toByteArray();
videoFile.write(compressedData);
outData.close();
}
byte[] intToByteArray(int value){
// return new byte[] {(byte) (value >> 24 & 0xFF),(byte) (value >> 16 & 0xFF),(byte) (value >> 8 & 0xFF),(byte) (value & 0xFF)};
return new byte[] {(byte) (value & 0xFF),(byte) ((value >> 8) & 0xFF),(byte) ((value >> 16) & 0xFF),(byte) ((value >> 24) & 0xFF)};
}
byte[] shortToByteArray(short value){
// return new byte[] {(byte) (value >> 8 & 0xFF),(byte) (value & 0xFF)};
return new byte[] {(byte) (value & 0xFF),(byte) ((value>>8) & 0xFF)};
}
byte[] intArrayToByteArray(int[] arrayIn){
byte[] arrayOut = new byte[arrayIn.length*4];
byte[] temp;
for (int i= 0; i<arrayIn.length; ++i){
temp = intToByteArray(arrayIn[i]);
for (int j = 0; j< 4; ++j){
arrayOut[4*i+j] = temp[j];
}
}
return arrayOut;
}
public static void main(String[] args)
{
/*
const char *filename,*filein;
unsigned short riveja, kolumneja,videon_korkeus,videon_leveys;
//MJPEG valmistelu
mjpegWriter videoksi(argv[2],videon_leveys,videon_korkeus,3, 99);
//TALLENNETAAN VIDEOKSI...
//printf("Kuvaa tayttamaan\n");
for (int jjj = 0;jjj<videon_korkeus;++jjj){
for (int iii = 0;iii<videon_leveys;++iii){
kuva[iii*3+jjj*videon_leveys*3]=vali[iii+jjj*kolumneja]; //R
kuva[iii*3+1+jjj*videon_leveys*3]=vali[iii+jjj*kolumneja+riveja*kolumneja]; //G
kuva[iii*3+2+jjj*videon_leveys*3]=vali[iii+jjj*kolumneja+2*riveja*kolumneja];; //B
}
}
//Kuva valmis
videoksi.write_frame(kuva); //add frame
printf("Kuva %u\r",kuvia_naytetty);
//Done
videoksi.finalize_mjpeg(kuvia_naytetty);
printf("Valmista tuli\n");
*/
}
}