kopia lustrzana https://github.com/F5OEO/tstools
Modify copyright notice in ac3.c (Kynesim is a trading name ..)
Initial import of yuv2. --HG-- extra : convert_revision : svn%3Aeff31bef-be4a-0410-a8fe-e47997df2690/trunk%4065issue20
rodzic
5e19e0782a
commit
fa9a6b71ee
2
ac3.c
2
ac3.c
|
@ -22,7 +22,7 @@
|
|||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Kynesim Ltd, Cambridge UK
|
||||
* Kynesim, Cambridge UK
|
||||
*
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
#
|
||||
# Set JAVA_HOME to the location of your Java installation.
|
||||
# Set SWTDIR to the location which contains your swt.jar.
|
||||
#
|
||||
# make will then build a yuv2.jar .
|
||||
#
|
||||
# bin/ contains a script wrapper you can use to invoke your
|
||||
# yuv2.jar . Edit bin/yuv2 to give the location of your yuv2.jar.
|
||||
#
|
||||
|
||||
SRC_DIR=src/com/aminocom/yuv2
|
||||
SRC_FILES=AboutBox.java BufferedImage.java FormatDialog.java \
|
||||
ImageCanvas.java LogWindow.java MainFrame.java Prefs.java \
|
||||
Utils.java YUV2.java
|
||||
|
||||
LOCATED_SRC=$(SRC_FILES:%.java=$(SRC_DIR)/%.java)
|
||||
|
||||
|
||||
all:
|
||||
if [ ! -d obj ]; then mkdir obj; fi
|
||||
$$JAVA_HOME/bin/javac -cp $$SWTDIR/swt.jar -d obj -s bin $(LOCATED_SRC)
|
||||
(cd obj; $$JAVA_HOME/bin/jar -xf $$SWTDIR/swt.jar)
|
||||
(cd obj; $$JAVA_HOME/bin/jar -cmf ../src/Manifest-Extras.txt ../yuv2.jar *)
|
||||
|
||||
clean:
|
||||
rm -rf obj
|
||||
rm -f yuv2.jar
|
||||
|
||||
|
||||
# End file.
|
|
@ -0,0 +1,37 @@
|
|||
YUV2: A YUV viewer.
|
||||
------------------
|
||||
|
||||
YUV2 is a cross-platform Java YUV file viewer intended for video
|
||||
codec engineers. It includes pseudo-video playback, macroblock
|
||||
and pixel value viewers for both frame and field mode.
|
||||
|
||||
It'll get extended as we need more features - do feel free to jump
|
||||
in and help.
|
||||
|
||||
This initial release is for Linux only (because that's what I've
|
||||
got on my desktop). To get things working on Windows you will need
|
||||
to translate the GNU makefile into a Windows NMAKE file or (more
|
||||
likely) a batch script and use the Windows SWT.
|
||||
|
||||
You will need SWT, available from <http://www.eclipse.org/swt/>.
|
||||
|
||||
This code was originally written for SJ Consulting and originally
|
||||
released by Amino Communications Ltd in March 2008 - I've only just
|
||||
got around to tidying it up enough that it deserves a public release.
|
||||
|
||||
TO BUILD YUV2
|
||||
-------------
|
||||
|
||||
Set JAVA_HOME to where your Java is - e.g. /usr/local/jdk1.6.0_07 .
|
||||
Set SWTDIR to wherever your swt.jar is.
|
||||
Type 'make'.
|
||||
Copy yuv2.jar to somewhere convenient (default is /usr/local/lib)
|
||||
Edit bin/yuv2 to reflect the directory where you put yuv2.
|
||||
Copy bin/yuv2 to somewhere on your PATH.
|
||||
Report (or better still, fix) the bugs!
|
||||
|
||||
|
||||
|
||||
Richard Watts
|
||||
<rrw@kynesim.co.uk>
|
||||
2008-09-15
|
|
@ -0,0 +1,5 @@
|
|||
#! /bin/sh
|
||||
|
||||
YUV2DIR=/usr/local/lib
|
||||
exec java -jar $YUV2DIR/yuv2.jar $*
|
||||
|
|
@ -0,0 +1 @@
|
|||
Main-Class: com.aminocom.yuv2.YUV2
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Code for the About box.
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the MPEG TS, PS and ES tools.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Amino Communications Ltd.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Amino Communications Ltd, Swavesey, Cambridge UK
|
||||
* Kynesim, Cambridge UK
|
||||
*
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
package com.aminocom.yuv2;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.custom.StyledText;
|
||||
import org.eclipse.swt.layout.FormAttachment;
|
||||
import org.eclipse.swt.layout.FormLayout;
|
||||
import org.eclipse.swt.layout.RowLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Listener;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
public class AboutBox {
|
||||
Shell mShell;
|
||||
|
||||
public static final String sCommentText =
|
||||
"Pre-release version. Please report bugs to \n" +
|
||||
" <rrw@sj.co.uk>";
|
||||
|
||||
public AboutBox(Shell inParent)
|
||||
{
|
||||
mShell = new Shell(inParent);
|
||||
mShell.setLayout(new FormLayout());
|
||||
mShell.setText("About YUV2");
|
||||
|
||||
Composite topPanel = new Composite(mShell, SWT.NONE);
|
||||
Composite bottomPanel = new Composite(mShell,
|
||||
SWT.NONE);
|
||||
|
||||
Label about = new Label(topPanel, SWT.NONE);
|
||||
about.setText("YUV2 0.3 (c) SJ Consulting 2006");
|
||||
|
||||
StyledText mainText = new StyledText(topPanel,
|
||||
SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
|
||||
mainText.setText(sCommentText);
|
||||
|
||||
{
|
||||
RowLayout rl = new RowLayout();
|
||||
rl.fill = true;
|
||||
rl.type = SWT.VERTICAL;
|
||||
topPanel.setLayout(rl);
|
||||
}
|
||||
|
||||
{
|
||||
RowLayout rl = new RowLayout();
|
||||
bottomPanel.setLayout(rl);
|
||||
}
|
||||
|
||||
Button ok = new Button(bottomPanel, SWT.NONE);
|
||||
ok.setText("Dismiss");
|
||||
ok.addListener(SWT.Selection,
|
||||
new Listener()
|
||||
{
|
||||
public void handleEvent(Event ev)
|
||||
{
|
||||
AboutBox.this.close();
|
||||
}
|
||||
});
|
||||
|
||||
topPanel.setLayoutData(Utils.makeFormData
|
||||
(new FormAttachment(0),
|
||||
new FormAttachment(100),
|
||||
new FormAttachment(0),
|
||||
new FormAttachment(bottomPanel)));
|
||||
|
||||
bottomPanel.setLayoutData(Utils.makeFormData
|
||||
(new FormAttachment(0),
|
||||
new FormAttachment(100),
|
||||
null,
|
||||
new FormAttachment(100)));
|
||||
mShell.pack();
|
||||
}
|
||||
public void show()
|
||||
{
|
||||
mShell.open();
|
||||
while (!mShell.isDisposed())
|
||||
{
|
||||
if (!mShell.getDisplay().readAndDispatch())
|
||||
{
|
||||
mShell.getDisplay().sleep();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
mShell.close();
|
||||
}
|
||||
|
||||
public boolean isDisposed()
|
||||
{
|
||||
return mShell.isDisposed();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,301 @@
|
|||
/*
|
||||
* Display an image, performing colourspace conversion as we do so.
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the MPEG TS, PS and ES tools.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Amino Communications Ltd.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Amino Communications Ltd, Swavesey, Cambridge UK
|
||||
* Kynesim, Cambridge UK
|
||||
*
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
|
||||
package com.aminocom.yuv2;
|
||||
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.graphics.ImageData;
|
||||
import org.eclipse.swt.graphics.PaletteData;
|
||||
|
||||
/** This class buffers a frame from a file in the hope that
|
||||
* we can make animation a bit smoother.
|
||||
*
|
||||
* @author rrw
|
||||
*
|
||||
*/
|
||||
public class BufferedImage {
|
||||
ImageCanvas mParentCanvas;
|
||||
MainFrame mContainingFrame;
|
||||
int mFrameNumber;
|
||||
boolean mReadyForDrawing;
|
||||
|
||||
/** The image data to paint. This is updated
|
||||
* whenever we do anything by updateImageData().
|
||||
*
|
||||
* When we have no image data, we set this to NULL
|
||||
* and paint plain white.
|
||||
*/
|
||||
ImageData mImageData;
|
||||
|
||||
/** The image to paint, if present.
|
||||
*/
|
||||
Image mImage;
|
||||
|
||||
/** Y frame buffer. Used in image conversion and
|
||||
* the dropper tool.
|
||||
* Frame buffers are stored in ordinary raster format.
|
||||
*/
|
||||
byte[] mYBuf, mUBuf, mVBuf;
|
||||
|
||||
BufferedImage(int inFrameNumber,
|
||||
ImageCanvas inParent)
|
||||
{
|
||||
mParentCanvas = inParent;
|
||||
mContainingFrame = inParent.mContainingFrame;
|
||||
mFrameNumber = inFrameNumber;
|
||||
mReadyForDrawing = false;
|
||||
}
|
||||
|
||||
void dispose()
|
||||
{
|
||||
if (mImage != null)
|
||||
{
|
||||
mImage.dispose();
|
||||
}
|
||||
mImage = null; mImageData = null;
|
||||
}
|
||||
|
||||
boolean convertImage(boolean inQuiet)
|
||||
{
|
||||
RandomAccessFile reader = mParentCanvas.getReader();
|
||||
|
||||
|
||||
if (reader == null)
|
||||
{
|
||||
// No file ..
|
||||
return false;
|
||||
}
|
||||
// Start off by killing any old data ..
|
||||
// We actually do want to do this here - the last thing the
|
||||
// user wants is to navigate to a frame and have us redisplay
|
||||
// the last one they visited.
|
||||
|
||||
if (mImage != null)
|
||||
{
|
||||
mImage.dispose();
|
||||
}
|
||||
mImageData = null;
|
||||
mImage = null;
|
||||
|
||||
if (mParentCanvas.mWidth == 0 ||
|
||||
mParentCanvas.mHeight == 0)
|
||||
{
|
||||
// Bugger. No dimensions. Have to wait
|
||||
// until we have some.
|
||||
mContainingFrame.updateStatus();
|
||||
mParentCanvas.closeReader(reader);
|
||||
return false;
|
||||
}
|
||||
|
||||
// frame size = width * height for luma, half that for chroma.
|
||||
long frameSize = (mParentCanvas.mWidth *
|
||||
mParentCanvas.mHeight * 3)>>1;
|
||||
long fileOffset = frameSize*((long)mFrameNumber);
|
||||
|
||||
if (!inQuiet)
|
||||
{
|
||||
mContainingFrame.log("Frame Size = 0x" +
|
||||
Long.toString(frameSize) + " file offset for frame " +
|
||||
Integer.toString(mFrameNumber) + " = 0x" +
|
||||
Long.toString(fileOffset, 16));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
long fileLen = reader.length();
|
||||
|
||||
mParentCanvas.mFrameTotal = fileLen/frameSize;
|
||||
mContainingFrame.setNumFrames
|
||||
(mParentCanvas.mFrameTotal);
|
||||
|
||||
if (fileOffset > fileLen)
|
||||
{
|
||||
// Can't display this frame.
|
||||
mContainingFrame.note("Attempt to read frame past end of file: " +
|
||||
"frame " + Integer.toString(mFrameNumber) +
|
||||
"@" + Long.toString(fileOffset) +
|
||||
" > file len " + Long.toString(fileLen));
|
||||
mContainingFrame.updateStatus();
|
||||
mParentCanvas.closeReader(reader);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fileOffset + frameSize > fileLen)
|
||||
{
|
||||
mContainingFrame.note("File ends between frame " +
|
||||
Integer.toString(mFrameNumber) + " and " +
|
||||
Integer.toString(mFrameNumber+1));
|
||||
}
|
||||
|
||||
reader.seek(fileOffset);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
mContainingFrame.updateStatus();
|
||||
Utils.showMessageBox(mParentCanvas.mShell,
|
||||
"Can't read frame from input file.");
|
||||
}
|
||||
|
||||
|
||||
// Right. Read as much data as we can into the
|
||||
// relevant buffers. Our YUV file format is
|
||||
// Y, then U, then V, in separate chunks.
|
||||
int array_height = mParentCanvas.mHeight;
|
||||
|
||||
// Round the array size up to a multiple of two lines so
|
||||
// our conversion routine will run at a sensible speed.
|
||||
if (array_height%1 != 0)
|
||||
{
|
||||
++array_height;
|
||||
}
|
||||
|
||||
|
||||
mYBuf = new byte[mParentCanvas.mWidth * array_height];
|
||||
mUBuf = new byte[(mParentCanvas.mWidth>>1)* (array_height>>1)];
|
||||
mVBuf = new byte[(mParentCanvas.mWidth>>1) * (array_height>>1)];
|
||||
|
||||
try
|
||||
{
|
||||
reader.readFully(mYBuf);
|
||||
reader.readFully(mUBuf);
|
||||
|
||||
reader.readFully(mVBuf);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
mContainingFrame.note("Didn't get whole frame (" +
|
||||
e.getMessage() + ")");
|
||||
}
|
||||
|
||||
// Now convert to RGB ...
|
||||
|
||||
// Internally, we'll use standard RGBA, so
|
||||
// Red = 0xff, Green = 0xff00, blue = 0xff0000
|
||||
mImageData = new ImageData
|
||||
(mParentCanvas.mWidth, mParentCanvas.mHeight,
|
||||
32, new PaletteData(0xff0000, 0xff00,
|
||||
0xff));
|
||||
|
||||
// We'll convert 2 lines to make copying somewhat
|
||||
// quicker (2 lines means we can cache the chroma).
|
||||
|
||||
int[] outgoingLine = new int[2*mParentCanvas.mWidth];
|
||||
|
||||
// The input is just a standard, line-by-line
|
||||
// 4:2:0 chroma file.
|
||||
|
||||
if (!inQuiet)
|
||||
{
|
||||
mContainingFrame.transientInfo("Converting YUV image " +
|
||||
Integer.toString(mParentCanvas.mWidth) + "x" +
|
||||
Integer.toString(mParentCanvas.mHeight) + "...");
|
||||
}
|
||||
for (int i=0;i<mParentCanvas.mHeight;i += 2)
|
||||
{
|
||||
int ypos = i * mParentCanvas.mWidth;
|
||||
int uvpos = (i>>1)*(mParentCanvas.mWidth>>1);
|
||||
|
||||
for (int j=0;j<mParentCanvas.mWidth;++j)
|
||||
{
|
||||
int y0 = mYBuf[ypos + j]&0xff;
|
||||
int y1 = mYBuf[ypos + mParentCanvas.mWidth + j]&0xff;
|
||||
int u = mUBuf[uvpos + (j>>1)]&0xff;
|
||||
int v = mVBuf[uvpos + (j>>1)]&0xff;
|
||||
int r, g, b;
|
||||
int ri, gi, bi;
|
||||
int C, D, E;
|
||||
|
||||
|
||||
|
||||
C = y0 - 16;
|
||||
D = u- 128;
|
||||
E = v - 128;
|
||||
|
||||
r = ((298 * C + 409 * E + 128)>>8);
|
||||
g = ((298 * C - 100 * D - 208 * E + 128) >> 8);
|
||||
b = ((298 * C + 516 * D + 128)>>8);
|
||||
|
||||
if (r < 0) { ri = 0; } else if (r > 255) { ri = 255; } else
|
||||
ri = r;
|
||||
if (g < 0) { gi = 0; } else if (g > 255) { gi = 255; } else
|
||||
gi = g;
|
||||
if (b < 0) { bi = 0; } else if (b > 255) { bi = 255; } else
|
||||
bi = b;
|
||||
|
||||
|
||||
outgoingLine[j] = (ri << 16) | (gi << 8) | bi;
|
||||
|
||||
C = y1 - 16;
|
||||
|
||||
r = ((298 * C + 409 * E + 128)>>8);
|
||||
g = ((298 * C - 100 * D - 208 * E + 128) >> 8);
|
||||
b = ((298 * C + 516 * D + 128)>>8);
|
||||
|
||||
if (r < 0) { ri = 0; } else if (r > 255) { ri = 255; } else
|
||||
ri = r;
|
||||
if (g < 0) { gi = 0; } else if (g > 255) { gi = 255; } else
|
||||
gi = g;
|
||||
if (b < 0) { bi = 0; } else if (b > 255) { bi = 255; } else
|
||||
bi = b;
|
||||
|
||||
outgoingLine[mParentCanvas.mWidth + j]
|
||||
= (ri << 16) | (gi << 8) | bi;
|
||||
}
|
||||
|
||||
|
||||
mImageData.setPixels(0, i,
|
||||
mParentCanvas.mWidth*2,
|
||||
outgoingLine,
|
||||
0);
|
||||
}
|
||||
if (!inQuiet)
|
||||
{
|
||||
mContainingFrame.transientInfo("Done Conversion.");
|
||||
}
|
||||
|
||||
// Now we've built the ImageData, build the image ..
|
||||
mImage = new Image(null, mImageData);
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
mReadyForDrawing = true;
|
||||
}
|
||||
|
||||
mParentCanvas.closeReader(reader);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* The image format dialogue.
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the MPEG TS, PS and ES tools.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Amino Communications Ltd.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Amino Communications Ltd, Swavesey, Cambridge UK
|
||||
* Kynesim, Cambridge UK
|
||||
*
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
|
||||
package com.aminocom.yuv2;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.layout.FormAttachment;
|
||||
import org.eclipse.swt.layout.FormLayout;
|
||||
import org.eclipse.swt.layout.RowLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Combo;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
import org.eclipse.swt.widgets.Group;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Listener;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
/** This class wraps the format and type dialog.
|
||||
* Create one, then call show() on it to show the dialog
|
||||
* and modify the relevant values.
|
||||
*
|
||||
* @author rrw
|
||||
*
|
||||
*/
|
||||
public class FormatDialog {
|
||||
Shell mDialogShell;
|
||||
Shell mMessageShell;
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
int mFormat;
|
||||
boolean mIsOK;
|
||||
Combo mDimensionCombo;
|
||||
|
||||
public final String[] sStandardDimensions =
|
||||
{ "480x480", "720x480" };
|
||||
|
||||
FormatDialog(Shell parentShell,
|
||||
int inWidth,
|
||||
int inHeight,
|
||||
int inFormat)
|
||||
{
|
||||
mMessageShell = parentShell;
|
||||
mDialogShell = new Shell(parentShell,
|
||||
SWT.DIALOG_TRIM |
|
||||
SWT.APPLICATION_MODAL);
|
||||
mDialogShell.setText("Select image dimensions");
|
||||
mDialogShell.setSize(300, 200);
|
||||
mWidth = inWidth; mHeight = inHeight; mFormat = inFormat;
|
||||
|
||||
Group fileSize = new Group(mDialogShell, SWT.NONE);
|
||||
fileSize.setText("Dimensions");
|
||||
|
||||
// Image dimensions thingy ..
|
||||
{
|
||||
Label aLabel;
|
||||
Composite hRow = new Composite(fileSize, SWT.NONE);
|
||||
|
||||
fileSize.setLayout(new FormLayout());
|
||||
hRow.setLayout(new RowLayout());
|
||||
|
||||
hRow.setLayoutData(Utils.makeFormData
|
||||
(new FormAttachment(20),
|
||||
new FormAttachment(100),
|
||||
new FormAttachment(20),
|
||||
new FormAttachment(100)));
|
||||
|
||||
aLabel = new Label(hRow, SWT.NONE);
|
||||
aLabel.setText("Image Size:");
|
||||
mDimensionCombo = new Combo(hRow, SWT.NONE);
|
||||
mDimensionCombo.setItems(sStandardDimensions);
|
||||
if (mWidth > 0 && mHeight > 0)
|
||||
{
|
||||
mDimensionCombo.add
|
||||
(Integer.toString(mWidth) + "x" +
|
||||
Integer.toString(mHeight), 0);
|
||||
mDimensionCombo.select
|
||||
(0);
|
||||
}
|
||||
}
|
||||
|
||||
Group fileFormat = new Group(mDialogShell, SWT.NONE);
|
||||
fileFormat.setText("File Type");
|
||||
|
||||
// Image format.
|
||||
{
|
||||
Composite hCol = new Composite(fileFormat, SWT.NONE);
|
||||
RowLayout theLayout = new RowLayout();
|
||||
|
||||
theLayout.type = SWT.VERTICAL;
|
||||
hCol.setLayout(theLayout);
|
||||
|
||||
{
|
||||
Button aButton = new Button(hCol, SWT.RADIO | SWT.RIGHT);
|
||||
aButton.setText("YUV");
|
||||
aButton.setSelection(mFormat == 0 ? true :
|
||||
false);
|
||||
}
|
||||
|
||||
fileFormat.setLayout(new FormLayout());
|
||||
hCol.setLayoutData(Utils.makeFormData
|
||||
(new FormAttachment(20),
|
||||
new FormAttachment(100),
|
||||
new FormAttachment(20),
|
||||
new FormAttachment(100)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Composite buttons = new Composite(mDialogShell,
|
||||
SWT.NONE);
|
||||
buttons.setLayout(new RowLayout());
|
||||
|
||||
Button ok = new Button(buttons, SWT.PUSH);
|
||||
ok.setText("Ok");
|
||||
mDialogShell.setDefaultButton(ok);
|
||||
ok.addListener(SWT.Selection, new Listener()
|
||||
{
|
||||
public void handleEvent(Event event)
|
||||
{
|
||||
boolean parsedOK = parseDialog();
|
||||
|
||||
if (parsedOK)
|
||||
{
|
||||
FormatDialog.this.mIsOK = true;
|
||||
FormatDialog.this.mDialogShell.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Button cancel = new Button(buttons, SWT.PUSH);
|
||||
cancel.setText("Cancel");
|
||||
cancel.addListener(SWT.Selection, new Listener()
|
||||
{
|
||||
public void handleEvent(Event event)
|
||||
{
|
||||
FormatDialog.this.mIsOK = false;
|
||||
FormatDialog.this.mDialogShell.close();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
mDialogShell.setLayout(new FormLayout());
|
||||
fileSize.setLayoutData(Utils.makeFormData
|
||||
(new FormAttachment(0),
|
||||
new FormAttachment(fileFormat),
|
||||
new FormAttachment(0),
|
||||
new FormAttachment(buttons)));
|
||||
|
||||
fileFormat.setLayoutData(Utils.makeFormData
|
||||
(null,
|
||||
new FormAttachment(100),
|
||||
new FormAttachment(0),
|
||||
new FormAttachment(buttons)));
|
||||
buttons.setLayoutData(Utils.makeFormData
|
||||
(new FormAttachment(0),
|
||||
new FormAttachment(100),
|
||||
null,
|
||||
new FormAttachment(100)));
|
||||
|
||||
// Add the size and type to the group
|
||||
|
||||
|
||||
mDialogShell.open();
|
||||
}
|
||||
|
||||
/** Try to parse the dialog box. If we succeed,
|
||||
* return true. If we don't, pop up a message
|
||||
* box and return false.
|
||||
*/
|
||||
boolean parseDialog()
|
||||
{
|
||||
boolean parsedOK;
|
||||
String dimensionString = mDimensionCombo.getText();
|
||||
String s = mDimensionCombo.getText();
|
||||
Point results = new Point(mWidth,mHeight);
|
||||
parsedOK = Utils.parseDimensions(s, results);
|
||||
|
||||
if (!parsedOK)
|
||||
{
|
||||
Utils.showMessageBox(mMessageShell,
|
||||
"Invalid dimensions - " + dimensionString +
|
||||
" - please try again");
|
||||
}
|
||||
else
|
||||
{
|
||||
mWidth = results.x; mHeight = results.y;
|
||||
}
|
||||
return parsedOK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
boolean show()
|
||||
{
|
||||
mDialogShell.open();
|
||||
while (!mDialogShell.isDisposed())
|
||||
{
|
||||
if (!mDialogShell.getDisplay().readAndDispatch())
|
||||
{
|
||||
mDialogShell.getDisplay().sleep();
|
||||
}
|
||||
}
|
||||
|
||||
return mIsOK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* End File */
|
|
@ -0,0 +1,952 @@
|
|||
/*
|
||||
* A canvas for painting BufferedImages on.
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the MPEG TS, PS and ES tools.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Amino Communications Ltd.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Amino Communications Ltd, Swavesey, Cambridge UK
|
||||
* Kynesim, Cambridge UK
|
||||
*
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
|
||||
package com.aminocom.yuv2;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Formatter;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.DisposeEvent;
|
||||
import org.eclipse.swt.events.DisposeListener;
|
||||
import org.eclipse.swt.events.MouseEvent;
|
||||
import org.eclipse.swt.events.MouseListener;
|
||||
import org.eclipse.swt.events.MouseMoveListener;
|
||||
import org.eclipse.swt.events.PaintEvent;
|
||||
import org.eclipse.swt.events.PaintListener;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.graphics.ImageData;
|
||||
import org.eclipse.swt.graphics.PaletteData;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.widgets.Canvas;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
import org.eclipse.swt.widgets.Listener;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
public class ImageCanvas extends Canvas {
|
||||
Color mBg, mWhite;
|
||||
Shell mShell;
|
||||
int mWidth, mHeight;
|
||||
int mFormat;
|
||||
int mFrameNumber;
|
||||
long mFrameTotal;
|
||||
int mZoomNumerator, mZoomDenominator;
|
||||
boolean mIsFieldMode;
|
||||
boolean mMBMarkers;
|
||||
RandomAccessFile mReader;
|
||||
public String mFilename;
|
||||
MainFrame mContainingFrame;
|
||||
int mMacroblockInfoCounter;
|
||||
boolean mPlayMode;
|
||||
int mPlayFrame;
|
||||
int mPlayTo;
|
||||
BufferedImage mCurrentImage;
|
||||
BufferedImage mNextImage;
|
||||
boolean mNextImagePending;
|
||||
|
||||
|
||||
static class PlayThread extends Thread
|
||||
{
|
||||
ImageCanvas mCanvas;
|
||||
|
||||
public PlayThread(ImageCanvas inCanvas)
|
||||
{
|
||||
mCanvas = inCanvas;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
int sleepTime = 40; // Inter-frame time.
|
||||
|
||||
|
||||
synchronized (mCanvas)
|
||||
{
|
||||
if (mCanvas.mKillAnimationThread)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (mCanvas.mPlayMode &&
|
||||
(mCanvas.mFrameNumber < mCanvas.mFrameTotal &&
|
||||
(mCanvas.mPlayTo == -1 ||
|
||||
mCanvas.mFrameNumber < mCanvas.mPlayTo)))
|
||||
{
|
||||
boolean done_something = false;
|
||||
|
||||
// We're not allowed to do this directly, so.
|
||||
if (!mCanvas.mAdvancePending &&
|
||||
!mCanvas.mNextImagePending)
|
||||
{
|
||||
YUV2.addWork(new YUV2.WorkRequest
|
||||
(mCanvas.mContainingFrame,
|
||||
YUV2.WorkRequest.ADVANCE_PLAY));
|
||||
mCanvas.mAdvancePending = true;
|
||||
done_something = true;
|
||||
}
|
||||
|
||||
if (!mCanvas.mNextImagePending)
|
||||
{
|
||||
mCanvas.mNextImagePending = true;
|
||||
YUV2.addWork(new YUV2.WorkRequest
|
||||
(mCanvas,
|
||||
YUV2.WorkRequest.BUFFER_NEXT_IMAGE));
|
||||
done_something = true;
|
||||
}
|
||||
|
||||
if (!done_something)
|
||||
{
|
||||
// We wanted to draw, but couldn't. Check
|
||||
// again soon!
|
||||
sleepTime = 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're stopped. Wait until we're turned on again.
|
||||
YUV2.addWork(new YUV2.WorkRequest
|
||||
(mCanvas.mContainingFrame,
|
||||
YUV2.WorkRequest.STOP_PLAY));
|
||||
|
||||
try
|
||||
{
|
||||
mCanvas.wait();
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
// Might as well check now ..
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Sleep for the inter-frame time, which is 1/25s =
|
||||
// 4ms.
|
||||
try
|
||||
{
|
||||
sleep(sleepTime);
|
||||
} catch (InterruptedException ie)
|
||||
{
|
||||
// Meh.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The actual play thread ..
|
||||
PlayThread mPlayThread;
|
||||
boolean mAdvancePending;
|
||||
boolean mKillAnimationThread;
|
||||
|
||||
ImageCanvas(Composite inParent,
|
||||
MainFrame inContainingFrame,
|
||||
Shell inShell,
|
||||
int style)
|
||||
{
|
||||
super(inParent, style + SWT.NO_BACKGROUND);
|
||||
mContainingFrame = inContainingFrame;
|
||||
mMacroblockInfoCounter = 0;
|
||||
mShell = inShell;
|
||||
mWidth = mHeight = 0;
|
||||
mFrameNumber = 0;
|
||||
mFrameTotal = 0;
|
||||
mFormat = 0;
|
||||
mIsFieldMode = false;
|
||||
mZoomNumerator = 1; mZoomDenominator = 1;
|
||||
mMBMarkers = false;
|
||||
mAdvancePending = false;
|
||||
mKillAnimationThread = false;
|
||||
mBg = new Color(null, 255, 255, 255);
|
||||
mWhite = new Color(null, 255, 255, 255);
|
||||
// Create the play thread.
|
||||
setPlayMode(false);
|
||||
mPlayTo = -1;
|
||||
mPlayFrame = 0;
|
||||
mNextImagePending = false;
|
||||
|
||||
mCurrentImage = mNextImage = null;
|
||||
|
||||
mPlayThread = new PlayThread(this);
|
||||
mPlayThread.start();
|
||||
setBackground(mBg);
|
||||
addDisposeListener(new Disposer());
|
||||
addPaintListener(new Painter());
|
||||
addMouseListener(new ClickLogger());
|
||||
addListener(SWT.Resize,
|
||||
new Listener()
|
||||
{
|
||||
public void handleEvent(Event ev)
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
addMouseMoveListener(new Mouser());
|
||||
}
|
||||
|
||||
// Instruct our animation thread to die.
|
||||
public void prepareForExit()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
mKillAnimationThread = true;
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/** Set the play mode
|
||||
*
|
||||
*/
|
||||
void setPlayMode(boolean inValue)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
mPlayMode = inValue;
|
||||
mPlayFrame = 0;
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Attempt to close a reader, emitting an error
|
||||
* dialog if we fail.
|
||||
*
|
||||
* @param reader The reader to close.
|
||||
*/
|
||||
void closeReader(RandomAccessFile reader)
|
||||
{
|
||||
|
||||
// Do we have anything to do at all?
|
||||
if (reader == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
reader.close();
|
||||
}
|
||||
catch (Exception ioe)
|
||||
{
|
||||
Utils.showMessageBox(mShell,
|
||||
"Cannot close " + mFilename + " - " +
|
||||
ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
RandomAccessFile getReader()
|
||||
{
|
||||
|
||||
if (mFilename == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
File aFile = new File(mFilename);
|
||||
RandomAccessFile rv = null;
|
||||
|
||||
if (!aFile.exists())
|
||||
{
|
||||
Utils.showMessageBox(mShell,
|
||||
mFilename + " does not exist");
|
||||
return null;
|
||||
}
|
||||
/* Open the file .. */
|
||||
try
|
||||
{
|
||||
rv = new RandomAccessFile(aFile, "r");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.showMessageBox
|
||||
(mShell,
|
||||
"Cannot open " + mFilename + " - " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/** Opens a file. If we have X and Y coordinates,
|
||||
* we will attempt to display the file.
|
||||
*
|
||||
* @return true if we succeeded, false if we didn't
|
||||
* and displayed an error box.
|
||||
*/
|
||||
boolean openFile(String fileName)
|
||||
{
|
||||
File theFile = new File(fileName);
|
||||
|
||||
if (!theFile.exists())
|
||||
{
|
||||
Utils.showMessageBox(mShell,
|
||||
fileName + " does not exist.");
|
||||
return false;
|
||||
}
|
||||
|
||||
RandomAccessFile reader = null;
|
||||
|
||||
try
|
||||
{
|
||||
reader = new RandomAccessFile(theFile,
|
||||
"r");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.showMessageBox
|
||||
(mShell,
|
||||
"Cannot open " + fileName + " - " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Otherwise .. */
|
||||
if (reader != null)
|
||||
{
|
||||
closeReader(reader);
|
||||
}
|
||||
|
||||
mFilename = fileName;
|
||||
updateImage();
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Change the frame number we're looking at, and
|
||||
* update the image.
|
||||
*/
|
||||
void changeFrameNumber(int inFrameNumber)
|
||||
{
|
||||
if (inFrameNumber == mFrameNumber)
|
||||
{
|
||||
return;
|
||||
}
|
||||
mFrameNumber = inFrameNumber;
|
||||
mContainingFrame.transientInfo("Go to frame " +
|
||||
Integer.toString(mFrameNumber));
|
||||
updateImage();
|
||||
}
|
||||
|
||||
/** Change the width, height and format settings, and
|
||||
* update the image.
|
||||
*/
|
||||
void changeFormat(int inWidth, int inHeight, int inFormat)
|
||||
{
|
||||
if (inWidth == mWidth && inHeight == mHeight &&
|
||||
inFormat == mFormat)
|
||||
{
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
mWidth = inWidth; mHeight = inHeight;
|
||||
mFormat = inFormat;
|
||||
|
||||
mContainingFrame.note("Changed format: " +
|
||||
Integer.toString(mWidth) + "x" +
|
||||
Integer.toString(mHeight) + " " +
|
||||
Utils.formatToString(mFormat));
|
||||
|
||||
updateImage();
|
||||
}
|
||||
|
||||
void makeNextImage()
|
||||
{
|
||||
if (mNextImage != null)
|
||||
{
|
||||
mNextImage.dispose();
|
||||
}
|
||||
|
||||
mNextImage =new BufferedImage(mFrameNumber + 1, this);
|
||||
mNextImage.convertImage(true);
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
mNextImagePending = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Try to read in the required image from the
|
||||
* given data.
|
||||
*
|
||||
* @return true if we managed to synthesise an
|
||||
* image, false if we didn't.
|
||||
*/
|
||||
boolean updateImage()
|
||||
{
|
||||
// Force a repaint.
|
||||
this.redraw();
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
if (mNextImage != null &&
|
||||
mNextImage.mFrameNumber == mFrameNumber)
|
||||
{
|
||||
// We already have one :-).
|
||||
mCurrentImage.dispose();
|
||||
mCurrentImage = mNextImage;
|
||||
mFrameNumber = mNextImage.mFrameNumber;
|
||||
mNextImage = null;
|
||||
if (!mCurrentImage.mReadyForDrawing)
|
||||
{
|
||||
this.redraw();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mCurrentImage != null)
|
||||
{
|
||||
mCurrentImage.dispose();
|
||||
}
|
||||
mCurrentImage = new BufferedImage(mFrameNumber, this);
|
||||
|
||||
|
||||
if (!mCurrentImage.convertImage(false))
|
||||
{
|
||||
this.redraw();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resize ourselves, incidentally updating the status bar.
|
||||
this.updateSize();
|
||||
|
||||
|
||||
|
||||
// The redraw itself may not happen, so setting advancePending here
|
||||
// is the least worst we can do.
|
||||
synchronized (this)
|
||||
{
|
||||
mAdvancePending = false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/** Update the size of this widget in response to an
|
||||
* image update or a zoom level update.
|
||||
*/
|
||||
void updateSize()
|
||||
{
|
||||
int actualWidth = (mWidth * mZoomNumerator) / mZoomDenominator;
|
||||
int actualHeight = (mHeight * mZoomNumerator) / mZoomDenominator;
|
||||
|
||||
if (actualWidth == 0 && actualHeight == 0)
|
||||
{
|
||||
actualWidth = 720;
|
||||
actualHeight = 576;
|
||||
}
|
||||
|
||||
Point currentSize = this.getSize();
|
||||
|
||||
if (actualWidth != currentSize.x ||
|
||||
actualHeight != currentSize.y)
|
||||
{
|
||||
this.setSize(actualWidth, actualHeight);
|
||||
}
|
||||
|
||||
this.setTitle();
|
||||
mContainingFrame.updateStatus();
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
if (mCurrentImage != null)
|
||||
{
|
||||
mCurrentImage.dispose();
|
||||
}
|
||||
if (mNextImage != null)
|
||||
{
|
||||
mNextImage.dispose();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// Local function: set the window title to something
|
||||
// descriptive.
|
||||
void setTitle()
|
||||
{
|
||||
StringBuffer aTitle = new StringBuffer();
|
||||
|
||||
if (mFilename == null)
|
||||
{
|
||||
aTitle.append("YUV2 - No file loaded ");
|
||||
}
|
||||
else
|
||||
{
|
||||
aTitle.append("YUV2 - ");
|
||||
aTitle.append(mFilename);
|
||||
aTitle.append(" ");
|
||||
aTitle.append(Integer.toString(mWidth));
|
||||
aTitle.append("x");
|
||||
aTitle.append(Integer.toString(mHeight));
|
||||
aTitle.append(" ");
|
||||
}
|
||||
aTitle.append(" F:");
|
||||
aTitle.append(Integer.toString(mFrameNumber));
|
||||
aTitle.append("/");
|
||||
aTitle.append(Long.toString(mFrameTotal-1));
|
||||
aTitle.append(" Z:");
|
||||
aTitle.append(Integer.toString(mZoomNumerator));
|
||||
aTitle.append("/");
|
||||
aTitle.append(Integer.toString(mZoomDenominator));
|
||||
|
||||
mShell.setText(aTitle.toString());
|
||||
}
|
||||
|
||||
public void SetZoomNumerator(int inNumerator)
|
||||
{
|
||||
mZoomNumerator = inNumerator;
|
||||
|
||||
mContainingFrame.transientInfo("Set zoom " +
|
||||
Integer.toString(mZoomNumerator) + ":" +
|
||||
Integer.toString(mZoomDenominator));
|
||||
|
||||
this.updateSize();
|
||||
this.redraw();
|
||||
}
|
||||
|
||||
public void SetZoomDenominator(int inDenominator)
|
||||
{
|
||||
if (inDenominator < 1)
|
||||
{
|
||||
// Ha ha. Very funny :-)
|
||||
return;
|
||||
}
|
||||
mZoomDenominator = inDenominator;
|
||||
|
||||
mContainingFrame.note("Set zoom " +
|
||||
Integer.toString(mZoomNumerator) + ":" +
|
||||
Integer.toString(mZoomDenominator));
|
||||
|
||||
this.updateSize();
|
||||
this.redraw();
|
||||
}
|
||||
|
||||
/** Get Info about a particular pixel location in the widget.
|
||||
*
|
||||
*/
|
||||
StringBuffer getPixelInfo(int x, int y)
|
||||
{
|
||||
StringBuffer rv = new StringBuffer();
|
||||
int pixel_x = (x * mZoomDenominator) / mZoomNumerator;
|
||||
int pixel_y = (y * mZoomDenominator) / mZoomNumerator;
|
||||
Point mb_frame = new Point(pixel_x/16, pixel_y/16);
|
||||
Point mb_field = new Point(pixel_x/16, (pixel_y >> 1)/16);
|
||||
|
||||
rv.append("("); rv.append(Integer.toString(pixel_x));
|
||||
rv.append(",");
|
||||
rv.append(Integer.toString(pixel_y));
|
||||
rv.append(") MB ");
|
||||
if (mIsFieldMode)
|
||||
{
|
||||
rv.append("<" + Integer.toString(mb_field.x) + "," +
|
||||
Integer.toString(mb_field.y) + "," +
|
||||
Integer.toString(((pixel_y & 16) != 0)? 1 : 0) + ">");
|
||||
rv.append(" @" + Integer.toString(pixel_x%16) + "," +
|
||||
Integer.toString((pixel_y>>1)%16));
|
||||
}
|
||||
else
|
||||
{
|
||||
rv.append("( " + Integer.toString(mb_frame.x) + "," +
|
||||
Integer.toString(mb_frame.y) + ")");
|
||||
rv.append(" @" + Integer.toString(pixel_x%16) + "," +
|
||||
Integer.toString(pixel_y%16));
|
||||
}
|
||||
|
||||
|
||||
|
||||
rv.append(" = ");
|
||||
if (pixel_x < mWidth && pixel_y <= mHeight &&
|
||||
pixel_x >= 0 && pixel_y >= 0)
|
||||
{
|
||||
int yoffset = (pixel_y * mWidth) + pixel_x;
|
||||
int uvoffset = ((pixel_y>>1) * (mWidth >> 1)) + (pixel_x>>1);
|
||||
rv.append("0x" + Integer.toString(mCurrentImage.mYBuf[yoffset]&0xff, 16) + " ");
|
||||
rv.append("0x" + Integer.toString(mCurrentImage.mUBuf[uvoffset]&0xff, 16) + " ");
|
||||
rv.append("0x" + Integer.toString(mCurrentImage.mVBuf[uvoffset]&0xff, 16) + ">");
|
||||
}
|
||||
return rv;
|
||||
|
||||
}
|
||||
|
||||
boolean hasValidImage()
|
||||
{
|
||||
return ((mCurrentImage != null) &&
|
||||
(mCurrentImage.mImage != null) &&
|
||||
(mCurrentImage.mUBuf != null) &&
|
||||
(mCurrentImage.mVBuf != null) &&
|
||||
(mCurrentImage.mYBuf != null));
|
||||
}
|
||||
|
||||
/** The user dragged on (x,y). Show them some information about
|
||||
* it.
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
void dropper(int x, int y, boolean clicked)
|
||||
{
|
||||
if (!hasValidImage())
|
||||
{
|
||||
mContainingFrame.transientInfo
|
||||
("No current image");
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuffer rv = getPixelInfo(x,y);
|
||||
if (!clicked)
|
||||
{
|
||||
mContainingFrame.transientInfo(rv.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
mContainingFrame.note(rv.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** The user double-clicked; dump macroblock info.
|
||||
*
|
||||
*
|
||||
*
|
||||
* */
|
||||
void dumpMacroblock(int click_x, int click_y)
|
||||
{
|
||||
if (!hasValidImage())
|
||||
{
|
||||
mContainingFrame.transientInfo
|
||||
("No current image");
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder logInfo = new StringBuilder();
|
||||
|
||||
int pixel_x = (click_x * mZoomDenominator) / mZoomNumerator;
|
||||
int pixel_y = (click_y * mZoomDenominator) / mZoomNumerator;
|
||||
|
||||
logInfo.append(Integer.toString(mMacroblockInfoCounter) +
|
||||
" : Macroblock info at pixel " +
|
||||
Integer.toString(pixel_x) + "," +
|
||||
Integer.toString(pixel_y));
|
||||
|
||||
++mMacroblockInfoCounter;
|
||||
|
||||
if (pixel_x < 0 || pixel_y < 0 ||
|
||||
pixel_x >= mWidth || pixel_y >= mHeight)
|
||||
{
|
||||
logInfo.append(": Coordinates out of range.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Actually do it.
|
||||
Point mb_coords = new Point(0,0);
|
||||
boolean topField;
|
||||
boolean inFieldMode = this.mIsFieldMode;
|
||||
// Formatter requires us to use a dummy array for its arguments.
|
||||
Object tmpO[] = new Object[1];
|
||||
|
||||
if (inFieldMode)
|
||||
{
|
||||
mb_coords.x = (pixel_x >> 4);
|
||||
mb_coords.y = (pixel_y&~1)>>4;
|
||||
topField = ((pixel_y&1) == 0) ? true : false;
|
||||
logInfo.append(" Field MB <" +
|
||||
Integer.toString(mb_coords.x) + "," +
|
||||
Integer.toString(mb_coords.y) + "," +
|
||||
(topField ? "0" : "1") + ">:\n");
|
||||
|
||||
// Now dump the MB
|
||||
{
|
||||
int y_offset = ((mb_coords.y * 32) +
|
||||
(topField ? 0 : 1)) * mWidth +
|
||||
mb_coords.x * 16;
|
||||
|
||||
// the -16 is here to cope with macroblocks that run just
|
||||
// off the end of the array.
|
||||
int y_max = ((mWidth) * mHeight) - 16;
|
||||
int uv_offset = ((mb_coords.y * 16) +
|
||||
(topField ? 0 : 1)) * (mWidth >> 1) +
|
||||
(mb_coords.x * 8);
|
||||
int uv_max = ((mWidth>>1)*(mHeight>>1))-8;
|
||||
Formatter formatter = new Formatter(logInfo, Locale.UK);
|
||||
|
||||
|
||||
logInfo.append("Y:\n");
|
||||
|
||||
// y_offset += mWidth *2 because we're in field mode.
|
||||
for (int y = 0; y < 16 && y_offset <= y_max; ++y,
|
||||
y_offset += mWidth*2)
|
||||
{
|
||||
for (int x = 0; x < 16; ++x)
|
||||
{
|
||||
tmpO[0] = new Byte(mCurrentImage.mYBuf[y_offset + x]);
|
||||
formatter.format("%02x ", tmpO);
|
||||
}
|
||||
logInfo.append("\n");
|
||||
}
|
||||
logInfo.append("\n");
|
||||
logInfo.append("U:\n");
|
||||
for (int y = 0, uv_cur = uv_offset;
|
||||
y < 8 && uv_cur <= uv_max;
|
||||
++y, uv_cur += mWidth)
|
||||
{
|
||||
for (int x = 0; x < 8; ++x)
|
||||
{
|
||||
tmpO[0] = new Byte(mCurrentImage.mUBuf[uv_cur + x]);
|
||||
formatter.format("%02x ", tmpO);
|
||||
|
||||
}
|
||||
logInfo.append("\n");
|
||||
}
|
||||
logInfo.append("\n");
|
||||
logInfo.append("V:\n");
|
||||
for (int y = 0, uv_cur = uv_offset;
|
||||
y < 8 && uv_cur <= uv_max;
|
||||
++y, uv_cur += mWidth)
|
||||
{
|
||||
for (int x = 0; x < 8; ++ x)
|
||||
{
|
||||
tmpO[0] = new Byte(mCurrentImage.mVBuf[uv_cur + x]);
|
||||
formatter.format("%02x ", tmpO);
|
||||
}
|
||||
logInfo.append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mb_coords.x = (pixel_x >> 4);
|
||||
mb_coords.y = (pixel_y >> 4);
|
||||
topField = true;
|
||||
logInfo.append(" Frame MB (" +
|
||||
Integer.toString(mb_coords.x) + "," +
|
||||
Integer.toString(mb_coords.y) + "):\n");
|
||||
|
||||
|
||||
/* Dump the macroblock */
|
||||
|
||||
{
|
||||
int y_offset = ((mb_coords.y * 16)*mWidth) +
|
||||
mb_coords.x*16;
|
||||
int y_max = (mWidth * mHeight) - 16;
|
||||
int uv_offset = ((mb_coords.y * 8) * (mWidth >> 1)) +
|
||||
mb_coords.x*8;
|
||||
int uv_max = ((mWidth >> 1) * (mHeight >> 1)) - 8;
|
||||
Formatter formatter = new Formatter(logInfo, Locale.UK);
|
||||
|
||||
logInfo.append("Y:\n");
|
||||
for (int y = 0; y < 16 && y_offset <= y_max; ++y,
|
||||
y_offset += mWidth)
|
||||
{
|
||||
for (int x = 0; x < 16 ; ++ x)
|
||||
{
|
||||
tmpO[0] = new Byte(mCurrentImage.mYBuf[y_offset + x]);
|
||||
formatter.format("%02x ", tmpO);
|
||||
}
|
||||
logInfo.append("\n");
|
||||
}
|
||||
|
||||
logInfo.append("\n");
|
||||
logInfo.append("U:\n");
|
||||
for (int y=0, uv_cur = uv_offset;
|
||||
y < 8 && uv_cur <= uv_max;
|
||||
++y, uv_cur += mWidth >> 1)
|
||||
{
|
||||
for (int x = 0; x<8;++x)
|
||||
{
|
||||
tmpO[0] = new Byte(mCurrentImage.mUBuf[uv_cur + x]);
|
||||
formatter.format("%02x ", tmpO);
|
||||
}
|
||||
logInfo.append("\n");
|
||||
}
|
||||
logInfo.append("\n");
|
||||
logInfo.append("V:\n");
|
||||
for (int y=0, uv_cur = uv_offset;
|
||||
y < 8 && uv_cur <= uv_max;
|
||||
++y, uv_cur += mWidth >> 1)
|
||||
{
|
||||
for (int x = 0; x<8;++x)
|
||||
{
|
||||
tmpO[0] = new Byte(mCurrentImage.mVBuf[uv_cur + x]);
|
||||
|
||||
formatter.format("%02x ", tmpO);
|
||||
}
|
||||
logInfo.append("\n");
|
||||
}
|
||||
logInfo.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Log everything ..
|
||||
mContainingFrame.log(logInfo.toString());
|
||||
|
||||
}
|
||||
|
||||
|
||||
void setFieldMode(boolean inIsField)
|
||||
{
|
||||
mIsFieldMode = inIsField;
|
||||
this.setTitle();
|
||||
mContainingFrame.updateStatus();
|
||||
this.redraw(); // << Markers may need updating.
|
||||
}
|
||||
void setMBMarkers(boolean inMBMarkers)
|
||||
{
|
||||
mMBMarkers = inMBMarkers;
|
||||
this.setTitle();
|
||||
mContainingFrame.updateStatus();
|
||||
redraw();
|
||||
}
|
||||
|
||||
|
||||
class ClickLogger implements MouseListener
|
||||
{
|
||||
public void mouseDoubleClick(MouseEvent e)
|
||||
{
|
||||
// Got a double-click; dump this macroblock to the log.
|
||||
dumpMacroblock(e.x, e.y);
|
||||
}
|
||||
public void mouseDown(MouseEvent e)
|
||||
{
|
||||
// Double-click is almost always what you want, and the
|
||||
// single-click behaviour messes up the logs :-(.
|
||||
// dropper(e.x, e.y, true);
|
||||
}
|
||||
public void mouseUp(MouseEvent e)
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
class Mouser implements MouseMoveListener
|
||||
{
|
||||
|
||||
public void mouseMove(MouseEvent theEvent)
|
||||
{
|
||||
/* If you move the mouse over a pixel, and you have a
|
||||
* button held down, we activate the dropper.
|
||||
*/
|
||||
dropper(theEvent.x, theEvent.y, false);
|
||||
}
|
||||
}
|
||||
|
||||
class Disposer implements DisposeListener
|
||||
{
|
||||
public void widgetDisposed(DisposeEvent e)
|
||||
{
|
||||
mBg.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class Painter implements PaintListener
|
||||
{
|
||||
public void paintControl(PaintEvent e)
|
||||
{
|
||||
int hDimension = (mWidth * mZoomNumerator)/ mZoomDenominator;
|
||||
int vDimension = (mHeight * mZoomNumerator) / mZoomDenominator;
|
||||
|
||||
// Just to prove we exist :-).
|
||||
e.gc.setBackground(mBg);
|
||||
e.gc.setForeground(mWhite);
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
if (mCurrentImage != null &&
|
||||
mCurrentImage.mImage != null)
|
||||
{
|
||||
e.gc.drawImage(mCurrentImage.mImage, 0, 0, mWidth, mHeight,
|
||||
0, 0,
|
||||
hDimension, vDimension);
|
||||
}
|
||||
else
|
||||
{
|
||||
e.gc.fillRectangle(e.x, e.y, e.width,e.height);
|
||||
}
|
||||
}
|
||||
|
||||
/* Any macroblock markers? */
|
||||
if (mMBMarkers)
|
||||
{
|
||||
/* Work out how big we're supposed to draw them .. */
|
||||
int hStep = (16 * mZoomNumerator) / mZoomDenominator;
|
||||
int vStep = (16 * mZoomNumerator) / mZoomDenominator;
|
||||
|
||||
/* If we're in field mode, double the Y stride
|
||||
* (actually, anything we do here will be wrong, but
|
||||
* Rhodri reckons this is the least wrong thing to do,
|
||||
* and I agree)
|
||||
*/
|
||||
if (mIsFieldMode)
|
||||
{
|
||||
vStep <<= 1;
|
||||
}
|
||||
|
||||
/* If either of our steps were going to be zero,
|
||||
* don't bother drawing anything - we'll just obliterate
|
||||
* the image.
|
||||
*/
|
||||
if (hStep != 0 && vStep != 0)
|
||||
{
|
||||
e.gc.setXORMode(true);
|
||||
for (int j=0;j<=vDimension;j += vStep)
|
||||
{
|
||||
/* Draw the horizontals */
|
||||
e.gc.drawLine(0, j, hDimension, j);
|
||||
}
|
||||
|
||||
/* Draw the verticals. We get cancellation
|
||||
* at the edges, but this isn't too much of
|
||||
* a problem.
|
||||
*/
|
||||
for (int i=0;i<=hDimension;i += hStep)
|
||||
{
|
||||
e.gc.drawLine(i, 0, i, vDimension);
|
||||
}
|
||||
e.gc.setXORMode(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* End file */
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* A log window.
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the MPEG TS, PS and ES tools.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Amino Communications Ltd.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Amino Communications Ltd, Swavesey, Cambridge UK
|
||||
* Kynesim, Cambridge UK
|
||||
*
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package com.aminocom.yuv2;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.custom.ScrolledComposite;
|
||||
import org.eclipse.swt.custom.StyledText;
|
||||
import org.eclipse.swt.events.SelectionAdapter;
|
||||
import org.eclipse.swt.events.SelectionEvent;
|
||||
import org.eclipse.swt.graphics.Font;
|
||||
import org.eclipse.swt.graphics.FontData;
|
||||
import org.eclipse.swt.layout.FillLayout;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.layout.RowLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
/*** This class wraps a shell that displays a log window, used
|
||||
* for persistent logging. The window is associated with a
|
||||
* MainFrame, and exists until closed.
|
||||
*
|
||||
* @author rrw
|
||||
*
|
||||
*/
|
||||
public class LogWindow {
|
||||
Shell mShell;
|
||||
ScrolledComposite mScrollArea;
|
||||
StyledText mData;
|
||||
boolean mDisposed;
|
||||
|
||||
LogWindow(Display inDisplay, Vector logLines, int nr)
|
||||
{
|
||||
mShell = new Shell(inDisplay);
|
||||
mShell.setText("Log " + Integer.toString(nr));
|
||||
mDisposed = false;
|
||||
{
|
||||
GridLayout rows = new GridLayout();
|
||||
rows.numColumns = 1;
|
||||
|
||||
mShell.setLayout(rows);
|
||||
}
|
||||
|
||||
// mScrollArea = new ScrolledComposite(mShell,
|
||||
// SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
|
||||
mData = new StyledText(mShell, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
|
||||
mData.setEditable(false);
|
||||
// mScrollArea.setLayout(new FillLayout());
|
||||
// Attempt to set a fixed pitch font.
|
||||
mData.setFont(new Font(null, new FontData("Courier", 8, SWT.NORMAL)));
|
||||
{
|
||||
GridData scrollData = new GridData();
|
||||
|
||||
scrollData.grabExcessHorizontalSpace = true;
|
||||
scrollData.grabExcessVerticalSpace = true;
|
||||
scrollData.verticalAlignment = SWT.FILL;
|
||||
scrollData.horizontalAlignment = SWT.FILL;
|
||||
mData.setLayoutData(scrollData);
|
||||
}
|
||||
|
||||
// mScrollArea.setContent(mData);
|
||||
// mScrollArea.setExpandHorizontal(true);
|
||||
// mScrollArea.setExpandVertical(true);
|
||||
// mScrollArea.setAlwaysShowScrollBars(true);
|
||||
// mScrollArea.pack();
|
||||
|
||||
mData.pack();
|
||||
{
|
||||
Composite buttonBar = new Composite(mShell, 0);
|
||||
buttonBar.setLayout(new RowLayout());
|
||||
|
||||
Button ok = new Button(buttonBar, 0);
|
||||
ok.setText("Dismiss");
|
||||
ok.addSelectionListener(new SelectionAdapter()
|
||||
{
|
||||
public void widgetSelected(SelectionEvent e)
|
||||
{
|
||||
LogWindow.this.close();
|
||||
}
|
||||
});
|
||||
|
||||
Button clear = new Button(buttonBar, 0);
|
||||
clear.setText("Clear");
|
||||
clear.addSelectionListener(new SelectionAdapter()
|
||||
{
|
||||
public void widgetSelected(SelectionEvent e)
|
||||
{
|
||||
LogWindow.this.mData.setText("");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
{
|
||||
GridData barData = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
|
||||
barData.verticalAlignment = SWT.CENTER;
|
||||
barData.verticalAlignment = SWT.CENTER;
|
||||
barData.grabExcessHorizontalSpace = false;
|
||||
barData.grabExcessVerticalSpace = false;
|
||||
buttonBar.setLayoutData(barData);
|
||||
buttonBar.pack();
|
||||
}
|
||||
}
|
||||
|
||||
loadData(logLines);
|
||||
mShell.pack();
|
||||
mShell.setSize(600, 200);
|
||||
mShell.open();
|
||||
}
|
||||
|
||||
/** Clear the log and load data into it. If you
|
||||
* set data to null, nothing will be loaded.
|
||||
*/
|
||||
void loadData(Vector inLines)
|
||||
{
|
||||
// Clear the content of the styled text.
|
||||
mData.setText("");
|
||||
|
||||
if (inLines != null)
|
||||
{
|
||||
for (int i=0;i<inLines.size();++i)
|
||||
{
|
||||
mData.append((String)inLines.elementAt(i));
|
||||
mData.append("\n");
|
||||
}
|
||||
}
|
||||
// Move to the end of the text.
|
||||
mData.setSelection(mData.getCharCount()-1);
|
||||
|
||||
mData.redraw();
|
||||
}
|
||||
|
||||
/** The log has been cleared - clear our copy of i
|
||||
*/
|
||||
void clearLog()
|
||||
{
|
||||
loadData(null);
|
||||
}
|
||||
|
||||
/** The log has been written to - update our copy.
|
||||
*
|
||||
*/
|
||||
void appendToLog(String s)
|
||||
{
|
||||
mData.append(s);
|
||||
mData.append("\n");
|
||||
|
||||
// Purely for the scroll side-effect ...
|
||||
mData.setSelection(mData.getCharCount()-1);
|
||||
mData.redraw();
|
||||
}
|
||||
|
||||
public boolean disposed()
|
||||
{
|
||||
return mDisposed;
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
mDisposed = true;
|
||||
mShell.close();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,977 @@
|
|||
/*
|
||||
* The main frame.
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the MPEG TS, PS and ES tools.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Amino Communications Ltd.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Amino Communications Ltd, Swavesey, Cambridge UK
|
||||
* Kynesim, Cambridge UK
|
||||
*
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
|
||||
package com.aminocom.yuv2;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.custom.ScrolledComposite;
|
||||
import org.eclipse.swt.events.ModifyEvent;
|
||||
import org.eclipse.swt.events.ModifyListener;
|
||||
import org.eclipse.swt.events.SelectionAdapter;
|
||||
import org.eclipse.swt.events.SelectionEvent;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.layout.FormAttachment;
|
||||
import org.eclipse.swt.layout.FormLayout;
|
||||
import org.eclipse.swt.layout.RowLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.CoolBar;
|
||||
import org.eclipse.swt.widgets.CoolItem;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
import org.eclipse.swt.widgets.FileDialog;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Listener;
|
||||
import org.eclipse.swt.widgets.Menu;
|
||||
import org.eclipse.swt.widgets.MenuItem;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.swt.widgets.Spinner;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
|
||||
|
||||
public class MainFrame {
|
||||
Shell mShell;
|
||||
Menu mMenuBar;
|
||||
Menu mRecentMenu;
|
||||
MenuItem mFileMenu;
|
||||
// The main pane.
|
||||
ScrolledComposite mImageHolder;
|
||||
ImageCanvas mImage;
|
||||
// The footer bar; consists of a couple of labels
|
||||
Composite mBottomComposite;
|
||||
Label mStatusLeft;
|
||||
Label mStatusRight;
|
||||
// Label mStatusMid;
|
||||
|
||||
// The play button, so we can set it when we stop
|
||||
// playing.
|
||||
Button mPlayButton;
|
||||
Spinner mFrameSpinner;
|
||||
|
||||
// Windows showing views on our log.
|
||||
Vector mLogWindows;
|
||||
// A vector of log lines.
|
||||
Vector mLogLines;
|
||||
|
||||
int mLogCounter;
|
||||
|
||||
// The text field which holds the number of frames
|
||||
// in the current file, so we can update it.
|
||||
Text mNumFrames;
|
||||
|
||||
// (Persistent) user preferences.
|
||||
Prefs mPrefs;
|
||||
|
||||
|
||||
/** When we change the status bar, we need to call this
|
||||
* to resize all the components
|
||||
*/
|
||||
public void displayStatusBar()
|
||||
{
|
||||
mStatusLeft.pack(); //mStatusMid.pack();
|
||||
mStatusRight.pack();
|
||||
|
||||
Point frameSize = mShell.getSize();
|
||||
Point sbSize = mBottomComposite.getSize();
|
||||
mBottomComposite.setSize(frameSize.x, sbSize.y);
|
||||
|
||||
mBottomComposite.layout();
|
||||
// mBottomComposite.pack();
|
||||
}
|
||||
|
||||
/** Display a message in the status bar - used
|
||||
* for transient messages like the dropper.
|
||||
*/
|
||||
public void transientInfo(String inString)
|
||||
{
|
||||
|
||||
mStatusLeft.setText(inString);
|
||||
displayStatusBar();
|
||||
}
|
||||
|
||||
/** Something for the log (only)
|
||||
*
|
||||
*/
|
||||
public void log(String inString)
|
||||
{
|
||||
writeToLog(inString);
|
||||
}
|
||||
|
||||
/** Something interesting happened; note it.
|
||||
*
|
||||
*/
|
||||
public void note(String inString)
|
||||
{
|
||||
// For now, do nothing.
|
||||
mStatusLeft.setText(inString);
|
||||
writeToLog(inString);
|
||||
displayStatusBar();
|
||||
}
|
||||
|
||||
/** Update the status bar in the bottom right of the
|
||||
* window.
|
||||
*
|
||||
*/
|
||||
public void updateStatus()
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
buf.append(Integer.toString(mImage.mWidth) + "x" +
|
||||
Integer.toString(mImage.mHeight));
|
||||
buf.append(" F:" + Integer.toString(mImage.mFrameNumber) + "/" +
|
||||
Long.toString(mImage.mFrameTotal-1));
|
||||
buf.append(" Z:" + Integer.toString(mImage.mZoomNumerator) + ":" +
|
||||
Integer.toString(mImage.mZoomDenominator));
|
||||
mStatusRight.setText(buf.toString());
|
||||
displayStatusBar();
|
||||
}
|
||||
|
||||
|
||||
/** Make the macroblock info toolbar
|
||||
*
|
||||
*/
|
||||
private CoolItem makeMBToolbar(CoolBar inBar)
|
||||
{
|
||||
Composite toolBar = new Composite(inBar, SWT.FLAT);
|
||||
|
||||
toolBar.setLayout(new RowLayout());
|
||||
|
||||
// Frame/field button.
|
||||
{
|
||||
Button frameField = new Button(toolBar,
|
||||
SWT.CHECK);
|
||||
frameField.setText("Field mode");
|
||||
frameField.addSelectionListener(new SelectionAdapter()
|
||||
{
|
||||
public void widgetSelected(SelectionEvent e)
|
||||
{
|
||||
MainFrame.this.mImage.setFieldMode
|
||||
(((Button)e.widget).getSelection());
|
||||
}
|
||||
});
|
||||
}
|
||||
{
|
||||
Button mbMarkers = new Button(toolBar, SWT.CHECK);
|
||||
mbMarkers.setText("MB Markers");
|
||||
mbMarkers.addSelectionListener(new SelectionAdapter()
|
||||
{
|
||||
public void widgetSelected(SelectionEvent e)
|
||||
{
|
||||
MainFrame.this.mImage.setMBMarkers
|
||||
(((Button)e.widget).getSelection());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
toolBar.pack();
|
||||
Point size = toolBar.getSize();
|
||||
CoolItem rv = new CoolItem(inBar, SWT.NONE);
|
||||
rv.setControl(toolBar);
|
||||
Point preferredSize = rv.computeSize(size.x, size.y);
|
||||
rv.setPreferredSize(preferredSize);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/** Make the zoom toolbar
|
||||
*
|
||||
*/
|
||||
private CoolItem makeZoomToolbar(CoolBar inBar)
|
||||
{
|
||||
Composite toolBar = new Composite(inBar, SWT.FLAT);
|
||||
|
||||
toolBar.setLayout(new RowLayout());
|
||||
|
||||
// Numerator ..
|
||||
{
|
||||
Spinner spinner = new Spinner(toolBar,
|
||||
SWT.BORDER);
|
||||
spinner.setMinimum(1);
|
||||
spinner.setMaximum(100);
|
||||
spinner.setSelection(1);
|
||||
spinner.setPageIncrement(1);
|
||||
spinner.pack();
|
||||
spinner.addModifyListener(new ModifyListener()
|
||||
{
|
||||
public void modifyText(ModifyEvent e)
|
||||
{
|
||||
MainFrame.this.mImage.SetZoomNumerator
|
||||
(((Spinner)e.widget).getSelection());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
Label sep = new Label(toolBar, SWT.NONE);
|
||||
sep.setText(":");
|
||||
|
||||
spinner = new Spinner(toolBar,
|
||||
SWT.BORDER);
|
||||
spinner.setMinimum(1);
|
||||
spinner.setMaximum(100);
|
||||
spinner.setSelection(1);
|
||||
spinner.setPageIncrement(1);
|
||||
spinner.pack();
|
||||
spinner.addModifyListener(new ModifyListener()
|
||||
{
|
||||
public void modifyText(ModifyEvent e)
|
||||
{
|
||||
MainFrame.this.mImage.SetZoomDenominator
|
||||
(((Spinner)e.widget).getSelection());
|
||||
}
|
||||
});
|
||||
}
|
||||
toolBar.pack();
|
||||
Point size = toolBar.getSize();
|
||||
CoolItem rv = new CoolItem(inBar, SWT.NONE);
|
||||
rv.setControl(toolBar);
|
||||
Point preferredSize = rv.computeSize(size.x, size.y);
|
||||
rv.setPreferredSize(preferredSize);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/** Make the frame toolbar
|
||||
*
|
||||
*/
|
||||
private CoolItem makeFrameToolbar(CoolBar inBar)
|
||||
{
|
||||
Composite toolBar = new Composite(inBar, SWT.FLAT);
|
||||
|
||||
toolBar.setLayout(new RowLayout());
|
||||
|
||||
// Spinner .
|
||||
{
|
||||
Spinner spinner = new Spinner(toolBar, SWT.FLAT);
|
||||
|
||||
spinner.setMinimum(0);
|
||||
spinner.setMaximum(999999);
|
||||
spinner.setSelection(0);
|
||||
spinner.setPageIncrement(1);
|
||||
spinner.pack();
|
||||
spinner.addModifyListener(new ModifyListener()
|
||||
{
|
||||
public void modifyText(ModifyEvent e)
|
||||
{
|
||||
MainFrame.this.mImage.changeFrameNumber
|
||||
(((Spinner)e.widget).getSelection());
|
||||
}
|
||||
});
|
||||
|
||||
mFrameSpinner = spinner;
|
||||
|
||||
Label sep = new Label(toolBar, SWT.NONE);
|
||||
sep.setText(" of ");
|
||||
|
||||
mNumFrames = new Text(toolBar, SWT.NONE);
|
||||
mNumFrames.setText("???");
|
||||
mNumFrames.setEditable(false);
|
||||
|
||||
// Play button.
|
||||
mPlayButton = new Button(toolBar, SWT.TOGGLE);
|
||||
mPlayButton.setText(">");
|
||||
mPlayButton.addListener(
|
||||
SWT.Selection,
|
||||
new Listener()
|
||||
{
|
||||
public void handleEvent(Event inEvent)
|
||||
{
|
||||
MainFrame.this.mImage.setPlayMode
|
||||
(((Button)inEvent.widget).getSelection());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
toolBar.pack();
|
||||
Point size = toolBar.getSize();
|
||||
CoolItem rv = new CoolItem(inBar, SWT.NONE);
|
||||
rv.setControl(toolBar);
|
||||
Point preferredSize = rv.computeSize(size.x, size.y);
|
||||
rv.setPreferredSize(preferredSize);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/** Make the view menu
|
||||
*/
|
||||
private MenuItem makeViewMenu(Menu topMenu)
|
||||
{
|
||||
MenuItem viewMenu = new MenuItem(topMenu, SWT.CASCADE);
|
||||
Menu dropDown = new Menu(mShell, SWT.DROP_DOWN);
|
||||
viewMenu.setText("View");
|
||||
viewMenu.setMenu(dropDown);
|
||||
|
||||
{
|
||||
MenuItem item = new MenuItem(dropDown, SWT.PUSH);
|
||||
item.setText("&Log");
|
||||
item.setAccelerator(SWT.CTRL + 'L');
|
||||
item.addListener(SWT.Selection,
|
||||
new Listener()
|
||||
{
|
||||
public void handleEvent(Event e)
|
||||
{
|
||||
openLog();
|
||||
}
|
||||
});
|
||||
}
|
||||
return viewMenu;
|
||||
};
|
||||
|
||||
/** Make the help menu
|
||||
*/
|
||||
private MenuItem makeHelpMenu(Menu topMenu)
|
||||
{
|
||||
MenuItem helpItem = new MenuItem(topMenu,
|
||||
SWT.CASCADE | SWT.RIGHT);
|
||||
helpItem.setText("Help");
|
||||
|
||||
Menu helpMenu = new Menu(mShell, SWT.DROP_DOWN);
|
||||
helpItem.setMenu(helpMenu);
|
||||
|
||||
{
|
||||
MenuItem aboutItem = new MenuItem(helpMenu,
|
||||
SWT.PUSH);
|
||||
aboutItem.setText("About");
|
||||
aboutItem.addListener(SWT.Selection,
|
||||
new Listener()
|
||||
{
|
||||
public void handleEvent(Event inEvent)
|
||||
{
|
||||
MainFrame.this.aboutBox();
|
||||
}});
|
||||
}
|
||||
|
||||
return helpItem;
|
||||
}
|
||||
|
||||
/** Make the recent items menu
|
||||
*
|
||||
*/
|
||||
private MenuItem makeRecentMenu(Menu topMenu)
|
||||
{
|
||||
MenuItem recentMenu = new MenuItem(topMenu,
|
||||
SWT.CASCADE);
|
||||
mRecentMenu = new Menu(mShell, SWT.DROP_DOWN);
|
||||
recentMenu.setText("Recent");
|
||||
recentMenu.setMenu(mRecentMenu);
|
||||
|
||||
mRecentMenu.addListener(SWT.Show,
|
||||
new Listener()
|
||||
{
|
||||
public void handleEvent(Event event)
|
||||
{
|
||||
fillRecentMenu();
|
||||
}
|
||||
});
|
||||
|
||||
return recentMenu;
|
||||
};
|
||||
|
||||
/** Make the file menu.
|
||||
*
|
||||
* @param topMenu
|
||||
* @return
|
||||
*/
|
||||
private MenuItem makeFileMenu(Menu topMenu)
|
||||
{
|
||||
MenuItem fileMenu = new MenuItem(topMenu, SWT.CASCADE);
|
||||
Menu dropDown = new Menu(mShell, SWT.DROP_DOWN);
|
||||
fileMenu.setText("File");
|
||||
fileMenu.setMenu(dropDown);
|
||||
|
||||
// Open
|
||||
{
|
||||
MenuItem item = new MenuItem(dropDown, SWT.PUSH);
|
||||
item.setText("&Open");
|
||||
item.setAccelerator(SWT.CTRL + 'O');
|
||||
item.addListener(SWT.Selection,
|
||||
new Listener()
|
||||
{
|
||||
public void handleEvent(Event e)
|
||||
{
|
||||
MainFrame.this.openFile(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Set parameters.
|
||||
{
|
||||
MenuItem item = new MenuItem(dropDown, SWT.PUSH);
|
||||
item.setText("&Dimensions");
|
||||
item.setAccelerator(SWT.CTRL + 'D');
|
||||
item.addListener(SWT.Selection,
|
||||
new Listener()
|
||||
{
|
||||
public void handleEvent(Event e)
|
||||
{
|
||||
MainFrame.this.setFormat
|
||||
(mPrefs.getDimensions
|
||||
(mImage.mFilename));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Separator
|
||||
{
|
||||
new MenuItem(dropDown, SWT.SEPARATOR);
|
||||
}
|
||||
|
||||
// Clear log.
|
||||
{
|
||||
MenuItem item = new MenuItem(dropDown, SWT.PUSH);
|
||||
item.setText("&Clear logs");
|
||||
item.setAccelerator(SWT.CTRL + 'C');
|
||||
item.addListener(SWT.Selection,
|
||||
new Listener()
|
||||
{
|
||||
public void handleEvent(Event e)
|
||||
{
|
||||
MainFrame.this.clearLog();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Quit
|
||||
{
|
||||
MenuItem item = new MenuItem(dropDown, SWT.PUSH);
|
||||
item.setText("E&xit");
|
||||
item.setAccelerator(SWT.CTRL + 'X');
|
||||
item.addListener(SWT.Selection,
|
||||
new Listener() {
|
||||
public void handleEvent(Event e)
|
||||
{
|
||||
MainFrame.this.quit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return fileMenu;
|
||||
}
|
||||
|
||||
/** Opens a log window, and adds it to the
|
||||
* vector of log windows we maintain.
|
||||
*
|
||||
* The idea here is that you can open many log windows..
|
||||
*
|
||||
*/
|
||||
void openLog()
|
||||
{
|
||||
LogWindow newLog = new LogWindow(mShell.getDisplay(),
|
||||
mLogLines, mLogCounter);
|
||||
++mLogCounter;
|
||||
mLogWindows.addElement(newLog);
|
||||
}
|
||||
|
||||
private void clearLog()
|
||||
{
|
||||
boolean needTidy = false;
|
||||
|
||||
// Clear the logs.
|
||||
mLogLines = new Vector();
|
||||
for (int i=0;i<mLogWindows.size();++i)
|
||||
{
|
||||
LogWindow cur = (LogWindow)mLogWindows.elementAt(i);
|
||||
|
||||
if (!cur.disposed())
|
||||
{
|
||||
cur.clearLog();
|
||||
}
|
||||
else
|
||||
{
|
||||
needTidy = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (needTidy)
|
||||
{
|
||||
cleanLogVector();
|
||||
}
|
||||
}
|
||||
|
||||
private void aboutBox()
|
||||
{
|
||||
AboutBox theBox = new AboutBox(mShell);
|
||||
|
||||
theBox.show();
|
||||
}
|
||||
|
||||
/** Write to the log. Private so external routines go through
|
||||
* one of the public wombats above.
|
||||
*/
|
||||
private void writeToLog(String logEntry)
|
||||
{
|
||||
boolean needsCleaning = false;
|
||||
boolean any = false;
|
||||
|
||||
mLogLines.addElement(logEntry);
|
||||
// Now tell all our loggers about it, removing those
|
||||
// that don't exist in the process.
|
||||
for (int i=0;i<mLogWindows.size();++i)
|
||||
{
|
||||
LogWindow cur = (LogWindow)mLogWindows.elementAt(i);
|
||||
if (cur.disposed())
|
||||
{
|
||||
needsCleaning = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
any = true;
|
||||
cur.appendToLog(logEntry);
|
||||
}
|
||||
}
|
||||
|
||||
if (needsCleaning)
|
||||
{
|
||||
cleanLogVector();
|
||||
}
|
||||
// if (!any)
|
||||
// {
|
||||
// openLog();
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
void cleanLogVector()
|
||||
{
|
||||
Vector newLogs;
|
||||
|
||||
newLogs = new Vector();
|
||||
for (int i=0;i<mLogWindows.size();++i)
|
||||
{
|
||||
LogWindow cur = (LogWindow)mLogWindows.elementAt(i);
|
||||
if (!cur.disposed())
|
||||
{
|
||||
newLogs.addElement(cur);
|
||||
}
|
||||
}
|
||||
mLogWindows = newLogs;
|
||||
}
|
||||
|
||||
|
||||
void quit()
|
||||
{
|
||||
//System.out.println("Wombats!");
|
||||
mPrefs.flush(this.mShell);
|
||||
mImage.prepareForExit();
|
||||
// this.mShell.close();
|
||||
YUV2.Exit();
|
||||
}
|
||||
|
||||
void fillRecentMenu()
|
||||
{
|
||||
MenuItem [] menuItems = mRecentMenu.getItems ();
|
||||
|
||||
for (int i=0;i < menuItems.length;
|
||||
++i)
|
||||
{
|
||||
menuItems[i].dispose();
|
||||
}
|
||||
|
||||
Vector theVec = mPrefs.getRecentFiles();
|
||||
|
||||
for (int i=0;i < theVec.size(); ++i)
|
||||
{
|
||||
String fileName = (String)theVec.elementAt(i);
|
||||
MenuItem theItem = new MenuItem(mRecentMenu,
|
||||
SWT.PUSH);
|
||||
theItem.setText(fileName);
|
||||
theItem.addListener(SWT.Selection,
|
||||
new Listener()
|
||||
{
|
||||
|
||||
public void handleEvent(Event inEvent)
|
||||
{
|
||||
MainFrame.this.openFile
|
||||
(((MenuItem)inEvent.widget).getText());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
MainFrame(Display d, String inInitialDimensions, String inInitialFile)
|
||||
{
|
||||
mLogWindows = new Vector();
|
||||
mLogLines = new Vector();
|
||||
mLogCounter = 0;
|
||||
|
||||
mShell = new Shell(d);
|
||||
mPrefs = new Prefs(mShell);
|
||||
|
||||
|
||||
mImageHolder = new ScrolledComposite(mShell,
|
||||
SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
|
||||
mImage = new ImageCanvas(mImageHolder, this,
|
||||
mShell,
|
||||
SWT.NONE);
|
||||
// For some odd reason, we have to do a ..
|
||||
mImageHolder.setContent(mImage);
|
||||
|
||||
// Make sure we fire up at a vaguely sensible
|
||||
// size.
|
||||
mImage.setSize(768, 576);
|
||||
mImage.pack();
|
||||
mImageHolder.setSize(mImageHolder.computeSize(SWT.DEFAULT,
|
||||
SWT.DEFAULT));
|
||||
//mImageHolder.setExpandHorizontal(true);
|
||||
//mImageHolder.setExpandVertical(true);
|
||||
|
||||
// Make a fancy title n stuff..
|
||||
mShell.setText("YUV2");
|
||||
|
||||
|
||||
// Add some menus ..
|
||||
mMenuBar = new Menu(mShell, SWT.BAR);
|
||||
mShell.setMenuBar(mMenuBar);
|
||||
mFileMenu = makeFileMenu(mMenuBar);
|
||||
makeViewMenu(mMenuBar);
|
||||
makeRecentMenu(mMenuBar);
|
||||
makeHelpMenu(mMenuBar);
|
||||
|
||||
// Register a close handler to quit the program.
|
||||
mShell.addListener(SWT.Close,
|
||||
new Listener()
|
||||
{
|
||||
public void handleEvent(Event inEvent)
|
||||
{
|
||||
MainFrame.this.quit();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
FormLayout topLevelLayout = new FormLayout();
|
||||
mShell.setLayout(topLevelLayout);
|
||||
|
||||
// Arrange a window with a toolbar at the top, infobar at the
|
||||
// bottom, and a viewing window in the middle.
|
||||
CoolBar coolBar = new CoolBar(mShell, SWT.BORDER);
|
||||
|
||||
|
||||
makeFrameToolbar(coolBar);
|
||||
makeZoomToolbar(coolBar);
|
||||
makeMBToolbar(coolBar);
|
||||
|
||||
coolBar.setLayoutData(Utils.makeFormData
|
||||
(new FormAttachment(0),
|
||||
new FormAttachment(100),
|
||||
new FormAttachment(0), null));
|
||||
coolBar.addListener(SWT.Resize,
|
||||
new Listener()
|
||||
{
|
||||
public void handleEvent(Event ev)
|
||||
{
|
||||
mShell.layout();
|
||||
}
|
||||
});
|
||||
|
||||
// Footer bar.
|
||||
mBottomComposite =
|
||||
new Composite(mShell, SWT.NONE);
|
||||
|
||||
{
|
||||
FormLayout former = new FormLayout();
|
||||
|
||||
mBottomComposite.setLayout(former);
|
||||
}
|
||||
|
||||
mImageHolder.setLayoutData(Utils.makeFormData(
|
||||
new FormAttachment(0),
|
||||
new FormAttachment(100),
|
||||
new FormAttachment(coolBar),
|
||||
new FormAttachment(mBottomComposite)));
|
||||
|
||||
mBottomComposite.setLayoutData(Utils.makeFormData(
|
||||
new FormAttachment(0),
|
||||
new FormAttachment(100),
|
||||
null, // No circularity ..
|
||||
new FormAttachment(100)));
|
||||
|
||||
mStatusLeft = new Label(mBottomComposite, SWT.LEFT);
|
||||
//mStatusMid = new Label(mBottomComposite, SWT.LEFT);
|
||||
|
||||
mStatusRight = new Label(mBottomComposite, SWT.RIGHT);
|
||||
|
||||
mStatusLeft.setLayoutData(Utils.makeFormData(
|
||||
new FormAttachment(0),
|
||||
null,
|
||||
new FormAttachment(0),
|
||||
null));
|
||||
mStatusLeft.setText("idle");
|
||||
|
||||
//mStatusMid.setLayoutData(Utils.makeFormData(
|
||||
// null,
|
||||
// null,
|
||||
// new FormAttachment(0),
|
||||
// null));
|
||||
// mStatusMid.setText("");
|
||||
|
||||
mStatusRight.setLayoutData(Utils.makeFormData(
|
||||
new FormAttachment(mStatusLeft),
|
||||
new FormAttachment(100),
|
||||
new FormAttachment(0),
|
||||
null));
|
||||
|
||||
mStatusLeft.pack(); mStatusRight.pack();
|
||||
mBottomComposite.pack();
|
||||
|
||||
mShell.pack();
|
||||
mImage.pack();
|
||||
mImageHolder.pack();
|
||||
coolBar.pack();
|
||||
mShell.setSize(700, 500);
|
||||
|
||||
initialLoadFile(inInitialFile, inInitialDimensions);
|
||||
}
|
||||
|
||||
boolean isDisposed() { return mShell.isDisposed(); }
|
||||
|
||||
void open()
|
||||
{
|
||||
mShell.open();
|
||||
}
|
||||
|
||||
// Called to update the number of frames in the file when
|
||||
// ImageCanvas knows this information.
|
||||
public void setNumFrames(long numFrames)
|
||||
{
|
||||
mNumFrames.setText(Long.toString(numFrames-1));
|
||||
mNumFrames.pack();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Action routines.
|
||||
public void initialLoadFile(String inFile, String inDimensions)
|
||||
{
|
||||
Prefs.FileDimensionInfo fdi = null;
|
||||
|
||||
if (inDimensions != null)
|
||||
{
|
||||
// Parse out the dimensions and add to the recent files
|
||||
// list.
|
||||
boolean parse_ok;
|
||||
Point result = new Point(0,0);
|
||||
|
||||
parse_ok = Utils.parseDimensions(inDimensions, result);
|
||||
if (parse_ok)
|
||||
{
|
||||
fdi = new Prefs.FileDimensionInfo(inFile, result.y, result.x,
|
||||
Utils.FORMAT_YUV);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (inFile != null)
|
||||
{
|
||||
boolean openedFile = false;
|
||||
|
||||
if (mImage.openFile(inFile))
|
||||
{
|
||||
openedFile = true;
|
||||
mPrefs.registerFileOpen(inFile);
|
||||
}
|
||||
|
||||
if (inDimensions == null)
|
||||
{
|
||||
|
||||
fdi = mPrefs.getDimensions(inFile);
|
||||
}
|
||||
|
||||
if (fdi.mFilename == null)
|
||||
{
|
||||
boolean doSave = displayFormatDialog(fdi);
|
||||
|
||||
|
||||
if (doSave)
|
||||
{
|
||||
mPrefs.setDimensions(fdi);
|
||||
}
|
||||
}
|
||||
|
||||
if (openedFile)
|
||||
{
|
||||
// We opened a file. Save the current dimensions back
|
||||
// with this file.
|
||||
fdi.mFilename = inFile;
|
||||
mPrefs.setDimensions(fdi);
|
||||
}
|
||||
|
||||
|
||||
mImage.changeFormat(fdi.mWidth,
|
||||
fdi.mHeight,
|
||||
fdi.mFormat);
|
||||
}
|
||||
}
|
||||
|
||||
public void openFile(String inFile)
|
||||
{
|
||||
String fileName;
|
||||
|
||||
if (inFile == null)
|
||||
{
|
||||
FileDialog theDialog = new FileDialog(mShell,
|
||||
SWT.OPEN);
|
||||
|
||||
theDialog.setFilterNames(new String[]{"YUV files", "All Files"});
|
||||
theDialog.setFilterExtensions
|
||||
(new String[]{"*.yuv","*.*"});
|
||||
theDialog.setFilterPath("c:\\");
|
||||
theDialog.setFileName("viddec.yuv");
|
||||
fileName = theDialog.open();
|
||||
}
|
||||
else
|
||||
{
|
||||
fileName = inFile;
|
||||
}
|
||||
|
||||
if (fileName == null)
|
||||
{
|
||||
// Someone clicked cancel on a dialog box.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mImage.openFile(fileName))
|
||||
{
|
||||
boolean doSave = false;
|
||||
|
||||
// Stash the file in the recent files list.
|
||||
mPrefs.registerFileOpen(fileName);
|
||||
|
||||
// Do we have dimensions for this file?
|
||||
Prefs.FileDimensionInfo fdInfo =
|
||||
mPrefs.getDimensions(fileName);
|
||||
|
||||
|
||||
if (fdInfo.mFilename == null)
|
||||
{
|
||||
// Need to ask.
|
||||
doSave = displayFormatDialog(fdInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
doSave = true;
|
||||
}
|
||||
|
||||
// Unconditionally save, so future
|
||||
// invocations work propely and we maintain
|
||||
// the order of file opens.
|
||||
if (doSave)
|
||||
{
|
||||
// If we had the defaults before, specialise them for
|
||||
// this file.
|
||||
if (fdInfo.mFilename == null)
|
||||
{
|
||||
fdInfo.mFilename = fileName;
|
||||
}
|
||||
|
||||
// Tell the image to update itself.
|
||||
mImage.changeFormat(fdInfo.mWidth,
|
||||
fdInfo.mHeight,
|
||||
fdInfo.mFormat);
|
||||
|
||||
mPrefs.setDimensions(fdInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean displayFormatDialog(Prefs.FileDimensionInfo inInfo)
|
||||
{
|
||||
boolean dialog_ok;
|
||||
|
||||
FormatDialog theDialog =
|
||||
new FormatDialog(mShell,
|
||||
inInfo.mWidth, inInfo.mHeight,
|
||||
inInfo.mFormat);
|
||||
dialog_ok = theDialog.show();
|
||||
|
||||
if (dialog_ok)
|
||||
{
|
||||
inInfo.mWidth = theDialog.mWidth;
|
||||
inInfo.mHeight = theDialog.mHeight;
|
||||
inInfo.mFormat = theDialog.mFormat;
|
||||
}
|
||||
return dialog_ok;
|
||||
}
|
||||
|
||||
/** Set the format and dimensions of the current file.
|
||||
*/
|
||||
public void setFormat(Prefs.FileDimensionInfo fdInfo)
|
||||
{
|
||||
boolean dialog_ok = displayFormatDialog(fdInfo);
|
||||
if (dialog_ok)
|
||||
{
|
||||
// Tell the image to update itself.
|
||||
mImage.changeFormat(fdInfo.mWidth,
|
||||
fdInfo.mHeight,
|
||||
fdInfo.mFormat);
|
||||
|
||||
mPrefs.setDimensions(fdInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/** We just advanced a frame.
|
||||
*/
|
||||
public void playAdvance()
|
||||
{
|
||||
int frameToSet = mImage.mFrameNumber;
|
||||
|
||||
++frameToSet;
|
||||
mFrameSpinner.setSelection(frameToSet);
|
||||
mImage.changeFrameNumber(frameToSet);
|
||||
// mAdvancePending is marked by ImageCanvas, once it's
|
||||
// actually done painting.
|
||||
}
|
||||
|
||||
/** We stopped playing; pop out the play button
|
||||
*/
|
||||
public void playStopped()
|
||||
{
|
||||
mImage.mPlayMode = false;
|
||||
// The test here is necessary, because we get
|
||||
// a spurious event when ImageCanvas's player starts up.
|
||||
if (mPlayButton != null)
|
||||
{
|
||||
mPlayButton.setSelection(false);
|
||||
}
|
||||
synchronized (mImage)
|
||||
{
|
||||
mImage.mAdvancePending = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* The preferences dialog.
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the MPEG TS, PS and ES tools.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Amino Communications Ltd.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Amino Communications Ltd, Swavesey, Cambridge UK
|
||||
* Kynesim, Cambridge UK
|
||||
*
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
|
||||
package com.aminocom.yuv2;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Vector;
|
||||
import java.util.prefs.Preferences;
|
||||
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
public class Prefs {
|
||||
public static final int NR_RECENT_FILENAMES = 8;
|
||||
|
||||
public static final int DEFAULT_X = 768;
|
||||
public static final int DEFAULT_Y = 576;
|
||||
|
||||
public static final int DEFAULT_FORMAT = Utils.FORMAT_YUV;
|
||||
|
||||
Preferences mPrefs;
|
||||
Preferences mRecentFiles;
|
||||
Preferences mDefaultInfo;
|
||||
Preferences mFileInfo;
|
||||
|
||||
// Used to notify errors.
|
||||
Shell mNotifyShell;
|
||||
|
||||
Prefs(Shell notifyShell)
|
||||
{
|
||||
mPrefs = Preferences.userNodeForPackage(Prefs.class);
|
||||
mPrefs = mPrefs.node("YUV2");
|
||||
mRecentFiles = mPrefs.node("RecentFiles");
|
||||
mDefaultInfo = mPrefs.node("DefaultInfo");
|
||||
mFileInfo = mPrefs.node("FileInfo");
|
||||
mNotifyShell = notifyShell;
|
||||
}
|
||||
|
||||
/** Flush all pending writes to the backing
|
||||
* store in preparation for closing the application.
|
||||
*
|
||||
*/
|
||||
void flush(Shell inShell)
|
||||
{
|
||||
try
|
||||
{
|
||||
mPrefs.flush();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.showMessageBox(inShell,
|
||||
"Cannot write preferences - " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/** Retrieve a list of the recent files, up to
|
||||
* NR_RECENT_FILENAMES
|
||||
*/
|
||||
Vector getRecentFiles()
|
||||
{
|
||||
Vector recentVector = new Vector();
|
||||
|
||||
for (int i = 0 ; i < NR_RECENT_FILENAMES; ++i)
|
||||
{
|
||||
String currentValue = mRecentFiles.get(Integer.toString(i), null);
|
||||
|
||||
if (currentValue != null)
|
||||
{
|
||||
recentVector.addElement(currentValue);
|
||||
}
|
||||
}
|
||||
return recentVector;
|
||||
}
|
||||
|
||||
/** Modify the preferences file to register that
|
||||
* we just opened this file.
|
||||
*/
|
||||
void registerFileOpen(String inFilename)
|
||||
{
|
||||
/* We just rewrite the whole array - it's less
|
||||
* error prone, and config file writes are cheap.
|
||||
*/
|
||||
Vector recentVector = new Vector();
|
||||
recentVector.addElement(inFilename);
|
||||
|
||||
File mostRecentFile = new File(inFilename);
|
||||
|
||||
for (int i=0;i< NR_RECENT_FILENAMES-1;++i)
|
||||
{
|
||||
String currentValue = mRecentFiles.get(Integer.toString(i), null);
|
||||
|
||||
if (currentValue != null)
|
||||
{
|
||||
File currentFile = new File(currentValue);
|
||||
|
||||
// Push duplications to the top.
|
||||
if (!currentFile.equals(mostRecentFile))
|
||||
{
|
||||
recentVector.addElement(currentValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now write back .. */
|
||||
for (int i=0;i < recentVector.size(); ++i)
|
||||
{
|
||||
mRecentFiles.put(Integer.toString(i), (String)recentVector.elementAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** A subclass which stores file association info
|
||||
*/
|
||||
public static class FileDimensionInfo
|
||||
{
|
||||
String mFilename;
|
||||
int mHeight;
|
||||
int mWidth;
|
||||
int mFormat;
|
||||
|
||||
FileDimensionInfo()
|
||||
{
|
||||
mFilename = null; mWidth = DEFAULT_X; mHeight = DEFAULT_Y;
|
||||
mFormat = DEFAULT_FORMAT;
|
||||
}
|
||||
|
||||
FileDimensionInfo(Preferences inPrefs)
|
||||
{
|
||||
read(inPrefs);
|
||||
}
|
||||
|
||||
FileDimensionInfo(String inFilename, int inHeight, int inWidth,
|
||||
int inFormat)
|
||||
{
|
||||
mFilename = inFilename; mHeight = inHeight;
|
||||
mWidth = inWidth; mFormat = inFormat;
|
||||
}
|
||||
|
||||
void read(Preferences inPrefs)
|
||||
{
|
||||
mFilename = inPrefs.get("filename", null);
|
||||
mWidth = inPrefs.getInt("x", DEFAULT_X);
|
||||
mHeight = inPrefs.getInt("y", DEFAULT_Y);
|
||||
mFormat = inPrefs.getInt("format", DEFAULT_FORMAT);
|
||||
}
|
||||
|
||||
void write(Preferences inPrefs)
|
||||
{
|
||||
if (mFilename != null)
|
||||
{
|
||||
inPrefs.put("filename", mFilename);
|
||||
}
|
||||
inPrefs.putInt("x", mWidth);
|
||||
inPrefs.putInt("y", mHeight);
|
||||
inPrefs.putInt("format", mFormat);
|
||||
}
|
||||
};
|
||||
|
||||
/** Retrieve default dimensions for this file, or
|
||||
* the global default if it doesn't appear in the list.
|
||||
*/
|
||||
FileDimensionInfo getDimensions(String inFilename)
|
||||
{
|
||||
if (inFilename != null)
|
||||
{
|
||||
File inFile = new File(inFilename);
|
||||
|
||||
|
||||
|
||||
for (int i=0;i < NR_RECENT_FILENAMES; ++i)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
if (mFileInfo.nodeExists(Integer.toString(i)))
|
||||
{
|
||||
FileDimensionInfo cur =
|
||||
new FileDimensionInfo
|
||||
(mFileInfo.node(Integer.toString(i)));
|
||||
File fileB = new File(cur.mFilename);
|
||||
|
||||
|
||||
if (inFile.equals(fileB))
|
||||
{
|
||||
// Gotcha.
|
||||
return cur;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Bugger.
|
||||
return new FileDimensionInfo(mDefaultInfo);
|
||||
}
|
||||
|
||||
|
||||
/** We just set dimensions - store them for future use as
|
||||
* the default, and associate them with this file in the
|
||||
* recent dimensions list.
|
||||
*
|
||||
* This way of doing things is a little clumsy, but it
|
||||
* at least maintains some sort of robustness in the face
|
||||
* of concurrent invocations.
|
||||
*/
|
||||
void setDimensions(FileDimensionInfo curDim)
|
||||
{
|
||||
curDim.write(mDefaultInfo);
|
||||
|
||||
if (curDim.mFilename == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector newFileInfo = new Vector();
|
||||
File newTopFile = new File(curDim.mFilename);
|
||||
|
||||
newFileInfo.addElement(curDim);
|
||||
|
||||
/* Now load up the recent files list */
|
||||
for (int i=0;i<NR_RECENT_FILENAMES-1;++i)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (mFileInfo.nodeExists(Integer.toString(i)))
|
||||
{
|
||||
FileDimensionInfo newDim = new FileDimensionInfo
|
||||
(mFileInfo.node(Integer.toString(i)));
|
||||
File curFile = new File(newDim.mFilename);
|
||||
|
||||
if (!curFile.equals(newTopFile))
|
||||
{
|
||||
newFileInfo.addElement(newDim);
|
||||
}
|
||||
}
|
||||
} catch (Exception e)
|
||||
{
|
||||
// Ignore...
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0;i<newFileInfo.size();++i)
|
||||
{
|
||||
((FileDimensionInfo)newFileInfo.elementAt(i)).write
|
||||
(mFileInfo.node(Integer.toString(i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// End file.
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* General utilities.
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the MPEG TS, PS and ES tools.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Amino Communications Ltd.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Amino Communications Ltd, Swavesey, Cambridge UK
|
||||
* Kynesim, Cambridge UK
|
||||
*
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
|
||||
package com.aminocom.yuv2;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.layout.FormAttachment;
|
||||
import org.eclipse.swt.layout.FormData;
|
||||
import org.eclipse.swt.widgets.MessageBox;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
|
||||
|
||||
public class Utils {
|
||||
public static final int FORMAT_YUV = 0;
|
||||
|
||||
public static String formatToString(int inFormat)
|
||||
{
|
||||
// We only know about one format so far.
|
||||
return "YUV 4:2:0";
|
||||
}
|
||||
|
||||
/** Try to parse a string as a set of dimensions.
|
||||
*
|
||||
* @return true on success, false on failure.
|
||||
*/
|
||||
public static boolean parseDimensions(String inString, Point rv)
|
||||
{
|
||||
// We're OK. Parse out the combo box.
|
||||
|
||||
boolean dimensionsOK = false;
|
||||
|
||||
// Bit before the 'x'.
|
||||
int pos = inString.indexOf('x');
|
||||
if (pos >= 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
rv.x = Integer.parseInt(inString.substring(0, pos));
|
||||
rv.y = Integer.parseInt(inString.substring(pos+1));
|
||||
dimensionsOK = true;
|
||||
}
|
||||
catch (NumberFormatException nfe)
|
||||
{
|
||||
// Do nothing - we're about to issue an error
|
||||
// anyway.
|
||||
};
|
||||
}
|
||||
|
||||
return dimensionsOK;
|
||||
}
|
||||
/** Make form data from attachments
|
||||
*
|
||||
*/
|
||||
public static FormData makeFormData(FormAttachment inLeft,
|
||||
FormAttachment inRight,
|
||||
FormAttachment inTop,
|
||||
FormAttachment inBottom)
|
||||
{
|
||||
FormData rv = new FormData();
|
||||
rv.left = inLeft; rv.right = inRight;
|
||||
rv.top = inTop; rv.bottom= inBottom;
|
||||
return rv;
|
||||
}
|
||||
public static void showMessageBox(Shell inShell, String s)
|
||||
{
|
||||
MessageBox mb = new MessageBox(inShell, SWT.OK);
|
||||
mb.setMessage(s);
|
||||
mb.open();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* YUV2 main program.
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the MPEG TS, PS and ES tools.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Amino Communications Ltd.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Amino Communications Ltd, Swavesey, Cambridge UK
|
||||
* Kynesim, Cambridge UK
|
||||
*
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
package com.aminocom.yuv2;
|
||||
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
|
||||
public class YUV2 {
|
||||
public static class WorkRequest
|
||||
{
|
||||
public static final int UPDATE_IMAGE = 0;
|
||||
public static final int STOP_PLAY = 1;
|
||||
public static final int ADVANCE_PLAY = 2;
|
||||
public static final int BUFFER_NEXT_IMAGE = 3;
|
||||
public static final int NOP = 2;
|
||||
|
||||
int mCode;
|
||||
ImageCanvas mImageCanvas;
|
||||
MainFrame mMainFrame;
|
||||
WorkRequest next;
|
||||
|
||||
WorkRequest()
|
||||
{
|
||||
mCode = NOP; mImageCanvas = null;
|
||||
mMainFrame = null;
|
||||
next = null;
|
||||
}
|
||||
|
||||
WorkRequest(ImageCanvas inObject, int inCode)
|
||||
{
|
||||
mCode = inCode;
|
||||
mImageCanvas = inObject;
|
||||
mMainFrame = null;
|
||||
next = null;
|
||||
}
|
||||
|
||||
WorkRequest(MainFrame inFrame, int inCode)
|
||||
{
|
||||
mCode = inCode;
|
||||
mImageCanvas = null;
|
||||
mMainFrame = inFrame;
|
||||
next = null;
|
||||
}
|
||||
};
|
||||
|
||||
/** A queue of things that need to be done by the UI
|
||||
* thread.
|
||||
*/
|
||||
static WorkRequest sDummyHead;
|
||||
|
||||
|
||||
/** This routine is safe for multithreading
|
||||
* We deliberately starve latecomers, first
|
||||
* because it's easy, second because we'd
|
||||
* rather give good service to one thread
|
||||
* and kill everyone else than do a bad
|
||||
* job everywhere.
|
||||
*/
|
||||
public static void addWork(WorkRequest newRequest)
|
||||
{
|
||||
Display responsibleDisplay =
|
||||
(newRequest.mImageCanvas != null ?
|
||||
newRequest.mImageCanvas.getDisplay() :
|
||||
newRequest.mMainFrame.mShell.getDisplay());
|
||||
|
||||
synchronized (sDummyHead)
|
||||
{
|
||||
newRequest.next = sDummyHead.next;
|
||||
sDummyHead.next = newRequest;
|
||||
}
|
||||
// Poke the display - new data just came in.
|
||||
responsibleDisplay.wake();
|
||||
}
|
||||
|
||||
|
||||
/** Pop a work request off the queue.
|
||||
*
|
||||
* */
|
||||
public static WorkRequest getWork()
|
||||
{
|
||||
WorkRequest popped = null;
|
||||
|
||||
synchronized (sDummyHead)
|
||||
{
|
||||
if (sDummyHead.next != null)
|
||||
{
|
||||
popped = sDummyHead.next;
|
||||
sDummyHead.next = popped.next;
|
||||
popped.next = null; // Just in case.
|
||||
}
|
||||
}
|
||||
return popped;
|
||||
}
|
||||
|
||||
/** Do a work request
|
||||
*/
|
||||
public static void DispatchWork(WorkRequest req)
|
||||
{
|
||||
switch (req.mCode)
|
||||
{
|
||||
case WorkRequest.UPDATE_IMAGE:
|
||||
req.mImageCanvas.updateImage();
|
||||
break;
|
||||
case WorkRequest.ADVANCE_PLAY:
|
||||
req.mMainFrame.playAdvance();
|
||||
break;
|
||||
case WorkRequest.STOP_PLAY:
|
||||
req.mMainFrame.playStopped();
|
||||
break;
|
||||
case WorkRequest.BUFFER_NEXT_IMAGE:
|
||||
req.mImageCanvas.makeNextImage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] s)
|
||||
{
|
||||
String dimensions = null, filename = null;
|
||||
|
||||
// Create the dummy work queue head (merely used
|
||||
// for synchronization).
|
||||
sDummyHead = new WorkRequest();
|
||||
|
||||
Display display = new Display();
|
||||
for (int i=0;i<s.length;++i)
|
||||
{
|
||||
if (s[i].charAt(0) == '/')
|
||||
{
|
||||
dimensions = s[i].substring(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = s[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MainFrame mainFrame = new MainFrame(display, dimensions, filename);
|
||||
|
||||
mainFrame.open();
|
||||
while (!mainFrame.isDisposed())
|
||||
{
|
||||
|
||||
if (!display.readAndDispatch())
|
||||
{
|
||||
// Do we have any video events?
|
||||
WorkRequest req = getWork();
|
||||
if (req != null)
|
||||
{
|
||||
DispatchWork(req);
|
||||
}
|
||||
|
||||
// There's no need to worry about
|
||||
// this sleeping too long - ImageCanvas's
|
||||
// play thread will poke us (via wake())
|
||||
// when it needs us.
|
||||
display.sleep();
|
||||
}
|
||||
}
|
||||
display.dispose();
|
||||
|
||||
|
||||
// Terminate the process - including the animation thread.
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
public static void Exit()
|
||||
{
|
||||
//System.out.println("Exit handler called");
|
||||
// Just kill ..
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
|
||||
}
|
Ładowanie…
Reference in New Issue