mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-16 15:30:17 +00:00
Replace movies with commandline
This commit is contained in:
@@ -26,9 +26,13 @@ import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.MovieExportMode;
|
||||
import com.jpexs.decompiler.flash.flv.FLVInputStream;
|
||||
import com.jpexs.decompiler.flash.flv.FLVTAG;
|
||||
import com.jpexs.decompiler.flash.flv.VIDEODATA;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ButtonTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.RenderContext;
|
||||
import com.jpexs.decompiler.flash.timeline.Timeline;
|
||||
import com.jpexs.decompiler.flash.timeline.Timelined;
|
||||
@@ -45,6 +49,7 @@ import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.decompiler.flash.types.filters.BlendComposite;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.Reference;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import com.jpexs.video.FrameListener;
|
||||
import com.jpexs.video.SimpleMediaPlayer;
|
||||
@@ -57,9 +62,15 @@ import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -94,8 +105,8 @@ public class DefineVideoStreamTag extends DrawableTag implements BoundedTag, Tim
|
||||
@Reserved
|
||||
@SWFType(value = BasicType.UB, count = 4)
|
||||
public int reserved;
|
||||
|
||||
@SWFType(value = BasicType.UB, count = 3)
|
||||
|
||||
@SWFType(value = BasicType.UB, count = 3)
|
||||
@EnumValue(value = DefineVideoStreamTag.DEBLOCKING_USE_VIDEOPACKET_VALUE, text = "use VIDEOPACKET value")
|
||||
@EnumValue(value = DefineVideoStreamTag.DEBLOCKING_OFF, text = "off")
|
||||
@EnumValue(value = DefineVideoStreamTag.DEBLOCKING_LEVEL1, text = "Level 1 (Fast deblocking filter)")
|
||||
@@ -108,7 +119,7 @@ public class DefineVideoStreamTag extends DrawableTag implements BoundedTag, Tim
|
||||
|
||||
public boolean videoFlagsSmoothing;
|
||||
|
||||
@SWFType(BasicType.UI8)
|
||||
@SWFType(BasicType.UI8)
|
||||
@EnumValue(value = DefineVideoStreamTag.CODEC_JPEG, text = "JPEG (unused)")
|
||||
@EnumValue(value = DefineVideoStreamTag.CODEC_SORENSON_H263, text = "Sorenson H.263")
|
||||
@EnumValue(value = DefineVideoStreamTag.CODEC_SCREEN_VIDEO, text = "Screen video")
|
||||
@@ -134,24 +145,24 @@ public class DefineVideoStreamTag extends DrawableTag implements BoundedTag, Tim
|
||||
|
||||
@Internal
|
||||
private Timeline timeline;
|
||||
|
||||
|
||||
@Internal
|
||||
private Map<Integer, VideoFrameTag> frames;
|
||||
|
||||
|
||||
private static final List<SimpleMediaPlayer> players = new ArrayList<>();
|
||||
private static List<File> tempFiles = new ArrayList<>();
|
||||
|
||||
|
||||
@Internal
|
||||
private boolean renderingPaused = false;
|
||||
|
||||
public static final int CODEC_JPEG = 1;
|
||||
public static final int CODEC_JPEG = 1;
|
||||
public static final int CODEC_SORENSON_H263 = 2;
|
||||
public static final int CODEC_SCREEN_VIDEO = 3;
|
||||
public static final int CODEC_VP6 = 4;
|
||||
public static final int CODEC_VP6_ALPHA = 5;
|
||||
public static final int CODEC_SCREEN_VIDEO_V2 = 6;
|
||||
public static final int CODEC_AVC = 7; //Is this FLV only, or SWF too?
|
||||
|
||||
|
||||
/**
|
||||
* use VIDEOPACKET value
|
||||
*/
|
||||
@@ -178,24 +189,22 @@ public class DefineVideoStreamTag extends DrawableTag implements BoundedTag, Tim
|
||||
public static final int DEBLOCKING_LEVEL4 = 5;
|
||||
public static final int DEBLOCKING_RESERVED1 = 6;
|
||||
public static final int DEBLOCKING_RESERVED2 = 7;
|
||||
|
||||
|
||||
|
||||
|
||||
static {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(){
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (SimpleMediaPlayer p:players) {
|
||||
p.stop();
|
||||
}
|
||||
for (File f:tempFiles) {
|
||||
f.delete();
|
||||
}
|
||||
for (SimpleMediaPlayer p : players) {
|
||||
p.stop();
|
||||
}
|
||||
for (File f : tempFiles) {
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@@ -276,7 +285,7 @@ public class DefineVideoStreamTag extends DrawableTag implements BoundedTag, Tim
|
||||
public static boolean displayAvailable() {
|
||||
return SimpleMediaPlayer.isAvailable();
|
||||
}
|
||||
|
||||
|
||||
private void initPlayer() {
|
||||
if (mediaPlayer != null) { // && !mediaPlayer.isFinished()) {
|
||||
return;
|
||||
@@ -319,20 +328,22 @@ public class DefineVideoStreamTag extends DrawableTag implements BoundedTag, Tim
|
||||
public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked, ExportRectangle viewRect, double unzoom) {
|
||||
return transformation.toTransform().createTransformedShape(new Rectangle2D.Double(0, 0, width * SWF.unitDivisor, height * SWF.unitDivisor));
|
||||
}
|
||||
|
||||
|
||||
public synchronized void resetPlayer() {
|
||||
mediaPlayer.stop();
|
||||
mediaPlayer = null;
|
||||
if (mediaPlayer != null) {
|
||||
mediaPlayer.stop();
|
||||
mediaPlayer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void setPauseRendering(boolean value) {
|
||||
this.renderingPaused = value;
|
||||
activeFrame = null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, SerializableImage fullImage, boolean isClip, Matrix transformation, Matrix prevTransformation, Matrix absoluteTransformation, Matrix fullTransformation, ColorTransform colorTransform, double unzoom, boolean sameImage, ExportRectangle viewRect, boolean scaleStrokes, int drawMode, int blendMode) {
|
||||
|
||||
|
||||
if (renderingPaused || !SimpleMediaPlayer.isAvailable()) {
|
||||
Graphics2D g = (Graphics2D) image.getBufferedImage().getGraphics();
|
||||
Matrix mat = transformation;
|
||||
@@ -354,28 +365,27 @@ public class DefineVideoStreamTag extends DrawableTag implements BoundedTag, Tim
|
||||
if (ratio == -1) {
|
||||
ratio = 0;
|
||||
}
|
||||
|
||||
|
||||
Set<Integer> keyFrames = getFrames().keySet();
|
||||
|
||||
|
||||
int f = 0;
|
||||
for(int i = 0; i <= ratio; i++) {
|
||||
for (int i = 0; i <= ratio; i++) {
|
||||
if (keyFrames.contains(i)) {
|
||||
f = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
synchronized (DefineVideoStreamTag.class) {
|
||||
if (!(activeFrame != null && lastFrame == f))
|
||||
{
|
||||
if (!(activeFrame != null && lastFrame == f)) {
|
||||
initPlayer();
|
||||
|
||||
float oneFr = 0; //1f / (getNumFrames() + 2);
|
||||
|
||||
|
||||
float oneFr = 0; //1f / (getNumFrames() + 2);
|
||||
|
||||
synchronized (getFrameLock) {
|
||||
activeFrame = null;
|
||||
}
|
||||
mediaPlayer.setPosition(((float) f) / (getNumFrames() + 2) - (f == 0 ? 0 : oneFr / 10f));
|
||||
|
||||
}
|
||||
mediaPlayer.setPosition(((float) f) / (getNumFrames() + 2) - (f == 0 ? 0 : oneFr / 10f));
|
||||
|
||||
try {
|
||||
synchronized (getFrameLock) {
|
||||
if (activeFrame == null) {
|
||||
@@ -435,7 +445,7 @@ public class DefineVideoStreamTag extends DrawableTag implements BoundedTag, Tim
|
||||
initTimeline();
|
||||
return timeline;
|
||||
}
|
||||
|
||||
|
||||
private Map<Integer, VideoFrameTag> getFrames() {
|
||||
if (this.frames != null) {
|
||||
return this.frames;
|
||||
@@ -523,4 +533,261 @@ public class DefineVideoStreamTag extends DrawableTag implements BoundedTag, Tim
|
||||
public int getFrameCount() {
|
||||
return numFrames;
|
||||
}
|
||||
|
||||
public void replace(InputStream fis) throws IOException {
|
||||
List<FLVTAG> videoTags = new ArrayList<>();
|
||||
|
||||
FLVInputStream flvIs = new FLVInputStream(fis);
|
||||
Reference<Boolean> audioPresent = new Reference<>(false);
|
||||
Reference<Boolean> videoPresent = new Reference<>(false);
|
||||
flvIs.readHeader(audioPresent, videoPresent);
|
||||
List<FLVTAG> flvTags = flvIs.readTags();
|
||||
|
||||
for (FLVTAG tag : flvTags) {
|
||||
if (tag.tagType == FLVTAG.DATATYPE_VIDEO) {
|
||||
videoTags.add(tag);
|
||||
}
|
||||
}
|
||||
if (!videoTags.isEmpty()) {
|
||||
FLVTAG firstVideoTag = videoTags.get(0);
|
||||
VIDEODATA videoData = ((VIDEODATA) firstVideoTag.data);
|
||||
FLVInputStream dis = new FLVInputStream(new ByteArrayInputStream(videoData.videoData));
|
||||
int newWidth = 0;
|
||||
int newHeight = 0;
|
||||
switch (videoData.codecId) {
|
||||
case VIDEODATA.CODEC_SORENSON_H263:
|
||||
dis.readUB(17); //pictureStartCode
|
||||
dis.readUB(5); //version
|
||||
dis.readUB(8); //temporalReference
|
||||
int pictureSize = (int) dis.readUB(3);
|
||||
switch (pictureSize) {
|
||||
case 0:
|
||||
newWidth = (int) dis.readUB(8);
|
||||
newHeight = (int) dis.readUB(8);
|
||||
break;
|
||||
case 1:
|
||||
newWidth = (int) dis.readUB(16);
|
||||
newHeight = (int) dis.readUB(16);
|
||||
break;
|
||||
case 2:
|
||||
newWidth = 352;
|
||||
newHeight = 288;
|
||||
break;
|
||||
case 3:
|
||||
newWidth = 176;
|
||||
newHeight = 144;
|
||||
break;
|
||||
case 4:
|
||||
newWidth = 128;
|
||||
newHeight = 96;
|
||||
break;
|
||||
case 5:
|
||||
newWidth = 320;
|
||||
newHeight = 240;
|
||||
break;
|
||||
case 6:
|
||||
newWidth = 160;
|
||||
newHeight = 120;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case VIDEODATA.CODEC_SCREEN_VIDEO:
|
||||
case VIDEODATA.CODEC_SCREEN_VIDEO_V2:
|
||||
dis.readUB(4); //blockWidth
|
||||
newWidth = (int) dis.readUB(12);
|
||||
dis.readUB(4); //blockHeight
|
||||
newHeight = (int) dis.readUB(12);
|
||||
break;
|
||||
case VIDEODATA.CODEC_VP6:
|
||||
case VIDEODATA.CODEC_VP6_ALPHA:
|
||||
int horizontalAdjustment = (int) dis.readUB(4);
|
||||
int verticalAdjustment = (int) dis.readUB(4);
|
||||
if (videoData.codecId == VIDEODATA.CODEC_VP6_ALPHA) {
|
||||
dis.readUI24(); //offsetToAlpha
|
||||
}
|
||||
|
||||
int frameMode = (int) dis.readUB(1); //frameMode
|
||||
|
||||
dis.readUB(6); //qp
|
||||
int multiStream = (int) dis.readUB(1); //marker
|
||||
if (frameMode == 0) {
|
||||
int vp3VersionNo = (int) dis.readUB(5);
|
||||
int vpProfile = (int) dis.readUB(2);
|
||||
dis.readUB(1); //interlace
|
||||
if (multiStream == 1 || vpProfile == 0) {
|
||||
dis.readUI16(); //offset
|
||||
}
|
||||
int dim_y = dis.readUI8();
|
||||
int dim_x = dis.readUI8();
|
||||
//dis.readUI8(); //render_y
|
||||
//dis.readUI8(); //render_x
|
||||
newWidth = 16 * dim_x - horizontalAdjustment;
|
||||
newHeight = 16 * dim_y - verticalAdjustment;
|
||||
}
|
||||
break;
|
||||
case VIDEODATA.CODEC_AVC:
|
||||
throw new IOException("AVC codec is not supported for import");
|
||||
case VIDEODATA.CODEC_JPEG:
|
||||
throw new IOException("JPEG codec is not supported for import");
|
||||
}
|
||||
if (newWidth <= 0 || newHeight <= 0) {
|
||||
throw new IOException("Invalid dimension");
|
||||
}
|
||||
this.codecID = videoData.codecId;
|
||||
this.width = newWidth;
|
||||
this.height = newHeight;
|
||||
this.videoFlagsDeblocking = DefineVideoStreamTag.DEBLOCKING_OFF;
|
||||
this.videoFlagsSmoothing = true;
|
||||
this.numFrames = videoTags.size();
|
||||
setPauseRendering(true);
|
||||
|
||||
videoTags.sort(new Comparator<FLVTAG>() {
|
||||
@Override
|
||||
public int compare(FLVTAG o1, FLVTAG o2) {
|
||||
return Long.compare(o1.timeStamp, o2.tagType);
|
||||
}
|
||||
});
|
||||
|
||||
//remove old VideoFrame tags
|
||||
Map<Integer, VideoFrameTag> frames = new HashMap<>();
|
||||
SWF.populateVideoFrames(characterID, swf.getTags(), frames);
|
||||
Timelined timelined = null;
|
||||
for (VideoFrameTag t : frames.values()) {
|
||||
t.getTimelined().removeTag(t);
|
||||
timelined = t.getTimelined();
|
||||
}
|
||||
timelined.resetTimeline();
|
||||
|
||||
int startFrame = 0;
|
||||
int placeDepth = -1;
|
||||
for (Tag t : timelined.getTags()) {
|
||||
if (t instanceof ShowFrameTag) {
|
||||
startFrame++;
|
||||
}
|
||||
if (t instanceof PlaceObjectTypeTag) {
|
||||
PlaceObjectTypeTag pt = (PlaceObjectTypeTag) t;
|
||||
if (pt.getCharacterId() == characterID) {
|
||||
placeDepth = pt.getDepth();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int importLastFrame = -1;
|
||||
if (timelined != null) {
|
||||
VideoFrameTag lastVideoFrame = null;
|
||||
for (FLVTAG ftag : videoTags) {
|
||||
videoData = ((VIDEODATA) ftag.data);
|
||||
if (videoData.codecId == VIDEODATA.CODEC_VP6 || videoData.codecId == VIDEODATA.CODEC_VP6_ALPHA) {
|
||||
int horizontalAdjustment = (int) dis.readUB(4);
|
||||
int verticalAdjustment = (int) dis.readUB(4);
|
||||
if (videoData.codecId == VIDEODATA.CODEC_VP6_ALPHA) {
|
||||
dis.readUI24(); //offsetToAlpha
|
||||
}
|
||||
|
||||
int frameMode = (int) dis.readUB(1); //frameMode
|
||||
|
||||
dis.readUB(6); //qp
|
||||
int multiStream = (int) dis.readUB(1); //marker
|
||||
if (frameMode == 1) {
|
||||
if (multiStream == 1) { // || version2 == 0) { ???
|
||||
dis.readUI16(); //buff2Offset
|
||||
}
|
||||
dis.readUB(1); //refreshGoldenFrame
|
||||
int useLoopFilter = (int) dis.readUB(1); //useLoopFilter
|
||||
if (useLoopFilter == 1) {
|
||||
int loopFilterSelector = (int) dis.readUB(1);
|
||||
if (loopFilterSelector == 0) {
|
||||
videoFlagsDeblocking = DefineVideoStreamTag.DEBLOCKING_LEVEL1;
|
||||
} else if (loopFilterSelector == 1) {
|
||||
videoFlagsDeblocking = DefineVideoStreamTag.DEBLOCKING_LEVEL4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int idealFrame = startFrame + (int) Math.floor(swf.frameRate * ftag.timeStamp / 1000.0);
|
||||
if (idealFrame == importLastFrame) {
|
||||
idealFrame++;
|
||||
}
|
||||
int swfFrameNum = -1;
|
||||
ReadOnlyTagList tagList = timelined.getTags();
|
||||
int p = 0;
|
||||
boolean found = false;
|
||||
for (; p < tagList.size(); p++) {
|
||||
Tag t = tagList.get(p);
|
||||
if (t instanceof ShowFrameTag) {
|
||||
swfFrameNum++;
|
||||
if (swfFrameNum == idealFrame) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//add frames when necessary
|
||||
if (!found) {
|
||||
p--;
|
||||
swfFrameNum++;
|
||||
for (; swfFrameNum <= idealFrame; swfFrameNum++) {
|
||||
PlaceObject2Tag placeObject = new PlaceObject2Tag(swf);
|
||||
placeObject.setTimelined(timelined);
|
||||
placeObject.depth = placeDepth;
|
||||
placeObject.placeFlagMove = true;
|
||||
placeObject.placeFlagHasRatio = true;
|
||||
placeObject.ratio = swfFrameNum - startFrame;
|
||||
timelined.addTag(placeObject);
|
||||
p++;
|
||||
ShowFrameTag sft = new ShowFrameTag(swf);
|
||||
sft.setTimelined(timelined);
|
||||
timelined.addTag(sft);
|
||||
p++;
|
||||
}
|
||||
swfFrameNum--;
|
||||
}
|
||||
VideoFrameTag videoFrameTag = new VideoFrameTag(swf);
|
||||
videoFrameTag.streamID = characterID;
|
||||
videoFrameTag.frameNum = swfFrameNum - startFrame;
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
VIDEODATA vdata = (VIDEODATA) ftag.data;
|
||||
switch (codecID) {
|
||||
case DefineVideoStreamTag.CODEC_VP6:
|
||||
case DefineVideoStreamTag.CODEC_VP6_ALPHA:
|
||||
baos.write(Arrays.copyOfRange(vdata.videoData, 1 /*strip adjustment*/, vdata.videoData.length));
|
||||
break;
|
||||
default:
|
||||
baos.write(vdata.videoData);
|
||||
break;
|
||||
}
|
||||
videoFrameTag.videoData = new ByteArrayRange(baos.toByteArray());
|
||||
timelined.addTag(p, videoFrameTag);
|
||||
videoFrameTag.setTimelined(timelined);
|
||||
importLastFrame = idealFrame;
|
||||
}
|
||||
}
|
||||
|
||||
List<Tag> tagsToRemove = new ArrayList<>();
|
||||
for (Tag t : timelined.getTags()) {
|
||||
if (t instanceof PlaceObjectTypeTag) {
|
||||
PlaceObjectTypeTag pt = (PlaceObjectTypeTag) t;
|
||||
if (pt.getDepth() == placeDepth) {
|
||||
int ratio = pt.getRatio();
|
||||
if (ratio > importLastFrame - startFrame) {
|
||||
tagsToRemove.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Tag t : tagsToRemove) {
|
||||
timelined.removeTag(t);
|
||||
}
|
||||
|
||||
setModified(true);
|
||||
timelined.resetTimeline();
|
||||
resetTimeline();
|
||||
resetPlayer();
|
||||
setPauseRendering(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user