mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-19 01:18:09 +00:00
Issue #374 Replace selected sound (DefineSound tag)
This commit is contained in:
@@ -235,6 +235,10 @@ public final class SWF implements TreeItem, Timelined {
|
||||
|
||||
private Timeline timeline;
|
||||
|
||||
public void updateCharacters() {
|
||||
parseCharacters(new ArrayList<ContainerItem>(tags));
|
||||
}
|
||||
|
||||
private void parseCharacters(List<ContainerItem> list) {
|
||||
for (ContainerItem t : list) {
|
||||
if (t instanceof CharacterTag) {
|
||||
@@ -563,7 +567,7 @@ public final class SWF implements TreeItem, Timelined {
|
||||
showFrameTag.innerTags = innerTags;
|
||||
}
|
||||
}
|
||||
parseCharacters(new ArrayList<ContainerItem>(tags));
|
||||
updateCharacters();
|
||||
assignExportNamesToSymbols();
|
||||
assignClassesToSymbols();
|
||||
findFileAttributes();
|
||||
|
||||
@@ -308,7 +308,7 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
|
||||
return 0;
|
||||
}
|
||||
if (stillFrame) {
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return timelined.getTimeline().frames.size();
|
||||
}
|
||||
|
||||
@@ -157,6 +157,7 @@ import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
@@ -282,6 +283,9 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
private File tempFile;
|
||||
private PlayerControls imagePlayControls;
|
||||
|
||||
private JPanel repPanel;
|
||||
private JPanel repPanel2;
|
||||
|
||||
private SoundThread soundThread = null;
|
||||
|
||||
private class SoundThread implements MediaDisplay {
|
||||
@@ -422,6 +426,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
private static final String ACTION_SELECT_BKCOLOR = "SELECTCOLOR";
|
||||
private static final String ACTION_REPLACE_IMAGE = "REPLACEIMAGE";
|
||||
private static final String ACTION_REPLACE_BINARY = "REPLACEBINARY";
|
||||
private static final String ACTION_REPLACE_OTHER = "REPLACEOTHER";
|
||||
private static final String ACTION_EDIT_GENERIC_TAG = "EDITGENERICTAG";
|
||||
private static final String ACTION_SAVE_GENERIC_TAG = "SAVEGENERICTAG";
|
||||
private static final String ACTION_CANCEL_GENERIC_TAG = "CANCELGENERICTAG";
|
||||
@@ -507,6 +512,11 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
replaceBinarySelectionMenuItem.addActionListener(this);
|
||||
contextPopupMenu.add(replaceBinarySelectionMenuItem);
|
||||
|
||||
final JMenuItem replaceSoundSelectionMenuItem = new JMenuItem(translate("button.replace"));
|
||||
replaceSoundSelectionMenuItem.setActionCommand(ACTION_REPLACE_OTHER);
|
||||
replaceSoundSelectionMenuItem.addActionListener(this);
|
||||
contextPopupMenu.add(replaceSoundSelectionMenuItem);
|
||||
|
||||
final JMenuItem closeSelectionMenuItem = new JMenuItem(translate("contextmenu.closeSwf"));
|
||||
closeSelectionMenuItem.setActionCommand(ACTION_CLOSE_SWF);
|
||||
closeSelectionMenuItem.addActionListener(this);
|
||||
@@ -548,6 +558,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
|
||||
replaceImageSelectionMenuItem.setVisible(false);
|
||||
replaceBinarySelectionMenuItem.setVisible(false);
|
||||
replaceSoundSelectionMenuItem.setVisible(false);
|
||||
closeSelectionMenuItem.setVisible(false);
|
||||
moveTagMenu.setVisible(false);
|
||||
expandRecursiveMenuItem.setVisible(false);
|
||||
@@ -564,6 +575,10 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
replaceBinarySelectionMenuItem.setVisible(true);
|
||||
}
|
||||
|
||||
if (item instanceof DefineSoundTag) {
|
||||
replaceSoundSelectionMenuItem.setVisible(true);
|
||||
}
|
||||
|
||||
if (treeNode instanceof SWFNode) {
|
||||
closeSelectionMenuItem.setVisible(true);
|
||||
}
|
||||
@@ -947,6 +962,13 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
|
||||
}
|
||||
pan.add(leftComponent, BorderLayout.CENTER);
|
||||
|
||||
repPanel = new JPanel(new FlowLayout());
|
||||
JButton repButton = new JButton(translate("button.replace"), View.getIcon("edit16"));
|
||||
repButton.addActionListener(this);
|
||||
repButton.setActionCommand(ACTION_REPLACE_OTHER);
|
||||
repPanel.add(repButton);
|
||||
pan.add(repPanel, BorderLayout.SOUTH);
|
||||
viewerCards.add(pan, FLASH_VIEWER_CARD);
|
||||
previewSplitPane.setLeftComponent(viewerCards);
|
||||
|
||||
@@ -976,9 +998,19 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
prevIntLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
//prevIntLabel.setBorder(new BevelBorder(BevelBorder.RAISED));
|
||||
previewPanel.add(prevIntLabel, BorderLayout.NORTH);
|
||||
|
||||
repPanel2 = new JPanel(new FlowLayout());
|
||||
JButton repButton2 = new JButton(translate("button.replace"), View.getIcon("edit16"));
|
||||
repButton2.addActionListener(this);
|
||||
repButton2.setActionCommand(ACTION_REPLACE_OTHER);
|
||||
repPanel2.add(repButton2);
|
||||
previewPanel.add(repPanel2, BorderLayout.SOUTH);
|
||||
|
||||
shapesCard.add(previewPanel, BorderLayout.CENTER);
|
||||
displayPanel.add(shapesCard, CARDDRAWPREVIEWPANEL);
|
||||
|
||||
displayReplace(false);
|
||||
|
||||
swfPreviewPanel = new ImagePanel();
|
||||
displayPanel.add(swfPreviewPanel, CARDSWFPREVIEWPANEL);
|
||||
|
||||
@@ -2251,13 +2283,79 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
reload(true);
|
||||
}
|
||||
break;
|
||||
case ACTION_REPLACE_IMAGE: {
|
||||
case ACTION_REPLACE_BINARY:
|
||||
case ACTION_REPLACE_IMAGE:
|
||||
case ACTION_REPLACE_OTHER: {
|
||||
TreeNode treeNode = (TreeNode) tagTree.getLastSelectedPathComponent();
|
||||
if (treeNode == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
TreeItem item = treeNode.getItem();
|
||||
if (item instanceof DefineSoundTag) {
|
||||
JFileChooser fc = new JFileChooser();
|
||||
fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get()));
|
||||
fc.setFileFilter(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File f) {
|
||||
return (f.getName().toLowerCase().endsWith(".mp3"))
|
||||
|| (f.getName().toLowerCase().endsWith(".wav"))
|
||||
|| (f.isDirectory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return translate("filter.sounds");
|
||||
}
|
||||
});
|
||||
fc.addChoosableFileFilter(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File f) {
|
||||
return (f.getName().toLowerCase().endsWith(".mp3"))
|
||||
|| (f.isDirectory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return translate("filter.sounds.mp3");
|
||||
}
|
||||
});
|
||||
fc.addChoosableFileFilter(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File f) {
|
||||
return (f.getName().toLowerCase().endsWith(".wav"))
|
||||
|| (f.isDirectory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return translate("filter.sounds.wav");
|
||||
}
|
||||
});
|
||||
JFrame f = new JFrame();
|
||||
View.setWindowIcon(f);
|
||||
int returnVal = fc.showOpenDialog(f);
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||
Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath());
|
||||
File selfile = Helper.fixDialogFile(fc.getSelectedFile());
|
||||
DefineSoundTag ds = (DefineSoundTag) item;
|
||||
int soundFormat = DefineSoundTag.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN;
|
||||
if (selfile.getName().toLowerCase().endsWith(".mp3")) {
|
||||
soundFormat = DefineSoundTag.FORMAT_MP3;
|
||||
}
|
||||
boolean ok = false;
|
||||
try {
|
||||
ok = ds.setSound(new FileInputStream(selfile), soundFormat);
|
||||
} catch (IOException ex) {
|
||||
//ignore
|
||||
}
|
||||
if (!ok) {
|
||||
View.showMessageDialog(null, translate("error.sound.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE);
|
||||
} else {
|
||||
reload(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (item instanceof ImageTag) {
|
||||
ImageTag it = (ImageTag) item;
|
||||
if (it.importSupported()) {
|
||||
@@ -2290,12 +2388,13 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
if (it instanceof DefineBitsTag) {
|
||||
DefineBitsJPEG2Tag jpeg2Tag = new DefineBitsJPEG2Tag(swf, it.getOriginalData(), it.getPos(), it.getCharacterId(), data);
|
||||
swf.tags.set(swf.tags.indexOf(it), jpeg2Tag);
|
||||
swf.updateCharacters();
|
||||
refreshTree();
|
||||
setTreeItem(jpeg2Tag);
|
||||
} else {
|
||||
it.setImage(data);
|
||||
}
|
||||
swf.clearImageCache();
|
||||
SWF.clearImageCache();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(MainPanel.class.getName()).log(Level.SEVERE, "Invalid image", ex);
|
||||
View.showMessageDialog(null, translate("error.image.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE);
|
||||
@@ -2304,15 +2403,6 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ACTION_REPLACE_BINARY: {
|
||||
TreeNode treeNode = (TreeNode) tagTree.getLastSelectedPathComponent();
|
||||
if (treeNode == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
TreeItem item = treeNode.getItem();
|
||||
if (item instanceof DefineBinaryDataTag) {
|
||||
DefineBinaryDataTag bt = (DefineBinaryDataTag) item;
|
||||
JFileChooser fc = new JFileChooser();
|
||||
@@ -2515,8 +2605,9 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
if (soundThread != null) {
|
||||
soundThread.pause();
|
||||
}
|
||||
imagePlayControls.setMedia(imagePanel);
|
||||
imagePlayControls.setMedia(previewImagePanel);
|
||||
stopFlashPlayer();
|
||||
displayReplace(tagObj instanceof DefineSoundTag);
|
||||
if (tagObj instanceof ScriptPack) {
|
||||
final ScriptPack scriptLeaf = (ScriptPack) tagObj;
|
||||
final List<ABCContainerTag> abcList = scriptLeaf.abc.swf.abcList;
|
||||
@@ -3320,4 +3411,11 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void displayReplace(boolean display) {
|
||||
|
||||
repPanel.setVisible(display);
|
||||
repPanel2.setVisible(display);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,3 +455,9 @@ generictag.array.insertend = Insert %item% at the end
|
||||
#after version 2.0.0
|
||||
contextmenu.expandAll = Expand all
|
||||
binaryData.truncateWarning = %count% bytes truncated.
|
||||
|
||||
filter.sounds = Supported sound formats (*.wav, *.mp3)
|
||||
filter.sounds.wav = Wave file format (*.wav)
|
||||
filter.sounds.mp3 = MP3 compressed format (*.mp3)
|
||||
|
||||
error.sound.invalid = Invalid sound.
|
||||
@@ -453,3 +453,10 @@ generictag.array.insertbefore = Vlo\u017eit %item% p\u0159ed
|
||||
generictag.array.remove = Odstranit %item%
|
||||
generictag.array.insertafter = Vlo\u017eit %item% za
|
||||
generictag.array.insertend = Vlo\u017eit %item% na konec
|
||||
|
||||
|
||||
filter.sounds = Podporovan\u00e9 zvukov\u00e9 form\u00e1ty (*.wav, *.mp3)
|
||||
filter.sounds.wav = Wave form\u00e1t (*.wav)
|
||||
filter.sounds.mp3 = MP3 komprimovan\u00fd form\u00e1t (*.mp3)
|
||||
|
||||
error.sound.invalid = Neplatn\u00fd zvuk.
|
||||
@@ -22,10 +22,20 @@ import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.sound.MP3FRAME;
|
||||
import com.jpexs.decompiler.flash.types.sound.MP3SOUNDDATA;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -83,6 +93,7 @@ public class DefineSoundTag extends CharacterTag {
|
||||
sos.writeUB(1, soundType ? 1 : 0);
|
||||
sos.writeUI32(soundSampleCount);
|
||||
sos.write(soundData);
|
||||
|
||||
} catch (IOException e) {
|
||||
}
|
||||
return baos.toByteArray();
|
||||
@@ -123,4 +134,153 @@ public class DefineSoundTag extends CharacterTag {
|
||||
}
|
||||
return "flv";
|
||||
}
|
||||
|
||||
private void loadID3v2(InputStream in) {
|
||||
int size = -1;
|
||||
try {
|
||||
// Read ID3v2 header (10 bytes).
|
||||
in.mark(10);
|
||||
size = readID3v2Header(in);
|
||||
} catch (IOException e) {
|
||||
} finally {
|
||||
try {
|
||||
// Unread ID3v2 header (10 bytes).
|
||||
in.reset();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
// Load ID3v2 tags.
|
||||
try {
|
||||
if (size > 0) {
|
||||
byte[] rawid3v2 = new byte[size];
|
||||
in.read(rawid3v2, 0, rawid3v2.length);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse ID3v2 tag header to find out size of ID3v2 frames.
|
||||
*
|
||||
* @param in MP3 InputStream
|
||||
* @return size of ID3v2 frames + header
|
||||
* @throws IOException
|
||||
* @author JavaZOOM
|
||||
*/
|
||||
private int readID3v2Header(InputStream in) throws IOException {
|
||||
byte[] id3header = new byte[4];
|
||||
int size = -10;
|
||||
in.read(id3header, 0, 3);
|
||||
// Look for ID3v2
|
||||
if ((id3header[0] == 'I') && (id3header[1] == 'D') && (id3header[2] == '3')) {
|
||||
in.read(id3header, 0, 3);
|
||||
int majorVersion = id3header[0];
|
||||
int revision = id3header[1];
|
||||
in.read(id3header, 0, 4);
|
||||
size = (int) (id3header[0] << 21) + (id3header[1] << 14) + (id3header[2] << 7) + (id3header[3]);
|
||||
}
|
||||
return (size + 10);
|
||||
}
|
||||
|
||||
public boolean setSound(InputStream is, int newSoundFormat) throws IOException {
|
||||
int newSoundRate = -1;
|
||||
boolean newSoundSize = false;
|
||||
boolean newSoundType = false;
|
||||
long newSoundSampleCount = -1;
|
||||
byte newSoundData[];
|
||||
switch (newSoundFormat) {
|
||||
case FORMAT_UNCOMPRESSED_LITTLE_ENDIAN:
|
||||
try (AudioInputStream audioIs = AudioSystem.getAudioInputStream(new BufferedInputStream(is))) {
|
||||
AudioFormat fmt = audioIs.getFormat();
|
||||
newSoundType = fmt.getChannels() == 2;
|
||||
newSoundSize = fmt.getSampleSizeInBits() == 16;
|
||||
newSoundSampleCount = audioIs.getFrameLength();
|
||||
newSoundData = Helper.readStream(audioIs);
|
||||
newSoundRate = (int) Math.round(fmt.getSampleRate());
|
||||
switch (newSoundRate) {
|
||||
case 5512:
|
||||
newSoundRate = 0;
|
||||
break;
|
||||
case 11025:
|
||||
newSoundRate = 1;
|
||||
break;
|
||||
case 22050:
|
||||
newSoundRate = 2;
|
||||
break;
|
||||
case 44100:
|
||||
newSoundRate = 3;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} catch (UnsupportedAudioFileException ex) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case FORMAT_MP3:
|
||||
BufferedInputStream bis = new BufferedInputStream(is);
|
||||
loadID3v2(bis);
|
||||
byte mp3data[] = Helper.readStream(bis);
|
||||
|
||||
final int ID3_V1_LENTGH = 128;
|
||||
final int ID3_V1_EXT_LENGTH = 227;
|
||||
|
||||
if (mp3data.length > ID3_V1_LENTGH) {
|
||||
//ID3v1
|
||||
if (mp3data[mp3data.length - ID3_V1_LENTGH] == 'T' && mp3data[mp3data.length - ID3_V1_LENTGH + 1] == 'A' && mp3data[mp3data.length - ID3_V1_LENTGH + 2] == 'G') {
|
||||
mp3data = Arrays.copyOf(mp3data, mp3data.length - ID3_V1_LENTGH);
|
||||
if (mp3data.length > ID3_V1_EXT_LENGTH) {
|
||||
//ID3v1 extended
|
||||
if (mp3data[mp3data.length - ID3_V1_EXT_LENGTH] == 'T' && mp3data[mp3data.length - ID3_V1_EXT_LENGTH + 1] == 'A' && mp3data[mp3data.length - ID3_V1_EXT_LENGTH + 2] == 'G' && mp3data[mp3data.length - ID3_V1_EXT_LENGTH + 3] == '+') {
|
||||
mp3data = Arrays.copyOf(mp3data, mp3data.length - ID3_V1_EXT_LENGTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MP3SOUNDDATA snd = new MP3SOUNDDATA(new ByteArrayInputStream(mp3data), true);
|
||||
if (!snd.frames.isEmpty()) {
|
||||
MP3FRAME fr = snd.frames.get(0);
|
||||
newSoundRate = fr.getSamplingRate();
|
||||
switch (newSoundRate) {
|
||||
case 11025:
|
||||
newSoundRate = 1;
|
||||
break;
|
||||
case 22050:
|
||||
newSoundRate = 2;
|
||||
break;
|
||||
case 44100:
|
||||
newSoundRate = 3;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
newSoundSize = true;
|
||||
newSoundType = fr.isStereo();
|
||||
int len = snd.sampleCount();
|
||||
if (fr.isStereo()) {
|
||||
len = len / 2;
|
||||
}
|
||||
newSoundSampleCount = len;
|
||||
|
||||
}
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos = new SWFOutputStream(baos, SWF.DEFAULT_VERSION);
|
||||
sos.writeSI16(0); //Latency - how to calculate it?
|
||||
sos.write(mp3data);
|
||||
newSoundData = baos.toByteArray();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if (newSoundData != null) {
|
||||
this.soundSize = newSoundSize;
|
||||
this.soundRate = newSoundRate;
|
||||
this.soundSampleCount = newSoundSampleCount;
|
||||
this.soundData = newSoundData;
|
||||
this.soundType = newSoundType;
|
||||
this.soundFormat = newSoundFormat;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,15 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types.sound;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javazoom.jl.decoder.Bitstream;
|
||||
import javazoom.jl.decoder.BitstreamException;
|
||||
import javazoom.jl.decoder.Decoder;
|
||||
import javazoom.jl.decoder.DecoderException;
|
||||
import javazoom.jl.decoder.Header;
|
||||
import javazoom.jl.decoder.SampleBuffer;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -31,113 +32,75 @@ import java.util.logging.Logger;
|
||||
*/
|
||||
public class MP3FRAME {
|
||||
|
||||
public int syncWord;
|
||||
public int mpegVersion;
|
||||
public int layer;
|
||||
public boolean protectionBit;
|
||||
public int bitRate;
|
||||
public int samplingRate;
|
||||
public boolean paddingBit;
|
||||
public int reserved;
|
||||
public int channelMode;
|
||||
public int modelExtension;
|
||||
public boolean copyright;
|
||||
public boolean original;
|
||||
public int emphasis;
|
||||
public byte[] sampleData;
|
||||
private Header h;
|
||||
private SampleBuffer samples;
|
||||
|
||||
public MP3FRAME(InputStream is) throws IOException {
|
||||
SWFInputStream sis = new SWFInputStream(is, SWF.DEFAULT_VERSION);
|
||||
syncWord = (int) sis.readUB(11);
|
||||
mpegVersion = (int) sis.readUB(2);
|
||||
layer = (int) sis.readUB(2);
|
||||
protectionBit = sis.readUB(1) == 1;
|
||||
bitRate = (int) sis.readUB(4);
|
||||
samplingRate = (int) sis.readUB(2);
|
||||
paddingBit = sis.readUB(1) == 1;
|
||||
reserved = (int) sis.readUB(1);
|
||||
channelMode = (int) sis.readUB(2);
|
||||
modelExtension = (int) sis.readUB(2);
|
||||
private MP3FRAME() {
|
||||
|
||||
int size = getSampleDataSize();
|
||||
int sizeBytes = (int) Math.ceil((double) size / 8.0);
|
||||
sampleData = sis.readBytes(sizeBytes);
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
public static MP3FRAME readFrame(Bitstream bitstream, Decoder decoder) throws IOException {
|
||||
MP3FRAME ret = new MP3FRAME();
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos = new SWFOutputStream(baos, SWF.DEFAULT_VERSION);
|
||||
sos.writeUB(11, syncWord);
|
||||
sos.writeUB(1, mpegVersion);
|
||||
sos.writeUB(2, layer);
|
||||
sos.writeUB(1, protectionBit ? 1 : 0);
|
||||
sos.writeUB(4, bitRate);
|
||||
sos.writeUB(2, samplingRate);
|
||||
sos.writeUB(1, paddingBit ? 1 : 0);
|
||||
sos.writeUB(1, reserved);
|
||||
sos.writeUB(2, channelMode);
|
||||
sos.writeUB(2, modelExtension);
|
||||
sos.write(sampleData);
|
||||
return baos.toByteArray();
|
||||
} catch (IOException ex) {
|
||||
ret.h = bitstream.readFrame();
|
||||
if (ret.h == null) {
|
||||
return null;
|
||||
}
|
||||
} catch (BitstreamException ex) {
|
||||
Logger.getLogger(MP3FRAME.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int getSampleDataSize() {
|
||||
return (((isMPEG1() ? 144 : 72) * bitRate) / samplingRate) + (paddingBit ? 1 : 0) - 4;
|
||||
}
|
||||
|
||||
public boolean isMPEG2() {
|
||||
return mpegVersion == 2;
|
||||
}
|
||||
|
||||
public boolean isMPEG1() {
|
||||
return mpegVersion == 3;
|
||||
}
|
||||
|
||||
public boolean isLayerI() {
|
||||
return layer == 3;
|
||||
}
|
||||
|
||||
public boolean isLayerII() {
|
||||
return layer == 2;
|
||||
}
|
||||
|
||||
public boolean isLayerIII() {
|
||||
return layer == 1;
|
||||
}
|
||||
|
||||
public int getBitrate() {
|
||||
int[] v1_l1_map = {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1};
|
||||
int[] v1_l2_map = {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1};
|
||||
int[] v1_l3_map = {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1};
|
||||
int[] v2_l1_map = {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1};
|
||||
int[] v2_l2l3_map = {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1};
|
||||
|
||||
int[][][] map = {
|
||||
{v1_l1_map, v1_l2_map, v1_l3_map},
|
||||
{v2_l1_map, v2_l2l3_map, v2_l2l3_map}
|
||||
};
|
||||
int layer = 0;
|
||||
if (isLayerI()) {
|
||||
layer = 0;
|
||||
try {
|
||||
ret.samples = (SampleBuffer) decoder.decodeFrame(ret.h, bitstream);
|
||||
} catch (DecoderException ex) {
|
||||
Logger.getLogger(MP3FRAME.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
if (isLayerII()) {
|
||||
layer = 1;
|
||||
bitstream.closeFrame();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public boolean isStereo() {
|
||||
return h.mode() != Header.SINGLE_CHANNEL;
|
||||
}
|
||||
|
||||
public SampleBuffer getSamples() {
|
||||
return samples;
|
||||
}
|
||||
|
||||
public int getSamplingRate() {
|
||||
switch (h.sample_frequency()) {
|
||||
case Header.THIRTYTWO:
|
||||
if (h.version() == Header.MPEG1) {
|
||||
return 32000;
|
||||
} else if (h.version() == Header.MPEG2_LSF) {
|
||||
return 16000;
|
||||
} else // SZD
|
||||
{
|
||||
return 8000;
|
||||
}
|
||||
case Header.FOURTYFOUR_POINT_ONE:
|
||||
if (h.version() == Header.MPEG1) {
|
||||
return 44100;
|
||||
} else if (h.version() == Header.MPEG2_LSF) {
|
||||
return 22050;
|
||||
} else // SZD
|
||||
{
|
||||
return 11025;
|
||||
}
|
||||
case Header.FOURTYEIGHT:
|
||||
if (h.version() == Header.MPEG1) {
|
||||
return 48000;
|
||||
} else if (h.version() == Header.MPEG2_LSF) {
|
||||
return 24000;
|
||||
} else // SZD
|
||||
{
|
||||
return 12000;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
if (isLayerIII()) {
|
||||
layer = 2;
|
||||
}
|
||||
int mver = 0;
|
||||
if (isMPEG1()) {
|
||||
mver = 0;
|
||||
}
|
||||
if (isMPEG2()) {
|
||||
mver = 1;
|
||||
}
|
||||
return map[mver][layer][bitRate];
|
||||
}
|
||||
|
||||
public int getBitRate() {
|
||||
return h.bitrate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javazoom.jl.decoder.Bitstream;
|
||||
import javazoom.jl.decoder.Decoder;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -32,12 +34,25 @@ public class MP3SOUNDDATA {
|
||||
public int seekSamples;
|
||||
public List<MP3FRAME> frames;
|
||||
|
||||
public MP3SOUNDDATA(InputStream is) throws IOException {
|
||||
public MP3SOUNDDATA(InputStream is, boolean raw) throws IOException {
|
||||
SWFInputStream sis = new SWFInputStream(is, SWF.DEFAULT_VERSION);
|
||||
seekSamples = sis.readUI16();
|
||||
if (!raw) {
|
||||
seekSamples = sis.readSI16();
|
||||
}
|
||||
frames = new ArrayList<>();
|
||||
while (sis.available() > 0) {
|
||||
frames.add(new MP3FRAME(sis));
|
||||
MP3FRAME f;
|
||||
Decoder decoder = new Decoder();
|
||||
Bitstream bitstream = new Bitstream(is);
|
||||
while ((f = MP3FRAME.readFrame(bitstream, decoder)) != null) {
|
||||
frames.add(f);
|
||||
}
|
||||
}
|
||||
|
||||
public int sampleCount() {
|
||||
int r = 0;
|
||||
for (MP3FRAME f : frames) {
|
||||
r += f.getSamples().getBufferLength();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
|
||||
import com.jpexs.decompiler.flash.types.sound.MP3FRAME;
|
||||
import com.jpexs.decompiler.flash.types.sound.MP3SOUNDDATA;
|
||||
import com.jpexs.decompiler.graph.ExportMode;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import com.jpexs.helpers.utf8.Utf8Helper;
|
||||
@@ -1441,9 +1442,11 @@ public class XFLConverter {
|
||||
format += 4; //quality best
|
||||
SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(soundData), swf.version);
|
||||
try {
|
||||
sis.readSI16();
|
||||
MP3FRAME frame = new MP3FRAME(sis);
|
||||
int bitRate = frame.getBitrate();
|
||||
MP3SOUNDDATA s = new MP3SOUNDDATA(sis, false);
|
||||
//sis.readSI16();
|
||||
//MP3FRAME frame = new MP3FRAME(sis);
|
||||
MP3FRAME frame = s.frames.get(0);
|
||||
int bitRate = frame.getBitRate();
|
||||
|
||||
switch (bitRate) {
|
||||
case 8:
|
||||
|
||||
@@ -46,6 +46,7 @@ public class MP3Player extends SoundPlayer {
|
||||
private int positionSamples = 0;
|
||||
private long sampleCount;
|
||||
private int frameRate;
|
||||
private int positionFrames = 0;
|
||||
|
||||
public MP3Player(InputStream stream, long sampleCount, int frameRate) throws JavaLayerException {
|
||||
this(stream, null);
|
||||
@@ -118,6 +119,7 @@ public class MP3Player extends SoundPlayer {
|
||||
}
|
||||
SampleBuffer output = (SampleBuffer) decoder.decodeFrame(h, bitstream);
|
||||
positionSamples += output.getBufferLength();
|
||||
positionFrames++;
|
||||
bitstream.closeFrame();
|
||||
if (positionSamples >= endPosition) {
|
||||
break;
|
||||
@@ -163,6 +165,7 @@ public class MP3Player extends SoundPlayer {
|
||||
|
||||
SampleBuffer output = (SampleBuffer) decoder.decodeFrame(h, bitstream);
|
||||
positionSamples += output.getBufferLength();
|
||||
positionFrames++;
|
||||
|
||||
synchronized (this) {
|
||||
out = audio;
|
||||
|
||||
Reference in New Issue
Block a user