使用air将视频从移动设备传输到FMS

时间:2014-01-19 11:21:25

标签: android ios actionscript-3 air flash-media-server

我正在使用Air将网络流式传输到FMS(Flash Media Server),因为您知道这在桌面上没有问题,但我可以从手机(Android,iOS)流式传输吗? 这是我的代码:

var nc:NetConnection = new NetConnection();
var bandwidth:int = 0; 
var quality:int = 50;
var camera:Camera = Camera.getCamera();

camera.setQuality(bandwidth, quality);
camera.setMode(430,320,15, true);

var video:Video = new Video();
video.attachCamera(camera);
addChild(video);
video.width = 430;
video.height = 320;


nc.connect("rtmp://***");
nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);

function netStatusHandler(event:NetStatusEvent):void{
    if (event.info.code == "NetConnection.Connect.Success")
    {
    label10.text = 'Connected';
    var ns:NetStream = new NetStream(nc);
    ns.attachCamera(camera);
    ns.publish("NewStream1", "live");
    }

}

我没有FMS来测试它,有没有人试过这个或者在aleast有没有办法测试这个而不购买FMS?

2 个答案:

答案 0 :(得分:1)

我已经通过Wowza媒体服务器从移动AIR应用程序完成了流式传输。标准流代码应该可以工作,只需注意iOS中不支持H.264视频。

答案 1 :(得分:0)

是的,你可以!

我有一段时间专注于这个话题,现在我可以将流发布到流媒体服务器并订阅它。我的流媒体服务器是Red5,它是免费的,你可以尝试使用它你会知道.Red5由Java编写,但它是为Flash编写的,其客户端使用Flash或Flex推荐。

如您所知,ActionScript中的NetConnection和NetStream是greate,您可以使用它们将流发布到Red5或FMS,您也可以使用它们来订阅流。

如果您想使用ActionScript编写移动应用程序,可以参考此链接。 http://help.adobe.com/en_US/flex/mobileapps/index.html 首先,您应该创建一个Flex移动应用程序,在其第一个视图中可以粘贴 下面的代码。当您能够发布流时,您将知道如何订阅它。

