Одно решение включает создание приложения AIR для кодирования отдельных кадров SWF:
- Загрузка SWF с использованием объекта Loader
- Найдите экземпляр видео внутри SWF
- Захватить каждый кадр видео в BitmapDataObject
- Кодировать BitmapDataObject в формате PNG или JPEG
- Записать закодированный кадр в файл
Один развсе кадры были выведены в виде отдельных изображений, их можно повторно собрать в видеопоследовательность с помощью Flash, FFMPEG или другого программного обеспечения для редактирования видео.
Ниже приведен код, который будет кодировать первые 20 кадров видеовстроенный в SWF как изображения PNG.Чтобы использовать это, создайте приложение AIR во Flash Pro следующим образом:
- Откройте меню «Файл»
- Выберите «Создать»
- Выберите «Flash File (Adobe AIR)»
- Откройте панель «Действия» (доступно в меню «Окно»)
- Вставьте код в панель действий
- Измените переменную videoFilename на имя SWF-файла, который вы хотите извлечь
- Запустите SWF-файл из Flash Pro или опубликуйте его и запустите как приложение AIR
Поскольку оно предназначено для образовательных целей, оно не было оптимизировано и поэтому будет работать очень медленнои ваш компьютер может перестать отвечать на запросы, поэтому он ограничен 20 кадрами.Лучший кодировщик будет обрабатывать кадры асинхронно, чтобы избежать перегрузки ЦП.
Причина, по которой требуется AIR, заключается в том, что он может записывать видеокадры непосредственно на жесткий диск.Мы не сможем сделать это, используя обычную веб-версию Flash-плеера, потому что она предотвращает такие действия по соображениям безопасности (вы не хотите, чтобы веб-сайт записывал файлы на ваш жесткий диск).
Самая сложная часть операции - это кодирование изображения в формат PNG.Это сделано с помощью PNG-кодера из открытого источника AS3CoreLib Майка Чамберса , отсюда и причина уведомления об авторских правах.
UPDATE: обновлен код для определения местоположения видеообъекта внутри 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);
}