{"id":167,"date":"2010-05-08T03:01:22","date_gmt":"2010-05-08T06:01:22","guid":{"rendered":"http:\/\/wahlers.com.br\/claus\/blog\/?p=167"},"modified":"2010-09-30T15:48:30","modified_gmt":"2010-09-30T18:48:30","slug":"timeline-reconstruction-with-as3swf","status":"publish","type":"post","link":"http:\/\/wahlers.com.br\/claus\/blog\/timeline-reconstruction-with-as3swf\/","title":{"rendered":"SWF Timeline Reconstruction with as3swf"},"content":{"rendered":"<p>In case you havent heard of it yet, <a href=\"http:\/\/github.com\/claus\/as3swf\">as3swf<\/a> is an ActionScript 3 library to parse and publish SWF files. It does that rather well by now, providing full roundtrip publishing, plus some neat extra features like shape export to AS3 Drawing API, AS3 GraphicsObjects, <a href=\"http:\/\/wiki.github.com\/claus\/as3swf\/shape-export-to-fxg\">FXG<\/a>, and <a href=\"http:\/\/wiki.github.com\/claus\/as3swf\/shape-export-to-objective-c\">Objective-C<\/a>.<\/p>\n<p>Whenever i find some free time i&#8217;m working on adding new, useful features. One feature of as3swf, that i haven&#8217;t talked about much yet but is implemented for quite a while already, is the reconstruction of timelines as you know them from Adobe&#8217;s Flash IDEs.<\/p>\n<p>In the first place, timelines in as3swf help you to export and render layered animations. Having a long list of parsed SWF tags won&#8217;t help much if you want to export or render frame X, as the Flash Player would display it.<\/p>\n<p><!--more--><\/p>\n<p><strong>Flash Player Display List<\/strong><\/p>\n<p>When executing a SWF, the Flash Player reads sequentially through all its tags, from start to end, and builds and maintains an internal display list along the way. This display list is manipulated by <code>PlaceObject<\/code> and <code>RemoveObject<\/code> tags, and rendered every time the Flash Player encounters a <code>ShowFrame<\/code> tag. Characters placed on the display list by <code>PlaceObject<\/code> tags stay on the display list until they are removed by a <code>RemoveObject<\/code> tag. <code>PlaceObject<\/code> tags are also used to manipulate a previously placed character (tweens).<\/p>\n<p>In order to figure out which characters are displayed how and at which depths in any given frame, as3swf simulates the Flash Player behavior and builds its own display list structures while parsing the tags.<\/p>\n<p>as3swf&#8217;s <code>SWF<\/code> (root) and <code>TagDefineSprite<\/code> (movieclips) classes each have a <code>timeline<\/code> property, containing an instance of the <code>SWFTimeline<\/code> class. Other than the <code>tags<\/code> itself, this class contains the following goodies:<\/p>\n<ul>\n<li><code>dictionary<\/code> &#8211; Contains references to all characters that may be placed on the display list. The dictionary&#8217;s key is the character ID as defined by the definition tag, the value is the index of the definition tag.<\/li>\n<li><code>scenes<\/code> &#8211; Lists all scenes with their names and frame numbers.<\/li>\n<li><code>frames<\/code> &#8211; Lists all frames. For each frame, you can access the contained characters and their depths, what tag placed the character on the display list, what tag modified its transformation\/color matrices if any (for tweens) and whether this frame is a key frame or not.<\/li>\n<li><code>layers<\/code> &#8211; Lists all layers. Each layer contains an array of active frames.<\/li>\n<li><code>soundStream<\/code> &#8211; If present, contains this timeline&#8217;s sound stream complete with raw MP3 data, start frame, length, number of samples etc.<\/li>\n<\/ul>\n<p><strong>Example<\/strong><\/p>\n<p>Consider the following very simple FLA. It has two layers, one containing a motion tween, the other a static on-stage shape starting at frame 5:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/wahlers.com.br\/claus\/blog\/wp-content\/uploads\/MotionTweenFLA.png\" alt=\"\" \/><\/p>\n<p>Published to SWF:<\/p>\n<p>[SWF]http:\/\/wahlers.com.br\/claus\/blog\/wp-content\/uploads\/MotionTween.swf, 180, 160[\/SWF]<\/p>\n<p>Parsed by as3swf, we get these timeline infos (get the <a href=\"http:\/\/wahlers.com.br\/claus\/blog\/wp-content\/uploads\/MotionTween.txt\">full trace dump here<\/a>):<\/p>\n<pre><code>  Scenes:\r\n    Name: Scene 1, Frame: 0\r\n  Frames:\r\n    [0] Start: 0, Length: 9\r\n      Depth: 1 (Layer 0), CharacterId: 2, PlacedAt: 5, IsKeyframe\r\n    [1] Start: 9, Length: 2\r\n      Depth: 1 (Layer 0), CharacterId: 2, PlacedAt: 5, LastModifiedAt: 9\r\n    [2] Start: 11, Length: 2\r\n      Depth: 1 (Layer 0), CharacterId: 2, PlacedAt: 5, LastModifiedAt: 11\r\n    [3] Start: 13, Length: 2\r\n      Depth: 1 (Layer 0), CharacterId: 2, PlacedAt: 5, LastModifiedAt: 13\r\n    [4] Start: 15, Length: 2\r\n      Depth: 1 (Layer 0), CharacterId: 2, PlacedAt: 5, LastModifiedAt: 15\r\n    [5] Start: 17, Length: 4\r\n      Depth: 1 (Layer 0), CharacterId: 2, PlacedAt: 5, LastModifiedAt: 17\r\n      Depth: 3 (Layer 1), CharacterId: 3, PlacedAt: 19, IsKeyframe\r\n    [6] Start: 21, Length: 2\r\n      Depth: 1 (Layer 0), CharacterId: 2, PlacedAt: 5, LastModifiedAt: 21\r\n      Depth: 3 (Layer 1), CharacterId: 3, PlacedAt: 19\r\n    [7] Start: 23, Length: 2\r\n      Depth: 1 (Layer 0), CharacterId: 2, PlacedAt: 5, LastModifiedAt: 23\r\n      Depth: 3 (Layer 1), CharacterId: 3, PlacedAt: 19\r\n    [8] Start: 25, Length: 2\r\n      Depth: 1 (Layer 0), CharacterId: 2, PlacedAt: 5, LastModifiedAt: 25\r\n      Depth: 3 (Layer 1), CharacterId: 3, PlacedAt: 19\r\n    [9] Start: 27, Length: 2\r\n      Depth: 1 (Layer 0), CharacterId: 2, PlacedAt: 5, LastModifiedAt: 27\r\n      Depth: 3 (Layer 1), CharacterId: 3, PlacedAt: 19\r\n  Layers:\r\n    [0] Frames 0, 1, 2, 3, 4, 5, 6, 7, 8, 9\r\n    [1] Frames 5, 6, 7, 8, 9<\/code><\/pre>\n<p>Lets take a closer look at frame 6:<\/p>\n<pre><code>  [5] Start: 17, Length: 4\r\n    Depth: 1 (Layer 0), CharacterId: 2, PlacedAt: 5, LastModifiedAt: 17\r\n    Depth: 3 (Layer 1), CharacterId: 3, PlacedAt: 19, IsKeyframe<\/code><\/pre>\n<p>This tells us that this frame:<\/p>\n<ul>\n<li>displays character ID 2 (the red square movieclip) at depth 1. This character was originally placed on the display list by tag index 5 and was modified by tag index 17 (this character is tweened).<\/li>\n<li>displays character ID 3 (the blue square shape) at depth 3. This character was placed on the display list by tag index 19. As the character was placed in this very frame, this is a key frame.<\/li>\n<li>starts at tag index 17 and consumes 4 tags total:\n<pre><code><span style=\"color:blue\">17: <\/span>[26:PlaceObject2] Depth: 1, Matrix: (1,1,0,0,1400,400)\r\n<span style=\"color:blue\">18: <\/span>[83:DefineShape4] ID: 3, EdgeBounds: (2200,3200,1800,2800)\r\n      FillStyles:\r\n        [1] [SWFFillStyle] Type: 0 (solid), Color: FF0000FF\r\n      LineStyles:\r\n        [1] [SWFLineStyle2] Width: 200, Color: FF000000\r\n      ShapeRecords:\r\n        [SWFShapeRecordStyleChange] MoveTo: 3200,1800, FillStyle1: 1, LineStyle: 1\r\n        [SWFShapeRecordStraightEdge] Vertical: 1000\r\n        [SWFShapeRecordStraightEdge] Horizontal: -1000\r\n        [SWFShapeRecordStraightEdge] Vertical: -1000\r\n        [SWFShapeRecordStraightEdge] Horizontal: 1000\r\n        [SWFShapeRecordEnd]\r\n<span style=\"color:blue\">19: <\/span>[26:PlaceObject2] Depth: 3, CharacterID: 3, Matrix: (1,1,0,0,0,0)\r\n<span style=\"color:blue\">20: <\/span>[01:ShowFrame]<\/code><\/pre>\n<\/li>\n<\/ul>\n<p>As you can see, this info is a quite exact reconstruction of the original FLA&#8217;s timeline, and can be used to rebuild the original FLA (XFL, rather), to publish SWFs to run natively on alternative runtimes and platforms (HTML5, iPhone OS), or as a very first step to creating a web based version of the Flash IDE.<\/p>\n<p>Happy hacking!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In case you havent heard of it yet, as3swf is an ActionScript 3 library to parse and publish SWF files. It does that rather well by now, providing full roundtrip publishing, plus some neat extra features like shape export to &hellip; <a href=\"http:\/\/wahlers.com.br\/claus\/blog\/timeline-reconstruction-with-as3swf\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,12,3],"tags":[],"class_list":["post-167","post","type-post","status-publish","format-standard","hentry","category-flash","category-swf","category-webdev"],"_links":{"self":[{"href":"http:\/\/wahlers.com.br\/claus\/blog\/wp-json\/wp\/v2\/posts\/167","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/wahlers.com.br\/claus\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/wahlers.com.br\/claus\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/wahlers.com.br\/claus\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/wahlers.com.br\/claus\/blog\/wp-json\/wp\/v2\/comments?post=167"}],"version-history":[{"count":28,"href":"http:\/\/wahlers.com.br\/claus\/blog\/wp-json\/wp\/v2\/posts\/167\/revisions"}],"predecessor-version":[{"id":236,"href":"http:\/\/wahlers.com.br\/claus\/blog\/wp-json\/wp\/v2\/posts\/167\/revisions\/236"}],"wp:attachment":[{"href":"http:\/\/wahlers.com.br\/claus\/blog\/wp-json\/wp\/v2\/media?parent=167"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/wahlers.com.br\/claus\/blog\/wp-json\/wp\/v2\/categories?post=167"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/wahlers.com.br\/claus\/blog\/wp-json\/wp\/v2\/tags?post=167"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}