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
final long timestamp = packet.getTimestamp();
final byte payloadType = packet.getPayloadType();
executorService.execute(new Runnable()
{
public void run()
{
//executorService.execute(new Runnable()
//{
// public void run()
// {
try {
//Log.info("Audio packet type " + payloadType);
recorder.write(rtp, 0, rtp.length, true, timestamp, false);
} catch (Exception e) {
Log.error("Error scanning audio", e);
}
}
});
// }
//});
} else {
Log.error("scan audio cannot parse packet data " + packet);
......@@ -1214,7 +1212,7 @@ public class PluginImpl implements Plugin, PropertyEventListener
{
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)
{
......@@ -1986,7 +1984,7 @@ public class PluginImpl implements Plugin, PropertyEventListener
byte[] ulawData = new byte[data.length /2];
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) {
......
......@@ -15,11 +15,6 @@ import java.io.FileNotFoundException;
import java.io.IOException;
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.Logger;
......@@ -27,6 +22,25 @@ import java.text.ParseException;
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
*/
......@@ -47,9 +61,12 @@ public class Recorder extends Thread
private boolean pcmu;
private int sampleRate;
private int channels;
private long lastTimecode = 0;
private MatroskaFileWriter mFW;
private FileDataWriter iFW;
private MkvWriter mkvWriter = null;
private Segment muxerSegment = null;
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
......@@ -113,28 +130,49 @@ public class Recorder extends Thread
private void openWebmFile() throws IOException
{
iFW = new FileDataWriter(recordPath);
mFW = new MatroskaFileWriter(iFW);
mFW.writeEBMLHeader();
mFW.writeSegmentHeader();
mFW.writeSegmentInfo();
MatroskaFileTrack track = new MatroskaFileTrack();
track.TrackNo = (short)1;
track.TrackUID = (long)1;
track.TrackType = MatroskaDocType.track_video;
track.Name = "VP8";
track.CodecName = "VP8";
track.Language = "und";
track.CodecID = "V_VP8";
track.DefaultDuration = 0;
track.Video_PixelWidth = 640;
track.Video_PixelHeight = 480;
track.CodecPrivate = new byte[0];
mFW.TrackList.add(track);
mFW.writeTracks();
Log.info("openWebmFile");
try {
mkvWriter = new MkvWriter();
if (!mkvWriter.open(recordPath)) {
Log.error("WebM Output name is invalid or error while opening." + recordPath);
return;
}
muxerSegment = new Segment();
if (!muxerSegment.init(mkvWriter)) {
Log.error("Could not initialize muxer segment." + recordPath);
return;
}
muxerSegmentInfo = muxerSegment.getSegmentInfo();
muxerSegmentInfo.setDuration(60 * 1000);
muxerSegmentInfo.setWritingApp("Jitsi Videobridge");
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 {
......@@ -304,8 +342,10 @@ public class Recorder extends Thread
public int length;
public boolean keyframe;
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
......@@ -316,6 +356,7 @@ public class Recorder extends Thread
this.length = length;
this.keyframe = keyframe;
this.timestamp = timestamp;
this.isVideo = isVideo;
System.arraycopy(data, offset, this.data, 0, length);
}
......@@ -347,12 +388,12 @@ public class Recorder extends Thread
buf[3] = (byte) (timeChange & 0xff);
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 {
write(data, offset, dataLength, keyframe, timestamp);
write(data, offset, dataLength, keyframe, timestamp, false);
}
}
......@@ -365,16 +406,16 @@ public class Recorder extends Thread
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) {
return;
}
synchronized(dataToWrite) {
dataToWrite.add(new DataToWrite(data, offset, length, keyframe, timestamp));
dataToWrite.add(new DataToWrite(data, offset, length, keyframe, timestamp, isVideo));
dataToWrite.notifyAll();
}
}
......@@ -421,55 +462,31 @@ public class Recorder extends Thread
writeDataSize();
}
private void writeData(DataToWrite d) {
private void writeData(DataToWrite d)
{
try {
synchronized(this)
{
if (recordWebm)
{
Log.info("writeData " + d.timestamp);
long duration = 0;
/*
if (d.keyframe || lastTimecode == 0)
if (muxerSegment != null)
{
if (lastTimecode != 0)
if (d.isVideo)
{
Log.info("writeData end cluster " + d.data);
duration = d.timestamp - lastTimecode;
mFW.endCluster();
}
Log.info("writeData start cluster " + d.timestamp);
mFW.startCluster(d.timestamp);
if (!muxerSegment.addFrame(d.data, newVideoTrackNumber, timestamp, d.keyframe)) {
Log.error("Could not add video frame." + recordPath);
}
lastTimecode = d.timestamp;
timestamp = timestamp + (1000000000 / 15);
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);
//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 {
bo.write(d.data, 0, d.length);
......@@ -482,14 +499,25 @@ public class Recorder extends Thread
}
}
private void writeDataSize() {
private void writeDataSize()
{
Log.info("writeDataSize");
try {
synchronized(this)
{
if (recordWebm)
{
//mFW.endCluster();
iFW.close();
if (muxerSegment != null)
{
if (!muxerSegment.finalizeSegment()) {
Log.error("Finalization of segment failed." + recordPath);
}
if (mkvWriter != null) {
mkvWriter.close();
}
}
} else {
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