www in docker support

This commit is contained in:
MaddoScientisto 2026-04-22 18:41:37 +02:00
commit c227fce036
2145 changed files with 399596 additions and 58 deletions

View file

@ -0,0 +1,88 @@
package org.jcodec.containers.mxf;
import org.jcodec.common.Codec;
import org.jcodec.containers.mxf.model.UL;
public class MXFCodec {
private final UL ul;
private final Codec codec;
static MXFCodec mxfCodec(String ul, Codec codec) {
return new MXFCodec(UL.newUL(ul), codec);
}
MXFCodec(UL ul, Codec codec) {
this.ul = ul;
this.codec = codec;
}
public UL getUl() {
return this.ul;
}
public Codec getCodec() {
return this.codec;
}
public static final MXFCodec MPEG2_XDCAM = mxfCodec("06.0E.2B.34.04.01.01.03.04.01.02.02.01.04.03", Codec.MPEG2);
public static final MXFCodec MPEG2_ML = mxfCodec("06.0E.2B.34.04.01.01.03.04.01.02.02.01.01.11", Codec.MPEG2);
public static final MXFCodec MPEG2_D10_PAL = mxfCodec("06.0E.2B.34.04.01.01.01.04.01.02.02.01.02.01.01", Codec.MPEG2);
public static final MXFCodec MPEG2_HL = mxfCodec("06.0E.2B.34.04.01.01.03.04.01.02.02.01.03.03", Codec.MPEG2);
public static final MXFCodec MPEG2_HL_422_I = mxfCodec("06.0E.2B.34.04.01.01.03.04.01.02.02.01.04.02", Codec.MPEG2);
public static final MXFCodec MPEG4_XDCAM_PROXY = mxfCodec("06.0E.2B.34.04.01.01.03.04.01.02.02.01.20.02.03", Codec.MPEG4);
public static final MXFCodec DV_25_PAL = mxfCodec("06.0E.2B.34.04.01.01.01.04.01.02.02.02.01.02", Codec.DV);
public static final MXFCodec JPEG2000 = mxfCodec("06.0E.2B.34.04.01.01.07.04.01.02.02.03.01.01", Codec.J2K);
public static final MXFCodec VC1 = mxfCodec("06.0e.2b.34.04.01.01.0A.04.01.02.02.04", Codec.VC1);
public static final MXFCodec RAW = mxfCodec("06.0E.2B.34.04.01.01.01.04.01.02.01.7F", null);
public static final MXFCodec RAW_422 = mxfCodec("06.0E.2B.34.04.01.01.0A.04.01.02.01.01.02.01", null);
public static final MXFCodec VC3_DNXHD = mxfCodec("06.0E.2B.34.04.01.01.01.04.01.02.02.03.02", Codec.VC3);
public static final MXFCodec VC3_DNXHD_2 = mxfCodec("06.0E.2B.34.04.01.01.01.04.01.02.02.71", Codec.VC3);
public static final MXFCodec VC3_DNXHD_AVID = mxfCodec("06.0E.2B.34.04.01.01.01.0E.04.02.01.02.04.01", Codec.VC3);
public static final MXFCodec AVC_INTRA = mxfCodec("06.0E.2B.34.04.01.01.0A.04.01.02.02.01.32", Codec.H264);
public static final MXFCodec AVC_SPSPPS = mxfCodec("06.0E.2B.34.04.01.01.0A.04.01.02.02.01.31.11.01", Codec.H264);
public static final MXFCodec V210 = mxfCodec("06.0E.2B.34.04.01.01.0A.04.01.02.01.01.02.02", Codec.V210);
public static final MXFCodec PRORES_AVID = mxfCodec("06.0E.2B.34.04.01.01.01.0E.04.02.01.02.11", Codec.PRORES);
public static final MXFCodec PRORES = mxfCodec("06.0E.2B.34.04.01.01.0D.04.01.02.02.03.06", Codec.PRORES);
public static final MXFCodec PCM_S16LE_1 = mxfCodec("06.0E.2B.34.04.01.01.01.04.02.02.01", null);
public static final MXFCodec PCM_S16LE_3 = mxfCodec("06.0E.2B.34.04.01.01.01.04.02.02.01.01", null);
public static final MXFCodec PCM_S16LE_2 = mxfCodec("06.0E.2B.34.04.01.01.01.04.02.02.01.7F", null);
public static final MXFCodec PCM_S16BE = mxfCodec("06.0E.2B.34.04.01.01.07.04.02.02.01.7E", null);
public static final MXFCodec PCM_ALAW = mxfCodec("06.0E.2B.34.04.01.01.04.04.02.02.02.03.01.01", Codec.ALAW);
public static final MXFCodec AC3 = mxfCodec("06.0E.2B.34.04.01.01.01.04.02.02.02.03.02.01", Codec.AC3);
public static final MXFCodec MP2 = mxfCodec("06.0E.2B.34.04.01.01.01.04.02.02.02.03.02.05", Codec.MP3);
public static final MXFCodec UNKNOWN = new MXFCodec(new UL(new byte[0]), null);
public static MXFCodec[] values() {
return new MXFCodec[] {
MPEG2_XDCAM, MPEG2_ML, MPEG2_D10_PAL, MPEG2_HL, MPEG2_HL_422_I, MPEG4_XDCAM_PROXY, DV_25_PAL, JPEG2000, VC1, RAW,
RAW_422, VC3_DNXHD, VC3_DNXHD_2, VC3_DNXHD_AVID, AVC_INTRA, AVC_SPSPPS, V210, PRORES_AVID, PRORES, PCM_S16LE_1,
PCM_S16LE_3, PCM_S16LE_2, PCM_S16BE, PCM_ALAW, AC3, MP2 };
}
}

View file

@ -0,0 +1,89 @@
package org.jcodec.containers.mxf;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import org.jcodec.containers.mxf.model.AES3PCMDescriptor;
import org.jcodec.containers.mxf.model.CDCIEssenceDescriptor;
import org.jcodec.containers.mxf.model.ContentStorage;
import org.jcodec.containers.mxf.model.EssenceContainerData;
import org.jcodec.containers.mxf.model.FileDescriptor;
import org.jcodec.containers.mxf.model.GenericDataEssenceDescriptor;
import org.jcodec.containers.mxf.model.GenericDescriptor;
import org.jcodec.containers.mxf.model.GenericPictureEssenceDescriptor;
import org.jcodec.containers.mxf.model.GenericSoundEssenceDescriptor;
import org.jcodec.containers.mxf.model.Identification;
import org.jcodec.containers.mxf.model.IndexSegment;
import org.jcodec.containers.mxf.model.J2KPictureDescriptor;
import org.jcodec.containers.mxf.model.MPEG2VideoDescriptor;
import org.jcodec.containers.mxf.model.MXFMetadata;
import org.jcodec.containers.mxf.model.MXFPartitionPack;
import org.jcodec.containers.mxf.model.MaterialPackage;
import org.jcodec.containers.mxf.model.Preface;
import org.jcodec.containers.mxf.model.RGBAEssenceDescriptor;
import org.jcodec.containers.mxf.model.Sequence;
import org.jcodec.containers.mxf.model.SourceClip;
import org.jcodec.containers.mxf.model.SourcePackage;
import org.jcodec.containers.mxf.model.TimecodeComponent;
import org.jcodec.containers.mxf.model.TimelineTrack;
import org.jcodec.containers.mxf.model.UL;
import org.jcodec.containers.mxf.model.WaveAudioDescriptor;
public class MXFConst {
public static final UL HEADER_PARTITION_KLV = UL.newUL("06.0e.2b.34.02.05.01.01.0d.01.02.01.01.02");
public static final UL INDEX_KLV = UL.newUL("06.0E.2B.34.02.53.01.01.0d.01.02.01.01.10.01.00");
public static final UL GENERIC_DESCRIPTOR_KLV = UL.newUL("06.0E.2B.34.02.53.01.01.0d.01.01.01.01.01");
public static Map<UL, Class<? extends MXFMetadata>> klMetadata = new HashMap<>();
static {
klMetadata.put(UL.newUL("06.0E.2B.34.02.53.01.01.0d.01.01.01.01.01.18.00"), ContentStorage.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.53.01.01.0d.01.01.01.01.01.37.00"), SourcePackage.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.53.01.01.0d.01.01.01.01.01.0F.00"), Sequence.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.53.01.01.0D.01.01.01.01.01.2F.00"), Preface.class);
klMetadata.put(UL.newUL("06.0e.2b.34.02.53.01.01.0d.01.01.01.01.01.30.00"), Identification.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.53.01.01.0d.01.01.01.01.01.11.00"), SourceClip.class);
klMetadata.put(UL.newUL("06.0e.2b.34.02.53.01.01.0d.01.01.01.01.01.23.00"), EssenceContainerData.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.53.01.01.0d.01.01.01.01.01.3A.00"), TimelineTrack.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.53.01.01.0d.01.01.01.01.01.3B.00"), TimelineTrack.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.53.01.01.0d.01.01.01.01.01.36.00"), MaterialPackage.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.53.01.01.0d.01.02.01.01.10.01.00"), IndexSegment.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.53.01.01.0d.01.01.01.01.01.44.00"), GenericDescriptor.class);
klMetadata.put(UL.newUL("06.0e.2b.34.02.53.01.01.0d.01.01.01.01.01.5b.00"), GenericDataEssenceDescriptor.class);
klMetadata.put(UL.newUL("06.0e.2b.34.02.53.01.01.0d.01.01.01.01.01.5b.00"), GenericDataEssenceDescriptor.class);
klMetadata.put(UL.newUL("06.0e.2b.34.02.53.01.01.0d.01.01.01.01.01.5c.00"), GenericDataEssenceDescriptor.class);
klMetadata.put(UL.newUL("06.0e.2b.34.02.53.01.01.0d.01.01.01.01.01.43.00"), GenericDataEssenceDescriptor.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.53.01.01.0d.01.01.01.01.01.42.00"), GenericSoundEssenceDescriptor.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.53.01.01.0d.01.01.01.01.01.28.00"), CDCIEssenceDescriptor.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.53.01.01.0d.01.01.01.01.01.29.00"), RGBAEssenceDescriptor.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.53.01.01.0d.01.01.01.01.01.51.00"), MPEG2VideoDescriptor.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.53.01.01.0d.01.01.01.01.01.48.00"), WaveAudioDescriptor.class);
klMetadata.put(UL.newUL("06.0e.2b.34.02.53.01.01.0d.01.01.01.01.01.25.00"), FileDescriptor.class);
klMetadata.put(UL.newUL("06.0e.2b.34.02.53.01.01.0d.01.01.01.01.01.27.00"), GenericPictureEssenceDescriptor.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.53.01.01.0d.01.01.01.01.01.47.00"), AES3PCMDescriptor.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.05.01.01.0d.01.02.01.01.05.01.00"), MXFPartitionPack.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.05.01.01.0d.01.02.01.01.02.01.00"), MXFPartitionPack.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.05.01.01.0d.01.02.01.01.02.02.00"), MXFPartitionPack.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.05.01.01.0d.01.02.01.01.02.03.00"), MXFPartitionPack.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.05.01.01.0d.01.02.01.01.02.04.00"), MXFPartitionPack.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.05.01.01.0d.01.02.01.01.03.01.00"), MXFPartitionPack.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.05.01.01.0d.01.02.01.01.03.02.00"), MXFPartitionPack.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.05.01.01.0d.01.02.01.01.03.03.00"), MXFPartitionPack.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.05.01.01.0d.01.02.01.01.03.04.00"), MXFPartitionPack.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.05.01.01.0d.01.02.01.01.04.02.00"), MXFPartitionPack.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.05.01.01.0d.01.02.01.01.04.04.00"), MXFPartitionPack.class);
klMetadata.put(UL.newUL("06.0E.2B.34.02.53.01.01.0D.01.01.01.01.01.14.00"), TimecodeComponent.class);
klMetadata.put(UL.newUL("06.0E.2B.34.01.01.01.02.03.01.02.10.01.00.00.00"), KLVFill.class);
klMetadata.put(UL.newUL("06.0e.2b.34.02.53.01.01.0d.01.01.01.01.01.5a.00"), J2KPictureDescriptor.class);
}
public static class KLVFill extends MXFMetadata {
public KLVFill(UL ul) {
super(ul);
}
public void readBuf(ByteBuffer bb) {}
}
}

