mirror of
https://github.com/TeamMidnightDust/PictureSignTheora.git
synced 2025-12-15 07:55:08 +01:00
PictureSign: Theora Addon
Big thanks to @unascribed (https://github.com/TeamMidnightDust/PictureSign/pull/23)
This commit is contained in:
26
.gitignore
vendored
Executable file
26
.gitignore
vendored
Executable 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
81
build.gradle
Executable 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
25
common/build.gradle
Normal 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.
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 ); }
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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.");
|
||||
|
||||
}*/
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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(){
|
||||
}
|
||||
}
|
||||
@@ -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){
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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]));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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(){
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
11
common/src/main/resources/picturesign-theora.mixins.json
Executable file
11
common/src/main/resources/picturesign-theora.mixins.json
Executable 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
63
fabric/build.gradle
Normal 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()
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
34
fabric/src/main/resources/fabric.mod.json
Executable file
34
fabric/src/main/resources/fabric.mod.json
Executable 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
24
gradle.properties
Executable 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
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Executable file
Binary file not shown.
7
gradle/wrapper/gradle-wrapper.properties
vendored
Executable file
7
gradle/wrapper/gradle-wrapper.properties
vendored
Executable 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
249
gradlew
vendored
Executable 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
92
gradlew.bat
vendored
Executable 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
76
neoforge/build.gradle
Normal 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()
|
||||
}
|
||||
}
|
||||
1
neoforge/gradle.properties
Normal file
1
neoforge/gradle.properties
Normal file
@@ -0,0 +1 @@
|
||||
loom.platform=neoforge
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
38
neoforge/src/main/resources/META-INF/neoforge.mods.toml
Normal file
38
neoforge/src/main/resources/META-INF/neoforge.mods.toml
Normal 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"
|
||||
BIN
neoforge/src/main/resources/icon.png
Executable file
BIN
neoforge/src/main/resources/icon.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
15
settings.gradle
Executable file
15
settings.gradle
Executable 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"
|
||||
Reference in New Issue
Block a user