Skip to content

Commit

Permalink
[common] New Fast MP4 framework #WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
aldenml committed Mar 22, 2016
1 parent 43124d1 commit bff4c1e
Show file tree
Hide file tree
Showing 20 changed files with 1,146 additions and 0 deletions.
74 changes: 74 additions & 0 deletions common/src/main/java/com/frostwire/fmp4/Bits.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Created by Angel Leon (@gubatron), Alden Torres (aldenml)
* Copyright (c) 2011-2016, FrostWire(R). All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.frostwire.fmp4;

import java.io.UnsupportedEncodingException;

/**
* @author gubatron
* @author aldenml
*/
final class Bits {

private Bits() {
}

public static byte int3(int x) {
return (byte) (x >> 24);
}

public static byte int2(int x) {
return (byte) (x >> 16);
}

public static byte int1(int x) {
return (byte) (x >> 8);
}

public static byte int0(int x) {
return (byte) (x);
}

public static int int32(byte b3, byte b2, byte b1, byte b0) {
return (((b3) << 24) |
((b2 & 0xff) << 16) |

This comment has been minimized.

Copy link
@gubatron

gubatron Mar 22, 2016

Collaborator

just out of curiosity, why x & 0xff? (doesn't this always return the same number for all n in [0,255])
can you have negative byte values?

This comment has been minimized.

Copy link
@aldenml

aldenml Mar 22, 2016

Author Collaborator

The byte in java is signed, then you need to convert the x to unsigned, this is only possible if the result type is bigger, but this happen automatically in the type promotion since 0xff is an integer.

This comment has been minimized.

Copy link
@gubatron

gubatron Mar 22, 2016

Collaborator

wow that's crazy "The byte in java is signed", that means a byte is always more than a byte, they gotta have the sign somewhere for every byte out there.

This comment has been minimized.

Copy link
@gubatron

gubatron Mar 22, 2016

Collaborator

so on that note, I wonder then why the sign conversion isn't done on ((b3) << 24) |

This comment has been minimized.

Copy link
@aldenml

aldenml Mar 22, 2016

Author Collaborator

the java byte is 8 bits, one sign bit give you [-128, 127] using two complement representation, a total of 256 values. Now, the b3 in the code is not & because it's not necessary, it's the most significant byte, and it carries the sign bit already.

((b1 & 0xff) << 8) |
((b0 & 0xff)));
}

public static String make4cc(int c) {
byte[] code = new byte[]{int3(c), int2(c), int1(c), int0(c)};

try {
return new String(code, "ISO-8859-1");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}

public static int make4cc(String c) {
byte[] code;
try {
code = c.getBytes("ISO-8859-1");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}

return int32(code[0], code[1], code[2], code[3]);
}
}
174 changes: 174 additions & 0 deletions common/src/main/java/com/frostwire/fmp4/Box.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* Created by Angel Leon (@gubatron), Alden Torres (aldenml)
* Copyright (c) 2011-2016, FrostWire(R). All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.frostwire.fmp4;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

/**
* @author gubatron
* @author aldenml
*/
public abstract class Box {

public static final int uuid = Bits.make4cc("uuid");
public static final int mdat = Bits.make4cc("mdat");
public static final int ftyp = Bits.make4cc("ftyp");
public static final int moov = Bits.make4cc("moov");
public static final int mvhd = Bits.make4cc("mvhd");
public static final int iods = Bits.make4cc("iods");
public static final int trak = Bits.make4cc("trak");
public static final int tkhd = Bits.make4cc("tkhd");
public static final int edts = Bits.make4cc("edts");
public static final int elst = Bits.make4cc("elst");
public static final int udta = Bits.make4cc("udta");
public static final int mdia = Bits.make4cc("mdia");

private static final Map<Integer, BoxLambda> mapping = buildMapping();

protected int size;
protected int type;
protected Long largesize;
protected byte[] usertype;
protected LinkedList<Box> boxes;

private long length;

Box() {
}

void header(int size, int type, Long largesize, byte[] usertype) {
this.size = size;
this.type = type;
this.largesize = largesize;
this.usertype = usertype;

// set length
length = size - 8;
if (size == 1) {
length = largesize - 16;
} else if (size == 0) {
length = -1;
}
if (type == uuid) {
length -= 16;
}
}

long length() {
return length;
}

void read(InputChannel in, ByteBuffer buf) throws IOException {
long len = length();

if (len > 0) {
IO.skip(in, len, buf);
} else {
IO.skip(in, buf);
}
}

@Override
public String toString() {
return Bits.make4cc(type);
}

static Box empty(int type) throws IOException {
BoxLambda p = mapping.get(type);
if (p != null) {
return p.empty();
} else {
return new UnknownBox();
}
}

private static Map<Integer, BoxLambda> buildMapping() {
Map<Integer, BoxLambda> map = new HashMap<>();

map.put(ftyp, new BoxLambda() {
@Override
public Box empty() {
return new FileTypeBox();
}
});
map.put(moov, new BoxLambda() {
@Override
public Box empty() {
return new MovieBox();
}
});
map.put(mvhd, new BoxLambda() {
@Override
public Box empty() {
return new MovieHeaderBox();
}
});
map.put(iods, new BoxLambda() {
@Override
public Box empty() {
return new ObjectDescriptorBox();
}
});
map.put(trak, new BoxLambda() {
@Override
public Box empty() {
return new TrackBox();
}
});
map.put(tkhd, new BoxLambda() {
@Override
public Box empty() {
return new TrackHeaderBox();
}
});
map.put(edts, new BoxLambda() {
@Override
public Box empty() {
return new EditBox();
}
});
map.put(elst, new BoxLambda() {
@Override
public Box empty() {
return new EditListBox();
}
});
map.put(udta, new BoxLambda() {
@Override
public Box empty() {
return new UserDataBox();
}
});
map.put(mdia, new BoxLambda() {
@Override
public Box empty() {
return new MediaBox();
}
});

return map;
}

private interface BoxLambda {
Box empty();
}
}
35 changes: 35 additions & 0 deletions common/src/main/java/com/frostwire/fmp4/ContainerBox.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Created by Angel Leon (@gubatron), Alden Torres (aldenml)
* Copyright (c) 2011-2016, FrostWire(R). All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.frostwire.fmp4;

import java.io.IOException;
import java.nio.ByteBuffer;

/**
* @author gubatron
* @author aldenml
*/
public abstract class ContainerBox extends Box {

ContainerBox() {
}

@Override
void read(InputChannel in, ByteBuffer buf) throws IOException {
}
}
28 changes: 28 additions & 0 deletions common/src/main/java/com/frostwire/fmp4/EditBox.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Created by Angel Leon (@gubatron), Alden Torres (aldenml)
* Copyright (c) 2011-2016, FrostWire(R). All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.frostwire.fmp4;

/**
* @author gubatron
* @author aldenml
*/
public final class EditBox extends ContainerBox {

EditBox() {
}
}
66 changes: 66 additions & 0 deletions common/src/main/java/com/frostwire/fmp4/EditListBox.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Created by Angel Leon (@gubatron), Alden Torres (aldenml)
* Copyright (c) 2011-2016, FrostWire(R). All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.frostwire.fmp4;

import java.io.IOException;
import java.nio.ByteBuffer;

/**
* @author gubatron
* @author aldenml
*/
public final class EditListBox extends FullBox {

protected int entry_count;
protected Entry[] entries;

EditListBox() {
}

@Override
void read(InputChannel in, ByteBuffer buf) throws IOException {
super.read(in, buf);

IO.read(in, 4, buf);
entry_count = buf.getInt();
entries = new Entry[entry_count];
for (int i = 0; i < entry_count; i++) {
Entry e = new Entry();
if (version == 1) {
IO.read(in, 16, buf);
e.segment_duration = buf.getLong();
e.media_time = buf.getLong();
} else {
IO.read(in, 8, buf);
e.segment_duration = buf.getInt();
e.media_time = buf.getInt();
}
IO.read(in, 4, buf);
e.media_rate_integer = buf.getShort();
e.media_rate_fraction = buf.getShort();
entries[i] = e;
}
}

private static final class Entry {
public long segment_duration;
public long media_time;
public short media_rate_integer;
public short media_rate_fraction;
}
}

0 comments on commit bff4c1e

Please sign in to comment.