摘要:How to load ByteArray to Sound Class (1)
Adobe Flex提供相當多支援多媒體的Class,包括:Sound、Video等,豐富並便利像我對於一些多媒體運用比較不熟悉的程式人員,
透過簡單的使用URLRequest(url:String) 將所需要的多媒體檔案之路徑或URL網址給予這些多媒體Class,即可以快速取得,並且進行播放。
但是我自己卻遇到了一個問題,如果今天我存在於Client或Server的多媒體檔(以MP3為例),那麼,我將必需知道所有檔案的路徑,老實說,
這樣有點辛苦,程式撰寫起來也不是說這麼方便。況且,現在是Database大量使用的年代,大部分的人都會把多媒體資訊儲存於Database之中
(但這不包括大型娛樂多媒體檔案),而這些存在於Database中的檔案,通常是利用二位元陣列(ByteArray)來存放,那在Adobe Flex所提供
的方式, 主要是透過URLRequest,這種情形下就沒有辦法支援讀取ByteArray的內容了。
看到這裡也許會有人誤會了我的意思,可能會被誤解為,那我可以透過 Embed的方式,就可以讓Sound來播放ByteArray了啊。這個方式,
如下之範例:
[Embed(source="assets/Sounds/voices/hello.mp3")]
private var musicClass:Class;
private var music:Sound = new musicClass();
private var soundChannel:SoundChannel=null;
public function Test()
{
soundChannel = music.play();
}
這個方式主要是把原始檔案根據路徑讀取,並且轉成Class的方式提供給Sound使用。這個方式其實沒有錯。但跟我真正遇到的問題還是不同的,
因為我主要強調是在於已經存於Database中的MP3,它是以ByteArray的方式存在,而不是一個檔案的方式,當然我也試過比較笨的方式,先把資
料從Database讀出來再寫入Disk,最後透過路徑的方式進行播放。這些都是不錯的方式,但效率不是特別好。
因此,我找到了一篇 <<How to load MP3 files from a FileReference>>,說明如透過FileReference把存在的MP3檔,
轉換成ByteArray並且進行播放。
文中的第一段就提到我剛才所描述的問題:「
FileReference.load
is a nice new feature in Flash Player 10, but the only thing you get back from it is the FileReference.data
property, which is a ByteArray
. This is useless (well, not altogether, as we’ll see) in the case of MP3 audio files, because the built-in Sound API does not support loading from ByteArray
.」
這篇文章中也有提供Souce Code的下載,MP3FileReferenceLoaderLib.zip,我稍微的為大家解釋一下:這個 MP3FileReferenceLoaderLib,
主要分成幾個重要的Class,
1. ByteArraySegement.as:做為擷取MP3 Data中的片段,進行部分資料與Header上修改上的使用。
2. SoundClassSwfByteCode.as:內部主要放了大量16位元的參數,做為Header上的位元資料修正與增加。
3. MP3FileReferenceLoader.as:主是產生MP3檔案的載入器,包括引入MP3Parser去剖析你所選擇的檔案,並且修改原本讀進來的檔案,
轉成Sound與SWF所能看懂的多媒體格式。
4. MP3Parser.as:剖析使用者選擇的檔案,將選擇的MP3檔轉成ByteArray,取得相關ID3之資訊與提供編寫ByteArray的方法。
5. MP3SoundEvent.as:整個Libary最後指定將ByteArray指定給Sound的事件。
另外更有範例的說明,如下表。主要操作方式:
1)先宣告一個MP3FileReferenceLoader的object(稱loader)與FileReference的object(稱fileReference),
2)接著透過這個fileReference.browser()跳出使用者選擇畫面,供使用者選擇MP3檔案,3)選擇完成觸發Event.SELECT事件,
進行loader.getSound(),
將實體檔案轉成SWF可以播放的Sound物件,編轉完成後,4)觸發MP3SoundEvent.COMPLETE事件,進行音樂的播放。
1: package {
2: import flash.display.Sprite;
3: import flash.events.Event;
4: import flash.events.MouseEvent;
5: import flash.net.FileFilter;
6: import flash.net.FileReference;
7:
8: import org.audiofx.mp3.MP3FileReferenceLoader;
9: import org.audiofx.mp3.MP3SoundEvent;
10:
11: public class MP3FileReferenceTest extends Sprite
12: {
13: private var loader:MP3FileReferenceLoader;
14: private var fileReference:FileReference;
15: public function MP3FileReferenceTest()
16: {
17: loader=new MP3FileReferenceLoader();
18: loader.addEventListener(MP3SoundEvent.COMPLETE,mp3LoaderCompleteHandler);
19: fileReference=new FileReference();
20: fileReference.addEventListener(Event.SELECT,fileReferenceSelectHandler);
21: stage.addEventListener(MouseEvent.CLICK,clickHandler);
22: }
23: private function clickHandler(ev:MouseEvent):void
24: {
25: fileReference.browse([new FileFilter("mp3 files","*.mp3")]);
26: }
27: private function fileReferenceSelectHandler(ev:Event):void
28: {
29: loader.getSound(fileReference);
30: }
31: private function mp3LoaderCompleteHandler(ev:MP3SoundEvent):void
32: {
33: ev.sound.play();
34: }
35: }
36: }
上面的Demo Code我相信不難理解。其另外5個主要的Class才是真的比較不好懂的地方,小弟不材,有些相關於SWF與MP3格式與
位元偏移的概念, 不是特別熟悉,因此沒有辦法多做詳細的說明。如果各位覺得有需要補充的,也可以留言在下面,大家彼此分享。
另外,如果你在執行上有遇到 “SecurityError: Error #3015: Loader.loadBytes() is not permitted to load content with executable code.”
這個問題時, 你可以參考[2],你只需要在 "MP3FileReferenceLoader.as"的generateSound()中,找到var swfBytesLoader:Loader=new Loader();
,並且修改為如下:
var swfBytesLoader:Loader=new Loader();
var loaderContext:LoaderContext = new LoaderContext();
loaderContext.allowLoadBytesCodeExecution = true;
swfBytesLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,swfCreated);
swfBytesLoader.loadBytes(swfBytes,loaderContext);
將可以修改掉剛SecurityError: Error #3015: Loader.loadBytes() is not permitted to load content with executable code.所出現的錯誤。
References: