PictureSign: Theora Addon

Big thanks to @unascribed (https://github.com/TeamMidnightDust/PictureSign/pull/23)
This commit is contained in:
Martin Prokoph
2024-07-07 20:11:57 +02:00
parent caf1c99392
commit 732e3420fb
86 changed files with 17041 additions and 0 deletions

26
.gitignore vendored Executable file
View File

@@ -0,0 +1,26 @@
# gradle
.gradle/
out/
classes/
build/
# idea
.idea/
*.iml
*.ipr
*.iws
# vscode
.settings/
.vscode/
bin/
.classpath
.project
# fabric
run/
/.architectury-transformer

81
build.gradle Executable file
View File

@@ -0,0 +1,81 @@
plugins {
id "architectury-plugin" version "3.4-SNAPSHOT"
id "dev.architectury.loom" version "1.6-SNAPSHOT" apply false
//id "me.shedaniel.unified-publishing" version "0.1.+" apply false
id 'com.github.johnrengelman.shadow' version '8.1.1' apply false
}
architectury {
minecraft = rootProject.minecraft_version
}
repositories {
maven {
url = "https://api.modrinth.com/maven"
}
maven { url 'https://jitpack.io' }
}
subprojects {
apply plugin: "dev.architectury.loom"
repositories {
maven {
url = "https://api.modrinth.com/maven"
}
maven { url 'https://jitpack.io' }
}
dependencies {
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
// The following line declares the mojmap mappings, you may use other mappings as well
//mappings loom.officialMojangMappings()
// The following line declares the yarn mappings you may select this one as well.
mappings loom.layered {
it.mappings("net.fabricmc:yarn:$rootProject.yarn_mappings:v2")
it.mappings("dev.architectury:yarn-mappings-patch-neoforge:$rootProject.yarn_mappings_patch_neoforge_version")
}
}
}
allprojects {
apply plugin: "java"
apply plugin: "architectury-plugin"
apply plugin: "maven-publish"
archivesBaseName = rootProject.archives_base_name
version = rootProject.mod_version
group = rootProject.maven_group
repositories {
// Add repositories to retrieve artifacts from in here.
// You should only use this when depending on other mods because
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
// for more information about repositories.
}
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
options.release = 21
}
ext {
releaseChangelog = {
def changes = new StringBuilder()
changes << "## PictureSignTheora v$project.version for $project.minecraft_version\n[View the changelog](https://www.github.com/TeamMidnightDust/PictureSignTheora/commits/)"
def proc = "git log --max-count=1 --pretty=format:%s".execute()
proc.in.eachLine { line ->
def processedLine = line.toString()
if (!processedLine.contains("New translations") && !processedLine.contains("Merge") && !processedLine.contains("branch")) {
changes << "\n- ${processedLine.capitalize()}"
}
}
proc.waitFor()
return changes.toString()
}
}
java {
withSourcesJar()
}
}

25
common/build.gradle Normal file
View File

@@ -0,0 +1,25 @@
architectury {
common(rootProject.enabled_platforms.split(","))
}
dependencies {
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
// Do NOT use other classes from fabric loader
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
modCompileOnlyApi "maven.modrinth:midnightlib:${rootProject.midnightlib_version}-fabric"
modCompileOnlyApi "maven.modrinth:picturesign:${rootProject.picturesign_version}-fabric"
}
publishing {
publications {
mavenCommon(MavenPublication) {
artifactId = rootProject.archives_base_name
from components.java
}
}
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
repositories {
// Add repositories to publish to here.
}
}

View File

@@ -0,0 +1,10 @@
package eu.midnightdust.picturesign_theora;
import eu.midnightdust.picturesign.util.MediaHandler;
import eu.midnightdust.picturesign_theora.util.TheoraMediaHandler;
public class PictureSignTheoraClient {
public static void init() {
MediaHandler.registerHandler(TheoraMediaHandler::new);
}
}

View File

@@ -0,0 +1,19 @@
package eu.midnightdust.picturesign_theora.mixin;
import eu.midnightdust.picturesign_theora.util.TheoraMediaHandler;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.client.MinecraftClient;
@Mixin(MinecraftClient.class)
public class MixinMinecraftClient {
@Inject(at=@At("HEAD"), method="render")
public void picturesign$updateVideos(boolean b, CallbackInfo ci) {
TheoraMediaHandler.manager.update();
}
}

View File

@@ -0,0 +1,351 @@
package eu.midnightdust.picturesign_theora.ogv;
import eu.midnightdust.picturesign_theora.ogv.jheora.TheoraComment;
import eu.midnightdust.picturesign_theora.ogv.jheora.TheoraInfo;
import eu.midnightdust.picturesign_theora.ogv.jheora.TheoraState;
import eu.midnightdust.picturesign_theora.ogv.jheora.YUVBuffer;
import eu.midnightdust.picturesign_theora.ogv.jogg.OggPacket;
import eu.midnightdust.picturesign_theora.ogv.jogg.OggPage;
import eu.midnightdust.picturesign_theora.ogv.jogg.OggStreamState;
import eu.midnightdust.picturesign_theora.ogv.jogg.OggSyncState;
import eu.midnightdust.picturesign_theora.ogv.jorbis.VorbisBlock;
import eu.midnightdust.picturesign_theora.ogv.jorbis.VorbisDspState;
import eu.midnightdust.picturesign_theora.ogv.jorbis.VorbisComment;
import eu.midnightdust.picturesign_theora.ogv.jorbis.VorbisInfo;
import java.io.IOException;
import java.io.InputStream;
public class Ogv {
public record VideoFrame(int width, int height, int[] rgba, long durationNs) {}
private final InputStream in;
public Ogv(InputStream in) throws IOException {
this.in = in;
initialize();
}
public TheoraInfo getTheoraInfo() {
return ti;
}
public VorbisInfo getVorbisInfo() {
return vi;
}
private final OggPacket op = new OggPacket();
private final OggSyncState oy = new OggSyncState();
private final OggPage og = new OggPage();
private OggStreamState vo = new OggStreamState();
private OggStreamState to = new OggStreamState();
private final TheoraInfo ti = new TheoraInfo();
private final TheoraComment tc = new TheoraComment();
private final TheoraState td = new TheoraState();
private final VorbisInfo vi = new VorbisInfo();
private final VorbisDspState vd = new VorbisDspState();
private final VorbisBlock vb = new VorbisBlock(this.vd);
private VorbisComment vc = new VorbisComment();
private int theora_p = 0;
private int vorbis_p = 0;
private int stateflag = 0;
private int videobuf_ready = 0;
private int audiobuf_fill = 0;
private int audiobuf_ready = 0;
private short[] audiobuf;
private int audiofd_fragsize;
private boolean end = false;
private long granule = 0;
private VideoFrame video;
private short[] audio;
public long getGranule() {
return granule;
}
public VideoFrame getVideo() {
var v = video;
video = null;
return v;
}
public short[] getAudio() {
var a = audio;
audio = null;
return a;
}
public boolean isEnd() {
return end;
}
private int buffer_data() throws IOException {
int fill = oy.buffer(4096);
byte[] buffer2 = oy.data;
int bytes = in.read(buffer2, fill, 4096);
if (bytes < 0) {
return bytes;
} else {
oy.wrote(bytes);
return bytes;
}
}
void video_write() {
YUVBuffer yuv = new YUVBuffer();
this.td.decodeYUVout(yuv);
int[] pixels = yuv.produce();
video = new VideoFrame(yuv.y_width, yuv.y_height, pixels, (ti.fps_denominator*1_000_000_000L)/ti.fps_numerator);
}
void audio_write() {
audio = audiobuf.clone();
}
int queue_page(OggPage page) {
if (this.theora_p != 0) {
this.to.pagein(this.og);
}
if (this.vorbis_p != 0) {
this.vo.pagein(this.og);
}
return 0;
}
private void initialize() throws IOException {
this.oy.init();
this.vi.init();
this.vc.init();
while (this.stateflag == 0) {
int read = this.buffer_data();
if (read <= 0) {
break;
}
while (this.oy.pageout(this.og) > 0) {
OggStreamState test = new OggStreamState();
if (this.og.bos() == 0) {
this.queue_page(this.og);
this.stateflag = 1;
break;
}
test.init(this.og.serialno());
test.pagein(this.og);
test.packetout(op);
if (this.theora_p == 0 && this.ti.decodeHeader(this.tc, op) >= 0) {
this.to = test;
this.theora_p = 1;
} else if (this.vorbis_p == 0 && this.vi.synthesis_headerin(this.vc, op) >= 0) {
this.vo = test;
this.vorbis_p = 1;
} else {
test.clear();
}
}
}
while (this.theora_p != 0 && this.theora_p < 3 || this.vorbis_p != 0 && this.vorbis_p < 3) {
int err;
if (this.theora_p != 0 && this.theora_p < 3 && (err = this.to.packetout(op)) != 0) {
if (err < 0) {
System.err.printf("Error parsing first Theora packet; corrupt stream? error %d\n", err);
end = true;
return;
}
if ((err = this.ti.decodeHeader(this.tc, op)) != 0) {
System.err.printf("Error parsing Theora stream headers; corrupt stream? error %d\n", err);
end = true;
return;// if (this.vorbis_p != 0) {
// this.vo.clear();
// this.vb.clear();
// this.vd.clear();
// this.vi.clear();
// }
//
// if (this.theora_p != 0) {
// this.to.clear();
// this.td.clear();
// this.ti.clear();
// }
}
++this.theora_p;
if (this.theora_p != 3) {
continue;
}
}
while (true) {
if (this.vorbis_p != 0 && this.vorbis_p < 3 && (err = this.vo.packetout(op)) != 0) {
if (err < 0) {
System.err.printf("Error parsing Vorbis stream headers; corrupt stream? error %d\n", err);
end = true;
return;
}
if ((err = this.vi.synthesis_headerin(this.vc, op)) != 0) {
System.err.printf("Error parsing Vorbis stream headers; corrupt stream? error %d\n", err);
end = true;
return;
}
++this.vorbis_p;
if (this.vorbis_p != 3) {
continue;
}
}
if (this.oy.pageout(this.og) > 0) {
this.queue_page(this.og);
} else {
int ret2 = this.buffer_data();
if (ret2 <= 0) {
System.err.print("End of file while searching for codec headers.\n");
end = true;
return;
}
}
break;
}
}
if (this.theora_p != 0) {
this.td.decodeInit(this.ti);
// System.out
// .printf(
// "Ogg logical stream %x is Theora %dx%d %.02f fps",
// getSerialNo(this.to),
// this.ti.width,
// this.ti.height,
// (double) this.ti.fps_numerator / (double) this.ti.fps_denominator);
// if (this.ti.width != this.ti.frame_width || this.ti.height != this.ti.frame_height) {
// System.out
// .printf(" Frame content is %dx%d with offset (%d,%d).\n", this.ti.frame_width, this.ti.frame_height, this.ti.offset_x, this.ti.offset_y);
// }
} else {
this.ti.clear();
}
if (this.vorbis_p != 0) {
this.vd.synthesis_init(this.vi);
this.vb.init(this.vd);
audiobuf = new short[vi.rate/4];
audiofd_fragsize = vi.rate/2;
// System.out.printf("Ogg logical stream %x is Vorbis %d channel %d Hz audio.\n", getSerialNo(this.vo), this.vi.channels, this.vi.rate);
} else {
this.vi.clear();
}
this.stateflag = 0;
}
public void step() throws IOException {
if (this.vorbis_p != 0 && this.audiobuf_ready == 0) {
float[][][] pcm = new float[1][][];
int[] index = new int[this.vi.channels];
int ret;
if ((ret = this.vd.synthesis_pcmout(pcm, index)) > 0) {
float[][] floatArrays = pcm[0];
int count = this.audiobuf_fill / 2;
int maxsamples = (this.audiofd_fragsize - this.audiobuf_fill) / 2 / this.vi.channels;
int i;
for (i = 0; i < ret && i < maxsamples; ++i) {
for (int j = 0; j < this.vi.channels; ++j) {
int val = Math.round(floatArrays[j][index[j] + i] * 32767.0F);
if (val > 32767) {
val = 32767;
}
if (val < -32768) {
val = -32768;
}
this.audiobuf[count++] = (short) val;
}
}
this.vd.synthesis_read(i);
this.audiobuf_fill += i * this.vi.channels * 2;
if (this.audiobuf_fill == this.audiofd_fragsize) {
this.audiobuf_ready = 1;
}
return;
}
if (this.vo.packetout(op) > 0) {
if (this.vb.synthesis(op) == 0) {
this.vd.synthesis_blockin(this.vb);
}
return;
}
}
while (this.theora_p != 0 && this.videobuf_ready == 0 && this.to.packetout(op) > 0) {
this.td.decodePacketin(op);
this.videobuf_ready = 1;
}
if (this.videobuf_ready == 0 || this.audiobuf_ready == 0) {
int bytes = this.buffer_data();
if (bytes < 0) {
while (this.oy.pageout(this.og) > 0) {
this.queue_page(this.og);
}
if (this.videobuf_ready == 0 && this.audiobuf_ready == 0) {
close();
return;
}
}
while (this.oy.pageout(this.og) > 0) {
this.queue_page(this.og);
}
}
if (this.stateflag != 0 && this.audiobuf_ready != 0) {
this.audio_write();
this.audiobuf_fill = 0;
this.audiobuf_ready = 0;
}
if (this.stateflag != 0 && this.videobuf_ready != 0) {
this.video_write();
this.videobuf_ready = 0;
}
if ((this.theora_p == 0 || this.videobuf_ready != 0) && (this.vorbis_p == 0 || this.audiobuf_ready != 0)) {
this.stateflag = 1;
}
granule = op.granulepos;
}
public void close() throws IOException {
// if (this.vorbis_p != 0) {
// this.vo.clear();
// this.vb.clear();
// this.vd.clear();
// this.vi.clear();
// }
//
// if (this.theora_p != 0) {
// this.to.clear();
// this.td.clear();
// this.ti.clear();
// }
// this.oy.clear();
in.close();
end = true;
}
}

View File

@@ -0,0 +1,359 @@
package eu.midnightdust.picturesign_theora.ogv;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.net.SocketException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpClient.Redirect;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse.BodyHandler;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.IntBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.ArrayDeque;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import org.lwjgl.system.MemoryUtil;
import com.mojang.blaze3d.platform.GlStateManager;
import com.google.common.io.ByteSource;
import com.google.common.io.MoreFiles;
import eu.midnightdust.picturesign_theora.ogv.Ogv.VideoFrame;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.texture.AbstractTexture;
import net.minecraft.resource.ResourceManager;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.Identifier;
import static org.lwjgl.opengl.GL12C.*;
import static org.lwjgl.openal.AL11.*;
public class Video {
private static final HttpClient client = HttpClient.newBuilder()
.followRedirects(Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(30))
.build();
private IntBuffer nativeBuffer;
private static final AtomicInteger nextId = new AtomicInteger();
private volatile AtomicBoolean alive = new AtomicBoolean(true);
private volatile boolean reset = false;
private boolean destroyed = false;
private String url = null;
private boolean playing = false;
private volatile long time = 0;
private volatile ArrayBlockingQueue<VideoFrame> videoQueue = new ArrayBlockingQueue<>(30);
//private final Identifier textureId;
private final AbstractTexture tex;
private volatile Ogv ogv;
private boolean repeat = false;
private Thread thread;
private volatile int alSourceName = -1;
private final ArrayDeque<Integer> unusedBuffers = new ArrayDeque<>();
private final IntList allBuffers = new IntArrayList();
private volatile long seekTarget = -1;
private volatile boolean audioReady = false;
private boolean stereo = false;
private long nextFrameUpdate = 0;
//private float x, y, z;
private int volume;
public Video(Identifier id) {
//this.textureId = new Identifier("dynamic/picturesign/video_"+nextId.getAndIncrement());
tex = new AbstractTexture() {
@Override public void load(ResourceManager manager) throws IOException {}
};
tex.setFilter(true, false);
//MinecraftClient.getInstance().getTextureManager().registerTexture(textureId, tex);
}
public void update() {
if (ogv != null && playing) {
var now = System.nanoTime();
if (!audioReady && videoQueue.remainingCapacity() > 0) {
// don't play video until audio is ready unless the video queue is full
return;
}
VideoFrame frame = null;
while (now > nextFrameUpdate) {
frame = videoQueue.poll();
if (frame == null) return;
if (nextFrameUpdate == 0) {
nextFrameUpdate = now;
} else {
nextFrameUpdate += frame.durationNs();
}
}
if (frame == null) return;
if (nativeBuffer == null) {
nativeBuffer = MemoryUtil.memCallocInt(frame.rgba().length);
} else if (nativeBuffer.capacity() < frame.rgba().length) {
nativeBuffer = MemoryUtil.memRealloc(nativeBuffer, frame.rgba().length);
}
nativeBuffer.clear();
nativeBuffer.put(frame.rgba()).flip();
GlStateManager._bindTexture(tex.getGlId()); // do it directly to dodge sketchy mixins
GlStateManager._pixelStore(GL_UNPACK_ROW_LENGTH, 0);
GlStateManager._pixelStore(GL_UNPACK_SKIP_ROWS, 0);
GlStateManager._pixelStore(GL_UNPACK_SKIP_PIXELS, 0);
GlStateManager._pixelStore(GL_UNPACK_ALIGNMENT, 4);
GlStateManager._texImage2D(GL_TEXTURE_2D, 0, GL_RGB, frame.width(), frame.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, nativeBuffer);
if (alSourceName != -1) {
alSourcef(alSourceName, AL_GAIN, volume);
if (alGetSourcei(alSourceName, AL_SOURCE_STATE) != AL_PLAYING) {
alSourcePlay(alSourceName);
alSourcei(alSourceName, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE);
alSourcei(alSourceName, AL_SOURCE_RELATIVE, AL_FALSE);
alSourcef(alSourceName, AL_MAX_DISTANCE, 24);
alSourcef(alSourceName, AL_ROLLOFF_FACTOR, 1);
alSourcef(alSourceName, AL_REFERENCE_DISTANCE, 0);
}
}
}
}
public void destroy() {
if (ogv != null) {
try {
ogv.close();
} catch (IOException ignored) {}
}
playing = false;
alive.set(false);
if (alSourceName != -1) {
alDeleteSources(alSourceName);
alDeleteBuffers(allBuffers.toIntArray());
allBuffers.clear();
alSourceName = -1;
}
if (nativeBuffer != null) MemoryUtil.memFree(nativeBuffer);
nativeBuffer = null;
destroyed = true;
//MinecraftClient.getInstance().getTextureManager().destroyTexture(textureId);
}
public void stop() {
playing = false;
}
public void play(String url) {
if (thread != null) {
if (url.equals(this.url)) {
playing = true;
return;
}
if (alSourceName != -1) {
alDeleteSources(alSourceName);
alDeleteBuffers(allBuffers.toIntArray());
allBuffers.clear();
alSourceName = -1;
}
var oldVideoQueue = this.videoQueue;
var oldAlive = this.alive;
videoQueue = new ArrayBlockingQueue<>(10);
alive = new AtomicBoolean(true);
// clear old queues to unblock the thread so it realizes it should exit
oldAlive.set(false);
oldVideoQueue.clear();
}
playing = true;
this.url = url;
// make local references so we can abandon old threads without having to wait for them to exit
var alive = this.alive;
var videoQueue = this.videoQueue;
thread = new Thread(() -> {
Path tmpFile = null;
try {
var req = HttpRequest.newBuilder(URI.create(url))
.header("User-Agent", "PictureSign Theora")
.header("Accept", "video/ogg; codecs=\"theora, vorbis\"")
.build();
ByteSource src;
if (repeat) {
// assume it's a short video that we don't want to be constantly redownloading
tmpFile = Files.createTempFile("picturesign", ".ogv");
src = retrying(req, BodyHandlers.ofFile(tmpFile), MoreFiles::asByteSource);
} else {
src = new ByteSource() {
@Override
public InputStream openStream() throws IOException {
try {
return retrying(req, BodyHandlers.ofInputStream(), t -> t);
} catch (InterruptedException e) {
throw new InterruptedIOException();
}
}
};
}
if (src == null) return;
ogv = new Ogv(src.openStream());
if (ogv.getVorbisInfo().channels == 0) {
// there will be no audio data, let the video run free
audioReady = true;
}
while (alive.get()) {
ogv.step();
if (ogv.isEnd() || reset) {
ogv.close();
if (repeat || reset) {
reset = false;
ogv = new Ogv(src.openStream());
continue;
} else {
ogv = null;
}
playing = false;
break;
}
var vid = ogv.getVideo();
if (vid != null) {
var info = ogv.getTheoraInfo();
time += (info.fps_denominator*1000)/info.fps_numerator;
}
var aud = ogv.getAudio();
if (seekTarget != -1) {
if (time < seekTarget) continue;
seekTarget = -1;
}
if (aud != null) {
if (alSourceName == -1) {
alSourceName = alGenSources();
alSourcef(alSourceName, AL_GAIN, volume);
if (ogv.getVorbisInfo().channels == 2) {
stereo = true;
} else {
stereo = false;
}
}
int[] unqueuedNames = new int[1];
while (true) {
unqueuedNames[0] = 0;
alSourceUnqueueBuffers(alSourceName, unqueuedNames);
if (alGetError() == 0 && unqueuedNames[0] != 0) {
unusedBuffers.add(unqueuedNames[0]);
} else {
break;
}
}
var buffer = unusedBuffers.poll();
if (buffer == null) {
buffer = alGenBuffers();
allBuffers.add(buffer.intValue());
}
alBufferData(buffer, ogv.getVorbisInfo().channels == 2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16, aud, ogv.getVorbisInfo().rate);
alSourceQueueBuffers(alSourceName, buffer);
if (!audioReady && alGetSourcei(alSourceName, AL_BUFFERS_QUEUED) > 12) {
audioReady = true;
}
}
if (vid != null) {
videoQueue.put(vid);
}
}
} catch (ClosedChannelException | SocketException e) {
// ogv got closed by destroy
} catch (IOException e) {
e.printStackTrace();
System.err.println("IO exception while decoding video from "+url);
} catch (InterruptedException e) {
throw new AssertionError(e);
} catch (IllegalArgumentException e) {
// bad url
} finally {
try {
if (tmpFile != null) Files.delete(tmpFile);
} catch (IOException e) {}
}
}, "Video decode thread ("+url+")");
thread.setDaemon(true);
thread.start();
}
private static <T, U> T retrying(HttpRequest req, BodyHandler<U> bodyHandler, Function<U, T> callback) throws IOException, InterruptedException {
int retries = 0;
while (true) {
var res = client.send(req, bodyHandler);
if (res.statusCode()/100 == 2) {
return callback.apply(res.body());
} else if (res.statusCode()/100 == 4) {
System.err.println("Server returned non-transient error "+res.statusCode()+" for "+req.uri());
return null;
} else {
retries++;
if (retries > 5) {
System.err.println("Maximum retries exceeded, giving up.");
return null;
} else {
System.err.println("Server returned error "+res.statusCode()+" for "+req.uri()+" - retrying in "+retries+"s");
}
Thread.sleep(retries*1000);
}
}
}
public boolean hasMedia() {
// returning true here will make the video not get updated when the sign is changed
return false;
}
public boolean isStopped() {
return !playing;
}
public void setRepeat(boolean value) {
this.repeat = value;
if (value && !playing && url != null) {
play(url);
}
}
public long getTime() {
return ogv == null ? 0 : time;
}
public void setTime(long value) {
if (value > time) {
reset = true;
}
seekTarget = value;
videoQueue.clear();
}
public int getTextureId() {
return tex.getGlId();
}
public float getFrameRate() {
return ogv == null ? 0 : ogv.getTheoraInfo().fps_numerator/((float)ogv.getTheoraInfo().fps_denominator);
}
public void setVolume(int volume) {
this.volume = volume;
}
}

View File

@@ -0,0 +1,25 @@
package eu.midnightdust.picturesign_theora.ogv;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.util.Identifier;
public class VideoManager {
private final Map<Identifier, Video> videos = new HashMap<>();
public void update() {
videos.values().forEach(Video::update);
}
public void closePlayer(Identifier id) {
var v = videos.remove(id);
if (v != null) v.destroy();
}
public Video getOrCreate(Identifier id) {
return videos.computeIfAbsent(id, Video::new);
}
}

View File

@@ -0,0 +1,90 @@
/* Cortado - a video player java applet
* Copyright (C) 2004 Fluendo S.L.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public class Base64Converter
{
public static final char[] alphabet = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0 to 7
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 8 to 15
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 16 to 23
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 24 to 31
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 32 to 39
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 40 to 47
'w', 'x', 'y', 'z', '0', '1', '2', '3', // 48 to 55
'4', '5', '6', '7', '8', '9', '+', '/'
}; // 56 to 63
public static String encode (byte[]octetString)
{
int bits24;
int bits6;
char[] out = new char[((octetString.length - 1) / 3 + 1) * 4];
int outIndex = 0;
int i = 0;
while ((i + 3) <= octetString.length)
{
// store the octets
bits24 = (octetString[i++] & 0xFF) << 16;
bits24 |= (octetString[i++] & 0xFF) << 8;
bits24 |= (octetString[i++] & 0xFF) << 0;
bits6 = (bits24 & 0x00FC0000) >> 18;
out[outIndex++] = alphabet[bits6];
bits6 = (bits24 & 0x0003F000) >> 12;
out[outIndex++] = alphabet[bits6];
bits6 = (bits24 & 0x00000FC0) >> 6;
out[outIndex++] = alphabet[bits6];
bits6 = (bits24 & 0x0000003F);
out[outIndex++] = alphabet[bits6];
}
if (octetString.length - i == 2)
{
bits24 = (octetString[i] & 0xFF) << 16;
bits24 |= (octetString[i + 1] & 0xFF) << 8;
bits6 = (bits24 & 0x00FC0000) >> 18;
out[outIndex++] = alphabet[bits6];
bits6 = (bits24 & 0x0003F000) >> 12;
out[outIndex++] = alphabet[bits6];
bits6 = (bits24 & 0x00000FC0) >> 6;
out[outIndex++] = alphabet[bits6];
out[outIndex++] = '=';
}
else if (octetString.length - i == 1)
{
bits24 = (octetString[i] & 0xFF) << 16;
bits6 = (bits24 & 0x00FC0000) >> 18;
out[outIndex++] = alphabet[bits6];
bits6 = (bits24 & 0x0003F000) >> 12;
out[outIndex++] = alphabet[bits6];
out[outIndex++] = '=';
out[outIndex++] = '=';
}
return new String (out);
}
}

View File

@@ -0,0 +1,117 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public final class BlockMapping
{
private int[][][] blockMap;
private static final int[] mbOrderMap = { 0, 2, 3, 1 };
private static final int[][] blockOrderMap1 =
{ { 0, 1, 3, 2 },
{ 0, 2, 3, 1 },
{ 0, 2, 3, 1 },
{ 3, 2, 0, 1 }
};
public final int quadMapToIndex1 (int sb, int mb, int b)
{
return blockMap[sb][mbOrderMap[mb]][blockOrderMap1[mb][b]];
}
public final int quadMapToMBTopLeft (int sb, int mb)
{
return blockMap[sb][mbOrderMap[mb]][0];
}
private void CreateMapping (int firstSB,
int firstFrag, int hFrags,
int vFrags)
{
int i = 0, j = 0;
int xpos;
int ypos;
int mb, B;
int sb=firstSB;
int fragIndex=firstFrag;
/* Set Super-Block dimensions */
int sBRows = (vFrags>>2) + ((vFrags & 0x3) != 0 ? 1 : 0 );
int sBCols = (hFrags>>2) + ((hFrags & 0x3) != 0 ? 1 : 0 );
/* Map each Super-Block */
for (int sBRow=0; sBRow<sBRows; sBRow++ ){
for (int sBCol=0; sBCol<sBCols; sBCol++ ){
/* Y co-ordinate of Super-Block in Block units */
ypos = sBRow<<2;
/* Map Blocks within this Super-Block */
for ( i=0; (i<4) && (ypos<vFrags); i++, ypos++ ){
/* X co-ordinate of Super-Block in Block units */
xpos = sBCol<<2;
for ( j=0; (j<4) && (xpos<hFrags); j++, xpos++ ){
mb = (i & 2) + ((j & 2) >> 1);
B = ((i & 1) << 1) + (j & 1);
/* Set mapping and move to next fragment */
blockMap[sb][mb][B] = fragIndex++;
}
/* Move to first fragment in next row in Super-Block */
fragIndex += hFrags-j;
}
/* Move on to next Super-Block */
sb++;
fragIndex -= i*hFrags-j;
}
/* Move to first Super-Block in next row */
fragIndex += 3*hFrags;
}
}
public BlockMapping (int ySuperBlocks, int uvSuperBlocks, int hFrags, int vFrags, int shiftx, int shifty)
{
blockMap = new int[ySuperBlocks + uvSuperBlocks * 2][4][4];
for (int i=0; i<ySuperBlocks + uvSuperBlocks * 2; i++ ){
for (int j=0; j<4; j++ ) {
blockMap[i][j][0] = -1;
blockMap[i][j][1] = -1;
blockMap[i][j][2] = -1;
blockMap[i][j][3] = -1;
}
}
CreateMapping (0, 0, hFrags, vFrags );
CreateMapping (ySuperBlocks, hFrags*vFrags, hFrags>>shiftx, vFrags>>shifty );
CreateMapping (ySuperBlocks + uvSuperBlocks, hFrags*vFrags + (hFrags>>shiftx)*(vFrags>>shifty),
hFrags>>shiftx, vFrags>>shifty );
}
}

View File

@@ -0,0 +1,72 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public class CodingMode {
private int value;
public static final CodingMode CODE_INTER_NO_MV =
new CodingMode(0x0); /* INTER prediction, (0,0) motion vector implied. */
public static final CodingMode CODE_INTRA =
new CodingMode(0x1); /* INTRA i.e. no prediction. */
public static final CodingMode CODE_INTER_PLUS_MV =
new CodingMode(0x2); /* INTER prediction, non zero motion vector. */
public static final CodingMode CODE_INTER_LAST_MV =
new CodingMode(0x3); /* Use Last Motion vector */
public static final CodingMode CODE_INTER_PRIOR_LAST =
new CodingMode(0x4); /* Prior last motion vector */
public static final CodingMode CODE_USING_GOLDEN =
new CodingMode(0x5); /* 'Golden frame' prediction (no MV). */
public static final CodingMode CODE_GOLDEN_MV =
new CodingMode(0x6); /* 'Golden frame' prediction plus MV. */
public static final CodingMode CODE_INTER_FOURMV =
new CodingMode(0x7); /* Inter prediction 4MV per macro block. */
public static final CodingMode[] MODES = {
CODE_INTER_NO_MV,
CODE_INTRA,
CODE_INTER_PLUS_MV,
CODE_INTER_LAST_MV,
CODE_INTER_PRIOR_LAST,
CODE_USING_GOLDEN,
CODE_GOLDEN_MV,
CODE_INTER_FOURMV
};
private CodingMode(int i) {
value=i;
}
public int getValue() {
return value;
}
}

View File

@@ -0,0 +1,40 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public class Colorspace {
public static final Colorspace UNSPECIFIED = new Colorspace ();
public static final Colorspace ITU_REC_470M = new Colorspace ();
public static final Colorspace ITU_REC_470BG = new Colorspace ();
public static final Colorspace[] spaces = {
UNSPECIFIED,
ITU_REC_470M,
ITU_REC_470BG
};
private Colorspace() {
}
}

View File

@@ -0,0 +1,62 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public class Constants
{
public static final int CURRENT_ENCODE_VERSION = 1;
/* Baseline dct height and width. */
public static final int BLOCK_HEIGHT_WIDTH = 8;
public static final int HFRAGPIXELS = 8;
public static final int VFRAGPIXELS = 8;
/* Baseline dct block size */
public static final int BLOCK_SIZE = (BLOCK_HEIGHT_WIDTH * BLOCK_HEIGHT_WIDTH);
/* Border is for unrestricted mv's */
public static final int UMV_BORDER = 16;
public static final int STRIDE_EXTRA = (UMV_BORDER * 2);
public static final int Q_TABLE_SIZE = 64;
public static final int BASE_FRAME = 0;
public static final int NORMAL_FRAME = 1;
public static final int MAX_MODES = 8;
public static final int MODE_BITS = 3;
public static final int MODE_METHODS = 8;
public static final int MODE_METHOD_BITS = 3;
public static final int[] dequant_index = {
0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34,
27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36,
29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46,
53, 60, 61, 54, 47, 55, 62, 63
};
}

View File

@@ -0,0 +1,40 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public class Coordinate
{
public int x, y;
public Coordinate() {
x=0;
y=0;
}
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
}

View File

@@ -0,0 +1,827 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public class DCTDecode
{
private static final int PUR = 8;
private static final int PU = 4;
private static final int PUL = 2;
private static final int PL = 1;
private short[] dequant_matrix = new short[64];
private static final int[] ModeUsesMC = { 0, 0, 1, 1, 1, 0, 1, 1 };
/* predictor multiplier up-left, up, up-right,left, shift
Entries are packed in the order L, UL, U, UR, with missing entries
moved to the end (before the shift parameters). */
private static final short[][] pc = {
{0,0,0,0,0,0},
{1,0,0,0,0,0}, /* PL */
{1,0,0,0,0,0}, /* PUL */
{1,0,0,0,0,0}, /* PUL|PL */
{1,0,0,0,0,0}, /* PU */
{1,1,0,0,1,1}, /* PU|PL */
{0,1,0,0,0,0}, /* PU|PUL */
{29,-26,29,0,5,31}, /* PU|PUL|PL */
{1,0,0,0,0,0}, /* PUR */
{75,53,0,0,7,127}, /* PUR|PL */
{1,1,0,0,1,1}, /* PUR|PUL */
{75,0,53,0,7,127}, /* PUR|PUL|PL */
{1,0,0,0,0,0}, /* PUR|PU */
{75,0,53,0,7,127}, /* PUR|PU|PL */
{3,10,3,0,4,15}, /* PUR|PU|PUL */
{29,-26,29,0,5,31} /* PUR|PU|PUL|PL */
};
/* boundary case bit masks. */
private static final int[] bc_mask = {
/* normal case no boundary condition */
PUR|PU|PUL|PL,
/* left column */
PUR|PU,
/* top row */
PL,
/* top row, left column */
0,
/* right column */
PU|PUL|PL,
/* right and left column */
PU,
/* top row, right column */
PL,
/* top row, right and left column */
0
};
private static final short[] Mode2Frame = {
1, /* CODE_INTER_NO_MV 0 => Encoded diff from same MB last frame */
0, /* CODE_INTRA 1 => DCT Encoded Block */
1, /* CODE_INTER_PLUS_MV 2 => Encoded diff from included MV MB last frame */
1, /* CODE_INTER_LAST_MV 3 => Encoded diff from MRU MV MB last frame */
1, /* CODE_INTER_PRIOR_MV 4 => Encoded diff from included 4 separate MV blocks */
2, /* CODE_USING_GOLDEN 5 => Encoded diff from same MB golden frame */
2, /* CODE_GOLDEN_MV 6 => Encoded diff from included MV MB golden frame */
1 /* CODE_INTER_FOUR_MV 7 => Encoded diff from included 4 separate MV blocks */
};
private short[] ReconDataBuffer = new short[64];
/* value left value up-left, value up, value up-right, missing
values skipped. */
private int[] v = new int[4];
/* fragment number left, up-left, up, up-right */
private int[] fn = new int[4];
private short[] Last = new short[3];
private iDCT idct = new iDCT();
private void ExpandKFBlock ( Playback pbi, int FragmentNumber ){
int ReconPixelsPerLine;
int ReconPixelIndex;
short[] dequant_coeffs;
/* determine which quantizer was specified for this block */
int qi = pbi.FragQs[FragmentNumber];
/* Select the appropriate inverse Q matrix and line stride */
if ( FragmentNumber<(int)pbi.YPlaneFragments ){
ReconPixelsPerLine = pbi.YStride;
// intra Y
dequant_coeffs = pbi.info.dequant_tables[0][0][pbi.frameQIS[qi]];
dequant_matrix[0] = pbi.info.dequant_tables[0][0][pbi.frameQIS[0]][0];
}else if(FragmentNumber < pbi.YPlaneFragments + pbi.UVPlaneFragments) {
ReconPixelsPerLine = pbi.UVStride;
// intra U
dequant_coeffs = pbi.info.dequant_tables[0][1][pbi.frameQIS[qi]];
dequant_matrix[0] = pbi.info.dequant_tables[0][1][pbi.frameQIS[0]][0];
} else {
ReconPixelsPerLine = pbi.UVStride;
// intra V
dequant_coeffs = pbi.info.dequant_tables[0][2][pbi.frameQIS[qi]];
dequant_matrix[0] = pbi.info.dequant_tables[0][2][pbi.frameQIS[0]][0];
}
// create copy with DC coefficient of primary frame qi
System.arraycopy(dequant_coeffs, 1, dequant_matrix, 1, 63);
/* Set up pointer into the quantisation buffer. */
short[] quantized_list = pbi.QFragData[FragmentNumber];
/* Invert quantisation and DCT to get pixel data. */
switch(pbi.FragCoefEOB[FragmentNumber]){
case 0:case 1:
idct.IDct1(quantized_list, dequant_matrix, ReconDataBuffer );
break;
case 2: case 3:case 4:case 5:case 6:case 7:case 8: case 9:case 10:
idct.IDct10(quantized_list, dequant_matrix, ReconDataBuffer );
break;
default:
idct.IDctSlow(quantized_list, dequant_matrix, ReconDataBuffer );
}
/*
for (int i=0; i<64; i++) {
System.out.print(ReconDataBuffer[i]+" ");
}
System.out.println();
*/
/* Convert fragment number to a pixel offset in a reconstruction buffer. */
ReconPixelIndex = pbi.recon_pixel_index_table[FragmentNumber];
/* Get the pixel index for the first pixel in the fragment. */
Recon.ReconIntra (pbi.ThisFrameRecon, ReconPixelIndex, ReconDataBuffer, ReconPixelsPerLine);
}
private void ExpandBlock ( Playback pbi, int FragmentNumber ){
short[] LastFrameRecPtr; /* Pointer into previous frame
reconstruction. */
int ReconPixelsPerLine; /* Pixels per line */
int ReconPixelIndex; /* Offset for block into a
reconstruction buffer */
int ReconPtr2Offset; /* Offset for second
reconstruction in half pixel
MC */
int MVOffset; /* Baseline motion vector offset */
int MvShiftX ; /* Shift to correct to 1/2 or 1/4 pixel */
int MvShiftY ; /* Shift to correct to 1/2 or 1/4 pixel */
int MvModMaskX; /* Mask to determine whether 1/2
pixel is used */
int MvModMaskY;
short[] dequant_coeffs;
CodingMode codingMode;
/* determine which quantizer was specified for this block */
int qi = pbi.FragQs[FragmentNumber];
/* Get coding mode for this block */
if (pbi.getFrameType() == Constants.BASE_FRAME ){
codingMode = CodingMode.CODE_INTRA;
}else{
/* Get Motion vector and mode for this block. */
codingMode = pbi.FragCodingMethod[FragmentNumber];
}
/* Select the appropriate inverse Q matrix and line stride */
if ( FragmentNumber<(int)pbi.YPlaneFragments ) {
ReconPixelsPerLine = pbi.YStride;
MvShiftX = MvShiftY = 1;
MvModMaskX = MvModMaskY = 0x00000001;
/* Select appropriate dequantiser matrix. */
if ( codingMode == CodingMode.CODE_INTRA ) {
// intra Y
dequant_coeffs = pbi.info.dequant_tables[0][0][pbi.frameQIS[qi]];
dequant_matrix[0] = pbi.info.dequant_tables[0][0][pbi.frameQIS[0]][0];
} else {
// inter Y
dequant_coeffs = pbi.info.dequant_tables[1][0][pbi.frameQIS[qi]];
dequant_matrix[0] = pbi.info.dequant_tables[1][0][pbi.frameQIS[0]][0];
}
}else{
ReconPixelsPerLine = pbi.UVStride;
MvShiftX = pbi.UVShiftX + 1;
MvShiftY = pbi.UVShiftY + 1;
MvModMaskX = MvModMaskY = 0x00000003;
if (MvShiftX == 1) MvModMaskX = 0x00000001;
if (MvShiftY == 1) MvModMaskY = 0x00000001;
/* Select appropriate dequantiser matrix. */
if(FragmentNumber < pbi.YPlaneFragments + pbi.UVPlaneFragments) {
if ( codingMode == CodingMode.CODE_INTRA ) {
// intra U
dequant_coeffs = pbi.info.dequant_tables[0][1][pbi.frameQIS[qi]];
dequant_matrix[0] = pbi.info.dequant_tables[0][1][pbi.frameQIS[0]][0];
} else {
// inter U
dequant_coeffs = pbi.info.dequant_tables[1][1][pbi.frameQIS[qi]];
dequant_matrix[0] = pbi.info.dequant_tables[1][1][pbi.frameQIS[0]][0];
}
} else {
if ( codingMode == CodingMode.CODE_INTRA ) {
// intra V
dequant_coeffs = pbi.info.dequant_tables[0][2][pbi.frameQIS[qi]];
dequant_matrix[0] = pbi.info.dequant_tables[0][2][pbi.frameQIS[0]][0];
} else {
// inter V
dequant_coeffs = pbi.info.dequant_tables[1][2][pbi.frameQIS[qi]];
dequant_matrix[0] = pbi.info.dequant_tables[1][2][pbi.frameQIS[0]][0];
}
}
}
// create copy with DC coefficient of primary frame qi
System.arraycopy(dequant_coeffs, 1, dequant_matrix, 1, 63);
/* Set up pointer into the quantisation buffer. */
short[] quantized_list = pbi.QFragData[FragmentNumber];
/* Invert quantisation and DCT to get pixel data. */
switch(pbi.FragCoefEOB[FragmentNumber]){
case 0:case 1:
idct.IDct1(quantized_list, dequant_matrix, ReconDataBuffer );
break;
case 2: case 3:case 4:case 5:case 6:case 7:case 8: case 9:case 10:
idct.IDct10(quantized_list, dequant_matrix, ReconDataBuffer );
break;
default:
idct.IDctSlow(quantized_list, dequant_matrix, ReconDataBuffer );
}
/*
for (int i=0; i<64; i++) {
System.out.print(ReconDataBuffer[i]+" ");
}
System.out.println();
*/
/* Convert fragment number to a pixel offset in a reconstruction buffer. */
ReconPixelIndex = pbi.recon_pixel_index_table[FragmentNumber];
/* Action depends on decode mode. */
if ( codingMode == CodingMode.CODE_INTER_NO_MV ){
/* Inter with no motion vector */
/* Reconstruct the pixel data using the last frame reconstruction
and change data when the motion vector is (0,0), the recon is
based on the lastframe without loop filtering---- for testing */
Recon.ReconInter(pbi.ThisFrameRecon, ReconPixelIndex,
pbi.LastFrameRecon, ReconPixelIndex,
ReconDataBuffer, ReconPixelsPerLine );
}else if (ModeUsesMC[codingMode.getValue()] != 0) {
/* The mode uses a motion vector. */
/* Get vector from list */
int dir;
/* Work out the base motion vector offset and the 1/2 pixel offset
if any. For the U and V planes the MV specifies 1/4 pixel
accuracy. This is adjusted to 1/2 pixel as follows ( 0.0,
1/4->1/2, 1/2->1/2, 3/4->1/2 ). */
ReconPtr2Offset = 0;
MVOffset = 0;
dir = pbi.FragMVect[FragmentNumber].x;
if (dir > 0) {
MVOffset = dir >> MvShiftX;
if ((dir & MvModMaskX) != 0 )
ReconPtr2Offset = 1;
} else if (dir < 0) {
MVOffset = -((-dir) >> MvShiftX);
if (((-dir) & MvModMaskX) != 0 )
ReconPtr2Offset = -1;
}
dir = pbi.FragMVect[FragmentNumber].y;
if ( dir > 0 ){
MVOffset += (dir >> MvShiftY) * ReconPixelsPerLine;
if ((dir & MvModMaskY) != 0 )
ReconPtr2Offset += ReconPixelsPerLine;
} else if (dir < 0 ){
MVOffset -= ((-dir) >> MvShiftY) * ReconPixelsPerLine;
if (((-dir) & MvModMaskY) != 0 )
ReconPtr2Offset -= ReconPixelsPerLine;
}
int LastFrameRecOffset = ReconPixelIndex + MVOffset;
/* Set up the first of the two reconstruction buffer pointers. */
if ( codingMode==CodingMode.CODE_GOLDEN_MV ) {
LastFrameRecPtr = pbi.GoldenFrame;
}else{
LastFrameRecPtr = pbi.LastFrameRecon;
}
/*
System.out.println(pbi.FragMVect[FragmentNumber].x+" "+
pbi.FragMVect[FragmentNumber].y+" "+
ReconPixelIndex+" "+LastFrameRecOffset+ " "+
ReconPtr2Offset);
*/
/* Select the appropriate reconstruction function */
if (ReconPtr2Offset == 0 ) {
/* Reconstruct the pixel dats from the reference frame and change data
(no half pixel in this case as the two references were the same. */
Recon.ReconInter(pbi.ThisFrameRecon, ReconPixelIndex,
LastFrameRecPtr, LastFrameRecOffset,
ReconDataBuffer, ReconPixelsPerLine );
}else{
/* Fractional pixel reconstruction. */
/* Note that we only use two pixels per reconstruction even for
the diagonal. */
Recon.ReconInterHalfPixel2(pbi.ThisFrameRecon, ReconPixelIndex,
LastFrameRecPtr, LastFrameRecOffset,
LastFrameRecPtr, LastFrameRecOffset+ReconPtr2Offset,
ReconDataBuffer, ReconPixelsPerLine );
}
} else if ( codingMode == CodingMode.CODE_USING_GOLDEN ){
/* Golden frame with motion vector */
/* Reconstruct the pixel data using the golden frame
reconstruction and change data */
Recon.ReconInter(pbi.ThisFrameRecon, ReconPixelIndex,
pbi.GoldenFrame, ReconPixelIndex ,
ReconDataBuffer, ReconPixelsPerLine );
} else {
/* Simple Intra coding */
/* Get the pixel index for the first pixel in the fragment. */
Recon.ReconIntra(pbi.ThisFrameRecon, ReconPixelIndex,
ReconDataBuffer, ReconPixelsPerLine );
}
}
private void UpdateUMV_HBorders( Playback pbi,
short[] DestReconPtr,
int PlaneFragOffset ) {
int i;
int PixelIndex;
int PlaneStride;
int BlockVStep;
int PlaneFragments;
int LineFragments;
int PlaneBorderWidth;
int PlaneBorderHeight;
short[] SrcPtr1;
int SrcOff1;
short[] SrcPtr2;
int SrcOff2;
short[] DestPtr1;
int DestOff1;
short[] DestPtr2;
int DestOff2;
/* Work out various plane specific values */
if ( PlaneFragOffset == 0 ) {
/* Y Plane */
BlockVStep = (pbi.YStride *
(Constants.VFRAGPIXELS - 1));
PlaneStride = pbi.YStride;
PlaneBorderWidth = Constants.UMV_BORDER;
PlaneBorderHeight = Constants.UMV_BORDER;
PlaneFragments = pbi.YPlaneFragments;
LineFragments = pbi.HFragments;
}else{
/* U or V plane. */
BlockVStep = (pbi.UVStride *
(Constants.VFRAGPIXELS - 1));
PlaneStride = pbi.UVStride;
PlaneBorderWidth = Constants.UMV_BORDER >> pbi.UVShiftX;
PlaneBorderHeight = Constants.UMV_BORDER >> pbi.UVShiftY;
PlaneFragments = pbi.UVPlaneFragments;
LineFragments = pbi.HFragments >> pbi.UVShiftX;
}
/* Setup the source and destination pointers for the top and bottom
borders */
PixelIndex = pbi.recon_pixel_index_table[PlaneFragOffset];
SrcPtr1 = DestReconPtr;
SrcOff1 = PixelIndex - PlaneBorderWidth;
DestPtr1 = SrcPtr1;
DestOff1 = SrcOff1 - (PlaneBorderHeight * PlaneStride);
PixelIndex = pbi.recon_pixel_index_table[PlaneFragOffset +
PlaneFragments - LineFragments] +
BlockVStep;
SrcPtr2 = DestReconPtr;
SrcOff2 = PixelIndex - PlaneBorderWidth;
DestPtr2 = SrcPtr2;
DestOff2 = SrcOff2 + PlaneStride;
/* Now copy the top and bottom source lines into each line of the
respective borders */
for ( i = 0; i < PlaneBorderHeight; i++ ) {
System.arraycopy(SrcPtr1, SrcOff1, DestPtr1, DestOff1, PlaneStride);
System.arraycopy(SrcPtr2, SrcOff2, DestPtr2, DestOff2, PlaneStride);
DestOff1 += PlaneStride;
DestOff2 += PlaneStride;
}
}
private void UpdateUMV_VBorders( Playback pbi,
short[] DestReconPtr,
int PlaneFragOffset ){
int i;
int PixelIndex;
int PlaneStride;
int LineFragments;
int PlaneBorderWidth;
int PlaneHeight;
short[] SrcPtr1;
int SrcOff1;
short[] SrcPtr2;
int SrcOff2;
short[] DestPtr1;
int DestOff1;
short[] DestPtr2;
int DestOff2;
/* Work out various plane specific values */
if ( PlaneFragOffset == 0 ) {
/* Y Plane */
PlaneStride = pbi.YStride;
PlaneBorderWidth = Constants.UMV_BORDER;
LineFragments = pbi.HFragments;
PlaneHeight = pbi.info.height;
}else{
/* U or V plane. */
PlaneStride = pbi.UVStride;
PlaneBorderWidth = Constants.UMV_BORDER >> pbi.UVShiftX;
LineFragments = pbi.HFragments >> pbi.UVShiftX;
PlaneHeight = pbi.info.height >> pbi.UVShiftY;
}
/* Setup the source data values and destination pointers for the
left and right edge borders */
PixelIndex = pbi.recon_pixel_index_table[PlaneFragOffset];
SrcPtr1 = DestReconPtr;
SrcOff1 = PixelIndex;
DestPtr1 = DestReconPtr;
DestOff1 = PixelIndex - PlaneBorderWidth;
PixelIndex = pbi.recon_pixel_index_table[PlaneFragOffset +
LineFragments - 1] +
(Constants.HFRAGPIXELS - 1);
SrcPtr2 = DestReconPtr;
SrcOff2 = PixelIndex;
DestPtr2 = DestReconPtr;
DestOff2 = PixelIndex + 1;
/* Now copy the top and bottom source lines into each line of the
respective borders */
for ( i = 0; i < PlaneHeight; i++ ) {
MemUtils.set(DestPtr1, DestOff1, SrcPtr1[SrcOff1], PlaneBorderWidth );
MemUtils.set(DestPtr2, DestOff2, SrcPtr2[SrcOff2], PlaneBorderWidth );
DestOff1 += PlaneStride;
DestOff2 += PlaneStride;
SrcOff1 += PlaneStride;
SrcOff2 += PlaneStride;
}
}
private void UpdateUMVBorder( Playback pbi,
short[] DestReconPtr ) {
int PlaneFragOffset;
/* Y plane */
PlaneFragOffset = 0;
UpdateUMV_VBorders( pbi, DestReconPtr, PlaneFragOffset );
UpdateUMV_HBorders( pbi, DestReconPtr, PlaneFragOffset );
/* Then the U and V Planes */
PlaneFragOffset = pbi.YPlaneFragments;
UpdateUMV_VBorders( pbi, DestReconPtr, PlaneFragOffset );
UpdateUMV_HBorders( pbi, DestReconPtr, PlaneFragOffset );
PlaneFragOffset = pbi.YPlaneFragments + pbi.UVPlaneFragments;
UpdateUMV_VBorders( pbi, DestReconPtr, PlaneFragOffset );
UpdateUMV_HBorders( pbi, DestReconPtr, PlaneFragOffset );
}
private void CopyRecon( Playback pbi, short[] DestReconPtr,
short[] SrcReconPtr ) {
int i;
int PlaneLineStep; /* Pixels per line */
int PixelIndex;
/* Copy over only updated blocks.*/
/* First Y plane */
PlaneLineStep = pbi.YStride;
for ( i = 0; i < pbi.YPlaneFragments; i++ ) {
if ( pbi.display_fragments[i] != 0) {
PixelIndex = pbi.recon_pixel_index_table[i];
Recon.CopyBlock(SrcReconPtr, DestReconPtr, PixelIndex, PlaneLineStep);
}
}
/* Then U and V */
PlaneLineStep = pbi.UVStride;
for ( i = pbi.YPlaneFragments; i < pbi.UnitFragments; i++ ) {
if ( pbi.display_fragments[i] != 0) {
PixelIndex = pbi.recon_pixel_index_table[i];
Recon.CopyBlock(SrcReconPtr, DestReconPtr, PixelIndex, PlaneLineStep);
}
}
}
private void CopyNotRecon( Playback pbi, short[] DestReconPtr,
short[] SrcReconPtr ) {
int i;
int PlaneLineStep; /* Pixels per line */
int PixelIndex;
/* Copy over only updated blocks. */
/* First Y plane */
PlaneLineStep = pbi.YStride;
for (i = 0; i < pbi.YPlaneFragments; i++) {
if (pbi.display_fragments[i] == 0) {
PixelIndex = pbi.recon_pixel_index_table[i];
Recon.CopyBlock(SrcReconPtr, DestReconPtr, PixelIndex, PlaneLineStep);
}
}
/* Then U and V */
PlaneLineStep = pbi.UVStride;
for (i = pbi.YPlaneFragments; i < pbi.UnitFragments; i++) {
if (pbi.display_fragments[i] == 0) {
PixelIndex = pbi.recon_pixel_index_table[i];
Recon.CopyBlock(SrcReconPtr, DestReconPtr, PixelIndex, PlaneLineStep);
}
}
}
public void ExpandToken( short[] ExpandedBlock,
byte[] CoeffIndex, int FragIndex, int Token,
int ExtraBits ){
/* Is the token is a combination run and value token. */
if ( Token >= Huffman.DCT_RUN_CATEGORY1 ){
/* Expand the token and additional bits to a zero run length and
data value. */
if ( Token < Huffman.DCT_RUN_CATEGORY2 ) {
/* Decoding method depends on token */
if ( Token < Huffman.DCT_RUN_CATEGORY1B ) {
/* Step on by the zero run length */
CoeffIndex[FragIndex] += (byte)((Token - Huffman.DCT_RUN_CATEGORY1) + 1);
/* The extra bit determines the sign. */
ExpandedBlock[CoeffIndex[FragIndex]] = (short)-(((ExtraBits&0x01)<<1)-1);
}
else if ( Token == Huffman.DCT_RUN_CATEGORY1B ) {
/* Bits 0-1 determines the zero run length */
CoeffIndex[FragIndex] += (6 + (ExtraBits & 0x03));
/* Bit 2 determines the sign */
ExpandedBlock[CoeffIndex[FragIndex]] = (short)-(((ExtraBits&0x04)>>1)-1);
}else{
/* Bits 0-2 determines the zero run length */
CoeffIndex[FragIndex] += (10 + (ExtraBits & 0x07));
/* Bit 3 determines the sign */
ExpandedBlock[CoeffIndex[FragIndex]] = (short)-(((ExtraBits&0x08)>>2)-1);
}
}else{
/* If token == Huffman.DCT_RUN_CATEGORY2 we have a single 0 followed by
a value */
if ( Token == Huffman.DCT_RUN_CATEGORY2 ){
/* Step on by the zero run length */
CoeffIndex[FragIndex] += 1;
/* Bit 1 determines sign, bit 0 the value */
ExpandedBlock[CoeffIndex[FragIndex]] = (short) ((2+(ExtraBits & 0x01)) * -((ExtraBits&0x02)-1));
}else{
/* else we have 2->3 zeros followed by a value */
/* Bit 0 determines the zero run length */
CoeffIndex[FragIndex] += 2 + (ExtraBits & 0x01);
/* Bit 2 determines the sign, bit 1 the value */
ExpandedBlock[CoeffIndex[FragIndex]] = (short) ((2+((ExtraBits&0x02)>>1))*-(((ExtraBits&0x04)>>1)-1));
}
}
/* Step on over value */
CoeffIndex[FragIndex] += 1;
} else if ( Token == Huffman.DCT_SHORT_ZRL_TOKEN ) {
/* Token is a ZRL token so step on by the appropriate number of zeros */
CoeffIndex[FragIndex] += ExtraBits + 1;
} else if ( Token == Huffman.DCT_ZRL_TOKEN ) {
/* Token is a ZRL token so step on by the appropriate number of zeros */
CoeffIndex[FragIndex] += ExtraBits + 1;
} else if ( Token < Huffman.LOW_VAL_TOKENS ) {
/* Token is a small single value token. */
switch ( Token ) {
case Huffman.ONE_TOKEN:
ExpandedBlock[CoeffIndex[FragIndex]] = 1;
break;
case Huffman.MINUS_ONE_TOKEN:
ExpandedBlock[CoeffIndex[FragIndex]] = -1;
break;
case Huffman.TWO_TOKEN:
ExpandedBlock[CoeffIndex[FragIndex]] = 2;
break;
case Huffman.MINUS_TWO_TOKEN:
ExpandedBlock[CoeffIndex[FragIndex]] = -2;
break;
}
/* Step on the coefficient index. */
CoeffIndex[FragIndex] += 1;
}else{
/* Token is a larger single value token */
/* Expand the token and additional bits to a data value. */
if ( Token < Huffman.DCT_VAL_CATEGORY3 ) {
/* Offset from LOW_VAL_TOKENS determines value */
Token = Token - Huffman.LOW_VAL_TOKENS;
/* Extra bit determines sign */
ExpandedBlock[CoeffIndex[FragIndex]] = (short) ((Token + Huffman.DCT_VAL_CAT2_MIN) *
-(((ExtraBits)<<1)-1));
} else if ( Token == Huffman.DCT_VAL_CATEGORY3 ) {
/* Bit 1 determines sign, Bit 0 the value */
ExpandedBlock[CoeffIndex[FragIndex]] = (short) ((Huffman.DCT_VAL_CAT3_MIN + (ExtraBits & 0x01)) *
-(((ExtraBits&0x02))-1));
} else if ( Token == Huffman.DCT_VAL_CATEGORY4 ) {
/* Bit 2 determines sign, Bit 0-1 the value */
ExpandedBlock[CoeffIndex[FragIndex]] = (short) ((Huffman.DCT_VAL_CAT4_MIN + (ExtraBits & 0x03)) *
-(((ExtraBits&0x04)>>1)-1));
} else if ( Token == Huffman.DCT_VAL_CATEGORY5 ) {
/* Bit 3 determines sign, Bit 0-2 the value */
ExpandedBlock[CoeffIndex[FragIndex]] = (short) ((Huffman.DCT_VAL_CAT5_MIN + (ExtraBits & 0x07)) *
-(((ExtraBits&0x08)>>2)-1));
} else if ( Token == Huffman.DCT_VAL_CATEGORY6 ) {
/* Bit 4 determines sign, Bit 0-3 the value */
ExpandedBlock[CoeffIndex[FragIndex]] = (short) ((Huffman.DCT_VAL_CAT6_MIN + (ExtraBits & 0x0F)) *
-(((ExtraBits&0x10)>>3)-1));
} else if ( Token == Huffman.DCT_VAL_CATEGORY7 ) {
/* Bit 5 determines sign, Bit 0-4 the value */
ExpandedBlock[CoeffIndex[FragIndex]] = (short) ((Huffman.DCT_VAL_CAT7_MIN + (ExtraBits & 0x1F)) *
-(((ExtraBits&0x20)>>4)-1));
} else if ( Token == Huffman.DCT_VAL_CATEGORY8 ) {
/* Bit 9 determines sign, Bit 0-8 the value */
ExpandedBlock[CoeffIndex[FragIndex]] = (short) ((Huffman.DCT_VAL_CAT8_MIN + (ExtraBits & 0x1FF)) *
-(((ExtraBits&0x200)>>8)-1));
}
/* Step on the coefficient index. */
CoeffIndex[FragIndex] += 1;
}
}
public void ReconRefFrames (Playback pbi){
int i;
int j,k,m,n;
/* predictor count. */
int pcount;
short wpc;
short PredictedDC;
int FragsAcross=pbi.HFragments;
int FromFragment;
int FragsDown = pbi.VFragments;
int WhichFrame;
int WhichCase;
boolean isBaseFrame;
isBaseFrame = pbi.getFrameType() == Constants.BASE_FRAME;
pbi.filter.SetupLoopFilter(pbi.FrameQIndex);
/* for y,u,v */
for ( j = 0; j < 3 ; j++) {
/* pick which fragments based on Y, U, V */
switch(j){
case 0: /* y */
FromFragment = 0;
FragsAcross = pbi.HFragments;
FragsDown = pbi.VFragments;
break;
case 1: /* u */
FromFragment = pbi.YPlaneFragments;
FragsAcross = pbi.HFragments >> pbi.UVShiftX;
FragsDown = pbi.VFragments >> pbi.UVShiftY;
break;
/*case 2: v */
default:
FromFragment = pbi.YPlaneFragments + pbi.UVPlaneFragments;
FragsAcross = pbi.HFragments >> pbi.UVShiftX;
FragsDown = pbi.VFragments >> pbi.UVShiftY;
break;
}
/* initialize our array of last used DC Components */
for(k=0;k<3;k++)
Last[k]=0;
i=FromFragment;
/* do prediction on all of Y, U or V */
for ( m = 0 ; m < FragsDown ; m++) {
for ( n = 0 ; n < FragsAcross ; n++, i++){
/* only do 2 prediction if fragment coded and on non intra or
if all fragments are intra */
if((pbi.display_fragments[i] != 0) || (pbi.getFrameType() == Constants.BASE_FRAME) ){
/* Type of Fragment */
WhichFrame = Mode2Frame[pbi.FragCodingMethod[i].getValue()];
/* Check Borderline Cases */
WhichCase = (n==0?1:0) + ((m==0?1:0) << 1) + ((n+1 == FragsAcross?1:0) << 2);
fn[0]=i-1;
fn[1]=i-FragsAcross-1;
fn[2]=i-FragsAcross;
fn[3]=i-FragsAcross+1;
/* fragment valid for prediction use if coded and it comes
from same frame as the one we are predicting */
for(k=pcount=wpc=0; k<4; k++) {
int pflag;
pflag=1<<k;
if((bc_mask[WhichCase]&pflag) != 0 &&
pbi.display_fragments[fn[k]] != 0 &&
(Mode2Frame[pbi.FragCodingMethod[fn[k]].getValue()] == WhichFrame))
{
v[pcount]=pbi.QFragData[fn[k]][0];
wpc|=pflag;
pcount++;
}
}
if(wpc==0){
/* fall back to the last coded fragment */
pbi.QFragData[i][0] += Last[WhichFrame];
}else{
/* don't do divide if divisor is 1 or 0 */
PredictedDC = (short) (pc[wpc][0]*v[0]);
for(k=1; k<pcount; k++){
PredictedDC += pc[wpc][k]*v[k];
}
/* if we need to do a shift */
if(pc[wpc][4] != 0 ){
/* If negative add in the negative correction factor */
if (PredictedDC < 0)
PredictedDC += pc[wpc][5];
/* Shift in lieu of a divide */
PredictedDC >>= pc[wpc][4];
}
/* check for outranging on the two predictors that can outrange */
if((wpc&(PU|PUL|PL)) == (PU|PUL|PL)){
if(Math.abs(PredictedDC - v[2]) > 128) {
PredictedDC = (short)v[2];
} else if( Math.abs(PredictedDC - v[0]) > 128) {
PredictedDC = (short)v[0];
} else if( Math.abs(PredictedDC - v[1]) > 128) {
PredictedDC = (short)v[1];
}
}
pbi.QFragData[i][0] += PredictedDC;
}
/* Save the last fragment coded for whatever frame we are
predicting from */
Last[WhichFrame] = pbi.QFragData[i][0];
/* Inverse DCT and reconstitute buffer in thisframe */
if (isBaseFrame)
ExpandKFBlock (pbi, i);
else
ExpandBlock (pbi, i);
}
}
}
}
/* Copy the current reconstruction back to the last frame recon buffer. */
if(pbi.CodedBlockIndex > (int) (pbi.UnitFragments >> 1)){
short[] SwapReconBuffersTemp = pbi.ThisFrameRecon;
pbi.ThisFrameRecon = pbi.LastFrameRecon;
pbi.LastFrameRecon = SwapReconBuffersTemp;
CopyNotRecon(pbi, pbi.LastFrameRecon, pbi.ThisFrameRecon);
}else{
CopyRecon(pbi, pbi.LastFrameRecon, pbi.ThisFrameRecon);
}
/* Apply a loop filter to edge pixels of updated blocks */
pbi.filter.LoopFilter(pbi);
/* We may need to update the UMV border */
UpdateUMVBorder(pbi, pbi.LastFrameRecon);
/* Reconstruct the golden frame if necessary.
For VFW codec only on key frames */
if (isBaseFrame) {
CopyRecon( pbi, pbi.GoldenFrame, pbi.LastFrameRecon );
UpdateUMVBorder(pbi, pbi.GoldenFrame);
}
}
}

View File

@@ -0,0 +1,82 @@
/* Cortado - a video player java applet
* Copyright (C) 2004 Fluendo S.L.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public class Debug {
public static final int NONE = 0;
public static final int ERROR = 1;
public static final int WARNING = 2;
public static final int INFO = 3;
public static final int DEBUG = 4;
public static int level = INFO;
/* static id counter */
private static int counter = 0;
private static long startTime = 0;
public static final int genId() {
synchronized (Debug.class) {
return counter++;
}
}
public static final String[] prefix = {
"NONE",
"ERRO",
"WARN",
"INFO",
"DBUG"};
public static String rpad(String s, int length) {
if ( length > s.length() ) {
int sz = length - s.length();
char arr[] = new char[sz];
for (int n=0; n<sz; ++n)
arr[n] = ' ';
return s + new String( arr );
} else {
return s;
}
}
public static void log(int lev, String line)
{
long t = System.currentTimeMillis();
if ( startTime == 0 ) {
startTime = t;
}
t -= startTime;
if (lev <= level) {
if (level >= DEBUG) {
System.out.println( "[" + Debug.rpad( Thread.currentThread().getName(), 30 ) + " "
+ Debug.rpad( Long.toString( t ), 6 ) + " " + prefix[lev] + "] " + line );
} else {
System.out.println( "[" + prefix[lev] + "] " + line );
}
}
}
public static void error(String line) { Debug.log( ERROR, line ); }
public static void warning(String line) { Debug.log( WARNING, line ); }
public static void warn(String line) { Debug.log( WARNING, line ); }
public static void info(String line) { Debug.log( INFO, line ); }
public static void debug(String line) { Debug.log( DEBUG, line ); }
}

View File

@@ -0,0 +1,940 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Parts ported from the new Theora C reference encoder, which was mostly
* written by Timothy B. Terriberry
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
interface ExtractMVectorComponent {
public int extract(OggBuffer opb);
}
class ExtractMVectorComponentA implements ExtractMVectorComponent {
public int extract (OggBuffer opb) {
/* Get group to which coded component belongs */
/* Now extract the appropriate number of bits to identify the component */
switch (opb.readB(3)){
case 0:
return 0;
case 1:
return 1;
case 2:
return -1;
case 3:
return 2 - (4*opb.readB(1));
case 4:
return 3 - (6*opb.readB(1));
case 5:
return (4 + opb.readB(2)) * -((opb.readB(1)<<1)-1);
case 6:
return (8 + opb.readB(3)) * -((opb.readB(1)<<1)-1);
case 7:
return (16 + opb.readB(4)) * -((opb.readB(1)<<1)-1);
}
return 0;
}
}
class ExtractMVectorComponentB implements ExtractMVectorComponent {
public int extract (OggBuffer opb) {
/* Get group to which coded component belongs */
return (opb.readB(5)) * -((opb.readB(1)<<1)-1);
}
}
public final class Decode {
private static final ExtractMVectorComponent MVA = new ExtractMVectorComponentA();
private static final ExtractMVectorComponent MVB = new ExtractMVectorComponentB();
private static final CodingMode[][] modeAlphabet = {
/* Last motion vector dominates */
{ CodingMode.CODE_INTER_LAST_MV, CodingMode.CODE_INTER_PRIOR_LAST,
CodingMode.CODE_INTER_PLUS_MV, CodingMode.CODE_INTER_NO_MV,
CodingMode.CODE_INTRA, CodingMode.CODE_USING_GOLDEN,
CodingMode.CODE_GOLDEN_MV, CodingMode.CODE_INTER_FOURMV },
{ CodingMode.CODE_INTER_LAST_MV, CodingMode.CODE_INTER_PRIOR_LAST,
CodingMode.CODE_INTER_NO_MV, CodingMode.CODE_INTER_PLUS_MV,
CodingMode.CODE_INTRA, CodingMode.CODE_USING_GOLDEN,
CodingMode.CODE_GOLDEN_MV, CodingMode.CODE_INTER_FOURMV },
{ CodingMode.CODE_INTER_LAST_MV, CodingMode.CODE_INTER_PLUS_MV,
CodingMode.CODE_INTER_PRIOR_LAST, CodingMode.CODE_INTER_NO_MV,
CodingMode.CODE_INTRA, CodingMode.CODE_USING_GOLDEN,
CodingMode.CODE_GOLDEN_MV, CodingMode.CODE_INTER_FOURMV },
{ CodingMode.CODE_INTER_LAST_MV, CodingMode.CODE_INTER_PLUS_MV,
CodingMode.CODE_INTER_NO_MV, CodingMode.CODE_INTER_PRIOR_LAST,
CodingMode.CODE_INTRA, CodingMode.CODE_USING_GOLDEN,
CodingMode.CODE_GOLDEN_MV, CodingMode.CODE_INTER_FOURMV },
/* No motion vector dominates */
{ CodingMode.CODE_INTER_NO_MV, CodingMode.CODE_INTER_LAST_MV,
CodingMode.CODE_INTER_PRIOR_LAST, CodingMode.CODE_INTER_PLUS_MV,
CodingMode.CODE_INTRA, CodingMode.CODE_USING_GOLDEN,
CodingMode.CODE_GOLDEN_MV, CodingMode.CODE_INTER_FOURMV },
{ CodingMode.CODE_INTER_NO_MV, CodingMode.CODE_USING_GOLDEN,
CodingMode.CODE_INTER_LAST_MV, CodingMode.CODE_INTER_PRIOR_LAST,
CodingMode.CODE_INTER_PLUS_MV, CodingMode.CODE_INTRA,
CodingMode.CODE_GOLDEN_MV, CodingMode.CODE_INTER_FOURMV },
/* dummy */
{ CodingMode.CODE_INTER_NO_MV, CodingMode.CODE_USING_GOLDEN,
CodingMode.CODE_INTER_LAST_MV, CodingMode.CODE_INTER_PRIOR_LAST,
CodingMode.CODE_INTER_PLUS_MV, CodingMode.CODE_INTRA,
CodingMode.CODE_GOLDEN_MV, CodingMode.CODE_INTER_FOURMV },
};
private int BlocksToDecode;
private int EOB_Run;
private DCTDecode dctDecode = new DCTDecode();
private byte[] FragCoeffs; /* # of coeffs decoded so far for
fragment */
private MotionVector LastInterMV = new MotionVector ();
private MotionVector PriorLastInterMV = new MotionVector ();
private Playback pbi;
public Decode (Playback pbi) {
FragCoeffs = new byte[pbi.UnitFragments];
this.pbi = pbi;
}
private int longRunBitStringDecode() {
/* lifted from new C Theora reference decoder */
int bits;
int ret;
OggBuffer opb = pbi.opb;
/*Coding scheme:
Codeword Run Length
0 1
10x 2-3
110x 4-5
1110xx 6-9
11110xxx 10-17
111110xxxx 18-33
111111xxxxxxxxxxxx 34-4129*/
bits = opb.readB(1);
if(bits==0)return 1;
bits = opb.readB(2);
if((bits&2)==0)return 2+(int)bits;
else if((bits&1)==0){
bits = opb.readB(1);
return 4+(int)bits;
}
bits = opb.readB(3);
if((bits&4)==0)return 6+(int)bits;
else if((bits&2)==0){
ret=10+((bits&1)<<2);
bits = opb.readB(2);
return ret+(int)bits;
}
else if((bits&1)==0){
bits = opb.readB(4);
return 18+(int)bits;
}
bits = opb.readB(12);
return 34+(int)bits;
}
private void decodeBlockLevelQi() {
/* lifted from new C Theora reference decoder */
/* pbi.CodedBlockIndex holds the number of coded blocks despite the
suboptimal variable name */
int ncoded_frags = pbi.CodedBlockIndex;
if(ncoded_frags <= 0) return;
if(pbi.frameNQIS == 1) {
/*If this frame has only a single qi value, then just set it in all coded
fragments.*/
for(int coded_frag = 0; coded_frag < ncoded_frags; ++coded_frag) {
pbi.FragQs[pbi.CodedBlockList[coded_frag]] = 0;
}
} else{
OggBuffer opb = pbi.opb;
int val;
int flag;
int nqi0;
int run_count;
/*Otherwise, we decode a qi index for each fragment, using two passes of
the same binary RLE scheme used for super-block coded bits.
The first pass marks each fragment as having a qii of 0 or greater than
0, and the second pass (if necessary), distinguishes between a qii of
1 and 2.
We store the qii of the fragment. */
val = opb.readB(1);
flag = val;
run_count = nqi0 = 0;
int coded_frag = 0;
while(coded_frag < ncoded_frags){
boolean full_run;
run_count = longRunBitStringDecode();
full_run = (run_count >= 4129);
do {
pbi.FragQs[pbi.CodedBlockList[coded_frag++]] = (byte)flag;
if(flag < 1) ++nqi0;
} while(--run_count > 0 && coded_frag < ncoded_frags);
if(full_run && coded_frag < ncoded_frags){
val = opb.readB(1);
flag=(int)val;
} else {
//flag=!flag;
flag = (flag != 0) ? 0 : 1;
}
}
/*TODO: run_count should be 0 here.
If it's not, we should issue a warning of some kind.*/
/*If we have 3 different qi's for this frame, and there was at least one
fragment with a non-zero qi, make the second pass.*/
if(pbi.frameNQIS==3 && nqi0 < ncoded_frags){
coded_frag = 0;
/*Skip qii==0 fragments.*/
for(coded_frag = 0; coded_frag < ncoded_frags && pbi.FragQs[pbi.CodedBlockList[coded_frag]] == 0; ++coded_frag){}
val = opb.readB(1);
flag = val;
while(coded_frag < ncoded_frags){
boolean full_run;
run_count = longRunBitStringDecode();
full_run = run_count >= 4129;
for(; coded_frag < ncoded_frags; ++coded_frag){
if(pbi.FragQs[pbi.CodedBlockList[coded_frag]] == 0) continue;
if(run_count-- <= 0) break;
pbi.FragQs[pbi.CodedBlockList[coded_frag]] += flag;
}
if(full_run && coded_frag < ncoded_frags){
val = opb.readB(1);
flag = val;
} else {
//flag=!flag;
flag = (flag != 0) ? 0 : 1;
}
}
/*TODO: run_count should be 0 here.
If it's not, we should issue a warning of some kind.*/
}
}
}
private int loadFrame()
{
int DctQMask;
OggBuffer opb = pbi.opb;
/* Is the frame and inter frame or a key frame */
pbi.FrameType = (byte)opb.readB(1);
/* Quality (Q) index */
DctQMask = (int) opb.readB(6);
pbi.frameQIS[0] = DctQMask;
pbi.frameNQIS = 1;
/* look if there are additional frame quality indices */
int moreQs = opb.readB(1);
if(moreQs > 0) {
pbi.frameQIS[1] = (int) opb.readB(6);
pbi.frameNQIS = 2;
moreQs = opb.readB(1);
if(moreQs > 0) {
pbi.frameQIS[2] = (int) opb.readB(6);
pbi.frameNQIS = 3;
}
}
if ( (pbi.FrameType == Constants.BASE_FRAME) ){
/* Read the type / coding method for the key frame. */
pbi.KeyFrameType = (byte)opb.readB(1);
opb.readB(2);
}
/* Set this frame quality value from Q Index */
//pbi.ThisFrameQualityValue = pbi.QThreshTable[pbi.frameQ];
/* Read in the updated block map */
pbi.frArray.quadDecodeDisplayFragments( pbi );
return 1;
}
private void decodeModes (int SBRows, int SBCols)
{
int MB;
int SBcol;
int SBrow;
CodingMode[] FragCodingMethod;
int SB=0;
long ret;
int FragIndex;
CodingMode CodingMethod;
int UVRow;
int UVColumn;
int UVFragOffset;
int MBListIndex = 0;
int i;
FragCodingMethod = pbi.FragCodingMethod;
/* If the frame is an intra frame then all blocks have mode intra. */
if ( pbi.getFrameType() == Constants.BASE_FRAME ){
MemUtils.set(FragCodingMethod, 0, CodingMode.CODE_INTRA, pbi.UnitFragments);
}else{
/* Clear down the macro block level mode and MV arrays. Default coding mode */
MemUtils.set(FragCodingMethod, 0, CodingMode.CODE_INTER_NO_MV, pbi.UnitFragments);
CodingMode ModeEntry; /* Mode bits read */
CodingMode[] ModeList;
/* Read the coding method */
ret = pbi.opb.readB( Constants.MODE_METHOD_BITS);
int CodingScheme=(int)ret;
/* If the coding method is method 0 then we have to read in a
custom coding scheme */
if ( CodingScheme == 0 ){
CodingMode[] CustomModeAlphabet = new CodingMode[Constants.MAX_MODES];
/* Read the coding scheme. */
for ( i = 0; i < Constants.MAX_MODES; i++ ){
ret = pbi.opb.readB( Constants.MODE_BITS);
CustomModeAlphabet[(int)ret]= CodingMode.MODES[i];
}
ModeList=CustomModeAlphabet;
}
else{
ModeList=modeAlphabet[CodingScheme-1];
}
/* Unravel the quad-tree */
for ( SBrow=0; SBrow<SBRows; SBrow++ ){
for ( SBcol=0; SBcol<SBCols; SBcol++ ){
for ( MB=0; MB<4; MB++ ){
/* There may be MB's lying out of frame which must be
ignored. For these MB's top left block will have a negative
Fragment Index. */
/* Upack the block level modes and motion vectors */
FragIndex = pbi.BlockMap.quadMapToMBTopLeft(SB, MB);
if (FragIndex >= 0){
/* Is the Macro-Block coded: */
if ( pbi.MBCodedFlags[MBListIndex++] != 0){
/* Unpack the mode. */
if ( CodingScheme == (Constants.MODE_METHODS-1) ){
/* This is the fall back coding scheme. */
/* Simply MODE_BITS bits per mode entry. */
ret = pbi.opb.readB( Constants.MODE_BITS);
CodingMethod = CodingMode.MODES[(int)ret];
}else{
ModeEntry = pbi.frArray.unpackMode(pbi.opb);
CodingMethod = ModeList[ModeEntry.getValue()];
}
/* Note the coding mode for each block in macro block. */
FragCodingMethod[FragIndex] = CodingMethod;
FragCodingMethod[FragIndex + 1] = CodingMethod;
FragCodingMethod[FragIndex + pbi.HFragments] = CodingMethod;
FragCodingMethod[FragIndex + pbi.HFragments + 1] = CodingMethod;
/* Matching fragments in the U and V planes */
if (pbi.UVShiftX == 1 && pbi.UVShiftY == 1){ /* TH_PF_420 */
UVRow = (FragIndex / (pbi.HFragments * 2));
UVColumn = (FragIndex % pbi.HFragments) / 2;
UVFragOffset = (UVRow * (pbi.HFragments / 2)) + UVColumn;
FragCodingMethod[pbi.YPlaneFragments + UVFragOffset] = CodingMethod;
FragCodingMethod[pbi.YPlaneFragments + pbi.UVPlaneFragments + UVFragOffset] =
CodingMethod;
} else if (pbi.UVShiftX == 0) { /* TH_PF_444 */
FragIndex += pbi.YPlaneFragments;
FragCodingMethod[FragIndex] =
FragCodingMethod[FragIndex + 1] =
FragCodingMethod[FragIndex + pbi.HFragments] =
FragCodingMethod[FragIndex + pbi.HFragments + 1] = CodingMethod;
FragIndex += pbi.UVPlaneFragments;
FragCodingMethod[FragIndex] =
FragCodingMethod[FragIndex + 1] =
FragCodingMethod[FragIndex + pbi.HFragments] =
FragCodingMethod[FragIndex + pbi.HFragments + 1] = CodingMethod;
} else { /*TH_PF_422 */
FragIndex = pbi.YPlaneFragments + FragIndex/2;
FragCodingMethod[FragIndex] =
FragCodingMethod[FragIndex + pbi.HFragments/2] = CodingMethod;
FragIndex += pbi.UVPlaneFragments;
FragCodingMethod[FragIndex] =
FragCodingMethod[FragIndex + pbi.HFragments/2] = CodingMethod;
}
}
}
}
/* Next Super-Block */
SB++;
}
}
}
}
private void decodeMVectors (int SBRows, int SBCols)
{
int FragIndex;
int MB;
int SBrow;
int SBcol;
int SB=0;
CodingMode CodingMethod;
ExtractMVectorComponent MVC;
int UVRow;
int UVColumn;
int UVFragOffset;
int x,y;
int MBListIndex = 0;
OggBuffer opb = pbi.opb;
/* Should not be decoding motion vectors if in INTRA only mode. */
if (pbi.getFrameType() == Constants.BASE_FRAME ){
return;
}
MotionVector dummy = new MotionVector();
/* set the default motion vector to 0,0 */
LastInterMV.x = 0;
LastInterMV.y = 0;
PriorLastInterMV.x = 0;
PriorLastInterMV.y = 0;
/* Read the entropy method used and set up the appropriate decode option */
if (opb.readB(1) == 0 )
MVC = MVA;
else
MVC = MVB;
/* Unravel the quad-tree */
for ( SBrow=0; SBrow<SBRows; SBrow++ ){
for ( SBcol=0; SBcol<SBCols; SBcol++ ){
for ( MB=0; MB<4; MB++ ){
/* There may be MB's lying out of frame which must be
ignored. For these MB's the top left block will have a
negative Fragment. */
FragIndex = pbi.BlockMap.quadMapToMBTopLeft(SB, MB );
if (FragIndex >= 0 ) {
/* Is the Macro-Block further coded: */
if (pbi.MBCodedFlags[MBListIndex++] != 0){
/* Unpack the mode (and motion vectors if necessary). */
CodingMethod = pbi.FragCodingMethod[FragIndex];
/* Note the coding mode and vector for each block in the
current macro block. */
MotionVector MVect0 = pbi.FragMVect[FragIndex];
MotionVector MVect1 = pbi.FragMVect[FragIndex + 1];
MotionVector MVect2 = pbi.FragMVect[FragIndex + pbi.HFragments];
MotionVector MVect3 = pbi.FragMVect[FragIndex + pbi.HFragments + 1];
/* Matching fragments in the U and V planes */
UVRow = (FragIndex / (pbi.HFragments << pbi.UVShiftY));
UVColumn = (FragIndex % pbi.HFragments) >> pbi.UVShiftX;
UVFragOffset = (UVRow * (pbi.HFragments >> pbi.UVShiftX)) + UVColumn;
MotionVector MVectU0 = pbi.FragMVect[pbi.YPlaneFragments + UVFragOffset];
MotionVector MVectV0 = pbi.FragMVect[pbi.YPlaneFragments + pbi.UVPlaneFragments + UVFragOffset];
MotionVector MVectU1 = dummy;
MotionVector MVectV1 = dummy;
MotionVector MVectU2 = dummy;
MotionVector MVectV2 = dummy;
MotionVector MVectU3 = dummy;
MotionVector MVectV3 = dummy;
if (pbi.UVShiftY == 0) {
MVectU2 = pbi.FragMVect[pbi.YPlaneFragments + UVFragOffset + (pbi.HFragments>>pbi.UVShiftX)];
MVectV2 = pbi.FragMVect[pbi.YPlaneFragments + pbi.UVPlaneFragments + UVFragOffset + (pbi.HFragments>>pbi.UVShiftX)];
if (pbi.UVShiftX == 0){
MVectU1 = pbi.FragMVect[pbi.YPlaneFragments + UVFragOffset + 1];
MVectV1 = pbi.FragMVect[pbi.YPlaneFragments + pbi.UVPlaneFragments + UVFragOffset + 1];
MVectU3 = pbi.FragMVect[pbi.YPlaneFragments + UVFragOffset + pbi.HFragments + 1];
MVectV3 = pbi.FragMVect[pbi.YPlaneFragments + pbi.UVPlaneFragments + UVFragOffset + pbi.HFragments + 1];
}
}
/* Read the motion vector or vectors if present. */
if (CodingMethod == CodingMode.CODE_INTER_PLUS_MV) {
PriorLastInterMV.x = LastInterMV.x;
PriorLastInterMV.y = LastInterMV.y;
LastInterMV.x = MVect0.x =
MVect1.x =
MVect2.x =
MVect3.x =
MVectU0.x =
MVectV0.x =
MVectU1.x =
MVectV1.x =
MVectU2.x =
MVectV2.x =
MVectU3.x =
MVectV3.x = MVC.extract(opb);
LastInterMV.y = MVect0.y =
MVect1.y =
MVect2.y =
MVect3.y =
MVectU0.y =
MVectV0.y =
MVectU1.y =
MVectV1.y =
MVectU2.y =
MVectV2.y =
MVectU3.y =
MVectV3.y = MVC.extract(opb);
}
else if (CodingMethod == CodingMode.CODE_GOLDEN_MV){
MVect0.x = MVect1.x =
MVect2.x =
MVect3.x =
MVectU0.x =
MVectV0.x =
MVectU1.x =
MVectV1.x =
MVectU2.x =
MVectV2.x =
MVectU3.x =
MVectV3.x = MVC.extract(opb);
MVect0.y = MVect1.y =
MVect2.y =
MVect3.y =
MVectU0.y =
MVectV0.y =
MVectU1.y =
MVectV1.y =
MVectU2.y =
MVectV2.y =
MVectU3.y =
MVectV3.y = MVC.extract(opb);
}
else if ( CodingMethod == CodingMode.CODE_INTER_FOURMV ){
/* Update last MV and prior last mv */
PriorLastInterMV.x = LastInterMV.x;
PriorLastInterMV.y = LastInterMV.y;
/* Extrac the 4 Y MVs */
if(pbi.display_fragments[FragIndex] != 0) {
x = MVect0.x = MVC.extract(opb);
y = MVect0.y = MVC.extract(opb);
LastInterMV.x = MVect0.x;
LastInterMV.y = MVect0.y;
} else {
x = MVect0.x = 0;
y = MVect0.y = 0;
}
if(pbi.display_fragments[FragIndex + 1] != 0) {
x += MVect1.x = MVC.extract(opb);
y += MVect1.y = MVC.extract(opb);
LastInterMV.x = MVect1.x;
LastInterMV.y = MVect1.y;
} else {
x += MVect1.x = 0;
y += MVect1.y = 0;
}
if(pbi.display_fragments[FragIndex + pbi.HFragments] != 0) {
x += MVect2.x = MVC.extract(opb);
y += MVect2.y = MVC.extract(opb);
LastInterMV.x = MVect2.x;
LastInterMV.y = MVect2.y;
} else {
x += MVect2.x = 0;
y += MVect2.y = 0;
}
if(pbi.display_fragments[FragIndex + pbi.HFragments + 1] != 0) {
x += MVect3.x = MVC.extract(opb);
y += MVect3.y = MVC.extract(opb);
LastInterMV.x = MVect3.x;
LastInterMV.y = MVect3.y;
} else {
x += MVect3.x = 0;
y += MVect3.y = 0;
}
if(pbi.UVShiftY == 0) {
if(pbi.UVShiftX == 0) {
MVectU0.x = MVectV0.x = MVect0.x;
MVectU0.y = MVectV0.y = MVect0.y;
MVectU1.x = MVectV1.x = MVect1.x;
MVectU1.y = MVectV1.y = MVect1.y;
MVectU2.x = MVectV2.x = MVect2.x;
MVectU2.y = MVectV2.y = MVect2.y;
MVectU3.x = MVectV3.x = MVect3.x;
MVectU3.y = MVectV3.y = MVect3.y;
} else {
/* 4:2:2, so average components only horizontally */
x = MVect0.x + MVect1.x;
if (x >= 0 ) x = (x+1) / 2;
else x = (x-1) / 2;
MVectU0.x =
MVectV0.x = x;
y = MVect0.y + MVect1.y;
if (y >= 0 ) y = (y+1) / 2;
else y = (y-1) / 2;
MVectU0.y =
MVectV0.y = y;
x = MVect2.x + MVect3.x;
if (x >= 0 ) x = (x+1) / 2;
else x = (x-1) / 2;
MVectU2.x =
MVectV2.x = x;
y = MVect2.y + MVect3.y;
if (y >= 0 ) y = (y+1) / 2;
else y = (y-1) / 2;
MVectU2.y =
MVectV2.y = y;
}
} else {
/* Calculate the U and V plane MVs as the average of the
Y plane MVs. */
/* First .x component */
if (x >= 0 ) x = (x+2) / 4;
else x = (x-2) / 4;
MVectU0.x = x;
MVectV0.x = x;
/* Then .y component */
if (y >= 0 ) y = (y+2) / 4;
else y = (y-2) / 4;
MVectU0.y = y;
MVectV0.y = y;
}
}
else if ( CodingMethod == CodingMode.CODE_INTER_LAST_MV ){
/* Use the last coded Inter motion vector. */
MVect0.x = MVect1.x =
MVect2.x =
MVect3.x =
MVectU0.x =
MVectV0.x =
MVectU1.x =
MVectV1.x =
MVectU2.x =
MVectV2.x =
MVectU3.x =
MVectV3.x = LastInterMV.x;
MVect0.y = MVect1.y =
MVect2.y =
MVect3.y =
MVectU0.y =
MVectV0.y =
MVectU1.y =
MVectV1.y =
MVectU2.y =
MVectV2.y =
MVectU3.y =
MVectV3.y = LastInterMV.y;
}
else if ( CodingMethod == CodingMode.CODE_INTER_PRIOR_LAST ){
/* Use the next-to-last coded Inter motion vector. */
MVect0.x = MVect1.x =
MVect2.x =
MVect3.x =
MVectU0.x =
MVectV0.x =
MVectU1.x =
MVectV1.x =
MVectU2.x =
MVectV2.x =
MVectU3.x =
MVectV3.x = PriorLastInterMV.x;
MVect0.y = MVect1.y =
MVect2.y =
MVect3.y =
MVectU0.y =
MVectV0.y =
MVectU1.y =
MVectV1.y =
MVectU2.y =
MVectV2.y =
MVectU3.y =
MVectV3.y = PriorLastInterMV.y;
/* Swap the prior and last MV cases over */
MotionVector TmpMVect = PriorLastInterMV;
PriorLastInterMV = LastInterMV;
LastInterMV = TmpMVect;
}
else {
/* Clear the motion vector else */
MVect0.x = 0;
MVect0.y = 0;
}
}
}
}
/* Next Super-Block */
SB++;
}
}
}
private final int ExtractToken(OggBuffer opb,
HuffEntry CurrentRoot){
/* Loop searches down through tree based upon bits read from the
bitstream */
/* until it hits a leaf at which point we have decoded a token */
while (CurrentRoot.value < 0 ){
CurrentRoot = CurrentRoot.Child[(int)opb.readB(1)];
}
return CurrentRoot.value;
}
private void unpackAndExpandToken(short[] ExpandedBlock,
byte[] CoeffIndex,
int FragIndex,
int HuffChoice){
int ExtraBits = 0;
int Token = ExtractToken(pbi.opb, pbi.HuffRoot_VP3x[HuffChoice]);
/* Now.. if we are using the DCT optimised coding system, extract any
* assosciated additional bits token.
*/
if (pbi.ExtraBitLengths_VP3x[Token] > 0){
/* Extract the appropriate number of extra bits. */
ExtraBits = (int)pbi.opb.readB(pbi.ExtraBitLengths_VP3x[Token]);
}
/* Take token dependant action */
if ( Token >= Huffman.DCT_SHORT_ZRL_TOKEN ) {
/* "Value", "zero run" and "zero run value" tokens */
dctDecode.ExpandToken(ExpandedBlock, CoeffIndex, FragIndex, Token, ExtraBits );
if ( CoeffIndex[FragIndex] >= Constants.BLOCK_SIZE )
BlocksToDecode --;
}else{
/* Special action and EOB tokens */
switch ( Token ){
case Huffman.DCT_EOB_PAIR_TOKEN:
EOB_Run = 1;
break;
case Huffman.DCT_EOB_TRIPLE_TOKEN:
EOB_Run = 2;
break;
case Huffman.DCT_REPEAT_RUN_TOKEN:
EOB_Run = ExtraBits + 3;
break;
case Huffman.DCT_REPEAT_RUN2_TOKEN:
EOB_Run = ExtraBits + 7;
break;
case Huffman.DCT_REPEAT_RUN3_TOKEN:
EOB_Run = ExtraBits + 15;
break;
case Huffman.DCT_REPEAT_RUN4_TOKEN:
EOB_Run = ExtraBits - 1;
break;
case Huffman.DCT_EOB_TOKEN:
break;
default:
return;
}
CoeffIndex[FragIndex] = Constants.BLOCK_SIZE;
BlocksToDecode --;
}
}
private void unPackVideo ()
{
int EncodedCoeffs = 1;
int FragIndex;
int AcHuffChoice;
int AcHuffChoice1;
int AcHuffChoice2;
int DcHuffChoice;
/* Bail out immediately if a decode error has already been reported. */
if ( pbi.DecoderErrorCode != 0)
return;
/* Clear down the array that indicates the current coefficient index
for each block. */
MemUtils.set(FragCoeffs, 0, 0, pbi.UnitFragments);
MemUtils.set(pbi.FragCoefEOB, 0, 0, pbi.UnitFragments);
/* Note the number of blocks to decode */
BlocksToDecode = pbi.CodedBlockIndex;
/* Get the DC huffman table choice for Y and then UV */
int DcHuffChoice1 = (int)(pbi.opb.readB(Huffman.DC_HUFF_CHOICE_BITS) + Huffman.DC_HUFF_OFFSET);
int DcHuffChoice2 = (int)(pbi.opb.readB(Huffman.DC_HUFF_CHOICE_BITS) + Huffman.DC_HUFF_OFFSET);
/* UnPack DC coefficients / tokens */
int cbl = 0;
int cble = pbi.CodedBlockIndex;
while (cbl < cble) {
/* Get the block data index */
FragIndex = pbi.CodedBlockList[cbl];
pbi.FragCoefEOB[FragIndex] = FragCoeffs[FragIndex];
/* Select the appropriate huffman table offset according to
whether the token is from a Y or UV block */
if (FragIndex < (int)pbi.YPlaneFragments )
DcHuffChoice = DcHuffChoice1;
else
DcHuffChoice = DcHuffChoice2;
/* If we are in the middle of an EOB run */
if ( EOB_Run != 0){
/* Mark the current block as fully expanded and decrement
EOB_RUN count */
FragCoeffs[FragIndex] = Constants.BLOCK_SIZE;
EOB_Run --;
BlocksToDecode --;
}else{
/* Else unpack a DC token */
unpackAndExpandToken(pbi.QFragData[FragIndex],
FragCoeffs,
FragIndex,
DcHuffChoice);
}
cbl++;
}
/* Get the AC huffman table choice for Y and then for UV. */
int AcHuffIndex1 = (int) (pbi.opb.readB(Huffman.AC_HUFF_CHOICE_BITS) + Huffman.AC_HUFF_OFFSET);
int AcHuffIndex2 = (int) (pbi.opb.readB(Huffman.AC_HUFF_CHOICE_BITS) + Huffman.AC_HUFF_OFFSET);
/* Unpack Lower AC coefficients. */
while ( EncodedCoeffs < 64 ) {
/* Repeatedly scan through the list of blocks. */
cbl = 0;
cble = pbi.CodedBlockIndex;
/* Huffman table selection based upon which AC coefficient we are on */
if ( EncodedCoeffs <= Huffman.AC_TABLE_2_THRESH ){
AcHuffChoice1 = AcHuffIndex1;
AcHuffChoice2 = AcHuffIndex2;
}else if ( EncodedCoeffs <= Huffman.AC_TABLE_3_THRESH ){
AcHuffChoice1 = (AcHuffIndex1 + Huffman.AC_HUFF_CHOICES);
AcHuffChoice2 = (AcHuffIndex2 + Huffman.AC_HUFF_CHOICES);
} else if ( EncodedCoeffs <= Huffman.AC_TABLE_4_THRESH ){
AcHuffChoice1 = (AcHuffIndex1 + (Huffman.AC_HUFF_CHOICES * 2));
AcHuffChoice2 = (AcHuffIndex2 + (Huffman.AC_HUFF_CHOICES * 2));
} else {
AcHuffChoice1 = (AcHuffIndex1 + (Huffman.AC_HUFF_CHOICES * 3));
AcHuffChoice2 = (AcHuffIndex2 + (Huffman.AC_HUFF_CHOICES * 3));
}
while(cbl < cble ) {
/* Get the linear index for the current fragment. */
FragIndex = pbi.CodedBlockList[cbl];
/* Should we decode a token for this block on this pass. */
if ( FragCoeffs[FragIndex] <= EncodedCoeffs ) {
pbi.FragCoefEOB[FragIndex] = FragCoeffs[FragIndex];
/* If we are in the middle of an EOB run */
if ( EOB_Run != 0) {
/* Mark the current block as fully expanded and decrement
EOB_RUN count */
FragCoeffs[FragIndex] = Constants.BLOCK_SIZE;
EOB_Run --;
BlocksToDecode --;
}else{
/* Else unpack an AC token */
/* Work out which huffman table to use, then decode a token */
if ( FragIndex < (int)pbi.YPlaneFragments )
AcHuffChoice = AcHuffChoice1;
else
AcHuffChoice = AcHuffChoice2;
unpackAndExpandToken(pbi.QFragData[FragIndex],
FragCoeffs,
FragIndex,
AcHuffChoice);
}
}
cbl++;
}
/* Test for condition where there are no blocks left with any
tokesn to decode */
if ( BlocksToDecode == 0)
break;
EncodedCoeffs ++;
}
}
public int loadAndDecode()
{
int loadFrameOK;
/* Load the next frame. */
loadFrameOK = loadFrame();
if (loadFrameOK != 0){
//System.out.println("Load: "+loadFrameOK+" "+pbi.ThisFrameQualityValue+" "+pbi.LastFrameQualityValue);
/* Decode the data into the fragment buffer. */
/* Bail out immediately if a decode error has already been reported. */
if (pbi.DecoderErrorCode != 0)
return 0;
/* Zero Decoder EOB run count */
EOB_Run = 0;
/* Make a note of the number of coded blocks this frame */
pbi.CodedBlocksThisFrame = pbi.CodedBlockIndex;
/* Decode the modes data */
decodeModes(pbi.YSBRows, pbi.YSBCols);
/* Unpack and decode the motion vectors. */
decodeMVectors (pbi.YSBRows, pbi.YSBCols);
/* Unpack per-block quantizer information */
decodeBlockLevelQi();
/* Unpack and decode the actual video data. */
unPackVideo();
/* Reconstruct and display the frame */
dctDecode.ReconRefFrames(pbi);
return 0;
}
return(Result.BADPACKET);
}
}

View File

@@ -0,0 +1,394 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public final class Filter
{
/* in-loop filter tables. one of these is used in dct_decode.c */
private static final byte[] LoopFilterLimitValuesV1 = {
30, 25, 20, 20, 15, 15, 14, 14,
13, 13, 12, 12, 11, 11, 10, 10,
9, 9, 8, 8, 7, 7, 7, 7,
6, 6, 6, 6, 5, 5, 5, 5,
4, 4, 4, 4, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
/* Loop filter bounding values */
private byte[] LoopFilterLimits = new byte[Constants.Q_TABLE_SIZE];
private int[] FiltBoundingValue = new int[512];
private void SetupBoundingValueArray_Generic(int FLimit)
{
/* Set up the bounding value array. */
MemUtils.set (FiltBoundingValue, 0, 0, 512);
for (int i = 0; i < FLimit; i++ ){
FiltBoundingValue[256-i-FLimit] = (-FLimit+i);
FiltBoundingValue[256-i] = -i;
FiltBoundingValue[256+i] = i;
FiltBoundingValue[256+i+FLimit] = FLimit-i;
}
}
/* copy in-loop filter limits from the bitstream header into our instance */
public void copyFilterTables(TheoraInfo ci) {
System.arraycopy(ci.LoopFilterLimitValues, 0, LoopFilterLimits, 0, Constants.Q_TABLE_SIZE);
}
/* initialize the filter limits from our static table */
public void InitFilterTables() {
System.arraycopy(LoopFilterLimitValuesV1, 0, LoopFilterLimits, 0, Constants.Q_TABLE_SIZE);
}
public void SetupLoopFilter(int FrameQIndex){
int FLimit;
/* nb: this was using the V2 values rather than V1
we think is was a mistake; the results were not used */
FLimit = LoopFilterLimits[FrameQIndex];
SetupBoundingValueArray_Generic(FLimit);
}
private static final short clamp255(int val) {
return (short)((~(val>>31)) & 255 & (val | ((255-val)>>31)));
}
private void FilterHoriz(short[] PixelPtr, int idx,
int LineLength,
int[] BoundingValuePtr)
{
int j;
int FiltVal;
for ( j = 0; j < 8; j++ ){
FiltVal =
( PixelPtr[0 + idx] ) -
( PixelPtr[1 + idx] * 3 ) +
( PixelPtr[2 + idx] * 3 ) -
( PixelPtr[3 + idx] );
FiltVal = BoundingValuePtr[256 + ((FiltVal + 4) >> 3)];
PixelPtr[1 + idx] = clamp255(PixelPtr[1 + idx] + FiltVal);
PixelPtr[2 + idx] = clamp255(PixelPtr[2 + idx] - FiltVal);
idx += LineLength;
}
}
private void FilterVert(short[] PixelPtr, int idx,
int LineLength,
int[] BoundingValuePtr){
int j;
int FiltVal;
/* the math was correct, but negative array indicies are forbidden
by ANSI/C99 and will break optimization on several modern
compilers */
idx -= 2*LineLength;
for ( j = 0; j < 8; j++ ) {
FiltVal =
( PixelPtr[idx + 0] ) -
( PixelPtr[idx + LineLength] * 3 ) +
( PixelPtr[idx + 2 * LineLength] * 3 ) -
( PixelPtr[idx + 3 * LineLength] );
FiltVal = BoundingValuePtr[256 + ((FiltVal + 4) >> 3)];
PixelPtr[idx + LineLength] = clamp255(PixelPtr[idx + LineLength] + FiltVal);
PixelPtr[idx + 2 * LineLength] = clamp255(PixelPtr[idx + 2*LineLength] - FiltVal);
idx++;
}
}
public void LoopFilter(Playback pbi){
int FragsAcross=pbi.HFragments;
int FromFragment;
int FragsDown = pbi.VFragments;
int LineFragments;
int LineLength;
int FLimit;
int QIndex;
int i,j,m,n;
int index;
/* Set the limit value for the loop filter based upon the current
quantizer. */
QIndex = pbi.frameQIS[0];
FLimit = LoopFilterLimits[QIndex];
if ( FLimit == 0 ) return;
SetupBoundingValueArray_Generic(FLimit);
for ( j = 0; j < 3 ; j++){
switch(j) {
case 0: /* y */
FromFragment = 0;
FragsAcross = pbi.HFragments;
FragsDown = pbi.VFragments;
LineLength = pbi.YStride;
LineFragments = pbi.HFragments;
break;
case 1: /* u */
FromFragment = pbi.YPlaneFragments;
FragsAcross = pbi.HFragments >> 1;
FragsDown = pbi.VFragments >> 1;
LineLength = pbi.UVStride;
LineFragments = pbi.HFragments / 2;
break;
/*case 2: v */
default:
FromFragment = pbi.YPlaneFragments + pbi.UVPlaneFragments;
FragsAcross = pbi.HFragments >> 1;
FragsDown = pbi.VFragments >> 1;
LineLength = pbi.UVStride;
LineFragments = pbi.HFragments / 2;
break;
}
i=FromFragment;
/**************************************************************
First Row
**************************************************************/
/* first column conditions */
/* only do 2 prediction if fragment coded and on non intra or if
all fragments are intra */
if( pbi.display_fragments[i] != 0){
/* Filter right hand border only if the block to the right is
not coded */
if ( pbi.display_fragments[ i + 1 ] == 0){
FilterHoriz(pbi.LastFrameRecon,
pbi.recon_pixel_index_table[i]+6,
LineLength,FiltBoundingValue);
}
/* Bottom done if next row set */
if( pbi.display_fragments[ i + LineFragments] == 0){
FilterVert(pbi.LastFrameRecon,
pbi.recon_pixel_index_table[i+LineFragments],
LineLength, FiltBoundingValue);
}
}
i++;
/***************************************************************/
/* middle columns */
for ( n = 1 ; n < FragsAcross - 1 ; n++) {
if( pbi.display_fragments[i] != 0){
index = pbi.recon_pixel_index_table[i];
/* Filter Left edge always */
FilterHoriz(pbi.LastFrameRecon, index-2,
LineLength, FiltBoundingValue);
/* Filter right hand border only if the block to the right is
not coded */
if (pbi.display_fragments[ i + 1 ] == 0){
FilterHoriz(pbi.LastFrameRecon,
index+6,
LineLength, FiltBoundingValue);
}
/* Bottom done if next row set */
if(pbi.display_fragments[ i + LineFragments] == 0){
FilterVert(pbi.LastFrameRecon,
pbi.recon_pixel_index_table[i+LineFragments],
LineLength, FiltBoundingValue);
}
}
i++;
}
/***************************************************************/
/* Last Column */
if( pbi.display_fragments[i] != 0){
/* Filter Left edge always */
FilterHoriz(pbi.LastFrameRecon,
pbi.recon_pixel_index_table[i] - 2 ,
LineLength, FiltBoundingValue);
/* Bottom done if next row set */
if(pbi.display_fragments[ i + LineFragments] == 0){
FilterVert(pbi.LastFrameRecon,
pbi.recon_pixel_index_table[i+LineFragments],
LineLength, FiltBoundingValue);
}
}
i++;
/***************************************************************/
/* Middle Rows */
/***************************************************************/
for ( m = 1 ; m < FragsDown-1 ; m++) {
/*****************************************************************/
/* first column conditions */
/* only do 2 prediction if fragment coded and on non intra or if
all fragments are intra */
if(pbi.display_fragments[i] != 0){
index = pbi.recon_pixel_index_table[i];
/* TopRow is always done */
FilterVert(pbi.LastFrameRecon, index,
LineLength, FiltBoundingValue);
/* Filter right hand border only if the block to the right is
not coded */
if (pbi.display_fragments[ i + 1 ] == 0){
FilterHoriz(pbi.LastFrameRecon, index + 6,
LineLength, FiltBoundingValue);
}
/* Bottom done if next row set */
if(pbi.display_fragments[ i + LineFragments] == 0){
FilterVert(pbi.LastFrameRecon,
pbi.recon_pixel_index_table[i+LineFragments],
LineLength, FiltBoundingValue);
}
}
i++;
/*****************************************************************/
/* middle columns */
for ( n = 1 ; n < FragsAcross - 1 ; n++, i++){
if( pbi.display_fragments[i] != 0){
index = pbi.recon_pixel_index_table[i];
/* Filter Left edge always */
FilterHoriz(pbi.LastFrameRecon, index - 2,
LineLength, FiltBoundingValue);
/* TopRow is always done */
FilterVert(pbi.LastFrameRecon, index,
LineLength, FiltBoundingValue);
/* Filter right hand border only if the block to the right
is not coded */
if (pbi.display_fragments[ i + 1 ] == 0){
FilterHoriz(pbi.LastFrameRecon, index + 6,
LineLength, FiltBoundingValue);
}
/* Bottom done if next row set */
if(pbi.display_fragments[ i + LineFragments] == 0){
FilterVert(pbi.LastFrameRecon,
pbi.recon_pixel_index_table[i+LineFragments],
LineLength, FiltBoundingValue);
}
}
}
/******************************************************************/
/* Last Column */
if( pbi.display_fragments[i] != 0){
index = pbi.recon_pixel_index_table[i];
/* Filter Left edge always*/
FilterHoriz(pbi.LastFrameRecon, index - 2,
LineLength, FiltBoundingValue);
/* TopRow is always done */
FilterVert(pbi.LastFrameRecon, index,
LineLength, FiltBoundingValue);
/* Bottom done if next row set */
if(pbi.display_fragments[ i + LineFragments] == 0){
FilterVert(pbi.LastFrameRecon,
pbi.recon_pixel_index_table[i+LineFragments],
LineLength, FiltBoundingValue);
}
}
i++;
}
/*******************************************************************/
/* Last Row */
/* first column conditions */
/* only do 2 prediction if fragment coded and on non intra or if
all fragments are intra */
if(pbi.display_fragments[i] != 0){
index = pbi.recon_pixel_index_table[i];
/* TopRow is always done */
FilterVert(pbi.LastFrameRecon, index,
LineLength, FiltBoundingValue);
/* Filter right hand border only if the block to the right is
not coded */
if (pbi.display_fragments[ i + 1 ] == 0){
FilterHoriz(pbi.LastFrameRecon, index+6,
LineLength, FiltBoundingValue);
}
}
i++;
/******************************************************************/
/* middle columns */
for ( n = 1 ; n < FragsAcross - 1 ; n++, i++){
if( pbi.display_fragments[i] != 0){
index = pbi.recon_pixel_index_table[i];
/* Filter Left edge always */
FilterHoriz(pbi.LastFrameRecon, index-2,
LineLength, FiltBoundingValue);
/* TopRow is always done */
FilterVert(pbi.LastFrameRecon, index,
LineLength, FiltBoundingValue);
/* Filter right hand border only if the block to the right is
not coded */
if (pbi.display_fragments[ i + 1 ] == 0){
FilterHoriz(pbi.LastFrameRecon, index+6,
LineLength, FiltBoundingValue);
}
}
}
/******************************************************************/
/* Last Column */
if(pbi.display_fragments[i] != 0){
index = pbi.recon_pixel_index_table[i];
/* Filter Left edge always */
FilterHoriz(pbi.LastFrameRecon, index - 2,
LineLength, FiltBoundingValue);
/* TopRow is always done */
FilterVert(pbi.LastFrameRecon, index,
LineLength, FiltBoundingValue);
}
}
}
}

View File

@@ -0,0 +1,419 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
public class FrArray {
private int bit_pattern;
private byte bits_so_far;
private byte NextBit;
private int BitsLeft;
public FrArray() {
}
public void init() {
/* Initialise the decoding of a run. */
bit_pattern = 0;
bits_so_far = 0;
}
private int deCodeBlockRun(int bit_value){
/* Add in the new bit value. */
bits_so_far++;
bit_pattern = (bit_pattern << 1) + (bit_value & 1);
/* Coding scheme:
Codeword RunLength
0x 1-2
10x 3-4
110x 5-6
1110xx 7-10
11110xx 11-14
11111xxxx 15-30
*/
switch ( bits_so_far ){
case 2:
/* If bit 1 is clear */
if ((bit_pattern & 0x0002) == 0){
BitsLeft = (bit_pattern & 0x0001) + 1;
return 1;
}
break;
case 3:
/* If bit 1 is clear */
if ((bit_pattern & 0x0002) == 0){
BitsLeft = (bit_pattern & 0x0001) + 3;
return 1;
}
break;
case 4:
/* If bit 1 is clear */
if ((bit_pattern & 0x0002) == 0){
BitsLeft = (bit_pattern & 0x0001) + 5;
return 1;
}
break;
case 6:
/* If bit 2 is clear */
if ((bit_pattern & 0x0004) == 0){
BitsLeft = (bit_pattern & 0x0003) + 7;
return 1;
}
break;
case 7:
/* If bit 2 is clear */
if ((bit_pattern & 0x0004) == 0){
BitsLeft = (bit_pattern & 0x0003) + 11;
return 1;
}
break;
case 9:
BitsLeft = (bit_pattern & 0x000F) + 15;
return 1;
}
return 0;
}
private int deCodeSBRun (int bit_value){
/* Add in the new bit value. */
bits_so_far++;
bit_pattern = (bit_pattern << 1) + (bit_value & 1);
/* Coding scheme:
Codeword RunLength
0 1
10x 2-3
110x 4-5
1110xx 6-9
11110xxx 10-17
111110xxxx 18-33
111111xxxxxxxxxxxx 34-4129
*/
switch ( bits_so_far ){
case 1:
if (bit_pattern == 0 ){
BitsLeft = 1;
return 1;
}
break;
case 3:
/* Bit 1 clear */
if ((bit_pattern & 0x0002) == 0){
BitsLeft = (bit_pattern & 0x0001) + 2;
return 1;
}
break;
case 4:
/* Bit 1 clear */
if ((bit_pattern & 0x0002) == 0){
BitsLeft = (bit_pattern & 0x0001) + 4;
return 1;
}
break;
case 6:
/* Bit 2 clear */
if ((bit_pattern & 0x0004) == 0){
BitsLeft = (bit_pattern & 0x0003) + 6;
return 1;
}
break;
case 8:
/* Bit 3 clear */
if ((bit_pattern & 0x0008) == 0){
BitsLeft = (bit_pattern & 0x0007) + 10;
return 1;
}
break;
case 10:
/* Bit 4 clear */
if ((bit_pattern & 0x0010) == 0){
BitsLeft = (bit_pattern & 0x000F) + 18;
return 1;
}
break;
case 18:
BitsLeft = (bit_pattern & 0x0FFF) + 34;
return 1;
}
return 0;
}
private void getNextBInit(OggBuffer opb){
long ret;
ret = opb.readB(1);
NextBit = (byte)ret;
/* Read run length */
init();
do {
ret = opb.readB(1);
}
while (deCodeBlockRun((int)ret)==0);
}
private byte getNextBBit (OggBuffer opb){
long ret;
if (BitsLeft == 0){
/* Toggle the value. */
NextBit = (byte) (NextBit ^ 1);
/* Read next run */
init();
do {
ret = opb.readB(1);
}
while (deCodeBlockRun((int)ret)==0);
}
/* Have read a bit */
BitsLeft--;
/* Return next bit value */
return NextBit;
}
private void getNextSbInit(OggBuffer opb){
long ret;
ret = opb.readB(1);
NextBit = (byte)ret;
/* Read run length */
init();
do {
ret = opb.readB(1);
}
while (deCodeSBRun((int)ret)==0);
}
private byte getNextSbBit (OggBuffer opb){
long ret;
if (BitsLeft == 0){
/* Toggle the value. */
NextBit = (byte) (NextBit ^ 1);
/* Read next run */
init();
do {
ret = opb.readB(1);
}
while (deCodeSBRun((int)ret)==0);
}
/* Have read a bit */
BitsLeft--;
/* Return next bit value */
return NextBit;
}
private final short[] empty64 = new short[64];
public void quadDecodeDisplayFragments ( Playback pbi ){
int SB, MB, B;
int DataToDecode;
int dfIndex;
int MBIndex = 0;
OggBuffer opb = pbi.opb;
/* Reset various data structures common to key frames and inter frames. */
pbi.CodedBlockIndex = 0;
MemUtils.set ( pbi.display_fragments, 0, 0, pbi.UnitFragments );
/* For "Key frames" mark all blocks as coded and return. */
/* Else initialise the ArrayPtr array to 0 (all blocks uncoded by default) */
if ( pbi.getFrameType() == Constants.BASE_FRAME ) {
MemUtils.set( pbi.SBFullyFlags, 0, 1, pbi.SuperBlocks );
MemUtils.set( pbi.SBCodedFlags, 0, 1, pbi.SuperBlocks );
MemUtils.set( pbi.MBCodedFlags, 0, 0, pbi.MacroBlocks );
}else{
MemUtils.set( pbi.SBFullyFlags, 0, 0, pbi.SuperBlocks );
MemUtils.set( pbi.MBCodedFlags, 0, 0, pbi.MacroBlocks );
/* Un-pack the list of partially coded Super-Blocks */
getNextSbInit(opb);
for( SB = 0; SB < pbi.SuperBlocks; SB++){
pbi.SBCodedFlags[SB] = getNextSbBit (opb);
}
/* Scan through the list of super blocks. Unless all are marked
as partially coded we have more to do. */
DataToDecode = 0;
for ( SB=0; SB<pbi.SuperBlocks; SB++ ) {
if (pbi.SBCodedFlags[SB] == 0) {
DataToDecode = 1;
break;
}
}
/* Are there further block map bits to decode ? */
if (DataToDecode != 0) {
/* Un-pack the Super-Block fully coded flags. */
getNextSbInit(opb);
for( SB = 0; SB < pbi.SuperBlocks; SB++) {
/* Skip blocks already marked as partially coded */
while( (SB < pbi.SuperBlocks) && (pbi.SBCodedFlags[SB] != 0 ))
SB++;
if (SB < pbi.SuperBlocks) {
pbi.SBFullyFlags[SB] = getNextSbBit (opb);
if (pbi.SBFullyFlags[SB] != 0) /* If SB is fully coded. */
pbi.SBCodedFlags[SB] = 1; /* Mark the SB as coded */
}
}
}
/* Scan through the list of coded super blocks. If at least one
is marked as partially coded then we have a block list to
decode. */
for ( SB=0; SB<pbi.SuperBlocks; SB++ ) {
if ((pbi.SBCodedFlags[SB] != 0) && (pbi.SBFullyFlags[SB] == 0)) {
/* Initialise the block list decoder. */
getNextBInit(opb);
break;
}
}
}
/* Decode the block data from the bit stream. */
for ( SB=0; SB<pbi.SuperBlocks; SB++ ){
for ( MB=0; MB<4; MB++ ){
/* If MB is in the frame */
if (pbi.BlockMap.quadMapToMBTopLeft(SB,MB) >= 0 ){
/* Only read block level data if SB was fully or partially coded */
if (pbi.SBCodedFlags[SB] != 0) {
for ( B=0; B<4; B++ ){
/* If block is valid (in frame)... */
dfIndex = pbi.BlockMap.quadMapToIndex1(SB, MB, B);
if ( dfIndex >= 0 ){
if ( pbi.SBFullyFlags[SB] != 0)
pbi.display_fragments[dfIndex] = 1;
else
pbi.display_fragments[dfIndex] = getNextBBit(opb);
/* Create linear list of coded block indices */
if ( pbi.display_fragments[dfIndex] != 0) {
pbi.MBCodedFlags[MBIndex] = 1;
pbi.CodedBlockList[pbi.CodedBlockIndex] = dfIndex;
/* Clear down the pbi.QFragData structure for this coded block. */
System.arraycopy(empty64, 0, pbi.QFragData[dfIndex], 0, 64);
pbi.CodedBlockIndex++;
}
}
}
}
MBIndex++;
}
}
}
}
public CodingMode unpackMode(OggBuffer opb){
/* Coding scheme:
Token Codeword Bits
Entry 0 (most frequent) 0 1
Entry 1 10 2
Entry 2 110 3
Entry 3 1110 4
Entry 4 11110 5
Entry 5 111110 6
Entry 6 1111110 7
Entry 7 1111111 7
*/
/* Initialise the decoding. */
bits_so_far = 0;
bit_pattern = (int) opb.readB(1);
/* Do we have a match */
if ( bit_pattern == 0 )
return CodingMode.MODES[0];
/* Get the next bit */
bit_pattern = (bit_pattern << 1) | (int)opb.readB(1);
/* Do we have a match */
if ( bit_pattern == 0x0002 )
return CodingMode.MODES[1];
bit_pattern = (bit_pattern << 1) | (int)opb.readB(1);
/* Do we have a match */
if ( bit_pattern == 0x0006 )
return CodingMode.MODES[2];
bit_pattern = (bit_pattern << 1) | (int)opb.readB(1);
/* Do we have a match */
if ( bit_pattern == 0x000E )
return CodingMode.MODES[3];
bit_pattern = (bit_pattern << 1) | (int)opb.readB(1);
/* Do we have a match */
if ( bit_pattern == 0x001E )
return CodingMode.MODES[4];
bit_pattern = (bit_pattern << 1) | (int)opb.readB(1);
/* Do we have a match */
if ( bit_pattern == 0x003E )
return CodingMode.MODES[5];
bit_pattern = (bit_pattern << 1) | (int)opb.readB(1);
/* Do we have a match */
if ( bit_pattern == 0x007E )
return CodingMode.MODES[6];
else
return CodingMode.MODES[7];
}
}

View File

@@ -0,0 +1,288 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public class FrInit {
static void InitializeFragCoordinates(Playback pbi)
{
int i, j;
int HorizFrags = pbi.HFragments;
int VertFrags = pbi.VFragments;
int StartFrag = 0;
/* Y */
for(i = 0; i< VertFrags; i++){
for(j = 0; j< HorizFrags; j++){
int ThisFrag = i * HorizFrags + j;
pbi.FragCoordinates[ ThisFrag ] =
new Coordinate(j * Constants.BLOCK_HEIGHT_WIDTH,
i * Constants.BLOCK_HEIGHT_WIDTH);
}
}
/* U */
HorizFrags >>= pbi.UVShiftX;
VertFrags >>= pbi.UVShiftY;
StartFrag = pbi.YPlaneFragments;
for(i = 0; i< VertFrags; i++) {
for(j = 0; j< HorizFrags; j++) {
int ThisFrag = StartFrag + i * HorizFrags + j;
pbi.FragCoordinates[ ThisFrag ] =
new Coordinate(j * Constants.BLOCK_HEIGHT_WIDTH,
i * Constants.BLOCK_HEIGHT_WIDTH);
}
}
/* V */
StartFrag = pbi.YPlaneFragments + pbi.UVPlaneFragments;
for(i = 0; i< VertFrags; i++) {
for(j = 0; j< HorizFrags; j++) {
int ThisFrag = StartFrag + i * HorizFrags + j;
pbi.FragCoordinates[ ThisFrag ] =
new Coordinate(j * Constants.BLOCK_HEIGHT_WIDTH,
i * Constants.BLOCK_HEIGHT_WIDTH);
}
}
}
static void CalcPixelIndexTable(Playback pbi){
int i, off;
int[] PixelIndexTablePtr;
/* Calculate the pixel index table for normal image buffers */
PixelIndexTablePtr = pbi.pixel_index_table;
for ( i = 0; i < pbi.YPlaneFragments; i++ ) {
PixelIndexTablePtr[ i ] =
((i / pbi.HFragments) * Constants.VFRAGPIXELS *
pbi.info.width);
PixelIndexTablePtr[ i ] +=
((i % pbi.HFragments) * Constants.HFRAGPIXELS);
}
off = pbi.YPlaneFragments;
for ( i = 0; i < ((pbi.HFragments >> pbi.UVShiftX) * pbi.VFragments); i++ ) {
PixelIndexTablePtr[ i + off] =
((i / (pbi.HFragments >> pbi.UVShiftX) ) *
(Constants.VFRAGPIXELS *
(pbi.info.width >> pbi.UVShiftX)) );
PixelIndexTablePtr[ i + off] +=
((i % (pbi.HFragments >> pbi.UVShiftX) ) *
Constants.HFRAGPIXELS) + pbi.YPlaneSize;
}
/************************************************************************/
/* Now calculate the pixel index table for image reconstruction buffers */
PixelIndexTablePtr = pbi.recon_pixel_index_table;
for ( i = 0; i < pbi.YPlaneFragments; i++ ){
PixelIndexTablePtr[ i ] =
((i / pbi.HFragments) * Constants.VFRAGPIXELS *
pbi.YStride);
PixelIndexTablePtr[ i ] +=
((i % pbi.HFragments) * Constants.HFRAGPIXELS) +
pbi.ReconYDataOffset;
}
/* U blocks */
off = pbi.YPlaneFragments;
for ( i = 0; i < pbi.UVPlaneFragments; i++ ) {
PixelIndexTablePtr[i+off] =
((i / (pbi.HFragments >> pbi.UVShiftX) ) *
(Constants.VFRAGPIXELS * (pbi.UVStride)) );
PixelIndexTablePtr[i+off] +=
((i % (pbi.HFragments >> pbi.UVShiftX) ) *
Constants.HFRAGPIXELS) + pbi.ReconUDataOffset;
}
/* V blocks */
off = pbi.YPlaneFragments + pbi.UVPlaneFragments;
for ( i = 0; i < pbi.UVPlaneFragments; i++ ) {
PixelIndexTablePtr[ i +off] =
((i / (pbi.HFragments >> pbi.UVShiftX) ) *
(Constants.VFRAGPIXELS * (pbi.UVStride)) );
PixelIndexTablePtr[ i +off] +=
((i % (pbi.HFragments >> pbi.UVShiftX) ) * Constants.HFRAGPIXELS) +
pbi.ReconVDataOffset;
}
}
static void ClearFragmentInfo(Playback pbi){
/* free prior allocs if present */
pbi.display_fragments = null;
pbi.pixel_index_table = null;
pbi.recon_pixel_index_table = null;
pbi.FragTokenCounts = null;
pbi.CodedBlockList = null;
pbi.FragMVect = null;
pbi.FragCoefEOB = null;
pbi.QFragData = null;
pbi.FragCodingMethod = null;
pbi.FragCoordinates = null;
pbi.FragQIndex = null;
pbi.BlockMap = null;
pbi.SBCodedFlags = null;
pbi.SBFullyFlags = null;
pbi.MBFullyFlags = null;
pbi.MBCodedFlags = null;
}
static void InitFragmentInfo(Playback pbi){
/* clear any existing info */
ClearFragmentInfo(pbi);
/* Perform Fragment Allocations */
pbi.display_fragments = new byte[pbi.UnitFragments];
pbi.pixel_index_table = new int[pbi.UnitFragments];
pbi.recon_pixel_index_table = new int[pbi.UnitFragments];
pbi.FragTokenCounts = new int[pbi.UnitFragments];
pbi.CodedBlockList = new int[pbi.UnitFragments];
pbi.FragMVect = new MotionVector[pbi.UnitFragments];
for (int i=0; i<pbi.UnitFragments; i++) {
pbi.FragMVect[i] = new MotionVector();
}
pbi.FragQs = new byte[pbi.UnitFragments];
pbi.FragCoefEOB = new byte[pbi.UnitFragments];
pbi.QFragData = new short[pbi.UnitFragments][64];
pbi.FragCodingMethod = new CodingMode[pbi.UnitFragments];
pbi.FragCoordinates = new Coordinate[pbi.UnitFragments];
pbi.FragQIndex = new int[pbi.UnitFragments];
/* Super Block Initialization */
pbi.SBCodedFlags = new byte[pbi.SuperBlocks];
pbi.SBFullyFlags = new byte[pbi.SuperBlocks];
/* Macro Block Initialization */
pbi.MBCodedFlags = new byte[pbi.MacroBlocks];
pbi.MBFullyFlags = new byte[pbi.MacroBlocks];
}
static void ClearFrameInfo(Playback pbi){
pbi.ThisFrameRecon = null;
pbi.GoldenFrame = null;
pbi.LastFrameRecon = null;
pbi.PostProcessBuffer = null;
}
static void InitFrameInfo(Playback pbi, int FrameSize){
/* clear any existing info */
ClearFrameInfo(pbi);
/* allocate frames */
pbi.ThisFrameRecon = new short[FrameSize];
pbi.GoldenFrame = new short[FrameSize];
pbi.LastFrameRecon = new short[FrameSize];
pbi.PostProcessBuffer = new short[FrameSize];
}
static void InitFrameDetails(Playback pbi){
int FrameSize, uv_fact;
/*pbi.PostProcessingLevel = 0;
pbi.PostProcessingLevel = 4;
pbi.PostProcessingLevel = 5;
pbi.PostProcessingLevel = 6;*/
pbi.PostProcessingLevel = 0;
pbi.UVShiftX = pbi.UVShiftY = 1;
if (pbi.info.pixel_fmt == PixelFormat.TH_PF_422)
pbi.UVShiftY = 0;
if (pbi.info.pixel_fmt == PixelFormat.TH_PF_444)
pbi.UVShiftX = pbi.UVShiftY = 0;
uv_fact = 1 << (pbi.UVShiftX + pbi.UVShiftY);
/* Set the frame size etc. */
pbi.YPlaneSize = pbi.info.width *
pbi.info.height;
pbi.UVPlaneSize = pbi.YPlaneSize / uv_fact;
pbi.HFragments = pbi.info.width / Constants.HFRAGPIXELS;
pbi.VFragments = pbi.info.height / Constants.VFRAGPIXELS;
pbi.YPlaneFragments = pbi.HFragments * pbi.VFragments;
pbi.UVPlaneFragments = pbi.YPlaneFragments / uv_fact;
pbi.UnitFragments = pbi.YPlaneFragments + 2*pbi.UVPlaneFragments;
pbi.YStride = (pbi.info.width + Constants.STRIDE_EXTRA);
pbi.UVStride = pbi.YStride >> pbi.UVShiftX;
pbi.ReconYPlaneSize = pbi.YStride *
(pbi.info.height + Constants.STRIDE_EXTRA);
pbi.ReconUVPlaneSize = pbi.ReconYPlaneSize / uv_fact;
FrameSize = pbi.ReconYPlaneSize + 2 * pbi.ReconUVPlaneSize;
pbi.YDataOffset = 0;
pbi.UDataOffset = pbi.YPlaneSize;
pbi.VDataOffset = pbi.YPlaneSize + pbi.UVPlaneSize;
pbi.ReconYDataOffset =
(pbi.YStride * Constants.UMV_BORDER) + Constants.UMV_BORDER;
pbi.ReconUDataOffset = pbi.ReconYPlaneSize +
(pbi.UVStride * (Constants.UMV_BORDER>>pbi.UVShiftY)) +
(Constants.UMV_BORDER>>pbi.UVShiftX);
pbi.ReconVDataOffset = pbi.ReconYPlaneSize + pbi.ReconUVPlaneSize +
(pbi.UVStride * (Constants.UMV_BORDER>>pbi.UVShiftY)) +
(Constants.UMV_BORDER>>pbi.UVShiftX);
/* Image dimensions in Super-Blocks */
pbi.YSBRows = (pbi.info.height/32) +
( pbi.info.height%32 !=0 ? 1 : 0 );
pbi.YSBCols = (pbi.info.width/32) +
( pbi.info.width%32 !=0 ? 1 : 0 );
pbi.UVSBRows = ((pbi.info.height>>pbi.UVShiftY)/32) +
( (pbi.info.height>>pbi.UVShiftY)%32 !=0 ? 1 : 0 );
pbi.UVSBCols = ((pbi.info.width>>pbi.UVShiftX)/32) +
( (pbi.info.width>>pbi.UVShiftX)%32 !=0 ? 1 : 0 );
/* Super-Blocks per component */
pbi.YSuperBlocks = pbi.YSBRows * pbi.YSBCols;
pbi.UVSuperBlocks = pbi.UVSBRows * pbi.UVSBCols;
pbi.SuperBlocks = pbi.YSuperBlocks+2*pbi.UVSuperBlocks;
/* Useful externals */
pbi.YMacroBlocks = ((pbi.VFragments+1)/2)*((pbi.HFragments+1)/2);
pbi.UVMacroBlocks =
(((pbi.VFragments>>pbi.UVShiftY)+1)/2)*(((pbi.HFragments>>pbi.UVShiftX)+1)/2);
pbi.MacroBlocks = pbi.YMacroBlocks+2*pbi.UVMacroBlocks;
InitFragmentInfo(pbi);
InitFrameInfo(pbi, FrameSize);
InitializeFragCoordinates(pbi);
/* Configure mapping between quad-tree and fragments */
pbi.BlockMap = new BlockMapping (pbi.YSuperBlocks,
pbi.UVSuperBlocks, pbi.HFragments, pbi.VFragments,
pbi.UVShiftX, pbi.UVShiftY);
/* Re-initialise the pixel index table. */
CalcPixelIndexTable( pbi );
}
}

View File

@@ -0,0 +1,83 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
public class HuffEntry
{
HuffEntry[] Child = new HuffEntry[2];
HuffEntry previous;
HuffEntry next;
int value;
int frequency;
public HuffEntry copy()
{
HuffEntry huffDst;
huffDst = new HuffEntry();
huffDst.value = value;
if (value < 0) {
huffDst.Child[0] = Child[0].copy();
huffDst.Child[1] = Child[1].copy();
}
return huffDst;
}
public int read(int depth, OggBuffer opb)
{
int bit;
int ret;
bit = opb.readB(1);
if(bit < 0) {
return Result.BADHEADER;
}
else if(bit == 0) {
if (++depth > 32)
return Result.BADHEADER;
Child[0] = new HuffEntry();
ret = Child[0].read(depth, opb);
if (ret < 0)
return ret;
Child[1] = new HuffEntry();
ret = Child[1].read(depth, opb);
if (ret < 0)
return ret;
value = -1;
}
else {
Child[0] = null;
Child[1] = null;
value = opb.readB(5);
if (value < 0)
return Result.BADHEADER;
}
return 0;
}
}

View File

@@ -0,0 +1,538 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public class HuffTables
{
static final byte[] ExtraBitLengths_VP31 = {
0, 0, 0, 2, 3, 4, 12,3, 6, /* EOB and Zero-run tokens. */
0, 0, 0, 0, /* Very low value tokens. */
1, 1, 1, 1, 2, 3, 4, 5, 6, 10, /* Other value tokens */
1, 1, 1, 1, 1, 3, 4, /* Category 1 runs. */
2, 3, /* Category 2 runs. */
};
static final short[][] FrequencyCounts_VP3 = {
/* DC Intra bias */
{ 198, 62, 22, 31, 14, 6, 6, 205, 3,
843, 843, 415, 516,
660, 509, 412, 347, 560, 779, 941, 930, 661, 377,
170, 155, 39, 2, 9, 15, 11,
128, 86,
},
{ 299, 92, 34, 39, 15, 6, 6, 132, 1,
851, 851, 484, 485,
666, 514, 416, 351, 567, 788, 953, 943, 670, 383,
117, 119, 26, 4, 17, 7, 1,
93, 56,
},
{ 367, 115, 42, 47, 16, 6, 6, 105, 1,
896, 896, 492, 493,
667, 510, 408, 342, 547, 760, 932, 927, 656, 379,
114, 103, 10, 3, 6, 2, 1,
88, 49,
},
{ 462, 158, 63, 76, 28, 9, 8, 145, 1,
1140, 1140, 573, 574,
754, 562, 435, 357, 555, 742, 793, 588, 274, 81,
154, 117, 13, 6, 12, 2, 1,
104, 62,
},
{ 558, 196, 81, 99, 36, 11, 9, 135, 1,
1300, 1301, 606, 607,
779, 560, 429, 349, 536, 680, 644, 405, 153, 30,
171, 120, 12, 5, 14, 3, 1,
104, 53,
},
{ 635, 233, 100, 122, 46, 14, 12, 113, 1,
1414, 1415, 631, 631,
785, 555, 432, 335, 513, 611, 521, 284, 89, 13,
170, 113, 10, 5, 14, 3, 1,
102, 62,
},
{ 720, 276, 119, 154, 62, 20, 16, 101, 1,
1583, 1583, 661, 661,
794, 556, 407, 318, 447, 472, 343, 153, 35, 1,
172, 115, 11, 7, 14, 3, 1,
112, 70,
},
{ 853, 326, 144, 184, 80, 27, 19, 52, 1,
1739, 1740, 684, 685,
800, 540, 381, 277, 364, 352, 218, 78, 13, 1,
139, 109, 9, 6, 20, 2, 1,
94, 50,
},
/* DC Inter Bias */
{ 490, 154, 57, 53, 10, 2, 1, 238, 160,
1391, 1390, 579, 578,
491, 273, 172, 118, 152, 156, 127, 79, 41, 39,
712, 547, 316, 125, 183, 306, 237,
451, 358,
},
{ 566, 184, 70, 65, 11, 2, 1, 235, 51,
1414, 1414, 599, 598,
510, 285, 180, 124, 157, 161, 131, 82, 42, 40,
738, 551, 322, 138, 195, 188, 93,
473, 365,
},
{ 711, 261, 111, 126, 27, 4, 1, 137, 52,
1506, 1505, 645, 645,
567, 316, 199, 136, 172, 175, 142, 88, 45, 48,
548, 449, 255, 145, 184, 174, 121,
260, 227,
},
{ 823, 319, 144, 175, 43, 7, 1, 53, 42,
1648, 1648, 653, 652,
583, 329, 205, 139, 175, 176, 139, 84, 44, 34,
467, 389, 211, 137, 181, 186, 107,
106, 85,
},
{ 948, 411, 201, 276, 85, 16, 2, 39, 33,
1778, 1777, 584, 583,
489, 265, 162, 111, 140, 140, 108, 64, 38, 23,
428, 356, 201, 139, 186, 165, 94,
78, 63,
},
{ 1002, 470, 248, 386, 153, 39, 6, 23, 23,
1866, 1866, 573, 573,
467, 249, 155, 103, 130, 128, 94, 60, 38, 14,
323, 263, 159, 111, 156, 153, 74,
46, 34,
},
{ 1020, 518, 291, 504, 242, 78, 18, 14, 14,
1980, 1979, 527, 526,
408, 219, 132, 87, 110, 104, 79, 55, 31, 7,
265, 213, 129, 91, 131, 111, 50,
31, 20,
},
{ 1018, 544, 320, 591, 338, 139, 47, 5, 2,
2123, 2123, 548, 547,
414, 212, 126, 83, 101, 96, 79, 60, 23, 1,
120, 97, 55, 39, 60, 38, 15,
11, 8,
},
/* AC INTRA Tables */
/* AC Intra bias group 1 tables */
{ 242, 62, 22, 20, 4, 1, 1, 438, 1,
593, 593, 489, 490,
657, 580, 471, 374, 599, 783, 869, 770, 491, 279,
358, 144, 82, 54, 49, 70, 5,
289, 107,
},
{ 317, 95, 38, 41, 8, 1, 1, 479, 1,
653, 654, 500, 501,
682, 611, 473, 376, 582, 762, 806, 656, 358, 155,
419, 162, 86, 58, 36, 34, 1,
315, 126,
},
{ 382, 121, 49, 59, 15, 3, 1, 496, 1,
674, 674, 553, 554,
755, 636, 487, 391, 576, 718, 701, 488, 221, 72,
448, 161, 107, 56, 37, 29, 1,
362, 156,
},
{ 415, 138, 57, 73, 21, 5, 1, 528, 1,
742, 741, 562, 563,
753, 669, 492, 388, 563, 664, 589, 340, 129, 26,
496, 184, 139, 71, 48, 33, 2,
387, 166,
},
{ 496, 170, 73, 94, 31, 8, 2, 513, 1,
855, 855, 604, 604,
769, 662, 477, 356, 486, 526, 381, 183, 51, 5,
590, 214, 160, 85, 60, 39, 3,
427, 203,
},
{ 589, 207, 89, 116, 40, 13, 3, 491, 1,
919, 919, 631, 631,
769, 633, 432, 308, 408, 378, 247, 94, 17, 1,
659, 247, 201, 105, 73, 51, 3,
466, 242,
},
{ 727, 266, 115, 151, 49, 17, 6, 439, 1,
977, 977, 642, 642,
718, 572, 379, 243, 285, 251, 133, 40, 1, 1,
756, 287, 253, 126, 94, 66, 4,
492, 280,
},
{ 940, 392, 180, 247, 82, 30, 14, 343, 1,
1064, 1064, 615, 616,
596, 414, 235, 146, 149, 108, 41, 1, 1, 1,
882, 314, 346, 172, 125, 83, 6,
489, 291,
},
/* AC Inter bias group 1 tables */
{ 440, 102, 33, 23, 2, 1, 1, 465, 85,
852, 852, 744, 743,
701, 496, 297, 193, 225, 200, 129, 58, 18, 2,
798, 450, 269, 202, 145, 308, 154,
646, 389,
},
{ 592, 151, 53, 43, 6, 1, 1, 409, 34,
875, 875, 748, 747,
723, 510, 305, 196, 229, 201, 130, 59, 18, 2,
800, 436, 253, 185, 115, 194, 88,
642, 368,
},
{ 759, 222, 86, 85, 17, 2, 1, 376, 46,
888, 888, 689, 688,
578, 408, 228, 143, 165, 141, 84, 35, 7, 1,
878, 488, 321, 244, 147, 266, 124,
612, 367,
},
{ 912, 298, 122, 133, 34, 7, 1, 261, 44,
1092, 1091, 496, 496,
409, 269, 150, 95, 106, 87, 49, 16, 1, 1,
1102, 602, 428, 335, 193, 323, 157,
423, 253,
},
{ 1072, 400, 180, 210, 60, 16, 3, 210, 40,
1063, 1063, 451, 451,
345, 221, 121, 73, 79, 64, 31, 6, 1, 1,
1105, 608, 462, 358, 202, 330, 155,
377, 228,
},
{ 1164, 503, 254, 330, 109, 34, 9, 167, 35,
1038, 1037, 390, 390,
278, 170, 89, 54, 56, 40, 13, 1, 1, 1,
1110, 607, 492, 401, 218, 343, 141,
323, 192,
},
{ 1173, 583, 321, 486, 196, 68, 23, 124, 23,
1037, 1037, 347, 346,
232, 139, 69, 40, 37, 20, 2, 1, 1, 1,
1128, 584, 506, 410, 199, 301, 113,
283, 159,
},
{ 1023, 591, 366, 699, 441, 228, 113, 79, 5,
1056, 1056, 291, 291,
173, 96, 38, 19, 8, 1, 1, 1, 1, 1,
1187, 527, 498, 409, 147, 210, 56,
263, 117,
},
/* AC Intra bias group 2 tables */
{ 311, 74, 27, 27, 5, 1, 1, 470, 24,
665, 667, 637, 638,
806, 687, 524, 402, 585, 679, 609, 364, 127, 20,
448, 210, 131, 76, 52, 111, 19,
393, 195,
},
{ 416, 104, 39, 38, 8, 1, 1, 545, 33,
730, 731, 692, 692,
866, 705, 501, 365, 495, 512, 387, 168, 39, 2,
517, 240, 154, 86, 64, 127, 19,
461, 247,
},
{ 474, 117, 43, 42, 9, 1, 1, 560, 40,
783, 783, 759, 760,
883, 698, 466, 318, 404, 377, 215, 66, 7, 1,
559, 259, 176, 110, 87, 170, 22,
520, 278,
},
{ 582, 149, 53, 53, 12, 2, 1, 473, 39,
992, 993, 712, 713,
792, 593, 373, 257, 299, 237, 114, 25, 1, 1,
710, 329, 221, 143, 116, 226, 26,
490, 259,
},
{ 744, 210, 78, 77, 16, 2, 1, 417, 37,
1034, 1035, 728, 728,
718, 509, 296, 175, 184, 122, 42, 3, 1, 1,
791, 363, 255, 168, 145, 311, 35,
492, 272,
},
{ 913, 291, 121, 128, 28, 4, 1, 334, 40,
1083, 1084, 711, 712,
624, 378, 191, 107, 95, 50, 7, 1, 1, 1,
876, 414, 288, 180, 164, 382, 39,
469, 275,
},
{ 1065, 405, 184, 216, 53, 8, 1, 236, 36,
1134, 1134, 685, 686,
465, 253, 113, 48, 41, 9, 1, 1, 1, 1,
965, 451, 309, 179, 166, 429, 53,
414, 249,
},
{ 1148, 548, 301, 438, 160, 42, 6, 84, 17,
1222, 1223, 574, 575,
272, 111, 23, 6, 2, 1, 1, 1, 1, 1,
1060, 502, 328, 159, 144, 501, 54,
302, 183,
},
/* AC Inter bias group 2 tables */
{ 403, 80, 24, 17, 1, 1, 1, 480, 90,
899, 899, 820, 819,
667, 413, 228, 133, 139, 98, 42, 10, 1, 1,
865, 470, 316, 222, 171, 419, 213,
645, 400,
},
{ 698, 169, 59, 49, 6, 1, 1, 414, 101,
894, 893, 761, 761,
561, 338, 171, 96, 97, 64, 26, 6, 1, 1,
896, 494, 343, 239, 192, 493, 215,
583, 366,
},
{ 914, 255, 94, 80, 10, 1, 1, 345, 128,
935, 935, 670, 671,
415, 222, 105, 55, 51, 30, 10, 1, 1, 1,
954, 530, 377, 274, 232, 641, 295,
456, 298,
},
{ 1103, 359, 146, 135, 20, 1, 1, 235, 119,
1042, 1042, 508, 507,
293, 146, 65, 33, 30, 16, 4, 1, 1, 1,
1031, 561, 407, 296, 265, 813, 317,
301, 192,
},
{ 1255, 504, 238, 265, 51, 5, 1, 185, 113,
1013, 1013, 437, 438,
212, 92, 41, 18, 15, 6, 1, 1, 1, 1,
976, 530, 386, 276, 260, 927, 357,
224, 148,
},
{ 1292, 610, 332, 460, 127, 16, 1, 136, 99,
1014, 1015, 384, 384,
153, 65, 25, 11, 6, 1, 1, 1, 1, 1,
942, 487, 343, 241, 238, 970, 358,
174, 103,
},
{ 1219, 655, 407, 700, 280, 55, 2, 100, 60,
1029, 1029, 337, 336,
119, 43, 11, 3, 2, 1, 1, 1, 1, 1,
894, 448, 305, 199, 213, 1005, 320,
136, 77,
},
{ 1099, 675, 435, 971, 581, 168, 12, 37, 16,
1181, 1081, 319, 318,
66, 11, 6, 1, 1, 1, 1, 1, 1, 1,
914, 370, 235, 138, 145, 949, 128,
94, 41,
},
/* AC Intra bias group 3 tables */
{ 486, 112, 39, 34, 6, 1, 1, 541, 67,
819, 818, 762, 763,
813, 643, 403, 280, 332, 295, 164, 53, 6, 1,
632, 294, 180, 131, 105, 208, 109,
594, 295,
},
{ 723, 191, 69, 65, 12, 1, 1, 445, 79,
865, 865, 816, 816,
750, 515, 290, 172, 184, 122, 46, 5, 1, 1,
740, 340, 213, 165, 129, 270, 168,
603, 326,
},
{ 884, 264, 102, 103, 21, 3, 1, 382, 68,
897, 897, 836, 836,
684, 427, 227, 119, 119, 70, 16, 1, 1, 1,
771, 367, 234, 184, 143, 272, 178,
555, 326,
},
{ 1028, 347, 153, 161, 36, 8, 1, 251, 44,
1083, 1084, 735, 735,
541, 289, 144, 77, 57, 23, 3, 1, 1, 1,
926, 422, 270, 215, 176, 301, 183,
443, 248,
},
{ 1155, 465, 224, 264, 71, 14, 3, 174, 27,
1110, 1111, 730, 731,
429, 206, 79, 30, 19, 4, 1, 1, 1, 1,
929, 443, 279, 225, 194, 298, 196,
354, 223,
},
{ 1191, 576, 296, 415, 144, 36, 8, 114, 16,
1162, 1162, 749, 749,
338, 108, 29, 8, 5, 1, 1, 1, 1, 1,
947, 458, 273, 207, 194, 248, 145,
258, 152,
},
{ 1169, 619, 366, 603, 247, 92, 23, 46, 1,
1236, 1236, 774, 775,
191, 35, 14, 1, 1, 1, 1, 1, 1, 1,
913, 449, 260, 214, 194, 180, 82,
174, 98,
},
{ 1006, 537, 381, 897, 504, 266, 101, 39, 1,
1307, 1307, 668, 667,
116, 3, 1, 1, 1, 1, 1, 1, 1, 1,
1175, 261, 295, 70, 164, 107, 31,
10, 76,
},
/* AC Inter bias group 3 tables */
{ 652, 156, 53, 43, 5, 1, 1, 368, 128,
983, 984, 825, 825,
583, 331, 163, 88, 84, 48, 15, 1, 1, 1,
870, 480, 316, 228, 179, 421, 244,
562, 349,
},
{ 988, 280, 104, 87, 12, 1, 1, 282, 194,
980, 981, 738, 739,
395, 189, 80, 37, 31, 12, 2, 1, 1, 1,
862, 489, 333, 262, 214, 600, 446,
390, 260,
},
{ 1176, 399, 165, 154, 24, 2, 1, 218, 224,
1017, 1018, 651, 651,
280, 111, 42, 16, 9, 3, 1, 1, 1, 1,
787, 469, 324, 269, 229, 686, 603,
267, 194,
},
{ 1319, 530, 255, 268, 47, 4, 1, 113, 183,
1149, 1150, 461, 461,
173, 58, 17, 5, 3, 1, 1, 1, 1, 1,
768, 450, 305, 261, 221, 716, 835,
136, 97,
},
{ 1362, 669, 355, 465, 104, 9, 1, 76, 153,
1253, 1253, 398, 397,
102, 21, 5, 1, 1, 1, 1, 1, 1, 1,
596, 371, 238, 228, 196, 660, 954,
68, 53,
},
{ 1354, 741, 446, 702, 174, 15, 1, 38, 87,
1498, 1498, 294, 294,
43, 7, 1, 1, 1, 1, 1, 1, 1, 1,
381, 283, 165, 181, 155, 544, 1039,
25, 21,
},
{ 1262, 885, 546, 947, 263, 18, 1, 18, 27,
1908, 1908, 163, 162,
14, 1, 1, 1, 1, 1, 1, 1, 1, 1,
195, 152, 83, 125, 109, 361, 827,
7, 5,
},
{ 2539, 951, 369, 554, 212, 18, 1, 1, 1,
2290, 2289, 64, 64,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
18, 18, 9, 55, 36, 184, 323,
1, 1,
},
/* AC Intra bias group 4 tables */
{ 921, 264, 101, 100, 19, 2, 1, 331, 98,
1015, 1016, 799, 799,
512, 269, 119, 60, 50, 17, 1, 1, 1, 1,
841, 442, 307, 222, 182, 493, 256,
438, 310,
},
{ 1147, 412, 184, 206, 50, 6, 1, 242, 141,
977, 976, 808, 807,
377, 135, 40, 10, 7, 1, 1, 1, 1, 1,
788, 402, 308, 223, 205, 584, 406,
316, 227,
},
{ 1243, 504, 238, 310, 79, 11, 1, 184, 150,
983, 984, 814, 813,
285, 56, 10, 1, 1, 1, 1, 1, 1, 1,
713, 377, 287, 217, 180, 615, 558,
208, 164,
},
{ 1266, 606, 329, 484, 161, 27, 1, 79, 92,
1187, 1188, 589, 588,
103, 10, 1, 1, 1, 1, 1, 1, 1, 1,
680, 371, 278, 221, 244, 614, 728,
80, 62,
},
{ 1126, 828, 435, 705, 443, 90, 8, 10, 55,
1220, 1219, 350, 350,
28, 1, 1, 1, 1, 1, 1, 1, 1, 1,
602, 330, 222, 168, 158, 612, 919,
104, 5,
},
{ 1210, 506, 1014, 926, 474, 240, 4, 1, 44,
1801, 1801, 171, 171,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
900, 132, 36, 11, 47, 191, 316,
2, 1,
},
{ 1210, 506, 1014, 926, 474, 240, 4, 1, 44,
1801, 1801, 171, 171,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
900, 132, 36, 11, 47, 191, 316,
2, 1,
},
{ 1210, 506, 1014, 926, 474, 240, 4, 1, 44,
1801, 1801, 171, 171,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
900, 132, 36, 11, 47, 191, 316,
2, 1,
},
/* AC Inter bias group 4 tables */
{ 1064, 325, 129, 117, 20, 2, 1, 266, 121,
1000, 1000, 706, 706,
348, 162, 67, 32, 25, 11, 1, 1, 1, 1,
876, 513, 363, 274, 225, 627, 384,
370, 251,
},
{ 1311, 517, 238, 254, 45, 3, 1, 188, 160,
1070, 1070, 635, 635,
239, 85, 30, 11, 6, 1, 1, 1, 1, 1,
744, 420, 313, 239, 206, 649, 541,
221, 155,
},
{ 1394, 632, 322, 385, 78, 7, 1, 134, 152,
1163, 1164, 607, 607,
185, 51, 12, 3, 1, 1, 1, 1, 1, 1,
631, 331, 275, 203, 182, 604, 620,
146, 98,
},
{ 1410, 727, 407, 546, 146, 19, 1, 67, 88,
1485, 1486, 419, 418,
103, 18, 3, 1, 1, 1, 1, 1, 1, 1,
555, 261, 234, 164, 148, 522, 654,
67, 39,
},
{ 1423, 822, 492, 719, 216, 22, 1, 28, 59,
1793, 1793, 323, 324,
37, 2, 1, 1, 1, 1, 1, 1, 1, 1,
376, 138, 158, 102, 119, 400, 604,
28, 9,
},
{ 1585, 923, 563, 918, 207, 25, 1, 5, 20,
2229, 2230, 172, 172,
7, 1, 1, 1, 1, 1, 1, 1, 1, 1,
191, 40, 56, 22, 65, 243, 312,
2, 1,
},
{ 2225, 1100, 408, 608, 133, 8, 1, 1, 1,
2658, 2658, 25, 24,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8, 1, 1, 1, 1, 125, 16,
1, 1,
},
{ 2539, 951, 369, 554, 212, 18, 1, 1, 1,
2290, 2289, 64, 64,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
18, 18, 9, 55, 36, 184, 323,
1, 1,
},
};
}

View File

@@ -0,0 +1,260 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
public class Huffman
{
public static final int NUM_HUFF_TABLES = 80;
public static final int DC_HUFF_OFFSET = 0;
public static final int AC_HUFF_OFFSET = 16;
public static final int AC_TABLE_2_THRESH = 5;
public static final int AC_TABLE_3_THRESH = 14;
public static final int AC_TABLE_4_THRESH = 27;
public static final int DC_HUFF_CHOICES = 16;
public static final int DC_HUFF_CHOICE_BITS = 4;
public static final int AC_HUFF_CHOICES = 16;
public static final int AC_HUFF_CHOICE_BITS = 4;
/* Constants assosciated with entropy tokenisation. */
public static final int MAX_SINGLE_TOKEN_VALUE = 6;
public static final int DCT_VAL_CAT2_MIN = 3;
public static final int DCT_VAL_CAT3_MIN = 7;
public static final int DCT_VAL_CAT4_MIN = 9;
public static final int DCT_VAL_CAT5_MIN = 13;
public static final int DCT_VAL_CAT6_MIN = 21;
public static final int DCT_VAL_CAT7_MIN = 37;
public static final int DCT_VAL_CAT8_MIN = 69;
public static final int DCT_EOB_TOKEN = 0;
public static final int DCT_EOB_PAIR_TOKEN = 1;
public static final int DCT_EOB_TRIPLE_TOKEN = 2;
public static final int DCT_REPEAT_RUN_TOKEN = 3;
public static final int DCT_REPEAT_RUN2_TOKEN = 4;
public static final int DCT_REPEAT_RUN3_TOKEN = 5;
public static final int DCT_REPEAT_RUN4_TOKEN = 6;
public static final int DCT_SHORT_ZRL_TOKEN = 7;
public static final int DCT_ZRL_TOKEN = 8;
public static final int ONE_TOKEN = 9; /* Special tokens for -1,1,-2,2 */
public static final int MINUS_ONE_TOKEN = 10;
public static final int TWO_TOKEN = 11;
public static final int MINUS_TWO_TOKEN = 12;
public static final int LOW_VAL_TOKENS = (MINUS_TWO_TOKEN + 1);
public static final int DCT_VAL_CATEGORY3 = (LOW_VAL_TOKENS + 4);
public static final int DCT_VAL_CATEGORY4 = (DCT_VAL_CATEGORY3 + 1);
public static final int DCT_VAL_CATEGORY5 = (DCT_VAL_CATEGORY4 + 1);
public static final int DCT_VAL_CATEGORY6 = (DCT_VAL_CATEGORY5 + 1);
public static final int DCT_VAL_CATEGORY7 = (DCT_VAL_CATEGORY6 + 1);
public static final int DCT_VAL_CATEGORY8 = (DCT_VAL_CATEGORY7 + 1);
public static final int DCT_RUN_CATEGORY1 = (DCT_VAL_CATEGORY8 + 1);
public static final int DCT_RUN_CATEGORY1B = (DCT_RUN_CATEGORY1 + 5);
public static final int DCT_RUN_CATEGORY1C = (DCT_RUN_CATEGORY1B + 1);
public static final int DCT_RUN_CATEGORY2 = (DCT_RUN_CATEGORY1C + 1);
/* 32 */
public static final int MAX_ENTROPY_TOKENS = (DCT_RUN_CATEGORY2 + 2);
private static void createHuffmanList (HuffEntry[] huffRoot,
int hIndex, short[] freqList) {
HuffEntry entry_ptr;
HuffEntry search_ptr;
/* Create a HUFF entry for token zero. */
huffRoot[hIndex] = new HuffEntry();
huffRoot[hIndex].previous = null;
huffRoot[hIndex].next = null;
huffRoot[hIndex].Child[0] = null;
huffRoot[hIndex].Child[1] = null;
huffRoot[hIndex].value = 0;
huffRoot[hIndex].frequency = freqList[0];
if ( huffRoot[hIndex].frequency == 0 )
huffRoot[hIndex].frequency = 1;
/* Now add entries for all the other possible tokens. */
for (int i = 1; i < Huffman.MAX_ENTROPY_TOKENS; i++) {
entry_ptr = new HuffEntry();
entry_ptr.value = i;
entry_ptr.frequency = freqList[i];
entry_ptr.Child[0] = null;
entry_ptr.Child[1] = null;
/* Force min value of 1. This prevents the tree getting too deep. */
if ( entry_ptr.frequency == 0 )
entry_ptr.frequency = 1;
if ( entry_ptr.frequency <= huffRoot[hIndex].frequency ){
entry_ptr.next = huffRoot[hIndex];
huffRoot[hIndex].previous = entry_ptr;
entry_ptr.previous = null;
huffRoot[hIndex] = entry_ptr;
}
else
{
search_ptr = huffRoot[hIndex];
while ( (search_ptr.next != null) &&
(search_ptr.frequency < entry_ptr.frequency) ){
search_ptr = search_ptr.next;
}
if ( search_ptr.frequency < entry_ptr.frequency ){
entry_ptr.next = null;
entry_ptr.previous = search_ptr;
search_ptr.next = entry_ptr;
}
else
{
entry_ptr.next = search_ptr;
entry_ptr.previous = search_ptr.previous;
search_ptr.previous.next = entry_ptr;
search_ptr.previous = entry_ptr;
}
}
}
}
private static void createCodeArray (HuffEntry huffRoot,
int[] huffCodeArray,
byte[] huffCodeLengthArray,
int codeValue,
byte codeLength)
{
/* If we are at a leaf then fill in a code array entry. */
if ((huffRoot.Child[0] == null) && (huffRoot.Child[1] == null)) {
huffCodeArray[huffRoot.value] = codeValue;
huffCodeLengthArray[huffRoot.value] = codeLength;
} else {
/* Recursive calls to scan down the tree. */
codeLength++;
createCodeArray(huffRoot.Child[0], huffCodeArray, huffCodeLengthArray,
((codeValue << 1) + 0), codeLength);
createCodeArray(huffRoot.Child[1], huffCodeArray, huffCodeLengthArray,
((codeValue << 1) + 1), codeLength);
}
}
public static void buildHuffmanTree (HuffEntry[] huffRoot,
int[] huffCodeArray,
byte[] huffCodeLengthArray,
int hIndex,
short[] freqList )
{
HuffEntry entry_ptr;
HuffEntry search_ptr;
/* First create a sorted linked list representing the frequencies of
each token. */
createHuffmanList( huffRoot, hIndex, freqList );
/* Now build the tree from the list. */
/* While there are at least two items left in the list. */
while ( huffRoot[hIndex].next != null ){
/* Create the new node as the parent of the first two in the list. */
entry_ptr = new HuffEntry();
entry_ptr.value = -1;
entry_ptr.frequency = huffRoot[hIndex].frequency +
huffRoot[hIndex].next.frequency ;
entry_ptr.Child[0] = huffRoot[hIndex];
entry_ptr.Child[1] = huffRoot[hIndex].next;
/* If there are still more items in the list then insert the new
node into the list. */
if (entry_ptr.Child[1].next != null ){
/* Set up the provisional 'new root' */
huffRoot[hIndex] = entry_ptr.Child[1].next;
huffRoot[hIndex].previous = null;
/* Now scan through the remaining list to insert the new entry
at the appropriate point. */
if ( entry_ptr.frequency <= huffRoot[hIndex].frequency ){
entry_ptr.next = huffRoot[hIndex];
huffRoot[hIndex].previous = entry_ptr;
entry_ptr.previous = null;
huffRoot[hIndex] = entry_ptr;
}else{
search_ptr = huffRoot[hIndex];
while ( (search_ptr.next != null) &&
(search_ptr.frequency < entry_ptr.frequency) ){
search_ptr = search_ptr.next;
}
if ( search_ptr.frequency < entry_ptr.frequency ){
entry_ptr.next = null;
entry_ptr.previous = search_ptr;
search_ptr.next = entry_ptr;
}else{
entry_ptr.next = search_ptr;
entry_ptr.previous = search_ptr.previous;
search_ptr.previous.next = entry_ptr;
search_ptr.previous = entry_ptr;
}
}
}else{
/* Build has finished. */
entry_ptr.next = null;
entry_ptr.previous = null;
huffRoot[hIndex] = entry_ptr;
}
/* Delete the next/previous properties of the children (PROB NOT NEC). */
entry_ptr.Child[0].next = null;
entry_ptr.Child[0].previous = null;
entry_ptr.Child[1].next = null;
entry_ptr.Child[1].previous = null;
}
/* Now build a code array from the tree. */
createCodeArray( huffRoot[hIndex], huffCodeArray,
huffCodeLengthArray, 0, (byte)0);
}
public static int readHuffmanTrees(HuffEntry[] huffRoot, OggBuffer opb) {
int i;
for (i=0; i<NUM_HUFF_TABLES; i++) {
int ret;
huffRoot[i] = new HuffEntry();
ret = huffRoot[i].read(0, opb);
if (ret != 0)
return ret;
}
return 0;
}
public static void clearHuffmanTrees(HuffEntry[] huffRoot){
int i;
for(i=0; i<Huffman.NUM_HUFF_TABLES; i++) {
huffRoot[i] = null;
}
}
}

View File

@@ -0,0 +1,42 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public class JTheoraException extends Exception {
private static final long serialVersionUID = 1L;
private int error;
public JTheoraException() {
super();
}
public JTheoraException(String str, int error) {
super(str);
this.error = error;
}
public int getErrorCode() {
return error;
}
}

View File

@@ -0,0 +1,116 @@
/* Cortado - a video player java applet
* Copyright (C) 2004 Fluendo S.L.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public class MemUtils {
private static final char[] bytes = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
public static final int cmp (byte[] mem1, byte[] mem2, int len)
{
for (int i=0; i<len; i++) {
if (mem1[i] != mem2[i]) {
if (mem1[i] < mem2[i])
return -i;
else
return i;
}
}
return 0;
}
public static final void set (byte[] mem, int offset, int val, int len)
{
len += offset;
for (int i=offset; i<len; i++) {
mem[i] = (byte)val;
}
}
public static final void set (short[] mem, int offset, int val, int len)
{
len += offset;
for (int i=offset; i<len; i++) {
mem[i] = (short)val;
}
}
public static final void set (int[] mem, int offset, int val, int len)
{
len += offset;
for (int i=offset; i<len; i++) {
mem[i] = (int)val;
}
}
public static final void set (Object[] mem, int offset, Object val, int len)
{
len += offset;
for (int i=offset; i<len; i++) {
mem[i] = val;
}
}
/* check if a given arr starts with the given pattern */
public static final boolean startsWith (byte[] arr, int offset, int len, byte[] pattern)
{
int length = pattern.length;
int i;
if (len < length)
return false;
for (i=0; i < length; i++)
if (arr[offset+i] != pattern[i])
break;
return i == length;
}
public static final void dump (byte[] mem, int start, int len)
{
int i, j;
StringBuffer string = new StringBuffer(50);
StringBuffer chars = new StringBuffer(18);
String vis = new String (mem, start, len);
i = j = 0;
while (i < len) {
int b = ((int)mem[i+start]); if (b<0) b+=256;
if (b > 0x20 && b < 0x7f)
chars.append (vis.charAt(i));
else
chars.append (".");
string.append (bytes[b/16]);
string.append (bytes[b%16]);
string.append (" ");
j++;
i++;
if (j == 16 || i == len) {
System.out.println ("" + (i-j) + " "+ string.toString() + chars.toString());
string.setLength(0);
chars.setLength(0);
j = 0;
}
}
}
}

View File

@@ -0,0 +1,37 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public class MotionVector extends Coordinate
{
public static final MotionVector NULL = new MotionVector (0,0);
public MotionVector () {
super();
}
public MotionVector (int x, int y) {
super(x,y);
}
}

View File

@@ -0,0 +1,42 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public class PixelFormat {
public static final PixelFormat TH_PF_420 = new PixelFormat ();
public static final PixelFormat TH_PF_RSVD = new PixelFormat();
public static final PixelFormat TH_PF_422 = new PixelFormat ();
public static final PixelFormat TH_PF_444 = new PixelFormat ();
public static final PixelFormat[] formats = {
TH_PF_420,
TH_PF_RSVD,
TH_PF_422,
TH_PF_444
};
private PixelFormat() {
}
}

View File

@@ -0,0 +1,271 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
public class Playback
{
/* Different key frame types/methods */
private static final int DCT_KEY_FRAME = 0;
//oggpack_buffer *opb;
OggBuffer opb = new OggBuffer();;
TheoraInfo info;
/* how far do we shift the granulepos to seperate out P frame counts? */
int keyframe_granule_shift;
/***********************************************************************/
/* Decoder and Frame Type Information */
int DecoderErrorCode;
int FramesHaveBeenSkipped;
int PostProcessEnabled;
int PostProcessingLevel; /* Perform post processing */
/* Frame Info */
byte FrameType;
byte KeyFrameType;
int QualitySetting;
int FrameQIndex; /* Quality specified as a
table index */
//int ThisFrameQualityValue; /* Quality value for this frame */
//int LastFrameQualityValue; /* Last Frame's Quality */
int CodedBlockIndex; /* Number of Coded Blocks */
int CodedBlocksThisFrame; /* Index into coded blocks */
int FrameSize; /* The number of bytes in the frame. */
int[] frameQIS = new int[3];
int frameNQIS; /* number of quality indices this frame uses */
/**********************************************************************/
/* Frame Size & Index Information */
int YPlaneSize;
int UVPlaneSize;
int YStride;
int UVStride;
int VFragments;
int HFragments;
int UnitFragments;
int YPlaneFragments;
int UVPlaneFragments;
int UVShiftX; /* 1 unless Info.pixel_fmt == TH_PF_444 */
int UVShiftY; /* 0 unless Info.pixel_fmt == TH_PF_420 */
int ReconYPlaneSize;
int ReconUVPlaneSize;
int YDataOffset;
int UDataOffset;
int VDataOffset;
int ReconYDataOffset;
int ReconUDataOffset;
int ReconVDataOffset;
int YSuperBlocks; /* Number of SuperBlocks in a Y frame */
int UVSuperBlocks; /* Number of SuperBlocks in a U or V frame */
int SuperBlocks; /* Total number of SuperBlocks in a
Y,U,V frame */
int YSBRows; /* Number of rows of SuperBlocks in a
Y frame */
int YSBCols; /* Number of cols of SuperBlocks in a
Y frame */
int UVSBRows; /* Number of rows of SuperBlocks in a
U or V frame */
int UVSBCols; /* Number of cols of SuperBlocks in a
U or V frame */
int YMacroBlocks; /* Number of Macro-Blocks in Y component */
int UVMacroBlocks; /* Number of Macro-Blocks in U/V component */
int MacroBlocks; /* Total number of Macro-Blocks */
/**********************************************************************/
/* Frames */
short[] ThisFrameRecon;
short[] GoldenFrame;
short[] LastFrameRecon;
short[] PostProcessBuffer;
/**********************************************************************/
/* Fragment Information */
int[] pixel_index_table; /* start address of first
pixel of fragment in
source */
int[] recon_pixel_index_table; /* start address of first
pixel in recon buffer */
byte[] display_fragments; /* Fragment update map */
int[] CodedBlockList; /* A list of fragment indices for
coded blocks. */
MotionVector[] FragMVect; /* fragment motion vectors */
int[] FragTokenCounts; /* Number of tokens per fragment */
int[] FragQIndex; /* Fragment Quality used in
PostProcess */
byte[] FragCoefEOB; /* Position of last non 0 coef
within QFragData */
short[][] QFragData; /* Fragment Coefficients
Array Pointers */
byte[] FragQs; /* per block quantizers */
CodingMode[] FragCodingMethod; /* coding method for the
fragment */
/***********************************************************************/
/* Macro Block and SuperBlock Information */
BlockMapping BlockMap; /* super block + sub macro
block + sub frag ->
FragIndex */
/* Coded flag arrays and counters for them */
byte[] SBCodedFlags;
byte[] SBFullyFlags;
byte[] MBCodedFlags;
byte[] MBFullyFlags;
/**********************************************************************/
Coordinate[] FragCoordinates;
FrArray frArray = new FrArray();
Filter filter = new Filter();
/* quality index for each block */
byte[] blockQ;
/* Dequantiser and rounding tables */
int[] quant_index = new int[64];
HuffEntry[] HuffRoot_VP3x = new HuffEntry[Huffman.NUM_HUFF_TABLES];
int[][] HuffCodeArray_VP3x;
byte[][] HuffCodeLengthArray_VP3x;
byte[] ExtraBitLengths_VP3x;
public void clear()
{
if (opb != null) {
opb = null;
}
}
private static int ilog (long v)
{
int ret=0;
while (v != 0) {
ret++;
v>>=1;
}
return ret;
}
public Playback (TheoraInfo ci)
{
info = ci;
DecoderErrorCode = 0;
KeyFrameType = DCT_KEY_FRAME;
FramesHaveBeenSkipped = 0;
FrInit.InitFrameDetails(this);
keyframe_granule_shift = ilog(ci.keyframe_frequency_force-1);
//LastFrameQualityValue = 0;
/* Initialise version specific quantiser and in-loop filter values */
filter.copyFilterTables(ci);
/* Huffman setup */
initHuffmanTrees(ci);
}
public int getFrameType() {
return FrameType;
}
void setFrameType(byte FrType ){
/* Set the appropriate frame type according to the request. */
switch ( FrType ){
case Constants.BASE_FRAME:
FrameType = FrType;
break;
default:
FrameType = FrType;
break;
}
}
public void clearHuffmanSet()
{
Huffman.clearHuffmanTrees(HuffRoot_VP3x);
HuffCodeArray_VP3x = null;
HuffCodeLengthArray_VP3x = null;
}
public void initHuffmanSet()
{
clearHuffmanSet();
ExtraBitLengths_VP3x = HuffTables.ExtraBitLengths_VP31;
HuffCodeArray_VP3x = new int[Huffman.NUM_HUFF_TABLES][Huffman.MAX_ENTROPY_TOKENS];
HuffCodeLengthArray_VP3x = new byte[Huffman.NUM_HUFF_TABLES][Huffman.MAX_ENTROPY_TOKENS];
for (int i = 0; i < Huffman.NUM_HUFF_TABLES; i++ ){
Huffman.buildHuffmanTree(HuffRoot_VP3x,
HuffCodeArray_VP3x[i],
HuffCodeLengthArray_VP3x[i],
i, HuffTables.FrequencyCounts_VP3[i]);
}
}
public int readHuffmanTrees(TheoraInfo ci, OggBuffer opb) {
int i;
for (i=0; i<Huffman.NUM_HUFF_TABLES; i++) {
int ret;
ci.HuffRoot[i] = new HuffEntry();
ret = ci.HuffRoot[i].read(0, opb);
if (ret != 0)
return ret;
}
return 0;
}
public void initHuffmanTrees(TheoraInfo ci)
{
int i;
ExtraBitLengths_VP3x = HuffTables.ExtraBitLengths_VP31;
for(i=0; i<Huffman.NUM_HUFF_TABLES; i++){
HuffRoot_VP3x[i] = ci.HuffRoot[i].copy();
}
}
}

View File

@@ -0,0 +1,318 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
* 2008 Maik Merten <maikmerten@googlemail.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
public class Quant
{
private static int ilog (long v)
{
int ret=0;
while (v != 0) {
ret++;
v>>=1;
}
return ret;
}
public static int readQTables(TheoraInfo ci, OggBuffer opb) {
/* Variable names according to Theora spec where it makes sense.
* I *know* this may violate Java coding style rules, but I consider
* readability against the Theora spec to be more important */
long NBITS,value;
int x, bmi, NBMS;
/* A 2 × 3 array containing the number of quant ranges for a
given qti and pli , respectively. This is at most 63. */
int[][] NQRS = new int[2][3];
/* A 2 × 3 × 63 array of the sizes of each quant range for a
given qti and pli , respectively. Only the first NQRS[qti ][pli ]
values are used. */
int[][][] QRSIZES = new int[2][3][63];
/* A 2 × 3 × 64 array of the bmi s used for each quant
range for a given qti and pli, respectively. Only the first
(NQRS[qti ][pli ] + 1) values are used. */
int[][][] QRBMIS = new int[2][3][64];
int qri, qi, qtj, plj;
/* 1. Read a 4-bit unsigned integer. Assign NBITS the value read, plus one. */
NBITS = opb.readB(4); NBITS++;
/* 2. For each consecutive value of qi from 0 to 63, inclusive:
(a) Read an NBITS-bit unsigned integer as ACSCALE[qi ]. */
for(x=0; x < 64; x++) {
value = opb.readB((int)NBITS);
if(NBITS<0) return Result.BADHEADER;
ci.AcScaleFactorTable[x]=(int)value;
}
/* 3. Read a 4-bit unsigned integer. Assign NBITS the value read, plus one. */
NBITS = opb.readB(4); NBITS++;
/* 4. For each consecutive value of qi from 0 to 63, inclusive:
(a) Read an NBITS-bit unsigned integer as DCSCALE[qi ]. */
for(x=0; x<Constants.Q_TABLE_SIZE; x++) {
value = opb.readB((int)NBITS);
if(NBITS<0) return Result.BADHEADER;
ci.DcScaleFactorTable[x]=(short)value;
}
/* 5. Read a 9-bit unsigned integer. Assign NBMS the value decoded, plus
one. NBMS MUST be no greater than 384. */
NBMS = opb.readB(9); NBMS++;
if(NBMS > 384) {
return Result.BADHEADER;
}
ci.MaxQMatrixIndex = NBMS;
/* 6. For each consecutive value of bmi from 0 to (NBMS - 1), inclusive:
(a) For each consecutive value of ci from 0 to 63, inclusive:
i. Read an 8-bit unsigned integer as BMS[bmi ][ci ]. */
ci.qmats= new short[NBMS*64];
for(bmi=0; bmi<NBMS; bmi++) {
for(x=0; x<64; x++) {
value = opb.readB(8);
if(NBITS<0)return Result.BADHEADER;
ci.qmats[(bmi<<6)+x]=(short)value;
}
}
/* 7. For each consecutive value of qti from 0 to 1, inclusive: */
for(int qti = 0; qti <= 1; ++qti) {
/* (a) For each consecutive value of pli from 0 to 2, inclusive: */
for(int pli = 0; pli <= 2; ++pli) {
int NEWQR;
if(qti > 0 || pli > 0) {
/* i. If qti > 0 or pli > 0, read a 1-bit unsigned integer as NEWQR. */
NEWQR = opb.readB(1);
} else {
/* ii. Else, assign NEWQR the value one. */
NEWQR = 1;
}
if(NEWQR == 0) {
/* If NEWQR is zero, then we are copying a previously defined set
of quant ranges. In that case: */
int RPQR;
if(qti > 0) {
/* A. If qti > 0, read a 1-bit unsigned integer as RPQR. */
RPQR = opb.readB(1);
} else {
/* B. Else, assign RPQR the value zero. */
RPQR = 0;
}
if(RPQR == 1) {
/* C. If RPQR is one, assign qtj the value (qti - 1) and assign plj
the value pli . This selects the set of quant ranges defined
for the same color plane as this one, but for the previous
quantization type. */
qtj = qti - 1;
plj = pli;
} else {
/* D. Else assign qtj the value (3 * qti + pli - 1)//3 and assign plj
the value (pli + 2)%3. This selects the most recent set of
quant ranges defined. */
qtj = (3 * qti + pli - 1) / 3;
plj = (pli + 2) % 3;
}
/* E. Assign NQRS[qti ][pli ] the value NQRS[qtj ][plj ]. */
NQRS[qti][pli] = NQRS[qtj][plj];
/* F. Assign QRSIZES[qti ][pli ] the values in QRSIZES[qtj ][plj ]. */
QRSIZES[qti][pli] = QRSIZES[qtj][plj];
/* G. Assign QRBMIS[qti ][pli ] the values in QRBMIS[qtj ][plj ]. */
QRBMIS[qti][pli] = QRBMIS[qtj][plj];
} else {
/* Else, NEWQR is one, which indicates that we are defining a new
set of quant ranges. In that case: */
/*A. Assign qri the value zero. */
qri = 0;
/*B. Assign qi the value zero. */
qi = 0;
/* C. Read an ilog(NBMS - 1)-bit unsigned integer as
QRBMIS[qti ][pli ][qri ]. If this is greater than or equal to
NBMS, stop. The stream is undecodable. */
QRBMIS[qti][pli][qri] = opb.readB(ilog(NBMS - 1));
if(QRBMIS[qti][pli][qri] >= NBMS) {
System.out.println("bad header (1)");
return Result.BADHEADER;
}
do {
/* D. Read an ilog(62 - qi )-bit unsigned integer. Assign
QRSIZES[qti ][pli ][qri ] the value read, plus one. */
QRSIZES[qti][pli][qri] = opb.readB(ilog(62 - qi)) + 1;
/* E. Assign qi the value qi + QRSIZES[qti ][pli ][qri ]. */
qi = qi + QRSIZES[qti][pli][qri];
/* F. Assign qri the value qri + 1. */
qri = qri + 1;
/* G. Read an ilog(NBMS - 1)-bit unsigned integer as
QRBMIS[qti ][pli ][qri ]. */
QRBMIS[qti][pli][qri] = opb.readB(ilog(NBMS - 1));
/* H. If qi is less than 63, go back to step 7(a)ivD. */
} while(qi < 63);
/* I. If qi is greater than 63, stop. The stream is undecodable. */
if(qi > 63) {
System.out.println("bad header (2): " + qi);
return Result.BADHEADER;
}
/* J. Assign NQRS[qti ][pli ] the value qri . */
NQRS[qti][pli] = qri;
}
}
}
/* Compute all 384 matrices */
for(int coding = 0; coding < 2; ++coding) {
for(int plane = 0; plane < 3; ++plane) {
for(int quality = 0; quality < 64; ++quality) {
short[] scaledmat = compQuantMatrix(ci.AcScaleFactorTable, ci.DcScaleFactorTable, ci.qmats, NQRS, QRSIZES, QRBMIS, coding, plane, quality);
for(int coeff = 0; coeff < 64; ++coeff) {
int j = Constants.dequant_index[coeff];
ci.dequant_tables[coding][plane][quality][coeff] = scaledmat[j];
}
}
}
}
return 0;
}
static short[] compQuantMatrix(int[] ACSCALE, short[] DCSCALE, short[] BMS, int[][] NQRS,
int[][][] QRSIZES, int[][][] QRBMIS, int qti, int pli, int qi) {
/* Variable names according to Theora spec where it makes sense.
* I *know* this may violate Java coding style rules, but I consider
* readability against the Theora spec to be more important */
short[] QMAT = new short[64];
int qri, qrj;
/* 1. Assign qri the index of a quant range such that
\qi \ge \sum_{\qrj=0}^{\qri-1} QRSIZES[\qti][\pli][\qrj],
and
\qi \le \sum_{\qrj=0}^{\qri} QRSIZES[\qti][\pli][\qrj],
*/
for(qri = 0; qri < 63; ++qri) {
int sum1 = 0;
for(qrj = 0; qrj < qri; ++qrj) {
sum1 += QRSIZES[qti][pli][qrj];
}
int sum2 = 0;
for(qrj = 0; qrj <= qri; ++qrj) {
sum2 += QRSIZES[qti][pli][qrj];
}
if(qi >= sum1 && qi <= sum2)
break;
}
/* 2. Assign QISTART the value
\sum_{\qrj=0}^{\qri-1} QRSIZES[\qti][\pli][\qrj].
*/
int QISTART = 0;
for(qrj = 0; qrj < qri; ++qrj) {
QISTART += QRSIZES[qti][pli][qrj];
}
/* 3. Assign QIEND the value
\sum_{\qrj=0}^{\qri} QRSIZES[\qti][\pli][\qrj].
*/
int QIEND = 0;
for(qrj = 0; qrj <= qri; ++qrj) {
QIEND += QRSIZES[qti][pli][qrj];
}
/* 4. Assign bmi the value QRBMIS[qti ][pli ][qri ]. */
int bmi = QRBMIS[qti][pli][qri];
/* 5. Assign bmj the value QRBMIS[qti ][pli ][qri + 1]. */
int bmj = QRBMIS[qti][pli][qri + 1];
int[] BM = new int[64];
int QMIN;
/* 6. For each consecutive value of ci from 0 to 63, inclusive: */
for(int ci = 0; ci < 64; ++ci) {
/* (a) Assign BM[ci ] the value
(2 (QIEND qi ) BMS[bmi ][ci ]
+ 2 (qi QISTART) BMS[bmj ][ci ]
+ QRSIZES[qti ][pli ][qri ])//(2 QRSIZES[qti ][pli ][qri ]) */
BM[ci] = (2 * (QIEND - qi) * BMS[(bmi<<6) + ci]
+ 2 * (qi - QISTART) * BMS[(bmj<<6) + ci]
+ QRSIZES[qti][pli][qri]) / (2 * QRSIZES[qti][pli][qri]);
/* (b) Assign QMIN the value given by Table 6.18 according to qti and ci . */
if(ci == 0 && qti == 0)
QMIN = 16;
else if(ci > 0 && qti == 0)
QMIN = 8;
else if(ci == 0 && qti == 1)
QMIN = 32;
else
QMIN = 16;
int QSCALE;
if(ci == 0) {
/* (c) If ci equals zero, assign QSCALE the value DCSCALE[qi ]. */
QSCALE = DCSCALE[qi];
} else {
/* (d) Else, assign QSCALE the value ACSCALE[qi ]. */
QSCALE = ACSCALE[qi];
}
/*(e) Assign QMAT[ci ] the value
max(QMIN, min((QSCALE BM[ci ]//100) 4, 4096)). */
QMAT[ci] = (short)Math.max(QMIN, Math.min((QSCALE * BM[ci]/100) * 4,4096));
}
return QMAT;
}
}

View File

@@ -0,0 +1,110 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public final class Recon
{
private static final short clamp255(int val) {
return (short)((~(val>>31)) & 255 & (val | ((255-val)>>31)));
}
public static final void CopyBlock(short[] src,
short[] dest, int idx,
int srcstride)
{
int i, off=idx;
for (i=0; i<8; i++){
dest[off+0] = src[off+0];
dest[off+1] = src[off+1];
dest[off+2] = src[off+2];
dest[off+3] = src[off+3];
dest[off+4] = src[off+4];
dest[off+5] = src[off+5];
dest[off+6] = src[off+6];
dest[off+7] = src[off+7];
off+=srcstride;
}
}
public static final void ReconIntra(short[] ReconPtr, int idx,
short[] ChangePtr, int LineStep)
{
int i, roff=idx, coff=0;
for (i=0; i<8; i++ ){
/* Convert the data back to 8 bit unsigned */
/* Saturate the output to unsigned 8 bit values */
ReconPtr[roff+0] = clamp255(ChangePtr[coff++] + 128);
ReconPtr[roff+1] = clamp255(ChangePtr[coff++] + 128);
ReconPtr[roff+2] = clamp255(ChangePtr[coff++] + 128);
ReconPtr[roff+3] = clamp255(ChangePtr[coff++] + 128);
ReconPtr[roff+4] = clamp255(ChangePtr[coff++] + 128);
ReconPtr[roff+5] = clamp255(ChangePtr[coff++] + 128);
ReconPtr[roff+6] = clamp255(ChangePtr[coff++] + 128);
ReconPtr[roff+7] = clamp255(ChangePtr[coff++] + 128);
roff += LineStep;
}
}
public static final void ReconInter(short[] ReconPtr, int idx1,
short[] RefPtr, int idx2, short[] ChangePtr,
int LineStep ) {
int coff=0, roff1=idx1, roff2=idx2, i;
for (i = 0; i < 8; i++) {
ReconPtr[roff1+0] = clamp255(RefPtr[roff2+0] + ChangePtr[coff++]);
ReconPtr[roff1+1] = clamp255(RefPtr[roff2+1] + ChangePtr[coff++]);
ReconPtr[roff1+2] = clamp255(RefPtr[roff2+2] + ChangePtr[coff++]);
ReconPtr[roff1+3] = clamp255(RefPtr[roff2+3] + ChangePtr[coff++]);
ReconPtr[roff1+4] = clamp255(RefPtr[roff2+4] + ChangePtr[coff++]);
ReconPtr[roff1+5] = clamp255(RefPtr[roff2+5] + ChangePtr[coff++]);
ReconPtr[roff1+6] = clamp255(RefPtr[roff2+6] + ChangePtr[coff++]);
ReconPtr[roff1+7] = clamp255(RefPtr[roff2+7] + ChangePtr[coff++]);
roff1 += LineStep;
roff2 += LineStep;
}
}
public static final void ReconInterHalfPixel2(short[] ReconPtr, int idx1,
short[] RefPtr1, int idx2, short[] RefPtr2, int idx3,
short[] ChangePtr, int LineStep ) {
int coff=0, roff1=idx1, roff2=idx2, roff3=idx3, i;
for (i = 0; i < 8; i++ ){
ReconPtr[roff1+0] = clamp255(((RefPtr1[roff2+0] + RefPtr2[roff3+0]) >> 1) + ChangePtr[coff++]);
ReconPtr[roff1+1] = clamp255(((RefPtr1[roff2+1] + RefPtr2[roff3+1]) >> 1) + ChangePtr[coff++]);
ReconPtr[roff1+2] = clamp255(((RefPtr1[roff2+2] + RefPtr2[roff3+2]) >> 1) + ChangePtr[coff++]);
ReconPtr[roff1+3] = clamp255(((RefPtr1[roff2+3] + RefPtr2[roff3+3]) >> 1) + ChangePtr[coff++]);
ReconPtr[roff1+4] = clamp255(((RefPtr1[roff2+4] + RefPtr2[roff3+4]) >> 1) + ChangePtr[coff++]);
ReconPtr[roff1+5] = clamp255(((RefPtr1[roff2+5] + RefPtr2[roff3+5]) >> 1) + ChangePtr[coff++]);
ReconPtr[roff1+6] = clamp255(((RefPtr1[roff2+6] + RefPtr2[roff3+6]) >> 1) + ChangePtr[coff++]);
ReconPtr[roff1+7] = clamp255(((RefPtr1[roff2+7] + RefPtr2[roff3+7]) >> 1) + ChangePtr[coff++]);
roff1 += LineStep;
roff2 += LineStep;
roff3 += LineStep;
}
}
}

View File

@@ -0,0 +1,36 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public final class Result {
public static final int FAULT = -1;
public static final int EINVAL = -10;
public static final int BADHEADER = -20;
public static final int NOTFORMAT = -21;
public static final int VERSION = -22;
public static final int IMPL = -23;
public static final int BADPACKET = -24;
public static final int NEWPACKET = -25;
}

View File

@@ -0,0 +1,36 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public class TheoraComment {
String[] user_comments;
String vendor;
public void clear() {
user_comments = null;
vendor = null;
}
}

View File

@@ -0,0 +1,265 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
public class TheoraInfo {
public int width;
public int height;
public int frame_width;
public int frame_height;
public int offset_x;
public int offset_y;
public int fps_numerator;
public int fps_denominator;
public int aspect_numerator;
public int aspect_denominator;
public Colorspace colorspace;
public PixelFormat pixel_fmt;
public int target_bitrate;
public int quality;
public int quick_p; /* quick encode/decode */
/* decode only */
public byte version_major;
public byte version_minor;
public byte version_subminor;
public int keyframe_granule_shift;
public long keyframe_frequency_force;
/* codec_setup_info */
short[][][][] dequant_tables = new short[2][3][64][64];
int[] AcScaleFactorTable = new int[Constants.Q_TABLE_SIZE];
short[] DcScaleFactorTable = new short[Constants.Q_TABLE_SIZE];
int MaxQMatrixIndex;
short[] qmats;
HuffEntry[] HuffRoot = new HuffEntry[Huffman.NUM_HUFF_TABLES];
byte[] LoopFilterLimitValues = new byte[Constants.Q_TABLE_SIZE];
private static void _tp_readbuffer(OggBuffer opb, byte[] buf, int len)
{
for (int i=0; i<len; i++) {
buf[i] = (byte)opb.readB(8);
}
}
private static int _tp_readlsbint(OggBuffer opb)
{
int value;
value = opb.readB(8);
value |= opb.readB(8) << 8;
value |= opb.readB(8) << 16;
value |= opb.readB(8) << 24;
return value;
}
private int unpackInfo(OggBuffer opb){
version_major = (byte)opb.readB(8);
version_minor = (byte)opb.readB(8);
version_subminor = (byte)opb.readB(8);
if (version_major != Version.VERSION_MAJOR)
return Result.VERSION;
if (version_minor > Version.VERSION_MINOR)
return Result.VERSION;
width = (int)(opb.readB(16)<<4);
height = (int)(opb.readB(16)<<4);
frame_width = (int)opb.readB(24);
frame_height = (int)opb.readB(24);
offset_x = (int)opb.readB(8);
offset_y = (int)opb.readB(8);
/* Invert the offset so that it is from the top down */
offset_y = height-frame_height-offset_y;
fps_numerator = opb.readB(32);
fps_denominator = opb.readB(32);
aspect_numerator = opb.readB(24);
aspect_denominator = opb.readB(24);
colorspace = Colorspace.spaces[opb.readB(8)];
target_bitrate = opb.readB(24);
quality = opb.readB(6);
keyframe_granule_shift = opb.readB(5);
keyframe_frequency_force = 1<<keyframe_granule_shift;
pixel_fmt = PixelFormat.formats[opb.readB(2)];
if (pixel_fmt==PixelFormat.TH_PF_RSVD)
return (Result.BADHEADER);
/* spare configuration bits */
if (opb.readB(3) == -1)
return (Result.BADHEADER);
return(0);
}
static int unpackComment (TheoraComment tc, OggBuffer opb)
{
int i;
int len;
byte[] tmp;
int comments;
len = _tp_readlsbint(opb);
if(len<0)
return(Result.BADHEADER);
tmp=new byte[len];
_tp_readbuffer(opb, tmp, len);
tc.vendor=new String(tmp);
comments = _tp_readlsbint(opb);
if(comments<0) {
tc.clear();
return Result.BADHEADER;
}
tc.user_comments=new String[comments];
for(i=0;i<comments;i++){
len = _tp_readlsbint(opb);
if(len<0) {
tc.clear();
return Result.BADHEADER;
}
tmp=new byte[len];
_tp_readbuffer(opb,tmp,len);
tc.user_comments[i]=new String(tmp);
}
return 0;
}
/* handle the in-loop filter limit value table */
private int readFilterTables(OggBuffer opb)
{
int bits = opb.readB(3);
for (int i=0; i<Constants.Q_TABLE_SIZE; i++) {
int value = opb.readB(bits);
LoopFilterLimitValues[i] = (byte) value;
}
if (bits<0)
return Result.BADHEADER;
return 0;
}
private int unpackTables (OggBuffer opb)
{
int ret;
ret = readFilterTables(opb);
if (ret != 0)
return ret;
ret = Quant.readQTables(this, opb);
if (ret != 0)
return ret;
ret = Huffman.readHuffmanTrees(HuffRoot, opb);
if (ret != 0)
return ret;
return ret;
}
public void clear() {
qmats = null;
Huffman.clearHuffmanTrees(HuffRoot);
}
public int decodeHeader (TheoraComment cc, OggPacket op)
{
long ret;
OggBuffer opb = new OggBuffer();
opb.readinit (op.packet_base, op.packet, op.bytes);
{
byte[] id = new byte[6];
int typeflag;
typeflag = opb.readB(8);
if((typeflag & 0x80) == 0) {
return Result.NOTFORMAT;
}
_tp_readbuffer(opb,id,6);
if (!"theora".equals(new String(id))) {
return Result.NOTFORMAT;
}
switch(typeflag){
case 0x80:
if(op.b_o_s == 0){
/* Not the initial packet */
return Result.BADHEADER;
}
if(version_major!=0){
/* previously initialized info header */
return Result.BADHEADER;
}
ret = unpackInfo(opb);
return (int)ret;
case 0x81:
if(version_major==0){
/* um... we didn't get the initial header */
return Result.BADHEADER;
}
ret = unpackComment(cc,opb);
return (int)ret;
case 0x82:
if(version_major==0 || cc.vendor==null){
/* um... we didn't get the initial header or comments yet */
return Result.BADHEADER;
}
ret = unpackTables(opb);
return (int)ret;
default:
if(version_major==0 || cc.vendor==null ||
HuffRoot[0]==null)
{
/* we haven't gotten the three required headers */
return Result.BADHEADER;
}
/* ignore any trailing header packets for forward compatibility */
return Result.NEWPACKET;
}
}
}
}

View File

@@ -0,0 +1,156 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
public class TheoraState
{
long granulepos;
private Playback pbi;
private Decode dec;
public void clear()
{
if(pbi != null){
pbi.info.clear();
pbi.clearHuffmanSet();
FrInit.ClearFragmentInfo(pbi);
FrInit.ClearFrameInfo(pbi);
pbi.clear();
}
pbi = null;
}
public int decodeInit(TheoraInfo ci)
{
pbi = new Playback(ci);
dec = new Decode(pbi);
granulepos=-1;
return(0);
}
public boolean isKeyframe (OggPacket op)
{
return (op.packet_base[op.packet] & 0x40) == 0;
}
public int decodePacketin (OggPacket op)
{
long ret;
pbi.DecoderErrorCode = 0;
if (op.bytes>0) {
pbi.opb.readinit(op.packet_base, op.packet, op.bytes);
/* verify that this is a video frame */
ret = pbi.opb.readB(1);
if (ret==0) {
try {
ret=dec.loadAndDecode();
} catch(Exception e) {
/* If lock onto the bitstream is lost all sort of Exceptions can occur.
* The bitstream damage may be local, so the next packet may be okay. */
e.printStackTrace();
return Result.BADPACKET;
}
if(ret != 0)
return (int) ret;
} else {
return Result.BADPACKET;
}
}
if(op.granulepos>-1)
granulepos=op.granulepos;
else{
if(granulepos==-1){
granulepos=0;
}
else {
if ((op.bytes>0) && (pbi.FrameType == Constants.BASE_FRAME)){
long frames= granulepos & ((1<<pbi.keyframe_granule_shift)-1);
granulepos>>=pbi.keyframe_granule_shift;
granulepos+=frames+1;
granulepos<<=pbi.keyframe_granule_shift;
}else
granulepos++;
}
}
return(0);
}
public int decodeYUVout (YUVBuffer yuv)
{
yuv.y_width = pbi.info.width;
yuv.y_height = pbi.info.height;
yuv.y_stride = pbi.YStride;
yuv.uv_width = pbi.info.width >> pbi.UVShiftX;
yuv.uv_height = pbi.info.height >> pbi.UVShiftY;
yuv.uv_stride = pbi.UVStride;
if(pbi.PostProcessingLevel != 0){
yuv.data = pbi.PostProcessBuffer;
}else{
yuv.data = pbi.LastFrameRecon;
}
yuv.y_offset = pbi.ReconYDataOffset;
yuv.u_offset = pbi.ReconUDataOffset;
yuv.v_offset = pbi.ReconVDataOffset;
/* we must flip the internal representation,
so make the stride negative and start at the end */
yuv.y_offset += yuv.y_stride * (yuv.y_height - 1);
yuv.u_offset += yuv.uv_stride * (yuv.uv_height - 1);
yuv.v_offset += yuv.uv_stride * (yuv.uv_height - 1);
yuv.y_stride = - yuv.y_stride;
yuv.uv_stride = - yuv.uv_stride;
yuv.newPixels();
return 0;
}
/* returns, in seconds, absolute time of current packet in given
logical stream */
public double granuleTime(long granulepos)
{
if(granulepos>=0){
long iframe=granulepos>>pbi.keyframe_granule_shift;
long pframe=granulepos-(iframe<<pbi.keyframe_granule_shift);
return (iframe+pframe)*
((double)pbi.info.fps_denominator/pbi.info.fps_numerator);
}
return(-1);
}
}

View File

@@ -0,0 +1,44 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public class Version
{
public static final int VERSION_MAJOR = 3;
public static final int VERSION_MINOR = 2;
public static final int VERSION_SUB = 0;
private static final String VENDOR_STRING = "Xiph.Org libTheora I 20040317 3 2 0";
public static String getVersionString()
{
return VENDOR_STRING;
}
public static int getVersionNumber()
{
return (VERSION_MAJOR<<16) + (VERSION_MINOR<<8) + (VERSION_SUB);
}
}

View File

@@ -0,0 +1,293 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public class YUVBuffer {
public int y_width;
public int y_height;
public int y_stride;
public int uv_width;
public int uv_height;
public int uv_stride;
public short[] data;
public int y_offset;
public int u_offset;
public int v_offset;
private int[] pixels;
private int pix_size;
private boolean newPixels = true;
public int[] produce() {
prepareRGBData(0, 0, y_width, y_height);
return pixels;
}
private synchronized void prepareRGBData(int x, int y, int width, int height) {
if (!newPixels) {
return;
}
int size = width * height;
try {
if (size != pix_size) {
pixels = new int[size];
pix_size = size;
}
/* rely on the buffer size being set correctly, and the only allowed
video formats being Theora's video formats */
if (uv_height < y_height) YUV420toRGB(x, y, width, height);
else if (uv_width == y_width) YUV444toRGB(x, y, width, height);
else YUV422toRGB(x, y, width, height);
} catch (Throwable t) {
/* ignore */
}
newPixels = false;
}
public synchronized void newPixels() {
newPixels = true;
}
private void YUV420toRGB(int x, int y, int width, int height) {
/*
* this modified version of the original YUVtoRGB was
* provided by Ilan and Yaniv Ben Hagai.
*
* additional thanks to Gumboot for helping with making this
* code perform better.
*/
// Set up starting values for YUV pointers
int YPtr = y_offset + x + y * (y_stride);
int YPtr2 = YPtr + y_stride;
int UPtr = u_offset + x / 2 + (y / 2) * (uv_stride);
int VPtr = v_offset + x / 2 + (y / 2) * (uv_stride);
int RGBPtr = 0;
int RGBPtr2 = width;
int width2 = width / 2;
int height2 = height / 2;
// Set the line step for the Y and UV planes and YPtr2
int YStep = y_stride * 2 - (width2) * 2;
int UVStep = uv_stride - (width2);
int RGBStep = width;
for (int i = 0; i < height2; i++) {
for (int j = 0; j < width2; j++) {
int D, E, r, g, b, t1, t2, t3, t4;
D = data[UPtr++];
E = data[VPtr++];
t1 = 298 * (data[YPtr] - 16);
t2 = 409 * E - 409*128 + 128;
t3 = (100 * D) + (208 * E) - 100*128 - 208*128 - 128;
t4 = 516 * D - 516*128 + 128;
r = (t1 + t2);
g = (t1 - t3);
b = (t1 + t4);
// retrieve data for next pixel now, hide latency?
t1 = 298 * (data[YPtr + 1] - 16);
// pack pixel
pixels[RGBPtr] =
(clamp65280(r) << 8) | clamp65280(g) | (clamp65280(b)>>8) | 0xff000000;
r = (t1 + t2);
g = (t1 - t3);
b = (t1 + t4);
// retrieve data for next pixel now, hide latency?
t1 = 298 * (data[YPtr2] - 16);
// pack pixel
pixels[RGBPtr + 1] =
(clamp65280(r) << 8) | clamp65280(g) | (clamp65280(b)>>8) | 0xff000000;
r = (t1 + t2);
g = (t1 - t3);
b = (t1 + t4);
// retrieve data for next pixel now, hide latency?
t1 = 298 * (data[YPtr2 + 1] - 16);
// pack pixel
pixels[RGBPtr2] =
(clamp65280(r) << 8) | clamp65280(g) | (clamp65280(b)>>8) | 0xff000000;
r = (t1 + t2);
g = (t1 - t3);
b = (t1 + t4);
// pack pixel
pixels[RGBPtr2 + 1] =
(clamp65280(r) << 8) | clamp65280(g) | (clamp65280(b)>>8) | 0xff000000;
YPtr += 2;
YPtr2 += 2;
RGBPtr += 2;
RGBPtr2 += 2;
}
// Increment the various pointers
YPtr += YStep;
YPtr2 += YStep;
UPtr += UVStep;
VPtr += UVStep;
RGBPtr += RGBStep;
RGBPtr2 += RGBStep;
}
}
// kept for reference
/*private static final int clamp255(int val) {
return ((~(val>>31)) & 255 & (val | ((255-val)>>31)));
}*/
private static final int clamp65280(int val) {
/* 65280 == 255 << 8 == 0x0000FF00 */
/* This function is just like clamp255, but only acting on the top
24 bits (bottom 8 are zero'd). This allows val, initially scaled
to 65536, to be clamped without shifting, thereby saving one shift.
(RGB packing must be aware that the info is in the second-lowest
byte.) */
return ((~(val>>31)) & 65280 & (val | ((65280-val)>>31)));
}
private void YUV444toRGB(int x, int y, int width, int height) {
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
int D, E, r, g, b, t1, t2, t3, t4, p;
p = x + i + (j + y)*y_stride;
D = data[u_offset + p];
E = data[v_offset + p];
t1 = 298 * (data[y_offset + p] - 16);
t2 = 409 * E - 409*128 + 128;
t3 = (100 * D) + (208 * E) - 100*128 - 208*128 - 128;
t4 = 516 * D - 516*128 + 128;
r = (t1 + t2);
g = (t1 - t3);
b = (t1 + t4);
// pack pixel
pixels[i + j*width] =
(clamp65280(r) << 8) | clamp65280(g) | (clamp65280(b)>>8) | 0xff000000;
}
}
}
private void YUV422toRGB(int x, int y, int width, int height) {
int x2 = x/2;
int width2 = width/2;
for (int j = 0; j < height; j++) {
for (int i = 0; i < width2; i++) {
int D, E, r, g, b, t1, t2, t3, t4, p;
p = x2 + i + (y + j)*uv_stride;
D = data[u_offset + p];
E = data[v_offset + p];
p = y_offset + 2*(x2 + i) + (y + j)*y_stride;
t1 = 298 * (data[p] - 16);
t2 = 409 * E - 409*128 + 128;
t3 = (100 * D) + (208 * E) - 100*128 - 208*128 - 128;
t4 = 516 * D - 516*128 + 128;
r = (t1 + t2);
g = (t1 - t3);
b = (t1 + t4);
p++;
t1 = 298 * (data[p] - 16);
// pack pixel
p = 2*i + j*width;
pixels[p] =
(clamp65280(r) << 8) | clamp65280(g) | (clamp65280(b)>>8) | 0xff000000;
r = (t1 + t2);
g = (t1 - t3);
b = (t1 + t4);
p++;
// pack pixel
pixels[p] =
(clamp65280(r) << 8) | clamp65280(g) | (clamp65280(b)>>8) | 0xff000000;
}
}
}
// some benchmarking stuff, uncomment if you need it
/*public static void main(String[] args) {
YUVBuffer yuvbuf = new YUVBuffer();
// let's create a 1280x720 picture with noise
int x = 1280;
int y = 720;
int size = (x * y) + (x * y) / 2;
short[] picdata = new short[size];
Random r = new Random();
for (int i = 0; i < picdata.length; ++i) {
picdata[i] = (short) (r.nextInt(255) | 0xFF);
}
System.out.println("bench...");
yuvbuf.data = picdata;
yuvbuf.y_height = y;
yuvbuf.y_width = x;
yuvbuf.y_stride = x;
yuvbuf.uv_height = y / 2;
yuvbuf.uv_width = x / 2;
yuvbuf.uv_stride = x / 2;
yuvbuf.u_offset = x / 2;
yuvbuf.v_offset = x + x / 2;
int times = 5000;
long start = System.currentTimeMillis();
for (int i = 0; i < times; ++i) {
yuvbuf.newPixels();
yuvbuf.prepareRGBData(0, 0, x, y);
}
long end = System.currentTimeMillis();
System.out.println("average conversion time per frame: " + ((double) (end - start)) / (times * 1f) + " ms.");
}*/
}

View File

@@ -0,0 +1,366 @@
/* Jheora
* Copyright (C) 2004 Fluendo S.L.
*
* Written by: 2004 Wim Taymans <wim@fluendo.com>
*
* Many thanks to
* The Xiph.Org Foundation http://www.xiph.org/
* Jheora was based on their Theora reference decoder.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jheora;
public final class iDCT
{
private static final int IdctAdjustBeforeShift = 8;
private static final int xC1S7 = 64277;
private static final int xC2S6 = 60547;
private static final int xC3S5 = 54491;
private static final int xC4S4 = 46341;
private static final int xC5S3 = 36410;
private static final int xC6S2 = 25080;
private static final int xC7S1 = 12785;
private int[] ip = new int[64];
private final void dequant_slow(short[] dequant_coeffs,
short[] quantized_list,
int[] DCT_block)
{
for(int i = 0; i < 64; i++) {
DCT_block[Constants.dequant_index[i]] = quantized_list[i] * dequant_coeffs[i];
/*
if (i%8 ==0)
System.out.print(": ");
System.out.print("("+DCT_block[Constants.dequant_index[i]]+" ");
System.out.print(dequant_coeffs[i]+" ");
System.out.print(quantized_list[i]+")");
if (i%8 ==7)
System.out.print("\n");
*/
}
}
public final void IDctSlow (short[] InputData, short[]QuantMatrix, short[] OutputData)
{
short[] op = OutputData;
int _A, _B, _C, _D, _Ad, _Bd, _Cd, _Dd, _E, _F, _G, _H;
int _Ed, _Gd, _Add, _Bdd, _Fd, _Hd;
int t1, t2;
dequant_slow (QuantMatrix, InputData, ip);
/* Inverse DCT on the rows now */
for (int loop = 0, off=0; loop < 8; loop++, off+=8){
/* Check for non-zero values */
if ((ip[0 + off] | ip[1 + off] | ip[2 + off] | ip[3 + off] |
ip[4 + off] | ip[5 + off] | ip[6 + off] | ip[7 + off]) != 0 )
{
t1 = (xC1S7 * ip[1 + off]) >> 16;
t2 = (xC7S1 * ip[7 + off]) >> 16;
_A = t1 + t2;
t1 = (xC7S1 * ip[1 + off]) >> 16;
t2 = (xC1S7 * ip[7 + off]) >> 16;
_B = t1 - t2;
t1 = (xC3S5 * ip[3 + off]) >> 16;
t2 = (xC5S3 * ip[5 + off]) >> 16;
_C = t1 + t2;
t1 = (xC3S5 * ip[5 + off]) >> 16;
t2 = (xC5S3 * ip[3 + off]) >> 16;
_D = t1 - t2;
_Ad = (xC4S4 * (short)(_A - _C)) >> 16;
_Bd = (xC4S4 * (short)(_B - _D)) >> 16;
_Cd = _A + _C;
_Dd = _B + _D;
_E = (xC4S4 * (short)(ip[0 + off] + ip[4 + off])) >> 16;
_F = (xC4S4 * (short)(ip[0 + off] - ip[4 + off])) >> 16;
t1 = (xC2S6 * ip[2 + off]) >> 16;
t2 = (xC6S2 * ip[6 + off]) >> 16;
_G = t1 + t2;
t1 = (xC6S2 * ip[2 + off]) >> 16;
t2 = (xC2S6 * ip[6 + off]) >> 16;
_H = t1 - t2;
_Ed = _E - _G;
_Gd = _E + _G;
_Add = _F + _Ad;
_Bdd = _Bd - _H;
_Fd = _F - _Ad;
_Hd = _Bd + _H;
/* Final sequence of operations over-write original inputs. */
ip[0 + off] = (short)((_Gd + _Cd ) >> 0);
ip[7 + off] = (short)((_Gd - _Cd ) >> 0);
ip[1 + off] = (short)((_Add + _Hd ) >> 0);
ip[2 + off] = (short)((_Add - _Hd ) >> 0);
ip[3 + off] = (short)((_Ed + _Dd ) >> 0);
ip[4 + off] = (short)((_Ed - _Dd ) >> 0);
ip[5 + off] = (short)((_Fd + _Bdd ) >> 0);
ip[6 + off] = (short)((_Fd - _Bdd ) >> 0);
}
}
for (int loop = 0, off=0; loop < 8; loop++, off++){
/* Check for non-zero values (bitwise or faster than ||) */
if ((ip[0 * 8 + off] | ip[1 * 8 + off] | ip[2 * 8 + off] | ip[3 * 8 + off] |
ip[4 * 8 + off] | ip[5 * 8 + off] | ip[6 * 8 + off] | ip[7 * 8 + off]) != 0)
{
t1 = (xC1S7 * ip[1*8 + off]) >> 16;
t2 = (xC7S1 * ip[7*8 + off]) >> 16;
_A = t1 + t2;
t1 = (xC7S1 * ip[1*8 + off]) >> 16;
t2 = (xC1S7 * ip[7*8 + off]) >> 16;
_B = t1 - t2;
t1 = (xC3S5 * ip[3*8 + off]) >> 16;
t2 = (xC5S3 * ip[5*8 + off]) >> 16;
_C = t1 + t2;
t1 = (xC3S5 * ip[5*8 + off]) >> 16;
t2 = (xC5S3 * ip[3*8 + off]) >> 16;
_D = t1 - t2;
_Ad = (xC4S4 * (short)(_A - _C)) >> 16;
_Bd = (xC4S4 * (short)(_B - _D)) >> 16;
_Cd = _A + _C;
_Dd = _B + _D;
_E = (xC4S4 * (short)(ip[0*8 + off] + ip[4*8 + off])) >> 16;
_F = (xC4S4 * (short)(ip[0*8 + off] - ip[4*8 + off])) >> 16;
t1 = (xC2S6 * ip[2*8 + off]) >> 16;
t2 = (xC6S2 * ip[6*8 + off]) >> 16;
_G = t1 + t2;
t1 = (xC6S2 * ip[2*8 + off]) >> 16;
t2 = (xC2S6 * ip[6*8 + off]) >> 16;
_H = t1 - t2;
_Ed = _E - _G;
_Gd = _E + _G;
_Add = _F + _Ad;
_Bdd = _Bd - _H;
_Fd = _F - _Ad;
_Hd = _Bd + _H;
_Gd += IdctAdjustBeforeShift;
_Add += IdctAdjustBeforeShift;
_Ed += IdctAdjustBeforeShift;
_Fd += IdctAdjustBeforeShift;
/* Final sequence of operations over-write original inputs. */
op[0*8 + off] = (short)((_Gd + _Cd ) >> 4);
op[7*8 + off] = (short)((_Gd - _Cd ) >> 4);
op[1*8 + off] = (short)((_Add + _Hd ) >> 4);
op[2*8 + off] = (short)((_Add - _Hd ) >> 4);
op[3*8 + off] = (short)((_Ed + _Dd ) >> 4);
op[4*8 + off] = (short)((_Ed - _Dd ) >> 4);
op[5*8 + off] = (short)((_Fd + _Bdd ) >> 4);
op[6*8 + off] = (short)((_Fd - _Bdd ) >> 4);
}else{
op[0*8 + off] = 0;
op[7*8 + off] = 0;
op[1*8 + off] = 0;
op[2*8 + off] = 0;
op[3*8 + off] = 0;
op[4*8 + off] = 0;
op[5*8 + off] = 0;
op[6*8 + off] = 0;
}
}
}
/************************
x x x x 0 0 0 0
x x x 0 0 0 0 0
x x 0 0 0 0 0 0
x 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
*************************/
private final void dequant_slow10 (short[] dequant_coeffs,
short[] quantized_list,
int[] DCT_block)
{
for(int i=0; i<32; i++)
DCT_block[i] = 0;
for(int i=0; i<10; i++)
DCT_block[Constants.dequant_index[i]] = quantized_list[i] * dequant_coeffs[i];
}
public final void IDct10 (short[] InputData, short[]QuantMatrix, short[] OutputData)
{
short[] op = OutputData;
int _A, _B, _C, _D, _Ad, _Bd, _Cd, _Dd, _E, _F, _G, _H;
int _Ed, _Gd, _Add, _Bdd, _Fd, _Hd;
dequant_slow10 (QuantMatrix, InputData, ip);
/* Inverse DCT on the rows now */
for (int loop = 0, off = 0; loop < 4; loop++, off += 8){
/* Check for non-zero values */
if ((ip[0 + off] | ip[1 + off] | ip[2 + off] | ip[3 + off]) != 0 ){
_A = (xC1S7 * ip[1 + off]) >> 16;
_B = (xC7S1 * ip[1 + off]) >> 16;
_C = (xC3S5 * ip[3 + off]) >> 16;
_D = -((xC5S3 * ip[3 + off]) >> 16);
_Ad = (xC4S4 * (short)(_A - _C)) >> 16;
_Bd = (xC4S4 * (short)(_B - _D)) >> 16;
_Cd = _A + _C;
_Dd = _B + _D;
_E = (xC4S4 * ip[0 + off] ) >> 16;
_F = _E;
_G = (xC2S6 * ip[2 + off]) >> 16;
_H = (xC6S2 * ip[2 + off]) >> 16;
_Ed = _E - _G;
_Gd = _E + _G;
_Add = _F + _Ad;
_Bdd = _Bd - _H;
_Fd = _F - _Ad;
_Hd = _Bd + _H;
/* Final sequence of operations over-write original inputs. */
ip[0 + off] = (short)((_Gd + _Cd ) >> 0);
ip[7 + off] = (short)((_Gd - _Cd ) >> 0);
ip[1 + off] = (short)((_Add + _Hd ) >> 0);
ip[2 + off] = (short)((_Add - _Hd ) >> 0);
ip[3 + off] = (short)((_Ed + _Dd ) >> 0);
ip[4 + off] = (short)((_Ed - _Dd ) >> 0);
ip[5 + off] = (short)((_Fd + _Bdd ) >> 0);
ip[6 + off] = (short)((_Fd - _Bdd ) >> 0);
}
}
for (int loop = 0, off = 0; loop < 8; loop++, off++) {
/* Check for non-zero values (bitwise or faster than ||) */
if ((ip[0*8 + off] | ip[1*8 + off] | ip[2*8 + off] | ip[3*8 + off]) != 0) {
_A = (xC1S7 * ip[1*8 + off]) >> 16;
_B = (xC7S1 * ip[1*8 + off]) >> 16;
_C = (xC3S5 * ip[3*8 + off]) >> 16;
_D = -((xC5S3 * ip[3*8 + off]) >> 16);
_Ad = (xC4S4 * (short)(_A - _C)) >> 16;
_Bd = (xC4S4 * (short)(_B - _D)) >> 16;
_Cd = _A + _C;
_Dd = _B + _D;
_E = (xC4S4 * ip[0*8 + off]) >> 16;
_F = _E;
_G = (xC2S6 * ip[2*8 + off]) >> 16;
_H = (xC6S2 * ip[2*8 + off]) >> 16;
_Ed = _E - _G;
_Gd = _E + _G;
_Add = _F + _Ad;
_Bdd = _Bd - _H;
_Fd = _F - _Ad;
_Hd = _Bd + _H;
_Gd += IdctAdjustBeforeShift;
_Add += IdctAdjustBeforeShift;
_Ed += IdctAdjustBeforeShift;
_Fd += IdctAdjustBeforeShift;
/* Final sequence of operations over-write original inputs. */
op[0*8 + off] = (short)((_Gd + _Cd ) >> 4);
op[7*8 + off] = (short)((_Gd - _Cd ) >> 4);
op[1*8 + off] = (short)((_Add + _Hd ) >> 4);
op[2*8 + off] = (short)((_Add - _Hd ) >> 4);
op[3*8 + off] = (short)((_Ed + _Dd ) >> 4);
op[4*8 + off] = (short)((_Ed - _Dd ) >> 4);
op[5*8 + off] = (short)((_Fd + _Bdd ) >> 4);
op[6*8 + off] = (short)((_Fd - _Bdd ) >> 4);
}else{
op[0*8 + off] = 0;
op[7*8 + off] = 0;
op[1*8 + off] = 0;
op[2*8 + off] = 0;
op[3*8 + off] = 0;
op[4*8 + off] = 0;
op[5*8 + off] = 0;
op[6*8 + off] = 0;
}
}
}
/***************************
x 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
**************************/
public final void IDct1( short[] InputData,
short[]QuantMatrix,
short[] OutputData ){
short OutD=(short) ((int)(InputData[0]*QuantMatrix[0]+15)>>5);
for (int loop=0; loop<64; loop++)
OutputData[loop]=OutD;
}
}

View File

@@ -0,0 +1,294 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jogg;
public class OggBuffer{
private static final int BUFFER_INCREMENT=256;
private static final int[] mask= {0x00000000, 0x00000001, 0x00000003,
0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff,
0x00007fff, 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff, 0x01ffffff, 0x03ffffff,
0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff};
int ptr=0;
byte[] buffer=null;
int endbit=0;
int endbyte=0;
int storage=0;
public void writeinit(){
buffer=new byte[BUFFER_INCREMENT];
ptr=0;
buffer[0]=(byte)'\0';
storage=BUFFER_INCREMENT;
}
public void write(byte[] s){
for(int i=0; i<s.length; i++){
if(s[i]==0)
break;
write(s[i], 8);
}
}
public void read(byte[] s, int bytes){
int i=0;
while(bytes--!=0){
s[i++]=(byte)(read(8));
}
}
void reset(){
ptr=0;
buffer[0]=(byte)'\0';
endbit=endbyte=0;
}
public void writeclear(){
buffer=null;
}
public void readinit(byte[] buf, int bytes){
readinit(buf, 0, bytes);
}
public void readinit(byte[] buf, int start, int bytes){
ptr=start;
buffer=buf;
endbit=endbyte=0;
storage=bytes;
}
public void write(int value, int bits){
if(endbyte+4>=storage){
byte[] foo=new byte[storage+BUFFER_INCREMENT];
System.arraycopy(buffer, 0, foo, 0, storage);
buffer=foo;
storage+=BUFFER_INCREMENT;
}
value&=mask[bits];
bits+=endbit;
buffer[ptr]|=(byte)(value<<endbit);
if(bits>=8){
buffer[ptr+1]=(byte)(value>>>(8-endbit));
if(bits>=16){
buffer[ptr+2]=(byte)(value>>>(16-endbit));
if(bits>=24){
buffer[ptr+3]=(byte)(value>>>(24-endbit));
if(bits>=32){
if(endbit>0)
buffer[ptr+4]=(byte)(value>>>(32-endbit));
else
buffer[ptr+4]=0;
}
}
}
}
endbyte+=bits/8;
ptr+=bits/8;
endbit=bits&7;
}
public int look(int bits){
int ret;
int m=mask[bits];
bits+=endbit;
if(endbyte+4>=storage){
if(endbyte+(bits-1)/8>=storage)
return (-1);
}
ret=((buffer[ptr])&0xff)>>>endbit;
if(bits>8){
ret|=((buffer[ptr+1])&0xff)<<(8-endbit);
if(bits>16){
ret|=((buffer[ptr+2])&0xff)<<(16-endbit);
if(bits>24){
ret|=((buffer[ptr+3])&0xff)<<(24-endbit);
if(bits>32&&endbit!=0){
ret|=((buffer[ptr+4])&0xff)<<(32-endbit);
}
}
}
}
return (m&ret);
}
public int look1(){
if(endbyte>=storage)
return (-1);
return ((buffer[ptr]>>endbit)&1);
}
public void adv(int bits){
bits+=endbit;
ptr+=bits/8;
endbyte+=bits/8;
endbit=bits&7;
}
public void adv1(){
++endbit;
if(endbit>7){
endbit=0;
ptr++;
endbyte++;
}
}
public int read(int bits){
int ret;
int m=mask[bits];
bits+=endbit;
if(endbyte+4>=storage){
ret=-1;
if(endbyte+(bits-1)/8>=storage){
ptr+=bits/8;
endbyte+=bits/8;
endbit=bits&7;
return (ret);
}
}
ret=((buffer[ptr])&0xff)>>>endbit;
if(bits>8){
ret|=((buffer[ptr+1])&0xff)<<(8-endbit);
if(bits>16){
ret|=((buffer[ptr+2])&0xff)<<(16-endbit);
if(bits>24){
ret|=((buffer[ptr+3])&0xff)<<(24-endbit);
if(bits>32&&endbit!=0){
ret|=((buffer[ptr+4])&0xff)<<(32-endbit);
}
}
}
}
ret&=m;
ptr+=bits/8;
endbyte+=bits/8;
endbit=bits&7;
return (ret);
}
public int readB(int bits){
int ret;
int m=32-bits;
bits+=endbit;
if(endbyte+4>=storage){
/* not the main path */
ret=-1;
if(endbyte*8+bits>storage*8){
ptr+=bits/8;
endbyte+=bits/8;
endbit=bits&7;
return (ret);
}
}
ret=(buffer[ptr]&0xff)<<(24+endbit);
if(bits>8){
ret|=(buffer[ptr+1]&0xff)<<(16+endbit);
if(bits>16){
ret|=(buffer[ptr+2]&0xff)<<(8+endbit);
if(bits>24){
ret|=(buffer[ptr+3]&0xff)<<(endbit);
if(bits>32&&(endbit!=0))
ret|=(buffer[ptr+4]&0xff)>>(8-endbit);
}
}
}
ret=(ret>>>(m>>1))>>>((m+1)>>1);
ptr+=bits/8;
endbyte+=bits/8;
endbit=bits&7;
return (ret);
}
public int read1(){
int ret;
if(endbyte>=storage){
ret=-1;
endbit++;
if(endbit>7){
endbit=0;
ptr++;
endbyte++;
}
return (ret);
}
ret=(buffer[ptr]>>endbit)&1;
endbit++;
if(endbit>7){
endbit=0;
ptr++;
endbyte++;
}
return (ret);
}
public int bytes(){
return (endbyte+(endbit+7)/8);
}
public int bits(){
return (endbyte*8+endbit);
}
public byte[] buffer(){
return (buffer);
}
public static int ilog(int v){
int ret=0;
while(v>0){
ret++;
v>>>=1;
}
return (ret);
}
public static void report(String in){
System.err.println(in);
System.exit(1);
}
}

View File

@@ -0,0 +1,47 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jogg;
public class OggPacket{
public byte[] packet_base;
public int packet;
public int bytes;
public int b_o_s;
public int e_o_s;
public long granulepos;
/**
* sequence number for decode; the framing
* knows where there's a hole in the data,
* but we need coupling so that the codec
* (which is in a seperate abstraction
* layer) also knows about the gap
*/
public long packetno;
}

View File

@@ -0,0 +1,135 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jogg;
public class OggPage{
private static int[] crc_lookup=new int[256];
static{
for(int i=0; i<crc_lookup.length; i++){
crc_lookup[i]=crc_entry(i);
}
}
private static int crc_entry(int index){
int r=index<<24;
for(int i=0; i<8; i++){
if((r&0x80000000)!=0){
r=(r<<1)^0x04c11db7; /* The same as the ethernet generator
polynomial, although we use an
unreflected alg and an init/final
of 0, not 0xffffffff */
}
else{
r<<=1;
}
}
return (r&0xffffffff);
}
public byte[] header_base;
public int header;
public int header_len;
public byte[] body_base;
public int body;
public int body_len;
int version(){
return header_base[header+4]&0xff;
}
int continued(){
return (header_base[header+5]&0x01);
}
public int bos(){
return (header_base[header+5]&0x02);
}
public int eos(){
return (header_base[header+5]&0x04);
}
public long granulepos(){
long foo=header_base[header+13]&0xff;
foo=(foo<<8)|(header_base[header+12]&0xff);
foo=(foo<<8)|(header_base[header+11]&0xff);
foo=(foo<<8)|(header_base[header+10]&0xff);
foo=(foo<<8)|(header_base[header+9]&0xff);
foo=(foo<<8)|(header_base[header+8]&0xff);
foo=(foo<<8)|(header_base[header+7]&0xff);
foo=(foo<<8)|(header_base[header+6]&0xff);
return (foo);
}
public int serialno(){
return (header_base[header+14]&0xff)|((header_base[header+15]&0xff)<<8)
|((header_base[header+16]&0xff)<<16)
|((header_base[header+17]&0xff)<<24);
}
int pageno(){
return (header_base[header+18]&0xff)|((header_base[header+19]&0xff)<<8)
|((header_base[header+20]&0xff)<<16)
|((header_base[header+21]&0xff)<<24);
}
void checksum(){
int crc_reg=0;
for(int i=0; i<header_len; i++){
crc_reg=(crc_reg<<8)
^crc_lookup[((crc_reg>>>24)&0xff)^(header_base[header+i]&0xff)];
}
for(int i=0; i<body_len; i++){
crc_reg=(crc_reg<<8)
^crc_lookup[((crc_reg>>>24)&0xff)^(body_base[body+i]&0xff)];
}
header_base[header+22]=(byte)crc_reg;
header_base[header+23]=(byte)(crc_reg>>>8);
header_base[header+24]=(byte)(crc_reg>>>16);
header_base[header+25]=(byte)(crc_reg>>>24);
}
public OggPage copy(){
return copy(new OggPage());
}
public OggPage copy(OggPage p){
byte[] tmp=new byte[header_len];
System.arraycopy(header_base, header, tmp, 0, header_len);
p.header_len=header_len;
p.header_base=tmp;
p.header=0;
tmp=new byte[body_len];
System.arraycopy(body_base, body, tmp, 0, body_len);
p.body_len=body_len;
p.body_base=tmp;
p.body=0;
return p;
}
}

View File

@@ -0,0 +1,526 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jogg;
public class OggStreamState{
byte[] body_data; /* bytes from packet bodies */
int body_storage; /* storage elements allocated */
int body_fill; /* elements stored; fill mark */
private int body_returned; /* elements of fill returned */
int[] lacing_vals; /* The values that will go to the segment table */
long[] granule_vals; /* pcm_pos values for headers. Not compact
this way, but it is simple coupled to the
lacing fifo */
int lacing_storage;
int lacing_fill;
int lacing_packet;
int lacing_returned;
byte[] header=new byte[282]; /* working space for header encode */
int header_fill;
public int e_o_s; /* set when we have buffered the last packet in the
logical bitstream */
int b_o_s; /* set after we've written the initial page
of a logical bitstream */
int serialno;
int pageno;
long packetno; /* sequence number for decode; the framing
knows where there's a hole in the data,
but we need coupling so that the codec
(which is in a seperate abstraction
layer) also knows about the gap */
long granulepos;
public OggStreamState(){
init();
}
OggStreamState(int serialno){
this();
init(serialno);
}
void init(){
body_storage=16*1024;
body_data=new byte[body_storage];
lacing_storage=1024;
lacing_vals=new int[lacing_storage];
granule_vals=new long[lacing_storage];
}
public void init(int serialno){
if(body_data==null){
init();
}
else{
for(int i=0; i<body_data.length; i++)
body_data[i]=0;
for(int i=0; i<lacing_vals.length; i++)
lacing_vals[i]=0;
for(int i=0; i<granule_vals.length; i++)
granule_vals[i]=0;
}
this.serialno=serialno;
}
public void clear(){
body_data=null;
lacing_vals=null;
granule_vals=null;
}
void destroy(){
clear();
}
void body_expand(int needed){
if(body_storage<=body_fill+needed){
body_storage+=(needed+1024);
byte[] foo=new byte[body_storage];
System.arraycopy(body_data, 0, foo, 0, body_data.length);
body_data=foo;
}
}
void lacing_expand(int needed){
if(lacing_storage<=lacing_fill+needed){
lacing_storage+=(needed+32);
int[] foo=new int[lacing_storage];
System.arraycopy(lacing_vals, 0, foo, 0, lacing_vals.length);
lacing_vals=foo;
long[] bar=new long[lacing_storage];
System.arraycopy(granule_vals, 0, bar, 0, granule_vals.length);
granule_vals=bar;
}
}
/* submit data to the internal buffer of the framing engine */
public int packetin(OggPacket op){
int lacing_val=op.bytes/255+1;
if(body_returned!=0){
/* advance packet data according to the body_returned pointer. We
had to keep it around to return a pointer into the buffer last
call */
body_fill-=body_returned;
if(body_fill!=0){
System.arraycopy(body_data, body_returned, body_data, 0, body_fill);
}
body_returned=0;
}
/* make sure we have the buffer storage */
body_expand(op.bytes);
lacing_expand(lacing_val);
/* Copy in the submitted packet. Yes, the copy is a waste; this is
the liability of overly clean abstraction for the time being. It
will actually be fairly easy to eliminate the extra copy in the
future */
System.arraycopy(op.packet_base, op.packet, body_data, body_fill, op.bytes);
body_fill+=op.bytes;
/* Store lacing vals for this packet */
int j;
for(j=0; j<lacing_val-1; j++){
lacing_vals[lacing_fill+j]=255;
granule_vals[lacing_fill+j]=granulepos;
}
lacing_vals[lacing_fill+j]=(op.bytes)%255;
granulepos=granule_vals[lacing_fill+j]=op.granulepos;
/* flag the first segment as the beginning of the packet */
lacing_vals[lacing_fill]|=0x100;
lacing_fill+=lacing_val;
/* for the sake of completeness */
packetno++;
if(op.e_o_s!=0)
e_o_s=1;
return (0);
}
public int packetout(OggPacket op){
/* The last part of decode. We have the stream broken into packet
segments. Now we need to group them into packets (or return the
out of sync markers) */
int ptr=lacing_returned;
if(lacing_packet<=ptr){
return (0);
}
if((lacing_vals[ptr]&0x400)!=0){
/* We lost sync here; let the app know */
lacing_returned++;
/* we need to tell the codec there's a gap; it might need to
handle previous packet dependencies. */
packetno++;
return (-1);
}
/* Gather the whole packet. We'll have no holes or a partial packet */
{
int size=lacing_vals[ptr]&0xff;
int bytes=0;
op.packet_base=body_data;
op.packet=body_returned;
op.e_o_s=lacing_vals[ptr]&0x200; /* last packet of the stream? */
op.b_o_s=lacing_vals[ptr]&0x100; /* first packet of the stream? */
bytes+=size;
while(size==255){
int val=lacing_vals[++ptr];
size=val&0xff;
if((val&0x200)!=0)
op.e_o_s=0x200;
bytes+=size;
}
op.packetno=packetno;
op.granulepos=granule_vals[ptr];
op.bytes=bytes;
body_returned+=bytes;
lacing_returned=ptr+1;
}
packetno++;
return (1);
}
// add the incoming page to the stream state; we decompose the page
// into packet segments here as well.
public int pagein(OggPage og){
byte[] header_base=og.header_base;
int header=og.header;
byte[] body_base=og.body_base;
int body=og.body;
int bodysize=og.body_len;
int segptr=0;
int version=og.version();
int continued=og.continued();
int bos=og.bos();
int eos=og.eos();
long granulepos=og.granulepos();
int _serialno=og.serialno();
int _pageno=og.pageno();
int segments=header_base[header+26]&0xff;
// clean up 'returned data'
{
int lr=lacing_returned;
int br=body_returned;
// body data
if(br!=0){
body_fill-=br;
if(body_fill!=0){
System.arraycopy(body_data, br, body_data, 0, body_fill);
}
body_returned=0;
}
if(lr!=0){
// segment table
if((lacing_fill-lr)!=0){
System.arraycopy(lacing_vals, lr, lacing_vals, 0, lacing_fill-lr);
System.arraycopy(granule_vals, lr, granule_vals, 0, lacing_fill-lr);
}
lacing_fill-=lr;
lacing_packet-=lr;
lacing_returned=0;
}
}
// check the serial number
if(_serialno!=serialno)
return (-1);
if(version>0)
return (-1);
lacing_expand(segments+1);
// are we in sequence?
if(_pageno!=pageno){
int i;
// unroll previous partial packet (if any)
for(i=lacing_packet; i<lacing_fill; i++){
body_fill-=lacing_vals[i]&0xff;
//System.out.println("??");
}
lacing_fill=lacing_packet;
// make a note of dropped data in segment table
if(pageno!=-1){
lacing_vals[lacing_fill++]=0x400;
lacing_packet++;
}
// are we a 'continued packet' page? If so, we'll need to skip
// some segments
if(continued!=0){
bos=0;
for(; segptr<segments; segptr++){
int val=(header_base[header+27+segptr]&0xff);
body+=val;
bodysize-=val;
if(val<255){
segptr++;
break;
}
}
}
}
if(bodysize!=0){
body_expand(bodysize);
System.arraycopy(body_base, body, body_data, body_fill, bodysize);
body_fill+=bodysize;
}
{
int saved=-1;
while(segptr<segments){
int val=(header_base[header+27+segptr]&0xff);
lacing_vals[lacing_fill]=val;
granule_vals[lacing_fill]=-1;
if(bos!=0){
lacing_vals[lacing_fill]|=0x100;
bos=0;
}
if(val<255)
saved=lacing_fill;
lacing_fill++;
segptr++;
if(val<255)
lacing_packet=lacing_fill;
}
/* set the granulepos on the last pcmval of the last full packet */
if(saved!=-1){
granule_vals[saved]=granulepos;
}
}
if(eos!=0){
e_o_s=1;
if(lacing_fill>0)
lacing_vals[lacing_fill-1]|=0x200;
}
pageno=_pageno+1;
return (0);
}
/* This will flush remaining packets into a page (returning nonzero),
even if there is not enough data to trigger a flush normally
(undersized page). If there are no packets or partial packets to
flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
try to flush a normal sized page like ogg_stream_pageout; a call to
ogg_stream_flush does not gurantee that all packets have flushed.
Only a return value of 0 from ogg_stream_flush indicates all packet
data is flushed into pages.
ogg_stream_page will flush the last page in a stream even if it's
undersized; you almost certainly want to use ogg_stream_pageout
(and *not* ogg_stream_flush) unless you need to flush an undersized
page in the middle of a stream for some reason. */
public int flush(OggPage og){
int i;
int vals=0;
int maxvals=(lacing_fill>255 ? 255 : lacing_fill);
int bytes=0;
int acc=0;
long granule_pos=granule_vals[0];
if(maxvals==0)
return (0);
/* construct a page */
/* decide how many segments to include */
/* If this is the initial header case, the first page must only include
the initial header packet */
if(b_o_s==0){ /* 'initial header page' case */
granule_pos=0;
for(vals=0; vals<maxvals; vals++){
if((lacing_vals[vals]&0x0ff)<255){
vals++;
break;
}
}
}
else{
for(vals=0; vals<maxvals; vals++){
if(acc>4096)
break;
acc+=(lacing_vals[vals]&0x0ff);
granule_pos=granule_vals[vals];
}
}
/* construct the header in temp storage */
System.arraycopy("OggS".getBytes(), 0, header, 0, 4);
/* stream structure version */
header[4]=0x00;
/* continued packet flag? */
header[5]=0x00;
if((lacing_vals[0]&0x100)==0)
header[5]|=0x01;
/* first page flag? */
if(b_o_s==0)
header[5]|=0x02;
/* last page flag? */
if(e_o_s!=0&&lacing_fill==vals)
header[5]|=0x04;
b_o_s=1;
/* 64 bits of PCM position */
for(i=6; i<14; i++){
header[i]=(byte)granule_pos;
granule_pos>>>=8;
}
/* 32 bits of stream serial number */
{
int _serialno=serialno;
for(i=14; i<18; i++){
header[i]=(byte)_serialno;
_serialno>>>=8;
}
}
/* 32 bits of page counter (we have both counter and page header
because this val can roll over) */
if(pageno==-1)
pageno=0; /* because someone called
stream_reset; this would be a
strange thing to do in an
encode stream, but it has
plausible uses */
{
int _pageno=pageno++;
for(i=18; i<22; i++){
header[i]=(byte)_pageno;
_pageno>>>=8;
}
}
/* zero for computation; filled in later */
header[22]=0;
header[23]=0;
header[24]=0;
header[25]=0;
/* segment table */
header[26]=(byte)vals;
for(i=0; i<vals; i++){
header[i+27]=(byte)lacing_vals[i];
bytes+=(header[i+27]&0xff);
}
/* set pointers in the ogg_page struct */
og.header_base=header;
og.header=0;
og.header_len=header_fill=vals+27;
og.body_base=body_data;
og.body=body_returned;
og.body_len=bytes;
/* advance the lacing data and set the body_returned pointer */
lacing_fill-=vals;
System.arraycopy(lacing_vals, vals, lacing_vals, 0, lacing_fill*4);
System.arraycopy(granule_vals, vals, granule_vals, 0, lacing_fill*8);
body_returned+=bytes;
/* calculate the checksum */
og.checksum();
/* done */
return (1);
}
/* This constructs pages from buffered packet segments. The pointers
returned are to static buffers; do not free. The returned buffers are
good only until the next call (using the same ogg_stream_state) */
public int pageout(OggPage og){
if((e_o_s!=0&&lacing_fill!=0)|| /* 'were done, now flush' case */
body_fill-body_returned>4096|| /* 'page nominal size' case */
lacing_fill>=255|| /* 'segment table full' case */
(lacing_fill!=0&&b_o_s==0)){ /* 'initial header page' case */
return flush(og);
}
return 0;
}
public int eof(){
return e_o_s;
}
public int reset(){
body_fill=0;
body_returned=0;
lacing_fill=0;
lacing_packet=0;
lacing_returned=0;
header_fill=0;
e_o_s=0;
b_o_s=0;
pageno=-1;
packetno=0;
granulepos=0;
return (0);
}
}

View File

@@ -0,0 +1,275 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jogg;
// DECODING PRIMITIVES: packet streaming layer
// This has two layers to place more of the multi-serialno and paging
// control in the application's hands. First, we expose a data buffer
// using ogg_decode_buffer(). The app either copies into the
// buffer, or passes it directly to read(), etc. We then call
// ogg_decode_wrote() to tell how many bytes we just added.
//
// Pages are returned (pointers into the buffer in ogg_sync_state)
// by ogg_decode_stream(). The page is then submitted to
// ogg_decode_page() along with the appropriate
// ogg_stream_state* (ie, matching serialno). We then get raw
// packets out calling ogg_stream_packet() with a
// ogg_stream_state. See the 'frame-prog.txt' docs for details and
// example code.
public class OggSyncState{
public byte[] data;
int storage;
int fill;
int returned;
int unsynced;
int headerbytes;
int bodybytes;
public int clear(){
data=null;
return (0);
}
public int buffer(int size){
// first, clear out any space that has been previously returned
if(returned!=0){
fill-=returned;
if(fill>0){
System.arraycopy(data, returned, data, 0, fill);
}
returned=0;
}
if(size>storage-fill){
// We need to extend the internal buffer
int newsize=size+fill+4096; // an extra page to be nice
if(data!=null){
byte[] foo=new byte[newsize];
System.arraycopy(data, 0, foo, 0, data.length);
data=foo;
}
else{
data=new byte[newsize];
}
storage=newsize;
}
return (fill);
}
public int wrote(int bytes){
if(fill+bytes>storage)
return (-1);
fill+=bytes;
return (0);
}
// sync the stream. This is meant to be useful for finding page
// boundaries.
//
// return values for this:
// -n) skipped n bytes
// 0) page not ready; more data (no bytes skipped)
// n) page synced at current location; page length n bytes
private OggPage pageseek=new OggPage();
private byte[] chksum=new byte[4];
public int pageseek(OggPage og){
int page=returned;
int next;
int bytes=fill-returned;
if(headerbytes==0){
int _headerbytes, i;
if(bytes<27)
return (0); // not enough for a header
/* verify capture pattern */
if(data[page]!='O'||data[page+1]!='g'||data[page+2]!='g'
||data[page+3]!='S'){
headerbytes=0;
bodybytes=0;
// search for possible capture
next=0;
for(int ii=0; ii<bytes-1; ii++){
if(data[page+1+ii]=='O'){
next=page+1+ii;
break;
}
}
//next=memchr(page+1,'O',bytes-1);
if(next==0)
next=fill;
returned=next;
return (-(next-page));
}
_headerbytes=(data[page+26]&0xff)+27;
if(bytes<_headerbytes)
return (0); // not enough for header + seg table
// count up body length in the segment table
for(i=0; i<(data[page+26]&0xff); i++){
bodybytes+=(data[page+27+i]&0xff);
}
headerbytes=_headerbytes;
}
if(bodybytes+headerbytes>bytes)
return (0);
// The whole test page is buffered. Verify the checksum
synchronized(chksum){
// Grab the checksum bytes, set the header field to zero
System.arraycopy(data, page+22, chksum, 0, 4);
data[page+22]=0;
data[page+23]=0;
data[page+24]=0;
data[page+25]=0;
// set up a temp page struct and recompute the checksum
OggPage log=pageseek;
log.header_base=data;
log.header=page;
log.header_len=headerbytes;
log.body_base=data;
log.body=page+headerbytes;
log.body_len=bodybytes;
log.checksum();
// Compare
if(chksum[0]!=data[page+22]||chksum[1]!=data[page+23]
||chksum[2]!=data[page+24]||chksum[3]!=data[page+25]){
// D'oh. Mismatch! Corrupt page (or miscapture and not a page at all)
// replace the computed checksum with the one actually read in
System.arraycopy(chksum, 0, data, page+22, 4);
// Bad checksum. Lose sync */
headerbytes=0;
bodybytes=0;
// search for possible capture
next=0;
for(int ii=0; ii<bytes-1; ii++){
if(data[page+1+ii]=='O'){
next=page+1+ii;
break;
}
}
//next=memchr(page+1,'O',bytes-1);
if(next==0)
next=fill;
returned=next;
return (-(next-page));
}
}
// yes, have a whole page all ready to go
{
page=returned;
if(og!=null){
og.header_base=data;
og.header=page;
og.header_len=headerbytes;
og.body_base=data;
og.body=page+headerbytes;
og.body_len=bodybytes;
}
unsynced=0;
returned+=(bytes=headerbytes+bodybytes);
headerbytes=0;
bodybytes=0;
return (bytes);
}
}
// sync the stream and get a page. Keep trying until we find a page.
// Supress 'sync errors' after reporting the first.
//
// return values:
// -1) recapture (hole in data)
// 0) need more data
// 1) page returned
//
// Returns pointers into buffered data; invalidated by next call to
// _stream, _clear, _init, or _buffer
public int pageout(OggPage og){
// all we need to do is verify a page at the head of the stream
// buffer. If it doesn't verify, we look for the next potential
// frame
while(true){
int ret=pageseek(og);
if(ret>0){
// have a page
return (1);
}
if(ret==0){
// need more data
return (0);
}
// head did not start a synced page... skipped some bytes
if(unsynced==0){
unsynced=1;
return (-1);
}
// loop. keep looking
}
}
// clear things to an initial state. Good to call, eg, before seeking
public int reset(){
fill=0;
returned=0;
unsynced=0;
headerbytes=0;
bodybytes=0;
return (0);
}
public void init(){
}
public int getDataOffset(){
return returned;
}
public int getBufferOffset(){
return fill;
}
}

View File

@@ -0,0 +1,478 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
class CodeBook{
int dim; // codebook dimensions (elements per vector)
int entries; // codebook entries
StaticCodeBook c=new StaticCodeBook();
float[] valuelist; // list of dim*entries actual entry values
int[] codelist; // list of bitstream codewords for each entry
DecodeAux decode_tree;
// returns the number of bits
int encode(int a, OggBuffer b){
b.write(codelist[a], c.lengthlist[a]);
return (c.lengthlist[a]);
}
// One the encode side, our vector writers are each designed for a
// specific purpose, and the encoder is not flexible without modification:
//
// The LSP vector coder uses a single stage nearest-match with no
// interleave, so no step and no error return. This is specced by floor0
// and doesn't change.
//
// Residue0 encoding interleaves, uses multiple stages, and each stage
// peels of a specific amount of resolution from a lattice (thus we want
// to match by threshhold, not nearest match). Residue doesn't *have* to
// be encoded that way, but to change it, one will need to add more
// infrastructure on the encode side (decode side is specced and simpler)
// floor0 LSP (single stage, non interleaved, nearest match)
// returns entry number and *modifies a* to the quantization value
int errorv(float[] a){
int best=best(a, 1);
for(int k=0; k<dim; k++){
a[k]=valuelist[best*dim+k];
}
return (best);
}
// returns the number of bits and *modifies a* to the quantization value
int encodev(int best, float[] a, OggBuffer b){
for(int k=0; k<dim; k++){
a[k]=valuelist[best*dim+k];
}
return (encode(best, b));
}
// res0 (multistage, interleave, lattice)
// returns the number of bits and *modifies a* to the remainder value
int encodevs(float[] a, OggBuffer b, int step, int addmul){
int best=besterror(a, step, addmul);
return (encode(best, b));
}
private int[] t=new int[15]; // decodevs_add is synchronized for re-using t.
synchronized int decodevs_add(float[] a, int offset, OggBuffer b, int n){
int step=n/dim;
int entry;
int i, j, o;
if(t.length<step){
t=new int[step];
}
for(i=0; i<step; i++){
entry=decode(b);
if(entry==-1)
return (-1);
t[i]=entry*dim;
}
for(i=0, o=0; i<dim; i++, o+=step){
for(j=0; j<step; j++){
a[offset+o+j]+=valuelist[t[j]+i];
}
}
return (0);
}
int decodev_add(float[] a, int offset, OggBuffer b, int n){
int i, j, entry;
int t;
if(dim>8){
for(i=0; i<n;){
entry=decode(b);
if(entry==-1)
return (-1);
t=entry*dim;
for(j=0; j<dim;){
a[offset+(i++)]+=valuelist[t+(j++)];
}
}
}
else{
for(i=0; i<n;){
entry=decode(b);
if(entry==-1)
return (-1);
t=entry*dim;
j=0;
switch(dim){
case 8:
a[offset+(i++)]+=valuelist[t+(j++)];
case 7:
a[offset+(i++)]+=valuelist[t+(j++)];
case 6:
a[offset+(i++)]+=valuelist[t+(j++)];
case 5:
a[offset+(i++)]+=valuelist[t+(j++)];
case 4:
a[offset+(i++)]+=valuelist[t+(j++)];
case 3:
a[offset+(i++)]+=valuelist[t+(j++)];
case 2:
a[offset+(i++)]+=valuelist[t+(j++)];
case 1:
a[offset+(i++)]+=valuelist[t+(j++)];
case 0:
break;
}
}
}
return (0);
}
int decodev_set(float[] a, int offset, OggBuffer b, int n){
int i, j, entry;
int t;
for(i=0; i<n;){
entry=decode(b);
if(entry==-1)
return (-1);
t=entry*dim;
for(j=0; j<dim;){
a[offset+i++]=valuelist[t+(j++)];
}
}
return (0);
}
int decodevv_add(float[][] a, int offset, int ch, OggBuffer b, int n){
int i, j, entry;
int chptr=0;
for(i=offset/ch; i<(offset+n)/ch;){
entry=decode(b);
if(entry==-1)
return (-1);
int t=entry*dim;
for(j=0; j<dim; j++){
a[chptr++][i]+=valuelist[t+j];
if(chptr==ch){
chptr=0;
i++;
}
}
}
return (0);
}
// Decode side is specced and easier, because we don't need to find
// matches using different criteria; we simply read and map. There are
// two things we need to do 'depending':
//
// We may need to support interleave. We don't really, but it's
// convenient to do it here rather than rebuild the vector later.
//
// Cascades may be additive or multiplicitive; this is not inherent in
// the codebook, but set in the code using the codebook. Like
// interleaving, it's easiest to do it here.
// stage==0 -> declarative (set the value)
// stage==1 -> additive
// stage==2 -> multiplicitive
// returns the entry number or -1 on eof
int decode(OggBuffer b){
int ptr=0;
DecodeAux t=decode_tree;
int lok=b.look(t.tabn);
if(lok>=0){
ptr=t.tab[lok];
b.adv(t.tabl[lok]);
if(ptr<=0){
return -ptr;
}
}
do{
switch(b.read1()){
case 0:
ptr=t.ptr0[ptr];
break;
case 1:
ptr=t.ptr1[ptr];
break;
case -1:
default:
return (-1);
}
}
while(ptr>0);
return (-ptr);
}
// returns the entry number or -1 on eof
int decodevs(float[] a, int index, OggBuffer b, int step, int addmul){
int entry=decode(b);
if(entry==-1)
return (-1);
switch(addmul){
case -1:
for(int i=0, o=0; i<dim; i++, o+=step)
a[index+o]=valuelist[entry*dim+i];
break;
case 0:
for(int i=0, o=0; i<dim; i++, o+=step)
a[index+o]+=valuelist[entry*dim+i];
break;
case 1:
for(int i=0, o=0; i<dim; i++, o+=step)
a[index+o]*=valuelist[entry*dim+i];
break;
default:
//System.err.println("CodeBook.decodeves: addmul="+addmul);
}
return (entry);
}
int best(float[] a, int step){
// brute force it!
{
int besti=-1;
float best=0.f;
int e=0;
for(int i=0; i<entries; i++){
if(c.lengthlist[i]>0){
float _this=dist(dim, valuelist, e, a, step);
if(besti==-1||_this<best){
best=_this;
besti=i;
}
}
e+=dim;
}
return (besti);
}
}
// returns the entry number and *modifies a* to the remainder value
int besterror(float[] a, int step, int addmul){
int best=best(a, step);
switch(addmul){
case 0:
for(int i=0, o=0; i<dim; i++, o+=step)
a[o]-=valuelist[best*dim+i];
break;
case 1:
for(int i=0, o=0; i<dim; i++, o+=step){
float val=valuelist[best*dim+i];
if(val==0){
a[o]=0;
}
else{
a[o]/=val;
}
}
break;
}
return (best);
}
void clear(){
}
private static float dist(int el, float[] ref, int index, float[] b, int step){
float acc=(float)0.;
for(int i=0; i<el; i++){
float val=(ref[index+i]-b[i*step]);
acc+=val*val;
}
return (acc);
}
int init_decode(StaticCodeBook s){
c=s;
entries=s.entries;
dim=s.dim;
valuelist=s.unquantize();
decode_tree=make_decode_tree();
if(decode_tree==null){
clear();
return (-1);
}
return (0);
}
// given a list of word lengths, generate a list of codewords. Works
// for length ordered or unordered, always assigns the lowest valued
// codewords first. Extended to handle unused entries (length 0)
static int[] make_words(int[] l, int n){
int[] marker=new int[33];
int[] r=new int[n];
for(int i=0; i<n; i++){
int length=l[i];
if(length>0){
int entry=marker[length];
// when we claim a node for an entry, we also claim the nodes
// below it (pruning off the imagined tree that may have dangled
// from it) as well as blocking the use of any nodes directly
// above for leaves
// update ourself
if(length<32&&(entry>>>length)!=0){
// error condition; the lengths must specify an overpopulated tree
//free(r);
return (null);
}
r[i]=entry;
// Look to see if the next shorter marker points to the node
// above. if so, update it and repeat.
{
for(int j=length; j>0; j--){
if((marker[j]&1)!=0){
// have to jump branches
if(j==1)
marker[1]++;
else
marker[j]=marker[j-1]<<1;
break; // invariant says next upper marker would already
// have been moved if it was on the same path
}
marker[j]++;
}
}
// prune the tree; the implicit invariant says all the longer
// markers were dangling from our just-taken node. Dangle them
// from our *new* node.
for(int j=length+1; j<33; j++){
if((marker[j]>>>1)==entry){
entry=marker[j];
marker[j]=marker[j-1]<<1;
}
else{
break;
}
}
}
}
// bitreverse the words because our bitwise packer/unpacker is LSb
// endian
for(int i=0; i<n; i++){
int temp=0;
for(int j=0; j<l[i]; j++){
temp<<=1;
temp|=(r[i]>>>j)&1;
}
r[i]=temp;
}
return (r);
}
// build the decode helper tree from the codewords
DecodeAux make_decode_tree(){
int top=0;
DecodeAux t=new DecodeAux();
int[] ptr0=t.ptr0=new int[entries*2];
int[] ptr1=t.ptr1=new int[entries*2];
int[] codelist=make_words(c.lengthlist, c.entries);
if(codelist==null)
return (null);
t.aux=entries*2;
for(int i=0; i<entries; i++){
if(c.lengthlist[i]>0){
int ptr=0;
int j;
for(j=0; j<c.lengthlist[i]-1; j++){
int bit=(codelist[i]>>>j)&1;
if(bit==0){
if(ptr0[ptr]==0){
ptr0[ptr]=++top;
}
ptr=ptr0[ptr];
}
else{
if(ptr1[ptr]==0){
ptr1[ptr]=++top;
}
ptr=ptr1[ptr];
}
}
if(((codelist[i]>>>j)&1)==0){
ptr0[ptr]=-i;
}
else{
ptr1[ptr]=-i;
}
}
}
t.tabn=Util.ilog(entries)-4;
if(t.tabn<5)
t.tabn=5;
int n=1<<t.tabn;
t.tab=new int[n];
t.tabl=new int[n];
for(int i=0; i<n; i++){
int p=0;
int j=0;
for(j=0; j<t.tabn&&(p>0||j==0); j++){
if((i&(1<<j))!=0){
p=ptr1[p];
}
else{
p=ptr0[p];
}
}
t.tab[i]=p; // -code
t.tabl[i]=j; // length
}
return (t);
}
class DecodeAux{
int[] tab;
int[] tabl;
int tabn;
int[] ptr0;
int[] ptr1;
int aux; // number of tree entries
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,335 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
class Floor0 extends FuncFloor{
void pack(Object i, OggBuffer opb){
InfoFloor0 info=(InfoFloor0)i;
opb.write(info.order, 8);
opb.write(info.rate, 16);
opb.write(info.barkmap, 16);
opb.write(info.ampbits, 6);
opb.write(info.ampdB, 8);
opb.write(info.numbooks-1, 4);
for(int j=0; j<info.numbooks; j++)
opb.write(info.books[j], 8);
}
Object unpack(VorbisInfo vi, OggBuffer opb){
InfoFloor0 info=new InfoFloor0();
info.order=opb.read(8);
info.rate=opb.read(16);
info.barkmap=opb.read(16);
info.ampbits=opb.read(6);
info.ampdB=opb.read(8);
info.numbooks=opb.read(4)+1;
if((info.order<1)||(info.rate<1)||(info.barkmap<1)||(info.numbooks<1)){
return (null);
}
for(int j=0; j<info.numbooks; j++){
info.books[j]=opb.read(8);
if(info.books[j]<0||info.books[j]>=vi.books){
return (null);
}
}
return (info);
}
Object look(VorbisDspState vd, InfoMode mi, Object i){
float scale;
VorbisInfo vi=vd.vi;
InfoFloor0 info=(InfoFloor0)i;
LookFloor0 look=new LookFloor0();
look.m=info.order;
look.n=vi.blocksizes[mi.blockflag]/2;
look.ln=info.barkmap;
look.vi=info;
look.lpclook.init(look.ln, look.m);
// we choose a scaling constant so that:
scale=look.ln/toBARK((float)(info.rate/2.));
// the mapping from a linear scale to a smaller bark scale is
// straightforward. We do *not* make sure that the linear mapping
// does not skip bark-scale bins; the decoder simply skips them and
// the encoder may do what it wishes in filling them. They're
// necessary in some mapping combinations to keep the scale spacing
// accurate
look.linearmap=new int[look.n];
for(int j=0; j<look.n; j++){
int val=(int)Math.floor(toBARK((float)((info.rate/2.)/look.n*j))*scale); // bark numbers represent band edges
if(val>=look.ln)
val=look.ln; // guard against the approximation
look.linearmap[j]=val;
}
return look;
}
static float toBARK(float f){
return (float)(13.1*Math.atan(.00074*(f))+2.24*Math.atan((f)*(f)*1.85e-8)+1e-4*(f));
}
Object state(Object i){
EchstateFloor0 state=new EchstateFloor0();
InfoFloor0 info=(InfoFloor0)i;
// a safe size if usually too big (dim==1)
state.codewords=new int[info.order];
state.curve=new float[info.barkmap];
state.frameno=-1;
return (state);
}
void free_info(Object i){
}
void free_look(Object i){
}
void free_state(Object vs){
}
int forward(VorbisBlock vb, Object i, float[] in, float[] out, Object vs){
return 0;
}
float[] lsp=null;
int inverse(VorbisBlock vb, Object i, float[] out){
//System.err.println("Floor0.inverse "+i.getClass()+"]");
LookFloor0 look=(LookFloor0)i;
InfoFloor0 info=look.vi;
int ampraw=vb.opb.read(info.ampbits);
if(ampraw>0){ // also handles the -1 out of data case
int maxval=(1<<info.ampbits)-1;
float amp=(float)ampraw/maxval*info.ampdB;
int booknum=vb.opb.read(Util.ilog(info.numbooks));
if(booknum!=-1&&booknum<info.numbooks){
synchronized(this){
if(lsp==null||lsp.length<look.m){
lsp=new float[look.m];
}
else{
for(int j=0; j<look.m; j++)
lsp[j]=0.f;
}
CodeBook b=vb.vd.fullbooks[info.books[booknum]];
float last=0.f;
for(int j=0; j<look.m; j++)
out[j]=0.0f;
for(int j=0; j<look.m; j+=b.dim){
if(b.decodevs(lsp, j, vb.opb, 1, -1)==-1){
for(int k=0; k<look.n; k++)
out[k]=0.0f;
return (0);
}
}
for(int j=0; j<look.m;){
for(int k=0; k<b.dim; k++, j++)
lsp[j]+=last;
last=lsp[j-1];
}
// take the coefficients back to a spectral envelope curve
Lsp.lsp_to_curve(out, look.linearmap, look.n, look.ln, lsp, look.m,
amp, info.ampdB);
return (1);
}
}
}
return (0);
}
Object inverse1(VorbisBlock vb, Object i, Object memo){
LookFloor0 look=(LookFloor0)i;
InfoFloor0 info=look.vi;
float[] lsp=null;
if(memo instanceof float[]){
lsp=(float[])memo;
}
int ampraw=vb.opb.read(info.ampbits);
if(ampraw>0){ // also handles the -1 out of data case
int maxval=(1<<info.ampbits)-1;
float amp=(float)ampraw/maxval*info.ampdB;
int booknum=vb.opb.read(Util.ilog(info.numbooks));
if(booknum!=-1&&booknum<info.numbooks){
CodeBook b=vb.vd.fullbooks[info.books[booknum]];
float last=0.f;
if(lsp==null||lsp.length<look.m+1){
lsp=new float[look.m+1];
}
else{
for(int j=0; j<lsp.length; j++)
lsp[j]=0.f;
}
for(int j=0; j<look.m; j+=b.dim){
if(b.decodev_set(lsp, j, vb.opb, b.dim)==-1){
return (null);
}
}
for(int j=0; j<look.m;){
for(int k=0; k<b.dim; k++, j++)
lsp[j]+=last;
last=lsp[j-1];
}
lsp[look.m]=amp;
return (lsp);
}
}
return (null);
}
int inverse2(VorbisBlock vb, Object i, Object memo, float[] out){
LookFloor0 look=(LookFloor0)i;
InfoFloor0 info=look.vi;
if(memo!=null){
float[] lsp=(float[])memo;
float amp=lsp[look.m];
Lsp.lsp_to_curve(out, look.linearmap, look.n, look.ln, lsp, look.m, amp,
info.ampdB);
return (1);
}
for(int j=0; j<look.n; j++){
out[j]=0.f;
}
return (0);
}
static float fromdB(float x){
return (float)(Math.exp((x)*.11512925));
}
static void lsp_to_lpc(float[] lsp, float[] lpc, int m){
int i, j, m2=m/2;
float[] O=new float[m2];
float[] E=new float[m2];
float A;
float[] Ae=new float[m2+1];
float[] Ao=new float[m2+1];
float B;
float[] Be=new float[m2];
float[] Bo=new float[m2];
float temp;
// even/odd roots setup
for(i=0; i<m2; i++){
O[i]=(float)(-2.*Math.cos(lsp[i*2]));
E[i]=(float)(-2.*Math.cos(lsp[i*2+1]));
}
// set up impulse response
for(j=0; j<m2; j++){
Ae[j]=0.f;
Ao[j]=1.f;
Be[j]=0.f;
Bo[j]=1.f;
}
Ao[j]=1.f;
Ae[j]=1.f;
// run impulse response
for(i=1; i<m+1; i++){
A=B=0.f;
for(j=0; j<m2; j++){
temp=O[j]*Ao[j]+Ae[j];
Ae[j]=Ao[j];
Ao[j]=A;
A+=temp;
temp=E[j]*Bo[j]+Be[j];
Be[j]=Bo[j];
Bo[j]=B;
B+=temp;
}
lpc[i-1]=(A+Ao[j]+B-Ae[j])/2;
Ao[j]=A;
Ae[j]=B;
}
}
static void lpc_to_curve(float[] curve, float[] lpc, float amp, LookFloor0 l,
String name, int frameno){
// l->m+1 must be less than l->ln, but guard in case we get a bad stream
float[] lcurve=new float[Math.max(l.ln*2, l.m*2+2)];
if(amp==0){
for(int j=0; j<l.n; j++)
curve[j]=0.0f;
return;
}
l.lpclook.lpc_to_curve(lcurve, lpc, amp);
for(int i=0; i<l.n; i++)
curve[i]=lcurve[l.linearmap[i]];
}
class InfoFloor0{
int order;
int rate;
int barkmap;
int ampbits;
int ampdB;
int numbooks; // <= 16
int[] books=new int[16];
}
class LookFloor0{
int n;
int ln;
int m;
int[] linearmap;
InfoFloor0 vi;
Lpc lpclook=new Lpc();
}
class EchstateFloor0{
int[] codewords;
float[] curve;
long frameno;
long codes;
}
}

View File

@@ -0,0 +1,611 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
class Floor1 extends FuncFloor{
static final int floor1_rangedb=140;
static final int VIF_POSIT=63;
void pack(Object i, OggBuffer opb){
InfoFloor1 info=(InfoFloor1)i;
int count=0;
int rangebits;
int maxposit=info.postlist[1];
int maxclass=-1;
/* save out partitions */
opb.write(info.partitions, 5); /* only 0 to 31 legal */
for(int j=0; j<info.partitions; j++){
opb.write(info.partitionclass[j], 4); /* only 0 to 15 legal */
if(maxclass<info.partitionclass[j])
maxclass=info.partitionclass[j];
}
/* save out partition classes */
for(int j=0; j<maxclass+1; j++){
opb.write(info.class_dim[j]-1, 3); /* 1 to 8 */
opb.write(info.class_subs[j], 2); /* 0 to 3 */
if(info.class_subs[j]!=0){
opb.write(info.class_book[j], 8);
}
for(int k=0; k<(1<<info.class_subs[j]); k++){
opb.write(info.class_subbook[j][k]+1, 8);
}
}
/* save out the post list */
opb.write(info.mult-1, 2); /* only 1,2,3,4 legal now */
opb.write(Util.ilog2(maxposit), 4);
rangebits=Util.ilog2(maxposit);
for(int j=0, k=0; j<info.partitions; j++){
count+=info.class_dim[info.partitionclass[j]];
for(; k<count; k++){
opb.write(info.postlist[k+2], rangebits);
}
}
}
Object unpack(VorbisInfo vi, OggBuffer opb){
int count=0, maxclass=-1, rangebits;
InfoFloor1 info=new InfoFloor1();
/* read partitions */
info.partitions=opb.read(5); /* only 0 to 31 legal */
for(int j=0; j<info.partitions; j++){
info.partitionclass[j]=opb.read(4); /* only 0 to 15 legal */
if(maxclass<info.partitionclass[j])
maxclass=info.partitionclass[j];
}
/* read partition classes */
for(int j=0; j<maxclass+1; j++){
info.class_dim[j]=opb.read(3)+1; /* 1 to 8 */
info.class_subs[j]=opb.read(2); /* 0,1,2,3 bits */
if(info.class_subs[j]<0){
info.free();
return (null);
}
if(info.class_subs[j]!=0){
info.class_book[j]=opb.read(8);
}
if(info.class_book[j]<0||info.class_book[j]>=vi.books){
info.free();
return (null);
}
for(int k=0; k<(1<<info.class_subs[j]); k++){
info.class_subbook[j][k]=opb.read(8)-1;
if(info.class_subbook[j][k]<-1||info.class_subbook[j][k]>=vi.books){
info.free();
return (null);
}
}
}
/* read the post list */
info.mult=opb.read(2)+1; /* only 1,2,3,4 legal now */
rangebits=opb.read(4);
for(int j=0, k=0; j<info.partitions; j++){
count+=info.class_dim[info.partitionclass[j]];
for(; k<count; k++){
int t=info.postlist[k+2]=opb.read(rangebits);
if(t<0||t>=(1<<rangebits)){
info.free();
return (null);
}
}
}
info.postlist[0]=0;
info.postlist[1]=1<<rangebits;
return (info);
}
Object look(VorbisDspState vd, InfoMode mi, Object i){
int _n=0;
int[] sortpointer=new int[VIF_POSIT+2];
// Info vi=vd.vi;
InfoFloor1 info=(InfoFloor1)i;
LookFloor1 look=new LookFloor1();
look.vi=info;
look.n=info.postlist[1];
/* we drop each position value in-between already decoded values,
and use linear interpolation to predict each new value past the
edges. The positions are read in the order of the position
list... we precompute the bounding positions in the lookup. Of
course, the neighbors can change (if a position is declined), but
this is an initial mapping */
for(int j=0; j<info.partitions; j++){
_n+=info.class_dim[info.partitionclass[j]];
}
_n+=2;
look.posts=_n;
/* also store a sorted position index */
for(int j=0; j<_n; j++){
sortpointer[j]=j;
}
// qsort(sortpointer,n,sizeof(int),icomp); // !!
int foo;
for(int j=0; j<_n-1; j++){
for(int k=j; k<_n; k++){
if(info.postlist[sortpointer[j]]>info.postlist[sortpointer[k]]){
foo=sortpointer[k];
sortpointer[k]=sortpointer[j];
sortpointer[j]=foo;
}
}
}
/* points from sort order back to range number */
for(int j=0; j<_n; j++){
look.forward_index[j]=sortpointer[j];
}
/* points from range order to sorted position */
for(int j=0; j<_n; j++){
look.reverse_index[look.forward_index[j]]=j;
}
/* we actually need the post values too */
for(int j=0; j<_n; j++){
look.sorted_index[j]=info.postlist[look.forward_index[j]];
}
/* quantize values to multiplier spec */
switch(info.mult){
case 1: /* 1024 -> 256 */
look.quant_q=256;
break;
case 2: /* 1024 -> 128 */
look.quant_q=128;
break;
case 3: /* 1024 -> 86 */
look.quant_q=86;
break;
case 4: /* 1024 -> 64 */
look.quant_q=64;
break;
default:
look.quant_q=-1;
}
/* discover our neighbors for decode where we don't use fit flags
(that would push the neighbors outward) */
for(int j=0; j<_n-2; j++){
int lo=0;
int hi=1;
int lx=0;
int hx=look.n;
int currentx=info.postlist[j+2];
for(int k=0; k<j+2; k++){
int x=info.postlist[k];
if(x>lx&&x<currentx){
lo=k;
lx=x;
}
if(x<hx&&x>currentx){
hi=k;
hx=x;
}
}
look.loneighbor[j]=lo;
look.hineighbor[j]=hi;
}
return look;
}
void free_info(Object i){
}
void free_look(Object i){
}
void free_state(Object vs){
}
int forward(VorbisBlock vb, Object i, float[] in, float[] out, Object vs){
return 0;
}
Object inverse1(VorbisBlock vb, Object ii, Object memo){
LookFloor1 look=(LookFloor1)ii;
InfoFloor1 info=look.vi;
CodeBook[] books=vb.vd.fullbooks;
/* unpack wrapped/predicted values from stream */
if(vb.opb.read(1)==1){
int[] fit_value=null;
if(memo instanceof int[]){
fit_value=(int[])memo;
}
if(fit_value==null||fit_value.length<look.posts){
fit_value=new int[look.posts];
}
else{
for(int i=0; i<fit_value.length; i++)
fit_value[i]=0;
}
fit_value[0]=vb.opb.read(Util.ilog(look.quant_q-1));
fit_value[1]=vb.opb.read(Util.ilog(look.quant_q-1));
/* partition by partition */
for(int i=0, j=2; i<info.partitions; i++){
int clss=info.partitionclass[i];
int cdim=info.class_dim[clss];
int csubbits=info.class_subs[clss];
int csub=1<<csubbits;
int cval=0;
/* decode the partition's first stage cascade value */
if(csubbits!=0){
cval=books[info.class_book[clss]].decode(vb.opb);
if(cval==-1){
return (null);
}
}
for(int k=0; k<cdim; k++){
int book=info.class_subbook[clss][cval&(csub-1)];
cval>>>=csubbits;
if(book>=0){
if((fit_value[j+k]=books[book].decode(vb.opb))==-1){
return (null);
}
}
else{
fit_value[j+k]=0;
}
}
j+=cdim;
}
/* unwrap positive values and reconsitute via linear interpolation */
for(int i=2; i<look.posts; i++){
int predicted=render_point(info.postlist[look.loneighbor[i-2]],
info.postlist[look.hineighbor[i-2]],
fit_value[look.loneighbor[i-2]], fit_value[look.hineighbor[i-2]],
info.postlist[i]);
int hiroom=look.quant_q-predicted;
int loroom=predicted;
int room=(hiroom<loroom ? hiroom : loroom)<<1;
int val=fit_value[i];
if(val!=0){
if(val>=room){
if(hiroom>loroom){
val=val-loroom;
}
else{
val=-1-(val-hiroom);
}
}
else{
if((val&1)!=0){
val=-((val+1)>>>1);
}
else{
val>>=1;
}
}
fit_value[i]=val+predicted;
fit_value[look.loneighbor[i-2]]&=0x7fff;
fit_value[look.hineighbor[i-2]]&=0x7fff;
}
else{
fit_value[i]=predicted|0x8000;
}
}
return (fit_value);
}
return (null);
}
private static int render_point(int x0, int x1, int y0, int y1, int x){
y0&=0x7fff; /* mask off flag */
y1&=0x7fff;
{
int dy=y1-y0;
int adx=x1-x0;
int ady=Math.abs(dy);
int err=ady*(x-x0);
int off=(int)(err/adx);
if(dy<0)
return (y0-off);
return (y0+off);
}
}
int inverse2(VorbisBlock vb, Object i, Object memo, float[] out){
LookFloor1 look=(LookFloor1)i;
InfoFloor1 info=look.vi;
int n=vb.vd.vi.blocksizes[vb.mode]/2;
if(memo!=null){
/* render the lines */
int[] fit_value=(int[])memo;
int hx=0;
int lx=0;
int ly=fit_value[0]*info.mult;
for(int j=1; j<look.posts; j++){
int current=look.forward_index[j];
int hy=fit_value[current]&0x7fff;
if(hy==fit_value[current]){
hy*=info.mult;
hx=info.postlist[current];
render_line(lx, hx, ly, hy, out);
lx=hx;
ly=hy;
}
}
for(int j=hx; j<n; j++){
out[j]*=out[j-1]; /* be certain */
}
return (1);
}
for(int j=0; j<n; j++){
out[j]=0.f;
}
return (0);
}
private static float[] FLOOR_fromdB_LOOKUP= {1.0649863e-07F, 1.1341951e-07F,
1.2079015e-07F, 1.2863978e-07F, 1.3699951e-07F, 1.4590251e-07F,
1.5538408e-07F, 1.6548181e-07F, 1.7623575e-07F, 1.8768855e-07F,
1.9988561e-07F, 2.128753e-07F, 2.2670913e-07F, 2.4144197e-07F,
2.5713223e-07F, 2.7384213e-07F, 2.9163793e-07F, 3.1059021e-07F,
3.3077411e-07F, 3.5226968e-07F, 3.7516214e-07F, 3.9954229e-07F,
4.2550680e-07F, 4.5315863e-07F, 4.8260743e-07F, 5.1396998e-07F,
5.4737065e-07F, 5.8294187e-07F, 6.2082472e-07F, 6.6116941e-07F,
7.0413592e-07F, 7.4989464e-07F, 7.9862701e-07F, 8.5052630e-07F,
9.0579828e-07F, 9.6466216e-07F, 1.0273513e-06F, 1.0941144e-06F,
1.1652161e-06F, 1.2409384e-06F, 1.3215816e-06F, 1.4074654e-06F,
1.4989305e-06F, 1.5963394e-06F, 1.7000785e-06F, 1.8105592e-06F,
1.9282195e-06F, 2.0535261e-06F, 2.1869758e-06F, 2.3290978e-06F,
2.4804557e-06F, 2.6416497e-06F, 2.8133190e-06F, 2.9961443e-06F,
3.1908506e-06F, 3.3982101e-06F, 3.6190449e-06F, 3.8542308e-06F,
4.1047004e-06F, 4.3714470e-06F, 4.6555282e-06F, 4.9580707e-06F,
5.2802740e-06F, 5.6234160e-06F, 5.9888572e-06F, 6.3780469e-06F,
6.7925283e-06F, 7.2339451e-06F, 7.7040476e-06F, 8.2047000e-06F,
8.7378876e-06F, 9.3057248e-06F, 9.9104632e-06F, 1.0554501e-05F,
1.1240392e-05F, 1.1970856e-05F, 1.2748789e-05F, 1.3577278e-05F,
1.4459606e-05F, 1.5399272e-05F, 1.6400004e-05F, 1.7465768e-05F,
1.8600792e-05F, 1.9809576e-05F, 2.1096914e-05F, 2.2467911e-05F,
2.3928002e-05F, 2.5482978e-05F, 2.7139006e-05F, 2.8902651e-05F,
3.0780908e-05F, 3.2781225e-05F, 3.4911534e-05F, 3.7180282e-05F,
3.9596466e-05F, 4.2169667e-05F, 4.4910090e-05F, 4.7828601e-05F,
5.0936773e-05F, 5.4246931e-05F, 5.7772202e-05F, 6.1526565e-05F,
6.5524908e-05F, 6.9783085e-05F, 7.4317983e-05F, 7.9147585e-05F,
8.4291040e-05F, 8.9768747e-05F, 9.5602426e-05F, 0.00010181521F,
0.00010843174F, 0.00011547824F, 0.00012298267F, 0.00013097477F,
0.00013948625F, 0.00014855085F, 0.00015820453F, 0.00016848555F,
0.00017943469F, 0.00019109536F, 0.00020351382F, 0.00021673929F,
0.00023082423F, 0.00024582449F, 0.00026179955F, 0.00027881276F,
0.00029693158F, 0.00031622787F, 0.00033677814F, 0.00035866388F,
0.00038197188F, 0.00040679456F, 0.00043323036F, 0.00046138411F,
0.00049136745F, 0.00052329927F, 0.00055730621F, 0.00059352311F,
0.00063209358F, 0.00067317058F, 0.00071691700F, 0.00076350630F,
0.00081312324F, 0.00086596457F, 0.00092223983F, 0.00098217216F,
0.0010459992F, 0.0011139742F, 0.0011863665F, 0.0012634633F,
0.0013455702F, 0.0014330129F, 0.0015261382F, 0.0016253153F,
0.0017309374F, 0.0018434235F, 0.0019632195F, 0.0020908006F,
0.0022266726F, 0.0023713743F, 0.0025254795F, 0.0026895994F,
0.0028643847F, 0.0030505286F, 0.0032487691F, 0.0034598925F,
0.0036847358F, 0.0039241906F, 0.0041792066F, 0.0044507950F,
0.0047400328F, 0.0050480668F, 0.0053761186F, 0.0057254891F,
0.0060975636F, 0.0064938176F, 0.0069158225F, 0.0073652516F,
0.0078438871F, 0.0083536271F, 0.0088964928F, 0.009474637F, 0.010090352F,
0.010746080F, 0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F,
0.014722068F, 0.015678791F, 0.016697687F, 0.017782797F, 0.018938423F,
0.020169149F, 0.021479854F, 0.022875735F, 0.024362330F, 0.025945531F,
0.027631618F, 0.029427276F, 0.031339626F, 0.033376252F, 0.035545228F,
0.037855157F, 0.040315199F, 0.042935108F, 0.045725273F, 0.048696758F,
0.051861348F, 0.055231591F, 0.058820850F, 0.062643361F, 0.066714279F,
0.071049749F, 0.075666962F, 0.080584227F, 0.085821044F, 0.091398179F,
0.097337747F, 0.10366330F, 0.11039993F, 0.11757434F, 0.12521498F,
0.13335215F, 0.14201813F, 0.15124727F, 0.16107617F, 0.17154380F,
0.18269168F, 0.19456402F, 0.20720788F, 0.22067342F, 0.23501402F,
0.25028656F, 0.26655159F, 0.28387361F, 0.30232132F, 0.32196786F,
0.34289114F, 0.36517414F, 0.38890521F, 0.41417847F, 0.44109412F,
0.46975890F, 0.50028648F, 0.53279791F, 0.56742212F, 0.60429640F,
0.64356699F, 0.68538959F, 0.72993007F, 0.77736504F, 0.82788260F,
0.88168307F, 0.9389798F, 1.F};
private static void render_line(int x0, int x1, int y0, int y1, float[] d){
int dy=y1-y0;
int adx=x1-x0;
int ady=Math.abs(dy);
int base=dy/adx;
int sy=(dy<0 ? base-1 : base+1);
int x=x0;
int y=y0;
int err=0;
ady-=Math.abs(base*adx);
d[x]*=FLOOR_fromdB_LOOKUP[y];
while(++x<x1){
err=err+ady;
if(err>=adx){
err-=adx;
y+=sy;
}
else{
y+=base;
}
d[x]*=FLOOR_fromdB_LOOKUP[y];
}
}
class InfoFloor1{
static final int VIF_POSIT=63;
static final int VIF_CLASS=16;
static final int VIF_PARTS=31;
int partitions; /* 0 to 31 */
int[] partitionclass=new int[VIF_PARTS]; /* 0 to 15 */
int[] class_dim=new int[VIF_CLASS]; /* 1 to 8 */
int[] class_subs=new int[VIF_CLASS]; /* 0,1,2,3 (bits: 1<<n poss) */
int[] class_book=new int[VIF_CLASS]; /* subs ^ dim entries */
int[][] class_subbook=new int[VIF_CLASS][]; /* [VIF_CLASS][subs] */
int mult; /* 1 2 3 or 4 */
int[] postlist=new int[VIF_POSIT+2]; /* first two implicit */
/* encode side analysis parameters */
float maxover;
float maxunder;
float maxerr;
int twofitminsize;
int twofitminused;
int twofitweight;
float twofitatten;
int unusedminsize;
int unusedmin_n;
int n;
InfoFloor1(){
for(int i=0; i<class_subbook.length; i++){
class_subbook[i]=new int[8];
}
}
void free(){
partitionclass=null;
class_dim=null;
class_subs=null;
class_book=null;
class_subbook=null;
postlist=null;
}
Object copy_info(){
InfoFloor1 info=this;
InfoFloor1 ret=new InfoFloor1();
ret.partitions=info.partitions;
System
.arraycopy(info.partitionclass, 0, ret.partitionclass, 0, VIF_PARTS);
System.arraycopy(info.class_dim, 0, ret.class_dim, 0, VIF_CLASS);
System.arraycopy(info.class_subs, 0, ret.class_subs, 0, VIF_CLASS);
System.arraycopy(info.class_book, 0, ret.class_book, 0, VIF_CLASS);
for(int j=0; j<VIF_CLASS; j++){
System.arraycopy(info.class_subbook[j], 0, ret.class_subbook[j], 0, 8);
}
ret.mult=info.mult;
System.arraycopy(info.postlist, 0, ret.postlist, 0, VIF_POSIT+2);
ret.maxover=info.maxover;
ret.maxunder=info.maxunder;
ret.maxerr=info.maxerr;
ret.twofitminsize=info.twofitminsize;
ret.twofitminused=info.twofitminused;
ret.twofitweight=info.twofitweight;
ret.twofitatten=info.twofitatten;
ret.unusedminsize=info.unusedminsize;
ret.unusedmin_n=info.unusedmin_n;
ret.n=info.n;
return (ret);
}
}
class LookFloor1{
static final int VIF_POSIT=63;
int[] sorted_index=new int[VIF_POSIT+2];
int[] forward_index=new int[VIF_POSIT+2];
int[] reverse_index=new int[VIF_POSIT+2];
int[] hineighbor=new int[VIF_POSIT];
int[] loneighbor=new int[VIF_POSIT];
int posts;
int n;
int quant_q;
InfoFloor1 vi;
int phrasebits;
int postbits;
int frames;
void free(){
sorted_index=null;
forward_index=null;
reverse_index=null;
hineighbor=null;
loneighbor=null;
}
}
class Lsfit_acc{
long x0;
long x1;
long xa;
long ya;
long x2a;
long y2a;
long xya;
long n;
long an;
long un;
long edgey0;
long edgey1;
}
class EchstateFloor1{
int[] codewords;
float[] curve;
long frameno;
long codes;
}
}

View File

@@ -0,0 +1,52 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
abstract class FuncFloor{
public static FuncFloor[] floor_P= {new Floor0(), new Floor1()};
abstract void pack(Object i, OggBuffer opb);
abstract Object unpack(VorbisInfo vi, OggBuffer opb);
abstract Object look(VorbisDspState vd, InfoMode mi, Object i);
abstract void free_info(Object i);
abstract void free_look(Object i);
abstract void free_state(Object vs);
abstract int forward(VorbisBlock vb, Object i, float[] in, float[] out, Object vs);
abstract Object inverse1(VorbisBlock vb, Object i, Object memo);
abstract int inverse2(VorbisBlock vb, Object i, Object memo, float[] out);
}

View File

@@ -0,0 +1,45 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
abstract class FuncMapping{
public static FuncMapping[] mapping_P= {new Mapping0()};
abstract void pack(VorbisInfo info, Object imap, OggBuffer buffer);
abstract Object unpack(VorbisInfo info, OggBuffer buffer);
abstract Object look(VorbisDspState vd, InfoMode vm, Object m);
abstract void free_info(Object imap);
abstract void free_look(Object imap);
abstract int inverse(VorbisBlock vd, Object lm);
}

View File

@@ -0,0 +1,46 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
abstract class FuncResidue{
public static FuncResidue[] residue_P= {new Residue0(), new Residue1(),
new Residue2()};
abstract void pack(Object vr, OggBuffer opb);
abstract Object unpack(VorbisInfo vi, OggBuffer opb);
abstract Object look(VorbisDspState vd, InfoMode vm, Object vr);
abstract void free_info(Object i);
abstract void free_look(Object i);
abstract int inverse(VorbisBlock vb, Object vl, float[][] in, int[] nonzero, int ch);
}

View File

@@ -0,0 +1,45 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
abstract class FuncTime{
public static FuncTime[] time_P= {new Time0()};
abstract void pack(Object i, OggBuffer opb);
abstract Object unpack(VorbisInfo vi, OggBuffer opb);
abstract Object look(VorbisDspState vd, InfoMode vm, Object i);
abstract void free_info(Object i);
abstract void free_look(Object i);
abstract int inverse(VorbisBlock vb, Object i, float[] in, float[] out);
}

View File

@@ -0,0 +1,34 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
class InfoMode{
int blockflag;
int windowtype;
int transformtype;
int mapping;
}

View File

@@ -0,0 +1,40 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
public class JOrbisException extends Exception{
private static final long serialVersionUID=1L;
public JOrbisException(){
super();
}
public JOrbisException(String s){
super("JOrbis: "+s);
}
}

View File

@@ -0,0 +1,152 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
class Lookup{
static final int COS_LOOKUP_SZ=128;
static final float[] COS_LOOKUP= {+1.0000000000000f, +0.9996988186962f,
+0.9987954562052f, +0.9972904566787f, +0.9951847266722f,
+0.9924795345987f, +0.9891765099648f, +0.9852776423889f,
+0.9807852804032f, +0.9757021300385f, +0.9700312531945f,
+0.9637760657954f, +0.9569403357322f, +0.9495281805930f,
+0.9415440651830f, +0.9329927988347f, +0.9238795325113f,
+0.9142097557035f, +0.9039892931234f, +0.8932243011955f,
+0.8819212643484f, +0.8700869911087f, +0.8577286100003f,
+0.8448535652497f, +0.8314696123025f, +0.8175848131516f,
+0.8032075314806f, +0.7883464276266f, +0.7730104533627f,
+0.7572088465065f, +0.7409511253550f, +0.7242470829515f,
+0.7071067811865f, +0.6895405447371f, +0.6715589548470f,
+0.6531728429538f, +0.6343932841636f, +0.6152315905806f,
+0.5956993044924f, +0.5758081914178f, +0.5555702330196f,
+0.5349976198871f, +0.5141027441932f, +0.4928981922298f,
+0.4713967368260f, +0.4496113296546f, +0.4275550934303f,
+0.4052413140050f, +0.3826834323651f, +0.3598950365350f,
+0.3368898533922f, +0.3136817403989f, +0.2902846772545f,
+0.2667127574749f, +0.2429801799033f, +0.2191012401569f,
+0.1950903220161f, +0.1709618887603f, +0.1467304744554f,
+0.1224106751992f, +0.0980171403296f, +0.0735645635997f,
+0.0490676743274f, +0.0245412285229f, +0.0000000000000f,
-0.0245412285229f, -0.0490676743274f, -0.0735645635997f,
-0.0980171403296f, -0.1224106751992f, -0.1467304744554f,
-0.1709618887603f, -0.1950903220161f, -0.2191012401569f,
-0.2429801799033f, -0.2667127574749f, -0.2902846772545f,
-0.3136817403989f, -0.3368898533922f, -0.3598950365350f,
-0.3826834323651f, -0.4052413140050f, -0.4275550934303f,
-0.4496113296546f, -0.4713967368260f, -0.4928981922298f,
-0.5141027441932f, -0.5349976198871f, -0.5555702330196f,
-0.5758081914178f, -0.5956993044924f, -0.6152315905806f,
-0.6343932841636f, -0.6531728429538f, -0.6715589548470f,
-0.6895405447371f, -0.7071067811865f, -0.7242470829515f,
-0.7409511253550f, -0.7572088465065f, -0.7730104533627f,
-0.7883464276266f, -0.8032075314806f, -0.8175848131516f,
-0.8314696123025f, -0.8448535652497f, -0.8577286100003f,
-0.8700869911087f, -0.8819212643484f, -0.8932243011955f,
-0.9039892931234f, -0.9142097557035f, -0.9238795325113f,
-0.9329927988347f, -0.9415440651830f, -0.9495281805930f,
-0.9569403357322f, -0.9637760657954f, -0.9700312531945f,
-0.9757021300385f, -0.9807852804032f, -0.9852776423889f,
-0.9891765099648f, -0.9924795345987f, -0.9951847266722f,
-0.9972904566787f, -0.9987954562052f, -0.9996988186962f,
-1.0000000000000f,};
/* interpolated lookup based cos function, domain 0 to PI only */
static float coslook(float a){
double d=a*(.31830989*(float)COS_LOOKUP_SZ);
int i=(int)d;
return COS_LOOKUP[i]+((float)(d-i))*(COS_LOOKUP[i+1]-COS_LOOKUP[i]);
}
static final int INVSQ_LOOKUP_SZ=32;
static final float[] INVSQ_LOOKUP= {1.414213562373f, 1.392621247646f,
1.371988681140f, 1.352246807566f, 1.333333333333f, 1.315191898443f,
1.297771369046f, 1.281025230441f, 1.264911064067f, 1.249390095109f,
1.234426799697f, 1.219988562661f, 1.206045378311f, 1.192569588000f,
1.179535649239f, 1.166919931983f, 1.154700538379f, 1.142857142857f,
1.131370849898f, 1.120224067222f, 1.109400392450f, 1.098884511590f,
1.088662107904f, 1.078719779941f, 1.069044967650f, 1.059625885652f,
1.050451462878f, 1.041511287847f, 1.032795558989f, 1.024295039463f,
1.016001016002f, 1.007905261358f, 1.000000000000f,};
/* interpolated 1./sqrt(p) where .5 <= p < 1. */
static float invsqlook(float a){
double d=a*(2.f*(float)INVSQ_LOOKUP_SZ)-(float)INVSQ_LOOKUP_SZ;
int i=(int)d;
return INVSQ_LOOKUP[i]+((float)(d-i))*(INVSQ_LOOKUP[i+1]-INVSQ_LOOKUP[i]);
}
static final int INVSQ2EXP_LOOKUP_MIN=-32;
static final int INVSQ2EXP_LOOKUP_MAX=32;
static final float[] INVSQ2EXP_LOOKUP= {65536.f, 46340.95001f, 32768.f,
23170.47501f, 16384.f, 11585.2375f, 8192.f, 5792.618751f, 4096.f,
2896.309376f, 2048.f, 1448.154688f, 1024.f, 724.0773439f, 512.f,
362.038672f, 256.f, 181.019336f, 128.f, 90.50966799f, 64.f, 45.254834f,
32.f, 22.627417f, 16.f, 11.3137085f, 8.f, 5.656854249f, 4.f,
2.828427125f, 2.f, 1.414213562f, 1.f, 0.7071067812f, 0.5f, 0.3535533906f,
0.25f, 0.1767766953f, 0.125f, 0.08838834765f, 0.0625f, 0.04419417382f,
0.03125f, 0.02209708691f, 0.015625f, 0.01104854346f, 0.0078125f,
0.005524271728f, 0.00390625f, 0.002762135864f, 0.001953125f,
0.001381067932f, 0.0009765625f, 0.000690533966f, 0.00048828125f,
0.000345266983f, 0.000244140625f, 0.0001726334915f, 0.0001220703125f,
8.631674575e-05f, 6.103515625e-05f, 4.315837288e-05f, 3.051757812e-05f,
2.157918644e-05f, 1.525878906e-05f,};
/* interpolated 1./sqrt(p) where .5 <= p < 1. */
static float invsq2explook(int a){
return INVSQ2EXP_LOOKUP[a-INVSQ2EXP_LOOKUP_MIN];
}
static final int FROMdB_LOOKUP_SZ=35;
static final int FROMdB2_LOOKUP_SZ=32;
static final int FROMdB_SHIFT=5;
static final int FROMdB2_SHIFT=3;
static final int FROMdB2_MASK=31;
static final float[] FROMdB_LOOKUP= {1.f, 0.6309573445f, 0.3981071706f,
0.2511886432f, 0.1584893192f, 0.1f, 0.06309573445f, 0.03981071706f,
0.02511886432f, 0.01584893192f, 0.01f, 0.006309573445f, 0.003981071706f,
0.002511886432f, 0.001584893192f, 0.001f, 0.0006309573445f,
0.0003981071706f, 0.0002511886432f, 0.0001584893192f, 0.0001f,
6.309573445e-05f, 3.981071706e-05f, 2.511886432e-05f, 1.584893192e-05f,
1e-05f, 6.309573445e-06f, 3.981071706e-06f, 2.511886432e-06f,
1.584893192e-06f, 1e-06f, 6.309573445e-07f, 3.981071706e-07f,
2.511886432e-07f, 1.584893192e-07f,};
static final float[] FROMdB2_LOOKUP= {0.9928302478f, 0.9786445908f,
0.9646616199f, 0.9508784391f, 0.9372921937f, 0.92390007f, 0.9106992942f,
0.8976871324f, 0.8848608897f, 0.8722179097f, 0.8597555737f,
0.8474713009f, 0.835362547f, 0.8234268041f, 0.8116616003f, 0.8000644989f,
0.7886330981f, 0.7773650302f, 0.7662579617f, 0.755309592f, 0.7445176537f,
0.7338799116f, 0.7233941627f, 0.7130582353f, 0.7028699885f,
0.6928273125f, 0.6829281272f, 0.6731703824f, 0.6635520573f,
0.6540711597f, 0.6447257262f, 0.6355138211f,};
/* interpolated lookup based fromdB function, domain -140dB to 0dB only */
static float fromdBlook(float a){
int i=(int)(a*((float)(-(1<<FROMdB2_SHIFT))));
return (i<0) ? 1.f : ((i>=(FROMdB_LOOKUP_SZ<<FROMdB_SHIFT)) ? 0.f
: FROMdB_LOOKUP[i>>>FROMdB_SHIFT]*FROMdB2_LOOKUP[i&FROMdB2_MASK]);
}
}

View File

@@ -0,0 +1,188 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
class Lpc{
// en/decode lookups
Drft fft=new Drft();;
int ln;
int m;
// Autocorrelation LPC coeff generation algorithm invented by
// N. Levinson in 1947, modified by J. Durbin in 1959.
// Input : n elements of time doamin data
// Output: m lpc coefficients, excitation energy
static float lpc_from_data(float[] data, float[] lpc, int n, int m){
float[] aut=new float[m+1];
float error;
int i, j;
// autocorrelation, p+1 lag coefficients
j=m+1;
while(j--!=0){
float d=0;
for(i=j; i<n; i++)
d+=data[i]*data[i-j];
aut[j]=d;
}
// Generate lpc coefficients from autocorr values
error=aut[0];
/*
if(error==0){
for(int k=0; k<m; k++) lpc[k]=0.0f;
return 0;
}
*/
for(i=0; i<m; i++){
float r=-aut[i+1];
if(error==0){
for(int k=0; k<m; k++)
lpc[k]=0.0f;
return 0;
}
// Sum up this iteration's reflection coefficient; note that in
// Vorbis we don't save it. If anyone wants to recycle this code
// and needs reflection coefficients, save the results of 'r' from
// each iteration.
for(j=0; j<i; j++)
r-=lpc[j]*aut[i-j];
r/=error;
// Update LPC coefficients and total error
lpc[i]=r;
for(j=0; j<i/2; j++){
float tmp=lpc[j];
lpc[j]+=r*lpc[i-1-j];
lpc[i-1-j]+=r*tmp;
}
if(i%2!=0)
lpc[j]+=lpc[j]*r;
error*=1.0-r*r;
}
// we need the error value to know how big an impulse to hit the
// filter with later
return error;
}
// Input : n element envelope spectral curve
// Output: m lpc coefficients, excitation energy
float lpc_from_curve(float[] curve, float[] lpc){
int n=ln;
float[] work=new float[n+n];
float fscale=(float)(.5/n);
int i, j;
// input is a real curve. make it complex-real
// This mixes phase, but the LPC generation doesn't care.
for(i=0; i<n; i++){
work[i*2]=curve[i]*fscale;
work[i*2+1]=0;
}
work[n*2-1]=curve[n-1]*fscale;
n*=2;
fft.backward(work);
// The autocorrelation will not be circular. Shift, else we lose
// most of the power in the edges.
for(i=0, j=n/2; i<n/2;){
float temp=work[i];
work[i++]=work[j];
work[j++]=temp;
}
return (lpc_from_data(work, lpc, n, m));
}
void init(int mapped, int m){
ln=mapped;
this.m=m;
// we cheat decoding the LPC spectrum via FFTs
fft.init(mapped*2);
}
void clear(){
fft.clear();
}
static float FAST_HYPOT(float a, float b){
return (float)Math.sqrt((a)*(a)+(b)*(b));
}
// One can do this the long way by generating the transfer function in
// the time domain and taking the forward FFT of the result. The
// results from direct calculation are cleaner and faster.
//
// This version does a linear curve generation and then later
// interpolates the log curve from the linear curve.
void lpc_to_curve(float[] curve, float[] lpc, float amp){
for(int i=0; i<ln*2; i++)
curve[i]=0.0f;
if(amp==0)
return;
for(int i=0; i<m; i++){
curve[i*2+1]=lpc[i]/(4*amp);
curve[i*2+2]=-lpc[i]/(4*amp);
}
fft.backward(curve);
{
int l2=ln*2;
float unit=(float)(1./amp);
curve[0]=(float)(1./(curve[0]*2+unit));
for(int i=1; i<ln; i++){
float real=(curve[i]+curve[l2-i]);
float imag=(curve[i]-curve[l2-i]);
float a=real+unit;
curve[i]=(float)(1.0/FAST_HYPOT(a, imag));
}
}
}
}

View File

@@ -0,0 +1,107 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
/*
function: LSP (also called LSF) conversion routines
The LSP generation code is taken (with minimal modification) from
"On the Computation of the LSP Frequencies" by Joseph Rothweiler
<rothwlr@altavista.net>, available at:
http://www2.xtdl.com/~rothwlr/lsfpaper/lsfpage.html
********************************************************************/
class Lsp{
static final float M_PI=(float)(3.1415926539);
static void lsp_to_curve(float[] curve, int[] map, int n, int ln,
float[] lsp, int m, float amp, float ampoffset){
int i;
float wdel=M_PI/ln;
for(i=0; i<m; i++)
lsp[i]=Lookup.coslook(lsp[i]);
int m2=(m/2)*2;
i=0;
while(i<n){
int k=map[i];
float p=.7071067812f;
float q=.7071067812f;
float w=Lookup.coslook(wdel*k);
for(int j=0; j<m2; j+=2){
q*=lsp[j]-w;
p*=lsp[j+1]-w;
}
if((m&1)!=0){
/* odd order filter; slightly assymetric */
/* the last coefficient */
q*=lsp[m-1]-w;
q*=q;
p*=p*(1.f-w*w);
}
else{
/* even order filter; still symmetric */
q*=q*(1.f+w);
p*=p*(1.f-w);
}
// q=frexp(p+q,&qexp);
q=p+q;
int hx=Float.floatToIntBits(q);
int ix=0x7fffffff&hx;
int qexp=0;
if(ix>=0x7f800000||(ix==0)){
// 0,inf,nan
}
else{
if(ix<0x00800000){ // subnormal
q*=3.3554432000e+07; // 0x4c000000
hx=Float.floatToIntBits(q);
ix=0x7fffffff&hx;
qexp=-25;
}
qexp+=((ix>>>23)-126);
hx=(hx&0x807fffff)|0x3f000000;
q=Float.intBitsToFloat(hx);
}
q=Lookup.fromdBlook(amp*Lookup.invsqlook(q)*Lookup.invsq2explook(qexp+m)
-ampoffset);
do{
curve[i++]*=q;
}
while(i<n&&map[i]==k);
}
}
}

View File

@@ -0,0 +1,375 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
class Mapping0 extends FuncMapping{
static int seq=0;
void free_info(Object imap){
};
void free_look(Object imap){
}
Object look(VorbisDspState vd, InfoMode vm, Object m){
//System.err.println("Mapping0.look");
VorbisInfo vi=vd.vi;
LookMapping0 look=new LookMapping0();
InfoMapping0 info=look.map=(InfoMapping0)m;
look.mode=vm;
look.time_look=new Object[info.submaps];
look.floor_look=new Object[info.submaps];
look.residue_look=new Object[info.submaps];
look.time_func=new FuncTime[info.submaps];
look.floor_func=new FuncFloor[info.submaps];
look.residue_func=new FuncResidue[info.submaps];
for(int i=0; i<info.submaps; i++){
int timenum=info.timesubmap[i];
int floornum=info.floorsubmap[i];
int resnum=info.residuesubmap[i];
look.time_func[i]=FuncTime.time_P[vi.time_type[timenum]];
look.time_look[i]=look.time_func[i].look(vd, vm, vi.time_param[timenum]);
look.floor_func[i]=FuncFloor.floor_P[vi.floor_type[floornum]];
look.floor_look[i]=look.floor_func[i].look(vd, vm,
vi.floor_param[floornum]);
look.residue_func[i]=FuncResidue.residue_P[vi.residue_type[resnum]];
look.residue_look[i]=look.residue_func[i].look(vd, vm,
vi.residue_param[resnum]);
}
if(vi.psys!=0&&vd.analysisp!=0){
// ??
}
look.ch=vi.channels;
return (look);
}
void pack(VorbisInfo vi, Object imap, OggBuffer opb){
InfoMapping0 info=(InfoMapping0)imap;
/* another 'we meant to do it this way' hack... up to beta 4, we
packed 4 binary zeros here to signify one submapping in use. We
now redefine that to mean four bitflags that indicate use of
deeper features; bit0:submappings, bit1:coupling,
bit2,3:reserved. This is backward compatable with all actual uses
of the beta code. */
if(info.submaps>1){
opb.write(1, 1);
opb.write(info.submaps-1, 4);
}
else{
opb.write(0, 1);
}
if(info.coupling_steps>0){
opb.write(1, 1);
opb.write(info.coupling_steps-1, 8);
for(int i=0; i<info.coupling_steps; i++){
opb.write(info.coupling_mag[i], Util.ilog2(vi.channels));
opb.write(info.coupling_ang[i], Util.ilog2(vi.channels));
}
}
else{
opb.write(0, 1);
}
opb.write(0, 2); /* 2,3:reserved */
/* we don't write the channel submappings if we only have one... */
if(info.submaps>1){
for(int i=0; i<vi.channels; i++)
opb.write(info.chmuxlist[i], 4);
}
for(int i=0; i<info.submaps; i++){
opb.write(info.timesubmap[i], 8);
opb.write(info.floorsubmap[i], 8);
opb.write(info.residuesubmap[i], 8);
}
}
// also responsible for range checking
Object unpack(VorbisInfo vi, OggBuffer opb){
InfoMapping0 info=new InfoMapping0();
if(opb.read(1)!=0){
info.submaps=opb.read(4)+1;
}
else{
info.submaps=1;
}
if(opb.read(1)!=0){
info.coupling_steps=opb.read(8)+1;
for(int i=0; i<info.coupling_steps; i++){
int testM=info.coupling_mag[i]=opb.read(Util.ilog2(vi.channels));
int testA=info.coupling_ang[i]=opb.read(Util.ilog2(vi.channels));
if(testM<0||testA<0||testM==testA||testM>=vi.channels
||testA>=vi.channels){
//goto err_out;
info.free();
return (null);
}
}
}
if(opb.read(2)>0){ /* 2,3:reserved */
info.free();
return (null);
}
if(info.submaps>1){
for(int i=0; i<vi.channels; i++){
info.chmuxlist[i]=opb.read(4);
if(info.chmuxlist[i]>=info.submaps){
info.free();
return (null);
}
}
}
for(int i=0; i<info.submaps; i++){
info.timesubmap[i]=opb.read(8);
if(info.timesubmap[i]>=vi.times){
info.free();
return (null);
}
info.floorsubmap[i]=opb.read(8);
if(info.floorsubmap[i]>=vi.floors){
info.free();
return (null);
}
info.residuesubmap[i]=opb.read(8);
if(info.residuesubmap[i]>=vi.residues){
info.free();
return (null);
}
}
return info;
}
float[][] pcmbundle=null;
int[] zerobundle=null;
int[] nonzero=null;
Object[] floormemo=null;
synchronized int inverse(VorbisBlock vb, Object l){
VorbisDspState vd=vb.vd;
VorbisInfo vi=vd.vi;
LookMapping0 look=(LookMapping0)l;
InfoMapping0 info=look.map;
InfoMode mode=look.mode;
int n=vb.pcmend=vi.blocksizes[vb.W];
float[] window=vd.window[vb.W][vb.lW][vb.nW][mode.windowtype];
if(pcmbundle==null||pcmbundle.length<vi.channels){
pcmbundle=new float[vi.channels][];
nonzero=new int[vi.channels];
zerobundle=new int[vi.channels];
floormemo=new Object[vi.channels];
}
// time domain information decode (note that applying the
// information would have to happen later; we'll probably add a
// function entry to the harness for that later
// NOT IMPLEMENTED
// recover the spectral envelope; store it in the PCM vector for now
for(int i=0; i<vi.channels; i++){
float[] pcm=vb.pcm[i];
int submap=info.chmuxlist[i];
floormemo[i]=look.floor_func[submap].inverse1(vb,
look.floor_look[submap], floormemo[i]);
if(floormemo[i]!=null){
nonzero[i]=1;
}
else{
nonzero[i]=0;
}
for(int j=0; j<n/2; j++){
pcm[j]=0;
}
}
for(int i=0; i<info.coupling_steps; i++){
if(nonzero[info.coupling_mag[i]]!=0||nonzero[info.coupling_ang[i]]!=0){
nonzero[info.coupling_mag[i]]=1;
nonzero[info.coupling_ang[i]]=1;
}
}
// recover the residue, apply directly to the spectral envelope
for(int i=0; i<info.submaps; i++){
int ch_in_bundle=0;
for(int j=0; j<vi.channels; j++){
if(info.chmuxlist[j]==i){
if(nonzero[j]!=0){
zerobundle[ch_in_bundle]=1;
}
else{
zerobundle[ch_in_bundle]=0;
}
pcmbundle[ch_in_bundle++]=vb.pcm[j];
}
}
look.residue_func[i].inverse(vb, look.residue_look[i], pcmbundle,
zerobundle, ch_in_bundle);
}
for(int i=info.coupling_steps-1; i>=0; i--){
float[] pcmM=vb.pcm[info.coupling_mag[i]];
float[] pcmA=vb.pcm[info.coupling_ang[i]];
for(int j=0; j<n/2; j++){
float mag=pcmM[j];
float ang=pcmA[j];
if(mag>0){
if(ang>0){
pcmM[j]=mag;
pcmA[j]=mag-ang;
}
else{
pcmA[j]=mag;
pcmM[j]=mag+ang;
}
}
else{
if(ang>0){
pcmM[j]=mag;
pcmA[j]=mag+ang;
}
else{
pcmA[j]=mag;
pcmM[j]=mag-ang;
}
}
}
}
// /* compute and apply spectral envelope */
for(int i=0; i<vi.channels; i++){
float[] pcm=vb.pcm[i];
int submap=info.chmuxlist[i];
look.floor_func[submap].inverse2(vb, look.floor_look[submap],
floormemo[i], pcm);
}
// transform the PCM data; takes PCM vector, vb; modifies PCM vector
// only MDCT right now....
for(int i=0; i<vi.channels; i++){
float[] pcm=vb.pcm[i];
//_analysis_output("out",seq+i,pcm,n/2,0,0);
((Mdct)vd.transform[vb.W][0]).backward(pcm, pcm);
}
// now apply the decoded pre-window time information
// NOT IMPLEMENTED
// window the data
for(int i=0; i<vi.channels; i++){
float[] pcm=vb.pcm[i];
if(nonzero[i]!=0){
for(int j=0; j<n; j++){
pcm[j]*=window[j];
}
}
else{
for(int j=0; j<n; j++){
pcm[j]=0.f;
}
}
}
// now apply the decoded post-window time information
// NOT IMPLEMENTED
// all done!
return (0);
}
class InfoMapping0{
int submaps; // <= 16
int[] chmuxlist=new int[256]; // up to 256 channels in a Vorbis stream
int[] timesubmap=new int[16]; // [mux]
int[] floorsubmap=new int[16]; // [mux] submap to floors
int[] residuesubmap=new int[16];// [mux] submap to residue
int[] psysubmap=new int[16]; // [mux]; encode only
int coupling_steps;
int[] coupling_mag=new int[256];
int[] coupling_ang=new int[256];
void free(){
chmuxlist=null;
timesubmap=null;
floorsubmap=null;
residuesubmap=null;
psysubmap=null;
coupling_mag=null;
coupling_ang=null;
}
}
class LookMapping0{
InfoMode mode;
InfoMapping0 map;
Object[] time_look;
Object[] floor_look;
Object[] floor_state;
Object[] residue_look;
PsyLook[] psy_look;
FuncTime[] time_func;
FuncFloor[] floor_func;
FuncResidue[] residue_func;
int ch;
float[][] decay;
int lastframe; // if a different mode is called, we need to
// invalidate decay and floor state
}
}

View File

@@ -0,0 +1,250 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
class Mdct{
int n;
int log2n;
float[] trig;
int[] bitrev;
float scale;
void init(int n){
bitrev=new int[n/4];
trig=new float[n+n/4];
log2n=(int)Math.rint(Math.log(n)/Math.log(2));
this.n=n;
int AE=0;
int AO=1;
int BE=AE+n/2;
int BO=BE+1;
int CE=BE+n/2;
int CO=CE+1;
// trig lookups...
for(int i=0; i<n/4; i++){
trig[AE+i*2]=(float)Math.cos((Math.PI/n)*(4*i));
trig[AO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i));
trig[BE+i*2]=(float)Math.cos((Math.PI/(2*n))*(2*i+1));
trig[BO+i*2]=(float)Math.sin((Math.PI/(2*n))*(2*i+1));
}
for(int i=0; i<n/8; i++){
trig[CE+i*2]=(float)Math.cos((Math.PI/n)*(4*i+2));
trig[CO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i+2));
}
{
int mask=(1<<(log2n-1))-1;
int msb=1<<(log2n-2);
for(int i=0; i<n/8; i++){
int acc=0;
for(int j=0; msb>>>j!=0; j++)
if(((msb>>>j)&i)!=0)
acc|=1<<j;
bitrev[i*2]=((~acc)&mask);
// bitrev[i*2]=((~acc)&mask)-1;
bitrev[i*2+1]=acc;
}
}
scale=4.f/n;
}
void clear(){
}
void forward(float[] in, float[] out){
}
float[] _x=new float[1024];
float[] _w=new float[1024];
synchronized void backward(float[] in, float[] out){
if(_x.length<n/2){
_x=new float[n/2];
}
if(_w.length<n/2){
_w=new float[n/2];
}
float[] x=_x;
float[] w=_w;
int n2=n>>>1;
int n4=n>>>2;
int n8=n>>>3;
// rotate + step 1
{
int inO=1;
int xO=0;
int A=n2;
int i;
for(i=0; i<n8; i++){
A-=2;
x[xO++]=-in[inO+2]*trig[A+1]-in[inO]*trig[A];
x[xO++]=in[inO]*trig[A+1]-in[inO+2]*trig[A];
inO+=4;
}
inO=n2-4;
for(i=0; i<n8; i++){
A-=2;
x[xO++]=in[inO]*trig[A+1]+in[inO+2]*trig[A];
x[xO++]=in[inO]*trig[A]-in[inO+2]*trig[A+1];
inO-=4;
}
}
float[] xxx=mdct_kernel(x, w, n, n2, n4, n8);
int xx=0;
// step 8
{
int B=n2;
int o1=n4, o2=o1-1;
int o3=n4+n2, o4=o3-1;
for(int i=0; i<n4; i++){
float temp1=(xxx[xx]*trig[B+1]-xxx[xx+1]*trig[B]);
float temp2=-(xxx[xx]*trig[B]+xxx[xx+1]*trig[B+1]);
out[o1]=-temp1;
out[o2]=temp1;
out[o3]=temp2;
out[o4]=temp2;
o1++;
o2--;
o3++;
o4--;
xx+=2;
B+=2;
}
}
}
private float[] mdct_kernel(float[] x, float[] w, int n, int n2, int n4,
int n8){
// step 2
int xA=n4;
int xB=0;
int w2=n4;
int A=n2;
for(int i=0; i<n4;){
float x0=x[xA]-x[xB];
float x1;
w[w2+i]=x[xA++]+x[xB++];
x1=x[xA]-x[xB];
A-=4;
w[i++]=x0*trig[A]+x1*trig[A+1];
w[i]=x1*trig[A]-x0*trig[A+1];
w[w2+i]=x[xA++]+x[xB++];
i++;
}
// step 3
{
for(int i=0; i<log2n-3; i++){
int k0=n>>>(i+2);
int k1=1<<(i+3);
int wbase=n2-2;
A=0;
float[] temp;
for(int r=0; r<(k0>>>2); r++){
int w1=wbase;
w2=w1-(k0>>1);
float AEv=trig[A], wA;
float AOv=trig[A+1], wB;
wbase-=2;
k0++;
for(int s=0; s<(2<<i); s++){
wB=w[w1]-w[w2];
x[w1]=w[w1]+w[w2];
wA=w[++w1]-w[++w2];
x[w1]=w[w1]+w[w2];
x[w2]=wA*AEv-wB*AOv;
x[w2-1]=wB*AEv+wA*AOv;
w1-=k0;
w2-=k0;
}
k0--;
A+=k1;
}
temp=w;
w=x;
x=temp;
}
}
// step 4, 5, 6, 7
{
int C=n;
int bit=0;
int x1=0;
int x2=n2-1;
for(int i=0; i<n8; i++){
int t1=bitrev[bit++];
int t2=bitrev[bit++];
float wA=w[t1]-w[t2+1];
float wB=w[t1-1]+w[t2];
float wC=w[t1]+w[t2+1];
float wD=w[t1-1]-w[t2];
float wACE=wA*trig[C];
float wBCE=wB*trig[C++];
float wACO=wA*trig[C];
float wBCO=wB*trig[C++];
x[x1++]=(wC+wACO+wBCE)*.5f;
x[x2--]=(-wD+wBCO-wACE)*.5f;
x[x1++]=(wD+wBCO-wACE)*.5f;
x[x2--]=(wC-wACO-wBCE)*.5f;
}
}
return (x);
}
}

View File

@@ -0,0 +1,74 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
// psychoacoustic setup
class PsyInfo{
int athp;
int decayp;
int smoothp;
int noisefitp;
int noisefit_subblock;
float noisefit_threshdB;
float ath_att;
int tonemaskp;
float[] toneatt_125Hz=new float[5];
float[] toneatt_250Hz=new float[5];
float[] toneatt_500Hz=new float[5];
float[] toneatt_1000Hz=new float[5];
float[] toneatt_2000Hz=new float[5];
float[] toneatt_4000Hz=new float[5];
float[] toneatt_8000Hz=new float[5];
int peakattp;
float[] peakatt_125Hz=new float[5];
float[] peakatt_250Hz=new float[5];
float[] peakatt_500Hz=new float[5];
float[] peakatt_1000Hz=new float[5];
float[] peakatt_2000Hz=new float[5];
float[] peakatt_4000Hz=new float[5];
float[] peakatt_8000Hz=new float[5];
int noisemaskp;
float[] noiseatt_125Hz=new float[5];
float[] noiseatt_250Hz=new float[5];
float[] noiseatt_500Hz=new float[5];
float[] noiseatt_1000Hz=new float[5];
float[] noiseatt_2000Hz=new float[5];
float[] noiseatt_4000Hz=new float[5];
float[] noiseatt_8000Hz=new float[5];
float max_curve_dB;
float attack_coeff;
float decay_coeff;
void free(){
}
}

View File

@@ -0,0 +1,42 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
class PsyLook{
int n;
PsyInfo vi;
float[][][] tonecurves;
float[][] peakatt;
float[][][] noisecurves;
float[] ath;
int[] octave;
void init(PsyInfo vi, int n, int rate){
}
}

View File

@@ -0,0 +1,330 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
class Residue0 extends FuncResidue{
void pack(Object vr, OggBuffer opb){
InfoResidue0 info=(InfoResidue0)vr;
int acc=0;
opb.write(info.begin, 24);
opb.write(info.end, 24);
opb.write(info.grouping-1, 24); /* residue vectors to group and
code with a partitioned book */
opb.write(info.partitions-1, 6); /* possible partition choices */
opb.write(info.groupbook, 8); /* group huffman book */
/* secondstages is a bitmask; as encoding progresses pass by pass, a
bitmask of one indicates this partition class has bits to write
this pass */
for(int j=0; j<info.partitions; j++){
int i=info.secondstages[j];
if(Util.ilog(i)>3){
/* yes, this is a minor hack due to not thinking ahead */
opb.write(i, 3);
opb.write(1, 1);
opb.write(i>>>3, 5);
}
else{
opb.write(i, 4); /* trailing zero */
}
acc+=Util.icount(i);
}
for(int j=0; j<acc; j++){
opb.write(info.booklist[j], 8);
}
}
Object unpack(VorbisInfo vi, OggBuffer opb){
int acc=0;
InfoResidue0 info=new InfoResidue0();
info.begin=opb.read(24);
info.end=opb.read(24);
info.grouping=opb.read(24)+1;
info.partitions=opb.read(6)+1;
info.groupbook=opb.read(8);
for(int j=0; j<info.partitions; j++){
int cascade=opb.read(3);
if(opb.read(1)!=0){
cascade|=(opb.read(5)<<3);
}
info.secondstages[j]=cascade;
acc+=Util.icount(cascade);
}
for(int j=0; j<acc; j++){
info.booklist[j]=opb.read(8);
}
if(info.groupbook>=vi.books){
free_info(info);
return (null);
}
for(int j=0; j<acc; j++){
if(info.booklist[j]>=vi.books){
free_info(info);
return (null);
}
}
return (info);
}
Object look(VorbisDspState vd, InfoMode vm, Object vr){
InfoResidue0 info=(InfoResidue0)vr;
LookResidue0 look=new LookResidue0();
int acc=0;
int dim;
int maxstage=0;
look.info=info;
look.map=vm.mapping;
look.parts=info.partitions;
look.fullbooks=vd.fullbooks;
look.phrasebook=vd.fullbooks[info.groupbook];
dim=look.phrasebook.dim;
look.partbooks=new int[look.parts][];
for(int j=0; j<look.parts; j++){
int i=info.secondstages[j];
int stages=Util.ilog(i);
if(stages!=0){
if(stages>maxstage)
maxstage=stages;
look.partbooks[j]=new int[stages];
for(int k=0; k<stages; k++){
if((i&(1<<k))!=0){
look.partbooks[j][k]=info.booklist[acc++];
}
}
}
}
look.partvals=(int)Math.rint(Math.pow(look.parts, dim));
look.stages=maxstage;
look.decodemap=new int[look.partvals][];
for(int j=0; j<look.partvals; j++){
int val=j;
int mult=look.partvals/look.parts;
look.decodemap[j]=new int[dim];
for(int k=0; k<dim; k++){
int deco=val/mult;
val-=deco*mult;
mult/=look.parts;
look.decodemap[j][k]=deco;
}
}
return (look);
}
void free_info(Object i){
}
void free_look(Object i){
}
private static int[][][] _01inverse_partword=new int[2][][]; // _01inverse is synchronized for
// re-using partword
synchronized static int _01inverse(VorbisBlock vb, Object vl, float[][] in, int ch,
int decodepart){
int i, j, k, l, s;
LookResidue0 look=(LookResidue0)vl;
InfoResidue0 info=look.info;
// move all this setup out later
int samples_per_partition=info.grouping;
int partitions_per_word=look.phrasebook.dim;
int n=info.end-info.begin;
int partvals=n/samples_per_partition;
int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
if(_01inverse_partword.length<ch){
_01inverse_partword=new int[ch][][];
}
for(j=0; j<ch; j++){
if(_01inverse_partword[j]==null||_01inverse_partword[j].length<partwords){
_01inverse_partword[j]=new int[partwords][];
}
}
for(s=0; s<look.stages; s++){
// each loop decodes on partition codeword containing
// partitions_pre_word partitions
for(i=0, l=0; i<partvals; l++){
if(s==0){
// fetch the partition word for each channel
for(j=0; j<ch; j++){
int temp=look.phrasebook.decode(vb.opb);
if(temp==-1){
return (0);
}
_01inverse_partword[j][l]=look.decodemap[temp];
if(_01inverse_partword[j][l]==null){
return (0);
}
}
}
// now we decode residual values for the partitions
for(k=0; k<partitions_per_word&&i<partvals; k++, i++)
for(j=0; j<ch; j++){
int offset=info.begin+i*samples_per_partition;
int index=_01inverse_partword[j][l][k];
if((info.secondstages[index]&(1<<s))!=0){
CodeBook stagebook=look.fullbooks[look.partbooks[index][s]];
if(stagebook!=null){
if(decodepart==0){
if(stagebook.decodevs_add(in[j], offset, vb.opb,
samples_per_partition)==-1){
return (0);
}
}
else if(decodepart==1){
if(stagebook.decodev_add(in[j], offset, vb.opb,
samples_per_partition)==-1){
return (0);
}
}
}
}
}
}
}
return (0);
}
static int[][] _2inverse_partword=null;
synchronized static int _2inverse(VorbisBlock vb, Object vl, float[][] in, int ch){
int i, k, l, s;
LookResidue0 look=(LookResidue0)vl;
InfoResidue0 info=look.info;
// move all this setup out later
int samples_per_partition=info.grouping;
int partitions_per_word=look.phrasebook.dim;
int n=info.end-info.begin;
int partvals=n/samples_per_partition;
int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
if(_2inverse_partword==null||_2inverse_partword.length<partwords){
_2inverse_partword=new int[partwords][];
}
for(s=0; s<look.stages; s++){
for(i=0, l=0; i<partvals; l++){
if(s==0){
// fetch the partition word for each channel
int temp=look.phrasebook.decode(vb.opb);
if(temp==-1){
return (0);
}
_2inverse_partword[l]=look.decodemap[temp];
if(_2inverse_partword[l]==null){
return (0);
}
}
// now we decode residual values for the partitions
for(k=0; k<partitions_per_word&&i<partvals; k++, i++){
int offset=info.begin+i*samples_per_partition;
int index=_2inverse_partword[l][k];
if((info.secondstages[index]&(1<<s))!=0){
CodeBook stagebook=look.fullbooks[look.partbooks[index][s]];
if(stagebook!=null){
if(stagebook.decodevv_add(in, offset, ch, vb.opb,
samples_per_partition)==-1){
return (0);
}
}
}
}
}
}
return (0);
}
int inverse(VorbisBlock vb, Object vl, float[][] in, int[] nonzero, int ch){
int used=0;
for(int i=0; i<ch; i++){
if(nonzero[i]!=0){
in[used++]=in[i];
}
}
if(used!=0)
return (_01inverse(vb, vl, in, used, 0));
else
return (0);
}
class LookResidue0{
InfoResidue0 info;
int map;
int parts;
int stages;
CodeBook[] fullbooks;
CodeBook phrasebook;
int[][] partbooks;
int partvals;
int[][] decodemap;
int postbits;
int phrasebits;
int frames;
}
class InfoResidue0{
// block-partitioned VQ coded straight residue
int begin;
int end;
// first stage (lossless partitioning)
int grouping; // group n vectors per partition
int partitions; // possible codebooks for a partition
int groupbook; // huffbook for partitioning
int[] secondstages=new int[64]; // expanded out to pointers in lookup
int[] booklist=new int[256]; // list of second stage books
// encode-only heuristic settings
float[] entmax=new float[64]; // book entropy threshholds
float[] ampmax=new float[64]; // book amp threshholds
int[] subgrp=new int[64]; // book heuristic subgroup size
int[] blimit=new int[64]; // subgroup position limits
}
}

View File

@@ -0,0 +1,45 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
class Residue1 extends Residue0{
int inverse(VorbisBlock vb, Object vl, float[][] in, int[] nonzero, int ch){
int used=0;
for(int i=0; i<ch; i++){
if(nonzero[i]!=0){
in[used++]=in[i];
}
}
if(used!=0){
return (_01inverse(vb, vl, in, used, 1));
}
else{
return 0;
}
}
}

View File

@@ -0,0 +1,41 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
class Residue2 extends Residue0{
int inverse(VorbisBlock vb, Object vl, float[][] in, int[] nonzero, int ch){
int i=0;
for(i=0; i<ch; i++)
if(nonzero[i]!=0)
break;
if(i==ch)
return (0); /* no nonzero vectors */
return (_2inverse(vb, vl, in, ch));
}
}

View File

@@ -0,0 +1,443 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
class StaticCodeBook{
int dim; // codebook dimensions (elements per vector)
int entries; // codebook entries
int[] lengthlist; // codeword lengths in bits
// mapping
int maptype; // 0=none
// 1=implicitly populated values from map column
// 2=listed arbitrary values
// The below does a linear, single monotonic sequence mapping.
int q_min; // packed 32 bit float; quant value 0 maps to minval
int q_delta; // packed 32 bit float; val 1 - val 0 == delta
int q_quant; // bits: 0 < quant <= 16
int q_sequencep; // bitflag
// additional information for log (dB) mapping; the linear mapping
// is assumed to actually be values in dB. encodebias is used to
// assign an error weight to 0 dB. We have two additional flags:
// zeroflag indicates if entry zero is to represent -Inf dB; negflag
// indicates if we're to represent negative linear values in a
// mirror of the positive mapping.
int[] quantlist; // map == 1: (int)(entries/dim) element column map
// map == 2: list of dim*entries quantized entry vals
StaticCodeBook(){
}
int pack(OggBuffer opb){
int i;
boolean ordered=false;
opb.write(0x564342, 24);
opb.write(dim, 16);
opb.write(entries, 24);
// pack the codewords. There are two packings; length ordered and
// length random. Decide between the two now.
for(i=1; i<entries; i++){
if(lengthlist[i]<lengthlist[i-1])
break;
}
if(i==entries)
ordered=true;
if(ordered){
// length ordered. We only need to say how many codewords of
// each length. The actual codewords are generated
// deterministically
int count=0;
opb.write(1, 1); // ordered
opb.write(lengthlist[0]-1, 5); // 1 to 32
for(i=1; i<entries; i++){
int _this=lengthlist[i];
int _last=lengthlist[i-1];
if(_this>_last){
for(int j=_last; j<_this; j++){
opb.write(i-count, Util.ilog(entries-count));
count=i;
}
}
}
opb.write(i-count, Util.ilog(entries-count));
}
else{
// length random. Again, we don't code the codeword itself, just
// the length. This time, though, we have to encode each length
opb.write(0, 1); // unordered
// algortihmic mapping has use for 'unused entries', which we tag
// here. The algorithmic mapping happens as usual, but the unused
// entry has no codeword.
for(i=0; i<entries; i++){
if(lengthlist[i]==0)
break;
}
if(i==entries){
opb.write(0, 1); // no unused entries
for(i=0; i<entries; i++){
opb.write(lengthlist[i]-1, 5);
}
}
else{
opb.write(1, 1); // we have unused entries; thus we tag
for(i=0; i<entries; i++){
if(lengthlist[i]==0){
opb.write(0, 1);
}
else{
opb.write(1, 1);
opb.write(lengthlist[i]-1, 5);
}
}
}
}
// is the entry number the desired return value, or do we have a
// mapping? If we have a mapping, what type?
opb.write(maptype, 4);
switch(maptype){
case 0:
// no mapping
break;
case 1:
case 2:
// implicitly populated value mapping
// explicitly populated value mapping
if(quantlist==null){
// no quantlist? error
return (-1);
}
// values that define the dequantization
opb.write(q_min, 32);
opb.write(q_delta, 32);
opb.write(q_quant-1, 4);
opb.write(q_sequencep, 1);
{
int quantvals=0;
switch(maptype){
case 1:
// a single column of (c->entries/c->dim) quantized values for
// building a full value list algorithmically (square lattice)
quantvals=maptype1_quantvals();
break;
case 2:
// every value (c->entries*c->dim total) specified explicitly
quantvals=entries*dim;
break;
}
// quantized values
for(i=0; i<quantvals; i++){
opb.write(Math.abs(quantlist[i]), q_quant);
}
}
break;
default:
// error case; we don't have any other map types now
return (-1);
}
return (0);
}
// unpacks a codebook from the packet buffer into the codebook struct,
// readies the codebook auxiliary structures for decode
int unpack(OggBuffer opb){
int i;
//memset(s,0,sizeof(static_codebook));
// make sure alignment is correct
if(opb.read(24)!=0x564342){
// goto _eofout;
clear();
return (-1);
}
// first the basic parameters
dim=opb.read(16);
entries=opb.read(24);
if(entries==-1){
// goto _eofout;
clear();
return (-1);
}
// codeword ordering.... length ordered or unordered?
switch(opb.read(1)){
case 0:
// unordered
lengthlist=new int[entries];
// allocated but unused entries?
if(opb.read(1)!=0){
// yes, unused entries
for(i=0; i<entries; i++){
if(opb.read(1)!=0){
int num=opb.read(5);
if(num==-1){
// goto _eofout;
clear();
return (-1);
}
lengthlist[i]=num+1;
}
else{
lengthlist[i]=0;
}
}
}
else{
// all entries used; no tagging
for(i=0; i<entries; i++){
int num=opb.read(5);
if(num==-1){
// goto _eofout;
clear();
return (-1);
}
lengthlist[i]=num+1;
}
}
break;
case 1:
// ordered
{
int length=opb.read(5)+1;
lengthlist=new int[entries];
for(i=0; i<entries;){
int num=opb.read(Util.ilog(entries-i));
if(num==-1){
// goto _eofout;
clear();
return (-1);
}
for(int j=0; j<num; j++, i++){
lengthlist[i]=length;
}
length++;
}
}
break;
default:
// EOF
return (-1);
}
// Do we have a mapping to unpack?
switch((maptype=opb.read(4))){
case 0:
// no mapping
break;
case 1:
case 2:
// implicitly populated value mapping
// explicitly populated value mapping
q_min=opb.read(32);
q_delta=opb.read(32);
q_quant=opb.read(4)+1;
q_sequencep=opb.read(1);
{
int quantvals=0;
switch(maptype){
case 1:
quantvals=maptype1_quantvals();
break;
case 2:
quantvals=entries*dim;
break;
}
// quantized values
quantlist=new int[quantvals];
for(i=0; i<quantvals; i++){
quantlist[i]=opb.read(q_quant);
}
if(quantlist[quantvals-1]==-1){
// goto _eofout;
clear();
return (-1);
}
}
break;
default:
// goto _eofout;
clear();
return (-1);
}
// all set
return (0);
// _errout:
// _eofout:
// vorbis_staticbook_clear(s);
// return(-1);
}
// there might be a straightforward one-line way to do the below
// that's portable and totally safe against roundoff, but I haven't
// thought of it. Therefore, we opt on the side of caution
private int maptype1_quantvals(){
int vals=(int)(Math.floor(Math.pow(entries, 1./dim)));
// the above *should* be reliable, but we'll not assume that FP is
// ever reliable when bitstream sync is at stake; verify via integer
// means that vals really is the greatest value of dim for which
// vals^b->bim <= b->entries
// treat the above as an initial guess
while(true){
int acc=1;
int acc1=1;
for(int i=0; i<dim; i++){
acc*=vals;
acc1*=vals+1;
}
if(acc<=entries&&acc1>entries){
return (vals);
}
else{
if(acc>entries){
vals--;
}
else{
vals++;
}
}
}
}
void clear(){
}
// unpack the quantized list of values for encode/decode
// we need to deal with two map types: in map type 1, the values are
// generated algorithmically (each column of the vector counts through
// the values in the quant vector). in map type 2, all the values came
// in in an explicit list. Both value lists must be unpacked
float[] unquantize(){
if(maptype==1||maptype==2){
int quantvals;
float mindel=float32_unpack(q_min);
float delta=float32_unpack(q_delta);
float[] r=new float[entries*dim];
// maptype 1 and 2 both use a quantized value vector, but
// different sizes
switch(maptype){
case 1:
// most of the time, entries%dimensions == 0, but we need to be
// well defined. We define that the possible vales at each
// scalar is values == entries/dim. If entries%dim != 0, we'll
// have 'too few' values (values*dim<entries), which means that
// we'll have 'left over' entries; left over entries use zeroed
// values (and are wasted). So don't generate codebooks like that
quantvals=maptype1_quantvals();
for(int j=0; j<entries; j++){
float last=0.f;
int indexdiv=1;
for(int k=0; k<dim; k++){
int index=(j/indexdiv)%quantvals;
float val=quantlist[index];
val=Math.abs(val)*delta+mindel+last;
if(q_sequencep!=0)
last=val;
r[j*dim+k]=val;
indexdiv*=quantvals;
}
}
break;
case 2:
for(int j=0; j<entries; j++){
float last=0.f;
for(int k=0; k<dim; k++){
float val=quantlist[j*dim+k];
//if((j*dim+k)==0){System.err.println(" | 0 -> "+val+" | ");}
val=Math.abs(val)*delta+mindel+last;
if(q_sequencep!=0)
last=val;
r[j*dim+k]=val;
//if((j*dim+k)==0){System.err.println(" $ r[0] -> "+r[0]+" | ");}
}
}
//System.err.println("\nr[0]="+r[0]);
}
return (r);
}
return (null);
}
// 32 bit float (not IEEE; nonnormalized mantissa +
// biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm
// Why not IEEE? It's just not that important here.
static final int VQ_FEXP=10;
static final int VQ_FMAN=21;
static final int VQ_FEXP_BIAS=768; // bias toward values smaller than 1.
// doesn't currently guard under/overflow
static long float32_pack(float val){
int sign=0;
int exp;
int mant;
if(val<0){
sign=0x80000000;
val=-val;
}
exp=(int)Math.floor(Math.log(val)/Math.log(2));
mant=(int)Math.rint(Math.pow(val, (VQ_FMAN-1)-exp));
exp=(exp+VQ_FEXP_BIAS)<<VQ_FMAN;
return (sign|exp|mant);
}
static float float32_unpack(int val){
float mant=val&0x1fffff;
float exp=(val&0x7fe00000)>>>VQ_FMAN;
if((val&0x80000000)!=0)
mant=-mant;
return (ldexp(mant, ((int)exp)-(VQ_FMAN-1)-VQ_FEXP_BIAS));
}
static float ldexp(float foo, int e){
return (float)(foo*Math.pow(2, e));
}
}

View File

@@ -0,0 +1,52 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
class Time0 extends FuncTime{
void pack(Object i, OggBuffer opb){
}
Object unpack(VorbisInfo vi, OggBuffer opb){
return "";
}
Object look(VorbisDspState vd, InfoMode mi, Object i){
return "";
}
void free_info(Object i){
}
void free_look(Object i){
}
int inverse(VorbisBlock vb, Object i, float[] in, float[] out){
return 0;
}
}

View File

@@ -0,0 +1,30 @@
package eu.midnightdust.picturesign_theora.ogv.jorbis;
class Util{
static int ilog(int v){
int ret=0;
while(v!=0){
ret++;
v>>>=1;
}
return (ret);
}
static int ilog2(int v){
int ret=0;
while(v>1){
ret++;
v>>>=1;
}
return (ret);
}
static int icount(int v){
int ret=0;
while(v!=0){
ret+=(v&1);
v>>>=1;
}
return (ret);
}
}

View File

@@ -0,0 +1,128 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
public class VorbisBlock{
///necessary stream state for linking to the framing abstraction
float[][] pcm=new float[0][]; // this is a pointer into local storage
OggBuffer opb=new OggBuffer();
int lW;
int W;
int nW;
int pcmend;
int mode;
int eofflag;
long granulepos;
long sequence;
VorbisDspState vd; // For read-only access of configuration
// bitmetrics for the frame
int glue_bits;
int time_bits;
int floor_bits;
int res_bits;
public VorbisBlock(VorbisDspState vd){
this.vd=vd;
if(vd.analysisp!=0){
opb.writeinit();
}
}
public void init(VorbisDspState vd){
this.vd=vd;
}
public int clear(){
if(vd!=null){
if(vd.analysisp!=0){
opb.writeclear();
}
}
return (0);
}
public int synthesis(OggPacket op){
VorbisInfo vi=vd.vi;
// first things first. Make sure decode is ready
opb.readinit(op.packet_base, op.packet, op.bytes);
// Check the packet type
if(opb.read(1)!=0){
// Oops. This is not an audio data packet
return (-1);
}
// read our mode and pre/post windowsize
int _mode=opb.read(vd.modebits);
if(_mode==-1)
return (-1);
mode=_mode;
W=vi.mode_param[mode].blockflag;
if(W!=0){
lW=opb.read(1);
nW=opb.read(1);
if(nW==-1)
return (-1);
}
else{
lW=0;
nW=0;
}
// more setup
granulepos=op.granulepos;
sequence=op.packetno-3; // first block is third packet
eofflag=op.e_o_s;
// alloc pcm passback storage
pcmend=vi.blocksizes[W];
if(pcm.length<vi.channels){
pcm=new float[vi.channels][];
}
for(int i=0; i<vi.channels; i++){
if(pcm[i]==null||pcm[i].length<pcmend){
pcm[i]=new float[pcmend];
}
else{
for(int j=0; j<pcmend; j++){
pcm[i][j]=0;
}
}
}
// unpack_header enforces range checking
int type=vi.map_type[vi.mode_param[mode].mapping];
return (FuncMapping.mapping_P[type].inverse(this, vd.mode[mode]));
}
}

View File

@@ -0,0 +1,243 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
// the comments are not part of vorbis_info so that vorbis_info can be
// static storage
public class VorbisComment{
private static byte[] _vorbis="vorbis".getBytes();
private static byte[] _vendor="Xiphophorus libVorbis I 20000508".getBytes();
private static final int OV_EIMPL=-130;
// unlimited user comment fields.
public byte[][] user_comments;
public int[] comment_lengths;
public int comments;
public byte[] vendor;
public void init(){
user_comments=null;
comments=0;
vendor=null;
}
public void add(String comment){
add(comment.getBytes());
}
private void add(byte[] comment){
byte[][] foo=new byte[comments+2][];
if(user_comments!=null){
System.arraycopy(user_comments, 0, foo, 0, comments);
}
user_comments=foo;
int[] goo=new int[comments+2];
if(comment_lengths!=null){
System.arraycopy(comment_lengths, 0, goo, 0, comments);
}
comment_lengths=goo;
byte[] bar=new byte[comment.length+1];
System.arraycopy(comment, 0, bar, 0, comment.length);
user_comments[comments]=bar;
comment_lengths[comments]=comment.length;
comments++;
user_comments[comments]=null;
}
public void add_tag(String tag, String contents){
if(contents==null)
contents="";
add(tag+"="+contents);
}
static boolean tagcompare(byte[] s1, byte[] s2, int n){
int c=0;
byte u1, u2;
while(c<n){
u1=s1[c];
u2=s2[c];
if('Z'>=u1&&u1>='A')
u1=(byte)(u1-'A'+'a');
if('Z'>=u2&&u2>='A')
u2=(byte)(u2-'A'+'a');
if(u1!=u2){
return false;
}
c++;
}
return true;
}
public String query(String tag){
return query(tag, 0);
}
public String query(String tag, int count){
int foo=query(tag.getBytes(), count);
if(foo==-1)
return null;
byte[] comment=user_comments[foo];
for(int i=0; i<comment_lengths[foo]; i++){
if(comment[i]=='='){
return new String(comment, i+1, comment_lengths[foo]-(i+1));
}
}
return null;
}
private int query(byte[] tag, int count){
int i=0;
int found=0;
int fulltaglen=tag.length+1;
byte[] fulltag=new byte[fulltaglen];
System.arraycopy(tag, 0, fulltag, 0, tag.length);
fulltag[tag.length]=(byte)'=';
for(i=0; i<comments; i++){
if(tagcompare(user_comments[i], fulltag, fulltaglen)){
if(count==found){
// We return a pointer to the data, not a copy
//return user_comments[i] + taglen + 1;
return i;
}
else{
found++;
}
}
}
return -1;
}
int unpack(OggBuffer opb){
int vendorlen=opb.read(32);
if(vendorlen<0){
clear();
return (-1);
}
vendor=new byte[vendorlen+1];
opb.read(vendor, vendorlen);
comments=opb.read(32);
if(comments<0){
clear();
return (-1);
}
user_comments=new byte[comments+1][];
comment_lengths=new int[comments+1];
for(int i=0; i<comments; i++){
int len=opb.read(32);
if(len<0){
clear();
return (-1);
}
comment_lengths[i]=len;
user_comments[i]=new byte[len+1];
opb.read(user_comments[i], len);
}
if(opb.read(1)!=1){
clear();
return (-1);
}
return (0);
}
int pack(OggBuffer opb){
// preamble
opb.write(0x03, 8);
opb.write(_vorbis);
// vendor
opb.write(_vendor.length, 32);
opb.write(_vendor);
// comments
opb.write(comments, 32);
if(comments!=0){
for(int i=0; i<comments; i++){
if(user_comments[i]!=null){
opb.write(comment_lengths[i], 32);
opb.write(user_comments[i]);
}
else{
opb.write(0, 32);
}
}
}
opb.write(1, 1);
return (0);
}
public int header_out(OggPacket op){
OggBuffer opb=new OggBuffer();
opb.writeinit();
if(pack(opb)!=0)
return OV_EIMPL;
op.packet_base=new byte[opb.bytes()];
op.packet=0;
op.bytes=opb.bytes();
System.arraycopy(opb.buffer(), 0, op.packet_base, 0, op.bytes);
op.b_o_s=0;
op.e_o_s=0;
op.granulepos=0;
return 0;
}
void clear(){
for(int i=0; i<comments; i++)
user_comments[i]=null;
user_comments=null;
vendor=null;
}
public String getVendor(){
return new String(vendor, 0, vendor.length-1);
}
public String getComment(int i){
if(comments<=i)
return null;
return new String(user_comments[i], 0, user_comments[i].length-1);
}
public String toString(){
String foo="Vendor: "+new String(vendor, 0, vendor.length-1);
for(int i=0; i<comments; i++){
foo=foo+"\nComment: "
+new String(user_comments[i], 0, user_comments[i].length-1);
}
foo=foo+"\n";
return foo;
}
}

View File

@@ -0,0 +1,376 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
public class VorbisDspState{
static final float M_PI=3.1415926539f;
static final int VI_TRANSFORMB=1;
static final int VI_WINDOWB=1;
int analysisp;
VorbisInfo vi;
int modebits;
float[][] pcm;
int pcm_storage;
int pcm_current;
int pcm_returned;
float[] multipliers;
int envelope_storage;
int envelope_current;
int eofflag;
int lW;
int W;
int nW;
int centerW;
long granulepos;
long sequence;
long glue_bits;
long time_bits;
long floor_bits;
long res_bits;
// local lookup storage
float[][][][][] window; // block, leadin, leadout, type
Object[][] transform;
CodeBook[] fullbooks;
// backend lookups are tied to the mode, not the backend or naked mapping
Object[] mode;
// local storage, only used on the encoding side. This way the
// application does not need to worry about freeing some packets'
// memory and not others'; packet storage is always tracked.
// Cleared next call to a _dsp_ function
byte[] header;
byte[] header1;
byte[] header2;
public VorbisDspState(){
transform=new Object[2][];
window=new float[2][][][][];
window[0]=new float[2][][][];
window[0][0]=new float[2][][];
window[0][1]=new float[2][][];
window[0][0][0]=new float[2][];
window[0][0][1]=new float[2][];
window[0][1][0]=new float[2][];
window[0][1][1]=new float[2][];
window[1]=new float[2][][][];
window[1][0]=new float[2][][];
window[1][1]=new float[2][][];
window[1][0][0]=new float[2][];
window[1][0][1]=new float[2][];
window[1][1][0]=new float[2][];
window[1][1][1]=new float[2][];
}
static float[] window(int type, int window, int left, int right){
float[] ret=new float[window];
switch(type){
case 0:
// The 'vorbis window' (window 0) is sin(sin(x)*sin(x)*2pi)
{
int leftbegin=window/4-left/2;
int rightbegin=window-window/4-right/2;
for(int i=0; i<left; i++){
float x=(float)((i+.5)/left*M_PI/2.);
x=(float)Math.sin(x);
x*=x;
x*=M_PI/2.;
x=(float)Math.sin(x);
ret[i+leftbegin]=x;
}
for(int i=leftbegin+left; i<rightbegin; i++){
ret[i]=1.f;
}
for(int i=0; i<right; i++){
float x=(float)((right-i-.5)/right*M_PI/2.);
x=(float)Math.sin(x);
x*=x;
x*=M_PI/2.;
x=(float)Math.sin(x);
ret[i+rightbegin]=x;
}
}
break;
default:
//free(ret);
return (null);
}
return (ret);
}
// Analysis side code, but directly related to blocking. Thus it's
// here and not in analysis.c (which is for analysis transforms only).
// The init is here because some of it is shared
int init(VorbisInfo vi, boolean encp){
this.vi=vi;
modebits=Util.ilog2(vi.modes);
transform[0]=new Object[VI_TRANSFORMB];
transform[1]=new Object[VI_TRANSFORMB];
// MDCT is tranform 0
transform[0][0]=new Mdct();
transform[1][0]=new Mdct();
((Mdct)transform[0][0]).init(vi.blocksizes[0]);
((Mdct)transform[1][0]).init(vi.blocksizes[1]);
window[0][0][0]=new float[VI_WINDOWB][];
window[0][0][1]=window[0][0][0];
window[0][1][0]=window[0][0][0];
window[0][1][1]=window[0][0][0];
window[1][0][0]=new float[VI_WINDOWB][];
window[1][0][1]=new float[VI_WINDOWB][];
window[1][1][0]=new float[VI_WINDOWB][];
window[1][1][1]=new float[VI_WINDOWB][];
for(int i=0; i<VI_WINDOWB; i++){
window[0][0][0][i]=window(i, vi.blocksizes[0], vi.blocksizes[0]/2,
vi.blocksizes[0]/2);
window[1][0][0][i]=window(i, vi.blocksizes[1], vi.blocksizes[0]/2,
vi.blocksizes[0]/2);
window[1][0][1][i]=window(i, vi.blocksizes[1], vi.blocksizes[0]/2,
vi.blocksizes[1]/2);
window[1][1][0][i]=window(i, vi.blocksizes[1], vi.blocksizes[1]/2,
vi.blocksizes[0]/2);
window[1][1][1][i]=window(i, vi.blocksizes[1], vi.blocksizes[1]/2,
vi.blocksizes[1]/2);
}
fullbooks=new CodeBook[vi.books];
for(int i=0; i<vi.books; i++){
fullbooks[i]=new CodeBook();
fullbooks[i].init_decode(vi.book_param[i]);
}
// initialize the storage vectors to a decent size greater than the
// minimum
pcm_storage=8192; // we'll assume later that we have
// a minimum of twice the blocksize of
// accumulated samples in analysis
pcm=new float[vi.channels][];
{
for(int i=0; i<vi.channels; i++){
pcm[i]=new float[pcm_storage];
}
}
// all 1 (large block) or 0 (small block)
// explicitly set for the sake of clarity
lW=0; // previous window size
W=0; // current window size
// all vector indexes; multiples of samples_per_envelope_step
centerW=vi.blocksizes[1]/2;
pcm_current=centerW;
// initialize all the mapping/backend lookups
mode=new Object[vi.modes];
for(int i=0; i<vi.modes; i++){
int mapnum=vi.mode_param[i].mapping;
int maptype=vi.map_type[mapnum];
mode[i]=FuncMapping.mapping_P[maptype].look(this, vi.mode_param[i],
vi.map_param[mapnum]);
}
return (0);
}
public int synthesis_init(VorbisInfo vi){
init(vi, false);
// Adjust centerW to allow an easier mechanism for determining output
pcm_returned=centerW;
centerW-=vi.blocksizes[W]/4+vi.blocksizes[lW]/4;
granulepos=-1;
sequence=-1;
return (0);
}
VorbisDspState(VorbisInfo vi){
this();
init(vi, false);
// Adjust centerW to allow an easier mechanism for determining output
pcm_returned=centerW;
centerW-=vi.blocksizes[W]/4+vi.blocksizes[lW]/4;
granulepos=-1;
sequence=-1;
}
// Unike in analysis, the window is only partially applied for each
// block. The time domain envelope is not yet handled at the point of
// calling (as it relies on the previous block).
public int synthesis_blockin(VorbisBlock vb){
// Shift out any PCM/multipliers that we returned previously
// centerW is currently the center of the last block added
if(centerW>vi.blocksizes[1]/2&&pcm_returned>8192){
// don't shift too much; we need to have a minimum PCM buffer of
// 1/2 long block
int shiftPCM=centerW-vi.blocksizes[1]/2;
shiftPCM=(pcm_returned<shiftPCM ? pcm_returned : shiftPCM);
pcm_current-=shiftPCM;
centerW-=shiftPCM;
pcm_returned-=shiftPCM;
if(shiftPCM!=0){
for(int i=0; i<vi.channels; i++){
System.arraycopy(pcm[i], shiftPCM, pcm[i], 0, pcm_current);
}
}
}
lW=W;
W=vb.W;
nW=-1;
glue_bits+=vb.glue_bits;
time_bits+=vb.time_bits;
floor_bits+=vb.floor_bits;
res_bits+=vb.res_bits;
if(sequence+1!=vb.sequence)
granulepos=-1; // out of sequence; lose count
sequence=vb.sequence;
{
int sizeW=vi.blocksizes[W];
int _centerW=centerW+vi.blocksizes[lW]/4+sizeW/4;
int beginW=_centerW-sizeW/2;
int endW=beginW+sizeW;
int beginSl=0;
int endSl=0;
// Do we have enough PCM/mult storage for the block?
if(endW>pcm_storage){
// expand the storage
pcm_storage=endW+vi.blocksizes[1];
for(int i=0; i<vi.channels; i++){
float[] foo=new float[pcm_storage];
System.arraycopy(pcm[i], 0, foo, 0, pcm[i].length);
pcm[i]=foo;
}
}
// overlap/add PCM
switch(W){
case 0:
beginSl=0;
endSl=vi.blocksizes[0]/2;
break;
case 1:
beginSl=vi.blocksizes[1]/4-vi.blocksizes[lW]/4;
endSl=beginSl+vi.blocksizes[lW]/2;
break;
}
for(int j=0; j<vi.channels; j++){
int _pcm=beginW;
// the overlap/add section
int i=0;
for(i=beginSl; i<endSl; i++){
pcm[j][_pcm+i]+=vb.pcm[j][i];
}
// the remaining section
for(; i<sizeW; i++){
pcm[j][_pcm+i]=vb.pcm[j][i];
}
}
// track the frame number... This is for convenience, but also
// making sure our last packet doesn't end with added padding. If
// the last packet is partial, the number of samples we'll have to
// return will be past the vb->granulepos.
//
// This is not foolproof! It will be confused if we begin
// decoding at the last page after a seek or hole. In that case,
// we don't have a starting point to judge where the last frame
// is. For this reason, vorbisfile will always try to make sure
// it reads the last two marked pages in proper sequence
if(granulepos==-1){
granulepos=vb.granulepos;
}
else{
granulepos+=(_centerW-centerW);
if(vb.granulepos!=-1&&granulepos!=vb.granulepos){
if(granulepos>vb.granulepos&&vb.eofflag!=0){
// partial last frame. Strip the padding off
_centerW-=(granulepos-vb.granulepos);
}// else{ Shouldn't happen *unless* the bitstream is out of
// spec. Either way, believe the bitstream }
granulepos=vb.granulepos;
}
}
// Update, cleanup
centerW=_centerW;
pcm_current=endW;
if(vb.eofflag!=0)
eofflag=1;
}
return (0);
}
// pcm==NULL indicates we just want the pending samples, no more
public int synthesis_pcmout(float[][][] _pcm, int[] index){
if(pcm_returned<centerW){
if(_pcm!=null){
for(int i=0; i<vi.channels; i++){
index[i]=pcm_returned;
}
_pcm[0]=pcm;
}
return (centerW-pcm_returned);
}
return (0);
}
public int synthesis_read(int bytes){
if(bytes!=0&&pcm_returned+bytes>centerW)
return (-1);
pcm_returned+=bytes;
return (0);
}
public void clear(){
}
}

View File

@@ -0,0 +1,470 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eu.midnightdust.picturesign_theora.ogv.jorbis;
import eu.midnightdust.picturesign_theora.ogv.jogg.*;
public class VorbisInfo{
private static final int OV_EBADPACKET=-136;
private static final int OV_ENOTAUDIO=-135;
private static byte[] _vorbis="vorbis".getBytes();
private static final int VI_TIMEB=1;
// private static final int VI_FLOORB=1;
private static final int VI_FLOORB=2;
// private static final int VI_RESB=1;
private static final int VI_RESB=3;
private static final int VI_MAPB=1;
private static final int VI_WINDOWB=1;
public int version;
public int channels;
public int rate;
// The below bitrate declarations are *hints*.
// Combinations of the three values carry the following implications:
//
// all three set to the same value:
// implies a fixed rate bitstream
// only nominal set:
// implies a VBR stream that averages the nominal bitrate. No hard
// upper/lower limit
// upper and or lower set:
// implies a VBR bitstream that obeys the bitrate limits. nominal
// may also be set to give a nominal rate.
// none set:
// the coder does not care to speculate.
int bitrate_upper;
int bitrate_nominal;
int bitrate_lower;
// Vorbis supports only short and long blocks, but allows the
// encoder to choose the sizes
int[] blocksizes=new int[2];
// modes are the primary means of supporting on-the-fly different
// blocksizes, different channel mappings (LR or mid-side),
// different residue backends, etc. Each mode consists of a
// blocksize flag and a mapping (along with the mapping setup
int modes;
int maps;
int times;
int floors;
int residues;
int books;
int psys; // encode only
InfoMode[] mode_param=null;
int[] map_type=null;
Object[] map_param=null;
int[] time_type=null;
Object[] time_param=null;
int[] floor_type=null;
Object[] floor_param=null;
int[] residue_type=null;
Object[] residue_param=null;
StaticCodeBook[] book_param=null;
PsyInfo[] psy_param=new PsyInfo[64]; // encode only
// for block long/sort tuning; encode only
int envelopesa;
float preecho_thresh;
float preecho_clamp;
// used by synthesis, which has a full, alloced vi
public void init(){
rate=0;
}
public void clear(){
for(int i=0; i<modes; i++){
mode_param[i]=null;
}
mode_param=null;
for(int i=0; i<maps; i++){ // unpack does the range checking
FuncMapping.mapping_P[map_type[i]].free_info(map_param[i]);
}
map_param=null;
for(int i=0; i<times; i++){ // unpack does the range checking
FuncTime.time_P[time_type[i]].free_info(time_param[i]);
}
time_param=null;
for(int i=0; i<floors; i++){ // unpack does the range checking
FuncFloor.floor_P[floor_type[i]].free_info(floor_param[i]);
}
floor_param=null;
for(int i=0; i<residues; i++){ // unpack does the range checking
FuncResidue.residue_P[residue_type[i]].free_info(residue_param[i]);
}
residue_param=null;
// the static codebooks *are* freed if you call info_clear, because
// decode side does alloc a 'static' codebook. Calling clear on the
// full codebook does not clear the static codebook (that's our
// responsibility)
for(int i=0; i<books; i++){
// just in case the decoder pre-cleared to save space
if(book_param[i]!=null){
book_param[i].clear();
book_param[i]=null;
}
}
//if(vi->book_param)free(vi->book_param);
book_param=null;
for(int i=0; i<psys; i++){
psy_param[i].free();
}
}
// Header packing/unpacking
int unpack_info(OggBuffer opb){
version=opb.read(32);
if(version!=0)
return (-1);
channels=opb.read(8);
rate=opb.read(32);
bitrate_upper=opb.read(32);
bitrate_nominal=opb.read(32);
bitrate_lower=opb.read(32);
blocksizes[0]=1<<opb.read(4);
blocksizes[1]=1<<opb.read(4);
if((rate<1)||(channels<1)||(blocksizes[0]<8)||(blocksizes[1]<blocksizes[0])
||(opb.read(1)!=1)){
clear();
return (-1);
}
return (0);
}
// all of the real encoding details are here. The modes, books,
// everything
int unpack_books(OggBuffer opb){
books=opb.read(8)+1;
if(book_param==null||book_param.length!=books)
book_param=new StaticCodeBook[books];
for(int i=0; i<books; i++){
book_param[i]=new StaticCodeBook();
if(book_param[i].unpack(opb)!=0){
clear();
return (-1);
}
}
// time backend settings
times=opb.read(6)+1;
if(time_type==null||time_type.length!=times)
time_type=new int[times];
if(time_param==null||time_param.length!=times)
time_param=new Object[times];
for(int i=0; i<times; i++){
time_type[i]=opb.read(16);
if(time_type[i]<0||time_type[i]>=VI_TIMEB){
clear();
return (-1);
}
time_param[i]=FuncTime.time_P[time_type[i]].unpack(this, opb);
if(time_param[i]==null){
clear();
return (-1);
}
}
// floor backend settings
floors=opb.read(6)+1;
if(floor_type==null||floor_type.length!=floors)
floor_type=new int[floors];
if(floor_param==null||floor_param.length!=floors)
floor_param=new Object[floors];
for(int i=0; i<floors; i++){
floor_type[i]=opb.read(16);
if(floor_type[i]<0||floor_type[i]>=VI_FLOORB){
clear();
return (-1);
}
floor_param[i]=FuncFloor.floor_P[floor_type[i]].unpack(this, opb);
if(floor_param[i]==null){
clear();
return (-1);
}
}
// residue backend settings
residues=opb.read(6)+1;
if(residue_type==null||residue_type.length!=residues)
residue_type=new int[residues];
if(residue_param==null||residue_param.length!=residues)
residue_param=new Object[residues];
for(int i=0; i<residues; i++){
residue_type[i]=opb.read(16);
if(residue_type[i]<0||residue_type[i]>=VI_RESB){
clear();
return (-1);
}
residue_param[i]=FuncResidue.residue_P[residue_type[i]].unpack(this, opb);
if(residue_param[i]==null){
clear();
return (-1);
}
}
// map backend settings
maps=opb.read(6)+1;
if(map_type==null||map_type.length!=maps)
map_type=new int[maps];
if(map_param==null||map_param.length!=maps)
map_param=new Object[maps];
for(int i=0; i<maps; i++){
map_type[i]=opb.read(16);
if(map_type[i]<0||map_type[i]>=VI_MAPB){
clear();
return (-1);
}
map_param[i]=FuncMapping.mapping_P[map_type[i]].unpack(this, opb);
if(map_param[i]==null){
clear();
return (-1);
}
}
// mode settings
modes=opb.read(6)+1;
if(mode_param==null||mode_param.length!=modes)
mode_param=new InfoMode[modes];
for(int i=0; i<modes; i++){
mode_param[i]=new InfoMode();
mode_param[i].blockflag=opb.read(1);
mode_param[i].windowtype=opb.read(16);
mode_param[i].transformtype=opb.read(16);
mode_param[i].mapping=opb.read(8);
if((mode_param[i].windowtype>=VI_WINDOWB)
||(mode_param[i].transformtype>=VI_WINDOWB)
||(mode_param[i].mapping>=maps)){
clear();
return (-1);
}
}
if(opb.read(1)!=1){
clear();
return (-1);
}
return (0);
}
// The Vorbis header is in three packets; the initial small packet in
// the first page that identifies basic parameters, a second packet
// with bitstream comments and a third packet that holds the
// codebook.
public int synthesis_headerin(VorbisComment vc, OggPacket op){
OggBuffer opb=new OggBuffer();
if(op!=null){
opb.readinit(op.packet_base, op.packet, op.bytes);
// Which of the three types of header is this?
// Also verify header-ness, vorbis
{
byte[] buffer=new byte[6];
int packtype=opb.read(8);
opb.read(buffer, 6);
if(buffer[0]!='v'||buffer[1]!='o'||buffer[2]!='r'||buffer[3]!='b'
||buffer[4]!='i'||buffer[5]!='s'){
// not a vorbis header
return (-1);
}
switch(packtype){
case 0x01: // least significant *bit* is read first
if(op.b_o_s==0){
// Not the initial packet
return (-1);
}
if(rate!=0){
// previously initialized info header
return (-1);
}
return (unpack_info(opb));
case 0x03: // least significant *bit* is read first
if(rate==0){
// um... we didn't get the initial header
return (-1);
}
return (vc.unpack(opb));
case 0x05: // least significant *bit* is read first
if(rate==0||vc.vendor==null){
// um... we didn;t get the initial header or comments yet
return (-1);
}
return (unpack_books(opb));
default:
// Not a valid vorbis header type
//return(-1);
break;
}
}
}
return (-1);
}
// pack side
int pack_info(OggBuffer opb){
// preamble
opb.write(0x01, 8);
opb.write(_vorbis);
// basic information about the stream
opb.write(0x00, 32);
opb.write(channels, 8);
opb.write(rate, 32);
opb.write(bitrate_upper, 32);
opb.write(bitrate_nominal, 32);
opb.write(bitrate_lower, 32);
opb.write(Util.ilog2(blocksizes[0]), 4);
opb.write(Util.ilog2(blocksizes[1]), 4);
opb.write(1, 1);
return (0);
}
int pack_books(OggBuffer opb){
opb.write(0x05, 8);
opb.write(_vorbis);
// books
opb.write(books-1, 8);
for(int i=0; i<books; i++){
if(book_param[i].pack(opb)!=0){
//goto err_out;
return (-1);
}
}
// times
opb.write(times-1, 6);
for(int i=0; i<times; i++){
opb.write(time_type[i], 16);
FuncTime.time_P[time_type[i]].pack(this.time_param[i], opb);
}
// floors
opb.write(floors-1, 6);
for(int i=0; i<floors; i++){
opb.write(floor_type[i], 16);
FuncFloor.floor_P[floor_type[i]].pack(floor_param[i], opb);
}
// residues
opb.write(residues-1, 6);
for(int i=0; i<residues; i++){
opb.write(residue_type[i], 16);
FuncResidue.residue_P[residue_type[i]].pack(residue_param[i], opb);
}
// maps
opb.write(maps-1, 6);
for(int i=0; i<maps; i++){
opb.write(map_type[i], 16);
FuncMapping.mapping_P[map_type[i]].pack(this, map_param[i], opb);
}
// modes
opb.write(modes-1, 6);
for(int i=0; i<modes; i++){
opb.write(mode_param[i].blockflag, 1);
opb.write(mode_param[i].windowtype, 16);
opb.write(mode_param[i].transformtype, 16);
opb.write(mode_param[i].mapping, 8);
}
opb.write(1, 1);
return (0);
}
public int blocksize(OggPacket op){
//codec_setup_info
OggBuffer opb=new OggBuffer();
int mode;
opb.readinit(op.packet_base, op.packet, op.bytes);
/* Check the packet type */
if(opb.read(1)!=0){
/* Oops. This is not an audio data packet */
return (OV_ENOTAUDIO);
}
{
int modebits=0;
int v=modes;
while(v>1){
modebits++;
v>>>=1;
}
/* read our mode and pre/post windowsize */
mode=opb.read(modebits);
}
if(mode==-1)
return (OV_EBADPACKET);
return (blocksizes[mode_param[mode].blockflag]);
}
@Override
public String toString(){
return "version:"+version+", channels:"+channels
+", rate:"+rate+", bitrate:"+bitrate_upper
+","+bitrate_nominal+","+bitrate_lower;
}
}

View File

@@ -0,0 +1,93 @@
package eu.midnightdust.picturesign_theora.util;
import eu.midnightdust.picturesign.util.MediaHandler;
import eu.midnightdust.picturesign_theora.ogv.Video;
import eu.midnightdust.picturesign_theora.ogv.VideoManager;
import net.minecraft.client.MinecraftClient;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import org.lwjgl.opengl.GL11;
public class TheoraMediaHandler extends MediaHandler {
public static final VideoManager manager = new VideoManager();
private Video player;
private String url;
public TheoraMediaHandler(Identifier id, BlockPos pos) {
super(id, pos);
mediaHandlers.put(id, this);
}
@Override
public void setVolume(int volume) {
player.setVolume((int) (volume * MinecraftClient.getInstance().options.getSoundVolume(SoundCategory.MASTER)));
}
@Override
public void closePlayer() {
manager.closePlayer(id);
if (player != null) {
player.stop();
player.destroy();
}
//mediaPlayers.remove(id);
player = null;
}
@Override
public void stop() {
player.stop();
isDeactivated = true;
}
@Override
public boolean isStopped() {
return player.isStopped();
}
@Override
public void restart() {
player.play(url);
}
@Override
public void play(String url, boolean isVideo) {
System.out.println("Playing: " + url);
this.player = manager.getOrCreate(id);
mediaHandlers.put(id, this);
//if (player.isBroken()) return;
player.play(url);
this.url = url;
this.playbackStarted = true;
}
@Override
public boolean hasMedia() {
return player != null && player.hasMedia();
}
@Override
public void setRepeat(boolean value) {
player.setRepeat(true);
}
@Override
public long getTime() {
return player.getTime();
}
@Override
public void setTime(long value) {
player.setTime(value);
}
@Override
public int getTexture() {
if (player != null) {
int tex = player.getTextureId();
if (GL11.glIsTexture(tex)) return tex;
}
return -1;
}
@Override
public boolean isReady() {
return true;
}
@Override
public boolean isWorking() {
return mediaHandlers.containsKey(id) && mediaHandlers.get(id) instanceof TheoraMediaHandler theoraMediaHandler
&& theoraMediaHandler.player != null;
}
}

View File

@@ -0,0 +1,11 @@
{
"required": true,
"package": "eu.midnightdust.picturesign_theora.mixin",
"compatibilityLevel": "JAVA_17",
"client": [
"MixinMinecraftClient"
],
"injectors": {
"defaultRequire": 1
}
}

63
fabric/build.gradle Normal file
View File

@@ -0,0 +1,63 @@
plugins {
id 'com.github.johnrengelman.shadow'
//id "me.shedaniel.unified-publishing"
}
architectury {
platformSetupLoomIde()
fabric()
}
loom {
}
configurations {
common
shadowCommon // Don't use shadow from the shadow plugin since it *excludes* files.
compileClasspath.extendsFrom common
runtimeClasspath.extendsFrom common
developmentFabric.extendsFrom common
archivesBaseName = rootProject.archives_base_name + "-fabric"
}
dependencies {
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
modApi "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}"
modImplementation include ("maven.modrinth:midnightlib:${rootProject.midnightlib_version}-fabric")
modImplementation ("maven.modrinth:picturesign:${rootProject.picturesign_version}-fabric")
common(project(path: ":common", configuration: "namedElements")) { transitive false }
shadowCommon(project(path: ":common", configuration: "transformProductionFabric")) { transitive false }
}
processResources {
inputs.property "version", project.version
filesMatching("fabric.mod.json") {
expand "version": project.version
}
}
shadowJar {
exclude "architectury.common.json"
configurations = [project.configurations.shadowCommon]
archiveClassifier = "dev-shadow"
}
remapJar {
input.set shadowJar.archiveFile
dependsOn shadowJar
}
sourcesJar {
def commonSources = project(":common").sourcesJar
dependsOn commonSources
from commonSources.archiveFile.map { zipTree(it) }
}
components.java {
withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
skip()
}
}

View File

@@ -0,0 +1,11 @@
package eu.midnightdust.picturesign_theora.fabric;
import eu.midnightdust.picturesign_theora.PictureSignTheoraClient;
import net.fabricmc.api.ClientModInitializer;
public class PictureSignTheoraClientFabric implements ClientModInitializer {
@Override
public void onInitializeClient() {
PictureSignTheoraClient.init();
}
}

View File

@@ -0,0 +1,34 @@
{
"schemaVersion": 1,
"id": "picturesign-theora",
"version": "${version}",
"name": "PictureSign: Theora",
"description": "Adds support for Theora, Vorbis and OGG to PictureSign",
"authors": [
"unascribed",
"Motschen"
],
"contact": {
"homepage": "https://www.midnightdust.eu/",
"sources": "https://github.com/TeamMidnightDust/PictureSignTheora",
"issues": "https://github.com/TeamMidnightDust/PictureSignTheora/issues"
},
"license": "MIT",
"icon": "assets/picturesign/icon.png",
"environment": "client",
"entrypoints": {
"client": [
"eu.midnightdust.picturesign_theora.fabric.PictureSignTheoraClientFabric"
]
},
"depends": {
"picturesign": "*"
},
"mixins": [
"picturesign-theora.mixins.json"
]
}

24
gradle.properties Executable file
View File

@@ -0,0 +1,24 @@
org.gradle.jvmargs=-Xmx2048M
minecraft_version=1.21
yarn_mappings=1.21+build.2
enabled_platforms=fabric,neoforge
archives_base_name=picturesign-theora
mod_version=1.0.0
maven_group=eu.midnightdust
release_type=release
curseforge_id=
modrinth_id=
midnightlib_version=1.5.7
picturesign_version=2.0.1
fabric_loader_version=0.15.11
fabric_api_version=0.100.1+1.21
neoforge_version=21.0.14-beta
yarn_mappings_patch_neoforge_version = 1.21+build.4
quilt_loader_version=0.19.0-beta.18
quilt_fabric_api_version=7.0.1+0.83.0-1.20

BIN
gradle/wrapper/gradle-wrapper.jar vendored Executable file

Binary file not shown.

7
gradle/wrapper/gradle-wrapper.properties vendored Executable file
View File

@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

249
gradlew vendored Executable file
View File

@@ -0,0 +1,249 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# 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
#
# https://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.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

92
gradlew.bat vendored Executable file
View File

@@ -0,0 +1,92 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

76
neoforge/build.gradle Normal file
View File

@@ -0,0 +1,76 @@
plugins {
id 'com.github.johnrengelman.shadow'
//id "me.shedaniel.unified-publishing"
}
repositories {
maven {
name = 'NeoForged'
url = 'https://maven.neoforged.net/releases'
}
}
architectury {
platformSetupLoomIde()
neoForge()
}
loom {
accessWidenerPath = project(":common").loom.accessWidenerPath
}
configurations {
common {
canBeResolved = true
canBeConsumed = false
}
compileClasspath.extendsFrom common
runtimeClasspath.extendsFrom common
developmentNeoForge.extendsFrom common
// Files in this configuration will be bundled into your mod using the Shadow plugin.
// Don't use the `shadow` configuration from the plugin itself as it's meant for excluding files.
shadowBundle {
canBeResolved = true
canBeConsumed = false
}
archivesBaseName = rootProject.archives_base_name + "-neoforge"
}
dependencies {
neoForge "net.neoforged:neoforge:$rootProject.neoforge_version"
modImplementation include ("maven.modrinth:midnightlib:${rootProject.midnightlib_version}-neoforge")
common(project(path: ':common', configuration: 'namedElements')) { transitive false }
shadowBundle project(path: ':common', configuration: 'transformProductionNeoForge')
}
processResources {
inputs.property 'version', project.version
filesMatching('META-INF/neoforge.mods.toml') {
expand version: project.version
}
}
shadowJar {
configurations = [project.configurations.shadowBundle]
archiveClassifier = 'dev-shadow'
}
remapJar {
input.set shadowJar.archiveFile
}
sourcesJar {
def commonSources = project(":common").sourcesJar
dependsOn commonSources
from commonSources.archiveFile.map { zipTree(it) }
}
components.java {
withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
skip()
}
}

View File

@@ -0,0 +1 @@
loom.platform=neoforge

View File

@@ -0,0 +1,13 @@
package eu.midnightdust.picturesign_theora.neoforge;
import eu.midnightdust.picturesign_theora.PictureSignTheoraClient;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.fml.common.Mod;
@SuppressWarnings("all")
@Mod(value = "picturesign-theora", dist = Dist.CLIENT)
public class PictureSignClientNeoForge {
public PictureSignClientNeoForge() {
PictureSignTheoraClient.init();
}
}

View File

@@ -0,0 +1,38 @@
modLoader = "javafml"
loaderVersion = "[2,)"
#issueTrackerURL = ""
license = "MIT License"
[[mods]]
modId = "picturesign-theora"
version = "${version}"
displayName = "PictureSign: Theora"
logoFile = "icon.png"
authors = "unascribed, Motschen"
description = '''
Adds support for Theora, Vorbis and OGG to PictureSign
'''
[[mixins]]
config = "picturesign-theora.mixins.json"
[[dependencies.visualoverhaul]]
modId = "neoforge"
mandatory = true
versionRange = "[21.0,)"
ordering = "NONE"
side = "BOTH"
[[dependencies.visualoverhaul]]
modId = "minecraft"
mandatory = true
versionRange = "[1.21,)"
ordering = "NONE"
side = "BOTH"
[[dependencies.visualoverhaul]]
modId = "picturesign"
mandatory = true
versionRange = "[1.0,)"
ordering = "AFTER"
side = "BOTH"

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

15
settings.gradle Executable file
View File

@@ -0,0 +1,15 @@
pluginManagement {
repositories {
maven { url "https://maven.fabricmc.net/" }
maven { url "https://maven.architectury.dev/" }
maven { url "https://maven.neoforged.net/releases" }
gradlePluginPortal()
}
}
include("common")
include("fabric")
//include("quilt")
include("neoforge")
rootProject.name = "picturesign-theora"