/* * Copyright (c) 2009-2011, IETR/INSA of Rennes * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the IETR/INSA of Rennes nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ package net.sf.orcc.simulators.runtime.std.video.impl; import java.awt.Canvas; import java.awt.Graphics; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferStrategy; import java.awt.image.BufferedImage; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.math.BigInteger; import javax.swing.JFrame; import net.sf.orcc.OrccRuntimeException; import net.sf.orcc.simulators.AbstractSimulator; import net.sf.orcc.simulators.runtime.impl.GenericDisplay; import net.sf.orcc.util.OrccLogger; /** * This class defines native functions for the DisplayYUV actor. * * @author Matthieu Wipliez * */ public class Display extends GenericDisplay { private static BufferStrategy buffer; private static Canvas canvas; private static JFrame frame; private static int frameNumber = 0; private static BufferedImage image; private static RandomAccessFile in; private static int lastHeight; private static int lastWidth; private static long t1; private static long t2; private static boolean useCompare; /** * Close open frames (if any) and clear all */ public static void clearAll() { if (frame != null && frame.isVisible()) { frame.setVisible(false); frame.dispose(); } if (buffer != null) { buffer.dispose(); } canvas = null; image = null; lastHeight = 0; lastWidth = 0; } private static int clip(int n) { if (n < 0) { return 0; } else if (n > 255) { return 255; } else { return n; } } private static int compareYUV_compareComponent(int width, int height, byte[] golden, byte[] approximate, int SizeMbSide) { int pix_x, pix_y, blk_x, blk_y; int error = 0; int WidthSzInBlk = width / SizeMbSide; int HeightSzInBlk = height / SizeMbSide; for (blk_y = 0; blk_y < HeightSzInBlk; blk_y++) { for (blk_x = 0; blk_x < WidthSzInBlk; blk_x++) { for (pix_y = 0; pix_y < SizeMbSide; pix_y++) { for (pix_x = 0; pix_x < SizeMbSide; pix_x++) { int Idx_pix = (blk_y * SizeMbSide + pix_y) * width + (blk_x * SizeMbSide + pix_x); if (golden[Idx_pix] - approximate[Idx_pix] != 0) { error++; } } } } } return error; } /** * Compares the contents in the given buffers with a golden reference. * * @param pictureBufferY * Y buffer * @param pictureBufferU * U buffer * @param pictureBufferV * V buffer * @param pictureWidth * width * @param pictureHeight * height */ public static void compareYUV_comparePicture(byte[] pictureBufferY, byte[] pictureBufferU, byte[] pictureBufferV, BigInteger pictureWidth, BigInteger pictureHeight) { int width = pictureWidth.intValue(); int height = pictureHeight.intValue(); if (useCompare) { byte[] Y = new byte[width * height]; byte[] U = new byte[width * height / 4]; byte[] V = new byte[width * height / 4]; try { int numErrors = 0; OrccLogger.trace("Frame number " + frameNumber); frameNumber++; in.read(Y, 0, width * height); in.read(U, 0, width * height / 4); in.read(V, 0, width * height / 4); numErrors += compareYUV_compareComponent(width, height, Y, pictureBufferY, 16); numErrors += compareYUV_compareComponent(width / 2, height / 2, U, pictureBufferU, 8); numErrors += compareYUV_compareComponent(width / 2, height / 2, V, pictureBufferV, 8); if (numErrors == 0) { OrccLogger.traceRaw("; no error detected !\n"); } else { OrccLogger.traceRaw("; " + numErrors + " errors detected !\n"); AbstractSimulator.statusCode++; } if (in.getFilePointer() == in.length()) { in.seek(0L); frameNumber = 0; } } catch (IOException e) { e.printStackTrace(); } } } /** * Init the YUV comparison. */ public static void compareYUV_init() { useCompare = false; if (!goldenReference.isEmpty()) { try { in = new RandomAccessFile(goldenReference, "r"); useCompare = true; } catch (FileNotFoundException e) { String msg = "File not found: \"" + goldenReference + "\""; throw new OrccRuntimeException(msg, e); } } } private static int convertYCbCrtoRGB(int y, int cb, int cr) { int C = y - 16; int D = cb - 128; int E = cr - 128; int r = clip((298 * C + 409 * E + 128) >> 8); int g = clip((298 * C - 100 * D - 208 * E + 128) >> 8); int b = clip((298 * C + 516 * D + 128) >> 8); return (r << 16) | (g << 8) | b; } public static void displayYUV_displayPicture(byte[] pictureBufferY, byte[] pictureBufferU, byte[] pictureBufferV, BigInteger biPictureWidth, BigInteger biPictureHeight) { int pictureWidth = biPictureWidth.intValue(); int pictureHeight = biPictureHeight.intValue(); if (pictureWidth != lastWidth || pictureHeight != lastHeight) { setVideoSize(pictureWidth, pictureHeight); } if (image == null) { return; } for (int i = 0; i < pictureWidth / 2; i++) { for (int j = 0; j < pictureHeight / 2; j++) { int u = pictureBufferU[i + j * pictureWidth / 2] & 0xFF; int v = pictureBufferV[i + j * pictureWidth / 2] & 0xFF; int y0 = pictureBufferY[i * 2 + j * 2 * pictureWidth] & 0xFF; int y1 = pictureBufferY[i * 2 + 1 + j * 2 * pictureWidth] & 0xFF; int y2 = pictureBufferY[i * 2 + (j * 2 + 1) * pictureWidth] & 0xFF; int y3 = pictureBufferY[i * 2 + 1 + (j * 2 + 1) * pictureWidth] & 0xFF; int rgb0 = convertYCbCrtoRGB(y0, u, v); int rgb1 = convertYCbCrtoRGB(y1, u, v); int rgb2 = convertYCbCrtoRGB(y2, u, v); int rgb3 = convertYCbCrtoRGB(y3, u, v); image.setRGB(i * 2, j * 2, rgb0); image.setRGB(i * 2 + 1, j * 2, rgb1); image.setRGB(i * 2, j * 2 + 1, rgb2); image.setRGB(i * 2 + 1, j * 2 + 1, rgb3); } } if (buffer != null) { Graphics graphics = buffer.getDrawGraphics(); graphics.drawImage(image, 0, 0, null); buffer.show(); graphics.dispose(); } } /** * Returns the flags of the display. This implementation returns a display * always enabled and ready. * * @return the flags of the display */ public static BigInteger displayYUV_getFlags() { return BigInteger.valueOf(displayStatus); } /** * Return the value user has set in command line with -f argument. * * @return The value set by user, or DEFAULT_NB_FRAMES value if user did not * set any value */ public static BigInteger displayYUV_getNbFrames() { return BigInteger.valueOf(nbFrames); } /** * Initializes the display. */ public static void displayYUV_init() { clearAll(); frame = new JFrame("display"); canvas = new Canvas(); frame.add(canvas); frame.setResizable(false); frame.setVisible(true); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { frame.dispose(); AbstractSimulator.userStop(); } }); } public static void fpsPrintInit() { t1 = System.currentTimeMillis(); } public static void fpsPrintNewPicDecoded() { t2 = System.currentTimeMillis(); OrccLogger.noticeRaw("Image displayed in " + (t2 - t1) + " ms\n"); t1 = t2; } private static void setVideoSize(int newWidth, int newHeight) { lastWidth = newWidth; lastHeight = newHeight; if (canvas != null) { canvas.setSize(lastWidth, lastHeight); frame.pack(); canvas.createBufferStrategy(2); buffer = canvas.getBufferStrategy(); image = new BufferedImage(lastWidth, lastHeight, BufferedImage.TYPE_INT_RGB); } } }