2007-06-28

取得 FLV 內的 header 資料

依據 osFlash 裡 FLV 檔案資料格式的說明, 利用 Flash 開發「取得 FLV 檔頭資料及串流資料」的 AIR app。
要注意的是 meta 裡包含兩個 AMF packets, 所以需使用 ByteArray.readObject() 兩次。
Flash frame AS3:
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;

var file:File;
var fs:FileStream;
var flvFilter:FileFilter = new FileFilter("Flash Video", "*.flv");
var header_ba:ByteArray;
var stream_ba:ByteArray;

function bClick(e:MouseEvent):void {
var targetName:String = e.target.name;
switch (targetName) {
case "open_btn" :
file = new File();
file.browseForOpen("Open", [flvFilter]);
file.addEventListener(Event.SELECT, readFLVHeader);
break;
case "show_btn" :
readStreamHeader();
break;
case "close_btn" :
fs.close();
break;
}
}
open_btn.addEventListener(MouseEvent.CLICK, bClick);
show_btn.addEventListener(MouseEvent.CLICK, bClick);
close_btn.addEventListener(MouseEvent.CLICK, bClick);


function readFLVHeader(e:Event) {
filename_txt.text = file.nativePath;
fs = new FileStream();
fs.open(file, FileMode.READ);

// read FLV Header
header_ba = new ByteArray();
fs.readBytes(header_ba, 0, 9);
main_txt.text = "Signature: "+ header_ba.readMultiByte(3, "") +"\n";
main_txt.appendText("Version: "+ header_ba.readUnsignedByte()+"\n");
main_txt.appendText("Flags: "+ header_ba.readUnsignedByte()+"\n");
main_txt.appendText("Offset: "+ header_ba.readUnsignedInt()+"\n");
main_txt.appendText("---\n");
}
function readStreamHeader() {
stream_ba = new ByteArray();
fs.readBytes(stream_ba, 0, 15);

main_txt.appendText("PreviousTagSize: "+ stream_ba.readInt()+" ----\n");
var type:uint = stream_ba.readUnsignedByte();
main_txt.appendText("Type: "+ type +"\n");
// 取 3 bytes
var bodyLength:uint = stream_ba.readUnsignedShort()<<8 | stream_ba.readUnsignedByte();
main_txt.appendText("BodyLength: "+ bodyLength +"\n");
var timestamp:uint = stream_ba.readUnsignedShort()<<8 | stream_ba.readUnsignedByte();
main_txt.appendText("Timestamp: "+ timestamp +"\n");
main_txt.appendText("Padding: "+ stream_ba.readUnsignedInt()+"\n");
if (type == 0x12) {
var t_ba:ByteArray = new ByteArray();
fs.readBytes(t_ba, 0, bodyLength);
// 設定 AMF 的格式, 即使是 on2 VP6 應該還是舊的
t_ba.objectEncoding = ObjectEncoding.AMF0;
// 第一個 AMF 物件是事件處理器的資料
var obj:Object = t_ba.readObject();
var str:String = QopDump.go( obj );
main_txt.appendText("***\nEvent handler:"+str+"\n***\n");
obj = t_ba.readObject();
str = QopDump.go( obj );
main_txt.appendText(str+"\n");
} else {
// skip the body
fs.position += bodyLength;
}
main_txt.verticalScrollPosition = main_txt.maxVerticalScrollPosition;
}

FLV 的第一個 stream unit 應該都是 meta。較舊 FLV 的 meta 大多有問題, 沒有提供仔細而實用的資料。

較新格式的 FLV 其 Flags 通常是 13 而不是 5。


原始檔: parseFLV.fla
安裝檔: parseFLV.air

沒有留言:

FB 留言