Flash Player作为流媒体的表现形式之一,视频编码是其最大的特色。.flv文件是Flash Player基本的视频文件格式,可以在Flash Player运行时加载,不被编译到虚拟机中,这就大大减小了Flash Player文件的体积,增加了Flash Player视频文件在网络上传输的速度。
21.1 视频类
在ActionScript 3.0中,提供了一个Video类,用来处理视频。使用Video类可以控制基本的视频文件功能比如编码、滤镜等。
通过使用Video类的属性和方法,可以在程序中直接显示实时的视频流,而不用把视频文件编译到Flash Player视频文件中。其常用的属性如表21.1所示,常用的方法如表21.2所示。
表21.1 Video类常用的属性
|
属 性 |
说 明 |
|
deblocking |
指示作为后处理的一部分应用于已解码视频的滤镜的类型 |
|
smoothing |
指定在缩放视频时是否应进行平滑处理(插补数据) |
|
videoHeight |
以像素为单位指定视频流的高度 |
|
videoWidth |
以像素为单位指定视频流的宽度 |
表21.2 Video类常用的方法
|
方 法 |
说 明 |
|
attachCamera |
指定在应用程序窗口中Video对象的边界内显示来自摄像头的视频流 |
|
attachNetStream |
指定在应用程序窗口中Video对象的边界内显示视频流 |
|
clear |
清除该Video对象中当前显示的图像 |
21.2 加载视频文件
.flv格式是Flash Player网络传输的视频文件的基本格式。可以通过一些工具把其他的视频文件格式转换为.flv格式,比如Flash CS3自带的工具Flash Video Encode。
加载一个视频文件,通常可以分为三步实现。其步骤如下所示。
创建一个NetConnection对象。NetConnection类作用是连接到远程服务器中,调用命令,播放视频。其代码如下所示:
// 建立连接
var nc:NetConnection = new NetConnection();
nc.connect(null);
创建一个NetStream对象。NetStream类作用是通过NetConnection对象提供的连接,打开Flash Player与服务器或Flash Player与本地文件系统之间的单向流连接。其代码如下所示:
// 创建视频流
var ns:NetStream = new NetStream(nc);
// 开始播放
ns.play("lake.flv");
创建一个Video对象。调用Video类的attachNetStream事件,可以直接显示视频流。其代码如下所示:
// 视频传输到本地
// 创建Video对象
var vid:Video = new Video();
vid.attachNetStream(ns);
通过这三个步骤的操作,视频文件就被加载并播放。
下面示例说明如何播放一个本地的视频文件lake.flv。其完整的代码如下所示:
package
{
import flash.display.Sprite;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.media.Video;
import flash.events.AsyncErrorEvent;
public class VideoExample extends Sprite
{
/*************************************
* 构造函数
* */
public function VideoExample()
{
// 建立连接
var nc:NetConnection = new NetConnection();
nc.connect(null);
// 创建视频流
var ns:NetStream = new NetStream(nc);
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
// 指定视频名
ns.play("lake.flv");
// 视频传输到本地
var vid:Video = new Video();
vid.attachNetStream(ns);
// 添加到舞台上
addChild(vid);
}
/*************************************
* 捕获连接异常
* */
function asyncErrorHandler(event:AsyncErrorEvent):void
{
// 错误处理
}
}
}
编译代码,运行效果如图21.1所示。

图21.1 加载视频文件
21.3 视频文件的控制
视频文件的控制是指在视频在播放过程中,用户通过一些交互式的按钮或者其他组件触发事件,精确的控制视频的播放,包括停止播放、暂停播放、视频回放等。
21.3.1
从指定的位置播放
通过NetStream对象的play()方法可以回放视频文件,但是play()方法是从视频文件的开始播放的。有时候,我们需要从指定的位置或者时间开始播放,那么什么方法可以满足这个要求呢?在NetStream类中提供了seek()方法,可以搜索指定位置开始播放。其参数有一个,表示从流的开始位置算起的偏移量,以秒为单位。其语法格式如下所示:
seek(offset:Number):void
比如下面的示例作用是从第5秒开始播放一个视频文件,代码如下所示:
package
{
import flash.display.Sprite;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.media.Video;
public class VideoExample extends Sprite
{
/*************************************
* 构造函数
* */
public function VideoExample()
{
// 建立连接
var nc:NetConnection = new NetConnection();
nc.connect(null);
// 创建视频流
var ns:NetStream = new NetStream(nc);
// 指定视频名
ns.play("lake.flv");
// 从第5秒开始播放
ns.seek(5);
// 视频传输到本地
var vid:Video = new Video();
vid.attachNetStream(ns);
// 添加到舞台上
addChild(vid);
}
}
}
编译代码,运行的效果如图21.2所示。

