From feb4102b85a85fdb888c7a715cbd0260c471a1f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 8 Jun 2025 23:07:56 +0200 Subject: [PATCH] #2451 Better MP3 stream matching --- .../flash/importers/SoundImporter.java | 28 ++++++++++++------- .../flash/timeline/SoundStreamFrameRange.java | 22 +++++++++++++++ 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SoundImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SoundImporter.java index 5d9911e12..87117adb1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SoundImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SoundImporter.java @@ -473,6 +473,7 @@ public class SoundImporter { List existingBlocks = new ArrayList<>(); Timelined timelined = streamHead.getTimelined(); + int firstSeekSamples = 0; if (startFrame == null) { for (SoundStreamFrameRange range : ranges) { @@ -494,6 +495,7 @@ public class SoundImporter { } else { for (SoundStreamFrameRange range : ranges) { if (range.startFrame == startFrame) { + firstSeekSamples = range.getSeekSamples(); existingBlocks.addAll(range.blocks); break; } @@ -538,27 +540,30 @@ public class SoundImporter { //ignore } } - if (mp3Frames != null) { + if (mp3Frames != null && !mp3Frames.isEmpty()) { + MP3FRAME firstMp3Frame = mp3Frames.get(0); + int sampleCountPerMp3Frame = firstMp3Frame.getSampleCount(); - int frame = 0; + int frame = startFrame; int mp3FrameNum = 0; - long lastNumSamplesLong = 0; + long lastNumSamplesLong = Math.round(startFrame * soundRateHz / swf.frameRate) - firstSeekSamples; while (mp3FrameNum < mp3Frames.size()) { - float timeAfterFrame = (frame + 1) / swf.frameRate; - float numSamplesAfterFrame = (frame + 1) * soundRateHz / swf.frameRate; + float idealNumberOfSamplesAfterFrame = (frame + 1) * soundRateHz / swf.frameRate; long numSamplesBeforeFrameLong = Math.round(frame * soundRateHz / swf.frameRate); - int seekSamples = (int) (lastNumSamplesLong - numSamplesBeforeFrameLong); + int seekSamples = (int) (numSamplesBeforeFrameLong - lastNumSamplesLong); SoundStreamBlockTag block = new SoundStreamBlockTag(swf); + block.forceWriteAsLong = true; List blockMp3Frames = new ArrayList<>(); int blockSamples = 0; - while (lastNumSamplesLong < numSamplesAfterFrame && mp3FrameNum < mp3Frames.size()) { + while (mp3FrameNum < mp3Frames.size() + && (lastNumSamplesLong + sampleCountPerMp3Frame < idealNumberOfSamplesAfterFrame)) { MP3FRAME mp3Frame = mp3Frames.get(mp3FrameNum); - lastNumSamplesLong += mp3Frame.getSampleCount(); - blockSamples += mp3Frame.getSampleCount(); + lastNumSamplesLong += sampleCountPerMp3Frame; + blockSamples += sampleCountPerMp3Frame; blockMp3Frames.add(mp3Frame); mp3FrameNum++; } @@ -571,11 +576,14 @@ public class SoundImporter { sos.write(mp3Frame.getBytes()); } } catch (IOException ex) { - Logger.getLogger(SoundStreamHeadTypeTag.class.getName()).log(Level.SEVERE, null, ex); + Logger.getLogger(SoundImporter.class.getName()).log(Level.SEVERE, null, ex); } block.streamSoundData = new ByteArrayRange(baos.toByteArray()); blocks.add(block); frame++; + + //TODO: maybe last frame empty? But how to calculate seekSamples + //lastNumSamplesLong - ((frame + 1) * soundRateHz / swf.frameRate)); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/SoundStreamFrameRange.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/SoundStreamFrameRange.java index 7cd910945..dc738764d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/SoundStreamFrameRange.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/SoundStreamFrameRange.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.timeline; +import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag; import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; import com.jpexs.decompiler.flash.tags.base.SoundTag; @@ -24,8 +25,11 @@ import com.jpexs.decompiler.flash.treeitems.TreeItem; 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; /** * SoundStream blocks across frame range. @@ -109,6 +113,24 @@ public class SoundStreamFrameRange implements TreeItem, SoundTag { return ret; } + public int getSeekSamples() { + if (blocks.isEmpty()) { + return 0; + } + if (getSoundFormatId() != SoundFormat.FORMAT_MP3) { + return 0; + } + ByteArrayRange data = blocks.get(0).streamSoundData; + SWFInputStream sis; + try { + sis = new SWFInputStream(null, data.getRangeData(0, 4)); + sis.readUI16("numSamples"); + return sis.readSI16("seekSamples"); + } catch (IOException ex) { + return 0; + } + } + @Override public int getSoundFormatId() { return head.getSoundFormatId();