还有两次课课程就结束了。前面关于评论的讨论基本上已经完结了,剩下的就是一些自我完善,有兴趣的同学可以考虑如何实现多篇日记的功能了,这里就暂时不再解析了,那么剩下的时间干嘛呢?明天的课是准备进行作业答辩的,所以也属于收尾的内容,如果有时间的话就把这个视频开个头,没时间的话就放到下周了。
在shangle的实例中有个Module是关于视频的,这里就对这个视频的功能模块做个简单的解析。首先例子中的视频是采用的播放指定文件的方式来进行的,这个我就简单讲下这个过程:
1、需要用到的控件主要就是一个文件列表List,一个视频播放VideoDisplay,其他的一些分页相关按钮就不特意提了,自己看代码吧。
2、在初始化时加载文件列表(init函数),这里不是自动去读指定文件夹并返回列表,而是和前面评论一样用了ArrayCollection写死的,所以大家可以自由发挥,将这个列表加载过程写成一个数据库或者XML文件的读取并自动加载的过程。
3、加载完成后List添加了一个playVideo事件监听(在net.shangle.event包中),主要就是点击List后的播放,然后设置VideoDisplay的source为List的当前点击项。因为设置过autoPlay所以直接播放。
4、返回按钮清空VideoDisplay的source属性
这个是原来的功能解析,说的挺简单的,大家自己看看代码应该不难。
下面我们进行些升级,这个升级的辅助环境需要先配置好,这里需要一个ADOBE的Flash Media Live Encoder和一个ADOBE的Flash Media Server。前一个用来编码推送,推送到后一个搭建的流媒体服务器中。然后在外部利用RTMP协议来获取推送内容。这里需要额外的三个对象:NetConnection、NetStream和Video对象。NetConnection对象用来连接到RTMP指定资源,NetStream对象用来获取连接成功后的数据流,Video对象用来加载NetStream数据,最后在VideoDisplay控件中append前面的Video对象来播放视频。这里粗糙的实现下这个功能代码:
videoInfoArr = new ArrayCollection([{videoID:1,catName:"默认",addTime:"2011年3月26日",title:"旅程的终点",content:"湿父,不给力啊",fileName:"201102221614.jpg",source:"upLoad/video/1.flv"},
{videoID:2,catName:"默认",title:"VS2010宣传片E1",addTime:"2011年3月26日",content:"做你的下一行Code",fileName:"201102221636.jpg",source:"upLoad/video/2.flv"},
{videoID:3,catName:"默认",title:"十胜石",addTime:"2011年3月26日",content:"为爱至死不渝",fileName:"201102221702.jpg",source:"upLoad/video/3.flv"},
{videoID:4,catName:"默认",title:"在线监控",addTime:"2014年5月29日",content:"摄像头监控",fileName:"video.jpg",source:"online"}]);
这里比原来的代码就多了最后videoID为4的一个条目,最后的source随便设置,当然也可以这里设定,后面获取,我这里采取了这里随意,后面指定的方式。
this.currentState = "play";
if(event.videoID<4)
videoDisplay.source = searchVideoByID(event.videoID);
else
{
connection = new NetConnection();
connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
connection.addEventListener(NetStatusEvent.NET_STATUS,netStatusHandler);
connection.connect("rtmp://172.16.1.2:1935/live"); //本机IP
}
这里加了个IF判断,主要为了区分开这个videoID为4的,也就是在线流媒体的视频。或者我们可以自定义添加一个属性用来区分各种类型的视频,如文件、VOD、LIVE等。如果是最后一条也就是流媒体视频,则进行connection连接。这里添加两个监听事件,一个是安全错误事件,一个是网络状态事件,安全错误事件代码就是显示错误信息:
private function securityErrorHandler(event:SecurityErrorEvent):void
{
Alert.show("securityErrorHandler: " + event);
}
主要是后面这个状态判断事件,查询后获知事件返回值列表如下:
代码属性 | 级别属性 | 意义 |
---|---|---|
"NetConnection.Call.BadVersion" | "error" | 以不能识别的格式编码的数据包。 |
"NetConnection.Call.Failed" | "error" | NetConnection.call() 方法无法调用服务器端的方法或命令。 |
"NetConnection.Call.Prohibited" | "error" | Action Message Format (AMF) 操作因安全原因而被阻止。AMF URL 与文件(其中包含调用 NetConnection.call() 方法的代码)不在同一个域中,或者 AMF 服务器没有信任文件(其中包含调用NetConnection.call() 方法的代码)所在域的策略文件。 |
"NetConnection.Connect.AppShutdown" | "error" | 正在关闭服务器端应用程序。 |
"NetConnection.Connect.Closed" | "status" | 成功关闭连接。 |
"NetConnection.Connect.Failed" | "error" | 连接尝试失败。 |
"NetConnection.Connect.IdleTimeout" | "status" | Flash Media Server 断开了与客户端的连接,因为客户端的闲置时间已超过了 <MaxIdleTime> 的配置值。 在 Flash Media Server 上,<AutoCloseIdleClients> 默认情况下处于禁用状态。 启用时,默认超时值为 3600 秒(1 小时)。有关详细信息,请参阅 关闭闲置连接。 |
"NetConnection.Connect.InvalidApp" | "error" | 对 NetConnection.connect() 的调用中指定的应用程序名称无效。 |
"NetConnection.Connect.NetworkChange" | "status" | Flash Player 检测到网络更改,例如,断开的无线连接、成功的无线连接或者网络电缆缺失。 使用此事件检查网络接口更改。不要使用此事件实现 NetConnection 重新连接逻辑。使用 |
"NetConnection.Connect.Rejected" | "error" | 连接尝试没有访问应用程序的权限。 |
"NetConnection.Connect.Success" | "status" | 连接尝试成功。 |
"NetGroup.Connect.Failed" | "error" | NetGroup 连接尝试失败。info.group 属性表示哪些 NetGroup 已失败。 |
"NetGroup.Connect.Rejected" | "error" | NetGroup 没有使用函数的权限。info.group 属性表示哪些 NetGroup 被拒绝。 |
"NetGroup.Connect.Succcess" | "status" | NetGroup 已构建成功并有权使用函数。info.group 属性表示哪些 NetGroup 已成功。 |
"NetGroup.LocalCoverage.Notify" | "status" | 当此节点负责的组地址空间的一部分发生更改时发送。 |
"NetGroup.MulticastStream.PublishNotify" | "status" | 当在 NetGroup 的组中检测到新命名的流时发送。info.name:String 属性是检测到的流的名称。 |
"NetGroup.MulticastStream.UnpublishNotify" | "status" | 当命名的流在此组中不再可用时发送。info.name:String 属性是已消失的流的名称。 |
"NetGroup.Neighbor.Connect" | "status" | 当邻域连接到此节点时发送。info.neighbor:String 属性是邻域的组地址。info.peerID:String 属性是邻域的对等 ID。 |
"NetGroup.Neighbor.Disconnect" | "status" | 当邻域与此节点断开连接时发送。info.neighbor:String 属性是邻域的组地址。info.peerID:String 属性是邻域的对等 ID。 |
"NetGroup.Posting.Notify" | "status" | 当收到新的 Group Posting 时发送。info.message:Object 属性是消息。info.messageID:String 属性是消息的 messageID。 |
"NetGroup.Replication.Fetch.Failed" | "status" | 当提取对象请求(之前已使用 NetGroup.Replication.Fetch.SendNotify 进行通知)失败或被拒绝时发送。如果仍需要此对象,则将重新尝试提取对象。info.index:Number 属性是已请求的对象的索引。 |
"NetGroup.Replication.Fetch.Result" | "status" | 当邻域满足了提取请求时发送。info.index:Number 属性是此结果的对象索引。info.object:Object 属性是此对象的值。此索引将自动从 Want 集中删除。如果此对象无效,可使用NetGroup.addWantObjects() 将此索引重新添加到 Want 集。 |
"NetGroup.Replication.Fetch.SendNotify" | "status" | 当 Object Replication 系统即将向邻域发送对象请求时发送。info.index:Number 属性是请求的对象的索引。 |
"NetGroup.Replication.Request" | "status" | 当邻域已请求此节点已使用 NetGroup.addHaveObjects() 进行通知的对象时发送。最终必须使用 NetGroup.writeRequestedObject() 或NetGroup.denyRequestedObject() 应答此请求。请注意答复可能会不同。info.index:Number 属性是已请求的对象的索引。info.requestID:int 属性是此请求的 ID,由NetGroup.writeRequestedObject() 或 NetGroup.denyRequestedObject() 使用。 |
"NetGroup.SendTo.Notify" | "status" | 收到定向到此节点的消息时发送。info.message:Object 属性是消息。info.from:String 属性是发送此消息的 groupAddress。如果由此节点消息发送,则info.fromLocal:Boolean 属性为TRUE (这意味着本地节点是距离目标组地址最近的节点);如果由其他节点发送消息,则为FALSE 。在 info.fromLocal 为 FALSE 的情况下,若要实现循环路由,则必须使用NetGroup.sendToNearest() 重新发送消息。 |
"NetStream.Buffer.Empty" | "status" | Flash Player 接收数据的速度不足以填充缓冲区。数据流在缓冲区重新填充(此时发送 NetStream.Buffer.Full 消息,流开始再次播放流)前处于中断状态。 |
"NetStream.Buffer.Flush" | "status" | 数据已完成流式处理,剩余缓冲区被清空。 |
"NetStream.Buffer.Full" | "status" | 缓冲区已满,流开始播放。 |
"NetStream.Connect.Closed" | "status" | 成功关闭 P2P 连接。info.stream 属性表示已关闭的流。 |
"NetStream.Connect.Failed" | "error" | P2P 连接尝试失败。info.stream 属性表示已失败的流。 |
"NetStream.Connect.Rejected" | "error" | P2P 连接尝试没有访问另一个对等方的权限。info.stream 属性表示被拒绝的流。 |
"NetStream.Connect.Success" | "status" | P2P 连接尝试成功。info.stream 属性表示已成功的流。 |
"NetStream.DRM.UpdateNeeded" | "status" | NetStream 对象尝试播放受保护的内容,但是所需的 Flash Access 模块不存在、有效内容策略不允许,或者与当前播放器不兼容。要更新模块或播放器,请使用 flash.system.SystemUpdater 的update() 方法。 |
"NetStream.Failed" | "error" | (Flash Media Server) 发生了错误,其他事件代码中没有列出此错误的原因。 |
"NetStream.MulticastStream.Reset" | "status" | 多播订阅已将焦点更改为同一组中使用同一名称发布的其他流。多播流参数的局部替换缺失。请重新应用局部替换,否则会使用新流的默认参数。 |
"NetStream.Pause.Notify" | "status" | 流已暂停。 |
"NetStream.Play.Failed" | "error" | 出于此表中列出的原因之外的某一原因(例如订阅者没有读取权限),播放发生了错误。 |
“NetStream.Play.FileStructureInvalid” | "error" | (AIR 和 Flash Player 9.0.115.0)应用程序检测到无效的文件结构,并且不会尝试播放此类型的文件。 |
"NetStream.Play.InsufficientBW" | "warning" | (Flash Media Server) 客户端没有足够的带宽,无法以正常速度播放数据。 |
“NetStream.Play.NoSupportedTrackFound” | "error" | (AIR 和 Flash Player 9.0.115.0) 应用程序未检测到任何受支持的轨道(视频、音频或数据),并且不会尝试播放此文件。 |
"NetStream.Play.PublishNotify" | "status" | 到流的初始发布被发送到所有的订阅者。 |
"NetStream.Play.Reset" | "status" | 由播放列表重置导致。 |
"NetStream.Play.Start" | "status" | 播放已开始。 |
"NetStream.Play.Stop" | "status" | 播放已结束。 |
"NetStream.Play.StreamNotFound" | "error" | 无法找到传递到 NetStream.play() 方法的文件。 |
"NetStream.Play.Transition" | "status" | (Flash Media Server 3.5) 服务器收到因位速率流切换而需要过渡到其他流的命令。此代码表示用于启动流切换的 NetStream.play2() 调用的成功状态事件。如果切换失败,则服务器将改为发送NetStream.Play.Failed 事件。当发生流切换时,将调度带有代码“NetStream.Play.TransitionComplete”的onPlayStatus 事件。用于 Flash Player 10 及更高版本。 |
"NetStream.Play.UnpublishNotify" | "status" | 从流取消的发布被发送到所有的订阅者。 |
"NetStream.Publish.BadName" | "error" | 试图发布已经被他人发布的流。 |
"NetStream.Publish.Idle" | "status" | 流发布者空闲而没有在传输数据。 |
"NetStream.Publish.Start" | "status" | 已经成功发布。 |
"NetStream.Record.AlreadyExists" | "status" | 正在记录的流映射到已经记录其他流的文件。由于错误配置了虚拟目录,会发生这种情况。 |
"NetStream.Record.Failed" | "error" | 尝试录制流失败。 |
"NetStream.Record.NoAccess" | "error" | 试图录制仍处于播放状态的流或客户端没有访问权限的流。 |
"NetStream.Record.Start" | "status" | 录制已开始。 |
"NetStream.Record.Stop" | "status" | 录制已停止。 |
"NetStream.Seek.Failed" | "error" | 搜索失败,如果流处于不可搜索状态,则会发生搜索失败。 |
"NetStream.Seek.InvalidTime" | "error" | 对于按渐进方式下载的视频,用户已尝试跳过到目前为止已下载的视频数据的结尾或跳过视频的结尾(当整个文件已下载后)进行搜寻或播放。事件对象的 info.details 属性包含一个时间代码,该代码表示用户可以搜索的最后一个有效位置。 |
"NetStream.Seek.Notify" | "status" | 搜寻操作完成。 当对 AS3 NetStream 数据生成模式中的流调用 |
"NetStream.Step.Notify" | "status" | 步骤操作完成。 |
"NetStream.Unpause.Notify" | "status" | 流已恢复。 |
"NetStream.Unpublish.Success" | "status" | 已成功执行取消发布操作。 |
"SharedObject.BadPersistence" | "error" | 使用永久性标志对共享对象进行了请求,但请求无法被批准,因为已经使用其他标记创建了该对象。 |
"SharedObject.Flush.Failed" | "error" | “待定”状态已解析,但 SharedObject.flush() 失败。 |
"SharedObject.Flush.Success" | "status" | “待定”状态已解析并且 SharedObject.flush() 调用成功。 |
"SharedObject.UriMismatch" | "error" | 试图连接到拥有与共享对象不同的 URI (URL) 的 NetConnection 对象。 |
所以我这里就判断下返回的CODE里有没有“Success”(当然这个判断很粗糙,自己完善下),如果Success则进行下一步的数据获取和加载:
private function netStatusHandler(event:NetStatusEvent):void{
if(event.info.code.toString().indexOf("Success")>0)
{
video = new Video();
video.width = 240;
video.height = 320;
stream = new NetStream(connection);
video.attachNetStream(stream);
stream.play("audioStream");
videoDisplay.addChild(video);
}
}
测试后发现返回按钮无效了,这个应该是因为原来的退出是用清空videoDisplay 的source属性来实现的,而这里采用了网络流,所以修改返回事件:
private function returnToListHandler() : void
{
if(connection!=null && connection.connected)
{
connection.close();
stream.close();
stream.dispose();
video.clear();
videoDisplay.removeChild(video);
playAndStop.selected = false;
this.currentState = 'list';
}
else
{
videoDisplay.stop();
videoDisplay.source = null;
playAndStop.selected = false;
this.currentState = 'list';
}
}
这里的判断主要是判断当前的连接是否有实例存在,并且该实例是连接着的,如果是就清空所有资源,然后返回list状态;否则的话就是普通文件视频,直接清空videoDisplay,并返回列表。以前用过windows的media server,功能类似,甚至连界面也类似(我能说ADOBE借鉴微软吗?),好处就是视频格式可以直接输出flv,因为现在的FLV格式比window下的WMV更为流行,所以我们就当这个好吧。
到这里本学期课程收工,若有后续,纯属杂谈……并衷心祝愿大家学有所得,再简单再少的得也是一种成就……