图21.2 从指定的位置播放
21.3.2
停止
需要停止一个正在播放的视频的时候,要使用NetStream对象的close()方法。close()方法同时也停止了从服务器中下载视频。其语法格式如下所示:
close():void
如果要继续播放和从服务器中下载视频,需要再次调用NetStream对象的play()方法。下面的示例使用close()方法停止正在播放的视频,代码如下所示:
package
{
import flash.display.Sprite;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.media.Video;
import flash.events.MouseEvent;
import flash.events.AsyncErrorEvent;
import fl.controls.Button;
public class VideoExample extends Sprite
{
var ns:NetStream;
var nc:NetConnection;
var vid:Video;
/*************************************
* 构造函数
* */
public function VideoExample()
{
LoadVideo();
LoadStopButton();
}
/*************************************
* 加载视频文件
* */
private function LoadVideo():void
{
// 建立连接
nc = new NetConnection();
nc.connect(null);
// 创建视频流
ns = new NetStream(nc);
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
// 指定视频名
ns.play("lake.flv");
// 视频传输到本地
vid = new Video();
vid.attachNetStream(ns);
// 添加到舞台上
addChild(vid);
}
/*************************************
* 创建一个停止的按钮
* */
private function LoadStopButton():void
{
// 增加停止按钮
var stop_btn:Button = new Button();
stop_btn.label = "停止";
stop_btn.move(10, 250);
stop_btn.addEventListener(MouseEvent.CLICK, StopBtn_Click);
addChild(stop_btn);
}
/*************************************
* 创建一个停止按钮的单击事件
* */
private function StopBtn_Click(e:MouseEvent):void
{
// 停止播放
ns.close();
}
/*************************************
* 捕获连接异常
* */
function asyncErrorHandler(event:AsyncErrorEvent):void
{
// 错误处理
}
}
}
编译代码,运行效果如图21.3所示。

图21.3 停止正在播放的视频
21.3.3
暂停与回放
暂停正在播放的视频,需要使用NetStream对象的pause()方法。如果暂停之后,需要从暂停的地方播放,就需要用到resume()方法了。resume()方法作用是恢复播放暂停的视频流。其语法格式如下所示:
resume():void
下面的示例使用pause()方法和resume()方法控制正在播放的视频,示例代码如下所示:
package
{
import flash.display.Sprite;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.media.Video;
import flash.events.MouseEvent;
import flash.events.AsyncErrorEvent;
import fl.controls.Button;
public class VideoExample extends Sprite
{
var ns:NetStream;
var nc:NetConnection;
var vid:Video;
var pause_btn:Button;
/*************************************
* 构造函数
* */
public function VideoExample()
{
LoadVideo();
LoadPauseButton();
}
/*************************************
* 加载视频文件
* */
private function LoadVideo():void
{
// 建立连接
nc = new NetConnection();
nc.connect(null);
// 创建视频流
ns = new NetStream(nc);
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
// 指定视频名
ns.play("lake.flv");
// 视频传输到本地
vid = new Video();
vid.attachNetStream(ns);
// 添加到舞台上
addChild(vid);
}
/*************************************
* 创建一个暂停/回放按钮
* */
private function LoadPauseButton():void
{
// 增加暂停/回放按钮
pause_btn = new Button();
pause_btn.label = "暂停";
pause_btn.move(10, 250);
pause_btn.addEventListener(MouseEvent.CLICK, PauseBtn_Click);
addChild(pause_btn);
}
/*************************************
* 创建一个暂停按钮的单击事件
* */
private function PauseBtn_Click(e:MouseEvent):void
{
if(e.target.label == "暂停")
{
// 停止播放
ns.pause();
pause_btn.label = "回放";
}
else
{
// 回放
ns.resume();
pause_btn.label = "暂停";
}
}
/*************************************
* 捕获连接异常
* */
function asyncErrorHandler(event:AsyncErrorEvent):void
{
// 错误处理
}
}
}
编译代码,运行效果如图21.4所示。

