/**
*
*/
package mp4.util.atom;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Arrays;
/**
* The media data atom. This atom holds the video frames and sound tracks.
*/
public class MdatAtom extends LeafAtom {
// the input stream contains the data. we use the stream instead of a data file
// because the amount of data is so large.
private static final int BUFFER_SIZE = 1024 * 1024;
private DataInputStream in;
private boolean hasMark = false;
byte[] input = new byte[BUFFER_SIZE];
/**
* Construct an empty mdat atom
*/
public MdatAtom() {
super(new byte[]{'m', 'd', 'a', 't'});
}
/**
* Copy constructor for the mdat atom. Performs a deep copy
* @param old the version to copy
*/
public MdatAtom(MdatAtom old) {
super(old);
}
/**
* Set the data input stream for the mdata atom. The input stream points
* at the start of the video and sound data.
* @param in the input stream.
*/
public void setInputStream(DataInputStream in) {
this.in = in;
if (in.markSupported()) {
in.mark(Integer.MAX_VALUE);
hasMark = true;
}
}
/**
* Cut the mdat atom by skipping the specified number of bytes. This
* action does not create a new mdat atom. Instead, it alters the existing
* atom to skip over the appropriate data.
* @param skip the number of bytes to skip
* @return an altered mdat atom that has skipped over the approriate data.
*/
public MdatAtom cut(long skip) {
try {
if (hasMark) {
in.reset();
}
in.skip(skip);
if (in.markSupported()) {
in.mark(Integer.MAX_VALUE);
}
if (dataSize() > 0) {
long newSize = dataSize() - skip;
setSize(ATOM_HEADER_SIZE + newSize);
}
} catch (IOException e) {
throw new AtomError("Unable to cut the mdat atom");
}
return this;
}
/**
* TODO
MdatAtom.writeData(DataOutput out) reads too much data (fills the whole
buffer), and writes them all (even data past the numBytesToRead limit). use
something like this instead:
out.write(input, 0, readToEof?read:(int)Math.min(read, numBytesToRead));
*
*
* Write the video and sound data to the specified output
* @param out the specified output
* @throws IOException if there is a problem writing the data
*/
@Override
public void writeData(DataOutput out) throws IOException {
writeHeader(out);
long numBytesToRead = dataSize();
// read data in using 1 MB chunks
boolean readToEof = (numBytesToRead == 0);
while (readToEof || numBytesToRead > 0) {
int read = in.read(input);
if (read < 1) {
break;
}
if (read > numBytesToRead) {
out.write(input, 0, (int) numBytesToRead);
} else {
out.write(input, 0, read);
}
numBytesToRead -= read;
}
}
public void writeChunk(DataOutput out, long offset, long size) throws IOException {
if (!hasMark) {
in.mark(Integer.MAX_VALUE);
hasMark = true;
}
in.reset();
in.mark(Integer.MAX_VALUE);
in.skip(offset);
while (size > 0) {
int read = in.read(input, 0, (int) Math.min(size, input.length));
out.write(input, 0, read);
size -= read;
}
}
@Override
public void accept(AtomVisitor v) throws AtomException {
v.visit(this);
}
@Override
public void writeHeader(DataOutput out) throws IOException {
byte[] sizeData = new byte[ATOM_WORD];
//unsignedIntToByteArray(sizeData, 0, size);
// size 0 means to-the-end-of-file
Arrays.fill(sizeData, (byte) 0);
out.write(sizeData);
out.write(type);
}
public void writeHeader(DataOutput out, long len) throws IOException {
byte[] sizeData = new byte[ATOM_WORD];
unsignedIntToByteArray(sizeData, 0, len);
// size 0 means to-the-end-of-file
// Arrays.fill(sizeData, (byte) 0);
out.write(sizeData);
out.write(type);
}
}