diff --git a/trunk/src/com/jpexs/decompiler/flash/SWF.java b/trunk/src/com/jpexs/decompiler/flash/SWF.java index 8e66a4d2a..fc3402e47 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWF.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWF.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash; import SevenZip.Compression.LZMA.Encoder; import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.CopyOutputStream; import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionGraphSource; @@ -805,6 +806,102 @@ public class SWF { } } + public byte[] exportMovie(DefineVideoStreamTag videoStream) throws IOException { + HashMap frames = new HashMap(); + List os = new ArrayList(this.tags); + populateVideoFrames(videoStream.characterID, os, frames); + + + + long fileSize = 0; + + //double ms = 1000.0f / ((float) frameRate); + + ByteArrayOutputStream fos = new ByteArrayOutputStream(); + fos = new ByteArrayOutputStream(); + //CopyOutputStream cos = new CopyOutputStream(fos, new FileInputStream("f:\\trunk\\testdata\\xfl\\xfl\\_obj\\streamvideo 7.flv")); + OutputStream tos = fos; + FLVOutputStream flv = new FLVOutputStream(tos); + flv.writeHeader(false, true); + //flv.writeTag(new FLVTAG(0, SCRIPTDATA.onMetaData(ms * frames.size() / 1000.0, videoStream.width, videoStream.height, 0, frameRate, videoStream.codecID, 0, 0, false, 0, fileSize))); + int horizontalAdjustment = 0; + int verticalAdjustment = 0; + for (int i = 0; i < frames.size(); i++) { + VideoFrameTag tag = frames.get(i); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + int frameType = 1; + + if ((videoStream.codecID == DefineVideoStreamTag.CODEC_VP6) + || (videoStream.codecID == DefineVideoStreamTag.CODEC_VP6_ALPHA)) { + SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(tag.videoData), SWF.DEFAULT_VERSION); + if (videoStream.codecID == DefineVideoStreamTag.CODEC_VP6_ALPHA) { + sis.readUI24(); //offsetToAlpha + } + int frameMode = (int) sis.readUB(1); + + if (frameMode == 0) { + frameType = 1; //intra + } else { + frameType = 2; //inter + } + int qp = (int) sis.readUB(6); + int marker = (int) sis.readUB(1); + if (frameMode == 0) { + int version = (int) sis.readUB(5); + int version2 = (int) sis.readUB(2); + boolean interlace = sis.readUB(1) == 1;//interlace + if (marker == 1 || version2 == 0) { + sis.readUI16();//offset + } + int dim_y = sis.readUI8(); + int dim_x = sis.readUI8(); + int render_y = sis.readUI8(); + int render_x = sis.readUI8(); + horizontalAdjustment = (int) (dim_x * Math.ceil(((double) videoStream.width) / (double) dim_x)) - videoStream.width; + verticalAdjustment = (int) (dim_y * Math.ceil(((double) videoStream.height) / (double) dim_y)) - videoStream.height; + + } + + SWFOutputStream sos = new SWFOutputStream(baos, SWF.DEFAULT_VERSION); + sos.writeUB(4, horizontalAdjustment); + sos.writeUB(4, verticalAdjustment); + } + if (videoStream.codecID == DefineVideoStreamTag.CODEC_SORENSON_H263) { + SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(tag.videoData), SWF.DEFAULT_VERSION); + sis.readUB(17);//pictureStartCode + sis.readUB(5); //version + sis.readUB(8); //temporalReference + int pictureSize = (int) sis.readUB(3); //pictureSize + if (pictureSize == 0) { + sis.readUB(8); //customWidth + sis.readUB(8); //customHeight + } + if (pictureSize == 1) { + sis.readUB(16); //customWidth + sis.readUB(16); //customHeight + } + int pictureType = (int) sis.readUB(2); + switch (pictureType) { + case 0: //intra + frameType = 1; //keyframe + break; + case 1://inter + frameType = 2; + break; + case 2: //disposable + frameType = 3; + break; + } + } + + baos.write(tag.videoData); + flv.writeTag(new FLVTAG((int) Math.floor(i * 1000.0f / ((float) frameRate)), new VIDEODATA(frameType, videoStream.codecID, baos.toByteArray()))); + } + fileSize = fos.toByteArray().length; + return fos.toByteArray(); + } + public void exportMovies(String outdir, List tags) throws IOException { if (tags.isEmpty()) { return; @@ -812,62 +909,12 @@ public class SWF { if (!(new File(outdir)).exists()) { (new File(outdir)).mkdirs(); } - List os = new ArrayList(this.tags); for (Tag t : tags) { if (t instanceof DefineVideoStreamTag) { DefineVideoStreamTag videoStream = (DefineVideoStreamTag) t; - HashMap frames = new HashMap(); - populateVideoFrames(videoStream.characterID, os, frames); - - FileOutputStream fos = null; - try { - fos = new FileOutputStream(outdir + File.separator + ((DefineVideoStreamTag) t).characterID + ".flv"); - FLVOutputStream flv = new FLVOutputStream(fos); - flv.writeHeader(false, true); - int ms = (int) (1000.0f / ((float) frameRate)); - for (int i = 0; i < frames.size(); i++) { - VideoFrameTag tag = frames.get(i); - int frameType = 0; - if (videoStream.codecID == 2) { //H263 - SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(tag.videoData), SWF.DEFAULT_VERSION); - sis.readUB(17);//pictureStartCode - sis.readUB(5); //version - sis.readUB(8); //temporalReference - int pictureSize = (int) sis.readUB(3); //pictureSize - if (pictureSize == 0) { - sis.readUB(8); //customWidth - sis.readUB(8); //customHeight - } - if (pictureSize == 1) { - sis.readUB(16); //customWidth - sis.readUB(16); //customHeight - } - int pictureType = (int) sis.readUB(2); - switch (pictureType) { - case 0: //intra - frameType = 1; //keyframe - break; - case 1://inter - frameType = 2; - break; - case 2: //disposable - frameType = 3; - break; - } - } - flv.writeTag(new FLVTAG(i * ms, new VIDEODATA(frameType, videoStream.codecID, tag.videoData))); - } - - - } finally { - if (fos != null) { - try { - fos.close(); - } catch (Exception ex) { - //ignore - } - } - } + FileOutputStream fos = new FileOutputStream(outdir + File.separator + ((DefineVideoStreamTag) t).characterID + ".flv"); + fos.write(exportMovie(videoStream)); + fos.close(); } } } diff --git a/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java b/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java index 99d14a9ac..d06b29fe1 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -252,6 +252,10 @@ public class SWFInputStream extends InputStream { return readEx() + (readEx() << 8); } + public int readUI24() throws IOException { + return readEx() + (readEx() << 8) + (readEx() << 16); + } + /** * Reads one SI32 (Signed 32bit integer) value from the stream * diff --git a/trunk/src/com/jpexs/decompiler/flash/flv/FLVOutputStream.java b/trunk/src/com/jpexs/decompiler/flash/flv/FLVOutputStream.java index 2d1fa99f2..525ca6d58 100644 --- a/trunk/src/com/jpexs/decompiler/flash/flv/FLVOutputStream.java +++ b/trunk/src/com/jpexs/decompiler/flash/flv/FLVOutputStream.java @@ -2,6 +2,7 @@ package com.jpexs.decompiler.flash.flv; import java.io.IOException; import java.io.OutputStream; +import java.util.List; /** * @@ -129,9 +130,116 @@ public class FLVOutputStream extends OutputStream { writeUI24(tag.timeStamp & 0xffffff); writeUI8((int) ((tag.timeStamp >> 24) & 0xff)); writeUI24(0); - write(data); + write(data); //codecId 4, frameType 1 long posAfter = getPos(); long size = posAfter - posBefore; writeUI32(size); } + + public void writeSCRIPTDATASTRING(String s) throws IOException { + int len = s.getBytes("UTF-8").length; + writeUI16(len); + write(s.getBytes("UTF-8")); + } + + public void writeSCRIPTDATALONGSTRING(String s) throws IOException { + int len = s.getBytes("UTF-8").length; + writeUI32(len); + write(s.getBytes("UTF-8")); + } + + private void writeLong(long value) throws IOException { + byte writeBuffer[] = new byte[8]; + writeBuffer[3] = (byte) (value >>> 56); + writeBuffer[2] = (byte) (value >>> 48); + writeBuffer[1] = (byte) (value >>> 40); + writeBuffer[0] = (byte) (value >>> 32); + writeBuffer[7] = (byte) (value >>> 24); + writeBuffer[6] = (byte) (value >>> 16); + writeBuffer[5] = (byte) (value >>> 8); + writeBuffer[4] = (byte) (value); + write(writeBuffer); + } + + public void writeDOUBLE(double value) throws IOException { + writeLong(Double.doubleToLongBits(value)); + } + + public void writeSCRIPTDATAOBJECT(SCRIPTDATAOBJECT o) throws IOException { + writeSCRIPTDATASTRING(o.objectName); + writeSCRIPTDATAVALUE(o.objectData); + } + + public void writeSCRIPTDATAVARIABLE(SCRIPTDATAVARIABLE v) throws IOException { + writeSCRIPTDATASTRING(v.variableName); + writeSCRIPTDATAVALUE(v.variableData); + } + + public void writeSCRIPTDATAVALUE(SCRIPTDATAVALUE v) throws IOException { + writeUI8(v.type); + switch (v.type) { + case 0: + writeDOUBLE((double) (Double) v.value); + break; + case 1: + writeUI8((boolean) (Boolean) v.value ? 1 : 0); + break; + case 2: + writeSCRIPTDATASTRING((String) v.value); + break; + case 3: + List objects = (List) v.value; + for (SCRIPTDATAOBJECT o : objects) { + writeSCRIPTDATAOBJECT(o); + } + writeUI24(9);//SCRIPTDATAOBJECTEND + break; + case 4: + writeSCRIPTDATASTRING((String) v.value); + break; + case 5: + //null + break; + case 6: + //undefined + break; + case 7: + writeUI16((int) (Integer) v.value); + break; + case 8: + List variables = (List) v.value; + writeUI32(variables.size()); + for (SCRIPTDATAVARIABLE var : variables) { + writeSCRIPTDATAVARIABLE(var); + } + writeUI24(9);//SCRIPTDATAVARIABLEEND + break; + case 9: + //reserved + break; + case 10: + List stvariables = (List) v.value; + writeUI32(stvariables.size()); + for (SCRIPTDATAVARIABLE var : stvariables) { + writeSCRIPTDATAVARIABLE(var); + } + break; + case 11: + writeSCRIPTDATADATE((SCRIPTDATADATE) v.value); + break; + case 12: + writeSCRIPTDATALONGSTRING((String) v.value); + break; + + } + } + + public void writeSI16(int value) throws IOException { + writeUI16(value); + } + + public void writeSCRIPTDATADATE(SCRIPTDATADATE d) throws IOException { + writeDOUBLE(d.dateTime); + writeSI16(d.localDateTimeOffset); + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/flv/FLVTAG.java b/trunk/src/com/jpexs/decompiler/flash/flv/FLVTAG.java index fb3809cd8..5231ff843 100644 --- a/trunk/src/com/jpexs/decompiler/flash/flv/FLVTAG.java +++ b/trunk/src/com/jpexs/decompiler/flash/flv/FLVTAG.java @@ -13,6 +13,11 @@ public class FLVTAG { public static final int DATATYPE_AUDIO = 8; public static final int DATATYPE_SCRIPT_DATA = 18; + public FLVTAG(long timeStamp, SCRIPTDATA data) { + tagType = DATATYPE_SCRIPT_DATA; + this.data = data; + } + public FLVTAG(long timeStamp, VIDEODATA data) { this.tagType = DATATYPE_VIDEO; this.timeStamp = timeStamp; diff --git a/trunk/src/com/jpexs/decompiler/flash/flv/SCRIPTDATA.java b/trunk/src/com/jpexs/decompiler/flash/flv/SCRIPTDATA.java new file mode 100644 index 000000000..f6a51f537 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/flv/SCRIPTDATA.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.flv; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class SCRIPTDATA extends DATA { + + public List data; + + public SCRIPTDATA(List data) { + this.data = data; + } + + @Override + public byte[] getBytes() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + FLVOutputStream fos = null; + try { + fos = new FLVOutputStream(baos); + for (SCRIPTDATAOBJECT d : data) { + fos.writeSCRIPTDATAOBJECT(d); + } + fos.writeUI24(9); //SCRIPTDATAOBJECTEND + } catch (IOException ex) { + Logger.getLogger(SCRIPTDATA.class.getName()).log(Level.SEVERE, "i/o error", ex); + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException ex) { + //ignore + } + } + } + return baos.toByteArray(); + } + + public static SCRIPTDATA onMetaData(double duration, double width, double height, double videodatarate, double framerate, double videocodecid, double audiosamplerate, double audiosamplesize, boolean stereo, double audiocodecid, double filesize) { + List list = new ArrayList(); + List values = new ArrayList(); + values.add(new SCRIPTDATAVARIABLE("duration", new SCRIPTDATAVALUE(duration))); + values.add(new SCRIPTDATAVARIABLE("width", new SCRIPTDATAVALUE(width))); + values.add(new SCRIPTDATAVARIABLE("height", new SCRIPTDATAVALUE(height))); + values.add(new SCRIPTDATAVARIABLE("videodatarate", new SCRIPTDATAVALUE(videodatarate))); + values.add(new SCRIPTDATAVARIABLE("framerate", new SCRIPTDATAVALUE(framerate))); + values.add(new SCRIPTDATAVARIABLE("videocodecid", new SCRIPTDATAVALUE(videocodecid))); + values.add(new SCRIPTDATAVARIABLE("audiosamplerate", new SCRIPTDATAVALUE(audiosamplerate))); + values.add(new SCRIPTDATAVARIABLE("audiosamplesize", new SCRIPTDATAVALUE(audiosamplesize))); + values.add(new SCRIPTDATAVARIABLE("stereo", new SCRIPTDATAVALUE(stereo))); + values.add(new SCRIPTDATAVARIABLE("audiocodecid", new SCRIPTDATAVALUE(audiocodecid))); + values.add(new SCRIPTDATAVARIABLE("filesize", new SCRIPTDATAVALUE(filesize))); + SCRIPTDATAVALUE valuesList = new SCRIPTDATAVALUE(8, values); + SCRIPTDATAOBJECT metaData = new SCRIPTDATAOBJECT("onMetaData", valuesList); + list.add(metaData); + SCRIPTDATA ret = new SCRIPTDATA(list); + return ret; + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/flv/SCRIPTDATADATE.java b/trunk/src/com/jpexs/decompiler/flash/flv/SCRIPTDATADATE.java new file mode 100644 index 000000000..5e8a3af54 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/flv/SCRIPTDATADATE.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.flv; + +/** + * + * @author JPEXS + */ +public class SCRIPTDATADATE { + + public double dateTime; + public int localDateTimeOffset; + + public SCRIPTDATADATE(double dateTime, int localDateTimeOffset) { + this.dateTime = dateTime; + this.localDateTimeOffset = localDateTimeOffset; + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/flv/SCRIPTDATAOBJECT.java b/trunk/src/com/jpexs/decompiler/flash/flv/SCRIPTDATAOBJECT.java new file mode 100644 index 000000000..472442dd5 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/flv/SCRIPTDATAOBJECT.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.flv; + +/** + * + * @author JPEXS + */ +public class SCRIPTDATAOBJECT { + + public String objectName; + public SCRIPTDATAVALUE objectData; + + public SCRIPTDATAOBJECT(String objectName, SCRIPTDATAVALUE objectData) { + this.objectName = objectName; + this.objectData = objectData; + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/flv/SCRIPTDATAVALUE.java b/trunk/src/com/jpexs/decompiler/flash/flv/SCRIPTDATAVALUE.java new file mode 100644 index 000000000..eb5ece94f --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/flv/SCRIPTDATAVALUE.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.flv; + +/** + * + * @author JPEXS + */ +public class SCRIPTDATAVALUE { + + public int type; + public Object value; + + public SCRIPTDATAVALUE(int type, Object value) { + this.type = type; + this.value = value; + } + + public SCRIPTDATAVALUE(boolean b) { + this.value = (Boolean) b; + type = 1; + } + + public SCRIPTDATAVALUE(double d) { + this.value = (Double) d; + type = 0; + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/flv/SCRIPTDATAVARIABLE.java b/trunk/src/com/jpexs/decompiler/flash/flv/SCRIPTDATAVARIABLE.java new file mode 100644 index 000000000..031832fbc --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/flv/SCRIPTDATAVARIABLE.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.flv; + +/** + * + * @author JPEXS + */ +public class SCRIPTDATAVARIABLE { + + public String variableName; + public SCRIPTDATAVALUE variableData; + + public SCRIPTDATAVARIABLE(String variableName, SCRIPTDATAVALUE variableData) { + this.variableName = variableName; + this.variableData = variableData; + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java index 3f7c0e1c2..4ced9221f 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineVideoStreamTag.java @@ -38,6 +38,10 @@ public class DefineVideoStreamTag extends CharacterTag { public int videoFlagsDeblocking; public boolean videoFlagsSmoothing; public int codecID; + 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; @Override public int getCharacterID() { diff --git a/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index 83dc484d6..a432d64c9 100644 --- a/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -30,6 +30,7 @@ import com.jpexs.decompiler.flash.tags.DefineSoundTag; import com.jpexs.decompiler.flash.tags.DefineSpriteTag; import com.jpexs.decompiler.flash.tags.DefineText2Tag; import com.jpexs.decompiler.flash.tags.DefineTextTag; +import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag; import com.jpexs.decompiler.flash.tags.DoActionTag; import com.jpexs.decompiler.flash.tags.DoInitActionTag; import com.jpexs.decompiler.flash.tags.ExportAssetsTag; @@ -366,6 +367,9 @@ public class XFLConverter { public static String convertMatrix(MATRIX m) { String ret = ""; + if (m == null) { + m = new MATRIX(); + } ret += ""; + ret += ""; + ret += convertMatrix(matrix); + ret += ""; + ret += ""; + ret += ""; + ret += ""; + ret += ""; + return ret; + } + private static String convertFrames(String initActionScript, String prevStr, String afterStr, List oneInstanceShapes, List tags, HashMap characters, int depth) { String ret = ""; prevStr += ""; @@ -1460,7 +1515,7 @@ public class XFLConverter { String lastActionScript = ""; String frameName = null; boolean isAnchor = false; - + DefineVideoStreamTag video = null; for (Tag t : tags) { if (t instanceof PlaceObjectTypeTag) { PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; @@ -1476,6 +1531,11 @@ public class XFLConverter { elements += convertShape(characters, po.getMatrix(), (ShapeTag) ch); } else if (ch instanceof TextTag) { elements += convertText(tags, (TextTag) ch, po.getMatrix(), po.getFilters()); + } else if (ch instanceof DefineVideoStreamTag) { + if (ch != video) { + elements += convertVideoInstance(po.getMatrix(), (DefineVideoStreamTag) ch); + } + video = (DefineVideoStreamTag) ch; } else { elements += convertSymbolInstance(po.getName(), po.getMatrix(), po.getColorTransform(), po.getColorTransformWithAlpha(), po.cacheAsBitmap(), po.getBlendMode(), po.getFilters(), po.isVisible(), po.getBackgroundColor(), characters.get(characterId), characters, tags); } @@ -1603,7 +1663,7 @@ public class XFLConverter { Stack parentLayers = new Stack(); int index = 0; if ((layerCount == 0) && (!initActionScript.equals(""))) { - ret += ""; + ret += ""; ret += ""; ret += ""; @@ -1624,7 +1684,7 @@ public class XFLConverter { parentLayers.push(index); } - ret += "