图21.4 暂停和回放视频
21.3.4
控制视频的音量
控制视频中的声音,需要使用NetStream对象中的soundTransform属性,soundTransform属性返回的是一个SoundTransform对象,SoundTransform对象中的volume属性可以控制声音。
下面的示例使用Slider控件控制视频中声音的大小,代码如下所示:
package
{
import flash.display.Sprite;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.media.Video;
import flash.media.SoundTransform;
import fl.events.SliderEvent;
import flash.events.AsyncErrorEvent;
import fl.controls.Slider;
public class VideoSoundExample extends Sprite
{
var ns:NetStream;
var nc:NetConnection;
var vid:Video;
var sound_slider:Slider;
var sound:SoundTransform;
/*************************************
* 构造函数
* */
public function VideoSoundExample()
{
LoadVideo();
LoadSlider();
}
/*************************************
* 加载视频文件
* */
private function LoadVideo():void
{
// 建立连接
nc = new NetConnection();
nc.connect(null);
// 创建视频流
ns = new NetStream(nc);
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
// 创建声音
sound = ns.soundTransform;
// 指定视频名
ns.play("lake.flv");
// 视频传输到本地
vid = new Video();
vid.attachNetStream(ns);
// 添加到舞台上
addChild(vid);
}
/*************************************
* 创建Slider控件
* */
private function LoadSlider():void
{
sound_slider = new Slider();
sound_slider.move(10, 250);
// 声音默认值
sound_slider.value = sound.volume;
sound_slider.addEventListener(SliderEvent.CHANGE, volumeChange
Handler);
addChild(sound_slider);
}
/*************************************
* 控制声音
* */
private function volumeChangeHandler(event:SliderEvent):void
{
// 获取Slider控件的值
sound.volume = event.value;
ns.soundTransform = sound;
}
/*************************************
* 捕获连接异常
* */
function asyncErrorHandler(event:AsyncErrorEvent):void
{
// 错误处理
}
}
}
编译代码,运行效果如图21.5所示。

图21.5 视频中的音量控制
21.4 获取视频文件的信息
可以使用onMetaData回调处理函数获取视频文件的信息。视频文件的信息包括持续时间、宽度、高度及帧速等。
21.4.1
onMetaData回调方法
onMetaData是一个回调函数,使用这个回调函数,可以获取元数据的信息,也就是视频文件的信息,包括持续时间、高度、宽度、帧速、视频编码器及音频编码器等。
回调方法有很多参数,通过不同的参数,可以获取元数据不同的信息。回调方法的常用的参数如表21.3所示。
表21.3 onMetaData回调函数的常用的参数
|
参 数 |
说 明 |
|
audiocodecid |
指示已使用的音频编解码器(编码/ 解码技术) |
|
audiodatarate |
指示音频的编码速率,以每秒千字节为单位 |
|
audiodelay |
指示原始FLV文件的“time 0”在FLV文件中保持多长时间。为了正确同步音频,视频内容需要有少量的延迟 |
|
canSeekToEnd |
如果FLV文件是用最后一帧(它允许定位到渐进式下载影片剪辑的末尾)上的关键帧编码的,则该值为true。如果FLV文件不是用最后一帧上的关键帧编码的,则该值为false |
|
cuePoints |
嵌入在FLV文件中的提示点对象组成的数组,每个提示点对应一个对象。如果FLV文件不包含任何提示点,则值是未定义的 |
|
duration |
以秒为单位指定FLV文件的持续时间 |
|
framerate |
表示FLV文件的帧速率 |
|
height |
以像素为单位表示FLV文件的高度 |
|
videocodecid |
表示用于对视频进行编码的编解码器的版本 |
|
videodatarate |
表示FLV文件的视频数据速率 |
|
width |
以像素为单位表示FLV文件的宽度 |
onMetaData回调方法的关联对象是赋值给NetStream对象的client()方法的,下面的示例说明onMetaData回调方法如何使用,代码如下所示:
// 创建回调函数的对象
var customClient:Object = new Object();
customClient.onMetaData = metaDataHandler;
// 创建视频流
var ns:NetStream = new NetStream(nc);
// 回调函数的对象customClient
// 赋值给NetStream对象的属性client
ns.client = customClient;
// 指定视频名
ns.play("Bear.flv");
/*************************************
* onMetaData回调函数的事件
* */
function metaDataHandler(metadata:Object):void
{
// 处理数据
}
21.4.2
获取视频文件的基本信息
使用回调函数onMetaData可以获取视频文件的基本信息。下面的示例通过onMetaData回调函数获取视频文件的持续时间、帧速、高度和宽度,代码如下所示:
package
{
import flash.display.Sprite;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.media.Video;
import flash.events.AsyncErrorEvent;
public class CuoPointExample extends Sprite
{
var ns:NetStream;
var nc:NetConnection;
var vid:Video;
public function CuoPointExample()
{
LoadVideo();
}
/*************************************
* 加载视频文件
* */
private function LoadVideo():void
{
// 建立连接
var nc:NetConnection = new NetConnection();
nc.connect(null);
// 创建回调函数的对象
var customClient:Object = new Object();
customClient.onMetaData = metaDataHandler;
// 创建视频流
var ns:NetStream = new NetStream(nc);
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
// 回调函数的对象customClient
// 赋值给NetStream对象的属性client
ns.client = customClient;
// 指定视频名
ns.play("Bear.flv");
// 视频传输到本地
var vid:Video = new Video();
vid.attachNetStream(ns);
// 添加到舞台上
addChild(vid);
}
/*************************************
* 捕获连接异常
* */
function asyncErrorHandler(event:AsyncErrorEvent):void
{
// 错误处理
trace(event.text);
}
/*************************************
* onMetaData回调函数的事件
* */
function metaDataHandler(metadata:Object):void
{
// 输出持续时间
trace("持续时间:" + metadata.duration);
// 输出帧速
trace("帧速:" + metadata.framerate);
// 输出视频文件的高度
trace("高度:" + metadata.height);
// 输出视频文件的宽度
trace("宽度:" + metadata.width);
}
}
}
编译代码,运行效果如图21.6所示。

