diff --git a/CHANGELOG.md b/CHANGELOG.md index d258bf6fb..616f96cf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file. - Hide zooming buttons in fonts display - [#2174] Ignoring PlaceObjects with flagMove on empty depth - [#2175] Removing DefineButtonSound, warning about incorrect sound character type in FLA export +- [#2175] FLA Export - exporting 320kbps MP3s as 160kbps ## [20.1.0] - 2023-12-30 ### Added diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java index bba8265b5..0c0228561 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java @@ -25,14 +25,14 @@ import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.annotations.EnumValue; import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.decompiler.flash.types.annotations.SWFVersion; +import com.jpexs.decompiler.flash.types.sound.MP3FRAME; +import com.jpexs.decompiler.flash.types.sound.MP3SOUNDDATA; import com.jpexs.decompiler.flash.types.sound.SoundExportFormat; import com.jpexs.decompiler.flash.types.sound.SoundFormat; import com.jpexs.helpers.ByteArrayRange; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; /** * @@ -139,7 +139,7 @@ public class DefineSoundTag extends CharacterTag implements SoundTag { @Override public SoundExportFormat getExportFormat() { if (soundFormat == SoundFormat.FORMAT_MP3) { - if (getInitialLatency() > 0) { + if (getInitialLatency() > 0 || isMp3HigherThan160Kbps()) { return SoundExportFormat.WAV; } return SoundExportFormat.MP3; @@ -261,4 +261,24 @@ public class DefineSoundTag extends CharacterTag implements SoundTag { } return 0; } + + private boolean isMp3HigherThan160Kbps() { + if (soundFormat != SoundFormat.FORMAT_MP3) { + return false; + } + try { + SWFInputStream sis = new SWFInputStream(swf, soundData.getRangeData()); + MP3SOUNDDATA s = new MP3SOUNDDATA(sis, false); + if (!s.frames.isEmpty()) { + MP3FRAME frame = s.frames.get(0); + int bitRate = frame.getBitRate() / 1000; + if (bitRate > 160) { + return true; + } + } + } catch (IOException ex) { + //ignore + } + return false; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java index 95090d0a4..1455082d2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java @@ -149,7 +149,7 @@ public class SoundStreamHead2Tag extends SoundStreamHeadTypeTag { @Override public SoundExportFormat getExportFormat() { if (streamSoundCompression == SoundFormat.FORMAT_MP3) { - if (getInitialLatency() > 0) { + if (getInitialLatency() > 0 || isMp3HigherThan160Kbps()) { return SoundExportFormat.WAV; } return SoundExportFormat.MP3; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java index fbb98fc55..01a1a40c2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java @@ -149,7 +149,7 @@ public class SoundStreamHeadTag extends SoundStreamHeadTypeTag { @Override public SoundExportFormat getExportFormat() { if (streamSoundCompression == SoundFormat.FORMAT_MP3) { - if (getInitialLatency() > 0) { + if (getInitialLatency() > 0 || isMp3HigherThan160Kbps()) { return SoundExportFormat.WAV; } return SoundExportFormat.MP3; 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 525665738..3a5cc2901 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 @@ -17,10 +17,15 @@ package com.jpexs.decompiler.flash.tags.base; import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.timeline.SoundStreamFrameRange; +import com.jpexs.decompiler.flash.types.sound.MP3FRAME; +import com.jpexs.decompiler.flash.types.sound.MP3SOUNDDATA; +import com.jpexs.decompiler.flash.types.sound.SoundFormat; import com.jpexs.helpers.ByteArrayRange; +import java.io.IOException; import java.util.List; /** @@ -40,4 +45,25 @@ public abstract class SoundStreamHeadTypeTag extends Tag implements CharacterIdT public abstract List getRanges(); + + protected boolean isMp3HigherThan160Kbps() { + List ranges = getRanges(); + if (ranges.isEmpty()) { + return false; + } + try { + SWFInputStream sis = new SWFInputStream(swf, ranges.get(0).blocks.get(0).streamSoundData.getRangeData()); + MP3SOUNDDATA s = new MP3SOUNDDATA(sis, false); + if (!s.frames.isEmpty()) { + MP3FRAME frame = s.frames.get(0); + int bitRate = frame.getBitRate() / 1000; + if (bitRate > 160) { + return true; + } + } + } catch (IOException ex) { + //ignore + } + return false; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index b800884a6..9bfe49e1a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -2068,6 +2068,7 @@ public class XFLConverter { } } int seekSamples = 0; + boolean convertMp3ToWav = false; if (soundFormat == SoundFormat.FORMAT_MP3) { exportFormat = "mp3"; if (!soundType) { //mono @@ -2080,6 +2081,7 @@ public class XFLConverter { if (s.seekSamples > 0) { seekSamples = s.seekSamples; exportFormat = "wav"; + convertMp3ToWav = true; } if (!s.frames.isEmpty()) { MP3FRAME frame = s.frames.get(0); @@ -2122,6 +2124,11 @@ public class XFLConverter { case 160: bits = 17; break; + default: + bits = 17; + exportFormat = "wav"; + convertMp3ToWav = true; + break; } } } catch (IOException | IndexOutOfBoundsException ex) { @@ -2132,7 +2139,7 @@ public class XFLConverter { SoundFormat fmt = st.getSoundFormat(); byte[] data = SWFInputStream.BYTE_ARRAY_EMPTY; try { - data = new SoundExporter().exportSound(st, seekSamples > 0 ? SoundExportMode.WAV : SoundExportMode.MP3_WAV); + data = new SoundExporter().exportSound(st, convertMp3ToWav ? SoundExportMode.WAV : SoundExportMode.MP3_WAV); } catch (IOException ex) { logger.log(Level.SEVERE, null, ex); } @@ -2149,7 +2156,7 @@ public class XFLConverter { String datFileName = null; - if (seekSamples > 0 && decodedData != null) { + if (convertMp3ToWav && decodedData != null) { long ts = getTimestamp(swf); datFileName = "M " + (datfiles.size() + 1) + " " + ts + ".dat"; datfiles.put(datFileName, decodedData); @@ -5107,6 +5114,9 @@ public class XFLConverter { case 160: streamCompress = 17; break; + default: + streamCompress = 17; + break; } } } catch (IOException | IndexOutOfBoundsException ex) {