video - 从 SWF 中提取视频帧

标签 video flash flash-cs5 frames

我有一个 SWF,我想从中提取 VideoFrames。当使用 7-Zip (VideoFrame) 打开 SWF 时,它们会出现在这个名称下。显然,以这种方式提取它们无济于事,因为它们不是任何可识别的图像格式。

我已经将 SWF 加载到 Flash Professional CS5 中,并且能够在库中查看所有位图对象(组合在“UI”中,在一个角上覆盖视频动画),但我找不到任何地方的视频帧,甚至找到显示它们的对象。

我是否遗漏了一些非常明显的东西? (我对Flash开发有些陌生,所以很有可能。)

免责声明:本文不以营利为目的,也不涉及任何侵犯版权的行为。这是个人练习。

编辑:我不想简单地导出 SWF 的整个帧,因为有几个 UI 元素覆盖了视频。我知道整个视频帧都存在(只是部分被遮盖)。我想提取嵌入视频的帧,而不是 SWF 帧。

最佳答案

一种解决方案涉及创建一个 AIR 应用程序来对 SWF 的各个帧进行编码:

  1. 使用 Loader 对象加载 SWF
  2. 在 SWF 中找到视频实例
  3. 将视频的每一帧捕获到 BitmapDataObject
  4. 将 BitmapDataObject 编码为 PNG 或 JPEG
  5. 将编码后的帧写入文件

一旦所有帧都作为单独的图像输出,就可以使用 Flash、FFMPEG 或其他视频编辑软件将它们重新组合成视频序列。

下面是将嵌入 SWF 中的视频的前 20 帧编码为 PNG 图像的代码。要使用它,请按如下所示在 Flash Pro 中创建一个 AIR 应用程序:

  1. 点击文件菜单
  2. 选择新建
  3. 选择 Flash 文件 (Adobe AIR)
  4. 打开“ Action ”面板(在“窗口”菜单上可用)
  5. 将代码粘贴到操作面板中
  6. 将 videoFilename 变量更改为您要提取的 SWF 文件的名称
  7. 从 Flash Pro 运行 SWF 或将其发布并作为 AIR 应用程序运行

由于这是出于教育目的,它还没有经过优化,因此它会运行得非常慢并且您的计算机可能会变得无响应,这就是为什么它被限制为 20 帧。更好的编码器会异步处理帧以避免 CPU 过载。

需要 AIR 的原因是它能够将视频帧直接写入您的硬盘。我们无法使用普通网络版本的 Flash 播放器执行此操作,因为出于安全原因它会阻止此类操作(您不希望网站将文件写入您的硬盘驱动器)。

操作中最复杂的部分是将图像编码为PNG格式。这是使用 PNG encoder from the open-source AS3CoreLib by Mike Chambers 完成的,因此是版权声明的原因。

更新:更新代码以在 SWF 中定位视频对象

// location to load the SWF file which you want to capture
var videoFilename:String = "Untitled-1.swf";

// initialise the frame counter
// the frame counter is used to number the individual output images
var frameCount:int = 0;

// create a folder to store the output files
// this creates a folder on the desktop called "video_frames"
var path:File = File.desktopDirectory.resolvePath("video_frames");
path.createDirectory();

var bitmapData:BitmapData;
var bitmap:Bitmap;

// create a loader to load the SWF file
// when the SWF file is loaded we start capturing the frames
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderCompleteHandler);
loader.load(new URLRequest(videoFilename));

var video:Video;

// this is called when the SWF is loaded and we can start capturing frames    
function loaderCompleteHandler(event:Event):void
{
    // find the video in the loaded SWF
    findVideo(loader.content);

    if (video == null)
        throw new Error("cannot find video");

    // create a bitmap to capture the frames into
    // the bitmap is later encoded into PNG format and written to a file
    bitmapData = new BitmapData(video.width, video.height, false, 0xFFFF00FF);
    bitmap = new Bitmap(bitmapData, PixelSnapping.ALWAYS, false);
    addChild(bitmap);

    addEventListener(Event.ENTER_FRAME, frameHandler);
}

function findVideo(input:DisplayObject):void
{
    if (!(input is DisplayObjectContainer))
        return;

    var container:DisplayObjectContainer = input as DisplayObjectContainer;

    for (var i:int = 0; i < container.numChildren; i++) {
        var child:DisplayObject = container.getChildAt(i);
        if (child is Video) {
            video = child as Video;
                    return;
            }
        else {
            findVideo(child);
            }
    }
}

