我正在使用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?
答案 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>