framerate is float

This commit is contained in:
honfika@gmail.com
2015-08-12 14:22:04 +02:00
parent 427e7ea70d
commit 809091ea42
16 changed files with 99 additions and 69 deletions

View File

@@ -206,7 +206,7 @@ public final class SWF implements SWFContainerItem, Timelined {
/**
* Movie frame rate
*/
public int frameRate;
public float frameRate;
/**
* Number of frames in movie
@@ -767,8 +767,7 @@ public final class SWF implements SWFContainerItem, Timelined {
sos.writeUI8(version);
sos.writeUI32(0); // placeholder for file length
sos.writeRECT(displayRect);
sos.writeUI8(0);
sos.writeUI8(frameRate);
sos.writeFIXED8(frameRate);
sos.writeUI16(frameCount);
sos.writeTags(tags);
@@ -1037,9 +1036,7 @@ public final class SWF implements SWFContainerItem, Timelined {
}
sis.setPercentMax(fileSize);
displayRect = sis.readRECT("displayRect");
// FIXED8 (16 bit fixed point) frameRate
sis.readUI8("tmpFirstByetOfFrameRate"); // tmpFirstByetOfFrameRate
frameRate = sis.readUI8("frameRate");
frameRate = sis.readFIXED8("frameRate");
frameCount = sis.readUI16("frameCount");
List<Tag> tags = sis.readTagList(this, 0, parallelRead, true, !checkOnly, lazy);
if (tags.size() > 0 && tags.get(tags.size() - 1).getId() == EndTag.ID) {

View File

@@ -617,11 +617,22 @@ public class SWFInputStream implements AutoCloseable {
*/
public int readSI8(String name) throws IOException {
newDumpLevel(name, "SI8");
int ret = readSI8Internal();
endDumpLevel(ret);
return ret;
}
/**
* Reads one SI8 (Signed 8bit integer) value from the stream
*
* @return SI8 value
* @throws IOException
*/
public int readSI8Internal() throws IOException {
int uval = readEx();
if (uval >= 0x80) {
uval = -(((~uval) & 0xff) + 1);
}
endDumpLevel(uval);
return uval;
}
@@ -636,13 +647,13 @@ public class SWFInputStream implements AutoCloseable {
newDumpLevel(name, "FIXED");
int afterPoint = readUI16Internal();
int beforePoint = readUI16Internal();
double ret = ((double) ((beforePoint << 16) + afterPoint)) / 65536;
double ret = beforePoint + ((double) (afterPoint)) / 65536;
endDumpLevel(ret);
return ret;
}
/**
* Reads one FIXED8 (Fixed point 8.8) value from the stream
* Reads one FIXED8 (Fixed point 8.8) signed value from the stream
*
* @param name
* @return FIXED8 value
@@ -651,8 +662,13 @@ public class SWFInputStream implements AutoCloseable {
public float readFIXED8(String name) throws IOException {
newDumpLevel(name, "FIXED8");
int afterPoint = readEx();
int beforePoint = readEx();
float ret = beforePoint + (((float) afterPoint) / 256);
int beforePoint = readSI8Internal();
float ret;
if (beforePoint < 0) {
ret = beforePoint - ((float) afterPoint) / 256;
} else {
ret = beforePoint + ((float) afterPoint) / 256;
}
endDumpLevel(ret);
return ret;
}

View File

@@ -295,7 +295,6 @@ public class SWFOutputStream extends OutputStream {
public void writeFIXED(double value) throws IOException {
long valueLong = (long) (value * (1 << 16));
int beforePoint = (int) valueLong >> 16;
int afterPoint = (int) valueLong % (1 << 16);
writeUI16(afterPoint);
writeUI16(beforePoint);
@@ -308,10 +307,11 @@ public class SWFOutputStream extends OutputStream {
* @throws IOException
*/
public void writeFIXED8(float value) throws IOException {
int beforePoint = (int) getIntPart(value);
int afterPoint = (int) getIntPart((value + (value < 0 ? beforePoint : -beforePoint)) * 256);
final int divisor = 1 << 8;
int beforePoint = (int) value;
int afterPoint = Math.abs((int) (value * divisor)) % divisor;
writeUI8(afterPoint);
writeUI8(beforePoint);
writeSI8(beforePoint);
}
private void writeLong(long value) throws IOException {
@@ -578,13 +578,6 @@ public class SWFOutputStream extends OutputStream {
return nBits;
}
private static long getIntPart(double value) {
if (value < 0) {
return (long) Math.ceil(value);
}
return (long) Math.floor(value);
}
public static int unsignedSize(final int value) {
final int val = (value < 0) ? -value - 1 : value;

View File

@@ -438,14 +438,14 @@ public class FrameExporter {
return "[" + rgb.red + "," + rgb.green + "," + rgb.blue + "," + ((rgb instanceof RGBA) ? ((RGBA) rgb).getAlphaFloat() : 1) + "]";
}
public static void makeAVI(Iterator<BufferedImage> images, int frameRate, File file, EventListener evl) throws IOException {
public static void makeAVI(Iterator<BufferedImage> images, float frameRate, File file, EventListener evl) throws IOException {
if (!images.hasNext()) {
return;
}
AVIWriter out = new AVIWriter(file);
BufferedImage img0 = images.next();
out.addVideoTrack(VideoFormatKeys.ENCODING_AVI_PNG, 1, frameRate, img0.getWidth(), img0.getHeight(), 0, 0);
out.addVideoTrack(VideoFormatKeys.ENCODING_AVI_PNG, 1, (int) frameRate, img0.getWidth(), img0.getHeight(), 0, 0);
try {
out.write(0, img0, 1);
while (images.hasNext()) {
@@ -456,7 +456,7 @@ public class FrameExporter {
}
}
public static void makeGIF(Iterator<BufferedImage> images, int frameRate, File file, EventListener evl) throws IOException {
public static void makeGIF(Iterator<BufferedImage> images, float frameRate, File file, EventListener evl) throws IOException {
if (!images.hasNext()) {
return;
}
@@ -464,7 +464,7 @@ public class FrameExporter {
AnimatedGifEncoder encoder = new AnimatedGifEncoder();
encoder.setRepeat(0); // repeat forever
encoder.start(file.getAbsolutePath());
encoder.setDelay(1000 / frameRate);
encoder.setDelay((int) (1000.0 / frameRate));
while (images.hasNext()) {
encoder.addFrame(images.next());
}
@@ -472,14 +472,14 @@ public class FrameExporter {
encoder.finish();
}
public static void makeGIFOld(Iterator<BufferedImage> images, int frameRate, File file, EventListener evl) throws IOException {
public static void makeGIFOld(Iterator<BufferedImage> images, float frameRate, File file, EventListener evl) throws IOException {
if (!images.hasNext()) {
return;
}
try (ImageOutputStream output = new FileImageOutputStream(file)) {
BufferedImage img0 = images.next();
GifSequenceWriter writer = new GifSequenceWriter(output, img0.getType(), 1000 / frameRate, true);
GifSequenceWriter writer = new GifSequenceWriter(output, img0.getType(), (int) (1000.0 / frameRate), true);
writer.writeToSequence(img0);
while (images.hasNext()) {

View File

@@ -180,7 +180,7 @@ public class MovieExporter {
}
baos.write(tag.videoData.getRangeData());
flv.writeTag(new FLVTAG((int) Math.floor(i * 1000.0f / ((float) swf.frameRate)), new VIDEODATA(frameType, videoStream.codecID, baos.toByteArray())));
flv.writeTag(new FLVTAG((int) Math.floor(i * 1000.0 / swf.frameRate), new VIDEODATA(frameType, videoStream.codecID, baos.toByteArray())));
}
return fos.toByteArray();
}

View File

@@ -147,7 +147,7 @@ public class SoundExporter {
flv.writeHeader(true, false);
List<SoundStreamBlockTag> blocks = sh.getBlocks();
int ms = (int) (1000.0f / ((float) ((Tag) st).getSwf().frameRate));
int ms = (int) (1000.0 / ((Tag) st).getSwf().frameRate);
for (int b = 0; b < blocks.size(); b++) {
byte[] data = blocks.get(b).streamSoundData.getRangeData();
if (st.getSoundFormatId() == 2) { //MP3

View File

@@ -66,7 +66,7 @@ public class Timeline {
public RECT displayRect;
public int frameRate;
public float frameRate;
public Timelined timelined;

View File

@@ -1577,10 +1577,10 @@ public class XFLConverter {
mediaLinkStr = "<DOMVideoItem name=\"" + symbolFile + "\" sourceLastImported=\"" + getTimestamp(swf) + "\" externalFileSize=\"" + data.length + "\"";
mediaLinkStr += " href=\"" + symbolFile + "\"";
mediaLinkStr += " videoType=\"" + videoType + "\"";
mediaLinkStr += " fps=\"" + swf.frameRate + "\"";
mediaLinkStr += " fps=\"" + (int) swf.frameRate + "\""; // todo: is the cast to in needed?
mediaLinkStr += " width=\"" + video.width + "\"";
mediaLinkStr += " height=\"" + video.height + "\"";
double len = ((double) video.numFrames) / ((double) swf.frameRate);
double len = (double) video.numFrames / swf.frameRate;
mediaLinkStr += " length=\"" + len + "\"";
boolean linkageExportForAS = false;
if (characterClasses.containsKey(symbol.getCharacterId())) {
@@ -2694,7 +2694,7 @@ public class XFLConverter {
}
domDocument.append("<DOMDocument xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://ns.adobe.com/xfl/2008/\" currentTimeline=\"1\" xflVersion=\"").append(flaVersion.xflVersion()).append("\" creatorInfo=\"").append(generator).append("\" platform=\"Windows\" versionInfo=\"Saved by ").append(generatorVerName).append("\" majorVersion=\"").append(generatorVersion).append("\" buildNumber=\"\" nextSceneIdentifier=\"2\" playOptionsPlayLoop=\"false\" playOptionsPlayPages=\"false\" playOptionsPlayFrameActions=\"false\" autoSaveHasPrompted=\"true\"");
domDocument.append(" backgroundColor=\"").append(backgroundColor).append("\"");
domDocument.append(" frameRate=\"").append(swf.frameRate).append("\"");
domDocument.append(" frameRate=\"").append((int) swf.frameRate).append("\"");
double width = twipToPixel(swf.displayRect.getWidth());
double height = twipToPixel(swf.displayRect.getHeight());

View File

@@ -1,18 +1,19 @@
/*
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash;
//import com.jpexs.decompiler.flash.gui.Main;
@@ -136,23 +137,47 @@ public class SWFStreamTest {
assertTrue(Double.compare(7.5, sis.readFIXED("test")) == 0);
sis.close();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
SWFOutputStream sos = new SWFOutputStream(baos, SWF.DEFAULT_VERSION);
double dd = 5.25;
sos.writeFIXED(dd);
sos.close();
sis = new SWFInputStream(null, baos.toByteArray());
assertTrue(Double.compare(dd, sis.readFIXED("test")) == 0);
double[] dds = new double[]{5.25, 65535.25};
for (double dd : dds) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
SWFOutputStream sos = new SWFOutputStream(baos, SWF.DEFAULT_VERSION);
sos.writeFIXED(dd);
sos.close();
sis = new SWFInputStream(null, baos.toByteArray());
double dd2 = sis.readFIXED("test");
assertTrue(Double.compare(dd, dd2) == 0, "Written and read value not equals. Written: " + dd + " read: " + dd2);
sis.close();
}
baos = new ByteArrayOutputStream();
sos = new SWFOutputStream(baos, SWF.DEFAULT_VERSION);
float ff = 5.25f;
sos.writeFIXED8(ff);
sos.close();
sis = new SWFInputStream(null, baos.toByteArray());
assertEquals(ff, sis.readFIXED8("test"));
float[] ffs = new float[]{5.25f, -5.25f, 127.75f, -128f};
for (float ff : ffs) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
SWFOutputStream sos = new SWFOutputStream(baos, SWF.DEFAULT_VERSION);
sos.writeFIXED8(ff);
sos.close();
sis = new SWFInputStream(null, baos.toByteArray());
float ff2 = sis.readFIXED8("test");
assertEquals(ff, ff2, "Written and read value not equals. Written: " + ff + " read: " + ff2);
sis.close();
}
}
//@Test
public void testAllFIXED8() throws IOException {
for (int i = 0; i < 65536; i++) {
byte[] data = new byte[]{(byte) (i % 256), (byte) (i / 256)};
SWFInputStream sis = new SWFInputStream(null, data);
float d = sis.readFIXED8("test");
sis.close();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
SWFOutputStream sos = new SWFOutputStream(baos, SWF.DEFAULT_VERSION);
sos.writeFIXED8(d);
sos.close();
byte[] data2 = baos.toByteArray();
assertTrue(data[0] == data2[0] && data[1] == data2[1]);
}
}
@Test

View File

@@ -225,7 +225,7 @@ public class HeaderInfoPanel extends JPanel implements TagEditorPanel {
swf.compression = getCompression();
swf.version = getVersionNumber();
swf.gfx = gfxCheckBox.isSelected();
swf.frameRate = (int) frameRateEditor.getModel().getValue();
swf.frameRate = ((Number) (frameRateEditor.getModel().getValue())).floatValue();
swf.displayRect.Xmin = (int) xMinEditor.getModel().getValue();
swf.displayRect.Xmax = (int) xMaxEditor.getModel().getValue();
swf.displayRect.Ymin = (int) yMinEditor.getModel().getValue();
@@ -266,7 +266,7 @@ public class HeaderInfoPanel extends JPanel implements TagEditorPanel {
fileSizeLabel.setText(Long.toString(swf.fileSize));
frameRateLabel.setText(Integer.toString(swf.frameRate));
frameRateLabel.setText(Float.toString(swf.frameRate));
frameRateEditor.setModel(new SpinnerNumberModel(swf.frameRate, -0x80000000, 0x7fffffff, 1));
frameCountLabel.setText("" + swf.frameCount);

View File

@@ -958,8 +958,8 @@ public final class ImagePanel extends JPanel implements MediaDisplay {
private void startTimer(Timeline timeline, boolean playing) {
int frameRate = timeline.frameRate;
int msPerFrame = frameRate == 0 ? 1000 : 1000 / frameRate;
float frameRate = timeline.frameRate;
int msPerFrame = frameRate == 0 ? 1000 : (int) (1000.0 / frameRate);
final boolean singleFrame = !playing || (timeline.getRealFrameCount() <= 1 && timeline.isSingleFrame());
timer = new Timer();
@@ -1043,7 +1043,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay {
}
@Override
public synchronized int getFrameRate() {
public synchronized float getFrameRate() {
if (timelined == null) {
return 1;
}

View File

@@ -3293,7 +3293,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
private void initTimeline(Timeline timeline) {
if (tag instanceof MorphShapeTag) {
tim.frameRate = MORPH_SHAPE_ANIMATION_FRAME_RATE;
int framesCnt = tim.frameRate * MORPH_SHAPE_ANIMATION_LENGTH;
int framesCnt = (int) (tim.frameRate * MORPH_SHAPE_ANIMATION_LENGTH);
for (int i = 0; i < framesCnt; i++) {
Frame f = new Frame(tim, i);
DepthState ds = new DepthState(tag.getSwf(), f);

View File

@@ -618,7 +618,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
}
int frameCount = 1;
int frameRate = swf.frameRate;
float frameRate = swf.frameRate;
HashMap<Integer, VideoFrameTag> videoFrames = new HashMap<>();
if (tagObj instanceof DefineVideoStreamTag) {
DefineVideoStreamTag vs = (DefineVideoStreamTag) tagObj;
@@ -634,7 +634,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
if ((tagObj instanceof DefineMorphShapeTag) || (tagObj instanceof DefineMorphShape2Tag)) {
frameRate = MainPanel.MORPH_SHAPE_ANIMATION_FRAME_RATE;
frameCount = MainPanel.MORPH_SHAPE_ANIMATION_LENGTH * frameRate;
frameCount = (int) (MainPanel.MORPH_SHAPE_ANIMATION_LENGTH * frameRate);
}
if (tagObj instanceof DefineSoundTag) {
@@ -660,8 +660,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
int height = outrect.getHeight();
sos2.writeRECT(outrect);
sos2.writeUI8(0);
sos2.writeUI8(frameRate);
sos2.writeFIXED8(frameRate);
sos2.writeUI16(frameCount); //framecnt
/*FileAttributesTag fa = new FileAttributesTag();

View File

@@ -299,7 +299,7 @@ public class SoundTagPlayer implements MediaDisplay {
}
@Override
public int getFrameRate() {
public float getFrameRate() {
return (int) (1000000L / FRAME_DIVISOR);
}

View File

@@ -48,7 +48,7 @@ public interface MediaDisplay extends Closeable {
public void setBackground(Color color);
public int getFrameRate();
public float getFrameRate();
public boolean isLoaded();

View File

@@ -348,7 +348,7 @@ public class PlayerControls extends JPanel implements MediaDisplayListener {
if (currentFrame >= totalFrames) {
currentFrame = totalFrames - 1;
}
int frameRate = display.getFrameRate();
float frameRate = display.getFrameRate();
if (totalFrames == 0) {
progress.setIndeterminate(true);
} else {
@@ -360,8 +360,8 @@ public class PlayerControls extends JPanel implements MediaDisplayListener {
frameLabel.setText(("" + (currentFrame + 1)));
totalFrameLabel.setText("" + totalFrames);
if (frameRate != 0) {
timeLabel.setText("(" + formatMs((currentFrame * 1000) / frameRate) + ")");
totalTimeLabel.setText("(" + formatMs((totalFrames * 1000) / frameRate) + ")");
timeLabel.setText("(" + formatMs((int) (currentFrame * 1000.0 / frameRate)) + ")");
totalTimeLabel.setText("(" + formatMs((int) (totalFrames * 1000.0 / frameRate)) + ")");
}
if (totalFrames <= 1 && playbackControls.isVisible()) {
playbackControls.setVisible(false);