Commit b44cd580 authored by Dele Olajide's avatar Dele Olajide

Jitsi Videobridge: Video recording re-write. Now using libwebm. Only working...

Jitsi Videobridge: Video recording re-write. Now using libwebm. Only working in Windows for now. TODO - generate linux binaries
parent 5fc6ca89
// Copyright 2012 Google Inc. All Rights Reserved.
// Author: frkoenig@google.com (Fritz Koenig)
package com.google.libvpx;
/**
* Common parts of the codec that are shared by
* the encoder and decoder.
*/
public class LibVpxCom {
static {
System.loadLibrary("vpx");
System.loadLibrary("vpxJNI");
}
protected long vpxCodecIface;
protected native String vpxCodecVersionStr();
protected native String vpxCodecVersionExtraStr();
protected native String vpxCodecBuildConfig();
protected native boolean vpxCodecIsError(long ctx);
protected native String vpxCodecErrToString(int err);
protected native String vpxCodecError(long ctx);
protected native String vpxCodecErrorDetail(long ctx);
protected native long vpxCodecAllocCodec();
protected native void vpxCodecFreeCodec(long cfg);
protected native void vpxCodecDestroy(long ctx);
public String versionString() {
return vpxCodecVersionStr();
}
public String versionExtraString() {
return vpxCodecVersionExtraStr();
}
public String buildConfigString() {
return vpxCodecBuildConfig();
}
public String errToString(int err) {
return vpxCodecErrToString(err);
}
public String errorString() {
return vpxCodecError(vpxCodecIface);
}
public String errorDetailString() {
return vpxCodecErrorDetail(vpxCodecIface);
}
}
\ No newline at end of file
// Copyright 2012 Google Inc. All Rights Reserved.
// Author: frkoenig@google.com (Fritz Koenig)
package com.google.libvpx;
/**
* libvpx JNI wrapper for decoding functions.
*/
public class LibVpxDec extends LibVpxCom {
private long decCfgObj;
private native long vpxCodecDecAllocCfg();
private native void vpxCodecDecFreeCfg(long cfg);
private native void vpxCodecDecSetThreads(long cfg, int value);
private native void vpxCodecDecSetWidth(long cfg, int value);
private native void vpxCodecDecSetHeight(long cfg, int value);
private native int vpxCodecDecGetThreads(long cfg);
private native int vpxCodecDecGetWidth(long cfg);
private native int vpxCodecDecGetHeight(long cfg);
private native boolean vpxCodecDecInit(long decoder, long cfg,
boolean postproc, boolean ecEnabled);
private native int vpxCodecDecDecode(long decoder, byte[] buf, int bufSize);
private native byte[] vpxCodecDecGetFrame(long decoder);
public LibVpxDec(int width, int height,
int threads,
boolean postProcEnabled,
boolean errorConcealmentEnabled) throws LibVpxException {
decCfgObj = vpxCodecDecAllocCfg();
vpxCodecIface = vpxCodecAllocCodec();
if (width > 0) {
vpxCodecDecSetWidth(decCfgObj, width);
}
if (height > 0) {
vpxCodecDecSetHeight(decCfgObj, height);
}
if (threads > 0) {
vpxCodecDecSetThreads(decCfgObj, threads);
}
if (!vpxCodecDecInit(vpxCodecIface, decCfgObj,
postProcEnabled, errorConcealmentEnabled)) {
throw new LibVpxException(vpxCodecError(vpxCodecIface));
}
}
public LibVpxDec(boolean postProcEnabled,
boolean errorConcealmentEnabled) throws LibVpxException {
this(0, 0, 0, postProcEnabled, errorConcealmentEnabled);
}
public LibVpxDec() throws LibVpxException {
this(0, 0, 0, false, false);
}
public byte[] decodeFrameToBuffer(byte[] rawFrame) throws LibVpxException {
if (vpxCodecDecDecode(vpxCodecIface, rawFrame, rawFrame.length) != 0) {
throw new LibVpxException(vpxCodecErrorDetail(vpxCodecIface));
}
return vpxCodecDecGetFrame(vpxCodecIface);
}
public void close() {
vpxCodecDestroy(vpxCodecIface);
vpxCodecDecFreeCfg(decCfgObj);
vpxCodecFreeCodec(vpxCodecIface);
}
}
// Copyright 2012 Google Inc. All Rights Reserved.
// Author: frkoenig@google.com (Fritz Koenig)
package com.google.libvpx;
import java.util.ArrayList;
/**
* libvpx JNI wrapper for encoding functions.
*/
public class LibVpxEnc extends LibVpxCom {
// Enums from libyuv.
public static final long FOURCC_I420 = 0x30323449;
public static final long FOURCC_I422 = 0x32323449;
public static final long FOURCC_NV21 = 0x3132564E;
public static final long FOURCC_NV12 = 0x3231564E;
public static final long FOURCC_YUY2 = 0x32595559;
public static final long FOURCC_UYVY = 0x56595559;
public static final long FOURCC_ARGB = 0x42475241;
public static final long FOURCC_BGRA = 0x41524742;
public static final long FOURCC_ABGR = 0x52474241;
public static final long FOURCC_24BG = 0x47423432; // rgb888
public static final long FOURCC_RGBA = 0x41424752;
public static final long FOURCC_RGBP = 0x50424752; // bgr565.
public static final long FOURCC_RGBO = 0x4F424752; // abgr1555.
public static final long FOURCC_R444 = 0x34343452; // argb4444.
public static final long FOURCC_YV12 = 0x32315659;
public static final long FOURCC_YV16 = 0x36315659;
// Enums from libvpx.
public static final int VPX_IMG_FMT_YV12 = 0x301;
public static final int VPX_IMG_FMT_I420 = 0x102;
private native void vpxCodecEncInit(long encoder, long cfg);
private native int vpxCodecEncCtlSetCpuUsed(long ctx, int value);
private native int vpxCodecEncCtlSetEnableAutoAltRef(long ctx, int value);
private native int vpxCodecEncCtlSetNoiseSensitivity(long ctx, int value);
private native int vpxCodecEncCtlSetSharpness(long ctx, int value);
private native int vpxCodecEncCtlSetStaticThreshold(long ctx, int value);
private native int vpxCodecEncCtlSetTokenPartitions(long ctx, int value);
private native int vpxCodecEncCtlSetARNRMaxFrames(long ctx, int value);
private native int vpxCodecEncCtlSetARNRStrength(long ctx, int value);
private native int vpxCodecEncCtlSetARNRType(long ctx, int value);
private native int vpxCodecEncCtlSetTuning(long ctx, int value);
private native int vpxCodecEncCtlSetCQLevel(long ctx, int value);
private native int vpxCodecEncCtlSetMaxIntraBitratePct(long ctx, int value);
private native boolean vpxCodecEncode(long ctx, byte[] frame,
int fmt, long pts, long duration,
long flags, long deadline);
private native boolean vpxCodecConvertByteEncode(long ctx, byte[] frame,
long pts, long duration,
long flags, long deadline,
long fourcc, int size);
private native boolean vpxCodecConvertIntEncode(long ctx, int[] frame,
long pts, long duration,
long flags, long deadline,
long fourcc, int size);
private static native boolean vpxCodecHaveLibyuv();
private native ArrayList<VpxCodecCxPkt> vpxCodecEncGetCxData(long ctx);
public LibVpxEnc(LibVpxEncConfig cfg) throws LibVpxException {
vpxCodecIface = vpxCodecAllocCodec();
if (vpxCodecIface == 0) {
throw new LibVpxException("Can not allocate JNI codec object");
}
vpxCodecEncInit(vpxCodecIface, cfg.handle());
if (isError()) {
String errorMsg = vpxCodecErrorDetail(vpxCodecIface);
vpxCodecFreeCodec(vpxCodecIface);
throw new LibVpxException(errorMsg);
}
}
public boolean isError() {
return vpxCodecIsError(vpxCodecIface);
}
private void throwOnError() throws LibVpxException {
if (vpxCodecIsError(vpxCodecIface)) {
throw new LibVpxException(vpxCodecErrorDetail(vpxCodecIface));
}
}
public ArrayList<VpxCodecCxPkt> encodeFrame(byte[] frame, int fmt, long frameStart, long frameDuration)
throws LibVpxException {
if (!vpxCodecEncode(vpxCodecIface, frame, fmt, frameStart, frameDuration, 0L, 0L)) {
throw new LibVpxException("Unable to encode frame");
}
throwOnError();
return vpxCodecEncGetCxData(vpxCodecIface);
}
public ArrayList<VpxCodecCxPkt> convertByteEncodeFrame(
byte[] frame, long frameStart, long frameDuration, long fourcc) throws LibVpxException {
if (!vpxCodecConvertByteEncode(vpxCodecIface,
frame, frameStart, frameDuration, 0L, 0L, fourcc, frame.length)) {
throw new LibVpxException("Unable to convert and encode frame");
}
throwOnError();
return vpxCodecEncGetCxData(vpxCodecIface);
}
public ArrayList<VpxCodecCxPkt> convertIntEncodeFrame(
int[] frame, long frameStart, long frameDuration, long fourcc) throws LibVpxException {
if (!vpxCodecConvertIntEncode(vpxCodecIface,
frame, frameStart, frameDuration, 0L, 0L, fourcc, frame.length)) {
throw new LibVpxException("Unable to convert and encode frame");
}
throwOnError();
return vpxCodecEncGetCxData(vpxCodecIface);
}
public static boolean haveLibyuv() {
return vpxCodecHaveLibyuv();
}
public void close() {
vpxCodecDestroy(vpxCodecIface);
vpxCodecFreeCodec(vpxCodecIface);
}
public void setCpuUsed(int value) throws LibVpxException {
// TODO(frkoenig) : Investigate anonymous interface class to reduce duplication
if (vpxCodecEncCtlSetCpuUsed(vpxCodecIface, value) != 0) {
throw new LibVpxException("Unable to set CpuUsed");
}
throwOnError();
}
public void setEnableAutoAltRef(int value) throws LibVpxException {
if (vpxCodecEncCtlSetEnableAutoAltRef(vpxCodecIface, value) != 0) {
throw new LibVpxException("Unable to Enable Auto Alt Ref");
}
throwOnError();
}
public void setNoiseSensitivity(int value) throws LibVpxException {
if (vpxCodecEncCtlSetNoiseSensitivity(vpxCodecIface, value) != 0) {
throw new LibVpxException("Unable to set Noise Sensitivity");
}
throwOnError();
}
public void setSharpness(int value) throws LibVpxException {
if (vpxCodecEncCtlSetSharpness(vpxCodecIface, value) != 0) {
throw new LibVpxException("Unable to set Sharpness");
}
throwOnError();
}
public void setStaticThreshold(int value) throws LibVpxException {
if (vpxCodecEncCtlSetStaticThreshold(vpxCodecIface, value) != 0) {
throw new LibVpxException("Unable to set Static Threshold");
}
throwOnError();
}
public void setTokenPartitions(int value) throws LibVpxException {
if (vpxCodecEncCtlSetTokenPartitions(vpxCodecIface, value) != 0) {
throw new LibVpxException("Unable to set Token Partitions");
}
throwOnError();
}
public void setARNRMaxFrames(int value) throws LibVpxException {
if (vpxCodecEncCtlSetARNRMaxFrames(vpxCodecIface, value) != 0) {
throw new LibVpxException("Unable to set ARNR Max Frames");
}
throwOnError();
}
public void setARNRStrength(int value) throws LibVpxException {
if (vpxCodecEncCtlSetARNRStrength(vpxCodecIface, value) != 0) {
throw new LibVpxException("Unable to set ARNR Strength");
}
throwOnError();
}
public void setARNRType(int value) throws LibVpxException {
if (vpxCodecEncCtlSetARNRType(vpxCodecIface, value) != 0) {
throw new LibVpxException("Unable to set ARNRType");
}
throwOnError();
}
public void setTuning(int value) throws LibVpxException {
if (vpxCodecEncCtlSetTuning(vpxCodecIface, value) != 0) {
throw new LibVpxException("Unable to set Tuning");
}
throwOnError();
}
public void setCQLevel(int value) throws LibVpxException {
if (vpxCodecEncCtlSetCQLevel(vpxCodecIface, value) != 0) {
throw new LibVpxException("Unable to set CQLevel");
}
throwOnError();
}
public void setMaxIntraBitratePct(int value) throws LibVpxException {
if (vpxCodecEncCtlSetMaxIntraBitratePct(vpxCodecIface, value) != 0) {
throw new LibVpxException("Unable to set Max Intra Bitrate Pct");
}
throwOnError();
}
}
// Copyright 2012 Google Inc. All Rights Reserved.
// Author: frkoenig@google.com (Fritz Koenig)
package com.google.libvpx;
/**
* JNI interface to C struct used for configuring
* the libvpx encoder.
*/
public class LibVpxEncConfig extends LibVpxCom {
private long encCfgObj;
private native long vpxCodecEncAllocCfg();
private native void vpxCodecEncFreeCfg(long cfg);
private native int vpxCodecEncConfigDefault(long cfg, int argUsage);
private native void vpxCodecEncSetUsage(long cfg, int value);
private native void vpxCodecEncSetThreads(long cfg, int value);
private native void vpxCodecEncSetProfile(long cfg, int value);
private native void vpxCodecEncSetWidth(long cfg, int value);
private native void vpxCodecEncSetHeight(long cfg, int value);
private native void vpxCodecEncSetTimebase(long cfg, int num, int den);
private native void vpxCodecEncSetErrorResilient(long cfg, int value);
private native void vpxCodecEncSetPass(long cfg, int value);
private native void vpxCodecEncSetLagInFrames(long cfg, int value);
private native void vpxCodecEncSetRCDropframeThresh(long cfg, int value);
private native void vpxCodecEncSetRCResizeAllowed(long cfg, int value);
private native void vpxCodecEncSetRCResizeUpThresh(long cfg, int value);
private native void vpxCodecEncSetRCResizeDownThresh(long cfg, int value);
private native void vpxCodecEncSetRCEndUsage(long cfg, int value);
private native void vpxCodecEncSetRCTargetBitrate(long cfg, int value);
private native void vpxCodecEncSetRCMinQuantizer(long cfg, int value);
private native void vpxCodecEncSetRCMaxQuantizer(long cfg, int value);
private native void vpxCodecEncSetRCUndershootPct(long cfg, int value);
private native void vpxCodecEncSetRCOvershootPct(long cfg, int value);
private native void vpxCodecEncSetRCBufSz(long cfg, int value);
private native void vpxCodecEncSetRCBufInitialSz(long cfg, int value);
private native void vpxCodecEncSetRCBufOptimalSz(long cfg, int value);
private native void vpxCodecEncSetRC2PassVBRBiasPct(long cfg, int value);
private native void vpxCodecEncSetRC2PassVBRMinsectionPct(long cfg, int value);
private native void vpxCodecEncSetRC2PassVBRMaxsectioniasPct(long cfg, int value);
private native void vpxCodecEncSetKFMode(long cfg, int value);
private native void vpxCodecEncSetKFMinDist(long cfg, int value);
private native void vpxCodecEncSetKFMaxDist(long cfg, int value);
private native int vpxCodecEncGetUsage(long cfg);
private native int vpxCodecEncGetThreads(long cfg);
private native int vpxCodecEncGetProfile(long cfg);
private native int vpxCodecEncGetWidth(long cfg);
private native int vpxCodecEncGetHeight(long cfg);
private native Rational vpxCodecEncGetTimebase(long cfg);
private native int vpxCodecEncGetErrorResilient(long cfg);
private native int vpxCodecEncGetPass(long cfg);
private native int vpxCodecEncGetLagInFrames(long cfg);
private native int vpxCodecEncGetRCDropframeThresh(long cfg);
private native int vpxCodecEncGetRCResizeAllowed(long cfg);
private native int vpxCodecEncGetRCResizeUpThresh(long cfg);
private native int vpxCodecEncGetRCResizeDownThresh(long cfg);
private native int vpxCodecEncGetRCEndUsage(long cfg);
private native int vpxCodecEncGetRCTargetBitrate(long cfg);
private native int vpxCodecEncGetRCMinQuantizer(long cfg);
private native int vpxCodecEncGetRCMaxQuantizer(long cfg);
private native int vpxCodecEncGetRCUndershootPct(long cfg);
private native int vpxCodecEncGetRCOvershootPct(long cfg);
private native int vpxCodecEncGetRCBufSz(long cfg);
private native int vpxCodecEncGetRCBufInitialSz(long cfg);
private native int vpxCodecEncGetRCBufOptimalSz(long cfg);
private native int vpxCodecEncGetRC2PassVBRBiasPct(long cfg);
private native int vpxCodecEncGetRC2PassVBRMinsectionPct(long cfg);
private native int vpxCodecEncGetRC2PassVBRMaxsectioniasPct(long cfg);
private native int vpxCodecEncGetKFMode(long cfg);
private native int vpxCodecEncGetKFMinDist(long cfg);
private native int vpxCodecEncGetKFMaxDist(long cfg);
private native int vpxCodecEncGetFourcc();
public LibVpxEncConfig(int width, int height) throws LibVpxException {
encCfgObj = vpxCodecEncAllocCfg();
if (encCfgObj == 0) {
throw new LibVpxException("Can not allocate JNI encoder configure object");
}
int res = vpxCodecEncConfigDefault(encCfgObj, 0);
if (res != 0) {
vpxCodecEncFreeCfg(encCfgObj);
throw new LibVpxException(errToString(res));
}
setWidth(width);
setHeight(height);
/* Change the default timebase to a high enough value so that the encoder
* will always create strictly increasing timestamps.
*/
setTimebase(1, 1000);
}
public void close() {
vpxCodecEncFreeCfg(encCfgObj);
}
public long handle() {
return encCfgObj;
}
public void setThreads(int value) {
vpxCodecEncSetThreads(encCfgObj, value);
}
public void setProfile(int value) {
vpxCodecEncSetProfile(encCfgObj, value);
}
public void setWidth(int value) {
vpxCodecEncSetWidth(encCfgObj, value);
}
public void setHeight(int value) {
vpxCodecEncSetHeight(encCfgObj, value);
}
public void setTimebase(int num, int den) {
vpxCodecEncSetTimebase(encCfgObj, num, den);
}
public void setErrorResilient(int value) {
vpxCodecEncSetErrorResilient(encCfgObj, value);
}
public void setPass(int value) {
vpxCodecEncSetPass(encCfgObj, value);
}
public void setLagInFrames(int value) {
vpxCodecEncSetLagInFrames(encCfgObj, value);
}
public void setRCDropframeThresh(int value) {
vpxCodecEncSetRCDropframeThresh(encCfgObj, value);
}
public void setRCResizeAllowed(int value) {
vpxCodecEncSetRCResizeAllowed(encCfgObj, value);
}
public void setRCResizeUpThresh(int value) {
vpxCodecEncSetRCResizeUpThresh(encCfgObj, value);
}
public void setRCResizeDownThresh(int value) {
vpxCodecEncSetRCResizeDownThresh(encCfgObj, value);
}
public void setRCEndUsage(int value) {
vpxCodecEncSetRCEndUsage(encCfgObj, value);
}
public void setRCTargetBitrate(int value) {
vpxCodecEncSetRCTargetBitrate(encCfgObj, value);
}
public void setRCMinQuantizer(int value) {
vpxCodecEncSetRCMinQuantizer(encCfgObj, value);
}
public void setRCMaxQuantizer(int value) {
vpxCodecEncSetRCMaxQuantizer(encCfgObj, value);
}
public void setRCUndershootPct(int value) {
vpxCodecEncSetRCUndershootPct(encCfgObj, value);
}
public void setRCOvershootPct(int value) {
vpxCodecEncSetRCOvershootPct(encCfgObj, value);
}
public void setRCBufSz(int value) {
vpxCodecEncSetRCBufSz(encCfgObj, value);
}
public void setRCBufInitialSz(int value) {
vpxCodecEncSetRCBufInitialSz(encCfgObj, value);
}
public void setRCBufOptimalSz(int value) {
vpxCodecEncSetRCBufOptimalSz(encCfgObj, value);
}
public void setKFMinDist(int value) {
vpxCodecEncSetKFMinDist(encCfgObj, value);
}
public void setKFMaxDist(int value) {
vpxCodecEncSetKFMaxDist(encCfgObj, value);
}
public int getThreads() {
return vpxCodecEncGetThreads(encCfgObj);
}
public int getProfile() {
return vpxCodecEncGetProfile(encCfgObj);
}
public int getWidth() {
return vpxCodecEncGetWidth(encCfgObj);
}
public int getHeight() {
return vpxCodecEncGetHeight(encCfgObj);
}
public Rational getTimebase() {
return vpxCodecEncGetTimebase(encCfgObj);
}
public int getErrorResilient() {
return vpxCodecEncGetErrorResilient(encCfgObj);
}
public int getPass() {
return vpxCodecEncGetPass(encCfgObj);
}
public int getLagInFrames() {
return vpxCodecEncGetLagInFrames(encCfgObj);
}
public int getRCDropframeThresh() {
return vpxCodecEncGetRCDropframeThresh(encCfgObj);
}
public int getRCResizeAllowed() {
return vpxCodecEncGetRCResizeAllowed(encCfgObj);
}
public int getRCResizeUpThresh() {
return vpxCodecEncGetRCResizeUpThresh(encCfgObj);
}
public int getRCResizeDownThresh() {
return vpxCodecEncGetRCResizeDownThresh(encCfgObj);
}
public int getRCEndUsage() {
return vpxCodecEncGetRCEndUsage(encCfgObj);
}
public int getRCTargetBitrate() {
return vpxCodecEncGetRCTargetBitrate(encCfgObj);
}
public int getRCMinQuantizer() {
return vpxCodecEncGetRCMinQuantizer(encCfgObj);
}
public int getRCMaxQuantizer() {
return vpxCodecEncGetRCMaxQuantizer(encCfgObj);
}
public int getRCUndershootPct() {
return vpxCodecEncGetRCUndershootPct(encCfgObj);
}
public int getRCOvershootPct() {
return vpxCodecEncGetRCOvershootPct(encCfgObj);
}
public int getRCBufSz() {
return vpxCodecEncGetRCBufSz(encCfgObj);
}
public int getRCBufInitialSz() {
return vpxCodecEncGetRCBufInitialSz(encCfgObj);
}
public int getRCBufOptimalSz() {
return vpxCodecEncGetRCBufOptimalSz(encCfgObj);
}
public int getFourcc() {
return vpxCodecEncGetFourcc();
}
}
// Copyright 2012 Google Inc. All Rights Reserved.
// Author: frkoenig@google.com (Fritz Koenig)
package com.google.libvpx;
/**
*
*/
public class LibVpxException extends Exception {
private static final long serialVersionUID = 1L;
public LibVpxException(String msg) {
super(msg);
}
}
// Copyright 2012 Google Inc. All Rights Reserved.
// Author: frkoenig@google.com (Fritz Koenig)
package com.google.libvpx;
/**
* Holds a rational number
*
*/
public class Rational {
private final long num;
private final long den;
public Rational() {
num = 0;
den = 1;
}
public Rational(long num, long den) {
this.num = num;
this.den = den;
}
public Rational(String num, String den) {
this.num = Integer.parseInt(num);
this.den = Integer.parseInt(den);
}
public Rational multiply(Rational b) {
return new Rational(num * b.num(), den * b.den());
}
public Rational multiply(int b) {
return new Rational(num * b, den);
}
public Rational reciprocal() {
return new Rational(den, num);
}
public float toFloat() {
return (float) num / (float) den;
}
public long toLong() {
// TODO(frkoenig) : consider adding rounding to the divide.
return num / den;
}
public long num() {
return num;
}
public long den() {
return den;
}
@Override
public String toString() {
if (den == 1) {
return new String(num + "");
} else {
return new String(num + "/" + den);
}
}
public String toColonSeparatedString() {
return new String(num + ":" + den);
}
}
// Copyright 2012 Google Inc. All Rights Reserved.
// Author: frkoenig@google.com (Fritz Koenig)
package com.google.libvpx;
/**
* Packet of data return from encoder.
*/
public class VpxCodecCxPkt {
public byte[] buffer; // compressed data buffer
public long sz; // length of compressed data
public long pts; // time stamp to show frame (in timebase units)
long duration; // duration to show frame (in timebase units)
public int flags; // flags for this frame
int partitionId; // the partition id
// defines the decoding order
// of the partitions. Only
// applicable when "output partition"
// mode is enabled. First partition
// has id 0
public VpxCodecCxPkt(long sz) {
this.sz = sz;
buffer = new byte[(int) this.sz];
}
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm;
public abstract class Common {
static {
System.loadLibrary("webm");
}
protected long nativePointer;
protected boolean ownMemory;
public long getNativePointer() {
return nativePointer;
}
protected Common() {
nativePointer = 0;
ownMemory = true;
}
protected Common(long nativePointer) {
this.nativePointer = nativePointer;
ownMemory = false;
}
protected abstract void deleteObject();
@Override
protected void finalize() {
if (ownMemory) {
deleteObject();
}
nativePointer = 0;
ownMemory = false;
}
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
public class AudioTrack extends Track {
public AudioTrack(int seed) {
nativePointer = newAudioTrack(seed);
}
public long bitDepth() {
return bitDepth(nativePointer);
}
public long channels() {
return channels(nativePointer);
}
@Override
public long payloadSize() {
return PayloadSize(nativePointer);
}
public double sampleRate() {
return sampleRate(nativePointer);
}
public void setBitDepth(long bitDepth) {
setBitDepth(nativePointer, bitDepth);
}
public void setChannels(long channels) {
setChannels(nativePointer, channels);
}
public void setSampleRate(double sampleRate) {
setSampleRate(nativePointer, sampleRate);
}
@Override
public boolean write(IMkvWriter writer) {
return Write(nativePointer, writer.getNativePointer());
}
protected AudioTrack(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteAudioTrack(nativePointer);
}
private static native long bitDepth(long jAudioTrack);
private static native long channels(long jAudioTrack);
private static native void deleteAudioTrack(long jAudioTrack);
private static native long newAudioTrack(int jSeed);
private static native long PayloadSize(long jAudioTrack);
private static native double sampleRate(long jAudioTrack);
private static native void setBitDepth(long jAudioTrack, long bit_depth);
private static native void setChannels(long jAudioTrack, long channels);
private static native void setSampleRate(long jAudioTrack, double sample_rate);
private static native boolean Write(long jAudioTrack, long jWriter);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
import com.google.libwebm.Common;
public class Chapter extends Common {
public boolean addString(String title, String language, String country) {
return addString(nativePointer, title, language, country);
}
public boolean setId(String id) {
return setId(nativePointer, id);
}
public void setTime(Segment segment, long startTimeNs, long endTimeNs) {
setTime(nativePointer, segment.getNativePointer(), startTimeNs, endTimeNs);
}
protected Chapter(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
}
private static native boolean addString(long jChapter, String jTitle, String jLanguage,
String jCountry);
private static native boolean setId(long jChapter, String jId);
private static native void setTime(long jChapter, long jSegment, long start_time_ns,
long end_time_ns);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
import com.google.libwebm.Common;
public class Chapters extends Common {
public Chapters() {
nativePointer = newChapters();
}
public Chapter addChapter(int seed) {
long pointer = AddChapter(nativePointer, seed);
return new Chapter(pointer);
}
public int count() {
return Count(nativePointer);
}
public boolean write(IMkvWriter writer) {
return Write(nativePointer, writer.getNativePointer());
}
protected Chapters(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteChapters(nativePointer);
}
private static native long AddChapter(long jChapters, int jSeed);
private static native int Count(long jChapters);
private static native void deleteChapters(long jChapters);
private static native long newChapters();
private static native boolean Write(long jChapters, long jWriter);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
import com.google.libwebm.Common;
public class Cluster extends Common {
public Cluster(long timecode, long cuesPos) {
nativePointer = newCluster(timecode, cuesPos);
}
public boolean addFrame(byte[] frame, long trackNumber, long timecode, boolean isKey) {
return AddFrame(nativePointer, frame, frame.length, trackNumber, timecode, isKey);
}
public boolean addMetadata(byte[] frame, long trackNumber, long timecode, long duration) {
return AddMetadata(nativePointer, frame, frame.length, trackNumber, timecode, duration);
}
public void addPayloadSize(long size) {
AddPayloadSize(nativePointer, size);
}
public int blocksAdded() {
return blocksAdded(nativePointer);
}
public boolean finalizeCluster() {
return Finalize(nativePointer);
}
public boolean init(IMkvWriter writer) {
return Init(nativePointer, writer.getNativePointer());
}
public long payloadSize() {
return payloadSize(nativePointer);
}
public long positionForCues() {
return positionForCues(nativePointer);
}
public long size() {
return Size(nativePointer);
}
public long timecode() {
return timecode(nativePointer);
}
protected Cluster(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteCluster(nativePointer);
}
private static native boolean AddFrame(long jCluster, byte[] jFrame, long length,
long track_number, long timecode, boolean is_key);
private static native boolean AddMetadata(long jCluster, byte[] jFrame, long length,
long track_number, long timecode, long duration);
private static native void AddPayloadSize(long jCluster, long size);
private static native int blocksAdded(long jCluster);
private static native void deleteCluster(long jCluster);
private static native boolean Finalize(long jCluster);
private static native boolean Init(long jCluster, long jWriter);
private static native long newCluster(long timecode, long cues_pos);
private static native long payloadSize(long jCluster);
private static native long positionForCues(long jCluster);
private static native long Size(long jCluster);
private static native long timecode(long jCluster);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
import com.google.libwebm.Common;
public class ContentEncAesSettings extends Common {
public ContentEncAesSettings() {
nativePointer = newContentEncAesSettings();
}
public long cipherMode() {
return cipherMode(nativePointer);
}
public long size() {
return Size(nativePointer);
}
public boolean write(IMkvWriter writer) {
return Write(nativePointer, writer.getNativePointer());
}
protected ContentEncAesSettings(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteContentEncAesSettings(nativePointer);
}
private static native long cipherMode(long jContentEncAesSettings);
private static native void deleteContentEncAesSettings(long jContentEncAesSettings);
private static native long newContentEncAesSettings();
private static native long Size(long jContentEncAesSettings);
private static native boolean Write(long jContentEncAesSettings, long jWriter);
public enum CipherMode {None, kCTR};
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
import com.google.libwebm.Common;
public class ContentEncoding extends Common {
public ContentEncoding() {
nativePointer = newContentEncoding();
}
public ContentEncAesSettings encAesSettings() {
long pointer = encAesSettings(nativePointer);
return new ContentEncAesSettings(pointer);
}
public long encAlgo() {
return encAlgo(nativePointer);
}
public long encodingOrder() {
return encodingOrder(nativePointer);
}
public long encodingScope() {
return encodingScope(nativePointer);
}
public long encodingType() {
return encodingType(nativePointer);
}
public boolean setEncryptionId(byte[] id) {
return SetEncryptionID(nativePointer, id, id.length);
}
public long size() {
return Size(nativePointer);
}
public boolean write(IMkvWriter writer) {
return Write(nativePointer, writer.getNativePointer());
}
protected ContentEncoding(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteContentEncoding(nativePointer);
}
private static native void deleteContentEncoding(long jContentEncoding);
private static native long encAesSettings(long jContentEncoding);
private static native long encAlgo(long jContentEncoding);
private static native long encodingOrder(long jContentEncoding);
private static native long encodingScope(long jContentEncoding);
private static native long encodingType(long jContentEncoding);
private static native long newContentEncoding();
private static native boolean SetEncryptionID(long jContentEncoding, byte[] jId, long length);
private static native long Size(long jContentEncoding);
private static native boolean Write(long jContentEncoding, long jWriter);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
import com.google.libwebm.Common;
public class CuePoint extends Common {
public CuePoint() {
nativePointer = newCuePoint();
}
public long blockNumber() {
return blockNumber(nativePointer);
}
public long clusterPos() {
return clusterPos(nativePointer);
}
public boolean outputBlockNumber() {
return outputBlockNumber(nativePointer);
}
public void setBlockNumber(long blockNumber) {
setBlockNumber(nativePointer, blockNumber);
}
public void setClusterPos(long clusterPos) {
setClusterPos(nativePointer, clusterPos);
}
public void setOutputBlockNumber(boolean outputBlockNumber) {
setOutputBlockNumber(nativePointer, outputBlockNumber);
}
public void setTime(long time) {
setTime(nativePointer, time);
}
public void setTrack(long track) {
setTrack(nativePointer, track);
}
public long size() {
return Size(nativePointer);
}
public long time() {
return time(nativePointer);
}
public long track() {
return track(nativePointer);
}
public boolean write(IMkvWriter writer) {
return Write(nativePointer, writer.getNativePointer());
}
protected CuePoint(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteCuePoint(nativePointer);
}
private static native long blockNumber(long jCuePoint);
private static native long clusterPos(long jCuePoint);
private static native void deleteCuePoint(long jCuePoint);
private static native long newCuePoint();
private static native boolean outputBlockNumber(long jCuePoint);
private static native void setBlockNumber(long jCuePoint, long block_number);
private static native void setClusterPos(long jCuePoint, long cluster_pos);
private static native void setOutputBlockNumber(long jCuePoint, boolean output_block_number);
private static native void setTime(long jCuePoint, long time);
private static native void setTrack(long jCuePoint, long track);
private static native long Size(long jCuePoint);
private static native long time(long jCuePoint);
private static native long track(long jCuePoint);
private static native boolean Write(long jCuePoint, long jWriter);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
import com.google.libwebm.Common;
public class Cues extends Common {
public Cues() {
nativePointer = newCues();
}
public boolean addCue(CuePoint cue) {
return AddCue(nativePointer, cue.getNativePointer());
}
public int cueEntriesSize() {
return cueEntriesSize(nativePointer);
}
public CuePoint getCueByIndex(int index) {
long pointer = GetCueByIndex(nativePointer, index);
return new CuePoint(pointer);
}
public boolean outputBlockNumber() {
return outputBlockNumber(nativePointer);
}
public void setOutputBlockNumber(boolean outputBlockNumber) {
setOutputBlockNumber(nativePointer, outputBlockNumber);
}
public boolean write(IMkvWriter writer) {
return Write(nativePointer, writer.getNativePointer());
}
protected Cues(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteCues(nativePointer);
}
private static native boolean AddCue(long jCues, long jCue);
private static native int cueEntriesSize(long jCues);
private static native long GetCueByIndex(long jCues, int index);
private static native void deleteCues(long jCuePoint);
private static native long newCues();
private static native boolean outputBlockNumber(long jCues);
private static native void setOutputBlockNumber(long jCues, boolean output_block_number);
private static native boolean Write(long jCues, long jWriter);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
import com.google.libwebm.Common;
public class Frame extends Common {
public Frame() {
nativePointer = newFrame();
}
public byte[] frame() {
return frame(nativePointer);
}
public boolean init(byte[] frame) {
return Init(nativePointer, frame, frame.length);
}
public boolean isKey() {
return isKey(nativePointer);
}
public long length() {
return length(nativePointer);
}
public void setIsKey(boolean key) {
setIsKey(nativePointer, key);
}
public void setTimestamp(long timestamp) {
setTimestamp(nativePointer, timestamp);
}
public void setTrackNumber(long trackNumber) {
setTrackNumber(nativePointer, trackNumber);
}
public long timestamp() {
return timestamp(nativePointer);
}
public long trackNumber() {
return trackNumber(nativePointer);
}
protected Frame(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteFrame(nativePointer);
}
private static native void deleteFrame(long jFrame);
private static native byte[] frame(long jFrame);
private static native boolean Init(long jFrame, byte[] jFrameBuffer, long length);
private static native boolean isKey(long jFrame);
private static native long length(long jFrame);
private static native long newFrame();
private static native void setIsKey(long jFrame, boolean key);
private static native void setTimestamp(long jFrame, long timestamp);
private static native void setTrackNumber(long jFrame, long track_number);
private static native long timestamp(long jFrame);
private static native long trackNumber(long jFrame);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
import com.google.libwebm.Common;
public abstract class IMkvWriter extends Common {
public static IMkvWriter newMkvWriter(long nativePointer) {
IMkvWriter mkvWriter = null;
int type = getType(nativePointer);
if (type == 1) {
mkvWriter = new MkvWriter(nativePointer);
}
return mkvWriter;
}
public abstract void elementStartNotify(long elementId, long position);
public abstract long position();
public abstract int position(long position);
public abstract boolean seekable();
public abstract int write(byte[] buffer);
protected IMkvWriter() {
super();
}
protected IMkvWriter(long nativePointer) {
super(nativePointer);
}
private static native int getType(long jMkvReader);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
import com.google.libwebm.Common;
public abstract class MkvMuxer extends Common {
public final long kEbmlUnknownValue = 0x01ffffffffffffffL;
public static long ebmlElementSize(long type, long value) {
return EbmlElementSizeLong(type, value);
}
public static long ebmlElementSize(long type, float value) {
return EbmlElementSizeFloat(type, value);
}
public static long ebmlElementSize(long type, byte[] value) {
return EbmlElementSizeBuffer(type, value, value.length);
}
public static long ebmlElementSize(long type, String value) {
return EbmlElementSizeString(type, value);
}
public static long ebmlMasterElementSize(long type, long value) {
return EbmlMasterElementSize(type, value);
}
public static void getVersion(int[] major, int[] minor, int[] build, int[] revision) {
GetVersion(major, minor, build, revision);
}
public static long makeUid(int seed) {
return MakeUID(seed);
}
public static int serializeInt(IMkvWriter writer, long value, int size) {
return SerializeInt(writer.getNativePointer(), value, size);
}
public static boolean writeEbmlElement(IMkvWriter writer, long type, long value) {
return WriteEbmlElementLong(writer.getNativePointer(), type, value);
}
public static boolean writeEbmlElement(IMkvWriter writer, long type, float value) {
return WriteEbmlElementFloat(writer.getNativePointer(), type, value);
}
public static boolean writeEbmlElement(IMkvWriter writer, long type, byte[] value) {
return WriteEbmlElementBuffer(writer.getNativePointer(), type, value, value.length);
}
public static boolean writeEbmlElement(IMkvWriter writer, long type, String value) {
return WriteEbmlElementString(writer.getNativePointer(), type, value);
}
public static boolean writeEbmlHeader(IMkvWriter writer) {
return WriteEbmlHeader(writer.getNativePointer());
}
public static boolean writeEbmlMasterElement(IMkvWriter writer, long value, long size) {
return WriteEbmlMasterElement(writer.getNativePointer(), value, size);
}
public static int writeId(IMkvWriter writer, long type) {
return WriteID(writer.getNativePointer(), type);
}
public static long writeMetadataBlock(IMkvWriter writer, byte[] data, long trackNumber,
long timeCode, long durationTimeCode) {
return WriteMetadataBlock(writer.getNativePointer(), data, data.length, trackNumber, timeCode,
durationTimeCode);
}
public static long writeSimpleBlock(IMkvWriter writer, byte[] data, long trackNumber,
long timeCode, long isKey) {
return WriteSimpleBlock(writer.getNativePointer(), data, data.length, trackNumber, timeCode,
isKey);
}
public static int writeUint(IMkvWriter writer, long value) {
return WriteUInt(writer.getNativePointer(), value);
}
public static int writeUintSize(IMkvWriter writer, long value, int size) {
return WriteUIntSize(writer.getNativePointer(), value, size);
}
public static long writeVoidElement(IMkvWriter writer, long size) {
return WriteVoidElement(writer.getNativePointer(), size);
}
private static native long EbmlElementSizeBuffer(long type, byte[] jValue, long size);
private static native long EbmlElementSizeFloat(long type, float value);
private static native long EbmlElementSizeLong(long type, long jValue);
private static native long EbmlElementSizeString(long type, String jValue);
private static native long EbmlMasterElementSize(long type, long value);
private static native void GetVersion(int[] jMajor, int[] jMinor, int[] jBuild, int[] jRevision);
private static native long MakeUID(int jSeed);
private static native int SerializeInt(long jWriter, long value, int size);
private static native boolean WriteEbmlElementBuffer(long jWriter, long type, byte[] jValue,
long size);
private static native boolean WriteEbmlElementFloat(long jWriter, long type, float value);
private static native boolean WriteEbmlElementLong(long jWriter, long type, long jValue);
private static native boolean WriteEbmlElementString(long jWriter, long type, String jValue);
private static native boolean WriteEbmlHeader(long jWriter);
private static native boolean WriteEbmlMasterElement(long jWriter, long value, long size);
private static native int WriteID(long jWriter, long type);
private static native long WriteMetadataBlock(long jWriter, byte[] jData, long length,
long track_number, long timecode, long duration_timecode);
private static native long WriteSimpleBlock(long jWriter, byte[] jData, long length,
long track_number, long timecode, long is_key);
private static native int WriteUInt(long jWriter, long value);
private static native int WriteUIntSize(long jWriter, long value, int size);
private static native long WriteVoidElement(long jWriter, long size);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
public class MkvWriter extends IMkvWriter {
public MkvWriter() {
nativePointer = newMkvWriter();
}
public void close() {
Close(nativePointer);
}
@Override
public void elementStartNotify(long elementId, long position) {
ElementStartNotify(nativePointer, elementId, position);
}
public boolean open(String fileName) {
return Open(nativePointer, fileName);
}
@Override
public long position() {
return GetPosition(nativePointer);
}
@Override
public int position(long position) {
return SetPosition(nativePointer, position);
}
@Override
public boolean seekable() {
return Seekable(nativePointer);
}
@Override
public int write(byte[] buffer) {
return Write(nativePointer, buffer, buffer.length);
}
protected MkvWriter(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteMkvWriter(nativePointer);
}
private static native void Close(long jMkvWriter);
private static native void deleteMkvWriter(long jMkvWriter);
private static native void ElementStartNotify(long jMkvWriter, long element_id, long position);
private static native long GetPosition(long jMkvWriter);
private static native long newMkvWriter();
private static native boolean Open(long jMkvWriter, String jFilename);
private static native boolean Seekable(long jMkvWriter);
private static native int SetPosition(long jMkvWriter, long position);
private static native int Write(long jMkvWriter, byte[] jBuffer, int length);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
import com.google.libwebm.Common;
public class SeekHead extends Common {
public SeekHead() {
nativePointer = newSeekHead();
}
public boolean addSeekEntry(int id, long pos) {
return AddSeekEntry(nativePointer, id, pos);
}
public boolean finalizeSeekHead(IMkvWriter writer) {
return Finalize(nativePointer, writer.getNativePointer());
}
public boolean write(IMkvWriter writer) {
return Write(nativePointer, writer.getNativePointer());
}
protected SeekHead(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteSeekHead(nativePointer);
}
private static native boolean AddSeekEntry(long jSeekHead, int id, long pos);
private static native void deleteSeekHead(long jSeekHead);
private static native boolean Finalize(long jSeekHead, long jWriter);
private static native long newSeekHead();
private static native boolean Write(long jSeekHead, long jWriter);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
import com.google.libwebm.Common;
public class Segment extends Common {
public enum Mode {
None,
kLive,
kFile
};
public static final long kDefaultMaxClusterDuration = 30000000000L;
public Segment() {
nativePointer = newSegment();
}
public long addAudioTrack(int sampleRate, int channels, int number) {
return AddAudioTrack(nativePointer, sampleRate, channels, number);
}
public Chapter addChapter() {
long pointer = AddChapter(nativePointer);
return new Chapter(pointer);
}
public boolean addCuePoint(long timestamp, long track) {
return AddCuePoint(nativePointer, timestamp, track);
}
public boolean addFrame(byte[] frame, long trackNumber, long timestampNs, boolean isKey) {
return AddFrame(nativePointer, frame, frame.length, trackNumber, timestampNs, isKey);
}
public boolean addMetadata(byte[] frame, long trackNumber, long timestampNs, long durationNs) {
return AddMetadata(nativePointer, frame, frame.length, trackNumber, timestampNs, durationNs);
}
public Track addTrack(int number) {
long pointer = AddTrack(nativePointer, number);
return Track.newTrack(pointer);
}
public long addVideoTrack(int width, int height, int number) {
return AddVideoTrack(nativePointer, width, height, number);
}
public boolean chunking() {
return chunking(nativePointer);
}
public long cuesTrack() {
return getCuesTrack(nativePointer);
}
public boolean cuesTrack(long trackNumber) {
return setCuesTrack(nativePointer, trackNumber);
}
public boolean finalizeSegment() {
return Finalize(nativePointer);
}
public void forceNewClusterOnNextFrame() {
ForceNewClusterOnNextFrame(nativePointer);
}
public Cues getCues() {
long pointer = GetCues(nativePointer);
return new Cues(pointer);
}
public SegmentInfo getSegmentInfo() {
long pointer = GetSegmentInfo(nativePointer);
return new SegmentInfo(pointer);
}
public Track getTrackByNumber(long trackNumber) {
long pointer = GetTrackByNumber(nativePointer, trackNumber);
return Track.newTrack(pointer);
}
public boolean init(IMkvWriter writer) {
return Init(nativePointer, writer.getNativePointer());
}
public long maxClusterDuration() {
return maxClusterDuration(nativePointer);
}
public long maxClusterSize() {
return maxClusterSize(nativePointer);
}
public Mode mode() {
int ordinal = mode(nativePointer);
return Mode.values()[ordinal];
}
public boolean outputCues() {
return outputCues(nativePointer);
}
public void outputCues(boolean outputCues) {
OutputCues(nativePointer, outputCues);
}
public SegmentInfo segmentInfo() {
long pointer = segmentInfo(nativePointer);
return new SegmentInfo(pointer);
}
public void setMaxClusterDuration(long maxClusterDuration) {
setMaxClusterDuration(nativePointer, maxClusterDuration);
}
public void setMaxClusterSize(long maxClusterSize) {
setMaxClusterSize(nativePointer, maxClusterSize);
}
public void setMode(Mode mode) {
setMode(nativePointer, mode.ordinal());
}
public boolean setChunking(boolean chunking, String filename) {
return SetChunking(nativePointer, chunking, filename);
}
protected Segment(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteSegment(nativePointer);
}
private static native long AddAudioTrack(long jSegment, int sample_rate, int channels,
int number);
private static native long AddChapter(long jSegment);
private static native boolean AddCuePoint(long jSegment, long timestamp, long track);
private static native boolean AddFrame(long jSegment, byte[] jFrame, long length,
long track_number, long timestamp_ns, boolean is_key);
private static native boolean AddMetadata(long jSegment, byte[] jFrame, long length,
long track_number, long timestamp_ns, long duration_ns);
private static native long AddTrack(long jSegment, int number);
private static native long AddVideoTrack(long jSegment, int width, int height, int number);
private static native boolean chunking(long jSegment);
private static native void deleteSegment(long jSegment);
private static native boolean Finalize(long jSegment);
private static native void ForceNewClusterOnNextFrame(long jSegment);
private static native long GetCues(long jSegment);
private static native long getCuesTrack(long jSegment);
private static native long GetSegmentInfo(long jSegment);
private static native long GetTrackByNumber(long jSegment, long track_number);
private static native boolean Init(long jSegment, long jWriter);
private static native long maxClusterDuration(long jSegment);
private static native long maxClusterSize(long jSegment);
private static native int mode(long jSegment);
private static native long newSegment();
private static native boolean outputCues(long jSegment);
private static native void OutputCues(long jSegment, boolean output_cues);
private static native long segmentInfo(long jSegment);
private static native boolean setCuesTrack(long jSegment, long track_number);
private static native void setMaxClusterDuration(long jSegment, long max_cluster_duration);
private static native void setMaxClusterSize(long jSegment, long max_cluster_size);
private static native void setMode(long jSegment, int mode);
private static native boolean SetChunking(long jSegment, boolean chunking, String jFilename);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
import com.google.libwebm.Common;
public class SegmentInfo extends Common {
public SegmentInfo() {
nativePointer = newSegmentInfo();
}
public double duration() {
return duration(nativePointer);
}
public boolean finalizeSegmentInfo(IMkvWriter writer) {
return Finalize(nativePointer, writer.getNativePointer());
}
public boolean init() {
return Init(nativePointer);
}
public String muxingApp() {
return muxingApp(nativePointer);
}
public void setDuration(double duration) {
setDuration(nativePointer, duration);
}
public void setMuxingApp(String app) {
setMuxingApp(nativePointer, app);
}
public void setTimecodeScale(long scale) {
setTimecodeScale(nativePointer, scale);
}
public void setWritingApp(String app) {
setWritingApp(nativePointer, app);
}
public long timecodeScale() {
return timecodeScale(nativePointer);
}
public boolean write(IMkvWriter writer) {
return Write(nativePointer, writer.getNativePointer());
}
public String writingApp() {
return writingApp(nativePointer);
}
protected SegmentInfo(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteSegmentInfo(nativePointer);
}
private static native void deleteSegmentInfo(long jSegmentInfo);
private static native double duration(long jSegmentInfo);
private static native boolean Finalize(long jSegmentInfo, long jWriter);
private static native boolean Init(long jSegmentInfo);
private static native String muxingApp(long jSegmentInfo);
private static native long newSegmentInfo();
private static native void setDuration(long jSegmentInfo, double duration);
private static native void setMuxingApp(long jSegmentInfo, String jApp);
private static native void setTimecodeScale(long jSegmentInfo, long scale);
private static native void setWritingApp(long jSegmentInfo, String jApp);
private static native long timecodeScale(long jSegmentInfo);
private static native boolean Write(long jSegmentInfo, long jWriter);
private static native String writingApp(long jSegmentInfo);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
import com.google.libwebm.Common;
public class Track extends Common {
public static Track newTrack(long nativePointer) {
Track track = null;
int type = getClassType(nativePointer);
if (type == 1) {
track = new AudioTrack(nativePointer);
} else if (type == 2) {
track = new Track(nativePointer);
} else if (type == 3) {
track = new VideoTrack(nativePointer);
}
return track;
}
public Track(int seed) {
nativePointer = newTrack(seed);
}
public boolean addContentEncoding() {
return AddContentEncoding(nativePointer);
}
public String codecId() {
return codecId(nativePointer);
}
public byte[] codecPrivate() {
return codecPrivate(nativePointer);
}
public long codecPrivateLength() {
return codecPrivateLength(nativePointer);
}
public int contentEncodingEntriesSize() {
return contentEncodingEntriesSize(nativePointer);
}
public ContentEncoding getContentEncodingByIndex(int index) {
long pointer = GetContentEncodingByIndex(nativePointer, index);
return new ContentEncoding(pointer);
}
public String language() {
return language(nativePointer);
}
public String name() {
return name(nativePointer);
}
public long number() {
return number(nativePointer);
}
public long payloadSize() {
return PayloadSize(nativePointer);
}
public void setCodecId(String codecId) {
setCodecId(nativePointer, codecId);
}
public boolean setCodecPrivate(byte[] codecPrivate) {
return SetCodecPrivate(nativePointer, codecPrivate, codecPrivate.length);
}
public void setLanguage(String language) {
setLanguage(nativePointer, language);
}
public void setName(String name) {
setName(nativePointer, name);
}
public void setNumber(long number) {
setNumber(nativePointer, number);
}
public void setType(long type) {
setType(nativePointer, type);
}
public long size() {
return Size(nativePointer);
}
public long type() {
return type(nativePointer);
}
public long uid() {
return uid(nativePointer);
}
public boolean write(IMkvWriter writer) {
return Write(nativePointer, writer.getNativePointer());
}
protected Track() {
}
protected Track(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteTrack(nativePointer);
}
private static native boolean AddContentEncoding(long jTrack);
private static native int contentEncodingEntriesSize(long jTrack);
private static native String codecId(long jTrack);
private static native byte[] codecPrivate(long jTrack);
private static native long codecPrivateLength(long jTrack);
private static native void deleteTrack(long jTrack);
private static native int getClassType(long jTrack);
private static native long GetContentEncodingByIndex(long jTrack, int index);
private static native String language(long jTrack);
private static native String name(long jTrack);
private static native long newTrack(int jSeed);
private static native long number(long jTrack);
private static native long PayloadSize(long jTrack);
private static native void setCodecId(long jTrack, String jCodecId);
private static native void setLanguage(long jTrack, String jLanguage);
private static native void setName(long jTrack, String jName);
private static native void setNumber(long jTrack, long number);
private static native void setType(long jTrack, long type);
private static native boolean SetCodecPrivate(long jTrack, byte[] jCodecPrivate, long length);
private static native long Size(long jTrack);
private static native long type(long jTrack);
private static native long uid(long jTrack);
private static native boolean Write(long jTrack, long jWriter);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
import com.google.libwebm.Common;
public class Tracks extends Common {
public enum Type {
None,
kVideo,
kAudio
};
public static final String kVorbisCodecId = "A_VORBIS";
public static final String kVp8CodecId = "V_VP8";
public Tracks() {
nativePointer = newTracks();
}
public boolean addTrack(Track track, int number) {
return AddTrack(nativePointer, track.getNativePointer(), number);
}
public Track getTrackByIndex(int index) {
long pointer = GetTrackByIndex(nativePointer, index);
return Track.newTrack(pointer);
}
public Track getTrackByNumber(long trackNumber) {
long pointer = GetTrackByNumber(nativePointer, trackNumber);
return Track.newTrack(pointer);
}
public int trackEntriesSize() {
return trackEntriesSize(nativePointer);
}
public boolean trackIsAudio(long trackNumber) {
return TrackIsAudio(nativePointer, trackNumber);
}
public boolean trackIsVideo(long trackNumber) {
return TrackIsVideo(nativePointer, trackNumber);
}
public boolean write(IMkvWriter writer) {
return Write(nativePointer, writer.getNativePointer());
}
protected Tracks(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteTracks(nativePointer);
}
private static native boolean AddTrack(long jTracks, long jTrack, int number);
private static native void deleteTracks(long jTracks);
private static native long GetTrackByIndex(long jTracks, int idx);
private static native long GetTrackByNumber(long jTracks, long track_number);
private static native long newTracks();
private static native int trackEntriesSize(long jTracks);
private static native boolean TrackIsAudio(long jTracks, long track_number);
private static native boolean TrackIsVideo(long jTracks, long track_number);
private static native boolean Write(long jTracks, long jWriter);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvmuxer;
import java.util.HashMap;
import java.util.Map;
public class VideoTrack extends Track {
public enum StereoMode {
kMono(0),
kSideBySideLeftIsFirst(1),
kTopBottomRightIsFirst(2),
kTopBottomLeftIsFirst(3),
kSideBySideRightIsFirst(11);
private static final Map<Integer, StereoMode> stereoModes = new HashMap<Integer, StereoMode>();
static {
for (StereoMode mode : StereoMode.values()) {
stereoModes.put(mode.toInt(), mode);
}
}
private final int value;
public static StereoMode toStereoMode(int value) {
return stereoModes.get(value);
}
public int toInt() {
return value;
}
private StereoMode(int value) {
this.value = value;
}
}
public VideoTrack(int seed) {
nativePointer = newVideoTrack(seed);
}
public long displayHeight() {
return displayHeight(nativePointer);
}
public long displayWidth() {
return displayWidth(nativePointer);
}
public double frameRate() {
return frameRate(nativePointer);
}
public long height() {
return height(nativePointer);
}
@Override
public long payloadSize() {
return PayloadSize(nativePointer);
}
public void setDisplayHeight(long height) {
setDisplayHeight(nativePointer, height);
}
public void setDisplayWidth(long width) {
setDisplayWidth(nativePointer, width);
}
public void setFrameRate(double frameRate) {
setFrameRate(nativePointer, frameRate);
}
public void setHeight(long height) {
setHeight(nativePointer, height);
}
public void setStereoMode(StereoMode stereoMode) {
SetStereoMode(nativePointer, stereoMode.toInt());
}
public void setWidth(long width) {
setWidth(nativePointer, width);
}
public StereoMode stereoMode() {
return StereoMode.toStereoMode((int) stereoMode(nativePointer));
}
public long width() {
return width(nativePointer);
}
@Override
public boolean write(IMkvWriter writer) {
return Write(nativePointer, writer.getNativePointer());
}
protected VideoTrack(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteVideoTrack(nativePointer);
}
private static native void deleteVideoTrack(long jVideoTrack);
private static native long displayHeight(long jVideoTrack);
private static native long displayWidth(long jVideoTrack);
private static native double frameRate(long jVideoTrack);
private static native long height(long jVideoTrack);
private static native long newVideoTrack(int jSeed);
private static native long PayloadSize(long jVideoTrack);
private static native void setDisplayHeight(long jVideoTrack, long height);
private static native void setDisplayWidth(long jVideoTrack, long width);
private static native void setFrameRate(long jVideoTrack, double frame_rate);
private static native void setHeight(long jVideoTrack, long height);
private static native void setWidth(long jVideoTrack, long width);
private static native void SetStereoMode(long jVideoTrack, long stereo_mode);
private static native long stereoMode(long jVideoTrack);
private static native long width(long jVideoTrack);
private static native boolean Write(long jVideoTrack, long jWriter);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
import com.google.libwebm.mkvmuxer.Chapters;
public class Atom extends Common {
public Display getDisplay(int index) {
long pointer = GetDisplay(nativePointer, index);
return new Display(pointer);
}
public int getDisplayCount() {
return GetDisplayCount(nativePointer);
}
public long getStartTime(Chapters chapters) {
return GetStartTime(nativePointer, chapters.getNativePointer());
}
public long getStartTimecode() {
return GetStartTimecode(nativePointer);
}
public long getStopTime(Chapters chapters) {
return GetStopTime(nativePointer, chapters.getNativePointer());
}
public long getStopTimecode() {
return GetStopTimecode(nativePointer);
}
public String getStringUid() {
return GetStringUID(nativePointer);
}
public long getUid() {
return GetUID(nativePointer);
}
protected Atom(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
}
private static native long GetDisplay(long jAtom, int index);
private static native int GetDisplayCount(long jAtom);
private static native long GetStartTime(long jAtom, long jChapters);
private static native long GetStartTimecode(long jAtom);
private static native long GetStopTime(long jAtom, long jChapters);
private static native long GetStopTimecode(long jAtom);
private static native String GetStringUID(long jAtom);
private static native long GetUID(long jAtom);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
public class AudioTrack extends Track {
public static long parse(Segment segment, Info info, long element_start, long element_size,
AudioTrack[] audioTrack) {
long[] jAudioTrack = {0};
long result = Parse(segment.getNativePointer(), info.getNativePointer(), element_start,
element_size, jAudioTrack);
audioTrack[0] = new AudioTrack(jAudioTrack[0]);
return result;
}
public long getBitDepth() {
return GetBitDepth(nativePointer);
}
public long getChannels() {
return GetChannels(nativePointer);
}
public double getSamplingRate() {
return GetSamplingRate(nativePointer);
}
@Override
public long seek(long time_ns, BlockEntry[] result) {
long[] jResult = {0};
long output = Seek(nativePointer, time_ns, jResult);
result[0] = BlockEntry.newBlockEntry(jResult[0]);
return output;
}
protected AudioTrack(long nativePointer) {
super(nativePointer);
}
private static native long GetBitDepth(long jAudioTrack);
private static native long GetChannels(long jAudioTrack);
private static native double GetSamplingRate(long jAudioTrack);
private static native long Parse(long jSegment, long jInfo, long element_start, long element_size,
long[] jAudioTrack);
private static native long Seek(long jAudioTrack, long time_ns, long[] jResult);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class Block extends Common {
public enum Lacing {
kLacingNone,
kLacingXiph,
kLacingFixed,
kLacingEbml
};
public Block() {
nativePointer = newBlock();
}
public Frame getFrame(int frameIndex) {
long pointer = GetFrame(nativePointer, frameIndex);
return new Frame(pointer);
}
public int getFrameCount() {
return GetFrameCount(nativePointer);
}
public Lacing getLacing() {
int ordinal = GetLacing(nativePointer);
return Lacing.values()[ordinal];
}
public long getSize() {
return getSize(nativePointer);
}
public long getStart() {
return getStart(nativePointer);
}
public long getTime(Cluster cluster) {
return GetTime(nativePointer, cluster.getNativePointer());
}
public long getTimeCode(Cluster cluster) {
return GetTimeCode(nativePointer, cluster.getNativePointer());
}
public long getTrackNumber() {
return GetTrackNumber(nativePointer);
}
public boolean isInvisible() {
return IsInvisible(nativePointer);
}
public boolean isKey() {
return IsKey(nativePointer);
}
public long parse(Cluster cluster) {
return Parse(nativePointer, cluster.getNativePointer());
}
public void setKey(boolean key) {
SetKey(nativePointer, key);
}
protected Block(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteBlock(nativePointer);
}
private static native void deleteBlock(long jBlock);
private static native long GetFrame(long jBlock, int frameIndex);
private static native int GetFrameCount(long jBlock);
private static native int GetLacing(long jBlock);
private static native long getSize(long jBlock);
private static native long getStart(long jBlock);
private static native long GetTime(long jBlock, long jCluster);
private static native long GetTimeCode(long jBlock, long jCluster);
private static native long GetTrackNumber(long jBlock);
private static native boolean IsInvisible(long jBlock);
private static native boolean IsKey(long jBlock);
private static native long newBlock();
private static native long Parse(long jBlock, long jCluster);
private static native void SetKey(long jBlock, boolean key);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public abstract class BlockEntry extends Common {
public enum Kind {
kBlockEOS,
kBlockSimple,
kBlockGroup
};
public static BlockEntry newBlockEntry(long nativePointer) {
BlockEntry blockEntry = null;
int type = getClassType(nativePointer);
if (type == 1) {
blockEntry = new BlockGroup(nativePointer);
} else if (type == 2) {
blockEntry = new SimpleBlock(nativePointer);
}
return blockEntry;
}
public boolean eos() {
return EOS(nativePointer);
}
public abstract Block getBlock();
public Cluster getCluster() {
long pointer = GetCluster(nativePointer);
return new Cluster(pointer);
}
public long getIndex() {
return GetIndex(nativePointer);
}
public abstract Kind getKind();
protected BlockEntry() {
super();
}
protected BlockEntry(long nativePointer) {
super(nativePointer);
}
private static native boolean EOS(long jBlockEntry);
private static native int getClassType(long jBlockEntry);
private static native long GetCluster(long jBlockEntry);
private static native long GetIndex(long jBlockEntry);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
public class BlockGroup extends BlockEntry {
public BlockGroup(Cluster cluster, long index, long blockStart, long blockSize, long previous,
long next, long duration) {
nativePointer = newBlockGroup(cluster.getNativePointer(), index, blockStart, blockSize,
previous, next, duration);
}
@Override
public Block getBlock() {
long pointer = GetBlock(nativePointer);
return new Block(pointer);
}
public long getDurationTimeCode() {
return GetDurationTimeCode(nativePointer);
}
@Override
public Kind getKind() {
int ordinal = GetKind(nativePointer);
return Kind.values()[ordinal];
}
public long getNextTimeCode() {
return GetNextTimeCode(nativePointer);
}
public long getPrevTimeCode() {
return GetPrevTimeCode(nativePointer);
}
public long Parse() {
return Parse(nativePointer);
}
protected BlockGroup(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteBlockGroup(nativePointer);
}
private static native void deleteBlockGroup(long jBlockGroup);
private static native long GetBlock(long jBlockGroup);
private static native long GetDurationTimeCode(long jBlockGroup);
private static native int GetKind(long jBlockGroup);
private static native long GetNextTimeCode(long jBlockGroup);
private static native long GetPrevTimeCode(long jBlockGroup);
private static native long newBlockGroup(long jCluster, long index, long blockStart,
long blockSize, long previous, long next, long duration);
private static native long Parse(long jBlockGroup);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class Chapters extends Common {
public Chapters(Segment segment, long payloadStart, long payloadSize, long elementStart,
long elementSize) {
nativePointer = newChapters(segment.getNativePointer(), payloadStart, payloadSize, elementStart,
elementSize);
}
public Edition getEdition(int index) {
long pointer = GetEdition(nativePointer, index);
return new Edition(pointer);
}
public int getEditionCount() {
return GetEditionCount(nativePointer);
}
public long getElementSize() {
return getElementSize(nativePointer);
}
public long getElementStart() {
return getElementStart(nativePointer);
}
public Segment getSegment() {
long pointer = getSegment(nativePointer);
return new Segment(pointer);
}
public long getSize() {
return getSize(nativePointer);
}
public long getStart() {
return getStart(nativePointer);
}
public long parse() {
return Parse(nativePointer);
}
protected Chapters(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteChapters(nativePointer);
}
private static native void deleteChapters(long jChapters);
private static native long GetEdition(long jChapters, int index);
private static native int GetEditionCount(long jChapters);
private static native long getElementSize(long jChapters);
private static native long getElementStart(long jChapters);
private static native long getSegment(long jChapters);
private static native long getSize(long jChapters);
private static native long getStart(long jChapters);
private static native long newChapters(long jSegment, long payload_start, long payload_size,
long element_start, long element_size);
private static native long Parse(long jChapters);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class Cluster extends Common {
public static Cluster create(Segment segment, long index, long offset) {
long pointer = Create(segment.getNativePointer(), index, offset);
return new Cluster(pointer);
}
public static long hasBlockEntries(Segment segment, long offset, long[] position, long[] size) {
return HasBlockEntries(segment.getNativePointer(), offset, position, size);
}
public Cluster() {
nativePointer = newCluster();
}
public boolean eos() {
return EOS(nativePointer);
}
public long getElementSize() {
return GetElementSize(nativePointer);
}
public long getElementStart() {
return getElementStart(nativePointer);
}
public long getEntryCount() {
return GetEntryCount(nativePointer);
}
public long getEntry(long index, BlockEntry[] blockEntry) {
long[] jBlockEntry = {0};
long result = GetEntryIndex(nativePointer, index, jBlockEntry);
blockEntry[0] = BlockEntry.newBlockEntry(jBlockEntry[0]);
return result;
}
public BlockEntry getEntry(CuePoint cuePoint, TrackPosition trackPosition) {
long pointer = GetEntryCuePoint(nativePointer, cuePoint.getNativePointer(),
trackPosition.getNativePointer());
return BlockEntry.newBlockEntry(pointer);
}
public BlockEntry getEntry(Track track, long ns) {
long pointer = GetEntryTrack(nativePointer, track.getNativePointer(), ns);
return BlockEntry.newBlockEntry(pointer);
}
public long getFirst(BlockEntry[] blockEntry) {
long[] jBlockEntry = {0};
long result = GetFirst(nativePointer, jBlockEntry);
blockEntry[0] = BlockEntry.newBlockEntry(jBlockEntry[0]);
return result;
}
public long getFirstTime() {
return GetFirstTime(nativePointer);
}
public long getLast(BlockEntry[] blockEntry) {
long[] jBlockEntry = {0};
long result = GetLast(nativePointer, jBlockEntry);
blockEntry[0] = BlockEntry.newBlockEntry(jBlockEntry[0]);
return result;
}
public long getLastTime() {
return GetLastTime(nativePointer);
}
public long getNext(BlockEntry current, BlockEntry[] next) {
long[] jNext = {0};
long result = GetNext(nativePointer, current.getNativePointer(), jNext);
next[0] = BlockEntry.newBlockEntry(jNext[0]);
return result;
}
public long getPosition() {
return GetPosition(nativePointer);
}
public long getSegment() {
return getSegment(nativePointer);
}
public long getTime() {
return GetTime(nativePointer);
}
public long getTimeCode() {
return GetTimeCode(nativePointer);
}
public long load(long[] position, long[] size) {
return Load(nativePointer, position, size);
}
public long parse(long[] position, long[] size) {
return Parse(nativePointer, position, size);
}
protected Cluster(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteCluster(nativePointer);
}
private static native long Create(long jSegment, long index, long offset);
private static native void deleteCluster(long jCluster);
private static native boolean EOS(long jCluster);
private static native long GetElementSize(long jCluster);
private static native long getElementStart(long jCluster);
private static native long GetEntryCount(long jCluster);
private static native long GetEntryCuePoint(long jCluster, long jCuePoint, long jTrackPosition);
private static native long GetEntryIndex(long jCluster, long index, long[] jBlockEntry);
private static native long GetEntryTrack(long jCluster, long jTrack, long ns);
private static native long GetFirst(long jCluster, long[] jBlockEntry);
private static native long GetFirstTime(long jCluster);
private static native long GetIndex(long jCluster);
private static native long GetLast(long jCluster, long[] jBlockEntry);
private static native long GetLastTime(long jCluster);
private static native long GetNext(long jCluster, long jCurrent, long[] jNext);
private static native long GetPosition(long jCluster);
private static native long getSegment(long jCluster);
private static native long GetTime(long jCluster);
private static native long GetTimeCode(long jCluster);
private static native long HasBlockEntries(long jSegment, long offset, long[] jPosition,
long[] jSize);
private static native long Load(long jCluster, long[] jPosition, long[] jSize);
private static native long newCluster();
private static native long Parse(long jCluster, long[] jPosition, long[] jSize);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class ContentCompression extends Common {
public ContentCompression() {
nativePointer = newContentCompression();
}
public long getAlgo() {
return getAlgo(nativePointer);
}
public void setAlgo(long algo) {
setAlgo(nativePointer, algo);
}
protected ContentCompression(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteContentCompression(nativePointer);
}
private static native void deleteContentCompression(long jContentCompression);
private static native long getAlgo(long jContentCompression);
private static native long newContentCompression();
private static native void setAlgo(long jContentCompression, long algo);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class ContentEncAesSettings extends Common {
public ContentEncAesSettings() {
nativePointer = newContentEncAesSettings();
}
public ContentEncoding.CipherMode getCipherMode() {
int ordinal = (int) getCipherMode(nativePointer);
return ContentEncoding.CipherMode.values()[ordinal];
}
public void setCipherMode(ContentEncoding.CipherMode cipherMode) {
setCipherMode(nativePointer, cipherMode.ordinal());
}
protected ContentEncAesSettings(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteContentEncAesSettings(nativePointer);
}
private static native void deleteContentEncAesSettings(long jContentEncAesSettings);
private static native long getCipherMode(long jContentEncAesSettings);
private static native long newContentEncAesSettings();
private static native void setCipherMode(long jContentEncAesSettings, long cipherMode);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class ContentEncoding extends Common {
public enum CipherMode {
None,
kCTR
};
public ContentEncoding() {
nativePointer = newContentEncoding();
}
public long encodingOrder() {
return encodingOrder(nativePointer);
}
public long encodingScope() {
return encodingScope(nativePointer);
}
public long encodingType() {
return encodingType(nativePointer);
}
public ContentCompression getCompressionByIndex(long index) {
long pointer = GetCompressionByIndex(nativePointer, index);
return new ContentCompression(pointer);
}
public long getCompressionCount() {
return GetCompressionCount(nativePointer);
}
public ContentEncryption getEncryptionByIndex(long index) {
long pointer = GetEncryptionByIndex(nativePointer, index);
return new ContentEncryption(pointer);
}
public long getEncryptionCount() {
return GetEncryptionCount(nativePointer);
}
public long parseContentEncAesSettingsEntry(long start, long size, IMkvReader mkvReader,
ContentEncAesSettings contentEncAesSettings) {
return ParseContentEncAESSettingsEntry(nativePointer, start, size, mkvReader.getNativePointer(),
contentEncAesSettings.getNativePointer());
}
public long parseContentEncodingEntry(long start, long size, IMkvReader mkvReader) {
return ParseContentEncodingEntry(nativePointer, start, size, mkvReader.getNativePointer());
}
public long parseEncryptionEntry(long start, long size, IMkvReader mkvReader,
ContentEncryption contentEncryption) {
return ParseEncryptionEntry(nativePointer, start, size, mkvReader.getNativePointer(),
contentEncryption.getNativePointer());
}
protected ContentEncoding(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteContentEncoding(nativePointer);
}
private static native void deleteContentEncoding(long jContentEncoding);
private static native long encodingOrder(long jContentEncoding);
private static native long encodingScope(long jContentEncoding);
private static native long encodingType(long jContentEncoding);
private static native long GetCompressionByIndex(long jContentEncoding, long idx);
private static native long GetCompressionCount(long jContentEncoding);
private static native long GetEncryptionByIndex(long jContentEncoding, long idx);
private static native long GetEncryptionCount(long jContentEncoding);
private static native long newContentEncoding();
private static native long ParseContentEncAESSettingsEntry(long jContentEncoding, long start,
long size, long jMkvReader, long jContentEncAesSettings);
private static native long ParseContentEncodingEntry(long jContentEncoding, long start, long size,
long jMkvReader);
private static native long ParseEncryptionEntry(long jContentEncoding, long start, long size,
long jMkvReader, long jContentEncryption);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class ContentEncryption extends Common {
public ContentEncryption() {
nativePointer = newContentEncrytpion();
}
public ContentEncAesSettings getAesSettings() {
long pointer = getAesSettings(nativePointer);
return new ContentEncAesSettings(pointer);
}
public long getAlgo() {
return getAlgo(nativePointer);
}
public byte[] getKeyId() {
return getKeyId(nativePointer);
}
public long getSigAlgo() {
return getSigAlgo(nativePointer);
}
public long getSigHashAlgo() {
return getSigHashAlgo(nativePointer);
}
public byte[] getSigKeyId() {
return getSigKeyId(nativePointer);
}
public byte[] getSignature() {
return getSignature(nativePointer);
}
public void setAesSettings(ContentEncAesSettings aesSettings) {
setAesSettings(nativePointer, aesSettings.getNativePointer());
}
public void setAlgo(long algo) {
setAlgo(nativePointer, algo);
}
public void setKeyId(byte[] keyId) {
setKeyId(nativePointer, keyId);
}
public void setSigAlgo(long sigAlgo) {
setSigAlgo(nativePointer, sigAlgo);
}
public void setSigHashAlgo(long sigHashAlgo) {
setSigHashAlgo(nativePointer, sigHashAlgo);
}
public void setSigKeyId(byte[] sigKeyId) {
setSigKeyId(nativePointer, sigKeyId);
}
public void setSignature(byte[] signature) {
setSignature(nativePointer, signature);
}
protected ContentEncryption(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteContentEncrytpion(nativePointer);
}
private static native void deleteContentEncrytpion(long jContentEncrytpion);
private static native long getAesSettings(long jContentEncrytpion);
private static native long getAlgo(long jContentEncrytpion);
private static native byte[] getKeyId(long jContentEncrytpion);
private static native long getSigAlgo(long jContentEncrytpion);
private static native long getSigHashAlgo(long jContentEncrytpion);
private static native byte[] getSigKeyId(long jContentEncrytpion);
private static native byte[] getSignature(long jContentEncrytpion);
private static native long newContentEncrytpion();
private static native void setAesSettings(long jContentEncrytpion, long aesSettings);
private static native void setAlgo(long jContentEncrytpion, long algo);
private static native void setKeyId(long jContentEncrytpion, byte[] jKeyId);
private static native void setSigAlgo(long jContentEncrytpion, long sigAlgo);
private static native void setSigHashAlgo(long jContentEncrytpion, long sigHashAlgo);
private static native void setSigKeyId(long jContentEncrytpion, byte[] jSigKeyId);
private static native void setSignature(long jContentEncrytpion, byte[] jSignature);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class CuePoint extends Common {
public TrackPosition find(Track track) {
long pointer = Find(nativePointer, track.getNativePointer());
return new TrackPosition(pointer);
}
public long getElementSize() {
return getElementSize(nativePointer);
}
public long getElementStart() {
return getElementStart(nativePointer);
}
public long getTime(Segment segment) {
return GetTime(nativePointer, segment.getNativePointer());
}
public long getTimeCode() {
return GetTimeCode(nativePointer);
}
public void load(IMkvReader mkvReader) {
Load(nativePointer, mkvReader.getNativePointer());
}
public void setElementSize(long elementSize) {
setElementSize(nativePointer, elementSize);
}
public void setElementStart(long elementStart) {
setElementStart(nativePointer, elementStart);
}
protected CuePoint(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
}
private static native long Find(long jCuePoint, long jTrack);
private static native long getElementSize(long jCuePoint);
private static native long getElementStart(long jCuePoint);
private static native long GetTime(long jCuePoint, long jSegment);
private static native long GetTimeCode(long jCuePoint);
private static native void Load(long jCuePoint, long jMkvReader);
private static native void setElementSize(long jCuePoint, long element_size);
private static native void setElementStart(long jCuePoint, long element_start);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class Cues extends Common {
public boolean doneParsing() {
return DoneParsing(nativePointer);
}
public boolean find(long timeNs, Track track, CuePoint[] cuePoint,
TrackPosition[] trackPosition) {
long[] jCuePoint = {0};
long[] jTrackPosition = {0};
boolean result =
Find(nativePointer, timeNs, track.getNativePointer(), jCuePoint, jTrackPosition);
cuePoint[0] = new CuePoint(jCuePoint[0]);
trackPosition[0] = new TrackPosition(jTrackPosition[0]);
return result;
}
public BlockEntry getBlock(CuePoint cp, TrackPosition tp) {
long pointer = GetBlock(nativePointer, cp.getNativePointer(), tp.getNativePointer());
return BlockEntry.newBlockEntry(pointer);
}
public long getCount() {
return GetCount(nativePointer);
}
public long getElementSize() {
return getElementSize(nativePointer);
}
public long getElementStart() {
return getElementStart(nativePointer);
}
public CuePoint getFirst() {
long pointer = GetFirst(nativePointer);
return new CuePoint(pointer);
}
public CuePoint getLast() {
long pointer = GetLast(nativePointer);
return new CuePoint(pointer);
}
public CuePoint getNext(CuePoint current) {
long pointer = GetNext(nativePointer, current.getNativePointer());
return new CuePoint(pointer);
}
public Segment getSegment() {
long pointer = getSegment(nativePointer);
return new Segment(pointer);
}
public long getSize() {
return getSize(nativePointer);
}
public long getStart() {
return getStart(nativePointer);
}
public boolean loadCuePoint() {
return LoadCuePoint(nativePointer);
}
protected Cues(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
}
private static native boolean DoneParsing(long jCues);
private static native boolean Find(long jCues, long time_ns, long jTrack, long[] jCuePoint,
long[] jTrackPosition);
private static native long GetBlock(long jCues, long jcp, long jtp);
private static native long GetCount(long jCues);
private static native long getElementSize(long jCues);
private static native long getElementStart(long jCues);
private static native long GetFirst(long jCues);
private static native long GetLast(long jCues);
private static native long GetNext(long jCues, long jCurrent);
private static native long getSegment(long jCues);
private static native long getSize(long jCues);
private static native long getStart(long jCues);
private static native boolean LoadCuePoint(long jCues);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class Display extends Common {
public String getCountry() {
return GetCountry(nativePointer);
}
public String getLanguage() {
return GetLanguage(nativePointer);
}
public String getString() {
return GetString(nativePointer);
}
protected Display(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
}
private static native String GetCountry(long jDisplay);
private static native String GetLanguage(long jDisplay);
private static native String GetString(long jDisplay);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class EbmlHeader extends Common {
public EbmlHeader() {
nativePointer = newEBMLHeader();
}
public String getDocType() {
return getDocType(nativePointer);
}
public long getDocTypeReadVersion() {
return getDocTypeReadVersion(nativePointer);
}
public long getDocTypeVersion() {
return getDocTypeVersion(nativePointer);
}
public long getMaxIdLength() {
return getMaxIdLength(nativePointer);
}
public long getMaxSizeLength() {
return getMaxSizeLength(nativePointer);
}
public long getReadVersion() {
return getReadVersion(nativePointer);
}
public long getVersion() {
return getVersion(nativePointer);
}
public void init() {
Init(nativePointer);
}
public long parse(IMkvReader mkvReader, long[] position) {
return Parse(nativePointer, mkvReader.getNativePointer(), position);
}
public void setDocType(String docType) {
setDocType(nativePointer, docType);
}
public void setDocTypeReadVersion(long docTypeReadVersion) {
setDocTypeReadVersion(nativePointer, docTypeReadVersion);
}
public void setDocTypeVersion(long docTypeVersion) {
setDocTypeVersion(nativePointer, docTypeVersion);
}
public void setMaxIdLength(long maxIdLength) {
setMaxIdLength(nativePointer, maxIdLength);
}
public void setMaxSizeLength(long maxSizeLength) {
setMaxSizeLength(nativePointer, maxSizeLength);
}
public void setReadVersion(long readVersion) {
setReadVersion(nativePointer, readVersion);
}
public void setVersion(long version) {
setVersion(nativePointer, version);
}
protected EbmlHeader(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteEBMLHeader(nativePointer);
}
private static native void deleteEBMLHeader(long jEbmlHeader);
private static native String getDocType(long jEbmlHeader);
private static native long getDocTypeReadVersion(long jEbmlHeader);
private static native long getDocTypeVersion(long jEbmlHeader);
private static native long getMaxIdLength(long jEbmlHeader);
private static native long getMaxSizeLength(long jEbmlHeader);
private static native long getReadVersion(long jEbmlHeader);
private static native long getVersion(long jEbmlHeader);
private static native void Init(long jEbmlHeader);
private static native long newEBMLHeader();
private static native long Parse(long jEbmlHeader, long jMkvReader, long[] jPosition);
private static native void setDocType(long jEbmlHeader, String jDocType);
private static native void setDocTypeReadVersion(long jEbmlHeader, long docTypeReadVersion);
private static native void setDocTypeVersion(long jEbmlHeader, long docTypeVersion);
private static native void setMaxIdLength(long jEbmlHeader, long maxIdLength);
private static native void setMaxSizeLength(long jEbmlHeader, long maxSizeLength);
private static native void setReadVersion(long jEbmlHeader, long readVersion);
private static native void setVersion(long jEbmlHeader, long version);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class Edition extends Common {
public Atom getAtom(int index) {
long pointer = GetAtom(nativePointer, index);
return new Atom(pointer);
}
public int getAtomCount() {
return GetAtomCount(nativePointer);
}
protected Edition(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
}
private static native long GetAtom(long jEdition, int index);
private static native int GetAtomCount(long jEdition);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class Entry extends Common {
public Entry() {
nativePointer = newEntry();
}
public long getElementSize() {
return getElementSize(nativePointer);
}
public long getElementStart() {
return getElementStart(nativePointer);
}
public long getId() {
return getId(nativePointer);
}
public long getPos() {
return getPos(nativePointer);
}
public void setElementSize(long elementSize) {
setElementSize(nativePointer, elementSize);
}
public void setElementStart(long elementStart) {
setElementStart(nativePointer, elementStart);
}
public void setId(long id) {
setId(nativePointer, id);
}
public void setPos(long pos) {
setPos(nativePointer, pos);
}
protected Entry(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteEntry(nativePointer);
}
private static native void deleteEntry(long jEntry);
private static native long getElementSize(long jEntry);
private static native long getElementStart(long jEntry);
private static native long getId(long jEntry);
private static native long getPos(long jEntry);
private static native long newEntry();
private static native void setElementSize(long jEntry, long element_size);
private static native void setElementStart(long jEntry, long element_start);
private static native void setId(long jEntry, long id);
private static native void setPos(long jEntry, long pos);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class Frame extends Common {
public Frame() {
nativePointer = newFrame();
}
public long getLen() {
return getLen(nativePointer);
}
public long getPos() {
return getPos(nativePointer);
}
public long read(IMkvReader mkvReader, byte[][] buffer) {
return Read(nativePointer, mkvReader.getNativePointer(), buffer);
}
public void setLen(long len) {
setLen(nativePointer, len);
}
public void setPos(long pos) {
setPos(nativePointer, pos);
}
protected Frame(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteFrame(nativePointer);
}
private static native void deleteFrame(long jFrame);
private static native long getLen(long jFrame);
private static native long getPos(long jFrame);
private static native long newFrame();
private static native long Read(long jFrame, long jMkvReader, byte[][] jBuffer);
private static native void setLen(long jFrame, long len);
private static native void setPos(long jFrame, long pos);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public abstract class IMkvReader extends Common {
public static IMkvReader newMkvReader(long nativePointer) {
IMkvReader mkvReader = null;
int type = getClassType(nativePointer);
if (type == 1) {
mkvReader = new MkvReader(nativePointer);
}
return mkvReader;
}
public abstract int length(long[] total, long[] available);
public abstract int read(long position, long length, byte[][] buffer);
protected IMkvReader() {
super();
}
protected IMkvReader(long nativePointer) {
super(nativePointer);
}
private static native int getClassType(long jMkvReader);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class Info extends Common {
public Info() {
nativePointer = newInfo();
}
public void clear() {
Clear(nativePointer);
}
public int copy(Info destination) {
return Copy(nativePointer, destination.getNativePointer());
}
public String getCodecId() {
return getCodecId(nativePointer);
}
public String getCodecNameAsUtf8() {
return getCodecNameAsUTF8(nativePointer);
}
public byte[] getCodecPrivate() {
return getCodecPrivate(nativePointer);
}
public boolean getLacing() {
return getLacing(nativePointer);
}
public String getNameAsUtf8() {
return getNameAsUTF8(nativePointer);
}
public long getNumber() {
return getNumber(nativePointer);
}
public Settings getSettings() {
long pointer = getSettings(nativePointer);
return new Settings(pointer);
}
public long getType() {
return getType(nativePointer);
}
public void setCodecId(String codecId) {
setCodecId(nativePointer, codecId);
}
public void setCodecNameAsUtf8(String codecNameAsUtf8) {
setCodecNameAsUTF8(nativePointer, codecNameAsUtf8);
}
public void setCodecPrivate(String codecPrivate) {
setCodecPrivate(nativePointer, codecPrivate);
}
public void setLacing(boolean lacing) {
setLacing(nativePointer, lacing);
}
public void setNameAsUtf8(String nameAsUtf8) {
setNameAsUTF8(nativePointer, nameAsUtf8);
}
public void setNumber(long number) {
setNumber(nativePointer, number);
}
public void setSettings(Settings settings) {
setSettings(nativePointer, settings.getNativePointer());
}
public void setType(long type) {
setType(nativePointer, type);
}
public void setUid(long uid) {
setUid(nativePointer, uid);
}
protected Info(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteInfo(nativePointer);
}
private static native void Clear(long jInfo);
private static native int Copy(long jInfo, long jDestination);
private static native void deleteInfo(long jInfo);
private static native String getCodecId(long jInfo);
private static native String getCodecNameAsUTF8(long jInfo);
private static native byte[] getCodecPrivate(long jInfo);
private static native boolean getLacing(long jInfo);
private static native String getNameAsUTF8(long jInfo);
private static native long getNumber(long jInfo);
private static native long getSettings(long jInfo);
private static native long getType(long jInfo);
private static native long newInfo();
private static native void setCodecId(long jInfo, String jCodecId);
private static native void setCodecNameAsUTF8(long jInfo, String jCodecNameAsUtf8);
private static native void setCodecPrivate(long jInfo, String jCodecPrivate);
private static native void setLacing(long jInfo, boolean lacing);
private static native void setNameAsUTF8(long jInfo, String jNameAsUtf8);
private static native void setNumber(long jInfo, long number);
private static native void setSettings(long jInfo, long jSettings);
private static native void setType(long jInfo, long type);
private static native void setUid(long jInfo, long uid);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public abstract class MkvParser extends Common {
public static final int E_BUFFER_NOT_FULL = -3;
public static final int E_FILE_FORMAT_INVALID = -2;
public static long getUintLength(IMkvReader mkvReader, long position, long[] length) {
return GetUIntLength(mkvReader.getNativePointer(), position, length);
}
public static void getVersion(int[] major, int[] minor, int[] build, int[] revision) {
GetVersion(major, minor, build, revision);
}
public static boolean match(IMkvReader mkvReader, long[] position, long id, long[] value) {
return MatchValue(mkvReader.getNativePointer(), position, id, value);
}
public static boolean match(IMkvReader mkvReader, long[] position, long id, byte[][] buffer) {
long[] bufferLength = {0};
return MatchBuffer(mkvReader.getNativePointer(), position, id, buffer, bufferLength);
}
public static long parseElementHeader(IMkvReader mkvReader, long[] position, long stop, long[] id,
long[] size) {
return ParseElementHeader(mkvReader.getNativePointer(), position, stop, id, size);
}
public static long readUint(IMkvReader mkvReader, long position, long[] length) {
return ReadUInt(mkvReader.getNativePointer(), position, length);
}
public static long unserializeFloat(IMkvReader mkvReader, long position, long size,
double[] result) {
return UnserializeFloat(mkvReader.getNativePointer(), position, size, result);
}
public static long unserializeInt(IMkvReader mkvReader, long position, long length,
long[] result) {
return UnserializeInt(mkvReader.getNativePointer(), position, length, result);
}
public static long unserializeString(IMkvReader mkvReader, long position, long size,
String[] str) {
return UnserializeString(mkvReader.getNativePointer(), position, size, str);
}
public static long unserializeUint(IMkvReader mkvReader, long position, long size) {
return UnserializeUInt(mkvReader.getNativePointer(), position, size);
}
private static native long GetUIntLength(long jMkvReader, long position, long[] jLength);
private static native void GetVersion(int[] jMajor, int[] jMinor, int[] jBuild, int[] jRevision);
private static native boolean MatchBuffer(long jMkvReader, long[] jPosition, long id,
byte[][] jBuffer, long[] jBufferLength);
private static native boolean MatchValue(long jMkvReader, long[] jPosition, long id,
long[] jValue);
private static native long ParseElementHeader(long jMkvReader, long[] jPosition, long stop,
long[] jId, long[] jSize);
private static native long ReadUInt(long jMkvReader, long position, long[] jLength);
private static native long UnserializeFloat(long jMkvReader, long position, long size,
double[] jResult);
private static native long UnserializeInt(long jMkvReader, long position, long length,
long[] jResult);
private static native long UnserializeString(long jMkvReader, long position, long size,
String[] jStr);
private static native long UnserializeUInt(long jMkvReader, long position, long size);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
public class MkvReader extends IMkvReader {
public MkvReader() {
nativePointer = newMkvReader();
}
public void close() {
Close(nativePointer);
}
@Override
public int length(long[] total, long[] available) {
return Length(nativePointer, total, available);
}
public int open(String fileName) {
return Open(nativePointer, fileName);
}
@Override
public int read(long position, long length, byte[][] buffer) {
return Read(nativePointer, position, length, buffer);
}
protected MkvReader(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteMkvReader(nativePointer);
}
private static native void Close(long jMkvReader);
private static native void deleteMkvReader(long jMkvReader);
private static native int Length(long jMkvReader, long[] jTotal, long[] jAvailable);
private static native long newMkvReader();
private static native int Open(long jMkvReader, String jFileName);
private static native int Read(long jMkvReader, long position, long length, byte[][] jBuffer);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class SeekHead extends Common {
public SeekHead(Segment segment, long start, long size, long elementStart, long elementSize) {
nativePointer = newSeekHead(segment.getNativePointer(), start, size, elementStart, elementSize);
}
public int getCount() {
return GetCount(nativePointer);
}
public long getElementSize() {
return getElementSize(nativePointer);
}
public long getElementStart() {
return getElementStart(nativePointer);
}
public Entry getEntry(int index) {
long pointer = GetEntry(nativePointer, index);
return new Entry(pointer);
}
public Segment getSegment() {
long pointer = getSegment(nativePointer);
return new Segment(pointer);
}
public long getSize() {
return getSize(nativePointer);
}
public long getStart() {
return getStart(nativePointer);
}
public VoidElement getVoidElement(int index) {
long pointer = GetVoidElement(nativePointer, index);
return new VoidElement(pointer);
}
public int getVoidElementCount() {
return GetVoidElementCount(nativePointer);
}
public long parse() {
return Parse(nativePointer);
}
protected SeekHead(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteSeekHead(nativePointer);
}
private static native void deleteSeekHead(long jSeekHead);
private static native int GetCount(long jSeekHead);
private static native long getElementSize(long jSeekHead);
private static native long getElementStart(long jSeekHead);
private static native long GetEntry(long jSeekHead, int idx);
private static native long getSegment(long jSeekHead);
private static native long getSize(long jSeekHead);
private static native long getStart(long jSeekHead);
private static native long GetVoidElement(long jSeekHead, int idx);
private static native int GetVoidElementCount(long jSeekHead);
private static native long newSeekHead(long jSegment, long start, long size, long element_start,
long element_size);
private static native long Parse(long jSeekHead);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class Segment extends Common {
public static long createInstance(IMkvReader mkvReader, long position, Segment[] segment) {
long[] jSegment = {0};
long result = CreateInstance(mkvReader.getNativePointer(), position, jSegment);
segment[0] = new Segment(jSegment[0]);
return result;
}
public boolean doneParsing() {
return DoneParsing(nativePointer);
}
public Cluster findCluster(long timeNanoseconds) {
long pointer = FindCluster(nativePointer, timeNanoseconds);
return new Cluster(pointer);
}
public Cluster findOrPreloadCluster(long position) {
long pointer = FindOrPreloadCluster(nativePointer, position);
return new Cluster(pointer);
}
public Chapters getChapters() {
long pointer = GetChapters(nativePointer);
return new Chapters(pointer);
}
public long getCount() {
return GetCount(nativePointer);
}
public Cues getCues() {
long pointer = GetCues(nativePointer);
return new Cues(pointer);
}
public long getDuration() {
return GetDuration(nativePointer);
}
public long getElementStart() {
return getElementStart(nativePointer);
}
public Cluster getEos() {
long pointer = getEos(nativePointer);
return new Cluster(pointer);
}
public Cluster getFirst() {
long pointer = GetFirst(nativePointer);
return new Cluster(pointer);
}
public SegmentInfo getInfo() {
long pointer = GetInfo(nativePointer);
return new SegmentInfo(pointer);
}
public Cluster getLast() {
long pointer = GetLast(nativePointer);
return new Cluster(pointer);
}
public Cluster getNext(Cluster current) {
long pointer = GetNext(nativePointer, current.getNativePointer());
return new Cluster(pointer);
}
public IMkvReader getReader() {
long pointer = getReader(nativePointer);
return IMkvReader.newMkvReader(pointer);
}
public SeekHead getSeekHead() {
long pointer = GetSeekHead(nativePointer);
return new SeekHead(pointer);
}
public long getSize() {
return getSize(nativePointer);
}
public long getStart() {
return getStart(nativePointer);
}
public Tracks getTracks() {
long pointer = GetTracks(nativePointer);
return new Tracks(pointer);
}
public long load() {
return Load(nativePointer);
}
public long loadCluster() {
return LoadClusterWithoutPosition(nativePointer);
}
public long loadCluster(long[] position, long[] size) {
return LoadClusterAndPosition(nativePointer, position, size);
}
public long parseCues(long cuesOffset, long[] position, long[] length) {
return ParseCues(nativePointer, cuesOffset, position, length);
}
public long parseHeaders() {
return ParseHeaders(nativePointer);
}
public long parseNext(Cluster current, Cluster[] next, long[] position, long[] size) {
long[] jNext = {0};
long result = ParseNext(nativePointer, current.getNativePointer(), jNext, position, size);
next[0] = new Cluster(jNext[0]);
return result;
}
public void setEos(Cluster eos) {
setEos(nativePointer, eos.getNativePointer());
}
protected Segment(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteSegment(nativePointer);
}
private static native long CreateInstance(long jMkvReader, long position, long[] jSegment);
private static native void deleteSegment(long jSegment);
private static native boolean DoneParsing(long jSegment);
private static native long FindCluster(long jSegment, long time_nanoseconds);
private static native long FindOrPreloadCluster(long jSegment, long position);
private static native long GetChapters(long jSegment);
private static native long GetCount(long jSegment);
private static native long GetCues(long jSegment);
private static native long GetDuration(long jSegment);
private static native long getElementStart(long jSegment);
private static native long getEos(long jSegment);
private static native long GetFirst(long jSegment);
private static native long GetInfo(long jSegment);
private static native long GetLast(long jSegment);
private static native long GetNext(long jSegment, long jCurrent);
private static native long getReader(long jSegment);
private static native long GetSeekHead(long jSegment);
private static native long getSize(long jSegment);
private static native long getStart(long jSegment);
private static native long GetTracks(long jSegment);
private static native long Load(long jSegment);
private static native long LoadClusterAndPosition(long jSegment, long[] jPosition, long[] jSize);
private static native long LoadClusterWithoutPosition(long jSegment);
private static native long ParseCues(long jSegment, long cues_off, long[] jPosition,
long[] jLength);
private static native long ParseHeaders(long jSegment);
private static native long ParseNext(long jSegment, long jCurrent, long[] jNext, long[] jPosition,
long[] jSize);
private static native void setEos(long jSegment, long jEos);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class SegmentInfo extends Common {
public SegmentInfo(Segment segment, long start, long size, long elementStart, long elementSize) {
nativePointer =
newSegmentInfo(segment.getNativePointer(), start, size, elementStart, elementSize);
}
public long getDuration() {
return GetDuration(nativePointer);
}
public long getElementSize() {
return getElementSize(nativePointer);
}
public long getElementStart() {
return getElementStart(nativePointer);
}
public String getMuxingAppAsUtf8() {
return GetMuxingAppAsUTF8(nativePointer);
}
public Segment getSegment() {
long pointer = getSegment(nativePointer);
return new Segment(pointer);
}
public long getSize() {
return getSize(nativePointer);
}
public long getStart() {
return getStart(nativePointer);
}
public long getTimeCodeScale() {
return GetTimeCodeScale(nativePointer);
}
public String getTitleAsUtf8() {
return GetTitleAsUTF8(nativePointer);
}
public String getWritingAppAsUtf8() {
return GetWritingAppAsUTF8(nativePointer);
}
public long Parse() {
return Parse(nativePointer);
}
protected SegmentInfo(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteSegmentInfo(nativePointer);
}
private static native void deleteSegmentInfo(long jSegmentInfo);
private static native long GetDuration(long jSegmentInfo);
private static native long getElementSize(long jSegmentInfo);
private static native long getElementStart(long jSegmentInfo);
private static native String GetMuxingAppAsUTF8(long jSegmentInfo);
private static native long getSegment(long jSegmentInfo);
private static native long getSize(long jSegmentInfo);
private static native long getStart(long jSegmentInfo);
private static native long GetTimeCodeScale(long jSegmentInfo);
private static native String GetTitleAsUTF8(long jSegmentInfo);
private static native String GetWritingAppAsUTF8(long jSegmentInfo);
private static native long newSegmentInfo(long jSegment, long start, long size,
long element_start, long element_size);
private static native long Parse(long jSegmentInfo);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class Settings extends Common {
public Settings() {
nativePointer = newSettings();
}
public long getSize() {
return getSize(nativePointer);
}
public long getStart() {
return getStart(nativePointer);
}
public void setSize(long size) {
setSize(nativePointer, size);
}
public void setStart(long start) {
setStart(nativePointer, start);
}
protected Settings(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteSettings(nativePointer);
}
private static native void deleteSettings(long jSettings);
private static native long getSize(long jSettings);
private static native long getStart(long jSettings);
private static native long newSettings();
private static native void setSize(long jSettings, long size);
private static native void setStart(long jSettings, long start);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
public class SimpleBlock extends BlockEntry {
public SimpleBlock(Cluster cluster, long index, long start, long size) {
nativePointer = newSimpleBlock(cluster.getNativePointer(), index, start, size);
}
@Override
public Block getBlock() {
long pointer = GetBlock(nativePointer);
return new Block(pointer);
}
@Override
public Kind getKind() {
int ordinal = GetKind(nativePointer);
return Kind.values()[ordinal];
}
public long Parse() {
return Parse(nativePointer);
}
protected SimpleBlock(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteSimpleBlock(nativePointer);
}
private static native void deleteSimpleBlock(long jSimpleBlock);
private static native long GetBlock(long jSimpleBlock);
private static native int GetKind(long jSimpleBlock);
private static native long newSimpleBlock(long jCluster, long index, long start, long size);
private static native long Parse(long jSimpleBlock);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class Track extends Common {
public enum Type {
None,
kVideo,
kAudio
};
public static long create(Segment segment, Info info, long element_start, long element_size,
Track[] track) {
long[] jTrack = {0};
long result = Create(segment.getNativePointer(), info.getNativePointer(), element_start,
element_size, jTrack);
track[0] = Track.newTrack(jTrack[0]);
return result;
}
public static Track newTrack(long nativePointer) {
Track track = null;
int type = getClassType(nativePointer);
if (type == 1) {
track = new AudioTrack(nativePointer);
} else if (type == 2) {
track = new Track(nativePointer);
} else if (type == 3) {
track = new VideoTrack(nativePointer);
}
return track;
}
public String getCodecId() {
return GetCodecId(nativePointer);
}
public String getCodecNameAsUtf8() {
return GetCodecNameAsUTF8(nativePointer);
}
public byte[] getCodecPrivate(long[] size) {
return GetCodecPrivate(nativePointer, size);
}
public ContentEncoding getContentEncodingByIndex(long idx) {
long pointer = GetContentEncodingByIndex(nativePointer, idx);
return new ContentEncoding(pointer);
}
public long getContentEncodingCount() {
return GetContentEncodingCount(nativePointer);
}
public long getElementSize() {
return getElementSize(nativePointer);
}
public long getElementStart() {
return getElementStart(nativePointer);
}
public BlockEntry getEos() {
long pointer = GetEOS(nativePointer);
return BlockEntry.newBlockEntry(pointer);
}
public long getFirst(BlockEntry[] blockEntry) {
long[] jBlockEntry = {0};
long result = GetFirst(nativePointer, jBlockEntry);
blockEntry[0] = BlockEntry.newBlockEntry(jBlockEntry[0]);
return result;
}
public boolean getLacing() {
return GetLacing(nativePointer);
}
public String getNameAsUtf8() {
return GetNameAsUTF8(nativePointer);
}
public long getNext(BlockEntry current, BlockEntry[] next) {
long[] jNext = {0};
long result = GetNext(nativePointer, current.getNativePointer(), jNext);
next[0] = BlockEntry.newBlockEntry(jNext[0]);
return result;
}
public long getNumber() {
return GetNumber(nativePointer);
}
public Segment getSegment() {
long pointer = getSegment(nativePointer);
return new Segment(pointer);
}
public Type getType() {
int ordinal = (int) GetType(nativePointer);
return Type.values()[ordinal];
}
public long getUid() {
return GetUid(nativePointer);
}
public long parseContentEncodingsEntry(long start, long size) {
return ParseContentEncodingsEntry(nativePointer, start, size);
}
public long seek(long time_ns, BlockEntry[] result) {
long[] jResult = {0};
long output = Seek(nativePointer, time_ns, jResult);
result[0] = BlockEntry.newBlockEntry(jResult[0]);
return output;
}
public boolean vetEntry(BlockEntry blockEntry) {
return VetEntry(nativePointer, blockEntry.getNativePointer());
}
protected Track(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteTrack(nativePointer);
}
private static native long Create(long jSegment, long jInfo, long element_start,
long element_size, long[] jTrack);
private static native void deleteTrack(long jTrack);
private static native int getClassType(long jTrack);
private static native String GetCodecId(long jTrack);
private static native String GetCodecNameAsUTF8(long jTrack);
private static native byte[] GetCodecPrivate(long jTrack, long[] jSize);
private static native long GetContentEncodingByIndex(long jTrack, long idx);
private static native long GetContentEncodingCount(long jTrack);
private static native long getElementSize(long jTrack);
private static native long getElementStart(long jTrack);
private static native long GetEOS(long jTrack);
private static native long GetFirst(long jTrack, long[] jBlockEntry);
private static native boolean GetLacing(long jTrack);
private static native String GetNameAsUTF8(long jTrack);
private static native long GetNext(long jTrack, long jCurrent, long[] jNext);
private static native long GetNumber(long jTrack);
private static native long getSegment(long jTrack);
private static native long GetType(long jTrack);
private static native long GetUid(long jTrack);
private static native long ParseContentEncodingsEntry(long jTrack, long start, long size);
private static native long Seek(long jTrack, long time_ns, long[] jResult);
private static native boolean VetEntry(long jTrack, long jBlockEntry);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class TrackPosition extends Common {
public TrackPosition() {
nativePointer = newTrackPosition();
}
public long getBlock() {
return getBlock(nativePointer);
}
public long getPos() {
return getPos(nativePointer);
}
public long getTrack() {
return getTrack(nativePointer);
}
public void parse(IMkvReader mkvReader, long start, long size) {
Parse(nativePointer, mkvReader.getNativePointer(), start, size);
}
public void setBlock(long block) {
setBlock(nativePointer, block);
}
public void setPos(long pos) {
setPos(nativePointer, pos);
}
public void setTrack(long track) {
setTrack(nativePointer, track);
}
protected TrackPosition(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteTrackPosition(nativePointer);
}
private static native void deleteTrackPosition(long jTrackPosition);
private static native long getBlock(long jTrackPosition);
private static native long getPos(long jTrackPosition);
private static native long getTrack(long jTrackPosition);
private static native long newTrackPosition();
private static native void Parse(long jTrackPosition, long jMkvReader, long start, long size);
private static native void setBlock(long jTrackPosition, long block);
private static native void setPos(long jTrackPosition, long pos);
private static native void setTrack(long jTrackPosition, long track);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class Tracks extends Common {
public Tracks(Segment segment, long start, long size, long element_start, long element_size) {
nativePointer = newTracks(segment.getNativePointer(), start, size, element_start, element_size);
}
public long getElementSize() {
return getElementSize(nativePointer);
}
public long getElementStart() {
return getElementStart(nativePointer);
}
public Segment getSegment() {
long pointer = getSegment(nativePointer);
return new Segment(pointer);
}
public long getSize() {
return getSize(nativePointer);
}
public long getStart() {
return getStart(nativePointer);
}
public Track getTrackByIndex(long idx) {
long pointer = GetTrackByIndex(nativePointer, idx);
return Track.newTrack(pointer);
}
public Track getTrackByNumber(long tn) {
long pointer = GetTrackByNumber(nativePointer, tn);
return Track.newTrack(pointer);
}
public long getTracksCount() {
return GetTracksCount(nativePointer);
}
public long Parse() {
return Parse(nativePointer);
}
protected Tracks(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteTracks(nativePointer);
}
private static native void deleteTracks(long jTracks);
private static native long getElementSize(long jTracks);
private static native long getElementStart(long jTracks);
private static native long getSegment(long jTracks);
private static native long getSize(long jTracks);
private static native long getStart(long jTracks);
private static native long GetTrackByIndex(long jTracks, long idx);
private static native long GetTrackByNumber(long jTracks, long tn);
private static native long GetTracksCount(long jTracks);
private static native long newTracks(long jSegment, long start, long size, long element_start,
long element_size);
private static native long Parse(long jTracks);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
public class VideoTrack extends Track {
public static long parse(Segment segment, Info info, long element_start, long element_size,
VideoTrack[] videoTrack) {
long[] jVideoTrack = {0};
long result = Parse(segment.getNativePointer(), info.getNativePointer(), element_start,
element_size, jVideoTrack);
videoTrack[0] = new VideoTrack(jVideoTrack[0]);
return result;
}
public double getFrameRate() {
return GetFrameRate(nativePointer);
}
public long getHeight() {
return GetHeight(nativePointer);
}
public long getWidth() {
return GetWidth(nativePointer);
}
@Override
public long seek(long time_ns, BlockEntry[] result) {
long[] jResult = {0};
long output = Seek(nativePointer, time_ns, jResult);
result[0] = BlockEntry.newBlockEntry(jResult[0]);
return output;
}
@Override
public boolean vetEntry(BlockEntry blockEntry) {
return VetEntry(nativePointer, blockEntry.getNativePointer());
}
protected VideoTrack(long nativePointer) {
super(nativePointer);
}
private static native double GetFrameRate(long jVideoTrack);
private static native long GetHeight(long jVideoTrack);
private static native long GetWidth(long jVideoTrack);
private static native long Parse(long jSegment, long jInfo, long element_start, long element_size,
long[] jVideoTrack);
private static native long Seek(long jVideoTrack, long time_ns, long[] jResult);
private static native boolean VetEntry(long jVideoTrack, long jBlockEntry);
}
// Author: mszal@google.com (Michael Szal)
package com.google.libwebm.mkvparser;
import com.google.libwebm.Common;
public class VoidElement extends Common {
public VoidElement() {
nativePointer = newVoidElement();
}
public long getElementSize() {
return getElementSize(nativePointer);
}
public long getElementStart() {
return getElementStart(nativePointer);
}
public void setElementSize(long elementSize) {
setElementSize(nativePointer, elementSize);
}
public void setElementStart(long elementStart) {
setElementStart(nativePointer, elementStart);
}
protected VoidElement(long nativePointer) {
super(nativePointer);
}
@Override
protected void deleteObject() {
deleteVoidElement(nativePointer);
}
private static native void deleteVoidElement(long jVoidElement);
private static native long getElementSize(long jVoidElement);
private static native long getElementStart(long jVoidElement);
private static native long newVoidElement();
private static native void setElementSize(long jVoidElement, long element_size);
private static native void setElementStart(long jVoidElement, long element_start);
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Element.java
*
*
*/
package org.ebml;
/**
* Defines the basic EBML element. Subclasses may provide child element
* access.
* Created on November 19, 2002, 9:11 PM
* @author John Cannon
*/
public class BinaryElement extends Element {
/*private byte[] type = {
0x00};*/
private static int MIN_SIZE_LENGTH = 4;
//private long size = 0;
//protected byte[] data;
/*
* Creates a new instance of Element
@param type The type ID of this element
*/
public BinaryElement(byte[] type) {
super(type);
}
/** Getter for property data.
* @return Value of property data.
*
*/
public byte[] getData() {
return this.data;
}
/** Setter for property data.
* @param data New value of property data.
*
*/
public void setData(byte[] data) {
this.data = data;
this.size = data.length;
}
/** Getter for property size.
* @return Value of property size.
*
*/
public long getSize() {
return size;
}
/** Setter for property size.
* @param size New value of property size.
*
*/
public void setSize(long size) {
this.size = size;
}
/** Getter for property type.
* @return Value of property type.
*
*/
public byte[] getType() {
return type;
}
/** Setter for property type.
* @param type New value of property type.
*
*/
public void setType(byte[] type) {
this.type = type;
}
public byte[] toByteArray() {
byte[] head = makeEbmlCode(type, size);
byte[] ret = new byte[head.length + data.length];
org.ebml.util.ArrayCopy.arraycopy(head, 0, ret, 0, head.length);
org.ebml.util.ArrayCopy.arraycopy(data, 0, ret, head.length, data.length);
return ret;
}
public static void setMinSizeLength(int minSize) {
MIN_SIZE_LENGTH = minSize;
}
public static int getMinSizeLength() {
return MIN_SIZE_LENGTH;
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml;
import java.util.*;
public class DateElement extends SignedIntegerElement {
//const uint64 EbmlDate::UnixEpochDelay = 978307200; // 2001/01/01 00:00:00 UTC
public static long UnixEpochDelay = 978307200; // 2001/01/01 00:00:00 UTC
private static int MIN_SIZE_LENGTH = 8;
public DateElement(byte[] type) {
super(type);
}
/**
* Set the Date of this element
* @param value Date to set
*/
public void setDate(Date value) {
long val = (value.getTime() - UnixEpochDelay) * 1000000000;
setData(packInt(val, MIN_SIZE_LENGTH));
}
/**
* Get the Date value of this element
* @return Date of this element
*/
public Date getDate() {
/*
Date begin = new Date(0);
Date start = new Date(1970, 1, 1, 0, 0, 0);
Date end = new Date(2001, 1, 1, 0, 0, 0);
long diff0 = begin.getTime();
long diff1 = start.getTime();
long diff2 = end.getTime();
long diff3 = Date.UTC(2001, 1, 1, 0, 0, 0) - Date.UTC(1970, 1, 1, 0, 0, 0);
*/
long val = getValue();;
val = val / 1000000000 + UnixEpochDelay;
return new Date(val);
}
/**
* It's not recommended to use this method.
* Use the setDate(Date) method instead.
*/
public void setValue(long value)
{
setData(packInt(value, MIN_SIZE_LENGTH));
}
}
\ No newline at end of file
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml;
public interface DocType {
public ElementType getElements();
public Element createElement(ElementType type);
public Element createElement(byte [] type);
}
\ No newline at end of file
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml;
import org.ebml.io.*;
import org.ebml.util.*;
/**
* EBMLReader.java
*
* Created on November 18, 2002, 4:03 PM
*
* @version 1.0
*/
/**
* <h1>JEBML Intro</h1>
* <hr>
* <p>The following are the basic steps of how reading in JEBML works.</p>
* <ul>
* <li>1. The EbmlReader class reads the element header (id+size) and
* looks it up in the supplied DocType class.
* <li>2. The correct element type (Binary, UInteger, String, etc) is
* created using the DocType data, BinaryElement is default
* element type for unknown elements.
* <li>3. The MatroskaDocType has the ids of all the elements staticly
* declared.
* <br>So to easily find out what an element is, you can use some code
* like the following code
* <p>
* <code>
* Element level1; <br>
* // ... fill level1 <br>
* if (level1.equals(MatroskaDocType.SegmentInfo_Id)) { <br>
* // Your Code Here <br>
* } <br>
* </code>
* </p>
* <li>4. To get the actual data for an Element you call the readData
* method, if you just want to skip it use skipData().
* <li>5. MasterElements are special, they have the readNextChild()
* method which returns the next child element, returning null
* when all the children have been read (it keeps track of the
* current inputstream position).
* <li>The usage method for JEBML is very close to libebml/libmatroska.
* </ul>
* <hr>
*
* Reads EBML elements from a <code>DataSource</code> and looks them up
* in the provided <code>DocType</code>.
*
* @author (c) 2002 John Cannon
* @author (c) 2004 Jory Stone
*/
public class EBMLReader {
protected DataSource source;
protected DocType doc;
protected ElementType elementTypes;
protected ElementType lastElementType;
/** Creates a new <code>EBMLReader</code> reading from the <code>DataSource
* source</code>. The <code>DocType doc</code> is used to validate the
* document.
*
* @param source DataSource to read from
* @param doc DocType to use to validate the docment
*/
public EBMLReader(DataSource source, DocType doc) {
this.source = source;
this.doc = doc;
this.elementTypes = doc.getElements();
}
public Element readNextElement() {
//Read the type.
byte[] elementType = readEBMLCodeAsBytes(source);
if (elementType == null)
// Failed to read type id
return null;
//Read the size.
byte[] data = getEBMLCodeAsBytes(source);
long elementSize = parseEBMLCode(data);
if (elementSize == 0)
// Zero sized element is valid
;//return null;
Element elem = null;
//lastElementType = elementTypes.findElement(elementType);
//if (lastElementType == null) {
// lastElementType = new UnknownElementType(elementType);
//}
//elem = doc.createElement(lastElementType);
elem = doc.createElement(elementType);
if (elem == null) {
return null;
}
//Set it's size
elem.setSize(elementSize);
elem.setHeaderSize(data.length);
//Setup a buffer for it's data
//byte[] elementData = new byte[(int)elementSize];
//Read the data
//source.read(elementData, 0, elementData.length);
//Set the data property on the element
//elem.setData(elementData);
//System.out.println("EBMLReader.readNextElement() returning element " + elem.getElementType().name + " with size " + Long.toString(elem.getTotalSize()-elementSize)+" "+Long.toString(elementSize));
//Return the element
return elem;
}
static public byte[] getEBMLCodeAsBytes(DataSource source) {
//Begin loop with byte set to newly read byte.
byte firstByte = source.readByte();
int numBytes = 0;
//Begin by counting the bits unset before the first '1'.
long mask = 0x0080;
for (int i = 0; i < 8; i++) {
//Start at left, shift to right.
if ((firstByte & mask) == mask) { //One found
//Set number of bytes in size = i+1 ( we must count the 1 too)
numBytes = i + 1;
//exit loop by pushing i out of the limit
i = 8;
}
mask >>>= 1;
}
if (numBytes == 0)
// Invalid size
return null;
//Setup space to store the bits
byte[] data = new byte[numBytes];
//Clear the 1 at the front of this byte, all the way to the beginning of the size
data[0] = (byte)(firstByte & ((0xFF >>> (numBytes))));
if (numBytes > 1) {
//Read the rest of the size.
source.read(data, 1, numBytes - 1);
}
return data;
}
/**
* Reads an (Unsigned) EBML code from the DataSource and encodes it into a long. This size should be
* cast into an int for actual use as Java only allows upto 32-bit file I/O operations.
*
* @return ebml size
*/
static public long readEBMLCode(DataSource source) {
//Begin loop with byte set to newly read byte.
byte firstByte = source.readByte();
int numBytes = 0;
//Begin by counting the bits unset before the first '1'.
long mask = 0x0080;
for (int i = 0; i < 8; i++) {
//Start at left, shift to right.
if ((firstByte & mask) == mask) { //One found
//Set number of bytes in size = i+1 ( we must count the 1 too)
numBytes = i + 1;
//exit loop by pushing i out of the limit
i = 8;
}
mask >>>= 1;
}
if (numBytes == 0)
// Invalid size
return 0;
//Setup space to store the bits
byte[] data = new byte[numBytes];
//Clear the 1 at the front of this byte, all the way to the beginning of the size
data[0] = (byte)(firstByte & ((0xFF >>> (numBytes))));
if (numBytes > 1) {
//Read the rest of the size.
source.read(data, 1, numBytes - 1);
}
//Put this into a long
long size = 0;
long n = 0;
for (int i = 0; i < numBytes; i++) {
n = ((long)data[numBytes - 1 - i] << 56) >>> 56;
size = size | (n << (8 * i));
}
return size;
}
public static long parseEBMLCode(byte[] data) {
if(data==null)
return 0;
//Put this into a long
long size = 0;
long n = 0;
for (int i = 0; i < data.length; i++) {
n = ((long)data[data.length - 1 - i] << 56) >>> 56;
size = size | (n << (8 * i));
}
return size;
}
/**
* Reads an (Unsigned) EBML code from the DataSource and encodes it into a long. This size should be
* cast into an int for actual use as Java only allows upto 32-bit file I/O operations.
*
* @return ebml size
*/
static public long readEBMLCode(byte [] source)
{
return readEBMLCode(source, 0);
}
/**
* Reads an (Unsigned) EBML code from the DataSource and encodes it into a long. This size should be
* cast into an int for actual use as Java only allows upto 32-bit file I/O operations.
*
* @return ebml size
*/
static public long readEBMLCode(byte [] source, int offset)
{
//Begin loop with byte set to newly read byte.
byte firstByte = source[offset];
int numBytes = 0;
//Begin by counting the bits unset before the first '1'.
long mask = 0x0080;
for (int i = 0; i < 8; i++)
{
//Start at left, shift to right.
if ((firstByte & mask) == mask)
{ //One found
//Set number of bytes in size = i+1 ( we must count the 1 too)
numBytes = i + 1;
//exit loop by pushing i out of the limit
i = 8;
}
mask >>>= 1;
}
if (numBytes == 0)
// Invalid size
return 0;
//Setup space to store the bits
byte[] data = new byte[numBytes];
//Clear the 1 at the front of this byte, all the way to the beginning of the size
data[0] = (byte)(firstByte & ((0xFF >>> (numBytes))));
if (numBytes > 1)
{
//Read the rest of the size.
ArrayCopy.arraycopy(data, 1, source, offset+1, numBytes - 1);
}
//Put this into a long
long size = 0;
long n = 0;
for (int i = 0; i < numBytes; i++)
{
n = ((long)data[numBytes - 1 - i] << 56) >>> 56;
size = size | (n << (8 * i));
}
return size;
}
/**
* Reads an Signed EBML code from the DataSource and encodes it into a long. This size should be
* cast into an int for actual use as Java only allows upto 32-bit file I/O operations.
*
* @return ebml size
*/
static public long readSignedEBMLCode(byte [] source)
{
return readSignedEBMLCode(source, 0);
}
/**
* Reads an Signed EBML code from the DataSource and encodes it into a long. This size should be
* cast into an int for actual use as Java only allows upto 32-bit file I/O operations.
*
* @return ebml size
*/
static public long readSignedEBMLCode(byte [] source, int offset)
{
//Begin loop with byte set to newly read byte.
byte firstByte = source[offset];
int numBytes = 0;
//Begin by counting the bits unset before the first '1'.
long mask = 0x0080;
for (int i = 0; i < 8; i++)
{
//Start at left, shift to right.
if ((firstByte & mask) == mask)
{ //One found
//Set number of bytes in size = i+1 ( we must count the 1 too)
numBytes = i + 1;
//exit loop by pushing i out of the limit
i = 8;
}
mask >>>= 1;
}
if (numBytes == 0)
// Invalid size
return 0;
//Setup space to store the bits
byte[] data = new byte[numBytes];
//Clear the 1 at the front of this byte, all the way to the beginning of the size
data[0] = (byte)(firstByte & ((0xFF >>> (numBytes))));
if (numBytes > 1)
{
//Read the rest of the size.
ArrayCopy.arraycopy(data, 1, source, offset+1, numBytes - 1);
}
//Put this into a long
long size = 0;
long n = 0;
for (int i = 0; i < numBytes; i++)
{
n = ((long)data[numBytes - 1 - i] << 56) >>> 56;
size = size | (n << (8 * i));
}
// Sign it ;)
if (numBytes == 1)
{
size -= 63;
}
else if (numBytes == 2)
{
size -= 8191;
}
else if (numBytes == 3)
{
size -= 1048575;
}
else if (numBytes == 4)
{
size -= 134217727;
}
return size;
}
/**
* Reads an Signed EBML code from the DataSource and encodes it into a long. This size should be
* cast into an int for actual use as Java only allows upto 32-bit file I/O operations.
*
* @return ebml size
*/
static public long readSignedEBMLCode(DataSource source) {
//Begin loop with byte set to newly read byte.
byte firstByte = source.readByte();
int numBytes = 0;
//Begin by counting the bits unset before the first '1'.
long mask = 0x0080;
for (int i = 0; i < 8; i++) {
//Start at left, shift to right.
if ((firstByte & mask) == mask) { //One found
//Set number of bytes in size = i+1 ( we must count the 1 too)
numBytes = i + 1;
//exit loop by pushing i out of the limit
i = 8;
}
mask >>>= 1;
}
if (numBytes == 0)
// Invalid size
return 0;
//Setup space to store the bits
byte[] data = new byte[numBytes];
//Clear the 1 at the front of this byte, all the way to the beginning of the size
data[0] = (byte)(firstByte & ((0xFF >>> (numBytes))));
if (numBytes > 1) {
//Read the rest of the size.
source.read(data, 1, numBytes - 1);
}
//Put this into a long
long size = 0;
long n = 0;
for (int i = 0; i < numBytes; i++) {
n = ((long)data[numBytes - 1 - i] << 56) >>> 56;
size = size | (n << (8 * i));
}
// Sign it ;)
if (numBytes == 1) {
size -= 63;
} else if (numBytes == 2) {
size -= 8191;
} else if (numBytes == 3) {
size -= 1048575;
} else if (numBytes == 4) {
size -= 134217727;
}
return size;
}
/**
*Reads an EBML code from the DataSource.
*
* @return byte array filled with the ebml size, (size bits included)
*/
static public byte[] readEBMLCodeAsBytes(DataSource source) {
//Begin loop with byte set to newly read byte.
byte firstByte = source.readByte();
int numBytes = 0;
//Begin by counting the bits unset before the first '1'.
long mask = 0x0080;
for (int i = 0; i < 8; i++) {
//Start at left, shift to right.
if ((firstByte & mask) == mask) { //One found
//Set number of bytes in size = i+1 ( we must count the 1 too)
numBytes = i + 1;
//exit loop by pushing i out of the limit
i = 8;
}
mask >>>= 1;
}
if (numBytes == 0)
// Invalid element
return null;
//Setup space to store the bits
byte[] data = new byte[numBytes];
//Clear the 1 at the front of this byte, all the way to the beginning of the size
data[0] = (byte)((firstByte));// & ((0xFF >>> (numBytes))));
if (numBytes > 1) {
//Read the rest of the size.
source.read(data, 1, numBytes - 1);
}
return data;
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml;
import org.ebml.io.*;
/**
* Summary description for EBMLWriter.
*/
public class EBMLWriter
{
protected DataWriter writer;
/** Creates a new <code>EBMLReader</code> reading from the <code>DataSource
* source</code>. The <code>DocType doc</code> is used to validate the
* document.
*
* @param source DataSource to read from
* @param doc DocType to use to validate the docment
*/
public EBMLWriter(DataWriter writer)
{
this.writer = writer;
}
public long writeElement(Element elem)
{
return elem.writeHeaderData(writer) + elem.writeData(writer);
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml;
/*
* Element.java
*
* Created on November 19, 2002, 9:11 PM
*/
import org.ebml.io.*;
import org.ebml.util.*;
/**
* Defines the basic EBML element. Subclasses may provide child element access.
* @author John Cannon
*/
public class Element {
protected Element parent;
protected ElementType typeInfo;
protected byte[] type = {
0x00};
private static int MIN_SIZE_LENGTH = 0;
protected long size = 0;
protected byte[] data;
protected boolean dataRead = false;
private int headerSize;
/** Creates a new instance of Element */
public Element(byte[] type) {
this.type = type;
}
/** Read the element data
*/
public void readData(DataSource source) {
//Setup a buffer for it's data
this.data = new byte[(int)size];
//Read the data
source.read(this.data, 0, this.data.length);
dataRead = true;
}
/** Skip the element data
*/
public void skipData(DataSource source) {
if (!dataRead) {
// Skip the data
source.skip(size);
dataRead = true;
}
}
public long writeElement(DataWriter writer)
{
return writeHeaderData(writer) + writeData(writer);
}
/** Write the element header data.
* Override this in sub-classes for more specialized writing.
*/
public long writeHeaderData(DataWriter writer)
{
long len = 0;
byte [] type = getType();
len += type.length;
writer.write(type);
byte [] size = Element.makeEbmlCodedSize(getSize());
len += size.length;
writer.write(size);
return len;
}
/** Write the element data.
* Override this in sub-classes for more specialized writing.
*/
public long writeData(DataWriter writer)
{
return writer.write(this.data, 0, this.data.length);
}
/** Getter for property data.
* @return Value of property data.
*
*/
public byte[] getData() {
return this.data;
}
/** Setter for property data.
* @param data New value of property data.
*
*/
public void setData(byte[] data) {
this.data = data;
this.size = data.length;
}
/** Clears the data of this element, useful if you just want
* this element to be a placeholder
*/
public void clearData()
{
this.data = null;
}
/** Getter for property size.
* @return Value of property size.
*
*/
public long getSize() {
return size;
}
/** Setter for property size.
* @param size New value of property size.
*
*/
public void setSize(long size) {
this.size = size;
}
/** Get the total size of this element
*/
public long getTotalSize()
{
long totalSize = 0;
totalSize += getType().length;
//totalSize += Element.codedSizeLength(getSize());
totalSize += this.headerSize;
totalSize += getSize();
return totalSize;
}
/** Getter for property type.
* @return Value of property type.
*
*/
public byte[] getType() {
return type;
}
/** Setter for property type.
* @param type New value of property type.
*
*/
public void setType(byte[] type) {
this.type = type;
}
public void setElementType(ElementType typeInfo) {
this.typeInfo = typeInfo;
}
public ElementType getElementType() {
return typeInfo;
}
/** Getter for property parent.
* @return Value of property parent.
*
*/
public Element getParent() {
return this.parent;
}
/** Setter for property parent.
* @param parent New value of property parent.
*
*/
public void setParent(Element parent) {
this.parent = parent;
}
public byte[] toByteArray() {
byte[] head = makeEbmlCode(type, size);
byte[] ret = new byte[head.length + data.length];
org.ebml.util.ArrayCopy.arraycopy(head, 0, ret, 0, head.length);
org.ebml.util.ArrayCopy.arraycopy(data, 0, ret, head.length, data.length);
return ret;
}
public boolean equals(byte [] typeId) {
return ElementType.compareIDs(this.type, typeId);
}
public boolean equals(ElementType elemType) {
return this.equals(elemType.id);
}
public static void setMinSizeLength(int minSize) {
MIN_SIZE_LENGTH = minSize;
}
public static int getMinSizeLength() {
return MIN_SIZE_LENGTH;
}
public static byte[] makeEbmlCode(byte[] typeID, long size) {
int codedLen = codedSizeLength(size);
byte[] ret = new byte[typeID.length + codedLen];
ArrayCopy.arraycopy(typeID, 0, ret, 0, typeID.length);
byte[] codedSize = makeEbmlCodedSize(size);
ArrayCopy.arraycopy(codedSize, 0, ret, typeID.length, codedSize.length);
return ret;
}
public static byte[] makeEbmlCodedSize(long size) {
int len = codedSizeLength(size);
byte[] ret = new byte[len];
//byte[] packedSize = packIntUnsigned(size);
long mask = 0x00000000000000FFL;
for (int i = 0; i < len; i++) {
ret[len - 1 - i] = (byte)((size & mask) >>> (i * 8));
mask <<= 8;
}
//The first size bits should be clear, otherwise we have an error in the size determination.
ret[0] |= 0x80 >> (len - 1);
return ret;
}
public static int getMinByteSize(long value) {
if (value <= 0x7F && value >= 0x80) {
return 1;
}
else if (value <= 0x7FFF && value >= 0x8000) {
return 2;
}
else if (value <= 0x7FFFFF && value >= 0x800000) {
return 3;
}
else if (value <= 0x7FFFFFFF && value >= 0x80000000) {
return 4;
}
else if (value <= 0x7FFFFFFFFFL && value >= 0x8000000000L) {
return 5;
}
else if (value <= 0x7FFFFFFFFFFFL && value >= 0x800000000000L) {
return 6;
}
else if (value <= 0x7FFFFFFFFFFFFFL && value >= 0x80000000000000L) {
return 7;
}
else {
return 8;
}
}
public static int getMinByteSizeUnsigned(long value) {
int size = 8;
long mask = 0xFF00000000000000L;
for (int i = 0; i < 8; i++) {
if ((value & mask) == 0) {
mask = mask >>> 8;
size--;
}
else {
return size;
}
}
return 8;
}
public static int codedSizeLength(long value) {
int codedSize = 0;
if (value < 127) {
codedSize = 1;
}
else if (value < 16383) {
codedSize = 2;
}
else if (value < 2097151) {
codedSize = 3;
}
else if (value < 268435455) {
codedSize = 4;
}
if ((MIN_SIZE_LENGTH > 0) && (codedSize <= MIN_SIZE_LENGTH)) {
codedSize = MIN_SIZE_LENGTH;
}
else {
//codedSize = 8;
}
return codedSize;
}
public static byte[] packIntUnsigned(long value) {
int size = getMinByteSizeUnsigned(value);
return packInt(value, size);
}
public static byte[] packInt(long value) {
int size = getMinByteSize(value);
return packInt(value, size);
}
public static byte[] packInt(long value, int size)
{
byte[] ret = new byte[size];
long mask = 0x00000000000000FFL;
int b = size - 1;
for (int i = 0; i < size; i++)
{
ret[b] = (byte)(((value >>> (8 * i)) & mask));
b--;
}
return ret;
}
public void setHeaderSize(int headerSize) {
this.headerSize = headerSize;
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml;
import java.util.*;
public class ElementType {
public static short UNKNOWN_ELEMENT = 0;
public static short MASTER_ELEMENT = 1;
public static short BINARY_ELEMENT = 2;
public static short SINTEGER_ELEMENT = 3;
public static short UINTEGER_ELEMENT = 4;
public static short FLOAT_ELEMENT = 5;
public static short STRING_ELEMENT = 6;
public static short ASCII_STRING_ELEMENT = 7;
public static short DATE_ELEMENT = 8;
public static short LAST_ELEMENT_TYPE = 100;
public String name;
public short level;
public byte [] id;
public short type;
//public HashMap child;
public ArrayList<ElementType> children;
public ElementType() {
}
public ElementType(String name, short level, byte [] id, short type, ArrayList<ElementType> children) {
this.name = name;
this.level = level;
this.id = id;
this.type = type;
this.children = children;
}
public ElementType findElement(byte [] id) {
if (this.isElement(id))
return this;
if (children != null) {
for (int i = 0; i < children.size(); i++) {
ElementType entry = (ElementType)children.get(i);
if (entry.isElement(id))
return entry;
entry = entry.findElement(id);
if (entry != null)
return entry;
}
}
return null;
}
public boolean isElement(byte [] id) {
return ElementType.compareIDs(this.id, id);
}
public static boolean compareIDs(byte[] id1, byte[] id2) {
if ((id1 == null)
|| (id2 == null)
|| (id1.length != id2.length))
return false;
for (int i = 0; i < id1.length; i++) {
if (id1[i] != id2[i])
return false;
}
return true;
}
public Element createElement() {
Element elem;
if (this.type == ElementType.MASTER_ELEMENT) {
elem = new MasterElement(this.id);
} else if (this.type == ElementType.BINARY_ELEMENT) {
elem = new BinaryElement(this.id);
} else if (this.type == ElementType.STRING_ELEMENT) {
elem = new StringElement(this.id);
} else if (this.type == ElementType.ASCII_STRING_ELEMENT) {
elem = new StringElement(this.id, "US-ASCII");
} else if (this.type == ElementType.SINTEGER_ELEMENT) {
elem = new SignedIntegerElement(this.id);
} else if (this.type == ElementType.UINTEGER_ELEMENT) {
elem = new UnsignedIntegerElement(this.id);
} else if (this.type == ElementType.FLOAT_ELEMENT) {
elem = new FloatElement(this.id);
} else if (this.type == ElementType.DATE_ELEMENT) {
elem = new DateElement(this.id);
} else if (this.type == ElementType.UNKNOWN_ELEMENT) {
elem = new BinaryElement(this.id);
} else {
return null;
}
elem.setElementType(this);
return elem;
}
}
\ No newline at end of file
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml;
import java.io.*;
public class FloatElement extends BinaryElement {
public FloatElement(byte[] type) {
super(type);
}
/**
* Set the float value of this element
* @param value Float value to set
* @throws ArithmeticException if the float value is larger than Double.MAX_VALUE
*/
public void setValue(double value) {
try {
if (value < Float.MAX_VALUE) {
ByteArrayOutputStream bIO = new ByteArrayOutputStream(4);
DataOutputStream dIO = new DataOutputStream(bIO);
dIO.writeFloat((float)value);
setData(bIO.toByteArray());
} else if (value < Double.MAX_VALUE) {
ByteArrayOutputStream bIO = new ByteArrayOutputStream(8);
DataOutputStream dIO = new DataOutputStream(bIO);
dIO.writeDouble(value);
setData(bIO.toByteArray());
} else {
throw new ArithmeticException(
"80-bit floats are not supported, BTW How did you create such a large float in Java?");
}
} catch (IOException ex) {
return;
}
}
/**
* Get the float value of this element
* @return Float value of this element
* @throws ArithmeticException for 80-bit or 10-byte floats. AFAIK Java doesn't support them
*/
public double getValue() {
try {
if (size == 4) {
float value = 0;
ByteArrayInputStream bIS = new ByteArrayInputStream(data);
DataInputStream dIS = new DataInputStream(bIS);
value = dIS.readFloat();
return value;
} else if (size == 8) {
double value = 0;
ByteArrayInputStream bIS = new ByteArrayInputStream(data);
DataInputStream dIS = new DataInputStream(bIS);
value = dIS.readDouble();
return value;
} else {
throw new ArithmeticException(
"80-bit floats are not supported");
}
} catch (IOException ex) {
return 0;
}
}
}
\ No newline at end of file
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml;
import org.ebml.io.*;
import java.util.*;
public class MasterElement extends Element {
protected long usedSize;
protected ArrayList<Element> children = new ArrayList<Element>();
public MasterElement(byte[] type) {
super(type);
usedSize = 0;
}
public Element readNextChild(EBMLReader reader) {
if (usedSize >= this.getSize())
return null;
Element elem = reader.readNextElement();
if (elem == null)
return null;
elem.setParent(this);
usedSize += elem.getTotalSize();
return elem;
}
/* Skip the element data */
public void skipData(DataSource source) {
// Skip the child elements
source.skip(size-usedSize);
}
public long writeData(DataWriter writer)
{
long len = 0;
for (int i = 0; i < children.size(); i++)
{
Element elem = (Element)children.get(i);
len += elem.writeElement(writer);
}
return len;
}
public void addChildElement(Element elem)
{
children.add(elem);
size += elem.getTotalSize();
}
}
\ No newline at end of file
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml;
/*
* SignedInteger.java
*
* Created on February 17, 2003, 1:54 PM
*/
/**
* Basic class for the Signed Integer EBML data type.
* @author John Cannon
*/
public class SignedIntegerElement
extends BinaryElement {
public SignedIntegerElement(byte[] typeID) {
super(typeID);
}
public void setValue(long value) {
//System.out.println(Long.toHexString(value));
setData(packInt(value));
/*for (int i = 0; i < data.length; i++) {
System.out.print(Integer.toHexString(data[i]) + ", ");
}
System.out.print("\n");*/
}
public long getValue() {
long l = 0;
long tmp = 0;
l |= ((long)data[0] << (56 - ((8 - data.length) * 8)));
for (int i = 1; i < data.length; i++) {
tmp = ((long)data[data.length - i]) << 56;
tmp >>>= 56 - (8 * (i - 1));
l |= tmp;
}
//System.out.println(Long.toHexString(l));
return l;
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml;
/**
* Baisc class for handling an EBML string data type. This class encapsulates
* both UTF and ASCII string types and can use any string type supported by
* the Java platform.
*
* @author John Cannon
*/
public class StringElement
extends org.ebml.BinaryElement {
private String charset = "UTF-8";
/** Creates a new instance of StringElement */
public StringElement(byte[] typeID) {
super(typeID);
}
public StringElement(byte[] typeID, String encoding) {
super(typeID);
charset = encoding;
}
private boolean checkForCharsetHack()
{
// Check if we are trying to read UTF-8, if so lets try UTF8.
// Microsofts Java supports "UTF8" but not "UTF-8"
if (charset.compareTo("UTF-8") == 0)
{
charset = "UTF8";
// Let's try again
return true;
}
else if (charset.compareTo("US-ASCII") == 0)
{
// This is the same story as UTF-8,
// If Microsoft is going to hijack Java they should at least support the orignal :>
charset = "ASCII";
// Let's try again
return true;
}
return false;
}
public String getValue() {
try {
if (data == null)
throw new java.lang.IllegalStateException("Call readData() before trying to extract the string value.");
return new String(data, charset);
}
catch (java.io.UnsupportedEncodingException ex) {
if (checkForCharsetHack())
{
return getValue();
}
ex.printStackTrace();
return "";
}
}
public void setValue(String value) {
try {
setData(value.getBytes(charset));
}
catch (java.io.UnsupportedEncodingException ex) {
if (checkForCharsetHack())
{
setValue(value);
return;
}
ex.printStackTrace();
}
}
public String getEncoding() {
return charset;
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml;
import java.util.*;
public class UnknownElementType extends ElementType {
public UnknownElementType(byte [] id) {
super("Unknown", (short)0, id, ElementType.UNKNOWN_ELEMENT, (ArrayList<ElementType>)null);
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml;
/*
* UnsignedIntegerElement.java
*
* Created on February 15, 2003, 6:27 PM
*/
/**
* Basic class for the Unsigned Integer data type in EBML.
* @author John Cannon
*/
public class UnsignedIntegerElement
extends org.ebml.BinaryElement {
public UnsignedIntegerElement(byte[] typeID) {
super(typeID);
}
public void setValue(long value) {
setData(packIntUnsigned(value));
}
public long getValue() {
long l = 0;
long tmp = 0;
for (int i = 0; i < data.length; i++) {
tmp = ((long)data[data.length - 1 - i]) << 56;
tmp >>>= (56 - (i * 8));
l |= tmp;
}
return l;
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.io;
/**
* Interface for seeking operations.
* Not designed to be used alone but as a super interface for a more
* specialied reading or writing interfaces.
*/
public interface DataSeekable
{
/**
* Returns the length
*
* @return <code>-1</code> if the length is unknown
* @return <code> >0</code> length of the <code>DataSeekable</code>
*/
public long length();
public long getFilePointer();
/**
* Check if the <code>DataSeekable</code> object is seekable
*
* @return <code>true</code> if seeking is supported.
* @return <code>false</code> if seeking is not supported.
*/
public boolean isSeekable();
/**
* Seeks in the <code>DataSeekable</code>
*
* @param pos Absolute position to seek to
* @return The new file position
*/
public long seek(long pos);
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.io;
/*
* DataSource.java
*
* Created on November 18, 2002, 4:08 PM
*/
/**
* Defines the interface used for custom <code>DataSource</code>'s. A
* <code>DataSource</code> provides methods of reading bytes individually or
* in arrays. These basic functions must be defined in any <code>DataSource</code>
* objects to be used with the <code>EBMLReader</code>.
*
* @author John Cannon
* @author Jory Stone
*/
public interface DataSource extends DataSeekable {
public byte readByte();
public int read(byte[] buff);
public int read(byte[] buff, int offset, int length);
/**
* Skip a number of bytes in the <code>DataSeekable</code>
*
* @param offset The number of bytes to skip
* @return The number of bytes skipped
*/
public long skip(long offset);
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.io;
/**
* Defines the interface used for custom <code>DataWriter</code>'s. A
* <code>DataWriter</code> provides methods of writing bytes individually or
* in arrays. These basic functions must be defined in any <code>DataWriter</code>
* objects to be used with the <code>EBMLWriter</code>.
*
* @author Jory Stone
*/
public interface DataWriter extends DataSeekable
{
public int write(byte b);
public int write(byte[] buff);
public int write(byte[] buff, int offset, int length);
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.io;
import java.io.*;
public class FileDataSource implements DataSource {
RandomAccessFile file = null;
public FileDataSource(String filename) throws FileNotFoundException, IOException {
file = new RandomAccessFile(filename, "r");
}
public FileDataSource(String filename, String mode) throws FileNotFoundException, IOException {
file = new RandomAccessFile(filename, mode);
}
public byte readByte() {
try {
return file.readByte();
} catch (IOException ex) {
return 0;
}
}
public int read(byte[] buff) {
try {
return file.read(buff);
} catch (IOException ex) {
return 0;
}
}
public int read(byte[] buff, int offset, int length) {
try {
return file.read(buff, offset, length);
} catch (IOException ex) {
return 0;
}
}
public long skip(long offset) {
try {
return file.skipBytes((int)offset);
} catch (IOException ex) {
return 0;
}
}
public long length() {
try {
return file.length();
} catch (IOException ex) {
return -1;
}
}
public long getFilePointer() {
try {
return file.getFilePointer();
} catch (IOException ex) {
return -1;
}
}
public boolean isSeekable() {
return true;
}
public long seek(long pos) {
try {
file.seek(pos);
return file.getFilePointer();
} catch (IOException ex) {
return -1;
}
}
}
\ No newline at end of file
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.io;
import java.io.*;
public class FileDataWriter implements DataWriter
{
RandomAccessFile file = null;
public FileDataWriter(String filename) throws FileNotFoundException, IOException
{
file = new RandomAccessFile(filename, "rw");
}
public FileDataWriter(String filename, String mode) throws FileNotFoundException, IOException
{
file = new RandomAccessFile(filename, mode);
}
public int write(byte b)
{
try
{
file.write(b);
return 1;
}
catch (IOException ex)
{
return 0;
}
}
public int write(byte[] buff)
{
try
{
file.write(buff);
return buff.length;
}
catch (IOException ex)
{
return 0;
}
}
public int write(byte[] buff, int offset, int length)
{
try
{
file.write(buff, offset, length);
return length;
}
catch (IOException ex)
{
return 0;
}
}
public long length()
{
try
{
return file.length();
}
catch (IOException ex)
{
return -1;
}
}
public long getFilePointer()
{
try
{
return file.getFilePointer();
}
catch (IOException ex)
{
return -1;
}
}
public boolean isSeekable()
{
return true;
}
public void close()
{
try
{
file.close();
}
catch (IOException ex)
{
}
}
public long seek(long pos)
{
try
{
file.seek(pos);
return file.getFilePointer();
}
catch (IOException ex)
{
return -1;
}
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.io;
import java.io.*;
/*
* InputStreamDataSource
*
* Created on November 19, 2002, 9:35 PM
*
* @author John Cannon
*/
public class InputStreamDataSource
implements DataSource {
protected InputStream in = null;
protected long pos = 0;
protected byte[] buffer = new byte[1];
public InputStream getInputStream() {
return in;
}
/** Creates a new instance of InputStreamDataSource */
public InputStreamDataSource(InputStream in) {
this.in = in;
}
public byte readByte() {
try {
int l = in.read(buffer);
pos += l;
return buffer[0];
}
catch (IOException e) {
e.printStackTrace();
return -1;
}
}
public int read(byte[] buff) {
try {
int l = in.read(buff);
pos += l;
return l;
}
catch (IOException e) {
e.printStackTrace();
return -1;
}
}
public int read(byte[] buff, int offset, int length) {
try {
int l = in.read(buff, offset, length);
pos += l;
return l;
}
catch (IOException e) {
e.printStackTrace();
return -1;
}
}
public long skip(long offset) {
try {
long l = in.skip(offset);
pos += l;
return l;
}
catch (IOException e) {
e.printStackTrace();
return -1;
}
}
public long length() {
try {
return pos + in.available();
}
catch (IOException e) {
e.printStackTrace();
return -1;
}
}
public long getFilePointer() {
return pos;
}
public boolean isSeekable() {
return false;
}
public long seek(long pos) {
return pos;
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.io;
import java.io.*;
public class StreamDataWriter implements DataWriter
{
OutputStream stream = null;
public StreamDataWriter(OutputStream stream) throws IOException
{
this.stream = stream;
}
public int write(byte b)
{
try
{
stream.write(b);
stream.flush();
return 1;
}
catch (IOException ex)
{
return 0;
}
}
public int write(byte[] buff)
{
try
{
stream.write(buff);
stream.flush();
return buff.length;
}
catch (IOException ex)
{
return 0;
}
}
public int write(byte[] buff, int offset, int length)
{
try
{
stream.write(buff, offset, length);
stream.flush();
return length;
}
catch (IOException ex)
{
return 0;
}
}
public boolean isSeekable()
{
return false;
}
public long seek(long pos)
{
return -1;
}
public long getFilePointer()
{
return -1;
}
public long length()
{
return -1;
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.matroska;
import org.ebml.*;
import org.ebml.util.*;
public class MatroskaBlock extends BinaryElement {
protected int [] Sizes = null;
protected int HeaderSize = 0;
protected int BlockTimecode = 0;
protected int TrackNo = 0;
private boolean keyFrame;
public MatroskaBlock(byte[] type) {
super(type);
}
//public void readData(DataSource source) {
// parseBlock();
//}
public void parseBlock() {
int index = 0;
TrackNo = (int)EBMLReader.readEBMLCode(data);
index = Element.codedSizeLength(TrackNo);
HeaderSize += index;
short BlockTimecode1 = (short)(data[index++] & 0xFF);
short BlockTimecode2 = (short)(data[index++] & 0xFF);
if (BlockTimecode1 != 0 || BlockTimecode2 != 0) {
BlockTimecode = (BlockTimecode1 << 8) | BlockTimecode2;
}
int keyFlag = data[index] & 0x80;
if(keyFlag > 0)
this.keyFrame = true;
else
this.keyFrame = false;
int LaceFlag = data[index] & 0x06;
index++;
// Increase the HeaderSize by the number of bytes we have read
HeaderSize += 3;
if (LaceFlag != 0x00) {
// We have lacing
byte LaceCount = data[index++];
HeaderSize += 1;
if (LaceFlag == 0x02) { // Xiph Lacing
Sizes = readXiphLaceSizes(index, LaceCount);
} else if (LaceFlag == 0x06) { // EBML Lacing
Sizes = readEBMLLaceSizes(index, LaceCount);
} else if (LaceFlag == 0x04) { // Fixed Size Lacing
Sizes = new int[LaceCount+1];
Sizes[0] = (int)(this.getSize() - HeaderSize) / (LaceCount+1);
for (int s = 0; s < LaceCount; s++)
Sizes[s+1] = Sizes[0];
} else {
throw new RuntimeException("Unsupported lacing type flag.");
}
}
//data = new byte[(int)(this.getSize() - HeaderSize)];
//source.read(data, 0, data.length);
//this.dataRead = true;
}
public int[] readEBMLLaceSizes(int index, short LaceCount) {
int [] LaceSizes = new int[LaceCount+1];
LaceSizes[LaceCount] = (int)this.getSize();
// This uses the DataSource.getBytePosition() for finding the header size
// because of the trouble of finding the byte size of sized ebml coded integers
//long ByteStartPos = source.getFilePointer();
int startIndex = index;
LaceSizes[0] = (int)EBMLReader.readEBMLCode(data, index);
index += Element.codedSizeLength(LaceSizes[0]);
LaceSizes[LaceCount] -= LaceSizes[0];
long FirstEBMLSize = LaceSizes[0];
long LastEBMLSize = 0;
for (int l = 0; l < LaceCount-1; l++) {
LastEBMLSize = EBMLReader.readSignedEBMLCode(data, index);
index += Element.codedSizeLength(LastEBMLSize);
FirstEBMLSize += LastEBMLSize;
LaceSizes[l+1] = (int)FirstEBMLSize;
// Update the size of the last block
LaceSizes[LaceCount] -= LaceSizes[l+1];
}
//long ByteEndPos = source.getFilePointer();
//HeaderSize = HeaderSize + (int)(ByteEndPos - ByteStartPos);
HeaderSize = HeaderSize + (int)(index - startIndex);
LaceSizes[LaceCount] -= HeaderSize;
return LaceSizes;
}
public int[] readXiphLaceSizes(int index, short LaceCount) {
int [] LaceSizes = new int[LaceCount+1];
LaceSizes[LaceCount] = (int)this.getSize();
//long ByteStartPos = source.getFilePointer();
for (int l = 0; l < LaceCount; l++) {
short LaceSizeByte = 255;
while (LaceSizeByte == 255) {
LaceSizeByte = (short)(data[index++] & 0xFF);
HeaderSize += 1;
LaceSizes[l] += LaceSizeByte;
}
// Update the size of the last block
LaceSizes[LaceCount] -= LaceSizes[l];
}
//long ByteEndPos = source.getFilePointer();
LaceSizes[LaceCount] -= HeaderSize;
return LaceSizes;
}
public int getFrameCount() {
if (Sizes == null) {
return 1;
}
return Sizes.length;
}
public byte [] getFrame(int frame) {
if (Sizes == null) {
if (frame != 0) {
throw new IllegalArgumentException("Tried to read laced frame on non-laced Block. MatroskaBlock.getFrame(frame > 0)");
}
byte [] FrameData = new byte[data.length-HeaderSize];
ArrayCopy.arraycopy(data, HeaderSize, FrameData, 0, FrameData.length);
return FrameData;
}
byte [] FrameData = new byte[Sizes[frame]];
// Calc the frame data offset
int StartOffset = HeaderSize;
for (int s = 0; s < frame; s++) {
StartOffset += Sizes[s];
}
// Copy the frame data
ArrayCopy.arraycopy(data, StartOffset, FrameData, 0, FrameData.length);
return FrameData;
}
public long getAdjustedBlockTimecode(long ClusterTimecode, long TimecodeScale) {
return ClusterTimecode + (BlockTimecode);// * TimecodeScale);
}
public int getTrackNo() {
return TrackNo;
}
public int getBlockTimecode() {
return BlockTimecode;
}
public void setFrameData(int trackNo, long timecode, byte [] frameData, boolean keyFrame)
{
this.data = new byte[4 + frameData.length];
this.keyFrame = keyFrame;
byte flags = 0;
if (keyFrame) flags |= 128;
this.data[0] = (byte) (trackNo | 0x80);
this.data[1] = (byte) (timecode >> 8);
this.data[2] = (byte) (timecode & 0xff);
this.data[3] = flags; // flags
ArrayCopy.arraycopy(frameData, 0, this.data, 4, frameData.length);
setSize(4 + frameData.length);
}
public boolean isKeyFrame() {
return keyFrame;
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.matroska;
import org.ebml.*;
import org.ebml.util.*;
/**
* Summary description for MatroskaCluster.
*/
public class MatroskaCluster extends MasterElement
{
static public int NO_LACING = 0;
static public int XIPH_LACING = 1;
static public int EBML_LACING = 2;
protected int [] laceMode = null;
protected TLinkedList frames = new TLinkedList();
protected long clusterTimecode = 0;
public MatroskaCluster(byte[] type)
{
super(type);
}
/**
* Set the current lacing mode.
*
* @param trackNo Track Number for the track to enable lacing for. 1-based index
* @param laceMode The lacing moe to use. See NO_LACING, XIPH_LACING, and EBML_LACING.
*/
void setLaceMode(short trackNo, int laceMode)
{
if (this.laceMode == null)
{
this.laceMode = new int[trackNo];
}
if (this.laceMode.length < trackNo)
{
int [] oldLaceMode = this.laceMode;
this.laceMode = new int[trackNo];;
ArrayCopy.arraycopy(this.laceMode, 0, oldLaceMode, 0, oldLaceMode.length);
}
this.laceMode[trackNo-1] = laceMode;
}
/**
* Get the current lacing mode.
*
* @param trackNo Track Number for the track to enable lacing for. 1-based index
* @return -1 if the track no is invalid
*/
int getLaceMode(short trackNo)
{
if (this.laceMode == null)
{
return -1;
}
if (this.laceMode.length < trackNo)
{
return -1;
}
return this.laceMode[trackNo-1];
}
public void AddFrame(MatroskaFileFrame frame)
{
// Is this the earliest timecode?
if (frame.Timecode < clusterTimecode)
{
clusterTimecode = frame.Timecode;
}
frames.add(frame);
}
public void FlushFrames()
{
TLinkedList.IteratorImpl iter = frames.first();
while (iter.hasNext())
{
//MatroskaFileFrame frame = (MatroskaFileFrame)
iter.next();
}
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.matroska;
import org.ebml.*;
import java.util.*;
/**
* DocType for Matroska files.
* This has all the element type id declares and also is in charge of
* creating the correct element classes from the type id.
*/
public class MatroskaDocType implements DocType
{
// Custom Element Types
static public short BLOCK_ELEMENT = (short)(ElementType.LAST_ELEMENT_TYPE + 1);
static public short SEGMENT_ELEMENT = (short)(ElementType.LAST_ELEMENT_TYPE + 2);
static public short CLUSTER_ELEMENT = (short)(ElementType.LAST_ELEMENT_TYPE + 3);
// EBML Id's
static public byte [] Void_Id = {(byte)0xEC};
static public byte [] EBMLHeader_Id = {0x1A, 0x45, (byte)0xDF, (byte)0xA3};
static public byte [] EBMLVersion_Id = {0x42, (byte)0x86};
static public byte [] DocTypeReadVersion_Id = {0x42, (byte)0x85};
static public byte [] EBMLReadVersion_Id = {0x42, (byte)0xF7};
static public byte [] EBMLMaxIDLength_Id = {0x42, (byte)0xF2};
static public byte [] EBMLMaxSizeLength_Id = {0x42, (byte)0xF3};
static public byte [] DocType_Id = {0x42, (byte)0x82};
static public byte [] DocTypeVersion_Id = {0x42, (byte)0x87};
static public byte [] Segment_Id = {0x18, 0x53, (byte)0x80, 0x67};
static public byte [] SeekHead_Id = {0x11, 0x4D, (byte)0x9B, 0x74};
static public byte [] SeekEntry_Id = {0x4D, (byte)0xBB};
static public byte [] SeekID_Id = {0x53, (byte)0xAB};
static public byte [] SeekPosition_Id = {0x53, (byte)0xAC};
static public byte [] SegmentInfo_Id = {0x15, (byte)0x49, (byte)0xA9, (byte)0x66};
static public byte [] SegmentUID_Id = {0x73, (byte)0xA4};
static public byte [] SegmentFilename_Id = {0x73, (byte)0x84};
static public byte [] TimecodeScale_Id = {0x2A, (byte)0xD7, (byte)0xB1};
static public byte [] Duration_Id = {0x44, (byte)0x89};
static public byte [] DateUTC_Id = {0x44, (byte)0x61};
static public byte [] Title_Id = {0x7B, (byte)0xA9};
static public byte [] MuxingApp_Id = {0x4D, (byte)0x80};
static public byte [] WritingApp_Id = {0x57, 0x41};
static public byte [] Tracks_Id = {0x16, (byte)0x54, (byte)0xAE, (byte)0x6B};
static public byte [] TrackEntry_Id = {(byte)0xAE};
static public byte [] TrackNumber_Id = {(byte)0xD7};
static public byte [] TrackUID_Id = {0x63, (byte)0xC5};
static public byte [] TrackType_Id = {(byte)0x83};
static public byte [] TrackFlagLacing_Id = {(byte)0x9C};
static public byte [] TrackDefaultDuration_Id = {0x23, (byte)0xE3, (byte)0x83};
static public byte [] TrackName_Id = {0x53, 0x6E};
static public byte [] TrackLanguage_Id = {0x22, (byte)0xB5, (byte)0x9C};
static public byte [] TrackCodecID_Id = {(byte)0x86};
static public byte [] TrackCodecName_Id = {0x25, (byte)0x86, (byte)0x88};
static public byte [] TrackCodecPrivate_Id = {(byte)0x63, (byte)0xA2};
static public byte [] TrackVideo_Id = {(byte)0xE0};
static public byte [] PixelWidth_Id = {(byte)0xB0};
static public byte [] PixelHeight_Id = {(byte)0xBA};
static public byte [] DisplayWidth_Id = {0x54, (byte)0xB0};
static public byte [] DisplayHeight_Id = {0x54, (byte)0xBA};
static public byte [] TrackAudio_Id = {(byte)0xE1};
static public byte [] SamplingFrequency_Id = {(byte)0xB5};
static public byte [] OutputSamplingFrequency_Id = {0x78, (byte)0xB5};
static public byte [] Channels_Id = {(byte)0x9F};
static public byte [] BitDepth_Id = {0x62, 0x64};
static public byte [] Attachments_Id = {0x19, 0x41, (byte)0xA4, 0x69};
static public byte [] AttachedFile_Id = {0x61, (byte)0xA7};
static public byte [] AttachedFileDescription_Id = {0x46, (byte)0x7E};
static public byte [] AttachedFileName_Id = {0x46, (byte)0x6E};
static public byte [] AttachedFileMimeType_Id = {0x46, (byte)0x60};
static public byte [] AttachedFileData_Id = {0x46, (byte)0x5C};
static public byte [] AttachedFileUID_Id = {0x46, (byte)0xAE};
static public byte [] Tags_Id = {0x12, (byte)0x54, (byte)0xC3, (byte)0x67};
static public byte [] Tag_Id = {0x73, (byte)0x73};
static public byte [] TagTargets_Id = {0x63, (byte)0xC0};
static public byte [] TagTargetTrackUID_Id = {0x63, (byte)0xC5};
static public byte [] TagTargetChapterUID_Id = {0x63, (byte)0xC4};
static public byte [] TagTargetAttachmentUID_Id = {0x63, (byte)0xC6};
static public byte [] TagSimpleTag_Id = {0x67, (byte)0xC8};
static public byte [] TagSimpleTagName_Id = {0x45, (byte)0xA3};
static public byte [] TagSimpleTagString_Id = {0x44, (byte)0x87};
static public byte [] TagSimpleTagBinary_Id = {0x44, (byte)0x85};
static public byte [] Cluster_Id = {0x1F, (byte)0x43, (byte)0xB6, (byte)0x75};
static public byte[] ClusterTimecode_Id = {(byte)0xE7};
static public byte[] ClusterBlockGroup_Id = {(byte)0xA0};
static public byte[] ClusterBlock_Id = {(byte)0xA1};
static public byte[] ClusterSimpleBlock_Id = {(byte)0xA3};
static public byte[] ClusterBlockDuration_Id = {(byte)0x9B};
static public byte[] ClusterReferenceBlock_Id = {(byte)0xFB};
static public byte[] Chapters_Id = {0x10, (byte)0x43, (byte)0xA7, (byte)0x70};
static public byte [] ChapterEditionEntry_Id = {(byte)0x45, (byte)0xB9};
static public byte [] ChapterEditionUID_Id = {(byte)0x45, (byte)0xBC};
static public byte [] ChapterEditionFlagHidden_Id = {(byte)0x45, (byte)0xBD};
static public byte [] ChapterEditionFlagDefault_Id = {(byte)0x45, (byte)0xDB};
static public byte [] ChapterEditionManaged_Id = {(byte)0x45, (byte)0xDD};
static public byte [] ChapterAtom_Id = {(byte)0xB6};
static public byte [] ChapterAtomChapterUID_Id = {(byte)0x73, (byte)0xC4};
static public byte [] ChapterAtomChapterTimeStart_Id = {(byte)0x91};
static public byte [] ChapterAtomChapterTimeEnd_Id = {(byte)0x92};
static public byte [] ChapterAtomChapterFlagHidden_Id = {(byte)0x98};
static public byte [] ChapterAtomChapterFlagEnabled_Id = {(byte)0x45, (byte)0x98};
static public byte [] ChapterAtomChapterPhysicalEquiv_Id = {(byte)0x63, (byte)0xC3};
static public byte [] ChapterAtomChapterTrack_Id = {(byte)0x8F};
static public byte [] ChapterAtomChapterTrackNumber_Id = {(byte)0x89};
static public byte [] ChapterAtomChapterDisplay_Id = {(byte)0x80};
static public byte [] ChapterAtomChapString_Id = {(byte)0x85};
static public byte [] ChapterAtomChapLanguage_Id = {(byte)0x43, (byte)0x7C};
static public byte [] ChapterAtomChapCountry_Id = {(byte)0x43, (byte)0x7E};
// Track Types
static public byte track_video = 0x01; ///< Rectangle-shaped non-transparent pictures aka video
static public byte track_audio = 0x02; ///< Anything you can hear
static public byte track_complex = 0x03; ///< Audio and video in same track, used by DV
static public byte track_logo = 0x10; ///< Overlay-pictures, displayed over video
static public byte track_subtitle = 0x11; ///< Text-subtitles. One track contains one language and only one track can be active (player-side configuration)
static public byte track_control = 0x20; ///< Control-codes for menus and other stuff
/**
* Converts a integer track type to String form.
*
* @param trackType Integer Track Type
* @return String <code>trackType</code> in String form
*/
static public String TrackTypeToString(byte trackType) {
if (trackType == track_video)
return "Video";
if (trackType == track_audio)
return "Audio";
if (trackType == track_complex)
return "Complex";
if (trackType == track_logo)
return "Logo";
if (trackType == track_subtitle)
return "Subtitle";
if (trackType == track_control)
return "Control";
return "";
}
protected ElementType type;
static public MatroskaDocType obj = new MatroskaDocType();
public MatroskaDocType() {
//long start = java.lang.System.currentTimeMillis();
init();
//System.out.println("MatroskaDocType Loaded in " + java.lang.System.currentTimeMillis() - start + " milliseconds");
}
protected void init() {
try {
ElementType baseLevel = new ElementType("", (short)0, (byte[])null,
(short)0, new ArrayList<ElementType>());
ElementType level0 = null;
ElementType level1 = null;
ElementType level2 = null;
ElementType level3 = null;
ElementType level4 = null;
ElementType level5 = null;
level0 = new ElementType("Void",
(short)1,
Void_Id,
ElementType.BINARY_ELEMENT,
(ArrayList<ElementType>)null);
baseLevel.children.add(level0);
level0 = new ElementType("EBMLHeader",
(short)0,
EBMLHeader_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level1 = new ElementType("EBMLVersion",
(short)1,
EBMLVersion_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level0.children.add(level1);
level1 = new ElementType("EBMLReadVersion",
(short)1,
EBMLReadVersion_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level0.children.add(level1);
level1 = new ElementType("EBMLMaxIDLength",
(short)1,
EBMLMaxIDLength_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level0.children.add(level1);
level1 = new ElementType("EBMLMaxSizeLength",
(short)1,
EBMLMaxSizeLength_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level0.children.add(level1);
level1 = new ElementType("DocType",
(short)1,
DocType_Id,
ElementType.STRING_ELEMENT,
(ArrayList<ElementType>)null);
level0.children.add(level1);
level1 = new ElementType("DocTypeVersion",
(short)1,
DocTypeVersion_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level0.children.add(level1);
level1 = new ElementType("DocTypeReadVersion",
(short)1,
DocTypeReadVersion_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level0.children.add(level1);
baseLevel.children.add(level0);
level0 = new ElementType("Segment",
(short)0,
Segment_Id,
MatroskaDocType.SEGMENT_ELEMENT,
new ArrayList<ElementType>());
level1 = new ElementType("SeekHead",
(short)1,
SeekHead_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level2 = new ElementType("SeekEntry",
(short)2,
SeekEntry_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level3 = new ElementType("SeekID",
(short)3,
SeekID_Id,
ElementType.BINARY_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("SeekPosition",
(short)3,
SeekPosition_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
// Add Seek Element
level1.children.add(level2);
// Add SeekHead Element
level0.children.add(level1);
level1 = new ElementType("SegmentInfo",
(short)1,
SegmentInfo_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level2 = new ElementType("SegmentUID",
(short)2,
SegmentUID_Id,
ElementType.BINARY_ELEMENT,
(ArrayList<ElementType>)null);
level1.children.add(level2);
level2 = new ElementType("SegmentFilename",
(short)2,
SegmentFilename_Id,
ElementType.STRING_ELEMENT,
(ArrayList<ElementType>)null);
level1.children.add(level2);
level2 = new ElementType("TimecodeScale",
(short)2,
TimecodeScale_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level1.children.add(level2);
level2 = new ElementType("Duration",
(short)2,
Duration_Id,
ElementType.FLOAT_ELEMENT,
(ArrayList<ElementType>)null);
level1.children.add(level2);
level2 = new ElementType("DateUTC",
(short)2,
DateUTC_Id,
ElementType.DATE_ELEMENT,
(ArrayList<ElementType>)null);
level1.children.add(level2);
level2 = new ElementType("Title",
(short)2,
Title_Id,
ElementType.STRING_ELEMENT,
(ArrayList<ElementType>)null);
level1.children.add(level2);
level2 = new ElementType("MuxingApp",
(short)2,
MuxingApp_Id,
ElementType.STRING_ELEMENT,
(ArrayList<ElementType>)null);
level1.children.add(level2);
level2 = new ElementType("WritingApp",
(short)2,
WritingApp_Id,
ElementType.STRING_ELEMENT,
(ArrayList<ElementType>)null);
level1.children.add(level2);
// Add Segment Infomation Element
level0.children.add(level1);
level1 = new ElementType("Tracks",
(short)1,
Tracks_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level2 = new ElementType("TrackEntry",
(short)2,
TrackEntry_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level3 = new ElementType("TrackNumber",
(short)3,
TrackNumber_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("TrackUID",
(short)3,
TrackUID_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("TrackType",
(short)3,
TrackType_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("TrackFlagLacing",
(short)3,
TrackFlagLacing_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("TrackDefaultDuration",
(short)3,
TrackDefaultDuration_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("TrackName",
(short)3,
TrackName_Id,
ElementType.STRING_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("TrackLanguage",
(short)3,
TrackLanguage_Id,
ElementType.ASCII_STRING_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("TrackCodecID",
(short)3,
TrackCodecID_Id,
ElementType.ASCII_STRING_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("TrackCodecName",
(short)3,
TrackCodecName_Id,
ElementType.ASCII_STRING_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("TrackCodecPrivate",
(short)3,
TrackCodecPrivate_Id,
ElementType.BINARY_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("TrackVideo",
(short)3,
TrackVideo_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level4 = new ElementType("PixelWidth",
(short)4,
PixelWidth_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
level4 = new ElementType("PixelHeight",
(short)4,
PixelHeight_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
level4 = new ElementType("DisplayWidth",
(short)4,
DisplayWidth_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
level4 = new ElementType("DisplayHeight",
(short)4,
DisplayHeight_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
// Add TrackVideo Element
level2.children.add(level3);
level3 = new ElementType("TrackAudio",
(short)3,
TrackAudio_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level4 = new ElementType("SamplingFrequency",
(short)4,
SamplingFrequency_Id,
ElementType.FLOAT_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
level4 = new ElementType("OutputSamplingFrequency",
(short)4,
OutputSamplingFrequency_Id,
ElementType.FLOAT_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
level4 = new ElementType("Channels",
(short)4,
Channels_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
level4 = new ElementType("BitDepth",
(short)4,
BitDepth_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
// Add TrackAudio Element
level2.children.add(level3);
// Add TrackEntry Element
level1.children.add(level2);
// Add Tracks Element
level0.children.add(level1);
level1 = new ElementType("Attachments",
(short)1,
Attachments_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level2 = new ElementType("AttachedFile",
(short)2,
AttachedFile_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level3 = new ElementType("AttachedFileDescription",
(short)3,
AttachedFileDescription_Id,
ElementType.STRING_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("AttachedFileName",
(short)3,
AttachedFileName_Id,
ElementType.STRING_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("AttachedFileMimeType",
(short)3,
AttachedFileMimeType_Id,
ElementType.ASCII_STRING_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("AttachedFileData",
(short)3,
AttachedFileData_Id,
ElementType.BINARY_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("AttachedFileUID",
(short)3,
AttachedFileUID_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
// Add AttachedFile Element
level1.children.add(level2);
// Add Attachments Element
level0.children.add(level1);
level1 = new ElementType("Tags",
(short)1,
Tags_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level2 = new ElementType("Tag",
(short)2,
Tag_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level3 = new ElementType("TagTargets",
(short)3,
TagTargets_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level4 = new ElementType("TagTargetTrackUID",
(short)4,
TagTargetTrackUID_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
level4 = new ElementType("TagTargetChapterUID",
(short)4,
TagTargetChapterUID_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
level4 = new ElementType("TagTargetAttachmentUID",
(short)4,
TagTargetAttachmentUID_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
// Add Targets
level2.children.add(level3);
level3 = new ElementType("TagSimpleTag",
(short)3,
TagSimpleTag_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level4 = new ElementType("TagSimpleTagName",
(short)4,
TagSimpleTagName_Id,
ElementType.STRING_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
level4 = new ElementType("TagSimpleTagString",
(short)4,
TagSimpleTagString_Id,
ElementType.STRING_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
level4 = new ElementType("TagSimpleTagBinary",
(short)4,
TagSimpleTagBinary_Id,
ElementType.BINARY_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
// Add SimpleTag
level2.children.add(level3);
// Add Tag Element
level1.children.add(level2);
// Add Tags Element
level0.children.add(level1);
level1 = new ElementType("Cluster",
(short)1,
Cluster_Id,
MatroskaDocType.CLUSTER_ELEMENT,
new ArrayList<ElementType>());
level2 = new ElementType("ClusterTimecode",
(short)2,
ClusterTimecode_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level1.children.add(level2);
level2 = new ElementType("ClusterBlockGroup",
(short)2,
ClusterBlockGroup_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level3 = new ElementType("ClusterBlock",
(short)3,
ClusterBlock_Id,
MatroskaDocType.BLOCK_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("ClusterBlockDuration",
(short)3,
ClusterBlockDuration_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("ClusterReferenceBlock",
(short)3,
ClusterReferenceBlock_Id,
ElementType.SINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
// Add ClusterBlockGroup Element
level1.children.add(level2);
level2 = new ElementType("SimpleBlock",
(short)2,
ClusterSimpleBlock_Id,
MatroskaDocType.BLOCK_ELEMENT,
new ArrayList<ElementType>());
// Add SimpleBlock Element
level1.children.add(level2);
// Add Cluster Element
level0.children.add(level1);
level1 = new ElementType("Chapters",
(short)1,
Chapters_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level2 = new ElementType("ChapterEditionEntry",
(short)2,
ChapterEditionEntry_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level3 = new ElementType("ChapterEditionUID",
(short)3,
ChapterEditionUID_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("ChapterEditionFlagHidden",
(short)3,
ChapterEditionFlagHidden_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("ChapterEditionFlagDefault",
(short)3,
ChapterEditionFlagDefault_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("ChapterEditionManaged",
(short)3,
ChapterEditionManaged_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level2.children.add(level3);
level3 = new ElementType("ChapterAtom",
(short)3,
ChapterAtom_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level4 = new ElementType("ChapterAtomChapterUID",
(short)4,
ChapterAtomChapterUID_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
level4 = new ElementType("ChapterAtomChapterTimeStart",
(short)4,
ChapterAtomChapterTimeStart_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
level4 = new ElementType("ChapterAtomChapterTimeEnd",
(short)4,
ChapterAtomChapterTimeEnd_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
level4 = new ElementType("ChapterAtomChapterFlagHidden",
(short)4,
ChapterAtomChapterFlagHidden_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
level4 = new ElementType("ChapterAtomChapterFlagEnabled",
(short)4,
ChapterAtomChapterFlagEnabled_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
level4 = new ElementType("ChapterAtomChapterPhysicalEquiv",
(short)4,
ChapterAtomChapterPhysicalEquiv_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level3.children.add(level4);
level4 = new ElementType("ChapterAtomChapterTrack",
(short)4,
ChapterAtomChapterTrack_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level5 = new ElementType("ChapterAtomChapterTrackNumber",
(short)5,
ChapterAtomChapterTrackNumber_Id,
ElementType.UINTEGER_ELEMENT,
(ArrayList<ElementType>)null);
level4.children.add(level5);
// Add ChapterAtomChapterTrack Element
level3.children.add(level4);
level4 = new ElementType("ChapterAtomChapterDisplay",
(short)4,
ChapterAtomChapterDisplay_Id,
ElementType.MASTER_ELEMENT,
new ArrayList<ElementType>());
level5 = new ElementType("ChapterAtomChapString",
(short)5,
ChapterAtomChapString_Id,
ElementType.STRING_ELEMENT,
(ArrayList<ElementType>)null);
level4.children.add(level5);
level5 = new ElementType("ChapterAtomChapLanguage",
(short)5,
ChapterAtomChapLanguage_Id,
ElementType.ASCII_STRING_ELEMENT,
(ArrayList<ElementType>)null);
level4.children.add(level5);
level5 = new ElementType("ChapterAtomChapCountry",
(short)5,
ChapterAtomChapCountry_Id,
ElementType.ASCII_STRING_ELEMENT,
(ArrayList<ElementType>)null);
level4.children.add(level5);
// Add ChapterAtomChapterDisplay Element
level3.children.add(level4);
// Add ChapterAtom Element
level2.children.add(level3);
// Add ChapterEditionEntry Element
level1.children.add(level2);
// Add Chapters Element
level0.children.add(level1);
// Add Segment Element
baseLevel.children.add(level0);
type = baseLevel;
} catch (java.lang.Exception ex) {
ex.printStackTrace();
}
}
/**
* Get the base ElementType tree.
*
* @return An ElementType that is filled with all the valid ElementType(s) for the MatroskaDocType
*/
public ElementType getElements() {
return type;
}
/**
* Creates an Element sub-class based on the ElementType.
*
* @param type ElementType to use for creation of Element.
* @return new Element sub-class, BinaryElement is the default.
* @throws RuntimeException if the ElementType has an unknown type field.
*/
public Element createElement(ElementType type) {
Element elem = null;
elem = type.createElement();
if (elem == null) {
if (type.type == MatroskaDocType.BLOCK_ELEMENT)
{
elem = new MatroskaBlock(type.id);
}
else if (type.type == MatroskaDocType.SEGMENT_ELEMENT)
{
elem = new MatroskaSegment(type.id);
}
else if (type.type == MatroskaDocType.CLUSTER_ELEMENT)
{
elem = new MatroskaCluster(type.id);
}
else if (type.type == ElementType.UNKNOWN_ELEMENT)
{
elem = new BinaryElement(type.id);
}
else
{
throw new java.lang.RuntimeException("Error: Unknown Element Type");
}
elem.setElementType(type);
}
return elem;
}
/**
* Creates an Element sub-class based on the element id.
*
* @param type id to use for creation of Element.
* @return new Element sub-class, BinaryElement is the default.
* @throws RuntimeException if the ElementType has an unknown type field.
*/
public Element createElement(byte [] type)
{
ElementType elementType = getElements().findElement(type);
if (elementType == null)
{
elementType = new UnknownElementType(type);
}
return createElement(elementType);
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.matroska;
import java.util.*;
import org.ebml.*;
import org.ebml.io.*;
import org.ebml.util.*;
public class MatroskaFile {
/**
* Number of Clusters to search before assuming that a track has ended
*/
public static int CLUSTER_TRACK_SEARCH_COUNT = 4;
protected DataSource ioDS;
protected EBMLReader reader;
protected Element level0 = null;
protected String SegmentTitle;
protected Date SegmentDate;
protected String MuxingApp;
protected String WritingApp;
protected long TimecodeScale = 1000000;
protected double Duration;
public ArrayList<MatroskaFileTrack> TrackList = new ArrayList<MatroskaFileTrack>();
protected ArrayList<MatroskaFileTagEntry> TagList = new ArrayList<MatroskaFileTagEntry>();
protected TLinkedList FrameQueue = new TLinkedList();
protected boolean ScanFirstCluster = true;
public long ClusterTimecode = 0;
/**
* Primary Constructor for Matroska File class.
*
* @param inputDataSource DataSource to read the Matroska file from
*/
public MatroskaFile(DataSource inputDataSource) {
ioDS = inputDataSource;
reader = new EBMLReader(ioDS, MatroskaDocType.obj);
}
/**
* Read / Parse the Matroska file.
* Call this before any other method.
* @throws RuntimeException On various errors
*/
public void readFile() {
Element level1 = null;
Element level2 = null;
// Element level3 = null;
// Element level4 = null;
level0 = reader.readNextElement();
if (level0 == null) {
throw new java.lang.RuntimeException("Error: Unable to scan for EBML elements");
}
if (level0.equals(MatroskaDocType.EBMLHeader_Id)) {
level1 = ((MasterElement)level0).readNextChild(reader);
while (level1 != null) {
level1.readData(ioDS);
if (level1.equals(MatroskaDocType.DocType_Id)) {
String DocType = ((StringElement)level1).getValue();
if (DocType.compareTo("matroska") != 0 && DocType.compareTo("webm") != 0) {
throw new java.lang.RuntimeException("Error: DocType is not matroska, \"" + ((StringElement)level1).getValue() + "\"");
}
}
level1 = ((MasterElement)level0).readNextChild(reader);
}
} else {
throw new java.lang.RuntimeException("Error: EBML Header not the first element in the file");
}
level0 = reader.readNextElement();
if (level0.equals(MatroskaDocType.Segment_Id)) {
level1 = ((MasterElement)level0).readNextChild(reader);
while (level1 != null) {
if (level1.equals(MatroskaDocType.SegmentInfo_Id)) {
_parseSegmentInfo(level1, level2);
} else if (level1.equals(MatroskaDocType.Tracks_Id)) {
_parseTracks(level1, level2);
} else if (level1.equals(MatroskaDocType.Cluster_Id)) {
if (ScanFirstCluster)
{
_parseNextCluster(level1);
}
// Break out of this loop, we should only parse the first cluster
break;
} else if (level1.equals(MatroskaDocType.Tags_Id)) {
_parseTags(level1, level2);
}
level1.skipData(ioDS);
level1 = ((MasterElement)level0).readNextChild(reader);
}
} else {
throw new java.lang.RuntimeException("Error: Segment not the second element in the file");
}
}
/**
* Get the Next MatroskaFileFrame
*
* @return The next MatroskaFileFrame in the queue, or null if the file has ended
*/
public MatroskaFileFrame getNextFrame() {
if (FrameQueue.isEmpty()) {
_fillFrameQueue();
}
// If FrameQueue is still empty, must be the end of the file
if (FrameQueue.isEmpty()) {
return null;
}
return (MatroskaFileFrame)FrameQueue.removeFirst();
}
/**
* Get the Next MatroskaFileFrame, limited by TrackNo
*
* @param TrackNo The track number to only get MatroskaFileFrame(s) from
* @return The next MatroskaFileFrame in the queue, or null if there are no more frames for the TrackNo track
*/
public MatroskaFileFrame getNextFrame(int TrackNo) {
if (FrameQueue.isEmpty()) {
_fillFrameQueue();
}
// If FrameQueue is still empty, must be the end of the file
if (FrameQueue.isEmpty()) {
return null;
}
int tryCount = 0;
MatroskaFileFrame frame = null;
try {
TLinkedList.IteratorImpl iter = FrameQueue.first();
while (frame == null) {
if (iter.hasNext()) {
frame = (MatroskaFileFrame)iter.next();
if (frame.TrackNo == TrackNo) {
synchronized (FrameQueue) {
iter.remove();
}
return frame;
}
frame = null;
} else {
_fillFrameQueue();
// Update Iterator
int index = iter.nextIndex();
iter = FrameQueue.listIterator(index);
if (++tryCount > CLUSTER_TRACK_SEARCH_COUNT) {
// If we have not found any frames belonging to a track in 4 clusters
// there is a good chance that the track is over
return null;
}
}
}
} catch (RuntimeException ex) {
ex.printStackTrace();
return null;
}
return frame;
}
public boolean isSeekable() {
return this.ioDS.isSeekable();
}
/**
* Seek to the requested timecode, rescaning clusters and/or discarding frames
* until we reach the nearest possible timecode, rounded down.
*
* <p>
* For example<br>
* Say we have a file with 10 frames
* <table><tr><th>Frame No</th><th>Timecode</th></tr>
* <tr><td>Frame 1</td> <td>0ms</td></tr>
* <tr><td>Frame 2</td> <td>50ms</td></tr>
* <tr><td>Frame 3</td> <td>100ms</td></tr>
* <tr><td>Frame 4</td> <td>150ms</td></tr>
* <tr><td>Frame 5</td> <td>200ms</td></tr>
* <tr><td>Frame 6</td> <td>250ms</td></tr>
* <tr><td>Frame 7</td> <td>300ms</td></tr>
* <tr><td>Frame 8</td> <td>350ms</td></tr>
* <tr><td>Frame 9</td> <td>400ms</td></tr>
* <tr><td>Frame 10</td> <td>450ms</td></tr>
* </table>
* We are requested to seek to 333ms, so we discard frames until we hit an
* timecode larger than the requested. We would seek to Frame 7 at 300ms.
* </p>
*
* @param timecode Timecode to seek to in millseconds
* @return Actual timecode we seeked to
*/
public long seek(long timecode) {
return 0;
}
private void _fillFrameQueue() {
if (level0 == null)
throw new java.lang.IllegalStateException("Call readFile() before reading frames");
synchronized (level0) {
Element level1 = ((MasterElement)level0).readNextChild(reader);
while (level1 != null) {
if (level1.equals(MatroskaDocType.Cluster_Id)) {
_parseNextCluster(level1);
}
level1.skipData(ioDS);
level1 = ((MasterElement)level0).readNextChild(reader);
}
}
}
private void _parseNextCluster(Element level1) {
Element level2 = null;
Element level3 = null;
level2 = ((MasterElement)level1).readNextChild(reader);
while (level2 != null) {
if (level2.equals(MatroskaDocType.ClusterTimecode_Id)) {
level2.readData(ioDS);
ClusterTimecode = ((UnsignedIntegerElement)level2).getValue();
}else if(level2.equals(MatroskaDocType.ClusterSimpleBlock_Id)) {
MatroskaBlock block = null;
long BlockDuration = 0;
long BlockReference = 0;
block = (MatroskaBlock)level2;
block.readData(ioDS);
block.parseBlock();
MatroskaFileFrame frame = new MatroskaFileFrame();
frame.TrackNo = block.getTrackNo();
frame.Timecode = block.getAdjustedBlockTimecode(ClusterTimecode, this.TimecodeScale);
frame.Duration = BlockDuration;
frame.Reference = BlockReference;
frame.Data = block.getFrame(0);
frame.KeyFrame = block.isKeyFrame();
synchronized (FrameQueue) {
FrameQueue.addLast(new MatroskaFileFrame(frame));
}
if (block.getFrameCount() > 1) {
for (int f = 1; f < block.getFrameCount(); f++) {
frame.Data = block.getFrame(f);
synchronized (FrameQueue) {
FrameQueue.addLast(new MatroskaFileFrame(frame));
}
}
}
level2.skipData(ioDS);
} else if (level2.equals(MatroskaDocType.ClusterBlockGroup_Id)) {
MatroskaBlock block = null;
long BlockDuration = 0;
long BlockReference = 0;
level3 = ((MasterElement)level2).readNextChild(reader);
while (level3 != null) {
if (level3.equals(MatroskaDocType.ClusterBlock_Id)) {
block = (MatroskaBlock)level3;
block.readData(ioDS);
block.parseBlock();
} else if (level3.equals(MatroskaDocType.ClusterBlockDuration_Id)) {
level3.readData(ioDS);
BlockDuration = ((UnsignedIntegerElement)level3).getValue();
} else if (level3.equals(MatroskaDocType.ClusterReferenceBlock_Id)) {
level3.readData(ioDS);
BlockReference = ((SignedIntegerElement)level3).getValue();
}
level3.skipData(ioDS);
level3 = ((MasterElement)level2).readNextChild(reader);
}
if (block == null)
throw new java.lang.NullPointerException("BlockGroup element with no child Block!");
MatroskaFileFrame frame = new MatroskaFileFrame();
frame.TrackNo = block.getTrackNo();
frame.Timecode = block.getAdjustedBlockTimecode(ClusterTimecode, this.TimecodeScale);
frame.Duration = BlockDuration;
frame.Reference = BlockReference;
frame.Data = block.getFrame(0);
synchronized (FrameQueue) {
FrameQueue.addLast(new MatroskaFileFrame(frame));
}
if (block.getFrameCount() > 1) {
for (int f = 1; f < block.getFrameCount(); f++) {
frame.Data = block.getFrame(f);
/*if (badMP3Headers()) {
throw new RuntimeException("Bad Data!");
}*/
synchronized (FrameQueue) {
FrameQueue.addLast(new MatroskaFileFrame(frame));
}
/*if (badMP3Headers()) {
throw new RuntimeException("Bad Data!");
}*/
}
}
}
level2.skipData(ioDS);
level2 = ((MasterElement)level1).readNextChild(reader);
}
}
protected boolean badMP3Headers() {
TLinkedList.IteratorImpl iter = FrameQueue.listIterator();
while (iter.hasNext()) {
MatroskaFileFrame frame = (MatroskaFileFrame)iter.next();
if (frame.TrackNo == 2
&& frame.Data[3] != 0x54)
{
throw new RuntimeException("Bad MP3 Header! Index: " + iter.nextIndex());
}
}
return false;
}
private void _parseSegmentInfo(Element level1, Element level2) {
level2 = ((MasterElement)level1).readNextChild(reader);
while (level2 != null) {
if (level2.equals(MatroskaDocType.Title_Id)) {
level2.readData(ioDS);
SegmentTitle = ((StringElement)level2).getValue();
} else if (level2.equals(MatroskaDocType.DateUTC_Id)) {
level2.readData(ioDS);
SegmentDate = ((DateElement)level2).getDate();
} else if (level2.equals(MatroskaDocType.MuxingApp_Id)) {
level2.readData(ioDS);
MuxingApp = ((StringElement)level2).getValue();
} else if (level2.equals(MatroskaDocType.WritingApp_Id)) {
level2.readData(ioDS);
WritingApp = ((StringElement)level2).getValue();
} else if (level2.equals(MatroskaDocType.Duration_Id)) {
level2.readData(ioDS);
Duration = ((FloatElement)level2).getValue();
} else if (level2.equals(MatroskaDocType.TimecodeScale_Id)) {
level2.readData(ioDS);
TimecodeScale = ((UnsignedIntegerElement)level2).getValue();
}
level2.skipData(ioDS);
level2 = ((MasterElement)level1).readNextChild(reader);
}
}
private void _parseTracks(Element level1, Element level2) {
Element level3 = null;
Element level4 = null;
level2 = ((MasterElement)level1).readNextChild(reader);
while (level2 != null) {
if (level2.equals(MatroskaDocType.TrackEntry_Id)) {
MatroskaFileTrack track = new MatroskaFileTrack();
level3 = ((MasterElement)level2).readNextChild(reader);
while (level3 != null) {
if (level3.equals(MatroskaDocType.TrackNumber_Id)) {
level3.readData(ioDS);
track.TrackNo = (short)((UnsignedIntegerElement)level3).getValue();
} else if (level3.equals(MatroskaDocType.TrackUID_Id)) {
level3.readData(ioDS);
track.TrackUID = ((UnsignedIntegerElement)level3).getValue();
} else if (level3.equals(MatroskaDocType.TrackType_Id)) {
level3.readData(ioDS);
track.TrackType = (byte)((UnsignedIntegerElement)level3).getValue();
} else if (level3.equals(MatroskaDocType.TrackDefaultDuration_Id)) {
level3.readData(ioDS);
track.DefaultDuration = ((UnsignedIntegerElement)level3).getValue();
} else if (level3.equals(MatroskaDocType.TrackName_Id)) {
level3.readData(ioDS);
track.Name = ((StringElement)level3).getValue();
} else if (level3.equals(MatroskaDocType.TrackLanguage_Id)) {
level3.readData(ioDS);
track.Language = ((StringElement)level3).getValue();
} else if (level3.equals(MatroskaDocType.TrackCodecID_Id)) {
level3.readData(ioDS);
track.CodecID = ((StringElement)level3).getValue();
} else if (level3.equals(MatroskaDocType.TrackCodecPrivate_Id)) {
level3.readData(ioDS);
track.CodecPrivate = ((BinaryElement)level3).getData();
} else if (level3.equals(MatroskaDocType.TrackVideo_Id)) {
level4 = ((MasterElement)level3).readNextChild(reader);
while (level4 != null) {
if (level4.equals(MatroskaDocType.PixelWidth_Id)) {
level4.readData(ioDS);
track.Video_PixelWidth = (short)((UnsignedIntegerElement)level4).getValue();
} else if (level4.equals(MatroskaDocType.PixelHeight_Id)) {
level4.readData(ioDS);
track.Video_PixelHeight = (short)((UnsignedIntegerElement)level4).getValue();
} else if (level4.equals(MatroskaDocType.DisplayWidth_Id)) {
level4.readData(ioDS);
track.Video_DisplayWidth = (short)((UnsignedIntegerElement)level4).getValue();
} else if (level4.equals(MatroskaDocType.DisplayHeight_Id)) {
level4.readData(ioDS);
track.Video_DisplayHeight = (short)((UnsignedIntegerElement)level4).getValue();
}
level4.skipData(ioDS);
level4 = ((MasterElement)level3).readNextChild(reader);
}
} else if (level3.equals(MatroskaDocType.TrackAudio_Id)) {
level4 = ((MasterElement)level3).readNextChild(reader);
while (level4 != null) {
if (level4.equals(MatroskaDocType.SamplingFrequency_Id)) {
level4.readData(ioDS);
track.Audio_SamplingFrequency = (float)((FloatElement)level4).getValue();
} else if (level4.equals(MatroskaDocType.OutputSamplingFrequency_Id)) {
level4.readData(ioDS);
track.Audio_OutputSamplingFrequency = (float)((FloatElement)level4).getValue();
} else if (level4.equals(MatroskaDocType.Channels_Id)) {
level4.readData(ioDS);
track.Audio_Channels = (short)((UnsignedIntegerElement)level4).getValue();
} else if (level4.equals(MatroskaDocType.BitDepth_Id)) {
level4.readData(ioDS);
track.Audio_BitDepth = (byte)((UnsignedIntegerElement)level4).getValue();
}
level4.skipData(ioDS);
level4 = ((MasterElement)level3).readNextChild(reader);
}
}
level3.skipData(ioDS);
level3 = ((MasterElement)level2).readNextChild(reader);
}
TrackList.add(track);
}
level2.skipData(ioDS);
level2 = ((MasterElement)level1).readNextChild(reader);
}
}
private void _parseTags(Element level1, Element level2) {
Element level3 = null;
Element level4 = null;
level2 = ((MasterElement)level1).readNextChild(reader);
while (level2 != null) {
if (level2.equals(MatroskaDocType.Tag_Id)) {
MatroskaFileTagEntry tag = new MatroskaFileTagEntry();
level3 = ((MasterElement)level2).readNextChild(reader);
while (level3 != null) {
if (level3.equals(MatroskaDocType.TagTargets_Id)) {
level4 = ((MasterElement)level3).readNextChild(reader);
while (level4 != null) {
if (level4.equals(MatroskaDocType.TagTargetTrackUID_Id)) {
level4.readData(ioDS);
tag.TrackUID.add(new Long(((UnsignedIntegerElement)level4).getValue()));
} else if (level4.equals(MatroskaDocType.TagTargetChapterUID_Id)) {
level4.readData(ioDS);
tag.ChapterUID.add(new Long(((UnsignedIntegerElement)level4).getValue()));
} else if (level4.equals(MatroskaDocType.TagTargetAttachmentUID_Id)) {
level4.readData(ioDS);
tag.AttachmentUID.add(new Long(((UnsignedIntegerElement)level4).getValue()));
}
level4.skipData(ioDS);
level4 = ((MasterElement)level3).readNextChild(reader);
}
} else if (level3.equals(MatroskaDocType.TagSimpleTag_Id)) {
tag.SimpleTags.add(_parseTagsSimpleTag(level3, level4));
}
level3.skipData(ioDS);
level3 = ((MasterElement)level2).readNextChild(reader);
}
TagList.add(tag);
}
level2.skipData(ioDS);
level2 = ((MasterElement)level1).readNextChild(reader);
}
}
private MatroskaFileSimpleTag _parseTagsSimpleTag(Element level3, Element level4) {
MatroskaFileSimpleTag SimpleTag = new MatroskaFileSimpleTag();
level4 = ((MasterElement)level3).readNextChild(reader);
while (level4 != null) {
if (level4.equals(MatroskaDocType.TagSimpleTagName_Id)) {
level4.readData(ioDS);
SimpleTag.Name = ((StringElement)level4).getValue();
} else if (level4.equals(MatroskaDocType.TagSimpleTagString_Id)) {
level4.readData(ioDS);
SimpleTag.Value = ((StringElement)level4).getValue();
} else if (level4.equals(MatroskaDocType.TagSimpleTag_Id)) {
SimpleTag.Children.add(_parseTagsSimpleTag(level3, level4));
}
level4.skipData(ioDS);
level4 = ((MasterElement)level3).readNextChild(reader);
}
return SimpleTag;
}
/**
* Get a String report for the Matroska file.
* Call readFile() before this method, else the report will be empty.
*
* @return String Report
*/
public String getReport() {
java.io.StringWriter s = new java.io.StringWriter();
int t;
s.write("MatroskaFile report\n");
s.write("Infomation Segment \n");
s.write("\tSegment Title: " + SegmentTitle + "\n");
s.write("\tSegment Date: " + SegmentDate + "\n");
s.write("\tMuxing App : " + MuxingApp + "\n");
s.write("\tWriting App : " + WritingApp + "\n");
s.write("\tDuration : " + Duration/1000 + "sec \n");
s.write("\tTimecodeScale : " + TimecodeScale + "\n");
s.write("Track Count: " + TrackList.size() + "\n");
for (t = 0; t < TrackList.size(); t++) {
s.write("\tTrack " + t + "\n");
s.write(TrackList.get(t).toString());
}
s.write("Tag Count: " + TagList.size() + "\n");
for (t = 0; t < TagList.size(); t++) {
s.write("\tTag Entry \n");
s.write(TagList.get(t).toString());
}
s.write("End report\n");
return s.getBuffer().toString();
}
public String getWritingApp() {
return WritingApp;
}
/**
* Returns an array of the tracks.
* If there are no MatroskaFileTracks to return the returned array
* will have a size of 0.
*
* @return Array of MatroskaFileTrack's
*/
public MatroskaFileTrack [] getTrackList() {
if (TrackList.size() > 0) {
MatroskaFileTrack [] tracks = new MatroskaFileTrack[TrackList.size()];
for (int t = 0; t < TrackList.size(); t++) {
tracks[t] = (MatroskaFileTrack)TrackList.get(t);
}
return tracks;
} else {
return new MatroskaFileTrack[0];
}
}
/**
* <p>
* This differs from the getTrackList method in that this method scans
* each track and returns the one that has the same track number as TrackNo.
* </p>
*
* <p>Note: TrackNo != track index</p>
*
* @param TrackNo The actual track number of the MatroskaFileTrack you would like to get
* @return null if no MatroskaFileTrack is found with the requested TrackNo
*/
public MatroskaFileTrack getTrack(int TrackNo) {
for (int t = 0; t < TrackList.size(); t++) {
MatroskaFileTrack track = (MatroskaFileTrack)TrackList.get(t);
if (track.TrackNo == TrackNo)
return track;
}
return null;
}
/**
* Get the timecode scale for this MatroskaFile.
* In Matroska the timecodes are stored scaled by this value.
* However any MatroskaFileFrame you get through the methods of this class
* will already have the timecodes correctly scaled to millseconds.
*
* @return TimecodeScale
*/
public long getTimecodeScale() {
return TimecodeScale;
}
public String getSegmentTitle() {
return SegmentTitle;
}
public String getMuxingApp() {
return MuxingApp;
}
/**
* Get the duration for this MatroskaFile.
* This is the duration value stored in the segment info.
* Which may or may not be the exact length of all, some, or one of the tracks.
*
* @return Duration in seconds
*/
public double getDuration() {
return Duration;
}
/**
* Sets if the readFile() method should scan the first cluster for infomation.
* Set to false for faster parsing.
*/
public void setScanFirstCluster(boolean scanFirstCluster)
{
ScanFirstCluster = scanFirstCluster;
}
/**
* Gets if the readFile() method should scan the first cluster for infomation.
* When set to false parsing is slightly faster.
*/
public boolean getScanFirstCluster()
{
return ScanFirstCluster;
}
}
package org.ebml.matroska;
import java.io.*;
/**
* <p>Title: JEBML</p>
* <p>Description: Java Classes to Read EBML Elements</p>
* <p>Copyright: Copyright (c) 2002-2004 John Cannon <spyder@matroska.org>, Jory Stone <jcsston@toughguy.net></p>
* <p>Company: </p>
* @author jcsston
* @version 1.0
*/
public class MatroskaFileFilter extends javax.swing.filechooser.FileFilter {
public MatroskaFileFilter() {
}
public boolean accept(File parm1) {
if (parm1.isDirectory())
return true;
String path = parm1.getAbsolutePath();
path = path.toLowerCase();
if (path.endsWith("mkv")
|| path.endsWith("mka")
|| path.endsWith("mks"))
return true;
return false;
}
public String getDescription() {
return "Matroska Video/Audio Files";
}
}
\ No newline at end of file
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.matroska;
import org.ebml.util.*;
/**
* Matroska Frame, holds a Matroska frame timecode, duration, and data
*/
public class MatroskaFileFrame
{
/**
* Matroska Frame Puller interface
*/
public interface MatroskaFramePuller
{
public void PushNewMatroskaFrame(MatroskaFileFrame frame);
};
/**
* The track this frame belongs to
*/
public int TrackNo;
/**
* A timecode, it should be in ms
*/
public long Timecode;
/**
* The duration of this frame, it should also be in ms
*/
public long Duration;
/**
* The first reference this frame has, set to 0 for no reference
*/
public long Reference;
/**
* More references, can be null if there are no more references
*/
public long [] References;
/**
* The frame data
*/
public byte [] Data;
public boolean KeyFrame;
/**
* MatroskaFrame Default constructor
*/
public MatroskaFileFrame()
{
//System.out.println("new " + this);
}
/**
* MatroskaFrame Copy constructor
* @param copy MatroskaFrame to copy
*/
public MatroskaFileFrame(MatroskaFileFrame copy)
{
//System.out.println("MatroskaFrame copy " + this);
this.TrackNo = copy.TrackNo;
this.Timecode = copy.Timecode;
this.Duration = copy.Duration;
this.Reference = copy.Reference;
this.KeyFrame = copy.KeyFrame;
if (copy.References != null)
{
this.References = new long[copy.References.length];
ArrayCopy.arraycopy(copy.References, 0, this.References, 0, copy.References.length);
}
if (copy.Data != null)
{
this.Data = new byte[copy.Data.length];
ArrayCopy.arraycopy(copy.Data, 0, this.Data, 0, copy.Data.length);
}
}
public boolean isKeyFrame() {
return KeyFrame;
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.matroska;
import java.util.ArrayList;
public class MatroskaFileSimpleTag
{
public String Name;
public String Value;
public ArrayList<MatroskaFileSimpleTag> Children = new ArrayList<MatroskaFileSimpleTag>();
public String toString(int depth)
{
String s = new String();
String depthIndent = new String();
for (int d = 0; d < depth; d++)
depthIndent += "\t";
s += depthIndent + "SimpleTag\n";
s += depthIndent + "\tName: " + Name + "\n";
s += depthIndent + "\tValue: " + Value + "\n";
depth++;
for (int t = 0; t < Children.size(); t++)
{
s += ((MatroskaFileSimpleTag)Children.get(t)).toString(depth);
}
return s;
}
}
\ No newline at end of file
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.matroska;
import java.util.ArrayList;
public class MatroskaFileTagEntry
{
public ArrayList<Long> TrackUID = new ArrayList<Long>();
public ArrayList<Long> ChapterUID = new ArrayList<Long>();
public ArrayList<Long> AttachmentUID = new ArrayList<Long>();
public ArrayList<MatroskaFileSimpleTag> SimpleTags = new ArrayList<MatroskaFileSimpleTag>();
public String toString()
{
String s = new String();
if (TrackUID.size() > 0)
{
s += "\t\t" + "TrackUID: " + TrackUID.toArray().toString() + "\n";
}
if (ChapterUID.size() > 0)
{
s += "\t\t" + "ChapterUID: " + ChapterUID.toArray().toString() + "\n";
}
if (AttachmentUID.size() > 0)
{
s += "\t\t" + "AttachmentUID: " + AttachmentUID.toArray().toString() + "\n";
}
for (int t = 0; t < SimpleTags.size(); t++)
{
s += ((MatroskaFileSimpleTag)SimpleTags.get(t)).toString(2);
}
return s;
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.matroska;
/**
* Matroska Track Class
*/
public class MatroskaFileTrack
{
public short TrackNo;
public long TrackUID;
public byte TrackType;
public long DefaultDuration;
public String Name;
public String Language;
public String CodecID;
public String CodecName;
public byte [] CodecPrivate;
public short Video_PixelWidth;
public short Video_PixelHeight;
public short Video_DisplayWidth;
public short Video_DisplayHeight;
public float Audio_SamplingFrequency;
public float Audio_OutputSamplingFrequency;
public short Audio_Channels;
public byte Audio_BitDepth;
/**
* Converts the Track to String form
* @return String form of MatroskaFileTrack data
*/
public String toString()
{
String s = new String();
s += "\t\t" + "TrackNo: " + TrackNo + "\n";
s += "\t\t" + "TrackUID: " + TrackUID + "\n";
s += "\t\t" + "TrackType: " + MatroskaDocType.TrackTypeToString(TrackType) + "\n";
s += "\t\t" + "DefaultDuration: " + DefaultDuration + "\n";
s += "\t\t" + "Name: " + Name + "\n";
s += "\t\t" + "Language: " + Language + "\n";
s += "\t\t" + "CodecID: " + CodecID + "\n";
s += "\t\t" + "CodecName: " + CodecName + "\n";
if (CodecPrivate != null)
s += "\t\t" + "CodecPrivate: " + CodecPrivate.length + " byte(s)" + "\n";
if (TrackType == MatroskaDocType.track_video)
{
s += "\t\t" + "PixelWidth: " + Video_PixelWidth + "\n";
s += "\t\t" + "PixelHeight: " + Video_PixelHeight + "\n";
s += "\t\t" + "DisplayWidth: " + Video_DisplayWidth + "\n";
s += "\t\t" + "DisplayHeight: " + Video_DisplayHeight + "\n";
}
if (TrackType == MatroskaDocType.track_audio)
{
s += "\t\t" + "SamplingFrequency: " + Audio_SamplingFrequency + "\n";
if (Audio_OutputSamplingFrequency != 0)
s += "\t\t" + "OutputSamplingFrequency: " + Audio_OutputSamplingFrequency + "\n";
s += "\t\t" + "Channels: " + Audio_Channels + "\n";
if (Audio_BitDepth != 0)
s += "\t\t" + "BitDepth: " + Audio_BitDepth + "\n";
}
return s;
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.matroska;
import java.util.ArrayList;
import java.util.Date;
import org.ebml.BinaryElement;
import org.ebml.DateElement;
import org.ebml.FloatElement;
import org.ebml.MasterElement;
import org.ebml.StringElement;
import org.ebml.UnsignedIntegerElement;
import org.ebml.io.DataWriter;
/**
* Summary description for MatroskaFileWriter.
*/
public class MatroskaFileWriter
{
protected DataWriter ioDW;
private MatroskaCluster clusterElem = null;
private MasterElement segmentElem = null;
private long clusterTimecode;
protected MatroskaDocType doc = new MatroskaDocType();
public long TimecodeScale = 1000000;
public double Duration = 60.0;
public Date SegmentDate = new Date();
public ArrayList<MatroskaFileTrack> TrackList = new ArrayList<MatroskaFileTrack>();
public MatroskaFileWriter(DataWriter outputDataWriter)
{
ioDW = outputDataWriter;
}
public void writeEBMLHeader()
{
MasterElement ebmlHeaderElem = (MasterElement)doc.createElement(MatroskaDocType.EBMLHeader_Id);
UnsignedIntegerElement ebml1 = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.EBMLVersion_Id);
ebml1.setValue(1);
UnsignedIntegerElement ebml2 = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.EBMLReadVersion_Id);
ebml2.setValue(1);
UnsignedIntegerElement ebml3 = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.EBMLMaxIDLength_Id);
ebml3.setValue(4);
UnsignedIntegerElement ebml4 = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.EBMLMaxSizeLength_Id);
ebml4.setValue(8);
StringElement docTypeElem = (StringElement)doc.createElement(MatroskaDocType.DocType_Id);
docTypeElem.setValue("webm");
UnsignedIntegerElement docTypeVersionElem = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.DocTypeVersion_Id);
docTypeVersionElem.setValue(2);
UnsignedIntegerElement docTypeReadVersionElem = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.DocTypeReadVersion_Id);
docTypeReadVersionElem.setValue(2);
ebmlHeaderElem.addChildElement(ebml1);
ebmlHeaderElem.addChildElement(ebml2);
ebmlHeaderElem.addChildElement(ebml3);
ebmlHeaderElem.addChildElement(ebml4);
ebmlHeaderElem.addChildElement(docTypeElem);
ebmlHeaderElem.addChildElement(docTypeVersionElem);
ebmlHeaderElem.addChildElement(docTypeReadVersionElem);
ebmlHeaderElem.writeElement(ioDW);
}
public void writeSegmentHeader()
{
segmentElem = (MasterElement)doc.createElement(MatroskaDocType.Segment_Id);
MasterElement ebmlSeekHeadElem = (MasterElement)doc.createElement(MatroskaDocType.SeekHead_Id);
MasterElement ebmlSeekEntryElem1 = (MasterElement)doc.createElement(MatroskaDocType.SeekEntry_Id);
BinaryElement seekID1 = (BinaryElement)doc.createElement(MatroskaDocType.SeekID_Id);
seekID1.setData(MatroskaDocType.Tracks_Id);
UnsignedIntegerElement SeekPosition1 = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.SeekPosition_Id);
SeekPosition1.setValue(0);
ebmlSeekEntryElem1.addChildElement(seekID1);
ebmlSeekEntryElem1.addChildElement(SeekPosition1);
ebmlSeekHeadElem.addChildElement(ebmlSeekEntryElem1);
segmentElem.addChildElement(ebmlSeekHeadElem);
}
public void writeSegmentInfo()
{
MasterElement segmentInfoElem = (MasterElement)doc.createElement(MatroskaDocType.SegmentInfo_Id);
StringElement writingAppElem = (StringElement)doc.createElement(MatroskaDocType.WritingApp_Id);
writingAppElem.setValue("Matroska File Writer v1.0");
StringElement muxingAppElem = (StringElement)doc.createElement(MatroskaDocType.MuxingApp_Id);
muxingAppElem.setValue("JEBML v1.0");
DateElement dateElem = (DateElement)doc.createElement(MatroskaDocType.DateUTC_Id);
dateElem.setDate(SegmentDate);
//Add timecode scale
UnsignedIntegerElement timecodescaleElem = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.TimecodeScale_Id);
timecodescaleElem.setValue(TimecodeScale);
FloatElement durationElem = (FloatElement)doc.createElement(MatroskaDocType.Duration_Id);
//durationElem.setValue(Duration * 1000.0);
durationElem.setValue(0);
//segmentInfoElem.addChildElement(dateElem);
segmentInfoElem.addChildElement(timecodescaleElem);
segmentInfoElem.addChildElement(muxingAppElem);
segmentInfoElem.addChildElement(writingAppElem);
segmentInfoElem.addChildElement(durationElem);
//segmentInfoElem.writeElement(ioDW);
segmentElem.addChildElement(segmentInfoElem);
}
public void writeTracks()
{
MasterElement tracksElem = (MasterElement)doc.createElement(MatroskaDocType.Tracks_Id);
for (int i = 0; i < TrackList.size(); i++)
{
MatroskaFileTrack track = (MatroskaFileTrack)TrackList.get(i);
MasterElement trackEntryElem = (MasterElement)doc.createElement(MatroskaDocType.TrackEntry_Id);
UnsignedIntegerElement trackNoElem = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.TrackNumber_Id);
trackNoElem.setValue(track.TrackNo);
UnsignedIntegerElement trackFlagLacingElem = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.TrackFlagLacing_Id);
trackFlagLacingElem.setValue(0);
UnsignedIntegerElement trackUIDElem = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.TrackUID_Id);
trackUIDElem.setValue(track.TrackUID);
UnsignedIntegerElement trackTypeElem = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.TrackType_Id);
trackTypeElem.setValue(track.TrackType);
StringElement trackNameElem = (StringElement)doc.createElement(MatroskaDocType.TrackName_Id);
trackNameElem.setValue(track.Name);
StringElement trackLangElem = (StringElement)doc.createElement(MatroskaDocType.TrackLanguage_Id);
trackLangElem.setValue(track.Language);
StringElement trackCodecIDElem = (StringElement)doc.createElement(MatroskaDocType.TrackCodecID_Id);
trackCodecIDElem.setValue(track.CodecID);
StringElement trackCodecName_IdElem = (StringElement)doc.createElement(MatroskaDocType.TrackCodecName_Id);
trackCodecName_IdElem.setValue(track.CodecName);
BinaryElement trackCodecPrivateElem = (BinaryElement)doc.createElement(MatroskaDocType.TrackCodecPrivate_Id);
trackCodecPrivateElem.setData(track.CodecPrivate);
UnsignedIntegerElement trackDefaultDurationElem = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.TrackDefaultDuration_Id);
trackDefaultDurationElem.setValue(track.DefaultDuration);
trackEntryElem.addChildElement(trackNoElem);
trackEntryElem.addChildElement(trackUIDElem);
trackEntryElem.addChildElement(trackFlagLacingElem);
trackEntryElem.addChildElement(trackLangElem);
trackEntryElem.addChildElement(trackCodecIDElem);
trackEntryElem.addChildElement(trackCodecName_IdElem);
trackEntryElem.addChildElement(trackTypeElem);
//trackEntryElem.addChildElement(trackNameElem);
//trackEntryElem.addChildElement(trackCodecPrivateElem);
// trackEntryElem.addChildElement(trackDefaultDurationElem);
// Now we add the audio/video dependant sub-elements
if (track.TrackType == MatroskaDocType.track_video)
{
MasterElement trackVideoElem = (MasterElement)doc.createElement(MatroskaDocType.TrackVideo_Id);
UnsignedIntegerElement trackVideoPixelWidthElem = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.PixelWidth_Id);
trackVideoPixelWidthElem.setValue(track.Video_PixelWidth);
UnsignedIntegerElement trackVideoPixelHeightElem = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.PixelHeight_Id);
trackVideoPixelHeightElem.setValue(track.Video_PixelHeight);
UnsignedIntegerElement trackVideoDisplayWidthElem = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.DisplayWidth_Id);
trackVideoDisplayWidthElem.setValue(track.Video_DisplayWidth);
UnsignedIntegerElement trackVideoDisplayHeightElem = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.DisplayHeight_Id);
trackVideoDisplayHeightElem.setValue(track.Video_DisplayHeight);
trackVideoElem.addChildElement(trackVideoPixelWidthElem);
trackVideoElem.addChildElement(trackVideoPixelHeightElem);
//trackVideoElem.addChildElement(trackVideoDisplayWidthElem);
//trackVideoElem.addChildElement(trackVideoDisplayHeightElem);
trackEntryElem.addChildElement(trackVideoElem);
}
else if (track.TrackType == MatroskaDocType.track_audio)
{
MasterElement trackAudioElem = (MasterElement)doc.createElement(MatroskaDocType.TrackVideo_Id);
UnsignedIntegerElement trackAudioChannelsElem = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.Channels_Id);
trackAudioChannelsElem.setValue(track.Audio_Channels);
UnsignedIntegerElement trackAudioBitDepthElem = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.BitDepth_Id);
trackAudioBitDepthElem.setValue(track.Audio_BitDepth);
FloatElement trackAudioSamplingRateElem = (FloatElement)doc.createElement(MatroskaDocType.SamplingFrequency_Id);
trackAudioSamplingRateElem.setValue(track.Audio_SamplingFrequency);
FloatElement trackAudioOutputSamplingFrequencyElem = (FloatElement)doc.createElement(MatroskaDocType.OutputSamplingFrequency_Id);
trackAudioOutputSamplingFrequencyElem.setValue(track.Audio_OutputSamplingFrequency);
trackAudioElem.addChildElement(trackAudioChannelsElem);
trackAudioElem.addChildElement(trackAudioBitDepthElem);
trackAudioElem.addChildElement(trackAudioSamplingRateElem);
trackAudioElem.addChildElement(trackAudioOutputSamplingFrequencyElem);
trackEntryElem.addChildElement(trackAudioElem);
}
tracksElem.addChildElement(trackEntryElem);
}
segmentElem.addChildElement(tracksElem);
segmentElem.writeElement(ioDW);
}
public void startCluster(long clusterTimecode)
{
clusterElem = (MatroskaCluster)doc.createElement(MatroskaDocType.Cluster_Id);
UnsignedIntegerElement clusterTimecodeElem = (UnsignedIntegerElement)doc.createElement(MatroskaDocType.ClusterTimecode_Id);
clusterTimecodeElem.setValue(clusterTimecode);
clusterElem.addChildElement(clusterTimecodeElem);
this.clusterTimecode = clusterTimecode;
}
public void endCluster()
{
if (clusterElem != null) clusterElem.writeElement(ioDW);
}
/**
* Add a frame
*
* @param frame The frame to add
*/
public void addFrame(MatroskaFileFrame frame)
{
MatroskaBlock simpleBlockElem = (MatroskaBlock)doc.createElement(MatroskaDocType.ClusterSimpleBlock_Id);
simpleBlockElem.setFrameData(frame.TrackNo, frame.Timecode - clusterTimecode, frame.Data, frame.KeyFrame);
clusterElem.addChildElement(simpleBlockElem);
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.matroska;
import org.ebml.*;
import org.ebml.io.*;
/**
* Summary description for MatroskaSegment.
*/
public class MatroskaSegment extends MasterElement
{
protected boolean bUnknownSize = false;
public MatroskaSegment(byte[] type)
{
super(type);
}
/** Write the element header data.
* The override will write the size as unknown if the flag is set.
*/
public long writeHeaderData(DataWriter writer)
{
long len = 0;
byte [] type = getType();
len += type.length;
writer.write(type);
byte [] size;
if (bUnknownSize)
{
size = new byte[5];
size[0] = (byte)(0xFF >>> (size.length-1));
for (int i = 1; i < size.length; i++)
size[i] = (byte)0xFF;
}
else
{
size = Element.makeEbmlCodedSize(getSize());
}
len += size.length;
writer.write(size);
return len;
}
/**
* Setter for Unknown Size flag.
* This is a special case for ebml. The size value is filled with 1's.
*/
public void setUnknownSize(boolean bUnknownSize)
{
this.bUnknownSize = bUnknownSize;
}
/**
* Getter for Unknown Size flag.
*/
public boolean getUnknownSize()
{
return bUnknownSize;
}
}
package org.ebml.sample;
import java.io.FileOutputStream;
import java.io.IOException;
import org.ebml.io.FileDataSource;
import org.ebml.io.FileDataWriter;
import org.ebml.matroska.MatroskaFile;
import org.ebml.matroska.MatroskaFileFrame;
import org.ebml.matroska.MatroskaFileTrack;
import org.ebml.matroska.MatroskaFileWriter;
/**
* <p>Title: JEBML</p>
* <p>Description: Java Classes to Read EBML Elements</p>
* <p>Copyright: Copyright (c) 2002-2004 John Cannon <spyder@matroska.org>, Jory Stone <jcsston@toughguy.net></p>
* <p>Company: </p>
* @author jcsston
* @version 1.0
*/
public class CommandLineSample {
public static void main(String[] args) {
System.out.println("JEBML CommandLineSample - (c) 2004 Jory 'jcsston' Stone <jcsston@toughguy.net>");
if (args.length < 3) {
System.out.println("Please provide a command and matroska filename on the command-line");
return;
}
try {
String mode = args[1];
if (mode.compareTo("-i") == 0)
{
readFile(args[2]);
}
else if (mode.compareTo("-o") == 0)
{
writeFile(args[2]);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
static void readFile(String filename) throws IOException
{
System.out.println("Scanning file: " + filename);
long startTime = System.currentTimeMillis();
FileDataSource iFS = new FileDataSource(filename);
MatroskaFile mF = new MatroskaFile(iFS);
mF.setScanFirstCluster(true);
mF.readFile();
System.out.println(mF.getReport());
MatroskaFileTrack track = mF.getTrack(1);
if (track.CodecID.compareTo("A_MPEG/L3") == 0)
{
System.out.println("Extracting mp3 track");
String outputFilename = filename + ".mp3";// + ".wav";
FileOutputStream oFS = new FileOutputStream(outputFilename);
/*
WavLib.WaveFormatEx wfx = new WavLib.WaveFormatEx();
wfx.wFormatTag = 0x55; // MP3
wfx.nSamplesPerSec = (int)track.Audio_SamplingFrequency;
if (track.Audio_Channels == 0) {
wfx.nChannels = 1;
} else {
wfx.nChannels = track.Audio_Channels;
}
if (track.Audio_BitDepth == 0) {
wfx.wBitsPerSample = 16;
} else {
wfx.wBitsPerSample = track.Audio_BitDepth;
}
//wfx.nBlockAlign = 4;
WavLib.WavWriter writer = new WavLib.WavWriter();
writer.Open(outputFilename, wfx);
*/
MatroskaFileFrame frame = mF.getNextFrame();
while (frame != null)
{
oFS.write(frame.Data);
//writer.WriteSampleData(frame.Data, 0, frame.Data.length);
frame = mF.getNextFrame();
}
//writer.Close();
}
long endTime = System.currentTimeMillis();
System.out.println("Scan complete. Took: " + ((endTime - startTime) / 1000.0) + " seconds");
}
static void writeFile(String filename) throws IOException
{
System.out.println("Write file: " + filename);
FileDataWriter iFW = new FileDataWriter(filename);
MatroskaFileWriter mFW = new MatroskaFileWriter(iFW);
mFW.writeEBMLHeader();
mFW.writeSegmentHeader();
mFW.writeSegmentInfo();
for (int i = 0; i < 5; i++)
{
MatroskaFileTrack track = new MatroskaFileTrack();
track.TrackNo = (short)i;
track.TrackUID = new java.util.Random().nextLong();
track.TrackType = 1;
track.Name = "Track " + Integer.toString(i);
track.Video_PixelWidth = 320;
track.Video_PixelHeight = 240;
mFW.TrackList.add(track);
}
mFW.writeTracks();
System.out.println("Write complete");
}
}
package org.ebml.sample;
import java.awt.*;
import javax.swing.*;
/**
* <p>Title: EBMLReader</p>
* <p>Description: Java Classes to Read EBML Elements</p>
* <p>Copyright: Copyright (c) 2004 Jory Stone <jcsston@toughguy.net></p>
* <p>Company: </p>
* @author jcsston
* @version 1.0
*/
public class EbmlSampleApp {
boolean packFrame = false;
//Construct the application
public EbmlSampleApp() {
EbmlSampleAppFrame frame = new EbmlSampleAppFrame();
//Validate frames that have preset sizes
//Pack frames that have useful preferred size info, e.g. from their layout
if (packFrame) {
frame.pack();
}
else {
frame.validate();
}
//Center the window
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = frame.getSize();
if (frameSize.height > screenSize.height) {
frameSize.height = screenSize.height;
}
if (frameSize.width > screenSize.width) {
frameSize.width = screenSize.width;
}
frame.setLocation((screenSize.width - frameSize.width) / 2,
(screenSize.height - frameSize.height) / 2);
frame.setVisible(true);
}
//Main method
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception e) {
e.printStackTrace();
}
new EbmlSampleApp();
}
}
\ No newline at end of file
package org.ebml.sample;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import org.ebml.io.*;
import org.ebml.matroska.*;
/**
* <p>Title: EBMLReader</p>
* <p>Description: Java Classes to Read EBML Elements</p>
* <p>Copyright: Copyright (c) 2004 Jory Stone <jcsston@toughguy.net></p>
* <p>Company: </p>
* @author jcsston
* @version 1.0
*/
public class EbmlSampleAppFrame
extends JFrame {
private static final long serialVersionUID = 1L;
JPanel contentPane;
JMenuBar jMenuBar1 = new JMenuBar();
JMenu jMenuFile = new JMenu();
JMenuItem jMenuFileExit = new JMenuItem();
BorderLayout borderLayout1 = new BorderLayout();
JMenuItem jMenuItemOpen = new JMenuItem();
JFileChooser jFileChooser1 = new JFileChooser();
JTextArea jTextArea1 = new JTextArea();
//Construct the frame
public EbmlSampleAppFrame() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch (Exception e) {
e.printStackTrace();
}
}
//Component initialization
private void jbInit() throws Exception {
contentPane = (JPanel)this.getContentPane();
contentPane.setLayout(borderLayout1);
this.setSize(new Dimension(400, 300));
this.setTitle("Ebml Sample App");
jMenuFile.setText("File");
jMenuFileExit.setText("Exit");
jMenuFileExit.addActionListener(new
EbmlSampleAppFrame_jMenuFileExit_ActionAdapter(this));
jMenuItemOpen.setText("Open");
jMenuItemOpen.addActionListener(new
EbmlSampleAppFrame_jMenuItemOpen_actionAdapter(this));
jFileChooser1.setAcceptAllFileFilterUsed(true);
jFileChooser1.setDialogTitle("Select a Matroska File");
jFileChooser1.setFileFilter(null);
jTextArea1.setTabSize(8);
jMenuFile.add(jMenuItemOpen);
jMenuFile.add(jMenuFileExit);
jMenuBar1.add(jMenuFile);
contentPane.add(jTextArea1, BorderLayout.CENTER);
this.setJMenuBar(jMenuBar1);
}
//File | Exit action performed
public void jMenuFileExit_actionPerformed(ActionEvent e) {
System.exit(0);
}
//Overridden so we can exit when window is closed
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
jMenuFileExit_actionPerformed(null);
}
}
void jMenuItemOpen_actionPerformed(ActionEvent e) {
try {
jFileChooser1.setFileFilter(new org.ebml.matroska.MatroskaFileFilter());
int ret = jFileChooser1.showOpenDialog(this);
if (ret == JFileChooser.APPROVE_OPTION) {
/*
FileInputStream inFS1 = new FileInputStream("I:\\videos\\111-Videos_111\\Linkin Park - Crawling-remux.mkvmerge.mp3");
FileOutputStream outFS1 = new FileOutputStream("I:\\videos\\111-Videos_111\\Linkin Park - Crawling-remux.mkvmerge.java.mp3");
byte [] buffer = new byte[64];
int len = 64;
while (len > 0) {
len = inFS1.read(buffer);
outFS1.write(buffer, 0, len);
}
*/
//FileOutputStream outFS = new FileOutputStream(jFileChooser1.getSelectedFile() + ".mp3");
FileInputStream ioF = new FileInputStream(jFileChooser1.getSelectedFile());
jTextArea1.append("Scanning file: " + jFileChooser1.getSelectedFile().toString() + "\n");
MatroskaFile mF = new MatroskaFile(new InputStreamDataSource(ioF));
mF.readFile();
jTextArea1.append(mF.getReport());
/*MatroskaFile.MatroskaFrame frame = mF.getNextFrame(2);
while (frame != null) {
frame = mF.getNextFrame(2);
if (frame != null)
outFS.write(frame.Data);
}*/
jTextArea1.append("Scan complete.\n");
}
} catch (java.io.FileNotFoundException ex) {
jTextArea1.append("File Not Found!\n");
ex.printStackTrace();
} catch (java.lang.RuntimeException ex) {
jTextArea1.append("Error: " + ex.toString() + ex.getMessage() + "\"\n");
ex.printStackTrace();
}
}
}
class EbmlSampleAppFrame_jMenuFileExit_ActionAdapter
implements ActionListener {
EbmlSampleAppFrame adaptee;
EbmlSampleAppFrame_jMenuFileExit_ActionAdapter(EbmlSampleAppFrame adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.jMenuFileExit_actionPerformed(e);
}
}
class EbmlSampleAppFrame_jMenuItemOpen_actionAdapter
implements java.awt.event.ActionListener {
EbmlSampleAppFrame adaptee;
EbmlSampleAppFrame_jMenuItemOpen_actionAdapter(EbmlSampleAppFrame adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.jMenuItemOpen_actionPerformed(e);
}
}
package org.ebml.sample;
import java.io.FileOutputStream;
import java.io.IOException;
import org.ebml.io.FileDataSource;
import org.ebml.matroska.MatroskaFile;
import org.ebml.matroska.MatroskaFileFrame;
import org.ebml.matroska.MatroskaFileTrack;
/**
* <p>Title: JEBML</p>
* <p>Description: Java Classes to Extract keyframes from WebM Files as WebP Images</p>
* <p>Copyright: Copyright (c) 2011 Brooss</p>
* <p>Company: </p>
* @author brooss
* @version 1.0
*/
public class WebMExtract {
public static void main(String[] args) {
System.out.println("JEBML WebMExtract");
if (args.length < 1) {
System.out.println("Please provide a WebM filename on the command-line");
return;
}
try {
readFile(args[0]);
} catch (IOException ex) {
ex.printStackTrace();
}
}
static void readFile(String filename) throws IOException
{
System.out.println("Scanning file: " + filename);
long startTime = System.currentTimeMillis();
FileDataSource iFS = new FileDataSource(filename);
MatroskaFile mF = new MatroskaFile(iFS);
mF.setScanFirstCluster(true);
mF.readFile();
System.out.println(mF.getReport());
MatroskaFileTrack track=null;
for(MatroskaFileTrack t : mF.getTrackList() ) {
if(t.CodecID.compareTo("V_VP8")==0)
track = t;
}
if (track!=null)
{
MatroskaFileFrame frame = mF.getNextFrame(track.TrackNo);
int count=0;
while (frame != null)
{
if(frame.isKeyFrame()) {
System.out.println("Extracting VP8 frame "+count);
String outputFilename = filename + ""+count+".webp";// + ".wav";
FileOutputStream oFS = new FileOutputStream(outputFilename);
oFS.write("RIFF".getBytes());
writeIntLE(oFS, frame.Data.length+20-8);
oFS.write("WEBPVP8".getBytes());
oFS.write(0x20);
writeIntLE(oFS, (frame.Data.length+20-8)-0xc);
oFS.write(frame.Data);
}
frame = mF.getNextFrame(track.TrackNo);
count++;
}
}
long endTime = System.currentTimeMillis();
System.out.println("Scan complete. Took: " + ((endTime - startTime) / 1000.0) + " seconds");
}
public static void writeIntLE(FileOutputStream out, int value) {
try {
out.write(value & 0xFF);
out.write((value >> 8) & 0xFF);
out.write((value >> 16) & 0xFF);
out.write((value >> 24) & 0xFF);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* JEBML - Java library to read/write EBML/Matroska elements.
* Copyright (C) 2004 Jory Stone <jebml@jory.info>
* Based on Javatroska (C) 2002 John Cannon <spyder@matroska.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ebml.util;
/**
* Static methods for copying arrays
*/
public class ArrayCopy
{
/**
* Private construct as this class only has static methods
*/
private ArrayCopy()
{
}
public static void arraycopy(byte [] src, int src_offset, byte [] dest, int dest_offset, int count)
{
for (int i = 0; i < count; i++)
{
dest[dest_offset + i] = src[src_offset + i];
}
}
public static void arraycopy(char [] src, int src_offset, char [] dest, int dest_offset, int count)
{
for (int i = 0; i < count; i++)
{
dest[dest_offset + i] = src[src_offset + i];
}
}
public static void arraycopy(short [] src, int src_offset, short [] dest, int dest_offset, int count)
{
for (int i = 0; i < count; i++)
{
dest[dest_offset + i] = src[src_offset + i];
}
}
public static void arraycopy(int [] src, int src_offset, int [] dest, int dest_offset, int count)
{
for (int i = 0; i < count; i++)
{
dest[dest_offset + i] = src[src_offset + i];
}
}
public static void arraycopy(long [] src, int src_offset, long [] dest, int dest_offset, int count)
{
for (int i = 0; i < count; i++)
{
dest[dest_offset + i] = src[src_offset + i];
}
}
public static void arraycopy(Object [] src, int src_offset, Object [] dest, int dest_offset, int count)
{
for (int i = 0; i < count; i++)
{
dest[dest_offset + i] = src[src_offset + i];
}
}
}
package org.ebml.util;
/**
* A LinkedList implementation which holds instances of type
* <tt>TLinkable</tt>.
*
* <p>Using this implementation allows you to get java.util.LinkedList
* behavior (a doubly linked list, with Iterators that support insert
* and delete operations) without incurring the overhead of creating
* <tt>Node</tt> wrapper objects for every element in your list.</p>
*
* <p>The requirement to achieve this time/space gain is that the
* Objects stored in the List implement the <tt>TLinkable</tt>
* interface.</p>
*
* <p>The limitations are that you cannot put the same object into
* more than one list or more than once in the same list. You must
* also ensure that you only remove objects that are actually in the
* list. That is, if you have an object A and lists l1 and l2, you
* must ensure that you invoke List.remove(A) on the correct list. It
* is also forbidden to invoke List.remove() with an unaffiliated
* TLinkable (one that belongs to no list): this will destroy the list
* you invoke it on.</p>
*
* <p>
* Created: Sat Nov 10 15:25:10 2001
* </p>
*
* @author Eric D. Friedman
* @version $Id: TLinkedList.java,v 1.4 2002/04/08 02:02:28 ericdf Exp $
* @see gnu.trove.TLinkable
*/
public class TLinkedList
{
class TLinkable
{
protected TLinkable _next;
protected TLinkable _prev;
protected Object _value;
public TLinkable(Object value)
{
_value = value;
}
/**
* Returns the linked list node after this one.
*
* @return a <code>TLinkable</code> value
*/
public TLinkable getNext()
{
return _next;
}
/**
* Returns the linked list node before this one.
*
* @return a <code>TLinkable</code> value
*/
public TLinkable getPrevious()
{
return _prev;
}
/**
* Sets the linked list node after this one.
*
* @param linkable a <code>TLinkable</code> value
*/
public void setNext(TLinkable linkable)
{
_next = linkable;
}
/**
* Sets the linked list node before this one.
*
* @param linkable a <code>TLinkable</code> value
*/
public void setPrevious(TLinkable linkable)
{
_prev = linkable;
}
/**
* Sets the value of this list entry
*
* @param value a <code>Object</code> value
*/
public void setValue(Object value)
{
_value = value;
}
/**
* Gets the value of this list entry
*
* @param value a <code>Object</code> value
*/
public Object getValue()
{
return _value;
}
}// TLinkable
/** the head of the list */
protected TLinkable _head;
/** the tail of the list */
protected TLinkable _tail;
/** the number of elements in the list */
protected int _size = 0;
/**
* Creates a new <code>TLinkedList</code> instance.
*
*/
public TLinkedList()
{
}
public boolean isEmpty()
{
return (_size == 0);
}
public IteratorImpl first()
{
return listIterator();
}
public IteratorImpl listIterator()
{
return listIterator(0);
}
/**
* Returns an iterator positioned at <tt>index</tt>. Assuming
* that the list has a value at that index, calling next() will
* retrieve and advance the iterator. Assuming that there is a
* value before <tt>index</tt> in the list, calling previous()
* will retrieve it (the value at index - 1) and move the iterator
* to that position. So, iterating from front to back starts at
* 0; iterating from back to front starts at <tt>size()</tt>.
*
* @param index an <code>int</code> value
* @return a <code>ListIterator</code> value
*/
public IteratorImpl listIterator(int index)
{
return new IteratorImpl(index);
}
/**
* Returns the number of elements in the list.
*
* @return an <code>int</code> value
*/
public int size()
{
return _size;
}
/**
* Inserts <tt>linkable</tt> at index <tt>index</tt> in the list.
* All values > index are shifted over one position to accomodate
* the new addition.
*
* @param index an <code>int</code> value
* @param linkable an object of type TLinkable
*/
public void add(int index, Object linkable)
{
if (index < 0 || index > size())
{
throw new IndexOutOfBoundsException("index:" + index);
}
insert(index,linkable);
}
/**
* Appends <tt>linkable</tt> to the end of the list.
*
* @param linkable an object of type TLinkable
* @return always true
*/
public boolean add(Object linkable)
{
insert(_size, linkable);
return true;
}
/**
* Inserts <tt>linkable</tt> at the head of the list.
*
* @param linkable an object of type TLinkable
*/
public void addFirst(Object linkable)
{
insert(0, linkable);
}
/**
* Adds <tt>linkable</tt> to the end of the list.
*
* @param linkable an object of type TLinkable
*/
public void addLast(Object linkable)
{
insert(size(), linkable);
}
/**
* Empties the list.
*
*/
public void clear()
{
if (null != _head)
{
for (TLinkable link = _head.getNext();
link != null;
link = link.getNext())
{
TLinkable prev = link.getPrevious();
prev.setNext(null);
link.setPrevious(null);
}
_head = _tail = null;
}
_size = 0;
}
/**
* Copies the list's contents into a native array. This will be a
* shallow copy: the Tlinkable instances in the Object[] array
* have links to one another: changing those will put this list
* into an unpredictable state. Holding a reference to one
* element in the list will prevent the others from being garbage
* collected unless you clear the next/previous links. <b>Caveat
* programmer!</b>
*
* @return an <code>Object[]</code> value
*/
public Object[] toArray()
{
Object[] o = new Object[_size];
int i = 0;
for (TLinkable link = _head; link != null; link = link.getNext())
{
o[i++] = link.getValue();
}
return o;
}
/**
* Copies the list to a native array, destroying the next/previous
* links as the copy is made. This list will be emptied after the
* copy (as if clear() had been invoked). The Object[] array
* returned will contain TLinkables that do <b>not</b> hold
* references to one another and so are less likely to be the
* cause of memory leaks.
*
* @return an <code>Object[]</code> value
*/
public Object[] toUnlinkedArray()
{
Object[] o = new Object[_size];
int i = 0;
for (TLinkable link = _head, tmp = null; link != null; i++)
{
o[i] = link.getValue();
tmp = link;
link = link.getNext();
tmp.setNext(null); // clear the links
tmp.setPrevious(null);
}
_size = 0; // clear the list
_head = _tail = null;
return o;
}
/**
* A linear search for <tt>o</tt> in the list.
*
* @param o an <code>Object</code> value
* @return a <code>boolean</code> value
*/
public boolean contains(Object o)
{
for (TLinkable link = _head; link != null; link = link.getNext())
{
if (o.equals(link))
{
return true;
}
}
return false;
}
/**
* Returns the head of the list
*
* @return an <code>Object</code> value
*/
public Object getFirst()
{
return (_head != null) ? _head.getValue() : null;
}
/**
* Returns the tail of the list.
*
* @return an <code>Object</code> value
*/
public Object getLast()
{
return (_tail != null) ? _tail.getValue() : null;
}
/**
* Remove and return the first element in the list.
*
* @return an <code>Object</code> value
*/
public Object removeFirst()
{
TLinkable o = _head;
TLinkable n = o.getNext();
o.setNext(null);
if (null != n)
{
n.setPrevious(null);
}
_head = n;
if (--_size == 0)
{
_tail = null;
}
return (o != null) ? o.getValue() : null;
}
/**
* Remove and return the last element in the list.
*
* @return an <code>Object</code> value
*/
public Object removeLast()
{
TLinkable o = _tail;
TLinkable prev = o.getPrevious();
o.setPrevious(null);
if (null != prev)
{
prev.setNext(null);
}
_tail = prev;
if (--_size == 0)
{
_head = null;
}
return (o != null) ? o.getValue() : null;
}
/**
* Implementation of index-based list insertions.
*
* @param index an <code>int</code> value
* @param linkable an object of type TLinkable
*/
protected void insert(int index, Object linkable)
{
TLinkable newLink = new TLinkable(linkable);
if (_size == 0)
{
_head = _tail = newLink; // first insertion
}
else if (index == 0)
{
newLink.setNext(_head); // insert at front
_head.setPrevious(newLink);
_head = newLink;
}
else if (index == _size)
{ // insert at back
_tail.setNext(newLink);
newLink.setPrevious(_tail);
_tail = newLink;
}
else
{
TLinkable prior = null, post = null;
// looking at the size of the list, we decide whether
// it's faster to reach `index' by traversing the
// list from the front or the back.
if (index > (_size >> 1))
{ // insert in 2nd half
// work from the tail
int pos = _size -1;
for (prior = _tail; pos > index; pos--)
{
prior = prior.getPrevious();
}
}
else
{ // insert in 1st half
// work from the head
int pos = 0;
for (prior = _head; pos < index; pos++)
{
prior = prior.getNext();
}
}
post = prior.getNext();
// insert newlink
newLink.setNext(post);
newLink.setPrevious(prior);
// adjust adjacent pointers
post.setPrevious(newLink);
prior.setNext(newLink);
}
_size++;
}
/**
* Removes the specified element from the list. Note that
* it is the caller's responsibility to ensure that the
* element does, in fact, belong to this list and not another
* instance of TLinkedList.
*
* @param o a TLinkable element already inserted in this list.
* @return true if the element was a TLinkable and removed
*/
public boolean remove(Object o)
{
TLinkable link = null;
for (link = _head; link != null; link = link.getNext())
{
if (o.equals(link))
{
break;
}
}
if (link != null)
{
TLinkable p, n;
p = link.getPrevious();
n = link.getNext();
if (n == null && p == null)
{ // emptying the list
_head = _tail = null;
}
else if (n == null)
{ // this is the tail
// make previous the new tail
link.setPrevious(null);
p.setNext(null);
_tail = p;
}
else if (p == null)
{ // this is the head
// make next the new head
link.setNext(null);
n.setPrevious(null);
_head = n;
}
else
{ // somewhere in the middle
p.setNext(n);
n.setPrevious(p);
link.setNext(null);
link.setPrevious(null);
}
_size--; // reduce size of list
return true;
}
else
{
return false;
}
}
/**
* Inserts newElement into the list immediately before current.
* All elements to the right of and including current are shifted
* over.
*
* @param current a <code>TLinkable</code> value currently in the list.
* @param newElement a <code>TLinkable</code> value to be added to
* the list.
*/
public void addBefore(TLinkable current, TLinkable newElement)
{
if (current == _head)
{
addFirst(newElement);
}
else if (current == null)
{
addLast(newElement);
}
else
{
TLinkable p = current.getPrevious();
newElement.setNext(current);
p.setNext(newElement);
newElement.setPrevious(p);
current.setPrevious(newElement);
_size++;
}
}
/**
* A ListIterator that supports additions and deletions.
*
*/
public class IteratorImpl
{
private int _nextIndex = 0;
private TLinkable _next;
private TLinkable _lastReturned;
/**
* Creates a new <code>Iterator</code> instance positioned at
* <tt>index</tt>.
*
* @param position an <code>int</code> value
*/
IteratorImpl(int position)
{
if (position < 0 || position > _size)
{
throw new IndexOutOfBoundsException();
}
_nextIndex = position;
if (position == 0)
{
_next = _head;
}
else if (position == _size)
{
_next = null;
}
else if (position < (_size >> 1))
{
int pos = 0;
for (_next = _head; pos < position; pos++)
{
_next = _next.getNext();
}
}
else
{
int pos = _size - 1;
for (_next = _tail; pos > position; pos--)
{
_next = _next.getPrevious();
}
}
}
/**
* Insert <tt>linkable</tt> at the current position of the iterator.
* Calling next() after add() will return the added object.
*
* @param linkable an object of type TLinkable
*/
public final void add(Object linkable)
{
_lastReturned = null;
_nextIndex++;
if (_size == 0)
{
TLinkedList.this.add(linkable);
}
else
{
TLinkedList.this.addBefore(_next, new TLinkable(linkable));
}
}
/**
* True if a call to next() will return an object.
*
* @return a <code>boolean</code> value
*/
public final boolean hasNext()
{
return _nextIndex != _size;
}
/**
* True if a call to previous() will return a value.
*
* @return a <code>boolean</code> value
*/
public final boolean hasPrevious()
{
return _nextIndex != 0;
}
/**
* Returns the value at the Iterator's index and advances the
* iterator.
*
* @return an <code>Object</code> value
* @exception NoSuchElementException if there is no next element
*/
public final Object next()
{
if (_nextIndex == _size)
{
throw new IndexOutOfBoundsException("NoSuchElementException");
}
_lastReturned = _next;
_next = _next.getNext();
_nextIndex++;
return (_lastReturned != null) ? _lastReturned.getValue() : null;
}
/**
* returns the index of the next node in the list (the
* one that would be returned by a call to next()).
*
* @return an <code>int</code> value
*/
public final int nextIndex()
{
return _nextIndex;
}
/**
* Returns the value before the Iterator's index and moves the
* iterator back one index.
*
* @return an <code>Object</code> value
* @exception NoSuchElementException if there is no previous element.
*/
public final Object previous()
{
if (_nextIndex == 0)
{
throw new IndexOutOfBoundsException("NoSuchElementException");
}
if (_nextIndex == _size)
{
_lastReturned = _next = _tail;
}
else
{
_lastReturned = _next = _next.getPrevious();
}
_nextIndex--;
return (_lastReturned != null) ? _lastReturned.getValue() : null;
}
/**
* Returns the previous element's index.
*
* @return an <code>int</code> value
*/
public final int previousIndex()
{
return _nextIndex - 1;
}
/**
* Removes the current element in the list and shrinks its
* size accordingly.
*
* @exception IllegalStateException neither next nor previous
* have been invoked, or remove or add have been invoked after
* the last invocation of next or previous.
*/
public final void remove()
{
if (_lastReturned == null)
{
throw new IllegalStateException("must invoke next or previous before invoking remove");
}
if (_lastReturned != _next)
{
_nextIndex--;
}
_next = _lastReturned.getNext();
TLinkedList.this.remove(_lastReturned);
_lastReturned = null;
}
/**
* Replaces the current element in the list with
* <tt>linkable</tt>
*
* @param linkable an object of type TLinkable
*/
public final void set(Object linkable)
{
if (_lastReturned == null)
{
throw new IllegalStateException();
}
TLinkable l = new TLinkable(linkable);
// need to check both, since this could be the only
// element in the list.
if (_lastReturned == _head)
{
_head = l;
}
if (_lastReturned == _tail)
{
_tail = l;
}
swap(_lastReturned, l);
_lastReturned = l;
}
/**
* Replace from with to in the list.
*
* @param from a <code>TLinkable</code> value
* @param to a <code>TLinkable</code> value
*/
private void swap(TLinkable from, TLinkable to)
{
TLinkable p = from.getPrevious();
TLinkable n = from.getNext();
if (null != p)
{
to.setPrevious(p);
p.setNext(to);
}
if (null != n)
{
to.setNext(n);
n.setPrevious(to);
}
from.setNext(null);
from.setPrevious(null);
}
}
} // TLinkedList
\ No newline at end of file
...@@ -1146,20 +1146,18 @@ public class PluginImpl implements Plugin, PropertyEventListener ...@@ -1146,20 +1146,18 @@ public class PluginImpl implements Plugin, PropertyEventListener
final long timestamp = packet.getTimestamp(); final long timestamp = packet.getTimestamp();
final byte payloadType = packet.getPayloadType(); final byte payloadType = packet.getPayloadType();
executorService.execute(new Runnable() //executorService.execute(new Runnable()
{ //{
public void run() // public void run()
{ // {
try { try {
recorder.write(rtp, 0, rtp.length, true, timestamp, false);
//Log.info("Audio packet type " + payloadType);
} catch (Exception e) { } catch (Exception e) {
Log.error("Error scanning audio", e); Log.error("Error scanning audio", e);
} }
} // }
}); //});
} else { } else {
Log.error("scan audio cannot parse packet data " + packet); Log.error("scan audio cannot parse packet data " + packet);
...@@ -1214,7 +1212,7 @@ public class PluginImpl implements Plugin, PropertyEventListener ...@@ -1214,7 +1212,7 @@ public class PluginImpl implements Plugin, PropertyEventListener
{ {
byte[] full = Arrays.copyOf(encodedFrame, encodedFrame.length); byte[] full = Arrays.copyOf(encodedFrame, encodedFrame.length);
recorder.write(full, 0, full.length, isKeyframe, timestamp); recorder.write(full, 0, full.length, isKeyframe, timestamp, true);
if (isKeyframe && snapshot < 1) if (isKeyframe && snapshot < 1)
{ {
...@@ -1986,7 +1984,7 @@ public class PluginImpl implements Plugin, PropertyEventListener ...@@ -1986,7 +1984,7 @@ public class PluginImpl implements Plugin, PropertyEventListener
byte[] ulawData = new byte[data.length /2]; byte[] ulawData = new byte[data.length /2];
AudioConversion.linearToUlaw(data, 0, ulawData, 0); AudioConversion.linearToUlaw(data, 0, ulawData, 0);
if (recorder != null) recorder.write(ulawData, 0, ulawData.length, false, 0); if (recorder != null) recorder.write(ulawData, 0, ulawData.length, false, 0, false);
} catch (Exception e) { } catch (Exception e) {
......
...@@ -15,11 +15,6 @@ import java.io.FileNotFoundException; ...@@ -15,11 +15,6 @@ import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import org.ebml.*;
import org.ebml.io.*;
import org.ebml.matroska.*;
import org.ebml.util.*;
import org.slf4j.*; import org.slf4j.*;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -27,6 +22,25 @@ import java.text.ParseException; ...@@ -27,6 +22,25 @@ import java.text.ParseException;
import java.util.LinkedList; import java.util.LinkedList;
import com.google.libwebm.mkvmuxer.AudioTrack;
import com.google.libwebm.mkvmuxer.Cues;
import com.google.libwebm.mkvmuxer.MkvMuxer;
import com.google.libwebm.mkvmuxer.MkvWriter;
import com.google.libwebm.mkvmuxer.Segment;
import com.google.libwebm.mkvmuxer.SegmentInfo;
import com.google.libwebm.mkvmuxer.VideoTrack;
import com.google.libwebm.mkvparser.Block;
import com.google.libwebm.mkvparser.BlockEntry;
import com.google.libwebm.mkvparser.Cluster;
import com.google.libwebm.mkvparser.EbmlHeader;
import com.google.libwebm.mkvparser.Frame;
import com.google.libwebm.mkvparser.MkvReader;
import com.google.libwebm.mkvparser.Track;
import com.google.libwebm.mkvparser.Tracks;
import com.google.libvpx.LibVpxEncConfig;
import com.google.libvpx.Rational;
/** /**
* Write audio data to a file * Write audio data to a file
*/ */
...@@ -47,9 +61,12 @@ public class Recorder extends Thread ...@@ -47,9 +61,12 @@ public class Recorder extends Thread
private boolean pcmu; private boolean pcmu;
private int sampleRate; private int sampleRate;
private int channels; private int channels;
private long lastTimecode = 0; private MkvWriter mkvWriter = null;
private MatroskaFileWriter mFW; private Segment muxerSegment = null;
private FileDataWriter iFW; private SegmentInfo muxerSegmentInfo = null;
private long newVideoTrackNumber = 0;
private long newAudioTrackNumber = 0;
private long timestamp = 0;
public Recorder(String recordDirectory, String fileName, String recordingType, boolean pcmu, int sampleRate, int channels) throws IOException public Recorder(String recordDirectory, String fileName, String recordingType, boolean pcmu, int sampleRate, int channels) throws IOException
...@@ -113,28 +130,49 @@ public class Recorder extends Thread ...@@ -113,28 +130,49 @@ public class Recorder extends Thread
private void openWebmFile() throws IOException private void openWebmFile() throws IOException
{ {
iFW = new FileDataWriter(recordPath); Log.info("openWebmFile");
mFW = new MatroskaFileWriter(iFW);
try {
mFW.writeEBMLHeader();
mFW.writeSegmentHeader(); mkvWriter = new MkvWriter();
mFW.writeSegmentInfo();
if (!mkvWriter.open(recordPath)) {
MatroskaFileTrack track = new MatroskaFileTrack(); Log.error("WebM Output name is invalid or error while opening." + recordPath);
track.TrackNo = (short)1; return;
track.TrackUID = (long)1; }
track.TrackType = MatroskaDocType.track_video;
track.Name = "VP8"; muxerSegment = new Segment();
track.CodecName = "VP8";
track.Language = "und"; if (!muxerSegment.init(mkvWriter)) {
track.CodecID = "V_VP8"; Log.error("Could not initialize muxer segment." + recordPath);
track.DefaultDuration = 0; return;
track.Video_PixelWidth = 640; }
track.Video_PixelHeight = 480;
track.CodecPrivate = new byte[0]; muxerSegmentInfo = muxerSegment.getSegmentInfo();
muxerSegmentInfo.setDuration(60 * 1000);
mFW.TrackList.add(track); muxerSegmentInfo.setWritingApp("Jitsi Videobridge");
mFW.writeTracks();
newVideoTrackNumber = muxerSegment.addVideoTrack(640, 480, 0);
//muxerSegment.cuesTrack(newVideoTrackNumber);
if (newVideoTrackNumber == 0) {
Log.error("Could not add video track." + recordPath);
}
/*
newAudioTrackNumber = muxerSegment.addAudioTrack(48000, 1, 0);
muxerSegment.cuesTrack(newAudioTrackNumber);
if (newAudioTrackNumber == 0) {
Log.error("Could not add audio track." + recordPath);
}
muxerSegment.outputCues(true);
*/
timestamp = 0;
} catch (Exception e) {
Log.error("openWebmFile failure " + recordPath, e);
}
} }
private void openFile() throws IOException { private void openFile() throws IOException {
...@@ -304,8 +342,10 @@ public class Recorder extends Thread ...@@ -304,8 +342,10 @@ public class Recorder extends Thread
public int length; public int length;
public boolean keyframe; public boolean keyframe;
public long timestamp; public long timestamp;
public boolean isVideo;
public DataToWrite(byte[] data, int offset, int length, boolean keyframe, long timestamp) public DataToWrite(byte[] data, int offset, int length, boolean keyframe, long timestamp, boolean isVideo)
{ {
/* /*
* We have to copy the data, otherwise caller could * We have to copy the data, otherwise caller could
...@@ -316,6 +356,7 @@ public class Recorder extends Thread ...@@ -316,6 +356,7 @@ public class Recorder extends Thread
this.length = length; this.length = length;
this.keyframe = keyframe; this.keyframe = keyframe;
this.timestamp = timestamp; this.timestamp = timestamp;
this.isVideo = isVideo;
System.arraycopy(data, offset, this.data, 0, length); System.arraycopy(data, offset, this.data, 0, length);
} }
...@@ -347,12 +388,12 @@ public class Recorder extends Thread ...@@ -347,12 +388,12 @@ public class Recorder extends Thread
buf[3] = (byte) (timeChange & 0xff); buf[3] = (byte) (timeChange & 0xff);
System.arraycopy(data, offset, buf, 4, dataLength); System.arraycopy(data, offset, buf, 4, dataLength);
write(buf, 0, buf.length, keyframe, timestamp); write(buf, 0, buf.length, keyframe, timestamp, false);
} else if (recordWebm) { } else if (recordWebm) {
} else { } else {
write(data, offset, dataLength, keyframe, timestamp); write(data, offset, dataLength, keyframe, timestamp, false);
} }
} }
...@@ -365,16 +406,16 @@ public class Recorder extends Thread ...@@ -365,16 +406,16 @@ public class Recorder extends Thread
byteData[(2 * i) + 1] = (byte) (data[i + offset] & 0xff); byteData[(2 * i) + 1] = (byte) (data[i + offset] & 0xff);
} }
write(byteData, 0, byteData.length, keyframe, timestamp); write(byteData, 0, byteData.length, keyframe, timestamp, false);
} }
public void write(byte[] data, int offset, int length, boolean keyframe, long timestamp) throws IOException { public void write(byte[] data, int offset, int length, boolean keyframe, long timestamp, boolean isVideo) throws IOException {
if (done) { if (done) {
return; return;
} }
synchronized(dataToWrite) { synchronized(dataToWrite) {
dataToWrite.add(new DataToWrite(data, offset, length, keyframe, timestamp)); dataToWrite.add(new DataToWrite(data, offset, length, keyframe, timestamp, isVideo));
dataToWrite.notifyAll(); dataToWrite.notifyAll();
} }
} }
...@@ -421,55 +462,31 @@ public class Recorder extends Thread ...@@ -421,55 +462,31 @@ public class Recorder extends Thread
writeDataSize(); writeDataSize();
} }
private void writeData(DataToWrite d) { private void writeData(DataToWrite d)
{
try { try {
synchronized(this) synchronized(this)
{ {
if (recordWebm) if (recordWebm)
{ {
Log.info("writeData " + d.timestamp); if (muxerSegment != null)
long duration = 0;
/*
if (d.keyframe || lastTimecode == 0)
{ {
if (lastTimecode != 0) if (d.isVideo)
{ {
Log.info("writeData end cluster " + d.data); if (!muxerSegment.addFrame(d.data, newVideoTrackNumber, timestamp, d.keyframe)) {
duration = d.timestamp - lastTimecode; Log.error("Could not add video frame." + recordPath);
mFW.endCluster(); }
}
Log.info("writeData start cluster " + d.timestamp);
mFW.startCluster(d.timestamp);
}
lastTimecode = d.timestamp;
MatroskaFileFrame frame = new MatroskaFileFrame(); timestamp = timestamp + (1000000000 / 15);
frame.TrackNo = 1;
frame.Duration = duration;
frame.Timecode = d.timestamp;
frame.Reference = 0;
frame.KeyFrame = d.keyframe;
frame.Data = d.data;
mFW.addFrame(frame);
//Log.info("writeData video " + d.data); } else {
/*
if (!muxerSegment.addFrame(d.data, newAudioTrackNumber, d.timestamp * 1000000, true)) {
Log.error("Could not add audio frame." + recordPath);
}
*/ */
}
duration = d.timestamp - lastTimecode; }
mFW.startCluster(d.timestamp);
MatroskaFileFrame frame = new MatroskaFileFrame();
frame.TrackNo = 1;
frame.Duration = duration;
frame.Timecode = d.timestamp;
frame.Reference = 0;
frame.KeyFrame = d.keyframe;
frame.Data = d.data;
mFW.addFrame(frame);
mFW.endCluster();
lastTimecode = d.timestamp;
} else { } else {
bo.write(d.data, 0, d.length); bo.write(d.data, 0, d.length);
...@@ -482,14 +499,25 @@ public class Recorder extends Thread ...@@ -482,14 +499,25 @@ public class Recorder extends Thread
} }
} }
private void writeDataSize() { private void writeDataSize()
{
Log.info("writeDataSize");
try { try {
synchronized(this) synchronized(this)
{ {
if (recordWebm) if (recordWebm)
{ {
//mFW.endCluster(); if (muxerSegment != null)
iFW.close(); {
if (!muxerSegment.finalizeSegment()) {
Log.error("Finalization of segment failed." + recordPath);
}
if (mkvWriter != null) {
mkvWriter.close();
}
}
} else { } else {
if (bo != null) { if (bo != null) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment