diff --git a/lib/jlayer-1.0.2.jar b/lib/jlayer-1.0.2.jar index 743579271..21d4188fc 100644 Binary files a/lib/jlayer-1.0.2.jar and b/lib/jlayer-1.0.2.jar differ diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/SoundStreamHeadTypeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/SoundStreamHeadTypeTag.java index a0cd3f0a5..c9cb90782 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/SoundStreamHeadTypeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/SoundStreamHeadTypeTag.java @@ -163,12 +163,13 @@ public abstract class SoundStreamHeadTypeTag extends Tag implements CharacterIdT newSoundSize = true; newSoundType = fr.isStereo(); - int len = snd.sampleCount(); + /*int len = snd.sampleCount(); if (fr.isStereo()) { len = len / 2; - } + }*/ - newSoundSampleCount = len; + newSoundSampleCount = (int) Math.ceil(soundRateHz / swf.frameRate); + //newSoundSampleCount = len; } mp3Frames = snd.frames; @@ -237,7 +238,7 @@ public abstract class SoundStreamHeadTypeTag extends Tag implements CharacterIdT } if (mp3Frames != null) { - /*int frame = 0; + int frame = 0; int mp3FrameNum = 0; long lastNumSamplesLong = 0; @@ -252,21 +253,28 @@ public abstract class SoundStreamHeadTypeTag extends Tag implements CharacterIdT List blockMp3Frames = new ArrayList<>(); int blockSamples = 0; - while(lastNumSamplesLong < numSamplesAfterFrame) { + while(lastNumSamplesLong < numSamplesAfterFrame && mp3FrameNum < mp3Frames.size()) { MP3FRAME mp3Frame = mp3Frames.get(mp3FrameNum); lastNumSamplesLong += mp3Frame.getSampleCount(); blockSamples += mp3Frame.getSampleCount(); blockMp3Frames.add(mp3Frame); + mp3FrameNum++; } ByteArrayOutputStream baos = new ByteArrayOutputStream(); SWFOutputStream sos = new SWFOutputStream(baos, SWF.DEFAULT_VERSION, null); try { sos.writeUI16(blockSamples); sos.writeSI16(seekSamples); + for (MP3FRAME mp3Frame:blockMp3Frames) { + sos.write(mp3Frame.getBytes()); + } } catch (IOException ex) { Logger.getLogger(SoundStreamHeadTypeTag.class.getName()).log(Level.SEVERE, null, ex); } - } */ + block.streamSoundData = new ByteArrayRange(baos.toByteArray()); + blocks.add(block); + frame++; + } } ReadOnlyTagList tags = timelined.getTags(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/sound/MP3FRAME.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/sound/MP3FRAME.java index b0bfadbf9..1af6eb4cd 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/sound/MP3FRAME.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/sound/MP3FRAME.java @@ -35,11 +35,22 @@ public class MP3FRAME { private Header h; private SampleBuffer samples; + + private byte[] fullData; private MP3FRAME() { } + public void setFullData(byte[] fullData) { + this.fullData = fullData; + } + + public byte[] getBytes() { + return fullData; + } + + public static MP3FRAME readFrame(Bitstream bitstream, Decoder decoder) throws IOException { MP3FRAME ret = new MP3FRAME(); try { @@ -60,24 +71,24 @@ public class MP3FRAME { } public int getSampleCount() { - if (h.version() == 3) { + if (h.version() == Header.MPEG1) { switch(h.layer()) { case 1: - return 1152; + return 384; case 2: return 1152; case 3: - return 384; + return 1152; } } - if (h.version() == 2 || h.version() == 0) { + if (h.version() == Header.MPEG2_LSF || h.version() == Header.MPEG25_LSF) { switch(h.layer()) { case 1: - return 576; + return 384; case 2: return 1152; case 3: - return 384; + return 576; } } return 0; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/sound/MP3SOUNDDATA.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/sound/MP3SOUNDDATA.java index d5e6e9678..bf1cf46ee 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/sound/MP3SOUNDDATA.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/sound/MP3SOUNDDATA.java @@ -20,9 +20,12 @@ import com.jpexs.decompiler.flash.SWFInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import javazoom.jl.decoder.Bitstream; import javazoom.jl.decoder.Decoder; +import javazoom.jl.decoder.MarkingBufferedInputStream; +import javazoom.jl.decoder.MarkingPushbackInputStream; /** * @@ -41,10 +44,23 @@ public class MP3SOUNDDATA { frames = new ArrayList<>(); MP3FRAME f; Decoder decoder = new Decoder(); - Bitstream bitstream = new Bitstream(new ByteArrayInputStream(sis.readBytesEx(sis.available(), "soundStream"))); - while ((f = MP3FRAME.readFrame(bitstream, decoder)) != null) { - frames.add(f); - } + + byte data[] = sis.readBytesEx(sis.available(), "soundStream"); + MarkingBufferedInputStream mis = new MarkingBufferedInputStream(new ByteArrayInputStream(data)); + Bitstream bitstream = new Bitstream(mis); //new ByteArrayInputStream(data) + long initLen = mis.getPosition(); + MarkingPushbackInputStream mpis = bitstream.getSource(); + while (true) { + //System.err.println("initLen = "+initLen); + long posBefore = initLen+mpis.getPosition(); + MP3FRAME frame = MP3FRAME.readFrame(bitstream, decoder); + if (frame == null) { + break; + } + long posAfter = initLen+mpis.getPosition(); + frame.setFullData(Arrays.copyOfRange(data, (int)posBefore, (int)posAfter)); + frames.add(frame); + } } public int sampleCount() { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/sound/MarkingInputStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/sound/MarkingInputStream.java new file mode 100644 index 000000000..08f32a4e3 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/sound/MarkingInputStream.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2010-2022 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. + */ +package com.jpexs.decompiler.flash.types.sound; + +import java.io.IOException; +import java.io.InputStream; + +/** + * + * @author JPEXS + */ +public class MarkingInputStream extends InputStream { + + private InputStream is; + + private long pos = 0; + + public MarkingInputStream(InputStream is) { + this.is = is; + } + + @Override + public int read() throws IOException { + pos++; + return is.read(); + } + + public long getPos() { + return pos; + } +} diff --git a/libsrc/jlayer-1.0.2/src/main/java/javazoom/jl/decoder/Bitstream.java b/libsrc/jlayer-1.0.2/src/main/java/javazoom/jl/decoder/Bitstream.java index 9f884c59b..abd535f3c 100644 --- a/libsrc/jlayer-1.0.2/src/main/java/javazoom/jl/decoder/Bitstream.java +++ b/libsrc/jlayer-1.0.2/src/main/java/javazoom/jl/decoder/Bitstream.java @@ -146,7 +146,24 @@ public final class Bitstream implements BitstreamErrors { closeFrame(); } + + //JPEXS + public Bitstream(MarkingBufferedInputStream in) { + if (in == null) + throw new NullPointerException("in"); + loadID3v2(in); + in.setFixed(true); + firstframe = true; + source = new MarkingPushbackInputStream(in, BUFFER_INT_SIZE * 4); + + closeFrame(); + } + //JPEXS + public MarkingPushbackInputStream getSource() { + return (MarkingPushbackInputStream) source; + } + /** * Return position of the first audio header. * diff --git a/libsrc/jlayer-1.0.2/src/main/java/javazoom/jl/decoder/MarkingBufferedInputStream.java b/libsrc/jlayer-1.0.2/src/main/java/javazoom/jl/decoder/MarkingBufferedInputStream.java new file mode 100644 index 000000000..340756337 --- /dev/null +++ b/libsrc/jlayer-1.0.2/src/main/java/javazoom/jl/decoder/MarkingBufferedInputStream.java @@ -0,0 +1,99 @@ +package javazoom.jl.decoder; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * + * @author JPEXS + */ +public class MarkingBufferedInputStream extends BufferedInputStream { + + private BufferedInputStream is; + + private long pos = 0; + + private long markedPos = -1; + + private boolean fixed = false; + + public long getPosition() { + return pos; + } + + public void setFixed(boolean fixed) { + this.fixed = fixed; + } + + + + public MarkingBufferedInputStream(InputStream in) { + super(in); + this.is = new BufferedInputStream(in); + } + + @Override + public synchronized int read() throws IOException { + if (!fixed) pos++; + return is.read(); + } + + @Override + public int read(byte[] b) throws IOException { + int ret = is.read(b); + if (!fixed) pos += ret; + return ret; + } + + @Override + public synchronized int read(byte[] b, int off, int len) throws IOException { + int ret = is.read(b, off, len); + if (!fixed) pos += ret; + return ret; + } + + @Override + public synchronized void reset() throws IOException { + if (markedPos > -1) { + if (!fixed) pos = markedPos; + markedPos = -1; + } + is.reset(); + } + + @Override + public synchronized void mark(int readlimit) { + markedPos = pos; + is.mark(readlimit); + } + + @Override + public synchronized int available() throws IOException { + return is.available(); + } + + @Override + public synchronized long skip(long n) throws IOException { + long ret = is.skip(n); + if (!fixed) pos+=ret; + return ret; + } + + @Override + public void skipNBytes(long n) throws IOException { + if (!fixed) pos+=n; + is.skipNBytes(n); + } + + @Override + public void close() throws IOException { + is.close(); + } + + @Override + public boolean markSupported() { + return is.markSupported(); + } + +} diff --git a/libsrc/jlayer-1.0.2/src/main/java/javazoom/jl/decoder/MarkingPushbackInputStream.java b/libsrc/jlayer-1.0.2/src/main/java/javazoom/jl/decoder/MarkingPushbackInputStream.java new file mode 100644 index 000000000..2e2f57e69 --- /dev/null +++ b/libsrc/jlayer-1.0.2/src/main/java/javazoom/jl/decoder/MarkingPushbackInputStream.java @@ -0,0 +1,104 @@ +package javazoom.jl.decoder; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PushbackInputStream; + +/** + * + * @author JPEXS + */ +public class MarkingPushbackInputStream extends PushbackInputStream { + + private PushbackInputStream is; + + private long pos = 0; + + public long getPosition() { + return pos; + } + + + + public MarkingPushbackInputStream(InputStream in, int size) { + super(in, size); + is = new PushbackInputStream(in, size); + } + + @Override + public int available() throws IOException { + return is.available(); + } + + @Override + public synchronized void close() throws IOException { + is.close(); + } + + @Override + public synchronized void mark(int readlimit) { + is.mark(readlimit); + } + + @Override + public boolean markSupported() { + return is.markSupported(); + } + + @Override + public int read() throws IOException { + pos++; + return is.read(); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + + int ret = is.read(b, off, len); + pos += ret; + return ret; + } + + @Override + public int read(byte[] b) throws IOException { + int ret = is.read(b); + pos += ret; + return ret; + } + + @Override + public synchronized void reset() throws IOException { + is.reset(); + } + + @Override + public void unread(byte[] b) throws IOException { + pos -= b.length; + is.unread(b); + } + + @Override + public void unread(int b) throws IOException { + pos--; + is.unread(b); + } + + @Override + public void unread(byte[] b, int off, int len) throws IOException { + pos -= len; + is.unread(b, off, len); + } + + @Override + public long skip(long n) throws IOException { + long ret = is.skip(n); + pos += ret; + return ret; + } + + @Override + public void skipNBytes(long n) throws IOException { + pos += n; + is.skipNBytes(n); + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 473e90d9a..a77494b38 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.OpenableSourceInfo; import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.RenameType; import com.jpexs.decompiler.flash.abc.ScriptPack; @@ -156,6 +157,7 @@ import com.jpexs.decompiler.flash.tags.PlaceObjectTag; import com.jpexs.decompiler.flash.tags.ProductInfoTag; import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag; import com.jpexs.decompiler.flash.tags.ShowFrameTag; +import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.TagInfo; import com.jpexs.decompiler.flash.tags.UnknownTag; @@ -4752,7 +4754,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se previewPanel.closeTag(); } - public static void showPreview(TreeItem treeItem, PreviewPanel previewPanel, int frame, Timelined timelinedContainer) { + public static void showPreview(TreeItem treeItem, PreviewPanel previewPanel, int frame, Timelined timelinedContainer) { previewPanel.clear(); if (treeItem == null) { previewPanel.showEmpty(); @@ -5034,6 +5036,20 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se showDetail(DETAILCARDEMPTYPANEL); } + if (treeItem instanceof SoundStreamBlockTag) { + SoundStreamBlockTag block = (SoundStreamBlockTag)treeItem; + byte[] data = block.streamSoundData.getRangeData(); + try{ + SWFInputStream sis = new SWFInputStream(block.getSwf(), data); + int sampleCount = sis.readUI16("sampleCount"); + int seekSamples = sis.readSI16("seekSamples"); + System.out.println("sampleCount = "+sampleCount); + System.out.println("seekSamples = "+seekSamples); + System.out.println("============"); + }catch(Exception ex){ + + } + } if (treeItem instanceof HeaderItem) { headerPanel.load((SWF) ((HeaderItem) treeItem).getOpenable()); showCard(CARDHEADER);