图21.6 获取视频文件的基本信息
21.5 提示点
在视频文件中,可以嵌入提示点。提示点可以嵌入到视频文件的任意时间点上,等到视频播放到该位置时,会调用回调函数onCuePoint。提示点有很多用途,比如记录日志、显示提示信息等。提示点大体分为三种:导航提示点、事件提示点和ActionScript提示点。
将导航提示点嵌入到视频中,起到信息提示的作用。
将事件提示点嵌入到视频中,视频播放到指定提示点的位置时,触发响应的事件。
ActionScript提示点属于外部提示点,通过外部的代码触发。
下面的示例使用onCuePoint回调函数,输出每个提示点的信息。代码如下所示:
package
{
import flash.display.Sprite;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.media.Video;
import flash.events.AsyncErrorEvent;
public class CuoPointExample extends Sprite
{
var ns:NetStream;
var nc:NetConnection;
var vid:Video;
public function CuoPointExample()
{
LoadVideo();
}
/*************************************
* 加载视频文件
* */
private function LoadVideo():void
{
// 建立连接
var nc:NetConnection = new NetConnection();
nc.connect(null);
// 创建回调函数的对象
var customClient:Object = new Object();
// 处理回调函数
customClient.onMetaData = metaDataHandler;
customClient.onCuePoint = cuePointHandler;
// 创建视频流
var ns:NetStream = new NetStream(nc);
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
// 回调函数的对象customClient
// 赋值给NetStream对象的属性client
ns.client = customClient;
// 指定视频名
ns.play("Bear.flv");
// 视频传输到本地
var vid:Video = new Video();
vid.attachNetStream(ns);
// 添加到舞台上
addChild(vid);
}
/*************************************
* 捕获连接异常
* */
function asyncErrorHandler(event:AsyncErrorEvent):void
{
// 错误处理
}
/*************************************
* onMetaData回调函数的事件
* */
function metaDataHandler(metadata:Object):void
{
// 处理onMetaData回调函数
}
/*************************************
* onCuePoint回调函数的事件
* */
function cuePointHandler(cuePoint:Object):void
{
// 输出信息
traceObject(cuePoint);
}
/*************************************
* 输出回调函数的值和参数
* */
function traceObject(obj:Object, indent:uint = 0):void
{
var indentString:String = "";
var i:uint;
var prop:String;
var val:*;
for (i = 0; i < indent; i++)
{
indentString += "\t";
}
for (prop in obj)
{
val = obj[prop];
if (typeof(val) == "object")
{
trace(indentString + " " + prop + ": [Object]");
traceObject(val, indent + 1);
}
else
{
trace(indentString + " " + prop + ": " + val);
}
}
}
}
}
编译代码,运行效果如图21.7所示。