这是我的主要代码,在此代码中我使用adobe的stratus服务来测试我的项目。很抱歉能够帮到你这么多:

    import mx.core.UIComponent;
        import mx.events.FlexEvent;

        import org.osmf.elements.VideoElement;

        import spark.components.VideoDisplay;

        private var netConnection:NetConnection = null;
        private var netStream:NetStream = null;
        private var netGroup:NetGroup = null;
        private var video:Video = null;
        private var sequenceNumber:uint = 0;

        //Stratus 服务器地址
        private const SERVER:String = "rtmfp://stratus.adobe.com/";
        //开发者Key,请使用你申请的Key
        private const DEVKEY:String = "1710124cbf69e3f25b780c13-d6cbf2cb35a1";
        //组的名字,名字要唯一
        private const GROUP_PREFIX:String = "www.flextheworld.com.stratus2.demo";

        //[Bindable]的作用是进行绑定,如果定义的值改变那么所有被它影响的引用都将改变其值,会有事件发送以获得引用的改变
        [Bindable] 
        private var connected:Boolean = false;
        [Bindable] 
        private var joinedGroup:Boolean = false;

        private var cam:Camera;

        protected function creationCompleteHandler(event:FlexEvent):void
        {
            groupName.text = "channel" + (int(Math.random() * 899) + 101);
            cam = Camera.getCamera();
            if(cam){
                cam.setMode(width, width, 25);
                cam.setQuality(144000,85);
                cam.setKeyFrameInterval(5);
                cam.setLoopback    (false);    
                var video: Video = new Video(cam.width, cam.height);
                ui.width = video.width;
                ui.height = video.height;
                /*ui.addChild(video);*/
                video.attachCamera(cam);


            }
        }


        /**
         * NetStream和Group的事件响应
         * */
        private function netStatusHandler(e:NetStatusEvent):void
        {
            switch(e.info.code)
            {
                case "NetConnection.Connect.Success": //与Stratus链接成功,开始创建/进入组
                    onConnect();
                    break;

                case "NetConnection.Connect.Closed":
                case "NetConnection.Connect.Failed":
                case "NetConnection.Connect.Rejected":
                case "NetConnection.Connect.AppShutdown":
                case "NetConnection.Connect.InvalidApp":    
                    onDisconnect();
                    break;

                case "NetStream.Connect.Success": //Net Stream 链接成功
                    onNetStreamConnect();
                    break;

                case "NetStream.Connect.Rejected": // e.info.stream
                case "NetStream.Connect.Failed": // e.info.stream
                    doDisconnect();
                    break;

                case "NetGroup.Connect.Success": // e.info.group
                    onNetGroupConnect();
                    break;

                case "NetGroup.Connect.Rejected": // e.info.group
                case "NetGroup.Connect.Failed": // e.info.group
                    doDisconnect();
                    break;

                case "NetGroup.Posting.Notify": // 收到信息
                case "NetStream.MulticastStream.Reset":
                case "NetStream.Buffer.Full":
                    break;

                case "NetGroup.SendTo.Notify": // e.info.message, e.info.from, e.info.fromLocal
                case "NetGroup.LocalCoverage.Notify": //
                case "NetGroup.Neighbor.Connect": // e.info.neighbor
                case "NetGroup.Neighbor.Disconnect": // e.info.neighbor
                case "NetGroup.MulticastStream.PublishNotify": // e.info.name
                case "NetGroup.MulticastStream.UnpublishNotify": // e.info.name
                case "NetGroup.Replication.Fetch.SendNotify": // e.info.index
                case "NetGroup.Replication.Fetch.Failed": // e.info.index
                case "NetGroup.Replication.Fetch.Result": // e.info.index, e.info.object
                case "NetGroup.Replication.Request": // e.info.index, e.info.requestID
                default:
                    break;
            }
        }

        private function doConnect():void
        {
            if(joinedGroup){
                doDisconnect()
                return;
            }

            startBtn.label = "链 接 中";
            startBtn.enabled = false;
            //updateStatus("Connecting to \"" + SERVER + "\"");
            netConnection = new NetConnection();
            //传入的两个参数分别为事件类型和监听器,这个监听器接收第一个参数定义的事件类型且不能有返回值。
            netConnection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
            netConnection.connect(SERVER + DEVKEY);
        }

        /**
         * 与Stratus 链接成功后触发
         * */
        private function onConnect():void
        {
            //GroupSpecifier 类用于构造可传递给 NetStream 和 NetGroup 构造函数的不透明的 groupspec 字符串
            var groupSpecifier:GroupSpecifier;

            //updateStatus("与Stratus链接成功\n");
            connected = true;

            //定义组,根据用户输入的groupName构造了唯一的GroupSpecifier
            groupSpecifier = new GroupSpecifier(GROUP_PREFIX + groupName.text);
            //允许多播
            groupSpecifier.multicastEnabled = true;
            //允许发送数据
            groupSpecifier.postingEnabled = true;
            //打开频道,只有打开服务器通道,服务器才能将支持功能提供给组成员。
            groupSpecifier.serverChannelEnabled = true;

            //创建netStream与用户组的链接,我们用他来发送视频和音频流
            /*
            * groupspecWithAuthorizations()返回可传递给 NetStream 和 NetGroup 构造函数的不透明的 groupspec 字符串,包括授权。
            * 在对等多播组中发布或播放,需指定 groupspec字符串
            */
            netStream = new NetStream(netConnection, groupSpecifier.groupspecWithAuthorizations());
            netStream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);

            //加入用户组 
            //NetGroup 类的实例表示 RTMFP组中的成员资格,此类可以监视服务质量,发布,直接路由(发送),对象复制
            netGroup = new NetGroup(netConnection, groupSpecifier.groupspecWithAuthorizations());
            netGroup.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);

            //updateStatus("加入用户组 \"" + groupSpecifier.groupspecWithAuthorizations() + "\"\n");
        }

        /**
         *
         * NetStraeam链接到用户组后触发
         * */
        private function onNetStreamConnect():void
        {
            //加载话筒
            netStream.client = this;                
            var mic:Microphone = Microphone.getMicrophone();
            if(mic)
            {
                mic.codec = SoundCodec.SPEEX;
                mic.setSilenceLevel(0);

                netStream.attachAudio(mic);

                    //updateStatus("话筒设置完毕\n");
            }
            //加载视频,并发布视频和话筒
            publishVideo();

        }
        /**
         * 发布视听流
         * */
        private function publishVideo():void{
            netStream.attachCamera(cam)
            //发布名字为stream 的流。这个部分这里就不讲解了,在原来的p2p教程里有详细说明 
            netStream.publish("stream");

        }

        private function onNetGroupConnect():void
        {
            startBtn.label = "直 播 中";
            startBtn.enabled = true;
            //加入用户组成功
            joinedGroup = true;
        }

        /**
         * 断开链接
         * */
        private function doDisconnect():void
        {
            if(netConnection){
                startBtn.label = "停 止 中";
                startBtn.enabled = false;
                netConnection.close();
            }

        }

        /**
         * netconnection断开后执行
         * */
        private function onDisconnect():void
        {
            startBtn.label = "开始 直 播";
            startBtn.enabled = true;
            netConnection = null;
            netStream = null;
            netGroup = null;
            connected = false;
            joinedGroup = false;
        }

    ]]>
</fx:Script>


<s:VGroup paddingTop="10" paddingLeft="10" paddingRight="10" id="cameraDisplay" width="100%"  >
    <s:Label fontSize="30" text="直播频道" />
    <s:TextInput id="groupName" width="100%" />
    <mx:UIComponent id="ui"  />
    <s:Group width="100%">
        <s:layout>
            <s:HorizontalLayout horizontalAlign="center" paddingTop="20" />
        </s:layout>
        <s:Button id="startBtn" fontSize="60" chromeColor="#9F2A2F"  label="开 始 直 播" click="doConnect()" />
    </s:Group>

</s:VGroup>