package org.jcodec.containers.mp4.boxes; import static org.jcodec.containers.mp4.TimeUtil.fromMovTime; import static org.jcodec.containers.mp4.TimeUtil.toMovTime; import org.jcodec.common.io.NIOUtils; import java.nio.ByteBuffer; /** * This class is part of JCodec ( www.jcodec.org ) This software is distributed * under FreeBSD License * * A movie header box * * @author The JCodec project * */ public class MovieHeaderBox extends FullBox { private int timescale; private long duration; private float rate; private float volume; private long created; private long modified; private int[] matrix; private int nextTrackId; public static String fourcc() { return "mvhd"; } public static MovieHeaderBox createMovieHeaderBox(int timescale, long duration, float rate, float volume, long created, long modified, int[] matrix, int nextTrackId) { MovieHeaderBox mvhd = new MovieHeaderBox(new Header(fourcc())); mvhd.timescale = timescale; mvhd.duration = duration; mvhd.rate = rate; mvhd.volume = volume; mvhd.created = created; mvhd.modified = modified; mvhd.matrix = matrix; mvhd.nextTrackId = nextTrackId; return mvhd; } public MovieHeaderBox(Header header) { super(header); } public int getTimescale() { return timescale; } public long getDuration() { return duration; } public int getNextTrackId() { return nextTrackId; } public float getRate() { return rate; } public float getVolume() { return volume; } public long getCreated() { return created; } public long getModified() { return modified; } public int[] getMatrix() { return matrix; } public void setTimescale(int newTs) { this.timescale = newTs; } public void setDuration(long duration) { this.duration = duration; } public void setNextTrackId(int nextTrackId) { this.nextTrackId = nextTrackId; } private int[] readMatrix(ByteBuffer input) { int[] matrix = new int[9]; for (int i = 0; i < 9; i++) matrix[i] = input.getInt(); return matrix; } private float readVolume(ByteBuffer input) { return (float) input.getShort() / 256f; } private float readRate(ByteBuffer input) { return (float) input.getInt() / 65536f; } public void parse(ByteBuffer input) { super.parse(input); if (version == 0) { created = fromMovTime(input.getInt()); modified = fromMovTime(input.getInt()); timescale = input.getInt(); duration = input.getInt(); } else if (version == 1) { created = fromMovTime((int) input.getLong()); modified = fromMovTime((int) input.getLong()); timescale = input.getInt(); duration = input.getLong(); } else { throw new RuntimeException("Unsupported version"); } rate = readRate(input); volume = readVolume(input); NIOUtils.skip(input, 10); matrix = readMatrix(input); NIOUtils.skip(input, 24); nextTrackId = input.getInt(); } public void doWrite(ByteBuffer out) { super.doWrite(out); out.putInt(toMovTime(created)); out.putInt(toMovTime(modified)); out.putInt(timescale); out.putInt((int) duration); writeFixed1616(out, rate); writeFixed88(out, volume); out.put(new byte[10]); writeMatrix(out); out.put(new byte[24]); out.putInt(nextTrackId); } private void writeMatrix(ByteBuffer out) { for (int i = 0; i < Math.min(9, matrix.length); i++) out.putInt(matrix[i]); for (int i = Math.min(9, matrix.length); i < 9; i++) out.putInt(0); } private void writeFixed88(ByteBuffer out, float volume) { out.putShort((short) (volume * 256.)); } private void writeFixed1616(ByteBuffer out, float rate) { out.putInt((int) (rate * 65536.)); } }