图21.7 输出提示点信息
21.6 捕获摄像头的输入
除了外部的.flv视频文件之外,摄像头也是Flash Player视频的主要来源之一。在ActionScript 3.0中,也相应的提供了一些关于摄像头的类,使用这些类,可以很容易捕获来自摄像头的视频信息。
21.6.1
Camera类
Camera类是跟摄像头有关的很重要的类。使用Camera类可以捕获连接到计算机上的摄像头,并获得相应的信息。Camera类的常用的属性如表21.4所示,常用的方法如表21.5所示,常用的事件如表21.6所示。
表21.4 Camera类常用的属性
|
属 性 |
说 明 |
|
activityLevel |
指定摄像头检测的运动量 |
|
bandwidth |
指定当前输出视频输入信号可以使用的最大带宽,以字节为单位 |
|
currentFPS |
摄像头捕获数据的速率,以每秒帧数为单位 |
|
fps |
希望摄像头在捕获数据时达到的最大速率,以每秒帧数为单位 |
|
height |
当前捕获高度,以像素为单位 |
|
index |
从零开始的整数,指定由names属性返回的数组中所反映的摄像头的索引 |
|
keyFrameInterval |
指定进行完整传输而不由视频压缩算法进行插值处理的视频帧(称为关键帧) |
|
loopback |
指定在本地查看摄像头所捕获图像时是进行压缩和解压缩 (true) 以便使用Flash Media Server进行实时传输,还是不进行压缩 (false) |
续表
|
属 性 |
说 明 |
|
motionLevel |
指定调用activity事件所需的运动量 |
|
motionTimeout |
摄像头停止检测运动的时间与调用activity事件的时间之间相差的毫秒数 |
|
muted |
指定用户在Flash Player的“隐私”面板中是拒绝了对摄像头的访问 (true) 还是允许访问 (false) |
|
name |
指定由摄像头硬件返回的当前摄像头的名称 |
|
names |
检索一个反映所有可用摄像头的名称的字符串数组,而不显示Flash Player的“隐私”面板 |
|
quality |
指定所需的画面质量级别,该级别由应用于每一视频帧的压缩量来确定 |
|
width |
当前捕获宽度,以像素为单位 |
表21.5 Camera类常用的方法
|
方 法 |
说 明 |
|
getCamera |
返回对用于捕获视频的Camera对象的引用 |
|
setKeyFrameInterval |
指定进行完整传输而不由视频压缩算法进行插值处理的视频帧(称为关键帧) |
|
setLoopback |
指定在本地查看摄像头时是否使用压缩视频流 |
|
setMode |
将摄像头的捕获模式设置为最符合指定要求的本机模式 |
|
setMotionLevel |
指定调度activity事件所需的运动量 |
|
setQuality |
设置每秒的最大带宽或当前输出视频输入信号所需的画面质量 |
表21.6 Camera类常用的事件
|
事 件 |
说 明 |
|
activity |
在摄像头开始或结束会话时调度 |
|
status |
在摄像头报告其状态时调度 |
21.6.2
验证摄像头
在捕获摄像头的内容之前,通常需要检测用户的计算机上是否安装了摄像头。验证摄像头的方法是利用Camera的实例对象,判断这个实例是否为空,为空则没有检测到摄像头,反之,用户就已经安装了摄像头。
下面的示例作用是检测用户的计算机上是否已经安装了摄像头,示例如下所示:
package
{
import flash.display.Sprite;
import flash.media.Camera;
public class CameraExample extends Sprite
{
/*************************************
* 构造函数
* */
public function CameraExample()
{
// 创建Camera对象
var camera:Camera = Camera.getCamera();
// 检测摄像头
if (camera != null)
{
trace("机器上已经安装了摄像头.");
}
else
{
trace("机器上没有安装摄像头.");
}
}
}
}
编译代码并运行,输出的结果如图21.8所示。

图21.8 验证摄像头
21.6.3
输出摄像头的内容
Flash Player对摄像头的输出是有一定的限制的,需要本地计算机用户进行有效的设置,才能连接摄像头。在Flash Player播放器中,单击右键,选择【设置】命令,就会弹出一个对话框,如图21.9所示。

图21.9 摄像头的设置
默认摄像头的设置是拒绝访问的,如果要使用摄像头,必须勾上【允许】选项。摄像头的捕获要通过静态方法getCamera()来实例化一个Camera对象,然后通过Video对象显示出来。
下面的示例使用Camera对象捕获摄像头的内容,并实时监视。代码如下所示:
package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.*;
import flash.media.Camera;
import flash.media.Video;
public class CameraExample extends Sprite
{
private var video:Video;
/*************************************
* 构造函数
* */
public function CameraExample()
{
// 设置舞台属性
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
// 创建Camera对象
var camera:Camera = Camera.getCamera();
// 检测摄像头
if (camera != null)
{
camera.addEventListener(ActivityEvent.ACTIVITY, activityHandler);
// 创建Video对象
video = new Video(camera.width * 2, camera.height * 2);
// 显示摄像头的内容
video.attachCamera(camera);
addChild(video);
}
else
{
trace("机器上没有安装摄像头.");
}
}
/*************************************
* 事件处理
* */
private function activityHandler(event:ActivityEvent):void
{
trace("activityHandler: " + event);
}
}
}
