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%4065
issue20
rrw 2008-09-18 20:17:54 +00:00
rodzic 5e19e0782a
commit fa9a6b71ee
14 zmienionych plików z 3449 dodań i 1 usunięć

2
ac3.c
Wyświetl plik

@ -22,7 +22,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Kynesim Ltd, Cambridge UK
* Kynesim, Cambridge UK
*
* ***** END LICENSE BLOCK *****
*/

30
yuv2/Makefile 100644
Wyświetl plik

@ -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.

37
yuv2/README 100644
Wyświetl plik

@ -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

5
yuv2/bin/yuv2 100755
Wyświetl plik

@ -0,0 +1,5 @@
#! /bin/sh
YUV2DIR=/usr/local/lib
exec java -jar $YUV2DIR/yuv2.jar $*

Wyświetl plik

@ -0,0 +1 @@
Main-Class: com.aminocom.yuv2.YUV2

Wyświetl plik

@ -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();
}
}

Wyświetl plik

@ -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;
}
}

Wyświetl plik

@ -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 */

Wyświetl plik

@ -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 */

Wyświetl plik

@ -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();
}
}

Wyświetl plik

@ -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;
}
}
}

Wyświetl plik

@ -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.

Wyświetl plik

@ -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();
}
}

Wyświetl plik

@ -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);
}
}