【转】FLV 轉 SWF 另類作法

本文转自:TICORE'S BLOG

網路上有很多可以將 FLV 轉為 SWF 的工具,譬如 FLV to SWF Using FFMPEG command line 不過測試發現 FPS 變得超高以下分享一個另類的做法,只要一行 Dos Command 就可以把 FLV 轉成 SWF,由於不需要重新取樣,速度非常快

Flash Player 10.1 之後新增 NetStream.appendBytesAction() 方法可以直接從 AS3 Binary 資料播放 Streaming 只要想辦法把 FLV 資料嵌入到 SWF,就能夠用 AS3 來播放最簡單的嵌入方式就事先寫好一個 Player SWF,然後用 Dos Command 將 FLV 資料接在後面。

FLVBytePlayer 程式碼如下:

  1package {
  2 import flash.display.Loader;
  3 import flash.display.Sprite;
  4 import flash.display.StageAlign;
  5 import flash.display.StageScaleMode;
  6 import flash.events.Event;
  7 import flash.events.NetStatusEvent;
  8 import flash.media.Video;
  9 import flash.net.NetConnection;
 10 import flash.net.NetStream;
 11 import flash.net.NetStreamAppendBytesAction;
 12 import flash.net.URLLoader;
 13 import flash.net.URLLoaderDataFormat;
 14 import flash.net.URLRequest;
 15 import flash.text.TextField;
 16 import flash.ui.ContextMenu;
 17 import flash.utils.ByteArray;
 18
 19 [SWF(width="300", height="300")]
 20 public class FLVBytePlayer extends Sprite {
 21  public var nc:NetConnection = new NetConnection();
 22  public var ns:NetStream;
 23  public var video:Video = new Video();
 24  public var videoWidth:Number = 1;
 25  public var videoHeight:Number = 1;
 26  public var videoByte:ByteArray;
 27  public var urlLdr:URLLoader = new URLLoader();
 28  public function FLVBytePlayer() {
 29   stage.scaleMode = StageScaleMode.NO_SCALE;
 30   stage.align = StageAlign.TOP_LEFT;
 31   stage.addEventListener(Event.RESIZE, onStageResizeHandler);
 32   contextMenu = new ContextMenu();
 33   contextMenu.hideBuiltInItems();
 34   nc.connect(null);
 35   ns = new NetStream(nc);
 36   ns.client = {
 37	onMetaData: function(info:Object):void{
 38	 trace("onMetaData:");
 39	 for (var i:String in info) {
 40	  trace("\t", i, info[i]);
 41	 }
 42	 videoWidth = info.width;
 43	 videoHeight = info.height;
 44	 onStageResizeHandler();
 45	}
 46   };
 47   ns.addEventListener(NetStatusEvent.NET_STATUS, onNsNetStatusHandler);
 48   video.smoothing = true;
 49   video.attachNetStream(ns);
 50   addChild(video);
 51   var ldr:Loader = new Loader();
 52   var req:URLRequest = new URLRequest(ldr.contentLoaderInfo.loaderURL);
 53   trace(ldr.contentLoaderInfo.loaderURL);
 54   urlLdr.dataFormat = URLLoaderDataFormat.BINARY;
 55   urlLdr.addEventListener(Event.COMPLETE, onLoadCompleteHandler);
 56   urlLdr.load(req);
 57  }
 58  public function onStageResizeHandler(e:Event = null):void{
 59   var stageRatio:Number = stage.stageWidth / stage.stageHeight;
 60   var videoRatio:Number = videoWidth / videoHeight;
 61   if (stageRatio > videoRatio) {
 62	video.height = stage.stageHeight;
 63	video.width = stage.stageHeight * videoRatio;
 64	video.y = 0;
 65	video.x = (stage.stageWidth - video.width) / 2;
 66   } else {
 67	video.width = stage.stageWidth;
 68	video.height = stage.stageWidth / videoRatio;
 69	video.x = 0;
 70	video.y = (stage.stageHeight - video.height) / 2;
 71   }
 72  }
 73  public function onNsNetStatusHandler(e:NetStatusEvent):void{
 74   trace(e.info.code);
 75   switch (e.info.code) {
 76	case "NetStream.Buffer.Empty":
 77	 break;
 78   }
 79  }
 80  public function onLoadCompleteHandler(e:Event):void{
 81   var data:ByteArray = urlLdr.data;
 82   for (var i:int = data.length - 1 ; i > 0  ; --i) {
 83	if (
 84	 data[i + 0] == 70 && /* "F".charCodeAt(0) */
 85	 (data[i + 1] == 76 || data[i + 1] == 52) &&
 86	 /* "L".charCodeAt(0) *//* "4".charCodeAt(0) */
 87	 data[i + 2] == 86   /* "V".charCodeAt(0) */
 88	) {
 89	 videoByte = new ByteArray();
 90	 data.position = i;
 91	 data.readBytes(videoByte, 0, 0);
 92	 trace(data.length, i, videoByte.length);
 93	 ns.play(null);
 94	 ns.appendBytesAction(NetStreamAppendBytesAction.RESET_SEEK);
 95	 ns.appendBytes(videoByte);
 96	 break;
 97	}
 98   }
 99  }
100 }
101}

以上 Player 只要編譯一次產生 SWF 後,利用以下的 Dos Command 接上 FLV就可以直接撥放了

copy /b FLVBytePlayer.swf + Video.flv FLVBytePlayer_FLV.swf

需要注意的是 NetStream.appendBytesAction 不適用於 H264 編碼請自行斟酌使用。