View file

@ -0,0 +1,585 @@
package org.jcodec.containers.mxf;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.jcodec.api.NotSupportedException;
import org.jcodec.common.DemuxerTrackMeta;
import org.jcodec.common.SeekableDemuxerTrack;
import org.jcodec.common.TrackType;
import org.jcodec.common.VideoCodecMeta;
import org.jcodec.common.io.FileChannelWrapper;
import org.jcodec.common.io.NIOUtils;
import org.jcodec.common.io.SeekableByteChannel;
import org.jcodec.common.logging.Logger;
import org.jcodec.common.model.ColorSpace;
import org.jcodec.common.model.Packet;
import org.jcodec.common.model.Rational;
import org.jcodec.common.model.Size;
import org.jcodec.common.model.TapeTimecode;
import org.jcodec.containers.mxf.model.FileDescriptor;
import org.jcodec.containers.mxf.model.GenericDescriptor;
import org.jcodec.containers.mxf.model.GenericPictureEssenceDescriptor;
import org.jcodec.containers.mxf.model.GenericSoundEssenceDescriptor;
import org.jcodec.containers.mxf.model.IndexSegment;
import org.jcodec.containers.mxf.model.KLV;
import org.jcodec.containers.mxf.model.MXFMetadata;
import org.jcodec.containers.mxf.model.MXFPartition;
import org.jcodec.containers.mxf.model.MXFUtil;
import org.jcodec.containers.mxf.model.SourceClip;
import org.jcodec.containers.mxf.model.TimecodeComponent;
import org.jcodec.containers.mxf.model.TimelineTrack;
import org.jcodec.containers.mxf.model.UL;
import org.jcodec.containers.mxf.model.WaveAudioDescriptor;
import org.jcodec.platform.Platform;
public class MXFDemuxer {
protected List<MXFMetadata> metadata;
protected MXFPartition header;
protected List<MXFPartition> partitions;
protected List<IndexSegment> indexSegments;
protected SeekableByteChannel ch;
protected MXFDemuxerTrack[] tracks;
protected int totalFrames;
protected double duration;
protected TimecodeComponent timecode;
public MXFDemuxer(SeekableByteChannel ch) throws IOException {
this.ch = ch;
ch.setPosition(0L);
parseHeader(ch);
findIndex();
this.tracks = findTracks();
this.timecode = MXFUtil.<TimecodeComponent>findMeta(this.metadata, TimecodeComponent.class);
}
public static final class OP {
public static final OP OP1a = new OP(1, 1);
public static final OP OP1b = new OP(1, 2);
public static final OP OP1c = new OP(1, 3);
public static final OP OP2a = new OP(2, 1);
public static final OP OP2b = new OP(2, 2);
public static final OP OP2c = new OP(2, 3);
public static final OP OP3a = new OP(3, 1);
public static final OP OP3b = new OP(3, 2);
public static final OP OP3c = new OP(3, 3);
public static final OP OPAtom = new OP(16, 0);
private static final OP[] _values = new OP[] { OP1a, OP1b, OP1c, OP2a, OP2b, OP2c, OP3a, OP3b, OP3c, OPAtom };
public int major;
public int minor;
private OP(int major, int minor) {
this.major = major;
this.minor = minor;
}
public static OP[] values() {
return _values;
}
}
public OP getOp() {
UL op = this.header.getPack().getOp();
OP[] values = OP.values();
for (int i = 0; i < values.length; i++) {
OP op2 = values[i];
if (op.get(12) == op2.major && op.get(13) == op2.minor)
return op2;
}
return OP.OPAtom;
}
public MXFDemuxerTrack[] findTracks() throws IOException {
List<TimelineTrack> _tracks = MXFUtil.findAllMeta(this.metadata, TimelineTrack.class);
List<FileDescriptor> descriptors = MXFUtil.findAllMeta(this.metadata, FileDescriptor.class);
Map<Integer, MXFDemuxerTrack> tracks = new LinkedHashMap<>();
for (TimelineTrack track : _tracks) {
if (track.getTrackId() == 0 || track.getTrackNumber() == 0) {
Logger.warn("trackId == 0 || trackNumber == 0");
continue;
}
int trackId = track.getTrackId();
if (tracks.containsKey(Integer.valueOf(trackId))) {
Logger.warn("duplicate trackId " + trackId);
continue;
}
FileDescriptor descriptor = findDescriptor(descriptors, track.getTrackId());
if (descriptor == null) {
Logger.warn("No generic descriptor for track: " + track.getTrackId());
if (descriptors.size() == 1 && descriptors.get(0).getLinkedTrackId() == 0)
descriptor = descriptors.get(0);
}
if (descriptor == null) {
Logger.warn("Track without descriptor: " + track.getTrackId());
continue;
}
int trackNumber = track.getTrackNumber();
UL ul = UL.newULFromInts(new int[] {
6, 14, 43, 52, 1, 2, 1, 1, 13, 1,
3, 1, trackNumber >>> 24 & 0xFF, trackNumber >>> 16 & 0xFF, trackNumber >>> 8 & 0xFF, trackNumber & 0xFF });
MXFDemuxerTrack dt = createTrack(ul, track, descriptor);
if (dt.getCodec() != null || descriptor instanceof WaveAudioDescriptor)
tracks.put(Integer.valueOf(trackId), dt);
}
return (MXFDemuxerTrack[])tracks.values().toArray(new MXFDemuxerTrack[tracks.size()]);
}
public static FileDescriptor findDescriptor(List<FileDescriptor> descriptors, int trackId) {
for (FileDescriptor descriptor : descriptors) {
if (descriptor.getLinkedTrackId() == trackId)
return descriptor;
}
return null;
}
protected MXFDemuxerTrack createTrack(UL ul, TimelineTrack track, GenericDescriptor descriptor) throws IOException {
return new MXFDemuxerTrack(this, ul, track, descriptor);
}
public List<IndexSegment> getIndexes() {
return this.indexSegments;
}
public List<MXFPartition> getEssencePartitions() {
return this.partitions;
}
public TimecodeComponent getTimecode() {
return this.timecode;
}
public void parseHeader(SeekableByteChannel ff) throws IOException {
this.header = readHeaderPartition(ff);
this.metadata = new ArrayList<>();
this.partitions = new ArrayList<>();
long nextPartition = ff.size();
ff.setPosition(this.header.getPack().getFooterPartition());
do {
long thisPartition = ff.position();
KLV kl = KLV.readKL(ff);
ByteBuffer fetchFrom = NIOUtils.fetchFromChannel(ff, (int)kl.len);
this.header = MXFPartition.read(kl.key, fetchFrom, ff.position() - kl.offset, nextPartition);
if (this.header.getPack().getNbEssenceContainers() > 0)
this.partitions.add(0, this.header);
this.metadata.addAll(0, readPartitionMeta(ff, this.header));
ff.setPosition(this.header.getPack().getPrevPartition());
nextPartition = thisPartition;
} while (this.header.getPack().getThisPartition() != 0L);
}
public static List<MXFMetadata> readPartitionMeta(SeekableByteChannel ff, MXFPartition header) throws IOException {
long basePos = ff.position();
List<MXFMetadata> local = new ArrayList<>();
ByteBuffer metaBuffer = NIOUtils.fetchFromChannel(ff, (int)Math.max(0L, header.getEssenceFilePos() - basePos));
KLV kl;
while (metaBuffer.hasRemaining() && (kl = KLV.readKLFromBuffer(metaBuffer, basePos)) != null &&
(long)metaBuffer.remaining() >= kl.len) {
MXFMetadata meta = parseMeta(kl.key, NIOUtils.read(metaBuffer, (int)kl.len));
if (meta != null)
local.add(meta);
}
return local;
}
public static MXFPartition readHeaderPartition(SeekableByteChannel ff) throws IOException {
MXFPartition header = null;
KLV kl;
while ((kl = KLV.readKL(ff)) != null) {
if (MXFConst.HEADER_PARTITION_KLV.equals(kl.key)) {
ByteBuffer data = NIOUtils.fetchFromChannel(ff, (int)kl.len);
header = MXFPartition.read(kl.key, data, ff.position() - kl.offset, 0L);
break;
}
ff.setPosition(ff.position() + kl.len);
}
return header;
}
private static MXFMetadata parseMeta(UL ul, ByteBuffer _bb) {
Class<? extends MXFMetadata> class1 = MXFConst.klMetadata.get(ul);
if (class1 == null) {
Logger.warn("Unknown metadata piece: " + String.valueOf(ul));
return null;
}
try {
MXFMetadata meta = Platform.newInstance(class1, new Object[] { ul });
meta.readBuf(_bb);
return meta;
} catch (Exception e) {
Logger.warn("Unknown metadata piece: " + String.valueOf(ul));
return null;
}
}
private void findIndex() {
this.indexSegments = new ArrayList<>();
for (MXFMetadata meta : this.metadata) {
if (meta instanceof IndexSegment) {
IndexSegment is = (IndexSegment)meta;
this.indexSegments.add(is);
this.totalFrames = (int)((long)this.totalFrames + is.getIndexDuration());
this.duration += (double)is.getIndexEditRateDen() * (double)is.getIndexDuration() / (double)is.getIndexEditRateNum();
}
}
}
public MXFDemuxerTrack[] getTracks() {
return this.tracks;
}
public MXFDemuxerTrack getVideoTrack() {
for (MXFDemuxerTrack track : this.tracks) {
if (track.isVideo())
return track;
}
return null;
}
public MXFDemuxerTrack[] getAudioTracks() {
List<MXFDemuxerTrack> audio = new ArrayList<>();
for (MXFDemuxerTrack track : this.tracks) {
if (track.isAudio())
audio.add(track);
}
return audio.<MXFDemuxerTrack>toArray(new MXFDemuxerTrack[0]);
}
public static class MXFDemuxerTrack implements SeekableDemuxerTrack {
private UL essenceUL;
private int dataLen;
private int indexSegmentIdx;
private int indexSegmentSubIdx;
private int frameNo;
private long pts;
private int partIdx;
private long partEssenceOffset;
private GenericDescriptor descriptor;
private TimelineTrack track;
private boolean video;
private boolean audio;
private MXFCodec codec;
private int audioFrameDuration;
private int audioTimescale;
private MXFDemuxer demuxer;
public MXFDemuxerTrack(MXFDemuxer demuxer, UL essenceUL, TimelineTrack track, GenericDescriptor descriptor) throws IOException {
this.demuxer = demuxer;
this.essenceUL = essenceUL;
this.track = track;
this.descriptor = descriptor;
if (descriptor instanceof GenericPictureEssenceDescriptor) {
this.video = true;
} else if (descriptor instanceof GenericSoundEssenceDescriptor) {
this.audio = true;
}
this.codec = resolveCodec();
if (this.codec != null || descriptor instanceof WaveAudioDescriptor) {
Logger.warn("Track type: " + this.video + ", " + this.audio);
if (this.audio && descriptor instanceof WaveAudioDescriptor) {
WaveAudioDescriptor wave = (WaveAudioDescriptor)descriptor;
cacheAudioFrameSizes(demuxer.ch);
this.audioFrameDuration = this.dataLen / ((wave.getQuantizationBits() >> 3) * wave.getChannelCount());
this.audioTimescale = (int)wave.getAudioSamplingRate().scalar();
}
}
}
public boolean isAudio() {
return this.audio;
}
public boolean isVideo() {
return this.video;
}
public double getDuration() {
return this.demuxer.duration;
}
public int getNumFrames() {
return this.demuxer.totalFrames;
}
public String getName() {
return this.track.getName();
}
private void cacheAudioFrameSizes(SeekableByteChannel ch) throws IOException {
for (MXFPartition mxfPartition : this.demuxer.partitions) {
if (mxfPartition.getEssenceLength() > 0L) {
KLV kl;
ch.setPosition(mxfPartition.getEssenceFilePos());
do {
kl = KLV.readKL(ch);
if (kl == null)
break;
ch.setPosition(ch.position() + kl.len);
} while (!this.essenceUL.equals(kl.key));
if (kl != null && this.essenceUL.equals(kl.key)) {
this.dataLen = (int)kl.len;
break;
}
}
}
}
public Packet nextFrame() throws IOException {
Packet result;
if (this.indexSegmentIdx >= this.demuxer.indexSegments.size())
return null;
IndexSegment seg = this.demuxer.indexSegments.get(this.indexSegmentIdx);
long[] off = seg.getIe().getFileOff();
int erDen = seg.getIndexEditRateNum();
int erNum = seg.getIndexEditRateDen();
long frameEssenceOffset = off[this.indexSegmentSubIdx];
byte toff = seg.getIe().getDisplayOff()[this.indexSegmentSubIdx];
boolean kf = (seg.getIe().getKeyFrameOff()[this.indexSegmentSubIdx] == 0);
while (frameEssenceOffset >= this.partEssenceOffset + this.demuxer.partitions.get(this.partIdx).getEssenceLength() && this.partIdx <
this.demuxer.partitions.size() - 1) {
this.partEssenceOffset += this.demuxer.partitions.get(this.partIdx).getEssenceLength();
this.partIdx++;
}
long frameFileOffset = frameEssenceOffset - this.partEssenceOffset +
this.demuxer.partitions.get(this.partIdx).getEssenceFilePos();
if (!this.audio) {
result = readPacket(frameFileOffset, this.dataLen, this.pts + (long)(erNum * toff), erDen, erNum, this.frameNo++, kf);
this.pts += (long)erNum;
} else {
result = readPacket(frameFileOffset, this.dataLen, this.pts, this.audioTimescale, this.audioFrameDuration, this.frameNo++, kf);
this.pts += (long)this.audioFrameDuration;
}
this.indexSegmentSubIdx++;
if (this.indexSegmentSubIdx >= off.length) {
this.indexSegmentIdx++;
this.indexSegmentSubIdx = 0;
if (this.dataLen == 0 && this.indexSegmentIdx < this.demuxer.indexSegments.size()) {
IndexSegment nseg = this.demuxer.indexSegments.get(this.indexSegmentIdx);
this.pts = this.pts * (long)nseg.getIndexEditRateNum() / (long)erDen;
}
}
return result;
}
public MXFDemuxer.MXFPacket readPacket(long off, int len, long pts, int timescale, int duration, int frameNo, boolean kf) throws IOException {
assert false : "Decompilation failed at line #420 -> offsets [0]";
assert false : "Decompilation failed at line #421 -> offsets [9]";
assert false : "Decompilation failed at line #422 -> offsets [15]";
assert false : "Decompilation failed at line #424 -> offsets [24]";
assert false : "Decompilation failed at line #425 -> offsets [31]";
assert false : "Decompilation failed at line #426 -> offsets [51]";
assert false : "Decompilation failed at line #427 -> offsets [72]";
assert false : "Decompilation failed at line #430 -> offsets [82, 154]";
assert false : "Decompilation failed at line #431 -> offsets [102]";
assert false : "Decompilation failed at line #432 -> offsets [127]";
assert false : "Decompilation failed at line #433 -> offsets [150]";
assert false : "Decompilation failed at line #434 -> offsets [155]";
}
public boolean gotoFrame(long frameNo) {
if (frameNo == (long)this.frameNo)
return true;
this.indexSegmentSubIdx = (int)frameNo;
this.indexSegmentIdx = 0;
for (; this.indexSegmentIdx < this.demuxer.indexSegments.size() && (long)this.indexSegmentSubIdx >= this.demuxer.indexSegments.get(this.indexSegmentIdx)
.getIndexDuration(); this.indexSegmentIdx++)
this.indexSegmentSubIdx = (int)((long)this.indexSegmentSubIdx - this.demuxer.indexSegments.get(this.indexSegmentIdx).getIndexDuration());
this.indexSegmentSubIdx = Math.min(this.indexSegmentSubIdx,
(int)this.demuxer.indexSegments.get(this.indexSegmentIdx).getIndexDuration());
return true;
}
public boolean gotoSyncFrame(long frameNo) {
if (!gotoFrame(frameNo))
return false;
IndexSegment seg = this.demuxer.indexSegments.get(this.indexSegmentIdx);
byte kfOff = seg.getIe().getKeyFrameOff()[this.indexSegmentSubIdx];
return gotoFrame(frameNo + (long)kfOff);
}
public long getCurFrame() {
return (long)this.frameNo;
}
public void seek(double second) {
throw new NotSupportedException("");
}
public UL getEssenceUL() {
return this.essenceUL;
}
public GenericDescriptor getDescriptor() {
return this.descriptor;
}
public MXFCodec getCodec() {
return this.codec;
}
private MXFCodec resolveCodec() {
UL codecUL;
if (this.video) {
codecUL = ((GenericPictureEssenceDescriptor)this.descriptor).getPictureEssenceCoding();
} else if (this.audio) {
codecUL = ((GenericSoundEssenceDescriptor)this.descriptor).getSoundEssenceCompression();
} else {
return null;
}
MXFCodec[] values = MXFCodec.values();
for (int i = 0; i < values.length; i++) {
MXFCodec codec = values[i];
if (codec.getUl().equals(codecUL))
return codec;
}
Logger.warn("Unknown codec: " + String.valueOf(codecUL));
return null;
}
public int getTrackId() {
return this.track.getTrackId();
}
public DemuxerTrackMeta getMeta() {
Size size = null;
if (this.video) {
GenericPictureEssenceDescriptor pd = (GenericPictureEssenceDescriptor)this.descriptor;
size = new Size(pd.getStoredWidth(), pd.getStoredHeight());
}
TrackType t = this.video ? TrackType.VIDEO : (this.audio ? TrackType.AUDIO : TrackType.OTHER);
return new DemuxerTrackMeta(t, getCodec().getCodec(), this.demuxer.duration, null, this.demuxer.totalFrames, null,
VideoCodecMeta.createSimpleVideoCodecMeta(size, ColorSpace.YUV420), null);
}
public Rational getEditRate() {
return this.track.getEditRate();
}
}
public static class MXFPacket extends Packet {
private long offset;
private int len;
public MXFPacket(ByteBuffer data, long pts, int timescale, long duration, long frameNo, Packet.FrameType frameType, TapeTimecode tapeTimecode, long offset, int len) {
super(data, pts, timescale, duration, frameNo, frameType, tapeTimecode, 0);
this.offset = offset;
this.len = len;
}
public long getOffset() {
return this.offset;
}
public int getLen() {
return this.len;
}
}
public static class Fast extends MXFDemuxer {
public Fast(SeekableByteChannel ch) throws IOException {
super(ch);
}
public void parseHeader(SeekableByteChannel ff) throws IOException {
this.partitions = new ArrayList<>();
this.metadata = new ArrayList<>();
this.header = readHeaderPartition(ff);
this.metadata.addAll(readPartitionMeta(ff, this.header));
this.partitions.add(this.header);
ff.setPosition(this.header.getPack().getFooterPartition());
KLV kl = KLV.readKL(ff);
if (kl != null) {
ByteBuffer fetchFrom = NIOUtils.fetchFromChannel(ff, (int)kl.len);
MXFPartition footer = MXFPartition.read(kl.key, fetchFrom, ff.position() - kl.offset, ff.size());
this.metadata.addAll(readPartitionMeta(ff, footer));
}
}
}
public List<SourceClip> getSourceClips(int trackId) {
boolean trackFound = true;
List<SourceClip> clips = new ArrayList<>();
for (MXFMetadata m : this.metadata) {
if (m instanceof TimelineTrack) {
TimelineTrack tt = (TimelineTrack)m;
int trackId2 = tt.getTrackId();
trackFound = (trackId2 == trackId);
}
if (trackFound && m instanceof SourceClip) {
SourceClip clip = (SourceClip)m;
if (clip.getSourceTrackId() == trackId)
clips.add(clip);
}
}
return clips;
}
public static TapeTimecode readTapeTimecode(File mxf) throws IOException {
FileChannelWrapper read = NIOUtils.readableChannel(mxf);
try {
Fast fast = new Fast(read);
MXFDemuxerTrack track = fast.getVideoTrack();
TimecodeComponent timecode = fast.getTimecode();
List<SourceClip> sourceClips = fast.getSourceClips(track.getTrackId());
long tc = 0L;
boolean dropFrame = false;
Rational editRate = null;
if (timecode != null) {
editRate = track.getEditRate();
dropFrame = (timecode.getDropFrame() != 0);
tc = timecode.getStart();
}
for (SourceClip sourceClip : sourceClips)
tc += sourceClip.getStartPosition();
if (editRate != null)
return TapeTimecode.tapeTimecode(tc, dropFrame, (int)Math.ceil(editRate.toDouble()));
return null;
} finally {
read.close();
}
}
public List<MXFMetadata> getMetadata() {
return Collections.unmodifiableList(this.metadata);
}
}

