package org.jcodec.containers.mp4;
import org.jcodec.common.io.NIOUtils;
import org.jcodec.common.io.SeekableByteChannel;
import org.jcodec.common.logging.Logger;
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;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* @author The JCodec project
*
*/
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 = vt.getStsc();
size -= stsc.getSampleToChunk().length * 12;
size += 12;
ChunkOffsetsBox stco = vt.getStco();
if (stco != null) {
size -= stco.getChunkOffsets().length << 2;
size += vt.getFrameCount() << 3;
} else {
ChunkOffsets64Box co64 = vt.getCo64();
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.getFileTypeBox());
headerPos = output.position() - 24;
output.setPosition(headerPos);
header = ByteBuffer.allocate(headerSize);
output.write(header);
header.clear();
Header.createHeader("wide", 8).writeChannel(output);
Header.createHeader("mdat", 1).writeChannel(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.setPosition(mdatOffset);
NIOUtils.writeLong(out, mdatSize);
out.setPosition(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)
Header.createHeader("free", rem).writeChannel(out);
} catch (ArrayIndexOutOfBoundsException e) {
Logger.warn("Could not web-optimize, header is bigger then allocated space.");
Header.createHeader("free", header.remaining()).writeChannel(out);
out.setPosition(mdatEnd);
MP4Util.writeMovie(out, movie);
}
}
}