Red5入门教程

joliny

贡献于2010-09-14

字数:0 关键词: Red5 流媒体服务器

作者:周英 科 email:li_li_li87222@163.com.qq:543246541 1 作者 :周英 科 email:li_li_li87222@163.com.qq:543246541 Red5Red5Red5Red5 入 门 教程 简介 : 在flex,java 盛行 天下时 red5把 二者 连为 一体 成 为更 强的 强者 , 为即 时通 信, 流媒体 开 发, 网络 在线 游戏 提供了 一个 简单 易行的 方案 。 越 来 越 多的公 司把 这个 方案当 成了 首先 , 熟 悉 相 关技 术的 人才 的缺少 也就 成了 发展的 障碍 ,而 相关资 料的 奇缺 成了技 术人 员成 长的障 碍。 本书 注重 实用 ,着 眼入门 , 用大量 实际 的例 子力求 带领 您进入 flex,red5 结合 开发 的天 堂 。 没一 个列 子都 是精心 挑选 , 每 一 个 列子都 代表 着一 个知识 点, 每 一 个列 子都 将成为 您以 后 项 目的一部分。当然这是入门级别的书籍,不可能把所有的相关知识都讲到, java,flex,spr ing,mina 等等 等等都 red5相关 , 如 果要 对每 一个点 讲解 那将 是一个 系列 , 而 不 是 一本 书。为 了突出 重点 ,本书 只讲解 把这些 联系起 来的 纽扣 red5,并 讲解如 何利用 red5开 发项 目。 内容 包括 red5的安 装, red5开发 中各种 概念, 各种 问题的 解决方 案,开 发工具 的使 用等 等, 但 有 详有 略, 如 工 具的 使用只 讲解 了书 本中需 要用 到的 相关知 识。 最 后 书本还 有数 个 完 整的 列子 ,也 是实际 开发 中常 用的列 子, 如聊 天程序 ,播 放视 频程序 。 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 2 目录: 一. Red5 介绍及安装: Red5 介绍 安装 red5 二. 编写运行第一个程序 编写服务器端 编写客户端 运行自己编写的程序 三.远程调用 客户端调用服务器端方法 Red5 调用客户端方法 遍历所有连接到服务器端 的用户 好友上线通知 四. sharedObject 共享对象 sharedObject 介绍 游戏中移动同步的原理和 简单实现 1 五. 服务器执行计划 六. 录制播放视频 播放服务器端视频 录制视频 设置视频保存位置 七. 利用 scope,room 管理客户端 八. 视频播放程序 九. 简单聊天程序 附录:开发工具的使用 1 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 3 一. Red5Red5Red5Red5介绍及安装 1. Red5介绍 Red5是一 个采用 Java开 发开 源 免费 的 的Flash流 媒体 服务 器 ,功 能和 Adobe的fms(Flash Media Server)相同,可以 上 官方 网站 http://www.osflash.org/red5免 费下 载并 使用 。 它支 持把 音频( MP3) 和 视频 ( FLV) 转换 成播 放流 , 在下 载的 同时 播放 流 ;录 制客 户端 播放 流( 只支持 FLV), 把摄 像头 ,麦 克 风等 传入 的视 频音 频录 制保 存到 服务 器 ;共享对象 ;现场直播 流发 布;远程调 用。 Red5使用 RSTP作为 流 媒体 传输 协议 。 Red5的 功能 使其 在许 多领 域得 到应 用。 如视 频播 放网 站, 远程 教育 ,视 频会 议程 序, 聊天 程序 ,网 络 游 戏等 等。 免费 开源 使软 件更 加容 易扩 展, 下载后你 可以 对源 代码 进行 修改 ; 更加经 济, 比 起 fms高 昂的 费用 red5 能为 一般 的应 用节 约大 笔费 用; 服务器端 的 java语 言比起 fms服 务器 端的 actionscript2语 言更 加面 向 对 象 更加 成熟 。这 使得 red5还 没到 版本 1就 已经 红遍 世界 。 2.red5 安装 第一 步 上java.sun.com下载 jdk6并 安装 。 如 果不 是安 装在 默认 路径 请设置 classpath和path。设 置classpath和path的 方法 请参 考其他 java 的资 料 。 第二 步 上http://www.osflash.org/red5下载 Red5 v0.7.0 Final 的window安 装版 。点 击下 载到 的exe文 件即 开始 安装 ,安 装过 程中 选择 要把 red5安 装到 的目 录。 安装 结束 后打 开浏 览器 输入 http://localhost:5080/如 果能 打开 显示 “Red5 Test Page”表 示安 装成 功。 安装 成功 后可 以运 行查看 red5自 带的 例子 。 第三 步 red5的 启动 和关 闭。 安装 版的 red5默 认情 况下 会在 计算 机启 动时 启动 ,如 果想 关闭 自启 动可 以 右 击我 的电 脑 ->管理->服 务和 程序 ,找到 red5的 那项 把启 动方 式的 自动 启动 改为 手动 或其 他的 。更 改了 启 动方 式后 可以 找到 red5的 安装 目录 下的 wrapper目 录下的 Red5.bat 文 件, 双击 即可 启动 ,这 样可 以 从 窗口 看到 客户 端连 接的 情况 。关 闭窗 口即 可关闭 red5, 也可 以双击 StopRed5-NT.bat关闭 服务 程序 。 二. 编写运行第 一个程 序 第 一个 程序 的运 行是 学习 的莫 大回 报, 也是 继续 下面 学习 的关 键, 只有 顺利 的运 行了 第一 个程 序才 会 更 加信 心百 倍的 去学 习更 深一 步的 知识 。 Red5+flex 或red5+flash 的 项目 一般 都包 括服 务器 和客 户端 俩个 部分 ,服 务器用 java, 客户 端用 flex 或flash。 编写 并编 译完 服务 器端 代码 后需 要把 服务 器的 的应 用部 署到 red5的webapps目 录下 这和 传 统的 java应 用没 区别 ,客 户端 可以 直接 点击 flash文 件运 行。 下 面开 始第 一个 程序 的编 写, 它分 成服 务器 和客 户端 俩部 分 ,以 后的 程序 也都 安这 种方 式分 。 1.编 写服 务器 端 打开 eclipse 新建 java 工 程或 javaee 工程 chapter2( 如果 不熟悉 eclipse 请 参考 附件 eclipse 的 使用 ) 。 把 red5安 装目 录下的 red5.jar以及 lib 目 录下的 jar 都 添加 到工 程的 类库 中。 新 建包 first, 然后 新建 类, 类名 称为 Application 并 继承 ApplicationAdapter。 类的 代码 如下 : package first; import org.red5.server.adapter.ApplicationAdapter; import org.red5.server.api.IConnection; public class Application extends ApplicationAdapter { public boolean appConnect(IConnection conn, Object[] args) { 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 4 System.out.println("连接"); return true; } public String change(String str){ System.out.println("客 户端 调用 服务 器 "); return str.toUpperCase();// 传 入的 字符 串转 换成 大写 后返 回 } } 2.编写 客户 端 打开 flexbuilder3 新建 flex 工 程 (具 体 flexbuilder 的 使用 请参 考附 录 ) , 名字取 名 为 chapter2。 打开 项目中 chapter2.mxml。chapter2.mxml 的代 码如 下: 3.部署 运行 程序 进入 red5的安 装目 录下的 webapps下,复制test文 件夹 , 把复制 的文 件夹 改 名 为 chapter2, 删除 chapter2\WEB-INF 目录 下的 文件 夹。 把服 务器 项目 下的 classes目录 下的 文件夹 first 拷贝到 chapter2\WEB-INF 下。 把red5-web.properties 中的 /test替换 为 /chapter2。 把red5-web.xml 中的删除 。 把org.red5.server.webapp.test.Application 替换为 first.Application。 把web.xml 中的/test替换为/chapter2 把 /tlds/c/WEB-INF/tlds/c.tld 删除 注意:webapps下的 文件 夹名 chapter2,red5-web.properties 中的 chapter2,web.xml中的 chapter2 要保 持相 同, 如果一 个改 了, 其他的 也改 成相 同的, 所有 以后 的工程 都这 样。 重新 启动 red5 在flexbuilder3 中选择 运行菜单中 的运行项 运行 chapter2。在文 本框里输入 字符串, 点击连 接按 钮, 然后 点击调 用方 法按 钮。上 面如 果显 示出输 入框 里的 字符串 的大 写表 示运行 正常 。 服务器端 类有俩个方法, appConnect类从 ApplicationAdapter 继承来 ,当 flash连 接 时触 发 , 可以 返回 true 或false。True表示 接受 客户 端的请 求 ,false 表示 拒绝 客户 端的请 求。 如果 拒绝那 么以后 flash和服 务器 端的 交互 服务 器都 不会 理会 , 所以当 想拒 绝某 些 ip的 请求 时只 需有 在用 户连 接时 检查 它的 ip 是否 在拒绝 ip 之内 ,如 果在 就返回 false,那 样就 可以 拒之门 外了 。 change是自 己定 义的 ,客户 可以 直 接调 用的 一个 远程方 法。 作用 是把客 户传 入的 参数变 成大 些后 返回, 此处 目的 在于运 行一个 red5 和flex 交 互的 过 程 ,并 没有 检查 传入 的参 数是 否有 大写 或都 已经 是大 写。 客 户端 的代 码稍 多些 ,位 于 之 外的 是图 形界 面的 代 码, 包括 俩个 按钮 ,一 个输 入框 ,一 个显 示文 本, 这就 不详 细讲 解了 ,注 意给 按钮 添加 事件 监听 器。 过 程 是这 样的 ,用 户点 击连 接, 按钮 的监 听器 clickConnect响应 , conn.connect(rtmpURL)连 接到 服务 器 , 在服 务器 和客 户端 建立 一条 信息 交流 的通 道。 当 这 条通 道打 通时 netStatus 执 行, 把 是否 是打 通的 开 关isConnectSuccess设 置为 通的 。当 用户 再点 击调 用按 钮时 ,通 过这 条通 道调 用服 务器 端的 方法 conn.call("c hange",responder,str.text) 。 传给 服务 器字 符串 str.text, 当服 务器 端方 法执 行完 后把 返 回 值给 responder定 义时 的方法 resultFun, 这样 一个 客户 端与 服务 器交 互的 过程 完成 。 三. 远程调用 通过 red5服务 器端和 客户端 可以 直接通 过方法 调用来 交互, 这是 非常方 便的( 想想你 在一 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 6 个类 里面 方法 调用发 方便 性吧 ) , 服 务器 调可 以用 客户端 的方 法, 客户端 也可 以调 用服务 器 端的 方法 。其 实上面 的例 子就 是通过 方法 调用 实现的 。 1.客户 端调 用服 务器端 方法 通过 red5可以 从客 户端 直接调 用服 务器上 java 编写 的方 法。 调用时 指明 被调 用的方 法 名称 ,如果有 返回值 则需要指 明返回 值处理的 responder,如 果被调用 的方法 有参数则 需要 传 入参 数。 可以 引用 第一 章的例 子, conn.ca ll( "change " "change " "change " "change " ,respon der,s tr.t ext) ; 表示客 户端 调用 服务器 端的 名称为 change的 方法 , 查 看 java 中change的定义 public public public public String change(String str){//函数体 }发现参 数 是 java 中String 类型的 ; 调 用时 传 入 的 str.text是 actionscript 中String 类型;假如 change有多个入口参数, 则可以把参数列在 str.text 后面, 并用 '',"隔开 。 返 回 值由 responder 处理 , change返回 值是 String 类型 的, 要求 responder 定义 时的 函数 resultF un 的入 口参 数是 String 类型 。 调用 过程 中需 要注意 的是 参数 类型的 对应 。具 体可以 看下 列表 表说 明假如 java 传给 flash 的参 数是 自定义 Bean类型 时, 客户 端接收 到的是 Object 类型 当被 调用 的方 法没有 返回 值时把 responder 设置为 null 。 具 体 怎么 实现就 不再 雷述 , 请 看第 二章 的例 子。 2.服务 器调 用客 户端方 法 不带 返回 的调 用 新建 eclipse 工程 chapter3,并建 立 包 first,在 包 里 新 建 一 个 类 Application 并继 承 ApplicationAdapter。Application 到代 码如 下: package first; import org.red5.server.adapter.ApplicationAdapter; import org.red5.server.api.IConnection; import org.red5.server.api.service.IServiceCapableConnection; public class Application extends ApplicationAdapter { @Override public boolean appConnect(IConnection arg0, Object[] arg1) { //TODO Auto-generated method stub callClient(arg0); return true; } private void callClient(IConnection conn){ if (conn instanceof IServiceCapableConnection) { IServiceCapableConnection sc = (IServiceCapableConnection) conn; sc.invoke("clientMethod", new Object[]{"One", 1}); Java actions cript null null int/flo at Number double Double boolean Boolean String String List Array Map Object Bean Object 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 7 } } } 复制 webapps下的 chapter2 文 件夹 , 并 改 名为 chapter3,把 工程下 class 目 录下的 first 拷 贝覆 盖以 前 的first ,把red5-web.properties 中的 /chapter2,替换 为 /chapter3。把 web.xml 中的 /chapter2替换 为 /chapter3 重启 red5。 新建 chapter3客户 端项 目 ,chapter.mxml 代码 如下 : 点击 调试 程序 运行客 户端 ,然 后点击 连接 按钮 可以发 现输 出 “接收 One2”表示 服务 器调 用 客户 端到 方法 成功。 服务 器端 还是 只有俩 个方 法, 当客户 端连 接时 服务器 调用 appConnect,在 appConnect里 调用 callClient 。在 callClient 中 服务 器调 用客 户端 的方法 clientMethod,并传给 客户 端俩 个参 数,一 个 字 符类 型, 一 个 数字 类型 。 只有 IServiceCapableConnection 类 型的 连接 才可 以调 用客 户端 方法 , 所 以 要 先对 连接 类型 进行 强制 转换 。 再 看客 户端 ,有 三个 方法 ,因 为不 需要 处理 连接 状态 的变 化事 件所 以用 个空 方法 以便 简单 突出 重点 。用 户 点击 按钮 连接 ,调用 clickConnect 方 法连 接服 务器 。还 有一 个方 法给 服务 器调 用的 ,这 个方 法附 着在 conn.client 上。 因为 ActionScript3 中NetConnection 是封 闭的, 无法 直接把 方法附 着在其 上,但 他 的 一个 属性 client 是Object类 型的 ,是 动态 的。 服务 器不 但可 以调用 客户 端的 方法, 还可 以把 客户端 方法 处理 的值返 回给 服务 器。 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 8 理服 务器 调用 客户端 方 法有返回 值就 就必须 实现 IPendingServiceCallback 接口 , 并 调 用方 式 改为sc.invoke("clientMethod", new Object[]{"One", 1},this);this 是任意一个实现 IPendingServiceCallback 接口 的类 , 在 接 口的 resultReceived 方法 中处 理返 回值。 现 在 把上 面 的类 改成 下面 样子 package first; import org.red5.server.adapter.ApplicationAdapter; import org.red5.server.api.IConnection; import org.red5.server.api.service.IPendingServiceCall; import org.red5.server.api.service.IPendingServiceCallback; import org.red5.server.api.service.IServiceCapableConnection; public class Application extends ApplicationAdapter implements IPendingServiceCallback{ @Override public boolean appConnect(IConnection arg0, Object[] arg1) { callClient(arg0); return true; } private void callClient(IConnection conn){ if (conn instanceof IServiceCapableConnection) { IServiceCapableConnection sc = (IServiceCapableConnection) conn; sc.invoke("clientMethod", new Object[]{"One", 1},this); } } public void resultReceived(IPendingServiceCall arg0) { System.out.println("来 自客 户端 到返 回: "+arg0.getResult()); } } 把客 户端 的 private function clientMethod(str:String,num:Number):void{ Alert.show("接收"+str+(num+1)); } 改成 private function clientMethod(str:String,num:Number):String{ Alert.show("接收"+str+(num+1)); Return "客 户端 返回 来的 字符 串 "; } 测试 可以从 red5的框 里看 到输 出 “客 户端 返回 来的 字符 串 " 3.遍 历所 有连 接到 服务 器端 的用 户 遍历 所有 链接 到服务 器的 客户 端是常 常的 事, 如 好 友上线 , 则 要及 时把 这个 消息通 知 给 在线 的人 员。 Red5通过 IConnection.getscope()得到 所在 scope, 通过 scope 可以 得到 连接 到这个 scope 的所 有客户 的连接 。在 得到连 接后就 可以通 过连接 调用 客户端 方法。 如调用 每个客 户端的 clientMethod 方法 一遍 可以 把服务 器改 成下 面的样 子 package chapter2; import java.util.Iterator; 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 9 import org.red5.server.adapter.ApplicationAdapter; import org.red5.server.api.IConnection; import org.red5.server.api.IScope; import org.red5.server.api.service.IPendingServiceCall; import org.red5.server.api.service.IPendingServiceCallback; import org.red5.server.api.service.IServiceCapableConnection; public class Application extends ApplicationAdapter implements IPendingServiceCallback{ @Override public boolean appConnect(IConnection arg0, Object[] arg1) { this.callEvery(arg0.getScope()); return true; } private void callEvery(IScope scope){ Iterator it=scope.getConnections(); while(it.hasNext()){ this.callClient(it.next()); } } private void callClient(IConnection conn){ if (conn instanceof IServiceCapableConnection) { IServiceCapableConnection sc = (IServiceCapableConnection) conn; sc.invoke("clientMethod", new Object[]{conn.getSessionId(), 1},this); } } public void resultReceived(IPendingServiceCall arg0) { System.out.println("来 自客 户端 到返 回: "+arg0.getResult()); } } 把 服务 器端的 class 覆 盖以 前的 文件 ,运 行客 户端 可以 看到 有一 个新 的客 户连 接时 每个 在线 的客 户端 会弹 出 新上 线用 户的 用户 id 四.shareObjectshareObjectshareObjectshareObject共 享 对象 共 享对 象 游 戏中 同步 的原 理 同 步的 简单 实现 共 享对 象分 为本 地和 远程 俩种 , 本 地的 可以看 adobe官方 文档 ,很详细 ,这里就讲 解远 程的 。远程 共 享对 象是 供指 定客 户端 群共 有的 数据 。就如你家 的钱 包是 你和 你爱 人共 有的 一样(某些 特殊 除外 ) , 可以 随 便花 , 一个人 少了 , 代表另 一个 也少 了,但是也有 限制 , 不是每个 人都 可以 花 (我就 不能 花你 家钱 包的 钱 ), 只 有指 定有 权限 的人 才可 以。 要花 钱先 得获 得钱 包, 然后 还要 打开 钱包 。共 享对 象为 数据 共享 提供 了很 大 的 方便 ,因 为数 据改 变时 会在 每个 客户 端同 步而 不用 人去 干预 太多 。 下 面以 一个 移动 同步 的例 子讲 解, 效果 是移 动方 块, 所有 其他 浏览 器中 的的 方块 都同 时改 变位 置。 新 建服 务器 项目 chapter4, 并新 建类 ,代 码如 下 package first; import org.red5.server.adapter.ApplicationAdapter; 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 10 import org.red5.server.api.IConnection; public class Application extends ApplicationAdapter { @Override public boolean appConnect(IConnection arg0, Object[] arg1) { return true; } } 修 改把 red5-web.xml ,web.xml, red5-web.properties 中的 chapter3替 换为 chapter4重启 red5. 新建 flex 应用代 码如 下 运 行俩个 flash客 户端 ,在 一个 里面 拖动 框, 看另 一个 框是 否同 步改 变位 置, 如果 是则 正常 。 shareObject应 用时 客户 端要 先用 SharedObject.getRemote("point",conn.uri,true)获 取服 务器 端 的 一个 共享 对象 ;然 后用 so.connect(conn)连 接对 象来 同步 ;最 后通过 so.addEventListener( SyncEvent.SYNC,syncro)可以 响应 共享 对象 的变 化。 服务器只 响应 客户 端的 连接 , 没有任 何其 他的 代 码。 如 果要 在服 务器 端处 理共 享对 象则 通过 服务 器端的 ISharedObject接 口实 现。 为了 演示 服务 器端 对共 享 对 象的 控制 把服 务器 端的 代码 改成 如下 package chapter4; import org.red5.server.adapter.ApplicationAdapter; import org.red5.server.api.IConnection; import org.red5.server.api.IScope; import org.red5.server.api.so.ISharedObject; public class Application extends ApplicationAdapter { @Override public boolean appConnect(IConnection arg0, Object[] arg1) { return true; } @Override public boolean appStart(IScope arg0) { System.out.println("appStart 程 序启 动 "); this.createSharedObject(arg0, "point", true); ISharedObject so=this.getSharedObject(arg0, "point"); if(so!=null) so.addSharedObjectListener(new ShareObjectListener()); else System.out.println("point 是null"); return true; 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 12 } } 并 添加 类 package chapter4; import java.util.List; import java.util.Map; import org.red5.server.api.IAttributeStore; import org.red5.server.api.so.ISharedObjectBase; import org.red5.server.api.so.ISharedObjectListener; public class ShareObjectListener implements ISharedObjectListener { public void onSharedObjectClear(ISharedObjectBase arg0) { System.out.println("onSharedObjectClear"); } public void onSharedObjectConnect(ISharedObjectBase arg0) { System.out.println("onSharedObjectConnect"); } public void onSharedObjectDelete(ISharedObjectBase arg0, String arg1) { System.out.println("onSharedObjectDelete"); } public void onSharedObjectDisconnect(ISharedObjectBase arg0) { System.out.println("onSharedObjectDisconnect"); } public void onSharedObjectSend(ISharedObjectBase arg0, String arg1, List arg2) { System.out.println("onSharedObjectSend"); } public void onSharedObjectUpdate(ISharedObjectBase arg0, IAttributeStore arg1) { System.out.println("onSharedObjectUpdate"); } public void onSharedObjectUpdate(ISharedObjectBase arg0, Map arg1) { System.out.println(" onSharedObjectUpdate"); } public void onSharedObjectUpdate(ISharedObjectBase arg0, String key, Object value) { System.out.println("更 新共 享对 象的 值 "+key+":"+value); } } 把 编译 好的 文件 放到 red5的 应用 下, 重启 red5。 再允 许客 户端 则每 次移 动都 可以 看到 移动 到的 位置 五 . 服务 器自动 执行 计划 可 以做 服务 器端 添加 脚本 来定 时执 行一 些语 句, 如调 用客 户端 的某 个函 数或 者清 空某 些共 享对 象。 新 建服 务器包 chapter5, 新建类 Application, 代码 如下 : package chapter5; 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 13 import java.util.Iterator; import org.red5.server.adapter.ApplicationAdapter; import org.red5.server.api.IConnection; import org.red5.server.api.IScope; import org.red5.server.api.scheduling.IScheduledJob; import org.red5.server.api.scheduling.ISchedulingService; import org.red5.server.api.service.IServiceCapableConnection; public class Application extends ApplicationAdapter implements IScheduledJob{ String jobID; @Override public boolean appConnect(IConnection arg0, Object[] arg1) { return true; } @Override public boolean appStart(IScope arg0) { jobID=this.addScheduledJob(60000, this); return true; } private void callEvery(IScope scope){ Iterator it=scope.getConnections(); while(it.hasNext()){ this.callClient(it.next()); } } private void callClient(IConnection conn){ if (conn instanceof IServiceCapableConnection) { IServiceCapableConnection sc = (IServiceCapableConnection) conn; sc.invoke("clientMethod", new Object[]{conn.getSessionId(), 1}); } } public void execute(ISchedulingService arg0) throws CloneNotSupportedException { System.out.println("运 行计 划 "); this.callEvery(this.getScope()); } } 把 编译 后的 文件 放到 red5下 。重启 red5。 新建 flex 应 用, 代码 如下 : 运 行客 户端 ,点 击连 接, 则每 隔一 段时 间会 弹出 窗口 提示 没有 注册 。 六.录制播放视 频 1.播放 服务 器端 视频 新建 服务 器包 chapter6,并新 建类 Application,代 码如 下: package chapter6; import org.red5.server.adapter.ApplicationAdapter; import org.red5.server.api.IConnection; public class Application extends ApplicationAdapter { public boolean appConnect(IConnection arg0, Object[] arg1) { return true; } } 把编 译后 的文 件放到 red5下, 重启 red5。 编写 客户 端, 新建 flex 应用 ,代 码如 下 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 15 另 外新 建类 StreamClient 代 码如 下 package { public class StreamClient { public function StreamClient() { } public function onMetaData(info:Object):void{ for(var n:* in info){ trace(n+":"+info[n]); } } public function onPlayStatus(info:Object):void{ for(var n:* in info){ 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 16 trace(n+":"+info[n]); } } } } 把一个 a.flv 的视 频文 件放 到 \webapps\jiaocheng\streams下, 运 行 客户 端既可 以看 到播 放视 频 2.录制 视频 新建 客户端 flex 应用 ,代码 如下 : 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 17 运行 客户 端, 点 击 视频可 以看 到自 己的视 频, 点 击 录制 可以 把视频 保存 到服 务器上 。 如 果 没 有视 频只 有麦 克风则 点击 视频 看不到 效果 , 但 还 是 可以录 制视 频, 只 是 是声音 而已 。 录 制 的 视频 保存 在 \webapps\jiaocheng\streams下。 3.设置 视频 保存 位置 录 制的 视频 往往 比较 多,与 red5放 同一 个目 录有 点不 太合 适, 那 么 该 怎么 把录 制的 视频 , 播 放 的视 频目 录 放 到其 他的 文件 夹或 分区 呢? Red5要 求实现 IStreamFilenameGenerator接 口, 并在 接口 里面 设置 位 置。 新 建服 务器 类, 代码 如下 : package chapter6; import org.red5.server.api.IScope; import org.red5.server.api.stream.IStreamFilenameGenerator; public class PathBean implements IStreamFilenameGenerator { public String recordPath = "streams/"; public String playbackPath ="streams/"; public String generateFilename(IScope scope, String name, GenerationType type) { return this.generateFilename(scope, name,null, type); } public String generateFilename(IScope scope, String name, String extension, GenerationType type) { String filename; if (type == GenerationType.RECORD) filena me = recordPath + name; else filena me = playbackPath + name; if (extension != null) filena me += extension; return filename; } public String getRecordPath() { return recordPath; } public void setRecordPath(String recordPath) { this.recordPath = recordPath; } public String getPlaybackPath() { return playbackPath; } public void setPlaybackPath(String playbackPath) { 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 18 this.playbackPath = playbackPath; } public boolean resolvesToAbsolutePath() { //TODO Auto-generated method stub return true; } } 在red5-web.xml 中 添加 下面 bean 其中 E:\streams\可 以改 成你 计算 机中 的任 意文 件夹 。 把编 译后 的文 件放到 red5下 , 运行 red5重启 , 运 行 客户 端应用 Record。 点击 录制 ,即 可在 指定 的文 件目 录下 看到 录制 的视 频。 同样 也可 以播 放指 定目 录 下 的视 频文 件。 七.ScopeScopeScopeScope与roomroomroomroom讲解 Red5有 范围 之分 ,就如 jsp 中 的范 围概 念。 Red5中 的范 围分成 application, room, place, lobby。 但 是他 们都 是一 样的 东西 scope。scope嵌 套, 最 上 的称为 Application, 也 是 默认 连接 到应 用时 的范 围 , 连 接到 Application 的url 是rtmp://localhost/appname/。Application 里 面的 子范 围称为 room连 接的 url 是rtmp://localhost/appname/roomnum/。 当然 要连 接到 子范 围必 然会 先连 接到 父范 围。 在 每个 范围 中保 存着 自己 的连 接的 信息 , sharedobject等 。下 面以 一个 列子 说明 scope的 应用 。这 个列 子 很简 单, 客户 端连 接到 各种 范围 ,服 务器 在客 户端 连接 时把 自己 范围 内的 客户端 id 打 印出 来。 服 务器 端代 码: package chapter7; import java.util.Set; import org.red5.server.adapter.ApplicationAdapter; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.IScope; public class Application extends ApplicationAdapter { @Override public boolean appStart(IScope arg0) { System.out.println("启动 appStart"); return true; } @Override public boolean appConnect(IConnection arg2, Object[] arg1) { IScope arg0=arg2.getScope(); System.out.println("连接 到 "+arg0.getName()+"ID 列表 : "); Set i=arg0.getClients(); for(IClient c:i){ System.out.println(c.getId()); } 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 19 return true; } @Override public boolean roomStart(IScope arg0) { System.out.println("启动 roomStart"); return true; } @Override public boolean roomConnect(IConnection arg2, Object[] arg1) { IScope arg0=arg2.getScope(); System.out.println("连接 到 "+arg0.getName()+"ID 列表 : "); Set i=arg0.getClients(); for(IClient c:i){ System.out.println(c.getId()); } return true; } } 客 户端 代码 : 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 20 打 开三 个客 户端 ,点 击各 个按 钮看 服务 器端 的输 出。 八....视频播放 这 章将 利用 以前 的知 识做 一个 在线 音乐 视频 播放 的程 序。 当连 接到 服务 器后 会把 服务 器端 的视 频列 表显 示 出来 ,当 用户 点击 后播 放。 尽管 功能 简陋 ,但 稍加 改进 就可 以成 为产 品。 程 序分 服务 器端 和客 户端 。 服 务器 端在 第七 章的 基础 上改 进, 新建类 StreamService。 代码 如下 package chapter7; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Locale; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.red5.server.api.IScope; import org.red5.server.api.Red5; import org.springframework.core.io.Resource; public class StreamService { /** * Getter for property 'listOfAvailableFLVs'. * *@return Value for property 'listOfAvailableFLVs'. */ public Map getListOfAvailableFLVs() { IScope scope = Red5.getConnectionLocal().getScope(); Map filesMap = new HashMap(); Map fileInfo; try { Resource[] flvs = scope.getResources("streams/*.flv"); 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 21 if (flvs != null) { for (Resource flv : flvs) { File file = flv.getFile(); Date lastModifiedDate = new Date(file.lastModified()); String lastModified = formatDate(lastModifiedDate); String flvName = flv.getFile().getName(); String flvBytes = Long.toString(file.length()); fileInfo = new HashMap(); fileInfo.put("name", flvName); fileInfo.put("lastModified", lastModified); fileInfo.put("size", flvBytes); filesMap.put(flvName, fileInfo); } } Resource[] mp3s = scope.getResources("streams/*.mp3"); if (mp3s != null) { for (Resource mp3 : mp3s) { File file = mp3.getFile(); Date lastModifiedDate = new Date(file.lastModified()); String lastModified = formatDate(lastModifiedDate); String flvName = mp3.getFile().getName(); String flvBytes = Long.toString(file.length()); fileInfo = new HashMap(); fileInfo.put("name", flvName); fileInfo.put("lastModified", lastModified); fileInfo.put("size", flvBytes); filesMap.put(flvName, fileInfo); } } } catch (IOException e) { e.printStackTrace(); } return filesMap; } private String format Date(Date date) { SimpleDateFormat formatter; String pattern = "dd/MM/yy H:mm:ss"; Locale locale = new Locale("en", "US"); formatter = new SimpleDateFormat(pattern, locale); return formatter.format(date); } } 作者:周英 科 email:li_li_li87222@163.com.qq:543246541 22 把 编译 后的 文件 拷贝到 red5下 ;修改 red5-web.xml, 添加 bean 配置 删除 id 是streamFilenameGenerator 的bean 配 置。在 streams 下 放几个 mp3 和flv 格 式的 文件 。 重启 red5。 新建 Flex Application 代 码如 下: 运 行客 户端 ,可 以看 到一 streams下 的文 件的 名字 。点 击既 可以 播放 。 附录 : Eclipse的使 用 新 建工 程: 从 菜单 栏中 选择 文件 菜单 ( file) ,然后选 择新 建( new) 。从新建 的类 型里 面选 择 java 项目 (java project) 设置 项目 名称 和保 存的 路径 后点 击确 定然 后点 击下 一步 下一 步就 行了 。 添加 库: 点击新建 的项 目, 选择菜单 栏的 工程 ( project),选择properties项, 左边选 择 java build path, 右 边选择 liberareis 面 板, 点击 add external jar,找 到需 要添 加的 jar, 点击 确定 。 Flexbuilder 的使 用 新 建工 程: file-->new-->new Flex project-->填 入工 程名 字 -->finish 运行 : ctrl+f11 调试 : f11。 调试 可以 看到 trace();语 句的 输出 。

下载文档,方便阅读与编辑

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 20 金币 [ 分享文档获得金币 ] 11 人已下载

下载文档

相关文档