posts - 562, comments - 10438, trackbacks - 594, articles - 0
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

公告

稳扎稳打Silverlight(49) - 4.0媒体之摄像头和麦克风

Posted on 2010-09-02 09:32 webabcd 阅读(...) 评论(...) 编辑 收藏

[索引页]
[源码下载]


稳扎稳打Silverlight(49) - 4.0媒体之摄像头和麦克风



作者:webabcd


介绍
Silverlight 4.0 媒体方面的增强:

  • 新增对摄像头的支持
  • 新增对麦克风的支持



在线DEMO
http://www.cnblogs.com/webabcd/archive/2010/08/09/1795417.html


示例
1、演示如何捕获摄像头
MemoryStreamVideoSink.cs

代码
/*
 * VideoSink - 用于捕获视频信息。抽象类,其有一个 CaptureSource 类型的属性
 
*/

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using System.IO;

namespace Silverlight40.WebcamMic
{
    
public class MemoryStreamVideoSink : VideoSink
    {
        
public VideoFormat VideoFormat { getprivate set; }
        
public MemoryStream MemoryStream { getprivate set; }

        
// 当视频设备开始捕获视频数据时所调用的方法
        protected override void OnCaptureStarted()
        {
            MemoryStream 
= new MemoryStream();
        }

        
// 当视频设备停止捕获视频数据时所调用的方法
        protected override void OnCaptureStopped()
        {

        }

        
/// <summary>
        
/// 当视频设备报告视频格式更改时所调用的方法
        
/// 当视频设备开始捕获视频数据时会调用一次 OnFormatChange,此时便可以确定当前的视频格式
        
/// </summary>
        
/// <param name="videoFormat">新的视频格式</param>
        protected override void OnFormatChange(VideoFormat videoFormat)
        {
            VideoFormat 
= videoFormat;
        }

        
/// <summary>
        
/// 当视频设备捕获了一个完整的视频采样时所调用的方法
        
/// </summary>
        
/// <param name="sampleTime">当前采样被捕获时的时间。单位:100纳秒</param>
        
/// <param name="frameDuration">当前采样的时长。单位:100纳秒</param>
        
/// <param name="sampleData">当前采样的视频数据的字节流</param>
        protected override void OnSample(long sampleTime, long frameDuration, byte[] sampleData)
        {
            MemoryStream.Write(sampleData, 
0, sampleData.Length);
        }
    }
}


Webcam.xaml

代码
<navigation:Page x:Class="Silverlight40.WebcamMic.Webcam" 
           xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
           xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml" 
           xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"
           xmlns:mc
="http://schemas.openxmlformats.org/markup-compatibility/2006"
           xmlns:navigation
="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
           Title
="Webcam Page">
    
<Grid x:Name="LayoutRoot">
        
<StackPanel HorizontalAlignment="Left">

            
<TextBlock Text="可用的视频捕获设备列表" />
            
<ListBox Name="videoSources">
                
<ListBox.ItemTemplate>
                    
<DataTemplate>
                        
<TextBlock Text="{Binding FriendlyName}" />
                    
</DataTemplate>
                
</ListBox.ItemTemplate>
            
</ListBox>

            
<!--显示 CaptureSource 中的视频-->
            
<Border Width="320" Height="240" CornerRadius="10" BorderThickness="1" BorderBrush="Blue">
                
<Rectangle Name="webcamCapture" Fill="Black"/>
            
</Border>

            
<Button Name="btnStartCapture" Content="开始捕获" Click="btnStartCapture_Click" />
            
<Button Name="btnStopCapture" Content="停止捕获" Click="btnStopCapture_Click" />
            
<Button Name="btnTakeSnapshot" Content="截图" Click="btnTakeSnapshot_Click" />

            
<!--显示截图结果-->
            
<ScrollViewer Width="320" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Auto">
                
<ItemsControl Name="snapshots">
                    
<ItemsControl.ItemTemplate>
                        
<DataTemplate>
                            
<Image Source="{Binding}" Margin="3" Stretch="Fill" Height="50" />
                        
</DataTemplate>
                    
</ItemsControl.ItemTemplate>
                    
<ItemsControl.ItemsPanel>
                        
<ItemsPanelTemplate>
                            
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" />
                        
</ItemsPanelTemplate>
                    
</ItemsControl.ItemsPanel>
                
</ItemsControl>
            
</ScrollViewer>
            
        
</StackPanel>
    
</Grid>
</navigation:Page>


Webcam.xaml.cs

