package org.jcodec.containers.mp4;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.jcodec.common.NIOUtils;
import org.jcodec.common.SeekableByteChannel;
import org.jcodec.containers.mp4.boxes.Box;
import org.jcodec.containers.mp4.boxes.ChunkOffsets64Box;
import org.jcodec.containers.mp4.boxes.ChunkOffsetsBox;
import org.jcodec.containers.mp4.boxes.Header;
import org.jcodec.containers.mp4.boxes.MovieBox;
import org.jcodec.containers.mp4.boxes.SampleToChunkBox;
import org.jcodec.containers.mp4.boxes.TrakBox;
import org.jcodec.containers.mp4.muxer.MP4Muxer;
public class WebOptimizedMP4Muxer extends MP4Muxer {
private ByteBuffer header;
private long headerPos;
public static WebOptimizedMP4Muxer withOldHeader(SeekableByteChannel output, Brand brand, MovieBox oldHeader)
throws IOException {
int size = (int) oldHeader.getHeader().getSize();
TrakBox vt = oldHeader.getVideoTrack();
SampleToChunkBox stsc = Box.findFirst(vt, SampleToChunkBox.class, "mdia", "minf", "stbl", "stsc");
size -= stsc.getSampleToChunk().length * 12;
size += 12;
ChunkOffsetsBox stco = Box.findFirst(vt, ChunkOffsetsBox.class, "mdia", "minf", "stbl", "stco");
if (stco != null) {
size -= stco.getChunkOffsets().length << 2;
size += vt.getFrameCount() << 3;
} else {
ChunkOffsets64Box co64 = Box.findFirst(vt, ChunkOffsets64Box.class, "mdia", "minf", "stbl", "co64");
size -= co64.getChunkOffsets().length << 3;
size += vt.getFrameCount() << 3;
}
return new WebOptimizedMP4Muxer(output, brand, size + (size >> 1));
}
public WebOptimizedMP4Muxer(SeekableByteChannel output, Brand brand, int headerSize) throws IOException {
super(output, brand);
headerPos = output.position() - 24;
output.position(headerPos);
header = ByteBuffer.allocate(headerSize);
output.write(header);
header.clear();
new Header("wide", 8).write(output);
new Header("mdat", 1).write(output);
mdatOffset = output.position();
NIOUtils.writeLong(output, 0);
}
@Override
public void storeHeader(MovieBox movie) throws IOException {
long mdatEnd = out.position();
long mdatSize = mdatEnd - mdatOffset + 8;
out.position(mdatOffset);
NIOUtils.writeLong(out, mdatSize);
out.position(headerPos);
try {
movie.write(header);
header.flip();
int rem = header.capacity() - header.limit();
if (rem < 8) {
header.duplicate().putInt(header.capacity());
}
out.write(header);
if (rem >= 8)
new Header("free", rem).write(out);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Could not web-optimize, header is bigger then allocated space.");
new Header("free", header.remaining()).write(out);
out.position(mdatEnd);
MP4Util.writeMovie(out, movie);
}
}
}