View file

@ -0,0 +1,89 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class AES3PCMDescriptor extends WaveAudioDescriptor {
private byte emphasis;
private short blockStartOffset;
private byte auxBitsMode;
private ByteBuffer channelStatusMode;
private ByteBuffer fixedChannelStatusData;
private ByteBuffer userDataMode;
private ByteBuffer fixedUserData;
public AES3PCMDescriptor(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
super.read(tags);
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 15629:
this.emphasis = _bb.get();
break;
case 15631:
this.blockStartOffset = _bb.getShort();
break;
case 15624:
this.auxBitsMode = _bb.get();
break;
case 15632:
this.channelStatusMode = _bb;
break;
case 15633:
this.fixedChannelStatusData = _bb;
break;
case 15634:
this.userDataMode = _bb;
break;
case 15635:
this.fixedUserData = _bb;
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public byte getEmphasis() {
return this.emphasis;
}
public short getBlockStartOffset() {
return this.blockStartOffset;
}
public byte getAuxBitsMode() {
return this.auxBitsMode;
}
public ByteBuffer getChannelStatusMode() {
return this.channelStatusMode;
}
public ByteBuffer getFixedChannelStatusData() {
return this.fixedChannelStatusData;
}
public ByteBuffer getUserDataMode() {
return this.userDataMode;
}
public ByteBuffer getFixedUserData() {
return this.fixedUserData;
}
}

View file

@ -0,0 +1,49 @@
package org.jcodec.containers.mxf.model;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.jcodec.common.io.NIOUtils;
import org.jcodec.common.io.SeekableByteChannel;
public class BER {
public static final byte ASN_LONG_LEN = -128;
public static final long decodeLength(SeekableByteChannel is) throws IOException {
long length = 0L;
int lengthbyte = NIOUtils.readByte(is) & 0xFF;
if ((lengthbyte & 0xFFFFFF80) > 0) {
lengthbyte &= 0x7F;
if (lengthbyte == 0)
throw new IOException("Indefinite lengths are not supported");
if (lengthbyte > 8)
throw new IOException("Data length > 4 bytes are not supported!");
byte[] bb = NIOUtils.readNByte(is, lengthbyte);
for (int i = 0; i < lengthbyte; i++)
length = length << 8L | (long)(bb[i] & 0xFF);
if (length < 0L)
throw new IOException("mxflib does not support data lengths > 2^63");
} else {
length = (long)(lengthbyte & 0xFF);
}
return length;
}
public static long decodeLengthBuf(ByteBuffer buffer) {
long length = 0L;
int lengthbyte = buffer.get() & 0xFF;
if ((lengthbyte & 0xFFFFFF80) > 0) {
lengthbyte &= 0x7F;
if (lengthbyte == 0)
throw new RuntimeException("Indefinite lengths are not supported");
if (lengthbyte > 8)
throw new RuntimeException("Data length > 8 bytes are not supported!");
for (int i = 0; i < lengthbyte; i++)
length = length << 8L | (long)(buffer.get() & 0xFF);
if (length < 0L)
throw new RuntimeException("mxflib does not support data lengths > 2^63");
} else {
length = (long)(lengthbyte & 0xFF);
}
return length;
}
}

View file

@ -0,0 +1,116 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class CDCIEssenceDescriptor extends GenericPictureEssenceDescriptor {
private int componentDepth;
private int horizontalSubsampling;
private int verticalSubsampling;
private byte colorSiting;
private byte reversedByteOrder;
private short paddingBits;
private int alphaSampleDepth;
private int blackRefLevel;
private int whiteReflevel;
private int colorRange;
public CDCIEssenceDescriptor(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
super.read(tags);
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 13057:
this.componentDepth = _bb.getInt();
break;
case 13058:
this.horizontalSubsampling = _bb.getInt();
break;
case 13064:
this.verticalSubsampling = _bb.getInt();
break;
case 13059:
this.colorSiting = _bb.get();
break;
case 13067:
this.reversedByteOrder = _bb.get();
break;
case 13063:
this.paddingBits = _bb.getShort();
break;
case 13065:
this.alphaSampleDepth = _bb.getInt();
break;
case 13060:
this.blackRefLevel = _bb.getInt();
break;
case 13061:
this.whiteReflevel = _bb.getInt();
break;
case 13062:
this.colorRange = _bb.getInt();
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public int getComponentDepth() {
return this.componentDepth;
}
public int getHorizontalSubsampling() {
return this.horizontalSubsampling;
}
public int getVerticalSubsampling() {
return this.verticalSubsampling;
}
public byte getColorSiting() {
return this.colorSiting;
}
public byte getReversedByteOrder() {
return this.reversedByteOrder;
}
public short getPaddingBits() {
return this.paddingBits;
}
public int getAlphaSampleDepth() {
return this.alphaSampleDepth;
}
public int getBlackRefLevel() {
return this.blackRefLevel;
}
public int getWhiteReflevel() {
return this.whiteReflevel;
}
public int getColorRange() {
return this.colorRange;
}
}

View file

@ -0,0 +1,43 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class ContentStorage extends MXFInterchangeObject {
private UL[] packageRefs;
private UL[] essenceContainerData;
public ContentStorage(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 6401:
this.packageRefs = readULBatch(_bb);
break;
case 6402:
this.essenceContainerData = readULBatch(_bb);
break;
default:
Logger.warn(String.format("Unknown tag [ ContentStorage: " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public UL[] getPackageRefs() {
return this.packageRefs;
}
public UL[] getEssenceContainerData() {
return this.essenceContainerData;
}
}

View file

@ -0,0 +1,35 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.jcodec.common.io.NIOUtils;
public class DeltaEntries {
private byte[] posTabIdx;
private byte[] slice;
private int[] elementData;
public DeltaEntries(byte[] posTabIdx, byte[] slice, int[] elementDelta) {
this.posTabIdx = posTabIdx;
this.slice = slice;
this.elementData = elementDelta;
}
public static DeltaEntries read(ByteBuffer bb) {
bb.order(ByteOrder.BIG_ENDIAN);
int n = bb.getInt();
int len = bb.getInt();
byte[] posTabIdx = new byte[n];
byte[] slice = new byte[n];
int[] elementDelta = new int[n];
for (int i = 0; i < n; i++) {
posTabIdx[i] = bb.get();
slice[i] = bb.get();
elementDelta[i] = bb.getInt();
NIOUtils.skip(bb, len - 6);
}
return new DeltaEntries(posTabIdx, slice, elementDelta);
}
}

View file

@ -0,0 +1,52 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class EssenceContainerData extends MXFInterchangeObject {
private UL linkedPackageUID;
private int indexSID;
private int bodySID;
public EssenceContainerData(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 9985:
this.linkedPackageUID = UL.read(_bb);
break;
case 16134:
this.indexSID = _bb.getInt();
break;
case 16135:
this.bodySID = _bb.getInt();
break;
default:
Logger.warn(String.format("Unknown tag [ EssenceContainerData: " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public UL getLinkedPackageUID() {
return this.linkedPackageUID;
}
public int getIndexSID() {
return this.indexSID;
}
public int getBodySID() {
return this.bodySID;
}
}

View file

@ -0,0 +1,72 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
import org.jcodec.common.model.Rational;
public class FileDescriptor extends GenericDescriptor {
private int linkedTrackId;
private Rational sampleRate;
private long containerDuration;
private UL essenceContainer;
private UL codec;
public FileDescriptor(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
super.read(tags);
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 12294:
this.linkedTrackId = _bb.getInt();
break;
case 12289:
this.sampleRate = new Rational(_bb.getInt(), _bb.getInt());
break;
case 12290:
this.containerDuration = _bb.getLong();
break;
case 12292:
this.essenceContainer = UL.read(_bb);
break;
case 12293:
this.codec = UL.read(_bb);
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public int getLinkedTrackId() {
return this.linkedTrackId;
}
public Rational getSampleRate() {
return this.sampleRate;
}
public long getContainerDuration() {
return this.containerDuration;
}
public UL getEssenceContainer() {
return this.essenceContainer;
}
public UL getCodec() {
return this.codec;
}
}

View file

@ -0,0 +1,35 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class GenericDataEssenceDescriptor extends FileDescriptor {
private UL dataEssenceCoding;
public GenericDataEssenceDescriptor(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
super.read(tags);
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 15873:
this.dataEssenceCoding = UL.read(_bb);
break;
default:
Logger.warn(String.format("Unknown tag [ FileDescriptor: " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public UL getDataEssenceCoding() {
return this.dataEssenceCoding;
}
}

View file

@ -0,0 +1,43 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class GenericDescriptor extends MXFInterchangeObject {
private UL[] locators;
private UL[] subDescriptors;
public GenericDescriptor(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 12033:
this.locators = readULBatch(_bb);
break;
case 16129:
this.subDescriptors = readULBatch(_bb);
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public UL[] getLocators() {
return this.locators;
}
public UL[] getSubDescriptors() {
return this.subDescriptors;
}
}

View file

@ -0,0 +1,71 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class GenericPackage extends MXFInterchangeObject {
private UL[] tracks;
private UL packageUID;
private String name;
private Date packageModifiedDate;
private Date packageCreationDate;
public GenericPackage(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 17409:
this.packageUID = UL.read(_bb);
break;
case 17410:
this.name = readUtf16String(_bb);
break;
case 17411:
this.tracks = readULBatch(_bb);
break;
case 17412:
this.packageModifiedDate = readDate(_bb);
break;
case 17413:
this.packageCreationDate = readDate(_bb);
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public UL[] getTracks() {
return this.tracks;
}
public UL getPackageUID() {
return this.packageUID;
}
public String getName() {
return this.name;
}
public Date getPackageModifiedDate() {
return this.packageModifiedDate;
}
public Date getPackageCreationDate() {
return this.packageCreationDate;
}
}

View file

@ -0,0 +1,265 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
import org.jcodec.common.model.Rational;
public class GenericPictureEssenceDescriptor extends FileDescriptor {
private byte signalStandard;
private LayoutType frameLayout;
private int storedWidth;
private int storedHeight;
private int storedF2Offset;
private int sampledWidth;
private int sampledHeight;
private int sampledXOffset;
private int sampledYOffset;
private int displayHeight;
private int displayWidth;
private int displayXOffset;
private int displayYOffset;
private int displayF2Offset;
private Rational aspectRatio;
private byte activeFormatDescriptor;
private int[] videoLineMap;
private byte alphaTransparency;
private UL transferCharacteristic;
private int imageAlignmentOffset;
private int imageStartOffset;
private int imageEndOffset;
private byte fieldDominance;
private UL pictureEssenceCoding;
private UL codingEquations;
private UL colorPrimaries;
public enum LayoutType {
FullFrame, SeparateFields, OneField, MixedFields, SegmentedFrame;
}
public GenericPictureEssenceDescriptor(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
super.read(tags);
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 12821:
this.signalStandard = _bb.get();
break;
case 12812:
this.frameLayout = LayoutType.values()[_bb.get()];
break;
case 12803:
this.storedWidth = _bb.getInt();
break;
case 12802:
this.storedHeight = _bb.getInt();
break;
case 12822:
this.storedF2Offset = _bb.getInt();
break;
case 12805:
this.sampledWidth = _bb.getInt();
break;
case 12804:
this.sampledHeight = _bb.getInt();
break;
case 12806:
this.sampledXOffset = _bb.getInt();
break;
case 12807:
this.sampledYOffset = _bb.getInt();
break;
case 12808:
this.displayHeight = _bb.getInt();
break;
case 12809:
this.displayWidth = _bb.getInt();
break;
case 12810:
this.displayXOffset = _bb.getInt();
break;
case 12811:
this.displayYOffset = _bb.getInt();
break;
case 12823:
this.displayF2Offset = _bb.getInt();
break;
case 12814:
this.aspectRatio = new Rational(_bb.getInt(), _bb.getInt());
break;
case 12824:
this.activeFormatDescriptor = _bb.get();
break;
case 12813:
this.videoLineMap = readInt32Batch(_bb);
break;
case 12815:
this.alphaTransparency = _bb.get();
break;
case 12816:
this.transferCharacteristic = UL.read(_bb);
break;
case 12817:
this.imageAlignmentOffset = _bb.getInt();
break;
case 12819:
this.imageStartOffset = _bb.getInt();
break;
case 12820:
this.imageEndOffset = _bb.getInt();
break;
case 12818:
this.fieldDominance = _bb.get();
break;
case 12801:
this.pictureEssenceCoding = UL.read(_bb);
break;
case 12826:
this.codingEquations = UL.read(_bb);
break;
case 12825:
this.colorPrimaries = UL.read(_bb);
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public byte getSignalStandard() {
return this.signalStandard;
}
public LayoutType getFrameLayout() {
return this.frameLayout;
}
public int getStoredWidth() {
return this.storedWidth;
}
public int getStoredHeight() {
return this.storedHeight;
}
public int getStoredF2Offset() {
return this.storedF2Offset;
}
public int getSampledWidth() {
return this.sampledWidth;
}
public int getSampledHeight() {
return this.sampledHeight;
}
public int getSampledXOffset() {
return this.sampledXOffset;
}
public int getSampledYOffset() {
return this.sampledYOffset;
}
public int getDisplayHeight() {
return this.displayHeight;
}
public int getDisplayWidth() {
return this.displayWidth;
}
public int getDisplayXOffset() {
return this.displayXOffset;
}
public int getDisplayYOffset() {
return this.displayYOffset;
}
public int getDisplayF2Offset() {
return this.displayF2Offset;
}
public Rational getAspectRatio() {
return this.aspectRatio;
}
public byte getActiveFormatDescriptor() {
return this.activeFormatDescriptor;
}
public int[] getVideoLineMap() {
return this.videoLineMap;
}
public byte getAlphaTransparency() {
return this.alphaTransparency;
}
public UL getTransferCharacteristic() {
return this.transferCharacteristic;
}
public int getImageAlignmentOffset() {
return this.imageAlignmentOffset;
}
public int getImageStartOffset() {
return this.imageStartOffset;
}
public int getImageEndOffset() {
return this.imageEndOffset;
}
public byte getFieldDominance() {
return this.fieldDominance;
}
public UL getPictureEssenceCoding() {
return this.pictureEssenceCoding;
}
public UL getCodingEquations() {
return this.codingEquations;
}
public UL getColorPrimaries() {
return this.colorPrimaries;
}
}

View file

@ -0,0 +1,99 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
import org.jcodec.common.model.Rational;
public class GenericSoundEssenceDescriptor extends FileDescriptor {
private Rational audioSamplingRate;
private byte locked;
private byte audioRefLevel;
private byte electroSpatialFormulation;
private int channelCount;
private int quantizationBits;
private byte dialNorm;
private UL soundEssenceCompression;
public GenericSoundEssenceDescriptor(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
super.read(tags);
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 15619:
this.audioSamplingRate = new Rational(_bb.getInt(), _bb.getInt());
break;
case 15618:
this.locked = _bb.get();
break;
case 15620:
this.audioRefLevel = _bb.get();
break;
case 15621:
this.electroSpatialFormulation = _bb.get();
break;
case 15623:
this.channelCount = _bb.getInt();
break;
case 15617:
this.quantizationBits = _bb.getInt();
break;
case 15628:
this.dialNorm = _bb.get();
break;
case 15622:
this.soundEssenceCompression = UL.read(_bb);
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public Rational getAudioSamplingRate() {
return this.audioSamplingRate;
}
public byte getLocked() {
return this.locked;
}
public byte getAudioRefLevel() {
return this.audioRefLevel;
}
public byte getElectroSpatialFormulation() {
return this.electroSpatialFormulation;
}
public int getChannelCount() {
return this.channelCount;
}
public int getQuantizationBits() {
return this.quantizationBits;
}
public byte getDialNorm() {
return this.dialNorm;
}
public UL getSoundEssenceCompression() {
return this.soundEssenceCompression;
}
}

View file

@ -0,0 +1,61 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class GenericTrack extends MXFInterchangeObject {
private int trackId;
private String name;
private UL sequenceRef;
private int trackNumber;
public GenericTrack(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 18433:
this.trackId = _bb.getInt();
break;
case 18434:
this.name = readUtf16String(_bb);
break;
case 18435:
this.sequenceRef = UL.read(_bb);
break;
case 18436:
this.trackNumber = _bb.getInt();
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public int getTrackId() {
return this.trackId;
}
public String getName() {
return this.name;
}
public UL getSequenceRef() {
return this.sequenceRef;
}
public int getTrackNumber() {
return this.trackNumber;
}
}

View file

@ -0,0 +1,89 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class Identification extends MXFInterchangeObject {
private UL thisGenerationUID;
private String companyName;
private String productName;
private short versionString;
private UL productUID;
private Date modificationDate;
private String platform;
public Identification(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 15369:
this.thisGenerationUID = UL.read(_bb);
break;
case 15361:
this.companyName = readUtf16String(_bb);
break;
case 15362:
this.productName = readUtf16String(_bb);
break;
case 15364:
this.versionString = _bb.getShort();
break;
case 15365:
this.productUID = UL.read(_bb);
break;
case 15366:
this.modificationDate = readDate(_bb);
break;
case 15368:
this.platform = readUtf16String(_bb);
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public UL getThisGenerationUID() {
return this.thisGenerationUID;
}
public String getCompanyName() {
return this.companyName;
}
public String getProductName() {
return this.productName;
}
public short getVersionString() {
return this.versionString;
}
public UL getProductUID() {
return this.productUID;
}
public Date getModificationDate() {
return this.modificationDate;
}
public String getPlatform() {
return this.platform;
}
}

View file

@ -0,0 +1,65 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.jcodec.common.io.NIOUtils;
public class IndexEntries {
private byte[] displayOff;
private byte[] flags;
private long[] fileOff;
private byte[] keyFrameOff;
public IndexEntries(byte[] displayOff, byte[] keyFrameOff, byte[] flags, long[] fileOff) {
this.displayOff = displayOff;
this.keyFrameOff = keyFrameOff;
this.flags = flags;
this.fileOff = fileOff;
}
public byte[] getDisplayOff() {
return this.displayOff;
}
public byte[] getFlags() {
return this.flags;
}
public long[] getFileOff() {
return this.fileOff;
}
public byte[] getKeyFrameOff() {
return this.keyFrameOff;
}
public static IndexEntries read(ByteBuffer bb) {
bb.order(ByteOrder.BIG_ENDIAN);
int n = bb.getInt();
int len = bb.getInt();
int[] temporalOff = new int[n];
byte[] flags = new byte[n];
long[] fileOff = new long[n];
byte[] keyFrameOff = new byte[n];
for (int i = 0; i < n; i++) {
temporalOff[i] = i + bb.get();
keyFrameOff[i] = bb.get();
flags[i] = bb.get();
fileOff[i] = bb.getLong();
NIOUtils.skip(bb, len - 11);
}
byte[] displayOff = new byte[n];
for (int j = 0; j < n; j++) {
for (int k = 0; k < n; k++) {
if (temporalOff[k] == j) {
displayOff[j] = (byte)(k - j);
break;
}
}
}
return new IndexEntries(displayOff, keyFrameOff, flags, fileOff);
}
}

View file

@ -0,0 +1,131 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class IndexSegment extends MXFInterchangeObject {
private IndexEntries ie;
private int editUnitByteCount;
private DeltaEntries deltaEntries;
private int indexSID;
private int bodySID;
private int indexEditRateNum;
private int indexEditRateDen;
private long indexStartPosition;
private long indexDuration;
private UL instanceUID;
private int sliceCount;
private int posTableCount;
public IndexSegment(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 15370:
this.instanceUID = UL.read(_bb);
break;
case 16133:
this.editUnitByteCount = _bb.getInt();
break;
case 16134:
this.indexSID = _bb.getInt();
break;
case 16135:
this.bodySID = _bb.getInt();
break;
case 16136:
this.sliceCount = _bb.get() & 0xFF;
break;
case 16137:
this.deltaEntries = DeltaEntries.read(_bb);
break;
case 16138:
this.ie = IndexEntries.read(_bb);
break;
case 16139:
this.indexEditRateNum = _bb.getInt();
this.indexEditRateDen = _bb.getInt();
break;
case 16140:
this.indexStartPosition = _bb.getLong();
break;
case 16141:
this.indexDuration = _bb.getLong();
break;
case 16142:
this.posTableCount = _bb.get() & 0xFF;
break;
default:
Logger.warn(String.format("Unknown tag [" + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public IndexEntries getIe() {
return this.ie;
}
public int getEditUnitByteCount() {
return this.editUnitByteCount;
}
public DeltaEntries getDeltaEntries() {
return this.deltaEntries;
}
public int getIndexSID() {
return this.indexSID;
}
public int getBodySID() {
return this.bodySID;
}
public int getIndexEditRateNum() {
return this.indexEditRateNum;
}
public int getIndexEditRateDen() {
return this.indexEditRateDen;
}
public long getIndexStartPosition() {
return this.indexStartPosition;
}
public long getIndexDuration() {
return this.indexDuration;
}
public UL getInstanceUID() {
return this.instanceUID;
}
public int getSliceCount() {
return this.sliceCount;
}
public int getPosTableCount() {
return this.posTableCount;
}
}

View file

@ -0,0 +1,115 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class J2KPictureDescriptor extends MXFInterchangeObject {
private short rsiz;
private int xsiz;
private int ysiz;
private int xOsiz;
private int yOsiz;
private int xTsiz;
private int yTsiz;
private int xTOsiz;
private int yTOsiz;
private short csiz;
public J2KPictureDescriptor(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 24836:
this.rsiz = _bb.getShort();
break;
case 24837:
this.xsiz = _bb.getInt();
break;
case 24838:
this.ysiz = _bb.getInt();
break;
case 24839:
this.xOsiz = _bb.getInt();
break;
case 24840:
this.yOsiz = _bb.getInt();
break;
case 24841:
this.xTsiz = _bb.getInt();
break;
case 24842:
this.yTsiz = _bb.getInt();
break;
case 24843:
this.xTOsiz = _bb.getInt();
break;
case 24844:
this.yTOsiz = _bb.getInt();
break;
case 24845:
this.csiz = _bb.getShort();
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public short getRsiz() {
return this.rsiz;
}
public int getXsiz() {
return this.xsiz;
}
public int getYsiz() {
return this.ysiz;
}
public int getxOsiz() {
return this.xOsiz;
}
public int getyOsiz() {
return this.yOsiz;
}
public int getxTsiz() {
return this.xTsiz;
}
public int getyTsiz() {
return this.yTsiz;
}
public int getxTOsiz() {
return this.xTOsiz;
}
public int getyTOsiz() {
return this.yTOsiz;
}
public short getCsiz() {
return this.csiz;
}
}

View file

@ -0,0 +1,61 @@
package org.jcodec.containers.mxf.model;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.jcodec.common.io.SeekableByteChannel;
public class KLV {
public final long offset;
public final long dataOffset;
public final UL key;
public final long len;
ByteBuffer value;
public KLV(UL k, long len, long offset, long dataOffset) {
this.key = k;
this.len = len;
this.offset = offset;
this.dataOffset = dataOffset;
}
public String toString() {
return "KLV [offset=" + this.offset + ", dataOffset=" + this.dataOffset + ", key=" + String.valueOf(this.key) + ", len=" + this.len + ", value=" + String.valueOf(this.value) + "]";
}
public static KLV readKL(SeekableByteChannel ch) throws IOException {
long offset = ch.position();
if (offset >= ch.size() - 1L)
return null;
byte[] key = new byte[16];
ch.read(ByteBuffer.wrap(key));
long len = BER.decodeLength(ch);
long dataOffset = ch.position();
return new KLV(new UL(key), len, offset, dataOffset);
}
public int getLenByteCount() {
int berlen = (int)(this.dataOffset - this.offset - 16L);
return (berlen <= 0) ? 4 : berlen;
}
public static boolean matches(byte[] key1, byte[] key2, int len) {
for (int i = 0; i < len; i++) {
if (key1[i] != key2[i])
return false;
}
return true;
}
public static KLV readKLFromBuffer(ByteBuffer buffer, long baseOffset) {
if (buffer.remaining() < 17)
return null;
long offset = baseOffset + (long)buffer.position();
UL ul = UL.read(buffer);
long len = BER.decodeLengthBuf(buffer);
return new KLV(ul, len, offset, baseOffset + (long)buffer.position());
}
}

View file

@ -0,0 +1,116 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class MPEG2VideoDescriptor extends CDCIEssenceDescriptor {
private byte singleSequence;
private byte constantBFrames;
private byte codedContentType;
private byte lowDelay;
private byte closedGOP;
private byte identicalGOP;
private short maxGOP;
private short bPictureCount;
private int bitRate;
private byte profileAndLevel;
public MPEG2VideoDescriptor(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
super.read(tags);
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 32768:
this.singleSequence = _bb.get();
break;
case 32769:
this.constantBFrames = _bb.get();
break;
case 32770:
this.codedContentType = _bb.get();
break;
case 32771:
this.lowDelay = _bb.get();
break;
case 32772:
this.closedGOP = _bb.get();
break;
case 32773:
this.identicalGOP = _bb.get();
break;
case 32774:
this.maxGOP = _bb.getShort();
break;
case 32775:
this.bPictureCount = (short)(_bb.get() & 0xFF);
break;
case 32776:
this.bitRate = _bb.getInt();
break;
case 32777:
this.profileAndLevel = _bb.get();
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x + (" + _bb.remaining() + ")", entry.getKey()));
continue;
}
it.remove();
}
}
public byte getSingleSequence() {
return this.singleSequence;
}
public byte getConstantBFrames() {
return this.constantBFrames;
}
public byte getCodedContentType() {
return this.codedContentType;
}
public byte getLowDelay() {
return this.lowDelay;
}
public byte getClosedGOP() {
return this.closedGOP;
}
public byte getIdenticalGOP() {
return this.identicalGOP;
}
public short getMaxGOP() {
return this.maxGOP;
}
public short getbPictureCount() {
return this.bPictureCount;
}
public int getBitRate() {
return this.bitRate;
}
public byte getProfileAndLevel() {
return this.profileAndLevel;
}
}

View file

@ -0,0 +1,51 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashMap;
import java.util.Map;
import org.jcodec.common.io.NIOUtils;
public abstract class MXFInterchangeObject extends MXFMetadata {
private UL generationUID;
private UL objectClass;
public MXFInterchangeObject(UL ul) {
super(ul);
}
public void readBuf(ByteBuffer bb) {
bb.order(ByteOrder.BIG_ENDIAN);
Map<Integer, ByteBuffer> tags = new HashMap<>();
while (bb.hasRemaining()) {
int tag = bb.getShort() & 0xFFFF;
int size = bb.getShort() & 0xFFFF;
ByteBuffer _bb = NIOUtils.read(bb, size);
switch (tag) {
case 15370:
this.uid = UL.read(_bb);
continue;
case 258:
this.generationUID = UL.read(_bb);
continue;
case 257:
this.objectClass = UL.read(_bb);
continue;
}
tags.put(Integer.valueOf(tag), _bb);
}
if (tags.size() > 0)
read(tags);
}
protected abstract void read(Map<Integer, ByteBuffer> paramMap);
public UL getGenerationUID() {
return this.generationUID;
}
public UL getObjectClass() {
return this.objectClass;
}
}

View file

@ -0,0 +1,67 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Calendar;
import java.util.Date;
import org.jcodec.common.io.NIOUtils;
import org.jcodec.platform.Platform;
public abstract class MXFMetadata {
protected UL ul;
protected UL uid;
public MXFMetadata(UL ul) {
this.ul = ul;
}
public abstract void readBuf(ByteBuffer paramByteBuffer);
protected static UL[] readULBatch(ByteBuffer _bb) {
int count = _bb.getInt();
_bb.getInt();
UL[] result = new UL[count];
for (int i = 0; i < count; i++)
result[i] = UL.read(_bb);
return result;
}
protected static int[] readInt32Batch(ByteBuffer _bb) {
int count = _bb.getInt();
_bb.getInt();
int[] result = new int[count];
for (int i = 0; i < count; i++)
result[i] = _bb.getInt();
return result;
}
protected static Date readDate(ByteBuffer _bb) {
Calendar calendar = Calendar.getInstance();
calendar.set(1, _bb.getShort());
calendar.set(2, _bb.get());
calendar.set(5, _bb.get());
calendar.set(10, _bb.get());
calendar.set(12, _bb.get());
calendar.set(13, _bb.get());
calendar.set(14, (_bb.get() & 0xFF) << 2);
return calendar.getTime();
}
protected String readUtf16String(ByteBuffer _bb) {
byte[] array;
if (_bb.getShort(_bb.limit() - 2) != 0) {
array = NIOUtils.toArray(_bb);
} else {
array = NIOUtils.toArray(_bb.limit(_bb.limit() - 2));
}
return Platform.stringFromCharset(array, "UTF-16");
}
public UL getUl() {
return this.ul;
}
public UL getUid() {
return this.uid;
}
}

View file

@ -0,0 +1,59 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
public class MXFPartition {
private MXFPartitionPack pack;
private long essenceFilePos;
private boolean closed;
private boolean complete;
private long essenceLength;
public MXFPartition(MXFPartitionPack pack, long essenceFilePos, boolean closed, boolean complete, long essenceLength) {
this.pack = pack;
this.essenceFilePos = essenceFilePos;
this.closed = closed;
this.complete = complete;
this.essenceLength = essenceLength;
}
public static MXFPartition read(UL ul, ByteBuffer bb, long packSize, long nextPartition) {
boolean closed = ((ul.get(14) & 0x1) == 0);
boolean complete = (ul.get(14) > 2);
MXFPartitionPack pp = new MXFPartitionPack(ul);
pp.readBuf(bb);
long essenceFilePos = roundToKag(pp.getThisPartition() + packSize, pp.getKagSize()) +
roundToKag(pp.getHeaderByteCount(), pp.getKagSize()) +
roundToKag(pp.getIndexByteCount(), pp.getKagSize());
return new MXFPartition(pp, essenceFilePos, closed, complete, nextPartition - essenceFilePos);
}
static long roundToKag(long position, int kag_size) {
long ret = position / (long)kag_size * (long)kag_size;
return (ret == position) ? ret : (ret + (long)kag_size);
}
public MXFPartitionPack getPack() {
return this.pack;
}
public long getEssenceFilePos() {
return this.essenceFilePos;
}
public boolean isClosed() {
return this.closed;
}
public boolean isComplete() {
return this.complete;
}
public long getEssenceLength() {
return this.essenceLength;
}
}

View file

@ -0,0 +1,87 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.jcodec.common.io.NIOUtils;
public class MXFPartitionPack extends MXFMetadata {
private int kagSize;
private long thisPartition;
private long prevPartition;
private long footerPartition;
private long headerByteCount;
private long indexByteCount;
private int indexSid;
private int bodySid;
private UL op;
private int nbEssenceContainers;
public MXFPartitionPack(UL ul) {
super(ul);
}
public void readBuf(ByteBuffer bb) {
bb.order(ByteOrder.BIG_ENDIAN);
NIOUtils.skip(bb, 4);
this.kagSize = bb.getInt();
this.thisPartition = bb.getLong();
this.prevPartition = bb.getLong();
this.footerPartition = bb.getLong();
this.headerByteCount = bb.getLong();
this.indexByteCount = bb.getLong();
this.indexSid = bb.getInt();
NIOUtils.skip(bb, 8);
this.bodySid = bb.getInt();
this.op = UL.read(bb);
this.nbEssenceContainers = bb.getInt();
}
public int getKagSize() {
return this.kagSize;
}
public long getThisPartition() {
return this.thisPartition;
}
public long getPrevPartition() {
return this.prevPartition;
}
public long getFooterPartition() {
return this.footerPartition;
}
public long getHeaderByteCount() {
return this.headerByteCount;
}
public long getIndexByteCount() {
return this.indexByteCount;
}
public int getIndexSid() {
return this.indexSid;
}
public int getBodySid() {
return this.bodySid;
}
public UL getOp() {
return this.op;
}
public int getNbEssenceContainers() {
return this.nbEssenceContainers;
}
}

View file

@ -0,0 +1,42 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class MXFStructuralComponent extends MXFInterchangeObject {
private long duration;
private UL dataDefinitionUL;
public MXFStructuralComponent(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
switch ((Integer)entry.getKey()) {
case 514:
this.duration = entry.getValue().getLong();
break;
case 513:
this.dataDefinitionUL = UL.read(entry.getValue());
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public long getDuration() {
return this.duration;
}
public UL getDataDefinitionUL() {
return this.dataDefinitionUL;
}
}

View file

@ -0,0 +1,48 @@
package org.jcodec.containers.mxf.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.jcodec.platform.Platform;
public class MXFUtil {
public static <T> T resolveRef(List<MXFMetadata> metadata, UL refs, Class<T> class1) {
List<T> res = resolveRefs(metadata, new UL[] { refs }, class1);
return (res.size() > 0) ? res.get(0) : null;
}
public static <T> List<T> resolveRefs(List<MXFMetadata> metadata, UL[] refs, Class<T> class1) {
List<MXFMetadata> copy = new ArrayList<>(metadata);
for (Iterator<MXFMetadata> iterator = copy.iterator(); iterator.hasNext(); ) {
MXFMetadata next = iterator.next();
if (next.getUid() == null || !Platform.isAssignableFrom(class1, next.getClass()))
iterator.remove();
}
List<MXFMetadata> result = new ArrayList();
for (int i = 0; i < refs.length; i++) {
for (MXFMetadata meta : copy) {
if (meta.getUid().equals(refs[i]))
result.add(meta);
}
}
return (List<T>)result;
}
public static <T> T findMeta(Collection<MXFMetadata> metadata, Class<T> class1) {
for (MXFMetadata mxfMetadata : metadata) {
if (Platform.isAssignableFrom(mxfMetadata.getClass(), class1))
return (T)mxfMetadata;
}
return null;
}
public static <T> List<T> findAllMeta(Collection<MXFMetadata> metadata, Class<T> class1) {
List<MXFMetadata> result = new ArrayList();
for (MXFMetadata mxfMetadata : metadata) {
if (Platform.isAssignableFrom(class1, mxfMetadata.getClass()))
result.add(mxfMetadata);
}
return (List<T>)result;
}
}

View file

@ -0,0 +1,7 @@
package org.jcodec.containers.mxf.model;
public class MaterialPackage extends GenericPackage {
public MaterialPackage(UL ul) {
super(ul);
}
}

View file

@ -0,0 +1,71 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class Preface extends MXFInterchangeObject {
private Date lastModifiedDate;
private int objectModelVersion;
private UL op;
private UL[] essenceContainers;
private UL[] dmSchemes;
public Preface(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 15106:
this.lastModifiedDate = readDate(_bb);
break;
case 15111:
this.objectModelVersion = _bb.getInt();
break;
case 15113:
this.op = UL.read(_bb);
break;
case 15114:
this.essenceContainers = readULBatch(_bb);
break;
case 15115:
this.dmSchemes = readULBatch(_bb);
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public Date getLastModifiedDate() {
return this.lastModifiedDate;
}
public int getObjectModelVersion() {
return this.objectModelVersion;
}
public UL getOp() {
return this.op;
}
public UL[] getEssenceContainers() {
return this.essenceContainers;
}
public UL[] getDmSchemes() {
return this.dmSchemes;
}
}

View file

@ -0,0 +1,99 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class RGBAEssenceDescriptor extends GenericPictureEssenceDescriptor {
private int componentMaxRef;
private int componentMinRef;
private int alphaMaxRef;
private int alphaMinRef;
private byte scanningDirection;
private ByteBuffer pixelLayout;
private ByteBuffer palette;
private ByteBuffer paletteLayout;
public RGBAEssenceDescriptor(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
super.read(tags);
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 13318:
this.componentMaxRef = _bb.getInt();
break;
case 13319:
this.componentMinRef = _bb.getInt();
break;
case 13320:
this.alphaMaxRef = _bb.getInt();
break;
case 13321:
this.alphaMinRef = _bb.getInt();
break;
case 13317:
this.scanningDirection = _bb.get();
break;
case 13313:
this.pixelLayout = _bb;
break;
case 13315:
this.palette = _bb;
break;
case 13316:
this.paletteLayout = _bb;
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x",
entry.getKey()));
continue;
}
it.remove();
}
}
public int getComponentMaxRef() {
return this.componentMaxRef;
}
public int getComponentMinRef() {
return this.componentMinRef;
}
public int getAlphaMaxRef() {
return this.alphaMaxRef;
}
public int getAlphaMinRef() {
return this.alphaMinRef;
}
public byte getScanningDirection() {
return this.scanningDirection;
}
public ByteBuffer getPixelLayout() {
return this.pixelLayout;
}
public ByteBuffer getPalette() {
return this.palette;
}
public ByteBuffer getPaletteLayout() {
return this.paletteLayout;
}
}

View file

@ -0,0 +1,34 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class Sequence extends MXFStructuralComponent {
private UL[] structuralComponentsRefs;
public Sequence(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
super.read(tags);
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
switch ((Integer)entry.getKey()) {
case 4097:
this.structuralComponentsRefs = readULBatch(entry.getValue());
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public UL[] getStructuralComponentsRefs() {
return this.structuralComponentsRefs;
}
}

View file

@ -0,0 +1,53 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class SourceClip extends MXFStructuralComponent {
private long startPosition;
private int sourceTrackId;
private UL sourcePackageUid;
public SourceClip(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
super.read(tags);
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 4609:
this.startPosition = _bb.getLong();
break;
case 4353:
this.sourcePackageUid = UL.read(_bb);
break;
case 4354:
this.sourceTrackId = _bb.getInt();
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public UL getSourcePackageUid() {
return this.sourcePackageUid;
}
public long getStartPosition() {
return this.startPosition;
}
public int getSourceTrackId() {
return this.sourceTrackId;
}
}

View file

@ -0,0 +1,41 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class SourcePackage extends GenericPackage {
private UL[] trackRefs;
private UL descriptorRef;
public SourcePackage(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
super.read(tags);
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 18177:
this.descriptorRef = UL.read(_bb);
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public UL[] getTrackRefs() {
return this.trackRefs;
}
public UL getDescriptorRef() {
return this.descriptorRef;
}
}

View file

@ -0,0 +1,53 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
public class TimecodeComponent extends MXFStructuralComponent {
private long start;
private int base;
private int dropFrame;
public TimecodeComponent(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
super.read(tags);
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 5377:
this.start = _bb.getLong();
break;
case 5378:
this.base = _bb.getShort();
break;
case 5379:
this.dropFrame = _bb.get();
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public long getStart() {
return this.start;
}
public int getBase() {
return this.base;
}
public int getDropFrame() {
return this.dropFrame;
}
}

View file

@ -0,0 +1,45 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
import org.jcodec.common.logging.Logger;
import org.jcodec.common.model.Rational;
public class TimelineTrack extends GenericTrack {
private Rational editRate;
private long origin;
public TimelineTrack(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
super.read(tags);
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 19201:
this.editRate = new Rational(_bb.getInt(), _bb.getInt());
break;
case 19202:
this.origin = _bb.getLong();
break;
default:
Logger.warn(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public Rational getEditRate() {
return this.editRate;
}
public long getOrigin() {
return this.origin;
}
}

View file

@ -0,0 +1,90 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import org.jcodec.common.Preconditions;
import org.jcodec.common.StringUtils;
import org.jcodec.platform.Platform;
public class UL {
private final byte[] bytes;
public UL(byte[] bytes) {
Preconditions.checkNotNull(bytes);
this.bytes = bytes;
}
public static UL newULFromInts(int[] args) {
byte[] bytes = new byte[args.length];
for (int i = 0; i < args.length; i++)
bytes[i] = (byte)args[i];
return new UL(bytes);
}
public static UL newUL(String ul) {
Preconditions.checkNotNull(ul);
String[] split = StringUtils.splitS(ul, ".");
byte[] b = new byte[split.length];
for (int i = 0; i < split.length; i++) {
int parseInt = Integer.parseInt(split[i], 16);
b[i] = (byte)parseInt;
}
return new UL(b);
}
public int hashCode() {
return (this.bytes[4] & 0xFF) << 24 | (this.bytes[5] & 0xFF) << 16 | (this.bytes[6] & 0xFF) << 8 | this.bytes[7] & 0xFF;
}
public boolean equals(Object obj) {
if (!(obj instanceof UL))
return false;
byte[] other = ((UL)obj).bytes;
for (int i = 4; i < Math.min(this.bytes.length, other.length); i++) {
if (this.bytes[i] != other[i])
return false;
}
return true;
}
public boolean maskEquals(UL o, int mask) {
if (o == null)
return false;
byte[] other = o.bytes;
mask >>= 4;
for (int i = 4; i < Math.min(this.bytes.length, other.length); i++, mask >>= 1) {
if ((mask & 0x1) == 1 && this.bytes[i] != other[i])
return false;
}
return true;
}
private static final char[] hex = new char[] {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F' };
public String toString() {
if (this.bytes.length == 0)
return "";
char[] str = new char[this.bytes.length * 3 - 1];
int i = 0;
int j = 0;
for (i = 0; i < this.bytes.length - 1; i++) {
str[j++] = hex[this.bytes[i] >> 4 & 0xF];
str[j++] = hex[this.bytes[i] & 0xF];
str[j++] = '.';
}
str[j++] = hex[this.bytes[i] >> 4 & 0xF];
str[j++] = hex[this.bytes[i] & 0xF];
return Platform.stringFromChars(str);
}
public int get(int i) {
return this.bytes[i];
}
public static UL read(ByteBuffer _bb) {
byte[] umid = new byte[16];
_bb.get(umid);
return new UL(umid);
}
}

View file

@ -0,0 +1,142 @@
package org.jcodec.containers.mxf.model;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Map;
public class WaveAudioDescriptor extends GenericSoundEssenceDescriptor {
private short blockAlign;
private byte sequenceOffset;
private int avgBps;
private UL channelAssignment;
private int peakEnvelopeVersion;
private int peakEnvelopeFormat;
private int pointsPerPeakValue;
private int peakEnvelopeBlockSize;
private int peakChannels;
private int peakFrames;
private ByteBuffer peakOfPeaksPosition;
private ByteBuffer peakEnvelopeTimestamp;
private ByteBuffer peakEnvelopeData;
public WaveAudioDescriptor(UL ul) {
super(ul);
}
protected void read(Map<Integer, ByteBuffer> tags) {
super.read(tags);
for (Iterator<Map.Entry<Integer, ByteBuffer>> it = tags.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Integer, ByteBuffer> entry = it.next();
ByteBuffer _bb = entry.getValue();
switch ((Integer)entry.getKey()) {
case 15626:
this.blockAlign = _bb.getShort();
break;
case 15627:
this.sequenceOffset = _bb.get();
break;
case 15625:
this.avgBps = _bb.getInt();
break;
case 15666:
this.channelAssignment = UL.read(_bb);
break;
case 15657:
this.peakEnvelopeVersion = _bb.getInt();
break;
case 15658:
this.peakEnvelopeFormat = _bb.getInt();
break;
case 15659:
this.pointsPerPeakValue = _bb.getInt();
break;
case 15660:
this.peakEnvelopeBlockSize = _bb.getInt();
break;
case 15661:
this.peakChannels = _bb.getInt();
break;
case 15662:
this.peakFrames = _bb.getInt();
break;
case 15663:
this.peakOfPeaksPosition = _bb;
break;
case 15664:
this.peakEnvelopeTimestamp = _bb;
break;
case 15665:
this.peakEnvelopeData = _bb;
break;
default:
System.out.println(String.format("Unknown tag [ " + String.valueOf(this.ul) + "]: %04x", entry.getKey()));
continue;
}
it.remove();
}
}
public short getBlockAlign() {
return this.blockAlign;
}
public byte getSequenceOffset() {
return this.sequenceOffset;
}
public int getAvgBps() {
return this.avgBps;
}
public UL getChannelAssignment() {
return this.channelAssignment;
}
public int getPeakEnvelopeVersion() {
return this.peakEnvelopeVersion;
}
public int getPeakEnvelopeFormat() {
return this.peakEnvelopeFormat;
}
public int getPointsPerPeakValue() {
return this.pointsPerPeakValue;
}
public int getPeakEnvelopeBlockSize() {
return this.peakEnvelopeBlockSize;
}
public int getPeakChannels() {
return this.peakChannels;
}
public int getPeakFrames() {
return this.peakFrames;
}
public ByteBuffer getPeakOfPeaksPosition() {
return this.peakOfPeaksPosition;
}
public ByteBuffer getPeakEnvelopeTimestamp() {
return this.peakEnvelopeTimestamp;
}
public ByteBuffer getPeakEnvelopeData() {
return this.peakEnvelopeData;
}
}