代码
/*
 * 演示 Silverlight 4.0 对视频捕获设备的支持
 * CaptureDeviceConfiguration - 视频捕获设备及音频捕获设备的相关信息
 *     GetAvailableVideoCaptureDevices() - 返回可用的视频捕获设备的集合。VideoCaptureDevice 类型的集合
 *     GetDefaultVideoCaptureDevice() - 返回默认的视频捕获设备。VideoCaptureDevice 类型
 *     RequestDeviceAccess() - 请求访问所有可能的视频捕获设备和音频捕获设备。弹出确认对话框后(被信任的应用程序不会弹出此对话框),用户允许则返回 true
 *     AllowedDeviceAccess - 用户以前是否允许了可以访问视频捕获设备和音频捕获设备(当用户以前允许过,并且允许的时候选择了“记住我的答案”,则返回 true)
 * 
 * CaptureSource - 捕获源,用于提供捕获视频和音频的一些相关方法
 *     Start() - 开始捕获 
 *     Stop() - 停止捕获
 *     VideoCaptureDevice - 指定用于捕获视频的设备, VideoCaptureDevice 类型
 *     State - 捕获状态 [System.Windows.Media.CaptureState 枚举(Stopped, Started, Failed)]
 *     CaptureImageAsync() - 启动一个异步图像捕获请求
 *     CaptureImageCompleted - 当异步图像捕获请求完成时所触发的事件
 *     CaptureFailed - 捕获失败时所触发的事件
 * 
 * VideoCaptureDevice - 视频捕获设备的相关信息
 *     FriendlyName - 视频捕获设备的名称
 *     IsDefaultDevice - 是否是默认的视频捕获设备
 *     SupportedFormats - 此视频捕获设备所支持的视频格式的集合。VideoFormat 类型的集合
 *     DesiredFormat - 需要视频捕获设备使用的视频格式。VideoFormat 类型
 * 
 * VideoFormat - 捕获视频的视频格式信息
 *     PixelWidth - 视频区域的宽度,以像素为单位
 *     PixelHeight - 视频区域的高度,以像素为单位
 *     PixelFormat - 视频编码格式 [System.Windows.Media.PixelFormatType 枚举],目前仅支持 PixelFormatType.Format32bppArgb
 *     FramesPerSecond - 视频的每秒帧数
 *     Stride - 图像的行的宽度,以字节为单位,如果是负数则表示图像倒置
 * 
 * VideoBrush.SetSource(CaptureSource) - 指定一个视频捕获源做为 VideoBrush 的源
 
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Navigation;

using System.Collections.ObjectModel;
using System.Windows.Media.Imaging;
using System.IO;

namespace Silverlight40.WebcamMic
{
    
public partial class Webcam : Page
    {
        
private CaptureSource _captureSource;
        
private MemoryStreamVideoSink _videoSink;
        
private ObservableCollection<WriteableBitmap> _images = new ObservableCollection<WriteableBitmap>();

        
public Webcam()
        {
            InitializeComponent();
        }

        
protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            
// 可用的视频捕获设备列表
            videoSources.ItemsSource = CaptureDeviceConfiguration.GetAvailableVideoCaptureDevices();

            _captureSource 
= new CaptureSource();
            _captureSource.VideoCaptureDevice 
= CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();

            
// 截图完成
            _captureSource.CaptureImageCompleted += ((s, args) => { _images.Add(args.Result); });
            
// 视频截图列表
            snapshots.ItemsSource = _images;

            
// VideoSink 用于处理捕获视频信息的相关逻辑
            _videoSink = new MemoryStreamVideoSink();
            _videoSink.CaptureSource 
= _captureSource;
        }


        
private void btnStartCapture_Click(object sender, RoutedEventArgs e)
        {
            
// 将视频捕获框填充到指定的 Rectangle 中
            VideoBrush videoBrush = new VideoBrush();
            videoBrush.SetSource(_captureSource);
            webcamCapture.Fill 
= videoBrush;

            
// 如果允许启用摄像头,则开始捕获
            if (CaptureDeviceConfiguration.AllowedDeviceAccess || CaptureDeviceConfiguration.RequestDeviceAccess())
                _captureSource.Start();
        }

        
private void btnStopCapture_Click(object sender, RoutedEventArgs e)
        {
            _captureSource.Stop();
        }

        
private void btnTakeSnapshot_Click(object sender, RoutedEventArgs e)
        {
            _captureSource.CaptureImageAsync();
        }
    }
}



2、演示如何捕获麦克风
MemoryStreamAudioSink.cs

代码
/*
 * AudioSink - 用于捕获音频信息。抽象类,其有一个 CaptureSource 类型的属性
 
*/

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using System.IO;

