From 1ba6b9196566c22c1ebb9a1f3a00a695015f1be2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 4 Dec 2022 23:22:40 +0100 Subject: [PATCH] video playback speed, hangs fixes, correct frame display --- CHANGELOG.md | 2 +- .../flash/exporters/MovieExporter.java | 2 +- .../flash/tags/DefineVideoStreamTag.java | 52 ++++++++++---- .../com/jpexs/video/SimpleMediaPlayer.java | 69 +++++++------------ 4 files changed, 66 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19e958ede..37f6a5432 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ All notable changes to this project will be documented in this file. - AS3 - "internal" keyword support - ProductInfo tag information display - DebugId tag proper display and editation -- [#1893] Experimental playback of DefineVideoStream tags with VLC player +- [#1893] Playback of DefineVideoStream tags with VLC player ### Fixed - [#1897] Close menu button without selecting specific item diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MovieExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MovieExporter.java index 4be4b36f0..67eb0828a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MovieExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MovieExporter.java @@ -202,7 +202,7 @@ public class MovieExporter { flv.writeTag(lastTag = new FLVTAG((long)Math.floor(ffdecInternal ? frameNum * 5000.0 : (frameNum * 1000.0 / swf.frameRate)), new VIDEODATA(frameType, videoStream.codecID, baos.toByteArray()))); } if (ffdecInternal && lastTag != null) { - lastTag.timeStamp = frameNum * 5000 + 5000; + lastTag.timeStamp = frameNum * 5000 + 10000; flv.writeTag(lastTag); } return fos.toByteArray(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java index 779680cce..3e3406d47 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java @@ -114,9 +114,13 @@ public class DefineVideoStreamTag extends DrawableTag implements BoundedTag, Tim private ReadOnlyTagList tags; @Internal - private int lastRatio = -1; + private int lastFrame = -1; + @Internal private Timeline timeline; + + @Internal + private Map frames; public static final int CODEC_SORENSON_H263 = 2; @@ -266,24 +270,36 @@ public class DefineVideoStreamTag extends DrawableTag implements BoundedTag, Tim g.setComposite(AlphaComposite.Dst); return; } + if (ratio == -1) { + ratio = 0; + } + + Set keyFrames = getFrames().keySet(); + + int f = 0; + for(int i = 0; i <= ratio; i++) { + if (keyFrames.contains(i)) { + f = i; + } + } + synchronized (DefineVideoStreamTag.class) { - if (!(activeFrame != null && lastRatio == ratio)) { + if (!(activeFrame != null && lastFrame == f)) { synchronized (getFrameLock) { activeFrame = null; getFrameLock.notifyAll(); } initPlayer(); - if (ratio == -1) { - ratio = 0; - } - //float oneFr = 1f / getNumFrames(); - ratio--; - + + if (mediaPlayer.isFinished()) { return; } - mediaPlayer.setPosition((float) ratio / getNumFrames()); + + float oneFr = 1f / (getNumFrames() + 2); + + mediaPlayer.setPosition(((float) f) / (getNumFrames() + 2) - (f == 0 ? 0 : oneFr / 10f)); try { synchronized (getFrameLock) { if (activeFrame == null) { @@ -296,6 +312,7 @@ public class DefineVideoStreamTag extends DrawableTag implements BoundedTag, Tim //Logger.getLogger(DefineVideoStreamTag.class.getName()).log(Level.SEVERE, null, ex); } } + lastFrame = f; synchronized (getFrameLock) { if (activeFrame != null) { //System.out.println("drawed"); @@ -338,20 +355,28 @@ public class DefineVideoStreamTag extends DrawableTag implements BoundedTag, Tim initTimeline(); return timeline; } + + private Map getFrames() { + if (this.frames != null) { + return this.frames; + } + Map frames = new HashMap<>(); + SWF.populateVideoFrames(characterID, swf.getTags(), frames); + this.frames = frames; + return frames; + } private void initTimeline() { if (timeline != null) { return; } - Map frames = new HashMap<>(); - SWF.populateVideoFrames(characterID, swf.getTags(), frames); - Set frameNums = new TreeSet<>(frames.keySet()); + Set frameNums = new TreeSet<>(getFrames().keySet()); int maxFr = 0; for (int f : frameNums) { maxFr = f; } List tags = new ArrayList<>(); - for (int f = 0; f < maxFr; f++) { + for (int f = 0; f <= maxFr; f++) { if (frames.containsKey(f)) { tags.add(frames.get(f)); } @@ -370,6 +395,7 @@ public class DefineVideoStreamTag extends DrawableTag implements BoundedTag, Tim @Override public void resetTimeline() { timeline = null; + frames = null; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/video/SimpleMediaPlayer.java b/libsrc/ffdec_lib/src/com/jpexs/video/SimpleMediaPlayer.java index 57b0ea374..a7aea887d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/video/SimpleMediaPlayer.java +++ b/libsrc/ffdec_lib/src/com/jpexs/video/SimpleMediaPlayer.java @@ -40,7 +40,7 @@ public class SimpleMediaPlayer { private final EmbeddedMediaPlayer embeddedMediaPlayer; private final MediaListPlayer mediaListPlayer; private final MediaPlayerFactory mediaPlayerFactory; - private boolean paused = true; + private boolean paused = false; private long time = 0L; @@ -93,41 +93,7 @@ public class SimpleMediaPlayer { public void stop() { embeddedMediaPlayer.controls().stop(); - } - - public void pause() { - if (paused) { - paused = false; - if (length != 0) { - embeddedMediaPlayer.controls().setPosition(((float) time) / length); - } - embeddedMediaPlayer.controls().play(); - return; - } - embeddedMediaPlayer.controls().pause(); - paused = true; - } - - public void setTime(long time) { - synchronized (displayLock) { - this.time = time; - positionSet = false; - if (paused) { - singleFrame = true; - } - embeddedMediaPlayer.controls().setTime(time); - embeddedMediaPlayer.controls().play(); - - if (paused) { - try { - displayLock.wait(); - } catch (InterruptedException ex) { - Logger.getLogger(SimpleMediaPlayer.class.getName()).log(Level.SEVERE, null, ex); - } - } - } - //embeddedMediaPlayer.controls().play(); - } + } public void setPosition(float position) { synchronized (displayLock) { @@ -136,9 +102,13 @@ public class SimpleMediaPlayer { singleFrame = true; } //System.out.println("setting position: "+ position); - embeddedMediaPlayer.controls().pause(); + if (!isPaused()) { + embeddedMediaPlayer.controls().pause(); + } embeddedMediaPlayer.controls().setPosition(position); - embeddedMediaPlayer.controls().play(); + //embeddedMediaPlayer.controls().nextFrame(); + setPaused(false); + embeddedMediaPlayer.controls().play(); /*if (paused) { try { displayLock.wait(); @@ -151,10 +121,14 @@ public class SimpleMediaPlayer { //embeddedMediaPlayer.controls().play(); } - public boolean isPaused() { + public synchronized boolean isPaused() { return paused; } + public synchronized void setPaused(boolean val) { + this.paused = val; + } + /*public void rewind() { System.out.println("rewinding"); //embeddedMediaPlayer.controls().stop(); @@ -230,11 +204,15 @@ public class SimpleMediaPlayer { @Override public void stopped(MediaPlayer mediaPlayer) { - System.out.println("stopped"); + //System.out.println("stopped"); + } + + @Override + public void paused(MediaPlayer mediaPlayer) { + setPaused(true); } - @Override public void playing(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer) { @@ -247,6 +225,7 @@ public class SimpleMediaPlayer { } //System.out.println("playing"); finished = false; + setPaused(false); //embeddedMediaPlayer.controls().setRepeat(true); } @@ -301,7 +280,7 @@ public class SimpleMediaPlayer { @Override public void display(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer, ByteBuffer[] nativeBuffers, BufferFormat bufferFormat) { synchronized (displayLock) { - if (singleFrame) { + if (singleFrame) { singleFrame = false; if (image == null) { this.width = bufferFormat.getWidth(); @@ -326,8 +305,10 @@ public class SimpleMediaPlayer { } } } - embeddedMediaPlayer.controls().pause(); - sendImage(); + if (!isPaused()) { + embeddedMediaPlayer.controls().pause(); + } + sendImage(); //System.out.println("display return"); } }