function frameHandler(event:Event):void {

    // count the individual frames and stop capturing after 20 frames
    frameCount ++;  
    if (frameCount > 20) {
        removeEventListener(Event.ENTER_FRAME, frameHandler);
        return;
    }

    // capture the current frame of the SWF to the bitmap
    // this grabs the pixels into a usable for  for encoding
    bitmapData.draw(video);

    // encode bitmap into PNG format
    // you can also easily use JPEG format from AS3CoreLib
    var data:ByteArray = encode(bitmapData);

    // write the PNG image to a file
    // this is the most time-consuming action 
    var file:File = path.resolvePath("frame" + frameCount + ".png");
    var stream:FileStream = new FileStream();
    stream.open(file, FileMode.WRITE);
    stream.writeBytes(data);
    stream.close();
}

/*
  Copyright (c) 2008, Adobe Systems Incorporated
  All rights reserved.

  Redistribution and use in source and binary forms, with or without 
  modification, are permitted provided that the following conditions are
  met:

  * Redistributions of source code must retain the above copyright notice, 
    this list of conditions and the following disclaimer.

  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the 
    documentation and/or other materials provided with the distribution.

  * Neither the name of Adobe Systems Incorporated nor the names of its 
    contributors may be used to endorse or promote products derived from 
    this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
    import flash.geom.*;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.utils.ByteArray;

/**
 * Created a PNG image from the specified BitmapData
 *
 * @param image The BitmapData that will be converted into the PNG format.
 * @return a ByteArray representing the PNG encoded image data.
 * @langversion ActionScript 3.0
 * @playerversion Flash 9.0
 * @tiptext
 */         
function encode(img:BitmapData):ByteArray {
    // Create output byte array
    var png:ByteArray = new ByteArray();
    // Write PNG signature
    png.writeUnsignedInt(0x89504e47);
    png.writeUnsignedInt(0x0D0A1A0A);
    // Build IHDR chunk
    var IHDR:ByteArray = new ByteArray();
    IHDR.writeInt(img.width);
    IHDR.writeInt(img.height);
    IHDR.writeUnsignedInt(0x08060000); // 32bit RGBA
    IHDR.writeByte(0);
    writeChunk(png,0x49484452,IHDR);
    // Build IDAT chunk
    var IDAT:ByteArray= new ByteArray();
    for(var i:int=0;i < img.height;i++) {
        // no filter
        IDAT.writeByte(0);
        var p:uint;
        var j:int;
        if ( !img.transparent ) {
            for(j=0;j < img.width;j++) {
                p = img.getPixel(j,i);
                IDAT.writeUnsignedInt(
                    uint(((p&0xFFFFFF) << 8)|0xFF));
            }
        } else {
            for(j=0;j < img.width;j++) {
                p = img.getPixel32(j,i);
                IDAT.writeUnsignedInt(
                    uint(((p&0xFFFFFF) << 8)|
                    (p>>>24)));
            }
        }
    }
    IDAT.compress();
    writeChunk(png,0x49444154,IDAT);
    // Build IEND chunk
    writeChunk(png,0x49454E44,null);
    // return PNG
    return png;
}

var crcTable:Array;
var crcTableComputed:Boolean = false;

function writeChunk(png:ByteArray, 
        type:uint, data:ByteArray):void {
    if (!crcTableComputed) {
        crcTableComputed = true;
        crcTable = [];
        var c:uint;
        for (var n:uint = 0; n < 256; n++) {
            c = n;
            for (var k:uint = 0; k < 8; k++) {
                if (c & 1) {
                    c = uint(uint(0xedb88320) ^ 
                        uint(c >>> 1));
                } else {
                    c = uint(c >>> 1);
                }
            }
            crcTable[n] = c;
        }
    }
    var len:uint = 0;
    if (data != null) {
        len = data.length;
    }
    png.writeUnsignedInt(len);
    var p:uint = png.position;
    png.writeUnsignedInt(type);
    if ( data != null ) {
        png.writeBytes(data);
    }
    var e:uint = png.position;
    png.position = p;
    c = 0xffffffff;
    for (var i:int = 0; i < (e-p); i++) {
        c = uint(crcTable[
            (c ^ png.readUnsignedByte()) & 
            uint(0xff)] ^ uint(c >>> 8));
    }
    c = uint(c^uint(0xffffffff));
    png.position = e;
    png.writeUnsignedInt(c);
}

关于video - 从 SWF 中提取视频帧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7243996/

相关文章:

video - ffmpeg和媒体播放器之间的帧提取差异

php - FFMPEG - 不显示 -vstats

video - 如何插入帧以补偿捕获期间丢失的帧

javascript - 加载一定数量后开始播放 HTML5 视频

flash - 有没有办法让Flash强制静态类型?

flash - Flash/ActionScript 3声音延迟

html - Flash 对象后面的下拉菜单

flash - Flash中如何获取对象的宽高?

actionscript-3 - 闪存 CS5 : compiling fla with huge internal library takes YEARS !

Flash CS4 与 Flash CS5 Actionscript - 我应该升级吗?