namespace Silverlight40.WebcamMic
{
    
public class MemoryStreamAudioSink : AudioSink
    {
        
public AudioFormat AudioFormat { getprivate set; }
        
public MemoryStream MemoryStream { getprivate set; }

        
// 当音频设备开始捕获音频数据时所调用的方法
        protected override void OnCaptureStarted()
        {
            MemoryStream 
= new MemoryStream();
        }

        
// 当音频设备停止捕获音频数据时所调用的方法
        protected override void OnCaptureStopped()
        {

        }

        
/// <summary>
        
/// 当音频设备报告音频格式更改时所调用的方法
        
/// 当音频设备开始捕获音频数据时会调用一次 OnFormatChange,此时便可以确定当前的音频格式
        
/// </summary>
        
/// <param name="audioFormat">新的音频格式</param>
        protected override void OnFormatChange(AudioFormat audioFormat)
        {
            AudioFormat 
= audioFormat;
        }

        
/// <summary>
        
/// 当音频设备捕获了一个完整的音频采样时所调用的方法
        
/// </summary>
        
/// <param name="sampleTime">当前采样被捕获时的时间。单位:100纳秒</param>
        
/// <param name="sampleDuration">当前采样的时长。单位:100纳秒</param>
        
/// <param name="sampleData">当前采样的音频数据的字节流</param>
        protected override void OnSamples(long sampleTime, long sampleDuration, byte[] sampleData)
        {
            MemoryStream.Write(sampleData, 
0, sampleData.Length);
        }
    }
}


WavFileHelper.cs

代码
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using System.IO;

namespace Silverlight40.WebcamMic
{
    
public static class WavFileHelper
    {
        
// 获取 PCM 格式的音频头的字节数组
        public static byte[] GetWavFileHeader(long audioByteLength, AudioFormat audioFormat)
        {
            MemoryStream stream 
= new MemoryStream(44);

            
// “RIFF”
            stream.Write(new byte[] { 0x520x490x460x46 }, 04);

            
// 文件长度 = 音频数据长度 + 44个字节的header长度 - 8个字节(上面的4个字节和这里的4个字节)
            stream.Write(BitConverter.GetBytes((UInt32)(audioByteLength + 44 - 8)), 04);

            
// “WAVE”
            stream.Write(new byte[] { 0x570x410x560x45 }, 04);

            
// “fmt ”
            stream.Write(new byte[] { 0x660x6D0x740x20 }, 04);

            
// 对于 PCM 来说,这里的值为 16
            stream.Write(BitConverter.GetBytes((UInt32)16), 04);

            
// “1”代表未压缩
            stream.Write(BitConverter.GetBytes((UInt16)1), 02);

            
// 通道数:“1”代表单声道;“2”代表双声道
            stream.Write(BitConverter.GetBytes((UInt16)audioFormat.Channels), 02);

            
// 采样率(采样频率),即每秒样本数
            stream.Write(BitConverter.GetBytes((UInt32)audioFormat.SamplesPerSecond), 04);

            
// 比特率,即每秒字节数。其值为通道数×每秒数据位数×每样本的数据位数/8(SampleRate * ChannelCount * BitsPerSample / 8)
            stream.Write(BitConverter.GetBytes((UInt32)((audioFormat.SamplesPerSecond * audioFormat.Channels * audioFormat.BitsPerSample) / 8)), 04);

            
// 通道数×每样本的数据位数/8(ChannelCount * BitsPerSample / 8)
            stream.Write(BitConverter.GetBytes((UInt16)((audioFormat.Channels * audioFormat.BitsPerSample) / 8)), 02);

            
// 采样位数(采样分辨率),即每样本的数据位数
            stream.Write(BitConverter.GetBytes((UInt16)audioFormat.BitsPerSample), 02);

            
// “data”
            stream.Write(new byte[] { 0x640x610x740x61 }, 04);

            
// 语音数据的长度
            stream.Write(BitConverter.GetBytes((UInt32)audioByteLength), 04);

            
return (stream.GetBuffer());
        }
    }  
}


Mic.xaml

代码
<navigation:Page x:Class="Silverlight40.WebcamMic.Mic" 
           xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
           xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml" 
           xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"
           xmlns:mc
="http://schemas.openxmlformats.org/markup-compatibility/2006"
           xmlns:navigation
="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
           Title
="Mic Page">
    
<Grid x:Name="LayoutRoot">
        
<StackPanel HorizontalAlignment="Left">

            
<TextBlock Text="可用的音频捕获设备列表" />
            
<ListBox Name="audioSources">
                
<ListBox.ItemTemplate>
                    
<DataTemplate>
                        
<TextBlock Text="{Binding FriendlyName}" />
                    
</DataTemplate>
                
</ListBox.ItemTemplate>
            
</ListBox>
            
            
<TextBlock Name="lblMsg" />

            
<Button Name="btnStartCapture" Content="开始捕获" Click="btnStartCapture_Click" />
            
<Button Name="btnStopCapture" Content="停止捕获" Click="btnStopCapture_Click" />
            
        
</StackPanel>
    
