[xiph-commits] r17142 - trunk/rhea/src/com/meviatronic/zeus/pollux
maikmerten at svn.xiph.org
maikmerten at svn.xiph.org
Mon Apr 12 11:00:41 PDT 2010
Author: maikmerten
Date: 2010-04-12 11:00:41 -0700 (Mon, 12 Apr 2010)
New Revision: 17142
Added:
trunk/rhea/src/com/meviatronic/zeus/pollux/DumpVideo.java
Modified:
trunk/rhea/src/com/meviatronic/zeus/pollux/TheoraDecoder.java
Log:
Port DumpVideo.java to Pollux. This enables PSNR comparisons with the reference decoder and jheora (hint: Anything other than INF is suboptimal).
Added: trunk/rhea/src/com/meviatronic/zeus/pollux/DumpVideo.java
===================================================================
--- trunk/rhea/src/com/meviatronic/zeus/pollux/DumpVideo.java (rev 0)
+++ trunk/rhea/src/com/meviatronic/zeus/pollux/DumpVideo.java 2010-04-12 18:00:41 UTC (rev 17142)
@@ -0,0 +1,310 @@
+/* Copyright (C) <2009> Maik Merten <maikmerten at googlemail.com>
+ * Copyright (C) <2004> Wim Taymans <wim at fluendo.com> (TheoraDec.java parts)
+ *
+ * This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package com.meviatronic.zeus.pollux;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.xiph.ogg.Packet;
+import org.xiph.ogg.Page;
+import org.xiph.ogg.StreamState;
+import org.xiph.ogg.SyncState;
+
+/**
+ * This class borrows code from TheoraDec.java
+ */
+public class DumpVideo {
+
+ public static final Integer OK = new Integer(0);
+ public static final Integer ERROR = new Integer(-5);
+ private static final byte[] signature = {-128, 0x74, 0x68, 0x65, 0x6f, 0x72, 0x61};
+ Logger log = Logger.getLogger(this.getClass().getName());
+
+ private class TheoraDecoderWrapper {
+
+ private VideoReader info = new VideoReader();
+ private TheoraDecoder dec;
+ private short[][] ycbcrdata;
+ int packet = 0;
+ int frame = 0;
+
+ public TheoraDecoderWrapper() {
+ super();
+ }
+
+ public boolean takePacket(Packet p) {
+
+ if (packet < 3) {
+ try {
+ info.readMediaInformation(p);
+ packet++;
+
+ if (packet == 3) {
+ dec = new TheoraDecoder(info);
+ }
+
+ } catch (Exception ex) {
+ Logger.getLogger(DumpVideo.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ } else {
+ try {
+ dec.synthesis(p);
+ ycbcrdata = dec.getYCbCrData();
+
+ System.out.println("Decoded frame: " + ++frame);
+
+ } catch (Exception ex) {
+ Logger.getLogger(DumpVideo.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ }
+ return true;
+ }
+ }
+
+ private class YUVWriter {
+
+ private OutputStream os;
+ private boolean wroteHeader = false;
+ private byte[] ybytes;
+ private byte[] uvbytes;
+ private boolean raw;
+
+ public YUVWriter(File outfile, boolean raw) {
+ this.raw = raw;
+ try {
+ os = new FileOutputStream(outfile);
+ } catch (FileNotFoundException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ public void writeYUVFrame(VideoReader ti, short[][] yuv) {
+
+ int width = ti.codedPictureWidth;
+ int height = ti.codedPictureHeight;
+
+ // TODO: Support other modes than 4:2:0!!!
+ int uvwidth = width / 2;
+ int uvheight = height / 2;
+
+ int fps_numerator = (int) ti.frameRate * 100000;
+ int fps_denominator = 100000;
+ int aspect_numerator = ti.aspectRatio.width;
+ int aspect_denominator = ti.aspectRatio.height;
+
+ // TODO: crop image according to offset
+
+ try {
+ if (!raw) {
+ if (!wroteHeader) {
+ String headerstring = "YUV4MPEG2 W" + width + " H" + height + " F" + fps_numerator + ":" + fps_denominator + " Ip A" + aspect_numerator + ":" + aspect_denominator + "\n";
+ os.write(headerstring.getBytes());
+ wroteHeader = true;
+ }
+ os.write("FRAME\n".getBytes());
+ }
+
+ if (ybytes == null || ybytes.length != yuv[0].length) {
+ ybytes = new byte[yuv[0].length];
+ }
+
+
+ // image from decoder is upside-down, so mirror it vertically
+ for (int line = 0; line < height; ++line) {
+ int offset = line * width;
+ int offset2 = ((height - 1) - line) * width;
+ for (int x = 0; x < width; ++x) {
+ ybytes[offset2 + x] = (byte) yuv[0][offset + x];
+ }
+ }
+
+ os.write(ybytes);
+
+ if (uvbytes == null || uvbytes.length != yuv[1].length) {
+ uvbytes = new byte[yuv[1].length];
+ }
+
+ for (int line = 0; line < uvheight; ++line) {
+ int offset = line * uvwidth;
+ int offset2 = ((uvheight - 1) - line) * uvwidth;
+ for (int x = 0; x < uvwidth; ++x) {
+ uvbytes[offset2 + x] = (byte) yuv[1][offset + x];
+ }
+ }
+ os.write(uvbytes);
+
+ if (uvbytes == null || uvbytes.length != yuv[2].length) {
+ uvbytes = new byte[yuv[2].length];
+ }
+
+ for (int line = 0; line < uvheight; ++line) {
+ int offset = line * uvwidth;
+ int offset2 = ((uvheight - 1) - line) * uvwidth;
+ for (int x = 0; x < uvwidth; ++x) {
+ uvbytes[offset2 + x] = (byte) yuv[2][offset + x];
+ }
+ }
+ os.write(uvbytes);
+
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ public boolean isTheora(Packet op) {
+ return typeFind(op.packetBase, op.packet, op.bytes) > 0;
+ }
+
+ private boolean startsWith(byte[] data, int offset, int length, byte[] signature) {
+ if (length < signature.length) {
+ return false;
+ }
+
+ for (int i = 0; i < signature.length; ++i) {
+ if (data[offset + i] != signature[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int typeFind(byte[] data, int offset, int length) {
+ if (startsWith(data, offset, length, signature)) {
+ return 10;
+ }
+ return -1;
+ }
+
+ public void dumpVideo(File videofile, List outfiles, boolean raw) throws IOException {
+ InputStream is = new FileInputStream(videofile);
+
+ SyncState oy = new SyncState();
+ Page og = new Page();
+ Packet op = new Packet();
+ byte[] buf = new byte[512];
+
+ Map streamstates = new HashMap();
+ Map theoradecoders = new HashMap();
+ Map yuvwriters = new HashMap();
+ Set hasdecoder = new HashSet();
+
+
+ int read = is.read(buf);
+ while (read > 0) {
+ int offset = oy.buffer(read);
+ java.lang.System.arraycopy(buf, 0, oy.data, offset, read);
+ oy.wrote(read);
+
+ while (oy.pageout(og) == 1) {
+
+ Integer serialno = new Integer(og.serialno());
+
+ StreamState state = (StreamState) streamstates.get(serialno);
+ if (state == null) {
+ state = new StreamState();
+ state.init(serialno.intValue());
+ streamstates.put(serialno, state);
+ log.info("created StreamState for stream no. " + og.serialno());
+ }
+
+ state.pagein(og);
+
+ while (state.packetout(op) == 1) {
+
+ if (!(hasdecoder.contains(serialno)) && isTheora(op)) {
+
+ TheoraDecoderWrapper theoradec = (TheoraDecoderWrapper) theoradecoders.get(serialno);
+ if (theoradec == null) {
+ theoradec = new TheoraDecoderWrapper();
+ theoradecoders.put(serialno, theoradec);
+ hasdecoder.add(serialno);
+ }
+
+ log.info("is Theora: " + serialno);
+ }
+
+ TheoraDecoderWrapper theoradec = (TheoraDecoderWrapper) theoradecoders.get(serialno);
+
+ if (theoradec != null) {
+ theoradec.takePacket(op);
+
+ if (theoradec.ycbcrdata != null) {
+ YUVWriter yuvwriter = (YUVWriter) yuvwriters.get(serialno);
+ if (yuvwriter == null && !outfiles.isEmpty()) {
+ yuvwriter = new YUVWriter((File) outfiles.get(0), raw);
+ yuvwriters.put(serialno, yuvwriter);
+ outfiles.remove(0);
+ }
+
+ if (yuvwriter != null) {
+ yuvwriter.writeYUVFrame(theoradec.info, theoradec.ycbcrdata);
+ }
+ }
+ }
+ }
+ }
+ read = is.read(buf);
+ }
+
+ }
+
+ public static void main(String[] args) throws Exception {
+
+ if (args.length < 2) {
+ System.err.println("usage: DumpVideo <videofile> <outfile_1> ... <outfile_n> [--raw>]");
+ System.exit(1);
+
+
+ }
+
+ boolean raw = false;
+ File infile = new File(args[0]);
+
+ List outfiles = new LinkedList();
+
+
+ for (int i = 1; i < args.length; ++i) {
+ if (args[i].equals("--raw")) {
+ raw = true;
+ break;
+ }
+ outfiles.add(new File(args[i]));
+ }
+
+ DumpVideo dv = new DumpVideo();
+
+ dv.dumpVideo(infile, outfiles, raw);
+
+ }
+}
+
Property changes on: trunk/rhea/src/com/meviatronic/zeus/pollux/DumpVideo.java
___________________________________________________________________
Added: svn:eol-style
+ native
Modified: trunk/rhea/src/com/meviatronic/zeus/pollux/TheoraDecoder.java
===================================================================
--- trunk/rhea/src/com/meviatronic/zeus/pollux/TheoraDecoder.java 2010-04-11 16:38:32 UTC (rev 17141)
+++ trunk/rhea/src/com/meviatronic/zeus/pollux/TheoraDecoder.java 2010-04-12 18:00:41 UTC (rev 17142)
@@ -2236,7 +2236,7 @@
}
}
- boolean display() {
+ public boolean display() {
if (ncbs == 0 || externFrameCount == internFrameCount) {
return false;
}
@@ -2256,8 +2256,11 @@
externFrameCount = internFrameCount;
return true;
}
-
+ public final short[][] getYCbCrData() {
+ return ref;
+ }
+
/**
* Frees all system resources, which are bounded to this object.
*/
More information about the commits
mailing list