2007年9月5日 星期三

將影片轉成連續圖檔

之前寫過

Flash WebCam 拍照存檔
http://benbenstudio.blogspot.com/2007/08/flash-webcam.html

NetStream 的 onMetaData
http://benbenstudio.blogspot.com/2007/09/netstream-onmetadata.html

這次來結合兩者,當影片在播放時,將畫面都抓下來,然後都上傳到後台存檔

Flash CS3 Document Class 的原始檔如下:

package{
import flash.display.*;
import flash.events.*
import flash.media.Video;
import flash.net.*;
import flash.utils.*;

import fl.controls.Button;

import net.kaourantin.JPEGEncoder;
import com.jooce.net.uploadFile;

public class Video2Jpeg extends MovieClip{

private var conn:NetConnection;
private var ns:NetStream;
private var myVideo:Video

private var nsClient:Object;

private var btnTogglePause:Button;

private var sendJpegToServerManager:Sprite;

public function Video2Jpeg(){
initComponents();
}

private function initComponents():void{

conn = new NetConnection();
conn.connect(null);
ns = new NetStream(conn);
ns.addEventListener(NetStatusEvent.NET_STATUS, ns_netStatus);

nsClient = new Object();
nsClient.onMetaData = nsClient_onMetaData;
ns.client = nsClient;

myVideo = new Video();
myVideo.attachNetStream(ns);
addChild(myVideo);

btnTogglePause = new Button();
btnTogglePause.label = "Pause";
btnTogglePause.x = 0;
btnTogglePause.y = myVideo.y + myVideo.height + 10;
btnTogglePause.addEventListener(MouseEvent.CLICK, btnTogglePause_click);
addChild(btnTogglePause);

sendJpegToServerManager = new Sprite();

ns.play("test.flv");
}

private function ns_netStatus(evt:NetStatusEvent):void
{
trace("[" + NetStatusEvent.NET_STATUS + "]<------" + getTime());
for(var i:String in evt.info){
trace(i + " = " + evt.info[i]);
}

if(evt.info.level=="status" && evt.info.code=="NetStream.Play.Start"){
sendJpegToServerManager.addEventListener(Event.ENTER_FRAME, sendJpegToServerManager_enterFrame);
}

if(evt.info.level=="status" && evt.info.code=="NetStream.Play.Stop"){
sendJpegToServerManager.removeEventListener(Event.ENTER_FRAME, sendJpegToServerManager_enterFrame);
}
}

private function nsClient_onMetaData(infoObject:Object):void{
trace("[onMetaData]<------" + getTime());
for(var i:String in infoObject)
trace(i + " = " + infoObject[i]);
}

private function sendJpegToServerManager_enterFrame(evt:Event):void{
takePhoto();
}

private function takePhoto():void{
if(myVideo!=null){
var bd:BitmapData = new BitmapData(320, 240);
bd.draw(myVideo);

var jpegEnc:JPEGEncoder = new JPEGEncoder(85);
var jpegDat:ByteArray = jpegEnc.encode(bd);

var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, onURLLoaderComplete);
loader.addEventListener(IOErrorEvent.IO_ERROR, onURLLoaderFailure);

var fileName:String = "video_" + getNSTime() + ".jpg";
uploadFile(loader, 'http://localhost:9002/FileUpload/FileUpload', jpegDat, fileName);
}
}

private function onURLLoaderComplete(evt:Event):void{
trace("onURLLoaderComplete");
}

private function onURLLoaderFailure(evt:IOErrorEvent):void{
trace("onURLLoaderFailure");
}

private function btnTogglePause_click(evt:MouseEvent):void{
btnTogglePause.label = btnTogglePause.label=="Pause"?"Play":"Pause";
ns.togglePause();
}

private function getNSTime():String{
return (Math.round(ns.time * 1000) / 1000) + "_" + getTimer();
}

private function getTime():String{
var dt:Date = new Date();
return dt.hours + ":" + dt.minutes + ":" + dt.seconds;
}
}
}

至於後台的部份,跟上次一樣不用改,因為就只是接收上傳檔案存起來而已。

存完的檔案,大概長得像這個畫面:







我檔名的命名原則是:video_影片播放幾秒(最多取小數點後三位)_啟動程式後經過多少微秒.jpg

所以,大約 34.478 秒的影片,花了大約 136.263 秒,將 268 張畫面上傳存檔完成!

3 則留言:

匿名 提到...
網誌管理員已經移除這則留言。
匿名 提到...

邦邦你好
請問有辦法將一個WMV影片讀入圖層中
並且畫面上有一按鈕
當按下按鈕時 影片開始做紀錄
直到再次按下按鈕時 影片停止紀錄

然後可以將剛剛紀錄的那個影片片段記錄下來
並且可以另存成一個SWF檔之類的

FLASH該怎麼做呢? 謝謝

Ben Chang 提到...

1. flash 無法在 runtime 期間 (也就是執行期間) 動態載入 *.wmv,若真需要,可能必須搭配其他後台程式負責轉檔,像是將 *.wmv 轉成 *.flv 再餵給 flash。

2. flash 本身無法將某段影片給錄影擷取下來,只能紀錄開始與結束的時間點,然後你下次還是必須載入完整影片,然後用程式跳到起始點播放到結束點。

我不確定若是搭配 flash media server 是否有機會做到,不過,若是你在 flash 中能知道起迄時間點的話,也可以傳給後台,叫後台程式由原始影片中擷取中所需的影片另存成新的影片檔案,不過相關技術與資源就要看有沒有人已經有開發好現成的 library 可用了。