</Grid>
</navigation:Page>


Mic.xaml.cs

代码
/*
 * 演示 Silverlight 4.0 对音频捕获设备的支持
 * CaptureDeviceConfiguration - 视频捕获设备及音频捕获设备的相关信息
 *     GetAvailableAudioCaptureDevices() - 返回可用的音频捕获设备的集合。AudioCaptureDevice 类型的集合
 *     GetDefaultAudioCaptureDevice() - 返回默认的音频捕获设备。AudioCaptureDevice 类型
 *     RequestDeviceAccess() - 请求访问所有可能的视频捕获设备和音频捕获设备。弹出确认对话框后(被信任的应用程序不会弹出此对话框),用户允许则返回 true
 *     AllowedDeviceAccess - 用户以前是否允许了可以访问视频捕获设备和音频捕获设备(当用户以前允许过,并且允许的时候选择了“记住我的答案”,则返回 true)
 * 
 * CaptureSource - 捕获源,用于提供捕获视频和音频的一些相关方法
 *     Start() - 开始捕获 
 *     Stop() - 停止捕获
 *     AudioCaptureDevice - 指定用于捕获音频的设备, AudioCaptureDevice 类型
 *     State - 捕获状态 [System.Windows.Media.CaptureState 枚举(Stopped, Started, Failed)]
 *     CaptureFailed - 捕获失败时所触发的事件
 * 
 * AudioCaptureDevice - 音频捕获设备的相关信息
 *     FriendlyName - 音频捕获设备的名称
 *     IsDefaultDevice - 是否是默认的音频捕获设备
 *     SupportedFormats - 此音频捕获设备所支持的音频格式的集合。AudioFormat 类型的集合
 *     DesiredFormat - 需要音频捕获设备使用的音频格式。AudioFormat 类型
 *     AudioFrameSize - 音频的帧大小。单位:毫秒。默认值:1000毫秒。范围:10 - 2000毫秒
 * 
 * AudioFormat - 捕获音频的音频格式信息
 *     Channels - 声道数
 *     SamplesPerSecond - 采样率(采样频率)
 *     BitsPerSample - 采样位数(采样分辨率)
 *     WaveFormat - 音频编码格式 [System.Windows.Media.WaveFormatType 枚举],目前仅支持 WaveFormatType.Pcm
 
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Navigation;

using System.IO;

namespace Silverlight40.WebcamMic
{
    
public partial class Mic : Page
    {
        
private CaptureSource _captureSource;
        
private MemoryStreamAudioSink _audioSink;

        
public Mic()
        {
            InitializeComponent();
        }

        
protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            
// 可用的音频捕获设备列表
            audioSources.ItemsSource = CaptureDeviceConfiguration.GetAvailableAudioCaptureDevices();

            _captureSource 
= new CaptureSource();
            _captureSource.AudioCaptureDevice 
= CaptureDeviceConfiguration.GetDefaultAudioCaptureDevice();

            
// AudioSink 用于处理捕获音频信息的相关逻辑
            _audioSink = new MemoryStreamAudioSink();
            _audioSink.CaptureSource 
= _captureSource;
        }

        
private void btnStartCapture_Click(object sender, RoutedEventArgs e)
        {
            
// 如果允许启用麦克风,则开始捕获
            if (CaptureDeviceConfiguration.AllowedDeviceAccess || CaptureDeviceConfiguration.RequestDeviceAccess())
                _captureSource.Start();

            lblMsg.Text 
= _captureSource.State.ToString();
        }

        
private void btnStopCapture_Click(object sender, RoutedEventArgs e)
        {
            _captureSource.Stop();

            lblMsg.Text 
= _captureSource.State.ToString();

            
if (_audioSink.MemoryStream == null)
                
return;

            
// 弹出“另存为”对话框,保存捕获到的全部音频数据
            SaveFileDialog dialog = new SaveFileDialog();
            dialog.Filter 
= "音频(*.wav)|*.wav";

            
bool? result = dialog.ShowDialog();
            
if (result == true)
            {
                
using (Stream stream = dialog.OpenFile())
                {
                    
// 写入音频头
                    byte[] wavFileHeader = WavFileHelper.GetWavFileHeader(_audioSink.MemoryStream.Length, _audioSink.AudioFormat);
                    stream.Write(wavFileHeader, 
0, wavFileHeader.Length);

                    
byte[] buffer = new byte[4096];
                    
int read = 0;

                    _audioSink.MemoryStream.Seek(
0, SeekOrigin.Begin);

                    
// 写入音频数据
                    while ((read = _audioSink.MemoryStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        stream.Write(buffer, 
0, read);
                    }
                }
            }
        }
    }
}



OK
[源码下载]